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 { 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;
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user