remove inventory
This commit is contained in:
@@ -22,7 +22,6 @@ import { NotificationsModule } from './modules/notifications/notifications.modul
|
||||
import { EventEmitterModule } from '@nestjs/event-emitter';
|
||||
import { PagerModule } from './modules/pager/pager.module';
|
||||
import { ContactModule } from './modules/contact/contact.module';
|
||||
import { InventoryModule } from './modules/inventory/inventory.module';
|
||||
import { IconsModule } from './modules/icons/icons.module';
|
||||
import { CacheModule } from '@nestjs/cache-manager';
|
||||
import { cacheConfig } from './config/cache.config';
|
||||
@@ -57,7 +56,6 @@ import { cacheConfig } from './config/cache.config';
|
||||
EventEmitterModule.forRoot(),
|
||||
PagerModule,
|
||||
ContactModule,
|
||||
InventoryModule,
|
||||
IconsModule,
|
||||
],
|
||||
controllers: [],
|
||||
|
||||
@@ -753,13 +753,6 @@ export const enum DeliveryMessage {
|
||||
DELIVERY_METHOD_NOT_FOUND = 'روش ارسال یافت نشد',
|
||||
}
|
||||
|
||||
export const enum InventoryMessage {
|
||||
AVAILABLE_STOCK_EXCEEDS_TOTAL = 'موجودی موجود نمیتواند از موجودی کل بیشتر باشد',
|
||||
PRODUCT_NOT_FOUND = 'محصول یافت نشد',
|
||||
PRODUCT_NOT_BELONGS_TO_SHOP = 'محصول به این فروشگاه تعلق ندارد',
|
||||
SHOP_NOT_FOUND = 'فروشگاه یافت نشد',
|
||||
PRODUCTS_NOT_FOUND = 'محصولات یافت نشدند',
|
||||
}
|
||||
|
||||
|
||||
export const enum PagerMessage {
|
||||
|
||||
@@ -9,7 +9,7 @@ import { Permission } from '../roles/entities/permission.entity';
|
||||
import { RolePermission } from '../roles/entities/rolePermission.entity';
|
||||
import { AdminController } from './controllers/admin.controller';
|
||||
import { UtilsModule } from '../utils/utils.module';
|
||||
import { RestaurantsModule } from ../../..shops.module';
|
||||
import { ShopsModule } from '../../../shops/shops.module';
|
||||
import { AdminRole } from './entities/adminRole.entity';
|
||||
|
||||
@Module({
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Entity, Index, ManyToOne, Unique } from '@mikro-orm/core';
|
||||
import { BaseEntity } from '../../../../common/entities/base.entity';
|
||||
import { Role } from '../../../roles/entities/role.entity';
|
||||
import { Shop } from ../../..shops/entities/shop.entity';
|
||||
import { Shop } from '../../../shops/entities/shop.entity';
|
||||
import { Admin } from './admin.entity';
|
||||
|
||||
@Entity({ tableName: 'admin_roles' })
|
||||
|
||||
@@ -3,7 +3,7 @@ import { InjectRepository } from '@mikro-orm/nestjs';
|
||||
import { EntityRepository } from '@mikro-orm/core';
|
||||
import { Admin } from '../entities/admin.entity';
|
||||
import { Role } from '../../../roles/entities/role.entity';
|
||||
import { Shop } from ../../..shops/entities/shop.entity';
|
||||
import { Shop } from ../../../shops/entities/shop.entity';
|
||||
import { EntityManager } from '@mikro-orm/postgresql';
|
||||
import { CacheService } from '../../../utils/cache.service';
|
||||
import { CreateMyRestaurantAdminDto } from '../dto/create-my-shop-admin.dto';
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { EntityManager, EntityRepository } from '@mikro-orm/postgresql';
|
||||
import { Admin } from '../entities/admin.entity';
|
||||
import { AdminRole } from '../entities/adminRole.entity';
|
||||
import { RestRepository } from ../../..shops/repositories/rest.repository';
|
||||
import { RestRepository } from ../../../shops/repositories/rest.repository';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { normalizePhone } from '../../../utils/phone.util';
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import { JwtModule } from '@nestjs/jwt';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { AdminModule } from '../admin/admin.module';
|
||||
import { TokensService } from './services/tokens.service';
|
||||
import { RestaurantsModule } from ../../..shops.module';
|
||||
import { RestaurantsModule } from ../../../shops.module';
|
||||
import { MikroOrmModule } from '@mikro-orm/nestjs';
|
||||
import { User } from '../users/entities/user.entity';
|
||||
import { AdminAuthGuard } from './guards/adminAuth.guard';
|
||||
|
||||
@@ -5,7 +5,7 @@ import { SmsService } from '../../../notifications/services/sms.service';
|
||||
import { UserService } from '../../../users/providers/user.service';
|
||||
import { randomInt } from 'crypto';
|
||||
import { TokensService } from './tokens.service';
|
||||
import { RestRepository } from ../../..shops/repositories/rest.repository';
|
||||
import { RestRepository } from ../../../shops/repositories/rest.repository';
|
||||
import { AuthMessage, RestMessage } from 'src/common/enums/message.enum';
|
||||
import { AdminRepository } from 'src/modules/admin/repositories/admin.repository';
|
||||
import { AdminLoginTransformer } from '../transformers/admin-login.transformer';
|
||||
|
||||
@@ -9,7 +9,7 @@ import dayjs from 'dayjs';
|
||||
import { AuthMessage } from '../../../../common/enums/message.enum';
|
||||
import { RefreshToken, RefreshTokenType } from '../entities/refresh-token.entity';
|
||||
import { IAdminTokenPayload, ITokenPayload } from '../interfaces/IToken-payload';
|
||||
import { Shop } from ../../..shops/entities/shop.entity';
|
||||
import { Shop } from ../../../shops/entities/shop.entity';
|
||||
|
||||
@Injectable()
|
||||
export class TokensService {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { Admin } from '../../../admin/entities/admin.entity';
|
||||
import type { Shop } from ../../..shops/entities/shop.entity';
|
||||
import type { Shop } from ../../../shops/entities/shop.entity';
|
||||
|
||||
export interface AdminLoginResponse {
|
||||
id: string;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { User } from '../../../users/entities/user.entity';
|
||||
import type { Shop } from ../../..shops/entities/shop.entity';
|
||||
import type { Shop } from ../../../shops/entities/shop.entity';
|
||||
|
||||
export interface UserLoginResponse {
|
||||
id: string;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Injectable, NotFoundException } from '@nestjs/common';
|
||||
import { Product } from ../../..products/entities/product.entity';
|
||||
import { Product } from ../../../products/entities/product.entity';
|
||||
import { Cart, CartItem } from '../interfaces/cart.interface';
|
||||
import { CartValidationService } from './cart-validation.service';
|
||||
import { CartCalculationService } from './cart-calculation.service';
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
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 { 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';
|
||||
@@ -23,10 +23,10 @@ export class CartValidationService {
|
||||
) { }
|
||||
|
||||
/**
|
||||
* Validate product exists, belongs to shop, has inventory, and check stock
|
||||
* 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', 'inventory'] });
|
||||
const product = await this.em.findOne(Product, { id: foodId }, { populate: ['shop'] });
|
||||
if (!product) {
|
||||
throw new NotFoundException(CartMessage.FOOD_NOT_FOUND);
|
||||
}
|
||||
@@ -35,23 +35,9 @@ export class CartValidationService {
|
||||
throw new BadRequestException(CartMessage.FOOD_NOT_BELONGS_TO_RESTAURANT);
|
||||
}
|
||||
|
||||
if (!product.inventory) {
|
||||
throw new BadRequestException(CartMessage.FOOD_NO_INVENTORY);
|
||||
}
|
||||
|
||||
this.validateStock(product, quantity);
|
||||
return product;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate stock availability for product
|
||||
*/
|
||||
validateStock(product: Product, quantity: number): void {
|
||||
const availableStock = product.inventory!.availableStock;
|
||||
if (availableStock < quantity) {
|
||||
throw new BadRequestException(CartMessage.INSUFFICIENT_STOCK + product.title);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user or throw if not found
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Entity, Enum, ManyToOne, Property } from '@mikro-orm/core';
|
||||
import { BaseEntity } from '../../../../common/entities/base.entity';
|
||||
import { ContactScope, ContactStatusEnum } from '../interface/interface';
|
||||
import { Shop } from ../../..shops/entities/shop.entity';
|
||||
import { Shop } from ../../../shops/entities/shop.entity';
|
||||
|
||||
@Entity({ tableName: 'contacts' })
|
||||
export class Contact extends BaseEntity {
|
||||
|
||||
@@ -8,7 +8,7 @@ import { PaginatedResult } from 'src/common/interfaces/pagination.interface';
|
||||
import { ContactStatusEnum } from '../interface/interface';
|
||||
import { EntityManager } from '@mikro-orm/postgresql';
|
||||
import { ContactScope } from '../interface/interface';
|
||||
import { Shop } from ../../..shops/entities/shop.entity';
|
||||
import { Shop } from ../../../shops/entities/shop.entity';
|
||||
|
||||
@Injectable()
|
||||
export class ContactService {
|
||||
|
||||
@@ -4,7 +4,7 @@ import { CouponController } from './controllers/coupon.controller';
|
||||
import { CouponRepository } from './repositories/coupon.repository';
|
||||
import { MikroOrmModule } from '@mikro-orm/nestjs';
|
||||
import { Coupon } from './entities/coupon.entity';
|
||||
import { RestaurantsModule } from ../../..shops.module';
|
||||
import { RestaurantsModule } from ../../../shops.module';
|
||||
import { AuthModule } from '../auth/auth.module';
|
||||
import { JwtModule } from '@nestjs/jwt';
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Entity, Index, ManyToOne, Property, Enum, Unique } from '@mikro-orm/core';
|
||||
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 { CouponType } from '../interface/coupon';
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import { CreateCouponDto } from '../dto/create-coupon.dto';
|
||||
import { UpdateCouponDto } from '../dto/update-coupon.dto';
|
||||
import { FindCouponsDto } from '../dto/find-coupons.dto';
|
||||
import { CouponRepository } from '../repositories/coupon.repository';
|
||||
import { RestRepository } from ../../..shops/repositories/rest.repository';
|
||||
import { RestRepository } from ../../../shops/repositories/rest.repository';
|
||||
import { EntityManager } from '@mikro-orm/postgresql';
|
||||
import { RequiredEntityData } from '@mikro-orm/core';
|
||||
import { Coupon } from '../entities/coupon.entity';
|
||||
|
||||
@@ -3,7 +3,7 @@ import { MikroOrmModule } from '@mikro-orm/nestjs';
|
||||
import { JwtModule } from '@nestjs/jwt';
|
||||
import { DeliveryController } from './controllers/delivery.controller';
|
||||
import { DeliveryService } from './providers/delivery.service';
|
||||
import { RestaurantsModule } from ../../..shops.module';
|
||||
import { RestaurantsModule } from ../../../shops.module';
|
||||
import { Delivery } from './entities/delivery.entity';
|
||||
import { DeliveryRepository } from './repositories/delivery.repository';
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import { Delivery } from '../entities/delivery.entity';
|
||||
import { DeliveryRepository } from '../repositories/delivery.repository';
|
||||
import { CreateDeliveryDto } from '../dto/create-delivery.dto';
|
||||
import { UpdateDeliveryDto } from '../dto/update-delivery.dto';
|
||||
import { RestRepository } from ../../..shops/repositories/rest.repository';
|
||||
import { RestRepository } from ../../../shops/repositories/rest.repository';
|
||||
import { DeliveryMethodEnum } from '../interface/delivery';
|
||||
import { DeliveryMessage } from 'src/common/enums/message.enum';
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ import { Category } from './category.entity';
|
||||
import { BaseEntity } from '../../../common/entities/base.entity';
|
||||
import { Shop } from '../../../modules/shops/entities/shop.entity';
|
||||
import { Review } from 'src/modules/review/entities/review.entity';
|
||||
import { Inventory } from 'src/modules/inventory/entities/inventory.entity';
|
||||
import { Favorite } from './favorite.entity';
|
||||
|
||||
@Entity({ tableName: 'products' })
|
||||
@@ -20,11 +19,6 @@ export class Product extends BaseEntity {
|
||||
@OneToMany(() => Review, review => review.product, { cascade: [Cascade.ALL], orphanRemoval: true })
|
||||
reviews = new Collection<Review>(this);
|
||||
|
||||
@OneToOne(() => Inventory, {
|
||||
mappedBy: 'product',
|
||||
nullable: true,
|
||||
})
|
||||
inventory?: Inventory;
|
||||
|
||||
@OneToMany(() => Favorite, favorite => favorite.product)
|
||||
favorites = new Collection<Favorite>(this);
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsNotEmpty, IsArray, ValidateNested, ArrayMinSize, IsString, IsNumber, Min } from 'class-validator';
|
||||
import { Type } from 'class-transformer';
|
||||
|
||||
export class BulkReserveFoodItemDto {
|
||||
@ApiProperty({ example: 'product-123', description: 'Product ID' })
|
||||
@IsNotEmpty()
|
||||
@IsString()
|
||||
foodId!: string;
|
||||
|
||||
@ApiProperty({ example: 5, description: 'Quantity to reserve' })
|
||||
@IsNotEmpty()
|
||||
@IsNumber()
|
||||
@Min(1)
|
||||
@Type(() => Number)
|
||||
quantity!: number;
|
||||
}
|
||||
|
||||
export class BulkReserveFoodDto {
|
||||
@ApiProperty({
|
||||
description: 'Array of product reservations to create',
|
||||
type: [BulkReserveFoodItemDto],
|
||||
example: [
|
||||
{ foodId: 'product-123', quantity: 5 },
|
||||
{ foodId: 'product-789', quantity: 3 },
|
||||
],
|
||||
})
|
||||
@IsNotEmpty()
|
||||
@IsArray()
|
||||
@ArrayMinSize(1, { message: 'At least one item is required' })
|
||||
@ValidateNested({ each: true })
|
||||
@Type(() => BulkReserveFoodItemDto)
|
||||
items!: BulkReserveFoodItemDto[];
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsNotEmpty, IsArray, ValidateNested, ArrayMinSize } from 'class-validator';
|
||||
import { Type } from 'class-transformer';
|
||||
import { SetStockDto } from './set-stock.dto';
|
||||
|
||||
export class BulkSetStockItemDto extends SetStockDto {
|
||||
@ApiProperty({ example: 'product-123', description: 'Product ID' })
|
||||
@IsNotEmpty()
|
||||
foodId!: string;
|
||||
}
|
||||
|
||||
export class BulkSetStockDto {
|
||||
@ApiProperty({
|
||||
description: 'Array of stock items to set',
|
||||
type: [BulkSetStockItemDto],
|
||||
example: [
|
||||
{ foodId: 'product-123', totalStock: 100, availableStock: 80 },
|
||||
{ foodId: 'product-456', totalStock: 50, availableStock: 45 },
|
||||
],
|
||||
})
|
||||
@IsNotEmpty()
|
||||
@IsArray()
|
||||
@ArrayMinSize(1, { message: 'At least one item is required' })
|
||||
@ValidateNested({ each: true })
|
||||
@Type(() => BulkSetStockItemDto)
|
||||
items!: BulkSetStockItemDto[];
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
export class CreateInventoryDto {}
|
||||
@@ -1,17 +0,0 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsNumber, Min } from 'class-validator';
|
||||
import { Type } from 'class-transformer';
|
||||
|
||||
export class SetStockDto {
|
||||
@ApiProperty({ example: 100, description: 'Total stock quantity' })
|
||||
@IsNumber()
|
||||
@Min(0)
|
||||
@Type(() => Number)
|
||||
totalStock!: number;
|
||||
|
||||
@ApiProperty({ example: 80, description: 'Available stock quantity' })
|
||||
@IsNumber()
|
||||
@Min(0)
|
||||
@Type(() => Number)
|
||||
availableStock!: number;
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
import { Cascade, Entity, Property, OneToOne } from '@mikro-orm/core';
|
||||
import { BaseEntity } from '../../../../common/entities/base.entity';
|
||||
import { Product } from '../../../products/entities/product.entity';
|
||||
|
||||
@Entity({ tableName: 'inventory' })
|
||||
export class Inventory extends BaseEntity {
|
||||
@OneToOne(() => Product, {
|
||||
cascade: [Cascade.ALL],
|
||||
orphanRemoval: true,
|
||||
})
|
||||
product!: Product;
|
||||
|
||||
@Property({ type: 'int' })
|
||||
totalStock!: number;
|
||||
|
||||
@Property({ type: 'int' })
|
||||
availableStock!: number;
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
export enum ReservationStatus {
|
||||
ACTIVE = 'active',
|
||||
CONFIRMED = 'confirmed',
|
||||
}
|
||||
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
import { Controller, Body, Patch, Param, Post, UseGuards } from '@nestjs/common';
|
||||
import { InventoryService } from './inventory.service';
|
||||
import { SetStockDto } from './dto/set-stock.dto';
|
||||
import { BulkSetStockDto } from './dto/bulk-set-stock.dto';
|
||||
import { ApiTags, ApiOperation, ApiBody, ApiParam, ApiBearerAuth } from '@nestjs/swagger';
|
||||
import { AdminAuthGuard } from 'src/modules/auth/guards/adminAuth.guard';
|
||||
import { RestId } from 'src/common/decorators';
|
||||
import { Inventory } from './entities/inventory.entity';
|
||||
import { Permissions } from 'src/common/decorators/permissions.decorator';
|
||||
import { Permission } from 'src/common/enums/permission.enum';
|
||||
|
||||
@ApiTags('inventory')
|
||||
@UseGuards(AdminAuthGuard)
|
||||
@ApiBearerAuth()
|
||||
@Permissions(Permission.MANAGE_FOODS)
|
||||
@Controller()
|
||||
export class InventoryController {
|
||||
constructor(private readonly inventoryService: InventoryService) { }
|
||||
|
||||
@Patch('admin/inventory/product/:foodId/stock')
|
||||
@ApiOperation({ summary: 'Set available and total stock for a product item' })
|
||||
@ApiParam({ name: 'foodId', description: 'Product ID' })
|
||||
@ApiBody({ type: SetStockDto })
|
||||
setStockForFood(
|
||||
@Param('foodId') foodId: string,
|
||||
@RestId() restaurantId: string,
|
||||
@Body() setStockDto: SetStockDto,
|
||||
): Promise<Inventory> {
|
||||
return this.inventoryService.setStockForFood(foodId, restaurantId, setStockDto);
|
||||
}
|
||||
|
||||
@Post('admin/inventory/products/stock/bulk')
|
||||
@ApiOperation({ summary: 'Bulk set available and total stock for multiple product items' })
|
||||
@ApiBody({ type: BulkSetStockDto })
|
||||
bulkSetStockForFoods(@RestId() restaurantId: string, @Body() bulkSetStockDto: BulkSetStockDto): Promise<Inventory[]> {
|
||||
return this.inventoryService.bulkSetStockForFoods(restaurantId, bulkSetStockDto);
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { MikroOrmModule } from '@mikro-orm/nestjs';
|
||||
import { InventoryService } from './inventory.service';
|
||||
import { InventoryController } from './inventory.controller';
|
||||
import { Inventory } from './entities/inventory.entity';
|
||||
import { AuthModule } from '../auth/auth.module';
|
||||
import { JwtModule } from '@nestjs/jwt';
|
||||
|
||||
@Module({
|
||||
imports: [MikroOrmModule.forFeature([Inventory]), AuthModule, JwtModule],
|
||||
controllers: [InventoryController],
|
||||
providers: [InventoryService],
|
||||
exports: [InventoryService],
|
||||
})
|
||||
export class InventoryModule {}
|
||||
@@ -1,227 +0,0 @@
|
||||
import { Injectable, NotFoundException, BadRequestException } from '@nestjs/common';
|
||||
import { EntityManager } from '@mikro-orm/postgresql';
|
||||
import { SetStockDto } from './dto/set-stock.dto';
|
||||
import { BulkSetStockDto } from './dto/bulk-set-stock.dto';
|
||||
import { BulkReserveFoodDto } from './dto/bulk-reserve-product.dto';
|
||||
import { Inventory } from './entities/inventory.entity';
|
||||
import { Product } from ../../..products/entities/product.entity';
|
||||
import { Shop } from ../../..shops/entities/shop.entity';
|
||||
|
||||
@Injectable()
|
||||
export class InventoryService {
|
||||
constructor(private readonly em: EntityManager) {}
|
||||
|
||||
async setStockForFood(foodId: string, restaurantId: string, setStockDto: SetStockDto): Promise<Inventory> {
|
||||
// Validate that availableStock doesn't exceed totalStock
|
||||
if (setStockDto.availableStock > setStockDto.totalStock) {
|
||||
throw new BadRequestException('Available stock cannot exceed total stock');
|
||||
}
|
||||
|
||||
// Find product and verify it belongs to the shop
|
||||
const product = await this.em.findOne(Product, { id: foodId }, { populate: ['shop'] });
|
||||
if (!product) {
|
||||
throw new NotFoundException(`Product with ID ${foodId} not found`);
|
||||
}
|
||||
|
||||
if (product.shop.id !== restaurantId) {
|
||||
throw new BadRequestException(`Product does not belong to shop ${restaurantId}`);
|
||||
}
|
||||
|
||||
// Find or create inventory record
|
||||
let inventory = await this.em.findOne(Inventory, {
|
||||
product: { id: foodId, shop: { id: restaurantId } },
|
||||
});
|
||||
|
||||
if (!inventory) {
|
||||
// Create new inventory record
|
||||
const shop = await this.em.findOne(Shop, { id: restaurantId });
|
||||
if (!shop) {
|
||||
throw new NotFoundException(`Shop with ID ${restaurantId} not found`);
|
||||
}
|
||||
|
||||
inventory = this.em.create(Inventory, {
|
||||
product,
|
||||
totalStock: setStockDto.totalStock,
|
||||
availableStock: setStockDto.availableStock,
|
||||
});
|
||||
} else {
|
||||
// Update existing inventory record
|
||||
inventory.totalStock = setStockDto.totalStock;
|
||||
inventory.availableStock = setStockDto.availableStock;
|
||||
}
|
||||
|
||||
await this.em.flush();
|
||||
|
||||
return inventory;
|
||||
}
|
||||
|
||||
async bulkSetStockForFoods(restaurantId: string, bulkSetStockDto: BulkSetStockDto): Promise<Inventory[]> {
|
||||
const { items } = bulkSetStockDto;
|
||||
// Validate all items first
|
||||
for (const item of items) {
|
||||
if (item.availableStock > item.totalStock) {
|
||||
throw new BadRequestException(`Available stock cannot exceed total stock for product ${item.foodId}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Get all product IDs
|
||||
const foodIds = items.map(item => item.foodId);
|
||||
|
||||
// Load all products in one query
|
||||
const products = await this.em.find(Product, { id: { $in: foodIds } }, { populate: ['shop'] });
|
||||
|
||||
// Verify all products exist and belong to the shop
|
||||
const foodMap = new Map<string, Product>();
|
||||
for (const product of products) {
|
||||
if (product.shop.id !== restaurantId) {
|
||||
throw new BadRequestException(`Product ${product.id} does not belong to shop ${restaurantId}`);
|
||||
}
|
||||
foodMap.set(product.id, product);
|
||||
}
|
||||
|
||||
// Check for missing products
|
||||
const missingFoodIds = foodIds.filter(id => !foodMap.has(id));
|
||||
if (missingFoodIds.length > 0) {
|
||||
throw new NotFoundException(`Products not found: ${missingFoodIds.join(', ')}`);
|
||||
}
|
||||
|
||||
// Load all existing inventories in one query
|
||||
const existingInventories = await this.em.find(Inventory, {
|
||||
product: { id: { $in: foodIds }, shop: { id: restaurantId } },
|
||||
});
|
||||
|
||||
const inventoryMap = new Map<string, Inventory>();
|
||||
for (const inventory of existingInventories) {
|
||||
inventoryMap.set(inventory.product.id, inventory);
|
||||
}
|
||||
|
||||
// Get shop once
|
||||
const shop = await this.em.findOne(Shop, { id: restaurantId });
|
||||
if (!shop) {
|
||||
throw new NotFoundException(`Shop with ID ${restaurantId} not found`);
|
||||
}
|
||||
|
||||
// Process all items
|
||||
const results: Inventory[] = [];
|
||||
for (const item of items) {
|
||||
const product = foodMap.get(item.foodId)!;
|
||||
let inventory = inventoryMap.get(item.foodId);
|
||||
|
||||
if (!inventory) {
|
||||
// Create new inventory record
|
||||
inventory = this.em.create(Inventory, {
|
||||
product,
|
||||
totalStock: item.totalStock,
|
||||
availableStock: item.availableStock,
|
||||
});
|
||||
} else {
|
||||
// Update existing inventory record
|
||||
inventory.totalStock = item.totalStock;
|
||||
inventory.availableStock = item.availableStock;
|
||||
}
|
||||
|
||||
results.push(inventory);
|
||||
}
|
||||
|
||||
// Flush all changes at once
|
||||
await this.em.flush();
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
async deductFromInventory(em: EntityManager, bulkReserveFoodDto: BulkReserveFoodDto): Promise<Inventory[]> {
|
||||
return em.transactional(async em => {
|
||||
const { items } = bulkReserveFoodDto;
|
||||
// Get all unique product IDs
|
||||
const foodIds = [...new Set(items.map(item => item.foodId))];
|
||||
|
||||
// Load all products in one query
|
||||
const products = await em.find(Product, { id: { $in: foodIds } });
|
||||
|
||||
// Verify all products exist and belong to the shop
|
||||
const foodMap = new Map<string, Product>();
|
||||
for (const product of products) {
|
||||
foodMap.set(product.id, product);
|
||||
}
|
||||
|
||||
// Check for missing products
|
||||
const missingFoodIds = foodIds.filter(id => !foodMap.has(id));
|
||||
if (missingFoodIds.length > 0) {
|
||||
throw new NotFoundException(`Products not found: ${missingFoodIds.join(', ')}`);
|
||||
}
|
||||
|
||||
// Load all existing inventories in one query
|
||||
const existingInventories = await em.find(Inventory, {
|
||||
product: { id: { $in: foodIds } },
|
||||
});
|
||||
|
||||
const inventoryMap = new Map<string, Inventory>();
|
||||
for (const inventory of existingInventories) {
|
||||
inventoryMap.set(inventory.product.id, inventory);
|
||||
}
|
||||
|
||||
// Validate stock availability and create reservations
|
||||
const inventories: Inventory[] = [];
|
||||
for (const item of items) {
|
||||
const inventory = inventoryMap.get(item.foodId);
|
||||
|
||||
// Check if inventory exists
|
||||
if (!inventory) {
|
||||
throw new NotFoundException(`Inventory not found for product ${item.foodId}`);
|
||||
}
|
||||
|
||||
// Check if available stock is sufficient
|
||||
if (inventory.availableStock < item.quantity) {
|
||||
throw new BadRequestException(
|
||||
`Insufficient stock for product ${item.foodId}. Available: ${inventory.availableStock}, Requested: ${item.quantity}`,
|
||||
);
|
||||
}
|
||||
inventory.availableStock -= item.quantity;
|
||||
inventories.push(inventory);
|
||||
em.persist(inventory);
|
||||
}
|
||||
return inventories;
|
||||
});
|
||||
}
|
||||
|
||||
async restoreToInventory(em: EntityManager, bulkRestoreDto: BulkReserveFoodDto): Promise<Inventory[]> {
|
||||
return em.transactional(async em => {
|
||||
const { items } = bulkRestoreDto;
|
||||
|
||||
const foodIds = [...new Set(items.map(item => item.foodId))];
|
||||
|
||||
const products = await em.find(Product, { id: { $in: foodIds } });
|
||||
const foodMap = new Map<string, Product>();
|
||||
for (const product of products) {
|
||||
foodMap.set(product.id, product);
|
||||
}
|
||||
|
||||
const missingFoodIds = foodIds.filter(id => !foodMap.has(id));
|
||||
if (missingFoodIds.length > 0) {
|
||||
throw new NotFoundException(`Products not found: ${missingFoodIds.join(', ')}`);
|
||||
}
|
||||
|
||||
const existingInventories = await em.find(Inventory, {
|
||||
product: { id: { $in: foodIds } },
|
||||
});
|
||||
|
||||
const inventoryMap = new Map<string, Inventory>();
|
||||
for (const inventory of existingInventories) {
|
||||
inventoryMap.set(inventory.product.id, inventory);
|
||||
}
|
||||
|
||||
const inventories: Inventory[] = [];
|
||||
for (const item of items) {
|
||||
const inventory = inventoryMap.get(item.foodId);
|
||||
if (!inventory) {
|
||||
throw new NotFoundException(`Inventory not found for product ${item.foodId}`);
|
||||
}
|
||||
inventory.availableStock += item.quantity;
|
||||
inventories.push(inventory);
|
||||
em.persist(inventory);
|
||||
}
|
||||
|
||||
return inventories;
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Entity, Property, ManyToOne, Unique } from '@mikro-orm/core';
|
||||
import { BaseEntity } from '../../../../common/entities/base.entity';
|
||||
import { Shop } from ../../..shops/entities/shop.entity';
|
||||
import { Shop } from ../../../shops/entities/shop.entity';
|
||||
import { NotifTitleEnum } from '../interfaces/notification.interface';
|
||||
import { NotifChannelEnum } from '../interfaces/notification.interface';
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Entity, Property, ManyToOne, Enum } from '@mikro-orm/core';
|
||||
import { BaseEntity } from '../../../../common/entities/base.entity';
|
||||
import { Shop } from ../../..shops/entities/shop.entity';
|
||||
import { Shop } from ../../../shops/entities/shop.entity';
|
||||
import { User } from '../../../users/entities/user.entity';
|
||||
import { NotifTitleEnum } from '../interfaces/notification.interface';
|
||||
import { Admin } from 'src/modules/admin/entities/admin.entity';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Entity, Property, ManyToOne, PrimaryKey } from '@mikro-orm/core';
|
||||
import { Shop } from ../../..shops/entities/shop.entity';
|
||||
import { Shop } from ../../../shops/entities/shop.entity';
|
||||
|
||||
@Entity({ tableName: 'sms_logs' })
|
||||
export class SmsLog {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
import { OnEvent } from '@nestjs/event-emitter';
|
||||
import { SmsSentEvent } from '../events/sms.events';
|
||||
import { RestRepository } from ../../..shops/repositories/rest.repository';
|
||||
import { RestRepository } from ../../../shops/repositories/rest.repository';
|
||||
import { EntityManager } from '@mikro-orm/postgresql';
|
||||
import { SmsLog } from '../entities/smsLogs.entity';
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ import { SmsProcessor } from './processors/sms.processor';
|
||||
import { PushProcessor } from './processors/push.processor';
|
||||
import { NotificationsController } from './controllers/notifications.controller';
|
||||
import { User } from '../users/entities/user.entity';
|
||||
import { Shop } from ../../..shops/entities/shop.entity';
|
||||
import { Shop } from ../../../shops/entities/shop.entity';
|
||||
import { AuthModule } from '../auth/auth.module';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { NotificationQueueNameEnum } from './constants/queue';
|
||||
@@ -26,7 +26,7 @@ import { NotificationCrone } from './crone/notification.crone';
|
||||
import { SmsService } from './services/sms.service';
|
||||
import { SmsLog } from './entities/smsLogs.entity';
|
||||
import { SmsLogRepository } from './repositories/sms-log.repository';
|
||||
import { RestaurantsModule } from ../../..shops.module';
|
||||
import { RestaurantsModule } from ../../../shops.module';
|
||||
import { SmsListeners } from './listeners/sms.listeners';
|
||||
|
||||
@Module({
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Injectable, NotFoundException } from '@nestjs/common';
|
||||
import { EntityManager } from '@mikro-orm/postgresql';
|
||||
import { NotificationPreference } from '../entities/notification-preference.entity';
|
||||
import { Shop } from ../../..shops/entities/shop.entity';
|
||||
import { Shop } from ../../../shops/entities/shop.entity';
|
||||
import { CreatePreferenceDto } from '../dto/create-preference.dto';
|
||||
import { UpdatePreferenceDto } from '../dto/update-preference.dto';
|
||||
import { NotifTitleEnum } from '../interfaces/notification.interface';
|
||||
|
||||
@@ -4,7 +4,6 @@ import { EntityManager } from '@mikro-orm/postgresql';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { Payment } from '../../../payments/entities/payment.entity';
|
||||
import { PaymentMethodEnum, PaymentStatusEnum } from '../../../payments/interface/payment';
|
||||
import { InventoryService } from '../../../inventory/inventory.service';
|
||||
import { OrderStatus } from '../interface/order.interface';
|
||||
import { Order } from '../entities/order.entity';
|
||||
import { OrderStatusChangedEvent } from '../events/order.events';
|
||||
@@ -15,7 +14,6 @@ export class OrdersCrone {
|
||||
|
||||
constructor(
|
||||
private readonly em: EntityManager,
|
||||
private readonly inventoryService: InventoryService,
|
||||
private readonly eventEmitter: EventEmitter2,
|
||||
) { }
|
||||
|
||||
@@ -63,23 +61,13 @@ export class OrdersCrone {
|
||||
|
||||
if (payment.order) {
|
||||
payment.order.status = OrderStatus.CANCELED;
|
||||
|
||||
// prepare restore payload
|
||||
const items = (payment.order as any).items || [];
|
||||
const restorePayload = {
|
||||
items: items.map((it: any) => ({ foodId: it.product.id, quantity: it.quantity })),
|
||||
};
|
||||
|
||||
if (restorePayload.items.length > 0) {
|
||||
await this.inventoryService.restoreToInventory(em, restorePayload);
|
||||
}
|
||||
}
|
||||
|
||||
em.persist(payment);
|
||||
if (payment.order) em.persist(payment.order);
|
||||
await em.flush();
|
||||
this.logger.log(
|
||||
`Marked payment ${payment.id} and order ${payment.order?.id} as failed and restored inventory`,
|
||||
`Marked payment ${payment.id} and order ${payment.order?.id} as failed`,
|
||||
);
|
||||
});
|
||||
} catch (err) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Entity, Index, ManyToOne, Property } from '@mikro-orm/core';
|
||||
import { BaseEntity } from '../../../../common/entities/base.entity';
|
||||
import { Order } from './order.entity';
|
||||
import { Product } from ../../..products/entities/product.entity';
|
||||
import { Product } from ../../../products/entities/product.entity';
|
||||
|
||||
@Entity({ tableName: 'order_items' })
|
||||
@Index({ properties: ['order'] })
|
||||
|
||||
@@ -14,7 +14,7 @@ import {
|
||||
import { BaseEntity } from '../../../../common/entities/base.entity';
|
||||
import { OrderCouponDetail, OrderStatus } from '../interface/order.interface';
|
||||
import { User } from '../../../users/entities/user.entity';
|
||||
import { Shop } from ../../..shops/entities/shop.entity';
|
||||
import { Shop } from ../../../shops/entities/shop.entity';
|
||||
import { PaymentMethod } from '../../../payments/entities/payment-method.entity';
|
||||
import { OrderItem } from './order-item.entity';
|
||||
import { Delivery } from '../../../delivery/entities/delivery.entity';
|
||||
|
||||
@@ -5,8 +5,8 @@ import { OrdersController } from './controllers/orders.controller';
|
||||
import { Order } from './entities/order.entity';
|
||||
import { OrderItem } from './entities/order-item.entity';
|
||||
import { User } from '../users/entities/user.entity';
|
||||
import { Shop } from ../../..shops/entities/shop.entity';
|
||||
import { Product } from ../../..products/entities/product.entity';
|
||||
import { Shop } from ../../../shops/entities/shop.entity';
|
||||
import { Product } from ../../../products/entities/product.entity';
|
||||
import { UserAddress } from '../users/entities/user-address.entity';
|
||||
import { PaymentMethod } from '../payments/entities/payment-method.entity';
|
||||
import { CartModule } from '../cart/cart.module';
|
||||
@@ -19,7 +19,6 @@ import { OrderListeners } from './listeners/order.listeners';
|
||||
import { OrdersCrone } from './crone/order.crone';
|
||||
import { AdminModule } from '../admin/admin.module';
|
||||
import { NotificationsModule } from '../notifications/notifications.module';
|
||||
import { InventoryModule } from '../inventory/inventory.module';
|
||||
import { UserModule } from '../users/user.module';
|
||||
|
||||
@Module({
|
||||
@@ -32,7 +31,6 @@ import { UserModule } from '../users/user.module';
|
||||
JwtModule,
|
||||
AdminModule,
|
||||
NotificationsModule,
|
||||
InventoryModule,
|
||||
forwardRef(() => UserModule)
|
||||
],
|
||||
controllers: [OrdersController],
|
||||
|
||||
@@ -3,8 +3,8 @@ import { EntityManager } from '@mikro-orm/postgresql';
|
||||
import { Order } from '../entities/order.entity';
|
||||
import { OrderItem } from '../entities/order-item.entity';
|
||||
import { User } from '../../../users/entities/user.entity';
|
||||
import { Shop } from ../../..shops/entities/shop.entity';
|
||||
import { Product } from ../../..products/entities/product.entity';
|
||||
import { Shop } from '../../../shops/entities/shop.entity';
|
||||
import { Product } from '../../../products/entities/product.entity';
|
||||
import { CartService } from '../../../cart/providers/cart.service';
|
||||
import { OrderStatus, OrderUserAddress, OrderCarAddress } from '../interface/order.interface';
|
||||
import { PaymentMethodEnum, PaymentStatusEnum } from '../../../payments/interface/payment';
|
||||
@@ -17,8 +17,6 @@ import { OrderRepository } from '../repositories/order.repository';
|
||||
import { FindOrdersDto } from '../dto/find-orders.dto';
|
||||
import { PaginatedResult } from 'src/common/interfaces/pagination.interface';
|
||||
import { Payment } from 'src/modules/payments/entities/payment.entity';
|
||||
import { InventoryService } from 'src/modules/inventory/inventory.service';
|
||||
import { BulkReserveFoodDto } from 'src/modules/inventory/dto/bulk-reserve-product.dto';
|
||||
import { StatusTransitionRef } from '../interface/order.interface';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { OrderCreatedEvent, OrderStatusChangedEvent } from '../events/order.events';
|
||||
@@ -55,7 +53,6 @@ export class OrdersService {
|
||||
private readonly cartService: CartService,
|
||||
private readonly orderRepository: OrderRepository,
|
||||
private readonly paymentsService: PaymentsService,
|
||||
private readonly inventoryService: InventoryService,
|
||||
private readonly eventEmitter: EventEmitter2,
|
||||
) { }
|
||||
|
||||
@@ -116,14 +113,6 @@ export class OrdersService {
|
||||
});
|
||||
|
||||
em.persist(payment);
|
||||
// reserve stock based on payment method.
|
||||
const bulkReserveFoodDto: BulkReserveFoodDto = {
|
||||
items: validated.orderItemsData.map(item => ({
|
||||
foodId: item.product.id,
|
||||
quantity: item.quantity,
|
||||
})),
|
||||
};
|
||||
await this.inventoryService.deductFromInventory(em, bulkReserveFoodDto);
|
||||
await em.flush();
|
||||
this.logger.debug(`Order ${order.id} created for user ${userId} (shop ${restaurantId})`);
|
||||
return order;
|
||||
@@ -426,15 +415,13 @@ export class OrdersService {
|
||||
const orderItemsData: OrderItemData[] = [];
|
||||
|
||||
for (const cartItem of cart.items) {
|
||||
const product = await this.em.findOne(Product, { id: cartItem.foodId }, { populate: ['shop', 'inventory'] });
|
||||
const product = await this.em.findOne(Product, { id: cartItem.foodId }, { populate: ['shop'] });
|
||||
if (!product) throw new NotFoundException(OrderMessage.FOOD_NOT_FOUND);
|
||||
|
||||
if (product.shop.id !== restaurantId) {
|
||||
throw new BadRequestException(OrderMessage.FOOD_NOT_BELONGS_TO_RESTAURANT);
|
||||
}
|
||||
|
||||
this.assertFoodHasSufficientStock(product, cartItem.quantity);
|
||||
|
||||
orderItemsData.push({
|
||||
product,
|
||||
quantity: cartItem.quantity,
|
||||
@@ -446,12 +433,6 @@ export class OrdersService {
|
||||
return orderItemsData;
|
||||
}
|
||||
|
||||
private assertFoodHasSufficientStock(product: Product, quantity: number) {
|
||||
const availableStock = product.inventory?.availableStock ?? 0;
|
||||
if (availableStock < quantity) {
|
||||
throw new BadRequestException(OrderMessage.FOOD_NOT_FOUND);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async getStats(restId: string) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Entity, ManyToOne, Property, Enum } from '@mikro-orm/core';
|
||||
import { BaseEntity } from '../../../../common/entities/base.entity';
|
||||
import { User } from '../../../users/entities/user.entity';
|
||||
import { Shop } from ../../..shops/entities/shop.entity';
|
||||
import { Shop } from ../../../shops/entities/shop.entity';
|
||||
import { PagerStatus } from '../interface/pager';
|
||||
import { Admin } from 'src/modules/admin/entities/admin.entity';
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import { BadRequestException, Injectable, NotFoundException, Inject, forwardRef
|
||||
import { CreatePagerDto } from '../dto/create-pager.dto';
|
||||
import { User } from '../../../users/entities/user.entity';
|
||||
import { EntityManager } from '@mikro-orm/postgresql';
|
||||
import { Shop } from ../../..shops/entities/shop.entity';
|
||||
import { Shop } from ../../../shops/entities/shop.entity';
|
||||
import { Pager } from '../entities/pager.entity';
|
||||
import { PagerStatus } from '../interface/pager';
|
||||
import { ulid } from 'ulid';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Entity, Enum, Index, ManyToOne, Property, Unique } from '@mikro-orm/core';
|
||||
import { BaseEntity } from '../../../../common/entities/base.entity';
|
||||
import { Shop } from ../../..shops/entities/shop.entity';
|
||||
import { Shop } from ../../../shops/entities/shop.entity';
|
||||
import { PaymentGatewayEnum, PaymentMethodEnum } from '../interface/payment';
|
||||
|
||||
@Entity({ tableName: 'payment_methods' })
|
||||
|
||||
@@ -27,7 +27,7 @@ export interface IPaymentVerifyData {
|
||||
cardPan?: string;
|
||||
raw: Record<string, any>;
|
||||
}
|
||||
////////////////////////// Zarinpal API v4 //////////////////////////
|
||||
../../../../../../////// Zarinpal API v../../../../../../////////
|
||||
export interface IZarinpalRequestPayment {
|
||||
amount: number;
|
||||
merchant_id: string;
|
||||
|
||||
@@ -4,7 +4,7 @@ import { MikroOrmModule } from '@mikro-orm/nestjs';
|
||||
import { PaymentMethod } from './entities/payment-method.entity';
|
||||
import { PaymentMethodRepository } from './repositories/payment-method.repository';
|
||||
import { PaymentMethodService } from './services/payment-method.service';
|
||||
import { Shop } from ../../..shops/entities/shop.entity';
|
||||
import { Shop } from '../../../shops/entities/shop.entity';
|
||||
import { PaymentsController } from './controllers/payments.controller';
|
||||
import { AuthModule } from '../auth/auth.module';
|
||||
import { JwtModule } from '@nestjs/jwt';
|
||||
@@ -12,7 +12,6 @@ import { Payment } from './entities/payment.entity';
|
||||
import { ZarinpalGateway } from './gateways/zarinpal.gateway';
|
||||
import { GatewayManager } from './gateways/gateway.manager';
|
||||
import { PaymentRepository } from './repositories/payment.repository';
|
||||
import { InventoryModule } from '../inventory/inventory.module';
|
||||
import { PaymentListeners } from './listeners/payment.listeners';
|
||||
import { AdminModule } from '../admin/admin.module';
|
||||
import { NotificationsModule } from '../notifications/notifications.module';
|
||||
@@ -20,7 +19,7 @@ import { OrdersModule } from '../orders/orders.module';
|
||||
|
||||
@Module({
|
||||
imports: [MikroOrmModule.forFeature([PaymentMethod, Payment, Shop]),
|
||||
AuthModule, JwtModule, InventoryModule, AdminModule, NotificationsModule,
|
||||
AuthModule, JwtModule, AdminModule, NotificationsModule,
|
||||
forwardRef(() => OrdersModule)],
|
||||
controllers: [PaymentsController],
|
||||
providers: [PaymentsService, PaymentMethodService, PaymentMethodRepository,
|
||||
|
||||
@@ -5,7 +5,7 @@ import { PaymentMethodRepository } from '../repositories/payment-method.reposito
|
||||
import { CreatePaymentMethodDto } from '../dto/create-payment-method.dto';
|
||||
import { UpdatePaymentMethodDto } from '../dto/update-payment-method.dto';
|
||||
import { RequiredEntityData } from '@mikro-orm/core';
|
||||
import { Shop } from ../../..shops/entities/shop.entity';
|
||||
import { Shop } from ../../../shops/entities/shop.entity';
|
||||
import { RestMessage, PaymentMessage } from 'src/common/enums/message.enum';
|
||||
|
||||
@Injectable()
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Controller, Get, Post, Body, Patch, Param, Delete, Query, UseGuards } f
|
||||
import { FoodService } from '../providers/product.service';
|
||||
import { CreateFoodDto } from '../dto/create-product.dto';
|
||||
import { UpdateFoodDto } from '../dto/update-product.dto';
|
||||
import { FindFoodsDto } from ../../..products.dto';
|
||||
import { FindFoodsDto } from ../../../products.dto';
|
||||
import {
|
||||
ApiTags,
|
||||
ApiOperation,
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
import { Cron } from '@nestjs/schedule';
|
||||
import { EntityManager } from '@mikro-orm/postgresql';
|
||||
import { Inventory } from '../../../inventory/entities/inventory.entity';
|
||||
|
||||
@Injectable()
|
||||
export class FoodStockCrone {
|
||||
@@ -9,37 +8,37 @@ export class FoodStockCrone {
|
||||
|
||||
constructor(private readonly em: EntityManager) {}
|
||||
|
||||
// run every day at 00:03
|
||||
@Cron('3 0 * * *', {
|
||||
name: 'resetAvailableStock',
|
||||
timeZone: 'UTC',
|
||||
})
|
||||
async handleCron() {
|
||||
try {
|
||||
this.logger.debug('Starting daily inventory reset (availableStock = totalStock)');
|
||||
// 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;
|
||||
}
|
||||
// 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`);
|
||||
// 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();
|
||||
});
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
// this.logger.log('Daily inventory reset completed');
|
||||
// } catch (err) {
|
||||
// this.logger.error(`FoodStockCrone failed: ${err?.message}`, err);
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Entity, Index, Property, Collection, OneToMany, ManyToOne } from '@mikro-orm/core';
|
||||
import { Product } from './product.entity';
|
||||
import { BaseEntity } from '../../../../common/entities/base.entity';
|
||||
import { Shop } from ../../..shops/entities/shop.entity';
|
||||
import { Shop } from ../../../shops/entities/shop.entity';
|
||||
|
||||
@Entity({ tableName: 'categories' })
|
||||
@Index({ properties: ['shop', 'isActive'] })
|
||||
|
||||
@@ -3,7 +3,6 @@ import { Category } from './category.entity';
|
||||
import { BaseEntity } from '../../../../common/entities/base.entity';
|
||||
import { Shop } from '../../../../modules/shops/entities/shop.entity';
|
||||
import { Review } from 'src/modules/review/entities/review.entity';
|
||||
import { Inventory } from 'src/modules/inventory/entities/inventory.entity';
|
||||
import { Favorite } from './favorite.entity';
|
||||
|
||||
@Entity({ tableName: 'products' })
|
||||
@@ -20,11 +19,6 @@ export class Product extends BaseEntity {
|
||||
@OneToMany(() => Review, review => review.product, { cascade: [Cascade.ALL], orphanRemoval: true })
|
||||
reviews = new Collection<Review>(this);
|
||||
|
||||
@OneToOne(() => Inventory, {
|
||||
mappedBy: 'product',
|
||||
nullable: true,
|
||||
})
|
||||
inventory?: Inventory;
|
||||
|
||||
@OneToMany(() => Favorite, favorite => favorite.product)
|
||||
favorites = new Collection<Favorite>(this);
|
||||
|
||||
@@ -6,7 +6,7 @@ import { EntityManager } from '@mikro-orm/postgresql';
|
||||
import { RequiredEntityData } from '@mikro-orm/core';
|
||||
import { Category } from '../entities/category.entity';
|
||||
import { CategoryMessage, RestMessage } from 'src/common/enums/message.enum';
|
||||
import { Shop } from ../../..shops/entities/shop.entity';
|
||||
import { Shop } from ../../../shops/entities/shop.entity';
|
||||
|
||||
@Injectable()
|
||||
export class CategoryService {
|
||||
|
||||
@@ -10,7 +10,6 @@ import { CategoryMessage, FoodMessage, RestMessage } from 'src/common/enums/mess
|
||||
import { RestRepository } from ../../..shops/repositories/rest.repository';
|
||||
import { CacheService } from '../../../utils/cache.service';
|
||||
import { Favorite } from '../entities/favorite.entity';
|
||||
import { Inventory } from 'src/modules/inventory/entities/inventory.entity';
|
||||
|
||||
@Injectable()
|
||||
export class FoodService {
|
||||
@@ -22,7 +21,7 @@ export class FoodService {
|
||||
) { }
|
||||
|
||||
async create(restId: string, createFoodDto: CreateFoodDto) {
|
||||
const { categoryId, dailyStock = 0, ...rest } = createFoodDto;
|
||||
const { categoryId, ...rest } = createFoodDto;
|
||||
const shop = await this.restRepository.findOne({ id: restId });
|
||||
if (!shop) {
|
||||
throw new NotFoundException(RestMessage.NOT_FOUND);
|
||||
@@ -32,7 +31,7 @@ export class FoodService {
|
||||
throw new NotFoundException(CategoryMessage.NOT_FOUND);
|
||||
}
|
||||
|
||||
const { product, inventory } = await this.em.transactional(async em => {
|
||||
const product = await this.em.transactional(async em => {
|
||||
// prepare data with defaults for required fields so repository.create typing is satisfied
|
||||
const data: RequiredEntityData<Product> = {
|
||||
desc: rest.desc,
|
||||
@@ -51,23 +50,16 @@ export class FoodService {
|
||||
};
|
||||
|
||||
const product = em.create(Product, data);
|
||||
const newInventoryRecord = em.create(Inventory, {
|
||||
product: product,
|
||||
availableStock: dailyStock,
|
||||
totalStock: dailyStock,
|
||||
});
|
||||
|
||||
await em.flush();
|
||||
return { product, inventory: newInventoryRecord };
|
||||
return product;
|
||||
});
|
||||
|
||||
// Re-load created entities with the primary EM to ensure they're attached
|
||||
const savedFood = product?.id
|
||||
? await this.foodRepository.findOne({ id: product.id }, { populate: ['category', 'shop'] })
|
||||
: null;
|
||||
const savedInventory = inventory?.id ? await this.em.findOne(Inventory, { id: inventory.id }) : inventory;
|
||||
|
||||
return { product: savedFood ?? product, inventory: savedInventory ?? inventory };
|
||||
return savedFood ?? product;
|
||||
}
|
||||
|
||||
findAll(restId: string, dto: FindFoodsDto) {
|
||||
@@ -78,7 +70,7 @@ export class FoodService {
|
||||
* Public product detail (only active products are visible).
|
||||
*/
|
||||
async findPublicById(foodId: string, userId?: string): Promise<any> {
|
||||
const product = await this.foodRepository.findOne({ id: foodId, isActive: true }, { populate: ['category', 'inventory'] });
|
||||
const product = await this.foodRepository.findOne({ id: foodId, isActive: true }, { populate: ['category'] });
|
||||
if (!product) throw new NotFoundException(FoodMessage.NOT_FOUND);
|
||||
let isFavorite = false;
|
||||
if (userId) {
|
||||
@@ -94,7 +86,7 @@ export class FoodService {
|
||||
* Admin product detail (scoped to the authenticated shop).
|
||||
*/
|
||||
async findAdminById(restId: string, id: string): Promise<Product> {
|
||||
const product = await this.foodRepository.findOne({ id, shop: { id: restId } }, { populate: ['category', 'inventory'] });
|
||||
const product = await this.foodRepository.findOne({ id, shop: { id: restId } }, { populate: ['category'] });
|
||||
|
||||
if (!product) throw new NotFoundException(FoodMessage.NOT_FOUND);
|
||||
return product;
|
||||
@@ -123,7 +115,7 @@ export class FoodService {
|
||||
}
|
||||
|
||||
async update(restId: string, id: string, dto: Partial<CreateFoodDto>): Promise<Product> {
|
||||
const { categoryId, dailyStock, ...rest } = dto;
|
||||
const { categoryId, ...rest } = dto;
|
||||
const product = await this.foodRepository.findOne({ id, shop: { id: restId } }, { populate: ['shop'] });
|
||||
if (!product) {
|
||||
throw new NotFoundException(FoodMessage.NOT_FOUND);
|
||||
@@ -143,25 +135,7 @@ export class FoodService {
|
||||
// assign other fields from DTO (excluding dailyStock handled below)
|
||||
this.em.assign(product, rest);
|
||||
|
||||
// Persist product and update/create related inventory atomically
|
||||
await this.em.transactional(async em => {
|
||||
await em.persistAndFlush(product);
|
||||
|
||||
if (typeof dailyStock !== 'undefined') {
|
||||
const inventoryRecord = await em.findOne(Inventory, { product: product });
|
||||
if (inventoryRecord) {
|
||||
inventoryRecord.totalStock = dailyStock;
|
||||
} else {
|
||||
em.create(Inventory, {
|
||||
product: product,
|
||||
availableStock: dailyStock,
|
||||
totalStock: dailyStock,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
await em.flush();
|
||||
});
|
||||
await this.em.persistAndFlush(product);
|
||||
|
||||
// Re-load the product to ensure populated relations and stable instance
|
||||
const savedFood = await this.foodRepository.findOne({ id: product.id }, { populate: ['category', 'shop'] });
|
||||
|
||||
@@ -48,7 +48,7 @@ export class FoodRepository extends EntityRepository<Product> {
|
||||
limit,
|
||||
offset,
|
||||
orderBy: { [orderBy]: order.toLowerCase() as 'asc' | 'desc' },
|
||||
populate: ['category','inventory'],
|
||||
populate: ['category'],
|
||||
});
|
||||
|
||||
const totalPages = Math.ceil(total / limit);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
import { Cron } from '@nestjs/schedule';
|
||||
import { EntityManager } from '@mikro-orm/postgresql';
|
||||
import { FoodRepository } from ../../..products/repositories/product.repository';
|
||||
import { FoodRepository } from ../../../products/repositories/product.repository';
|
||||
import { ReviewRepository } from '../repositories/review.repository';
|
||||
import { ReviewStatus } from '../enums/review-status.enum';
|
||||
|
||||
@@ -27,7 +27,7 @@ export class FoodRatingCronService {
|
||||
this.logger.log('Starting daily product rating calculation cron job...');
|
||||
|
||||
try {
|
||||
// Get all products from ../../..shops
|
||||
// Get all products from ../../../shops
|
||||
const products = await this.foodRepository.find({});
|
||||
|
||||
this.logger.log(`Found ${products.length} products to process`);
|
||||
|
||||
@@ -3,7 +3,7 @@ import { CreateReviewDto } from '../dto/create-review.dto';
|
||||
import { UpdateReviewDto } from '../dto/update-review.dto';
|
||||
import { FindRestuarantReviewsDto, FindReviewsDto } from '../dto/find-reviews.dto';
|
||||
import { ReviewRepository } from '../repositories/review.repository';
|
||||
import { FoodRepository } from ../../..products/repositories/product.repository';
|
||||
import { FoodRepository } from ../../../products/repositories/product.repository';
|
||||
import { UserRepository } from '../../../users/repositories/user.repository';
|
||||
import { EntityManager } from '@mikro-orm/postgresql';
|
||||
import { RequiredEntityData } from '@mikro-orm/core';
|
||||
@@ -11,7 +11,7 @@ import { Review } from '../entities/review.entity';
|
||||
import { FoodMessage, UserMessage, ReviewMessage } from 'src/common/enums/message.enum';
|
||||
import { Order } from '../../../orders/entities/order.entity';
|
||||
import { OrderItem } from '../../../orders/entities/order-item.entity';
|
||||
import { Shop } from ../../..shops/entities/shop.entity';
|
||||
import { Shop } from ../../../shops/entities/shop.entity';
|
||||
import { ReviewStatus } from '../enums/review-status.enum';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { ReviewCreatedEvent } from '../events/review.events';
|
||||
|
||||
@@ -5,7 +5,7 @@ import { ReviewRepository } from './repositories/review.repository';
|
||||
import { FoodRatingCronService } from './providers/product-rating-cron.service';
|
||||
import { MikroOrmModule } from '@mikro-orm/nestjs';
|
||||
import { Review } from './entities/review.entity';
|
||||
import { FoodModule } from ../../..products/product.module';
|
||||
import { FoodModule } from ../../../products/product.module';
|
||||
import { UserModule } from '../users/user.module';
|
||||
import { AuthModule } from '../auth/auth.module';
|
||||
import { JwtModule } from '@nestjs/jwt';
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Collection, Entity, Index, ManyToMany, OneToMany, ManyToOne, Property } from '@mikro-orm/core';
|
||||
import { BaseEntity } from '../../../../common/entities/base.entity';
|
||||
import { Permission } from './permission.entity';
|
||||
import { Shop } from ../../..shops/entities/shop.entity';
|
||||
import { Shop } from ../../../shops/entities/shop.entity';
|
||||
import { RolePermission } from './rolePermission.entity';
|
||||
import { AdminRole } from 'src/modules/admin/entities/adminRole.entity';
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import { InjectRepository } from '@mikro-orm/nestjs';
|
||||
import { EntityRepository, FilterQuery } from '@mikro-orm/core';
|
||||
import { Role } from '../entities/role.entity';
|
||||
import { Permission } from '../entities/permission.entity';
|
||||
import { Shop } from ../../..shops/entities/shop.entity';
|
||||
import { Shop } from ../../../shops/entities/shop.entity';
|
||||
import { EntityManager } from '@mikro-orm/postgresql';
|
||||
import { CreateRoleDto } from '../dto/create-role.dto';
|
||||
import { UpdateRoleDto } from '../dto/update-role.dto';
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
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 { UpdateRestaurantDto } from '../dto/update-shop.dto';
|
||||
import { UpgradeSubscriptionDto } from '../dto/upgrade-subscription.dto';
|
||||
import { FindRestaurantsDto } from ../../..shops.dto';
|
||||
import { FindRestaurantsDto } from ../../../shops.dto';
|
||||
import { AdminAuthGuard } from 'src/modules/auth/guards/adminAuth.guard';
|
||||
import {
|
||||
ApiBearerAuth,
|
||||
|
||||
@@ -240,7 +240,7 @@ export class RestaurantsService {
|
||||
// Delete coupons
|
||||
await em.nativeDelete(Coupon, { shop: id });
|
||||
|
||||
// Delete products (will cascade to reviews, favorites, and inventory due to cascade settings)
|
||||
// Delete products (will cascade to reviews and favorites due to cascade settings)
|
||||
await em.nativeDelete(Product, { shop: id });
|
||||
|
||||
// Delete categories (products should be deleted by cascade, but delete explicitly to be safe)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Entity, Property, ManyToOne, Index, Enum } from '@mikro-orm/core';
|
||||
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 { PointTransactionReason } 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 { User } from './user.entity';
|
||||
import { WalletTransactionReason, WalletTransactionType } from '../interface/wallet';
|
||||
import { Shop } from ../../..shops/entities/shop.entity';
|
||||
import { Shop } from ../../../shops/entities/shop.entity';
|
||||
|
||||
@Entity({ tableName: 'wallet_transactions' })
|
||||
@Index({ properties: ['user', 'shop'] })
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Injectable, NotFoundException, BadRequestException } from '@nestjs/comm
|
||||
import { FilterQuery, RequiredEntityData } from '@mikro-orm/core';
|
||||
import { User } from '../entities/user.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 { UpdateUserDto } from '../dto/update-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 { UserRepository } from '../repositories/user.repository';
|
||||
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 { WalletService } from './wallet.service';
|
||||
import { WalletTransactionReason, WalletTransactionType } from '../interface/wallet';
|
||||
|
||||
@@ -6,7 +6,7 @@ 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 { RestaurantsModule } from ../../..shops.module';
|
||||
import { RestaurantsModule } from ../../../shops.module';
|
||||
import { WalletTransactionRepository } from './repositories/wallet-transaction.repository';
|
||||
import { WalletService } from './providers/wallet.service';
|
||||
import { WalletTransaction } from './entities/wallet-transaction.entity';
|
||||
|
||||
@@ -14,12 +14,11 @@ import { UsersSeeder } from './users.seeder';
|
||||
import { CouponsSeeder } from './coupons.seeder';
|
||||
import { NotificationPreferencesSeeder } from './notification-preferences.seeder';
|
||||
import { UserWalletsSeeder } from './user-wallets.seeder';
|
||||
import { InventorySeeder } from './inventory.seeder';
|
||||
// import { NotificationsSeeder } from './notifications.seeder';
|
||||
|
||||
export class DatabaseSeeder extends Seeder {
|
||||
async run(em: EntityManager) {
|
||||
const TOTAL_STEPS = 15;
|
||||
const TOTAL_STEPS = 14;
|
||||
console.info('[Seeder] Starting database seed');
|
||||
// 1. Create Permissions
|
||||
console.info(`[Seeder] Step 1/${TOTAL_STEPS}: Creating permissions`);
|
||||
@@ -76,38 +75,33 @@ export class DatabaseSeeder extends Seeder {
|
||||
await productsSeeder.run(em, shopsMap, categoriesMap);
|
||||
console.info(`[Seeder] Step 9/${TOTAL_STEPS}: Done`);
|
||||
|
||||
// 10. Create Inventory for all Products
|
||||
console.info(`[Seeder] Step 10/${TOTAL_STEPS}: Creating inventory`);
|
||||
const inventorySeeder = new InventorySeeder();
|
||||
await inventorySeeder.run(em);
|
||||
console.info(`[Seeder] Step 10/${TOTAL_STEPS}: Done`);
|
||||
|
||||
// 11. Create Coupons
|
||||
console.info(`[Seeder] Step 11/${TOTAL_STEPS}: Creating coupons`);
|
||||
// 10. Create Coupons
|
||||
console.info(`[Seeder] Step 10/${TOTAL_STEPS}: Creating coupons`);
|
||||
const couponsSeeder = new CouponsSeeder();
|
||||
await couponsSeeder.run(em, shopsMap);
|
||||
console.info(`[Seeder] Step 11/${TOTAL_STEPS}: Done`);
|
||||
console.info(`[Seeder] Step 10/${TOTAL_STEPS}: Done`);
|
||||
|
||||
// 12. Create Admins
|
||||
console.info(`[Seeder] Step 12/${TOTAL_STEPS}: Creating admins`);
|
||||
// 11. Create Admins
|
||||
console.info(`[Seeder] Step 11/${TOTAL_STEPS}: Creating admins`);
|
||||
const adminsSeeder = new AdminsSeeder();
|
||||
await adminsSeeder.run(em, rolesMap, shopsMap);
|
||||
console.info(`[Seeder] Step 12/${TOTAL_STEPS}: Done`);
|
||||
console.info(`[Seeder] Step 11/${TOTAL_STEPS}: Done`);
|
||||
|
||||
// 13. Create Users
|
||||
console.info(`[Seeder] Step 13/${TOTAL_STEPS}: Creating users`);
|
||||
// 12. Create Users
|
||||
console.info(`[Seeder] Step 12/${TOTAL_STEPS}: Creating users`);
|
||||
const usersSeeder = new UsersSeeder();
|
||||
await usersSeeder.run(em);
|
||||
console.info(`[Seeder] Step 13/${TOTAL_STEPS}: Done`);
|
||||
console.info(`[Seeder] Step 12/${TOTAL_STEPS}: Done`);
|
||||
|
||||
// 14. Create User Wallets
|
||||
console.info(`[Seeder] Step 14/${TOTAL_STEPS}: Creating user wallets`);
|
||||
// 13. Create User Wallets
|
||||
console.info(`[Seeder] Step 13/${TOTAL_STEPS}: Creating user wallets`);
|
||||
const userWalletsSeeder = new UserWalletsSeeder();
|
||||
await userWalletsSeeder.run(em);
|
||||
console.info(`[Seeder] Step 14/${TOTAL_STEPS}: Done`);
|
||||
console.info(`[Seeder] Step 13/${TOTAL_STEPS}: Done`);
|
||||
|
||||
// 15. Create Notifications for admins and users for all shops
|
||||
console.info(`[Seeder] Step 15/${TOTAL_STEPS}: (optional) creating notifications`);
|
||||
// 14. Create Notifications for admins and users for all shops
|
||||
console.info(`[Seeder] Step 14/${TOTAL_STEPS}: (optional) creating notifications`);
|
||||
// const notificationsSeeder = new NotificationsSeeder();
|
||||
// await notificationsSeeder.run(em);
|
||||
console.info(`[Seeder] Step 15/${TOTAL_STEPS}: Done`);
|
||||
|
||||
@@ -2,7 +2,7 @@ import type { EntityManager } from '@mikro-orm/core';
|
||||
import { Admin } from '../modules/admin/entities/admin.entity';
|
||||
import { AdminRole } from '../modules/admin/entities/adminRole.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 { normalizePhone } from '../modules/utils/phone.util';
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { EntityManager } from '@mikro-orm/core';
|
||||
import { Category } from ../../..products/entities/category.entity';
|
||||
import type { Shop } from ../../..shops/entities/shop.entity';
|
||||
import { Category } from ../../../products/entities/category.entity';
|
||||
import type { Shop } from ../../../shops/entities/shop.entity';
|
||||
import { categoriesData } from './data/categories.data';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { EntityManager } from '@mikro-orm/core';
|
||||
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';
|
||||
|
||||
export class CouponsSeeder {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { EntityManager } from '@mikro-orm/core';
|
||||
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 { DeliveryFeeTypeEnum } from 'src/modules/delivery/interface/delivery';
|
||||
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
import type { EntityManager } from '@mikro-orm/core';
|
||||
import { Product } from ../../..products/entities/product.entity';
|
||||
import { Inventory } from '../modules/inventory/entities/inventory.entity';
|
||||
|
||||
export class InventorySeeder {
|
||||
async run(em: EntityManager): Promise<void> {
|
||||
const products = await em.find(Product, {});
|
||||
|
||||
for (const product of products) {
|
||||
// Check if inventory already exists for this product
|
||||
const existingInventory = await em.findOne(Inventory, {
|
||||
product: { id: product.id },
|
||||
});
|
||||
|
||||
if (!existingInventory) {
|
||||
const inventory = em.create(Inventory, {
|
||||
product,
|
||||
totalStock: 50,
|
||||
availableStock: 50,
|
||||
});
|
||||
|
||||
em.persist(inventory);
|
||||
}
|
||||
}
|
||||
|
||||
await em.flush();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { EntityManager } from '@mikro-orm/core';
|
||||
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';
|
||||
|
||||
export class NotificationPreferencesSeeder {
|
||||
|
||||
@@ -2,7 +2,7 @@ import type { EntityManager } from '@mikro-orm/core';
|
||||
import { Notification } from '../modules/notifications/entities/notification.entity';
|
||||
import { Admin } from '../modules/admin/entities/admin.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';
|
||||
|
||||
export class NotificationsSeeder {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { EntityManager } from '@mikro-orm/core';
|
||||
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';
|
||||
|
||||
export class PaymentMethodsSeeder {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { EntityManager } from '@mikro-orm/core';
|
||||
import { Schedule } from ../../..shops/entities/schedule.entity';
|
||||
import type { Shop } from ../../..shops/entities/shop.entity';
|
||||
import { Schedule } from ../../../shops/entities/schedule.entity';
|
||||
import type { Shop } from ../../../shops/entities/shop.entity';
|
||||
import { timeSlots } from './data/schedules.data';
|
||||
|
||||
export class SchedulesSeeder {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { EntityManager } from '@mikro-orm/core';
|
||||
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 { WalletTransactionReason, WalletTransactionType } from 'src/modules/users/interface/wallet';
|
||||
|
||||
|
||||
Reference in New Issue
Block a user