ソースを参照

feat: 优化发货单删除和保存

JaneDoe 3 ヶ月 前
コミット
d74b881404

+ 0 - 3
UniformMaterialManagementSystem/Entities/DeliveryReceipt.cs

@@ -66,9 +66,6 @@ namespace UniformMaterialManagementSystem.Entities
 
         public bool IsExportUsage { get; set; } = false;
 
-        [NotMapped]
-        public decimal? HasShippedQty { get; set; } = null;
-
         [NotMapped]
         public bool IsNewRow { get; set; } = true;
 

+ 115 - 119
UniformMaterialManagementSystem/ViewModels/DeliveryReceiptViewModel.cs

@@ -255,7 +255,7 @@ namespace UniformMaterialManagementSystem.ViewModels
             }
         }
 
-        #region 主表命令
+        #region 主表事件
 
         // CallMethodAction 不需要注册命令,可以传递事件参数。参数列表必须与事件自带的参数列表保持一致
         public void FdgDelivery_SelectionChanged(object sender, SelectionChangedEventArgs args)
@@ -342,8 +342,6 @@ namespace UniformMaterialManagementSystem.ViewModels
             CurrDeliveryReceipt.ContractQty = _selectedContractDetail.ContractQty;
             // 合同时间
             CurrDeliveryReceipt.ContractSigningDate = _selectedContract.SigningDate.Date;
-            // 已发运数量:来源于合同明细
-            CurrDeliveryReceipt.HasShippedQty = _selectedContractDetail.ShippedQuantity;
             // 接收单位
             CurrDeliveryReceipt.ReceivedCompanyName = _selectedContract.PurchaseCompany.Name;
             // 发运时间:默认当前日期
@@ -487,24 +485,7 @@ namespace UniformMaterialManagementSystem.ViewModels
             }
 
             // 反写合同数据
-            var serviceCDtl = App.Current.Services.GetService<IDataBaseService<ContractDetail>>();
-            if (serviceCDtl == null) { return; }
-            var contractDetails = serviceCDtl.Query(x => x.ContractGuid.Equals(CurrDeliveryReceipt.ContractGuid) && x.Material.Name.Equals(CurrDeliveryReceipt.ProductName))
-                                  .Include(x => x.Material);
-            if (contractDetails == null) { return; }
-            ContractDetail? contractDtl = contractDetails.FirstOrDefault();
-            if (contractDtl is null) { return; }
-            contractDtl.ShippedQuantity = CurrDeliveryReceipt.ShippedQty;
-            contractDtl.ShippedStatus = contractDtl.ShippedQuantity >= contractDtl.ContractQty; // todo 之前校验过不会超过合同数量+200,则超过合同数量就已完成
-            serviceCDtl.Update(contractDtl);
-            bool isContractSuccess = serviceCDtl.SaveChanges();
-            if (!isContractSuccess)
-            {
-                MessageBox.Show("反写合同数据失败!");
-                return;
-            }
-
-            MessageBox.Show("保存并反写成功。", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
+            UpdataContractDetail();
         }
 
         [RelayCommand]
@@ -544,7 +525,7 @@ namespace UniformMaterialManagementSystem.ViewModels
 
         #endregion
 
-        #region 子表命令
+        #region 子表事件
 
         public void FdgDeliveryDetail_SelectedCellsChanged(object sender, SelectedCellsChangedEventArgs e)
         {
@@ -566,12 +547,12 @@ namespace UniformMaterialManagementSystem.ViewModels
 
                     if (cellInfo.Column.Header.Equals("发运数量*"))
                     {
-                        // todo 保留一位小数?
-                        // 若输入的数据不是 decimal ,单元格会标红,ShippedQuantity 的值也不会更新,保存失败(暂时不管)
+                        // 若输入的数据不是 decimal ,单元格会标红,并且不允许编辑其他单元格,保存会抛出异常(数量列设置了 StringFormat)
                         // 发运数量不能为负
                         DeliveryReceiptDetail? dtl = cellInfo.Item as DeliveryReceiptDetail;
                         if (dtl?.ShippedQuantity < 0)
                         {
+                            dtl.ShippedQuantity = 0;
                             MessageBox.Show("输入的数量异常,请重新输入!");
                             return;
                         }
@@ -622,7 +603,7 @@ namespace UniformMaterialManagementSystem.ViewModels
                     }
 
                     // todo 点击两下才能勾选/取消勾选
-                    // 单击勾选/取消勾选行
+                    // 勾选/取消勾选行
                     if (cellInfo.Column is DataGridCheckBoxColumn colCheck)
                     {
                         if (cellInfo.Item is not DeliveryReceiptDetail dtl) { continue; }
@@ -685,7 +666,6 @@ namespace UniformMaterialManagementSystem.ViewModels
                 {
                     details.Remove(dtl);
                     newRowCount++;
-                    // fdgDeliveryDetail.Items.Refresh(); // 刷新索引:删除后单元格变化,不允许刷新索引
                     continue;
                 }
 
@@ -712,12 +692,21 @@ namespace UniformMaterialManagementSystem.ViewModels
                 }
             }
 
