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.

    1. custom_ResponsibleForLocations - Data model source
      1. Multiple Elements
      2. SPSLocationClassBase
      3. On Initialization
      4. 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;
    2. Context.DestinationType
      1. custom_ResponsibleForLocations.DefaultDestinationType
        if (defaultDestinationType.$hasChanges && !!defaultDestinationType.$value){
        return defaultDestinationType.$value;
        }else{
        return $value;
        }
    3. Context.IsCompanyOrder
      1. Context.DestinationType
        return destinationType.$value == 2;
    4. Context.IsIndividualOrder
      1. Context.DestinationType
        return destinationType.$value == 1;
    5. Added Enumeration Picker for Context.DestinationType
      1. Ud_DestinationTypePickup
      2. Disabled <=> custom_ResponsibleForLocations.IsNonOfficeEmployee
    6. SubmitData.orderInfo.CostCenterId
      1. Shopping_Cart_Context.return.Recipient.CostCenter.Id AS recipientCostCenter
      2. 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;
        }
    7. Added IsInvalidStoredArticleOrder - Error Form Message
      1. custom_StoredArticles.IsInvalidStoredArticleOrder
      2. Error
    8. Added IsIndividualOfficeEmployeeOrder - Warning Form Message
      1. custom_StoredArticles.IsIndividualOfficeEmployeeOrder
      2. Warning
    9. Context.IsValidCompanyOrder
      1. Context.IsCompanyOrder
      2. custom_StoredArticles.IsValidStoredArticleOrder
        return isCompanyOrder.$value && isValidStoredArticleOrder.$value;
    10. Added IsValidCompanyOrder - Info Form Message
      1. Context.IsValidCompanyOrder
      2. Info
    11. 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
    12. custom_StoredArticles - Data model source
      1. Multiple Elements
      2. Ud_ArticleStorage Data Query
      3. On Data Update
      4. 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;