|
|
@@ -119,3 +119,33 @@ test('门店预约使用真实数值关联字段,并在查询内过滤门店
|
|
|
assert.deepEqual(plain(await c.storeAppointmentRows(ctx,{},'2026-10-01','2026-10-31')).map(r=>r.targetId),['a1']);
|
|
|
}finally{await db.close();}
|
|
|
});
|
|
|
+
|
|
|
+test('门店运营趋势按服务器身份隔离,去重学员、补零并排除取消和已删除学生',async()=>{
|
|
|
+ const db=new PGlite();try{await db.exec(`
|
|
|
+ CREATE TABLE "CommonModel"(company text,"itemId" numeric,"modelId" numeric,status numeric);
|
|
|
+ CREATE TABLE "CourseAppointment"(id numeric,company text,szyh text,yysj text,bxrq text,dszt text);
|
|
|
+ CREATE TABLE "_User"(company text,"legacyUserId" numeric,"identityType" text,"legacyUserData" jsonb,"isDeleted" boolean);
|
|
|
+ INSERT INTO "_User" VALUES ('co',20,'member','{"ParentUserID":10}',false),('co',21,'member','{"ParentUserID":11}',false),('co',22,'member','{"ParentUserID":10}',true),('other',20,'member','{"ParentUserID":10}',false);
|
|
|
+ INSERT INTO "CourseAppointment" VALUES
|
|
|
+ (1,'co','20','2026-10-20 10:00',null,'30'),(2,'co','20','2026-10-20 11:00',null,'20'),
|
|
|
+ (3,'co','21','2026-10-20 12:00',null,'30'),(4,'co','22','2026-10-20 13:00',null,'30'),
|
|
|
+ (5,'co','20','2026-10-20 14:00',null,'30'),(6,'other','20','2026-10-20 15:00',null,'30'),
|
|
|
+ (7,'co','20','2026-10-01 10:00',null,'40'),(8,'co','20','2026-01-01 10:00',null,'30');
|
|
|
+ INSERT INTO "CommonModel" SELECT company,id,54,CASE WHEN id=5 THEN -2 ELSE 99 END FROM "CourseAppointment";
|
|
|
+ `);
|
|
|
+ const c=env();c.businessDate=value=>value?new Date(value).toLocaleDateString('sv-SE',{timeZone:'Asia/Shanghai'}):'2026-10-20';
|
|
|
+ c.Psql={query:async(q,args)=>(await db.query(q,args)).rows};
|
|
|
+ for(const [period,count,days] of [['week',2,7],['month',3,20],['year',4,293]]){
|
|
|
+ const input={operation:'ops/dashboard/schedule-trend',period,storeId:11,_storeId:11,filters:{parentUserId:11}};
|
|
|
+ await c.prepareStoreRequest(ctx,input,{});const result=await c.scheduleTrendFast(ctx,input);
|
|
|
+ assert.equal(result.totalCourseCount,count);assert.equal(result.totalStudentCount,1);assert.equal(result.points.length,days);
|
|
|
+ assert.equal(result.todayStudentCount,1);assert.equal(result.todayCourseCount,2);assert.equal(result.points.at(-1).completedCount,1);
|
|
|
+ assert.ok(result.points.some(p=>p.courseCount===0));
|
|
|
+ }
|
|
|
+ const other=await c.scheduleTrendFast({...ctx,storeId:11},{period:'week'});assert.equal(other.totalCourseCount,1);
|
|
|
+ const empty=await c.scheduleTrendFast({...ctx,storeId:12},{period:'week'});assert.equal(empty.totalCourseCount,0);assert.equal(empty.maxValue,1);
|
|
|
+ const headquarters=await c.scheduleTrendFast({...ctx,storeId:0},{period:'week'});assert.equal(headquarters.totalCourseCount,4);
|
|
|
+ await assert.rejects(c.scheduleTrendFast(ctx,{period:'invalid'}),/无效/);
|
|
|
+ await assert.rejects(c.prepareStoreRequest(ctx,{operation:'ops/dashboard/summary'},{}),/无权/);
|
|
|
+ }finally{await db.close();}
|
|
|
+});
|