Ver código fonte

fix(core): Account for refund status when calculating order coverage (#3719)

Fixes #3670
Will Nahmens 5 meses atrás
pai
commit
1400bbcdbf

+ 62 - 0
packages/core/src/service/helpers/utils/order-utils.spec.ts

@@ -2,6 +2,7 @@ import { describe, expect, it } from 'vitest';
 
 import { Order } from '../../../entity/order/order.entity';
 import { Payment } from '../../../entity/payment/payment.entity';
+import { Refund } from '../../../entity/refund/refund.entity';
 
 import { totalCoveredByPayments } from './order-utils';
 
@@ -86,4 +87,65 @@ describe('totalCoveredByPayments()', () => {
 
         expect(totalCoveredByPayments(order, ['Settled', 'Authorized'])).toBe(800);
     });
+
+    it('single payment, refunds with different states', () => {
+        const order = new Order({
+            payments: [
+                new Payment({
+                    state: 'Settled',
+                    amount: 500,
+                    refunds: [
+                        new Refund({ state: 'Settled', total: 100 }),
+                        new Refund({ state: 'Pending', total: 200 }),
+                    ],
+                }),
+            ],
+        });
+
+        expect(totalCoveredByPayments(order, ['Settled', 'Authorized'])).toBe(400);
+    });
+
+    it('single payment, refunds with different states', () => {
+        const order = new Order({
+            payments: [
+                new Payment({
+                    state: 'Settled',
+                    amount: 500,
+                    refunds: [
+                        new Refund({ state: 'Settled', total: 100 }),
+                        new Refund({ state: 'Pending', total: 200 }),
+                    ],
+                }),
+            ],
+        });
+
+        expect(totalCoveredByPayments(order, ['Settled', 'Authorized'])).toBe(400);
+    });
+
+    it('multiple payments, refunds with different states', () => {
+        const order = new Order({
+            payments: [
+                new Payment({
+                    state: 'Settled',
+                    amount: 500,
+                    refunds: [
+                        new Refund({ state: 'Settled', total: 100 }),
+                        new Refund({ state: 'Pending', total: 200 }),
+                        new Refund({ state: 'Settled', total: 100 }),
+                    ],
+                }),
+                new Payment({
+                    state: 'Settled',
+                    amount: 500,
+                    refunds: [
+                        new Refund({ state: 'Settled', total: 100 }),
+                        new Refund({ state: 'Failed', total: 200 }),
+                        new Refund({ state: 'Pending', total: 200 }),
+                    ],
+                }),
+            ],
+        });
+
+        expect(totalCoveredByPayments(order, ['Settled', 'Authorized'])).toBe(700);
+    });
 });

+ 12 - 8
packages/core/src/service/helpers/utils/order-utils.ts

@@ -8,9 +8,9 @@ import { RequestContext } from '../../../api/common/request-context';
 import { EntityNotFoundError } from '../../../common/error/errors';
 import { idsAreEqual } from '../../../common/utils';
 import { TransactionalConnection } from '../../../connection/transactional-connection';
-import { Order } from '../../../entity/order/order.entity';
-import { OrderLine } from '../../../entity/order-line/order-line.entity';
 import { FulfillmentLine } from '../../../entity/order-line-reference/fulfillment-line.entity';
+import { OrderLine } from '../../../entity/order-line/order-line.entity';
+import { Order } from '../../../entity/order/order.entity';
 import { FulfillmentState } from '../fulfillment-state-machine/fulfillment-state';
 import { PaymentState } from '../payment-state-machine/payment-state';
 
@@ -35,8 +35,9 @@ export function totalCoveredByPayments(order: Order, state?: PaymentState | Paym
           );
     let total = 0;
     for (const payment of payments) {
-        const refundTotal = summate(payment.refunds, 'total');
-        total += payment.amount - Math.abs(refundTotal);
+        const settledRefunds = payment.refunds?.filter(refund => refund.state === 'Settled') ?? [];
+        const settledRefundTotal = summate(settledRefunds, 'total');
+        total += payment.amount - Math.abs(settledRefundTotal);
     }
     return total;
 }
@@ -126,10 +127,13 @@ function getOrderFulfillmentLines(order: Order): FulfillmentLine[] {
  */
 function isOrderPartiallyFulfilled(order: Order) {
     const fulfillmentLines = getOrderFulfillmentLines(order);
-    const lines = fulfillmentLines.reduce((acc, item) => {
-        acc[item.orderLineId] = (acc[item.orderLineId] || 0) + item.quantity;
-        return acc;
-    }, {} as { [orderLineId: string]: number });
+    const lines = fulfillmentLines.reduce(
+        (acc, item) => {
+            acc[item.orderLineId] = (acc[item.orderLineId] || 0) + item.quantity;
+            return acc;
+        },
+        {} as { [orderLineId: string]: number },
+    );
     return order.lines.some(line => line.quantity > lines[line.id]);
 }