@final-commerce/command-frame 0.8.0-online.4 → 0.8.0-online.5
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/actions/attach-checkout-contact/action.d.ts +6 -0
- package/dist/actions/attach-checkout-contact/action.js +8 -0
- package/dist/actions/attach-checkout-contact/mock.d.ts +15 -0
- package/dist/actions/attach-checkout-contact/mock.js +22 -0
- package/dist/actions/attach-checkout-contact/types.d.ts +35 -0
- package/dist/actions/attach-checkout-contact/types.js +16 -0
- package/dist/actions/start-checkout/mock.d.ts +1 -1
- package/dist/actions/start-checkout/mock.js +4 -4
- package/dist/actions/start-checkout/types.d.ts +10 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/projects/render/mocks.js +2 -0
- package/dist/projects/render/types.d.ts +2 -1
- package/package.json +1 -1
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Attach Checkout Contact action
|
|
3
|
+
* Calls the attachCheckoutContact action on the parent window
|
|
4
|
+
*/
|
|
5
|
+
import { commandFrameClient } from '../../client';
|
|
6
|
+
export const attachCheckoutContact = async (params) => {
|
|
7
|
+
return await commandFrameClient.call('attachCheckoutContact', params);
|
|
8
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { AttachCheckoutContact } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Standalone mock of attaching contact to an online order.
|
|
4
|
+
*
|
|
5
|
+
* It mirrors the one REFUSAL the real command makes — a missing email — because
|
|
6
|
+
* that is the mistake a builder actually hits, and a mock that accepted anything
|
|
7
|
+
* would let a checkout screen look finished and lose receipts on the published
|
|
8
|
+
* site.
|
|
9
|
+
*
|
|
10
|
+
* It does NOT mirror "no order to attach to". The real command answers
|
|
11
|
+
* `attached: false` there rather than throwing, precisely so a flow can call it
|
|
12
|
+
* optimistically and still let the shopper pay; the mock always has a checkout
|
|
13
|
+
* to attach to, so it reports `true`.
|
|
14
|
+
*/
|
|
15
|
+
export declare const mockAttachCheckoutContact: AttachCheckoutContact;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Standalone mock of attaching contact to an online order.
|
|
3
|
+
*
|
|
4
|
+
* It mirrors the one REFUSAL the real command makes — a missing email — because
|
|
5
|
+
* that is the mistake a builder actually hits, and a mock that accepted anything
|
|
6
|
+
* would let a checkout screen look finished and lose receipts on the published
|
|
7
|
+
* site.
|
|
8
|
+
*
|
|
9
|
+
* It does NOT mirror "no order to attach to". The real command answers
|
|
10
|
+
* `attached: false` there rather than throwing, precisely so a flow can call it
|
|
11
|
+
* optimistically and still let the shopper pay; the mock always has a checkout
|
|
12
|
+
* to attach to, so it reports `true`.
|
|
13
|
+
*/
|
|
14
|
+
export const mockAttachCheckoutContact = async (params) => {
|
|
15
|
+
console.log('[Mock] attachCheckoutContact called', params);
|
|
16
|
+
if (!params)
|
|
17
|
+
throw new Error('Params required');
|
|
18
|
+
if (!params.email || !params.email.trim()) {
|
|
19
|
+
throw new Error('attachCheckoutContact: email is required — it is where the receipt goes');
|
|
20
|
+
}
|
|
21
|
+
return { attached: true, timestamp: new Date().toISOString() };
|
|
22
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Guest contact for the order. There is no shopper account, so this is the only
|
|
3
|
+
* way to reach them — `email` is where the receipt goes and is required.
|
|
4
|
+
*/
|
|
5
|
+
export interface AttachCheckoutContactParams {
|
|
6
|
+
email: string;
|
|
7
|
+
name?: string;
|
|
8
|
+
phone?: string;
|
|
9
|
+
/** Defaults to the outlet the storefront booted against. */
|
|
10
|
+
outletId?: string;
|
|
11
|
+
}
|
|
12
|
+
export interface AttachCheckoutContactResponse {
|
|
13
|
+
/**
|
|
14
|
+
* `false` means there was nothing to attach to — no checkout had been started
|
|
15
|
+
* for this cart. It is NOT a failure to record the contact on an order that
|
|
16
|
+
* exists, and it never means the shopper was charged.
|
|
17
|
+
*/
|
|
18
|
+
attached: boolean;
|
|
19
|
+
timestamp: string;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Put the shopper's contact on the order `startCheckout` already created.
|
|
23
|
+
*
|
|
24
|
+
* Call it BEFORE paying, whenever the email is known — on blur, on submit, or
|
|
25
|
+
* as the shopper leaves the contact step. It reuses the order's idempotency
|
|
26
|
+
* key, so it updates that order rather than creating a second one.
|
|
27
|
+
*
|
|
28
|
+
* SAFE TO CALL TWICE. The server only ever ADDS contact to an order that has
|
|
29
|
+
* none, so a later call cannot redirect a receipt that was already addressed.
|
|
30
|
+
*
|
|
31
|
+
* NEVER THROWS FOR A MISSING ORDER. Failing to record an email must not stop a
|
|
32
|
+
* payment the shopper is trying to make, so the caller gets `attached: false`
|
|
33
|
+
* and can carry on to pay.
|
|
34
|
+
*/
|
|
35
|
+
export type AttachCheckoutContact = (params: AttachCheckoutContactParams) => Promise<AttachCheckoutContactResponse>;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// Attach Checkout Contact Types
|
|
2
|
+
//
|
|
3
|
+
// The second half of the online checkout. `startCheckout` creates the order and
|
|
4
|
+
// mounts the payment fields the moment a shopper ARRIVES; this puts their email
|
|
5
|
+
// on that same order once they have typed it.
|
|
6
|
+
//
|
|
7
|
+
// WHY THESE ARE TWO COMMANDS. The card fields cannot render without a payment
|
|
8
|
+
// session, a session needs a server-priced amount, and an amount needs an order.
|
|
9
|
+
// So the order has to exist before the shopper has typed anything. Demanding an
|
|
10
|
+
// email first is what forced the old "fill the form, then see the card fields"
|
|
11
|
+
// checkout — and it also meant every cart edit minted a NEW order, because the
|
|
12
|
+
// idempotency key moved with the cart.
|
|
13
|
+
//
|
|
14
|
+
// Served ONLY by the storefront runtime (a published website), like
|
|
15
|
+
// `startCheckout` itself. On a register it does not exist.
|
|
16
|
+
export {};
|
|
@@ -2,7 +2,7 @@ import { StartCheckout } from './types';
|
|
|
2
2
|
/**
|
|
3
3
|
* Standalone mock of the storefront checkout.
|
|
4
4
|
*
|
|
5
|
-
* It mirrors the REFUSALS of the real command (empty cart,
|
|
5
|
+
* It mirrors the REFUSALS of the real command (empty cart,
|
|
6
6
|
* container not on the page) in the same order, because those are what a
|
|
7
7
|
* builder actually hits first — a mock that accepted anything would let a
|
|
8
8
|
* checkout screen look finished and fail on the published site.
|
|
@@ -2,7 +2,7 @@ import { MOCK_CART, MOCK_COMPANY, mockPublishEvent } from '../../demo/database';
|
|
|
2
2
|
/**
|
|
3
3
|
* Standalone mock of the storefront checkout.
|
|
4
4
|
*
|
|
5
|
-
* It mirrors the REFUSALS of the real command (empty cart,
|
|
5
|
+
* It mirrors the REFUSALS of the real command (empty cart,
|
|
6
6
|
* container not on the page) in the same order, because those are what a
|
|
7
7
|
* builder actually hits first — a mock that accepted anything would let a
|
|
8
8
|
* checkout screen look finished and fail on the published site.
|
|
@@ -17,9 +17,9 @@ export const mockStartCheckout = async (params) => {
|
|
|
17
17
|
console.log('[Mock] startCheckout called', params);
|
|
18
18
|
if (!params)
|
|
19
19
|
throw new Error('Params required');
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
// No email check: contact is optional now, because checkout starts on arrival.
|
|
21
|
+
// Refusing here would make "start on arrival" fail in PREVIEW while working on
|
|
22
|
+
// the published site, which is the worst way for this to be wrong.
|
|
23
23
|
if (!params.container || typeof params.container !== 'string') {
|
|
24
24
|
throw new Error('startCheckout: container must be a CSS selector string (e.g. "#card-fields") — a DOM element cannot cross the command boundary');
|
|
25
25
|
}
|
|
@@ -8,7 +8,16 @@ export interface StartCheckoutContact {
|
|
|
8
8
|
phone?: string;
|
|
9
9
|
}
|
|
10
10
|
export interface StartCheckoutParams {
|
|
11
|
-
|
|
11
|
+
/**
|
|
12
|
+
* OPTIONAL, because checkout starts when the shopper ARRIVES rather than when
|
|
13
|
+
* they submit a form. The card fields cannot render without a payment session,
|
|
14
|
+
* a session needs a server-priced amount, and an amount needs an order — so the
|
|
15
|
+
* order has to exist before they have typed anything.
|
|
16
|
+
*
|
|
17
|
+
* Supply it afterwards with `attachCheckoutContact`, which re-sends the same
|
|
18
|
+
* idempotency key and so reaches the SAME order.
|
|
19
|
+
*/
|
|
20
|
+
contact?: StartCheckoutContact;
|
|
12
21
|
/**
|
|
13
22
|
* CSS SELECTOR for the element the payment fields mount into, e.g.
|
|
14
23
|
* `'#card-fields'`. The element must already be in the DOM when this is
|
package/dist/index.d.ts
CHANGED
|
@@ -46,6 +46,7 @@ export declare const command: {
|
|
|
46
46
|
readonly createPaymentLink: import(".").CreatePaymentLink;
|
|
47
47
|
readonly chargeMoto: import(".").ChargeMoto;
|
|
48
48
|
readonly startCheckout: import(".").StartCheckout;
|
|
49
|
+
readonly attachCheckoutContact: import(".").AttachCheckoutContact;
|
|
49
50
|
readonly resumeCheckout: import(".").ResumeCheckout;
|
|
50
51
|
readonly addCustomerNote: import(".").AddCustomerNote;
|
|
51
52
|
readonly removeCustomerNote: import(".").RemoveCustomerNote;
|
|
@@ -185,6 +186,7 @@ export type { IntegrationPayment, IntegrationPaymentParams, IntegrationPaymentRe
|
|
|
185
186
|
export type { CreatePaymentLink, CreatePaymentLinkParams, CreatePaymentLinkResponse, } from './actions/create-payment-link/types';
|
|
186
187
|
export type { ChargeMoto, ChargeMotoParams, ChargeMotoResponse, ChargeMotoCardFields, } from './actions/charge-moto/types';
|
|
187
188
|
export type { StartCheckout, StartCheckoutParams, StartCheckoutResponse, StartCheckoutContact, StartCheckoutOrder, } from './actions/start-checkout/types';
|
|
189
|
+
export type { AttachCheckoutContact, AttachCheckoutContactParams, AttachCheckoutContactResponse, } from './actions/attach-checkout-contact/types';
|
|
188
190
|
export type { ResumeCheckout, ResumeCheckoutParams, ResumeCheckoutResponse, ResumeCheckoutResult, } from './actions/resume-checkout/types';
|
|
189
191
|
export type { AddCustomerNote, AddCustomerNoteParams, AddCustomerNoteResponse, } from './actions/add-customer-note/types';
|
|
190
192
|
export type { RemoveCustomerNote, RemoveCustomerNoteParams, RemoveCustomerNoteResponse, } from './actions/remove-customer-note/types';
|
package/dist/index.js
CHANGED
|
@@ -46,6 +46,7 @@ import { integrationPayment } from './actions/integration-payment/action';
|
|
|
46
46
|
import { createPaymentLink } from './actions/create-payment-link/action';
|
|
47
47
|
import { chargeMoto } from './actions/charge-moto/action';
|
|
48
48
|
import { startCheckout } from './actions/start-checkout/action';
|
|
49
|
+
import { attachCheckoutContact } from './actions/attach-checkout-contact/action';
|
|
49
50
|
import { resumeCheckout } from './actions/resume-checkout/action';
|
|
50
51
|
// Customer Actions
|
|
51
52
|
import { addCustomerNote } from './actions/add-customer-note/action';
|
|
@@ -187,6 +188,7 @@ export const command = {
|
|
|
187
188
|
createPaymentLink,
|
|
188
189
|
chargeMoto,
|
|
189
190
|
startCheckout,
|
|
191
|
+
attachCheckoutContact,
|
|
190
192
|
resumeCheckout,
|
|
191
193
|
// Customer Actions
|
|
192
194
|
addCustomerNote,
|
|
@@ -34,6 +34,7 @@ import { mockGetCashRoundingAmount } from '../../actions/get-cash-rounding-amoun
|
|
|
34
34
|
import { mockCreatePaymentLink } from '../../actions/create-payment-link/mock';
|
|
35
35
|
import { mockChargeMoto } from '../../actions/charge-moto/mock';
|
|
36
36
|
import { mockStartCheckout } from '../../actions/start-checkout/mock';
|
|
37
|
+
import { mockAttachCheckoutContact } from '../../actions/attach-checkout-contact/mock';
|
|
37
38
|
import { mockResumeCheckout } from '../../actions/resume-checkout/mock';
|
|
38
39
|
import { mockGetTimeClockStatus } from '../../actions/get-time-clock-status/mock';
|
|
39
40
|
import { mockClearCart } from '../../actions/clear-cart/mock';
|
|
@@ -135,6 +136,7 @@ export const RENDER_MOCKS = {
|
|
|
135
136
|
createPaymentLink: mockCreatePaymentLink,
|
|
136
137
|
chargeMoto: mockChargeMoto,
|
|
137
138
|
startCheckout: mockStartCheckout,
|
|
139
|
+
attachCheckoutContact: mockAttachCheckoutContact,
|
|
138
140
|
resumeCheckout: mockResumeCheckout,
|
|
139
141
|
clearCart: mockClearCart,
|
|
140
142
|
deleteParkedOrder: mockDeleteParkedOrder,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ExampleFunction, GetProducts, AddCustomSale, EditCustomSale, GetCustomers, AssignCustomer, AddCustomer, EditCustomer, GetCategories, GetOrders, GetRefunds, GetTaxTables, AddProductDiscount, AddProductToCart, RemoveProductFromCart, UpdateCartItemQuantity, AddCartDiscount, GetContext, GetFinalContext, AddProductNote, AddProductFee, GetProductModifierSelections, SetProductModifierSelections, SetActiveProductFee, SetActiveProductDiscount, GetActiveProduct, SetActiveProduct, AdjustInventory, AddOrderNote, AddCartFee, ClearCart, ParkOrder, ResumeParkedOrder, DeleteParkedOrder, VoidOrder, InitiateRefund, CashPayment, GetCashRoundingAmount, TapToPayPayment, TerminalPayment, ExtensionPayment, RedeemPayment, AddNonRevenueItem, AddCustomerNote, RemoveCustomerNote, RemoveCustomerFromCart, GoToStationHome, OpenCashDrawer, ShowNotification, ShowConfirmation, AuthenticateUser, PartialPayment, SwitchUser, SetRefundStockAction, SelectAllRefundItems, ResetRefundDetails, CalculateRefundTotal, GetRemainingRefundableQuantities, ProcessPartialRefund, RedeemRefund, GetRefundPlan, CheckPermission, 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, ApplyTransition, IntegrationPayment, GetSmartGridLayout, SaveSmartGridLayout, SendEmail, SendSms, CreatePaymentLink, ChargeMoto, StartCheckout, ResumeCheckout, GetTimeClockStatus } from '../../index';
|
|
1
|
+
import type { ExampleFunction, GetProducts, AddCustomSale, EditCustomSale, GetCustomers, AssignCustomer, AddCustomer, EditCustomer, GetCategories, GetOrders, GetRefunds, GetTaxTables, AddProductDiscount, AddProductToCart, RemoveProductFromCart, UpdateCartItemQuantity, AddCartDiscount, GetContext, GetFinalContext, AddProductNote, AddProductFee, GetProductModifierSelections, SetProductModifierSelections, SetActiveProductFee, SetActiveProductDiscount, GetActiveProduct, SetActiveProduct, AdjustInventory, AddOrderNote, AddCartFee, ClearCart, ParkOrder, ResumeParkedOrder, DeleteParkedOrder, VoidOrder, InitiateRefund, CashPayment, GetCashRoundingAmount, TapToPayPayment, TerminalPayment, ExtensionPayment, RedeemPayment, AddNonRevenueItem, AddCustomerNote, RemoveCustomerNote, RemoveCustomerFromCart, GoToStationHome, OpenCashDrawer, ShowNotification, ShowConfirmation, AuthenticateUser, PartialPayment, SwitchUser, SetRefundStockAction, SelectAllRefundItems, ResetRefundDetails, CalculateRefundTotal, GetRemainingRefundableQuantities, ProcessPartialRefund, RedeemRefund, GetRefundPlan, CheckPermission, 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, ApplyTransition, IntegrationPayment, GetSmartGridLayout, SaveSmartGridLayout, SendEmail, SendSms, CreatePaymentLink, ChargeMoto, StartCheckout, AttachCheckoutContact, ResumeCheckout, GetTimeClockStatus } from '../../index';
|
|
2
2
|
export interface RenderProviderActions {
|
|
3
3
|
exampleFunction: ExampleFunction;
|
|
4
4
|
getProducts: GetProducts;
|
|
@@ -51,6 +51,7 @@ export interface RenderProviderActions {
|
|
|
51
51
|
* a register, because the two declare different things to the card networks.
|
|
52
52
|
*/
|
|
53
53
|
startCheckout: StartCheckout;
|
|
54
|
+
attachCheckoutContact: AttachCheckoutContact;
|
|
54
55
|
/**
|
|
55
56
|
* The RETURN LEG of an online checkout, after a redirect payment method or
|
|
56
57
|
* 3-D Secure sent the shopper away and back. Storefront-only, like
|