@pisell/private-materials 6.12.312 → 6.12.314

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.
@@ -25,23 +25,52 @@ function ConfirmOrderIcon() {
25
25
  "aria-hidden": "true"
26
26
  }, /* @__PURE__ */ React.createElement("path", { d: "m5 12 4 4L19 6" }));
27
27
  }
28
- /** 与 PaymentModal 一致:EFTPOS/信用卡使用 credit,其余自定义方式使用 custom。 */
29
- function PaymentMethodIcon({ code, type }) {
30
- const isCard = code === "EFTPOS" || type === "credit-card" || type === "eftpos";
28
+ /** 名称含 cash 时优先展示纸币,否则按卡支付、现金配置和自定义支付区分。 */
29
+ function PaymentMethodIcon({ code, name, type, eftpos, cash }) {
30
+ const nameContainsCash = /cash/i.test(name);
31
+ const isCash = nameContainsCash || cash;
32
+ const isCard = !nameContainsCash && (eftpos || code === "EFTPOS" || type === "credit-card" || type === "eftpos");
31
33
  return /* @__PURE__ */ React.createElement("span", {
32
34
  className: "hdl-payment-method__icon",
33
- style: { background: isCard ? "#FE8279" : "#D277E4" },
35
+ style: { background: isCard ? "#FE8279" : isCash ? "#D69B28" : "#D277E4" },
34
36
  "aria-hidden": "true"
35
- }, /* @__PURE__ */ React.createElement(Iconfont, {
36
- type: isCard ? "pisell2-credit" : "pisell2-custom",
37
+ }, isCard ? /* @__PURE__ */ React.createElement(Iconfont, {
38
+ type: "pisell2-credit-card-02",
37
39
  style: {
38
40
  fontSize: "46px",
39
41
  color: "#fff"
40
42
  }
41
- }));
43
+ }) : /* @__PURE__ */ React.createElement("svg", {
44
+ viewBox: "0 0 32 32",
45
+ width: "48",
46
+ height: "48",
47
+ fill: "none",
48
+ stroke: "#fff",
49
+ strokeWidth: "1.8",
50
+ strokeLinecap: "round",
51
+ strokeLinejoin: "round",
52
+ focusable: "false"
53
+ }, isCash ? /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("rect", {
54
+ x: "3",
55
+ y: "6",
56
+ width: "26",
57
+ height: "17",
58
+ rx: "3"
59
+ }), /* @__PURE__ */ React.createElement("path", { d: "M7 26h18M3 11a5 5 0 0 0 5-5m16 0a5 5 0 0 0 5 5M3 18a5 5 0 0 1 5 5m16 0a5 5 0 0 1 5-5" }), /* @__PURE__ */ React.createElement("ellipse", {
60
+ cx: "16",
61
+ cy: "14.5",
62
+ rx: "3.5",
63
+ ry: "4.5"
64
+ })) : /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("rect", {
65
+ x: "7",
66
+ y: "4",
67
+ width: "14",
68
+ height: "9",
69
+ rx: "2"
70
+ }), /* @__PURE__ */ React.createElement("path", { d: "M11 8.5h6M14 13v3M8 16h16l4 7v4a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1v-4l4-7ZM4 23h24M13 25.5h6M10 19.5h2m3 0h2m3 0h2" }))));
42
71
  }
