2023-09-27 13:16:42 +03:00

956 lines
24 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React from "react"
import numeral from "numeral";
import moment from "moment";
import { eachLimit } from "async";
import { SpinnerCircular } from "spinners-react";
import FileDropzoneDeals from "../FileDropzoneDeals";
import { acceptDealOffers, uploadDocument } from "../../actions";
class Step extends React.Component
{
componentDidMount()
{
if(this.status.indexOf(this.props.statuscode_id) > -1)
{
this.setState({ open: true });
}
}
componentDidUpdate(prevProps, prevState)
{
if(this.props.statuscode_id !== prevProps.statuscode_id)
{
if(this.status.indexOf(this.props.statuscode_id) > -1)
{
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[ 0 ] ? { position: "relative", } : { position: "relative", cursor: "inherit" }} onClick={ statuscode_id >= this.status[ 0 ] ? this._handle_onSwitch : () => {} }>
{ this.status.indexOf(statuscode_id) > -1 && ( <div className="background"></div> )}
<i className={`status_${ this.status[ 0 ] } ${ statuscode_id < this.status[ 0 ] ? "inactive" : "" }`}></i>
<p>{ title }</p>
{ statuscode_id >= this.status[ 0 ] && (
<div className="button_arrow">
<div className={`icon ${ open ? "up" : "down" }`}></div>
</div>
) }
{ this._renderHeaderButtons !== undefined && this._renderHeaderButtons() }
</div>
)
}
}
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_numbers: 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;
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.indexOf( statuscode_id ) > -1 ? "current" : statuscode_id > this.status[ 0 ] ? "done" : "" }`}>
<p> { dealSelected }</p>
<span></span>
<div className="status_body">
{ 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>
{ statuscode_id === 100 && <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) => (
<tr key={ offer_index }>
{ offer.quote_status ? (
<td>
<div className="form_field checkbox">
<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 }`}></label>
</div>
</td>
) : (
<td></td>
)}
<td>{ offer_index + 1 }</td>
<td>{ numeral(offer.price).format(' ., ') } р.</td>
<td>{ numeral(offer.first_payment_rub).format(' ., ') } р.</td>
<td>{ offer.first_payment_perc }%</td>
<td>{ offer.brand_name }</td>
<td>{ offer.model_name }</td>
<td>{ offer.object_count }</td>
<td>
<div className="docs_list">
<div className="row">
<div className="small-icon">
<p className="doc_name i-pdf">
КП
<span>{ offer.quote_number }</span>
</p>
</div>
</div>
</div>
</td>
</tr>
)) }
</tbody>
</table>
) : (
<p>Нет предложений</p>
) }
</>
) }
</div>
</div>
</div>
)
}
}
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.indexOf( statuscode_id ) > -1 ? "current" : statuscode_id > this.status[ 0 ] ? "done" : "" }`}>
<p> { dealSelected }</p>
<span></span>
<div className="status_body">
{ this._renderHeader("Программа финансирования") }
<div className="wrap" style={{ display: open ? "block" : "none" }}>
<div className="single_text">
<p>Статусный текст о том что выбирается программа финансированияи</p>
</div>
</div>
</div>
</div>
)
}
}
class DocumentsForm extends Step
{
constructor(props)
{
super(props);
this.state = {
open: false,
files: {},
uploading: false,
completed: false,
};
this.status = [ 102 ];
}
_handle_onSendFiles = (event) =>
{
event.stopPropagation();
// event.preventDefault();
const { files } = this.state;
const files_array = [];
for(let g in files)
{
for(let f in files[g])
{
files_array.push(files[g][f])
}
}
this.setState({ uploading: true }, () =>
{
eachLimit(files_array, 1, (file, callback) =>
{
console.log({ file, props: this.props });
const { opp_number } = this.props;
const payload = {
number: opp_number,
entity: "opportunity",
id: file.group,
filename: file.name,
file,
};
uploadDocument(payload)
.then(() =>
{
this._onSendFileStats(file.group, file.index);
callback();
}, 1000)
}, () =>
{
console.log("ready");
this.setState({ uploading: false }, () =>
{
this._checkFilesCompleted();
});
});
});
}
_onSendFileStats = (group, index) =>
{
const files = { ...this.state.files };
files[group][index].sent = true;
this.setState({ files });
}
_handle_onAddFile = (file_id, files) =>
{
const existed_files = this.state.files;
const document_files = existed_files[ file_id ] === undefined ? [] : existed_files[ file_id ];
for(let nf in files)
{
let e = false;
for(let ef in document_files)
{
if(document_files[ef].name === files[nf].name) { e = true; }
}
if(!e)
{
files[nf].index = nf;
files[nf].group = file_id;
files[nf].sent = false;
document_files.push(files[nf]);
}
existed_files[ file_id ] = document_files;
this.setState({ files: existed_files }, () =>
{
this._checkFilesCompleted();
});
}
}
_handle_onDeleteFile = (file_id, file) =>
{
const files = { ...this.state.files };
const list = [];
for(let i in files[file_id])
{
if(files[file_id][i].name !== file.name)
{
list.push(files[file_id][i]);
}
}
if(list.length > 0)
{
files[file_id] = list;
}
else
{
delete files[file_id];
}
this.setState({ files }, () =>
{
this._checkFilesCompleted();
});
}
_checkFilesCompleted = () =>
{
//Object.keys(files).length > 0
const { files } = this.state;
const { documents } = this.props;
let c = true;
for(let g in documents)
{
const group = documents[g].doc_id;
if(files[group] === undefined || files[group].length === 0)
{
c = false;
break;
}
else
{
for(let f in files[group])
{
if(!files[group][f].sent)
{
c = false;
break;
}
}
}
}
/*
if(c)
{
for(let g in files)
{
for(let f in files[g])
{
if(!files[g][f].sent)
{
c = false;
break;
}
}
}
}
*/
console.log({ c })
this.setState({ completed: c });
}
_renderHeaderButtons = () =>
{
const { open, uploading, completed, } = this.state;
if(open && !uploading && !completed)
{
return (
<div className="buttons">
<button className="button button button-blue" onClick={ this._handle_onSendFiles }>Отправить документы</button>
</div>
)
}
return null;
}
render()
{
const { index, statuscode_id, dealSelected, documents, questionnaire_status } = this.props;
const { open, files, uploading } = this.state;
// console.log("DocumentsForm", { documents });
return (
<div className={`${ this.status.indexOf( statuscode_id ) > -1 ? "current" : statuscode_id > this.status[ 0 ] ? "done" : "" }`}>
<p> { dealSelected }</p>
<span></span>
<div className="status_body">
{ this._renderHeader("Сборка пакета документов") }
<div className="wrap form" style={{ display: open ? "block" : "none" }}>
<div className="block">
<div className="left">
<p><b>Устав организации:</b></p>
</div>
<div className="right">
{ questionnaire_status === "need_to_fill" ? (
<div className="message alert">
<p>Требуется обновить данные в анкете</p>
<button className="button button-blue">Актуализировать данные</button>
</div>
) : (
<>
{ questionnaire_status !== "up_to_date" ? (
<div className="message wait">
<p>Проводится проверка анкеты Вашей организации</p>
</div>
) : (
<div className="message ok">
<p>Вам не требуется актуализация данных анкеты Клиента</p>
</div>
) }
</>
) }
</div>
</div>
{ documents === undefined ? (
<></>
) : (
<>
{ documents.map((document, index) => (
<div className="block" key={ index }>
<div className="left">
<p><b><span>{ document.name }</span>:</b></p>
</div>
<div className="right">
<FileDropzoneDeals
uploading={ uploading }
files={ files[ document.doc_id ] !== undefined ? files[ document.doc_id ] : [] }
onAddFile={ (file) => { this._handle_onAddFile(document.doc_id, file) } }
onDeleteFile={ (file) => this._handle_onDeleteFile(document.doc_id, file) }
/>
</div>
</div>
)) }
</>
) }
{/*}
<div className="message documents">
<div className="doc_list">
<div className="docs_list medium-icon">
<div className="row">
<p className="doc_name i-pdf i-medium">№123/2023 от 01.01.2023</p>
</div>
</div>
<div className="docs_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>
</div>
</div>
)
}
}
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={`${ this.status.indexOf( statuscode_id ) > -1 ? "current" : statuscode_id > this.status[ 0 ] ? "done" : "" }`}>
<p> { dealSelected }</p>
<span></span>
<div className="status_body">
{ this._renderHeader("Проверка документов") }
<div className="wrap" style={{ display: open ? "block" : "none" }}>
<div className="single_text">
<p>Статусный текст о том что выбирается программа финансированияи</p>
</div>
</div>
</div>
</div>
)
}
}
class StatusDecisionMaking extends Step
{
constructor(props)
{
super(props);
this.state = {
open: false,
};
this.status = [ 104, 105, ];
}
render()
{
const { index, statuscode_id, dealSelected } = this.props;
const { open } = this.state;
return (
<div className={`${ this.status.indexOf(statuscode_id) > -1 ? "current" : (statuscode_id > this.status[0] && statuscode_id > this.status[1]) ? "done" : "" }`}>
<p> { dealSelected }</p>
<span></span>
<div className="status_body">
{ this._renderHeader("Принятие решения по сделке") }
<div className="wrap" style={{ display: open ? "block" : "none" }}>
<div className="single_text">
<p>Статусный текст о том что выбирается программа финансированияи</p>
</div>
</div>
</div>
</div>
)
}
}
class StatusLeasingRegistration 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.indexOf( statuscode_id ) > -1 ? "current" : statuscode_id > this.status[ 0 ] ? "done" : "" }`}>
<p> { dealSelected }</p>
<span></span>
<div className="status_body">
{ this._renderHeader("Принято положительное решение") }
<div className="wrap" style={{ display: open ? "block" : "none" }}>
<div className="single_text">
<p>Статусный текст о том что выбирается программа финансированияи</p>
</div>
</div>
</div>
</div>
)
}
}
class SigningTypeSelection extends Step
{
constructor(props)
{
super(props);
this.state = {
open: false,
checked: {
prepared_contracts: [],
signing_plan_contracts: [],
signing_fact_contracts: [],
issued_contracts: [],
annulled_contracts: [],
},
};
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",
},
];
}
_render_preparedContracts = () =>
{
const checked = this.state.checked.prepared_contracts;
const contracts = this.props.contracts['prepared_contracts'];
console.log("_render_preparedContracts", { contracts });
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="" checked={ checked.indexOf(contract.name) > -1 ? true : false } onChange={ () => {} }/>
<label htmlFor="">{ 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>
<div className="block_footer_btn">
<button className="button button-blue">Подписать в ЭДО</button>
<button className="button button-blue">Подписать в бумажном виде</button>
</div>
</div>
)
}
_render_signingPlanContracts = () =>
{
const contracts = this.props.contracts['prepared_contracts'];
console.log("_render_signingPlanContracts", { contracts });
return (
<div className="documents">
{ contracts.length > 0 ?
contracts.map((contract, index) => (
<div className="document" key={ index }>
<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>
{ index === 0 && (
<div className="actions">
<button className="button blue">Перейти в ЭДО</button>
</div>
) }
{ index === 1 && (
<div className="actions">
<button className="button blue">Скачать документ</button>
<button className="button blue">Загрузить подписанный экземпляр</button>
</div>
) }
</div>
)) : (
<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) => (
<div className="document" key={ index }>
<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>
<div className="actions wide">
<div className="status">
<div className="status_icon"></div>
<span>{ contract.statuscode_name }</span>
</div>
<button className="button blue">Скачать</button>
</div>
</div>
)) : (
<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">
<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>
</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">
<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>
</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 } = this.state;
return (
<div className={`${ this.status.indexOf( statuscode_id ) > -1 ? "current" : statuscode_id > this.status[ 0 ] ? "done" : "" }`}>
<p> { dealSelected }</p>
<span></span>
<div className="status_body">
{ this._renderHeader("Оформление лизинга") }
<div className="wrap form contracts" style={{ display: open ? "block" : "none" }}>
{ this.types.map((type, index) => (
<div className="block" key={ index }>
<div className="left">
<p><b>{ type.title }</b></p>
</div>
<div className="right">
{ this._render_contracts(type.key) }
</div>
</div>
)) }
</div>
</div>
</div>
)
}
}
export default class SingleDeal extends React.Component
{
constructor(props)
{
super(props);
}
render()
{
const { index, status, deals, dealSelected, onCloseDeal, } = this.props;
console.log({ "deals": deals });
const offers = deals.details[ dealSelected ] !== undefined ? deals.details[ dealSelected ].offers : undefined;
const documents = deals.details[ dealSelected ] !== undefined ? deals.details[ dealSelected ].documents : undefined;
const contracts = deals.details[ dealSelected ] !== undefined ? deals.details[ dealSelected ].contracts : undefined;
return (
<div className="contractStatus_modal">
{/*}
<div className="modal_header">
<p className="modal_title">Статус сделки</p>
<button className="modal_close" onClick={close}></button>
</div>
{*/}
<div className="modal_body single_status">
<Offers { ...this.props } offers={ offers }/>
<FinancialProgram { ...this.props }/>
<DocumentsForm { ...this.props } documents={ documents }/>
<StatusDocumentsCheck { ...this.props }/>
<StatusDecisionMaking { ...this.props }/>
<StatusLeasingRegistration { ...this.props }/>
<SigningTypeSelection { ...this.props } contracts={ contracts }/>
</div>
<div className="bottom_button_close" onClick={ onCloseDeal } >
<span>Свернуть</span>
<div className="icon"></div>
</div>
</div>
)
}
}