UNPKG

@accounter/scraper-app

Version:
149 lines (137 loc) 5.08 kB
import type { z } from 'zod'; import type { HapoalimForeignTransactionsBusiness, HapoalimForeignTransactionsPersonal, HapoalimILSTransactions, IsracardCardsTransactionsList, SwiftTransactions, } from '@accounter/modern-poalim-scraper'; import type { SourceType, ValidatedPayload } from './check-accounts.js'; import type { CalPayload } from './payload-schemas/cal.schema.js'; import type { DiscountPayload } from './payload-schemas/discount.schema.js'; import type { MaxPayload } from './payload-schemas/max.schema.js'; import type { CalAccountSchema, DiscountAccountSchema, IsracardAmexAccountSchema, MaxAccountSchema, PoalimAccountSchema, } from './vault.js'; export type FilterableCreds = | z.infer<typeof PoalimAccountSchema> | z.infer<typeof IsracardAmexAccountSchema> | z.infer<typeof CalAccountSchema> | z.infer<typeof MaxAccountSchema> | z.infer<typeof DiscountAccountSchema>; export function effectiveSet( accepted: string[] | undefined, ignored: string[] | undefined, all: string[], ): Set<string> { const base = accepted?.length ? accepted : all; const ignoredSet = new Set(ignored ?? []); return new Set(base.filter(c => !ignoredSet.has(c))); } function filterIsracardAmex( payload: IsracardCardsTransactionsList, accepted: string[] | undefined, ignored: string[] | undefined, ): IsracardCardsTransactionsList { const bean = payload.CardsTransactionsListBean; const allCards = bean.cardNumberList.map(c => c.match(/\d{4}/)?.[0]); const allowed = effectiveSet(accepted, ignored, allCards.filter(Boolean) as string[]); const filteredBean: Record<string, unknown> = {}; for (const [key, val] of Object.entries(bean)) { if (/^Index\d+$/.test(key)) { const card = allCards[Number(key.slice(5))]; // 'Index0' → 0 → cardNumbers[0] if (!card || !allowed.has(card)) { continue; } } filteredBean[key] = val; } return { ...payload, CardsTransactionsListBean: filteredBean as IsracardCardsTransactionsList['CardsTransactionsListBean'], }; } export function filterPayload( type: SourceType, payload: ValidatedPayload, creds: FilterableCreds, ): ValidatedPayload { switch (type) { case 'isracard': case 'amex': { const p = payload as IsracardCardsTransactionsList; const opts = (creds as z.infer<typeof IsracardAmexAccountSchema>).options; return filterIsracardAmex( p, opts?.acceptedCardNumbers, opts?.ignoredCardNumbers, ) as IsracardCardsTransactionsList; } case 'cal': { const p = payload as CalPayload; const opts = (creds as z.infer<typeof CalAccountSchema>).options; const allCards = [...new Set(p.map(e => e.card))]; const allowed = effectiveSet(opts?.acceptedCardNumbers, opts?.ignoredCardNumbers, allCards); return p.filter(e => allowed.has(e.card)); } case 'max': { const p = payload as MaxPayload; const opts = (creds as z.infer<typeof MaxAccountSchema>).options; const allAccounts = [...new Set(p.map(e => e.accountNumber))]; const allowed = effectiveSet( opts?.acceptedCardNumbers, opts?.ignoredCardNumbers, allAccounts, ); return p.filter(e => allowed.has(e.accountNumber)); } case 'poalim': { const opts = (creds as z.infer<typeof PoalimAccountSchema>).options; // PoalimIls has retrievalTransactionData; Foreign has balancesAndLimitsDataList; Swift has swiftsList if ('retrievalTransactionData' in payload) { const p = payload as HapoalimILSTransactions; const { accountNumber, branchNumber } = p.retrievalTransactionData; const allAccounts = [String(accountNumber)]; const allBranches = [String(branchNumber)]; const allowedAccounts = effectiveSet( opts?.acceptedAccountNumbers, opts?.ignoredAccountNumbers, allAccounts, ); const allowedBranches = effectiveSet( opts?.acceptedBranchNumbers, opts?.ignoredBranchNumbers, allBranches, ); if ( !allowedAccounts.has(String(accountNumber)) || !allowedBranches.has(String(branchNumber)) ) { return { ...p, transactions: [] }; } return p; } if ('balancesAndLimitsDataList' in payload) { // Foreign payloads carry no account/branch identifiers — account-level filtering // is handled by the caller, which correlates each Foreign payload with its // positionally-matched ILS payload (which does carry the identifiers). return payload as HapoalimForeignTransactionsPersonal | HapoalimForeignTransactionsBusiness; } if ('swiftsList' in payload) { // Swift payloads carry no account/branch identifiers — same as Foreign above. return payload as SwiftTransactions; } return payload; } case 'discount': { // No filter options for discount const p = payload as DiscountPayload; return p; } } }