update revoke

This commit is contained in:
2026-05-05 10:14:48 +03:30
parent 6a48f203a9
commit 4af07fe3e8
10 changed files with 84 additions and 57 deletions
+1
View File
@@ -3,6 +3,7 @@ import { ConsumerSelect, ConsumerWhereInput } from '@/generated/prisma/models'
const now = new Date()
export const infoSelect: ConsumerSelect = {
type: true,
legal: {
select: {
name: true,
@@ -11,7 +11,7 @@ export default (consumer: any) => {
return {
...rest,
partner,
type: translateEnumValue('ConsumerType', consumer.type),
type: translateEnumValue('ConsumerType', type),
status: translateEnumValue('ConsumerStatus', consumer.status),
legal: legal ? { ...legal } : null,
individual: individual
+1 -8
View File
@@ -57,14 +57,7 @@ async function bootstrap() {
// Enable CORS. You can set `CORS_ORIGINS` to a comma-separated list of allowed origins.
// Defaults include common localhost origins used by front-end dev servers.
const defaultOrigins = [
'http://localhost:5000',
'http://127.0.0.1:5000',
'http://192.168.128.73:5000',
'http://localhost:5005',
'http://127.0.0.1:5005',
'http://192.168.128.73:5005',
]
const defaultOrigins = []
const envOrigins = process.env.CORS_ORIGINS
? process.env.CORS_ORIGINS.split(',')
.map(s => s.trim())
@@ -1,3 +1,4 @@
import { translateEnumValue } from '@/common/utils'
import { ConsumerAccountSelect } from '@/generated/prisma/models'
import { PrismaService } from '@/prisma/prisma.service'
import { Injectable } from '@nestjs/common'
@@ -62,7 +63,21 @@ export class AccountsService {
where: this.defaultWhere(partner_id, consumer_id),
select: this.default_select,
})
return ResponseMapper.list(accounts)
const mappedAccounts = accounts.map(account => {
const { account: mainAccount, role, ...rest } = account
return {
...rest,
account: {
...mainAccount,
status: translateEnumValue('AccountStatus', mainAccount.status),
},
role: translateEnumValue('ConsumerRole', role),
}
})
return ResponseMapper.list(mappedAccounts)
}
async findOne(partner_id: string, consumer_id: string, id: string) {
@@ -33,6 +33,7 @@ export class PartnerConsumersService {
id: true,
status: true,
created_at: true,
type: true,
...QUERY_CONSTANTS.CONSUMER.infoSelect,
...QUERY_CONSTANTS.CONSUMER.activeBusinessCount,
}
@@ -258,48 +258,14 @@ export class SalesInvoicesService {
return ResponseMapper.single({
...rest,
status: tsp_attempts?.[0]?.status || TspProviderResponseStatus.NOT_SEND,
status: translateEnumValue(
'TspProviderResponseStatus',
invoice.tsp_attempts?.[0]?.status || TspProviderResponseStatus.NOT_SEND,
),
})
} else throw new NotFoundException('فاکتور مورد نظر شما یافت نشد.')
}
async send(invoiceId: string, posInfo: IPosPayload) {
const consumer_id = await this.checkAccessToInvoice(
posInfo.consumer_account_id,
posInfo.pos_id,
)
const invoice = await this.salesInvoiceTaxService.send(consumer_id, invoiceId)
return ResponseMapper.single(invoice)
}
async revoke(invoiceId: string, posInfo: IPosPayload) {
await this.checkAccessToInvoice(posInfo.consumer_account_id, posInfo.pos_id)
const invoice = await this.salesInvoiceTaxService.revoke(posInfo.pos_id, invoiceId)
return ResponseMapper.single(invoice)
}
async inquiry(consumer_account_id: string, pos_id: string, invoiceId: string) {
const consumer_id = await this.checkAccessToInvoice(consumer_account_id, pos_id)
const invoice = await this.salesInvoiceTaxService.get(invoiceId, pos_id, consumer_id)
return ResponseMapper.single(invoice)
}
// async sendBulk(invoiceIds: string[], posInfo: IPosPayload) {
// if (!invoiceIds.length) {
// throw new BadRequestException('invoice_ids is required and cannot be empty.')
// }
// await this.salesInvoiceTaxService.sendBulk(invoiceIds, posInfo.pos_id)
// return ResponseMapper.single({
// invoice_ids: invoiceIds,
// sent_to_tax: true,
// })
// }
async create(data: CreateSalesInvoiceDto, posInfo: IPosPayload) {
const { business_id, pos_id, consumer_account_id, complex_id } = posInfo
const normalizedInvoiceDate = this.normalizeInvoiceDate(data.invoice_date)
@@ -360,6 +326,43 @@ export class SalesInvoicesService {
throw new BadRequestException('ایجاد فاکتور با خطا مواجه شد.')
}
async send(invoiceId: string, posInfo: IPosPayload) {
const consumer_id = await this.checkAccessToInvoice(
posInfo.consumer_account_id,
posInfo.pos_id,
)
const invoice = await this.salesInvoiceTaxService.send(consumer_id, invoiceId)
return ResponseMapper.single(invoice)
}
async revoke(invoiceId: string, posInfo: IPosPayload) {
await this.checkAccessToInvoice(posInfo.consumer_account_id, posInfo.pos_id)
const invoice = await this.salesInvoiceTaxService.revoke(posInfo.pos_id, invoiceId)
return ResponseMapper.single(invoice)
}
async inquiry(consumer_account_id: string, pos_id: string, invoiceId: string) {
const consumer_id = await this.checkAccessToInvoice(consumer_account_id, pos_id)
const invoice = await this.salesInvoiceTaxService.get(invoiceId, pos_id, consumer_id)
return ResponseMapper.single(invoice)
}
// async sendBulk(invoiceIds: string[], posInfo: IPosPayload) {
// if (!invoiceIds.length) {
// throw new BadRequestException('invoice_ids is required and cannot be empty.')
// }
// await this.salesInvoiceTaxService.sendBulk(invoiceIds, posInfo.pos_id)
// return ResponseMapper.single({
// invoice_ids: invoiceIds,
// sent_to_tax: true,
// })
// }
private isRetryableInvoiceConflict(error: unknown) {
if (!(error instanceof Prisma.PrismaClientKnownRequestError)) {
return false
@@ -470,6 +470,7 @@ export class SalesInvoiceTspService {
select: {
id: true,
status: true,
tax_id: true,
},
},
pos: {
@@ -531,7 +532,7 @@ export class SalesInvoiceTspService {
fiscal_id: invoice.pos.complex.business_activity.fiscal_id,
tsp_token: invoice.pos.complex.business_activity.partner_token,
tsp_provider: partner.tsp_provider!,
last_attempt_tax_id: invoice.tsp_attempts[0].id,
last_attempt_tax_id: invoice.tsp_attempts[0].tax_id!,
}
}
@@ -180,6 +180,8 @@ export class NamaProviderSwitchAdapter implements IProviderSwitchAdapter {
const mappedRequest: NamaProviderRevokeRequestDto =
this.namaProviderUtils.mapRevokeToNamaRequestDto(payload)
this.logger.debug('NAMA provider response', mappedRequest)
try {
const response = await this.httpClient.request(
this.buildSendUrl(),
@@ -5,7 +5,6 @@ import {
IsArray,
IsEnum,
IsNumber,
IsObject,
IsOptional,
IsString,
Min,
@@ -145,7 +144,11 @@ export class NamaProviderHeaderDto {
@IsString()
name: string
@ApiProperty({ required: true, description: 'نوع شخصیت خریدار' })
@ApiProperty({
required: false,
description:
'نوع شخصیت خریدار (در صورتی‌که خریدار نوع ۲ باشه باید ۱ یا ۲ گذاشته بشه)',
})
@IsString()
tob: string
@@ -296,6 +299,13 @@ export class NamaProviderRevokeHeaderDto {
@IsString()
inno: string
@ApiProperty({
required: true,
description: 'تاریخ و زمان صدور صورتحساب به صورت timestamp',
})
@IsString()
indatim: string
@ApiProperty({
required: true,
description: 'آخرین شماره مالیاتی دریافت شده مربوط به فاکتور',
@@ -315,9 +325,9 @@ export class NamaProviderRevokeRequestDto {
// @ValidateNested({ each: true })
// @Type(() => NamaProviderPaymentInfoDto)
// payment: NamaProviderPaymentInfoDto[]
@ApiProperty({ type: Object, required: true })
@IsObject()
body: {}
// @ApiProperty({ type: Object, required: true })
// @IsObject()
// body: {}
@ApiProperty({ type: NamaProviderRevokeHeaderDto })
@ValidateNested()
@@ -77,8 +77,8 @@ export class NamaProviderUtils {
inno: payload.invoice_number.toString(),
ins: this.mapTspProviderRequestType(TspProviderRequestType.REVOKE),
irtaxid: payload.last_attempt_tax_id,
indatim: new Date().getTime() + '',
},
body: {},
}
}
@@ -140,17 +140,17 @@ export class NamaProviderUtils {
case CustomerType.LEGAL:
return '2'
default:
return '5'
return ''
}
}
private mapCustomerInfo(customer?: CustomerInfoDto) {
const info = {} as any
info.tob = this.mapCustomerType(customer?.type)
if (customer?.type === CustomerType.LEGAL && customer.legal_info) {
info.name = customer.legal_info.name
info.bid = customer.legal_info.economic_code
info.address = ''
info.tob = '2'
} else if (customer?.type === CustomerType.INDIVIDUAL && customer.individual_info) {
info.name = `${customer.individual_info?.first_name || ''} ${
customer.individual_info?.last_name || ''
@@ -158,6 +158,7 @@ export class NamaProviderUtils {
info.bid = customer.individual_info.national_id
info.mobile = customer.individual_info.mobile_number
info.address = ''
info.tob = '1'
}
return info
}