Attached Files | Videograbación 2023-05-09 09:47:31.mp4 [^] (1,520,893 bytes) 2023-05-09 14:47
patch52399.diff [^] (12,887 bytes) 2023-05-24 10:04 [Show Content] [Hide Content]commit 515c5b8ee71a6719f81cb6fee4984617df8ab862
Author: Aaron Calero <aaron.calero@openbravo.com>
Date: Wed May 24 09:46:13 2023 +0200
Fixed ISSUE-52399: Backport of 49994 and 48273. Fixed payment and discounts rounding issues
diff --git a/web-test/model/business-object/ticket/CalculateTotalsModelHook.test.js b/web-test/model/business-object/ticket/CalculateTotalsModelHook.test.js
index a305f6e00..95af798d4 100644
--- a/web-test/model/business-object/ticket/CalculateTotalsModelHook.test.js
+++ b/web-test/model/business-object/ticket/CalculateTotalsModelHook.test.js
@@ -1,6 +1,6 @@
/*
************************************************************************************
- * Copyright (C) 2020-2021 Openbravo S.L.U.
+ * Copyright (C) 2020-2022 Openbravo S.L.U.
* Licensed under the Openbravo Commercial License version 1.0
* You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html
* or in the legal folder of this module distribution.
@@ -407,9 +407,11 @@ describe('Apply Discounts and Taxes Model Hook', () => {
});
test.each`
- payloadTicket | discountsEngineResult | taxEngineResult | resultTicket
- ${{ id: '0', priceIncludesTax: true, lines: [{ id: '1', grossUnitPrice: 0, baseGrossUnitPrice: 100, qty: -1, quantity: 1, skipApplyPromotions: true, promotions: [{ amt: 100, actualAmt: 100, displayedTotalAmount: 100 }] }], payments: [] }} | ${{ lines: [] }} | ${{ grossAmount: 0, lines: [{ id: '1', grossUnitAmount: 0, grossUnitPrice: 0 }] }} | ${{ id: '0', grossAmount: 0, lines: [{ id: '1', grossUnitAmount: 0, grossUnitPrice: 0, promotions: [{ amt: 100, actualAmt: 100, displayedTotalAmount: 100 }] }] }}
- ${{ id: '0', priceIncludesTax: true, lines: [{ id: '1', grossUnitPrice: 90, baseGrossUnitPrice: 100, qty: -1, quantity: 1, skipApplyPromotions: true, promotions: [{ amt: 10, actualAmt: 10, displayedTotalAmount: 10 }] }], payments: [] }} | ${{ lines: [] }} | ${{ grossAmount: -90, lines: [{ id: '1', grossUnitAmount: -90, grossUnitPrice: 90 }] }} | ${{ id: '0', grossAmount: -90, lines: [{ id: '1', grossUnitAmount: -90, grossUnitPrice: 90, promotions: [{ amt: 10, actualAmt: 10, displayedTotalAmount: 10 }] }] }}
+ payloadTicket | discountsEngineResult | taxEngineResult | resultTicket
+ ${{ id: '0', priceIncludesTax: true, lines: [{ id: '1', grossUnitPrice: 0, baseGrossUnitPrice: 100, qty: -1, quantity: 1, skipApplyPromotions: true, promotions: [{ amt: -100 }] }], payments: [] }} | ${{ lines: [] }} | ${{ grossAmount: 0, lines: [{ id: '1', grossUnitAmount: 0 }] }} | ${{ id: '0', grossAmount: 0, lines: [{ id: '1', qty: -1, grossUnitAmount: 0, promotions: [{ amt: -100 }] }] }}
+ ${{ id: '0', priceIncludesTax: true, lines: [{ id: '1', grossUnitPrice: 90, baseGrossUnitPrice: 100, qty: -1, quantity: 1, skipApplyPromotions: true, promotions: [{ amt: -10 }] }], payments: [] }} | ${{ lines: [] }} | ${{ grossAmount: -90, lines: [{ id: '1', grossUnitAmount: -90 }] }} | ${{ id: '0', grossAmount: -90, lines: [{ id: '1', qty: -1, grossUnitAmount: -90, promotions: [{ amt: -10 }] }] }}
+ ${{ id: '0', priceIncludesTax: true, lines: [{ id: '1', grossUnitPrice: 3.56, baseGrossUnitPrice: 3.95, qty: -2, quantity: 2, skipApplyPromotions: true, promotions: [{ amt: -0.79 }] }], payments: [] }} | ${{ lines: [] }} | ${{ grossAmount: -7.11, lines: [{ id: '1', grossUnitAmount: -7.11 }] }} | ${{ id: '0', grossAmount: -7.11, lines: [{ id: '1', qty: -2, grossUnitAmount: -7.11, promotions: [{ amt: -0.79 }] }] }}
+ ${{ id: '0', priceIncludesTax: false, lines: [{ id: '1', netUnitPrice: 3.56, baseNetUnitPrice: 3.95, qty: -2, quantity: 2, skipApplyPromotions: true, promotions: [{ amt: -0.79 }] }], payments: [] }} | ${{ lines: [] }} | ${{ grossAmount: -7.11, lines: [{ id: '1', netUnitAmount: -7.11 }] }} | ${{ id: '0', grossAmount: -7.11, lines: [{ id: '1', qty: -2, netUnitAmount: -7.11, promotions: [{ amt: -0.79 }] }] }}
`(
'Skip calculate line gross amount if line skipApplyPromotions is true',
({
@@ -419,7 +421,12 @@ describe('Apply Discounts and Taxes Model Hook', () => {
resultTicket
}) => {
setDiscountsEngineResultAs(discountsEngineResult);
- setTaxesEngineResultAs(taxEngineResult);
+ OB.Taxes.Pos.translateTaxes = jest.fn().mockReturnValue(taxEngineResult);
+ OB.Taxes.Pos.applyTaxes = jest.fn().mockImplementation(ticket => {
+ expect(ticket.lines).toMatchObject(resultTicket.lines);
+ return taxEngineResult;
+ });
+
const result = hook(deepfreeze(payloadTicket), payload());
expect(result).toMatchObject(resultTicket);
}
diff --git a/web/org.openbravo.retail.posterminal/app/model/business-object/ticket/TicketUtils.js b/web/org.openbravo.retail.posterminal/app/model/business-object/ticket/TicketUtils.js
index a6b3a767c..e3259b786 100644
--- a/web/org.openbravo.retail.posterminal/app/model/business-object/ticket/TicketUtils.js
+++ b/web/org.openbravo.retail.posterminal/app/model/business-object/ticket/TicketUtils.js
@@ -1,6 +1,6 @@
/*
************************************************************************************
- * Copyright (C) 2020-2021 Openbravo S.L.U.
+ * Copyright (C) 2020-2022 Openbravo S.L.U.
* Licensed under the Openbravo Commercial License version 1.0
* You may obtain a copy of the License at http://www.openbravo.com/legal/obcl.html
* or in the legal folder of this module distribution.
@@ -444,77 +444,59 @@
return quantity === 0 ? 0 : OB.DEC.div(unitAmount, quantity);
};
+ const isBooked = OB.App.State.Ticket.Utils.isBooked(this.ticket);
+
// sets line amounts and prices and applies the discount calculation result into the ticket
this.ticket.lines = this.ticket.lines.map(line => {
const hasDiscounts = line.promotions && line.promotions.length > 0;
const {
baseGrossUnitPrice,
grossUnitPrice,
- grossUnitAmount,
baseNetUnitPrice,
netUnitPrice,
- netUnitAmount,
qty
} = line;
- if (line.skipApplyPromotions && hasDiscounts) {
- const newLine = { ...line };
-
- if (priceIncludesTax) {
- newLine.grossUnitAmount =
- grossUnitAmount || OB.DEC.mul(grossUnitPrice, qty);
- newLine.netUnitAmount = undefined;
- // This part is only used for visualization in WebPOS 2.0
- newLine.grossUnitAmountWithoutTicketDiscounts = calculateUnitAmountWithoutTicketDiscounts(
- OB.DEC.mul(baseGrossUnitPrice, qty),
- newLine.promotions
- );
- newLine.grossUnitPriceWithoutTicketDiscounts = calculateUnitPriceWithoutTicketDiscounts(
- newLine.grossUnitAmountWithoutTicketDiscounts,
- qty
- );
- } else {
- newLine.netUnitAmount =
- netUnitAmount || OB.DEC.mul(baseNetUnitPrice, qty);
- newLine.grossUnitAmount = undefined;
- // This part is only used for visualization in WebPOS 2.0
- newLine.netUnitAmountWithoutTicketDiscounts = calculateUnitAmountWithoutTicketDiscounts(
- OB.DEC.mul(baseNetUnitPrice, qty),
- newLine.promotions
- );
- newLine.netUnitPriceWithoutTicketDiscounts = calculateUnitPriceWithoutTicketDiscounts(
- newLine.netUnitAmountWithoutTicketDiscounts,
- qty
- );
- }
-
- return newLine;
- }
- const isBooked = OB.App.State.Ticket.Utils.isBooked(this.ticket);
- const discounts = line.skipApplyPromotions
- ? undefined
- : discountsResult.lines.find(l => l.id === line.id);
+ const calculatePrice = !(
+ isBooked ||
+ (line.skipApplyPromotions && hasDiscounts)
+ );
+ let discounts;
+ let discountAmt;
const newLine = {
- ...line,
- // eslint-disable-next-line no-nested-ternary
- promotions: discounts
- ? discounts.discounts
- : isBooked
- ? line.promotions
- : []
+ ...line
};
+ if (calculatePrice) {
+ discounts = line.skipApplyPromotions
+ ? undefined
+ : discountsResult.lines.find(l => l.id === line.id);
+ newLine.promotions = discounts ? discounts.discounts : [];
+ } else {
+ newLine.promotions = line.promotions || [];
+ discountAmt = newLine.promotions.reduce(
+ (t, p) => OB.DEC.add(t, p.amt),
+ OB.DEC.Zero
+ );
+ }
if (priceIncludesTax) {
newLine.baseGrossUnitAmount = OB.DEC.mul(baseGrossUnitPrice, qty);
+ if (calculatePrice) {
+ newLine.grossUnitPrice = discounts
+ ? discounts.grossUnitPrice
+ : baseGrossUnitPrice;
+ newLine.grossUnitAmount = discounts
+ ? discounts.grossUnitAmount
+ : newLine.baseGrossUnitAmount;
+ } else {
+ newLine.grossUnitPrice = grossUnitPrice || line.grossListPrice;
+ newLine.grossUnitAmount = OB.DEC.sub(
+ newLine.baseGrossUnitAmount,
+ discountAmt
+ );
+ }
newLine.baseNetUnitAmount = OB.DEC.Zero;
- // eslint-disable-next-line no-nested-ternary
- newLine.grossUnitPrice = discounts
- ? discounts.grossUnitPrice
- : isBooked
- ? grossUnitPrice
- : baseGrossUnitPrice;
- newLine.grossUnitAmount = discounts
- ? discounts.grossUnitAmount
- : OB.DEC.mul(isBooked ? grossUnitPrice : baseGrossUnitPrice, qty);
+ newLine.netUnitPrice = OB.DEC.Zero;
+ newLine.netUnitAmount = OB.DEC.Zero;
// This part is only used for visualization in WebPOS 2.0
newLine.grossUnitAmountWithoutTicketDiscounts = calculateUnitAmountWithoutTicketDiscounts(
newLine.baseGrossUnitAmount,
@@ -525,17 +507,24 @@
qty
);
} else {
- newLine.baseGrossUnitAmount = OB.DEC.Zero;
newLine.baseNetUnitAmount = OB.DEC.mul(baseNetUnitPrice, qty);
- // eslint-disable-next-line no-nested-ternary
- newLine.netUnitPrice = discounts
- ? discounts.netUnitPrice
- : isBooked
- ? netUnitPrice
- : baseNetUnitPrice;
- newLine.netUnitAmount = discounts
- ? discounts.netUnitAmount
- : OB.DEC.mul(isBooked ? netUnitPrice : baseNetUnitPrice, qty);
+ if (calculatePrice) {
+ newLine.netUnitPrice = discounts
+ ? discounts.netUnitPrice
+ : baseNetUnitPrice;
+ newLine.netUnitAmount = discounts
+ ? discounts.netUnitAmount
+ : newLine.baseNetUnitAmount;
+ } else {
+ newLine.netUnitPrice = netUnitPrice;
+ newLine.netUnitAmount = OB.DEC.sub(
+ newLine.baseNetUnitAmount,
+ discountAmt
+ );
+ }
+ newLine.baseGrossUnitAmount = OB.DEC.Zero;
+ newLine.grossUnitPrice = OB.DEC.Zero;
+ newLine.grossUnitAmount = OB.DEC.Zero;
// This part is only used for visualization in WebPOS 2.0
newLine.netUnitAmountWithoutTicketDiscounts = calculateUnitAmountWithoutTicketDiscounts(
newLine.baseNetUnitAmount,
@@ -546,13 +535,13 @@
qty
);
}
+
return newLine;
});
let ticketTaxRules;
// Applied Taxes should be used to calculate if ticket is booked
- const isTicketBooked = OB.App.State.Ticket.Utils.isBooked(this.ticket);
- if (isTicketBooked) {
+ if (isBooked) {
ticketTaxRules = this.ticket.receiptTaxes.map(receiptTax =>
taxRules.find(taxRule => taxRule.id === receiptTax.taxid)
);
@@ -562,7 +551,7 @@
try {
taxesResult = OB.Taxes.Pos.applyTaxes(
this.ticket,
- isTicketBooked ? ticketTaxRules : taxRules
+ isBooked ? ticketTaxRules : taxRules
);
} catch (error) {
if (error instanceof OB.App.Class.TaxEngineError) {
|