Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

In this section you will learn more about Customs Forms.

Lab Info

Lesson: Product Discount Data Management (Standalone Custom Form)

Target Audience: Certified Configuration Engineer

Estimated Time to complete: TBD

Requirements & Solution Author: Petr Rys

Solution Developer & Lab Author: Marcin Ɓuczakuczak

User Story / Requirements

Create a standalone Custom Form to help pricing managers manage discounts per Product Groups and Families.
Product Group is part of Product Master, Product Family is assigned per Product Group.

...

Anchor
Details
Details
isMissingRequiredParameterstrue
Details

Product Discount Data Management Custom Form allows user to perform these tasks:

Change Data - Pick a table, Change values in the table, without adding any rows

Add new Product Group - Add a group, Assign it to the product family, Assign to it all the required discounts for all the required levels

Discount for each additional level has to be >= to the previous level, otherwise validation fails

Add a product family - Re assign product groups to reflect new Product Family,

Add new discount level to existing product family - Create new discount levels. Levels must be continuous.

...

Assign new discounts for new levels. Discount for each additional level has to be >= to the previous level, otherwise validation fails

Learning Outcomes

At the end of the Lab, you should be able to:

  • Create Standalone Custom Form, Custom Form Type

  • Utilize Input Matrix as Custom Form input

  • Understand Custom Forms Workflow

Provided resources

Logics:

sCFO_ProductDiscountLib

...

ProductFamilyMapping, DiscountLevelDefinition, Discount

Acceptance Criteria

  • User can access a standalone Custom Form within the Analytics section to complete tasks listed in the Details section.

...

  • After the user submits the form, changes should be saved in the corresponding company parameter tables. If a workflow has been added to the form, the changes should be saved after approval.

  • Sample solution

...

Step-by-step solution

Develop the logic and test in Studio

  1. Go to the Pricefx Studio and create the following logics.

...

Code Block
languagegroovy
import net.pricefx.server.dto.calculation.ConfiguratorEntry

// Get value of the first input from the OtionInput.groovy, only if it exists
String selectedType = 
// Use configuratorSwitch method. Pass selectedType as a parameter.

/**
 * This method is used to select and configure different types of ConfiguratorEntries.
 * It also loads the correct messages for each type.
 *
 * @param selectedType The type of ConfiguratorEntry to be used. This could be 'CHANGE_DATA', 'NEW_FAMILY', or 'NEW_GROUP'.
 * @return A ConfiguratorEntry instance configured based on the selectedType.
 * If the getterMethod or message for the selectedType do not exist, the method will return null.
 */
ConfiguratorEntry configuratorSwitch(String selectedType) {
    Script CONFIG_UTILS = libs.sCFO_ProductDiscountLib.CfoConfiguratorUtils
    Script CONST_CONFIG = libs.sCFO_ProductDiscountLib.ConstConfig

    def getterMap = [
            (CONST_CONFIG.CHANGE_DATA) : CONFIG_UTILS.&getChangeDataConfiguratorEntry,
            (CONST_CONFIG.NEW_FAMILY)  : CONFIG_UTILS.&getAddFamilyConfiguratorEntry,
            (CONST_CONFIG.NEW_GROUP)   : CONFIG_UTILS.&getAddGroupConfiguratorEntry,
    ]

    def messageMap = [
            (CONST_CONFIG.CHANGE_DATA) : CONST_CONFIG.CFO_CONFIGURATOR_CONFIG.PARAGRAPH_MESSAGE_CHANGE,
            (CONST_CONFIG.NEW_FAMILY)  : CONST_CONFIG.CFO_CONFIGURATOR_CONFIG.PARAGRAPH_MESSAGE_ADD_FAMILY,
            (CONST_CONFIG.NEW_GROUP)   : CONST_CONFIG.CFO_CONFIGURATOR_CONFIG.PARAGRAPH_MESSAGE_ADD_GROUP,
    ]

    def getterMethod = getterMap[selectedType]
    def message = messageMap[selectedType]

    if (getterMethod && message) {
        return configureEntries(getterMethod, message)
    }
}

/**
 * This method applies configuration to entries.
 *
 * @param getterMethod Method reference for getting configurator entry.
 * @param message The message to be set as paragraph header in configurator entry.
 * @return ConfiguratorEntry The modified configurator entry with new paragraph header.
 */
ConfiguratorEntry configureEntries(def getterMethod, String message) {
    ConfiguratorEntry configuratorEntry = getterMethod.call()
    configuratorEntry.setMessage(message)
    return configuratorEntry
}

EXPECTED RESULT

...

DEBAGINGDEBUGGING

  • Open logic.json in sCFO_ProductDiscountHeader_Configurator.

  • Open Studio Editor.

  • Click on the Inputs tab.

  • Set the Context to CONFIGURATOR.

  • Test Logic

  • Click on the Results tab and check output

...

Task

Code samples

Get user inputs from current item assign it to inputs variable

Code Block
api.currentItem()?.inputs?.get(0)?.value

Get individual field values from user inputs:

Code Block
inputs?.get("managementOptionsInput")

Get "Discount" lookup table Id assign it to the discountID variable.

Code Block
def discountID = api.findLookupTable("Discount").id

Create filters:

  • 'ProductGroup' equal oldName

  • 'lookupTable.id' equal discountID

Code Block
def discountFilters = [
        Filter.equal("ProductGroup", oldName),
        Filter.equal('lookupTable.id', discountID)
]

Update "ProductFamilyMapping" lookup table. To obtain accurate data, make use of filters.

Code Block
api.find('LTV', 0, *discountFilters).collect {
    def entry = [
            lookupTableName: "ProductFamilyMapping",
            id             : it.id,
            valueType      : it.valueType,
            typedId        : it.typedId,
            name           : newName,
            value          : it.value
    ]
    api.addOrUpdate("LTV", entry)
}

Use discountEntries and update "Discount" lookup table

Code Block
discountEntries.each {
    api.addOrUpdate("MLTV2", [
            lookupTableName: "Discount",
            key1           : it["Product Group"].value,
            key2           : it["Discount Level"].value,
            attribute1     : it["Target Discount %"].value,
            attribute2     : it["Max Discount %"].value
    ])
}

Get "DiscountLevelDefinitionMatrix" table outputs from current item

Code Block
languagegroovy
api.currentItem()?.outputs?.find { it.resultName == "DiscountLevelDefinitionMatrix" }

If output is null get an empty list

Code Block
languagegroovy
discountLevelDefinitionTable = discountLevelDefinitionTable ? discountLevelDefinitionTable : []

Filter the rows in their respective tables based on the values of Map.

Code Block
languagegroovy
def discountLevelDefinitionEntries = discountLevelDefinitionTable.result.entries.findAll { it['Product Family'] instanceof Map }

References

Custom Forms (Reference)

Custom Forms Configuration How-To(s)

Unity Documentation

Custom Forms

Custom Forms General Settings

Custom Forms Header Logics

Company Parameters

Groovy API

setConfigParameter

Other

Pricefx chatbot AI