const test = require('node:test'); const assert = require('node:assert'); const { calculate } = require('../provisionService'); function baseInput(overrides = {}) { return Object.assign({ schaltung: { hardware: null, hardware_ek: null, kundenverkaufspreis_netto: null }, tarif: { id: 1, name: 'Tarif X', provision_euro: 100, mitarbeiter_provision: 0, beschreibung: null }, tarifRule: null, anbieterRule: null, tarifoptionen: [], mitarbeiterProzentsatz: 10, }, overrides); } test('falls back to direct tariff commission when no rules exist', () => { const r = calculate(baseInput()); assert.strictEqual(r.shop.betrag, 100); assert.strictEqual(r.shop.quelle, 'Direkte Tarif-Provision'); }); test('tariff-specific fix rule wins over global and direct', () => { const r = calculate(baseInput({ tarifRule: { provision_typ: 'fix', betrag: 50, basis_euro: null }, anbieterRule: { provision_typ: 'fix', betrag: 30, basis_euro: null }, })); assert.strictEqual(r.shop.betrag, 50); assert.strictEqual(r.shop.quelle, 'Tarif-spezifische Regel'); }); test('global anbieter rule applied when no tariff-specific rule', () => { const r = calculate(baseInput({ tarifRule: null, anbieterRule: { provision_typ: 'fix', betrag: 25, basis_euro: null }, })); assert.strictEqual(r.shop.betrag, 25); assert.strictEqual(r.shop.quelle, 'Globale Anbieter-Regel'); }); test('percent rule uses basis_euro as the base', () => { const r = calculate(baseInput({ anbieterRule: { provision_typ: 'prozent', betrag: 12, basis_euro: 200 }, })); assert.strictEqual(r.shop.betrag, 24); }); test('percent rule with missing basis_euro yields 0', () => { const r = calculate(baseInput({ anbieterRule: { provision_typ: 'prozent', betrag: 12, basis_euro: null }, })); assert.strictEqual(r.shop.betrag, 0); }); test('tarifoptionen are added (positive)', () => { const r = calculate(baseInput({ tarifoptionen: [{ name: 'Bonus', provision_euro: 25 }], })); assert.strictEqual(r.shop.betrag, 125); assert.strictEqual(r.tarifoptionen.betrag, 25); }); test('tarifoptionen rebates (negative) reduce commission', () => { const r = calculate(baseInput({ tarifoptionen: [{ name: 'Rabatt', provision_euro: -30 }], })); assert.strictEqual(r.shop.betrag, 70); }); test('hardware adds (KVP - EK) to commission', () => { const r = calculate(baseInput({ schaltung: { hardware: '123456789012345', hardware_ek: 40, kundenverkaufspreis_netto: 100 }, })); assert.strictEqual(r.shop.betrag, 160); // 100 + (100 - 40) assert.strictEqual(r.hardware_gewinn, 60); }); test('hardware ignored when hardware string is empty', () => { const r = calculate(baseInput({ schaltung: { hardware: '', hardware_ek: 40, kundenverkaufspreis_netto: 100 }, })); assert.strictEqual(r.shop.betrag, 100); }); test('employee fix rule wins regardless of percent fallback', () => { const r = calculate(baseInput({ tarifRule: { provision_typ: 'fix', betrag: 100, basis_euro: null, verkaeufer_provision_typ: 'fix', verkaeufer_provision_betrag: 15, }, })); assert.strictEqual(r.shop.betrag, 100); assert.strictEqual(r.mitarbeiter.betrag, 15); }); test('employee percent rule uses shop commission as base', () => { const r = calculate(baseInput({ tarifRule: { provision_typ: 'fix', betrag: 200, basis_euro: null, verkaeufer_provision_typ: 'prozent', verkaeufer_provision_betrag: 10, }, })); assert.strictEqual(r.shop.betrag, 200); assert.strictEqual(r.mitarbeiter.betrag, 20); }); test('employee falls back to anbieter percentage when rule has no employee fields', () => { const r = calculate(baseInput({ tarif: { provision_euro: 100 }, mitarbeiterProzentsatz: 8, })); assert.strictEqual(r.shop.betrag, 100); assert.strictEqual(r.mitarbeiter.betrag, 8); // 8% of 100 }); test('rounding produces 2-decimal numbers', () => { const r = calculate(baseInput({ anbieterRule: { provision_typ: 'prozent', betrag: 33.33, basis_euro: 100 }, })); assert.strictEqual(r.shop.betrag, 33.33); }); test('full scenario: tariff rule + tarifoptionen + hardware + employee %', () => { const r = calculate({ schaltung: { hardware: '111111111111111', hardware_ek: 50, kundenverkaufspreis_netto: 80 }, tarif: { provision_euro: 0 }, tarifRule: { provision_typ: 'fix', betrag: 200, basis_euro: null, verkaeufer_provision_typ: 'prozent', verkaeufer_provision_betrag: 10, }, anbieterRule: null, tarifoptionen: [{ name: 'Aktion', provision_euro: 25 }, { name: 'Rabatt', provision_euro: -45 }], mitarbeiterProzentsatz: 0, }); // shop = 200 + (25 - 45) + (80 - 50) = 200 - 20 + 30 = 210 assert.strictEqual(r.shop.betrag, 210); // employee = 10% of 210 = 21 assert.strictEqual(r.mitarbeiter.betrag, 21); });