digital certificates selection

This commit is contained in:
merelendor 2023-03-27 14:13:12 +03:00
parent 81d5cf6569
commit d38fa550b7
18 changed files with 1912 additions and 584 deletions

View File

@ -9,6 +9,7 @@
"lint": "next lint"
},
"dependencies": {
"@mpth/react-no-ssr": "^1.0.1",
"@nano-sql/core": "^2.3.7",
"async": "^3.2.2",
"axios": "^0.24.0",
@ -39,7 +40,6 @@
"react-dom": "17.0.2",
"react-dropzone": "^14.2.2",
"react-google-recaptcha-v3": "^1.10.0",
"react-no-ssr": "^1.1.0",
"react-redux": "^7.2.6",
"react-select": "^5.7.2",
"react-slick": "^0.29.0",

View File

@ -2,7 +2,7 @@ import React from "react";
import Link from "next/link";
import { connect } from "react-redux";
import { getContractEvents, getContractFines, getContractInfo, } from "../../../../actions";
import NoSSR from 'react-no-ssr';
import NoSSR from '@mpth/react-no-ssr';
class InnerMenu extends React.Component
{
@ -66,7 +66,6 @@ class InnerMenu extends React.Component
{ this.props.router && this._getActiveLink(this.props.router.asPath) }
</button>
<ul className={ menuOpened ? "aside_nav open" : "aside_nav" } ref={ this.menuRef }>
<li>[ { this.props.router.asPath }]</li>
<li>
<Link href={`/questionnaire/#main`} shallow>
<a style={{ fontWeight: 400, }} disabled={ questionnaire.step > 1 ? false : true } className={ this.props.router && this.props.router.asPath.indexOf("#main") > -1 || this.props.router.asPath.indexOf("#") < 0 ? "active" : "" }>1. Информация о лизингополучателе</a>

View File

@ -0,0 +1,169 @@
import React from "react";
import Link from "next/link";
import { getCertificates, isPluginCryptoProInstalled } from "../../../../utils/digital_signature";
import { SpinnerCircular } from "spinners-react";
import moment from "moment";
export default class DigitalSignaturesList extends React.Component
{
constructor(props)
{
super(props);
this.state = {
loading: true,
certificates_error: null,
certificate_selected: undefined,
};
}
componentDidMount()
{
const script = document.createElement("script");
script.src = `${ process.env.NEXT_PUBLIC_SELF_API_HOST }/assets/js/cadesplugin_api.js`;
script.async = true;
document.body.appendChild(script);
setTimeout(() =>
{
isPluginCryptoProInstalled()
.then(
getCertificates()
.then(certificates =>
{
const certificates_list = [];
for(let i in certificates)
{
const certificate = certificates[i];
let today = moment();
if(today < moment(certificate.info.validToDate))
{
certificate.info.validToDate = moment(certificate.info.validToDate).format('DD.MM.YYYY');
certificates_list.push(certificate);
}
}
this.setState({ certificates: certificates_list, certificates_error: certificates_list.length > 0 ? null : "ISSUED", loading: false });
})
.catch((error_get_certificates) =>
{
console.error("error_get_certificates");
console.error(error_get_certificates);
console.log("certificates", 'OTHER');
this.setState({ certificates: [], certificates_error: "OTHER", loading: false });
})
)
.catch((error_plugin_installed) =>
{
console.error("error_plugin_installed");
console.error(error_plugin_installed);
console.log("certificates", 'NOT_INSTALLED');
this.setState({ certificates: [], certificates_error: "NOT_INSTALLED", loading: false })
});
}, 1000);
}
componentDidUpdate(prevProps, prevState)
{
}
_sign = () =>
{
alert("Подписание ЭЦП и отправка данных");
}
render()
{
const { certificates, certificates_error, certificate_selected, loading } = this.state;
console.log(certificates);
if(loading)
{
return (
<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>
);
}
else
{
if(certificates_error === null)
{
return (
<React.Fragment>
<div className="feed">
<p>Выберите подписанта</p>
<div className="feed_list">
{ certificates.map((certificate, index) => (
<div className="form_field checkbox" key={ index }>
<input type="radio"
hidden=""
id={ `certificate_${ certificate.index }` }
name={ `certificate_${ certificate.index }` }
checked={ certificate_selected === certificate.index ? true : false }
onChange={ () => { this.setState({ certificate_selected: certificate.index }) } }
/>
<label htmlFor={ `certificate_${ certificate.index }` }>
<div className="feed_item user">
<img src="/assets/images/icons/avatar.svg" alt="" />
<div>
<p className="item_title">{ certificate?.info?.subjectName }</p>
<p className="item_desc">
<span>Подпись действительна до { certificate?.info?.validToDate }</span>
</p>
</div>
</div>
</label>
</div>
)) }
</div>
</div>
<div className="action">
<div></div>
<button
type="submit"
className="button button-blue"
disabled={ certificate_selected !== undefined ? false : true }
onClick={ this._sign }
>
Подписать выбранной подписью
</button>
</div>
</React.Fragment>
)
}
else
{
return (
<div className="questionnaire message error">
<svg width="44" height="45" viewBox="0 0 44 45" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M40.5425 31.1863L25.7969 8.08116C24.9653 6.77804 23.5459 6 22 6C20.4539 6 19.0345 6.77804 18.2032 8.08116L3.45741 31.1862C2.57234 32.5732 2.51363 34.3313 3.30467 35.7746C4.09572 37.2173 5.60918 38.1137 7.25444 38.1137H36.7456C38.3909 38.1137 39.9044 37.2175 40.6956 35.7742C41.4863 34.3313 41.4276 32.5733 40.5425 31.1863ZM22 34.2245C20.644 34.2245 19.5448 33.1252 19.5448 31.7694C19.5448 30.4133 20.6441 29.3141 22 29.3141C23.356 29.3141 24.4551 30.4133 24.4551 31.7694C24.4551 33.1252 23.3559 34.2245 22 34.2245ZM25.403 17.1635L24.1937 25.3052C24.0157 26.5037 22.8999 27.3309 21.7016 27.1529C20.7334 27.0091 20.0075 26.25 19.8582 25.333L18.5451 17.2074C18.2394 15.3155 19.5251 13.534 21.417 13.2283C23.3089 12.9226 25.0904 14.2083 25.3962 16.1002C25.4536 16.4565 25.4517 16.8243 25.403 17.1635Z" fill="white"/>
</svg>
{ certificates_error === "NOT_INSTALLED" && (
<p><b>Ошибка</b>
Плагин КриптоПРО не установлен, <Link href="https://cryptopro.ru/products/cades/plugin"><a target="_blank" rel="noopener noreferrer" style={{ color: "white", textDecoration: "underline" }}>посмотрите инструкцию</a></Link> как установить плагин КриптоПРО.
</p>
) }
{ certificates_error === "OTHER" && (
<p><b>Ошибка</b>
Плагин КриптоПРО не активирован, пожалуйста, обновите страницу и подтвердите разрешение для сайта на доступ к списку сертификатов.
</p>
) }
{ certificates_error === "ISSUED" && (
<p><b>Ошибка</b>
Отсутствуют действующие сертификаты.
</p>
) }
{ certificates_error === "MISMATCH" && (
<p><b>Ошибка</b>
Подписант не соответствует указанному подписанту в анкете.
</p>
) }
</div>
)
}
}
}
}

View File

@ -3,13 +3,16 @@ import Head from 'next/head';
import Image from 'next/image';
import Link from "next/link";
import cookie from 'cookie';
import { connect } from "react-redux";
import numeral from "numeral";
import pluralize from 'pluralize-ru';
import { SpinnerCircular } from 'spinners-react';
import QuestionnaireForm from "../QuestionnaireForm";
import { connect } from "react-redux";
import { withRouter } from 'next/router';
export default class Form_1_Main extends QuestionnaireForm
import QuestionnaireForm from "../QuestionnaireForm";
import { reduxWrapper } from '../../../../../store';
class Form_1_Main extends QuestionnaireForm
{
constructor(props)
{
@ -43,8 +46,7 @@ export default class Form_1_Main extends QuestionnaireForm
static getDerivedStateFromProps(nextProps, prevState)
{
return {
observer: nextProps.observer,
user: nextProps.user,
main: nextProps.main,
};
}
@ -67,64 +69,14 @@ export default class Form_1_Main extends QuestionnaireForm
return false;
}
_handle_onPhoneSubmit = (event) =>
{
event.preventDefault();
const { user, address, phone_check_loading } = this.state;
if(!phone_check_loading)
{
this.setState({ phone_check_loading: true }, () =>
{
});
}
}
_handle_onFormSubmit = (event) =>
{
event.preventDefault();
console.log("FormMain", "_handle_onFormSubmit");
console.log("Form_1_Main", "_handle_onFormSubmit");
const { address, phone_code, code_check_loading } = this.state;
//if(!code_check_loading)
//{
/*
this.setState({ code_check_loading: true }, () =>
{
});
*/
//}
}
_handle_onAddressChange = (value) =>
{
this.setState({ address: value, }, () =>
{
/*
suggestsAddress("Москва")
.then((suggests) =>
{
console.log({ suggests });
})
.catch(() =>
{
console.log("_handle_onAddressChange", "error");
});
*/
});
//const phone_number_format_error = value.length > 1 && (value[0] !== "+" || value[1] !== "7") ? true : false;
//this.setState({ phone: value, phone_login_disabled: this._check_fields_disabled([ value ]), phone_number_error: false, phone_number_format_error: phone_number_format_error });
}
// _handle_onPhoneCodeChange = (value) =>
// {
// this.setState({ phone_code: value, phone_code_submit_disabled: this._check_fields_disabled([ value ]), phone_sms_code_error: false });
// }
_check_fields_disabled = (values) =>
{
for(let i in values)
@ -270,4 +222,19 @@ export default class Form_1_Main extends QuestionnaireForm
</React.Fragment>
)
}
}
}
function mapStateToProps(state, ownProps)
{
return {
main: state.questionnaire.main,
}
}
export const getServerSideProps = reduxWrapper.getServerSideProps(store =>
async ({ req, res, query }) =>
{
}
);
export default connect(mapStateToProps)(Form_1_Main);

View File

@ -3,15 +3,18 @@ import Head from 'next/head';
import Image from 'next/image';
import Link from "next/link";
import cookie from 'cookie';
import { connect } from "react-redux";
import numeral from "numeral";
import pluralize from 'pluralize-ru';
import Select from 'react-select'
import { SpinnerCircular } from 'spinners-react';
import { connect } from "react-redux";
import { withRouter } from 'next/router';
import QuestionnaireForm from "../QuestionnaireForm";
import AddressSuggestsSelect from "../AddressSuggestsSelect";
import { reduxWrapper } from '../../../../../store';
export default class Form_2_Contacts extends QuestionnaireForm
class Form_2_Contacts extends QuestionnaireForm
{
constructor(props)
{
@ -52,14 +55,7 @@ export default class Form_2_Contacts extends QuestionnaireForm
_handle_onFormSubmit = (event) =>
{
event.preventDefault();
console.log("FormAddress", "_handle_onFormSubmit");
}
_handle_onAddressChange = (value) =>
{
this.setState({ address: value, }, () =>
{
});
console.log("Form_2_Contacts", "_handle_onFormSubmit");
}
_check_fields_disabled = (values) =>
@ -77,13 +73,7 @@ export default class Form_2_Contacts extends QuestionnaireForm
render()
{
const { address_type, fact_address, postal_address, phone_check_loading, phone_number_format_error } = this.state;
const options = [
{ value: 'Москва', label: 'Москва' },
{ value: 'Казань', label: 'Казань' },
{ value: 'Воронеж', label: 'Воронеж' }
]
const { address_type, fact_address, postal_address, phone_check_loading, } = this.state;
return (
<React.Fragment>
@ -92,28 +82,11 @@ export default class Form_2_Contacts extends QuestionnaireForm
<div className="form_field">
<label>Фактический адрес</label>
{/*
<input type="text" name="fact_address" value={ fact_address } placeholder="Введите адрес" onChange={ (event) => this._handle_onTextFieldChange(event.target.name, event.target.value) } required={ true }/>
*/}
{/*
<input type="text" name="address" value={ address } placeholder="Введите адрес" onChange={ (event) => this._handle_onAddressChange(event.target.value) } required={ true }/>
*/}
<AddressSuggestsSelect
value={ fact_address.title }
fias={ fact_address.fias_id }
onChange={ (data) => this._handle_onTextFieldChange("fact_address", data) }
/>
{/*}
<Select
options={ options }
placeholder="Фактический адрес"
noOptionsMessage={ ({inputValue}) => !inputValue ? noOptionsText :"Ничего не найдено" }
isSearchable={ true }
className="autocomlete"
classNamePrefix="react-select"
//menuIsOpen={ true }
/>
{*/}
<p>для юр.диц - заполняется, если отличается от указанного в ЕГРЮЛ; для ИП - заполняется всегда</p>
</div>
@ -159,9 +132,6 @@ export default class Form_2_Contacts extends QuestionnaireForm
onChange={ (data) => this._handle_onTextFieldChange("postal_address", data) }
disabled={ address_type === "postal" ? false : true }
/>
{/*}
<input type="text" name="postal_address" value={ postal_address } placeholder="Введите адрес" onChange={ (event) => this._handle_onTextFieldChange(event.target.name, event.target.value) } disabled={ address_type === "postal" ? false : true } required={ true }/>
{*/}
</label>
</div>
</div>
@ -178,4 +148,21 @@ export default class Form_2_Contacts extends QuestionnaireForm
</React.Fragment>
)
}
}
}
function mapStateToProps(state, ownProps)
{
return {
fact_address: state.questionnaire.fact_address,
legal_address: state.questionnaire.legal_address,
postal_address: state.questionnaire.postal_address,
}
}
export const getServerSideProps = reduxWrapper.getServerSideProps(store =>
async ({ req, res, query }) =>
{
}
);
export default connect(mapStateToProps)(Form_2_Contacts);

