/** * Commission Calculation Service * * This service handles all commission calculations for schaltungen. * It implements a fallback hierarchy for determining commission rates: * 1. Direct tariff commission (highest priority) * 2. Tariff-specific rules * 3. Global provider rules (fallback) * 4. Tariff options (additive) */ /** * Calculate shop commission based on hierarchy * @param {Object} schaltungData - Data from database including tariff and provider info * @param {Array} tarifoptionen - Selected tariff options for this schaltung * @returns {Object} Calculation result with amount, type, description, and source */ function calculateShopProvision(schaltungData, tarifoptionen) { let provision_typ = null; let provision_betrag = null; let provision_beschreibung = null; let berechnete_provision = 0; let quelle = 'Keine Shop-Provision definiert'; // Priority 1: Direct tariff commission if (schaltungData.tarif_provision_typ && schaltungData.tarif_provision_betrag) { provision_typ = schaltungData.tarif_provision_typ; provision_betrag = schaltungData.tarif_provision_betrag; provision_beschreibung = schaltungData.tarif_provision_beschreibung; quelle = 'Direkte Tarif-Provision'; } // Priority 2: Tariff-specific rule else if (schaltungData.regel_provision_typ && schaltungData.regel_provision_betrag) { provision_typ = schaltungData.regel_provision_typ; provision_betrag = schaltungData.regel_provision_betrag; provision_beschreibung = schaltungData.regel_provision_beschreibung; quelle = 'Tarif-spezifische Regel'; } // Priority 3: Global provider rule as fallback else if (schaltungData.global_provision_typ && schaltungData.global_provision_betrag) { provision_typ = schaltungData.global_provision_typ; provision_betrag = schaltungData.global_provision_betrag; provision_beschreibung = schaltungData.global_provision_beschreibung; quelle = 'Globale Anbieter-Regel'; } // Calculate base commission if (provision_typ && provision_betrag) { if (provision_typ === 'fix') { berechnete_provision = parseFloat(provision_betrag); } else if (provision_typ === 'prozent') { const basisBetrag = 100; // This could come from tariff table berechnete_provision = (parseFloat(provision_betrag) / 100) * basisBetrag; } } // Add tarifoptionen to commission let tarifoptionen_provision = 0; let verwendete_tarifoptionen = []; if (tarifoptionen && tarifoptionen.length > 0) { tarifoptionen.forEach(option => { if (option.provision_betrag && option.provision_betrag > 0) { tarifoptionen_provision += parseFloat(option.provision_betrag); verwendete_tarifoptionen.push(option.name); } }); } berechnete_provision += tarifoptionen_provision; // Update description if tarifoptionen were added if (tarifoptionen_provision > 0) { const tarifoptionen_text = verwendete_tarifoptionen.join(', '); provision_beschreibung = provision_beschreibung ? `${provision_beschreibung} + Tarifoptionen: ${tarifoptionen_text}` : `Tarifoptionen: ${tarifoptionen_text}`; } return { typ: provision_typ, betrag: provision_betrag, beschreibung: provision_beschreibung, berechnete_provision: berechnete_provision, quelle: quelle, tarifoptionen_provision: tarifoptionen_provision }; } /** * Calculate employee commission based on hierarchy * @param {Object} schaltungData - Data from database including tariff and provider info * @param {number} shopProvision - Calculated shop commission (for percentage calculations) * @returns {Object} Calculation result with amount, type, description, and source */ function calculateMitarbeiterProvision(schaltungData, shopProvision) { let provision_typ = null; let provision_betrag = null; let provision_beschreibung = null; let berechnete_provision = 0; let quelle = 'Keine Mitarbeiter-Provision definiert'; // Priority 1: Direct tariff employee commission if (schaltungData.tarif_verkaeufer_provision_typ && schaltungData.tarif_verkaeufer_provision_betrag) { provision_typ = schaltungData.tarif_verkaeufer_provision_typ; provision_betrag = schaltungData.tarif_verkaeufer_provision_betrag; provision_beschreibung = schaltungData.tarif_verkaeufer_provision_beschreibung; quelle = 'Direkte Tarif-Verkäufer-Provision'; } // Priority 2: Tariff-specific rule employee commission else if (schaltungData.regel_verkaeufer_provision_typ && schaltungData.regel_verkaeufer_provision_betrag) { provision_typ = schaltungData.regel_verkaeufer_provision_typ; provision_betrag = schaltungData.regel_verkaeufer_provision_betrag; provision_beschreibung = schaltungData.regel_verkaeufer_provision_beschreibung; quelle = 'Tarif-spezifische Verkäufer-Regel'; } // Priority 3: Global provider rule employee commission else if (schaltungData.global_verkaeufer_provision_typ && schaltungData.global_verkaeufer_provision_betrag) { provision_typ = schaltungData.global_verkaeufer_provision_typ; provision_betrag = schaltungData.global_verkaeufer_provision_betrag; provision_beschreibung = schaltungData.global_verkaeufer_provision_beschreibung; quelle = 'Globale Anbieter-Verkäufer-Regel'; } // Calculate employee commission if (provision_typ && provision_betrag) { if (provision_typ === 'fix') { berechnete_provision = parseFloat(provision_betrag); } else if (provision_typ === 'prozent') { // If percentage, calculate based on shop commission berechnete_provision = (parseFloat(provision_betrag) / 100) * shopProvision; } } return { typ: provision_typ, betrag: provision_betrag, beschreibung: provision_beschreibung, berechnete_provision: berechnete_provision, quelle: quelle }; } /** * Main function to calculate all commissions for a schaltung * @param {Object} schaltungData - Complete schaltung data with tariff and provider info * @param {Array} tarifoptionen - Selected tariff options * @returns {Object} Complete commission calculation result */ function calculateProvision(schaltungData, tarifoptionen) { const shopResult = calculateShopProvision(schaltungData, tarifoptionen); const mitarbeiterResult = calculateMitarbeiterProvision(schaltungData, shopResult.berechnete_provision); return { schaltung: { id: schaltungData.id, schaltungs_id: schaltungData.schaltungs_id, tarif: schaltungData.tarif_name, anbieter: schaltungData.anbieter_name }, shop_provision: { typ: shopResult.typ, betrag: shopResult.betrag, beschreibung: shopResult.beschreibung, berechnete_provision: shopResult.berechnete_provision, quelle: shopResult.quelle }, mitarbeiter_provision: { typ: mitarbeiterResult.typ, betrag: mitarbeiterResult.betrag, beschreibung: mitarbeiterResult.beschreibung, berechnete_provision: mitarbeiterResult.berechnete_provision, quelle: mitarbeiterResult.quelle, prozentsatz: schaltungData.mitarbeiter_prozentsatz || 0 }, tarifoptionen: tarifoptionen || [], tarifoptionen_provision: shopResult.tarifoptionen_provision }; } module.exports = { calculateProvision, calculateShopProvision, calculateMitarbeiterProvision };