Refactor: Remove stored procedures and replace with direct database operations

feat: Add economic code and guild information to sales invoice selection

fix: Update error messages for invoice access and creation to use "صورت‌حساب"

fix: Change error messages in SaleInvoicesService to use "صورت‌حساب" instead of "فاکتور"

fix: Update error messages in SalesInvoicesService for not found cases to use "صورت‌حساب"

fix: Modify TSP service to handle invoice updates and error messages consistently with "صورت‌حساب"

fix: Update common DTO descriptions to refer to "صورت‌حساب" instead of "فاکتور"

fix: Adjust utility functions to handle invoice references and error messages with "صورت‌حساب"
This commit is contained in:
2026-06-11 16:13:17 +03:30
parent 47a27fb54f
commit 23bfe1ecbe
12 changed files with 114 additions and 2105 deletions
@@ -23,44 +23,46 @@ export async function getOriginalResendAttemptNumber(
): Promise<number> {
let attemptNumber = 1
const existingAttempt = await prisma.saleInvoiceTspAttempts.findFirst({
const invoice = await prisma.salesInvoice.findFirst({
where: {
invoice_id,
id: invoice_id,
},
include: {
invoice: {
select: {
type: true,
},
},
select: {
type: true,
last_attempt_no: true,
last_tsp_status: true,
},
orderBy: {
created_at: 'desc',
},
})
if (existingAttempt) {
attemptNumber = existingAttempt.attempt_no + 1
if (existingAttempt.invoice.type !== TspProviderRequestType.ORIGINAL) {
if (invoice) {
const { last_attempt_no, type, last_tsp_status } = invoice
attemptNumber = (last_attempt_no ?? 0) + 1
if (type !== TspProviderRequestType.ORIGINAL) {
throw new BadRequestException(
'فقط فاکتورهای اصلی قابل ارسال مجدد به سامانه مالیاتی هستند.',
'فقط ‌صورت‌حساب‌های اصلی قابل ارسال مجدد به سامانه مالیاتی هستند.',
)
}
if (existingAttempt.status === TspProviderResponseStatus.SUCCESS) {
if (last_tsp_status === TspProviderResponseStatus.SUCCESS) {
throw new BadRequestException(
'فاکتور تایید شده از طرف سازمان مالیاتی قابل ارسال مجدد نیست.',
'صورت‌حساب تایید شده از طرف سازمان مالیاتی قابل ارسال مجدد نیست.',
)
}
if (
existingAttempt.status === TspProviderResponseStatus.QUEUED ||
existingAttempt.status === TspProviderResponseStatus.FISCAL_QUEUED
) {
if (last_tsp_status === TspProviderResponseStatus.QUEUED) {
throw new BadRequestException(
'در حال حاضر فاکتور شما در حال بررسی توسط سازمان مالیاتی است.',
'در حال حاضر صورت‌حساب شما در صف ارسال به سازمان مالیاتی است.',
)
}
}
if (last_tsp_status === TspProviderResponseStatus.FISCAL_QUEUED) {
throw new BadRequestException(
'در حال حاضر صورت‌حساب شما در حال بررسی توسط سازمان مالیاتی است.',
)
}
} else throw new NotFoundException('صورت‌حساب مورد نظر یافت نشد.')
return attemptNumber
}
@@ -138,7 +140,7 @@ export async function buildRevokePayload(
})
if (!invoice) {
throw new NotFoundException('فاکتور مورد نظر یافت نشد.')
throw new NotFoundException('صورت‌حساب مورد نظر یافت نشد.')
}
const { partner } = (invoice.pos.complex.business_activity.consumer.legal ||
@@ -425,7 +427,7 @@ export async function buildOriginalPayload(
})
if (!invoice) {
throw new NotFoundException('فاکتور مورد نظر یافت نشد.')
throw new NotFoundException('صورت‌حساب مورد نظر یافت نشد.')
}
const {
@@ -552,12 +554,12 @@ export async function getRelatedInvoiceForModification(
})
if (!relatedInvoice) {
throw new NotFoundException('فاکتور مورد نظر یافت نشد.')
throw new NotFoundException('صورت‌حساب مورد نظر یافت نشد.')
}
if (relatedInvoice.type === TspProviderRequestType.REVOKE) {
throw new BadRequestException(
'فاکتور ارسالی قبلا ابطال شده است و امکان ویرایش آن وجود ندارد.',
'صورت‌حساب ارسالی قبلا ابطال شده است و امکان ویرایش آن وجود ندارد.',
)
}
@@ -566,7 +568,7 @@ export async function getRelatedInvoiceForModification(
relatedInvoice.tsp_attempts?.[0].status !== TspProviderResponseStatus.SUCCESS
) {
throw new BadRequestException(
'فاکتور قبلی همچنان در حال بررسی است و امکان اصلاح آن وجود ندارد.',
'صورت‌حساب قبلی همچنان در حال بررسی است و امکان اصلاح آن وجود ندارد.',
)
}
@@ -587,11 +589,11 @@ export async function trySend(
export async function onResult(
prisma: PrismaService,
result: TspProviderOriginalResponseDto | TspProviderGetResponseDto,
attempt_id: string,
invoice_id: string,
): Promise<TspProviderActionResponseDto> {
let attemptUpdatedData: SaleInvoiceTspAttemptsUpdateInput = {}
console.log('attempt', result, attempt_id)
console.log('attempt', result)
const resultMessage = result.message
@@ -606,7 +608,7 @@ export async function onResult(
? resultMessage
: result.hasError
? 'وجود مشکل در ارسال به سامانه مالیاتی'
: 'فاکتور با موفقیت به سامانه مالیاتی ارسال شد.',
: 'صورت‌حساب با موفقیت به سامانه مالیاتی ارسال شد.',
invoice: {
update: {
tax_id: result['tax_id'] ? result['tax_id'] : undefined,
@@ -633,26 +635,37 @@ export async function onResult(
attemptUpdatedData = {
status: TspProviderResponseStatus.SEND_FAILURE,
message:
'متاسفانه امکان ارسال فاکتور به سیستم مالیاتی در حال حاضر وجود ندارد. لطفا بعدا تلاش کنید.',
'متاسفانه امکان ارسال صورت‌حساب به سیستم مالیاتی در حال حاضر وجود ندارد. لطفا بعدا تلاش کنید.',
received_at: new Date().toISOString(),
}
}
const updatedAttempt = await prisma.saleInvoiceTspAttempts.update({
where: {
id: attempt_id,
},
data: attemptUpdatedData,
select: {
status: true,
invoice: true,
message: true,
},
const invoice = await prisma.$transaction(async tx => {
const lastAttempt = await tx.saleInvoiceTspAttempts.findFirst({
where: { invoice_id },
orderBy: { attempt_no: 'desc' },
select: { id: true },
})
if (!lastAttempt) throw new NotFoundException('صورت‌حساب مورد نظر یافت نشد.')
await tx.saleInvoiceTspAttempts.update({
where: { id: lastAttempt.id },
data: attemptUpdatedData,
})
const updatedInvoice = await tx.salesInvoice.update({
where: { id: invoice_id },
data: {
last_tsp_status: attemptUpdatedData.status,
},
})
return updatedInvoice
})
return {
invoice: updatedAttempt.invoice,
status: updatedAttempt.status,
message: updatedAttempt.message,
invoice,
status: attemptUpdatedData.status as TspProviderResponseStatus,
message: attemptUpdatedData.message as string,
}
}