All checks were successful
Build and Deploy / deploy (push) Successful in 1m43s
新增 /order/pickup-order/downstream-forward,productCode/supplierCode/地址重量商品均取揽收单,不再依赖关联物流单。 Co-authored-by: Cursor <cursoragent@cursor.com>
191 lines
7.2 KiB
C#
191 lines
7.2 KiB
C#
using Oms.Application.Dtos.Orders;
|
||
using Oms.Domain.ChannelsAggregate.Repositories;
|
||
using Oms.Domain.OrdersAggregate.Consts;
|
||
using Oms.Domain.OrdersAggregate.Entities;
|
||
using Oms.Domain.SystemAggregate.Entities;
|
||
|
||
namespace Oms.Application.Shared;
|
||
|
||
/// <summary>
|
||
/// 从揽收单表组装 itfx createOrderOne 标准请求体(不读关联物流单)。
|
||
/// </summary>
|
||
public static class PickupOrderDownstreamCreateOneBodyBuilder
|
||
{
|
||
public static async Task<(ItfxCreateOrderOneBody Body, string? ForecastProductCode)> BuildAsync(
|
||
PickupOrder pickup,
|
||
WarehouseAddress warehouse,
|
||
ISalesProductRepository salesProductRepository,
|
||
IServiceChannelRepository serviceChannelRepository,
|
||
CancellationToken cancellationToken = default)
|
||
{
|
||
var productCode = await ResolveForecastProductCodeAsync(
|
||
pickup.CarrierService,
|
||
salesProductRepository,
|
||
serviceChannelRepository,
|
||
cancellationToken);
|
||
|
||
var isReverse = string.Equals(
|
||
PickupDirectionCodes.NormalizeOrDefault(pickup.Direction),
|
||
PickupDirectionCodes.Reverse,
|
||
StringComparison.OrdinalIgnoreCase);
|
||
|
||
var customerSide = MapCustomerSide(pickup);
|
||
var warehouseSide = MapWarehouseSide(warehouse);
|
||
|
||
var weight = pickup.TotalActualWeight ?? pickup.ChargeableWeight;
|
||
var qty = pickup.ParcelCount > 0 ? pickup.ParcelCount : 1;
|
||
var cargoName = string.IsNullOrWhiteSpace(pickup.Remark)
|
||
? "上门揽收包裹"
|
||
: pickup.Remark.Trim();
|
||
|
||
return (new ItfxCreateOrderOneBody
|
||
{
|
||
ClientNo = pickup.PickupNo,
|
||
ServiceNo = pickup.PickupNo,
|
||
TrackNo = pickup.CarrierWaybillNo,
|
||
ProductCode = productCode,
|
||
CargoAttribute = CargoAttributeCodes.General,
|
||
WarehouseId = pickup.WarehouseId,
|
||
CustomerId = pickup.CustomerId,
|
||
Length = 1,
|
||
Width = 1,
|
||
Height = 1,
|
||
ActualWeight = weight,
|
||
ChargeableWeight = pickup.ChargeableWeight ?? weight,
|
||
IsCod = false,
|
||
DeclaredCurrency = pickup.Currency,
|
||
DeclaredSum = FormatDecimal(pickup.ReceivableAmount ?? pickup.FreightAmount ?? 1),
|
||
Quantity = qty.ToString(),
|
||
Sender = isReverse ? warehouseSide.Sender : customerSide.Sender,
|
||
Receiver = isReverse ? customerSide.Receiver : warehouseSide.Receiver,
|
||
Items =
|
||
[
|
||
new OrderParcelItemInput
|
||
{
|
||
CnName = cargoName,
|
||
EnName = cargoName,
|
||
UnitPrice = 1,
|
||
UnitWeight = weight,
|
||
Quantity = qty,
|
||
Amount = 1,
|
||
Weight = weight
|
||
}
|
||
]
|
||
}, productCode);
|
||
}
|
||
|
||
/// <summary>
|
||
/// createOrderOne.productCode:承运服务(销售产品)对应渠道的 ForecastCode,缺省回退 CarrierService。
|
||
/// </summary>
|
||
public static async Task<string?> ResolveForecastProductCodeAsync(
|
||
string? carrierService,
|
||
ISalesProductRepository salesProductRepository,
|
||
IServiceChannelRepository serviceChannelRepository,
|
||
CancellationToken cancellationToken = default)
|
||
{
|
||
var salesProductCode = carrierService?.Trim();
|
||
if (string.IsNullOrWhiteSpace(salesProductCode))
|
||
{
|
||
return null;
|
||
}
|
||
|
||
var product = await salesProductRepository.GetByProductCodeAsync(salesProductCode, cancellationToken);
|
||
if (product == null)
|
||
{
|
||
return salesProductCode;
|
||
}
|
||
|
||
var providers = await salesProductRepository.GetAllocationProvidersAsync(product.Id, cancellationToken);
|
||
var channelId = providers
|
||
.Where(x => x.ServiceChannelId is > 0)
|
||
.OrderBy(x => x.SerialNumber)
|
||
.Select(x => x.ServiceChannelId!.Value)
|
||
.FirstOrDefault();
|
||
if (channelId <= 0)
|
||
{
|
||
return salesProductCode;
|
||
}
|
||
|
||
var channel = await serviceChannelRepository.FirstOrDefaultAsync(x => x.Id == channelId, cancellationToken);
|
||
var forecastCode = channel?.ForecastCode?.Trim();
|
||
return string.IsNullOrWhiteSpace(forecastCode) ? salesProductCode : forecastCode;
|
||
}
|
||
|
||
private static string? FormatDecimal(decimal? value) =>
|
||
value.HasValue ? value.Value.ToString(System.Globalization.CultureInfo.InvariantCulture) : null;
|
||
|
||
private static (OrderParcelSenderInput Sender, OrderParcelReceiverInput Receiver) MapCustomerSide(PickupOrder pickup)
|
||
{
|
||
var sender = new OrderParcelSenderInput
|
||
{
|
||
SenderName = pickup.SenderName,
|
||
Company = pickup.SenderCompany,
|
||
Phone = pickup.SenderPhone,
|
||
TelePhone = pickup.SenderTelePhone,
|
||
Email = pickup.SenderEmail,
|
||
CountryCode = string.IsNullOrWhiteSpace(pickup.SenderCountryCode)
|
||
? "CN"
|
||
: pickup.SenderCountryCode.Trim().ToUpperInvariant(),
|
||
Province = pickup.SenderProvince,
|
||
City = pickup.SenderCity,
|
||
ZipCode = pickup.SenderZipCode,
|
||
StreetAddress1 = pickup.SenderStreetAddress1,
|
||
StreetAddress2 = pickup.SenderStreetAddress2,
|
||
StreetAddress3 = pickup.SenderStreetAddress3,
|
||
HouseNumber = pickup.SenderHouseNumber
|
||
};
|
||
|
||
var receiver = new OrderParcelReceiverInput
|
||
{
|
||
RecipientsName = pickup.SenderName,
|
||
CompanyName = pickup.SenderCompany,
|
||
Phone = pickup.SenderPhone,
|
||
TelePhone = pickup.SenderTelePhone,
|
||
Email = pickup.SenderEmail,
|
||
CountryCode = string.IsNullOrWhiteSpace(pickup.SenderCountryCode)
|
||
? "CN"
|
||
: pickup.SenderCountryCode.Trim().ToUpperInvariant(),
|
||
Province = pickup.SenderProvince,
|
||
City = pickup.SenderCity,
|
||
ZipCode = string.IsNullOrWhiteSpace(pickup.SenderZipCode) ? "000000" : pickup.SenderZipCode,
|
||
StreetAddress1 = pickup.SenderStreetAddress1,
|
||
StreetAddress2 = pickup.SenderStreetAddress2,
|
||
StreetAddress3 = pickup.SenderStreetAddress3,
|
||
StreetNumber = pickup.SenderHouseNumber
|
||
};
|
||
|
||
return (sender, receiver);
|
||
}
|
||
|
||
private static (OrderParcelSenderInput Sender, OrderParcelReceiverInput Receiver) MapWarehouseSide(
|
||
WarehouseAddress warehouse)
|
||
{
|
||
var contact = string.IsNullOrWhiteSpace(warehouse.Recipient)
|
||
? warehouse.WarehouseName
|
||
: warehouse.Recipient!.Trim();
|
||
var street = string.IsNullOrWhiteSpace(warehouse.ShippingAddress)
|
||
? warehouse.WarehouseName
|
||
: warehouse.ShippingAddress!.Trim();
|
||
|
||
var sender = new OrderParcelSenderInput
|
||
{
|
||
SenderName = contact,
|
||
Phone = warehouse.ContactPhone,
|
||
CountryCode = "CN",
|
||
StreetAddress1 = street,
|
||
ZipCode = "000000"
|
||
};
|
||
|
||
var receiver = new OrderParcelReceiverInput
|
||
{
|
||
RecipientsName = contact,
|
||
Phone = warehouse.ContactPhone,
|
||
CountryCode = "CN",
|
||
ZipCode = "000000",
|
||
StreetAddress1 = street
|
||
};
|
||
|
||
return (sender, receiver);
|
||
}
|
||
}
|