diff --git a/lang/es.json b/lang/es.json index aabf9dba..df18dfbf 100644 --- a/lang/es.json +++ b/lang/es.json @@ -1696,6 +1696,7 @@ "Works everywhere": "Funciona en todas partes", "Would you like to add more accounts or continue to the dashboard?": "¿Quieres agregar más cuentas o continuar al panel?", "YYYY-MM-DD (e.g., 2024-12-31)": "YYYY-MM-DD (ej., 2024-12-31)", + "YYYYMMDD (e.g., 20241231)": "YYYYMMDD (ej., 20241231)", "Year": "Año", "Yearly": "Anual", "Yearly code": "Código anual", diff --git a/resources/js/components/accounts/import-balances/import-balance-step-mapping.tsx b/resources/js/components/accounts/import-balances/import-balance-step-mapping.tsx index 2a336af4..a28a1e1d 100644 --- a/resources/js/components/accounts/import-balances/import-balance-step-mapping.tsx +++ b/resources/js/components/accounts/import-balances/import-balance-step-mapping.tsx @@ -282,6 +282,19 @@ export function ImportBalanceStepMapping({ {__('DD-MM-YYYY (e.g., 31-12-2024)')} +
+ + + +
)} diff --git a/resources/js/components/transactions/import-step-mapping.tsx b/resources/js/components/transactions/import-step-mapping.tsx index 1bb1143e..c52a27ad 100644 --- a/resources/js/components/transactions/import-step-mapping.tsx +++ b/resources/js/components/transactions/import-step-mapping.tsx @@ -593,6 +593,19 @@ export function ImportStepMapping({ {__('DD-MM-YYYY (e.g., 31-12-2024)')} +
+ + + +
)} diff --git a/resources/js/lib/file-parser.test.ts b/resources/js/lib/file-parser.test.ts index dd45e206..1123e3d8 100644 --- a/resources/js/lib/file-parser.test.ts +++ b/resources/js/lib/file-parser.test.ts @@ -72,6 +72,30 @@ describe('convertRowsToTransactions', () => { process.env.TZ = originalTimezone; } }); + + it('parses YYYYMMDD compact dates', () => { + const transactions = convertRowsToTransactions( + [ + { + date: '20241231', + description: 'New Year Eve', + amount: '10.00', + }, + ], + { + transaction_date: 'date', + description: 'description', + amount: 'amount', + balance: null, + creditor_name: null, + debtor_name: null, + }, + DateFormat.YearMonthDayCompact, + ); + + expect(transactions).toHaveLength(1); + expect(transactions[0].transaction_date).toBe('2024-12-31'); + }); }); describe('convertRowsToTransactions balance column', () => { @@ -279,6 +303,17 @@ describe('autoDetectDateFormat', () => { DateFormat.DayMonthYear, ); }); + + it('detects YYYYMMDD compact format unambiguously', () => { + const data = [ + { date: '20240115' }, + { date: '20240220' }, + { date: '20240325' }, + ]; + expect(autoDetectDateFormat(data, 'date')).toBe( + DateFormat.YearMonthDayCompact, + ); + }); }); describe('getLatestTransactionDate', () => { diff --git a/resources/js/lib/file-parser.ts b/resources/js/lib/file-parser.ts index 6b500bff..74369496 100644 --- a/resources/js/lib/file-parser.ts +++ b/resources/js/lib/file-parser.ts @@ -224,12 +224,14 @@ export function autoDetectDateFormat( DateFormat.YearMonthDay, DateFormat.DayMonthYear, DateFormat.MonthDayYear, + DateFormat.YearMonthDayCompact, ]; const sampleSize = Math.min(10, data.length); const scores: Record = { [DateFormat.YearMonthDay]: 0, [DateFormat.DayMonthYear]: 0, [DateFormat.MonthDayYear]: 0, + [DateFormat.YearMonthDayCompact]: 0, }; for (let i = 0; i < sampleSize; i++) { @@ -427,7 +429,14 @@ export function parseDate( month: number | undefined, day: number | undefined; - if (str.length === 5) { + if (format === DateFormat.YearMonthDayCompact) { + const compactArray = /^(\d{4})(\d{2})(\d{2})$/.exec(str); + if (compactArray) { + year = Number(compactArray[1]); + month = Number(compactArray[2]); + day = Number(compactArray[3]); + } + } else if (str.length === 5) { const dateRegex = /^(\d{1,2})-(\d{1,2})$/; const dateArray = dateRegex.exec(str); if (dateArray) { diff --git a/resources/js/types/import.ts b/resources/js/types/import.ts index c309b8eb..719fb9f9 100644 --- a/resources/js/types/import.ts +++ b/resources/js/types/import.ts @@ -11,6 +11,7 @@ export enum DateFormat { YearMonthDay = 'YYYY-MM-DD', MonthDayYear = 'MM-DD-YYYY', DayMonthYear = 'DD-MM-YYYY', + YearMonthDayCompact = 'YYYYMMDD', } export interface ColumnMapping {