feat: implement correction and original send functionality for Nama provider

- Added new DTOs for correction requests and responses in `nama-provider.dto.ts`.
- Updated `nama-provider.adapter.ts` to include `originalSend` and `correctionSend` methods.
- Enhanced `nama-provider.util.ts` with mapping functions for correction requests.
- Created operational guidelines for agents in `AGENT.md`.
- Updated Prisma migrations to support new invoice types and relationships.
- Introduced new service and DTO for creating sales invoices in `sale-invoice-create.service.ts` and `sale-invoice-create.dto.ts`.
- Added utility for handling Prisma errors in `prisma-error.util.ts`.
This commit is contained in:
2026-05-05 22:42:09 +03:30
parent 4af07fe3e8
commit 658496320b
43 changed files with 2808 additions and 1354 deletions
@@ -15,7 +15,7 @@ export default (consumer: any) => {
status: translateEnumValue('ConsumerStatus', consumer.status),
legal: legal ? { ...legal } : null,
individual: individual
? { ...individual, fullname: `${rest?.first_name} ${rest?.last_name}` }
? { ...individual, fullname: `${individual?.first_name} ${individual?.last_name}` }
: null,
name: legal ? legal.name : `${individual?.first_name} ${individual?.last_name}`,
business_counts,
+54
View File
@@ -0,0 +1,54 @@
import { BadRequestException, ConflictException } from '@nestjs/common'
import { Prisma } from 'generated/prisma/client'
type UniqueMessageMap = Record<string, string>
export class PrismaErrorUtil {
static isKnownError(error: unknown): error is Prisma.PrismaClientKnownRequestError {
return error instanceof Prisma.PrismaClientKnownRequestError
}
static isCode(error: unknown, code: string): boolean {
return this.isKnownError(error) && error.code === code
}
static hasTarget(error: unknown, targetKey: string): boolean {
if (!this.isKnownError(error)) {
return false
}
const target = error.meta?.target as string[] | string | undefined
if (Array.isArray(target)) {
return target.includes(targetKey)
}
if (typeof target === 'string') {
return target.includes(targetKey)
}
return false
}
static throwIfKnown(error: unknown, uniqueMap: UniqueMessageMap = {}) {
if (!(error instanceof Prisma.PrismaClientKnownRequestError)) {
throw error
}
if (error.code === 'P2002') {
const target = (error.meta?.target as string[]) || []
for (const key of Object.keys(uniqueMap)) {
if (target.includes(key)) {
throw new BadRequestException(uniqueMap[key])
}
}
throw new ConflictException('رکورد تکراری است.')
}
if (error.code === 'P2003') {
throw new BadRequestException('ارتباط داده‌ای نامعتبر است.')
}
if (error.code === 'P2025') {
throw new BadRequestException('رکورد مورد نظر یافت نشد.')
}
throw error
}
}
@@ -1,4 +1,5 @@
import { randomBytes } from 'crypto'
import { PrismaErrorUtil } from './prisma-error.util'
export function generateTrackingCode(prefix: string, suffixLength: number) {
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
@@ -13,23 +14,8 @@ export function generateTrackingCode(prefix: string, suffixLength: number) {
}
export function isTrackingCodeUniqueViolation(error: unknown) {
const prismaError = error as {
code?: string
meta?: { target?: string[] | string }
}
if (prismaError?.code !== 'P2002') {
if (!PrismaErrorUtil.isCode(error, 'P2002')) {
return false
}
const target = prismaError.meta?.target
if (Array.isArray(target)) {
return target.includes('tracking_code')
}
if (typeof target === 'string') {
return target.includes('tracking_code')
}
return true
return PrismaErrorUtil.hasTarget(error, 'tracking_code')
}