Files
WMS-Api/src/WMS.Web.Domain/Entitys/OutStockTask.cs
2024-07-13 10:10:35 +08:00

297 lines
11 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text;
using WMS.Web.Core;
using WMS.Web.Core.Help;
using WMS.Web.Core.Internal.Results;
using WMS.Web.Domain.Values;
namespace WMS.Web.Domain.Entitys
{
/// <summary>
/// erp出库任务单
/// </summary>
[Serializable]
[Table("t_erp_outstock_task")]
public class OutStockTask : EntityBase
{
public OutStockTask() { }
/// <summary>
/// 主键 订单编号
/// </summary>
[Column("Id")]
public override int Id { get; set; }
/// <summary>
/// 单据编号
/// </summary>
[Column("BillNo")]
public string BillNo { get; set; }
/// <summary>
/// 发货组织
///</summary>
[Column("DeliveryOrgId")]
public int DeliveryOrgId { get; set; }
/// <summary>
/// 组织编码
///</summary>
[Column("OrgCode")]
public string OrgCode { get; set; }
/// <summary>
/// 收货客户
///</summary>
[Column("ReceiptCustomerId")]
public int ReceiptCustomerId { get; set; }
/// <summary>
/// 仓库ID
///</summary>
[Column("StockCode")]
public string StockCode { get; set; } = "";
/// <summary>
/// 单据状态
/// </summary>
[Column("Status")]
public OutStockStatus Status { get; set; } = OutStockStatus.Wait;
/// <summary>
/// 单据类型
/// </summary>
[Column("Type")]
public OutStockType Type { get; set; } = OutStockType.Sal;
/// <summary>
/// 操作人
/// </summary>
[Column("OperatorId")]
public int? OperatorId { get; set; }
/// <summary>
/// 操作时间
/// </summary>
[Column("OperateTime")]
public DateTime? OperateTime { get; set; }
/// <summary>
/// 出库人
/// </summary>
[Column("OutStockId")]
public int? OutStockId { get; set; }
/// <summary>
/// 出库时间
/// </summary>
[Column("OutStockTime")]
public DateTime? OutStockTime { get; set; }
/// <summary>
/// 创建时间erp那边的创建时间
///</summary>
[Column("CreateTime")]
public DateTime? CreateTime { get; set; }
/// <summary>
/// 在wms最新数据修改时间
/// </summary>
[Column("WmsUpdateTime")]
public DateTime WmsUpdateTime { get; set; } = DateTime.Now;
/// <summary>
/// 明细
/// </summary>
public List<OutStockTaskDetails> Details = new List<OutStockTaskDetails>();
public void Create(OutStockType type, string stockCode, string orgCode, int deliveryOrgId, int receiptCustomerId, DateTime createTime)
{
this.Type = type;
this.StockCode = stockCode;
this.OrgCode = orgCode;
this.DeliveryOrgId = deliveryOrgId;
this.ReceiptCustomerId = receiptCustomerId;
this.CreateTime = createTime;
}
/// <summary>
/// 出库 反写 任务单(返回 这个物料下面的来源单号出了多少数量)
/// </summary>
/// <param name="materialNumber"></param>
/// <param name="qty"></param>
/// <returns></returns>
public Result<List<(int erpDetailId, decimal qty)>> OutStock(string materialNumber, decimal qty, int outStockId)
{
if (this.Status == OutStockStatus.Already)
return Result<List<(int erpDetailId, decimal qty)>>.ReFailure(ResultCodes.OutStockTaskAlready);
if (this.Status == OutStockStatus.Repeal)
return Result<List<(int erpDetailId, decimal qty)>>.ReFailure(ResultCodes.OutStockTaskRepeal);
var detail = this.Details.FirstOrDefault(f => f.MaterialNumber == materialNumber);
if (detail == null) return Result<List<(int erpDetailId, decimal qty)>>.ReFailure(ResultCodes.OrderNoData);
if ((detail.AccruedQty - detail.RealityQty) < qty)
return Result<List<(int erpDetailId, decimal qty)>>.ReFailure(ResultCodes.OutStockQtyError);
List<(int erpDetailId, decimal qty)> resList = new List<(int erpDetailId, decimal qty)>();
var mQty = qty;
foreach (var d in detail.ErpDetails)
{
if ((d.AccruedQty - d.RealityQty) >= mQty)
{
d.RealityQty += qty;
resList.Add((d.Erp_DetailId, mQty));
break;//本次出库数量已经分配完毕 调出循环
}
else
{
//代表这一个来源单号对应的物料 能全部出掉,并且还有剩余 进行下一个来源单的出货
var cQty = d.AccruedQty - d.RealityQty;//本次出货数量
mQty -= cQty;
d.RealityQty = d.AccruedQty;
resList.Add((d.Erp_DetailId, cQty));
}
}
if (detail.RealityQty <= 0)
detail.OutStockBeginTime = DateTime.Now;
//全部出库完成
if (detail.AccruedQty == (detail.RealityQty + qty))
detail.OutStockEndTime = DateTime.Now;
detail.RealityQty = detail.RealityQty + qty;
this.OutStockId = outStockId;
this.OutStockTime = DateTime.Now;
GenerateStatus();
return Result<List<(int erpDetailId, decimal qty)>>.ReSuccess(resList);
}
/// <summary>
/// 自动验证出库状态
/// </summary>
public void GenerateStatus()
{
if (this.Status == OutStockStatus.Repeal)
return;
var details = this.Details.Where(w => w.IsRepeal != true).ToList();
if (details.Where(w => w.RealityQty <= 0).Count() == details.Count())
this.Status = OutStockStatus.Wait;
else if (details.Where(w => w.RealityQty >= w.AccruedQty).Count() == details.Count())
this.Status = OutStockStatus.Already;
else
this.Status = OutStockStatus.Part;
}
/// <summary>
/// 生成单据号
/// </summary>
public void GenerateNo()
{
//用户手动输入了 就不自动生成了
if (!string.IsNullOrEmpty(this.BillNo)) return;
if (this.Id.ToString().Length >= 8)
{
this.BillNo = "CKRW" + this.Id.ToString();
return;
}
string idStr = this.Id.ToString();
while (true)
{
idStr = "0" + idStr;
if (idStr.Length >= 8) break;
}
//this.Number = CNSpellTranslator.GetFirstSpell(this.Name) + idStr;
this.BillNo = "CKRW" + idStr;
}
/// <summary>
/// 作废
/// </summary>
public void Repeal(int creatorId, List<int> ids)
{
this.OperatorId = creatorId;
this.OperateTime = DateTime.Now;
foreach (var d in this.Details.Where(w => ids.Contains(w.Id)))
{
d.IsRepeal = true;
}
//如果明细全部作废,则单据状态作废
if (this.Details.Where(w => w.IsRepeal == true).Count() == this.Details.Count())
this.Status = OutStockStatus.Repeal;
GenerateStatus();
}
/// <summary>
/// 反作废
/// </summary>
public void NoRepeal(int creatorId, List<int> ids)
{
this.OperatorId = 0;
this.OperateTime = null;
foreach (var d in this.Details.Where(w => ids.Contains(w.Id)))
{
d.IsRepeal = false;
}
var details = this.Details.Where(w => w.IsRepeal != true).ToList();
if (details.Where(w => w.RealityQty <= 0).Count() == details.Count())
this.Status = OutStockStatus.Wait;
else if (details.Where(w => w.RealityQty >= w.AccruedQty).Count() == details.Count())
this.Status = OutStockStatus.Already;
else
this.Status = OutStockStatus.Part;
}
/// <summary>
/// 合并
/// </summary>
/// <param name="list"></param>
/// <param name="creatorId"></param>
/// <returns></returns>
public Result Merge(List<OutStockTask> list, int creatorId)
{
if (list.Count() <= 1) return Result.ReFailure(ResultCodes.MergeNumberError);
// 符合合并数据逻辑:出库状态为”待拣货”+出库类型为:销售出库+发货组织一致+收货客户一致+发货仓库一致
if (list.Where(w => w.Status != OutStockStatus.Wait).Any()) return Result.ReFailure(ResultCodes.MergeStatusError);
if (list.Where(w => w.Type != OutStockType.Sal).Any()) return Result.ReFailure(ResultCodes.MergeStatusError);
if (list.GroupBy(g => g.DeliveryOrgId).Count() > 1) return Result.ReFailure(ResultCodes.MergeStatusError);
if (list.GroupBy(g => g.ReceiptCustomerId).Count() > 1) return Result.ReFailure(ResultCodes.MergeStatusError);
if (list.GroupBy(g => g.OrgCode).Count() > 1) return Result.ReFailure(ResultCodes.MergeStatusError);
var details = list.SelectMany(s => s.Details).ToList().Clone();
if (list.GroupBy(g => g.StockCode).Count() > 1) return Result.ReFailure(ResultCodes.MergeStatusError);
List<OutStockTaskDetails> details_new = new List<OutStockTaskDetails>();
//清空数据绑定
foreach (var d in details)
{
d.Id = 0;
d.Fid = 0;
var detail_new = details_new.FirstOrDefault(f => f.MaterialNumber == d.MaterialNumber);
if (detail_new != null)
{
detail_new.AccruedQty += d.AccruedQty;//应出数量累加
detail_new.Remark = detail_new.Remark + "\r\n" + d.Remark;
foreach (var erpd in d.ErpDetails)
{
var cd = erpd.Clone();
cd.Id = 0; cd.DetailId = 0;
detail_new.ErpDetails.Add(cd);
}
}
else
{
foreach (var erpd in d.ErpDetails)
{
erpd.Id = 0;
erpd.DetailId = 0;
}
details_new.Add(d);
}
}
this.CreateTime = list.Max(o => o.CreateTime);//取最新的时间
this.OperatorId = creatorId;
this.OperateTime = DateTime.Now;
this.Status = OutStockStatus.Wait;
this.DeliveryOrgId = list.First().DeliveryOrgId;
this.ReceiptCustomerId = list.First().ReceiptCustomerId;
this.StockCode = list.First().StockCode;
this.OrgCode = list.First().OrgCode;
this.Type = OutStockType.Sal;
this.Details = details_new;
return Result.ReSuccess();
}
}
}