Files
psp_api/src/modules/tspProviders/switch/nama/nama-provider.adapter.ts
T

228 lines
7.4 KiB
TypeScript
Raw Normal View History

import {
createEnsureSuccessResponseInterceptor,
createHeaderRequestInterceptor,
FetchRequestInterceptor,
} from '@/common/interceptors/fetch-request.interceptor'
import { HttpClientUtil } from '@/common/utils/http-client.util'
2026-05-04 11:21:49 +03:30
import { TspProviderResponseStatus } from '@/generated/prisma/enums'
import { Injectable, Logger } from '@nestjs/common'
import {
IProviderSwitchAdapter,
TspProviderBulkSendResultDto,
TspProviderGetResultDto,
2026-05-04 11:21:49 +03:30
TspProviderRevokePayloadDto,
TspProviderRevokeResponseDto,
TspProviderSendItemResultDto,
TspProviderSendPayloadDto,
} from '../../dto/provider-switch.dto'
import {
NamaProviderGetResponseDto,
NamaProviderResponseStatus,
2026-05-04 11:21:49 +03:30
NamaProviderRevokeRequestDto,
NamaProviderRevokeResponseDto,
NamaProviderSendItemResponseDto,
} from './nama-provider.dto'
2026-05-04 11:21:49 +03:30
import { NamaProviderUtils } from './nama-provider.util'
@Injectable()
export class NamaProviderSwitchAdapter implements IProviderSwitchAdapter {
readonly code = 'NAMA'
private readonly logger = new Logger(NamaProviderSwitchAdapter.name)
private readonly sandboxBaseUrl =
process.env.NAMA_PROVIDER_SANDBOX_URL || 'https://external-api-dev.namatsp.ir'
private readonly productionBaseUrl =
process.env.NAMA_PROVIDER_PRODUCTION_URL || 'https://api.nama.ir'
private readonly sendPath = '/api/v1/invoices/single-send'
private readonly sendBulkPath = '/api/v1/invoices'
private readonly checkBulkStatus = '/api/v1/invoices/check-by-uuids'
private readonly getPath = '/api/v1/invoices'
2026-05-04 11:21:49 +03:30
constructor(
private readonly httpClient: HttpClientUtil,
private readonly namaProviderUtils: NamaProviderUtils,
) {}
private get baseUrl() {
return this.sandboxBaseUrl
// return process.env.NODE_ENV === 'production'
// ? this.productionBaseUrl
// : this.sandboxBaseUrl
}
private buildSendUrl() {
return `${this.baseUrl}${this.sendPath}`
}
private buildGetUrl(invoiceId: string) {
return `${this.baseUrl}${this.getPath}/${invoiceId}`
}
private createRequestInterceptors(token: string): FetchRequestInterceptor[] {
return [
createHeaderRequestInterceptor({
'Content-Type': 'application/json',
Authorization: token,
}),
createEnsureSuccessResponseInterceptor(),
{
onError: (context, error) => {
this.logger.error(`NAMA request failed: ${context.url}`, error)
return Promise.reject(error)
},
},
]
}
async send(payload: TspProviderSendPayloadDto): Promise<TspProviderSendItemResultDto> {
2026-05-04 11:21:49 +03:30
const mappedRequest = this.namaProviderUtils.mapToNamaRequestDto(payload)
try {
console.log(mappedRequest)
const response = await this.httpClient.request(
this.buildSendUrl(),
{
method: 'POST',
body: JSON.stringify(mappedRequest),
},
this.createRequestInterceptors(payload.tsp_token),
)
const providerResponse: NamaProviderSendItemResponseDto = await response.json()
this.logger.debug('NAMA provider response', providerResponse)
const result: TspProviderSendItemResultDto = {
invoice_id: payload.invoice_id,
request_payload: payload,
hasError: !response.ok,
message: providerResponse.message,
sent_at: new Date().toISOString(),
response_payload: providerResponse,
received_at: providerResponse.tsp_update_time,
tax_id: providerResponse.tax_id,
2026-05-04 11:21:49 +03:30
status: this.namaProviderUtils.mapResponseStatus(
providerResponse.status as NamaProviderResponseStatus,
),
}
return result
} catch (err) {
this.logger.error('NAMA send failed', err)
const failure: TspProviderSendItemResultDto = {
invoice_id: payload.invoice_id,
request_payload: payload,
hasError: true,
message: (err as Error).message,
sent_at: new Date().toISOString(),
received_at: new Date().toISOString(),
tax_id: null,
status: TspProviderResponseStatus.NOT_SEND,
}
return failure
}
}
async sendBulk(
payloads: TspProviderSendPayloadDto[],
): Promise<TspProviderBulkSendResultDto[]> {
const result: TspProviderBulkSendResultDto[] = []
for (const payload of payloads) {
const itemResults = await this.send(payload)
result.push({
invoice_id: payload.invoice_id,
items: [itemResults],
})
}
return result
}
async get(invoiceId: string, tsp_token: string): Promise<TspProviderGetResultDto> {
try {
const response = await this.httpClient.request(
this.buildGetUrl(invoiceId),
{
method: 'GET',
},
this.createRequestInterceptors(tsp_token),
)
const providerResponse: NamaProviderGetResponseDto = await response.json()
this.logger.debug('NAMA provider response', providerResponse)
const result: TspProviderGetResultDto = {
hasError: !response.ok,
message: providerResponse.message,
response_payload: providerResponse,
sent_at: new Date().toISOString(),
received_at: providerResponse.tsp_update_time || new Date().toISOString(),
tax_id: providerResponse.tax_id,
2026-05-04 11:21:49 +03:30
status: this.namaProviderUtils.mapResponseStatus(
providerResponse.status as NamaProviderResponseStatus,
),
}
return result
} catch (err) {
this.logger.error('NAMA send failed', err)
// const failure: TspProviderGetResultDto = {
// invoice_id: invoiceId,
// hasError: true,
// message: (err as Error).message,
// received_at: new Date().toISOString(),
// tax_id: null,
// status: TspProviderResponseStatus.NOT_SEND,
// }
// return failure
throw err
}
}
2026-05-04 11:21:49 +03:30
async revoke(
payload: TspProviderRevokePayloadDto,
): Promise<TspProviderRevokeResponseDto> {
const mappedRequest: NamaProviderRevokeRequestDto =
this.namaProviderUtils.mapRevokeToNamaRequestDto(payload)
2026-05-05 10:14:48 +03:30
this.logger.debug('NAMA provider response', mappedRequest)
2026-05-04 11:21:49 +03:30
try {
const response = await this.httpClient.request(
this.buildSendUrl(),
{
method: 'POST',
body: JSON.stringify(mappedRequest),
},
this.createRequestInterceptors(payload.tsp_token),
)
const providerResponse: NamaProviderRevokeResponseDto = await response.json()
this.logger.debug('NAMA provider response', providerResponse)
2026-05-04 11:21:49 +03:30
const result: TspProviderRevokeResponseDto = {
invoice_id: payload.invoice_id,
request_payload: mappedRequest,
hasError: !response.ok,
message: providerResponse.message,
sent_at: new Date().toISOString(),
response_payload: providerResponse,
received_at: providerResponse.tsp_update_time,
tax_id: providerResponse.tax_id,
status: this.namaProviderUtils.mapResponseStatus(
providerResponse.status as NamaProviderResponseStatus,
),
}
2026-05-04 11:21:49 +03:30
return result
} catch (err) {
this.logger.error('NAMA Revoke failed', err)
const failure: TspProviderRevokeResponseDto = {
invoice_id: payload.invoice_id,
request_payload: mappedRequest,
hasError: true,
message: (err as Error).message,
sent_at: new Date().toISOString(),
received_at: new Date().toISOString(),
tax_id: '',
status: TspProviderResponseStatus.FAILURE,
}
return failure
}
}
}