@pisell/pisellos 2.2.70 → 2.2.72
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/effects/index.js +19 -44
- package/dist/model/strategy/adapter/index.d.ts +2 -0
- package/dist/model/strategy/adapter/index.js +2 -1
- package/dist/model/strategy/adapter/promotion/adapter.d.ts +66 -0
- package/dist/model/strategy/adapter/promotion/adapter.js +271 -0
- package/dist/model/strategy/adapter/promotion/evaluator.d.ts +213 -0
- package/dist/model/strategy/adapter/promotion/evaluator.js +1206 -0
- package/dist/model/strategy/adapter/promotion/examples.d.ts +138 -0
- package/dist/model/strategy/adapter/promotion/examples.js +166 -0
- package/dist/model/strategy/adapter/promotion/index.d.ts +4 -0
- package/dist/model/strategy/adapter/promotion/index.js +0 -0
- package/dist/model/strategy/adapter/promotion/type.d.ts +447 -0
- package/dist/model/strategy/adapter/promotion/type.js +209 -0
- package/dist/model/strategy/adapter/walletPass/evaluator.js +4 -1
- package/dist/model/strategy/engine.d.ts +106 -0
- package/dist/model/strategy/engine.js +611 -0
- package/dist/model/strategy/index.d.ts +2 -93
- package/dist/model/strategy/index.js +6 -549
- package/dist/modules/BaseModule.d.ts +4 -0
- package/dist/modules/BaseModule.js +5 -0
- package/dist/modules/Rules/index.d.ts +1 -0
- package/dist/modules/Rules/index.js +28 -16
- package/lib/effects/index.js +7 -7
- package/lib/model/strategy/adapter/index.d.ts +2 -0
- package/lib/model/strategy/adapter/index.js +6 -0
- package/lib/model/strategy/adapter/promotion/adapter.d.ts +66 -0
- package/lib/model/strategy/adapter/promotion/adapter.js +217 -0
- package/lib/model/strategy/adapter/promotion/evaluator.d.ts +213 -0
- package/lib/model/strategy/adapter/promotion/evaluator.js +844 -0
- package/lib/model/strategy/adapter/promotion/examples.d.ts +138 -0
- package/lib/model/strategy/adapter/promotion/examples.js +192 -0
- package/lib/model/strategy/adapter/promotion/index.d.ts +4 -0
- package/lib/model/strategy/adapter/promotion/index.js +0 -0
- package/lib/model/strategy/adapter/promotion/type.d.ts +447 -0
- package/lib/model/strategy/adapter/promotion/type.js +51 -0
- package/lib/model/strategy/adapter/walletPass/evaluator.js +2 -1
- package/lib/model/strategy/engine.d.ts +106 -0
- package/lib/model/strategy/engine.js +450 -0
- package/lib/model/strategy/index.d.ts +2 -93
- package/lib/model/strategy/index.js +6 -381
- package/lib/modules/BaseModule.d.ts +4 -0
- package/lib/modules/BaseModule.js +3 -0
- package/lib/modules/Rules/index.d.ts +1 -0
- package/lib/modules/Rules/index.js +23 -17
- package/package.json +1 -1
package/dist/effects/index.js
CHANGED
|
@@ -1,7 +1,4 @@
|
|
|
1
1
|
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
|
|
2
|
-
function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
|
|
3
|
-
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
|
|
4
|
-
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
|
|
5
2
|
function _regeneratorRuntime() { "use strict"; /*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/facebook/regenerator/blob/main/LICENSE */ _regeneratorRuntime = function _regeneratorRuntime() { return e; }; var t, e = {}, r = Object.prototype, n = r.hasOwnProperty, o = Object.defineProperty || function (t, e, r) { t[e] = r.value; }, i = "function" == typeof Symbol ? Symbol : {}, a = i.iterator || "@@iterator", c = i.asyncIterator || "@@asyncIterator", u = i.toStringTag || "@@toStringTag"; function define(t, e, r) { return Object.defineProperty(t, e, { value: r, enumerable: !0, configurable: !0, writable: !0 }), t[e]; } try { define({}, ""); } catch (t) { define = function define(t, e, r) { return t[e] = r; }; } function wrap(t, e, r, n) { var i = e && e.prototype instanceof Generator ? e : Generator, a = Object.create(i.prototype), c = new Context(n || []); return o(a, "_invoke", { value: makeInvokeMethod(t, r, c) }), a; } function tryCatch(t, e, r) { try { return { type: "normal", arg: t.call(e, r) }; } catch (t) { return { type: "throw", arg: t }; } } e.wrap = wrap; var h = "suspendedStart", l = "suspendedYield", f = "executing", s = "completed", y = {}; function Generator() {} function GeneratorFunction() {} function GeneratorFunctionPrototype() {} var p = {}; define(p, a, function () { return this; }); var d = Object.getPrototypeOf, v = d && d(d(values([]))); v && v !== r && n.call(v, a) && (p = v); var g = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(p); function defineIteratorMethods(t) { ["next", "throw", "return"].forEach(function (e) { define(t, e, function (t) { return this._invoke(e, t); }); }); } function AsyncIterator(t, e) { function invoke(r, o, i, a) { var c = tryCatch(t[r], t, o); if ("throw" !== c.type) { var u = c.arg, h = u.value; return h && "object" == _typeof(h) && n.call(h, "__await") ? e.resolve(h.__await).then(function (t) { invoke("next", t, i, a); }, function (t) { invoke("throw", t, i, a); }) : e.resolve(h).then(function (t) { u.value = t, i(u); }, function (t) { return invoke("throw", t, i, a); }); } a(c.arg); } var r; o(this, "_invoke", { value: function value(t, n) { function callInvokeWithMethodAndArg() { return new e(function (e, r) { invoke(t, n, e, r); }); } return r = r ? r.then(callInvokeWithMethodAndArg, callInvokeWithMethodAndArg) : callInvokeWithMethodAndArg(); } }); } function makeInvokeMethod(e, r, n) { var o = h; return function (i, a) { if (o === f) throw new Error("Generator is already running"); if (o === s) { if ("throw" === i) throw a; return { value: t, done: !0 }; } for (n.method = i, n.arg = a;;) { var c = n.delegate; if (c) { var u = maybeInvokeDelegate(c, n); if (u) { if (u === y) continue; return u; } } if ("next" === n.method) n.sent = n._sent = n.arg;else if ("throw" === n.method) { if (o === h) throw o = s, n.arg; n.dispatchException(n.arg); } else "return" === n.method && n.abrupt("return", n.arg); o = f; var p = tryCatch(e, r, n); if ("normal" === p.type) { if (o = n.done ? s : l, p.arg === y) continue; return { value: p.arg, done: n.done }; } "throw" === p.type && (o = s, n.method = "throw", n.arg = p.arg); } }; } function maybeInvokeDelegate(e, r) { var n = r.method, o = e.iterator[n]; if (o === t) return r.delegate = null, "throw" === n && e.iterator.return && (r.method = "return", r.arg = t, maybeInvokeDelegate(e, r), "throw" === r.method) || "return" !== n && (r.method = "throw", r.arg = new TypeError("The iterator does not provide a '" + n + "' method")), y; var i = tryCatch(o, e.iterator, r.arg); if ("throw" === i.type) return r.method = "throw", r.arg = i.arg, r.delegate = null, y; var a = i.arg; return a ? a.done ? (r[e.resultName] = a.value, r.next = e.nextLoc, "return" !== r.method && (r.method = "next", r.arg = t), r.delegate = null, y) : a : (r.method = "throw", r.arg = new TypeError("iterator result is not an object"), r.delegate = null, y); } function pushTryEntry(t) { var e = { tryLoc: t[0] }; 1 in t && (e.catchLoc = t[1]), 2 in t && (e.finallyLoc = t[2], e.afterLoc = t[3]), this.tryEntries.push(e); } function resetTryEntry(t) { var e = t.completion || {}; e.type = "normal", delete e.arg, t.completion = e; } function Context(t) { this.tryEntries = [{ tryLoc: "root" }], t.forEach(pushTryEntry, this), this.reset(!0); } function values(e) { if (e || "" === e) { var r = e[a]; if (r) return r.call(e); if ("function" == typeof e.next) return e; if (!isNaN(e.length)) { var o = -1, i = function next() { for (; ++o < e.length;) if (n.call(e, o)) return next.value = e[o], next.done = !1, next; return next.value = t, next.done = !0, next; }; return i.next = i; } } throw new TypeError(_typeof(e) + " is not iterable"); } return GeneratorFunction.prototype = GeneratorFunctionPrototype, o(g, "constructor", { value: GeneratorFunctionPrototype, configurable: !0 }), o(GeneratorFunctionPrototype, "constructor", { value: GeneratorFunction, configurable: !0 }), GeneratorFunction.displayName = define(GeneratorFunctionPrototype, u, "GeneratorFunction"), e.isGeneratorFunction = function (t) { var e = "function" == typeof t && t.constructor; return !!e && (e === GeneratorFunction || "GeneratorFunction" === (e.displayName || e.name)); }, e.mark = function (t) { return Object.setPrototypeOf ? Object.setPrototypeOf(t, GeneratorFunctionPrototype) : (t.__proto__ = GeneratorFunctionPrototype, define(t, u, "GeneratorFunction")), t.prototype = Object.create(g), t; }, e.awrap = function (t) { return { __await: t }; }, defineIteratorMethods(AsyncIterator.prototype), define(AsyncIterator.prototype, c, function () { return this; }), e.AsyncIterator = AsyncIterator, e.async = function (t, r, n, o, i) { void 0 === i && (i = Promise); var a = new AsyncIterator(wrap(t, r, n, o), i); return e.isGeneratorFunction(r) ? a : a.next().then(function (t) { return t.done ? t.value : a.next(); }); }, defineIteratorMethods(g), define(g, u, "Generator"), define(g, a, function () { return this; }), define(g, "toString", function () { return "[object Generator]"; }), e.keys = function (t) { var e = Object(t), r = []; for (var n in e) r.push(n); return r.reverse(), function next() { for (; r.length;) { var t = r.pop(); if (t in e) return next.value = t, next.done = !1, next; } return next.done = !0, next; }; }, e.values = values, Context.prototype = { constructor: Context, reset: function reset(e) { if (this.prev = 0, this.next = 0, this.sent = this._sent = t, this.done = !1, this.delegate = null, this.method = "next", this.arg = t, this.tryEntries.forEach(resetTryEntry), !e) for (var r in this) "t" === r.charAt(0) && n.call(this, r) && !isNaN(+r.slice(1)) && (this[r] = t); }, stop: function stop() { this.done = !0; var t = this.tryEntries[0].completion; if ("throw" === t.type) throw t.arg; return this.rval; }, dispatchException: function dispatchException(e) { if (this.done) throw e; var r = this; function handle(n, o) { return a.type = "throw", a.arg = e, r.next = n, o && (r.method = "next", r.arg = t), !!o; } for (var o = this.tryEntries.length - 1; o >= 0; --o) { var i = this.tryEntries[o], a = i.completion; if ("root" === i.tryLoc) return handle("end"); if (i.tryLoc <= this.prev) { var c = n.call(i, "catchLoc"), u = n.call(i, "finallyLoc"); if (c && u) { if (this.prev < i.catchLoc) return handle(i.catchLoc, !0); if (this.prev < i.finallyLoc) return handle(i.finallyLoc); } else if (c) { if (this.prev < i.catchLoc) return handle(i.catchLoc, !0); } else { if (!u) throw new Error("try statement without catch or finally"); if (this.prev < i.finallyLoc) return handle(i.finallyLoc); } } } }, abrupt: function abrupt(t, e) { for (var r = this.tryEntries.length - 1; r >= 0; --r) { var o = this.tryEntries[r]; if (o.tryLoc <= this.prev && n.call(o, "finallyLoc") && this.prev < o.finallyLoc) { var i = o; break; } } i && ("break" === t || "continue" === t) && i.tryLoc <= e && e <= i.finallyLoc && (i = null); var a = i ? i.completion : {}; return a.type = t, a.arg = e, i ? (this.method = "next", this.next = i.finallyLoc, y) : this.complete(a); }, complete: function complete(t, e) { if ("throw" === t.type) throw t.arg; return "break" === t.type || "continue" === t.type ? this.next = t.arg : "return" === t.type ? (this.rval = this.arg = t.arg, this.method = "return", this.next = "end") : "normal" === t.type && e && (this.next = e), y; }, finish: function finish(t) { for (var e = this.tryEntries.length - 1; e >= 0; --e) { var r = this.tryEntries[e]; if (r.finallyLoc === t) return this.complete(r.completion, r.afterLoc), resetTryEntry(r), y; } }, catch: function _catch(t) { for (var e = this.tryEntries.length - 1; e >= 0; --e) { var r = this.tryEntries[e]; if (r.tryLoc === t) { var n = r.completion; if ("throw" === n.type) { var o = n.arg; resetTryEntry(r); } return o; } } throw new Error("illegal catch attempt"); }, delegateYield: function delegateYield(e, r, n) { return this.delegate = { iterator: values(e), resultName: r, nextLoc: n }, "next" === this.method && (this.arg = t), y; } }, e; }
|
|
6
3
|
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
|
|
7
4
|
function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
|
|
@@ -102,7 +99,7 @@ var EffectsManager = /*#__PURE__*/function () {
|
|
|
102
99
|
key: "emit",
|
|
103
100
|
value: function () {
|
|
104
101
|
var _emit = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee3(event, payload) {
|
|
105
|
-
var callbacks;
|
|
102
|
+
var callbacks, res, isAllPass;
|
|
106
103
|
return _regeneratorRuntime().wrap(function _callee3$(_context3) {
|
|
107
104
|
while (1) switch (_context3.prev = _context3.next) {
|
|
108
105
|
case 0:
|
|
@@ -116,62 +113,40 @@ var EffectsManager = /*#__PURE__*/function () {
|
|
|
116
113
|
data: []
|
|
117
114
|
});
|
|
118
115
|
case 3:
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
116
|
+
res = [];
|
|
117
|
+
_context3.next = 6;
|
|
118
|
+
return Promise.all(Array.from(callbacks).reverse().map( /*#__PURE__*/function () {
|
|
119
|
+
var _ref2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee2(cb) {
|
|
120
|
+
var result;
|
|
122
121
|
return _regeneratorRuntime().wrap(function _callee2$(_context2) {
|
|
123
122
|
while (1) switch (_context2.prev = _context2.next) {
|
|
124
123
|
case 0:
|
|
125
|
-
|
|
126
|
-
_iterator = _createForOfIteratorHelper(callbacks);
|
|
127
|
-
_context2.prev = 2;
|
|
128
|
-
_iterator.s();
|
|
129
|
-
case 4:
|
|
130
|
-
if ((_step = _iterator.n()).done) {
|
|
131
|
-
_context2.next = 12;
|
|
132
|
-
break;
|
|
133
|
-
}
|
|
134
|
-
cb = _step.value;
|
|
135
|
-
_context2.next = 8;
|
|
124
|
+
_context2.next = 2;
|
|
136
125
|
return cb(payload);
|
|
137
|
-
case
|
|
126
|
+
case 2:
|
|
138
127
|
result = _context2.sent;
|
|
139
128
|
if (result !== undefined && _typeof(result) === 'object' && 'status' in result) {
|
|
140
129
|
res.push(result);
|
|
141
130
|
}
|
|
142
|
-
case
|
|
143
|
-
_context2.next = 4;
|
|
144
|
-
break;
|
|
145
|
-
case 12:
|
|
146
|
-
_context2.next = 17;
|
|
147
|
-
break;
|
|
148
|
-
case 14:
|
|
149
|
-
_context2.prev = 14;
|
|
150
|
-
_context2.t0 = _context2["catch"](2);
|
|
151
|
-
_iterator.e(_context2.t0);
|
|
152
|
-
case 17:
|
|
153
|
-
_context2.prev = 17;
|
|
154
|
-
_iterator.f();
|
|
155
|
-
return _context2.finish(17);
|
|
156
|
-
case 20:
|
|
157
|
-
isAllPass = res.every(function (r) {
|
|
158
|
-
return (r === null || r === void 0 ? void 0 : r.status) !== false;
|
|
159
|
-
});
|
|
160
|
-
resolve({
|
|
161
|
-
status: isAllPass,
|
|
162
|
-
data: res
|
|
163
|
-
});
|
|
164
|
-
case 22:
|
|
131
|
+
case 4:
|
|
165
132
|
case "end":
|
|
166
133
|
return _context2.stop();
|
|
167
134
|
}
|
|
168
|
-
}, _callee2
|
|
135
|
+
}, _callee2);
|
|
169
136
|
}));
|
|
170
137
|
return function (_x4) {
|
|
171
138
|
return _ref2.apply(this, arguments);
|
|
172
139
|
};
|
|
173
140
|
}()));
|
|
174
|
-
case
|
|
141
|
+
case 6:
|
|
142
|
+
isAllPass = res.every(function (r) {
|
|
143
|
+
return (r === null || r === void 0 ? void 0 : r.status) !== false;
|
|
144
|
+
});
|
|
145
|
+
return _context3.abrupt("return", {
|
|
146
|
+
status: isAllPass,
|
|
147
|
+
data: res
|
|
148
|
+
});
|
|
149
|
+
case 8:
|
|
175
150
|
case "end":
|
|
176
151
|
return _context3.stop();
|
|
177
152
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export * from "./type";
|
|
2
2
|
export { default as WalletPassAdapter } from "./walletPass";
|
|
3
3
|
export { WalletPassEvaluator } from "./walletPass/evaluator";
|
|
4
|
-
|
|
4
|
+
export { PromotionEvaluator } from "./promotion/evaluator";
|
|
5
|
+
export { PromotionAdapter } from "./promotion/adapter";
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { EvaluationResult, RuntimeContext } from '../../type';
|
|
2
|
+
import type { BusinessAdapter } from '../type';
|
|
3
|
+
import type { PromotionBusinessData, PromotionTransformResult } from './type';
|
|
4
|
+
/**
|
|
5
|
+
* Promotion 适配器
|
|
6
|
+
*
|
|
7
|
+
* 用于将促销活动业务数据转换为策略引擎可识别的格式
|
|
8
|
+
* 策略引擎只负责匹配,具体的优惠计算由业务层完成
|
|
9
|
+
*/
|
|
10
|
+
export declare class PromotionAdapter implements BusinessAdapter {
|
|
11
|
+
name: string;
|
|
12
|
+
version: string;
|
|
13
|
+
/**
|
|
14
|
+
* 准备运行时上下文
|
|
15
|
+
*
|
|
16
|
+
* 将业务数据转换为策略引擎可识别的 RuntimeContext
|
|
17
|
+
*/
|
|
18
|
+
prepareContext(businessData: PromotionBusinessData): RuntimeContext;
|
|
19
|
+
/**
|
|
20
|
+
* 转换执行结果
|
|
21
|
+
*
|
|
22
|
+
* 将策略引擎的通用结果转换为业务层需要的格式
|
|
23
|
+
* 主要是整理 matchedActions,让业务层更容易使用
|
|
24
|
+
*/
|
|
25
|
+
transformResult(result: EvaluationResult, businessData?: PromotionBusinessData): PromotionTransformResult;
|
|
26
|
+
/**
|
|
27
|
+
* 格式化配置
|
|
28
|
+
*/
|
|
29
|
+
formatConfig(result: EvaluationResult, businessData?: PromotionBusinessData): {
|
|
30
|
+
result: EvaluationResult;
|
|
31
|
+
businessData?: PromotionBusinessData;
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* 格式化日期时间
|
|
35
|
+
*/
|
|
36
|
+
private formatDateTime;
|
|
37
|
+
/**
|
|
38
|
+
* 解析 Action 详情
|
|
39
|
+
*
|
|
40
|
+
* 将 matchedAction 转换为更易用的结构
|
|
41
|
+
*/
|
|
42
|
+
private parseActionDetail;
|
|
43
|
+
/**
|
|
44
|
+
* 解析 X件Y元 Action
|
|
45
|
+
*/
|
|
46
|
+
private parseXItemsForYPriceAction;
|
|
47
|
+
/**
|
|
48
|
+
* 解析 买X送Y Action
|
|
49
|
+
*/
|
|
50
|
+
private parseBuyXGetYFreeAction;
|
|
51
|
+
/**
|
|
52
|
+
* 获取适用的商品列表
|
|
53
|
+
*
|
|
54
|
+
* 从购物车商品中筛选出符合策略条件的商品
|
|
55
|
+
*/
|
|
56
|
+
private getApplicableProducts;
|
|
57
|
+
/**
|
|
58
|
+
* 查找商品匹配规则
|
|
59
|
+
*/
|
|
60
|
+
private findProductMatchRule;
|
|
61
|
+
/**
|
|
62
|
+
* 检查商品是否匹配
|
|
63
|
+
*/
|
|
64
|
+
private isProductMatch;
|
|
65
|
+
}
|
|
66
|
+
export default PromotionAdapter;
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
|
|
2
|
+
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
3
|
+
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
4
|
+
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
|
5
|
+
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); } }
|
|
6
|
+
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }
|
|
7
|
+
function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
8
|
+
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : String(i); }
|
|
9
|
+
function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
|
10
|
+
import { PROMOTION_ACTION_TYPES } from "./type";
|
|
11
|
+
// ============================================
|
|
12
|
+
// Promotion 适配器实现
|
|
13
|
+
// ============================================
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Promotion 适配器
|
|
17
|
+
*
|
|
18
|
+
* 用于将促销活动业务数据转换为策略引擎可识别的格式
|
|
19
|
+
* 策略引擎只负责匹配,具体的优惠计算由业务层完成
|
|
20
|
+
*/
|
|
21
|
+
export var PromotionAdapter = /*#__PURE__*/function () {
|
|
22
|
+
function PromotionAdapter() {
|
|
23
|
+
_classCallCheck(this, PromotionAdapter);
|
|
24
|
+
_defineProperty(this, "name", 'PromotionAdapter');
|
|
25
|
+
_defineProperty(this, "version", '1.0.0');
|
|
26
|
+
}
|
|
27
|
+
_createClass(PromotionAdapter, [{
|
|
28
|
+
key: "prepareContext",
|
|
29
|
+
value:
|
|
30
|
+
/**
|
|
31
|
+
* 准备运行时上下文
|
|
32
|
+
*
|
|
33
|
+
* 将业务数据转换为策略引擎可识别的 RuntimeContext
|
|
34
|
+
*/
|
|
35
|
+
function prepareContext(businessData) {
|
|
36
|
+
var products = businessData.products,
|
|
37
|
+
currentProduct = businessData.currentProduct,
|
|
38
|
+
channel = businessData.channel,
|
|
39
|
+
custom = businessData.custom;
|
|
40
|
+
|
|
41
|
+
// 当前时间(用于时间条件判断)
|
|
42
|
+
var now = new Date();
|
|
43
|
+
var currentDateTime = this.formatDateTime(now);
|
|
44
|
+
|
|
45
|
+
// 如果有 currentProduct,用于单商品场景(商品卡片展示)
|
|
46
|
+
var evaluatingProduct = currentProduct || (products.length > 0 ? products[0] : null);
|
|
47
|
+
return {
|
|
48
|
+
entities: {
|
|
49
|
+
products: products,
|
|
50
|
+
currentProduct: evaluatingProduct
|
|
51
|
+
},
|
|
52
|
+
attributes: _objectSpread({
|
|
53
|
+
// 当前时间(格式化字符串,用于时间条件判断)
|
|
54
|
+
currentDateTime: currentDateTime,
|
|
55
|
+
// 当前评估的商品信息(用于 product_match 运算符)
|
|
56
|
+
productIdAndVariantId: evaluatingProduct ? {
|
|
57
|
+
product_id: evaluatingProduct.product_id,
|
|
58
|
+
product_variant_id: evaluatingProduct.product_variant_id
|
|
59
|
+
} : null,
|
|
60
|
+
// 渠道
|
|
61
|
+
channel: channel || '',
|
|
62
|
+
// 商品总数量
|
|
63
|
+
totalQuantity: products.reduce(function (sum, p) {
|
|
64
|
+
return sum + p.quantity;
|
|
65
|
+
}, 0),
|
|
66
|
+
// 商品总金额
|
|
67
|
+
totalAmount: products.reduce(function (sum, p) {
|
|
68
|
+
return sum + p.price * p.quantity;
|
|
69
|
+
}, 0)
|
|
70
|
+
}, custom),
|
|
71
|
+
metadata: {
|
|
72
|
+
timestamp: Date.now()
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* 转换执行结果
|
|
79
|
+
*
|
|
80
|
+
* 将策略引擎的通用结果转换为业务层需要的格式
|
|
81
|
+
* 主要是整理 matchedActions,让业务层更容易使用
|
|
82
|
+
*/
|
|
83
|
+
}, {
|
|
84
|
+
key: "transformResult",
|
|
85
|
+
value: function transformResult(result, businessData) {
|
|
86
|
+
// 获取适用的商品列表
|
|
87
|
+
var applicableProducts = businessData ? this.getApplicableProducts(result, businessData) : [];
|
|
88
|
+
if (!result.applicable) {
|
|
89
|
+
return {
|
|
90
|
+
isApplicable: false,
|
|
91
|
+
applicableProducts: [],
|
|
92
|
+
reason: result.message,
|
|
93
|
+
reasonCode: result.code,
|
|
94
|
+
strategyResult: result
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// 获取第一个匹配的 action(按 priority 排序后的)
|
|
99
|
+
var matchedAction = result.matchedActions[0];
|
|
100
|
+
if (!matchedAction) {
|
|
101
|
+
return {
|
|
102
|
+
isApplicable: false,
|
|
103
|
+
applicableProducts: [],
|
|
104
|
+
reason: 'No matched action',
|
|
105
|
+
reasonCode: 'NO_ACTION',
|
|
106
|
+
strategyResult: result
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// 解析 action 详情
|
|
111
|
+
var actionDetail = this.parseActionDetail(matchedAction);
|
|
112
|
+
return {
|
|
113
|
+
isApplicable: true,
|
|
114
|
+
actionType: matchedAction.type,
|
|
115
|
+
actionDetail: actionDetail,
|
|
116
|
+
applicableProducts: applicableProducts,
|
|
117
|
+
strategyResult: result
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* 格式化配置
|
|
123
|
+
*/
|
|
124
|
+
}, {
|
|
125
|
+
key: "formatConfig",
|
|
126
|
+
value: function formatConfig(result, businessData) {
|
|
127
|
+
return {
|
|
128
|
+
result: result,
|
|
129
|
+
businessData: businessData
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// ============================================
|
|
134
|
+
// 私有辅助方法
|
|
135
|
+
// ============================================
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* 格式化日期时间
|
|
139
|
+
*/
|
|
140
|
+
}, {
|
|
141
|
+
key: "formatDateTime",
|
|
142
|
+
value: function formatDateTime(date) {
|
|
143
|
+
var year = date.getFullYear();
|
|
144
|
+
var month = String(date.getMonth() + 1).padStart(2, '0');
|
|
145
|
+
var day = String(date.getDate()).padStart(2, '0');
|
|
146
|
+
var hours = String(date.getHours()).padStart(2, '0');
|
|
147
|
+
var minutes = String(date.getMinutes()).padStart(2, '0');
|
|
148
|
+
var seconds = String(date.getSeconds()).padStart(2, '0');
|
|
149
|
+
return "".concat(year, "-").concat(month, "-").concat(day, " ").concat(hours, ":").concat(minutes, ":").concat(seconds);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* 解析 Action 详情
|
|
154
|
+
*
|
|
155
|
+
* 将 matchedAction 转换为更易用的结构
|
|
156
|
+
*/
|
|
157
|
+
}, {
|
|
158
|
+
key: "parseActionDetail",
|
|
159
|
+
value: function parseActionDetail(action) {
|
|
160
|
+
switch (action.type) {
|
|
161
|
+
case PROMOTION_ACTION_TYPES.X_ITEMS_FOR_Y_PRICE:
|
|
162
|
+
return this.parseXItemsForYPriceAction(action);
|
|
163
|
+
case PROMOTION_ACTION_TYPES.BUY_X_GET_Y_FREE:
|
|
164
|
+
return this.parseBuyXGetYFreeAction(action);
|
|
165
|
+
default:
|
|
166
|
+
return undefined;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* 解析 X件Y元 Action
|
|
172
|
+
*/
|
|
173
|
+
}, {
|
|
174
|
+
key: "parseXItemsForYPriceAction",
|
|
175
|
+
value: function parseXItemsForYPriceAction(action) {
|
|
176
|
+
var _config$allowCrossPro, _config$cumulative;
|
|
177
|
+
var value = action.value || {};
|
|
178
|
+
var config = action.config || {};
|
|
179
|
+
return {
|
|
180
|
+
type: PROMOTION_ACTION_TYPES.X_ITEMS_FOR_Y_PRICE,
|
|
181
|
+
x: value.x || 2,
|
|
182
|
+
price: value.price || 0,
|
|
183
|
+
allowCrossProduct: (_config$allowCrossPro = config.allowCrossProduct) !== null && _config$allowCrossPro !== void 0 ? _config$allowCrossPro : true,
|
|
184
|
+
cumulative: (_config$cumulative = config.cumulative) !== null && _config$cumulative !== void 0 ? _config$cumulative : true
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* 解析 买X送Y Action
|
|
190
|
+
*/
|
|
191
|
+
}, {
|
|
192
|
+
key: "parseBuyXGetYFreeAction",
|
|
193
|
+
value: function parseBuyXGetYFreeAction(action) {
|
|
194
|
+
var _config$cumulative2;
|
|
195
|
+
var value = action.value || {};
|
|
196
|
+
var config = action.config || {};
|
|
197
|
+
return {
|
|
198
|
+
type: PROMOTION_ACTION_TYPES.BUY_X_GET_Y_FREE,
|
|
199
|
+
buyQuantity: value.buyQuantity || 1,
|
|
200
|
+
freeQuantity: value.freeQuantity || 1,
|
|
201
|
+
giftSelectionMode: config.giftSelectionMode || 'user_select',
|
|
202
|
+
cumulative: (_config$cumulative2 = config.cumulative) !== null && _config$cumulative2 !== void 0 ? _config$cumulative2 : true,
|
|
203
|
+
giftProducts: config.giftProducts || []
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* 获取适用的商品列表
|
|
209
|
+
*
|
|
210
|
+
* 从购物车商品中筛选出符合策略条件的商品
|
|
211
|
+
*/
|
|
212
|
+
}, {
|
|
213
|
+
key: "getApplicableProducts",
|
|
214
|
+
value: function getApplicableProducts(result, businessData) {
|
|
215
|
+
var _this = this;
|
|
216
|
+
var products = businessData.products;
|
|
217
|
+
|
|
218
|
+
// 从策略配置中获取商品范围条件
|
|
219
|
+
var productMatchRule = this.findProductMatchRule(result.config);
|
|
220
|
+
if (!productMatchRule) {
|
|
221
|
+
// 如果没有商品范围条件,所有商品都适用
|
|
222
|
+
return products;
|
|
223
|
+
}
|
|
224
|
+
var configProducts = productMatchRule.value;
|
|
225
|
+
|
|
226
|
+
// 筛选适用的商品
|
|
227
|
+
return products.filter(function (product) {
|
|
228
|
+
return _this.isProductMatch(product, configProducts);
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* 查找商品匹配规则
|
|
234
|
+
*/
|
|
235
|
+
}, {
|
|
236
|
+
key: "findProductMatchRule",
|
|
237
|
+
value: function findProductMatchRule(config) {
|
|
238
|
+
var _config$conditions;
|
|
239
|
+
if (!(config !== null && config !== void 0 && (_config$conditions = config.conditions) !== null && _config$conditions !== void 0 && _config$conditions.rules)) {
|
|
240
|
+
return null;
|
|
241
|
+
}
|
|
242
|
+
return config.conditions.rules.find(function (rule) {
|
|
243
|
+
return rule.field === 'productIdAndVariantId' && (rule.operator === 'product_match' || rule.operator === 'object_in');
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* 检查商品是否匹配
|
|
249
|
+
*/
|
|
250
|
+
}, {
|
|
251
|
+
key: "isProductMatch",
|
|
252
|
+
value: function isProductMatch(product, configProducts) {
|
|
253
|
+
return configProducts.some(function (config) {
|
|
254
|
+
// 首先检查 product_id
|
|
255
|
+
if (config.product_id !== product.product_id) {
|
|
256
|
+
return false;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// 如果配置的 product_variant_id = 0,只需要 product_id 匹配
|
|
260
|
+
if (config.product_variant_id === 0) {
|
|
261
|
+
return true;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// 否则需要 product_variant_id 精确匹配
|
|
265
|
+
return config.product_variant_id === product.product_variant_id;
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
}]);
|
|
269
|
+
return PromotionAdapter;
|
|
270
|
+
}();
|
|
271
|
+
export default PromotionAdapter;
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import type { StrategyConfig } from '../../type';
|
|
2
|
+
import { type PromotionProduct, type PromotionActionDetail, type PromotionEvaluatorInput, type ProductPromotionResult, type ApplicablePromotion, type CartEvaluationResult, type CartWithPricingResult } from './type';
|
|
3
|
+
/**
|
|
4
|
+
* Promotion 评估器
|
|
5
|
+
*
|
|
6
|
+
* 用于评估商品适用的促销活动
|
|
7
|
+
* 封装了 StrategyEngine 和 PromotionAdapter 的调用逻辑
|
|
8
|
+
*/
|
|
9
|
+
export declare class PromotionEvaluator {
|
|
10
|
+
private engine;
|
|
11
|
+
private adapter;
|
|
12
|
+
private strategyConfigs;
|
|
13
|
+
private locale;
|
|
14
|
+
private locales;
|
|
15
|
+
constructor();
|
|
16
|
+
/**
|
|
17
|
+
* 设置策略配置列表
|
|
18
|
+
*/
|
|
19
|
+
setStrategyConfigs(strategyConfigs: StrategyConfig[]): void;
|
|
20
|
+
/**
|
|
21
|
+
* 获取策略配置列表
|
|
22
|
+
*/
|
|
23
|
+
getStrategyConfigs(): StrategyConfig[];
|
|
24
|
+
/**
|
|
25
|
+
* 添加策略配置
|
|
26
|
+
*/
|
|
27
|
+
addStrategyConfig(strategyConfig: StrategyConfig): void;
|
|
28
|
+
/**
|
|
29
|
+
* 设置语言
|
|
30
|
+
*/
|
|
31
|
+
setLocale(locale: string): void;
|
|
32
|
+
/**
|
|
33
|
+
* 设置自定义多语言文案
|
|
34
|
+
*/
|
|
35
|
+
setLocales(locales: Record<string, Record<string, string>>): void;
|
|
36
|
+
/**
|
|
37
|
+
* 获取多语言文案
|
|
38
|
+
*/
|
|
39
|
+
getText(key: string): string;
|
|
40
|
+
/**
|
|
41
|
+
* 获取多语言名称
|
|
42
|
+
*/
|
|
43
|
+
getLocalizedName(name: string | Record<string, string>): string;
|
|
44
|
+
/**
|
|
45
|
+
* 评估商品列表
|
|
46
|
+
*
|
|
47
|
+
* 判断每个商品适用哪些促销活动
|
|
48
|
+
* 支持主商品和 bundle 子商品的匹配
|
|
49
|
+
*
|
|
50
|
+
* @param input 评估输入
|
|
51
|
+
* @returns 每个商品的促销评估结果
|
|
52
|
+
*/
|
|
53
|
+
evaluateProducts(input: PromotionEvaluatorInput): ProductPromotionResult[];
|
|
54
|
+
/**
|
|
55
|
+
* 评估购物车
|
|
56
|
+
*
|
|
57
|
+
* 返回所有适用的促销及按促销分组的商品
|
|
58
|
+
* 支持 bundle 子商品的数量计算(主商品数量 × 子商品数量)
|
|
59
|
+
*
|
|
60
|
+
* @param input 评估输入
|
|
61
|
+
* @returns 购物车评估结果
|
|
62
|
+
*/
|
|
63
|
+
evaluateCart(input: PromotionEvaluatorInput): CartEvaluationResult;
|
|
64
|
+
/**
|
|
65
|
+
* 评估购物车并计算定价
|
|
66
|
+
*
|
|
67
|
+
* 返回处理后的商品数组(包含拆分、finalPrice)和赠品信息
|
|
68
|
+
* - 对于 X_ITEMS_FOR_Y_PRICE:按原价比例均摊价格,优先使用高价商品
|
|
69
|
+
* - 对于 BUY_X_GET_Y_FREE:计算赠品数量和可选赠品列表
|
|
70
|
+
*
|
|
71
|
+
* @param input 评估输入
|
|
72
|
+
* @returns 带定价的购物车评估结果
|
|
73
|
+
*/
|
|
74
|
+
evaluateCartWithPricing(input: PromotionEvaluatorInput): CartWithPricingResult;
|
|
75
|
+
/**
|
|
76
|
+
* 获取商品适用的促销列表
|
|
77
|
+
*
|
|
78
|
+
* 简化方法,用于商品卡片展示
|
|
79
|
+
*
|
|
80
|
+
* @param product 商品
|
|
81
|
+
* @param strategyConfigs 策略配置(可选)
|
|
82
|
+
* @returns 适用的促销列表
|
|
83
|
+
*/
|
|
84
|
+
getProductPromotions(product: PromotionProduct, strategyConfigs?: StrategyConfig[]): ApplicablePromotion[];
|
|
85
|
+
/**
|
|
86
|
+
* 获取商品的促销标签
|
|
87
|
+
*
|
|
88
|
+
* 用于商品卡片展示
|
|
89
|
+
*
|
|
90
|
+
* @param product 商品
|
|
91
|
+
* @param strategyConfigs 策略配置(可选)
|
|
92
|
+
* @returns 促销标签列表
|
|
93
|
+
*/
|
|
94
|
+
getProductPromotionTags(product: PromotionProduct, strategyConfigs?: StrategyConfig[]): Array<{
|
|
95
|
+
text: string;
|
|
96
|
+
type: string;
|
|
97
|
+
strategyId: string;
|
|
98
|
+
}>;
|
|
99
|
+
/**
|
|
100
|
+
* 查找商品适用的策略配置
|
|
101
|
+
*
|
|
102
|
+
* @param product 商品
|
|
103
|
+
* @param strategyConfigs 策略配置列表(可选)
|
|
104
|
+
* @returns 适用的策略配置列表
|
|
105
|
+
*/
|
|
106
|
+
findApplicableStrategies(product: PromotionProduct, strategyConfigs?: StrategyConfig[]): StrategyConfig[];
|
|
107
|
+
/**
|
|
108
|
+
* 批量获取商品列表的适用策略信息
|
|
109
|
+
*
|
|
110
|
+
* 用于给商品列表追加策略标签信息
|
|
111
|
+
* 只检查商品 ID 匹配和策略时间范围
|
|
112
|
+
*
|
|
113
|
+
* @param input 评估输入(商品列表)
|
|
114
|
+
* @param matchVariant 是否需要匹配 product_variant_id,默认 true(严格匹配),false 时只匹配 product_id
|
|
115
|
+
* @returns 每个商品的适用策略完整数据
|
|
116
|
+
*/
|
|
117
|
+
getProductsApplicableStrategies(input: PromotionEvaluatorInput, matchVariant?: boolean): Array<{
|
|
118
|
+
product: PromotionProduct;
|
|
119
|
+
applicableStrategies: Array<{
|
|
120
|
+
strategyId: string;
|
|
121
|
+
strategyName: string | Record<string, string>;
|
|
122
|
+
strategyMetadata: any;
|
|
123
|
+
actionType: string;
|
|
124
|
+
actionDetail: PromotionActionDetail;
|
|
125
|
+
display?: {
|
|
126
|
+
text: string | Record<string, string>;
|
|
127
|
+
type: string;
|
|
128
|
+
};
|
|
129
|
+
strategyConfig: StrategyConfig;
|
|
130
|
+
/** 满足促销所需的商品数量 */
|
|
131
|
+
requiredQuantity: number;
|
|
132
|
+
/** 可参与此促销的商品列表 */
|
|
133
|
+
eligibleProducts: Array<{
|
|
134
|
+
product_id: number;
|
|
135
|
+
product_variant_id: number;
|
|
136
|
+
}>;
|
|
137
|
+
}>;
|
|
138
|
+
hasApplicableStrategy: boolean;
|
|
139
|
+
}>;
|
|
140
|
+
/**
|
|
141
|
+
* 获取促销所需数量和可参与商品列表
|
|
142
|
+
*
|
|
143
|
+
* @param actionType 促销类型
|
|
144
|
+
* @param actionDetail 促销详情
|
|
145
|
+
* @param config 策略配置
|
|
146
|
+
* @returns { requiredQuantity, eligibleProducts }
|
|
147
|
+
*/
|
|
148
|
+
private getPromotionRequirements;
|
|
149
|
+
/**
|
|
150
|
+
* 按优先级排序促销组
|
|
151
|
+
* 优先级从 strategyConfig.actions[0].priority 获取,数值越小优先级越高
|
|
152
|
+
*/
|
|
153
|
+
private sortPromotionGroupsByPriority;
|
|
154
|
+
/**
|
|
155
|
+
* 处理 X件Y元 促销
|
|
156
|
+
*
|
|
157
|
+
* 1. 展开商品为单件列表,按价格从高到低排序
|
|
158
|
+
* 2. 计算可凑成的组数
|
|
159
|
+
* 3. 按原价比例均摊价格
|
|
160
|
+
* 4. 拆分商品(部分参与促销、部分原价)
|
|
161
|
+
*
|
|
162
|
+
* 注意:每个商品按 id 独立处理,不会合并不同 id 的商品
|
|
163
|
+
*/
|
|
164
|
+
private processXItemsForYPrice;
|
|
165
|
+
/**
|
|
166
|
+
* 处理 买X送Y 促销
|
|
167
|
+
*
|
|
168
|
+
* 计算赠品数量,商品本身价格不变
|
|
169
|
+
* 支持 bundle 子商品的数量计算(主商品数量 × 子商品数量)
|
|
170
|
+
*/
|
|
171
|
+
private processBuyXGetYFree;
|
|
172
|
+
/**
|
|
173
|
+
* 获取未参与任何促销的商品
|
|
174
|
+
*/
|
|
175
|
+
private getRemainingProducts;
|
|
176
|
+
/**
|
|
177
|
+
* 价格统一保留两位小数
|
|
178
|
+
*/
|
|
179
|
+
private formatPrice;
|
|
180
|
+
/**
|
|
181
|
+
* 获取商品唯一标识 key
|
|
182
|
+
* 使用商品的 id 作为唯一标识,不同 id 的商品不会被合并
|
|
183
|
+
*/
|
|
184
|
+
private getProductKey;
|
|
185
|
+
/**
|
|
186
|
+
* 生成随机ID
|
|
187
|
+
*/
|
|
188
|
+
private generateRandomId;
|
|
189
|
+
/**
|
|
190
|
+
* 商品匹配结果信息
|
|
191
|
+
*/
|
|
192
|
+
private getProductMatchInfo;
|
|
193
|
+
/**
|
|
194
|
+
* 检查商品是否在策略的适用范围内
|
|
195
|
+
*/
|
|
196
|
+
private isProductInStrategy;
|
|
197
|
+
/**
|
|
198
|
+
* 查找商品匹配规则
|
|
199
|
+
*/
|
|
200
|
+
private findProductMatchRule;
|
|
201
|
+
/**
|
|
202
|
+
* 检查商品ID是否匹配配置列表
|
|
203
|
+
*/
|
|
204
|
+
private isProductIdMatch;
|
|
205
|
+
/**
|
|
206
|
+
* 检查商品是否匹配配置(兼容旧方法)
|
|
207
|
+
*/
|
|
208
|
+
private isProductMatch;
|
|
209
|
+
/**
|
|
210
|
+
* 获取展示配置
|
|
211
|
+
*/
|
|
212
|
+
private getDisplayConfig;
|
|
213
|
+
}
|