Back to js-datatype-intermediate
10-upi-transaction-log.js
JavaScript
1/**
2 * 💸 UPI Transaction Log Analyzer
3 *
4 * Aaj kal sab UPI pe chalta hai! Tujhe ek month ke transactions ka log
5 * milega, aur tujhe pura analysis karna hai - kitna aaya, kitna gaya,
6 * kiski saath zyada transactions hue, etc.
7 *
8 * Rules:
9 * - transactions is array of objects:
10 * [{ id: "TXN001", type: "credit"/"debit", amount: 500,
11 * to: "Rahul", category: "food", date: "2025-01-15" }, ...]
12 * - Skip transactions where amount is not a positive number
13 * - Skip transactions where type is not "credit" or "debit"
14 * - Calculate (on valid transactions only):
15 * - totalCredit: sum of all "credit" type amounts
16 * - totalDebit: sum of all "debit" type amounts
17 * - netBalance: totalCredit - totalDebit
18 * - transactionCount: total number of valid transactions
19 * - avgTransaction: Math.round(sum of all valid amounts / transactionCount)
20 * - highestTransaction: the full transaction object with highest amount
21 * - categoryBreakdown: object with category as key and total amount as value
22 * e.g., { food: 1500, travel: 800 } (include both credit and debit)
23 * - frequentContact: the "to" field value that appears most often
24 * (if tie, return whichever appears first)
25 * - allAbove100: boolean, true if every valid transaction amount > 100 (use every)
26 * - hasLargeTransaction: boolean, true if some valid amount >= 5000 (use some)
27 * - Hint: Use filter(), reduce(), sort(), find(), every(), some(),
28 * Object.entries(), Math.round(), typeof
29 *
30 * Validation:
31 * - Agar transactions array nahi hai ya empty hai, return null
32 * - Agar after filtering invalid transactions, koi valid nahi bacha, return null
33 *
34 * @param {Array<{ id: string, type: string, amount: number, to: string, category: string, date: string }>} transactions
35 * @returns {{ totalCredit: number, totalDebit: number, netBalance: number, transactionCount: number, avgTransaction: number, highestTransaction: object, categoryBreakdown: object, frequentContact: string, allAbove100: boolean, hasLargeTransaction: boolean } | null}
36 *
37 * @example
38 * analyzeUPITransactions([
39 * { id: "T1", type: "credit", amount: 5000, to: "Salary", category: "income", date: "2025-01-01" },
40 * { id: "T2", type: "debit", amount: 200, to: "Swiggy", category: "food", date: "2025-01-02" },
41 * { id: "T3", type: "debit", amount: 100, to: "Swiggy", category: "food", date: "2025-01-03" }
42 * ])
43 * // => { totalCredit: 5000, totalDebit: 300, netBalance: 4700,
44 * // transactionCount: 3, avgTransaction: 1767,
45 * // highestTransaction: { id: "T1", ... },
46 * // categoryBreakdown: { income: 5000, food: 300 },
47 * // frequentContact: "Swiggy", allAbove100: false, hasLargeTransaction: true }
48 */
49export function analyzeUPITransactions(transactions) {
50
51 if (!Array.isArray(transactions) || transactions.length === 0) {
52 return null;
53 }
54
55
56 const validTransaction = transactions.filter(trx => {
57 const validAmount =
58 typeof trx.amount === "number" &&
59 Number.isFinite(trx.amount) &&
60 trx.amount > 0;
61
62 const validType =
63 trx.type === "credit" || trx.type === "debit";
64
65 return validAmount && validType;
66 });
67
68 if (validTransaction.length === 0) {
69 return null;
70 }
71
72
73 const totals = validTransaction.reduce(
74 (acc, trx) => {
75 if (trx.type === "credit") {
76 acc.totalCredit += trx.amount;
77 } else {
78 acc.totalDebit += trx.amount;
79 }
80 return acc;
81 },
82 { totalCredit: 0, totalDebit: 0 }
83 );
84
85 const totalCredit = totals.totalCredit;
86 const totalDebit = totals.totalDebit;
87
88
89 const netBalance = totalCredit - totalDebit;
90
91 const transactionCount = validTransaction.length;
92
93 const avgTransaction = Math.round(
94 (totalCredit + totalDebit) / transactionCount
95 );
96
97 const highestTransaction = validTransaction.reduce((max, trx) =>
98 trx.amount > max.amount ? trx : max
99 );
100
101
102 const categoryBreakdown = validTransaction.reduce((acc, trx) => {
103 acc[trx.category] = (acc[trx.category] || 0) + trx.amount;
104 return acc;
105 }, {});
106
107 const frequency = {};
108 let frequentContact = "";
109 let maxCount = 0;
110
111 for (const trx of validTransaction) {
112 frequency[trx.to] = (frequency[trx.to] || 0) + 1;
113
114 if (frequency[trx.to] > maxCount) {
115 maxCount = frequency[trx.to];
116 frequentContact = trx.to;
117 }
118 }
119
120
121 const allAbove100 = validTransaction.every(
122 trx => trx.amount > 100
123 );
124
125
126 const hasLargeTransaction = validTransaction.some(
127 trx => trx.amount >= 5000
128 );
129
130 return {
131 totalCredit,totalDebit,netBalance,transactionCount,avgTransaction,highestTransaction,categoryBreakdown,frequentContact,allAbove100,hasLargeTransaction
132 };
133}
134