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:
2026-04-30 16:27:46 +03:30
parent 58a7c359d8
commit a68a7f594d
38 changed files with 2678 additions and 287 deletions
@@ -0,0 +1,169 @@
import { ApiProperty } from '@nestjs/swagger'
import { Type } from 'class-transformer'
import {
IsArray,
IsDateString,
IsEnum,
IsNumber,
IsObject,
IsOptional,
IsString,
ValidateNested,
} from 'class-validator'
export enum TaxSendStatus {
SENT = 'SENT',
FAILED = 'FAILED',
PENDING = 'PENDING',
}
export class TaxSwitchSendItemPayloadDto {
@ApiProperty()
@IsString()
invoice_item_id: string
@ApiProperty()
@IsNumber()
quantity: number
@ApiProperty()
@IsNumber()
unit_price: number
@ApiProperty()
@IsNumber()
total_amount: number
@ApiProperty()
@IsString()
unit_type: string
@ApiProperty({ required: false, nullable: true })
@IsOptional()
@IsString()
good_id?: string | null
@ApiProperty({ required: false, nullable: true })
@IsOptional()
@IsString()
service_id?: string | null
@ApiProperty({ required: false, nullable: true, type: Object })
@IsOptional()
@IsObject()
payload?: unknown
@ApiProperty({ required: false, nullable: true, type: Object })
@IsOptional()
@IsObject()
good_snapshot?: unknown
}
export class TaxSwitchSendPayloadDto {
@ApiProperty()
@IsString()
invoice_id: string
@ApiProperty()
@IsString()
invoice_code: string
@ApiProperty({ required: false, nullable: true })
@IsOptional()
@IsDateString()
invoice_date: string | null
@ApiProperty()
@IsNumber()
total_amount: number
@ApiProperty({ required: false, nullable: true })
@IsOptional()
@IsString()
provider_code?: string | null
@ApiProperty({ type: [TaxSwitchSendItemPayloadDto] })
@IsArray()
@ValidateNested({ each: true })
@Type(() => TaxSwitchSendItemPayloadDto)
items: TaxSwitchSendItemPayloadDto[]
}
export class TaxSwitchSendItemResultDto {
@ApiProperty()
@IsString()
invoice_item_id: string
@ApiProperty({ enum: TaxSendStatus })
@IsEnum(TaxSendStatus)
status: TaxSendStatus
@ApiProperty({ required: false, nullable: true })
@IsOptional()
@IsString()
tax_id?: string | null
@ApiProperty({ required: false, nullable: true, type: Object })
@IsOptional()
@IsObject()
request_payload?: unknown
@ApiProperty({ required: false, nullable: true, type: Object })
@IsOptional()
@IsObject()
response_payload?: unknown
@ApiProperty({ required: false, nullable: true })
@IsOptional()
@IsString()
error_message?: string | null
@ApiProperty({ required: false, nullable: true })
@IsOptional()
@IsDateString()
sent_at?: string | null
@ApiProperty({ required: false, nullable: true })
@IsOptional()
@IsDateString()
received_at?: string | null
}
export class TaxSwitchBulkSendResultDto {
@ApiProperty()
@IsString()
invoice_id: string
@ApiProperty({ type: [TaxSwitchSendItemResultDto] })
@IsArray()
@ValidateNested({ each: true })
@Type(() => TaxSwitchSendItemResultDto)
items: TaxSwitchSendItemResultDto[]
}
export class TaxSwitchGetResultDto {
@ApiProperty()
@IsString()
tax_id: string
@ApiProperty({ enum: TaxSendStatus })
@IsEnum(TaxSendStatus)
status: TaxSendStatus
@ApiProperty({ required: false, nullable: true, type: Object })
@IsOptional()
@IsObject()
response_payload?: unknown
@ApiProperty({ required: false, nullable: true })
@IsOptional()
@IsDateString()
received_at?: string | null
}
export interface ITaxSwitchAdapter {
readonly code: string
send(payload: TaxSwitchSendPayloadDto): Promise<TaxSwitchSendItemResultDto[]>
sendBulk(payloads: TaxSwitchSendPayloadDto[]): Promise<TaxSwitchBulkSendResultDto[]>
get(taxId: string): Promise<TaxSwitchGetResultDto>
}