@pisell/pisellos 0.0.507 → 0.0.508

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.
@@ -235,3 +235,9 @@ export interface ScanOrderLoggerRuntimeConfig {
235
235
  }
236
236
  export interface ScanOrderAddLogParams extends ScanOrderLogInput {
237
237
  }
238
+ /** ScanOrder.scanCode 对外的轻量结果(不含 discountList,UI 在 resolve 后调 getDiscountList) */
239
+ export interface ScanOrderScanCodeResult {
240
+ isAvailable: boolean;
241
+ type?: 'server' | string;
242
+ unavailableReason?: 'time_limit' | string;
243
+ }
@@ -17,4 +17,6 @@ export var ScanOrderHooks = /*#__PURE__*/function (ScanOrderHooks) {
17
17
 
18
18
  /** `resource_capacity[i].capacity_list[j]` */
19
19
 
20
- /** `/order/resource/occupy-detail` 单条 `occupy_details[i]` */
20
+ /** `/order/resource/occupy-detail` 单条 `occupy_details[i]` */
21
+
22
+ /** ScanOrder.scanCode 对外的轻量结果(不含 discountList,UI 在 resolve 后调 getDiscountList) */
@@ -0,0 +1,49 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
20
+ // If the importer is in node compatibility mode or this is not an ESM
21
+ // file that has been converted to a CommonJS file using a Babel-
22
+ // compatible transform (i.e. "__esModule" has not been set), then set
23
+ // "default" to the CommonJS "module.exports" for node compatibility.
24
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
25
+ mod
26
+ ));
27
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
28
+
29
+ // src/model/strategy/adapter/promotion/index.ts
30
+ var promotion_exports = {};
31
+ __export(promotion_exports, {
32
+ BUY_X_GET_Y_FREE_STRATEGY: () => import_examples.BUY_X_GET_Y_FREE_STRATEGY,
33
+ PromotionAdapter: () => import_adapter.PromotionAdapter,
34
+ PromotionEvaluator: () => import_evaluator.PromotionEvaluator,
35
+ X_ITEMS_FOR_Y_PRICE_STRATEGY: () => import_examples.X_ITEMS_FOR_Y_PRICE_STRATEGY,
36
+ default: () => import_adapter2.default
37
+ });
38
+ module.exports = __toCommonJS(promotion_exports);
39
+ var import_evaluator = require("./evaluator");
40
+ var import_adapter = require("./adapter");
41
+ var import_adapter2 = __toESM(require("./adapter"));
42
+ var import_examples = require("./examples");
43
+ // Annotate the CommonJS export names for ESM import in node:
44
+ 0 && (module.exports = {
45
+ BUY_X_GET_Y_FREE_STRATEGY,
46
+ PromotionAdapter,
47
+ PromotionEvaluator,
48
+ X_ITEMS_FOR_Y_PRICE_STRATEGY
49
+ });
@@ -86,7 +86,7 @@ export declare class OrderModule extends BaseModule implements Module, OrderModu
86
86
  enhancePayload?: SubmitPayloadEnhancer;
87
87
  }): Promise<T>;
88
88
  createOrder(params: CommitOrderParams['query']): {
89
- type: "appointment_booking" | "virtual";
89
+ type: "virtual" | "appointment_booking";
90
90
  platform: string;
91
91
  sales_channel: string;
92
92
  order_sales_channel: string;
@@ -311,7 +311,7 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
311
311
  date: string;
312
312
  status: string;
313
313
  week: string;
314
- weekNum: 0 | 2 | 1 | 3 | 5 | 4 | 6;
314
+ weekNum: 0 | 1 | 2 | 3 | 4 | 5 | 6;
315
315
  }[]>;
316
316
  submitTimeSlot(timeSlots: TimeSliceItem): void;
317
317
  private getScheduleDataByIds;
