From f03fadec246b496ff8f98179b13cb53dbf2ab7da Mon Sep 17 00:00:00 2001 From: Kolibri <66674482+Kolibri1990@users.noreply.github.com> Date: Wed, 24 Dec 2025 13:00:40 +0100 Subject: [PATCH] [NO-TASK] Add monthly volume --- .../core/buy-crypto/routes/buy/buy.service.ts | 15 ++++++++++++- .../buy-crypto/routes/swap/swap.service.ts | 20 ++++++++++++++++- .../core/sell-crypto/route/sell.service.ts | 15 ++++++++++++- .../user/models/user-data/user-data.entity.ts | 10 +++++++++ .../user/models/user/dto/user-dto.mapper.ts | 6 ++--- .../generic/user/models/user/dto/user.dto.ts | 3 +++ .../generic/user/models/user/user.entity.ts | 9 ++++++++ .../generic/user/models/user/user.service.ts | 22 ++++++++++++++----- 8 files changed, 88 insertions(+), 12 deletions(-) diff --git a/src/subdomains/core/buy-crypto/routes/buy/buy.service.ts b/src/subdomains/core/buy-crypto/routes/buy/buy.service.ts index 4843d3b864..86d62e56e7 100644 --- a/src/subdomains/core/buy-crypto/routes/buy/buy.service.ts +++ b/src/subdomains/core/buy-crypto/routes/buy/buy.service.ts @@ -73,7 +73,9 @@ export class BuyService { select: ['id', 'user'], }); const userVolume = await this.getUserVolume(user.id); - await this.userService.updateBuyVolume(user.id, userVolume.volume, userVolume.annualVolume); + const monthlyVolume = await this.getMonthlyVolume(user.id); + + await this.userService.updateBuyVolume(user.id, userVolume.volume, userVolume.annualVolume, monthlyVolume.volume); } async getUserVolume(userId: number): Promise<{ volume: number; annualVolume: number }> { @@ -85,6 +87,17 @@ export class BuyService { .getRawOne<{ volume: number; annualVolume: number }>(); } + async getMonthlyVolume(userId: number): Promise<{ volume: number }> { + return this.buyRepo + .createQueryBuilder('buy') + .select('SUM(volume)', 'volume') + .where('userId = :id', { id: userId }) + .andWhere('buy.created >= :startOfMonth', { + startOfMonth: new Date(new Date().getFullYear(), new Date().getMonth(), 1), + }) + .getRawOne<{ volume: number }>(); + } + async getTotalVolume(): Promise { return this.buyRepo .createQueryBuilder('buy') diff --git a/src/subdomains/core/buy-crypto/routes/swap/swap.service.ts b/src/subdomains/core/buy-crypto/routes/swap/swap.service.ts index 59f05fbdde..0f9d02df7e 100644 --- a/src/subdomains/core/buy-crypto/routes/swap/swap.service.ts +++ b/src/subdomains/core/buy-crypto/routes/swap/swap.service.ts @@ -94,7 +94,14 @@ export class SwapService { select: ['id', 'user'], }); const userVolume = await this.getUserVolume(user.id); - await this.userService.updateCryptoVolume(user.id, userVolume.volume, userVolume.annualVolume); + const monthlyVolume = await this.getMonthlyVolume(user.id); + + await this.userService.updateCryptoVolume( + user.id, + userVolume.volume, + userVolume.annualVolume, + monthlyVolume.volume, + ); } async getUserVolume(userId: number): Promise<{ volume: number; annualVolume: number }> { @@ -106,6 +113,17 @@ export class SwapService { .getRawOne<{ volume: number; annualVolume: number }>(); } + async getMonthlyVolume(userId: number): Promise<{ volume: number }> { + return this.swapRepo + .createQueryBuilder('crypto') + .select('SUM(volume)', 'volume') + .where('userId = :id', { id: userId }) + .andWhere('crypto.created >= :startOfMonth', { + startOfMonth: new Date(new Date().getFullYear(), new Date().getMonth(), 1), + }) + .getRawOne<{ volume: number }>(); + } + async getTotalVolume(): Promise { return this.swapRepo .createQueryBuilder('crypto') diff --git a/src/subdomains/core/sell-crypto/route/sell.service.ts b/src/subdomains/core/sell-crypto/route/sell.service.ts index 48970f728d..02a127802c 100644 --- a/src/subdomains/core/sell-crypto/route/sell.service.ts +++ b/src/subdomains/core/sell-crypto/route/sell.service.ts @@ -284,7 +284,9 @@ export class SellService { select: ['id', 'user'], }); const userVolume = await this.getUserVolume(user.id); - await this.userService.updateSellVolume(user.id, userVolume.volume, userVolume.annualVolume); + const monthlyVolume = await this.getMonthlyVolume(user.id); + + await this.userService.updateSellVolume(user.id, userVolume.volume, userVolume.annualVolume, monthlyVolume.volume); } async getUserVolume(userId: number): Promise<{ volume: number; annualVolume: number }> { @@ -296,6 +298,17 @@ export class SellService { .getRawOne<{ volume: number; annualVolume: number }>(); } + async getMonthlyVolume(userId: number): Promise<{ volume: number }> { + return this.sellRepo + .createQueryBuilder('sell') + .select('SUM(volume)', 'volume') + .where('userId = :id', { id: userId }) + .andWhere('sell.created >= :startOfMonth', { + startOfMonth: new Date(new Date().getFullYear(), new Date().getMonth(), 1), + }) + .getRawOne<{ volume: number }>(); + } + async getTotalVolume(): Promise { return this.sellRepo .createQueryBuilder('sell') diff --git a/src/subdomains/generic/user/models/user-data/user-data.entity.ts b/src/subdomains/generic/user/models/user-data/user-data.entity.ts index 92ae538de6..743e0c3152 100644 --- a/src/subdomains/generic/user/models/user-data/user-data.entity.ts +++ b/src/subdomains/generic/user/models/user-data/user-data.entity.ts @@ -293,18 +293,28 @@ export class UserData extends IEntity { apiFilterCT?: string; // Volumes + + @Column({ type: 'float', default: 0 }) + monthlyBuyVolume: number; // CHF + @Column({ type: 'float', default: 0 }) annualBuyVolume: number; // CHF @Column({ type: 'float', default: 0 }) buyVolume: number; // CHF + @Column({ type: 'float', default: 0 }) + monthlySellVolume: number; // CHF + @Column({ type: 'float', default: 0 }) annualSellVolume: number; // CHF @Column({ type: 'float', default: 0 }) sellVolume: number; // CHF + @Column({ type: 'float', default: 0 }) + monthlyCryptoVolume: number; // CHF + @Column({ type: 'float', default: 0 }) annualCryptoVolume: number; // CHF diff --git a/src/subdomains/generic/user/models/user/dto/user-dto.mapper.ts b/src/subdomains/generic/user/models/user/dto/user-dto.mapper.ts index 0efdbab538..e1d70390ff 100644 --- a/src/subdomains/generic/user/models/user/dto/user-dto.mapper.ts +++ b/src/subdomains/generic/user/models/user/dto/user-dto.mapper.ts @@ -62,9 +62,9 @@ export class UserDtoMapper { private static mapVolumes(user: UserData | User): VolumesDto { const dto: VolumesDto = { - buy: { total: user.buyVolume, annual: user.annualBuyVolume }, - sell: { total: user.sellVolume, annual: user.annualSellVolume }, - swap: { total: user.cryptoVolume, annual: user.annualCryptoVolume }, + buy: { total: user.buyVolume, annual: user.annualBuyVolume, monthly: user.monthlyBuyVolume }, + sell: { total: user.sellVolume, annual: user.annualSellVolume, monthly: user.monthlySellVolume }, + swap: { total: user.cryptoVolume, annual: user.annualCryptoVolume, monthly: user.monthlyCryptoVolume }, }; return Object.assign(new VolumesDto(), dto); diff --git a/src/subdomains/generic/user/models/user/dto/user.dto.ts b/src/subdomains/generic/user/models/user/dto/user.dto.ts index 130dd84a95..d73b86e376 100644 --- a/src/subdomains/generic/user/models/user/dto/user.dto.ts +++ b/src/subdomains/generic/user/models/user/dto/user.dto.ts @@ -13,6 +13,9 @@ export class VolumeInformation { @ApiProperty() annual: number; + + @ApiProperty() + monthly: number; } export class TradingLimit { diff --git a/src/subdomains/generic/user/models/user/user.entity.ts b/src/subdomains/generic/user/models/user/user.entity.ts index 8ddea97a29..8b150f0d7a 100644 --- a/src/subdomains/generic/user/models/user/user.entity.ts +++ b/src/subdomains/generic/user/models/user/user.entity.ts @@ -67,18 +67,27 @@ export class User extends IEntity { @Column({ length: 256, nullable: true }) apiFilterCT?: string; + @Column({ type: 'float', default: 0 }) + monthlyBuyVolume: number; // CHF + @Column({ type: 'float', default: 0 }) annualBuyVolume: number; // CHF @Column({ type: 'float', default: 0 }) buyVolume: number; // CHF + @Column({ type: 'float', default: 0 }) + monthlySellVolume: number; // CHF + @Column({ type: 'float', default: 0 }) annualSellVolume: number; // CHF @Column({ type: 'float', default: 0 }) sellVolume: number; // CHF + @Column({ type: 'float', default: 0 }) + monthlyCryptoVolume: number; // CHF + @Column({ type: 'float', default: 0 }) annualCryptoVolume: number; // CHF diff --git a/src/subdomains/generic/user/models/user/user.service.ts b/src/subdomains/generic/user/models/user/user.service.ts index 16c75e928a..6d4d773248 100644 --- a/src/subdomains/generic/user/models/user/user.service.ts +++ b/src/subdomains/generic/user/models/user/user.service.ts @@ -378,28 +378,38 @@ export class UserService { await this.userRepo.update({ annualSellVolume: Not(0) }, { annualSellVolume: 0 }); } - async updateBuyVolume(userId: number, volume: number, annualVolume: number): Promise { + @DfxCron(CronExpression.EVERY_1ST_DAY_OF_MONTH_AT_MIDNIGHT) + async resetMonthVolumes(): Promise { + await this.userRepo.update({ monthlyBuyVolume: Not(0) }, { monthlyBuyVolume: 0 }); + await this.userRepo.update({ monthlySellVolume: Not(0) }, { monthlySellVolume: 0 }); + await this.userRepo.update({ monthlyCryptoVolume: Not(0) }, { monthlyCryptoVolume: 0 }); + } + + async updateBuyVolume(userId: number, volume: number, annualVolume: number, monthlyVolume: number): Promise { await this.userRepo.update(userId, { buyVolume: Util.round(volume, Config.defaultVolumeDecimal), annualBuyVolume: Util.round(annualVolume, Config.defaultVolumeDecimal), + monthlyBuyVolume: Util.round(monthlyVolume, Config.defaultVolumeDecimal), }); await this.updateUserDataVolume(userId); } - async updateCryptoVolume(userId: number, volume: number, annualVolume: number): Promise { + async updateCryptoVolume(userId: number, volume: number, annualVolume: number, monthlyVolume: number): Promise { await this.userRepo.update(userId, { cryptoVolume: Util.round(volume, Config.defaultVolumeDecimal), annualCryptoVolume: Util.round(annualVolume, Config.defaultVolumeDecimal), + monthlyCryptoVolume: Util.round(monthlyVolume, Config.defaultVolumeDecimal), }); await this.updateUserDataVolume(userId); } - async updateSellVolume(userId: number, volume: number, annualVolume: number): Promise { + async updateSellVolume(userId: number, volume: number, annualVolume: number, monthlyVolume: number): Promise { await this.userRepo.update(userId, { sellVolume: Util.round(volume, Config.defaultVolumeDecimal), annualSellVolume: Util.round(annualVolume, Config.defaultVolumeDecimal), + monthlySellVolume: Util.round(monthlyVolume, Config.defaultVolumeDecimal), }); await this.updateUserDataVolume(userId); @@ -614,9 +624,9 @@ export class UserService { user.buyVolume + user.sellVolume + user.cryptoVolume >= Config.support.blackSquad.limit ? Config.support.blackSquad.link : undefined, - buyVolume: { total: user.buyVolume, annual: user.annualBuyVolume }, - sellVolume: { total: user.sellVolume, annual: user.annualSellVolume }, - cryptoVolume: { total: user.cryptoVolume, annual: user.annualCryptoVolume }, + buyVolume: { total: user.buyVolume, annual: user.annualBuyVolume, monthly: user.monthlyBuyVolume }, + sellVolume: { total: user.sellVolume, annual: user.annualSellVolume, monthly: user.monthlySellVolume }, + cryptoVolume: { total: user.cryptoVolume, annual: user.annualCryptoVolume, monthly: user.monthlyCryptoVolume }, stakingBalance: 0, }; }