add card owner
deploy to danak / build_and_deploy (push) Has been cancelled

This commit is contained in:
2026-06-15 12:55:51 +03:30
parent 5a07ea13ed
commit fb7671338a
8 changed files with 47 additions and 4 deletions
@@ -0,0 +1,13 @@
import { Migration } from '@mikro-orm/migrations';
export class Migration20260615140000_add_card_owner_to_payment_methods extends Migration {
override async up(): Promise<void> {
this.addSql(`alter table "payment_methods" add column "card_owner" varchar(255) null;`);
}
override async down(): Promise<void> {
this.addSql(`alter table "payment_methods" drop column "card_owner";`);
}
}
+1
View File
@@ -745,6 +745,7 @@ export const enum PaymentMessage {
PAYMENT_METHOD_NOT_CASH = 'روش پرداخت نقدی نیست',
PAYMENT_METHOD_NOT_CREDIT_CARD = 'روش پرداخت کارت به کارت نیست',
CARD_NUMBER_REQUIRED = 'شماره کارت برای پرداخت کارت به کارت الزامی است',
CARD_OWNER_REQUIRED = 'نام صاحب کارت برای پرداخت کارت به کارت الزامی است',
PAYMENT_ALREADY_PAID = 'پرداخت قبلا انجام شده است',
EXISTING_PENDING_PAYMENT_MISMATCH = 'پرداخت در انتظار موجود با روش پرداخت سفارش مطابقت ندارد',
ZARINPAL_INVALID_RESPONSE = 'پاسخ نامعتبر از API زرین‌پال',
@@ -1,4 +1,4 @@
import { IsString, IsOptional, IsBoolean, IsNumber, IsEnum } from 'class-validator';
import { IsString, IsOptional, IsBoolean, IsNumber, IsEnum, ValidateIf, IsNotEmpty } from 'class-validator';
import { ApiProperty } from '@nestjs/swagger';
import { PaymentMethodEnum, PaymentGatewayEnum } from '../interface/payment';
@@ -23,6 +23,12 @@ export class CreatePaymentMethodDto {
@IsString()
cardNumber?: string;
@ApiProperty({ description: 'Card owner name for card-to-card payments', required: false })
@ValidateIf((dto: CreatePaymentMethodDto) => dto.method === PaymentMethodEnum.CreditCard)
@IsNotEmpty()
@IsString()
cardOwner?: string;
@ApiProperty({ description: 'Is payment method enabled', required: false, default: true })
@IsOptional()
@IsBoolean()
@@ -23,6 +23,9 @@ export class PaymentMethod extends BaseEntity {
@Property({ nullable: true })
cardNumber?: string;
@Property({ nullable: true })
cardOwner?: string;
@Property({ default: true })
enabled: boolean = true;
@@ -1,4 +1,4 @@
import { Injectable, NotFoundException, ConflictException } from '@nestjs/common';
import { BadRequestException, Injectable, NotFoundException } from '@nestjs/common';
import { EntityManager } from '@mikro-orm/postgresql';
import { PaymentMethod } from '../entities/payment-method.entity';
import { PaymentMethodRepository } from '../repositories/payment-method.repository';
@@ -7,6 +7,7 @@ import { UpdatePaymentMethodDto } from '../dto/update-payment-method.dto';
import { RequiredEntityData } from '@mikro-orm/core';
import { PaymentMessage } from 'src/common/enums/message.enum';
import { RestaurantsService } from 'src/modules/restaurants/providers/restaurants.service';
import { PaymentMethodEnum } from '../interface/payment';
@Injectable()
export class PaymentMethodService {
@@ -18,7 +19,8 @@ export class PaymentMethodService {
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 paymentMethod = this.paymentMethodRepository.create({
restaurant,
@@ -43,10 +45,17 @@ export class PaymentMethodService {
async update(id: string, updatePaymentMethodDto: UpdatePaymentMethodDto): Promise<PaymentMethod> {
const paymentMethod = await this.findOneOrFail(id);
this.em.assign(paymentMethod, updatePaymentMethodDto);
this.assertCreditCardOwner(paymentMethod.method, paymentMethod.cardOwner);
await this.em.flush();
return paymentMethod;
}
private assertCreditCardOwner(method: PaymentMethodEnum, cardOwner?: string): void {
if (method === PaymentMethodEnum.CreditCard && !cardOwner?.trim()) {
throw new BadRequestException(PaymentMessage.CARD_OWNER_REQUIRED);
}
}
async remove(id: string): Promise<PaymentMethod> {
const paymentMethod = await this.findOneOrFail(id);
await this.em.removeAndFlush(paymentMethod);
@@ -83,6 +83,10 @@ export class PaymentsService {
throw new BadRequestException(PaymentMessage.CARD_NUMBER_REQUIRED);
}
if (pm.method === PaymentMethodEnum.CreditCard && !pm.cardOwner?.trim()) {
throw new BadRequestException(PaymentMessage.CARD_OWNER_REQUIRED);
}
return {
order,
amount: order.total,
+2
View File
@@ -7,6 +7,7 @@ export interface PaymentMethodData {
order: number;
gateway: PaymentGatewayEnum | null;
cardNumber?: string;
cardOwner?: string;
merchantId?: string;
}
@@ -40,5 +41,6 @@ export const paymentMethodsData: PaymentMethodData[] = [
order: 4,
gateway: null,
cardNumber: '6037991234567890',
cardOwner: 'صاحب کارت',
},
];
+6 -1
View File
@@ -23,6 +23,7 @@ export class PaymentMethodsSeeder {
order: methodData.order,
gateway: methodData.gateway,
cardNumber: methodData.cardNumber,
cardOwner: methodData.cardOwner,
merchantId: methodData.merchantId,
});
em.persist(paymentMethod);
@@ -32,7 +33,8 @@ export class PaymentMethodsSeeder {
existing.description !== methodData.description ||
existing.enabled !== methodData.enabled ||
existing.order !== methodData.order ||
existing.cardNumber !== methodData.cardNumber
existing.cardNumber !== methodData.cardNumber ||
existing.cardOwner !== methodData.cardOwner
) {
existing.description = methodData.description;
existing.enabled = methodData.enabled;
@@ -43,6 +45,9 @@ export class PaymentMethodsSeeder {
if (methodData.cardNumber !== undefined) {
existing.cardNumber = methodData.cardNumber;
}
if (methodData.cardOwner !== undefined) {
existing.cardOwner = methodData.cardOwner;
}
if (methodData.merchantId !== undefined) {
existing.merchantId = methodData.merchantId;
}