ac94f5f5de
Co-authored-by: Cursor <cursoragent@cursor.com>
105 lines
3.4 KiB
TypeScript
105 lines
3.4 KiB
TypeScript
import { describe, expect, it } from 'vitest';
|
|
import {
|
|
assertCanDeleteCityPartner,
|
|
assertCanDeleteStore,
|
|
validatePartnerCityBinding,
|
|
validatePartnerCommissionRates,
|
|
} from './city-partner';
|
|
|
|
describe('validatePartnerCityBinding', () => {
|
|
it('rejects duplicate partner', () => {
|
|
const result = validatePartnerCityBinding(
|
|
[{ id: '1', partnerAccountId: '10', scopeType: 'CITY_WIDE' }],
|
|
{ partnerAccountId: '10', scopeType: 'DISTRICT', districtCodes: ['410105'] },
|
|
);
|
|
expect(result.ok).toBe(false);
|
|
});
|
|
|
|
it('rejects second city-wide partner', () => {
|
|
const result = validatePartnerCityBinding(
|
|
[{ id: '1', partnerAccountId: '10', scopeType: 'CITY_WIDE' }],
|
|
{ partnerAccountId: '11', scopeType: 'CITY_WIDE' },
|
|
);
|
|
expect(result.ok).toBe(false);
|
|
});
|
|
|
|
it('allows overlapping district codes as labels', () => {
|
|
const result = validatePartnerCityBinding(
|
|
[
|
|
{
|
|
id: '1',
|
|
partnerAccountId: '10',
|
|
scopeType: 'DISTRICT',
|
|
districtCodes: ['410105'],
|
|
companyName: '甲公司',
|
|
},
|
|
],
|
|
{ partnerAccountId: '11', scopeType: 'DISTRICT', districtCodes: ['410105'] },
|
|
);
|
|
expect(result.ok).toBe(true);
|
|
});
|
|
|
|
it('allows district partner without district codes', () => {
|
|
const result = validatePartnerCityBinding(
|
|
[],
|
|
{ partnerAccountId: '11', scopeType: 'DISTRICT', districtCodes: [] },
|
|
);
|
|
expect(result.ok).toBe(true);
|
|
});
|
|
|
|
it('allows valid district binding', () => {
|
|
const result = validatePartnerCityBinding(
|
|
[{ id: '1', partnerAccountId: '10', scopeType: 'DISTRICT', districtCodes: ['410105'] }],
|
|
{ partnerAccountId: '11', scopeType: 'DISTRICT', districtCodes: ['410106'] },
|
|
);
|
|
expect(result.ok).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe('validatePartnerCommissionRates', () => {
|
|
it('allows sum within default 5% cap', () => {
|
|
expect(validatePartnerCommissionRates(0.02, 0.03).ok).toBe(true);
|
|
});
|
|
|
|
it('rejects sum above cap', () => {
|
|
const result = validatePartnerCommissionRates(0.03, 0.03, 0.05);
|
|
expect(result.ok).toBe(false);
|
|
expect(result.message).toContain('5.00%');
|
|
});
|
|
|
|
it('respects custom city cap', () => {
|
|
expect(validatePartnerCommissionRates(0.04, 0.04, 0.08).ok).toBe(true);
|
|
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);
|
|
});
|
|
});
|