Skip to content

Commit 744b230

Browse files
authored
Refactored files.ts (#1031)
* Refactored files.ts. * Removed superfluous comments.
1 parent a22d279 commit 744b230

1 file changed

Lines changed: 175 additions & 94 deletions

File tree

utils/files.ts

Lines changed: 175 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -119,35 +119,171 @@ export function streamToCSV (
119119
}
120120
}
121121

122-
const getUniquePrices = (tempTxGroup: TransactionsWithPaybuttonsAndPrices[], groupKey: string, currency: SupportedQuotesType): Set<number> => {
123-
const uniquePrices: Set<number> = new Set()
124-
const quoteId = QUOTE_IDS[currency.toUpperCase()]
125-
tempTxGroup
126-
.forEach(tx => {
122+
class TransactionGroupManager {
123+
private tempTxGroups: Record<string, TransactionsWithPaybuttonsAndPrices[]> = {}
124+
125+
constructor(
126+
private currency: SupportedQuotesType,
127+
private timezone: string
128+
) {}
129+
130+
addToGroup(groupKey: string, tx: TransactionsWithPaybuttonsAndPrices): void {
131+
if (this.tempTxGroups[groupKey] === undefined) {
132+
this.tempTxGroups[groupKey] = []
133+
}
134+
this.tempTxGroups[groupKey].push(tx)
135+
}
136+
137+
processAllGroups(treatedPayments: TransactionFileData[]): void {
138+
Object.keys(this.tempTxGroups).forEach(key => {
139+
this.processGroup(key, treatedPayments)
140+
})
141+
}
142+
143+
processGroup(groupKey: string, treatedPayments: TransactionFileData[]): void {
144+
const tempTxGroup = this.tempTxGroups[groupKey]
145+
if (tempTxGroup === undefined || tempTxGroup.length === 0) return
146+
147+
if (tempTxGroup.length === 1) {
148+
this.addSingleTransaction(tempTxGroup[0], groupKey, treatedPayments)
149+
} else {
150+
this.addCollapsedTransactionGroup(tempTxGroup, groupKey, treatedPayments)
151+
}
152+
153+
this.tempTxGroups[groupKey] = []
154+
}
155+
156+
private addSingleTransaction(
157+
tx: TransactionsWithPaybuttonsAndPrices,
158+
groupKey: string,
159+
treatedPayments: TransactionFileData[]
160+
): void {
161+
const { timestamp, hash, address, amount } = tx
162+
const values = getTransactionValue(tx)
163+
const value = Number(values[this.currency])
164+
const rate = tx.prices.find(p => p.price.quoteId === QUOTE_IDS[this.currency.toUpperCase()])!.price.value
165+
const buttonNames = this.extractButtonNamesFromGroupKey(groupKey)
166+
167+
treatedPayments.push({
168+
amount,
169+
value,
170+
date: moment.tz(timestamp * 1000, this.timezone),
171+
transactionId: hash,
172+
rate,
173+
currency: this.currency,
174+
address: address.address,
175+
notes: buttonNames,
176+
newtworkId: address.networkId
177+
} as TransactionFileData)
178+
}
179+
180+
private addCollapsedTransactionGroup(
181+
tempTxGroup: TransactionsWithPaybuttonsAndPrices[],
182+
groupKey: string,
183+
treatedPayments: TransactionFileData[]
184+
): void {
185+
const totalAmount = tempTxGroup.reduce((sum, p) => sum + Number(p.amount), 0)
186+
const totalValue = tempTxGroup.reduce((sum, p) => sum + Number(getTransactionValue(p)[this.currency]), 0)
187+
const uniquePrices = this.getUniquePrices(tempTxGroup, groupKey)
188+
const rate = new Prisma.Decimal(uniquePrices.values().next().value as number)
189+
const buttonNames = this.extractButtonNamesFromGroupKey(groupKey)
190+
const notes = `${buttonNames} - ${tempTxGroup.length.toString()} transactions`
191+
192+
treatedPayments.push({
193+
amount: totalAmount,
194+
value: totalValue,
195+
date: moment.tz(tempTxGroup[0].timestamp * 1000, this.timezone),
196+
transactionId: DEFAULT_MULTI_VALUES_LINE_LABEL,
197+
rate,
198+
currency: this.currency,
199+
address: DEFAULT_MULTI_VALUES_LINE_LABEL,
200+
newtworkId: tempTxGroup[0].address.networkId,
201+
notes
202+
} as TransactionFileData)
203+
}
204+
205+
private extractButtonNamesFromGroupKey(groupKey: string): string {
206+
return groupKey.split('_').slice(2).join(';')
207+
}
208+
209+
private getUniquePrices(tempTxGroup: TransactionsWithPaybuttonsAndPrices[], groupKey: string): Set<number> {
210+
const uniquePrices: Set<number> = new Set()
211+
const quoteId = QUOTE_IDS[this.currency.toUpperCase()]
212+
213+
tempTxGroup.forEach(tx => {
127214
const price = tx.prices.find(p => p.price.quoteId === quoteId)!.price.value
128215
uniquePrices.add(Number(price))
129216
})
130-
if (uniquePrices.size !== 1) {
217+
218+
if (uniquePrices.size !== 1) {
219+
this.handlePriceValidationError(tempTxGroup, groupKey, uniquePrices, quoteId)
220+
}
221+
222+
return uniquePrices
223+
}
224+
225+
private handlePriceValidationError(
226+
tempTxGroup: TransactionsWithPaybuttonsAndPrices[],
227+
groupKey: string,
228+
uniquePrices: Set<number>,
229+
quoteId: number
230+
): void {
131231
if (uniquePrices.size > 1) {
132232
const nonUniquePrices = [...uniquePrices]
133233
const txsForPrice: Record<number, string[]> = {}
134234
nonUniquePrices.forEach(nonUniquePrice => {
135-
txsForPrice[nonUniquePrice] = tempTxGroup.filter(tx => nonUniquePrice === tx.prices.find(p => p.price.quoteId === quoteId)!.price.value.toNumber()).map(tx => tx.id)
235+
txsForPrice[nonUniquePrice] = tempTxGroup
236+
.filter(tx => nonUniquePrice === tx.prices.find(p => p.price.quoteId === quoteId)!.price.value.toNumber())
237+
.map(tx => tx.id)
136238
})
137239
console.error('ERROR WHEN TRYING TO COLLAPSE TXS INTO DIFFERENT PRICES:', { txsForPrice, nonUniquePrices })
138240
} else {
139241
console.error('ERROR WHEN TRYING TO COLLAPSE TXS INTO DIFFERENT PRICES, NO PRICES FOR GROUP KEY', { groupKey })
140242
}
141243

142244
throw new Error(
143-
RESPONSE_MESSAGES
144-
.INVALID_PRICES_AMOUNT_FOR_TX_ON_CSV_CREATION_500(tempTxGroup.length).message
245+
RESPONSE_MESSAGES.INVALID_PRICES_AMOUNT_FOR_TX_ON_CSV_CREATION_500(tempTxGroup.length).message
145246
)
146247
}
147-
return uniquePrices
148248
}
149249

150-
const collapsePaymentsPushTx = (
250+
const generateGroupKey = (
251+
tx: TransactionsWithPaybuttonsAndPrices,
252+
timezone: string,
253+
userId: string,
254+
paybuttonId?: string
255+
): string => {
256+
const { timestamp } = tx
257+
const dateKey = moment.tz(timestamp * 1000, timezone).format('YYYY-MM-DD')
258+
const dateKeyUTC = moment.utc(timestamp * 1000).format('YYYY-MM-DD')
259+
const buttonNamesKey = extractPaybuttonNames(tx, userId, paybuttonId)
260+
261+
return `${dateKey}_${dateKeyUTC}_${buttonNamesKey}`
262+
}
263+
264+
const extractPaybuttonNames = (
265+
tx: TransactionsWithPaybuttonsAndPrices,
266+
userId: string,
267+
paybuttonId?: string
268+
): string => {
269+
const uniqueButtonNames = new Set(
270+
tx.address.paybuttons
271+
.filter(pb => pb.paybutton.providerUserId === userId)
272+
.map(pb => pb.paybutton.name)
273+
)
274+
275+
if (uniqueButtonNames.size > 1) {
276+
if (paybuttonId !== undefined) {
277+
return tx.address.paybuttons.find(pb => pb.paybutton.id === paybuttonId)?.paybutton.name ?? ''
278+
} else {
279+
return [...uniqueButtonNames].join('_')
280+
}
281+
} else {
282+
return uniqueButtonNames.values().next().value ?? ''
283+
}
284+
}
285+
286+
const addSingleTransactionToResults = (
151287
tx: TransactionsWithPaybuttonsAndPrices,
152288
groupKey: string,
153289
currency: SupportedQuotesType,
@@ -173,61 +309,6 @@ const collapsePaymentsPushTx = (
173309
} as TransactionFileData)
174310
}
175311

176-
const collapsePaymentsPushTempGroup = (
177-
groupKey: string,
178-
tempTxGroups: Record<string, TransactionsWithPaybuttonsAndPrices[]>,
179-
currency: SupportedQuotesType,
180-
treatedPayments: TransactionFileData[],
181-
timezone: string
182-
): void => {
183-
const tempTxGroup = tempTxGroups[groupKey]
184-
if (tempTxGroup === undefined || tempTxGroup.length === 0) return
185-
if (tempTxGroup.length === 1) {
186-
collapsePaymentsPushTx(tempTxGroup[0], groupKey, currency, treatedPayments, timezone)
187-
tempTxGroups[groupKey] = []
188-
return
189-
}
190-
const totalAmount = tempTxGroup.reduce((sum, p) => sum + Number(p.amount), 0)
191-
const totalValue = tempTxGroup.reduce((sum, p) => sum + Number(getTransactionValue(p)[currency]), 0)
192-
const uniquePrices = getUniquePrices(tempTxGroup, groupKey, currency)
193-
const rate = new Prisma.Decimal(uniquePrices.values().next().value as number)
194-
const buttonNames = groupKey.split('_').slice(2).join(';')
195-
const notes = `${buttonNames} - ${tempTxGroup.length.toString()} transactions`
196-
197-
treatedPayments.push({
198-
amount: totalAmount,
199-
value: totalValue,
200-
date: moment.tz(tempTxGroup[0].timestamp * 1000, timezone),
201-
transactionId: DEFAULT_MULTI_VALUES_LINE_LABEL,
202-
rate,
203-
currency,
204-
address: DEFAULT_MULTI_VALUES_LINE_LABEL,
205-
newtworkId: tempTxGroup[0].address.networkId,
206-
notes
207-
} as TransactionFileData)
208-
209-
tempTxGroups[groupKey] = []
210-
}
211-
212-
const getButtonNames = (tx: TransactionsWithPaybuttonsAndPrices, userId: string, paybuttonId?: string): string => {
213-
let buttonNamesKey: string = ''
214-
const uniqueButtonNames = new Set(
215-
tx.address.paybuttons
216-
.filter(pb => pb.paybutton.providerUserId === userId)
217-
.map(pb => pb.paybutton.name)
218-
)
219-
if (uniqueButtonNames.size > 1) {
220-
if (paybuttonId !== undefined) {
221-
buttonNamesKey = tx.address.paybuttons.find(pb => pb.paybutton.id === paybuttonId)?.paybutton.name ?? ''
222-
} else {
223-
buttonNamesKey = [...uniqueButtonNames].join('_')
224-
}
225-
} else {
226-
buttonNamesKey = uniqueButtonNames.values().next().value ?? ''
227-
}
228-
return buttonNamesKey
229-
}
230-
231312
export const collapseSmallPayments = (
232313
payments: TransactionsWithPaybuttonsAndPrices[],
233314
currency: SupportedQuotesType,
@@ -237,52 +318,52 @@ export const collapseSmallPayments = (
237318
paybuttonId?: string
238319
): TransactionFileData[] => {
239320
const treatedPayments: TransactionFileData[] = []
240-
const tempTxGroups: Record<string, TransactionsWithPaybuttonsAndPrices[]> = {}
321+
const groupManager = new TransactionGroupManager(currency, timezone)
241322

242323
payments.forEach((tx: TransactionsWithPaybuttonsAndPrices, index: number) => {
243324
const { timestamp } = tx
244325
const values = getTransactionValue(tx)
245326
const value = Number(values[currency])
246-
const dateKey = moment.tz(timestamp * 1000, timezone).format('YYYY-MM-DD')
247-
const dateKeyUTC = moment.utc(timestamp * 1000).format('YYYY-MM-DD')
248-
const buttonNamesKey = getButtonNames(tx, userId, paybuttonId)
249-
250-
const groupKey = `${dateKey}_${dateKeyUTC}_${buttonNamesKey}`
251-
252-
let nextGroupKey: string | null = ''
253-
const nextPayment = payments[index + 1]
254-
if (nextPayment !== undefined) {
255-
const nextDateKey = moment.tz(nextPayment.timestamp * 1000, timezone).format('YYYY-MM-DD')
256-
const nextDateKeyUTC = moment.utc(nextPayment.timestamp * 1000).format('YYYY-MM-DD')
257-
const nextButtonName = getButtonNames(nextPayment, userId, paybuttonId)
327+
const groupKey = generateGroupKey(tx, timezone, userId, paybuttonId)
258328

259-
nextGroupKey = `${nextDateKey}_${nextDateKeyUTC}_${nextButtonName}`
260-
} else {
261-
nextGroupKey = null
262-
}
329+
const shouldProcessGroups = shouldProcessGroupsAtCurrentIndex(
330+
payments, index, timezone, userId, paybuttonId, groupKey
331+
)
263332

264333
if (value < collapseThreshold) {
265-
if (tempTxGroups[groupKey] === undefined) tempTxGroups[groupKey] = []
266-
tempTxGroups[groupKey].push(tx)
334+
groupManager.addToGroup(groupKey, tx)
267335
} else {
268-
Object.keys(tempTxGroups).forEach(key => {
269-
collapsePaymentsPushTempGroup(key, tempTxGroups, currency, treatedPayments, timezone)
270-
})
271-
collapsePaymentsPushTx(tx, groupKey, currency, treatedPayments, timezone)
336+
groupManager.processAllGroups(treatedPayments)
337+
addSingleTransactionToResults(tx, groupKey, currency, treatedPayments, timezone)
272338
}
273339

274-
if (nextGroupKey !== groupKey) {
275-
collapsePaymentsPushTempGroup(groupKey, tempTxGroups, currency, treatedPayments, timezone)
340+
if (shouldProcessGroups) {
341+
groupManager.processGroup(groupKey, treatedPayments)
276342
}
277343
})
278344

279-
Object.keys(tempTxGroups).forEach(key => {
280-
collapsePaymentsPushTempGroup(key, tempTxGroups, currency, treatedPayments, timezone)
281-
})
345+
groupManager.processAllGroups(treatedPayments)
282346

283347
return treatedPayments
284348
}
285349

350+
const shouldProcessGroupsAtCurrentIndex = (
351+
payments: TransactionsWithPaybuttonsAndPrices[],
352+
currentIndex: number,
353+
timezone: string,
354+
userId: string,
355+
paybuttonId: string | undefined,
356+
currentGroupKey: string
357+
): boolean => {
358+
const nextPayment = payments[currentIndex + 1]
359+
if (nextPayment === undefined) {
360+
return false // No next payment, will be handled at the end
361+
}
362+
363+
const nextGroupKey = generateGroupKey(nextPayment, timezone, userId, paybuttonId)
364+
return nextGroupKey !== currentGroupKey
365+
}
366+
286367
const sortPaymentsByNetworkId = (payments: TransactionsWithPaybuttonsAndPrices[]): TransactionsWithPaybuttonsAndPrices[] => {
287368
const groupedByNetworkIdPayments = payments.reduce<Record<number, TransactionsWithPaybuttonsAndPrices[]>>((acc, transaction) => {
288369
const networkId = transaction.address.networkId

0 commit comments

Comments
 (0)