mirror of
https://github.com/HamzaSha1/zod-backend.git
synced 2025-11-26 00:24:54 +00:00
feat: view child active cards
This commit is contained in:
@ -8,7 +8,7 @@ import { CardEmbossingDetailsResponseDto } from '~/common/modules/neoleap/dtos/r
|
|||||||
import { ApiDataResponse } from '~/core/decorators';
|
import { ApiDataResponse } from '~/core/decorators';
|
||||||
import { ResponseFactory } from '~/core/utils';
|
import { ResponseFactory } from '~/core/utils';
|
||||||
import { FundIbanRequestDto } from '../dtos/requests';
|
import { FundIbanRequestDto } from '../dtos/requests';
|
||||||
import { AccountIbanResponseDto, CardResponseDto } from '../dtos/responses';
|
import { AccountIbanResponseDto, CardResponseDto, ChildCardResponseDto } from '../dtos/responses';
|
||||||
import { CardService } from '../services';
|
import { CardService } from '../services';
|
||||||
|
|
||||||
@Controller('cards')
|
@Controller('cards')
|
||||||
@ -25,6 +25,15 @@ export class CardsController {
|
|||||||
return ResponseFactory.data(new CardResponseDto(card));
|
return ResponseFactory.data(new CardResponseDto(card));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Get('child-cards')
|
||||||
|
@UseGuards(RolesGuard)
|
||||||
|
@AllowedRoles(Roles.GUARDIAN)
|
||||||
|
@ApiDataResponse(ChildCardResponseDto)
|
||||||
|
async getChildCards(@AuthenticatedUser() { sub }: IJwtPayload) {
|
||||||
|
const cards = await this.cardService.getChildCards(sub);
|
||||||
|
return ResponseFactory.data(cards.map((card) => new ChildCardResponseDto(card)));
|
||||||
|
}
|
||||||
|
|
||||||
@Get('current')
|
@Get('current')
|
||||||
@ApiDataResponse(CardResponseDto)
|
@ApiDataResponse(CardResponseDto)
|
||||||
async getCurrentCard(@AuthenticatedUser() { sub }: IJwtPayload) {
|
async getCurrentCard(@AuthenticatedUser() { sub }: IJwtPayload) {
|
||||||
|
|||||||
48
src/card/dtos/responses/child-card.response.dto.ts
Normal file
48
src/card/dtos/responses/child-card.response.dto.ts
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { Card } from '~/card/entities';
|
||||||
|
import { Gender } from '~/customer/enums';
|
||||||
|
import { DocumentMetaResponseDto } from '~/document/dtos/response';
|
||||||
|
import { CardResponseDto } from './card.response.dto';
|
||||||
|
|
||||||
|
class JuniorInfo {
|
||||||
|
@ApiProperty({ example: 'id' })
|
||||||
|
id!: string;
|
||||||
|
|
||||||
|
@ApiProperty({ example: 'FirstName' })
|
||||||
|
firstName!: string;
|
||||||
|
|
||||||
|
@ApiProperty({ example: 'LastName' })
|
||||||
|
lastName!: string;
|
||||||
|
|
||||||
|
@ApiProperty({ example: 'test@example.com' })
|
||||||
|
email!: string;
|
||||||
|
|
||||||
|
@ApiProperty({ enum: Gender, example: Gender.MALE })
|
||||||
|
gender!: Gender;
|
||||||
|
|
||||||
|
@ApiProperty({ example: '2000-01-01' })
|
||||||
|
dateOfBirth!: Date;
|
||||||
|
|
||||||
|
@ApiProperty({ example: DocumentMetaResponseDto, nullable: true })
|
||||||
|
profilePicture!: DocumentMetaResponseDto | null;
|
||||||
|
|
||||||
|
constructor(card: Card) {
|
||||||
|
this.id = card.customer?.junior?.id;
|
||||||
|
this.firstName = card.customer?.firstName;
|
||||||
|
this.lastName = card.customer?.lastName;
|
||||||
|
this.email = card.customer?.user?.email;
|
||||||
|
this.gender = card.customer.gender;
|
||||||
|
this.profilePicture = card.customer?.user?.profilePicture
|
||||||
|
? new DocumentMetaResponseDto(card.customer.user.profilePicture)
|
||||||
|
: null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export class ChildCardResponseDto extends CardResponseDto {
|
||||||
|
@ApiProperty({ type: JuniorInfo })
|
||||||
|
junior!: JuniorInfo | null;
|
||||||
|
|
||||||
|
constructor(card: Card) {
|
||||||
|
super(card);
|
||||||
|
this.junior = card.customer?.junior ? new JuniorInfo(card) : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,2 +1,3 @@
|
|||||||
export * from './account-iban.response.dto';
|
export * from './account-iban.response.dto';
|
||||||
export * from './card.response.dto';
|
export * from './card.response.dto';
|
||||||
|
export * from './child-card.response.dto';
|
||||||
|
|||||||
@ -14,14 +14,14 @@ export class CardRepository {
|
|||||||
accountId: string,
|
accountId: string,
|
||||||
card: CreateApplicationResponse,
|
card: CreateApplicationResponse,
|
||||||
cardColor?: CardColors,
|
cardColor?: CardColors,
|
||||||
isChildCard = false,
|
parentId?: string,
|
||||||
): Promise<Card> {
|
): Promise<Card> {
|
||||||
return this.cardRepository.save(
|
return this.cardRepository.save(
|
||||||
this.cardRepository.create({
|
this.cardRepository.create({
|
||||||
customerId: customerId,
|
customerId: customerId,
|
||||||
expiry: card.expiryDate,
|
expiry: card.expiryDate,
|
||||||
cardReference: card.cardId,
|
cardReference: card.cardId,
|
||||||
customerType: isChildCard ? CustomerType.CHILD : CustomerType.PARENT,
|
customerType: parentId ? CustomerType.CHILD : CustomerType.PARENT,
|
||||||
firstSixDigits: card.firstSixDigits,
|
firstSixDigits: card.firstSixDigits,
|
||||||
lastFourDigits: card.lastFourDigits,
|
lastFourDigits: card.lastFourDigits,
|
||||||
color: cardColor ? cardColor : CardColors.DEEP_MAGENTA,
|
color: cardColor ? cardColor : CardColors.DEEP_MAGENTA,
|
||||||
@ -29,10 +29,18 @@ export class CardRepository {
|
|||||||
issuer: CardIssuers.NEOLEAP,
|
issuer: CardIssuers.NEOLEAP,
|
||||||
accountId: accountId,
|
accountId: accountId,
|
||||||
vpan: card.vpan,
|
vpan: card.vpan,
|
||||||
|
parentId,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
findChildCardsForGuardian(guardianId: string): Promise<Card[]> {
|
||||||
|
return this.cardRepository.find({
|
||||||
|
where: { parentId: guardianId, customerType: CustomerType.CHILD },
|
||||||
|
relations: ['account', 'customer', 'customer.user', 'customer.user.profilePicture', 'customer.junior'],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
getCardById(id: string): Promise<Card | null> {
|
getCardById(id: string): Promise<Card | null> {
|
||||||
return this.cardRepository.findOne({ where: { id }, relations: ['account'] });
|
return this.cardRepository.findOne({ where: { id }, relations: ['account'] });
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { BadRequestException, forwardRef, Inject, Injectable } from '@nestjs/common';
|
import { BadRequestException, forwardRef, Inject, Injectable, Logger } from '@nestjs/common';
|
||||||
import Decimal from 'decimal.js';
|
import Decimal from 'decimal.js';
|
||||||
import { Transactional } from 'typeorm-transactional';
|
import { Transactional } from 'typeorm-transactional';
|
||||||
import { AccountCardStatusChangedWebhookRequest } from '~/common/modules/neoleap/dtos/requests';
|
import { AccountCardStatusChangedWebhookRequest } from '~/common/modules/neoleap/dtos/requests';
|
||||||
@ -6,6 +6,7 @@ import { NeoLeapService } from '~/common/modules/neoleap/services';
|
|||||||
import { Customer } from '~/customer/entities';
|
import { Customer } from '~/customer/entities';
|
||||||
import { KycStatus } from '~/customer/enums';
|
import { KycStatus } from '~/customer/enums';
|
||||||
import { CustomerService } from '~/customer/services';
|
import { CustomerService } from '~/customer/services';
|
||||||
|
import { OciService } from '~/document/services';
|
||||||
import { Card } from '../entities';
|
import { Card } from '../entities';
|
||||||
import { CardColors } from '../enums';
|
import { CardColors } from '../enums';
|
||||||
import { CardStatusMapper } from '../mappers/card-status.mapper';
|
import { CardStatusMapper } from '../mappers/card-status.mapper';
|
||||||
@ -15,9 +16,11 @@ import { TransactionService } from './transaction.service';
|
|||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class CardService {
|
export class CardService {
|
||||||
|
private readonly logger = new Logger(CardService.name);
|
||||||
constructor(
|
constructor(
|
||||||
private readonly cardRepository: CardRepository,
|
private readonly cardRepository: CardRepository,
|
||||||
private readonly accountService: AccountService,
|
private readonly accountService: AccountService,
|
||||||
|
private readonly ociService: OciService,
|
||||||
@Inject(forwardRef(() => TransactionService)) private readonly transactionService: TransactionService,
|
@Inject(forwardRef(() => TransactionService)) private readonly transactionService: TransactionService,
|
||||||
@Inject(forwardRef(() => NeoLeapService)) private readonly neoleapService: NeoLeapService,
|
@Inject(forwardRef(() => NeoLeapService)) private readonly neoleapService: NeoLeapService,
|
||||||
@Inject(forwardRef(() => CustomerService)) private readonly customerService: CustomerService,
|
@Inject(forwardRef(() => CustomerService)) private readonly customerService: CustomerService,
|
||||||
@ -42,6 +45,12 @@ export class CardService {
|
|||||||
return this.getCardById(createdCard.id);
|
return this.getCardById(createdCard.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getChildCards(guardianId: string): Promise<Card[]> {
|
||||||
|
const cards = await this.cardRepository.findChildCardsForGuardian(guardianId);
|
||||||
|
await this.prepareJuniorImages(cards);
|
||||||
|
return cards;
|
||||||
|
}
|
||||||
|
|
||||||
async createCardForChild(parentCustomer: Customer, childCustomer: Customer, cardColor: CardColors, cardPin: string) {
|
async createCardForChild(parentCustomer: Customer, childCustomer: Customer, cardColor: CardColors, cardPin: string) {
|
||||||
const data = await this.neoleapService.createChildCard(parentCustomer, childCustomer, cardPin);
|
const data = await this.neoleapService.createChildCard(parentCustomer, childCustomer, cardPin);
|
||||||
const createdCard = await this.cardRepository.createCard(
|
const createdCard = await this.cardRepository.createCard(
|
||||||
@ -49,7 +58,7 @@ export class CardService {
|
|||||||
parentCustomer.cards[0].account.id,
|
parentCustomer.cards[0].account.id,
|
||||||
data,
|
data,
|
||||||
cardColor,
|
cardColor,
|
||||||
true,
|
parentCustomer.id,
|
||||||
);
|
);
|
||||||
|
|
||||||
return this.getCardById(createdCard.id);
|
return this.getCardById(createdCard.id);
|
||||||
@ -140,4 +149,17 @@ export class CardService {
|
|||||||
fundIban(iban: string, amount: number) {
|
fundIban(iban: string, amount: number) {
|
||||||
return this.accountService.fundIban(iban, amount);
|
return this.accountService.fundIban(iban, amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async prepareJuniorImages(cards: Card[]) {
|
||||||
|
this.logger.log(`Preparing junior images`);
|
||||||
|
await Promise.all(
|
||||||
|
cards.map(async (card) => {
|
||||||
|
const profilePicture = card.customer?.user?.profilePicture;
|
||||||
|
|
||||||
|
if (profilePicture) {
|
||||||
|
profilePicture.url = await this.ociService.generatePreSignedUrl(profilePicture);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -33,10 +33,10 @@ export class JuniorResponseDto {
|
|||||||
profilePicture!: DocumentMetaResponseDto | null;
|
profilePicture!: DocumentMetaResponseDto | null;
|
||||||
|
|
||||||
@ApiProperty({ example: 2000.0, description: 'The available balance' })
|
@ApiProperty({ example: 2000.0, description: 'The available balance' })
|
||||||
availableBalance!: number;
|
availableBalance!: number | null;
|
||||||
|
|
||||||
constructor(junior: Junior) {
|
constructor(junior: Junior) {
|
||||||
const card = junior.customer.cards?.[0];
|
const card = junior.customer?.cards?.[0];
|
||||||
this.id = junior.id;
|
this.id = junior.id;
|
||||||
this.firstName = junior.customer.firstName;
|
this.firstName = junior.customer.firstName;
|
||||||
this.lastName = junior.customer.lastName;
|
this.lastName = junior.customer.lastName;
|
||||||
@ -45,7 +45,7 @@ export class JuniorResponseDto {
|
|||||||
this.dateOfBirth = junior.customer.dateOfBirth;
|
this.dateOfBirth = junior.customer.dateOfBirth;
|
||||||
this.relationship = junior.relationship;
|
this.relationship = junior.relationship;
|
||||||
this.guardianRelationship = GuardianRelationship[junior.relationship];
|
this.guardianRelationship = GuardianRelationship[junior.relationship];
|
||||||
this.availableBalance = card ? Math.min(card.limit, card.account.balance) : 0;
|
this.availableBalance = card ? Math.min(card.limit, card.account.balance) : null;
|
||||||
this.profilePicture = junior.customer.user.profilePicture
|
this.profilePicture = junior.customer.user.profilePicture
|
||||||
? new DocumentMetaResponseDto(junior.customer.user.profilePicture)
|
? new DocumentMetaResponseDto(junior.customer.user.profilePicture)
|
||||||
: null;
|
: null;
|
||||||
|
|||||||
Reference in New Issue
Block a user