feat: enhance CustomerIndividual and CustomerLegal models with new unique input types
feat: add cache invalidation method for POS middleware feat: implement Redis caching in POS middleware for improved performance feat: refactor sales invoice DTOs for POS to include correction functionality feat: extend SalesInvoicesController to handle invoice corrections and returns feat: update SalesInvoicesService to support invoice correction and return operations feat: enhance TSP provider correction functionality with new DTOs and utility methods fix: improve error handling and logging in Nama provider switch adapter refactor: streamline invoice payload building in TSP provider utilities
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
import {
|
import {
|
||||||
InvoiceSettlementType,
|
InvoiceSettlementType,
|
||||||
|
TspProviderRequestType,
|
||||||
TspProviderResponseStatus,
|
TspProviderResponseStatus,
|
||||||
} from '@/generated/prisma/enums'
|
} from '@/generated/prisma/enums'
|
||||||
|
|
||||||
@@ -153,10 +154,10 @@ export default {
|
|||||||
[InvoiceSettlementType.MIXED]: 'نقدی / نسیه',
|
[InvoiceSettlementType.MIXED]: 'نقدی / نسیه',
|
||||||
},
|
},
|
||||||
TspProviderRequestType: {
|
TspProviderRequestType: {
|
||||||
ORIGINAL: 'اصلی',
|
[TspProviderRequestType.ORIGINAL]: 'اصلی',
|
||||||
CORRECTION: 'اصلاح',
|
[TspProviderRequestType.CORRECTION]: 'اصلاح',
|
||||||
REVOKE: 'ابطال',
|
[TspProviderRequestType.REVOKE]: 'ابطال',
|
||||||
REMOVE: 'حذف',
|
[TspProviderRequestType.RETURN]: 'برگشت از فروش',
|
||||||
},
|
},
|
||||||
TspProviderCustomerType: {
|
TspProviderCustomerType: {
|
||||||
Unknown: 'ناشناس',
|
Unknown: 'ناشناس',
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { SharedSaleInvoiceAccessService } from '@/common/services/saleInvoices/sale-invoice-access.service'
|
import { SharedSaleInvoiceAccessService } from '@/common/services/saleInvoices/sale-invoice-access.service'
|
||||||
import { Injectable } from '@nestjs/common'
|
import { PosCorrectionSalesInvoiceDto } from '@/modules/pos/sales-invoices/dto/create-sales-invoice.dto'
|
||||||
import { SalesInvoiceTspService } from '@/modules/tspProviders/sales-invoice-tsp.service'
|
import { SalesInvoiceTspService } from '@/modules/tspProviders/sales-invoice-tsp.service'
|
||||||
|
import { Injectable } from '@nestjs/common'
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class SharedSaleInvoiceActionsService {
|
export class SharedSaleInvoiceActionsService {
|
||||||
@@ -45,6 +46,28 @@ export class SharedSaleInvoiceActionsService {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async correction(
|
||||||
|
data: PosCorrectionSalesInvoiceDto,
|
||||||
|
consumerAccountId: string,
|
||||||
|
posId: string,
|
||||||
|
complexId: string,
|
||||||
|
businessId: string,
|
||||||
|
invoiceId: string,
|
||||||
|
) {
|
||||||
|
await this.saleInvoiceAccessService.getConsumerIdWithPosAccess(
|
||||||
|
consumerAccountId,
|
||||||
|
posId,
|
||||||
|
)
|
||||||
|
return this.salesInvoiceTspService.correctionSend(
|
||||||
|
consumerAccountId,
|
||||||
|
posId,
|
||||||
|
complexId,
|
||||||
|
businessId,
|
||||||
|
invoiceId,
|
||||||
|
data,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
async inquiry(consumerAccountId: string, posId: string, invoiceId: string) {
|
async inquiry(consumerAccountId: string, posId: string, invoiceId: string) {
|
||||||
const consumerId = await this.saleInvoiceAccessService.getConsumerIdWithPosAccess(
|
const consumerId = await this.saleInvoiceAccessService.getConsumerIdWithPosAccess(
|
||||||
consumerAccountId,
|
consumerAccountId,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import type { SaleInvoiceType } from '@/common/interfaces/sale-invoice-payload'
|
import type { SaleInvoiceType } from '@/common/interfaces/sale-invoice-payload'
|
||||||
import { ApiProperty } from '@nestjs/swagger'
|
import { ApiProperty, OmitType } from '@nestjs/swagger'
|
||||||
import { Type } from 'class-transformer'
|
import { Type } from 'class-transformer'
|
||||||
import {
|
import {
|
||||||
ArrayMinSize,
|
ArrayMinSize,
|
||||||
@@ -206,8 +206,6 @@ export class SharedCreateSalesInvoiceDto {
|
|||||||
@IsBoolean()
|
@IsBoolean()
|
||||||
send_to_tsp?: boolean
|
send_to_tsp?: boolean
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ApiProperty({ required: true, default: CustomerType.UNKNOWN })
|
@ApiProperty({ required: true, default: CustomerType.UNKNOWN })
|
||||||
@IsEnum(CustomerType)
|
@IsEnum(CustomerType)
|
||||||
customer_type: CustomerType
|
customer_type: CustomerType
|
||||||
@@ -229,3 +227,8 @@ export class SharedCreateSalesInvoiceDto {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class SharedCorrectionSalesInvoiceDto extends OmitType(
|
||||||
|
SharedCreateSalesInvoiceDto,
|
||||||
|
['customer', 'customer_id', 'send_to_tsp', 'customer_type', 'settlement_type'],
|
||||||
|
) {}
|
||||||
|
|||||||
@@ -18,13 +18,13 @@ export function checkAndDecodeJwtToken(
|
|||||||
token = authHeader.slice(7)
|
token = authHeader.slice(7)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!token) throw new UnauthorizedException('Missing accessToken cookie')
|
if (!token) throw new UnauthorizedException('توکن احراز هویت ارسال نشده است')
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const payload = jwtService.decode(token) as AccessTokenPayload
|
const payload = jwtService.decode(token) as AccessTokenPayload
|
||||||
|
|
||||||
return payload as ITokenPayload
|
return payload as ITokenPayload
|
||||||
} catch {
|
} catch {
|
||||||
return null
|
throw new UnauthorizedException('توکن احراز هویت نامعتبر است')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ export class RedisKeyMaker extends PartnerKeyMaker {
|
|||||||
static guildStockKeepingUnitsList = GuildKeyMaker.guildStockKeepingUnitsList
|
static guildStockKeepingUnitsList = GuildKeyMaker.guildStockKeepingUnitsList
|
||||||
static guildGoodsList = GuildKeyMaker.guildGoodsList
|
static guildGoodsList = GuildKeyMaker.guildGoodsList
|
||||||
|
|
||||||
|
static posMiddleware = PosKeyMaker.middleware
|
||||||
static posInfo = PosKeyMaker.info
|
static posInfo = PosKeyMaker.info
|
||||||
static posMe = PosKeyMaker.me
|
static posMe = PosKeyMaker.me
|
||||||
static posGoodsList = PosKeyMaker.goodList
|
static posGoodsList = PosKeyMaker.goodList
|
||||||
|
|||||||
@@ -1,4 +1,8 @@
|
|||||||
export class PosKeyMaker {
|
export class PosKeyMaker {
|
||||||
|
static middleware(token: string): string {
|
||||||
|
return `pos:${token}:middleware`
|
||||||
|
}
|
||||||
|
|
||||||
static info(posId: string): string {
|
static info(posId: string): string {
|
||||||
return `pos:${posId}:info`
|
return `pos:${posId}:info`
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -227,6 +227,7 @@ export type CustomerIndividualOrderByWithRelationInput = {
|
|||||||
export type CustomerIndividualWhereUniqueInput = Prisma.AtLeast<{
|
export type CustomerIndividualWhereUniqueInput = Prisma.AtLeast<{
|
||||||
customer_id?: string
|
customer_id?: string
|
||||||
business_activity_id_national_id?: Prisma.CustomerIndividualBusiness_activity_idNational_idCompoundUniqueInput
|
business_activity_id_national_id?: Prisma.CustomerIndividualBusiness_activity_idNational_idCompoundUniqueInput
|
||||||
|
business_activity_id_postal_code_national_id?: Prisma.CustomerIndividualBusiness_activity_idPostal_codeNational_idCompoundUniqueInput
|
||||||
AND?: Prisma.CustomerIndividualWhereInput | Prisma.CustomerIndividualWhereInput[]
|
AND?: Prisma.CustomerIndividualWhereInput | Prisma.CustomerIndividualWhereInput[]
|
||||||
OR?: Prisma.CustomerIndividualWhereInput[]
|
OR?: Prisma.CustomerIndividualWhereInput[]
|
||||||
NOT?: Prisma.CustomerIndividualWhereInput | Prisma.CustomerIndividualWhereInput[]
|
NOT?: Prisma.CustomerIndividualWhereInput | Prisma.CustomerIndividualWhereInput[]
|
||||||
@@ -239,7 +240,7 @@ export type CustomerIndividualWhereUniqueInput = Prisma.AtLeast<{
|
|||||||
business_activity_id?: Prisma.StringFilter<"CustomerIndividual"> | string
|
business_activity_id?: Prisma.StringFilter<"CustomerIndividual"> | string
|
||||||
business_activity?: Prisma.XOR<Prisma.BusinessActivityScalarRelationFilter, Prisma.BusinessActivityWhereInput>
|
business_activity?: Prisma.XOR<Prisma.BusinessActivityScalarRelationFilter, Prisma.BusinessActivityWhereInput>
|
||||||
customer?: Prisma.XOR<Prisma.CustomerScalarRelationFilter, Prisma.CustomerWhereInput>
|
customer?: Prisma.XOR<Prisma.CustomerScalarRelationFilter, Prisma.CustomerWhereInput>
|
||||||
}, "customer_id" | "business_activity_id_national_id">
|
}, "customer_id" | "business_activity_id_national_id" | "business_activity_id_postal_code_national_id">
|
||||||
|
|
||||||
export type CustomerIndividualOrderByWithAggregationInput = {
|
export type CustomerIndividualOrderByWithAggregationInput = {
|
||||||
first_name?: Prisma.SortOrderInput | Prisma.SortOrder
|
first_name?: Prisma.SortOrderInput | Prisma.SortOrder
|
||||||
@@ -370,6 +371,12 @@ export type CustomerIndividualBusiness_activity_idNational_idCompoundUniqueInput
|
|||||||
national_id: string
|
national_id: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type CustomerIndividualBusiness_activity_idPostal_codeNational_idCompoundUniqueInput = {
|
||||||
|
business_activity_id: string
|
||||||
|
postal_code: string
|
||||||
|
national_id: string
|
||||||
|
}
|
||||||
|
|
||||||
export type CustomerIndividualCountOrderByAggregateInput = {
|
export type CustomerIndividualCountOrderByAggregateInput = {
|
||||||
first_name?: Prisma.SortOrder
|
first_name?: Prisma.SortOrder
|
||||||
last_name?: Prisma.SortOrder
|
last_name?: Prisma.SortOrder
|
||||||
|
|||||||
@@ -209,6 +209,7 @@ export type CustomerLegalOrderByWithRelationInput = {
|
|||||||
export type CustomerLegalWhereUniqueInput = Prisma.AtLeast<{
|
export type CustomerLegalWhereUniqueInput = Prisma.AtLeast<{
|
||||||
customer_id?: string
|
customer_id?: string
|
||||||
business_activity_id_economic_code?: Prisma.CustomerLegalBusiness_activity_idEconomic_codeCompoundUniqueInput
|
business_activity_id_economic_code?: Prisma.CustomerLegalBusiness_activity_idEconomic_codeCompoundUniqueInput
|
||||||
|
business_activity_id_postal_code_registration_number?: Prisma.CustomerLegalBusiness_activity_idPostal_codeRegistration_numberCompoundUniqueInput
|
||||||
AND?: Prisma.CustomerLegalWhereInput | Prisma.CustomerLegalWhereInput[]
|
AND?: Prisma.CustomerLegalWhereInput | Prisma.CustomerLegalWhereInput[]
|
||||||
OR?: Prisma.CustomerLegalWhereInput[]
|
OR?: Prisma.CustomerLegalWhereInput[]
|
||||||
NOT?: Prisma.CustomerLegalWhereInput | Prisma.CustomerLegalWhereInput[]
|
NOT?: Prisma.CustomerLegalWhereInput | Prisma.CustomerLegalWhereInput[]
|
||||||
@@ -219,7 +220,7 @@ export type CustomerLegalWhereUniqueInput = Prisma.AtLeast<{
|
|||||||
business_activity_id?: Prisma.StringFilter<"CustomerLegal"> | string
|
business_activity_id?: Prisma.StringFilter<"CustomerLegal"> | string
|
||||||
business_activity?: Prisma.XOR<Prisma.BusinessActivityScalarRelationFilter, Prisma.BusinessActivityWhereInput>
|
business_activity?: Prisma.XOR<Prisma.BusinessActivityScalarRelationFilter, Prisma.BusinessActivityWhereInput>
|
||||||
customer?: Prisma.XOR<Prisma.CustomerScalarRelationFilter, Prisma.CustomerWhereInput>
|
customer?: Prisma.XOR<Prisma.CustomerScalarRelationFilter, Prisma.CustomerWhereInput>
|
||||||
}, "customer_id" | "business_activity_id_economic_code">
|
}, "customer_id" | "business_activity_id_economic_code" | "business_activity_id_postal_code_registration_number">
|
||||||
|
|
||||||
export type CustomerLegalOrderByWithAggregationInput = {
|
export type CustomerLegalOrderByWithAggregationInput = {
|
||||||
name?: Prisma.SortOrderInput | Prisma.SortOrder
|
name?: Prisma.SortOrderInput | Prisma.SortOrder
|
||||||
@@ -332,6 +333,12 @@ export type CustomerLegalBusiness_activity_idEconomic_codeCompoundUniqueInput =
|
|||||||
economic_code: string
|
economic_code: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type CustomerLegalBusiness_activity_idPostal_codeRegistration_numberCompoundUniqueInput = {
|
||||||
|
business_activity_id: string
|
||||||
|
postal_code: string
|
||||||
|
registration_number: string
|
||||||
|
}
|
||||||
|
|
||||||
export type CustomerLegalCountOrderByAggregateInput = {
|
export type CustomerLegalCountOrderByAggregateInput = {
|
||||||
name?: Prisma.SortOrder
|
name?: Prisma.SortOrder
|
||||||
economic_code?: Prisma.SortOrder
|
economic_code?: Prisma.SortOrder
|
||||||
|
|||||||
@@ -6,6 +6,10 @@ import { Injectable } from '@nestjs/common'
|
|||||||
export class PosCacheInvalidationService {
|
export class PosCacheInvalidationService {
|
||||||
constructor(private readonly redisService: RedisService) {}
|
constructor(private readonly redisService: RedisService) {}
|
||||||
|
|
||||||
|
async invalidatePosMiddleware(token: string): Promise<void> {
|
||||||
|
this.redisService.delete(PosKeyMaker.middleware(token))
|
||||||
|
}
|
||||||
|
|
||||||
async invalidatePosGoodsList(
|
async invalidatePosGoodsList(
|
||||||
guildId: string,
|
guildId: string,
|
||||||
businessActivityId: string,
|
businessActivityId: string,
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
|
import { RedisKeyMaker } from '@/common/utils'
|
||||||
import { checkAndDecodeJwtToken } from '@/common/utils/jwt-user.util'
|
import { checkAndDecodeJwtToken } from '@/common/utils/jwt-user.util'
|
||||||
import { ConsumerRole, POSStatus } from '@/generated/prisma/enums'
|
import { ConsumerRole, POSStatus } from '@/generated/prisma/enums'
|
||||||
import { PosSelect, PosWhereInput } from '@/generated/prisma/models'
|
import { PosSelect, PosWhereInput } from '@/generated/prisma/models'
|
||||||
import { PrismaService } from '@/prisma/prisma.service'
|
import { PrismaService } from '@/prisma/prisma.service'
|
||||||
|
import { RedisService } from '@/redis/redis.service'
|
||||||
import {
|
import {
|
||||||
ForbiddenException,
|
ForbiddenException,
|
||||||
Injectable,
|
Injectable,
|
||||||
@@ -16,15 +18,38 @@ export class PosMiddleware implements NestMiddleware {
|
|||||||
constructor(
|
constructor(
|
||||||
private prisma: PrismaService,
|
private prisma: PrismaService,
|
||||||
private jwtService: JwtService,
|
private jwtService: JwtService,
|
||||||
|
private redisService: RedisService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async use(req: Request, _res: Response, next: NextFunction) {
|
async use(req: Request, _res: Response, next: NextFunction) {
|
||||||
const doForbidden = () => {
|
const doForbidden = () => {
|
||||||
throw new ForbiddenException('شما دسترسی لازم را ندارید')
|
throw new ForbiddenException('شما دسترسی لازم را ندارید')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const token = req.cookies?.accessToken
|
||||||
|
const cacheKey = RedisKeyMaker.posMiddleware(token)
|
||||||
|
let cashedPosData: unknown
|
||||||
|
try {
|
||||||
|
cashedPosData = await this.redisService.getJson(cacheKey)
|
||||||
|
} catch (_) {}
|
||||||
|
const tokenAccount = checkAndDecodeJwtToken(req, this.jwtService)
|
||||||
|
req.decodedToken = tokenAccount!
|
||||||
|
|
||||||
|
if (
|
||||||
|
cashedPosData &&
|
||||||
|
typeof cashedPosData === 'object' &&
|
||||||
|
'pos_id' in cashedPosData &&
|
||||||
|
'complex_id' in cashedPosData &&
|
||||||
|
'business_id' in cashedPosData &&
|
||||||
|
'guild_id' in cashedPosData &&
|
||||||
|
'consumer_account_id' in cashedPosData
|
||||||
|
) {
|
||||||
|
req.posData = cashedPosData as any
|
||||||
|
return next()
|
||||||
|
}
|
||||||
|
|
||||||
return this.prisma.$transaction(async tx => {
|
return this.prisma.$transaction(async tx => {
|
||||||
try {
|
try {
|
||||||
const tokenAccount = checkAndDecodeJwtToken(req, this.jwtService)
|
|
||||||
const { type, role, account_id } = tokenAccount!
|
const { type, role, account_id } = tokenAccount!
|
||||||
const posSelect: PosSelect = {
|
const posSelect: PosSelect = {
|
||||||
id: true,
|
id: true,
|
||||||
@@ -103,6 +128,20 @@ export class PosMiddleware implements NestMiddleware {
|
|||||||
return doForbidden()
|
return doForbidden()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await this.redisService.setJson(
|
||||||
|
cacheKey,
|
||||||
|
{
|
||||||
|
pos_id: posId,
|
||||||
|
complex_id: pos.complex.id,
|
||||||
|
business_id: pos.complex.business_activity.id,
|
||||||
|
guild_id: pos.complex.business_activity.guild_id,
|
||||||
|
consumer_account_id: account_id,
|
||||||
|
},
|
||||||
|
60 * 60,
|
||||||
|
)
|
||||||
|
} catch (_) {}
|
||||||
|
|
||||||
req.posData = {
|
req.posData = {
|
||||||
pos_id: posId,
|
pos_id: posId,
|
||||||
complex_id: pos.complex.id,
|
complex_id: pos.complex.id,
|
||||||
@@ -110,7 +149,6 @@ export class PosMiddleware implements NestMiddleware {
|
|||||||
guild_id: pos.complex.business_activity.guild_id,
|
guild_id: pos.complex.business_activity.guild_id,
|
||||||
consumer_account_id: account_id,
|
consumer_account_id: account_id,
|
||||||
}
|
}
|
||||||
req.decodedToken = tokenAccount!
|
|
||||||
|
|
||||||
return next()
|
return next()
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { SharedCreateSalesInvoiceDto } from '@/common/services/saleInvoices/sale-invoice-create.dto'
|
import {
|
||||||
import { PartialType } from '@nestjs/swagger'
|
SharedCorrectionSalesInvoiceDto,
|
||||||
|
SharedCreateSalesInvoiceDto,
|
||||||
|
} from '@/common/services/saleInvoices/sale-invoice-create.dto'
|
||||||
|
|
||||||
export class CreateSalesInvoiceDto extends SharedCreateSalesInvoiceDto {}
|
export class PosCreateSalesInvoiceDto extends SharedCreateSalesInvoiceDto {}
|
||||||
|
export class PosCorrectionSalesInvoiceDto extends SharedCorrectionSalesInvoiceDto {}
|
||||||
export class UpdateSalesInvoiceDto extends PartialType(CreateSalesInvoiceDto) {}
|
|
||||||
|
|||||||
@@ -2,7 +2,10 @@ import { Body, Controller, Get, Param, Post, Query } from '@nestjs/common'
|
|||||||
|
|
||||||
import { PosInfo } from '@/common/decorators/posInfo.decorator'
|
import { PosInfo } from '@/common/decorators/posInfo.decorator'
|
||||||
import type { IPosPayload } from '@/common/models/posPayload.model'
|
import type { IPosPayload } from '@/common/models/posPayload.model'
|
||||||
import { CreateSalesInvoiceDto } from './dto/create-sales-invoice.dto'
|
import {
|
||||||
|
PosCorrectionSalesInvoiceDto,
|
||||||
|
PosCreateSalesInvoiceDto,
|
||||||
|
} from './dto/create-sales-invoice.dto'
|
||||||
import { SalesInvoicesFilterDto } from './dto/sales-invoices-filter.dto'
|
import { SalesInvoicesFilterDto } from './dto/sales-invoices-filter.dto'
|
||||||
import { SalesInvoicesService } from './sales-invoices.service'
|
import { SalesInvoicesService } from './sales-invoices.service'
|
||||||
|
|
||||||
@@ -30,7 +33,7 @@ export class SalesInvoicesController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Post()
|
@Post()
|
||||||
create(@Body() data: CreateSalesInvoiceDto, @PosInfo() posInfo: IPosPayload) {
|
create(@Body() data: PosCreateSalesInvoiceDto, @PosInfo() posInfo: IPosPayload) {
|
||||||
return this.salesInvoicesService.create(data, posInfo)
|
return this.salesInvoicesService.create(data, posInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,6 +52,19 @@ export class SalesInvoicesController {
|
|||||||
return this.salesInvoicesService.revoke(id, posInfo)
|
return this.salesInvoicesService.revoke(id, posInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Post(':id/correction')
|
||||||
|
correction(
|
||||||
|
@Param('id') id: string,
|
||||||
|
@PosInfo() posInfo: IPosPayload,
|
||||||
|
@Body() data: PosCorrectionSalesInvoiceDto,
|
||||||
|
) {
|
||||||
|
return this.salesInvoicesService.correction(id, posInfo, data)
|
||||||
|
}
|
||||||
|
@Post(':id/return')
|
||||||
|
return(@Param('id') id: string, @PosInfo() posInfo: IPosPayload) {
|
||||||
|
return this.salesInvoicesService.return(id, posInfo)
|
||||||
|
}
|
||||||
|
|
||||||
// @Post('send/bulk')
|
// @Post('send/bulk')
|
||||||
// sendBulk(@Body() data: SendBulkSalesInvoicesDto, @PosInfo() posInfo: IPosPayload) {
|
// sendBulk(@Body() data: SendBulkSalesInvoicesDto, @PosInfo() posInfo: IPosPayload) {
|
||||||
// return this.salesInvoicesService.sendBulk(data.invoice_ids, posInfo)
|
// return this.salesInvoicesService.sendBulk(data.invoice_ids, posInfo)
|
||||||
|
|||||||
@@ -9,7 +9,10 @@ import { ResponseMapper } from 'common/response/response-mapper'
|
|||||||
import { Prisma } from 'generated/prisma/client'
|
import { Prisma } from 'generated/prisma/client'
|
||||||
import { TspProviderRequestType, TspProviderResponseStatus } from 'generated/prisma/enums'
|
import { TspProviderRequestType, TspProviderResponseStatus } from 'generated/prisma/enums'
|
||||||
import { SalesInvoiceTspService } from '../../tspProviders/sales-invoice-tsp.service'
|
import { SalesInvoiceTspService } from '../../tspProviders/sales-invoice-tsp.service'
|
||||||
import { CreateSalesInvoiceDto } from './dto/create-sales-invoice.dto'
|
import {
|
||||||
|
PosCorrectionSalesInvoiceDto,
|
||||||
|
PosCreateSalesInvoiceDto,
|
||||||
|
} from './dto/create-sales-invoice.dto'
|
||||||
import { SalesInvoicesFilterDto } from './dto/sales-invoices-filter.dto'
|
import { SalesInvoicesFilterDto } from './dto/sales-invoices-filter.dto'
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
@@ -91,7 +94,7 @@ export class SalesInvoicesService {
|
|||||||
} else throw new NotFoundException('فاکتور مورد نظر شما یافت نشد.')
|
} else throw new NotFoundException('فاکتور مورد نظر شما یافت نشد.')
|
||||||
}
|
}
|
||||||
|
|
||||||
async create(data: CreateSalesInvoiceDto, posInfo: IPosPayload) {
|
async create(data: PosCreateSalesInvoiceDto, posInfo: IPosPayload) {
|
||||||
let salesInvoice = await this.sharedSaleInvoiceCreateService.create({
|
let salesInvoice = await this.sharedSaleInvoiceCreateService.create({
|
||||||
data,
|
data,
|
||||||
businessId: posInfo.business_id,
|
businessId: posInfo.business_id,
|
||||||
@@ -148,6 +151,39 @@ export class SalesInvoicesService {
|
|||||||
return ResponseMapper.single(invoice)
|
return ResponseMapper.single(invoice)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async correction(
|
||||||
|
invoiceId: string,
|
||||||
|
posInfo: IPosPayload,
|
||||||
|
data: PosCorrectionSalesInvoiceDto,
|
||||||
|
) {
|
||||||
|
const { consumer_account_id, pos_id, business_id, complex_id } = posInfo
|
||||||
|
|
||||||
|
const invoice = await this.sharedSaleInvoiceActionsService.correction(
|
||||||
|
data,
|
||||||
|
consumer_account_id,
|
||||||
|
pos_id,
|
||||||
|
complex_id,
|
||||||
|
business_id,
|
||||||
|
invoiceId,
|
||||||
|
)
|
||||||
|
|
||||||
|
return ResponseMapper.single(invoice)
|
||||||
|
}
|
||||||
|
|
||||||
|
async return(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) {
|
async inquiry(consumer_account_id: string, pos_id: string, invoiceId: string) {
|
||||||
const invoice = await this.sharedSaleInvoiceActionsService.inquiry(
|
const invoice = await this.sharedSaleInvoiceActionsService.inquiry(
|
||||||
consumer_account_id,
|
consumer_account_id,
|
||||||
|
|||||||
@@ -7,14 +7,22 @@ import { Type } from 'class-transformer'
|
|||||||
import {
|
import {
|
||||||
ArrayMinSize,
|
ArrayMinSize,
|
||||||
IsArray,
|
IsArray,
|
||||||
|
IsDateString,
|
||||||
IsNumber,
|
IsNumber,
|
||||||
IsObject,
|
IsObject,
|
||||||
IsString,
|
IsString,
|
||||||
ValidateNested,
|
ValidateNested,
|
||||||
} from 'class-validator'
|
} from 'class-validator'
|
||||||
import { TspProviderOriginalSendPayloadDto } from './original.dto'
|
import {
|
||||||
|
TspProviderOriginalResponseDto,
|
||||||
|
TspProviderOriginalSendPayloadDto,
|
||||||
|
} from './original.dto'
|
||||||
|
|
||||||
export class TspProviderCorrectionInvoicePayloadDto {
|
export class TspProviderCorrectionInvoicePayloadDto {
|
||||||
|
@ApiProperty({ required: true, nullable: true })
|
||||||
|
@IsDateString()
|
||||||
|
invoice_date: Date
|
||||||
|
|
||||||
@ApiProperty({ type: [SharedCreateSalesInvoiceItemDto] })
|
@ApiProperty({ type: [SharedCreateSalesInvoiceItemDto] })
|
||||||
@IsArray()
|
@IsArray()
|
||||||
@ValidateNested({ each: true })
|
@ValidateNested({ each: true })
|
||||||
@@ -46,4 +54,4 @@ export class TspProviderCorrectionSendPayloadDto extends TspProviderOriginalSend
|
|||||||
last_tax_id: string
|
last_tax_id: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export class TspProviderCorrectionSendResponseDto {}
|
export class TspProviderCorrectionSendResponseDto extends TspProviderOriginalResponseDto {}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import {
|
|||||||
IsOptional,
|
IsOptional,
|
||||||
IsString,
|
IsString,
|
||||||
Min,
|
Min,
|
||||||
ValidateNested
|
ValidateNested,
|
||||||
} from 'class-validator'
|
} from 'class-validator'
|
||||||
import {
|
import {
|
||||||
CustomerInfoDto,
|
CustomerInfoDto,
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import {
|
|||||||
buildOriginalPayload,
|
buildOriginalPayload,
|
||||||
buildRevokePayload,
|
buildRevokePayload,
|
||||||
getOriginalResendAttemptNumber,
|
getOriginalResendAttemptNumber,
|
||||||
|
getRelatedInvoiceForCorrection,
|
||||||
onResult,
|
onResult,
|
||||||
trySend,
|
trySend,
|
||||||
} from './utils/sales-invoice-tsp.utils'
|
} from './utils/sales-invoice-tsp.utils'
|
||||||
@@ -165,45 +166,13 @@ export class SalesInvoiceTspService {
|
|||||||
): Promise<TspProviderActionResponseDto> {
|
): Promise<TspProviderActionResponseDto> {
|
||||||
const [newInvoice, attempt, correctionPayload] = await this.prisma.$transaction(
|
const [newInvoice, attempt, correctionPayload] = await this.prisma.$transaction(
|
||||||
async tx => {
|
async tx => {
|
||||||
const relatedInvoice = await tx.salesInvoice.findUnique({
|
const relatedInvoice = await getRelatedInvoiceForCorrection(tx, ref_invoice_id)
|
||||||
where: {
|
|
||||||
id: ref_invoice_id,
|
|
||||||
},
|
|
||||||
include: {
|
|
||||||
customer: {
|
|
||||||
select: {
|
|
||||||
type: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
tsp_attempts: {
|
|
||||||
orderBy: {
|
|
||||||
attempt_no: 'desc',
|
|
||||||
},
|
|
||||||
take: 1,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
if (!relatedInvoice) {
|
|
||||||
throw new NotFoundException('فاکتور مورد نظر یافت نشد.')
|
|
||||||
}
|
|
||||||
|
|
||||||
if (relatedInvoice.type === TspProviderRequestType.REVOKE) {
|
|
||||||
throw new BadRequestException(
|
|
||||||
'فاکتور ارسالی قبلا ابطال شده است و امکان ویرایش آن وجود ندارد.',
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!relatedInvoice.tax_id) {
|
|
||||||
throw new BadRequestException(
|
|
||||||
'فاکتور قبلی همچنان در حال بررسی است و امکان ویرایش آن وجود ندارد.',
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const newInvoice = await this.sharedSaleInvoiceCreateService.create({
|
const newInvoice = await this.sharedSaleInvoiceCreateService.create({
|
||||||
|
tx,
|
||||||
data: {
|
data: {
|
||||||
customer_type: relatedInvoice.customer?.type || CustomerType.UNKNOWN,
|
customer_type: relatedInvoice.customer?.type || CustomerType.UNKNOWN,
|
||||||
invoice_date: new Date(),
|
invoice_date: dataToUpdate.invoice_date,
|
||||||
payments: dataToUpdate.payments,
|
payments: dataToUpdate.payments,
|
||||||
items: dataToUpdate.items,
|
items: dataToUpdate.items,
|
||||||
total_amount: dataToUpdate.total_amount,
|
total_amount: dataToUpdate.total_amount,
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ export class NamaProviderCorrectionRequestDto {
|
|||||||
payment: NamaProviderPaymentInfoDto[]
|
payment: NamaProviderPaymentInfoDto[]
|
||||||
|
|
||||||
@ApiProperty({ type: NamaProviderCorrectionHeaderDto })
|
@ApiProperty({ type: NamaProviderCorrectionHeaderDto })
|
||||||
@ValidateNested()
|
@ValidateNested({ each: true })
|
||||||
@Type(() => NamaProviderCorrectionHeaderDto)
|
@Type(() => NamaProviderCorrectionHeaderDto)
|
||||||
header: NamaProviderCorrectionHeaderDto
|
header: NamaProviderCorrectionHeaderDto
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import {
|
|||||||
TspProviderBulkSendResultDto,
|
TspProviderBulkSendResultDto,
|
||||||
} from '../../dto/provider-switch.dto'
|
} from '../../dto/provider-switch.dto'
|
||||||
import {
|
import {
|
||||||
|
NamaProviderCorrectionResponseDto,
|
||||||
NamaProviderGetResponseDto,
|
NamaProviderGetResponseDto,
|
||||||
NamaProviderOriginalResponseDto,
|
NamaProviderOriginalResponseDto,
|
||||||
NamaProviderResponseStatus,
|
NamaProviderResponseStatus,
|
||||||
@@ -38,6 +39,7 @@ export class NamaProviderSwitchAdapter implements IProviderSwitchAdapter {
|
|||||||
process.env.NAMA_PROVIDER_PRODUCTION_URL || 'https://api.nama.ir'
|
process.env.NAMA_PROVIDER_PRODUCTION_URL || 'https://api.nama.ir'
|
||||||
|
|
||||||
private readonly sendPath = '/api/v1/invoices/single-send'
|
private readonly sendPath = '/api/v1/invoices/single-send'
|
||||||
|
private readonly correctionPath = this.sendPath
|
||||||
private readonly sendBulkPath = '/api/v1/invoices'
|
private readonly sendBulkPath = '/api/v1/invoices'
|
||||||
private readonly checkBulkStatus = '/api/v1/invoices/check-by-uuids'
|
private readonly checkBulkStatus = '/api/v1/invoices/check-by-uuids'
|
||||||
private readonly getPath = '/api/v1/invoices'
|
private readonly getPath = '/api/v1/invoices'
|
||||||
@@ -57,6 +59,10 @@ export class NamaProviderSwitchAdapter implements IProviderSwitchAdapter {
|
|||||||
return `${this.baseUrl}${this.sendPath}`
|
return `${this.baseUrl}${this.sendPath}`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private buildCorrectionUrl() {
|
||||||
|
return `${this.baseUrl}${this.correctionPath}`
|
||||||
|
}
|
||||||
|
|
||||||
private buildGetUrl(invoiceId: string) {
|
private buildGetUrl(invoiceId: string) {
|
||||||
return `${this.baseUrl}${this.getPath}/${invoiceId}`
|
return `${this.baseUrl}${this.getPath}/${invoiceId}`
|
||||||
}
|
}
|
||||||
@@ -110,9 +116,8 @@ export class NamaProviderSwitchAdapter implements IProviderSwitchAdapter {
|
|||||||
|
|
||||||
return result
|
return result
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log('err@@@@@@@@@@@@@@@@@@', err);
|
console.log('err@@@@@@@@@@@@@@@@@@', err)
|
||||||
console.log(JSON.parse(JSON.stringify(mappedRequest)));
|
console.log(JSON.parse(JSON.stringify(mappedRequest)))
|
||||||
|
|
||||||
|
|
||||||
const failure: TspProviderOriginalResponseDto = {
|
const failure: TspProviderOriginalResponseDto = {
|
||||||
invoice_id: payload.id,
|
invoice_id: payload.id,
|
||||||
@@ -129,21 +134,21 @@ export class NamaProviderSwitchAdapter implements IProviderSwitchAdapter {
|
|||||||
async correctionSend(
|
async correctionSend(
|
||||||
payload: TspProviderCorrectionSendPayloadDto,
|
payload: TspProviderCorrectionSendPayloadDto,
|
||||||
): Promise<TspProviderCorrectionSendResponseDto> {
|
): Promise<TspProviderCorrectionSendResponseDto> {
|
||||||
const mappedRequest = this.namaProviderUtils.mapToNamaOriginalRequestDto(payload)
|
const mappedRequest = this.namaProviderUtils.mapToNamaCorrectionDto(payload)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await this.httpClient.request(
|
const response = await this.httpClient.request(
|
||||||
this.buildSendUrl(),
|
this.buildCorrectionUrl(),
|
||||||
{
|
{
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: JSON.stringify(mappedRequest),
|
body: JSON.stringify(mappedRequest),
|
||||||
},
|
},
|
||||||
this.createRequestInterceptors(payload.token),
|
this.createRequestInterceptors(payload.token),
|
||||||
)
|
)
|
||||||
const providerResponse: NamaProviderOriginalResponseDto = await response.json()
|
const providerResponse: NamaProviderCorrectionResponseDto = await response.json()
|
||||||
this.logger.debug('NAMA provider response', providerResponse)
|
this.logger.debug('NAMA provider correction response', providerResponse)
|
||||||
|
|
||||||
const result: TspProviderOriginalResponseDto = {
|
const result: TspProviderCorrectionSendResponseDto = {
|
||||||
invoice_id: payload.id,
|
invoice_id: payload.id,
|
||||||
provider_request_payload: JSON.parse(JSON.stringify(mappedRequest)),
|
provider_request_payload: JSON.parse(JSON.stringify(mappedRequest)),
|
||||||
hasError: !response.ok,
|
hasError: !response.ok,
|
||||||
@@ -158,15 +163,14 @@ export class NamaProviderSwitchAdapter implements IProviderSwitchAdapter {
|
|||||||
|
|
||||||
return result
|
return result
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.logger.error('NAMA send failed', err)
|
this.logger.error('NAMA correction send failed', err)
|
||||||
const failure: TspProviderOriginalResponseDto = {
|
const failure: TspProviderCorrectionSendResponseDto = {
|
||||||
invoice_id: payload.id,
|
invoice_id: payload.id,
|
||||||
provider_request_payload: JSON.parse(JSON.stringify(mappedRequest)),
|
provider_request_payload: JSON.parse(JSON.stringify(mappedRequest)),
|
||||||
hasError: true,
|
hasError: true,
|
||||||
message: (err as Error).message,
|
message: (err as Error).message,
|
||||||
received_at: new Date().toISOString(),
|
received_at: new Date().toISOString(),
|
||||||
tax_id: null,
|
status: TspProviderResponseStatus.SEND_FAILURE,
|
||||||
status: TspProviderResponseStatus.NOT_SEND,
|
|
||||||
}
|
}
|
||||||
return failure
|
return failure
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import {
|
|||||||
PaymentInfoDto,
|
PaymentInfoDto,
|
||||||
TspProviderCorrectionSendPayloadDto,
|
TspProviderCorrectionSendPayloadDto,
|
||||||
TspProviderOriginalSendPayloadDto,
|
TspProviderOriginalSendPayloadDto,
|
||||||
TspProviderRevokePayloadDto
|
TspProviderRevokePayloadDto,
|
||||||
} from '../../dto'
|
} from '../../dto'
|
||||||
import {
|
import {
|
||||||
NamaProviderCorrectionRequestDto,
|
NamaProviderCorrectionRequestDto,
|
||||||
@@ -76,11 +76,8 @@ export class NamaProviderUtils {
|
|||||||
spro: '0',
|
spro: '0',
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('item.gold_type_payload', item.gold_type_payload);
|
|
||||||
|
|
||||||
|
|
||||||
if (item.gold_type_payload) {
|
if (item.gold_type_payload) {
|
||||||
const { profit='0', commission = '0', wages = "0" } = item.gold_type_payload
|
const { profit = '0', commission = '0', wages = '0' } = item.gold_type_payload
|
||||||
data = {
|
data = {
|
||||||
...data,
|
...data,
|
||||||
consfee: wages,
|
consfee: wages,
|
||||||
@@ -110,21 +107,39 @@ export class NamaProviderUtils {
|
|||||||
inno: payload.invoice_number.toString(),
|
inno: payload.invoice_number.toString(),
|
||||||
tins: '',
|
tins: '',
|
||||||
indatim: payload.invoice_date.getTime() + '',
|
indatim: payload.invoice_date.getTime() + '',
|
||||||
setm: '1',
|
irtaxid: payload.last_tax_id,
|
||||||
|
...this.mapSettlementBased(
|
||||||
|
payload.settlement_type,
|
||||||
|
payload.payments,
|
||||||
|
payload.total_amount,
|
||||||
|
),
|
||||||
...this.mapCustomerInfo(payload.customer),
|
...this.mapCustomerInfo(payload.customer),
|
||||||
},
|
},
|
||||||
body: payload.items.map(item => ({
|
body: payload.items.map(item => {
|
||||||
sstid: item.sku,
|
let data: NamaProviderOriginalBodyItemDto = {
|
||||||
vra: item.sku_vat,
|
sstid: item.sku,
|
||||||
// sstt: item.unit_type,
|
vra: item.sku_vat,
|
||||||
fee: String(item.unit_price),
|
fee: String(item.unit_price),
|
||||||
dis: String(item.discount_amount),
|
dis: String(item.discount_amount),
|
||||||
mu: item.measure_unit,
|
mu: item.measure_unit,
|
||||||
am: String(item.quantity),
|
am: String(item.quantity),
|
||||||
consfee: '0',
|
consfee: '0',
|
||||||
bros: '0',
|
bros: '0',
|
||||||
spro: '0',
|
spro: '0',
|
||||||
})),
|
}
|
||||||
|
|
||||||
|
if (item.gold_type_payload) {
|
||||||
|
const { profit = '0', commission = '0', wages = '0' } = item.gold_type_payload
|
||||||
|
data = {
|
||||||
|
...data,
|
||||||
|
consfee: wages,
|
||||||
|
bros: commission,
|
||||||
|
spro: profit,
|
||||||
|
tcpbs: (Number(profit) + Number(commission) + Number(wages)).toString(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return data
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
|
import { CustomerType } from '@/generated/prisma/enums'
|
||||||
import { SaleInvoiceTspAttemptsUpdateInput } from '@/generated/prisma/models'
|
import { SaleInvoiceTspAttemptsUpdateInput } from '@/generated/prisma/models'
|
||||||
import { PrismaService } from '@/prisma/prisma.service'
|
import { PrismaService } from '@/prisma/prisma.service'
|
||||||
import { BadRequestException, NotFoundException } from '@nestjs/common'
|
import { BadRequestException, NotFoundException } from '@nestjs/common'
|
||||||
import {
|
|
||||||
CustomerType,
|
|
||||||
} from '@/generated/prisma/enums'
|
|
||||||
import {
|
import {
|
||||||
Prisma,
|
Prisma,
|
||||||
TspProviderRequestType,
|
TspProviderRequestType,
|
||||||
@@ -172,7 +170,6 @@ export async function buildCorrectionPayload(
|
|||||||
invoice_date: true,
|
invoice_date: true,
|
||||||
invoice_number: true,
|
invoice_number: true,
|
||||||
settlement_type: true,
|
settlement_type: true,
|
||||||
tax_id: true,
|
|
||||||
discount_amount: true,
|
discount_amount: true,
|
||||||
tax_amount: true,
|
tax_amount: true,
|
||||||
items: true,
|
items: true,
|
||||||
@@ -226,16 +223,17 @@ export async function buildCorrectionPayload(
|
|||||||
legal: true,
|
legal: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
reference_invoice: {
|
|
||||||
select: {
|
|
||||||
tax_id: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
payments: {
|
payments: {
|
||||||
include: {
|
include: {
|
||||||
terminal_info: true,
|
terminal_info: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
reference_invoice: {
|
||||||
|
select: {
|
||||||
|
tax_id: true,
|
||||||
|
id: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -284,7 +282,9 @@ export async function buildCorrectionPayload(
|
|||||||
token: invoice.pos.complex.business_activity.partner_token,
|
token: invoice.pos.complex.business_activity.partner_token,
|
||||||
tsp_provider: partner.tsp_provider!,
|
tsp_provider: partner.tsp_provider!,
|
||||||
template: invoice.pos.complex.business_activity.guild.invoice_template,
|
template: invoice.pos.complex.business_activity.guild.invoice_template,
|
||||||
invoice_date: new Date(),
|
invoice_date: invoice?.invoice_date
|
||||||
|
? new Date(invoice.invoice_date)
|
||||||
|
: invoice.invoice_date,
|
||||||
settlement_type: invoice.settlement_type,
|
settlement_type: invoice.settlement_type,
|
||||||
|
|
||||||
customer:
|
customer:
|
||||||
@@ -305,11 +305,9 @@ export async function buildCorrectionPayload(
|
|||||||
first_name: invoice.customer.individual.first_name ?? undefined,
|
first_name: invoice.customer.individual.first_name ?? undefined,
|
||||||
last_name: invoice.customer.individual.last_name ?? undefined,
|
last_name: invoice.customer.individual.last_name ?? undefined,
|
||||||
national_id: invoice.customer.individual.national_id ?? undefined,
|
national_id: invoice.customer.individual.national_id ?? undefined,
|
||||||
mobile_number:
|
mobile_number: invoice.customer.individual.mobile_number ?? undefined,
|
||||||
invoice.customer.individual.mobile_number ?? undefined,
|
|
||||||
postal_code: invoice.customer.individual.postal_code ?? undefined,
|
postal_code: invoice.customer.individual.postal_code ?? undefined,
|
||||||
economic_code:
|
economic_code: invoice.customer.individual.economic_code ?? undefined,
|
||||||
invoice.customer.individual.economic_code ?? undefined,
|
|
||||||
}
|
}
|
||||||
: undefined,
|
: undefined,
|
||||||
}
|
}
|
||||||
@@ -487,11 +485,9 @@ export async function buildOriginalPayload(
|
|||||||
first_name: invoice.customer.individual.first_name ?? undefined,
|
first_name: invoice.customer.individual.first_name ?? undefined,
|
||||||
last_name: invoice.customer.individual.last_name ?? undefined,
|
last_name: invoice.customer.individual.last_name ?? undefined,
|
||||||
national_id: invoice.customer.individual.national_id ?? undefined,
|
national_id: invoice.customer.individual.national_id ?? undefined,
|
||||||
mobile_number:
|
mobile_number: invoice.customer.individual.mobile_number ?? undefined,
|
||||||
invoice.customer.individual.mobile_number ?? undefined,
|
|
||||||
postal_code: invoice.customer.individual.postal_code ?? undefined,
|
postal_code: invoice.customer.individual.postal_code ?? undefined,
|
||||||
economic_code:
|
economic_code: invoice.customer.individual.economic_code ?? undefined,
|
||||||
invoice.customer.individual.economic_code ?? undefined,
|
|
||||||
}
|
}
|
||||||
: undefined,
|
: undefined,
|
||||||
}
|
}
|
||||||
@@ -521,6 +517,62 @@ export async function buildOriginalPayload(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function getRelatedInvoiceForCorrection(
|
||||||
|
tx: Prisma.TransactionClient,
|
||||||
|
ref_invoice_id: string,
|
||||||
|
) {
|
||||||
|
const relatedInvoice = await getRelatedInvoiceForModification(tx, ref_invoice_id)
|
||||||
|
return relatedInvoice
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getRelatedInvoiceForModification(
|
||||||
|
tx: Prisma.TransactionClient,
|
||||||
|
ref_invoice_id: string,
|
||||||
|
) {
|
||||||
|
const relatedInvoice = await tx.salesInvoice.findUnique({
|
||||||
|
where: {
|
||||||
|
id: ref_invoice_id,
|
||||||
|
},
|
||||||
|
include: {
|
||||||
|
customer: {
|
||||||
|
select: {
|
||||||
|
type: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
payments: {
|
||||||
|
select: {},
|
||||||
|
},
|
||||||
|
tsp_attempts: {
|
||||||
|
orderBy: {
|
||||||
|
attempt_no: 'desc',
|
||||||
|
},
|
||||||
|
take: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!relatedInvoice) {
|
||||||
|
throw new NotFoundException('فاکتور مورد نظر یافت نشد.')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (relatedInvoice.type === TspProviderRequestType.REVOKE) {
|
||||||
|
throw new BadRequestException(
|
||||||
|
'فاکتور ارسالی قبلا ابطال شده است و امکان ویرایش آن وجود ندارد.',
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
!relatedInvoice.tax_id ||
|
||||||
|
relatedInvoice.tsp_attempts?.[0].status !== TspProviderResponseStatus.SUCCESS
|
||||||
|
) {
|
||||||
|
throw new BadRequestException(
|
||||||
|
'فاکتور قبلی همچنان در حال بررسی است و امکان اصلاح آن وجود ندارد.',
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return relatedInvoice
|
||||||
|
}
|
||||||
|
|
||||||
export async function trySend(
|
export async function trySend(
|
||||||
tspSwitchService: {
|
tspSwitchService: {
|
||||||
send(
|
send(
|
||||||
|
|||||||
Reference in New Issue
Block a user