2025-02-16 - Supply Chain Transform Units examples
Jump to navigation
Jump to search
Calculate cost of outputUnit from many inputUnits
- the below values are the smallest unit of a transfromUnits operation
- the below values can be multiplied by the number of transfromUnits operations being submitted, eg if making 8 shirts and 12 hats all values get multiplied by 4
- frontend sends to backend each inputUnit used and the valueUse for each input calculatedProperties
- One outputUnit instance might use valueUse from multiple inputUnit instances
- outputUnit calculatedProperties.calculation must be performed for each inputUnit instance valueUse
- the resulting calculation value then needs to be divided by numberOfUnits.numberOfUnits to calculate the final unitTrackedProperty value
let transformConfigInputOutput = {
inputUnits: {
{unitTypeId(fabric)}: {
calculatedProperties:{
unitTypeTrackedPropertyId(remainingYards): {
integerOnly: false, // maybe not needed, in unitTypeTrackedProperty.precision
quantityReductionSetting: "clearPerUnit", // used by frontend to spread valueUse across multiple Units
valueUse: 5.7 // per transformUnitsObject quantity, maybe allow overwriting on frontend
},
},
},
{unitTypeId(bagOfButtons)}: {
calculatedProperties:{
unitTypeTrackedPropertyId(remainingButtons): {
integerOnly: false,
quantityReductionSetting: "clearPerUnit",
valueUse: 72
},
},
},
//..
},
outputUnits: [
{
unitTypeId: "shirt",
numberOfUnits: 2,
calculatedProperties: {
unitTypeTrackedPropertyId(shirtCost): {
calculationType: "calculateValue",
integerOnly: false, // maybe not needed, in unitTypeTrackedProperty.precision
combinationEquation: "[yardCost]+[buttonCost]+[stitchCost]", // default is to sum all calculateByProperties
calculateByProperties: {
yardCost: {
calculationType: "calculationPerInputUnit",
inputUnitValueUseCalcs:{ // used by frontend to calculate default values per inputUnit instances
inputUnitTypeId(fabric): {
unitTypeTrackedPropertyId(remainingYards): "[valueUse]*0.8"
}
},
// inputUnitValueUse.fabric.remainingYards in calculation is the value sent by frontend
calculation: "[inputUnitValueUse:{inputUnitTypeId(fabric)}:{unitTypeTrackedPropertyId(remainingYards)}]*[unitTypeTrackedProperty:{inputUnitTypeId(fabric)}:{unitTypeTrackedPropertyId(costPerYard)}]",
},
buttonCost: {
calculationType: "calculationPerInputUnit",
inputUnitValueUseCalcs:{ // used by frontend to calculate default values per inputUnit instances
inputUnitTypeId(fabric): {
unitTypeTrackedPropertyId(remainingYards): "[valueUse]*0.75"
}
},
calculation: "[inputUnitValueUse:{inputUnitTypeId(bagOfButtons)}:{unitTypeTrackedPropertyId(remainingButtons)}]*([unitTypeTrackedProperty:{inputUnitTypeId(fabric)}:{unitTypeTrackedPropertyId(costPerBag)}]/200)",
round: "round",
},
stitchCost: {
calculationType: "singleValue",
defaultValue: "30",
},
},
},
//..
}
},
{
unitTypeId: "hat",
numberOfUnits: 3,
calculatedProperties: {
unitTypeTrackedPropertyId(hatCost): {
calculationType: "calculateValue",
integerOnly: false,
combinationEquation: "[yardCost]+[buttonCost]+[stitchCost]",
calculateByProperties: {
yardCost: {
calculationType: "calculationPerInputUnit",
inputUnitValueUseCalcs:{ // used by frontend to calculate default values per inputUnit instances
inputUnitTypeId(fabric): {
unitTypeTrackedPropertyId(remainingYards): "[valueUse]*0.25"
}
},
calculation: "(inputUnitValueUse:{inputUnitTypeId(fabric)}:{unitTypeTrackedPropertyId(remainingYards)}]*[unitTypeTrackedProperty:{inputUnitTypeId(fabric)}:{unitTypeTrackedPropertyId(costPerYard)}]",
},
buttonCost: {
calculationType: "calculationPerInputUnit",
inputUnitValueUseCalcs:{ // used by frontend to calculate default values per inputUnit instances
inputUnitTypeId(fabric): {
unitTypeTrackedPropertyId(remainingYards): "[valueUse]*0.2"
}
},
calculation: "[inputUnitValueUse:{inputUnitTypeId(bagOfButtons)}:{unitTypeTrackedPropertyId(remainingButtons)}]*([unitTypeTrackedProperty:{inputUnitTypeId(fabric)}:{unitTypeTrackedPropertyId(costPerBag)}]/200)",
round: "round",
},
stitchCost: {
calculationType: "singleValue",
defaultValue: "12",
},
},
},
//..
}
},
//..
],
}
notes
- fabric has costPerYard property
- each fabric unit has yard unitTypeTrackedProperty and each outputUnit will specify how many yards from which fabric Unit it uses
- bagOfButtons has costPerBag property
- each bagOfButtons has 200 buttons in it, so divide costPerBag/200 to get per button cost
- each 2 shirts uses 80% of the transformUnits operations remainingYards used
- valueUse: 5.7, 80% = 4.56, per shirt: 2.28 yards
- each 3 hats uses 20% of the transformUnits operations remainingYards used
- valueUse: 5.7, 20% = 1.14, per hat: 0.38 yards
- each 2 shirts uses 75% of the transformUnits operations remainingButtons used
- valueUse: 72, 75% = 54, per shirt: 27 buttons
- each 3 hats uses 25% of the transformUnits operations remainingButtons used
- valueUse: 72, 25% = 18, per shirt: 6 buttons
Initial state
- fabricA has 7 remainingYards, costPerYard = 3
- fabricB has 100 remainingYards, costPerYard = 2.5
- bagOfButtonsA has 5 remainingButtons, costPerBag = 480
- bagOfButtonsB has 2 remainingButtons, costPerBag = 485
- bagOfButtonsB has 200 remainingButtons, costPerBag = 495
Request from Frontend
let transformUnitsOperation = {
numberOfOperations: 2,
outputUnits: [ // count should match total outputUnits.numberOfUnits * numberOfOperations
{ // 1 shirt Unit
unitTypeId: "shirt",
inputUnits: {
{unitTypeId(fabric)}:{
calculatedPropertyValueUse:{
unitTypeTrackedPropertyId(remainingYards): [
unitId(fabricA): 2.28
],
}
},
{unitTypeId(bagOfButtons)}:{
calculatedPropertyValueUse:{
unitTypeTrackedPropertyId(remainingButtons): [
unitId(bagOfButtonsA): 5,
unitId(bagOfButtonsB): 2,
unitId(bagOfButtonsC): 20
]
}
}
},
singleValues: { stitchCost: 30 }
},
{
unitTypeId: "shirt",
inputUnits: {
{unitTypeId(fabric)}:{
calculatedPropertyValueUse:{
unitTypeTrackedPropertyId(remainingYards): [
unitId(fabricA): 2.28
],
}
},
// bagOfButtons same as above
},
singleValues: { stitchCost: 30 }
},
{
unitTypeId: "shirt",
inputUnits: {
{unitTypeId(fabric)}:{
calculatedPropertyValueUse:{
unitTypeTrackedPropertyId(remainingYards): [
unitId(fabricA): 2.28
],
}
},
// bagOfButtons same as above
},
singleValues: { stitchCost: 30 }
},
{
unitTypeId: "shirt",
inputUnits: {
{unitTypeId(fabric)}:{
calculatedPropertyValueUse:{
unitTypeTrackedPropertyId(remainingYards): [
unitId(fabricA): 0.16
unitId(fabricB): 2.12
],
}
},
// bagOfButtons same as above
},
singleValues: { stitchCost: 30 }
},
{ // 1 hat Unit
unitTypeId: "hat",
inputUnits: {
{unitTypeId(fabric)}:{
calculatedPropertyValueUse:{
unitTypeTrackedPropertyId(remainingYards): [
unitId(fabricB): 0.38
],
}
},
{unitTypeId(bagOfButtons)}:{
calculatedPropertyValueUse:{
unitTypeTrackedPropertyId(remainingButtons): [
unitId(bagOfButtonsC): 6
]
}
}
},
singleValues: { stitchCost: 12 }
},
{
unitTypeId: "hat",
// inputUnits same as above
},
{
unitTypeId: "hat",
// inputUnits same as above
},
{
unitTypeId: "hat",
// inputUnits same as above
},
{
unitTypeId: "hat",
// inputUnits same as above
},
{
unitTypeId: "hat",
// inputUnits same as above
},
// total 4 shirts and 6 hats
]
}
Calculation
inputUnits
- reduce by total amount used
- fabricA usage is 2.28+2.28+2.28+0.16 = 7, this reduces remainingYards to 0 (would trigger this Unit to being inactive if fabric>remainingYards.inactiveIfZero=true)
- fabricB usage is 2.12, this reduces remainingYards to 99.84
outputUnits
Example, first shirt:
- yardCost: fabricA uses 2.28 * costPerYard 3 = 6.84
- buttonCost:
- bagOfButtonsA uses 5 * ( costPerBag 480 / 200) = 12
- bagOfButtonsB uses 2 * ( costPerBag 485 / 200) = 2.425
- bagOfButtonsB uses 20 * ( costPerBag 495 / 200) = 49.5
- total buttonCost = 63.925
- stitchCost = 30
- combinationEquation: "[yardCost]+[buttonCost]+[stitchCost]"
- 6.84+63.925+30 = 100.765
- final value entered into unitTrackedProperty shirtCost is 100.765