-            // 已保存行 则询问后删除
-            string msg = "";
-            if (savedRows.Count > 0)
+            // 只删除新增行,则更新数据后直接返回
+            if (savedRows.Count == 0)
             {
-                msg = "是否确定删除选中行?";
+                // 删除后更新数据
+                fdgDeliveryDetail.Items.Refresh(); // 刷新子表索引
+                CurrDeliveryReceipt.ShippedPackets = details.Count;
+                CurrDeliveryReceipt.ShippedQty = details.Select(x => x.ShippedQuantity).Sum();
+                //OnCurrDeliveryReceiptChanged(CurrDeliveryReceipt);
+                OnPropertyChanged(nameof(CurrDeliveryReceipt));
+
+                return;
             }
+
+            // 已保存行 则询问后删除
+            string msg = "是否确定删除选中行?";
             if (isModified)
             {
                 msg = msg.Insert(0, "以下数据已修改,") + hint;
@@ -725,28 +714,37 @@ namespace UniformMaterialManagementSystem.ViewModels
             MessageBoxResult result = MessageBox.Show(msg, "询问", MessageBoxButton.YesNoCancel, MessageBoxImage.Question);
             if (result != MessageBoxResult.Yes) { return; }
 
-            // todo 能成功多选删除子表吗?
             // 删除行
             foreach (DeliveryReceiptDetail dtl in savedRows)
             {
                 // 界面删除
                 details.Remove(dtl);
-                fdgDeliveryDetail.Items.Refresh(); // 刷新索引
                 // 数据库删除
                 serviceDtl?.Delete(dtl);
             }
 
+            // 删除成功后更新数据
+            fdgDeliveryDetail.Items.Refresh();
+            CurrDeliveryReceipt.ShippedPackets = details.Count;
+            CurrDeliveryReceipt.ShippedQty = details.Select(x => x.ShippedQuantity).Sum();
+            //OnCurrDeliveryReceiptChanged(CurrDeliveryReceipt);
+            OnPropertyChanged(nameof(CurrDeliveryReceipt));
+
             // 保存到数据库
+            bool isMainSuccess = _service?.SaveChanges() ?? false;
             bool isSuccess = serviceDtl?.SaveChanges() ?? false;
-            if (!isSuccess)
+            if (!isMainSuccess)
             {
                 // 删除失败提示
                 MessageBox.Show("删除失败!", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
+                return;
             }
-            else
-            {
-                MessageBox.Show($"删除 {savedRows.Count} 行。");
-            }
+
+            // 删除成功提示
+            MessageBox.Show($"删除 {savedRows.Count} 行已保存行。");
+
+            // 反写合同
+            UpdataContractDetail();
         }
 
         [RelayCommand]
@@ -762,17 +760,6 @@ namespace UniformMaterialManagementSystem.ViewModels
                 return;
             }
 
-            //// 删除新增的空行
-            //DeleteEmptyRows();
-
-            //// 若子表中存在未保存的行,则不允许导入
-            //var newRows = CurrDeliveryReceipt.DeliveryReceiptDetails.Where(x => x.IsNewRow);
-            //if (newRows.Any())
-            //{
-            //    MessageBox.Show("存在未保存的行,请保存后导入。");
-            //    return;
-            //}
-
             // 询问
             if (CurrDeliveryReceipt.DeliveryReceiptDetails.Count > 0)
             {
@@ -996,26 +983,19 @@ namespace UniformMaterialManagementSystem.ViewModels
                 return;
             }
 
-            // 校验发货数量:每一条批号对应一条检验申请,一个发货单对应一条合同明细,合同的剩余数量对应合同明细的已发货数量
+            // 校验发货数量:不能超出 合同明细已发货数量 + 200
             decimal importQty = importRows.Select(x => x.ShippedQuantity).Sum();
             decimal contractQty = CurrDeliveryReceipt.ContractQty;
