Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
44 lines
2.9 KiB
TypeScript
44 lines
2.9 KiB
TypeScript
import { describe, expect, it } from 'vitest';
|
||
import { partnerSplit, partnerTerms, withinDailyLimits } from './partners.ts';
|
||
import { isProviderFreeWithGap } from './slots.ts';
|
||
import { fromYerevan } from './time.ts';
|
||
|
||
describe('партнёры услуг: деньги', () => {
|
||
it('как Uber: наш % с оплаченного, остальное партнёру', () => {
|
||
const r = partnerSplit(20_000, { deal: 'COMMISSION', commissionPct: 30, profitSharePct: 0, fotPct: 0, taxPct: 0 });
|
||
expect(r).toMatchObject({ partner: 14_000, margin: 6_000, fot: 0, tax: 0, pct: 30 });
|
||
});
|
||
|
||
it('расходы наши: % партнёра от (оплачено − ФОТ − налог)', () => {
|
||
const r = partnerSplit(20_000, { deal: 'PROFIT_SHARE', commissionPct: 0, profitSharePct: 30, fotPct: 60, taxPct: 5 });
|
||
// ФОТ 12 000, налог 1 000, прибыль 7 000 → партнёру 2 100
|
||
expect(r).toMatchObject({ fot: 12_000, tax: 1_000, partner: 2_100, cost: 14_100, margin: 5_900 });
|
||
});
|
||
|
||
it('ФОТ и налог по умолчанию из настроек, свои — у партнёра', () => {
|
||
const base = { deal: 'PROFIT_SHARE' as const, commissionPct: 0, profitSharePct: 50 };
|
||
expect(partnerTerms({ ...base, fotPct: null, taxPct: null }, { fotPct: 50, taxPct: 10 })).toMatchObject({ fotPct: 50, taxPct: 10 });
|
||
expect(partnerTerms({ ...base, fotPct: 40, taxPct: 0 }, { fotPct: 50, taxPct: 10 })).toMatchObject({ fotPct: 40, taxPct: 0 });
|
||
});
|
||
});
|
||
|
||
describe('партнёры услуг: нагрузка сотрудника', () => {
|
||
it('лимит заказов и часов в день', () => {
|
||
const day = [{ durationMinutes: 180 }, { durationMinutes: 120 }];
|
||
expect(withinDailyLimits({ maxOrdersPerDay: 3, maxHoursPerDay: null }, day, 60)).toBe(true);
|
||
expect(withinDailyLimits({ maxOrdersPerDay: 2, maxHoursPerDay: null }, day, 60)).toBe(false);
|
||
expect(withinDailyLimits({ maxOrdersPerDay: null, maxHoursPerDay: 6 }, day, 60)).toBe(true);
|
||
expect(withinDailyLimits({ maxOrdersPerDay: null, maxHoursPerDay: 6 }, day, 61)).toBe(false);
|
||
});
|
||
|
||
it('между заказами остаётся время на дорогу', () => {
|
||
// суббота 24.10.2026, график 9:00–21:00 (0 — понедельник), занят 10:00–12:00
|
||
const p = { id: 'p', schedule: [{ weekday: 5, startMinute: 9 * 60, endMinute: 21 * 60 }], busy: [{ start: fromYerevan(2026, 10, 24, 600), end: fromYerevan(2026, 10, 24, 720) }] };
|
||
const at = (m: number, len = 120) => ({ start: fromYerevan(2026, 10, 24, m), end: fromYerevan(2026, 10, 24, m + len) });
|
||
expect(isProviderFreeWithGap(p, at(12 * 60), 0)).toBe(true);
|
||
expect(isProviderFreeWithGap(p, at(12 * 60 + 30), 60)).toBe(false);
|
||
expect(isProviderFreeWithGap(p, at(13 * 60), 60)).toBe(true);
|
||
expect(isProviderFreeWithGap(p, at(7 * 60 + 30, 90), 60)).toBe(false);
|
||
});
|
||
});
|