paymnet methods cards new table
This commit is contained in:
@@ -0,0 +1,103 @@
|
|||||||
|
import { Migration } from '@mikro-orm/migrations';
|
||||||
|
|
||||||
|
export class Migration20260627120000_add_payment_method_cards_table extends Migration {
|
||||||
|
|
||||||
|
override async up(): Promise<void> {
|
||||||
|
this.addSql(`
|
||||||
|
create table "payment_method_cards" (
|
||||||
|
"id" char(26) not null,
|
||||||
|
"created_at" timestamptz not null default now(),
|
||||||
|
"updated_at" timestamptz not null default now(),
|
||||||
|
"deleted_at" timestamptz null,
|
||||||
|
"payment_method_id" char(26) not null,
|
||||||
|
"card_number" varchar(255) not null,
|
||||||
|
"owner" varchar(255) not null,
|
||||||
|
constraint "payment_method_cards_pkey" primary key ("id")
|
||||||
|
);
|
||||||
|
`);
|
||||||
|
this.addSql(`create index "payment_method_cards_payment_method_id_index" on "payment_method_cards" ("payment_method_id");`);
|
||||||
|
this.addSql(`create index "payment_method_cards_deleted_at_index" on "payment_method_cards" ("deleted_at");`);
|
||||||
|
this.addSql(`create index "payment_method_cards_created_at_index" on "payment_method_cards" ("created_at");`);
|
||||||
|
this.addSql(`
|
||||||
|
alter table "payment_method_cards"
|
||||||
|
add constraint "payment_method_cards_payment_method_id_foreign"
|
||||||
|
foreign key ("payment_method_id") references "payment_methods" ("id")
|
||||||
|
on update cascade on delete cascade;
|
||||||
|
`);
|
||||||
|
|
||||||
|
this.addSql(`
|
||||||
|
insert into "payment_method_cards" ("id", "created_at", "updated_at", "payment_method_id", "card_number", "owner")
|
||||||
|
select substring(replace(gen_random_uuid()::text, '-', ''), 1, 26), now(), now(), "id", "card_number", "card_owner"
|
||||||
|
from "payment_methods"
|
||||||
|
where "card_number" is not null and "card_owner" is not null;
|
||||||
|
`);
|
||||||
|
this.addSql(`
|
||||||
|
insert into "payment_method_cards" ("id", "created_at", "updated_at", "payment_method_id", "card_number", "owner")
|
||||||
|
select substring(replace(gen_random_uuid()::text, '-', ''), 1, 26), now(), now(), "id", "card_number2", "card_owner2"
|
||||||
|
from "payment_methods"
|
||||||
|
where "card_number2" is not null and "card_owner2" is not null;
|
||||||
|
`);
|
||||||
|
this.addSql(`
|
||||||
|
insert into "payment_method_cards" ("id", "created_at", "updated_at", "payment_method_id", "card_number", "owner")
|
||||||
|
select substring(replace(gen_random_uuid()::text, '-', ''), 1, 26), now(), now(), "id", "card_number3", "card_owner3"
|
||||||
|
from "payment_methods"
|
||||||
|
where "card_number3" is not null and "card_owner3" is not null;
|
||||||
|
`);
|
||||||
|
|
||||||
|
this.addSql(`
|
||||||
|
alter table "payment_methods"
|
||||||
|
drop column "card_number",
|
||||||
|
drop column "card_number2",
|
||||||
|
drop column "card_number3",
|
||||||
|
drop column "card_owner",
|
||||||
|
drop column "card_owner2",
|
||||||
|
drop column "card_owner3";
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
|
||||||
|
override async down(): Promise<void> {
|
||||||
|
this.addSql(`
|
||||||
|
alter table "payment_methods"
|
||||||
|
add column "card_number" varchar(255) null,
|
||||||
|
add column "card_number2" varchar(255) null,
|
||||||
|
add column "card_number3" varchar(255) null,
|
||||||
|
add column "card_owner" varchar(255) null,
|
||||||
|
add column "card_owner2" varchar(255) null,
|
||||||
|
add column "card_owner3" varchar(255) null;
|
||||||
|
`);
|
||||||
|
|
||||||
|
this.addSql(`
|
||||||
|
update "payment_methods" pm
|
||||||
|
set
|
||||||
|
"card_number" = c1."card_number",
|
||||||
|
"card_owner" = c1."owner",
|
||||||
|
"card_number2" = c2."card_number",
|
||||||
|
"card_owner2" = c2."owner",
|
||||||
|
"card_number3" = c3."card_number",
|
||||||
|
"card_owner3" = c3."owner"
|
||||||
|
from (
|
||||||
|
select distinct on ("payment_method_id") *
|
||||||
|
from "payment_method_cards"
|
||||||
|
order by "payment_method_id", "created_at"
|
||||||
|
) c1
|
||||||
|
left join lateral (
|
||||||
|
select *
|
||||||
|
from "payment_method_cards"
|
||||||
|
where "payment_method_id" = c1."payment_method_id"
|
||||||
|
order by "created_at"
|
||||||
|
offset 1 limit 1
|
||||||
|
) c2 on true
|
||||||
|
left join lateral (
|
||||||
|
select *
|
||||||
|
from "payment_method_cards"
|
||||||
|
where "payment_method_id" = c1."payment_method_id"
|
||||||
|
order by "created_at"
|
||||||
|
offset 2 limit 1
|
||||||
|
) c3 on true
|
||||||
|
where pm."id" = c1."payment_method_id";
|
||||||
|
`);
|
||||||
|
|
||||||
|
this.addSql(`drop table if exists "payment_method_cards" cascade;`);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
import { IsString, IsOptional, IsBoolean, IsNumber, IsEnum, ValidateIf, IsNotEmpty } from 'class-validator';
|
import { IsString, IsOptional, IsBoolean, IsNumber, IsEnum, ValidateIf, IsArray, ValidateNested, ArrayMinSize } from 'class-validator';
|
||||||
import { ApiProperty } from '@nestjs/swagger';
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { Type } from 'class-transformer';
|
||||||
import { PaymentMethodEnum, PaymentGatewayEnum } from '../interface/payment';
|
import { PaymentMethodEnum, PaymentGatewayEnum } from '../interface/payment';
|
||||||
|
import { PaymentMethodCardDto } from './payment-method-card.dto';
|
||||||
|
|
||||||
export class CreatePaymentMethodDto {
|
export class CreatePaymentMethodDto {
|
||||||
|
|
||||||
@@ -18,36 +20,13 @@ export class CreatePaymentMethodDto {
|
|||||||
@IsString()
|
@IsString()
|
||||||
description?: string;
|
description?: string;
|
||||||
|
|
||||||
@ApiProperty({ description: 'Card number for card-to-card payments', required: false })
|
@ApiProperty({ description: 'Cards for card-to-card payments', type: [PaymentMethodCardDto], required: false })
|
||||||
@IsOptional()
|
|
||||||
@IsString()
|
|
||||||
cardNumber?: string;
|
|
||||||
|
|
||||||
@ApiProperty({ description: 'Second card number for card-to-card payments', required: false })
|
|
||||||
@IsOptional()
|
|
||||||
@IsString()
|
|
||||||
cardNumber2?: string;
|
|
||||||
|
|
||||||
@ApiProperty({ description: 'Third card number for card-to-card payments', required: false })
|
|
||||||
@IsOptional()
|
|
||||||
@IsString()
|
|
||||||
cardNumber3?: string;
|
|
||||||
|
|
||||||
@ApiProperty({ description: 'Card owner name for card-to-card payments', required: false })
|
|
||||||
@ValidateIf((dto: CreatePaymentMethodDto) => dto.method === PaymentMethodEnum.CreditCard)
|
@ValidateIf((dto: CreatePaymentMethodDto) => dto.method === PaymentMethodEnum.CreditCard)
|
||||||
@IsNotEmpty()
|
@IsArray()
|
||||||
@IsString()
|
@ArrayMinSize(1)
|
||||||
cardOwner?: string;
|
@ValidateNested({ each: true })
|
||||||
|
@Type(() => PaymentMethodCardDto)
|
||||||
@ApiProperty({ description: 'Second card owner name for card-to-card payments', required: false })
|
cards?: PaymentMethodCardDto[];
|
||||||
@IsOptional()
|
|
||||||
@IsString()
|
|
||||||
cardOwner2?: string;
|
|
||||||
|
|
||||||
@ApiProperty({ description: 'Third card owner name for card-to-card payments', required: false })
|
|
||||||
@IsOptional()
|
|
||||||
@IsString()
|
|
||||||
cardOwner3?: string;
|
|
||||||
|
|
||||||
@ApiProperty({ description: 'Is payment method enabled', required: false, default: true })
|
@ApiProperty({ description: 'Is payment method enabled', required: false, default: true })
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { IsNotEmpty, IsString } from 'class-validator';
|
||||||
|
|
||||||
|
export class PaymentMethodCardDto {
|
||||||
|
@ApiProperty({ description: 'Card number for card-to-card payments' })
|
||||||
|
@IsNotEmpty()
|
||||||
|
@IsString()
|
||||||
|
cardNumber!: string;
|
||||||
|
|
||||||
|
@ApiProperty({ description: 'Card owner name for card-to-card payments' })
|
||||||
|
@IsNotEmpty()
|
||||||
|
@IsString()
|
||||||
|
owner!: string;
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import { Entity, Index, ManyToOne, Property } from '@mikro-orm/core';
|
||||||
|
import { BaseEntity } from '../../../common/entities/base.entity';
|
||||||
|
import { PaymentMethod } from './payment-method.entity';
|
||||||
|
|
||||||
|
@Entity({ tableName: 'payment_method_cards' })
|
||||||
|
@Index({ properties: ['paymentMethod'] })
|
||||||
|
export class PaymentMethodCard extends BaseEntity {
|
||||||
|
@ManyToOne(() => PaymentMethod)
|
||||||
|
paymentMethod!: PaymentMethod;
|
||||||
|
|
||||||
|
@Property()
|
||||||
|
cardNumber!: string;
|
||||||
|
|
||||||
|
@Property()
|
||||||
|
owner!: string;
|
||||||
|
}
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
import { Entity, Enum, Index, ManyToOne, Property, Unique } from '@mikro-orm/core';
|
import { Cascade, Collection, Entity, Enum, Index, ManyToOne, OneToMany, Property, Unique } from '@mikro-orm/core';
|
||||||
import { BaseEntity } from '../../../common/entities/base.entity';
|
import { BaseEntity } from '../../../common/entities/base.entity';
|
||||||
import { Restaurant } from 'src/modules/restaurants/entities/restaurant.entity';
|
import { Restaurant } from 'src/modules/restaurants/entities/restaurant.entity';
|
||||||
import { PaymentGatewayEnum, PaymentMethodEnum } from '../interface/payment';
|
import { PaymentGatewayEnum, PaymentMethodEnum } from '../interface/payment';
|
||||||
|
import { PaymentMethodCard } from './payment-method-card.entity';
|
||||||
|
|
||||||
@Entity({ tableName: 'payment_methods' })
|
@Entity({ tableName: 'payment_methods' })
|
||||||
@Unique({ properties: ['restaurant', 'method'] })
|
@Unique({ properties: ['restaurant', 'method'] })
|
||||||
@@ -20,23 +21,11 @@ export class PaymentMethod extends BaseEntity {
|
|||||||
@Property({ nullable: true })
|
@Property({ nullable: true })
|
||||||
description?: string;
|
description?: string;
|
||||||
|
|
||||||
@Property({ nullable: true })
|
@OneToMany(() => PaymentMethodCard, card => card.paymentMethod, {
|
||||||
cardNumber?: string;
|
cascade: [Cascade.ALL],
|
||||||
|
orphanRemoval: true,
|
||||||
@Property({ nullable: true })
|
})
|
||||||
cardNumber2?: string;
|
cards = new Collection<PaymentMethodCard>(this);
|
||||||
|
|
||||||
@Property({ nullable: true })
|
|
||||||
cardNumber3?: string;
|
|
||||||
|
|
||||||
@Property({ nullable: true })
|
|
||||||
cardOwner?: string;
|
|
||||||
|
|
||||||
@Property({ nullable: true })
|
|
||||||
cardOwner2?: string;
|
|
||||||
|
|
||||||
@Property({ nullable: true })
|
|
||||||
cardOwner3?: string;
|
|
||||||
|
|
||||||
@Property({ default: true })
|
@Property({ default: true })
|
||||||
enabled: boolean = true;
|
enabled: boolean = true;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { Module, forwardRef } from '@nestjs/common';
|
|||||||
import { PaymentsService } from './services/payments.service';
|
import { PaymentsService } from './services/payments.service';
|
||||||
import { MikroOrmModule } from '@mikro-orm/nestjs';
|
import { MikroOrmModule } from '@mikro-orm/nestjs';
|
||||||
import { PaymentMethod } from './entities/payment-method.entity';
|
import { PaymentMethod } from './entities/payment-method.entity';
|
||||||
|
import { PaymentMethodCard } from './entities/payment-method-card.entity';
|
||||||
import { PaymentMethodRepository } from './repositories/payment-method.repository';
|
import { PaymentMethodRepository } from './repositories/payment-method.repository';
|
||||||
import { PaymentMethodService } from './services/payment-method.service';
|
import { PaymentMethodService } from './services/payment-method.service';
|
||||||
import { Restaurant } from '../restaurants/entities/restaurant.entity';
|
import { Restaurant } from '../restaurants/entities/restaurant.entity';
|
||||||
@@ -20,7 +21,7 @@ import { OrdersModule } from '../orders/orders.module';
|
|||||||
import { RestaurantsModule } from '../restaurants/restaurants.module';
|
import { RestaurantsModule } from '../restaurants/restaurants.module';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [MikroOrmModule.forFeature([PaymentMethod, Payment, Restaurant]),
|
imports: [MikroOrmModule.forFeature([PaymentMethod, PaymentMethodCard, Payment, Restaurant]),
|
||||||
AuthModule, JwtModule, InventoryModule, AdminModule, NotificationsModule,
|
AuthModule, JwtModule, InventoryModule, AdminModule, NotificationsModule,
|
||||||
RestaurantsModule,
|
RestaurantsModule,
|
||||||
forwardRef(() => OrdersModule)],
|
forwardRef(() => OrdersModule)],
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
import { BadRequestException, Injectable, NotFoundException } from '@nestjs/common';
|
import { BadRequestException, Injectable, NotFoundException } from '@nestjs/common';
|
||||||
import { EntityManager } from '@mikro-orm/postgresql';
|
import { EntityManager } from '@mikro-orm/postgresql';
|
||||||
import { PaymentMethod } from '../entities/payment-method.entity';
|
import { PaymentMethod } from '../entities/payment-method.entity';
|
||||||
|
import { PaymentMethodCard } from '../entities/payment-method-card.entity';
|
||||||
import { PaymentMethodRepository } from '../repositories/payment-method.repository';
|
import { PaymentMethodRepository } from '../repositories/payment-method.repository';
|
||||||
import { CreatePaymentMethodDto } from '../dto/create-payment-method.dto';
|
import { CreatePaymentMethodDto } from '../dto/create-payment-method.dto';
|
||||||
import { UpdatePaymentMethodDto } from '../dto/update-payment-method.dto';
|
import { UpdatePaymentMethodDto } from '../dto/update-payment-method.dto';
|
||||||
|
import { PaymentMethodCardDto } from '../dto/payment-method-card.dto';
|
||||||
import { RequiredEntityData } from '@mikro-orm/core';
|
import { RequiredEntityData } from '@mikro-orm/core';
|
||||||
import { PaymentMessage } from 'src/common/enums/message.enum';
|
import { PaymentMessage } from 'src/common/enums/message.enum';
|
||||||
import { RestaurantsService } from 'src/modules/restaurants/providers/restaurants.service';
|
import { RestaurantsService } from 'src/modules/restaurants/providers/restaurants.service';
|
||||||
@@ -18,20 +20,23 @@ export class PaymentMethodService {
|
|||||||
) { }
|
) { }
|
||||||
|
|
||||||
async create(restId: string, createPaymentMethodDto: CreatePaymentMethodDto): Promise<PaymentMethod> {
|
async create(restId: string, createPaymentMethodDto: CreatePaymentMethodDto): Promise<PaymentMethod> {
|
||||||
// Check if restaurant exists
|
|
||||||
const restaurant = await this.restaurantsService.findOneOrFail(restId);
|
const restaurant = await this.restaurantsService.findOneOrFail(restId);
|
||||||
this.assertCreditCardOwner(createPaymentMethodDto.method, createPaymentMethodDto.cardOwner);
|
const { cards, ...paymentMethodData } = createPaymentMethodDto;
|
||||||
|
this.assertCreditCards(createPaymentMethodDto.method, cards);
|
||||||
|
|
||||||
const paymentMethod = this.paymentMethodRepository.create({
|
const paymentMethod = this.paymentMethodRepository.create({
|
||||||
restaurant,
|
restaurant,
|
||||||
...createPaymentMethodDto,
|
...paymentMethodData,
|
||||||
} as unknown as RequiredEntityData<PaymentMethod>);
|
} as unknown as RequiredEntityData<PaymentMethod>);
|
||||||
|
|
||||||
|
this.assignCards(paymentMethod, cards);
|
||||||
|
|
||||||
await this.em.persistAndFlush(paymentMethod);
|
await this.em.persistAndFlush(paymentMethod);
|
||||||
return paymentMethod;
|
return paymentMethod;
|
||||||
}
|
}
|
||||||
|
|
||||||
async findOneOrFail(id: string): Promise<PaymentMethod> {
|
async findOneOrFail(id: string): Promise<PaymentMethod> {
|
||||||
const paymentMethod = await this.paymentMethodRepository.findOne({ id }, { populate: ['restaurant'] });
|
const paymentMethod = await this.paymentMethodRepository.findOne({ id }, { populate: ['restaurant', 'cards'] });
|
||||||
if (!paymentMethod) {
|
if (!paymentMethod) {
|
||||||
throw new NotFoundException(PaymentMessage.PAYMENT_METHOD_NOT_FOUND);
|
throw new NotFoundException(PaymentMessage.PAYMENT_METHOD_NOT_FOUND);
|
||||||
}
|
}
|
||||||
@@ -39,19 +44,55 @@ export class PaymentMethodService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async findByRestaurant(restaurantId: string): Promise<PaymentMethod[]> {
|
async findByRestaurant(restaurantId: string): Promise<PaymentMethod[]> {
|
||||||
return this.paymentMethodRepository.find({ restaurant: { id: restaurantId } }, { populate: ['restaurant'] });
|
return this.paymentMethodRepository.find(
|
||||||
|
{ restaurant: { id: restaurantId } },
|
||||||
|
{ populate: ['restaurant', 'cards'] },
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async update(id: string, updatePaymentMethodDto: UpdatePaymentMethodDto): Promise<PaymentMethod> {
|
async update(id: string, updatePaymentMethodDto: UpdatePaymentMethodDto): Promise<PaymentMethod> {
|
||||||
const paymentMethod = await this.findOneOrFail(id);
|
const paymentMethod = await this.findOneOrFail(id);
|
||||||
this.em.assign(paymentMethod, updatePaymentMethodDto);
|
const { cards, ...paymentMethodData } = updatePaymentMethodDto;
|
||||||
this.assertCreditCardOwner(paymentMethod.method, paymentMethod.cardOwner);
|
|
||||||
|
this.em.assign(paymentMethod, paymentMethodData);
|
||||||
|
|
||||||
|
if (cards !== undefined) {
|
||||||
|
this.assignCards(paymentMethod, cards);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.assertCreditCards(
|
||||||
|
paymentMethod.method,
|
||||||
|
paymentMethod.cards.getItems().map(card => ({ cardNumber: card.cardNumber, owner: card.owner })),
|
||||||
|
);
|
||||||
|
|
||||||
await this.em.flush();
|
await this.em.flush();
|
||||||
return paymentMethod;
|
return paymentMethod;
|
||||||
}
|
}
|
||||||
|
|
||||||
private assertCreditCardOwner(method: PaymentMethodEnum, cardOwner?: string): void {
|
private assignCards(paymentMethod: PaymentMethod, cards?: PaymentMethodCardDto[]): void {
|
||||||
if (method === PaymentMethodEnum.CreditCard && !cardOwner?.trim()) {
|
if (!cards) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
paymentMethod.cards.removeAll();
|
||||||
|
for (const card of cards) {
|
||||||
|
paymentMethod.cards.add(
|
||||||
|
this.em.create(PaymentMethodCard, {
|
||||||
|
paymentMethod,
|
||||||
|
cardNumber: card.cardNumber,
|
||||||
|
owner: card.owner,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private assertCreditCards(method: PaymentMethodEnum, cards?: PaymentMethodCardDto[]): void {
|
||||||
|
if (method !== PaymentMethodEnum.CreditCard) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const hasValidCard = cards?.some(card => card.cardNumber?.trim() && card.owner?.trim());
|
||||||
|
if (!hasValidCard) {
|
||||||
throw new BadRequestException(PaymentMessage.CARD_OWNER_REQUIRED);
|
throw new BadRequestException(PaymentMessage.CARD_OWNER_REQUIRED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -61,6 +102,4 @@ export class PaymentMethodService {
|
|||||||
await this.em.removeAndFlush(paymentMethod);
|
await this.em.removeAndFlush(paymentMethod);
|
||||||
return paymentMethod;
|
return paymentMethod;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ export class PaymentsService {
|
|||||||
const order = await this.em.findOne(
|
const order = await this.em.findOne(
|
||||||
Order,
|
Order,
|
||||||
{ id: orderId },
|
{ id: orderId },
|
||||||
{ populate: ['user', 'restaurant', 'paymentMethod', 'paymentMethod.restaurant'] },
|
{ populate: ['user', 'restaurant', 'paymentMethod', 'paymentMethod.restaurant', 'paymentMethod.cards'] },
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!order) {
|
if (!order) {
|
||||||
@@ -79,13 +79,6 @@ export class PaymentsService {
|
|||||||
if (!pm.restaurant?.domain) throw new BadRequestException(PaymentMessage.RESTAURANT_DOMAIN_REQUIRED);
|
if (!pm.restaurant?.domain) throw new BadRequestException(PaymentMessage.RESTAURANT_DOMAIN_REQUIRED);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pm.method === PaymentMethodEnum.CreditCard && !pm.cardNumber) {
|
|
||||||
throw new BadRequestException(PaymentMessage.CARD_NUMBER_REQUIRED);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pm.method === PaymentMethodEnum.CreditCard && !pm.cardOwner?.trim()) {
|
|
||||||
throw new BadRequestException(PaymentMessage.CARD_OWNER_REQUIRED);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
order,
|
order,
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { PaymentMethodEnum, PaymentGatewayEnum } from '../../modules/payments/interface/payment';
|
import { PaymentMethodEnum, PaymentGatewayEnum } from '../../modules/payments/interface/payment';
|
||||||
|
import { PaymentMethodCardDto } from '../../modules/payments/dto/payment-method-card.dto';
|
||||||
|
|
||||||
export interface PaymentMethodData {
|
export interface PaymentMethodData {
|
||||||
method: PaymentMethodEnum;
|
method: PaymentMethodEnum;
|
||||||
@@ -6,12 +7,7 @@ export interface PaymentMethodData {
|
|||||||
enabled: boolean;
|
enabled: boolean;
|
||||||
order: number;
|
order: number;
|
||||||
gateway: PaymentGatewayEnum | null;
|
gateway: PaymentGatewayEnum | null;
|
||||||
cardNumber?: string;
|
cards?: PaymentMethodCardDto[];
|
||||||
cardNumber2?: string;
|
|
||||||
cardNumber3?: string;
|
|
||||||
cardOwner?: string;
|
|
||||||
cardOwner2?: string;
|
|
||||||
cardOwner3?: string;
|
|
||||||
merchantId?: string;
|
merchantId?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,7 +40,11 @@ export const paymentMethodsData: PaymentMethodData[] = [
|
|||||||
enabled: true,
|
enabled: true,
|
||||||
order: 4,
|
order: 4,
|
||||||
gateway: null,
|
gateway: null,
|
||||||
cardNumber: '6037991234567890',
|
cards: [
|
||||||
cardOwner: 'صاحب کارت',
|
{
|
||||||
|
cardNumber: '6037991234567890',
|
||||||
|
owner: 'صاحب کارت',
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -1,18 +1,41 @@
|
|||||||
import type { EntityManager } from '@mikro-orm/core';
|
import type { EntityManager } from '@mikro-orm/core';
|
||||||
import { PaymentMethod } from '../modules/payments/entities/payment-method.entity';
|
import { PaymentMethod } from '../modules/payments/entities/payment-method.entity';
|
||||||
|
import { PaymentMethodCard } from '../modules/payments/entities/payment-method-card.entity';
|
||||||
import type { Restaurant } from '../modules/restaurants/entities/restaurant.entity';
|
import type { Restaurant } from '../modules/restaurants/entities/restaurant.entity';
|
||||||
import { paymentMethodsData } from './data/payment-methods.data';
|
import { paymentMethodsData } from './data/payment-methods.data';
|
||||||
|
|
||||||
|
function cardsMatch(
|
||||||
|
existing: PaymentMethodCard[],
|
||||||
|
expected: { cardNumber: string; owner: string }[] | undefined,
|
||||||
|
): boolean {
|
||||||
|
if (!expected?.length) {
|
||||||
|
return existing.length === 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (existing.length !== expected.length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return expected.every((card, index) => {
|
||||||
|
const current = existing[index];
|
||||||
|
return current.cardNumber === card.cardNumber && current.owner === card.owner;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export class PaymentMethodsSeeder {
|
export class PaymentMethodsSeeder {
|
||||||
async run(em: EntityManager, restaurants: Restaurant[]): Promise<void> {
|
async run(em: EntityManager, restaurants: Restaurant[]): Promise<void> {
|
||||||
for (const restaurant of restaurants) {
|
for (const restaurant of restaurants) {
|
||||||
if (!restaurant) continue;
|
if (!restaurant) continue;
|
||||||
|
|
||||||
for (const methodData of paymentMethodsData) {
|
for (const methodData of paymentMethodsData) {
|
||||||
const existing = await em.findOne(PaymentMethod, {
|
const existing = await em.findOne(
|
||||||
restaurant: { id: restaurant.id },
|
PaymentMethod,
|
||||||
method: methodData.method,
|
{
|
||||||
});
|
restaurant: { id: restaurant.id },
|
||||||
|
method: methodData.method,
|
||||||
|
},
|
||||||
|
{ populate: ['cards'] },
|
||||||
|
);
|
||||||
|
|
||||||
if (!existing) {
|
if (!existing) {
|
||||||
const paymentMethod = em.create(PaymentMethod, {
|
const paymentMethod = em.create(PaymentMethod, {
|
||||||
@@ -22,27 +45,27 @@ export class PaymentMethodsSeeder {
|
|||||||
enabled: methodData.enabled,
|
enabled: methodData.enabled,
|
||||||
order: methodData.order,
|
order: methodData.order,
|
||||||
gateway: methodData.gateway,
|
gateway: methodData.gateway,
|
||||||
cardNumber: methodData.cardNumber,
|
|
||||||
cardNumber2: methodData.cardNumber2,
|
|
||||||
cardNumber3: methodData.cardNumber3,
|
|
||||||
cardOwner: methodData.cardOwner,
|
|
||||||
cardOwner2: methodData.cardOwner2,
|
|
||||||
cardOwner3: methodData.cardOwner3,
|
|
||||||
merchantId: methodData.merchantId,
|
merchantId: methodData.merchantId,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
for (const card of methodData.cards ?? []) {
|
||||||
|
paymentMethod.cards.add(
|
||||||
|
em.create(PaymentMethodCard, {
|
||||||
|
paymentMethod,
|
||||||
|
cardNumber: card.cardNumber,
|
||||||
|
owner: card.owner,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
em.persist(paymentMethod);
|
em.persist(paymentMethod);
|
||||||
} else {
|
} else {
|
||||||
// Update existing payment method if needed
|
const existingCards = existing.cards.getItems();
|
||||||
if (
|
if (
|
||||||
existing.description !== methodData.description ||
|
existing.description !== methodData.description ||
|
||||||
existing.enabled !== methodData.enabled ||
|
existing.enabled !== methodData.enabled ||
|
||||||
existing.order !== methodData.order ||
|
existing.order !== methodData.order ||
|
||||||
existing.cardNumber !== methodData.cardNumber ||
|
!cardsMatch(existingCards, methodData.cards)
|
||||||
existing.cardNumber2 !== methodData.cardNumber2 ||
|
|
||||||
existing.cardNumber3 !== methodData.cardNumber3 ||
|
|
||||||
existing.cardOwner !== methodData.cardOwner ||
|
|
||||||
existing.cardOwner2 !== methodData.cardOwner2 ||
|
|
||||||
existing.cardOwner3 !== methodData.cardOwner3
|
|
||||||
) {
|
) {
|
||||||
existing.description = methodData.description;
|
existing.description = methodData.description;
|
||||||
existing.enabled = methodData.enabled;
|
existing.enabled = methodData.enabled;
|
||||||
@@ -50,27 +73,21 @@ export class PaymentMethodsSeeder {
|
|||||||
if (methodData.gateway !== undefined) {
|
if (methodData.gateway !== undefined) {
|
||||||
existing.gateway = methodData.gateway;
|
existing.gateway = methodData.gateway;
|
||||||
}
|
}
|
||||||
if (methodData.cardNumber !== undefined) {
|
|
||||||
existing.cardNumber = methodData.cardNumber;
|
|
||||||
}
|
|
||||||
if (methodData.cardNumber2 !== undefined) {
|
|
||||||
existing.cardNumber2 = methodData.cardNumber2;
|
|
||||||
}
|
|
||||||
if (methodData.cardNumber3 !== undefined) {
|
|
||||||
existing.cardNumber3 = methodData.cardNumber3;
|
|
||||||
}
|
|
||||||
if (methodData.cardOwner !== undefined) {
|
|
||||||
existing.cardOwner = methodData.cardOwner;
|
|
||||||
}
|
|
||||||
if (methodData.cardOwner2 !== undefined) {
|
|
||||||
existing.cardOwner2 = methodData.cardOwner2;
|
|
||||||
}
|
|
||||||
if (methodData.cardOwner3 !== undefined) {
|
|
||||||
existing.cardOwner3 = methodData.cardOwner3;
|
|
||||||
}
|
|
||||||
if (methodData.merchantId !== undefined) {
|
if (methodData.merchantId !== undefined) {
|
||||||
existing.merchantId = methodData.merchantId;
|
existing.merchantId = methodData.merchantId;
|
||||||
}
|
}
|
||||||
|
if (methodData.cards !== undefined) {
|
||||||
|
existing.cards.removeAll();
|
||||||
|
for (const card of methodData.cards) {
|
||||||
|
existing.cards.add(
|
||||||
|
em.create(PaymentMethodCard, {
|
||||||
|
paymentMethod: existing,
|
||||||
|
cardNumber: card.cardNumber,
|
||||||
|
owner: card.owner,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
em.persist(existing);
|
em.persist(existing);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user