@shushed/helpers 0.0.223 → 0.0.224-main-20251222140743

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.
@@ -17,7 +17,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
17
17
  return (mod && mod.__esModule) ? mod : { "default": mod };
18
18
  };
19
19
  Object.defineProperty(exports, "__esModule", { value: true });
20
- exports.Order = exports.PurchaseOrderline = exports.StockMovement = exports.MarketingPref = exports.CustomerSegment = exports.Asset = exports.DevelopmentColour = exports.Category = exports.ProductCategory = exports.Product = exports.ProductDraft = exports.Total = exports.Money = exports.Country = exports.Currency = void 0;
20
+ exports.Order = exports.MarketingPref = exports.CustomerSegment = exports.Asset = exports.DevelopmentColour = exports.Category = exports.ProductCategory = exports.Product = exports.ProductDraft = exports.Total = exports.Money = exports.Country = exports.Currency = void 0;
21
21
  var currency_schema_json_1 = require("./currency.schema.json");
22
22
  Object.defineProperty(exports, "Currency", { enumerable: true, get: function () { return __importDefault(currency_schema_json_1).default; } });
23
23
  var country_schema_json_1 = require("./country.schema.json");
@@ -42,10 +42,6 @@ var customer_segment_schema_json_1 = require("./customer-segment.schema.json");
42
42
  Object.defineProperty(exports, "CustomerSegment", { enumerable: true, get: function () { return __importDefault(customer_segment_schema_json_1).default; } });
43
43
  var marketing_preferences_schema_json_1 = require("./marketing-preferences.schema.json");
44
44
  Object.defineProperty(exports, "MarketingPref", { enumerable: true, get: function () { return __importDefault(marketing_preferences_schema_json_1).default; } });
45
- var stock_movement_schema_json_1 = require("./stock-movement.schema.json");
46
- Object.defineProperty(exports, "StockMovement", { enumerable: true, get: function () { return __importDefault(stock_movement_schema_json_1).default; } });
47
- var purchase_orderline_schema_json_1 = require("./purchase-orderline.schema.json");
48
- Object.defineProperty(exports, "PurchaseOrderline", { enumerable: true, get: function () { return __importDefault(purchase_orderline_schema_json_1).default; } });
49
45
  __exportStar(require("./order"), exports);
50
46
  var order_schema_json_1 = require("./order.schema.json");
51
47
  Object.defineProperty(exports, "Order", { enumerable: true, get: function () { return __importDefault(order_schema_json_1).default; } });
@@ -36,7 +36,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
36
36
  return (mod && mod.__esModule) ? mod : { "default": mod };
37
37
  };
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
- exports.Order = exports.Messages = exports.Total = exports.Stock = exports.StockMovement = exports.PurchaseOrderline = exports.Product = exports.ProductDraft = exports.ProductCategory = exports.Price = exports.Money = exports.MarketingPreferences = exports.DevelopmentColour = exports.CustomerSegment = exports.Currency = exports.Country = exports.Category = exports.Asset = void 0;
39
+ exports.Order = exports.Messages = exports.Total = exports.Stock = exports.Product = exports.ProductDraft = exports.ProductCategory = exports.Price = exports.Money = exports.MarketingPreferences = exports.DevelopmentColour = exports.CustomerSegment = exports.Currency = exports.Country = exports.Category = exports.Asset = void 0;
40
40
  var asset_1 = require("./asset");
41
41
  Object.defineProperty(exports, "Asset", { enumerable: true, get: function () { return __importDefault(asset_1).default; } });
42
42
  var category_1 = require("./category");
@@ -61,10 +61,6 @@ var product_draft_1 = require("./product-draft");
61
61
  Object.defineProperty(exports, "ProductDraft", { enumerable: true, get: function () { return __importDefault(product_draft_1).default; } });
62
62
  var product_1 = require("./product");
63
63
  Object.defineProperty(exports, "Product", { enumerable: true, get: function () { return __importDefault(product_1).default; } });
64
- var purchase_orderline_1 = require("./purchase-orderline");
65
- Object.defineProperty(exports, "PurchaseOrderline", { enumerable: true, get: function () { return __importDefault(purchase_orderline_1).default; } });
66
- var stock_movement_1 = require("./stock-movement");
67
- Object.defineProperty(exports, "StockMovement", { enumerable: true, get: function () { return __importDefault(stock_movement_1).default; } });
68
64
  var stock_1 = require("./stock");
69
65
  Object.defineProperty(exports, "Stock", { enumerable: true, get: function () { return __importDefault(stock_1).default; } });
70
66
  var total_1 = require("./total");
@@ -42,107 +42,71 @@ class AirtableHelper extends runtime_1.default {
42
42
  }
43
43
  return existingRecord;
44
44
  }
