hl-core 0.0.9-beta.29 → 0.0.9-beta.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/api/base.api.ts CHANGED
@@ -114,6 +114,13 @@ export class ApiClass {
114
114
  });
115
115
  }
116
116
 
117
+ async getEconomicActivityType() {
118
+ return await this.axiosCall<Value[]>({
119
+ method: Methods.GET,
120
+ url: '/Ekk/api/Contragentinsis/DictionaryItems/Questionary?filter=500024',
121
+ });
122
+ }
123
+
117
124
  async getFamilyStatuses() {
118
125
  return await this.axiosCall<Value[]>({
119
126
  method: Methods.GET,
@@ -773,4 +780,83 @@ export class ApiClass {
773
780
  url: `/Arm/api/Dictionary/ProcessGfot/${processCode}`,
774
781
  });
775
782
  }
783
+
784
+ async getClientData(clientId: string) {
785
+ return this.axiosCall({
786
+ method: Methods.GET,
787
+ url: `/${this.productUrl}/api/Application/GetClientData`,
788
+ params: {
789
+ clientId,
790
+ },
791
+ });
792
+ }
793
+
794
+ async getInsuredData(insuredId: string) {
795
+ return this.axiosCall({
796
+ method: Methods.GET,
797
+ url: `/${this.productUrl}/api/Application/GetClientData`,
798
+ params: {
799
+ insuredId,
800
+ },
801
+ });
802
+ }
803
+
804
+ async getBeneficiaryData(beneficiaryId: string) {
805
+ return this.axiosCall({
806
+ method: Methods.GET,
807
+ url: `/${this.productUrl}/api/Application/GetBeneficiaryData`,
808
+ params: {
809
+ beneficiaryId,
810
+ },
811
+ });
812
+ }
813
+
814
+ async saveClientData(clientId: string) {
815
+ return this.axiosCall({
816
+ method: Methods.POST,
817
+ url: `/${this.productUrl}/api/Application/SaveClient`,
818
+ params: {
819
+ clientId,
820
+ },
821
+ });
822
+ }
823
+
824
+ async saveInsuredData(processInstanceId: string, insuredId: string) {
825
+ return this.axiosCall({
826
+ method: Methods.POST,
827
+ url: `/${this.productUrl}/api/Application/SaveInsured`,
828
+ params: {
829
+ processInstanceId,
830
+ insuredId,
831
+ },
832
+ });
833
+ }
834
+
835
+ async saveBeneficiaryData(processInstanceId: string, benificiaryId: string) {
836
+ return this.axiosCall({
837
+ method: Methods.POST,
838
+ url: `/${this.productUrl}/api/Application/SaveBenificiary`,
839
+ params: {
840
+ processInstanceId,
841
+ benificiaryId,
842
+ },
843
+ });
844
+ }
845
+
846
+ async setApplicationData() {
847
+ return this.axiosCall({
848
+ method: Methods.POST,
849
+ url: `/${this.productUrl}/api/Application/SetApplicationData`,
850
+ });
851
+ }
852
+
853
+ async calculate(processInstanceId: string) {
854
+ return this.axiosCall({
855
+ method: Methods.POST,
856
+ url: `/${this.productUrl}/api/Application/Calculator`,
857
+ params: {
858
+ processInstanceId,
859
+ },
860
+ });
861
+ }
776
862
  }
@@ -1,12 +1,30 @@
1
1
  <template>
2
2
  <v-form class="dynamic-form">
3
3
  <base-form-section v-for="(section, sectionIndex) in form.sections" :key="sectionIndex" class="rounded-lg" :title="section.title">
4
- <base-dynamic-input :fields="section.fields" />
4
+ <base-dynamic-input :fields="section.fields" @onClickField="onClickField" />
5
5
  </base-form-section>
6
+ <Teleport v-if="isPanelOpen" to="#right-panel-actions">
7
+ <div :class="[$styles.scrollPage]" class="flex flex-col items-center">
8
+ <base-rounded-input v-model="searchQuery" :label="$dataStore.t('labels.search')" class="w-full p-2" :hide-details="true" />
9
+ <div v-if="panelList && isPanelLoading === false" class="w-full flex flex-col gap-2 p-2">
10
+ <base-panel-select-item :text="$dataStore.t('form.notChosen')" :selected="panelValue.nameRu === null" @click="pickPanelValue(new Value())" />
11
+ <base-panel-select-item
12
+ v-for="(item, index) of panelList.filter(i => i.nameRu && (i.nameRu as string).match(new RegExp(searchQuery, 'i')))"
13
+ :key="index"
14
+ :text="(item.nameRu as string)"
15
+ :selected="item.nameRu === panelValue.nameRu"
16
+ @click="pickPanelValue(item)"
17
+ />
18
+ </div>
19
+ <base-loader v-if="isPanelLoading" class="absolute mt-10" :size="50" />
20
+ </div>
21
+ </Teleport>
6
22
  </v-form>
7
23
  </template>
8
24
 
9
25
  <script lang="ts">
