set payment method
This commit is contained in:
@@ -4,6 +4,7 @@ import { AddItemToCartDto } from '../dto/add-item.dto';
|
||||
import { UpdateItemQuantityDto } from '../dto/update-item.dto';
|
||||
import { ApplyCouponDto } from '../dto/apply-coupon.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 { AuthGuard } from '../../auth/guards/auth.guard';
|
||||
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) {
|
||||
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[];
|
||||
coupon?: CartCoupon;
|
||||
addressId?: string;
|
||||
paymentMethodId?: string;
|
||||
paymentMethodFee: number;
|
||||
totalPrice: number;
|
||||
totalDiscount: number;
|
||||
couponDiscount: number;
|
||||
|
||||
@@ -8,10 +8,11 @@ import { AddItemToCartDto } from '../dto/add-item.dto';
|
||||
import { UpdateItemQuantityDto } from '../dto/update-item.dto';
|
||||
import { ApplyCouponDto } from '../dto/apply-coupon.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 { RestaurantPaymentMethod } from '../../payments/entities/restaurant-payment-method.entity';
|
||||
import { Cart, CartItem, CartCoupon } from '../interfaces/cart.interface';
|
||||
|
||||
|
||||
@Injectable()
|
||||
export class CartService {
|
||||
private readonly CART_TTL = 1200; // 20 minutes in seconds
|
||||
@@ -44,6 +45,7 @@ export class CartService {
|
||||
restaurantId,
|
||||
restaurantName: restaurant.name,
|
||||
items: [],
|
||||
paymentMethodFee: 0,
|
||||
totalPrice: 0,
|
||||
totalDiscount: 0,
|
||||
couponDiscount: 0,
|
||||
@@ -279,6 +281,52 @@ export class CartService {
|
||||
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)
|
||||
*/
|
||||
@@ -323,7 +371,22 @@ export class CartService {
|
||||
}
|
||||
|
||||
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.updatedAt = new Date().toISOString();
|
||||
}
|
||||
|
||||
@@ -16,6 +16,9 @@ export class RestaurantPaymentMethod extends BaseEntity {
|
||||
@Property({ nullable: true })
|
||||
merchantId?: string;
|
||||
|
||||
@Property({ type: 'decimal', precision: 10, scale: 2, default: 0 })
|
||||
price: number = 0;
|
||||
|
||||
@Property({ type: 'boolean', default: true })
|
||||
isActive: boolean = true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user