Account Plan LWC Reference

The tpm-account-plan LWC is a service component that loads a TPM account plan, exposing methods to update the account plan state, and events to keep all UI components of the account plan page in sync when the account plan state changes.
Important

Important

The content in this Consumer Goods Cloud Trade Promotion Management documentation is confidential and may be viewed only by customers or partners as authorized by Salesforce, and copying and further distribution is prohibited without prior written consent from Salesforce. The content is the highly confidential and proprietary information of Salesforce and is protected under the confidentiality obligations of your Agreement with Salesforce. Accordingly, the content may be used only as necessary in order to implement the Consumer Goods Cloud Trade Promotion Management functionality.

Properties

account-plan-id: Id. Required. The ID of the account plan record to load.

Namespace

cgcloud

Events

Here’s the event payload structure.

{
    detail : {
        value: <<new value of the property>>,
        property: <<property name>>,
        recordId: <<promotionId>>
    }
}

onstatuschange

This event is triggered when the lifecycle state of the TPM account plan component changes. Status changes are triggered by lifecycle operations on the account plan record.

{
    detail : {
        value: 'VALID',
        property: 'status',
        recordId: 'a2WTC0000000F772AE'
    }
}

The possible values are:

  • LOADING: The account plan is being loaded.
  • VALID: The account plan is loaded and can be interacted with.
  • SAVING: The account plan is being saved to the database.
  • ERROR: An irrecoverable error has occurred.

oncalculationstatuschange

This event is triggered when the account plan grids are calculated or recalculated.

{
    detail : {
        value: 'LOADING',
        property: 'calculationStatus',
        recordId: 'a2WTC0000000F772AE'
    }
}

The possible values are:

  • LOADING: The calculations are being processed, or the engine is loading.
  • VALID: The calculations are completed, and values can be requested.
  • ERROR: An irrecoverable error has occurred.
  • DISABLED: The calculations engine is disabled for the account plan.

oncategoryfilterchange

This event is triggered when the account plan’s selected product category filter changes. The event contains the selected category product ID.

{
    detail : {
        value: '01pXXXXXXXXXXXXXXX000',
        property: 'categoryFilter',
        recordId: 'a2WTC0000000F772AE'
    }
}

onkpisubsetsfilterchange

This event is triggered when the account plan subset filter changes. The event contains the selected category product ID.

{
    detail : {
        value: 'BaselineManagement',
        property: 'kpiSubsetFilter',
        recordId: 'a2WTC0000000F772AE'
    }
}

Example Implementation

Here’s an example of how to use the tpm-account-plan component.

<!-- YourComponent.html -->
<template>
   <cgcloud-tpm-account-plan
      account-plan-id={recordId} <!-- Id of the account plan record -->
      <!-- Events -->
      oncategoryfilterchange={onCategoryFilterChange}
      oncalculationstatuschange={onCalculationStatusChange}
   </cgcloud-tpm-account-plan>
   
   <!-- Your Component code -->
</template>
<!-- YourComponent.js-meta.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>55.0</apiVersion>
    <isExposed>true</isExposed>
    <targets>
        <target>lightning__RecordPage</target>
    </targets>
    <targetConfigs>
        <targetConfig targets="lightning__RecordPage">
            <objects>
                <object>cgcloud__Promotion__c</object>
            </objects>
        </targetConfig>
    </targetConfigs>
    <runtimeNamespace>cgcloud</runtimeNamespace>
</LightningComponentBundle>
import {
    LightningElement,
    api
} from 'lwc';

// Import the TPMManualInput class to create new instances
import {
    TPMManualInput
} from 'c/tpmGenericUtils';

export default class SampleAccountPlanTester extends LightningElement {
    @api recordId; // Record Id provided by the LWC framework

    currentCategoryId = '';
    currentCalculationStatus = 'LOADING';

    onCategoryFilterChange(event) {
        // Store currently selected category
        this.currentCategoryId = event.detail.value;
    }

