/** * Conversion utilities for Receipt form data * * These functions convert between the API format (dynamic arrays) and * the UI format (fixed fields for TVA and payments). */ /** * Default fixed TVA structure for UI */ export const getDefaultTva = () => ({ A: { percent: 19, amount: 0 }, B: { percent: 9, amount: 0 }, C: { percent: 5, amount: 0 }, D: { percent: 0, amount: 0 }, E: { percent: null, amount: 0 }, }) /** * Default fixed payments structure for UI */ export const getDefaultPayments = () => ({ CARD: 0, NUMERAR: 0, ALTE: { amount: 0, type: null }, }) /** * Convert API tva_entries/tva_breakdown array → UI fixed fields * * @param {Array} entries - Array of {code, percent, amount} * @returns {Object} Fixed TVA fields {A, B, C, D, E} */ export const apiToUiTva = (entries) => { const ui = getDefaultTva() if (!entries || !Array.isArray(entries)) { return ui } entries.forEach(entry => { const code = entry.code?.toUpperCase() if (code && ui[code]) { ui[code] = { percent: entry.percent ?? ui[code].percent, amount: parseFloat(entry.amount) || 0 } } }) return ui } /** * Convert UI fixed TVA fields → API tva_breakdown array * Only includes entries with amount > 0 * * @param {Object} tvaUi - Fixed TVA fields {A, B, C, D, E} * @returns {Array} Array of {code, percent, amount} or null if empty */ export const uiToApiTva = (tvaUi) => { if (!tvaUi) return null const entries = Object.entries(tvaUi) .filter(([_, v]) => v.amount && v.amount > 0) .map(([code, v]) => ({ code, percent: v.percent ?? 0, amount: parseFloat(v.amount) || 0 })) return entries.length > 0 ? entries : null } /** * Calculate total TVA from UI fixed fields * * @param {Object} tvaUi - Fixed TVA fields {A, B, C, D, E} * @returns {number} Total TVA amount */ export const calculateTvaTotal = (tvaUi) => { if (!tvaUi) return 0 return Object.values(tvaUi) .reduce((sum, v) => sum + (parseFloat(v.amount) || 0), 0) } /** * Convert API payment_methods array → UI fixed fields * * @param {Array} methods - Array of {method, amount} * @returns {Object} Fixed payment fields {CARD, NUMERAR, ALTE} */ export const apiToUiPayments = (methods) => { const ui = getDefaultPayments() if (!methods || !Array.isArray(methods)) { return ui } methods.forEach(pm => { const method = pm.method?.toUpperCase() const amount = parseFloat(pm.amount) || 0 if (method === 'CARD') { ui.CARD = amount } else if (method === 'NUMERAR' || method === 'CASH') { ui.NUMERAR = amount } else if (method) { // Other payment types go to ALTE ui.ALTE.amount += amount // Try to determine type from method name if (method.includes('TICH') || method.includes('MASA')) { ui.ALTE.type = 'tichete_masa' } else if (method.includes('VOUCHER')) { ui.ALTE.type = 'voucher' } else if (method.includes('CREDIT')) { ui.ALTE.type = 'credit_magazin' } } }) return ui } /** * Convert UI fixed payment fields → API payment_methods array * Only includes entries with amount > 0 * * @param {Object} paymentsUi - Fixed payment fields {CARD, NUMERAR, ALTE} * @returns {Array} Array of {method, amount} or null if empty */ export const uiToApiPayments = (paymentsUi) => { if (!paymentsUi) return null const methods = [] if (paymentsUi.CARD && paymentsUi.CARD > 0) { methods.push({ method: 'CARD', amount: paymentsUi.CARD }) } if (paymentsUi.NUMERAR && paymentsUi.NUMERAR > 0) { methods.push({ method: 'NUMERAR', amount: paymentsUi.NUMERAR }) } if (paymentsUi.ALTE?.amount && paymentsUi.ALTE.amount > 0) { // Map type to method name let methodName = 'ALTE' if (paymentsUi.ALTE.type === 'tichete_masa') { methodName = 'TICHETE_MASA' } else if (paymentsUi.ALTE.type === 'voucher') { methodName = 'VOUCHER' } else if (paymentsUi.ALTE.type === 'credit_magazin') { methodName = 'CREDIT_MAGAZIN' } methods.push({ method: methodName, amount: paymentsUi.ALTE.amount }) } return methods.length > 0 ? methods : null } /** * Calculate total payments from UI fixed fields * * @param {Object} paymentsUi - Fixed payment fields {CARD, NUMERAR, ALTE} * @returns {number} Total payment amount */ export const calculatePaymentsTotal = (paymentsUi) => { if (!paymentsUi) return 0 return ( (paymentsUi.CARD || 0) + (paymentsUi.NUMERAR || 0) + (paymentsUi.ALTE?.amount || 0) ) } /** * Get default form state for unified receipt form */ export const getDefaultUnifiedFormState = () => ({ receipt_type: 'bon_fiscal', receipt_date: new Date(), receipt_number: '', // Supplier (DB validated) partner_name: null, cui: '', vendor_address: '', // Total amount: null, // TVA (5 fixed fields) tva: getDefaultTva(), // Payments (3 fixed fields) payments: getDefaultPayments(), // Auxiliary expense_type_code: null, description: '', // Metadata ocr_raw_text: '', items_count: null, company_id: null, }) /** * Convert legacy form state to unified form state * * @param {Object} legacyForm - Old form format * @returns {Object} Unified form format */ export const legacyToUnifiedForm = (legacyForm) => { return { receipt_type: legacyForm.receipt_type || 'bon_fiscal', receipt_date: legacyForm.receipt_date instanceof Date ? legacyForm.receipt_date : new Date(legacyForm.receipt_date), receipt_number: legacyForm.receipt_number || '', partner_name: legacyForm.partner_name || null, cui: legacyForm.cui || '', vendor_address: legacyForm.vendor_address || '', amount: parseFloat(legacyForm.amount) || null, tva: apiToUiTva(legacyForm.tva_breakdown), payments: apiToUiPayments(legacyForm.payment_methods), expense_type_code: legacyForm.expense_type_code || null, description: legacyForm.description || '', ocr_raw_text: legacyForm.ocr_raw_text || '', items_count: legacyForm.items_count || null, company_id: legacyForm.company_id || null, } } /** * Convert unified form state to API payload * * @param {Object} unifiedForm - Unified form format * @returns {Object} API payload format */ export const unifiedFormToApiPayload = (unifiedForm) => { return { receipt_type: unifiedForm.receipt_type, direction: 'cheltuiala', // Always expense (no more income) receipt_date: unifiedForm.receipt_date instanceof Date ? unifiedForm.receipt_date.toISOString().split('T')[0] : unifiedForm.receipt_date, receipt_number: unifiedForm.receipt_number || null, partner_name: typeof unifiedForm.partner_name === 'string' ? unifiedForm.partner_name : unifiedForm.partner_name?.name || null, cui: unifiedForm.cui || null, vendor_address: unifiedForm.vendor_address || null, amount: unifiedForm.amount || 0, tva_breakdown: uiToApiTva(unifiedForm.tva), tva_total: calculateTvaTotal(unifiedForm.tva) || null, payment_methods: uiToApiPayments(unifiedForm.payments), expense_type_code: unifiedForm.expense_type_code || null, description: unifiedForm.description || null, ocr_raw_text: unifiedForm.ocr_raw_text || null, items_count: unifiedForm.items_count || null, company_id: unifiedForm.company_id, // Legacy fields (removed but kept for backwards compat) payment_mode: null, cash_register_id: null, cash_register_name: null, cash_register_account: null, } }