import { lastDayOfMonth } from 'date-fns';
import { LedgerError } from './utils.helper.js';
function generateEntryRaw(accountId, amount, month, transactionDate, ownerId, isCreditor, chargeId, defaultLocalCurrency) {
    return {
        id: `${accountId}|${month}`,
        invoiceDate: transactionDate,
        valueDate: transactionDate,
        currency: defaultLocalCurrency,
        ...(isCreditor ? { creditAccountID1: accountId } : { debitAccountID1: accountId }),
        localCurrencyCreditAmount1: amount,
        localCurrencyDebitAmount1: amount,
        description: `${month} salary: ${accountId}`,
        isCreditorCounterparty: false,
        ownerId,
        chargeId,
    };
}
function getTotalPension(salaryRecord) {
    const pensionEmployerAmount = Number(salaryRecord.pension_employer_amount ?? '0');
    const pensionEmployeeAmount = Number(salaryRecord.pension_employee_amount ?? '0');
    const compensationsEmployerAmount = Number(salaryRecord.compensations_employer_amount ?? '0');
    const totalPension = pensionEmployeeAmount + pensionEmployerAmount + compensationsEmployerAmount;
    return totalPension;
}
function getTotalTrainingFund(salaryRecord) {
    const trainingFundEmployerAmount = Number(salaryRecord.training_fund_employer_amount ?? '0');
    const trainingFundEmployeeAmount = Number(salaryRecord.training_fund_employee_amount ?? '0');
    const totalTrainingFund = trainingFundEmployeeAmount + trainingFundEmployerAmount;
    return totalTrainingFund;
}
export function generateEntriesFromSalaryRecords(salaryRecords, charge, adminContext) {
    const { salaries: { taxDeductionsBusinessId }, authorities: { socialSecurityBusinessId }, defaultLocalCurrency, salaries, } = adminContext;
    const chargeId = charge.id;
    if (!salaryRecords.length) {
        throw new LedgerError(`No salary records found for charge ${chargeId}`);
    }
    if (!taxDeductionsBusinessId) {
        throw new LedgerError('Tax deductions business is not set');
    }
    const entries = [];
    function generateEntry(chargeId, accountId, amount, month, isCreditor = true) {
        return generateEntryRaw(accountId, amount, month, lastDayOfMonth(new Date(`${month}-01`)), charge.owner_id, isCreditor, chargeId, defaultLocalCurrency);
    }
    const amountPerBusiness = {};
    const taxAmountPerMonth = {};
    let month = undefined;
    // expenses
    let salaryExpensesAmount = 0;
    let socialSecurityExpensesAmount = 0;
    let pensionFundExpensesAmount = 0;
    let compensationProvidentFundExpensesAmount = 0;
    let trainingFundExpensesAmount = 0;
    let zkufotAmount = 0;
    for (const salaryRecord of salaryRecords) {
        // record validations
        if (!salaryRecord.base_salary) {
            throw new LedgerError(`Base salary record for ${salaryRecord.month}, employee ID=${salaryRecord.employee_id}  is missing amount`);
        }
        month ??= salaryRecord.month;
        const salaryExpense = Number(salaryRecord.base_salary ?? '0') +
            Number(salaryRecord.global_additional_hours ?? '0') +
            Number(salaryRecord.bonus ?? '0') +
            Number(salaryRecord.gift ?? '0') +
            Number(salaryRecord.recovery ?? '0') +
            Number(salaryRecord.vacation_takeout ?? '0') +
            Number(salaryRecord.travel_and_subsistence ?? '0');
        const directPayment = salaryExpense -
            Number(salaryRecord.social_security_amount_employee ?? '0') -
            Number(salaryRecord.health_payment_amount ?? '0') -
            Number(salaryRecord.tax_amount ?? '0') -
            Number(salaryRecord.pension_employee_amount ?? '0') -
            Number(salaryRecord.training_fund_employee_amount ?? '0');
        entries.push(generateEntry(charge.id, salaryRecord.employee_id, directPayment, salaryRecord.month));
        // salary expenses handling
        salaryExpensesAmount += salaryExpense;
        // social security handling
        const socialSecurityEmployeeAmount = Number(salaryRecord.social_security_amount_employee ?? '0');
        const socialSecurityEmployerAmount = Number(salaryRecord.social_security_amount_employer ?? '0');
        const HealthPaymentAmount = Number(salaryRecord.health_payment_amount ?? '0');
        amountPerBusiness[socialSecurityBusinessId] ??= 0;
        amountPerBusiness[socialSecurityBusinessId] +=
            socialSecurityEmployeeAmount + socialSecurityEmployerAmount + HealthPaymentAmount;
        socialSecurityExpensesAmount += Number(salaryRecord.social_security_amount_employer ?? '0');
        // pension handling
        const totalPension = getTotalPension(salaryRecord);
        const pensionAccount = salaryRecord.pension_fund_id;
        if (totalPension > 0) {
            if (!pensionAccount) {
                throw new LedgerError(`Missing pension account for charge ID=${chargeId}`);
            }
            amountPerBusiness[pensionAccount] ??= 0;
            amountPerBusiness[pensionAccount] += totalPension;
        }
        pensionFundExpensesAmount += Number(salaryRecord.pension_employer_amount ?? '0');
        compensationProvidentFundExpensesAmount += Number(salaryRecord.compensations_employer_amount ?? '0');
        // training fund handling
        const totalTrainingFund = getTotalTrainingFund(salaryRecord);
        const trainingFundAccount = salaryRecord.training_fund_id;
        if (totalTrainingFund > 0) {
            if (!trainingFundAccount) {
                throw new LedgerError(`Missing training fund account for charge ID=${chargeId}`);
            }
            amountPerBusiness[trainingFundAccount] ??= 0;
            amountPerBusiness[trainingFundAccount] += totalTrainingFund;
        }
        trainingFundExpensesAmount += Number(salaryRecord.training_fund_employer_amount ?? '0');
        // tax handling
        taxAmountPerMonth[salaryRecord.month] ??= 0;
        taxAmountPerMonth[salaryRecord.month] += Number(salaryRecord.tax_amount ?? '0');
        // zkufot handling
        zkufotAmount += Number(salaryRecord.zkufot ?? '0');
    }
    if (!month) {
        throw new LedgerError(`No month found for salary charge ID=${chargeId}`);
    }
    // generate pension/training funds entries
    for (const [businessId, amount] of Object.entries(amountPerBusiness)) {
        if (amount) {
            entries.push(generateEntry(charge.id, businessId, amount, month));
        }
    }
    // generate tax entries
    for (const [month, amount] of Object.entries(taxAmountPerMonth)) {
        if (amount > 0) {
            entries.push(generateEntry(charge.id, taxDeductionsBusinessId, amount, month));
        }
    }
    const monthlyEntriesProto = getMonthlyExpensesEntriesProto({
        salaryExpensesAmount,
        socialSecurityExpensesAmount,
        pensionFundExpensesAmount,
        compensationProvidentFundExpensesAmount,
        trainingFundExpensesAmount,
        zkufotAmount,
        salaries,
    });
    return {
        entries,
        monthlyEntriesProto,
        month,
    };
}
export function getMonthlyExpensesEntriesProto({ salaryExpensesAmount, socialSecurityExpensesAmount, pensionFundExpensesAmount, compensationProvidentFundExpensesAmount, trainingFundExpensesAmount, zkufotAmount, salaries, }) {
    const { zkufotExpensesTaxCategoryId, zkufotIncomeTaxCategoryId, socialSecurityExpensesTaxCategoryId, salaryExpensesTaxCategoryId, trainingFundExpensesTaxCategoryId, pensionExpensesTaxCategoryId, compensationFundExpensesTaxCategoryId, } = salaries;
    if (!zkufotExpensesTaxCategoryId ||
        !zkufotIncomeTaxCategoryId ||
        !socialSecurityExpensesTaxCategoryId ||
        !salaryExpensesTaxCategoryId ||
        !trainingFundExpensesTaxCategoryId ||
        !pensionExpensesTaxCategoryId ||
        !compensationFundExpensesTaxCategoryId) {
        throw new LedgerError('Missing salary tax categories');
    }
    const monthlyEntriesProto = [
        {
            taxCategoryId: zkufotExpensesTaxCategoryId,
            amount: zkufotAmount,
            isCredit: false,
        },
        {
            taxCategoryId: zkufotIncomeTaxCategoryId,
            amount: zkufotAmount,
            isCredit: true,
        },
        {
            taxCategoryId: socialSecurityExpensesTaxCategoryId,
            amount: socialSecurityExpensesAmount,
            isCredit: false,
        },
        {
            taxCategoryId: salaryExpensesTaxCategoryId,
            amount: salaryExpensesAmount,
            isCredit: false,
        },
        {
            taxCategoryId: trainingFundExpensesTaxCategoryId,
            amount: trainingFundExpensesAmount,
            isCredit: false,
        },
        {
            taxCategoryId: pensionExpensesTaxCategoryId,
            amount: pensionFundExpensesAmount,
            isCredit: false,
        },
        {
            taxCategoryId: compensationFundExpensesTaxCategoryId,
            amount: compensationProvidentFundExpensesAmount,
            isCredit: false,
        },
    ];
    return monthlyEntriesProto;
}
//# sourceMappingURL=salary-charge-ledger.helper.js.map