feat(order): support balance payment, dynamic marketing coupon recommendation, and quick activity picker
这个提交包含在:
@@ -263,5 +263,60 @@ describe('ContentSecurityService & Compliance Architecture (TDD 微信内容安
|
||||
expect(createActContent).toContain('activity_rules');
|
||||
});
|
||||
});
|
||||
|
||||
describe('8. 订单结算体系与前端交互人性化专项验证 (支付方式二选一、动态优惠券、组局快捷时段与商圈选点)', () => {
|
||||
it('MySQL Schema 必须包含 pay_type 与 coupon_discount 字段升级补丁', () => {
|
||||
const mysqlPath = path.join(rootDir, 'server', 'src', 'db', 'mysql.ts');
|
||||
const content = fs.readFileSync(mysqlPath, 'utf-8');
|
||||
expect(content).toContain('ALTER TABLE orders ADD COLUMN pay_type');
|
||||
expect(content).toContain('ALTER TABLE orders ADD COLUMN coupon_discount');
|
||||
});
|
||||
|
||||
it('Repository createOrder 必须支持余额支付原子事务校验、扣减余额及财务流水记录', () => {
|
||||
const repoPath = path.join(rootDir, 'server', 'src', 'db', 'repository.ts');
|
||||
const content = fs.readFileSync(repoPath, 'utf-8');
|
||||
expect(content).toContain("data.payType === 'BALANCE'");
|
||||
expect(content).toContain('SELECT balance FROM users WHERE id = ? FOR UPDATE');
|
||||
expect(content).toContain('const newBalance = userBalance - amount');
|
||||
expect(content).toContain('UPDATE users SET balance = ? WHERE id = ?');
|
||||
expect(content).toContain('钱包余额支付订单');
|
||||
expect(content).toContain("INSERT INTO finance_records (id, record_no, type, amount, direction, counterparty, related_id)");
|
||||
});
|
||||
|
||||
it('小程序订单创建页面必须支持钱包余额与微信支付二选一并动态拉取营销优惠券', () => {
|
||||
const orderCreatePath = path.join(rootDir, 'pwuniapp', 'pages', 'order', 'create.vue');
|
||||
const content = fs.readFileSync(orderCreatePath, 'utf-8');
|
||||
expect(content).toContain('payType');
|
||||
expect(content).toContain("'BALANCE'");
|
||||
expect(content).toContain("'WECHAT'");
|
||||
expect(content).toContain('getMarketingCoupons');
|
||||
expect(content).toContain('couponDiscount');
|
||||
});
|
||||
|
||||
it('小程序活动发起页面必须包含快捷时段胶囊与示范商圈及地图选点交互', () => {
|
||||
const actCreatePath = path.join(rootDir, 'pwuniapp', 'pages', 'activity', 'create.vue');
|
||||
const content = fs.readFileSync(actCreatePath, 'utf-8');
|
||||
expect(content).toContain('presetTimeOptions');
|
||||
expect(content).toContain('recommendPublicZones');
|
||||
expect(content).toContain('handleChooseLocation');
|
||||
expect(content).toContain('uni.chooseLocation');
|
||||
});
|
||||
|
||||
it('所有新增代码与测试套件严禁包含任何 Emoji 字符', () => {
|
||||
const pathsToCheck = [
|
||||
path.join(rootDir, 'server', 'src', 'db', 'mysql.ts'),
|
||||
path.join(rootDir, 'server', 'src', 'db', 'repository.ts'),
|
||||
path.join(rootDir, 'pwuniapp', 'pages', 'order', 'create.vue'),
|
||||
path.join(rootDir, 'pwuniapp', 'pages', 'activity', 'create.vue'),
|
||||
path.join(rootDir, 'pwuniapp', 'common', 'icons.js'),
|
||||
path.join(rootDir, 'pwuniapp', 'common', 'api.js')
|
||||
];
|
||||
const emojiRegex = /(?:\p{Extended_Pictographic}|\p{Emoji_Presentation}|[\u2600-\u27BF])/u;
|
||||
for (const p of pathsToCheck) {
|
||||
const text = fs.readFileSync(p, 'utf-8');
|
||||
expect(emojiRegex.test(text)).toBe(false);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
在新工单中引用
屏蔽一个用户