feat: add settlement_type to SalesInvoice model and related DTOs
- Added settlement_type field to SalesInvoice model with ENUM values (CASH, CREDIT, MIXED). - Updated SalesInvoice aggregate types, input types, and where filters to include settlement_type. - Modified StatisticsService to calculate credit amounts based on settlement_type. - Enhanced TspProviderOriginalSendPayloadDto to include settlement_type. - Updated NamaProvider DTOs and utility functions to handle new settlement_type logic. - Created migration to add settlement_type column to sales_invoices table and backfill existing records.
This commit is contained in:
@@ -23,6 +23,8 @@ export class StatisticsService {
|
||||
pending_count: number | null
|
||||
not_sended_amount_sum: number | null
|
||||
not_sended_count: number | null
|
||||
credit_amount_sum: number | null
|
||||
credit_count: number | null
|
||||
}>
|
||||
>`
|
||||
SELECT
|
||||
@@ -35,19 +37,21 @@ export class StatisticsService {
|
||||
SUM(CASE WHEN la.status = ${TspProviderResponseStatus.QUEUED} THEN si.total_amount ELSE 0 END) AS pending_amount_sum,
|
||||
SUM(CASE WHEN la.status = ${TspProviderResponseStatus.QUEUED} THEN 1 ELSE 0 END) AS pending_count,
|
||||
SUM(CASE WHEN la.status IS NULL THEN si.total_amount ELSE 0 END) AS not_sended_amount_sum,
|
||||
SUM(CASE WHEN la.status IS NULL THEN 1 ELSE 0 END) AS not_sended_count
|
||||
SUM(CASE WHEN la.status IS NULL THEN 1 ELSE 0 END) AS not_sended_count,
|
||||
SUM(CASE WHEN si.settlement_type = 'CREDIT' THEN si.total_amount ELSE 0 END) AS credit_amount_sum,
|
||||
SUM(CASE WHEN si.settlement_type = 'CREDIT' THEN 1 ELSE 0 END) AS credit_count
|
||||
FROM sales_invoices si
|
||||
INNER JOIN poses p ON p.id = si.pos_id
|
||||
LEFT JOIN (
|
||||
SELECT a1.invoice_id, a1.status
|
||||
FROM sale_invoice_tsp_attempts a1
|
||||
SELECT att.invoice_id, att.status
|
||||
FROM sale_invoice_tsp_attempts att
|
||||
INNER JOIN (
|
||||
SELECT invoice_id, MAX(attempt_no) AS max_attempt_no
|
||||
FROM sale_invoice_tsp_attempts
|
||||
GROUP BY invoice_id
|
||||
) latest
|
||||
ON latest.invoice_id = a1.invoice_id
|
||||
AND latest.max_attempt_no = a1.attempt_no
|
||||
ON latest.invoice_id = att.invoice_id
|
||||
AND latest.max_attempt_no = att.attempt_no
|
||||
) la ON la.invoice_id = si.id
|
||||
WHERE si.invoice_date >= ${seasonDate.start}
|
||||
AND si.invoice_date <= ${seasonDate.end}
|
||||
@@ -55,6 +59,11 @@ export class StatisticsService {
|
||||
AND p.complex_id IN (
|
||||
SELECT c.id FROM complexes c WHERE c.business_activity_id = ${businessId}
|
||||
)
|
||||
AND NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM sales_invoices child
|
||||
WHERE child.ref_id = si.id
|
||||
)
|
||||
`
|
||||
|
||||
return ResponseMapper.single({
|
||||
@@ -83,6 +92,11 @@ export class StatisticsService {
|
||||
total_tax: Number(0),
|
||||
count: Number(item?.not_sended_count || 0),
|
||||
},
|
||||
credit: {
|
||||
total_amount: Number(item?.credit_amount_sum || 0),
|
||||
total_tax: Number(0),
|
||||
count: Number(item?.credit_count || 0),
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
} from '@/common/services/saleInvoices/sale-invoice-create.dto'
|
||||
import {
|
||||
CustomerType,
|
||||
InvoiceSettlementType,
|
||||
InvoiceTemplateType,
|
||||
PaymentMethodType,
|
||||
TspProviderRequestType,
|
||||
@@ -208,6 +209,10 @@ export class TspProviderOriginalSendPayloadDto {
|
||||
@ApiProperty({ required: true })
|
||||
@IsString()
|
||||
tsp_token: string
|
||||
|
||||
@ApiProperty({ required: true, enum: InvoiceSettlementType })
|
||||
@IsEnum(InvoiceSettlementType)
|
||||
settlement_type: InvoiceSettlementType
|
||||
}
|
||||
|
||||
export class TspProviderSendItemResultDto {
|
||||
|
||||
@@ -288,6 +288,7 @@ export class SalesInvoiceTspService {
|
||||
items: dataToUpdate.items,
|
||||
total_amount: dataToUpdate.total_amount,
|
||||
customer_id: relatedInvoice.customer_id || undefined,
|
||||
settlement_type: relatedInvoice.settlement_type,
|
||||
},
|
||||
businessId,
|
||||
complexId,
|
||||
@@ -320,8 +321,7 @@ export class SalesInvoiceTspService {
|
||||
)
|
||||
if (result?.hasError) {
|
||||
result.provider_request_payload =
|
||||
result.provider_request_payload ||
|
||||
JSON.parse(JSON.stringify(correctionPayload))
|
||||
result.provider_request_payload || JSON.parse(JSON.stringify(correctionPayload))
|
||||
result.sent_at = result.sent_at || new Date().toISOString()
|
||||
result.received_at = result.received_at || new Date().toISOString()
|
||||
}
|
||||
@@ -472,6 +472,7 @@ export class SalesInvoiceTspService {
|
||||
customer_type: relatedInvoice.customer?.type || CustomerType.UNKNOWN,
|
||||
invoice_date: new Date(),
|
||||
payments,
|
||||
settlement_type: relatedInvoice.settlement_type,
|
||||
items: relatedInvoice.items.map(item => ({
|
||||
unit_price: Number(item.unit_price),
|
||||
quantity: Number(item.quantity),
|
||||
|
||||
@@ -168,9 +168,17 @@ export class NamaProviderHeaderDto {
|
||||
@IsString()
|
||||
bid: string
|
||||
|
||||
@ApiProperty({ required: true, description: 'روش تسویه' })
|
||||
@ApiProperty({ required: true, description: 'روش تسویه (۱.نقدی، ۲.نسیه، ۳.نقدی-نسیه)' })
|
||||
@IsString()
|
||||
setm: string
|
||||
setm: '1' | '2' | '3'
|
||||
|
||||
@ApiProperty({ description: 'سهم پرداخت نقدی در صورتی که نقدی - نسیه باشد (۳)' })
|
||||
@IsString()
|
||||
cap: string
|
||||
|
||||
@ApiProperty({ description: 'سهم پرداخت نسیه در صورتی که نقدی - نسیه باشد (۳)' })
|
||||
@IsString()
|
||||
insp: string
|
||||
}
|
||||
|
||||
export class NamaProviderRequestDto {
|
||||
@@ -508,9 +516,17 @@ export class NamaProviderCorrectionHeaderDto {
|
||||
@IsString()
|
||||
bid: string
|
||||
|
||||
@ApiProperty({ required: true, description: 'روش تسویه' })
|
||||
@ApiProperty({ required: true, description: 'روش تسویه (۱.نقدی، ۲.نسیه، ۳.نقدی-نسیه)' })
|
||||
@IsString()
|
||||
setm: string
|
||||
setm: '1' | '2' | '3'
|
||||
|
||||
@ApiProperty({ description: 'سهم پرداخت نقدی در صورتی که نقدی - نسیه باشد (۳)' })
|
||||
@IsString()
|
||||
cap: string
|
||||
|
||||
@ApiProperty({ description: 'سهم پرداخت نسیه در صورتی که نقدی - نسیه باشد (۳)' })
|
||||
@IsString()
|
||||
insp: string
|
||||
}
|
||||
|
||||
export class NamaProviderCorrectionRequestDto {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { TspProviderCustomerType } from '@/common/enums/enums'
|
||||
import {
|
||||
CustomerType,
|
||||
InvoiceSettlementType,
|
||||
InvoiceTemplateType,
|
||||
PaymentMethodType,
|
||||
TspProviderRequestType,
|
||||
@@ -54,7 +55,11 @@ export class NamaProviderUtils {
|
||||
inno: payload.invoice_number.toString(),
|
||||
tins: '',
|
||||
indatim: payload.invoice_date.getTime() + '',
|
||||
setm: '1',
|
||||
...this.mapSettlementBased(
|
||||
payload.settlement_type,
|
||||
payload.payments,
|
||||
payload.total_amount,
|
||||
),
|
||||
...this.mapCustomerInfo(payload.customer),
|
||||
},
|
||||
body: payload.items.map(item => ({
|
||||
@@ -134,6 +139,41 @@ export class NamaProviderUtils {
|
||||
}
|
||||
}
|
||||
|
||||
private mapSettlementType(type: InvoiceSettlementType) {
|
||||
switch (type) {
|
||||
case InvoiceSettlementType.CASH:
|
||||
return '1'
|
||||
case InvoiceSettlementType.CREDIT:
|
||||
return '2'
|
||||
case InvoiceSettlementType.MIXED:
|
||||
return '3'
|
||||
}
|
||||
}
|
||||
|
||||
private mapSettlementBased(
|
||||
type: InvoiceSettlementType,
|
||||
payments: PaymentInfoDto[],
|
||||
totalAmount: number,
|
||||
) {
|
||||
switch (type) {
|
||||
case InvoiceSettlementType.CASH:
|
||||
return {
|
||||
setm: '1',
|
||||
}
|
||||
case InvoiceSettlementType.CREDIT:
|
||||
return {
|
||||
setm: '2',
|
||||
}
|
||||
case InvoiceSettlementType.MIXED:
|
||||
const totalPayed = payments.reduce((prev, curr) => (prev += curr.amount), 0)
|
||||
return {
|
||||
setm: '3',
|
||||
cap: totalPayed.toString(),
|
||||
insp: (totalAmount - totalPayed).toString(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private mapInvoiceTemplate(template: InvoiceTemplateType) {
|
||||
switch (template) {
|
||||
case InvoiceTemplateType.SALE:
|
||||
|
||||
Reference in New Issue
Block a user