set payment method

This commit is contained in:
2025-11-23 10:03:44 +03:30
parent cc6614fe97
commit 4ea7c8d068
5 changed files with 95 additions and 2 deletions
@@ -4,6 +4,7 @@ import { AddItemToCartDto } from '../dto/add-item.dto';
import { UpdateItemQuantityDto } from '../dto/update-item.dto'; import { UpdateItemQuantityDto } from '../dto/update-item.dto';
import { ApplyCouponDto } from '../dto/apply-coupon.dto'; import { ApplyCouponDto } from '../dto/apply-coupon.dto';
import { SetAddressDto } from '../dto/set-address.dto'; import { SetAddressDto } from '../dto/set-address.dto';
import { SetPaymentMethodDto } from '../dto/set-payment-method.dto';
import { ApiTags, ApiOperation, ApiResponse, ApiBearerAuth, ApiBody, ApiParam } from '@nestjs/swagger'; import { ApiTags, ApiOperation, ApiResponse, ApiBearerAuth, ApiBody, ApiParam } from '@nestjs/swagger';
import { AuthGuard } from '../../auth/guards/auth.guard'; import { AuthGuard } from '../../auth/guards/auth.guard';
import { UserId } from 'src/common/decorators/user-id.decorator'; import { UserId } from 'src/common/decorators/user-id.decorator';
@@ -84,4 +85,18 @@ export class CartController {
async setAddress(@UserId() userId: string, @RestId() restaurantId: string, @Body() setAddressDto: SetAddressDto) { async setAddress(@UserId() userId: string, @RestId() restaurantId: string, @Body() setAddressDto: SetAddressDto) {
return this.cartService.setAddress(userId, restaurantId, setAddressDto); return this.cartService.setAddress(userId, restaurantId, setAddressDto);
} }
@Patch('payment-method')
@ApiOperation({ summary: 'Set payment method for cart' })
@ApiBody({ type: SetPaymentMethodDto })
@ApiResponse({ status: 200, description: 'Payment method set successfully' })
@ApiResponse({ status: 400, description: 'Bad request (e.g., payment method is not active)' })
@ApiResponse({ status: 404, description: 'Payment method not found for restaurant' })
async setPaymentMethod(
@UserId() userId: string,
@RestId() restaurantId: string,
@Body() setPaymentMethodDto: SetPaymentMethodDto,
) {
return this.cartService.setPaymentMethod(userId, restaurantId, setPaymentMethodDto);
}
} }
@@ -0,0 +1,10 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsNotEmpty, IsString } from 'class-validator';
export class SetPaymentMethodDto {
@ApiProperty({ description: 'Payment method ID', example: '01ARZ3NDEKTSV4RRFFQ69G5FAV' })
@IsNotEmpty()
@IsString()
paymentMethodId!: string;
}
@@ -21,6 +21,8 @@ export interface Cart {
items: CartItem[]; items: CartItem[];
coupon?: CartCoupon; coupon?: CartCoupon;
addressId?: string; addressId?: string;
paymentMethodId?: string;
paymentMethodFee: number;
totalPrice: number; totalPrice: number;
totalDiscount: number; totalDiscount: number;
couponDiscount: number; couponDiscount: number;
+65 -2
View File
@@ -8,10 +8,11 @@ import { AddItemToCartDto } from '../dto/add-item.dto';
import { UpdateItemQuantityDto } from '../dto/update-item.dto'; import { UpdateItemQuantityDto } from '../dto/update-item.dto';
import { ApplyCouponDto } from '../dto/apply-coupon.dto'; import { ApplyCouponDto } from '../dto/apply-coupon.dto';
import { SetAddressDto } from '../dto/set-address.dto'; import { SetAddressDto } from '../dto/set-address.dto';
import { SetPaymentMethodDto } from '../dto/set-payment-method.dto';
import { UserAddress } from '../../users/entities/user-address.entity'; import { UserAddress } from '../../users/entities/user-address.entity';
import { RestaurantPaymentMethod } from '../../payments/entities/restaurant-payment-method.entity';
import { Cart, CartItem, CartCoupon } from '../interfaces/cart.interface'; import { Cart, CartItem, CartCoupon } from '../interfaces/cart.interface';
@Injectable() @Injectable()
export class CartService { export class CartService {
private readonly CART_TTL = 1200; // 20 minutes in seconds private readonly CART_TTL = 1200; // 20 minutes in seconds
@@ -44,6 +45,7 @@ export class CartService {
restaurantId, restaurantId,
restaurantName: restaurant.name, restaurantName: restaurant.name,
items: [], items: [],
paymentMethodFee: 0,
totalPrice: 0, totalPrice: 0,
totalDiscount: 0, totalDiscount: 0,
couponDiscount: 0, couponDiscount: 0,
@@ -279,6 +281,52 @@ export class CartService {
return cart; return cart;
} }
/**
* Set payment method for cart
*/
async setPaymentMethod(
userId: string,
restaurantId: string,
setPaymentMethodDto: SetPaymentMethodDto,
): Promise<Cart> {
const cart = await this.findOne(userId, restaurantId);
// Find and validate payment method belongs to restaurant
const restaurantPaymentMethod = await this.em.findOne(
RestaurantPaymentMethod,
{
restaurant: { id: restaurantId },
paymentMethod: { id: setPaymentMethodDto.paymentMethodId },
},
{ populate: ['restaurant', 'paymentMethod'] },
);
if (!restaurantPaymentMethod) {
throw new NotFoundException(
`Payment method with ID ${setPaymentMethodDto.paymentMethodId} not found for restaurant ${restaurantId}`,
);
}
// Verify payment method is active
if (!restaurantPaymentMethod.isActive) {
throw new BadRequestException('Payment method is not active for this restaurant');
}
// Verify the payment method itself is active
if (!restaurantPaymentMethod.paymentMethod.isActive) {
throw new BadRequestException('Payment method is not active');
}
cart.paymentMethodId = setPaymentMethodDto.paymentMethodId;
cart.paymentMethodFee = Number(restaurantPaymentMethod.price) || 0;
// Recalculate cart totals to include payment method fee
await this.recalculateCartTotals(cart);
await this.saveCart(cart);
return cart;
}
/** /**
* Recalculate cart totals (including coupon discount and VAT) * Recalculate cart totals (including coupon discount and VAT)
*/ */
@@ -323,7 +371,22 @@ export class CartService {
} }
cart.vatAmount = vatAmount; cart.vatAmount = vatAmount;
cart.finalPrice = priceAfterDiscounts + vatAmount;
// Get payment method fee if payment method is set
let paymentMethodFee = 0;
if (cart.paymentMethodId) {
const restaurantPaymentMethod = await this.em.findOne(RestaurantPaymentMethod, {
restaurant: { id: cart.restaurantId },
paymentMethod: { id: cart.paymentMethodId },
});
if (restaurantPaymentMethod) {
paymentMethodFee = Number(restaurantPaymentMethod.price) || 0;
}
}
cart.paymentMethodFee = paymentMethodFee;
// Final price includes items, discounts, VAT, and payment method fee
cart.finalPrice = priceAfterDiscounts + vatAmount + paymentMethodFee;
cart.totalItems = totalItems; cart.totalItems = totalItems;
cart.updatedAt = new Date().toISOString(); cart.updatedAt = new Date().toISOString();
} }
@@ -16,6 +16,9 @@ export class RestaurantPaymentMethod extends BaseEntity {
@Property({ nullable: true }) @Property({ nullable: true })
merchantId?: string; merchantId?: string;
@Property({ type: 'decimal', precision: 10, scale: 2, default: 0 })
price: number = 0;
@Property({ type: 'boolean', default: true }) @Property({ type: 'boolean', default: true })
isActive: boolean = true; isActive: boolean = true;
} }