feat: 完善对象存储上传与真实条码二维码引擎,彻底剥离保底Mock数据
这个提交包含在:
@@ -192,5 +192,205 @@ describe('ActivityService (TDD 测试套件: 活动项目与4位核销码)', ()
|
||||
expect(check.success).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('5. 房主手动调价与加赏加急机制 (提价/降价与已报名成员差额补偿)', () => {
|
||||
it('发单500元/人招募4人,2人报名后房主手动提价至800元/人,全员同享新高价差额', () => {
|
||||
// 1. 房主发起4人单,每人500元 (50000分)
|
||||
const activity = activityService.createActivity({
|
||||
creatorId: 1001,
|
||||
title: '【高端陪玩】四排吃鸡车队高额赏金局',
|
||||
gameCategory: '热门电竞',
|
||||
payType: ActivityPayType.PROJECT_PAY,
|
||||
perPersonFeeCents: 50000,
|
||||
maxParticipants: 4,
|
||||
allowDynamicPrice: true,
|
||||
priceAdjustRule: 'UNIFIED_HIGH',
|
||||
});
|
||||
|
||||
// 2. 两人报名成功
|
||||
const p1 = activityService.joinActivity(activity.id, { userId: 2001, payAmountCents: 50000 });
|
||||
const p2 = activityService.joinActivity(activity.id, { userId: 2002, payAmountCents: 50000 });
|
||||
expect(activity.currentParticipants).toBe(2);
|
||||
expect(p1.payAmountCents).toBe(50000);
|
||||
expect(p2.payAmountCents).toBe(50000);
|
||||
|
||||
// 3. 房主提价至 800元/人 (80000分) 加急招募
|
||||
const result = activityService.adjustActivityPrice({
|
||||
activityId: activity.id,
|
||||
operatorId: 1001,
|
||||
newPriceCents: 80000,
|
||||
});
|
||||
|
||||
expect(result.priceDiffCents).toBe(30000); // 每人加赏300元
|
||||
expect(result.affectedParticipantsCount).toBe(2);
|
||||
expect(result.activity.perPersonFeeCents).toBe(80000);
|
||||
expect(result.activity.totalFeeCents).toBe(320000); // 800 * 4 = 3200元
|
||||
expect(p1.payAmountCents).toBe(80000);
|
||||
expect(p2.payAmountCents).toBe(80000);
|
||||
|
||||
// 4. 第3位新加入的成员直接按最新高价800元报名
|
||||
const p3 = activityService.joinActivity(activity.id, { userId: 2003, payAmountCents: 80000 });
|
||||
expect(p3.payAmountCents).toBe(80000);
|
||||
expect(activity.currentParticipants).toBe(3);
|
||||
});
|
||||
|
||||
it('非房主尝试调价应抛出权限异常', () => {
|
||||
const act = activityService.createActivity({
|
||||
creatorId: 1001,
|
||||
title: '测试活动',
|
||||
gameCategory: '同城陪吃',
|
||||
payType: ActivityPayType.PROJECT_PAY,
|
||||
perPersonFeeCents: 50000,
|
||||
maxParticipants: 4,
|
||||
});
|
||||
|
||||
expect(() => {
|
||||
activityService.adjustActivityPrice({
|
||||
activityId: act.id,
|
||||
operatorId: 2002, // 非房主
|
||||
newPriceCents: 80000,
|
||||
});
|
||||
}).toThrow('只有发起人有权调整活动出价');
|
||||
});
|
||||
});
|
||||
|
||||
describe('6. 房主解散与取消组局 (0人报名秒撤 / 有人报名退款全员)', () => {
|
||||
it('0人报名时,房主可直接解散取消组局', () => {
|
||||
const act = activityService.createActivity({
|
||||
creatorId: 1001,
|
||||
title: '测试酸汤火锅局',
|
||||
gameCategory: '同城陪吃',
|
||||
payType: ActivityPayType.AA_PAY,
|
||||
aaFeeCents: 5000,
|
||||
maxParticipants: 4,
|
||||
});
|
||||
|
||||
const result = activityService.cancelActivity({
|
||||
activityId: act.id,
|
||||
operatorId: 1001,
|
||||
reason: '临时有事改期',
|
||||
});
|
||||
|
||||
expect(result.success).toBe(true);
|
||||
expect(result.status).toBe('CANCELLED');
|
||||
expect(result.refundedCount).toBe(0);
|
||||
expect(result.totalRefundCents).toBe(0);
|
||||
});
|
||||
|
||||
it('已有搭子报名时,房主解散将全额退还已报名成员款项', () => {
|
||||
const act = activityService.createActivity({
|
||||
creatorId: 1001,
|
||||
title: '三里屯火锅局',
|
||||
gameCategory: '同城陪吃',
|
||||
payType: ActivityPayType.AA_PAY,
|
||||
aaFeeCents: 5000,
|
||||
maxParticipants: 4,
|
||||
});
|
||||
|
||||
// 两位搭子报名付款
|
||||
activityService.joinActivity(act.id, { userId: 2001, payAmountCents: 5000 });
|
||||
activityService.joinActivity(act.id, { userId: 2002, payAmountCents: 5000 });
|
||||
|
||||
const result = activityService.cancelActivity({
|
||||
activityId: act.id,
|
||||
operatorId: 1001,
|
||||
reason: '突发暴雨改期',
|
||||
});
|
||||
|
||||
expect(result.success).toBe(true);
|
||||
expect(result.status).toBe('CANCELLED');
|
||||
expect(result.refundedCount).toBe(2);
|
||||
expect(result.totalRefundCents).toBe(10000); // 5000 * 2 = 10000分
|
||||
expect(result.refundDetails).toEqual([
|
||||
{ userId: 2001, refundAmountCents: 5000 },
|
||||
{ userId: 2002, refundAmountCents: 5000 },
|
||||
]);
|
||||
});
|
||||
|
||||
it('非房主尝试解散组局应抛出权限异常', () => {
|
||||
const act = activityService.createActivity({
|
||||
creatorId: 1001,
|
||||
title: '测试活动',
|
||||
gameCategory: '同城陪吃',
|
||||
payType: ActivityPayType.AA_PAY,
|
||||
aaFeeCents: 5000,
|
||||
maxParticipants: 4,
|
||||
});
|
||||
|
||||
expect(() => {
|
||||
activityService.cancelActivity({
|
||||
activityId: act.id,
|
||||
operatorId: 2005, // 非房主
|
||||
});
|
||||
}).toThrow('只有发起人有权解散此组局');
|
||||
});
|
||||
|
||||
it('已核销或已完成的活动不可再被解散', () => {
|
||||
const act = activityService.createActivity({
|
||||
creatorId: 1001,
|
||||
title: '测试活动',
|
||||
gameCategory: '同城陪吃',
|
||||
payType: ActivityPayType.AA_PAY,
|
||||
aaFeeCents: 5000,
|
||||
maxParticipants: 2,
|
||||
});
|
||||
const pt = activityService.joinActivity(act.id, { userId: 2001, payAmountCents: 5000 });
|
||||
activityService.verifyCheckin({ activityId: act.id, operatorId: 1001, verifyCode: pt.verifyCode });
|
||||
|
||||
expect(() => {
|
||||
activityService.cancelActivity({
|
||||
activityId: act.id,
|
||||
operatorId: 1001,
|
||||
});
|
||||
}).toThrow('聚会已有成员到场核销,不可随意解散');
|
||||
});
|
||||
});
|
||||
|
||||
describe('7. 已报名成员主动退席与名额释放', () => {
|
||||
it('成员在未核销前可主动退席,席位人数自动回退', () => {
|
||||
const act = activityService.createActivity({
|
||||
creatorId: 1001,
|
||||
title: '四人拼桌火锅',
|
||||
gameCategory: '同城陪吃',
|
||||
payType: ActivityPayType.AA_PAY,
|
||||
aaFeeCents: 6000,
|
||||
maxParticipants: 4,
|
||||
});
|
||||
|
||||
activityService.joinActivity(act.id, { userId: 2001, payAmountCents: 6000 });
|
||||
activityService.joinActivity(act.id, { userId: 2002, payAmountCents: 6000 });
|
||||
expect(act.currentParticipants).toBe(2);
|
||||
|
||||
const leaveResult = activityService.leaveActivity({
|
||||
activityId: act.id,
|
||||
userId: 2001,
|
||||
});
|
||||
|
||||
expect(leaveResult.success).toBe(true);
|
||||
expect(leaveResult.refundAmountCents).toBe(6000);
|
||||
expect(act.currentParticipants).toBe(1);
|
||||
});
|
||||
|
||||
it('已核销到场的成员不可退席', () => {
|
||||
const act = activityService.createActivity({
|
||||
creatorId: 1001,
|
||||
title: '四人拼桌火锅',
|
||||
gameCategory: '同城陪吃',
|
||||
payType: ActivityPayType.AA_PAY,
|
||||
aaFeeCents: 6000,
|
||||
maxParticipants: 4,
|
||||
});
|
||||
|
||||
const pt = activityService.joinActivity(act.id, { userId: 2001, payAmountCents: 6000 });
|
||||
activityService.verifyCheckin({ activityId: act.id, operatorId: 1001, verifyCode: pt.verifyCode });
|
||||
|
||||
expect(() => {
|
||||
activityService.leaveActivity({
|
||||
activityId: act.id,
|
||||
userId: 2001,
|
||||
});
|
||||
}).toThrow('已核销到场,无法申请退席');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
在新工单中引用
屏蔽一个用户