    onCalculationStatusChange(event) {
        // Store current status of calculation engine
        this.currentCalculationStatus = event.detail.value;
    }

    // In this method, we will be adding a new manual input to the grid.
    // This can, for instance, be executed in the click of a button or after
    // some user interaction
    async addNewManualInputs() {
        const tpmAccountPlan = this.template.querySelector('cgcloud-tpm-account-plan');

        // Extract the current manual inputs
        const currentManualInputs = tpmAccountPlan.getProperty('manualInputs');

        // You can read information from the current Manual Inputs:
        currentManualInputs.forEach((mi) => {
            console.log(mi.getKPICode()); // 'ALMD'
            console.log(mi.getPeriodDateFrom()); // Date
            console.log(mi.getPeriodDateThru()); // Date
            console.log(mi.ProductId()); // '01qXXXXXXXXXXXXXXX'
            console.log(mi.getValue()); // 133
            console.log(mi.isObsolete()); // false
        });

        // Example: KPI Code to set the manual input to
        const kpiCode = 'ABCD';

        // Example: Product Id to set the manual input to. If null,
        // the manual input will be applied to the "Total" for the KPI
        // productId can be any level on the product hierarchy that is part of 
        // the calculation (SubCategory, Brand, etc...)
        const productId = '01tXXXXXXXXXXXXXXX';

        // Methods used to extract data from Grid require the Grid to be in valid
        // status. If trying to extract data from grid when not in the correct status
        // an exception will be thrown
        if (this.currentCalculationStatus !== 'VALID') {
            throw new Error('Grid not in VALID status');
        }

        // Extract the periods information from the grid
        const periods = await tpmAccountPlan.getPeriods();

        // We find the period where we want to set the manual input.
        // You can find periods by name or use the periods "dateFrom, "dateThru" and "periodtype"
        // attributes to search for an specific period.
        // In this example, we will set the manual input on the "Total" period
        // that uses an specific label
        const manualInputPeriod = periods.find((p) => p.periodtype === 'Total');

        // Create the new instance
        const newManualInput = new TPMManualInput({
            kpiCode: kpiCode,
            period: manualInputPeriod,
            productId: productId,
            value: 123 // Value to set
        });

        // Create a new array with our new manual input appended
        const newManualInputArray = [currentManualInputs, newManualInput];

        // Set the manual inputs
        // If the array length is greater than the limit of 
        // manual inputs, the "set" operation will throw an error
        tpmAccountPlan.setManualInputs(newManualInputArray);

        // After setting the new manual inputs, the Grid will be automatically
        // reloaded and re-rendered with the new values in place.

        // At this point, manual inputs are still not saved to SFDC database.
        // the user must save & calculate the account plan
    }
}

TPM Account Plan Component Methods

Here are the methods supported by the tpm-account-plan LWC.

exportKPIs

This method returns a promise resolving to the values of the KPIs for the selected KPI subsets or names, levels, and period types.

API Version

58.0

Signature

exportKPIs(options)

Properties

Name Type Description Required or Optional
options.subsets List<String> List of loaded KPI subsets to retrieve data from.

You can get a list of loaded subsets using the getKPISubsets() method.

Provide either the KPI subsets or the KPI names.

Optional
options.kpis List<String> List of KPI names to retrieve data from.

You can get a list of loaded KPI names using the getKPIs() method.

Provide either the KPI subsets or the KPI names.

Optional
options.levels List<String> List of loaded levels to retrieve data from. 

You can get a list of loaded levels using the getLevelNames() method.

Optional
options.periods List<String> List of loaded period types to retrieve data.

You can get a list of loaded period types using the getPeriodTypes() method.

Optional
options.format List<String> Format in which the response is returned.

Possible formats are:

  • JSON: The response is an array of JavaScript objects.
  • Serialized: The response is a JSON string of JavaScript objects.
  • CSV: The response is a CSV string.

The default format is JSON.

