fix
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
import { Injectable, NotFoundException, BadRequestException } from '@nestjs/common';
|
import { Injectable, NotFoundException, BadRequestException } from '@nestjs/common';
|
||||||
import { EntityManager } from '@mikro-orm/postgresql';
|
import { EntityManager } from '@mikro-orm/postgresql';
|
||||||
import { Product } from ../../../products/entities/product.entity';
|
import { Product } from '../../../products/entities/product.entity';
|
||||||
import { Shop } from ../../../shops/entities/shop.entity';
|
import { Shop } from '../../../shops/entities/shop.entity';
|
||||||
import { UserAddress } from '../../../users/entities/user-address.entity';
|
import { UserAddress } from '../../../users/entities/user-address.entity';
|
||||||
import { User } from '../../../users/entities/user.entity';
|
import { User } from '../../../users/entities/user.entity';
|
||||||
import { PaymentMethod } from '../../../payments/entities/payment-method.entity';
|
import { PaymentMethod } from '../../../payments/entities/payment-method.entity';
|
||||||
|
|||||||
@@ -0,0 +1,273 @@
|
|||||||
|
import { Injectable, NotFoundException, BadRequestException } from '@nestjs/common';
|
||||||
|
import { EntityManager } from '@mikro-orm/postgresql';
|
||||||
|
import { Product } from ../../../products/entities/product.entity';
|
||||||
|
import { Shop } from ../../../shops/entities/shop.entity';
|
||||||
|
import { UserAddress } from '../../../users/entities/user-address.entity';
|
||||||
|
import { User } from '../../../users/entities/user.entity';
|
||||||
|
import { PaymentMethod } from '../../../payments/entities/payment-method.entity';
|
||||||
|
import { Delivery } from '../../../delivery/entities/delivery.entity';
|
||||||
|
import { DeliveryMethodEnum } from '../../../delivery/interface/delivery';
|
||||||
|
import { PointTransaction } from '../../../users/entities/point-transaction.entity';
|
||||||
|
import { Order } from '../../../orders/entities/order.entity';
|
||||||
|
import { OrderStatus } from '../../../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';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class CartValidationService {
|
||||||
|
constructor(
|
||||||
|
private readonly em: EntityManager,
|
||||||
|
private readonly walletTransactionRepository: WalletTransactionRepository,
|
||||||
|
) { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.FOOD_NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (product.shop.id !== restaurantId) {
|
||||||
|
throw new BadRequestException(CartMessage.FOOD_NOT_BELONGS_TO_RESTAURANT);
|
||||||
|
}
|
||||||
|
|
||||||
|
return product;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.FOOD_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.RESTAURANT_NOT_FOUND);
|
||||||
|
}
|
||||||
|
return shop;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate address belongs to user
|
||||||
|
*/
|
||||||
|
validateAddressOwnership(address: UserAddress, userId: string): void {
|
||||||
|
if (address.user.id !== userId) {
|
||||||
|
throw new BadRequestException(CartMessage.ADDRESS_NOT_BELONGS_TO_USER);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assert address is inside shop service area
|
||||||
|
*/
|
||||||
|
async assertAddressInsideServiceArea(
|
||||||
|
restaurantId: string,
|
||||||
|
latitude?: number | null,
|
||||||
|
longitude?: number | null,
|
||||||
|
): Promise<void> {
|
||||||
|
if (latitude === undefined || latitude === null || longitude === undefined || longitude === null) {
|
||||||
|
throw new BadRequestException(CartMessage.ADDRESS_NO_COORDINATES);
|
||||||
|
}
|
||||||
|
|
||||||
|
const shop = await this.getRestaurantOrFail(restaurantId);
|
||||||
|
|
||||||
|
const serviceArea = shop.serviceArea;
|
||||||
|
// If no service area is defined, assume service is available everywhere
|
||||||
|
if (!serviceArea || !serviceArea.coordinates || !Array.isArray(serviceArea.coordinates)) return;
|
||||||
|
|
||||||
|
// GeoJSON coordinates: [ [ [lng, lat], ... ] ] -> take first ring
|
||||||
|
const rings = serviceArea.coordinates;
|
||||||
|
if (!rings || rings.length === 0 || !Array.isArray(rings[0])) return;
|
||||||
|
|
||||||
|
const ring = rings[0];
|
||||||
|
const point: [number, number] = [Number(longitude), Number(latitude)];
|
||||||
|
|
||||||
|
// Ensure polygon has the correct tuple typing ([lng, lat] pairs)
|
||||||
|
const polygon: [number, number][] = ring.map(
|
||||||
|
coord => [Number(coord[0] ?? 0), Number(coord[1] ?? 0)] as [number, number],
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!GeographicUtils.isPointInPolygon(point, polygon)) {
|
||||||
|
throw new BadRequestException(CartMessage.ADDRESS_OUTSIDE_SERVICE_AREA);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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_RESTAURANT);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
if (!deliveryMethod.enabled) {
|
||||||
|
throw new BadRequestException(CartMessage.DELIVERY_METHOD_NOT_ENABLED);
|
||||||
|
}
|
||||||
|
return deliveryMethod;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assert delivery method matches expected type
|
||||||
|
*/
|
||||||
|
assertDeliveryMethod(actual: DeliveryMethodEnum, expected: DeliveryMethodEnum, message: string): void {
|
||||||
|
if (actual !== expected) {
|
||||||
|
throw new BadRequestException(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Require delivery method ID or throw
|
||||||
|
*/
|
||||||
|
requireDeliveryMethodId(cart: Cart, message: string): string {
|
||||||
|
if (!cart.deliveryMethodId) {
|
||||||
|
throw new BadRequestException(message);
|
||||||
|
}
|
||||||
|
return cart.deliveryMethodId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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);
|
||||||
|
}
|
||||||
|
if (!paymentMethod.enabled) {
|
||||||
|
throw new BadRequestException(CartMessage.PAYMENT_METHOD_NOT_ENABLED);
|
||||||
|
}
|
||||||
|
return paymentMethod;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assert wallet has enough balance
|
||||||
|
*/
|
||||||
|
async assertWalletHasEnoughBalance(userId: string, restaurantId: string, amount: number): Promise<void> {
|
||||||
|
const balance = await this.walletTransactionRepository.getCurrentWalletBalance(userId, restaurantId);
|
||||||
|
|
||||||
|
if (balance < amount) {
|
||||||
|
throw new BadRequestException(CartMessage.WALLET_INSUFFICIENT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assert coupon usage limit
|
||||||
|
*/
|
||||||
|
async assertCouponUsageLimit(userId: string, couponId: string, maxUsesPerUser?: number): Promise<void> {
|
||||||
|
if (!maxUsesPerUser) return;
|
||||||
|
|
||||||
|
const ordersThatUsedTheCouponCount = await this.em.count(Order, {
|
||||||
|
user: { id: userId },
|
||||||
|
couponDetail: { couponId: couponId },
|
||||||
|
status: { $ne: OrderStatus.CANCELED },
|
||||||
|
deletedAt: null,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (ordersThatUsedTheCouponCount >= maxUsesPerUser) {
|
||||||
|
throw new BadRequestException(CartMessage.COUPON_MAX_USES_REACHED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assert coupon matches cart if restricted
|
||||||
|
*/
|
||||||
|
async assertCouponMatchesCartIfRestricted(
|
||||||
|
cart: Cart,
|
||||||
|
foodCategories?: string[] | null,
|
||||||
|
products?: string[] | null,
|
||||||
|
): Promise<void> {
|
||||||
|
const categoryRestriction = foodCategories?.filter(Boolean) ?? [];
|
||||||
|
const foodRestriction = products?.filter(Boolean) ?? [];
|
||||||
|
const hasCategoryRestriction = categoryRestriction.length > 0;
|
||||||
|
const hasFoodRestriction = foodRestriction.length > 0;
|
||||||
|
if (!hasCategoryRestriction && !hasFoodRestriction) return;
|
||||||
|
|
||||||
|
const foodMap = await this.getFoodsInCartWithCategories(cart);
|
||||||
|
|
||||||
|
for (const item of cart.items) {
|
||||||
|
const product = foodMap.get(item.foodId);
|
||||||
|
if (!product) continue;
|
||||||
|
|
||||||
|
const matchesCategory = hasCategoryRestriction && product.category && categoryRestriction.includes(product.category.id);
|
||||||
|
const matchesFood = hasFoodRestriction && foodRestriction.includes(product.id);
|
||||||
|
if (matchesCategory || matchesFood) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new BadRequestException(CartMessage.COUPON_CANNOT_BE_APPLIED);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 products = await this.em.find(Product, { id: { $in: foodIds } }, { populate: ['category'] });
|
||||||
|
return new Map(products.map(f => [f.id, f]));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Entity, Index, ManyToOne, Property, Enum, Unique } from '@mikro-orm/core';
|
import { Entity, Index, ManyToOne, Property, Enum, Unique } from '@mikro-orm/core';
|
||||||
import { BaseEntity } from '../../../../common/entities/base.entity';
|
import { BaseEntity } from '../../../../common/entities/base.entity';
|
||||||
import { Shop } from ../../../ shops / entities / shop.entity';
|
import { Shop } from '../../../shops/entities/shop.entity';
|
||||||
import { normalizePhone } from '../../../utils/phone.util';
|
import { normalizePhone } from '../../../utils/phone.util';
|
||||||
import { CouponType } from '../interface/coupon';
|
import { CouponType } from '../interface/coupon';
|
||||||
|
|
||||||
|
|||||||
@@ -1,44 +0,0 @@
|
|||||||
import { Injectable, Logger } from '@nestjs/common';
|
|
||||||
import { Cron } from '@nestjs/schedule';
|
|
||||||
import { EntityManager } from '@mikro-orm/postgresql';
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class FoodStockCrone {
|
|
||||||
private readonly logger = new Logger(FoodStockCrone.name);
|
|
||||||
|
|
||||||
constructor(private readonly em: EntityManager) {}
|
|
||||||
|
|
||||||
// Inventory cron job disabled - inventory module removed
|
|
||||||
// @Cron('3 0 * * *', {
|
|
||||||
// name: 'resetAvailableStock',
|
|
||||||
// timeZone: 'UTC',
|
|
||||||
// })
|
|
||||||
// async handleCron() {
|
|
||||||
// try {
|
|
||||||
// this.logger.debug('Starting daily inventory reset (availableStock = totalStock)');
|
|
||||||
|
|
||||||
// const inventories = await this.em.find(Inventory, {});
|
|
||||||
// if (!inventories || inventories.length === 0) {
|
|
||||||
// this.logger.debug('No inventory records found to reset');
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// this.logger.log(`Resetting available stock for ${inventories.length} inventory records`);
|
|
||||||
|
|
||||||
// await this.em.transactional(async em => {
|
|
||||||
// for (const inv of inventories) {
|
|
||||||
// // reload inside transaction to avoid concurrency issues
|
|
||||||
// const record = await em.findOne(Inventory, { id: inv.id });
|
|
||||||
// if (!record) continue;
|
|
||||||
// record.availableStock = record.totalStock;
|
|
||||||
// em.persist(record);
|
|
||||||
// }
|
|
||||||
// await em.flush();
|
|
||||||
// });
|
|
||||||
|
|
||||||
// this.logger.log('Daily inventory reset completed');
|
|
||||||
// } catch (err) {
|
|
||||||
// this.logger.error(`FoodStockCrone failed: ${err?.message}`, err);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
@@ -27,9 +27,6 @@ export class CreateVariantDto {
|
|||||||
@ApiProperty()
|
@ApiProperty()
|
||||||
price: number
|
price: number
|
||||||
|
|
||||||
@IsNumber()
|
|
||||||
@ApiProperty()
|
|
||||||
stock: number
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class CreateProductDto {
|
export class CreateProductDto {
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import { Variant } from './variant.entity';
|
|||||||
@Index({ properties: ['isActive'] })
|
@Index({ properties: ['isActive'] })
|
||||||
export class Product extends BaseEntity {
|
export class Product extends BaseEntity {
|
||||||
@ManyToOne(() => Shop)
|
@ManyToOne(() => Shop)
|
||||||
shop: Shop;
|
shop!: Shop;
|
||||||
|
|
||||||
@ManyToOne(() => Category)
|
@ManyToOne(() => Category)
|
||||||
category: Category;
|
category: Category;
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { Entity, Index, Property, ManyToOne, ManyToMany, Collection } from '@mikro-orm/core';
|
import { Entity, Index, Property, ManyToOne, ManyToMany, Collection } from '@mikro-orm/core';
|
||||||
import { Product } from './product.entity';
|
import { Product } from './product.entity';
|
||||||
import { BaseEntity } from '../../../../common/entities/base.entity';
|
import { BaseEntity } from '../../../common/entities/base.entity';
|
||||||
|
|
||||||
@Entity({ tableName: 'variants' })
|
@Entity({ tableName: 'variants' })
|
||||||
@Index({ properties: ['product', 'isActive'] })
|
@Index({ properties: ['product'] })
|
||||||
export class Variant extends BaseEntity {
|
export class Variant extends BaseEntity {
|
||||||
@ManyToOne(() => Product)
|
@ManyToOne(() => Product)
|
||||||
product!: Product;
|
product!: Product;
|
||||||
@@ -14,7 +14,4 @@ export class Variant extends BaseEntity {
|
|||||||
@Property({ type: 'decimal', precision: 10, scale: 0, nullable: true })
|
@Property({ type: 'decimal', precision: 10, scale: 0, nullable: true })
|
||||||
price?: number;
|
price?: number;
|
||||||
|
|
||||||
@Property({ type: 'int', default: 0 })
|
|
||||||
stock: number = 0;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ export class ProductService {
|
|||||||
constructor(
|
constructor(
|
||||||
private readonly productRepository: ProductRepository,
|
private readonly productRepository: ProductRepository,
|
||||||
private readonly categoryRepository: CategoryRepository,
|
private readonly categoryRepository: CategoryRepository,
|
||||||
private readonly shopService: ShopService,
|
private readonly shopService: ShopService,
|
||||||
private readonly em: EntityManager,
|
private readonly em: EntityManager,
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
@@ -42,8 +42,7 @@ export class ProductService {
|
|||||||
// map single-title/content DTO to localized fields
|
// map single-title/content DTO to localized fields
|
||||||
title: rest.title,
|
title: rest.title,
|
||||||
attribute: rest.attribute,
|
attribute: rest.attribute,
|
||||||
// numeric/array fields
|
|
||||||
price: rest.price ?? 0,
|
|
||||||
images: rest.images ?? undefined,
|
images: rest.images ?? undefined,
|
||||||
shop: shop,
|
shop: shop,
|
||||||
category: category,
|
category: category,
|
||||||
@@ -57,7 +56,6 @@ export class ProductService {
|
|||||||
const variantRecord = em.create(Variant, {
|
const variantRecord = em.create(Variant, {
|
||||||
product,
|
product,
|
||||||
value: variant.value,
|
value: variant.value,
|
||||||
stock: variant.stock,
|
|
||||||
price: variant.price,
|
price: variant.price,
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -102,7 +100,7 @@ export class ProductService {
|
|||||||
|
|
||||||
|
|
||||||
async findByShop(slug: string): Promise<Product[]> {
|
async findByShop(slug: string): Promise<Product[]> {
|
||||||
const shop = await this.shopService.findOrFailBySlug( slug );
|
const shop = await this.shopService.findOrFailBySlug(slug);
|
||||||
|
|
||||||
const queryFilter: FilterQuery<Product> = {
|
const queryFilter: FilterQuery<Product> = {
|
||||||
shop: { slug },
|
shop: { slug },
|
||||||
@@ -142,7 +140,7 @@ export class ProductService {
|
|||||||
const updatedVariantIds = new Set<string>();
|
const updatedVariantIds = new Set<string>();
|
||||||
|
|
||||||
for (const variant of variants) {
|
for (const variant of variants) {
|
||||||
const { id, value, stock, price } = variant;
|
const { id, value, price } = variant;
|
||||||
|
|
||||||
if (id) {
|
if (id) {
|
||||||
// Update existing variant
|
// Update existing variant
|
||||||
@@ -152,14 +150,13 @@ export class ProductService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update the variant fields
|
// Update the variant fields
|
||||||
this.em.assign(existingVariant, { value, stock, price });
|
this.em.assign(existingVariant, { value, price });
|
||||||
updatedVariantIds.add(id);
|
updatedVariantIds.add(id);
|
||||||
} else {
|
} else {
|
||||||
// Create new variant
|
// Create new variant
|
||||||
const variantRecord = this.em.create(Variant, {
|
const variantRecord = this.em.create(Variant, {
|
||||||
product,
|
product,
|
||||||
value,
|
value,
|
||||||
stock,
|
|
||||||
price,
|
price,
|
||||||
});
|
});
|
||||||
this.em.persist(variantRecord);
|
this.em.persist(variantRecord);
|
||||||
@@ -182,10 +179,10 @@ export class ProductService {
|
|||||||
return product;
|
return product;
|
||||||
}
|
}
|
||||||
|
|
||||||
async remove(restId: string, id: string): Promise<void> {
|
async remove(shopId: string, id: string): Promise<void> {
|
||||||
const product = await this.findOrFail(id)
|
const product = await this.findOrFail(id)
|
||||||
|
|
||||||
if (product.shop.id !== restId) {
|
if (product.shop.id !== shopId) {
|
||||||
throw new BadRequestException("Product doesnt belongs to you")
|
throw new BadRequestException("Product doesnt belongs to you")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { Controller, Get, Post, Body, Patch, Param, UseGuards, Delete, Query } from '@nestjs/common';
|
import { Controller, Get, Post, Body, Patch, Param, UseGuards, Delete, Query } from '@nestjs/common';
|
||||||
import { RestaurantsService } from ../../../ shops.service';
|
import { RestaurantsService } from '../../../shops.service';
|
||||||
import { CreateRestaurantDto } from '../dto/create-shop.dto';
|
import { CreateRestaurantDto } from '../dto/create-shop.dto';
|
||||||
import { UpdateRestaurantDto } from '../dto/update-shop.dto';
|
import { UpdateRestaurantDto } from '../dto/update-shop.dto';
|
||||||
import { UpgradeSubscriptionDto } from '../dto/upgrade-subscription.dto';
|
import { UpgradeSubscriptionDto } from '../dto/upgrade-subscription.dto';
|
||||||
import { FindRestaurantsDto } from ../../../ shops.dto';
|
import { FindRestaurantsDto } from '../dto/find-shops.dto';
|
||||||
import { AdminAuthGuard } from 'src/modules/auth/guards/adminAuth.guard';
|
import { AdminAuthGuard } from 'src/modules/auth/guards/adminAuth.guard';
|
||||||
import {
|
import {
|
||||||
ApiBearerAuth,
|
ApiBearerAuth,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Collection, Entity, Enum, Index, OneToMany, Property } from '@mikro-orm/core';
|
import { Collection, Entity, Enum, Index, OneToMany, Property } from '@mikro-orm/core';
|
||||||
import { BaseEntity } from '../../../../common/entities/base.entity';
|
import { BaseEntity } from '../../../common/entities/base.entity';
|
||||||
import { Delivery } from '../../../delivery/entities/delivery.entity';
|
import { Delivery } from '../../delivery/entities/delivery.entity';
|
||||||
import { PlanEnum } from '../interface/plan.interface';
|
import { PlanEnum } from '../interface/plan.interface';
|
||||||
|
|
||||||
@Entity({ tableName: 'shops' })
|
@Entity({ tableName: 'shops' })
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { Shop } from '../entities/shop.entity';
|
|||||||
import { EntityManager } from '@mikro-orm/postgresql';
|
import { EntityManager } from '@mikro-orm/postgresql';
|
||||||
import { shopRepository } from '../repositories/rest.repository';
|
import { shopRepository } from '../repositories/rest.repository';
|
||||||
import { RestMessage } from 'src/common/enums/message.enum';
|
import { RestMessage } from 'src/common/enums/message.enum';
|
||||||
import { FindRestaurantsDto } from '../providers/shops.dto';
|
import { FindRestaurantsDto } from '../dto/find-shops.dto';
|
||||||
import { PaginatedResult } from 'src/common/interfaces/pagination.interface';
|
import { PaginatedResult } from 'src/common/interfaces/pagination.interface';
|
||||||
import { PlanEnum } from '../interface/plan.interface';
|
import { PlanEnum } from '../interface/plan.interface';
|
||||||
import { Admin } from '../../../admin/entities/admin.entity';
|
import { Admin } from '../../../admin/entities/admin.entity';
|
||||||
@@ -18,8 +18,8 @@ import { NotificationPreference } from '../../../notifications/entities/notifica
|
|||||||
import { notificationPreferencesData } from '../../../../seeders/data/notification-preferences.data';
|
import { notificationPreferencesData } from '../../../../seeders/data/notification-preferences.data';
|
||||||
import { Order } from '../../../orders/entities/order.entity';
|
import { Order } from '../../../orders/entities/order.entity';
|
||||||
import { Coupon } from '../../../coupons/entities/coupon.entity';
|
import { Coupon } from '../../../coupons/entities/coupon.entity';
|
||||||
import { Category } from ../../..products / entities / category.entity';
|
import { Category } from '../../../products/entities/category.entity';
|
||||||
import { Product } from ../../..products / entities / product.entity';
|
import { Product } from '../../../products/entities/product.entity';
|
||||||
import { Delivery } from '../../../delivery/entities/delivery.entity';
|
import { Delivery } from '../../../delivery/entities/delivery.entity';
|
||||||
import { PaymentMethod } from '../../../payments/entities/payment-method.entity';
|
import { PaymentMethod } from '../../../payments/entities/payment-method.entity';
|
||||||
import { Pager } from '../../../pager/entities/pager.entity';
|
import { Pager } from '../../../pager/entities/pager.entity';
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Entity, Property, ManyToOne, Index, Enum } from '@mikro-orm/core';
|
import { Entity, Property, ManyToOne, Index, Enum } from '@mikro-orm/core';
|
||||||
import { BaseEntity } from '../../../../common/entities/base.entity';
|
import { BaseEntity } from '../../../../common/entities/base.entity';
|
||||||
import { Shop } from ../../../shops/entities/shop.entity';
|
import { Shop } from '../../../shops/entities/shop.entity';
|
||||||
import { User } from './user.entity';
|
import { User } from './user.entity';
|
||||||
import { PointTransactionReason } from '../interface/point';
|
import { PointTransactionReason } from '../interface/point';
|
||||||
import { PointTransactionType } from '../interface/point';
|
import { PointTransactionType } from '../interface/point';
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { Entity, Index, Property, ManyToOne, Enum } from '@mikro-orm/core';
|
|||||||
import { BaseEntity } from '../../../../common/entities/base.entity';
|
import { BaseEntity } from '../../../../common/entities/base.entity';
|
||||||
import { User } from './user.entity';
|
import { User } from './user.entity';
|
||||||
import { WalletTransactionReason, WalletTransactionType } from '../interface/wallet';
|
import { WalletTransactionReason, WalletTransactionType } from '../interface/wallet';
|
||||||
import { Shop } from ../../../shops/entities/shop.entity';
|
import { Shop } from '../../../shops/entities/shop.entity';
|
||||||
|
|
||||||
@Entity({ tableName: 'wallet_transactions' })
|
@Entity({ tableName: 'wallet_transactions' })
|
||||||
@Index({ properties: ['user', 'shop'] })
|
@Index({ properties: ['user', 'shop'] })
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { Injectable, NotFoundException, BadRequestException } from '@nestjs/comm
|
|||||||
import { FilterQuery, RequiredEntityData } from '@mikro-orm/core';
|
import { FilterQuery, RequiredEntityData } from '@mikro-orm/core';
|
||||||
import { User } from '../entities/user.entity';
|
import { User } from '../entities/user.entity';
|
||||||
import { UserAddress } from '../entities/user-address.entity';
|
import { UserAddress } from '../entities/user-address.entity';
|
||||||
import { Shop } from ../../../shops/entities/shop.entity';
|
import { Shop } from '../../../shops/entities/shop.entity';
|
||||||
import { EntityManager } from '@mikro-orm/postgresql';
|
import { EntityManager } from '@mikro-orm/postgresql';
|
||||||
import { UpdateUserDto } from '../dto/update-user.dto';
|
import { UpdateUserDto } from '../dto/update-user.dto';
|
||||||
import { FindUsersDto } from '../dto/find-user.dto';
|
import { FindUsersDto } from '../dto/find-user.dto';
|
||||||
@@ -13,7 +13,7 @@ import { UpdateUserAddressDto } from '../dto/update-user-address.dto';
|
|||||||
import { PaginatedResult } from 'src/common/interfaces/pagination.interface';
|
import { PaginatedResult } from 'src/common/interfaces/pagination.interface';
|
||||||
import { UserRepository } from '../repositories/user.repository';
|
import { UserRepository } from '../repositories/user.repository';
|
||||||
import { normalizePhone } from '../../../utils/phone.util';
|
import { normalizePhone } from '../../../utils/phone.util';
|
||||||
import { RestRepository } from ../../../shops/repositories/rest.repository';
|
import { RestRepository } from '../../../shops/repositories/rest.repository';
|
||||||
import { WalletTransactionRepository } from '../repositories/wallet-transaction.repository';
|
import { WalletTransactionRepository } from '../repositories/wallet-transaction.repository';
|
||||||
import { WalletService } from './wallet.service';
|
import { WalletService } from './wallet.service';
|
||||||
import { WalletTransactionReason, WalletTransactionType } from '../interface/wallet';
|
import { WalletTransactionReason, WalletTransactionType } from '../interface/wallet';
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { User } from './entities/user.entity';
|
|||||||
import { UserAddress } from './entities/user-address.entity';
|
import { UserAddress } from './entities/user-address.entity';
|
||||||
import { JwtModule } from '@nestjs/jwt';
|
import { JwtModule } from '@nestjs/jwt';
|
||||||
import { UserRepository } from './repositories/user.repository';
|
import { UserRepository } from './repositories/user.repository';
|
||||||
import { RestaurantsModule } from ../../../shops.module';
|
import { RestaurantsModule } from '../../../shops.module';
|
||||||
import { WalletTransactionRepository } from './repositories/wallet-transaction.repository';
|
import { WalletTransactionRepository } from './repositories/wallet-transaction.repository';
|
||||||
import { WalletService } from './providers/wallet.service';
|
import { WalletService } from './providers/wallet.service';
|
||||||
import { WalletTransaction } from './entities/wallet-transaction.entity';
|
import { WalletTransaction } from './entities/wallet-transaction.entity';
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import type { EntityManager } from '@mikro-orm/core';
|
|||||||
import { Admin } from '../modules/admin/entities/admin.entity';
|
import { Admin } from '../modules/admin/entities/admin.entity';
|
||||||
import { AdminRole } from '../modules/admin/entities/adminRole.entity';
|
import { AdminRole } from '../modules/admin/entities/adminRole.entity';
|
||||||
import type { Role } from '../modules/roles/entities/role.entity';
|
import type { Role } from '../modules/roles/entities/role.entity';
|
||||||
import type { Shop } from ../../../shops/entities/shop.entity';
|
import type { Shop } from '../../../shops/entities/shop.entity';
|
||||||
import { adminsData } from './data/admins.data';
|
import { adminsData } from './data/admins.data';
|
||||||
import { normalizePhone } from '../modules/utils/phone.util';
|
import { normalizePhone } from '../modules/utils/phone.util';
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import type { EntityManager } from '@mikro-orm/core';
|
import type { EntityManager } from '@mikro-orm/core';
|
||||||
import { Category } from ../../../products/entities/category.entity';
|
import { Category } from '../../../products/entities/category.entity';
|
||||||
import type { Shop } from ../../../shops/entities/shop.entity';
|
import type { Shop } from '../../../shops/entities/shop.entity';
|
||||||
import { categoriesData } from './data/categories.data';
|
import { categoriesData } from './data/categories.data';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import type { EntityManager } from '@mikro-orm/core';
|
import type { EntityManager } from '@mikro-orm/core';
|
||||||
import { Coupon } from '../modules/coupons/entities/coupon.entity';
|
import { Coupon } from '../modules/coupons/entities/coupon.entity';
|
||||||
import type { Shop } from ../../../shops/entities/shop.entity';
|
import type { Shop } from '../../../shops/entities/shop.entity';
|
||||||
import { couponsData } from './data/coupons.data';
|
import { couponsData } from './data/coupons.data';
|
||||||
|
|
||||||
export class CouponsSeeder {
|
export class CouponsSeeder {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import type { EntityManager } from '@mikro-orm/core';
|
import type { EntityManager } from '@mikro-orm/core';
|
||||||
import { Delivery } from '../modules/delivery/entities/delivery.entity';
|
import { Delivery } from '../modules/delivery/entities/delivery.entity';
|
||||||
import type { Shop } from ../../../shops/entities/shop.entity';
|
import type { Shop } from '../../../shops/entities/shop.entity';
|
||||||
import { deliveryMethodsData } from './data/delivery-methods.data';
|
import { deliveryMethodsData } from './data/delivery-methods.data';
|
||||||
import { DeliveryFeeTypeEnum } from 'src/modules/delivery/interface/delivery';
|
import { DeliveryFeeTypeEnum } from 'src/modules/delivery/interface/delivery';
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import type { EntityManager } from '@mikro-orm/core';
|
import type { EntityManager } from '@mikro-orm/core';
|
||||||
import { NotificationPreference } from '../modules/notifications/entities/notification-preference.entity';
|
import { NotificationPreference } from '../modules/notifications/entities/notification-preference.entity';
|
||||||
import type { Shop } from ../../../shops/entities/shop.entity';
|
import type { Shop } from '../../../shops/entities/shop.entity';
|
||||||
import { notificationPreferencesData } from './data/notification-preferences.data';
|
import { notificationPreferencesData } from './data/notification-preferences.data';
|
||||||
|
|
||||||
export class NotificationPreferencesSeeder {
|
export class NotificationPreferencesSeeder {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import type { EntityManager } from '@mikro-orm/core';
|
|||||||
import { Notification } from '../modules/notifications/entities/notification.entity';
|
import { Notification } from '../modules/notifications/entities/notification.entity';
|
||||||
import { Admin } from '../modules/admin/entities/admin.entity';
|
import { Admin } from '../modules/admin/entities/admin.entity';
|
||||||
import { User } from '../modules/users/entities/user.entity';
|
import { User } from '../modules/users/entities/user.entity';
|
||||||
import { Shop } from ../../../shops/entities/shop.entity';
|
import { Shop } from '../../../shops/entities/shop.entity';
|
||||||
import { NotifTitleEnum } from '../modules/notifications/interfaces/notification.interface';
|
import { NotifTitleEnum } from '../modules/notifications/interfaces/notification.interface';
|
||||||
|
|
||||||
export class NotificationsSeeder {
|
export class NotificationsSeeder {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import type { EntityManager } from '@mikro-orm/core';
|
import type { EntityManager } from '@mikro-orm/core';
|
||||||
import { PaymentMethod } from '../modules/payments/entities/payment-method.entity';
|
import { PaymentMethod } from '../modules/payments/entities/payment-method.entity';
|
||||||
import type { Shop } from ../../../shops/entities/shop.entity';
|
import type { Shop } from '../../../shops/entities/shop.entity';
|
||||||
import { paymentMethodsData } from './data/payment-methods.data';
|
import { paymentMethodsData } from './data/payment-methods.data';
|
||||||
|
|
||||||
export class PaymentMethodsSeeder {
|
export class PaymentMethodsSeeder {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import type { EntityManager } from '@mikro-orm/core';
|
import type { EntityManager } from '@mikro-orm/core';
|
||||||
import { Schedule } from ../../../shops/entities/schedule.entity';
|
import { Schedule } from '../../../shops/entities/schedule.entity';
|
||||||
import type { Shop } from ../../../shops/entities/shop.entity';
|
import type { Shop } from '../../../shops/entities/shop.entity';
|
||||||
import { timeSlots } from './data/schedules.data';
|
import { timeSlots } from './data/schedules.data';
|
||||||
|
|
||||||
export class SchedulesSeeder {
|
export class SchedulesSeeder {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import type { EntityManager } from '@mikro-orm/core';
|
import type { EntityManager } from '@mikro-orm/core';
|
||||||
import { User } from '../modules/users/entities/user.entity';
|
import { User } from '../modules/users/entities/user.entity';
|
||||||
import { Shop } from ../../../shops/entities/shop.entity';
|
import { Shop } from '../../../shops/entities/shop.entity';
|
||||||
import { WalletTransaction } from '../modules/users/entities/wallet-transaction.entity';
|
import { WalletTransaction } from '../modules/users/entities/wallet-transaction.entity';
|
||||||
import { WalletTransactionReason, WalletTransactionType } from 'src/modules/users/interface/wallet';
|
import { WalletTransactionReason, WalletTransactionType } from 'src/modules/users/interface/wallet';
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user