View File

@ -3,21 +3,23 @@ import Head from 'next/head';
import Image from 'next/image';
import Link from "next/link";
import cookie from 'cookie';
import { connect } from "react-redux";
import numeral from "numeral";
import pluralize from 'pluralize-ru';
import { SpinnerCircular } from 'spinners-react';
import Select from 'react-select';
import { connect } from "react-redux";
import { withRouter } from 'next/router';
import DateInput from '../../../../components/DatePicker';
import QuestionnaireForm from "../QuestionnaireForm";
import DateInput from '../../../../components/DatePicker';
import FilesList from "../FilesList";
import Modal from "../../../../components/Modal/modal";
import AddressSuggestsSelect from "../AddressSuggestsSelect";
import countries from "../countries";
import citizenships from "../citizenships";
import AddressSuggestsSelect from "../AddressSuggestsSelect";
import { reduxWrapper } from '../../../../../store';
export default class Form_3_Signer extends QuestionnaireForm
class Form_3_Signer extends QuestionnaireForm
{
constructor(props)
{
@ -108,26 +110,20 @@ export default class Form_3_Signer extends QuestionnaireForm
signatory_person_files: [],
personal_data_consent: false,
address: "",
phone_check_loading: false,
phone_number_format_error: false,
date_to: "",
evo_assignment_date: "",
evo_credentials_dateend: "",
evo_indefinite: false,
loading: false,
modal_show_personal_data: false,
head_person_registration_address_values: [],
signatory_person_address_values: [],
};
}
static getDerivedStateFromProps(nextProps, prevState)
{
return {
observer: nextProps.observer,
user: nextProps.user,
main: nextProps.main,
head_person: nextProps.head_person,
head_person_files: nextProps.head_person_files,
individual_executive_files: nextProps.individual_executive_files,
signatory_person: nextProps.signatory_person,
signatory_person_files: nextProps.signatory_person_files,
};
}
@ -138,14 +134,7 @@ export default class Form_3_Signer extends QuestionnaireForm
_handle_onFormSubmit = (event) =>
{
event.preventDefault();
console.log("FormAddress", "_handle_onFormSubmit");
}
_handle_onAddressChange = (value) =>
{
this.setState({ address: value, }, () =>
{
});
console.log("Form_3_Signer", "_handle_onFormSubmit");
}
_check_fields_disabled = (values) =>
@ -164,24 +153,15 @@ export default class Form_3_Signer extends QuestionnaireForm
render()
{
const {
//not_head_person,
//delegation_agreement,
personal_data_consent,
//evo_assignment_date,
//evo_credentials_dateend,
evo_indefinite,
head_person_files,
signatory_person_files,
individual_executive_files,
modal_show_personal_data,
} = this.state;
const { address, phone_check_loading, phone_number_format_error } = this.state;
const { loading, } = this.state;
const { main, head_person, signatory_person } = this.state;
const {
not_head_person,
delegation_agreement,
} = signatory_person;
return (
<React.Fragment>
@ -311,26 +291,6 @@ export default class Form_3_Signer extends QuestionnaireForm
fias={ head_person.identity_document.registration_address.fias_id }
onChange={ (data) => this._handle_onTextFieldChange("head_person.identity_document.registration_address", data) }
/>
{/*}
<AsyncSelect
placeholder="Укажите адрес"
className="autocomlete"
classNamePrefix="react-select"
cacheOptions={ this.state }
defaultOptions
loadOptions={ (text) => this._getAddress("head_person_registration_address_values", text) }
/>
*/}
{/*}
<input type="text"
id="head_person.identity_document.registration_address.title"
name="head_person.identity_document.registration_address.title"
value={ head_person.identity_document.registration_address.title }
placeholder="Введите адрес"
onChange={ (event) => this._handle_onTextFieldChange(event.target.name, event.target.value) }
required={ true }
/>
{*/}
</div>
<div className="form_field">
<label>Должность</label>
@ -343,12 +303,6 @@ export default class Form_3_Signer extends QuestionnaireForm
required={ true }
/>
</div>
{/*}
<div className="form_field">
<label>Кем выдан</label>
<input type="text" id="head_person." name="head_person." value={ head_person. } placeholder="Введите наименование подразделения выдавшего документ" onChange={ (event) => this._handle_onAddressChange(event.target.value) } required={ true }/>
</div>
*/}
<div className="form_field picker">
<label>Дата назначения</label>
<div style={{ display: "flex", flexWrap: "wrap", width: "calc(100% - 198px)" }}>
@ -361,15 +315,15 @@ export default class Form_3_Signer extends QuestionnaireForm
<div className="form_field checkbox" style={{width: "auto", marginLeft: "28px"}}>
<input type="checkbox"
hidden=""
id="evo_indefinite"
name="evo_indefinite"
onChange={ (event) => this._handle_onCheckboxFieldChange(event.target.name, !evo_indefinite ? true : false) }
id="head_person.evo_indefinite"
name="head_person.evo_indefinite"
onChange={ (event) => this._handle_onCheckboxFieldChange(event.target.name, !head_person.evo_indefinite ? true : false) }
/>
<label htmlFor="evo_indefinite" className="unselectable">Полномочия бессрочны</label>
<label htmlFor="head_person.evo_indefinite" className="unselectable">Полномочия бессрочны</label>
</div>
</div>
</div>
{ !evo_indefinite && (
{ !head_person.evo_indefinite && (
<div className="form_field picker">
<label>Дата окончания полномочий</label>
<div style={{ display: "flex", flexWrap: "wrap", width: "calc(100% - 198px)" }}>
@ -396,13 +350,13 @@ export default class Form_3_Signer extends QuestionnaireForm
hidden=""
id="signatory_person.not_head_person"
name="signatory_person.not_head_person"
onChange={ (event) => this._handle_onCheckboxFieldChange(event.target.name, !not_head_person ? true : false) }
onChange={ (event) => this._handle_onCheckboxFieldChange(event.target.name, !signatory_person.not_head_person ? true : false) }
/>
<label htmlFor="signatory_person.not_head_person" className="unselectable">Полномочия единоличного исполнительного органа переданы управляющей организации или управляющему</label>
</div>
</div>
{ not_head_person && (
{ signatory_person.not_head_person && (
<React.Fragment>
<p className="title">Информация об управляющей организации или управляющем</p>
<p>Организационно-правовая форма и полное наименование управляющей организации или управляющего</p>
@ -498,13 +452,13 @@ export default class Form_3_Signer extends QuestionnaireForm
hidden=""
id="signatory_person.delegation_agreement"
name="signatory_person.delegation_agreement"
onChange={ (event) => this._handle_onCheckboxFieldChange(event.target.name, !delegation_agreement ? true : false) }
onChange={ (event) => this._handle_onCheckboxFieldChange(event.target.name, !signatory_person.delegation_agreement ? true : false) }
/>
<label htmlFor="signatory_person.delegation_agreement" className="unselectable">Подписант отличается от единоличного исполнительного органа</label>
</div>
</div>
{ delegation_agreement && (
{ signatory_person.delegation_agreement && (
<React.Fragment>
<p className="title">Информация о подписанте <small>(заполняется если подписант договора лизинга отличается от единоличного исполнительного органа)</small></p>
@ -776,7 +730,7 @@ export default class Form_3_Signer extends QuestionnaireForm
</div>
<div className="action">
<button type="submit" className="button button-blue" disabled={ false }>
{ phone_check_loading ? (
{ 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>
@ -795,4 +749,24 @@ export default class Form_3_Signer extends QuestionnaireForm
</React.Fragment>
)
}
}
}
function mapStateToProps(state, ownProps)
{
return {
main: state.questionnaire.main,
head_person: state.questionnaire.head_person,
head_person_files: state.questionnaire.head_person_files,
individual_executive_files: state.questionnaire.individual_executive_files,
signatory_person: state.questionnaire.signatory_person,
signatory_person_files: state.questionnaire.signatory_person_files,
}
}
export const getServerSideProps = reduxWrapper.getServerSideProps(store =>
async ({ req, res, query }) =>
{
}
);
export default connect(mapStateToProps)(Form_3_Signer);

View File

@ -10,11 +10,11 @@ import Select from 'react-select';
import { connect } from "react-redux";
import { withRouter } from 'next/router';
import { reduxWrapper } from '../../../../../store';
import DateInput from '../../../../components/DatePicker';
import QuestionnaireForm from "../QuestionnaireForm";
import DateInput from '../../../../components/DatePicker';
import citizenships from "../citizenships";
import AddressSuggestsSelect from "../AddressSuggestsSelect";
import { reduxWrapper } from '../../../../../store';
class ShareholderForm extends React.Component
{
@ -24,7 +24,6 @@ class ShareholderForm extends React.Component
render()
{
const { index, shareholder } = this.props;
console.log({ index, shareholder });
let citizenship = undefined;
if(shareholder.identity_document.citizenship_code !== "")
@ -196,9 +195,24 @@ class Shareholder extends React.Component
_handle_onTextFieldChange = this.props._handle_onTextFieldChange;
_handle_onCheckboxFieldChange = this.props._handle_onCheckboxFieldChange;
_checkSignatoryDisabled = (signatory_id) =>
{
const { shareholders } = this.props;
for(let i in shareholders)
{
if(shareholders[i].signatory_id === signatory_id)
{
return true;
}
}
return false;
}
render()
{
const { index, shareholder, removeShareholder, } = this.props;
const { index, shareholders, removeShareholder, signatories, changeSignatorySelection, clearSignatorySelection, } = this.props;
const shareholder = shareholders[index];
return (
<React.Fragment>
@ -214,7 +228,7 @@ class Shareholder extends React.Component
checked={ shareholder.founder_from_list }
id={ `founded_persons[${ index }].founder_from_list` }
name={ `founded_persons[${ index }].founder_from_list` }
onChange={ (event) => this._handle_onCheckboxFieldChange(event.target.name, !shareholder.founder_from_list ? true : false) }
onChange={ (event) => clearSignatorySelection(`founded_persons[${ index }]`, { founder_from_list: !shareholder.founder_from_list ? true : false, lastname: "", firstname: "", middlename: "", no_middle_name: false, }) }
/>
<label className="unselectable" htmlFor={ `founded_persons[${ index }].founder_from_list` }>Выбрать из списка</label>
</div>
@ -238,53 +252,38 @@ class Shareholder extends React.Component
{ shareholder.founder_from_list ? (
<div className="feed">
<div className="feed_list">
<div className="form_field checkbox">
<input type="radio" hidden="" id="" name="" />
<label htmlFor="">
<div className="feed_item user">
<img src="/assets/images/icons/avatar.svg" alt="" />
<div>
<p className="item_title">Басок Дмитрий Вадимович</p>
<p className="item_desc">
<span>ИНН 1234567890</span>
<span>Подпись действительна до 01.10.2023</span>
</p>
</div>
</div>
</label>
</div>
<div className="form_field checkbox">
<input type="radio" hidden="" id="" name="" />
<label htmlFor="">
<div className="feed_item user">
<img src="/assets/images/icons/avatar.svg" alt="" />
<div>
<p className="item_title">Басок Дмитрий Вадимович</p>
<p className="item_desc">
<span>ИНН 1234567890</span>
<span>Подпись действительна до 01.10.2023</span>
</p>
{ signatories.map((signatory, s_index) => {
const disabled = signatory.signatoryid !== shareholder.signatory_id ? this._checkSignatoryDisabled(signatory.signatoryid) : false;
return (
<div className="form_field checkbox" key={ s_index }>
<input type="radio" hidden=""
id={ `founded_persons[${ index }].signatory_${ signatory.signatoryid }` }
name={ `founded_persons[${ index }].signatory_${ signatory.signatoryid }` }
checked={ signatory.signatoryid === shareholder.signatory_id }
onChange={ () => changeSignatorySelection(`founded_persons[${ index }]`, { ...shareholder, ...{
founder_from_list: true,
signatory_id: signatory.signatoryid,
lastname: signatory.lastname,
firstname: signatory.firstname,
middlename: signatory.middlename,
} }) }
disabled={ disabled }
/>
<label className="unselectable" style={ disabled ? { opacity: "0.5" } : {} } htmlFor={ `founded_persons[${ index }].signatory_${ signatory.signatoryid }` }>
<div className="feed_item user">
<img src="/assets/images/icons/avatar.svg" alt="" />
<div>
<p className="item_title">{ signatory.lastname } { signatory.firstname } { signatory.middlename }</p>
<p className="item_desc">
<span>{ signatory.jobtitle }</span>
</p>
</div>
</div>
</label>
</div>
</label>
</div>
<div className="form_field checkbox">
<input type="radio" hidden="" id="" name="" />
<label htmlFor="">
<div className="feed_item user">
<img src="/assets/images/icons/avatar.svg" alt="" />
<div>
<p className="item_title">Басок Дмитрий Вадимович</p>
<p className="item_desc">
<span>ИНН 1234567890</span>
<span>Подпись действительна до 01.10.2023</span>
</p>
</div>
</div>
</label>
</div>
);
}) }
</div>
</div>
) : (
@ -318,7 +317,7 @@ class Shareholder extends React.Component
checked={ shareholder.is_beneficial ? false : true }
onChange={ (event) => this._handle_onCheckboxFieldChange(event.target.name, parseInt(event.target.value, 10)) }
/>
<label htmlFor={ `founded_persons[${ index }].is_beneficial_1` }>Да</label>
<label className="unselectable" htmlFor={ `founded_persons[${ index }].is_beneficial_1` }>Да</label>
</div>
<div className="form_field checkbox">
<input type="radio" hidden=""
@ -328,7 +327,7 @@ class Shareholder extends React.Component
checked={ shareholder.is_beneficial ? false : true }
onChange={ (event) => this._handle_onCheckboxFieldChange(event.target.name, parseInt(event.target.value, 10)) }
/>
<label htmlFor={ `founded_persons[${ index }].is_beneficial_0` }>Нет</label>
<label className="unselectable" htmlFor={ `founded_persons[${ index }].is_beneficial_0` }>Нет</label>
</div>
</div>
</div>
@ -345,12 +344,9 @@ class Form_4_Shareholders extends QuestionnaireForm
{
super(props);
this.state = {
address: "",
phone_check_loading: false,
phone_number_format_error: false,
founded_persons: [],
founded_persons_template: {},
loading: false,
};
}
@ -381,10 +377,7 @@ class Form_4_Shareholders extends QuestionnaireForm
if(founded_persons.length < 4)
{
console.log("TEMPLATE", founded_persons_template);
console.log("founded_persons BEFORE PUSH", founded_persons);
founded_persons.push({ ...founded_persons_template });
console.log("founded_persons AFTER PUSH", founded_persons);
this._updateQuestionnaire({
founded_persons,
@ -394,22 +387,29 @@ class Form_4_Shareholders extends QuestionnaireForm
_handle_onRemoveShareholder = (index) =>
{
console.log("_handle_onRemoveShareholder", index);
const founded_persons = [ ...this.state.founded_persons ];
console.log("founded_persons", founded_persons);
founded_persons.splice(index, 1);
console.log("founded_persons AFTER SPLICE", founded_persons);
this._updateQuestionnaire({
founded_persons,
});
}
_handle_onClearSignatorySelection = (name, values) =>
{
this._handle_onFieldChange(name, { ...this.state.founded_persons_template , ...values } );
}
_handle_onChangeSignatorySelection = (name, values) =>
{
this._handle_onFieldChange(name, { ...values } );
}
_handle_onFormSubmit = (event) =>
{
event.preventDefault();
console.log("Form_4_Shareholders", "_handle_onFormSubmit");
}
_check_fields_disabled = (values) =>
@ -427,41 +427,44 @@ class Form_4_Shareholders extends QuestionnaireForm
render()
{
const { founded_persons, phone_check_loading, address, phone_number_format_error } = this.state;
const { signatories } = this.props;
const { founded_persons, loading, address, } = this.state;
return (
<React.Fragment>
<form onSubmit={ this._handle_onFormSubmit } className="questionnaire questionnaire_4">
<p className="title">4. Сведения об участниках (акционерах) и бенефициарных владельцах</p>
<p> физических лицах, владеющих долей в уставном капитале более 25%
<small>*бенефициарный владелец (в соответствии с Федеральным законом от 07.08.2001 No115-ФЗ «О противодействии легализации (отмыванию) доходов, полученных преступным путем, и финансированию терроризма»)
<form onSubmit={ this._handle_onFormSubmit } className="questionnaire questionnaire_4">
<p className="title">4. Сведения об участниках (акционерах) и бенефициарных владельцах</p>
<p> физических лицах, владеющих долей в уставном капитале более 25%
<small>*бенефициарный владелец (в соответствии с Федеральным законом от 07.08.2001 No115-ФЗ «О противодействии легализации (отмыванию) доходов, полученных преступным путем, и финансированию терроризма»)
физическое лицо, которое в конечном счете прямо или косвенно (через третьих лиц) владеет (имеет преобладающее участие более 25 процентов в капитале) вышеуказанным лизингополучателем-юридическим лицом, либо
имеет возможность контролировать действия вышеуказанного лизингополучателя. Бенефициарным владельцем лизингополучателя-физического лица считается это лицо, за исключением случаев, если имеются основания
полагать, что бенефициарным владельцем является иное физическое лицо. В случае, если бенефициарным владельцем являются несколько человек, сведения предоставляются в отношении каждого.</small>
</p>
</p>
{ founded_persons.map((shareholder, index) => (
<Shareholder
key={ index }
index={ index }
shareholder={ shareholder }
address={ address }
_handle_onTextFieldChange={ this._handle_onTextFieldChange }
_handle_onCheckboxFieldChange={ this._handle_onCheckboxFieldChange }
removeShareholder={ this._handle_onRemoveShareholder }
/>
)) }
{ founded_persons.map((shareholder, index) => (
<Shareholder
key={ index }
index={ index }
shareholders={ founded_persons }
address={ address }
_handle_onTextFieldChange={ this._handle_onTextFieldChange }
_handle_onCheckboxFieldChange={ this._handle_onCheckboxFieldChange }
selectSignatory={ this._handle_onSelectSignatory }
removeShareholder={ this._handle_onRemoveShareholder }
clearSignatorySelection={ this._handle_onClearSignatorySelection }
changeSignatorySelection={ this._handle_onChangeSignatorySelection }
signatories={ signatories }
/>
)) }
<div className="action">
<button className="button button-blue" disabled={ false } onClick={ (event) => { event.preventDefault(); this._handle_onAddShareholder(); }}>Добавить еще одного владельца</button>
<button type="submit" className="button button-blue" disabled={ false }>
{ phone_check_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>
</React.Fragment>
<div className="action">
<button className="button button-blue" disabled={ false } onClick={ (event) => { event.preventDefault(); this._handle_onAddShareholder(); }}>Добавить еще одного владельца</button>
<button type="submit" className="button button-blue" disabled={ false }>
{ 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>
)
}
}

View File

@ -3,12 +3,16 @@ import Head from 'next/head';
import Image from 'next/image';
import Link from "next/link";
import cookie from 'cookie';
import { connect } from "react-redux";
import numeral from "numeral";
import pluralize from 'pluralize-ru';
import { SpinnerCircular } from 'spinners-react';
import { connect } from "react-redux";
import { withRouter } from 'next/router';
export default class Form_5_Regulatory extends React.Component
import QuestionnaireForm from "../QuestionnaireForm";
import { reduxWrapper } from '../../../../../store';
class Form_5_Regulatory extends QuestionnaireForm
{
constructor(props)
{
@ -17,14 +21,37 @@ export default class Form_5_Regulatory extends React.Component
address: "",
phone_check_loading: false,
phone_number_format_error: false,
main: {
title: "",
inn: "",
kpp: "",
email: "",
telephone: "",
websiteurl: "",
financial_loan: "",
is_individual_executive: false,
individual_executive_inn: "",
individual_executive_kpp: "",
individual_executive_oop: "",
individual_executive_docnum: "",
individual_executive_docdate: "",
high_level: "",
board_of_directors: "",
collective_executive: "",
individual_executive: "",
other_control: "",
nko: false,
accept: false,
},
loading: false,
};
}
static getDerivedStateFromProps(nextProps, prevState)
{
return {
observer: nextProps.observer,
user: nextProps.user,
main: nextProps.main,
};
}
@ -35,14 +62,7 @@ export default class Form_5_Regulatory extends React.Component
_handle_onFormSubmit = (event) =>
{
event.preventDefault();
console.log("FormAddress", "_handle_onFormSubmit");
}
_handle_onAddressChange = (value) =>
{
this.setState({ address: value, }, () =>
{
});
console.log("Form_5_Regulatory", "_handle_onFormSubmit");
}
_check_fields_disabled = (values) =>
@ -60,7 +80,7 @@ export default class Form_5_Regulatory extends React.Component
render()
{
const { address, phone_check_loading, phone_number_format_error } = this.state;
const { main, loading } = this.state;
return (
<React.Fragment>
@ -81,7 +101,14 @@ export default class Form_5_Regulatory extends React.Component
Высший орган управления
<small>например, общее собрание акционеров, общее собрание участников, общее собрание членов, общее собрание трудового коллектива, съезд, совет и т.д.</small>
</label>
<textarea type="text" name="address" value={ address } placeholder="Введите фамилию" onChange={ (event) => this._handle_onAddressChange(event.target.value) } required={ true }></textarea>
<textarea type="text"
id={ "main.high_level" }
name={ "main.high_level" }
value={ main.high_level }
placeholder="Введите наименование органа управления"
onChange={ (event) => this._handle_onTextFieldChange(event.target.name, event.target.value) }
required={ true }
/>
</div>
<div className="form_field">
@ -89,7 +116,14 @@ export default class Form_5_Regulatory extends React.Component
Совет директоров
<small>например, Правление, Дирекция</small>
</label>
<input type="text" name="address" value={ address } placeholder="Введите имя" onChange={ (event) => this._handle_onAddressChange(event.target.value) } required={ true }/>
<input type="text"
id={ "main.board_of_directors" }
name={ "main.board_of_directors" }
value={ main.board_of_directors }
placeholder="Введите наименование"
onChange={ (event) => this._handle_onTextFieldChange(event.target.name, event.target.value) }
required={ true }
/>
</div>
<div className="form_field">
@ -97,7 +131,14 @@ export default class Form_5_Regulatory extends React.Component
Коллегиальный исполнительный орган
<small>индекс, страна, область (республика, край), населенный пункт, улица, дом, корпус, квартира</small>
</label>
<textarea type="text" name="address" value={ address } placeholder="Введите отчество" onChange={ (event) => this._handle_onAddressChange(event.target.value) } required={ true }></textarea>
<textarea type="text"
id={ "main.collective_executive" }
name={ "main.collective_executive" }
value={ main.collective_executive }
placeholder="Введите адрес"
onChange={ (event) => this._handle_onTextFieldChange(event.target.name, event.target.value) }
required={ true }
/>
</div>
<div className="form_field">
@ -105,33 +146,55 @@ export default class Form_5_Regulatory extends React.Component
Единоличный исполнительный орган
<small>например, Генеральный директор, Директор, Президент. Обязательно для заполнения</small>
</label>
<textarea type="text" name="address" value={ address } placeholder="Введите наименование подразделения выдавшего документ" onChange={ (event) => this._handle_onAddressChange(event.target.value) } required={ true }></textarea>
<textarea type="text"
id={ "main.individual_executive" }
name={ "main.individual_executive" }
value={ main.individual_executive }
placeholder="Введите наименование должности"
onChange={ (event) => this._handle_onTextFieldChange(event.target.name, event.target.value) }
required={ true }
/>
</div>
<div className="form_field">
<label>Иной орган управления</label>
<input type="text" name="address" value={ address } placeholder="Введите данные" onChange={ (event) => this._handle_onAddressChange(event.target.value) } required={ true }/>
<input type="text"
id={ "main.other_control" }
name={ "main.other_control" }
value={ main.other_control }
placeholder="Введите наименование"
onChange={ (event) => this._handle_onTextFieldChange(event.target.name, event.target.value) }
/>
</div>
<p><b>Настоящим я, нижеподписавшийся, заявляю, что перечисленные в анкете представители лизингополучателя не являются:</b></p>
<div className="form_field">
<input type="checkbox" hidden=""
id={ "main.accept" }
name={ "main.accept" }
checked={ main.accept }
onChange={ (event) => this._handle_onCheckboxFieldChange(event.target.name, !main.accept ? true : false) }
required={ true }
/>
<label className="unselectable" htmlFor={ "main.accept" } style={{ width: "100%" }}>Настоящим я заявляю, что перечисленные в анкете представители лизингополучателя не являются:</label>
</div>
<ul>
<li>иностранным публичным должностным лицом (ИПДЛ) или родственниками ИПДЛ (супруг, близкий родственник
(родственник по прямой восходящей и нисходящей линии (родитель и ребенок, дедушка, бабушка и внук), полнородный и неполнородный (имеющий общих отца или мать) брат и сестра, усыновитель и усыновленный);</li>
<li>должностным лицом публичных международных организаций;</li>
<li>публичным должностным лицом Российской Федерации.</li>
<li style={{ lineHeight: "18px" }}>иностранным публичным должностным лицом (ИПДЛ) или родственниками ИПДЛ (супруг, близкий родственник
(родственник по прямой восходящей и нисходящей линии (родитель и ребенок, дедушка, бабушка и внук), полнородный и неполнородный (имеющий общих отца или мать) брат и сестра, усыновитель и усыновленный);</li>
<li style={{ lineHeight: "18px" }}>должностным лицом публичных международных организаций;</li>
<li style={{ lineHeight: "18px" }}>публичным должностным лицом Российской Федерации.</li>
</ul>
<ul>
<li>Сведения о целях установления отношений заключение договора лизинга.</li>
<li>Сведения о целях финансово-хозяйственной деятельности получение прибыли (кроме НКО).</li>
<li>Сведения о характере деловых отношений длящиеся.</li>
<li>Сведения об источниках происхождения денежных средств приносящая доход деятельность (кроме НКО и физ.лиц).</li>
<li style={{ lineHeight: "18px" }}>Сведения о целях установления отношений заключение договора лизинга.</li>
<li style={{ lineHeight: "18px" }}>Сведения о целях финансово-хозяйственной деятельности получение прибыли (кроме НКО).</li>
<li style={{ lineHeight: "18px" }}>Сведения о характере деловых отношений длящиеся.</li>
<li style={{ lineHeight: "18px" }}>Сведения об источниках происхождения денежных средств приносящая доход деятельность (кроме НКО и физ.лиц).</li>
</ul>
<div className="action">
<div></div>
<button type="submit" className="button button-blue" disabled={ false }>
{ phone_check_loading ? (
{ 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>
@ -140,4 +203,19 @@ export default class Form_5_Regulatory extends React.Component
</React.Fragment>
)
}
}
}
function mapStateToProps(state, ownProps)
{
return {
main: state.questionnaire.main,
}
}
export const getServerSideProps = reduxWrapper.getServerSideProps(store =>
async ({ req, res, query }) =>
{
}
);
export default connect(mapStateToProps)(Form_5_Regulatory);

View File

@ -3,38 +3,40 @@ import Head from 'next/head';
import Image from 'next/image';
import Link from "next/link";
import cookie from 'cookie';
import { connect } from "react-redux";
import numeral from "numeral";
import pluralize from 'pluralize-ru';
import { SpinnerCircular } from 'spinners-react';
import QuestionnaireForm from "../QuestionnaireForm";
import { connect } from "react-redux";
import { withRouter } from 'next/router';
export default class Form_6_NonProfit extends QuestionnaireForm
import QuestionnaireForm from "../QuestionnaireForm";
import { reduxWrapper } from '../../../../../store';
class Form_6_NonProfit extends QuestionnaireForm
{
constructor(props)
{
super(props);
this.state = {
fin_source_business: false,
fin_source_donate: false,
fin_source_fees: false,
fin_source_another: false,
fin_source_another_description: "",
foreign_payers: false,
fin_goals_cars: "",
fin_goals_trucks: "",
fin_goals_special: "",
address: "",
phone_check_loading: false,
phone_number_format_error: false,
non_profit: {
fin_source_business: false,
fin_source_donate: false,
fin_source_fees: false,
fin_source_another: false,
fin_source_another_description: "",
foreign_payers: false,
fin_goals_cars: "",
fin_goals_trucks: "",
fin_goals_special: "",
},
loading: false,
};
}
static getDerivedStateFromProps(nextProps, prevState)
{
return {
observer: nextProps.observer,
user: nextProps.user,
non_profit: nextProps.non_profit,
};
}
@ -45,14 +47,7 @@ export default class Form_6_NonProfit extends QuestionnaireForm
_handle_onFormSubmit = (event) =>
{
event.preventDefault();
console.log("FormAddress", "_handle_onFormSubmit");
}
_handle_onAddressChange = (value) =>
{
this.setState({ address: value, }, () =>
{
});
console.log("Form_6_NonProfit", "_handle_onFormSubmit");
}
_check_fields_disabled = (values) =>
@ -70,52 +65,91 @@ export default class Form_6_NonProfit extends QuestionnaireForm
render()
{
const { fin_source_business, fin_source_donate, fin_source_fees, fin_source_another, fin_source_another_description, foreign_payers,
fin_goals_cars, fin_goals_trucks, fin_goals_special } = this.state;
const { address, phone_check_loading, phone_number_format_error } = this.state;
const { non_profit, loading } = this.state;
return (
<React.Fragment>
<form onSubmit={ this._handle_onFormSubmit } className="questionnaire questionnaire_6">
<p className="title">6. Данные о некомерческой организации</p>
<p>Источники происхождения денежных средств, из которых будут осуществляться лизинговые платежи:</p>
<div className="form_field">
<div style={{ width: "100%" }}>
<div className="form_field checkbox">
<input type="checkbox" hidden="" id="fin_source_business" name="fin_source_business" checked={ fin_source_business } onChange={ (event) => this._handle_onCheckboxFieldChange(event.target.name, !fin_source_business ? true : false) }/>
<label htmlFor="fin_source_business">От приносящей доход деятельности</label>
<input type="checkbox" hidden=""
id="non_profit.fin_source_business"
name="non_profit.fin_source_business"
checked={ non_profit.fin_source_business }
onChange={ (event) => this._handle_onCheckboxFieldChange(event.target.name, !non_profit.fin_source_business ? true : false) }
/>
<label htmlFor="non_profit.fin_source_business" className="unselectable">От приносящей доход деятельности</label>
</div>
<div className="form_field checkbox">
<input type="checkbox" hidden="" id="fin_source_donate" name="fin_source_donate" checked={ fin_source_donate } onChange={ (event) => this._handle_onCheckboxFieldChange(event.target.name, !fin_source_donate ? true : false) }/>
<label htmlFor="fin_source_donate">Добровольные пожертвования</label>
<input type="checkbox" hidden=""
id="non_profit.fin_source_donate"
name="non_profit.fin_source_donate"
checked={ non_profit.fin_source_donate }
onChange={ (event) => this._handle_onCheckboxFieldChange(event.target.name, !non_profit.fin_source_donate ? true : false) }
/>
<label htmlFor="non_profit.fin_source_donate" className="unselectable">Добровольные пожертвования</label>
</div>
<div className="form_field checkbox">
<input type="checkbox" hidden="" id="fin_source_fees" name="fin_source_fees" checked={ fin_source_fees } onChange={ (event) => this._handle_onCheckboxFieldChange(event.target.name, !fin_source_fees ? true : false ) }/>
<label htmlFor="fin_source_fees">Вступительные членские взносы</label>
<input type="checkbox" hidden=""
id="non_profit.fin_source_fees"
name="non_profit.fin_source_fees"
checked={ non_profit.fin_source_fees }
onChange={ (event) => this._handle_onCheckboxFieldChange(event.target.name, !non_profit.fin_source_fees ? true : false ) }
/>
<label htmlFor="non_profit.fin_source_fees" className="unselectable">Вступительные членские взносы</label>
</div>
<div className="form_field checkbox">
<input type="checkbox" hidden="" id="fin_source_another" name="fin_source_another" checked={ fin_source_another } onChange={ (event) => this._handle_onCheckboxFieldChange(event.target.name, !fin_source_another ? true : false ) }/>
<label htmlFor="fin_source_another" style={{ width: "100%" }}>
<input type="checkbox" hidden=""
id="non_profit.fin_source_another"
name="non_profit.fin_source_another"
checked={ non_profit.fin_source_another }
onChange={ (event) => this._handle_onCheckboxFieldChange(event.target.name, !non_profit.fin_source_another ? true : false ) }
/>
<label htmlFor="non_profit.fin_source_another" style={{ width: "100%" }} className="unselectable">
<span>Иное</span>
<input type="text" name="fin_source_another_description" value={ fin_source_another_description } disabled={ fin_source_another ? false : true } placeholder="Введите адрес электронной почты" onChange={ (event) => this._handle_onTextFieldChange(event.target.name, event.target.value) } required={ true }/>
<input type="text"
id="non_profit.fin_source_another_description"
name="non_profit.fin_source_another_description"
value={ non_profit.fin_source_another_description }
disabled={ non_profit.fin_source_another ? false : true }
placeholder="Введите адрес электронной почты"
onChange={ (event) => this._handle_onTextFieldChange(event.target.name, event.target.value) }
/>
</label>
</div>
</div>
</div>
<p>Организация является получателем денежных средств и имущества от иностранных государств, международных и иностранных организаций, иностранных граждан и лиц без гражданства:</p>
<div className="form_field">
<div style={{ width: "100%" }}>
<div className="form_field checkbox">
<input type="radio" value="0" hidden="" id="foreign_payers_0" name="foreign_payers" checked={ foreign_payers === false ? true : false } onChange={ (event) => this._handle_onCheckboxFieldChange(event.target.name, false) }/>
<label htmlFor="foreign_payers_0">Нет</label>
<input type="radio" hidden=""
value="0"
id="non_profit.foreign_payers_0"
name="non_profit.foreign_payers"
checked={ non_profit.foreign_payers === false ? true : false }
onChange={ (event) => this._handle_onCheckboxFieldChange(event.target.name, false) }
/>
<label htmlFor="non_profit.foreign_payers_0" className="unselectable">Нет</label>
</div>
<div className="form_field checkbox">
<input type="radio" value="1" hidden="" id="foreign_payers_1" name="foreign_payers" checked={ foreign_payers === false ? false : true } onChange={ (event) => this._handle_onCheckboxFieldChange(event.target.name, true) }/>
<label htmlFor="foreign_payers_1">Да</label>
<input type="radio" hidden=""
value="1"
id="non_profit.foreign_payers_1"
name="non_profit.foreign_payers"
checked={ non_profit.foreign_payers === false ? false : true }
onChange={ (event) => this._handle_onCheckboxFieldChange(event.target.name, true) }
/>
<label htmlFor="non_profit.foreign_payers_1" className="unselectable">Да</label>
</div>
</div>
</div>
@ -123,23 +157,44 @@ export default class Form_6_NonProfit extends QuestionnaireForm
<p>Укажите цели использования предмета лизинга и подтвердите их соответствие уставным целям для каждого предмета лизинга отдельно</p>
<div className="form_field">
<label>Легковые автомобили</label>
<input type="text" name="fin_goals_cars" value={ fin_goals_cars } placeholder="Введите данные" onChange={ (event) => this._handle_onCheckboxFieldChange(event.target.name, event.target.value) } required={ true }/>
<label className="unselectable">Легковые автомобили</label>
<input type="text"
id="non_profit.fin_goals_cars"
name="non_profit.fin_goals_cars"
value={ non_profit.fin_goals_cars }
placeholder="Введите данные"
onChange={ (event) => this._handle_onCheckboxFieldChange(event.target.name, event.target.value) }
required={ true }
/>
</div>
<div className="form_field">
<label>Легкий коммерческий транспорт</label>
<input type="text" name="fin_goals_trucks" value={ fin_goals_trucks } placeholder="Введите данные" onChange={ (event) => this._handle_onCheckboxFieldChange(event.target.name, event.target.value) } required={ true }/>
<label className="unselectable">Легкий коммерческий транспорт</label>
<input type="text"
id="non_profit.fin_goals_trucks"
name="non_profit.fin_goals_trucks"
value={ non_profit.fin_goals_trucks }
placeholder="Введите данные"
onChange={ (event) => this._handle_onCheckboxFieldChange(event.target.name, event.target.value) }
required={ true }
/>
</div>
<div className="form_field">
<label>Грузовые автомобили/ спецтехника</label>
<input type="text" name="fin_goals_special" value={ fin_goals_special } placeholder="Введите данные" onChange={ (event) => this._handle_onCheckboxFieldChange(event.target.name, event.target.value) } required={ true }/>
<label className="unselectable">Грузовые автомобили/ спецтехника</label>
<input type="text"
id="non_profit.fin_goals_special"
name="non_profit.fin_goals_special"
value={ non_profit.fin_goals_special }
placeholder="Введите данные"
onChange={ (event) => this._handle_onCheckboxFieldChange(event.target.name, event.target.value) }
required={ true }
/>
</div>
<div className="action">
<button type="submit" className="button button-blue" disabled={ false }>
{ phone_check_loading ? (
{ 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>
@ -148,4 +203,19 @@ export default class Form_6_NonProfit extends QuestionnaireForm
</React.Fragment>
)
}
}
}
function mapStateToProps(state, ownProps)
{
return {
non_profit: state.questionnaire.non_profit,
}
}
export const getServerSideProps = reduxWrapper.getServerSideProps(store =>
async ({ req, res, query }) =>
{
}
);
export default connect(mapStateToProps)(Form_6_NonProfit);

View File

@ -3,12 +3,16 @@ import Head from 'next/head';
import Image from 'next/image';
import Link from "next/link";
import cookie from 'cookie';
import { connect } from "react-redux";
import numeral from "numeral";
import pluralize from 'pluralize-ru';
import { SpinnerCircular } from 'spinners-react';
import { connect } from "react-redux";
import { withRouter } from 'next/router';
export default class Form_7_Check extends React.Component
import QuestionnaireForm from "../QuestionnaireForm";
import { reduxWrapper } from '../../../../../store';
class Form_7_Check extends QuestionnaireForm
{
constructor(props)
{
@ -17,14 +21,38 @@ export default class Form_7_Check extends React.Component
address: "",
phone_check_loading: false,
phone_number_format_error: false,
step: 7,
main: {},
legal_address: {},
fact_address: {},
postal_address: {},
head_person: {},
head_person_files: [],
signatory_person: {},
signatory_person_files: [],
founded_persons_template: {},
founded_persons: [],
client_contacts: {},
non_profit: {},
};
}
static getDerivedStateFromProps(nextProps, prevState)
{
return {
observer: nextProps.observer,
user: nextProps.user,
main: nextProps.main,
legal_address: nextProps.legal_address,
fact_address: nextProps.fact_address,
postal_address: nextProps.postal_address,
head_person: nextProps.head_person,
head_person_files: nextProps.head_person_files,
signatory_person: nextProps.signatory_person,
signatory_person_files: nextProps.signatory_person_files,
founded_persons_template: nextProps.founded_persons_template,
founded_persons: nextProps.founded_persons,
client_contacts: nextProps.client_contacts,
non_profit: nextProps.non_profit,
};
}
@ -646,4 +674,29 @@ export default class Form_7_Check extends React.Component
</React.Fragment>
)
}
}
}
function mapStateToProps(state, ownProps)
{
return {
main: state.questionnaire.main,
legal_address: state.questionnaire.legal_address,
fact_address: state.questionnaire.fact_address,
postal_address: state.questionnaire.postal_address,
head_person: state.questionnaire.head_person,
head_person_files: state.questionnaire.head_person_files,
signatory_person: state.questionnaire.signatory_person,
signatory_person_files: state.questionnaire.signatory_person_files,
founded_persons: state.questionnaire.founded_persons,
client_contacts: state.questionnaire.client_contacts,
non_profit: state.questionnaire.non_profit,
}
}
export const getServerSideProps = reduxWrapper.getServerSideProps(store =>
async ({ req, res, query }) =>
{
}
);
export default connect(mapStateToProps)(Form_7_Check);

View File

@ -3,20 +3,29 @@ import Head from "next/head";
import Image from "next/image";
import Link from "next/link";
import cookie from "cookie";
import { connect } from "react-redux";
import numeral from "numeral";
import pluralize from "pluralize-ru";
import { SpinnerCircular } from "spinners-react";
import { connect } from "react-redux";
import { withRouter } from 'next/router';
import moment from "moment";
export default class Form_8_Signing extends React.Component
import QuestionnaireForm from "../QuestionnaireForm";
import { reduxWrapper } from '../../../../../store';
import DigitalSignaturesList from "../DigitalSignaturesList";
class Form_8_Signing extends QuestionnaireForm
{
constructor(props)
{
super(props);
this.state = {
sign_digital: true,
address: "",
phone_check_loading: false,
phone_number_format_error: false,
certificates: [],
};
}
@ -28,7 +37,9 @@ export default class Form_8_Signing extends React.Component
};
}
componentDidMount() {}
componentDidMount()
{
}
_handle_onFormSubmit = (event) =>
{
@ -36,11 +47,6 @@ export default class Form_8_Signing extends React.Component
console.log("FormAddress", "_handle_onFormSubmit");
};
_handle_onAddressChange = (value) =>
{
this.setState({ address: value }, () => {});
};
_check_fields_disabled = (values) =>
{
for (let i in values)
@ -54,137 +60,94 @@ export default class Form_8_Signing extends React.Component
return false;
};
_download = () =>
{
alert("Скачивание сформированного PDF");
}
render()
{
const { address, phone_check_loading, phone_number_format_error } = this.state;
const { phone_check_loading, sign_digital, certificates } = this.state;
return (
<React.Fragment>
<form
onSubmit={this._handle_onFormSubmit}
className="questionnaire questionnaire_8"
>
<p className="title">8. Выбор метода подписания</p>
<div className="form_field">
<div style={{ width: "100%" }}>
<div className="form_field checkbox">
<input type="radio" hidden="" id="" name="" checked />
<label htmlFor="">
<b>Подписать онлайн используя ЭЦП</b>
</label>
<form onSubmit={ this._handle_onFormSubmit } className="questionnaire questionnaire_8">
<p className="title">8. Выбор метода подписания</p>
<div className="form_field">
<div style={{ width: "100%" }}>
<div className="form_field checkbox">
<input type="radio" hidden=""
id="sign_digital"
name="sign_digital"
checked={ sign_digital }
onChange={ () => this.setState({ sign_digital: true }) }
/>
<label htmlFor="sign_digital">
<b>Подписать онлайн используя ЭЦП</b>
</label>
</div>
</div>
</div>
</div>
<div className="feed">
<p>Выберите подписанта</p>
<div className="feed_list">
<div className="form_field checkbox">
<input type="radio" hidden="" id="" name="" />
<label htmlFor="">
<div className="feed_item user">
<img src="/assets/images/icons/avatar.svg" alt="" />
<div>
<p className="item_title">Басок Дмитрий Вадимович</p>
<p className="item_desc">
<span>ИНН 1234567890</span>
<span>Подпись действительна до 01.10.2023</span>
</p>
</div>
</div>
</label>
</div>
<div className="form_field checkbox">
<input type="radio" hidden="" id="" name="" />
<label htmlFor="">
<div className="feed_item user">
<img src="/assets/images/icons/avatar.svg" alt="" />
<div>
<p className="item_title">Басок Дмитрий Вадимович</p>
<p className="item_desc">
<span>ИНН 1234567890</span>
<span>Подпись действительна до 01.10.2023</span>
</p>
</div>
</div>
</label>
</div>
<div className="form_field checkbox">
<input type="radio" hidden="" id="" name="" />
<label htmlFor="">
<div className="feed_item user">
<img src="/assets/images/icons/avatar.svg" alt="" />
<div>
<p className="item_title">Басок Дмитрий Вадимович</p>
<p className="item_desc">
<span>ИНН 1234567890</span>
<span>Подпись действительна до 01.10.2023</span>
</p>
</div>
</div>
</label>
</div>
</div>
</div>
<div className="form_field">
<div style={{ width: "100%" }}>
<div className="form_field checkbox">
<input type="radio" hidden="" id="" name="" checked />
<label htmlFor="">
<b>Подписать в бумажном виде</b>
</label>
</div>
</div>
</div>
<div className="dosc_list medium-icon">
<div className="row">
<p className="doc_name i-pdf extension">
01/20/2020 (.PDF)
<span style={{ width: "100%" }}>Постановление</span>
</p>
<a className="button button-blue ">Скачать</a>
</div>
</div>
<div className="action">
<div></div>
<button
type="submit"
className="button button-blue"
disabled={ false }
>
{ phone_check_loading ? (
<SpinnerCircular
size={ 24 }
thickness={ 100 }
speed={ 100 }
color="rgba(255, 255, 255, 1)"
secondaryColor="rgba(255, 255, 255, 0.5)"
style={{ marginTop: "4px" }}
/>
) : (
"Продолжить"
{ sign_digital && (
<DigitalSignaturesList form={ null }/>
) }
<div className="form_field">
<div style={{ width: "100%" }}>
<div className="form_field checkbox">
<input type="radio" hidden=""
id="sign_print"
name="sign_print"
checked={ !sign_digital }
onChange={ () => this.setState({ sign_digital: false }) }
/>
<label htmlFor="sign_print">
<b>Подписать в бумажном виде</b>
</label>
</div>
</div>
</div>
{ !sign_digital && (
<div className="dosc_list medium-icon">
<div className="row">
<p className="doc_name i-pdf extension">
{ moment().format("DD.MM.YYYY HH:mm:ss") } (.PDF)
<span style={{ width: "100%" }}>Анкета клиента</span>
</p>
<a className="button button-blue " onClick={ this._download }>Скачать</a>
</div>
</div>
) }
</button>
</div>
</form>
<div className="questionnaire message error">
<svg width="44" height="45" viewBox="0 0 44 45" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M40.5425 31.1863L25.7969 8.08116C24.9653 6.77804 23.5459 6 22 6C20.4539 6 19.0345 6.77804 18.2032 8.08116L3.45741 31.1862C2.57234 32.5732 2.51363 34.3313 3.30467 35.7746C4.09572 37.2173 5.60918 38.1137 7.25444 38.1137H36.7456C38.3909 38.1137 39.9044 37.2175 40.6956 35.7742C41.4863 34.3313 41.4276 32.5733 40.5425 31.1863ZM22 34.2245C20.644 34.2245 19.5448 33.1252 19.5448 31.7694C19.5448 30.4133 20.6441 29.3141 22 29.3141C23.356 29.3141 24.4551 30.4133 24.4551 31.7694C24.4551 33.1252 23.3559 34.2245 22 34.2245ZM25.403 17.1635L24.1937 25.3052C24.0157 26.5037 22.8999 27.3309 21.7016 27.1529C20.7334 27.0091 20.0075 26.25 19.8582 25.333L18.5451 17.2074C18.2394 15.3155 19.5251 13.534 21.417 13.2283C23.3089 12.9226 25.0904 14.2083 25.3962 16.1002C25.4536 16.4565 25.4517 16.8243 25.403 17.1635Z" fill="white"/>
</svg>
<p>
<b>Ошибка</b>
Подписан не соответствует указанному подписанту в анкете
</p>
</div>
</React.Fragment>
);
}
}
function mapStateToProps(state, ownProps)
{
return {
main: state.questionnaire.main,
legal_address: state.questionnaire.legal_address,
fact_address: state.questionnaire.fact_address,
postal_address: state.questionnaire.postal_address,
head_person: state.questionnaire.head_person,
head_person_files: state.questionnaire.head_person_files,
signatory_person: state.questionnaire.signatory_person,
signatory_person_files: state.questionnaire.signatory_person_files,
founded_persons: state.questionnaire.founded_persons,
client_contacts: state.questionnaire.client_contacts,
non_profit: state.questionnaire.non_profit,
}
}
export const getServerSideProps = reduxWrapper.getServerSideProps(store =>
async ({ req, res, query }) =>
{
}
);
export default connect(mapStateToProps)(Form_8_Signing);

View File

@ -139,6 +139,15 @@ export default class QuestionnaireForm extends React.Component
this.setState(update);
}
_handle_onFieldChange = (name, payload) =>
{
console.log("_handle_onFieldChange", name, payload);
const update = { ...this.state };
_set(update, name, payload);
this.setState(update);
}
_handle_onAddFile = (name, files) =>
{
console.log("QuestionnaireForm", "_handle_onAdd", { name, files });

View File

@ -15,7 +15,7 @@ import InnerMenu from "./components/InnerMenu";
import Header from '../components/Header';
import Footer from '../components/Footer';
import { sendPhoneChangeNumber, sendPhoneChangeNumberSmsCode, setUserPhone, getQuestionnaire } from '../../actions';
import { sendPhoneChangeNumber, sendPhoneChangeNumberSmsCode, setUserPhone, getQuestionnaire, getContractGraphicChangeSignatories } from '../../actions';
import AccountLayout from "../components/Layout/Account";
import Form_1_Main from "./components/forms/Form_1_Main";
import Form_2_Contacts from "./components/forms/Form_2_Contacts";
@ -35,95 +35,23 @@ class QuestionnairePage extends React.Component
phone: "",
phone_check_loading: false,
phone_number_format_error: false,
signatories: [],
};
}
static getDerivedStateFromProps(nextProps, prevState)
{
return {
signatories: nextProps.signatories,
};
}
componentDidMount()
{
getQuestionnaire({ dispatch: this.props.dispatch });
}
const { dispatch } = this.props;
_handle_onPhoneSubmit = (event) =>
{
event.preventDefault();
const { user, phone, phone_check_loading } = this.state;
if(!phone_check_loading)
{
this.setState({ phone_check_loading: true }, () =>
{
sendPhoneChangeNumber({ email: user.email, phone })
.then(() =>
{
this.setState({ phone_check_loading: false, phone_number_error: false, timer: 60, phone_form_step: 2, }, () =>
{
this.timer_ref = setInterval(() =>
{
const t = this.state.timer - 1;
this.setState({ timer: t, }, () =>
{
if(t === 0)
{
clearInterval(this.timer_ref);
}
});
}, 1000);
});
})
.catch(() =>
{
this.setState({ phone_number_error: true, phone_check_loading: false });
});
});
}
}
_handle_onCodeSubmit = (event) =>
{
event.preventDefault();
const { phone, phone_code, code_check_loading } = this.state;
if(!code_check_loading)
{
this.setState({ code_check_loading: true }, () =>
{
sendPhoneChangeNumberSmsCode({ phone, code: phone_code })
.then(() =>
{
const new_user = { ...this.state.user };
new_user.phone = phone;
setUserPhone({ dispatch: this.props.dispatch, user: new_user });
this.setState({ phone_sms_code_error: false, code_check_loading: false, phone_form_step: 3 });
})
.catch(() =>
{
this.setState({ phone_sms_code_error: true, code_check_loading: false });
});
});
}
}
_handle_onResendCode = (event) =>
{
this.setState({ phone_sms_code_error: false }, () =>
{
this._handle_onPhoneSubmit(event);
});
}
_handle_onPhoneChange = (value) =>
{
const phone_number_format_error = value.length > 1 && (value[0] !== "+" || value[1] !== "7") ? true : false;
this.setState({ phone: value, phone_login_disabled: this._check_fields_disabled([ value ]), phone_number_error: false, phone_number_format_error: phone_number_format_error });
}
_handle_onPhoneCodeChange = (value) =>
{
this.setState({ phone_code: value, phone_code_submit_disabled: this._check_fields_disabled([ value ]), phone_sms_code_error: false });
getQuestionnaire({ dispatch });
getContractGraphicChangeSignatories({ dispatch });
}
_check_fields_disabled = (values) =>
@ -141,12 +69,13 @@ class QuestionnairePage extends React.Component
_renderForm = () =>
{
const { signatories } = this.state;
const route = this.props.router.asPath;
if (route.indexOf("#main") > -1) return (<Form_1_Main/>);
if (route.indexOf("#contacts") > -1) return (<Form_2_Contacts/>);
if (route.indexOf("#signer") > -1) return (<Form_3_Signer/>);
if (route.indexOf("#shareholders") > -1) return (<Form_4_Shareholders/>);
if (route.indexOf("#shareholders") > -1) return (<Form_4_Shareholders signatories={ signatories }/>);
if (route.indexOf("#regulatory") > -1) return (<Form_5_Regulatory/>);
if (route.indexOf("#non-profit") > -1) return (<Form_6_NonProfit/>);
if (route.indexOf("#check") > -1) return (<Form_7_Check/>);
@ -191,8 +120,7 @@ class QuestionnairePage extends React.Component
function mapStateToProps(state, ownProps)
{
return {
observer: state.auth.observer,
user: state.user,
signatories: state.contract.change.signatories,
}
}

View File

@ -0,0 +1,734 @@
;(function () {
//already loaded
if(window.cadesplugin)
return;
var pluginObject;
var plugin_resolved = 0;
var plugin_reject;
var plugin_resolve;
var isOpera = 0;
var isFireFox = 0;
var isEdge = 0;
var isSafari = 0;
var failed_extensions = 0;
var canPromise = !!window.Promise;
var cadesplugin;
if(canPromise)
{
cadesplugin = new Promise(function(resolve, reject)
{
plugin_resolve = resolve;
plugin_reject = reject;
});
} else
{
cadesplugin = {};
}
function check_browser() {
var ua= navigator.userAgent, tem, M= ua.match(/(opera|chrome|safari|firefox|msie|trident(?=\/))\/?\s*(\d+)/i) || [];
if(/trident/i.test(M[1])){
tem= /\brv[ :]+(\d+)/g.exec(ua) || [];
return {name:'IE',version:(tem[1] || '')};
}
if(M[1]=== 'Chrome'){
tem= ua.match(/\b(OPR|Edge)\/(\d+)/);
if(tem!= null) return {name:tem[1].replace('OPR', 'Opera'),version:tem[2]};
}
M= M[2]? [M[1], M[2]]: [navigator.appName, navigator.appVersion, '-?'];
if((tem= ua.match(/version\/(\d+)/i))!= null) M.splice(1, 1, tem[1]);
return {name:M[0],version:M[1]};
}
var browserSpecs = check_browser();
function cpcsp_console_log(level, msg){
//IE9 не может писать в консоль если не открыта вкладка developer tools
if(typeof(console) === 'undefined')
return;
if (level <= cadesplugin.current_log_level ){
if (level === cadesplugin.LOG_LEVEL_DEBUG)
console.log("DEBUG: %s", msg);
if (level === cadesplugin.LOG_LEVEL_INFO)
console.info("INFO: %s", msg);
if (level === cadesplugin.LOG_LEVEL_ERROR)
console.error("ERROR: %s", msg);
return;
}
}
function set_log_level(level){
if (!((level === cadesplugin.LOG_LEVEL_DEBUG) ||
(level === cadesplugin.LOG_LEVEL_INFO) ||
(level === cadesplugin.LOG_LEVEL_ERROR))){
cpcsp_console_log(cadesplugin.LOG_LEVEL_ERROR, "cadesplugin_api.js: Incorrect log_level: " + level);
return;
}
cadesplugin.current_log_level = level;
if (cadesplugin.current_log_level === cadesplugin.LOG_LEVEL_DEBUG)
cpcsp_console_log(cadesplugin.LOG_LEVEL_INFO, "cadesplugin_api.js: log_level = DEBUG");
if (cadesplugin.current_log_level === cadesplugin.LOG_LEVEL_INFO)
cpcsp_console_log(cadesplugin.LOG_LEVEL_INFO, "cadesplugin_api.js: log_level = INFO");
if (cadesplugin.current_log_level === cadesplugin.LOG_LEVEL_ERROR)
cpcsp_console_log(cadesplugin.LOG_LEVEL_INFO, "cadesplugin_api.js: log_level = ERROR");
if(isNativeMessageSupported())
{
if (cadesplugin.current_log_level === cadesplugin.LOG_LEVEL_DEBUG)
window.postMessage("set_log_level=debug", "*");
if (cadesplugin.current_log_level === cadesplugin.LOG_LEVEL_INFO)
window.postMessage("set_log_level=info", "*");
if (cadesplugin.current_log_level === cadesplugin.LOG_LEVEL_ERROR)
window.postMessage("set_log_level=error", "*");
}
}
function set_constantValues()
{
cadesplugin.CAPICOM_LOCAL_MACHINE_STORE = 1;
cadesplugin.CAPICOM_CURRENT_USER_STORE = 2;
cadesplugin.CADESCOM_LOCAL_MACHINE_STORE = 1;
cadesplugin.CADESCOM_CURRENT_USER_STORE = 2;
cadesplugin.CADESCOM_CONTAINER_STORE = 100;
cadesplugin.CAPICOM_MY_STORE = "My";
cadesplugin.CAPICOM_STORE_OPEN_MAXIMUM_ALLOWED = 2;
cadesplugin.CAPICOM_CERTIFICATE_FIND_SUBJECT_NAME = 1;
cadesplugin.CADESCOM_XML_SIGNATURE_TYPE_ENVELOPED = 0;
cadesplugin.CADESCOM_XML_SIGNATURE_TYPE_ENVELOPING = 1;
cadesplugin.CADESCOM_XML_SIGNATURE_TYPE_TEMPLATE = 2;
cadesplugin.XmlDsigGost3410UrlObsolete = "http://www.w3.org/2001/04/xmldsig-more#gostr34102001-gostr3411";
cadesplugin.XmlDsigGost3411UrlObsolete = "http://www.w3.org/2001/04/xmldsig-more#gostr3411";
cadesplugin.XmlDsigGost3410Url = "urn:ietf:params:xml:ns:cpxmlsec:algorithms:gostr34102001-gostr3411";
cadesplugin.XmlDsigGost3411Url = "urn:ietf:params:xml:ns:cpxmlsec:algorithms:gostr3411";
cadesplugin.CADESCOM_CADES_DEFAULT = 0;
cadesplugin.CADESCOM_CADES_BES = 1;
cadesplugin.CADESCOM_CADES_T = 0x5;
cadesplugin.CADESCOM_CADES_X_LONG_TYPE_1 = 0x5d;
cadesplugin.CADESCOM_PKCS7_TYPE = 0xffff;
cadesplugin.CADESCOM_ENCODE_BASE64 = 0;
cadesplugin.CADESCOM_ENCODE_BINARY = 1;
cadesplugin.CADESCOM_ENCODE_ANY = -1;
cadesplugin.CAPICOM_CERTIFICATE_INCLUDE_CHAIN_EXCEPT_ROOT = 0;
cadesplugin.CAPICOM_CERTIFICATE_INCLUDE_WHOLE_CHAIN = 1;
cadesplugin.CAPICOM_CERTIFICATE_INCLUDE_END_ENTITY_ONLY = 2;
cadesplugin.CAPICOM_CERT_INFO_SUBJECT_SIMPLE_NAME = 0;
cadesplugin.CAPICOM_CERT_INFO_ISSUER_SIMPLE_NAME = 1;
cadesplugin.CAPICOM_CERTIFICATE_FIND_SHA1_HASH = 0;
cadesplugin.CAPICOM_CERTIFICATE_FIND_SUBJECT_NAME = 1;
cadesplugin.CAPICOM_CERTIFICATE_FIND_ISSUER_NAME = 2;
cadesplugin.CAPICOM_CERTIFICATE_FIND_ROOT_NAME = 3;
cadesplugin.CAPICOM_CERTIFICATE_FIND_TEMPLATE_NAME = 4;
cadesplugin.CAPICOM_CERTIFICATE_FIND_EXTENSION = 5;
cadesplugin.CAPICOM_CERTIFICATE_FIND_EXTENDED_PROPERTY = 6;
cadesplugin.CAPICOM_CERTIFICATE_FIND_APPLICATION_POLICY = 7;
cadesplugin.CAPICOM_CERTIFICATE_FIND_CERTIFICATE_POLICY = 8;
cadesplugin.CAPICOM_CERTIFICATE_FIND_TIME_VALID = 9;
cadesplugin.CAPICOM_CERTIFICATE_FIND_TIME_NOT_YET_VALID = 10;
cadesplugin.CAPICOM_CERTIFICATE_FIND_TIME_EXPIRED = 11;
cadesplugin.CAPICOM_CERTIFICATE_FIND_KEY_USAGE = 12;
cadesplugin.CAPICOM_DIGITAL_SIGNATURE_KEY_USAGE = 128;
cadesplugin.CAPICOM_PROPID_ENHKEY_USAGE = 9;
cadesplugin.CAPICOM_OID_OTHER = 0;
cadesplugin.CAPICOM_OID_KEY_USAGE_EXTENSION = 10;
cadesplugin.CAPICOM_EKU_CLIENT_AUTH = 2;
cadesplugin.CAPICOM_EKU_SMARTCARD_LOGON = 5;
cadesplugin.CAPICOM_EKU_OTHER = 0;
cadesplugin.CAPICOM_AUTHENTICATED_ATTRIBUTE_SIGNING_TIME = 0;
cadesplugin.CAPICOM_AUTHENTICATED_ATTRIBUTE_DOCUMENT_NAME = 1;
cadesplugin.CAPICOM_AUTHENTICATED_ATTRIBUTE_DOCUMENT_DESCRIPTION = 2;
cadesplugin.CADESCOM_AUTHENTICATED_ATTRIBUTE_SIGNING_TIME = 0;
cadesplugin.CADESCOM_AUTHENTICATED_ATTRIBUTE_DOCUMENT_NAME = 1;
cadesplugin.CADESCOM_AUTHENTICATED_ATTRIBUTE_DOCUMENT_DESCRIPTION = 2;
cadesplugin.CADESCOM_ATTRIBUTE_OTHER = -1;
cadesplugin.CADESCOM_STRING_TO_UCS2LE = 0;
cadesplugin.CADESCOM_BASE64_TO_BINARY = 1;
cadesplugin.CADESCOM_DISPLAY_DATA_NONE = 0;
cadesplugin.CADESCOM_DISPLAY_DATA_CONTENT = 1;
cadesplugin.CADESCOM_DISPLAY_DATA_ATTRIBUTE = 2;
cadesplugin.CADESCOM_ENCRYPTION_ALGORITHM_RC2 = 0;
cadesplugin.CADESCOM_ENCRYPTION_ALGORITHM_RC4 = 1;
cadesplugin.CADESCOM_ENCRYPTION_ALGORITHM_DES = 2;
cadesplugin.CADESCOM_ENCRYPTION_ALGORITHM_3DES = 3;
cadesplugin.CADESCOM_ENCRYPTION_ALGORITHM_AES = 4;
cadesplugin.CADESCOM_ENCRYPTION_ALGORITHM_GOST_28147_89 = 25;
cadesplugin.CADESCOM_HASH_ALGORITHM_SHA1 = 0;
cadesplugin.CADESCOM_HASH_ALGORITHM_MD2 = 1;
cadesplugin.CADESCOM_HASH_ALGORITHM_MD4 = 2;
cadesplugin.CADESCOM_HASH_ALGORITHM_MD5 = 3;
cadesplugin.CADESCOM_HASH_ALGORITHM_SHA_256 = 4;
cadesplugin.CADESCOM_HASH_ALGORITHM_SHA_384 = 5;
cadesplugin.CADESCOM_HASH_ALGORITHM_SHA_512 = 6;
cadesplugin.CADESCOM_HASH_ALGORITHM_CP_GOST_3411 = 100;
cadesplugin.CADESCOM_HASH_ALGORITHM_CP_GOST_3411_2012_256 = 101;
cadesplugin.CADESCOM_HASH_ALGORITHM_CP_GOST_3411_2012_512 = 102;
cadesplugin.CADESCOM_HASH_ALGORITHM_CP_GOST_3411_HMAC = 110;
cadesplugin.CADESCOM_HASH_ALGORITHM_CP_GOST_3411_2012_256_HMAC = 111;
cadesplugin.CADESCOM_HASH_ALGORITHM_CP_GOST_3411_2012_512_HMAC = 112;
cadesplugin.LOG_LEVEL_DEBUG = 4;
cadesplugin.LOG_LEVEL_INFO = 2;
cadesplugin.LOG_LEVEL_ERROR = 1;
cadesplugin.CADESCOM_AllowNone = 0;
cadesplugin.CADESCOM_AllowNoOutstandingRequest = 0x1;
cadesplugin.CADESCOM_AllowUntrustedCertificate = 0x2;
cadesplugin.CADESCOM_AllowUntrustedRoot = 0x4;
cadesplugin.CADESCOM_SkipInstallToStore = 0x10000000;
}
function async_spawn(generatorFunc) {
function continuer(verb, arg) {
var result;
try {
result = generator[verb](arg);
} catch (err) {
return Promise.reject(err);
}
if (result.done) {
return result.value;
} else {
return Promise.resolve(result.value).then(onFulfilled, onRejected);
}
}
var generator = generatorFunc(Array.prototype.slice.call(arguments, 1));
var onFulfilled = continuer.bind(continuer, "next");
var onRejected = continuer.bind(continuer, "throw");
return onFulfilled();
}
function isIE() {
// var retVal = (("Microsoft Internet Explorer" == navigator.appName) || // IE < 11
// navigator.userAgent.match(/Trident\/./i)); // IE 11
return (browserSpecs.name === 'IE' || browserSpecs.name === 'MSIE');
}
function isIOS() {
return (navigator.userAgent.match(/ipod/i) ||
navigator.userAgent.match(/ipad/i) ||
navigator.userAgent.match(/iphone/i));
}
function isNativeMessageSupported()
{
// В IE работаем через NPAPI
if(isIE())
return false;
// В Edge работаем через NativeMessage
if(browserSpecs.name === 'Edge') {
isEdge = true;
return true;
}
// В Chrome, Firefox, Safari и Opera работаем через асинхронную версию в зависимости от версии
if(browserSpecs.name === 'Opera') {
isOpera = true;
if(browserSpecs.version >= 33){
return true;
}
else{
return false;
}
}
if(browserSpecs.name === 'Firefox') {
isFireFox = true;
if(browserSpecs.version >= 52){
return true;
}
else{
return false;
}
}
if(browserSpecs.name === 'Chrome') {
if(browserSpecs.version >= 42){
return true;
}
else{
return false;
}
}
//В Сафари начиная с 12 версии нет NPAPI
if(browserSpecs.name === 'Safari') {
isSafari = true;
if(browserSpecs.version >= 12) {
return true;
} else {
return false;
}
}
}
// Функция активации объектов КриптоПро ЭЦП Browser plug-in
function CreateObject(name) {
if (isIOS()) {
// На iOS для создания объектов используется функция
// call_ru_cryptopro_npcades_10_native_bridge, определенная в IOS_npcades_supp.js
return call_ru_cryptopro_npcades_10_native_bridge("CreateObject", [name]);
}
if (isIE()) {
// В Internet Explorer создаются COM-объекты
if (name.match(/X509Enrollment/i)) {
try {
// Объекты CertEnroll пробуем создавать через нашу фабрику,
// если не получилось то через CX509EnrollmentWebClassFactory
var objCertEnrollClassFactory = document.getElementById("webClassFactory");
return objCertEnrollClassFactory.CreateObject(name);
}
catch (e) {
try {
var objWebClassFactory = document.getElementById("certEnrollClassFactory");
return objWebClassFactory.CreateObject(name);
}
catch (err) {
throw ("Для создания обьектов X509Enrollment следует настроить веб-узел на использование проверки подлинности по протоколу HTTPS");
}
}
}
// Объекты CAPICOM и CAdESCOM создаются через CAdESCOM.WebClassFactory
try {
var objWebClassFactory = document.getElementById("webClassFactory");
return objWebClassFactory.CreateObject(name);
}
catch (e) {
// Для версий плагина ниже 2.0.12538
return new ActiveXObject(name);
}
}
// создаются объекты NPAPI
return pluginObject.CreateObject(name);
}
function decimalToHexString(number) {
if (number < 0) {
number = 0xFFFFFFFF + number + 1;
}
return number.toString(16).toUpperCase();
}
function GetMessageFromException(e) {
var err = e.message;
if (!err) {
err = e;
} else if (e.number) {
err += " (0x" + decimalToHexString(e.number) + ")";
}
return err;
}
function getLastError(exception) {
if(isNativeMessageSupported() || isIE() || isIOS() ) {
return GetMessageFromException(exception);
}
try {
return pluginObject.getLastError();
} catch(e) {
return GetMessageFromException(exception);
}
}
// Функция для удаления созданных объектов
function ReleasePluginObjects() {
return cpcsp_chrome_nmcades.ReleasePluginObjects();
}
// Функция активации асинхронных объектов КриптоПро ЭЦП Browser plug-in
function CreateObjectAsync(name) {
return pluginObject.CreateObjectAsync(name);
}
//Функции для IOS
var ru_cryptopro_npcades_10_native_bridge = {
callbacksCount : 1,
callbacks : {},
// Automatically called by native layer when a result is available
resultForCallback : function resultForCallback(callbackId, resultArray) {
var callback = ru_cryptopro_npcades_10_native_bridge.callbacks[callbackId];
if (!callback) return;
callback.apply(null,resultArray);
},
// Use this in javascript to request native objective-c code
// functionName : string (I think the name is explicit :p)
// args : array of arguments
// callback : function with n-arguments that is going to be called when the native code returned
call : function call(functionName, args, callback) {
var hasCallback = callback && typeof callback === "function";
var callbackId = hasCallback ? ru_cryptopro_npcades_10_native_bridge.callbacksCount++ : 0;
if (hasCallback)
ru_cryptopro_npcades_10_native_bridge.callbacks[callbackId] = callback;
var iframe = document.createElement("IFRAME");
var arrObjs = new Array("_CPNP_handle");
try{
iframe.setAttribute("src", "cpnp-js-call:" + functionName + ":" + callbackId+ ":" + encodeURIComponent(JSON.stringify(args, arrObjs)));
} catch(e){
alert(e);
}
document.documentElement.appendChild(iframe);
iframe.parentNode.removeChild(iframe);
iframe = null;
}
};
function call_ru_cryptopro_npcades_10_native_bridge(functionName, array){
var tmpobj;
var ex;
ru_cryptopro_npcades_10_native_bridge.call(functionName, array, function(e, response){
ex = e;
var str='tmpobj='+response;
eval(str);
if (typeof (tmpobj) === "string"){
tmpobj = tmpobj.replace(/\\\n/gm, "\n");
tmpobj = tmpobj.replace(/\\\r/gm, "\r");
}
});
if(ex)
throw ex;
return tmpobj;
}
function show_firefox_missing_extension_dialog()
{
if (!window.cadesplugin_skip_extension_install)
{
var ovr = document.createElement('div');
ovr.id = "cadesplugin_ovr";
ovr.style = "visibility: hidden; position: fixed; left: 0px; top: 0px; width:100%; height:100%; background-color: rgba(0,0,0,0.7)";
ovr.innerHTML = "<div id='cadesplugin_ovr_item' style='position:relative; width:400px; margin:100px auto; background-color:#fff; border:2px solid #000; padding:10px; text-align:center; opacity: 1; z-index: 1500'>" +
"<button id='cadesplugin_close_install' style='float: right; font-size: 10px; background: transparent; border: 1; margin: -5px'>X</button>" +
"<p>Для работы КриптоПро ЭЦП Browser plugin на данном сайте необходимо расширение для браузера. Убедитесь, что оно у Вас включено или установите его." +
"<p><a href='https://www.cryptopro.ru/sites/default/files/products/cades/extensions/firefox_cryptopro_extension_latest.xpi'>Скачать расширение</a></p>" +
"</div>";
document.getElementsByTagName("Body")[0].appendChild(ovr);
document.getElementById("cadesplugin_close_install").addEventListener('click',function()
{
plugin_loaded_error("Плагин недоступен");
document.getElementById("cadesplugin_ovr").style.visibility = 'hidden';
});
ovr.addEventListener('click',function()
{
plugin_loaded_error("Плагин недоступен");
document.getElementById("cadesplugin_ovr").style.visibility = 'hidden';
});
ovr.style.visibility="visible";
}
}
//Выводим окно поверх других с предложением установить расширение для Opera.
//Если установленна переменная cadesplugin_skip_extension_install - не предлагаем установить расширение
function install_opera_extension()
{
if (!window.cadesplugin_skip_extension_install)
{
document.addEventListener('DOMContentLoaded', function() {
var ovr = document.createElement('div');
ovr.id = "cadesplugin_ovr";
ovr.style = "visibility: hidden; position: fixed; left: 0px; top: 0px; width:100%; height:100%; background-color: rgba(0,0,0,0.7)";
ovr.innerHTML = "<div id='cadesplugin_ovr_item' style='position:relative; width:400px; margin:100px auto; background-color:#fff; border:2px solid #000; padding:10px; text-align:center; opacity: 1; z-index: 1500'>" +
"<button id='cadesplugin_close_install' style='float: right; font-size: 10px; background: transparent; border: 1; margin: -5px'>X</button>" +
"<p>Для работы КриптоПро ЭЦП Browser plugin на данном сайте необходимо установить расширение из каталога дополнений Opera." +
"<p><button id='cadesplugin_install' style='font:12px Arial'>Установить расширение</button></p>" +
"</div>";
document.getElementsByTagName("Body")[0].appendChild(ovr);
var btn_install = document.getElementById("cadesplugin_install");
btn_install.addEventListener('click', function(event) {
opr.addons.installExtension("epebfcehmdedogndhlcacafjaacknbcm",
function()
{
document.getElementById("cadesplugin_ovr").style.visibility = 'hidden';
location.reload();
},
function(){})
});
document.getElementById("cadesplugin_close_install").addEventListener('click',function()
{
plugin_loaded_error("Плагин недоступен");
document.getElementById("cadesplugin_ovr").style.visibility = 'hidden';
});
ovr.addEventListener('click',function()
{
plugin_loaded_error("Плагин недоступен");
document.getElementById("cadesplugin_ovr").style.visibility = 'hidden';
});
ovr.style.visibility="visible";
document.getElementById("cadesplugin_ovr_item").addEventListener('click',function(e){
e.stopPropagation();
});
});
}else
{
plugin_loaded_error("Плагин недоступен");
}
}
function firefox_or_edge_nmcades_onload() {
cpcsp_chrome_nmcades.check_chrome_plugin(plugin_loaded, plugin_loaded_error);
}
function nmcades_api_onload () {
window.postMessage("cadesplugin_echo_request", "*");
window.addEventListener("message", function (event){
if (typeof(event.data) !== "string" || !event.data.match("cadesplugin_loaded"))
return;
if(isFireFox || isEdge || isSafari)
{
// Для Firefox, Сафари, Edge вместе с сообщением cadesplugin_loaded прилетает url для загрузки nmcades_plugin_api.js
var url = event.data.substring(event.data.indexOf("url:") + 4);
var fileref = document.createElement('script');
fileref.setAttribute("type", "text/javascript");
fileref.setAttribute("src", url);
fileref.onerror = plugin_loaded_error;
fileref.onload = firefox_or_edge_nmcades_onload;
document.getElementsByTagName("head")[0].appendChild(fileref);
// Для Firefox, Safari и Edge у нас только по одному расширению.
failed_extensions++;
}else {
cpcsp_chrome_nmcades.check_chrome_plugin(plugin_loaded, plugin_loaded_error);
}
}, false);
}
//Загружаем расширения для Chrome, Opera, YaBrowser, FireFox, Edge, Safari
function load_extension()
{
if(isFireFox || isEdge || isSafari){
// вызываем callback руками т.к. нам нужно узнать ID расширения. Он уникальный для браузера.
nmcades_api_onload();
} else {
// в асинхронном варианте для chrome и opera подключаем оба расширения
var fileref = document.createElement('script');
fileref.setAttribute("type", "text/javascript");
fileref.setAttribute("src", "chrome-extension://iifchhfnnmpdbibifmljnfjhpififfog/nmcades_plugin_api.js");
fileref.onerror = plugin_loaded_error;
fileref.onload = nmcades_api_onload;
document.getElementsByTagName("head")[0].appendChild(fileref);
fileref = document.createElement('script');
fileref.setAttribute("type", "text/javascript");
fileref.setAttribute("src", "chrome-extension://epebfcehmdedogndhlcacafjaacknbcm/nmcades_plugin_api.js");
fileref.onerror = plugin_loaded_error;
fileref.onload = nmcades_api_onload;
document.getElementsByTagName("head")[0].appendChild(fileref);
}
}
//Загружаем плагин для NPAPI
function load_npapi_plugin()
{
var elem = document.createElement('object');
elem.setAttribute("id", "cadesplugin_object");
elem.setAttribute("type", "application/x-cades");
elem.setAttribute("style", "visibility: hidden");
document.getElementsByTagName("body")[0].appendChild(elem);
pluginObject = document.getElementById("cadesplugin_object");
if(isIE())
{
var elem1 = document.createElement('object');
elem1.setAttribute("id", "certEnrollClassFactory");
elem1.setAttribute("classid", "clsid:884e2049-217d-11da-b2a4-000e7bbb2b09");
elem1.setAttribute("style", "visibility: hidden");
document.getElementsByTagName("body")[0].appendChild(elem1);
var elem2 = document.createElement('object');
elem2.setAttribute("id", "webClassFactory");
elem2.setAttribute("classid", "clsid:B04C8637-10BD-484E-B0DA-B8A039F60024");
elem2.setAttribute("style", "visibility: hidden");
document.getElementsByTagName("body")[0].appendChild(elem2);
}
}
//Отправляем событие что все ок.
function plugin_loaded()
{
plugin_resolved = 1;
if(canPromise)
{
plugin_resolve();
}else {
window.postMessage("cadesplugin_loaded", "*");
}
}
//Отправляем событие что сломались.
function plugin_loaded_error(msg)
{
if(isNativeMessageSupported())
{
//в асинхронном варианте подключаем оба расширения, если сломались оба пробуем установить для Opera
failed_extensions++;
if(failed_extensions<2)
return;
if(isOpera && (typeof(msg) === 'undefined'|| typeof(msg) === 'object'))
{
install_opera_extension();
return;
}
}
if(typeof(msg) === 'undefined' || typeof(msg) === 'object')
msg = "Плагин недоступен";
plugin_resolved = 1;
if(canPromise)
{
plugin_reject(msg);
} else {
window.postMessage("cadesplugin_load_error", "*");
}
}
//проверяем что у нас хоть какое то событие ушло, и если не уходило кидаем еще раз ошибку
function check_load_timeout()
{
if(plugin_resolved === 1)
return;
if(isFireFox)
{
show_firefox_missing_extension_dialog();
}
plugin_resolved = 1;
if(canPromise)
{
plugin_reject("Истекло время ожидания загрузки плагина");
} else {
window.postMessage("cadesplugin_load_error", "*");
}
}
//Вспомогательная функция для NPAPI
function createPromise(arg)
{
return new Promise(arg);
}
function check_npapi_plugin (){
try {
var oAbout = CreateObject("CAdESCOM.About");
plugin_loaded();
}
catch (err) {
document.getElementById("cadesplugin_object").style.display = 'none';
// Объект создать не удалось, проверим, установлен ли
// вообще плагин. Такая возможность есть не во всех браузерах
var mimetype = navigator.mimeTypes["application/x-cades"];
if (mimetype) {
var plugin = mimetype.enabledPlugin;
if (plugin) {
plugin_loaded_error("Плагин загружен, но не создаются обьекты");
}else
{
plugin_loaded_error("Ошибка при загрузке плагина");
}
}else
{
plugin_loaded_error("Плагин недоступен");
}
}
}
//Проверяем работает ли плагин
function check_plugin_working()
{
var div = document.createElement("div");
div.innerHTML = "<!--[if lt IE 9]><i></i><![endif]-->";
var isIeLessThan9 = (div.getElementsByTagName("i").length === 1);
if (isIeLessThan9) {
plugin_loaded_error("Internet Explorer версии 8 и ниже не поддерживается");
return;
}
if(isNativeMessageSupported())
{
load_extension();
}else if(!canPromise) {
window.addEventListener("message", function (event){
if (event.data !== "cadesplugin_echo_request")
return;
load_npapi_plugin();
check_npapi_plugin();
},
false);
}else
{
if(document.readyState === "complete"){
load_npapi_plugin();
check_npapi_plugin();
} else {
window.addEventListener("load", function (event) {
load_npapi_plugin();
check_npapi_plugin();
}, false);
}
}
}
function set_pluginObject(obj)
{
pluginObject = obj;
}
function is_capilite_enabled()
{
if ((typeof (cadesplugin.EnableInternalCSP) !== 'undefined') && cadesplugin.EnableInternalCSP)
return true;
return false;
};
//Export
cadesplugin.JSModuleVersion = "2.1.2";
cadesplugin.async_spawn = async_spawn;
cadesplugin.set = set_pluginObject;
cadesplugin.set_log_level = set_log_level;
cadesplugin.getLastError = getLastError;
cadesplugin.is_capilite_enabled = is_capilite_enabled;
if(isNativeMessageSupported())
{
cadesplugin.CreateObjectAsync = CreateObjectAsync;
cadesplugin.ReleasePluginObjects = ReleasePluginObjects;
}
if(!isNativeMessageSupported())
{
cadesplugin.CreateObject = CreateObject;
}
if(window.cadesplugin_load_timeout)
{
setTimeout(check_load_timeout, window.cadesplugin_load_timeout);
}
else
{
setTimeout(check_load_timeout, 20000);
}
set_constantValues();
cadesplugin.current_log_level = cadesplugin.LOG_LEVEL_ERROR;
window.cadesplugin = cadesplugin;
check_plugin_working();
}());

View File

@ -122,6 +122,7 @@ export const defaultState = {
individual_executive: "",
other_control: "",
nko: false,
accept: false,
},
legal_address: {
title: "",
@ -198,6 +199,7 @@ export const defaultState = {
},
signatory_person_files: [],
founded_persons_template: {
signatory_id: null,
lastname: "",
firstname: "",
middlename: "",
@ -260,6 +262,17 @@ export const defaultState = {
}
}
},
non_profit: {
fin_source_business: false,
fin_source_donate: false,
fin_source_fees: false,
fin_source_another: false,
fin_source_another_description: "",
foreign_payers: false,
fin_goals_cars: "",
fin_goals_trucks: "",
fin_goals_special: "",
},
},
};

View File

@ -48,7 +48,7 @@ const makeStore = (context) =>
const persistConfig = {
key: 'lkevoleasing',
whitelist: [ 'auth', 'user', 'company', 'events', 'companies', 'contracts_info', 'contract_events', 'contract_fines', 'questionnaire'],
whitelist: [ 'auth', 'user', 'company', 'events', 'companies', 'contracts_info', 'contract_events', 'contract_fines', ],
storage
};

View File

@ -0,0 +1,401 @@
import moment from "moment";
export function isPluginCryptoProInstalled()
{
return new Promise(function(resolve, reject)
{
console.log("isPluginCryptoProInstalled");
console.log("window.cadesplugin", window.cadesplugin);
window.cadesplugin.async_spawn(function *(args)
{
try {
yield window.cadesplugin
} catch (e) {
reject({message: e})
return;
}
resolve();
});
});
}
/**
* Получение списка сертификатов пользователя
* @returns {*}
*/
export function getCertificates()
{
return new Promise(function(resolve, reject)
{
window.cadesplugin.async_spawn(function *(args)
{
try {
var store = yield window.cadesplugin.CreateObjectAsync("CAdESCOM.Store");
yield store.Open(
window.cadesplugin.CAPICOM_CURRENT_USER_STORE,
window.cadesplugin.CAPICOM_MY_STORE,
window.cadesplugin.CAPICOM_STORE_OPEN_MAXIMUM_ALLOWED
);
var certificates = yield store.Certificates;
var certificatesCount = yield certificates.Count
var data = [];
for (let i = 0; i < certificatesCount; i++)
{
let certificate = yield certificates.Item(i+1)
data.push({
index: i+1,
certificate: certificate,
info: {
subjectName: parseSubjectNameToObj(yield certificate.SubjectName)['name'],
subjectFields: parseSubjectNameToArray(yield certificate.SubjectName),
issuerName: yield certificate.IssuerName,
validFromDate: yield certificate.ValidFromDate,
validToDate: yield certificate.ValidToDate
}
});
}
store.Close();
resolve(data);
} catch (e) {
reject(e);
}
});
});
}
/**
* Парсинг данных владельца сертификата
* @param string - Строка с информацией о владельце
* @returns {[{}]}
*
* example:
* input: 'C=RU, S="Магаданская область", L=Магадан, O="OOO ""Несуществующая компания""", OU=Подразделение, CN=Иван Иванов, E=ivan@mail.ru'
* output: [{
* fieldName: 'Имя',
* value: 'Иван Иванов'
* }, {
* fieldName: 'Электронная почта',
* value: 'ivan@mail.ru'
* }, {
* fieldName: 'Страна',
* value: 'RU'
* }, {
* fieldName: 'Область, шташ',
* value: '"Магаданская область"'
* }, {
* fieldName: 'Город',
* value: 'Магадан'
* }, {
* fieldName: 'Организация',
* value: 'OOO ""Несуществующая компания""'
* }, {
* fieldName: 'Подраздиление',
* value: 'Подразделение'
* }]
*
*/
function parseSubjectNameToArray(string)
{
let outputData = [];
let fieldsNames = {
'CN': 'Имя',
'E': 'Электронная почта',
'C': 'Страна',
'S': 'Область, штат',
'L': 'Город',
'O': 'Организация',
'OU': 'Подраздиление'
};
// 'C=RU, S="Область, штат"' -> [['C', 'RU'], ['S', '"Область, штат"']]
let reg = RegExp('[а-яА-Я\\w]*=.*?((?=, [а-яА-Я\\w]+=)|$)','g');
let fields = string.matchAll(reg);
fields = Array.from(fields, x => x[0]);
fields = fields.map(field => field.split('='));
fields.forEach(field => {
if (field[0] in fieldsNames)
{
let fieldName = fieldsNames[field[0]];
outputData.push({
fieldName: fieldName,
value: field[1]
});
}
});
return outputData;
}
/**
* Парсинг данных владельца сертификата
* @param string - Строка с информацией о владельце
* @returns {{}}
*
* example:
* input: 'C=RU, S="Магаданская область", L=Магадан, O="OOO ""Несуществующая компания""", OU=Подразделение, CN=Иван Иванов, E=ivan@mail.ru'
* output: {
* name: 'Иван Иванов',
* email: 'ivan@mail.ru',
* country: 'RU',
* state: '"Магаданская область"',
* city: 'Магадан',
* organization: '"OOO ""Несуществующая компания"""',
* subdivision: 'Подразделение'
* }
*
*/
function parseSubjectNameToObj(string)
{
let outputData = [];
let fieldsNames = {
'CN': 'name',
'E': 'email',
'C': 'country',
'S': 'state',
'L': 'city',
'O': 'organization',
'OU': 'subdivision'
};
// 'C=RU, S="Область, штат"' -> [['C', 'RU'], ['S', '"Область, штат"']]
let reg = RegExp('[а-яА-Я\\w]*=.*?((?=, [а-яА-Я\\w]+=)|$)','g');
let fields = string.matchAll(reg);
fields = Array.from(fields, x => x[0]);
fields = fields.map(field => field.split('='));
fields.forEach(field => {
if (field[0] in fieldsNames)
{
let fieldName = fieldsNames[field[0]];
outputData[fieldName] = field[1];
}
});
return outputData;
}
/**
* Подпись данных
* @param dataToSign {String} - Данные для подписи
* @param certificate - Сертификат подписи
*
* @param returnObj - RETURN_DATA | RETURN_SIGNATURE
* RETURN_SIGNED_DATA - Возвращает подписанный файл
* RETURN_SIGNATURE - Возвращает подпись
*
* @param signingType - SIGN_ALL_DATA | ADD_SIGNATURE_TO_DATA
* SIGN_ALL_DATA - Подписать данные целиком
* ADD_SIGNATURE_TO_DATA - Добавить подпись к уже подписанным данным
*
* @returns {*}
*/
export function signData(dataToSign, certificate, returnObj, signingType)
{
return new Promise(function(resolve, reject)
{
window.cadesplugin.async_spawn(function *(args)
{
try {
var oSigner = yield window.cadesplugin.CreateObjectAsync("CAdESCOM.CPSigner");
yield oSigner.propset_Certificate(certificate);
var oSignedData = yield window.cadesplugin.CreateObjectAsync("CAdESCOM.CadesSignedData");
var CADES_BES = 1;
yield oSignedData.propset_ContentEncoding(1); //CADESCOM_BASE64_TO_BINARY
yield oSignedData.propset_Content(dataToSign);
yield oSigner.propset_Options(window.cadesplugin.CAPICOM_CERTIFICATE_INCLUDE_END_ENTITY_ONLY);
let returnObjFlags = {
'RETURN_SIGNED_DATA': false,
'RETURN_SIGNATURE': true
};
let returnObjFlag = returnObjFlags[returnObj];
if (returnObjFlag === undefined)
{
reject("Некорректное значения параметра returnObj. Данный параметр может принимать значения RETURN_SIGNED_DATA или RETURN_SIGNATURE");
return;
}
let signedData = '';
if (signingType === 'SIGN_ALL_DATA')
{
signedData = yield oSignedData.SignCades(oSigner, CADES_BES, returnObjFlag);
}
else if (signingType === 'ADD_SIGNATURE_TO_DATA')
{
yield oSignedData.VerifyCades(dataToSign, CADES_BES);
signedData = yield oSignedData.CoSignCades(oSigner, CADES_BES, returnObjFlag);
}
else
{
reject('Incorrect signature type');
}
resolve(signedData);
} catch (e)
{
console.error(e);
reject(e);
}
});
});
}
/**
* Проверка наличия у данных подписи
* @param data
* @returns {*} - true | false
* true - данные подписаны
* false - данные не подписаны
*/
export function hasDataSignature(data)
{
return new Promise((resolve, reject) =>
{
window.cadesplugin.async_spawn(function *(args)
{
try
{
var oSignedData = yield window.cadesplugin.CreateObjectAsync("CAdESCOM.CadesSignedData");
try
{
let CADES_BES = 1;
yield oSignedData.VerifyCades(data, CADES_BES);
resolve(true);
}
catch (e2)
{
resolve(false);
}
}
catch (e)
{
reject(e);
}
});
});
}
/**
* Подписание файла
* @param file - Файл для подписи
* @param certificate - Сертификат подписи
*
* @param returnObj - RETURN_DATA | RETURN_SIGNATURE
* RETURN_SIGNED_DATA - Возвращает подписанный файл
* RETURN_SIGNATURE - Возвращает подпись
*
* @returns Подписанный файл
*/
export function signing(file, certificate, returnObj)
{
return new Promise((resolve, reject) =>
{
// Подписываем файл, у которого нет подписи
let handlerWithoutSig = (file) =>
{
return new Promise((resolve, reject) =>
{
var oFReader = new FileReader();
oFReader.readAsDataURL(file);
oFReader.onload = (oFREvent) =>
{
var header = ";base64,";
var sFileData = oFREvent.target.result;
var sBase64Data = sFileData.substr(sFileData.indexOf(header) + header.length);
signData(sBase64Data, certificate, returnObj, 'SIGN_ALL_DATA').then(resolve, reject);
}
});
}
// Подписываем файл, у которого уже есть подпись
let handlerWithSig = (file) =>
{
return new Promise((resolve, reject) =>
{
file.text()
.then(text =>
{
signData(text, certificate, returnObj, 'ADD_SIGNATURE_TO_DATA').then(resolve, reject);
})
.catch(reject);
});
}
file.text()
.then(text =>
{
return hasDataSignature(text)
})
.then(result =>
{
if (result)
{
return handlerWithSig(file)
}
else
{
return handlerWithoutSig(file)
}
})
.then(resolve).catch(reject);
});
}
/**
* Подпись файла и вернуть подписанный файл
* @param file - Файл для подписи
* @param certificate - Сертификат подписи
* @returns Подписанный файл
*/
export function signFile(file, certificate)
{
return new Promise((resolve, reject) =>
{
signing(file, certificate, 'RETURN_SIGNED_DATA')
.then(signedData =>
{
let filename = file.name + '.sig';
let signedFile = new File([signedData], filename);
resolve(signedFile);
})
.catch(reject);
});
}
/**
* Подписать файл и вернуть файл с данными подписи
* @param file - Файл для подписи
* @param certificate - Сертификат подписи
* @returns Подписанный файл
*/
export function generateSignature(file, certificate)
{
return new Promise((resolve, reject) =>
{
signing(file, certificate, 'RETURN_SIGNATURE')
.then(signedData =>
{
let filename = file.name + '.sig';
let signedFile = new File([signedData], filename);
resolve(signedFile);
})
.catch(reject);
});
}

View File

@ -249,6 +249,11 @@
resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45"
integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==
"@mpth/react-no-ssr@^1.0.1":
version "1.0.1"
resolved "https://registry.yarnpkg.com/@mpth/react-no-ssr/-/react-no-ssr-1.0.1.tgz#4840b157d38b51ef3014959e9de6420e5d788695"
integrity sha512-roOiU0MFvoB75kESxKI+w2QVK6DGQLFOPOWzcnFfaVJCuvrpbUf0AgppTtchV/hEVk/ltXpe3lgrQybQpkGO2g==
"@nano-sql/core@^2.3.7":
version "2.3.7"
resolved "https://registry.yarnpkg.com/@nano-sql/core/-/core-2.3.7.tgz#df4ea7916272cab7c4a4bf4294197dd64637fe59"
@ -687,14 +692,6 @@ babel-plugin-macros@^3.1.0:
cosmiconfig "^7.0.0"
resolve "^1.19.0"
babel-runtime@6.x.x:
version "6.26.0"
resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe"
integrity sha512-ITKNuq2wKlW1fJg9sSW52eepoYgZBggvOAHC0u/CYu/qxQ9EVzThCgR69BnSXLHjy2f7SY5zaQ4yt7H9ZVxY2g==
dependencies:
core-js "^2.4.0"
regenerator-runtime "^0.11.0"
balanced-match@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
@ -1076,11 +1073,6 @@ core-js-pure@^3.20.2:
resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.24.1.tgz#8839dde5da545521bf282feb7dc6d0b425f39fd3"
integrity sha512-r1nJk41QLLPyozHUUPmILCEMtMw24NG4oWK6RbsDdjzQgg9ZvrUsPBj1MnG0wXXp1DCDU6j+wUvEmBSrtRbLXg==
core-js@^2.4.0:
version "2.6.12"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.12.tgz#d9333dfa7b065e347cc5682219d6f690859cc2ec"
integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==
core-util-is@~1.0.0:
version "1.0.3"
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85"
@ -3320,13 +3312,6 @@ react-lifecycles-compat@^3.0.4:
resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362"
integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==
react-no-ssr@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/react-no-ssr/-/react-no-ssr-1.1.0.tgz#313b48d2e26020f969ed98e472f10481604e3cc8"
integrity sha512-3td8iPIEFKWXOJ3Ar5xURvZAsv/aIlngJLBH6fP5QC3WhsfuO2pn7WQR0ZlkTE0puWCL0RDEvXtOfAg4qMp+xA==
dependencies:
babel-runtime "6.x.x"
react-redux@^7.2.6:
version "7.2.8"
resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-7.2.8.tgz#a894068315e65de5b1b68899f9c6ee0923dd28de"
@ -3474,11 +3459,6 @@ redux@^4.0.0, redux@^4.1.2:
dependencies:
"@babel/runtime" "^7.9.2"
regenerator-runtime@^0.11.0:
version "0.11.1"
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9"
integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==
regenerator-runtime@^0.13.4:
version "0.13.9"
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52"