From 59da9585c49a7c94cb3581b716454cabbf2d3a5d Mon Sep 17 00:00:00 2001 From: ahasani194 Date: Mon, 13 Apr 2026 15:47:59 +0330 Subject: [PATCH] init to partner module --- req.d.ts | 5 +- src/app.module.ts | 2 + .../decorators/consumerInfo.decorator.ts | 2 +- .../decorators/partnerInfo.decorator.ts | 33 ++++++++ src/common/guards/auth-partner.guard.ts | 49 ++++++++++++ src/common/guards/jwt-auth.guard.ts | 22 +++--- src/common/models/partnerPayload.model.ts | 4 + src/main.ts | 2 + src/modules/consumer/consumer.middleware.ts | 2 +- .../partners/accounts/accounts.controller.ts | 39 +++++++++ .../partners/accounts/accounts.module.ts | 12 +++ .../partners/accounts/accounts.service.ts | 79 +++++++++++++++++++ .../partners/accounts/dto/account.dto.ts | 24 ++++++ .../customers/customers.controller.ts | 18 +++++ .../partners/customers/customers.module.ts | 11 +++ .../partners/customers/customers.service.ts | 61 ++++++++++++++ .../customers/dto/create-customers.dto.ts | 74 +++++++++++++++++ src/modules/partners/partners.controller.ts | 15 ++++ src/modules/partners/partners.middleware.ts | 61 ++++++++++++++ src/modules/partners/partners.module.ts | 27 +++++++ src/modules/partners/partners.service.ts | 23 ++++++ 21 files changed, 553 insertions(+), 12 deletions(-) create mode 100644 src/common/decorators/partnerInfo.decorator.ts create mode 100644 src/common/guards/auth-partner.guard.ts create mode 100644 src/common/models/partnerPayload.model.ts create mode 100644 src/modules/partners/accounts/accounts.controller.ts create mode 100644 src/modules/partners/accounts/accounts.module.ts create mode 100644 src/modules/partners/accounts/accounts.service.ts create mode 100644 src/modules/partners/accounts/dto/account.dto.ts create mode 100644 src/modules/partners/customers/customers.controller.ts create mode 100644 src/modules/partners/customers/customers.module.ts create mode 100644 src/modules/partners/customers/customers.service.ts create mode 100644 src/modules/partners/customers/dto/create-customers.dto.ts create mode 100644 src/modules/partners/partners.controller.ts create mode 100644 src/modules/partners/partners.middleware.ts create mode 100644 src/modules/partners/partners.module.ts create mode 100644 src/modules/partners/partners.service.ts diff --git a/req.d.ts b/req.d.ts index e5deca3..07308e2 100644 --- a/req.d.ts +++ b/req.d.ts @@ -1,15 +1,18 @@ import { AccessTokenPayload, IConsumerPayload, IPosPayload } from '@/common/models' +import { IPartnerPayload } from '@/common/models/partnerPayload.model' declare global { interface Request { decodedToken?: AccessTokenPayload consumerData?: IConsumerPayload + partnerData?: IPartnerPayload posData?: IPosPayload } namespace Express { interface Request { decodedToken?: AccessTokenPayload - consumerData?: IConsumerPayload + partnerData?: IConsumerPayload + partnerData?: IPartnerPayload posData?: IPosPayload } } diff --git a/src/app.module.ts b/src/app.module.ts index 0177426..db57dce 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -6,6 +6,7 @@ import { AuthModule } from './modules/auth/auth.module' import { CatalogModule } from './modules/catalog/catalog.module' import { ConsumerModule } from './modules/consumer/consumer.module' import { EnumsModule } from './modules/enums/enums.module' +import { PartnerModule } from './modules/partners/partners.module' import { PosModule } from './modules/pos/pos.module' import { SalesInvoiceItemsModule } from './modules/pos/sales-invoices/sales-invoice-items/sales-invoice-items.module' import { SalesInvoicePaymentsModule } from './modules/pos/sales-invoices/sales-invoice-payments/sales-invoice-payments.module' @@ -21,6 +22,7 @@ import { PrismaModule } from './prisma/prisma.module' CatalogModule, ConsumerModule, PosModule, + PartnerModule, AuthModule, SalesInvoiceItemsModule, SalesInvoicePaymentsModule, diff --git a/src/common/decorators/consumerInfo.decorator.ts b/src/common/decorators/consumerInfo.decorator.ts index b303bc5..5587b88 100644 --- a/src/common/decorators/consumerInfo.decorator.ts +++ b/src/common/decorators/consumerInfo.decorator.ts @@ -11,7 +11,7 @@ export const ConsumerInfo = createParamDecorator( (data: keyof IConsumerPayload | undefined, ctx: ExecutionContext) => { try { const request = ctx.switchToHttp().getRequest() - const info = request.consumerData + const info = request.partnerData if (!info) { throw new ForbiddenException('شما به این بخش دسترسی ندارید') diff --git a/src/common/decorators/partnerInfo.decorator.ts b/src/common/decorators/partnerInfo.decorator.ts new file mode 100644 index 0000000..86c0875 --- /dev/null +++ b/src/common/decorators/partnerInfo.decorator.ts @@ -0,0 +1,33 @@ +import { + BadRequestException, + createParamDecorator, + ExecutionContext, + ForbiddenException, +} from '@nestjs/common' +import { Request } from 'express' +import { IPartnerPayload } from '../models/partnerPayload.model' + +export const PartnerInfo = createParamDecorator( + (data: keyof IPartnerPayload | undefined, ctx: ExecutionContext) => { + try { + const request = ctx.switchToHttp().getRequest() + const info = request.partnerData + + if (!info) { + throw new ForbiddenException('شما به این بخش دسترسی ندارید') + } + + if (data) { + return info[data] + } + + return info + } catch (err) { + if (err) { + throw err + } + + throw new BadRequestException('مشکلی در ساختار درخواست شما وجود دارد.') + } + }, +) diff --git a/src/common/guards/auth-partner.guard.ts b/src/common/guards/auth-partner.guard.ts new file mode 100644 index 0000000..fee8372 --- /dev/null +++ b/src/common/guards/auth-partner.guard.ts @@ -0,0 +1,49 @@ +// src/common/guards/permissions.guard.ts +import { ITokenPayload } from '@/modules/auth/auth.utils' +import { PrismaService } from '@/prisma/prisma.service' +import { + ExecutionContext, + ForbiddenException, + Injectable, + UnauthorizedException, +} from '@nestjs/common' +import { Request as ExpressRequest } from 'express' + +@Injectable() +export class PartnerGuard { + constructor(private prisma: PrismaService) {} + + async canActivate( + tokenPayload: ITokenPayload, + context: ExecutionContext, + ): Promise { + if (!tokenPayload || tokenPayload.type !== 'PARTNER') { + throw new UnauthorizedException() + } + + const partner = await this.prisma.partner.findFirst({ + where: { + partner_accounts: { + some: { + id: tokenPayload.account_id, + }, + }, + }, + select: { + partner_accounts: { + select: { + role: true, + }, + }, + }, + }) + + if (!partner) { + throw new ForbiddenException('شما دسترسی لازم را ندارید.') + } + + const req = context.switchToHttp().getRequest() + + return true + } +} diff --git a/src/common/guards/jwt-auth.guard.ts b/src/common/guards/jwt-auth.guard.ts index fc4b6e4..f17a0be 100644 --- a/src/common/guards/jwt-auth.guard.ts +++ b/src/common/guards/jwt-auth.guard.ts @@ -2,7 +2,6 @@ import { ITokenPayload } from '@/modules/auth/auth.utils' import { CanActivate, ExecutionContext, - ForbiddenException, Injectable, UnauthorizedException, } from '@nestjs/common' @@ -12,6 +11,7 @@ import { Request as ExpressRequest } from 'express' import { IS_PUBLIC_KEY } from '../decorators/public.decorator' import { IS_PUBLIC_WITH_TOKEN_KEY } from '../decorators/withToken.decorator' import { ConsumerGuard } from './auth-consumer.guard' +import { PartnerGuard } from './auth-partner.guard' import { PosGuard } from './auth-pos.guard' @Injectable() @@ -21,6 +21,7 @@ export class JwtAuthGuard implements CanActivate { private reflector: Reflector, private consumerGuard: ConsumerGuard, private posGuard: PosGuard, + private partnerGuard: PartnerGuard, ) {} async canActivate(context: ExecutionContext): Promise { @@ -59,14 +60,17 @@ export class JwtAuthGuard implements CanActivate { const tokenPayload = this.jwt.decode(token) as ITokenPayload - if (req.url.startsWith('/api/v1/consumer')) { - await this.consumerGuard.canActivate(tokenPayload, context) - } else if (req.url.startsWith('/api/v1/pos')) { - // await this.consumerGuard.canActivate(tokenPayload, context) - await this.posGuard.canActivate(tokenPayload, context) - } else if (tokenPayload.type != 'ADMIN') { - throw new ForbiddenException('شما دسترسی لازم را ندارید') - } + // if (req.url.startsWith('/api/v1/partner')) { + // await this.partnerGuard.canActivate(tokenPayload, context) + // } + // if (req.url.startsWith('/api/v1/consumer')) { + // await this.consumerGuard.canActivate(tokenPayload, context) + // } else if (req.url.startsWith('/api/v1/pos')) { + // // await this.consumerGuard.canActivate(tokenPayload, context) + // await this.posGuard.canActivate(tokenPayload, context) + // } else if (tokenPayload.type != 'ADMIN') { + // throw new ForbiddenException('شما دسترسی لازم را ندارید') + // } return true } catch (err) { if (err) throw err diff --git a/src/common/models/partnerPayload.model.ts b/src/common/models/partnerPayload.model.ts new file mode 100644 index 0000000..6ac59ab --- /dev/null +++ b/src/common/models/partnerPayload.model.ts @@ -0,0 +1,4 @@ +export interface IPartnerPayload { + id: string + account_id: string +} diff --git a/src/main.ts b/src/main.ts index 5a05895..d0d9eb9 100644 --- a/src/main.ts +++ b/src/main.ts @@ -6,6 +6,7 @@ import { AppModule } from './app.module' import { PrismaExceptionFilter } from './common/filters/prisma-exception.filter' import { ValidationExceptionFilter } from './common/filters/validation-exception.filter' import { ConsumerGuard } from './common/guards/auth-consumer.guard' +import { PartnerGuard } from './common/guards/auth-partner.guard' import { PosGuard } from './common/guards/auth-pos.guard' import { JwtAuthGuard } from './common/guards/jwt-auth.guard' import { LoggingInterceptor } from './common/interceptors/logging.interceptor' @@ -88,6 +89,7 @@ async function bootstrap() { app.get(Reflector), new ConsumerGuard(new PrismaService()), new PosGuard(new PrismaService()), + new PartnerGuard(new PrismaService()), ), ) diff --git a/src/modules/consumer/consumer.middleware.ts b/src/modules/consumer/consumer.middleware.ts index 020977c..7876d3e 100644 --- a/src/modules/consumer/consumer.middleware.ts +++ b/src/modules/consumer/consumer.middleware.ts @@ -44,7 +44,7 @@ export class ConsumerMiddleware implements NestMiddleware { return doForbidden() } - req.consumerData = { + req.partnerData = { account_id: consumerAccount.id, id: consumerAccount.consumer_id, } diff --git a/src/modules/partners/accounts/accounts.controller.ts b/src/modules/partners/accounts/accounts.controller.ts new file mode 100644 index 0000000..80e5ba9 --- /dev/null +++ b/src/modules/partners/accounts/accounts.controller.ts @@ -0,0 +1,39 @@ +import { TokenAccount } from '@/common/decorators/tokenInfo.decorator' +import { Body, Controller, Get, Param, Patch } from '@nestjs/common' +import { ApiTags } from '@nestjs/swagger' +import { AccountsService } from './accounts.service' +import { UpdateAccountDto } from './dto/account.dto' + +@ApiTags('PartnerAccounts') +@Controller('partner/accounts') +export class AccountsController { + constructor(private readonly service: AccountsService) {} + + @Get() + async findAll(@TokenAccount('userId') consumerId: string) { + return this.service.findAll(consumerId) + } + + @Get(':id') + async findOne(@Param('id') id: string) { + return this.service.findOne(id) + } + + // @Post() + // async create( + // @TokenAccount('userId') consumerId: string, + // @Body() data: CreateConsumerAccountDto, + // ) { + // return this.service.create(consumerId, data) + // } + + @Patch(':id') + async update(@Param('id') id: string, @Body() data: UpdateAccountDto) { + return this.service.update(id, data) + } + + // @Delete(':id') + // async delete(@Param('id') id: string) { + // return this.service.delete(id) + // } +} diff --git a/src/modules/partners/accounts/accounts.module.ts b/src/modules/partners/accounts/accounts.module.ts new file mode 100644 index 0000000..9d8a77a --- /dev/null +++ b/src/modules/partners/accounts/accounts.module.ts @@ -0,0 +1,12 @@ +import { PrismaModule } from '@/prisma/prisma.module' +import { Module } from '@nestjs/common' +import { AccountsController } from './accounts.controller' +import { AccountsService } from './accounts.service' + +@Module({ + imports: [PrismaModule], + controllers: [AccountsController], + providers: [AccountsService], + exports: [AccountsService], +}) +export class PartnerAccountsModule {} diff --git a/src/modules/partners/accounts/accounts.service.ts b/src/modules/partners/accounts/accounts.service.ts new file mode 100644 index 0000000..ce1f16d --- /dev/null +++ b/src/modules/partners/accounts/accounts.service.ts @@ -0,0 +1,79 @@ +import { PasswordUtil } from '@/common/utils/password.util' +import { AccountStatus, AccountType } from '@/generated/prisma/enums' +import { PrismaService } from '@/prisma/prisma.service' +import { Injectable } from '@nestjs/common' +import { ResponseMapper } from 'common/response/response-mapper' +import { CreatePartnerAccountDto, UpdateAccountDto } from './dto/account.dto' + +@Injectable() +export class AccountsService { + constructor(private readonly prisma: PrismaService) {} + + async findAll(partner_id: string) { + const accounts = await this.prisma.partnerAccount.findMany({ + where: { partner_id }, + select: { + id: true, + role: true, + created_at: true, + account: { + select: { + username: true, + status: true, + }, + }, + }, + }) + return ResponseMapper.list(accounts) + } + + async findOne(id: string) { + const account = await this.prisma.partnerAccount.findUniqueOrThrow({ + where: { id }, + select: { + id: true, + role: true, + created_at: true, + account: { + select: { + username: true, + status: true, + }, + }, + }, + }) + return ResponseMapper.single(account) + } + + async create(partnerId: string, data: CreatePartnerAccountDto) { + const account = await this.prisma.partnerAccount.create({ + data: { + role: data.role, + account: { + create: { + password: await PasswordUtil.hash(data.password), + status: AccountStatus.ACTIVE, + type: AccountType.PARTNER, + username: data.username, + }, + }, + partner: { + connect: { + id: partnerId, + }, + }, + }, + }) + return ResponseMapper.create(account) + } + + async update(id: string, data: UpdateAccountDto) { + const account = await this.prisma.account.update({ where: { id }, data }) + return ResponseMapper.update(account) + } + + // async delete(id: string) { + // await this.prisma.account.delete({ where: { id } }) + // return ResponseMapper.delete() + // } +} diff --git a/src/modules/partners/accounts/dto/account.dto.ts b/src/modules/partners/accounts/dto/account.dto.ts new file mode 100644 index 0000000..46592d4 --- /dev/null +++ b/src/modules/partners/accounts/dto/account.dto.ts @@ -0,0 +1,24 @@ +import { ApiProperty, PartialType } from '@nestjs/swagger' +import { IsEnum, IsOptional, IsString } from 'class-validator' +import { AccountStatus, PartnerRole } from 'generated/prisma/enums' + +export class CreatePartnerAccountDto { + @IsString() + @ApiProperty({ required: true }) + username: string + + @IsString() + @ApiProperty({ required: true }) + password: string + + @IsEnum(PartnerRole) + @ApiProperty({ required: true, enum: PartnerRole }) + role: PartnerRole +} + +export class UpdateAccountDto extends PartialType(CreatePartnerAccountDto) { + @IsOptional() + @IsEnum(AccountStatus) + @ApiProperty({ enum: AccountStatus }) + status?: AccountStatus +} diff --git a/src/modules/partners/customers/customers.controller.ts b/src/modules/partners/customers/customers.controller.ts new file mode 100644 index 0000000..015e510 --- /dev/null +++ b/src/modules/partners/customers/customers.controller.ts @@ -0,0 +1,18 @@ +import { PartnerInfo } from '@/common/decorators/partnerInfo.decorator' +import { Controller, Get, Param } from '@nestjs/common' +import { PartnerCustomersService } from './customers.service' + +@Controller('partner/customers') +export class PartnerCustomersController { + constructor(private readonly service: PartnerCustomersService) {} + + @Get() + async findAll(@PartnerInfo('id') partnerId: string) { + return this.service.findAll(partnerId) + } + + @Get(':id') + async findOne(@PartnerInfo('id') partnerId: string, @Param('id') id: string) { + return this.service.findOne(partnerId, id) + } +} diff --git a/src/modules/partners/customers/customers.module.ts b/src/modules/partners/customers/customers.module.ts new file mode 100644 index 0000000..273ad47 --- /dev/null +++ b/src/modules/partners/customers/customers.module.ts @@ -0,0 +1,11 @@ +import { PrismaModule } from '@/prisma/prisma.module' +import { Module } from '@nestjs/common' +import { PartnerCustomersController } from './customers.controller' +import { PartnerCustomersService } from './customers.service' + +@Module({ + imports: [PrismaModule], + controllers: [PartnerCustomersController], + providers: [PartnerCustomersService], +}) +export class PartnerCustomersModule {} diff --git a/src/modules/partners/customers/customers.service.ts b/src/modules/partners/customers/customers.service.ts new file mode 100644 index 0000000..476cd2d --- /dev/null +++ b/src/modules/partners/customers/customers.service.ts @@ -0,0 +1,61 @@ +import { ConsumerSelect, ConsumerWhereInput } from '@/generated/prisma/models' +import { PrismaService } from '@/prisma/prisma.service' +import { Injectable } from '@nestjs/common' +import { ResponseMapper } from 'common/response/response-mapper' + +@Injectable() +export class PartnerCustomersService { + constructor(private readonly prisma: PrismaService) {} + + defaultSelect: ConsumerSelect = { + id: true, + first_name: true, + last_name: true, + status: true, + license: { + select: { + id: true, + starts_at: true, + status: true, + expires_at: true, + created_at: true, + }, + }, + created_at: true, + } + + private defaultWhere = (partner_id: string): ConsumerWhereInput => ({ + license: { + partner_id, + }, + }) + + async findAll(partner_id: string, page = 1, pageSize = 10) { + const [partners, count] = await this.prisma.$transaction(async tx => [ + await tx.consumer.findMany({ + where: this.defaultWhere(partner_id), + select: this.defaultSelect, + skip: (page - 1) * pageSize, + take: 10, + }), + await tx.consumer.count({ + where: this.defaultWhere(partner_id), + }), + ]) + return ResponseMapper.paginate(partners, { count, page, pageSize }) + } + + async findOne(partner_id: string, consumer_id: string) { + const partner = await this.prisma.consumer.findUniqueOrThrow({ + where: { + license: { + partner_id, + }, + id: consumer_id, + }, + select: this.defaultSelect, + }) + + return ResponseMapper.single(partner) + } +} diff --git a/src/modules/partners/customers/dto/create-customers.dto.ts b/src/modules/partners/customers/dto/create-customers.dto.ts new file mode 100644 index 0000000..1099b32 --- /dev/null +++ b/src/modules/partners/customers/dto/create-customers.dto.ts @@ -0,0 +1,74 @@ +import { ApiProperty } from '@nestjs/swagger' +import { + IsBoolean, + IsNumber, + IsOptional, + IsString, + MaxLength, + MinLength, +} from 'class-validator' + +export class UpdateCustomerLegalDto { + @IsString() + @IsOptional() + @ApiProperty({ required: true }) + company_name?: string + + @IsString() + @IsOptional() + @ApiProperty({ required: true }) + economic_code?: string + + @IsString() + @IsOptional() + @ApiProperty({ required: true }) + registration_number?: string + + @IsNumber() + @MaxLength(10) + @MinLength(10) + @IsOptional() + @ApiProperty({ maxLength: 10, minLength: 10 }) + postal_code?: string + + @IsBoolean() + @IsOptional() + @ApiProperty({ required: false }) + is_favorite?: boolean +} + +export class UpdateCustomerIndividualDto { + @IsString() + @IsOptional() + @ApiProperty({ required: true }) + first_name?: string + + @IsString() + @IsOptional() + @ApiProperty({ required: true }) + last_name?: string + + @IsNumber() + @MaxLength(10) + @MinLength(10) + @IsOptional() + @ApiProperty({ required: true, maxLength: 10, minLength: 10 }) + national_code?: string + + @IsNumber() + @MaxLength(10) + @MinLength(10) + @IsOptional() + @ApiProperty({ maxLength: 10, minLength: 10 }) + postal_code?: string + + @IsBoolean() + @IsOptional() + @ApiProperty({ required: false }) + is_favorite?: boolean + + @IsNumber() + @IsOptional() + @ApiProperty({ required: false }) + economic_code?: string +} diff --git a/src/modules/partners/partners.controller.ts b/src/modules/partners/partners.controller.ts new file mode 100644 index 0000000..99f6aca --- /dev/null +++ b/src/modules/partners/partners.controller.ts @@ -0,0 +1,15 @@ +import { ConsumerInfo } from '@/common/decorators/consumerInfo.decorator' +import { Controller, Get } from '@nestjs/common' +import { ApiTags } from '@nestjs/swagger' +import { PartnerService } from './partners.service' + +@ApiTags('Partner') +@Controller('partner') +export class PartnerController { + constructor(private service: PartnerService) {} + + @Get('') + async findOne(@ConsumerInfo('id') consumerId: string) { + return this.service.getInfo(consumerId) + } +} diff --git a/src/modules/partners/partners.middleware.ts b/src/modules/partners/partners.middleware.ts new file mode 100644 index 0000000..69fecda --- /dev/null +++ b/src/modules/partners/partners.middleware.ts @@ -0,0 +1,61 @@ +import { checkAndDecodeJwtToken } from '@/common/utils/jwt-user.util' +import { PrismaService } from '@/prisma/prisma.service' +import { + ForbiddenException, + Injectable, + NestMiddleware, + UnauthorizedException, +} from '@nestjs/common' +import { JwtService } from '@nestjs/jwt' +import { NextFunction, Request, Response } from 'express' + +@Injectable() +export class PartnerMiddleware implements NestMiddleware { + constructor( + private prisma: PrismaService, + private jwtService: JwtService, + ) {} + + async use(req: Request, _res: Response, next: NextFunction) { + const doForbidden = () => { + console.log('doForbidden') + + throw new ForbiddenException('شما دسترسی لازم را ندارید') + } + try { + const tokenAccount = checkAndDecodeJwtToken(req, this.jwtService) + + if (tokenAccount?.type !== 'PARTNER') { + throw new UnauthorizedException() + } + + const partnerAccount = await this.prisma.partnerAccount.findUnique({ + where: { + id: tokenAccount.account_id, + }, + select: { + partner_id: true, + id: true, + }, + }) + + if (!partnerAccount) { + return doForbidden() + } + + req.partnerData = { + account_id: partnerAccount.id, + id: partnerAccount.partner_id, + } + + req.decodedToken = tokenAccount + + return next() + } catch (error) { + if (error && typeof error === 'object') { + throw error + } + return doForbidden() + } + } +} diff --git a/src/modules/partners/partners.module.ts b/src/modules/partners/partners.module.ts new file mode 100644 index 0000000..13b23d1 --- /dev/null +++ b/src/modules/partners/partners.module.ts @@ -0,0 +1,27 @@ +import { MiddlewareConsumer, Module, NestModule, RequestMethod } from '@nestjs/common' +import { JwtService } from '@nestjs/jwt' +import { PartnerAccountsModule } from './accounts/accounts.module' +import { PartnerCustomersModule } from './customers/customers.module' +import { PartnerController } from './partners.controller' +import { PartnerMiddleware } from './partners.middleware' +import { PartnerService } from './partners.service' + +@Module({ + controllers: [PartnerController], + imports: [PartnerAccountsModule, PartnerCustomersModule], + providers: [JwtService, PartnerService], +}) +export class PartnerModule implements NestModule { + configure(partner: MiddlewareConsumer) { + partner.apply(PartnerMiddleware).forRoutes({ + path: '/partner*path', + method: RequestMethod.ALL, + version: '1', + }) + partner.apply(PartnerMiddleware).forRoutes({ + path: '/partner', + method: RequestMethod.ALL, + version: '1', + }) + } +} diff --git a/src/modules/partners/partners.service.ts b/src/modules/partners/partners.service.ts new file mode 100644 index 0000000..bd18f38 --- /dev/null +++ b/src/modules/partners/partners.service.ts @@ -0,0 +1,23 @@ +import { ResponseMapper } from '@/common/response/response-mapper' +import { PrismaService } from '@/prisma/prisma.service' +import { Injectable } from '@nestjs/common' + +@Injectable() +export class PartnerService { + constructor(private readonly prisma: PrismaService) {} + + async getInfo(partner_id: string) { + const partner = await this.prisma.partner.findUniqueOrThrow({ + where: { + id: partner_id, + }, + select: { + id: true, + name: true, + status: true, + }, + }) + + return ResponseMapper.single(partner) + } +}