import { describe, it, expect } from 'vitest'; import { mapAdminTenantDetail } from '../../resources/js/composables/adminTenantDetailMapper'; import type { AdminTenantDetailResponse } from '../../resources/js/api/admin'; function makeApi(overrides: Partial = {}): AdminTenantDetailResponse { return { tenant: { id: 1, subdomain: 'test-co', organization_name: 'Test ООО', contact_email: 'admin@test-co.ru', status: 'active', balance_rub: '10000.00', balance_leads: 5, is_trial: false, last_activity_at: null, tariff_id: 1, tariff_name: 'Команда', mrr_rub: '990.00', desired_daily_numbers: 10, chargeback_unrecovered_rub: '0.00', created_at: '2025-01-01T00:00:00+00:00', }, users: [], projects: [], balance_history: [], activity: [], metrics: { leads_today: 5, leads_this_week: 30, leads_this_month: 120, avg_lead_cost_rub: 250, runway_days: 40, }, ...overrides, }; } describe('adminTenantDetailMapper', () => { it('маппит code = subdomain', () => { const ui = mapAdminTenantDetail(makeApi()); expect(ui.code).toBe('test-co'); }); it('маппит name = organization_name', () => { expect(mapAdminTenantDetail(makeApi()).name).toBe('Test ООО'); }); it('inn/contact_phone/legal_address пустые (нет в schema)', () => { const ui = mapAdminTenantDetail(makeApi()); expect(ui.inn).toBe(''); expect(ui.contact_phone).toBe(''); expect(ui.legal_address).toBe(''); }); it('balanceRub парсится из string в number', () => { expect(mapAdminTenantDetail(makeApi()).balanceRub).toBe(10000); }); it('mrrRub: парсится в число для не-trial; null для trial', () => { expect(mapAdminTenantDetail(makeApi()).mrrRub).toBe(990); const trial = mapAdminTenantDetail(makeApi({ tenant: { ...makeApi().tenant, is_trial: true, mrr_rub: null } })); expect(trial.mrrRub).toBeNull(); }); it('status derive: trial при is_trial=true', () => { const ui = mapAdminTenantDetail(makeApi({ tenant: { ...makeApi().tenant, is_trial: true, mrr_rub: null } })); expect(ui.status).toBe('trial'); expect(ui.statusText).toBe('Trial'); }); it('status derive: overdue при balance<0 или chargeback>0', () => { const a = mapAdminTenantDetail(makeApi({ tenant: { ...makeApi().tenant, balance_rub: '-100.00' } })); expect(a.status).toBe('overdue'); const b = mapAdminTenantDetail( makeApi({ tenant: { ...makeApi().tenant, chargeback_unrecovered_rub: '500.00' } }), ); expect(b.status).toBe('overdue'); }); it('status derive: suspended → suspended', () => { const ui = mapAdminTenantDetail(makeApi({ tenant: { ...makeApi().tenant, status: 'suspended' } })); expect(ui.status).toBe('suspended'); }); it('tariff: из tariff_name (или Trial если is_trial)', () => { expect(mapAdminTenantDetail(makeApi()).tariff).toBe('Команда'); const trial = mapAdminTenantDetail(makeApi({ tenant: { ...makeApi().tenant, is_trial: true, mrr_rub: null } })); expect(trial.tariff).toBe('Trial'); }); it('tariff fallback Trial если name не из known list', () => { const ui = mapAdminTenantDetail(makeApi({ tenant: { ...makeApi().tenant, tariff_name: 'NotInList' } })); expect(ui.tariff).toBe('Trial'); }); it('todayActual = metrics.leads_today; todayDesired = desired_daily_numbers', () => { const ui = mapAdminTenantDetail(makeApi()); expect(ui.todayActual).toBe(5); expect(ui.todayDesired).toBe(10); }); it('users mapping: fullName из first+last; fallback на email', () => { const ui = mapAdminTenantDetail( makeApi({ users: [ { id: 1, email: 'a@b.ru', first_name: 'Иван', last_name: 'Петров', is_active: true, totp_enabled: false, last_active_at: null, last_login_at: null, }, { id: 2, email: 'c@d.ru', first_name: null, last_name: null, is_active: false, totp_enabled: false, last_active_at: null, last_login_at: null, }, ], }), ); expect(ui.users[0]!.fullName).toBe('Иван Петров'); expect(ui.users[1]!.fullName).toBe('c@d.ru'); expect(ui.users[0]!.role).toBe('manager'); }); it('projects mapping: slug=tag, suppliers=suppliers_count, leadsToday/desiredToday', () => { const ui = mapAdminTenantDetail( makeApi({ projects: [ { id: 1, name: 'P1', tag: 'p1-slug', is_active: true, daily_limit_target: 8, suppliers_count: 3, leads_today: 5, }, ], }), ); expect(ui.projects[0]!.slug).toBe('p1-slug'); expect(ui.projects[0]!.suppliers).toBe(3); expect(ui.projects[0]!.leadsToday).toBe(5); expect(ui.projects[0]!.desiredToday).toBe(8); }); it('balanceHistory: id префиксуется TX-, amount парсится в number', () => { const ui = mapAdminTenantDetail( makeApi({ balance_history: [ { id: 347, type: 'topup', amount_rub: '5000.00', amount_leads: 0, balance_rub_after: '15000.00', description: 'X', created_at: '2026-01-01T00:00:00Z', }, ], }), ); expect(ui.balanceHistory[0]!.id).toBe('TX-347'); expect(ui.balanceHistory[0]!.amount).toBe(5000); expect(ui.balanceHistory[0]!.type).toBe('topup'); }); it('balanceHistory: chargeback_writedown → manual_adjustment, chargeback_repayment → topup', () => { const ui = mapAdminTenantDetail( makeApi({ balance_history: [ { id: 1, type: 'chargeback_writedown', amount_rub: '-500', amount_leads: 0, balance_rub_after: null, description: '', created_at: '2026-01-01T00:00:00Z', }, { id: 2, type: 'chargeback_repayment', amount_rub: '500', amount_leads: 0, balance_rub_after: null, description: '', created_at: '2026-01-01T00:00:00Z', }, ], }), ); expect(ui.balanceHistory[0]!.type).toBe('manual_adjustment'); expect(ui.balanceHistory[1]!.type).toBe('topup'); }); it('activity: actor=actor_email; null → system', () => { const ui = mapAdminTenantDetail( makeApi({ activity: [ { id: 1, event: 'webhook.received', deal_id: 100, actor_email: null, context: null, created_at: '2026-01-01T00:00:00Z', }, { id: 2, event: 'deal.status_changed', deal_id: 200, actor_email: 'user@test.io', context: { from: 'new', to: 'worked' }, created_at: '2026-01-01T00:00:00Z', }, ], }), ); expect(ui.activity[0]!.actor).toBe('system'); expect(ui.activity[1]!.actor).toBe('user@test.io'); expect(ui.activity[1]!.summary).toBe('Сделка #200: new → worked'); }); it('metrics: leadsThisMonth/Week/avgLeadCost/runwayDays', () => { const ui = mapAdminTenantDetail(makeApi()); expect(ui.leadsThisMonth).toBe(120); expect(ui.leadsThisWeek).toBe(30); expect(ui.avgLeadCost).toBe(250); expect(ui.runwayDays).toBe(40); }); it('avgLeadCost / runwayDays default 0 если null', () => { const ui = mapAdminTenantDetail( makeApi({ metrics: { leads_today: 0, leads_this_week: 0, leads_this_month: 0, avg_lead_cost_rub: null, runway_days: null, }, }), ); expect(ui.avgLeadCost).toBe(0); expect(ui.runwayDays).toBe(0); }); it('activitySince: «N мин назад» / «не активен» если null', () => { const now = new Date('2026-05-09T12:00:00Z'); const ui1 = mapAdminTenantDetail( makeApi({ tenant: { ...makeApi().tenant, last_activity_at: '2026-05-09T11:30:00Z', }, }), now, ); expect(ui1.activitySince).toBe('30 мин назад'); const ui2 = mapAdminTenantDetail(makeApi(), now); expect(ui2.activitySince).toBe('не активен'); }); });