From c96ff31be73b737837d86c0f36d84b1585c4e43a Mon Sep 17 00:00:00 2001 From: mahdi Date: Sun, 12 Jan 2025 09:16:22 +0330 Subject: [PATCH] Implement transaction module for storing wallet transactions --- src/app.module.ts | 6 ++++ src/core/constants/index.ts | 2 ++ src/core/database/database.providers.ts | 16 ++++++++- src/modules/users/entities/user.entity.ts | 4 +++ .../dto/create-wallets-transaction.dto.ts | 5 +++ .../entities/transaction-operation.entity.ts | 14 ++++++++ .../entities/wallets-transaction.entity.ts | 34 +++++++++++++++++++ .../wallets-transactions.controller.ts | 33 ++++++++++++++++++ .../wallets-transactions.module.ts | 11 ++++++ .../wallets-transactions.providers.ts | 9 +++++ .../wallets-transactions.service.ts | 31 +++++++++++++++++ src/modules/wallets/wallets.module.ts | 12 ++++++- src/modules/wallets/wallets.service.ts | 27 +++++++++++++-- 13 files changed, 200 insertions(+), 4 deletions(-) create mode 100644 src/modules/wallets-transactions/dto/create-wallets-transaction.dto.ts create mode 100644 src/modules/wallets-transactions/entities/transaction-operation.entity.ts create mode 100644 src/modules/wallets-transactions/entities/wallets-transaction.entity.ts create mode 100644 src/modules/wallets-transactions/wallets-transactions.controller.ts create mode 100644 src/modules/wallets-transactions/wallets-transactions.module.ts create mode 100644 src/modules/wallets-transactions/wallets-transactions.providers.ts create mode 100644 src/modules/wallets-transactions/wallets-transactions.service.ts diff --git a/src/app.module.ts b/src/app.module.ts index 3da81e1..9c08b73 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -9,6 +9,9 @@ import { ProductsModule } from './modules/products/products.module'; import { AuthModule } from './modules/auth/auth.module'; import { OrdersModule } from './modules/orders/orders.module'; import { WalletsModule } from './modules/wallets/wallets.module'; +import { WalletsTransactionsModule } from './modules/wallets-transactions/wallets-transactions.module'; +import { ReceiptsModule } from './modules/receipts/receipts.module'; +import { ShoppingCardsModule } from './modules/shopping-cards/shopping-cards.module'; @Module({ imports: [ @@ -19,6 +22,9 @@ import { WalletsModule } from './modules/wallets/wallets.module'; AuthModule, OrdersModule, WalletsModule, + WalletsTransactionsModule, + ReceiptsModule, + ShoppingCardsModule, ], controllers: [AppController, UsersController], providers: [AppService], diff --git a/src/core/constants/index.ts b/src/core/constants/index.ts index 518e7f0..977a3cd 100644 --- a/src/core/constants/index.ts +++ b/src/core/constants/index.ts @@ -7,3 +7,5 @@ export const PRODUCT_REPOSITORY = 'PRODUCT_REPOSITORY'; export const ORDER_REPOSITORY = 'ORDER_REPOSITORY'; export const ORDER_STATUSES_REPOSITORY = 'ORDER_STATUSES_REPOSITORY'; export const WALLET_REPOSITORY = 'WALLET_REPOSITORY'; +export const WALLET_TRANSACTIONS_REPOSITORY = 'WALLET_TRANSACTIONS_REPOSITORY'; +export const RECEIPT_REPOSITORY = 'RECEIPT_REPOSITORY'; diff --git a/src/core/database/database.providers.ts b/src/core/database/database.providers.ts index 804c2a0..8375cfa 100644 --- a/src/core/database/database.providers.ts +++ b/src/core/database/database.providers.ts @@ -6,6 +6,10 @@ import { Product } from 'src/modules/products/entities/product.entity'; import { OrderStatuses } from 'src/modules/orders/entities/order-status.entity'; import { Order } from 'src/modules/orders/entities/order.entity'; import { Wallet } from 'src/modules/wallets/entities/wallet.entity'; +import { TransactionOperations } from 'src/modules/wallets-transactions/entities/transaction-operation.entity'; +import { WalletsTransactions } from 'src/modules/wallets-transactions/entities/wallets-transaction.entity'; +import { Receipt } from 'src/modules/receipts/entities/receipt.entity'; +import { ShoppingCard } from 'src/modules/shopping-cards/entities/shopping-card.entity'; export const databaseProviders = [ { @@ -26,7 +30,17 @@ export const databaseProviders = [ config = databaseConfig.development; } const sequelize = new Sequelize(config); - sequelize.addModels([User, Product, Order, OrderStatuses, Wallet]); + sequelize.addModels([ + User, + Product, + Order, + OrderStatuses, + Wallet, + TransactionOperations, + WalletsTransactions, + Receipt, + ShoppingCard, + ]); await sequelize.sync(); return sequelize; }, diff --git a/src/modules/users/entities/user.entity.ts b/src/modules/users/entities/user.entity.ts index e35ecfd..2011faa 100644 --- a/src/modules/users/entities/user.entity.ts +++ b/src/modules/users/entities/user.entity.ts @@ -8,6 +8,7 @@ import { } from 'sequelize-typescript'; import { Order } from '../../orders/entities/order.entity'; import { Wallet } from 'src/modules/wallets/entities/wallet.entity'; +import { Receipt } from 'src/modules/receipts/entities/receipt.entity'; @Table({ tableName: 'users' }) export class User extends Model { @@ -67,4 +68,7 @@ export class User extends Model { @HasOne(() => Wallet) wallet: Wallet; + + @HasMany(() => Receipt) + receipts: Receipt[]; } diff --git a/src/modules/wallets-transactions/dto/create-wallets-transaction.dto.ts b/src/modules/wallets-transactions/dto/create-wallets-transaction.dto.ts new file mode 100644 index 0000000..61e728a --- /dev/null +++ b/src/modules/wallets-transactions/dto/create-wallets-transaction.dto.ts @@ -0,0 +1,5 @@ +export class CreateWalletsTransactionDto { + userId: number; + operation: number; + byAmount: number; +} diff --git a/src/modules/wallets-transactions/entities/transaction-operation.entity.ts b/src/modules/wallets-transactions/entities/transaction-operation.entity.ts new file mode 100644 index 0000000..2be1061 --- /dev/null +++ b/src/modules/wallets-transactions/entities/transaction-operation.entity.ts @@ -0,0 +1,14 @@ +import { Table, Column, Model, DataType, HasOne } from 'sequelize-typescript'; +import { WalletsTransactions } from './wallets-transaction.entity'; + +@Table({ tableName: 'transaction_operations', timestamps: false }) +export class TransactionOperations extends Model { + @Column({ + type: DataType.STRING, + allowNull: false, + }) + name: string; + + @HasOne(() => WalletsTransactions) + order: WalletsTransactions; +} diff --git a/src/modules/wallets-transactions/entities/wallets-transaction.entity.ts b/src/modules/wallets-transactions/entities/wallets-transaction.entity.ts new file mode 100644 index 0000000..24f8fb7 --- /dev/null +++ b/src/modules/wallets-transactions/entities/wallets-transaction.entity.ts @@ -0,0 +1,34 @@ +import { + Table, + Column, + Model, + DataType, + ForeignKey, + BelongsTo, +} from 'sequelize-typescript'; +import { User } from 'src/modules/users/entities/user.entity'; +import { TransactionOperations } from './transaction-operation.entity'; + +@Table({ tableName: 'wallets_transactions', updatedAt: false }) +export class WalletsTransactions extends Model { + @Column({ + type: DataType.FLOAT, + allowNull: false, + defaultValue: 0, + }) + byAmount: number; + + @ForeignKey(() => User) + @Column + userId: number; + + @BelongsTo(() => User) + user: User; + + @ForeignKey(() => TransactionOperations) + @Column + operation: number; + + @BelongsTo(() => TransactionOperations) + transactionOperations: TransactionOperations; +} diff --git a/src/modules/wallets-transactions/wallets-transactions.controller.ts b/src/modules/wallets-transactions/wallets-transactions.controller.ts new file mode 100644 index 0000000..2e0c06c --- /dev/null +++ b/src/modules/wallets-transactions/wallets-transactions.controller.ts @@ -0,0 +1,33 @@ +import { + Controller, + Get, + Post, + Body, + Patch, + Param, + Delete, +} from '@nestjs/common'; +import { WalletsTransactionsService } from './wallets-transactions.service'; +import { CreateWalletsTransactionDto } from './dto/create-wallets-transaction.dto'; + +@Controller('wallets-transactions') +export class WalletsTransactionsController { + constructor( + private readonly walletsTransactionsService: WalletsTransactionsService, + ) {} + + @Get() + findAll() { + return this.walletsTransactionsService.findAll(); + } + + @Get(':id') + findOne(@Param('id') id: number) { + return this.walletsTransactionsService.findOne(id); + } + + @Get('users/:id') + findByUser(@Param('id') id: number) { + return this.walletsTransactionsService.findByUser(id); + } +} diff --git a/src/modules/wallets-transactions/wallets-transactions.module.ts b/src/modules/wallets-transactions/wallets-transactions.module.ts new file mode 100644 index 0000000..fbd9a4c --- /dev/null +++ b/src/modules/wallets-transactions/wallets-transactions.module.ts @@ -0,0 +1,11 @@ +import { Module } from '@nestjs/common'; +import { WalletsTransactionsService } from './wallets-transactions.service'; +import { WalletsTransactionsController } from './wallets-transactions.controller'; +import { walletsTransactionsProviders } from './wallets-transactions.providers'; + +@Module({ + controllers: [WalletsTransactionsController], + providers: [WalletsTransactionsService, ...walletsTransactionsProviders], + exports: [WalletsTransactionsService], +}) +export class WalletsTransactionsModule {} diff --git a/src/modules/wallets-transactions/wallets-transactions.providers.ts b/src/modules/wallets-transactions/wallets-transactions.providers.ts new file mode 100644 index 0000000..00c6039 --- /dev/null +++ b/src/modules/wallets-transactions/wallets-transactions.providers.ts @@ -0,0 +1,9 @@ +import { WalletsTransactions } from './entities/wallets-transaction.entity'; +import { WALLET_TRANSACTIONS_REPOSITORY } from '../../core/constants'; + +export const walletsTransactionsProviders = [ + { + provide: WALLET_TRANSACTIONS_REPOSITORY, + useValue: WalletsTransactions, + }, +]; diff --git a/src/modules/wallets-transactions/wallets-transactions.service.ts b/src/modules/wallets-transactions/wallets-transactions.service.ts new file mode 100644 index 0000000..712965e --- /dev/null +++ b/src/modules/wallets-transactions/wallets-transactions.service.ts @@ -0,0 +1,31 @@ +import { Inject, Injectable } from '@nestjs/common'; +import { CreateWalletsTransactionDto } from './dto/create-wallets-transaction.dto'; +import { WALLET_TRANSACTIONS_REPOSITORY } from 'src/core/constants'; +import { WalletsTransactions } from './entities/wallets-transaction.entity'; + +@Injectable() +export class WalletsTransactionsService { + constructor( + @Inject(WALLET_TRANSACTIONS_REPOSITORY) + private readonly walletsTransactionsRepository: typeof WalletsTransactions, + ) {} + async create(createWalletsTransactionDto: CreateWalletsTransactionDto) { + return await this.walletsTransactionsRepository.create( + createWalletsTransactionDto, + ); + } + + async findAll() { + return await this.walletsTransactionsRepository.findAll(); + } + + async findOne(id: number) { + return await this.walletsTransactionsRepository.findAll({ where: { id } }); + } + + async findByUser(id: number) { + return await this.walletsTransactionsRepository.findAll({ + where: { userId: id }, + }); + } +} diff --git a/src/modules/wallets/wallets.module.ts b/src/modules/wallets/wallets.module.ts index a397c3f..678478c 100644 --- a/src/modules/wallets/wallets.module.ts +++ b/src/modules/wallets/wallets.module.ts @@ -2,10 +2,20 @@ import { Module } from '@nestjs/common'; import { WalletsService } from './wallets.service'; import { WalletsController } from './wallets.controller'; import { walletsProviders } from './wallets.providers'; +import { UsersService } from '../users/users.service'; +import { WalletsTransactionsModule } from '../wallets-transactions/wallets-transactions.module'; +import { UsersModule } from '../users/users.module'; +import { usersProviders } from '../users/users.providers'; @Module({ + imports: [WalletsTransactionsModule, UsersModule], controllers: [WalletsController], - providers: [WalletsService, ...walletsProviders], + providers: [ + WalletsService, + UsersService, + ...walletsProviders, + ...usersProviders, + ], exports: [WalletsService], }) export class WalletsModule {} diff --git a/src/modules/wallets/wallets.service.ts b/src/modules/wallets/wallets.service.ts index c25c5d1..3a44bed 100644 --- a/src/modules/wallets/wallets.service.ts +++ b/src/modules/wallets/wallets.service.ts @@ -4,11 +4,15 @@ import { WALLET_REPOSITORY } from 'src/core/constants'; import { Wallet } from './entities/wallet.entity'; import { User } from '../users/entities/user.entity'; import { UpdateWalletDto } from './dto/update-wallet.dto'; +import { WalletsTransactionsService } from '../wallets-transactions/wallets-transactions.service'; +import { UsersService } from '../users/users.service'; @Injectable() export class WalletsService { constructor( @Inject(WALLET_REPOSITORY) private readonly walletRepository: typeof Wallet, + private readonly usersService: UsersService, + private readonly walletsTransactionsService: WalletsTransactionsService, ) {} async getWallet(id: UUID) { @@ -29,7 +33,9 @@ export class WalletsService { const [wallet] = await this.getWallet(id); wallet.balance += amount; - return wallet.save(); + await wallet.save(); + + this.createTransaction(id, 1, amount); } async withdraw(id: UUID, updateWalletDto: UpdateWalletDto) { @@ -40,6 +46,23 @@ export class WalletsService { const [wallet] = await this.getWallet(id); wallet.balance -= amount; - return wallet.save(); + await wallet.save(); + + this.createTransaction(id, 2, amount); + } + + private async createTransaction( + id: UUID, + operation: number, + byAmount: number, + ) { + const [user] = await this.usersService.findOne(id); + + const transaction = { + operation: operation, + byAmount: byAmount, + userId: user.id, + }; + await this.walletsTransactionsService.create(transaction); } }