@final-commerce/command-frame 0.8.1-online.1 → 0.9.0-preprod.2
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 +4 -15
- package/dist/actions/adjust-inventory/mock.js +20 -0
- package/dist/actions/adjust-inventory/types.d.ts +13 -0
- package/dist/actions/adjust-inventory/types.js +1 -0
- package/dist/actions/assign-order-user/action.d.ts +6 -0
- package/dist/actions/assign-order-user/action.js +8 -0
- package/dist/actions/assign-order-user/mock.d.ts +2 -0
- package/dist/actions/assign-order-user/mock.js +30 -0
- package/dist/actions/assign-order-user/types.d.ts +15 -0
- package/dist/actions/get-custom-stock-actions/action.d.ts +5 -0
- package/dist/actions/get-custom-stock-actions/action.js +7 -0
- package/dist/actions/get-custom-stock-actions/mock.d.ts +2 -0
- package/dist/actions/get-custom-stock-actions/mock.js +11 -0
- package/dist/actions/get-custom-stock-actions/types.d.ts +12 -0
- package/dist/actions/get-custom-stock-actions/types.js +2 -0
- package/dist/actions/get-order-statuses/action.d.ts +6 -0
- package/dist/actions/get-order-statuses/action.js +8 -0
- package/dist/actions/get-order-statuses/mock.d.ts +2 -0
- package/dist/actions/get-order-statuses/mock.js +5 -0
- package/dist/actions/get-order-statuses/types.d.ts +8 -0
- package/dist/actions/get-orders/action.d.ts +1 -1
- package/dist/actions/get-orders/action.js +2 -2
- package/dist/actions/get-orders/mock.d.ts +1 -1
- package/dist/actions/get-orders/mock.js +49 -19
- package/dist/actions/get-orders/types.d.ts +21 -1
- package/dist/actions/get-outlets/action.js +2 -2
- package/dist/actions/get-outlets/mock.d.ts +0 -12
- package/dist/actions/get-outlets/mock.js +4 -28
- package/dist/actions/get-outlets/types.d.ts +1 -19
- package/dist/actions/record-external-payment/action.d.ts +6 -0
- package/dist/actions/record-external-payment/action.js +8 -0
- package/dist/actions/record-external-payment/mock.d.ts +2 -0
- package/dist/actions/record-external-payment/mock.js +36 -0
- package/dist/actions/record-external-payment/types.d.ts +37 -0
- package/dist/actions/release-from-cart/action.d.ts +6 -0
- package/dist/actions/release-from-cart/action.js +8 -0
- package/dist/actions/release-from-cart/mock.d.ts +2 -0
- package/dist/actions/release-from-cart/mock.js +26 -0
- package/dist/actions/release-from-cart/types.d.ts +8 -0
- package/dist/actions/release-from-cart/types.js +1 -0
- package/dist/actions/resume-order/action.d.ts +6 -0
- package/dist/actions/resume-order/action.js +8 -0
- package/dist/actions/resume-order/mock.d.ts +2 -0
- package/dist/actions/resume-order/mock.js +55 -0
- package/dist/actions/resume-order/types.d.ts +17 -0
- package/dist/actions/resume-order/types.js +1 -0
- package/dist/actions/resume-parked-order/mock.d.ts +6 -1
- package/dist/actions/resume-parked-order/mock.js +32 -31
- package/dist/actions/set-order-metadata/action.d.ts +6 -0
- package/dist/actions/set-order-metadata/action.js +8 -0
- package/dist/actions/set-order-metadata/mock.d.ts +5 -0
- package/dist/actions/set-order-metadata/mock.js +38 -0
- package/dist/actions/set-order-metadata/types.d.ts +20 -0
- package/dist/actions/set-order-metadata/types.js +1 -0
- package/dist/actions/set-order-status/action.d.ts +6 -0
- package/dist/actions/set-order-status/action.js +8 -0
- package/dist/actions/set-order-status/mock.d.ts +3 -0
- package/dist/actions/set-order-status/mock.js +39 -0
- package/dist/actions/set-order-status/types.d.ts +20 -0
- package/dist/actions/set-order-status/types.js +1 -0
- package/dist/actions/set-order-type/action.d.ts +6 -0
- package/dist/actions/set-order-type/action.js +8 -0
- package/dist/actions/set-order-type/mock.d.ts +3 -0
- package/dist/actions/set-order-type/mock.js +27 -0
- package/dist/actions/set-order-type/types.d.ts +17 -0
- package/dist/actions/set-order-type/types.js +1 -0
- package/dist/common-types/order-state.d.ts +15 -1
- package/dist/demo/database.d.ts +4 -0
- package/dist/demo/database.js +11 -0
- package/dist/index.d.ts +20 -12
- package/dist/index.js +18 -9
- package/dist/projects/render/mocks.js +18 -10
- package/dist/projects/render/types.d.ts +10 -16
- package/dist/pubsub/topics/index.d.ts +17 -18
- package/dist/pubsub/topics/index.js +17 -18
- package/dist/pubsub/topics/types.d.ts +0 -8
- package/package.json +2 -2
- package/dist/actions/attach-checkout-contact/action.d.ts +0 -6
- package/dist/actions/attach-checkout-contact/action.js +0 -8
- package/dist/actions/attach-checkout-contact/mock.d.ts +0 -15
- package/dist/actions/attach-checkout-contact/mock.js +0 -22
- package/dist/actions/attach-checkout-contact/types.d.ts +0 -35
- package/dist/actions/attach-checkout-contact/types.js +0 -16
- package/dist/actions/resume-checkout/action.d.ts +0 -6
- package/dist/actions/resume-checkout/action.js +0 -8
- package/dist/actions/resume-checkout/mock.d.ts +0 -16
- package/dist/actions/resume-checkout/mock.js +0 -51
- package/dist/actions/resume-checkout/types.d.ts +0 -59
- package/dist/actions/resume-checkout/types.js +0 -13
- package/dist/actions/set-outlet/action.d.ts +0 -6
- package/dist/actions/set-outlet/action.js +0 -8
- package/dist/actions/set-outlet/mock.d.ts +0 -13
- package/dist/actions/set-outlet/mock.js +0 -24
- package/dist/actions/set-outlet/types.d.ts +0 -31
- package/dist/actions/set-outlet/types.js +0 -21
- package/dist/actions/start-checkout/action.d.ts +0 -6
- package/dist/actions/start-checkout/action.js +0 -8
- package/dist/actions/start-checkout/mock.d.ts +0 -16
- package/dist/actions/start-checkout/mock.js +0 -80
- package/dist/actions/start-checkout/types.d.ts +0 -90
- package/dist/actions/start-checkout/types.js +0 -10
- package/dist/pubsub/topics/checkout/checkout-started/types.d.ts +0 -26
- package/dist/pubsub/topics/checkout/index.d.ts +0 -7
- package/dist/pubsub/topics/checkout/index.js +0 -28
- package/dist/pubsub/topics/checkout/payment-completed/types.d.ts +0 -31
- package/dist/pubsub/topics/checkout/payment-failed/types.d.ts +0 -20
- package/dist/pubsub/topics/checkout/types.d.ts +0 -12
- package/dist/pubsub/topics/checkout/types.js +0 -8
- /package/dist/{pubsub/topics/checkout/checkout-started → actions/assign-order-user}/types.js +0 -0
- /package/dist/{pubsub/topics/checkout/payment-completed → actions/get-order-statuses}/types.js +0 -0
- /package/dist/{pubsub/topics/checkout/payment-failed → actions/record-external-payment}/types.js +0 -0
package/dist/CommonTypes.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export * from './common-types';
|
|
2
|
-
import type { Tax, Tip, Address, MetadataItem, PosDataItem, CartFeeTaxEntry, CartFeeItem, CartDiscountItem, OrderNote, NonRevenueItem, DiscountDetail, FeeDetail, DiscountLineItem, FeeLineItem, LineItem, TipPayment, RefundedTipPayment, PaymentMethod, Discount, CustomFee, Summary, CustomSale, RefundedCustomSale, RefundItem, RefundedLineItem, ActiveStation, ActiveSession, ActiveOutlet, ActiveUser, ActiveUserRole, ActiveOrder, ActiveCart, ActivePark, ActiveCompany, ActiveCustomSales, ActiveProduct, ActiveCustomer, FullProduct, ProductVariant, Inventory, ResolvedModifier, ResolvedModifierChoice, ModifierSelectionType, ModifierSelection, ModifierChoiceSelection, CartLineModifier, ProdModifierBreakdown, OrderLineItemModifier, CustomerNote, Attribute, AttributeOption, Category, Transaction, ActiveSplitPayment, BookingAvailability, BookingSlot, BookingSlotResource, BookingResource, Booking, CartReservation, OrderReservation } from '@final-commerce/common/pos-types';
|
|
2
|
+
import type { Tax, Tip, Address, MetadataItem, OrderAssignedUser, OrderInCart, OrderCustomStatus, PosDataItem, CartFeeTaxEntry, CartFeeItem, CartDiscountItem, OrderNote, NonRevenueItem, DiscountDetail, FeeDetail, DiscountLineItem, FeeLineItem, LineItem, TipPayment, RefundedTipPayment, PaymentMethod, Discount, CustomFee, Summary, CustomSale, RefundedCustomSale, RefundItem, RefundedLineItem, ActiveStation, ActiveSession, ActiveOutlet, ActiveUser, ActiveUserRole, ActiveOrder, ActiveCart, ActivePark, ActiveCompany, ActiveCustomSales, ActiveProduct, ActiveCustomer, FullProduct, ProductVariant, Inventory, ResolvedModifier, ResolvedModifierChoice, ModifierSelectionType, ModifierSelection, ModifierChoiceSelection, CartLineModifier, ProdModifierBreakdown, OrderLineItemModifier, CustomerNote, Attribute, AttributeOption, Category, Transaction, ActiveSplitPayment, BookingAvailability, BookingSlot, BookingSlotResource, BookingResource, Booking, CartReservation, OrderReservation } from '@final-commerce/common/pos-types';
|
|
3
3
|
export { CurrencyCode, ProductType as CFProductType, UserTypes as CFUserTypes } from '@final-commerce/common';
|
|
4
4
|
/** Open record used as a base for active entities. */
|
|
5
5
|
export type CFActiveEntity = Record<string, unknown>;
|
|
@@ -7,6 +7,9 @@ export type CFDiscount = Discount;
|
|
|
7
7
|
export type CFCustomFee = CustomFee;
|
|
8
8
|
export type CFAddress = Address;
|
|
9
9
|
export type CFMetadataItem = MetadataItem;
|
|
10
|
+
export type CFOrderAssignedUser = OrderAssignedUser;
|
|
11
|
+
export type CFOrderInCart = OrderInCart;
|
|
12
|
+
export type CFOrderCustomStatus = OrderCustomStatus;
|
|
10
13
|
export type CFTax = Tax;
|
|
11
14
|
export type CFCartFeeTaxEntry = CartFeeTaxEntry;
|
|
12
15
|
export type CFInventory = Inventory;
|
|
@@ -181,23 +184,9 @@ export interface CFOutletInfo {
|
|
|
181
184
|
state?: string;
|
|
182
185
|
postCode?: string;
|
|
183
186
|
};
|
|
184
|
-
address2?: string;
|
|
185
187
|
city?: string;
|
|
186
188
|
state?: string;
|
|
187
189
|
country?: string;
|
|
188
|
-
postCode?: string;
|
|
189
|
-
phone?: string;
|
|
190
|
-
/** Short display alias, when the merchant set one (e.g. `DTWN`). */
|
|
191
|
-
alias?: string;
|
|
192
|
-
/**
|
|
193
|
-
* Whether this location can take an ONLINE payment. Storefront only — it is
|
|
194
|
-
* absent on a register, where it has no meaning.
|
|
195
|
-
*
|
|
196
|
-
* `false` means the outlet has no completed payment connection, so starting a
|
|
197
|
-
* checkout against it WILL fail. A pickup picker must not offer it as a
|
|
198
|
-
* selectable location, or must show it as unavailable.
|
|
199
|
-
*/
|
|
200
|
-
connected?: boolean;
|
|
201
190
|
}
|
|
202
191
|
export interface CFContextManage {
|
|
203
192
|
user: unknown;
|
|
@@ -1,6 +1,26 @@
|
|
|
1
1
|
import { MOCK_PRODUCTS } from '../../demo/database';
|
|
2
|
+
// Same rules and messages as the kaching handler.
|
|
3
|
+
const STOCK_TYPE_BY_REASON = {
|
|
4
|
+
STOCK_RECEIVED: 'add',
|
|
5
|
+
RESTOCK_RETURN: 'add',
|
|
6
|
+
DAMAGE: 'subtract',
|
|
7
|
+
THEFT: 'subtract',
|
|
8
|
+
LOSS: 'subtract',
|
|
9
|
+
INVENTORY_RECOUNT: 'set',
|
|
10
|
+
};
|
|
2
11
|
export const mockAdjustInventory = async (params) => {
|
|
3
12
|
console.log('[Mock] adjustInventory called', params);
|
|
13
|
+
if (params?.specificAction != null) {
|
|
14
|
+
const { specificAction, stockType, customActionId } = params;
|
|
15
|
+
if (customActionId)
|
|
16
|
+
throw new Error('Pass either customActionId or specificAction, not both');
|
|
17
|
+
const reasonStockType = STOCK_TYPE_BY_REASON[specificAction];
|
|
18
|
+
if (!reasonStockType)
|
|
19
|
+
throw new Error(`Unknown specificAction: ${specificAction}`);
|
|
20
|
+
if (reasonStockType !== stockType) {
|
|
21
|
+
throw new Error(`specificAction ${specificAction} requires stockType '${reasonStockType}', got '${stockType}'`);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
4
24
|
let newStock = 0;
|
|
5
25
|
// Real handler keys off variantId (falling back to the active product's
|
|
6
26
|
// variant); mirror that here by finding the owning product for the variant.
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
/** The manual reasons a person can pick, as hub-api's InventorySpecificActionType names them. */
|
|
2
|
+
export type ManualStockReason = 'STOCK_RECEIVED' | 'RESTOCK_RETURN' | 'DAMAGE' | 'THEFT' | 'LOSS' | 'INVENTORY_RECOUNT';
|
|
1
3
|
export interface AdjustInventoryParams {
|
|
2
4
|
/** String to preserve precision. */
|
|
3
5
|
amount: string;
|
|
@@ -5,6 +7,17 @@ export interface AdjustInventoryParams {
|
|
|
5
7
|
stockType: 'add' | 'subtract' | 'set';
|
|
6
8
|
/** Variant to adjust. Omit to use the active product's selected variant. */
|
|
7
9
|
variantId?: string;
|
|
10
|
+
/**
|
|
11
|
+
* A company action from getCustomStockActions. The movement is recorded under its name;
|
|
12
|
+
* `stockType` must match its baseAction (ADD → 'add', REMOVE → 'subtract', RECOUNT → 'set').
|
|
13
|
+
*/
|
|
14
|
+
customActionId?: string;
|
|
15
|
+
/**
|
|
16
|
+
* A built-in reason to record instead of the host's default for `stockType`. Must match it:
|
|
17
|
+
* STOCK_RECEIVED / RESTOCK_RETURN → 'add', DAMAGE / THEFT / LOSS → 'subtract', INVENTORY_RECOUNT → 'set'.
|
|
18
|
+
* Rejected together with `customActionId`.
|
|
19
|
+
*/
|
|
20
|
+
specificAction?: ManualStockReason;
|
|
8
21
|
}
|
|
9
22
|
export interface AdjustInventoryResponse {
|
|
10
23
|
success: boolean;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Assign order user action
|
|
3
|
+
* Calls the assignOrderUser action on the parent window
|
|
4
|
+
*/
|
|
5
|
+
import { commandFrameClient } from '../../client';
|
|
6
|
+
export const assignOrderUser = async (params) => {
|
|
7
|
+
return await commandFrameClient.call('assignOrderUser', params);
|
|
8
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { MOCK_ORDERS, MOCK_PARKED_ORDERS, MOCK_USERS, mockPublishEvent } from '../../demo/database';
|
|
2
|
+
export const mockAssignOrderUser = async (params) => {
|
|
3
|
+
console.log('[Mock] assignOrderUser called', params);
|
|
4
|
+
if (!params?.orderId) {
|
|
5
|
+
throw new Error('assignOrderUser: the demo has no live-cart order — pass an orderId');
|
|
6
|
+
}
|
|
7
|
+
if (params.userId !== null && typeof params.userId !== 'string') {
|
|
8
|
+
throw new Error('assignOrderUser: userId must be a user id or null');
|
|
9
|
+
}
|
|
10
|
+
const order = [...MOCK_ORDERS, ...MOCK_PARKED_ORDERS].find((o) => o._id === params.orderId);
|
|
11
|
+
if (!order) {
|
|
12
|
+
throw new Error(`Order with ID ${params.orderId} not found`);
|
|
13
|
+
}
|
|
14
|
+
if (params.userId === null) {
|
|
15
|
+
order.assignedUser = null;
|
|
16
|
+
}
|
|
17
|
+
else if (order.assignedUser?.userId !== params.userId) {
|
|
18
|
+
if (!MOCK_USERS.some((u) => u.id === params.userId)) {
|
|
19
|
+
throw new Error(`User with ID ${params.userId} not found`);
|
|
20
|
+
}
|
|
21
|
+
order.assignedUser = { userId: params.userId, assignedAt: new Date().toISOString() };
|
|
22
|
+
}
|
|
23
|
+
mockPublishEvent('orders', 'order-updated', { order });
|
|
24
|
+
return {
|
|
25
|
+
success: true,
|
|
26
|
+
orderId: order._id,
|
|
27
|
+
assignedUser: order.assignedUser ?? null,
|
|
28
|
+
timestamp: new Date().toISOString(),
|
|
29
|
+
};
|
|
30
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { CFOrderAssignedUser } from '../../CommonTypes';
|
|
2
|
+
export interface AssignOrderUserParams {
|
|
3
|
+
/** Order to assign. Omit to target the live cart's order — it must already exist (parked, paid or transitioned). */
|
|
4
|
+
orderId?: string;
|
|
5
|
+
/** User to assign (e.g. the driver), or null to unassign. Replaces any current assignee. */
|
|
6
|
+
userId: string | null;
|
|
7
|
+
}
|
|
8
|
+
export interface AssignOrderUserResponse {
|
|
9
|
+
success: boolean;
|
|
10
|
+
orderId: string;
|
|
11
|
+
/** The order's assignee after the call; null when unassigned. */
|
|
12
|
+
assignedUser: CFOrderAssignedUser | null;
|
|
13
|
+
timestamp: string;
|
|
14
|
+
}
|
|
15
|
+
export type AssignOrderUser = (params: AssignOrderUserParams) => Promise<AssignOrderUserResponse>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export const mockGetCustomStockActions = async () => {
|
|
2
|
+
console.log('[Mock] getCustomStockActions called');
|
|
3
|
+
return {
|
|
4
|
+
customStockActions: [
|
|
5
|
+
{ _id: 'mock_custom_action_1', name: 'Opening stock', baseAction: 'ADD' },
|
|
6
|
+
{ _id: 'mock_custom_action_2', name: 'Exhibition loan', baseAction: 'REMOVE' },
|
|
7
|
+
{ _id: 'mock_custom_action_3', name: 'Year-end count', baseAction: 'RECOUNT' },
|
|
8
|
+
],
|
|
9
|
+
timestamp: new Date().toISOString(),
|
|
10
|
+
};
|
|
11
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export interface CustomStockActionPayload {
|
|
2
|
+
_id: string;
|
|
3
|
+
/** Name the company gave the action, shown in pickers and stock history. */
|
|
4
|
+
name: string;
|
|
5
|
+
/** What the action does to stock — pass the matching `stockType` to adjustInventory. */
|
|
6
|
+
baseAction: 'ADD' | 'REMOVE' | 'RECOUNT';
|
|
7
|
+
}
|
|
8
|
+
export interface GetCustomStockActionsResponse {
|
|
9
|
+
customStockActions: CustomStockActionPayload[];
|
|
10
|
+
timestamp: string;
|
|
11
|
+
}
|
|
12
|
+
export type GetCustomStockActions = () => Promise<GetCustomStockActionsResponse>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Get order statuses action
|
|
3
|
+
* Calls the getOrderStatuses action on the parent window
|
|
4
|
+
*/
|
|
5
|
+
import { commandFrameClient } from '../../client';
|
|
6
|
+
export const getOrderStatuses = async () => {
|
|
7
|
+
return await commandFrameClient.call('getOrderStatuses', undefined);
|
|
8
|
+
};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { MOCK_ORDER_STATUSES } from '../../demo/database';
|
|
2
|
+
export const mockGetOrderStatuses = async () => {
|
|
3
|
+
console.log('[Mock] getOrderStatuses called');
|
|
4
|
+
return { success: true, statuses: MOCK_ORDER_STATUSES.map((s) => ({ ...s })), timestamp: new Date().toISOString() };
|
|
5
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { CFOrderStatusDefinition } from '../../common-types/order-state';
|
|
2
|
+
export interface GetOrderStatusesResponse {
|
|
3
|
+
success: boolean;
|
|
4
|
+
/** The company's order statuses, in the order they were defined. Empty when none are defined. */
|
|
5
|
+
statuses: CFOrderStatusDefinition[];
|
|
6
|
+
timestamp: string;
|
|
7
|
+
}
|
|
8
|
+
export type GetOrderStatuses = () => Promise<GetOrderStatusesResponse>;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Get orders action
|
|
3
3
|
* Calls the getOrders action on the parent window
|
|
4
4
|
*/
|
|
5
|
-
import { commandFrameClient } from
|
|
5
|
+
import { commandFrameClient } from '../../client';
|
|
6
6
|
export const getOrders = async (params) => {
|
|
7
|
-
return await commandFrameClient.call(
|
|
7
|
+
return await commandFrameClient.call('getOrders', params);
|
|
8
8
|
};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { GetOrders } from
|
|
1
|
+
import { GetOrders } from './types';
|
|
2
2
|
export declare const mockGetOrders: GetOrders;
|
|
@@ -1,26 +1,60 @@
|
|
|
1
|
-
import { MOCK_ORDERS, MOCK_PARKED_ORDERS, MOCK_USERS, MOCK_STATIONS, MOCK_OUTLETS, safeSerialize } from
|
|
1
|
+
import { MOCK_ORDERS, MOCK_PARKED_ORDERS, MOCK_USERS, MOCK_STATIONS, MOCK_OUTLETS, safeSerialize, } from '../../demo/database';
|
|
2
2
|
export const mockGetOrders = async (params) => {
|
|
3
|
-
console.log(
|
|
3
|
+
console.log('[Mock] getOrders called', params);
|
|
4
4
|
// Start with a safe copy of mock orders, including parked (status: "parked").
|
|
5
5
|
let orders = safeSerialize([...MOCK_ORDERS, ...MOCK_PARKED_ORDERS]);
|
|
6
6
|
// Filter simulation
|
|
7
7
|
if (params) {
|
|
8
|
-
const { customerId, status, sessionId, searchValue, limit, offset, sortBy, sortDirection } = params;
|
|
8
|
+
const { customerId, status, sessionId, paymentState, fulfillmentState, outletId, assignedUserId, inCart, orderType, customStatusId, searchValue, limit, offset, sortBy, sortDirection, } = params;
|
|
9
9
|
// 1. Filtering
|
|
10
10
|
if (customerId) {
|
|
11
|
-
orders = orders.filter(o => o.customer &&
|
|
12
|
-
'_id' in o.customer &&
|
|
13
|
-
o.customer._id === customerId);
|
|
11
|
+
orders = orders.filter((o) => o.customer && '_id' in o.customer && o.customer._id === customerId);
|
|
14
12
|
}
|
|
15
13
|
if (status) {
|
|
16
|
-
orders = orders.filter(o => o.status === status);
|
|
14
|
+
orders = orders.filter((o) => o.status === status);
|
|
17
15
|
}
|
|
18
16
|
if (sessionId) {
|
|
19
|
-
orders = orders.filter(o => o.sessionId === sessionId);
|
|
17
|
+
orders = orders.filter((o) => o.sessionId === sessionId);
|
|
18
|
+
}
|
|
19
|
+
const anyOf = (criteria, value) => criteria === undefined ||
|
|
20
|
+
(Array.isArray(criteria) ? criteria.length === 0 || criteria.includes(value ?? '') : criteria === value);
|
|
21
|
+
if (paymentState !== undefined) {
|
|
22
|
+
orders = orders.filter((o) => anyOf(paymentState, o.paymentState));
|
|
23
|
+
}
|
|
24
|
+
if (fulfillmentState !== undefined) {
|
|
25
|
+
orders = orders.filter((o) => anyOf(fulfillmentState, o.fulfillmentState));
|
|
26
|
+
}
|
|
27
|
+
if (outletId) {
|
|
28
|
+
orders = orders.filter((o) => o.posData?.outlet === outletId);
|
|
29
|
+
}
|
|
30
|
+
if (assignedUserId) {
|
|
31
|
+
orders = orders.filter((o) => o.assignedUser?.userId === assignedUserId);
|
|
32
|
+
}
|
|
33
|
+
else if (assignedUserId === null) {
|
|
34
|
+
orders = orders.filter((o) => o.assignedUser == null);
|
|
35
|
+
}
|
|
36
|
+
if (orderType !== undefined) {
|
|
37
|
+
const types = Array.isArray(orderType) ? orderType : [orderType];
|
|
38
|
+
if (types.length)
|
|
39
|
+
orders = orders.filter((o) => types.includes(o.orderType ?? ''));
|
|
40
|
+
}
|
|
41
|
+
if (customStatusId !== undefined) {
|
|
42
|
+
const ids = Array.isArray(customStatusId) ? customStatusId : [customStatusId];
|
|
43
|
+
if (ids.length)
|
|
44
|
+
orders = orders.filter((o) => !!o.customStatus && ids.includes(o.customStatus.id));
|
|
45
|
+
}
|
|
46
|
+
if (typeof inCart === 'boolean') {
|
|
47
|
+
// Mirrors common's isInCart: the flag when present, else the legacy reading.
|
|
48
|
+
const orderInCart = (o) => o.inCart != null
|
|
49
|
+
? o.inCart.active
|
|
50
|
+
: o.fulfillmentState
|
|
51
|
+
? o.fulfillmentState === 'draft'
|
|
52
|
+
: o.status === 'in-cart';
|
|
53
|
+
orders = orders.filter((o) => orderInCart(o) === inCart);
|
|
20
54
|
}
|
|
21
55
|
if (searchValue) {
|
|
22
56
|
const searchLower = String(searchValue).toLowerCase();
|
|
23
|
-
orders = orders.filter(o => {
|
|
57
|
+
orders = orders.filter((o) => {
|
|
24
58
|
const receiptMatch = o.receiptId?.toLowerCase().includes(searchLower);
|
|
25
59
|
const customerNameMatch = o.customer && 'firstName' in o.customer
|
|
26
60
|
? `${o.customer.firstName} ${o.customer.lastName}`.toLowerCase().includes(searchLower)
|
|
@@ -42,14 +76,10 @@ export const mockGetOrders = async (params) => {
|
|
|
42
76
|
if (!valB && sortBy === 'createdAt')
|
|
43
77
|
valB = b.createdAt || '';
|
|
44
78
|
if (typeof valA === 'string' && typeof valB === 'string') {
|
|
45
|
-
return sortDirection === 'descending'
|
|
46
|
-
? valB.localeCompare(valA)
|
|
47
|
-
: valA.localeCompare(valB);
|
|
79
|
+
return sortDirection === 'descending' ? valB.localeCompare(valA) : valA.localeCompare(valB);
|
|
48
80
|
}
|
|
49
81
|
// Number comparison
|
|
50
|
-
return sortDirection === 'descending'
|
|
51
|
-
? (valB || 0) - (valA || 0)
|
|
52
|
-
: (valA || 0) - (valB || 0);
|
|
82
|
+
return sortDirection === 'descending' ? (valB || 0) - (valA || 0) : (valA || 0) - (valB || 0);
|
|
53
83
|
});
|
|
54
84
|
}
|
|
55
85
|
else {
|
|
@@ -73,21 +103,21 @@ export const mockGetOrders = async (params) => {
|
|
|
73
103
|
if (enrichedOrder.posData) {
|
|
74
104
|
// Enrich Employee
|
|
75
105
|
if (typeof enrichedOrder.posData.employee === 'string') {
|
|
76
|
-
const employee = MOCK_USERS.find(u => u.id === enrichedOrder.posData.employee);
|
|
106
|
+
const employee = MOCK_USERS.find((u) => u.id === enrichedOrder.posData.employee);
|
|
77
107
|
if (employee) {
|
|
78
108
|
enrichedOrder.posData.employee = employee;
|
|
79
109
|
}
|
|
80
110
|
}
|
|
81
111
|
// Enrich Station
|
|
82
112
|
if (typeof enrichedOrder.posData.station === 'string') {
|
|
83
|
-
const station = MOCK_STATIONS.find(s => s._id === enrichedOrder.posData.station);
|
|
113
|
+
const station = MOCK_STATIONS.find((s) => s._id === enrichedOrder.posData.station);
|
|
84
114
|
if (station) {
|
|
85
115
|
enrichedOrder.posData.station = station;
|
|
86
116
|
}
|
|
87
117
|
}
|
|
88
118
|
// Enrich Outlet
|
|
89
119
|
if (typeof enrichedOrder.posData.outlet === 'string') {
|
|
90
|
-
const outlet = MOCK_OUTLETS.find(o => o.id === enrichedOrder.posData.outlet);
|
|
120
|
+
const outlet = MOCK_OUTLETS.find((o) => o.id === enrichedOrder.posData.outlet);
|
|
91
121
|
if (outlet) {
|
|
92
122
|
enrichedOrder.posData.outlet = outlet;
|
|
93
123
|
}
|
|
@@ -99,6 +129,6 @@ export const mockGetOrders = async (params) => {
|
|
|
99
129
|
success: true,
|
|
100
130
|
orders: enrichedOrders,
|
|
101
131
|
total: MOCK_ORDERS.length, // Total before pagination
|
|
102
|
-
timestamp: new Date().toISOString()
|
|
132
|
+
timestamp: new Date().toISOString(),
|
|
103
133
|
};
|
|
104
134
|
};
|
|
@@ -1,9 +1,29 @@
|
|
|
1
|
-
import { CFOrder } from
|
|
1
|
+
import { CFOrder } from '../../CommonTypes';
|
|
2
2
|
export interface GetOrdersParams {
|
|
3
3
|
/** e.g. 'completed', 'parked', 'refunded'. */
|
|
4
4
|
status?: string;
|
|
5
5
|
customerId?: string;
|
|
6
6
|
sessionId?: string;
|
|
7
|
+
/** Payment state(s), e.g. 'paid' or ['unpaid', 'partially_paid']. A list matches any of them. */
|
|
8
|
+
paymentState?: string | string[];
|
|
9
|
+
/** Fulfillment state(s), e.g. 'in_progress' or ['pending', 'in_progress']. A list matches any of them. */
|
|
10
|
+
fulfillmentState?: string | string[];
|
|
11
|
+
/** Only orders placed at this outlet (`posData.outlet`). Without it, orders from every outlet in the company are returned. */
|
|
12
|
+
outletId?: string;
|
|
13
|
+
/**
|
|
14
|
+
* Only orders assigned to this user (`assignedUser.userId`), e.g. a driver's deliveries.
|
|
15
|
+
* `null`: only orders nobody is assigned to yet (e.g. deliveries awaiting a driver).
|
|
16
|
+
*/
|
|
17
|
+
assignedUserId?: string | null;
|
|
18
|
+
/**
|
|
19
|
+
* true: only orders loaded in a cart; false: only orders that aren't. Reads `order.inCart` when the order
|
|
20
|
+
* carries it, otherwise the legacy reading (fulfillment 'draft' / status 'in-cart').
|
|
21
|
+
*/
|
|
22
|
+
inCart?: boolean;
|
|
23
|
+
/** Order type label(s) set with setOrderType, e.g. 'delivery' or ['pickup', 'takeout']. Exact match; a list matches any. */
|
|
24
|
+
orderType?: string | string[];
|
|
25
|
+
/** Custom status id(s) set with setOrderStatus, e.g. 'in-kitchen'. A list matches any of them. */
|
|
26
|
+
customStatusId?: string | string[];
|
|
7
27
|
/** Default: 50. */
|
|
8
28
|
limit?: number;
|
|
9
29
|
/** Default: 0. */
|
|
@@ -1,14 +1,2 @@
|
|
|
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";
|
|
14
2
|
export declare const mockGetOutlets: GetOutlets;
|
|
@@ -1,40 +1,16 @@
|
|
|
1
1
|
import { MOCK_OUTLETS, safeSerialize } from "../../demo/database";
|
|
2
|
-
|
|
3
|
-
|
|
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);
|
|
2
|
+
export const mockGetOutlets = async () => {
|
|
3
|
+
console.log("[Mock] getOutlets called");
|
|
26
4
|
const outlets = safeSerialize(MOCK_OUTLETS).map((o) => ({
|
|
27
5
|
_id: o._id || o.id,
|
|
28
6
|
name: o.name || "",
|
|
29
7
|
address: o.address,
|
|
30
8
|
city: o.city,
|
|
31
9
|
state: o.state,
|
|
32
|
-
country: o.country
|
|
33
|
-
connected: true
|
|
10
|
+
country: o.country
|
|
34
11
|
}));
|
|
35
|
-
const all = [...outlets, UNCONNECTED_OUTLET];
|
|
36
12
|
return {
|
|
37
|
-
outlets
|
|
13
|
+
outlets,
|
|
38
14
|
timestamp: new Date().toISOString()
|
|
39
15
|
};
|
|
40
16
|
};
|
|
@@ -1,24 +1,6 @@
|
|
|
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
|
-
}
|
|
10
2
|
export interface GetOutletsResponse {
|
|
11
3
|
outlets: CFOutletInfo[];
|
|
12
4
|
timestamp: string;
|
|
13
5
|
}
|
|
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>;
|
|
6
|
+
export type GetOutlets = () => Promise<GetOutletsResponse>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Record external payment action
|
|
3
|
+
* Calls the recordExternalPayment action on the parent window
|
|
4
|
+
*/
|
|
5
|
+
import { commandFrameClient } from '../../client';
|
|
6
|
+
export const recordExternalPayment = async (params) => {
|
|
7
|
+
return await commandFrameClient.call('recordExternalPayment', params);
|
|
8
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { isFulfillmentState } from '@final-commerce/common';
|
|
2
|
+
import { applyMockPayment, MOCK_CART } from '../../demo/database';
|
|
3
|
+
export const mockRecordExternalPayment = async (params) => {
|
|
4
|
+
console.log('[Mock] recordExternalPayment called', params);
|
|
5
|
+
const label = typeof params?.label === 'string' ? params.label.trim() : '';
|
|
6
|
+
if (!label) {
|
|
7
|
+
throw new Error('recordExternalPayment: label is required');
|
|
8
|
+
}
|
|
9
|
+
const balanceDue = MOCK_CART.amountToBeCharged ?? MOCK_CART.total;
|
|
10
|
+
const amount = params.amount ?? balanceDue;
|
|
11
|
+
// Same rule as the host: positive, except on a zero-balance checkout.
|
|
12
|
+
if (!Number.isFinite(amount) || amount < 0 || (amount === 0 && balanceDue > 0)) {
|
|
13
|
+
throw new Error('recordExternalPayment: amount must be a positive integer (minor units)');
|
|
14
|
+
}
|
|
15
|
+
const target = params.checkoutFulfillmentTarget;
|
|
16
|
+
if (target !== undefined && !isFulfillmentState(target)) {
|
|
17
|
+
throw new Error(`recordExternalPayment: invalid checkoutFulfillmentTarget "${String(target)}"`);
|
|
18
|
+
}
|
|
19
|
+
if (amount > balanceDue) {
|
|
20
|
+
throw new Error(`recordExternalPayment: amount ${amount} exceeds the balance due ${balanceDue}`);
|
|
21
|
+
}
|
|
22
|
+
const order = applyMockPayment(amount, 'external', label);
|
|
23
|
+
const remainingBalance = MOCK_CART.remainingBalance ?? 0;
|
|
24
|
+
return {
|
|
25
|
+
success: true,
|
|
26
|
+
amount,
|
|
27
|
+
label,
|
|
28
|
+
paymentType: 'external',
|
|
29
|
+
change: 0,
|
|
30
|
+
cashRounding: 0,
|
|
31
|
+
order,
|
|
32
|
+
saleFinalized: !!order,
|
|
33
|
+
remainingBalance: order ? 0 : remainingBalance,
|
|
34
|
+
timestamp: new Date().toISOString(),
|
|
35
|
+
};
|
|
36
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { CFOrder } from '../../CommonTypes';
|
|
2
|
+
export interface RecordExternalPaymentParams {
|
|
3
|
+
/**
|
|
4
|
+
* What the payment was — shown on the order and in reports, e.g. 'Paid online',
|
|
5
|
+
* 'Uber Eats', 'Voucher'. Required; trimmed. Not checked against a list, so keep
|
|
6
|
+
* labels consistent across flows.
|
|
7
|
+
*/
|
|
8
|
+
label: string;
|
|
9
|
+
/**
|
|
10
|
+
* Amount to record, in integer MINOR currency units. Omit to record the full balance
|
|
11
|
+
* due (completing the order). Below the balance due it records a partial payment —
|
|
12
|
+
* the rest can be taken with any other tender. Above the balance due is an error.
|
|
13
|
+
*/
|
|
14
|
+
amount?: number;
|
|
15
|
+
/** Fulfillment state to land on after full payment, e.g. 'pending' to keep the order going to the kitchen. */
|
|
16
|
+
checkoutFulfillmentTarget?: string;
|
|
17
|
+
}
|
|
18
|
+
export interface RecordExternalPaymentResponse {
|
|
19
|
+
success: boolean;
|
|
20
|
+
/** The amount recorded, in integer MINOR currency units. */
|
|
21
|
+
amount: number;
|
|
22
|
+
/** The label, as recorded. */
|
|
23
|
+
label: string;
|
|
24
|
+
paymentType: 'external';
|
|
25
|
+
/** Always 0 — no money changes hands at the terminal. */
|
|
26
|
+
change: number;
|
|
27
|
+
/** Always 0 — cash rounding applies to cash only. */
|
|
28
|
+
cashRounding: number;
|
|
29
|
+
/** The order once the sale completes; null for a partial (split) leg. */
|
|
30
|
+
order: CFOrder | null;
|
|
31
|
+
/** True when this payment settled the remaining balance. */
|
|
32
|
+
saleFinalized: boolean;
|
|
33
|
+
/** Balance still due after this payment, in integer MINOR currency units. */
|
|
34
|
+
remainingBalance: number;
|
|
35
|
+
timestamp: string;
|
|
36
|
+
}
|
|
37
|
+
export type RecordExternalPayment = (params: RecordExternalPaymentParams) => Promise<RecordExternalPaymentResponse>;
|