feat: implement tax switch functionality with Nama adapter
- Add DTOs for tax switch operations including payloads and results. - Create SalesInvoiceFiscalSwitchService to handle sending and retrieving tax data. - Implement SalesInvoiceFiscalService for managing invoice tax submissions and results persistence. - Develop NamaTaxSwitchAdapter for interfacing with the external tax service. - Introduce NamaTaxRequestDto and related classes for structured tax requests.
This commit is contained in:
+12
-10
@@ -1,14 +1,14 @@
|
||||
import { Injectable } from '@nestjs/common'
|
||||
import {
|
||||
TaxSwitchBulkSendResultDto,
|
||||
TaxSwitchBulkSendResultDto as FiscalSwitchBulkSendResultDto,
|
||||
TaxSwitchSendItemResultDto as FiscalSwitchSendItemResultDto,
|
||||
TaxSwitchSendPayloadDto as FiscalSwitchSendPayloadDto,
|
||||
TaxSwitchGetResultDto,
|
||||
TaxSwitchSendItemResultDto,
|
||||
TaxSwitchSendPayloadDto,
|
||||
} from './dto/tax-switch.dto'
|
||||
import { NamaTaxSwitchAdapter } from './switch/nama-tax-switch.adapter'
|
||||
import { NamaTaxSwitchAdapter } from './switch/nama/nama-fiscal-switch.adapter'
|
||||
|
||||
@Injectable()
|
||||
export class SalesInvoiceTaxSwitchService {
|
||||
export class SalesInvoiceFiscalSwitchService {
|
||||
constructor(private readonly namaAdapter: NamaTaxSwitchAdapter) {}
|
||||
|
||||
private resolveSwitch(providerCode?: string | null) {
|
||||
@@ -21,15 +21,17 @@ export class SalesInvoiceTaxSwitchService {
|
||||
}
|
||||
}
|
||||
|
||||
async send(payload: TaxSwitchSendPayloadDto): Promise<TaxSwitchSendItemResultDto[]> {
|
||||
async send(
|
||||
payload: FiscalSwitchSendPayloadDto,
|
||||
): Promise<FiscalSwitchSendItemResultDto[]> {
|
||||
const adapter = this.resolveSwitch(payload.provider_code)
|
||||
return adapter.send(payload)
|
||||
}
|
||||
|
||||
async sendBulk(
|
||||
payloads: TaxSwitchSendPayloadDto[],
|
||||
): Promise<TaxSwitchBulkSendResultDto[]> {
|
||||
const groupedByProvider = new Map<string, TaxSwitchSendPayloadDto[]>()
|
||||
payloads: FiscalSwitchSendPayloadDto[],
|
||||
): Promise<FiscalSwitchBulkSendResultDto[]> {
|
||||
const groupedByProvider = new Map<string, FiscalSwitchSendPayloadDto[]>()
|
||||
|
||||
for (const payload of payloads) {
|
||||
const key = payload.provider_code?.trim().toUpperCase() || 'NAMA'
|
||||
@@ -38,7 +40,7 @@ export class SalesInvoiceTaxSwitchService {
|
||||
groupedByProvider.set(key, currentGroup)
|
||||
}
|
||||
|
||||
const result: TaxSwitchBulkSendResultDto[] = []
|
||||
const result: FiscalSwitchBulkSendResultDto[] = []
|
||||
for (const [providerCode, groupedPayloads] of groupedByProvider.entries()) {
|
||||
const adapter = this.resolveSwitch(providerCode)
|
||||
const providerResult = await adapter.sendBulk(groupedPayloads)
|
||||
+4
-4
@@ -7,7 +7,7 @@ import {
|
||||
TaxSwitchSendItemResultDto,
|
||||
TaxSwitchSendPayloadDto,
|
||||
} from './dto/tax-switch.dto'
|
||||
import { SalesInvoiceTaxSwitchService } from './sales-invoice-tax-switch.service'
|
||||
import { SalesInvoiceFiscalSwitchService } from './sales-invoice-fiscal-switch.service'
|
||||
|
||||
type TaxRow = {
|
||||
id: string
|
||||
@@ -20,10 +20,10 @@ type ItemTaxProviderRow = {
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class SalesInvoiceTaxService {
|
||||
export class SalesInvoiceFiscalService {
|
||||
constructor(
|
||||
private readonly prisma: PrismaService,
|
||||
private readonly taxSwitchService: SalesInvoiceTaxSwitchService,
|
||||
private readonly taxSwitchService: SalesInvoiceFiscalSwitchService,
|
||||
) {}
|
||||
|
||||
async send(consumer_id: string, invoice_id: string): Promise<void> {
|
||||
@@ -173,7 +173,7 @@ export class SalesInvoiceTaxService {
|
||||
})
|
||||
|
||||
if (!invoice) {
|
||||
throw new NotFoundException('Sales invoice was not found.')
|
||||
throw new NotFoundException('فاکتور مورد نظر یافت نشد.')
|
||||
}
|
||||
|
||||
return {
|
||||
+1
-1
@@ -6,7 +6,7 @@ import {
|
||||
TaxSwitchGetResultDto,
|
||||
TaxSwitchSendItemResultDto,
|
||||
TaxSwitchSendPayloadDto,
|
||||
} from '../dto/tax-switch.dto'
|
||||
} from '../../dto/tax-switch.dto'
|
||||
|
||||
@Injectable()
|
||||
export class NamaTaxSwitchAdapter implements ITaxSwitchAdapter {
|
||||
@@ -0,0 +1,124 @@
|
||||
import { ApiProperty } from '@nestjs/swagger'
|
||||
import { Type } from 'class-transformer'
|
||||
import { IsArray, IsString, ValidateNested } from 'class-validator'
|
||||
|
||||
export class NamaTaxBodyItemDto {
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
sstid: string
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
vra: string
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
sstt: string
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
fee: string
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
dis: string
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
mu: string
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
am: string
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
consfee: string
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
bros: string
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
spro: string
|
||||
}
|
||||
|
||||
export class NamaTaxHeaderDto {
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
ins: string
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
inp: string
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
inty: string
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
unique_tax_code: string
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
inno: string
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
tins: string
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
indatim: string
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
name: string
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
tob: string
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
address: string
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
mobile: string
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
bid: string
|
||||
}
|
||||
|
||||
export class NamaTaxRequestDto {
|
||||
@ApiProperty({ type: [NamaTaxBodyItemDto] })
|
||||
@IsArray()
|
||||
@ValidateNested({ each: true })
|
||||
@Type(() => NamaTaxBodyItemDto)
|
||||
body: NamaTaxBodyItemDto[]
|
||||
|
||||
@ApiProperty({ type: [Object] })
|
||||
@IsArray()
|
||||
payment: unknown[]
|
||||
|
||||
@ApiProperty({ type: NamaTaxHeaderDto })
|
||||
@ValidateNested()
|
||||
@Type(() => NamaTaxHeaderDto)
|
||||
header: NamaTaxHeaderDto
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
uuid: string
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
economic_code: string
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
fiscal_id: string
|
||||
}
|
||||
@@ -1,18 +1,18 @@
|
||||
import { PrismaModule } from '@/prisma/prisma.module'
|
||||
import { Module } from '@nestjs/common'
|
||||
import { SalesInvoiceFiscalSwitchService } from './fiscal/sales-invoice-fiscal-switch.service'
|
||||
import { SalesInvoiceFiscalService } from './fiscal/sales-invoice-fiscal.service'
|
||||
import { NamaTaxSwitchAdapter } from './fiscal/switch/nama/nama-fiscal-switch.adapter'
|
||||
import { StatisticsController } from './saleInvoices.controller'
|
||||
import { SaleInvoicesService } from './saleInvoices.service'
|
||||
import { SalesInvoiceTaxSwitchService } from './tax/sales-invoice-tax-switch.service'
|
||||
import { SalesInvoiceTaxService } from './tax/sales-invoice-tax.service'
|
||||
import { NamaTaxSwitchAdapter } from './tax/switch/nama-tax-switch.adapter'
|
||||
|
||||
@Module({
|
||||
imports: [PrismaModule],
|
||||
controllers: [StatisticsController],
|
||||
providers: [
|
||||
SaleInvoicesService,
|
||||
SalesInvoiceTaxService,
|
||||
SalesInvoiceTaxSwitchService,
|
||||
SalesInvoiceFiscalService,
|
||||
SalesInvoiceFiscalSwitchService,
|
||||
NamaTaxSwitchAdapter,
|
||||
],
|
||||
exports: [SaleInvoicesService],
|
||||
|
||||
@@ -6,13 +6,13 @@ import {
|
||||
import { PrismaService } from '@/prisma/prisma.service'
|
||||
import { BadRequestException, Injectable } from '@nestjs/common'
|
||||
import { ResponseMapper } from 'common/response/response-mapper'
|
||||
import { SalesInvoiceTaxService } from './tax/sales-invoice-tax.service'
|
||||
import { SalesInvoiceFiscalService } from './fiscal/sales-invoice-fiscal.service'
|
||||
|
||||
@Injectable()
|
||||
export class SaleInvoicesService {
|
||||
constructor(
|
||||
private readonly prisma: PrismaService,
|
||||
private salesInvoiceTaxService: SalesInvoiceTaxService,
|
||||
private salesInvoiceTaxService: SalesInvoiceFiscalService,
|
||||
) {}
|
||||
|
||||
private readonly defaultSelect: SalesInvoiceSelect = {
|
||||
|
||||
Reference in New Issue
Block a user