Files
psp_api/src/modules/pos/sales-invoices/sales-invoices.service.ts
T

267 lines
7.8 KiB
TypeScript
Raw Normal View History

2026-03-29 18:06:41 +03:30
import { IPosPayload } from '@/common/models/posPayload.model'
import { PrismaService } from '@/prisma/prisma.service'
import { BadRequestException, Injectable } from '@nestjs/common'
import { ResponseMapper } from 'common/response/response-mapper'
import type { CustomerIndividual, CustomerLegal } from 'generated/prisma/client'
import { CustomerType, PaymentMethodType } from 'generated/prisma/enums'
import { SalesInvoiceTaxService } from '../../consumer/saleInvoices/tax/sales-invoice-tax.service'
import { CreateSalesInvoiceDto } from './dto/create-sales-invoice.dto'
// Define type guard for CustomerIndividual
function isCustomerIndividual(customer: any): customer is CustomerIndividual {
return (
customer &&
typeof customer.first_name === 'string' &&
typeof customer.last_name === 'string'
)
}
// Define type guard for CustomerLegal
function isCustomerLegal(customer: any): customer is CustomerLegal {
return (
customer &&
typeof customer.company_name === 'string' &&
typeof customer.registration_number === 'string'
)
}
2026-01-07 15:25:59 +03:30
@Injectable()
export class SalesInvoicesService {
constructor(
private prisma: PrismaService,
private salesInvoiceTaxService: SalesInvoiceTaxService,
) {}
findAll() {
// TODO: Implement fetching all sales invoices
return []
2026-01-07 15:25:59 +03:30
}
findOne(id: number) {
// TODO: Implement fetching a single sales invoice
return {}
2026-01-07 15:25:59 +03:30
}
// async send(invoiceId: string, posInfo: IPosPayload) {
// await this.salesInvoiceTaxService.send(invoiceId, posInfo.pos_id)
// return ResponseMapper.single({
// invoice_id: invoiceId,
// sent_to_tax: true,
// })
// }
// async sendBulk(invoiceIds: string[], posInfo: IPosPayload) {
// if (!invoiceIds.length) {
// throw new BadRequestException('invoice_ids is required and cannot be empty.')
// }
// await this.salesInvoiceTaxService.sendBulk(invoiceIds, posInfo.pos_id)
// return ResponseMapper.single({
// invoice_ids: invoiceIds,
// sent_to_tax: true,
// })
// }
2026-03-29 18:06:41 +03:30
async create(data: CreateSalesInvoiceDto, posInfo: IPosPayload) {
data.invoice_date = new Date(data.invoice_date).toISOString() as any
const { business_id, pos_id, consumer_account_id } = posInfo
2026-03-29 18:06:41 +03:30
const salesInvoice = await this.prisma.$transaction(async $tx => {
const payments = Object.entries(data.payments)
.filter(([_, value]) => value > 0 && PaymentMethodType[_.toUpperCase()])
.map(([key, value]) => {
return {
amount: value,
payment_method: key.toLocaleUpperCase() as PaymentMethodType,
paid_at: data.invoice_date,
}
})
const totalPayments = payments.reduce((sum, payment) => sum + payment.amount, 0)
2026-03-29 18:06:41 +03:30
if (totalPayments !== data.total_amount) {
throw new Error('مبلغ پرداختی باید برابر با مبلغ کل فاکتور باشد.')
}
const { customer_id, customer_type, customer, ...invoiceData } = data
let newCustomerId: string | null = customer_id || null
if (customer_id) {
} else if (
customer_type === CustomerType.INDIVIDUAL &&
customer?.customer_individual
) {
const customer_individual = customer.customer_individual
const customerIndividual = await $tx.customerIndividual.upsert({
where: {
business_activity_id_national_id: {
business_activity_id: business_id,
national_id: customer_individual.national_id,
},
},
create: {
...customer_individual,
customer: {
create: {
type: CustomerType.INDIVIDUAL,
},
},
business_activity: {
connect: {
id: business_id,
},
},
},
update: {},
select: {
customer_id: true,
},
})
if (!customerIndividual) {
throw new BadRequestException('متاسفانه مشکلی در اطلاعات مشتری وجود دارد.')
}
newCustomerId = customerIndividual.customer_id
} else if (data.customer_type === CustomerType.LEGAL && customer?.customer_legal) {
const customer_legal = customer.customer_legal
const customerLegal = await $tx.customerLegal.upsert({
where: {
business_activity_id_economic_code: {
business_activity_id: business_id,
economic_code: customer_legal.economic_code,
},
},
create: {
...customer_legal,
customer: {
create: {
type: CustomerType.LEGAL,
},
},
business_activity: {
connect: {
id: business_id,
},
},
},
update: {},
select: {
customer_id: true,
},
})
if (!customerLegal) {
throw new BadRequestException('متاسفانه مشکلی در اطلاعات مشتری وجود دارد.')
}
newCustomerId = customerLegal.customer_id
2026-03-29 18:06:41 +03:30
} else if (data.customer_type === CustomerType.UNKNOWN) {
}
const itemGoodIds = data.items
.map(item => item.good_id)
.filter((goodId): goodId is string => Boolean(goodId))
const goods = itemGoodIds.length
? await $tx.good.findMany({
where: {
id: {
in: itemGoodIds,
},
},
select: {
id: true,
name: true,
sku: true,
local_sku: true,
barcode: true,
pricing_model: true,
unit_type: true,
base_sale_price: true,
image_url: true,
category: {
select: {
id: true,
name: true,
},
},
},
})
: []
const goodsById = new Map(goods.map(good => [good.id, good]))
const salesInvoiceData: any = {
...invoiceData,
total_amount: data.total_amount,
code: 'INV-' + Date.now(),
items: {
createMany: {
data: data.items.map(item => ({
good_id: item.good_id,
quantity: item.quantity,
unit_price: item.unit_price,
total_amount: item.total_amount,
payload: item.payload
? JSON.parse(JSON.stringify(item.payload))
: undefined,
good_snapshot: item.good_id
? JSON.parse(
JSON.stringify({
good: goodsById.get(item.good_id) || null,
}),
)
: undefined,
unit_type: item.unit_type,
// pricing_model: item.pricingModel,
})),
},
},
unknown_customer: {},
payments: {
createMany: {
data: payments,
},
},
// customer: {
// connect: {
// id: newCustomerId || undefined,
// },
// },
consumer_account: {
connect: {
id: consumer_account_id,
2026-03-29 18:06:41 +03:30
},
},
pos: {
connect: {
id: pos_id,
2026-03-29 18:06:41 +03:30
},
},
}
if (newCustomerId) {
salesInvoiceData.customer = {
connect: {
id: newCustomerId || undefined,
},
}
}
const salesInvoice = await $tx.salesInvoice.create({
data: salesInvoiceData,
})
return salesInvoice
})
if (data.send_to_tax) {
await this.salesInvoiceTaxService.send(salesInvoice.id, pos_id)
}
return ResponseMapper.create(salesInvoice)
2026-01-07 15:25:59 +03:30
}
}