Order Management Processing
To implement the required logic within Matrix42 for order management processing, the configuration project RootITUp.OrderManagement.Processing was introduced.
Name | Type | Description |
Ud_SmartphoneProvisioningClass | Data Definition | Information required for configuring a service with contracted and contractless variants |
Ud_BookingPickupStatus | Data Definition | The external states a booking can be in. |
Ud_DestinationTypePickup | Data Definition | Allows for distinction between an individual order versus an order for company stock |
Ud_StockDecisionPickup | Data Definition | Decides if existing software stock can be used or new one needs to be purchased |
SPSActivityClassBase.Ud_StockDecision | Data Definition | Added Ud_StockDecision attribute to persist software stock decision |
SVCServiceBookingClassBase.Ud_ExternalBookingStatus | Data Definition | Added Ud_ExternalBookingStatus for persisting external booking status |
Ud_SmartphoneProvisioning | Configuration Item | Service Form for configuring contracted and contractless variants |
Action - Order Acceptance | Wizard | Custom wizard for accepting orders |
Software Wareneingang | Wizard | Adds logic for IT Procurement to mark software as delivered |
Smartphone Provisioning Dialog | Dialog | |
Smartphone Provisioning Dataset View | Dataset View | |
Ud_Office_Catalog_Services_Tiles (Self Service Portal) | Dataset View | Custom Catalog display filtering articles based on employees managed locations |
IT-Procurement | Cost Center | Cost center to encode "company order" during shopping |
Software Wareneingang | Action | Cost center to encode "company order" during shopping |
Ud_ArticleStorage | Data Query | To allow for a data query that easily associates an article with its storage location the data query Ud_ArticleStorage was added. |
office_catalog | Navigation Item | To increase the usability for office employees a separate navigation object was added. The catalog displays different articles than the standard catalog. |
Action - Order Acceptance | Workflow | Custom Acceptance of order now using S4Hana based logic (if required) |
Action - RootITUp Accept Booking | Workflow | Notifies BProc about the final acceptance of a booking, completion Step |
Action - RootITUp FollowUp Processing | Workflow | Workflow to be used from a ticket, dispatches control to the responsible workflow implementations |
Actions - RootITUp S4Hana Handout Asset | Workflow | |
Approval - RootITUp Order Analysis | Workflow | Approval workflow for S4Hana based articles, respects beyond article and custom "free" order values |
Approval - RootITUp Smartphone Order Analysis | Workflow | |
Connector - RootITUp External Booking Status | Workflow | |
Provisioning - RootITUp Booking Processing | Workflow | Handles all S4Hana based article bookings, complex business logic resides within BProc |
Office Catalog
The visibility of the office catalog navigation item is managed by an expression looking up, if the user is responsible for any location known to Matrix42.
SUBQUERY(
SPSLocationClassBase AS L,
COUNT(L.*),
L.Ud_ResponsibleEmployees.ID = base.ID
) > 0
The displayed articles are managed by the Ud_Office Catalog Service Tiles (Self Service Portal). There a query filters the articles to match the locations the user is responsible for.
let filter = $format("ID IN SUBQUERY(SPSLocationClassBase AS L, L.Ud_StorageForArticles.ID, L.Ud_ResponsibleEmployees.ID = '{currentUser}')");
return filter;
Shopping Cart
We updated the shopping cart to include the company and individual order concepts. The following changes to the shopping cart are not included within the configuration project. They may be alternated within the productive environment to fit the current needs.
- custom_ResponsibleForLocations - Data model source
- Multiple Elements
- SPSLocationClassBase
- On Initialization
- Filter
- Context.CurrentUser
let filter = $format("ID IN SUBQUERY(SPSLocationClassBase AS L, L.ID, L.Ud_ResponsibleEmployees.ID = '{currentUser}')");return filter;
- Added Attribute IsOfficeEmployee
- custom_ResponsibleForLocations.$totalCount
return totalCount.$value > 0;
- Added Attribute IsNonOfficeEmployee
- custom_ResponsibleForLocations.IsOfficeEmployee
return !isOfficeEmployee.$value;
- Added Attribute DefaultDestinationType
- custom_ResponsibleForLocations.IsOfficeEmployee
// 2 : Company
// 1 : Individual
return (isOfficeEmployee.$value) ? 2 : 1; - Added Attribute IsIndividualOfficeEmployeeOrder
- custom_ResponsibleForLocations.IsOfficeEmployee
- Context.IsIndividualOrder
return isOfficeEmployee.$value && isIndividualOrder.$value;
- Context.DestinationType
- custom_ResponsibleForLocations.DefaultDestinationType
if (defaultDestinationType.$hasChanges && !!defaultDestinationType.$value){
return defaultDestinationType.$value;
}else{
return $value;
} - Context.IsCompanyOrder
- Context.DestinationType
return destinationType.$value == 2;
- Context.IsIndividualOrder
- Context.DestinationType
return destinationType.$value == 1;
- Added Enumeration Picker for Context.DestinationType
- Ud_DestinationTypePickup
- Disabled <=> custom_ResponsibleForLocations.IsNonOfficeEmployee
- SubmitData.orderInfo.CostCenterId
- Shopping_Cart_Context.return.Recipient.CostCenter.Id AS recipientCostCenter
- Context.DestinationType
// Company Wide Order -> Book on IT-Procurement
if (destinationType.$hasChanges){
if(destinationType.$value === 2){
// Obtain ID from SPSCostCenterClassBase
return 'A1B66E0F-E53E-ED11-19A3-00505685D9FB';
}else{
return recipientCostCenter.$value;
}
}else{
// Default :
return $oldValue != $value ? $value : $value || recipientCostCenter.$value;
} - Added IsInvalidStoredArticleOrder - Error Form Message
- custom_StoredArticles.IsInvalidStoredArticleOrder
- Error
- Added IsIndividualOfficeEmployeeOrder - Warning Form Message
- custom_StoredArticles.IsIndividualOfficeEmployeeOrder
- Warning
- Context.IsValidCompanyOrder
- Context.IsCompanyOrder
- custom_StoredArticles.IsValidStoredArticleOrder
return isCompanyOrder.$value && isValidStoredArticleOrder.$value;
- Added IsValidCompanyOrder - Info Form Message
- Context.IsValidCompanyOrder
- Info
- Limit selectable addresses of orderInfo.DeliveryLocationId
LEN(T(SPSAddressClassBase).City) > 0 AND LEN(T(SPSAddressClassBase).Street) > 0 AND LEN(T(SPSAddressClassBase).ZIP) > 0 AND Country > 0 AND Type=4 AND State=1
- custom_StoredArticles - Data model source
- Multiple Elements
- Ud_ArticleStorage Data Query
- On Data Update
- Filter
- Cart_Items.return.Items
if (items.$value.length == 0){
return 'ArticleId IS NULL';
}else{
let ids = [];
for(let i=0; i < items.$value.length; i++){
ids.push(items.$value[i].Service.Id);
}
let filter = "ArticleId IN ('" + ids.join("','") + "')";
return filter;
} - Added Attribute IsValidStoredArticleOrder to determine validity of an office order
- Context.IsCompanyOrder
- custom_ResponsibleForLocations.SPSLocationClassBase AS responsibleItems
- custom_StoredArticles.return AS givenItems
- Cart_Items.return.Items
- SubmitData.orderInfo.DeliveryLocationId
if (
isCompanyOrder.$value &&
responsibleItems.$value &&
givenItems.$value &&
items.$value && items.$value.length > 0
) {
// Can never send storage related items to custom address
if (!isDeliveryToAddress.$value){
console.log("The delivery is going to a custom location.");
return false;
}
// A) Company has to go to location
if (!deliveryLocationId.$value){
console.log("The delivery is missing a location.");
return false;
}
let responsible = new Set();
let stored = new Set();
let isValid = true;
// B) Setup location cache where this user is responsible
for (let i = 0; i < responsibleItems.$value.length; i++){
responsible.add(responsibleItems.$value[i].ID);
}
if (!responsible.has(deliveryLocationId.$value)){
console.log("The user is not responsible for the delivery location.");
return false;
}
// C) Setup article cache for the desired location
for (let i = 0; i < givenItems.$value.length; i++){
if (givenItems.$value[i].LocationId == deliveryLocationId.$value){
stored.add(givenItems.$value[i].ArticleId);
}
}
// D) Determine if all ordered articles are validly stored
for (let i = 0; i < items.$value.length && isValid; i++){
let articleId = items.$value[i].Service.Id;
isValid = stored.has(articleId);
if(!isValid){
console.log("The article " + articleId + " can not be handled.");
console.log(stored);
console.log(responsible);
console.log(givenItems.$value);
}
}
return isValid;
}else{
return true;
}
- Added Attribute IsInvalidStoredArticleOrder
return !isValidStoredArticleOrder.$value;