Files
doormilxpress_astryx/tests/lib/skills/CashExposureSkill.test.js

68 lines
3.2 KiB
JavaScript

import { CashExposureSkill } from '@/lib/assistant/skills/definitions/CashExposureSkill';
describe('CashExposureSkill', () => {
const NOW = '2026-08-31 14:00:00';
it('flags riders carrying total COD cash above max threshold', () => {
const rows = [
// Rider 1: 12000 total (Critical)
{ bookingid: 1, userid: 101, ridername: 'Rider A', orderstatus: 'picked', paymenttype: 'cod', cod_amount: '5000' },
{ bookingid: 2, userid: 101, ridername: 'Rider A', orderstatus: 'accepted', paymenttype: 'cod', cod_amount: '7000' },
// Rider 2: 8000 total (Warning)
{ bookingid: 3, userid: 102, ridername: 'Rider B', orderstatus: 'picked', paymenttype: 'cod', cod_amount: '8000' },
// Rider 3: 4000 total (Safe)
{ bookingid: 4, userid: 103, ridername: 'Rider C', orderstatus: 'picked', paymenttype: 'cod', cod_amount: '4000' },
// Non-COD order for Rider 1 (Ignored)
{ bookingid: 5, userid: 101, ridername: 'Rider A', orderstatus: 'picked', paymenttype: 'prepaid', cod_amount: '0' }
];
const findings = CashExposureSkill.evaluate(rows, NOW, { maxCashPerRider: 10000, warningCashPercent: 75 });
const critical = findings.find((f) => f.id === 'cash_exposure_critical');
const warning = findings.find((f) => f.id === 'cash_exposure_warning');
expect(critical).toBeDefined();
expect(critical.count).toBe(1); // Only Rider 1
expect(critical.rows.length).toBe(2); // Rider 1 has 2 COD orders
expect(critical.detail[0]).toContain('12,000');
expect(warning).toBeDefined();
expect(warning.count).toBe(1); // Only Rider 2
expect(warning.detail[0]).toContain('8,000');
});
it('returns no findings when all riders are under warning threshold', () => {
const rows = [
{ bookingid: 1, userid: 101, orderstatus: 'picked', paymenttype: 'cod', cod_amount: '5000' }
];
const findings = CashExposureSkill.evaluate(rows, NOW, { maxCashPerRider: 10000, warningCashPercent: 75 });
expect(findings.length).toBe(0);
});
it('executes enforce_cash_handoff tool handler', async () => {
const tool = CashExposureSkill.tools.find((t) => t.name === 'enforce_cash_handoff');
expect(tool).toBeDefined();
const result = await tool.handler({ milerId: 101, totalCash: 12000, hubId: 'HUB-1' });
expect(result.success).toBe(true);
expect(result.proposal.action).toBe('cash_handoff');
expect(result.proposal.milerId).toBe(101);
expect(result.proposal.totalCash).toBe(12000);
expect(result.proposal.hubId).toBe('HUB-1');
});
it('handles orders with non-numeric or missing amounts gracefully', () => {
const rows = [
{ bookingid: 1, userid: 101, orderstatus: 'picked', paymenttype: 'cod' }, // missing amount
{ bookingid: 2, userid: 101, orderstatus: 'picked', paymenttype: 'cod', cod_amount: 'invalid' }, // invalid amount
{ bookingid: 3, userid: 101, orderstatus: 'picked', paymenttype: 'cod', cod_amount: '12000' } // valid amount
];
const findings = CashExposureSkill.evaluate(rows, NOW, { maxCashPerRider: 10000, warningCashPercent: 75 });
const critical = findings.find((f) => f.id === 'cash_exposure_critical');
expect(critical).toBeDefined();
expect(critical.detail[0]).toContain('12,000');
});
});