sequelize-game-bank 5.0.2 → 5.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.cache_ggshield +1 -0
- package/config/setup-env.js +43 -24
- package/database/models/Credit.js +35 -22
- package/database/services/account/create-credit.js +70 -27
- package/database/services/bot/cron-schedule.js +155 -41
- package/package.json +1 -1
- package/public/credit.html +139 -81
- package/public/home.html +427 -344
- package/public/js/js.js +191 -88
- package/public/uploads/avatars/Pavel_1793516096895.png +0 -0
- package/public/uploads/avatars/root_1793520405521.png +0 -0
- package/server/server.js +304 -88
package/public/js/js.js
CHANGED
|
@@ -180,6 +180,36 @@ async function loadData() {
|
|
|
180
180
|
if (document.getElementById("table-logs")) {
|
|
181
181
|
await loadTransactionLogs();
|
|
182
182
|
}
|
|
183
|
+
|
|
184
|
+
const creditContainer = document.getElementById("active-credit-actions");
|
|
185
|
+
if (creditContainer) {
|
|
186
|
+
creditContainer.innerHTML = "";
|
|
187
|
+
let creditRes = await fetch("/api/bank/accounts/my-current-credit", {
|
|
188
|
+
headers: { "Bypass-Tunnel-Reminder": "true" },
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
if (creditRes.ok) {
|
|
192
|
+
let creditData = await creditRes.json();
|
|
193
|
+
|
|
194
|
+
if (creditData && creditData.activeCredit) {
|
|
195
|
+
const cr = creditData.activeCredit;
|
|
196
|
+
const regularPayment = cr.totalRepay / cr.termMonths;
|
|
197
|
+
|
|
198
|
+
creditContainer.innerHTML = `
|
|
199
|
+
<div class="credit-info-block" style="margin-top: 15px;">
|
|
200
|
+
<p>Остаток по кредиту: <b>${parseFloat(cr.remainingRepay).toFixed(2)}</b> руб.</p>
|
|
201
|
+
<button class="btn btn-success" onclick="payCreditManually(${parseInt(cr.id, 10)}, ${parseFloat(regularPayment)})">
|
|
202
|
+
Внести регулярный платеж (${regularPayment.toFixed(2)} руб.)
|
|
203
|
+
</button>
|
|
204
|
+
</div>
|
|
205
|
+
`;
|
|
206
|
+
} else {
|
|
207
|
+
creditContainer.innerHTML = `<p style="color: gray; margin-top: 15px;">У вас нет активных кредитов.</p>`;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
await syncProfileSectionData();
|
|
183
213
|
} catch (e) {
|
|
184
214
|
console.error("Критическая ошибка выполнения скрипта страницы:", e);
|
|
185
215
|
window.Swal.fire({
|
|
@@ -301,58 +331,6 @@ async function executeTransfer() {
|
|
|
301
331
|
console.error("Ошибка [" + data.statusCode + "]: " + data.message);
|
|
302
332
|
}
|
|
303
333
|
}
|
|
304
|
-
async function applyForCredit() {
|
|
305
|
-
const targetAccountId = document.getElementById("credit-target").value;
|
|
306
|
-
const amount = document.getElementById("credit-amount").value;
|
|
307
|
-
const paymentsCount = document.getElementById("credit-payments").value;
|
|
308
|
-
const autoWithdrawal = document.getElementById("credit-auto").checked;
|
|
309
|
-
const pinCode = document.getElementById("credit-pin").value;
|
|
310
|
-
const res = await fetch("/api/bank/accounts/credit", {
|
|
311
|
-
method: "POST",
|
|
312
|
-
headers: {
|
|
313
|
-
"Content-Type": "application/json",
|
|
314
|
-
"Bypass-Tunnel-Reminder": "true",
|
|
315
|
-
},
|
|
316
|
-
body: JSON.stringify({
|
|
317
|
-
accountId: targetAccountId,
|
|
318
|
-
amount: parseFloat(amount),
|
|
319
|
-
termMonths: parseInt(paymentsCount, 10),
|
|
320
|
-
autoRepay: autoWithdrawal,
|
|
321
|
-
pinCode: pinCode,
|
|
322
|
-
rate: 0.1,
|
|
323
|
-
}),
|
|
324
|
-
});
|
|
325
|
-
const data = await res.json();
|
|
326
|
-
if (data.success || data.status) {
|
|
327
|
-
await Swal.fire({
|
|
328
|
-
title: "Кредит",
|
|
329
|
-
text:
|
|
330
|
-
"Кредит одобрен! Деньги зачислены на счет #" +
|
|
331
|
-
(data.creditId || data.creditAccountId),
|
|
332
|
-
icon: "success",
|
|
333
|
-
confirmButtonColor: "#3085d6",
|
|
334
|
-
confirmButtonText: "Ок",
|
|
335
|
-
});
|
|
336
|
-
|
|
337
|
-
Toastify({
|
|
338
|
-
text: `Вы взяли кредит`,
|
|
339
|
-
duration: 3000,
|
|
340
|
-
style: { background: "rgb(58, 245, 11)" },
|
|
341
|
-
}).showToast();
|
|
342
|
-
|
|
343
|
-
if (typeof loadData === "function") loadData();
|
|
344
|
-
} else {
|
|
345
|
-
await Swal.fire({
|
|
346
|
-
title: "Кредит",
|
|
347
|
-
text: data.error || data.message || "Ошибка оформления кредита",
|
|
348
|
-
icon: "warning",
|
|
349
|
-
iconColor: "orange",
|
|
350
|
-
confirmButtonColor: "#3085d6",
|
|
351
|
-
confirmButtonText: "Ок",
|
|
352
|
-
});
|
|
353
|
-
console.error("Ошибка: " + (data.error || data.message));
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
334
|
document.getElementById("logoutBtn").addEventListener("click", async () => {
|
|
357
335
|
const logOut = await Swal.fire({
|
|
358
336
|
title: "Выход",
|
|
@@ -411,16 +389,22 @@ async function syncProfileSectionData() {
|
|
|
411
389
|
const statusText = document.getElementById("2fa-current-status");
|
|
412
390
|
const toggleBtn = document.getElementById("btn-toggle-2fa");
|
|
413
391
|
|
|
414
|
-
if (
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
392
|
+
if (statusText && toggleBtn) {
|
|
393
|
+
if (user2FaActive) {
|
|
394
|
+
statusText.innerHTML =
|
|
395
|
+
'Текущий статус: <span style="color:green; font-weight:bold;">ЗАЩИЩЕН (2FA включена)</span>';
|
|
396
|
+
toggleBtn.innerText = "Отключить защиту 2FA";
|
|
397
|
+
toggleBtn.className = "btn btn-danger";
|
|
398
|
+
} else {
|
|
399
|
+
statusText.innerHTML =
|
|
400
|
+
'Текущий статус: <span style="color:red; font-weight:bold;">НЕБЕЗОПАСНО (2FA выключена)</span>';
|
|
401
|
+
toggleBtn.innerText = "Включить защиту 2FA";
|
|
402
|
+
toggleBtn.className = "btn";
|
|
403
|
+
}
|
|
419
404
|
} else {
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
toggleBtn.className = "btn";
|
|
405
|
+
console.log(
|
|
406
|
+
"ℹ️ Элементы управления 2FA не найдены на текущей вкладке (это нормально).",
|
|
407
|
+
);
|
|
424
408
|
}
|
|
425
409
|
}
|
|
426
410
|
} catch (e) {
|
|
@@ -795,32 +779,56 @@ async function loadTransactionLogs() {
|
|
|
795
779
|
}
|
|
796
780
|
async function executeCreateCredit() {
|
|
797
781
|
try {
|
|
798
|
-
const accountIdField =
|
|
782
|
+
const accountIdField =
|
|
783
|
+
document.getElementById("credit-target") ||
|
|
784
|
+
document.getElementById("credit-accountId");
|
|
799
785
|
const amountField = document.getElementById("credit-amount");
|
|
800
|
-
const
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
786
|
+
const termMonthsField =
|
|
787
|
+
document.getElementById("credit-payments") ||
|
|
788
|
+
document.getElementById("credit-termMonths");
|
|
789
|
+
const autoRepayField =
|
|
790
|
+
document.getElementById("credit-credit-auto") ||
|
|
791
|
+
document.getElementById("credit-auto") ||
|
|
792
|
+
document.getElementById("credit-autoRepay");
|
|
793
|
+
const pinCodeField = document.getElementById("credit-pin");
|
|
794
|
+
|
|
795
|
+
if (!accountIdField || !amountField || !pinCodeField) {
|
|
804
796
|
console.error(
|
|
805
|
-
"Критические элементы формы кредита не найдены в HTML
|
|
797
|
+
"Критические элементы формы кредита (Счет, Сумма или Пин-код) не найдены в HTML.",
|
|
798
|
+
);
|
|
799
|
+
Swal.fire(
|
|
800
|
+
"Ошибка",
|
|
801
|
+
"Ошибка структуры формы. Обратитесь к администратору.",
|
|
802
|
+
"error",
|
|
806
803
|
);
|
|
807
804
|
return;
|
|
808
805
|
}
|
|
809
|
-
|
|
806
|
+
|
|
807
|
+
const targetAccountId = accountIdField.value;
|
|
810
808
|
const amount = parseFloat(amountField.value);
|
|
809
|
+
const pinCode = pinCodeField.value.trim();
|
|
811
810
|
const autoRepay = autoRepayField ? autoRepayField.checked : false;
|
|
812
|
-
const rate = rateField ? parseFloat(rateField.value) : 0.1;
|
|
813
811
|
const termMonths = termMonthsField
|
|
814
812
|
? parseInt(termMonthsField.value, 10)
|
|
815
813
|
: 12;
|
|
816
|
-
|
|
814
|
+
|
|
815
|
+
if (!targetAccountId || isNaN(amount) || amount <= 0) {
|
|
816
|
+
Swal.fire(
|
|
817
|
+
"Внимание",
|
|
818
|
+
"Пожалуйста, выберите счет и укажите корректную сумму кредитования.",
|
|
819
|
+
"warning",
|
|
820
|
+
);
|
|
821
|
+
return;
|
|
822
|
+
}
|
|
823
|
+
if (!pinCode) {
|
|
817
824
|
Swal.fire(
|
|
818
825
|
"Внимание",
|
|
819
|
-
"Пожалуйста,
|
|
826
|
+
"Пожалуйста, введите PIN-код выбранного счета для подтверждения.",
|
|
820
827
|
"warning",
|
|
821
828
|
);
|
|
822
829
|
return;
|
|
823
830
|
}
|
|
831
|
+
|
|
824
832
|
const response = await fetch("/api/bank/accounts/credit", {
|
|
825
833
|
method: "POST",
|
|
826
834
|
headers: {
|
|
@@ -828,37 +836,132 @@ async function executeCreateCredit() {
|
|
|
828
836
|
"Bypass-Tunnel-Reminder": "true",
|
|
829
837
|
},
|
|
830
838
|
body: JSON.stringify({
|
|
831
|
-
|
|
832
|
-
amount,
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
839
|
+
targetAccountId: targetAccountId,
|
|
840
|
+
amount: amount,
|
|
841
|
+
paymentsCount: termMonths,
|
|
842
|
+
autoWithdrawal: autoRepay,
|
|
843
|
+
pinCode: pinCode,
|
|
836
844
|
}),
|
|
837
845
|
});
|
|
846
|
+
|
|
838
847
|
if (!response.ok) {
|
|
839
848
|
throw new Error(`Ошибка сервера: ${response.status}`);
|
|
840
849
|
}
|
|
850
|
+
|
|
841
851
|
const result = await response.json();
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
852
|
+
|
|
853
|
+
if (result.success || result.status) {
|
|
854
|
+
await Swal.fire({
|
|
855
|
+
title: "Успех!",
|
|
856
|
+
text:
|
|
857
|
+
result.message ||
|
|
858
|
+
`Кредит одобрен! Деньги зачислены на счет #${targetAccountId}`,
|
|
859
|
+
icon: "success",
|
|
860
|
+
confirmButtonColor: "#3085d6",
|
|
861
|
+
confirmButtonText: "Ок",
|
|
849
862
|
});
|
|
863
|
+
|
|
864
|
+
Toastify({
|
|
865
|
+
text: `Вы успешно взяли кредит`,
|
|
866
|
+
duration: 3000,
|
|
867
|
+
style: { background: "rgb(58, 245, 11)" },
|
|
868
|
+
}).showToast();
|
|
869
|
+
|
|
870
|
+
window.location.href = "/bank/accounts.html";
|
|
850
871
|
} else {
|
|
851
|
-
Swal.fire(
|
|
852
|
-
"Ошибка оформления",
|
|
853
|
-
result.error || "Не удалось выдать кредит",
|
|
854
|
-
"
|
|
872
|
+
Swal.fire({
|
|
873
|
+
title: "Ошибка оформления",
|
|
874
|
+
text: result.error || result.message || "Не удалось выдать кредит",
|
|
875
|
+
icon: "warning",
|
|
876
|
+
iconColor: "orange",
|
|
877
|
+
confirmButtonColor: "#3085d6",
|
|
878
|
+
confirmButtonText: "Ок",
|
|
879
|
+
});
|
|
880
|
+
console.error(
|
|
881
|
+
"Ошибка оформления кредита: " + (result.error || result.message),
|
|
855
882
|
);
|
|
856
883
|
}
|
|
857
884
|
} catch (error) {
|
|
858
885
|
console.error("Ошибка выполнения executeCreateCredit:", error);
|
|
859
886
|
Swal.fire(
|
|
860
887
|
"Критическая ошибка",
|
|
861
|
-
"Не удалось связаться с сервером банка",
|
|
888
|
+
"Не удалось связаться с сервером банка или обработать запрос",
|
|
889
|
+
"error",
|
|
890
|
+
);
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
async function payCreditManually(creditId, defaultAmount) {
|
|
894
|
+
const { value: formValues } = await Swal.fire({
|
|
895
|
+
title: "Погашение кредита",
|
|
896
|
+
html:
|
|
897
|
+
`<div style="text-align: left; margin-bottom: 8px;"><label style="font-weight:bold;">Сумма платежа (руб.)</label></div>` +
|
|
898
|
+
`<input id="swal-pay-amount" class="swal2-input" type="number" value="${parseFloat(defaultAmount).toFixed(2)}" min="1" step="any">` +
|
|
899
|
+
`<div style="text-align: left; margin-top: 12px; margin-bottom: 8px;"><label style="font-weight:bold;">PIN-код вашего счета</label></div>` +
|
|
900
|
+
`<input id="swal-pay-pin" class="swal2-input" type="password" placeholder="••••" maxlength="4">`,
|
|
901
|
+
focusConfirm: false,
|
|
902
|
+
showCancelButton: true,
|
|
903
|
+
confirmButtonText: "Оплатить",
|
|
904
|
+
cancelButtonText: "Отмена",
|
|
905
|
+
preConfirm: () => {
|
|
906
|
+
const amountVal = document.getElementById("swal-pay-amount").value;
|
|
907
|
+
const pinVal = document.getElementById("swal-pay-pin").value;
|
|
908
|
+
return {
|
|
909
|
+
amount: amountVal,
|
|
910
|
+
pinCode: pinVal,
|
|
911
|
+
};
|
|
912
|
+
},
|
|
913
|
+
});
|
|
914
|
+
|
|
915
|
+
if (!formValues || !formValues.amount || !formValues.pinCode) return;
|
|
916
|
+
|
|
917
|
+
try {
|
|
918
|
+
const res = await fetch("/api/bank/accounts/credit/pay", {
|
|
919
|
+
method: "POST",
|
|
920
|
+
headers: {
|
|
921
|
+
"Content-Type": "application/json",
|
|
922
|
+
"Bypass-Tunnel-Reminder": "true",
|
|
923
|
+
},
|
|
924
|
+
body: JSON.stringify({
|
|
925
|
+
creditId: parseInt(creditId, 10),
|
|
926
|
+
amount: parseFloat(formValues.amount),
|
|
927
|
+
pinCode: formValues.pinCode.trim(),
|
|
928
|
+
}),
|
|
929
|
+
});
|
|
930
|
+
|
|
931
|
+
const contentType = res.headers.get("content-type");
|
|
932
|
+
if (!contentType || !contentType.includes("application/json")) {
|
|
933
|
+
const textError = await res.text();
|
|
934
|
+
console.error("Критический ответ бэка:", textError);
|
|
935
|
+
Swal.fire(
|
|
936
|
+
"Ошибка сервера",
|
|
937
|
+
"Сервер вернул некорректный текстовый ответ. Проверьте консоль Node.js.",
|
|
938
|
+
"error",
|
|
939
|
+
);
|
|
940
|
+
return;
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
const data = await res.json();
|
|
944
|
+
|
|
945
|
+
if (data.status) {
|
|
946
|
+
await Swal.fire({
|
|
947
|
+
title: "Успех!",
|
|
948
|
+
text: data.message,
|
|
949
|
+
icon: "success",
|
|
950
|
+
});
|
|
951
|
+
|
|
952
|
+
if (typeof loadData === "function") loadData();
|
|
953
|
+
} else {
|
|
954
|
+
Swal.fire(
|
|
955
|
+
"Ошибка оплаты",
|
|
956
|
+
data.message || "Не удалось провести транзакцию",
|
|
957
|
+
"warning",
|
|
958
|
+
);
|
|
959
|
+
}
|
|
960
|
+
} catch (err) {
|
|
961
|
+
console.error("Ошибка запроса:", err);
|
|
962
|
+
Swal.fire(
|
|
963
|
+
"Критическая ошибка",
|
|
964
|
+
"Не удалось связаться с сервером банка.",
|
|
862
965
|
"error",
|
|
863
966
|
);
|
|
864
967
|
}
|
|
Binary file
|
|
Binary file
|