@@ -131,7 +131,7 @@ export declare class BookingTicketImpl extends BaseModule implements Module {
131
131
  * 获取当前的客户搜索条件
132
132
  * @returns 当前搜索条件
133
133
  */
134
- getCurrentCustomerSearchParams(): Omit<import("../../modules").ShopGetCustomerListParams, "skip" | "num">;
134
+ getCurrentCustomerSearchParams(): Omit<import("../../modules").ShopGetCustomerListParams, "num" | "skip">;
135
135
  /**
136
136
  * 获取客户列表状态(包含滚动加载相关状态)
137
137
  * @returns 客户状态
@@ -1,6 +1,7 @@
1
1
  import { Module, ModuleOptions, PisellCore } from '../../types';
2
2
  import { BaseModule } from '../../modules/BaseModule';
3
- import { ScanOrderAddLogParams, ScanOrderAvailabilityInfo, ScanOrderOrderProduct, ScanOrderOrderProductIdentity } from './types';
3
+ import { ScanOrderAddLogParams, ScanOrderAvailabilityInfo, ScanOrderOrderProduct, ScanOrderOrderProductIdentity, ScanOrderScanCodeResult } from './types';
4
+ import type { Discount } from '../../modules/Discount/types';
4
5
  import { type CartItemSummary, type PaxInfo, type QuantityCheckResult, type QuantityLimitResult } from '../../model/strategy/adapter/itemRule';
5
6
  import type { StrategyConfig } from '../../model/strategy/type';
6
7
  export * from './types';
@@ -29,6 +30,10 @@ export declare class ScanOrderImpl extends BaseModule implements Module {
29
30
  private itemRuleRuntimeConfig;
30
31
  /** 最近一次 checkResourceAvailable 从预约规则 link 拉取的商品快照 */
31
32
  private enabledReservationRuleProducts;
33
+ private loginEffectDisposers;
34
+ private customerLoginRefreshInFlight;
35
+ private customerLoginRefreshIdInFlight;
36
+ private static readonly PISELL1_LOGIN_SUCCESS;
32
37
  private getScanOrderLoggerContext;
33
38
  private serializeError;
34
39
  private addScanOrderLog;
@@ -36,6 +41,12 @@ export declare class ScanOrderImpl extends BaseModule implements Module {
36
41
  private logMethodSuccess;
37
42
  private logMethodError;
38
43
  addLog(params: ScanOrderAddLogParams): Promise<void>;
44
+ private normalizeCustomerId;
45
+ private resolveCustomerIdFromLoginPayload;
46
+ private clearLoginEffectListeners;
47
+ private registerLoginEffect;
48
+ private registerCustomerLoginListeners;
49
+ private refreshOrderMarketingAfterLogin;
39
50
  constructor(name?: string, version?: string);
40
51
  initialize(core: PisellCore, options?: ModuleOptions): Promise<void>;
41
52
  destroy(): Promise<void>;
@@ -62,6 +73,15 @@ export declare class ScanOrderImpl extends BaseModule implements Module {
62
73
  restoreOrder(): Promise<import("./types").ScanOrderTempOrder>;
63
74
  getOrderProducts(): ScanOrderOrderProduct[];
64
75
  getSummary(): Promise<import("./types").ScanOrderSummary>;
76
+ getDiscountList(): Discount[];
77
+ scanCode(code: string, customerId?: number): Promise<ScanOrderScanCodeResult>;
78
+ setDiscountSelected(params: {
79
+ discountId: number;
80
+ isSelected: boolean;
81
+ }): Promise<void>;
82
+ onCustomerLogin(params: {
83
+ customerId: number;
84
+ }): Promise<void>;
65
85
  private buildSubmitPayloadEnhancer;
66
86
  submitScanOrder<T = any>(): Promise<T>;
67
87
  addProductToOrder(product: Partial<ScanOrderOrderProduct> & ScanOrderOrderProductIdentity): Promise<ScanOrderOrderProduct[]>;
@@ -35,8 +35,12 @@ __export(ScanOrder_exports, {
35
35
  module.exports = __toCommonJS(ScanOrder_exports);
36
36
  var import_BaseModule = require("../../modules/BaseModule");
37
37
  var import_types = require("./types");
38
+ var import_Order = require("../../modules/Order");
39
+ var import_types2 = require("../../modules/Account/types");
40
+ var import_types3 = require("../RegisterAndLogin/types");
41
+ var import_decimal = __toESM(require("decimal.js"));
38
42
  var import_utils = require("./utils");
39
- var import_types2 = require("../BookingByStep/types");
43
+ var import_types4 = require("../BookingByStep/types");
40
44
  var import_ProductList = require("../../modules/ProductList");
41
45
  var import_Schedule = require("../../modules/Schedule");
42
46
  var import_getDateIsInSchedule = require("../../modules/Schedule/getDateIsInSchedule");
@@ -74,6 +78,9 @@ var _ScanOrderImpl = class extends import_BaseModule.BaseModule {
74
78
  this.itemRuleRuntimeConfig = {};
75
79
  /** 最近一次 checkResourceAvailable 从预约规则 link 拉取的商品快照 */
76
80
  this.enabledReservationRuleProducts = [];
81
+ this.loginEffectDisposers = [];
82
+ this.customerLoginRefreshInFlight = null;
83
+ this.customerLoginRefreshIdInFlight = null;
77
84
  }
78
85
  getScanOrderLoggerContext() {
79
86
  return {
@@ -157,6 +164,102 @@ var _ScanOrderImpl = class extends import_BaseModule.BaseModule {
157
164
  }
158
165
  });
159
166
  }
167
+ normalizeCustomerId(value) {
168
+ const customerId = Number(value);
169
+ if (!Number.isFinite(customerId) || customerId <= 0)
170
+ return null;
171
+ return customerId;
172
+ }
173
+ resolveCustomerIdFromLoginPayload(payload) {
174
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i;
175
+ const candidates = [
176
+ payload == null ? void 0 : payload.customerId,
177
+ payload == null ? void 0 : payload.customer_id,
178
+ payload == null ? void 0 : payload.id,
179
+ (_a = payload == null ? void 0 : payload.user) == null ? void 0 : _a.customerId,
180
+ (_b = payload == null ? void 0 : payload.user) == null ? void 0 : _b.customer_id,
181
+ (_c = payload == null ? void 0 : payload.user) == null ? void 0 : _c.id,
182
+ (_e = (_d = payload == null ? void 0 : payload.user) == null ? void 0 : _d._origin) == null ? void 0 : _e.customer_id,
183
+ (_f = payload == null ? void 0 : payload.account) == null ? void 0 : _f.customerId,
184
+ (_g = payload == null ? void 0 : payload.account) == null ? void 0 : _g.customer_id,
185
+ (_h = payload == null ? void 0 : payload.account) == null ? void 0 : _h.id,
186
+ (_i = payload == null ? void 0 : payload._origin) == null ? void 0 : _i.customer_id
187
+ ];
188
+ for (const candidate of candidates) {
189
+ const customerId = this.normalizeCustomerId(candidate);
190
+ if (customerId)
191
+ return customerId;
192
+ }
193
+ return null;
194
+ }
195
+ clearLoginEffectListeners() {
196
+ for (const dispose of this.loginEffectDisposers) {
197
+ dispose();
198
+ }
199
+ this.loginEffectDisposers = [];
200
+ }
201
+ registerLoginEffect(event, callback) {
202
+ var _a;
203
+ const effects = (_a = this.core) == null ? void 0 : _a.effects;
204
+ if (!(effects == null ? void 0 : effects.on))
205
+ return;
206
+ effects.on(event, callback);
207
+ this.loginEffectDisposers.push(() => {
208
+ if (typeof effects.off === "function") {
209
+ effects.off(event, callback);
210
+ }
211
+ });
212
+ }
213
+ registerCustomerLoginListeners() {
214
+ this.clearLoginEffectListeners();
215
+ const createHandleLogin = () => async (payload) => {
216
+ const customerId = this.resolveCustomerIdFromLoginPayload(payload);
217
+ if (!customerId)
218
+ return;
219
+ await this.refreshOrderMarketingAfterLogin({ customerId });
220
+ };
221
+ this.registerLoginEffect(
222
+ _ScanOrderImpl.PISELL1_LOGIN_SUCCESS,
223
+ createHandleLogin()
224
+ );
225
+ this.registerLoginEffect(import_types2.AccountHooks.OnLogin, createHandleLogin());
226
+ this.registerLoginEffect(
227
+ import_types3.RegisterAndLoginHooks.onLoginSuccess,
228
+ createHandleLogin()
229
+ );
230
+ }
231
+ async refreshOrderMarketingAfterLogin(params) {
232
+ if (!this.store.order)
233
+ throw new Error("order 模块未初始化");
234
+ if (this.customerLoginRefreshInFlight) {
235
+ if (this.customerLoginRefreshIdInFlight === params.customerId) {
236
+ await this.customerLoginRefreshInFlight;
237
+ return;
238
+ }
239
+ await this.customerLoginRefreshInFlight;
240
+ }
241
+ this.customerLoginRefreshIdInFlight = params.customerId;
242
+ const refreshTask = (async () => {
243
+ await this.store.order.loadDiscountConfig({
244
+ customerId: params.customerId
245
+ });
246
+ await this.store.order.recalculateSummary({ createIfMissing: true });
247
+ this.store.order.persistTempOrder();
248
+ await this.refreshItemRuleQuantityLimits();
249
+ await this.refreshCartValidationPassed();
250
+ })();
251
+ this.customerLoginRefreshInFlight = refreshTask;
252
+ try {
253
+ await refreshTask;
254
+ } catch (error) {
255
+ throw error;
256
+ } finally {
257
+ if (this.customerLoginRefreshInFlight === refreshTask) {
258
+ this.customerLoginRefreshInFlight = null;
259
+ this.customerLoginRefreshIdInFlight = null;
260
+ }
261
+ }
262
+ }
160
263
  async initialize(core, options = {}) {
161
264
  var _a, _b, _c, _d, _e, _f;
162
265
  this.logMethodStart("initialize");
@@ -195,7 +298,7 @@ var _ScanOrderImpl = class extends import_BaseModule.BaseModule {
195
298
  ];
196
299
  moduleArr.forEach((step) => {
197
300
  var _a2, _b2, _c2, _d2, _e2, _f2;
198
- const targetModule = (0, import_types2.createModule)(step, this.name);
301
+ const targetModule = (0, import_types4.createModule)(step, this.name);
199
302
  if (targetModule) {
200
303
  this.store[step] = targetModule;
201
304
  const initialState = step === "salesSummary" ? {
@@ -236,6 +339,7 @@ var _ScanOrderImpl = class extends import_BaseModule.BaseModule {
236
339
  fatherModule: this.name
237
340
  }
238
341
  });
342
+ this.registerCustomerLoginListeners();
239
343
  console.log("[ScanOrder] 初始化开始");
240
344
  try {
241
345
  await ((_e = this.store.order) == null ? void 0 : _e.recalculateSummary({ createIfMissing: false }));
@@ -269,6 +373,7 @@ var _ScanOrderImpl = class extends import_BaseModule.BaseModule {
269
373
  }
270
374
  async destroy() {
271
375
  this.logMethodStart("destroy");
376
+ this.clearLoginEffectListeners();
272
377
  await this.core.effects.emit(import_types.ScanOrderHooks.onDestroy, {});
273
378
  console.log("[ScanOrder] 已销毁");
274
379
  this.logMethodSuccess("destroy");
@@ -494,6 +599,127 @@ var _ScanOrderImpl = class extends import_BaseModule.BaseModule {
494
599
  throw error;
495
600
  }
496
601
  }
602
+ getDiscountList() {
603
+ if (!this.store.order)
604
+ return [];
605
+ return this.store.order.getDiscountList();
606
+ }
607
+ async scanCode(code, customerId) {
608
+ this.logMethodStart("scanCode", { code });
609
+ try {
610
+ if (!this.store.order)
611
+ throw new Error("order 模块未初始化");
612
+ const raw = await this.store.order.scanCode(code, customerId);
613
+ if (raw.isAvailable) {
614
+ await this.store.order.recalculateSummary({ createIfMissing: true });
615
+ this.store.order.persistTempOrder();
616
+ }
617
+ this.logMethodSuccess("scanCode", { isAvailable: raw.isAvailable });
618
+ return {
619
+ isAvailable: raw.isAvailable,
620
+ type: raw.type,
621
+ unavailableReason: raw.unavailableReason
622
+ };
623
+ } catch (error) {
624
+ this.logMethodError("scanCode", error);
625
+ throw error;
626
+ }
627
+ }
628
+ async setDiscountSelected(params) {
629
+ var _a, _b, _c;
630
+ this.logMethodStart("setDiscountSelected", params);
631
+ try {
632
+ if (!this.store.order)
633
+ throw new Error("order 模块未初始化");
634
+ const list = this.store.order.getDiscountList();
635
+ const updated = list.map(
636
+ (d) => d.id === params.discountId ? {
637
+ ...d,
638
+ isSelected: params.isSelected,
639
+ isManualSelect: !params.isSelected
640
+ } : d
641
+ );
642
+ const tempOrder = this.store.order.ensureTempOrder();
643
+ const orderStore = this.store.order.store || {};
644
+ const discountModule = orderStore.discount;
645
+ const rulesModule = orderStore.rules;
646
+ const holders = ((_a = tempOrder.holder) == null ? void 0 : _a.form_record_id) ? [{ form_record_id: tempOrder.holder.form_record_id }] : [];
647
+ let nextDiscountList = updated;
648
+ await (discountModule == null ? void 0 : discountModule.setDiscountList(updated));
649
+ if (rulesModule) {
650
+ const result = rulesModule.calcDiscount(
651
+ {
652
+ productList: tempOrder.products,
653
+ discountList: updated,
654
+ holders,
655
+ isFormSubject: !!((_b = tempOrder.holder) == null ? void 0 : _b.type) && tempOrder.holder.type === "form"
656
+ },
657
+ {
658
+ discountId: params.discountId,
659
+ isSelected: params.isSelected
660
+ }
661
+ ) || { productList: tempOrder.products, discountList: updated };
662
+ if (result == null ? void 0 : result.productList) {
663
+ tempOrder.products = result.productList;
664
+ }
665
+ if (result == null ? void 0 : result.discountList) {
666
+ nextDiscountList = result.discountList;
667
+ if (!params.isSelected) {
668
+ const beforeSelectedIds = new Set(
669
+ updated.filter((d) => d.isSelected).map((d) => d.id)
670
+ );
671
+ for (const d of nextDiscountList) {
672
+ if (d.isSelected && !beforeSelectedIds.has(d.id)) {
673
+ d.isSelected = false;
674
+ }
675
+ }
676
+ }
677
+ }
678
+ }
679
+ const selectedResourceIds = new Set(
680
+ nextDiscountList.filter((d) => d.isSelected).map((d) => d.id)
681
+ );
682
+ for (const product of tempOrder.products) {
683
+ if ((_c = product._origin) == null ? void 0 : _c.isManualDiscount)
684
+ continue;
685
+ product.discount_list = (product.discount_list || []).filter((pd) => {
686
+ var _a2;
687
+ const rid = ((_a2 = pd.discount) == null ? void 0 : _a2.resource_id) ?? pd.id;
688
+ return rid != null && selectedResourceIds.has(rid);
689
+ });
690
+ const totalPerUnitDiscount = (product.discount_list || []).reduce(
691
+ (sum, pd) => sum + (pd.amount || 0),
692
+ 0
693
+ );
694
+ const newSellingPrice = new import_decimal.default(product.original_price || 0).minus(totalPerUnitDiscount).toDecimalPlaces(2).toString();
695
+ product.selling_price = newSellingPrice;
696
+ if (product.metadata) {
697
+ product.metadata.main_product_selling_price = newSellingPrice;
698
+ }
699
+ }
700
+ import_Order.OrderModule.populateSavedAmounts(tempOrder.products, nextDiscountList);
701
+ await (discountModule == null ? void 0 : discountModule.setDiscountList(nextDiscountList));
702
+ tempOrder.discount_list = (nextDiscountList || []).filter((d) => d.isSelected);
703
+ await this.store.order.recalculateSummary({ createIfMissing: true });
704
+ this.store.order.persistTempOrder();
705
+ this.logMethodSuccess("setDiscountSelected", params);
706
+ } catch (error) {
707
+ this.logMethodError("setDiscountSelected", error);
708
+ throw error;
709
+ }
710
+ }
711
+ async onCustomerLogin(params) {
712
+ this.logMethodStart("onCustomerLogin", { customerId: params.customerId });
713
+ try {
714
+ await this.refreshOrderMarketingAfterLogin({
715
+ customerId: params.customerId
716
+ });
717
+ this.logMethodSuccess("onCustomerLogin", { customerId: params.customerId });
718
+ } catch (error) {
719
+ this.logMethodError("onCustomerLogin", error);
720
+ throw error;
721
+ }
722
+ }
497
723
  // ScanOrder 提交 payload enhancer:
498
724
  // - 给所有 booking 注入 appointment_status: 'started'(扫码点餐语义)
499
725
  // - 给所有 booking 的 metadata 注入 resource_select_type(来自预约规则商品的 resource.type)
@@ -1499,6 +1725,7 @@ var _ScanOrderImpl = class extends import_BaseModule.BaseModule {
1499
1725
  }
1500
1726
  };
1501
1727
  var ScanOrderImpl = _ScanOrderImpl;
1728
+ ScanOrderImpl.PISELL1_LOGIN_SUCCESS = "pisell1.login.success";
1502
1729
  // ─── UI 状态缓存(按 cacheId 分桶,sessionStorage) ───
1503
1730
  //
1504
1731
  // 用于物料层持久化 UI 层面的轻量状态(如当前步骤、gate 标记、登录回跳意图等)。
@@ -235,3 +235,9 @@ export interface ScanOrderLoggerRuntimeConfig {
235
235
  }
236
236
  export interface ScanOrderAddLogParams extends ScanOrderLogInput {
237
237
  }
238
+ /** ScanOrder.scanCode 对外的轻量结果(不含 discountList,UI 在 resolve 后调 getDiscountList) */
239
+ export interface ScanOrderScanCodeResult {
240
+ isAvailable: boolean;
241
+ type?: 'server' | string;
242
+ unavailableReason?: 'time_limit' | string;
243
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "private": false,
3
3
  "name": "@pisell/pisellos",
4
- "version": "0.0.507",
4
+ "version": "0.0.508",
5
5
  "description": "一个可扩展的前端模块化SDK框架,支持插件系统",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",