cart refactored
This commit is contained in:
@@ -20,6 +20,10 @@ import { CartCalculationService } from './providers/cart-calculation.service';
|
||||
import { CartItemService } from './providers/cart-item.service';
|
||||
import { PointTransaction } from '../users/entities/point-transaction.entity';
|
||||
import { WalletTransaction } from '../users/entities/wallet-transaction.entity';
|
||||
import { ShopsModule } from '../shops/shops.module';
|
||||
import { DeliveryModule } from '../delivery/delivery.module';
|
||||
import { ProductModule } from '../products/product.module';
|
||||
import { PaymentsModule } from '../payments/payments.module';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
@@ -39,6 +43,10 @@ import { WalletTransaction } from '../users/entities/wallet-transaction.entity';
|
||||
JwtModule,
|
||||
UtilsModule,
|
||||
CouponModule,
|
||||
ShopsModule,
|
||||
DeliveryModule,
|
||||
ProductModule,
|
||||
PaymentsModule
|
||||
],
|
||||
controllers: [CartController],
|
||||
providers: [
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import type { OrderCouponDetail, OrderUserAddress } from 'src/modules/orders/interface/order.interface';
|
||||
|
||||
export interface CartItem {
|
||||
foodId: string;
|
||||
foodTitle?: string;
|
||||
productId: string;
|
||||
productTitle?: string;
|
||||
quantity: number;
|
||||
price: number;
|
||||
discount: number;
|
||||
|
||||
@@ -14,7 +14,7 @@ export class CartCalculationService {
|
||||
constructor(
|
||||
private readonly em: EntityManager,
|
||||
private readonly couponService: CouponService,
|
||||
) {}
|
||||
) { }
|
||||
|
||||
/**
|
||||
* Calculate total price for a cart item
|
||||
@@ -71,7 +71,7 @@ export class CartCalculationService {
|
||||
const foodMap = await this.getFoodsInCartWithCategories(cart);
|
||||
|
||||
for (const item of cart.items) {
|
||||
const product = foodMap.get(item.foodId);
|
||||
const product = foodMap.get(item.productId);
|
||||
if (!product) continue;
|
||||
|
||||
const matchesCategory =
|
||||
@@ -227,7 +227,7 @@ export class CartCalculationService {
|
||||
* Get products in cart with categories
|
||||
*/
|
||||
private async getFoodsInCartWithCategories(cart: Cart): Promise<Map<string, Product>> {
|
||||
const foodIds = cart.items.map(item => item.foodId);
|
||||
const foodIds = cart.items.map(item => item.productId);
|
||||
if (foodIds.length === 0) return new Map();
|
||||
|
||||
const products = await this.em.find(Product, { id: { $in: foodIds } }, { populate: ['category'] });
|
||||
|
||||
@@ -4,13 +4,15 @@ import { Cart, CartItem } from '../interfaces/cart.interface';
|
||||
import { CartValidationService } from './cart-validation.service';
|
||||
import { CartCalculationService } from './cart-calculation.service';
|
||||
import { CartMessage } from 'src/common/enums/message.enum';
|
||||
import { ProductService } from 'src/modules/products/providers/product.service';
|
||||
|
||||
@Injectable()
|
||||
export class CartItemService {
|
||||
constructor(
|
||||
private readonly validationService: CartValidationService,
|
||||
private readonly calculationService: CartCalculationService,
|
||||
) {}
|
||||
private readonly productService: ProductService,
|
||||
) { }
|
||||
|
||||
/**
|
||||
* Create a new cart item from product
|
||||
@@ -20,8 +22,8 @@ export class CartItemService {
|
||||
const itemDiscount = product.discount || 0;
|
||||
|
||||
return {
|
||||
foodId: product.id,
|
||||
foodTitle: product.title,
|
||||
productId: product.id,
|
||||
productTitle: product.title,
|
||||
quantity,
|
||||
price: itemPrice,
|
||||
discount: itemDiscount,
|
||||
@@ -37,8 +39,8 @@ export class CartItemService {
|
||||
const itemDiscount = product.discount || 0;
|
||||
return {
|
||||
...(previous ?? ({} as CartItem)),
|
||||
foodId: product.id,
|
||||
foodTitle: product.title,
|
||||
productId: product.id,
|
||||
productTitle: product.title,
|
||||
quantity,
|
||||
price: itemPrice,
|
||||
discount: itemDiscount,
|
||||
@@ -49,16 +51,16 @@ export class CartItemService {
|
||||
/**
|
||||
* Get item index in cart
|
||||
*/
|
||||
getItemIndex(cart: Cart, foodId: string): number {
|
||||
return cart.items.findIndex(item => item.foodId === foodId);
|
||||
getItemIndex(cart: Cart, shopId: string): number {
|
||||
return cart.items.findIndex(item => item.productId === shopId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add or increment item in cart
|
||||
*/
|
||||
async addOrIncrementItem(cart: Cart, foodId: string, restaurantId: string, quantityToAdd: number): Promise<void> {
|
||||
const product = await this.validationService.validateAndGetFood(foodId, restaurantId, quantityToAdd);
|
||||
|
||||
async addOrIncrementItem(cart: Cart, shopId: string, restaurantId: string, quantityToAdd: number): Promise<void> {
|
||||
const product = await this.validationService.validateAndGetFood(shopId, restaurantId, quantityToAdd);
|
||||
|
||||
const index = this.getItemIndex(cart, product.id);
|
||||
|
||||
if (index < 0) {
|
||||
@@ -68,15 +70,15 @@ export class CartItemService {
|
||||
|
||||
const existingItem = cart.items[index];
|
||||
const newQuantity = existingItem.quantity + quantityToAdd;
|
||||
this.validationService.validateStock(product, newQuantity);
|
||||
|
||||
cart.items[index] = this.buildCartItemFromFood(product, newQuantity, existingItem);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove item from cart
|
||||
*/
|
||||
removeItemOrFail(cart: Cart, foodId: string): void {
|
||||
const itemIndex = this.getItemIndex(cart, foodId);
|
||||
removeItemOrFail(cart: Cart, shopId: string): void {
|
||||
const itemIndex = this.getItemIndex(cart, shopId);
|
||||
if (itemIndex < 0) {
|
||||
throw new NotFoundException(CartMessage.ITEM_NOT_FOUND);
|
||||
}
|
||||
@@ -86,8 +88,8 @@ export class CartItemService {
|
||||
/**
|
||||
* Decrement item quantity or remove if quantity reaches 0
|
||||
*/
|
||||
async decrementOrRemoveItem(cart: Cart, foodId: string): Promise<void> {
|
||||
const itemIndex = this.getItemIndex(cart, foodId);
|
||||
async decrementOrRemoveItem(cart: Cart, shopId: string): Promise<void> {
|
||||
const itemIndex = this.getItemIndex(cart, shopId);
|
||||
if (itemIndex < 0) {
|
||||
throw new NotFoundException(CartMessage.ITEM_NOT_FOUND);
|
||||
}
|
||||
@@ -100,7 +102,7 @@ export class CartItemService {
|
||||
return;
|
||||
}
|
||||
|
||||
const product = await this.validationService.getFoodOrFail(foodId);
|
||||
const product = await this.productService.findOrFail(shopId);
|
||||
cart.items[itemIndex] = this.buildCartItemFromFood(product, newQuantity, existingItem);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,37 +1,40 @@
|
||||
import { Injectable, NotFoundException, BadRequestException } from '@nestjs/common';
|
||||
import { EntityManager } from '@mikro-orm/postgresql';
|
||||
import { Product } from 'src/modules/products/entities/product.entity';
|
||||
import { Shop } from 'src/modules/shops/entities/shop.entity';
|
||||
import { UserAddress } from 'src/modules/users/entities/user-address.entity';
|
||||
import { User } from 'src/modules/users/entities/user.entity';
|
||||
import { PaymentMethod } from 'src/modules/payments/entities/payment-method.entity';
|
||||
import { Delivery } from 'src/modules/delivery/entities/delivery.entity';
|
||||
import { DeliveryMethodEnum } from 'src/modules/delivery/interface/delivery';
|
||||
import { PointTransaction } from 'src/modules/users/entities/point-transaction.entity';
|
||||
import { Order } from 'src/modules/orders/entities/order.entity';
|
||||
import { OrderStatus } from 'src/modules/orders/interface/order.interface';
|
||||
import { Cart } from '../interfaces/cart.interface';
|
||||
import { GeographicUtils } from '../utils/geographic.utils';
|
||||
import { CartMessage } from 'src/common/enums/message.enum';
|
||||
import { WalletTransactionRepository } from 'src/modules/users/repositories/wallet-transaction.repository';
|
||||
import { ProductService } from 'src/modules/products/providers/product.service';
|
||||
import { ShopService } from 'src/modules/shops/providers/shops.service';
|
||||
import { DeliveryService } from 'src/modules/delivery/providers/delivery.service';
|
||||
import { PaymentsService } from 'src/modules/payments/services/payments.service';
|
||||
import { PaymentMethodService } from 'src/modules/payments/services/payment-method.service';
|
||||
|
||||
@Injectable()
|
||||
export class CartValidationService {
|
||||
constructor(
|
||||
private readonly em: EntityManager,
|
||||
private readonly walletTransactionRepository: WalletTransactionRepository,
|
||||
private readonly productService: ProductService,
|
||||
private readonly shopService: ShopService,
|
||||
private readonly deliveryService: DeliveryService,
|
||||
private readonly paymentMethodService: PaymentMethodService,
|
||||
) { }
|
||||
|
||||
/**
|
||||
* Validate product exists and belongs to shop
|
||||
*/
|
||||
async validateAndGetFood(foodId: string, restaurantId: string, quantity: number): Promise<Product> {
|
||||
const product = await this.em.findOne(Product, { id: foodId }, { populate: ['shop'] });
|
||||
if (!product) {
|
||||
throw new NotFoundException(CartMessage.PRODUCT_NOT_FOUND);
|
||||
}
|
||||
async validateAndGetFood(productId: string, shopId: string, quantity: number): Promise<Product> {
|
||||
const product = await this.productService.findOrFail(productId)
|
||||
|
||||
if (product.shop.id !== restaurantId) {
|
||||
if (product.shop.id !== shopId) {
|
||||
throw new BadRequestException(CartMessage.PRODUCT_NOT_BELONGS_TO_SHOP);
|
||||
}
|
||||
|
||||
@@ -39,50 +42,6 @@ export class CartValidationService {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get user or throw if not found
|
||||
*/
|
||||
async getUserOrFail(userId: string): Promise<User> {
|
||||
const user = await this.em.findOne(User, { id: userId });
|
||||
if (!user) {
|
||||
throw new NotFoundException(CartMessage.USER_NOT_FOUND);
|
||||
}
|
||||
return user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user address or throw if not found
|
||||
*/
|
||||
async getUserAddressOrFail(addressId: string): Promise<UserAddress> {
|
||||
const address = await this.em.findOne(UserAddress, { id: addressId }, { populate: ['user'] });
|
||||
if (!address) {
|
||||
throw new NotFoundException(CartMessage.ADDRESS_NOT_FOUND);
|
||||
}
|
||||
return address;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get product or throw if not found
|
||||
*/
|
||||
async getFoodOrFail(foodId: string): Promise<Product> {
|
||||
const product = await this.em.findOne(Product, { id: foodId });
|
||||
if (!product) {
|
||||
throw new NotFoundException(CartMessage.PRODUCT_NOT_FOUND);
|
||||
}
|
||||
return product;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get shop or throw if not found
|
||||
*/
|
||||
async getRestaurantOrFail(restaurantId: string): Promise<Shop> {
|
||||
const shop = await this.em.findOne(Shop, { id: restaurantId });
|
||||
if (!shop) {
|
||||
throw new NotFoundException(CartMessage.SHOP_NOT_FOUND);
|
||||
}
|
||||
return shop;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate address belongs to user
|
||||
*/
|
||||
@@ -96,7 +55,7 @@ export class CartValidationService {
|
||||
* Assert address is inside shop service area
|
||||
*/
|
||||
async assertAddressInsideServiceArea(
|
||||
restaurantId: string,
|
||||
shopId: string,
|
||||
latitude?: number | null,
|
||||
longitude?: number | null,
|
||||
): Promise<void> {
|
||||
@@ -104,7 +63,7 @@ export class CartValidationService {
|
||||
throw new BadRequestException(CartMessage.ADDRESS_NO_COORDINATES);
|
||||
}
|
||||
|
||||
const shop = await this.getRestaurantOrFail(restaurantId);
|
||||
const shop = await this.shopService.findOrFail(shopId);
|
||||
|
||||
const serviceArea = shop.serviceArea;
|
||||
// If no service area is defined, assume service is available everywhere
|
||||
@@ -130,34 +89,13 @@ export class CartValidationService {
|
||||
/**
|
||||
* Get delivery method for shop or throw if not found
|
||||
*/
|
||||
async getDeliveryMethodForRestaurantOrFail(
|
||||
restaurantId: string,
|
||||
deliveryMethodId: string,
|
||||
): Promise<Delivery> {
|
||||
const deliveryMethod = await this.em.findOne(Delivery, {
|
||||
id: deliveryMethodId,
|
||||
shop: { id: restaurantId },
|
||||
});
|
||||
|
||||
if (!deliveryMethod) {
|
||||
throw new NotFoundException(CartMessage.DELIVERY_METHOD_NOT_FOUND_FOR_SHOP);
|
||||
}
|
||||
|
||||
return deliveryMethod;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get enabled delivery method or throw if not found or disabled
|
||||
*/
|
||||
async getEnabledDeliveryMethodOrFail(restaurantId: string, deliveryMethodId: string): Promise<Delivery> {
|
||||
const deliveryMethod = await this.em.findOne(
|
||||
Delivery,
|
||||
{ id: deliveryMethodId, shop: { id: restaurantId } },
|
||||
{ populate: ['shop'] },
|
||||
);
|
||||
if (!deliveryMethod) {
|
||||
throw new NotFoundException(CartMessage.DELIVERY_METHOD_NOT_FOUND);
|
||||
}
|
||||
async getEnabledDeliveryMethodOrFail(shopId: string, deliveryMethodId: string): Promise<Delivery> {
|
||||
const deliveryMethod = await this.deliveryService.findOrFail(shopId, deliveryMethodId)
|
||||
if (!deliveryMethod.enabled) {
|
||||
throw new BadRequestException(CartMessage.DELIVERY_METHOD_NOT_ENABLED);
|
||||
}
|
||||
@@ -186,14 +124,10 @@ export class CartValidationService {
|
||||
/**
|
||||
* Get enabled payment method or throw if not found or disabled
|
||||
*/
|
||||
async getEnabledPaymentMethodOrFail(restaurantId: string, paymentMethodId: string): Promise<PaymentMethod> {
|
||||
const paymentMethod = await this.em.findOne(
|
||||
PaymentMethod,
|
||||
{ id: paymentMethodId, shop: { id: restaurantId } },
|
||||
{ populate: ['shop'] },
|
||||
);
|
||||
if (!paymentMethod) {
|
||||
throw new NotFoundException(CartMessage.PAYMENT_METHOD_NOT_FOUND);
|
||||
async getEnabledPaymentMethodOrFail(shopId: string, paymentMethodId: string): Promise<PaymentMethod> {
|
||||
const paymentMethod = await this.paymentMethodService.findOneOrFail(paymentMethodId)
|
||||
if (paymentMethod.shop.id !== shopId) {
|
||||
throw new BadRequestException('CartMessage.PAYMENT_METHOD_NOT_BELONGS_TO_SHOP');
|
||||
}
|
||||
if (!paymentMethod.enabled) {
|
||||
throw new BadRequestException(CartMessage.PAYMENT_METHOD_NOT_ENABLED);
|
||||
@@ -204,8 +138,8 @@ export class CartValidationService {
|
||||
/**
|
||||
* Assert wallet has enough balance
|
||||
*/
|
||||
async assertWalletHasEnoughBalance(userId: string, restaurantId: string, amount: number): Promise<void> {
|
||||
const balance = await this.walletTransactionRepository.getCurrentWalletBalance(userId, restaurantId);
|
||||
async assertWalletHasEnoughBalance(userId: string, shopId: string, amount: number): Promise<void> {
|
||||
const balance = await this.walletTransactionRepository.getCurrentWalletBalance(userId, shopId);
|
||||
|
||||
if (balance < amount) {
|
||||
throw new BadRequestException(CartMessage.WALLET_INSUFFICIENT);
|
||||
@@ -247,7 +181,7 @@ export class CartValidationService {
|
||||
const foodMap = await this.getFoodsInCartWithCategories(cart);
|
||||
|
||||
for (const item of cart.items) {
|
||||
const product = foodMap.get(item.foodId);
|
||||
const product = foodMap.get(item.productId);
|
||||
if (!product) continue;
|
||||
|
||||
const matchesCategory = hasCategoryRestriction && product.category && categoryRestriction.includes(product.category.id);
|
||||
@@ -262,19 +196,14 @@ export class CartValidationService {
|
||||
* Get products in cart with categories
|
||||
*/
|
||||
async getFoodsInCartWithCategories(cart: Cart): Promise<Map<string, Product>> {
|
||||
const foodIds = cart.items.map(item => item.foodId);
|
||||
if (foodIds.length === 0) return new Map();
|
||||
const productIds = cart.items.map(item => item.productId);
|
||||
if (productIds.length === 0) return new Map();
|
||||
|
||||
const products = await this.em.find(Product, { id: { $in: foodIds } }, { populate: ['category'] });
|
||||
const products = await this.em.find(Product, { id: { $in: productIds } }, { populate: ['category'] });
|
||||
return new Map(products.map(f => [f.id, f]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate stock for a product
|
||||
*/
|
||||
validateStock(product: Product, quantity: number): void {
|
||||
// TODO: Implement stock validation logic
|
||||
// For now, assume unlimited stock
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,9 @@ import { CartValidationService } from './cart-validation.service';
|
||||
import { CartCalculationService } from './cart-calculation.service';
|
||||
import { CartItemService } from './cart-item.service';
|
||||
import { CartMessage } from 'src/common/enums/message.enum';
|
||||
import { UserService } from 'src/modules/users/providers/user.service';
|
||||
import { ShopService } from 'src/modules/shops/providers/shops.service';
|
||||
import { DeliveryService } from 'src/modules/delivery/providers/delivery.service';
|
||||
|
||||
@Injectable()
|
||||
export class CartService {
|
||||
@@ -21,6 +24,9 @@ export class CartService {
|
||||
private readonly calculationService: CartCalculationService,
|
||||
private readonly itemService: CartItemService,
|
||||
private readonly couponService: CouponService,
|
||||
private readonly userService: UserService,
|
||||
private readonly shopService: ShopService,
|
||||
private readonly deliveryService: DeliveryService,
|
||||
) { }
|
||||
|
||||
/**
|
||||
@@ -54,7 +60,7 @@ export class CartService {
|
||||
throw new BadRequestException(CartMessage.ADDRESS_REQUIRED);
|
||||
}
|
||||
this.clearFieldsIncompatibleWithDeliveryMethod(cart, DeliveryMethodEnum.DeliveryCourier);
|
||||
const address = await this.validationService.getUserAddressOrFail(addressId);
|
||||
const address = await this.userService.getUserAddressOrFail(addressId);
|
||||
this.validationService.validateAddressOwnership(address, userId);
|
||||
|
||||
// ensure address is within shop service area
|
||||
@@ -111,7 +117,7 @@ export class CartService {
|
||||
}
|
||||
|
||||
// Find shop
|
||||
const shop = await this.validationService.getRestaurantOrFail(restaurantId);
|
||||
const shop = await this.shopService.findOrFail(restaurantId);
|
||||
|
||||
// Create new cart
|
||||
const now = this.nowIso();
|
||||
@@ -194,7 +200,7 @@ export class CartService {
|
||||
const cart = await this.findOneOrFail(userId, restaurantId);
|
||||
|
||||
const orderAmount = cart.subTotal - cart.itemsDiscount;
|
||||
const user = await this.validationService.getUserOrFail(userId);
|
||||
const user = await this.userService.findOneOrFail(userId);
|
||||
// check if coupon is valid and belong to the shop
|
||||
const { valid, coupon, message } = await this.couponService.validateCoupon(
|
||||
applyCouponDto.code,
|
||||
@@ -252,10 +258,8 @@ export class CartService {
|
||||
cart,
|
||||
'Delivery method must be set before setting address',
|
||||
);
|
||||
const deliveryMethod = await this.validationService.getDeliveryMethodForRestaurantOrFail(
|
||||
restaurantId,
|
||||
deliveryMethodId,
|
||||
);
|
||||
const deliveryMethod = await this.deliveryService.findOrFail(restaurantId, deliveryMethodId);
|
||||
|
||||
this.validationService.assertDeliveryMethod(
|
||||
deliveryMethod.method,
|
||||
DeliveryMethodEnum.DeliveryCourier,
|
||||
@@ -263,7 +267,7 @@ export class CartService {
|
||||
);
|
||||
|
||||
// Find and validate address belongs to user
|
||||
const address = await this.validationService.getUserAddressOrFail(addressId);
|
||||
const address = await this.userService.getUserAddressOrFail(addressId);
|
||||
|
||||
// Verify address belongs to the user
|
||||
this.validationService.validateAddressOwnership(address, userId);
|
||||
@@ -354,7 +358,6 @@ export class CartService {
|
||||
*/
|
||||
private clearFieldsIncompatibleWithDeliveryMethod(cart: Cart, method: DeliveryMethodEnum): void {
|
||||
|
||||
|
||||
if (method === DeliveryMethodEnum.CustomerPickup) {
|
||||
cart.userAddress = null;
|
||||
cart.tableNumber = undefined;
|
||||
@@ -366,7 +369,6 @@ export class CartService {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -27,7 +27,7 @@ import { DeliveryModule } from '../delivery/delivery.module';
|
||||
@Module({
|
||||
imports: [
|
||||
MikroOrmModule.forFeature([Order, OrderItem, User, Shop, Product, Variant, UserAddress, PaymentMethod]),
|
||||
CartModule,
|
||||
forwardRef(() => CartModule),
|
||||
UtilsModule,
|
||||
AuthModule,
|
||||
forwardRef(() => PaymentsModule),
|
||||
|
||||
@@ -366,7 +366,7 @@ export class OrdersService {
|
||||
const orderItemsData: OrderItemData[] = [];
|
||||
|
||||
for (const cartItem of cart.items) {
|
||||
const variant = await this.em.findOne(Variant, { id: cartItem.foodId }, { populate: ['product', 'product.shop'] });
|
||||
const variant = await this.em.findOne(Variant, { id: cartItem.productId }, { populate: ['product', 'product.shop'] });
|
||||
if (!variant) throw new NotFoundException(OrderMessage.PRODUCT_NOT_FOUND);
|
||||
|
||||
if (variant.product.shop.id !== shopId) {
|
||||
|
||||
@@ -13,6 +13,7 @@ import { PaymentMessage, OrderMessage } from 'src/common/enums/message.enum';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { onlinePaymentSucceedEvent, paymentSucceedEvent } from '../events/payment.events';
|
||||
import { WalletTransactionReason, WalletTransactionType } from 'src/modules/users/interface/wallet';
|
||||
import { PaymentRepository } from '../repositories/payment.repository';
|
||||
|
||||
@Injectable()
|
||||
export class PaymentsService {
|
||||
@@ -22,6 +23,7 @@ export class PaymentsService {
|
||||
private readonly em: EntityManager,
|
||||
private readonly gatewayManager: GatewayManager,
|
||||
private readonly eventEmitter: EventEmitter2,
|
||||
private readonly paymentRepository: PaymentRepository,
|
||||
) { }
|
||||
|
||||
async payOrder(orderId: string): Promise<{ paymentUrl: string | null }> {
|
||||
@@ -141,7 +143,7 @@ export class PaymentsService {
|
||||
payment.paidAt = new Date();
|
||||
order.status = OrderStatus.PAID;
|
||||
|
||||
em.persist([ payment, order, newWalletTransaction]);
|
||||
em.persist([payment, order, newWalletTransaction]);
|
||||
await em.flush();
|
||||
});
|
||||
this.eventEmitter.emit(
|
||||
@@ -278,6 +280,13 @@ export class PaymentsService {
|
||||
payment.order.status = OrderStatus.CANCELED;
|
||||
}
|
||||
|
||||
async findOneOrFail(paymentId: string): Promise<Payment> {
|
||||
const payment=await this.paymentRepository.findOne({ id: paymentId });
|
||||
if (!payment) {
|
||||
throw new NotFoundException(PaymentMessage.PAYMENT_NOT_FOUND);
|
||||
}
|
||||
return payment;
|
||||
}
|
||||
|
||||
private async getOrCreateLatestPendingPayment(
|
||||
orderId: string,
|
||||
|
||||
@@ -25,6 +25,6 @@ import { Favorite } from './entities/favorite.entity';
|
||||
],
|
||||
controllers: [FoodController, CategoryController],
|
||||
providers: [ProductService, CategoryService, ProductRepository, CategoryRepository],
|
||||
exports: [ProductRepository, CategoryRepository],
|
||||
exports: [ProductRepository, CategoryRepository, ProductService],
|
||||
})
|
||||
export class ProductModule {}
|
||||
|
||||
@@ -392,4 +392,12 @@ export class UserService {
|
||||
}
|
||||
return user;
|
||||
}
|
||||
|
||||
async getUserAddressOrFail(addressId: string): Promise<UserAddress> {
|
||||
const address = await this.em.findOne(UserAddress, { id: addressId }, { populate: ['user'] });
|
||||
if (!address) {
|
||||
throw new NotFoundException("User address not found.");
|
||||
}
|
||||
return address;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { EntityManager, EntityRepository } from '@mikro-orm/postgresql';
|
||||
import { UserAddress } from '../entities/user-address.entity';
|
||||
|
||||
@Injectable()
|
||||
export class AddressRepository extends EntityRepository<UserAddress> {
|
||||
constructor(readonly em: EntityManager) {
|
||||
super(em, UserAddress);
|
||||
}
|
||||
}
|
||||
@@ -6,21 +6,24 @@ import { User } from './entities/user.entity';
|
||||
import { UserAddress } from './entities/user-address.entity';
|
||||
import { JwtModule } from '@nestjs/jwt';
|
||||
import { UserRepository } from './repositories/user.repository';
|
||||
import { WalletTransactionRepository } from './repositories/wallet-transaction.repository';
|
||||
import { WalletTransactionRepository } from './repositories/wallet-transaction.repository';
|
||||
import { WalletService } from './providers/wallet.service';
|
||||
import { WalletTransaction } from './entities/wallet-transaction.entity';
|
||||
import { PointTransaction } from './entities/point-transaction.entity';
|
||||
import { PointTransactionRepository } from './repositories/point-transaction.repository';
|
||||
import { ShopsModule } from '../shops/shops.module';
|
||||
import { AddressRepository } from './repositories/address.repository';
|
||||
|
||||
@Module({
|
||||
providers: [UserService, WalletService, UserRepository, WalletTransactionRepository, PointTransactionRepository],
|
||||
providers: [UserService, WalletService, UserRepository,
|
||||
WalletTransactionRepository, PointTransactionRepository, AddressRepository],
|
||||
controllers: [UsersController],
|
||||
imports: [
|
||||
MikroOrmModule.forFeature([User, UserAddress, WalletTransaction, PointTransaction]),
|
||||
JwtModule,
|
||||
ShopsModule
|
||||
],
|
||||
exports: [UserService, WalletService, UserRepository, WalletTransactionRepository, PointTransactionRepository],
|
||||
exports: [UserService, WalletService, UserRepository,
|
||||
WalletTransactionRepository, PointTransactionRepository, AddressRepository],
|
||||
})
|
||||
export class UserModule {}
|
||||
export class UserModule { }
|
||||
|
||||
Reference in New Issue
Block a user