Fix price issues in models and enhance payment system

master
nicekid1 2 months ago
parent d0cb571c40
commit 871fda173b
  1. 17
      migrations/20250104112403-create-product.js
  2. 41
      migrations/20250105062732-create-invoice.js
  3. 8
      migrations/20250105063054-create-cart.js
  4. 43
      migrations/20250108065213-create-wallet.js
  5. 4
      src/cart/dto/add-to-cart.dto.ts
  6. 2
      src/cart/entities/cart.entity.ts
  7. 2
      src/invoice/entities/invoice.entity.ts
  8. 4
      src/invoice/invoice.service.ts
  9. 28
      src/payment/payment.controller.ts
  10. 3
      src/payment/payment.module.ts
  11. 1
      src/payment/payment.service.ts
  12. 7
      src/products/dto/create-product.dto.ts
  13. 6
      src/products/dto/update-product.dto.ts
  14. 2
      src/products/entities/product.entity.ts
  15. 2
      src/wallet/entities/wallet.entity.ts
  16. 2
      src/wallet/wallet.service.ts

@ -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');
},
};

@ -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');
},
};

@ -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: {

@ -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');
},
};

@ -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;

@ -33,7 +33,7 @@ export class Cart extends Model<Cart> {
quantity: number;
@Column({
type: DataType.DECIMAL(10, 2),
type: DataType.INTEGER,
allowNull: true,
})
productPrice: number;

@ -23,7 +23,7 @@ export class Invoice extends Model<Invoice> {
carts: Cart[];
@Column({
type: DataType.FLOAT,
type: DataType.INTEGER,
allowNull: false,
})
totalPaymentAmount: number;

@ -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<Invoice> {
async getInvoiceByUser(userId: number): Promise<Invoice> {
try {
if (!userId ) {
throw new HttpException("User ID are required.", HttpStatus.BAD_REQUEST);

@ -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}`);
}
}
}

@ -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],
})

@ -42,7 +42,6 @@ export class PaymentService {
Amount: amount,
Authority: authority,
});
if (result.status === 100) {
return result.RefID;
} else {

@ -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()

@ -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()

@ -15,7 +15,7 @@ export class Product extends Model<Product> {
description: string;
@Column({
type: DataType.DECIMAL(10, 2),
type: DataType.INTEGER,
allowNull: false,
})
price: number;

@ -11,7 +11,7 @@ export class Wallet extends Model<Wallet> {
user: User;
@Column({
type: DataType.DECIMAL(10, 2),
type: DataType.INTEGER,
allowNull: false,
defaultValue: 0,
})

@ -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 {

Loading…
Cancel
Save