43
72
  function CheckoutScreen({ model, orderBar, send }) {
44
- var _model$paymentFeedbac;
73
+ var _model$paymentFeedbac2, _model$paymentFeedbac4, _model$paymentFeedbac5;
45
74
  const sendRef = useRef(send);
46
75
  sendRef.current = send;
47
76
  const goBack = useCallback(() => {
@@ -53,6 +82,47 @@ function CheckoutScreen({ model, orderBar, send }) {
53
82
  const canReturnToCart = Boolean(orderBar && orderBar.cartLineCount > 0) && model.canLeavePayment;
54
83
  const [restartOrderOpen, setRestartOrderOpen] = useState(false);
55
84
  const [dismissedFeedbackKey, setDismissedFeedbackKey] = useState();
85
+ const automaticPaymentHandled = useRef(false);
86
+ const confirmNoPayment = useCallback(() => {
87
+ var _model$paymentFeedbac;
88
+ automaticPaymentHandled.current = true;
89
+ setDismissedFeedbackKey((_model$paymentFeedbac = model.paymentFeedback) === null || _model$paymentFeedbac === void 0 ? void 0 : _model$paymentFeedbac.key);
90
+ sendRef.current({
91
+ kind: "command",
92
+ command: "checkout.completeNoPayment"
93
+ });
94
+ }, [(_model$paymentFeedbac2 = model.paymentFeedback) === null || _model$paymentFeedbac2 === void 0 ? void 0 : _model$paymentFeedbac2.key]);
95
+ const selectPayment = useCallback((method) => {
96
+ var _model$paymentFeedbac3;
97
+ automaticPaymentHandled.current = true;
98
+ setDismissedFeedbackKey((_model$paymentFeedbac3 = model.paymentFeedback) === null || _model$paymentFeedbac3 === void 0 ? void 0 : _model$paymentFeedbac3.key);
99
+ sendRef.current({
100
+ kind: "command",
101
+ command: method.eftpos ? "checkout.payEftpos" : "checkout.requestStaffPaymentApproval",
102
+ input: { paymentMethodId: method.id }
103
+ });
104
+ }, [(_model$paymentFeedbac4 = model.paymentFeedback) === null || _model$paymentFeedbac4 === void 0 ? void 0 : _model$paymentFeedbac4.key]);
105
+ useEffect(() => {
106
+ if (model.paymentFeedback) automaticPaymentHandled.current = true;
107
+ if (automaticPaymentHandled.current || model.busy || model.resetting || model.paymentResult || model.paymentResultPending || restartOrderOpen || !model.totalText) return;
108
+ let startPayment;
109
+ if (model.noPaymentRequired) {
110
+ if (model.canCompleteNoPayment) startPayment = confirmNoPayment;
111
+ } else if (model.canSelectPayment && !model.paymentMethodsLoading && !model.paymentMethodsErrorReference && model.paymentMethods.length === 1) startPayment = () => selectPayment(model.paymentMethods[0]);
112
+ if (!startPayment) return;
113
+ let cancelled = false;
114
+ Promise.resolve().then(() => {
115
+ if (!cancelled && !automaticPaymentHandled.current) startPayment();
116
+ });
117
+ return () => {
118
+ cancelled = true;
119
+ };
120
+ }, [
121
+ model,
122
+ restartOrderOpen,
123
+ confirmNoPayment,
124
+ selectPayment
125
+ ]);
56
126
  const [returnCountdown, setReturnCountdown] = useState(10);
57
127
  const resetOrder = useCallback((source) => sendRef.current({
58
128
  kind: "session",
@@ -148,11 +218,7 @@ function CheckoutScreen({ model, orderBar, send }) {
148
218
  role: "status"
149
219
  }, /* @__PURE__ */ React.createElement("span", { className: "hdl-operation-overlay__spinner" }), /* @__PURE__ */ React.createElement("strong", null, locales.getText("pisell2.hdl-kiosk.payment-processing"))));
150
220
  const paymentDisabled = !model.canSelectPayment || !model.totalText;
151
- const visibleFeedback = ((_model$paymentFeedbac = model.paymentFeedback) === null || _model$paymentFeedbac === void 0 ? void 0 : _model$paymentFeedbac.key) === dismissedFeedbackKey ? void 0 : model.paymentFeedback;
152
- const dismissCurrentFeedback = () => {
153
- var _model$paymentFeedbac2;
154
- return setDismissedFeedbackKey((_model$paymentFeedbac2 = model.paymentFeedback) === null || _model$paymentFeedbac2 === void 0 ? void 0 : _model$paymentFeedbac2.key);
155
- };
221
+ const visibleFeedback = ((_model$paymentFeedbac5 = model.paymentFeedback) === null || _model$paymentFeedbac5 === void 0 ? void 0 : _model$paymentFeedbac5.key) === dismissedFeedbackKey ? void 0 : model.paymentFeedback;
156
222
  return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("section", {
157
223
  className: "hdl-checkout-screen",
158
224
  "aria-labelledby": "hdl-payment-method-title"
@@ -167,13 +233,7 @@ function CheckoutScreen({ model, orderBar, send }) {
167
233
  className: "hdl-payment-method hdl-no-payment-confirm",
168
234
  "aria-busy": model.busy,
169
235
  disabled: !model.canCompleteNoPayment,
170
- onClick: () => {
171
- dismissCurrentFeedback();
172
- send({
173
- kind: "command",
174
- command: "checkout.completeNoPayment"
175
- });
176
- }
236
+ onClick: confirmNoPayment
177
237
  }, /* @__PURE__ */ React.createElement("span", { className: "hdl-no-payment-confirm__icon" }, /* @__PURE__ */ React.createElement(ConfirmOrderIcon, null)), /* @__PURE__ */ React.createElement("strong", null, locales.getText(model.busy ? "pisell2.hdl-kiosk.no-payment-confirming" : "pisell2.hdl-kiosk.no-payment-confirm")), /* @__PURE__ */ React.createElement(NextIcon, null)) : /* @__PURE__ */ React.createElement(React.Fragment, null, model.paymentMethodsLoading ? /* @__PURE__ */ React.createElement("p", {
178
238
  className: "hdl-payment-methods__notice",
179
239
  role: "status"
@@ -182,32 +242,21 @@ function CheckoutScreen({ model, orderBar, send }) {
182
242
  role: model.paymentMethodsErrorReference ? "alert" : "status"
183
243
  }, locales.getText("pisell2.hdl-kiosk.payment-methods-unavailable")) : null, model.paymentMethods.map((method) => {
184
244
  const eftpos = method.eftpos;
245
+ const displayName = method.name.replace(/-Linkly/g, "");
185
246
  return /* @__PURE__ */ React.createElement("button", {
186
247
  key: method.id,
187
248
  type: "button",
188
249
  className: `hdl-payment-method hdl-payment-method--${eftpos ? "card" : "cash"}`,
189
- "aria-label": method.name,
250
+ "aria-label": displayName,
190
251
  disabled: paymentDisabled,
191
- onClick: () => {
192
- dismissCurrentFeedback();
193
- if (eftpos) {
194
- send({
195
- kind: "command",
196
- command: "checkout.payEftpos",
197
- input: { paymentMethodId: method.id }
198
- });
199
- return;
200
- }
201
- send({
202
- kind: "command",
203
- command: "checkout.requestStaffPaymentApproval",
204
- input: { paymentMethodId: method.id }
205
- });
206
- }
252
+ onClick: () => selectPayment(method)
207
253
  }, /* @__PURE__ */ React.createElement(PaymentMethodIcon, {
208
254
  code: method.code,
209
- type: method.type
210
- }), /* @__PURE__ */ React.createElement("span", null, /* @__PURE__ */ React.createElement("strong", null, method.name)), /* @__PURE__ */ React.createElement(NextIcon, null));
255
+ name: method.name,
256
+ type: method.type,
257
+ eftpos: method.eftpos,
258
+ cash: method.cash
259
+ }), /* @__PURE__ */ React.createElement("span", null, /* @__PURE__ */ React.createElement("strong", null, displayName)), /* @__PURE__ */ React.createElement(NextIcon, null));
211
260
  }))), /* @__PURE__ */ React.createElement("div", { className: "hdl-payment-restart-section" }, /* @__PURE__ */ React.createElement(RestartOrderButton, {
212
261
  disabled: !model.canRestartOrder,
213
262
  title: model.restartOrderBlockedReason,
@@ -71,10 +71,13 @@ function createCheckoutScreenModel(snapshot, sales, payment, completed = false,
71
71
  busy: snapshot.status === "running",
72
72
  noPaymentRequired,
73
73
  canCompleteNoPayment: noPaymentRequired && interactionAvailable,
74
- paymentMethods: payment.methods,
74
+ paymentMethods: payment.methods.map((method) => {
75
+ var _method$metadata, _method$metadata2;
76
+ return _objectSpread2(_objectSpread2({}, method), {}, { cash: method.type === "custom" && (((_method$metadata = method.metadata) === null || _method$metadata === void 0 ? void 0 : _method$metadata.order_open_cash_drawer) === 1 || ((_method$metadata2 = method.metadata) === null || _method$metadata2 === void 0 ? void 0 : _method$metadata2.order_open_cash_drawer) === "1") });
77
+ }),
75
78
  paymentMethodsLoading: payment.loading,
76
79
  paymentMethodsErrorReference: payment.errorReference,
77
- canSelectPayment: interactionAvailable,
80
+ canSelectPayment: interactionAvailable && sales.summary.status === "ready",
78
81
  canLeavePayment: interactionAvailable,
79
82
  canRestartOrder: interactionAvailable,
80
83
  restartOrderBlockedReason: paymentSafeToChange ? void 0 : locales.getText("pisell2.hdl-kiosk.restart-order-payment-blocked"),
@@ -117,7 +117,7 @@ const BigSale = ({ osKey = DEFAULT_OS_KEY, enableMultiCurrencySettlement = false
117
117
  variant
118
118
  ]);
119
119
  const isPosProductSelectionFlow = resolvedTemplate !== "kiosk" && isProductSelectionFlow;
120
- const fulfillmentOtherParams = useMemo(() => _objectSpread2(_objectSpread2({}, otherParams), {}, { enablePickupTiming: resolvedTemplate !== "HDLKiosk" }), [otherParams, resolvedTemplate]);
120
+ const fulfillmentOtherParams = useMemo(() => _objectSpread2(_objectSpread2({ enforceSingleBookingStartDate: false }, otherParams), {}, { enablePickupTiming: resolvedTemplate !== "HDLKiosk" }), [otherParams, resolvedTemplate]);
121
121
  const resolvedSaleDetailModuleConfig = useMemo(() => isPosProductSelectionFlow ? _objectSpread2(_objectSpread2({}, saleDetailModuleConfig), {}, { cartItems: _objectSpread2(_objectSpread2({}, saleDetailModuleConfig === null || saleDetailModuleConfig === void 0 ? void 0 : saleDetailModuleConfig.cartItems), {}, { bookingQuantityMode: "editable" }) }) : saleDetailModuleConfig, [isPosProductSelectionFlow, saleDetailModuleConfig]);
122
122
  const runtimeRef = useRef({
123
123
  date: void 0,
@@ -244,6 +244,7 @@ function KioskBigSaleTemplate({ isActive = true, osKey, productListPreferencesCh
244
244
  const app = (_utils$getApp = utils.getApp) === null || _utils$getApp === void 0 ? void 0 : _utils$getApp.call(utils);
245
245
  const hostChannel = String((engineContext === null || engineContext === void 0 || (_engineContext$appHel2 = engineContext.appHelper) === null || _engineContext$appHel2 === void 0 || (_engineContext$appHel2 = _engineContext$appHel2.constants) === null || _engineContext$appHel2 === void 0 || (_engineContext$appHel2 = _engineContext$appHel2.config) === null || _engineContext$appHel2 === void 0 ? void 0 : _engineContext$appHel2.channel) || "").trim().toLowerCase();
246
246
  const shouldUseConsumerPayment = hostChannel === "pc" || hostChannel === "h5";
247
+ const shouldUseFulfillmentCheckout = shouldUseConsumerPayment || platform === "kiosk";
247
248
  const shouldRequireLogin = isRequireLoginChannel(hostChannel);
248
249
  const { isLoggedIn, openLoginModal } = useSalesUserLogin();
249
250
  const [view, setView] = useState(() => normalizeKioskNavigableView(kioskShellLayout, readKioskSessionView(context.sales.bookingTicket)));
@@ -264,8 +265,8 @@ function KioskBigSaleTemplate({ isActive = true, osKey, productListPreferencesCh
264
265
  const fulfillmentOpeningRef = useRef(false);
265
266
  const fulfillmentCheckout = useKioskFulfillmentCheckout({
266
267
  context,
267
- enabled: shouldUseConsumerPayment,
268
- scopeKey: `${osKey || ""}:${businessCode || ""}:${hostChannel}`,
268
+ enabled: shouldUseFulfillmentCheckout,
269
+ scopeKey: `${osKey || ""}:${businessCode || ""}:${hostChannel}:${platform}`,
269
270
  isActive,
270
271
  mobile: hostChannel === "h5"
271
272
  });
@@ -417,7 +418,7 @@ function KioskBigSaleTemplate({ isActive = true, osKey, productListPreferencesCh
417
418
  ...((_saleDetailModuleConf = saleDetailModuleConfig === null || saleDetailModuleConfig === void 0 ? void 0 : saleDetailModuleConfig.hidden) !== null && _saleDetailModuleConf !== void 0 ? _saleDetailModuleConf : []).filter((moduleKey) => !KIOSK_REQUIRED_MODULES.has(moduleKey))
418
419
  ])],
419
420
  cartItems: _objectSpread2(_objectSpread2({}, saleDetailModuleConfig === null || saleDetailModuleConfig === void 0 ? void 0 : saleDetailModuleConfig.cartItems), {}, {
420
- beforeContent: shouldUseConsumerPayment ? saleDetailModuleConfig === null || saleDetailModuleConfig === void 0 || (_saleDetailModuleConf2 = saleDetailModuleConfig.cartItems) === null || _saleDetailModuleConf2 === void 0 ? void 0 : _saleDetailModuleConf2.beforeContent : /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(KioskPickupTiming, {
421
+ beforeContent: shouldUseFulfillmentCheckout ? saleDetailModuleConfig === null || saleDetailModuleConfig === void 0 || (_saleDetailModuleConf2 = saleDetailModuleConfig.cartItems) === null || _saleDetailModuleConf2 === void 0 ? void 0 : _saleDetailModuleConf2.beforeContent : /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(KioskPickupTiming, {
421
422
  key: `${osKey || ""}:${businessCode || ""}:${hostChannel}:${String(((_context$sales$tempOr = context.sales.tempOrder) === null || _context$sales$tempOr === void 0 || (_context$sales$tempOr = _context$sales$tempOr._extend) === null || _context$sales$tempOr === void 0 ? void 0 : _context$sales$tempOr.localId) || ((_context$sales$tempOr2 = context.sales.tempOrder) === null || _context$sales$tempOr2 === void 0 ? void 0 : _context$sales$tempOr2.external_sale_number) || ((_context$sales$tempOr3 = context.sales.tempOrder) === null || _context$sales$tempOr3 === void 0 ? void 0 : _context$sales$tempOr3.order_id) || orderId || "draft")}`,
422
423
  context,
423
424
  mobile: variant === "phone",
@@ -463,7 +464,7 @@ function KioskBigSaleTemplate({ isActive = true, osKey, productListPreferencesCh
463
464
  orderId,
464
465
  osKey,
465
466
  pickupTimingError,
466
- shouldUseConsumerPayment,
467
+ shouldUseFulfillmentCheckout,
467
468
  saleDetailModuleConfig,
468
469
  requestRemoveItemConfirmation,
469
470
  variant
@@ -645,7 +646,7 @@ function KioskBigSaleTemplate({ isActive = true, osKey, productListPreferencesCh
645
646
  };
646
647
  const performCheckout = function() {
647
648
  var _ref22 = _asyncToGenerator(function* () {
648
- if (checkoutOpeningRef.current || !shouldUseConsumerPayment && isPickupTimingPending || cartItemCount === 0) return;
649
+ if (checkoutOpeningRef.current || !shouldUseFulfillmentCheckout && isPickupTimingPending || cartItemCount === 0) return;
649
650
  checkoutOpeningRef.current = true;
650
651
  const openingScope = fulfillmentCheckout.captureScope();
651
652
  const isCurrentCheckoutRequest = () => {
@@ -669,15 +670,15 @@ function KioskBigSaleTemplate({ isActive = true, osKey, productListPreferencesCh
669
670
  setPickupTimingError(void 0);
670
671
  try {
671
672
  var _context$sales$bookin4, _context$sales$bookin5;
672
- if (shouldUseConsumerPayment && !(yield fulfillmentCheckout.request(true))) {
673
+ if (shouldUseFulfillmentCheckout && !(yield fulfillmentCheckout.request(true))) {
673
674
  setNavigableView("cart");
674
675
  return;
675
676
  }
676
- if (shouldUseConsumerPayment && !fulfillmentCheckout.isCurrent(openingScope)) return;
677
+ if (shouldUseFulfillmentCheckout && !fulfillmentCheckout.isCurrent(openingScope)) return;
677
678
  yield context.cart.waitForCartConsistency();
678
- if (shouldUseConsumerPayment && !fulfillmentCheckout.isCurrent(openingScope)) return;
679
+ if (shouldUseFulfillmentCheckout && !fulfillmentCheckout.isCurrent(openingScope)) return;
679
680
  yield (_context$sales$bookin4 = context.sales.bookingTicket) === null || _context$sales$bookin4 === void 0 || (_context$sales$bookin5 = _context$sales$bookin4.preparePickupTimingForCheckout) === null || _context$sales$bookin5 === void 0 ? void 0 : _context$sales$bookin5.call(_context$sales$bookin4);
680
- if (shouldUseConsumerPayment && !fulfillmentCheckout.isCurrent(openingScope)) return;
681
+ if (shouldUseFulfillmentCheckout && !fulfillmentCheckout.isCurrent(openingScope)) return;
681
682
  context.cart.refreshCartSnapshot();
682
683
  if (!isCurrentCheckoutRequest()) return;
683
684
  } catch (reason) {
@@ -940,7 +941,7 @@ function KioskBigSaleTemplate({ isActive = true, osKey, productListPreferencesCh
940
941
  const beginCheckoutWithFulfillment = function() {
941
942
  var _ref25 = _asyncToGenerator(function* () {
942
943
  if (!(yield businessAvailability.ensureCanShop())) return;
943
- if (!shouldUseConsumerPayment) {
944
+ if (!shouldUseFulfillmentCheckout) {
944
945
  continueCheckout();
945
946
  return;
946
947
  }
@@ -996,9 +997,9 @@ function KioskBigSaleTemplate({ isActive = true, osKey, productListPreferencesCh
996
997
  openCustomerAuth: (payload) => salesHostBridges.customerAuth.request(payload),
997
998
  setOrderCustomer: (_context$sales$bookin31 = context.sales.bookingTicket) === null || _context$sales$bookin31 === void 0 || (_context$sales$bookin31 = _context$sales$bookin31.setOrderCustomer) === null || _context$sales$bookin31 === void 0 ? void 0 : _context$sales$bookin31.bind(context.sales.bookingTicket),
998
999
  loadDiscountConfig: () => context.cart.loadDiscountConfig(),
999
- isActive: () => isActiveRef.current && (!shouldUseConsumerPayment || fulfillmentCheckout.isCurrent(openingScope))
1000
+ isActive: () => isActiveRef.current && (!shouldUseFulfillmentCheckout || fulfillmentCheckout.isCurrent(openingScope))
1000
1001
  }).then((canProceed) => {
1001
- if (canProceed && isActiveRef.current && (!shouldUseConsumerPayment || fulfillmentCheckout.isCurrent(openingScope))) return beginCheckoutWithFulfillment();
1002
+ if (canProceed && isActiveRef.current && (!shouldUseFulfillmentCheckout || fulfillmentCheckout.isCurrent(openingScope))) return beginCheckoutWithFulfillment();
1002
1003
  }).catch((error) => {
1003
1004
  console.warn("[KioskBigSale] Login2 登录后同步下单客户失败", error);
1004
1005
  }).finally(() => {
@@ -1015,7 +1016,7 @@ function KioskBigSaleTemplate({ isActive = true, osKey, productListPreferencesCh
1015
1016
  },
1016
1017
  callback: createKioskLoginContinuationHandler({
1017
1018
  continueCheckout: beginCheckoutWithFulfillment,
1018
- isActive: () => isActiveRef.current && (!shouldUseConsumerPayment || fulfillmentCheckout.isCurrent(openingScope)),
1019
+ isActive: () => isActiveRef.current && (!shouldUseFulfillmentCheckout || fulfillmentCheckout.isCurrent(openingScope)),
1019
1020
  syncAuthenticatedOrderCustomer: () => syncKioskAuthenticatedOrderCustomer({
1020
1021
  bookingTicket: context.sales.bookingTicket,
1021
1022
  loadDiscountConfig: () => context.cart.loadDiscountConfig()
@@ -1147,8 +1148,8 @@ function KioskBigSaleTemplate({ isActive = true, osKey, productListPreferencesCh
1147
1148
  })) : null, layoutState.showCart ? /* @__PURE__ */ React.createElement("section", {
1148
1149
  "aria-label": locales.getText("pisell2.big-sale.kiosk.your-order"),
1149
1150
  className: "pisell-kiosk-sale__screen pisell-kiosk-sale__cart-screen",
1150
- "data-fulfillment": !shouldUseConsumerPayment && isPickupTimingVisible ? "true" : "false"
1151
- }, shouldUseConsumerPayment || !isPickupTimingVisible ? /* @__PURE__ */ React.createElement("header", { className: "pisell-kiosk-sale__cart-header" }, /* @__PURE__ */ React.createElement("h1", null, locales.getText("pisell2.big-sale.kiosk.your-order"), " ", "(", cartItemCount, ")")) : null, /* @__PURE__ */ React.createElement("div", { className: "pisell-kiosk-sale__cart-body" }, shouldUseConsumerPayment && pickupTimingError ? /* @__PURE__ */ React.createElement(Alert, {
1151
+ "data-fulfillment": !shouldUseFulfillmentCheckout && isPickupTimingVisible ? "true" : "false"
1152
+ }, shouldUseFulfillmentCheckout || !isPickupTimingVisible ? /* @__PURE__ */ React.createElement("header", { className: "pisell-kiosk-sale__cart-header" }, /* @__PURE__ */ React.createElement("h1", null, locales.getText("pisell2.big-sale.kiosk.your-order"), " ", "(", cartItemCount, ")")) : null, /* @__PURE__ */ React.createElement("div", { className: "pisell-kiosk-sale__cart-body" }, shouldUseFulfillmentCheckout && pickupTimingError ? /* @__PURE__ */ React.createElement(Alert, {
1152
1153
  type: "error",
1153
1154
  showIcon: true,
1154
1155
  message: pickupTimingError,
@@ -1176,7 +1177,7 @@ function KioskBigSaleTemplate({ isActive = true, osKey, productListPreferencesCh
1176
1177
  promotionAppliedCount: selectedCustomerVoucherCount,
1177
1178
  onAddNote: openOrderNoteModal,
1178
1179
  onBack: handleCapsuleBack,
1179
- checkoutLoading: isCheckoutLoading || !shouldUseConsumerPayment && view === "cart" && isPickupTimingPending,
1180
+ checkoutLoading: isCheckoutLoading || !shouldUseFulfillmentCheckout && view === "cart" && isPickupTimingPending,
1180
1181
  checkoutDisabled: shoppingBlocked,
1181
1182
  onCheckout: handleCheckout,
1182
1183
  onTogglePromotion: isVirtualSettlementOrder ? void 0 : handleToggleFloatingPromotion,
@@ -63,7 +63,7 @@ function KioskSale(props) {
63
63
  const { menu_list_ids: _ignoredMenuListIds } = productLoadParams;
64
64
  return _objectWithoutProperties(productLoadParams, _excluded2);
65
65
  }, [productLoadParams]);
66
- const resolvedOtherParams = useMemo(() => _objectSpread2(_objectSpread2(_objectSpread2({}, otherParams || {}), channel ? { channel } : {}), {}, { enableBusinessAvailability: Boolean(kioskPresentation.platform) }, kioskPresentation.platform ? { platform: kioskPresentation.platform } : {}), [
66
+ const resolvedOtherParams = useMemo(() => _objectSpread2(_objectSpread2(_objectSpread2({}, otherParams || {}), {}, { enforceSingleBookingStartDate: true }, channel ? { channel } : {}), {}, { enableBusinessAvailability: Boolean(kioskPresentation.platform) }, kioskPresentation.platform ? { platform: kioskPresentation.platform } : {}), [
67
67
  channel,
68
68
  kioskPresentation.platform,
69
69
  otherParams
@@ -1,10 +1,10 @@
1
1
  import { _objectSpread2 } from "../../../_virtual/_@oxc-project_runtime@0.122.0/helpers/objectSpread2.js";
2
2
  import dayjs from "dayjs";
3
- import timezone from "dayjs/plugin/timezone";
4
- import utc from "dayjs/plugin/utc";
3
+ import timezonePlugin from "dayjs/plugin/timezone";
4
+ import utcPlugin from "dayjs/plugin/utc";
5
5
  //#region src/plus/saasDevice/devicePasscodes/model.ts
6
- dayjs.extend(utc);
7
- dayjs.extend(timezone);
6
+ dayjs.extend(utcPlugin);
7
+ dayjs.extend(timezonePlugin);
8
8
  const INITIAL_DEVICE_PASSCODE_STATE = {
9
9
  deviceIds: [],
10
10
  devicesById: {}
@@ -983,7 +983,8 @@ const SalesSdkCartProvider = ({ children, normalProductDetailConfig, deferHolder
983
983
  }
984
984
  return products;
985
985
  }
986
- const products = yield bookingTicket.addProductToOrder(productToAdd, booking, Object.keys(addOptions).length > 0 ? addOptions : void 0);
986
+ let products = yield bookingTicket.addProductToOrder(productToAdd, booking, Object.keys(addOptions).length > 0 ? addOptions : void 0);
987
+ if (booking && bookingTicket.removeBookingProductsOutsideStartDate) products = yield bookingTicket.removeBookingProductsOutsideStartDate(booking.start_date);
987
988
  const deferredConsistencyRefresh = scheduleDeferredAddConsistencyRefresh();
988
989
  refreshCartSnapshot(deferredConsistencyRefresh.refreshVersion);
989
990
  yield deferredConsistencyRefresh.promise;
@@ -1028,6 +1028,7 @@ interface BookingTicketHandle extends PickupTimingHandle {
1028
1028
  setSalesNote?: (input: SalesSdkSetSalesNoteInput) => Promise<SalesSdkSalesNote>;
1029
1029
  removeSalesNote?: (uuid: string) => Promise<void>;
1030
1030
  getOrderProducts: () => ScanOrderOrderProduct[];
1031
+ removeBookingProductsOutsideStartDate?: (startDate: unknown) => Promise<ScanOrderOrderProduct[]>;
1031
1032
  getDiscountList: () => any[];
1032
1033
  getOriginalDiscountList?: () => any[];
1033
1034
  replaceDiscountStoreLists?: (params: {
@@ -581,6 +581,7 @@ function _editCartLineBooking() {
581
581
  }, allowBookingReprice ? { allow_booking_reprice: true } : {}));
582
582
  }
583
583
  commitLifecycle === null || commitLifecycle === void 0 || commitLifecycle.beforeCommit();
584
+ if (bookingTicket.removeBookingProductsOutsideStartDate) yield bookingTicket.removeBookingProductsOutsideStartDate(bookingPatch === null || bookingPatch === void 0 ? void 0 : bookingPatch.start_date);
584
585
  products = input.syncQuantityByRows ? yield input.syncQuantityByRows({
585
586
  sources: targets,
586
587
  targetQuantity,
@@ -6,12 +6,12 @@ import React, { useCallback, useEffect, useMemo, useRef } from "react";
6
6
  import { locales } from "@pisell/utils";
7
7
  import { Button, PisellEmpty, PisellModal, PisellStatisticList, Skeleton, Timeline, usePisellConfig } from "@pisell/materials";
8
8
  import { useRequest } from "ahooks";
9
- import timezone from "dayjs/plugin/timezone";
10
- import utc from "dayjs/plugin/utc";
9
+ import timezonePlugin from "dayjs/plugin/timezone";
10
+ import utcPlugin from "dayjs/plugin/utc";
11
11
  import "./index.less";
12
12
  //#region src/plus/walletPassGallery/components/timelineSection/index.tsx
13
- dayjs.extend(timezone);
14
- dayjs.extend(utc);
13
+ dayjs.extend(timezonePlugin);
14
+ dayjs.extend(utcPlugin);
15
15
  const stateTimeUnix = 1723255863;
16
16
  const POLL_INTERVAL = 2e3;
17
17
  const POLL_MAX_TIMES = 5;
@@ -27,23 +27,52 @@ function ConfirmOrderIcon() {
27
27
  "aria-hidden": "true"
28
28
  }, /* @__PURE__ */ react.default.createElement("path", { d: "m5 12 4 4L19 6" }));
29
29
  }
30
- /** 与 PaymentModal 一致:EFTPOS/信用卡使用 credit,其余自定义方式使用 custom。 */
31
- function PaymentMethodIcon({ code, type }) {
32
- const isCard = code === "EFTPOS" || type === "credit-card" || type === "eftpos";
30
+ /** 名称含 cash 时优先展示纸币,否则按卡支付、现金配置和自定义支付区分。 */
31
+ function PaymentMethodIcon({ code, name, type, eftpos, cash }) {
32
+ const nameContainsCash = /cash/i.test(name);
33
+ const isCash = nameContainsCash || cash;
34
+ const isCard = !nameContainsCash && (eftpos || code === "EFTPOS" || type === "credit-card" || type === "eftpos");
33
35
  return /* @__PURE__ */ react.default.createElement("span", {
34
36
  className: "hdl-payment-method__icon",
35
- style: { background: isCard ? "#FE8279" : "#D277E4" },
37
+ style: { background: isCard ? "#FE8279" : isCash ? "#D69B28" : "#D277E4" },
36
38
  "aria-hidden": "true"
37
- }, /* @__PURE__ */ react.default.createElement(_pisell_materials.Iconfont, {
38
- type: isCard ? "pisell2-credit" : "pisell2-custom",
39
+ }, isCard ? /* @__PURE__ */ react.default.createElement(_pisell_materials.Iconfont, {
40
+ type: "pisell2-credit-card-02",
39
41
  style: {
40
42
  fontSize: "46px",
41
43
  color: "#fff"
42
44
  }
43
- }));
45
+ }) : /* @__PURE__ */ react.default.createElement("svg", {
46
+ viewBox: "0 0 32 32",
47
+ width: "48",
48
+ height: "48",
49
+ fill: "none",
50
+ stroke: "#fff",
51
+ strokeWidth: "1.8",
52
+ strokeLinecap: "round",
53
+ strokeLinejoin: "round",
54
+ focusable: "false"
55
+ }, isCash ? /* @__PURE__ */ react.default.createElement(react.default.Fragment, null, /* @__PURE__ */ react.default.createElement("rect", {
56
+ x: "3",
57
+ y: "6",
58
+ width: "26",
59
+ height: "17",
60
+ rx: "3"
61
+ }), /* @__PURE__ */ react.default.createElement("path", { d: "M7 26h18M3 11a5 5 0 0 0 5-5m16 0a5 5 0 0 0 5 5M3 18a5 5 0 0 1 5 5m16 0a5 5 0 0 1 5-5" }), /* @__PURE__ */ react.default.createElement("ellipse", {
62
+ cx: "16",
63
+ cy: "14.5",
64
+ rx: "3.5",
65
+ ry: "4.5"
66
+ })) : /* @__PURE__ */ react.default.createElement(react.default.Fragment, null, /* @__PURE__ */ react.default.createElement("rect", {
67
+ x: "7",
68
+ y: "4",
69
+ width: "14",
70
+ height: "9",
71
+ rx: "2"
72
+ }), /* @__PURE__ */ react.default.createElement("path", { d: "M11 8.5h6M14 13v3M8 16h16l4 7v4a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1v-4l4-7ZM4 23h24M13 25.5h6M10 19.5h2m3 0h2m3 0h2" }))));
44
73
  }
45
74
  function CheckoutScreen({ model, orderBar, send }) {
46
- var _model$paymentFeedbac;
75
+ var _model$paymentFeedbac2, _model$paymentFeedbac4, _model$paymentFeedbac5;
47
76
  const sendRef = (0, react.useRef)(send);
48
77
  sendRef.current = send;
49
78
  const goBack = (0, react.useCallback)(() => {
@@ -55,6 +84,47 @@ function CheckoutScreen({ model, orderBar, send }) {
55
84
  const canReturnToCart = Boolean(orderBar && orderBar.cartLineCount > 0) && model.canLeavePayment;
56
85
  const [restartOrderOpen, setRestartOrderOpen] = (0, react.useState)(false);
57
86
  const [dismissedFeedbackKey, setDismissedFeedbackKey] = (0, react.useState)();
87
+ const automaticPaymentHandled = (0, react.useRef)(false);
88
+ const confirmNoPayment = (0, react.useCallback)(() => {
89
+ var _model$paymentFeedbac;
90
+ automaticPaymentHandled.current = true;
91
+ setDismissedFeedbackKey((_model$paymentFeedbac = model.paymentFeedback) === null || _model$paymentFeedbac === void 0 ? void 0 : _model$paymentFeedbac.key);
92
+ sendRef.current({
93
+ kind: "command",
94
+ command: "checkout.completeNoPayment"
95
+ });
96
+ }, [(_model$paymentFeedbac2 = model.paymentFeedback) === null || _model$paymentFeedbac2 === void 0 ? void 0 : _model$paymentFeedbac2.key]);
97
+ const selectPayment = (0, react.useCallback)((method) => {
98
+ var _model$paymentFeedbac3;
99
+ automaticPaymentHandled.current = true;
100
+ setDismissedFeedbackKey((_model$paymentFeedbac3 = model.paymentFeedback) === null || _model$paymentFeedbac3 === void 0 ? void 0 : _model$paymentFeedbac3.key);
101
+ sendRef.current({
102
+ kind: "command",
103
+ command: method.eftpos ? "checkout.payEftpos" : "checkout.requestStaffPaymentApproval",
104
+ input: { paymentMethodId: method.id }
105
+ });
106
+ }, [(_model$paymentFeedbac4 = model.paymentFeedback) === null || _model$paymentFeedbac4 === void 0 ? void 0 : _model$paymentFeedbac4.key]);
107
+ (0, react.useEffect)(() => {
108
+ if (model.paymentFeedback) automaticPaymentHandled.current = true;
109
+ if (automaticPaymentHandled.current || model.busy || model.resetting || model.paymentResult || model.paymentResultPending || restartOrderOpen || !model.totalText) return;
110
+ let startPayment;
111
+ if (model.noPaymentRequired) {
112
+ if (model.canCompleteNoPayment) startPayment = confirmNoPayment;
113
+ } else if (model.canSelectPayment && !model.paymentMethodsLoading && !model.paymentMethodsErrorReference && model.paymentMethods.length === 1) startPayment = () => selectPayment(model.paymentMethods[0]);
114
+ if (!startPayment) return;
115
+ let cancelled = false;
116
+ Promise.resolve().then(() => {
117
+ if (!cancelled && !automaticPaymentHandled.current) startPayment();
118
+ });
119
+ return () => {
120
+ cancelled = true;
121
+ };
122
+ }, [
123
+ model,
124
+ restartOrderOpen,
125
+ confirmNoPayment,
126
+ selectPayment
127
+ ]);
58
128
  const [returnCountdown, setReturnCountdown] = (0, react.useState)(10);
59
129
  const resetOrder = (0, react.useCallback)((source) => sendRef.current({
60
130
  kind: "session",
@@ -150,11 +220,7 @@ function CheckoutScreen({ model, orderBar, send }) {
150
220
  role: "status"
151
221
  }, /* @__PURE__ */ react.default.createElement("span", { className: "hdl-operation-overlay__spinner" }), /* @__PURE__ */ react.default.createElement("strong", null, _pisell_utils.locales.getText("pisell2.hdl-kiosk.payment-processing"))));
152
222
  const paymentDisabled = !model.canSelectPayment || !model.totalText;
153
- const visibleFeedback = ((_model$paymentFeedbac = model.paymentFeedback) === null || _model$paymentFeedbac === void 0 ? void 0 : _model$paymentFeedbac.key) === dismissedFeedbackKey ? void 0 : model.paymentFeedback;
154
- const dismissCurrentFeedback = () => {
155
- var _model$paymentFeedbac2;
156
- return setDismissedFeedbackKey((_model$paymentFeedbac2 = model.paymentFeedback) === null || _model$paymentFeedbac2 === void 0 ? void 0 : _model$paymentFeedbac2.key);
157
- };
223
+ const visibleFeedback = ((_model$paymentFeedbac5 = model.paymentFeedback) === null || _model$paymentFeedbac5 === void 0 ? void 0 : _model$paymentFeedbac5.key) === dismissedFeedbackKey ? void 0 : model.paymentFeedback;
158
224
  return /* @__PURE__ */ react.default.createElement(react.default.Fragment, null, /* @__PURE__ */ react.default.createElement("section", {
159
225
  className: "hdl-checkout-screen",
160
226
  "aria-labelledby": "hdl-payment-method-title"
@@ -169,13 +235,7 @@ function CheckoutScreen({ model, orderBar, send }) {
169
235
  className: "hdl-payment-method hdl-no-payment-confirm",
170
236
  "aria-busy": model.busy,
171
237
  disabled: !model.canCompleteNoPayment,
172
- onClick: () => {
173
- dismissCurrentFeedback();
174
- send({
175
- kind: "command",
176
- command: "checkout.completeNoPayment"
177
- });
178
- }
238
+ onClick: confirmNoPayment
179
239
  }, /* @__PURE__ */ react.default.createElement("span", { className: "hdl-no-payment-confirm__icon" }, /* @__PURE__ */ react.default.createElement(ConfirmOrderIcon, null)), /* @__PURE__ */ react.default.createElement("strong", null, _pisell_utils.locales.getText(model.busy ? "pisell2.hdl-kiosk.no-payment-confirming" : "pisell2.hdl-kiosk.no-payment-confirm")), /* @__PURE__ */ react.default.createElement(NextIcon, null)) : /* @__PURE__ */ react.default.createElement(react.default.Fragment, null, model.paymentMethodsLoading ? /* @__PURE__ */ react.default.createElement("p", {
180
240
  className: "hdl-payment-methods__notice",
181
241
  role: "status"
@@ -184,32 +244,21 @@ function CheckoutScreen({ model, orderBar, send }) {
184
244
  role: model.paymentMethodsErrorReference ? "alert" : "status"
185
245
  }, _pisell_utils.locales.getText("pisell2.hdl-kiosk.payment-methods-unavailable")) : null, model.paymentMethods.map((method) => {
186
246
  const eftpos = method.eftpos;
247
+ const displayName = method.name.replace(/-Linkly/g, "");
187
248
  return /* @__PURE__ */ react.default.createElement("button", {
188
249
  key: method.id,
189
250
  type: "button",
190
251
  className: `hdl-payment-method hdl-payment-method--${eftpos ? "card" : "cash"}`,
191
- "aria-label": method.name,
252
+ "aria-label": displayName,
192
253
  disabled: paymentDisabled,
193
- onClick: () => {
194
- dismissCurrentFeedback();
195
- if (eftpos) {
196
- send({
197
- kind: "command",
198
- command: "checkout.payEftpos",
199
- input: { paymentMethodId: method.id }
200
- });
201
- return;
202
- }
203
- send({
204
- kind: "command",
205
- command: "checkout.requestStaffPaymentApproval",
206
- input: { paymentMethodId: method.id }
207
- });
208
- }
254
+ onClick: () => selectPayment(method)
209
255
  }, /* @__PURE__ */ react.default.createElement(PaymentMethodIcon, {
210
256
  code: method.code,
211
- type: method.type
212
- }), /* @__PURE__ */ react.default.createElement("span", null, /* @__PURE__ */ react.default.createElement("strong", null, method.name)), /* @__PURE__ */ react.default.createElement(NextIcon, null));
257
+ name: method.name,
258
+ type: method.type,
259
+ eftpos: method.eftpos,
260
+ cash: method.cash
261
+ }), /* @__PURE__ */ react.default.createElement("span", null, /* @__PURE__ */ react.default.createElement("strong", null, displayName)), /* @__PURE__ */ react.default.createElement(NextIcon, null));
213
262
  }))), /* @__PURE__ */ react.default.createElement("div", { className: "hdl-payment-restart-section" }, /* @__PURE__ */ react.default.createElement(require_index$3.RestartOrderButton, {
214
263
  disabled: !model.canRestartOrder,
215
264
  title: model.restartOrderBlockedReason,
@@ -73,10 +73,13 @@ function createCheckoutScreenModel(snapshot, sales, payment, completed = false,
73
73
  busy: snapshot.status === "running",
74
74
  noPaymentRequired,
75
75
  canCompleteNoPayment: noPaymentRequired && interactionAvailable,
76
- paymentMethods: payment.methods,
76
+ paymentMethods: payment.methods.map((method) => {
77
+ var _method$metadata, _method$metadata2;
78
+ return require_objectSpread2._objectSpread2(require_objectSpread2._objectSpread2({}, method), {}, { cash: method.type === "custom" && (((_method$metadata = method.metadata) === null || _method$metadata === void 0 ? void 0 : _method$metadata.order_open_cash_drawer) === 1 || ((_method$metadata2 = method.metadata) === null || _method$metadata2 === void 0 ? void 0 : _method$metadata2.order_open_cash_drawer) === "1") });
79
+ }),
77
80
  paymentMethodsLoading: payment.loading,
78
81
  paymentMethodsErrorReference: payment.errorReference,
79
- canSelectPayment: interactionAvailable,
82
+ canSelectPayment: interactionAvailable && sales.summary.status === "ready",
80
83
  canLeavePayment: interactionAvailable,
81
84
  canRestartOrder: interactionAvailable,
82
85
  restartOrderBlockedReason: paymentSafeToChange ? void 0 : _pisell_utils.locales.getText("pisell2.hdl-kiosk.restart-order-payment-blocked"),
@@ -119,7 +119,7 @@ const BigSale = ({ osKey = DEFAULT_OS_KEY, enableMultiCurrencySettlement = false
119
119
  variant
120
120
  ]);
121
121
  const isPosProductSelectionFlow = resolvedTemplate !== "kiosk" && isProductSelectionFlow;
122
- const fulfillmentOtherParams = (0, react.useMemo)(() => require_objectSpread2._objectSpread2(require_objectSpread2._objectSpread2({}, otherParams), {}, { enablePickupTiming: resolvedTemplate !== "HDLKiosk" }), [otherParams, resolvedTemplate]);
122
+ const fulfillmentOtherParams = (0, react.useMemo)(() => require_objectSpread2._objectSpread2(require_objectSpread2._objectSpread2({ enforceSingleBookingStartDate: false }, otherParams), {}, { enablePickupTiming: resolvedTemplate !== "HDLKiosk" }), [otherParams, resolvedTemplate]);
123
123
  const resolvedSaleDetailModuleConfig = (0, react.useMemo)(() => isPosProductSelectionFlow ? require_objectSpread2._objectSpread2(require_objectSpread2._objectSpread2({}, saleDetailModuleConfig), {}, { cartItems: require_objectSpread2._objectSpread2(require_objectSpread2._objectSpread2({}, saleDetailModuleConfig === null || saleDetailModuleConfig === void 0 ? void 0 : saleDetailModuleConfig.cartItems), {}, { bookingQuantityMode: "editable" }) }) : saleDetailModuleConfig, [isPosProductSelectionFlow, saleDetailModuleConfig]);
124
124
  const runtimeRef = (0, react.useRef)({
125
125
  date: void 0,