Optional

The returned data is a list of rows (JavaScript objects or CSV rows). Each row represents the value of the KPI for the determined level. Each row contains values for all the periods specified in the request.

Example Implementation

const api = this.template.querySelector('cgcloud-tpm-promotion');

// Export options, the possible values can be extracted using
// the other described methods
const exportOptions = {
    subsets: ["Planning"], // Subsets to request data
    periods: [
        "Total",
        "Week"
    ],
    levels: [
        "Total",
        "Category",
        "Product"
    ],
    format: "json"
};

// Correct Scenario
api.getProperty('calculationStatus'); // 'VALID'

api.exportKPIs(exportOptions)
    .then((data) => {
        // Example response as CSV
        //
        // kpiName,Category,Product,AP_LBL_TOTAL,03/2022,04/2022
        // SampleKPI1,,,246,123,123
        // SampleKPI1,01tTC0000000001AAA,,246,123,123
        // SampleKPI1,01tTC0000000001AAA,01tTC0000000002AAA,246,123,123
        // SampleKPI2,,,1974,987,987
        // SampleKPI2,01tTC0000000001AAA,,1974,987,987
        // SampleKPI2,01tTC0000000001AAA,01tTC0000000002AAA,1974,987,987

        // Example response as JSON
        //
        // [{
        //    kpiName: "SampleKPI1",
        //    Category: null,
        //    Product: null,
        //    AP_LBL_TOTAL: 246,
        //    "03/2022": 123,
        //    "04/2022": 123     
        // }, {
        //    kpiName: "SampleKPI1",
        //    Category: "01tTC0000000001AAA",
        //    Product: null,
        //    AP_LBL_TOTAL: 246,
        //    "03/2022": 123,
        //    "04/2022": 123
        // },{
        //    kpiName: "SampleKPI1",
        //    Category: "01tTC0000000001AAA",
        //    Product: "01tTC0000000002AAA",
        //    AP_LBL_TOTAL: 246,
        //    "03/2022": 123,
        //    "04/2022": 123
        // },{
        //    kpiName: "SampleKPI2",
        //    Category: null,
        //    Product: null,
        //    AP_LBL_TOTAL: 1974,
        //    "03/2022": 987,
        //    "04/2022": 987
        // },{
        //    kpiName: "SampleKPI2",
        //    Category: "01tTC0000000001AAA",
        //    Product: null,
        //    AP_LBL_TOTAL: 1974,
        //    "03/2022": 987,
        //    "04/2022": 987
        // },{
        //    kpiName: "SampleKPI2",
        //    Category: "01tTC0000000001AAA",
        //    Product: "01tTC0000000002AAA",
        //    AP_LBL_TOTAL: 1974,
        //    "03/2022": 987,
        //    "04/2022": 987
        // }]


        // We can access the properties on the result:
        const firstRecord = data[0];

        console.log(firstRecord["kpiName"]); // "SampleKPI1"
        // Since we request the total period, 
        // we can read the total period value
        console.log(firstRecord["AP_LBL_TOTAL"]); // 246
        // We can also read specific periods information
        console.log(firstRecord["03/2022"]); // 123
        // We can also know which level the row references 
        console.log(firstRecord["Category"]); // null
        console.log(firstRecord["Product"]); // null
        // Since Category is null, it means this data row 
        // represents the total value for KPI "SampleKPI1" 

        // For last record
        const lastRecord = data[data.length - 1];

        console.log(lastRecord["kpiName"]); // "SampleKPI2"
        // Since we request the total period, 
        // we can read the total period value
        console.log(lastRecord["AP_LBL_TOTAL"]); // 1974
        // We can also read specific periods information
        console.log(lastRecord["03/2022"]); // 987
        // We can also know which level the row references 
        console.log(lastRecord["Category"]); // "01tTC0000000001AAA"
        console.log(lastRecord["Product"]); // "01tTC0000000002AAA"
        // Since Product is not null, it means this data row 
        // represents the value for KPI "SampleKPI2" for that
        // specific product
    });