26
+ import { Value } from '#imports';
27
+
10
28
  export default defineComponent({
11
29
  props: {
12
30
  form: {
@@ -14,5 +32,68 @@ export default defineComponent({
14
32
  required: true,
15
33
  },
16
34
  },
35
+ setup() {
36
+ const dataStore = useDataStore();
37
+ const isPanelOpen = ref<boolean>(false);
38
+ const panelValue = ref<Value>(new Value());
39
+ const panelList = ref<Value[]>([]);
40
+ const isPanelLoading = ref<boolean>(false);
41
+ const searchQuery = ref<string>('');
42
+ const listOfPanelTitles: {
43
+ [key in FetchFunctions]: string;
44
+ } = {
45
+ getResidents: 'form.signOfResidency',
46
+ getFamilyStatuses: 'form.familyStatus',
47
+ getRelationTypes: 'form.relations',
48
+ getCountries: 'form.Country',
49
+ getLocalityTypes: 'form.RegionType',
50
+ getStates: 'form.Province',
51
+ getCities: 'form.City',
52
+ getRegions: 'form.Region',
53
+ getDocumentTypes: 'form.documentType',
54
+ getTaxCountries: 'form.countryOfTaxResidency',
55
+ getCitizenshipCountries: 'form.countryOfCitizenship',
56
+ getSectorCodeList: 'form.economySectorCode',
57
+ getInsurancePay: 'form.insurancePay',
58
+ getEconomicActivityType: 'form.typeEconomicActivity',
59
+ getBanks: 'form.bankName',
60
+ getDocumentIssuers: 'form.documentIssuers',
61
+ getGenderList: 'form.gender',
62
+ };
63
+
64
+ const currentField = ref<InputType | null>(null);
65
+
66
+ const pickPanelValue = (item: Value) => {
67
+ if (currentField.value) {
68
+ currentField.value.modelValue = item;
69
+ dataStore.rightPanel.open = false;
70
+ searchQuery.value = '';
71
+ currentField.value = null;
72
+ }
73
+ isPanelOpen.value = false;
74
+ };
75
+
76
+ const onClickField = async (field: InputType) => {
77
+ currentField.value = field;
78
+ if (field.fetchFrom) {
79
+ isPanelLoading.value = true;
80
+ isPanelOpen.value = true;
81
+ dataStore.rightPanel.open = true;
82
+ dataStore.rightPanel.title = dataStore.t(listOfPanelTitles[field.fetchFrom]);
83
+ panelList.value = (await dataStore[field.fetchFrom]()) as Value[];
84
+ isPanelLoading.value = false;
85
+ }
86
+ };
87
+
88
+ return {
89
+ panelValue,
90
+ panelList,
91
+ isPanelOpen,
92
+ isPanelLoading,
93
+ searchQuery,
94
+ pickPanelValue,
95
+ onClickField,
96
+ };
97
+ },
17
98
  });
18
99
  </script>
@@ -5,6 +5,7 @@
5
5
  :control="field"
6
6
  class="bg-[#fff]"
7
7
  :class="{ 'rounded-t-lg': fieldIndex === 0 || fields[fieldIndex - 1].type !== 'text', 'rounded-b-lg': fieldIndex === fields.length - 1 }"
8
+ @onClickField="$emit('onClickField', field)"
8
9
  />
9
10
  <base-switch-input v-if="field.type === 'switch'" :field="field" />
10
11
  </div>
@@ -1,12 +1,12 @@
1
1
  <template>
2
- <div class="base-text-input flex justify-between items-center pr-4 mb-[1px] bg-[#fff]">
2
+ <div class="base-text-input flex justify-between items-center pr-4 mb-[1px] bg-[#fff]" @click="$emit('onClickField')">
3
3
  <v-text-field v-model="control.modelValue" v-bind="textFieldProps" v-maska="mask">
4
4
  <div v-if="hasSuffix" class="absolute top-[27px] left-[18px] flex items-center justify-center">
5
5
  <p class="opacity-0 inline-block mr-[2px]">{{ control.modelValue }}</p>
6
6
  <span>{{ suffix }}</span>
7
7
  </div>
8
8
  </v-text-field>
9
- <v-icon v-if="control.iconName" :icon="`mdi cursor-pointer ${iconsList[control.iconName]}`" color="#A0B3D8" @click="onClickIcon" />
9
+ <v-icon v-if="control.iconName" :icon="`mdi cursor-pointer ${iconsList[control.iconName]}`" color="#A0B3D8" />
10
10
  <vue-date-picker v-if="control.maska === 'date'" v-model="control.modelValue" v-bind="datePickerProps" @update:modelValue="$emit('update:modelValue', $event)">
11
11
  <template #trigger>
12
12
  <v-icon icon="mdi mdi-calendar-blank-outline cursor-pointer" color="#a0b3d8" />
@@ -38,6 +38,7 @@ export default defineComponent({
38
38
  },
39
39
  setup(props) {
40
40
  const mask = computed(() => (props.control.maska ? useMask()[props.control.maska] : ''));
41
+ const dataStore = useDataStore();
41
42
 
42
43
  const textFieldProps = computed(() => {
43
44
  return {
@@ -76,7 +77,12 @@ export default defineComponent({
76
77
  return hasSuffix.value ? suffixList[props.control.suffix!] : '';
77
78
  });
78
79
 
79
- const onClickIcon = () => {};
80
+ const onClickIcon = async () => {
81
+ if (props.control.fetchFrom) {
82
+ dataStore.rightPanel.open = true;
83
+ dataStore.rightPanel.title = 'test panel name';
84
+ }
85
+ };
80
86
 
81
87
  return {
82
88
  // State
@@ -86,7 +92,6 @@ export default defineComponent({
86
92
  mask,
87
93
  suffix,
88
94
  iconsList,
89
-
90
95
  // Functions
91
96
  onClickIcon,
92
97
  };
@@ -891,7 +891,7 @@ export default {
891
891
  isPanelLoading.value = true;
892
892
  newList = await asyncFunction(filterKey, member.value);
893
893
  }
894
- panelList.value = filterList(newList, key);
894
+ panelList.value = filterList(newList, key);
895
895
  panelValue.value = member.value[currentPanel.value];
896
896
  isPanelLoading.value = false;
897
897
  } else {
@@ -1,6 +1,6 @@
1
1
  <template>
2
2
  <section class="flex flex-col gap-4 px-[10px]">
3
- <v-form ref="vForm" @submit="submitForm" class="max-h-[80svh] overflow-y-scroll">
3
+ <v-form ref="vForm" @submit="submitForm" class="overflow-y-scroll" :class="[!$dataStore.isCalculator && isCalculator && hasCalculated ? 'max-h-[73svh]' : 'max-h-[80svh]']">
4
4
  <base-message-block
5
5
  v-if="isCalculator"
6
6
  class="mt-4"
@@ -44,7 +44,7 @@
44
44
  <base-form-input v-model="formStore.policyholderForm.age" :label="$dataStore.t('form.age')" :readonly="true" />
45
45
  <base-form-input v-model="formStore.policyholderForm.gender.nameRu" class="mb-4" :label="$dataStore.t('form.gender')" :readonly="true" />
46
46
  </base-form-section>
47
- <base-form-section v-if="isUnderwriterRole && $dataStore.members.insuredApp.has === true && !$dataStore.isLifeBusiness" :title="$dataStore.t('insuredForm')">
47
+ <base-form-section v-if="isUnderwriterRole && $dataStore.members.insuredApp.has === true && whichProduct !== 'lifebusiness'" :title="$dataStore.t('insuredForm')">
48
48
  <div v-for="(insured, index) of formStore.insuredForm" :key="index">
49
49
  <base-form-input v-model="insured.longName" :label="$dataStore.t('labels.insurerLongName')" :readonly="true" />
50
50
  <base-form-input v-model="insured.job" :label="$dataStore.t('form.job')" :readonly="true" />
@@ -274,7 +274,7 @@
274
274
  :clearable="!isDisabledProcessGfot"
275
275
  :label="$dataStore.t('productConditionsForm.processGfot')"
276
276
  append-inner-icon="mdi mdi-chevron-right"
277
- @append="openPanel($dataStore.t('productConditionsForm.processGfot'), $dataStore.processTariff, 'processGfot', $dataStore.getProcessGfot)"
277
+ @append="openPanel($dataStore.t('productConditionsForm.processGfot'), $dataStore.processGfot, 'processGfot', $dataStore.getProcessGfot)"
278
278
  />
279
279
  </base-form-section>
280
280
  <base-form-section v-if="hasAnnuityPayments" :title="$dataStore.t('calculationAnnuityPayments')">
@@ -629,7 +629,7 @@ export default defineComponent({
629
629
  });
630
630
  const isDisabled = computed(() => (dataStore.isCalculator ? false : !memberStore.isStatementEditible('productConditionsForm')));
631
631
  const isTermsDisabled = computed(() => {
632
- if (dataStore.isGons || whichProduct.value === 'gons') {
632
+ if (whichProduct.value === 'gons') {
633
633
  return true;
634
634
  }
635
635
  return isDisabled.value;
@@ -642,7 +642,7 @@ export default defineComponent({
642
642
  if (dataStore.isUnderwriter() && !isRecalculationDisabled.value) {
643
643
  return false;
644
644
  }
645
- if (dataStore.isLifeBusiness) {
645
+ if (whichProduct.value === 'lifebusiness') {
646
646
  return true;
647
647
  }
648
648
  return isDisabled.value;
@@ -1351,8 +1351,10 @@ export default defineComponent({
1351
1351
  if (defaultData.signDate) {
1352
1352
  productConditionsForm.signDate = reformatDate(defaultData.signDate);
1353
1353
  }
1354
- if (dataStore.isLifeBusiness) {
1354
+ if (whichProduct.value === 'lifebusiness') {
1355
1355
  productConditionsForm.coverPeriod = defaultData.insTermInMonth ?? null;
1356
+ productConditionsForm.requestedSumInsured = null;
1357
+ productConditionsForm.insurancePremiumPerMonth = null;
1356
1358
  }
1357
1359
  }
1358
1360
  }
@@ -1364,7 +1366,7 @@ export default defineComponent({
1364
1366
  if (!!productConditionsForm.requestedSumInsured) {
1365
1367
  whichSum.value = 'requestedSumInsured';
1366
1368
  }
1367
- if (dataStore.isLifeBusiness && !productConditionsForm.requestedSumInsured) {
1369
+ if (whichProduct.value === 'lifebusiness' && !productConditionsForm.requestedSumInsured) {
1368
1370
  whichSum.value = 'requestedSumInsured';
1369
1371
  }
1370
1372
  if (dataStore.isCalculator) {
@@ -27,10 +27,11 @@
27
27
  </div>
28
28
  </section>
29
29
  <section v-if="chooseSignActions">
30
- <div v-if="!isElectronicContract && !isPaperContract && !isScansDocuments" :class="[$styles.flexColNav]">
30
+ <div v-if="!isElectronicContract && !isPaperContract && !isScansDocuments && !isQr" :class="[$styles.flexColNav]">
31
31
  <base-btn :text="$dataStore.t('buttons.sendOnPaper')" :disabled="isPaperDisabled" @click="handleSignAction('paper')" />
32
32
  <base-btn :text="$dataStore.t('buttons.sendElectronically')" :disabled="isElectronicDisabled" @click="handleSignAction('electronic')" />
33
33
  <base-btn :text="$dataStore.t('buttons.generatePrintedForms')" :disabled="isScansDisabled" @click="handleSignAction('scans')" />
34
+ <base-btn :text="$dataStore.t('buttons.sendEgovMob')" :disabled="isQrDisabled" @click="handleSignAction('qr')" />
34
35
  </div>
35
36
  <div v-if="isPaperContract" :class="[$styles.flexColNav]">
36
37
  <base-btn :text="$dataStore.t('buttons.downloadContract')" :loading="$dataStore.isButtonsLoading" @click="generateDocument" />
@@ -50,6 +51,14 @@
50
51
  <base-btn :text="$dataStore.t('buttons.sign')" :loading="$dataStore.isButtonsLoading" @click="sendFiles" />
51
52
  <base-btn :text="$dataStore.t('buttons.cancel')" :btn="$styles.whiteBtn" @click="isScansDocuments = false" />
52
53
  </div>
54
+ <div v-if="isQr" :class="[$styles.flexColNav]">
55
+ <base-form-section :title="''">
56
+ <img width="135" height="135" class="ma-auto" v-if="qrUrl" :src="qrUrl" alt="" />
57
+ <span :class="[$styles.textSimple]" class="mt-3 text-center">{{ $dataStore.t('sign.scanQrCode') }}</span>
58
+ <base-btn class="mt-10" :loading="loading" :text="$dataStore.t('sign.copyEgov')" @click="$dataStore.copyToClipboard(qrUrl)" />
59
+ <base-btn :text="$dataStore.t('buttons.cancel')" :btn="$styles.whiteBtn" @click="isQr = false" />
60
+ </base-form-section>
61
+ </div>
53
62
  </section>
54
63
  <section v-if="signingActions" class="relative">
55
64
  <base-fade-transition>
@@ -169,8 +178,10 @@ export default defineComponent({
169
178
  const loading = ref<boolean>(false);
170
179
  const isPaperContract = ref<boolean>(false);
171
180
  const isScansDocuments = ref<boolean>(false);
181
+ const isQr = ref<boolean>(false);
172
182
  const isElectronicContract = ref<boolean>(true);
173
183
  const email = ref<string>('');
184
+ const qrUrl = ref<string>('');
174
185
 
175
186
  const vForm = ref<any>();
176
187
  const isSendNumberOpen = ref<boolean>(false);
@@ -408,6 +419,12 @@ export default defineComponent({
408
419
  }
409
420
  return false;
410
421
  });
422
+ const isQrDisabled = computed(() => {
423
+ if (dataStore.isLifeBusiness) {
424
+ return false;
425
+ }
426
+ return true;
427
+ });
411
428
  const downloadTemplate = async () => {
412
429
  dataStore.panel.open = false;
413
430
  dataStore.panelAction = null;
@@ -424,7 +441,7 @@ export default defineComponent({
424
441
  });
425
442
  };
426
443
 
427
- const handleSignAction = async (type: 'paper' | 'electronic' | 'scans') => {
444
+ const handleSignAction = async (type: 'paper' | 'electronic' | 'scans' | 'qr') => {
428
445
  if (type === 'electronic') {
429
446
  await dataStore.signDocument();
430
447
  isElectronicContract.value = true;
@@ -435,6 +452,17 @@ export default defineComponent({
435
452
  if (type === 'scans') {
436
453
  isScansDocuments.value = true;
437
454
  }
455
+ if (type === 'qr') {
456
+ await generateQR();
457
+ isQr.value = true;
458
+ }
459
+ };
460
+
461
+ // TODO Рефактор QR c npm
462
+ const generateQR = async () => {
463
+ const uuid = crypto.randomUUID();
464
+ const qrValue = `${getValuePerEnv('qrGenUrl')}/${uuid}`;
465
+ qrUrl.value = `https://api.qrserver.com/v1/create-qr-code/?size=135x135&data=${qrValue}`;
438
466
  };
439
467
 
440
468
  const generateDocument = async () => {
@@ -455,6 +483,8 @@ export default defineComponent({
455
483
  isPaperContract,
456
484
  isScansDocuments,
457
485
  email,
486
+ isQr,
487
+ qrUrl,
458
488
  // Functions
459
489
  closePanel,
460
490
  submitForm,
@@ -488,6 +518,7 @@ export default defineComponent({
488
518
  isPaperDisabled,
489
519
  isElectronicDisabled,
490
520
  isScansDisabled,
521
+ isQrDisabled,
491
522
  };
492
523
  },
493
524
  });
@@ -980,6 +980,7 @@ export class DataStoreClass {
980
980
  residents: Value[];
981
981
  ipdl: Value[];
982
982
  economySectorCode: Value[];
983
+ economicActivityType: Value[];
983
984
  gender: Value[];
984
985
  fontSize: number;
985
986
  isFontChangerOpen: boolean = false;
@@ -1152,6 +1153,7 @@ export class DataStoreClass {
1152
1153
  this.residents = [];
1153
1154
  this.ipdl = [new Value(1, null), new Value(2, 'Да'), new Value(3, 'Нет')];
1154
1155
  this.economySectorCode = [];
1156
+ this.economicActivityType = [];
1155
1157
  this.gender = [new Value(0, null), new Value(1, 'Мужской'), new Value(2, 'Женский')];
1156
1158
  this.fontSize = 14;
1157
1159
  this.isFontChangerOpen = false;
@@ -1437,7 +1439,7 @@ export class MemberV2 {
1437
1439
  resident: Value;
1438
1440
  taxResidentCountry: Value;
1439
1441
  economySectorCode: Value;
1440
- isActualAddressEqualLegalAddres: boolean;
1442
+ isPublicPerson: boolean;
1441
1443
  identityDocument?: {
1442
1444
  documentType: Value;
1443
1445
  documentNumber: string | null;
@@ -1476,6 +1478,7 @@ export class MemberV2 {
1476
1478
  organizationEmail: string | null;
1477
1479
  organizationInternetResource: string | null;
1478
1480
  organizationStartDate: string | null;
1481
+ isActualAddressEqualLegalAddres: boolean;
1479
1482
  activityTypes: {
1480
1483
  activityTypeName: string | null;
1481
1484
  empoloyeeCount: number | null;
@@ -1498,7 +1501,7 @@ export class MemberV2 {
1498
1501
  this.resident = new Value();
1499
1502
  this.taxResidentCountry = new Value();
1500
1503
  this.economySectorCode = new Value();
1501
- this.isActualAddressEqualLegalAddres = true;
1504
+ this.isPublicPerson = false;
1502
1505
  this.identityDocument = {
1503
1506
  documentType: new Value(),
1504
1507
  documentNumber: null,
@@ -1537,6 +1540,7 @@ export class MemberV2 {
1537
1540
  organizationEmail: null,
1538
1541
  organizationInternetResource: null,
1539
1542
  organizationStartDate: null,
1543
+ isActualAddressEqualLegalAddres: true,
1540
1544
  activityTypes: [
1541
1545
  {
1542
1546
  activityTypeName: null,
@@ -1544,7 +1548,7 @@ export class MemberV2 {
1544
1548
  },
1545
1549
  ],
1546
1550
  };
1547
- this.isLeader = true;
1551
+ this.isLeader = false;
1548
1552
  this.beneficalOwnerQuest = [
1549
1553
  {
1550
1554
  order: 0,
@@ -0,0 +1,203 @@
1
+ import { i18n } from '../configs/i18n';
2
+ import { FieldTypes } from '../types/form';
3
+
4
+ const t = i18n.t;
5
+
6
+ export const FieldBase = ({
7
+ label = '',
8
+ placeholder = '',
9
+ readonly = false,
10
+ disabled = false,
11
+ modelValue = null,
12
+ iconName = null,
13
+ rules = [],
14
+ maxLength = null,
15
+ clearable = true,
16
+ hint = undefined,
17
+ suffix = null,
18
+ maska = null,
19
+ key = '',
20
+ fetchFrom = null,
21
+ }: InputBase): InputBase =>
22
+ ({
23
+ label,
24
+ placeholder,
25
+ readonly,
26
+ disabled,
27
+ modelValue,
28
+ iconName,
29
+ rules,
30
+ maxLength,
31
+ clearable,
32
+ hint,
33
+ suffix,
34
+ maska,
35
+ key,
36
+ fetchFrom,
37
+ } as InputBase);
38
+
39
+ export const TextInput = ({ ...rest }: Partial<TextInput>): TextInput => {
40
+ return {
41
+ ...FieldBase(rest),
42
+ type: FieldTypes.TEXT,
43
+ };
44
+ };
45
+
46
+ export const SwitchInput = ({ ...rest }: Partial<SwitchInput>): SwitchInput => {
47
+ return {
48
+ ...FieldBase(rest),
49
+ type: FieldTypes.SWITCH,
50
+ direction: 'horizontal',
51
+ trueValue: null,
52
+ falseValue: null,
53
+ labeling: false,
54
+ };
55
+ };
56
+
57
+ export const NumberInput = ({ ...rest }: Partial<NumberInput>): NumberInput => {
58
+ return {
59
+ ...FieldBase(rest),
60
+ type: FieldTypes.NUMBER,
61
+ };
62
+ };
63
+
64
+ export const dynamic = <T>(obj: T, key: keyof T) => {
65
+ return computed({
66
+ get: () => {
67
+ const value = obj[key];
68
+ if (typeof value === 'object' && value) {
69
+ if ('nameRu' in value) return value.nameRu as any;
70
+ }
71
+ return value;
72
+ },
73
+ set: (val: any) => {
74
+ obj[key] = val;
75
+ },
76
+ });
77
+ };
78
+
79
+ type PersonalDataKeys = 'iin' | 'phoneNumber' | 'lastName' | 'firstName' | 'middleName' | 'citizenship' | 'position' | 'email' | 'gender';
80
+ type PersonalData = Record<PersonalDataKeys, InputType>;
81
+
82
+ type AddressesKeys = 'country' | 'province' | 'regionType' | 'city' | 'quarter' | 'microDistrict' | 'street' | 'houseNumber';
83
+ type Address = Record<AddressesKeys, InputType>;
84
+
85
+ type RepeatedFields = {
86
+ personalData: PersonalData;
87
+ address: Address;
88
+ };
89
+
90
+ export const RepeatedFields: RepeatedFields = {
91
+ personalData: {
92
+ iin: TextInput({
93
+ label: t('form.iin'),
94
+ maska: 'iin',
95
+ }),
96
+ phoneNumber: TextInput({
97
+ label: t('form.phoneNumber'),
98
+ maska: 'phone',
99
+ }),
100
+ lastName: TextInput({
101
+ label: t('form.lastName'),
102
+ }),
103
+ firstName: TextInput({
104
+ label: t('form.firstName'),
105
+ }),
106
+ middleName: TextInput({
107
+ label: t('form.middleName'),
108
+ }),
109
+ citizenship: TextInput({
110
+ label: t('clients.form.citizenship'),
111
+ iconName: 'arrowRight',
112
+ fetchFrom: 'getCountries',
113
+ }),
114
+ position: TextInput({
115
+ label: t('clients.form.namePosition'),
116
+ }),
117
+ email: TextInput({
118
+ label: t('form.email'),
119
+ }),
120
+ gender: TextInput({
121
+ label: t('form.gender'),
122
+ }),
123
+ },
124
+ address: {
125
+ country: TextInput({
126
+ label: t('form.Country'),
127
+ iconName: 'arrowRight',
128
+ fetchFrom: 'getCountries',
129
+ }),
130
+ province: TextInput({
131
+ label: t('form.Province'),
132
+ iconName: 'arrowRight',
133
+ fetchFrom: 'getStates',
134
+ }),
135
+ regionType: TextInput({
136
+ label: t('form.RegionType'),
137
+ iconName: 'arrowRight',
138
+ fetchFrom: 'getLocalityTypes',
139
+ }),
140
+ city: TextInput({
141
+ label: t('form.City'),
142
+ iconName: 'arrowRight',
143
+ fetchFrom: 'getCities',
144
+ }),
145
+ quarter: TextInput({
146
+ label: t('form.Quarter'),
147
+ }),
148
+ microDistrict: TextInput({
149
+ label: t('form.MicroDistrict'),
150
+ }),
151
+ street: TextInput({
152
+ label: t('form.Street'),
153
+ }),
154
+ houseNumber: TextInput({
155
+ label: t('form.NumberHouse'),
156
+ }),
157
+ },
158
+ };
159
+
160
+ export class BaseFields {
161
+ public mutatedList: InputType[] = [];
162
+ public fieldsLength: number = 0;
163
+
164
+ init<T extends keyof RepeatedFields>(sectionName: T, fieldsOrder?: (keyof RepeatedFields[T])[] | null, excludeFields?: (keyof RepeatedFields[T])[] | null): InputType[] {
165
+ const inputsWithDefinedKey = Object.entries(RepeatedFields[sectionName]).map(([key, field]: [string, InputType]) => {
166
+ return { ...field, key };
167
+ });
168
+
169
+ const originalFields = Object.values(RepeatedFields[sectionName]);
170
+
171
+ if (fieldsOrder && !excludeFields) {
172
+ this.fieldsLength = fieldsOrder.length;
173
+ return inputsWithDefinedKey
174
+ .filter((field: InputType) => fieldsOrder.includes(field.key))
175
+ .sort((a: InputType, b: InputType) => {
176
+ return fieldsOrder.indexOf(a.key) - fieldsOrder.indexOf(b.key);
177
+ });
178
+ }
179
+
180
+ if (!fieldsOrder && excludeFields) {
181
+ this.fieldsLength = originalFields.length - excludeFields.length;
182
+ return inputsWithDefinedKey.filter((field: InputType) => !excludeFields.includes(field.key));
183
+ }
184
+
185
+ this.fieldsLength = originalFields.length;
186
+ return originalFields;
187
+ }
188
+
189
+ setModels(modelList: any[]) {
190
+ if (modelList.length !== this.fieldsLength) {
191
+ throw new Error('Invalid v-models');
192
+ } else {
193
+ return this.mutatedList.map((field: InputType, index: number) => {
194
+ return { ...field, modelValue: modelList[index] };
195
+ });
196
+ }
197
+ }
198
+
199
+ getFields<T extends keyof RepeatedFields>(sectionName: T, fieldsOrder?: (keyof RepeatedFields[T])[] | null, excludeFields?: (keyof RepeatedFields[T])[] | null): this {
200
+ this.mutatedList = this.init(sectionName, fieldsOrder, excludeFields);
201
+ return this;
202
+ }
203
+ }
@@ -2,7 +2,6 @@ import { useDisplay } from 'vuetify';
2
2
  import jwt_decode from 'jwt-decode';
3
3
  import { XMLParser } from 'fast-xml-parser';
4
4
  import { AxiosError } from 'axios';
5
- import { FieldTypes } from '../types/form';
6
5
 
7
6
  export const getBaseCredentials = () => {
8
7
  return {
@@ -286,67 +285,20 @@ export const getLastDayOfMonth = (year: number, month: number) => {
286
285
  return new Date(year, month + 1, 0, (date.getTimezoneOffset() / 60) * -1).toISOString();
287
286
  };
288
287
 
289
- export const FieldBase = ({
290
- label = '',
291
- placeholder = '',
292
- readonly = false,
293
- disabled = false,
294
- modelValue = null,
295
- iconName = null,
296
- rules = [],
297
- maxLength = null,
298
- clearable = true,
299
- hint = undefined,
300
- suffix = null,
301
- maska = null,
302
- }: InputBase): InputBase =>
303
- ({
304
- label,
305
- placeholder,
306
- readonly,
307
- disabled,
308
- modelValue,
309
- iconName,
310
- rules,
311
- maxLength,
312
- clearable,
313
- hint,
314
- suffix,
315
- maska,
316
- } as InputBase);
317
-
318
- export const TextInput = ({ ...rest }: Partial<TextInput>): TextInput => {
319
- return {
320
- ...FieldBase(rest),
321
- type: FieldTypes.TEXT,
322
- };
323
- };
324
-
325
- export const SwitchInput = ({ ...rest }: Partial<SwitchInput>): SwitchInput => {
326
- return {
327
- ...FieldBase(rest),
328
- type: FieldTypes.SWITCH,
329
- direction: 'horizontal',
330
- trueValue: null,
331
- falseValue: null,
332
- labeling: false,
333
- };
334
- };
335
-
336
- export const NumberInput = ({ ...rest }: Partial<NumberInput>): NumberInput => {
337
- return {
338
- ...FieldBase(rest),
339
- type: FieldTypes.NUMBER,
340
- };
341
- };
342
-
343
- export const dynamic = <T>(obj: T, key: keyof T) => {
344
- return computed({
345
- get: () => {
346
- return obj[key];
347
- },
348
- set: (val: any) => {
349
- obj[key] = val;
288
+ type WhichValuePerEnv = 'qrGenUrl';
289
+
290
+ export const getValuePerEnv = (which: WhichValuePerEnv) => {
291
+ type Envs = Exclude<EnvModes, 'vercel'>;
292
+ const valuesPerEnv: {
293
+ [key in WhichValuePerEnv]: {
294
+ [key in Envs]: string;
295
+ };
296
+ } = {
297
+ qrGenUrl: {
298
+ production: 'mobileSign:https://test-sign.halyklife.kz/EgovQr',
299
+ development: 'mobileSign:https://test-sign.halyklife.kz/EgovQr',
300
+ test: 'mobileSign:https://test-sign.halyklife.kz/EgovQr',
350
301
  },
351
- });
302
+ };
303
+ return valuesPerEnv[which][useEnv().envMode as Envs];
352
304
  };
package/locales/ru.json CHANGED
@@ -210,7 +210,8 @@
210
210
  "generatePrintedForms": "Сформировать печатные формы",
211
211
  "downloadStatement": "Скачать заявление",
212
212
  "downloadApplication": "Скачать приложение №1",
213
- "downloadPowerOfAttorney": "Скачать доверенность"
213
+ "downloadPowerOfAttorney": "Скачать доверенность",
214
+ "sendEgovMob": "Отправить на подпись через Egov Mobile"
214
215
  },
215
216
  "dialog": {
216
217
  "title": "Подтверждение",
@@ -261,7 +262,9 @@
261
262
  "codeFromSMS": "Код из СМС",
262
263
  "signEgov": "Подписать с помощью eGov mobile",
263
264
  "showQR": "Показать QR-код",
264
- "timer": "Вы создали счет на оплату, через 00:59 сек счет станет не активным"
265
+ "timer": "Вы создали счет на оплату, через 00:59 сек счет станет не активным",
266
+ "copyEgov": "Скопировать ссылку на подпись через Egov",
267
+ "scanQrCode": "Отсканируйте этот QR-код в приложении, чтобы осуществить подписание"
265
268
  },
266
269
  "questionnaireType": {
267
270
  "byHealth": "Анкета по здоровью Застрахованного",
@@ -363,7 +366,15 @@
363
366
  "totalRequestedSumInsured": "Общая страховая сумма",
364
367
  "totalInsurancePremiumAmount": "Общая страховая премия",
365
368
  "agencyPart": "Агентская переменная часть, %",
366
- "processGfot": "Кратность страховой суммы к ГФОТ-у"
369
+ "processGfot": "Кратность страховой суммы к ГФОТ-у",
370
+ "annuiteStartDate": "Дата расчета",
371
+ "annuityFullPaymentPeriod": "Срок аннуитетных выплат (с / по)",
372
+ "guaranteedFullPaymentPeriod": "Период осуществления гарантийных выплат (с / по)",
373
+ "effectiveAnnualpercentage": "Эффективная годовая процентная ставка доходности",
374
+ "factorCurrentValueGP": "Фактор текущей стоимости с учетом гарантированных выплат",
375
+ "alfa": "Расходы от премии, в %",
376
+ "gamma": "Расходы от выплат, в %",
377
+ "mrpPayment": "Выплата на погребение (в тенге)"
367
378
  },
368
379
  "calculatorForm": {
369
380
  "selectedCountries": "Выбранные страны",
@@ -812,6 +823,8 @@
812
823
  "countryOfTaxResidency": "Страна налогового резиденства",
813
824
  "addTaxResidency": "Указать если налоговое резиденство выбрано другое",
814
825
  "economySectorCode": "Код сектора экономики",
826
+ "typeEconomicActivity": "Вид экономической деятельности",
827
+ "bankName": "Наименование банка",
815
828
  "contactsData": "Контакты",
816
829
  "phoneNumber": "Номер телефона",
817
830
  "homePhone": "Домашний номер телефон",
@@ -965,9 +978,22 @@
965
978
  "refundPremiumWithin30days": "Расторжение договора страхования и возврат страховой премии в течении 30/40 дней с даты заключения договора страхования",
966
979
  "transferPremiumOrAmount": "Расторжение договора страхования и перенос выкупной суммы/страховой премии"
967
980
  },
981
+ "reasonsChangeOfContract": {
982
+ "title": "Типы изменении"
983
+ },
984
+ "insuranceConditions": {
985
+ "title": "Условия страхования",
986
+ "grossPremium": "Текущая страховая премия",
987
+ "insValue": "Текущая страховая сумма",
988
+ "redemptionAmount": "Текущая выкупная сумма",
989
+ "bonusInsuredAmount": "Текущая бонусная сумма"
990
+ },
968
991
  "needDocuments": "Необходимо вложить оригинал страхового полиса в разделе “Документы”",
969
- "hasOriginalContract": "Имеется ли оригинал страхового полиса? Да",
992
+ "hasOriginalContract": "Имеется ли оригинал страхового полиса? ",
970
993
  "byAttorney": "По доверенности? Нет",
994
+ "newPolicyholder": "Новый страхователь",
995
+ "newBeneficiary": "Новый(-ые) выгодоприобретатель(-и)",
996
+ "productConditions": "Условие страховых взносов и/или дополнительные условия",
971
997
  "changePolicyholder": "Изменить Страхователя? Нет",
972
998
  "Contract/Policy/Statement": "Договор/Полис/Заявление"
973
999
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hl-core",
3
- "version": "0.0.9-beta.29",
3
+ "version": "0.0.9-beta.30",
4
4
  "license": "MIT",
5
5
  "private": false,
6
6
  "main": "nuxt.config.ts",
@@ -1198,7 +1198,13 @@ export const useDataStore = defineStore('data', {
1198
1198
  return this[whichField];
1199
1199
  },
1200
1200
  async getCountries() {
1201
- return await this.getFromApi('countries', 'getCountries');
1201
+ const response = await this.getFromApi('countries', 'getCountries');
1202
+ const kzIndex = response.findIndex(country => country.ids === 'KZ');
1203
+ if (kzIndex !== -1) {
1204
+ const element = response.splice(kzIndex, 1)[0];
1205
+ response.splice(0, 0, element);
1206
+ }
1207
+ return response;
1202
1208
  },
1203
1209
  async getDicCountries() {
1204
1210
  if (this.isLifetrip) return await this.getFromApi('dicAllCountries', 'getArmDicts', 'DicCountry');
@@ -1290,6 +1296,9 @@ export const useDataStore = defineStore('data', {
1290
1296
  async getSectorCodeList() {
1291
1297
  return await this.getFromApi('economySectorCode', 'getSectorCode');
1292
1298
  },
1299
+ async getEconomicActivityType() {
1300
+ if (this.isDas) return await this.getFromApi('economicActivityType', 'getEconomicActivityType');
1301
+ },
1293
1302
  async getFamilyStatuses() {
1294
1303
  return await this.getFromApi('familyStatuses', 'getFamilyStatuses');
1295
1304
  },
@@ -1297,7 +1306,7 @@ export const useDataStore = defineStore('data', {
1297
1306
  return await this.getFromApi('relations', 'getRelationTypes');
1298
1307
  },
1299
1308
  async getBanks() {
1300
- if (this.isLifeBusiness) return await this.getFromApi('banks', 'getBanks');
1309
+ if (this.isLifeBusiness || this.isDas) return await this.getFromApi('banks', 'getBanks');
1301
1310
  },
1302
1311
  async getProcessIndexRate() {
1303
1312
  if (this.processCode) {
@@ -1344,6 +1353,9 @@ export const useDataStore = defineStore('data', {
1344
1353
  async getDictionaryItems(dictName: string) {
1345
1354
  return await this.getFromApi(dictName, 'getDictionaryItems', dictName);
1346
1355
  },
1356
+ getGenderList() {
1357
+ return this.gender;
1358
+ },
1347
1359
  async getAllFormsData() {
1348
1360
  await Promise.allSettled([
1349
1361
  this.getCountries(),
@@ -1377,6 +1389,8 @@ export const useDataStore = defineStore('data', {
1377
1389
  this.getDicTripPurpose(),
1378
1390
  this.getCurrencies(),
1379
1391
  this.getProcessGfot(),
1392
+ this.getBanks(),
1393
+ this.getEconomicActivityType(),
1380
1394
  ]);
1381
1395
  },
1382
1396
  async getQuestionList(
@@ -3071,6 +3085,7 @@ export const useDataStore = defineStore('data', {
3071
3085
 
3072
3086
  this.formStore.applicationData.processInstanceId = applicationData.processInstanceId;
3073
3087
  this.formStore.lfb.policyholder = clientData;
3088
+ this.formStore.lfb.policyholder.iin = reformatIin(clientData.iin);
3074
3089
  this.formStore.lfb.clientId = clientId;
3075
3090
  this.formStore.lfb.policyholder.authorityDetails.date = reformatDate(clientData.authorityDetails.date);
3076
3091
 
@@ -3080,6 +3095,7 @@ export const useDataStore = defineStore('data', {
3080
3095
 
3081
3096
  if (beneficialOwnerApp && beneficialOwnerApp.length) {
3082
3097
  this.formStore.lfb.beneficialOwners = beneficialOwnerApp;
3098
+ this.formStore.lfb.isPolicyholderBeneficialOwner = clientData.iin.replace(/-/g, '') === beneficialOwnerApp[0].beneficialOwnerData.iin ? true : false;
3083
3099
  this.formStore.lfb.beneficialOwners.forEach(beneficial => {
3084
3100
  beneficial.beneficialOwnerData.identityDocument!.validUntil = reformatDate(beneficial.beneficialOwnerData.identityDocument!.validUntil as string);
3085
3101
  });
package/store/rules.ts CHANGED
@@ -49,6 +49,7 @@ export const rules = {
49
49
  ],
50
50
  cyrillic: [(v: any) => v === null || /^[\u0400-\u04FF ]+$/.test(v) || t('rules.cyrillic')],
51
51
  latin: [(v: any) => v === null || /^[a-zA-Z]+$/.test(v) || t('rules.latin')],
52
+ latinAndNumber: [(v: any) => v === null || /^[0-9a-zA-Z]+$/.test(v) || t('rules.latinAndNumber')],
52
53
  cyrillicNonRequired: [
53
54
  (v: any) => {
54
55
  if (!v) return true;
package/types/form.ts CHANGED
@@ -15,6 +15,25 @@ declare global {
15
15
  type FormIcons = 'arrowRight' | 'search' | 'sms' | null;
16
16
  type Suffix = 'kzt' | 'usd' | 'percent' | null;
17
17
 
18
+ type FetchFunctions =
19
+ | 'getResidents'
20
+ | 'getFamilyStatuses'
21
+ | 'getRelationTypes'
22
+ | 'getCountries'
23
+ | 'getStates'
24
+ | 'getLocalityTypes'
25
+ | 'getRegions'
26
+ | 'getCities'
27
+ | 'getDocumentTypes'
28
+ | 'getTaxCountries'
29
+ | 'getCitizenshipCountries'
30
+ | 'getSectorCodeList'
31
+ | 'getInsurancePay'
32
+ | 'getEconomicActivityType'
33
+ | 'getBanks'
34
+ | 'getDocumentIssuers'
35
+ | 'getGenderList';
36
+
18
37
  export interface DynamicForm {
19
38
  formRef: any;
20
39
  sections: SectionType[];
@@ -22,6 +41,7 @@ declare global {
22
41
  }
23
42
 
24
43
  type InputBase = {
44
+ key?: any;
25
45
  modelValue?: any;
26
46
  clearable?: boolean;
27
47
  label?: string;
@@ -36,6 +56,7 @@ declare global {
36
56
  suffix?: Suffix | null;
37
57
  hint?: string | undefined;
38
58
  maska?: FormMasks | null;
59
+ fetchFrom?: FetchFunctions | null;
39
60
  };
40
61
 
41
62
  type FormControl<T extends InputType> = T & {