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() const now = new Date()
export const infoSelect: ConsumerSelect = { export const infoSelect: ConsumerSelect = {
type: true,
legal: { legal: {
select: { select: {
name: true, name: true,
@@ -11,7 +11,7 @@ export default (consumer: any) => {
return { return {
...rest, ...rest,
partner, partner,
type: translateEnumValue('ConsumerType', consumer.type), type: translateEnumValue('ConsumerType', type),
status: translateEnumValue('ConsumerStatus', consumer.status), status: translateEnumValue('ConsumerStatus', consumer.status),
legal: legal ? { ...legal } : null, legal: legal ? { ...legal } : null,
individual: individual 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. // 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. // Defaults include common localhost origins used by front-end dev servers.
const defaultOrigins = [ 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 envOrigins = process.env.CORS_ORIGINS const envOrigins = process.env.CORS_ORIGINS
? process.env.CORS_ORIGINS.split(',') ? process.env.CORS_ORIGINS.split(',')
.map(s => s.trim()) .map(s => s.trim())
@@ -1,3 +1,4 @@
import { translateEnumValue } from '@/common/utils'
import { ConsumerAccountSelect } from '@/generated/prisma/models' import { ConsumerAccountSelect } from '@/generated/prisma/models'
import { PrismaService } from '@/prisma/prisma.service' import { PrismaService } from '@/prisma/prisma.service'
import { Injectable } from '@nestjs/common' import { Injectable } from '@nestjs/common'
@@ -62,7 +63,21 @@ export class AccountsService {
where: this.defaultWhere(partner_id, consumer_id), where: this.defaultWhere(partner_id, consumer_id),
select: this.default_select, 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) { async findOne(partner_id: string, consumer_id: string, id: string) {
@@ -33,6 +33,7 @@ export class PartnerConsumersService {
id: true, id: true,
status: true, status: true,
created_at: true, created_at: true,
type: true,
...QUERY_CONSTANTS.CONSUMER.infoSelect, ...QUERY_CONSTANTS.CONSUMER.infoSelect,
...QUERY_CONSTANTS.CONSUMER.activeBusinessCount, ...QUERY_CONSTANTS.CONSUMER.activeBusinessCount,
} }
@@ -258,48 +258,14 @@ export class SalesInvoicesService {
return ResponseMapper.single({ return ResponseMapper.single({
...rest, ...rest,
status: tsp_attempts?.[0]?.status || TspProviderResponseStatus.NOT_SEND, status: translateEnumValue(
'TspProviderResponseStatus',
invoice.tsp_attempts?.[0]?.status || TspProviderResponseStatus.NOT_SEND,
),
}) })
} else throw new NotFoundException('فاکتور مورد نظر شما یافت نشد.') } 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) { async create(data: CreateSalesInvoiceDto, posInfo: IPosPayload) {
const { business_id, pos_id, consumer_account_id, complex_id } = posInfo const { business_id, pos_id, consumer_account_id, complex_id } = posInfo
const normalizedInvoiceDate = this.normalizeInvoiceDate(data.invoice_date) const normalizedInvoiceDate = this.normalizeInvoiceDate(data.invoice_date)
@@ -360,6 +326,43 @@ export class SalesInvoicesService {
throw new BadRequestException('ایجاد فاکتور با خطا مواجه شد.') 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) { private isRetryableInvoiceConflict(error: unknown) {
if (!(error instanceof Prisma.PrismaClientKnownRequestError)) { if (!(error instanceof Prisma.PrismaClientKnownRequestError)) {
return false return false
@@ -470,6 +470,7 @@ export class SalesInvoiceTspService {
select: { select: {
id: true, id: true,
status: true, status: true,
tax_id: true,
}, },
}, },
pos: { pos: {
@@ -531,7 +532,7 @@ export class SalesInvoiceTspService {
fiscal_id: invoice.pos.complex.business_activity.fiscal_id, fiscal_id: invoice.pos.complex.business_activity.fiscal_id,
tsp_token: invoice.pos.complex.business_activity.partner_token, tsp_token: invoice.pos.complex.business_activity.partner_token,
tsp_provider: partner.tsp_provider!, 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 = const mappedRequest: NamaProviderRevokeRequestDto =
this.namaProviderUtils.mapRevokeToNamaRequestDto(payload) this.namaProviderUtils.mapRevokeToNamaRequestDto(payload)
this.logger.debug('NAMA provider response', mappedRequest)
try { try {
const response = await this.httpClient.request( const response = await this.httpClient.request(
this.buildSendUrl(), this.buildSendUrl(),
@@ -5,7 +5,6 @@ import {
IsArray, IsArray,
IsEnum, IsEnum,
IsNumber, IsNumber,
IsObject,
IsOptional, IsOptional,
IsString, IsString,
Min, Min,
@@ -145,7 +144,11 @@ export class NamaProviderHeaderDto {
@IsString() @IsString()
name: string name: string
@ApiProperty({ required: true, description: 'نوع شخصیت خریدار' }) @ApiProperty({
required: false,
description:
'نوع شخصیت خریدار (در صورتی‌که خریدار نوع ۲ باشه باید ۱ یا ۲ گذاشته بشه)',
})
@IsString() @IsString()
tob: string tob: string
@@ -296,6 +299,13 @@ export class NamaProviderRevokeHeaderDto {
@IsString() @IsString()
inno: string inno: string
@ApiProperty({
required: true,
description: 'تاریخ و زمان صدور صورتحساب به صورت timestamp',
})
@IsString()
indatim: string
@ApiProperty({ @ApiProperty({
required: true, required: true,
description: 'آخرین شماره مالیاتی دریافت شده مربوط به فاکتور', description: 'آخرین شماره مالیاتی دریافت شده مربوط به فاکتور',
@@ -315,9 +325,9 @@ export class NamaProviderRevokeRequestDto {
// @ValidateNested({ each: true }) // @ValidateNested({ each: true })
// @Type(() => NamaProviderPaymentInfoDto) // @Type(() => NamaProviderPaymentInfoDto)
// payment: NamaProviderPaymentInfoDto[] // payment: NamaProviderPaymentInfoDto[]
@ApiProperty({ type: Object, required: true }) // @ApiProperty({ type: Object, required: true })
@IsObject() // @IsObject()
body: {} // body: {}
@ApiProperty({ type: NamaProviderRevokeHeaderDto }) @ApiProperty({ type: NamaProviderRevokeHeaderDto })
@ValidateNested() @ValidateNested()
@@ -77,8 +77,8 @@ export class NamaProviderUtils {
inno: payload.invoice_number.toString(), inno: payload.invoice_number.toString(),
ins: this.mapTspProviderRequestType(TspProviderRequestType.REVOKE), ins: this.mapTspProviderRequestType(TspProviderRequestType.REVOKE),
irtaxid: payload.last_attempt_tax_id, irtaxid: payload.last_attempt_tax_id,
indatim: new Date().getTime() + '',
}, },
body: {},
} }
} }
@@ -140,17 +140,17 @@ export class NamaProviderUtils {
case CustomerType.LEGAL: case CustomerType.LEGAL:
return '2' return '2'
default: default:
return '5' return ''
} }
} }
private mapCustomerInfo(customer?: CustomerInfoDto) { private mapCustomerInfo(customer?: CustomerInfoDto) {
const info = {} as any const info = {} as any
info.tob = this.mapCustomerType(customer?.type)
if (customer?.type === CustomerType.LEGAL && customer.legal_info) { if (customer?.type === CustomerType.LEGAL && customer.legal_info) {
info.name = customer.legal_info.name info.name = customer.legal_info.name
info.bid = customer.legal_info.economic_code info.bid = customer.legal_info.economic_code
info.address = '' info.address = ''
info.tob = '2'
} else if (customer?.type === CustomerType.INDIVIDUAL && customer.individual_info) { } else if (customer?.type === CustomerType.INDIVIDUAL && customer.individual_info) {
info.name = `${customer.individual_info?.first_name || ''} ${ info.name = `${customer.individual_info?.first_name || ''} ${
customer.individual_info?.last_name || '' customer.individual_info?.last_name || ''
@@ -158,6 +158,7 @@ export class NamaProviderUtils {
info.bid = customer.individual_info.national_id info.bid = customer.individual_info.national_id
info.mobile = customer.individual_info.mobile_number info.mobile = customer.individual_info.mobile_number
info.address = '' info.address = ''
info.tob = '1'
} }
return info return info
} }