shareneus 1.7.4 → 1.7.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.
- package/README.md +1 -0
- package/dist/accounting/invoice/invoice-pdf/invoice-pdf.service.js +18 -45
- package/dist/accounting/invoice/reports/excel/analysis-excel.service.js +17 -7
- package/dist/accounting/invoice/reports/excel/category-wise-item-excel.service.js +17 -7
- package/dist/accounting/invoice/reports/excel/cust-wise-sales-details.js +17 -7
- package/dist/accounting/invoice/reports/excel/cust-wise-sales-summary-excel.service.js +17 -7
- package/dist/accounting/invoice/reports/excel/invoice-wise-excel.service.js +17 -7
- package/dist/accounting/invoice/reports/excel/item-wise-doctor-sale-excel.service.js +17 -7
- package/dist/accounting/invoice/reports/excel/items-wise-sales-excel.service.js +17 -7
- package/dist/accounting/invoice/reports/excel/manf-wise-sales-excel.service.js +17 -7
- package/dist/accounting/invoice/reports/excel/operator-wise-details.js +17 -7
- package/dist/accounting/invoice/reports/excel/operator-wise-summary.js +17 -7
- package/dist/accounting/invoice/reports/excel/sa-wise-labor-sales-excel.service.js +17 -7
- package/dist/accounting/invoice/reports/excel/sa-wise-part-sales-excel.service.js +17 -7
- package/dist/accounting/invoice/reports/excel/sale-summary-excel.service.js +17 -7
- package/dist/accounting/invoice/reports/excel/sales-by-service-summary-excel.service.js +17 -7
- package/dist/accounting/invoice/reports/excel/scheduled-drug-summary-excel.service.js +17 -7
- package/dist/accounting/invoice/reports/excel/scheduled-drugs-excel.service.js +17 -7
- package/dist/accounting/invoice/unified-invoice-pdf.service.d.ts +1 -1
- package/dist/accounting/payment-receive/reports/excel/cust-balance-excel.service.js +17 -7
- package/dist/accounting/payment-receive/reports/excel/payment-receive-excel.service.js +17 -7
- package/dist/common/reports/excel/product-without-owner-excel.service.js +17 -7
- package/dist/gst/excel/GSTR-RO-excel.service.js +17 -7
- package/dist/gst/excel/GSTR1-excel.service.js +17 -7
- package/dist/gst/excel/GSTR2-excel.service.js +17 -7
- package/dist/gst/excel/hsn-summary.js +17 -7
- package/dist/gst/excel/tally-sales-import.service.js +17 -7
- package/dist/index.d.ts +1 -1
- package/dist/index.js +6 -6
- package/dist/inventory/items/reports/excel/expiring-drugs-excel.service.js +17 -7
- package/dist/inventory/items/reports/excel/item-wise-mout-details.js +17 -7
- package/dist/inventory/items/reports/excel/item-wise-mout-summary.js +17 -7
- package/dist/inventory/items/reports/excel/spares-issue-excel.service.js +17 -7
- package/dist/inventory/items/reports/excel/stock-excel.service.js +17 -7
- package/dist/purchases/payment-made/reports/excel/payments-made-excel.service.js +17 -7
- package/dist/purchases/payment-made/reports/excel/ven-balance-excel.service.js +17 -7
- package/dist/services/reports/excel/insurance-expire-excel.service.js +17 -7
- package/dist/services/reports/excel/next-service-date-excel.service.js +17 -7
- package/dist/services/reports/excel/repair-orders-excel.service.js +17 -7
- package/dist/shared/table-section/pdf-table.header.d.ts +1 -1
- package/dist/shared/table-section/pdf-table.header.js +14 -2
- package/dist/shared/table-section/pdf-table.section.js +6 -13
- package/dist/{accounting/invoice/invoice-pdf.service.js → shared/transactions-pdf.service.js} +15 -15
- package/package.json +1 -1
- package/src/accounting/counter-sales/auto-sales-receipt-pdf.service.ts +569 -0
- package/src/accounting/counter-sales/pos-receipt-pdf.ts +577 -0
- package/src/accounting/counter-sales/sales-receipt-pdf.service.ts +628 -0
- package/src/accounting/counter-sales/sales-receipt-print.service.ts +506 -0
- package/src/accounting/credit-note/cn-print.service.ts +264 -0
- package/src/accounting/credit-note/credit-note-pdf.service.ts +602 -0
- package/src/accounting/credit-note/credit-note-totals.service.ts +424 -0
- package/src/accounting/debit-note/debit-note-pdf.service.ts +681 -0
- package/src/accounting/debit-note/debit-note-print.service.ts +276 -0
- package/src/accounting/debit-note/debit-note-totals.service.ts +361 -0
- package/src/accounting/invoice/hc-inv-pdf.service.ts +880 -0
- package/src/accounting/invoice/inv-pdf.service.ts +812 -0
- package/src/accounting/invoice/inv-print.service.ts +532 -0
- package/src/accounting/invoice/invoice-landscape-pdf.service.ts +947 -0
- package/src/accounting/invoice/invoice-letterhead-pdf.service.ts +813 -0
- package/src/accounting/invoice/invoice-pdf/invoice-pdf.service.ts +359 -0
- package/src/accounting/invoice/invoice-portrait-pdf.ts +972 -0
- package/src/accounting/invoice/invoice-print.service.ts +2906 -0
- package/src/accounting/invoice/invoice-total.service.ts +834 -0
- package/src/accounting/invoice/reports/excel/analysis-excel.service.ts +291 -0
- package/src/accounting/invoice/reports/excel/category-wise-item-excel.service.ts +267 -0
- package/src/accounting/invoice/reports/excel/cust-wise-sales-details.ts +321 -0
- package/src/accounting/invoice/reports/excel/cust-wise-sales-summary-excel.service.ts +300 -0
- package/src/accounting/invoice/reports/excel/invoice-wise-excel.service.ts +859 -0
- package/src/accounting/invoice/reports/excel/item-wise-doctor-sale-excel.service.ts +255 -0
- package/src/accounting/invoice/reports/excel/items-wise-sales-excel.service.ts +312 -0
- package/src/accounting/invoice/reports/excel/manf-wise-sales-excel.service.ts +273 -0
- package/src/accounting/invoice/reports/excel/operator-wise-details.ts +258 -0
- package/src/accounting/invoice/reports/excel/operator-wise-summary.ts +259 -0
- package/src/accounting/invoice/reports/excel/sa-wise-labor-sales-excel.service.ts +230 -0
- package/src/accounting/invoice/reports/excel/sa-wise-part-sales-excel.service.ts +231 -0
- package/src/accounting/invoice/reports/excel/sale-summary-excel.service.ts +326 -0
- package/src/accounting/invoice/reports/excel/sales-by-service-details-excel.service.ts +0 -0
- package/src/accounting/invoice/reports/excel/sales-by-service-summary-excel.service.ts +432 -0
- package/src/accounting/invoice/reports/excel/scheduled-drug-summary-excel.service.ts +373 -0
- package/src/accounting/invoice/reports/excel/scheduled-drugs-excel.service.ts +372 -0
- package/src/accounting/invoice/reports/pdf/analysis-pdf.service.ts +113 -0
- package/src/accounting/invoice/reports/pdf/category-wise-item-pdf.service.ts +107 -0
- package/src/accounting/invoice/reports/pdf/cust-wise-sales-details-pdf.service.ts +125 -0
- package/src/accounting/invoice/reports/pdf/cust-wise-sales-summary-pdf.service.ts +119 -0
- package/src/accounting/invoice/reports/pdf/item-wise-doctor-sale-pdf.service.ts +180 -0
- package/src/accounting/invoice/reports/pdf/item-wise-sales-pdf.service.ts +193 -0
- package/src/accounting/invoice/reports/pdf/manf-wise-sales-pdf.service.ts +188 -0
- package/src/accounting/invoice/reports/pdf/operator-wise-details-pdf.service.ts +118 -0
- package/src/accounting/invoice/reports/pdf/operator-wise-summary-pdf.ts +116 -0
- package/src/accounting/invoice/reports/pdf/sales-by-service-pdf.service.ts +132 -0
- package/src/accounting/invoice/reports/pdf/scheduled-drug-pdf.service.ts +191 -0
- package/src/accounting/invoice/reports/pdf/scheduled-drug-summary-pdf.service.ts +202 -0
- package/src/accounting/invoice/shared-inv-pdf.service.ts +787 -0
- package/src/accounting/invoice/unified-invoice-pdf.service.ts +937 -0
- package/src/accounting/payment-receive/payment-pdf.service.ts +410 -0
- package/src/accounting/payment-receive/payment-receipt-pdf/receipt-pdf.service.ts +470 -0
- package/src/accounting/payment-receive/receipt-print.service.ts +71 -0
- package/src/accounting/payment-receive/reports/excel/cust-balance-excel.service.ts +298 -0
- package/src/accounting/payment-receive/reports/excel/payment-receive-excel.service.ts +221 -0
- package/src/accounting/payment-receive/reports/pdf/customer-balances-pdf.service.ts +182 -0
- package/src/accounting/payment-receive/reports/pdf/payment-report-pdf.service.ts +116 -0
- package/src/aggregation/aggregation.ts +58 -0
- package/src/appointments/appointments/appointment-total.service.ts +298 -0
- package/src/appointments/consultations/consultation-fee-receipt.service.ts +407 -0
- package/src/appointments/consultations/consultation-full-pdf.service.ts +238 -0
- package/src/appointments/consultations/consultation-letterhead-pdf.service.ts +430 -0
- package/src/appointments/consultations/consultation-pdf.service.ts +417 -0
- package/src/common/reports/excel/product-without-owner-excel.service.ts +308 -0
- package/src/common/reports/pdf/product-without-owner-pdf.service.ts +146 -0
- package/src/enums/cache-enums.ts +33 -0
- package/src/enums/code-enums.ts +291 -0
- package/src/enums/country-enums.ts +9 -0
- package/src/enums/enums.ts +364 -0
- package/src/enums/industry-enums.ts +26 -0
- package/src/enums/treatment-enums.ts +9 -0
- package/src/gst/excel/GSTR-RO-excel.service.ts +926 -0
- package/src/gst/excel/GSTR1-excel.service.ts +313 -0
- package/src/gst/excel/GSTR2-excel.service.ts +314 -0
- package/src/gst/excel/hsn-summary.ts +314 -0
- package/src/gst/excel/tally-sales-import.service.ts +767 -0
- package/src/gst/pdf/hsn-summary-pdf.ts +176 -0
- package/src/index.ts +194 -0
- package/src/inventory/items/adjustment-pdf.service.ts +177 -0
- package/src/inventory/items/issue-parts-pdf.service.ts +795 -0
- package/src/inventory/items/item-bar-code-label-pdf.ts +194 -0
- package/src/inventory/items/item-detais-pdf.ts +141 -0
- package/src/inventory/items/item-price-for-pricelist.ts +368 -0
- package/src/inventory/items/reports/excel/expiring-drugs-excel.service.ts +290 -0
- package/src/inventory/items/reports/excel/item-wise-mout-details.ts +284 -0
- package/src/inventory/items/reports/excel/item-wise-mout-summary.ts +279 -0
- package/src/inventory/items/reports/excel/spares-issue-excel.service.ts +494 -0
- package/src/inventory/items/reports/excel/stock-excel.service.ts +319 -0
- package/src/inventory/items/reports/pdf/expiring-drugs-pdf.service.ts +172 -0
- package/src/inventory/items/reports/pdf/item-wise-mout-details-pdf.ts +122 -0
- package/src/inventory/items/reports/pdf/item-wise-mout-summary-pdf.ts +115 -0
- package/src/inventory/items/reports/pdf/reorder-point-pdf.service.ts +163 -0
- package/src/inventory/material-out/mout-pdf.service.ts +545 -0
- package/src/inventory/transfer-order/transfer-order-pdf.service.ts +154 -0
- package/src/purchases/bills/bill-pdf/bill-pdf.service.ts +211 -0
- package/src/purchases/bills/bill-pdf.service.ts +21 -0
- package/src/purchases/payment-made/reports/excel/payments-made-excel.service.ts +313 -0
- package/src/purchases/payment-made/reports/excel/ven-balance-excel.service.ts +307 -0
- package/src/purchases/payment-made/reports/pdf/vendor-balances-pdf.service.ts +114 -0
- package/src/purchases/purchase-order/po-totals.service.ts +343 -0
- package/src/purchases/purchase-order/purchase-order-pdf.service.ts +1016 -0
- package/src/purchases/purchase-order/purchase-order-print.service.ts +279 -0
- package/src/purchases/purchase-order/purchase-order-totals.service.ts +637 -0
- package/src/purchases/vendor-credit-note/vendor-credit-note-pdf.service.ts +1055 -0
- package/src/purchases/vendor-credit-note/vendor-credit-note-print.service.ts +145 -0
- package/src/purchases/vendor-credit-note/vendor-credit-note-totals.service.ts +399 -0
- package/src/purchases/vendor-debit-note/vendor-debit-note-pdf.service.ts +582 -0
- package/src/purchases/vendor-debit-note/vendor-debit-note-print.service.ts +295 -0
- package/src/purchases/vendor-debit-note/vendor-debit-note-totals.service.ts +377 -0
- package/src/sales/delivery-challan/dc-landscape-pdf.service.ts +922 -0
- package/src/sales/delivery-challan/dc-landscape-without-price-pdf.service.ts +869 -0
- package/src/sales/delivery-challan/dc-without-price-pdf.service.ts +505 -0
- package/src/sales/delivery-challan/delivery-challan-pdf.service.ts +461 -0
- package/src/sales/delivery-challan/delivery-challan-print.service.ts +229 -0
- package/src/sales/delivery-challan/delivery-challan-totals.ts +466 -0
- package/src/sales/sales/equipment-design-pdf.service.ts +153 -0
- package/src/sales/sales/pack-ship-pdf.service.ts +128 -0
- package/src/sales/sales/pack-ship-print.service.ts +198 -0
- package/src/sales/sales/sales-pdf.service.ts +658 -0
- package/src/sales/sales/sales-print.service.ts +376 -0
- package/src/sales/sales/sales-totals.service.ts +500 -0
- package/src/sales-receive/sales-receive-pdf.service.ts +602 -0
- package/src/sales-receive/sales-receive-print.service.ts +242 -0
- package/src/sales-receive/sales-receive-totals.service.ts +651 -0
- package/src/services/checklist-pdf.ts +151 -0
- package/src/services/checklists-pdf.ts +133 -0
- package/src/services/est.print-service.ts +1155 -0
- package/src/services/reports/excel/insurance-expire-excel.service.ts +292 -0
- package/src/services/reports/excel/next-service-date-excel.service.ts +317 -0
- package/src/services/reports/excel/repair-orders-excel.service.ts +249 -0
- package/src/services/reports/pdf/insurance-expire-pdf.service.ts +115 -0
- package/src/services/reports/pdf/next-service-date-pdf.service.ts +198 -0
- package/src/services/reports/pdf/repair-orders-pdf.service.ts +184 -0
- package/src/services/ro-pdf.service.ts +1917 -0
- package/src/services/ro-print-service.ts +881 -0
- package/src/services/ro-totals.service.ts +1314 -0
- package/src/services/separate-wo-print.service.ts +396 -0
- package/src/services/service-history-pdf.service.ts +145 -0
- package/src/services/service-price-for-pricelist.ts +649 -0
- package/src/services/technician-pdf.service.ts +234 -0
- package/src/services/technician-print.service.ts +95 -0
- package/src/shared/header-footer-section/pdf-header-footer.section.ts +519 -0
- package/src/shared/header-footer-section/pdf-shared.utils.ts +46 -0
- package/src/shared/math-operations.ts +208 -0
- package/src/shared/party-details-section/pdf-party-details.section.ts +602 -0
- package/src/shared/shared-pdf.service.ts +3042 -0
- package/src/shared/shared-print.service.ts +879 -0
- package/src/shared/table-section/pdf-table.config.ts +8 -0
- package/src/shared/table-section/pdf-table.header.ts +396 -0
- package/src/shared/table-section/pdf-table.row.ts +248 -0
- package/src/shared/table-section/pdf-table.section.ts +447 -0
- package/src/shared/totals-section/pdf-totals.section.ts +921 -0
- package/src/shared/transactions-pdf.service.ts +191 -0
- package/src/shared/util.ts +101 -0
- package/src/tasks/meetings/meeting-pdf.ts +410 -0
- package/src/tasks/tasks/task-pdf.service.ts +238 -0
- package/src/tasks/tasks/task-reports-pdf.service.ts +313 -0
- package/src/tax/index.ts +86 -0
- package/src/tax/tax-calculator.ts +1025 -0
- package/src/tax/tax.types.ts +535 -0
- package/src/transaction-calculations/discounts-distribution.ts +343 -0
- package/src/transaction-calculations/index.ts +3 -0
- package/src/transaction-calculations/total-calculation.ts +443 -0
- package/src/transaction-calculations/transaction-calculation-engine.ts +903 -0
- package/src/utils/my-date.ts +111 -0
- package/src/utils/tr-utils.ts +104 -0
- package/tsconfig.json +2 -2
- /package/dist/{accounting/invoice/invoice-pdf.service.d.ts → shared/transactions-pdf.service.d.ts} +0 -0
|
@@ -0,0 +1,649 @@
|
|
|
1
|
+
import { CalcDiscPrice } from "../shared/math-operations";
|
|
2
|
+
import { IsNotNull, IsNull } from "../shared/util";
|
|
3
|
+
|
|
4
|
+
type QuantityTier = {
|
|
5
|
+
MinQty?: number | null;
|
|
6
|
+
Price?: number | null;
|
|
7
|
+
Disc?: number | null;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
type PriceListDoc = {
|
|
11
|
+
_id?: any;
|
|
12
|
+
TType: "SALE" | "PUR";
|
|
13
|
+
PrCalc: "FIXED" | "DISC" | "FORMULA";
|
|
14
|
+
BasedOn?: "SP" | "PC" | "PCBD" | "PCAD";
|
|
15
|
+
Fixed?: { Price?: number | null };
|
|
16
|
+
CalcDisc?: { Mark?: boolean; Perc?: number | null };
|
|
17
|
+
Round?: string | null;
|
|
18
|
+
Deci?: number | null;
|
|
19
|
+
QtyTiers?: QuantityTier[];
|
|
20
|
+
Currency?: string | null;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const ROUND_VALUES = new Set(["-1", "0", "0.99", "0.50", "0.49", "Dec"]);
|
|
24
|
+
|
|
25
|
+
export function ApplyServicePriceListToProcedure(
|
|
26
|
+
procedure: any,
|
|
27
|
+
priceList: PriceListDoc | null,
|
|
28
|
+
quantity: number = 1
|
|
29
|
+
): any {
|
|
30
|
+
if (!procedure || !priceList) {
|
|
31
|
+
return procedure;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const resolvedQty = Math.max(1, Number(quantity) || 1);
|
|
35
|
+
const warnings: string[] = [];
|
|
36
|
+
|
|
37
|
+
if (priceList.TType === "SALE" && procedure.Sale) {
|
|
38
|
+
const basePrice = IsNotNull(procedure.Sale.Price) ? procedure.Sale.Price : null;
|
|
39
|
+
const { value, tierWarnings, appliedTier, appliedCalc } = evaluatePriceBlock(
|
|
40
|
+
basePrice,
|
|
41
|
+
procedure.Pur,
|
|
42
|
+
priceList,
|
|
43
|
+
resolvedQty
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
procedure.Sale.PriceBeforePriceList = basePrice;
|
|
47
|
+
if (value != null) {
|
|
48
|
+
procedure.Sale.Price = value;
|
|
49
|
+
procedure.Sale.AppliedPriceListId = priceList._id ?? null;
|
|
50
|
+
procedure.Sale.AppliedPriceTier = appliedTier ?? undefined;
|
|
51
|
+
procedure.Sale.AppliedPriceCalc = appliedCalc ?? undefined;
|
|
52
|
+
}
|
|
53
|
+
if (tierWarnings.length > 0) {
|
|
54
|
+
warnings.push(...tierWarnings);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (priceList.TType === "PUR" && procedure.Pur) {
|
|
59
|
+
const baseCost = IsNotNull(procedure.Pur.Cost) ? procedure.Pur.Cost : null;
|
|
60
|
+
const { value, tierWarnings, appliedTier, appliedCalc } = evaluatePriceBlock(
|
|
61
|
+
baseCost,
|
|
62
|
+
procedure.Pur,
|
|
63
|
+
priceList,
|
|
64
|
+
resolvedQty
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
procedure.Pur.CostBeforePriceList = baseCost;
|
|
68
|
+
if (value != null) {
|
|
69
|
+
procedure.Pur.Cost = value;
|
|
70
|
+
procedure.Pur.AppliedPriceListId = priceList._id ?? null;
|
|
71
|
+
procedure.Pur.AppliedPriceTier = appliedTier ?? undefined;
|
|
72
|
+
procedure.Pur.AppliedPriceCalc = appliedCalc ?? undefined;
|
|
73
|
+
}
|
|
74
|
+
if (tierWarnings.length > 0) {
|
|
75
|
+
warnings.push(...tierWarnings);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (warnings.length > 0) {
|
|
80
|
+
procedure.PriceListWarnings = warnings;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return procedure;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export function ApplyServicePriceListToOpcode(
|
|
87
|
+
opcode: any,
|
|
88
|
+
priceList: PriceListDoc | null,
|
|
89
|
+
quantity: number = 1
|
|
90
|
+
): any {
|
|
91
|
+
if (!opcode || !priceList) {
|
|
92
|
+
return opcode;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const resolvedQty = Math.max(1, Number(quantity) || 1);
|
|
96
|
+
const warnings: string[] = [];
|
|
97
|
+
|
|
98
|
+
if (Array.isArray(opcode.Prices) && opcode.Prices.length > 0) {
|
|
99
|
+
opcode.Prices = opcode.Prices.map((pricing: any) => {
|
|
100
|
+
const cloned: any = { ...pricing };
|
|
101
|
+
if (cloned.Sale) {
|
|
102
|
+
cloned.Sale = { ...cloned.Sale };
|
|
103
|
+
}
|
|
104
|
+
if (cloned.Pur) {
|
|
105
|
+
cloned.Pur = { ...cloned.Pur };
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (
|
|
109
|
+
priceList.TType === "SALE" &&
|
|
110
|
+
cloned.Sale &&
|
|
111
|
+
(!cloned.PS || cloned.PS === "S" || cloned.PS === "SP")
|
|
112
|
+
) {
|
|
113
|
+
const basePrice = IsNotNull(cloned.Sale.Price) ? cloned.Sale.Price : null;
|
|
114
|
+
const { value, tierWarnings, appliedTier, appliedCalc } = evaluatePriceBlock(
|
|
115
|
+
basePrice,
|
|
116
|
+
cloned.Pur,
|
|
117
|
+
priceList,
|
|
118
|
+
resolvedQty
|
|
119
|
+
);
|
|
120
|
+
cloned.Sale.PriceBeforePriceList = basePrice;
|
|
121
|
+
if (value != null) {
|
|
122
|
+
cloned.Sale.Price = value;
|
|
123
|
+
cloned.Sale.AppliedPriceListId = priceList._id ?? null;
|
|
124
|
+
cloned.Sale.AppliedPriceTier = appliedTier ?? undefined;
|
|
125
|
+
cloned.Sale.AppliedPriceCalc = appliedCalc ?? undefined;
|
|
126
|
+
}
|
|
127
|
+
if (tierWarnings.length > 0) {
|
|
128
|
+
warnings.push(...tierWarnings);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (
|
|
133
|
+
priceList.TType === "PUR" &&
|
|
134
|
+
cloned.Pur &&
|
|
135
|
+
(!cloned.PS || cloned.PS === "P" || cloned.PS === "SP")
|
|
136
|
+
) {
|
|
137
|
+
const baseCost = IsNotNull(cloned.Pur.Cost) ? cloned.Pur.Cost : null;
|
|
138
|
+
const { value, tierWarnings, appliedTier, appliedCalc } = evaluatePriceBlock(
|
|
139
|
+
baseCost,
|
|
140
|
+
cloned.Pur,
|
|
141
|
+
priceList,
|
|
142
|
+
resolvedQty
|
|
143
|
+
);
|
|
144
|
+
cloned.Pur.CostBeforePriceList = baseCost;
|
|
145
|
+
if (value != null) {
|
|
146
|
+
cloned.Pur.Cost = value;
|
|
147
|
+
cloned.Pur.AppliedPriceListId = priceList._id ?? null;
|
|
148
|
+
cloned.Pur.AppliedPriceTier = appliedTier ?? undefined;
|
|
149
|
+
cloned.Pur.AppliedPriceCalc = appliedCalc ?? undefined;
|
|
150
|
+
}
|
|
151
|
+
if (tierWarnings.length > 0) {
|
|
152
|
+
warnings.push(...tierWarnings);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
return cloned;
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (warnings.length > 0) {
|
|
161
|
+
opcode.PriceListWarnings = warnings;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
return opcode;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function evaluatePriceBlock(
|
|
168
|
+
baseValue: number | null,
|
|
169
|
+
purchaseBlock: any,
|
|
170
|
+
priceList: PriceListDoc,
|
|
171
|
+
quantity: number
|
|
172
|
+
): {
|
|
173
|
+
value: number | null;
|
|
174
|
+
tierWarnings: string[];
|
|
175
|
+
appliedTier?: any;
|
|
176
|
+
appliedCalc?: string;
|
|
177
|
+
} {
|
|
178
|
+
const warnings: string[] = [];
|
|
179
|
+
|
|
180
|
+
const tier = resolveTier(quantity, priceList.QtyTiers);
|
|
181
|
+
if (tier) {
|
|
182
|
+
const tierValue = applyTierAdjustment(baseValue, purchaseBlock, tier, priceList);
|
|
183
|
+
const rounded = applyRounding(priceList, tierValue);
|
|
184
|
+
return {
|
|
185
|
+
value: rounded,
|
|
186
|
+
tierWarnings: warnings,
|
|
187
|
+
appliedTier: buildAppliedTierMeta(tier),
|
|
188
|
+
appliedCalc: "TIER",
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
switch (priceList.PrCalc) {
|
|
193
|
+
case "FIXED": {
|
|
194
|
+
if (IsNull(priceList.Fixed?.Price)) {
|
|
195
|
+
warnings.push("Fixed price list selected but Fixed.Price is not configured.");
|
|
196
|
+
return { value: null, tierWarnings: warnings };
|
|
197
|
+
}
|
|
198
|
+
const rounded = applyRounding(priceList, priceList.Fixed?.Price ?? null);
|
|
199
|
+
return { value: rounded, tierWarnings: warnings, appliedCalc: "FIXED" };
|
|
200
|
+
}
|
|
201
|
+
case "DISC": {
|
|
202
|
+
const base = resolveDiscountBase(priceList, baseValue, purchaseBlock);
|
|
203
|
+
if (base == null) {
|
|
204
|
+
warnings.push("Discount price list requires a base value but none was available.");
|
|
205
|
+
return { value: null, tierWarnings: warnings };
|
|
206
|
+
}
|
|
207
|
+
const perc = priceList.CalcDisc?.Perc ?? 0;
|
|
208
|
+
const mark = priceList.CalcDisc?.Mark ?? false;
|
|
209
|
+
const price = CalcDiscPrice(base, perc, mark);
|
|
210
|
+
return {
|
|
211
|
+
value: applyRounding(priceList, price),
|
|
212
|
+
tierWarnings: warnings,
|
|
213
|
+
appliedCalc: "DISCOUNT",
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
case "FORMULA": {
|
|
217
|
+
warnings.push("Formula-based service price lists are not implemented.");
|
|
218
|
+
return { value: null, tierWarnings: warnings };
|
|
219
|
+
}
|
|
220
|
+
default:
|
|
221
|
+
return { value: null, tierWarnings: warnings };
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
function applyTierAdjustment(
|
|
226
|
+
baseValue: number | null,
|
|
227
|
+
purchaseBlock: any,
|
|
228
|
+
tier: QuantityTier,
|
|
229
|
+
priceList: PriceListDoc
|
|
230
|
+
): number | null {
|
|
231
|
+
if (IsNotNull(tier.Price)) {
|
|
232
|
+
return tier.Price ?? null;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
const targetBase = resolveDiscountBase(priceList, baseValue, purchaseBlock);
|
|
236
|
+
if (targetBase == null || IsNull(tier.Disc)) {
|
|
237
|
+
return baseValue;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
return CalcDiscPrice(targetBase, tier.Disc ?? 0, false);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
function resolveDiscountBase(
|
|
244
|
+
priceList: PriceListDoc,
|
|
245
|
+
baseValue: number | null,
|
|
246
|
+
purchaseBlock: any
|
|
247
|
+
): number | null {
|
|
248
|
+
const basedOn = priceList.BasedOn ?? "SP";
|
|
249
|
+
switch (basedOn) {
|
|
250
|
+
case "SP":
|
|
251
|
+
return baseValue;
|
|
252
|
+
case "PC":
|
|
253
|
+
case "PCBD":
|
|
254
|
+
case "PCAD":
|
|
255
|
+
if (purchaseBlock && IsNotNull(purchaseBlock.Cost)) {
|
|
256
|
+
return purchaseBlock.Cost;
|
|
257
|
+
}
|
|
258
|
+
return null;
|
|
259
|
+
default:
|
|
260
|
+
return baseValue;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
function applyRounding(priceList: PriceListDoc, value: number | null): number | null {
|
|
265
|
+
if (value == null) {
|
|
266
|
+
return null;
|
|
267
|
+
}
|
|
268
|
+
if (!priceList.Round || !ROUND_VALUES.has(priceList.Round)) {
|
|
269
|
+
return value;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
switch (priceList.Round) {
|
|
273
|
+
case "-1":
|
|
274
|
+
return value;
|
|
275
|
+
case "0":
|
|
276
|
+
return Math.round(value);
|
|
277
|
+
case "0.99":
|
|
278
|
+
return Math.floor(value) + 0.99;
|
|
279
|
+
case "0.50":
|
|
280
|
+
return Math.round(value * 2) / 2;
|
|
281
|
+
case "0.49":
|
|
282
|
+
return Math.floor(value) + 0.49;
|
|
283
|
+
case "Dec":
|
|
284
|
+
if (IsNotNull(priceList.Deci)) {
|
|
285
|
+
const factor = Math.pow(10, priceList.Deci ?? 0);
|
|
286
|
+
return Math.round(value * factor) / factor;
|
|
287
|
+
}
|
|
288
|
+
return value;
|
|
289
|
+
default:
|
|
290
|
+
return value;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
function resolveTier(quantity: number, tiers?: QuantityTier[] | null): QuantityTier | null {
|
|
295
|
+
if (!Array.isArray(tiers) || tiers.length === 0) {
|
|
296
|
+
return null;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
const sorted = [...tiers]
|
|
300
|
+
.filter((tier) => IsNotNull(tier?.MinQty))
|
|
301
|
+
.sort((a, b) => (a?.MinQty ?? 0) - (b?.MinQty ?? 0));
|
|
302
|
+
|
|
303
|
+
let selected: QuantityTier | null = null;
|
|
304
|
+
for (const tier of sorted) {
|
|
305
|
+
if (quantity >= (tier?.MinQty ?? 0)) {
|
|
306
|
+
selected = tier ?? null;
|
|
307
|
+
} else {
|
|
308
|
+
break;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
return selected;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
function buildAppliedTierMeta(tier: QuantityTier | null) {
|
|
315
|
+
if (!tier) {
|
|
316
|
+
return undefined;
|
|
317
|
+
}
|
|
318
|
+
return {
|
|
319
|
+
MinQty: IsNotNull(tier.MinQty) ? tier.MinQty : null,
|
|
320
|
+
Price: IsNotNull(tier.Price) ? tier.Price : null,
|
|
321
|
+
Disc: IsNotNull(tier.Disc) ? tier.Disc : null,
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Applies price list to Service with support for equipment-based pricing (FitPriceCosts)
|
|
327
|
+
* Handles both simple services (healthcare) and equipment-based services (automotive, HVAC, medical, industrial, etc.)
|
|
328
|
+
*/
|
|
329
|
+
export function GetServicePriceForPriceList(
|
|
330
|
+
service: any,
|
|
331
|
+
priceList: PriceListDoc | null,
|
|
332
|
+
equipment: any = null,
|
|
333
|
+
quantity: number = 1
|
|
334
|
+
): any {
|
|
335
|
+
if (!service || !priceList) {
|
|
336
|
+
return service;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
const resolvedQty = Math.max(1, Number(quantity) || 1);
|
|
340
|
+
const warnings: string[] = [];
|
|
341
|
+
const priceListId = priceList?._id?.toString?.();
|
|
342
|
+
|
|
343
|
+
// Step 1: Determine base pricing (equipment-specific or simple)
|
|
344
|
+
let basePrice: any = null;
|
|
345
|
+
let basePriceSource: string = "BASE";
|
|
346
|
+
let matchedFitPriceCost: any = null;
|
|
347
|
+
|
|
348
|
+
if (priceList.TType === "SALE" && service.Sale) {
|
|
349
|
+
// Check if equipment-based service (FitPriceCosts) or simple service (Price)
|
|
350
|
+
if (service.FitPriceCosts && service.FitPriceCosts.length > 0) {
|
|
351
|
+
// Equipment-based service - need equipment information
|
|
352
|
+
if (!equipment) {
|
|
353
|
+
warnings.push("Equipment information required for equipment-based service pricing.");
|
|
354
|
+
service.PriceListWarnings = warnings;
|
|
355
|
+
return service;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// Find matching FitPriceCost for equipment
|
|
359
|
+
matchedFitPriceCost = findMatchingFitPriceCost(service.FitPriceCosts, equipment);
|
|
360
|
+
if (!matchedFitPriceCost || !matchedFitPriceCost.Sale) {
|
|
361
|
+
warnings.push(`No pricing found for ${equipment.Make || 'Unknown'} ${equipment.Model || ''}`);
|
|
362
|
+
service.PriceListWarnings = warnings;
|
|
363
|
+
return service;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
basePrice = matchedFitPriceCost.Sale;
|
|
367
|
+
basePriceSource = "FIT";
|
|
368
|
+
} else if (IsNotNull(service.Sale.Price)) {
|
|
369
|
+
// Simple service - single base price
|
|
370
|
+
basePrice = {
|
|
371
|
+
Price: service.Sale.Price,
|
|
372
|
+
FSale: service.Sale.FSale,
|
|
373
|
+
BHours: service.Sale.BHours,
|
|
374
|
+
Dur: service.Sale.Dur,
|
|
375
|
+
};
|
|
376
|
+
basePriceSource = "BASE";
|
|
377
|
+
} else {
|
|
378
|
+
warnings.push("No base pricing configured for service.");
|
|
379
|
+
service.PriceListWarnings = warnings;
|
|
380
|
+
return service;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// Step 2: Check for item-specific price list overrides (SalePrices)
|
|
384
|
+
// For equipment services: Look inside matched FitPriceCost
|
|
385
|
+
// For simple services: Look at root level
|
|
386
|
+
let salePriceOverride: any = null;
|
|
387
|
+
if (priceListId) {
|
|
388
|
+
if (matchedFitPriceCost && Array.isArray(matchedFitPriceCost.Sale?.SalePrices)) {
|
|
389
|
+
// Equipment service - check nested SalePrices inside matched FitPriceCost
|
|
390
|
+
salePriceOverride = matchedFitPriceCost.Sale.SalePrices.find(
|
|
391
|
+
(sp: any) => sp?.PrListId && sp.PrListId.toString() === priceListId
|
|
392
|
+
);
|
|
393
|
+
} else if (Array.isArray(service.SalePrices)) {
|
|
394
|
+
// Simple service - check root-level SalePrices
|
|
395
|
+
salePriceOverride = service.SalePrices.find(
|
|
396
|
+
(sp: any) => sp?.PrListId && sp.PrListId.toString() === priceListId
|
|
397
|
+
);
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
if (salePriceOverride) {
|
|
402
|
+
// Apply item-specific override
|
|
403
|
+
const originalPrice = basePrice.Price;
|
|
404
|
+
service.Sale.PriceBeforePriceList = originalPrice;
|
|
405
|
+
|
|
406
|
+
// Check for quantity tiers in override
|
|
407
|
+
const tierList = salePriceOverride.QtyTiers ?? priceList.QtyTiers;
|
|
408
|
+
const tier = resolveTier(resolvedQty, tierList);
|
|
409
|
+
|
|
410
|
+
if (tier) {
|
|
411
|
+
// Apply tier pricing
|
|
412
|
+
const tierValue = applyTierAdjustmentForSale(basePrice, tier);
|
|
413
|
+
service.Sale.Price = applyRounding(priceList, tierValue);
|
|
414
|
+
service.Sale.AppliedPriceListId = priceList._id ?? null;
|
|
415
|
+
service.Sale.AppliedPriceTier = buildAppliedTierMeta(tier);
|
|
416
|
+
service.Sale.AppliedPriceCalc = "TIER_OVERRIDE";
|
|
417
|
+
service.Sale.PriceSource = basePriceSource;
|
|
418
|
+
} else if (IsNotNull(salePriceOverride.Price)) {
|
|
419
|
+
// Fixed price override
|
|
420
|
+
service.Sale.Price = applyRounding(priceList, salePriceOverride.Price);
|
|
421
|
+
service.Sale.AppliedPriceListId = priceList._id ?? null;
|
|
422
|
+
service.Sale.AppliedPriceCalc = "FIXED_OVERRIDE";
|
|
423
|
+
service.Sale.PriceSource = basePriceSource;
|
|
424
|
+
} else if (IsNotNull(salePriceOverride.Disc)) {
|
|
425
|
+
// Percentage discount override
|
|
426
|
+
const discountedPrice = CalcDiscPrice(originalPrice, salePriceOverride.Disc, false);
|
|
427
|
+
service.Sale.Price = applyRounding(priceList, discountedPrice);
|
|
428
|
+
service.Sale.AppliedPriceListId = priceList._id ?? null;
|
|
429
|
+
service.Sale.AppliedPriceCalc = "DISCOUNT_OVERRIDE";
|
|
430
|
+
service.Sale.PriceSource = basePriceSource;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
// Apply other override fields
|
|
434
|
+
if (IsNotNull(salePriceOverride.BHours)) {
|
|
435
|
+
service.Sale.BHours = salePriceOverride.BHours;
|
|
436
|
+
}
|
|
437
|
+
if (IsNotNull(salePriceOverride.Dur)) {
|
|
438
|
+
service.Sale.Dur = salePriceOverride.Dur;
|
|
439
|
+
}
|
|
440
|
+
if (IsNotNull(salePriceOverride.FSale)) {
|
|
441
|
+
service.Sale.FSale = salePriceOverride.FSale;
|
|
442
|
+
}
|
|
443
|
+
} else {
|
|
444
|
+
// Step 3: Apply global price list calculation
|
|
445
|
+
const originalPrice = basePrice.Price;
|
|
446
|
+
service.Sale.PriceBeforePriceList = originalPrice;
|
|
447
|
+
|
|
448
|
+
const tier = resolveTier(resolvedQty, priceList.QtyTiers);
|
|
449
|
+
if (tier) {
|
|
450
|
+
const tierValue = applyTierAdjustmentForSale(basePrice, tier);
|
|
451
|
+
service.Sale.Price = applyRounding(priceList, tierValue);
|
|
452
|
+
service.Sale.AppliedPriceListId = priceList._id ?? null;
|
|
453
|
+
service.Sale.AppliedPriceTier = buildAppliedTierMeta(tier);
|
|
454
|
+
service.Sale.AppliedPriceCalc = "TIER";
|
|
455
|
+
service.Sale.PriceSource = basePriceSource;
|
|
456
|
+
} else {
|
|
457
|
+
// Apply global calculation
|
|
458
|
+
const { value, tierWarnings, appliedCalc } = evaluatePriceBlock(
|
|
459
|
+
originalPrice,
|
|
460
|
+
service.Pur,
|
|
461
|
+
priceList,
|
|
462
|
+
resolvedQty
|
|
463
|
+
);
|
|
464
|
+
|
|
465
|
+
if (value != null) {
|
|
466
|
+
service.Sale.Price = value;
|
|
467
|
+
service.Sale.AppliedPriceListId = priceList._id ?? null;
|
|
468
|
+
service.Sale.AppliedPriceCalc = appliedCalc ?? "GLOBAL";
|
|
469
|
+
service.Sale.PriceSource = basePriceSource;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
if (tierWarnings.length > 0) {
|
|
473
|
+
warnings.push(...tierWarnings);
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
// Step 4: Handle Purchase pricing (similar logic for Pur side)
|
|
480
|
+
if (priceList.TType === "PUR" && service.Pur) {
|
|
481
|
+
let baseCost: any = null;
|
|
482
|
+
let baseCostSource: string = "BASE";
|
|
483
|
+
|
|
484
|
+
if (service.FitPriceCosts && service.FitPriceCosts.length > 0) {
|
|
485
|
+
// Equipment-based service - need equipment information
|
|
486
|
+
if (!equipment) {
|
|
487
|
+
warnings.push("Equipment information required for equipment-based service costing.");
|
|
488
|
+
service.PriceListWarnings = warnings;
|
|
489
|
+
return service;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
// Reuse the matchedFitPriceCost from Sale section if available
|
|
493
|
+
const fitPriceCostEntry = matchedFitPriceCost || findMatchingFitPriceCost(service.FitPriceCosts, equipment);
|
|
494
|
+
if (!fitPriceCostEntry || !fitPriceCostEntry.Pur) {
|
|
495
|
+
warnings.push(`No costing found for ${equipment.Make || 'Unknown'} ${equipment.Model || ''}`);
|
|
496
|
+
service.PriceListWarnings = warnings;
|
|
497
|
+
return service;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
baseCost = fitPriceCostEntry.Pur;
|
|
501
|
+
baseCostSource = "FIT";
|
|
502
|
+
matchedFitPriceCost = fitPriceCostEntry; // Store for later use
|
|
503
|
+
} else if (IsNotNull(service.Pur.Cost)) {
|
|
504
|
+
baseCost = {
|
|
505
|
+
Cost: service.Pur.Cost,
|
|
506
|
+
FCost: service.Pur.FCost,
|
|
507
|
+
};
|
|
508
|
+
baseCostSource = "BASE";
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
if (baseCost) {
|
|
512
|
+
// Check for purchase cost overrides
|
|
513
|
+
// For equipment services: Look inside matched FitPriceCost
|
|
514
|
+
// For simple services: Look at root level
|
|
515
|
+
let purchaseCostOverride: any = null;
|
|
516
|
+
if (priceListId) {
|
|
517
|
+
if (matchedFitPriceCost && Array.isArray(matchedFitPriceCost.Pur?.PurchaseCosts)) {
|
|
518
|
+
// Equipment service - check nested PurchaseCosts inside matched FitPriceCost
|
|
519
|
+
purchaseCostOverride = matchedFitPriceCost.Pur.PurchaseCosts.find(
|
|
520
|
+
(pc: any) => pc?.PrListId && pc.PrListId.toString() === priceListId
|
|
521
|
+
);
|
|
522
|
+
} else if (Array.isArray(service.PurchaseCosts)) {
|
|
523
|
+
// Simple service - check root-level PurchaseCosts
|
|
524
|
+
purchaseCostOverride = service.PurchaseCosts.find(
|
|
525
|
+
(pc: any) => pc?.PrListId && pc.PrListId.toString() === priceListId
|
|
526
|
+
);
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
const originalCost = baseCost.Cost;
|
|
531
|
+
service.Pur.CostBeforePriceList = originalCost;
|
|
532
|
+
|
|
533
|
+
if (purchaseCostOverride) {
|
|
534
|
+
if (IsNotNull(purchaseCostOverride.Cost)) {
|
|
535
|
+
service.Pur.Cost = applyRounding(priceList, purchaseCostOverride.Cost);
|
|
536
|
+
service.Pur.AppliedPriceListId = priceList._id ?? null;
|
|
537
|
+
service.Pur.CostSource = baseCostSource;
|
|
538
|
+
} else if (IsNotNull(purchaseCostOverride.Disc)) {
|
|
539
|
+
const discountedCost = CalcDiscPrice(originalCost, purchaseCostOverride.Disc, false);
|
|
540
|
+
service.Pur.Cost = applyRounding(priceList, discountedCost);
|
|
541
|
+
service.Pur.AppliedPriceListId = priceList._id ?? null;
|
|
542
|
+
service.Pur.CostSource = baseCostSource;
|
|
543
|
+
}
|
|
544
|
+
} else {
|
|
545
|
+
const { value, tierWarnings } = evaluatePriceBlock(
|
|
546
|
+
originalCost,
|
|
547
|
+
service.Pur,
|
|
548
|
+
priceList,
|
|
549
|
+
resolvedQty
|
|
550
|
+
);
|
|
551
|
+
|
|
552
|
+
if (value != null) {
|
|
553
|
+
service.Pur.Cost = value;
|
|
554
|
+
service.Pur.AppliedPriceListId = priceList._id ?? null;
|
|
555
|
+
service.Pur.CostSource = baseCostSource;
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
if (tierWarnings.length > 0) {
|
|
559
|
+
warnings.push(...tierWarnings);
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
if (warnings.length > 0) {
|
|
566
|
+
service.PriceListWarnings = warnings;
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
return service;
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
/**
|
|
573
|
+
* Finds the matching FitPriceCost entry for a given equipment (automotive, HVAC, medical, industrial, etc.)
|
|
574
|
+
* Tries most specific match first (Make + Model + Variant), then progressively less specific
|
|
575
|
+
*/
|
|
576
|
+
function findMatchingFitPriceCost(fitPriceCosts: any[], equipment: any): any | null {
|
|
577
|
+
if (!Array.isArray(fitPriceCosts) || fitPriceCosts.length === 0 || !equipment) {
|
|
578
|
+
return null;
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
const equipmentMakeId = equipment.Make_Id?.toString?.();
|
|
582
|
+
const equipmentModelId = equipment.Model_Id?.toString?.();
|
|
583
|
+
const equipmentVarId = equipment.Var_Id?.toString?.() || equipment.Variant_Id?.toString?.();
|
|
584
|
+
|
|
585
|
+
// Try Make + Model + Variant
|
|
586
|
+
if (equipmentMakeId && equipmentModelId && equipmentVarId) {
|
|
587
|
+
const match = fitPriceCosts.find((fpc: any) => {
|
|
588
|
+
if (!Array.isArray(fpc.Fit) || fpc.Fit.length === 0) return false;
|
|
589
|
+
return fpc.Fit.some((fit: any) =>
|
|
590
|
+
fit.Make_Id?.toString?.() === equipmentMakeId &&
|
|
591
|
+
fit.Model_Id?.toString?.() === equipmentModelId &&
|
|
592
|
+
fit.Var_Id?.toString?.() === equipmentVarId
|
|
593
|
+
);
|
|
594
|
+
});
|
|
595
|
+
if (match) return match;
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
// Try Make + Model
|
|
599
|
+
if (equipmentMakeId && equipmentModelId) {
|
|
600
|
+
const match = fitPriceCosts.find((fpc: any) => {
|
|
601
|
+
if (!Array.isArray(fpc.Fit) || fpc.Fit.length === 0) return false;
|
|
602
|
+
return fpc.Fit.some((fit: any) =>
|
|
603
|
+
fit.Make_Id?.toString?.() === equipmentMakeId &&
|
|
604
|
+
fit.Model_Id?.toString?.() === equipmentModelId &&
|
|
605
|
+
!fit.Var_Id
|
|
606
|
+
);
|
|
607
|
+
});
|
|
608
|
+
if (match) return match;
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
// Try Make only
|
|
612
|
+
if (equipmentMakeId) {
|
|
613
|
+
const match = fitPriceCosts.find((fpc: any) => {
|
|
614
|
+
if (!Array.isArray(fpc.Fit) || fpc.Fit.length === 0) return false;
|
|
615
|
+
return fpc.Fit.some((fit: any) =>
|
|
616
|
+
fit.Make_Id?.toString?.() === equipmentMakeId &&
|
|
617
|
+
!fit.Model_Id
|
|
618
|
+
);
|
|
619
|
+
});
|
|
620
|
+
if (match) return match;
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
// Try generic (no Make/Model/Variant specified = applies to all)
|
|
624
|
+
const genericMatch = fitPriceCosts.find((fpc: any) => {
|
|
625
|
+
if (!Array.isArray(fpc.Fit) || fpc.Fit.length === 0) return true; // No fit = applies to all
|
|
626
|
+
return fpc.Fit.some((fit: any) => !fit.Make_Id && !fit.Model_Id && !fit.Var_Id);
|
|
627
|
+
});
|
|
628
|
+
|
|
629
|
+
return genericMatch || null;
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
/**
|
|
633
|
+
* Applies tier adjustment to sale pricing
|
|
634
|
+
*/
|
|
635
|
+
function applyTierAdjustmentForSale(
|
|
636
|
+
baseSale: any,
|
|
637
|
+
tier: QuantityTier
|
|
638
|
+
): number | null {
|
|
639
|
+
if (IsNotNull(tier.Price)) {
|
|
640
|
+
return tier.Price ?? null;
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
if (IsNotNull(tier.Disc)) {
|
|
644
|
+
const basePrice = baseSale?.Price ?? 0;
|
|
645
|
+
return CalcDiscPrice(basePrice, tier.Disc ?? 0, false);
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
return baseSale?.Price ?? null;
|
|
649
|
+
}
|