@final-commerce/command-frame 0.8.0-online.5 → 0.8.0-online.6
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/CommonTypes.d.ts +14 -0
- package/dist/actions/get-outlets/action.js +2 -2
- package/dist/actions/get-outlets/mock.d.ts +12 -0
- package/dist/actions/get-outlets/mock.js +28 -4
- package/dist/actions/get-outlets/types.d.ts +19 -1
- package/dist/actions/set-outlet/action.d.ts +6 -0
- package/dist/actions/set-outlet/action.js +8 -0
- package/dist/actions/set-outlet/mock.d.ts +13 -0
- package/dist/actions/set-outlet/mock.js +24 -0
- package/dist/actions/set-outlet/types.d.ts +31 -0
- package/dist/actions/set-outlet/types.js +21 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.js +2 -0
- package/dist/projects/render/mocks.js +4 -0
- package/dist/projects/render/types.d.ts +3 -1
- package/package.json +1 -1
package/dist/CommonTypes.d.ts
CHANGED
|
@@ -156,9 +156,23 @@ export interface CFOutletInfo {
|
|
|
156
156
|
state?: string;
|
|
157
157
|
postCode?: string;
|
|
158
158
|
};
|
|
159
|
+
address2?: string;
|
|
159
160
|
city?: string;
|
|
160
161
|
state?: string;
|
|
161
162
|
country?: string;
|
|
163
|
+
postCode?: string;
|
|
164
|
+
phone?: string;
|
|
165
|
+
/** Short display alias, when the merchant set one (e.g. `DTWN`). */
|
|
166
|
+
alias?: string;
|
|
167
|
+
/**
|
|
168
|
+
* Whether this location can take an ONLINE payment. Storefront only — it is
|
|
169
|
+
* absent on a register, where it has no meaning.
|
|
170
|
+
*
|
|
171
|
+
* `false` means the outlet has no completed payment connection, so starting a
|
|
172
|
+
* checkout against it WILL fail. A pickup picker must not offer it as a
|
|
173
|
+
* selectable location, or must show it as unavailable.
|
|
174
|
+
*/
|
|
175
|
+
connected?: boolean;
|
|
162
176
|
}
|
|
163
177
|
export interface CFContextManage {
|
|
164
178
|
user: unknown;
|
|
@@ -1,2 +1,14 @@
|
|
|
1
1
|
import { GetOutlets } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* A second location that CANNOT take an online payment.
|
|
4
|
+
*
|
|
5
|
+
* The shared demo data has exactly one outlet, so without this a pickup picker
|
|
6
|
+
* built against mocks would never render the case that matters: an outlet a
|
|
7
|
+
* shopper must not be allowed to check out against. `setOutlet` refuses this id,
|
|
8
|
+
* so the two mocks tell the same story.
|
|
9
|
+
*
|
|
10
|
+
* Mock-only, and deliberately NOT added to `MOCK_OUTLETS` — that array is shared
|
|
11
|
+
* with every other outlet mock and `MOCK_OUTLET`.
|
|
12
|
+
*/
|
|
13
|
+
export declare const MOCK_UNCONNECTED_OUTLET_ID = "outlet-mock-unconnected";
|
|
2
14
|
export declare const mockGetOutlets: GetOutlets;
|
|
@@ -1,16 +1,40 @@
|
|
|
1
1
|
import { MOCK_OUTLETS, safeSerialize } from "../../demo/database";
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
/**
|
|
3
|
+
* A second location that CANNOT take an online payment.
|
|
4
|
+
*
|
|
5
|
+
* The shared demo data has exactly one outlet, so without this a pickup picker
|
|
6
|
+
* built against mocks would never render the case that matters: an outlet a
|
|
7
|
+
* shopper must not be allowed to check out against. `setOutlet` refuses this id,
|
|
8
|
+
* so the two mocks tell the same story.
|
|
9
|
+
*
|
|
10
|
+
* Mock-only, and deliberately NOT added to `MOCK_OUTLETS` — that array is shared
|
|
11
|
+
* with every other outlet mock and `MOCK_OUTLET`.
|
|
12
|
+
*/
|
|
13
|
+
export const MOCK_UNCONNECTED_OUTLET_ID = "outlet-mock-unconnected";
|
|
14
|
+
const UNCONNECTED_OUTLET = {
|
|
15
|
+
_id: MOCK_UNCONNECTED_OUTLET_ID,
|
|
16
|
+
name: "Airport (not connected)",
|
|
17
|
+
address: "2 Terminal Road",
|
|
18
|
+
city: "San Francisco",
|
|
19
|
+
state: "CA",
|
|
20
|
+
country: "US",
|
|
21
|
+
postCode: "94128",
|
|
22
|
+
connected: false
|
|
23
|
+
};
|
|
24
|
+
export const mockGetOutlets = async (params) => {
|
|
25
|
+
console.log("[Mock] getOutlets called", params);
|
|
4
26
|
const outlets = safeSerialize(MOCK_OUTLETS).map((o) => ({
|
|
5
27
|
_id: o._id || o.id,
|
|
6
28
|
name: o.name || "",
|
|
7
29
|
address: o.address,
|
|
8
30
|
city: o.city,
|
|
9
31
|
state: o.state,
|
|
10
|
-
country: o.country
|
|
32
|
+
country: o.country,
|
|
33
|
+
connected: true
|
|
11
34
|
}));
|
|
35
|
+
const all = [...outlets, UNCONNECTED_OUTLET];
|
|
12
36
|
return {
|
|
13
|
-
outlets,
|
|
37
|
+
outlets: params?.connectedOnly ? all.filter((o) => o.connected) : all,
|
|
14
38
|
timestamp: new Date().toISOString()
|
|
15
39
|
};
|
|
16
40
|
};
|
|
@@ -1,6 +1,24 @@
|
|
|
1
1
|
import { CFOutletInfo } from "../../CommonTypes";
|
|
2
|
+
export interface GetOutletsParams {
|
|
3
|
+
/**
|
|
4
|
+
* Return only locations that can take an online payment. Storefront only.
|
|
5
|
+
* Default `false`, so a flow sees every outlet and decides how to present
|
|
6
|
+
* the ones it cannot sell from.
|
|
7
|
+
*/
|
|
8
|
+
connectedOnly?: boolean;
|
|
9
|
+
}
|
|
2
10
|
export interface GetOutletsResponse {
|
|
3
11
|
outlets: CFOutletInfo[];
|
|
4
12
|
timestamp: string;
|
|
5
13
|
}
|
|
6
|
-
|
|
14
|
+
/**
|
|
15
|
+
* List the company's outlets.
|
|
16
|
+
*
|
|
17
|
+
* ON A STOREFRONT this is the pickup picker's source. Each outlet carries
|
|
18
|
+
* `connected`, and an outlet with `connected: false` cannot take a payment, so
|
|
19
|
+
* `setOutlet` refuses it — filter those out rather than relying on the refusal.
|
|
20
|
+
*
|
|
21
|
+
* There are no coordinates on an outlet, so "closest branch" is not something
|
|
22
|
+
* this can answer; sort on the address fields or let the shopper choose.
|
|
23
|
+
*/
|
|
24
|
+
export type GetOutlets = (params?: GetOutletsParams) => Promise<GetOutletsResponse>;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { SetOutlet } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Standalone mock of switching location.
|
|
4
|
+
*
|
|
5
|
+
* It mirrors the two REFUSALS the real command makes — a missing id, and an
|
|
6
|
+
* outlet that cannot take a payment — because those are the mistakes a builder
|
|
7
|
+
* actually hits. A mock that accepted anything would let a location picker look
|
|
8
|
+
* finished and then strand a shopper at a dead payment step on the real site.
|
|
9
|
+
*
|
|
10
|
+
* The unconnected id comes from the `getOutlets` mock rather than being repeated
|
|
11
|
+
* here, so the two cannot drift into telling different stories.
|
|
12
|
+
*/
|
|
13
|
+
export declare const mockSetOutlet: SetOutlet;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { MOCK_UNCONNECTED_OUTLET_ID } from '../get-outlets/mock';
|
|
2
|
+
/**
|
|
3
|
+
* Standalone mock of switching location.
|
|
4
|
+
*
|
|
5
|
+
* It mirrors the two REFUSALS the real command makes — a missing id, and an
|
|
6
|
+
* outlet that cannot take a payment — because those are the mistakes a builder
|
|
7
|
+
* actually hits. A mock that accepted anything would let a location picker look
|
|
8
|
+
* finished and then strand a shopper at a dead payment step on the real site.
|
|
9
|
+
*
|
|
10
|
+
* The unconnected id comes from the `getOutlets` mock rather than being repeated
|
|
11
|
+
* here, so the two cannot drift into telling different stories.
|
|
12
|
+
*/
|
|
13
|
+
export const mockSetOutlet = async (params) => {
|
|
14
|
+
console.log('[Mock] setOutlet called', params);
|
|
15
|
+
if (!params)
|
|
16
|
+
throw new Error('Params required');
|
|
17
|
+
if (!params.outletId || !params.outletId.trim()) {
|
|
18
|
+
throw new Error('setOutlet: outletId is required');
|
|
19
|
+
}
|
|
20
|
+
if (params.outletId === MOCK_UNCONNECTED_OUTLET_ID) {
|
|
21
|
+
throw new Error(`setOutlet: outlet ${params.outletId} cannot take an online payment — offer only outlets with connected: true`);
|
|
22
|
+
}
|
|
23
|
+
return { outletId: params.outletId, rehydrated: true, timestamp: new Date().toISOString() };
|
|
24
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export interface SetOutletParams {
|
|
2
|
+
/** An `id` from `getOutlets`. */
|
|
3
|
+
outletId: string;
|
|
4
|
+
}
|
|
5
|
+
export interface SetOutletResponse {
|
|
6
|
+
/** The location now in effect. */
|
|
7
|
+
outletId: string;
|
|
8
|
+
/**
|
|
9
|
+
* `true` when the catalog and tax tables were re-pulled for this location.
|
|
10
|
+
*
|
|
11
|
+
* `false` means the switch took effect but the refresh could not reach the
|
|
12
|
+
* server — the shop is running on what it already had cached. Totals may be
|
|
13
|
+
* the previous location's until the next refresh pass lands, so a flow can
|
|
14
|
+
* tell the shopper to try again rather than quietly showing stale tax.
|
|
15
|
+
*/
|
|
16
|
+
rehydrated: boolean;
|
|
17
|
+
timestamp: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Switch the shop to another of the company's locations.
|
|
21
|
+
*
|
|
22
|
+
* REFUSES AN OUTLET THAT CANNOT TAKE A PAYMENT, and one that does not belong to
|
|
23
|
+
* this company, rather than letting either fail later at the payment step. Check
|
|
24
|
+
* `connected` from `getOutlets` and do not offer those, so this refusal is a
|
|
25
|
+
* backstop rather than something a shopper ever sees.
|
|
26
|
+
*
|
|
27
|
+
* The cart survives the switch. Its lines are kept and re-priced; a line that is
|
|
28
|
+
* not purchasable at the new location is not silently dropped here, it is
|
|
29
|
+
* reported when the checkout is next priced.
|
|
30
|
+
*/
|
|
31
|
+
export type SetOutlet = (params: SetOutletParams) => Promise<SetOutletResponse>;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// Set Outlet Types
|
|
2
|
+
//
|
|
3
|
+
// Choose which of the company's locations this shop is ordering from.
|
|
4
|
+
//
|
|
5
|
+
// WHAT IT ACTUALLY CHANGES. An outlet decides three things, and a shop that lets
|
|
6
|
+
// a shopper pick one has to move all three together:
|
|
7
|
+
//
|
|
8
|
+
// tax rates follow the outlet's own address, so the total moves
|
|
9
|
+
// availability stock is counted per location, and a product can be hidden at one
|
|
10
|
+
// fulfilment the order records where the goods come from, so the right
|
|
11
|
+
// location's stock is the one that is drawn down
|
|
12
|
+
//
|
|
13
|
+
// So this is not a display preference. It re-pulls the catalog for the new
|
|
14
|
+
// location, re-hydrates the tax tables, and re-prices the cart. The totals a
|
|
15
|
+
// flow reads afterwards are the new location's.
|
|
16
|
+
//
|
|
17
|
+
// SAFE MID-CHECKOUT. Checkout starts when a shopper ARRIVES, so by the time
|
|
18
|
+
// anyone changes their mind an order usually already exists. That order is
|
|
19
|
+
// re-priced and moved to the new outlet in place, keeping its id and its receipt
|
|
20
|
+
// id, rather than being abandoned and replaced.
|
|
21
|
+
export {};
|
package/dist/index.d.ts
CHANGED
|
@@ -47,6 +47,7 @@ export declare const command: {
|
|
|
47
47
|
readonly chargeMoto: import(".").ChargeMoto;
|
|
48
48
|
readonly startCheckout: import(".").StartCheckout;
|
|
49
49
|
readonly attachCheckoutContact: import(".").AttachCheckoutContact;
|
|
50
|
+
readonly setOutlet: import(".").SetOutlet;
|
|
50
51
|
readonly resumeCheckout: import(".").ResumeCheckout;
|
|
51
52
|
readonly addCustomerNote: import(".").AddCustomerNote;
|
|
52
53
|
readonly removeCustomerNote: import(".").RemoveCustomerNote;
|
|
@@ -136,7 +137,7 @@ export type { AddProduct, AddProductParams, AddProductResponse } from './actions
|
|
|
136
137
|
export type { EditProduct, EditProductParams, EditProductResponse } from './actions/edit-product/types';
|
|
137
138
|
export type { EditProductVariants, EditProductVariantsParams, EditProductVariantsResponse, } from './actions/edit-product-variants/types';
|
|
138
139
|
export type { DeleteProduct, DeleteProductParams, DeleteProductResponse } from './actions/delete-product/types';
|
|
139
|
-
export type { GetOutlets, GetOutletsResponse } from './actions/get-outlets/types';
|
|
140
|
+
export type { GetOutlets, GetOutletsParams, GetOutletsResponse } from './actions/get-outlets/types';
|
|
140
141
|
export type { GetStations, GetStationsParams, GetStationsResponse } from './actions/get-stations/types';
|
|
141
142
|
export type { GetSmartGridLayout, GetSmartGridLayoutParams, GetSmartGridLayoutResponse, } from './actions/get-smart-grid-layout/types';
|
|
142
143
|
export type { SaveSmartGridLayout, SaveSmartGridLayoutParams, SaveSmartGridLayoutResponse, } from './actions/save-smart-grid-layout/types';
|
|
@@ -187,6 +188,7 @@ export type { CreatePaymentLink, CreatePaymentLinkParams, CreatePaymentLinkRespo
|
|
|
187
188
|
export type { ChargeMoto, ChargeMotoParams, ChargeMotoResponse, ChargeMotoCardFields, } from './actions/charge-moto/types';
|
|
188
189
|
export type { StartCheckout, StartCheckoutParams, StartCheckoutResponse, StartCheckoutContact, StartCheckoutOrder, } from './actions/start-checkout/types';
|
|
189
190
|
export type { AttachCheckoutContact, AttachCheckoutContactParams, AttachCheckoutContactResponse, } from './actions/attach-checkout-contact/types';
|
|
191
|
+
export type { SetOutlet, SetOutletParams, SetOutletResponse } from './actions/set-outlet/types';
|
|
190
192
|
export type { ResumeCheckout, ResumeCheckoutParams, ResumeCheckoutResponse, ResumeCheckoutResult, } from './actions/resume-checkout/types';
|
|
191
193
|
export type { AddCustomerNote, AddCustomerNoteParams, AddCustomerNoteResponse, } from './actions/add-customer-note/types';
|
|
192
194
|
export type { RemoveCustomerNote, RemoveCustomerNoteParams, RemoveCustomerNoteResponse, } from './actions/remove-customer-note/types';
|
package/dist/index.js
CHANGED
|
@@ -47,6 +47,7 @@ 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
49
|
import { attachCheckoutContact } from './actions/attach-checkout-contact/action';
|
|
50
|
+
import { setOutlet } from './actions/set-outlet/action';
|
|
50
51
|
import { resumeCheckout } from './actions/resume-checkout/action';
|
|
51
52
|
// Customer Actions
|
|
52
53
|
import { addCustomerNote } from './actions/add-customer-note/action';
|
|
@@ -189,6 +190,7 @@ export const command = {
|
|
|
189
190
|
chargeMoto,
|
|
190
191
|
startCheckout,
|
|
191
192
|
attachCheckoutContact,
|
|
193
|
+
setOutlet,
|
|
192
194
|
resumeCheckout,
|
|
193
195
|
// Customer Actions
|
|
194
196
|
addCustomerNote,
|
|
@@ -35,6 +35,8 @@ 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
37
|
import { mockAttachCheckoutContact } from '../../actions/attach-checkout-contact/mock';
|
|
38
|
+
import { mockGetOutlets } from '../../actions/get-outlets/mock';
|
|
39
|
+
import { mockSetOutlet } from '../../actions/set-outlet/mock';
|
|
38
40
|
import { mockResumeCheckout } from '../../actions/resume-checkout/mock';
|
|
39
41
|
import { mockGetTimeClockStatus } from '../../actions/get-time-clock-status/mock';
|
|
40
42
|
import { mockClearCart } from '../../actions/clear-cart/mock';
|
|
@@ -137,6 +139,8 @@ export const RENDER_MOCKS = {
|
|
|
137
139
|
chargeMoto: mockChargeMoto,
|
|
138
140
|
startCheckout: mockStartCheckout,
|
|
139
141
|
attachCheckoutContact: mockAttachCheckoutContact,
|
|
142
|
+
getOutlets: mockGetOutlets,
|
|
143
|
+
setOutlet: mockSetOutlet,
|
|
140
144
|
resumeCheckout: mockResumeCheckout,
|
|
141
145
|
clearCart: mockClearCart,
|
|
142
146
|
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, AttachCheckoutContact, 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, GetOutlets, SetOutlet, ResumeCheckout, GetTimeClockStatus } from '../../index';
|
|
2
2
|
export interface RenderProviderActions {
|
|
3
3
|
exampleFunction: ExampleFunction;
|
|
4
4
|
getProducts: GetProducts;
|
|
@@ -52,6 +52,8 @@ export interface RenderProviderActions {
|
|
|
52
52
|
*/
|
|
53
53
|
startCheckout: StartCheckout;
|
|
54
54
|
attachCheckoutContact: AttachCheckoutContact;
|
|
55
|
+
getOutlets: GetOutlets;
|
|
56
|
+
setOutlet: SetOutlet;
|
|
55
57
|
/**
|
|
56
58
|
* The RETURN LEG of an online checkout, after a redirect payment method or
|
|
57
59
|
* 3-D Secure sent the shopper away and back. Storefront-only, like
|