feat(ops): v4.0.4 开发任务多行与版本状态同步、合伙人/门店删除、账单合伙人列
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import {
|
||||
assertCanDeleteCityPartner,
|
||||
assertCanDeleteStore,
|
||||
validatePartnerCityBinding,
|
||||
validatePartnerCommissionRates,
|
||||
} from './city-partner';
|
||||
@@ -70,3 +72,33 @@ describe('validatePartnerCommissionRates', () => {
|
||||
expect(validatePartnerCommissionRates(0.05, 0.04, 0.08).ok).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('assertCanDeleteCityPartner', () => {
|
||||
it('requires stores to be deleted first', () => {
|
||||
const result = assertCanDeleteCityPartner({ storeCount: 2, orderCount: 0, redeemCount: 0 });
|
||||
expect(result.ok).toBe(false);
|
||||
expect(result.message).toContain('请先删除门店');
|
||||
});
|
||||
|
||||
it('blocks when orders exist', () => {
|
||||
const result = assertCanDeleteCityPartner({ storeCount: 0, orderCount: 1, redeemCount: 0 });
|
||||
expect(result.ok).toBe(false);
|
||||
expect(result.message).toContain('关联订单');
|
||||
});
|
||||
|
||||
it('allows delete when empty', () => {
|
||||
expect(assertCanDeleteCityPartner({ storeCount: 0, orderCount: 0, redeemCount: 0 }).ok).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('assertCanDeleteStore', () => {
|
||||
it('blocks when redeem records exist', () => {
|
||||
const result = assertCanDeleteStore({ orderCount: 0, redeemCount: 3 });
|
||||
expect(result.ok).toBe(false);
|
||||
expect(result.message).toContain('关联核销单');
|
||||
});
|
||||
|
||||
it('allows delete when no orders or redeems', () => {
|
||||
expect(assertCanDeleteStore({ orderCount: 0, redeemCount: 0 }).ok).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -66,3 +66,33 @@ export function validatePartnerCommissionRates(
|
||||
}
|
||||
return { ok: true };
|
||||
}
|
||||
|
||||
export function assertCanDeleteCityPartner(input: {
|
||||
storeCount: number;
|
||||
orderCount: number;
|
||||
redeemCount: number;
|
||||
}): PartnerCityValidationResult {
|
||||
if (input.storeCount > 0) {
|
||||
return { ok: false, message: '该城市合伙人下还有门店,请先删除门店' };
|
||||
}
|
||||
if (input.orderCount > 0) {
|
||||
return { ok: false, message: '该账号下有关联订单,禁止删除' };
|
||||
}
|
||||
if (input.redeemCount > 0) {
|
||||
return { ok: false, message: '该账号下有关联核销单,禁止删除' };
|
||||
}
|
||||
return { ok: true };
|
||||
}
|
||||
|
||||
export function assertCanDeleteStore(input: {
|
||||
orderCount: number;
|
||||
redeemCount: number;
|
||||
}): PartnerCityValidationResult {
|
||||
if (input.orderCount > 0) {
|
||||
return { ok: false, message: '该账号下有关联订单,禁止删除' };
|
||||
}
|
||||
if (input.redeemCount > 0) {
|
||||
return { ok: false, message: '该账号下有关联核销单,禁止删除' };
|
||||
}
|
||||
return { ok: true };
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import {
|
||||
resolveTaskStatusFromVersions,
|
||||
taskStatusFromVersionStatus,
|
||||
} from './dev-plan';
|
||||
|
||||
describe('taskStatusFromVersionStatus', () => {
|
||||
it('maps version status to task status', () => {
|
||||
expect(taskStatusFromVersionStatus('PENDING')).toBe('TODO');
|
||||
expect(taskStatusFromVersionStatus('IN_PROGRESS')).toBe('IN_PROGRESS');
|
||||
expect(taskStatusFromVersionStatus('TESTING')).toBe('DEVELOPED');
|
||||
expect(taskStatusFromVersionStatus('RELEASED')).toBe('RELEASED');
|
||||
});
|
||||
});
|
||||
|
||||
describe('resolveTaskStatusFromVersions', () => {
|
||||
it('returns null when no versions', () => {
|
||||
expect(resolveTaskStatusFromVersions([])).toBeNull();
|
||||
});
|
||||
|
||||
it('picks the highest mapped status across versions', () => {
|
||||
expect(resolveTaskStatusFromVersions(['PENDING', 'TESTING'])).toBe('DEVELOPED');
|
||||
expect(resolveTaskStatusFromVersions(['IN_PROGRESS', 'RELEASED'])).toBe('RELEASED');
|
||||
});
|
||||
});
|
||||
@@ -61,3 +61,36 @@ export function taskCompletedAtOnStatus(
|
||||
void prev;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const TASK_STATUS_RANK: Record<DevPlanTaskStatus, number> = {
|
||||
TODO: 0,
|
||||
IN_PROGRESS: 1,
|
||||
DEVELOPED: 2,
|
||||
RELEASED: 3,
|
||||
};
|
||||
|
||||
/** 版本状态 → 任务状态:待开始/开发中/测试中/已发布 ↔ 待处理/进行中/已开发/已发布 */
|
||||
export function taskStatusFromVersionStatus(status: DevPlanVersionStatus): DevPlanTaskStatus {
|
||||
switch (status) {
|
||||
case 'PENDING':
|
||||
return 'TODO';
|
||||
case 'IN_PROGRESS':
|
||||
return 'IN_PROGRESS';
|
||||
case 'TESTING':
|
||||
return 'DEVELOPED';
|
||||
case 'RELEASED':
|
||||
return 'RELEASED';
|
||||
}
|
||||
}
|
||||
|
||||
/** 任务挂多个版本时取进度最高的对应状态 */
|
||||
export function resolveTaskStatusFromVersions(
|
||||
versionStatuses: DevPlanVersionStatus[],
|
||||
): DevPlanTaskStatus | null {
|
||||
if (!versionStatuses.length) return null;
|
||||
return versionStatuses
|
||||
.map(taskStatusFromVersionStatus)
|
||||
.reduce((highest, current) =>
|
||||
TASK_STATUS_RANK[current] > TASK_STATUS_RANK[highest] ? current : highest,
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user