feat: refactor sales invoice services and introduce pagination and filtering

- Added SharedSaleInvoicePaginationService for handling pagination logic.
- Introduced SharedSaleInvoiceFilterService to centralize filtering logic for sales invoices.
- Updated SalesInvoicesService to utilize the new pagination and filtering services.
- Refactored findAll methods in SalesInvoicesService, CustomerSaleInvoicesService, and other related services to support pagination and filtering.
- Enhanced DTOs for sales invoice filtering to extend shared filter properties.
- Updated module imports to include new services.
- Cleaned up redundant code related to filtering and pagination across various services.
This commit is contained in:
2026-06-14 16:34:00 +03:30
parent d2bd576277
commit 5f70b95589
20 changed files with 427 additions and 680 deletions
@@ -1,57 +1,28 @@
import { QUERY_CONSTANTS } from '@/common/queryConstants'
import consumer_mappersUtil from '@/common/utils/mappers/consumer_mappers.util'
import { SalesInvoiceSelect, SalesInvoiceWhereInput } from '@/generated/prisma/models'
import { SharedSaleInvoicePaginationService } from '@/common/services/saleInvoices/sale-invoice-pagination.service'
import { translateEnumValue } from '@/common/utils'
import { TspProviderResponseStatus } from '@/generated/prisma/enums'
import { SalesInvoiceWhereInput } from '@/generated/prisma/models'
import { PrismaService } from '@/prisma/prisma.service'
import { Injectable } from '@nestjs/common'
import { Injectable, NotFoundException } from '@nestjs/common'
import { ResponseMapper } from 'common/response/response-mapper'
@Injectable()
export class CustomerSaleInvoicesService {
constructor(private readonly prisma: PrismaService) {}
constructor(
private readonly prisma: PrismaService,
private readonly sharedSaleInvoicePaginationService: SharedSaleInvoicePaginationService,
) {}
private readonly defaultSelect: SalesInvoiceSelect = {
id: true,
code: true,
invoice_date: true,
notes: true,
total_amount: true,
pos: {
select: {
id: true,
name: true,
complex: {
select: {
id: true,
name: true,
business_activity: {
select: {
id: true,
name: true,
},
},
},
},
},
},
consumer_account: {
select: {
role: true,
consumer: {
select: {
...QUERY_CONSTANTS.CONSUMER.infoSelect,
},
},
account: {
select: {
username: true,
},
},
},
},
created_at: true,
}
async findAll(
consumer_id: string,
customer_id: string,
requestedPage = 1,
requestedPerPage = 10,
) {
const { page, perPage, skip, take } =
this.sharedSaleInvoicePaginationService.normalize(requestedPage, requestedPerPage)
async findAll(consumer_id: string, customer_id: string, page = 1, perPage = 10) {
const salesWhere: SalesInvoiceWhereInput = {
customer_id,
pos: {
@@ -67,15 +38,30 @@ export class CustomerSaleInvoicesService {
await tx.salesInvoice.findMany({
where: salesWhere,
select: {
...this.defaultSelect,
...QUERY_CONSTANTS.SALE_INVOICE.summarySelect,
pos: {
select: {
name: true,
complex: {
select: {
name: true,
business_activity: {
select: {
name: true,
},
},
},
},
},
},
_count: {
select: {
items: true,
},
},
},
skip: (page - 1) * perPage,
take: 10,
skip,
take,
}),
await tx.salesInvoice.count({
where: salesWhere,
@@ -83,16 +69,11 @@ export class CustomerSaleInvoicesService {
])
const mappedAccounts = saleInvoices.map(saleInvoice => {
const { _count, consumer_account, ...rest } = saleInvoice
const { consumer, ...restConsumerAccount } = consumer_account as any
const mappedConsumer = consumer_mappersUtil(consumer)
const { _count, consumer_account, last_tsp_status, ...rest } = saleInvoice
return {
...rest,
items_count: _count.items,
consumer_account: {
...restConsumerAccount,
consumer: mappedConsumer,
},
status: translateEnumValue('TspProviderResponseStatus', last_tsp_status),
}
})
@@ -104,7 +85,7 @@ export class CustomerSaleInvoicesService {
}
async findOne(consumer_id: string, customer_id: string, id: string) {
const saleInvoice = await this.prisma.salesInvoice.findUniqueOrThrow({
const invoice = await this.prisma.salesInvoice.findUnique({
where: {
id,
customer_id,
@@ -117,59 +98,26 @@ export class CustomerSaleInvoicesService {
},
},
select: {
...this.defaultSelect,
items: {
select: {
id: true,
notes: true,
unit_price: true,
quantity: true,
discount_amount: true,
tax_amount: true,
total_amount: true,
payload: true,
good: {
select: {
id: true,
name: true,
pricing_model: true,
measure_unit: {
select: {
id: true,
name: true,
},
},
category: {
select: {
id: true,
name: true,
image_url: true,
},
},
},
},
},
},
payments: {
select: {
amount: true,
paid_at: true,
payment_method: true,
},
},
...QUERY_CONSTANTS.SALE_INVOICE.select,
},
})
const { _count, consumer_account, ...rest } = saleInvoice
const { consumer, ...restConsumerAccount } = consumer_account as any
const mappedConsumer = consumer_mappersUtil(consumer)
return ResponseMapper.single({
...rest,
items_count: _count.items,
consumer_account: {
...restConsumerAccount,
consumer: mappedConsumer,
},
})
if (invoice) {
const { type, ...rest } = invoice
const mappedInvoice = {
...rest,
type: translateEnumValue('TspProviderRequestType', type),
status: translateEnumValue(
'TspProviderResponseStatus',
invoice.last_tsp_status || TspProviderResponseStatus.NOT_SEND,
),
settlement_type: translateEnumValue(
'InvoiceSettlementType',
invoice.settlement_type,
),
}
return ResponseMapper.single(mappedInvoice)
}
throw new NotFoundException('صورت‌حساب مورد نظر شما یافت نشد.')
}
}