Refactor code structure for improved readability and maintainability
This commit is contained in:
@@ -3,11 +3,10 @@ import { JwtService } from '@nestjs/jwt'
|
||||
import { AppController } from './application.controller'
|
||||
import { AppService } from './application.service'
|
||||
import { ApplicationAuthModule } from './auth/auth.module'
|
||||
import { ApplicationConfigModule } from './config/config.module'
|
||||
|
||||
@Module({
|
||||
controllers: [AppController],
|
||||
providers: [AppService, JwtService],
|
||||
imports: [ApplicationConfigModule, ApplicationAuthModule],
|
||||
imports: [ApplicationAuthModule],
|
||||
})
|
||||
export class ApplicationModule {}
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
import { Public } from '@/common/decorators/public.decorator'
|
||||
import { TokenAccount } from '@/common/decorators/tokenInfo.decorator'
|
||||
import { Body, Controller, Get, Param, Post } from '@nestjs/common'
|
||||
import { ConfigService } from './config.service'
|
||||
import { CreateConfigDto } from './dto/create-config.dto'
|
||||
|
||||
@Controller('app/config')
|
||||
export class ConfigController {
|
||||
constructor(private readonly configService: ConfigService) {}
|
||||
|
||||
@Get(':id')
|
||||
findOne(@Param('id') uuid: string) {
|
||||
return this.configService.findOne(uuid)
|
||||
}
|
||||
|
||||
@Post()
|
||||
@Public()
|
||||
create(@TokenAccount('userId') consumerId: string, @Body() data: CreateConfigDto) {
|
||||
return this.configService.create(consumerId, data)
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
import { Module } from '@nestjs/common'
|
||||
import { ConfigController } from './config.controller'
|
||||
import { ConfigService } from './config.service'
|
||||
|
||||
@Module({
|
||||
controllers: [ConfigController],
|
||||
providers: [ConfigService],
|
||||
})
|
||||
export class ApplicationConfigModule {}
|
||||
@@ -1,83 +0,0 @@
|
||||
import { QUERY_CONSTANTS } from '@/common/queryConstants'
|
||||
import { ConsumerDevicesSelect } from '@/generated/prisma/models'
|
||||
import { PrismaService } from '@/prisma/prisma.service'
|
||||
import { BadRequestException, Injectable } from '@nestjs/common'
|
||||
import { ResponseMapper } from 'common/response/response-mapper'
|
||||
import { CreateConfigDto } from './dto/create-config.dto'
|
||||
|
||||
@Injectable()
|
||||
export class ConfigService {
|
||||
constructor(private prisma: PrismaService) {}
|
||||
|
||||
private readonly defaultSelect: ConsumerDevicesSelect = {
|
||||
uuid: true,
|
||||
app_version: true,
|
||||
brand: true,
|
||||
browser_name: true,
|
||||
build_number: true,
|
||||
device: true,
|
||||
os_version: true,
|
||||
fcm_token: true,
|
||||
model: true,
|
||||
platform: true,
|
||||
release_number: true,
|
||||
sdk_version: true,
|
||||
consumer: {
|
||||
select: {
|
||||
id: true,
|
||||
...QUERY_CONSTANTS.CONSUMER.infoSelect,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
async findOne(uuid: string) {
|
||||
const config = await this.prisma.consumerDevices.findUnique({
|
||||
where: {
|
||||
uuid,
|
||||
},
|
||||
select: this.defaultSelect,
|
||||
})
|
||||
|
||||
return ResponseMapper.single(config)
|
||||
}
|
||||
|
||||
async create(consumer_id: string, data: CreateConfigDto) {
|
||||
const prevConfig = await this.prisma.consumerDevices.findUnique({
|
||||
where: {
|
||||
uuid: data.uuid,
|
||||
},
|
||||
select: {
|
||||
consumer_id: true,
|
||||
},
|
||||
})
|
||||
|
||||
if (prevConfig && consumer_id !== prevConfig.consumer_id) {
|
||||
throw new BadRequestException('این دستگاه با کاربری دیگری ثبت شده است.')
|
||||
}
|
||||
|
||||
const config = await this.prisma.consumerDevices.upsert({
|
||||
where: {
|
||||
uuid: data.uuid,
|
||||
},
|
||||
update: {
|
||||
...data,
|
||||
consumer: {
|
||||
connect: {
|
||||
id: consumer_id,
|
||||
},
|
||||
},
|
||||
},
|
||||
create: {
|
||||
...data,
|
||||
consumer: {
|
||||
connect: {
|
||||
id: consumer_id,
|
||||
},
|
||||
},
|
||||
},
|
||||
select: this.defaultSelect,
|
||||
})
|
||||
|
||||
return ResponseMapper.create(config)
|
||||
}
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
import type { ConfigService } from '../config.service'
|
||||
|
||||
export type ConfigServiceCreateResponseDto = Awaited<ReturnType<ConfigService['create']>>
|
||||
export type ConfigServiceFindOneResponseDto = Awaited<ReturnType<ConfigService['findOne']>>
|
||||
@@ -1,66 +0,0 @@
|
||||
import { ApplicationPlatform, ApplicationPublisher } from '@/generated/prisma/enums'
|
||||
import { ApiProperty, PartialType } from '@nestjs/swagger'
|
||||
import { IsEnum, IsOptional, IsString } from 'class-validator'
|
||||
|
||||
export class CreateConfigDto {
|
||||
@ApiProperty({ required: true })
|
||||
@IsString()
|
||||
uuid: string
|
||||
|
||||
@ApiProperty({ required: true })
|
||||
@IsEnum(ApplicationPublisher)
|
||||
publisher: ApplicationPublisher
|
||||
|
||||
@ApiProperty({ required: true })
|
||||
@IsString()
|
||||
app_version: string
|
||||
|
||||
@ApiProperty({ required: true })
|
||||
@IsString()
|
||||
build_number: string
|
||||
|
||||
@ApiProperty({ required: true })
|
||||
@IsEnum(ApplicationPlatform)
|
||||
platform: ApplicationPlatform
|
||||
|
||||
@ApiProperty({ required: true })
|
||||
@IsString()
|
||||
brand: string
|
||||
|
||||
@ApiProperty({ required: true })
|
||||
@IsString()
|
||||
model: string
|
||||
|
||||
@ApiProperty({ required: true })
|
||||
@IsString()
|
||||
device: string
|
||||
|
||||
@ApiProperty({ required: true })
|
||||
@IsString()
|
||||
os_version: string
|
||||
|
||||
@ApiProperty({ required: true })
|
||||
@IsString()
|
||||
sdk_version: string
|
||||
|
||||
@ApiProperty({ required: true })
|
||||
@IsString()
|
||||
release_number: string
|
||||
|
||||
@ApiProperty({ required: false })
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
browser_name: string
|
||||
|
||||
@ApiProperty({ required: false })
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
user_agent: string
|
||||
|
||||
@ApiProperty({ required: false })
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
fcm_token?: string
|
||||
}
|
||||
|
||||
export class UpdateConfigDto extends PartialType(CreateConfigDto) {}
|
||||
@@ -12,29 +12,33 @@ export class AuthService {
|
||||
private authUtils: AuthUtils,
|
||||
) {}
|
||||
|
||||
async login(dto: LoginDto, isPos = false) {
|
||||
async login(dto: LoginDto, isPos = false, deviceId?: string) {
|
||||
const { username, password } = dto
|
||||
|
||||
const account = await this.prisma.account.findUnique({
|
||||
where: {
|
||||
username,
|
||||
},
|
||||
})
|
||||
|
||||
if (!account) {
|
||||
throw new NotFoundException('اطلاعات ورودی شما اشتباه است')
|
||||
}
|
||||
|
||||
if (isPos) {
|
||||
const posAccount = await this.prisma.consumerAccount.findUnique({
|
||||
const account = await this.prisma.$transaction(async tx => {
|
||||
const account = await tx.account.findUnique({
|
||||
where: {
|
||||
account_id: account.id,
|
||||
username,
|
||||
},
|
||||
})
|
||||
if (!posAccount) {
|
||||
|
||||
if (!account) {
|
||||
throw new NotFoundException('اطلاعات ورودی شما اشتباه است')
|
||||
}
|
||||
}
|
||||
|
||||
if (isPos) {
|
||||
const posAccount = await tx.consumerAccount.findUnique({
|
||||
where: {
|
||||
account_id: account.id,
|
||||
},
|
||||
})
|
||||
if (!posAccount) {
|
||||
throw new NotFoundException('اطلاعات ورودی شما اشتباه است')
|
||||
}
|
||||
}
|
||||
|
||||
return account
|
||||
})
|
||||
|
||||
await this.authUtils.checkAuthPassword(password, account.password)
|
||||
|
||||
|
||||
@@ -39,6 +39,11 @@ export class SalesInvoicesController {
|
||||
return this.salesInvoicesService.send(id, posInfo)
|
||||
}
|
||||
|
||||
@Post(':id/retry')
|
||||
retry(@Param('id') id: string, @PosInfo() posInfo: IPosPayload) {
|
||||
return this.salesInvoicesService.retry(id, posInfo)
|
||||
}
|
||||
|
||||
@Post(':id/revoke')
|
||||
revoke(@Param('id') id: string, @PosInfo() posInfo: IPosPayload) {
|
||||
return this.salesInvoicesService.revoke(id, posInfo)
|
||||
|
||||
@@ -253,6 +253,19 @@ export class SalesInvoicesService {
|
||||
}
|
||||
|
||||
async send(invoiceId: string, posInfo: IPosPayload) {
|
||||
await this.checkAccessToInvoice(posInfo.consumer_account_id, posInfo.pos_id)
|
||||
|
||||
const invoice = await this.salesInvoiceTaxService.originalSend(
|
||||
posInfo.pos_id,
|
||||
invoiceId,
|
||||
)
|
||||
|
||||
return ResponseMapper.single(invoice)
|
||||
}
|
||||
|
||||
async retry(invoiceId: string, posInfo: IPosPayload) {
|
||||
await this.checkAccessToInvoice(posInfo.consumer_account_id, posInfo.pos_id)
|
||||
|
||||
const invoice = await this.salesInvoiceTaxService.originalSend(
|
||||
posInfo.pos_id,
|
||||
invoiceId,
|
||||
|
||||
@@ -33,6 +33,52 @@ export class SalesInvoiceTspService {
|
||||
private sharedSaleInvoiceCreateService: SharedSaleInvoiceCreateService,
|
||||
) {}
|
||||
|
||||
private mapProviderError(error: any) {
|
||||
const isProviderFailureObject =
|
||||
error &&
|
||||
typeof error === 'object' &&
|
||||
('provider_request_payload' in error ||
|
||||
'provider_response_payload' in error ||
|
||||
'sent_at' in error ||
|
||||
'received_at' in error)
|
||||
|
||||
if (isProviderFailureObject) {
|
||||
return {
|
||||
hasError: true,
|
||||
status: error.status || TspProviderResponseStatus.FAILURE,
|
||||
message:
|
||||
error.message?.toString() ||
|
||||
'خطا در ارتباط با سامانه مالیاتی. لطفا مجددا تلاش کنید.',
|
||||
provider_request_payload: error.provider_request_payload,
|
||||
provider_response_payload: error.provider_response_payload,
|
||||
sent_at: error.sent_at || new Date().toISOString(),
|
||||
received_at: error.received_at || new Date().toISOString(),
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
hasError: true,
|
||||
status: TspProviderResponseStatus.FAILURE,
|
||||
message:
|
||||
error?.message?.toString() ||
|
||||
'خطا در ارتباط با سامانه مالیاتی. لطفا مجددا تلاش کنید.',
|
||||
provider_response_payload: {
|
||||
error: error?.message || 'fetch failed',
|
||||
cause: error?.cause || null,
|
||||
},
|
||||
sent_at: new Date().toISOString(),
|
||||
received_at: new Date().toISOString(),
|
||||
}
|
||||
}
|
||||
|
||||
private async runProviderCall(fn: () => Promise<any>) {
|
||||
try {
|
||||
return await fn()
|
||||
} catch (error: any) {
|
||||
return this.mapProviderError(error)
|
||||
}
|
||||
}
|
||||
|
||||
async originalSend(
|
||||
posId: string,
|
||||
invoice_id: string,
|
||||
@@ -40,6 +86,7 @@ export class SalesInvoiceTspService {
|
||||
const payload = await buildPayload(this.prisma, invoice_id, posId)
|
||||
|
||||
const attemptNumber = await getOriginalResendAttemptNumber(this.prisma, invoice_id)
|
||||
console.log('attemptNumber', attemptNumber)
|
||||
|
||||
const attempt = await this.prisma.saleInvoiceTspAttempts.create({
|
||||
data: {
|
||||
@@ -51,7 +98,15 @@ export class SalesInvoiceTspService {
|
||||
},
|
||||
})
|
||||
|
||||
const result = await trySend(this.tspSwitchService, payload)
|
||||
const result = await this.runProviderCall(() =>
|
||||
trySend(this.tspSwitchService, payload),
|
||||
)
|
||||
if (result?.hasError) {
|
||||
result.provider_request_payload =
|
||||
result.provider_request_payload || JSON.parse(JSON.stringify(payload))
|
||||
result.sent_at = result.sent_at || new Date().toISOString()
|
||||
result.received_at = result.received_at || new Date().toISOString()
|
||||
}
|
||||
|
||||
return await onResult(this.prisma, result, attempt.id)
|
||||
}
|
||||
@@ -260,7 +315,16 @@ export class SalesInvoiceTspService {
|
||||
},
|
||||
)
|
||||
|
||||
const result = await trySend(this.tspSwitchService, correctionPayload)
|
||||
const result = await this.runProviderCall(() =>
|
||||
trySend(this.tspSwitchService, correctionPayload),
|
||||
)
|
||||
if (result?.hasError) {
|
||||
result.provider_request_payload =
|
||||
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()
|
||||
}
|
||||
|
||||
console.log('sendResult')
|
||||
console.log(result)
|
||||
@@ -447,7 +511,15 @@ export class SalesInvoiceTspService {
|
||||
},
|
||||
)
|
||||
|
||||
const result = await this.tspSwitchService.revoke(revokePayload)
|
||||
const result = await this.runProviderCall(() =>
|
||||
this.tspSwitchService.revoke(revokePayload),
|
||||
)
|
||||
if (result?.hasError) {
|
||||
result.provider_request_payload =
|
||||
result.provider_request_payload || JSON.parse(JSON.stringify(revokePayload))
|
||||
result.sent_at = result.sent_at || new Date().toISOString()
|
||||
result.received_at = result.received_at || new Date().toISOString()
|
||||
}
|
||||
|
||||
return await onResult(this.prisma, result, attempt.id)
|
||||
}
|
||||
|
||||
@@ -120,7 +120,7 @@ export class NamaProviderSwitchAdapter implements IProviderSwitchAdapter {
|
||||
tax_id: null,
|
||||
status: TspProviderResponseStatus.NOT_SEND,
|
||||
}
|
||||
return failure
|
||||
throw failure
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -31,6 +31,9 @@ export async function getOriginalResendAttemptNumber(
|
||||
},
|
||||
},
|
||||
},
|
||||
orderBy: {
|
||||
created_at: 'desc',
|
||||
},
|
||||
})
|
||||
|
||||
if (existingAttempt) {
|
||||
@@ -464,6 +467,8 @@ export async function onResult(
|
||||
provider_request_payload: result.provider_request_payload,
|
||||
provider_response_payload: JSON.parse(JSON.stringify(result)),
|
||||
status: result.status,
|
||||
sent_at: result.sent_at || new Date().toISOString(),
|
||||
received_at: result.received_at || new Date().toISOString(),
|
||||
message: result.message?.toString() || 'وجود مشکل در ارسال به سامانه مالیاتی',
|
||||
},
|
||||
select: {
|
||||
@@ -507,7 +512,27 @@ export async function onResult(
|
||||
}
|
||||
}
|
||||
|
||||
throw new NotFoundException(
|
||||
'متاسفانه امکان ارسال فاکتور به سیستم مالیاتی در حال حاضر وجود ندارد. لطفا بعدا تلاش کنید.',
|
||||
)
|
||||
const updatedAttempt = await prisma.saleInvoiceTspAttempts.update({
|
||||
where: {
|
||||
id: attempt_id,
|
||||
},
|
||||
data: {
|
||||
provider_response_payload: {},
|
||||
status: TspProviderResponseStatus.FAILURE,
|
||||
message:
|
||||
'متاسفانه امکان ارسال فاکتور به سیستم مالیاتی در حال حاضر وجود ندارد. لطفا بعدا تلاش کنید.',
|
||||
received_at: new Date().toISOString(),
|
||||
},
|
||||
select: {
|
||||
status: true,
|
||||
invoice: true,
|
||||
message: true,
|
||||
},
|
||||
})
|
||||
|
||||
return {
|
||||
invoice: updatedAttempt.invoice,
|
||||
status: updatedAttempt.status,
|
||||
message: updatedAttempt.message,
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user