Pull request #336: story(TEAMMSBMOB-15615): подписание заявки на депозит

Merge in MCB_FE/mcb-platform-monorepo from story/TEAMMSBMOB-15615_deposit-sign-choose to develop

* commit '306f4c7737ebdcca0a05988cf1284e82bac9300f':
  story(TEAMMSBMOB-15615): флоу подписания депозита
  story(TEAMMSBMOB-15615): сетевой слой генерации подписи и данных для подписания депозита
  story(TEAMMSBMOB-15615): логика сабмита формы депозита
  story(TEAMMSBMOB-15615): создание документа депозита для подписания
This commit is contained in:
Даниил Лисицын
2025-09-05 16:36:18 +03:00
28 changed files with 859 additions and 38 deletions
+2
View File
@@ -28,6 +28,7 @@ import {
treasuryDealsI18nHandlers,
calculatorHandlers,
treasuryDealsSaveTemplateHandlers,
signTreasuryDealsHandlers,
showcaseHandlers,
} from '../treasury-deals-client';
import { userProfileHandlers } from '../uaa-client';
@@ -72,6 +73,7 @@ const handlers = [
...depositDocumentValidateHandlers,
...treasuryDealsI18nHandlers,
...treasuryDealsSaveTemplateHandlers,
...signTreasuryDealsHandlers,
...showcaseHandlers,
...signPaymentsHandler,
];
@@ -19,6 +19,7 @@ interface ClientOriginalInfo {
}
interface DepositDocumentNewForEditDto {
id?: string;
docSource: string;
docType: string;
docSubType: string;
@@ -54,4 +55,9 @@ interface DepositDocumentNewForEditResponseDto {
data: DepositDocumentNewForEditDto;
}
export type { DepositDocumentNewForEditDto , DepositDocumentNewForEditResponseDto };
export type {
DepositDocumentNewForEditDto,
DepositDocumentNewForEditResponseDto,
GeneralAgreement,
ClientOriginalInfo
};
@@ -17,4 +17,5 @@ export * from './treasuryDealsBestRates';
export * from './validate';
export * from './i18n';
export * from './saveTemplate';
export * from './signTreasuryDeals';
export * from './showcase';
@@ -0,0 +1,7 @@
const CREATE_TO_SIGN_DEPOSIT_DOCUMENT = '/treasury-deals-client/deposit-document' as const;
const GENERATE_SIGN_DATA_DEPOSIT_DOCUMENT = '/treasury-deals-client/deposit-document/generate-sign-data' as const;
const SIGN_AND_SEND_DEPOSIT_DOCUMENT = '/treasury-deals-client/deposit-document/sign-and-send' as const;
export { CREATE_TO_SIGN_DEPOSIT_DOCUMENT, GENERATE_SIGN_DATA_DEPOSIT_DOCUMENT, SIGN_AND_SEND_DEPOSIT_DOCUMENT };
@@ -0,0 +1,2 @@
export * from './const';
export * from './types';
@@ -0,0 +1,97 @@
import { DepositDocumentValidateResponseDto } from '../validate';
import { DepositDocumentRateDto } from '../treasuryDealsRates';
import { GeneralAgreement, ClientOriginalInfo } from '../fetchDepositDocumentNewForEdit';
import { Branch, AccountWriteOff, AccountRefund, AccountInterestPay, DealRate } from '../fetchProducts';
import { ISignRequestData } from '@msb/crypto';
interface CreateToSignDepositDocumentResponseDto extends DepositDocumentValidateResponseDto {}
interface CreateToSignDepositDocumentRequestBody extends DepositDocumentRateDto {}
type GenerateToSignDepositDocumentRequestBody = string;
interface DigestField {
field?: string; // опциональное поле для маппинга
fieldName: string; // название поля для отображения
values: string; // значение поля
}
interface GenerateToSignDepositDocumentResponseDto {
data: {
id: string;
digest: {
value: string;
version: number;
signFields: string;
};
digestInfo: {
title: string;
description: string;
fields: DigestField[];
};
dssLabel: string;
};
}
interface SignAndSendDepositDocumentDto {
id: string;
docSource: 'WEB_DEALING';
docType: 'DEPOSIT';
docSubType: 'REQUEST';
docPrintTemplateVersion: number;
docNumber: number;
docDate: string;
docCreatorId: string;
docCreatorFullName: string;
createdAt: string;
updatedAt: string;
docStatus: string;
uuid: number;
version: number;
clientSignerFio: string;
dealDate: string;
dealDateTime: string;
cancelDateTime: string;
generalAgreement: GeneralAgreement;
branch: Branch;
dateBegin: string;
dateEnd: string;
period: number;
amount: string;
currency: string;
clientWebDealingId: string;
clientOriginalInfo: ClientOriginalInfo;
clientFullNameExt: string;
clientShortNameExt: string;
dealStatus: string;
dealStatusDetails: string;
hidden: boolean;
tempRequest: boolean;
editVersion: number;
clientTimezoneOffset: number;
earlyRefund: boolean;
interestPaymentMethod: string;
accountWriteOff: AccountWriteOff;
accountRefund: AccountRefund;
accountInterestPay: AccountInterestPay;
dealRate: DealRate;
interestPaymentMethodLocalisedCode: string;
dealStatusDescription: string;
docStatusDescription: string;
cancelLifeTime: number;
}
interface SignAndSendDepositDocumentResponseDto {
data: SignAndSendDepositDocumentDto;
}
interface SignAndSendDepositDocumentRequestBody extends ISignRequestData {}
export type {
CreateToSignDepositDocumentRequestBody,
CreateToSignDepositDocumentResponseDto,
GenerateToSignDepositDocumentRequestBody,
GenerateToSignDepositDocumentResponseDto,
SignAndSendDepositDocumentResponseDto,
SignAndSendDepositDocumentRequestBody
};
@@ -17,4 +17,5 @@ export * from './treasuryDealsBestRates';
export * from './validate';
export * from './i18n';
export * from './saveTemplate';
export * from './signTreasuryDeals';
export * from './showcase';
@@ -0,0 +1,13 @@
import {
CREATE_TO_SIGN_DEPOSIT_DOCUMENT_HANDLER,
GENERATE_SIGN_DATA_DEPOSIT_DOCUMENT_HANDLER,
SIGN_AND_SEND_DEPOSIT_DOCUMENT_HANDLER,
} from './signTreasuryDeals';
const signTreasuryDealsHandlers = [
CREATE_TO_SIGN_DEPOSIT_DOCUMENT_HANDLER,
GENERATE_SIGN_DATA_DEPOSIT_DOCUMENT_HANDLER,
SIGN_AND_SEND_DEPOSIT_DOCUMENT_HANDLER,
];
export { signTreasuryDealsHandlers };
@@ -0,0 +1,370 @@
//@ts-nocheck
import type { CreateToSignDepositDocumentResponseDto, GenerateToSignDepositDocumentResponseDto, SignAndSendDepositDocumentResponseDto } from '../../endpoints';
const CREATE_TO_SIGN_DEPOSIT_DOCUMENT_MOCK: CreateToSignDepositDocumentResponseDto = {
"data": {
"id": "95b2caca-14ac-4915-bca9-0bd03f769954",
"docSource": "WEB_DEALING",
"docType": "DEPOSIT",
"docSubType": "REQUEST",
"docPrintTemplateVersion": 1,
"docNumber": 136,
"docDate": "2024-12-27",
"docCreatorId": "f46a2104-5285-4e3d-93db-6b064bc464d1",
"docCreatorFullName": "Рыжаков Юрий Александрович",
"createdAt": "2024-12-27T08:32:18.617349Z",
"updatedAt": "2024-12-27T08:33:14.335156Z",
"docStatus": "QUOTED",
"uuid": 85452,
"version": 8,
"dealDate": "2024-12-27",
"generalAgreement": {
"businessId": "8174e16d-3cc1-4836-8d64-3a37cab675d8",
"id": "8174e16d-3cc1-4836-8d64-3a37cab675d8",
"contractId": 89382,
"contractType": "ACCESSION",
"date": "2024-10-29",
"number": "Д01-12313010/2024",
"earlyRefund": true,
"earlyRefundRateRub": "0.90",
"earlyRefundRateFor": "0.11",
"default": false
},
"branch": {
"id": "584cd35e-3cad-4045-9db8-328092c4956f",
"knosisBranchId": 33,
"absCode": "032/0000",
"name": "Филиал",
"bic": "045773808",
"filialName": "Ф-Л БАНКА ГПБ (АО) \"ЗАПАДНО-УРАЛЬСКИЙ\""
},
"dateBegin": "2024-12-27",
"dateEnd": "2025-01-22",
"period": 26,
"amount": "180000.00",
"currency": "RUB",
"clientWebDealingId": "fcd417bf-5242-4969-be1a-02c889cb1cc2",
"clientOriginalInfo": {
"innKio": "4221030530",
"ogrn": "1104221001840",
"fullName": "ОБЩЕСТВО С ОГРАНИЧЕННОЙ ОТВЕТСТВЕННОСТЬЮ \"НК ГИДРОПРИВОД\"",
"shortName": "ООО \"НК ГИДРОПРИВОД\""
},
"clientFullNameExt": "ОБЩЕСТВО С ОГРАНИЧЕННОЙ ОТВЕТСТВЕННОСТЬЮ \"НК ГИДРОПРИВОД\"",
"clientShortNameExt": "ООО \"НК ГИДРОПРИВОД\"",
"dealStatus": "QUOTED",
"dealStatusDetails": "Заключение сделки на полученных условиях можно продолжить до окончания времени действия ставки",
"hidden": true,
"tempRequest": false,
"baseTemplateId": "21afd9bf-a69f-4d39-a28b-9019c04f558a",
"parentTemplateId": "21afd9bf-a69f-4d39-a28b-9019c04f558a",
"editVersion": 1,
"baseEditVersion": 1,
"earlyRefund": false,
"interestPaymentMethod": "END",
"accountWriteOff": {
"businessId": "512593125593871561",
"absId": "00000000-0000-0000-0000-000756493581",
"accountType": "INTERNAL",
"accountNameExtended": "ООО \"НК ГИДРОПРИВОД\"",
"currency": "RUB",
"accountNumber": "40702810700000063869",
"bankName": "БАНК ГПБ (АО)",
"bankCode": "044525823",
"bankKS": "30101810200000000823",
"absPropertyMNO": "ACCEPTABLE",
"absPropertyDepositValue": "ACCEPTABLE",
"absPropertyDepositMaturity": "ACCEPTABLE",
"absPropertyInterest": "ACCEPTABLE"
},
"accountRefund": {
"businessId": "512593125593871561",
"absId": "00000000-0000-0000-0000-000756493581",
"accountType": "INTERNAL",
"accountNameExtended": "ООО \"НК ГИДРОПРИВОД\"",
"currency": "RUB",
"accountNumber": "40702810700000063869",
"bankName": "БАНК ГПБ (АО)",
"bankCode": "044525823",
"bankKS": "30101810200000000823",
"absPropertyMNO": "ACCEPTABLE",
"absPropertyDepositValue": "ACCEPTABLE",
"absPropertyDepositMaturity": "ACCEPTABLE",
"absPropertyInterest": "ACCEPTABLE"
},
"accountInterestPay": {
"businessId": "512593125593871561",
"absId": "00000000-0000-0000-0000-000756493581",
"accountType": "INTERNAL",
"accountNameExtended": "ООО \"НК ГИДРОПРИВОД\"",
"currency": "RUB",
"accountNumber": "40702810700000063869",
"bankName": "БАНК ГПБ (АО)",
"bankCode": "044525823",
"bankKS": "30101810200000000823",
"absPropertyMNO": "ACCEPTABLE",
"absPropertyDepositValue": "ACCEPTABLE",
"absPropertyDepositMaturity": "ACCEPTABLE",
"absPropertyInterest": "ACCEPTABLE"
},
"dealRate": {
"clientWebDealingId": "fcd417bf-5242-4969-be1a-02c889cb1cc2",
"obtained": "2024-12-27T08:32:48.104062Z",
"dateBegin": "2024-12-27",
"dateEnd": "2025-01-22",
"period": 26,
"amount": "180000.00",
"currency": "RUB",
"value": "7.60",
"percentAmount": "974.06",
"expiration": "2024-12-27T08:33:48.104062Z",
"rateMatricesAskId": 62256,
"rateAskId": 18914182,
"earlyRefund": false,
"interestPaymentMethod": "END",
"interestPaymentMethodLocalisedCode": "fld.interestPaymentMethod.end",
"lifeTime": 33744
},
"interestPaymentMethodLocalisedCode": "fld.interestPaymentMethod.end",
"dealStatusDescription": "Получена ставка",
"docStatusDescription": "Получена ставка"
},
"validationResult": {
"result": "INVALID",
"groupResults": [
{
"id": "GroupDocumentDefault",
"name": "[[doc.cpm.GroupDocumentDefault.name]]",
"result": "INVALID",
"controlResults": [
{
"id": "generalAgreement.in.catalog",
"name": "[[deposit_document.generalAgreement.in.catalog.name]]",
"result": "INVALID",
"level": "CRITICAL",
"checkResults": [
{
"fieldName": "generalAgreement",
"result": "INVALID",
"message": {
"message": "cpm.field.generalAgreement.not.in.catalog",
"params": {}
}
}
]
}
]
}
]
}
};
const GENERATE_SIGN_DATA_DEPOSIT_DOCUMENT_MOCK: GenerateToSignDepositDocumentResponseDto = {
"data": {
"id": "1aa4fcaa-284d-4df0-a304-52fb6c3587bd",
"digest": {
"value": "eyJkZWFsRGF0ZSI6IjIwMjUtMDktMDUiLCJnZW5lcmFsQWdyZWVtZW50LmRhdGUiOiIyMDE4LTA0LTA2IiwiZ2VuZXJhbEFncmVlbWVudC5udW1iZXIiOiLQlDEtMjk4NjkvMjAxOC8wMDQiLCJkYXRlQmVnaW4iOiIyMDI1LTA5LTA1IiwiZGF0ZUVuZCI6IjIwMjUtMDktMDgiLCJhbW91bnQiOjI1MC4wMCwiY3VycmVuY3kiOiJSVUIiLCJkZWFsUmF0ZS52YWx1ZSI6MTguNTAwMCwiY2xpZW50RnVsbE5hbWVFeHQiOiLQkNC60YbQuNC+0L3QtdGA0L3QvtC1INC+0LHRidC10YHRgtCy0L4gXCLQotGD0LvQsNGH0LXRgNC80LXRglwiIiwiZWFybHlSZWZ1bmQiOmZhbHNlLCJpbnRlcmVzdFBheW1lbnRNZXRob2QiOiJFTkQiLCJhY2NvdW50V3JpdGVPZmYuY3VycmVuY3kiOiJSVUIiLCJhY2NvdW50V3JpdGVPZmYuYWNjb3VudE51bWJlciI6IjQwNzAyODEwMzAwMDAwMDU3NTUwIiwiYWNjb3VudFdyaXRlT2ZmLmJhbmtOYW1lIjoi0JHQkNCd0Jog0JPQn9CRICjQkNCeKSIsImFjY291bnRXcml0ZU9mZi5iYW5rQ29kZSI6IjA0NDUyNTgyMyIsImFjY291bnRXcml0ZU9mZi5iYW5rS1MiOiIzMDEwMTgxMDIwMDAwMDAwMDgyMyIsImFjY291bnRSZWZ1bmQuY3VycmVuY3kiOiJSVUIiLCJhY2NvdW50UmVmdW5kLmFjY291bnROdW1iZXIiOiI0MDcwMjgxMDYwMDAwMDA1NzU1MSIsImFjY291bnRSZWZ1bmQuYmFua05hbWUiOiLQkdCQ0J3QmiDQk9Cf0JEgKNCQ0J4pIiwiYWNjb3VudFJlZnVuZC5iYW5rQ29kZSI6IjA0NDUyNTgyMyIsImFjY291bnRSZWZ1bmQuYmFua0tTIjoiMzAxMDE4MTAyMDAwMDAwMDA4MjMiLCJhY2NvdW50SW50ZXJlc3RQYXkuY3VycmVuY3kiOiJSVUIiLCJhY2NvdW50SW50ZXJlc3RQYXkuYWNjb3VudE51bWJlciI6IjQwNzAyODEwNjAwMDAwMDU3NTUxIiwiYWNjb3VudEludGVyZXN0UGF5LmJhbmtOYW1lIjoi0JHQkNCd0Jog0JPQn9CRICjQkNCeKSIsImFjY291bnRJbnRlcmVzdFBheS5iYW5rQ29kZSI6IjA0NDUyNTgyMyIsImFjY291bnRJbnRlcmVzdFBheS5iYW5rS1MiOiIzMDEwMTgxMDIwMDAwMDAwMDgyMyJ9",
"version": 6,
"signFields": "{\"dealDate\":\"2025-09-05\",\"generalAgreement.date\":\"2018-04-06\",\"generalAgreement.number\":\"Д1-29869/2018/004\",\"dateBegin\":\"2025-09-05\",\"dateEnd\":\"2025-09-08\",\"amount\":250.00,\"currency\":\"RUB\",\"dealRate.value\":18.5000,\"clientFullNameExt\":\"Акционерное общество \\\"Тулачермет\\\"\",\"earlyRefund\":false,\"interestPaymentMethod\":\"END\",\"accountWriteOff.currency\":\"RUB\",\"accountWriteOff.accountNumber\":\"40702810300000057550\",\"accountWriteOff.bankName\":\"БАНК ГПБ (АО)\",\"accountWriteOff.bankCode\":\"044525823\",\"accountWriteOff.bankKS\":\"30101810200000000823\",\"accountRefund.currency\":\"RUB\",\"accountRefund.accountNumber\":\"40702810600000057551\",\"accountRefund.bankName\":\"БАНК ГПБ (АО)\",\"accountRefund.bankCode\":\"044525823\",\"accountRefund.bankKS\":\"30101810200000000823\",\"accountInterestPay.currency\":\"RUB\",\"accountInterestPay.accountNumber\":\"40702810600000057551\",\"accountInterestPay.bankName\":\"БАНК ГПБ (АО)\",\"accountInterestPay.bankCode\":\"044525823\",\"accountInterestPay.bankKS\":\"30101810200000000823\"}"
},
"digestInfo": {
"title": "Подтверждение от 05.09.2025",
"description": "Настоящее Подтверждение направлено в соответствии с Генеральным соглашением о порядке проведения депозитных операций [[№Д1-29869/2018/004]] от 06.04.2018 и является его неотъемлемой частью",
"fields": [
{
"fieldName": "Банк",
"values": "Ф-Л БАНКА ГПБ (АО) \"УРАЛЬСКИЙ\""
},
{
"field": "clientFullNameExt",
"fieldName": "Наименование клиента",
"values": "Акционерное общество \"Тулачермет\""
},
{
"fieldName": "Сумма и валюта вклада",
"values": "250,00 RUB"
},
{
"field": "earlyRefund",
"fieldName": "Возможность досрочного истребования вклада",
"values": "Нет"
},
{
"fieldName": "Процентная ставка",
"values": "18,50% годовых"
},
{
"field": "interestPaymentMethod",
"fieldName": "Порядок (периодичность) уплаты процентов",
"values": "В конце срока"
},
{
"fieldName": "Дата начала срока",
"values": "05.014:309.2025"
},
{
"fieldName": "Дата окончания срока",
"values": "08.09.2025"
},
{
"fieldName": "Дополнительные условия",
"values": "Нет"
},
{
"fieldName": "Депозитный счет",
"values": ""
},
{
"field": "accountWriteOff",
"fieldName": "Реквизиты счета для списания средств в сумме вклада для зачисления на Депозитный счет Клиента",
"values": "Счет № 40702.810.3.00000057550\nБАНК ГПБ (АО)\nБИК 044525823\nКор/сч 30101.810.2.00000000823"
},
{
"field": "accountRefund",
"fieldName": "Платежные инструкции для возврата вклада",
"values": "Счет № 40702.810.6.00000057551\nБАНК ГПБ (АО)\nБИК 044525823\nКор/сч 30101.810.2.00000000823"
},
{
"field": "accountInterestPay",
"fieldName": "Платежные инструкции для уплаты процентов",
"values": "Счет № 40702.810.6.00000057551\nБАНК ГПБ (АО)\nБИК 044525823\nКор/сч 30101.810.2.00000000823"
}
]
},
"dssLabel": "ПОДПИСЬ ДОКУМЕНТА\nПодтверждение депозитной сделки от 05.09.2025\nНастоящее Подтверждение направлено в соответствии с Генеральным соглашением о порядке проведения депозитных операций № Д1-29869/2018/004 от 06.04.2018 и является его неотъемлемой частью\nБанк: Ф-Л БАНКА ГПБ (АО) \"УРАЛЬСКИЙ\"\nНаименование клиента: Акционерное общество \"Тулачермет\"\nСумма и валюта вклада: 250,00 RUB\nВозможность досрочного истребования вклада: Нет\nПроцентная ставка: 18,50% годовых\nПорядок (периодичность) уплаты процентов: В конце срока\nДата начала срока: 05.09.2025\nДата окончания срока: 08.09.2025\nДополнительные условия: Нет\nДепозитный счет: -\nРеквизиты счета для списания средств в сумме вклада для зачисления на Депозитный счет Клиента:\nСчет № 40702.810.3.00000057550\nБАНК ГПБ (АО)\nБИК 044525823\nКор/сч 30101.810.2.00000000823\nПлатежные инструкции для возврата вклада:\nСчет № 40702.810.6.00000057551\nБАНК ГПБ (АО)\nБИК 044525823\nКор/сч 30101.810.2.00000000823\nПлатежные инструкции для уплаты процентов:\nСчет № 40702.810.6.00000057551\nБАНК ГПБ (АО)\nБИК 044525823\nКор/сч 30101.810.2.00000000823"
}
};
const SIGN_AND_SEND_DEPOSIT_DOCUMENT_MOCK: SignAndSendDepositDocumentResponseDto = {
"data": {
"id": "bfe50881-a996-4430-87dc-26af43cda769",
"docSource": "WEB_DEALING",
"docType": "DEPOSIT",
"docSubType": "REQUEST",
"docPrintTemplateVersion": 1,
"docNumber": 22,
"docDate": "2024-11-29",
"docCreatorId": "f46a2104-5285-4e3d-93db-6b064bc464d1",
"docCreatorFullName": "Рыжаков Юрий Александрович",
"createdAt": "2024-11-29T09:13:37.933237Z",
"updatedAt": "2024-11-29T09:16:17.643741Z",
"docStatus": "DELAYED",
"uuid": 66921,
"version": 9,
"clientSignerFio": "Рыжаков Юрий Александрович",
"dealDate": "2024-11-29",
"dealDateTime": "2024-11-29T12:16:17.807914Z",
"cancelDateTime": "2024-11-29T09:17:17.810049Z",
"generalAgreement": {
"businessId": "8174e16d-3cc1-4836-8d64-3a37cab675d8",
"id": "8174e16d-3cc1-4836-8d64-3a37cab675d8",
"contractId": 89382,
"contractType": "ACCESSION",
"date": "2024-10-29",
"number": "Д01-12313010/2024",
"earlyRefund": true,
"earlyRefundRateRub": "0.10",
"earlyRefundRateFor": "0.01",
"default": false
},
"branch": {
"id": "584cd35e-3cad-4045-9db8-328092c4956f",
"knosisBranchId": 33,
"absCode": "032/0000",
"name": "Филиал",
"bic": "045773808",
"filialName": "Ф-Л БАНКА ГПБ (АО) \"ЗАПАДНО-УРАЛЬСКИЙ\""
},
"dateBegin": "2024-11-29",
"dateEnd": "2024-12-02",
"period": 3,
"amount": "542.00",
"currency": "RUB",
"clientWebDealingId": "fcd417bf-5242-4969-be1a-02c889cb1cc2",
"clientOriginalInfo": {
"innKio": "4221030530",
"ogrn": "1104221001840",
"fullName": "ОБЩЕСТВО С ОГРАНИЧЕННОЙ ОТВЕТСТВЕННОСТЬЮ \"НК ГИДРОПРИВОД\"",
"shortName": "ООО \"НК ГИДРОПРИВОД\""
},
"clientFullNameExt": "ОБЩЕСТВО С ОГРАНИЧЕННОЙ ОТВЕТСТВЕННОСТЬЮ \"НК ГИДРОПРИВОД\"",
"clientShortNameExt": "ООО \"НК ГИДРОПРИВОД\"",
"dealStatus": "DELIVERED",
"dealStatusDetails": "Подтверждение по сделке направлено в Банк. Условия сделки будут согласованы после получения Подтверждения по сделке, направленного Банком.",
"hidden": false,
"tempRequest": false,
"editVersion": 1,
"clientTimezoneOffset": -180,
"earlyRefund": false,
"interestPaymentMethod": "END",
"accountWriteOff": {
"businessId": "512593125593871561",
"absId": "00000000-0000-0000-0000-000756493581",
"accountType": "INTERNAL",
"accountNameExtended": "ООО \"НК ГИДРОПРИВОД\"",
"currency": "RUB",
"accountNumber": "40702810700000063869",
"bankName": "БАНК ГПБ (АО)",
"bankCode": "044525823",
"bankKS": "30101810200000000823",
"absPropertyMNO": "ACCEPTABLE",
"absPropertyDepositValue": "ACCEPTABLE",
"absPropertyDepositMaturity": "ACCEPTABLE",
"absPropertyInterest": "ACCEPTABLE"
},
"accountRefund": {
"businessId": "512593125593871561",
"absId": "00000000-0000-0000-0000-000756493581",
"accountType": "INTERNAL",
"accountNameExtended": "ООО \"НК ГИДРОПРИВОД\"",
"currency": "RUB",
"accountNumber": "40702810700000063869",
"bankName": "БАНК ГПБ (АО)",
"bankCode": "044525823",
"bankKS": "30101810200000000823",
"absPropertyMNO": "ACCEPTABLE",
"absPropertyDepositValue": "ACCEPTABLE",
"absPropertyDepositMaturity": "ACCEPTABLE",
"absPropertyInterest": "ACCEPTABLE"
},
"accountInterestPay": {
"businessId": "512593125593871561",
"absId": "00000000-0000-0000-0000-000756493581",
"accountType": "INTERNAL",
"accountNameExtended": "ООО \"НК ГИДРОПРИВОД\"",
"currency": "RUB",
"accountNumber": "40702810700000063869",
"bankName": "БАНК ГПБ (АО)",
"bankCode": "044525823",
"bankKS": "30101810200000000823",
"absPropertyMNO": "ACCEPTABLE",
"absPropertyDepositValue": "ACCEPTABLE",
"absPropertyDepositMaturity": "ACCEPTABLE",
"absPropertyInterest": "ACCEPTABLE"
},
"dealRate": {
"clientWebDealingId": "fcd417bf-5242-4969-be1a-02c889cb1cc2",
"obtained": "2024-11-29T09:15:37.788080Z",
"dateBegin": "2024-11-29",
"dateEnd": "2024-12-02",
"period": 3,
"amount": "542.00",
"currency": "RUB",
"value": "7.10",
"percentAmount": "0.32",
"expiration": "2024-11-29T09:16:37.788080Z",
"rateMatricesAskId": 62256,
"rateAskId": 18914226,
"earlyRefund": false,
"interestPaymentMethod": "END",
"interestPaymentMethodLocalisedCode": "fld.interestPaymentMethod.end",
"lifeTime": 19966
},
"interestPaymentMethodLocalisedCode": "fld.interestPaymentMethod.end",
"dealStatusDescription": "Подтверждено Клиентом",
"docStatusDescription": "Задержка отправки",
"cancelLifeTime": 59988
}
};
export { CREATE_TO_SIGN_DEPOSIT_DOCUMENT_MOCK, GENERATE_SIGN_DATA_DEPOSIT_DOCUMENT_MOCK, SIGN_AND_SEND_DEPOSIT_DOCUMENT_MOCK };
@@ -0,0 +1,35 @@
import { rest } from 'msw';
import type {
CreateToSignDepositDocumentResponseDto,
CreateToSignDepositDocumentRequestBody,
GenerateToSignDepositDocumentRequestBody,
GenerateToSignDepositDocumentResponseDto,
SignAndSendDepositDocumentRequestBody,
SignAndSendDepositDocumentResponseDto,
} from '../../endpoints';
import { CREATE_TO_SIGN_DEPOSIT_DOCUMENT, GENERATE_SIGN_DATA_DEPOSIT_DOCUMENT, SIGN_AND_SEND_DEPOSIT_DOCUMENT } from '../../endpoints';
import {
CREATE_TO_SIGN_DEPOSIT_DOCUMENT_MOCK,
GENERATE_SIGN_DATA_DEPOSIT_DOCUMENT_MOCK,
SIGN_AND_SEND_DEPOSIT_DOCUMENT_MOCK,
} from './mocks';
const CREATE_TO_SIGN_DEPOSIT_DOCUMENT_HANDLER = rest.post<
CreateToSignDepositDocumentRequestBody,
never,
CreateToSignDepositDocumentResponseDto
>(CREATE_TO_SIGN_DEPOSIT_DOCUMENT, (_, res, ctx) => res(ctx.json(CREATE_TO_SIGN_DEPOSIT_DOCUMENT_MOCK)));
const GENERATE_SIGN_DATA_DEPOSIT_DOCUMENT_HANDLER = rest.post<
GenerateToSignDepositDocumentRequestBody,
never,
GenerateToSignDepositDocumentResponseDto
>(GENERATE_SIGN_DATA_DEPOSIT_DOCUMENT, (_, res, ctx) => res(ctx.json(GENERATE_SIGN_DATA_DEPOSIT_DOCUMENT_MOCK)));
const SIGN_AND_SEND_DEPOSIT_DOCUMENT_HANDLER = rest.post<
SignAndSendDepositDocumentRequestBody,
never,
SignAndSendDepositDocumentResponseDto
>(SIGN_AND_SEND_DEPOSIT_DOCUMENT, (_, res, ctx) => res(ctx.json(SIGN_AND_SEND_DEPOSIT_DOCUMENT_MOCK)));
export { CREATE_TO_SIGN_DEPOSIT_DOCUMENT_HANDLER, GENERATE_SIGN_DATA_DEPOSIT_DOCUMENT_HANDLER, SIGN_AND_SEND_DEPOSIT_DOCUMENT_HANDLER };
@@ -2,3 +2,4 @@ export * from './downloadDocuments';
export * from './earlyRefund';
export * from './cancelDocuments';
export * from './downloadFullDocuments';
export * from './signTreausuryDeals';
@@ -0,0 +1,45 @@
import type {
CreateToSignDepositDocumentRequestBody,
CreateToSignDepositDocumentResponseDto,
GenerateToSignDepositDocumentRequestBody,
GenerateToSignDepositDocumentResponseDto,
SignAndSendDepositDocumentRequestBody,
SignAndSendDepositDocumentResponseDto,
} from '@msb/http';
import { CREATE_TO_SIGN_DEPOSIT_DOCUMENT, GENERATE_SIGN_DATA_DEPOSIT_DOCUMENT, network, SIGN_AND_SEND_DEPOSIT_DOCUMENT } from '@msb/http';
const createToSignDepositDocument = async (
data: CreateToSignDepositDocumentRequestBody
): Promise<CreateToSignDepositDocumentResponseDto> => {
const payload = {
data,
};
const response = await network.client.post<CreateToSignDepositDocumentResponseDto>(CREATE_TO_SIGN_DEPOSIT_DOCUMENT, payload);
return response.data;
};
const generateSignDataDepositDocument = async (
data: GenerateToSignDepositDocumentRequestBody
): Promise<GenerateToSignDepositDocumentResponseDto> => {
const payload = {
data,
};
const response = await network.client.post<GenerateToSignDepositDocumentResponseDto>(GENERATE_SIGN_DATA_DEPOSIT_DOCUMENT, payload);
return response.data;
};
const signAndSendDepositDocument = async (data: SignAndSendDepositDocumentRequestBody): Promise<SignAndSendDepositDocumentResponseDto> => {
const payload = {
data,
};
const response = await network.client.post<SignAndSendDepositDocumentResponseDto>(SIGN_AND_SEND_DEPOSIT_DOCUMENT, payload);
return response.data;
};
export { createToSignDepositDocument, generateSignDataDepositDocument, signAndSendDepositDocument };
@@ -0,0 +1,3 @@
const CREATE_TO_SIGN_DEPOSIT_DOCUMENT_KEY = 'CREATE_TO_SIGN_DEPOSIT_DOCUMENT_KEY' as const;
export { CREATE_TO_SIGN_DEPOSIT_DOCUMENT_KEY };
@@ -2,3 +2,4 @@ export * from './downloadDocuments';
export * from './cancelDocuments';
export * from './localization';
export * from './earlyRefund';
export * from './createToSignDocuments';
@@ -3,3 +3,4 @@ export * from './usePostCancelDocuments';
export * from './useFetchFullDocument';
export * from './useEarlyRefund';
export * from './usePostEarlyRefundDocument';
export * from './useLazyCreateToSignDocuments';
@@ -0,0 +1,33 @@
import type { CreateToSignDepositDocumentRequestBody, CreateToSignDepositDocumentResponseDto } from '@msb/http';
import { useMutation } from '@msb/http';
import { createToSignDepositDocument } from '../api';
import { CREATE_TO_SIGN_DEPOSIT_DOCUMENT_KEY } from '../constants';
const useLazyCreateToSignDepositDocument = () => {
const {
mutate: createToSignDeposit,
mutateAsync: createToSignDepositDocumentAsync,
data: createToSignDepositDocumentData,
isLoading: isCreateToSignDepositDocumentLoading,
isError: isCreateToSignDepositDocumentError,
error: createToSignDepositDocumentError,
isSuccess: isCreateToSignDepositDocumentSuccess,
reset: resetCreateToSignDepositDocument,
} = useMutation<CreateToSignDepositDocumentResponseDto, Error, CreateToSignDepositDocumentRequestBody>({
mutationFn: createToSignDepositDocument,
mutationKey: [CREATE_TO_SIGN_DEPOSIT_DOCUMENT_KEY],
});
return {
createToSignDeposit,
createToSignDepositDocumentAsync,
createToSignDepositDocumentData,
isCreateToSignDepositDocumentLoading,
isCreateToSignDepositDocumentError,
createToSignDepositDocumentError,
isCreateToSignDepositDocumentSuccess,
resetCreateToSignDepositDocument,
};
};
export { useLazyCreateToSignDepositDocument };
@@ -1,7 +1,7 @@
enum TREASURY_DEALS_FORM_FIELDS {
ORGANIZATIONS = 'organizations',
GENERAL_AGREEMENTS = 'generalAgreement',
MANAGEMENT_FUNDS = 'management-funds',
MANAGEMENT_FUNDS = 'managementFund',
AMOUNT = 'amount',
CURRENCY = 'currency',
PERIOD = 'period',
@@ -9,7 +9,7 @@ enum TREASURY_DEALS_FORM_FIELDS {
EARLY_REFUND = 'earlyRefund',
ACCOUNTS_WRITE_OFF = 'accountWriteOff',
ACCOUNTS_REFUND = 'accountRefund',
ACCOUNTS_INTPAY = 'accountIntpay',
ACCOUNTS_INTPAY = 'accountInterestPay',
ACCOUNTS_SWITCH = 'accounts-switch',
}
@@ -1,5 +1,6 @@
import type { DepositGeneralAgreementContractType } from '@msb/http';
const ALLOWED_CONTRACT_TYPES_FOR_MANAGEMENT_FUNDS: DepositGeneralAgreementContractType[] = ['ACCESSION_DU', 'INDIVIDUAL_DU', 'STANDART_DU'];
const DIGITAL_SIGNATURE_TOOL_VIEW = 'DIGITAL_SIGNATURE_TOOL_VIEW' as const;
export { ALLOWED_CONTRACT_TYPES_FOR_MANAGEMENT_FUNDS };
export { ALLOWED_CONTRACT_TYPES_FOR_MANAGEMENT_FUNDS, DIGITAL_SIGNATURE_TOOL_VIEW };
@@ -0,0 +1,15 @@
import { GENERATE_SIGN_DATA_DEPOSIT_DOCUMENT, SIGN_AND_SEND_DEPOSIT_DOCUMENT } from '@msb/http';
const GENERATE_SIGN_DATA_ENDPOINTS: Record<string, string> = {
DEPOSIT: GENERATE_SIGN_DATA_DEPOSIT_DOCUMENT,
MNO: '',
GSNO: '',
};
const SIGN_AND_SEND_DATA_ENDPOINTS: Record<string, string> = {
DEPOSIT: SIGN_AND_SEND_DEPOSIT_DOCUMENT,
MNO: '',
GSNO: '',
};
export { GENERATE_SIGN_DATA_ENDPOINTS, SIGN_AND_SEND_DATA_ENDPOINTS };
@@ -1 +1,3 @@
export * from './localization';
export * from './endpoints';
export * from './constants';
@@ -2,4 +2,12 @@ const TREAUSRY_DEALS_PAGE_TITLE = {
DEPOSIT: 'Заявка на депозит',
} as const;
export { TREAUSRY_DEALS_PAGE_TITLE };
const LOCALIZATION = {
BUTTON_SIGN_AND_SEND: 'Подписать и отправить',
MODAL_HEADER: 'Заявка принята',
MODAL_MESSAGE: 'Деньги будут размещены на депозите после того как банк подтвердит заявку',
MODAL_OK_BUTTON_TEXT: 'К списку депозитов',
MODAL_CANCEL_BUTTON_TEXT: 'На главную страницу',
};
export { TREAUSRY_DEALS_PAGE_TITLE, LOCALIZATION };
@@ -8,3 +8,4 @@ export { mutators } from './mutators';
export { useAsyncValidation } from './useAsyncValidation';
export { validate } from './validation';
export { useHandleBackButtonClick } from './useHandleBackButtonClick';
export { useHandleSubmit } from './useHandleSubmit';
@@ -1,6 +1,6 @@
import { useMemo } from 'react';
import type { DepositGeneralAgreementContractType, DepositGeneralAgreementsResponseDto } from '@msb/http';
import { ALLOWED_CONTRACT_TYPES_FOR_MANAGEMENT_FUNDS } from './constants';
import { ALLOWED_CONTRACT_TYPES_FOR_MANAGEMENT_FUNDS } from '../constants';
interface Params {
depositGeneralAgreementsData?: DepositGeneralAgreementsResponseDto;
@@ -0,0 +1,162 @@
import type { IBaseEntity, ISignModalApi, ISignRequestData } from '@msb/crypto';
import { openSignModal } from '@msb/crypto';
import type { DepositDocumentRateResponseDto, DepositDocumentValidateRequestBody, MessagesResponseDto } from '@msb/http';
import { fetchValidate, to } from '@msb/http';
import { localization } from '@msb/localization';
import { BaseDialog, checkHaveUserPermissions, PATHS, useAppContext, useModal, useRedirect } from '@msb/shared';
import type { ValidationErrors } from 'final-form';
import { DIGITAL_SIGNATURE_TOOL_VIEW, LOCALIZATION } from '../constants';
import { transformValidationErrors } from './useAsyncValidation';
import { validate } from './validation';
import { generateSignDataDepositDocument, signAndSendDepositDocument, useLazyCreateToSignDepositDocument } from '@/entities/documents';
import { parseSignDataToCryptoData } from '@/shared/lib';
interface Params {
values: any;
treasuryDealsRatesData?: DepositDocumentRateResponseDto;
requestBody?: DepositDocumentValidateRequestBody;
treasuryDealsI18nData?: MessagesResponseDto;
clientId: string;
}
const useHandleSubmit = () => {
const { userAuthorities } = useAppContext();
const { createToSignDepositDocumentAsync } = useLazyCreateToSignDepositDocument();
const { showModal } = useModal(BaseDialog);
const toDeposits = useRedirect(PATHS.DEPOSITS);
const toMain = useRedirect(PATHS.HOME);
const handleSubmit = async ({ values, treasuryDealsRatesData, requestBody, treasuryDealsI18nData, clientId }: Params) => {
const errors: ValidationErrors = validate(values) || {};
const asyncErrors: ValidationErrors = {};
// TODO: Если отсутсвуют привелегии для подписания, то что делать???
if (userAuthorities?.data?.authorities) {
const haveSignatire = checkHaveUserPermissions(userAuthorities.data.authorities, [DIGITAL_SIGNATURE_TOOL_VIEW]);
console.log('-Есть права на подпись?-', haveSignatire);
}
const res = await fetchValidate(requestBody as DepositDocumentValidateRequestBody);
if (res.validationResult) {
const serverErrors = transformValidationErrors(res.validationResult, treasuryDealsI18nData?.data) || {};
Object.keys(serverErrors).forEach(fieldName => {
const fieldError = serverErrors?.[fieldName];
if (fieldError && typeof fieldError === 'object' && 'error' in fieldError) {
asyncErrors[fieldName] = { error: fieldError.error };
}
});
}
// Если есть ошибки валидации, то возвращаем их
if (Object.keys(errors).length > 0 || Object.keys(asyncErrors).length > 0) {
console.log('-Ошибки валидации-', { ...errors, ...asyncErrors });
return { ...errors, ...asyncErrors };
}
// TODO: Если нет тела от ручки rate, то что делать?
if (!treasuryDealsRatesData?.data) {
return;
}
// Флоу подписания
try {
const document = await createToSignDepositDocumentAsync(treasuryDealsRatesData?.data);
// TODO: localization.translate работает некорректно, надо править
const defaultSignErrorMessage = localization.translate('ltr.lbl.dsError2');
// Оставить для просмотра логов на стенде
console.log('-Созданный документ для подписания-', document);
const signData = document
? {
documentsRegistry: [
{
documents: [{ id: document.data.id! }],
clientId,
clientName: document.data.clientOriginalInfo.fullName,
},
],
statistics: {
documentsCount: 1,
documentsSum: 0,
clientsCount: 1,
},
}
: undefined;
// Оставить для просмотра логов на стенде
console.log('-sign data-', signData);
const signService = {
sign: async ([doc]: ISignRequestData[]) => {
const [response, error] = await to(signAndSendDepositDocument(doc));
// Оставить для просмотра логов на стенде
console.log('-Ответ от ручки sign and send-', response);
console.log('-Ошибки от ручки sign and send-', error);
if (error) return Promise.reject({ error: defaultSignErrorMessage });
return [response];
},
getSignData: async ([id]: string[]) => {
const response = await generateSignDataDepositDocument(id);
// Оставить для просмотра логов на стенде
console.log('-Ответ от ручки generate sign data-', response);
const parsedResponseToV2 = parseSignDataToCryptoData(response, id, clientId);
if (parsedResponseToV2.signDocuments.length > 0) return parsedResponseToV2;
return Promise.reject({ error: defaultSignErrorMessage });
},
send: async ([id]: IBaseEntity[]) => {
if (!id) return Promise.reject({ error: defaultSignErrorMessage });
return Promise.resolve([{ data: id }]);
},
} as unknown as ISignModalApi;
if (signData) {
try {
const response = await openSignModal({
api: signService,
signData,
type: 'single',
});
// Оставить для просмотра логов на стенде
console.log('-Ответ от openSignModal-', response);
if (response.signedDocs.length > 0) {
await showModal({
header: LOCALIZATION.MODAL_HEADER,
message: LOCALIZATION.MODAL_MESSAGE,
okButtonText: LOCALIZATION.MODAL_OK_BUTTON_TEXT,
cancelButtonText: LOCALIZATION.MODAL_CANCEL_BUTTON_TEXT,
onOk: toDeposits,
onCancel: toMain,
type: 'success',
});
return response;
}
} catch (e: unknown) {
console.error(JSON.stringify(e));
}
}
} catch (e) {
console.error(JSON.stringify(e));
}
};
return handleSubmit;
};
export { useHandleSubmit };
@@ -6,11 +6,11 @@ const validate = (values: any): ValidationErrors => {
const emptyFieldErrorMsg = 'Поле не заполнено';
// Базовая синхронная валидация
if (!values[TREASURY_DEALS_FORM_FIELDS.ACCOUNTS_REFUND]) {
if (!values[TREASURY_DEALS_FORM_FIELDS.ACCOUNTS_REFUND] && values[TREASURY_DEALS_FORM_FIELDS.ACCOUNTS_REFUND] !== undefined) {
errors[TREASURY_DEALS_FORM_FIELDS.ACCOUNTS_REFUND] = { error: emptyFieldErrorMsg };
}
if (!values[TREASURY_DEALS_FORM_FIELDS.ACCOUNTS_INTPAY]) {
if (!values[TREASURY_DEALS_FORM_FIELDS.ACCOUNTS_INTPAY] && values[TREASURY_DEALS_FORM_FIELDS.ACCOUNTS_INTPAY] !== undefined) {
errors[TREASURY_DEALS_FORM_FIELDS.ACCOUNTS_INTPAY] = { error: emptyFieldErrorMsg };
}
@@ -1,8 +1,7 @@
import { useEffect, useMemo, useRef, useState } from 'react';
import type { DepositDocumentValidateRequestBody } from '@msb/http';
import { fetchValidate, useTreasuryDealsI18n, useUserInfoUnion, useValidate, type CurrencyCode, type RateRequestBody } from '@msb/http';
import { useTreasuryDealsI18n, useUserInfoUnion, useValidate, type CurrencyCode, type RateRequestBody } from '@msb/http';
import { addToDate, PageLayoutWithSections, showOverlay, hideOverlay } from '@msb/shared';
import type { ValidationErrors } from 'final-form';
import { Form } from 'react-final-form';
import { TREAUSRY_DEALS_PAGE_TITLE } from '../constants';
import {
@@ -12,12 +11,11 @@ import {
handleFormChange,
formTreasuryDealsBodyRequest,
useGetInfoByChosenOrg,
validate,
mutators,
useAsyncValidation,
useHandleBackButtonClick,
useHandleSubmit,
} from '../model';
import { transformValidationErrors } from '../model/useAsyncValidation';
import { FormSpyAlike } from './FormSpyAlike';
import { Shimmer } from './Shimmer';
import * as S from './TreasuryDealsPage.styles';
@@ -102,7 +100,6 @@ const TreasuryDealsPage = () => {
currency: chosenCurrency,
},
});
const { isAccountsSwitchDisabled } = useGetDefaultValuesOfAccountsAndSwitch({
chosenWriteOffAccount,
setIsAccountsSwitchOn,
@@ -110,6 +107,7 @@ const TreasuryDealsPage = () => {
accountsIntpayData,
formRef,
});
const handleSubmit = useHandleSubmit();
useResetManagementFundsField({ formRef, isManagementFundsAvailable });
useAsyncValidation({ formRef, depositDocumentValidateData, treasuryDealsI18nData });
@@ -175,30 +173,6 @@ const TreasuryDealsPage = () => {
}
}, [depositDocumentNewForEditData]);
const handleSubmit = async (values: any) => {
// Заготовка валидации на submit
const errors: ValidationErrors = validate(values) || {};
const asyncErrors: ValidationErrors = {};
const res = await fetchValidate(requestBody as DepositDocumentValidateRequestBody);
if (res.validationResult) {
const serverErrors = transformValidationErrors(res.validationResult, treasuryDealsI18nData?.data) || {};
Object.keys(serverErrors).forEach(fieldName => {
const fieldError = serverErrors?.[fieldName];
if (fieldError && typeof fieldError === 'object' && 'error' in fieldError) {
asyncErrors[fieldName] = { error: fieldError.error };
}
});
}
if (Object.keys(errors) || Object.keys(asyncErrors)) {
return { ...errors, ...asyncErrors };
}
};
// TODO: вынести в model, когда добавлю обработку всех загрузок
useEffect(() => {
if (isTreasuryDealsRatesFetching || isTreasuryDealsBestRatesFetching) {
@@ -274,7 +248,15 @@ const TreasuryDealsPage = () => {
</>
);
}}
onSubmit={handleSubmit}
onSubmit={values =>
handleSubmit({
values,
treasuryDealsRatesData,
requestBody: requestBody as DepositDocumentValidateRequestBody,
treasuryDealsI18nData,
clientId: chosenOrgId,
})
}
/>
</S.Wrapper>
</PageLayoutWithSections>
@@ -1,3 +1,4 @@
export * from './fetchDocuments';
export * from './parsedCancelDataToCryptoData';
export * from './useGetPermissionDataFromUnion';
export * from './parseSignDataToCryptoData';
@@ -0,0 +1,31 @@
import type { GenerateToSignDepositDocumentResponseDto } from '@msb/http';
import type { SignDataList, SignDocument } from '@/shared/models';
const transformSignFieldsToArraySimple = (
fields: GenerateToSignDepositDocumentResponseDto['data']['digestInfo']['fields']
): Array<{ label: string; value: string }> => fields.map(field => ({ label: field.fieldName, value: field.values }));
const parseSignDataToCryptoData = (
data: GenerateToSignDepositDocumentResponseDto,
documentId: string,
clientId: string = ''
): { signDocuments: SignDocument[] } => {
const signDataList: SignDataList = {
label: data.data.digestInfo.title || 'Документ',
digest: data.data.digest.value,
type: 'DOCUMENT',
dssLabel: data.data.dssLabel,
signDataViewList: [
{
label: 'Основная информация',
signFieldsViewList: transformSignFieldsToArraySimple(data.data.digestInfo.fields),
},
],
};
const signDocument: SignDocument = { documentId, clientId, signDataList: [signDataList] };
return { signDocuments: [signDocument] };
};
export { parseSignDataToCryptoData };