feat: implement SalesInvoiceTspSwitchService and SalesInvoiceTspService for handling TSP provider interactions
- Add SalesInvoiceTspSwitchService to manage TSP provider selection and sending invoices. - Introduce SalesInvoiceTspService for creating, sending, and retrieving sales invoices. - Implement NamaProviderSwitchAdapter for communication with the NAMA TSP provider API. - Define DTOs for request and response structures specific to the NAMA provider. - Enhance error handling and logging for TSP provider interactions.
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { FiscalResponseStatus } from '@/generated/prisma/enums'
|
||||
import { TspProviderResponseStatus } from '@/generated/prisma/enums'
|
||||
|
||||
export default {
|
||||
PaymentMethodType: {
|
||||
@@ -132,23 +132,23 @@ export default {
|
||||
CAFE_BAZAR: 'کافه بازار',
|
||||
MAYKET: 'مایکت',
|
||||
},
|
||||
PartnerFiscalSwitchType: {
|
||||
TspProviderType: {
|
||||
NAMA: 'نما',
|
||||
SUN: 'سان',
|
||||
},
|
||||
FiscalResponseStatus: {
|
||||
TspProviderResponseStatus: {
|
||||
SUCCESS: 'موفق',
|
||||
FAILURE: 'ناموفق',
|
||||
NOT_SEND: 'ارسال نشده',
|
||||
[FiscalResponseStatus.QUEUED]: 'در صف ارسال',
|
||||
[TspProviderResponseStatus.QUEUED]: 'در صف ارسال',
|
||||
},
|
||||
FiscalRequestType: {
|
||||
TspProviderRequestType: {
|
||||
MAIN: 'اصلی',
|
||||
UPDATE: 'اصلاح',
|
||||
REVOKE: 'ابطال',
|
||||
REMOVE: 'حذف',
|
||||
},
|
||||
FiscalInvoiceCustomerType: {
|
||||
TspProviderCustomerType: {
|
||||
Unknown: 'ناشناس',
|
||||
Known: 'شناسایی شده',
|
||||
},
|
||||
|
||||
@@ -4,14 +4,14 @@ export enum GoldKarat {
|
||||
KARAT_24 = '24',
|
||||
}
|
||||
|
||||
export enum FiscalRequestType {
|
||||
export enum TspProviderRequestType {
|
||||
MAIN = 'MAIN',
|
||||
UPDATE = 'UPDATE',
|
||||
REVOKE = 'REVOKE',
|
||||
REMOVE = 'REMOVE',
|
||||
}
|
||||
|
||||
export enum FiscalInvoiceCustomerType {
|
||||
export enum TspProviderCustomerType {
|
||||
Unknown = 'Unknown',
|
||||
Known = 'Known',
|
||||
}
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
export interface FetchRequestContext {
|
||||
url: string
|
||||
init: RequestInit
|
||||
}
|
||||
|
||||
export interface FetchRequestInterceptor {
|
||||
onRequest?(
|
||||
context: FetchRequestContext,
|
||||
): Promise<FetchRequestContext> | FetchRequestContext
|
||||
onResponse?(
|
||||
context: FetchRequestContext,
|
||||
response: Response,
|
||||
): Promise<Response> | Response
|
||||
onError?(context: FetchRequestContext, error: unknown): Promise<void> | void
|
||||
}
|
||||
|
||||
function mergeHeaders(
|
||||
currentHeaders: HeadersInit | undefined,
|
||||
newHeaders: HeadersInit,
|
||||
): Headers {
|
||||
const mergedHeaders = new Headers(currentHeaders)
|
||||
const incomingHeaders = new Headers(newHeaders)
|
||||
|
||||
incomingHeaders.forEach((value, key) => {
|
||||
mergedHeaders.set(key, value)
|
||||
})
|
||||
|
||||
return mergedHeaders
|
||||
}
|
||||
|
||||
export function createHeaderRequestInterceptor(
|
||||
headers: HeadersInit,
|
||||
): FetchRequestInterceptor {
|
||||
return {
|
||||
onRequest(context) {
|
||||
return {
|
||||
...context,
|
||||
init: {
|
||||
...context.init,
|
||||
headers: mergeHeaders(context.init.headers, headers),
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export function createEnsureSuccessResponseInterceptor(): FetchRequestInterceptor {
|
||||
return {
|
||||
async onResponse(_, response) {
|
||||
if (response.ok) {
|
||||
return response
|
||||
}
|
||||
|
||||
const errorBody = await response.text().catch(() => '')
|
||||
const normalizedBody = errorBody
|
||||
return Promise.reject({
|
||||
status: response.status,
|
||||
statusText: response.statusText,
|
||||
body: normalizedBody,
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ export interface SaleInvoiceGoldTypePayload {
|
||||
karat: keyof typeof GoldKarat
|
||||
wages: number
|
||||
profit: number
|
||||
commission: number
|
||||
}
|
||||
export interface SaleInvoiceStandardPayload {}
|
||||
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
import {
|
||||
FetchRequestContext,
|
||||
FetchRequestInterceptor,
|
||||
} from '@/common/interceptors/fetch-request.interceptor'
|
||||
import { Injectable } from '@nestjs/common'
|
||||
|
||||
@Injectable()
|
||||
export class HttpClientUtil {
|
||||
async request(
|
||||
url: string,
|
||||
init: RequestInit = {},
|
||||
interceptors: FetchRequestInterceptor[] = [],
|
||||
): Promise<Response> {
|
||||
let context: FetchRequestContext = { url, init }
|
||||
|
||||
for (const interceptor of interceptors) {
|
||||
if (!interceptor.onRequest) {
|
||||
continue
|
||||
}
|
||||
|
||||
context = await interceptor.onRequest(context)
|
||||
}
|
||||
|
||||
try {
|
||||
let response = await fetch(context.url, context.init)
|
||||
|
||||
for (const interceptor of interceptors) {
|
||||
if (!interceptor.onResponse) {
|
||||
continue
|
||||
}
|
||||
response = await interceptor.onResponse(context, response)
|
||||
console.log('response')
|
||||
console.log(response)
|
||||
}
|
||||
|
||||
return response
|
||||
} catch (error: any) {
|
||||
for (const interceptor of interceptors) {
|
||||
if (!interceptor.onError) {
|
||||
continue
|
||||
}
|
||||
await interceptor.onError(context, error)
|
||||
}
|
||||
throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,3 +3,4 @@ export * from './enum-translator.util'
|
||||
export * from './mappers/consumer_mappers.util'
|
||||
export * from './password.util'
|
||||
export * from './tracking-code-generator.util'
|
||||
export * from './http-client.util'
|
||||
|
||||
Reference in New Issue
Block a user