UNPKG

@accounter/server

Version:
171 lines • 9.68 kB
import { GraphQLError } from 'graphql'; import { AdminContextProvider } from '../../admin-context/providers/admin-context.provider.js'; import { mergeChargesExecutor } from '../../charges/helpers/merge-charges.helper.js'; import { ChargesProvider } from '../../charges/providers/charges.provider.js'; import { CornJobsProvider } from '../providers/corn-jobs.provider.js'; const WIDE_DATE_DIFF_MILLISECONDS = 2_592_000_000; // 30 days const ACCEPTABLE_DATE_DIFF_MILLISECONDS = 86_400_000; // 1 days export const cornJobsResolvers = { Mutation: { mergeChargesByTransactionReference: async (_, __, { injector }) => { try { const { ownerId } = await injector.get(AdminContextProvider).getVerifiedAdminContext(); const candidates = await injector.get(CornJobsProvider).getReferenceMergeCandidates({ ownerId, }); const chargeIds = new Set(candidates.map(candidate => candidate.charge_id)); const charges = await injector .get(ChargesProvider) .getChargeByIdLoader.loadMany(Array.from(chargeIds)) .then(res => res.filter(charge => charge && !(charge instanceof Error))); const referenceMap = new Map(); candidates.map(candidate => { const reference = candidate.source_reference; if (!reference) { throw new GraphQLError('reference is missing'); } const charge = charges.find(charge => charge.id === candidate.charge_id); if (!charge) { throw new GraphQLError(`Charge is missing for transaction ID=${candidate.id}`); } if (!referenceMap.has(reference)) { referenceMap.set(reference, []); } referenceMap.get(reference)?.push({ transaction: candidate, charge }); }); const mergableMathces = {}; Array.from(referenceMap.values()).map(candidates => { const candidatesIDs = new Set(candidates.map(candidate => candidate.transaction.id)); for (const { transaction, charge } of candidates) { if (!transaction.id || !candidatesIDs.has(transaction.id) || !transaction.event_date) { continue; } candidatesIDs.delete(transaction.id); // filter candidates const fromDate = transaction.event_date.getTime() - ACCEPTABLE_DATE_DIFF_MILLISECONDS; const toDate = transaction.event_date.getTime() + ACCEPTABLE_DATE_DIFF_MILLISECONDS; const widelyFromDate = transaction.event_date.getTime() - WIDE_DATE_DIFF_MILLISECONDS; const widelyToDate = transaction.event_date.getTime() + WIDE_DATE_DIFF_MILLISECONDS; const matches = candidates.filter(({ transaction: internatTransaction }) => { if (!candidatesIDs.has(internatTransaction.id)) { return false; } const isWithinTimeRange = internatTransaction.event_date.getTime() >= fromDate && internatTransaction.event_date.getTime() <= toDate; // check if details match const isWidelyInTimeRange = internatTransaction.event_date.getTime() >= widelyFromDate && internatTransaction.event_date.getTime() <= widelyToDate; const areDetailsSufficient = isWidelyInTimeRange && internatTransaction.source_description && internatTransaction.source_description.length >= 5 && transaction.source_description && transaction.source_description.length >= 5; const isMatchingDetails = areDetailsSufficient && (internatTransaction.source_description?.includes(transaction.source_description) || internatTransaction.source_description?.includes(transaction.source_description)); return isWithinTimeRange || isMatchingDetails; }); if (matches.length === 0) { return; } matches.map(match => candidatesIDs.delete(match.transaction.id)); matches.push({ transaction, charge }); // preparation for merge: rearrange based on charge const chargesWithTransactions = new Map(); matches.map(({ transaction, charge }) => { if (!chargesWithTransactions.has(charge.id)) { chargesWithTransactions.set(charge.id, { transactions: [], charge }); } chargesWithTransactions.get(charge.id)?.transactions.push(transaction); }); if (chargesWithTransactions.size === 1) { return; } // figure which charge will be the main for merge const chargeMatches = Array.from(chargesWithTransactions.values()); const mainCandidates = chargeMatches.filter(({ charge, transactions }) => { const isFee = !transactions.some(transaction => !transaction.is_fee); const isUnlinked = !!charge.user_description?.includes('unlinked from charge'); return !isFee && !isUnlinked; }); if (mainCandidates.length === 0) { const main = chargeMatches.shift(); logMatch(main, chargeMatches); mergableMathces[main.charge.id] = chargeMatches.map(match => match.charge.id); return; } if (mainCandidates.length === 1) { const main = mainCandidates[0]; const chargesToMerge = chargeMatches.filter(match => match.charge.id !== main.charge.id); logMatch(main, chargesToMerge); mergableMathces[main.charge.id] = chargesToMerge.map(match => match.charge.id); return; } const main = chargeMatches.shift(); logMatch(main, chargeMatches); console.log('not sure what to do now'); } }); // execute merges const chargeMergePromises = Object.entries(mergableMathces).map(async ([baseChargeID, chargeIdsToMerge]) => { await mergeChargesExecutor(chargeIdsToMerge, baseChargeID, injector); console.log(`Merged into charge ID=${baseChargeID} successfully`); }); await Promise.all(chargeMergePromises); return { success: true, charges: Object.keys(mergableMathces) .map(id => charges.find(charge => charge.id === id)) .filter(charge => charge), }; } catch (e) { if (e instanceof GraphQLError) { throw e; } return { success: false, errors: [e?.message ?? 'Unknown error'], }; } }, flagForeignFeeTransactions: async (_, __, { injector }) => { try { const { ownerId } = await injector.get(AdminContextProvider).getVerifiedAdminContext(); const res = await injector.get(CornJobsProvider).flagForeignFeeTransactions({ ownerId }); const updatedTransactionsIds = res.map(({ id }) => id); return { success: true, transactions: updatedTransactionsIds, }; } catch (e) { return { success: false, errors: [e?.message ?? 'Unknown error'], }; } }, calculateCreditcardTransactionsDebitDate: async (_, __, { injector }) => { try { const { ownerId } = await injector.get(AdminContextProvider).getVerifiedAdminContext(); await injector.get(CornJobsProvider).calculateCreditcardDebitDate({ ownerId }); return true; } catch (e) { console.error(e); throw new GraphQLError('Failed to calculate creditcard transactions debit date'); } }, }, }; function logMatch(main, others) { console.log('\n\n\n'); for (const { charge, transactions } of [main, ...others]) { console.log(charge.user_description); for (const transaction of transactions) { console.log(' ', transaction.source_description); } } } //# sourceMappingURL=corn-jobs.resolver.js.map