-            decimal hasShippedQty = CurrDeliveryReceipt.HasShippedQty ?? 0;
-            decimal remainQty = contractQty - hasShippedQty;
-            bool isShipComplete = false;
-            if (importQty > remainQty + _tolerance) // 导入时校验,发运数量必须为可转换为 decimal 且 > 0 
+            decimal hasShippedQty = _service.Query(x => x.ProductName.Equals(CurrDeliveryReceipt!.ProductName) && x.ContractNo.Equals(CurrDeliveryReceipt.ContractNo) && !x.Guid.Equals(CurrDeliveryReceipt.Guid))
+                                    .Select(x => x.ShippedQty)
+                                    .ToList()
+                                    .Sum();
+            decimal currRemainQty = contractQty - hasShippedQty;
+            if (importQty > currRemainQty + _tolerance)
             {
                 MessageBox.Show($"导入的发货数量超出合同数量,请修改后重新导入!");
                 return;
             }
-            else if (importQty <= remainQty + _tolerance && importQty >= remainQty)
-            {
-                // 判断是否发货完成
-                isShipComplete = true;
-            }
-            else if (importQty < remainQty)
-            {
-                isShipComplete = false;
-            }
 
             // 清空子表数据
             foreach (var dtl in CurrDeliveryReceipt.DeliveryReceiptDetails)
@@ -1048,26 +1028,10 @@ namespace UniformMaterialManagementSystem.ViewModels
                 return;
             }
 
-            // 反写合同数据
-            var serviceCDtl = App.Current.Services.GetService<IDataBaseService<ContractDetail>>();
-            if (serviceCDtl == null) { return; }
-            var contractDetails = serviceCDtl.Query(x => x.ContractGuid.Equals(CurrDeliveryReceipt.ContractGuid) && x.Material.Name.Equals(CurrDeliveryReceipt.ProductName))
-                                  .Include(x => x.Material);
-            if (contractDetails == null) { return; }
-            ContractDetail? contractDtl = contractDetails.FirstOrDefault();
-            if (contractDtl is null) { return; }
-            // todo 其他发货单有发货数量时?
-            contractDtl.ShippedQuantity = CurrDeliveryReceipt.ShippedQty;
-            contractDtl.ShippedStatus = isShipComplete;
-            serviceCDtl.Update(contractDtl);
-            bool isContractSuccess = serviceCDtl.SaveChanges();
-            if (!isContractSuccess)
-            {
-                MessageBox.Show("反写合同数据失败!");
-                return;
-            }
+            MessageBox.Show($"成功导入 {importRows.Count} 行。" + batchErrMsg + packNoMsg);
 
-            MessageBox.Show($"成功导入 {importRows.Count} 行,并反写合同数据。" + batchErrMsg + packNoMsg);
+            // 反写合同数据
+            UpdataContractDetail();
         }
 
         [RelayCommand]
@@ -1138,6 +1102,8 @@ namespace UniformMaterialManagementSystem.ViewModels
 
         #endregion
 
+        #region 私有方法
+
         /// <summary>
         /// 加载发货单数据
         /// </summary>
@@ -1154,18 +1120,6 @@ namespace UniformMaterialManagementSystem.ViewModels
                 // 是否为新行:否
                 delivery.IsNewRow = false;
 
-                // 已发货数量:合同明细的已发货数量
-                string contractNo = delivery.ContractNo;
-                string productName = delivery.ProductName;
-                var contractDetails = App.Current.Services.GetService<IDataBaseService<ContractDetail>>()?.Query(x => x.Contract.ContractNo.Equals(contractNo) && x.Material.Name.Equals(productName))
-                    .Include(x => x.Contract)
-                    .Include(x => x.Material);
-                if (contractDetails != null && contractDetails.Any())
-                {
-                    ContractDetail? dtl = contractDetails.FirstOrDefault();
-                    delivery.HasShippedQty = dtl?.ShippedQuantity;
-                }
-
                 // 子表明细行
                 var details = delivery.DeliveryReceiptDetails.OrderBy(x => x.PacketNo).ToArray();
                 foreach (DeliveryReceiptDetail dtl in details)
