@qrwise/pos-calculations 0.0.27 → 0.0.29
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/dist/index.cjs +55 -2
- package/dist/index.d.cts +14 -1
- package/dist/index.d.ts +14 -1
- package/dist/index.js +53 -2
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -27,6 +27,8 @@ __export(index_exports, {
|
|
|
27
27
|
getDiscountBreakdown: () => getDiscountBreakdown,
|
|
28
28
|
isAddVatAfterDiscount: () => isAddVatAfterDiscount,
|
|
29
29
|
isVatExemptDiscount: () => isVatExemptDiscount,
|
|
30
|
+
subscriptionTaxFromBase: () => subscriptionTaxFromBase,
|
|
31
|
+
subscriptionTaxFromTotal: () => subscriptionTaxFromTotal,
|
|
30
32
|
toMoneyNumber: () => toMoneyNumber
|
|
31
33
|
});
|
|
32
34
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -436,6 +438,7 @@ function buildTransactionProjection(transaction, options = {}) {
|
|
|
436
438
|
const storedZeroRatedSales = toMoneyNumber(transaction.zero_rated_sales);
|
|
437
439
|
const storedNonTaxableSales = toMoneyNumber(transaction.non_taxable_sales);
|
|
438
440
|
const storedNetOfVat = storedVatSales + storedVatExemptSales + storedZeroRatedSales + storedNonTaxableSales;
|
|
441
|
+
const serviceCharge = toMoneyNumber(transaction.service_charge_amount);
|
|
439
442
|
const reconstructsVoidedVoucherSale = !isSuccessful && hasVoucher && gross > 0 && options.isVatRegistered !== void 0;
|
|
440
443
|
const voidedVoucherNet = reconstructsVoidedVoucherSale ? format2(gross / (options.isVatRegistered ? 1.12 : 1)) : 0;
|
|
441
444
|
const netOfVat = voidedVoucherNet || storedNetOfVat || Math.max(0, toMoneyNumber(transaction.amount_payable) - storedVat);
|
|
@@ -487,12 +490,25 @@ function buildTransactionProjection(transaction, options = {}) {
|
|
|
487
490
|
adjustments.vatOnReturns = returned ? -vatAmount : 0;
|
|
488
491
|
adjustments.vatOnCancelled = cancelled ? -vatAmount : 0;
|
|
489
492
|
adjustments.totalAdjustments = Object.values(adjustments).reduce((total, amount) => total + amount, 0);
|
|
490
|
-
|
|
493
|
+
let vatableSales = isSuccessful ? isNonVat ? 0 : hasVoucherAndDiscount ? format2(storedVatSales + Math.abs(otherDiscount)) : voucher > 0 ? scopedVoucherVatNet : storedVatSales : isNonVat ? 0 : netOfVat;
|
|
494
|
+
const projectedGross = format2(vatableSales + vatAmount + vatExemptSales + storedZeroRatedSales);
|
|
495
|
+
const unclassifiedDiscountGross = format2(gross - projectedGross);
|
|
496
|
+
const storedComponentPayable = format2(storedNetOfVat + storedVat - discount + serviceCharge);
|
|
497
|
+
const hasHistoricalUnclassifiedDiscount = isSuccessful && !isNonVat && !hasVoucher && storedNonTaxableSales === 0 && unclassifiedDiscountGross > 0.02 && Math.abs(format2(toMoneyNumber(transaction.amount_payable) - storedComponentPayable)) <= 0.02;
|
|
498
|
+
if (hasHistoricalUnclassifiedDiscount) {
|
|
499
|
+
const inferredDiscountNet = format2(unclassifiedDiscountGross / 1.12);
|
|
500
|
+
const inferredDiscountVat = format2(unclassifiedDiscountGross - inferredDiscountNet);
|
|
501
|
+
vatableSales = format2(vatableSales + inferredDiscountNet);
|
|
502
|
+
vatAmount = format2(vatAmount + inferredDiscountVat);
|
|
503
|
+
deductions.otherDiscount = -inferredDiscountNet;
|
|
504
|
+
deductions.totalDeductions = format2(deductions.totalDeductions - inferredDiscountNet);
|
|
505
|
+
adjustments.otherDiscountAdjustment = -inferredDiscountVat;
|
|
506
|
+
adjustments.totalAdjustments = format2(adjustments.totalAdjustments - inferredDiscountVat);
|
|
507
|
+
}
|
|
491
508
|
const zeroRatedSales = isSuccessful ? storedZeroRatedSales : 0;
|
|
492
509
|
const netSales = isSuccessful ? format2(
|
|
493
510
|
vatableSales + vatExemptSales + zeroRatedSales + (isNonVat ? 0 : storedNonTaxableSales) + deductions.scDiscount + deductions.pwdDiscount + deductions.naacDiscount + deductions.soloDiscount + deductions.movDiscount + deductions.otherDiscount
|
|
494
511
|
) : 0;
|
|
495
|
-
const serviceCharge = toMoneyNumber(transaction.service_charge_amount);
|
|
496
512
|
return {
|
|
497
513
|
state,
|
|
498
514
|
receipt: {
|
|
@@ -530,6 +546,41 @@ function buildTransactionProjection(transaction, options = {}) {
|
|
|
530
546
|
discountCounts: counts
|
|
531
547
|
};
|
|
532
548
|
}
|
|
549
|
+
|
|
550
|
+
// src/subscription-tax.ts
|
|
551
|
+
function cents(amount) {
|
|
552
|
+
const value = Number(amount);
|
|
553
|
+
const result = Math.round(value * 100);
|
|
554
|
+
if (!Number.isFinite(value) || value < 0 || !Number.isSafeInteger(result) || Math.abs(value * 100 - result) > 1e-4)
|
|
555
|
+
throw new Error("Invalid subscription amount");
|
|
556
|
+
return result;
|
|
557
|
+
}
|
|
558
|
+
function subscriptionTaxFromBase(amount) {
|
|
559
|
+
const base = cents(amount);
|
|
560
|
+
const vat = Math.round(base * 12 / 100);
|
|
561
|
+
if (!Number.isSafeInteger(base + vat)) throw new Error("Invalid subscription total");
|
|
562
|
+
return { base_price: base / 100, vat_amount: vat / 100, amount: (base + vat) / 100 };
|
|
563
|
+
}
|
|
564
|
+
function subscriptionTaxFromTotal(amount) {
|
|
565
|
+
const total = cents(amount);
|
|
566
|
+
const { vatNet } = calculateTotals({
|
|
567
|
+
quantity: 1,
|
|
568
|
+
discountableTotalAmount: total / 100,
|
|
569
|
+
nonDiscountableTotalAmount: 0,
|
|
570
|
+
serviceChargeableTotalAmount: 0,
|
|
571
|
+
togoableTotalAmount: 0,
|
|
572
|
+
voucherType: null,
|
|
573
|
+
voucherRate: 0,
|
|
574
|
+
discountType: null,
|
|
575
|
+
discountRate: 0,
|
|
576
|
+
vatRate: 112,
|
|
577
|
+
isVatRegistered: true,
|
|
578
|
+
serviceChargeRate: 0,
|
|
579
|
+
togoCharge: 0
|
|
580
|
+
});
|
|
581
|
+
const base = Math.round(vatNet * 100);
|
|
582
|
+
return { base_price: base / 100, vat_amount: (total - base) / 100, amount: total / 100 };
|
|
583
|
+
}
|
|
533
584
|
// Annotate the CommonJS export names for ESM import in node:
|
|
534
585
|
0 && (module.exports = {
|
|
535
586
|
buildTransactionProjection,
|
|
@@ -539,5 +590,7 @@ function buildTransactionProjection(transaction, options = {}) {
|
|
|
539
590
|
getDiscountBreakdown,
|
|
540
591
|
isAddVatAfterDiscount,
|
|
541
592
|
isVatExemptDiscount,
|
|
593
|
+
subscriptionTaxFromBase,
|
|
594
|
+
subscriptionTaxFromTotal,
|
|
542
595
|
toMoneyNumber
|
|
543
596
|
});
|
package/dist/index.d.cts
CHANGED
|
@@ -197,4 +197,17 @@ declare function buildTransactionProjection(transaction: FinancialTransactionInp
|
|
|
197
197
|
discountCounts: DiscountWeights;
|
|
198
198
|
};
|
|
199
199
|
|
|
200
|
-
|
|
200
|
+
/** Catalog subscription prices exclude 12% VAT. Round VAT once per charge. */
|
|
201
|
+
declare function subscriptionTaxFromBase(amount: number | string): {
|
|
202
|
+
base_price: number;
|
|
203
|
+
vat_amount: number;
|
|
204
|
+
amount: number;
|
|
205
|
+
};
|
|
206
|
+
/** Preserve the actual total on legacy subscriptions and historical payments. */
|
|
207
|
+
declare function subscriptionTaxFromTotal(amount: number | string): {
|
|
208
|
+
base_price: number;
|
|
209
|
+
vat_amount: number;
|
|
210
|
+
amount: number;
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
export { type CalculateTotalsInput, type CalculateTotalsResult, type DiscountBreakdown, type DiscountRates, type DiscountType, type FinancialTransactionInput, type PaxDiscountCounts, type ReportDiscountCategory, type TransactionProjectionOptions, type VoucherType, buildTransactionProjection, calculateTotals, clamp, format2, getDiscountBreakdown, isAddVatAfterDiscount, isVatExemptDiscount, subscriptionTaxFromBase, subscriptionTaxFromTotal, toMoneyNumber };
|
package/dist/index.d.ts
CHANGED
|
@@ -197,4 +197,17 @@ declare function buildTransactionProjection(transaction: FinancialTransactionInp
|
|
|
197
197
|
discountCounts: DiscountWeights;
|
|
198
198
|
};
|
|
199
199
|
|
|
200
|
-
|
|
200
|
+
/** Catalog subscription prices exclude 12% VAT. Round VAT once per charge. */
|
|
201
|
+
declare function subscriptionTaxFromBase(amount: number | string): {
|
|
202
|
+
base_price: number;
|
|
203
|
+
vat_amount: number;
|
|
204
|
+
amount: number;
|
|
205
|
+
};
|
|
206
|
+
/** Preserve the actual total on legacy subscriptions and historical payments. */
|
|
207
|
+
declare function subscriptionTaxFromTotal(amount: number | string): {
|
|
208
|
+
base_price: number;
|
|
209
|
+
vat_amount: number;
|
|
210
|
+
amount: number;
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
export { type CalculateTotalsInput, type CalculateTotalsResult, type DiscountBreakdown, type DiscountRates, type DiscountType, type FinancialTransactionInput, type PaxDiscountCounts, type ReportDiscountCategory, type TransactionProjectionOptions, type VoucherType, buildTransactionProjection, calculateTotals, clamp, format2, getDiscountBreakdown, isAddVatAfterDiscount, isVatExemptDiscount, subscriptionTaxFromBase, subscriptionTaxFromTotal, toMoneyNumber };
|
package/dist/index.js
CHANGED
|
@@ -403,6 +403,7 @@ function buildTransactionProjection(transaction, options = {}) {
|
|
|
403
403
|
const storedZeroRatedSales = toMoneyNumber(transaction.zero_rated_sales);
|
|
404
404
|
const storedNonTaxableSales = toMoneyNumber(transaction.non_taxable_sales);
|
|
405
405
|
const storedNetOfVat = storedVatSales + storedVatExemptSales + storedZeroRatedSales + storedNonTaxableSales;
|
|
406
|
+
const serviceCharge = toMoneyNumber(transaction.service_charge_amount);
|
|
406
407
|
const reconstructsVoidedVoucherSale = !isSuccessful && hasVoucher && gross > 0 && options.isVatRegistered !== void 0;
|
|
407
408
|
const voidedVoucherNet = reconstructsVoidedVoucherSale ? format2(gross / (options.isVatRegistered ? 1.12 : 1)) : 0;
|
|
408
409
|
const netOfVat = voidedVoucherNet || storedNetOfVat || Math.max(0, toMoneyNumber(transaction.amount_payable) - storedVat);
|
|
@@ -454,12 +455,25 @@ function buildTransactionProjection(transaction, options = {}) {
|
|
|
454
455
|
adjustments.vatOnReturns = returned ? -vatAmount : 0;
|
|
455
456
|
adjustments.vatOnCancelled = cancelled ? -vatAmount : 0;
|
|
456
457
|
adjustments.totalAdjustments = Object.values(adjustments).reduce((total, amount) => total + amount, 0);
|
|
457
|
-
|
|
458
|
+
let vatableSales = isSuccessful ? isNonVat ? 0 : hasVoucherAndDiscount ? format2(storedVatSales + Math.abs(otherDiscount)) : voucher > 0 ? scopedVoucherVatNet : storedVatSales : isNonVat ? 0 : netOfVat;
|
|
459
|
+
const projectedGross = format2(vatableSales + vatAmount + vatExemptSales + storedZeroRatedSales);
|
|
460
|
+
const unclassifiedDiscountGross = format2(gross - projectedGross);
|
|
461
|
+
const storedComponentPayable = format2(storedNetOfVat + storedVat - discount + serviceCharge);
|
|
462
|
+
const hasHistoricalUnclassifiedDiscount = isSuccessful && !isNonVat && !hasVoucher && storedNonTaxableSales === 0 && unclassifiedDiscountGross > 0.02 && Math.abs(format2(toMoneyNumber(transaction.amount_payable) - storedComponentPayable)) <= 0.02;
|
|
463
|
+
if (hasHistoricalUnclassifiedDiscount) {
|
|
464
|
+
const inferredDiscountNet = format2(unclassifiedDiscountGross / 1.12);
|
|
465
|
+
const inferredDiscountVat = format2(unclassifiedDiscountGross - inferredDiscountNet);
|
|
466
|
+
vatableSales = format2(vatableSales + inferredDiscountNet);
|
|
467
|
+
vatAmount = format2(vatAmount + inferredDiscountVat);
|
|
468
|
+
deductions.otherDiscount = -inferredDiscountNet;
|
|
469
|
+
deductions.totalDeductions = format2(deductions.totalDeductions - inferredDiscountNet);
|
|
470
|
+
adjustments.otherDiscountAdjustment = -inferredDiscountVat;
|
|
471
|
+
adjustments.totalAdjustments = format2(adjustments.totalAdjustments - inferredDiscountVat);
|
|
472
|
+
}
|
|
458
473
|
const zeroRatedSales = isSuccessful ? storedZeroRatedSales : 0;
|
|
459
474
|
const netSales = isSuccessful ? format2(
|
|
460
475
|
vatableSales + vatExemptSales + zeroRatedSales + (isNonVat ? 0 : storedNonTaxableSales) + deductions.scDiscount + deductions.pwdDiscount + deductions.naacDiscount + deductions.soloDiscount + deductions.movDiscount + deductions.otherDiscount
|
|
461
476
|
) : 0;
|
|
462
|
-
const serviceCharge = toMoneyNumber(transaction.service_charge_amount);
|
|
463
477
|
return {
|
|
464
478
|
state,
|
|
465
479
|
receipt: {
|
|
@@ -497,6 +511,41 @@ function buildTransactionProjection(transaction, options = {}) {
|
|
|
497
511
|
discountCounts: counts
|
|
498
512
|
};
|
|
499
513
|
}
|
|
514
|
+
|
|
515
|
+
// src/subscription-tax.ts
|
|
516
|
+
function cents(amount) {
|
|
517
|
+
const value = Number(amount);
|
|
518
|
+
const result = Math.round(value * 100);
|
|
519
|
+
if (!Number.isFinite(value) || value < 0 || !Number.isSafeInteger(result) || Math.abs(value * 100 - result) > 1e-4)
|
|
520
|
+
throw new Error("Invalid subscription amount");
|
|
521
|
+
return result;
|
|
522
|
+
}
|
|
523
|
+
function subscriptionTaxFromBase(amount) {
|
|
524
|
+
const base = cents(amount);
|
|
525
|
+
const vat = Math.round(base * 12 / 100);
|
|
526
|
+
if (!Number.isSafeInteger(base + vat)) throw new Error("Invalid subscription total");
|
|
527
|
+
return { base_price: base / 100, vat_amount: vat / 100, amount: (base + vat) / 100 };
|
|
528
|
+
}
|
|
529
|
+
function subscriptionTaxFromTotal(amount) {
|
|
530
|
+
const total = cents(amount);
|
|
531
|
+
const { vatNet } = calculateTotals({
|
|
532
|
+
quantity: 1,
|
|
533
|
+
discountableTotalAmount: total / 100,
|
|
534
|
+
nonDiscountableTotalAmount: 0,
|
|
535
|
+
serviceChargeableTotalAmount: 0,
|
|
536
|
+
togoableTotalAmount: 0,
|
|
537
|
+
voucherType: null,
|
|
538
|
+
voucherRate: 0,
|
|
539
|
+
discountType: null,
|
|
540
|
+
discountRate: 0,
|
|
541
|
+
vatRate: 112,
|
|
542
|
+
isVatRegistered: true,
|
|
543
|
+
serviceChargeRate: 0,
|
|
544
|
+
togoCharge: 0
|
|
545
|
+
});
|
|
546
|
+
const base = Math.round(vatNet * 100);
|
|
547
|
+
return { base_price: base / 100, vat_amount: (total - base) / 100, amount: total / 100 };
|
|
548
|
+
}
|
|
500
549
|
export {
|
|
501
550
|
buildTransactionProjection,
|
|
502
551
|
calculateTotals,
|
|
@@ -505,5 +554,7 @@ export {
|
|
|
505
554
|
getDiscountBreakdown,
|
|
506
555
|
isAddVatAfterDiscount,
|
|
507
556
|
isVatExemptDiscount,
|
|
557
|
+
subscriptionTaxFromBase,
|
|
558
|
+
subscriptionTaxFromTotal,
|
|
508
559
|
toMoneyNumber
|
|
509
560
|
};
|