@merchi/sdk 1.42.4 → 1.42.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -131,7 +131,7 @@ var Job = /** @class */ (function (_super) {
131
131
  __metadata("design:type", Object)
132
132
  ], Job.prototype, "productionStatus", void 0);
133
133
  __decorate([
134
- Job.property(),
134
+ Job.property({ type: String }),
135
135
  __metadata("design:type", Object)
136
136
  ], Job.prototype, "productionQuotingSpec", void 0);
137
137
  __decorate([
@@ -120,6 +120,36 @@ function areaCostFactor(field, sel, groupQuantities) {
120
120
  });
121
121
  return { setup: setup, unitList: unitList };
122
122
  }
123
+ function colourExtractCostFactor(field, sel, groupQuantities) {
124
+ var _a, _b, _c, _d;
125
+ var n = groupQuantities.length;
126
+ var zeros = { setup: 0, unitList: new Array(n).fill(0) };
127
+ // Extracted colours are not in the static options list. Count them, then
128
+ // apply the field fee once and the per-colour fee once per colour.
129
+ var colourCount = (sel === null || sel === void 0 ? void 0 : sel.colourCount) != null
130
+ ? sel.colourCount
131
+ : (_b = (_a = sel === null || sel === void 0 ? void 0 : sel.selectedOptionIds) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0;
132
+ var active = colourCount > 0 || Boolean(sel === null || sel === void 0 ? void 0 : sel.hasFiles);
133
+ if (!active)
134
+ return zeros;
135
+ var totalQty = groupQuantities.reduce(function (a, b) { return a + b; }, 0);
136
+ var setup = variationSetupCost(field, totalQty);
137
+ var unitList = variationUnitCosts(field, groupQuantities);
138
+ if (colourCount > 0) {
139
+ var colourSetup = variationSetupCost({
140
+ variationCost: field.colourVariationCost || 0,
141
+ variationCostDiscountGroup: (_c = field.colourVariationCostDiscountGroup) !== null && _c !== void 0 ? _c : null,
142
+ }, totalQty);
143
+ var colourUnits = variationUnitCosts({
144
+ variationUnitCost: field.colourVariationUnitCost || 0,
145
+ variationUnitCostDiscountGroup: (_d = field.colourVariationUnitCostDiscountGroup) !== null && _d !== void 0 ? _d : null,
146
+ }, groupQuantities);
147
+ setup += colourSetup * colourCount;
148
+ for (var i = 0; i < n; i++)
149
+ unitList[i] += colourUnits[i] * colourCount;
150
+ }
151
+ return { setup: setup, unitList: unitList };
152
+ }
123
153
  function costFactor(field, sel, groupQuantities) {
124
154
  var e_1, _a, e_2, _b;
125
155
  var n = groupQuantities.length;
@@ -127,6 +157,9 @@ function costFactor(field, sel, groupQuantities) {
127
157
  if (Number(field.fieldType) === FieldType.AREA) {
128
158
  return areaCostFactor(field, sel, groupQuantities);
129
159
  }
160
+ if (Number(field.fieldType) === FieldType.COLOUR_EXTRACT) {
161
+ return colourExtractCostFactor(field, sel, groupQuantities);
162
+ }
130
163
  if (isEmpty(field, sel)) {
131
164
  return { setup: 0, unitList: new Array(n).fill(0) };
132
165
  }
@@ -72,6 +72,56 @@ test('hidden conditional field is not costed', function () {
72
72
  var r = estimateQuote(rules, { quantity: 10, fieldValues: { 2: { selectedOptionIds: [201] } } });
73
73
  expect(r.cost).toBe(100);
74
74
  });
75
+ function colourExtractField() {
76
+ return {
77
+ id: 13, originalId: 13, position: 0, fieldType: 13, independent: true,
78
+ isSelectable: true, selectedBy: [],
79
+ variationCost: 180, variationUnitCost: 6.52,
80
+ variationCostDiscountGroup: null, variationUnitCostDiscountGroup: null,
81
+ colourVariationCost: 60, colourVariationUnitCost: 0.8,
82
+ colourVariationCostDiscountGroup: null,
83
+ colourVariationUnitCostDiscountGroup: null,
84
+ options: [],
85
+ };
86
+ }
87
+ test('colour extract with no colours or file does not add a charge', function () {
88
+ var rules = __assign(__assign({}, base), { product: { unitPrice: 1, minimumPrice: null, discountGroup: null }, fields: [colourExtractField()] });
89
+ var r = estimateQuote(rules, {
90
+ quantity: 30,
91
+ fieldValues: { 13: { selectedOptionIds: [], colourCount: 0, hasFiles: false } },
92
+ });
93
+ expect(r.cost).toBe(30);
94
+ expect(r.totalCost).toBe(33);
95
+ });
96
+ test('colour extract adds the field fee and each selected colour', function () {
97
+ var rules = __assign(__assign({}, base), { product: { unitPrice: 1, minimumPrice: null, discountGroup: null }, fields: [colourExtractField()] });
98
+ var r = estimateQuote(rules, {
99
+ quantity: 30,
100
+ fieldValues: { 13: { selectedOptionIds: [1, 2, 3], colourCount: 3 } },
101
+ });
102
+ // 30*1 + 180 + 6.52*30 + 3*60 + 3*0.80*30 = 657.6
103
+ expect(r.cost).toBe(657.6);
104
+ expect(r.taxAmount).toBe(65.76);
105
+ expect(r.totalCost).toBe(723.36);
106
+ });
107
+ test('colour extract counts selected option ids when colourCount is omitted', function () {
108
+ var rules = __assign(__assign({}, base), { product: { unitPrice: 1, minimumPrice: null, discountGroup: null }, fields: [colourExtractField()] });
109
+ var r = estimateQuote(rules, {
110
+ quantity: 30,
111
+ fieldValues: { 13: { selectedOptionIds: [9, 8] } },
112
+ });
113
+ // 30 + 180 + 195.6 + 2*60 + 2*0.8*30 = 573.6
114
+ expect(r.cost).toBe(573.6);
115
+ });
116
+ test('colour extract file without colours still charges the field fee', function () {
117
+ var rules = __assign(__assign({}, base), { product: { unitPrice: 1, minimumPrice: null, discountGroup: null }, fields: [colourExtractField()] });
118
+ var r = estimateQuote(rules, {
119
+ quantity: 30,
120
+ fieldValues: { 13: { colourCount: 0, hasFiles: true } },
121
+ });
122
+ // 30 + 180 + 6.52*30 = 405.6
123
+ expect(r.cost).toBe(405.6);
124
+ });
75
125
  test('area field multiplies height/width rate cards when dimensions set', function () {
76
126
  var rules = __assign(__assign({}, base), { product: { unitPrice: 1, minimumPrice: null, discountGroup: null }, fields: [{
77
127
  id: 14, originalId: 14, position: 0, fieldType: 14, independent: true,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@merchi/sdk",
3
- "version": "1.42.4",
3
+ "version": "1.42.6",
4
4
  "main": "dist/index.js",
5
5
  "type": "module",
6
6
  "repository": {
@@ -66,7 +66,7 @@ export class Job extends Entity {
66
66
  @Job.property({type: Number})
67
67
  public productionStatus?: number | null;
68
68
 
69
- @Job.property()
69
+ @Job.property({type: String})
70
70
  public productionQuotingSpec?: string | null;
71
71
 
72
72
  @Job.property()
@@ -79,6 +79,77 @@ test('hidden conditional field is not costed', () => {
79
79
  expect(r.cost).toBe(100);
80
80
  });
81
81
 
82
+ function colourExtractField(): PricingRules['fields'][number] {
83
+ return {
84
+ id: 13, originalId: 13, position: 0, fieldType: 13, independent: true,
85
+ isSelectable: true, selectedBy: [],
86
+ variationCost: 180, variationUnitCost: 6.52,
87
+ variationCostDiscountGroup: null, variationUnitCostDiscountGroup: null,
88
+ colourVariationCost: 60, colourVariationUnitCost: 0.8,
89
+ colourVariationCostDiscountGroup: null,
90
+ colourVariationUnitCostDiscountGroup: null,
91
+ options: [],
92
+ };
93
+ }
94
+
95
+ test('colour extract with no colours or file does not add a charge', () => {
96
+ const rules: PricingRules = {
97
+ ...base,
98
+ product: { unitPrice: 1, minimumPrice: null, discountGroup: null },
99
+ fields: [colourExtractField()],
100
+ };
101
+ const r = estimateQuote(rules, {
102
+ quantity: 30,
103
+ fieldValues: { 13: { selectedOptionIds: [], colourCount: 0, hasFiles: false } },
104
+ }) as QuoteResult;
105
+ expect(r.cost).toBe(30);
106
+ expect(r.totalCost).toBe(33);
107
+ });
108
+
109
+ test('colour extract adds the field fee and each selected colour', () => {
110
+ const rules: PricingRules = {
111
+ ...base,
112
+ product: { unitPrice: 1, minimumPrice: null, discountGroup: null },
113
+ fields: [colourExtractField()],
114
+ };
115
+ const r = estimateQuote(rules, {
116
+ quantity: 30,
117
+ fieldValues: { 13: { selectedOptionIds: [1, 2, 3], colourCount: 3 } },
118
+ }) as QuoteResult;
119
+ // 30*1 + 180 + 6.52*30 + 3*60 + 3*0.80*30 = 657.6
120
+ expect(r.cost).toBe(657.6);
121
+ expect(r.taxAmount).toBe(65.76);
122
+ expect(r.totalCost).toBe(723.36);
123
+ });
124
+
125
+ test('colour extract counts selected option ids when colourCount is omitted', () => {
126
+ const rules: PricingRules = {
127
+ ...base,
128
+ product: { unitPrice: 1, minimumPrice: null, discountGroup: null },
129
+ fields: [colourExtractField()],
130
+ };
131
+ const r = estimateQuote(rules, {
132
+ quantity: 30,
133
+ fieldValues: { 13: { selectedOptionIds: [9, 8] } },
134
+ }) as QuoteResult;
135
+ // 30 + 180 + 195.6 + 2*60 + 2*0.8*30 = 573.6
136
+ expect(r.cost).toBe(573.6);
137
+ });
138
+
139
+ test('colour extract file without colours still charges the field fee', () => {
140
+ const rules: PricingRules = {
141
+ ...base,
142
+ product: { unitPrice: 1, minimumPrice: null, discountGroup: null },
143
+ fields: [colourExtractField()],
144
+ };
145
+ const r = estimateQuote(rules, {
146
+ quantity: 30,
147
+ fieldValues: { 13: { colourCount: 0, hasFiles: true } },
148
+ }) as QuoteResult;
149
+ // 30 + 180 + 6.52*30 = 405.6
150
+ expect(r.cost).toBe(405.6);
151
+ });
152
+
82
153
  test('area field multiplies height/width rate cards when dimensions set', () => {
83
154
  const rules: PricingRules = {
84
155
  ...base,
@@ -142,6 +142,47 @@ function areaCostFactor(
142
142
  return { setup, unitList };
143
143
  }
144
144
 
145
+ function colourExtractCostFactor(
146
+ field: PricingField,
147
+ sel: FieldSelection | undefined,
148
+ groupQuantities: number[]
149
+ ): { setup: number; unitList: number[] } {
150
+ const n = groupQuantities.length;
151
+ const zeros = { setup: 0, unitList: new Array(n).fill(0) };
152
+ // Extracted colours are not in the static options list. Count them, then
153
+ // apply the field fee once and the per-colour fee once per colour.
154
+ const colourCount =
155
+ sel?.colourCount != null
156
+ ? sel.colourCount
157
+ : sel?.selectedOptionIds?.length ?? 0;
158
+ const active = colourCount > 0 || Boolean(sel?.hasFiles);
159
+ if (!active) return zeros;
160
+
161
+ const totalQty = groupQuantities.reduce((a, b) => a + b, 0);
162
+ let setup = variationSetupCost(field, totalQty);
163
+ const unitList = variationUnitCosts(field, groupQuantities);
164
+ if (colourCount > 0) {
165
+ const colourSetup = variationSetupCost(
166
+ {
167
+ variationCost: field.colourVariationCost || 0,
168
+ variationCostDiscountGroup: field.colourVariationCostDiscountGroup ?? null,
169
+ },
170
+ totalQty
171
+ );
172
+ const colourUnits = variationUnitCosts(
173
+ {
174
+ variationUnitCost: field.colourVariationUnitCost || 0,
175
+ variationUnitCostDiscountGroup:
176
+ field.colourVariationUnitCostDiscountGroup ?? null,
177
+ },
178
+ groupQuantities
179
+ );
180
+ setup += colourSetup * colourCount;
181
+ for (let i = 0; i < n; i++) unitList[i] += colourUnits[i] * colourCount;
182
+ }
183
+ return { setup, unitList };
184
+ }
185
+
145
186
  function costFactor(
146
187
  field: PricingField,
147
188
  sel: FieldSelection | undefined,
@@ -152,6 +193,9 @@ function costFactor(
152
193
  if (Number(field.fieldType) === FieldType.AREA) {
153
194
  return areaCostFactor(field, sel, groupQuantities);
154
195
  }
196
+ if (Number(field.fieldType) === FieldType.COLOUR_EXTRACT) {
197
+ return colourExtractCostFactor(field, sel, groupQuantities);
198
+ }
155
199
  if (isEmpty(field, sel)) {
156
200
  return { setup: 0, unitList: new Array(n).fill(0) };
157
201
  }
@@ -45,6 +45,11 @@ export interface PricingField {
45
45
  heightVariationUnitCostDiscountGroup?: DiscountGroup | null;
46
46
  widthVariationCostDiscountGroup?: DiscountGroup | null;
47
47
  widthVariationUnitCostDiscountGroup?: DiscountGroup | null;
48
+ /** Colour extract (fieldType 13): per selected colour, not a static option. */
49
+ colourVariationCost?: number;
50
+ colourVariationUnitCost?: number;
51
+ colourVariationCostDiscountGroup?: DiscountGroup | null;
52
+ colourVariationUnitCostDiscountGroup?: DiscountGroup | null;
48
53
  options: PricingOption[];
49
54
  }
50
55
 
@@ -82,6 +87,10 @@ export interface InventoryUnit {
82
87
  export interface FieldSelection {
83
88
  selectedOptionIds?: number[];
84
89
  value?: string | number | null;
90
+ /** Colour extract: number of chosen colours when ids are not in the rules. */
91
+ colourCount?: number;
92
+ /** Colour extract: an artwork file is attached, even if no colour was kept. */
93
+ hasFiles?: boolean;
85
94
  }
86
95
 
87
96
  export interface GroupSelection {