refactor cart

This commit is contained in:
2025-12-15 23:07:50 +03:30
parent fea123f61e
commit 3e4a4eebe4
13 changed files with 494 additions and 414 deletions
+5 -11
View File
@@ -16,10 +16,10 @@ import { PaymentStatusEnum } from '../../payments/interface/payment';
import { OrderCouponDetail, OrderStatus } from '../interface/order-status';
import { User } from '../../users/entities/user.entity';
import { Restaurant } from '../../restaurants/entities/restaurant.entity';
import { UserAddress } from '../../users/entities/user-address.entity';
import { PaymentMethod } from '../../payments/entities/payment-method.entity';
import { OrderItem } from './order-item.entity';
import { Delivery } from '../../delivery/entities/delivery.entity';
import { OrderUserAddress, OrderCarAddress } from '../interface/order-status';
@Entity({ tableName: 'orders' })
@Unique({ properties: ['restaurant', 'orderNumber'] })
@@ -45,16 +45,10 @@ export class Order extends BaseEntity {
items = new Collection<OrderItem>(this);
@Property({ type: 'json', nullable: true })
address?: {
address: string;
latitude: number;
longitude: number;
city: string;
province: string;
postalCode: string;
fullName: string;
phone: string;
};
userAddress?: OrderUserAddress | null;
// for car delivery
@Property({ type: 'json', nullable: true })
carAddress?: OrderCarAddress | null;
@ManyToOne(() => PaymentMethod)
paymentMethod: PaymentMethod;
+21 -22
View File
@@ -1,28 +1,27 @@
import type { CouponType } from 'src/modules/coupons/interface/coupon';
// export enum OrderStatus {
// // Initial status
// Pending = 'pending',
export interface OrderUserAddress {
address?: string;
latitude?: number;
longitude?: number;
city: string;
province: string;
postalCode?: string;
fullName: string;
phone: string;
}
// // Cancellation statuses
// CancelledBySystem = 'cancelledBySystem',
// CancelledByUser = 'cancelledByUser',
// RejectedByRestaurant = 'rejectedByRestaurant',
export interface OrderCarAddress {
carModel: string;
carColor: string;
plateNumber: string;
address?: string;
latitude?: number;
longitude?: number;
fullName: string;
phone: string;
}
// // Active processing statuses
// Confirmed = 'confirmed',
// Preparing = 'preparing',
// // Ready for pickup/delivery statuses
// ReadyForCustomerPickup = 'readyForCustomerPickup',
// ReadyForDineIn = 'readyForDineIn',
// ReadyForDeliveryCar = 'readyForDeliveryCar',
// ReadyForDeliveryCourier = 'readyForDeliveryCourier',
// Shipping = 'shipping',
// // Final status
// Delivered = 'delivered',
// }
export enum OrderStatus {
NEW = 'new',
PENDING_PAYMENT = 'pendingPayment',
@@ -32,7 +31,7 @@ export enum OrderStatus {
READY = 'ready',
SHIPPED = 'shipped',
COMPLETED = 'completed',
CANCELED = 'canceled',
FAILED = 'failed',
REFUNDED = 'refunded',
+23 -16
View File
@@ -5,7 +5,6 @@ import { OrderItem } from '../entities/order-item.entity';
import { User } from '../../users/entities/user.entity';
import { Restaurant } from '../../restaurants/entities/restaurant.entity';
import { Food } from '../../foods/entities/food.entity';
import { UserAddress } from '../../users/entities/user-address.entity';
import { CartService } from '../../cart/providers/cart.service';
import { OrderStatus } from '../interface/order-status';
import { PaymentMethodEnum, PaymentStatusEnum } from '../../payments/interface/payment';
@@ -20,6 +19,7 @@ import { OrderRepository } from '../repositories/order.repository';
import { FindOrdersDto } from '../dto/find-orders.dto';
import { PaginatedResult } from 'src/common/interfaces/pagination.interface';
import { EventEmitter2 } from '@nestjs/event-emitter';
import { OrderUserAddress, OrderCarAddress } from '../interface/order-status';
@Injectable()
export class OrdersService {
@@ -68,7 +68,8 @@ export class OrdersService {
user: validationResult.user,
restaurant: validationResult.restaurant,
deliveryMethod: validationResult.delivery,
address: validationResult.address,
userAddress: validationResult.userAddress,
carAddress: validationResult.carAddress,
paymentMethod: validationResult.paymentMethod,
couponDiscount: cart.couponDiscount || 0,
itemsDiscount: cart.itemsDiscount || 0,
@@ -133,7 +134,8 @@ export class OrdersService {
user: User;
restaurant: Restaurant;
delivery: Delivery;
address: UserAddress | null;
userAddress: OrderUserAddress | null;
carAddress: OrderCarAddress | null;
paymentMethod: PaymentMethod;
orderItemsData: Array<{ food: Food; quantity: number; unitPrice: number; discount: number }>;
}> {
@@ -185,19 +187,12 @@ export class OrdersService {
}
}
if (delivery.method === DeliveryMethodEnum.DeliveryCourier && !cart.addressId) {
if (delivery.method === DeliveryMethodEnum.DeliveryCourier && !cart.userAddress) {
throw new BadRequestException('Address is required. Please set a delivery address before creating an order.');
}
let address: UserAddress | null = null;
if (cart.addressId) {
address = await this.em.findOne(UserAddress, { id: cart.addressId }, { populate: ['user'] });
if (!address) {
throw new NotFoundException('Address not found');
}
// Verify address belongs to the user
if (address.user.id !== userId) {
throw new BadRequestException('Address does not belong to the current user');
}
if (delivery.method === DeliveryMethodEnum.DeliveryCar && !cart.carAddress) {
throw new BadRequestException('Car address is required. Please set a car address before creating an order.');
}
const paymentMethod = await this.em.findOne(
@@ -256,8 +251,9 @@ export class OrdersService {
user,
restaurant,
delivery,
address,
paymentMethod,
userAddress: cart?.userAddress ?? null,
carAddress: cart?.carAddress ?? null,
orderItemsData,
};
}
@@ -298,7 +294,18 @@ export class OrdersService {
async findOne(id: string, restId: string): Promise<Order> {
const order = await this.orderRepository.findOne(
{ id, restaurant: { id: restId } },
{ populate: ['user', 'restaurant', 'deliveryMethod', 'address', 'paymentMethod', 'items', 'items.food'] },
{
populate: [
'user',
'restaurant',
'deliveryMethod',
'userAddress',
'carAddress',
'paymentMethod',
'items',
'items.food',
],
},
);
if (!order) {
throw new NotFoundException('Order not found');