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:
@@ -73,6 +73,12 @@ export const select: SalesInvoiceSelect = {
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
economic_code: true,
|
||||
guild: {
|
||||
select: {
|
||||
name: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -21,7 +21,7 @@ export class SharedSaleInvoiceAccessService {
|
||||
})
|
||||
|
||||
if (!consumer) {
|
||||
throw new BadRequestException('شما دسترسی لازم برای ارسال فاکتور را ندارید.')
|
||||
throw new BadRequestException('شما دسترسی لازم برای ارسال صورتحساب را ندارید.')
|
||||
}
|
||||
|
||||
return consumer.consumer_id
|
||||
|
||||
@@ -109,7 +109,7 @@ export class SharedSaleInvoiceCreateService {
|
||||
}
|
||||
}
|
||||
|
||||
throw new BadRequestException('ایجاد فاکتور با خطا مواجه شد.')
|
||||
throw new BadRequestException('ایجاد صورتحساب با خطا مواجه شد.')
|
||||
}
|
||||
|
||||
private isRetryableInvoiceConflict(error: unknown) {
|
||||
@@ -197,7 +197,7 @@ export class SharedSaleInvoiceCreateService {
|
||||
const roundedTotalAmount = Number(Number(totalAmount).toFixed(2))
|
||||
|
||||
if (roundedTotalPayments !== roundedTotalAmount) {
|
||||
throw new BadRequestException('مبلغ پرداختی باید برابر با مبلغ کل فاکتور باشد.')
|
||||
throw new BadRequestException('مبلغ پرداختی باید برابر با مبلغ کل صورتحساب باشد.')
|
||||
}
|
||||
|
||||
const terminalPayments = payments.filter(
|
||||
@@ -431,7 +431,7 @@ export class SharedSaleInvoiceCreateService {
|
||||
type !== TspProviderRequestType.ORIGINAL &&
|
||||
!(main_invoice_id || ref_invoice_id)
|
||||
) {
|
||||
throw new BadRequestException('متاسفانه مشکلی در اطلاعات فاکتور وجود دارد.')
|
||||
throw new BadRequestException('متاسفانه مشکلی در اطلاعات صورتحساب وجود دارد.')
|
||||
}
|
||||
|
||||
const salesInvoiceData: SalesInvoiceCreateInput = {
|
||||
|
||||
@@ -253,7 +253,7 @@ export class SaleInvoicesService {
|
||||
if (invoice) {
|
||||
return ResponseMapper.single(this.invoiceMapper(invoice))
|
||||
}
|
||||
throw new NotFoundException('فاکتور مورد نظر شما یافت نشد.')
|
||||
throw new NotFoundException('صورتحساب مورد نظر شما یافت نشد.')
|
||||
}
|
||||
|
||||
async send(invoiceId: string, posInfo: IPosPayload) {
|
||||
@@ -301,7 +301,7 @@ export class SaleInvoicesService {
|
||||
|
||||
async sendBulk(consumer_id: string, invoiceIds: string[]) {
|
||||
if (!invoiceIds.length) {
|
||||
throw new BadRequestException('لیست شناسه فاکتورها نمیتواند خالی باشد.')
|
||||
throw new BadRequestException('لیست شناسه صورتحسابها نمیتواند خالی باشد.')
|
||||
}
|
||||
|
||||
await this.salesInvoiceTaxService.sendBulk(consumer_id, invoiceIds)
|
||||
|
||||
@@ -91,7 +91,7 @@ export class SalesInvoicesService {
|
||||
}
|
||||
|
||||
return ResponseMapper.single(mappedInvoice)
|
||||
} else throw new NotFoundException('فاکتور مورد نظر شما یافت نشد.')
|
||||
} else throw new NotFoundException('صورتحساب مورد نظر شما یافت نشد.')
|
||||
}
|
||||
|
||||
async create(data: PosCreateSalesInvoiceDto, posInfo: IPosPayload) {
|
||||
|
||||
@@ -42,20 +42,28 @@ export class SalesInvoiceTspService {
|
||||
|
||||
const attemptNumber = await getOriginalResendAttemptNumber(this.prisma, invoice_id)
|
||||
|
||||
const attempt = await this.prisma.saleInvoiceTspAttempts.create({
|
||||
const invoice = await this.prisma.salesInvoice.update({
|
||||
where: {
|
||||
id: invoice_id,
|
||||
},
|
||||
data: {
|
||||
attempt_no: attemptNumber,
|
||||
invoice_id,
|
||||
provider_request_payload: {},
|
||||
status: TspProviderResponseStatus.QUEUED,
|
||||
raw_request_payload: JSON.parse(JSON.stringify(payload)),
|
||||
sent_at: new Date().toISOString(),
|
||||
message: 'در حال ارسال به سامانه مالیاتی...',
|
||||
last_tsp_status: TspProviderResponseStatus.QUEUED,
|
||||
last_attempt_no: attemptNumber,
|
||||
tsp_attempts: {
|
||||
create: {
|
||||
attempt_no: attemptNumber,
|
||||
provider_request_payload: {},
|
||||
status: TspProviderResponseStatus.QUEUED,
|
||||
raw_request_payload: JSON.parse(JSON.stringify(payload)),
|
||||
sent_at: new Date().toISOString(),
|
||||
message: 'در حال ارسال به سامانه مالیاتی...',
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
const result = await this.tspSwitchService.send(payload)
|
||||
return await onResult(this.prisma, result, attempt.id)
|
||||
return await onResult(this.prisma, result, invoice.id)
|
||||
}
|
||||
|
||||
async sendBulk(consumer_id: string, invoice_ids: string[]): Promise<void> {
|
||||
@@ -75,18 +83,17 @@ export class SalesInvoiceTspService {
|
||||
pos_id: string,
|
||||
consumer_id: string,
|
||||
): Promise<TspProviderActionResponseDto> {
|
||||
const [attempt, pos] = await this.prisma.$transaction(async tx => [
|
||||
await tx.saleInvoiceTspAttempts.findFirst({
|
||||
const [invoice, pos] = await this.prisma.$transaction(async tx => [
|
||||
await tx.salesInvoice.findUnique({
|
||||
where: {
|
||||
invoice_id,
|
||||
invoice: {
|
||||
pos: {
|
||||
id: pos_id,
|
||||
},
|
||||
id: invoice_id,
|
||||
pos: {
|
||||
id: pos_id,
|
||||
},
|
||||
},
|
||||
orderBy: {
|
||||
attempt_no: 'desc',
|
||||
select: {
|
||||
last_tsp_status: true,
|
||||
id: true,
|
||||
},
|
||||
}),
|
||||
|
||||
@@ -135,12 +142,25 @@ export class SalesInvoiceTspService {
|
||||
}),
|
||||
])
|
||||
|
||||
if (!attempt) {
|
||||
throw new NotFoundException('صورتحساب ارسالی فاکتور شما به سامانه یافت نشد.')
|
||||
if (!invoice) {
|
||||
throw new NotFoundException('صورتحساب ارسالی صورتحساب شما به سامانه یافت نشد.')
|
||||
}
|
||||
if (!pos) {
|
||||
throw new NotFoundException('مشکلی در ساختار اطلاعات ورودی شما وجود دارد.')
|
||||
}
|
||||
if (
|
||||
!invoice.last_tsp_status ||
|
||||
invoice.last_tsp_status === TspProviderResponseStatus.NOT_SEND
|
||||
) {
|
||||
throw new BadRequestException(
|
||||
'صورتحساب شما هنوز به سامانه مالیاتی ارسال نشده است. لطفا چند لحظه دیگر مجددا تلاش کنید.',
|
||||
)
|
||||
}
|
||||
if (invoice.last_tsp_status === TspProviderResponseStatus.QUEUED) {
|
||||
throw new BadRequestException(
|
||||
'صورتحساب شما در صف ارسال به سامانه مالیاتی قرار دارد. لطفا چند لحظه دیگر مجددا تلاش کنید.',
|
||||
)
|
||||
}
|
||||
|
||||
const { business_activity } = pos.complex
|
||||
|
||||
@@ -153,7 +173,7 @@ export class SalesInvoiceTspService {
|
||||
business_activity.partner_token,
|
||||
)
|
||||
|
||||
return await onResult(this.prisma, result, attempt.id)
|
||||
return await onResult(this.prisma, result, invoice.id)
|
||||
}
|
||||
|
||||
async correctionSend(
|
||||
@@ -282,18 +302,18 @@ export class SalesInvoiceTspService {
|
||||
})
|
||||
|
||||
if (!relatedInvoice) {
|
||||
throw new NotFoundException('فاکتور مورد نظر یافت نشد.')
|
||||
throw new NotFoundException('صورتحساب مورد نظر یافت نشد.')
|
||||
}
|
||||
|
||||
if (relatedInvoice.type === TspProviderRequestType.REVOKE) {
|
||||
throw new BadRequestException(
|
||||
'فاکتور ارسالی قبلا ابطال شده است و امکان ویرایش آن وجود ندارد.',
|
||||
'صورتحساب ارسالی قبلا ابطال شده است و امکان ویرایش آن وجود ندارد.',
|
||||
)
|
||||
}
|
||||
|
||||
if (!relatedInvoice.tax_id) {
|
||||
throw new BadRequestException(
|
||||
'فاکتور قبلی همچنان در حال بررسی است و امکان ویرایش آن وجود ندارد.',
|
||||
'صورتحساب قبلی همچنان در حال بررسی است و امکان ویرایش آن وجود ندارد.',
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -226,7 +226,7 @@ export class NamaProviderValidationErrorDto {
|
||||
}
|
||||
|
||||
export class NamaProviderResponseDto {
|
||||
@ApiProperty({ description: 'شناسه پیگیری فاکتور' })
|
||||
@ApiProperty({ description: 'شناسه پیگیری صورتحساب' })
|
||||
@IsString()
|
||||
uuid: string
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ export class NamaProviderRevokeHeaderDto {
|
||||
|
||||
@ApiProperty({
|
||||
required: true,
|
||||
description: 'آخرین شماره مالیاتی دریافت شده مربوط به فاکتور',
|
||||
description: 'آخرین شماره مالیاتی دریافت شده مربوط به صورتحساب',
|
||||
})
|
||||
@IsString()
|
||||
irtaxid: string
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user