diff --git a/migrations/20250104112403-create-product.js b/migrations/20250104112403-create-product.js index b707233..bfd5c1d 100644 --- a/migrations/20250104112403-create-product.js +++ b/migrations/20250104112403-create-product.js @@ -1,15 +1,14 @@ -"use strict"; +'use strict'; module.exports = { up: async (queryInterface, Sequelize) => { - await queryInterface.dropTable("Products", { cascade: true }); - - await queryInterface.createTable("Products", { + await queryInterface.dropTable('Products', { cascade: true }); + await queryInterface.createTable('Products', { id: { type: Sequelize.INTEGER, - allowNull: false, autoIncrement: true, primaryKey: true, + allowNull: false, }, name: { type: Sequelize.STRING, @@ -20,7 +19,7 @@ module.exports = { allowNull: false, }, price: { - type: Sequelize.DECIMAL(10, 2), + type: Sequelize.INTEGER, allowNull: false, }, imageUrl: { @@ -51,17 +50,17 @@ module.exports = { createdAt: { type: Sequelize.DATE, allowNull: false, - defaultValue: Sequelize.NOW, + defaultValue: Sequelize.fn('NOW'), }, updatedAt: { type: Sequelize.DATE, allowNull: false, - defaultValue: Sequelize.NOW, + defaultValue: Sequelize.fn('NOW'), }, }); }, down: async (queryInterface, Sequelize) => { - await queryInterface.dropTable("Products"); + await queryInterface.dropTable('Products'); }, }; diff --git a/migrations/20250105062732-create-invoice.js b/migrations/20250105062732-create-invoice.js index 56cc8f9..1a387d1 100644 --- a/migrations/20250105062732-create-invoice.js +++ b/migrations/20250105062732-create-invoice.js @@ -1,16 +1,8 @@ -"use strict"; +'use strict'; module.exports = { up: async (queryInterface, Sequelize) => { - const tableExists = await queryInterface - .describeTable("Invoices") - .then(() => true) - .catch(() => false); - - if (tableExists) { - await queryInterface.dropTable("Invoices", { cascade: true }); - } - await queryInterface.createTable("Invoices", { + await queryInterface.createTable('Invoices', { id: { type: Sequelize.INTEGER, autoIncrement: true, @@ -21,34 +13,45 @@ module.exports = { type: Sequelize.INTEGER, allowNull: false, references: { - model: "Users", - key: "id", + model: 'Users', + key: 'id', }, - onDelete: "CASCADE", + onDelete: 'CASCADE', }, totalPaymentAmount: { - type: Sequelize.FLOAT, + type: Sequelize.INTEGER, allowNull: false, }, status: { - type: Sequelize.ENUM("pending", "paid"), + type: Sequelize.ENUM('pending', 'paid'), allowNull: false, - defaultValue: "pending", + defaultValue: 'pending', }, createdAt: { type: Sequelize.DATE, allowNull: false, - defaultValue: Sequelize.fn("NOW"), + defaultValue: Sequelize.fn('NOW'), }, updatedAt: { type: Sequelize.DATE, allowNull: false, - defaultValue: Sequelize.fn("NOW"), + defaultValue: Sequelize.fn('NOW'), + }, + }); + + await queryInterface.addConstraint('Invoices', { + fields: ['userId'], + type: 'foreign key', + name: 'fk_user_id', + references: { + table: 'Users', + field: 'id', }, + onDelete: 'CASCADE', }); }, down: async (queryInterface, Sequelize) => { - await queryInterface.dropTable("Invoices", { cascade: true }); + await queryInterface.dropTable('Invoices'); }, }; diff --git a/migrations/20250105063054-create-cart.js b/migrations/20250105063054-create-cart.js index 02df389..8f18d49 100644 --- a/migrations/20250105063054-create-cart.js +++ b/migrations/20250105063054-create-cart.js @@ -21,7 +21,7 @@ module.exports = { }, productId: { type: Sequelize.INTEGER, - allowNull: true, + allowNull: false, references: { model: 'Products', key: 'id', @@ -30,9 +30,9 @@ module.exports = { }, invoiceId: { type: Sequelize.INTEGER, - allowNull: true, + allowNull: false, references: { - model: 'Invoices', + model: 'Invoices', // نام جدول Invoices key: 'id', }, onDelete: 'CASCADE', @@ -42,7 +42,7 @@ module.exports = { allowNull: true, }, productPrice: { - type: Sequelize.DECIMAL(10, 2), + type: Sequelize.INTEGER, allowNull: true, }, status: { diff --git a/migrations/20250108065213-create-wallet.js b/migrations/20250108065213-create-wallet.js new file mode 100644 index 0000000..53c5357 --- /dev/null +++ b/migrations/20250108065213-create-wallet.js @@ -0,0 +1,43 @@ +'use strict'; + +module.exports = { + up: async (queryInterface, Sequelize) => { + await queryInterface.dropTable("Wallets", { cascade: true }); + await queryInterface.createTable('Wallets', { + id: { + type: Sequelize.INTEGER, + autoIncrement: true, + primaryKey: true, + allowNull: false, + }, + userId: { + type: Sequelize.INTEGER, + allowNull: false, + references: { + model: 'Users', + key: 'id', + }, + onDelete: 'CASCADE', + }, + balance: { + type: Sequelize.INTEGER, + allowNull: false, + defaultValue: 0, + }, + createdAt: { + type: Sequelize.DATE, + allowNull: false, + defaultValue: Sequelize.fn('NOW'), + }, + updatedAt: { + type: Sequelize.DATE, + allowNull: false, + defaultValue: Sequelize.fn('NOW'), + }, + }); + }, + + down: async (queryInterface, Sequelize) => { + await queryInterface.dropTable('Wallets'); + }, +}; diff --git a/src/cart/dto/add-to-cart.dto.ts b/src/cart/dto/add-to-cart.dto.ts index 540da4a..0df51ee 100644 --- a/src/cart/dto/add-to-cart.dto.ts +++ b/src/cart/dto/add-to-cart.dto.ts @@ -1,8 +1,8 @@ // add-to-cart.dto.ts -import { IsInt, IsNotEmpty, IsNumber, min, Min } from 'class-validator'; +import { isInt, IsInt, IsNotEmpty, IsNumber, min, Min } from 'class-validator'; export class AddToCartDto { - @IsNumber() + @IsInt() @IsNotEmpty() productId: number; diff --git a/src/cart/entities/cart.entity.ts b/src/cart/entities/cart.entity.ts index 540221c..79816c3 100644 --- a/src/cart/entities/cart.entity.ts +++ b/src/cart/entities/cart.entity.ts @@ -33,7 +33,7 @@ export class Cart extends Model { quantity: number; @Column({ - type: DataType.DECIMAL(10, 2), + type: DataType.INTEGER, allowNull: true, }) productPrice: number; diff --git a/src/invoice/entities/invoice.entity.ts b/src/invoice/entities/invoice.entity.ts index c54258c..8f90710 100644 --- a/src/invoice/entities/invoice.entity.ts +++ b/src/invoice/entities/invoice.entity.ts @@ -23,7 +23,7 @@ export class Invoice extends Model { carts: Cart[]; @Column({ - type: DataType.FLOAT, + type: DataType.INTEGER, allowNull: false, }) totalPaymentAmount: number; diff --git a/src/invoice/invoice.service.ts b/src/invoice/invoice.service.ts index 0765107..0d95a82 100644 --- a/src/invoice/invoice.service.ts +++ b/src/invoice/invoice.service.ts @@ -3,7 +3,6 @@ import { InjectModel } from "@nestjs/sequelize"; import { Invoice } from "./entities/invoice.entity"; import { CartService } from "src/cart/cart.service"; import { User } from "src/users/entities/user.entity"; -import { where } from "sequelize"; @Injectable() export class InvoiceService { @@ -44,8 +43,7 @@ export class InvoiceService { await invoice.save(); } - - async getInvoiceByUserAndCart(userId: number): Promise { + async getInvoiceByUser(userId: number): Promise { try { if (!userId ) { throw new HttpException("User ID are required.", HttpStatus.BAD_REQUEST); diff --git a/src/payment/payment.controller.ts b/src/payment/payment.controller.ts index dfa41b3..941866e 100644 --- a/src/payment/payment.controller.ts +++ b/src/payment/payment.controller.ts @@ -10,19 +10,14 @@ export class PaymentController { private readonly wallet: WalletService, private readonly paymentService: PaymentService, private readonly cartService: CartService, + private readonly invoiceService: InvoiceService, ) {} @Post("request/:userId") async requestPayment(@Param("userId") userId: number): Promise<{ url: string }> { - const userCartItems = await this.cartService.getUserCart(userId); - - if (!userCartItems || userCartItems.cartItems.length === 0) { - throw new Error("Cart is empty!"); - } - - const totalAmount = userCartItems.totalPrice; - - const callbackUrl = `http://localhost:3000/payment/verify?userId=${userId}`; + const invoice = await this.invoiceService.getInvoiceByUser(userId); + const totalAmount = Math.round(invoice.totalPaymentAmount); + const callbackUrl = `http://localhost:3000/payment/verify?userId=${userId}`; const paymentUrl = await this.paymentService.requestPayment(totalAmount, "Purchase products", callbackUrl); return { url: paymentUrl }; @@ -41,19 +36,14 @@ export class PaymentController { } try { - const userCartItems = await this.cartService.getUserCart(userId); - if (!userCartItems || userCartItems.cartItems.length === 0) { - throw new Error("Cart is empty!"); - } - const totalAmount = userCartItems.totalPrice; - + const invoice = await this.invoiceService.getInvoiceByUser(userId); + const totalAmount = Math.round(invoice.totalPaymentAmount); const refId = await this.paymentService.verifyPayment(Authority, totalAmount); - await this.wallet.addBalance(userId,totalAmount) - return { message: "Payment successful", refId}; + await this.wallet.addBalance(userId, totalAmount); + return { message: "Payment successful", refId }; } catch (error) { - console.log(error) + console.log(error); throw new Error(`Error during payment verification: ${error.message}`); } } } - diff --git a/src/payment/payment.module.ts b/src/payment/payment.module.ts index 1405a69..8bc39e0 100644 --- a/src/payment/payment.module.ts +++ b/src/payment/payment.module.ts @@ -4,9 +4,10 @@ import { PaymentController } from './payment.controller'; import { InvoiceService } from 'src/invoice/invoice.service'; import { CartModule } from 'src/cart/cart.module'; import { WalletModule } from 'src/wallet/wallet.module'; +import { InvoiceModule } from 'src/invoice/invoice.module'; @Module({ - imports:[CartModule,WalletModule], + imports:[CartModule,WalletModule,InvoiceModule], controllers: [PaymentController], providers: [PaymentService], }) diff --git a/src/payment/payment.service.ts b/src/payment/payment.service.ts index a910e93..b4d2ce1 100644 --- a/src/payment/payment.service.ts +++ b/src/payment/payment.service.ts @@ -42,7 +42,6 @@ export class PaymentService { Amount: amount, Authority: authority, }); - if (result.status === 100) { return result.RefID; } else { diff --git a/src/products/dto/create-product.dto.ts b/src/products/dto/create-product.dto.ts index 1d3fba9..c8458b9 100644 --- a/src/products/dto/create-product.dto.ts +++ b/src/products/dto/create-product.dto.ts @@ -1,4 +1,4 @@ -import { IsString, IsNumber, IsOptional, IsNotEmpty, IsArray } from 'class-validator'; +import { IsString, IsNumber, IsOptional, IsNotEmpty, IsArray, IsInt } from 'class-validator'; export class CreateProductDto { @IsString() @@ -9,7 +9,7 @@ export class CreateProductDto { @IsNotEmpty() description: string; - @IsNumber() + @IsInt() @IsNotEmpty() price: number; @@ -23,8 +23,7 @@ export class CreateProductDto { tags?: string[]; @IsOptional() - @IsNumber() - @IsNotEmpty() + @IsInt() quantity?: number; @IsOptional() diff --git a/src/products/dto/update-product.dto.ts b/src/products/dto/update-product.dto.ts index a6adc80..1e7f22f 100644 --- a/src/products/dto/update-product.dto.ts +++ b/src/products/dto/update-product.dto.ts @@ -1,4 +1,4 @@ -import { IsString, IsNumber, IsOptional, IsArray } from 'class-validator'; +import { IsString, IsNumber, IsOptional, IsArray, IsInt, isInt } from 'class-validator'; export class UpdateProductDto { @IsOptional() @@ -10,7 +10,7 @@ export class UpdateProductDto { description?: string; @IsOptional() - @IsNumber() + @IsInt() price?: number; @IsOptional() @@ -23,7 +23,7 @@ export class UpdateProductDto { tags?: string[]; @IsOptional() - @IsNumber() + @IsInt() quantity?: number; @IsOptional() diff --git a/src/products/entities/product.entity.ts b/src/products/entities/product.entity.ts index c1210a5..e61aa86 100644 --- a/src/products/entities/product.entity.ts +++ b/src/products/entities/product.entity.ts @@ -15,7 +15,7 @@ export class Product extends Model { description: string; @Column({ - type: DataType.DECIMAL(10, 2), + type: DataType.INTEGER, allowNull: false, }) price: number; diff --git a/src/wallet/entities/wallet.entity.ts b/src/wallet/entities/wallet.entity.ts index 35e23b3..6c70b98 100644 --- a/src/wallet/entities/wallet.entity.ts +++ b/src/wallet/entities/wallet.entity.ts @@ -11,7 +11,7 @@ export class Wallet extends Model { user: User; @Column({ - type: DataType.DECIMAL(10, 2), + type: DataType.INTEGER, allowNull: false, defaultValue: 0, }) diff --git a/src/wallet/wallet.service.ts b/src/wallet/wallet.service.ts index 7e0b0cc..231ac6c 100644 --- a/src/wallet/wallet.service.ts +++ b/src/wallet/wallet.service.ts @@ -17,7 +17,7 @@ export class WalletService { const wallet = await this.walletModel.findOne({ where: { userId } }); if (wallet) { - wallet.balance += Number(amount); + wallet.balance += amount; await wallet.save(); return { message: "Balance updated successfully.", balance: wallet.balance }; } else {