一、业务背景种类:
(1)单托数量差别小,出库固定托数,分配总数控制误差范围
A客户,标准托盘,产品单一不混托,单托数量基本固定,略有误差,例如单托2.5t ± 0.5t
出库方式:集装箱装货,每个集装箱装货11托产品,需要要求出库总重27.5t ± 0.3t,需WMS自动分配库存,并可以人工手动调整分配结果(人工调整这里不进行代码展示)
相关策略详见:代码展示 第(1)条
(2)不固定托数,分配总数控制误差范围
B客户,单据出库总数50t,需WMS自动分配托数,使其总数满足 [50-5 , 50] t 的区间之内
相关策略详见:代码展示 第(2)条
(3)凑整出库,减少分拣返库,每托数量较为规律,差异不太大
A物料每托的数量可能是10,12,15,18......,其中数量为10有x托,数量为12的有y托,以此类推;假设客户需要出库30,需要WMS自动分配出库托盘,如果库内托盘存在数量相加正好等于30,就不要多出,减少分拣返库。
相关策略详见:代码展示 第(3)条
(4)凑整出库,减少分拣返库,每托数量完全为无规律——本方法仅适用于执行样本量小或者出库托数不多的项目
A物料每托的数量可能是10,12,15,18......,很少出现两个托盘数量完全一样的,客户需要要出库30,需要WMS自动分配出库托盘,如果库内托盘存在数量相加正好等于30,就不要多出,减少分拣返库。
相关策略详见:代码展示 第(4)条
二、代码说明
本人刚从房地产成本转行WMS开发一年多时间,代码用的C#,本次分享完全为个人实战总结,有不足之处欢迎指正,混托分配/入库策略等以后分享。
三、代码展示
(1)业务场景(1)代码实现:
public void getjiList(List<UnitLoadItem> yangben//库存样本, List<UnitLoadItem> jieguo//分配返回的结果, decimal star//范围下限, decimal end//范围上限, int rongliang//托数, List<UnitLoadItem> zuhe = null)
{
foreach (var item in yangben)
{
if (jieguo.Count > 0)
{
return;
}
if (zuhe == null)
{
zuhe = new List<UnitLoadItem>();
}
List<UnitLoadItem> newzuhe = zuhe.ToList();
newzuhe.Add(item);
if (newzuhe.Count == rongliang)
{
decimal sum = newzuhe.Sum(x => x.Quantity.Number);
if (sum >= star && sum <= end)
{
jieguo.AddRange(newzuhe);
}
return;
}
List<UnitLoadItem> newyangben = yangben.Where(x => x != item).OrderBy(x => x.UnitLoad.CreatedAt).ToList();
if (newyangben.Count > 0)
{
getjiList(newyangben, jieguo, star, end, rongliang, newzuhe);
}
}
}
(2)业务场景(2)代码实现:
public void getziList(List<UnitLoadItem> yangben//库存样本, List<UnitLoadItem> jieguo//返回分配的结果, decimal total//出库总数, decimal wucha//误差 List<UnitLoadItem> zuhe = null)
{
foreach (var item in yangben)
{
if (jieguo.Count > 0)
{
return;
}
if (zuhe == null)
{
zuhe = new List<UnitLoadItem>();
}
List<UnitLoadItem> newzuhe = zuhe.ToList();
newzuhe.Add(item);
decimal sum = newzuhe.Sum(x => x.Quantity.Number);
if (sum >= total - wucha && sum <= total)
{
jieguo.AddRange(newzuhe);
return;
}
List<UnitLoadItem> newyangben = yangben.Where(x => x != item).OrderBy(x => x.UnitLoad.CreatedAt).ToList();
if (newyangben.Count > 0)
{
getziList(newyangben, jieguo, total, wucha, newzuhe);
}
}
}
(3)业务场景(3)代码实现:
设计思路:有点类似于栈的概念:后如先出,可以兼顾一点先进先出的要求
public void getList2(List<UnitLoadItem> zong//库存样本, List<UnitLoadItem> fen//待分配样本, List<decimal> groupList//样本按数量分组后的KEY集合, List<UnitLoadItem> jieguo//返回的分配结果, decimal xz//迭代用的, decimal total//出库总数, List<UnitLoadItem> zuhe = null)
{
foreach (var item in fen)
{
if (jieguo.Count > 0)
{
return;
}
if (zuhe == null)
{
zuhe = new List<UnitLoadItem>();
}
List<UnitLoadItem> newzuhe = zuhe.ToList();
decimal sum = newzuhe.Sum(x => x.Quantity.Number) + item.Quantity.Number;
if (sum > total)
{
var index = newzuhe.Count - 1;
for (var i = index; i >= 0; i--)
{
if (newzuhe[i].Quantity.Number != xz)
{
return;
}
newzuhe.RemoveAt(i);
var newxzzu = groupList.Where(x => x > xz).ToList();
if (newxzzu.Count > 0)
{
var newxz = newxzzu.OrderBy(x => x).FirstOrDefault();
var newfen = zong.Where(x => x.Quantity.Number == newxz).OrderBy(x => x.UnitLoad.CreatedAt).ToList();
getList2(zong, newfen, groupList, jieguo, newxz, total, zuhe);
if (jieguo.Count > 0)
{
return;
}
}
}
}
else if (sum == total)
{
newzuhe.Add(item);
jieguo.AddRange(newzuhe);
return;
}
else
{
zuhe.Add(item);
}
}
}
(4)业务场景(4)代码实现:
提醒:看似最灵活的设计,实际样本量稍微有点大,CPU就完犊子了
public void getList(List<UnitLoadItem> yangben, List<UnitLoadItem> jieguo, decimal total, List<UnitLoadItem> zuhe = null)
{
foreach (var item in yangben)
{
if (jieguo.Count > 0)
{
return;
}
if (zuhe == null)
{
zuhe = new List<UnitLoadItem>();
}
List<UnitLoadItem> newzuhe = zuhe.ToList();
newzuhe.Add(item);
decimal sum = newzuhe.Sum(x => x.Quantity.Number);
if (sum > total)
{
return;
}
if (sum == total)
{
jieguo.AddRange(newzuhe);
return;
}
List<UnitLoadItem> newyangben = yangben.Where(x => x != item).ToList();
if (newyangben.Count > 0)
{
getList(newyangben, jieguo, total, newzuhe);
}
}
}