• WMS手动配货和自动配货的区别


    手动配货

    不知道配货流程的朋友可以看一下前面的文章链接: 深入浅出WMS之出库流程里面有对出库的解释说明,其中也有对配货的解释。前端页面也可以在前面的那篇文章中看到,这里我们来说一下后端部分。

    手动配货是选中出库单的某条数据,然后点击手动配货,这个时候前端会把这个出库单的guid传给后端,这个时候我们有guid了,就可以去出库单表里去找到这条数据,取出其中的订单号、批次号等等信息。这个时候我们要做的就很简单,去库存里找符合我们可以出库的信息。

     public async Task<PageData> QueryPeiH(int pages, int limit, string matno, string batch, string cflag)
            {
                PageData pageData = new PageData();
                var list = _fsql.Select<LogMstore, LOGMATERIAL,LOGSTORAGE>()
                    .LeftJoin((a, b, c) => a.MATNO == b.MATNO)
                    .LeftJoin((a, b, c) => a.ADDRE == c.ADDRE);
                if (!string.IsNullOrWhiteSpace(matno))
                {
                    list = list.Where((a,b,c) => a.MATNO == matno);
                }
                if (!string.IsNullOrWhiteSpace(batch))
                {
                    list = list.Where((a, b, c) => a.BATCH == batch);
                }
                if (!string.IsNullOrWhiteSpace(cflag))
                {
                    list = list.Where((a, b, c) => a.CFLAG == cflag);
                }
                //在这里添加我们对库存信息的限制条件
                list = list.Where((a, b, c) => Convert.ToDouble(a.QUANT) - Convert.ToDouble(a.QUANTOUT) > 0);
                list = list.Where((a, b, c) => c.PkFlag != "PK");
                //
                if (limit <= 0)
                {
                    //pageData.pageData = await list.Count(out var total).ToListAsync();
                    //pageData.total = (int)total;
                    pageData.pageData = await list.Count(out var total).ToListAsync((a, b, c) => new {
                        a.MATNO,
                        b.MNAME,
                        b.SZNO,
                        a.BATCH,
                        keyong = Convert.ToDouble(a.QUANT) - Convert.ToDouble(a.QUANTOUT),
                        a.ADDRE,
                        a.PALNO,
                        a.SECTN,
                        a.CFLAG
                    });
                    pageData.total = (int)total;
                }
                else
                {
                    pageData.pageData = await list.Count(out var total).Skip((pages - 1) * limit).Take(limit).ToListAsync((a, b, c) => new {
                        a.MATNO,
                        b.MNAME,
                        b.SZNO,
                        a.BATCH,
                        keyong = Convert.ToDouble(a.QUANT) - Convert.ToDouble(a.QUANTOUT),
                        a.ADDRE,
                        a.PALNO,
                        a.SECTN,
                        a.CFLAG
                    });
                    pageData.total = (int)total;
                }
    
                return pageData;
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57

    当我们查到所有符合条件的库存信息后,把数据返回给前端。这个时候也就是当前端选中出库单点击手动配货按钮时,会弹出一个页面,也就是我们上面执行的查询结果。这个时候又操作人员来进行货位分配。例如我们要出750个A货物,然后有符合出库的8个托盘,每个托盘上有100个A物品,这个时候我们手动配货是可以选择每个托盘出多少的,比如说第一个托盘出90个,第二个托盘出80等。当配完货后会生成相对应的出库任务,那么接下来我们看一下这个业务是怎么用代码来实现的。

            [HttpPost]
            public async Task<IActionResult> QueryPeiH(List<LogMstore> logMstores)
            {
                return Ok(await _erpOutService.PeiHuo2(logMstores));
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    这个是我们的配货接口,这个时候前端会发一个list过来,写list的目的是为了把配货的数据一次性发给后端,而不是一直调用接口。
    这个时候可以看到我们调用了server层。我们来看一下server层对业务的处理。

    public async Task<ResultData> PeiHuo2(List<LogMstore> logMstores)
            {
                try
                {
                //循环list
                    LOGOUTTASK lOGOUTTASK = new LOGOUTTASK();
                    for (int i = 0; i < logMstores.Count; i++)
                    {
                        string quant = logMstores[i].QUANTOUT;
                        string palno = logMstores[i].PALNO;
                        string ordno = logMstores[i].DEMO1;
                        string itmno = logMstores[i].DEMO2;
                        string keyong = logMstores[i].DEMO3;
                        //通过订单号和行号查询出库表
                        var ErpOut = await _erpOutRepository.QueryMI(ordno, itmno);
                        //通过托盘号查询库存表
                        var OutMstore = await _mstoreRepository.QueryPalno(palno);
                        #region 赋值给出库任务做添加
                        lOGOUTTASK.ErpoutId = ErpOut.Id.ToString();
                        lOGOUTTASK.TICNO = "";
                        lOGOUTTASK.SEQNO = "";
                        lOGOUTTASK.INTASKID = OutMstore.INTASKID;
                        lOGOUTTASK.ORDNO = ordno;
                        lOGOUTTASK.ITMNO = itmno;
                        lOGOUTTASK.RECTYPE = ErpOut.RECTYPE;
                        lOGOUTTASK.MATNO = ErpOut.MATNO;
                        lOGOUTTASK.MUNIT = ErpOut.MUNIT;
                        lOGOUTTASK.QUANT = quant;
                        lOGOUTTASK.QUANT0 = keyong;
                        lOGOUTTASK.QuantQy = "0";
                        lOGOUTTASK.JIAN = ErpOut.JIAN;
                        lOGOUTTASK.STANO = "0";
                        lOGOUTTASK.ADDRESRC = OutMstore.ADDRE;
                        lOGOUTTASK.ADDREDESC = "-";
                        lOGOUTTASK.PALNO = OutMstore.PALNO;
                        lOGOUTTASK.MstoreId = OutMstore.MstoreId.ToString();
                        lOGOUTTASK.CFLAG = ErpOut.CFLAG;
                        lOGOUTTASK.BATCH = ErpOut.BATCH;
                        lOGOUTTASK.LOTNO = ErpOut.LOTNO;
                        lOGOUTTASK.CUSTOM = ErpOut.CUSTOM;
                        lOGOUTTASK.CustAddress = "-";
                        lOGOUTTASK.WORKS = "-";
                        lOGOUTTASK.STORE = ErpOut.STORE;
                        lOGOUTTASK.VCDSCR = ErpOut.VCDSCR;
                        lOGOUTTASK.PONO = ErpOut.PONO;
                        lOGOUTTASK.POITEM = ErpOut.POITEM;
                        lOGOUTTASK.STYPE = "N";
                        lOGOUTTASK.ATTACHMENT = "N";
                        lOGOUTTASK.SECTN = ErpOut.SECTN;
                        lOGOUTTASK.PRDAT = ErpOut.PRDAT;
                        lOGOUTTASK.QUDAT = ErpOut.QUDAT;
                        lOGOUTTASK.PRICE = "-";
                        lOGOUTTASK.KEEPER = "-";
                        lOGOUTTASK.PRNNO = "-";
                        lOGOUTTASK.TKDAT = DateTime.Now;
                        lOGOUTTASK.COMDAT = DateTime.Now;
                        lOGOUTTASK.IFDO = "O";
                        lOGOUTTASK.OPUSER = ErpOut.OPUSER;
                        lOGOUTTASK.USERID = "";
                        lOGOUTTASK.OutPort = "";
                        lOGOUTTASK.OutportJ = "";
                        lOGOUTTASK.Deviceno = "";
                        lOGOUTTASK.DEMO1 = ordno;
                        lOGOUTTASK.DEMO2 = itmno;
                        lOGOUTTASK.DEMO3= logMstores[i].DEMO3;
                        lOGOUTTASK.Tasktype = "N";
                        lOGOUTTASK.DEMO19 = "自建";
                        lOGOUTTASK.DEMO24 = ErpOut.DEMO24;
                        #endregion
                        if (Convert.ToDouble(OutMstore.QUANT) <Convert.ToDouble(quant))
                        {
                            throw new Exception("库存数量不足!");
                        }
                        if (await _erpOutRepository.PeiHuo(lOGOUTTASK) == 0)
                        {
                            resultData.code = 0;
                            resultData.message = "配货成功!";
                        }
                      
                    }
                }
                catch (Exception ex)
                {
                    resultData.code = 1;
                    resultData.message = ex.Message;
                }
                return resultData;
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88

    在这里面我们又调用了一层,因为这层是处理业务的,会有另外一层专门写增删改查等操作,这样的话也是为了提高代码的利用率,这也符合我们写代码的原则“高内聚,低耦合”。

            public async Task<int> PeiHuo(LOGOUTTASK lOGOUTTASK)
            {
                try
                {
                    var ErpOut = await _fsql.Select<LogErpOut>().Where(x => x.ORDNO == lOGOUTTASK.ORDNO && x.ITMNO == lOGOUTTASK.ITMNO).FirstAsync();
                    string quant0 = ErpOut.QUANT0;
                    var Pdian = await _fsql.Select<LOGSTORAGE>().Where(x => x.ADDRE == lOGOUTTASK.ADDRESRC).FirstAsync();
                    if (Pdian.PkFlag == "PK") return 6001;
                    quant0 = (Convert.ToDouble(quant0) + Convert.ToDouble(lOGOUTTASK.QUANT)).ToString();
                    _fsql.Transaction(() => {
                        //添加出库任务
                        var inrows = _fsql.Insert(lOGOUTTASK).ExecuteAffrows();
                        if (inrows <= 0) throw new Exception("出库任务添加失败!");
    
                        //var erpin = _fsql.Select().Where(x => x.Id == Convert.ToDecimal(lOGOUTTASK.ErpoutId)).First();
                        //修改出库单已配货数量
                        var uprows = _fsql.Update<LogErpOut>().Set(x =>x.QUANT0 == quant0)
                        .Set(x => x.IfDo == "O")
                        .Where(x => x.ORDNO == lOGOUTTASK.ORDNO && x.ITMNO == lOGOUTTASK.ITMNO).ExecuteAffrows();
                        if (uprows <= 0) throw new Exception("配货数量回写失败!");
                        //库存表可用数量加上
    
                    });
                    return 0;
                }
                catch (Exception ex)
                {
                    return 1;
                }
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    这里我们需要使用到事务,以防数据出现错误。手动配货的相比较自动配货来说比较简单,了解业务之后就可以一步一步的往下写。而且一般来说不会出现什么错误,只需要多注意数据的增减。例如配货成功后出库单的已配货数量,未配货数量,出库任务的出库数量,库存的剩余数量,可用数量等等。假如对这个配货还不太懂的话,可以看一下前面的文章,里面有出库的整个流程,其中对配货也有一定说明。接下来我们来说一下重点-自动配货。

    自动配货

    自动配货前端写起来比较简单,因为只需要写一个按钮就可以。自动配货相对手动配货来说第一步的查询是一样的,只不过区别是手动配货需要我们把查出来的数据返回给前端,让操作人员进行分配,然后再把分配完的数据再传给后端。自动配货的话就是我们查出来数据后,我们后端自己处理。
    在这里插入图片描述
    上面的是我初次写的自动配货,如今已弃用,下面的是优化过的。还是那么一个简简单单的接口,只需要前端给我们传一个guid,我们就去server层自己玩。说明我写在下面代码的注释里,方便大家了解流程。

    public async Task<ResultData> AutomaticPicking(string guid)
            {
                ResultData resultData = new ResultData()
                {
                    code = 0,
                    message = "success",
                };
                try
                {
                    List<LogMstore> logMstores = new List<LogMstore>();
                    var ErpOut = await _erpOutRepository.Queryguid(guid);//根据guid查询出库单
                    string quantout = ErpOut.QUANT;//出库单计划出库数量
                    string matno = ErpOut.MATNO;
                    string batch = ErpOut.BATCH;
                    string cflag = ErpOut.CFLAG;
                    //查询符合条件的库存信息
                    var logmstore = await _mstoreRepository.QueryZiDong(1, 20, matno, batch, cflag);
                    //序列化查询符合条件的库存信息
                    var json = JsonConvert.SerializeObject(logmstore.pageData, Formatting.Indented);
                    var newdynamicData = JsonConvert.DeserializeObject<List<dynamic>>(json);
                    //未配货数量 = 计划数量 - 已配货数量
                    Double UnshippedQuantity = Convert.ToDouble(ErpOut.QUANT) - Convert.ToDouble(ErpOut.QUANT0);
                    //符合条件的数据循环插入到List集合中
                    for (int i = 0; i < newdynamicData.Count; i++)
                    {
                        //如果大于0说明是整托出库,例如750个的货,每个托盘100个,那么前7个托盘就是整托出库,最后的一个托盘就是拣选出库,因为我们只需要50,剩下的50还需要再回库。
                        if((UnshippedQuantity - Convert.ToDouble(newdynamicData[i].QUANT)) >= 0)
                        {
                            UnshippedQuantity = UnshippedQuantity - Convert.ToDouble(newdynamicData[i].QUANT);
                            logMstores.Add(new LogMstore
                            {
                                ADDRE = newdynamicData[i].ADDRE,//货位地址
                                BATCH = newdynamicData[i].BATCH,//批次号
                                CFLAG = newdynamicData[i].CFLAG,
                                DEMO1 = ErpOut.ORDNO,//订单号
                                DEMO2 = ErpOut.ITMNO,//行号
                                MATNO = newdynamicData[i].MATNO,//物料编码
                                PALNO = newdynamicData[i].PALNO,
                                QUDAT = newdynamicData[i].QUDAT,
                                SECTN = newdynamicData[i].SECTN,
                                //QUANT = newdynamicData[i].QUANT //库存数量
                                QUANTOUT = newdynamicData[i].QUANT
                            });
                        }
                        else
                        {
                            
                            logMstores.Add(new LogMstore
                            {
                                ADDRE = newdynamicData[i].ADDRE,//货位地址
                                BATCH = newdynamicData[i].BATCH,//批次号
                                CFLAG = newdynamicData[i].CFLAG,
                                DEMO1 = ErpOut.ORDNO,//订单号
                                DEMO2 = ErpOut.ITMNO,//行号
                                MATNO = newdynamicData[i].MATNO,//物料编码
                                PALNO = newdynamicData[i].PALNO,
                                QUDAT = newdynamicData[i].QUDAT,
                                SECTN = newdynamicData[i].SECTN,
                                //QUANT = newdynamicData[i].QUANT //库存数量
                                QUANTOUT = UnshippedQuantity.ToString()
                            });
                            break;
                        }                   
                    }
                   await ZiDong(logMstores);//这一步和手动配货一样
                }
                catch (Exception ex)
                {
                    resultData.code = 1;
                    resultData.message = ex.Message;
                }
                return resultData;
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73

    自动配货的话一般有先入先出原则,也有随机出库原则等等,这个都是根据甲方需求来写。先入先出原则比较简单,查询的时候按时间进行排序查询结果就可以。这里我们用的也是先入先出原则。自动配货的话一般来说比较常用。

  • 相关阅读:
    基于Java毕业设计一中体育馆管理系统源码+系统+mysql+lw文档+部署软件
    在嵌入式开发中如何提高自己的代码水平
    “我将 20 年前开发的操作系统迁移到 .NET 6,居然成功了”
    Thymeleaf模板引擎
    go并发之context
    zabbix监控的部署
    c#学习系列相关之多线程(三)----invoke和begininvoke
    『现学现忘』Docker基础 — 24、Docker图形化管理工具Portainer
    item_search - 根据关键词获取义乌购商品列表
    【设计模式】一、设计模式七大原则
  • 原文地址:https://blog.csdn.net/qq_43434929/article/details/128162420