297 lines
11 KiB
C#
297 lines
11 KiB
C#
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();
|
||
}
|
||
}
|
||
}
|