@qrwise/pos-calculations 0.0.20 → 0.0.22

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 CHANGED
@@ -416,6 +416,17 @@ function voucherVatNet(transaction, voucher, discount) {
416
416
  const eligibleGross = itemizedGross > 0 ? itemizedGross : percentageGross > 0 ? percentageGross : gross;
417
417
  return format2(Math.min(gross, eligibleGross) / 1.12);
418
418
  }
419
+ function itemizedVoucherCount(transaction) {
420
+ const splits = transaction.metadata?.split_discounts;
421
+ if (!Array.isArray(splits)) return 0;
422
+ return splits.reduce((count, rawSplit) => {
423
+ if (!rawSplit || typeof rawSplit !== "object") return count;
424
+ const rawVoucher = rawSplit.voucher;
425
+ if (!rawVoucher || typeof rawVoucher !== "object") return count;
426
+ const voucher = rawVoucher;
427
+ return Math.abs(toMoneyNumber(voucher.discount_amount)) > 0 ? count + 1 : count;
428
+ }, 0);
429
+ }
419
430
  function buildTransactionProjection(transaction, options = {}) {
420
431
  const status = `${transaction.status} ${transaction.payment_status}`.toLowerCase();
421
432
  const state = status.includes("refund") || status.includes("return") ? "RETURNED" : status.includes("cancel") || status.includes("void") ? "CANCELLED" : "SUCCESS";
@@ -424,10 +435,10 @@ function buildTransactionProjection(transaction, options = {}) {
424
435
  const discount = Math.abs(toMoneyNumber(transaction.discount_amount));
425
436
  const voucher = Math.abs(toMoneyNumber(transaction.voucher_discount_amount));
426
437
  const voucherRate = toMoneyNumber(transaction.voucher_rate);
427
- const hasVoucher = voucherRate > 0;
438
+ const hasVoucher = voucher > 0;
428
439
  const hasVoucherAndDiscount = isSuccessful && voucher > 0 && discount > 0;
429
440
  const scopedVoucherVatNet = voucherVatNet(transaction, voucher, discount);
430
- const voucherForBirDiscount = -format2(
441
+ const voucherForBirDiscount = itemizedVoucherCount(transaction) > 1 ? -format2(voucher / 1.12) : -format2(
431
442
  transaction.voucher_type?.toLowerCase() === "fixed" ? scopedVoucherVatNet - format2(voucherRate) : scopedVoucherVatNet * format2(voucherRate / 100)
432
443
  );
433
444
  const otherDiscount = isSuccessful && hasVoucher ? format2(voucherForBirDiscount) : 0;
@@ -437,7 +448,9 @@ function buildTransactionProjection(transaction, options = {}) {
437
448
  const storedVatExemptSales = toMoneyNumber(transaction.vat_exempt_sales);
438
449
  const storedZeroRatedSales = toMoneyNumber(transaction.zero_rated_sales);
439
450
  const storedNonTaxableSales = toMoneyNumber(transaction.non_taxable_sales);
440
- const netOfVat = storedVatSales + storedVatExemptSales + storedZeroRatedSales + storedNonTaxableSales || Math.max(0, toMoneyNumber(transaction.amount_payable) - storedVat);
451
+ const storedNetOfVat = storedVatSales + storedVatExemptSales + storedZeroRatedSales + storedNonTaxableSales;
452
+ const fullyDiscountedCancellationNet = !isSuccessful && storedNetOfVat === 0 && toMoneyNumber(transaction.amount_payable) === 0 && gross > 0 && options.isVatRegistered !== void 0 ? format2(gross / (options.isVatRegistered ? 1.12 : 1)) : 0;
453
+ const netOfVat = storedNetOfVat || fullyDiscountedCancellationNet || Math.max(0, toMoneyNumber(transaction.amount_payable) - storedVat);
441
454
  const returned = state === "RETURNED" ? -format2(netOfVat) : 0;
442
455
  const cancelled = state === "CANCELLED" ? -format2(netOfVat) : 0;
443
456
  const { counts, discountWeights, vatExemptWeights } = discountAllocation(transaction, options);
@@ -475,9 +488,10 @@ function buildTransactionProjection(transaction, options = {}) {
475
488
  };
476
489
  const regularVat = storedVat || format2(Math.abs(storedVatExemptSales * 0.12));
477
490
  let vatAmount = format2(
478
- isSuccessful ? voucher > 0 ? Math.abs(scopedVoucherVatNet * 0.12) : regularVat : netOfVat * 0.12
491
+ isSuccessful ? voucher > 0 ? Math.abs(scopedVoucherVatNet * 0.12) : regularVat : options.isVatRegistered === false ? 0 : netOfVat * 0.12
479
492
  );
480
- if (hasVoucherAndDiscount) {
493
+ const hasMixedStatutoryTax = isSuccessful && discount > 0 && storedVat > 0 && storedVatSales > 0 && storedVatExemptSales > 0;
494
+ if (hasVoucherAndDiscount || hasMixedStatutoryTax) {
481
495
  vatAmount = format2(
482
496
  storedVat + Math.abs(adjustments.scDiscountAdjustment) + Math.abs(adjustments.pwdDiscountAdjustment) + Math.abs(adjustments.otherDiscountAdjustment)
483
497
  );
@@ -491,7 +505,6 @@ function buildTransactionProjection(transaction, options = {}) {
491
505
  vatableSales + vatExemptSales + zeroRatedSales + storedNonTaxableSales + deductions.scDiscount + deductions.pwdDiscount + deductions.naacDiscount + deductions.soloDiscount + deductions.movDiscount + deductions.otherDiscount
492
506
  ) : 0;
493
507
  const serviceCharge = toMoneyNumber(transaction.service_charge_amount);
494
- const takeoutCharge = toMoneyNumber(transaction.takeout_charge_amount);
495
508
  return {
496
509
  state,
497
510
  receipt: {
@@ -510,7 +523,6 @@ function buildTransactionProjection(transaction, options = {}) {
510
523
  storedVatSales + storedVatExemptSales + storedZeroRatedSales + storedNonTaxableSales + storedVat
511
524
  ),
512
525
  serviceCharge,
513
- takeoutCharge,
514
526
  amountPayable: toMoneyNumber(transaction.amount_payable)
515
527
  },
516
528
  report: {
@@ -522,7 +534,6 @@ function buildTransactionProjection(transaction, options = {}) {
522
534
  zeroRatedSales,
523
535
  deductions,
524
536
  serviceCharge,
525
- takeoutCharge,
526
537
  adjustments,
527
538
  vatPayable: isSuccessful ? Math.max(0, format2(vatAmount - Math.abs(adjustments.totalAdjustments))) : 0,
528
539
  netSales,
package/dist/index.d.cts CHANGED
@@ -118,7 +118,6 @@ interface FinancialTransactionInput {
118
118
  zero_rated_sales?: number | string | null;
119
119
  non_taxable_sales?: number | string | null;
120
120
  service_charge_amount?: number | string | null;
121
- takeout_charge_amount?: number | string | null;
122
121
  discount_customers?: Array<{
123
122
  discount_id?: string | null;
124
123
  discount_name?: string | null;
@@ -139,6 +138,7 @@ interface FinancialTransactionInput {
139
138
  }
140
139
  interface TransactionProjectionOptions {
141
140
  discountRatesById?: Record<string, number>;
141
+ isVatRegistered?: boolean;
142
142
  }
143
143
  declare function buildTransactionProjection(transaction: FinancialTransactionInput, options?: TransactionProjectionOptions): {
144
144
  state: string;
@@ -156,7 +156,6 @@ declare function buildTransactionProjection(transaction: FinancialTransactionInp
156
156
  vatAmount: number;
157
157
  totalSales: number;
158
158
  serviceCharge: number;
159
- takeoutCharge: number;
160
159
  amountPayable: number;
161
160
  };
162
161
  report: {
@@ -178,7 +177,6 @@ declare function buildTransactionProjection(transaction: FinancialTransactionInp
178
177
  totalDeductions: number;
179
178
  };
180
179
  serviceCharge: number;
181
- takeoutCharge: number;
182
180
  adjustments: {
183
181
  scDiscountAdjustment: number;
184
182
  pwdDiscountAdjustment: number;
package/dist/index.d.ts CHANGED
@@ -118,7 +118,6 @@ interface FinancialTransactionInput {
118
118
  zero_rated_sales?: number | string | null;
119
119
  non_taxable_sales?: number | string | null;
120
120
  service_charge_amount?: number | string | null;
121
- takeout_charge_amount?: number | string | null;
122
121
  discount_customers?: Array<{
123
122
  discount_id?: string | null;
124
123
  discount_name?: string | null;
@@ -139,6 +138,7 @@ interface FinancialTransactionInput {
139
138
  }
140
139
  interface TransactionProjectionOptions {
141
140
  discountRatesById?: Record<string, number>;
141
+ isVatRegistered?: boolean;
142
142
  }
143
143
  declare function buildTransactionProjection(transaction: FinancialTransactionInput, options?: TransactionProjectionOptions): {
144
144
  state: string;
@@ -156,7 +156,6 @@ declare function buildTransactionProjection(transaction: FinancialTransactionInp
156
156
  vatAmount: number;
157
157
  totalSales: number;
158
158
  serviceCharge: number;
159
- takeoutCharge: number;
160
159
  amountPayable: number;
161
160
  };
162
161
  report: {
@@ -178,7 +177,6 @@ declare function buildTransactionProjection(transaction: FinancialTransactionInp
178
177
  totalDeductions: number;
179
178
  };
180
179
  serviceCharge: number;
181
- takeoutCharge: number;
182
180
  adjustments: {
183
181
  scDiscountAdjustment: number;
184
182
  pwdDiscountAdjustment: number;
package/dist/index.js CHANGED
@@ -383,6 +383,17 @@ function voucherVatNet(transaction, voucher, discount) {
383
383
  const eligibleGross = itemizedGross > 0 ? itemizedGross : percentageGross > 0 ? percentageGross : gross;
384
384
  return format2(Math.min(gross, eligibleGross) / 1.12);
385
385
  }
386
+ function itemizedVoucherCount(transaction) {
387
+ const splits = transaction.metadata?.split_discounts;
388
+ if (!Array.isArray(splits)) return 0;
389
+ return splits.reduce((count, rawSplit) => {
390
+ if (!rawSplit || typeof rawSplit !== "object") return count;
391
+ const rawVoucher = rawSplit.voucher;
392
+ if (!rawVoucher || typeof rawVoucher !== "object") return count;
393
+ const voucher = rawVoucher;
394
+ return Math.abs(toMoneyNumber(voucher.discount_amount)) > 0 ? count + 1 : count;
395
+ }, 0);
396
+ }
386
397
  function buildTransactionProjection(transaction, options = {}) {
387
398
  const status = `${transaction.status} ${transaction.payment_status}`.toLowerCase();
388
399
  const state = status.includes("refund") || status.includes("return") ? "RETURNED" : status.includes("cancel") || status.includes("void") ? "CANCELLED" : "SUCCESS";
@@ -391,10 +402,10 @@ function buildTransactionProjection(transaction, options = {}) {
391
402
  const discount = Math.abs(toMoneyNumber(transaction.discount_amount));
392
403
  const voucher = Math.abs(toMoneyNumber(transaction.voucher_discount_amount));
393
404
  const voucherRate = toMoneyNumber(transaction.voucher_rate);
394
- const hasVoucher = voucherRate > 0;
405
+ const hasVoucher = voucher > 0;
395
406
  const hasVoucherAndDiscount = isSuccessful && voucher > 0 && discount > 0;
396
407
  const scopedVoucherVatNet = voucherVatNet(transaction, voucher, discount);
397
- const voucherForBirDiscount = -format2(
408
+ const voucherForBirDiscount = itemizedVoucherCount(transaction) > 1 ? -format2(voucher / 1.12) : -format2(
398
409
  transaction.voucher_type?.toLowerCase() === "fixed" ? scopedVoucherVatNet - format2(voucherRate) : scopedVoucherVatNet * format2(voucherRate / 100)
399
410
  );
400
411
  const otherDiscount = isSuccessful && hasVoucher ? format2(voucherForBirDiscount) : 0;
@@ -404,7 +415,9 @@ function buildTransactionProjection(transaction, options = {}) {
404
415
  const storedVatExemptSales = toMoneyNumber(transaction.vat_exempt_sales);
405
416
  const storedZeroRatedSales = toMoneyNumber(transaction.zero_rated_sales);
406
417
  const storedNonTaxableSales = toMoneyNumber(transaction.non_taxable_sales);
407
- const netOfVat = storedVatSales + storedVatExemptSales + storedZeroRatedSales + storedNonTaxableSales || Math.max(0, toMoneyNumber(transaction.amount_payable) - storedVat);
418
+ const storedNetOfVat = storedVatSales + storedVatExemptSales + storedZeroRatedSales + storedNonTaxableSales;
419
+ const fullyDiscountedCancellationNet = !isSuccessful && storedNetOfVat === 0 && toMoneyNumber(transaction.amount_payable) === 0 && gross > 0 && options.isVatRegistered !== void 0 ? format2(gross / (options.isVatRegistered ? 1.12 : 1)) : 0;
420
+ const netOfVat = storedNetOfVat || fullyDiscountedCancellationNet || Math.max(0, toMoneyNumber(transaction.amount_payable) - storedVat);
408
421
  const returned = state === "RETURNED" ? -format2(netOfVat) : 0;
409
422
  const cancelled = state === "CANCELLED" ? -format2(netOfVat) : 0;
410
423
  const { counts, discountWeights, vatExemptWeights } = discountAllocation(transaction, options);
@@ -442,9 +455,10 @@ function buildTransactionProjection(transaction, options = {}) {
442
455
  };
443
456
  const regularVat = storedVat || format2(Math.abs(storedVatExemptSales * 0.12));
444
457
  let vatAmount = format2(
445
- isSuccessful ? voucher > 0 ? Math.abs(scopedVoucherVatNet * 0.12) : regularVat : netOfVat * 0.12
458
+ isSuccessful ? voucher > 0 ? Math.abs(scopedVoucherVatNet * 0.12) : regularVat : options.isVatRegistered === false ? 0 : netOfVat * 0.12
446
459
  );
447
- if (hasVoucherAndDiscount) {
460
+ const hasMixedStatutoryTax = isSuccessful && discount > 0 && storedVat > 0 && storedVatSales > 0 && storedVatExemptSales > 0;
461
+ if (hasVoucherAndDiscount || hasMixedStatutoryTax) {
448
462
  vatAmount = format2(
449
463
  storedVat + Math.abs(adjustments.scDiscountAdjustment) + Math.abs(adjustments.pwdDiscountAdjustment) + Math.abs(adjustments.otherDiscountAdjustment)
450
464
  );
@@ -458,7 +472,6 @@ function buildTransactionProjection(transaction, options = {}) {
458
472
  vatableSales + vatExemptSales + zeroRatedSales + storedNonTaxableSales + deductions.scDiscount + deductions.pwdDiscount + deductions.naacDiscount + deductions.soloDiscount + deductions.movDiscount + deductions.otherDiscount
459
473
  ) : 0;
460
474
  const serviceCharge = toMoneyNumber(transaction.service_charge_amount);
461
- const takeoutCharge = toMoneyNumber(transaction.takeout_charge_amount);
462
475
  return {
463
476
  state,
464
477
  receipt: {
@@ -477,7 +490,6 @@ function buildTransactionProjection(transaction, options = {}) {
477
490
  storedVatSales + storedVatExemptSales + storedZeroRatedSales + storedNonTaxableSales + storedVat
478
491
  ),
479
492
  serviceCharge,
480
- takeoutCharge,
481
493
  amountPayable: toMoneyNumber(transaction.amount_payable)
482
494
  },
483
495
  report: {
@@ -489,7 +501,6 @@ function buildTransactionProjection(transaction, options = {}) {
489
501
  zeroRatedSales,
490
502
  deductions,
491
503
  serviceCharge,
492
- takeoutCharge,
493
504
  adjustments,
494
505
  vatPayable: isSuccessful ? Math.max(0, format2(vatAmount - Math.abs(adjustments.totalAdjustments))) : 0,
495
506
  netSales,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qrwise/pos-calculations",
3
- "version": "0.0.20",
3
+ "version": "0.0.22",
4
4
  "description": "Shared POS calculations for QR Wise POS",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",