merge branch migration/agents

This commit is contained in:
Chika 2022-11-02 21:36:48 +03:00
parent 34bab4f715
commit 391f9039f7
58 changed files with 2460 additions and 1098 deletions

View File

@ -74,7 +74,10 @@
"ignore": ["^.*.(jsx|tsx)$"]
}
],
"import/no-unresolved": "warn"
"import/no-unresolved": "warn",
"implicit-arrow-linebreak": "warn",
"operator-linebreak": "warn",
"function-paren-newline": "warn"
},
"overrides": [
// Only uses Testing Library lint rules in test files

View File

@ -14,7 +14,7 @@ function PaymentsParams() {
const [selectSeasonType, tbxParmentsDecreasePercent, selectHighSeasonStart] = renderedElements;
const { $calculation } = useStore();
const graphType = $calculation.getElementValue('radioGraphType');
const graphType = $calculation.element('radioGraphType').getValue();
switch (graphType) {
case 100_000_000:

View File

@ -14,7 +14,7 @@ const QUERY_GET_CURRENCY_SYMBOL = gql`
const CurrencyAddon = observer(() => {
const { $calculation } = useStore();
const currencyid = $calculation.$values.getValue('supplierCurrency');
const currencyid = $calculation.element('selectSupplierCurrency').getValue();
const { data } = useQuery<
CRMTypes.GetCurrencySymbolQuery,

View File

@ -180,7 +180,7 @@ const overrideRender: Partial<Record<keyof typeof map, RenderProps>> = {
const Title = observer(() => {
const { $calculation } = useStore();
const graphType = $calculation.getElementValue('radioGraphType');
const graphType = $calculation.element('radioGraphType').getValue();
switch (graphType) {
case 100_000_001:

View File

@ -3,7 +3,6 @@ import { observer } from 'mobx-react-lite';
import { useStore } from 'stores/hooks';
import styled from 'styled-components';
import { Box, Flex } from 'UIKit/grid';
import titles from '../Calculation/config/elements-titles';
const Bold = styled.span`
font-weight: bold;
@ -19,14 +18,19 @@ function Message(title, text) {
);
}
const AlertWrapper = styled(Box)`
margin: 0 0 5px 0;
`;
function getElementsErrors($calculation) {
const { elementsErrors } = $calculation.$validation;
const errors = Object.keys(elementsErrors).map((elementName) => {
const elementErrors = elementsErrors[elementName];
const elementTitle = titles[elementName];
const errors = Object.values($calculation.$validation).map((validation) => {
const elementErrors = validation.getMessages();
const elementTitle = validation.params.err_title;
return elementErrors.map((error) => (
<Alert key={error.name} type="error" showIcon message={Message(elementTitle, error.text)} />
<AlertWrapper>
<Alert key={error.name} type="error" showIcon message={Message(elementTitle, error)} />
</AlertWrapper>
));
});
@ -51,14 +55,22 @@ function getInsuranceTableErrors($tables) {
const Errors = observer(() => {
const { $calculation, $tables } = useStore();
const hasElementsErrors = Object.values($calculation.$validation).some(
(validation) => validation.hasErrors
);
const hasPaymentsErrors = $tables.payments.validation.hasErrors;
const hasInsuranceErrors = $tables.insurance.validation.hasErrors;
if (!hasElementsErrors && !hasPaymentsErrors && !hasInsuranceErrors) {
return <Alert type="success" showIcon message="Ошибок нет 🙂" />;
}
const elementsErrors = getElementsErrors($calculation);
const paymentsErrors = getPaymentsTableErrors($tables);
const insuranceErrors = getInsuranceTableErrors($tables);
const errors = [...elementsErrors, ...paymentsErrors, ...insuranceErrors];
if (errors.length === 0) return <Alert type="success" showIcon message="Ошибок нет 🙂" />;
return <Flex flexDirection="column">{errors}</Flex>;
});

2
Elements/message.js Normal file
View File

@ -0,0 +1,2 @@
/* eslint-disable no-restricted-exports */
export { message as default } from 'antd';

View File

@ -1,10 +1,10 @@
import type { CalculationStatuses } from 'stores/calculation/statuses/types';
const defaultStatuses: CalculationStatuses = {
selectIndAgent: 'Disabled',
selectCalcBroker: 'Disabled',
selectCalcFinDepartment: 'Disabled',
selectCalcDoubleAgent: 'Disabled',
selectIndAgent: 'Default',
selectCalcBroker: 'Default',
selectCalcFinDepartment: 'Default',
selectCalcDoubleAgent: 'Default',
selectClientType: 'Disabled',
tbxImporterRewardRub: 'Disabled',
tbxImporterRewardPerc: 'Disabled',
@ -71,13 +71,13 @@ const defaultStatuses: CalculationStatuses = {
selectDealerBrokerRewardCondition: 'Default',
tbxDealerBrokerRewardSumm: 'Disabled',
selectIndAgentRewardCondition: 'Default',
tbxIndAgentRewardSumm: 'Default',
tbxIndAgentRewardSumm: 'Disabled',
selectCalcDoubleAgentRewardCondition: 'Default',
tbxCalcDoubleAgentRewardSumm: 'Default',
tbxCalcDoubleAgentRewardSumm: 'Disabled',
selectCalcBrokerRewardCondition: 'Default',
tbxCalcBrokerRewardSum: 'Default',
tbxCalcBrokerRewardSum: 'Disabled',
selectFinDepartmentRewardCondtion: 'Default',
tbxFinDepartmentRewardSumm: 'Default',
tbxFinDepartmentRewardSumm: 'Disabled',
selectGPSBrand: 'Default',
selectGPSModel: 'Default',
selectRegionRegistration: 'Default',

144
config/schema/values.ts Normal file
View File

@ -0,0 +1,144 @@
import { z } from 'zod';
const ValuesSchema = z.object({
lead: z.string().nullable(),
opportunity: z.string().nullable(),
quote: z.string().nullable(),
recalcWithRevision: z.boolean(),
product: z.string().nullable(),
clientRisk: z.string().nullable(),
clientType: z.string().nullable(),
leaseObjectPrice: z.number(),
supplierCurrency: z.string().nullable(),
supplierDiscountRub: z.number(),
supplierDiscountPerc: z.number(),
leasingPeriod: z.number(),
firstPaymentPerc: z.number(),
firstPaymentRub: z.number(),
lastPaymentPerc: z.number(),
lastPaymentRub: z.number(),
lastPaymentRule: z.number().nullable(),
importProgram: z.string().nullable(),
importProgramSum: z.number(),
addEquipmentPrice: z.number(),
redemptionPaymentSum: z.number(),
balanceHolder: z.number().nullable(),
graphType: z.number().nullable(),
parmentsDecreasePercent: z.number(),
seasonType: z.number().nullable(),
highSeasonStart: z.number().nullable(),
comissionPerc: z.number(),
comissionRub: z.number(),
saleBonus: z.number(),
IRR_Perc: z.number(),
leaseObjectType: z.string().nullable(),
deliveryTime: z.number().nullable(),
leaseObjectCount: z.number(),
withTrailer: z.boolean(),
leaseObjectUsed: z.boolean(),
maxMass: z.number(),
countSeats: z.number(),
maxSpeed: z.number(),
brand: z.string().nullable(),
model: z.string().nullable(),
configuration: z.string().nullable(),
leaseObjectYear: z.number(),
engineType: z.number().nullable(),
leaseObjectCategory: z.number().nullable(),
leaseObjectMotorPower: z.number(),
engineVolume: z.number(),
leaseObjectUseFor: z.number().nullable(),
dealer: z.string().nullable(),
dealerPerson: z.string().nullable(),
dealerRewardCondition: z.string().nullable(),
dealerRewardSumm: z.number(),
dealerBroker: z.string().nullable(),
dealerBrokerRewardCondition: z.string().nullable(),
dealerBrokerRewardSumm: z.number(),
indAgent: z.string().nullable(),
indAgentRewardCondition: z.string().nullable(),
indAgentRewardSumm: z.number(),
calcDoubleAgent: z.string().nullable(),
calcDoubleAgentRewardCondition: z.string().nullable(),
calcDoubleAgentRewardSumm: z.number(),
calcBroker: z.string().nullable(),
calcBrokerRewardCondition: z.string().nullable(),
calcBrokerRewardSum: z.number(),
calcFinDepartment: z.string().nullable(),
finDepartmentRewardCondtion: z.string().nullable(),
finDepartmentRewardSumm: z.number(),
GPSBrand: z.string().nullable(),
GPSModel: z.string().nullable(),
regionRegistration: z.string().nullable(),
townRegistration: z.string().nullable(),
infuranceOPF: z.number().nullable(),
insKaskoType: z.number().nullable(),
insDecentral: z.boolean(),
insFranchise: z.number(),
insUnlimitDrivers: z.boolean(),
insAgeDrivers: z.number(),
insExpDrivers: z.number(),
INNForCalc: z.number(),
lastPaymentRedemption: z.boolean(),
priceWithDiscount: z.boolean(),
fullPriceWithDiscount: z.boolean(),
costIncrease: z.boolean(),
insurance: z.boolean(),
registrationQuote: z.boolean(),
technicalCardQuote: z.boolean(),
NSIB: z.boolean(),
quoteName: z.string().nullable(),
quoteContactGender: z.number().nullable(),
quoteRedemptionGraph: z.boolean(),
showFinGAP: z.boolean(),
tarif: z.string().nullable(),
creditRate: z.number(),
rate: z.string().nullable(),
requirementTelematic: z.number().nullable(),
minPriceChange: z.number(),
maxPriceChange: z.number(),
importerRewardPerc: z.number(),
importerRewardRub: z.number(),
disableChecks: z.boolean(),
registration: z.string().nullable(),
insNSIB: z.string().nullable(),
technicalCard: z.string().nullable(),
telematic: z.string().nullable(),
tracker: z.string().nullable(),
mileage: z.number(),
calcType: z.number().nullable(),
totalPayments: z.number(),
objectRegistration: z.number().nullable(),
objectRegionRegistration: z.string().nullable(),
vehicleTaxInYear: z.number(),
vehicleTaxInLeasingPeriod: z.number(),
objectCategoryTax: z.number().nullable(),
objectTypeTax: z.number().nullable(),
typePTS: z.number().nullable(),
legalClientRegion: z.string().nullable(),
legalClientTown: z.string().nullable(),
subsidy: z.string().nullable(),
fuelCard: z.string().nullable(),
leaseObjectPriceWthtVAT: z.number(),
VATInLeaseObjectPrice: z.number(),
engineHours: z.number(),
bonusCoefficient: z.number(),
/** Link Values */
kpUrl: z.string().nullable(),
leadUrl: z.string().nullable(),
opportunityUrl: z.string().nullable(),
quoteUrl: z.string().nullable(),
/** Readonly Values */
leaseObjectRiskName: z.string().nullable(),
insKaskoPriceLeasePeriod: z.number(),
irrInfo: z.string().nullable(),
registrationDescription: z.string().nullable(),
depreciationGroup: z.string().nullable(),
subsidySum: z.number(),
plPriceRub: z.number(),
discountRub: z.number(),
});
export default ValuesSchema;

View File

@ -122,70 +122,6 @@ export type GetCurrencySymbolQueryVariables = Exact<{
export type GetCurrencySymbolQuery = { __typename?: 'Query', transactioncurrency?: { __typename?: 'transactioncurrency', currencysymbol?: string | null } | null };
export type GetAgentQueryVariables = Exact<{
agentid: Scalars['Uuid'];
}>;
export type GetAgentQuery = { __typename?: 'Query', agent?: { __typename?: 'account', label?: string | null, value?: any | null } | null };
export type GetAgentAccountIdFromLeadQueryVariables = Exact<{
leadid: Scalars['Uuid'];
}>;
export type GetAgentAccountIdFromLeadQuery = { __typename?: 'Query', lead?: { __typename?: 'lead', agentid?: any | null } | null };
export type GetDoubleAgentAccountIdQueryVariables = Exact<{
leadid: Scalars['Uuid'];
}>;
export type GetDoubleAgentAccountIdQuery = { __typename?: 'Query', lead?: { __typename?: 'lead', agentid?: any | null } | null };
export type GetBrokerAccountIdQueryVariables = Exact<{
leadid: Scalars['Uuid'];
}>;
export type GetBrokerAccountIdQuery = { __typename?: 'Query', lead?: { __typename?: 'lead', agentid?: any | null } | null };
export type GetFinDepartmentAccountIdQueryVariables = Exact<{
leadid: Scalars['Uuid'];
}>;
export type GetFinDepartmentAccountIdQuery = { __typename?: 'Query', lead?: { __typename?: 'lead', agentid?: any | null } | null };
export type GetDealerPersonQueryVariables = Exact<{
dealerId: Scalars['Uuid'];
}>;
export type GetDealerPersonQuery = { __typename?: 'Query', salon_providers?: Array<{ __typename?: 'account', label?: string | null, value?: any | null } | null> | null };
export type GetBrokerAccountIdFromDealerQueryVariables = Exact<{
dealerId: Scalars['Uuid'];
}>;
export type GetBrokerAccountIdFromDealerQuery = { __typename?: 'Query', dealer?: { __typename?: 'account', evo_broker_accountid?: any | null } | null };
export type GetRewardConditionsQueryVariables = Exact<{
agentid: Scalars['Uuid'];
currentDate?: InputMaybe<Scalars['DateTime']>;
}>;
export type GetRewardConditionsQuery = { __typename?: 'Query', evo_reward_conditions?: Array<{ __typename?: 'evo_reward_condition', evo_reward_summ?: any | null, label?: string | null, value?: any | null } | null> | null };
export type GetRewardSummQueryVariables = Exact<{
conditionId: Scalars['Uuid'];
}>;
export type GetRewardSummQuery = { __typename?: 'Query', evo_reward_condition?: { __typename?: 'evo_reward_condition', evo_reward_summ?: any | null } | null };
export type GetFinGapAddProductTypesQueryVariables = Exact<{
currentDate?: InputMaybe<Scalars['DateTime']>;
}>;
@ -301,3 +237,102 @@ export type GetCurrencyIsoCodeQueryVariables = Exact<{
export type GetCurrencyIsoCodeQuery = { __typename?: 'Query', transactioncurrency?: { __typename?: 'transactioncurrency', isocurrencycode?: string | null } | null };
export type GetRewardRulesQueryVariables = Exact<{
conditionId: Scalars['Uuid'];
}>;
export type GetRewardRulesQuery = { __typename?: 'Query', evo_reward_condition?: { __typename?: 'evo_reward_condition', evo_calc_reward_rules?: number | null } | null };
export type GetAgentsDataFromQuoteQueryVariables = Exact<{
quoteId: Scalars['Uuid'];
}>;
export type GetAgentsDataFromQuoteQuery = { __typename?: 'Query', quote?: { __typename?: 'quote', evo_supplier_accountid?: any | null, evo_dealer_person_accountid?: any | null, evo_dealer_reward_conditionid?: any | null, evo_dealer_reward_total?: any | null, evo_dealer_reward_summ?: any | null, evo_dealer_broker_accountid?: any | null, evo_dealer_broker_reward_conditionid?: any | null, evo_dealer_broker_reward_total?: any | null, evo_dealer_broker_reward_summ?: any | null, evo_agent_accountid?: any | null, evo_agent_reward_conditionid?: any | null, evo_agent_reward_total?: any | null, evo_agent_reward_summ?: any | null, evo_double_agent_accountid?: any | null, evo_double_agent_reward_conditionid?: any | null, evo_double_agent_reward_total?: any | null, evo_double_agent_reward_summ?: any | null, evo_broker_accountid?: any | null, evo_broker_reward_conditionid?: any | null, evo_broker_reward_total?: any | null, evo_broker_reward_summ?: any | null, evo_fin_department_accountid?: any | null, evo_fin_department_reward_conditionid?: any | null, evo_fin_department_reward_total?: any | null, evo_fin_department_reward_summ?: any | null } | null };
export type GetRewardConditionsQueryVariables = Exact<{
agentid: Scalars['Uuid'];
currentDate?: InputMaybe<Scalars['DateTime']>;
}>;
export type GetRewardConditionsQuery = { __typename?: 'Query', evo_reward_conditions?: Array<{ __typename?: 'evo_reward_condition', evo_reward_summ?: any | null, label?: string | null, value?: any | null } | null> | null };
export type GetRewardSummQueryVariables = Exact<{
conditionId: Scalars['Uuid'];
}>;
export type GetRewardSummQuery = { __typename?: 'Query', evo_reward_condition?: { __typename?: 'evo_reward_condition', evo_reward_summ?: any | null } | null };
export type GetRewardConditionQueryVariables = Exact<{
conditionId: Scalars['Uuid'];
}>;
export type GetRewardConditionQuery = { __typename?: 'Query', evo_reward_condition?: { __typename?: 'evo_reward_condition', evo_reward_summ?: any | null, evo_reduce_reward?: boolean | null, evo_min_reward_summ?: any | null } | null };
export type GetAgentAccountIdFromLeadQueryVariables = Exact<{
leadid: Scalars['Uuid'];
}>;
export type GetAgentAccountIdFromLeadQuery = { __typename?: 'Query', lead?: { __typename?: 'lead', agentid?: any | null } | null };
export type GetDoubleAgentAccountIdQueryVariables = Exact<{
leadid: Scalars['Uuid'];
}>;
export type GetDoubleAgentAccountIdQuery = { __typename?: 'Query', lead?: { __typename?: 'lead', agentid?: any | null } | null };
export type GetBrokerAccountIdQueryVariables = Exact<{
leadid: Scalars['Uuid'];
}>;
export type GetBrokerAccountIdQuery = { __typename?: 'Query', lead?: { __typename?: 'lead', agentid?: any | null } | null };
export type GetFinDepartmentAccountIdQueryVariables = Exact<{
leadid: Scalars['Uuid'];
}>;
export type GetFinDepartmentAccountIdQuery = { __typename?: 'Query', lead?: { __typename?: 'lead', agentid?: any | null } | null };
export type GetAgentQueryVariables = Exact<{
agentid: Scalars['Uuid'];
}>;
export type GetAgentQuery = { __typename?: 'Query', agent?: { __typename?: 'account', label?: string | null, value?: any | null } | null };
export type GetRewardWithoutOtherAgentQueryVariables = Exact<{
conditionId: Scalars['Uuid'];
}>;
export type GetRewardWithoutOtherAgentQuery = { __typename?: 'Query', evo_reward_condition?: { __typename?: 'evo_reward_condition', evo_agency_agreementidData?: { __typename?: 'evo_agency_agreement', evo_reward_without_other_agent?: boolean | null } | null } | null };
export type GetDealerReturnLeasingQueryVariables = Exact<{
dealerId: Scalars['Uuid'];
}>;
export type GetDealerReturnLeasingQuery = { __typename?: 'Query', dealer?: { __typename?: 'account', evo_return_leasing_dealer?: boolean | null } | null };
export type GetDealerPersonQueryVariables = Exact<{
dealerId: Scalars['Uuid'];
}>;
export type GetDealerPersonQuery = { __typename?: 'Query', salon_providers?: Array<{ __typename?: 'account', evo_inn?: string | null, evo_kpp?: string | null, label?: string | null, value?: any | null } | null> | null };
export type GetBrokerAccountIdFromDealerQueryVariables = Exact<{
dealerId: Scalars['Uuid'];
}>;
export type GetBrokerAccountIdFromDealerQuery = { __typename?: 'Query', dealer?: { __typename?: 'account', evo_broker_accountid?: any | null } | null };

View File

@ -16,7 +16,6 @@ const nextConfig = {
compiler: {
styledComponents: true,
},
pageExtensions: ['tsx', 'jsx'],
rewrites:
process.env.NODE_ENV === 'development' &&
async function rewrites() {

View File

@ -21,7 +21,11 @@
"@ant-design/icons": "^4.7.0",
"@apollo/client": "^3.7.0",
"@fontsource/montserrat": "^4.5.12",
"@tanstack/react-query": "^4.13.0",
"@tanstack/react-query": "^4.14.1",
"@trpc/client": "^10.0.0-rc.3",
"@trpc/next": "^10.0.0-rc.3",
"@trpc/react-query": "^10.0.0-rc.3",
"@trpc/server": "^10.0.0-rc.3",
"antd": "^4.21.3",
"axios": "^1.1.3",
"dayjs": "^1.11.2",
@ -40,7 +44,9 @@
"rebass": "^4.0.7",
"sharp": "^0.30.4",
"styled-components": "^5.3.5",
"use-debounce": "^8.0.1"
"superjson": "^1.11.0",
"use-debounce": "^8.0.1",
"zod": "^3.19.1"
},
"devDependencies": {
"@graphql-codegen/cli": "2.12.0",

View File

@ -9,6 +9,7 @@ import 'normalize.css';
import { useMemo } from 'react';
import StoreProvider from 'stores/Provider';
import { ThemeProvider } from 'styled-components';
import { trpcClient } from 'trpc/client';
import { GlobalStyle } from 'UIKit/colors';
import theme from 'UIKit/theme';
import '../styles/fonts.css';
@ -51,4 +52,4 @@ function App({ Component, pageProps }) {
);
}
export default App;
export default trpcClient.withTRPC(App);

8
pages/api/trpc/[trpc].ts Normal file
View File

@ -0,0 +1,8 @@
import * as trpcNext from '@trpc/server/adapters/next';
import appRouter from 'trpc/routers';
export default trpcNext.createNextApiHandler({
router: appRouter,
// eslint-disable-next-line object-curly-newline
createContext: () => ({}),
});

View File

@ -11,6 +11,7 @@ import injectDefaultReactions from 'process/init/inject-reactions/default';
import { useEffect } from 'react';
import { useStore } from 'stores/hooks';
import styled from 'styled-components';
import { trpcPureClient } from 'trpc/client';
import { Box } from 'UIKit/grid';
import { min } from 'UIKit/mq';
@ -45,7 +46,7 @@ function Home() {
useEffect(() => {
getData(apolloClient, store);
injectDefaultReactions(store, apolloClient, queryClient);
injectDefaultReactions(store, apolloClient, queryClient, trpcPureClient);
}, []);
return (

View File

@ -1,292 +0,0 @@
/* eslint-disable @typescript-eslint/naming-convention */
import type { ApolloClient } from '@apollo/client';
import { gql } from '@apollo/client';
import dayjs from 'dayjs';
import utc from 'dayjs/plugin/utc';
import type * as CRMTypes from 'graphql/crm.types';
import { reaction } from 'mobx';
import type RootStore from 'stores/root';
import { normalizeOptions } from 'tools/entity';
import * as fillAgentsFromLead from '../lib/fill-agents-from-lead';
import { QUERY_GET_AGENT } from '../lib/query';
dayjs.extend(utc);
export default function commonReactions(store: RootStore, apolloClient: ApolloClient<object>) {
const { $calculation } = store;
/**
* Заполняем агентов из Интереса
*/
reaction(
() => $calculation.getElementValue('selectLead'),
(leadid) => {
fillAgentsFromLead.fillIndAgent(store, apolloClient, leadid);
fillAgentsFromLead.fillCalcDoubleAgent(store, apolloClient, leadid);
fillAgentsFromLead.fillCalcBroker(store, apolloClient, leadid);
fillAgentsFromLead.fillFinDepartment(store, apolloClient, leadid);
}
);
/**
* Заполняем selectDealerPerson
* На изменение Салон приобретения формируем список в поле ЮЛ поставщика - записи Контрагент,
* у которых статус = активный И Поставщик = Да И Тип поставщика = Юридическое лицо
* И связаны с карточкой Контрагент из поля "Салон приобретения" по связи Салон-ЮЛ
*/
const QUERY_GET_DEALER_PERSON = gql`
query GetDealerPerson($dealerId: Uuid!) {
salon_providers(statecode: 0, salonaccountid: $dealerId) {
label: name
value: accountid
}
}
`;
reaction(
() => $calculation.getElementValue('selectDealer'),
async (dealerId) => {
if (!dealerId) {
$calculation.resetElement('selectDealerPerson');
$calculation.resetElement('selectDealerBroker');
return;
}
const {
data: { salon_providers },
} = await apolloClient.query<
CRMTypes.GetDealerPersonQuery,
CRMTypes.GetDealerPersonQueryVariables
>({
query: QUERY_GET_DEALER_PERSON,
variables: {
dealerId,
},
});
if (salon_providers?.length) {
$calculation.setElementOptions('selectDealerPerson', normalizeOptions(salon_providers));
$calculation.setElementValue('selectDealerPerson', salon_providers[0]?.value);
}
}
);
/**
* Заполняем selectDealerBroker
*/
const QUERY_GET_BROKER_ACCOUNTID_FROM_DEALER = gql`
query GetBrokerAccountIdFromDealer($dealerId: Uuid!) {
dealer: account(accountid: $dealerId) {
evo_broker_accountid
}
}
`;
reaction(
() => $calculation.getElementValue('selectDealerPerson'),
async (dealerPersonId) => {
if (!dealerPersonId) {
return;
}
const {
data: { dealer },
} = await apolloClient.query<
CRMTypes.GetBrokerAccountIdFromDealerQuery,
CRMTypes.GetBrokerAccountIdFromDealerQueryVariables
>({
query: QUERY_GET_BROKER_ACCOUNTID_FROM_DEALER,
variables: {
dealerId: dealerPersonId,
},
});
if (dealer?.evo_broker_accountid) {
const {
data: { agent: dealerBroker },
} = await apolloClient.query<CRMTypes.GetAgentQuery, CRMTypes.GetAgentQueryVariables>({
query: QUERY_GET_AGENT,
variables: {
agentid: dealer?.evo_broker_accountid,
},
});
if (dealerBroker) {
$calculation.setElementOptions('selectDealerBroker', normalizeOptions([dealerBroker]));
$calculation.setElementValue('selectDealerBroker', dealerBroker.value);
}
} else {
$calculation.resetElement('selectDealerBroker');
}
}
);
/**
* Заполняем selectDealerRewardCondition
*/
const QUERY_GET_REWARD_CONDITIONS = gql`
query GetRewardConditions($agentid: Uuid!, $currentDate: DateTime) {
evo_reward_conditions(
evo_agent_accountid: $agentid
evo_datefrom_param: { lte: $currentDate }
evo_dateto_param: { gte: $currentDate }
statecode: 0
evo_agency_agreementid_param: { has: true }
) {
label: evo_name
value: evo_reward_conditionid
evo_reward_summ
}
}
`;
reaction(
() => $calculation.getElementValue('selectDealerPerson'),
async (dealerPersonId) => {
if (!dealerPersonId) {
$calculation.resetElement('selectDealerRewardCondition');
return;
}
const {
data: { evo_reward_conditions },
} = await apolloClient.query<
CRMTypes.GetRewardConditionsQuery,
CRMTypes.GetRewardConditionsQueryVariables
>({
query: QUERY_GET_REWARD_CONDITIONS,
variables: {
agentid: dealerPersonId,
currentDate: dayjs().toISOString(),
},
});
if (evo_reward_conditions?.length) {
$calculation.setElementOptions(
'selectDealerRewardCondition',
normalizeOptions(evo_reward_conditions)
);
}
}
);
const QUERY_GET_REWARD_SUMM = gql`
query GetRewardSumm($conditionId: Uuid!) {
evo_reward_condition(evo_reward_conditionid: $conditionId) {
evo_reward_summ
}
}
`;
reaction(
() => $calculation.getElementValue('selectDealerRewardCondition'),
async (rewardConditionId) => {
if (!rewardConditionId) {
$calculation.resetElement('tbxDealerRewardSumm');
return;
}
const {
data: { evo_reward_condition },
} = await apolloClient.query<
CRMTypes.GetRewardSummQuery,
CRMTypes.GetRewardSummQueryVariables
>({
query: QUERY_GET_REWARD_SUMM,
variables: {
conditionId: rewardConditionId,
},
});
$calculation.setElementValue('tbxDealerRewardSumm', evo_reward_condition?.evo_reward_summ);
$calculation.unblockElement('tbxDealerRewardSumm');
}
);
/**
* Заполняем selectDealerBrokerRewardCondition
*/
reaction(
() => $calculation.getElementValue('selectDealerBroker'),
async (dealerBrokerId) => {
if (!dealerBrokerId) {
$calculation.resetElement('selectDealerBrokerRewardCondition');
return;
}
const {
data: { evo_reward_conditions },
} = await apolloClient.query<
CRMTypes.GetRewardConditionsQuery,
CRMTypes.GetRewardConditionsQueryVariables
>({
query: QUERY_GET_REWARD_CONDITIONS,
variables: {
agentid: dealerBrokerId,
currentDate: dayjs().toISOString(),
},
});
if (evo_reward_conditions?.length) {
$calculation.setElementOptions(
'selectDealerBrokerRewardCondition',
normalizeOptions(evo_reward_conditions)
);
}
}
);
reaction(
() => $calculation.getElementValue('selectDealerBrokerRewardCondition'),
async (rewardConditionId) => {
if (!rewardConditionId) {
$calculation.resetElement('tbxDealerBrokerRewardSumm');
return;
}
const {
data: { evo_reward_condition },
} = await apolloClient.query<
CRMTypes.GetRewardSummQuery,
CRMTypes.GetRewardSummQueryVariables
>({
query: QUERY_GET_REWARD_SUMM,
variables: {
conditionId: rewardConditionId,
},
});
$calculation.setElementValue(
'tbxDealerBrokerRewardSumm',
evo_reward_condition?.evo_reward_summ
);
$calculation.unblockElement('tbxDealerBrokerRewardSumm');
}
);
reaction(
() => $calculation.getElementValue('selectDealerRewardCondition'),
(dealerRewardConditionId) => {
if (dealerRewardConditionId) {
$calculation.resetElementValue('selectDealerBroker');
}
}
);
reaction(
() => $calculation.getElementValue('selectDealerBrokerRewardCondition'),
(dealerBrokerRewardConditionId) => {
if (dealerBrokerRewardConditionId) {
$calculation.resetElementValue('selectDealerPerson');
}
}
);
}

View File

@ -1,2 +0,0 @@
/* eslint-disable import/prefer-default-export */
export { default as common } from './common';

View File

@ -6,7 +6,9 @@ export default function validationReactions(store: RootStore, apolloClient: Apol
const { $calculation, $tables } = store;
reaction(
() => {
const hasElementsErrors = $calculation.$validation.hasErrors;
const hasElementsErrors = Object.values($calculation.$validation).some(
(validation) => validation.hasErrors
);
const hasPaymentsErrors = $tables.payments.validation.hasErrors;
const hasInsuranceErrors = $tables.insurance.validation.hasErrors;
const hasFingapErrors = $tables.fingap.validation.hasErrors;
@ -15,11 +17,11 @@ export default function validationReactions(store: RootStore, apolloClient: Apol
},
(hasErrors) => {
if (hasErrors) {
$calculation.blockElement('btnCalculate');
$calculation.blockElement('btnCreateKP');
$calculation.$status.setStatus('btnCalculate', 'Disabled');
$calculation.$status.setStatus('btnCreateKP', 'Disabled');
} else {
$calculation.unblockElement('btnCalculate');
$calculation.unblockElement('btnCreateKP');
$calculation.$status.setStatus('btnCalculate', 'Default');
$calculation.$status.setStatus('btnCreateKP', 'Default');
}
},
{

View File

@ -53,7 +53,7 @@ export default function commonReactions(
reaction(
() => {
const finGAPInsuranceCompany = $tables.insurance.getRowValue('fingap', 'insuranceCompany');
const leasingPeriod = $calculation.getElementValue('tbxLeasingPeriod');
const leasingPeriod = $calculation.element('tbxLeasingPeriod').getValue();
return {
finGAPInsuranceCompany,
@ -127,8 +127,8 @@ export default function commonReactions(
const paymentsValues = toJS($tables.payments.values);
const plPriceRub = $calculation.$values.getValue('plPriceRub');
const discountRub = $calculation.$values.getValue('discountRub');
const firstPaymentRub = $calculation.getElementValue('tbxFirstPaymentRub');
const leasingPeriod = $calculation.getElementValue('tbxLeasingPeriod');
const firstPaymentRub = $calculation.element('tbxFirstPaymentRub').getValue();
const leasingPeriod = $calculation.element('tbxLeasingPeriod').getValue();
return {
finGAPInsuranceCompany,
@ -147,8 +147,7 @@ export default function commonReactions(
firstPaymentRub,
leasingPeriod,
}) => {
if ($tables.fingap.validation.hasErrors) return;
if (!finGAPInsuranceCompany) return;
if (!finGAPInsuranceCompany || $tables.payments.validation.hasErrors) return;
const {
data: { evo_addproduct_types },

View File

@ -10,9 +10,6 @@ export default function validationReactions(
) {
const { $tables } = store;
const errorText = 'Неверно заполнены платежи';
let removeError: () => void;
reaction(
() => {
const hasPaymentsErrors = $tables.payments.validation.hasErrors;
@ -24,9 +21,10 @@ export default function validationReactions(
};
},
({ hasPaymentsErrors, finGAPInsuranceCompany }) => {
if (finGAPInsuranceCompany && hasPaymentsErrors) {
removeError = $tables.fingap.validation.addError(errorText);
} else if (removeError) removeError();
$tables.fingap.validate({
invalid: finGAPInsuranceCompany !== null && hasPaymentsErrors,
message: 'Неверно заполнены платежи',
});
},
{
fireImmediately: true,

View File

@ -10,7 +10,7 @@ export default function getData(apolloClient, store) {
function setManyOptions(options) {
Object.keys(options).forEach((elementName) => {
const elementOptions = options[elementName];
$calculation.$options.setOptions(elementName, elementOptions);
$calculation.element(elementName).setOptions(elementOptions);
});
}

View File

@ -1,19 +1,28 @@
import * as agentsReactions from '../../agents/reactions';
import loadKpReactions from 'process/load-kp/reactions';
import * as calculateReactions from '../../calculate/reactions';
import * as fingapReactions from '../../fingap/reactions';
import * as leadOpportunityReactions from '../../lead-opportunity/reactions';
import paymentsReactions from '../../payments/reactions';
import * as priceReactions from '../../price/reactions';
import * as agentsReactions from '../../supplier-agent/reactions/agents';
import leasebackReactions from '../../supplier-agent/reactions/leaseback';
import * as supplierReactions from '../../supplier-agent/reactions/supplier';
import setInitialValuesReactions from '../set-values/reactions';
export default function injectDefaultReactions(store, apolloClient, queryClient) {
export default function injectDefaultReactions(store, apolloClient, queryClient, trpcClient) {
leadOpportunityReactions.common(store, apolloClient, queryClient);
leadOpportunityReactions.urls(store, apolloClient, queryClient);
paymentsReactions(store, apolloClient, queryClient);
calculateReactions.validation(store, apolloClient, queryClient);
agentsReactions.common(store, apolloClient, queryClient);
supplierReactions.commonReactions(store, apolloClient, queryClient);
supplierReactions.validationReactions(store, apolloClient, queryClient);
agentsReactions.fillReactions(store, apolloClient, queryClient);
agentsReactions.commonReactions(store, apolloClient, queryClient);
agentsReactions.validationReactions(store, apolloClient, queryClient);
leasebackReactions(store, apolloClient, queryClient);
priceReactions.computed(store, apolloClient, queryClient);
fingapReactions.common(store, apolloClient, queryClient);
fingapReactions.validation(store, apolloClient, queryClient);
setInitialValuesReactions(store, apolloClient, queryClient);
loadKpReactions(store, apolloClient, queryClient, trpcClient);
}

View File

@ -35,10 +35,9 @@ export default function setInitialValuesReactions(
(x) => x?.isocurrencycode === 'RUB'
);
$calculation.setElementValue(
'selectSupplierCurrency',
transactioncurrency_rub?.transactioncurrencyid
);
$calculation
.element('selectSupplierCurrency')
.setValue(transactioncurrency_rub?.transactioncurrencyid);
}
);
}

View File

@ -1,12 +1,14 @@
/* eslint-disable implicit-arrow-linebreak */
import type { ApolloClient } from '@apollo/client';
import { gql } from '@apollo/client';
import type * as CRMTypes from 'graphql/crm.types';
import { reaction } from 'mobx';
import type RootStore from 'stores/root';
import { normalizeOptions } from 'tools/entity';
import { makeDisposable } from 'tools/mobx';
export default function commonReactions(store: RootStore, apolloClient: ApolloClient<object>) {
const { $calculation } = store;
const { $calculation, $process } = store;
/**
* Если lead содержит данные, то в opportunity подгружается значение из поля Интереса
@ -26,33 +28,37 @@ export default function commonReactions(store: RootStore, apolloClient: ApolloCl
}
`;
reaction(
() => $calculation.getElementValue('selectLead'),
async (leadid) => {
if (!leadid) {
$calculation.resetElementValue('selectOpportunity');
makeDisposable(
() =>
reaction(
() => $calculation.element('selectLead').getValue(),
async (leadid) => {
if (!leadid) {
$calculation.element('selectOpportunity').resetValue();
return;
}
return;
}
const {
data: { lead },
} = await apolloClient.query<
CRMTypes.GetOpportunityByLeadQuery,
CRMTypes.GetOpportunityByLeadQueryVariables
>({
query: QUERY_GET_OPPORTUNITY_BY_LEAD,
variables: {
leadid,
},
});
const {
data: { lead },
} = await apolloClient.query<
CRMTypes.GetOpportunityByLeadQuery,
CRMTypes.GetOpportunityByLeadQueryVariables
>({
query: QUERY_GET_OPPORTUNITY_BY_LEAD,
variables: {
leadid,
},
});
if (lead?.evo_opportunityidData?.value) {
$calculation.setElementValue('selectOpportunity', lead?.evo_opportunityidData?.value);
} else {
$calculation.resetElementValue('selectOpportunity');
}
}
if (lead?.evo_opportunityidData?.value) {
$calculation.element('selectOpportunity').setValue(lead?.evo_opportunityidData?.value);
} else {
$calculation.element('selectOpportunity').resetValue();
}
}
),
() => $process.has('LoadKP')
);
/**
@ -70,9 +76,9 @@ export default function commonReactions(store: RootStore, apolloClient: ApolloCl
`;
reaction(
() => $calculation.getElementValue('selectOpportunity'),
() => $calculation.element('selectOpportunity').getValue(),
async (opportunityid) => {
const leadid = $calculation.getElementValue('selectLead');
const leadid = $calculation.element('selectLead').getValue();
if (leadid) {
const {
@ -88,7 +94,7 @@ export default function commonReactions(store: RootStore, apolloClient: ApolloCl
});
if (!opportunityid && lead?.evo_opportunityidData?.value) {
$calculation.resetElementValue('selectLead');
$calculation.element('selectLead').resetValue();
}
}
@ -103,7 +109,7 @@ export default function commonReactions(store: RootStore, apolloClient: ApolloCl
},
});
$calculation.setElementValue('selectLead', data.opportunity?.evo_leadid);
$calculation.element('selectLead').setValue(data.opportunity?.evo_leadid);
}
}
);
@ -125,7 +131,7 @@ export default function commonReactions(store: RootStore, apolloClient: ApolloCl
`;
reaction(
() => $calculation.getElementValue('selectLead'),
() => $calculation.element('selectLead').getValue(),
async (leadid) => {
if (leadid) {
const {
@ -140,9 +146,9 @@ export default function commonReactions(store: RootStore, apolloClient: ApolloCl
},
});
$calculation.setElementOptions('selectQuote', normalizeOptions(quotes));
$calculation.element('selectQuote').setOptions(normalizeOptions(quotes));
} else {
$calculation.resetElement('selectQuote');
$calculation.element('selectQuote').reset();
}
}
);

View File

@ -12,10 +12,10 @@ export default function urlsReactions(store: RootStore, apolloClient: ApolloClie
*/
function makeLinkReaction(elementName: Elements, linkElementName: Elements, query: DocumentNode) {
reaction(
() => $calculation.getElementValue(elementName),
() => $calculation.element(elementName).getValue(),
(id) => {
if (!id) {
$calculation.resetElementValue(linkElementName);
$calculation.element(linkElementName).resetValue();
return;
}
@ -34,22 +34,22 @@ export default function urlsReactions(store: RootStore, apolloClient: ApolloClie
.then(({ data }) => {
clearTimeout(timeoutId);
if (data.entity?.link) {
$calculation.setElementValue(linkElementName, data.entity?.link);
$calculation.element(linkElementName).setValue(data.entity?.link);
}
})
.catch(() => {
clearTimeout(timeoutId);
$calculation.resetElementValue(linkElementName);
$calculation.element(linkElementName).resetValue();
});
}
);
reaction(
() => $calculation.getElementValue(linkElementName),
() => $calculation.element(linkElementName).getValue(),
(url) => {
if (!url) {
$calculation.blockElement(linkElementName);
$calculation.element(linkElementName).block();
} else {
$calculation.unblockElement(linkElementName);
$calculation.element(linkElementName).unblock();
}
}
);

View File

@ -0,0 +1,51 @@
import type { ApolloClient } from '@apollo/client';
import type { QueryClient } from '@tanstack/react-query';
import message from 'Elements/message';
import { reaction, toJS } from 'mobx';
import type RootStore from 'stores/root';
import type { TRPCPureClient } from 'trpc/types';
export default function loadKpReactions(
store: RootStore,
apolloClient: ApolloClient<object>,
queryClient: QueryClient,
trpcClient: TRPCPureClient
) {
const { $calculation, $process } = store;
reaction(
() => $calculation.element('selectQuote').getValue(),
(quoteId) => {
if (!quoteId) return;
$process.add('LoadKP');
const quoteName = $calculation.element('selectQuote').getOption()?.label;
const { quote } = toJS($calculation.$values.values);
trpcClient.quote.getValues
.query({
values: {
quote,
},
})
.then(({ values }) => {
$calculation.$values.setValues({
values,
exclude: ['lead', 'opportunity', 'quote', 'leadUrl', 'opportunityUrl', 'quoteUrl'],
});
message.success({
content: `КП ${quoteName} загружено`,
});
})
.catch(() => {
message.error({
content: `Ошибка во время загрузки КП ${quoteName}`,
});
})
.finally(() => {
$process.delete('LoadKP');
});
}
);
}

View File

@ -8,7 +8,9 @@ import { shift } from 'radash';
import type { CalculationOptions } from 'stores/calculation/options/types';
import type RootStore from 'stores/root';
import type { Row } from 'stores/tables/payments/types';
import ValidationHelper from 'stores/validation/helper';
import { difference } from 'tools/array';
import { makeDisposable } from 'tools/mobx';
import * as seasonsConstants from './lib/seasons-constants';
import * as seasonsTools from './lib/seasons-tools';
import validatePaymentsTable from './validation';
@ -18,17 +20,17 @@ export default function paymentsReactions(
apolloClient: ApolloClient<object>,
queryClient: QueryClient
) {
const { $calculation, $tables } = store;
const { $calculation, $tables, $process } = store;
reaction(
() => $calculation.getElementValue('tbxFirstPaymentPerc'),
() => $calculation.element('tbxFirstPaymentPerc').getValue(),
(firstPaymentPerc) => {
$tables.payments.setValue(0, firstPaymentPerc);
}
);
reaction(
() => $calculation.getElementValue('tbxLastPaymentPerc'),
() => $calculation.element('tbxLastPaymentPerc').getValue(),
(lastPaymentPerc) => {
const paymentsLength = $tables.payments.values.length;
$tables.payments.setValue(paymentsLength - 1, lastPaymentPerc);
@ -38,155 +40,169 @@ export default function paymentsReactions(
/**
* Аннуитет
*/
reaction(
() => {
const graphType = $calculation.getElementValue('radioGraphType');
const leasingPeriod = $calculation.getElementValue('tbxLeasingPeriod');
makeDisposable(
() =>
reaction(
() => {
const graphType = $calculation.element('radioGraphType').getValue();
const leasingPeriod = $calculation.element('tbxLeasingPeriod').getValue();
return {
graphType,
leasingPeriod,
};
},
({ graphType, leasingPeriod }) => {
if (graphType === 100_000_000) {
const middlePayments: Row[] = Array.from(
{
length: leasingPeriod - 2,
},
() => ({
value: 100,
status: 'Disabled',
})
);
return {
graphType,
leasingPeriod,
};
},
({ graphType, leasingPeriod }) => {
if (graphType === 100_000_000) {
const middlePayments: Row[] = Array.from(
{
length: leasingPeriod - 2,
},
() => ({
value: 100,
status: 'Disabled',
})
);
const firstPaymentPerc = $calculation.getElementValue('tbxFirstPaymentPerc');
const lastPaymentPerc = $calculation.getElementValue('tbxLastPaymentPerc');
const firstPaymentPerc = $calculation.element('tbxFirstPaymentPerc').getValue();
const lastPaymentPerc = $calculation.element('tbxLastPaymentPerc').getValue();
$tables.payments.setRows([
{
value: firstPaymentPerc,
status: 'Disabled',
},
...middlePayments,
{
value: lastPaymentPerc,
status: 'Disabled',
},
]);
}
},
{
fireImmediately: true,
}
$tables.payments.setRows([
{
value: firstPaymentPerc,
status: 'Disabled',
},
...middlePayments,
{
value: lastPaymentPerc,
status: 'Disabled',
},
]);
}
},
{
fireImmediately: true,
}
),
() => $process.has('LoadKP')
);
/**
* Равноубывающий
*/
reaction(
() => {
const graphType = $calculation.getElementValue('radioGraphType');
const leasingPeriod = $calculation.getElementValue('tbxLeasingPeriod');
const parmentsDecreasePercent = $calculation.getElementValue('tbxParmentsDecreasePercent');
makeDisposable(
() =>
reaction(
() => {
const graphType = $calculation.element('radioGraphType').getValue();
const leasingPeriod = $calculation.element('tbxLeasingPeriod').getValue();
const parmentsDecreasePercent = $calculation
.element('tbxParmentsDecreasePercent')
.getValue();
return {
graphType,
leasingPeriod,
parmentsDecreasePercent,
};
},
({ graphType, leasingPeriod, parmentsDecreasePercent }) => {
if (graphType === 100_000_002) {
const middlePayments: Row[] = Array.from(
{
length: leasingPeriod - 2,
},
(_, k) => {
const payment = 100 * (parmentsDecreasePercent / 100) ** k;
return {
graphType,
leasingPeriod,
parmentsDecreasePercent,
};
},
({ graphType, leasingPeriod, parmentsDecreasePercent }) => {
if (graphType === 100_000_002) {
const middlePayments: Row[] = Array.from(
{
length: leasingPeriod - 2,
},
(_, k) => {
const payment = 100 * (parmentsDecreasePercent / 100) ** k;
return {
value: Number(payment.toFixed(2)),
status: 'Disabled',
};
return {
value: Number(payment.toFixed(2)),
status: 'Disabled',
};
}
);
const firstPaymentPerc = $calculation.element('tbxFirstPaymentPerc').getValue();
const lastPaymentPerc = $calculation.element('tbxLastPaymentPerc').getValue();
$tables.payments.setRows([
{
value: firstPaymentPerc,
status: 'Disabled',
},
...middlePayments,
{
value: lastPaymentPerc,
status: 'Disabled',
},
]);
}
);
const firstPaymentPerc = $calculation.getElementValue('tbxFirstPaymentPerc');
const lastPaymentPerc = $calculation.getElementValue('tbxLastPaymentPerc');
$tables.payments.setRows([
{
value: firstPaymentPerc,
status: 'Disabled',
},
...middlePayments,
{
value: lastPaymentPerc,
status: 'Disabled',
},
]);
}
}
}
),
() => $process.has('LoadKP')
);
/**
* Легкий старт
*/
reaction(
() => {
const graphType = $calculation.getElementValue('radioGraphType');
const leasingPeriod = $calculation.getElementValue('tbxLeasingPeriod');
makeDisposable(
() =>
reaction(
() => {
const graphType = $calculation.element('radioGraphType').getValue();
const leasingPeriod = $calculation.element('tbxLeasingPeriod').getValue();
return {
graphType,
leasingPeriod,
};
},
({ graphType, leasingPeriod }) => {
if (graphType === 100_000_004) {
const editablePayments: Row[] = [
{
value: 25,
status: 'Default',
},
{
value: 50,
status: 'Default',
},
{
value: 75,
status: 'Default',
},
];
return {
graphType,
leasingPeriod,
};
},
({ graphType, leasingPeriod }) => {
if (graphType === 100_000_004) {
const editablePayments: Row[] = [
{
value: 25,
status: 'Default',
},
{
value: 50,
status: 'Default',
},
{
value: 75,
status: 'Default',
},
];
const payments: Row[] = Array.from(
{
length: leasingPeriod - 5,
},
() => ({
value: 100,
status: 'Disabled',
})
);
const payments: Row[] = Array.from(
{
length: leasingPeriod - 5,
},
() => ({
value: 100,
status: 'Disabled',
})
);
const firstPaymentPerc = $calculation.getElementValue('tbxFirstPaymentPerc');
const lastPaymentPerc = $calculation.getElementValue('tbxLastPaymentPerc');
const firstPaymentPerc = $calculation.element('tbxFirstPaymentPerc').getValue();
const lastPaymentPerc = $calculation.element('tbxLastPaymentPerc').getValue();
$tables.payments.setRows([
{
value: firstPaymentPerc,
status: 'Disabled',
},
...editablePayments,
...payments,
{
value: lastPaymentPerc,
status: 'Disabled',
},
]);
}
}
$tables.payments.setRows([
{
value: firstPaymentPerc,
status: 'Disabled',
},
...editablePayments,
...payments,
{
value: lastPaymentPerc,
status: 'Disabled',
},
]);
}
}
),
() => $process.has('LoadKP')
);
/**
@ -200,7 +216,7 @@ export default function paymentsReactions(
reaction(
() => {
const graphType = $calculation.getElementValue('radioGraphType');
const graphType = $calculation.element('radioGraphType').getValue();
return graphType;
},
@ -216,7 +232,7 @@ export default function paymentsReactions(
seasonSeasonTypes.has(option.value)
);
}
$calculation.setElementOptions('selectSeasonType', selectSeasonTypeOptions);
$calculation.element('selectSeasonType').setOptions(selectSeasonTypeOptions);
}
);
@ -227,133 +243,141 @@ export default function paymentsReactions(
100_000_006: [100, 7, 3],
};
reaction(
() => {
const degressionType = $calculation.getElementValue('selectSeasonType');
const leasingPeriod = $calculation.getElementValue('tbxLeasingPeriod');
const graphType = $calculation.getElementValue('radioGraphType');
makeDisposable(
() =>
reaction(
() => {
const degressionType = $calculation.element('selectSeasonType').getValue();
const leasingPeriod = $calculation.element('tbxLeasingPeriod').getValue();
const graphType = $calculation.element('radioGraphType').getValue();
return {
degressionType,
leasingPeriod,
graphType,
};
},
({ degressionType, leasingPeriod, graphType }) => {
if (graphType === 100_000_001) {
let payments: Row[] = [];
return {
degressionType,
leasingPeriod,
graphType,
};
},
({ degressionType, leasingPeriod, graphType }) => {
if (graphType === 100_000_001) {
let payments: Row[] = [];
switch (degressionType) {
case 100_000_007: {
const editablePayments: Row[] = Array.from(
switch (degressionType) {
case 100_000_007: {
const editablePayments: Row[] = Array.from(
{
length: leasingPeriod - 3,
},
() => ({
value: 100,
status: 'Default',
})
);
payments = [
{
value: 100,
status: 'Disabled',
},
...editablePayments,
];
break;
}
case 100_000_003:
case 100_000_004:
case 100_000_005:
case 100_000_006: {
const [step1, step2, step3] = degressionSteps[degressionType];
const paymentsInStep = Math.ceil((leasingPeriod - 2) / 3);
payments = Array.from(
{
length: leasingPeriod - 2,
},
(_v, i) => {
let value = step3;
if (i <= paymentsInStep * 2 - 1) {
value = step2;
}
if (i <= paymentsInStep - 1) {
value = step1;
}
return {
value,
status: 'Disabled',
};
}
);
break;
}
default: {
break;
}
}
const firstPaymentPerc = $calculation.element('tbxFirstPaymentPerc').getValue();
const lastPaymentPerc = $calculation.element('tbxLastPaymentPerc').getValue();
$tables.payments.setRows([
{
length: leasingPeriod - 3,
},
() => ({
value: 100,
status: 'Default',
})
);
payments = [
{
value: 100,
value: firstPaymentPerc,
status: 'Disabled',
},
...editablePayments,
];
break;
}
case 100_000_003:
case 100_000_004:
case 100_000_005:
case 100_000_006: {
const [step1, step2, step3] = degressionSteps[degressionType];
const paymentsInStep = Math.ceil((leasingPeriod - 2) / 3);
payments = Array.from(
...payments,
{
length: leasingPeriod - 2,
value: lastPaymentPerc,
status: 'Disabled',
},
(_v, i) => {
let value = step3;
if (i <= paymentsInStep * 2 - 1) {
value = step2;
}
if (i <= paymentsInStep - 1) {
value = step1;
}
return {
value,
status: 'Disabled',
};
}
);
break;
}
default: {
break;
]);
}
}
const firstPaymentPerc = $calculation.getElementValue('tbxFirstPaymentPerc');
const lastPaymentPerc = $calculation.getElementValue('tbxLastPaymentPerc');
$tables.payments.setRows([
{
value: firstPaymentPerc,
status: 'Disabled',
},
...payments,
{
value: lastPaymentPerc,
status: 'Disabled',
},
]);
}
}
),
() => $process.has('LoadKP')
);
reaction(
() => {
const graphType = $calculation.getElementValue('radioGraphType');
const payments = toJS($tables.payments.values);
const degressionType = $calculation.getElementValue('selectSeasonType');
makeDisposable(
() =>
reaction(
() => {
const graphType = $calculation.element('radioGraphType').getValue();
const payments = toJS($tables.payments.values);
const degressionType = $calculation.element('selectSeasonType').getValue();
return {
graphType,
payments,
degressionType,
};
},
(nextParams, prevParams) => {
if (nextParams.graphType === 100_000_001 && nextParams.degressionType === 100_000_007) {
const changes = difference(nextParams.payments, prevParams.payments);
return {
graphType,
payments,
degressionType,
};
},
(nextParams, prevParams) => {
if (nextParams.graphType === 100_000_001 && nextParams.degressionType === 100_000_007) {
const changes = difference(nextParams.payments, prevParams.payments);
if (changes === null || changes.length > 1) return;
if (changes === null || changes.length > 1) return;
const [changeIndex] = changes;
const value = nextParams.payments[changeIndex];
const payments = nextParams.payments.slice(1, -1).map((payment, i) => {
if (i <= changeIndex - 2) return payment;
const [changeIndex] = changes;
const value = nextParams.payments[changeIndex];
const payments = nextParams.payments.slice(1, -1).map((payment, i) => {
if (i <= changeIndex - 2) return payment;
return value;
});
return value;
});
const firstPaymentPerc = $calculation.getElementValue('tbxFirstPaymentPerc');
const lastPaymentPerc = $calculation.getElementValue('tbxLastPaymentPerc');
const firstPaymentPerc = $calculation.element('tbxFirstPaymentPerc').getValue();
const lastPaymentPerc = $calculation.element('tbxLastPaymentPerc').getValue();
$tables.payments.setValues([firstPaymentPerc, ...payments, lastPaymentPerc]);
}
},
{
delay: 50,
equals: comparer.structural,
}
$tables.payments.setValues([firstPaymentPerc, ...payments, lastPaymentPerc]);
}
},
{
delay: 50,
equals: comparer.structural,
}
),
() => $process.has('LoadKP')
);
/**
@ -362,7 +386,7 @@ export default function paymentsReactions(
reaction(
() => {
const graphType = $calculation.getElementValue('radioGraphType');
const graphType = $calculation.element('radioGraphType').getValue();
return {
graphType,
@ -371,8 +395,8 @@ export default function paymentsReactions(
({ graphType }) => {
if (graphType !== 100_000_003) return;
const seasonType = $calculation.getElementValue('selectSeasonType');
const highSeasonStart = $calculation.getElementValue('selectHighSeasonStart');
const seasonType = $calculation.element('selectSeasonType').getValue();
const highSeasonStart = $calculation.element('selectHighSeasonStart').getValue();
if (!seasonType || !highSeasonStart) {
$tables.payments.setValues([]);
@ -382,16 +406,16 @@ export default function paymentsReactions(
reaction(
() => {
const seasonType = $calculation.getElementValue('selectSeasonType');
const seasonType = $calculation.element('selectSeasonType').getValue();
return seasonType;
},
(seasonType) => {
const graphType = $calculation.getElementValue('radioGraphType');
const graphType = $calculation.element('radioGraphType').getValue();
if (graphType !== 100_000_003) return;
if (!seasonType) {
$calculation.resetElement('selectHighSeasonStart');
$calculation.element('selectHighSeasonStart').reset();
return;
}
@ -400,7 +424,7 @@ export default function paymentsReactions(
(option) => !seasonsConstants.FORBIDDEN_HIGH_SEASON_START[seasonType].includes(option.label)
);
$calculation.setElementOptions('selectHighSeasonStart', highSeasonStartOptions);
$calculation.element('selectHighSeasonStart').setOptions(highSeasonStartOptions);
}
);
@ -418,123 +442,131 @@ export default function paymentsReactions(
return rows;
}
reaction(
() => {
const seasonType = $calculation.getElementValue('selectSeasonType');
const highSeasonStartOption = $calculation.getElementOption('selectHighSeasonStart');
const leasingPeriod = $calculation.getElementValue('tbxLeasingPeriod');
makeDisposable(
() =>
reaction(
() => {
const seasonType = $calculation.element('selectSeasonType').getValue();
const highSeasonStartOption = $calculation.element('selectHighSeasonStart').getOption();
const leasingPeriod = $calculation.element('tbxLeasingPeriod').getValue();
return {
seasonType,
highSeasonStartOption,
leasingPeriod,
};
},
({ seasonType, highSeasonStartOption, leasingPeriod }) => {
const graphType = $calculation.getElementValue('radioGraphType');
if (graphType !== 100_000_003) return;
if (!seasonType || !highSeasonStartOption) {
$tables.payments.setValues([]);
return;
}
const seasons = seasonsTools.generateSeasons(
seasonType,
seasonsConstants.DEFAULT_SEASONS_VALUES
);
const shiftNumber = Number.parseInt(highSeasonStartOption.label, 10) - 2;
const payments = seasonsTools.generateSeasonsPayments(
leasingPeriod,
shift(seasons, shiftNumber)
);
const rows: Row[] = generateSeasonPaymentsRows(seasonType, shiftNumber, payments);
const firstPaymentPerc = $calculation.getElementValue('tbxFirstPaymentPerc');
const lastPaymentPerc = $calculation.getElementValue('tbxLastPaymentPerc');
$tables.payments.setRows([
{
value: firstPaymentPerc,
status: 'Disabled',
return {
seasonType,
highSeasonStartOption,
leasingPeriod,
};
},
...rows,
{
value: lastPaymentPerc,
status: 'Disabled',
},
]);
}
({ seasonType, highSeasonStartOption, leasingPeriod }) => {
const graphType = $calculation.element('radioGraphType').getValue();
if (graphType !== 100_000_003) return;
if (!seasonType || !highSeasonStartOption) {
$tables.payments.setValues([]);
return;
}
const seasons = seasonsTools.generateSeasons(
seasonType,
seasonsConstants.DEFAULT_SEASONS_VALUES
);
const shiftNumber = Number.parseInt(highSeasonStartOption.label, 10) - 2;
const payments = seasonsTools.generateSeasonsPayments(
leasingPeriod,
shift(seasons, shiftNumber)
);
const rows: Row[] = generateSeasonPaymentsRows(seasonType, shiftNumber, payments);
const firstPaymentPerc = $calculation.element('tbxFirstPaymentPerc').getValue();
const lastPaymentPerc = $calculation.element('tbxLastPaymentPerc').getValue();
$tables.payments.setRows([
{
value: firstPaymentPerc,
status: 'Disabled',
},
...rows,
{
value: lastPaymentPerc,
status: 'Disabled',
},
]);
}
),
() => $process.has('LoadKP')
);
reaction(
() => {
const payments = toJS($tables.payments.values);
const seasons = payments.slice(1, seasonsConstants.SEASONS_PERIOD_NUMBER + 1);
makeDisposable(
() =>
reaction(
() => {
const payments = toJS($tables.payments.values);
const seasons = payments.slice(1, seasonsConstants.SEASONS_PERIOD_NUMBER + 1);
return seasons;
},
(nextSeasons, prevSeasons) => {
const graphType = $calculation.getElementValue('radioGraphType');
if (graphType !== 100_000_003) return;
const seasonType = $calculation.getElementValue('selectSeasonType');
const highSeasonStartOption = $calculation.getElementOption('selectHighSeasonStart');
if (!seasonType || !highSeasonStartOption) return;
const shiftNumber = Number.parseInt(highSeasonStartOption.label, 10) - 2;
const unshiftedNextSeasons = shift(nextSeasons, -shiftNumber);
const unshiftedPrevSeasons = shift(prevSeasons, -shiftNumber);
const changes = difference(unshiftedNextSeasons, unshiftedPrevSeasons);
if (changes === null || changes.length > 1) return;
const [changeIndex] = changes;
const positionIndex = seasonsTools.getPositionIndex(seasonType, changeIndex);
const values = seasonsTools.getSeasonsValues(seasonType, unshiftedNextSeasons);
values[positionIndex] = unshiftedNextSeasons[changeIndex];
const seasons = seasonsTools.generateSeasons(seasonType, values);
const leasingPeriod = $calculation.getElementValue('tbxLeasingPeriod');
const payments = seasonsTools.generateSeasonsPayments(
leasingPeriod,
shift(seasons, shiftNumber)
);
const rows: Row[] = generateSeasonPaymentsRows(seasonType, shiftNumber, payments);
const firstPaymentPerc = $calculation.getElementValue('tbxFirstPaymentPerc');
const lastPaymentPerc = $calculation.getElementValue('tbxLastPaymentPerc');
$tables.payments.setRows([
{
value: firstPaymentPerc,
status: 'Disabled',
return seasons;
},
...rows,
{
value: lastPaymentPerc,
status: 'Disabled',
(nextSeasons, prevSeasons) => {
const graphType = $calculation.element('radioGraphType').getValue();
if (graphType !== 100_000_003) return;
const seasonType = $calculation.element('selectSeasonType').getValue();
const highSeasonStartOption = $calculation.element('selectHighSeasonStart').getOption();
if (!seasonType || !highSeasonStartOption) return;
const shiftNumber = Number.parseInt(highSeasonStartOption.label, 10) - 2;
const unshiftedNextSeasons = shift(nextSeasons, -shiftNumber);
const unshiftedPrevSeasons = shift(prevSeasons, -shiftNumber);
const changes = difference(unshiftedNextSeasons, unshiftedPrevSeasons);
if (changes === null || changes.length > 1) return;
const [changeIndex] = changes;
const positionIndex = seasonsTools.getPositionIndex(seasonType, changeIndex);
const values = seasonsTools.getSeasonsValues(seasonType, unshiftedNextSeasons);
values[positionIndex] = unshiftedNextSeasons[changeIndex];
const seasons = seasonsTools.generateSeasons(seasonType, values);
const leasingPeriod = $calculation.element('tbxLeasingPeriod').getValue();
const payments = seasonsTools.generateSeasonsPayments(
leasingPeriod,
shift(seasons, shiftNumber)
);
const rows: Row[] = generateSeasonPaymentsRows(seasonType, shiftNumber, payments);
const firstPaymentPerc = $calculation.element('tbxFirstPaymentPerc').getValue();
const lastPaymentPerc = $calculation.element('tbxLastPaymentPerc').getValue();
$tables.payments.setRows([
{
value: firstPaymentPerc,
status: 'Disabled',
},
...rows,
{
value: lastPaymentPerc,
status: 'Disabled',
},
]);
},
]);
},
{
delay: 50,
equals: comparer.structural,
}
{
delay: 50,
equals: comparer.structural,
}
),
() => $process.has('LoadKP')
);
/**
* Валидация
*/
let removeError: () => void;
const validationHelper = new ValidationHelper();
reaction(
() => {
const payments = toJS($tables.payments.values);
const graphType = $calculation.getElementValue('radioGraphType');
const seasonType = $calculation.getElementValue('selectSeasonType');
const highSeasonStart = $calculation.getElementValue('selectHighSeasonStart');
const leasingPeriod = $calculation.getElementValue('tbxLeasingPeriod');
const graphType = $calculation.element('radioGraphType').getValue();
const seasonType = $calculation.element('selectSeasonType').getValue();
const highSeasonStart = $calculation.element('selectHighSeasonStart').getValue();
const leasingPeriod = $calculation.element('tbxLeasingPeriod').getValue();
return {
payments,
@ -545,11 +577,12 @@ export default function paymentsReactions(
};
},
() => {
if (removeError) removeError();
validationHelper.removeErrors();
const errorText = validatePaymentsTable(store);
if (errorText) {
removeError = $tables.payments.validation.addError(errorText);
const removeError = $tables.payments.validation.addError(errorText);
validationHelper.add(removeError);
}
},
{

View File

@ -7,10 +7,10 @@ import { areEqual, isSorted } from 'tools/array';
import { SEASONS_PERIODS, SEASONS_PERIOD_NUMBER } from './lib/seasons-constants';
export default function validatePaymentsTable({ $calculation, $tables }: RootStore) {
switch ($calculation.getElementValue('radioGraphType')) {
switch ($calculation.element('radioGraphType').getValue()) {
// Дегрессия
case 100_000_001:
if (!$calculation.getElementValue('selectSeasonType')) {
if (!$calculation.element('selectSeasonType').getValue()) {
return 'Не выбран тип дегрессии';
}
/**
@ -18,7 +18,7 @@ export default function validatePaymentsTable({ $calculation, $tables }: RootSto
*/
{
const MIN_PAYMENT = 3;
const leasingPeriod = $calculation.getElementValue('tbxLeasingPeriod');
const leasingPeriod = $calculation.element('tbxLeasingPeriod').getValue();
const targetPayments = $tables.payments.values.slice(1, leasingPeriod - 1);
if (!targetPayments.every((payment) => payment >= MIN_PAYMENT)) {
@ -30,7 +30,7 @@ export default function validatePaymentsTable({ $calculation, $tables }: RootSto
* при Дегрессии все значения не должны быть равны друг другу + что при Легком старте 2,3 и 4 платежи не должны быть равны 100
*/
{
const leasingPeriod = $calculation.getElementValue('tbxLeasingPeriod');
const leasingPeriod = $calculation.element('tbxLeasingPeriod').getValue();
const targetPayments = $tables.payments.values.slice(1, leasingPeriod - 1);
if (new Set(targetPayments).size === 1) {
@ -42,7 +42,7 @@ export default function validatePaymentsTable({ $calculation, $tables }: RootSto
* Проверка на возрастание
*/
{
const leasingPeriod = $calculation.getElementValue('tbxLeasingPeriod');
const leasingPeriod = $calculation.element('tbxLeasingPeriod').getValue();
const targetPayments = $tables.payments.values.slice(1, leasingPeriod - 1);
for (let i = 2; i < targetPayments.length - 1; i += 1) {
@ -73,7 +73,7 @@ export default function validatePaymentsTable({ $calculation, $tables }: RootSto
* иначе не осуществлять Расчет графика и выводить ошибку "Нельзя осуществить расчет - указана очень жетская дегрессия. Не менее чем у 4х платежей "Соотношение платежа" должно не отличаться между самой",
*/
{
const leasingPeriod = $calculation.getElementValue('tbxLeasingPeriod');
const leasingPeriod = $calculation.element('tbxLeasingPeriod').getValue();
const targetPayments = $tables.payments.values.slice(1, leasingPeriod - 1);
const counts = counting(targetPayments, (v) => v);
if (Object.values(counts).filter((count) => count > 1).length < 2) {
@ -84,17 +84,17 @@ export default function validatePaymentsTable({ $calculation, $tables }: RootSto
break;
case 100_000_003: {
const leasingPeriod = $calculation.getElementValue('tbxLeasingPeriod');
const leasingPeriod = $calculation.element('tbxLeasingPeriod').getValue();
if (leasingPeriod < 14) {
return 'При сезонном виде графика срок лизинга должен быть больше 14 месяцев';
}
const seasonType = $calculation.getElementValue('selectSeasonType');
const seasonType = $calculation.element('selectSeasonType').getValue();
if (!seasonType) {
return 'Не выбран тип сезонности';
}
const highSeasonStartOption = $calculation.getElementOption('selectHighSeasonStart');
const highSeasonStartOption = $calculation.element('selectHighSeasonStart').getOption();
if (!highSeasonStartOption) {
return 'Не выбрано смещение сезонности';
}

View File

@ -31,9 +31,9 @@ export default function computedReactions(store: RootStore, apolloClient: Apollo
autorun(
async () => {
const supplierCurrencyId = $calculation.getElementValue('selectSupplierCurrency');
const leaseObjectPrice = $calculation.getElementValue('tbxLeaseObjectPrice');
const supplierDiscountRub = $calculation.getElementValue('tbxSupplierDiscountRub');
const supplierCurrencyId = $calculation.element('selectSupplierCurrency').getValue();
const leaseObjectPrice = $calculation.element('tbxLeaseObjectPrice').getValue();
const supplierDiscountRub = $calculation.element('tbxSupplierDiscountRub').getValue();
if (!supplierCurrencyId) {
$calculation.$values.setValue('plPriceRub', leaseObjectPrice);

View File

@ -0,0 +1,97 @@
/* eslint-disable @typescript-eslint/naming-convention */
import { gql } from '@apollo/client';
import initializeApollo from 'apollo/client';
import type * as CRMTypes from 'graphql/crm.types';
import type { Quote } from './index';
const QUERY_GET_REWARD_RULES = gql`
query GetRewardRules($conditionId: Uuid!) {
evo_reward_condition(evo_reward_conditionid: $conditionId) {
evo_calc_reward_rules
}
}
`;
async function getRewardSum(
conditionId: string | null | undefined,
quote: Quote,
quoteRewardSummField: keyof Quote,
quoteRewardTotalField: keyof Quote
) {
if (!conditionId) return 0;
const apolloClient = initializeApollo();
const {
data: { evo_reward_condition },
} = await apolloClient.query<CRMTypes.GetRewardRulesQuery, CRMTypes.GetRewardRulesQueryVariables>(
{
query: QUERY_GET_REWARD_RULES,
variables: {
conditionId,
},
}
);
if (evo_reward_condition?.evo_calc_reward_rules === 100_000_001) {
return quote[quoteRewardSummField];
}
return quote[quoteRewardTotalField];
}
export default async function getSums(quote: Quote) {
const [
dealerRewardSumm,
dealerBrokerRewardSumm,
indAgentRewardSumm,
calcDoubleAgentRewardSumm,
calcBrokerRewardSum,
finDepartmentRewardSumm,
] = await Promise.all([
getRewardSum(
quote?.evo_dealer_reward_conditionid,
quote,
'evo_dealer_reward_summ',
'evo_dealer_reward_total'
),
getRewardSum(
quote?.evo_dealer_broker_reward_conditionid,
quote,
'evo_dealer_broker_reward_summ',
'evo_dealer_broker_reward_total'
),
getRewardSum(
quote?.evo_agent_reward_conditionid,
quote,
'evo_agent_reward_summ',
'evo_agent_reward_total'
),
getRewardSum(
quote.evo_double_agent_reward_conditionid,
quote,
'evo_double_agent_reward_summ',
'evo_double_agent_reward_total'
),
getRewardSum(
quote.evo_broker_reward_conditionid,
quote,
'evo_broker_reward_summ',
'evo_broker_reward_total'
),
getRewardSum(
quote.evo_fin_department_reward_conditionid,
quote,
'evo_fin_department_reward_summ',
'evo_fin_department_reward_total'
),
]);
return {
dealerRewardSumm,
dealerBrokerRewardSumm,
indAgentRewardSumm,
calcDoubleAgentRewardSumm,
calcBrokerRewardSum,
finDepartmentRewardSumm,
};
}

View File

@ -0,0 +1,103 @@
import { gql } from '@apollo/client';
import initializeApollo from 'apollo/client';
import type * as CRMTypes from 'graphql/crm.types';
import type { CalculationValues } from 'stores/calculation/values/types';
import getSums from './get-sums';
const QUERY_GET_AGENTS_DATA_FROM_QUOTE = gql`
query GetAgentsDataFromQuote($quoteId: Uuid!) {
quote(quoteId: $quoteId) {
evo_supplier_accountid
evo_dealer_person_accountid
evo_dealer_reward_conditionid
evo_dealer_reward_total
evo_dealer_reward_summ
evo_dealer_broker_accountid
evo_dealer_broker_reward_conditionid
evo_dealer_broker_reward_total
evo_dealer_broker_reward_summ
evo_agent_accountid
evo_agent_reward_conditionid
evo_agent_reward_total
evo_agent_reward_summ
evo_double_agent_accountid
evo_double_agent_reward_conditionid
evo_double_agent_reward_total
evo_double_agent_reward_summ
evo_broker_accountid
evo_broker_reward_conditionid
evo_broker_reward_total
evo_broker_reward_summ
evo_fin_department_accountid
evo_fin_department_reward_conditionid
evo_fin_department_reward_total
evo_fin_department_reward_summ
}
}
`;
export type Quote = NonNullable<CRMTypes.GetAgentsDataFromQuoteQuery['quote']>;
type InputData = {
quoteId: NonNullable<CalculationValues['quote']>;
};
type ResultData = {
values: Partial<CalculationValues>;
};
export default async function getSupplierAgentsDataFromKP({
quoteId,
}: InputData): Promise<ResultData> {
const apolloClient = initializeApollo();
const {
data: { quote },
} = await apolloClient.query<
CRMTypes.GetAgentsDataFromQuoteQuery,
CRMTypes.GetAgentsDataFromQuoteQueryVariables
>({
query: QUERY_GET_AGENTS_DATA_FROM_QUOTE,
variables: {
quoteId,
},
});
if (!quote) {
throw new Error('Quote is empty');
}
const {
dealerRewardSumm,
dealerBrokerRewardSumm,
indAgentRewardSumm,
calcDoubleAgentRewardSumm,
calcBrokerRewardSum,
finDepartmentRewardSumm,
} = await getSums(quote);
return {
values: {
dealer: quote?.evo_supplier_accountid,
dealerPerson: quote?.evo_dealer_person_accountid,
dealerRewardCondition: quote?.evo_dealer_reward_conditionid,
dealerRewardSumm,
dealerBroker: quote?.evo_dealer_broker_accountid,
dealerBrokerRewardCondition: quote?.evo_dealer_broker_reward_conditionid,
dealerBrokerRewardSumm,
indAgent: quote?.evo_agent_accountid,
indAgentRewardCondition: quote?.evo_agent_reward_conditionid,
indAgentRewardSumm,
calcDoubleAgent: quote?.evo_double_agent_accountid,
calcDoubleAgentRewardCondition: quote?.evo_double_agent_reward_conditionid,
calcDoubleAgentRewardSumm,
calcBroker: quote?.evo_broker_accountid,
calcBrokerRewardCondition: quote?.evo_broker_reward_conditionid,
calcBrokerRewardSum,
calcFinDepartment: quote?.evo_fin_department_accountid,
finDepartmentRewardCondtion: quote?.evo_fin_department_reward_conditionid,
finDepartmentRewardSumm,
},
};
}

View File

@ -0,0 +1,216 @@
/* eslint-disable @typescript-eslint/naming-convention */
import type { ApolloClient } from '@apollo/client';
import { gql } from '@apollo/client';
import type * as Values from 'Components/Calculation/config/map/values';
import dayjs from 'dayjs';
import utc from 'dayjs/plugin/utc';
import type * as CRMTypes from 'graphql/crm.types';
import { reaction } from 'mobx';
import type RootStore from 'stores/root';
import ValidationHelper from 'stores/validation/helper';
import { normalizeOptions } from 'tools/entity';
import { makeDisposable } from 'tools/mobx';
dayjs.extend(utc);
const QUERY_GET_REWARD_CONDITIONS = gql`
query GetRewardConditions($agentid: Uuid!, $currentDate: DateTime) {
evo_reward_conditions(
evo_agent_accountid: $agentid
evo_datefrom_param: { lte: $currentDate }
evo_dateto_param: { gte: $currentDate }
statecode: 0
evo_agency_agreementid_param: { has: true }
) {
label: evo_name
value: evo_reward_conditionid
evo_reward_summ
}
}
`;
export function fillAgentRewardReaction(
store: RootStore,
apolloClient: ApolloClient<object>,
agentParams: {
agentField: Values.Elements;
rewardConditionField: Values.Elements;
}
) {
const { $calculation, $process } = store;
const { agentField, rewardConditionField } = agentParams;
reaction(
() => $calculation.element(agentField).getValue(),
async (agentId) => {
if (!agentId) {
$calculation.element(rewardConditionField).reset();
return;
}
const {
data: { evo_reward_conditions },
} = await apolloClient.query<
CRMTypes.GetRewardConditionsQuery,
CRMTypes.GetRewardConditionsQueryVariables
>({
query: QUERY_GET_REWARD_CONDITIONS,
variables: {
agentid: agentId,
currentDate: dayjs().toISOString(),
},
});
if (evo_reward_conditions?.length) {
$calculation
.element(rewardConditionField)
.setOptions(normalizeOptions(evo_reward_conditions));
}
}
);
}
const QUERY_GET_REWARD_SUMM = gql`
query GetRewardSumm($conditionId: Uuid!) {
evo_reward_condition(evo_reward_conditionid: $conditionId) {
evo_reward_summ
}
}
`;
export function fillAgentRewardSummReaction(
store: RootStore,
apolloClient: ApolloClient<object>,
agentParams: {
rewardConditionField: Values.Elements;
rewardSummField: Values.Elements;
}
) {
const { $calculation, $process } = store;
const { rewardConditionField, rewardSummField } = agentParams;
makeDisposable(
() =>
reaction(
() => $calculation.element(rewardConditionField).getValue(),
async (rewardConditionId) => {
if (!rewardConditionId) {
$calculation.element(rewardSummField).reset();
return;
}
const {
data: { evo_reward_condition },
} = await apolloClient.query<
CRMTypes.GetRewardSummQuery,
CRMTypes.GetRewardSummQueryVariables
>({
query: QUERY_GET_REWARD_SUMM,
variables: {
conditionId: rewardConditionId,
},
});
$calculation.element(rewardSummField).setValue(evo_reward_condition?.evo_reward_summ);
}
),
() => $process.has('LoadKP')
);
reaction(
() => $calculation.element(rewardConditionField).getValue(),
(rewardConditionId) => {
if (!rewardConditionId) {
$calculation.element(rewardSummField).block();
} else {
$calculation.element(rewardSummField).unblock();
}
}
);
}
const QUERY_GET_REWARD_CONDITION = gql`
query GetRewardCondition($conditionId: Uuid!) {
evo_reward_condition(evo_reward_conditionid: $conditionId) {
evo_reward_summ
evo_reduce_reward
evo_min_reward_summ
}
}
`;
export function validateAgentRewardSumm(
store: RootStore,
apolloClient: ApolloClient<object>,
agentParams: {
rewardConditionField: Values.Elements;
rewardSummField: Values.Elements;
}
) {
const { $calculation } = store;
const { rewardConditionField, rewardSummField } = agentParams;
const validationHelper = new ValidationHelper();
reaction(
() => $calculation.element(rewardSummField).getValue() as number,
async (rewardSumm) => {
const conditionId = $calculation.element(rewardConditionField).getValue();
if (!conditionId) {
validationHelper.removeErrors();
return;
}
const {
data: { evo_reward_condition },
} = await apolloClient.query<
CRMTypes.GetRewardConditionQuery,
CRMTypes.GetRewardConditionQueryVariables
>({
query: QUERY_GET_REWARD_CONDITION,
variables: {
conditionId,
},
});
$calculation
.element(rewardSummField)
.validate({
invalid:
evo_reward_condition?.evo_reward_summ &&
rewardSumm > evo_reward_condition.evo_reward_summ,
message: 'Вознаграждение указано больше условия по агентскому договору!',
})
.err((removeError) => {
validationHelper.add(removeError);
});
$calculation
.element(rewardSummField)
.validate({
invalid:
!evo_reward_condition?.evo_reduce_reward &&
evo_reward_condition?.evo_reward_summ &&
rewardSumm < evo_reward_condition.evo_reward_summ,
message: 'Вознаграждение указано меньше условия по агентскому договору!',
})
.err((removeError) => {
validationHelper.add(removeError);
});
$calculation
.element(rewardSummField)
.validate({
invalid:
evo_reward_condition?.evo_min_reward_summ &&
rewardSumm < evo_reward_condition?.evo_min_reward_summ,
message: 'Вознаграждение указано меньше условия по агентскому договору!',
})
.err((removeError) => {
validationHelper.add(removeError);
});
}
);
}

View File

@ -18,7 +18,7 @@ function makeFillAgentFromLead(
leadid: string | null
) {
if (!leadid) {
$calculation.resetElement(elementName);
$calculation.element(elementName).reset();
return;
}
@ -43,11 +43,13 @@ function makeFillAgentFromLead(
});
if (agent) {
$calculation.setElementOptions(elementName, normalizeOptions([agent]));
$calculation.setElementValue(elementName, agent.value);
$calculation
.element(elementName)
.setOptions(normalizeOptions([agent]))
.setValue(agent.value);
}
} else {
$calculation.resetElement(elementName);
$calculation.element(elementName).reset();
}
};
}

View File

@ -1,6 +1,6 @@
/* eslint-disable import/prefer-default-export */
import { gql } from '@apollo/client';
/* eslint-disable import/prefer-default-export */
export const QUERY_GET_AGENT = gql`
query GetAgent($agentid: Uuid!) {
agent: account(accountid: $agentid) {

View File

@ -0,0 +1,513 @@
/* eslint-disable @typescript-eslint/naming-convention */
import type { ApolloClient } from '@apollo/client';
import { gql } from '@apollo/client';
import dayjs from 'dayjs';
import utc from 'dayjs/plugin/utc';
import type * as CRMTypes from 'graphql/crm.types';
import { reaction } from 'mobx';
import type RootStore from 'stores/root';
import { makeDisposable } from 'tools/mobx';
import * as createReactions from '../lib/create-reactions';
import * as fillAgentsFromLead from '../lib/fill-agents-from-lead';
dayjs.extend(utc);
export function fillReactions(store: RootStore, apolloClient: ApolloClient<object>) {
const { $calculation, $process } = store;
/**
* Заполняем агентов из Интереса
*/
makeDisposable(
() =>
reaction(
() => $calculation.element('selectLead').getValue(),
(leadid) => {
fillAgentsFromLead.fillIndAgent(store, apolloClient, leadid);
fillAgentsFromLead.fillCalcDoubleAgent(store, apolloClient, leadid);
fillAgentsFromLead.fillCalcBroker(store, apolloClient, leadid);
fillAgentsFromLead.fillFinDepartment(store, apolloClient, leadid);
}
),
() => $process.has('LoadKP')
);
/**
* IndAgent
*/
// Заполняем selectIndAgentRewardCondition
createReactions.fillAgentRewardReaction(store, apolloClient, {
agentField: 'selectIndAgent',
rewardConditionField: 'selectIndAgentRewardCondition',
});
// Заполняем tbxIndAgentRewardSumm
createReactions.fillAgentRewardSummReaction(store, apolloClient, {
rewardConditionField: 'selectIndAgentRewardCondition',
rewardSummField: 'tbxIndAgentRewardSumm',
});
/**
* CalcDoubleAgent
*/
// Заполняем selectCalcDoubleAgentRewardCondition
createReactions.fillAgentRewardReaction(store, apolloClient, {
agentField: 'selectCalcDoubleAgent',
rewardConditionField: 'selectCalcDoubleAgentRewardCondition',
});
// Заполняем tbxCalcDoubleAgentRewardSumm
createReactions.fillAgentRewardSummReaction(store, apolloClient, {
rewardConditionField: 'selectCalcDoubleAgentRewardCondition',
rewardSummField: 'tbxCalcDoubleAgentRewardSumm',
});
/**
* CalcBroker
*/
// Заполняем selectCalcBrokerRewardCondition
createReactions.fillAgentRewardReaction(store, apolloClient, {
agentField: 'selectCalcBroker',
rewardConditionField: 'selectCalcBrokerRewardCondition',
});
// Заполняем tbxCalcBrokerRewardSum
createReactions.fillAgentRewardSummReaction(store, apolloClient, {
rewardConditionField: 'selectCalcBrokerRewardCondition',
rewardSummField: 'tbxCalcBrokerRewardSum',
});
/**
* CalcFinDepartment
*/
// Заполняем selectFinDepartmentRewardCondtion
createReactions.fillAgentRewardReaction(store, apolloClient, {
agentField: 'selectCalcFinDepartment',
rewardConditionField: 'selectFinDepartmentRewardCondtion',
});
// Заполняем tbxCalcBrokerRewardSum
createReactions.fillAgentRewardSummReaction(store, apolloClient, {
rewardConditionField: 'selectFinDepartmentRewardCondtion',
rewardSummField: 'tbxFinDepartmentRewardSumm',
});
}
export function commonReactions(store: RootStore, apolloClient: ApolloClient<object>) {
const { $calculation } = store;
const QUERY_GET_REWARD_WITHOUT_OTHER_AGENT = gql`
query GetRewardWithoutOtherAgent($conditionId: Uuid!) {
evo_reward_condition(evo_reward_conditionid: $conditionId) {
evo_agency_agreementidData {
evo_reward_without_other_agent
}
}
}
`;
/**
* Добавить реакцию на изменение списка в поле selectDealerRewardCondition :
Если в списке selectDealerRewardCondition есть запись,
у которой evo_reward_condition.evo_agency_agreementid.
Выплата без других агентов (evo_reward_without_other_agent) = True,
то сбрасывают значение и закрываются для выбора поля:
selectDealerBroker
selectIndAgent
selectCalcDoubleAgent
selectCalcBroker
selectFinDepartment
*/
reaction(
() => $calculation.element('selectDealerRewardCondition').getValue(),
async (rewardConditionId) => {
function fillAgents() {
const leadid = $calculation.element('selectLead').getValue();
fillAgentsFromLead.fillIndAgent(store, apolloClient, leadid);
fillAgentsFromLead.fillCalcDoubleAgent(store, apolloClient, leadid);
fillAgentsFromLead.fillCalcBroker(store, apolloClient, leadid);
fillAgentsFromLead.fillFinDepartment(store, apolloClient, leadid);
}
if (!rewardConditionId) {
fillAgents();
return;
}
const {
data: { evo_reward_condition },
} = await apolloClient.query<
CRMTypes.GetRewardWithoutOtherAgentQuery,
CRMTypes.GetRewardWithoutOtherAgentQueryVariables
>({
query: QUERY_GET_REWARD_WITHOUT_OTHER_AGENT,
variables: {
conditionId: rewardConditionId,
},
});
if (evo_reward_condition?.evo_agency_agreementidData?.evo_reward_without_other_agent) {
$calculation.element('selectDealerBroker').reset();
$calculation.element('selectIndAgent').reset();
$calculation.element('selectCalcDoubleAgent').reset();
$calculation.element('selectCalcBroker').reset();
$calculation.element('selectCalcFinDepartment').reset();
} else {
fillAgents();
}
}
);
/**
* Добавить реакцию на изменение списка в поле selectDealerBrokerRewardCondition :
Если в списке selectDealerBrokerRewardCondition есть запись,
у которой evo_reward_condition.evo_agency_agreementid.
Выплата без других агентов (evo_reward_without_other_agent) = True,
то сбрасывают значение и закрываются для выбора поля:
selectDealerPerson (не обнуляем)
selectIndAgent
selectCalcDoubleAgent
selectCalcBroker
selectFinDepartment
иначе
selectDealerPerson открываем для редактирования
selectIndAgent заполняется значением из Интереса
selectCalcDoubleAgent заполняется значением из Интереса
selectCalcBrokerRewardCondition заполняется значением из Интереса
selectFinDepartmentRewardCondtion заполняется значением из Интереса
*/
reaction(
() => $calculation.element('selectDealerBrokerRewardCondition').getValue(),
async (rewardConditionId) => {
function fillAgents() {
const leadid = $calculation.element('selectLead').getValue();
fillAgentsFromLead.fillIndAgent(store, apolloClient, leadid);
fillAgentsFromLead.fillCalcDoubleAgent(store, apolloClient, leadid);
fillAgentsFromLead.fillCalcBroker(store, apolloClient, leadid);
fillAgentsFromLead.fillFinDepartment(store, apolloClient, leadid);
}
if (!rewardConditionId) {
fillAgents();
return;
}
const {
data: { evo_reward_condition },
} = await apolloClient.query<
CRMTypes.GetRewardWithoutOtherAgentQuery,
CRMTypes.GetRewardWithoutOtherAgentQueryVariables
>({
query: QUERY_GET_REWARD_WITHOUT_OTHER_AGENT,
variables: {
conditionId: rewardConditionId,
},
});
if (evo_reward_condition?.evo_agency_agreementidData?.evo_reward_without_other_agent) {
$calculation.element('selectDealerPerson').block();
$calculation.element('selectIndAgent').reset();
$calculation.element('selectCalcDoubleAgent').reset();
$calculation.element('selectCalcBroker').reset();
$calculation.element('selectCalcFinDepartment').reset();
} else {
$calculation.element('selectDealerPerson').unblock();
fillAgents();
}
}
);
/**
* Добавить реакцию на изменение списка в поле selectIndAgentRewardCondition :
Если в списке selectIndAgentRewardCondition есть запись,
у которой evo_reward_condition.evo_agency_agreementid.
Выплата без других агентов (evo_reward_without_other_agent) = True,
то сбрасывают значение и закрываются для выбора поля:
selectDealerPerson (не обнуляем)
selectDealerBroker
selectCalcDoubleAgent
selectCalcBroker
selectFinDepartment
иначе
selectDealerPerson открываем для редактирования
selectDealerBroker открываем для редактирования
selectCalcDoubleAgent заполняется значением из Интереса
selectCalcBroker заполняется значением из Интереса
selectCalcFinDepartment заполняется значением из Интереса
*/
reaction(
() => $calculation.element('selectIndAgentRewardCondition').getValue(),
async (rewardConditionId) => {
function fillAgents() {
const leadid = $calculation.element('selectLead').getValue();
fillAgentsFromLead.fillCalcDoubleAgent(store, apolloClient, leadid);
fillAgentsFromLead.fillCalcBroker(store, apolloClient, leadid);
fillAgentsFromLead.fillFinDepartment(store, apolloClient, leadid);
}
if (!rewardConditionId) {
fillAgents();
return;
}
const {
data: { evo_reward_condition },
} = await apolloClient.query<
CRMTypes.GetRewardWithoutOtherAgentQuery,
CRMTypes.GetRewardWithoutOtherAgentQueryVariables
>({
query: QUERY_GET_REWARD_WITHOUT_OTHER_AGENT,
variables: {
conditionId: rewardConditionId,
},
});
if (evo_reward_condition?.evo_agency_agreementidData?.evo_reward_without_other_agent) {
$calculation.element('selectDealerPerson').block();
$calculation.element('selectDealerBroker').reset();
$calculation.element('selectCalcDoubleAgent').reset();
$calculation.element('selectCalcBroker').reset();
$calculation.element('selectCalcFinDepartment').reset();
} else {
$calculation.element('selectDealerPerson').unblock();
fillAgents();
}
}
);
/**
* Добавить реакцию на изменение списка в поле selectCalcDoubleAgentRewardCondition :
Если в списке selectCalcDoubleAgentRewardCondition есть запись,
у которой evo_reward_condition.evo_agency_agreementid.
Выплата без других агентов (evo_reward_without_other_agent) = True,
то сбрасывают значение и закрываются для выбора поля:
selectDealerPerson (не обнуляем)
selectDealerBroker
selectIndAgent
selectCalcBroker
selectCalcFinDepartment
иначе
selectDealerPerson открываем для редактирования
selectDealerBroker открываем для редактирования
selectIndAgent заполняется значением из Интереса
selectCalcBroker заполняется значением из Интереса
selectCalcFinDepartment заполняется значением из Интереса
*/
reaction(
() => $calculation.element('selectCalcDoubleAgentRewardCondition').getValue(),
async (rewardConditionId) => {
function fillAgents() {
const leadid = $calculation.element('selectLead').getValue();
fillAgentsFromLead.fillIndAgent(store, apolloClient, leadid);
fillAgentsFromLead.fillCalcBroker(store, apolloClient, leadid);
fillAgentsFromLead.fillFinDepartment(store, apolloClient, leadid);
}
if (!rewardConditionId) {
fillAgents();
return;
}
const {
data: { evo_reward_condition },
} = await apolloClient.query<
CRMTypes.GetRewardWithoutOtherAgentQuery,
CRMTypes.GetRewardWithoutOtherAgentQueryVariables
>({
query: QUERY_GET_REWARD_WITHOUT_OTHER_AGENT,
variables: {
conditionId: rewardConditionId,
},
});
if (evo_reward_condition?.evo_agency_agreementidData?.evo_reward_without_other_agent) {
$calculation.element('selectDealerPerson').block();
$calculation.element('selectDealerBroker').reset();
$calculation.element('selectIndAgent').reset();
$calculation.element('selectCalcBroker').reset();
$calculation.element('selectCalcFinDepartment').reset();
} else {
$calculation.element('selectDealerPerson').unblock();
$calculation.element('selectDealerBroker').unblock();
fillAgents();
}
}
);
/**
* @description
* Добавить реакцию на изменение списка в поле selectCalcBrokerRewardCondition:
Если в списке selectCalcBrokerRewardCondition есть запись,
у которой evo_reward_condition.evo_agency_agreementid.
Выплата без других агентов (evo_reward_without_other_agent) = True,
то сбрасывают значение и закрываются для выбора поля:
selectDealerPerson (не обнуляем)
selectDealerBroker
selectIndAgent
selectCalcDoubleAgent
selectCalcFinDepartment
иначе
selectDealerPerson открываем для редактирования
selectDealerBroker открываем для редактирования
selectIndAgent заполняется значением из Интереса
selectCalcDoubleAgent заполняется значением из Интереса
selectCalcFinDepartment заполняется значением из Интереса
*/
reaction(
() => $calculation.element('selectCalcBrokerRewardCondition').getValue(),
async (rewardConditionId) => {
function fillAgents() {
const leadid = $calculation.element('selectLead').getValue();
fillAgentsFromLead.fillIndAgent(store, apolloClient, leadid);
fillAgentsFromLead.fillCalcDoubleAgent(store, apolloClient, leadid);
fillAgentsFromLead.fillFinDepartment(store, apolloClient, leadid);
}
if (!rewardConditionId) {
fillAgents();
return;
}
const {
data: { evo_reward_condition },
} = await apolloClient.query<
CRMTypes.GetRewardWithoutOtherAgentQuery,
CRMTypes.GetRewardWithoutOtherAgentQueryVariables
>({
query: QUERY_GET_REWARD_WITHOUT_OTHER_AGENT,
variables: {
conditionId: rewardConditionId,
},
});
if (evo_reward_condition?.evo_agency_agreementidData?.evo_reward_without_other_agent) {
$calculation.element('selectDealerPerson').block();
$calculation.element('selectDealerBroker').reset();
$calculation.element('selectIndAgent').reset();
$calculation.element('selectCalcDoubleAgent').reset();
$calculation.element('selectCalcFinDepartment').reset();
} else {
$calculation.element('selectDealerPerson').unblock();
$calculation.element('selectDealerBroker').unblock();
fillAgents();
}
}
);
/**
* Добавить реакцию на изменение списка в поле selectFinDepartmentRewardCondtion:
Если в списке selectFinDepartmentRewardCondtion есть запись,
у которой evo_reward_condition.evo_agency_agreementid.
Выплата без других агентов (evo_reward_without_other_agent) = True,
то сбрасывают значение и закрываются для выбора поля:
selectDealerPerson (не обнуляем)
selectDealerBroker
selectIndAgent
selectCalcDoubleAgent
selectCalcBroker
иначе
selectDealerPerson открываем для редактирования
selectDealerBroker открываем для редактирования
selectIndAgent заполняется значением из Интереса
selectCalcDoubleAgent заполняется значением из Интереса
selectCalcBroker заполняется значением из Интереса
*/
reaction(
() => $calculation.element('selectFinDepartmentRewardCondtion').getValue(),
async (rewardConditionId) => {
function fillAgents() {
const leadid = $calculation.element('selectLead').getValue();
fillAgentsFromLead.fillIndAgent(store, apolloClient, leadid);
fillAgentsFromLead.fillCalcDoubleAgent(store, apolloClient, leadid);
fillAgentsFromLead.fillFinDepartment(store, apolloClient, leadid);
}
if (!rewardConditionId) {
fillAgents();
return;
}
const {
data: { evo_reward_condition },
} = await apolloClient.query<
CRMTypes.GetRewardWithoutOtherAgentQuery,
CRMTypes.GetRewardWithoutOtherAgentQueryVariables
>({
query: QUERY_GET_REWARD_WITHOUT_OTHER_AGENT,
variables: {
conditionId: rewardConditionId,
},
});
if (evo_reward_condition?.evo_agency_agreementidData?.evo_reward_without_other_agent) {
$calculation.element('selectDealerPerson').block();
$calculation.element('selectDealerBroker').reset();
$calculation.element('selectIndAgent').reset();
$calculation.element('selectCalcDoubleAgent').reset();
$calculation.element('selectCalcBroker').reset();
} else {
$calculation.element('selectDealerPerson').unblock();
$calculation.element('selectDealerBroker').unblock();
fillAgents();
}
}
);
}
export function validationReactions(store: RootStore, apolloClient: ApolloClient<object>) {
createReactions.validateAgentRewardSumm(store, apolloClient, {
rewardConditionField: 'selectDealerRewardCondition',
rewardSummField: 'tbxDealerRewardSumm',
});
createReactions.validateAgentRewardSumm(store, apolloClient, {
rewardConditionField: 'selectDealerBrokerRewardCondition',
rewardSummField: 'tbxDealerBrokerRewardSumm',
});
createReactions.validateAgentRewardSumm(store, apolloClient, {
rewardConditionField: 'selectIndAgentRewardCondition',
rewardSummField: 'tbxIndAgentRewardSumm',
});
createReactions.validateAgentRewardSumm(store, apolloClient, {
rewardConditionField: 'selectCalcDoubleAgentRewardCondition',
rewardSummField: 'tbxCalcDoubleAgentRewardSumm',
});
createReactions.validateAgentRewardSumm(store, apolloClient, {
rewardConditionField: 'selectCalcBrokerRewardCondition',
rewardSummField: 'tbxCalcBrokerRewardSum',
});
createReactions.validateAgentRewardSumm(store, apolloClient, {
rewardConditionField: 'selectFinDepartmentRewardCondtion',
rewardSummField: 'tbxFinDepartmentRewardSumm',
});
}

View File

@ -0,0 +1,90 @@
import type { ApolloClient } from '@apollo/client';
import { gql } from '@apollo/client';
import type * as CRMTypes from 'graphql/crm.types';
import { reaction } from 'mobx';
import type RootStore from 'stores/root';
export default function leasebackReactions(store: RootStore, apolloClient: ApolloClient<object>) {
const { $calculation, $tables } = store;
/**
* Дополнить реакцию на изменение поля Салон приобретения selectDealer:
если в поле selectDealer указан account, у которого evo_return_leasing_dealer = true, то
1) поле selectDealerPerson обнулять и закрывать для редактирования,
иначе формировать список связанных значений
2) в таблице страхования в столбце Плательщик
в строках ОСАГО и КАСКО указывать "Лизингополучатель" (100 000 000) и закрывать для редактирования ,
иначе открывать данные поля для редактирования
3) ПЛ БУ cbxLeaseObjectUsed = true
*/
const QUERY_GET_DEALER_RETURN_LEASING = gql`
query GetDealerReturnLeasing($dealerId: Uuid!) {
dealer: account(accountid: $dealerId) {
evo_return_leasing_dealer
}
}
`;
reaction(
() => $calculation.element('selectDealer').getValue(),
async (dealerId) => {
if (!dealerId) return;
const {
data: { dealer },
} = await apolloClient.query<
CRMTypes.GetDealerReturnLeasingQuery,
CRMTypes.GetDealerReturnLeasingQueryVariables
>({
query: QUERY_GET_DEALER_RETURN_LEASING,
variables: {
dealerId,
},
});
if (dealer?.evo_return_leasing_dealer === true) {
$tables.insurance.row('kasko').setValue('insured', 100_000_000).block('insured');
$calculation.element('cbxLeaseObjectUsed').setValue(true);
} else {
$tables.insurance.row('kasko').resetStatus('insured');
}
}
);
// объединили реакцию для прицепа и возвратного лизинга
reaction(
() => ({
dealerId: $calculation.element('selectDealer').getValue(),
leaseObjectCategory: $calculation.element('selectLeaseObjectCategory').getValue(),
}),
async ({ dealerId, leaseObjectCategory }) => {
const isTrailer = leaseObjectCategory === 100_000_004;
let returnLeasing = false;
if (dealerId) {
const {
data: { dealer },
} = await apolloClient.query<
CRMTypes.GetDealerReturnLeasingQuery,
CRMTypes.GetDealerReturnLeasingQueryVariables
>({
query: QUERY_GET_DEALER_RETURN_LEASING,
variables: {
dealerId,
},
});
returnLeasing = dealer?.evo_return_leasing_dealer === true;
}
if (isTrailer || returnLeasing) {
$tables.insurance.row('osago').setValue('insured', 100_000_000).block('insured');
} else {
$tables.insurance.row('osago').resetStatus('insured');
}
}
);
}

View File

@ -0,0 +1,173 @@
/* eslint-disable @typescript-eslint/naming-convention */
import type { ApolloClient } from '@apollo/client';
import { gql } from '@apollo/client';
import dayjs from 'dayjs';
import utc from 'dayjs/plugin/utc';
import type * as CRMTypes from 'graphql/crm.types';
import { reaction } from 'mobx';
import { sift } from 'radash';
import type RootStore from 'stores/root';
import { normalizeOptions } from 'tools/entity';
import * as createReactions from '../lib/create-reactions';
import * as query from '../lib/query';
dayjs.extend(utc);
export function commonReactions(store: RootStore, apolloClient: ApolloClient<object>) {
const { $calculation, $process } = store;
/**
* Заполняем selectDealerPerson
* На изменение Салон приобретения формируем список в поле ЮЛ поставщика - записи Контрагент,
* у которых статус = активный И Поставщик = Да И Тип поставщика = Юридическое лицо
* И связаны с карточкой Контрагент из поля "Салон приобретения" по связи Салон-ЮЛ
*/
const QUERY_GET_DEALER_PERSON = gql`
query GetDealerPerson($dealerId: Uuid!) {
salon_providers(statecode: 0, salonaccountid: $dealerId) {
label: name
value: accountid
evo_inn
evo_kpp
}
}
`;
reaction(
() => $calculation.element('selectDealer').getValue(),
async (dealerId) => {
if (!dealerId) {
$calculation.element('selectDealerPerson').reset();
$calculation.element('selectDealerBroker').reset();
return;
}
const {
data: { salon_providers },
} = await apolloClient.query<
CRMTypes.GetDealerPersonQuery,
CRMTypes.GetDealerPersonQueryVariables
>({
query: QUERY_GET_DEALER_PERSON,
variables: {
dealerId,
},
});
if (salon_providers?.length) {
$calculation.element('selectDealerPerson').setOptions(
normalizeOptions(
salon_providers.map((dp) => ({
...dp,
label: `${dp?.label} ${sift([dp?.evo_inn, dp?.evo_kpp]).join(' | ')}`,
}))
)
);
if (!$process.has('LoadKP')) {
$calculation.element('selectDealerPerson').setValue(salon_providers[0]?.value);
}
}
}
);
/**
* Заполняем selectDealerBroker
*/
const QUERY_GET_BROKER_ACCOUNTID_FROM_DEALER = gql`
query GetBrokerAccountIdFromDealer($dealerId: Uuid!) {
dealer: account(accountid: $dealerId) {
evo_broker_accountid
}
}
`;
reaction(
() => $calculation.element('selectDealerPerson').getValue(),
async (dealerPersonId) => {
if (!dealerPersonId) {
return;
}
const {
data: { dealer },
} = await apolloClient.query<
CRMTypes.GetBrokerAccountIdFromDealerQuery,
CRMTypes.GetBrokerAccountIdFromDealerQueryVariables
>({
query: QUERY_GET_BROKER_ACCOUNTID_FROM_DEALER,
variables: {
dealerId: dealerPersonId,
},
});
if (dealer?.evo_broker_accountid) {
const {
data: { agent: dealerBroker },
} = await apolloClient.query<CRMTypes.GetAgentQuery, CRMTypes.GetAgentQueryVariables>({
query: query.QUERY_GET_AGENT,
variables: {
agentid: dealer?.evo_broker_accountid,
},
});
if (dealerBroker) {
$calculation.element('selectDealerBroker').setOptions(normalizeOptions([dealerBroker]));
if (!$process.has('LoadKP')) {
$calculation.element('selectDealerBroker').setValue(dealerBroker.value);
}
}
} else {
$calculation.element('selectDealerBroker').reset();
}
}
);
// Заполняем selectDealerRewardCondition
createReactions.fillAgentRewardReaction(store, apolloClient, {
agentField: 'selectDealerPerson',
rewardConditionField: 'selectDealerRewardCondition',
});
// Заполняем tbxDealerRewardSumm
createReactions.fillAgentRewardSummReaction(store, apolloClient, {
rewardConditionField: 'selectDealerRewardCondition',
rewardSummField: 'tbxDealerRewardSumm',
});
// Заполняем selectDealerBrokerRewardCondition
createReactions.fillAgentRewardReaction(store, apolloClient, {
agentField: 'selectDealerBroker',
rewardConditionField: 'selectDealerBrokerRewardCondition',
});
// Заполняем tbxDealerBrokerRewardSumm
createReactions.fillAgentRewardSummReaction(store, apolloClient, {
rewardConditionField: 'selectDealerBrokerRewardCondition',
rewardSummField: 'tbxDealerBrokerRewardSumm',
});
reaction(
() => $calculation.element('selectDealerRewardCondition').getValue(),
(dealerRewardConditionId) => {
if (dealerRewardConditionId) {
$calculation.element('selectDealerBroker').resetValue();
}
}
);
reaction(
() => $calculation.element('selectDealerBrokerRewardCondition').getValue(),
(dealerBrokerRewardConditionId) => {
if (dealerBrokerRewardConditionId) {
$calculation.element('selectDealerPerson').resetValue();
}
}
);
}
export function validationReactions(store: RootStore, apolloClient: ApolloClient<object>) {}

View File

@ -1,72 +1,118 @@
/* eslint-disable import/no-cycle */
import type { Elements as ElementsActions } from 'Components/Calculation/config/map/actions';
import titles from 'Components/Calculation/config/elements-titles';
import type * as Values from 'Components/Calculation/config/map/values';
import { getValueName } from 'Components/Calculation/config/map/values';
import type { BaseOption } from 'Elements/types';
import { observable } from 'mobx';
import type RootStore from 'stores/root';
import Validation from 'stores/validation';
import type { RemoveError, ValidationParams } from '../validation/types';
import OptionsStore from './options';
import StatusStore from './statuses';
import ValidationStore from './validation';
import ValuesStore from './values';
export default class CalculationStore {
$values: ValuesStore;
$status: StatusStore;
$options: OptionsStore;
$validation: ValidationStore;
$validation: Partial<Record<Values.Elements, Validation>>;
constructor(rootStore: RootStore) {
this.$values = new ValuesStore(rootStore);
this.$status = new StatusStore(rootStore);
this.$options = new OptionsStore(rootStore);
this.$validation = new ValidationStore(rootStore);
this.$validation = observable.object({});
}
resetElement = (elementName: Values.Elements) => {
this.resetElementValue(elementName);
this.$options.resetOptions(elementName);
this.$status.resetStatus(elementName);
this.$validation.clearErrors(elementName);
private createElementValidation = <E extends Values.Elements>(elementName: E) => {
this.$validation[elementName] = new Validation({
err_key: elementName,
err_title: titles[elementName],
});
};
blockElement = (elementName: Values.Elements | ElementsActions) => {
this.$status.setStatus(elementName, 'Disabled');
};
element = <E extends Values.Elements>(elementName: E) => ({
reset: () => {
const valueName = getValueName(elementName);
this.$values.resetValue(valueName);
unblockElement = (elementName: Values.Elements | ElementsActions) => {
this.$status.setStatus(elementName, 'Default');
};
this.$options.resetOptions(elementName);
this.$status.resetStatus(elementName);
this.$validation[elementName]?.clearErrors();
getElementValue<E extends Values.Elements>(elementName: E) {
const valueName = getValueName(elementName);
return this.element(elementName);
},
return this.$values.getValue(valueName) as Values.ElementsTypes[E];
}
block: () => {
this.$status.setStatus(elementName, 'Disabled');
setElementValue = <E extends Values.Elements>(elementName: E, value: Values.ElementsTypes[E]) => {
const valueName = getValueName(elementName);
this.$values.setValue(valueName, value);
};
return this.element(elementName);
},
resetElementValue = (elementName: Values.Elements) => {
const valueName = getValueName(elementName);
this.$values.resetValue(valueName);
};
unblock: () => {
this.$status.setStatus(elementName, 'Default');
setElementOptions = <T extends Values.Elements>(
elementName: T,
options: BaseOption<Values.ElementsTypes[T]>[]
) => {
this.$options.setOptions(elementName, options);
};
return this.element(elementName);
},
resetElementOptions = <T extends Values.Elements>(elementName: T) => {
this.$options.resetOptions(elementName);
};
getValue: () => {
const valueName = getValueName(elementName);
getElementOption<T extends Values.Elements>(elementName: T) {
const value = this.getElementValue(elementName);
return this.$values.getValue(valueName) as Values.ElementsTypes[E];
},
return this.$options.getOptions(elementName)?.find((x) => x.value === value);
}
setValue: (value: Values.ElementsTypes[E]) => {
const valueName = getValueName(elementName);
this.$values.setValue(valueName, value);
return this.element(elementName);
},
resetValue: () => {
const valueName = getValueName(elementName);
this.$values.resetValue(valueName);
return this.element(elementName);
},
getOption: () => {
const valueName = getValueName(elementName);
const value = this.$values.getValue(valueName) as Values.ElementsTypes[E];
return this.$options.getOptions(elementName)?.find((x) => x.value === value);
},
setOptions: (options: BaseOption<Values.ElementsTypes[E]>[]) => {
this.$options.setOptions(elementName, options);
return this.element(elementName);
},
resetOptions: () => {
this.$options.resetOptions(elementName);
return this.element(elementName);
},
validate: ({ invalid, message }: ValidationParams) => {
if (!this.$validation[elementName]) this.createElementValidation(elementName);
let removeError: RemoveError | undefined;
if (invalid) {
removeError = this.$validation[elementName]?.addError(message);
} else {
this.$validation[elementName]?.removeError(message);
}
return {
err(callback: (removeError: RemoveError) => void) {
if (removeError) callback(removeError);
},
};
},
cleanErrors: () => {
this.$validation[elementName]?.clearErrors();
},
});
}

View File

@ -30,13 +30,12 @@ export default class OptionsStore {
/**
* Проверяем, что значение есть в новом списке, иначе сбрасываем значение
*/
const value = this.root.$calculation.getElementValue(elementName);
const value = this.root.$calculation.element(elementName).getValue();
if (
// eslint-disable-next-line operator-linebreak
!this.options[elementName]?.length ||
!this.options[elementName].some((x) => x.value === value)
) {
this.root.$calculation.resetElementValue(elementName);
this.root.$calculation.element(elementName).resetValue();
}
};

View File

@ -3,10 +3,16 @@ import { useStore } from 'stores/hooks';
export function useValidation(elementName) {
const { $calculation } = useStore();
const validationResult = $calculation.$validation.getValidation(elementName);
const messages = $calculation.$validation[elementName]?.getMessages();
if (messages?.length) {
return {
isValid: false,
help: 'Некорректные данные',
};
}
return {
...validationResult,
help: validationResult?.isValid === false ? 'Некорректные данные' : null,
isValid: true,
};
}

View File

@ -1,60 +0,0 @@
/* eslint-disable object-curly-newline */
import titles from 'Components/Calculation/config/elements-titles';
import type { Elements } from 'Components/Calculation/config/map/values';
import notification from 'Elements/notification';
import { makeAutoObservable, observable } from 'mobx';
import type RootStore from 'stores/root';
import type { ElementsErrors, Error } from './types';
export default class ValidationStore {
root: RootStore;
elementsErrors: Partial<ElementsErrors> = {};
constructor(rootStore: RootStore) {
makeAutoObservable(this);
this.root = rootStore;
}
get hasErrors() {
return (Object.keys(this.elementsErrors) as Elements[]).some(
(elementName) => this.elementsErrors[elementName]?.length
);
}
getValidation(elementName: Elements) {
return {
isValid: !this.elementsErrors[elementName]?.length,
errors: this.elementsErrors[elementName]?.map((x) => x.text),
};
}
addError = (elementName: Elements, error: Error) => {
if (!this.elementsErrors[elementName]) this.elementsErrors[elementName] = observable([]);
const errorIndex = this.elementsErrors[elementName]?.findIndex((x) => x.name === error.name);
const hasError = errorIndex !== undefined && errorIndex !== -1;
if (!hasError) {
this.elementsErrors[elementName]?.push(error);
} else {
this.elementsErrors[elementName]?.splice(errorIndex, 1, error);
}
notification.error({
key: error.name,
message: `${titles[elementName]}`,
description: error.text,
});
return () => this.#removeError(elementName, error.name);
};
#removeError = (elementName: Elements, errorName: Error['name']) => {
const errorIndex = this.elementsErrors[elementName]?.findIndex((x) => x.name === errorName);
if (errorIndex) this.elementsErrors[elementName]?.splice(errorIndex, 1);
};
clearErrors = (elementName: Elements) => {
this.elementsErrors[elementName]?.clear();
};
}

View File

@ -1,5 +0,0 @@
import type { Elements } from 'Components/Calculation/config/map/values';
import type { IObservableArray } from 'mobx';
export type Error = { name: string; text: string };
export type ElementsErrors = Record<Elements, IObservableArray<Error>>;

View File

@ -1,6 +1,7 @@
/* eslint-disable object-curly-newline */
import defaultValues from 'config/default-values';
import { makeAutoObservable } from 'mobx';
import { pick } from 'radash';
import type RootStore from '../../root';
import type { CalculationValues, Values } from './types';
@ -17,6 +18,13 @@ export default class ValuesStore {
this.values = initialValues;
};
setValues = (params: { values: CalculationValues; exclude: Values[] }) => {
const { values, exclude } = params;
const savedValues = pick(this.values, exclude);
this.values = { ...values, ...savedValues };
};
getValue<V extends Values>(valueName: V) {
return this.values[valueName];
}

View File

@ -1,142 +1,5 @@
export type CalculationValues = {
lead: string | null;
opportunity: string | null;
quote: string | null;
recalcWithRevision: boolean;
product: string | null;
clientRisk: string | null;
clientType: string | null;
leaseObjectPrice: number;
supplierCurrency: string | null;
supplierDiscountRub: number;
supplierDiscountPerc: number;
leasingPeriod: number;
firstPaymentPerc: number;
firstPaymentRub: number;
lastPaymentPerc: number;
lastPaymentRub: number;
lastPaymentRule: number | null;
importProgram: string | null;
importProgramSum: number;
addEquipmentPrice: number;
redemptionPaymentSum: number;
balanceHolder: number | null;
graphType: number | null;
parmentsDecreasePercent: number;
seasonType: number | null;
highSeasonStart: number | null;
comissionPerc: number;
comissionRub: number;
saleBonus: number;
IRR_Perc: number;
leaseObjectType: string | null;
deliveryTime: number | null;
leaseObjectCount: number;
withTrailer: boolean;
leaseObjectUsed: boolean;
maxMass: number;
countSeats: number;
maxSpeed: number;
brand: string | null;
model: string | null;
configuration: string | null;
leaseObjectYear: number;
engineType: number | null;
leaseObjectCategory: number | null;
leaseObjectMotorPower: number;
engineVolume: number;
leaseObjectUseFor: number | null;
dealer: string | null;
dealerPerson: string | null;
dealerRewardCondition: string | null;
dealerRewardSumm: number;
dealerBroker: string | null;
dealerBrokerRewardCondition: string | null;
dealerBrokerRewardSumm: number;
indAgent: string | null;
indAgentRewardCondition: string | null;
indAgentRewardSumm: number;
calcDoubleAgent: string | null;
calcDoubleAgentRewardCondition: string | null;
calcDoubleAgentRewardSumm: number;
calcBroker: string | null;
calcBrokerRewardCondition: string | null;
calcBrokerRewardSum: number;
calcFinDepartment: string | null;
finDepartmentRewardCondtion: string | null;
finDepartmentRewardSumm: number;
GPSBrand: string | null;
GPSModel: string | null;
regionRegistration: string | null;
townRegistration: string | null;
infuranceOPF: number | null;
insKaskoType: number | null;
insDecentral: boolean;
insFranchise: number;
insUnlimitDrivers: boolean;
insAgeDrivers: number;
insExpDrivers: number;
INNForCalc: number;
lastPaymentRedemption: boolean;
priceWithDiscount: boolean;
fullPriceWithDiscount: boolean;
costIncrease: boolean;
insurance: boolean;
registrationQuote: boolean;
technicalCardQuote: boolean;
NSIB: boolean;
quoteName: string | null;
quoteContactGender: number | null;
quoteRedemptionGraph: boolean;
showFinGAP: boolean;
tarif: string | null;
creditRate: number;
rate: string | null;
requirementTelematic: number | null;
minPriceChange: number;
maxPriceChange: number;
importerRewardPerc: number;
importerRewardRub: number;
disableChecks: boolean;
registration: string | null;
insNSIB: string | null;
technicalCard: string | null;
telematic: string | null;
tracker: string | null;
mileage: number;
calcType: number | null;
totalPayments: number;
objectRegistration: number | null;
objectRegionRegistration: string | null;
vehicleTaxInYear: number;
vehicleTaxInLeasingPeriod: number;
objectCategoryTax: number | null;
objectTypeTax: number | null;
typePTS: number | null;
legalClientRegion: string | null;
legalClientTown: string | null;
subsidy: string | null;
fuelCard: string | null;
leaseObjectPriceWthtVAT: number;
VATInLeaseObjectPrice: number;
engineHours: number;
bonusCoefficient: number;
/** Link Values */
kpUrl: string | null;
leadUrl: string | null;
opportunityUrl: string | null;
quoteUrl: string | null;
/** Readonly Values */
leaseObjectRiskName: string | null;
insKaskoPriceLeasePeriod: number;
irrInfo: string | null;
registrationDescription: string | null;
depreciationGroup: string | null;
subsidySum: number;
plPriceRub: number;
discountRub: number;
};
import type ValuesSchema from 'config/schema/values';
import type { z } from 'zod';
export type CalculationValues = z.infer<typeof ValuesSchema>;
export type Values = keyof CalculationValues;

9
stores/process/index.ts Normal file
View File

@ -0,0 +1,9 @@
import type { ObservableSet } from 'mobx';
import { observable } from 'mobx';
export type Process = 'LoadKP' | 'ELT';
export type ProcessStore = ObservableSet<Process>;
export default function createProcessStore() {
return observable.set<Process>();
}

View File

@ -1,6 +1,8 @@
/* eslint-disable import/no-cycle */
import { enableStaticRendering } from 'mobx-react-lite';
import CalculationStore from './calculation';
import type { ProcessStore } from './process';
import createProcessStore from './process';
import ResultsStore from './results';
import TablesStore from './tables';
@ -10,10 +12,12 @@ export default class RootStore {
$calculation: CalculationStore;
$results: ResultsStore;
$tables: TablesStore;
$process: ProcessStore;
constructor() {
this.$calculation = new CalculationStore(this);
this.$results = new ResultsStore(this);
this.$tables = new TablesStore(this);
this.$process = createProcessStore();
}
}

View File

@ -2,7 +2,8 @@ import type * as FinGAP from 'Components/Calculation/Form/Insurance/FinGAPTable/
import type { IObservableArray } from 'mobx';
import { makeAutoObservable, observable } from 'mobx';
import type RootStore from 'stores/root';
import Validation from '../validation';
import Validation from '../../validation';
import type { ValidationParams } from '../../validation/types';
export default class FinGAPTable {
root: RootStore;
@ -13,13 +14,13 @@ export default class FinGAPTable {
constructor(rootStore: RootStore) {
this.selectedKeys = new Set();
this.risks = observable<FinGAP.Risk>([]);
makeAutoObservable(this);
this.validation = new Validation({
err_key: 'ERR_FINGAP_TABLE',
err_title: 'Таблица рисков Safe Finance',
});
makeAutoObservable(this);
this.root = rootStore;
}
@ -37,6 +38,14 @@ export default class FinGAPTable {
.reduce((sum, risk) => sum + risk.premium, 0);
}
validate = ({ invalid, message }: ValidationParams) => {
if (invalid) {
this.validation?.addError(message);
} else {
this.validation?.removeError(message);
}
};
clear = () => {
this.risks.clear();
this.selectedKeys.clear();

View File

@ -3,7 +3,8 @@ import type * as Insurance from 'Components/Calculation/Form/Insurance/Insurance
import * as insuranceTableConfig from 'config/tables/insurance-table';
import { makeAutoObservable } from 'mobx';
import type RootStore from 'stores/root';
import Validation from '../validation';
import Validation from '../../validation';
import type { ValidationParams } from '../../validation/types';
export interface InsuranceTableData {
values?: Insurance.RowValues[];
@ -19,12 +20,13 @@ export default class InsuranceTable {
statuses: Record<Insurance.Keys, Insurance.RowStatuses> = insuranceTableConfig.defaultStatuses;
constructor(rootStore: RootStore) {
this.root = rootStore;
this.validation = new Validation({
err_key: 'ERR_INSURANCE_TABLE',
err_title: 'Таблица страхования',
});
makeAutoObservable(this);
this.root = rootStore;
}
hydrate = ({
@ -49,6 +51,8 @@ export default class InsuranceTable {
if (rowIndex >= 0) {
this.values[rowIndex] = { ...this.values[rowIndex], ...rowValues };
}
return this;
};
getRowOptions(key: Insurance.Keys) {
@ -65,12 +69,81 @@ export default class InsuranceTable {
setRowStatuses = (key: Insurance.Keys, rowStatuses: Partial<Insurance.RowStatuses>) => {
this.statuses[key] = { ...this.statuses[key], ...rowStatuses };
return this;
};
reset = () => {
validate = ({ invalid, message }: ValidationParams) => {
if (invalid) {
this.validation?.addError(message);
} else {
this.validation?.removeError(message);
}
};
resetTable = () => {
this.values = insuranceTableConfig.defaultValues;
this.options = insuranceTableConfig.defaultOptions;
this.statuses = insuranceTableConfig.defaultStatuses;
this.validation.clearErrors();
};
row = <K extends Insurance.Keys>(key: K) => ({
setValue: <V extends Insurance.Values>(valueName: V, value: Insurance.RowValues[V]) => {
const rowIndex = this.values.findIndex((x) => x.key === key);
if (rowIndex >= 0) {
this.values[rowIndex] = { ...this.values[rowIndex], [valueName]: value };
}
return this.row(key);
},
block: (valueName: Insurance.Values) => {
this.statuses[key][valueName] = 'Disabled';
return this.row(key);
},
unblock: (valueName: Insurance.Values) => {
this.statuses[key][valueName] = 'Default';
return this.row(key);
},
setOptions: <V extends Insurance.Values>(valueName: V, options: Insurance.RowOptions[V]) => {
this.options[key][valueName] = options;
return this.row(key);
},
resetValue: (valueName: Insurance.Values) => {
const rowIndex = this.values.findIndex((x) => x.key === key);
if (rowIndex >= 0) {
const defaultValue = insuranceTableConfig.defaultValues[rowIndex][valueName];
this.values[rowIndex] = { ...this.values[rowIndex], [valueName]: defaultValue };
}
return this.row(key);
},
resetStatus: (valueName: Insurance.Values) => {
this.statuses[key][valueName] = insuranceTableConfig.defaultStatuses[key][valueName];
return this.row(key);
},
resetOptions: <V extends Insurance.Values>(valueName: V) => {
this.options[key][valueName] = insuranceTableConfig.defaultOptions[key][valueName];
return this.row(key);
},
reset: (valueName: Insurance.Values) => {
this.row(key).resetValue(valueName).resetStatus(valueName).resetOptions(valueName);
return this.row(key);
},
});
}

View File

@ -3,7 +3,8 @@ import type { IObservableArray } from 'mobx';
import { makeAutoObservable, observable, reaction } from 'mobx';
import type RootStore from 'stores/root';
import Validation from '../validation';
import Validation from '../../validation';
import type { ValidationParams } from '../../validation/types';
import type { Row } from './types';
export default class PaymentsTable {
@ -13,14 +14,16 @@ export default class PaymentsTable {
statuses: IObservableArray<Status>;
constructor(rootStore: RootStore) {
this.root = rootStore;
this.validation = new Validation({
err_key: 'ERR_PAYMENTS_TABLE',
err_title: 'Таблица платежей',
});
this.values = observable<number>([]);
this.statuses = observable<Status>([]);
makeAutoObservable(this);
this.root = rootStore;
/**
* Синхронизируем длину массива значений и статусов
@ -70,6 +73,14 @@ export default class PaymentsTable {
this.setStatuses(statuses);
};
validate = ({ invalid, message }: ValidationParams) => {
if (invalid) {
this.validation?.addError(message);
} else {
this.validation?.removeError(message);
}
};
reset = () => {
this.values.clear();
this.statuses.clear();

View File

@ -0,0 +1,20 @@
import type { ObservableSet } from 'mobx';
import { observable } from 'mobx';
import type { RemoveError } from './types';
export default class ValidationHelper {
errors: ObservableSet<RemoveError>;
constructor() {
this.errors = observable.set();
}
add = (removeError: RemoveError) => {
this.errors.add(removeError);
};
removeErrors = () => {
this.errors.forEach((removeError) => removeError());
this.errors.clear();
};
}

View File

@ -1,17 +1,13 @@
import notification from 'Elements/notification';
import { makeAutoObservable } from 'mobx';
type Params = {
err_key: string;
err_title: string;
};
import type { ValidationConfig } from './types';
export default class Validation {
params: Params;
params: ValidationConfig;
messages: Set<string>;
constructor(params: Params) {
this.params = params;
constructor(config: ValidationConfig) {
this.params = config;
this.messages = new Set();
makeAutoObservable(this);
}
@ -24,24 +20,25 @@ export default class Validation {
return [...this.messages];
}
removeError = (message: string) => {
this.messages.delete(message);
if (this.messages.size === 0) notification.close(this.params.err_key);
};
addError = (message: string) => {
this.messages.add(message);
const removeError = () => {
this.messages.delete(message);
notification.close(this.params.err_key);
};
notification.error({
key: this.params.err_key,
message: this.params.err_title,
description: message,
});
return removeError;
return () => this.removeError(message);
};
clearErrors = () => {
this.messages.clear();
notification.close(this.params.err_key);
};
}

View File

@ -0,0 +1,11 @@
export type ValidationConfig = {
err_key: string;
err_title: string;
};
export type ValidationParams = {
invalid: boolean;
message: string;
};
export type RemoveError = () => void;

23
tools/mobx.ts Normal file
View File

@ -0,0 +1,23 @@
/* eslint-disable import/prefer-default-export */
import type { IReactionDisposer } from 'mobx';
import { autorun } from 'mobx';
export function makeDisposable(
createReaction: () => IReactionDisposer,
mustBeDisposed: () => boolean
) {
let disposer: IReactionDisposer | undefined;
function cleanDisposer() {
disposer = undefined;
}
autorun(() => {
if (mustBeDisposed()) {
if (disposer !== undefined) disposer();
cleanDisposer();
} else {
disposer = createReaction();
}
});
}

35
trpc/client.ts Normal file
View File

@ -0,0 +1,35 @@
import { createTRPCProxyClient, httpBatchLink } from '@trpc/client';
import { createTRPCNext } from '@trpc/next';
import SuperJSON from 'superjson';
import type { AppRouter } from './routers';
function getBaseUrl() {
if (typeof window !== 'undefined') {
return process.env.NEXT_PUBLIC_BASE_PATH ?? '';
}
return `http://localhost:${process.env.PORT ?? 3000}${process.env.NEXT_PUBLIC_BASE_PATH ?? ''}`;
}
export const trpcClient = createTRPCNext<AppRouter>({
config() {
return {
links: [
httpBatchLink({
url: `${getBaseUrl()}/api/trpc`,
}),
],
transformer: SuperJSON,
};
},
ssr: true,
});
export const trpcPureClient = createTRPCProxyClient<AppRouter>({
links: [
httpBatchLink({
url: `${getBaseUrl()}/api/trpc`,
}),
],
transformer: SuperJSON,
});

10
trpc/routers/index.ts Normal file
View File

@ -0,0 +1,10 @@
import { t } from '../server';
import quoteRouter from './quote';
const appRouter = t.router({
quote: quoteRouter,
});
export type AppRouter = typeof appRouter;
export default appRouter;

32
trpc/routers/quote.ts Normal file
View File

@ -0,0 +1,32 @@
import defaultValues from 'config/default-values';
import ValuesSchema from 'config/schema/values';
import getSupplierAgentsDataFromKP from 'process/supplier-agent/get-kp-values';
import { z } from 'zod';
import { t } from '../server';
const quoteRouter = t.router({
getValues: t.procedure
.input(
z.object({
values: ValuesSchema.pick({
quote: true,
}),
})
)
.output(
z.object({
values: ValuesSchema,
})
)
.query(async ({ input }) => {
const { values } = await getSupplierAgentsDataFromKP({
quoteId: input.values.quote!,
});
return {
values: Object.assign(defaultValues, values),
};
}),
});
export default quoteRouter;

7
trpc/server.ts Normal file
View File

@ -0,0 +1,7 @@
/* eslint-disable import/prefer-default-export */
import { initTRPC } from '@trpc/server';
import SuperJSON from 'superjson';
export const t = initTRPC.create({
transformer: SuperJSON,
});

5
trpc/types.ts Normal file
View File

@ -0,0 +1,5 @@
import type { trpcClient, trpcPureClient } from './client';
export type TRPCClient = typeof trpcClient;
export type TRPCPureClient = typeof trpcPureClient;

View File

@ -2078,17 +2078,17 @@
dependencies:
tslib "^2.4.0"
"@tanstack/query-core@4.13.0":
version "4.13.0"
resolved "https://registry.yarnpkg.com/@tanstack/query-core/-/query-core-4.13.0.tgz#89153096d1fce42c0294fa1d1ae4b3e72aa5353b"
integrity sha512-PzmLQcEgC4rl2OzkiPHYPC9O79DFcMGaKsOzDEP+U4PJ+tbkcEP+Z+FQDlfvX8mCwYC7UNH7hXrQ5EdkGlJjVg==
"@tanstack/query-core@4.14.1":
version "4.14.1"
resolved "https://registry.yarnpkg.com/@tanstack/query-core/-/query-core-4.14.1.tgz#a74c4da03e79a8be07fa5ab2ebc12865146915e2"
integrity sha512-mUejKoFDe4NZB8jQJR1uuAl6IwvkUpOD2m8NcuTVPOu0pcxeeFPdrnHaljwOEFPtlqXoiiIIQGYy6whjCMN+iQ==
"@tanstack/react-query@^4.13.0":
version "4.13.0"
resolved "https://registry.yarnpkg.com/@tanstack/react-query/-/react-query-4.13.0.tgz#13797d590a6c0708545881e38aea5eb39b960c28"
integrity sha512-dI/5hJ/pGQ74P5hxBLC9h6K0/Cap2T3k0ZjjjFLBCNnohDYgl7LNmMopzrRzBHk2mMjf2hgXHIzcKNG8GOZ5hg==
"@tanstack/react-query@^4.14.1":
version "4.14.1"
resolved "https://registry.yarnpkg.com/@tanstack/react-query/-/react-query-4.14.1.tgz#336545119b191e2096c394a3f2df2744cdc5e041"
integrity sha512-cRgNzigw4GSPwGlTEkXi8hi/xgUnSEt9jCkiC8oAT3PEIdsQ50onZcpXd+JNJcZk2RTh8KM1fGyWz6xYLiY8bg==
dependencies:
"@tanstack/query-core" "4.13.0"
"@tanstack/query-core" "4.14.1"
use-sync-external-store "^1.2.0"
"@testing-library/dom@^8.5.0":
@ -2139,6 +2139,28 @@
resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-2.0.0.tgz#f544a148d3ab35801c1f633a7441fd87c2e484bf"
integrity sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==
"@trpc/client@^10.0.0-rc.3":
version "10.0.0-rc.3"
resolved "https://registry.yarnpkg.com/@trpc/client/-/client-10.0.0-rc.3.tgz#22cea038dd5e38ce0e39ff4a339793bb5808ab18"
integrity sha512-gZYVfZra1YB2DluDY+GcIrL7KqPXCI9y0mF4utXYAUAl+jrxfLyG63pCv30USRRYlwwSKaoLJNpjQB9k05aYaw==
"@trpc/next@^10.0.0-rc.3":
version "10.0.0-rc.3"
resolved "https://registry.yarnpkg.com/@trpc/next/-/next-10.0.0-rc.3.tgz#2585aa271c2916afb2f7291583c9299c324f799d"
integrity sha512-L9sHV93dPA4lZ/I8opfn3BJONnlnnJzJERggv7srt8H3aEhKVlNWIqxciNLHGXSq9q0C9i3Q6ND4F5kpRSQ5YA==
dependencies:
react-ssr-prepass "^1.5.0"
"@trpc/react-query@^10.0.0-rc.3":
version "10.0.0-rc.3"
resolved "https://registry.yarnpkg.com/@trpc/react-query/-/react-query-10.0.0-rc.3.tgz#34a0449c62544522d1fa0f07844d1f11cf38eb55"
integrity sha512-nEBqkTdKsd+vIE4RuDRX/b8U5ayxENp0G2vnh/fn4hiIszrLiPTGvnhGCZm/fT2GGW5nk7EEBcqf2o0z3r8Ftg==
"@trpc/server@^10.0.0-rc.3":
version "10.0.0-rc.3"
resolved "https://registry.yarnpkg.com/@trpc/server/-/server-10.0.0-rc.3.tgz#4ddc4410305b17a47248b3bfa881df3b52202e60"
integrity sha512-aSs3uDQ5wumwVjtxj855WLDjlDC+v50QoqHzvuptI33NhJZV7meu0pU2EJkrSZXFt27CSNfP9o2ZPfoReoPUuw==
"@tsconfig/node10@^1.0.7":
version "1.0.9"
resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.9.tgz#df4907fc07a886922637b15e02d4cebc4c0021b2"
@ -3897,6 +3919,13 @@ copy-anything@^2.0.1:
dependencies:
is-what "^3.14.1"
copy-anything@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/copy-anything/-/copy-anything-3.0.2.tgz#7189171ff5e1893b2287e8bf574b8cd448ed50b1"
integrity sha512-CzATjGXzUQ0EvuvgOCI6A4BGOo2bcVx8B+eC2nF862iv9fopnPQwlrbACakNCHRIJbCSBj+J/9JeDf60k64MkA==
dependencies:
is-what "^4.1.6"
copy-to-clipboard@^3.2.0:
version "3.3.1"
resolved "https://registry.yarnpkg.com/copy-to-clipboard/-/copy-to-clipboard-3.3.1.tgz#115aa1a9998ffab6196f93076ad6da3b913662ae"
@ -5928,6 +5957,11 @@ is-what@^3.14.1:
resolved "https://registry.yarnpkg.com/is-what/-/is-what-3.14.1.tgz#e1222f46ddda85dead0fd1c9df131760e77755c1"
integrity sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==
is-what@^4.1.6:
version "4.1.7"
resolved "https://registry.yarnpkg.com/is-what/-/is-what-4.1.7.tgz#c41dc1d2d2d6a9285c624c2505f61849c8b1f9cc"
integrity sha512-DBVOQNiPKnGMxRMLIYSwERAS5MVY1B7xYiGnpgctsOFvVDz9f9PFXXxMcTOHuoqYp4NK9qFYQaIC1NRRxLMpBQ==
is-windows@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d"
@ -8315,6 +8349,11 @@ react-is@^18.0.0:
resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b"
integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==
react-ssr-prepass@^1.5.0:
version "1.5.0"
resolved "https://registry.yarnpkg.com/react-ssr-prepass/-/react-ssr-prepass-1.5.0.tgz#bc4ca7fcb52365e6aea11cc254a3d1bdcbd030c5"
integrity sha512-yFNHrlVEReVYKsLI5lF05tZoHveA5pGzjFbFJY/3pOqqjGOmMmqx83N4hIjN2n6E1AOa+eQEUxs3CgRnPmT0RQ==
react@^18.2.0:
version "18.2.0"
resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5"
@ -9178,6 +9217,13 @@ styled-system@^5.0.0, styled-system@^5.1.5:
"@styled-system/variant" "^5.1.5"
object-assign "^4.1.1"
superjson@^1.11.0:
version "1.11.0"
resolved "https://registry.yarnpkg.com/superjson/-/superjson-1.11.0.tgz#f6e2ae0d8fbac61c3fca09ab6739ac9678414d1b"
integrity sha512-6PfAg1FKhqkwWvPb2uXhH4MkMttdc17eJ91+Aoz4s1XUEDZFmLfFx/xVA3wgkPxAGy5dpozgGdK6V/n20Wj9yg==
dependencies:
copy-anything "^3.0.2"
supports-color@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
@ -10028,3 +10074,8 @@ zen-observable@0.8.15, zen-observable@^0.8.0:
version "0.8.15"
resolved "https://registry.yarnpkg.com/zen-observable/-/zen-observable-0.8.15.tgz#96415c512d8e3ffd920afd3889604e30b9eaac15"
integrity sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ==
zod@^3.19.1:
version "3.19.1"
resolved "https://registry.yarnpkg.com/zod/-/zod-3.19.1.tgz#112f074a97b50bfc4772d4ad1576814bd8ac4473"
integrity sha512-LYjZsEDhCdYET9ikFu6dVPGp2YH9DegXjdJToSzD9rO6fy4qiRYFoyEYwps88OseJlPyl2NOe2iJuhEhL7IpEA==