diff --git a/cancel.cjs b/cancel.cjs new file mode 100644 index 00000000..bfce04db --- /dev/null +++ b/cancel.cjs @@ -0,0 +1,48 @@ +const { generateToken } = require("./deep-packages/payments/tinkoff/generateToken.cjs"); +const { getError } = require("./deep-packages/payments/tinkoff/getError.cjs"); +const { getUrl } = require("./deep-packages/payments/tinkoff/getUrl.cjs"); +const dotenv = require('dotenv'); +const dotenvExpand = require('dotenv-expand'); +const crypto = require('crypto'); +const axios = require('axios'); + +const cancel = async (options) => { + try { + const response = await axios({ + method: 'post', + url: getUrl('Cancel'), + data: { ...options, Token: generateToken(options) }, + }); + + const error = getError(response.data.ErrorCode); + + return { + error, + request: options, + response: response.data, + }; + } catch (error) { + return { + error, + request: options, + response: null, + }; + } + }; + +var myEnv = dotenv.config(); +dotenvExpand.expand(myEnv); + +const f = async () => { + const cancelOptions = { + TerminalKey: process.env.PAYMENTS_C2B_TERMINAL_KEY, + PaymentId: 1942727609, + Amount: 3000 + } + + const cancelResult = await cancel(cancelOptions); + console.log({cancelResult}); +} + +f(); + diff --git a/deep-packages/insertHandler.cjs b/deep-packages/insertHandler.cjs new file mode 100644 index 00000000..5378e225 --- /dev/null +++ b/deep-packages/insertHandler.cjs @@ -0,0 +1,49 @@ +exports.insertHandler = async (param) => { + console.log('insertHandler', {param}) + const {deep,fileTypeLinkId, fileName, handlerName, handleName, triggerTypeLinkId, code, supportsId, handleOperationTypeLinkId, containTypeLinkId, packageId, handlerTypeLinkId} = param; + return await deep.insert({ + type_id: fileTypeLinkId, + in: { + data: [ + { + type_id: containTypeLinkId, + from_id: packageId, // before created package + string: { data: { value: fileName } }, + }, + { + from_id: supportsId, + type_id: handlerTypeLinkId, + in: { + data: [ + { + type_id: containTypeLinkId, + from_id: packageId, // before created package + string: { data: { value: handlerName } }, + }, + { + type_id: handleOperationTypeLinkId, + from_id: triggerTypeLinkId, + in: { + data: [ + { + type_id: containTypeLinkId, + from_id: packageId, // before created package + string: { data: { value: handleName } }, + }, + ], + }, + }, + ], + }, + }, + ], + }, + string: { + data: { + value: code, + }, + }, + }); + }; + + \ No newline at end of file diff --git a/deep-packages/insertNotificationHandler.cjs b/deep-packages/insertNotificationHandler.cjs new file mode 100644 index 00000000..64bc591f --- /dev/null +++ b/deep-packages/insertNotificationHandler.cjs @@ -0,0 +1,132 @@ +exports.insertNotificationHandler = async (param) => { + console.log('insertNotificationHandler', {param}) + const {deep, packageId,notificationPort, notificationRoute, portTypeLinkId, routerListeningTypeLinkId, routerTypeLinkId, routerStringUseTypeLinkId, routeTypeLinkId, handleRouteTypeLinkId, handlerTypeLinkId, supportsId, containTypeLinkId, adminId, fileTypeLinkId, handlerName, code} = param; + const insertData = { + type_id: portTypeLinkId, + number: { + data: { value: notificationPort }, + }, + in: { + data: [ + { + type_id: routerListeningTypeLinkId, + in: { + data: { + type_id: containTypeLinkId, + from_id: packageId, + }, + }, + from: { + data: { + type_id: routerTypeLinkId, + in: { + data: [ + { + type_id: routerStringUseTypeLinkId, + in: { + data: { + type_id: containTypeLinkId, + from_id: packageId, + string: { + data: { + value: handlerName, + }, + }, + }, + }, + string: { + data: { + value: + notificationRoute, + }, + }, + from: { + data: { + type_id: routeTypeLinkId, + in: { + data: { + type_id: containTypeLinkId, + from_id: packageId, + }, + }, + out: { + data: { + type_id: handleRouteTypeLinkId, + in: { + data: [ + { + type_id: containTypeLinkId, + from_id: packageId, + } + ] + }, + to: { + data: { + type_id: handlerTypeLinkId, + from_id: supportsId, + in: { + data: { + type_id: containTypeLinkId, + // from_id: deep.linkId, + from_id: packageId, + string: { + data: { + value: handlerName, + }, + }, + }, + }, + to: { + data: { + type_id: fileTypeLinkId, + string: { + data: { + value: code, + }, + }, + in: { + data: { + type_id: containTypeLinkId, + from_id: packageId, + string: { + data: { + value: handlerName, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + { + type_id: containTypeLinkId, + from_id: packageId, + } + ], + }, + }, + }, + } + , + { + type_id: containTypeLinkId, + from_id: packageId, + } + ], + }, + }; + console.log(JSON.stringify({insertData},null,2)) +return await deep.insert( + insertData, + { + name: 'INSERT_HANDLE_ROUTE_HIERARCHICAL', + } + ) +} + diff --git a/deep-packages/payments/tinkoff/_generateToken.cjs b/deep-packages/payments/tinkoff/_generateToken.cjs new file mode 100644 index 00000000..33540f3a --- /dev/null +++ b/deep-packages/payments/tinkoff/_generateToken.cjs @@ -0,0 +1,15 @@ +const crypto = require('crypto'); + +const _generateToken = (dataWithPassword) => { + const dataString = Object.keys(dataWithPassword) + .sort((a, b) => a.localeCompare(b)) + .map(key => dataWithPassword[key]) + .reduce((acc, item) => `${acc}${item}`, ''); + const hash = crypto + .createHash('sha256') + .update(dataString) + .digest('hex'); + return hash; + }; + +exports._generateToken = _generateToken; \ No newline at end of file diff --git a/deep-packages/payments/tinkoff/addCard.cjs b/deep-packages/payments/tinkoff/addCard.cjs new file mode 100644 index 00000000..4c375e6f --- /dev/null +++ b/deep-packages/payments/tinkoff/addCard.cjs @@ -0,0 +1,33 @@ +const axios = require('axios'); +const { generateToken } = require("./generateToken.cjs"); +const { getError } = require("./getError.cjs"); +const { getUrl } = require("./getUrl.cjs"); + +const addCard = async (options) => { + try { + const response = await axios({ + method: 'post', + url: getUrl('AddCard'), + headers: { + 'Content-Type': 'application/json', + }, + data: { ...options, Token: generateToken(options) }, + }); + + const error = getError(response.data.ErrorCode); + + return { + error, + request: options, + response: response.data, + }; + } catch (error) { + return { + error, + request: options, + response: null, + }; + } + }; + + exports.addCard = addCard; \ No newline at end of file diff --git a/deep-packages/payments/tinkoff/addCardInBrowser.cjs b/deep-packages/payments/tinkoff/addCardInBrowser.cjs new file mode 100644 index 00000000..1cd25862 --- /dev/null +++ b/deep-packages/payments/tinkoff/addCardInBrowser.cjs @@ -0,0 +1,44 @@ +const { sleep } = require("../../sleep.cjs"); + +const addCardInBrowser = async ({ page, browser, url }) => { + await page.goto(url, { waitUntil: 'networkidle2' }); + await page.waitForSelector('#card-number__input'); + await sleep(300); + await page.type('#card-number__input', process.env.PAYMENTS_C2B_CARD_NUMBER_SUCCESS); // card number + await sleep(300); + await page.keyboard.press('Tab'); + await sleep(300); + await page.type('#card-expiration__input', process.env.PAYMENTS_C2B_CARD_EXPDATE); // expired date + await sleep(300); + await page.keyboard.press('Tab'); + await sleep(300); + const needToEnterCVC = await page.evaluate(() => { + return !!document.querySelector('#cvv__input1'); + }); + if (needToEnterCVC) { + console.log('NEED CVC!!!!!!!'); + await page.type('#cvv__input1', process.env.PAYMENTS_C2B_CARD_CVC[0]); // CVC code + await sleep(300); + await page.keyboard.press('Tab'); + await sleep(300); + await page.type('#cvv__input2', process.env.PAYMENTS_C2B_CARD_CVC[1]); // CVC code + await sleep(300); + await page.keyboard.press('Tab'); + await sleep(300); + await page.type('#cvv__input3', process.env.PAYMENTS_C2B_CARD_CVC[2]); // CVC code + await sleep(3000); + } else { + console.log('NO NEED CVC!!!!!!!'); + } + await sleep(1000); + await page.keyboard.press('Tab'); + await sleep(2000); + await page.click('.form-submit button'); // submit button + await sleep(3000); + // await sleep(100); + // await page.close(); + // await sleep(100); + await browser.close(); +}; + + exports.addCardInBrowser = addCardInBrowser; \ No newline at end of file diff --git a/deep-packages/payments/tinkoff/c2c/addCard.cjs b/deep-packages/payments/tinkoff/c2c/addCard.cjs new file mode 100644 index 00000000..e815dba2 --- /dev/null +++ b/deep-packages/payments/tinkoff/c2c/addCard.cjs @@ -0,0 +1,54 @@ +const axios = require('axios'); +const { generateToken } = require("./generateToken.cjs"); +const { getError } = require("./getError.cjs"); +const { getUrl } = require("./getUrl.cjs"); + +const objectToFormData = (details) => { + const formBody = []; + for (const property in details) { + const encodedKey = encodeURIComponent(property); + const encodedValue = encodeURIComponent(details[property]); + formBody.push(`${encodedKey}=${encodedValue}`); + } + return formBody.join('&'); +}; + +const addCard = async (options) => { + try { + const response = await axios({ + method: 'post', + url: getUrl('AddCard'), + headers: { + 'Content-Type': 'application/json', + }, + data: { ...options, Token: generateToken(options) }, + }); + + const error = getError(response.data.ErrorCode); + + const d = { + error, + request: options, + response: response.data, + }; + options?.log && options.log(d); + + return { + error, + request: options, + response: response.data, + }; + } catch (e) { + console.log(e?.response?.data); + console.log(e?.response?.status); + console.log(e?.response?.data?.Causes); + const error = getError(e?.response?.ErrorCode); + return { + error, + request: options, + response: null, + }; + } + }; + + exports.addCard = addCard; \ No newline at end of file diff --git a/deep-packages/payments/tinkoff/c2c/addCustomer.cjs b/deep-packages/payments/tinkoff/c2c/addCustomer.cjs new file mode 100644 index 00000000..d50492d7 --- /dev/null +++ b/deep-packages/payments/tinkoff/c2c/addCustomer.cjs @@ -0,0 +1,54 @@ +const axios = require('axios'); +const { generateToken } = require("./generateToken.cjs"); +const { getError } = require("./getError.cjs"); +const { getUrl } = require("./getUrl.cjs"); + +const objectToFormData = (details) => { + const formBody = []; + for (const property in details) { + const encodedKey = encodeURIComponent(property); + const encodedValue = encodeURIComponent(details[property]); + formBody.push(`${encodedKey}=${encodedValue}`); + } + return formBody.join('&'); +}; + +const addCustomer = async (options) => { + try { + const response = await axios({ + method: 'post', + url: getUrl('AddCustomer'), + headers: { + 'Content-Type': 'application/json', + }, + data: { ...options, Token: generateToken(options) }, + }); + + const error = getError(response.data.ErrorCode); + + const d = { + error, + request: options, + response: response.data, + }; + options?.log && options.log(d); + + return { + error, + request: options, + response: response.data, + }; + } catch (e) { + console.log(e?.response?.data); + console.log(e?.response?.status); + console.log(e?.response?.data?.Causes); + const error = getError(e?.response?.ErrorCode); + return { + error, + request: options, + response: null, + }; + } + }; + + exports.addCustomer = addCustomer; \ No newline at end of file diff --git a/deep-packages/payments/tinkoff/c2c/errors.cjs b/deep-packages/payments/tinkoff/c2c/errors.cjs new file mode 100644 index 00000000..26aac8b1 --- /dev/null +++ b/deep-packages/payments/tinkoff/c2c/errors.cjs @@ -0,0 +1,40 @@ +const errors = { + 99: 'Воспользуйтесь другой картой, банк, выпустивший карту, отклонил операцию', + 101: 'Не пройдена идентификация 3DS', + 191: 'Некорректный статус договора, обратитесь к вашему менеджеру', + 604: 'Не получилось совершить платеж. Свяжитесь с поддержкой', + 619: 'Отсутствуют обязательные данные отправителя', + 620: 'Проверьте сумму — она не может быть равна 0.', + 623: 'Выплата по этому заказу уже прошла', + 632: 'Превышен лимит на сумму операции', + 633: 'Превышен лимит на количество переводов в день по иностранным картам', + 634: 'Превышен лимит на сумму переводов по номеру карты в месяц', + 637: 'Не хватает данных получателя или отправителя для выплаты наиностранную карту. Проверьте заполнение', + 642: 'Проверьте номер карты', + 648: 'Не получилось пополнить карту. Свяжитесь с поддержкой', + 650: 'Не получилось пополнить карту. Попробуйте позже', + 651: 'Не получилось совершить платеж. Свяжитесь с поддержкой', + 703: 'Не получилось пополнить карту. Попробуйте позже', + 1006: 'Проверьте реквизиты или воспользуйтесь другой картой', + 1012: 'Воспользуйтесь другой картой', + 1013: 'Повторите попытку позже', + 1014: 'Неверно введены реквизиты карты. Проверьте корректность введенных данных', + 1030: 'Повторите попытку позже', + 1033: 'Проверьте реквизиты или воспользуйтесь другой картой', + 1034: 'Воспользуйтесь другой картой, банк, выпустивший карту, отклонил операцию', + 1041: 'Воспользуйтесь другой картой, банк, выпустивший карту, отклонил операцию', + 1043: 'Воспользуйтесь другой картой, банк, выпустивший карту, отклонил операцию', + 1051: 'Недостаточно средств на карте', + 1054: 'Проверьте реквизиты или воспользуйтесь другой картой', + 1057: 'Воспользуйтесь другой картой, банк, выпустивший карту, отклонил операцию', + 1065: 'Воспользуйтесь другой картой, банк, выпустивший карту, отклонил операцию', + 1082: 'Проверьте реквизиты или воспользуйтесь другой картой', + 1089: 'Воспользуйтесь другой картой, банк, выпустивший карту, отклонил операцию', + 1091: 'Воспользуйтесь другой картой', + 1096: 'Повторите попытку позже', + 1502: 'Недостаточно средств на счете компании', + 1503: 'Некорректный статус счета, обратитесь в поддержку', + 9999: 'Внутренняя ошибка системы', + }; + +exports.errors = errors; \ No newline at end of file diff --git a/deep-packages/payments/tinkoff/c2c/generateToken.cjs b/deep-packages/payments/tinkoff/c2c/generateToken.cjs new file mode 100644 index 00000000..551f6a32 --- /dev/null +++ b/deep-packages/payments/tinkoff/c2c/generateToken.cjs @@ -0,0 +1,18 @@ +const crypto = require('crypto'); +const {_generateToken} = require("./../_generateToken.cjs"); + +const generateToken = (data) => { + const { Receipt, DATA, ...restData } = data; + const dataWithPassword = { ...restData, Password: process.env.PAYMENTS_C2C_TERMINAL_PASSWORD }; + return _generateToken(dataWithPassword); + }; + + const generateTokenStringWithInsertedTerminalPassword = generateToken + .toString() + .replace( + 'process.env.PAYMENTS_C2C_TERMINAL_PASSWORD', + `"${process.env.PAYMENTS_C2C_TERMINAL_PASSWORD}"` + ); + +exports.generateToken = generateToken; +exports.generateTokenStringWithInsertedTerminalPassword = generateTokenStringWithInsertedTerminalPassword; \ No newline at end of file diff --git a/deep-packages/payments/tinkoff/c2c/getCardList.cjs b/deep-packages/payments/tinkoff/c2c/getCardList.cjs new file mode 100644 index 00000000..a40e0a35 --- /dev/null +++ b/deep-packages/payments/tinkoff/c2c/getCardList.cjs @@ -0,0 +1,33 @@ +const axios = require('axios'); +const { generateToken } = require("./generateToken.cjs"); +const { getError } = require("./getError.cjs"); +const { getUrl } = require("./getUrl.cjs"); + +const getCardList = async (options) => { + try { + const response = await axios({ + method: 'post', + url: getUrl('GetCardList'), + headers: { + 'Content-Type': 'application/json', + }, + data: { ...options, Token: generateToken(options) }, + }); + + const error = getError(response.data.ErrorCode || '0'); + + return { + error, + request: options, + response: response.data, + }; + } catch (error) { + return { + error, + request: options, + response: null, + }; + } + }; + + exports.getCardList = getCardList; \ No newline at end of file diff --git a/deep-packages/payments/tinkoff/c2c/getError.cjs b/deep-packages/payments/tinkoff/c2c/getError.cjs new file mode 100644 index 00000000..0ab73890 --- /dev/null +++ b/deep-packages/payments/tinkoff/c2c/getError.cjs @@ -0,0 +1,6 @@ +const {errors} = require("./errors.cjs"); + + +const getError = errorCode => errorCode === '0' ? undefined : (errors[errorCode] || 'broken'); + +exports.getError = getError; \ No newline at end of file diff --git a/deep-packages/payments/tinkoff/c2c/getUrl.cjs b/deep-packages/payments/tinkoff/c2c/getUrl.cjs new file mode 100644 index 00000000..0bb81bf0 --- /dev/null +++ b/deep-packages/payments/tinkoff/c2c/getUrl.cjs @@ -0,0 +1,12 @@ +const getUrl = (method) => + `${process.env.PAYMENTS_C2B_URL}/${method}`; + const getUrlString = getUrl + .toString() + .replace( + '${process.env.PAYMENTS_C2B_URL}', + process.env.PAYMENTS_C2B_URL + ); + console.log({ getUrlString }); + + exports.getUrl = getUrl; + exports.getUrlString = getUrlString; \ No newline at end of file diff --git a/deep-packages/payments/tinkoff/c2c/init.cjs b/deep-packages/payments/tinkoff/c2c/init.cjs new file mode 100644 index 00000000..18711ba4 --- /dev/null +++ b/deep-packages/payments/tinkoff/c2c/init.cjs @@ -0,0 +1,43 @@ +const axios = require('axios'); +const { generateToken } = require("./generateToken.cjs"); +const { getError } = require("./getError.cjs"); +const { getUrl } = require("./getUrl.cjs"); + +const objectToFormData = (details) => { + const formBody = []; + for (const property in details) { + const encodedKey = encodeURIComponent(property); + const encodedValue = encodeURIComponent(details[property]); + formBody.push(`${encodedKey}=${encodedValue}`); + } + return formBody.join('&'); +}; + +const init = async (options) => { + try { + const response = await axios({ + method: 'post', + url: getUrl('Init'), + headers: { + 'Content-Type': 'application/json', + }, + data: { ...options, Token: generateToken(options) }, + }); + + const error = getError(response.data.ErrorCode); + + return { + error, + request: options, + response: response.data, + }; + } catch (error) { + return { + error, + request: options, + response: null, + }; + } +}; + + exports.init = init; \ No newline at end of file diff --git a/deep-packages/payments/tinkoff/c2c/notificationHandler.js b/deep-packages/payments/tinkoff/c2c/notificationHandler.js new file mode 100644 index 00000000..ad374a95 --- /dev/null +++ b/deep-packages/payments/tinkoff/c2c/notificationHandler.js @@ -0,0 +1,385 @@ + +async ( + req, + res, + next, + { deep, require, gql } +) => { + +const crypto = require('crypto'); +const axios = require('axios'); +const errors = {"7":"Покупатель не найден","53":"Обратитесь к продавцу","99":"Платеж отклонен","100":"Повторите попытку позже","101":"Не пройдена идентификация 3DS","102":"Операция отклонена, пожалуйста обратитесь в интернет-магазин или воспользуйтесь другой картой","103":"Повторите попытку позже","119":"Превышено кол-во запросов на авторизацию","191":"Некорректный статус договора, обратитесь к вашему менеджеру","1001":"Свяжитесь с банком, выпустившим карту, чтобы провести платеж","1003":"Неверный merchant ID","1004":"Карта украдена. Свяжитесь с банком, выпустившим карту","1005":"Платеж отклонен банком, выпустившим карту","1006":"Свяжитесь с банком, выпустившим карту, чтобы провести платеж","1007":"Карта украдена. Свяжитесь с банком, выпустившим карту","1008":"Платеж отклонен, необходима идентификация","1012":"Такие операции запрещены для этой карты","1013":"Повторите попытку позже","1014":"Карта недействительна. Свяжитесь с банком, выпустившим карту","1015":"Попробуйте снова или свяжитесь с банком, выпустившим карту","1019":"Платеж отклонен — попробуйте снова","1030":"Повторите попытку позже","1033":"Истек срок действия карты. Свяжитесь с банком, выпустившим карту","1034":"Попробуйте повторить попытку позже","1038":"Превышено количество попыток ввода ПИН-кода","1039":"Платеж отклонен — счет не найден","1041":"Карта утеряна. Свяжитесь с банком, выпустившим карту","1043":"Карта украдена. Свяжитесь с банком, выпустившим карту","1051":"Недостаточно средств на карте","1053":"Платеж отклонен — счет не найден","1054":"Истек срок действия карты","1055":"Неверный ПИН","1057":"Такие операции запрещены для этой карты","1058":"Такие операции запрещены для этой карты","1059":"Подозрение в мошенничестве. Свяжитесь с банком, выпустившим карту","1061":"Превышен дневной лимит платежей по карте","1062":"Платежи по карте ограничены","1063":"Операции по карте ограничены","1064":"Проверьте сумму","1065":"Превышен дневной лимит транзакций","1075":"Превышено число попыток ввода ПИН-кода","1076":"Платеж отклонен — попробуйте снова","1077":"Коды не совпадают — попробуйте снова","1080":"Неверный срок действия","1082":"Неверный CVV","1086":"Платеж отклонен — не получилось подтвердить ПИН-код","1088":"Ошибка шифрования. Попробуйте снова","1089":"Попробуйте повторить попытку позже","1091":"Банк, выпустивший карту недоступен для проведения авторизации","1092":"Платеж отклонен — попробуйте снова","1093":"Подозрение в мошенничестве. Свяжитесь с банком, выпустившим карту","1094":"Системная ошибка","1096":"Повторите попытку позже","9999":"Внутренняя ошибка системы"}; +const getError = (errorCode) => + errorCode === '0' ? undefined : errors[errorCode] || 'broken'; +const getUrl = (method) => + `https://securepay.tinkoff.ru/v2/${method}`; +const generateToken = (data) => { + const { Receipt, DATA, Shops, ...restData } = data; + const dataWithPassword = { + Password: "w4k58ksi9g5sammh", + ...restData, + }; + console.log({ dataWithPassword }); + + const dataString = Object.keys(dataWithPassword) + .sort((a, b) => a.localeCompare(b)) + .map((key) => dataWithPassword[key]) + .reduce((acc, item) => `${acc}${item}`, ''); + console.log({ dataString }); + const hash = crypto.createHash('sha256').update(dataString).digest('hex'); + console.log({ hash }); + return hash; +}; + + + if(!(req.body.Status === "AUTHORIZED" || req.body.Status === "CONFIRMED" )) { + return next(); + } + + if (req.body.Status === 'AUTHORIZED') { + const reqBody = req.body; + console.log({reqBody}); + + const tinkoffProviderTypeLinkId = await deep.id("@deep-foundation/payments-tinkoff-c2b", "TinkoffProvider"); + const tinkoffProviderLinkSelectQuery = await deep.select({ + type_id: tinkoffProviderTypeLinkId + }); + if(tinkoffProviderLinkSelectQuery.error) {throw new Error(tinkoffProviderLinkSelectQuery.error.message);} + const tinkoffProviderLinkId = tinkoffProviderLinkSelectQuery.data[0].id; + console.log({tinkoffProviderLinkId}); + + console.log(JSON.stringify(await deep.select({type_id: await deep.id("@deep-foundation/payments-tinkoff-c2b", "Payment")}))) + console.log("Select args:" ,JSON.stringify({ + object: {value: {_contains: {bankPaymentId: req.body.PaymentId}}} + })) + + const paymentLinkSelectQuery = await deep.select({ + object: {value: {_contains: {bankPaymentId: parseInt(req.body.PaymentId)}}} + }); + if(paymentLinkSelectQuery.error) { throw new Error(paymentLinkSelectQuery.error.message); } + const paymentLink = paymentLinkSelectQuery.data[0]; + console.log({paymentLink}); + if(!paymentLink) { throw new Error("The payment link associated with the bank payment id " + req.body.PaymentId + " is not found."); } + + const {data: mpUpPayment, error: mpUpPaymentSelectQueryError} = await deep.select({ + up: { + parent_id: { _eq: paymentLink.id }, + tree_id: { _eq: await deep.id("@deep-foundation/payments-tinkoff-c2b", "paymentTree") } + } + }); + console.log({mpUpPayment}); + if(mpUpPaymentSelectQueryError) { throw new Error(mpUpPaymentSelectQueryError.message); } + + const payTypeLinkId = await deep.id("@deep-foundation/payments-tinkoff-c2b", "Pay"); + const payLink = mpUpPayment.find(link => link.type_id === payTypeLinkId); + console.log({payLink}); + if(!payLink) { throw new Error("The pay link associated with payment link " + paymentLink + " is not found.") } + + const confirm = async (options) => { + try { + const response = await axios({ + method: 'post', + url: getUrl('Confirm'), + data: { ...options, Token: generateToken(options) }, + }); + + const error = getError(response.data.ErrorCode); + + return { + error, + request: options, + response: response.data, + }; + } catch (error) { + return { + error, + request: options, + response: null, + }; + } + }; + + const storageReceiverLinkSelectQuery = await deep.select({ + id: paymentLink.to_id + }); + if(storageReceiverLinkSelectQuery.error) {throw new Error(storageReceiverLinkSelectQuery.error.message);} + const storageReceiverId = storageReceiverLinkSelectQuery.data[0].id; + console.log({storageReceiverId}); + + + const usesTokenTypeLinkId = await deep.id("@deep-foundation/payments-tinkoff-c2b", "UsesToken"); + const usesTokenLinkSelectQuery = await deep.select({ + type_id: usesTokenTypeLinkId, + from_id: storageReceiverId, + }); + if(usesTokenLinkSelectQuery.error) {throw new Error(usesTokenLinkSelectQuery.error.message);} + const usesTokenLink = usesTokenLinkSelectQuery.data[0]; + console.log({usesTokenLink}); + + const tokenLinkSelectQuery = await deep.select({ + id: usesTokenLink.to_id, + }); + if(tokenLinkSelectQuery.error) {throw new Error(tokenLinkSelectQuery.error.message);} + const tokenLink = tokenLinkSelectQuery.data[0]; + console.log({tokenLink}); + + const confirmOptions = { + TerminalKey: tokenLink.value.value, + PaymentId: req.body.PaymentId, + Amount: req.body.Amount, + // Receipt: req.body.Receipt, + }; + console.log({confirmOptions}); + + const confirmResult = await confirm(confirmOptions); + console.log({confirmResult}); + + if (confirmResult.error) { + const errorMessage = "Could not confirm the pay. " + confirmResult.error; + const {error: errorLinkInsertError} = await deep.insert({ + type_id: (await deep.id("@deep-foundation/payments-tinkoff-c2b", "Error")), + from_id: tinkoffProviderLinkId, + to_id: payLink.id, + string: { data: { value: errorMessage } }, + }); + if(errorLinkInsertError) { throw new Error(errorLinkInsertError); } + throw new Error(errorMessage); + } + + return confirmResult; + } else if (req.body.Status === 'CONFIRMED') { + +const TinkoffProvider = await deep.id("@deep-foundation/payments-tinkoff-c2b", "TinkoffProvider"); +const tinkoffProviderLinkSelectQuery = await deep.select({ + type_id: TinkoffProvider +}); +if (tinkoffProviderLinkSelectQuery.error) { throw new Error(tinkoffProviderLinkSelectQuery.error.message); } +const tinkoffProviderId = tinkoffProviderLinkSelectQuery.data[0].id; +console.log({ tinkoffProviderId }); + +const paymentLinkSelectQuery = await deep.select({ + object: { value: { _contains: { orderId: req.body.OrderId } } } +}); +if (paymentLinkSelectQuery.error) { throw new Error(paymentLinkSelectQuery.error.message); } +const paymentLink = paymentLinkSelectQuery.data[0]; +console.log({ paymentLink }); +if (!paymentLink) { throw new Error("The payment link associated with the order id " + req.body.OrderId + " is not found."); } + +const { data: mpUpPayment, error: mpUpPaymentSelectQueryError } = await deep.select({ + up: { + parent_id: { _eq: paymentLink.id }, + tree_id: { _eq: await deep.id("@deep-foundation/payments-tinkoff-c2b", "paymentTree") } + } +}); +console.log({ mpUpPayment }); +if (mpUpPaymentSelectQueryError) { throw new Error(mpUpPaymentSelectQueryError.message); } + +const Pay = await deep.id("@deep-foundation/payments-tinkoff-c2b", "Pay"); +const payLink = mpUpPayment.find(link => link.type_id === Pay); +console.log({ payLink }); +if (!payLink) { throw new Error("The pay link associated with payment link " + paymentLink + " is not found.") } + +const storageReceiverLinkSelectQuery = await deep.select({ + id: paymentLink.to_id +}); +if (storageReceiverLinkSelectQuery.error) { throw new Error(storageReceiverLinkSelectQuery.error.message); } +const storageReceiverLink = storageReceiverLinkSelectQuery.data[0]; +console.log({ storageReceiverLink }); + +const Token = await deep.id("@deep-foundation/payments-tinkoff-c2b", "Token"); +const tokenLinkSelectQuery = await deep.select({ + type_id: Token, + from_id: storageReceiverLink.id, + to_id: storageReceiverLink.id +}); +if (tokenLinkSelectQuery.error) { throw new Error(tokenLinkSelectQuery.error.message); } +const tokenLink = tokenLinkSelectQuery.data[0]; +console.log({ tokenLink }); + +const storageReceiverSelectQuery = await deep.select({ + id: paymentLink.to_id +}); +if (storageReceiverSelectQuery.error) { throw new Error(storageReceiverSelectQuery.error.message); } +const storageReceiver = storageReceiverSelectQuery.data[0]; +console.log({ storageReceiver }); +if (!storageReceiver) { throw new Error("The storage receiver link associated with the order id " + req.body.OrderId + " is not found."); } + +const sumLinkSelectQuery = await deep.select({ + type_id: await deep.id("@deep-foundation/payments-tinkoff-c2b", "Sum"), + to_id: paymentLink.id +}); +if (sumLinkSelectQuery.error) { throw new Error(sumLinkSelectQuery.error.message); } +const sumLink = sumLinkSelectQuery.data[0]; +console.log({ sumLink }); +if (!sumLink) { throw new Error("The sum link associated with the order id " + req.body.OrderId + " is not found."); } + +const _generateToken = (dataWithPassword) => { + const dataString = Object.keys(dataWithPassword) + .sort((a, b) => a.localeCompare(b)) + .map(key => dataWithPassword[key]) + .reduce((acc, item) => `${acc}${item}`, ''); + const hash = crypto + .createHash('sha256') + .update(dataString) + .digest('hex'); + return hash; + }; +const generateToken = (data) => { + const { Receipt, DATA, ...restData } = data; + const dataWithPassword = { ...restData, Password: "undefined" }; + return _generateToken(dataWithPassword); + }; +const getUrl = (method) => + `undefined/${method}`; +const getError = errorCode => errorCode === '0' ? undefined : (errors[errorCode] || 'broken'); + +const C2CToken = await deep.id("@deep-foundation/payments-tinkoff-c2b", "C2CToken"); +const C2CTokenLinkSelectQuery = await deep.select({ + type_id: C2CToken, + from_id: storageReceiverLink.id, + to_id: storageReceiverLink.id +}); +if (C2CTokenLinkSelectQuery.error) { throw new Error(C2CTokenLinkSelectQuery.error.message); } +const C2CTokenLink = C2CTokenLinkSelectQuery.data[0]; +console.log({ C2CTokenLink }); + +const initOptions = { + TerminalKey: C2CTokenLink.value.value, + OrderId: req.body.OrderId, + CardId: storageReceiver.value.value, + Amount: sumLink.value.value, +}; +console.log({ initOptions }); + +const init = async (options) => { + try { + const response = await axios({ + method: 'post', + url: getUrl('Init'), + headers: { + 'Content-Type': 'application/json', + }, + data: { ...options, Token: generateToken(options) }, + }); + + const error = getError(response.data.ErrorCode); + + return { + error, + request: options, + response: response.data, + }; + } catch (error) { + return { + error, + request: options, + response: null, + }; + } +}; +const initResult = await init(initOptions); +console.log({ initResult }); +if (initResult.error) { + const errorMessage = initResult.error; + const { error: errorLinkInsertQueryError } = await deep.insert({ + type_id: (await deep.id("@deep-foundation/payments-tinkoff-c2b", "Error")), + from_id: tinkoffProviderId, + to_id: payLink.id, + string: { data: { value: errorMessage } }, + }); + if (errorLinkInsertQueryError) { throw new Error(errorLinkInsertQueryError.message); } + throw new Error(errorMessage); +} + +const paymentOptions = { + TerminalKey: C2CTokenLink.value.value, + PaymentId: initResult.response.PaymentId, +} + +const payment = async (options) => { + try { + const response = await axios({ + method: 'post', + url: getUrl('Payment'), + headers: { + 'Content-Type': 'application/json', + }, + data: {...options, Token: generateToken(options)}, + }); + + const error = getError(response.data.ErrorCode); + + const d = { + error, + request: options, + response: response.data, + }; + options?.log && options.log(d); + + return { + error, + request: options, + response: response.data, + }; + } catch (error) { + return { + error, + request: options, + response: null, + }; + } + }; +const paymentResult = await payment(paymentOptions); +console.log({ paymentResult }); +if (paymentResult.error) { + const errorMessage = "Could not initialize the order. " + paymentResult.error; + const { error: errorLinkInsertQueryError } = await deep.insert({ + type_id: (await deep.id("@deep-foundation/payments-tinkoff-c2b", "Error")), + from_id: tinkoffProviderId, + to_id: payLink.id, + string: { data: { value: errorMessage } }, + }); + if (errorLinkInsertQueryError) { throw new Error(errorLinkInsertQueryError.message); } + throw new Error(errorMessage); +} + +const payedLinkInsertQuery = await deep.insert({ + type_id: await deep.id("@deep-foundation/payments-tinkoff-c2b", "Payed"), + from_id: tinkoffProviderId, + to_id: payLink.id, +}); + +if (payedLinkInsertQuery.error) { throw new Error(payedLinkInsertQuery.error.message); } +const payedLinkId = payedLinkInsertQuery.data[0].id; +console.log({ payedLinkId }); + +const StorageClient = await deep.id("@deep-foundation/payments-tinkoff-c2b", "StorageClient"); +const storagePayerLinkSelectQuery = await deep.select({ + type_id: StorageClient, + number: { value: req.body.CardId } +}); +if (storagePayerLinkSelectQuery.error) { throw new Error(storagePayerLinkSelectQuery.error.message); } +let storagePayerLinkId = storagePayerLinkSelectQuery.data[0]; +console.log({ storagePayerLinkId }); +if (!storagePayerLinkId) { + const storagePayerLinkInsertQuery = await deep.insert({ + type_id: StorageClient, + number: { data: { value: req.body.CardId } } + }); + if (storagePayerLinkInsertQuery.error) { throw new Error(storagePayerLinkInsertQuery.error.message); } + storagePayerLinkId = storagePayerLinkInsertQuery.data[0].id; + console.log({ storagePayerLinkId }); +} + +const Income = await deep.id("@deep-foundation/payments-tinkoff-c2b", "Income"); +const incomeLinkInsertQuery = await deep.insert({ + type_id: Income, + from_id: paymentLink.id, + to_id: storagePayerLinkId, +}); +if (incomeLinkInsertQuery.error) { throw new Error(incomeLinkInsertQuery.error.message); } +const incomeLinkId = incomeLinkInsertQuery.data[0].id; +console.log({ incomeLinkId }); + + } +}; diff --git a/deep-packages/payments/tinkoff/c2c/payInsertHandler.js b/deep-packages/payments/tinkoff/c2c/payInsertHandler.js new file mode 100644 index 00000000..4a9c4302 --- /dev/null +++ b/deep-packages/payments/tinkoff/c2c/payInsertHandler.js @@ -0,0 +1,197 @@ + +async ({ deep, require, data: { newLink, triggeredByLinkId } }) => { + +const crypto = require('crypto'); +const axios = require('axios'); + +const terminalPasswordTypeLinkId = await deep.id("@deep-foundation/payments-tinkoff-c2b", "TerminalPassword"); +const usesTerminalPasswordTypeLinkId = await deep.id("@deep-foundation/payments-tinkoff-c2b", "UsesTerminalPassword"); +const { data: [terminalPasswordLink] } = await deep.select({ + type_id: terminalPasswordTypeLinkId, + in: { + type_id: usesTerminalPasswordTypeLinkId, + from_id: storageBusinessLink.id + } +}); +if (!terminalPasswordLink) { + throw new Error(`A link with type ##${terminalPasswordTypeLinkId} is not found`); +} +if (!terminalPasswordLink.value?.value) { + throw new Error(`##${terminalPasswordLink.id} must have a value`); +} +const terminalPassword = terminalPasswordLink.value.value; + +const generateToken = (data) => { + const { Receipt, DATA, Shops, ...restData } = data; + const dataWithPassword = { + Password: terminalPassword, + ...restData, + }; + console.log({ dataWithPassword }); + + const dataString = Object.keys(dataWithPassword) + .sort((a, b) => a.localeCompare(b)) + .map((key) => dataWithPassword[key]) + .reduce((acc, item) => `${acc}${item}`, ''); + console.log({ dataString }); + const hash = crypto.createHash('sha256').update(dataString).digest('hex'); + console.log({ hash }); + return hash; +}; + +const tinkoffApiUrlTypeLinkId = await deep.id("@deep-foundation/payments-tinkoff-c2b", "TinkoffApiUrl"); +const { data: [tinkoffApiUrlLink] } = await deep.select({ + type_id: tinkoffApiUrlTypeLinkId +}); +if (!tinkoffApiUrlLink) { + throw new Error(`A link with type ##${tinkoffApiUrlTypeLinkId} is not found`); +} +if (!tinkoffApiUrlLink.value?.value) { + throw new Error(`##${tinkoffApiUrlLink.id} must have a value`); +} +const tinkoffApiUrl = tinkoffApiUrlLink.value.value; + + + const tinkoffProviderTypeLinkId = await deep.id("@deep-foundation/payments-tinkoff-c2b", "TinkoffProvider"); + const tinkoffProviderLinkSelectQuery = await deep.select({ + type_id: tinkoffProviderTypeLinkId + }); + if(tinkoffProviderLinkSelectQuery.error) {throw new Error(tinkoffProviderLinkSelectQuery.error.message);} + const tinkoffProviderLinkId = tinkoffProviderLinkSelectQuery.data[0].id; + + const {data: mpDownPay, error: mpDownPaySelectQueryError} = await deep.select({ + down: { + link_id: { _eq: newLink.id }, + tree_id: { _eq: await deep.id("@deep-foundation/payments-tinkoff-c2b", "paymentTree") }, + }, + }); + console.log({mpDownPay}); + if(mpDownPaySelectQueryError) { throw new Error(mpDownPaySelectQueryError.message); } + + const paymentTypeLinkId = await deep.id("@deep-foundation/payments-tinkoff-c2b", "Payment"); + const paymentLink = mpDownPay.find(link => link.type_id === paymentTypeLinkId); + console.log({paymentLink}); + if(!paymentLink) throw new Error("Payment link associated with the pay link " + newLink.id + " is not found."); + + const sumTypeLinkId = await deep.id("@deep-foundation/payments-tinkoff-c2b", "Sum"); + const sumLink = mpDownPay.find(link => link.type_id === sumTypeLinkId); + console.log({sumLink}); + if(!sumLink) throw new Error("Sum link associated with the pay link " + newLink.id + " is not found."); + + const fromLinkOfPaymentSelectQuery = await deep.select({ + id: paymentLink.from_id + }); + if(fromLinkOfPaymentSelectQuery.error) { throw new Error(fromLinkOfPaymentSelectQuery.error.message); } + const fromLinkOfPayment = fromLinkOfPaymentSelectQuery.data[0]; + console.log({fromLinkOfPayment}); + + const storageBusinessLinkSelectQuery = await deep.select({ + id: paymentLink.to_id + }); + if(storageBusinessLinkSelectQuery.error) { throw new Error(storageBusinessLinkSelectQuery.error.message); } + const storageBusinessLinkId = storageBusinessLinkSelectQuery.data[0].id; + console.log({storageBusinessLinkId}); + + const usesTokenTypeLinkId = await deep.id("@deep-foundation/payments-tinkoff-c2b", "UsesToken"); + const usesTokenLinkSelectQuery = await deep.select({ + type_id: usesTokenTypeLinkId, + from_id: storageBusinessLinkId, + }); + if(usesTokenLinkSelectQuery.error) {throw new Error(usesTokenLinkSelectQuery.error.message);} + const usesTokenLink = usesTokenLinkSelectQuery.data[0]; + console.log({usesTokenLink}); + + const tokenLinkSelectQuery = await deep.select({ + id: usesTokenLink.to_id, + }); + if(tokenLinkSelectQuery.error) {throw new Error(tokenLinkSelectQuery.error.message);} + const tokenLink = tokenLinkSelectQuery.data[0]; + console.log({tokenLink}); + + const init = async (options) => { + try { + const response = await axios({ + method: 'post', + url: `${tinkoffApiUrl}/Init`, + headers: { + 'Content-Type': 'application/json', + }, + data: { ...options, Token: generateToken(options) }, + }); + + const error = response.data.Details; + + return { + error, + request: options, + response: response.data, + }; + } catch (error) { + return { + error, + request: options, + response: null, + }; + } + }; + + const options = { + TerminalKey: tokenLink.value.value, + OrderId: "" + Date.now() + paymentLink.id, + CustomerKey: triggeredByLinkId, + NotificationURL: "https://5237-deepfoundation-dev-ymdvap98nh7.ws-us87.gitpod.io/payments-tinkoff-c2b", + PayType: 'T', + Amount: sumLink.value.value, + Description: 'Test shopping', + Language: 'ru', + Recurrent: 'Y', + DATA: { + Email: "karafizi.artur@gmail.com", + Phone: "+79003201234", + }, + // Receipt: { + // Items: [{ + // Name: 'Test item', + // Price: sum, + // Quantity: 1, + // Amount: sumLink.value.value, + // PaymentMethod: 'prepayment', + // PaymentObject: 'service', + // Tax: 'none', + // }], + // Email: "karafizi.artur@gmail.com", + // Phone: "+79003201234", + // Taxation: 'usn_income', + // } + }; + console.log({options}); + + let initResult = await init(options); + console.log({initResult}); + if (initResult.error) { + const errorMessage = "Could not initialize the order. " + initResult.error; + const {error: errorLinkInsertQueryError} = await deep.insert({ + type_id: (await deep.id("@deep-foundation/payments-tinkoff-c2b", "Error")), + from_id: tinkoffProviderLinkId, + to_id: newLink.id, + string: { data: { value: errorMessage } }, + }); + if(errorLinkInsertQueryError) { throw new Error(errorLinkInsertQueryError.message); } + throw new Error(errorMessage); + } + + const urlTypeLinkId = await deep.id("@deep-foundation/payments-tinkoff-c2b", "Url"); + const {error: urlLinkInsertQueryError} = await deep.insert({ + type_id: urlTypeLinkId, + from_id: tinkoffProviderLinkId, + to_id: newLink.id, + string: { data: { value: initResult.response.PaymentURL } }, + }); + if(urlLinkInsertQueryError) { throw new Error(urlLinkInsertQueryError.message); } + + const paymentValueLinkInsertQuery = await deep.insert({link_id: paymentLink.id, value: {bankPaymentId: parseInt(initResult.response.PaymentId)}}, {table: "objects"}) + if(paymentValueLinkInsertQuery.error) { throw new Error(paymentValueLinkInsertQuery.error.message); } + console.log(JSON.stringify(paymentValueLinkInsertQuery)); + + return initResult; +}; diff --git a/deep-packages/payments/tinkoff/c2c/payment.cjs b/deep-packages/payments/tinkoff/c2c/payment.cjs new file mode 100644 index 00000000..634191fc --- /dev/null +++ b/deep-packages/payments/tinkoff/c2c/payment.cjs @@ -0,0 +1,41 @@ +const axios = require('axios'); +const { generateToken } = require("./generateToken.cjs"); +const { getError } = require("./getError.cjs"); +const { getUrl } = require("./getUrl.cjs"); + + +const payment = async (options) => { + try { + const response = await axios({ + method: 'post', + url: getUrl('Payment'), + headers: { + 'Content-Type': 'application/json', + }, + data: {...options, Token: generateToken(options)}, + }); + + const error = getError(response.data.ErrorCode); + + const d = { + error, + request: options, + response: response.data, + }; + options?.log && options.log(d); + + return { + error, + request: options, + response: response.data, + }; + } catch (error) { + return { + error, + request: options, + response: null, + }; + } + }; + +exports.payment = payment; \ No newline at end of file diff --git a/deep-packages/payments/tinkoff/insertTinkoffNotificationHandler.cjs b/deep-packages/payments/tinkoff/insertTinkoffNotificationHandler.cjs new file mode 100644 index 00000000..4c2fb079 --- /dev/null +++ b/deep-packages/payments/tinkoff/insertTinkoffNotificationHandler.cjs @@ -0,0 +1,118 @@ +const {insertNotificationHandler: baseInsertNotificationHandler} = require("../../insertNotificationHandler.cjs"); +const {handlersDependencies} = require("./handlersDependencies.cjs"); +const {confirm} = require("./confirm.cjs"); + +exports.insertTinkoffNotificationHandler = async (param) => { + console.log('insertTinkoffNotificationHandler' , {param}) + const {packageName, packageId, deep, notificationPort, notificationRoute, portTypeLinkId, routerListeningTypeLinkId, routerTypeLinkId, routerStringUseTypeLinkId, routeTypeLinkId, handleRouteTypeLinkId, handlerTypeLinkId, supportsId, containTypeLinkId, adminId, fileTypeLinkId, onConfirmedCode} = param; + const code = ` +async ( + req, + res, + next, + { deep, require, gql } +) => { + ${handlersDependencies} + + if(!(req.body.Status === "AUTHORIZED" || req.body.Status === "CONFIRMED" )) { + return next(); + } + + if (req.body.Status === 'AUTHORIZED') { + const reqBody = req.body; + console.log({reqBody}); + + const tinkoffProviderTypeLinkId = await deep.id("${packageName}", "TinkoffProvider"); + const tinkoffProviderLinkSelectQuery = await deep.select({ + type_id: tinkoffProviderTypeLinkId + }); + if(tinkoffProviderLinkSelectQuery.error) {throw new Error(tinkoffProviderLinkSelectQuery.error.message);} + const tinkoffProviderLinkId = tinkoffProviderLinkSelectQuery.data[0].id; + console.log({tinkoffProviderLinkId}); + + console.log(JSON.stringify(await deep.select({type_id: await deep.id("${packageName}", "Payment")}))) + console.log("Select args:" ,JSON.stringify({ + object: {value: {_contains: {bankPaymentId: req.body.PaymentId}}} + })) + + const paymentLinkSelectQuery = await deep.select({ + object: {value: {_contains: {bankPaymentId: parseInt(req.body.PaymentId)}}} + }); + if(paymentLinkSelectQuery.error) { throw new Error(paymentLinkSelectQuery.error.message); } + const paymentLink = paymentLinkSelectQuery.data[0]; + console.log({paymentLink}); + if(!paymentLink) { throw new Error("The payment link associated with the bank payment id " + req.body.PaymentId + " is not found."); } + + const {data: mpUpPayment, error: mpUpPaymentSelectQueryError} = await deep.select({ + up: { + parent_id: { _eq: paymentLink.id }, + tree_id: { _eq: await deep.id("${packageName}", "paymentTree") } + } + }); + console.log({mpUpPayment}); + if(mpUpPaymentSelectQueryError) { throw new Error(mpUpPaymentSelectQueryError.message); } + + const payTypeLinkId = await deep.id("${packageName}", "Pay"); + const payLink = mpUpPayment.find(link => link.type_id === payTypeLinkId); + console.log({payLink}); + if(!payLink) { throw new Error("The pay link associated with payment link " + paymentLink + " is not found.") } + + const confirm = ${confirm.toString()}; + + const storageReceiverLinkSelectQuery = await deep.select({ + id: paymentLink.to_id + }); + if(storageReceiverLinkSelectQuery.error) {throw new Error(storageReceiverLinkSelectQuery.error.message);} + const storageReceiverId = storageReceiverLinkSelectQuery.data[0].id; + console.log({storageReceiverId}); + + + const usesTokenTypeLinkId = await deep.id("${packageName}", "UsesToken"); + const usesTokenLinkSelectQuery = await deep.select({ + type_id: usesTokenTypeLinkId, + from_id: storageReceiverId, + }); + if(usesTokenLinkSelectQuery.error) {throw new Error(usesTokenLinkSelectQuery.error.message);} + const usesTokenLink = usesTokenLinkSelectQuery.data[0]; + console.log({usesTokenLink}); + + const tokenLinkSelectQuery = await deep.select({ + id: usesTokenLink.to_id, + }); + if(tokenLinkSelectQuery.error) {throw new Error(tokenLinkSelectQuery.error.message);} + const tokenLink = tokenLinkSelectQuery.data[0]; + console.log({tokenLink}); + + const confirmOptions = { + TerminalKey: tokenLink.value.value, + PaymentId: req.body.PaymentId, + Amount: req.body.Amount, + // Receipt: req.body.Receipt, + }; + console.log({confirmOptions}); + + const confirmResult = await confirm(confirmOptions); + console.log({confirmResult}); + + if (confirmResult.error) { + const errorMessage = "Could not confirm the pay. " + confirmResult.error; + const {error: errorLinkInsertError} = await deep.insert({ + type_id: (await deep.id("${packageName}", "Error")), + from_id: tinkoffProviderLinkId, + to_id: payLink.id, + string: { data: { value: errorMessage } }, + }); + if(errorLinkInsertError) { throw new Error(errorLinkInsertError); } + throw new Error(errorMessage); + } + + return confirmResult; + } else if (req.body.Status === 'CONFIRMED') { + ${onConfirmedCode} + } +}; +`; + +return await baseInsertNotificationHandler({packageId, adminId, containTypeLinkId, deep, fileTypeLinkId, handlerName: "tinkoffNotificationHandler", handleRouteTypeLinkId,handlerTypeLinkId,notificationPort,notificationRoute,portTypeLinkId,routerListeningTypeLinkId,routerStringUseTypeLinkId,routerTypeLinkId,routeTypeLinkId,supportsId, code}); +} + diff --git a/deep-packages/payments/tinkoff/insertTinkoffPayInsertHandler.cjs b/deep-packages/payments/tinkoff/insertTinkoffPayInsertHandler.cjs new file mode 100644 index 00000000..a598e3b0 --- /dev/null +++ b/deep-packages/payments/tinkoff/insertTinkoffPayInsertHandler.cjs @@ -0,0 +1,134 @@ +const { insertHandler } = require("../../insertHandler.cjs"); +const {handlersDependencies} = require("./handlersDependencies.cjs"); +const {init} = require("./init.cjs"); + +exports.insertTinkoffPayInsertHandler = async (param) => { + console.log({param}) + const {packageName, deep, notificationUrl, userEmail, userPhone, fileTypeLinkId, containTypeLinkId, packageId, dockerSupportsJsId, handleInsertTypeLinkId, handlerTypeLinkId, payTypeLinkId} = param; + const code = ` +async ({ deep, require, data: { newLink, triggeredByLinkId } }) => { + ${handlersDependencies} + + const tinkoffProviderTypeLinkId = await deep.id("${packageName}", "TinkoffProvider"); + const tinkoffProviderLinkSelectQuery = await deep.select({ + type_id: tinkoffProviderTypeLinkId + }); + if(tinkoffProviderLinkSelectQuery.error) {throw new Error(tinkoffProviderLinkSelectQuery.error.message);} + const tinkoffProviderLinkId = tinkoffProviderLinkSelectQuery.data[0].id; + + const {data: mpDownPay, error: mpDownPaySelectQueryError} = await deep.select({ + down: { + link_id: { _eq: newLink.id }, + tree_id: { _eq: await deep.id("${packageName}", "paymentTree") }, + }, + }); + console.log({mpDownPay}); + if(mpDownPaySelectQueryError) { throw new Error(mpDownPaySelectQueryError.message); } + + const paymentTypeLinkId = await deep.id("${packageName}", "Payment"); + const paymentLink = mpDownPay.find(link => link.type_id === paymentTypeLinkId); + console.log({paymentLink}); + if(!paymentLink) throw new Error("Payment link associated with the pay link " + newLink.id + " is not found."); + + const sumTypeLinkId = await deep.id("${packageName}", "Sum"); + const sumLink = mpDownPay.find(link => link.type_id === sumTypeLinkId); + console.log({sumLink}); + if(!sumLink) throw new Error("Sum link associated with the pay link " + newLink.id + " is not found."); + + const fromLinkOfPaymentSelectQuery = await deep.select({ + id: paymentLink.from_id + }); + if(fromLinkOfPaymentSelectQuery.error) { throw new Error(fromLinkOfPaymentSelectQuery.error.message); } + const fromLinkOfPayment = fromLinkOfPaymentSelectQuery.data[0]; + console.log({fromLinkOfPayment}); + + const storageBusinessLinkSelectQuery = await deep.select({ + id: paymentLink.to_id + }); + if(storageBusinessLinkSelectQuery.error) { throw new Error(storageBusinessLinkSelectQuery.error.message); } + const storageBusinessLinkId = storageBusinessLinkSelectQuery.data[0].id; + console.log({storageBusinessLinkId}); + + const usesTokenTypeLinkId = await deep.id("${packageName}", "UsesToken"); + const usesTokenLinkSelectQuery = await deep.select({ + type_id: usesTokenTypeLinkId, + from_id: storageBusinessLinkId, + }); + if(usesTokenLinkSelectQuery.error) {throw new Error(usesTokenLinkSelectQuery.error.message);} + const usesTokenLink = usesTokenLinkSelectQuery.data[0]; + console.log({usesTokenLink}); + + const tokenLinkSelectQuery = await deep.select({ + id: usesTokenLink.to_id, + }); + if(tokenLinkSelectQuery.error) {throw new Error(tokenLinkSelectQuery.error.message);} + const tokenLink = tokenLinkSelectQuery.data[0]; + console.log({tokenLink}); + + const init = ${init.toString()}; + + const options = { + TerminalKey: tokenLink.value.value, + OrderId: "" + Date.now() + paymentLink.id, + CustomerKey: triggeredByLinkId, + NotificationURL: "${notificationUrl}", + PayType: 'T', + Amount: sumLink.value.value, + Description: 'Test shopping', + Language: 'ru', + Recurrent: 'Y', + DATA: { + Email: "${userEmail}", + Phone: "${userPhone}", + }, + // Receipt: { + // Items: [{ + // Name: 'Test item', + // Price: sum, + // Quantity: 1, + // Amount: sumLink.value.value, + // PaymentMethod: 'prepayment', + // PaymentObject: 'service', + // Tax: 'none', + // }], + // Email: "${userEmail}", + // Phone: "${userPhone}", + // Taxation: 'usn_income', + // } + }; + console.log({options}); + + let initResult = await init(options); + console.log({initResult}); + if (initResult.error) { + const errorMessage = "Could not initialize the order. " + initResult.error; + const {error: errorLinkInsertQueryError} = await deep.insert({ + type_id: (await deep.id("${packageName}", "Error")), + from_id: tinkoffProviderLinkId, + to_id: newLink.id, + string: { data: { value: errorMessage } }, + }); + if(errorLinkInsertQueryError) { throw new Error(errorLinkInsertQueryError.message); } + throw new Error(errorMessage); + } + + const urlTypeLinkId = await deep.id("${packageName}", "Url"); + const {error: urlLinkInsertQueryError} = await deep.insert({ + type_id: urlTypeLinkId, + from_id: tinkoffProviderLinkId, + to_id: newLink.id, + string: { data: { value: initResult.response.PaymentURL } }, + }); + if(urlLinkInsertQueryError) { throw new Error(urlLinkInsertQueryError.message); } + + const paymentValueLinkInsertQuery = await deep.insert({link_id: paymentLink.id, value: {bankPaymentId: parseInt(initResult.response.PaymentId)}}, {table: "objects"}) + if(paymentValueLinkInsertQuery.error) { throw new Error(paymentValueLinkInsertQuery.error.message); } + console.log(JSON.stringify(paymentValueLinkInsertQuery)); + + return initResult; +}; +`; + +return await insertHandler({deep, fileTypeLinkId, fileName: 'payInsertHandlerFile', handlerName: 'payInsertHandler', handleName: 'payInsertHandle', triggerTypeLinkId: payTypeLinkId, code, supportsId: dockerSupportsJsId, handleOperationTypeLinkId: handleInsertTypeLinkId, containTypeLinkId, packageId, handlerTypeLinkId, code}); +} + diff --git a/deep-packages/payments/tinkoff/payInBrowser.cjs b/deep-packages/payments/tinkoff/payInBrowser.cjs new file mode 100644 index 00000000..ba782fe1 --- /dev/null +++ b/deep-packages/payments/tinkoff/payInBrowser.cjs @@ -0,0 +1,128 @@ +const {sleep} = require('./../../sleep.cjs'); +const promptSync = require('prompt-sync'); +const prompt = promptSync({ sigint: true }); + +const payInBrowser = async ({ page, browser, url }) => { + + + + // // Если можно удалить уже ранее добавленную карту + // await sleep(300); + // const removeCardIcon = await page.evaluate(() => { + // return !!document.querySelector( + // 'tui-svg[class="ng-star-inserted"]' + // ); + // }); + // if (removeCardIcon) { + // await page.click('tui-svg[class="ng-star-inserted"]'); + // } + + await page.goto(url, { waitUntil: 'networkidle2' }); + + await sleep(300); + await page.evaluate(() => { + const saveCardTextDiv = [...document.querySelectorAll("div.t-content")].find(element => element.innerText == "Сохранить карту "); + if(saveCardTextDiv) { + const saveCardInput = saveCardTextDiv.parentElement.querySelector("input"); + if(saveCardInput.checked) {saveCardInput.click()} + } + }); + + + await sleep(5000); + const oldForm = await page.evaluate(() => { + return !!document.querySelector( + 'input[automation-id="tui-input-card-grouped__card"]' + ); + }); + if (oldForm) { + console.log('OLD FORM!!!!!!!'); + + // Старая форма используется на тестовом сервере + const cvc1 = await page.evaluate(() => { + return !!document.querySelector( + 'button[automation-id="pay-card__submit"]' + ); + }); + if (cvc1) { + await page.waitForSelector( + 'input[automation-id="tui-input-card-grouped__card"]' + ); + await sleep(300); + await page.type( + 'input[automation-id="tui-input-card-grouped__card"]', + process.env.PAYMENTS_C2B_CARD_NUMBER_SUCCESS + ); // card number + await sleep(300); + await page.keyboard.press('Tab'); + await sleep(300); + await page.type( + 'input[automation-id="tui-input-card-grouped__expire"]', + process.env.PAYMENTS_C2B_CARD_EXPDATE + ); // expired date + await sleep(300); + await page.keyboard.press('Tab'); + await sleep(300); + await page.type( + 'input[automation-id="tui-input-card-grouped__cvc"]', + process.env.PAYMENTS_C2B_CARD_CVC + ); // CVC code + await sleep(300); + await page.click('button[automation-id="pay-card__submit"]'); // submit button + } else { + await page.waitForSelector( + 'input[automation-id="tui-input-card-grouped__card"]' + ); + await sleep(300); + await page.type( + 'input[automation-id="tui-input-card-grouped__card"]', + process.env.PAYMENTS_C2B_CARD_NUMBER_SUCCESS + ); // card number + await sleep(300); + await page.keyboard.press('Tab'); + await sleep(300); + await page.type( + 'input[automation-id="tui-input-card-grouped__expire"]', + process.env.PAYMENTS_C2B_CARD_EXPDATE + ); // expired date + await sleep(300); + await page.keyboard.press('Tab'); + await sleep(300); + await page.type( + 'input[automation-id="tui-input-card-grouped__cvc"]', + process.env.PAYMENTS_C2B_CARD_CVC + ); // CVC code + await sleep(300); + await page.click('button[automation-id="pay-wallet__submit"]'); // submit button + await sleep(300); + // const ifPasswordExist = await page.waitForSelector(() => { + // return !!document.querySelector( + // 'input[name="password"]' + // ); + // }); + // if (ifPasswordExist) { + await page.waitForSelector('input[name="password"]'); + const code = prompt('enter code '); + console.log('code', code); + await page.type('input[name="password"]', code); + await sleep(1000); + // } + } + // TODO: пока старая форма вызывалась только на тестовой карте, где ввод смс кода не нужен + await sleep(1000); + } else { + console.log('NEW FORM!!!!!!!'); + await page.type('#pan', process.env.PAYMENTS_C2B_CARD_NUMBER_SUCCESS); // card number + await page.type('#expDate', process.env.PAYMENTS_C2B_CARD_EXPDATE); // expired date + await page.type('#card_cvc', process.env.PAYMENTS_C2B_CARD_CVC); // CVC code + await page.click('button[type=submit]'); // submit button + await page.waitForSelector('input[name="password"]'); + const code = prompt('enter code '); + console.log('code', code); + await page.type('input[name="password"]', code); + await sleep(3000); + } + await browser.close(); +}; + + \ No newline at end of file diff --git a/payments-tinkoff-c2c.cjs b/payments-tinkoff-c2c.cjs new file mode 100644 index 00000000..9853886f --- /dev/null +++ b/payments-tinkoff-c2c.cjs @@ -0,0 +1,1440 @@ +require('react'); +require('graphql'); +require('lodash'); +require('subscriptions-transport-ws'); +const dotenv = require('dotenv'); +const dotenvExpand = require('dotenv-expand'); +const { generateApolloClient } = require('@deep-foundation/hasura/client'); +const { DeepClient } = require('@deep-foundation/deeplinks/imports/client'); +const { + minilinks, + Link, +} = require('@deep-foundation/deeplinks/imports/minilinks'); +const puppeteer = require('puppeteer'); +const crypto = require('crypto'); +const axios = require('axios'); +const uniqid = require('uniqid'); +const { expect } = require('chai'); +const { get } = require('lodash'); +const { + default: links, +} = require('@deep-foundation/deeplinks/imports/router/links'); +var myEnv = dotenv.config(); +dotenvExpand.expand(myEnv); +const promptSync = require('prompt-sync'); +const prompt = promptSync({ sigint: true }); +const { addCard } = require('./deep-packages/payments/tinkoff/addCard.cjs'); +const { addCardInBrowser } = require('./deep-packages/payments/tinkoff/addCardInBrowser.cjs'); +const {payInBrowser} = require("./deep-packages/payments/tinkoff/payInBrowser.cjs"); +const {getError} = require("./deep-packages/payments/tinkoff/getError.cjs"); +const { generateToken, generateTokenStringWithInsertedTerminalPassword } = require("./deep-packages/payments/tinkoff/generateToken.cjs"); +const { getUrl } = require("./deep-packages/payments/tinkoff/getUrl.cjs"); +const { getState } = require("./deep-packages/payments/tinkoff/getState.cjs"); +const { checkOrder } = require("./deep-packages/payments/tinkoff/checkOrder.cjs"); +const { getCardList } = require("./deep-packages/payments/tinkoff/getCardList.cjs"); +const { init } = require("./deep-packages/payments/tinkoff/init.cjs"); +const { charge } = require("./deep-packages/payments/tinkoff/charge.cjs"); +const { addCustomer } = require("./deep-packages/payments/tinkoff/addCustomer.cjs"); +const { getCustomer } = require("./deep-packages/payments/tinkoff/getCustomer.cjs"); +const { removeCustomer } = require("./deep-packages/payments/tinkoff/removeCustomer.cjs"); +const { handlersDependencies } = require("./deep-packages/payments/tinkoff/handlersDependencies.cjs"); +const { insertTinkoffPayInsertHandler } = require("./deep-packages/payments/tinkoff/insertTinkoffPayInsertHandler.cjs"); +const { insertTinkoffNotificationHandler } = require("./deep-packages/payments/tinkoff/insertTinkoffNotificationHandler.cjs"); +const {sleep} = require("./deep-packages/sleep.cjs"); +const {confirm} = require("./deep-packages/payments/tinkoff/confirm.cjs"); +const { _generateToken } = require('./deep-packages/payments/tinkoff/_generateToken.cjs'); +const getUrlC2CString = require("./deep-packages/payments/tinkoff/c2c/getUrl.cjs").getUrlString; +const initC2C = require("./deep-packages/payments/tinkoff/c2c/init.cjs").init; +const getErrorC2C = require("./deep-packages/payments/tinkoff/c2c/getError.cjs").getError; +const addCustomerC2C = require("./deep-packages/payments/tinkoff/c2c/addCustomer.cjs").addCustomer; +const addCardC2C = require("./deep-packages/payments/tinkoff/c2c/addCard.cjs").addCard; +const paymentC2C = require("./deep-packages/payments/tinkoff/c2c/payment.cjs").payment; +const generateTokenStringWithInsertedTerminalPasswordC2C = require("./deep-packages/payments/tinkoff/c2c/generateToken.cjs").generateTokenStringWithInsertedTerminalPassword; + +console.log('Installing payments-tinkoff-c2c package'); + +const requiredEnvVariableNames = [ +"PAYMENTS_C2B_TERMINAL_KEY", +"PAYMENTS_C2B_TERMINAL_PASSWORD", +"PAYMENTS_C2B_URL", +"PAYMENTS_C2B_NOTIFICATION_ROUTE", +"PAYMENTS_C2B_NOTIFICATION_PORT", +"PAYMENTS_C2B_NOTIFICATION_URL", +"PAYMENTS_C2B_CARD_NUMBER_SUCCESS", +"PAYMENTS_C2B_CARD_EXPDATE", +"PAYMENTS_C2B_CARD_CVC", +"PAYMENTS_C2B_PHONE_NUMBER", +"PAYMENTS_C2B_EMAIL", +]; + +for (const requiredEnvVariableName of requiredEnvVariableNames) { + if(!process.env[requiredEnvVariableName]) { + throw new Error(`The environment variable ${requiredEnvVariableName} is required. All the required environment variables: \n${requiredEnvVariableNames.join("\n")}`); + } +} + +const packageName = "@deep-foundation/payments-tinkoff-c2c"; + +const allCreatedLinkIds = []; + +const CUSTOMER_KEY = uniqid(); + +const installPackage = async () => { + const apolloClient = generateApolloClient({ + path: process.env.NEXT_PUBLIC_GQL_PATH || '', // <<= HERE PATH TO UPDATE + ssl: !!~process.env.NEXT_PUBLIC_GQL_PATH.indexOf('localhost') + ? false + : true, + // admin token in prealpha deep secret key + // token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwczovL2hhc3VyYS5pby9qd3QvY2xhaW1zIjp7IngtaGFzdXJhLWFsbG93ZWQtcm9sZXMiOlsibGluayJdLCJ4LWhhc3VyYS1kZWZhdWx0LXJvbGUiOiJsaW5rIiwieC1oYXN1cmEtdXNlci1pZCI6IjI2MiJ9LCJpYXQiOjE2NTYxMzYyMTl9.dmyWwtQu9GLdS7ClSLxcXgQiKxmaG-JPDjQVxRXOpxs', + }); + + const unloginedDeep = new DeepClient({ apolloClient }); + const guest = await unloginedDeep.guest(); + const guestDeep = new DeepClient({ deep: unloginedDeep, ...guest }); + const admin = await guestDeep.login({ + linkId: await guestDeep.id('deep', 'admin'), + }); + const adminDeep = new DeepClient({ deep: guestDeep, ...admin }); + await adminDeep.insert({ + type_id: deep.idLocal("@deep-foundation/core", "Join"), + from_id: guestDeep.linkId, + to_id: adminDeep.linkId + }) + const deep = guestDeep; + + try { + const User = await deep.id('@deep-foundation/core', 'User'); + const typeTypeId = await deep.id('@deep-foundation/core', 'Type'); + const anyTypeId = await deep.id('@deep-foundation/core', 'Any'); + const joinTypeId = await deep.id('@deep-foundation/core', 'Join'); + const containTypeId = await deep.id('@deep-foundation/core', 'Contain'); + const Value = await deep.id('@deep-foundation/core', 'Value'); + const String = await deep.id('@deep-foundation/core', 'String'); + const packageTypeId = await deep.id('@deep-foundation/core', 'Package'); + + + const syncTextFileTypeId = await deep.id('@deep-foundation/core', 'SyncTextFile'); + const dockerSupportsJs = await deep.id( + '@deep-foundation/core', + 'dockerSupportsJs' + ); + const handleInsertTypeId = await deep.id('@deep-foundation/core', 'HandleInsert'); + const portTypeId = await deep.id('@deep-foundation/core', 'Port'); + const routerListeningTypeId = await deep.id('@deep-foundation/core', 'RouterListening'); + const routerTypeId = await deep.id('@deep-foundation/core', 'Router'); + const routerStringUseTypeId = await deep.id( + '@deep-foundation/core', + 'RouterStringUse' + ); + const routeTypeId = await deep.id('@deep-foundation/core', 'Route'); + const handleRouteTypeId = await deep.id( + '@deep-foundation/core', + 'HandleRoute' + ); + const handlerTypeId = await deep.id( + '@deep-foundation/core', + 'Handler' + ); + const dockerSupportsJsId = await deep.id( + '@deep-foundation/core', + 'dockerSupportsJs' + ); + + const treeTypeId = await deep.id('@deep-foundation/core', 'Tree'); + const treeIncludeNodeTypeId = await deep.id( + '@deep-foundation/core', + 'TreeIncludeNode' + ); + const treeIncludeUpTypeId = await deep.id('@deep-foundation/core', 'TreeIncludeUp'); + const treeIncludeDownTypeId = await deep.id( + '@deep-foundation/core', + 'TreeIncludeDown' + ); + + const Rule = await deep.id('@deep-foundation/core', 'Rule'); + const RuleSubject = await deep.id('@deep-foundation/core', 'RuleSubject'); + const RuleObject = await deep.id('@deep-foundation/core', 'RuleObject'); + const RuleAction = await deep.id('@deep-foundation/core', 'RuleAction'); + const Selector = await deep.id('@deep-foundation/core', 'Selector'); + const SelectorInclude = await deep.id( + '@deep-foundation/core', + 'SelectorInclude' + ); + const SelectorExclude = await deep.id( + '@deep-foundation/core', + 'SelectorExclude' + ); + const SelectorTree = await deep.id('@deep-foundation/core', 'SelectorTree'); + const containTree = await deep.id('@deep-foundation/core', 'containTree'); + const AllowInsertType = await deep.id( + '@deep-foundation/core', + 'AllowInsertType' + ); + const AllowDeleteType = await deep.id( + '@deep-foundation/core', + 'AllowDeleteType' + ); + const SelectorFilter = await deep.id( + '@deep-foundation/core', + 'SelectorFilter' + ); + const Query = await deep.id('@deep-foundation/core', 'Query'); + const usersId = await deep.id('deep', 'users'); + + const BasePayment = await deep.id('@deep-foundation/payments', 'Payment'); + const BaseObject = await deep.id('@deep-foundation/payments', 'Object'); + const BaseSum = await deep.id('@deep-foundation/payments', 'Sum'); + const BasePay = await deep.id('@deep-foundation/payments', 'Pay'); + const BaseUrl = await deep.id('@deep-foundation/payments', 'Url'); + const BasePayed = await deep.id('@deep-foundation/payments', 'Payed'); + const BaseError = await deep.id('@deep-foundation/payments', 'Error'); + const Storage = await deep.id('@deep-foundation/payments', 'Storage'); + + const { + data: [{ id: packageId }], + } = await deep.insert({ + type_id: packageTypeId, + string: { data: { value: packageName } }, + in: { + data: [ + { + type_id: containTypeId, + from_id: deep.linkId, + }, + ], + }, + out: { + data: [ + { + type_id: joinTypeId, + to_id: await deep.id('deep', 'users', 'packages'), + }, + { + type_id: joinTypeId, + to_id: await deep.id('deep', 'admin'), + }, + ], + }, + }); + + console.log({ packageId }); + + const { + data: [{ id: sumProviderTypeId }], + } = await deep.insert({ + type_id: typeTypeId, + from_id: anyTypeId, + to_id: anyTypeId, + in: { + data: { + type_id: containTypeId, + from_id: packageId, + string: { data: { value: 'SumProvider' } }, + }, + }, + }); + + console.log({ sumProviderTypeId }); + + const { + data: [{ id: tinkoffProviderTypeId }], + } = await deep.insert({ + type_id: typeTypeId, + from_id: anyTypeId, + to_id: anyTypeId, + in: { + data: { + type_id: containTypeId, + from_id: packageId, + string: { data: { value: 'TinkoffProvider' } }, + }, + }, + }); + + console.log({ tinkoffProviderTypeId }); + + const { + data: [{ id: paymentTypeId }], + } = await deep.insert({ + type_id: typeTypeId, + from_id: anyTypeId, + to_id: anyTypeId, + in: { + data: { + type_id: containTypeId, + from_id: packageId, + string: { data: { value: 'Payment' } }, + }, + }, + }); + + console.log({ paymentTypeId }); + + const { + data: [{ id: objectTypeId }], + } = await deep.insert({ + type_id: typeTypeId, + from_id: paymentTypeId, + to_id: anyTypeId, + in: { + data: { + type_id: containTypeId, + from_id: packageId, + string: { data: { value: 'Object' } }, + }, + }, + }); + + console.log({ objectTypeId }); + + const { + data: [{ id: sumTypeId }], + } = await deep.insert({ + type_id: typeTypeId, + from_id: anyTypeId, + to_id: anyTypeId, + in: { + data: { + type_id: containTypeId, + from_id: packageId, // before created package + string: { data: { value: 'Sum' } }, + }, + }, + }); + + console.log({ sumTypeId }); + + // TODO Rest restrictions + const { + data: [{ id: payTypeId }], + } = await deep.insert({ + type_id: typeTypeId, + from_id: anyTypeId, + to_id: anyTypeId, + in: { + data: { + type_id: containTypeId, + from_id: packageId, // before created package + string: { data: { value: 'Pay' } }, + }, + }, + }); + + console.log({ payTypeId }); + + const { + data: [{ id: urlTypeId }], + } = await deep.insert({ + type_id: typeTypeId, + from_id: anyTypeId, + to_id: anyTypeId, + in: { + data: { + type_id: containTypeId, + from_id: packageId, // before created package + string: { data: { value: 'Url' } }, + }, + }, + }); + + console.log({ urlTypeId }); + + const { + data: [{ id: payedTypeId }], + } = await deep.insert({ + type_id: typeTypeId, + from_id: anyTypeId, + to_id: anyTypeId, + in: { + data: { + type_id: containTypeId, + from_id: packageId, // before created package + string: { data: { value: 'Payed' } }, + }, + }, + }); + + console.log({ payedTypeId }); + + const { + data: [{ id: errorTypeId }], + } = await deep.insert({ + type_id: typeTypeId, + from_id: anyTypeId, + to_id: anyTypeId, + in: { + data: { + type_id: containTypeId, + from_id: packageId, // before created package + string: { data: { value: 'Error' } }, + }, + }, + }); + + console.log({ errorTypeId }); + + const { + data: [{ id: paymentTreeId }], + } = await deep.insert({ + type_id: treeTypeId, + in: { + data: { + type_id: containTypeId, + from_id: packageId, + string: { data: { value: 'paymentTree' } }, + }, + }, + out: { + data: [ + { + type_id: treeIncludeNodeTypeId, + to_id: paymentTypeId, + in: { + data: [ + { + type_id: containTypeId, + from_id: deep.linkId, + }, + ], + }, + }, + { + type_id: treeIncludeUpTypeId, + to_id: sumTypeId, + in: { + data: [ + { + type_id: containTypeId, + from_id: deep.linkId, + }, + ], + }, + }, + { + type_id: treeIncludeDownTypeId, + to_id: objectTypeId, + in: { + data: [ + { + type_id: containTypeId, + from_id: deep.linkId, + }, + ], + }, + }, + { + type_id: treeIncludeUpTypeId, + to_id: errorTypeId, + in: { + data: [ + { + type_id: containTypeId, + from_id: deep.linkId, + }, + ], + }, + }, + { + type_id: treeIncludeUpTypeId, + to_id: payedTypeId, + in: { + data: [ + { + type_id: containTypeId, + from_id: deep.linkId, + }, + ], + }, + }, + { + type_id: treeIncludeUpTypeId, + to_id: payTypeId, + in: { + data: [ + { + type_id: containTypeId, + from_id: deep.linkId, + }, + ], + }, + }, + { + type_id: treeIncludeUpTypeId, + to_id: urlTypeId, + in: { + data: [ + { + type_id: containTypeId, + from_id: deep.linkId, + }, + ], + }, + }, + ], + }, + }); + + const { + data: [{ id: tokenTypeId }], + } = await deep.insert({ + type_id: typeTypeId, + from_id: anyTypeId, + to_id: anyTypeId, + in: { + data: { + type_id: containTypeId, + from_id: packageId, // before created package + string: { data: { value: 'Token' } }, + }, + }, + }); + console.log({tokenTypeId}); + + const { + data: [{ id: C2CtokenTypeId }], + } = await deep.insert({ + type_id: typeTypeId, + from_id: anyTypeId, + to_id: anyTypeId, + in: { + data: { + type_id: containTypeId, + from_id: packageId, // before created package + string: { data: { value: 'C2CToken' } }, + }, + }, + }); + console.log({C2CtokenTypeId}); + + + const { + data: [{ id: storageClientTypeId }], + } = await deep.insert({ + type_id: typeTypeId, + from_id: anyTypeId, + to_id: anyTypeId, + in: { + data: { + type_id: containTypeId, + from_id: packageId, // before created package + string: { data: { value: 'StorageClient' } }, + }, + }, + }); + console.log({storageClientTypeId}); + + const { + data: [{ id: titleTypeId }], + } = await deep.insert({ + type_id: typeTypeId, + from_id: anyTypeId, + to_id: anyTypeId, + in: { + data: { + type_id: containTypeId, + from_id: packageId, // before created package + string: { data: { value: 'Title' } }, + }, + }, + }); + console.log({ titleTypeId }); + + const { + data: [{ id: incomeTypeId }], + } = await deep.insert({ + type_id: typeTypeId, + from_id: anyTypeId, + to_id: anyTypeId, + in: { + data: { + type_id: containTypeId, + from_id: packageId, // before created package + string: { data: { value: 'Income' } }, + }, + }, + }); + console.log({ incomeTypeId }); + debugger; + + await insertTinkoffPayInsertHandler({packageName,deep, containTypeId, fileTypeLinkId: syncTextFileTypeId, handleInsertTypeId, handlerTypeId, notificationUrl: process.env.PAYMENTS_C2B_NOTIFICATION_URL, packageId, supportsId: dockerSupportsJs, userEmail: process.env.PAYMENTS_C2B_EMAIL, userPhone: process.env.PAYMENTS_C2B_PHONE_NUMBER, dockerSupportsJsId, payTypeId, handleInsertTypeLinkId: handleInsertTypeId, containTypeLinkId: containTypeId, handlerTypeLinkId: handlerTypeId, payTypeLinkId: payTypeId, }); + + const tinkoffNotificationOnConfirmedCode = ` +const TinkoffProvider = await deep.id("${packageName}", "TinkoffProvider"); +const tinkoffProviderLinkSelectQuery = await deep.select({ + type_id: TinkoffProvider +}); +if (tinkoffProviderLinkSelectQuery.error) { throw new Error(tinkoffProviderLinkSelectQuery.error.message); } +const tinkoffProviderId = tinkoffProviderLinkSelectQuery.data[0].id; +console.log({ tinkoffProviderId }); + +const paymentLinkSelectQuery = await deep.select({ + object: { value: { _contains: { orderId: req.body.OrderId } } } +}); +if (paymentLinkSelectQuery.error) { throw new Error(paymentLinkSelectQuery.error.message); } +const paymentLink = paymentLinkSelectQuery.data[0]; +console.log({ paymentLink }); +if (!paymentLink) { throw new Error("The payment link associated with the order id " + req.body.OrderId + " is not found."); } + +const { data: mpUpPayment, error: mpUpPaymentSelectQueryError } = await deep.select({ + up: { + parent_id: { _eq: paymentLink.id }, + tree_id: { _eq: await deep.id("${packageName}", "paymentTree") } + } +}); +console.log({ mpUpPayment }); +if (mpUpPaymentSelectQueryError) { throw new Error(mpUpPaymentSelectQueryError.message); } + +const Pay = await deep.id("${packageName}", "Pay"); +const payLink = mpUpPayment.find(link => link.type_id === Pay); +console.log({ payLink }); +if (!payLink) { throw new Error("The pay link associated with payment link " + paymentLink + " is not found.") } + +const storageReceiverLinkSelectQuery = await deep.select({ + id: paymentLink.to_id +}); +if (storageReceiverLinkSelectQuery.error) { throw new Error(storageReceiverLinkSelectQuery.error.message); } +const storageReceiverLink = storageReceiverLinkSelectQuery.data[0]; +console.log({ storageReceiverLink }); + +const Token = await deep.id("${packageName}", "Token"); +const tokenLinkSelectQuery = await deep.select({ + type_id: Token, + from_id: storageReceiverLink.id, + to_id: storageReceiverLink.id +}); +if (tokenLinkSelectQuery.error) { throw new Error(tokenLinkSelectQuery.error.message); } +const tokenLink = tokenLinkSelectQuery.data[0]; +console.log({ tokenLink }); + +const storageReceiverSelectQuery = await deep.select({ + id: paymentLink.to_id +}); +if (storageReceiverSelectQuery.error) { throw new Error(storageReceiverSelectQuery.error.message); } +const storageReceiver = storageReceiverSelectQuery.data[0]; +console.log({ storageReceiver }); +if (!storageReceiver) { throw new Error("The storage receiver link associated with the order id " + req.body.OrderId + " is not found."); } + +const sumLinkSelectQuery = await deep.select({ + type_id: await deep.id("${packageName}", "Sum"), + to_id: paymentLink.id +}); +if (sumLinkSelectQuery.error) { throw new Error(sumLinkSelectQuery.error.message); } +const sumLink = sumLinkSelectQuery.data[0]; +console.log({ sumLink }); +if (!sumLink) { throw new Error("The sum link associated with the order id " + req.body.OrderId + " is not found."); } + +const _generateToken = ${ _generateToken.toString()}; +const generateToken = ${ generateTokenStringWithInsertedTerminalPasswordC2C.toString()}; +const getUrl = ${ getUrlC2CString }; +const getError = ${ getErrorC2C.toString()}; + +const C2CToken = await deep.id("${packageName}", "C2CToken"); +const C2CTokenLinkSelectQuery = await deep.select({ + type_id: C2CToken, + from_id: storageReceiverLink.id, + to_id: storageReceiverLink.id +}); +if (C2CTokenLinkSelectQuery.error) { throw new Error(C2CTokenLinkSelectQuery.error.message); } +const C2CTokenLink = C2CTokenLinkSelectQuery.data[0]; +console.log({ C2CTokenLink }); + +const initOptions = { + TerminalKey: C2CTokenLink.value.value, + OrderId: req.body.OrderId, + CardId: storageReceiver.value.value, + Amount: sumLink.value.value, +}; +console.log({ initOptions }); + +const init = ${ initC2C.toString()}; +const initResult = await init(initOptions); +console.log({ initResult }); +if (initResult.error) { + const errorMessage = initResult.error; + const { error: errorLinkInsertQueryError } = await deep.insert({ + type_id: (await deep.id("${packageName}", "Error")), + from_id: tinkoffProviderId, + to_id: payLink.id, + string: { data: { value: errorMessage } }, + }); + if (errorLinkInsertQueryError) { throw new Error(errorLinkInsertQueryError.message); } + throw new Error(errorMessage); +} + +const paymentOptions = { + TerminalKey: C2CTokenLink.value.value, + PaymentId: initResult.response.PaymentId, +} + +const payment = ${ paymentC2C.toString()}; +const paymentResult = await payment(paymentOptions); +console.log({ paymentResult }); +if (paymentResult.error) { + const errorMessage = "Could not initialize the order. " + paymentResult.error; + const { error: errorLinkInsertQueryError } = await deep.insert({ + type_id: (await deep.id("${packageName}", "Error")), + from_id: tinkoffProviderId, + to_id: payLink.id, + string: { data: { value: errorMessage } }, + }); + if (errorLinkInsertQueryError) { throw new Error(errorLinkInsertQueryError.message); } + throw new Error(errorMessage); +} + +const payedLinkInsertQuery = await deep.insert({ + type_id: await deep.id("${packageName}", "Payed"), + from_id: tinkoffProviderId, + to_id: payLink.id, +}); + +if (payedLinkInsertQuery.error) { throw new Error(payedLinkInsertQuery.error.message); } +const payedLinkId = payedLinkInsertQuery.data[0].id; +console.log({ payedLinkId }); + +const StorageClient = await deep.id("${packageName}", "StorageClient"); +const storagePayerLinkSelectQuery = await deep.select({ + type_id: StorageClient, + number: { value: req.body.CardId } +}); +if (storagePayerLinkSelectQuery.error) { throw new Error(storagePayerLinkSelectQuery.error.message); } +let storagePayerLinkId = storagePayerLinkSelectQuery.data[0]; +console.log({ storagePayerLinkId }); +if (!storagePayerLinkId) { + const storagePayerLinkInsertQuery = await deep.insert({ + type_id: StorageClient, + number: { data: { value: req.body.CardId } } + }); + if (storagePayerLinkInsertQuery.error) { throw new Error(storagePayerLinkInsertQuery.error.message); } + storagePayerLinkId = storagePayerLinkInsertQuery.data[0].id; + console.log({ storagePayerLinkId }); +} + +const Income = await deep.id("${packageName}", "Income"); +const incomeLinkInsertQuery = await deep.insert({ + type_id: Income, + from_id: paymentLink.id, + to_id: storagePayerLinkId, +}); +if (incomeLinkInsertQuery.error) { throw new Error(incomeLinkInsertQuery.error.message); } +const incomeLinkId = incomeLinkInsertQuery.data[0].id; +console.log({ incomeLinkId }); + `; + + await insertTinkoffNotificationHandler({packageName,packageId,deep, adminId: await deep.id('deep', 'admin'), containTypeId, fileTypeId: syncTextFileTypeId, handleRouteTypeId, handlerTypeId, notificationPort: process.env.PAYMENTS_C2B_NOTIFICATION_PORT, notificationRoute: process.env.PAYMENTS_C2B_NOTIFICATION_ROUTE, portTypeId, routerListeningTypeId, routerStringUseTypeId, routerTypeId, routeTypeId, supportsId: dockerSupportsJsId, onConfirmedCode: tinkoffNotificationOnConfirmedCode, fileTypeLinkId: syncTextFileTypeId, handleRouteTypeLinkId: handleRouteTypeId, handlerTypeLinkId: handlerTypeId, portTypeLinkId: portTypeId, routerListeningTypeLinkId:routerListeningTypeId, routerStringUseTypeLinkId: routerStringUseTypeId, routerTypeLinkId: routerTypeId, routeTypeLinkId:routeTypeId, containTypeLinkId: containTypeId}); + + const callTests = async () => { + console.log('callTests-start'); + + const PRICE = 3000; + + const callRealizationTests = async () => { + const testInit = async () => { + const initOptions = { + TerminalKey: process.env.PAYMENTS_C2B_TERMINAL_KEY, + OrderId: uniqid(), + Amount: PRICE, + Description: 'Test shopping', + CustomerKey: deep.linkId, + Language: 'ru', + Recurrent: 'Y', + DATA: { + Email: process.env.PAYMENTS_C2B_EMAIL, + Phone: process.env.PAYMENTS_C2B_PHONE_NUMBER, + }, + // Receipt: { + // Items: [{ + // Name: 'Test item', + // Price: PRICE, + // Quantity: 1, + // Amount: PRICE, + // PaymentMethod: 'prepayment', + // PaymentObject: 'service', + // Tax: 'none', + // }], + // Email: process.env.PAYMENTS_C2B_EMAIL, + // Phone: process.env.PAYMENTS_C2B_PHONE_NUMBER, + // Taxation: 'usn_income', + // }, + }; + + const initResult = await init(initOptions); + + expect(initResult.error).to.equal(undefined); + + return initResult; + }; + + const testConfirm = async () => { + const browser = await puppeteer.launch({ args: ['--no-sandbox'] }); + const page = await browser.newPage(); + + const initOptions = { + TerminalKey: process.env.PAYMENTS_C2B_TERMINAL_KEY, + Amount: PRICE, + OrderId: uniqid(), + CustomerKey: deep.linkId, + PayType: 'T', + // Receipt: { + // Items: [{ + // Name: 'Test item', + // Price: PRICE, + // Quantity: 1, + // Amount: PRICE, + // PaymentMethod: 'prepayment', + // PaymentObject: 'service', + // Tax: 'none', + // }], + // Email: process.env.PAYMENTS_C2B_EMAIL, + // Phone: process.env.PAYMENTS_C2B_PHONE_NUMBER, + // Taxation: 'usn_income', + // }, + }; + + const initResult = await init(initOptions); + + await payInBrowser({ + browser, + page, + url: initResult.response.PaymentURL, + }); + + const confirmOptions = { + TerminalKey: process.env.PAYMENTS_C2B_TERMINAL_KEY, + PaymentId: initResult.response.PaymentId, + }; + + const confirmResult = await confirm(confirmOptions); + + expect(confirmResult.error).to.equal(undefined); + expect(confirmResult.response.Status).to.equal('CONFIRMED'); + + return confirmResult; + }; + + const testGetState = async () => { + const initResult = await init({ + TerminalKey: process.env.PAYMENTS_C2B_TERMINAL_KEY, + OrderId: uniqid(), + CustomerKey: deep.linkId, + Amount: PRICE, + }); + + const browser = await puppeteer.launch({ args: ['--no-sandbox'] }); + const page = await browser.newPage(); + await payInBrowser({ + browser, + page, + url: initResult.response.PaymentURL, + }); + + const getStateOptions = { + TerminalKey: process.env.PAYMENTS_C2B_TERMINAL_KEY, + PaymentId: initResult.response.PaymentId, + }; + + const getStateResult = await getState(getStateOptions); + + expect(getStateResult.error).to.equal(undefined); + }; + + const testGetCardList = async () => { + const initResult = await init({ + TerminalKey: process.env.PAYMENTS_C2B_TERMINAL_KEY, + CustomerKey: deep.linkId, + OrderId: uniqid(), + Amount: PRICE, + Recurrent: 'Y', + }); + + const browser = await puppeteer.launch({ args: ['--no-sandbox'] }); + const page = await browser.newPage(); + await payInBrowser({ + browser, + page, + url: initResult.response.PaymentURL, + }); + + const getCardListOptions = { + TerminalKey: process.env.PAYMENTS_C2B_TERMINAL_KEY, + CustomerKey: deep.linkId, + }; + + const getCardListResult = await getCardList(getCardListOptions); + + expect(getCardListResult.error).to.equal(undefined); + }; + + const testResend = async () => { + console.log('testResend-start'); + const resendOptions = { + TerminalKey: process.env.PAYMENTS_C2B_TERMINAL_KEY, + }; + console.log({ resendOptions }); + + const resendResult = await resend(resendOptions); + console.log({ resendResult }); + + expect(resendResult.error).to.equal(undefined); + console.log('testResend-end'); + }; + + const testCharge = async () => { + console.log('testCharge-start'); + const browser = await puppeteer.launch({ args: ['--no-sandbox'] }); + const page = await browser.newPage(); + + const initResult = await init({ + TerminalKey: process.env.PAYMENTS_C2B_TERMINAL_KEY, + Amount: PRICE, + OrderId: uniqid(), + CustomerKey: deep.linkId, + Recurrent: 'Y', + }); + + await payInBrowser({ + browser, + page, + url: initResult.response.PaymentURL, + }); + + const getCardListOptions = { + TerminalKey: process.env.PAYMENTS_C2B_TERMINAL_KEY, + CustomerKey: deep.linkId, + }; + + const getCardListResult = await getCardList(getCardListOptions); + + expect(getCardListResult.response[0].RebillId).to.have.length.above(0); + + const getStateOptions = { + TerminalKey: process.env.PAYMENTS_C2B_TERMINAL_KEY, + PaymentId: initResult.response.PaymentId, + }; + + const getStateResult = await getState(getStateOptions); + + expect(getStateResult.response.Status).to.equal('AUTHORIZED'); + + const newInitResult = await init({ + TerminalKey: process.env.PAYMENTS_C2B_TERMINAL_KEY, + Amount: PRICE, + OrderId: uniqid(), + CustomerKey: deep.linkId, + }); + + const newChargeOptions = { + TerminalKey: process.env.PAYMENTS_C2B_TERMINAL_KEY, + PaymentId: newInitResult.response.PaymentId, + RebillId: Number(getCardListResult.response[0].RebillId), + }; + + const chargeResult = await charge(newChargeOptions); + + expect(chargeResult.error).to.equal(undefined); + console.log('testCharge-end'); + }; + + const testAddCustomer = async () => { + console.log('testAddCustomer-start'); + + const addCustomerOptions = { + TerminalKey: process.env.PAYMENTS_C2B_TERMINAL_KEY, + CustomerKey: uniqid(), + }; + console.log({ addCustomerOptions }); + + const addCustomerResult = await addCustomer(addCustomerOptions); + console.log({ addCustomerResult }); + + expect(addCustomerResult.error).to.equal(undefined); + console.log('testAddCustomer-end'); + }; + + const testGetCustomer = async () => { + console.log('testGetCustomer-start'); + + const customerOptions = { + TerminalKey: process.env.PAYMENTS_C2B_TERMINAL_KEY, + CustomerKey: uniqid(), + }; + + const addCustomerDataOptions = { + ...customerOptions, + Phone: process.env.PAYMENTS_C2B_PHONE_NUMBER, + }; + + const addResult = await addCustomer(addCustomerDataOptions); + + expect(addResult.error).to.equal(undefined); + + const getResult = await getCustomer(customerOptions); + + expect(getResult.error).to.equal(undefined); + expect(getResult.response.Phone).to.equal( + process.env.PAYMENTS_C2B_PHONE_NUMBER + ); + + console.log('testGetCustomer-end'); + }; + + const testRemoveCustomer = async () => { + console.log('testRemoveCustomer-start'); + + const removeCustomerData = { + TerminalKey: process.env.PAYMENTS_C2B_TERMINAL_KEY, + CustomerKey: uniqid(), + }; + + const newAddCustomerData = { + ...removeCustomerData, + Phone: process.env.PAYMENTS_C2B_PHONE_NUMBER, + }; + + const addResult = await addCustomer(newAddCustomerData); + + expect(addResult.error).to.equal(undefined); + + const removeResult = await removeCustomer(removeCustomerData); + + expect(removeResult.error).to.equal(undefined); + + console.log('testRemoveCustomer-end'); + }; + + await testInit(); + await testConfirm(); + await testGetState(); + await testGetCardList(); + await testResend(); + await testCharge(); + await testAddCustomer(); + await testGetCustomer(); + await testRemoveCustomer(); + }; + + const callIntegrationTests = async () => { + + const createdLinkIds = []; + + const { + data: [{ id: tinkoffProviderLinkId }], + } = await deep.insert({ + type_id: tinkoffProviderTypeId, + in: { + data: [ + { + type_id: containTypeId, + from_id: deep.linkId, + }, + ], + }, + }); + console.log({ tinkoffProviderLinkId }); + createdLinkIds.push(tinkoffProviderLinkId); + allCreatedLinkIds.push(tinkoffProviderLinkId); + + const { + data: [{ id: sumProviderLinkId }], + } = await deep.insert({ + type_id: sumProviderTypeId, + in: { + data: [ + { + type_id: containTypeId, + from_id: deep.linkId, + }, + ], + }, + }); + console.log({ sumProviderLinkId }); + createdLinkIds.push(sumProviderLinkId); + allCreatedLinkIds.push(sumProviderLinkId); + + const addCustomerResult = await addCustomerC2C({ + TerminalKey: process.env.PAYMENTS_C2C_TERMINAL_KEY, + CustomerKey: CUSTOMER_KEY, + }); + + console.log({addCustomerResult}); + + const addCardResult = await addCardC2C({ + TerminalKey: process.env.PAYMENTS_C2C_TERMINAL_KEY, + CustomerKey: CUSTOMER_KEY, + }); + + console.log({addCardResult}); + + const browser = await puppeteer.launch({ args: [],headless: true }); + const page = await browser.newPage(); + await addCardInBrowser({browser, page, url: addCardResult.response.PaymentURL}); + + const getCardListOptions = { + TerminalKey: process.env.PAYMENTS_C2C_TERMINAL_KEY, + CustomerKey: CUSTOMER_KEY, + } + const getCardListResult = await getCardList(getCardListOptions); + const getCardListResultResponse = getCardListResult.response; + console.log({getCardListResultResponse}); + + const { + data: [{ id: storageReceiverLinkId }], + } = await deep.insert({ + type_id: storageClientTypeId, + number: {data: {value: getCardListResult.response[0].CardId}}, + in: { + data: [ + { + type_id: containTypeId, + from_id: deep.linkId, + }, + ], + }, + }); + console.log({ storageReceiverLinkId }); + createdLinkIds.push(storageReceiverLinkId); + allCreatedLinkIds.push(storageReceiverLinkId); + + const { + data: [{ id: tokenLinkId }], + } = await deep.insert({ + type_id: tokenTypeId, + from_id: storageReceiverLinkId, + to_id: storageReceiverLinkId, + string: { data: { value: process.env.PAYMENTS_C2B_TERMINAL_KEY } }, + in: { + data: [ + { + type_id: containTypeId, + from_id: deep.linkId, + }, + ], + }, + }); + console.log({ tokenLinkId }); + createdLinkIds.push(tokenLinkId); + allCreatedLinkIds.push(tokenLinkId); + + const { + data: [{ id: C2CtokenLinkId }], + } = await deep.insert({ + type_id: C2CtokenTypeId, + from_id: storageReceiverLinkId, + to_id: storageReceiverLinkId, + string: { data: { value: process.env.PAYMENTS_C2C_TERMINAL_KEY } }, + in: { + data: [ + { + type_id: containTypeId, + from_id: deep.linkId, + }, + ], + }, + }); + console.log({ C2CtokenLinkId }); + createdLinkIds.push(C2CtokenLinkId); + allCreatedLinkIds.push(C2CtokenLinkId); + + const { + data: [{ id: Product }], + } = await deep.insert({ + type_id: typeTypeId, + from_id: anyTypeId, + to_id: anyTypeId, + in: { + data: [ + { + type_id: containTypeId, + from_id: deep.linkId, + }, + ], + }, + }); + console.log({ Product }); + createdLinkIds.push(Product); + allCreatedLinkIds.push(Product); + + const { + data: [{ id: productLinkId }], + } = await deep.insert({ + type_id: Product, + in: { + data: [ + { + type_id: containTypeId, + from_id: deep.linkId, + }, + ], + }, + }); + console.log({ productLinkId }); + createdLinkIds.push(productLinkId); + allCreatedLinkIds.push(productLinkId); + + const testInit = async ({ customerKey } = { customerKey: CUSTOMER_KEY }) => { + console.log('testInit-start'); + + const createdLinkIds = []; + + const { + data: [{ id: paymentLinkId }], + } = await deep.insert({ + type_id: paymentTypeId, + object: { data: { value: { orderId: uniqid() } } }, + from_id: deep.linkId, + to_id: storageReceiverLinkId, + in: { + data: [ + { + type_id: containTypeId, + from_id: deep.linkId, + }, + ], + }, + }); + console.log({ paymentLinkId }); + createdLinkIds.push(paymentLinkId); + allCreatedLinkIds.push(paymentLinkId); + + const { + data: [{ id: sumLinkId }], + } = await deep.insert({ + type_id: sumTypeId, + from_id: sumProviderLinkId, + to_id: paymentLinkId, + number: { data: { value: PRICE } }, + in: { + data: [ + { + type_id: containTypeId, + from_id: deep.linkId, + }, + ], + }, + }); + console.log({ sumLinkId }); + createdLinkIds.push(sumLinkId); + allCreatedLinkIds.push(sumLinkId); + + const { + data: [{ id: objectLinkId }], + } = await deep.insert({ + type_id: objectTypeId, + from_id: paymentLinkId, + to_id: productLinkId, + in: { + data: [ + { + type_id: containTypeId, + from_id: deep.linkId, + }, + ], + }, + }); + console.log({ objectLinkId }); + createdLinkIds.push(objectLinkId); + allCreatedLinkIds.push(objectLinkId); + + const { + data: [{ id: payLinkId }], + } = await deep.insert({ + type_id: payTypeId, + from_id: deep.linkId, + to_id: sumLinkId, + in: { + data: [ + { + type_id: containTypeId, + from_id: deep.linkId, + }, + ], + }, + }); + console.log({ payLinkId }); + createdLinkIds.push(payLinkId); + allCreatedLinkIds.push(payLinkId); + + var urlLinkSelectQuery; + for (let i = 0; i < 10; i++) { + urlLinkSelectQuery = await deep.select({ + type_id: urlTypeId, + to_id: payLinkId, + }); + + if (urlLinkSelectQuery.data.length > 0) { + break; + } + + await sleep(1000); + } + + expect(urlLinkSelectQuery.data.length).to.greaterThan(0); + + createdLinkIds.push(urlLinkSelectQuery.data[0].id); + allCreatedLinkIds.push(urlLinkSelectQuery.data[0].id); + + const createdLinks = (await deep.select(createdLinkIds)).data; + console.log({ createdLinks }); + + console.log('testInit-end'); + + return { + createdLinks + } + }; + + const testFinishAuthorize = async ({ customerKey } = { customerKey: CUSTOMER_KEY }) => { + console.log('testFinishAuthorize-start'); + const { createdLinks } = await testInit({ customerKey }); + + const urlLink = createdLinks.find(link => link.type_id === urlTypeId); + expect(urlLink).to.not.be.equal(undefined) + + const url = urlLink.value.value; + console.log({ url }); + + const browser = await puppeteer.launch({ args: ['--no-sandbox'] }); + const page = await browser.newPage(); + await payInBrowser({ + browser, + page, + url, + }); + + console.log({ createdLinks }); + + console.log('testFinishAuthorize-end'); + + return { + createdLinks + } + }; + + const testConfirm = async ({ customerKey } = { customerKey: CUSTOMER_KEY }) => { + console.log('testConfirm-start'); + const { createdLinks } = await testFinishAuthorize({ customerKey }); + + const createdLinkIds = []; + + const payLink = createdLinks.find(link => link.type_id === payTypeId); + expect(payLink).to.not.be.equal(undefined); + + var payedLinkSelectQuery; + for (let i = 0; i < 10; i++) { + payedLinkSelectQuery = await deep.select({ + type_id: payedTypeId, + to_id: payLink.id + }); + + if (payedLinkSelectQuery.data.length > 0) { + break; + } + + await sleep(1000); + } + + expect(payedLinkSelectQuery.data.length).to.greaterThan(0); + + createdLinkIds.push(payedLinkSelectQuery.data[0].id); + allCreatedLinkIds.push(payedLinkSelectQuery.data[0].id); + + createdLinks.push(...(await deep.select(createdLinkIds)).data); + + console.log({ createdLinks }); + + console.log('testConfirm-end'); + + return { + createdLinks + } + }; + + /* + const testGetState = async () => { + console.log('testGetState-start'); + await testFinishAuthorize(); + + const { + data: [payLink], + } = await deep.select({ type_id: Pay }); + + const bankPaymentId = await getBankPaymentId( + payLink?.value?.value ?? payLink.id + ); + + const getStateOptions = { + TerminalKey: process.env.PAYMENTS_C2B_TERMINAL_KEY, + PaymentId: bankPaymentId, + }; + + const getStateResult = await getState(getStateOptions); + + expect(getStateResult.error).to.equal(undefined); + console.log('testGetState-end'); + }; + + const testGetCardList = async () => { + console.log('testGetCardList-end'); + await testFinishAuthorize(); + + const getCardListOptions = { + TerminalKey: process.env.PAYMENTS_C2B_TERMINAL_KEY, + CustomerKey: deep.linkId, + }; + + const getCardListResult = await getCardList(getCardListOptions); + + expect(getCardListResult.error).to.equal(undefined); + console.log('testGetCardList-end'); + }; + */ + + const callTest = async (testFunction) => { + const { createdLinks } = await testFunction(); + for (const createdLink of createdLinks) { + if(createdLink.type_id === payTypeId) { + const errorLinkSelectQuery = await deep.select({ + type_id: errorTypeId, + to_id: createdLink.id + }); + createdLinks.push(...errorLinkSelectQuery.data); + } + } + await deep.delete(createdLinks.map((link) => link.id)); + } + + await callTest(testInit); + // await callTest(testFinishAuthorize); + await callTest(testConfirm); + + await deep.delete(createdLinkIds); + + /*await testGetState(); + await testGetCardList();*/ + }; + + // await callRealizationTests(); + await callIntegrationTests(); + }; + + await callTests(); + await deep.delete({ + up: { + parent_id: deep.linkId, + tree_id: deep.idLocal("@deep-foundation/core", "containTree") + } + }) + + } catch (error) { + await deep.delete({ + up: { + parent_id: deep.linkId, + tree_id: deep.idLocal("@deep-foundation/core", "containTree") + } + }) + console.log(error); + process.exit(1); + } +}; + +installPackage(); \ No newline at end of file