@final-commerce/command-frame 0.5.0-preprod.6 → 0.5.0-preprod.9
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.
|
@@ -10,5 +10,10 @@ import { GetRefundPlan } from './types';
|
|
|
10
10
|
* `maxRefundable` as the full captured amount. Against real kaching those
|
|
11
11
|
* numbers come from `order.refund[]` and the capture's `emv` JSON. Use this
|
|
12
12
|
* only to shape UI in local/standalone mode — never to assert real capacity.
|
|
13
|
+
*
|
|
14
|
+
* `allocation` is likewise shape-only: the demo has no refund SELECTION state
|
|
15
|
+
* and no company cash-rounding setting, so it always describes a FULL refund
|
|
16
|
+
* with `rounding: 0` and no cash `payout`. Against real kaching the allocation
|
|
17
|
+
* tracks the live selection and carries the drawer snap.
|
|
13
18
|
*/
|
|
14
19
|
export declare const mockGetRefundPlan: GetRefundPlan;
|
|
@@ -10,6 +10,11 @@ import { MOCK_ORDERS } from '../../demo/database';
|
|
|
10
10
|
* `maxRefundable` as the full captured amount. Against real kaching those
|
|
11
11
|
* numbers come from `order.refund[]` and the capture's `emv` JSON. Use this
|
|
12
12
|
* only to shape UI in local/standalone mode — never to assert real capacity.
|
|
13
|
+
*
|
|
14
|
+
* `allocation` is likewise shape-only: the demo has no refund SELECTION state
|
|
15
|
+
* and no company cash-rounding setting, so it always describes a FULL refund
|
|
16
|
+
* with `rounding: 0` and no cash `payout`. Against real kaching the allocation
|
|
17
|
+
* tracks the live selection and carries the drawer snap.
|
|
13
18
|
*/
|
|
14
19
|
export const mockGetRefundPlan = async (params) => {
|
|
15
20
|
console.log('[Mock] getRefundPlan called', params);
|
|
@@ -45,10 +50,28 @@ export const mockGetRefundPlan = async (params) => {
|
|
|
45
50
|
});
|
|
46
51
|
const totalCaptured = sources.reduce((sum, s) => sum + s.capturedAmount, 0);
|
|
47
52
|
const nonRefundableLiability = order.summary?.nonRevenueTotal ?? 0;
|
|
53
|
+
// Full-refund legs: every source returns its whole capture (the demo's
|
|
54
|
+
// `maxRefundable`), which is exactly the shape a full selection produces.
|
|
55
|
+
const legs = sources
|
|
56
|
+
.filter((s) => s.maxRefundable > 0)
|
|
57
|
+
.map((s) => ({
|
|
58
|
+
transactionId: s.transactionId,
|
|
59
|
+
amount: s.maxRefundable,
|
|
60
|
+
paymentType: s.paymentType,
|
|
61
|
+
requiresGiftCardDestination: s.paymentType === 'redeem',
|
|
62
|
+
}));
|
|
63
|
+
const budget = legs.reduce((sum, l) => sum + l.amount, 0);
|
|
48
64
|
return {
|
|
49
65
|
success: true,
|
|
50
66
|
orderId: order._id,
|
|
51
67
|
sources,
|
|
68
|
+
allocation: {
|
|
69
|
+
budget,
|
|
70
|
+
// No cash rounding in the demo, so the goods value and the budget agree.
|
|
71
|
+
itemTotal: budget,
|
|
72
|
+
rounding: 0,
|
|
73
|
+
legs,
|
|
74
|
+
},
|
|
52
75
|
// Demo: no prior refunds, so remaining = captured minus the non-revenue load.
|
|
53
76
|
remainingRefundable: Math.max(0, totalCaptured - nonRefundableLiability),
|
|
54
77
|
nonRefundableLiability,
|
|
@@ -1,6 +1,29 @@
|
|
|
1
1
|
export interface GetRefundPlanParams {
|
|
2
2
|
/** Order to inspect; defaults to the active order. */
|
|
3
3
|
orderId?: string;
|
|
4
|
+
/**
|
|
5
|
+
* The selection to allocate — the SAME array you will pass to
|
|
6
|
+
* `processPartialRefund({ items })`, so the plan you render and the refund
|
|
7
|
+
* you submit are computed from one input.
|
|
8
|
+
*
|
|
9
|
+
* A flow that owns its own refund UI holds the selection in its own state and
|
|
10
|
+
* never stages it on the POS, so without this there is nothing for the engine
|
|
11
|
+
* to allocate. Pass it here on every selection change to get the matching
|
|
12
|
+
* {@link RefundPlanAllocation} back. **Purely a read** — unlike
|
|
13
|
+
* `processPartialRefund`, this never stages the selection or touches POS
|
|
14
|
+
* state, so it is safe to call as the cashier ticks rows.
|
|
15
|
+
*
|
|
16
|
+
* Omit it to fall back to the selection already staged on the POS (what
|
|
17
|
+
* `selectAllRefundItems` sets) — the in-POS modal's path. Omitted with
|
|
18
|
+
* nothing staged, no `allocation` comes back.
|
|
19
|
+
*/
|
|
20
|
+
items?: {
|
|
21
|
+
/** `internalId` / `variantId` for a product, `customSaleId`, cart-fee id, or tip `transactionId`. */
|
|
22
|
+
itemKey: string;
|
|
23
|
+
quantity: number;
|
|
24
|
+
/** Optional hint; inferred from the order when omitted. */
|
|
25
|
+
type?: 'product' | 'customSale' | 'fee' | 'tip';
|
|
26
|
+
}[];
|
|
4
27
|
}
|
|
5
28
|
export interface RefundPlanSource {
|
|
6
29
|
transactionId: string;
|
|
@@ -17,10 +40,68 @@ export interface RefundPlanSource {
|
|
|
17
40
|
/** For redeem sources: the card number from the payment entry's emv, when present. */
|
|
18
41
|
cardNumber?: string;
|
|
19
42
|
}
|
|
43
|
+
/**
|
|
44
|
+
* One ready-to-submit refund leg. Pass these straight to
|
|
45
|
+
* `processPartialRefund({ openUI: false, legs })` — the amounts are the
|
|
46
|
+
* engine's own allocation and already satisfy its Σ-contract.
|
|
47
|
+
*/
|
|
48
|
+
export interface RefundPlanLeg {
|
|
49
|
+
/** `transactionId` of the source payment this leg draws from — join key to `sources`. */
|
|
50
|
+
transactionId: string;
|
|
51
|
+
/** Amount to return to this source (minor units). Submit VERBATIM; do not re-derive. */
|
|
52
|
+
amount: number;
|
|
53
|
+
/** `cash` / `card` / `redeem` / etc., copied from the source. */
|
|
54
|
+
paymentType: string;
|
|
55
|
+
/** True when the leg must carry a `giftCard` destination (a `redeem` source). */
|
|
56
|
+
requiresGiftCardDestination: boolean;
|
|
57
|
+
/**
|
|
58
|
+
* Cash legs only: what the drawer actually pays after the company's
|
|
59
|
+
* cash-rounding snap, and the signed delta from `amount`. Display it
|
|
60
|
+
* ("drawer pays 6.50 (+0.01 rounding)") — never apply the snap yourself,
|
|
61
|
+
* and never stage `payout.amount` as the leg (`amount` is the leg).
|
|
62
|
+
*/
|
|
63
|
+
payout?: {
|
|
64
|
+
amount: number;
|
|
65
|
+
rounding: number;
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* The engine's own allocation of the CURRENT refund selection across the
|
|
70
|
+
* order's captures — what a flow renders and submits instead of computing a
|
|
71
|
+
* split of its own.
|
|
72
|
+
*
|
|
73
|
+
* Present when the call carries a selection: either `params.items` (a flow
|
|
74
|
+
* holding its own selection — the usual case) or a selection already staged on
|
|
75
|
+
* the POS for the active order (`selectAllRefundItems`). Omitted for a bare
|
|
76
|
+
* capacity read with neither.
|
|
77
|
+
*/
|
|
78
|
+
export interface RefundPlanAllocation {
|
|
79
|
+
/**
|
|
80
|
+
* What Σ `legs.amount` MUST equal — `min(itemTotal, Σ maxRefundable)`, which
|
|
81
|
+
* on a FULL selection is the captured total, not the goods value. Staging the
|
|
82
|
+
* goods value instead is rejected with `refund.legSumMismatch`.
|
|
83
|
+
*/
|
|
84
|
+
budget: number;
|
|
85
|
+
/** Goods value of the selection (minor units). DISPLAY ONLY — never allocate against it. */
|
|
86
|
+
itemTotal: number;
|
|
87
|
+
/**
|
|
88
|
+
* `budget − itemTotal` — the sale's cash rounding, returned to the tender that
|
|
89
|
+
* took it. Non-zero only on a cash-rounded capture; the engine stamps it as
|
|
90
|
+
* refund residue at commit.
|
|
91
|
+
*/
|
|
92
|
+
rounding: number;
|
|
93
|
+
/** One leg per source that receives money. Submit as `legs`, unchanged. */
|
|
94
|
+
legs: RefundPlanLeg[];
|
|
95
|
+
}
|
|
20
96
|
export interface GetRefundPlanResponse {
|
|
21
97
|
success: boolean;
|
|
22
98
|
orderId: string;
|
|
23
99
|
sources: RefundPlanSource[];
|
|
100
|
+
/**
|
|
101
|
+
* Ready-to-submit allocation of the current selection. Present only when a
|
|
102
|
+
* refund selection exists on the active order. See {@link RefundPlanAllocation}.
|
|
103
|
+
*/
|
|
104
|
+
allocation?: RefundPlanAllocation;
|
|
24
105
|
/** Order-level remaining refundable (minor units) — non-revenue liability already excluded. */
|
|
25
106
|
remainingRefundable: number;
|
|
26
107
|
/** Non-refundable liability (gift-card loads etc., minor units). */
|
|
@@ -4,4 +4,10 @@
|
|
|
4
4
|
// order-level math so flows can PRESENT accurate refund options without
|
|
5
5
|
// re-deriving the numbers client-side (the mutating commands —
|
|
6
6
|
// `processPartialRefund` / `redeemRefund` — re-validate at submit time).
|
|
7
|
+
//
|
|
8
|
+
// `allocation` closes the last gap: capacities alone still left a flow to work
|
|
9
|
+
// out WHICH tender gets WHAT, and a flow that split the goods value across the
|
|
10
|
+
// tenders shaved the sale's cash rounding off gift-card legs and was rejected
|
|
11
|
+
// at submit. The engine now returns the legs it would accept — render them,
|
|
12
|
+
// submit them unchanged, compute nothing.
|
|
7
13
|
export {};
|
package/dist/index.d.ts
CHANGED
|
@@ -141,8 +141,8 @@ export type { CalculateRefundTotal, CalculateRefundTotalParams, CalculateRefundT
|
|
|
141
141
|
export type { GetRemainingRefundableQuantities, GetRemainingRefundableQuantitiesParams, GetRemainingRefundableQuantitiesResponse, } from './actions/get-remaining-refundable-quantities/types';
|
|
142
142
|
export type { ProcessPartialRefund, ProcessPartialRefundParams, ProcessPartialRefundResponse, } from './actions/process-partial-refund/types';
|
|
143
143
|
export type { RedeemRefund, RedeemRefundParams, RedeemRefundResponse } from './actions/redeem-refund/types';
|
|
144
|
-
export type { GetRefundPlan, GetRefundPlanParams, GetRefundPlanResponse, RefundPlanSource, } from './actions/get-refund-plan/types';
|
|
145
|
-
export type { CheckPermission, CheckPermissionParams, CheckPermissionResponse
|
|
144
|
+
export type { GetRefundPlan, GetRefundPlanParams, GetRefundPlanResponse, RefundPlanSource, RefundPlanAllocation, RefundPlanLeg, } from './actions/get-refund-plan/types';
|
|
145
|
+
export type { CheckPermission, CheckPermissionParams, CheckPermissionResponse } from './actions/check-permission/types';
|
|
146
146
|
export type { InitiateRefund, InitiateRefundParams, InitiateRefundResponse } from './actions/initiate-refund/types';
|
|
147
147
|
export type { GetCurrentCart, GetCurrentCartResponse } from './actions/get-current-cart/types';
|
|
148
148
|
export type { AddProductDiscount, AddProductDiscountParams, AddProductDiscountResponse, } from './actions/add-product-discount/types';
|