-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathemail.services.ts
More file actions
102 lines (85 loc) · 2.9 KB
/
Copy pathemail.services.ts
File metadata and controls
102 lines (85 loc) · 2.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
import { load } from "cheerio";
import { Decimal } from "decimal.js";
import { prisma } from "../../utils/prisma";
import { calculateOrderTotal } from "../order/order.services";
export const parseUnverifiedVenmoEmail = (raw: string) => {
let parsedAmount: Decimal | null = null;
const $ = load(raw);
const amount = $('span[style="color:#148572;float:right;"]').text().trim();
const amountStr = amount.replace("$", "").replace("+", "");
parsedAmount = new Decimal(amountStr);
if (parsedAmount.isNaN()) {
console.log("Parsed amount is NaN");
parsedAmount = null;
throw new Error("Failed to parse payment amount");
}
const transactionNote = $('table[role="presentation"] tbody tr div p')
.text()
.trim();
if (!transactionNote) {
throw new Error("Failed to parse venmo message for retreiving orderId");
}
return { parsedAmount, transactionNote };
};
export const parseVerifiedVenmoEmail = (raw: string) => {
// Load HTML into Cheerio
const $ = load(raw);
// Extract data
const dollarAmount =
$("div.amount-container__amount-text").text().trim() || "0"; // "5"
const centAmount =
$("div.amount-container__text-high").eq(1).text().trim() || "00"; // "01"
const transactionNote = $("p.transaction-note").text().trim(); // "4a1s"
if (!transactionNote) {
throw new Error("Failed to parse venmo message for retreiving orderId");
}
// Convert to integers
const dollarAmountInt = parseInt(dollarAmount, 10);
const centAmountInt = parseInt(centAmount, 10);
// Convert to Decimal.js value
const parsedAmount = new Decimal(dollarAmountInt).plus(
new Decimal(centAmountInt).dividedBy(100),
);
// Validate parsed amount
if (isNaN(parsedAmount.toNumber())) {
throw new Error("Failed to parse payment amount");
}
return { parsedAmount, transactionNote };
};
export const updateOrderPaymentStatus = async (
orderId: string,
paidAmount: Decimal,
) => {
try {
// Calculate expected order total
const expectedAmount = await calculateOrderTotal(orderId);
// Validate that paid amount matches expected amount using Decimal comparison
const tolerance = new Decimal(0.01);
const difference = paidAmount.minus(expectedAmount).abs();
if (difference.greaterThan(tolerance)) {
// TODO: Handle amount mismatch (e.g., log, alert, etc.)
throw new Error(
`Payment amount mismatch: expected $${expectedAmount.toFixed(
2,
)}, received $${paidAmount.toFixed(2)}`,
);
}
// Update order with Venmo payment confirmation
const order = await prisma.order.update({
where: {
id: orderId,
},
data: {
paymentMethod: "VENMO",
paymentStatus: "CONFIRMED",
},
});
return order;
} catch (error) {
throw new Error(
`Failed to update order payment status: ${
error instanceof Error ? error.message : "Unknown error"
}`,
);
}
};