From 99fa47356a263a9352635429d2f5499cab1db57e Mon Sep 17 00:00:00 2001 From: Matin Date: Thu, 20 Feb 2025 09:50:01 +0330 Subject: [PATCH] chore: update user profile --- src/common/enums/message.enum.ts | 9 ++++++++ .../invoices/providers/invoices.service.ts | 13 ++++++++---- src/modules/users/DTO/update-profile.dto.ts | 21 ++++++++++++++++++- src/modules/users/entities/user.entity.ts | 13 ++++++++++-- src/modules/users/providers/users.service.ts | 12 +++++++++-- 5 files changed, 59 insertions(+), 9 deletions(-) diff --git a/src/common/enums/message.enum.ts b/src/common/enums/message.enum.ts index 4e3f5b4..86b8842 100644 --- a/src/common/enums/message.enum.ts +++ b/src/common/enums/message.enum.ts @@ -76,6 +76,15 @@ export const enum UserMessage { INVALID_EMAIL_TOKEN = "توکن ایمیل نامعتبر است", EXPIRED_EMAIL_TOKEN = "توکن ایمیل منقضی شده است", PHONE_EXIST = "شماره تلفن قبلا ثبت شده است", + ADDRESS_REQUIRED = "آدرس نمی‌تواند خالی باشد", + ADDRESS_SHOULD_BE_STRING = "آدرس باید یک رشته باشد", + ADDRESS_LENGTH = "آدرس باید بین ۵ تا ۲۵۵ کاراکتر باشد", + POSTAL_CODE_REQUIRED = "کد پستی نمی‌تواند خالی باشد", + POSTAL_CODE_SHOULD_BE_STRING = "کد پستی باید یک رشته باشد", + POSTAL_CODE_LENGTH = "کد پستی باید ۱۰ رقم باشد", + CITY_REQUIRED = "شهر نمی‌تواند خالی باشد", + CITY_NOT_FOUND = "شهر یافت نشد", + CITY_SHOULD_BE_UUID = "شناسه شهر باید یک UUID باشد", } export const enum CommonMessage { diff --git a/src/modules/invoices/providers/invoices.service.ts b/src/modules/invoices/providers/invoices.service.ts index 1b2aef6..ff351bc 100644 --- a/src/modules/invoices/providers/invoices.service.ts +++ b/src/modules/invoices/providers/invoices.service.ts @@ -310,34 +310,39 @@ export class InvoicesService { } async cancelDiscount(invoiceId: string, userId: string) { + // Find the invoice by ID and ensure it is in a PENDING status const invoice = await this.invoiceRepository.findOneBy({ id: invoiceId, status: InvoiceStatus.PENDING }); if (!invoice) throw new BadRequestException(InvoiceMessage.NOT_FOUND_BY_ID); + // Find the usage discount associated with the user and invoice const usage = await this.usageDiscountRepository.findOne({ where: { - users: { - id: userId, - }, + users: { id: userId }, + discount: { invoice: { id: invoice.id } }, }, relations: { discount: true, + users: true, }, }); - console.log(usage); if (!usage) throw new BadRequestException(DiscountMessage.NOT_FOUND); + // Find the discount associated with the usage const discount = await this.discountRepository.findOneBy({ id: usage.discount.id }); if (!discount) throw new BadRequestException(DiscountMessage.NOT_FOUND); + // Calculate the discount amount to be removed from the invoice const discountAmount = discount.calculationType === "PERCENTAGE" ? new Decimal(invoice.totalPrice).mul(discount.amount).div(100) : new Decimal(discount.amount); + // Update the invoice's total price by adding the discount amount (effectively removing the discount) invoice.totalPrice = new Decimal(invoice.totalPrice).add(discountAmount); await this.invoiceRepository.save(invoice); + // Delete the usage discount record await this.usageDiscountRepository.delete(usage.id); return { diff --git a/src/modules/users/DTO/update-profile.dto.ts b/src/modules/users/DTO/update-profile.dto.ts index da18290..e74444f 100644 --- a/src/modules/users/DTO/update-profile.dto.ts +++ b/src/modules/users/DTO/update-profile.dto.ts @@ -12,9 +12,28 @@ export class UpdateProfileDto extends PartialType(PickType(CompleteRegistrationD @ApiPropertyOptional({ description: "User name", example: "mamad24" }) userName?: string; + @ApiPropertyOptional({ description: "Profile picture", example: "https://www.google.com" }) @IsOptional() @IsNotEmpty({ message: UserMessage.PROFILE_PIC_REQUIRED }) @IsUrl({ protocols: ["http", "https"], require_protocol: true }, { message: UserMessage.PROFILE_PIC_URL }) - @ApiPropertyOptional({ description: "Profile picture", example: "https://www.google.com" }) profilePic?: string; + + @ApiPropertyOptional({ description: "User address", example: "123 Main St" }) + @IsOptional() + @IsNotEmpty({ message: UserMessage.ADDRESS_REQUIRED }) + @IsString({ message: UserMessage.ADDRESS_SHOULD_BE_STRING }) + @Length(5, 255, { message: UserMessage.ADDRESS_LENGTH }) + userAddress?: string; + + @ApiPropertyOptional({ description: "Postal code", example: "1234567890" }) + @IsOptional() + @IsNotEmpty({ message: UserMessage.POSTAL_CODE_REQUIRED }) + @IsString({ message: UserMessage.POSTAL_CODE_SHOULD_BE_STRING }) + @Length(10, 10, { message: UserMessage.POSTAL_CODE_LENGTH }) + postalCode?: string; + + @ApiPropertyOptional({ description: "City id" }) + @IsOptional() + @IsNotEmpty({ message: UserMessage.CITY_REQUIRED }) + cityId: string; } diff --git a/src/modules/users/entities/user.entity.ts b/src/modules/users/entities/user.entity.ts index 2c58e62..000c544 100644 --- a/src/modules/users/entities/user.entity.ts +++ b/src/modules/users/entities/user.entity.ts @@ -1,5 +1,5 @@ import { Exclude } from "class-transformer"; -import { Column, Entity, JoinColumn, JoinTable, ManyToMany, OneToMany, OneToOne } from "typeorm"; +import { Column, Entity, JoinColumn, JoinTable, ManyToMany, ManyToOne, OneToMany, OneToOne } from "typeorm"; import { LegalUser } from "./legal-user.entity"; import { RealUser } from "./real-user.entity"; @@ -7,6 +7,7 @@ import { Role } from "./role.entity"; import { UserGroup } from "./user-group.entity"; import { BaseEntity } from "../../../common/entities/base.entity"; import { Address } from "../../address/entities/address.entity"; +import { City } from "../../address/entities/city.entity"; import { UserAnnouncement } from "../../announcements/entities/user-announcement.entity"; import { Criticism } from "../../criticisms/entities/criticism.entity"; import { DanakServiceReview } from "../../danak-services/entities/danak-service-review.entity"; @@ -54,10 +55,18 @@ export class User extends BaseEntity { @Column({ type: "boolean", default: false }) emailVerified: boolean; + + @Column({ type: "varchar", length: 255, nullable: true }) + userAddress: string; + + @Column({ type: "varchar", length: 10, nullable: true }) + postalCode: string; //----------------------------------------- + + @ManyToOne(() => City, { eager: true, nullable: true }) + city: City; // @ManyToOne(() => Role, { eager: true, onDelete: "RESTRICT", nullable: false }) // role: Role; - @ManyToMany(() => Role, (role) => role.users) @JoinTable({ name: "user_role_relation" }) roles: Role[]; diff --git a/src/modules/users/providers/users.service.ts b/src/modules/users/providers/users.service.ts index 25e4cfb..479ded6 100644 --- a/src/modules/users/providers/users.service.ts +++ b/src/modules/users/providers/users.service.ts @@ -80,7 +80,7 @@ export class UsersService { /************************************************************ */ async getMe(userId: string) { - const user = await this.userRepository.findOne({ where: { id: userId }, relations: { roles: true } }); + const user = await this.userRepository.findOne({ where: { id: userId }, relations: { roles: true, city: { province: true } } }); if (!user) throw new BadRequestException(UserMessage.USER_NOT_FOUND); return { user }; } @@ -104,9 +104,17 @@ export class UsersService { /************************************************************ */ async updateProfile(userId: string, updateProfileDto: UpdateProfileDto) { + let city; + const user = await this.userRepository.findOneBy({ id: userId }); if (!user) throw new BadRequestException(UserMessage.USER_NOT_FOUND); + if (updateProfileDto.cityId) { + const { city: existCity } = await this.addressService.getCity(+updateProfileDto.cityId); + if (!existCity) throw new BadRequestException(UserMessage.CITY_NOT_FOUND); + city = existCity; + } + // if (updateProfileDto.userName) { updateProfileDto.userName = slugify(updateProfileDto.userName, { lower: true, trim: true }); @@ -114,7 +122,7 @@ export class UsersService { if (existUserName) throw new BadRequestException(UserMessage.USERNAME_EXIST); } - await this.userRepository.save({ ...user, ...updateProfileDto }); + await this.userRepository.save({ ...user, ...updateProfileDto, city }); // return { message: CommonMessage.UPDATE_SUCCESS,