144 lines
4.2 KiB
JavaScript
144 lines
4.2 KiB
JavaScript
function toNumberRu(s) {
|
||
if (!s) return null;
|
||
const cleaned = String(s)
|
||
.replace(/\s/g, "")
|
||
.replace(",", ".")
|
||
.replace(/[^\d.]/g, "");
|
||
const n = Number(cleaned);
|
||
console.log("toNumberRu: " + Number.isFinite(n));
|
||
return Number.isFinite(n) ? n : null;
|
||
}
|
||
|
||
function paringSms(sms) {
|
||
console.log(sms);
|
||
|
||
const raw = sms.body.message ?? "";
|
||
|
||
console.log("raw: " + raw);
|
||
|
||
const text = String(raw).replace(/\s+/g, " ").trim();
|
||
const lower = text.toLowerCase();
|
||
|
||
console.log("text: " + text);
|
||
|
||
const sender = sms.body?.sender ?? null;
|
||
|
||
console.log("sender: " + sender);
|
||
|
||
// 1) Классификация
|
||
let action = "unknown";
|
||
|
||
const rules = [
|
||
{ action: "salary", re: /зарплат/i },
|
||
{ action: "reversal", re: /(отмена|возврат)/i },
|
||
{ action: "payment", re: /(оплата|покупк)/i },
|
||
{ action: "transfer", re: /перевод/i },
|
||
{ action: "writeoff", re: /списан/i },
|
||
{ action: "income", re: /(поступлен|поступление|зачислен)/i },
|
||
];
|
||
|
||
for (const r of rules) {
|
||
if (r.re.test(lower)) {
|
||
action = r.action;
|
||
break;
|
||
}
|
||
}
|
||
|
||
console.log("action: " + action);
|
||
|
||
// 2) Баланс
|
||
const balanceRegex =
|
||
/(баланс)[:\s]*([0-9][0-9\s]*[.,]?\d{0,2})\s*(₽|руб\.?|rub|р)(?=\s|$)/i;
|
||
const balanceMatch = text.match(balanceRegex);
|
||
console.log("balanceMatch: " + balanceMatch);
|
||
|
||
const balance = balanceMatch ? toNumberRu(balanceMatch[2]) : null;
|
||
|
||
console.log("balance: " + balance);
|
||
|
||
// 3) Сумма операции
|
||
let amount = null;
|
||
const amountNearActionRegex =
|
||
/(отмена[:\s-]*оплата|отмена|списание|оплата|перевод|поступление|зарплат[аы]?)[\s:]*([0-9][0-9\s]*[.,]?\d{0,2})\s*(₽|руб\.?|rub|р)/i;
|
||
|
||
const near = text.match(amountNearActionRegex);
|
||
|
||
console.log("near: " + near);
|
||
|
||
if (near) {
|
||
amount = toNumberRu(near[2]);
|
||
console.log(amount);
|
||
} else {
|
||
const textWithoutBalance = text.replace(balanceRegex, " ");
|
||
|
||
console.log("textWithoutBalance: " + textWithoutBalance);
|
||
|
||
const amountRegex = /([0-9][0-9\s]*[.,]?\d{0,2})\s*(₽|руб\.?|rub|р)/i;
|
||
const m = textWithoutBalance.match(amountRegex);
|
||
amount = m ? toNumberRu(m[1]) : null;
|
||
console.log("m: " + m);
|
||
}
|
||
|
||
const currency = "RUB";
|
||
|
||
// 4) signedAmount
|
||
let signedAmount = amount;
|
||
if (amount != null) {
|
||
if (["payment", "transfer", "writeoff"].includes(action))
|
||
signedAmount = -Math.abs(amount);
|
||
if (["income", "salary", "reversal"].includes(action))
|
||
signedAmount = Math.abs(amount);
|
||
}
|
||
|
||
console.log({
|
||
raw_sms: raw,
|
||
sms_text: text,
|
||
sms_sender: sender,
|
||
action, // income/payment/transfer/salary/reversal/writeoff
|
||
amount,
|
||
signed_amount: signedAmount,
|
||
currency,
|
||
balance,
|
||
received_at: new Date().toISOString(),
|
||
});
|
||
|
||
return [
|
||
{
|
||
raw_sms: raw,
|
||
sms_text: text,
|
||
sms_sender: sender,
|
||
action, // income/payment/transfer/salary/reversal/writeoff
|
||
amount,
|
||
signed_amount: signedAmount,
|
||
currency,
|
||
balance,
|
||
received_at: new Date().toISOString(),
|
||
},
|
||
];
|
||
}
|
||
|
||
const input_sms = {
|
||
body: {
|
||
message:
|
||
'Оплата 980р Карта*4215 "SKURATOV COFFE Баланс 207033.86р 19:52',
|
||
sender: "VTB",
|
||
formatted_message:
|
||
'📩 *New SMS Received*\n👤 *From:* VTB\n\nОплата 980р Карта*4215 "SKURATOV COFFE Баланс 207033.86р 19:52',
|
||
contact: "",
|
||
},
|
||
};
|
||
|
||
const input_sms2 = {
|
||
body: {
|
||
formatted_message:
|
||
"📩 *New SMS Received*\n👤 *From:* VTB\n\nОплата 6800р Карта*4215 IP SHARAFETDINO Баланс 199083.86р 09:56",
|
||
contact: "",
|
||
sender: "VTB",
|
||
message:
|
||
"Оплата 6800р Карта*4215 IP SHARAFETDINO Баланс 199083.86р 09:56",
|
||
},
|
||
};
|
||
|
||
paringSms(input_sms);
|
||
// paringSms(input_sms2);
|