@final-commerce/command-frame 0.3.0-beta.6 → 0.3.0-beta.8
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/README.md +16 -0
- package/dist/CommonTypes.d.ts +7 -0
- package/dist/actions/add-cart-discount/types.d.ts +1 -1
- package/dist/actions/add-cart-fee/types.d.ts +1 -1
- package/dist/actions/add-custom-sale/types.d.ts +1 -0
- package/dist/actions/add-non-revenue-item/types.d.ts +1 -1
- package/dist/actions/add-product-discount/types.d.ts +1 -1
- package/dist/actions/add-product-fee/types.d.ts +1 -0
- package/dist/actions/cash-payment/action.js +5 -5
- package/dist/actions/cash-payment/mock.js +44 -26
- package/dist/actions/cash-payment/types.d.ts +45 -4
- package/dist/actions/extension-payment/types.d.ts +8 -2
- package/dist/actions/get-cash-rounding-amount/action.d.ts +9 -0
- package/dist/actions/get-cash-rounding-amount/action.js +11 -0
- package/dist/actions/get-cash-rounding-amount/mock.d.ts +2 -0
- package/dist/actions/get-cash-rounding-amount/mock.js +15 -0
- package/dist/actions/get-cash-rounding-amount/types.d.ts +25 -0
- package/dist/actions/get-cash-rounding-amount/types.js +2 -0
- package/dist/actions/get-context/mock.js +1 -0
- package/dist/actions/integration-payment/types.d.ts +2 -2
- package/dist/actions/partial-payment/types.d.ts +1 -1
- package/dist/actions/redeem-payment/types.d.ts +1 -0
- package/dist/actions/send-email/action.d.ts +6 -0
- package/dist/actions/send-email/action.js +8 -0
- package/dist/actions/send-email/mock.d.ts +2 -0
- package/dist/actions/send-email/mock.js +11 -0
- package/dist/actions/send-email/types.d.ts +28 -0
- package/dist/actions/send-email/types.js +2 -0
- package/dist/actions/send-sms/action.d.ts +6 -0
- package/dist/actions/send-sms/action.js +8 -0
- package/dist/actions/send-sms/mock.d.ts +2 -0
- package/dist/actions/send-sms/mock.js +11 -0
- package/dist/actions/send-sms/types.d.ts +24 -0
- package/dist/actions/send-sms/types.js +2 -0
- package/dist/actions/set-active-product-discount/types.d.ts +1 -1
- package/dist/actions/set-active-product-fee/types.d.ts +1 -0
- package/dist/actions/tap-to-pay-payment/types.d.ts +10 -2
- package/dist/actions/terminal-payment/types.d.ts +10 -2
- package/dist/actions/vendara-payment/types.d.ts +10 -2
- package/dist/demo/database.js +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +8 -1
- package/dist/projects/render/mocks.js +7 -1
- package/dist/projects/render/types.d.ts +4 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -47,6 +47,22 @@ npm install @final-commerce/command-frame
|
|
|
47
47
|
|
|
48
48
|
Commands let the extension iframe call typed functions on the host. Each host environment (Render, Manage) exposes its own set of commands.
|
|
49
49
|
|
|
50
|
+
### Money values: integer minor units
|
|
51
|
+
|
|
52
|
+
Every money value on this API — params **and** responses — is an **integer in
|
|
53
|
+
minor currency units**: `1575` means $15.75 in USD, ¥1575 in JPY. The host
|
|
54
|
+
does all money math in minor units and never converts your inputs. Use
|
|
55
|
+
`getContext().minorUnits` (the currency's decimal exponent, e.g. `2` for USD,
|
|
56
|
+
`0` for JPY) to convert user-typed values before sending:
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
const { minorUnits } = await command.getContext();
|
|
60
|
+
const amount = Math.round(parseFloat(userInput) * 10 ** (minorUnits ?? 2));
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
The two exceptions, always flagged in the field docs: percentages (`isPercent:
|
|
64
|
+
true` → `amount` is `0–100`), and quantities.
|
|
65
|
+
|
|
50
66
|
### Render (POS System)
|
|
51
67
|
|
|
52
68
|
For building applications that run inside the Render Point of Sale interface.
|
package/dist/CommonTypes.d.ts
CHANGED
|
@@ -113,6 +113,13 @@ export interface CFContextRender {
|
|
|
113
113
|
buildIsPremium: boolean;
|
|
114
114
|
isOffline: boolean;
|
|
115
115
|
currency: string | null;
|
|
116
|
+
/**
|
|
117
|
+
* Number of minor-unit decimals for the company currency (e.g. 2 for USD
|
|
118
|
+
* — $15.75 = 1575 minor units; 0 for JPY). Every money param/response on
|
|
119
|
+
* this API is expressed in integer minor units; use this to convert user
|
|
120
|
+
* input.
|
|
121
|
+
*/
|
|
122
|
+
minorUnits: number | null;
|
|
116
123
|
currencySymbol: string | null;
|
|
117
124
|
currencyPrefix: string | null;
|
|
118
125
|
currencySuffix: string | null;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export interface AddCartDiscountParams {
|
|
2
|
-
/** The discount amount. If isPercent is true, this is a percentage (0-100). */
|
|
2
|
+
/** The discount amount in integer MINOR currency units (e.g. 500 = $5.00). If isPercent is true, this is a percentage (0-100) instead. */
|
|
3
3
|
amount: number;
|
|
4
4
|
/** Defaults to `false`. */
|
|
5
5
|
isPercent?: boolean;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export interface AddCartFeeParams {
|
|
2
|
-
/** The fee amount. If isPercent is true, this is a percentage. */
|
|
2
|
+
/** The fee amount in integer MINOR currency units (e.g. 500 = $5.00). If isPercent is true, this is a percentage (0-100) instead. */
|
|
3
3
|
amount: number;
|
|
4
4
|
/** Defaults to `false`. */
|
|
5
5
|
isPercent?: boolean;
|
|
@@ -8,7 +8,7 @@ export interface AddNonRevenueItemParams {
|
|
|
8
8
|
* The cart uses a separate unique line id per add so multiple lines can share the same refId.
|
|
9
9
|
*/
|
|
10
10
|
id: string;
|
|
11
|
-
/** Amount in
|
|
11
|
+
/** Amount in integer MINOR currency units (e.g. 1575 = $15.75), same as cart totals. */
|
|
12
12
|
amount: number;
|
|
13
13
|
/** Short label for receipts/UI */
|
|
14
14
|
label?: string;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export interface AddProductDiscountParams {
|
|
2
|
-
/** The discount amount. If isPercent is true, this is a percentage. */
|
|
2
|
+
/** The discount amount in integer MINOR currency units (e.g. 500 = $5.00). If isPercent is true, this is a percentage (0-100) instead. */
|
|
3
3
|
amount: number;
|
|
4
4
|
/** Defaults to `false`. */
|
|
5
5
|
isPercent?: boolean;
|
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { commandFrameClient } from "../../client";
|
|
6
6
|
export const cashPayment = async (params) => {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
return await commandFrameClient.call("cashPayment",
|
|
7
|
+
// NOTE: beta.6 defaulted `openChangeCalculator` to true here. The change
|
|
8
|
+
// calculator is deprecated (the flow owns the tender UI via
|
|
9
|
+
// `tenderedAmount` + `getCashRoundingAmount`), so the flag now passes
|
|
10
|
+
// through as-sent and defaults to false host-side.
|
|
11
|
+
return await commandFrameClient.call("cashPayment", params);
|
|
12
12
|
};
|
|
@@ -1,40 +1,58 @@
|
|
|
1
1
|
import { applyMockPayment, MOCK_CART } from "../../demo/database";
|
|
2
2
|
export const mockCashPayment = async (params) => {
|
|
3
3
|
console.log("[Mock] cashPayment called", params);
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
const fail = (reason) => {
|
|
5
|
+
console.warn(`[Mock] cashPayment rejected: ${reason}`);
|
|
6
|
+
return {
|
|
7
|
+
success: false,
|
|
8
|
+
amount: 0,
|
|
9
|
+
openChangeCalculator: params?.openChangeCalculator ?? false,
|
|
10
|
+
change: 0,
|
|
11
|
+
cashRounding: 0,
|
|
12
|
+
paymentType: "cash",
|
|
13
|
+
order: null,
|
|
14
|
+
timestamp: new Date().toISOString()
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
// Contract: `amount` is required, integer MINOR currency units — same
|
|
18
|
+
// scale as the mock cart's totals, so comparisons are direct.
|
|
19
|
+
if (params?.amount === undefined || params.amount === null) {
|
|
20
|
+
return fail("amount is required (integer minor currency units)");
|
|
21
|
+
}
|
|
22
|
+
const balanceDue = MOCK_CART.amountToBeCharged ?? MOCK_CART.total;
|
|
23
|
+
if (params.amount > balanceDue) {
|
|
24
|
+
return fail(`amount ${params.amount} exceeds balance due ${balanceDue}`);
|
|
25
|
+
}
|
|
26
|
+
// Flow-owned tender: compute change here (no rounding in the mock).
|
|
27
|
+
let change = 0;
|
|
28
|
+
if (params.tenderedAmount !== undefined) {
|
|
29
|
+
if (params.tenderedAmount < params.amount) {
|
|
30
|
+
return fail(`tenderedAmount ${params.tenderedAmount} is less than amount ${params.amount}`);
|
|
31
|
+
}
|
|
32
|
+
change = params.tenderedAmount - params.amount;
|
|
33
|
+
}
|
|
34
|
+
else if (params.openChangeCalculator) {
|
|
35
|
+
// Deprecated legacy path: simulate the POS-owned change calculator.
|
|
9
36
|
try {
|
|
10
|
-
const input = window.prompt(`Amount due: $${(
|
|
11
|
-
if (input === null)
|
|
12
|
-
return
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
paymentType: "cash",
|
|
17
|
-
order: null,
|
|
18
|
-
timestamp: new Date().toISOString()
|
|
19
|
-
};
|
|
20
|
-
}
|
|
21
|
-
const tendered = parseFloat(input); // dollars
|
|
22
|
-
if (!isNaN(tendered)) {
|
|
23
|
-
const change = tendered - due / 100;
|
|
24
|
-
window.alert(change >= 0
|
|
25
|
-
? `Change Due: $${change.toFixed(2)}`
|
|
26
|
-
: `Warning: Tendered is short by: $${Math.abs(change).toFixed(2)}`);
|
|
27
|
-
}
|
|
37
|
+
const input = window.prompt(`Amount due: $${(params.amount / 100).toFixed(2)}\nEnter amount tendered (dollars):`, (params.amount / 100).toFixed(2));
|
|
38
|
+
if (input === null)
|
|
39
|
+
return fail("cancelled");
|
|
40
|
+
const tendered = parseFloat(input);
|
|
41
|
+
if (!isNaN(tendered))
|
|
42
|
+
change = Math.round(tendered * 100) - params.amount;
|
|
28
43
|
}
|
|
29
44
|
catch (e) {
|
|
30
45
|
console.warn("Could not open prompt/alert (possibly in non-interactive environment)", e);
|
|
31
46
|
}
|
|
32
47
|
}
|
|
33
|
-
const order = applyMockPayment(
|
|
48
|
+
const order = applyMockPayment(params.amount, "cash", "cash");
|
|
34
49
|
return {
|
|
35
50
|
success: true,
|
|
36
|
-
amount:
|
|
37
|
-
openChangeCalculator,
|
|
51
|
+
amount: params.amount,
|
|
52
|
+
openChangeCalculator: params.openChangeCalculator ?? false,
|
|
53
|
+
change,
|
|
54
|
+
tenderedAmount: params.tenderedAmount,
|
|
55
|
+
cashRounding: 0,
|
|
38
56
|
paymentType: "cash",
|
|
39
57
|
order,
|
|
40
58
|
timestamp: new Date().toISOString()
|
|
@@ -1,21 +1,62 @@
|
|
|
1
1
|
import { CFOrder } from "../../CommonTypes";
|
|
2
2
|
import type { CFTransitionResult } from "../../common-types/order-state";
|
|
3
3
|
export interface CashPaymentParams {
|
|
4
|
-
/**
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
/**
|
|
5
|
+
* The amount to pay with this tender, in integer MINOR currency units
|
|
6
|
+
* (e.g. 1575 = $15.75 — see `getContext().minorUnits` for the currency's
|
|
7
|
+
* exponent). Required. Semantics against the cart's balance due:
|
|
8
|
+
* - missing → error
|
|
9
|
+
* - less than balance → partial payment (the POS enters a fixed
|
|
10
|
+
* split-payment leg for this amount)
|
|
11
|
+
* - equal to balance → full payment
|
|
12
|
+
* - more than balance → error (overpayment is `tenderedAmount`'s job)
|
|
13
|
+
*/
|
|
14
|
+
amount: number;
|
|
15
|
+
/**
|
|
16
|
+
* Cash physically handed over by the customer, in integer MINOR currency
|
|
17
|
+
* units. When provided, the POS computes the change itself (after applying
|
|
18
|
+
* the company's cash-rounding setting to the charge) and does NOT open its
|
|
19
|
+
* own change-calculator modal — the flow owns the tender UI. Must be >= the
|
|
20
|
+
* (rounded) charge or the payment fails.
|
|
21
|
+
* Pair with `getCashRoundingAmount` to display the rounded total before
|
|
22
|
+
* collecting the tender.
|
|
23
|
+
*/
|
|
24
|
+
tenderedAmount?: number;
|
|
25
|
+
/**
|
|
26
|
+
* @deprecated The change calculator now lives in the flow: call
|
|
27
|
+
* `getCashRoundingAmount`, collect the tender in your own UI, and pass
|
|
28
|
+
* `tenderedAmount` instead. When true (and `tenderedAmount` is absent) the
|
|
29
|
+
* POS still opens its legacy change-calculator modal.
|
|
30
|
+
*/
|
|
7
31
|
openChangeCalculator?: boolean;
|
|
8
32
|
/** Override the fulfillment state after full payment. Render resolves the cascade. */
|
|
9
33
|
checkoutFulfillmentTarget?: string;
|
|
10
34
|
}
|
|
11
35
|
export interface CashPaymentResponse {
|
|
12
36
|
success: boolean;
|
|
37
|
+
/** The amount paid with this tender, in integer MINOR currency units. */
|
|
13
38
|
amount: number;
|
|
39
|
+
/** @deprecated Mirror of the deprecated request flag. */
|
|
14
40
|
openChangeCalculator: boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Change due back to the customer in integer MINOR currency units.
|
|
43
|
+
* Non-zero only when `tenderedAmount` exceeded the (cash-rounded) charge.
|
|
44
|
+
* Display this — don't recompute it client-side: it accounts for cash
|
|
45
|
+
* rounding.
|
|
46
|
+
*/
|
|
47
|
+
change: number;
|
|
48
|
+
/** Echo of the tendered cash (MINOR units) when it was provided. */
|
|
49
|
+
tenderedAmount?: number;
|
|
50
|
+
/**
|
|
51
|
+
* Signed cash-rounding delta applied to the charge, in integer MINOR
|
|
52
|
+
* currency units (positive = rounded up). 0 when the company has no
|
|
53
|
+
* cash-rounding setting.
|
|
54
|
+
*/
|
|
55
|
+
cashRounding: number;
|
|
15
56
|
paymentType: string;
|
|
16
57
|
order: CFOrder | null;
|
|
17
58
|
timestamp: string;
|
|
18
59
|
/** Present when the state machine blocked or forced the transition. */
|
|
19
60
|
transitionResult?: CFTransitionResult;
|
|
20
61
|
}
|
|
21
|
-
export type CashPayment = (params
|
|
62
|
+
export type CashPayment = (params: CashPaymentParams) => Promise<CashPaymentResponse>;
|
|
@@ -4,7 +4,13 @@ import type { CFTransitionResult } from "../../common-types/order-state";
|
|
|
4
4
|
export interface ExtensionPaymentParams {
|
|
5
5
|
paymentType: string;
|
|
6
6
|
processor?: string;
|
|
7
|
-
|
|
7
|
+
/**
|
|
8
|
+
* The amount to pay with this tender, in integer MINOR currency units
|
|
9
|
+
* (e.g. 1575 = $15.75). Required. Semantics against the cart's balance
|
|
10
|
+
* due: missing → error; less than balance → partial payment (fixed
|
|
11
|
+
* split-payment leg); equal → full payment; more → error.
|
|
12
|
+
*/
|
|
13
|
+
amount: number;
|
|
8
14
|
label?: string;
|
|
9
15
|
referenceId?: string;
|
|
10
16
|
extensionId?: string;
|
|
@@ -13,7 +19,7 @@ export interface ExtensionPaymentParams {
|
|
|
13
19
|
checkoutFulfillmentTarget?: string;
|
|
14
20
|
/** EMV data when the underlying payment carries one (typed as `IntegrationEmvData` by the integration wrapper). */
|
|
15
21
|
emvData?: unknown;
|
|
16
|
-
/** Processor fee in
|
|
22
|
+
/** Processor fee in integer MINOR currency units; recorded on the order's paymentMethod.processorFee. */
|
|
17
23
|
processorFee?: number;
|
|
18
24
|
}
|
|
19
25
|
export interface ExtensionPaymentResponse {
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Get cash rounding amount action — preview the company's cash rounding for an
|
|
3
|
+
* amount (or the cart's balance due) WITHOUT touching any state. Read-only.
|
|
4
|
+
*
|
|
5
|
+
* Built for flow-owned cash tender UIs: fetch the rounded total, display it,
|
|
6
|
+
* collect the tendered cash, then call `cashPayment({ amount, tenderedAmount })`.
|
|
7
|
+
*/
|
|
8
|
+
import type { GetCashRoundingAmount } from "./types";
|
|
9
|
+
export declare const getCashRoundingAmount: GetCashRoundingAmount;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Get cash rounding amount action — preview the company's cash rounding for an
|
|
3
|
+
* amount (or the cart's balance due) WITHOUT touching any state. Read-only.
|
|
4
|
+
*
|
|
5
|
+
* Built for flow-owned cash tender UIs: fetch the rounded total, display it,
|
|
6
|
+
* collect the tendered cash, then call `cashPayment({ amount, tenderedAmount })`.
|
|
7
|
+
*/
|
|
8
|
+
import { commandFrameClient } from "../../client";
|
|
9
|
+
export const getCashRoundingAmount = async (params) => {
|
|
10
|
+
return await commandFrameClient.call("getCashRoundingAmount", params);
|
|
11
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { MOCK_CART } from "../../demo/database";
|
|
2
|
+
/** Mock rounds to the nearest 5 minor units (a typical $0.05 cash-rounding setting). */
|
|
3
|
+
const MOCK_INCREMENT_MINOR = 5;
|
|
4
|
+
export const mockGetCashRoundingAmount = async (params) => {
|
|
5
|
+
console.log("[Mock] getCashRoundingAmount called", params);
|
|
6
|
+
const amount = Math.round(params?.amount ?? MOCK_CART.amountToBeCharged ?? MOCK_CART.total);
|
|
7
|
+
const roundedAmount = Math.round(amount / MOCK_INCREMENT_MINOR) * MOCK_INCREMENT_MINOR;
|
|
8
|
+
return {
|
|
9
|
+
success: true,
|
|
10
|
+
amount,
|
|
11
|
+
roundedAmount,
|
|
12
|
+
cashRounding: roundedAmount - amount,
|
|
13
|
+
timestamp: new Date().toISOString()
|
|
14
|
+
};
|
|
15
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export interface GetCashRoundingAmountParams {
|
|
2
|
+
/**
|
|
3
|
+
* The amount to round, in integer MINOR currency units (e.g. 1577 =
|
|
4
|
+
* $15.77). Defaults to the cart's current balance due when omitted.
|
|
5
|
+
*/
|
|
6
|
+
amount?: number;
|
|
7
|
+
}
|
|
8
|
+
export interface GetCashRoundingAmountResponse {
|
|
9
|
+
success: boolean;
|
|
10
|
+
/** The input amount that was rounded, in integer MINOR currency units. */
|
|
11
|
+
amount: number;
|
|
12
|
+
/**
|
|
13
|
+
* The amount after applying the company's cash-rounding setting, in
|
|
14
|
+
* integer MINOR currency units. Equals `amount` when no cash-rounding
|
|
15
|
+
* setting is configured.
|
|
16
|
+
*/
|
|
17
|
+
roundedAmount: number;
|
|
18
|
+
/**
|
|
19
|
+
* Signed rounding delta (`roundedAmount - amount`) in integer MINOR
|
|
20
|
+
* currency units. Positive = rounded up. 0 when no setting is configured.
|
|
21
|
+
*/
|
|
22
|
+
cashRounding: number;
|
|
23
|
+
timestamp: string;
|
|
24
|
+
}
|
|
25
|
+
export type GetCashRoundingAmount = (params?: GetCashRoundingAmountParams) => Promise<GetCashRoundingAmountResponse>;
|
|
@@ -33,7 +33,7 @@ export interface IntegrationEmvData {
|
|
|
33
33
|
* Render can record the transaction + order.
|
|
34
34
|
*
|
|
35
35
|
* Required fields (compile-time enforced by TS, runtime-enforced by the host handler):
|
|
36
|
-
* - `amount` —
|
|
36
|
+
* - `amount` — integer MINOR currency units of the captured amount (e.g. 1575 = $15.75)
|
|
37
37
|
* - `emvData` — typed card display fields; the host maps + JSON-serializes to `paymentMethod.emv`
|
|
38
38
|
* (same persisted shape as the native card flow). Required: if the integration
|
|
39
39
|
* doesn't produce card data, use redeemPayment instead.
|
|
@@ -49,7 +49,7 @@ export interface IntegrationPaymentParams {
|
|
|
49
49
|
processor?: string;
|
|
50
50
|
referenceId?: string;
|
|
51
51
|
metadata?: Record<string, unknown>;
|
|
52
|
-
/** Provider fee in
|
|
52
|
+
/** Provider fee in integer MINOR currency units — stored on paymentMethod.processorFee. */
|
|
53
53
|
processorFee?: number;
|
|
54
54
|
}
|
|
55
55
|
export type IntegrationPaymentResponse = ExtensionPaymentResponse;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { CFOrder } from "../../CommonTypes";
|
|
2
2
|
import type { CFTransitionResult } from "../../common-types/order-state";
|
|
3
3
|
export interface PartialPaymentParams {
|
|
4
|
-
/** The payment amount (required if openUI is false). */
|
|
4
|
+
/** The payment amount in integer MINOR currency units (required if openUI is false). If isPercent is true, this is a percentage (0-100) instead. */
|
|
5
5
|
amount?: number;
|
|
6
6
|
/** Defaults to false. */
|
|
7
7
|
isPercent?: boolean;
|
|
@@ -5,6 +5,7 @@ import type { ExtensionPaymentResponse } from "../extension-payment/types";
|
|
|
5
5
|
* total. The host handler also re-validates this at runtime to catch raw-postMessage callers.
|
|
6
6
|
*/
|
|
7
7
|
export interface RedeemPaymentParams {
|
|
8
|
+
/** Amount in integer MINOR currency units (e.g. 1575 = $15.75). */
|
|
8
9
|
amount: number;
|
|
9
10
|
label?: string;
|
|
10
11
|
extensionId?: string;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Send email action — email the customer the active order's (or a refund's) receipt.
|
|
3
|
+
* Calls the sendEmail action on the parent window.
|
|
4
|
+
*/
|
|
5
|
+
import { commandFrameClient } from "../../client";
|
|
6
|
+
export const sendEmail = async (params) => {
|
|
7
|
+
return await commandFrameClient.call("sendEmail", params);
|
|
8
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export const mockSendEmail = async (params) => {
|
|
2
|
+
console.log("[Mock] sendEmail called", params);
|
|
3
|
+
return {
|
|
4
|
+
success: true,
|
|
5
|
+
channel: "email",
|
|
6
|
+
email: params?.email || "mock@example.com",
|
|
7
|
+
entityId: params?.refundId || params?.orderId || "mock_order_1",
|
|
8
|
+
type: params?.type || "order",
|
|
9
|
+
timestamp: new Date().toISOString()
|
|
10
|
+
};
|
|
11
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which receipt to send: a finalized order (default) or a refund.
|
|
3
|
+
* Values MUST stay in lockstep with `ReceiptType` in `@final-commerce/common` (used by hub-api);
|
|
4
|
+
* this SDK intentionally has no dependency on that package, so the literal is duplicated here.
|
|
5
|
+
*/
|
|
6
|
+
export type SendReceiptType = 'order' | 'refund';
|
|
7
|
+
export interface SendEmailParams {
|
|
8
|
+
/** Recipient email. Defaults to the active customer's email. */
|
|
9
|
+
email?: string;
|
|
10
|
+
/** Order id to send the receipt for. Defaults to the active order. */
|
|
11
|
+
orderId?: string;
|
|
12
|
+
/** Refund id — required when `type` is 'refund'. */
|
|
13
|
+
refundId?: string;
|
|
14
|
+
/** 'order' (default) or 'refund'. */
|
|
15
|
+
type?: SendReceiptType;
|
|
16
|
+
}
|
|
17
|
+
export interface SendEmailResponse {
|
|
18
|
+
success: boolean;
|
|
19
|
+
/** Always 'email' for this action. */
|
|
20
|
+
channel: 'email';
|
|
21
|
+
/** The email the receipt was sent to. */
|
|
22
|
+
email: string;
|
|
23
|
+
/** The order or refund id the receipt was sent for. */
|
|
24
|
+
entityId: string;
|
|
25
|
+
type: SendReceiptType;
|
|
26
|
+
timestamp: string;
|
|
27
|
+
}
|
|
28
|
+
export type SendEmail = (params?: SendEmailParams) => Promise<SendEmailResponse>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Send SMS action — text the customer the active order's (or a refund's) receipt.
|
|
3
|
+
* Calls the sendSms action on the parent window.
|
|
4
|
+
*/
|
|
5
|
+
import { commandFrameClient } from "../../client";
|
|
6
|
+
export const sendSms = async (params) => {
|
|
7
|
+
return await commandFrameClient.call("sendSms", params);
|
|
8
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export const mockSendSms = async (params) => {
|
|
2
|
+
console.log("[Mock] sendSms called", params);
|
|
3
|
+
return {
|
|
4
|
+
success: true,
|
|
5
|
+
channel: "text",
|
|
6
|
+
phone: params?.phone || "+15555550123",
|
|
7
|
+
entityId: params?.refundId || params?.orderId || "mock_order_1",
|
|
8
|
+
type: params?.type || "order",
|
|
9
|
+
timestamp: new Date().toISOString()
|
|
10
|
+
};
|
|
11
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { SendReceiptType } from "../send-email/types";
|
|
2
|
+
export type { SendReceiptType };
|
|
3
|
+
export interface SendSmsParams {
|
|
4
|
+
/** Recipient phone in E.164 format (e.g. +15555550123). Defaults to the active customer's phone. */
|
|
5
|
+
phone?: string;
|
|
6
|
+
/** Order id to send the receipt for. Defaults to the active order. */
|
|
7
|
+
orderId?: string;
|
|
8
|
+
/** Refund id — required when `type` is 'refund'. */
|
|
9
|
+
refundId?: string;
|
|
10
|
+
/** 'order' (default) or 'refund'. */
|
|
11
|
+
type?: SendReceiptType;
|
|
12
|
+
}
|
|
13
|
+
export interface SendSmsResponse {
|
|
14
|
+
success: boolean;
|
|
15
|
+
/** Always 'text' for this action. */
|
|
16
|
+
channel: 'text';
|
|
17
|
+
/** The phone the receipt was sent to (E.164). */
|
|
18
|
+
phone: string;
|
|
19
|
+
/** The order or refund id the receipt was sent for. */
|
|
20
|
+
entityId: string;
|
|
21
|
+
type: SendReceiptType;
|
|
22
|
+
timestamp: string;
|
|
23
|
+
}
|
|
24
|
+
export type SendSms = (params?: SendSmsParams) => Promise<SendSmsResponse>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export interface SetActiveProductDiscountParams {
|
|
2
|
-
/** The discount amount. If isPercent is true, this is a percentage. */
|
|
2
|
+
/** The discount amount in integer MINOR currency units (e.g. 500 = $5.00). If isPercent is true, this is a percentage (0-100) instead. */
|
|
3
3
|
amount: number;
|
|
4
4
|
/** Defaults to `false`. */
|
|
5
5
|
isPercent?: boolean;
|
|
@@ -1,8 +1,16 @@
|
|
|
1
1
|
import { CFOrder } from "../../CommonTypes";
|
|
2
2
|
import type { CFTransitionResult } from "../../common-types/order-state";
|
|
3
3
|
export interface TapToPayPaymentParams {
|
|
4
|
-
/**
|
|
5
|
-
|
|
4
|
+
/**
|
|
5
|
+
* The amount to pay with this tender, in integer MINOR currency units
|
|
6
|
+
* (e.g. 1575 = $15.75). Required. Semantics against the cart's balance due:
|
|
7
|
+
* - missing → error
|
|
8
|
+
* - less than balance → partial payment (the POS enters a fixed
|
|
9
|
+
* split-payment leg for this amount)
|
|
10
|
+
* - equal to balance → full payment
|
|
11
|
+
* - more than balance → error
|
|
12
|
+
*/
|
|
13
|
+
amount: number;
|
|
6
14
|
/** Override the fulfillment state after full payment. Render resolves the cascade. */
|
|
7
15
|
checkoutFulfillmentTarget?: string;
|
|
8
16
|
}
|
|
@@ -1,8 +1,16 @@
|
|
|
1
1
|
import { CFOrder } from "../../CommonTypes";
|
|
2
2
|
import type { CFTransitionResult } from "../../common-types/order-state";
|
|
3
3
|
export interface TerminalPaymentParams {
|
|
4
|
-
/**
|
|
5
|
-
|
|
4
|
+
/**
|
|
5
|
+
* The amount to pay with this tender, in integer MINOR currency units
|
|
6
|
+
* (e.g. 1575 = $15.75). Required. Semantics against the cart's balance due:
|
|
7
|
+
* - missing → error
|
|
8
|
+
* - less than balance → partial payment (the POS enters a fixed
|
|
9
|
+
* split-payment leg for this amount)
|
|
10
|
+
* - equal to balance → full payment
|
|
11
|
+
* - more than balance → error
|
|
12
|
+
*/
|
|
13
|
+
amount: number;
|
|
6
14
|
/** "Bluetooth" or "Cloud". Defaults to "Cloud". */
|
|
7
15
|
paymentType?: 'Bluetooth' | 'Cloud';
|
|
8
16
|
/** Override the fulfillment state after full payment. Render resolves the cascade. */
|
|
@@ -1,8 +1,16 @@
|
|
|
1
1
|
import { CFOrder } from "../../CommonTypes";
|
|
2
2
|
import type { CFTransitionResult } from "../../common-types/order-state";
|
|
3
3
|
export interface VendaraPaymentParams {
|
|
4
|
-
/**
|
|
5
|
-
|
|
4
|
+
/**
|
|
5
|
+
* The amount to pay with this tender, in integer MINOR currency units
|
|
6
|
+
* (e.g. 1575 = $15.75). Required. Semantics against the cart's balance due:
|
|
7
|
+
* - missing → error
|
|
8
|
+
* - less than balance → partial payment (the POS enters a fixed
|
|
9
|
+
* split-payment leg for this amount)
|
|
10
|
+
* - equal to balance → full payment
|
|
11
|
+
* - more than balance → error
|
|
12
|
+
*/
|
|
13
|
+
amount: number;
|
|
6
14
|
/** Override the fulfillment state after full payment. Render resolves the cascade. */
|
|
7
15
|
checkoutFulfillmentTarget?: string;
|
|
8
16
|
}
|
package/dist/demo/database.js
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -33,6 +33,7 @@ export declare const command: {
|
|
|
33
33
|
readonly resumeParkedOrder: import(".").ResumeParkedOrder;
|
|
34
34
|
readonly deleteParkedOrder: import(".").DeleteParkedOrder;
|
|
35
35
|
readonly cashPayment: import(".").CashPayment;
|
|
36
|
+
readonly getCashRoundingAmount: import(".").GetCashRoundingAmount;
|
|
36
37
|
readonly tapToPayPayment: import(".").TapToPayPayment;
|
|
37
38
|
readonly terminalPayment: import(".").TerminalPayment;
|
|
38
39
|
readonly vendaraPayment: import(".").VendaraPayment;
|
|
@@ -68,6 +69,8 @@ export declare const command: {
|
|
|
68
69
|
readonly removeOrderNote: import(".").RemoveOrderNote;
|
|
69
70
|
readonly removeCustomSale: import(".").RemoveCustomSale;
|
|
70
71
|
readonly removeNonRevenueItem: import(".").RemoveNonRevenueItem;
|
|
72
|
+
readonly sendEmail: import(".").SendEmail;
|
|
73
|
+
readonly sendSms: import(".").SendSms;
|
|
71
74
|
readonly initiateRefund: import(".").InitiateRefund;
|
|
72
75
|
readonly setRefundStockAction: import(".").SetRefundStockAction;
|
|
73
76
|
readonly selectAllRefundItems: import(".").SelectAllRefundItems;
|
|
@@ -157,6 +160,7 @@ export type { ParkOrder, ParkOrderResponse } from "./actions/park-order/types";
|
|
|
157
160
|
export type { ResumeParkedOrder, ResumeParkedOrderParams, ResumeParkedOrderResponse } from "./actions/resume-parked-order/types";
|
|
158
161
|
export type { DeleteParkedOrder, DeleteParkedOrderParams, DeleteParkedOrderResponse } from "./actions/delete-parked-order/types";
|
|
159
162
|
export type { CashPayment, CashPaymentParams, CashPaymentResponse } from "./actions/cash-payment/types";
|
|
163
|
+
export type { GetCashRoundingAmount, GetCashRoundingAmountParams, GetCashRoundingAmountResponse } from "./actions/get-cash-rounding-amount/types";
|
|
160
164
|
export type { TapToPayPayment, TapToPayPaymentParams, TapToPayPaymentResponse } from "./actions/tap-to-pay-payment/types";
|
|
161
165
|
export type { TerminalPayment, TerminalPaymentParams, TerminalPaymentResponse } from "./actions/terminal-payment/types";
|
|
162
166
|
export type { VendaraPayment, VendaraPaymentParams, VendaraPaymentResponse } from "./actions/vendara-payment/types";
|
|
@@ -198,6 +202,8 @@ export type { RemoveCartFee, RemoveCartFeeParams, RemoveCartFeeResponse } from "
|
|
|
198
202
|
export type { RemoveOrderNote, RemoveOrderNoteResponse } from "./actions/remove-order-note/types";
|
|
199
203
|
export type { RemoveCustomSale, RemoveCustomSaleParams, RemoveCustomSaleResponse } from "./actions/remove-custom-sale/types";
|
|
200
204
|
export type { RemoveNonRevenueItem, RemoveNonRevenueItemParams, RemoveNonRevenueItemResponse } from "./actions/remove-non-revenue-item/types";
|
|
205
|
+
export type { SendEmail, SendEmailParams, SendEmailResponse, SendReceiptType } from "./actions/send-email/types";
|
|
206
|
+
export type { SendSms, SendSmsParams, SendSmsResponse } from "./actions/send-sms/types";
|
|
201
207
|
export * from "./CommonTypes";
|
|
202
208
|
export { setMockDatabase, setMockActiveProduct } from "./demo/database";
|
|
203
209
|
export type { MockDatabaseConfig } from "./demo/database";
|
package/dist/index.js
CHANGED
|
@@ -33,6 +33,7 @@ import { parkOrder } from "./actions/park-order/action";
|
|
|
33
33
|
import { resumeParkedOrder } from "./actions/resume-parked-order/action";
|
|
34
34
|
import { deleteParkedOrder } from "./actions/delete-parked-order/action";
|
|
35
35
|
import { cashPayment } from "./actions/cash-payment/action";
|
|
36
|
+
import { getCashRoundingAmount } from "./actions/get-cash-rounding-amount/action";
|
|
36
37
|
import { tapToPayPayment } from "./actions/tap-to-pay-payment/action";
|
|
37
38
|
import { terminalPayment } from "./actions/terminal-payment/action";
|
|
38
39
|
import { vendaraPayment } from "./actions/vendara-payment/action";
|
|
@@ -72,6 +73,9 @@ import { removeOrderNote } from "./actions/remove-order-note/action";
|
|
|
72
73
|
import { removeCustomSale } from "./actions/remove-custom-sale/action";
|
|
73
74
|
import { removeNonRevenueItem } from "./actions/remove-non-revenue-item/action";
|
|
74
75
|
// Integration Actions
|
|
76
|
+
// Receipt send Actions
|
|
77
|
+
import { sendEmail } from "./actions/send-email/action";
|
|
78
|
+
import { sendSms } from "./actions/send-sms/action";
|
|
75
79
|
// Refund Actions
|
|
76
80
|
import { getRefunds } from "./actions/get-refunds/action";
|
|
77
81
|
import { initiateRefund } from "./actions/initiate-refund/action";
|
|
@@ -158,6 +162,7 @@ export const command = {
|
|
|
158
162
|
resumeParkedOrder,
|
|
159
163
|
deleteParkedOrder,
|
|
160
164
|
cashPayment,
|
|
165
|
+
getCashRoundingAmount,
|
|
161
166
|
tapToPayPayment,
|
|
162
167
|
terminalPayment,
|
|
163
168
|
vendaraPayment,
|
|
@@ -197,6 +202,9 @@ export const command = {
|
|
|
197
202
|
removeCustomSale,
|
|
198
203
|
removeNonRevenueItem,
|
|
199
204
|
// Integration Actions
|
|
205
|
+
// Receipt send Actions
|
|
206
|
+
sendEmail,
|
|
207
|
+
sendSms,
|
|
200
208
|
// Refund Actions
|
|
201
209
|
initiateRefund,
|
|
202
210
|
setRefundStockAction,
|
|
@@ -245,7 +253,6 @@ export const command = {
|
|
|
245
253
|
getAvailableTransitions,
|
|
246
254
|
applyTransition
|
|
247
255
|
};
|
|
248
|
-
// Integration Actions
|
|
249
256
|
// Export Common Types
|
|
250
257
|
export * from "./CommonTypes";
|
|
251
258
|
// Mock database override (standalone / extension dev)
|
|
@@ -27,6 +27,7 @@ import { mockAssignCustomer } from "../../actions/assign-customer/mock";
|
|
|
27
27
|
import { mockAuthenticateUser } from "../../actions/authenticate-user/mock";
|
|
28
28
|
import { mockCalculateRefundTotal } from "../../actions/calculate-refund-total/mock";
|
|
29
29
|
import { mockCashPayment } from "../../actions/cash-payment/mock";
|
|
30
|
+
import { mockGetCashRoundingAmount } from "../../actions/get-cash-rounding-amount/mock";
|
|
30
31
|
import { mockClearCart } from "../../actions/clear-cart/mock";
|
|
31
32
|
import { mockDeleteParkedOrder } from "../../actions/delete-parked-order/mock";
|
|
32
33
|
import { mockExampleFunction } from "../../actions/example-function/mock";
|
|
@@ -91,6 +92,8 @@ import { canTransitionMock } from "../../actions/can-transition/mock";
|
|
|
91
92
|
import { getAvailableTransitionsMock } from "../../actions/get-available-transitions/mock";
|
|
92
93
|
import { mockGetSmartGridLayout } from "../../actions/get-smart-grid-layout/mock";
|
|
93
94
|
import { mockSaveSmartGridLayout } from "../../actions/save-smart-grid-layout/mock";
|
|
95
|
+
import { mockSendEmail } from "../../actions/send-email/mock";
|
|
96
|
+
import { mockSendSms } from "../../actions/send-sms/mock";
|
|
94
97
|
export const RENDER_MOCKS = {
|
|
95
98
|
addCartDiscount: mockAddCartDiscount,
|
|
96
99
|
addCartFee: mockAddCartFee,
|
|
@@ -115,6 +118,7 @@ export const RENDER_MOCKS = {
|
|
|
115
118
|
authenticateUser: mockAuthenticateUser,
|
|
116
119
|
calculateRefundTotal: mockCalculateRefundTotal,
|
|
117
120
|
cashPayment: mockCashPayment,
|
|
121
|
+
getCashRoundingAmount: mockGetCashRoundingAmount,
|
|
118
122
|
clearCart: mockClearCart,
|
|
119
123
|
deleteParkedOrder: mockDeleteParkedOrder,
|
|
120
124
|
exampleFunction: mockExampleFunction,
|
|
@@ -186,5 +190,7 @@ export const RENDER_MOCKS = {
|
|
|
186
190
|
canTransition: canTransitionMock,
|
|
187
191
|
getAvailableTransitions: getAvailableTransitionsMock,
|
|
188
192
|
getSmartGridLayout: mockGetSmartGridLayout,
|
|
189
|
-
saveSmartGridLayout: mockSaveSmartGridLayout
|
|
193
|
+
saveSmartGridLayout: mockSaveSmartGridLayout,
|
|
194
|
+
sendEmail: mockSendEmail,
|
|
195
|
+
sendSms: mockSendSms
|
|
190
196
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ExampleFunction, GetProducts, AddCustomSale, GetCustomers, AssignCustomer, AddCustomer, EditCustomer, GetCategories, GetOrders, GetRefunds, GetTaxTables, AddProductDiscount, AddProductToCart, RemoveProductFromCart, UpdateCartItemQuantity, AddCartDiscount, GetContext, GetFinalContext, AddProductNote, AddProductFee, SetActiveProductFee, SetActiveProductDiscount, GetActiveProduct, SetActiveProduct, AdjustInventory, AddOrderNote, AddCartFee, ClearCart, ParkOrder, ResumeParkedOrder, DeleteParkedOrder, InitiateRefund, CashPayment, TapToPayPayment, TerminalPayment, VendaraPayment, ExtensionPayment, RedeemPayment, AddNonRevenueItem, AddCustomerNote, RemoveCustomerNote, RemoveCustomerFromCart, GoToStationHome, OpenCashDrawer, ShowNotification, ShowConfirmation, AuthenticateUser, PartialPayment, SwitchUser, SetRefundStockAction, SelectAllRefundItems, ResetRefundDetails, CalculateRefundTotal, GetRemainingRefundableQuantities, ProcessPartialRefund, GetCurrentCart, Print, SetActiveOrder, GetCustomTables, GetCustomTableData, UpsertCustomTableData, DeleteCustomTableData, GetCustomExtensions, GetCurrentCompanyCustomExtensions, GetCustomExtensionCustomTables, GetCustomTableFields, GetSecretsKeys, GetSecretVal, SetSecretVal, GetUsers, GetRoles, RemoveCartDiscount, GetActiveOrder, GetActiveCustomer, SetActiveCustomer, GetActiveOutlet, GetActiveStation, GetActiveSession, GetActiveUser, SetActiveUser, SetActiveRefund, RemoveProductDiscount, RemoveProductFee, RemoveProductNote, RemoveCartFee, RemoveOrderNote, RemoveCustomSale, RemoveNonRevenueItem, CanTransition, GetAvailableTransitions, IntegrationPayment, GetSmartGridLayout, SaveSmartGridLayout } from "../../index";
|
|
1
|
+
import type { ExampleFunction, GetProducts, AddCustomSale, GetCustomers, AssignCustomer, AddCustomer, EditCustomer, GetCategories, GetOrders, GetRefunds, GetTaxTables, AddProductDiscount, AddProductToCart, RemoveProductFromCart, UpdateCartItemQuantity, AddCartDiscount, GetContext, GetFinalContext, AddProductNote, AddProductFee, SetActiveProductFee, SetActiveProductDiscount, GetActiveProduct, SetActiveProduct, AdjustInventory, AddOrderNote, AddCartFee, ClearCart, ParkOrder, ResumeParkedOrder, DeleteParkedOrder, InitiateRefund, CashPayment, GetCashRoundingAmount, TapToPayPayment, TerminalPayment, VendaraPayment, ExtensionPayment, RedeemPayment, AddNonRevenueItem, AddCustomerNote, RemoveCustomerNote, RemoveCustomerFromCart, GoToStationHome, OpenCashDrawer, ShowNotification, ShowConfirmation, AuthenticateUser, PartialPayment, SwitchUser, SetRefundStockAction, SelectAllRefundItems, ResetRefundDetails, CalculateRefundTotal, GetRemainingRefundableQuantities, ProcessPartialRefund, GetCurrentCart, Print, SetActiveOrder, GetCustomTables, GetCustomTableData, UpsertCustomTableData, DeleteCustomTableData, GetCustomExtensions, GetCurrentCompanyCustomExtensions, GetCustomExtensionCustomTables, GetCustomTableFields, GetSecretsKeys, GetSecretVal, SetSecretVal, GetUsers, GetRoles, RemoveCartDiscount, GetActiveOrder, GetActiveCustomer, SetActiveCustomer, GetActiveOutlet, GetActiveStation, GetActiveSession, GetActiveUser, SetActiveUser, SetActiveRefund, RemoveProductDiscount, RemoveProductFee, RemoveProductNote, RemoveCartFee, RemoveOrderNote, RemoveCustomSale, RemoveNonRevenueItem, CanTransition, GetAvailableTransitions, IntegrationPayment, GetSmartGridLayout, SaveSmartGridLayout, SendEmail, SendSms } from "../../index";
|
|
2
2
|
import type { OpenExtensionOverlay } from "../../actions/open-extension-overlay/types";
|
|
3
3
|
import type { ResolveExtensionOverlay } from "../../actions/resolve-extension-overlay/types";
|
|
4
4
|
export interface RenderProviderActions {
|
|
@@ -37,6 +37,7 @@ export interface RenderProviderActions {
|
|
|
37
37
|
openExtensionOverlay: OpenExtensionOverlay;
|
|
38
38
|
resolveExtensionOverlay: ResolveExtensionOverlay;
|
|
39
39
|
cashPayment: CashPayment;
|
|
40
|
+
getCashRoundingAmount: GetCashRoundingAmount;
|
|
40
41
|
tapToPayPayment: TapToPayPayment;
|
|
41
42
|
terminalPayment: TerminalPayment;
|
|
42
43
|
vendaraPayment: VendaraPayment;
|
|
@@ -97,4 +98,6 @@ export interface RenderProviderActions {
|
|
|
97
98
|
getAvailableTransitions: GetAvailableTransitions;
|
|
98
99
|
getSmartGridLayout: GetSmartGridLayout;
|
|
99
100
|
saveSmartGridLayout: SaveSmartGridLayout;
|
|
101
|
+
sendEmail: SendEmail;
|
|
102
|
+
sendSms: SendSms;
|
|
100
103
|
}
|