import { IPosPayload } from '@/common/models/posPayload.model' import { QUERY_CONSTANTS } from '@/common/queryConstants' import { SharedSaleInvoiceActionsService } from '@/common/services/saleInvoices/sale-invoice-actions.service' import { SharedSaleInvoiceCreateService } from '@/common/services/saleInvoices/sale-invoice-create.service' import { translateEnumValue } from '@/common/utils' import { PrismaService } from '@/prisma/prisma.service' import { Injectable, NotFoundException } from '@nestjs/common' import { ResponseMapper } from 'common/response/response-mapper' import { Prisma } from 'generated/prisma/client' import { TspProviderRequestType, TspProviderResponseStatus } from 'generated/prisma/enums' import { SalesInvoiceTspService } from '../../tspProviders/sales-invoice-tsp.service' import { CreateSalesInvoiceDto } from './dto/create-sales-invoice.dto' import { SalesInvoicesFilterDto } from './dto/sales-invoices-filter.dto' @Injectable() export class SalesInvoicesService { constructor( private prisma: PrismaService, private salesInvoiceTaxService: SalesInvoiceTspService, private sharedSaleInvoiceCreateService: SharedSaleInvoiceCreateService, private sharedSaleInvoiceActionsService: SharedSaleInvoiceActionsService, ) {} async findAll(posInfo: IPosPayload, query: SalesInvoicesFilterDto = {}) { const page = query.page || 1 const perPage = Math.min(query.perPage || 10, 100) const where = this.buildFindAllWhere(posInfo, query) const [items, total] = await this.prisma.$transaction(async tx => [ await tx.salesInvoice.findMany({ where, orderBy: { created_at: 'desc', }, skip: (page - 1) * perPage, take: perPage, select: { ...QUERY_CONSTANTS.SALE_INVOICE.summarySelect, }, }), await tx.salesInvoice.count({ where }), ]) const summaryItems = items.map(invoice => { const { tsp_attempts, type, ...rest } = invoice return { ...rest, type: translateEnumValue('TspProviderRequestType', type), status: translateEnumValue( 'TspProviderResponseStatus', invoice.tsp_attempts?.[0]?.status || TspProviderResponseStatus.NOT_SEND, ), } }) return ResponseMapper.paginate(summaryItems, { total, page, perPage }) } async findOne(posInfo: IPosPayload, id: string) { const invoice = await this.prisma.salesInvoice.findUnique({ where: { id, pos: { id: posInfo.pos_id, complex: { business_activity_id: posInfo.business_id, }, }, }, select: { ...QUERY_CONSTANTS.SALE_INVOICE.select, }, }) if (invoice) { const { tsp_attempts, type, ...rest } = invoice const mappedInvoice = { ...rest, type: translateEnumValue('TspProviderRequestType', type), status: translateEnumValue( 'TspProviderResponseStatus', invoice.tsp_attempts?.[0]?.status || TspProviderResponseStatus.NOT_SEND, ), settlement_type: translateEnumValue( 'InvoiceSettlementType', invoice.settlement_type, ), } return ResponseMapper.single(mappedInvoice) } else throw new NotFoundException('فاکتور مورد نظر شما یافت نشد.') } async create(data: CreateSalesInvoiceDto, posInfo: IPosPayload) { let salesInvoice = await this.sharedSaleInvoiceCreateService.create({ data, businessId: posInfo.business_id, complexId: posInfo.complex_id, posId: posInfo.pos_id, consumerAccountId: posInfo.consumer_account_id, type: TspProviderRequestType.ORIGINAL, }) if (data.send_to_tsp) { const providerResponse = await this.salesInvoiceTaxService.originalSend( salesInvoice.id, posInfo.pos_id, ) if (providerResponse?.invoice) { salesInvoice = providerResponse?.invoice as any } } return ResponseMapper.create(salesInvoice) } async send(invoiceId: string, posInfo: IPosPayload) { const invoice = await this.sharedSaleInvoiceActionsService.send( posInfo.consumer_account_id, posInfo.pos_id, invoiceId, ) return ResponseMapper.single(invoice) } async retry(invoiceId: string, posInfo: IPosPayload) { const invoice = await this.sharedSaleInvoiceActionsService.retry( posInfo.consumer_account_id, posInfo.pos_id, invoiceId, ) return ResponseMapper.single(invoice) } async revoke(invoiceId: string, posInfo: IPosPayload) { const { consumer_account_id, pos_id, business_id, complex_id } = posInfo const invoice = await this.sharedSaleInvoiceActionsService.revoke( consumer_account_id, pos_id, complex_id, business_id, invoiceId, ) return ResponseMapper.single(invoice) } async inquiry(consumer_account_id: string, pos_id: string, invoiceId: string) { const invoice = await this.sharedSaleInvoiceActionsService.inquiry( consumer_account_id, pos_id, invoiceId, ) return ResponseMapper.single(invoice) } private buildFindAllWhere(posInfo: IPosPayload, query: SalesInvoicesFilterDto) { const where: Prisma.SalesInvoiceWhereInput = { pos: { id: posInfo.pos_id, complex: { business_activity_id: posInfo.business_id, }, }, } if (query.invoice_number) { where.invoice_number = parseInt(query.invoice_number + '') } if (query.invoice_date_from || query.invoice_date_to) { where.invoice_date = { ...(query.invoice_date_from ? { gte: new Date(query.invoice_date_from) } : {}), ...(query.invoice_date_to ? { lte: new Date(query.invoice_date_to) } : {}), } } if (query.created_at_from || query.created_at_to) { where.created_at = { ...(query.created_at_from ? { gte: new Date(query.created_at_from) } : {}), ...(query.created_at_to ? { lte: new Date(query.created_at_to) } : {}), } } if ( query.total_amount !== undefined || query.total_amount_from !== undefined || query.total_amount_to !== undefined ) { where.total_amount = { ...(query.total_amount !== undefined ? { equals: query.total_amount } : {}), ...(query.total_amount_from !== undefined ? { gte: query.total_amount_from } : {}), ...(query.total_amount_to !== undefined ? { lte: query.total_amount_to } : {}), } } if ( query.customer_name?.trim() || query.customer_mobile?.trim() || query.customer_national_id?.trim() || query.customer_economic_code?.trim() ) { where.customer = { is: { OR: [ ...(query.customer_name?.trim() ? [ { individual: { is: { OR: [ { first_name: { contains: query.customer_name.trim(), }, }, { last_name: { contains: query.customer_name.trim(), }, }, ], }, }, }, { legal: { is: { name: { contains: query.customer_name.trim(), }, }, }, }, ] : []), ...(query.customer_mobile?.trim() ? [ { individual: { is: { mobile_number: { contains: query.customer_mobile.trim(), }, }, }, }, ] : []), ...(query.customer_national_id?.trim() ? [ { individual: { is: { national_id: { contains: query.customer_national_id.trim(), }, }, }, }, ] : []), ...(query.customer_economic_code?.trim() ? [ { legal: { is: { OR: [ { economic_code: { contains: query.customer_economic_code.trim(), }, }, { registration_number: { contains: query.customer_economic_code.trim(), }, }, ], }, }, }, ] : []), ], }, } } if (query.status) { if (query.status === TspProviderResponseStatus.NOT_SEND) { where.tsp_attempts = { none: {}, } } else { where.tsp_attempts = { some: { status: query.status, }, } } } return where } }