@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.
@@ -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,4 +1,4 @@
1
1
  import { commandFrameClient } from "../../client";
2
- export const getOutlets = async () => {
3
- return await commandFrameClient.call("getOutlets");
2
+ export const getOutlets = async (params) => {
3
+ return await commandFrameClient.call("getOutlets", params ?? {});
4
4
  };
@@ -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
- export const mockGetOutlets = async () => {
3
- console.log("[Mock] getOutlets called");
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
- export type GetOutlets = () => Promise<GetOutletsResponse>;
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,6 @@
1
+ /**
2
+ * Set Outlet action
3
+ * Calls the setOutlet action on the parent window
4
+ */
5
+ import type { SetOutlet } from './types';
6
+ export declare const setOutlet: SetOutlet;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Set Outlet action
3
+ * Calls the setOutlet action on the parent window
4
+ */
5
+ import { commandFrameClient } from '../../client';
6
+ export const setOutlet = async (params) => {
7
+ return await commandFrameClient.call('setOutlet', params);
8
+ };
@@ -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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@final-commerce/command-frame",
3
- "version": "0.8.0-online.5",
3
+ "version": "0.8.0-online.6",
4
4
  "description": "Commands Frame library",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",