feat: enhance business activities and sale invoices handling with new query constants and pagination support
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
export enum GoldKarat {
|
||||
KARAT_18 = '18',
|
||||
KARAT_21 = '21',
|
||||
KARAT_24 = '24',
|
||||
KARAT_18 = 'KARAT_18',
|
||||
KARAT_21 = 'KARAT_21',
|
||||
KARAT_24 = 'KARAT_24',
|
||||
}
|
||||
|
||||
export enum TspProviderRequestType {
|
||||
@@ -16,16 +16,16 @@ export enum SKUGuildType {
|
||||
}
|
||||
|
||||
export const UploadedFileTypes = {
|
||||
GOOD: 'good',
|
||||
SERVICE: 'service',
|
||||
PROFILE_AVATAR: 'profile_avatar',
|
||||
PARTNER_LOGO: 'partner_logo',
|
||||
GOOD: 'GOOD',
|
||||
SERVICE: 'SERVICE',
|
||||
PROFILE_AVATAR: 'PROFILE_AVATAR',
|
||||
PARTNER_LOGO: 'PARTNER_LOGO',
|
||||
}
|
||||
export type UploadedFileTypes = (typeof UploadedFileTypes)[keyof typeof UploadedFileTypes]
|
||||
|
||||
export const TspProviderCustomerType = {
|
||||
UNKNOWN: 'Unknown',
|
||||
KNOWN: 'Known',
|
||||
UNKNOWN: 'UNKNOWN',
|
||||
KNOWN: 'KNOWN',
|
||||
}
|
||||
|
||||
export type TspProviderCustomerType =
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
import { BusinessActivitySelect } from '@/generated/prisma/models'
|
||||
|
||||
export const summarySelect: BusinessActivitySelect = {
|
||||
id: true,
|
||||
name: true,
|
||||
economic_code: true,
|
||||
created_at: true,
|
||||
fiscal_id: true,
|
||||
invoice_number_sequence: true,
|
||||
partner_token: true,
|
||||
guild: {
|
||||
select: {
|
||||
id: true,
|
||||
code: true,
|
||||
name: true,
|
||||
},
|
||||
},
|
||||
license_activation: {
|
||||
select: {
|
||||
id: true,
|
||||
starts_at: true,
|
||||
expires_at: true,
|
||||
license: {
|
||||
select: {
|
||||
activation: {
|
||||
select: {
|
||||
_count: {
|
||||
select: {
|
||||
account_allocations: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export const select: BusinessActivitySelect = {
|
||||
...summarySelect,
|
||||
}
|
||||
|
||||
export const mappedData = (businessActivity: any) => {
|
||||
const { license_activation, ...rest } = businessActivity
|
||||
const { license, ...license_activation_rest } = license_activation
|
||||
const { _count } = license.activation
|
||||
|
||||
return {
|
||||
...rest,
|
||||
license_info: {
|
||||
...license_activation_rest,
|
||||
accounts_limit: _count.account_allocations,
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
import * as BUSINESS_ACTIVITIES from './businessActivities'
|
||||
import * as CONSUMER from './consumer'
|
||||
import * as LICENSE_ACTIVATION from './licenseActivation'
|
||||
import * as POS from './pos'
|
||||
@@ -8,4 +9,5 @@ export const QUERY_CONSTANTS = {
|
||||
CONSUMER,
|
||||
LICENSE_ACTIVATION,
|
||||
SALE_INVOICE,
|
||||
BUSINESS_ACTIVITIES,
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { QUERY_CONSTANTS } from '@/common/queryConstants'
|
||||
import { BusinessActivitySelect } from '@/generated/prisma/models'
|
||||
import { PrismaService } from '@/prisma/prisma.service'
|
||||
import { Injectable } from '@nestjs/common'
|
||||
@@ -7,45 +8,35 @@ export class BusinessActivitiesQueryService {
|
||||
constructor(private readonly prisma: PrismaService) {}
|
||||
|
||||
readonly baseSelect: BusinessActivitySelect = {
|
||||
id: true,
|
||||
name: true,
|
||||
economic_code: true,
|
||||
created_at: true,
|
||||
partner_token: true,
|
||||
fiscal_id: true,
|
||||
guild: {
|
||||
select: {
|
||||
id: true,
|
||||
code: true,
|
||||
name: true,
|
||||
},
|
||||
},
|
||||
...QUERY_CONSTANTS.BUSINESS_ACTIVITIES.summarySelect,
|
||||
}
|
||||
|
||||
findAllByConsumer(consumer_id: string, select: BusinessActivitySelect) {
|
||||
return this.prisma.businessActivity.findMany({
|
||||
async findAllByConsumer(consumer_id: string, select: BusinessActivitySelect) {
|
||||
const businessActivities = await this.prisma.businessActivity.findMany({
|
||||
where: { consumer_id },
|
||||
select,
|
||||
})
|
||||
return businessActivities.map(QUERY_CONSTANTS.BUSINESS_ACTIVITIES.mappedData)
|
||||
}
|
||||
|
||||
findOneByConsumer(
|
||||
async findOneByConsumer(
|
||||
consumer_id: string,
|
||||
id: string,
|
||||
select: BusinessActivitySelect,
|
||||
orThrow = false,
|
||||
) {
|
||||
if (orThrow) {
|
||||
return this.prisma.businessActivity.findUniqueOrThrow({
|
||||
where: { consumer_id, id },
|
||||
select,
|
||||
})
|
||||
}
|
||||
// if (orThrow) {
|
||||
// return await this.prisma.businessActivity.findUniqueOrThrow({
|
||||
// where: { consumer_id, id },
|
||||
// select,
|
||||
// })
|
||||
// }
|
||||
|
||||
return this.prisma.businessActivity.findUnique({
|
||||
const businessActivity = await this.prisma.businessActivity.findUnique({
|
||||
where: { consumer_id, id },
|
||||
select,
|
||||
})
|
||||
|
||||
return QUERY_CONSTANTS.BUSINESS_ACTIVITIES.mappedData(businessActivity)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -151,7 +151,7 @@ export class SharedSaleInvoiceCreateService {
|
||||
const terminalInfo = rawPayments.terminals as TerminalPaymentInfo | undefined
|
||||
|
||||
const payments: NormalizedPayment[] = Object.entries(rawPayments)
|
||||
.filter(([key]) => key !== 'terminals')
|
||||
.filter(([key, value]) => key !== 'terminals' && value && Number(value) > 0)
|
||||
.map(([key, value]) => ({
|
||||
method: paymentMethodMap[key.toLowerCase()],
|
||||
amount: typeof value === 'number' ? value : Number(value || 0),
|
||||
|
||||
@@ -12,6 +12,8 @@ export function translateEnumValue(
|
||||
enumKey: keyof typeof translates.enums,
|
||||
value: string | null | undefined,
|
||||
): EnumTranslatedValue {
|
||||
console.log(enumKey, value)
|
||||
|
||||
const enumsRegistry = translates.enums as EnumsRegistry
|
||||
const enumMap = enumsRegistry[String(enumKey)]
|
||||
|
||||
|
||||
+10
@@ -63,6 +63,9 @@ async function bootstrap() {
|
||||
.map(s => s.trim())
|
||||
.filter(Boolean)
|
||||
: []
|
||||
|
||||
console.log('envOrigins', envOrigins)
|
||||
|
||||
const allowedOrigins = (envOrigins.length ? envOrigins : defaultOrigins).filter(Boolean)
|
||||
|
||||
const isOriginAllowed = (origin: string) => {
|
||||
@@ -74,6 +77,9 @@ async function bootstrap() {
|
||||
const rootDomain = pattern.slice(2)
|
||||
return hostname === rootDomain || hostname.endsWith(`.${rootDomain}`)
|
||||
}
|
||||
console.log('origin', origin, 'pattern', pattern, 'hostname', hostname)
|
||||
console.log(hostname === pattern || origin === pattern)
|
||||
|
||||
return hostname === pattern || origin === pattern
|
||||
})
|
||||
} catch {
|
||||
@@ -84,14 +90,18 @@ async function bootstrap() {
|
||||
app.enableCors({
|
||||
origin: (origin, callback) => {
|
||||
if (!origin) {
|
||||
console.log('1')
|
||||
callback(null, true)
|
||||
return
|
||||
}
|
||||
|
||||
if (isOriginAllowed(origin)) {
|
||||
console.log('2')
|
||||
|
||||
callback(null, true)
|
||||
return
|
||||
}
|
||||
console.log('3')
|
||||
|
||||
callback(new Error('Not allowed by CORS'), false)
|
||||
},
|
||||
|
||||
@@ -23,12 +23,14 @@ export class GoodsService {
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
code: true,
|
||||
},
|
||||
},
|
||||
measure_unit: {
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
code: true,
|
||||
},
|
||||
},
|
||||
category: {
|
||||
|
||||
@@ -59,6 +59,8 @@ export class AuthService {
|
||||
include: accountInclude,
|
||||
})
|
||||
|
||||
console.log('account', account)
|
||||
|
||||
if (!account) {
|
||||
throw new NotFoundException('اطلاعات ورودی شما اشتباه است')
|
||||
}
|
||||
|
||||
@@ -71,7 +71,6 @@ export class BusinessActivitiesService {
|
||||
consumer_id,
|
||||
id,
|
||||
this.defaultSelect,
|
||||
true,
|
||||
)
|
||||
return ResponseMapper.single(this.prepareBusinessActivityResponse(businessActivity))
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
import { ApiPropertyOptional } from '@nestjs/swagger'
|
||||
import { Type } from 'class-transformer'
|
||||
import { IsOptional, Max, Min } from 'class-validator'
|
||||
|
||||
export class ConsumerSaleInvoicesFilterDto {
|
||||
@ApiPropertyOptional({ type: Number, example: 1 })
|
||||
@Type(() => Number)
|
||||
@Min(1)
|
||||
@IsOptional()
|
||||
page?: number
|
||||
|
||||
@ApiPropertyOptional({ type: Number, example: 10, description: 'Max value is 50.' })
|
||||
@Type(() => Number)
|
||||
@Min(1)
|
||||
@Max(50)
|
||||
@IsOptional()
|
||||
perPage?: number
|
||||
}
|
||||
@@ -1,8 +1,9 @@
|
||||
import { PosInfo } from '@/common/decorators/posInfo.decorator'
|
||||
import { TokenAccount } from '@/common/decorators/tokenInfo.decorator'
|
||||
import type { IPosPayload } from '@/common/models'
|
||||
import { Body, Controller, Get, Param, Post } from '@nestjs/common'
|
||||
import { Body, Controller, Get, Param, Post, Query } from '@nestjs/common'
|
||||
import { ApiTags } from '@nestjs/swagger'
|
||||
import { ConsumerSaleInvoicesFilterDto } from './dto/saleInvoices-filter.dto'
|
||||
import type {
|
||||
SaleInvoicesServiceFindAllResponseDto,
|
||||
SaleInvoicesServiceFindOneResponseDto,
|
||||
@@ -18,8 +19,15 @@ export class StatisticsController {
|
||||
@Get('')
|
||||
async findAll(
|
||||
@TokenAccount('userId') consumerId: string,
|
||||
@Query('page') page = '1',
|
||||
@Query('perPage') perPage = '10',
|
||||
): Promise<SaleInvoicesServiceFindAllResponseDto> {
|
||||
return this.service.findAll(consumerId)
|
||||
const filter: ConsumerSaleInvoicesFilterDto = {
|
||||
page: Number(page) || 1,
|
||||
perPage: Number(perPage) || 10,
|
||||
}
|
||||
|
||||
return this.service.findAll(consumerId, filter)
|
||||
}
|
||||
|
||||
@Get(':id')
|
||||
|
||||
@@ -12,6 +12,7 @@ import { PrismaService } from '@/prisma/prisma.service'
|
||||
import { BadRequestException, Injectable, NotFoundException } from '@nestjs/common'
|
||||
import { ResponseMapper } from 'common/response/response-mapper'
|
||||
import { SalesInvoiceTspService } from '../../tspProviders/sales-invoice-tsp.service'
|
||||
import { ConsumerSaleInvoicesFilterDto } from './dto/saleInvoices-filter.dto'
|
||||
|
||||
@Injectable()
|
||||
export class SaleInvoicesService {
|
||||
@@ -21,6 +22,9 @@ export class SaleInvoicesService {
|
||||
private sharedSaleInvoiceActionsService: SharedSaleInvoiceActionsService,
|
||||
) {}
|
||||
|
||||
private readonly defaultPerPage = 10
|
||||
private readonly maxPerPage = 50
|
||||
|
||||
private readonly defaultSelect: SalesInvoiceSelect = {
|
||||
pos: {
|
||||
select: {
|
||||
@@ -54,27 +58,45 @@ export class SaleInvoicesService {
|
||||
}
|
||||
}
|
||||
|
||||
async findAll(consumer_id: string, page = 1, perPage = 10) {
|
||||
async findAll(consumer_id: string, filter: ConsumerSaleInvoicesFilterDto) {
|
||||
const invoicesWhere: SalesInvoiceWhereInput = {
|
||||
consumer_account: {
|
||||
consumer_id,
|
||||
},
|
||||
}
|
||||
const normalizedPageValue = Number(filter.page ?? 1)
|
||||
const normalizedPage = Number.isFinite(normalizedPageValue)
|
||||
? Math.max(1, Math.floor(normalizedPageValue))
|
||||
: 1
|
||||
|
||||
const requestedPerPageValue = Number(filter.perPage ?? this.defaultPerPage)
|
||||
const requestedPerPage = Number.isFinite(requestedPerPageValue)
|
||||
? Math.max(1, Math.floor(requestedPerPageValue))
|
||||
: this.defaultPerPage
|
||||
const normalizedPerPage = Math.min(requestedPerPage, this.maxPerPage)
|
||||
|
||||
const [invoices, total] = await this.prisma.$transaction(async tx => [
|
||||
await tx.salesInvoice.findMany({
|
||||
where: invoicesWhere,
|
||||
orderBy: {
|
||||
created_at: 'desc',
|
||||
},
|
||||
skip: (normalizedPage - 1) * normalizedPerPage,
|
||||
take: normalizedPerPage,
|
||||
select: {
|
||||
...QUERY_CONSTANTS.SALE_INVOICE.summarySelect,
|
||||
...this.defaultSelect,
|
||||
},
|
||||
skip: (page - 1) * perPage,
|
||||
take: perPage,
|
||||
}),
|
||||
await tx.salesInvoice.count({ where: invoicesWhere }),
|
||||
])
|
||||
|
||||
const mappedInvoices = invoices.map(this.invoiceMapper)
|
||||
return ResponseMapper.paginate(mappedInvoices, { page, perPage, total })
|
||||
return ResponseMapper.paginate(mappedInvoices, {
|
||||
page: normalizedPage,
|
||||
perPage: normalizedPerPage,
|
||||
total,
|
||||
})
|
||||
}
|
||||
|
||||
async findOne(consumer_id: string, id: string) {
|
||||
|
||||
@@ -18,6 +18,7 @@ export class GoodsService {
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
code: true,
|
||||
},
|
||||
},
|
||||
local_sku: true,
|
||||
|
||||
Reference in New Issue
Block a user