45
- async updateMultiple(payload, options = {}) {
45
+ async updateMultiple(payload, options = {}, callIdx = 0, collectedResult = {
46
+ updatedRecords: [],
47
+ createdRecords: [],
48
+ records: []
49
+ }) {
46
50
  let response = null;
47
51
  const tableUrl = `https://api.airtable.com/v0/${this.baseId}/${this.tableId}`;
48
- const batchSize = 10;
49
- let collectedResult = {
50
- updatedRecords: [],
51
- createdRecords: [],
52
- records: []
53
- };
54
- const fieldsToMergeOn = (options.fieldsToMergeOn || [this.primaryKeyFieldName]);
55
- const fieldsToMergeOnIds = fieldsToMergeOn.map(x => this.dictionary[x] || x);
56
- let callIdx = 0;
57
- const payloadDeduplicated = payload.filter((x, idx, self) => idx === self.findIndex((t) => fieldsToMergeOn.every(field => (0, lodash_isequal_1.default)(t[field], x[field]))));
58
- const maxCallIdx = Math.ceil(payloadDeduplicated.length / batchSize);
59
- while (callIdx < maxCallIdx) {
60
- const currentBatch = payloadDeduplicated.slice(callIdx * batchSize, (callIdx + 1) * batchSize);
61
- const recordsInBatch = currentBatch.map(x => {
62
- const recordId = x.$recordId;
63
- const fieldsWithoutRecordId = { ...x };
64
- delete fieldsWithoutRecordId.$recordId;
65
- const record = {
66
- fields: AirtableHelper.convertToDictionary(this.dictionary, this.primaryKeyWritable === false
67
- ? AirtableHelper.removePrimaryKey(fieldsWithoutRecordId, this.primaryKeyFieldName)
68
- : fieldsWithoutRecordId),
69
- };
70
- if (recordId) {
71
- record.id = recordId;
72
- }
73
- return record;
74
- });
75
- try {
76
- response = await fetch(`${tableUrl}`, {
77
- method: "PATCH",
78
- headers: {
79
- Authorization: `Bearer ${this.apiKey}`,
80
- "Content-Type": "application/json",
52
+ const currentBatch = payload.slice(callIdx * 10, (callIdx + 1) * 10);
53
+ try {
54
+ response = await fetch(`${tableUrl}`, {
55
+ method: "PATCH",
56
+ headers: {
57
+ Authorization: `Bearer ${this.apiKey}`,
58
+ "Content-Type": "application/json",
59
+ },
60
+ body: JSON.stringify({
61
+ performUpsert: {
62
+ fieldsToMergeOn: (options.fieldsToMergeOn ?? [this.primaryKeyFieldName]).map(x => this.dictionary[x] || x),
81
63
  },
82
- body: JSON.stringify({
83
- performUpsert: {
84
- fieldsToMergeOn: fieldsToMergeOnIds,
85
- },
86
- returnFieldsByFieldId: true,
87
- typecast: options.typecast || false,
88
- records: recordsInBatch
89
- }),
90
- });
91
- if (!response.ok && response) {
92
- const text = await response.text().catch(() => `${response?.status || 'unknown'}`);
93
- throw new Error(text);
94
- }
95
- const resp = (await response.json());
96
- collectedResult = {
97
- updatedRecords: collectedResult.updatedRecords.concat(resp.updatedRecords),
98
- createdRecords: collectedResult.createdRecords.concat(resp.createdRecords),
99
- records: collectedResult.records.concat(resp.records.map(x => AirtableHelper.translateFields(this.dictionary, x)))
100
- };
101
- }
102
- catch (err) {
103
- const errorMessage = `Failed to update records in ${this.tableId} table (baseId: ${this.baseId}). Status: ${response?.status || 'unknown'}. Error: ${err.message}`;
104
- const batchErrors = currentBatch.map(() => new Error(errorMessage));
105
- collectedResult = {
106
- updatedRecords: collectedResult.updatedRecords,
107
- createdRecords: collectedResult.createdRecords,
108
- records: collectedResult.records.concat(batchErrors)
109
- };
64
+ returnFieldsByFieldId: true,
65
+ typecast: options.typecast || false,
66
+ records: currentBatch.map(x => {
67
+ const recordId = x.$recordId;
68
+ const fieldsWithoutRecordId = { ...x };
69
+ delete fieldsWithoutRecordId.$recordId;
70
+ const record = {
71
+ fields: AirtableHelper.convertToDictionary(this.dictionary, this.primaryKeyWritable === false
72
+ ? AirtableHelper.removePrimaryKey(fieldsWithoutRecordId, this.primaryKeyFieldName)
73
+ : fieldsWithoutRecordId),
74
+ };
75
+ if (recordId) {
76
+ record.id = recordId;
77
+ }
78
+ return record;
79
+ })
80
+ }),
81
+ });
82
+ if (!response.ok && response) {
83
+ const text = await response.text().catch(() => `${response?.status || 'unknown'}`);
84
+ throw new Error(text);
110
85
  }
111
- finally {
112
- callIdx += 1;
86
+ const resp = (await response.json());
87
+ const nextCollectedResult = {
88
+ updatedRecords: collectedResult.updatedRecords.concat(resp.updatedRecords),
89
+ createdRecords: collectedResult.createdRecords.concat(resp.createdRecords),
90
+ records: collectedResult.records.concat(resp.records.map(x => AirtableHelper.translateFields(this.dictionary, x)))
91
+ };
92
+ if (payload.length > (callIdx + 1) * 10) {
93
+ return this.updateMultiple(payload, options, callIdx + 1, nextCollectedResult);
113
94
  }
95
+ return nextCollectedResult;
114
96
  }
115
- const resultInOrder = [];
116
- for (let i = 0; i < payload.length; i++) {
117
- let j = 0;
118
- let foundMatchingRecord = null;
119
- while (j < collectedResult.records.length && foundMatchingRecord === null) {
120
- let isMatching = true;
121
- let k = 0;
122
- while (k < fieldsToMergeOn.length && isMatching) {
123
- const field = fieldsToMergeOn[k];
124
- if (!(0, lodash_isequal_1.default)(collectedResult.records[j].fields[field], payload[i][field])) {
125
- isMatching = false;
126
- }
127
- k += 1;
128
- }
129
- if (isMatching) {
130
- foundMatchingRecord = j;
131
- }
132
- j += 1;
133
- }
134
- if (foundMatchingRecord !== null) {
135
- resultInOrder.push(collectedResult.records[foundMatchingRecord]);
136
- }
137
- else {
138
- resultInOrder.push(new Error(`Record ${payload[i][this.primaryKeyFieldName]} does not match any record in the response`));
97
+ catch (err) {
98
+ const errorMessage = `Failed to update records in ${this.tableId} table (baseId: ${this.baseId}). Status: ${response?.status || 'unknown'}. Error: ${err.message}`;
99
+ const batchErrors = currentBatch.map(() => new Error(errorMessage));
100
+ const nextCollectedResult = {
101
+ updatedRecords: collectedResult.updatedRecords,
102
+ createdRecords: collectedResult.createdRecords,
103
+ records: collectedResult.records.concat(batchErrors)
104
+ };
105
+ if (payload.length > (callIdx + 1) * 10) {
106
+ return this.updateMultiple(payload, options, callIdx + 1, nextCollectedResult);
139
107
  }
108
+ return nextCollectedResult;
140
109
  }
141
- return {
142
- updatedRecords: collectedResult.updatedRecords,
143
- createdRecords: collectedResult.createdRecords,
144
- records: resultInOrder
145
- };
146
110
  }
147
111
  async upsert(payload) {
148
112
  const existingRecord = await this.getExistingRecord(payload);
@@ -294,10 +258,9 @@ class AirtableHelper extends runtime_1.default {
294
258
  const escapeFormulaValue = (value) => {
295
259
  return value.replace(/"/g, '\\"');
296
260
  };
297
- const dedupedKeys = keys.filter((x, idx, self) => self.indexOf(x) === idx);
298
261
  const batchSize = 50;
299
- for (let i = 0; i < dedupedKeys.length; i += batchSize) {
300
- const batch = dedupedKeys.slice(i, i + batchSize);
262
+ for (let i = 0; i < keys.length; i += batchSize) {
263
+ const batch = keys.slice(i, i + batchSize);
301
264
  const orConditions = batch.map(key => `${this.dictionary[this.primaryKeyFieldName]} = "${escapeFormulaValue(key)}"`).join(', ');
302
265
  const formula = `OR(${orConditions})`;
303
266
  const records = await this.getExistingRecords(formula);
@@ -400,18 +400,15 @@ function transformMasterOrder(payload) {
400
400
  const desc = String(line?.description || '').trim().toLowerCase();
401
401
  return desc === 'delivery';
402
402
  };
403
- let invoicesNetMinor = 0;
404
403
  let invoicesGrossMinor = 0;
405
404
  (payload.invoices || []).forEach((inv) => {
406
405
  (inv.invoice_lines || []).forEach((line) => {
407
406
  if (!isDeliveryItem(line)) {
408
- invoicesNetMinor += toMinorUnits(Number(line?.amount || line?.amount_excl_vat || 0));
409
407
  invoicesGrossMinor += toMinorUnits(Number(line?.amount_including_vat || line?.amount_incl_vat || 0));
410
408
  }
411
409
  });
412
410
  });
413
411
  if (invoicesGrossMinor === 0 && (payload.invoices || []).length > 0) {
414
- invoicesNetMinor = toMinorUnits((payload.invoices || []).reduce((acc, inv) => acc + (inv.amount_excl_vat || 0), 0));
415
412
  invoicesGrossMinor = toMinorUnits((payload.invoices || []).reduce((acc, inv) => acc + (inv.amount_incl_vat || 0), 0));
416
413
  }
417
414
  if (invoicesGrossMinor === 0 && invoicedLineNos.size > 0 && sale0?.sale_lines) {
@@ -423,10 +420,8 @@ function transformMasterOrder(payload) {
423
420
  const lineNo = Number(l?.line_no || -1);
424
421
  return invoicedLineNos.has(lineNo);
425
422
  });
426
- invoicesNetMinor = toMinorUnits(invoicedSaleLines.reduce((acc, l) => acc + (Number(l?.amount || 0)), 0));
427
423
  invoicesGrossMinor = toMinorUnits(invoicedSaleLines.reduce((acc, l) => acc + (Number(l?.amount_including_vat || 0)), 0));
428
424
  }
429
- let nonInvSalesNetMinor = 0;
430
425
  let nonInvSalesGrossMinor = 0;
431
426
  if (sale0?.sale_lines && sale0.sale_lines.length > 0) {
432
427
  const allSaleLines = (sale0.sale_lines || []).filter((l) => {
@@ -436,26 +431,20 @@ function transformMasterOrder(payload) {
436
431
  return false;
437
432
  return true;
438
433
  });
439
- const totalSaleNetMinor = toMinorUnits(allSaleLines.reduce((acc, l) => acc + (Number(l?.amount || 0)), 0));
440
434
  const totalSaleGrossMinor = toMinorUnits(allSaleLines.reduce((acc, l) => acc + (Number(l?.amount_including_vat || 0)), 0));
441
435
  if (invoicesGrossMinor > 0) {
442
- nonInvSalesNetMinor = Math.max(0, totalSaleNetMinor - invoicesNetMinor);
443
436
  nonInvSalesGrossMinor = Math.max(0, totalSaleGrossMinor - invoicesGrossMinor);
444
437
  }
445
438
  else {
446
- nonInvSalesNetMinor = totalSaleNetMinor;
447
439
  nonInvSalesGrossMinor = totalSaleGrossMinor;
448
440
  }
449
441
  }
450
442
  else if (sale0 && (sale0.amount_excl_vat || sale0.amount_incl_vat)) {
451
- const saleNetMinor = toMinorUnits(sale0.amount_excl_vat || 0);
452
443
  const saleGrossMinor = toMinorUnits(sale0.amount_incl_vat || 0);
453
444
  if (invoicesGrossMinor > 0) {
454
- nonInvSalesNetMinor = Math.max(0, saleNetMinor - invoicesNetMinor);
455
445
  nonInvSalesGrossMinor = Math.max(0, saleGrossMinor - invoicesGrossMinor);
456
446
  }
457
447
  else {
458
- nonInvSalesNetMinor = saleNetMinor;
459
448
  nonInvSalesGrossMinor = saleGrossMinor;
460
449
  }
461
450
  }
@@ -468,32 +457,57 @@ function transformMasterOrder(payload) {
468
457
  const lineNo = Number(l?.line_no || -1);
469
458
  return !invoicedLineNos.has(lineNo);
470
459
  });
471
- nonInvSalesNetMinor = toMinorUnits(nonInvoicedSales.reduce((acc, l) => acc + (Number(l?.amount || 0)), 0));
472
460
  nonInvSalesGrossMinor = toMinorUnits(nonInvoicedSales.reduce((acc, l) => acc + (Number(l?.amount_including_vat || 0)), 0));
473
461
  }
474
- const returnsNetMinor = toMinorUnits((payload.credit_memos || []).reduce((acc, cm) => acc + (cm.amount_excl_vat || 0), 0));
475
- const returnsGrossMinor = toMinorUnits((payload.credit_memos || []).reduce((acc, cm) => acc + (cm.amount_incl_vat || 0), 0));
476
- const totalNetMinor = invoicesNetMinor + nonInvSalesNetMinor;
477
462
  const totalGrossMinor = invoicesGrossMinor + nonInvSalesGrossMinor;
478
- const total = {
479
- amount_net: moneyFromMinor(totalNetMinor),
480
- amount_gross: moneyFromMinor(totalGrossMinor),
481
- discount_amount_net: money(0),
482
- discount_amount_gross: money(0),
483
- discount_amount_percent: 0,
484
- };
485
- const return_total = (payload.credit_memos && payload.credit_memos.length > 0)
486
- ? {
487
- amount_net: moneyFromMinor(returnsNetMinor),
488
- amount_gross: moneyFromMinor(returnsGrossMinor),
489
- discount_amount_net: money(0),
490
- discount_amount_gross: money(0),
491
- discount_amount_percent: 0,
463
+ const invoicesNetMinorWithDelivery = toMinorUnits((payload.invoices || []).reduce((acc, inv) => acc + (inv.amount_excl_vat || 0), 0));
464
+ const invoicesGrossMinorWithDelivery = toMinorUnits((payload.invoices || []).reduce((acc, inv) => acc + (inv.amount_incl_vat || 0), 0));
465
+ let nonInvSalesNetMinorWithDelivery = 0;
466
+ let nonInvSalesGrossMinorWithDelivery = 0;
467
+ if (sale0?.sale_lines && sale0.sale_lines.length > 0) {
468
+ const allSaleLinesWithDelivery = (sale0.sale_lines || []).filter((l) => {
469
+ if (String(l?.type || '').toLowerCase() !== 'item')
470
+ return false;
471
+ return true;
472
+ });
473
+ const totalSaleNetMinorWithDelivery = toMinorUnits(allSaleLinesWithDelivery.reduce((acc, l) => acc + (Number(l?.amount || 0)), 0));
474
+ const totalSaleGrossMinorWithDelivery = toMinorUnits(allSaleLinesWithDelivery.reduce((acc, l) => acc + (Number(l?.amount_including_vat || 0)), 0));
475
+ if (invoicesGrossMinorWithDelivery > 0) {
476
+ nonInvSalesNetMinorWithDelivery = Math.max(0, totalSaleNetMinorWithDelivery - invoicesNetMinorWithDelivery);
477
+ nonInvSalesGrossMinorWithDelivery = Math.max(0, totalSaleGrossMinorWithDelivery - invoicesGrossMinorWithDelivery);
492
478
  }
493
- : undefined;
494
- const net_total = {
495
- amount_net: moneyFromMinor(Math.max(0, totalNetMinor - returnsNetMinor)),
496
- amount_gross: moneyFromMinor(Math.max(0, totalGrossMinor - returnsGrossMinor)),
479
+ else {
480
+ nonInvSalesNetMinorWithDelivery = totalSaleNetMinorWithDelivery;
481
+ nonInvSalesGrossMinorWithDelivery = totalSaleGrossMinorWithDelivery;
482
+ }
483
+ }
484
+ else if (sale0 && (sale0.amount_excl_vat || sale0.amount_incl_vat)) {
485
+ const saleNetMinor = toMinorUnits(sale0.amount_excl_vat || 0);
486
+ const saleGrossMinor = toMinorUnits(sale0.amount_incl_vat || 0);
487
+ if (invoicesGrossMinorWithDelivery > 0) {
488
+ nonInvSalesNetMinorWithDelivery = Math.max(0, saleNetMinor - invoicesNetMinorWithDelivery);
489
+ nonInvSalesGrossMinorWithDelivery = Math.max(0, saleGrossMinor - invoicesGrossMinorWithDelivery);
490
+ }
491
+ else {
492
+ nonInvSalesNetMinorWithDelivery = saleNetMinor;
493
+ nonInvSalesGrossMinorWithDelivery = saleGrossMinor;
494
+ }
495
+ }
496
+ else {
497
+ const nonInvoicedSalesWithDelivery = (sale0?.sale_lines || []).filter((l) => {
498
+ if (String(l?.type || '').toLowerCase() !== 'item')
499
+ return false;
500
+ const lineNo = Number(l?.line_no || -1);
501
+ return !invoicedLineNos.has(lineNo);
502
+ });
503
+ nonInvSalesNetMinorWithDelivery = toMinorUnits(nonInvoicedSalesWithDelivery.reduce((acc, l) => acc + (Number(l?.amount || 0)), 0));
504
+ nonInvSalesGrossMinorWithDelivery = toMinorUnits(nonInvoicedSalesWithDelivery.reduce((acc, l) => acc + (Number(l?.amount_including_vat || 0)), 0));
505
+ }
506
+ const totalNetMinorWithDelivery = invoicesNetMinorWithDelivery + nonInvSalesNetMinorWithDelivery;
507
+ const totalGrossMinorWithDelivery = invoicesGrossMinorWithDelivery + nonInvSalesGrossMinorWithDelivery;
508
+ const total = {
509
+ amount_net: moneyFromMinor(totalNetMinorWithDelivery),
510
+ amount_gross: moneyFromMinor(totalGrossMinorWithDelivery),
497
511
  discount_amount_net: money(0),
498
512
  discount_amount_gross: money(0),
499
513
  discount_amount_percent: 0,
@@ -603,7 +617,7 @@ function transformMasterOrder(payload) {
603
617
  const merchReturnGrossFromCreditMemos = (payload.credit_memos || []).reduce((acc, cm) => {
604
618
  const lines = cm?.credit_memo_lines || [];
605
619
  let hasQualifying = false;
606
- const sum = lines.reduce((s, l) => {
620
+ const sumGross = lines.reduce((s, l) => {
607
621
  const itemNo = String(l?.item_no || l?.no || "");
608
622
  const desc = String(l?.description || "");
609
623
  const looksProduct = itemNo.includes('-') || desc.includes(' - ');
@@ -616,24 +630,36 @@ function transformMasterOrder(payload) {
616
630
  }
617
631
  return s;
618
632
  }, 0);
633
+ const sumNet = lines.reduce((s, l) => {
634
+ const itemNo = String(l?.item_no || l?.no || "");
635
+ const desc = String(l?.description || "");
636
+ const looksProduct = itemNo.includes('-') || desc.includes(' - ');
637
+ const typeStr = String(l?.type || "").toLowerCase();
638
+ const isItemish = typeStr.includes('item') || looksProduct;
639
+ const isRefund = itemNo.toUpperCase() === 'REFUND';
640
+ if ((l?.quantity || 0) > 0 && isItemish && !isRefund && !isDeliveryItem(l)) {
641
+ return s + (l?.amount || l?.amount_excl_vat || 0);
642
+ }
643
+ return s;
644
+ }, 0);
619
645
  if (!hasQualifying)
620
646
  return acc;
621
647
  if (cm?.amount_incl_vat != null && cm.amount_incl_vat > 0) {
622
- return acc + cm.amount_incl_vat;
648
+ return { gross: acc.gross + cm.amount_incl_vat, net: acc.net + (cm.amount_excl_vat || 0) };
623
649
  }
624
- return acc + sum;
625
- }, 0);
650
+ return { gross: acc.gross + sumGross, net: acc.net + sumNet };
651
+ }, { gross: 0, net: 0 });
626
652
  const merchReturnGrossFromReturnSales = (payload.sales || []).reduce((acc, sale) => {
627
653
  const docTypeRaw = String(sale?.document_type || sale?.documentType || "");
628
654
  const isReturnOrder = docTypeRaw.toLowerCase().includes('return');
629
655
  if (!isReturnOrder)
630
656
  return acc;
631
657
  if (sale?.amount_incl_vat != null && sale.amount_incl_vat > 0) {
632
- return acc + sale.amount_incl_vat;
658
+ return { gross: acc.gross + sale.amount_incl_vat, net: acc.net + (sale.amount_excl_vat || sale.amount || 0) };
633
659
  }
634
660
  const lines = sale?.sale_lines || [];
635
661
  let hasQualifying = false;
636
- const sum = lines.reduce((s, l) => {
662
+ const sumGross = lines.reduce((s, l) => {
637
663
  const itemNo = String(l?.item_no || l?.no || "");
638
664
  const desc = String(l?.description || "");
639
665
  const looksProduct = itemNo.includes('-') || desc.includes(' - ');
@@ -646,10 +672,46 @@ function transformMasterOrder(payload) {
646
672
  }
647
673
  return s;
648
674
  }, 0);
649
- return acc + (sum > 0 ? sum : (hasQualifying ? (sale?.amount_incl_vat || sale?.amount_including_vat || 0) : 0));
650
- }, 0);
651
- const merchReturnGross = merchReturnGrossFromCreditMemos + merchReturnGrossFromReturnSales;
675
+ const sumNet = lines.reduce((s, l) => {
676
+ const itemNo = String(l?.item_no || l?.no || "");
677
+ const desc = String(l?.description || "");
678
+ const looksProduct = itemNo.includes('-') || desc.includes(' - ');
679
+ const typeStr = String(l?.type || "").toLowerCase();
680
+ const isItemish = typeStr.includes('item') || looksProduct;
681
+ const isRefund = itemNo.toUpperCase() === 'REFUND';
682
+ if ((l?.quantity || 0) > 0 && isItemish && !isRefund && !isDeliveryItem(l)) {
683
+ return s + (l?.amount || l?.amount_excl_vat || 0);
684
+ }
685
+ return s;
686
+ }, 0);
687
+ if (sumGross > 0) {
688
+ return { gross: acc.gross + sumGross, net: acc.net + sumNet };
689
+ }
690
+ if (hasQualifying) {
691
+ return { gross: acc.gross + (sale?.amount_incl_vat || sale?.amount_including_vat || 0), net: acc.net + (sale?.amount_excl_vat || sale?.amount || 0) };
692
+ }
693
+ return acc;
694
+ }, { gross: 0, net: 0 });
695
+ const merchReturnGross = merchReturnGrossFromCreditMemos.gross + merchReturnGrossFromReturnSales.gross;
652
696
  const hasMerchReturn = merchReturnGross > 0;
697
+ const returnsNetMinor = toMinorUnits((payload.credit_memos || []).reduce((acc, cm) => acc + (cm.amount_excl_vat || 0), 0));
698
+ const returnsGrossMinor = toMinorUnits((payload.credit_memos || []).reduce((acc, cm) => acc + (cm.amount_incl_vat || 0), 0));
699
+ const return_total = (returnsGrossMinor > 0)
700
+ ? {
701
+ amount_net: moneyFromMinor(returnsNetMinor),
702
+ amount_gross: moneyFromMinor(returnsGrossMinor),
703
+ discount_amount_net: money(0),
704
+ discount_amount_gross: money(0),
705
+ discount_amount_percent: 0,
706
+ }
707
+ : undefined;
708
+ const net_total = {
709
+ amount_net: moneyFromMinor(Math.max(0, totalNetMinorWithDelivery - returnsNetMinor)),
710
+ amount_gross: moneyFromMinor(Math.max(0, totalGrossMinorWithDelivery - returnsGrossMinor)),
711
+ discount_amount_net: money(0),
712
+ discount_amount_gross: money(0),
713
+ discount_amount_percent: 0,
714
+ };
653
715
  const totalOrderGrossMinor = totalGrossMinor;
654
716
  const sourceLineMap = new Map();
655
717
  sourceLines.forEach((line) => {
@@ -6,7 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const crypto_1 = __importDefault(require("crypto"));
7
7
  const env_1 = __importDefault(require("./env"));
8
8
  const utils_1 = require("./utils");
9
- const CACHE_EXPIRATION_MS = 1000 * 60 * 5;
9
+ const CACHE_EXPIRATION_MS = 1000 * 60 * 60 * 3;
10
10
  class CentraHelper extends env_1.default {
11
11
  opts;
12
12
  shaToken;
@@ -99,12 +99,6 @@ class CentraHelper extends env_1.default {
99
99
  getCacheKeyForMarket(marketExternalId) {
100
100
  return `${this.getCacheKeyForMarkets()}_${marketExternalId}`;
101
101
  }
102
- getCacheKeyForCampaigns() {
103
- return `centra_${this.shaToken}_campaign_name`;
104
- }
105
- getCacheKeyForCampaign(campaignName) {
106
- return `${this.getCacheKeyForCampaigns()}_${campaignName}`;
107
- }
108
102
  getCacheKeyForSizeCharts() {
109
103
  return `centra_${this.shaToken}_size_chart_external_id`;
110
104
  }
@@ -136,7 +130,7 @@ class CentraHelper extends env_1.default {
136
130
  return `${this.getCacheKeyForCentraWarehouses()}_${warehouseExternalId}`;
137
131
  }
138
132
  getCacheKeyForCentraPricelists() {
139
- return `centra_${this.shaToken}_pricelists_external_id`;
133
+ return `centra_${this.shaToken}_pricelist_external_id`;
140
134
  }
141
135
  getCacheKeyForCentraPricelist(pricelistExternalId) {
142
136
  return `${this.getCacheKeyForCentraPricelists()}_${pricelistExternalId}`;
@@ -224,7 +218,7 @@ class CentraHelper extends env_1.default {
224
218
  return result;
225
219
  }
226
220
  async fetchCentraCampaigns(names) {
227
- const limit = names ? (names.length > 200 ? 200 : names.length) : 200;
221
+ const limit = (names?.length || 0) > 200 ? 200 : (names?.length || 0);
228
222
  let nextCursor = null;
229
223
  const result = {};
230
224
  do {
@@ -276,7 +270,7 @@ class CentraHelper extends env_1.default {
276
270
  nextCursor = null;
277
271
  }
278
272
  if (campaignConnection && campaignConnection.edges?.length) {
279
- for (let i = 0; i < campaignConnection.edges.length; i++) {
273
+ for (let i = campaignConnection.edges.length; i < (names?.length || 0); i++) {
280
274
  const { node } = campaignConnection.edges[i];
281
275
  result[node.name] = node;
282
276
  }
@@ -727,9 +721,7 @@ class CentraHelper extends env_1.default {
727
721
  }
728
722
  else {
729
723
  for (const warehouse of warehouses) {
730
- if (warehouse.externalId) {
731
- warehouseToSet[warehouse.externalId] = warehouse;
732
- }
724
+ warehouseToSet[warehouse.externalId] = warehouse;
733
725
  }
734
726
  await this.set(Object.entries(warehouseToSet).filter(([_, value]) => !(value instanceof Error)).map(([key, value]) => ({ name: this.getCacheKeyForCentraWarehouse(key), value: JSON.stringify(value) })), 'env', {
735
727
  ephemeralMs: CACHE_EXPIRATION_MS,
@@ -805,49 +797,6 @@ class CentraHelper extends env_1.default {
805
797
  }
806
798
  return Object.assign({}, pricelistInCache, pricelistToSet);
807
799
  }
808
- async getCentraCampaigns(alwaysFetch = false) {
809
- let campaignInCache = {};
810
- let dedupedCampaignNamesInCache = [];
811
- let campaignsToFetch = null;
812
- if (!alwaysFetch) {
813
- const campaignNamesInCache = await (this.get(this.getCacheKeyForCampaigns(), 'env', {
814
- isEphemeral: true,
815
- encrypted: false,
816
- }).then(x => x ? JSON.parse(x) : null));
817
- if (campaignNamesInCache) {
818
- dedupedCampaignNamesInCache = campaignNamesInCache.filter((x, index, self) => self.indexOf(x) === index);
819
- campaignInCache = Object.fromEntries(Object.entries(await this.get(dedupedCampaignNamesInCache.map((x) => this.getCacheKeyForCampaign(x)), 'env', {
820
- isEphemeral: true,
821
- encrypted: false,
822
- })).map(([key, value]) => [key, value ? JSON.parse(value || 'null') : undefined]).filter(([_, value]) => value));
823
- campaignsToFetch = dedupedCampaignNamesInCache.filter(x => !campaignInCache[x]);
824
- }
825
- }
826
- const campaignToSet = {};
827
- if (!campaignsToFetch || campaignsToFetch.length) {
828
- const campaigns = await this.fetchCentraCampaigns();
829
- if (CentraHelper.isCentraErrors(campaigns)) {
830
- return new Error(`Failed to fetch campaigns: ${campaigns.errors.map((x) => x.message).join(', ')}`);
831
- }
832
- else {
833
- for (const campaign of Object.values(campaigns)) {
834
- campaignToSet[campaign.name] = campaign;
835
- }
836
- await this.set(Object.entries(campaignToSet).filter(([_, value]) => !(value instanceof Error)).map(([key, value]) => ({ name: this.getCacheKeyForCampaign(key), value: JSON.stringify(value) })), 'env', {
837
- ephemeralMs: CACHE_EXPIRATION_MS,
838
- encrypted: false,
839
- });
840
- await this.set([{
841
- name: this.getCacheKeyForCampaigns(),
842
- value: JSON.stringify(Object.keys(campaignToSet)),
843
- }], 'env', {
844
- ephemeralMs: CACHE_EXPIRATION_MS,
845
- encrypted: false,
846
- });
847
- }
848
- }
849
- return Object.assign({}, campaignInCache, campaignToSet);
850
- }
851
800
  async getCentraMarkets(alwaysFetch = false) {
852
801
  let marketInCache = {};
853
802
  let dedupedMarketNamesInCache = [];
@@ -17,7 +17,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
17
17
  return (mod && mod.__esModule) ? mod : { "default": mod };
18
18
  };
19
19
  Object.defineProperty(exports, "__esModule", { value: true });
20
- exports.SitooHelper = exports.RedisConnectionError = exports.RateLimit = exports.setHeaders = exports.BCOrderHelper = exports.DatoHelper = exports.AirtableHelper = exports.CentraHelper = exports.BigQueryHelper = exports.JWKSHelper = exports.CloudTasksHelper = exports.Secrets = exports.SchedulerHelper = exports.Logging = exports.Runtime = exports.PubSubHelper = exports.EnvEngine = exports.validate = void 0;
20
+ exports.RedisConnectionError = exports.RateLimit = exports.setHeaders = exports.BCOrderHelper = exports.DatoHelper = exports.AirtableHelper = exports.CentraHelper = exports.BigQueryHelper = exports.JWKSHelper = exports.CloudTasksHelper = exports.Secrets = exports.SchedulerHelper = exports.Logging = exports.Runtime = exports.PubSubHelper = exports.EnvEngine = exports.validate = void 0;
21
21
  var validate_1 = require("./validate");
22
22
  Object.defineProperty(exports, "validate", { enumerable: true, get: function () { return __importDefault(validate_1).default; } });
23
23
  __exportStar(require("./sanitize"), exports);
@@ -52,5 +52,3 @@ Object.defineProperty(exports, "setHeaders", { enumerable: true, get: function (
52
52
  var rateLimit_1 = require("./rateLimit");
53
53
  Object.defineProperty(exports, "RateLimit", { enumerable: true, get: function () { return __importDefault(rateLimit_1).default; } });
54
54
  Object.defineProperty(exports, "RedisConnectionError", { enumerable: true, get: function () { return rateLimit_1.RedisConnectionError; } });
55
- var sitoo_1 = require("./sitoo");
56
- Object.defineProperty(exports, "SitooHelper", { enumerable: true, get: function () { return __importDefault(sitoo_1).default; } });
package/dist/package.json CHANGED
@@ -5,7 +5,6 @@
5
5
  "license": "UNLICENSED",
6
6
  "description": "",
7
7
  "dependencies": {
8
- "@google-cloud/firestore": "^7.11.1",
9
8
  "@hackylabs/deep-redact": "^2.2.1",
10
9
  "ajv": "^8.17.1",
11
10
  "ajv-formats": "^3.0.1",
@@ -13,15 +12,15 @@
13
12
  "jose": "^6.0.11",
14
13
  "lodash.chunk": "^4.2.0",
15
14
  "lodash.clonedeep": "^4.5.0",
16
- "lodash.groupby": "^4.6.0",
17
15
  "lodash.isequal": "^4.5.0",
18
16
  "lodash.omit": "^4.5.0",
19
17
  "lodash.pick": "^4.4.0",
20
18
  "mime-types": "^3.0.1",
21
19
  "p-limit": "^7.1.1",
22
20
  "rate-limiter-flexible": "^7.2.0",
21
+ "uuid": "^11.1.0",
23
22
  "redis": "^5.6.0",
24
- "uuid": "^11.1.0"
23
+ "@google-cloud/firestore": "^7.11.1"
25
24
  },
26
25
  "files": [
27
26
  "dist"
@@ -10,8 +10,6 @@ export { default as DevelopmentColour } from './development-colour.schema.json';
10
10
  export { default as Asset } from './asset.schema.json';
11
11
  export { default as CustomerSegment } from './customer-segment.schema.json';
12
12
  export { default as MarketingPref } from './marketing-preferences.schema.json';
13
- export { default as StockMovement } from './stock-movement.schema.json';
14
- export { default as PurchaseOrderline } from './purchase-orderline.schema.json';
15
13
  export * from './order';
16
14
  export { default as Order } from './order.schema.json';
17
15
  export * from './messages';
@@ -10,8 +10,6 @@ export { default as Price } from './price';
10
10
  export { default as ProductCategory } from './product-category';
11
11
  export { default as ProductDraft } from './product-draft';
12
12
  export { default as Product } from './product';
13
- export { default as PurchaseOrderline } from './purchase-orderline';
14
- export { default as StockMovement } from './stock-movement';
15
13
  export { default as Stock } from './stock';
16
14
  export { default as Total } from './total';
17
15
  export * as Messages from './messages';
@@ -10,8 +10,6 @@ export { default as Price } from './price';
10
10
  export { default as ProductCategory } from './product-category';
11
11
  export { default as ProductDraft } from './product-draft';
12
12
  export { default as Product } from './product';
13
- export { default as PurchaseOrderline } from './purchase-orderline';
14
- export { default as StockMovement } from './stock-movement';
15
13
  export { default as Stock } from './stock';
16
14
  export { default as Total } from './total';
17
15
  export * as Messages from './messages';