@@ -1236,8 +1190,8 @@ namespace UniformMaterialManagementSystem.ViewModels
         {
             if (CurrDeliveryReceipt == null || CurrDeliveryReceipt.DeliveryReceiptDetails == null) { return; }
 
-            // 删除子表的新增空行
-            var emptyRows = CurrDeliveryReceipt.DeliveryReceiptDetails.Where(x => x.IsNewRow && string.IsNullOrEmpty(x.PacketNo) && x.ShippedQuantity == 0);
+            // 删除子表的新增空行:发运数量为空的行
+            var emptyRows = CurrDeliveryReceipt.DeliveryReceiptDetails.Where(x => x.IsNewRow && string.IsNullOrEmpty(x.BatchNo) && string.IsNullOrEmpty(x.PacketNo) && x.ShippedQuantity == 0);
             if (emptyRows.Any())
             {
                 for (int i = emptyRows.Count() - 1; i >= 0; i--)
@@ -1380,8 +1334,8 @@ namespace UniformMaterialManagementSystem.ViewModels
         private bool VerifyDelivery(DatePicker datePicker)
         {
             // 检查主表必录项
-            // todo 清空日期选择框,但 发运日期 并不会清空
-            if (string.IsNullOrWhiteSpace(datePicker.Text)) // DateTime 类型永远不等于 null
+
+            if (string.IsNullOrWhiteSpace(datePicker.Text)) // 清空日期选择框,但 发运日期 并不会清空,判断控件的文本
             {
                 MessageBox.Show("发运时间为空,不允许保存!");
                 return false;
@@ -1411,33 +1365,31 @@ namespace UniformMaterialManagementSystem.ViewModels
                 return false;
             }
 
-            // todo 子表新增行和删除行和修改列时实时计算
-            // 计算发运包数和发运数量
-            int packNum = CurrDeliveryReceipt.DeliveryReceiptDetails.Count;
-            CurrDeliveryReceipt.ShippedPackets = packNum;
-            decimal shippedQty = CurrDeliveryReceipt.DeliveryReceiptDetails.Select(x => x.ShippedQuantity).Sum();
-            CurrDeliveryReceipt.ShippedQty = shippedQty;
-
-            // 检查发运数量不能超出可发运数量
-            //if (CurrDeliveryReceipt.ShippedQty >= CurrDeliveryReceipt.RemainQty)
-            //{
-            //    MessageBox.Show("发货数量超出可发运数量,请检查数据后重新保存!");
-            //    return false;
-            //}
-
-            // 检查子表的包号不允许重复
-            // 保存时检查材料名称是否存在重复项
-            var repeatPacketNos = CurrDeliveryReceipt.DeliveryReceiptDetails.GroupBy(x => x.PacketNo).Where(g => g.Count() > 1).Select(g => g.Key);
-            if (repeatPacketNos.Any())
+            // 保存时检查材料批号和包号不允许重复
+            var repeatNos = CurrDeliveryReceipt.DeliveryReceiptDetails.GroupBy(x => new { BatchNo = x.BatchNo, PacketNo = x.PacketNo }).Where(g => g.Count() > 1).Select(g => g.Key);
+            if (repeatNos.Any())
             {
                 // 若存在重复项则提示后返回
-                string repeatPacketNoText = string.Join("、", repeatPacketNos.ToArray());
-                MessageBox.Show("包号列存在以下重复值,请修改后保存:" + repeatPacketNoText, "错误", MessageBoxButton.OK, MessageBoxImage.Error);
+                StringBuilder nos = new StringBuilder();
+                foreach (var g in repeatNos)
+                {
+                    nos.AppendLine($"材料批号 [{g.BatchNo}],包号 [{g.PacketNo}]");
+                }
+                MessageBox.Show("材料批号和包号存在以下重复值,请修改后保存:" + nos, "错误", MessageBoxButton.OK, MessageBoxImage.Error);
                 return false;
             }
 
-            // todo 批号和包号必须存在,发运数量<合同数量
-            // todo 保留1位小数?
+            // 检查发运数量不能超出可发运数量
+            decimal hasShippedQty = _service.Query(x => x.ProductName.Equals(CurrDeliveryReceipt!.ProductName) && x.ContractNo.Equals(CurrDeliveryReceipt.ContractNo) && !x.Guid.Equals(CurrDeliveryReceipt.Guid)).Select(x => x.ShippedQty)
+                                    .ToList() // 必须转换为 List<decimal> 才不抛异常
+                                    .Sum();
+            decimal currQty = CurrDeliveryReceipt.ShippedQty;
+            decimal currRemainQty = CurrDeliveryReceipt.ContractQty - hasShippedQty;
+            if (currQty > currRemainQty + _tolerance)
+            {
+                MessageBox.Show("发货数量超出可发运数量,请检查数据后重新保存!");
+                return false;
+            }
 
             return true;
         }
@@ -1484,6 +1436,50 @@ namespace UniformMaterialManagementSystem.ViewModels
 
             return true;
         }
+
+        /// <summary>
+        /// 反写合同明细
+        /// </summary>
+        /// <returns></returns>
+        private void UpdataContractDetail()
+        {
+            // 反写合同明细
+            var serviceCD = App.Current.Services.GetService<IDataBaseService<ContractDetail>>();
+            if (serviceCD == null) { return; }
+            var contractDetails = serviceCD.Query(x => x.ContractGuid.Equals(CurrDeliveryReceipt!.ContractGuid) && x.Material.Name.Equals(CurrDeliveryReceipt.ProductName))
+                                  .Include(x => x.Material);
+            if (contractDetails == null || !contractDetails.Any())
+            {
+                MessageBox.Show("获取对应的合同明细失败!");
+                return;
+            }
+
+            // 更新发货数量
+            ContractDetail? contractDtl = contractDetails.FirstOrDefault();
+            if (contractDtl == null) { return; }
+            // 除了本单
+            decimal hasShippedQty = _service.Query(x => x.ProductName.Equals(CurrDeliveryReceipt!.ProductName) && x.ContractNo.Equals(CurrDeliveryReceipt.ContractNo) && !x.Guid.Equals(CurrDeliveryReceipt.Guid))
+                                    .Select(x => x.ShippedQty)
+                                    .ToList()
+                                    .Sum();
+            contractDtl.ShippedQuantity = hasShippedQty + CurrDeliveryReceipt!.ShippedQty;
+            // 保存、导入时会校验数量,删除时不会超出数量,所以不用再次校验
+            contractDtl.ShippedStatus = CurrDeliveryReceipt!.ShippedQty >= contractDtl.ContractQty;
+
+            // 保存到数据库
+            serviceCD.Update(contractDtl);
+            bool isContractSuccess = serviceCD.SaveChanges();
+            if (!isContractSuccess)
+            {
+                MessageBox.Show("反写合同明细失败!");
+                return;
+            }
+
+            MessageBox.Show("反写合同明细成功。");
+            return;
+        }
+
+        #endregion
     }
 
     /// <summary>

