From 23ae3556de7803821d0655bcfdd511c12af5d321 Mon Sep 17 00:00:00 2001 From: ahasani194 Date: Mon, 18 May 2026 10:53:58 +0330 Subject: [PATCH] feat: implement consumer info update and password change functionality with DTOs --- Dockerfile | 2 +- .../sale-invoice-create.service.ts | 20 ++++-- .../utils/mappers/consumer_mappers.util.ts | 10 ++- src/modules/consumer/consumer.controller.ts | 30 +++++++- src/modules/consumer/consumer.service.ts | 71 +++++++++++++++++++ .../consumer/dto/consumer-response.dto.ts | 7 +- .../consumer/dto/update-info-request.dto.ts | 28 ++++++++ .../dto/update-password-request.dto.ts | 8 +++ .../statistics/statistics.controller.ts | 6 +- 9 files changed, 165 insertions(+), 17 deletions(-) create mode 100644 src/modules/consumer/dto/update-info-request.dto.ts create mode 100644 src/modules/consumer/dto/update-password-request.dto.ts diff --git a/Dockerfile b/Dockerfile index 6b4f95d..961869d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,7 @@ FROM node:22-slim AS base WORKDIR /app -ARG NPM_REGISTRY=https://registry.npmjs.org/ +ARG NPM_REGISTRY=https://hub.megan.ir/npm/ ENV NPM_CONFIG_REGISTRY=${NPM_REGISTRY} ENV npm_config_registry=${NPM_REGISTRY} ENV PNPM_HOME="/pnpm" diff --git a/src/common/services/saleInvoices/sale-invoice-create.service.ts b/src/common/services/saleInvoices/sale-invoice-create.service.ts index 7572148..7ccdcd9 100644 --- a/src/common/services/saleInvoices/sale-invoice-create.service.ts +++ b/src/common/services/saleInvoices/sale-invoice-create.service.ts @@ -11,13 +11,13 @@ import { import { SharedCreateSalesInvoiceDto } from './sale-invoice-create.dto' interface TerminalPaymentInfo { - terminalId: string + terminal_id: string stan: string rrn: string - transactionDateTime: string | Date - customerCardNO?: string + transaction_date_time: string | Date + customer_card_no: string description?: string - amount?: number + amount: number } interface NormalizedPayment { @@ -150,6 +150,12 @@ export class SharedSaleInvoiceCreateService { const rawPayments = (paymentsData || {}) as Record const terminalInfo = rawPayments.terminals as TerminalPaymentInfo | undefined + console.log( + 'terminalInfo0', + rawPayments.terminals?.[0]?.customer_card_no, + terminalInfo, + ) + const payments: NormalizedPayment[] = Object.entries(rawPayments) .filter(([key, value]) => key !== 'terminals' && value && Number(value) > 0) .map(([key, value]) => ({ @@ -508,11 +514,11 @@ export class SharedSaleInvoiceCreateService { await tx.salesInvoicePaymentTerminalInfo.create({ data: { payment_id: createdPayment.id, - terminal_id: terminalInfo.terminalId, + terminal_id: terminalInfo.terminal_id, stan: terminalInfo.stan, rrn: terminalInfo.rrn, - transaction_date_time: new Date(terminalInfo.transactionDateTime || ''), - customer_card_no: terminalInfo.customerCardNO || null, + transaction_date_time: new Date(terminalInfo.transaction_date_time || ''), + customer_card_no: terminalInfo.customer_card_no || null, description: terminalInfo.description || null, }, }) diff --git a/src/common/utils/mappers/consumer_mappers.util.ts b/src/common/utils/mappers/consumer_mappers.util.ts index 2252eb8..d8a3aad 100644 --- a/src/common/utils/mappers/consumer_mappers.util.ts +++ b/src/common/utils/mappers/consumer_mappers.util.ts @@ -8,7 +8,7 @@ export default (consumer: any) => { delete legal?.partner delete individual?.partner - return { + const returnData = { ...rest, partner, type: translateEnumValue('ConsumerType', type), @@ -18,9 +18,13 @@ export default (consumer: any) => { ? { ...individual, fullname: `${individual?.first_name} ${individual?.last_name}` } : null, name: legal ? legal.name : `${individual?.first_name} ${individual?.last_name}`, - business_counts, - // license_info: prepareLicenseInfo(activation), } + + if (business_counts !== undefined) { + returnData['business_counts'] = business_counts + } + + return returnData } function prepareLicenseInfo(latestLicense: any) { diff --git a/src/modules/consumer/consumer.controller.ts b/src/modules/consumer/consumer.controller.ts index bc2de55..376979e 100644 --- a/src/modules/consumer/consumer.controller.ts +++ b/src/modules/consumer/consumer.controller.ts @@ -1,8 +1,13 @@ import { ConsumerInfo } from '@/common/decorators/consumerInfo.decorator' -import { Controller, Get } from '@nestjs/common' +import { Body, Controller, Get, Patch, Put } from '@nestjs/common' import { ApiTags } from '@nestjs/swagger' import { ConsumerService } from './consumer.service' -import type { ConsumerServiceGetInfoResponseDto } from './dto/consumer-response.dto' +import type { + ConsumerServiceGetInfoResponseDto, + ConsumerServiceUpdateInfoResponseDto, +} from './dto/consumer-response.dto' +import { UpdateConsumerInfoDto } from './dto/update-info-request.dto' +import { UpdateConsumerPasswordDto } from './dto/update-password-request.dto' @ApiTags('Consumer') @Controller('consumer') @@ -10,7 +15,26 @@ export class ConsumerController { constructor(private service: ConsumerService) {} @Get('') - async findOne(@ConsumerInfo('id') consumerId: string): Promise { + async findOne( + @ConsumerInfo('id') consumerId: string, + ): Promise { return this.service.getInfo(consumerId) } + + @Patch('') + async updateInfo( + @ConsumerInfo('id') consumerId: string, + @Body() data: UpdateConsumerInfoDto, + ): Promise { + return this.service.updateInfo(consumerId, data) + } + + @Put('update-password') + async updatePassword( + @ConsumerInfo('id') consumerId: string, + @ConsumerInfo('account_id') accountId: string, + @Body() data: UpdateConsumerPasswordDto, + ) { + return this.service.updatePassword(consumerId, accountId, data) + } } diff --git a/src/modules/consumer/consumer.service.ts b/src/modules/consumer/consumer.service.ts index 03817a1..25f3af8 100644 --- a/src/modules/consumer/consumer.service.ts +++ b/src/modules/consumer/consumer.service.ts @@ -1,8 +1,12 @@ import { QUERY_CONSTANTS } from '@/common/queryConstants' import { ResponseMapper } from '@/common/response/response-mapper' +import { PasswordUtil } from '@/common/utils' +import { ConsumerUpdateInput } from '@/generated/prisma/models' import { PrismaService } from '@/prisma/prisma.service' import { Injectable } from '@nestjs/common' import consumer_mappersUtil from '../../common/utils/mappers/consumer_mappers.util' +import { UpdateConsumerInfoDto } from './dto/update-info-request.dto' +import { UpdateConsumerPasswordDto } from './dto/update-password-request.dto' @Injectable() export class ConsumerService { @@ -22,4 +26,71 @@ export class ConsumerService { return ResponseMapper.single(consumer_mappersUtil(consumer)) } + + async updateInfo(consumer_id: string, data: UpdateConsumerInfoDto) { + const consumerExists = await this.prisma.consumer.findUnique({ + where: { + id: consumer_id, + }, + select: { + type: true, + }, + }) + + let dataForUpdate: ConsumerUpdateInput = {} + + if (consumerExists?.type === 'LEGAL') { + dataForUpdate = { + legal: { + update: { + name: data.company_name, + registration_code: data.registration_code, + }, + }, + } + } else if (consumerExists?.type === 'INDIVIDUAL') { + dataForUpdate = { + individual: { + update: { + first_name: data.first_name, + last_name: data.last_name, + mobile_number: data.mobile_number, + national_code: data.national_code, + }, + }, + } + } + const consumer = await this.prisma.consumer.update({ + where: { + id: consumer_id, + }, + data: { + ...dataForUpdate, + }, + }) + + return ResponseMapper.update(consumer) + } + + async updatePassword( + consumer_id: string, + accountId: string, + data: UpdateConsumerPasswordDto, + ) { + const consumer = await this.prisma.consumerAccount.update({ + where: { + id: accountId, + consumer_id, + }, + data: { + account: { + update: { + password: await PasswordUtil.hash(data.password), + }, + }, + }, + }) + + return ResponseMapper.update(consumer) + } } diff --git a/src/modules/consumer/dto/consumer-response.dto.ts b/src/modules/consumer/dto/consumer-response.dto.ts index c118702..64df1b0 100644 --- a/src/modules/consumer/dto/consumer-response.dto.ts +++ b/src/modules/consumer/dto/consumer-response.dto.ts @@ -1,3 +1,8 @@ import type { ConsumerService } from '../consumer.service' -export type ConsumerServiceGetInfoResponseDto = Awaited> +export type ConsumerServiceGetInfoResponseDto = Awaited< + ReturnType +> +export type ConsumerServiceUpdateInfoResponseDto = Awaited< + ReturnType +> diff --git a/src/modules/consumer/dto/update-info-request.dto.ts b/src/modules/consumer/dto/update-info-request.dto.ts new file mode 100644 index 0000000..9561b20 --- /dev/null +++ b/src/modules/consumer/dto/update-info-request.dto.ts @@ -0,0 +1,28 @@ +import { ApiProperty } from '@nestjs/swagger' +import { IsString } from 'class-validator' + +export class UpdateConsumerInfoDto { + @IsString() + @ApiProperty() + first_name: string + + @IsString() + @ApiProperty() + last_name: string + + @IsString() + @ApiProperty() + mobile_number: string + + @IsString() + @ApiProperty() + national_code: string + + @IsString() + @ApiProperty() + company_name: string + + @IsString() + @ApiProperty() + registration_code: string +} diff --git a/src/modules/consumer/dto/update-password-request.dto.ts b/src/modules/consumer/dto/update-password-request.dto.ts new file mode 100644 index 0000000..cc395c0 --- /dev/null +++ b/src/modules/consumer/dto/update-password-request.dto.ts @@ -0,0 +1,8 @@ +import { ApiProperty } from '@nestjs/swagger' +import { IsString } from 'class-validator' + +export class UpdateConsumerPasswordDto { + @IsString() + @ApiProperty({ required: true }) + password: string +} diff --git a/src/modules/consumer/statistics/statistics.controller.ts b/src/modules/consumer/statistics/statistics.controller.ts index 15ec79e..42a3d6f 100644 --- a/src/modules/consumer/statistics/statistics.controller.ts +++ b/src/modules/consumer/statistics/statistics.controller.ts @@ -1,8 +1,8 @@ import { TokenAccount } from '@/common/decorators/tokenInfo.decorator' import { Controller, Get } from '@nestjs/common' import { ApiTags } from '@nestjs/swagger' -import { StatisticsService } from './statistics.service' import type { StatisticsServiceGetInvoicesResponseDto } from './dto/statistics-response.dto' +import { StatisticsService } from './statistics.service' @ApiTags('ConsumerStatistics') @Controller('consumer/statistics') @@ -10,7 +10,9 @@ export class StatisticsController { constructor(private readonly service: StatisticsService) {} @Get('invoices') - async getInvoices(@TokenAccount('userId') consumerId: string): Promise { + async getInvoices( + @TokenAccount('userId') consumerId: string, + ): Promise { return this.service.getInvoices(consumerId) } }