diff --git a/src/common/queryConstants/consumer.ts b/src/common/queryConstants/consumer.ts index 29547d0..dce9a2d 100644 --- a/src/common/queryConstants/consumer.ts +++ b/src/common/queryConstants/consumer.ts @@ -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, diff --git a/src/common/utils/mappers/consumer_mappers.util.ts b/src/common/utils/mappers/consumer_mappers.util.ts index 96acfca..ca2fb5d 100644 --- a/src/common/utils/mappers/consumer_mappers.util.ts +++ b/src/common/utils/mappers/consumer_mappers.util.ts @@ -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 diff --git a/src/main.ts b/src/main.ts index 84a831f..c472a03 100644 --- a/src/main.ts +++ b/src/main.ts @@ -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()) diff --git a/src/modules/partners/consumers/accounts/accounts.service.ts b/src/modules/partners/consumers/accounts/accounts.service.ts index 99d964d..7f868fc 100644 --- a/src/modules/partners/consumers/accounts/accounts.service.ts +++ b/src/modules/partners/consumers/accounts/accounts.service.ts @@ -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) { diff --git a/src/modules/partners/consumers/consumers.service.ts b/src/modules/partners/consumers/consumers.service.ts index 72eafd8..d2d0a51 100644 --- a/src/modules/partners/consumers/consumers.service.ts +++ b/src/modules/partners/consumers/consumers.service.ts @@ -33,6 +33,7 @@ export class PartnerConsumersService { id: true, status: true, created_at: true, + type: true, ...QUERY_CONSTANTS.CONSUMER.infoSelect, ...QUERY_CONSTANTS.CONSUMER.activeBusinessCount, } diff --git a/src/modules/pos/sales-invoices/sales-invoices.service.ts b/src/modules/pos/sales-invoices/sales-invoices.service.ts index 7850427..85a9698 100644 --- a/src/modules/pos/sales-invoices/sales-invoices.service.ts +++ b/src/modules/pos/sales-invoices/sales-invoices.service.ts @@ -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 diff --git a/src/modules/tspProviders/sales-invoice-tsp.service.ts b/src/modules/tspProviders/sales-invoice-tsp.service.ts index afc8aad..43048e9 100644 --- a/src/modules/tspProviders/sales-invoice-tsp.service.ts +++ b/src/modules/tspProviders/sales-invoice-tsp.service.ts @@ -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!, } } diff --git a/src/modules/tspProviders/switch/nama/nama-provider.adapter.ts b/src/modules/tspProviders/switch/nama/nama-provider.adapter.ts index c704bb8..8382dd8 100644 --- a/src/modules/tspProviders/switch/nama/nama-provider.adapter.ts +++ b/src/modules/tspProviders/switch/nama/nama-provider.adapter.ts @@ -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(), diff --git a/src/modules/tspProviders/switch/nama/nama-provider.dto.ts b/src/modules/tspProviders/switch/nama/nama-provider.dto.ts index b1b4124..54bbc63 100644 --- a/src/modules/tspProviders/switch/nama/nama-provider.dto.ts +++ b/src/modules/tspProviders/switch/nama/nama-provider.dto.ts @@ -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() diff --git a/src/modules/tspProviders/switch/nama/nama-provider.util.ts b/src/modules/tspProviders/switch/nama/nama-provider.util.ts index b768a9f..effdc37 100644 --- a/src/modules/tspProviders/switch/nama/nama-provider.util.ts +++ b/src/modules/tspProviders/switch/nama/nama-provider.util.ts @@ -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 }