order confirm after pay

This commit is contained in:
2025-12-17 20:07:54 +03:30
parent bfb7441a0c
commit 7f72d7d70f
16 changed files with 102 additions and 42 deletions
@@ -0,0 +1,7 @@
import { PaymentMethodEnum } from "src/modules/payments/interface/payment";
export const STOCK_RESERVE_MINUTES: Record<PaymentMethodEnum, number> = {
[PaymentMethodEnum.Online]: 15,
[PaymentMethodEnum.Cash]: 120,
[PaymentMethodEnum.Wallet]: 15,
};
@@ -15,11 +15,6 @@ export class BulkReserveFoodItemDto {
@Type(() => Number)
quantity!: number;
@ApiProperty({ example: '2024-12-31T23:59:59Z', description: 'Reservation expiration date' })
@IsNotEmpty()
@IsDate()
@Type(() => Date)
expiresAt!: Date;
}
export class BulkReserveFoodDto {
@@ -2,3 +2,5 @@ export enum ReservationStatus {
ACTIVE = 'active',
CONFIRMED = 'confirmed',
}
@@ -10,5 +10,6 @@ import { JwtModule } from '@nestjs/jwt';
imports: [MikroOrmModule.forFeature([Inventory]), AuthModule, JwtModule],
controllers: [InventoryController],
providers: [InventoryService],
exports: [InventoryService],
})
export class InventoryModule {}
+31 -13
View File
@@ -9,6 +9,8 @@ import { Food } from '../foods/entities/food.entity';
import { Restaurant } from '../restaurants/entities/restaurant.entity';
import { Order } from '../orders/entities/order.entity';
import { ReservationStatus } from './inteface/reservation';
import { STOCK_RESERVE_MINUTES } from './const/reservation';
import { PaymentMethodEnum } from '../payments/interface/payment';
@Injectable()
export class InventoryService {
@@ -59,8 +61,8 @@ export class InventoryService {
}
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) {
@@ -134,17 +136,19 @@ export class InventoryService {
}
async tempBulkReserveFood(
em: EntityManager,
restaurantId: string,
orderId: string,
paymentMethod: PaymentMethodEnum,
bulkReserveFoodDto: BulkReserveFoodDto,
): Promise<Reservation[]> {
const { items } = bulkReserveFoodDto;
const expiresAt = this.getReservationExpiry(paymentMethod);
// Get all unique food IDs
const foodIds = [...new Set(items.map(item => item.foodId))];
// Load all foods in one query
const foods = await this.em.find(Food, { id: { $in: foodIds } }, { populate: ['restaurant'] });
const foods = await em.find(Food, { id: { $in: foodIds } }, { populate: ['restaurant'] });
// Verify all foods exist and belong to the restaurant
const foodMap = new Map<string, Food>();
@@ -162,13 +166,13 @@ export class InventoryService {
}
// Load order
const order = await this.em.findOne(Order, { id: orderId });
const order = await em.findOne(Order, { id: orderId });
if (!order) {
throw new NotFoundException(`Order with ID ${orderId} not found`);
}
// Load all existing inventories in one query
const existingInventories = await this.em.find(Inventory, {
const existingInventories = await em.find(Inventory, {
food: { id: { $in: foodIds }, restaurant: { id: restaurantId } },
});
@@ -196,11 +200,11 @@ export class InventoryService {
}
// Create reservation record
const reservation = this.em.create(Reservation, {
const reservation = em.create(Reservation, {
food,
order,
quantity: item.quantity,
expiresAt: item.expiresAt,
expiresAt,
status: ReservationStatus.ACTIVE,
});
@@ -209,22 +213,36 @@ export class InventoryService {
// Update available stock (decrease by quantity)
inventory.availableStock -= item.quantity;
}
// Flush all changes at once
await this.em.flush();
return reservations;
}
async confirmReservationByOrderId(orderId: string): Promise<Reservation[]> {
const reservations = await this.em.find(Reservation, { order: { id: orderId } });
async confirmReservationByOrderId(em: EntityManager, orderId: string): Promise<Reservation[]> {
const reservations = await em.find(Reservation, { order: { id: orderId } });
if (!reservations) {
throw new NotFoundException(`Reservations with order ID ${orderId} not found`);
}
for (const reservation of reservations) {
reservation.status = ReservationStatus.CONFIRMED;
}
await this.em.flush();
return reservations;
}
async releaseReservationByOrderId(em: EntityManager, orderId: string): Promise<Reservation[]> {
const reservations = await em.find(Reservation, { order: { id: orderId } });
if (!reservations) {
throw new NotFoundException(`Reservations with order ID ${orderId} not found`);
}
for (const reservation of reservations) {
em.remove(reservation);
}
return reservations;
}
getReservationExpiry(method: PaymentMethodEnum): Date {
const minutes = STOCK_RESERVE_MINUTES[method] ?? 15;
return new Date(Date.now() + minutes * 60 * 1000);
}
}