142 lines
5.5 KiB
C#
142 lines
5.5 KiB
C#
using AyCode.Core.Loggers;
|
|
using FruitBank.Common.Entities;
|
|
using FruitBank.Common.Enums;
|
|
using LinqToDB;
|
|
using Mango.Nop.Core.Loggers;
|
|
using Mango.Nop.Data.Repositories;
|
|
using Nop.Core.Caching;
|
|
using Nop.Core.Domain.Catalog;
|
|
using Nop.Core.Domain.Customers;
|
|
using Nop.Core.Domain.Orders;
|
|
using Nop.Core.Events;
|
|
using Nop.Data;
|
|
using Nop.Plugin.Misc.FruitBankPlugin.Domains.DataLayer.Interfaces;
|
|
using Nop.Plugin.Misc.FruitBankPlugin.Services;
|
|
|
|
namespace Nop.Plugin.Misc.FruitBankPlugin.Domains.DataLayer;
|
|
|
|
public class PreorderDbContext :
|
|
IPreorderDbSet<PreorderDbTable>,
|
|
IPreorderItemDbSet<PreorderItemDbTable>
|
|
{
|
|
private readonly ILogger _logger;
|
|
|
|
public PreorderDbTable Preorders { get; set; }
|
|
public PreorderItemDbTable PreorderItems { get; set; }
|
|
|
|
// Read-only access to related NopCommerce repositories needed during conversion
|
|
public IRepository<Customer> Customers { get; set; }
|
|
public IRepository<Product> Products { get; set; }
|
|
public IRepository<Order> Orders { get; set; }
|
|
public IRepository<OrderItem> OrderItems { get; set; }
|
|
|
|
public PreorderDbContext(
|
|
PreorderDbTable preorderDbTable,
|
|
PreorderItemDbTable preorderItemDbTable,
|
|
IRepository<Customer> customerRepository,
|
|
IRepository<Product> productRepository,
|
|
IRepository<Order> orderRepository,
|
|
IRepository<OrderItem> orderItemRepository,
|
|
IEnumerable<IAcLogWriterBase> logWriters)
|
|
{
|
|
Preorders = preorderDbTable;
|
|
PreorderItems = preorderItemDbTable;
|
|
Customers = customerRepository;
|
|
Products = productRepository;
|
|
Orders = orderRepository;
|
|
OrderItems = orderItemRepository;
|
|
_logger = new Logger<PreorderDbContext>(logWriters.ToArray());
|
|
}
|
|
|
|
/// <summary>
|
|
/// Insert a complete preorder with all its items in one operation.
|
|
/// Returns the saved preorder (with Id populated).
|
|
/// </summary>
|
|
public async Task<Preorder> InsertPreorderAsync(Preorder preorder, IList<PreorderItem> items)
|
|
{
|
|
preorder.CreatedOnUtc = DateTime.UtcNow;
|
|
preorder.UpdatedOnUtc = DateTime.UtcNow;
|
|
preorder.Status = PreorderStatus.Pending;
|
|
|
|
await Preorders.InsertAsync(preorder);
|
|
|
|
foreach (var item in items)
|
|
{
|
|
item.PreorderId = preorder.Id;
|
|
item.FulfilledQuantity = 0;
|
|
item.Status = PreorderItemStatus.Pending;
|
|
await PreorderItems.InsertAsync(item);
|
|
}
|
|
|
|
_logger.Info($"PreorderDbContext: inserted Preorder #{preorder.Id} with {items.Count} items for customer #{preorder.CustomerId}");
|
|
return preorder;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns all pending preorder items for a set of productIds, ordered by PreorderId (FCFS).
|
|
/// Used by PreorderConversionService after IncomingQuantity is written.
|
|
/// </summary>
|
|
public async Task<List<PreorderItem>> GetPendingItemsForProductsAsync(IList<int> productIds)
|
|
{
|
|
// Fetch all items for these products first, then filter by status in memory
|
|
// LinqToDB cannot translate enum comparisons to SQL in this codebase
|
|
var all = await PreorderItems.Table
|
|
.Where(i => productIds.Contains(i.ProductId))
|
|
.OrderBy(i => i.PreorderId)
|
|
.ToListAsync();
|
|
|
|
return all.Where(i =>
|
|
i.Status == PreorderItemStatus.Pending ||
|
|
i.Status == PreorderItemStatus.PartiallyFulfilled)
|
|
.ToList();
|
|
}
|
|
|
|
/// <summary>
|
|
/// After conversion: check if all items in a preorder are resolved and update the preorder's status.
|
|
/// </summary>
|
|
public async Task RefreshPreorderStatusAsync(int preorderId)
|
|
{
|
|
var preorder = await Preorders.GetByIdAsync(preorderId);
|
|
if (preorder == null) return;
|
|
|
|
var items = await PreorderItems.GetAllByPreorderIdAsync(preorderId).ToListAsync();
|
|
|
|
var hasDropped = items.Any(i => i.Status == PreorderItemStatus.Dropped);
|
|
var hasPartial = items.Any(i => i.Status == PreorderItemStatus.PartiallyFulfilled);
|
|
var hasPending = items.Any(i => i.Status == PreorderItemStatus.Pending);
|
|
var allFulfilled = items.All(i => i.Status == PreorderItemStatus.Fulfilled);
|
|
|
|
preorder.Status = (hasDropped || hasPartial) && !hasPending ? PreorderStatus.PartiallyFulfilled
|
|
: allFulfilled ? PreorderStatus.Confirmed
|
|
: PreorderStatus.Pending;
|
|
|
|
preorder.UpdatedOnUtc = DateTime.UtcNow;
|
|
await Preorders.UpdateAsync(preorder);
|
|
|
|
_logger.Info($"PreorderDbContext: Preorder #{preorderId} status → {preorder.Status}");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Mark a preorder as cancelled (customer or admin action).
|
|
/// </summary>
|
|
public async Task CancelPreorderAsync(int preorderId)
|
|
{
|
|
var preorder = await Preorders.GetByIdAsync(preorderId);
|
|
if (preorder == null) return;
|
|
|
|
preorder.Status = PreorderStatus.Cancelled;
|
|
preorder.UpdatedOnUtc = DateTime.UtcNow;
|
|
await Preorders.UpdateAsync(preorder);
|
|
|
|
var items = await PreorderItems.GetAllByPreorderIdAsync(preorderId).ToListAsync();
|
|
var cancellableStatuses = new[] { PreorderItemStatus.Pending, PreorderItemStatus.PartiallyFulfilled };
|
|
foreach (var item in items.Where(i => cancellableStatuses.Contains(i.Status)))
|
|
{
|
|
item.Status = PreorderItemStatus.Dropped;
|
|
await PreorderItems.UpdateAsync(item);
|
|
}
|
|
|
|
_logger.Info($"PreorderDbContext: Preorder #{preorderId} cancelled");
|
|
}
|
|
}
|