@aglyn/plugins-commerce 1.0.0-beta.232 → 1.0.0-beta.233
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/package.json +13 -13
- package/src/lib/components/cart-extras.d.ts +6 -0
- package/src/lib/components/cart-extras.js +4 -1
- package/src/lib/components/cart-extras.js.map +1 -1
- package/src/lib/components/cart-fulfillment.d.ts +117 -0
- package/src/lib/components/cart-fulfillment.js +367 -0
- package/src/lib/components/cart-fulfillment.js.map +1 -0
- package/src/lib/components/cart.js +52 -10
- package/src/lib/components/cart.js.map +1 -1
- package/src/lib/components/commerce-console-page.js +42 -1
- package/src/lib/components/commerce-console-page.js.map +1 -1
- package/src/lib/components/console/host-orders-card.component.js +38 -10
- package/src/lib/components/console/host-orders-card.component.js.map +1 -1
- package/src/lib/components/console/local-delivery-settings-card.component.d.ts +37 -0
- package/src/lib/components/console/local-delivery-settings-card.component.js +542 -0
- package/src/lib/components/console/local-delivery-settings-card.component.js.map +1 -0
- package/src/lib/components/console/locations-card.component.js +177 -3
- package/src/lib/components/console/locations-card.component.js.map +1 -1
- package/src/lib/components/console/order-detail-dialog.component.js +10 -0
- package/src/lib/components/console/order-detail-dialog.component.js.map +1 -1
- package/src/lib/components/console/order-local-fulfillment-panel.component.d.ts +44 -0
- package/src/lib/components/console/order-local-fulfillment-panel.component.js +265 -0
- package/src/lib/components/console/order-local-fulfillment-panel.component.js.map +1 -0
- package/src/lib/components/console/order-offline-notice.component.d.ts +12 -0
- package/src/lib/components/console/order-offline-notice.component.js +53 -0
- package/src/lib/components/console/order-offline-notice.component.js.map +1 -0
- package/src/lib/components/console/pickup-delivery-queue-card.component.d.ts +35 -0
- package/src/lib/components/console/pickup-delivery-queue-card.component.js +222 -0
- package/src/lib/components/console/pickup-delivery-queue-card.component.js.map +1 -0
- package/src/lib/components/console/pos/pos-api.d.ts +24 -1
- package/src/lib/components/console/pos/pos-api.js +13 -0
- package/src/lib/components/console/pos/pos-api.js.map +1 -1
- package/src/lib/components/console/pos/pos-item-dialog.component.d.ts +12 -0
- package/src/lib/components/console/pos/pos-item-dialog.component.js +10 -8
- package/src/lib/components/console/pos/pos-item-dialog.component.js.map +1 -1
- package/src/lib/components/console/pos/pos-kiosk-queue.component.d.ts +22 -0
- package/src/lib/components/console/pos/pos-kiosk-queue.component.js +168 -0
- package/src/lib/components/console/pos/pos-kiosk-queue.component.js.map +1 -0
- package/src/lib/components/console/pos/pos-tender-dialogs.component.d.ts +18 -0
- package/src/lib/components/console/pos/pos-tender-dialogs.component.js +116 -1
- package/src/lib/components/console/pos/pos-tender-dialogs.component.js.map +1 -1
- package/src/lib/components/console/pos/pos-tender-panel.component.d.ts +8 -0
- package/src/lib/components/console/pos/pos-tender-panel.component.js +77 -18
- package/src/lib/components/console/pos/pos-tender-panel.component.js.map +1 -1
- package/src/lib/components/console/pos/use-pos-display.d.ts +5 -2
- package/src/lib/components/console/pos/use-pos-display.js +3 -2
- package/src/lib/components/console/pos/use-pos-display.js.map +1 -1
- package/src/lib/components/console/pos-devices-card.component.js +2 -2
- package/src/lib/components/console/pos-devices-card.component.js.map +1 -1
- package/src/lib/components/console/pos-display/pairing-screen.d.ts +5 -2
- package/src/lib/components/console/pos-display/pairing-screen.js +7 -5
- package/src/lib/components/console/pos-display/pairing-screen.js.map +1 -1
- package/src/lib/components/console/pos-display/pos-display-api.d.ts +7 -1
- package/src/lib/components/console/pos-display/pos-display-api.js +7 -2
- package/src/lib/components/console/pos-display/pos-display-api.js.map +1 -1
- package/src/lib/components/console/pos-kiosk/kiosk-checkout.d.ts +41 -0
- package/src/lib/components/console/pos-kiosk/kiosk-checkout.js +275 -0
- package/src/lib/components/console/pos-kiosk/kiosk-checkout.js.map +1 -0
- package/src/lib/components/console/pos-kiosk/kiosk-menu.d.ts +32 -0
- package/src/lib/components/console/pos-kiosk/kiosk-menu.js +344 -0
- package/src/lib/components/console/pos-kiosk/kiosk-menu.js.map +1 -0
- package/src/lib/components/console/pos-kiosk/kiosk-staff.d.ts +12 -0
- package/src/lib/components/console/pos-kiosk/kiosk-staff.js +257 -0
- package/src/lib/components/console/pos-kiosk/kiosk-staff.js.map +1 -0
- package/src/lib/components/console/pos-kiosk/pos-kiosk-api.d.ts +114 -0
- package/src/lib/components/console/pos-kiosk/pos-kiosk-api.js +189 -0
- package/src/lib/components/console/pos-kiosk/pos-kiosk-api.js.map +1 -0
- package/src/lib/components/console/pos-kiosk/use-kiosk-idle.d.ts +16 -0
- package/src/lib/components/console/pos-kiosk/use-kiosk-idle.js +80 -0
- package/src/lib/components/console/pos-kiosk/use-kiosk-idle.js.map +1 -0
- package/src/lib/components/console/pos-kiosk-page.component.d.ts +28 -0
- package/src/lib/components/console/pos-kiosk-page.component.js +791 -0
- package/src/lib/components/console/pos-kiosk-page.component.js.map +1 -0
- package/src/lib/components/console/pos-offline/pos-offline-api.d.ts +44 -0
- package/src/lib/components/console/pos-offline/pos-offline-api.js +69 -0
- package/src/lib/components/console/pos-offline/pos-offline-api.js.map +1 -0
- package/src/lib/components/console/pos-offline/pos-offline-banner.component.d.ts +7 -0
- package/src/lib/components/console/pos-offline/pos-offline-banner.component.js +135 -0
- package/src/lib/components/console/pos-offline/pos-offline-banner.component.js.map +1 -0
- package/src/lib/components/console/pos-offline/pos-offline-checkout.component.d.ts +32 -0
- package/src/lib/components/console/pos-offline/pos-offline-checkout.component.js +287 -0
- package/src/lib/components/console/pos-offline/pos-offline-checkout.component.js.map +1 -0
- package/src/lib/components/console/pos-offline/pos-offline-store.d.ts +63 -0
- package/src/lib/components/console/pos-offline/pos-offline-store.js +145 -0
- package/src/lib/components/console/pos-offline/pos-offline-store.js.map +1 -0
- package/src/lib/components/console/pos-offline/register-offline.d.ts +24 -0
- package/src/lib/components/console/pos-offline/register-offline.js +24 -0
- package/src/lib/components/console/pos-offline/register-offline.js.map +1 -0
- package/src/lib/components/console/pos-offline/use-pos-offline.d.ts +85 -0
- package/src/lib/components/console/pos-offline/use-pos-offline.js +542 -0
- package/src/lib/components/console/pos-offline/use-pos-offline.js.map +1 -0
- package/src/lib/components/console/pos-ops/pos-shift-history-card.component.js +72 -17
- package/src/lib/components/console/pos-ops/pos-shift-history-card.component.js.map +1 -1
- package/src/lib/components/console/pos-page.component.js +174 -27
- package/src/lib/components/console/pos-page.component.js.map +1 -1
- package/src/lib/components/console/products-hub-card.component.js +35 -10
- package/src/lib/components/console/products-hub-card.component.js.map +1 -1
- package/src/lib/components/console/shipping-settings-card.component.js +1 -1
- package/src/lib/components/console/shipping-settings-card.component.js.map +1 -1
- package/src/lib/components/console/stock-movements-card.component.js +48 -16
- package/src/lib/components/console/stock-movements-card.component.js.map +1 -1
- package/src/lib/components/console/store-zones.d.ts +8 -1
- package/src/lib/components/console/store-zones.js +11 -1
- package/src/lib/components/console/store-zones.js.map +1 -1
- package/src/lib/components/order-status.js +66 -0
- package/src/lib/components/order-status.js.map +1 -1
- package/src/lib/components/product-detail.js +42 -15
- package/src/lib/components/product-detail.js.map +1 -1
- package/src/lib/constants/local-fulfillment-list-query.d.ts +48 -0
- package/src/lib/constants/local-fulfillment-list-query.js +84 -0
- package/src/lib/constants/local-fulfillment-list-query.js.map +1 -0
- package/src/lib/constants/orders-list-query.d.ts +7 -2
- package/src/lib/constants/orders-list-query.js +89 -8
- package/src/lib/constants/orders-list-query.js.map +1 -1
- package/src/lib/constants/pos-shift-list-query.d.ts +22 -0
- package/src/lib/constants/pos-shift-list-query.js +115 -0
- package/src/lib/constants/pos-shift-list-query.js.map +1 -0
- package/src/lib/constants/product-list-query.d.ts +6 -1
- package/src/lib/constants/product-list-query.js +77 -8
- package/src/lib/constants/product-list-query.js.map +1 -1
- package/src/lib/constants/stock-movement-query.d.ts +3 -2
- package/src/lib/constants/stock-movement-query.js +52 -8
- package/src/lib/constants/stock-movement-query.js.map +1 -1
- package/src/lib/model/buyer-notifications.d.ts +5 -3
- package/src/lib/model/buyer-notifications.js +25 -4
- package/src/lib/model/buyer-notifications.js.map +1 -1
- package/src/lib/model/commerce-orders.d.ts +59 -0
- package/src/lib/model/commerce-orders.js.map +1 -1
- package/src/lib/model/commerce-pos-kiosk.d.ts +175 -0
- package/src/lib/model/commerce-pos-kiosk.js +147 -0
- package/src/lib/model/commerce-pos-kiosk.js.map +1 -0
- package/src/lib/model/commerce-pos-offline.d.ts +234 -0
- package/src/lib/model/commerce-pos-offline.js +301 -0
- package/src/lib/model/commerce-pos-offline.js.map +1 -0
- package/src/lib/model/commerce-pos-ops.d.ts +16 -6
- package/src/lib/model/commerce-pos-ops.js +12 -4
- package/src/lib/model/commerce-pos-ops.js.map +1 -1
- package/src/lib/model/commerce-pos.d.ts +13 -1
- package/src/lib/model/commerce-pos.js +5 -4
- package/src/lib/model/commerce-pos.js.map +1 -1
- package/src/lib/model/commerce-stock-holds.d.ts +24 -3
- package/src/lib/model/commerce-stock-holds.js +26 -8
- package/src/lib/model/commerce-stock-holds.js.map +1 -1
- package/src/lib/model/commerce.d.ts +3 -0
- package/src/lib/model/commerce.js.map +1 -1
- package/src/lib/model/index.d.ts +4 -0
- package/src/lib/model/index.js +4 -0
- package/src/lib/model/index.js.map +1 -1
- package/src/lib/model/local-fulfillment-settings.d.ts +178 -0
- package/src/lib/model/local-fulfillment-settings.js +361 -0
- package/src/lib/model/local-fulfillment-settings.js.map +1 -0
- package/src/lib/model/order-list-fields.d.ts +10 -1
- package/src/lib/model/order-list-fields.js +1 -0
- package/src/lib/model/order-list-fields.js.map +1 -1
- package/src/lib/model/order-local-fulfillment.d.ts +131 -0
- package/src/lib/model/order-local-fulfillment.js +125 -0
- package/src/lib/model/order-local-fulfillment.js.map +1 -0
- package/src/lib/model/order-shipping-export.js +4 -0
- package/src/lib/model/order-shipping-export.js.map +1 -1
- package/src/lib/model/order-status-view.d.ts +20 -1
- package/src/lib/model/order-status-view.js +60 -6
- package/src/lib/model/order-status-view.js.map +1 -1
- package/src/lib/plugin-config.js +6 -2
- package/src/lib/plugin-config.js.map +1 -1
- package/src/lib/plugin.js +8 -0
- package/src/lib/plugin.js.map +1 -1
- package/src/lib/pos-kiosk-config.d.ts +26 -0
- package/src/lib/pos-kiosk-config.js +59 -0
- package/src/lib/pos-kiosk-config.js.map +1 -0
- package/src/lib/server/api-v1/openapi.js +8 -0
- package/src/lib/server/api-v1/openapi.js.map +1 -1
- package/src/lib/server/api-v1/order-view.d.ts +19 -0
- package/src/lib/server/api-v1/order-view.js +35 -0
- package/src/lib/server/api-v1/order-view.js.map +1 -1
- package/src/lib/server/billing-webhook.js +238 -87
- package/src/lib/server/billing-webhook.js.map +1 -1
- package/src/lib/server/cart-checkout.d.ts +2 -0
- package/src/lib/server/cart-checkout.js +173 -13
- package/src/lib/server/cart-checkout.js.map +1 -1
- package/src/lib/server/checkout-extras.js +18 -4
- package/src/lib/server/checkout-extras.js.map +1 -1
- package/src/lib/server/checkout.js +71 -14
- package/src/lib/server/checkout.js.map +1 -1
- package/src/lib/server/local-fulfillment-status.d.ts +86 -0
- package/src/lib/server/local-fulfillment-status.js +379 -0
- package/src/lib/server/local-fulfillment-status.js.map +1 -0
- package/src/lib/server/local-fulfillment.d.ts +190 -0
- package/src/lib/server/local-fulfillment.js +580 -0
- package/src/lib/server/local-fulfillment.js.map +1 -0
- package/src/lib/server/membership-register.js +3 -1
- package/src/lib/server/membership-register.js.map +1 -1
- package/src/lib/server/order-notifications.js +61 -0
- package/src/lib/server/order-notifications.js.map +1 -1
- package/src/lib/server/pos-display.d.ts +27 -1
- package/src/lib/server/pos-display.js +50 -9
- package/src/lib/server/pos-display.js.map +1 -1
- package/src/lib/server/pos-kiosk-principal.d.ts +29 -0
- package/src/lib/server/pos-kiosk-principal.js +42 -0
- package/src/lib/server/pos-kiosk-principal.js.map +1 -0
- package/src/lib/server/pos-kiosk.d.ts +54 -0
- package/src/lib/server/pos-kiosk.js +972 -0
- package/src/lib/server/pos-kiosk.js.map +1 -0
- package/src/lib/server/pos-offline-sync.d.ts +85 -0
- package/src/lib/server/pos-offline-sync.js +765 -0
- package/src/lib/server/pos-offline-sync.js.map +1 -0
- package/src/lib/server/pos-order.js +22 -4
- package/src/lib/server/pos-order.js.map +1 -1
- package/src/lib/server/pos-payment.d.ts +6 -0
- package/src/lib/server/pos-payment.js +225 -6
- package/src/lib/server/pos-payment.js.map +1 -1
- package/src/lib/server/pos-print.js +5 -0
- package/src/lib/server/pos-print.js.map +1 -1
- package/src/lib/server/pos-return.js +27 -0
- package/src/lib/server/pos-return.js.map +1 -1
- package/src/lib/server/pos-sale.d.ts +6 -0
- package/src/lib/server/pos-sale.js +2 -0
- package/src/lib/server/pos-sale.js.map +1 -1
- package/src/lib/server/pos-shift.js +8 -1
- package/src/lib/server/pos-shift.js.map +1 -1
- package/src/lib/server/refund.js +3 -0
- package/src/lib/server/refund.js.map +1 -1
- package/src/lib/server/stock-hold.d.ts +9 -1
- package/src/lib/server/stock-hold.js +15 -7
- package/src/lib/server/stock-hold.js.map +1 -1
- package/src/lib/server.js +16 -0
- package/src/lib/server.js.map +1 -1
- package/src/lib/tenant-emails.js +161 -0
- package/src/lib/tenant-emails.js.map +1 -1
|
@@ -0,0 +1,580 @@
|
|
|
1
|
+
import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
2
|
+
/**
|
|
3
|
+
* @license
|
|
4
|
+
* Copyright 2026 Aglyn LLC
|
|
5
|
+
*
|
|
6
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
|
+
* you may not use this file except in compliance with the License.
|
|
8
|
+
* You may obtain a copy of the License at
|
|
9
|
+
*
|
|
10
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
*
|
|
12
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
* See the License for the specific language governing permissions and
|
|
16
|
+
* limitations under the License.
|
|
17
|
+
*/ import { resolveSiteTimeZone } from "@aglyn/aglyn/app-utils/collection-entry-date";
|
|
18
|
+
import { normalizePhone } from "@aglyn/aglyn/foundation/definitions/contact.types";
|
|
19
|
+
import { pluginSmsMessaging } from "@aglyn/aglyn/plugin-manager/plugin-sms-messaging";
|
|
20
|
+
import { pluginShippingRateQuoter } from "@aglyn/aglyn/plugin-manager/plugin-shipping-rates";
|
|
21
|
+
import * as Aglyn from "@aglyn/aglyn/server";
|
|
22
|
+
import { consumeRateLimit, firebaseAdmin, getOrgForHost } from "@aglyn/tenant-data-admin";
|
|
23
|
+
import { isDocumentId } from "@aglyn/tenant-data-admin/server/document-id";
|
|
24
|
+
import * as CommerceModel from "../model/index.js";
|
|
25
|
+
import { readCartId } from "./cart-cookie.js";
|
|
26
|
+
/** Reads the cart's declaration; `null` when it made none (a shipped order). */ export function readLocalFulfillmentRequest(value) {
|
|
27
|
+
if (!value || typeof value !== 'object') return null;
|
|
28
|
+
const raw = value;
|
|
29
|
+
const method = raw['method'];
|
|
30
|
+
if (method !== 'pickup' && method !== 'local_delivery') return null;
|
|
31
|
+
const text = (input, max)=>String(input != null ? input : '').trim().slice(0, max);
|
|
32
|
+
const request = {
|
|
33
|
+
method
|
|
34
|
+
};
|
|
35
|
+
const phone = normalizePhone(text(raw['textPhone'], 32));
|
|
36
|
+
if (phone) request.textPhone = phone;
|
|
37
|
+
if (method === 'pickup') {
|
|
38
|
+
request.locationId = text(raw['locationId'], 120);
|
|
39
|
+
return request;
|
|
40
|
+
}
|
|
41
|
+
const postalCode = text(raw['postalCode'], 16);
|
|
42
|
+
if (postalCode) request.postalCode = postalCode;
|
|
43
|
+
const start = Math.round(Number(raw['windowStartMs']));
|
|
44
|
+
if (Number.isFinite(start) && start > 0) request.windowStartMs = start;
|
|
45
|
+
const address = raw['address'];
|
|
46
|
+
if (address && typeof address === 'object') {
|
|
47
|
+
const parts = address;
|
|
48
|
+
request.address = {
|
|
49
|
+
line1: text(parts['line1'], 120),
|
|
50
|
+
line2: text(parts['line2'], 120),
|
|
51
|
+
city: text(parts['city'], 80),
|
|
52
|
+
state: text(parts['state'], 40),
|
|
53
|
+
postalCode: text(parts['postalCode'], 16) || postalCode
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
return request;
|
|
57
|
+
}
|
|
58
|
+
/** Reads what checkout and the cart need. Never throws: a failed read offers nothing. */ export async function readLocalFulfillmentStore(input) {
|
|
59
|
+
var _ref, _input_org;
|
|
60
|
+
const { hostRef } = input;
|
|
61
|
+
const [locationsSnapshot, settings, host] = await Promise.all([
|
|
62
|
+
hostRef.collection('locations').limit(CommerceModel.PICKUP_LOCATIONS_MAX).get().catch(()=>null),
|
|
63
|
+
input.storeSettings !== undefined ? Promise.resolve(input.storeSettings) : hostRef.collection('settings').doc('store').get().then((snapshot)=>{
|
|
64
|
+
var _ref;
|
|
65
|
+
var _snapshot_data;
|
|
66
|
+
return (_ref = snapshot == null ? void 0 : (_snapshot_data = snapshot.data) == null ? void 0 : _snapshot_data.call(snapshot)) != null ? _ref : null;
|
|
67
|
+
}).catch(()=>null),
|
|
68
|
+
input.host !== undefined ? Promise.resolve(input.host) : hostRef.get().then((snapshot)=>{
|
|
69
|
+
var _ref;
|
|
70
|
+
var _snapshot_data;
|
|
71
|
+
return (_ref = snapshot == null ? void 0 : (_snapshot_data = snapshot.data) == null ? void 0 : _snapshot_data.call(snapshot)) != null ? _ref : null;
|
|
72
|
+
}).catch(()=>null)
|
|
73
|
+
]);
|
|
74
|
+
const locations = ((_ref = locationsSnapshot == null ? void 0 : locationsSnapshot.docs) != null ? _ref : []).map((snapshot)=>_extends({}, snapshot.data(), {
|
|
75
|
+
id: String(snapshot.id)
|
|
76
|
+
}));
|
|
77
|
+
return {
|
|
78
|
+
pickupLocations: CommerceModel.pickupLocationOptions(locations),
|
|
79
|
+
delivery: CommerceModel.normalizeLocalDeliverySettings(settings == null ? void 0 : settings['localDelivery']),
|
|
80
|
+
timeZone: resolveSiteTimeZone((_input_org = input.org) != null ? _input_org : null, host != null ? host : null)
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
/** How long checkout waits for an address to be placed on a map. */ export const LOCAL_DELIVERY_GEOCODE_TIMEOUT_MS = 3000;
|
|
84
|
+
/**
|
|
85
|
+
* Places an address on the map through the shipping plugin's address check,
|
|
86
|
+
* or answers `null`: no plugin, not available on this site, no position in
|
|
87
|
+
* the answer, or slower than the timeout. Never throws.
|
|
88
|
+
*/ export async function placeDeliveryAddress(hostId, address) {
|
|
89
|
+
if (!address.line1 || !address.postalCode) return null;
|
|
90
|
+
const quoter = pluginShippingRateQuoter();
|
|
91
|
+
if (!(quoter == null ? void 0 : quoter.validateAddress)) return null;
|
|
92
|
+
let timer;
|
|
93
|
+
try {
|
|
94
|
+
const placed = await Promise.race([
|
|
95
|
+
(async ()=>{
|
|
96
|
+
var _ref;
|
|
97
|
+
if (!await quoter.available(hostId)) return null;
|
|
98
|
+
const check = await (quoter.validateAddress == null ? void 0 : quoter.validateAddress.call(quoter, hostId, _extends({
|
|
99
|
+
line1: address.line1
|
|
100
|
+
}, address.line2 ? {
|
|
101
|
+
line2: address.line2
|
|
102
|
+
} : {}, address.city ? {
|
|
103
|
+
city: address.city
|
|
104
|
+
} : {}, address.state ? {
|
|
105
|
+
state: address.state
|
|
106
|
+
} : {}, {
|
|
107
|
+
postalCode: address.postalCode,
|
|
108
|
+
country: address.country
|
|
109
|
+
})));
|
|
110
|
+
return (check == null ? void 0 : check.verdict) === 'invalid' ? null : (_ref = check == null ? void 0 : check.coordinates) != null ? _ref : null;
|
|
111
|
+
})().catch(()=>null),
|
|
112
|
+
new Promise((resolve)=>{
|
|
113
|
+
timer = setTimeout(()=>resolve(null), LOCAL_DELIVERY_GEOCODE_TIMEOUT_MS);
|
|
114
|
+
})
|
|
115
|
+
]);
|
|
116
|
+
return placed != null ? placed : null;
|
|
117
|
+
} finally{
|
|
118
|
+
if (timer) clearTimeout(timer);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
/** The shipping option id a local delivery fee is declared under. */ export const LOCAL_DELIVERY_RATE_ID = 'local-delivery';
|
|
122
|
+
const money = (cents)=>CommerceModel.formatOrderMoney(cents, 'USD');
|
|
123
|
+
/**
|
|
124
|
+
* Turns the cart's declaration into what the session needs, or a refusal.
|
|
125
|
+
* Taken BEFORE any reservation or Stripe call, so a refusal costs nothing
|
|
126
|
+
* and the buyer's same button works once they choose again.
|
|
127
|
+
*/ export async function planLocalFulfillment(input) {
|
|
128
|
+
var _input_nowMs, _request_postalCode;
|
|
129
|
+
var _request_address;
|
|
130
|
+
const { request, store } = input;
|
|
131
|
+
// A cart of downloads is not collected or driven anywhere.
|
|
132
|
+
if (!request || request.method === 'shipping' || !input.hasPhysicalLine) return {
|
|
133
|
+
kind: 'shipping'
|
|
134
|
+
};
|
|
135
|
+
const nowMs = (_input_nowMs = input.nowMs) != null ? _input_nowMs : Date.now();
|
|
136
|
+
if (request.method === 'pickup') {
|
|
137
|
+
const location = store.pickupLocations.find((entry)=>entry.id === request.locationId);
|
|
138
|
+
if (!location) {
|
|
139
|
+
return {
|
|
140
|
+
kind: 'refusal',
|
|
141
|
+
status: 409,
|
|
142
|
+
error: 'That pickup location is no longer available. Choose another.',
|
|
143
|
+
changed: 'pickup'
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
return {
|
|
147
|
+
kind: 'pickup',
|
|
148
|
+
location,
|
|
149
|
+
metadata: _extends({
|
|
150
|
+
fulfillment: 'pickup',
|
|
151
|
+
pickupLocationId: location.id
|
|
152
|
+
}, request.textPhone ? {
|
|
153
|
+
orderTextPhone: request.textPhone
|
|
154
|
+
} : {})
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
const delivery = store.delivery;
|
|
158
|
+
if (!CommerceModel.localDeliveryOffered(delivery)) {
|
|
159
|
+
return {
|
|
160
|
+
kind: 'refusal',
|
|
161
|
+
status: 409,
|
|
162
|
+
error: 'Local delivery is not available right now. Choose shipping or pickup.',
|
|
163
|
+
changed: 'delivery'
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
const country = String(delivery.country);
|
|
167
|
+
const postalCode = CommerceModel.normalizePostcode((_request_postalCode = request.postalCode) != null ? _request_postalCode : (_request_address = request.address) == null ? void 0 : _request_address.postalCode, country);
|
|
168
|
+
if (!postalCode) {
|
|
169
|
+
return {
|
|
170
|
+
kind: 'refusal',
|
|
171
|
+
status: 400,
|
|
172
|
+
error: 'Enter your postal code for delivery.'
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
let zone = CommerceModel.matchLocalDeliveryZone(delivery, {
|
|
176
|
+
country,
|
|
177
|
+
postalCode
|
|
178
|
+
});
|
|
179
|
+
if (!zone && CommerceModel.localDeliveryHasRadiusZones(delivery)) {
|
|
180
|
+
var _request_address1;
|
|
181
|
+
if (!((_request_address1 = request.address) == null ? void 0 : _request_address1.line1)) {
|
|
182
|
+
return {
|
|
183
|
+
kind: 'refusal',
|
|
184
|
+
status: 400,
|
|
185
|
+
error: 'Enter your street address for delivery.'
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
const coordinates = await placeDeliveryAddress(input.hostId, _extends({}, request.address, {
|
|
189
|
+
postalCode,
|
|
190
|
+
country
|
|
191
|
+
}));
|
|
192
|
+
zone = CommerceModel.matchLocalDeliveryZone(delivery, {
|
|
193
|
+
country,
|
|
194
|
+
postalCode,
|
|
195
|
+
coordinates
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
if (!zone) {
|
|
199
|
+
return {
|
|
200
|
+
kind: 'refusal',
|
|
201
|
+
status: 409,
|
|
202
|
+
error: `We don’t deliver to ${postalCode}. Choose shipping or pickup instead.`
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
const shortfall = CommerceModel.localDeliveryMinimumShortfall(zone, input.itemsCents);
|
|
206
|
+
if (shortfall > 0) {
|
|
207
|
+
var _zone_minimumCents;
|
|
208
|
+
return {
|
|
209
|
+
kind: 'refusal',
|
|
210
|
+
status: 409,
|
|
211
|
+
error: `Delivery to ${postalCode} needs an order of at least ${money((_zone_minimumCents = zone.minimumCents) != null ? _zone_minimumCents : 0)}. ` + `Add ${money(shortfall)} more, or choose shipping or pickup.`
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
const window = CommerceModel.findLocalDeliveryWindow(delivery, request.windowStartMs, {
|
|
215
|
+
nowMs,
|
|
216
|
+
timeZone: store.timeZone
|
|
217
|
+
});
|
|
218
|
+
if (!window) {
|
|
219
|
+
return {
|
|
220
|
+
kind: 'refusal',
|
|
221
|
+
status: 409,
|
|
222
|
+
error: 'That delivery time is no longer available. Choose another.',
|
|
223
|
+
changed: 'delivery'
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
const feeCents = CommerceModel.localDeliveryFeeCents(zone, input.itemsCents);
|
|
227
|
+
const label = CommerceModel.formatLocalDeliveryWindow(window, store.timeZone);
|
|
228
|
+
return _extends({
|
|
229
|
+
kind: 'local_delivery',
|
|
230
|
+
zone,
|
|
231
|
+
window,
|
|
232
|
+
feeCents,
|
|
233
|
+
country
|
|
234
|
+
}, delivery.locationId ? {
|
|
235
|
+
locationId: delivery.locationId
|
|
236
|
+
} : {}, {
|
|
237
|
+
option: {
|
|
238
|
+
rateId: LOCAL_DELIVERY_RATE_ID,
|
|
239
|
+
name: `Local delivery — ${label}`.slice(0, 100),
|
|
240
|
+
amountCents: feeCents
|
|
241
|
+
},
|
|
242
|
+
metadata: _extends({
|
|
243
|
+
fulfillment: 'local_delivery',
|
|
244
|
+
deliveryZoneId: zone.id,
|
|
245
|
+
deliveryWindowStartMs: String(window.startMs),
|
|
246
|
+
deliveryWindowEndMs: String(window.endMs),
|
|
247
|
+
deliveryPostalCode: postalCode,
|
|
248
|
+
deliveryFeeCents: String(feeCents)
|
|
249
|
+
}, delivery.locationId ? {
|
|
250
|
+
deliveryLocationId: delivery.locationId
|
|
251
|
+
} : {}, request.textPhone ? {
|
|
252
|
+
orderTextPhone: request.textPhone
|
|
253
|
+
} : {})
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
/** Sets a plan's metadata on a session's form body. */ export function appendLocalFulfillmentMetadata(params, metadata) {
|
|
257
|
+
for (const [key, value] of Object.entries(metadata)){
|
|
258
|
+
params.set(`metadata[${key}]`, String(value).slice(0, 480));
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
/** The location a plan takes its stock from, if any. */ export function localFulfillmentLocationId(plan) {
|
|
262
|
+
if (plan.kind === 'pickup') return plan.location.id;
|
|
263
|
+
if (plan.kind === 'local_delivery') return plan.locationId;
|
|
264
|
+
return undefined;
|
|
265
|
+
}
|
|
266
|
+
/** A stock refusal for a plan that reserves at one location (AGL-3624). */ export function localStockRefusalMessage(plan, productName) {
|
|
267
|
+
const what = productName ? `"${productName}"` : 'An item in your cart';
|
|
268
|
+
if (plan.kind === 'pickup') {
|
|
269
|
+
return `${what} is not in stock at ${plan.location.name}. Choose another location, or have it shipped.`;
|
|
270
|
+
}
|
|
271
|
+
return `${what} is not in stock for local delivery. Choose pickup at another location, or have it shipped.`;
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Reads a paid session's `fulfillment` metadata into order fields, or `null`
|
|
275
|
+
* for a shipped order. The location and zone are re-read so the order keeps
|
|
276
|
+
* their names as they were when the buyer paid.
|
|
277
|
+
*/ export async function orderLocalFulfillmentFromSession(input) {
|
|
278
|
+
var _input_metadata, _metadata_orderTextPhone, _ref, _metadata_deliveryZoneId, _store_delivery_zones, _metadata_deliveryPostalCode, _store_delivery_country, _ref1, _metadata_deliveryLocationId, _ref2, _store_delivery_instructions;
|
|
279
|
+
var _input_shippingAddress, _input_shippingAddress1;
|
|
280
|
+
const metadata = (_input_metadata = input.metadata) != null ? _input_metadata : {};
|
|
281
|
+
const method = metadata['fulfillment'];
|
|
282
|
+
if (method !== 'pickup' && method !== 'local_delivery') return null;
|
|
283
|
+
const textPhone = normalizePhone(String((_metadata_orderTextPhone = metadata['orderTextPhone']) != null ? _metadata_orderTextPhone : ''));
|
|
284
|
+
const phone = textPhone ? {
|
|
285
|
+
customerPhone: textPhone
|
|
286
|
+
} : {};
|
|
287
|
+
const org = await getOrgForHost(input.hostId).catch(()=>null);
|
|
288
|
+
const store = await readLocalFulfillmentStore({
|
|
289
|
+
hostRef: input.hostRef,
|
|
290
|
+
org: (_ref = org == null ? void 0 : org.org) != null ? _ref : null
|
|
291
|
+
});
|
|
292
|
+
if (method === 'pickup') {
|
|
293
|
+
var _metadata_pickupLocationId, _location_instructions;
|
|
294
|
+
const locationId = String((_metadata_pickupLocationId = metadata['pickupLocationId']) != null ? _metadata_pickupLocationId : '');
|
|
295
|
+
let location = store.pickupLocations.find((entry)=>entry.id === locationId);
|
|
296
|
+
// A location renamed or switched off after the buyer paid: the order
|
|
297
|
+
// still goes there, under the name the location doc now has.
|
|
298
|
+
if (!location && locationId) {
|
|
299
|
+
const snapshot = await input.hostRef.collection('locations').doc(locationId).get().catch(()=>null);
|
|
300
|
+
const data = (snapshot == null ? void 0 : snapshot.exists) ? snapshot.data() : null;
|
|
301
|
+
location = _extends({
|
|
302
|
+
id: locationId,
|
|
303
|
+
name: String((data == null ? void 0 : data.name) || 'the store')
|
|
304
|
+
}, data ? {
|
|
305
|
+
address: CommerceModel.formatPostalAddressLine(data.postalAddress, data.address) || undefined
|
|
306
|
+
} : {});
|
|
307
|
+
}
|
|
308
|
+
if (!location) return null;
|
|
309
|
+
const pickup = _extends({
|
|
310
|
+
locationId: location.id,
|
|
311
|
+
locationName: location.name
|
|
312
|
+
}, location.address ? {
|
|
313
|
+
address: location.address
|
|
314
|
+
} : {}, location.instructions ? {
|
|
315
|
+
instructions: location.instructions
|
|
316
|
+
} : {}, location.hours ? {
|
|
317
|
+
hours: location.hours
|
|
318
|
+
} : {}, {
|
|
319
|
+
status: 'preparing',
|
|
320
|
+
updatedAtMs: input.createdAtMs
|
|
321
|
+
});
|
|
322
|
+
const order = {
|
|
323
|
+
fulfillmentMethod: 'pickup',
|
|
324
|
+
pickup,
|
|
325
|
+
createdAtMs: input.createdAtMs
|
|
326
|
+
};
|
|
327
|
+
const list = CommerceModel.orderLocalFulfillmentListFields(order);
|
|
328
|
+
const ready = CommerceModel.pickupReadyWithinLabel(location.readyWithinMinutes);
|
|
329
|
+
return {
|
|
330
|
+
fields: _extends({
|
|
331
|
+
fulfillmentMethod: 'pickup',
|
|
332
|
+
pickup,
|
|
333
|
+
locationId: location.id
|
|
334
|
+
}, phone, list),
|
|
335
|
+
summary: [
|
|
336
|
+
`Pickup at ${location.name}${location.address ? `, ${location.address}` : ''}.`,
|
|
337
|
+
`We’ll let you know when it’s ready${ready ? ` (${ready.toLowerCase()})` : ''}.`,
|
|
338
|
+
(_location_instructions = location.instructions) != null ? _location_instructions : ''
|
|
339
|
+
].filter(Boolean).join(' '),
|
|
340
|
+
outsideZone: false
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
const zoneId = String((_metadata_deliveryZoneId = metadata['deliveryZoneId']) != null ? _metadata_deliveryZoneId : '');
|
|
344
|
+
const zone = ((_store_delivery_zones = store.delivery.zones) != null ? _store_delivery_zones : []).find((entry)=>entry.id === zoneId);
|
|
345
|
+
const windowStartMs = Number(metadata['deliveryWindowStartMs']) || 0;
|
|
346
|
+
const windowEndMs = Number(metadata['deliveryWindowEndMs']) || windowStartMs;
|
|
347
|
+
const declared = String((_metadata_deliveryPostalCode = metadata['deliveryPostalCode']) != null ? _metadata_deliveryPostalCode : '');
|
|
348
|
+
const country = (_store_delivery_country = store.delivery.country) != null ? _store_delivery_country : String((_ref1 = (_input_shippingAddress = input.shippingAddress) == null ? void 0 : _input_shippingAddress.country) != null ? _ref1 : '');
|
|
349
|
+
const entered = CommerceModel.normalizePostcode((_input_shippingAddress1 = input.shippingAddress) == null ? void 0 : _input_shippingAddress1.postalCode, country);
|
|
350
|
+
// The fee was charged for the code the buyer declared. The address they
|
|
351
|
+
// then typed at payment must be in a zone too — a zone of ANY fee, since
|
|
352
|
+
// the store delivers there — or the store is told.
|
|
353
|
+
const outsideZone = Boolean(entered && entered !== declared && !CommerceModel.matchLocalDeliveryZone(store.delivery, {
|
|
354
|
+
country,
|
|
355
|
+
postalCode: entered
|
|
356
|
+
}));
|
|
357
|
+
const windowLabel = windowStartMs ? CommerceModel.formatLocalDeliveryWindow({
|
|
358
|
+
startMs: windowStartMs,
|
|
359
|
+
endMs: windowEndMs
|
|
360
|
+
}, store.timeZone) : '';
|
|
361
|
+
const locationId = String((_metadata_deliveryLocationId = metadata['deliveryLocationId']) != null ? _metadata_deliveryLocationId : '') || undefined;
|
|
362
|
+
const localDelivery = _extends({
|
|
363
|
+
zoneId,
|
|
364
|
+
zoneName: (_ref2 = zone == null ? void 0 : zone.name) != null ? _ref2 : 'Local delivery',
|
|
365
|
+
feeCents: Math.max(0, Math.round(Number(metadata['deliveryFeeCents']) || 0)),
|
|
366
|
+
windowStartMs,
|
|
367
|
+
windowEndMs
|
|
368
|
+
}, windowLabel ? {
|
|
369
|
+
windowLabel
|
|
370
|
+
} : {}, declared ? {
|
|
371
|
+
postalCode: declared
|
|
372
|
+
} : {}, locationId ? {
|
|
373
|
+
locationId
|
|
374
|
+
} : {}, {
|
|
375
|
+
status: 'scheduled'
|
|
376
|
+
}, outsideZone ? {
|
|
377
|
+
addressOutsideZone: true
|
|
378
|
+
} : {}, {
|
|
379
|
+
updatedAtMs: input.createdAtMs
|
|
380
|
+
});
|
|
381
|
+
const order = {
|
|
382
|
+
fulfillmentMethod: 'local_delivery',
|
|
383
|
+
localDelivery,
|
|
384
|
+
createdAtMs: input.createdAtMs
|
|
385
|
+
};
|
|
386
|
+
const list = CommerceModel.orderLocalFulfillmentListFields(order);
|
|
387
|
+
return {
|
|
388
|
+
fields: _extends({
|
|
389
|
+
fulfillmentMethod: 'local_delivery',
|
|
390
|
+
localDelivery
|
|
391
|
+
}, locationId ? {
|
|
392
|
+
locationId
|
|
393
|
+
} : {}, phone, list),
|
|
394
|
+
summary: [
|
|
395
|
+
`Local delivery${windowLabel ? `: ${windowLabel}` : ''}.`,
|
|
396
|
+
(_store_delivery_instructions = store.delivery.instructions) != null ? _store_delivery_instructions : ''
|
|
397
|
+
].filter(Boolean).join(' '),
|
|
398
|
+
outsideZone
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
// ---------------------------------------------------------------------------
|
|
402
|
+
// The cart's question: what can this basket be?
|
|
403
|
+
// ---------------------------------------------------------------------------
|
|
404
|
+
/** Distance zones place an address through a provider: a visitor may ask this often. */ const PLACE_LIMIT = {
|
|
405
|
+
limit: 20,
|
|
406
|
+
windowMs: 60 * 60 * 1000
|
|
407
|
+
};
|
|
408
|
+
/**
|
|
409
|
+
* `POST commerce/local-fulfillment-options` (AGL-3624): what the cart offers
|
|
410
|
+
* besides shipping — the pickup locations and, with a postal code, the
|
|
411
|
+
* delivery zone's fee, minimum and the windows open to book.
|
|
412
|
+
*
|
|
413
|
+
* Public, because a shopper asks it; it returns only what a storefront would
|
|
414
|
+
* print anyway (location names, addresses, hours, fees). It reads the
|
|
415
|
+
* visitor's own cart through the cart cookie and offers nothing for a
|
|
416
|
+
* basket with nothing physical in it.
|
|
417
|
+
*/ export const localFulfillmentOptionsHandler = async (req, res)=>{
|
|
418
|
+
var _body_hostId;
|
|
419
|
+
if (req.method !== 'POST' && req.method !== 'GET') {
|
|
420
|
+
return res.status(405).json({
|
|
421
|
+
error: 'Method not allowed'
|
|
422
|
+
});
|
|
423
|
+
}
|
|
424
|
+
let body;
|
|
425
|
+
try {
|
|
426
|
+
var _req_body, _req_query;
|
|
427
|
+
body = req.method === 'POST' ? typeof req.body === 'string' ? JSON.parse(req.body || '{}') : (_req_body = req.body) != null ? _req_body : {} : (_req_query = req.query) != null ? _req_query : {};
|
|
428
|
+
} catch (unused) {
|
|
429
|
+
return res.status(400).json({
|
|
430
|
+
error: 'Invalid request'
|
|
431
|
+
});
|
|
432
|
+
}
|
|
433
|
+
const hostId = String((_body_hostId = body.hostId) != null ? _body_hostId : '');
|
|
434
|
+
if (!isDocumentId(hostId)) return res.status(400).json({
|
|
435
|
+
error: 'Missing or invalid hostId'
|
|
436
|
+
});
|
|
437
|
+
const nothing = {
|
|
438
|
+
pickup: [],
|
|
439
|
+
delivery: null
|
|
440
|
+
};
|
|
441
|
+
try {
|
|
442
|
+
var _cart_lines, _cart_lines1;
|
|
443
|
+
var _pluginSmsMessaging;
|
|
444
|
+
const firestore = firebaseAdmin.app().firestore();
|
|
445
|
+
const hostRef = firestore.collection('hosts').doc(hostId);
|
|
446
|
+
const ownerOrg = await getOrgForHost(hostId).catch(()=>null);
|
|
447
|
+
if (!(ownerOrg == null ? void 0 : ownerOrg.org) || !Aglyn.checkEntitlement(ownerOrg.org, 'commerce')) {
|
|
448
|
+
return res.status(200).json(nothing);
|
|
449
|
+
}
|
|
450
|
+
// The visitor's own basket decides whether there is anything to collect
|
|
451
|
+
// — or, from a product's Buy button, that one product (AGL-3624).
|
|
452
|
+
const buyNowProductId = typeof body.productId === 'string' ? body.productId : '';
|
|
453
|
+
let cart;
|
|
454
|
+
if (buyNowProductId) {
|
|
455
|
+
if (!isDocumentId(buyNowProductId)) return res.status(400).json({
|
|
456
|
+
error: 'Invalid productId'
|
|
457
|
+
});
|
|
458
|
+
cart = {
|
|
459
|
+
lines: [
|
|
460
|
+
_extends({
|
|
461
|
+
productId: buyNowProductId
|
|
462
|
+
}, typeof body.variantId === 'string' && body.variantId ? {
|
|
463
|
+
variantId: body.variantId
|
|
464
|
+
} : {}, {
|
|
465
|
+
quantity: Math.min(99, Math.max(1, Math.round(Number(body.quantity) || 1)))
|
|
466
|
+
})
|
|
467
|
+
]
|
|
468
|
+
};
|
|
469
|
+
} else {
|
|
470
|
+
var _ref;
|
|
471
|
+
var _cartSnapshot_data;
|
|
472
|
+
const cartId = readCartId(req.cookies, hostId);
|
|
473
|
+
const cartSnapshot = cartId ? await hostRef.collection('carts').doc(cartId).get().catch(()=>null) : null;
|
|
474
|
+
cart = (_ref = cartSnapshot == null ? void 0 : (_cartSnapshot_data = cartSnapshot.data) == null ? void 0 : _cartSnapshot_data.call(cartSnapshot)) != null ? _ref : {
|
|
475
|
+
lines: []
|
|
476
|
+
};
|
|
477
|
+
}
|
|
478
|
+
const productIds = [
|
|
479
|
+
...new Set(((_cart_lines = cart.lines) != null ? _cart_lines : []).map((line)=>line.productId))
|
|
480
|
+
].slice(0, 50);
|
|
481
|
+
const products = await Promise.all(productIds.map((id)=>hostRef.collection('products').doc(id).get().catch(()=>null)));
|
|
482
|
+
let itemsCents = 0;
|
|
483
|
+
let hasPhysicalLine = false;
|
|
484
|
+
for (const line of (_cart_lines1 = cart.lines) != null ? _cart_lines1 : []){
|
|
485
|
+
var _ref1, _product_type;
|
|
486
|
+
const snapshot = products[productIds.indexOf(line.productId)];
|
|
487
|
+
if (!(snapshot == null ? void 0 : snapshot.exists)) continue;
|
|
488
|
+
const product = CommerceModel.liftLegacyProduct(snapshot.data());
|
|
489
|
+
const variant = line.variantId ? product.variants.find((item)=>item.id === line.variantId) : product.variants[0];
|
|
490
|
+
itemsCents += Math.round(Number((_ref1 = variant == null ? void 0 : variant.priceUsd) != null ? _ref1 : 0) * 100) * (Number(line.quantity) || 0);
|
|
491
|
+
if (((_product_type = product.type) != null ? _product_type : 'physical') === 'physical') hasPhysicalLine = true;
|
|
492
|
+
}
|
|
493
|
+
if (!hasPhysicalLine) return res.status(200).json(nothing);
|
|
494
|
+
const store = await readLocalFulfillmentStore({
|
|
495
|
+
hostRef,
|
|
496
|
+
org: ownerOrg.org
|
|
497
|
+
});
|
|
498
|
+
const nowMs = Date.now();
|
|
499
|
+
let delivery = null;
|
|
500
|
+
if (CommerceModel.localDeliveryOffered(store.delivery)) {
|
|
501
|
+
var _ref2;
|
|
502
|
+
var _request_address;
|
|
503
|
+
const settings = store.delivery;
|
|
504
|
+
const country = String(settings.country);
|
|
505
|
+
const windows = CommerceModel.upcomingLocalDeliveryWindows(settings, {
|
|
506
|
+
nowMs,
|
|
507
|
+
timeZone: store.timeZone
|
|
508
|
+
}).map((window)=>_extends({}, window, {
|
|
509
|
+
label: CommerceModel.formatLocalDeliveryWindow(window, store.timeZone)
|
|
510
|
+
}));
|
|
511
|
+
const radius = CommerceModel.localDeliveryHasRadiusZones(settings);
|
|
512
|
+
delivery = _extends({
|
|
513
|
+
country
|
|
514
|
+
}, settings.instructions ? {
|
|
515
|
+
instructions: settings.instructions
|
|
516
|
+
} : {}, {
|
|
517
|
+
needsAddress: radius,
|
|
518
|
+
windows
|
|
519
|
+
});
|
|
520
|
+
const request = readLocalFulfillmentRequest({
|
|
521
|
+
method: 'local_delivery',
|
|
522
|
+
postalCode: body.postalCode,
|
|
523
|
+
address: body.address
|
|
524
|
+
});
|
|
525
|
+
const postalCode = CommerceModel.normalizePostcode((_ref2 = request == null ? void 0 : request.postalCode) != null ? _ref2 : request == null ? void 0 : (_request_address = request.address) == null ? void 0 : _request_address.postalCode, country);
|
|
526
|
+
if (postalCode) {
|
|
527
|
+
var _request_address1;
|
|
528
|
+
let zone = CommerceModel.matchLocalDeliveryZone(settings, {
|
|
529
|
+
country,
|
|
530
|
+
postalCode
|
|
531
|
+
});
|
|
532
|
+
if (!zone && radius && (request == null ? void 0 : (_request_address1 = request.address) == null ? void 0 : _request_address1.line1)) {
|
|
533
|
+
var _ref3;
|
|
534
|
+
var _req_socket;
|
|
535
|
+
const visitor = String((_ref3 = (_req_socket = req.socket) == null ? void 0 : _req_socket.remoteAddress) != null ? _ref3 : '') || 'no-address';
|
|
536
|
+
const allowed = await consumeRateLimit(`local-delivery:place:${hostId}:${visitor}`, PLACE_LIMIT).then((result)=>result.allowed).catch(()=>false);
|
|
537
|
+
const coordinates = allowed ? await placeDeliveryAddress(hostId, _extends({}, request.address, {
|
|
538
|
+
postalCode,
|
|
539
|
+
country
|
|
540
|
+
})) : null;
|
|
541
|
+
zone = CommerceModel.matchLocalDeliveryZone(settings, {
|
|
542
|
+
country,
|
|
543
|
+
postalCode,
|
|
544
|
+
coordinates
|
|
545
|
+
});
|
|
546
|
+
}
|
|
547
|
+
delivery['quote'] = zone ? _extends({
|
|
548
|
+
zoneId: zone.id,
|
|
549
|
+
zoneName: zone.name,
|
|
550
|
+
feeCents: CommerceModel.localDeliveryFeeCents(zone, itemsCents)
|
|
551
|
+
}, zone.minimumCents ? {
|
|
552
|
+
minimumCents: zone.minimumCents
|
|
553
|
+
} : {}, zone.freeOverCents ? {
|
|
554
|
+
freeOverCents: zone.freeOverCents
|
|
555
|
+
} : {}, {
|
|
556
|
+
shortfallCents: CommerceModel.localDeliveryMinimumShortfall(zone, itemsCents)
|
|
557
|
+
}) : {
|
|
558
|
+
unavailable: `We don’t deliver to ${postalCode}.`
|
|
559
|
+
};
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
// Whether the cart may offer texts about the pickup or delivery: the
|
|
563
|
+
// platform can send them and the store has not turned them off.
|
|
564
|
+
const toggles = await hostRef.collection('settings').doc('store').get().then((snapshot)=>{
|
|
565
|
+
var _snapshot_get;
|
|
566
|
+
return snapshot == null ? void 0 : (_snapshot_get = snapshot.get) == null ? void 0 : _snapshot_get.call(snapshot, 'buyerNotifications');
|
|
567
|
+
}).catch(()=>null);
|
|
568
|
+
const texts = Boolean(((_pluginSmsMessaging = pluginSmsMessaging()) == null ? void 0 : _pluginSmsMessaging.isConfigured()) && CommerceModel.buyerNotificationEnabled(toggles, 'texts'));
|
|
569
|
+
return res.status(200).json({
|
|
570
|
+
pickup: store.pickupLocations,
|
|
571
|
+
delivery,
|
|
572
|
+
texts
|
|
573
|
+
});
|
|
574
|
+
} catch (error) {
|
|
575
|
+
console.error('[local-fulfillment] options failed', hostId, error);
|
|
576
|
+
return res.status(200).json(nothing);
|
|
577
|
+
}
|
|
578
|
+
};
|
|
579
|
+
|
|
580
|
+
//# sourceMappingURL=local-fulfillment.js.map
|