|
|
@@ -61,6 +61,7 @@ let memberLegacyId = 0;
|
|
|
let coachId = '';
|
|
|
let coachLegacyId = 0;
|
|
|
let temporaryAppointmentId = '';
|
|
|
+let temporaryAppointmentObjectId = '';
|
|
|
const temporaryLessonIds = [];
|
|
|
try {
|
|
|
const sample = await jsonRequest(`${PARSE_URL}/classes/Company?limit=1&keys=objectId`, {}, true);
|
|
|
@@ -87,7 +88,7 @@ try {
|
|
|
memberLegacyId = 900000000 + Math.floor(Date.now() / 1000) % 90000000;
|
|
|
const member = await jsonRequest(`${PARSE_URL}/users`, {
|
|
|
method: 'POST',
|
|
|
- body: JSON.stringify({ username: memberUsername, password: memberPassword, legacyUserId: memberLegacyId, legacyGroupId: 1, company }),
|
|
|
+ body: JSON.stringify({ username: memberUsername, password: memberPassword, legacyUserId: memberLegacyId, legacyGroupId: 1, legacyUserData: { Purse: 2, SilverCoin: 2, UserExp: 2, UserPoint: 2 }, company }),
|
|
|
}, true);
|
|
|
memberId = member.objectId;
|
|
|
const coachUsername = `codex_coach_smoke_${Date.now()}`;
|
|
|
@@ -105,11 +106,6 @@ try {
|
|
|
}, true);
|
|
|
temporaryLessonIds.push(lesson.objectId);
|
|
|
}
|
|
|
- const createdAppointment = await jsonRequest(`${PARSE_URL}/classes/CourseAppointment`, {
|
|
|
- method: 'POST',
|
|
|
- body: JSON.stringify({ company, sourceKey: `cloud:smoke-appointment:${memberLegacyId}`, szyh: String(memberLegacyId), kcid: '16', dslx: '1', dszt: '30', pl: String(coachLegacyId) }),
|
|
|
- }, true);
|
|
|
- temporaryAppointmentId = createdAppointment.objectId;
|
|
|
const memberLogin = await jsonRequest(`${PARSE_URL}/login`, {
|
|
|
method: 'POST',
|
|
|
body: JSON.stringify({ username: memberUsername, password: memberPassword }),
|
|
|
@@ -118,6 +114,13 @@ try {
|
|
|
method: 'POST',
|
|
|
body: JSON.stringify({ username: coachUsername, password: coachPassword }),
|
|
|
});
|
|
|
+ const createdAppointment = await callLegacyFunction(login.sessionToken, { action: 'content_add', content: JSON.stringify({ ModelID: 54, nodeId: 29, inputer: coachUsername, status: 99, title: memberUsername }), addon: JSON.stringify({ szyh: memberLegacyId, kcid: 16, dslx: 1, dszt: 0, pl: coachLegacyId, fxpl: coachLegacyId, sdsd: '19:00' }) });
|
|
|
+ temporaryAppointmentId = String(createdAppointment.result);
|
|
|
+ const appointmentSourceKey = `cloud:content_add:${memberLegacyId}:${temporaryAppointmentId}`;
|
|
|
+ const appointmentWhere = encodeURIComponent(JSON.stringify({ sourceKey: appointmentSourceKey }));
|
|
|
+ const appointmentRows = await jsonRequest(`${PARSE_URL}/classes/CourseAppointment?where=${appointmentWhere}&limit=1`, {}, true);
|
|
|
+ temporaryAppointmentObjectId = appointmentRows.results?.[0]?.objectId || '';
|
|
|
+ if (!temporaryAppointmentObjectId) throw new Error('临时预约副表创建失败');
|
|
|
|
|
|
const meta = await callFunction('xiaoshu/admin/gateway', login.sessionToken, { operation: 'meta' });
|
|
|
if (meta.identity?.objectId !== userId || !meta.cloudFunctions) throw new Error('管理员 meta 校验失败');
|
|
|
@@ -151,7 +154,7 @@ try {
|
|
|
const compatibilityActions = blockedActions.filter((action) => !sourceActionList.includes(action)).sort();
|
|
|
const sourceImplemented = implementedActions.filter((action) => sourceActionList.includes(action));
|
|
|
const compatibilityImplemented = implementedActions.filter((action) => !sourceActionList.includes(action)).sort();
|
|
|
- if (sourceImplemented.length !== 31 || sourceBlocked.length !== 60) throw new Error(`app gateway 源 action 计数异常:${sourceImplemented.length} 已映射 / ${sourceBlocked.length} 阻塞`);
|
|
|
+ if (sourceImplemented.length !== 32 || sourceBlocked.length !== 59) throw new Error(`app gateway 源 action 计数异常:${sourceImplemented.length} 已映射 / ${sourceBlocked.length} 阻塞`);
|
|
|
if (compatibilityImplemented.join(',') !== 'content_add_zt') throw new Error(`app gateway 已实现兼容 action 计数异常:${compatibilityImplemented.join(',')}`);
|
|
|
if (compatibilityActions.join(',') !== 'product_add,product_upd') throw new Error(`app gateway 阻塞兼容 action 计数异常:${compatibilityActions.join(',')}`);
|
|
|
|
|
|
@@ -220,7 +223,7 @@ try {
|
|
|
if (String(assessmentDetail.result?.df) !== '7' || String(assessmentDetail.result?.prevScore) !== '0' || Number(assessmentDetail.result?.UserID ?? assessmentDetail.result?.userId) !== memberLegacyId) throw new Error('规范化测评内容新增写后读失败');
|
|
|
const missingSchemaCreate = await callLegacyFunction(memberLogin.sessionToken, { action: 'content_add', content: JSON.stringify({ ModelID: 55, nodeId: 255 }), addon: JSON.stringify({ UserID: memberLegacyId, scnr: '[]' }) }, 501);
|
|
|
if (!String(missingSchemaCreate.retmsg).includes('未迁移内容模型 55')) throw new Error('缺 Schema 内容新增未明确拒绝');
|
|
|
- const studyAddon = { con: '云函数学习记录冒烟测试', dqrq: '20260818', UserID: memberLegacyId, learned: 1, ygg: 0, djq: 0, xxqs: JSON.stringify([{ GeneralID: 2505, Title: 'woman', check: 0 }]) };
|
|
|
+ const studyAddon = { con: '云函数学习记录冒烟测试', dqrq: '20260818', fxrl: '20260819,20260820', UserID: memberLegacyId, learned: 1, ygg: 0, djq: 0, xxqs: JSON.stringify([{ GeneralID: 2505, Title: 'woman', check: 0 }]) };
|
|
|
const createdStudy = await callLegacyFunction(memberLogin.sessionToken, { action: 'stu_record_update_v2', orderId: temporaryAppointmentId, uid: memberLegacyId, inputer: memberUsername, addon: JSON.stringify(studyAddon) });
|
|
|
if (!createdStudy.result?.created || !createdStudy.result?.GeneralID || !createdStudy.result?.recordObjectId) throw new Error('预约学习记录首次双表写入校验失败');
|
|
|
const studyDetail = await callLegacyFunction(memberLogin.sessionToken, { action: 'e_record_detail', id: createdStudy.result.GeneralID });
|
|
|
@@ -230,8 +233,29 @@ try {
|
|
|
if (updatedStudy.result?.created || updatedStudy.result?.GeneralID !== createdStudy.result.GeneralID) throw new Error('预约学习记录幂等更新校验失败');
|
|
|
const studyList = await callLegacyFunction(memberLogin.sessionToken, { action: 'content_list', modelId: 56, myfield2: `UserId=${memberLegacyId}|dsid=${temporaryAppointmentId}`, page: 1, pageSize: 2 });
|
|
|
if (studyList.page?.itemCount !== 1 || Number(studyList.result?.[0]?.ygg) !== 1 || Number(studyList.result?.[0]?.learned) !== 1) throw new Error('预约学习记录聚合字段写后读校验失败');
|
|
|
- const blockedOrderUpdate = await callLegacyFunction(coachLogin.sessionToken, { action: 'e_order_update_v2', uid: coachLegacyId, status: 10, content: JSON.stringify({ GeneralID: temporaryAppointmentId }) }, 501);
|
|
|
- if (!String(blockedOrderUpdate.retmsg).includes('课时')) throw new Error('预约状态写入未显式阻塞隐藏副作用');
|
|
|
+ const orderContent = JSON.stringify({ GeneralID: temporaryAppointmentId, UpDateTime: '2026-08-18 13:30' });
|
|
|
+ await callLegacyFunction(memberLogin.sessionToken, { action: 'e_order_update_v2', uid: memberLegacyId, status: 10, content: orderContent }, 403);
|
|
|
+ const startedOrder = await callLegacyFunction(coachLogin.sessionToken, { action: 'e_order_update_v2', uid: coachLegacyId, status: 10, content: orderContent });
|
|
|
+ if (startedOrder.result?.previousStatus !== 0 || startedOrder.result?.status !== 10) throw new Error('预约开始状态迁移失败');
|
|
|
+ const endedOrder = await callLegacyFunction(coachLogin.sessionToken, { action: 'e_order_update_v2', uid: coachLegacyId, status: 11, content: orderContent });
|
|
|
+ if (endedOrder.result?.reviewCount !== 2 || !endedOrder.result?.periodDeducted) throw new Error('预约结束课时与抗遗忘副作用失败');
|
|
|
+ const repeatedEnd = await callLegacyFunction(coachLogin.sessionToken, { action: 'e_order_update_v2', uid: coachLegacyId, status: 11, content: orderContent });
|
|
|
+ if (!repeatedEnd.result?.unchanged) throw new Error('预约结束状态未保持幂等');
|
|
|
+ const updatedMember = await jsonRequest(`${PARSE_URL}/users/${memberId}`, {}, true);
|
|
|
+ if (Number(updatedMember.legacyUserData?.Purse) !== 1 || Number(updatedMember.legacyUserData?.UserPoint) !== 1.5) throw new Error(`预约结束课时扣减异常:${JSON.stringify(updatedMember.legacyUserData)}`);
|
|
|
+ const sideEffectWhere = encodeURIComponent(JSON.stringify({ sourceKey: { $regex: `^cloud:e_order_update:${temporaryAppointmentId}:` } }));
|
|
|
+ const [periodLogs, pointLogs, memoryRows, memoryCommonRows] = await Promise.all([
|
|
|
+ jsonRequest(`${PARSE_URL}/classes/UserExpDomP?where=${sideEffectWhere}&count=1&limit=0`, {}, true),
|
|
|
+ jsonRequest(`${PARSE_URL}/classes/UserUserPoint?where=${sideEffectWhere}&count=1&limit=0`, {}, true),
|
|
|
+ jsonRequest(`${PARSE_URL}/classes/MemoryPracticeRecord?where=${sideEffectWhere}&count=1&limit=0`, {}, true),
|
|
|
+ jsonRequest(`${PARSE_URL}/classes/CommonModel?where=${sideEffectWhere}&count=1&limit=0`, {}, true),
|
|
|
+ ]);
|
|
|
+ if (periodLogs.count !== 1 || pointLogs.count !== 1 || memoryRows.count !== 2 || memoryCommonRows.count !== 2) throw new Error(`预约结束账本/抗遗忘数量异常:${periodLogs.count}/${pointLogs.count}/${memoryRows.count}/${memoryCommonRows.count}`);
|
|
|
+ await callLegacyFunction(coachLogin.sessionToken, { action: 'e_order_update_v2', uid: coachLegacyId, status: 20, content: orderContent }, 403);
|
|
|
+ await callLegacyFunction(memberLogin.sessionToken, { action: 'e_order_update_v2', uid: memberLegacyId, status: 20, content: orderContent });
|
|
|
+ await callLegacyFunction(coachLogin.sessionToken, { action: 'e_order_update_v2', uid: coachLegacyId, status: 30, content: orderContent });
|
|
|
+ const completedOrder = await callLegacyFunction(memberLogin.sessionToken, { action: 'e_order_detail', id: temporaryAppointmentId });
|
|
|
+ if (Number(completedOrder.result?.[0]?.dszt) !== 30) throw new Error('预约状态机写后读失败');
|
|
|
const coachStats = await callLegacyFunction(coachLogin.sessionToken, { action: 'e_order_tongji', uid: coachLegacyId });
|
|
|
if (coachStats.result?.t30 !== '1' || coachStats.result?.t60 !== '1' || coachStats.result?.t_tiyan !== '1' || coachStats.result?.t_total !== '3' || coachStats.result?.t_shichang !== '2.5' || coachStats.result?.t_yongji !== '100') throw new Error('陪练预约统计公式校验失败');
|
|
|
const memberStats = await callLegacyFunction(memberLogin.sessionToken, { action: 'e_order_tongji', uid: memberLegacyId });
|
|
|
@@ -267,10 +291,20 @@ try {
|
|
|
process.exitCode = 1;
|
|
|
});
|
|
|
}
|
|
|
- if (temporaryAppointmentId) await jsonRequest(`${PARSE_URL}/classes/CourseAppointment/${temporaryAppointmentId}`, { method: 'DELETE' }, true).catch((error) => {
|
|
|
+ if (temporaryAppointmentObjectId) await jsonRequest(`${PARSE_URL}/classes/CourseAppointment/${temporaryAppointmentObjectId}`, { method: 'DELETE' }, true).catch((error) => {
|
|
|
console.error(`临时预约清理失败:${error.message}`);
|
|
|
process.exitCode = 1;
|
|
|
});
|
|
|
+ if (temporaryAppointmentId) {
|
|
|
+ const sideEffectWhere = encodeURIComponent(JSON.stringify({ sourceKey: { $regex: `^cloud:e_order_update:${temporaryAppointmentId}:` } }));
|
|
|
+ for (const className of ['CommonModel', 'MemoryPracticeRecord', 'UserExpDomP', 'UserUserPoint']) {
|
|
|
+ const rows = await jsonRequest(`${PARSE_URL}/classes/${className}?where=${sideEffectWhere}&limit=1000`, {}, true).catch(() => ({ results: [] }));
|
|
|
+ for (const row of rows.results || []) await jsonRequest(`${PARSE_URL}/classes/${className}/${row.objectId}`, { method: 'DELETE' }, true).catch((error) => {
|
|
|
+ console.error(`临时预约副作用清理失败(${className}):${error.message}`);
|
|
|
+ process.exitCode = 1;
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
if (memberLegacyId) {
|
|
|
const assessmentWhere = encodeURIComponent(JSON.stringify({ sourceKey: { $regex: `^cloud:content_add:${memberLegacyId}:` } }));
|
|
|
const assessments = await jsonRequest(`${PARSE_URL}/classes/AssessmentProfile?where=${assessmentWhere}&limit=1000`, {}, true).catch(() => ({ results: [] }));
|