From 8dd9627849171f44d8d048f4b743dba3fb20aa69 Mon Sep 17 00:00:00 2001 From: vchikalkin Date: Wed, 4 Oct 2023 17:36:52 +0300 Subject: [PATCH] merge refactor/error-monitoring --- .../Components/Calculation/Form/ELT/Kasko.tsx | 8 +- .../Components/Calculation/Form/ELT/Osago.tsx | 8 +- .../Calculation/Form/ELT/lib/make-request.ts | 8 +- apps/web/config/schema/elt.ts | 196 +++++++++--------- apps/web/mocks/handlers.js | 65 +++--- apps/web/pages/api/trpc/[trpc].ts | 19 +- apps/web/process/calculate/action.ts | 25 +-- apps/web/process/create-kp/action.ts | 57 +++-- apps/web/process/load-kp/reactions.ts | 11 +- apps/web/server/routers/calculate/index.ts | 85 ++++---- .../routers/calculate/lib/validation.ts | 6 +- apps/web/server/routers/calculate/types.ts | 14 +- apps/web/server/routers/quote/index.ts | 113 +++++----- apps/web/utils/axios.ts | 32 +-- apps/web/utils/error.ts | 9 + apps/web/utils/trpc.ts | 38 ++++ 16 files changed, 355 insertions(+), 339 deletions(-) create mode 100644 apps/web/utils/error.ts create mode 100644 apps/web/utils/trpc.ts diff --git a/apps/web/Components/Calculation/Form/ELT/Kasko.tsx b/apps/web/Components/Calculation/Form/ELT/Kasko.tsx index 9d57c95..f18f6e3 100644 --- a/apps/web/Components/Calculation/Form/ELT/Kasko.tsx +++ b/apps/web/Components/Calculation/Form/ELT/Kasko.tsx @@ -57,7 +57,6 @@ export const Kasko = observer(() => { ) .then((res) => { if (res) { - const companyRes = res?.[row.id]; const { kaskoSum = 0, message, @@ -65,8 +64,8 @@ export const Kasko = observer(() => { totalFranchise = 0, requestId, paymentPeriods, - } = companyRes; - let { error } = companyRes; + } = res; + let { error } = res; if (totalFranchise > MAX_FRANCHISE) { error ||= `Франшиза по страховке превышает максимально допустимое значение: ${Intl.NumberFormat( @@ -111,10 +110,11 @@ export const Kasko = observer(() => { } }) .catch((error) => { + const _err = error as Error; $tables.elt.kasko.setRow({ ...initialData, key, - message: error, + message: _err.message || String(error), status: 'error', }); }); diff --git a/apps/web/Components/Calculation/Form/ELT/Osago.tsx b/apps/web/Components/Calculation/Form/ELT/Osago.tsx index 11ecde5..2dcbd57 100644 --- a/apps/web/Components/Calculation/Form/ELT/Osago.tsx +++ b/apps/web/Components/Calculation/Form/ELT/Osago.tsx @@ -51,9 +51,8 @@ export const Osago = observer(() => { ) .then((res) => { if (res) { - const companyRes = res?.[row.id]; - const { numCalc, premiumSum = 0, message, skCalcId } = companyRes; - let { error } = companyRes; + const { numCalc, premiumSum = 0, message, skCalcId } = res; + let { error } = res; if (premiumSum > MAX_INSURANCE) { error ||= `Сумма по страховке превышает максимально допустимое значение по стоимости ОСАГО: ${Intl.NumberFormat( 'ru', @@ -83,10 +82,11 @@ export const Osago = observer(() => { } }) .catch((error) => { + const _err = error as Error; $tables.elt.osago.setRow({ ...initialData, key, - message: error, + message: _err.message || String(error), status: 'error', }); }); diff --git a/apps/web/Components/Calculation/Form/ELT/lib/make-request.ts b/apps/web/Components/Calculation/Form/ELT/lib/make-request.ts index 1f8a016..b5c1d33 100644 --- a/apps/web/Components/Calculation/Form/ELT/lib/make-request.ts +++ b/apps/web/Components/Calculation/Form/ELT/lib/make-request.ts @@ -231,7 +231,8 @@ export async function makeEltOsagoRequest( } return { - ELTParams: { + companyId: row.id, + params: { FullDriversInfo: [ { kbm: '3', @@ -272,7 +273,6 @@ export async function makeEltOsagoRequest( ownerType: 1, tsToRegistrationPlace: 0, }, - companyIds: [row.id], preparams: { brandId, kladr, @@ -611,7 +611,8 @@ export async function makeEltKaskoRequest( } return { - ELTParams: { + companyId: row.id, + params: { Insurer: { SubjectType: 1, SubjectTypeSpecified: true, @@ -697,7 +698,6 @@ export async function makeEltKaskoRequest( // }, // ], }, - companyIds: [row.id], preparams: { brandId, kladr, diff --git a/apps/web/config/schema/elt.ts b/apps/web/config/schema/elt.ts index a209314..fdbe589 100644 --- a/apps/web/config/schema/elt.ts +++ b/apps/web/config/schema/elt.ts @@ -1,7 +1,8 @@ import { z } from 'zod'; export const RequestEltKaskoSchema = z.object({ - ELTParams: z.object({ + companyId: z.string(), + params: z.object({ Insurer: z.object({ SubjectType: z.number(), SubjectTypeSpecified: z.boolean(), @@ -82,7 +83,6 @@ export const RequestEltKaskoSchema = z.object({ vehicleDateSpecified: z.boolean(), vehicleYear: z.number(), }), - companyIds: z.array(z.string()), preparams: z.object({ brandId: z.string(), kladr: z.string(), @@ -98,85 +98,84 @@ export const RequestEltKaskoSchema = z.object({ }), }); -export const ResultEltKaskoSchema = z.record( - z.object({ - calcInfo: z.null(), - comment: z.null(), - doSum: z.number(), - error: z.string(), - errorType: z.null(), - gapSum: z.number(), - goSum: z.number(), - insuranceCompanyFranchise: z.object({ id: z.string(), value: z.string() }), - insuranceCompanyGo: z.object({ id: z.string(), value: z.string() }), - isNeedInspection: z.string(), - kaskoSum: z.number(), - kbmOsago: z.null(), - message: z.string(), - nsSum: z.number(), - options: z.array( - z.union([ - z.object({ - id: z.string(), - name: z.string(), - values: z.array(z.object({ id: z.string(), name: z.string() })), - }), - z.object({ - id: z.string(), - name: z.string(), - values: z.array(z.object({ id: z.string(), name: z.null() })), - }), - z.object({ - id: z.string(), - name: z.string(), - values: z.array(z.object({ id: z.null(), name: z.null() })), - }), - ]) - ), - paymentPeriods: z.array( +export const ResultEltKaskoSchema = z.object({ + calcInfo: z.null(), + comment: z.null(), + doSum: z.number(), + error: z.string(), + errorType: z.null(), + gapSum: z.number(), + goSum: z.number(), + insuranceCompanyFranchise: z.object({ id: z.string(), value: z.string() }), + insuranceCompanyGo: z.object({ id: z.string(), value: z.string() }), + isNeedInspection: z.string(), + kaskoSum: z.number(), + kbmOsago: z.null(), + message: z.string(), + nsSum: z.number(), + options: z.array( + z.union([ z.object({ - date: z.string(), - doSum: z.number(), - doSumSpecified: z.boolean(), - duration: z.number(), - durationSpecified: z.boolean(), - franchiseSum: z.number(), - franchiseSumSpecified: z.boolean(), - gapSum: z.number(), - gapSumSpecified: z.boolean(), - goSum: z.number(), - goSumSpecified: z.boolean(), - id: z.null(), - kaskoSum: z.number(), - kaskoSumSpecified: z.boolean(), - name: z.null(), - nsSum: z.number(), - nsSumSpecified: z.boolean(), - num: z.number(), - numSpecified: z.boolean(), - premiumSum: z.number(), - premiumSumSpecified: z.boolean(), - rate: z.number(), - rateSpecified: z.boolean(), - }) - ), - policyNumber: z.null(), - premiumSum: z.number(), - product: z.string(), - productId: z.string(), - program: z.string(), - programCode: z.string(), - programId: z.string(), - requestId: z.string(), - skCalcId: z.string(), - totalFranchise: z.number(), - totalFranchiseSpecified: z.boolean(), - unicusGUID: z.string(), - }) -); + id: z.string(), + name: z.string(), + values: z.array(z.object({ id: z.string(), name: z.string() })), + }), + z.object({ + id: z.string(), + name: z.string(), + values: z.array(z.object({ id: z.string(), name: z.null() })), + }), + z.object({ + id: z.string(), + name: z.string(), + values: z.array(z.object({ id: z.null(), name: z.null() })), + }), + ]) + ), + paymentPeriods: z.array( + z.object({ + date: z.string(), + doSum: z.number(), + doSumSpecified: z.boolean(), + duration: z.number(), + durationSpecified: z.boolean(), + franchiseSum: z.number(), + franchiseSumSpecified: z.boolean(), + gapSum: z.number(), + gapSumSpecified: z.boolean(), + goSum: z.number(), + goSumSpecified: z.boolean(), + id: z.null(), + kaskoSum: z.number(), + kaskoSumSpecified: z.boolean(), + name: z.null(), + nsSum: z.number(), + nsSumSpecified: z.boolean(), + num: z.number(), + numSpecified: z.boolean(), + premiumSum: z.number(), + premiumSumSpecified: z.boolean(), + rate: z.number(), + rateSpecified: z.boolean(), + }) + ), + policyNumber: z.null(), + premiumSum: z.number(), + product: z.string(), + productId: z.string(), + program: z.string(), + programCode: z.string(), + programId: z.string(), + requestId: z.string(), + skCalcId: z.string(), + totalFranchise: z.number(), + totalFranchiseSpecified: z.boolean(), + unicusGUID: z.string(), +}); export const RequestEltOsagoSchema = z.object({ - ELTParams: z.object({ + companyId: z.string(), + params: z.object({ FullDriversInfo: z.array(z.object({ kbm: z.string() })), carInfo: z.object({ mark: z.string(), @@ -244,7 +243,6 @@ export const RequestEltOsagoSchema = z.object({ ownerType: z.number(), tsToRegistrationPlace: z.number(), }), - companyIds: z.array(z.string()), preparams: z.object({ brandId: z.string(), kladr: z.string(), @@ -252,27 +250,25 @@ export const RequestEltOsagoSchema = z.object({ }), }); -export const ResultEltOsagoSchema = z.record( - z.object({ - calcInfo: z.array( - z.object({ - itemName: z.string(), - value: z.number(), - valueSpecified: z.boolean(), - }) - ), - error: z.string(), - fullDriversInfo: z.array(z.unknown()), - kbm: z.object({ class: z.number(), value: z.number() }), - message: z.string(), - numCalc: z.number(), - premiumSum: z.number(), - prevoiusKBM: z.object({ class: z.number(), value: z.number() }), - rsaRequestId: z.string(), - skCalcId: z.string(), - tb: z.number(), - }) -); +export const ResultEltOsagoSchema = z.object({ + calcInfo: z.array( + z.object({ + itemName: z.string(), + value: z.number(), + valueSpecified: z.boolean(), + }) + ), + error: z.string(), + fullDriversInfo: z.array(z.unknown()), + kbm: z.object({ class: z.number(), value: z.number() }), + message: z.string(), + numCalc: z.number(), + premiumSum: z.number(), + prevoiusKBM: z.object({ class: z.number(), value: z.number() }), + rsaRequestId: z.string(), + skCalcId: z.string(), + tb: z.number(), +}); export const RowSchema = z.object({ id: z.string(), diff --git a/apps/web/mocks/handlers.js b/apps/web/mocks/handlers.js index 29d865e..f975dc1 100644 --- a/apps/web/mocks/handlers.js +++ b/apps/web/mocks/handlers.js @@ -28,53 +28,46 @@ const { URL_GET_USER, URL_CORE_FINGAP, URL_1C_TRANSTAX, URL_ELT_OSAGO, URL_ELT_K export const handlers = [ rest.get(URL_GET_USER, (req, res, ctx) => res(ctx.json(users.akalinina))), - rest.post(URL_CORE_FINGAP, (req, res, ctx) => res( + rest.post(URL_CORE_FINGAP, (req, res, ctx) => + res( ctx.json({ sum: _.random(100000, 200000), premium: _.random(1000, 10000), }) - )), - rest.post(URL_1C_TRANSTAX, (req, res, ctx) => res( + ) + ), + rest.post(URL_1C_TRANSTAX, (req, res, ctx) => + res( ctx.json({ error: null, tax: _.random(100000, 200000), }) + ) + ), + rest.post(URL_ELT_OSAGO, async (req, res, ctx) => res( + ctx.json({ + numCalc: _.random(1000000, 3000000), + skCalcId: _.random(50000000, 60000000).toString(), + premiumSum: _.random(10000, 20000), + message: 'OSAGO Message', + }) )), - rest.post(URL_ELT_OSAGO, async (req, res, ctx) => { - const companyId = (await req.json()).companyIds[0]; - - return res( + rest.post(URL_ELT_KASKO, async (req, res, ctx) => res( ctx.json({ - [companyId]: { - numCalc: _.random(1000000, 3000000), - skCalcId: _.random(50000000, 60000000).toString(), - premiumSum: _.random(10000, 20000), - message: 'OSAGO Message', - }, + requestId: _.random(3000000, 4000000).toString(), + skCalcId: _.random(50000000, 60000000).toString(), + message: 'KASKO Message', + premiumSum: _.random(100000, 200000), + kaskoSum: _.random(100000, 200000), + paymentPeriods: [ + { + num: 1, + kaskoSum: _.random(100000, 200000), + }, + ], + totalFranchise: _.random(20000, 40000), }) - ); - }), - rest.post(URL_ELT_KASKO, async (req, res, ctx) => { - const companyId = (await req.json()).companyIds[0]; - return res( - ctx.json({ - [companyId]: { - requestId: _.random(3000000, 4000000).toString(), - skCalcId: _.random(50000000, 60000000).toString(), - message: 'KASKO Message', - premiumSum: _.random(100000, 200000), - kaskoSum: _.random(100000, 200000), - paymentPeriods: [ - { - num: 1, - kaskoSum: _.random(100000, 200000), - }, - ], - totalFranchise: _.random(20000, 40000), - }, - }) - ); - }), + )), // rest.post(URL_CRM_GRAPHQL, (req, res, ctx) => { // return res(ctx.status(503)); diff --git a/apps/web/pages/api/trpc/[trpc].ts b/apps/web/pages/api/trpc/[trpc].ts index d2f86de..3e78ce9 100644 --- a/apps/web/pages/api/trpc/[trpc].ts +++ b/apps/web/pages/api/trpc/[trpc].ts @@ -23,16 +23,17 @@ export default trpcNext.createNextApiHandler({ onError(opts) { const { error } = opts; // send to bug reporting - withScope((scope) => { - (Object.keys(opts) as Array).forEach((key) => { - if (key !== 'req') { - let extra = opts[key]; - if (key === 'input') extra = JSON.stringify(extra); - scope.setExtra(key, extra); - } + if (!['BAD_REQUEST', 'UNAUTHORIZED', 'FORBIDDEN'].includes(error.code)) + withScope((scope) => { + (Object.keys(opts) as Array).forEach((key) => { + if (key !== 'req') { + let extra = opts[key]; + if (key === 'input') extra = JSON.stringify(extra); + scope.setExtra(key, extra); + } + }); + captureException(error); }); - captureException(error); - }); // eslint-disable-next-line no-console console.error('Something went wrong', error); }, diff --git a/apps/web/process/calculate/action.ts b/apps/web/process/calculate/action.ts index b0d319f..1ad27cd 100644 --- a/apps/web/process/calculate/action.ts +++ b/apps/web/process/calculate/action.ts @@ -34,24 +34,15 @@ export async function action({ store, trpcClient }: ProcessContext) { values, }) .then((res) => { - if (res.success === false) { - notification.error({ - description: res.error, - key, - message: errorMessage, - placement: 'bottomRight', - }); - } else { - $results.setPayments(res.data.resultPayments); - $results.setValues(res.data.resultValues); - $calculation.$values.setValues(res.data.values); + $results.setPayments(res.data.resultPayments); + $results.setValues(res.data.resultValues); + $calculation.$values.setValues(res.data.values); - notification.success({ - key, - message: successMessage, - placement: 'bottomRight', - }); - } + notification.success({ + key, + message: successMessage, + placement: 'bottomRight', + }); }) .catch((error_) => { const error = error_ as Error; diff --git a/apps/web/process/create-kp/action.ts b/apps/web/process/create-kp/action.ts index c1ea0dd..757892f 100644 --- a/apps/web/process/create-kp/action.ts +++ b/apps/web/process/create-kp/action.ts @@ -42,42 +42,33 @@ export function action({ store, trpcClient, apolloClient }: ProcessContext) { values, }) .then(async (res) => { - if (res.success === false) { - notification.error({ - description: res.error, - key, - message: errorMessage, - placement: 'bottomRight', - }); - } else { - $results.setPayments(res.data.resultPayments); - $results.setValues(res.data.resultValues); - $calculation.$values.setValues({ ...res.data.values, recalcWithRevision: false }); + $results.setPayments(res.data.resultPayments); + $results.setValues(res.data.resultValues); + $calculation.$values.setValues({ ...res.data.values, recalcWithRevision: false }); - notification.success({ - key, - message: successMessage, - placement: 'bottomRight', + notification.success({ + key, + message: successMessage, + placement: 'bottomRight', + }); + + const leadid = $calculation.element('selectLead').getValue(); + + if (leadid) { + const { + data: { quotes }, + } = await apolloClient.query({ + fetchPolicy: 'network-only', + query: CRMTypes.GetQuotesDocument, + variables: { + leadid, + }, }); - const leadid = $calculation.element('selectLead').getValue(); - - if (leadid) { - const { - data: { quotes }, - } = await apolloClient.query({ - fetchPolicy: 'network-only', - query: CRMTypes.GetQuotesDocument, - variables: { - leadid, - }, - }); - - $calculation - .element('selectQuote') - .setOptions(normalizeOptions(quotes)) - .setValue(values.quote); - } + $calculation + .element('selectQuote') + .setOptions(normalizeOptions(quotes)) + .setValue(values.quote); } }) .catch((error_) => { diff --git a/apps/web/process/load-kp/reactions.ts b/apps/web/process/load-kp/reactions.ts index e55ae35..22e6e29 100644 --- a/apps/web/process/load-kp/reactions.ts +++ b/apps/web/process/load-kp/reactions.ts @@ -2,13 +2,12 @@ import eltHelper from '../elt/lib/helper'; import { message } from '@/Components/Common/Notification'; import type { ProcessContext } from '@/process/types'; -import { captureException, withScope } from '@sentry/nextjs'; import { reaction } from 'mobx'; import { omit } from 'radash'; const key = 'KP_LOADING_INFO'; -export function common({ store, trpcClient, apolloClient, user }: ProcessContext) { +export function common({ store, trpcClient, apolloClient }: ProcessContext) { const { $calculation, $process, $tables } = store; const { init: initElt } = eltHelper({ apolloClient, store }); @@ -86,18 +85,12 @@ export function common({ store, trpcClient, apolloClient, user }: ProcessContext key, }); }) - .catch((error_) => { + .catch(() => { message.error({ content: `Ошибка во время загрузки КП ${quote.label}`, key, }); $calculation.element('selectQuote').resetValue(); - - withScope((scope) => { - scope.setExtra('quote', quote); - scope.setExtra('user', user); - captureException(error_); - }); }) .finally(() => { $process.delete('LoadKP'); diff --git a/apps/web/server/routers/calculate/index.ts b/apps/web/server/routers/calculate/index.ts index ecb9aff..b664075 100644 --- a/apps/web/server/routers/calculate/index.ts +++ b/apps/web/server/routers/calculate/index.ts @@ -7,6 +7,8 @@ import { calculate } from '@/api/core/query'; import type { User } from '@/api/user/types'; import initializeApollo from '@/apollo/client'; import { protectedProcedure } from '@/server/procedure'; +import { HttpError } from '@/utils/error'; +import { createTRPCError } from '@/utils/trpc'; import { QueryClient } from '@tanstack/react-query'; export const calculateRouter = router({ @@ -17,55 +19,56 @@ export const calculateRouter = router({ const apolloClient = initializeApollo(); const queryClient = new QueryClient(); - if (!ctx.unlimited) { - const validationResult = await validate({ + try { + if (!ctx.unlimited) { + const validationResult = await validate({ + context: { + apolloClient, + queryClient, + user: ctx.user, + }, + input, + }); + + if (validationResult.success === false) { + throw new HttpError(validationResult.message, 400); + } + } + + let user: Pick = { domainName: ctx.user.domainName }; + if (ctx.unlimited && input.values.user) { + user = { domainName: input.values.user }; + } + + const requestData = await createRequestData({ context: { apolloClient, queryClient, - user: ctx.user, + ...ctx, + user, }, input, }); - if (validationResult.success === false) { - return { - error: validationResult.error, - success: false, - }; + const calculateResult = await calculate(requestData); + + const result = transformCalculateResults({ + calculateInput: input, + requestCalculate: requestData, + responseCalculate: calculateResult, + }); + + // TEMP + if (ctx.unlimited) { + result.__calculateResult = calculateResult; } + + return { + data: result, + success: true, + }; + } catch (error) { + throw createTRPCError(error); } - - let user: Pick = { domainName: ctx.user.domainName }; - if (ctx.unlimited && input.values.user) { - user = { domainName: input.values.user }; - } - - const requestData = await createRequestData({ - context: { - apolloClient, - queryClient, - ...ctx, - user, - }, - input, - }); - - const calculateResult = await calculate(requestData); - - const result = transformCalculateResults({ - calculateInput: input, - requestCalculate: requestData, - responseCalculate: calculateResult, - }); - - // TEMP - if (ctx.unlimited) { - result.__calculateResult = calculateResult; - } - - return { - data: result, - success: true, - }; }), }); diff --git a/apps/web/server/routers/calculate/lib/validation.ts b/apps/web/server/routers/calculate/lib/validation.ts index 85b2ef7..25c878d 100644 --- a/apps/web/server/routers/calculate/lib/validation.ts +++ b/apps/web/server/routers/calculate/lib/validation.ts @@ -49,14 +49,14 @@ export async function validate({ input, context }: { context: Context; input: Ca }); if (validationResult.success === false) { - const error = getMessage(validationResult.error.errors); + const message = getMessage(validationResult.error.errors); - return { error, success: false }; + return { message, success: false }; } } return { - error: '', + message: '', success: true, }; } diff --git a/apps/web/server/routers/calculate/types.ts b/apps/web/server/routers/calculate/types.ts index c508af1..1633d9f 100644 --- a/apps/web/server/routers/calculate/types.ts +++ b/apps/web/server/routers/calculate/types.ts @@ -34,15 +34,9 @@ export const OutputDataSchema = z.object({ export type OutputData = z.infer; -export const CalculateOutputSchema = z.union([ - z.object({ - data: OutputDataSchema, - success: z.literal(true), - }), - z.object({ - error: z.string(), - success: z.literal(false), - }), -]); +export const CalculateOutputSchema = z.object({ + data: OutputDataSchema, + success: z.literal(true), +}); export type CalculateOutput = z.infer; diff --git a/apps/web/server/routers/quote/index.ts b/apps/web/server/routers/quote/index.ts index 65ab388..348baa3 100644 --- a/apps/web/server/routers/quote/index.ts +++ b/apps/web/server/routers/quote/index.ts @@ -34,6 +34,8 @@ import * as price from '@/process/price'; import * as subsidy from '@/process/subsidy'; import * as supplierAgent from '@/process/supplier-agent'; import type { CalculationValues } from '@/stores/calculation/values/types'; +import { HttpError } from '@/utils/error'; +import { createTRPCError } from '@/utils/trpc'; import { QueryClient } from '@tanstack/react-query'; const { DEFAULT_FINGAP_ROW, DEFAULT_KASKO_ROW, DEFAULT_OSAGO_ROW } = insuranceTable; @@ -96,70 +98,71 @@ export const quoteRouter = router({ const apolloClient = initializeApollo(); const queryClient = new QueryClient(); - if (!ctx.unlimited) { - const validationResult = await validate({ + try { + if (!ctx.unlimited) { + const validationResult = await validate({ + context: { + apolloClient, + queryClient, + user: ctx.user, + }, + input, + }); + + if (validationResult.success === false) { + throw new HttpError(validationResult.message, 400); + } + } + + let user: Pick = { domainName: ctx.user.domainName }; + if (ctx.unlimited && input.values.user) { + user = { domainName: input.values.user }; + } + + const requestData = await createRequestData({ context: { apolloClient, queryClient, - user: ctx.user, + ...ctx, + user, }, input, }); - if (validationResult.success === false) { - return { - error: validationResult.error, - success: false, - }; + const calculateResult = await calculate(requestData); + + const requestCreateKP = compatRequestCreateKP({ + domainName: user.domainName, + finGAP: input.fingap, + insurance: Object.values(input.insurance.values), + calculation: { + calculationValues: await compatValues(input.values, { apolloClient }), + ...calculateResult, + preparedPayments: requestData.preparedPayments, + additionalData: requestData.additionalData, + }, + elt: input.elt, + }); + + const createKPResult = await createKP(requestCreateKP); + + const result = transformCalculateResults({ + calculateInput: input, + requestCalculate: requestData, + responseCalculate: calculateResult, + }); + + if (URL_CRM_DOWNLOADKP) { + result.values.downloadKp = URL_CRM_DOWNLOADKP?.concat(createKPResult.offerprintformapi); } + + return { + data: result, + success: true, + }; + } catch (error) { + throw createTRPCError(error); } - - let user: Pick = { domainName: ctx.user.domainName }; - if (ctx.unlimited && input.values.user) { - user = { domainName: input.values.user }; - } - - const requestData = await createRequestData({ - context: { - apolloClient, - queryClient, - ...ctx, - user, - }, - input, - }); - - const calculateResult = await calculate(requestData); - - const requestCreateKP = compatRequestCreateKP({ - domainName: user.domainName, - finGAP: input.fingap, - insurance: Object.values(input.insurance.values), - calculation: { - calculationValues: await compatValues(input.values, { apolloClient }), - ...calculateResult, - preparedPayments: requestData.preparedPayments, - additionalData: requestData.additionalData, - }, - elt: input.elt, - }); - - const createKPResult = await createKP(requestCreateKP); - - const result = transformCalculateResults({ - calculateInput: input, - requestCalculate: requestData, - responseCalculate: calculateResult, - }); - - if (URL_CRM_DOWNLOADKP) { - result.values.downloadKp = URL_CRM_DOWNLOADKP?.concat(createKPResult.offerprintformapi); - } - - return { - data: result, - success: true, - }; }), }); diff --git a/apps/web/utils/axios.ts b/apps/web/utils/axios.ts index 22d68e3..ef5d05f 100644 --- a/apps/web/utils/axios.ts +++ b/apps/web/utils/axios.ts @@ -1,3 +1,4 @@ +import { HttpError } from './error'; import { captureException, withScope } from '@sentry/nextjs'; import type { AxiosError } from 'axios'; import { isAxiosError } from 'axios'; @@ -17,25 +18,28 @@ function getErrorMessage(fn: Promise) { return fn.catch((error_: AxiosError | Error) => { if (isAxiosError(error_)) { - const err = pick(error_, ['code', 'message', 'status', 'cause']); - const data = error_.config?.data; - const params = error_.config?.params; - const message = getErrorMessage(error_); - const opts = { ...err, data, message, params }; - error_.message += ` | ${message}`; + if (error_.response?.status && error_.response?.status >= 500) { + const err = pick(error_, ['code', 'message', 'status', 'cause']); + const data = error_.config?.data; + const params = error_.config?.params; - withScope((scope) => { - (Object.keys(opts) as Array).forEach((key) => { - let extra = opts[key]; - if (key === 'data') extra = JSON.stringify(extra); - scope.setExtra(key, extra); + const opts = { ...err, data, message, params }; + + error_.message += ` | ${message}`; + + withScope((scope) => { + (Object.keys(opts) as Array).forEach((key) => { + let extra = opts[key]; + if (key === 'data') extra = JSON.stringify(extra); + scope.setExtra(key, extra); + }); + captureException(error_); }); - captureException(error_); - }); + } - throw new Error(message); + throw new HttpError(message, error_.status || error_.response?.status); } return null as unknown as T; diff --git a/apps/web/utils/error.ts b/apps/web/utils/error.ts new file mode 100644 index 0000000..0aa96f0 --- /dev/null +++ b/apps/web/utils/error.ts @@ -0,0 +1,9 @@ +export class HttpError extends Error { + public statusCode: number; + + constructor(message: string, statusCode = 500) { + super(message); + this.name = 'HttpError'; + this.statusCode = statusCode; + } +} diff --git a/apps/web/utils/trpc.ts b/apps/web/utils/trpc.ts new file mode 100644 index 0000000..80c1ab3 --- /dev/null +++ b/apps/web/utils/trpc.ts @@ -0,0 +1,38 @@ +import { HttpError } from './error'; +import { TRPCError } from '@trpc/server'; +import type { TRPC_ERROR_CODE_KEY } from '@trpc/server/rpc'; + +const HTTP_CODE_TO_JSONRPC2: Record = { + 400: 'BAD_REQUEST', + 401: 'UNAUTHORIZED', + 403: 'FORBIDDEN', + 404: 'NOT_FOUND', + 405: 'METHOD_NOT_SUPPORTED', + 408: 'TIMEOUT', + 409: 'CONFLICT', + 412: 'PRECONDITION_FAILED', + 413: 'PAYLOAD_TOO_LARGE', + 429: 'TOO_MANY_REQUESTS', + 499: 'CLIENT_CLOSED_REQUEST', + 500: 'INTERNAL_SERVER_ERROR', +}; + +export function createTRPCError(error: unknown) { + let code: TRPC_ERROR_CODE_KEY = 'INTERNAL_SERVER_ERROR'; + let message = ''; + + if (error instanceof HttpError) { + const { statusCode = 500 } = error; + code = HTTP_CODE_TO_JSONRPC2[statusCode]; + } + + if (error instanceof Error) { + message = error.message; + } + + return new TRPCError({ + cause: error, + code, + message, + }); +}