+ 3 - 3
UniformMaterialManagementSystem/Views/DeliveryReceiptControl.xaml

@@ -835,15 +835,15 @@
                 <fdg:FilterDataGridTextColumn Header="发运数量" Width="100"
                                               ElementStyle="{StaticResource TextColumnElementStyle}"
                                               EditingElementStyle="{StaticResource TextColumnEditingStyle}"
-                                              Binding="{Binding ShippedQuantity, UpdateSourceTrigger=PropertyChanged}" />
+                                              Binding="{Binding ShippedQuantity, UpdateSourceTrigger=PropertyChanged, StringFormat='#0.0'}" />
                 <fdg:FilterDataGridTextColumn Header="接收数量" Width="100"
                                               ElementStyle="{StaticResource TextColumnElementStyle}"
                                               EditingElementStyle="{StaticResource TextColumnEditingStyle}"
-                                              Binding="{Binding ReceiveQuantity, UpdateSourceTrigger=PropertyChanged}" />
+                                              Binding="{Binding ReceiveQuantity, UpdateSourceTrigger=PropertyChanged, StringFormat='#0.0'}" />
                 <fdg:FilterDataGridTextColumn Header="使用数量" Width="100"
                                               ElementStyle="{StaticResource TextColumnElementStyle}"
                                               EditingElementStyle="{StaticResource TextColumnEditingStyle}"
-                                              Binding="{Binding UsageQuantity, UpdateSourceTrigger=PropertyChanged}" />
+                                              Binding="{Binding UsageQuantity, UpdateSourceTrigger=PropertyChanged, StringFormat='#0.0'}" />
                 <fdg:FilterDataGridTextColumn Header="使用状态" Width="100"
                                               ElementStyle="{StaticResource TextColumnElementStyle}"
                                               EditingElementStyle="{StaticResource TextColumnEditingStyle}"