Try your search with a different keyword or use * as a wildcard.
using Nop.Core;
using Nop.Core.Domain.Catalog;
using Nop.Core.Domain.Common;
using Nop.Core.Domain.Orders;
using Nop.Core.Domain.Shipping;
using Nop.Data;
using Nop.Services.Shipping.Pickup;
using Nop.Services.Shipping.Tracking;
namespace Nop.Services.Shipping;
/// <summary>
/// Shipment service
/// </summary>
public partial class ShipmentService : IShipmentService
{
#region Fields
protected readonly IPickupPluginManager _pickupPluginManager;
protected readonly IRepository<Address> _addressRepository;
protected readonly IRepository<Order> _orderRepository;
protected readonly IRepository<OrderItem> _orderItemRepository;
protected readonly IRepository<Product> _productRepository;
protected readonly IRepository<Shipment> _shipmentRepository;
protected readonly IRepository<ShipmentItem> _siRepository;
protected readonly IShippingPluginManager _shippingPluginManager;
#endregion
#region Ctor
public ShipmentService(IPickupPluginManager pickupPluginManager,
IRepository<Address> addressRepository,
IRepository<Order> orderRepository,
IRepository<OrderItem> orderItemRepository,
IRepository<Product> productRepository,
IRepository<Shipment> shipmentRepository,
IRepository<ShipmentItem> siRepository,
IShippingPluginManager shippingPluginManager)
{
_pickupPluginManager = pickupPluginManager;
_addressRepository = addressRepository;
_orderRepository = orderRepository;
_orderItemRepository = orderItemRepository;
_productRepository = productRepository;
_shipmentRepository = shipmentRepository;
_siRepository = siRepository;
_shippingPluginManager = shippingPluginManager;
}
#endregion
#region Methods
/// <summary>
/// Deletes a shipment
/// </summary>
/// <param name="shipment">Shipment</param>
/// <returns>A task that represents the asynchronous operation</returns>
public virtual async Task DeleteShipmentAsync(Shipment shipment)
{
await _shipmentRepository.DeleteAsync(shipment);
}
/// <summary>
/// Search shipments
/// </summary>
/// <param name="vendorId">Vendor identifier; 0 to load all records</param>
/// <param name="warehouseId">Warehouse identifier, only shipments with products from a specified warehouse will be loaded; 0 to load all orders</param>
/// <param name="shippingCountryId">Shipping country identifier; 0 to load all records</param>
/// <param name="shippingStateId">Shipping state identifier; 0 to load all records</param>
/// <param name="shippingCounty">Shipping county; null to load all records</param>
/// <param name="shippingCity">Shipping city; null to load all records</param>
/// <param name="trackingNumber">Search by tracking number</param>
/// <param name="loadNotShipped">A value indicating whether we should load only not shipped shipments</param>
/// <param name="loadNotReadyForPickup">A value indicating whether we should load only not ready for pickup shipments</param>
/// <param name="loadNotDelivered">A value indicating whether we should load only not delivered shipments</param>
/// <param name="orderId">Order identifier; 0 to load all records</param>
/// <param name="createdFromUtc">Created date from (UTC); null to load all records</param>
/// <param name="createdToUtc">Created date to (UTC); null to load all records</param>
/// <param name="pageIndex">Page index</param>
/// <param name="pageSize">Page size</param>
/// <returns>
/// A task that represents the asynchronous operation
/// The task result contains the shipments
/// </returns>
public virtual async Task<IPagedList<Shipment>> GetAllShipmentsAsync(int vendorId = 0, int warehouseId = 0,
int shippingCountryId = 0,
int shippingStateId = 0,
string shippingCounty = null,
string shippingCity = null,
string trackingNumber = null,
bool loadNotShipped = false,
bool loadNotReadyForPickup = false,
bool loadNotDelivered = false,
int orderId = 0,
DateTime? createdFromUtc = null, DateTime? createdToUtc = null,
int pageIndex = 0, int pageSize = int.MaxValue)
{
var shipments = await _shipmentRepository.GetAllPagedAsync(query =>
{
if (orderId > 0)
query = query.Where(o => o.OrderId == orderId);
if (!string.IsNullOrEmpty(trackingNumber))
query = query.Where(s => s.TrackingNumber.Contains(trackingNumber));
if (shippingCountryId > 0)
query = from s in query
join o in _orderRepository.Table on s.OrderId equals o.Id
where _addressRepository.Table.Any(a =>
a.Id == (o.PickupInStore ? o.PickupAddressId : o.ShippingAddressId) &&
a.CountryId == shippingCountryId)
select s;
if (shippingStateId > 0)
query = from s in query
join o in _orderRepository.Table on s.OrderId equals o.Id
where _addressRepository.Table.Any(a =>
a.Id == (o.PickupInStore ? o.PickupAddressId : o.ShippingAddressId) &&
a.StateProvinceId == shippingStateId)
select s;
if (!string.IsNullOrWhiteSpace(shippingCounty))
query = from s in query
join o in _orderRepository.Table on s.OrderId equals o.Id
where _addressRepository.Table.Any(a =>
a.Id == (o.PickupInStore ? o.PickupAddressId : o.ShippingAddressId) &&
a.County.Contains(shippingCounty))
select s;
if (!string.IsNullOrWhiteSpace(shippingCity))
query = from s in query
join o in _orderRepository.Table on s.OrderId equals o.Id
where _addressRepository.Table.Any(a =>
a.Id == (o.PickupInStore ? o.PickupAddressId : o.ShippingAddressId) &&
a.City.Contains(shippingCity))
select s;
if (loadNotShipped)
query = from s in query
join o in _orderRepository.Table on s.OrderId equals o.Id
where !s.ShippedDateUtc.HasValue && !o.PickupInStore
select s;
if (loadNotReadyForPickup)
query = from s in query
join o in _orderRepository.Table on s.OrderId equals o.Id
where !s.ReadyForPickupDateUtc.HasValue && o.PickupInStore
select s;
if (loadNotDelivered)
query = query.Where(s => !s.DeliveryDateUtc.HasValue);
if (createdFromUtc.HasValue)
query = query.Where(s => createdFromUtc.Value <= s.CreatedOnUtc);
if (createdToUtc.HasValue)
query = query.Where(s => createdToUtc.Value >= s.CreatedOnUtc);
query = from s in query
join o in _orderRepository.Table on s.OrderId equals o.Id
where !o.Deleted
select s;
query = query.Distinct();
if (vendorId > 0)
{
var queryVendorOrderItems = from orderItem in _orderItemRepository.Table
join p in _productRepository.Table on orderItem.ProductId equals p.Id
where p.VendorId == vendorId
select orderItem.Id;
query = from s in query
join si in _siRepository.Table on s.Id equals si.ShipmentId
where queryVendorOrderItems.Contains(si.OrderItemId)
select s;
query = query.Distinct();
}
if (warehouseId > 0)
{
query = from s in query
join si in _siRepository.Table on s.Id equals si.ShipmentId
where si.WarehouseId == warehouseId
select s;
query = query.Distinct();
}
query = query.OrderByDescending(s => s.CreatedOnUtc);
return query;
}, pageIndex, pageSize);
return shipments;
}
/// <summary>
/// Get shipment by identifiers
/// </summary>
/// <param name="shipmentIds">Shipment identifiers</param>
/// <returns>
/// A task that represents the asynchronous operation
/// The task result contains the shipments
/// </returns>
public virtual async Task<IList<Shipment>> GetShipmentsByIdsAsync(int[] shipmentIds)
{
return await _shipmentRepository.GetByIdsAsync(shipmentIds);
}
/// <summary>
/// Gets a shipment
/// </summary>
/// <param name="shipmentId">Shipment identifier</param>
/// <returns>
/// A task that represents the asynchronous operation
/// The task result contains the shipment
/// </returns>
public virtual async Task<Shipment> GetShipmentByIdAsync(int shipmentId)
{
return await _shipmentRepository.GetByIdAsync(shipmentId, cache => default, useShortTermCache: true);
}
/// <summary>
/// Gets a list of order shipments
/// </summary>
/// <param name="orderId">Order identifier</param>
/// <param name="shipped">A value indicating whether to count only shipped or not shipped shipments; pass null to ignore</param>
/// <param name="readyForPickup">A value indicating whether to load only ready for pickup shipments; pass null to ignore</param>
/// <param name="vendorId">Vendor identifier; pass 0 to ignore</param>
/// <returns>
/// A task that represents the asynchronous operation
/// The task result contains the result
/// </returns>
public virtual async Task<IList<Shipment>> GetShipmentsByOrderIdAsync(int orderId, bool? shipped = null, bool? readyForPickup = null, int vendorId = 0)
{
if (orderId == 0)
return new List<Shipment>();
var shipments = _shipmentRepository.Table;
if (shipped.HasValue)
shipments = shipments.Where(s => s.ShippedDateUtc.HasValue == shipped);
if (readyForPickup.HasValue)
shipments = shipments.Where(s => s.ReadyForPickupDateUtc.HasValue == readyForPickup);
return await shipments.Where(shipment => shipment.OrderId == orderId).ToListAsync();
}
/// <summary>
/// Inserts a shipment
/// </summary>
/// <param name="shipment">Shipment</param>
/// <returns>A task that represents the asynchronous operation</returns>
public virtual async Task InsertShipmentAsync(Shipment shipment)
{
await _shipmentRepository.InsertAsync(shipment);
}
/// <summary>
/// Updates the shipment
/// </summary>
/// <param name="shipment">Shipment</param>
/// <returns>A task that represents the asynchronous operation</returns>
public virtual async Task UpdateShipmentAsync(Shipment shipment)
{
await _shipmentRepository.UpdateAsync(shipment);
}
/// <summary>
/// Gets a shipment items of shipment
/// </summary>
/// <param name="shipmentId">Shipment identifier</param>
/// <returns>
/// A task that represents the asynchronous operation
/// The task result contains the shipment items
/// </returns>
public virtual async Task<IList<ShipmentItem>> GetShipmentItemsByShipmentIdAsync(int shipmentId)
{
if (shipmentId == 0)
return null;
return await _siRepository.Table.Where(si => si.ShipmentId == shipmentId).ToListAsync();
}
/// <summary>
/// Inserts a shipment item
/// </summary>
/// <param name="shipmentItem">Shipment item</param>
/// <returns>A task that represents the asynchronous operation</returns>
public virtual async Task InsertShipmentItemAsync(ShipmentItem shipmentItem)
{
await _siRepository.InsertAsync(shipmentItem);
}
/// <summary>
/// Deletes a shipment item
/// </summary>
/// <param name="shipmentItem">Shipment Item</param>
/// <returns>A task that represents the asynchronous operation</returns>
public virtual async Task DeleteShipmentItemAsync(ShipmentItem shipmentItem)
{
await _siRepository.DeleteAsync(shipmentItem);
}
/// <summary>
/// Updates a shipment item
/// </summary>
/// <param name="shipmentItem">Shipment item</param>
/// <returns>A task that represents the asynchronous operation</returns>
public virtual async Task UpdateShipmentItemAsync(ShipmentItem shipmentItem)
{
await _siRepository.UpdateAsync(shipmentItem);
}
/// <summary>
/// Gets a shipment item
/// </summary>
/// <param name="shipmentItemId">Shipment item identifier</param>
/// <returns>
/// A task that represents the asynchronous operation
/// The task result contains the shipment item
/// </returns>
public virtual async Task<ShipmentItem> GetShipmentItemByIdAsync(int shipmentItemId)
{
return await _siRepository.GetByIdAsync(shipmentItemId, cache => default, useShortTermCache: true);
}
/// <summary>
/// Get quantity in shipments. For example, get planned quantity to be shipped
/// </summary>
/// <param name="product">Product</param>
/// <param name="warehouseId">Warehouse identifier</param>
/// <param name="ignoreShipped">Ignore already shipped shipments</param>
/// <param name="ignoreDelivered">Ignore already delivered shipments</param>
/// <returns>
/// A task that represents the asynchronous operation
/// The task result contains the quantity
/// </returns>
public virtual async Task<int> GetQuantityInShipmentsAsync(Product product, int warehouseId,
bool ignoreShipped, bool ignoreDelivered)
{
ArgumentNullException.ThrowIfNull(product);
//only products with "use multiple warehouses" are handled this way
if (product.ManageInventoryMethod != ManageInventoryMethod.ManageStock)
return 0;
if (!product.UseMultipleWarehouses)
return 0;
const int cancelledOrderStatusId = (int)OrderStatus.Cancelled;
var query = _siRepository.Table;
query = from si in query
join s in _shipmentRepository.Table on si.ShipmentId equals s.Id
join o in _orderRepository.Table on s.OrderId equals o.Id
where !o.Deleted && o.OrderStatusId != cancelledOrderStatusId
select si;
query = query.Distinct();
if (warehouseId > 0)
query = query.Where(si => si.WarehouseId == warehouseId);
if (ignoreShipped)
{
query = from si in query
join s in _shipmentRepository.Table on si.ShipmentId equals s.Id
where !s.ShippedDateUtc.HasValue
select si;
}
if (ignoreDelivered)
{
query = from si in query
join s in _shipmentRepository.Table on si.ShipmentId equals s.Id
where !s.DeliveryDateUtc.HasValue
select si;
}
var queryProductOrderItems = from orderItem in _orderItemRepository.Table
where orderItem.ProductId == product.Id
select orderItem.Id;
query = from si in query
where queryProductOrderItems.Any(orderItemId => orderItemId == si.OrderItemId)
select si;
//some null validation
var result = Convert.ToInt32(await query.SumAsync(si => (int?)si.Quantity));
return result;
}
/// <summary>
/// Get the tracker of the shipment
/// </summary>
/// <param name="shipment">Shipment</param>
/// <returns>
/// A task that represents the asynchronous operation
/// The task result contains the shipment tracker
/// </returns>
public virtual async Task<IShipmentTracker> GetShipmentTrackerAsync(Shipment shipment)
{
var order = await _orderRepository.GetByIdAsync(shipment.OrderId, cache => default, useShortTermCache: true);
IShipmentTracker shipmentTracker = null;
if (order.PickupInStore)
{
var pickupPointProvider = await _pickupPluginManager
.LoadPluginBySystemNameAsync(order.ShippingRateComputationMethodSystemName);
if (pickupPointProvider != null)
shipmentTracker = await pickupPointProvider.GetShipmentTrackerAsync();
}
else
{
var shippingRateComputationMethod = await _shippingPluginManager
.LoadPluginBySystemNameAsync(order.ShippingRateComputationMethodSystemName);
if (shippingRateComputationMethod != null)
shipmentTracker = await shippingRateComputationMethod.GetShipmentTrackerAsync();
}
return shipmentTracker;
}
#endregion
}