import { string } from 'alga-js' import refreshTokenHelper from '../../utils/refreshTokenHelper' import errorHandlingHelper from '../../utils/errorHandlingHelper' import getTokenHelper from '../../utils/getTokenHelper' // GET /api/bi/bank-cash-report?year=2026 // Raw material for the cash-basis GuV / EÜR BI reports: every bank statement // line (c_bankstatementline, all bank accounts, Drafted + Completed statements) // whose StatementLineDate falls into the requested year, plus the own bank // accounts (needed client-side to flag transfers between own accounts). // No account assignment / posting relevance — the sign of StmtAmt decides // income (+) vs expense (−); all grouping happens in useBankCashReport(). const PAGE = 500 const MAX_LINES = 20000 const handleFunc = async (event: any, authToken: any = null) => { const token = authToken ?? await getTokenHelper(event) const query = getQuery(event) const now = new Date() let year = Number(query.year) || now.getFullYear() if (!Number.isInteger(year) || year < 2000 || year > now.getFullYear() + 1) year = now.getFullYear() // Own bank accounts (Volksbank, PayPal, …) — small list, one request. const accRes: any = await event.context.fetch( 'models/c_bankaccount?$select=C_BankAccount_ID,Name,AccountNo,IBAN,IsActive,C_Bank_ID' + `&$expand=${string.urlEncode('C_Bank_ID($select=Name)')}&$orderby=C_BankAccount_ID&$top=50`, 'GET', token, null ) const accounts = (accRes?.records || []).map((a: any) => ({ id: a.id, name: a.Name || a.identifier || `#${a.id}`, accountNo: a.AccountNo || '', iban: a.IBAN || '', bankName: a.C_Bank_ID?.Name || a.C_Bank_ID?.identifier || '', isActive: a.IsActive !== false })) const filter = string.urlEncode( `StatementLineDate ge '${year}-01-01 00:00:00' and StatementLineDate le '${year}-12-31 23:59:59'` ) const select = '$select=C_BankStatementLine_ID,StatementLineDate,ValutaDate,StmtAmt,TrxAmt,ChargeAmt,' + 'EftPayee,EftPayeeAccount,EftMemo,Description,ReferenceNo,C_BankStatement_ID,C_Payment_ID,C_Charge_ID,C_BPartner_ID' const expand = '$expand=' + string.urlEncode( 'C_BankStatement_ID($select=DocumentNo,DocStatus,C_BankAccount_ID),' + 'C_Payment_ID($select=DocumentNo),C_Charge_ID($select=Name),C_BPartner_ID($select=Name)' ) const orderby = string.urlEncode('StatementLineDate,C_BankStatementLine_ID') const records: any[] = [] let skip = 0 let truncated = false while (true) { const res: any = await event.context.fetch( `models/c_bankstatementline?$filter=${filter}&${select}&${expand}&$orderby=${orderby}&$top=${PAGE}&$skip=${skip}`, 'GET', token, null ) const page = res?.records || [] records.push(...page) if (page.length < PAGE) break skip += PAGE if (records.length >= MAX_LINES) { truncated = true; break } } const lines = records .filter((r: any) => { const st = r.C_BankStatement_ID?.DocStatus?.id || r.C_BankStatement_ID?.DocStatus || '' return st !== 'VO' && st !== 'RE' // voided / reversed statements never count }) .map((r: any) => ({ id: r.id, date: String(r.StatementLineDate || '').slice(0, 10), valutaDate: r.ValutaDate ? String(r.ValutaDate).slice(0, 10) : null, amount: Number(r.StmtAmt ?? 0), trxAmt: Number(r.TrxAmt ?? 0), chargeAmt: Number(r.ChargeAmt ?? 0), accountId: r.C_BankStatement_ID?.C_BankAccount_ID?.id || null, statementId: r.C_BankStatement_ID?.id || null, statementNo: r.C_BankStatement_ID?.DocumentNo || r.C_BankStatement_ID?.identifier || '', statementStatus: r.C_BankStatement_ID?.DocStatus?.id || r.C_BankStatement_ID?.DocStatus || '', counterpart: r.EftPayee || '', counterpartAccount: r.EftPayeeAccount || '', memo: r.EftMemo || r.Description || '', reference: r.ReferenceNo || '', matched: r.C_Payment_ID?.id ? 'payment' : (r.C_Charge_ID?.id ? 'charge' : null), paymentNo: r.C_Payment_ID?.DocumentNo || r.C_Payment_ID?.identifier || '', chargeName: r.C_Charge_ID?.Name || r.C_Charge_ID?.identifier || '', partnerName: r.C_BPartner_ID?.Name || r.C_BPartner_ID?.identifier || '' })) return { status: 200, year, accounts, lines, total: lines.length, truncated, generatedAt: new Date().toISOString() } } export default defineEventHandler(async (event) => { let data: any = {} try { data = await handleFunc(event) } catch (err: any) { try { const authToken = await refreshTokenHelper(event) data = await handleFunc(event, authToken) } catch (error: any) { data = errorHandlingHelper(err?.data ?? err, error?.data ?? error) } } return data })