This commit is contained in:
merelendor 2023-11-01 12:52:04 +03:00
commit e7cf51bc21
178 changed files with 13456 additions and 3249 deletions

View File

@ -4,6 +4,7 @@ import Router from 'next/router';
import moment from 'moment';
import * as actionTypes from '../constants/actionTypes';
import { getEDOOperatorList } from './index';
if(process.browser)
{
@ -18,12 +19,12 @@ if(process.browser)
this.append(keyName, obj[key]);
}
}
};
};
}
export const getCompanyInfo = ({ dispatch }) =>
{
//console.log("getCompanyInfo");
console.log("ACTION", "company", "getCompanyInfo");
return new Promise((resolve, reject) =>
{
@ -32,9 +33,9 @@ export const getCompanyInfo = ({ dispatch }) =>
})
.then((response) =>
{
getEDOOperatorList({ dispatch }).then(() => {}).catch(() => {});
//console.log("getCompanyInfo", "response", response.data);
dispatch({ type: actionTypes.COMPANY, data: response.data });
resolve();
})

View File

@ -336,7 +336,7 @@ export const getContractFines = ({ dispatch, contract, }) =>
//console.log("ACTION", "getContractFines", "response.data", response.data);
let query = nSQL(response.data.fines).query("select");
let query = nSQL(response.data).query("select");
query = query.orderBy({ date: "desc" });
query.exec().then((rows) =>
{

View File

@ -3,101 +3,390 @@ import { Cookies } from 'react-cookie';
import Router from 'next/router';
import moment from 'moment';
import { nSQL } from "@nano-sql/core";
import { eachSeries } from 'async';
import fileDownload from 'js-file-download';
import * as actionTypes from '../constants/actionTypes';
import * as currentState from '../reducers/initialState';
/*DEALS_LIST
/lk/ConsiderationOpportunity/quote
[{
"quote_number": "582189",
"price": 5490000,
"first_payment_perc": 30,
"first_payment_rub": 1647000,
"brand_name": "Volkswagen",
"model_name": "Touareg",
"object_count": 1,
}, {
"quote_number": "580008",
"price": 5341770,
"first_payment_perc": 30,
"first_payment_rub": 1647000,
"brand_name": "Volkswagen",
"model_name": "Touareg",
"object_count": 1,
}]
[{
"opp_number": "780",
"statuscode_id": 107,
"statuscode_name": " ",
"comment": null,
}, {
"opp_number": "37197",
"statuscode_id": 101,
"statuscode_name": " ",
"comment": null,
}]
opp_number- номер Лизинговой сделки
statuscode_id - номер этапа
statuscode_name - имя этапа
comment - сопроводительный текст для данного этапа, который надо выводить
*/
export const getDeals = ({ dispatch }) =>
if(process.browser)
{
console.log("ACTION", "deals", "getDeals()", `${ process.env.NEXT_PUBLIC_SELF_API_HOST }/api/deals`);
FormData.prototype.appendObject = function(obj, namespace)
{
let keyName;
for (var key in obj)
{
if (obj.hasOwnProperty(key))
{
keyName = [namespace, '[', key, ']'].join('');
this.append(keyName, obj[key]);
}
}
};
}
export const getDeals = ({ dispatch, update = false }) =>
{
const url = `${ process.env.NEXT_PUBLIC_SELF_API_HOST }/api/deals`;
console.log("ACTION", "deals", "getDeals()", { url });
return new Promise((resolve, reject) =>
{
console.log("??????????????????????? WTF");
axios.post(`${ process.env.NEXT_PUBLIC_SELF_API_HOST }/api/deals`, {}, {
axios.post(url, {}, {
withCredentials: true,
})
.then((response) =>
{
console.log("!!!!!!!!!!!!!!!!!!!!!!!!! GOOOOOOD");
console.log("ACTION", "deals", "getDeals()", "response", response.data);
/*
if(update)
{
for(let i in response.data)
{
if(response.data[i].opp_number == "20325")
{
response.data[i].statuscode_id = 101;
}
}
}
*/
dispatch({
type: actionTypes.DEALS_LIST,
data: {
list: [{
"opp_number": "780",
"statuscode_id": 107,
"statuscode_name": " ",
"comment": null,
}, {
"opp_number": "37197",
"statuscode_id": 101,
"statuscode_name": " ",
"comment": null,
}]
list: response.data
}
});
resolve();
})
.catch((error) =>
{
console.log("!!!!!!!!!!!!!!!!!!!!!!!!! ERROR", { action: actionTypes.DEALS_LIST });
console.error("ACTION", "deals", "getDeals()", "ERROR");
console.error(error);
const eventMessage = new CustomEvent("_message", { detail: { type: "error", title: "Ошибка", content: "Ошибка при вызове метода ConsiderationOpportunity" } });
window.dispatchEvent(eventMessage);
dispatch({
type: actionTypes.DEALS_LIST,
data: {
list: [{
"opp_number": "780",
"statuscode_id": 107,
"statuscode_name": " ",
"comment": null,
}, {
"opp_number": "37197",
"statuscode_id": 101,
"statuscode_name": " ",
"comment": null,
}]
list: []
}
});
reject();
});
});
}
export const getDealOffers = ({ dispatch, deal_id }) =>
{
const url = `${ process.env.NEXT_PUBLIC_SELF_API_HOST }/api/deals/offer/list`;
console.log("ACTION", "deals", "getDealOffers()", { url });
console.log("ACTION", "deals", "getDealOffers()", { deal_id });
return new Promise((resolve, reject) =>
{
axios.post(url, { deal_id }, {
withCredentials: true,
})
.then((response) =>
{
console.log("ACTION", "deals", "getDealOffers()", "response", response.data);
dispatch({
type: actionTypes.DEAL_OFFERS_LIST,
data: {
deal_id,
list: response.data
}
});
resolve();
})
.catch((error) =>
{
console.error("ACTION", "deals", "getDealOffers()", "ERROR");
console.error(error);
const eventMessage = new CustomEvent("_message", { detail: { type: "error", title: "Ошибка", content: "Ошибка при вызове метода quote" } });
window.dispatchEvent(eventMessage);
dispatch({
type: actionTypes.DEAL_OFFERS_LIST,
data: {
deal_id,
list: []
}
});
reject();
});
});
}
export const downloadDealOffer = ({ quote_number, filename }) =>
{
return new Promise((resolve, reject) =>
{
const url = `${ process.env.NEXT_PUBLIC_SELF_API_HOST }/api/deals/offer/download`;
axios.get(url, {
params: { quote_number },
responseType: 'blob',
})
.then((response) =>
{
fileDownload(response.data, filename);
resolve();
})
.catch((error) =>
{
console.error("ACTION", "sign", "downloadDealOffer()", "ERROR");
console.error(error);
const eventMessage = new CustomEvent("_message", { detail: { type: "error", title: "Ошибка", content: "Ошибка при вызове метода offerprintform" } });
window.dispatchEvent(eventMessage);
reject(error.data);
});
});
}
export const acceptDealOffers = ({ deal_id, offers }) =>
{
const url = `${ process.env.NEXT_PUBLIC_SELF_API_HOST }/api/deals/accept`;
console.log("ACTION", "deals", "acceptDealOffers()", { url });
console.log("ACTION", "deals", "acceptDealOffers()", { deal_id, offers, });
return new Promise((resolve, reject) =>
{
axios.post(url, { deal_id, offers }, {
withCredentials: true,
})
.then((response) =>
{
console.log("ACTION", "deals", "acceptDealOffers()", "response", response.data);
resolve();
})
.catch((error) =>
{
console.error("ACTION", "deals", "acceptDealOffers()", "ERROR");
console.error(error);
const eventMessage = new CustomEvent("_message", { detail: { type: "error", title: "Ошибка", content: "Ошибка при вызове метода quote accept" } });
window.dispatchEvent(eventMessage);
reject();
});
});
}
export const getDealDocuments = ({ dispatch, deal_id }) =>
{
const url = `${ process.env.NEXT_PUBLIC_SELF_API_HOST }/api/deals/documents`;
console.log("ACTION", "deals", "getDealDocuments()", { url });
console.log("ACTION", "deals", "getDealDocuments()", { deal_id, });
return new Promise((resolve, reject) =>
{
axios.post(url, { deal_id }, {
withCredentials: true,
})
.then((response) =>
{
console.log("ACTION", "deals", "getDealDocuments()", "response", response.data);
dispatch({
type: actionTypes.DEAL_DOCUMENTS_LIST,
data: {
deal_id,
documents: response.data.documents,
uploaded: response.data.uploaded,
}
});
resolve();
})
.catch((error) =>
{
console.error("ACTION", "deals", "getDealDocuments()", "ERROR");
console.error(error);
const eventMessage = new CustomEvent("_message", { detail: { type: "error", title: "Ошибка", content: "Ошибка при вызове метода document" } });
window.dispatchEvent(eventMessage);
dispatch({
type: actionTypes.DEAL_DOCUMENTS_LIST,
data: {
deal_id,
documents: [],
uploaded: {},
}
});
reject();
});
});
}
export const sendDealDocuments = ({ deal_id }) =>
{
return new Promise((resolve, reject) =>
{
const payload = {
deal_id,
};
axios.post(`${ process.env.NEXT_PUBLIC_SELF_API_HOST }/api/deals/upload`, payload,
{
withCredentials: true,
})
.then(async (response) =>
{
console.log("ACTION", "deals", "sendDealDocuments", "response.data", response.data);
setTimeout(() =>
{
resolve();
}, 20000);
})
.catch((error) =>
{
console.error(error);
const eventMessage = new CustomEvent("_message", { detail: { type: "error", title: "Ошибка", content: "Ошибка при отправке пакета документов для сделки" } });
window.dispatchEvent(eventMessage);
reject();
});
});
}
export const getDealContracts = ({ dispatch, deal_id }) =>
{
const url = `${ process.env.NEXT_PUBLIC_SELF_API_HOST }/api/deals/contracts`;
console.log("ACTION", "deals", "getDealContracts()", { url });
console.log("ACTION", "deals", "getDealContracts()", { deal_id, });
return new Promise((resolve, reject) =>
{
axios.post(url, { deal_id }, {
withCredentials: true,
})
.then((response) =>
{
console.log("ACTION", "deals", "getDealContracts()", "response", response.data);
dispatch({
type: actionTypes.DEAL_CONTRACTS_LIST,
data: {
deal_id,
list: response.data
}
});
resolve();
})
.catch((error) =>
{
console.error("ACTION", "deals", "getDealContracts()", "ERROR");
console.error(error);
const eventMessage = new CustomEvent("_message", { detail: { type: "error", title: "Ошибка", content: "Ошибка при вызове метода contract" } });
window.dispatchEvent(eventMessage);
dispatch({
type: actionTypes.DEAL_CONTRACTS_LIST,
data: {
deal_id,
list: []
}
});
reject();
});
});
}
export const attachDealDocument = ({ deal_id, document_id, document_name, group, index, lastModified, filename, file, type }) =>
{
return new Promise((resolve, reject) =>
{
let data = new FormData();
data.append('file', file);
const payload = new URLSearchParams({
deal_id,
document_id,
document_name,
group,
filename,
index,
lastModified,
type
});
axios.post(`${ process.env.NEXT_PUBLIC_SELF_API_HOST }/api/deals/file/attach?${ payload.toString() }`, data,
{
headers: {
"Content-Type": "multipart/form-data",
},
withCredentials: true,
})
.then(async (response) =>
{
console.log("ACTION", "deals", "attachDealDocument", "response.data", response.data);
resolve();
})
.catch((error) =>
{
console.error(error);
const eventMessage = new CustomEvent("_message", { detail: { type: "error", title: "Ошибка", content: "Ошибка при загрузке документа" } });
window.dispatchEvent(eventMessage);
reject();
});
});
}
export const removeDealDocument = ({ deal_id, group, index, }) =>
{
return new Promise((resolve, reject) =>
{
const payload = new URLSearchParams({
deal_id,
group,
index,
});
axios.post(`${ process.env.NEXT_PUBLIC_SELF_API_HOST }/api/deals/file/remove?${ payload.toString() }`, {},
{
withCredentials: true,
})
.then(async (response) =>
{
console.log("ACTION", "deals", "removeDocument", "response.data", response.data);
resolve();
})
.catch((error) =>
{
console.error(error);
const eventMessage = new CustomEvent("_message", { detail: { type: "error", title: "Ошибка", content: "Ошибка при удалении документа" } });
window.dispatchEvent(eventMessage);
reject();
});
});

323
actions/edoActions.js Normal file
View File

@ -0,0 +1,323 @@
import axios from 'axios';
import { Cookies } from 'react-cookie';
import Router from 'next/router';
import moment from 'moment';
import { nSQL } from "@nano-sql/core";
import { eachSeries } from 'async';
import * as actionTypes from '../constants/actionTypes';
import * as currentState from '../reducers/initialState';
export const getEDOOperatorList = ({ dispatch, update = false }) =>
{
const url = `${ process.env.NEXT_PUBLIC_SELF_API_HOST }/api/edo/operators`;
console.log("ACTION", "edo", "getEDOOperatorList()", { url });
return new Promise((resolve, reject) =>
{
axios.post(url, {}, {
withCredentials: true,
})
.then((response) =>
{
console.log("ACTION", "edo", "getEDOOperatorList()", "response", response.data);
/*
dispatch({
type: actionTypes.EDO_OPERATORS_LIST,
data: {
list: [
{
"box_name": "ООО С К \"МОНОЛИТ-РУ\"",
"box_id": "7785f775578d4646aea1d323e703065d@diadoc.ru"
}, {
"box_name": "ООО СК \"МОНОЛИТ-РУ\" (роуминг, ООО «Такском» (Файлер))",
"box_id": "b8fbc5c395f54deabe6b8d84a10921f0@diadoc.ru"
}
]
}
});
*/
dispatch({
type: actionTypes.EDO_OPERATORS_LIST,
data: {
operators: response.data.box_edo,
message: response.data.message,
}
});
resolve();
})
.catch((error) =>
{
console.error("ACTION", "edo", "getEDOOperatorList()", "ERROR");
console.error(error);
const eventMessage = new CustomEvent("_message", { detail: { type: "error", title: "Ошибка", content: "Ошибка при вызове метода GetEdoBox" } });
window.dispatchEvent(eventMessage);
dispatch({
type: actionTypes.EDO_OPERATORS_LIST,
data: {
operators: [],
message: "Невозможно получить список операторов ЭДО",
}
});
reject();
});
});
}
export const getEDOInvitesList = ({ dispatch, update = false }) =>
{
const url = `${ process.env.NEXT_PUBLIC_SELF_API_HOST }/api/edo/invites`;
console.log("ACTION", "edo", "getEDOInvitesList()", { url });
return new Promise((resolve, reject) =>
{
axios.post(url, {}, {
withCredentials: true,
})
.then((response) =>
{
console.log("ACTION", "edo", "getEDOInvitesList()", "response", response.data);
dispatch({
type: actionTypes.EDO_INVITES_LIST,
data: {
invites: response.data.box_edo
}
});
resolve();
})
.catch((error) =>
{
console.error("ACTION", "edo", "getEDOInvitesList()", "ERROR");
console.error(error);
const eventMessage = new CustomEvent("_message", { detail: { type: "error", title: "Ошибка", content: "Ошибка при вызове метода GetInviteEdoBox" } });
window.dispatchEvent(eventMessage);
dispatch({
type: actionTypes.EDO_INVITES_LIST,
data: {
invites: []
}
});
reject();
});
});
}
export const inviteToEDO = () =>
{
const url = `${ process.env.NEXT_PUBLIC_SELF_API_HOST }/api/edo/invite/send`;
console.log("ACTION", "edo", "inviteToEDO()", { url });
return new Promise((resolve, reject) =>
{
axios.post(url, {}, {
withCredentials: true,
})
.then((response) =>
{
console.log("ACTION", "edo", "inviteToEDO()", "response", response.data);
resolve(response.data);
})
.catch((error) =>
{
console.error("ACTION", "edo", "inviteToEDO()", "ERROR");
console.error(error);
const eventMessage = new CustomEvent("_message", { detail: { type: "error", title: "Ошибка", content: "Ошибка при вызове метода InviteEdoBox" } });
window.dispatchEvent(eventMessage);
reject(error.data);
});
});
}
export const createEDOProject = (payload) =>
{
const url = `${ process.env.NEXT_PUBLIC_SELF_API_HOST }/api/edo/project`;
console.log("ACTION", "edo", "createEDOProject()", { url });
return new Promise((resolve, reject) =>
{
axios.post(url, payload, {
withCredentials: true,
})
.then((response) =>
{
console.log("ACTION", "edo", "createEDOProject()", "response", response.data);
resolve(response.data);
})
.catch((error) =>
{
console.error("ACTION", "edo", "createEDOProject()", "ERROR");
console.error(error);
const eventMessage = new CustomEvent("_message", { detail: { type: "error", title: "Ошибка", content: "Ошибка при вызове метода CreateEDOProject" } });
window.dispatchEvent(eventMessage);
reject(error.data);
});
});
}
export const docEDOSign = (payload) =>
{
const url = `${ process.env.NEXT_PUBLIC_SELF_API_HOST }/api/edo/sign`;
if(parseInt(process.env.LOG, 10) === 1)
{
console.log("ACTION", "edo", "docEDOSign()", { url });
}
return new Promise((resolve, reject) =>
{
axios.post(url, payload, {
withCredentials: true,
})
.then((response) =>
{
if(parseInt(process.env.LOG, 10) === 1)
{
console.log("ACTION", "edo", "docEDOSign()", "response", response.data);
}
resolve(response.data);
})
.catch((error) =>
{
if(parseInt(process.env.LOG, 10) === 1)
{
console.error("ACTION", "edo", "docEDOSign()", "ERROR");
console.error(error);
}
const eventMessage = new CustomEvent("_message", { detail: { type: "error", title: "Ошибка", content: "Ошибка при вызове метода SignEDODocument" } });
window.dispatchEvent(eventMessage);
reject(error.data);
});
});
}
export const docEDOCancel = (payload) =>
{
const url = `${ process.env.NEXT_PUBLIC_SELF_API_HOST }/api/edo/cancel`;
console.log("ACTION", "edo", "docEDOCancel()", { url });
return new Promise((resolve, reject) =>
{
axios.post(url, payload, {
withCredentials: true,
})
.then((response) =>
{
console.log("ACTION", "edo", "docEDOCancel()", "response", response.data);
resolve(response.data);
})
.catch((error) =>
{
console.error("ACTION", "edo", "docEDOCancel()", "ERROR");
console.error(error);
const eventMessage = new CustomEvent("_message", { detail: { type: "error", title: "Ошибка", content: "Ошибка при вызове метода CancelDocument" } });
window.dispatchEvent(eventMessage);
reject(error.data);
});
});
}
export const docEDOConnect = (payload) =>
{
const url = `${ process.env.NEXT_PUBLIC_SELF_API_HOST }/api/contract/sign/document/connect`;
if(parseInt(process.env.LOG, 10) === 1)
{
console.log("ACTION", "edo", "docEDOConnect()", { url });
}
return new Promise((resolve, reject) =>
{
axios.post(url, payload, {
withCredentials: true,
})
.then((response) =>
{
if(parseInt(process.env.LOG, 10) === 1)
{
console.log("ACTION", "edo", "docEDOConnect()", "response", response.data);
}
resolve(response.data);
})
.catch((error) =>
{
if(parseInt(process.env.LOG, 10) === 1)
{
console.error("ACTION", "edo", "docEDOConnect()", "ERROR");
console.error(error);
}
const eventMessage = new CustomEvent("_message", { detail: { type: "error", title: "Ошибка", content: "Ошибка при вызове метода DocEdoConnect" } });
window.dispatchEvent(eventMessage);
reject(error.data);
});
});
}
export const docEDOStatus = (payload) =>
{
const url = `${ process.env.NEXT_PUBLIC_SELF_API_HOST }/api/contract/sign/document/status`;
if(parseInt(process.env.LOG, 10) === 1)
{
console.log("ACTION", "edo", "docEDOStatus()", { url });
}
return new Promise((resolve, reject) =>
{
axios.post(url, payload, {
withCredentials: true,
})
.then((response) =>
{
if(parseInt(process.env.LOG, 10) === 1)
{
console.log("ACTION", "edo", "docEDOStatus()", "response", response.data);
}
resolve(response.data);
})
.catch((error) =>
{
if(parseInt(process.env.LOG, 10) === 1)
{
console.error("ACTION", "edo", "docEDOStatus()", "ERROR");
console.error(error);
}
const eventMessage = new CustomEvent("_message", { detail: { type: "error", title: "Ошибка", content: "Ошибка при вызове метода GetEdoProjectID" } });
window.dispatchEvent(eventMessage);
reject(error.data);
});
});
}

View File

@ -5,6 +5,7 @@ import moment from 'moment';
import fileDownload from 'js-file-download';
import * as actionTypes from '../constants/actionTypes';
import { logDocumentAccess } from './logsActions';
if(process.browser)
{
@ -66,8 +67,6 @@ export const getFile = ({ id, filename }) =>
})
.catch((error) =>
{
//console.log("error");
console.error(error);
reject();
@ -166,6 +165,14 @@ export const getReconciliationFile = ({ contract, date_from, date_to, filename }
.then((response) =>
{
fileDownload(response.data, filename);
logDocumentAccess({
contract_number: contract,
document_name: "Акт сверки по ДЛ",
document_type: "act_bu",
document_period_from: date_from,
document_period_to: date_to,
});
resolve();
})
.catch((error) =>

View File

@ -14,4 +14,6 @@ export * from './adminActions';
export * from './suggestsActions';
export * from './questionnaireActions';
export * from './feedbackActions';
export * from './dealsActions';
export * from './dealsActions';
export * from './edoActions';
export * from './signActions';

40
actions/logsActions.js Normal file
View File

@ -0,0 +1,40 @@
import axios from 'axios';
import { Cookies } from 'react-cookie';
import Router from 'next/router';
import moment from 'moment';
import { nSQL } from "@nano-sql/core";
import { eachSeries } from 'async';
import * as actionTypes from '../constants/actionTypes';
import * as currentState from '../reducers/initialState';
export const logDocumentAccess = (payload) =>
{
const url = `${ process.env.NEXT_PUBLIC_SELF_API_HOST }/api/logs/track`;
console.log("ACTION", "deals", "logDocumentAccess()", { url });
console.log("ACTION", "deals", "logDocumentAccess()", { payload });
return new Promise((resolve, reject) =>
{
payload.lk_user_id = global.store.getState().user.email;
payload.acc_number = global.store.getState().company.active;
axios.post(url, [ payload ], {
withCredentials: true,
})
.then((response) =>
{
console.log("ACTION", "deals", "logDocumentAccess()", "response", response.data);
resolve();
})
.catch((error) =>
{
console.error("ACTION", "deals", "logDocumentAccess()", "ERROR");
console.error(error);
reject();
});
});
}

View File

@ -9,6 +9,7 @@ import { eachSeries, each } from "async";
import * as actionTypes from '../constants/actionTypes';
import { getCitizenshipTitleByCode } from '../utils/citizenship';
import { questionnaire_template } from '../reducers/initialState';
import { getCompanyInfo } from './companyActions';
if(process.browser)
{
@ -26,11 +27,28 @@ if(process.browser)
};
}
export const createQuestionnaire = (deal_id) =>
{
return new Promise((resolve, reject) =>
{
axios.post(`${ process.env.NEXT_PUBLIC_SELF_API_HOST }/api/questionnaire/create`, { deal_id }, {
withCredentials: true,
})
.then(() => {}).catch(() => {}).finally(() =>
{
getCompanyInfo({ dispatch: global.store.dispatch })
.then(() => {}).catch(() => {}).finally(() =>
{
resolve();
});
});
});
}
export const getQuestionnaire = ({ dispatch, id }) =>
{
//console.log("ACTION", "support", "getAppeals()", `${ process.env.NEXT_PUBLIC_SELF_API_HOST }/api/questionnaire/get`);
return new Promise((resolve, reject) =>
{
axios.get(`${ process.env.NEXT_PUBLIC_SELF_API_HOST }/api/questionnaire/read`, {})

339
actions/signActions.js Normal file
View File

@ -0,0 +1,339 @@
import axios from 'axios';
import { Cookies } from 'react-cookie';
import Router from 'next/router';
import moment from 'moment';
import { nSQL } from "@nano-sql/core";
import { concatSeries, eachSeries } from 'async';
import fileDownload from 'js-file-download';
import * as actionTypes from '../constants/actionTypes';
import * as currentState from '../reducers/initialState';
export const signCheckCreatePrintForm = (payload) =>
{
const url = `${ process.env.NEXT_PUBLIC_SELF_API_HOST }/api/contract/sign/check`;
console.log("ACTION", "sign", "signCheckCreatePrintForm()", { url });
return new Promise((resolve, reject) =>
{
axios.post(url, payload, {
withCredentials: true,
})
.then((response) =>
{
console.log("ACTION", "sign", "signCheckCreatePrintForm()", "response", response.data);
resolve(response.data);
})
.catch((error) =>
{
console.error("ACTION", "sign", "signCheckCreatePrintForm()", "ERROR");
console.error(error);
const eventMessage = new CustomEvent("_message", { detail: { type: "error", title: "Ошибка", content: "Ошибка при вызове метода CheckCreatePrintForm" } });
window.dispatchEvent(eventMessage);
reject(error.data);
});
});
}
export const signGetGUIDEntity = (payload) =>
{
const url = `${ process.env.NEXT_PUBLIC_SELF_API_HOST }/api/contract/sign/entity`;
console.log("ACTION", "sign", "signGetGUIDEntity()", { url });
return new Promise((resolve, reject) =>
{
axios.post(url, payload, {
withCredentials: true,
})
.then((response) =>
{
console.log("ACTION", "sign", "signGetGUIDEntity()", "response", response.data);
resolve(response.data);
})
.catch((error) =>
{
console.error("ACTION", "sign", "signGetGUIDEntity()", "ERROR");
console.error(error);
const eventMessage = new CustomEvent("_message", { detail: { type: "error", title: "Ошибка", content: "Ошибка при вызове метода GetGUIDEntity" } });
window.dispatchEvent(eventMessage);
resolve(response.data);
});
});
}
export const signCheckPowerAttorneyClient = (payload) =>
{
const url = `${ process.env.NEXT_PUBLIC_SELF_API_HOST }/api/contract/sign/attorney/check`;
return new Promise((resolve, reject) =>
{
axios.post(url, payload, {
withCredentials: true,
})
.then((response) =>
{
console.log("ACTION", "sign", "signCheckPowerAttorneyClient()", "response", response.data);
resolve(response.data);
})
.catch((error) =>
{
console.error("ACTION", "sign", "signCheckPowerAttorneyClient()", "ERROR");
console.error(error);
const eventMessage = new CustomEvent("_message", { detail: { type: "error", title: "Ошибка", content: "Ошибка при вызове метода CheckPowerAttorneyClient" } });
window.dispatchEvent(eventMessage);
reject(error.data);
});
});
}
export const signGetPowerAttorneyClient = (payload) =>
{
const url = `${ process.env.NEXT_PUBLIC_SELF_API_HOST }/api/contract/sign/attorney/get`;
return new Promise((resolve, reject) =>
{
axios.post(url, payload, {
withCredentials: true,
})
.then((response) =>
{
console.log("ACTION", "sign", "signGetPowerAttorneyClient()", "response", response.data);
resolve(response.data);
})
.catch((error) =>
{
console.error("ACTION", "sign", "signGetPowerAttorneyClient()", "ERROR");
console.error(error);
const eventMessage = new CustomEvent("_message", { detail: { type: "error", title: "Ошибка", content: "Ошибка при вызове метода GetPowerAttorneyClient" } });
window.dispatchEvent(eventMessage);
reject(error.data);
});
});
}
export const signGetWMDoc = (payload) =>
{
const url = `${ process.env.NEXT_PUBLIC_SELF_API_HOST }/api/contract/sign/document/create`;
return new Promise((resolve, reject) =>
{
axios.post(url, payload, {
withCredentials: true,
})
.then((response) =>
{
console.log("ACTION", "sign", "signGetWMDoc()", "response", response.data);
resolve(response.data);
})
.catch((error) =>
{
console.error("ACTION", "sign", "signGetWMDoc()", "ERROR");
console.error(error);
const eventMessage = new CustomEvent("_message", { detail: { type: "error", title: "Ошибка", content: "Ошибка при вызове метода GetWMDoc" } });
window.dispatchEvent(eventMessage);
reject(error.data);
});
});
}
export const signDownloadFile = ({ payload, filename }) =>
{
const url = `${ process.env.NEXT_PUBLIC_SELF_API_HOST }/api/contract/sign/document/download`;
return new Promise((resolve, reject) =>
{
axios.get(url, {
params: payload,
responseType: 'blob',
})
.then((response) =>
{
fileDownload(response.data, filename);
resolve();
})
.catch((error) =>
{
console.error("ACTION", "sign", "signDownloadFile()", "ERROR");
console.error(error);
const eventMessage = new CustomEvent("_message", { detail: { type: "error", title: "Ошибка", content: "Ошибка при вызове метода GetWMDoc" } });
window.dispatchEvent(eventMessage);
reject(error.data);
});
});
}
export const signGetFileContractProject = (payload) =>
{
const url = `${ process.env.NEXT_PUBLIC_SELF_API_HOST }/api/contract/sign/document/link`;
return new Promise((resolve, reject) =>
{
axios.post(url, payload, {
withCredentials: true,
})
.then((response) =>
{
if(parseInt(process.env.LOG, 10) === 1) { console.log("ACTION", "sign", "signGetFileContractProject()", "response", response.data); }
resolve(response.data);
})
.catch((error) =>
{
console.error("ACTION", "sign", "signGetFileContractProject()", "ERROR");
console.error(error);
const eventMessage = new CustomEvent("_message", { detail: { type: "error", title: "Ошибка", content: "Ошибка при вызове метода GetFileContractProject" } });
window.dispatchEvent(eventMessage);
reject(error.data);
});
});
}
export const signCheckDownloadContractProject = (payload) =>
{
const url = `${ process.env.NEXT_PUBLIC_SELF_API_HOST }/api/contract/sign/document/check`;
return new Promise((resolve, reject) =>
{
axios.post(url, payload, {
withCredentials: true,
})
.then((response) =>
{
if(parseInt(process.env.LOG, 10) === 1) { console.log("ACTION", "sign", "signCheckDownloadContractProject()", "response", response.data); }
resolve(response.data);
})
.catch((error) =>
{
console.error("ACTION", "sign", "signCheckDownloadContractProject()", "ERROR");
console.error(error);
const eventMessage = new CustomEvent("_message", { detail: { type: "error", title: "Ошибка", content: "Ошибка при вызове метода CheckDownloadContractProject" } });
window.dispatchEvent(eventMessage);
reject(error.data);
});
});
}
export const signUploadPaperDocument = (contract_number, deal_id, files) =>
{
console.log({ contract_number, files });
const url = `${ process.env.NEXT_PUBLIC_SELF_API_HOST }/api/contract/sign/document/upload`;
return new Promise((resolve, reject) =>
{
let data = new FormData();
data.append('contract_number', contract_number);
data.append('deal_id', deal_id);
for(let i in files)
{
data.append('files', files[i]);
}
axios.post(url, data, {
headers: {
"Content-Type": "multipart/form-data",
},
withCredentials: true,
})
.then((response) =>
{
if(parseInt(process.env.LOG, 10) === 1) { console.log("ACTION", "sign", "signUploadPaperDocument()", "response", response.data); }
setTimeout(() =>
{
resolve();
}, 2000);
})
.catch((error) =>
{
console.error("ACTION", "sign", "signUploadPaperDocument()", "ERROR");
console.error(error);
const eventMessage = new CustomEvent("_message", { detail: { type: "error", title: "Ошибка", content: "Ошибка при отправке подписанного пакета документов" } });
window.dispatchEvent(eventMessage);
reject(error.data);
});
});
}
export const signCheckCancelDocument = (payload) =>
{
const url = `${ process.env.NEXT_PUBLIC_SELF_API_HOST }/api/contract/sign/cancel/check`;
console.log("ACTION", "sign", "signCheckCancelDocument()", { url });
return new Promise((resolve, reject) =>
{
axios.post(url, payload, {
withCredentials: true,
})
.then((response) =>
{
console.log("ACTION", "sign", "signCheckCancelDocument()", "response", response.data);
resolve(response.data);
})
.catch((error) =>
{
console.error("ACTION", "sign", "signCheckCancelDocument()", "ERROR");
console.error(error);
const eventMessage = new CustomEvent("_message", { detail: { type: "error", title: "Ошибка", content: "Ошибка при вызове метода CheckCancelDocument" } });
window.dispatchEvent(eventMessage);
reject(error.data);
});
});
}
export const signCancelDocument = (payload) =>
{
const url = `${ process.env.NEXT_PUBLIC_SELF_API_HOST }/api/contract/sign/cancel`;
console.log("ACTION", "sign", "signCancelDocument()", { url });
return new Promise((resolve, reject) =>
{
axios.post(url, payload, {
withCredentials: true,
})
.then((response) =>
{
console.log("ACTION", "sign", "signCancelDocument()", "response", response.data);
resolve(response.data);
})
.catch((error) =>
{
console.error("ACTION", "sign", "signCancelDocument()", "ERROR");
console.error(error);
const eventMessage = new CustomEvent("_message", { detail: { type: "error", title: "Ошибка", content: "Ошибка при вызове метода CancelDocument" } });
window.dispatchEvent(eventMessage);
reject(error.data);
});
});
}

View File

@ -7,25 +7,65 @@ export default class DealsList extends React.Component
constructor(props)
{
super(props);
this.list_ref = React.createRef();
this.items_ref = [];
}
_scrollToDeal = (index) =>
{
const element = this.list_ref.current.children[index];
const y = (element.getBoundingClientRect().top + window.scrollY - 90);
window.scrollTo({top: y, behavior: 'smooth'});
}
_handle_onSelectDeal = (deal_id, index) =>
{
const { onSelectDeal } = this.props;
onSelectDeal(deal_id);
setTimeout(() =>
{
this._scrollToDeal(index);
}, 50);
}
_handle_onCloseDeal = () =>
{
const { onCloseDeal } = this.props;
onCloseDeal();
setTimeout(() =>
{
const element = this.list_ref.current;
const y = (element.getBoundingClientRect().top + window.scrollY - 160);
window.scrollTo({top: y, behavior: 'smooth'});
}, 50);
}
render()
{
const { deals, dealSelected } = this.props;
console.log({ deals });
const { status, deals, questionnaire_status, dealSelected, onCloseDeal, onDealsUpdate, onDealContractsUpdate, onQuestionnaire } = this.props;
return (
<div className="contractStatus_list">
<div className="contractStatus_list" ref={ this.list_ref }>
{ deals.list !== undefined && deals.list !== null && deals.list.map((deal, index) =>
{
if(index === dealSelected)
if(dealSelected === deal.opp_number)
{
return (<SingleDeal
router={ this.props.router }
key={ index }
close={() => {
this._handleModalToggle("current")
}}
index={ index }
ref={ ref => this.items_ref[index] = ref }
status={ status }
dealSelected={ dealSelected }
deals={ deals }
questionnaire_status={ questionnaire_status }
onFocusDeal={ () => this._scrollToDeal(index) }
onCloseDeal={ this._handle_onCloseDeal }
onDealsUpdate={ onDealsUpdate }
onDealContractsUpdate={ onDealContractsUpdate }
onQuestionnaire={ onQuestionnaire }
{ ...deal }
/>)
}
else
@ -34,7 +74,9 @@ export default class DealsList extends React.Component
<DealsListDeal
key={ index }
index={ index }
ref={ ref => this.items_ref[index] = ref }
{ ...deal }
onSelectDeal={ this._handle_onSelectDeal }
/>
)
}

View File

@ -1,12 +1,48 @@
import React from "react";
import pluralize from 'pluralize-ru';
const statuses = [
{
const statuses = {
"100": {
index: undefined,
title: "Выбор КП",
icon: "/assets/images/status/icon_deal_status_100.svg",
},
"101": {
index: 1,
title: "Выбор программы финансирования",
icon: "/assets/images/status/icon_deal_status_101.svg",
},
"102": {
index: 2,
title: "Сбор пакета документов",
icon: "/assets/images/status/1.svg",
}
];
icon: "/assets/images/status/icon_deal_status_102.svg",
},
"103": {
index: 3,
title: "Проверка документов",
icon: "/assets/images/status/icon_deal_status_103.svg",
},
"104": {
index: 4,
title: "Принятие решения по сделке",
icon: "/assets/images/status/icon_deal_status_104.svg",
},
"105": {
index: 5,
title: "Требуется изменение параметров",
icon: "/assets/images/status/icon_deal_status_105.svg",
},
"106": {
index: 5,
title: "Принято положительное решение",
icon: "/assets/images/status/icon_deal_status_106.svg",
},
"107": {
index: 6,
title: "Оформление лизинга",
icon: "/assets/images/status/icon_deal_status_107.svg",
},
};
export default class DealsListDeal extends React.Component
{
@ -15,21 +51,21 @@ export default class DealsListDeal extends React.Component
super(props)
}
//getDealOffers
render()
{
const { index, comment, opp_number, statuscode_id, statuscode_name } = this.props;
const { onSelectDeal, index, comment, opp_number, statuscode_id, statuscode_name } = this.props;
const step = statuscode_id - 100;
console.log("deal list item", { props: this.props });
return (
<div className="list_item">
<div>
<p>Сделка { index + 1 }</p>
<p> { opp_number }</p>
</div>
<div>
<p>
{ step === 0 ? "Не начата" : `${ step } ${ pluralize(step, 'этапа', 'этап', 'этапа', 'этапов') } ${ pluralize(step, 'пройдено', 'пройден', 'пройдено', 'пройдено') }` }
{ statuses[ statuscode_id ].index === undefined ? "Новая сделка" : `${ statuses[ statuscode_id ].index } ${ pluralize(step, 'этапа', 'этап', 'этапа', 'этапов') } ${ pluralize(statuses[ statuscode_id ].index, 'пройдено', 'пройден', 'пройдено', 'пройдено') }` }
{/*}
<svg xmlns="http://www.w3.org/2000/svg" width={18} height={18} fill="none">
<path stroke="#8E94A7" strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M14.625 6.75 9 12.375 3.375 6.75" />
@ -38,12 +74,17 @@ export default class DealsListDeal extends React.Component
</p>
</div>
<div>
<img src="/assets/images/status/1.svg" width="50" height="50" />
<p>Сбор пакета документов</p>
<img src={ statuses[ statuscode_id ].icon } width="50" height="50" />
{/*}<p>{ statuscode_name }</p>{*/}
<p>{ statuses[ statuscode_id ].title }</p>
</div>
<div>
<button className="button" onClick={() => { this._handleModalToggle("all") }} >
Еще 4 этапа
<button className="button" onClick={() => { onSelectDeal(opp_number, index) }} >
{ statuscode_id === 105 || statuscode_id === 107 ? (
"Подробнее"
) : (
<>Еще { statuses[ statuscode_id ].index !== undefined ? (6 - statuses[ statuscode_id ].index) : 6 } { pluralize(statuses[ statuscode_id ].index !== undefined ? (6 - statuses[ statuscode_id ].index) : 6, 'этапа', 'этап', 'этапа', 'этапов') }</>
) }
<svg xmlns="http://www.w3.org/2000/svg" width={18} height={18} fill="none">
<path stroke="#1C01A9" strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M14.625 6.75 9 12.375 3.375 6.75" />
</svg>

View File

@ -1,17 +1,38 @@
import React from "react"
import React from "react";
import Offers from "./components/Offers";
import FinancialProgram from "./components/FinancialProgram";
import DocumentsForm from "./components/DocumentsForm";
import StatusDocumentsCheck from "./components/StatusDocumentsCheck";
import StatusDecisionMaking from "./components/StatusDecisionMaking";
import StatusDecisionRefuse from "./components/StatusDecisionRefuse";
import StatusPositiveDecision from "./components/StatusPositiveDecision";
import LeasingRegistration from "./components/LeasingRegistration";
export default class SingleDeal extends React.Component
{
constructor(props)
{
super(props);
this.leasing_registration_ref = React.createRef();
}
_onDealContractsUpdate = () =>
{
const { onDealContractsUpdate, dealSelected } = this.props;
onDealContractsUpdate(dealSelected);
}
render()
{
const { close } = this.props;
const { index, status, deals, dealSelected, onCloseDeal, } = this.props;
return (
const offers = deals.details[ dealSelected ] !== undefined ? deals.details[ dealSelected ].offers : undefined;
const documents = deals.details[ dealSelected ] !== undefined ? deals.details[ dealSelected ].documents : undefined;
const uploaded = deals.details[ dealSelected ] !== undefined ? deals.details[ dealSelected ].uploaded : undefined;
const contracts = deals.details[ dealSelected ] !== undefined ? deals.details[ dealSelected ].contracts : undefined;
return (
<div className="contractStatus_modal">
{/*}
<div className="modal_header">
@ -20,287 +41,18 @@ export default class SingleDeal extends React.Component
</div>
{*/}
<div className="modal_body single_status">
<div className="current">
<p>Сделка 1</p>
<span></span>
<div className="status_body">
<div className="status_header">
<i className="status_1"></i>
<p>Выбор КП</p>
</div>
<div className="wrap">
<table>
<thead>
<tr>
<th></th>
<th></th>
<th>Стоимость</th>
<th>Первый платеж, р.</th>
<th>Первый платеж, %</th>
<th>Марка</th>
<th>Модель</th>
<th>Объектов лизинга</th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td>
<div className="form_field checkbox">
<input type="checkbox" name="row" id="row" checked="" onChange={ () => {} }/>
<label htmlFor="row"></label>
</div>
</td>
<td>1</td>
<td>5 600 000 р.</td>
<td>560 000 р.</td>
<td>10 %</td>
<td>Audi</td>
<td>A8</td>
<td>1</td>
<td>
<div className="dosc_list">
<div className="row">
<div className="small-icon">
<p className="doc_name i-pdf">
КП
<span>1</span>
</p>
</div>
</div>
</div>
</td>
</tr>
<tr>
<td>
<div className="form_field checkbox">
<input type="checkbox" name="row" id="row" checked="" onChange={ () => {} }/>
<label htmlFor="row"></label>
</div>
</td>
<td>1</td>
<td>5 600 000 р.</td>
<td>560 000 р.</td>
<td>10 %</td>
<td>Audi</td>
<td>A8</td>
<td>1</td>
<td>
<div className="dosc_list">
<div className="row">
<div className="small-icon">
<p className="doc_name i-pdf">
КП
<span>1</span>
</p>
</div>
</div>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div>
<p>Сделка 1</p>
<span></span>
<div className="status_body">
<div className="status_header">
<i className="status_2"></i>
<p className="header">Программа финансирования</p>
</div>
<div className="wrap">
<div className="single_text">
<p>Статусный текст о том что выбирается программа финансированияи может быть по центру иконочка часиков или слева от статусного текста иконочка часиков</p>
</div>
</div>
</div>
</div>
<div>
<p>Сделка 1</p>
<span></span>
<div className="status_body">
<div className="status_header">
<i className="status_3"></i>
<p>Сборка пакета документов</p>
</div>
<div className="wrap">
<div className="message ok">
<p>Вам не требуется актуализация данных анкеты Клиента</p>
</div>
<div className="message alert">
<p>Требуется обновить данные в анкете</p>
<button className="button button-blue">Актуализировать данные</button>
</div>
<div className="message wait">
<p>Проводится проверка анкеты Вашей организации</p>
</div>
<p><b>Устав организации</b></p>
<div className="attach_file">
<label>
<input type="file" hidden onChange={ () => {} }/>
Прикрепить скан документов
</label>
</div>
<div className="message documents">
<div className="doc_list">
<div className="dosc_list medium-icon">
<div className="row">
<p className="doc_name i-pdf i-medium">123/2023 от 01.01.2023</p>
</div>
</div>
<div className="dosc_list medium-icon">
<div className="row">
<p className="doc_name i-pdf i-medium">123/2023 от 01.01.2023</p>
</div>
</div>
</div>
<p>Документы, отправленные Вами принадлежат другой организации бла бла коммент от менеджера</p>
</div>
<div className="attach_file">
<label>
<input type="file" hidden onChange={ () => {} }/>
Прикрепить ещё
</label>
</div>
<p><b>Другое название документа</b></p>
<div className="attach_file">
<label>
<input type="file" hidden onChange={ () => {} }/>
Прикрепить скан документов
</label>
</div>
</div>
</div>
</div>
<div className="">
<p>Сделка 1</p>
<span></span>
<div className="status_body">
<div className="status_header">
<i className="status_4"></i>
<p>Проверка документов</p>
</div>
<div className="wrap">
<div className="single_text">
<p>Статусный текст о том что выбирается программа финансированияи может быть по центру иконочка часиков или слева от статусного текста иконочка часиков</p>
</div>
</div>
</div>
</div>
<div>
<p>Сделка 1</p>
<span></span>
<div className="status_body">
<div className="status_header">
<i className="status_5"></i>
<p>Принятие решения по заявке</p>
</div>
<div className="wrap">
<div className="single_text">
<p>Статусный текст о том что выбирается программа финансированияи может быть по центру иконочка часиков или слева от статусного текста иконочка часиков</p>
</div>
</div>
</div>
</div>
<div>
<p>Сделка 1</p>
<span></span>
<div className="status_body">
<div className="status_header">
<i className="status_6"></i>
<p>Оформление лизинга</p>
</div>
<div className="wrap">
<div className="single_text">
<p>Статусный текст о том что выбирается программа финансированияи может быть по центру иконочка часиков или слева от статусного текста иконочка часиков</p>
</div>
</div>
</div>
</div>
<div>
<p>Сделка 1</p>
<span></span>
<div className="status_body">
<div className="status_header">
<i className="status_7"></i>
<p>Выбор типа подписания</p>
</div>
<div className="wrap">
<div className="block-column">
<div className="dropdown_block open" >
<div className="block_header default">
<p><b>Подготовлено 3 из 12</b></p>
</div>
</div>
<div className="dosc_list acts_list-checkbox medium-icon">
<div className="row">
<p className="doc_name i-doc i-medium" >
<input type="checkbox" name="" id="" checked="" onChange={ () => {} }/>
<label htmlFor="">2022_6875 от 28.06.2022</label>
</p>
</div>
</div>
<div className="block_footer_btn">
<button className="button button-blue">Подписать в ЭДО</button>
<button className="button button-blue">Подписать в бумажном виде</button>
</div>
</div>
<div className="block-column">
<div className="dropdown_block open" >
<div className="block_header default">
<p><b>К подписанию 3 из 12</b></p>
</div>
</div>
<div className="dosc_list medium-icon">
<div className="row flex-start">
<p className="doc_name i-doc i-medium" >
123/2023 от 01.01.2023
</p>
<button className="button">Перейти в ЭДО</button>
</div>
<div className="row flex-start">
<p className="doc_name i-doc i-medium" >
123/2023 от 01.01.2023
</p>
<button className="button">Скачать документ</button>
<button className="button">Загрузить подписанный экземпляр</button>
</div>
</div>
</div>
<div className="block-column">
<div className="dropdown_block open" >
<div className="block_header default">
<p><b>Подписано 3 из 12</b></p>
</div>
</div>
<div className="dosc_list medium-icon">
<div className="row">
<p className="doc_name i-doc i-medium" >
<a href="#">Скачать 129/2023 от 01.01.2023 - Ожидание оплаты</a>
</p>
</div>
</div>
</div>
<div className="block-column">
<div className="dropdown_block open">
<div className="block_header default">
<p><b>Подготовлено 3 из 12</b></p>
</div>
</div>
<div className="dosc_list medium-icon">
<div className="row">
<p className="doc_name i-doc i-medium">
123/2023 от 01.01.2023
</p>
</div>
</div>
</div>
</div>
</div>
</div>
<Offers { ...this.props } offers={ offers }/>
<FinancialProgram { ...this.props }/>
<DocumentsForm { ...this.props } documents={ documents } uploaded={ uploaded }/>
<StatusDocumentsCheck { ...this.props }/>
<StatusDecisionMaking { ...this.props }/>
<StatusDecisionRefuse { ...this.props }/>
<StatusPositiveDecision { ...this.props }/>
<LeasingRegistration { ...this.props } contracts={ contracts } onDealContractsUpdate={ this._onDealContractsUpdate }/>
</div>
<div className="bottom_button_close" onClick={ onCloseDeal } >
<span>Свернуть</span>
<div className="icon"></div>
</div>
</div>
)

View File

@ -0,0 +1,592 @@
import React from "react";
import { connect } from "react-redux";
import moment from "moment";
import { SpinnerCircular } from "spinners-react";
import { concatSeries } from "async";
import { eachSeries } from 'async';
import Select from 'react-select';
import { createEDOProject, signCheckCreatePrintForm, signCheckPowerAttorneyClient, signDownloadFile, signGetGUIDEntity, signGetPowerAttorneyClient, signGetWMDoc, docEDOSign, docEDOStatus, docEDOConnect, getFile, signGetFileContractProject, signCheckCancelDocument, signCancelDocument } from "../../../actions";
class DealContractsSignEDO extends React.Component
{
constructor(props)
{
super(props)
this.state = {
finished: false,
operators: null,
edo_message: null,
loading: false,
disabled: false,
documents: [],
operator_selected: {},
statuses: {},
step: 0,
}
}
static getDerivedStateFromProps(nextProps, prevState)
{
return {
operators: nextProps.operators,
edo_message: nextProps.edo_message,
}
}
componentDidMount()
{
const docs = [];
for(let i in this.props.documents)
{
docs.push({ ...this.props.documents[i], ...{ index: i, loading: true, ready: false, attorney: false } });
}
this.setState({ documents: docs });
if(this.state.operator_selected.box_id === undefined)
{
this.setState({ operator_selected: this.state.operators !== null && this.state.operators[0] !== undefined ? this.state.operators[0] : {} });
}
}
_updateDocs = (id, update) =>
{
return new Promise((resolve) =>
{
const docs = [ ...this.state.documents ];
docs[ id ] = { ...docs[id], ...update };
this.setState({ documents: docs }, () =>
{
resolve();
});
});
}
_checkDocumentsCompleted = () =>
{
const { documents } = this.state;
let completed = true;
for(let i in documents)
{
if(!documents[i].error && !documents[i].completed)
{
completed = false;
break;
}
}
return completed;
}
_sign = () =>
{
const { operator_selected, step } = this.state;
const documents = [ ...this.state.documents ];
this.setState({ loading: true }, () =>
{
eachSeries(documents, async (document, callback) =>
{
if(document.completed)
{
callback();
}
else if(document.signing)
{
await this._updateDocs(document.index, { loading: true, });
const status_result = await docEDOStatus({ contract_number: document.id });
if(status_result.status === 3)
{
await this._updateDocs(document.index, { loading: false, signing: false, ready: false, completed: true, });
}
else
{
await this._updateDocs(document.index, { loading: false, signing: true, ready: false, });
}
callback();
}
else if(document.ready)
{
await this._updateDocs(document.index, { loading: true, });
const status_result = await docEDOStatus({ contract_number: document.id });
if(status_result.status > 0)
{
const sign_result = await docEDOSign({ edoid: status_result.edoid });
}
await this._updateDocs(document.index, { loading: false, signing: true, ready: false, error: false, });
callback();
}
else
{
await this._updateDocs(document.index, { loading: true });
if(document.attorney && document.attorney_selected !== undefined)
{
const create_edo_project_result = await createEDOProject({
contract_number: document.id,
power_attorney: document.attorney_selected.value,
power_attorney_number: document.attorney_selected.label,
edo_box: operator_selected.edo_box,
});
const get_guid_entity_result = await signGetGUIDEntity({
contract_number: document.id,
});
const wmdoc_result = await signGetWMDoc({
entity_name: "evo_contract",
entity_id: get_guid_entity_result.entityid,
sign_type: "EDO",
evo_id: "144",
code: "Leas_Contract",
});
const connect_result = await docEDOConnect({ contract_number: document.id });
await this._updateDocs(document.index, {
entity_id: get_guid_entity_result.entityid,
ready: true,
loading: false,
attorney: false,
});
callback();
}
else
{
const create_print_form_result = await signCheckCreatePrintForm({ contract_number: document.id, sign_type: "EDO" });
const docs = { status: create_print_form_result.status };
if(create_print_form_result.status !== "success")
{
docs.loading = false;
docs.error = true;
docs.ready = true;
docs.message = create_print_form_result.message;
}
await this._updateDocs(document.index, docs);
if(create_print_form_result.status === "success")
{
const check_attorney_client_result = await signCheckPowerAttorneyClient({ contract_number: document.id })
await this._updateDocs(document.index, { attorney: check_attorney_client_result.power_attorney_required, });
if(check_attorney_client_result.power_attorney_required)
{
const get_attorney_client_result = await signGetPowerAttorneyClient({ contract_number: document.id });
if(get_attorney_client_result === null)
{
await this._updateDocs(document.index, { loading: false, error: true, ready: true, message: "Возникла ошибка при создании документа для подписания." });
callback();
}
else
{
if(get_attorney_client_result.length === null)
{
await this._updateDocs(document.index, { loading: false, error: true, ready: true, message: "Не обнаружена доверенность на подписанта. Для продолжения подписания обратитесь к своему персональному менеджеру" });
callback();
}
else
{
const attorneys = [];
for(let i in get_attorney_client_result)
{
attorneys.push({
value: get_attorney_client_result[i].power_attorney,
label: get_attorney_client_result[i].power_attorney_number,
});
}
await this._updateDocs(document.index, { loading: false, error: false, attorneys, attorney_selected: undefined });
callback();
}
}
}
else
{
const create_edo_project_result = await createEDOProject({
contract_number: document.id,
edo_box: operator_selected.edo_box,
});
const get_guid_entity_result = await signGetGUIDEntity({
contract_number: document.id,
});
const wmdoc_result = await signGetWMDoc({
entity_name: "evo_contract",
entity_id: get_guid_entity_result.entityid,
sign_type: "EDO",
evo_id: "144",
});
const connect_result = await docEDOConnect({ contract_number: document.id });
await this._updateDocs(document.index, {
entity_id: get_guid_entity_result.entityid,
ready: true,
loading: false,
attorney: false,
});
callback();
}
}
else
{
await this._updateDocs(document.index, {
loading: false,
error: true,
ready: true,
message: create_print_form_result.message !== undefined && create_print_form_result.message !== null ? create_print_form_result.message : "Возникла ошибка при создании документа для подписания.",
});
callback();
}
}
}
}, () =>
{
if(this._checkDocumentsCompleted())
{
this.setState({ loading: false, disabled: false, finished: true, });
}
else
{
this.setState({ loading: false, disabled: false, finished: false, });
}
});
});
}
_handle_onFormSubmit = (event) =>
{
event.preventDefault();
const { onFinish, onGoToEDOInvites } = this.props;
const { operators, operator_selected, step, finished } = this.state;
if(operators !== null && operators.length === 0)
{
onGoToEDOInvites();
}
else
{
if(finished)
{
onFinish();
}
else
{
switch(step)
{
case 0:
{
this.setState({ step: 1 }, () =>
{
this._sign();
});
}
break;
case 1:
{
this._sign();
}
break;
}
}
}
}
_handle_onSelectOperator = (operator) =>
{
this.setState({ operator_selected: operator });
}
_handle_onAttorneyChange = (index, attorney) =>
{
this._updateDocs(index, { attorney_selected: attorney });
}
_handle_onDownloadFile = (index) =>
{
const { documents } = this.state;
this.setState({ loading: true, disabled: true, }, async () =>
{
await this._updateDocs(index, { loading: true });
const link_result = await signGetFileContractProject({
contract_number: documents[index].id,
});
await getFile({ id: link_result.url, filename: `ЛК ЭВОЛЮЦИЯ ${ documents[index].id }.${ link_result.extension }` });
await this._updateDocs(index, { loading: false, disabled: false, });
this.setState({ loading: false, disabled: false, });
});
}
_handle_onCancelFile = async (index) =>
{
const { onCancel } = this.props;
const { documents } = this.state;
await this._updateDocs(index, { loading: true });
this.setState({ loading: true, disabled: true }, async () =>
{
const check_result = await signCheckCancelDocument({ contract_number: documents[index].id, doc_type_id: "144" });
if(check_result.status === "success")
{
await signCancelDocument({ contract_number: documents[index].id, doc_type_id: "144" });
const docs = [ ...this.state.documents ];
docs.splice(index, 1);
if(docs.length > 0)
{
this.setState({ documents: docs, loading: false, disabled: false, });
}
else
{
onCancel(true);
}
}
else
{
await this._updateDocs(index, {
loading: false,
error: true,
message: check_result.message !== undefined && check_result.message !== null ? check_result.message : "Возникла ошибка при отмене подписания через ЭДО",
});
}
});
}
_handle_onCancel = () =>
{
const { onCancel } = this.props;
const { documents } = this.state;
var clean = false;
if(documents.length === 0)
{
clean = true;
}
onCancel(clean);
}
_handle_onCheckEDOStatus = async (index) =>
{
const { documents } = this.state;
await this._updateDocs(index, { loading: true });
this.setState({ loading: true, disabled: true }, async () =>
{
const status_result = await docEDOStatus({ contract_number: documents[index].id });
if(status_result.status >= 2)
{
await this._updateDocs(index, { loading: false, disabled: false, signing: false, completed: true, url: status_result.url_edo, });
}
else
{
await this._updateDocs(index, { loading: false, disabled: false, signing: true, completed: false, url: status_result.url_edo, });
}
if(this._checkDocumentsCompleted())
{
this.setState({ loading: false, disabled: false, finished: true, });
}
else
{
this.setState({ loading: false, disabled: false, finished: false, });
}
});
}
_handle_onGoToEDO = (index) =>
{
const { documents } = this.state;
if(documents[index].url !== undefined && documents[index].url !== null)
{
window.open(documents[index].url, "_blank");
}
}
render()
{
const { step, operators, edo_message, documents, loading, disabled, finished, operator_selected } = this.state;
const { onCancel, } = this.props;
return (
<div className="edo_detail">
<div className="docs_list medium-icon">
<p className="list_title">Подписание через ЭДО</p>
</div>
{ step === 0 && (
<div className="form_field edo_list_field">
<label>Выберите оператора для отправки пакета документов</label>
<div className="edo_list_selection edo_sign_documents_document" style={{ flexDirection: "column", border: "none", padding: "0px 0px 0px 15px", }}>
{ operators !== undefined && operators !== null && (
<>
{ operators.length === 0 ? (
<div className="edo_sign_documents_document_right" style={{ border: "none", }}>
<div className="status_icon await"></div>
<div className="status_title">
<i>{ edo_message }</i>
</div>
</div>
) : (
operators.map((operator, index) => (
<div className="form_field checkbox item" key={ index }>
<input type="radio"
checked={ operator.box_id === operator_selected.box_id }
hidden=""
id={ `operator_${ index }` }
name={ `operator_${ index }` }
onChange={ (event) => this._handle_onSelectOperator(operator) }
disabled={ false }
/>
<label htmlFor={ `operator_${ index }` } className="unselectable">{ operator.provider_edo }</label>
</div>
) )
)}
</>
) }
</div>
</div>
) }
{ step === 1 && (
<div className="docs_list medium-icon edo_sign_documents_list">
{ documents.map((document, index) =>
{
return (
<div className="edo_sign_documents_document" key={ index }>
<div className="edo_sign_documents_document_left">
<p className="doc_name i-pdf extension edo_sign_document" data-format={ document.extension }>
{ document.name } от { moment(document.date).format("DD.MM.YYYY") }
{ document.type !== undefined && (<span>{ document.type }</span>) }
</p>
</div>
<div className="edo_sign_documents_document_right">
{ document.loading ? (
<>
{ loading && (
<SpinnerCircular size={ 22 } thickness={ 100 } speed={ 100 } color="rgba(236, 239, 244, 1)" secondaryColor="rgba(28, 1, 169, 1)" />
) }
</>
) : (
<>
{ document.error ? (
<>
<div className="status_icon error"></div>
<i>{ document.message !== undefined && document.message !== null ? document.message : "" }</i>
</>
) : (
<>
{ document.attorney && (
<>
<div className="status_icon await"></div>
<div className="edo_sign_status_attorney_select">
<Select
id="edo_attorneys_list"
name="edo_attorneys_list"
options={ document.attorneys }
placeholder="Выберите доверенность"
noOptionsMessage={ ({ inputValue }) => !inputValue ? "" :"Ничего не найдено" }
isSearchable={ true }
className="autocomlete autocomlete_with_indicators"
classNamePrefix="react-select"
value={ document.attorney_selected }
onChange={ (element) => { this._handle_onAttorneyChange(document.index, element) } }
required={ true }
/>
</div>
</>
) }
{ document.ready && (
<>
<div className="status_icon success"></div>
{ document.entity_id !== undefined && (
<>
<button className="button" disabled={ disabled } onClick={ () => this._handle_onDownloadFile(index) }>Посмотреть проект договора</button>
<button className="button" disabled={ disabled } onClick={ () => this._handle_onCancelFile(index) }>Отменить подписание</button>
</>
) }
</>
) }
{ document.signing && (
<>
<div className="status_icon success"></div>
<div className="status_title">
<i>Идет процесс подписания</i>
</div>
{ document.entity_id !== undefined && (
<>
<button className="button" disabled={ disabled } onClick={ () => this._handle_onCheckEDOStatus(index) }>Проверить статус</button>
</>
) }
</>
) }
{ document.completed && (
<>
<div className="status_icon success"></div>
<div className="status_title">
<i>Договор подписан со стороны "ЛК Эволюция"</i>
</div>
{ document.entity_id !== undefined && (
<button className="button" disabled={ disabled } onClick={ () => this._handle_onGoToEDO(index) }>Перейти в ЭДО</button>
) }
</>
) }
</>
) }
</>
) }
</div>
</div>
)
} ) }
</div>
) }
<form ref={ this.ref_form } onSubmit={ this._handle_onFormSubmit } onKeyDown={(e) => {if (e.key === 'Enter') e.preventDefault() }}>
<div className="form_field" style={{ display: "flex", justifyContent: "space-between" }}>
<button className="button button-blue" onClick={ this._handle_onCancel }>Отменить</button>
{ finished ? (
<button type="submit" className="button button-blue">Завершить</button>
) : (
<button type="submit" className="button button-blue">
{ loading ? (
<SpinnerCircular size={24} thickness={100} speed={100} color="rgba(255, 255, 255, 1)" secondaryColor="rgba(255, 255, 255, 0.5)" style={{ marginTop: "4px" }}/>
) : "Продолжить" }
</button>
) }
</div>
</form>
</div>
)
}
}
function mapStateToProps(state, ownProps)
{
return {
operators: state.edo.operators,
edo_message: state.edo.message,
}
}
export default connect(mapStateToProps)(DealContractsSignEDO)

View File

@ -0,0 +1,370 @@
import React from "react";
import { connect } from "react-redux";
import moment from "moment";
import { SpinnerCircular } from "spinners-react";
import { concatSeries } from "async";
import { eachSeries } from 'async';
import Select from 'react-select';
import Dropzone from 'react-dropzone';
import { signCheckCreatePrintForm, signGetGUIDEntity, signGetWMDoc, docEDOStatus, getFile, signGetFileContractProject, signUploadPaperDocument, signCheckCancelDocument, signCancelDocument } from "../../../actions";
export default class DealContractsSignPaper extends React.Component
{
constructor(props)
{
super(props)
this.state = {
finished: false,
loading: false,
disabled: false,
documents: [],
operator_selected: {},
statuses: {},
step: 0,
}
}
componentDidMount()
{
const docs = [];
for(let i in this.props.documents)
{
docs.push({ ...this.props.documents[i], ...{ index: i, loading: true, ready: false, upload: false, } });
}
this.setState({ documents: docs, loading: true }, () =>
{
this._sign();
});
}
_updateDocs = (id, update) =>
{
return new Promise((resolve) =>
{
const docs = [ ...this.state.documents ];
docs[ id ] = { ...docs[id], ...update };
this.setState({ documents: docs }, () =>
{
resolve();
});
});
}
_checkDocumentsCompleted = () =>
{
const { documents } = this.state;
let completed = true;
for(let i in documents)
{
if(documents[i].error)
{
continue;
}
else
{
if(!documents[i].completed)
{
completed = false;
break;
}
}
}
return completed;
}
_sign = () =>
{
const documents = [ ...this.state.documents ];
this.setState({ loading: true }, () =>
{
eachSeries(documents, async (document, callback) =>
{
if(document.completed)
{
callback();
}
if(document.uploading)
{
callback();
}
else if(document.ready)
{
callback();
}
else
{
const create_print_form_result = await signCheckCreatePrintForm({ contract_number: document.id, sign_type: "Paper" });
const docs = { status: create_print_form_result.status };
if(create_print_form_result.status !== "success")
{
docs.loading = false;
docs.error = true;
docs.ready = true;
docs.message = create_print_form_result.message;
}
await this._updateDocs(document.index, docs);
if(create_print_form_result.status === "success")
{
const get_guid_entity_result = await signGetGUIDEntity({
contract_number: document.id,
});
const wmdoc_result = await signGetWMDoc({
entity_name: "evo_contract",
entity_id: get_guid_entity_result.entityid,
sign_type: "Paper",
evo_id: "60",
code: "Leas_Contract",
});
await this._updateDocs(document.index, {
entity_id: get_guid_entity_result.entityid,
ready: true,
loading: false,
});
callback();
}
else
{
await this._updateDocs(document.index, {
loading: false,
error: true,
ready: true,
message: create_print_form_result.message !== undefined && create_print_form_result.message !== null ? create_print_form_result.message : "Возникла ошибка при создании документа для подписания.",
});
callback();
}
}
}, () =>
{
if(this._checkDocumentsCompleted())
{
this.setState({ loading: false, finished: true, });
}
else
{
this.setState({ loading: false, finished: false, });
}
});
});
}
_handle_onFormSubmit = (event) =>
{
event.preventDefault();
const { onFinish } = this.props;
const { finished } = this.state;
if(finished)
{
onFinish();
}
else
{
this._sign();
}
}
_handle_onDownloadFile = (index) =>
{
const { documents } = this.state;
this.setState({ loading: true, disabled: true, }, async () =>
{
await this._updateDocs(index, { loading: true });
const link_result = await signGetFileContractProject({
contract_number: documents[index].id,
});
await getFile({ id: link_result.url, filename: `ЛК ЭВОЛЮЦИЯ ${ documents[index].id }.${ link_result.extension }` });
await this._updateDocs(index, { loading: false, disabled: false, ready: false, uploading: true, });
this.setState({ loading: false, disabled: false, });
});
}
_handle_onCancelFile = async (index) =>
{
const { onCancel } = this.props;
const { documents } = this.state;
await this._updateDocs(index, { loading: true });
this.setState({ loading: true, disabled: true }, async () =>
{
const check_result = await signCheckCancelDocument({ contract_number: documents[index].id, doc_type_id: "60" });
if(check_result.status === "success")
{
await signCancelDocument({ contract_number: documents[index].id, doc_type_id: "60" });
const docs = [ ...this.state.documents ];
docs.splice(index, 1);
if(docs.length > 0)
{
this.setState({ documents: docs, loading: false, disabled: false, });
}
else
{
onCancel(true);
}
}
else
{
await this._updateDocs(index, {
loading: false,
error: true,
message: check_result.message !== undefined && check_result.message !== null ? check_result.message : "Возникла ошибка при отмене подписания",
});
}
});
}
_handle_onCancel = () =>
{
const { onCancel } = this.props;
const { documents } = this.state;
var clean = false;
if(documents.length === 0)
{
clean = true;
}
onCancel(clean);
}
_handle_onUploadFile = async (files, index) =>
{
const { documents } = this.state;
const { deal_id } = this.props;
await this._updateDocs(index, { loading: true });
this.setState({ loading: true, disabled: true }, async () =>
{
await signUploadPaperDocument(documents[index].id, deal_id, files);
await this._updateDocs(index, { loading: false, uploading: false, completed: true, });
if(this._checkDocumentsCompleted())
{
this.setState({ loading: false, disabled: false, finished: true, });
}
else
{
this.setState({ loading: false, disabled: false, finished: false, });
}
});
}
_handle_onCancelUpload = async (index) =>
{
await this._updateDocs(index, { ready: true, uploading: false, });
}
render()
{
const { documents, loading, disabled, finished, } = this.state;
return (
<div className="edo_detail">
<div className="docs_list medium-icon">
<p className="list_title">Подписание в бумажном виде</p>
</div>
<div className="docs_list medium-icon edo_sign_documents_list">
{ documents.map((document, index) =>
{
return (
<div className="edo_sign_documents_document" key={ index }>
<div className="edo_sign_documents_document_left">
<p className="doc_name i-pdf extension edo_sign_document" data-format={ document.extension }>
{ document.name } от { moment(document.date).format("DD.MM.YYYY") }
{ document.type !== undefined && (<span>{ document.type }</span>) }
</p>
</div>
<div className="edo_sign_documents_document_right">
{ document.loading ? (
<>
{ loading && (
<SpinnerCircular size={ 22 } thickness={ 100 } speed={ 100 } color="rgba(236, 239, 244, 1)" secondaryColor="rgba(28, 1, 169, 1)" />
) }
</>
) : (
<>
{ document.error ? (
<>
<div className="status_icon error"></div>
<i>{ document.message !== undefined && document.message !== null ? document.message : "" }</i>
</>
) : (
<>
{ document.ready && (
<>
<div className="status_icon success"></div>
{ document.entity_id !== undefined && (
<>
<button className="button" disabled={ disabled } onClick={ () => this._handle_onDownloadFile(index) }>Посмотреть проект договора</button>
<button className="button" disabled={ disabled } onClick={ () => this._handle_onCancelFile(index) }>Отменить подписание</button>
</>
) }
</>
) }
{ document.uploading && (
<>
<div className="status_icon await"></div>
{ document.entity_id !== undefined && (
<>
<Dropzone onDrop={ (acceptedFiles) => this._handle_onUploadFile(acceptedFiles, index) } maxFiles={ 10 }>
{ ({getRootProps, getInputProps}) => (
<div { ...getRootProps() }>
<button className="button" disabled={ disabled }>Загрузить скан подписанного документа</button>
<input { ...getInputProps() } />
</div>
) }
</Dropzone>
<button className="button" disabled={ disabled } onClick={ () => this._handle_onCancelUpload(index) }>Отменить загрузку</button>
</>
) }
</>
) }
{ document.completed && (
<>
<div className="status_icon success"></div>
<div className="status_title">
<i>Договор отправлен вашему менеджеру "ЛК Эволюция"</i>
</div>
</>
) }
</>
) }
</>
) }
</div>
</div>
)
} ) }
</div>
<form ref={ this.ref_form } onSubmit={ this._handle_onFormSubmit } onKeyDown={(e) => {if (e.key === 'Enter') e.preventDefault() }}>
<div className="form_field" style={{ display: "flex", justifyContent: "space-between" }}>
<button className="button button-blue" onClick={ this._handle_onCancel }>Отменить</button>
<button type="submit" className="button button-blue" disabled={ finished ? false : true }>
{ loading ? (
<SpinnerCircular size={24} thickness={100} speed={100} color="rgba(255, 255, 255, 1)" secondaryColor="rgba(255, 255, 255, 0.5)" style={{ marginTop: "4px" }}/>
) : "Продолжить" }
</button>
</div>
</form>
</div>
)
}
}

View File

@ -0,0 +1,404 @@
import React from "react";
import { eachSeries } from "async";
import { SpinnerCircular } from "spinners-react";
import FileDropzoneDeals from "../../FileDropzoneDeals";
import { attachDealDocument, createQuestionnaire, removeDealDocument, sendDealDocuments, } from "../../../actions";
import Step from "./Step";
import md5 from "md5";
class QuestionnaireForm extends React.Component
{
constructor(props)
{
super(props);
this.state = {
loading: false
}
}
_handle_onQuestionnaire = (event) =>
{
event.preventDefault();
const { onQuestionnaire } = this.props;
onQuestionnaire();
}
_handle_onCreateQuestionnaire = (event) =>
{
event.preventDefault();
const { onQuestionnaire, deal_id } = this.props;
this.setState({ loading: true, }, () =>
{
createQuestionnaire(deal_id)
.then(() =>
{
onQuestionnaire();
});
});
}
render()
{
const { loading } = this.state;
const { questionnaire_status } = this.props;
switch(questionnaire_status)
{
case "need_to_fill":
{
return (
<div className="message alert">
<p>Требуется обновить данные в анкете</p>
<button className="button button-blue" onClick={ this._handle_onQuestionnaire }>Актуализировать данные</button>
</div>
)
}
case "need_to_create":
{
return (
<div className="message alert">
<p>Требуется предоставить данные в анкете клиента</p>
<button className="button button-blue" style={{ minWidth: "130px" }} onClick={ this._handle_onCreateQuestionnaire }>
{ loading ? (
<SpinnerCircular size={24} thickness={100} speed={100} color="rgba(255, 255, 255, 1)" secondaryColor="rgba(255, 255, 255, 0.5)" style={{ marginTop: "0px" }}/>
) :
"Создать анкету"
}
</button>
</div>
)
}
case "up_to_date":
{
<div className="message ok">
<p>Вам не требуется актуализация данных анкеты Клиента</p>
</div>
}
default:
{
return (
<div className="message wait">
<p>Проводится проверка анкеты Вашей организации</p>
</div>
)
}
}
}
}
export default class DocumentsForm extends Step
{
constructor(props)
{
super(props);
this.state = {
open: false,
uploaded: {},
uploading: false,
completed: false,
loading: true,
questionnaire_loading: false,
};
this.status = 102;
}
componentDidMount()
{
if(this.status === this.props.statuscode_id)
{
this.setState({ open: true, });
}
}
componentDidUpdate(prevProps, prevState)
{
if(this.props.statuscode_id !== prevProps.statuscode_id)
{
if(this.status === this.props.statuscode_id)
{
this.setState({ open: true });
}
else
{
this.setState({ open: false });
}
}
if(prevProps.uploaded !== this.props.uploaded)
{
this.setState({ uploaded: this.props.uploaded, loading: false }, () =>
{
const completed = this._checkFilesCompleted();
this.setState({ completed });
});
}
}
_handle_onSendFiles = (event) =>
{
event.stopPropagation();
const { dealSelected, onDealsUpdate } = this.props;
this.props.onFocusDeal();
setTimeout(() =>
{
this.setState({ loading: true }, () =>
{
sendDealDocuments({ deal_id: dealSelected })
.then(() =>
{
onDealsUpdate();
})
.catch(() =>
{
});
});
}, 100);
}
_onSendFileStats = (group, index) =>
{
return new Promise((resolve) =>
{
const uploaded = { ...this.state.uploaded };
uploaded[group].files[index].uploaded = true;
this.setState({ uploaded }, () =>
{
resolve();
});
})
}
_handle_onAddFile = ({ document_id, document_name, files, update }) =>
{
const existed_files = { ...this.state.uploaded };
const group = md5(`${ document_id }_${ document_name }`);
const document_files = existed_files[ group ] === undefined ? [] : existed_files[ group ].files;
if(existed_files[ group ] === undefined)
{
existed_files[ group ] = {
files: [],
};
}
let index = parseInt(existed_files[ group ].files.length, 10);
for(let nf in files)
{
files[nf].document_id = document_id;
files[nf].group = group;
files[nf].group_name = document_name;
files[nf].uploaded = false;
files[nf].update = update;
document_files.push(files[nf]);
existed_files[ group ].files = document_files;
}
this.setState({ uploaded: existed_files, uploading: true }, () =>
{
const { opp_number } = this.props;
eachSeries(files, (file, callback) =>
{
const payload = {
deal_id: opp_number,
document_id: file.document_id,
group: file.group,
document_name: file.group_name,
filename: file.name,
lastModified: file.lastModified,
type: file.type,
file,
update,
index,
};
attachDealDocument(payload)
.then(async () =>
{
await this._onSendFileStats(group, index);
index++;
callback();
}, 1000)
}, () =>
{
const completed = this._checkFilesCompleted();
this.setState({ uploading: false, completed });
});
});
}
_handle_onDeleteFile = (group, index) =>
{
const uploaded = { ...this.state.uploaded };
const { opp_number } = this.props;
const list = [ ...uploaded[group].files ];
list.splice(index, 1);
uploaded[group].files = list;
this.setState({ uploaded }, () =>
{
const completed = this._checkFilesCompleted();
this.setState({ completed }, () =>
{
removeDealDocument({ deal_id: opp_number, group, index });
});
});
}
_checkFilesCompleted = () =>
{
const { uploaded } = this.state;
const { documents, questionnaire_status, } = this.props;
let c = true;
if(questionnaire_status !== "need_to_fill" && questionnaire_status !== "need_to_create")
{
if(documents !== undefined)
{
for(let g in documents)
{
if(!documents[g].add)
{
continue;
}
const group = md5(`${ documents[g].doc_id }_${ documents[g].name }`);
if(uploaded[group] === undefined || uploaded[group].files.length === 0)
{
c = false;
break;
}
else
{
for(let f in uploaded[group].files)
{
if(!uploaded[group].files[f].uploaded)
{
c = false;
break;
}
}
}
}
}
}
else
{
c = false;
}
return c;
}
render()
{
const { index, statuscode_id, dealSelected, documents, questionnaire_status, onQuestionnaire, } = this.props;
const { open, uploaded, uploading, loading, completed } = this.state;
return (
<div className={`${ this.status === statuscode_id ? "current" : statuscode_id > this.status ? "done" : "" }`}>
<p> { dealSelected }</p>
<span></span>
<div className="status_body with_footer">
{ this._renderHeader("Сборка пакета документов") }
<div className="wrap form" style={{ display: open ? "block" : "none", }}>
{ loading ? (
<div style={{ minHeight: 100, display: "flex", justifyContent: "center", alignItems: "center", }}>
<SpinnerCircular size={ 50 } thickness={ 51 } speed={ 100 } color="rgba(28, 1, 169, 1)" secondaryColor="rgba(236, 239, 244, 1)" />
</div>
) : (
<>
<div className="block">
<div className="left">
<p><b>Анкета клиента:</b></p>
</div>
<div className="right">
<QuestionnaireForm
questionnaire_status={ questionnaire_status }
onQuestionnaire={ onQuestionnaire }
deal_id={ dealSelected }
/>
</div>
</div>
{ documents === undefined ? (
<></>
) : (
<>
{ documents.map((document, index) => {
const group = md5(`${ document.doc_id }_${ document.name }`);
return (
<div className="block deal_documents_form_group" key={ index }>
<div className="left">
<p><b><span>{ document.name }</span>:</b></p>
</div>
<div className="right">
{ document.add ? (
<FileDropzoneDeals
statuscode_id={ statuscode_id }
uploading={ uploading }
uploaded={ uploaded[ group ] !== undefined ? uploaded[ group ] : { files: [] } }
onAddFile={ (files, update) => { this._handle_onAddFile({ document_id: document.doc_id, document_name: document.name, files, update }) } }
onDeleteFile={ this._handle_onDeleteFile }
document={ document }
/>
) : (
<>
{ document.check === "Документ принят" ? (
<div className="message ok">
<p>{ document.check }</p>
</div>
) : (
<div className="message wait">
<p>{ document.check }</p>
</div>
) }
</>
) }
</div>
</div>
)
} ) }
</>
) }
{/*}
<div className="message documents">
<div className="doc_list">
</div>
<p>Документы, отправленные Вами принадлежат другой организации бла бла коммент от менеджера</p>
</div>
{*/}
</>
) }
</div>
{ open && !loading && (
<div className="status_footer">
{ this.status === statuscode_id && (
<div className="buttons">
<button className="button button button-blue" onClick={ this._handle_onSendFiles } disabled={ completed ? false : true }>Отправить документы</button>
</div>
) }
</div>
) }
</div>
</div>
)
}
}

View File

@ -0,0 +1,44 @@
import React from "react";
import Step from "./Step";
export default class FinancialProgram extends Step
{
constructor(props)
{
super(props);
this.state = {
open: false,
};
this.status = 101;
}
render()
{
const { index, statuscode_id, dealSelected } = this.props;
const { open } = this.state;
return (
<div className={`${ this.status === statuscode_id ? "current" : statuscode_id > this.status ? "done" : "" }`}>
<p> { dealSelected }</p>
<span></span>
<div className="status_body with_footer">
{ this._renderHeader("Программа финансирования") }
<div className="wrap" style={{ display: open ? "block" : "none" }}>
<div className="single_text">
{ statuscode_id === this.status ? (
<p>Идёт подбор оптимальной программы финансирования</p>
) : (
<p>Программа финансирования выбрана</p>
) }
</div>
</div>
{ open && (
<div className="status_footer">
</div>
) }
</div>
</div>
)
}
}

View File

@ -0,0 +1,427 @@
import React from "react";
import moment from "moment";
import { SpinnerCircular } from "spinners-react";
import Link from "next/link";
//import EDOSign from "../../../components/EDOSign";
import Step from "./Step";
import DealContractsSignEDO from "./DealContractsSignEDO";
import DealContractsSignPaper from "./DealContractsSignPaper";
import SignPlannedContract from "./SignPlannedContract";
import SignedContract from "./SignedContract";
export default class LeasingRegistration extends Step
{
constructor(props)
{
super(props);
this.state = {
open: false,
/*
checked: {
prepared_contracts: [],
signing_plan_contracts: [],
signing_fact_contracts: [],
issued_contracts: [],
annulled_contracts: [],
},
*/
checked: [],
edo: false,
paper: false,
};
this.status = 107;
this.types = [
{
title: "Подготовлено",
key: "prepared_contracts",
},
{
title: "К подписанию",
key: "signing_plan_contracts",
},
{
title: "Подписано",
key: "signing_fact_contracts",
},
{
title: "Выдано",
key: "issued_contracts",
},
{
title: "Аннулировано",
key: "annulled_contracts",
},
];
this.container_ref = React.createRef();
}
_handle_onScrollToContainer = () =>
{
const element = this.container_ref.current;
const y = (element.getBoundingClientRect().top + window.scrollY - 160);
window.scrollTo({top: y, behavior: 'smooth'});
}
_handle_onPreparedContract = (contract) =>
{
const checked = [ ...this.state.checked ];
if(checked.indexOf(contract) > -1)
{
checked.splice(checked.indexOf(contract), 1);
}
else
{
checked.push(contract);
}
this.setState({ checked });
}
_handle_onSignEDO = () =>
{
this.setState({ edo: true, paper: false }, () =>
{
this._handle_onScrollToContainer();
});
}
_handle_onSignPaper = (contract) =>
{
this.setState({ edo: false, paper: true }, () =>
{
this._handle_onScrollToContainer();
});
}
_onEDOCancel = (clean = false) =>
{
if(clean)
{
this.setState({ edo: false, checked: [] });
}
else
{
this.setState({ edo: false });
}
}
_handle_onCancelEDO = () =>
{
const { onDealContractsUpdate } = this.props;
this.setState({ edo: false, checked: [] }, () =>
{
onDealContractsUpdate();
});
}
_handle_onFinishEDO = () =>
{
const { onDealContractsUpdate } = this.props;
this.setState({ edo: false, checked: [] }, () =>
{
onDealContractsUpdate();
});
}
_handle_onCancelPaper = () =>
{
const { onDealContractsUpdate } = this.props;
this.setState({ paper: false, checked: [] }, () =>
{
onDealContractsUpdate();
});
}
_handle_onFinishPaper = () =>
{
const { onDealContractsUpdate } = this.props;
this.setState({ paper: false, checked: [] }, () =>
{
onDealContractsUpdate();
});
}
_handle_onGoToEDOInvites = () =>
{
console.log("_handle_onGoToEDOInvites", { props: this.props });
this.props.router.push("/settings/digital");
}
_getDocuments = () =>
{
const contracts = this.props.contracts['prepared_contracts'];
const { checked } = this.state;
const documents = [];
for(let i in contracts)
{
if(checked.indexOf(contracts[i].name) > -1)
{
documents.push({
id: contracts[i].name,
name: `Договор № ${ contracts[i].name }`,
date: contracts[i].date,
type: `${ contracts[i].brand_name } ${ contracts[i].model_name }`,
extension: 'pdf',
})
}
}
return documents;
}
_render_preparedContracts = () =>
{
const { dealSelected } = this.props;
const { edo, paper, checked } = this.state;
//const checked = this.state.checked.prepared_contracts;
const contracts = this.props.contracts['prepared_contracts'];
console.log("_render_preparedContracts", { contracts });
if(edo)
{
return (
<DealContractsSignEDO
documents={ this._getDocuments() }
onCancel={ this._handle_onCancelEDO }
onFinish={ this._handle_onFinishEDO }
onGoToEDOInvites={ this._handle_onGoToEDOInvites }
/>
)
}
if(paper)
{
return (
<DealContractsSignPaper
deal_id={ dealSelected }
documents={ this._getDocuments() }
onCancel={ this._handle_onCancelPaper }
onFinish={ this._handle_onFinishPaper }
/>
)
}
return (
<div className="block-column">
<div className="docs_list acts_list-checkbox medium-icon">
{ contracts.length > 0 ?
contracts.map((contract, index) => (
<div className="row" key={ index }>
<div className="doc_name i-doc i-medium blue deals_contracts" style={{ alignItems: "flex-start" }}>
<input type="checkbox" name="" id={ `contract_${ index }` } checked={ checked.indexOf(contract.name) > -1 ? true : false } onChange={ () => { this._handle_onPreparedContract(contract.name) } }/>
<label htmlFor={ `contract_${ index }` }>{ contract.name }</label>
<div className="info">
<span>{ moment(contract.date).format('MM.DD.YYYY') }</span>
<span>{ contract.brand_name }</span>
<span>{ contract.model_name }</span>
</div>
</div>
</div>
)) : (
<p className="empty">Нет договоров</p>
) }
</div>
{ contracts.length > 0 &&
(
<div className="block_footer_btn">
<button className="button button-blue" onClick={ this._handle_onSignEDO } disabled={ checked.length > 0 ? false : true }>Подписать в ЭДО</button>
<button className="button button-blue" onClick={ this._handle_onSignPaper } disabled={ checked.length > 0 ? false : true }>Подписать в бумажном виде</button>
</div>
) }
</div>
)
}
_render_signingPlanContracts = () =>
{
const contracts = this.props.contracts['signing_plan_contracts'];
const { onDealContractsUpdate, dealSelected } = this.props;
console.log("_render_signingPlanContracts", { contracts });
return (
<div className="documents deal_contract_sign_list">
{ contracts.length > 0 ?
contracts.map((contract, index) => (
<SignPlannedContract
key={ `SignPlannedContract_${ contract.name }` }
index={ index }
contract={ contract }
deal_id={ dealSelected }
onDealContractsUpdate={ onDealContractsUpdate }
/>
)
) : (
<p className="empty">Нет договоров</p>
) }
</div>
)
}
_render_signingFactContracts = () =>
{
const contracts = this.props.contracts['signing_fact_contracts'];
console.log("_render_signingFactContracts", { contracts });
return (
<div className="documents">
{ contracts.length > 0 ?
contracts.map((contract, index) => (
<SignedContract
key={ `SignedContract_${ contract.name }` }
index={ index }
contract={ contract }
/>
)
) : (
<p className="empty">Нет договоров</p>
) }
</div>
)
}
_render_issuedContracts = () =>
{
const contracts = this.props.contracts['issued_contracts'];
console.log("_render_issuedContracts", { contracts });
return (
<div className="documents">
{ contracts.length > 0 ?
contracts.map((contract, index) => (
<div className="document" key={ index }>
<div className="icon formal"></div>
<div className="title">
<p><Link href={`/contract/${ contract.name }/payments`}><a>{ contract.name }</a></Link></p>
<div className="description">
<span>{ moment(contract.date).format("DD.MM.YYYY") }</span>
<span>{ contract.brand_name }</span>
<span>{ contract.model_name }</span>
</div>
</div>
</div>
)) : (
<p className="empty">Нет договоров</p>
) }
</div>
)
}
_render_annuledContracts = () =>
{
const contracts = this.props.contracts['annulled_contracts'];
console.log("_render_annuledContracts", { contracts });
return (
<div className="documents">
{ contracts.length > 0 ?
contracts.map((contract, index) => (
<div className="document" key={ index }>
<div className="icon formal"></div>
<div className="title">
<p>{ contract.name }</p>
<div className="description">
<span>{ moment(contract.date).format("DD.MM.YYYY") }</span>
<span>{ contract.brand_name }</span>
<span>{ contract.model_name }</span>
</div>
</div>
</div>
)) : (
<p className="empty">Нет договоров</p>
) }
</div>
)
}
_render_contracts = (type) =>
{
const { contracts } = this.props;
if(contracts !== undefined)
{
switch (type)
{
case "prepared_contracts":
{
return this._render_preparedContracts();
}
case "signing_plan_contracts":
{
return this._render_signingPlanContracts();
}
case "signing_fact_contracts":
{
return this._render_signingFactContracts();
}
case "issued_contracts":
{
return this._render_issuedContracts();
}
case "annulled_contracts":
{
return this._render_annuledContracts();
}
}
}
else
{
return null;
}
}
render()
{
const { index, statuscode_id, dealSelected } = this.props;
const { open, edo } = this.state;
return (
<div className={`${ this.status === statuscode_id ? "current" : statuscode_id > this.status ? "done" : "" }`} ref={ this.container_ref }>
<p> { dealSelected }</p>
<span></span>
<div className="status_body">
{ this._renderHeader("Оформление лизинга") }
<div className="wrap form contracts" style={{ display: open ? "block" : "none" }}>
{ this.props.contracts === undefined ? (
<div style={{ minHeight: 200, display: "flex", justifyContent: "center", alignItems: "center", }}>
<SpinnerCircular size={ 90 } thickness={ 51 } speed={ 100 } color="rgba(28, 1, 169, 1)" secondaryColor="rgba(236, 239, 244, 1)" />
</div>
) : (
<>
{ this.types.map((type, index) => (
<div className="block deal_contracts_group_item" key={ index }>
{ edo ? (
<>
{ type.key !== "prepared_contracts" && (
<div className="left"><p><b>{ type.title }</b></p></div>
) }
</>
) : (
<div className="left"><p><b>{ type.title }</b></p></div>
) }
<div className="right" style={ edo && type.key === "prepared_contracts" ? { width: "100%" } : {} }>
{ this._render_contracts(type.key) }
</div>
</div>
)) }
</>
) }
</div>
</div>
</div>
)
}
}

View File

@ -0,0 +1,234 @@
import React from "react";
import numeral from "numeral";
import { SpinnerCircular } from "spinners-react";
import { acceptDealOffers, downloadDealOffer, } from "../../../actions";
import Step from "./Step";
class OfferDownload extends React.Component
{
constructor(props)
{
super(props);
this.state = {
loading: false,
}
}
_handle_onOffer = (quote_number) =>
{
this.setState({ loading: true }, () =>
{
downloadDealOffer({ quote_number, filename: `ЛК Эволюция КП №${ quote_number }.pdf` })
.then(() => {
this.setState({ loading: false });
})
.catch(() => {
this.setState({ loading: false });
});
})
}
render()
{
const { offer } = this.props;
const { loading } = this.state;
return (
<div className="docs_list" style={{ cursor: "pointer" }} onClick={ () => this._handle_onOffer(offer.quote_number) }>
<div className="row">
<div className="small-icon">
{ loading ? (
<div style={{ width: "105px", height: "30px", display: "flex", alignItems: "center", justifyContent: "center", }}>
<SpinnerCircular size={ 22 } thickness={ 100 } speed={ 100 } color="rgba(236, 239, 244, 1)" secondaryColor="rgba(28, 1, 169, 1)" />
</div>
) : (
<p className="doc_name i-pdf">
КП
<span>{ offer.quote_number }</span>
</p>
) }
</div>
</div>
</div>
)
}
}
export default class Offers extends Step
{
constructor(props)
{
super(props);
this.state = {
open: false,
loading: false,
checked: [],
};
this.status = 100;
}
_handle_onCheckOffer = (quote_number) =>
{
const checked = [ ...this.state.checked ];
let is_new = true;
if(checked.indexOf(quote_number) > -1)
{
checked.splice(checked.indexOf(quote_number), 1);
is_new = false;
}
if(is_new)
{
checked.push(quote_number);
}
this.setState({ checked });
}
_handle_onSend = (event) =>
{
event.preventDefault();
event.stopPropagation();
this.setState({ loading: true }, () =>
{
const { checked } = this.state;
const { dealSelected, onDealsUpdate } = this.props;
const offers = [];
for(let i in checked)
{
offers.push({
quote_number: checked[i],
agreed: true,
});
}
acceptDealOffers({ deal_id: dealSelected, offers })
.then(() =>
{
onDealsUpdate()
.then(() =>
{
this.setState({ loading: false });
})
.catch(() =>
{
this.setState({ loading: false });
});
})
});
}
/*
_renderHeaderButtons = () =>
{
const { open, checked, loading } = this.state;
const { statuscode_id } = this.props;
if(statuscode_id === this.status)
{
if(!loading && open && checked.length > 0)
{
return (
<div className="buttons">
<button className="button button button-blue" onClick={ this._handle_onSend }>Согласовать</button>
</div>
)
}
}
return null;
}
*/
render()
{
const { index, statuscode_id, dealSelected, offers } = this.props;
const { checked, open, loading } = this.state;
return (
<div className={`${ this.status === statuscode_id ? "current" : statuscode_id > this.status ? "done" : "" }`}>
<p> { dealSelected }</p>
<span></span>
<div className="status_body with_footer">
{ this._renderHeader("Выбор КП ") }
<div className="wrap" style={{ display: open ? "block" : "none" }}>
{ offers === undefined || loading ? (
<div style={{ minHeight: 100, display: "flex", justifyContent: "center", alignItems: "center", }}>
<SpinnerCircular size={ 50 } thickness={ 51 } speed={ 100 } color="rgba(28, 1, 169, 1)" secondaryColor="rgba(236, 239, 244, 1)" />
</div>
) : (
<>
{ offers.length > 0 ? (
<table className="deal_offers_table">
<thead>
<tr>
<th></th>
<th></th>
<th>Стоимость</th>
<th>Первый платеж, </th>
<th>Первый платеж, %</th>
<th>Марка</th>
<th>Модель</th>
<th>Объектов лизинга</th>
<th></th>
</tr>
</thead>
<tbody>
{ offers.map((offer, offer_index) =>
{
return (
<tr key={ offer_index }>
{ statuscode_id === this.status && offer.quote_status ? (
<td>
<div className="form_field checkbox offer_selection">
<input type="checkbox" name="row" id={`offer_${ offer.quote_number }`} checked={ checked.indexOf(offer.quote_number) > -1 } onChange={ () => { this._handle_onCheckOffer(offer.quote_number) } }/>
<label htmlFor={`offer_${ offer.quote_number }`} data-text={`Выбрать коммерческое предложение`}></label>
</div>
</td>
) : (
<td>
<div className="form_field checkbox checkbox_disabled">
<input type="checkbox" name="row" id={`offer_${ offer.quote_number }`} checked={ true } onChange={ () => { } } style={{ filter: "grayscale", opacity: 0.5 }}/>
<label htmlFor={`offer_${ offer.quote_number }`} data-text={`Принято`}></label>
</div>
</td>
) }
<td data-title="№">{ offer_index + 1 }</td>
<td data-title="Стоимость">{ numeral(offer.price).format(' ., ') } </td>
<td data-title="Первый платеж, ₽">{ numeral(offer.first_payment_rub).format(' ., ') } </td>
<td data-title="Первый платеж, %">{ offer.first_payment_perc }%</td>
<td data-title="Марка">{ offer.brand_name }</td>
<td data-title="Модель">{ offer.model_name }</td>
<td data-title="Объектов лизинга">{ offer.object_count }</td>
<td>
<OfferDownload offer={ offer }/>
</td>
</tr>
)
} ) }
</tbody>
</table>
) : (
<p>Нет предложений</p>
) }
</>
) }
</div>
{ open && !loading && (
<div className="status_footer">
{ checked.length > 0 && statuscode_id === this.status && (
<div className="buttons">
<button className="button button button-blue" onClick={ this._handle_onSend }>Согласовать</button>
</div>
) }
</div>
) }
</div>
</div>
)
}
}

View File

@ -0,0 +1,288 @@
import React from "react";
import moment from "moment";
import { SpinnerCircular } from "spinners-react";
import Dropzone from 'react-dropzone';
import { docEDOSign, docEDOStatus, getFile, signCancelDocument, signCheckCancelDocument, signCheckDownloadContractProject, signGetFileContractProject, signUploadPaperDocument } from "../../../actions";
export default class SignPlannedContract extends React.Component
{
constructor(props)
{
super(props);
this.state = {
loading: true,
uploading: false,
finished: false,
loading_download_file: false,
loading_cancel_sign: false,
loading_signing: false,
loading_uploading_file: false,
disabled: false,
status: undefined,
contract_entity_id: undefined,
url: undefined,
error: false,
message: undefined,
};
}
async componentDidMount()
{
const { contract } = this.props;
if(contract.sign_type === "EDO")
{
const status_result = await docEDOStatus({ contract_number: contract.name });
this.setState({ contract_entity_id: status_result.edoid, status: status_result.status, loading: false, url: status_result.url_edo });
}
else
{
this.setState({ loading: false });
}
}
_handle_onUploadFile = async (files, index) =>
{
const { contract, deal_id } = this.props;
this.setState({ loading: true, disabled: true, uploading: true, loading_uploading_file: true, finished: false, }, async () =>
{
await signUploadPaperDocument(contract.name, deal_id, files);
this.setState({ loading: false, disabled: false, uploading: false, loading_uploading_file: false, finished: true, });
});
}
_handle_downloadFile = () =>
{
const { contract } = this.props;
this.setState({ disabled: true, loading_download_file: true, error: false, }, async () =>
{
const check_result = await signCheckDownloadContractProject({ contract_number: contract.name });
if(check_result.status === "success")
{
const link_result = await signGetFileContractProject({
contract_number: contract.name
});
await getFile({ id: link_result.url, filename: `ЛК ЭВОЛЮЦИЯ ${ contract.name }.${ link_result.extension }` });
this.setState({ disabled: false, loading_download_file: false, error: false, uploading: contract.sign_type === "EDO" ? false : true, });
}
else
{
this.setState({ disabled: false, loading_download_file: false, error: true, uploading: false, message: check_result.message !== undefined && check_result.message !== null ? check_result.message : "Возникла ошибка обработки документа" })
}
});
}
_handle_cancelSign = () =>
{
const { contract, onDealContractsUpdate } = this.props;
this.setState({ disabled: true, loading_cancel_sign: true }, async () =>
{
const check_result = await signCheckCancelDocument({ contract_number: contract.name, doc_type_id: contract.sign_type === "EDO" ? "144" : "60" });
if(check_result.status === "success")
{
const cancel_result = await signCancelDocument({ contract_number: contract.name, doc_type_id: contract.sign_type === "EDO" ? "144" : "60" });
setTimeout(() => {
onDealContractsUpdate();
}, 1000);
}
else
{
this.setState({
loading: false,
loading_cancel_sign: false,
error: true,
message: check_result.message !== undefined && check_result.message !== null ? check_result.message : `Возникла ошибка при отмене подписания${ contract.sign_type === "EDO" ? " через ЭДО" : "" }`,
});
}
});
}
_handle_sendToEDO = () =>
{
const { contract, onDealContractsUpdate } = this.props;
this.setState({ disabled: true, loading_signing: true }, async () =>
{
const check_result = await signCheckDownloadContractProject({ contract_number: contract.name });
if(check_result.status === "success")
{
const status_result = await docEDOStatus({ contract_number: contract.name });
if(status_result.status > 0)
{
const sign_result = await docEDOSign({ edoid: status_result.edoid });
const new_status_result = await docEDOStatus({ contract_number: contract.name });
this.setState({ status: new_status_result.status, loading: false, disabled: false, loading_signing: false });
}
else
{
this.setState({
loading: false,
loading_signing: false,
error: true,
message: status_result.message !== undefined && status_result.message !== null ? status_result.message : `Возникла ошибка при отправке в ЭДО`,
});
}
}
else
{
this.setState({
loading: false,
loading_signing: false,
error: true,
message: check_result.message !== undefined && check_result.message !== null ? check_result.message : `Возникла ошибка при отправке в ЭДО`,
});
}
});
}
_handle_onGoToEDO = () =>
{
const { url } = this.state;
if(url !== undefined && url !== null)
{
window.open(url, "_blank");
}
}
render()
{
const { index, contract, } = this.props;
const { loading, status, uploading, disabled, finished, error, message, loading_download_file, loading_uploading_file, loading_cancel_sign, loading_signing } = this.state;
return (
<div className="document deal_contract_sign_item">
<div className="icon">
<span className="extension">PDF</span>
</div>
<div className="title">
<p>{ contract.name }</p>
<div className="description">
<span>{ moment(contract.date).format("DD.MM.YYYY") }</span>
<span>{ contract.brand_name }</span>
<span>{ contract.model_name }</span>
</div>
</div>
{ loading ? (
<div className="actions actions_with_status">
<SpinnerCircular size={ 22 } thickness={ 100 } speed={ 100 } color="rgba(236, 239, 244, 1)" secondaryColor="rgba(28, 1, 169, 1)" />
</div>
) : (
<>
{ error ? (
<div className="actions actions_with_status">
<div className="status_icon error"></div>
<div className="status_title">
<i>{ message }</i>
</div>
</div>
) : (
<>
{ contract.sign_type === "PAPER" && (
<>
{ finished ? (
<div className="actions actions_with_status">
<div className="status_icon success"></div>
<div className="status_title">
<i>Договор отправлен вашему менеджеру "ЛК Эволюция"</i>
</div>
</div>
) : (
<div className="actions" style={{ justifyContent: "flex-end" }}>
{ uploading ? (
<Dropzone onDrop={ (acceptedFiles) => this._handle_onUploadFile(acceptedFiles, index) } maxFiles={ 10 }>
{ ({getRootProps, getInputProps}) => (
<div { ...getRootProps() }>
<button className="button" style={{ minWidth: "294px", }} disabled={ disabled }>
{ loading_uploading_file ? (
<SpinnerCircular size={ 22 } thickness={ 100 } speed={ 100 } color="rgba(236, 239, 244, 1)" secondaryColor="rgba(28, 1, 169, 1)" />
) : (
"Загрузить скан подписанного документа"
) }
</button>
<input { ...getInputProps() } />
</div>
) }
</Dropzone>
) : (
<>
<button className="button blue" style={{ minWidth: "230px", }} disabled={ disabled } onClick={ () => this._handle_downloadFile() }>
{ loading_download_file ? (
<SpinnerCircular size={ 22 } thickness={ 100 } speed={ 100 } color="rgba(236, 239, 244, 1)" secondaryColor="rgba(28, 1, 169, 1)" />
) : (
"Скачать файл для подписания"
) }
</button>
<button className="button blue" style={{ minWidth: "175px", }} disabled={ disabled } onClick={ () => this._handle_cancelSign() }>
{ loading_cancel_sign ? (
<SpinnerCircular size={ 22 } thickness={ 100 } speed={ 100 } color="rgba(236, 239, 244, 1)" secondaryColor="rgba(28, 1, 169, 1)" />
) : (
"Отменить подписание"
) }
</button>
</>
) }
</div>
) }
</>
) }
{ contract.sign_type === "EDO" && (
<>
{ status === 3 ? (
<div className="actions actions_with_status">
<div className="status_icon success"></div>
<div className="status_title">
<i>Подписанный договор будет доступен для скачивания в течение 1-2 минут.</i>
</div>
</div>
) : (
<div className="actions">
{ status === 1 && (
<button className="button blue" style={{ minWidth: "130px", }} disabled={ disabled } onClick={ () => this._handle_downloadFile() }>
{ loading_download_file ? (
<SpinnerCircular size={ 22 } thickness={ 100 } speed={ 100 } color="rgba(236, 239, 244, 1)" secondaryColor="rgba(28, 1, 169, 1)" />
) : (
"Скачать проект"
) }
</button>
) }
{ status === 1 && (
<button className="button blue" style={{ minWidth: "175px", }} disabled={ disabled } onClick={ () => this._handle_cancelSign() }>
{ loading_cancel_sign ? (
<SpinnerCircular size={ 22 } thickness={ 100 } speed={ 100 } color="rgba(236, 239, 244, 1)" secondaryColor="rgba(28, 1, 169, 1)" />
) : (
"Отменить подписание"
) }
</button>
)}
{ status === 1 && (
<button className="button blue" style={{ minWidth: "144px", }} disabled={ disabled } onClick={ () => this._handle_sendToEDO() }>
{ loading_signing ? (
<SpinnerCircular size={ 22 } thickness={ 100 } speed={ 100 } color="rgba(236, 239, 244, 1)" secondaryColor="rgba(28, 1, 169, 1)" />
) : (
"Отправить в ЭДО"
) }
</button>
) }
{ status === 2 && (
<button className="button blue" onClick={ () => this._handle_onGoToEDO() }>Перейти в ЭДО</button>
) }
</div>
) }
</>
) }
</>
) }
</>
) }
</div>
)
}
}

View File

@ -0,0 +1,82 @@
import React from "react";
import moment from "moment";
import { SpinnerCircular } from "spinners-react";
import Link from "next/link";
import { signCheckDownloadContractProject, signGetFileContractProject, getFile, } from "../../../actions";
export default class SignedContract extends React.Component
{
constructor(props)
{
super(props);
this.state = {
loading: false,
url: undefined,
error: false,
message: undefined,
};
}
async componentDidMount()
{
}
_handle_downloadFile = () =>
{
const { contract } = this.props;
this.setState({ loading: true, error: false, }, async () =>
{
const check_result = await signCheckDownloadContractProject({ contract_number: contract.name });
if(check_result.status === "success")
{
const link_result = await signGetFileContractProject({
contract_number: contract.name
});
await getFile({ id: link_result.url, filename: `ЛК ЭВОЛЮЦИЯ ${ contract.name }.${ link_result.extension }` });
this.setState({ loading: false, error: false, });
}
else
{
this.setState({ loading: false, error: true, message: check_result.message !== undefined && check_result.message !== null ? check_result.message : "Возникла ошибка обработки документа" })
}
});
}
render()
{
const { index, contract, } = this.props;
const { loading, error, message, } = this.state;
return (
<div className="document" key={ index }>
<div className="icon">
<span className="extension">PDF</span>
</div>
<div className="title">
<p><Link href={`/contract/${ contract.name }/payments`}>{ contract.name }</Link></p>
<div className="description">
<span>{ moment(contract.date).format("DD.MM.YYYY") }</span>
<span>{ contract.brand_name }</span>
<span>{ contract.model_name }</span>
</div>
</div>
<div className="actions wide">
<div className="status">
<div className="status_icon"></div>
<span>{ contract.statuscode_name }</span>
</div>
{ loading ? (
<div className="actions actions_with_status">
<SpinnerCircular style={{ margin: "0px 30px 0px", }} size={ 22 } thickness={ 100 } speed={ 100 } color="rgba(236, 239, 244, 1)" secondaryColor="rgba(28, 1, 169, 1)" />
</div>
) : (
<button className="button blue" onClick={ () => this._handle_downloadFile(true) }>Скачать</button>
) }
</div>
</div>
)
}
}

View File

@ -0,0 +1,49 @@
import React from "react";
import Step from "./Step";
export default class StatusDecisionMaking extends Step
{
constructor(props)
{
super(props);
this.state = {
open: false,
};
this.status = 104;
}
render()
{
const { index, statuscode_id, dealSelected } = this.props;
const { open } = this.state;
if(statuscode_id === 105)
{
return null;
}
return (
<div className={`${ this.status === statuscode_id ? "current" : (statuscode_id > this.status) ? "done" : "" }`}>
<p> { dealSelected }</p>
<span></span>
<div className="status_body with_footer">
{ this._renderHeader("Принятие решения по сделке") }
<div className="wrap" style={{ display: open ? "block" : "none" }}>
<div className="single_text">
{ this.status === statuscode_id ? (
<p>Принятие решение о финансировании</p>
) : (
<p>Поздравляем! Принято положительное решение по сделке.</p>
) }
</div>
</div>
{ open && (
<div className="status_footer">
</div>
) }
</div>
</div>
)
}
}

View File

@ -0,0 +1,45 @@
import React from "react";
import Step from "./Step";
export default class StatusDecisionRefuse extends Step
{
constructor(props)
{
super(props);
this.state = {
open: false,
};
this.status = 105;
}
render()
{
const { index, statuscode_id, dealSelected } = this.props;
const { open } = this.state;
if(statuscode_id !== this.status)
{
return null;
}
return (
<div className={`${ this.status === statuscode_id ? "current" : (statuscode_id > this.status) ? "done" : "" }`}>
<p> { dealSelected }</p>
<span></span>
<div className="status_body with_footer">
{ this._renderHeader("Требуется изменение параметров") }
<div className="wrap" style={{ display: open ? "block" : "none" }}>
<div className="single_text">
<p>Продолжение оформления заблокировано</p>
</div>
</div>
{ open && (
<div className="status_footer">
</div>
) }
</div>
</div>
)
}
}

View File

@ -0,0 +1,44 @@
import React from "react";
import Step from "./Step";
export default class StatusDocumentsCheck extends Step
{
constructor(props)
{
super(props);
this.state = {
open: false,
};
this.status = 103;
}
render()
{
const { index, statuscode_id, dealSelected } = this.props;
const { open } = this.state;
return (
<div className={`${ statuscode_id === this.status ? "current" : statuscode_id > this.status ? "done" : "" }`}>
<p> { dealSelected }</p>
<span></span>
<div className="status_body with_footer">
{ this._renderHeader("Проверка документов") }
<div className="wrap" style={{ display: open ? "block" : "none" }}>
<div className="single_text">
{ statuscode_id === this.status ? (
<p>Идёт проверка предоставленных документов</p>
) : (
<p>Документы проверены</p>
) }
</div>
</div>
{ open && (
<div className="status_footer">
</div>
) }
</div>
</div>
)
}
}

View File

@ -0,0 +1,44 @@
import React from "react";
import Step from "./Step";
export default class StatusPositiveDecision extends Step
{
constructor(props)
{
super(props);
this.state = {
open: false,
};
this.status = 106;
}
render()
{
const { index, statuscode_id, dealSelected } = this.props;
const { open } = this.state;
return (
<div className={`${ this.status === statuscode_id ? "current" : statuscode_id > this.status ? "done" : "" }`}>
<p> { dealSelected }</p>
<span></span>
<div className="status_body with_footer">
{ this._renderHeader("Принято положительное решение") }
<div className="wrap" style={{ display: open ? "block" : "none" }}>
<div className="single_text">
{ statuscode_id === this.status ? (
<p>Идёт подготовка необходимых документов для заключения сделки</p>
) : (
<p>Документы подготовлены</p>
) }
</div>
</div>
{ open && (
<div className="status_footer">
</div>
) }
</div>
</div>
)
}
}

View File

@ -0,0 +1,53 @@
import React from "react";
export default class Step extends React.Component
{
componentDidMount()
{
if(this.status === this.props.statuscode_id)
{
this.setState({ open: true });
}
}
componentDidUpdate(prevProps, prevState)
{
if(this.props.statuscode_id !== prevProps.statuscode_id)
{
if(this.status === this.props.statuscode_id)
{
this.setState({ open: true });
}
else
{
this.setState({ open: false });
}
}
}
_handle_onSwitch = () =>
{
const { statuscode_id } = this.props;
this.setState({ open: !this.state.open ? true : false });
}
_renderHeader = (title) =>
{
const { statuscode_id } = this.props;
const { open } = this.state;
return (
<div className="status_header" style={statuscode_id >= this.status ? { position: "relative", } : { position: "relative", cursor: "inherit" }} onClick={ statuscode_id >= this.status ? this._handle_onSwitch : () => {} }>
{ this.status === statuscode_id && ( <div className="background"></div> )}
<i className={`status_${ this.status } ${ statuscode_id < this.status ? "inactive" : "" }`}></i>
<p>{ title }</p>
{ statuscode_id >= this.status && (
<div className="button_arrow">
<div className={`icon ${ open ? "up" : "down" }`}></div>
</div>
) }
{ this._renderHeaderButtons !== undefined && this._renderHeaderButtons() }
</div>
)
}
}

View File

@ -2,79 +2,7 @@ import React from "react"
import { connect } from "react-redux"
import DealsList from "./DealsList";
import SingleDeal from "./SingleDeal";
import { getDeals } from "../../actions";
class AllContractsModal extends React.Component
{
constructor(props)
{
super(props);
}
render()
{
const { open, close, activeContract, handleContractSelected } = this.props
return (
<div className={open ? "fade opened" : "fade"}>
<div className="contractStatus_modal all_contracts_modal">
<div className="modal_header">
<p className="modal_title">Статусы сделок</p>
<button className="modal_close" onClick={close}></button>
</div>
<div className="modal_body">
<div className="contractStatus_list">
<div className="single_status">
<div>
<p>Сделка 1</p>
<span></span>
<i className="status_1"></i>
<p>Выбор КП</p>
</div>
<div>
<p>Сделка 1</p>
<span></span>
<i className="status_2"></i>
<p>Программа финансирования</p>
</div>
<div>
<p>Сделка 1</p>
<span></span>
<i className="status_3"></i>
<p>Сборка пакета документов</p>
</div>
<div className="current">
<p>Сделка 1</p>
<span></span>
<i className="status_4"></i>
<p>Проверка документов</p>
</div>
<div>
<p>Сделка 1</p>
<span></span>
<i className="status_5"></i>
<p>Принятие решения по заявке</p>
</div>
<div>
<p>Сделка 1</p>
<span></span>
<i className="status_6"></i>
<p>Оформление лизинга</p>
</div>
<div>
<p>Сделка 1</p>
<span></span>
<i className="status_7"></i>
<p>Выбор типа подписания</p>
</div>
</div>
</div>
</div>
</div>
</div>
)
}
}
import { getDeals, getDealOffers, getDealDocuments, getDealContracts } from "../../actions";
class DealsStatus extends React.Component
{
@ -82,17 +10,17 @@ class DealsStatus extends React.Component
{
super(props)
this.state = {
status: 2,
currentContractModalOpened: false,
allContractModalOpened: false,
currentSelected: null,
dealSelected: false,
dealSelected: undefined,
deals: undefined,
}
}
static getDerivedStateFromProps(nextProps, prevState)
{
console.log("DealsStatus", "getDerivedStateFromProps", { nextProps });
return {
deals: nextProps.deals,
}
@ -106,6 +34,30 @@ class DealsStatus extends React.Component
componentDidUpdate(prevProps, prevState) { }
_onDealsUpdate = () =>
{
return new Promise((resolve) =>
{
const { dispatch } = this.props;
getDeals({ dispatch, update: true })
.then(() =>
{
resolve();
})
.catch(() =>
{
resolve();
});
});
}
_onDealContractsUpdate = (deal_id) =>
{
const { dispatch } = this.props;
getDealContracts({ dispatch, deal_id, });
}
_handleModalToggle = (modal) =>
{
if (modal === "current")
@ -129,26 +81,49 @@ class DealsStatus extends React.Component
})
}
_handle_onSelectDeal = (deal_id) =>
{
const { dispatch } = this.props;
this.setState({ dealSelected: deal_id });
getDealOffers({ dispatch, deal_id, });
getDealDocuments({ dispatch, deal_id, });
getDealContracts({ dispatch, deal_id, });
}
_handle_onCloseDeal = () =>
{
this.setState({ dealSelected: undefined });
}
render()
{
const { currentContractModalOpened, allContractModalOpened, currentSelected, dealSelected, deals } = this.state
const { currentContractModalOpened, allContractModalOpened, currentSelected, dealSelected, deals, status, } = this.state
const { questionnaire_status, onQuestionnaire, } = this.props;
return (
<>
<div>
<p className="deals_list_title">Статусы сделок</p>
</div>
<DealsList deals={ deals } dealSelected={ dealSelected }/>
{/*}
<AllContractsModal
open={allContractModalOpened}
close={() => {
this._handleModalToggle("all")
}}
activeContract={currentSelected}
handleContractSelected={this._handleContractSelected}
/>
{*/}
{ deals.list !== undefined && deals.list !== null && deals.list.length > 0 && (
<>
<div>
<p className="deals_list_title">Статусы сделок</p>
</div>
<DealsList
dispatch={ this.props.dispatch }
router={ this.props.router }
status={ status }
deals={ deals }
questionnaire_status={ questionnaire_status }
dealSelected={ dealSelected }
onSelectDeal={ this._handle_onSelectDeal }
onCloseDeal={ this._handle_onCloseDeal }
onDealsUpdate={ this._onDealsUpdate }
onDealContractsUpdate={ this._onDealContractsUpdate }
onQuestionnaire={ onQuestionnaire }
/>
</>
) }
</>
)
}
@ -156,7 +131,6 @@ class DealsStatus extends React.Component
function mapStateToProps(state, ownProps)
{
console.log({ "DealsStatus.state": state });
return {
deals: state.deals,
}

View File

@ -0,0 +1,21 @@
import React from "react";
export default class DigitalDocumentAutomationBanner extends React.Component
{
constructor(props)
{
super(props);
this.state = {};
}
render()
{
return (
<div>
<p>Наш оператор Диадок. Идентификатор участника ЭДО (GUID) 2BM-9724016636-772401001-202007300714591533849».</p>
<div>Что такое ЭДО?</div>
<div>Получить приглашение в ЭДО</div>
</div>
)
}
}

580
components/EDOSign/index.js Normal file
View File

@ -0,0 +1,580 @@
import React from "react";
import { connect } from "react-redux";
import moment from "moment";
import { SpinnerCircular } from "spinners-react";
import { concatSeries } from "async";
import { eachSeries } from 'async';
import Select from 'react-select';
import { createEDOProject, signCheckCreatePrintForm, signCheckPowerAttorneyClient, signDownloadFile, signGetGUIDEntity, signGetPowerAttorneyClient, signGetWMDoc, docEDOSign, docEDOStatus, docEDOConnect, getFile, signGetFileContractProject, signCheckCancelDocument } from "../../actions";
//import { getDeals, getDealOffers, getDealDocuments, getDealContracts } from "../../actions";
class EDOSign extends React.Component
{
constructor(props)
{
super(props)
this.state = {
finished: false,
operators: null,
edo_message: null,
loading: false,
disabled: false,
documents: [],
operator_selected: {},
statuses: {},
step: 0,
}
}
static getDerivedStateFromProps(nextProps, prevState)
{
return {
operators: nextProps.operators,
edo_message: nextProps.edo_message,
}
}
componentDidMount()
{
const docs = [];
for(let i in this.props.documents)
{
docs.push({ ...this.props.documents[i], ...{ index: i, loading: true, ready: false, attorney: false } });
}
this.setState({ documents: docs });
if(this.state.operator_selected.box_id === undefined)
{
this.setState({ operator_selected: this.state.operators !== null && this.state.operators[0] !== undefined ? this.state.operators[0] : {} });
}
}
_updateDocs = (id, update) =>
{
return new Promise((resolve) =>
{
const docs = [ ...this.state.documents ];
docs[ id ] = { ...docs[id], ...update };
this.setState({ documents: docs }, () =>
{
resolve();
});
});
}
_checkDocumentsCompleted = () =>
{
const { documents } = this.state;
let completed = true;
for(let i in documents)
{
if(!documents[i].completed)
completed = false;
break;
}
return completed;
}
_sign = () =>
{
const { operator_selected, step } = this.state;
const documents = [ ...this.state.documents ];
this.setState({ loading: true }, () =>
{
eachSeries(documents, async (document, callback) =>
{
if(document.completed)
{
callback();
}
else if(document.signing)
{
await this._updateDocs(document.index, { loading: true, });
const status_result = await docEDOStatus({ contract_number: document.id });
if(status_result.status === 3)
{
await this._updateDocs(document.index, { loading: false, signing: false, ready: false, completed: true, });
}
else
{
await this._updateDocs(document.index, { loading: false, signing: true, ready: false, });
}
callback();
}
else if(document.ready)
{
await this._updateDocs(document.index, { loading: true, });
const status_result = await docEDOStatus({ contract_number: document.id });
if(status_result.status > 0)
{
const sign_result = await docEDOSign({ edoid: status_result.edoid });
}
await this._updateDocs(document.index, { loading: false, signing: true, ready: false, error: false, });
callback();
}
else
{
await this._updateDocs(document.index, { loading: true });
if(document.attorney && document.attorney_selected !== undefined)
{
const create_edo_project_result = await createEDOProject({
contract_number: document.id,
power_attorney: document.attorney_selected.value,
power_attorney_number: document.attorney_selected.label,
edo_box: operator_selected.edo_box,
});
const get_guid_entity_result = await signGetGUIDEntity({
contract_number: document.id,
});
const wmdoc_result = await signGetWMDoc({
entity_name: "evo_contract",
entity_id: get_guid_entity_result.entityid,
sign_type: "EDO",
evo_id: "144",
code: "Leas_Contract",
});
const connect_result = await docEDOConnect({ contract_number: document.id });
await this._updateDocs(document.index, {
entity_id: get_guid_entity_result.entityid,
ready: true,
loading: false,
attorney: false,
});
callback();
}
else
{
const create_print_form_result = await signCheckCreatePrintForm({ contract_number: document.id, sign_type: "EDO" });
const docs = { status: create_print_form_result.status };
if(create_print_form_result.status !== "success")
{
docs.loading = false;
docs.error = true;
docs.ready = true;
docs.message = create_print_form_result.message;
}
await this._updateDocs(document.index, docs);
if(create_print_form_result.status === "success")
{
const check_attorney_client_result = await signCheckPowerAttorneyClient({ contract_number: document.id })
await this._updateDocs(document.index, { attorney: check_attorney_client_result.power_attorney_required, });
if(check_attorney_client_result.power_attorney_required)
{
const get_attorney_client_result = await signGetPowerAttorneyClient({ contract_number: document.id });
if(get_attorney_client_result === null)
{
await this._updateDocs(document.index, { loading: false, error: true, ready: true, message: "Возникла ошибка при создании документа для подписания." });
callback();
}
else
{
if(get_attorney_client_result.length === null)
{
await this._updateDocs(document.index, { loading: false, error: true, ready: true, message: "Не обнаружена доверенность на подписанта. Для продолжения подписания обратитесь к своему персональному менеджеру" });
callback();
}
else
{
const attorneys = [];
for(let i in get_attorney_client_result)
{
attorneys.push({
value: get_attorney_client_result[i].power_attorney,
label: get_attorney_client_result[i].power_attorney_number,
});
}
await this._updateDocs(document.index, { loading: false, error: false, attorneys, attorney_selected: undefined });
callback();
}
}
}
else
{
const create_edo_project_result = await createEDOProject({
contract_number: document.id,
edo_box: operator_selected.edo_box,
});
const get_guid_entity_result = await signGetGUIDEntity({
contract_number: document.id,
});
const wmdoc_result = await signGetWMDoc({
entity_name: "evo_contract",
entity_id: get_guid_entity_result.entityid,
sign_type: "EDO",
evo_id: "144",
});
const connect_result = await docEDOConnect({ contract_number: document.id });
await this._updateDocs(document.index, {
entity_id: get_guid_entity_result.entityid,
ready: true,
loading: false,
attorney: false,
});
callback();
}
}
else
{
await this._updateDocs(document.index, {
loading: false,
error: true,
ready: true,
message: create_print_form_result.message !== undefined && create_print_form_result.message !== null ? create_print_form_result.message : "Возникла ошибка при создании документа для подписания.",
});
callback();
}
}
}
}, () =>
{
if(this._checkDocumentsCompleted())
{
this.setState({ loading: false, disabled: false, finished: true, });
}
else
{
this.setState({ loading: false, disabled: false, finished: false, });
}
});
});
}
_handle_onFormSubmit = (event) =>
{
event.preventDefault();
const { onFinish, onGoToEDOInvites } = this.props;
const { operators, operator_selected, step, finished } = this.state;
const documents = [ ...this.state.documents ];
if(operators !== null && operators.length === 0)
{
onGoToEDOInvites();
}
else
{
if(finished)
{
onFinish();
}
else
{
switch(step)
{
case 0:
{
this.setState({ step: 1 }, () =>
{
this._sign();
});
}
break;
case 1:
{
this._sign();
}
break;
}
}
}
}
_handle_onSelectOperator = (operator) =>
{
this.setState({ operator_selected: operator });
}
_handle_onAttorneyChange = (index, attorney) =>
{
this._updateDocs(index, { attorney_selected: attorney });
}
_handle_onDownloadFile = (index) =>
{
const { documents } = this.state;
this.setState({ loading: true, disabled: true, }, async () =>
{
await this._updateDocs(index, { loading: true });
const link_result = await signGetFileContractProject({
contract_number: documents[index].id,
});
await getFile({ id: link_result.url, filename: `ЛК ЭВОЛЮЦИЯ ${ documents[index].id }.${ link_result.extension }` });
await this._updateDocs(index, { loading: false, disabled: false, });
this.setState({ loading: false, disabled: false, });
});
}
_handle_onCancelFile = async (index) =>
{
const { onCancel } = this.props;
const { documents } = this.state;
await this._updateDocs(index, { loading: true });
this.setState({ loading: true, disabled: true }, async () =>
{
await signCheckCancelDocument({ contract_number: documents[index].id, doc_type_id: "144" });
const docs = [ ...this.state.documents ];
docs.splice(index, 1);
if(docs.length > 0)
{
this.setState({ documents: docs, loading: false, disabled: false, });
}
else
{
onCancel(true);
}
});
}
_handle_onCancel = () =>
{
const { onCancel } = this.props;
const { documents } = this.state;
var clean = false;
if(documents.length === 0)
{
clean = true;
}
onCancel(clean);
}
_handle_onCheckEDOStatus = async (index) =>
{
const { documents } = this.state;
await this._updateDocs(index, { loading: true });
this.setState({ loading: true, disabled: true }, async () =>
{
const status_result = await docEDOStatus({ contract_number: documents[index].id });
if(status_result.status >= 2)
{
await this._updateDocs(index, { loading: false, disabled: false, signing: false, completed: true, url: status_result.url_edo, });
}
else
{
await this._updateDocs(index, { loading: false, disabled: false, signing: true, completed: false, url: status_result.url_edo, });
}
if(this._checkDocumentsCompleted())
{
this.setState({ loading: false, disabled: false, finished: true, });
}
else
{
this.setState({ loading: false, disabled: false, finished: false, });
}
});
}
_handle_onGoToEDO = (index) =>
{
const { documents } = this.state;
if(documents[index].url !== undefined && documents[index].url !== null)
{
window.open(documents[index].url, "_blank");
}
}
render()
{
const { step, operators, edo_message, documents, loading, disabled, finished, operator_selected } = this.state;
const { onCancel, } = this.props;
return (
<div className="edo_detail">
<div className="docs_list medium-icon">
<p className="list_title">Подписание через ЭДО</p>
</div>
{ step === 0 && (
<div className="form_field edo_list_field">
<label>Выберите оператора для отправки пакета документов</label>
<div className="edo_list_selection edo_sign_documents_document" style={{ flexDirection: "column", border: "none", padding: "0px 0px 0px 15px", }}>
{ operators !== undefined && operators !== null && (
<>
{ operators.length === 0 ? (
<div className="edo_sign_documents_document_right" style={{ border: "none", }}>
<div className="status_icon await"></div>
<div className="status_title">
<i>{ edo_message }</i>
</div>
</div>
) : (
operators.map((operator, index) => (
<div className="form_field checkbox item" key={ index }>
<input type="radio"
checked={ operator.box_id === operator_selected.box_id }
hidden=""
id={ `operator_${ index }` }
name={ `operator_${ index }` }
onChange={ (event) => this._handle_onSelectOperator(operator) }
disabled={ false }
/>
<label htmlFor={ `operator_${ index }` } className="unselectable">{ operator.provider_edo }</label>
</div>
) )
)}
</>
) }
</div>
</div>
) }
{ step === 1 && (
<div className="docs_list medium-icon edo_sign_documents_list">
{ documents.map((document, index) =>
{
return (
<div className="edo_sign_documents_document" key={ index }>
<div className="edo_sign_documents_document_left">
<p className="doc_name i-pdf extension edo_sign_document" data-format={ document.extension }>
{ document.name } от { moment(document.date).format("DD.MM.YYYY") }
{ document.type !== undefined && (<span>{ document.type }</span>) }
</p>
</div>
<div className="edo_sign_documents_document_right">
{ document.loading ? (
<>
{ loading && (
<SpinnerCircular size={ 22 } thickness={ 100 } speed={ 100 } color="rgba(236, 239, 244, 1)" secondaryColor="rgba(28, 1, 169, 1)" />
) }
</>
) : (
<>
{ document.error ? (
<>
<div className="status_icon error"></div>
<i>{ document.message !== undefined && document.message !== null ? document.message : "" }</i>
</>
) : (
<>
{ document.attorney && (
<>
<div className="status_icon await"></div>
<div className="edo_sign_status_attorney_select">
<Select
id="edo_attorneys_list"
name="edo_attorneys_list"
options={ document.attorneys }
placeholder="Выберите доверенность"
noOptionsMessage={ ({ inputValue }) => !inputValue ? "" :"Ничего не найдено" }
isSearchable={ true }
className="autocomlete autocomlete_with_indicators"
classNamePrefix="react-select"
value={ document.attorney_selected }
onChange={ (element) => { this._handle_onAttorneyChange(document.index, element) } }
required={ true }
/>
</div>
</>
) }
{ document.ready && (
<>
<div className="status_icon success"></div>
{ document.entity_id !== undefined && (
<>
<button className="button" disabled={ disabled } onClick={ () => this._handle_onDownloadFile(index) }>Посмотреть проект договора</button>
<button className="button" disabled={ disabled } onClick={ () => this._handle_onCancelFile(index) }>Отменить подписание</button>
</>
) }
</>
) }
{ document.signing && (
<>
<div className="status_icon success"></div>
<div className="status_title">
<i>Идет процесс подписания</i>
</div>
{ document.entity_id !== undefined && (
<>
<button className="button" disabled={ disabled } onClick={ () => this._handle_onCheckEDOStatus(index) }>Проверить статус</button>
</>
) }
</>
) }
{ document.completed && (
<>
<div className="status_icon success"></div>
<div className="status_title">
<i>Договор подписан со стороны "ЛК Эволюция"</i>
</div>
{ document.entity_id !== undefined && (
<button className="button" disabled={ disabled } onClick={ () => this._handle_onGoToEDO(index) }>Перейти в ЭДО</button>
) }
</>
) }
</>
) }
</>
) }
</div>
</div>
)
} ) }
</div>
) }
<form ref={ this.ref_form } onSubmit={ this._handle_onFormSubmit } onKeyDown={(e) => {if (e.key === 'Enter') e.preventDefault() }}>
<div className="form_field" style={{ display: "flex", justifyContent: "space-between" }}>
<button className="button button-blue" onClick={ this._handle_onCancel }>Отменить</button>
{ finished ? (
<button type="submit" className="button button-blue">Завершить</button>
) : (
<button type="submit" className="button button-blue">
{ loading ? (
<SpinnerCircular size={24} thickness={100} speed={100} color="rgba(255, 255, 255, 1)" secondaryColor="rgba(255, 255, 255, 0.5)" style={{ marginTop: "4px" }}/>
) : "Продолжить" }
</button>
) }
</div>
</form>
</div>
)
}
}
function mapStateToProps(state, ownProps)
{
return {
operators: state.edo.operators,
edo_message: state.edo.message,
}
}
export default connect(mapStateToProps)(EDOSign)

View File

@ -0,0 +1,55 @@
import React from "react";
import Dropzone from 'react-dropzone';
const LIMIT = 10000000;
const LIMIT_FILES = 10;
export default class FileDropzone extends React.Component
{
constructor(props)
{
super(props);
this.state = {};
}
render()
{
const { files, onAddFile, onDeleteFile } = this.props;
return (
<>
{ files.length > 0 && (
<div className="column">
<div className="column_text_block">
<p><b>Приложенные файлы ({ files.length }/{ LIMIT_FILES })</b></p>
{ files.map((file, index) => (
<p key={ index }>{ file.size > LIMIT && (<span style={{ color: "#A8026B", }}>Ошибка, превышен допустимый размер файла в 10 мб.</span>) } { file.name } - { parseFloat(file.size / 1000000).toFixed(file.size < 100000 ? 3 : 2) } мб. <small style={{ color: "#A8026B", textDecoration: "underline", cursor: "pointer" }} onClick={ () => onDeleteFile(file.name) }>[ удалить ]</small></p>
)) }
</div>
</div>
) }
<div className="column">
<div className="column_text_block">
<p style={{ color: "#999", fontStyle: "italic" }}>Вы можете приложить до 10 файлов, максимальный размер одного файла: 10 мегабайт.</p>
</div>
</div>
{ files.length < LIMIT_FILES && (
<Dropzone onDrop={ (acceptedFiles) => onAddFile(acceptedFiles) } maxFiles={ LIMIT_FILES }>
{ ({getRootProps, getInputProps}) => (
<div className="file_upload dropzone" { ...getRootProps() }>
<div className="files"></div>
<div>
<p data-sm-text="Выберите файлы">
<span>Перенесите файлы на экран для быстрой загрузки или выберите файл с компьютера </span>
</p>
<label htmlFor="" className="button button-blue">Загрузить файл</label>
</div>
<input { ...getInputProps() } />
</div>
) }
</Dropzone>
) }
</>
)
}
}

View File

@ -0,0 +1,108 @@
import Dropzone from 'react-dropzone';
import FileDropzone from "../FileDropzone";
import moment from "moment";
import { SpinnerCircular } from 'spinners-react';
const LIMIT = 10000000;
const LIMIT_FILES = 10;
export default class FileDropzoneDeals extends FileDropzone
{
constructor(props)
{
super(props);
this.state = {
message: true,
};
}
componentDidMount()
{
}
_handle_onToggleShowMessage = () =>
{
this.setState({ message: this.state.message ? false : true });
}
render()
{
const { uploaded, onAddFile, onDeleteFile, uploading, document, statuscode_id, } = this.props;
const { message } = this.state;
let show_comment = false;
if(document.comment !== null && document.comment !== "")
{
show_comment = true;
}
return (
<>
{ show_comment && (
<div className="horizontal_dropzone_files_item horizontal_dropzone_files_error">
{ message ? (
<p className="horizontal_dropzone_files_comment">
<span className="title">{ document.check }</span>
<span>{ document.comment }</span>
</p>
) : (
<p className={`horizontal_dropzone_files_comment ${ !message ? "closed" : "" }`}>
<span>Комментарий к ранее загруженным файлам</span>
</p>
) }
<div className={`switch ${ !message ? "up" : "" }`} onClick={ this._handle_onToggleShowMessage }></div>
</div>
) }
{ statuscode_id === 102 && (
<>
{ uploaded.files.length > 0 && (
<div className="horizontal_dropzone_files_wrapper">
<div className="horizontal_dropzone_files horizontal_dropzone_files_item">
{ uploaded.files.map((file, index) =>
{
return (
<div className="file" key={ index }>
{ file.uploaded ? (
<div className="delete" onClick={ () => onDeleteFile(file.group, index) }>
<div className="icon"></div>
</div>
) : (
<div className="loading">
<SpinnerCircular size={ 22 } thickness={ 100 } speed={ 100 } color="rgba(255, 255, 255, 1)" secondaryColor="rgba(168, 2, 107, 0.5)" style={{ marginTop: "8px" }}/>
</div>
) }
<div className="doc_icon">
<span className="extension">PDF</span>
</div>
<div className="title">
<span>{ file.name }</span>
<span>{ moment().format("DD.MM.YYYY") }</span>
</div>
</div>
)
} ) }
</div>
</div>
) }
{ uploaded.files.length < LIMIT_FILES && (
<Dropzone onDrop={ (acceptedFiles) => onAddFile(acceptedFiles, document.comment !== null && document.comment !== "" ? true : false) } maxFiles={ LIMIT_FILES } multiple={ true } disabled={ uploading }>
{ ({getRootProps, getInputProps}) => (
<div className={`file_upload dropzone horizontal_dropzone_wrapper ${ uploading ? "disabled" : "" }`} { ...getRootProps() }>
<div className={`files`}></div>
<div className={`horizontal_dropzone_inner`}>
<p data-sm-text="Выберите файлы">
<span>Перенесите файлы на экран для быстрой загрузки или выберите файл с компьютера</span>
</p>
<label htmlFor="" className="button button-blue">Загрузить файл</label>
</div>
<input { ...getInputProps() } />
</div>
) }
</Dropzone>
) }
</>
) }
</>
)
}
}

View File

@ -0,0 +1,19 @@
import React from "react";
import { logDocumentAccess } from "../../actions/logsActions";
export default class LogFileDownload extends React.Component
{
_log = () =>
{
const{ log } = this.props;
if(log !== undefined)
{
const { log } = this.props;
logDocumentAccess(log)
.then(() => {})
.catch(() => {});
}
}
}

View File

@ -127,7 +127,7 @@ export default class FilesList extends React.Component
{ files.map((file, index) => {
if(file.name === undefined) { return null; }
return (
<div key={ index } className="dosc_list medium-icon" style={{ marginBottom: "2%", position: "relative", border: "1px dashed rgb(28, 1, 169)", width: "32%", height: "100px", borderRadius: "4px", display: "flex", alignItems: "center", justifyContent: "center", }}>
<div key={ index } className="docs_list medium-icon" style={{ marginBottom: "2%", position: "relative", border: "1px dashed rgb(28, 1, 169)", width: "32%", height: "100px", borderRadius: "4px", display: "flex", alignItems: "center", justifyContent: "center", }}>
<div className="row" style={{ alignItems: "center", justifyContent: "center", display: "flex", flexDirection: "row", flex: 1, marginBottom: "0px" }}>
<p className="doc_name extension" data-format={ this._renderFileType(file) } style={{ wordBreak: "break-all", lineHeight: "15px", }}>{ this._renderFileName(file.name) }{/*}<span style={{width: "100%"}}>Постановление</span>{*/}</p>
</div>
@ -141,7 +141,7 @@ export default class FilesList extends React.Component
}) }
{ loading && (
<div className="dosc_list medium-icon" style={{ position: "relative", border: "1px dashed rgb(28, 1, 169)", width: "32%", height: "100px", borderRadius: "4px", display: "flex", alignItems: "center", justifyContent: "center", }}>
<div className="docs_list medium-icon" style={{ position: "relative", border: "1px dashed rgb(28, 1, 169)", width: "32%", height: "100px", borderRadius: "4px", display: "flex", alignItems: "center", justifyContent: "center", }}>
<div className="row" style={{ alignItems: "center", justifyContent: "center", display: "flex", flexDirection: "row", flex: 1, marginBottom: "0px" }}>
<div style={{ display: "flex", justifyContent: "center", alignItems: "center", }}>
<SpinnerCircular size={ 50 } thickness={ 100 } speed={ 100 } color="rgba(28, 1, 169, 1)" secondaryColor="rgba(236, 239, 244, 1)" />

View File

@ -233,7 +233,7 @@ class Form_8_Signing extends QuestionnaireForm
<FormMessage type="error" title="Ошибка" message="К сожалению в процессе создания документа возникла ошибка. Пожалуйста, обратитесь к сотруднику Отдела по работе с клиентами или попробуйте еще раз."/>
)}
{ !sign.digital && (
<div className="dosc_list medium-icon">
<div className="docs_list medium-icon">
<div className="row">
<p className="doc_name i-pdf extension">
{ filename }

View File

@ -151,7 +151,7 @@ class Form_9_Status extends QuestionnaireForm
</React.Fragment>
) }
<div className="questionnaire status_action" style={{ width: "100%" }}>
<div className="dosc_list medium-icon">
<div className="docs_list medium-icon">
<div className="row">
<p className="doc_name i-pdf extension">
{ file.name }

View File

@ -54,3 +54,8 @@ export const DEAL_DOCUMENTS_LIST = 'DEAL_DOCUMENTS_LIST';
export const DEAL_CONTRACTS_LIST = 'DEAL_CONTRACTS_LIST';
export const DEALS_RESET = 'DEALS_RESET';
export const DEAL_RESET = 'DEAL_RESET';
export const EDO_LOADED = 'EDO_LOADED';
export const EDO_OPERATORS_LIST = 'EDO_OPERATORS_LIST';
export const EDO_INVITES_LIST = 'EDO_INVITES_LIST';
export const EDO_RESET = 'EDO_RESET';

View File

@ -158,10 +158,11 @@ input[type="checkbox"] + label:before {
position: absolute;
left: 0;
top: 2px;
border-radius: 0px;
}
input[type="checkbox"]:checked + label:before {
background: url("/assets/images/icons/checkbox_white.svg") no-repeat center var(--primary);
border-color: var(--primary);
background: url("/assets/images/icons/checkbox_white.svg") no-repeat center var(--blue);
border-color: var(--blue);
}
input[type="checkbox"]:disabled + label {
cursor: default;
@ -196,8 +197,8 @@ input[type="radio"] + label:before {
}
input[type="radio"]:checked + label:before {
background: #fff;
box-shadow: inset 0px 0 0px 5px #005FF9;
border-color: #005FF9;
box-shadow: inset 0px 0 0px 5px #1c01a9;
border-color: #1c01a9;
border: 0;
}
input[type="radio"]:disabled + label {

View File

@ -187,13 +187,14 @@ input[type="checkbox"] {
position: absolute;
left: 0;
top: 2px;
border-radius: 0px;
}
}
&:checked + label {
&:before {
background: url("/assets/images/icons/checkbox_white.svg") no-repeat center var(--primary);
border-color: var(--primary);
background: url("/assets/images/icons/checkbox_white.svg") no-repeat center var(--blue);
border-color: var(--blue);
}
}
&:disabled + label {
@ -235,8 +236,8 @@ input[type="radio"] {
&:checked + label {
&:before {
background: #fff;
box-shadow: inset 0px 0 0px 5px #005FF9;
border-color: #005FF9;
box-shadow: inset 0px 0 0px 5px #1c01a9;
border-color: #1c01a9;
border: 0;
}
}

View File

@ -1064,19 +1064,11 @@
}
@media all and (max-width: 768px) {
.dropzone {
border: 0;
background: transparent;
height: auto;
flex-wrap: wrap;
}
.dropzone div p {
margin-bottom: 10px;
}
.dropzone div p:before {
content: attr(data-sm-text);
display: block;
}
.dropzone div p span {
display: none;
.dropzone p {
width: 100%;
}
}
/* questionnaire */
@ -1387,14 +1379,17 @@
line-height: 20px;
}
}
.questionnaire .autocomlete_with_indicators .react-select__control .react-select__indicators {
display: block !important;
}
.questionnaire .files_list {
padding-bottom: 30px;
}
@media all and (max-width: 720px) {
.questionnaire .files_list .dosc_list {
.questionnaire .files_list .docs_list {
width: 100% !important;
}
.questionnaire .files_list .dosc_list .doc_name {
.questionnaire .files_list .docs_list .doc_name {
align-items: center;
align-content: center;
width: auto;
@ -1665,3 +1660,6 @@
margin: 0px!important;
}
}
.deal_offers_table {
width: 100%;
}

View File

@ -1265,23 +1265,11 @@
}
@media all and (max-width: 768px) {
border: 0;
background: transparent;
height: auto;
flex-wrap: wrap;
div {
p {
margin-bottom: 10px;
&:before {
content: attr(data-sm-text);
display: block;
}
span {
display: none;
}
}
p {
width: 100%;
}
}
}
@ -1554,25 +1542,28 @@
max-width: 800px;
}
.autocomlete {
.autocomlete
{
* {
outline: none;
box-shadow: none !important;
}
.react-select__control {
.react-select__control
{
border-radius: 0;
border: 1px solid rgba(0,16,61,0.12);
height: 40px;
min-height: 40px;
&.react-select__control--menu-is-open {
&.react-select__control--menu-is-open
{
border-color: var(--blue);
}
.react-select__value-container {
.react-select__value-container
{
padding:0 12px;
height: 100%;
background: #fff;
@ -1581,13 +1572,15 @@
//background-color: #EDEFF5;
}
.react-select__input-container {
.react-select__input-container
{
margin: 0;
padding: 0;
}
}
.react-select__indicators {
.react-select__indicators
{
display: none;
}
}
@ -1622,19 +1615,30 @@
color: var(--blue);
}
@media all and (max-width: 960px) {
font-size: 13px;
line-height: 20px;
}
}
}
}
@media all and (max-width: 960px) {
font-size: 13px;
line-height: 20px;
}
}
}
}
.autocomlete_with_indicators
{
.react-select__control
{
.react-select__indicators
{
display: block !important;
}
}
}
.files_list {
padding-bottom: 30px;
@media all and (max-width: 720px) {
.dosc_list {
.docs_list {
width: 100% !important;
.doc_name {
@ -1939,4 +1943,8 @@
margin: 0px!important;
}
}
}
.deal_offers_table {
width: 100%;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -507,6 +507,9 @@ div {
background-position: 0 5px;
}
}
.i-doc.blue {
background-image: url("data:image/svg+xml,%3Csvg width='26' height='28' viewBox='0 0 26 28' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M2 3.5C2 1.84315 3.34315 0.5 5 0.5H18.3701L20.7774 4L23.1848 7.06354V24.5C23.1848 26.1569 21.8417 27.5 20.1848 27.5H5C3.34314 27.5 2 26.1569 2 24.5V3.5Z' fill='%231C01A9'/%3E%3Cpath opacity='0.4' d='M23.1858 11.5V7L19.334 6.5L23.1858 11.5Z' fill='%230C0C0C'/%3E%3Cline y1='-0.5' x2='11.5553' y2='-0.5' transform='matrix(1 -9.89866e-05 0.000132759 1 6.81445 7.50098)' stroke='%23F0F0F0'/%3E%3Cline y1='-0.5' x2='11.5553' y2='-0.5' transform='matrix(1 -9.89866e-05 0.000132759 1 6.81445 12.501)' stroke='%23F0F0F0'/%3E%3Cline y1='-0.5' x2='11.5553' y2='-0.5' transform='matrix(1 -9.89866e-05 0.000132759 1 6.81445 17.501)' stroke='%23F0F0F0'/%3E%3Cline y1='-0.5' x2='11.5553' y2='-0.5' transform='matrix(1 -9.89866e-05 0.000132759 1 6.81445 22.501)' stroke='%23F0F0F0'/%3E%3Cpath d='M23.1858 7H19.3711C18.8188 7 18.3711 6.55228 18.3711 6V3.5V0.5L23.1858 7Z' fill='%232F80ED'/%3E%3C/svg%3E");
}
.success {
color: var(--green);
}
@ -639,3 +642,43 @@ div {
margin-top: 35px;
margin-bottom: 35px;
}
.messages_overlay {
position: fixed;
top: 0px;
right: 0px;
width: 30%;
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: flex-start;
z-index: 100;
gap: 10px 10px;
margin: 10px;
}
.messages_overlay .overlay_message_error {
position: relative;
width: 100%;
background-color: #df2525;
padding: 10px 15px;
font-size: 12px;
}
.messages_overlay .overlay_message_error h4,
.messages_overlay .overlay_message_error p {
color: #fff;
}
.messages_overlay .overlay_message_error h4 {
padding: 0px;
margin: 0px;
margin-bottom: 2px;
}
.messages_overlay .overlay_message_error .button {
position: absolute;
top: 8px;
right: 8px;
width: 16px;
height: 16px;
padding: 0;
border: 0;
background: url("/assets/images/icons/close-white.svg") no-repeat center;
background-size: 16px;
}

View File

@ -524,20 +524,24 @@ div {
}
.i-doc {
padding-left: 80px;
background: url("/assets/images/icons/icon-doc.svg") no-repeat left center;
background-size: 56px;
padding-left: 80px;
background: url("/assets/images/icons/icon-doc.svg") no-repeat left center;
background-size: 56px;
@media all and (max-width: 1600px) and (min-width: 1280px) {
padding-left: 56px;
background-size: 42px;
}
@media all and (max-width: 1600px) and (min-width: 1280px) {
padding-left: 56px;
background-size: 42px;
}
@media all and (max-width: 960px) {
padding-left: 55px;
background-size: 32px;
background-position: 0 5px;
}
@media all and (max-width: 960px) {
padding-left: 55px;
background-size: 32px;
background-position: 0 5px;
}
&.blue {
background-image: url("data:image/svg+xml,%3Csvg width='26' height='28' viewBox='0 0 26 28' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M2 3.5C2 1.84315 3.34315 0.5 5 0.5H18.3701L20.7774 4L23.1848 7.06354V24.5C23.1848 26.1569 21.8417 27.5 20.1848 27.5H5C3.34314 27.5 2 26.1569 2 24.5V3.5Z' fill='%231C01A9'/%3E%3Cpath opacity='0.4' d='M23.1858 11.5V7L19.334 6.5L23.1858 11.5Z' fill='%230C0C0C'/%3E%3Cline y1='-0.5' x2='11.5553' y2='-0.5' transform='matrix(1 -9.89866e-05 0.000132759 1 6.81445 7.50098)' stroke='%23F0F0F0'/%3E%3Cline y1='-0.5' x2='11.5553' y2='-0.5' transform='matrix(1 -9.89866e-05 0.000132759 1 6.81445 12.501)' stroke='%23F0F0F0'/%3E%3Cline y1='-0.5' x2='11.5553' y2='-0.5' transform='matrix(1 -9.89866e-05 0.000132759 1 6.81445 17.501)' stroke='%23F0F0F0'/%3E%3Cline y1='-0.5' x2='11.5553' y2='-0.5' transform='matrix(1 -9.89866e-05 0.000132759 1 6.81445 22.501)' stroke='%23F0F0F0'/%3E%3Cpath d='M23.1858 7H19.3711C18.8188 7 18.3711 6.55228 18.3711 6V3.5V0.5L23.1858 7Z' fill='%232F80ED'/%3E%3C/svg%3E");
}
}
.success {
@ -683,4 +687,48 @@ div {
line-height: 35px;
margin-top: 35px;
margin-bottom: 35px;
}
.messages_overlay {
position: fixed;
top: 0px;
right: 0px;
width: 30%;
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: flex-start;
z-index: 100;
gap: 10px 10px;
margin: 10px;
.overlay_message_error {
position: relative;
width: 100%;
background-color: #df2525;
padding: 10px 15px;
font-size: 12px;
h4, p {
color: #fff;
}
h4 {
padding: 0px;
margin: 0px;
margin-bottom: 2px;
}
.button {
position: absolute;
top: 8px;
right: 8px;
width: 16px;
height: 16px;
padding: 0;
border: 0;
background: url("/assets/images/icons/close-white.svg") no-repeat center;
background-size: 16px;
}
}
}

72
lib/CRMRequest/index.js Normal file
View File

@ -0,0 +1,72 @@
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
import axios from 'axios';
import { Cookies } from 'react-cookie';
import cookie from 'cookie';
import moment from 'moment';
import jwt from 'jsonwebtoken';
import { cors } from '../cors';
import { inspect } from 'util';
export default async function CRMRequest(req, res, path, method, data, log = false)
{
await cors(req, res);
if(req.headers.cookie !== undefined)
{
const cookies = cookie.parse(req.headers?.cookie ? req.headers?.cookie : "");
if(cookies.jwt !== undefined && cookies.jwt !== null)
{
var client_jwt_decoded = jwt.verify(cookies.jwt, process.env.JWT_SECRET_CLIENT);
var crm_jwt = jwt.sign({ acc_number: client_jwt_decoded.acc_number }, process.env.JWT_SECRET_CRM, { noTimestamp: true });
if(log)
{
console.log("client_jwt_decoded", client_jwt_decoded);
console.log("crm_jwt", crm_jwt);
console.log("path", path);
}
try
{
axios.request({
url: path,
method,
headers: {
"Authorization": `Bearer ${ crm_jwt }`,
"Content-Type": "application/json"
},
data,
})
.then((crm_response) =>
{
if(log)
{
console.log("crm_response for", path);
console.log("payload", payload);
console.log(inspect(crm_response.data, true, null, true));
}
res.status(200).json(crm_response.data);
})
.catch((error) =>
{
console.error(error);
console.error("-".repeat(30), "error.response.data:");
console.error(error.response.data);
res.status(500).json(error.response.data);
});
}
catch(e)
{
console.error(e);
res.status(500).send(e);
}
}
else
{
res.status(403);
}
}
}

View File

@ -1,13 +1,15 @@
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
import fs from 'fs';
import axios from 'axios';
import { Cookies } from 'react-cookie';
import cookie from 'cookie';
import moment from 'moment';
import jwt from 'jsonwebtoken';
import { cors } from '../cors';
import { inspect } from 'util';
export default async function CRMRequestGet(req, res, path, params)
import { cors } from '../cors';
export default async function CRMRequestGet({ req, res, path, params, data = undefined, log = false, headers = {}, options = {} })
{
await cors(req, res);
@ -16,47 +18,55 @@ export default async function CRMRequestGet(req, res, path, params)
const cookies = cookie.parse(req.headers?.cookie ? req.headers?.cookie : "");
//console.log("-".repeat(50));
//console.log("CRMRequestGet", "req.body");
//console.log(req.body);
if(cookies.jwt !== undefined && cookies.jwt !== null)
{
//console.log("cookies.jwt");
//console.log(cookies.jwt);
var client_jwt_decoded = jwt.verify(cookies.jwt, process.env.JWT_SECRET_CLIENT);
var crm_jwt = jwt.sign({ acc_number: client_jwt_decoded.acc_number }, process.env.JWT_SECRET_CRM, { noTimestamp: true });
//console.log("client_jwt_decoded", client_jwt_decoded);
//console.log("crm_jwt", crm_jwt);
if(log)
{
console.log("client_jwt_decoded", client_jwt_decoded);
console.log("crm_jwt", crm_jwt);
}
//console.log("path", path);
//console.log("params", { ...client_jwt_decoded, ...params });
const payload = { ...{ acc_number: client_jwt_decoded.acc_number }, ...params };
const request_options = {
headers: { ...{ "Authorization": `Bearer ${ crm_jwt }` }, ...headers },
withCredentials: true,
};
if(data !== undefined)
{
request_options.data = data;
}
else
{
request_options.params = payload;
}
try
{
await axios.get(path, {
params: { ...{ acc_number: client_jwt_decoded.acc_number }, ...params },
headers: {
"Authorization": `Bearer ${ crm_jwt }`,
},
withCredentials: true,
})
console.log({ options, __dirname });
console.log("{ ...request_options, ...options }", { ...request_options, ...options });
await axios.get(path, { ...request_options, ...options })
.then((crm_response) =>
{
//console.log("crm_response for", path);
//console.log(inspect(crm_response.data, true, null, true));
if(log)
{
console.log("crm_response for", path);
console.log("payload", payload);
console.log(inspect(crm_response.data, true, null, true));
}
res.status(200).json(crm_response.data);
})

View File

@ -7,7 +7,7 @@ import jwt from 'jsonwebtoken';
import { cors } from '../cors';
import { inspect } from 'util';
export default async function CRMRequestPost(req, res, path, params)
export default async function CRMRequestPost({ req, res, path, params, headers = {}, options = {}, array = false, log = false })
{
await cors(req, res);
@ -15,45 +15,42 @@ export default async function CRMRequestPost(req, res, path, params)
{
const cookies = cookie.parse(req.headers?.cookie ? req.headers?.cookie : "");
//console.log("-".repeat(50));
//console.log("CRMRequestPost", "req.body");
//console.log(req.body);
if(cookies.jwt !== undefined && cookies.jwt !== null)
{
//console.log("cookies.jwt");
//console.log(cookies.jwt);
var client_jwt_decoded = jwt.verify(cookies.jwt, process.env.JWT_SECRET_CLIENT);
var crm_jwt = jwt.sign({ acc_number: client_jwt_decoded.acc_number }, process.env.JWT_SECRET_CRM, { noTimestamp: true });
const payload = { ...{ acc_number: client_jwt_decoded.acc_number }, ...params };
//console.log("path", path);
//console.log("payload", payload);
if(log)
{
console.log("client_jwt_decoded", client_jwt_decoded);
console.log("crm_jwt", crm_jwt);
}
let payload;
if(array)
{
payload = params;
}
else
{
payload = { ...{ acc_number: client_jwt_decoded.acc_number }, ...params };
}
try
{
await axios.post(path, payload,
{
headers: {
//"Content-Type": "application/json",
"Authorization": `Bearer ${ crm_jwt }`,
},
headers: { ...{ "Content-Type": "application/json", "Authorization": `Bearer ${ crm_jwt }` }, ...headers },
withCredentials: true,
})
.then((crm_response) =>
{
//console.log("crm_response for", path);
//console.log(inspect(crm_response.data, true, null, true));
if(log)
{
console.log("crm_response for", path);
console.log("payload", payload);
console.log(inspect(crm_response.data, true, null, true));
}
res.status(200).json(crm_response.data);
})

View File

@ -35,6 +35,7 @@
"next-with-less": "^1.0.1",
"nextjs-cors": "^2.1.0",
"node-fetch": "^3.3.1",
"nodemailer": "^6.9.7",
"numeral": "^2.0.6",
"pdf-lib": "^1.17.1",
"pluralize-ru": "^1.0.1",

View File

@ -41,6 +41,28 @@ class Doc extends Document
<body>
<Main/>
<NextScript />
<script type="text/javascript" dangerouslySetInnerHTML={{
__html: `
(function(m,e,t,r,i,k,a){m[i]=m[i]||function(){(m[i].a=m[i].a||[]).push(arguments)};
m[i].l=1*new Date();
for (var j = 0; j < document.scripts.length; j++) {if (document.scripts[j].src === r) { return; }}
k=e.createElement(t),a=e.getElementsByTagName(t)[0],k.async=1,k.src=r,a.parentNode.insertBefore(k,a)})
(window, document, "script", "https://mc.yandex.ru/metrika/tag.js", "ym");
ym(${ process.env.YANDEX_METRIKA_ID }, "init", {
clickmap:true,
trackLinks:true,
accurateTrackBounce:true,
webvisor:true,
});
`, }}
/>
<noscript>
<div>
<img src={`https://mc.yandex.ru/watch/${ process.env.YANDEX_METRIKA_ID }`} style={{ position:'absolute', left:'-9999px' }} alt=""/>
</div>
</noscript>
</body>
</Html>
)

View File

@ -50,7 +50,7 @@ export default function ActsPage()
</aside>
<article>
<div className="acts_wrapper">
<div className="dosc_list acts_list-checkbox">
<div className="docs_list acts_list-checkbox">
<div className="row">
<p className="doc_name">
<input type="checkbox" name="name" id="name" />

View File

@ -34,6 +34,7 @@ export default async function handler(req, res)
})
.then((crm_response) =>
{
console.log("/Account/GetCompanyInfo/", "RESPONSE", { data: crm_response.data });
res.status(200).json({ ...crm_response.data, ...{ active: client_jwt_decoded.acc_number } });
})
.catch((error) =>

View File

@ -1,56 +1,6 @@
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
import axios from 'axios';
import { Cookies } from 'react-cookie';
import cookie from 'cookie';
import moment from 'moment';
import jwt from 'jsonwebtoken';
import { cors } from '../../../lib/cors';
import CRMRequestGet from '../../../lib/CRMRequestGet';
export default async function handler(req, res)
{
await cors(req, res);
if(req.headers.cookie !== undefined)
{
const cookies = cookie.parse(req.headers?.cookie ? req.headers?.cookie : "");
if(cookies.jwt !== undefined && cookies.jwt !== null)
{
var client_jwt_decoded = jwt.verify(cookies.jwt, process.env.JWT_SECRET_CLIENT);
var crm_jwt = jwt.sign(client_jwt_decoded, process.env.JWT_SECRET_CRM, { noTimestamp: true });
console.log("----------");
console.log(crm_jwt);
console.log("----------");
try
{
console.log(`${ process.env.CRM_API_HOST }/lk/Contract/GetDocumentList`, { ...client_jwt_decoded, contract_number: req.body.number });
await axios.get(`${ process.env.CRM_API_HOST }/lk/Contract/GetDocumentList`, {
params: { ...client_jwt_decoded, contract_number: req.body.number },
headers: { "Authorization": `Bearer ${ crm_jwt }`, },
withCredentials: true,
})
.then((crm_response) =>
{
console.log(`${ process.env.CRM_API_HOST }/lk/Contract/GetDocumentList`, "RESPONSE", crm_response.data);
res.status(200).json(crm_response.data);
})
.catch((error) =>
{
console.error(error);
res.status(500);
});
}
catch(e)
{
console.error(e);
res.status(500);
}
}
else
{
res.status(403);
}
}
await CRMRequestGet({ req, res, path: `${ process.env.CRM_API_HOST }/lk/Contract/GetDocumentList`, params: { contract_number: req.body.number } });
}

View File

@ -3,5 +3,5 @@ import CRMRequestGet from '../../../../lib/CRMRequestGet';
export default async function handler(req, res)
{
await CRMRequestGet(req, res, `${ process.env.CRM_API_HOST }/lk/add-contract/GetPreCalculations`, { contract_number: req.body.number });
await CRMRequestGet({ req, res, path: `${ process.env.CRM_API_HOST }/lk/add-contract/GetPreCalculations`, params: { contract_number: req.body.number } });
}

View File

@ -7,5 +7,10 @@ export default async function handler(req, res)
console.log(req.body);
console.log("-".repeat(50));
await CRMRequestPost(req, res, `${ process.env.CRM_API_HOST }/lk/add-contract/CreateCalculation?contract_number=${ req.body.contract_number }`, req.body);
await CRMRequestPost({
req, res,
path: `${ process.env.CRM_API_HOST }/lk/add-contract/CreateCalculation?contract_number=${ req.body.contract_number }`,
params: req.body,
log: true,
});
}

View File

@ -7,5 +7,5 @@ export default async function handler(req, res)
console.log(req.body);
console.log("-".repeat(50));
await CRMRequestGet(req, res, `${ process.env.CRM_API_HOST }/lk/add-contract/GetPreCalculationGraph`, { addcontract_number: req.body.calculation });
await CRMRequestGet({ req, res, path: `${ process.env.CRM_API_HOST }/lk/add-contract/GetPreCalculationGraph`, params: { addcontract_number: req.body.calculation } });
}

View File

@ -7,5 +7,5 @@ export default async function handler(req, res)
console.log(req.body);
console.log("-".repeat(50));
await CRMRequestGet(req, res, `${ process.env.CRM_API_HOST }/lk/add-contract/GetCurrentGraph`, { contract_number: req.body.number });
await CRMRequestGet({ req, res, path: `${ process.env.CRM_API_HOST }/lk/add-contract/GetCurrentGraph`, params: { contract_number: req.body.number } });
}

View File

@ -7,5 +7,10 @@ export default async function handler(req, res)
console.log(req.body);
console.log("-".repeat(50));
await CRMRequestPost(req, res, `${ process.env.CRM_API_HOST }/lk/add-contract/Signing?addcontract_number=${ req.body.addcontract_number }`, req.body);
await CRMRequestPost({
req, res,
path: `${ process.env.CRM_API_HOST }/lk/add-contract/Signing?addcontract_number=${ req.body.addcontract_number }`,
params: req.body,
log: true,
});
}

View File

@ -7,5 +7,5 @@ export default async function handler(req, res)
console.log(req.body);
console.log("-".repeat(50));
await CRMRequestGet(req, res, `${ process.env.CRM_API_HOST }/lk/add-contract/GetTypeOptions`, { ...{ contract_number: req.body.number }, ...req.body.variants });
await CRMRequestGet({ req, res, path: `${ process.env.CRM_API_HOST }/lk/add-contract/GetTypeOptions`, params: { ...{ contract_number: req.body.number }, ...req.body.variants } });
}

View File

@ -3,5 +3,5 @@ import CRMRequestGet from '../../../../lib/CRMRequestGet';
export default async function handler(req, res)
{
await CRMRequestGet(req, res, `${ process.env.CRM_API_HOST }/lk/add-contract/GetSignatories`, {});
await CRMRequestGet({ req, res, path: `${ process.env.CRM_API_HOST }/lk/add-contract/GetSignatories`, params: {} });
}

View File

@ -7,5 +7,5 @@ export default async function handler(req, res)
console.log(req.body);
console.log("-".repeat(50));
await CRMRequestGet(req, res, `${ process.env.CRM_API_HOST }/lk/add-contract/GetAvaliableGraphChangeTypes`, { ...{ contract_number: req.body.number }, ...req.body.variants });
await CRMRequestGet({ req, res, path: `${ process.env.CRM_API_HOST }/lk/add-contract/GetAvaliableGraphChangeTypes`, params: { ...{ contract_number: req.body.number }, ...req.body.variants } });
}

View File

@ -11,50 +11,65 @@ export default async function handler(req, res)
{
await cors(req, res);
if(req.headers.cookie !== undefined)
return new Promise(async (resolve) =>
{
const cookies = cookie.parse(req.headers?.cookie ? req.headers?.cookie : "");
if(cookies.jwt !== undefined && cookies.jwt !== null)
if(req.headers.cookie !== undefined)
{
var client_jwt_decoded = jwt.verify(cookies.jwt, process.env.JWT_SECRET_CLIENT);
var crm_jwt = jwt.sign(client_jwt_decoded, process.env.JWT_SECRET_CRM, { noTimestamp: true });
const cookies = cookie.parse(req.headers?.cookie ? req.headers?.cookie : "");
if(cookies.jwt !== undefined && cookies.jwt !== null)
{
var client_jwt_decoded = jwt.verify(cookies.jwt, process.env.JWT_SECRET_CLIENT);
var crm_jwt = jwt.sign(client_jwt_decoded, process.env.JWT_SECRET_CRM, { noTimestamp: true });
const result = {
upd: [],
upd_avans: [],
billfines: [],
};
const result = {
upd: [],
upd_avans: [],
billfines: [],
};
axios.get(`${ process.env.CRM_API_HOST }/lk/Contract/GetUPDListByContract`, {
params: { ...client_jwt_decoded, contract_number: req.body.number },
headers: { "Authorization": `Bearer ${ crm_jwt }`, },
})
.then((crm_response) =>
{
console.log(inspect(crm_response.data, true, null, true));
for(let i in crm_response.data)
{
if(crm_response.data[i].type === "UPD")
axios.get(`${ process.env.CRM_API_HOST }/lk/Contract/GetUPDListByContract`, {
params: { ...client_jwt_decoded, contract_number: req.body.number },
headers: { "Authorization": `Bearer ${ crm_jwt }`, },
})
.then((crm_response) =>
{
console.log(inspect(crm_response.data, true, null, true));
for(let i in crm_response.data)
{
result.upd = crm_response.data[i].upd;
if(crm_response.data[i].type === "UPD")
{
result.upd = crm_response.data[i].upd;
}
if(crm_response.data[i].type === "UPD_Avans")
{
result.upd_avans = crm_response.data[i].upd;
}
if(crm_response.data[i].type === "BillFine")
{
result.billfines = crm_response.data[i].upd;
}
}
if(crm_response.data[i].type === "UPD_Avans")
{
result.upd_avans = crm_response.data[i].upd;
}
if(crm_response.data[i].type === "BillFine")
{
result.billfines = crm_response.data[i].upd;
}
}
res.status(200).json(result);
})
.catch((error) => { console.error(error); resolve(); });
res.status(200).json(result);
resolve();
})
.catch((error) =>
{
console.error(error);
res.status(500).send();
resolve();
});
}
else
{
res.status(403).send();
resolve();
}
}
else
{
res.status(403);
res.status(403).send();
resolve();
}
}
});
}

View File

@ -1,44 +1,6 @@
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
import axios from 'axios';
import { Cookies } from 'react-cookie';
import cookie from 'cookie';
import moment from 'moment';
import jwt from 'jsonwebtoken';
import { cors } from '../../../lib/cors';
import { inspect } from 'util';
import CRMRequestGet from '../../../lib/CRMRequestGet';
export default async function handler(req, res)
{
await cors(req, res);
if(req.headers.cookie !== undefined)
{
const cookies = cookie.parse(req.headers?.cookie ? req.headers?.cookie : "");
if(cookies.jwt !== undefined && cookies.jwt !== null)
{
var client_jwt_decoded = jwt.verify(cookies.jwt, process.env.JWT_SECRET_CLIENT);
var crm_jwt = jwt.sign(client_jwt_decoded, process.env.JWT_SECRET_CRM, { noTimestamp: true });
const result = {
fines: [],
};
axios.get(`${ process.env.CRM_API_HOST }/lk/Contract/GetFineGIBDDList`, {
params: { ...client_jwt_decoded, contract_number: req.body.number },
headers: { "Authorization": `Bearer ${ crm_jwt }`, },
})
.then((crm_response) =>
{
result.fines = crm_response.data;
res.status(200).json(result);
})
.catch((error) => { console.error(error); });
}
else
{
res.status(403);
}
}
await CRMRequestGet({ req, res, path: `${ process.env.CRM_API_HOST }/lk/Contract/GetFineGIBDDList`, params: { contract_number: req.body.number } });
}

View File

@ -1,46 +1,6 @@
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
import axios from 'axios';
import { Cookies } from 'react-cookie';
import cookie from 'cookie';
import moment from 'moment';
import jwt from 'jsonwebtoken';
import { cors } from '../../../lib/cors';
import CRMRequestGet from '../../../lib/CRMRequestGet';
export default async function handler(req, res)
{
await cors(req, res);
if(req.headers.cookie !== undefined)
{
const cookies = cookie.parse(req.headers?.cookie ? req.headers?.cookie : "");
if(cookies.jwt !== undefined && cookies.jwt !== null)
{
var client_jwt_decoded = jwt.verify(cookies.jwt, process.env.JWT_SECRET_CLIENT);
var crm_jwt = jwt.sign(client_jwt_decoded, process.env.JWT_SECRET_CRM, { noTimestamp: true });
const response = await new Promise((resolve) =>
{
axios.get(`${ process.env.CRM_API_HOST }/lk/Contract/GetHelpCard`, {
params: { ...client_jwt_decoded, contract_number: req.body.number },
headers: { "Authorization": `Bearer ${ crm_jwt }`, },
withCredentials: true,
})
.then((crm_response) =>
{
resolve(crm_response.data);
})
.catch((error) =>
{
console.error(error);
resolve(error);
});
});
res.status(200).json(response);
}
else
{
res.status(403);
}
}
await CRMRequestGet({ req, res, path: `${ process.env.CRM_API_HOST }/lk/Contract/GetHelpCard`, params: { contract_number: req.body.number } });
}

View File

@ -1,66 +1,6 @@
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
import axios from 'axios';
import { Cookies } from 'react-cookie';
import cookie from 'cookie';
import moment from 'moment';
import jwt from 'jsonwebtoken';
import { cors } from '../../../lib/cors';
import CRMRequestGet from '../../../lib/CRMRequestGet';
export default async function handler(req, res)
{
await cors(req, res);
if(req.headers.cookie !== undefined)
{
const cookies = cookie.parse(req.headers?.cookie ? req.headers?.cookie : "");
console.log("req.body");
console.log(req.body);
if(cookies.jwt !== undefined && cookies.jwt !== null)
{
console.log("cookies.jwt");
console.log(cookies.jwt);
var client_jwt_decoded = jwt.verify(cookies.jwt, process.env.JWT_SECRET_CLIENT);
var crm_jwt = jwt.sign(client_jwt_decoded, process.env.JWT_SECRET_CRM, { noTimestamp: true });
console.log("client_jwt_decoded", client_jwt_decoded);
console.log("crm_jwt", crm_jwt);
console.log(`${ process.env.CRM_API_HOST }/lk/Contract/GetSchedulePayments`);
try
{
await axios.get(`${ process.env.CRM_API_HOST }/lk/Contract/GetSchedulePayments`, {
params: { ...client_jwt_decoded, contract_number: req.body.number },
headers: {
"Authorization": `Bearer ${ crm_jwt }`,
},
withCredentials: true,
})
.then((crm_response) =>
{
console.log("API", "contract", "crm_response.data");
//console.log("API", "contract", crm_response.data);
res.status(200).json(crm_response.data);
})
.catch((error) =>
{
console.error(error);
res.status(500);
});
}
catch(e)
{
console.error(e);
res.status(500);
}
}
else
{
res.status(403);
}
}
await CRMRequestGet({ req, res, path: `${ process.env.CRM_API_HOST }/lk/Contract/GetSchedulePayments`, params: { contract_number: req.body.number } });
}

View File

@ -1,49 +1,6 @@
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
import axios from 'axios';
import { Cookies } from 'react-cookie';
import cookie from 'cookie';
import moment from 'moment';
import jwt from 'jsonwebtoken';
import { cors } from '../../../lib/cors';
import CRMRequestGet from '../../../lib/CRMRequestGet';
export default async function handler(req, res)
{
await cors(req, res);
if(req.headers.cookie !== undefined)
{
const cookies = cookie.parse(req.headers?.cookie ? req.headers?.cookie : "");
if(cookies.jwt !== undefined && cookies.jwt !== null)
{
var client_jwt_decoded = jwt.verify(cookies.jwt, process.env.JWT_SECRET_CLIENT);
var crm_jwt = jwt.sign(client_jwt_decoded, process.env.JWT_SECRET_CRM, { noTimestamp: true });
try
{
await axios.get(`${ process.env.CRM_API_HOST }/lk/Contract/GetAddInfoForContract`, {
params: { ...client_jwt_decoded, contract_number: req.body.number },
headers: { "Authorization": `Bearer ${ crm_jwt }`, },
withCredentials: true,
})
.then((crm_response) =>
{
res.status(200).json(crm_response.data);
})
.catch((error) =>
{
console.error(error);
res.status(500);
});
}
catch(e)
{
console.error(e);
res.status(500);
}
}
else
{
res.status(403);
}
}
await CRMRequestGet({ req, res, path: `${ process.env.CRM_API_HOST }/lk/Contract/GetAddInfoForContract`, params: { contract_number: req.body.number } });
}

View File

@ -10,103 +10,108 @@ export default async function handler(req, res)
{
await cors(req, res);
if(req.headers.cookie !== undefined)
return new Promise(async (resolve) =>
{
const cookies = cookie.parse(req.headers?.cookie ? req.headers?.cookie : "");
console.log("req.body");
console.log(req.body);
if(cookies.jwt !== undefined && cookies.jwt !== null)
if(req.headers.cookie !== undefined)
{
console.log("cookies.jwt");
console.log(cookies.jwt);
const cookies = cookie.parse(req.headers?.cookie ? req.headers?.cookie : "");
var client_jwt_decoded = jwt.verify(cookies.jwt, process.env.JWT_SECRET_CLIENT);
var crm_jwt = jwt.sign(client_jwt_decoded, process.env.JWT_SECRET_CRM, { noTimestamp: true });
console.log("req.body");
console.log(req.body);
console.log("client_jwt_decoded", client_jwt_decoded);
console.log("crm_jwt", crm_jwt);
console.log(`${ process.env.CRM_API_HOST }/lk/Contract/GetOsago`);
const result = {
osago: null,
kasko: null,
nsib: null,
};
await Promise.all([
new Promise((resolve) => {
axios.get(`${ process.env.CRM_API_HOST }/lk/Contract/GetOsago`, {
params: { ...client_jwt_decoded, contract_number: req.body.number },
headers: { "Authorization": `Bearer ${ crm_jwt }`, },
})
.then((crm_response) => { result.osago = crm_response.data; resolve(); })
.catch((error) => { console.error(error); resolve(); });
}),
new Promise((resolve) => {
axios.get(`${ process.env.CRM_API_HOST }/lk/Contract/GetKasko`, {
params: { ...client_jwt_decoded, contract_number: req.body.number },
headers: { "Authorization": `Bearer ${ crm_jwt }`, },
})
.then((crm_response) => { result.kasko = crm_response.data; resolve(); })
.catch((error) => { console.error(error); resolve(); });
}),
new Promise((resolve) => {
axios.get(`${ process.env.CRM_API_HOST }/lk/Contract/GetNsib`, {
params: { ...client_jwt_decoded, contract_number: req.body.number },
headers: { "Authorization": `Bearer ${ crm_jwt }`, },
})
.then((crm_response) => { result.nsib = crm_response.data; resolve(); })
.catch((error) => { console.error(error); resolve(); });
}),
new Promise((resolve) => {
axios.get(`${ process.env.CRM_API_HOST }/lk/Contract/GetFinGap`, {
params: { ...client_jwt_decoded, contract_number: req.body.number },
headers: { "Authorization": `Bearer ${ crm_jwt }`, },
})
.then((crm_response) => {
result.fingap = crm_response.data;
/*result.fingap = [
{
paid: true,
period_type: "current",
invoice_url: null,
company: "АО \"ГСК \"ЮГОРИЯ\"",
site: null,
phone: null,
number: "ТестФингап",
url: null,
period: "14.07.2021 - 13.07.2022",
amount: 1200000.00
},
{
paid: false,
period_type: "prolong",
invoice_url: "353082cc-f38f-4da6-bcd4-3a6048eceb10",
company: "АО \"ГСК \"ЮГОРИЯ\"",
site: null,
phone: null,
number: "ТестФингап",
url: null,
period: "14.07.2022 - 13.07.2023",
amount: null
}
];*/
resolve();
})
.catch((error) => { console.error(error); resolve(); });
}),
])
.then(() =>
if(cookies.jwt !== undefined && cookies.jwt !== null)
{
res.status(200).json(result);
});
console.log("cookies.jwt");
console.log(cookies.jwt);
var client_jwt_decoded = jwt.verify(cookies.jwt, process.env.JWT_SECRET_CLIENT);
var crm_jwt = jwt.sign(client_jwt_decoded, process.env.JWT_SECRET_CRM, { noTimestamp: true });
console.log("client_jwt_decoded", client_jwt_decoded);
console.log("crm_jwt", crm_jwt);
console.log(`${ process.env.CRM_API_HOST }/lk/Contract/GetOsago`);
const result = {
osago: null,
kasko: null,
nsib: null,
};
await Promise.all([
new Promise((resolve_osago) => {
axios.get(`${ process.env.CRM_API_HOST }/lk/Contract/GetOsago`, {
params: { ...client_jwt_decoded, contract_number: req.body.number },
headers: { "Authorization": `Bearer ${ crm_jwt }`, },
})
.then((crm_response) => {
result.osago = crm_response.data;
resolve_osago();
})
.catch((error) => {
console.error(error);
resolve_osago();
});
}),
new Promise((resolve_kasko) => {
axios.get(`${ process.env.CRM_API_HOST }/lk/Contract/GetKasko`, {
params: { ...client_jwt_decoded, contract_number: req.body.number },
headers: { "Authorization": `Bearer ${ crm_jwt }`, },
})
.then((crm_response) => {
result.kasko = crm_response.data;
resolve_kasko();
})
.catch((error) => {
console.error(error);
resolve_kasko();
});
}),
new Promise((resolve_nsib) => {
axios.get(`${ process.env.CRM_API_HOST }/lk/Contract/GetNsib`, {
params: { ...client_jwt_decoded, contract_number: req.body.number },
headers: { "Authorization": `Bearer ${ crm_jwt }`, },
})
.then((crm_response) => {
result.nsib = crm_response.data;
resolve_nsib();
})
.catch((error) => {
console.error(error);
resolve_nsib();
});
}),
new Promise((resolve_fingap) => {
axios.get(`${ process.env.CRM_API_HOST }/lk/Contract/GetFinGap`, {
params: { ...client_jwt_decoded, contract_number: req.body.number },
headers: { "Authorization": `Bearer ${ crm_jwt }`, },
})
.then((crm_response) => {
result.fingap = crm_response.data;
resolve_fingap();
})
.catch((error) => {
console.error(error);
resolve_fingap();
});
}),
])
.then(() =>
{
res.status(200).json(result);
resolve();
});
}
else
{
res.status(403).send();
resolve();
}
}
else
{
res.status(403);
res.status(403).send();
resolve();
}
}
});
}

View File

@ -10,14 +10,14 @@ export default async function handler(req, res)
{
await cors(req, res);
if(req.headers.cookie !== undefined)
return new Promise(async (resolve) =>
{
const cookies = cookie.parse(req.headers?.cookie ? req.headers?.cookie : "");
if(cookies.jwt !== undefined && cookies.jwt !== null)
if(req.headers.cookie !== undefined)
{
if(jwt.verify(cookies.jwt, process.env.JWT_SECRET_CLIENT))
const cookies = cookie.parse(req.headers?.cookie ? req.headers?.cookie : "");
if(cookies.jwt !== undefined && cookies.jwt !== null)
{
const response = await new Promise((resolve, reject) =>
if(jwt.verify(cookies.jwt, process.env.JWT_SECRET_CLIENT))
{
axios.post(`${ process.env.NEXT_PUBLIC_API_HOST }/api/account/materials/`, {
})
@ -26,27 +26,34 @@ export default async function handler(req, res)
console.log("RESPONSE");
console.log(api_response.data);
resolve(api_response.data);
res.status(200).json(api_response.data);
resolve();
})
.catch((error) =>
{
console.log("error");
console.error(error);
reject([]);
res.status(500).send();
resolve();
});
});
res.status(200).json(response);
}
else
{
res.status(403).send();
resolve();
}
}
else
{
res.status(403);
res.status(403).send();
resolve();
}
}
else
{
res.status(403);
res.status(403).send();
resolve();
}
}
});
}

View File

@ -1,51 +1,6 @@
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
import axios from 'axios';
import { Cookies } from 'react-cookie';
import cookie from 'cookie';
import moment from 'moment';
import jwt from 'jsonwebtoken';
import { cors } from '../../../lib/cors';
import CRMRequestGet from '../../../lib/CRMRequestGet';
export default async function handler(req, res)
{
console.log("API", "penalties");
await cors(req, res);
if(req.headers.cookie !== undefined)
{
const cookies = cookie.parse(req.headers?.cookie ? req.headers?.cookie : "");
if(cookies.jwt !== undefined && cookies.jwt !== null)
{
var client_jwt_decoded = jwt.verify(cookies.jwt, process.env.JWT_SECRET_CLIENT);
var crm_jwt = jwt.sign(client_jwt_decoded, process.env.JWT_SECRET_CRM, { noTimestamp: true });
const response = await new Promise((resolve) =>
{
console.log("API", "penalties", `${ process.env.CRM_API_HOST }/lk/Contract/GetPlannedFines`, { contract_number: req.body.number, planned_date: req.body.date });
axios.get(`${ process.env.CRM_API_HOST }/lk/Contract/GetPlannedFines`, {
params: { ...client_jwt_decoded, contract_number: req.body.number, planned_date: req.body.date },
headers: { "Authorization": `Bearer ${ crm_jwt }`, },
withCredentials: true,
})
.then((crm_response) =>
{
console.log("API", "penalties", "crm_response.data", crm_response.data);
resolve(crm_response.data);
})
.catch((error) =>
{
console.error(error);
resolve(error);
});
});
res.status(200).json(response);
}
else
{
res.status(403);
}
}
await CRMRequestGet({ req, res, path: `${ process.env.CRM_API_HOST }/lk/Contract/GetPlannedFines`, params: { contract_number: req.body.number, planned_date: req.body.date } });
}

View File

@ -1,46 +1,6 @@
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
import axios from 'axios';
import { Cookies } from 'react-cookie';
import cookie from 'cookie';
import moment from 'moment';
import jwt from 'jsonwebtoken';
import { cors } from '../../../lib/cors';
import CRMRequestGet from '../../../lib/CRMRequestGet';
export default async function handler(req, res)
{
await cors(req, res);
if(req.headers.cookie !== undefined)
{
const cookies = cookie.parse(req.headers?.cookie ? req.headers?.cookie : "");
if(cookies.jwt !== undefined && cookies.jwt !== null)
{
var client_jwt_decoded = jwt.verify(cookies.jwt, process.env.JWT_SECRET_CLIENT);
var crm_jwt = jwt.sign(client_jwt_decoded, process.env.JWT_SECRET_CRM, { noTimestamp: true });
const response = await new Promise((resolve) =>
{
axios.get(`${ process.env.CRM_API_HOST }/lk/Contract/GetRegistration`, {
params: { ...client_jwt_decoded, contract_number: req.body.number },
headers: { "Authorization": `Bearer ${ crm_jwt }`, },
withCredentials: true,
})
.then((crm_response) =>
{
resolve(crm_response.data);
})
.catch((error) =>
{
console.error(error);
resolve(error);
});
});
res.status(200).json(response);
}
else
{
res.status(403);
}
}
await CRMRequestGet({ req, res, path: `${ process.env.CRM_API_HOST }/lk/Contract/GetRegistration`, params: { contract_number: req.body.number } });
}

View File

@ -10,14 +10,14 @@ export default async function handler(req, res)
{
await cors(req, res);
if(req.headers.cookie !== undefined)
return new Promise(async (resolve) =>
{
const cookies = cookie.parse(req.headers?.cookie ? req.headers?.cookie : "");
if(cookies.jwt !== undefined && cookies.jwt !== null)
if(req.headers.cookie !== undefined)
{
if(jwt.verify(cookies.jwt, process.env.JWT_SECRET_CLIENT))
const cookies = cookie.parse(req.headers?.cookie ? req.headers?.cookie : "");
if(cookies.jwt !== undefined && cookies.jwt !== null)
{
const response = await new Promise((resolve, reject) =>
if(jwt.verify(cookies.jwt, process.env.JWT_SECRET_CLIENT))
{
axios.post(`${ process.env.NEXT_PUBLIC_API_HOST }/api/account/rules/`, {
date: req.body.date,
@ -27,27 +27,34 @@ export default async function handler(req, res)
console.log("RESPONSE");
console.log(api_response.data);
resolve(api_response.data);
res.status(200).json(api_response.data);
resolve();
})
.catch((error) =>
{
console.log("error");
console.error(error);
reject([]);
res.status(500).send();
resolve();
});
});
res.status(200).json(response);
}
else
{
res.status(403).send();
resolve();
}
}
else
{
res.status(403);
res.status(403).send();
resolve();
}
}
else
{
res.status(403);
res.status(403).send();
resolve();
}
}
});
}

View File

@ -0,0 +1,19 @@
import CRMRequestGet from '../../../../../lib/CRMRequestGet';
export default async function handler(req, res)
{
console.log("\n\n", "API", "SIGN", "/attorney/check");
const { contract_number, addcontract_number, contactid, } = req.body;
const payload = {
contract_number,
addcontract_number,
contactid,
};
await CRMRequestGet({ req, res,
path: `${ process.env.CRM_API_HOST }/lk/Contract/CheckPowerAttorneyClient`,
params: payload,
log: true,
});
}

View File

@ -0,0 +1,19 @@
import CRMRequestGet from '../../../../../lib/CRMRequestGet';
export default async function handler(req, res)
{
console.log("\n\n", "API", "SIGN", "/attorney/get");
const { contract_number, addcontract_number, contactid, } = req.body;
const payload = {
contract_number,
addcontract_number,
contactid,
};
await CRMRequestGet({ req, res,
path: `${ process.env.CRM_API_HOST }/lk/Contract/GetPowerAttorneyClient`,
params: payload,
log: true,
});
}

View File

@ -0,0 +1,19 @@
import CRMRequestGet from '../../../../../lib/CRMRequestGet';
export default async function handler(req, res)
{
console.log("\n\n", "API", "SIGN", "/cancel/check");
const { contract_number, addcontract_number, doc_type_id } = req.body;
const payload = {
contract_number,
addcontract_number,
doc_type_id,
};
await CRMRequestGet({ req, res,
path: `${ process.env.CRM_API_HOST }/lk/Contract/CheckCancelDocument`,
params: payload,
log: true,
});
}

View File

@ -0,0 +1,19 @@
import CRMRequestGet from '../../../../../lib/CRMRequestGet';
export default async function handler(req, res)
{
console.log("\n\n", "API", "SIGN", "/cancel");
const { contract_number, addcontract_number, doc_type_id } = req.body;
const payload = {
contract_number,
addcontract_number,
doc_type_id,
};
await CRMRequestGet({ req, res,
path: `${ process.env.CRM_API_HOST }/lk/Contract/CancelDocument`,
params: payload,
log: true,
});
}

View File

@ -0,0 +1,19 @@
import CRMRequestGet from '../../../../lib/CRMRequestGet';
export default async function handler(req, res)
{
console.log("\n\n", "API", "SIGN", "api/contract/sign/check");
const { contract_number, addcontract_number, sign_type } = req.body;
const payload = {
contract_number,
addcontract_number,
sign_type,
};
await CRMRequestGet({ req, res,
path: `${ process.env.CRM_API_HOST }/lk/Contract/CheckCreatePrintForm`,
params: payload,
log: true,
});
}

View File

@ -0,0 +1,20 @@
import CRMRequestGet from '../../../../../lib/CRMRequestGet';
export default async function handler(req, res)
{
console.log("\n\n", "API", "SIGN", "/document/check");
const { contract_number, addcontract_number } = req.body;
const payload = {
contract_number,
addcontract_number,
};
console.log({ payload });
await CRMRequestGet({ req, res,
path: `${ process.env.CRM_API_HOST }/lk/Contract/CheckDownloadContractProject`,
params: payload,
log: true,
});
}

View File

@ -0,0 +1,20 @@
import CRMRequestGet from '../../../../../lib/CRMRequestGet';
export default async function handler(req, res)
{
console.log("\n\n", "API", "SIGN", "/sign/document/connect");
const { contract_number, addcontract_number, } = req.body;
const payload = {
contract_number,
addcontract_number,
};
console.log({ payload });
await CRMRequestGet({ req, res,
path: `${ process.env.CRM_API_HOST }/lk/Contract/DocEdoConnect`,
params: payload,
log: true,
});
}

View File

@ -0,0 +1,26 @@
import CRMRequestPost from '../../../../../lib/CRMRequestPost';
export default async function handler(req, res)
{
console.log("\n\n", "API", "SIGN", "/document/create");
const { entity_name, entity_id, sign_type, evo_id, code } = req.body;
const payload = {
entityName: entity_name,
entityId: entity_id,
reportCodes: [ code ],
inputParameters: [ sign_type ],
createDocument: true,
openFile: false,
documentTypeEvoId: evo_id,
};
console.log({ payload });
await CRMRequestPost({ req, res,
path: `${ process.env.CRM_API_HOST }/File/GetWMDoc`,
params: payload,
headers: { "Content-Type": "application/json" },
log: true,
});
}

View File

@ -0,0 +1,84 @@
import fs from 'fs';
import axios from 'axios';
import { Cookies } from 'react-cookie';
import cookie from 'cookie';
import moment from 'moment';
import jwt from 'jsonwebtoken';
import { inspect } from 'util';
import { cors } from '../../../../../lib/cors';
export default async function handler(req, res)
{
console.log("\n\n", "API", "SIGN", "/document/download");
await cors(req, res);
const { entity_name, entity_id, sign_type, evo_id } = req.query;
const payload = {
entityName: entity_name,
entityId: entity_id,
reportCodes: [ "Leas_Contract" ],
inputParameters: [ sign_type ],
createDocument: false,
openFile: true,
documentTypeEvoId: evo_id,
};
console.log({ payload });
return new Promise(async (resolve) =>
{
if(req.headers.cookie !== undefined)
{
const cookies = cookie.parse(req.headers?.cookie ? req.headers?.cookie : "");
if(cookies.jwt !== undefined && cookies.jwt !== null)
{
var client_jwt_decoded = jwt.verify(cookies.jwt, process.env.JWT_SECRET_CLIENT);
var crm_jwt = jwt.sign({ acc_number: client_jwt_decoded.acc_number }, process.env.JWT_SECRET_CRM, { noTimestamp: true });
try
{
axios.get(`${ process.env.CRM_API_HOST }/File/GetWMDoc`, {
data: JSON.stringify(payload),
responseType: 'arraybuffer',
headers: {
"Authorization": `Bearer ${ crm_jwt }`,
"Content-Type": "application/json",
},
})
.then((crm_response) =>
{
res.status(200).send(crm_response.data);
resolve();
})
.catch((error) =>
{
console.error(error);
console.error(error.data);
res.status(500).send(error.data);
resolve();
});
}
catch(e)
{
console.error(e);
res.status(500).send(e);
resolve();
}
}
else
{
res.status(403).send();
resolve();
}
}
else
{
res.status(403).send();
resolve();
}
});
}

View File

@ -0,0 +1,20 @@
import CRMRequestGet from '../../../../../lib/CRMRequestGet';
export default async function handler(req, res)
{
console.log("\n\n", "API", "SIGN", "/document/link");
const { contract_number, addcontract_number, } = req.body;
const payload = {
contract_number,
addcontract_number,
};
console.log({ payload });
await CRMRequestGet({ req, res,
path: `${ process.env.CRM_API_HOST }/lk/Contract/GetFileContractProject`,
params: payload,
log: true,
});
}

View File

@ -0,0 +1,20 @@
import CRMRequestGet from '../../../../../lib/CRMRequestGet';
export default async function handler(req, res)
{
console.log("\n\n", "API", "SIGN", "/sign/document/status");
const { contract_number, addcontract_number, } = req.body;
const payload = {
contract_number,
addcontract_number,
};
console.log({ payload });
await CRMRequestGet({ req, res,
path: `${ process.env.CRM_API_HOST }/lk/Contract/GetEdoProjectID`,
params: payload,
log: true,
});
}

View File

@ -0,0 +1,116 @@
import fs from 'fs';
import axios from 'axios';
import { Cookies } from 'react-cookie';
import cookie from 'cookie';
import moment from 'moment';
import jwt from 'jsonwebtoken';
import Redis from 'ioredis';
import md5 from 'md5';
import { inspect } from 'util';
import multer from 'multer';
import nodemailer from "nodemailer";
import { cors } from '../../../../../lib/cors';
const transporter = nodemailer.createTransport({
host: process.env.EMAIL_HOSTNAME,
port: 465,
secure: true,
auth: {
user: process.env.EMAIL_USERNAME,
pass: process.env.EMAIL_PASSWORD,
},
});
console.log({ host: process.env.EMAIL_HOSTNAME, user: process.env.EMAIL_USERNAME, pass: process.env.EMAIL_PASSWORD });
const storage = multer.memoryStorage();
const upload = multer({ storage: storage, limits: { fileSize: 1024 * 1024 * 300 } });
export default async function handler(req, res)
{
console.log("\n\n", "API", "SIGN", "/document/upload");
await cors(req, res);
return new Promise(async (resolve) =>
{
if(req.headers.cookie !== undefined)
{
const cookies = cookie.parse(req.headers?.cookie ? req.headers?.cookie : "");
if(cookies.jwt !== undefined && cookies.jwt !== null)
{
var client_jwt_decoded = jwt.verify(cookies.jwt, process.env.JWT_SECRET_CLIENT);
var crm_jwt = jwt.sign({ acc_number: client_jwt_decoded.acc_number }, process.env.JWT_SECRET_CRM, { noTimestamp: true });
upload.array("files", 10)(req, {}, (err) =>
{
const { contract_number, deal_id, } = req.body;
const { files } = req;
const attachments = [];
for(let i in files)
{
attachments.push({
filename: Buffer.from(files[i].originalname, 'latin1').toString('utf8'),
content: files[i].buffer,
});
}
axios.get(`${ process.env.CRM_API_HOST }/lk/Account/GetCompanyInfo/`, {
params: {
acc_number: client_jwt_decoded.acc_number,
},
headers: {
"Authorization": `Bearer ${ crm_jwt }`,
}
})
.then(async (crm_response) =>
{
console.log({ crm_response: crm_response.data });
const { manager_email } = crm_response.data;
if(manager_email !== undefined && manager_email !== null && manager_email !== "")
{
const mail_result = await transporter.sendMail({
from: process.env.EMAIL_USERNAME,
to: manager_email,
subject: `Скан договора №${ contract_number } для сделки №${ deal_id }`,
text: `Клиентом загружен скан договора №${ contract_number } для сделки №${ deal_id }`,
attachments,
});
console.log({ mail_result });
}
res.status(200).send();
resolve();
})
.catch((crm_error) =>
{
console.error("\n\n", "API", "SIGN", "/document/upload");
console.error(crm_error);
res.status(500).send();
resolve();
})
});
}
else
{
res.status(403).send();
resolve();
}
}
else
{
res.status(403).send();
resolve();
}
});
}
export const config = {
api: {
bodyParser: false
}
}

View File

@ -0,0 +1,18 @@
import CRMRequestGet from '../../../../lib/CRMRequestGet';
export default async function handler(req, res)
{
console.log("\n\n", "API", "SIGN", "/entity");
const { contract_number, addcontract_number, } = req.body;
const payload = {
contract_number,
addcontract_number,
};
await CRMRequestGet({ req, res,
path: `${ process.env.CRM_API_HOST }/lk/Contract/GetGUIDEntity`,
params: payload,
log: true,
});
}

View File

@ -1,46 +1,6 @@
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
import axios from 'axios';
import { Cookies } from 'react-cookie';
import cookie from 'cookie';
import moment from 'moment';
import jwt from 'jsonwebtoken';
import { cors } from '../../../lib/cors';
import CRMRequestGet from '../../../lib/CRMRequestGet';
export default async function handler(req, res)
{
await cors(req, res);
if(req.headers.cookie !== undefined)
{
const cookies = cookie.parse(req.headers?.cookie ? req.headers?.cookie : "");
if(cookies.jwt !== undefined && cookies.jwt !== null)
{
var client_jwt_decoded = jwt.verify(cookies.jwt, process.env.JWT_SECRET_CLIENT);
var crm_jwt = jwt.sign(client_jwt_decoded, process.env.JWT_SECRET_CRM, { noTimestamp: true });
const response = await new Promise((resolve) =>
{
axios.get(`${ process.env.CRM_API_HOST }/lk/Contract/GetTelematics`, {
params: { ...client_jwt_decoded, contract_number: req.body.number },
headers: { "Authorization": `Bearer ${ crm_jwt }`, },
withCredentials: true,
})
.then((crm_response) =>
{
resolve(crm_response.data);
})
.catch((error) =>
{
console.error(error);
resolve(error);
});
});
res.status(200).json(response);
}
else
{
res.status(403);
}
}
await CRMRequestGet({ req, res, path: `${ process.env.CRM_API_HOST }/lk/Contract/GetTelematics`, params: { contract_number: req.body.number } });
}

26
pages/api/deals/accept.js Normal file
View File

@ -0,0 +1,26 @@
/*
2.7.3 - Метод согласования Предложений Клиентом по Лизинговой сделке в CRM
POST /lk/ConsiderationOpportunity/quote
*/
import CRMRequestPost from '../../../lib/CRMRequestPost';
export default async function handler(req, res)
{
console.log("\n\n", "API", "DEALS", "quote");
console.log(req.body);
console.log("-".repeat(50));
const { deal_id, offers } = req.body;
console.log("/accept");
console.log({ offers });
await CRMRequestPost({
req, res,
path: `${ process.env.CRM_API_HOST }/lk/ConsiderationOpportunity/quote?opp_number=${ deal_id }`,
params: offers,
array: true,
log: true,
});
}

View File

@ -1,4 +1,17 @@
/*
2.7.6 - Метод получения списка договоров со статусами по Лизинговой сделке в CRM
GET /lk/ConsiderationOpportunity/contract
*/
*/
import CRMRequestGet from '../../../lib/CRMRequestGet';
export default async function handler(req, res)
{
console.log("\n\n", "API", "DEALS", "contracts");
console.log(req.body);
console.log("-".repeat(50));
const { deal_id } = req.body;
await CRMRequestGet({ req, res, path: `${ process.env.CRM_API_HOST }/lk/ConsiderationOpportunity/contract`, params: { ...{ opp_number: deal_id } } });
}

View File

@ -1,4 +1,91 @@
/*
2.7.4 - Метод получения списка документов для рассмотрения Лизинговой сделке в CRM
GET /lk/ConsiderationOpportunity/document
*/
*/
import axios from 'axios';
import { Cookies } from 'react-cookie';
import cookie from 'cookie';
import moment from 'moment';
import jwt from 'jsonwebtoken';
import { cors } from '../../../lib/cors';
import RedisClient from '../../../lib/RedisClient';
export default async function handler(req, res)
{
console.log("\n\n", "API", "DEALS", "documents");
await cors(req, res);
const { deal_id } = req.body;
return new Promise((resolve) =>
{
if(req.headers.cookie !== undefined)
{
const cookies = cookie.parse(req.headers?.cookie ? req.headers?.cookie : "");
if(cookies.jwt !== undefined && cookies.jwt !== null)
{
var client_jwt_decoded = jwt.verify(cookies.jwt, process.env.JWT_SECRET_CLIENT);
var crm_jwt = jwt.sign(client_jwt_decoded, process.env.JWT_SECRET_CRM, { noTimestamp: true });
try
{
axios.get(`${ process.env.CRM_API_HOST }/lk/ConsiderationOpportunity/document`, {
params: { opp_number: deal_id },
headers: {
"Authorization": `Bearer ${ crm_jwt }`,
}
})
.then(async (crm_response) =>
{
const documents = crm_response.data;
const key = `deals_${ client_jwt_decoded.acc_number }`;
var deals = await RedisClient.get(key);
console.log({ key })
var files = {};
var uploaded = {};
if(deals !== null)
{
deals = JSON.parse(deals);
if(deals[ deal_id ] !== undefined)
{
files = deals[ deal_id ].files;
uploaded = deals[ deal_id ].uploaded;
}
}
res.status(200).send({ documents, files, uploaded, });
resolve();
})
.catch((error) =>
{
console.error(error);
res.status(500).send();
resolve();
});
}
catch(e)
{
console.error(e);
res.status(500).send();
resolve();
}
}
else
{
res.status(403).send();
resolve();
}
}
else
{
res.status(403).send();
resolve();
}
});
}

View File

@ -0,0 +1,125 @@
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
import fs from 'fs';
import axios from 'axios';
import { Cookies } from 'react-cookie';
import cookie from 'cookie';
import moment from 'moment';
import jwt from 'jsonwebtoken';
import Redis from 'ioredis';
import md5 from 'md5';
import { inspect } from 'util';
import multer from 'multer';
import { cors } from '../../../../lib/cors';
import RedisClient from '../../../../lib/RedisClient';
const storage = multer.memoryStorage();
const upload = multer({ storage: storage, limits: { fileSize: 1024 * 1024 * 300 } });
export default async function handler(req, res)
{
console.log("\n\n", "API", "DEALS", "FILE", "upload");
await cors(req, res);
return new Promise(async (resolve) =>
{
if(req.headers.cookie !== undefined)
{
const cookies = cookie.parse(req.headers?.cookie ? req.headers?.cookie : "");
if(cookies.jwt !== undefined && cookies.jwt !== null)
{
var client_jwt_decoded = jwt.verify(cookies.jwt, process.env.JWT_SECRET_CLIENT);
upload.single("file")(req, {}, async (err) =>
{
const { file, } = req;
const { deal_id, document_id, document_name, group, type, index, lastModified, } = req.query;
console.log({ deal_id, document_id, document_name, group, type, index, lastModified, });
const local_filename = `${ client_jwt_decoded.acc_number }_${ deal_id }_${ group }_${ index }`;
const file_payload = {
name: Buffer.from(file.originalname, 'latin1').toString('utf8'),
filename: local_filename,
document_id: document_id,
group,
index,
type,
uploaded: true,
lastModified,
};
try
{
fs.writeFileSync(`${ __dirname }/../../../../../../uploads/deals/${ local_filename }`, file.buffer);
console.log("multer.upload.single file");
console.log({ file_payload });
const key = `deals_${ client_jwt_decoded.acc_number }`;
var deals = await RedisClient.get(key);
var uploaded = {};
//var files = {};
if(deals !== null)
{
deals = JSON.parse(deals);
if(deals[ deal_id ] !== undefined)
{
//files = deals[ deal_id ].files;
uploaded = deals[ deal_id ].uploaded;
}
}
else
{
deals = {};
}
if(uploaded !== undefined)
{
if(uploaded[ group ] !== undefined)
{
uploaded[ group ].files.push(file_payload);
}
else
{
uploaded[ group ] = {
id: document_id,
name: document_name,
files: [ file_payload ],
}
}
}
deals[ deal_id ] = { uploaded };
await RedisClient.set(key, JSON.stringify(deals));
res.status(200).json(file_payload);
resolve();
}
catch(upload_single_error)
{
console.error("upload_single_error");
console.error(upload_single_error);
res.status(500).send();
resolve();
}
});
}
else
{
res.status(403).send();
resolve();
}
}
});
}
export const config = {
api: {
bodyParser: false
}
}

View File

@ -0,0 +1,114 @@
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
import fs from 'fs';
import axios from 'axios';
import { Cookies } from 'react-cookie';
import cookie from 'cookie';
import moment from 'moment';
import jwt from 'jsonwebtoken';
import Redis from 'ioredis';
import md5 from 'md5';
import { inspect } from 'util';
import multer from 'multer';
import { cors } from '../../../../lib/cors';
import RedisClient from '../../../../lib/RedisClient';
const storage = multer.memoryStorage();
const upload = multer({ storage: storage });
export default async function handler(req, res)
{
console.log("\n\n", "API", "DEALS", "FILE", "remove");
await cors(req, res);
return new Promise(async (resolve) =>
{
if(req.headers.cookie !== undefined)
{
const cookies = cookie.parse(req.headers?.cookie ? req.headers?.cookie : "");
if(cookies.jwt !== undefined && cookies.jwt !== null)
{
var client_jwt_decoded = jwt.verify(cookies.jwt, process.env.JWT_SECRET_CLIENT);
const { deal_id, group, index } = req.query;
const local_filename = `${ client_jwt_decoded.acc_number }_${ deal_id }_${ group }_${ index }`;
try
{
console.log("local_filename", local_filename);
const filename = `${ __dirname }/../../../../../../uploads/deals/${ local_filename }`;
if (fs.existsSync(filename))
{
fs.unlinkSync(filename);
}
const key = `deals_${ client_jwt_decoded.acc_number }`;
var deals = await RedisClient.get(key);
var uploaded = {};
var files = {};
if(deals !== null)
{
deals = JSON.parse(deals);
if(deals[ deal_id ] !== undefined)
{
//files = deals[ deal_id ].files;
uploaded = deals[ deal_id ].uploaded;
}
}
else
{
deals = {};
}
if(uploaded !== undefined)
{
if(uploaded[ group ] !== undefined)
{
if(uploaded[ group ].files !== undefined)
{
console.log({ files: uploaded[ group ].files });
uploaded[ group ].files.splice(index, 1);
}
}
}
deals[ deal_id ] = { uploaded };
await RedisClient.set(key, JSON.stringify(deals));
// }
// else
// {
// console.error("NOT exists filename", filename);
// }
res.status(200).send();
resolve();
}
catch(remove_single_error)
{
console.error("remove_single_error");
console.error(remove_single_error);
res.status(500).send();
resolve();
}
}
else
{
res.status(403).send();
resolve();
}
}
});
}
export const config = {
api: {
bodyParser: false
}
}

View File

@ -3,82 +3,11 @@
GET /lk/ConsiderationOpportunity
*/
import axios from 'axios';
import { Cookies } from 'react-cookie';
import cookie from 'cookie';
import moment from 'moment';
import jwt from 'jsonwebtoken';
import { cors } from '../../../lib/cors';
import CRMRequestGet from '../../../lib/CRMRequestGet';
export default async function handler(req, res)
{
await cors(req, res);
console.log("\n\n", "API", "DEALS", "index");
return new Promise(async (resolve) =>
{
if(req.headers.cookie !== undefined)
{
const cookies = cookie.parse(req.headers?.cookie ? req.headers?.cookie : "");
console.log("req.body");
console.log(req.body);
if(cookies.jwt !== undefined && cookies.jwt !== null)
{
console.log("cookies.jwt");
console.log(cookies.jwt);
var client_jwt_decoded = jwt.verify(cookies.jwt, process.env.JWT_SECRET_CLIENT);
const crm_payload = { acc_number: client_jwt_decoded.acc_number };
var crm_jwt = jwt.sign(crm_payload, process.env.JWT_SECRET_CRM, { noTimestamp: true });
console.log("client_jwt_decoded", client_jwt_decoded);
console.log("crm_jwt", crm_jwt);
const url = `${ process.env.CRM_API_HOST }/lk/ConsiderationOpportunity`;
console.log({ url });
try
{
await axios.get(url, {
params: crm_payload,
headers: {
"Authorization": `Bearer ${ crm_jwt }`,
},
withCredentials: true,
})
.then((crm_response) =>
{
console.log("API", "contract", "crm_response.data");
//console.log("API", "contract", crm_response.data);
res.status(200).json(crm_response.data);
resolve();
})
.catch((error) =>
{
console.error(error);
res.status(500).send();
resolve();
});
}
catch(e)
{
console.error(e);
res.status(500).send();
resolve();
}
}
else
{
res.status(403).send();
resolve();
}
}
else
{
res.status(403).send();
resolve();
}
});
await CRMRequestGet({ req, res, path: `${ process.env.CRM_API_HOST }/lk/ConsiderationOpportunity/`, params: {} });
}

View File

@ -0,0 +1,82 @@
import fs from 'fs';
import axios from 'axios';
import { Cookies } from 'react-cookie';
import cookie from 'cookie';
import moment from 'moment';
import jwt from 'jsonwebtoken';
import { inspect } from 'util';
import { cors } from '../../../../lib/cors';
export default async function handler(req, res)
{
console.log("\n\n", "API", "DEALS", "/offer/download");
await cors(req, res);
const { quote_number, } = req.query;
return new Promise(async (resolve) =>
{
if(req.headers.cookie !== undefined)
{
const cookies = cookie.parse(req.headers?.cookie ? req.headers?.cookie : "");
if(cookies.jwt !== undefined && cookies.jwt !== null)
{
var client_jwt_decoded = jwt.verify(cookies.jwt, process.env.JWT_SECRET_CLIENT);
var crm_jwt = jwt.sign({ acc_number: client_jwt_decoded.acc_number }, process.env.JWT_SECRET_CRM, { noTimestamp: true });
const payload = {
quote_number,
acc_number: client_jwt_decoded.acc_number,
};
console.log({ payload });
try
{
axios.get(`${ process.env.CRM_API_HOST }/lk/ConsiderationOpportunity/quote/offerprintform`, {
params: payload,
responseType: 'arraybuffer',
headers: {
"Authorization": `Bearer ${ crm_jwt }`,
"Content-Type": "application/json",
},
})
.then((crm_response) =>
{
console.log("API", "DEALS", "/offer/download", "RESPONSE");
res.status(200).send(crm_response.data);
resolve();
})
.catch((error) =>
{
console.error("API", "DEALS", "/offer/download", "ERROR");
console.error(error);
console.error(error.data);
res.status(500).send(error.data);
resolve();
});
}
catch(e)
{
console.error(e);
res.status(500).send(e);
resolve();
}
}
else
{
res.status(403).send();
resolve();
}
}
else
{
res.status(403).send();
resolve();
}
});
}

View File

@ -0,0 +1,17 @@
/*
2.7.2 - Метод получения списка Предложений по Лизинговой сделке в CRM
GET /lk/ConsiderationOpportunity/quote
*/
import CRMRequestGet from '../../../../lib/CRMRequestGet';
export default async function handler(req, res)
{
console.log("\n\n", "API", "DEALS", "offers");
console.log(req.body);
console.log("-".repeat(50));
const { deal_id } = req.body;
await CRMRequestGet({ req, res, path: `${ process.env.CRM_API_HOST }/lk/ConsiderationOpportunity/quote`, params: { ...{ opp_number: deal_id } } });
}

View File

@ -1,4 +1,17 @@
/*
2.7.2 - Метод получения списка Предложений по Лизинговой сделке в CRM
GET /lk/ConsiderationOpportunity/quote
*/
*/
import CRMRequestGet from '../../../lib/CRMRequestGet';
export default async function handler(req, res)
{
console.log("\n\n", "API", "DEALS", "offers");
console.log(req.body);
console.log("-".repeat(50));
const { deal_id } = req.body;
await CRMRequestGet({ req, res, path: `${ process.env.CRM_API_HOST }/lk/ConsiderationOpportunity/quote`, params: { ...{ opp_number: deal_id } } });
}

View File

@ -1,4 +0,0 @@
/*
2.7.3 - Метод согласования Предложений Клиентом по Лизинговой сделке в CRM
POST /lk/ConsiderationOpportunity/quote
*/

View File

@ -1,4 +1,255 @@
/*
2.7.5 - Метод отправки документов по Сделке на проверку
POST /lk/document
*/
*/
import fs from 'fs';
import axios from 'axios';
import { Cookies } from 'react-cookie';
import cookie from 'cookie';
import moment from 'moment';
import jwt from 'jsonwebtoken';
import { inspect } from 'util';
import FormData from 'form-data';
import multer from 'multer';
import { eachLimit, eachSeries } from 'async';
import archiver from 'archiver';
import { cors } from '../../../lib/cors';
import RedisClient from '../../../lib/RedisClient';
const uploads = `${ __dirname }/../../../../../uploads/deals/`;
/*
function uploadFiles()
{
return new Promise(() => )
}
*/
function createZipFile(zip_filename, files)
{
return new Promise(async (resolve) =>
{
const output = fs.createWriteStream(zip_filename);
const archive = archiver('zip', {
zlib: { level: 9 } // Sets the compression level.
});
output.on('close', function()
{
console.log('archive on close');
resolve();
});
output.on('end', function()
{
console.log('archive on end');
});
archive.on('warning', function(err)
{
if (err.code === 'ENOENT')
{
} else {
throw err;
}
});
archive.on('error', function(err)
{
throw err;
});
archive.pipe(output);
for(let i in files)
{
archive.append(fs.createReadStream(files[i].path), { name: files[i].name });
}
archive.finalize();
});
}
function uploadFile({ deal_id, local_filename, filename, name, id, crm_jwt })
{
return new Promise((resolve) =>
{
if(fs.existsSync(`${ uploads }${ local_filename }`))
{
const path = `${ uploads }${ local_filename }`;
const file_to_send_data = fs.readFileSync(path);
console.log("uploadFile", { filename, len: file_to_send_data.length, path });
const data = new FormData();
data.append("file", file_to_send_data, filename);
const payload = new URLSearchParams({
name: deal_id,
entity: "opportunity",
documentTypeNumber: id,
documentName: name,
});
console.log("uploadFile", { payload });
const payload_string = new URLSearchParams(payload).toString();
const file_upload_url = `${ process.env.CRM_API_HOST }/lk/document/upload?${ payload_string }`;
console.log( file_upload_url );
axios.post(file_upload_url, data,
{
headers: {
"Content-Type": `multipart/form-data; boundary=${ data._boundary }`,
"Authorization": `Bearer ${ crm_jwt }`,
},
withCredentials: true,
})
.then(() =>
{
console.log("FILE", filename, "SENT");
resolve();
})
.catch((error) =>
{
console.error("FILE", filename, "ERROR");
console.error(error);
resolve();
});
}
else
{
resolve();
}
});
}
export default async function handler(req, res)
{
console.log("\n\n", "API", "DEALS", "upload");
await cors(req, res);
// const { number, entity, id, filename } = req.query;
const { deal_id } = req.body;
return new Promise(async (resolve) =>
{
if(req.headers.cookie !== undefined)
{
const cookies = cookie.parse(req.headers?.cookie ? req.headers?.cookie : "");
if(cookies.jwt !== undefined && cookies.jwt !== null)
{
var client_jwt_decoded = jwt.verify(cookies.jwt, process.env.JWT_SECRET_CLIENT);
var crm_jwt = jwt.sign({ acc_number: client_jwt_decoded.acc_number }, process.env.JWT_SECRET_CRM, { noTimestamp: true });
const key = `deals_${ client_jwt_decoded.acc_number }`;
var deals = await RedisClient.get(key);
var files = [];
if(deals !== null)
{
deals = JSON.parse(deals);
if(deals[ deal_id ] !== undefined)
{
//for(let i in deals[ deal_id ].uploaded.files)
//{
// files.push(deals[ deal_id ].uploaded.files[i]);
//}
eachSeries(Object.keys(deals[ deal_id ].uploaded), (group, callback) =>
{
const document = deals[ deal_id ].uploaded[ group ];
console.log({ group, document, });
if(document.files.length === 1)
{
const file = document.files[0];
uploadFile({ deal_id, local_filename: file.filename, filename: file.name, name: document.name, id: document.id, crm_jwt })
.then(() =>
{
callback();
});
}
else
{
let files_to_zip = [];
for(let f in document.files)
{
const file = document.files[f];
const ext_regex = new RegExp("\.([0-9a-z]+)$", "i");
const ext = file.name.match(ext_regex);
files_to_zip.push({
name: `${ file.name }`,
path: `${ uploads }${ file.filename }`,
});
}
const zip_filename = `${ client_jwt_decoded.acc_number }_${ deal_id }_${ group }.zip`;
console.log({ files_to_zip });
createZipFile(`${ uploads }${ zip_filename }`, files_to_zip)
.then(() =>
{
uploadFile({ deal_id, local_filename: zip_filename, filename: zip_filename, name: document.name, id: document.id, crm_jwt })
.then(() =>
{
callback();
});
})
}
}, async () =>
{
console.log("ALL FILES SENT");
delete deals[ deal_id ];
await RedisClient.set(key, JSON.stringify(deals));
res.status(200).json({});
axios.post(`${ process.env.CRM_API_HOST }/lk/ConsiderationOpportunity/documentdone?opp_number=${ deal_id }`, {}, {
headers: {
"Authorization": `Bearer ${ crm_jwt }`,
},
withCredentials: true, }
)
.then(() => {})
.catch((error) =>
{
console.error(error);
});
resolve();
});
}
else
{
res.status(403).json({});
resolve();
}
}
else
{
res.status(403).json({});
resolve();
}
}
else
{
res.status(403).json({});
resolve();
}
}
else
{
res.status(403).send();
resolve();
}
});
}

22
pages/api/edo/cancel.js Normal file
View File

@ -0,0 +1,22 @@
/*
2.8.1 - Метод получения доступных для работы в ЭДО ящиков (lk/Account/GetEdoBox)
*/
import CRMRequestGet from '../../../lib/CRMRequestGet';
export default async function handler(req, res)
{
console.log("\n\n", "API", "EDO", "/edo/cancel");
const { contract_number, addcontract_number, doc_type_id, } = req.body;
const payload = {
contract_number,
addcontract_number,
doc_type_id,
};
await CRMRequestGet({ req, res,
path: `${ process.env.CRM_API_HOST }/lk/Contract/CancelDocument`,
params: payload,
log: true,
});
}

3
pages/api/edo/check.js Normal file
View File

@ -0,0 +1,3 @@
/*
2.8.2 - Метод ограничений количества отправок Приглашений Клиенту(для ЭДО) (lk/Account/GetAccessInviteEdoBox)
*/

View File

@ -0,0 +1,3 @@
/*
2.8.4 - Метод получения отправленных (но еще не принятых) приглашений Клиенту (для ЭДО) (lk/Account/GetInviteEdoBox)
*/

View File

@ -0,0 +1,16 @@
/*
2.8.3 - Метод отправки Приглашения Клиенту(для ЭДО) (lk/Account/InviteEdoBox)
*/
import CRMRequestGet from '../../../../lib/CRMRequestGet';
export default async function handler(req, res)
{
console.log("\n\n", "API", "EDO", "/invite/send");
await CRMRequestGet({ req, res,
path: `${ process.env.CRM_API_HOST }/lk/Account/InviteEdoBox`,
params: {},
log: true,
});
}

View File

@ -0,0 +1,3 @@
/*
2.8.5 - Метод обновления (по кнопке!) Приглашений Клиенту(для ЭДО) (lk/Account/UpdateEdoBox)
*/

15
pages/api/edo/invites.js Normal file
View File

@ -0,0 +1,15 @@
/*
2.8.1 - Метод получения доступных для работы в ЭДО ящиков (lk/Account/GetEdoBox)
*/
import CRMRequestGet from '../../../lib/CRMRequestGet';
export default async function handler(req, res)
{
console.log("\n\n", "API", "EDO", "/invites");
await CRMRequestGet({ req, res,
path: `${ process.env.CRM_API_HOST }/lk/Account/GetInviteEdoBox`,
params: {},
log: true,
});
}

Some files were not shown because too many files have changed in this diff Show More