// Error Scenario
api.getProperty('calculationStatus'); // 'LOADING'

api.exportKPIs(exportOptions)
    .catch((error) => {
        console.log(error.message); // CalculationStatus is not "VALID". Current Status "LOADING"
    });

getProperty

Imperatively retrieve the account plan state properties.

API Version

59.0

Signature

getProperty(propName)

The available properties to retrieve are:

  • status
  • calculationStatus
  • manualInputs
  • kpiSubsetFilter
  • categoryFilter

getLevelNames

This method returns a promise resolving to the list of levels that are currently loaded in the calculation engine. If the calculation status isn’t valid, the method returns an error.

API Version

59.0

Signature

getLevelNames()

Example Implementation

const api = this.template.querySelector('cgcloud-tpm-account-plan');

// Correct Scenario
api.getProperty('calculationStatus'); // 'VALID'

api.getLevelNames()
    .then((levels) => {
        console.log(levels); // [ "Brand", "Product"]
    });

// Error Scenario
api.getProperty('calculationStatus'); // 'LOADING'

api.getLevelNames()
    .catch((error) => {
        console.log(error.message); // CalculationStatus is not "VALID". Current Status "LOADING"
    });

getKPISubsets

This method returns a promise resolving to the list of KPI subsets that are currently loaded in the calculation engine. If the calculation status isn’t valid, the method returns an error.

API Version

59.0

Signature

getKPISubsets()

Example Implementation

const api = this.template.querySelector('cgcloud-tpm-account-plan');

// Correct Scenario
api.getProperty('calculationStatus'); // 'VALID'

api.getKPISubsets()
    .then((subsets) => {
        console.log(subsets); // ["Planning", ...
    });

// Error Scenario
api.getProperty('calculationStatus'); // 'LOADING'

api.getKPISubsets()
    .catch((error) => {
        console.log(error.message); // CalculationStatus is not "VALID". Current Status "LOADING"
    });

getKPIs

This method returns a promise resolving to the list of KPIs that are currently loaded in the calculation engine. If the calculation status isn’t valid, the method returns an error.

API Version

59.0

Signature

getKPIs()

Example Implementation

const api = this.template.querySelector('cgcloud-tpm-account-plan');

// Correct Scenario
api.getProperty('calculationStatus'); // 'VALID'

api.getKPIs()
    .then((kpis) => {
        // 0 
        console.log(kpis[0].id); // "0"
        console.log(kpis[0].name); // "BasePrice"
        console.log(kpis[0].kpitype); // "account"
        console.log(kpis[0].skipped); // ["Tactic"]
        console.log(kpis[0].type); // "read"
        console.log(kpis[0].valuetype); // "Price"
    });

// Error Scenario
api.getProperty('calculationStatus'); // 'LOADING'

api.getKPIs()
    .catch((error) => {
        console.log(error.message); // CalculationStatus is not "VALID". Current Status "LOADING"
    });

getPeriods

This method returns a promise resolving to the list of periods that are currently loaded in the calculation engine. If the calculation status isn’t valid, the method returns an error.

API Version

59.0

Signature

getPeriods()

Example Implementation

const api = this.template.querySelector('cgcloud-tpm-account-plan');

// Correct Scenario
api.getProperty('calculationStatus'); // 'VALID'

api.getPeriods()
    .then((periods) => {
        // 0 
        console.log(periods[0].id); // "0"
        console.log(periods[0].name); // "AP_LBL_TOTAL" (label of the period)
        console.log(periods[0].periodtype); // "Total"
        console.log(periods[0].dateFrom); // null
        console.log(periods[0].dateThru); // null
        // 1 
        console.log(periods[1].id); // 1
        console.log(periods[1].name); // "36/2022" // label in case of label is specified alternativly it returns the ....
        console.log(periods[1].periodtype); // "Week"
        console.log(periods[1].dateFrom); // 1661731200000 timestamp
        console.log(periods[1].dateThru); // 1662249600000 timestamp
    });

