diff --git a/src/products/entities/transaction.entity.ts b/src/products/entities/transaction.entity.ts new file mode 100644 index 0000000..10e27e6 --- /dev/null +++ b/src/products/entities/transaction.entity.ts @@ -0,0 +1,19 @@ +import { Model, Table, Column, ForeignKey, BelongsTo, DataType } from 'sequelize-typescript'; +import { Wallet } from './wallet.entity'; + +@Table +export class Transaction extends Model { + @ForeignKey(() => Wallet) + @Column + walletId: number; + + @BelongsTo(() => Wallet, { onDelete: 'CASCADE' }) + wallet: Wallet; + + @Column({ + type: DataType.STRING, + allowNull: false, + defaultValue: "0", + }) + amount: string; +} diff --git a/src/products/entities/wallet.entity.ts b/src/products/entities/wallet.entity.ts new file mode 100644 index 0000000..6c70b98 --- /dev/null +++ b/src/products/entities/wallet.entity.ts @@ -0,0 +1,19 @@ +import { Model, Table, Column, ForeignKey, BelongsTo, DataType } from 'sequelize-typescript'; +import { User } from '../../users/entities/user.entity'; + +@Table +export class Wallet extends Model { + @ForeignKey(() => User) + @Column + userId: number; + + @BelongsTo(() => User, { onDelete: 'CASCADE' }) + user: User; + + @Column({ + type: DataType.INTEGER, + allowNull: false, + defaultValue: 0, + }) + balance: number; +} diff --git a/src/products/products.controller.ts b/src/products/products.controller.ts index 918e980..654c642 100644 --- a/src/products/products.controller.ts +++ b/src/products/products.controller.ts @@ -7,10 +7,15 @@ import { RoleGuard } from "src/guard/role.guard"; import { AddToCartDto } from "./dto/cart/add-to-cart.dto"; import { JwtAuthGuard } from "src/guard/auth.guard"; import { UpdateCartDto } from "./dto/cart/update-cart.dto"; +import { PaymentService } from "src/payment/payment.service"; @Controller("shop") export class ProductsController { - constructor(private readonly productsService: ProductsService) {} + constructor( + private readonly productsService: ProductsService, + private paymentService: PaymentService, + + ) {} ////////////////////////////////////////products//////////////////////////////////////// //create a new product (admin) @@ -50,22 +55,22 @@ export class ProductsController { async remove(@Param("id") id: string): Promise<{ message: string }> { return this.productsService.remove(id); } - ////////////////////////////////////////////cart/////////////////////////////////////////////////// - //create and a item to cart by user + ////////////////////////////////////////cart//////////////////////////////////////// + //create and a item to cart (user) @UseGuards(JwtAuthGuard) @Post("cart") async createAndAddItemToCart(@Body() addToCartDto: AddToCartDto, @Request() req: any) { const userId = req.user.id; return this.productsService.createAndAddItemToCart({ ...addToCartDto, userId }); } - //get user cart items + //get user cart items(user) @UseGuards(JwtAuthGuard) @Get("cart") async getUserOpenCart(@Request() req: any) { const userId = req.user.id; return this.productsService.getUserOpenCart(userId); } - //edit quantity an item in cart by user + //edit quantity an item in cart (user) @UseGuards(JwtAuthGuard) @Patch("cart/:productId") async updateCart(@Param("productId") productId: number, @Body() updateCartDto: UpdateCartDto, @Request() req: any) { @@ -76,31 +81,63 @@ export class ProductsController { updatedCart, }; } - //delete an item from cart by user + //delete an item from cart (user) @UseGuards(JwtAuthGuard) @Delete("cart/:productId") async removeFromCart(@Param("productId") productId: number, @Request() req: any) { const userId = req.user.id; return await this.productsService.removeFromCart(userId, productId); } - //clear whole cart by user + //clear whole cart (user) @UseGuards(JwtAuthGuard) @Get("cart/clear-cart") async clearCart(@Request() req: any) { const userId = req.user.id; return await this.productsService.clearCart(userId); } - //get checkout process - @UseGuards(JwtAuthGuard) - @Get("cart/checkout") - async processOrder(@Request() req: any){ - const userId = req.user.id; - try { - const totalAmount = (await this.productsService.getUserOpenCart(userId)).totalPrice - const result = await this.productsService.processOrder(userId, totalAmount); - return result; - } catch (error) { - throw new HttpException(error.message || "Order processing failed.", HttpStatus.INTERNAL_SERVER_ERROR); - } + //get checkout process (user) + @UseGuards(JwtAuthGuard) + @Get("cart/checkout") + async processOrder(@Request() req: any) { + const userId = req.user.id; + try { + const totalAmount = (await this.productsService.getUserOpenCart(userId)).totalPrice; + const result = await this.productsService.processOrder(userId, totalAmount); + return result; + } catch (error) { + throw new HttpException(error.message || "Order processing failed.", HttpStatus.INTERNAL_SERVER_ERROR); } + } + ////////////////////////////////////////wallet//////////////////////////////////////// + //getting wallet balance (user) + @UseGuards(JwtAuthGuard) + @Get('wallet') + async getBalance(@Request() req) { + const userId = req.user.id; + return this.productsService.getBalance(userId); + } + //charging wallet (user) + @UseGuards(JwtAuthGuard) + @Post("wallet/charge") + async addBalance(@Body("amount") amount: number, @Request() req) { + const userId = req.user.id; + const callbackUrl = `http://localhost:3000/payment/verify?userId=${userId}&amount=${amount}`; + const paymentUrl = this.paymentService.requestPayment(amount, "Wallet Charge", callbackUrl); + return paymentUrl; + } + //get transaction (user) + @UseGuards(JwtAuthGuard) + @Get("wallet/transaction") + async getTransactionById(@Request() req) { + const userId = req.user.id; + return this.productsService.getTransactionById(userId); + } + //get specific user transaction (admin) + @UseGuards(RoleGuard) + @Get("wallet/transaction/:id") + async getTransactionByIdForAdmin(@Param("id") id: number) { + return this.productsService.getTransactionByIdForAdmin(id); + } + + } diff --git a/src/products/products.module.ts b/src/products/products.module.ts index 22ac746..9e0d594 100644 --- a/src/products/products.module.ts +++ b/src/products/products.module.ts @@ -10,9 +10,12 @@ import { JwtAuthGuard } from "src/guard/auth.guard"; import { Invoice } from "src/invoice/entities/invoice.entity"; import { InvoiceModule } from "src/invoice/invoice.module"; import { WalletModule } from "src/wallet/wallet.module"; +import { Wallet } from "./entities/wallet.entity"; +import { Transaction } from "./entities/transaction.entity"; +import { PaymentService } from "src/payment/payment.service"; @Module({ - imports: [SequelizeModule.forFeature([Product,Cart,Invoice]), + imports: [SequelizeModule.forFeature([Product,Cart,Invoice,Wallet, Transaction]), JwtModule.register({ secret: process.env.JWT_SECRET, signOptions: { expiresIn: '1h' }, @@ -21,6 +24,6 @@ import { WalletModule } from "src/wallet/wallet.module"; InvoiceModule ], controllers: [ProductsController], - providers: [ProductsService,RoleGuard,JwtAuthGuard], + providers: [ProductsService,RoleGuard,JwtAuthGuard,PaymentService], }) export class ProductsModule {} diff --git a/src/products/products.service.ts b/src/products/products.service.ts index 3cb8baa..68558f0 100644 --- a/src/products/products.service.ts +++ b/src/products/products.service.ts @@ -9,6 +9,8 @@ import { Cart } from "./entities/cart.entity"; import { Invoice } from "src/invoice/entities/invoice.entity"; import { InvoiceService } from "src/invoice/invoice.service"; import { WalletService } from "src/wallet/WalletService"; +import { Wallet } from "./entities/wallet.entity"; +import { Transaction } from "./entities/transaction.entity"; @Injectable() export class ProductsService { @@ -16,6 +18,8 @@ export class ProductsService { @InjectModel(Product) private readonly productModel: typeof Product, @InjectModel(Cart) private readonly cartModel: typeof Cart, @InjectModel(Invoice) private readonly invoiceModel: typeof Invoice, + @InjectModel(Wallet) private walletModel: typeof Wallet, + @InjectModel(Transaction) private transactionModel: typeof Transaction, private invoiceService: InvoiceService, private walletService: WalletService, ) {} @@ -42,7 +46,6 @@ export class ProductsService { throw new HttpException("An error occurred while creating or updating the product.", HttpStatus.INTERNAL_SERVER_ERROR); } } - // find a product by id async findOne(id: string): Promise { try { @@ -61,7 +64,6 @@ export class ProductsService { throw new HttpException("An unexpected error occurred while fetching the product.", HttpStatus.INTERNAL_SERVER_ERROR); } } - // list of all product async findAll( search?: string, @@ -114,7 +116,6 @@ export class ProductsService { throw new HttpException("An unexpected error occurred while retrieving products.", HttpStatus.INTERNAL_SERVER_ERROR); } } - // update a product info async update(id: string, updateProductDto: UpdateProductDto): Promise { const product = await this.productModel.findByPk(id); @@ -176,7 +177,6 @@ export class ProductsService { throw new HttpException("An error occurred while updating the product.", HttpStatus.INTERNAL_SERVER_ERROR); } } - // delete a product async remove(id: string): Promise<{ message: string }> { try { @@ -335,7 +335,7 @@ export class ProductsService { where: { userId, status: "open" }, }); return { message: "Cart cleared successfully" }; - }//order + } //order async processOrder(userId: number, totalAmount: number): Promise<{ message: string; invoice: Invoice }> { try { const carts = await this.cartModel.findAll({ where: { userId, status: "open" } }); @@ -395,5 +395,46 @@ export class ProductsService { } } } + ///////////////////////////////////////////wallet////////////////////////////////////////////// + //get wallet info + async getWalletInfo(userId: number) { + const wallet = await this.walletModel.findOne({ where: { userId } }); + + if (!wallet) { + const newWallet = await this.walletModel.create({ userId, balance: 0 }); + return { walletId: newWallet.id, userId: newWallet.userId, balance: newWallet.balance }; + } + + return { walletId: wallet.id, userId: wallet.userId, balance: wallet.balance }; + } + //get wallet balance + async getBalance(userId: number) { + const wallet = await this.walletModel.findOne({ where: { userId } }); + + if (!wallet) { + throw new HttpException("Wallet not found!", HttpStatus.NOT_FOUND); + } + return { balance: wallet.balance }; + } + //getting transaction + async getTransactionById(userId: number) { + const wallet = await this.getWalletInfo(userId); + if (!wallet) { + throw new HttpException("Wallet not found for the user.", HttpStatus.NOT_FOUND); + } + return await this.transactionModel.findAll({ + where: { walletId: wallet.walletId }, + }); + } + //getting transaction a user (admin) + async getTransactionByIdForAdmin(userId: number) { + const wallet = await this.getWalletInfo(userId); + if (!wallet) { + throw new HttpException("Wallet not found for the user.", HttpStatus.NOT_FOUND); + } + return await this.transactionModel.findAll({ + where: { walletId: wallet.walletId }, + }); + } }