hl-core 0.0.10-beta.63 → 0.0.10-beta.65

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
@@ -503,7 +503,7 @@ export class ApiClass {
503
503
  }
504
504
 
505
505
  async availableToAccureStartEducationalCapital(id: string | number) {
506
- return await this.axiosCall<boolean>({
506
+ return await this.axiosCall<any>({
507
507
  method: Methods.GET,
508
508
  url: `/${this.productUrl}/api/Application/AvailableToAccureStartEducationalCapital?processInstanceId=${id}`,
509
509
  });
@@ -617,6 +617,14 @@ export class ApiClass {
617
617
  });
618
618
  }
619
619
 
620
+ async checkExistProcess(iin: string, processCode: number) {
621
+ return await this.axiosCall<string>({
622
+ method: Methods.GET,
623
+ url: '/Arm/api/Bpm/CheckExistProcess',
624
+ params: { iin, processCode },
625
+ });
626
+ }
627
+
620
628
  async getContragentFromGBDFL(data: Types.Api.GBD.Request) {
621
629
  return await this.axiosCall<Types.Api.GBD.Response>({
622
630
  method: Methods.POST,
@@ -859,6 +867,13 @@ export class ApiClass {
859
867
  });
860
868
  }
861
869
 
870
+ async getCloseDate() {
871
+ return await this.axiosCall<string>({
872
+ method: Methods.GET,
873
+ url: `/${this.productUrl}/api/Application/GetCloseDate`,
874
+ });
875
+ }
876
+
862
877
  async getProcessGfot(processCode: string | number) {
863
878
  return await this.axiosCall<Value[]>({
864
879
  method: Methods.GET,
@@ -1097,6 +1112,16 @@ export class ApiClass {
1097
1112
  });
1098
1113
  }
1099
1114
 
1115
+ async setIsNotCalculated(processInstanceId: string | number) {
1116
+ return await this.axiosCall<boolean>({
1117
+ method: Methods.POST,
1118
+ url: `/${this.productUrl}/api/Application/SetIsNotCalculated`,
1119
+ params: {
1120
+ processInstanceId,
1121
+ },
1122
+ });
1123
+ }
1124
+
1100
1125
  async checkProActiveService(processInstanceId: string | number, iin: string) {
1101
1126
  return await this.axiosCall({
1102
1127
  method: Methods.GET,
@@ -1173,6 +1198,14 @@ export class ApiClass {
1173
1198
  data: data,
1174
1199
  });
1175
1200
  },
1201
+ resetApplicationData: async (processInstanceId: string | number) => {
1202
+ return await this.axiosCall<void>({
1203
+ method: Methods.POST,
1204
+ baseURL: getStrValuePerEnv('efoBaseApi'),
1205
+ url: `${this.pensionannuityNew.base}/ResetApplicationData`,
1206
+ params: { processInstanceId },
1207
+ });
1208
+ },
1176
1209
  };
1177
1210
 
1178
1211
  externalServices = {
@@ -1,46 +1,107 @@
1
- import { AxiosError, type AxiosInstance } from 'axios';
1
+ import { AxiosError, type AxiosInstance, type InternalAxiosRequestConfig, isAxiosError } from 'axios';
2
2
 
3
- export default function (axios: AxiosInstance) {
3
+ /**
4
+ * Обновляет baseURL в зависимости от текущего хоста
5
+ */
6
+ function updateBaseUrlForEnvironment(request: InternalAxiosRequestConfig): void {
7
+ if (!request.url || !request.baseURL) return;
8
+
9
+ const host = window.location.hostname;
10
+
11
+ if (host.startsWith('bpmsrv02') || host.startsWith('vega')) {
12
+ if (request.baseURL === getStrValuePerEnv('baseApi')) {
13
+ request.baseURL = getStrValuePerEnv('baseApiLocal');
14
+ }
15
+ if (request.baseURL === getStrValuePerEnv('efoBaseApi')) {
16
+ request.baseURL = getStrValuePerEnv('efoBaseApiLocal');
17
+ }
18
+ if (request.baseURL === getStrValuePerEnv('amlBaseApi')) {
19
+ request.baseURL = getStrValuePerEnv('amlBaseApiLocal');
20
+ }
21
+ if (request.baseURL === getStrValuePerEnv('gatewayApiUrl')) {
22
+ request.baseURL = getStrValuePerEnv('gatewayApiUrlLocal');
23
+ }
24
+ }
25
+ }
26
+
27
+ /**
28
+ * Обрабатывает специальную логику для нового API
29
+ */
30
+ function handleNewApiLogic(request: InternalAxiosRequestConfig): void {
31
+ if (!request.url || !request.baseURL) return;
32
+
33
+ if (import.meta.env.VITE_ON_NEW_API === 'true' && request.url.includes('api/Application')) {
34
+ if (request.baseURL === 'http://vega:84') {
35
+ request.baseURL = 'http://efo-dev.halyklife.nb/api';
36
+ }
37
+ if (request.baseURL === 'http://bpmsrv02.halyklife.nb') {
38
+ request.baseURL = 'http://efo-prod.halyklife.nb/api';
39
+ }
40
+
41
+ request.url = request.url.replace('/api/Application', '');
42
+
43
+ if (request.baseURL.includes('api/v1/insis')) {
44
+ request.baseURL = request.baseURL.replace('api/v1/insis', 'efo/api');
45
+ }
46
+ if (request.baseURL.includes('api/v1/test/insis')) {
47
+ request.baseURL = request.baseURL.replace('api/v1/test/insis', 'test/efo/api');
48
+ }
49
+ }
50
+ }
51
+
52
+ /**
53
+ * Извлекает полезное сообщение об ошибке из ответа
54
+ */
55
+ function extractErrorMessage(data: any, status: number, dataStore: any): string {
56
+ // .NET ProblemDetails
57
+ if (data && typeof data === 'object') {
58
+ if (data.title || data.detail) {
59
+ return data.title || data.detail;
60
+ }
61
+ // Распространённые поля
62
+ if (data.message || data.status || data.statusName) {
63
+ return data.message || data.status || data.statusName;
64
+ }
65
+ }
66
+
67
+ // Если строка/HTML
68
+ if (typeof data === 'string') {
69
+ return data.slice(0, 200);
70
+ }
71
+
72
+ // Фолбэк
73
+ return status === 500 ? dataStore.t('toaster.serverError') : `HTTP ${status}`;
74
+ }
75
+
76
+ /**
77
+ * Настраивает interceptors для axios instance
78
+ *
79
+ * @param axios - Экземпляр axios для настройки
80
+ *
81
+ * Включает:
82
+ * - Автоматическое добавление токена авторизации
83
+ * - Обработку различных окружений (dev/prod)
84
+ * - Комплексную обработку ошибок с информативными сообщениями
85
+ * - Мягкую обработку 401 ошибок с сохранением redirect URL
86
+ * - Защиту от дублирования 401 ошибок
87
+ */
88
+ export default function setupInterceptors(axios: AxiosInstance): void {
4
89
  axios.interceptors.request.use(
5
- request => {
90
+ (request: InternalAxiosRequestConfig) => {
6
91
  const dataStore = useDataStore();
92
+
93
+ // Добавляем токен авторизации
7
94
  if (dataStore.accessToken) {
95
+ request.headers = request.headers || {};
8
96
  request.headers.Authorization = `Bearer ${dataStore.accessToken}`;
9
97
  }
10
- if (request.url && request.baseURL) {
11
- const host = window.location.hostname;
12
- if (host.startsWith('bpmsrv02') || host.startsWith('vega')) {
13
- if (request.baseURL === getStrValuePerEnv('baseApi')) {
14
- request.baseURL = getStrValuePerEnv('baseApiLocal');
15
- }
16
- if (request.baseURL === getStrValuePerEnv('efoBaseApi')) {
17
- request.baseURL = getStrValuePerEnv('efoBaseApiLocal');
18
- }
19
- if (request.baseURL === getStrValuePerEnv('amlBaseApi')) {
20
- request.baseURL = getStrValuePerEnv('amlBaseApiLocal');
21
- }
22
- if (request.baseURL === getStrValuePerEnv('gatewayApiUrl')) {
23
- request.baseURL = getStrValuePerEnv('gatewayApiUrlLocal');
24
- }
25
- }
26
- if (import.meta.env.VITE_ON_NEW_API === 'true') {
27
- if (request.url.includes('api/Application')) {
28
- if (request.baseURL === 'http://vega:84') {
29
- request.baseURL = 'http://efo-dev.halyklife.nb/api';
30
- }
31
- if (request.baseURL === 'http://bpmsrv02.halyklife.nb') {
32
- request.baseURL = 'http://efo-prod.halyklife.nb/api';
33
- }
34
- request.url = request.url.replace('/api/Application', '');
35
- if (request.baseURL.includes('api/v1/insis')) {
36
- request.baseURL = request.baseURL.replace('api/v1/insis', 'efo/api');
37
- }
38
- if (request.baseURL.includes('api/v1/test/insis')) {
39
- request.baseURL = request.baseURL.replace('api/v1/test/insis', 'test/efo/api');
40
- }
41
- }
42
- }
43
- }
98
+
99
+ // Обновляем baseURL для разных окружений
100
+ updateBaseUrlForEnvironment(request);
101
+
102
+ // Обрабатываем логику нового API
103
+ handleNewApiLogic(request);
104
+
44
105
  return request;
45
106
  },
46
107
  (error: AxiosError) => {
@@ -48,32 +109,77 @@ export default function (axios: AxiosInstance) {
48
109
  },
49
110
  );
50
111
  axios.interceptors.response.use(
51
- response => {
52
- return response;
53
- },
54
- (error: AxiosError) => {
112
+ response => response,
113
+ (err: unknown) => {
55
114
  const dataStore = useDataStore();
56
- if (!dataStore.isCalculator) {
57
- const router = useRouter();
58
- if (error && error.response && error.response.status) {
59
- if (error.response.status === 401) {
60
- dataStore.$reset();
61
- localStorage.clear();
62
- if (dataStore.isBridge) {
63
- router.push({ name: 'Auth', query: { error: 401 } });
64
- } else {
65
- dataStore.sendToParent(constants.postActions.Error401, 401);
66
- }
67
- }
68
- if (error.response.status === 403 && error.response.config.url) {
69
- dataStore.showToaster('error', `Нет доступа на запрос: ${error.response.config.url.substring(error.response.config.url.lastIndexOf('/') + 1)}`, 5000);
70
- }
71
- if (error.response.status === 413) {
72
- dataStore.showToaster('error', dataStore.t('error.exceedUploadLimitFile'), 5000);
73
- }
115
+
116
+ // если калькулятор, выходим (твоя логика)
117
+ if (dataStore.isCalculator) {
118
+ return Promise.reject(err);
119
+ }
120
+
121
+ // 1) Не-Axios ошибка (например, thrown Error)
122
+ if (!isAxiosError(err)) {
123
+ dataStore.showToaster('error', dataStore.t('toaster.unknownError'), 5000);
124
+ return Promise.reject(err);
125
+ }
126
+
127
+ const { response, request, code, message, config } = err;
128
+
129
+ // 2) Нет ответа вообще (timeout, сеть, CORS)
130
+ if (!response) {
131
+ const isTimeout = code === 'ECONNABORTED' || /timeout/i.test(String(message));
132
+ dataStore.showToaster('error', isTimeout ? dataStore.t('toaster.timeout') : dataStore.t('toaster.networkError'), 5000);
133
+ return Promise.reject(err);
134
+ }
135
+
136
+ const status = response.status;
137
+ const data = response.data;
138
+
139
+ // 3) 401 — простая обработка, показываем ошибку
140
+ if (status === 401) {
141
+ dataStore.showToaster('error', dataStore.t('error.401'), 5000);
142
+ return Promise.reject(err);
143
+ }
144
+
145
+ // 4) 403 — вытаскиваем только path без query/hash
146
+ if (status === 403) {
147
+ try {
148
+ const rawUrl = response.config?.url ?? '';
149
+ const urlObj = new URL(rawUrl, window.location.origin);
150
+ const pathSegment = urlObj.pathname.split('/').filter(Boolean).pop() ?? 'resource';
151
+ dataStore.showToaster('error', dataStore.t('error.403', { text: pathSegment }), 5000);
152
+ } catch (urlError) {
153
+ console.warn('Error parsing URL for 403 response:', urlError);
154
+ dataStore.showToaster('error', dataStore.t('error.403'), 5000);
74
155
  }
156
+ return Promise.reject(err);
75
157
  }
76
- return Promise.reject(error);
158
+
159
+ // 5) 404
160
+ if (status === 404) {
161
+ dataStore.showToaster('error', dataStore.t('error.404'), 5000);
162
+ return Promise.reject(err);
163
+ }
164
+
165
+ // 6) 413
166
+ if (status === 413) {
167
+ dataStore.showToaster('error', dataStore.t('error.exceedUploadLimitFile'), 5000);
168
+ return Promise.reject(err);
169
+ }
170
+
171
+ // 7) 500 — явная обработка
172
+ if (status === 500) {
173
+ const errorMessage = extractErrorMessage(data, status, dataStore);
174
+ dataStore.showToaster('error', String(errorMessage), 5000);
175
+ return Promise.reject(err);
176
+ }
177
+
178
+ // 8) Прочие коды — показываем полезное сообщение
179
+ const errorMessage = extractErrorMessage(data, status, dataStore);
180
+ dataStore.showToaster('error', String(errorMessage), 5000);
181
+
182
+ return Promise.reject(err);
77
183
  },
78
184
  );
79
185
  }
@@ -156,29 +156,54 @@ export default defineComponent({
156
156
  const isSaleChanellReadonly = computed(() => {
157
157
  if (!isReadonly.value) {
158
158
  if (dataStore.isTravelAgent()) return true;
159
- if (dataStore.isGons) return !dataStore.isServiceManager();
159
+ if (dataStore.isGons) {
160
+ return !dataStore.isServiceManager() &&
161
+ !dataStore.isChiefManagerNSZH() &&
162
+ !dataStore.isChiefSalesManager() &&
163
+ !dataStore.isSalesManager() &&
164
+ !dataStore.isManager();
165
+ }
160
166
  }
161
167
  return isReadonly.value;
162
168
  });
163
169
  const isRegionReadonly = computed(() => {
164
170
  if (!isReadonly.value) {
165
171
  if (dataStore.isTravelAgent()) return true;
166
- if (dataStore.isGons) return !dataStore.isServiceManager() && !dataStore.isAgent();
172
+ if (dataStore.isGons) {
173
+ return !dataStore.isServiceManager() &&
174
+ !dataStore.isAgent() &&
175
+ !dataStore.isChiefManagerNSZH() &&
176
+ !dataStore.isChiefSalesManager() &&
177
+ !dataStore.isSalesManager() &&
178
+ !dataStore.isManager();
179
+ }
167
180
  }
168
181
  return isReadonly.value;
169
182
  });
170
183
  const isManagerReadonly = computed(() => {
171
184
  if (!isReadonly.value) {
172
185
  if (dataStore.isTravelAgent()) return true;
173
- if (dataStore.isGons) return !dataStore.isServiceManager();
186
+ if (dataStore.isGons) {
187
+ return !dataStore.isServiceManager() &&
188
+ !dataStore.isChiefManagerNSZH() &&
189
+ !dataStore.isChiefSalesManager() &&
190
+ !dataStore.isSalesManager() &&
191
+ !dataStore.isManager();
192
+ }
174
193
  }
175
194
  return isReadonly.value;
176
195
  });
177
196
  const isAgentReadonly = computed(() => {
178
197
  if (!isReadonly.value) {
179
198
  if (dataStore.isTravelAgent()) return true;
180
- if (dataStore.isGons) return !dataStore.isServiceManager();
181
199
  if (dataStore.isPension) return true;
200
+ if (dataStore.isGons) {
201
+ return !dataStore.isServiceManager() &&
202
+ !dataStore.isChiefManagerNSZH() &&
203
+ !dataStore.isChiefSalesManager() &&
204
+ !dataStore.isSalesManager() &&
205
+ !dataStore.isManager();
206
+ }
182
207
  }
183
208
  return isReadonly.value;
184
209
  });
@@ -0,0 +1,13 @@
1
+ <template>
2
+ <p class="p-1 px-2 text-[10px]" :class="[$styles.greyText]">{{ text }}</p>
3
+ </template>
4
+ <script>
5
+ export default {
6
+ props: {
7
+ text: {
8
+ type: String,
9
+ required: true,
10
+ },
11
+ },
12
+ };
13
+ </script>
@@ -126,6 +126,7 @@
126
126
 
127
127
  <script lang="ts">
128
128
  import type { InputTypes } from '../../types';
129
+ import { handleSuccessfulLogin } from '../../utils/auth-helpers';
129
130
 
130
131
  export default defineComponent({
131
132
  setup() {
@@ -182,11 +183,7 @@ export default defineComponent({
182
183
  await dataStore.loginUser(login.value, password.value, numAttempts.value);
183
184
  numAttempts.value++;
184
185
  authLoading.value = false;
185
- if (!!dataStore.user.id) {
186
- await router.push({ name: 'index' });
187
- }
188
- } else {
189
- // TODO Reset password
186
+ await handleSuccessfulLogin(router);
190
187
  }
191
188
  }
192
189
  });
@@ -373,6 +373,10 @@ export default defineComponent({
373
373
  };
374
374
 
375
375
  const validateESBD = async (docTypeNumber: number) => {
376
+ if (!dataStore.checkWithESBD) {
377
+ return true;
378
+ }
379
+
376
380
  const data: ESBDValidationType = {
377
381
  personType: 1,
378
382
  iin: props.member.iin!.replaceAll('-', ''),
@@ -390,7 +394,20 @@ export default defineComponent({
390
394
  resident: props.member.signOfResidency.ids === '500011.2' || props.member.signOfResidency.ids === null ? 0 : 1,
391
395
  countryId: Number((props.member.countryOfTaxResidency.ids! as string).at(-1)),
392
396
  };
393
- return await dataStore.getValidateClientESBD(data);
397
+ const ESBDResponse = await dataStore.getValidateClientESBD(data);
398
+ if (!ESBDResponse) {
399
+ dataStore.isLoading = false;
400
+ return false;
401
+ }
402
+ const initialPoint = `${props.member.iin!.replaceAll('-', '')}.`;
403
+ const RESPONSE = ESBDMessage(ESBDResponse, initialPoint);
404
+ let errorMessage = RESPONSE !== false ? RESPONSE : 'Что-то произошло не так';
405
+ if (typeof ESBDResponse !== 'object' || ESBDResponse.errorCode !== 0) {
406
+ dataStore.isLoading = false;
407
+ dataStore.showToaster('error', errorMessage, 5000);
408
+ return false;
409
+ }
410
+ return true;
394
411
  };
395
412
 
396
413
  const saveMember = async () => {
@@ -411,22 +428,11 @@ export default defineComponent({
411
428
  const docType = props.member.documentType.ids;
412
429
  if (props.member.gotFromInsis === true && (docType === '1UDL' || docType === 'SBI')) {
413
430
  dataStore.isLoading = true;
414
- const ESBDResponse = await validateESBD(docType === '1UDL' ? 1 : 3);
415
- if (!ESBDResponse) {
416
- dataStore.isLoading = false;
417
- return;
418
- }
419
- const initialPoint = `${props.member.iin!.replaceAll('-', '')}.`;
420
- const RESPONSE = ESBDMessage(ESBDResponse, initialPoint);
421
- let errorMessage = RESPONSE !== false ? RESPONSE : 'Что-то произошло не так';
422
- if (typeof ESBDResponse === 'object' && ESBDResponse.errorCode === 0) {
423
- props.member.verifyType = 'ESBD';
424
- props.member.verifyDate = ESBDResponse.verifiedDate;
425
- const hasMemberSaved = await saveMember();
426
- } else {
427
- dataStore.isLoading = false;
428
- dataStore.showToaster('error', errorMessage, 5000);
429
- }
431
+
432
+ const isESBDValid = await validateESBD(docType === '1UDL' ? 1 : 3);
433
+ if (isESBDValid === false) return;
434
+
435
+ const hasMemberSaved = await saveMember();
430
436
  } else {
431
437
  const hasMemberSaved = await saveMember();
432
438
  }