diff --git a/src/common/guards/auth-pos.guard.ts b/src/common/guards/auth-pos.guard.ts index 62d0045..92be1ad 100644 --- a/src/common/guards/auth-pos.guard.ts +++ b/src/common/guards/auth-pos.guard.ts @@ -23,12 +23,22 @@ export class PosGuard { const { posId } = cookie if (!posId) { - throw new ForbiddenException('شما دسترسی لازم را ندارید.') + return false + // throw new ForbiddenException('شما دسترسی لازم را ندارید.') } const checkLicenseActivation = await this.prisma.licenseAccountAllocation.findFirst({ where: { - account_id: tokenPayload.account_id, + OR: [ + { + account_id: tokenPayload.account_id, + }, + { + account: { + consumer_id: tokenPayload.user?.id, + }, + }, + ], license_activation: { OR: [ { diff --git a/src/common/interceptors/response-mapping.interceptor.ts b/src/common/interceptors/response-mapping.interceptor.ts index 521a1f3..519ca17 100644 --- a/src/common/interceptors/response-mapping.interceptor.ts +++ b/src/common/interceptors/response-mapping.interceptor.ts @@ -84,6 +84,9 @@ export class ResponseMappingInterceptor implements NestInterceptor { // } break case 'paginate': { + const { items: a, ...rest } = wrapped + console.log(rest) + const items = Array.isArray(wrapped.items) ? wrapped.items : [] const total = typeof wrapped.total === 'number' ? wrapped.total : items.length diff --git a/src/common/response/response-mapper.ts b/src/common/response/response-mapper.ts index ea05bbe..6ddd692 100644 --- a/src/common/response/response-mapper.ts +++ b/src/common/response/response-mapper.ts @@ -12,9 +12,9 @@ export type MapperWrapper = | { __mapped: 'delete' } interface IPaginateMeta { - count: number + total: number page?: number - pageSize?: number + perPage?: number } export const ResponseMapper = { @@ -38,12 +38,12 @@ export const ResponseMapper = { return { __mapped: 'list', items } }, - paginate(items: T[], { count, page = 1, pageSize: perPage }: IPaginateMeta) { - return { __mapped: 'paginate', items, count, page, perPage } + paginate(items: T[], { total, page = 1, perPage }: IPaginateMeta) { + return { __mapped: 'paginate', items, total, page, perPage } }, - sequelizePaginate(rows: T[], count: number, page = 1, pageSize = rows.length) { - return { __mapped: 'sequelize', rows, count, page, pageSize } + sequelizePaginate(rows: T[], total: number, page = 1, pageSize = rows.length) { + return { __mapped: 'sequelize', rows, total, page, pageSize } }, } diff --git a/src/modules/admin/consumers/consumers.service.ts b/src/modules/admin/consumers/consumers.service.ts index 84ec968..885d3ba 100644 --- a/src/modules/admin/consumers/consumers.service.ts +++ b/src/modules/admin/consumers/consumers.service.ts @@ -46,14 +46,14 @@ export class AdminConsumersService { } async findAll() { - const [consumers, count] = await this.prisma.$transaction([ + const [consumers, total] = await this.prisma.$transaction([ this.prisma.consumer.findMany({ select: this.defaultSelect, }), this.prisma.consumer.count(), ]) - return ResponseMapper.paginate(consumers.map(mapConsumerWithLicenseUtil), { count }) + return ResponseMapper.paginate(consumers.map(mapConsumerWithLicenseUtil), { total }) } async findOne(id: string) { diff --git a/src/modules/admin/devices/devices.service.ts b/src/modules/admin/devices/devices.service.ts index 955adb8..3cbe331 100644 --- a/src/modules/admin/devices/devices.service.ts +++ b/src/modules/admin/devices/devices.service.ts @@ -7,16 +7,16 @@ import { CreateDeviceDto, UpdateDeviceDto } from './dto/device.dto' export class DevicesService { constructor(private readonly prisma: PrismaService) {} - async findAll(page = 1, pageSize = 10) { - const [items, count] = await this.prisma.$transaction([ + async findAll(page = 1, perPage = 10) { + const [items, total] = await this.prisma.$transaction([ this.prisma.device.findMany({ - skip: (page - 1) * pageSize, - take: pageSize, + skip: (page - 1) * perPage, + take: perPage, include: { brand: true }, }), this.prisma.device.count(), ]) - return ResponseMapper.paginate(items, { count, page, pageSize }) + return ResponseMapper.paginate(items, { total, page, perPage }) } async findOne(id: string) { diff --git a/src/modules/admin/guilds/goods/goods.service.ts b/src/modules/admin/guilds/goods/goods.service.ts index 4bfdd4e..8fb0e65 100644 --- a/src/modules/admin/guilds/goods/goods.service.ts +++ b/src/modules/admin/guilds/goods/goods.service.ts @@ -37,7 +37,7 @@ export class GoodsService { }) async findAll(guildId: string) { - const [goods, count] = await this.prisma.$transaction([ + const [goods, total] = await this.prisma.$transaction([ this.prisma.good.findMany({ where: this.defaultWhere(guildId), select: this.defaultSelect, @@ -45,7 +45,7 @@ export class GoodsService { this.prisma.good.count(), ]) return ResponseMapper.paginate(goods, { - count, + total, }) } diff --git a/src/modules/admin/guilds/guilds.service.ts b/src/modules/admin/guilds/guilds.service.ts index 3d4e2a7..ae76a66 100644 --- a/src/modules/admin/guilds/guilds.service.ts +++ b/src/modules/admin/guilds/guilds.service.ts @@ -9,7 +9,7 @@ export class GuildsService { constructor(private prisma: PrismaService) {} async findAll() { - const [guilds, count] = await this.prisma.$transaction([ + const [guilds, total] = await this.prisma.$transaction([ this.prisma.guild.findMany({ include: { _count: { @@ -30,7 +30,7 @@ export class GuildsService { businessActivitiesCount: guild._count.business_activities, } }), - { count }, + { total }, ) } diff --git a/src/modules/admin/licenses/licenses.service.ts b/src/modules/admin/licenses/licenses.service.ts index 3f5147d..1eaba6e 100644 --- a/src/modules/admin/licenses/licenses.service.ts +++ b/src/modules/admin/licenses/licenses.service.ts @@ -48,20 +48,20 @@ export class PartnerLicensesService { created_at: true, } - async findAll(page = 1, pageSize = 10) { - const [licenses, count] = await this.prisma.$transaction([ + async findAll(page = 1, perPage = 10) { + const [licenses, total] = await this.prisma.$transaction([ this.prisma.licenseActivation.findMany({ select: this.licenseDefaultSelect, - skip: (page - 1) * pageSize, - take: pageSize, + skip: (page - 1) * perPage, + take: perPage, }), this.prisma.licenseActivation.count(), ]) return ResponseMapper.paginate(licenses, { - count, + total, page, - pageSize, + perPage, }) } diff --git a/src/modules/admin/partners/activatedLicenses/activatedLicenses.service.ts b/src/modules/admin/partners/activatedLicenses/activatedLicenses.service.ts index 86bd81a..47114ba 100644 --- a/src/modules/admin/partners/activatedLicenses/activatedLicenses.service.ts +++ b/src/modules/admin/partners/activatedLicenses/activatedLicenses.service.ts @@ -7,7 +7,7 @@ import { ResponseMapper } from 'common/response/response-mapper' export class PartnerActivatedLicensesService { constructor(private readonly prisma: PrismaService) {} - async findAll(partner_id: string, page = 1, pageSize = 10) { + async findAll(partner_id: string, page = 1, perPage = 10) { const defaultWhere: LicenseActivationWhereInput = { license: { charge_transaction: { @@ -15,11 +15,11 @@ export class PartnerActivatedLicensesService { }, }, } - const [licenses, count] = await this.prisma.$transaction(async tx => [ + const [licenses, total] = await this.prisma.$transaction(async tx => [ await tx.licenseActivation.findMany({ where: defaultWhere, - skip: (page - 1) * pageSize, - take: pageSize, + skip: (page - 1) * perPage, + take: perPage, select: { id: true, starts_at: true, @@ -71,8 +71,8 @@ export class PartnerActivatedLicensesService { return ResponseMapper.paginate(mappedLicenses, { page, - pageSize, - count, + perPage, + total, }) } diff --git a/src/modules/admin/partners/allocatedAccounts/allocatedAccounts.service.ts b/src/modules/admin/partners/allocatedAccounts/allocatedAccounts.service.ts index b5b4cfb..9cb0b57 100644 --- a/src/modules/admin/partners/allocatedAccounts/allocatedAccounts.service.ts +++ b/src/modules/admin/partners/allocatedAccounts/allocatedAccounts.service.ts @@ -7,18 +7,18 @@ import { ResponseMapper } from 'common/response/response-mapper' export class PartnerAllocatedAccountsService { constructor(private readonly prisma: PrismaService) {} - async findAll(partner_id: string, page = 1, pageSize = 10) { + async findAll(partner_id: string, page = 1, perPage = 10) { const defaultWhere: PartnerAccountQuotaCreditWhereInput = { charge_transaction: { partner_id, }, } - const [allocations, count] = await this.prisma.$transaction(async tx => [ + const [allocations, total] = await this.prisma.$transaction(async tx => [ await tx.partnerAccountQuotaCredit.findMany({ where: defaultWhere, - skip: (page - 1) * pageSize, - take: pageSize, + skip: (page - 1) * perPage, + take: perPage, select: { id: true, created_at: true, @@ -54,8 +54,8 @@ export class PartnerAllocatedAccountsService { return ResponseMapper.paginate(allocations, { page, - pageSize, - count, + perPage, + total, }) } } diff --git a/src/modules/admin/partners/chargeAccountQoutaTransactions/chargeAccountQuotaTransactions.service.ts b/src/modules/admin/partners/chargeAccountQoutaTransactions/chargeAccountQuotaTransactions.service.ts index 6f5373e..8ede352 100644 --- a/src/modules/admin/partners/chargeAccountQoutaTransactions/chargeAccountQuotaTransactions.service.ts +++ b/src/modules/admin/partners/chargeAccountQoutaTransactions/chargeAccountQuotaTransactions.service.ts @@ -51,16 +51,16 @@ export class PartnerAccountChargeTransactionService { }, } - async findAll(partner_id: string, page = 1, pageSize = 10) { + async findAll(partner_id: string, page = 1, perPage = 10) { const defaultWhere: PartnerAccountQuotaChargeTransactionWhereInput = { partner_id, } - const [transactions, count] = await this.prisma.$transaction(async tx => [ + const [transactions, total] = await this.prisma.$transaction(async tx => [ await tx.partnerAccountQuotaChargeTransaction.findMany({ where: defaultWhere, - skip: (page - 1) * pageSize, - take: pageSize, + skip: (page - 1) * perPage, + take: perPage, select: this.defaultSelect, }), await tx.partnerAccountQuotaChargeTransaction.count({ @@ -72,8 +72,8 @@ export class PartnerAccountChargeTransactionService { return ResponseMapper.paginate(mappedTransactions, { page, - pageSize, - count, + perPage, + total, }) } diff --git a/src/modules/admin/partners/chargedLicenseTransactions/chargedLicenseTransactions.service.ts b/src/modules/admin/partners/chargedLicenseTransactions/chargedLicenseTransactions.service.ts index 0a7e2db..1412a7d 100644 --- a/src/modules/admin/partners/chargedLicenseTransactions/chargedLicenseTransactions.service.ts +++ b/src/modules/admin/partners/chargedLicenseTransactions/chargedLicenseTransactions.service.ts @@ -51,16 +51,16 @@ export class PartnerLicenseChargeTransactionService { }, } - async findAll(partner_id: string, page = 1, pageSize = 10) { + async findAll(partner_id: string, page = 1, perPage = 10) { const defaultWhere: LicenseChargeTransactionWhereInput = { partner_id, } - const [transactions, count] = await this.prisma.$transaction(async tx => [ + const [transactions, total] = await this.prisma.$transaction(async tx => [ await tx.licenseChargeTransaction.findMany({ where: defaultWhere, - skip: (page - 1) * pageSize, - take: pageSize, + skip: (page - 1) * perPage, + take: perPage, select: this.defaultSelect, }), await tx.licenseChargeTransaction.count({ @@ -72,8 +72,8 @@ export class PartnerLicenseChargeTransactionService { return ResponseMapper.paginate(mappedTransactions, { page, - pageSize, - count, + perPage, + total, }) } diff --git a/src/modules/admin/users/users.service.ts b/src/modules/admin/users/users.service.ts index efeb372..9a4eee7 100644 --- a/src/modules/admin/users/users.service.ts +++ b/src/modules/admin/users/users.service.ts @@ -8,13 +8,13 @@ export class AdminUsersService { constructor(private readonly prisma: PrismaService) {} async findAll() { - const [users, count] = await this.prisma.$transaction([ + const [users, total] = await this.prisma.$transaction([ this.prisma.admin.findMany(), this.prisma.admin.count(), ]) return ResponseMapper.paginate( users.map(user => ({ ...user, fullname: `${user.first_name} ${user.last_name}` })), - { count }, + { total }, ) } diff --git a/src/modules/consumer/business-activities/complexes/poses/sales-invoices/sales-invoices.service.ts b/src/modules/consumer/business-activities/complexes/poses/sales-invoices/sales-invoices.service.ts index f0e6d48..50cb19a 100644 --- a/src/modules/consumer/business-activities/complexes/poses/sales-invoices/sales-invoices.service.ts +++ b/src/modules/consumer/business-activities/complexes/poses/sales-invoices/sales-invoices.service.ts @@ -20,10 +20,10 @@ export class SalesInvoicesService { }, } - const pageSize = 10 + const perPage = 10 const page = 1 - const [items, count] = await this.prisma.$transaction([ + const [items, total] = await this.prisma.$transaction([ this.prisma.salesInvoice.findMany({ where: defaultWhere, select: { @@ -91,14 +91,14 @@ export class SalesInvoicesService { }, unknown_customer: true, }, - skip: (page - 1) * pageSize, - take: pageSize, + skip: (page - 1) * perPage, + take: perPage, }), this.prisma.salesInvoice.count({ where: defaultWhere, }), ]) - return ResponseMapper.paginate(items, { count, page, pageSize }) + return ResponseMapper.paginate(items, { total, page, perPage }) } findOne(complex_id: string, pos_id: string, id: string) { diff --git a/src/modules/consumer/customers/customers.service.ts b/src/modules/consumer/customers/customers.service.ts index 624fd3b..8319f4c 100644 --- a/src/modules/consumer/customers/customers.service.ts +++ b/src/modules/consumer/customers/customers.service.ts @@ -60,19 +60,19 @@ export class consumerCustomersService { } } - async findAll(consumer_id: string, page = 1, pageSize = 10) { - const [customers, count] = await this.prisma.$transaction(async tx => [ + async findAll(consumer_id: string, page = 1, perPage = 10) { + const [customers, total] = await this.prisma.$transaction(async tx => [ await tx.customer.findMany({ where: this.defaultWhere(consumer_id), select: this.defaultSelect, - skip: (page - 1) * pageSize, + skip: (page - 1) * perPage, take: 10, }), await tx.customer.count({ where: this.defaultWhere(consumer_id), }), ]) - return ResponseMapper.paginate(customers, { count, page, pageSize }) + return ResponseMapper.paginate(customers, { total, page, perPage }) } async findOne(consumer_id: string, customer_id: string) { diff --git a/src/modules/consumer/customers/sale-invoices/sale-invoices.service.ts b/src/modules/consumer/customers/sale-invoices/sale-invoices.service.ts index aaaa355..5dbd9b8 100644 --- a/src/modules/consumer/customers/sale-invoices/sale-invoices.service.ts +++ b/src/modules/consumer/customers/sale-invoices/sale-invoices.service.ts @@ -50,7 +50,7 @@ export class CustomerSaleInvoicesService { created_at: true, } - async findAll(consumer_id: string, customer_id: string, page = 1, pageSize = 10) { + async findAll(consumer_id: string, customer_id: string, page = 1, perPage = 10) { const salesWhere: SalesInvoiceWhereInput = { customer_id, pos: { @@ -62,7 +62,7 @@ export class CustomerSaleInvoicesService { }, } - const [accounts, count] = await this.prisma.$transaction(async tx => [ + const [accounts, total] = await this.prisma.$transaction(async tx => [ await tx.salesInvoice.findMany({ where: salesWhere, select: { @@ -73,7 +73,7 @@ export class CustomerSaleInvoicesService { }, }, }, - skip: (page - 1) * pageSize, + skip: (page - 1) * perPage, take: 10, }), await tx.salesInvoice.count({ @@ -90,9 +90,9 @@ export class CustomerSaleInvoicesService { }) return ResponseMapper.paginate(mappedAccounts, { - count, + total, page, - pageSize, + perPage, }) } diff --git a/src/modules/consumer/saleInvoices/saleInvoices.service.ts b/src/modules/consumer/saleInvoices/saleInvoices.service.ts index 95924ea..54787cb 100644 --- a/src/modules/consumer/saleInvoices/saleInvoices.service.ts +++ b/src/modules/consumer/saleInvoices/saleInvoices.service.ts @@ -47,22 +47,22 @@ export class SaleInvoicesService { }, } - async findAll(consumer_id: string, page = 1, pageSize = 10) { + async findAll(consumer_id: string, page = 1, perPage = 10) { const invoicesWhere: SalesInvoiceWhereInput = { consumer_account: { consumer_id, }, } - const [invoices, count] = await this.prisma.$transaction(async tx => [ + const [invoices, total] = await this.prisma.$transaction(async tx => [ await tx.salesInvoice.findMany({ where: invoicesWhere, select: this.defaultSelect, - skip: (page - 1) * pageSize, - take: pageSize, + skip: (page - 1) * perPage, + take: perPage, }), await tx.salesInvoice.count({ where: invoicesWhere }), ]) - return ResponseMapper.paginate(invoices, { page, pageSize, count }) + return ResponseMapper.paginate(invoices, { page, perPage, total }) } async findOne(consumer_id: string, id: string) { diff --git a/src/modules/partners/consumers/consumers.service.ts b/src/modules/partners/consumers/consumers.service.ts index a9f7c39..7f0aacd 100644 --- a/src/modules/partners/consumers/consumers.service.ts +++ b/src/modules/partners/consumers/consumers.service.ts @@ -37,12 +37,12 @@ export class PartnerConsumersService { partner_id, }) - async findAll(partner_id: string, page = 1, pageSize = 10) { - const [consumers, count] = await this.prisma.$transaction(async tx => [ + async findAll(partner_id: string, page = 1, perPage = 10) { + const [consumers, total] = await this.prisma.$transaction(async tx => [ await tx.consumer.findMany({ where: this.defaultWhere(partner_id), select: this.defaultSelect, - skip: (page - 1) * pageSize, + skip: (page - 1) * perPage, take: 10, }), await tx.consumer.count({ @@ -50,9 +50,9 @@ export class PartnerConsumersService { }), ]) return ResponseMapper.paginate(consumers.map(mapConsumerWithLicenseUtil), { - count, + total, page, - pageSize, + perPage, }) } diff --git a/src/modules/partners/licenses/dto/licenses-response.dto.ts b/src/modules/partners/licenses/dto/licenses-response.dto.ts new file mode 100644 index 0000000..a4a4fe4 --- /dev/null +++ b/src/modules/partners/licenses/dto/licenses-response.dto.ts @@ -0,0 +1,140 @@ +import { ApiProperty } from '@nestjs/swagger' +import { Paginated } from 'common/response/response-mapper' + +export interface PartnerLicenseActivationConsumerResponseDto { + id: string + first_name: string + last_name: string + mobile_number: string +} + +export interface PartnerLicenseActivationBusinessActivityResponseDto { + id: string + name: string + consumer: PartnerLicenseActivationConsumerResponseDto +} + +export interface PartnerLicenseActivationChargeTransactionResponseDto { + id: string + tracking_code: string + activation_expires_at: Date +} + +export interface PartnerLicenseActivationLicenseResponseDto { + id: string + accounts_limit: number + charge_transaction: PartnerLicenseActivationChargeTransactionResponseDto +} + +export interface PartnerLicenseActivationCountResponseDto { + account_allocations: number +} + +export interface PartnerLicenseActivationResponseDto { + id: string + starts_at: Date + expires_at: Date + created_at: Date + updated_at: Date + business_activity: PartnerLicenseActivationBusinessActivityResponseDto + license: PartnerLicenseActivationLicenseResponseDto + _count: PartnerLicenseActivationCountResponseDto +} + +export type PartnerLicenseActivationPaginatedResponseDto = + Paginated + +export class PartnerLicenseActivationConsumerResponseSchema { + @ApiProperty() + id: string + + @ApiProperty() + first_name: string + + @ApiProperty() + last_name: string + + @ApiProperty() + mobile_number: string +} + +export class PartnerLicenseActivationBusinessActivityResponseSchema { + @ApiProperty() + id: string + + @ApiProperty() + name: string + + @ApiProperty({ type: () => PartnerLicenseActivationConsumerResponseSchema }) + consumer: PartnerLicenseActivationConsumerResponseSchema +} + +export class PartnerLicenseActivationChargeTransactionResponseSchema { + @ApiProperty() + id: string + + @ApiProperty() + tracking_code: string + + @ApiProperty() + activation_expires_at: Date +} + +export class PartnerLicenseActivationLicenseResponseSchema { + @ApiProperty() + id: string + + @ApiProperty() + accounts_limit: number + + @ApiProperty({ type: () => PartnerLicenseActivationChargeTransactionResponseSchema }) + charge_transaction: PartnerLicenseActivationChargeTransactionResponseSchema +} + +export class PartnerLicenseActivationCountResponseSchema { + @ApiProperty() + account_allocations: number +} + +export class PartnerLicenseActivationResponseSchema { + @ApiProperty() + id: string + + @ApiProperty() + starts_at: Date + + @ApiProperty() + expires_at: Date + + @ApiProperty() + created_at: Date + + @ApiProperty() + updated_at: Date + + @ApiProperty({ type: () => PartnerLicenseActivationBusinessActivityResponseSchema }) + business_activity: PartnerLicenseActivationBusinessActivityResponseSchema + + @ApiProperty({ type: () => PartnerLicenseActivationLicenseResponseSchema }) + license: PartnerLicenseActivationLicenseResponseSchema + + @ApiProperty({ type: () => PartnerLicenseActivationCountResponseSchema }) + _count: PartnerLicenseActivationCountResponseSchema +} + +export class PartnerLicenseActivationPaginatedResponseSchema { + @ApiProperty({ example: 'paginate' }) + __mapped: string + + @ApiProperty({ type: () => [PartnerLicenseActivationResponseSchema] }) + items: PartnerLicenseActivationResponseSchema[] + + @ApiProperty() + total: number + + @ApiProperty() + page: number + + @ApiProperty() + perPage: number +} diff --git a/src/modules/partners/licenses/licenses.controller.ts b/src/modules/partners/licenses/licenses.controller.ts new file mode 100644 index 0000000..5721c60 --- /dev/null +++ b/src/modules/partners/licenses/licenses.controller.ts @@ -0,0 +1,49 @@ +import { PartnerInfo } from '@/common/decorators/partnerInfo.decorator' +import { Controller, Get, Query } from '@nestjs/common' +import { ApiOkResponse, ApiQuery, ApiTags } from '@nestjs/swagger' +import { PartnerLicenseActivationPaginatedResponseSchema } from './dto/licenses-response.dto' +import { PartnerLicensesService } from './licenses.service' + +@ApiTags('PartnerLicenses') +@Controller('partner/licenses') +export class PartnerLicensesController { + constructor(private readonly service: PartnerLicensesService) {} + + @Get() + @ApiQuery({ name: 'page', required: false, type: Number, example: 1 }) + @ApiQuery({ + name: 'perPage', + required: false, + type: Number, + example: 10, + description: 'Max value is 50.', + }) + @ApiQuery({ name: 'consumer_name', required: false, type: String }) + @ApiQuery({ name: 'consumer_mobile', required: false, type: String }) + @ApiQuery({ + name: 'expires_from', + required: false, + type: String, + example: '2026-01-01', + }) + @ApiQuery({ name: 'expires_to', required: false, type: String, example: '2026-12-31' }) + @ApiOkResponse({ type: PartnerLicenseActivationPaginatedResponseSchema }) + async findAll( + @PartnerInfo('id') partnerId: string, + @Query('page') page = '1', + @Query('perPage') perPage = '10', + @Query('consumer_name') consumer_name?: string, + @Query('consumer_mobile') consumer_mobile?: string, + @Query('expires_from') expires_from?: string, + @Query('expires_to') expires_to?: string, + ) { + return this.service.findAll(partnerId, { + page: Number(page) || 1, + perPage: Number(perPage) || 10, + consumer_name, + consumer_mobile, + expires_from, + expires_to, + }) + } +} diff --git a/src/modules/partners/licenses/licenses.module.ts b/src/modules/partners/licenses/licenses.module.ts new file mode 100644 index 0000000..9d8a9e6 --- /dev/null +++ b/src/modules/partners/licenses/licenses.module.ts @@ -0,0 +1,11 @@ +import { PrismaModule } from '@/prisma/prisma.module' +import { Module } from '@nestjs/common' +import { PartnerLicensesController } from './licenses.controller' +import { PartnerLicensesService } from './licenses.service' + +@Module({ + imports: [PrismaModule], + controllers: [PartnerLicensesController], + providers: [PartnerLicensesService], +}) +export class PartnerLicensesModule {} diff --git a/src/modules/partners/licenses/licenses.service.ts b/src/modules/partners/licenses/licenses.service.ts new file mode 100644 index 0000000..c757705 --- /dev/null +++ b/src/modules/partners/licenses/licenses.service.ts @@ -0,0 +1,167 @@ +import { PrismaService } from '@/prisma/prisma.service' +import { BadRequestException, Injectable } from '@nestjs/common' +import { ResponseMapper } from 'common/response/response-mapper' +import { + PartnerLicenseActivationPaginatedResponseDto, + PartnerLicenseActivationResponseDto, +} from './dto/licenses-response.dto' + +type FindPartnerLicensesParams = { + perPage?: number + page?: number + consumer_name?: string + consumer_mobile?: string + expires_from?: string + expires_to?: string +} + +@Injectable() +export class PartnerLicensesService { + private readonly defaultPerPage = 10 + private readonly maxPerPage = 50 + + constructor(private readonly prisma: PrismaService) {} + + async findAll( + partner_id: string, + params: FindPartnerLicensesParams = {}, + ): Promise { + const { perPage, page, consumer_name, consumer_mobile, expires_from, expires_to } = + params + + const normalizedPage = Number.isFinite(page) + ? Math.max(1, Math.floor(page as number)) + : 1 + const requestedPerPage = Number.isFinite(perPage) + ? Math.max(1, Math.floor(perPage as number)) + : this.defaultPerPage + const normalizedPerPage = Math.min(requestedPerPage, this.maxPerPage) + + const andWhere: any[] = [ + { + license: { + charge_transaction: { + partner_id, + }, + }, + }, + ] + + const consumerName = consumer_name?.trim() + const consumerMobile = consumer_mobile?.trim() + + if (consumerName || consumerMobile) { + andWhere.push({ + business_activity: { + consumer: { + OR: [ + { first_name: { contains: consumerName } }, + { last_name: { contains: consumerName } }, + ], + }, + }, + }) + } + + if (consumerMobile) { + andWhere.push({ + business_activity: { + consumer: { + mobile_number: { + contains: consumerMobile, + }, + }, + }, + }) + } + + if (expires_from || expires_to) { + const expiresAtFilter: { + gte?: Date + lte?: Date + } = {} + + if (expires_from) { + const fromDate = new Date(expires_from) + if (Number.isNaN(fromDate.getTime())) { + throw new BadRequestException('مقدار expires_from نامعتبر است.') + } + expiresAtFilter.gte = fromDate + } + + if (expires_to) { + const toDate = new Date(expires_to) + if (Number.isNaN(toDate.getTime())) { + throw new BadRequestException('مقدار expires_to نامعتبر است.') + } + expiresAtFilter.lte = toDate + } + + andWhere.push({ + expires_at: expiresAtFilter, + }) + } + + const where = { AND: andWhere } + + const [licenseActivations, total] = await this.prisma.$transaction(async tx => [ + await tx.licenseActivation.findMany({ + where, + orderBy: { + created_at: 'desc', + }, + skip: (normalizedPage - 1) * normalizedPerPage, + take: normalizedPerPage, + select: { + id: true, + starts_at: true, + expires_at: true, + created_at: true, + updated_at: true, + business_activity: { + select: { + id: true, + name: true, + consumer: { + select: { + id: true, + first_name: true, + last_name: true, + mobile_number: true, + }, + }, + }, + }, + license: { + select: { + id: true, + accounts_limit: true, + charge_transaction: { + select: { + id: true, + tracking_code: true, + activation_expires_at: true, + }, + }, + }, + }, + _count: { + select: { + account_allocations: true, + }, + }, + }, + }), + await tx.licenseActivation.count({ where }), + ]) + + return ResponseMapper.paginate( + licenseActivations, + { + total, + page: normalizedPage, + perPage: normalizedPerPage, + }, + ) + } +} diff --git a/src/modules/partners/partners.module.ts b/src/modules/partners/partners.module.ts index e7e0836..da7f32c 100644 --- a/src/modules/partners/partners.module.ts +++ b/src/modules/partners/partners.module.ts @@ -2,13 +2,14 @@ import { MiddlewareConsumer, Module, NestModule, RequestMethod } from '@nestjs/c import { JwtService } from '@nestjs/jwt' import { PartnerAccountsModule } from './accounts/accounts.module' import { PartnerCustomersModule } from './consumers/consumers.module' +import { PartnerLicensesModule } from './licenses/licenses.module' import { PartnerController } from './partners.controller' import { PartnerMiddleware } from './partners.middleware' import { PartnerService } from './partners.service' @Module({ controllers: [PartnerController], - imports: [PartnerAccountsModule, PartnerCustomersModule], + imports: [PartnerAccountsModule, PartnerCustomersModule, PartnerLicensesModule], providers: [JwtService, PartnerService], }) export class PartnerModule implements NestModule { diff --git a/src/modules/pos/pos.service.ts b/src/modules/pos/pos.service.ts index 1be196a..5ce2f8f 100644 --- a/src/modules/pos/pos.service.ts +++ b/src/modules/pos/pos.service.ts @@ -18,6 +18,7 @@ export class PosService { select: { id: true, name: true, + branch_code: true, business_activity: { select: { id: true, @@ -72,6 +73,7 @@ export class PosService { complex: { id: complexId, name: complexName, + branch_code: complex.branch_code, }, businessActivity: { id: businessId,