// Error Scenario
api.getProperty('calculationStatus'); // 'LOADING'

api.getPeriods()
    .catch((error) => {
        console.log(error.message); // CalculationStatus is not "VALID". Current Status "LOADING"
    });

getPeriodTypes

This method returns a promise resolving to the list of period types that are currently loaded in the calculation engine. If the calculation status isn’t valid, the method returns an error.

API Version

59.0

Signature

getPeriodTypes()

Example Implementation

const api = this.template.querySelector('cgcloud-tpm-account-plan');

// Correct Scenario
api.getProperty('calculationStatus'); // 'VALID'

api.getPeriodTypes()
    .then((periodTypes) => {
        console.log(periodTypes); // ["Total", "Week"]
    });

// Error Scenario
api.getProperty('calculationStatus'); // 'LOADING'

api.getPeriodTypes()
    .catch((error) => {
        console.log(error.message); // CalculationStatus is not "VALID". Current Status "LOADING"
    });

setManualInputs

This method sets an array of manual inputs in the account plan service component.

Manual grid edits are an array of TPMManualInput instances. You can add new entries or remove entries from the existing array of elements.

API Version

60.0

Signature

setManualInputs(manualInputs)

Example Implementation

// Import the TPMManualInput class to create new instances
import {
    TPMManualInput
} from 'cgcloud/tpmGenericUtils';


// In this method, we will be adding a new manual input to the grid.
// This can, for instance, be executed in the click of a button or after
// some user interaction
async addNewManualInputs() {
    const tpmAccountPlan = this.template.querySelector('cgcloud-tpm-account-plan');

    // Extract the current manual inputs
    const currentManualInputs = tpmAccountPlan.getProperty('manualInputs');

    // You can read information from the current Manual Inputs:
    currentManualInputs.forEach((mi) => {
        console.log(mi.getKPICode()); // 'ALMN'
        console.log(mi.getPeriodDateFrom()); // Date
        console.log(mi.getPeriodDateThru()); // Date
        console.log(mi.ProductId()); // '03sXXXXXXXXXXXXXXX'
        console.log(mi.getValue()); // 133
    });

    // Example: KPI code to set the manual input to
    const kpiCode = 'ABCD';

    // Example: Product Id to set the manual input to. If null,
    // the manual input will be applied to the "Total" for the KPI
    // productId can be any level on the product hierarchy that is part of 
    // the calculation (SubCategory, Brand, etc)
    const productId = '01tXXXXXXXXXXXXXXX';

    // Methods used to extract data from Grid require the Grid to be in valid
    // status. If trying to extract data from grid when not in the correct status
    // an exception will be thrown
    if (tpmAccountPlan.getProperty('calculationStatus') !== 'VALID') {
        throw new Error('Grid not in VALID status');
    }

    // Extract the periods information from the grid
    const periods = await tpmAccountPlan.getPeriods();

    // We find the period where we want to set the manual input.
    // You can find periods by name or use the periods "dateFrom, "dateThru" and "periodtype"
    // attributes to search for an specific period.
    // In this example, we will set the manual input on the "Total" period
    // that uses an specific label
    const manualInputPeriod = periods.find((p) => p.periodtype === 'Total');

    // Create the new instance
    const newManualInput = new TPMManualInput({
        kpiCode: kpiCode,
        period: manualInputPeriod,
        productId: productId,
        value: 123 // Value to set
    });

    // Create a new array with our new manual input appended
    const newManualInputArray = [currentManualInputs, newManualInput];

    // Set the manual inputs
    tpmAccountPlan.setManualInputs(newManualInputArray);

    // After setting the new manual inputs, the grids will be automatically
    // reloaded and re-rendered with the new values in place.

    // At this point, manual inputs are still not saved to SFDC database.
    // the user must save the account plan
}