소스 검색

fix: 修改删除问题,优化导出

JaneDoe 2 달 전
부모
커밋
f6e5d8b9a8

+ 237 - 64
UniformMaterialManagementSystem/ViewModels/DeliveryReceiptViewModel.cs

@@ -3,6 +3,7 @@ using System.Collections.Generic;
 using System.Collections.ObjectModel;
 using System.ComponentModel;
 using System.Data;
+using System.Dynamic;
 using System.Linq;
 using System.Reflection;
 using System.Reflection.Metadata.Ecma335;
@@ -16,12 +17,16 @@ using CommunityToolkit.Mvvm.ComponentModel;
 using CommunityToolkit.Mvvm.Input;
 using DocumentFormat.OpenXml.Drawing;
 using DocumentFormat.OpenXml.Drawing.Charts;
+using DocumentFormat.OpenXml.InkML;
 using DocumentFormat.OpenXml.Office2016.Drawing.ChartDrawing;
 using DocumentFormat.OpenXml.Spreadsheet;
+using DocumentFormat.OpenXml.Vml.Office;
 using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.ChangeTracking;
 using Microsoft.Extensions.DependencyInjection;
 using Microsoft.Win32;
 using UniformMaterialManagementSystem.Custom;
+using UniformMaterialManagementSystem.Data;
 using UniformMaterialManagementSystem.Entities;
 using UniformMaterialManagementSystem.Models;
 using UniformMaterialManagementSystem.Services;
@@ -37,9 +42,6 @@ namespace UniformMaterialManagementSystem.ViewModels
         [ObservableProperty]
         private ObservableCollection<DeliveryReceipt> _deliveryReceipts = [];
 
-        [ObservableProperty]
-        private ObservableCollection<DeliveryReceiptDetail> _deliveryDetails = [];
-
         [ObservableProperty]
         private DeliveryReceipt? _currDeliveryReceipt = null;
 
@@ -283,7 +285,7 @@ namespace UniformMaterialManagementSystem.ViewModels
                 if (isChanged)
                 {
                     // 询问是否切换
-                    MessageBoxResult res = MessageBox.Show("当前行已修改,切换行会丢失已修改的数据,是否确认切换行?", "询问", MessageBoxButton.YesNoCancel, MessageBoxImage.Question);
+                    MessageBoxResult res = MessageBox.Show("当前行已修改未保存,是否确认切换行?", "询问", MessageBoxButton.YesNoCancel, MessageBoxImage.Question);
                     // 不切换:重新赋值为切换前的行
                     if (res != MessageBoxResult.Yes)
                     {
@@ -312,6 +314,16 @@ namespace UniformMaterialManagementSystem.ViewModels
             _isExcute = true;
         }
 
+        [RelayCommand]
+        public void DeliverySelectionChanged(DeliveryReceiptControl page)
+        {
+            if (CurrDeliveryReceipt == null) { return; }
+
+            // 已导出数据包的行不允许编辑
+            page.fieldShippedMan.IsEnabled = page.fieldShippedTel.IsEnabled = page.dpShippedDate.IsEnabled = !CurrDeliveryReceipt.IsExportDelivery;
+            page.fdgDeliveryDetail.IsEnabled = !CurrDeliveryReceipt.IsExportDelivery;
+        }
+
         [RelayCommand]
         public void AddDelivery()
         {
@@ -360,6 +372,7 @@ namespace UniformMaterialManagementSystem.ViewModels
         [RelayCommand]
         public void DeleteDelivery(DataGrid fdgDelivery)
         {
+            // todo 删除时删除当前行
             // 没有选中行直接删除
             if (CurrDeliveryReceipt == null)
             {
@@ -393,30 +406,31 @@ namespace UniformMaterialManagementSystem.ViewModels
                 {
                     return;
                 }
+            }
 
-                // 界面删除
-                DeliveryReceipts.Remove(CurrDeliveryReceipt);
-
-                // todo 删除后反写到数据库
+            // 界面删除
+            string currContracNo = CurrDeliveryReceipt.ContractNo;
+            string currProductName = CurrDeliveryReceipt.ProductName;
+            DeliveryReceipts.Remove(CurrDeliveryReceipt);
 
-                // 保存到数据库
-                _service.Delete(CurrDeliveryReceipt);
-                bool isSuccess = _service.SaveChanges();
-                if (isSuccess)
-                {
-                    MessageBox.Show("删除成功");
-                }
-                else
-                {
-                    MessageBox.Show("删除失败!");
-                }
+            // 保存到数据库
+            _service.Delete(CurrDeliveryReceipt);
+            bool isSuccess = _service.SaveChanges();
+            if (!isSuccess)
+            {
+                MessageBox.Show("删除失败!");
+                return;
             }
+
+            MessageBox.Show("删除成功");
+
+            // 删除后反写到数据库
+            UpdataContractDetail(currContracNo, currProductName);
         }
 
         [RelayCommand]
         public void Save(DeliveryReceiptControl page)
         {
-            // 未选择行或者当前行已导出,直接返回
             if (CurrDeliveryReceipt == null) { return; }
             if (CurrDeliveryReceipt.IsExportDelivery || CurrDeliveryReceipt.IsExportReceive || CurrDeliveryReceipt.IsExportUsage) { return; }
 
@@ -428,7 +442,7 @@ namespace UniformMaterialManagementSystem.ViewModels
             switch (_deliveryPageCategroy)
             {
                 case DeliveryPageCategroy.Delivery:
-                    canSave = VerifyDelivery(page.dpShippedDate);
+                    canSave = VerifyDelivery(page);
                     break;
                 case DeliveryPageCategroy.Receipt:
                     canSave = VerifyReceipt();
@@ -445,9 +459,11 @@ namespace UniformMaterialManagementSystem.ViewModels
             }
 
             // 保存到数据库
+            bool isNeedRewrite = false;
             var serviceDtl = App.Current.Services.GetService<IDataBaseService<DeliveryReceiptDetail>>();
             if (CurrDeliveryReceipt.IsNewRow)
             {
+                isNeedRewrite = true;
                 // 新增行插入到数据库
                 CurrDeliveryReceipt.IsNewRow = false;
                 _service.Insert(CurrDeliveryReceipt);
@@ -460,8 +476,17 @@ namespace UniformMaterialManagementSystem.ViewModels
             }
             else
             {
+                // 判断已保存的行是否需要反写
+                SqliteContext? context = App.Current.Services.GetService<SqliteContext>();
+                if (context == null) { return; }
+                EntityEntry? entry = context.Entry(CurrDeliveryReceipt);
+                var modifiedProperties = entry.CurrentValues.Properties
+                                        .Where(p => entry.Property(p.Name).IsModified)
+                                        .Select(p => p.Name)
+                                        .ToList();
+                isNeedRewrite = modifiedProperties.Contains("ShippedPackets") || modifiedProperties.Contains("ShippedQty");
+
                 // 已保存行更新到数据库
-                // todo 主表已保存,但子表明细 新增/删除/修改 怎么保存
                 _service.Update(CurrDeliveryReceipt);
 
                 foreach (DeliveryReceiptDetail dtl in CurrDeliveryReceipt.DeliveryReceiptDetails)
@@ -487,9 +512,13 @@ namespace UniformMaterialManagementSystem.ViewModels
                 MessageBox.Show("数据库保存失败!", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
                 return;
             }
+            MessageBox.Show("当前行保存成功。");
 
             // 反写合同数据
-            UpdataContractDetail();
+            if (isNeedRewrite)
+            {
+                UpdataContractDetail(CurrDeliveryReceipt.ContractNo, CurrDeliveryReceipt.ProductName);
+            }
         }
 
         [RelayCommand]
@@ -540,19 +569,50 @@ namespace UniformMaterialManagementSystem.ViewModels
         }
 
         [RelayCommand]
-        public void ExportDB()
+        public void ExportDB(DataGrid fdgDelivery)
         {
-            if (CurrDeliveryReceipt != null)
+            // 检查选中行是否未保存
+            List<DeliveryReceipt> selectedDeliveries = new List<DeliveryReceipt>();
+            foreach (DeliveryReceipt delivery in DeliveryReceipts)
             {
-                bool isChanged = IsChanged(CurrDeliveryReceipt);
+                if (!delivery.IsSelected) { continue; }
+
+                // 跳过已导出的行
+                if (delivery.IsExportDelivery) { continue; }
+
+                bool isChanged = IsChanged(delivery);
                 if (isChanged)
                 {
-                    MessageBox.Show("当前发货单未保存,请保存后导出数据包!");
+                    MessageBox.Show($"发货单 [{delivery.ContractNo}, {delivery.ProductName}] 未保存,请保存后重试!");
+                    return;
                 }
+
+                selectedDeliveries.Add(delivery);
             }
 
-            // 需要存在 bin\DataBase 目录,且目录下存在一份 .db 文件,需要存在表
+            if (selectedDeliveries.Count == 0)
+            {
+                MessageBox.Show("当前未选择未导出的行,请选择后重试!");
+                return;
+            }
 
+            // 清空当前行(实现导出后不允许编辑)
+            CurrDeliveryReceipt = null;
+
+            // 设置为已导出
+            foreach (var delivery in selectedDeliveries)
+            {
+                delivery.IsExportDelivery = true;
+                _service.Update(delivery);
+            }
+            bool isSuccess = _service.SaveChanges();
+            if (!isSuccess)
+            {
+                MessageBox.Show("更新发货单导出状态失败,请重试!");
+                return;
+            }
+
+            // 需要存在 bin\DataBase 目录,且目录下存在一份 .db 文件,需要存在表
             // 导出主表到 bin\DataBase 目录下的 .db:根据主键判断,存在数据则更新,不存在则插入
             var deliveries = DeliveryReceipts;
             DataBaseUtil.ExportTable(deliveries, "DeliveryReceipts"); // 数据库表名输错会抛出异常,但在本方法里获取不到抛出异常
@@ -582,6 +642,7 @@ namespace UniformMaterialManagementSystem.ViewModels
                 if (isChanged)
                 {
                     MessageBox.Show("当前发货单未保存,请保存后导入数据包!");
+                    return;
                 }
             }
 
@@ -626,26 +687,35 @@ namespace UniformMaterialManagementSystem.ViewModels
                 // 如果编辑的列是发运数量/接收数量/使用数量,自动汇总至主表 更新使用状态
                 foreach (DataGridCellInfo cellInfo in e.RemovedCells)
                 {
+                    // 删除行时为 null
+                    if (!cellInfo.IsValid) { continue; }
                     if (cellInfo.Column == null || cellInfo.Column.Header == null)
                     {
-                        // DataGridCellInfo 类型的值永不等于 null
-                        continue;  // 删除行时为 null
+                        MessageBox.Show("IsValid 为 true 但 Column 为空");
+                        continue;
                     }
 
                     if (cellInfo.Column.Header.Equals("发运数量*"))
                     {
-                        // 若输入的数据不是 decimal ,单元格会标红,并且不允许编辑其他单元格,保存会抛出异常(数量列设置了 StringFormat)
-                        // 发运数量不能为负
+                        // 输入数据不能转化为 decimal 时单元格标红,不能切换单元格
+                        // 发运数量不能为负(跟合同数量对比需要数据库取数,太耗资源,单元格切换时不校验)
                         DeliveryReceiptDetail? dtl = cellInfo.Item as DeliveryReceiptDetail;
-                        if (dtl?.ShippedQuantity < 0)
+                        if (dtl == null) { continue; }
+                        if (dtl.ShippedQuantity < 0)
                         {
                             dtl.ShippedQuantity = 0;
+                            fdgDeliveryDetail.Items.Refresh();
                             MessageBox.Show("输入的数量异常,请重新输入!");
                             return;
                         }
 
                         // 汇总大于 0 的行
-                        SummaryDeliveryDetail();
+                        dtl.ShippedQuantity = Math.Round(dtl.ShippedQuantity, 1); // 虽然显示文本自动格式化为1位小数,但字段值还是多位小数,转化为1位小数
+                        ObservableCollection<DeliveryReceiptDetail> details = CurrDeliveryReceipt!.DeliveryReceiptDetails;
+                        int deliCount = details.Where(x => x.ShippedQuantity > 0).Count();
+                        CurrDeliveryReceipt.ShippedPackets = deliCount;
+                        decimal deliQty = details.Where(x => x.ShippedQuantity > 0).Select(x => x.ShippedQuantity).Sum();
+                        CurrDeliveryReceipt.ShippedQty = deliQty;
                     }
                     else if (cellInfo.Column.Header.Equals("接收数量*"))
                     {
@@ -671,10 +741,10 @@ namespace UniformMaterialManagementSystem.ViewModels
                 }
 
                 // 手动触发值更新事件:此时没有切换焦点,不会自动触发更新
-                OnPropertyChanged(new PropertyChangedEventArgs(nameof(CurrDeliveryReceipt)));
+                OnPropertyChanged(nameof(CurrDeliveryReceipt));
             }
 
-            // 单元格切换时,Added 里的是新单元格;Removed是旧单元格
+            // 新单元格
             if (e.AddedCells.Count > 0)
             {
                 foreach (DataGridCellInfo cellInfo in e.AddedCells)
@@ -682,26 +752,19 @@ namespace UniformMaterialManagementSystem.ViewModels
                     // 进入单元格时自动进入编辑状态
                     fdgDeliveryDetail.BeginEdit();
 
-                    // todo IsValid ?
-                    if (cellInfo.IsValid) { }
-                    if (cellInfo.Column == null)
-                    {
-                        continue;
-                    }
-
-                    // todo 点击两下才能勾选/取消勾选
                     // 勾选/取消勾选行
                     if (cellInfo.Column is DataGridCheckBoxColumn colCheck)
                     {
                         if (cellInfo.Item is not DeliveryReceiptDetail dtl) { continue; }
                         dtl.IsSelected = !dtl.IsSelected;
+                        fdgDeliveryDetail.CommitEdit(); // 提交编辑前台更新勾选
                     }
                 }
             }
         }
 
         [RelayCommand]
-        public void AddDetail()
+        public void AddDetail(DataGrid fdgDeliveryDetail)
         {
             // 若当前主表行为空,则直接返回
             if (CurrDeliveryReceipt == null) { return; }
@@ -713,11 +776,12 @@ namespace UniformMaterialManagementSystem.ViewModels
                 return;
             }
 
+            // 子表提交编辑
+            fdgDeliveryDetail.CommitEdit();
+            fdgDeliveryDetail.UnselectAllCells();
+
             // 新增一行子表
             DeliveryReceiptDetail detail = new();
-            //DeliveryDetails.Add(detail);
-            // 当前子表数据绑定到主表
-            // todo 主表行切换子表展示数据清空(但保存在主表中)
             CurrDeliveryReceipt!.DeliveryReceiptDetails.Add(detail);
         }
 
@@ -734,11 +798,14 @@ namespace UniformMaterialManagementSystem.ViewModels
                 return;
             }
 
-            ObservableCollection<DeliveryReceiptDetail> details = CurrDeliveryReceipt.DeliveryReceiptDetails;
-            // 没选中行则提示后返回
+            // 子表提交编辑
+            fdgDeliveryDetail.CommitEdit();
+            fdgDeliveryDetail.UnselectAllCells();
 
+            // 没选中行则提示后返回
+            ObservableCollection<DeliveryReceiptDetail> details = CurrDeliveryReceipt.DeliveryReceiptDetails;
             var serviceDtl = App.Current.Services.GetService<IDataBaseService<DeliveryReceiptDetail>>();
-            int newRowCount = 0;
+            int selectedCount = 0;
             StringBuilder hint = new StringBuilder();
             List<DeliveryReceiptDetail> savedRows = [];
             bool isModified = false;
@@ -748,11 +815,12 @@ namespace UniformMaterialManagementSystem.ViewModels
                 DeliveryReceiptDetail dtl = details[i];
                 if (!dtl.IsSelected) { continue; }
 
+                selectedCount++;
+
                 // 新增行直接删除
                 if (dtl.IsNewRow)
                 {
                     details.Remove(dtl);
-                    newRowCount++;
                     continue;
                 }
 
@@ -779,15 +847,16 @@ namespace UniformMaterialManagementSystem.ViewModels
                 }
             }
 
+            if (selectedCount == 0) { return; }
+
             // 只删除新增行,则更新数据后直接返回
             if (savedRows.Count == 0)
             {
                 // 删除后更新数据
-                fdgDeliveryDetail.Items.Refresh(); // 刷新子表索引
                 CurrDeliveryReceipt.ShippedPackets = details.Count;
                 CurrDeliveryReceipt.ShippedQty = details.Select(x => x.ShippedQuantity).Sum();
-                //OnCurrDeliveryReceiptChanged(CurrDeliveryReceipt);
                 OnPropertyChanged(nameof(CurrDeliveryReceipt));
+                fdgDeliveryDetail.Items.Refresh(); // 刷新子表索引
 
                 return;
             }
@@ -831,7 +900,7 @@ namespace UniformMaterialManagementSystem.ViewModels
             MessageBox.Show($"删除 {savedRows.Count} 行已保存行。");
 
             // 反写合同
-            UpdataContractDetail();
+            UpdataContractDetail(CurrDeliveryReceipt.ContractNo, CurrDeliveryReceipt.ProductName);
         }
 
         [RelayCommand]
@@ -1118,7 +1187,7 @@ namespace UniformMaterialManagementSystem.ViewModels
             MessageBox.Show($"成功导入 {importRows.Count} 行。" + batchErrMsg + packNoMsg);
 
             // 反写合同数据
-            UpdataContractDetail();
+            UpdataContractDetail(CurrDeliveryReceipt.ContractNo, CurrDeliveryReceipt.ProductName);
         }
 
         [RelayCommand]
@@ -1418,11 +1487,15 @@ namespace UniformMaterialManagementSystem.ViewModels
         /// <summary>
         /// 发货单保存校验
         /// </summary>
-        private bool VerifyDelivery(DatePicker datePicker)
+        private bool VerifyDelivery(DeliveryReceiptControl page)
         {
-            // 检查主表必录项
+            // 提交编辑
+            page.fdgDelivery.Focus(); // 主表字段提交编辑
+            page.fdgDeliveryDetail.CommitEdit();
+            page.fdgDeliveryDetail.UnselectAllCells();
 
-            if (string.IsNullOrWhiteSpace(datePicker.Text)) // 清空日期选择框,但 发运日期 并不会清空,判断控件的文本
+            // 检查主表必录项
+            if (string.IsNullOrWhiteSpace(page.dpShippedDate.Text)) // 清空日期选择框,但 发运日期 并不会清空,判断控件的文本
             {
                 MessageBox.Show("发运时间为空,不允许保存!");
                 return false;
@@ -1452,6 +1525,36 @@ namespace UniformMaterialManagementSystem.ViewModels
                 return false;
             }
 
+            // 检查发运数量列是否存在非数值型的值:防止输入异常数据后直接点保存按钮
+            foreach (var dtl in page.fdgDeliveryDetail.Items)
+            {
+                DataGridRow? row = page.fdgDeliveryDetail.ItemContainerGenerator.ContainerFromItem(dtl) as DataGridRow;
+                if (row == null) { continue; }
+
+                DataGridColumn? col = page.fdgDeliveryDetail.Columns.Where(x => x.Header.Equals("发运数量*")).FirstOrDefault() as DataGridColumn;
+                if (col == null) { continue; }
+
+                var cell = page.fdgDeliveryDetail.Columns[col.DisplayIndex].GetCellContent(row)?.Parent as DataGridCell;
+                if (cell == null) { continue; }
+                string cellValue = "";
+                if (cell.Content is TextBox textBox)
+                {
+                    cellValue = textBox.Text;
+                }
+                else if (cell.Content is TextBlock textBlock)
+                {
+                    cellValue = textBlock.Text;
+                }
+
+                bool isValid = decimal.TryParse(cellValue, out var decimalValue);
+                // bool hasError = Validation.GetHasError(cell); // 获取不到错误
+                if (!isValid)
+                {
+                    MessageBox.Show("发运数量列存在异常数据,请修改后重试!");
+                    return false;
+                }
+            }
+
             // 保存时检查材料批号和包号不允许重复
             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())
@@ -1466,6 +1569,63 @@ namespace UniformMaterialManagementSystem.ViewModels
                 return false;
             }
 
+            // 检查批号和包号是否存在
+            string productName = CurrDeliveryReceipt.ProductName;
+            string companyName = CurrDeliveryReceipt.CompanyName;
+            Dictionary<string, int> errBatchNos = [];
+            StringBuilder batchNoMsg = new StringBuilder();
+            StringBuilder packNoMsg = new StringBuilder();
+            InspectApply? apply = null;
+            foreach (var dtl in CurrDeliveryReceipt.DeliveryReceiptDetails)
+            {
+                // 根据生产企业、产品名称、材料批号从数据库查询检验申请
+                string batchNo = dtl.BatchNo;
+                var applies = App.Current.Services.GetService<IDataBaseService<InspectApply>>()?.Query(x => x.Company.Equals(companyName) && x.ProductName.Equals(productName) && x.BatchNo.Equals(batchNo))
+                    .Include(x => x.InspectApplyDetails);
+                if (applies == null) { continue; }
+                int count = applies.Count();
+                if (count != 1)
+                {
+                    if (!errBatchNos.ContainsKey(batchNo))
+                    {
+                        errBatchNos.Add(batchNo, count);
+                        batchNoMsg.Append($"材料批号 [{batchNo}] 对应着 [{count}] 条检验申请");
+                    }
+                    continue;
+                }
+                else
+                {
+                    apply = applies.FirstOrDefault();
+                }
+
+                // 判断导入的行是否存在对应的检验申请明细
+                string? importPackNo = dtl.PacketNo;
+                var packApplyDetails = apply!.InspectApplyDetails.Where(x => x.PacketNo.Equals(importPackNo));
+                if (!packApplyDetails.Any())
+                {
+                    packNoMsg.AppendLine($"材料批号 [{importPackNo}] ,包号 [{importPackNo}] (对应检验申请 [{apply.ApplyNo}])");
+                    continue;
+                }
+            }
+
+            // 拼接导入异常信息
+            StringBuilder hint = new StringBuilder();
+            if (errBatchNos.Count > 0)
+            {
+                batchNoMsg = batchNoMsg.Insert(0, "以下材料批号数据异常,请检查数据后保存!\n");
+                hint.AppendLine(batchNoMsg.ToString());
+            }
+            if (packNoMsg.Length > 0)
+            {
+                packNoMsg = packNoMsg.Insert(0, "以下材料批号和包号在对应的检验申请中找不到对应的明细,请检查数据后重新导入!\n");
+                hint.AppendLine(packNoMsg.ToString());
+            }
+            if (hint.Length > 0)
+            {
+                MessageBox.Show(hint.ToString());
+                return false;
+            }
+
             // 检查发运数量不能超出可发运数量
             decimal hasShippedQty = _service.Query(x => x.ProductName.Equals(CurrDeliveryReceipt!.ProductName) && x.ContractNo.Equals(CurrDeliveryReceipt.ContractNo) && !x.Guid.Equals(CurrDeliveryReceipt.Guid))
                                     .Select(x => x.ShippedQty)
@@ -1529,12 +1689,13 @@ namespace UniformMaterialManagementSystem.ViewModels
         /// 反写合同明细
         /// </summary>
         /// <returns></returns>
-        private void UpdataContractDetail()
+        private void UpdataContractDetail(string contactNo, string productName)
         {
             // 反写合同明细
             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))
+            var contractDetails = serviceCD.Query(x => x.Contract.ContractNo.Equals(contactNo) && x.Material.Name.Equals(productName))
+                                  .Include(x => x.Contract)
                                   .Include(x => x.Material);
             if (contractDetails == null || !contractDetails.Any())
             {
@@ -1546,13 +1707,25 @@ namespace UniformMaterialManagementSystem.ViewModels
             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))
+            decimal hasShippedQty = _service.Query(x => x.ProductName.Equals(productName) && x.ContractNo.Equals(contactNo))
                                     .Select(x => x.ShippedQty)
                                     .ToList()
                                     .Sum();
-            contractDtl.ShippedQuantity = hasShippedQty + CurrDeliveryReceipt!.ShippedQty;
+            contractDtl.ShippedQuantity = hasShippedQty;
             // 保存、导入时会校验数量,删除时不会超出数量,所以不用再次校验
-            contractDtl.ShippedStatus = CurrDeliveryReceipt!.ShippedQty >= contractDtl.ContractQty;
+            if (hasShippedQty < contractDtl.ContractQty) // 主表的发运数量只汇总 > 0 的,不为负数
+            {
+                contractDtl.ShippedStatus = false;
+            }
+            else if (hasShippedQty >= contractDtl.ContractQty && hasShippedQty < contractDtl.ContractQty + _tolerance)
+            {
+                contractDtl.ShippedStatus = false;
+            }
+            else if (hasShippedQty >= contractDtl.ContractQty + _tolerance)
+            {
+                MessageBox.Show("反写合同明细出错:发运数量超出合同数量!");
+                return;
+            }
 
             // 保存到数据库
             serviceCD.Update(contractDtl);

+ 26 - 10
UniformMaterialManagementSystem/Views/DeliveryReceiptControl.xaml

@@ -208,7 +208,7 @@
             <Setter Property="TextAlignment" Value="Right" />
             <Setter Property="Margin" Value="5" />
         </Style>
-        
+
         <!-- Label 样式:自带边框 -->
         <Style x:Key="CustomLabelStyle" TargetType="Label">
             <Setter Property="BorderBrush" Value="Gray" />
@@ -305,12 +305,13 @@
                 <Button Content="导出数据包" 
                         Tag="{x:Static utils:RegularFontUtil.Arrow_Export_Up_24}"
                         Template="{StaticResource CustomToolBarButtomTemplate}"
-                        Command="{Binding ExportDBCommand}" />
+                        Command="{Binding ExportDBCommand}"
+                        CommandParameter="{Binding ElementName=fdgDelivery}"/>
                 <Button Content="导入数据包" 
                         Tag="{x:Static utils:RegularFontUtil.Arrow_Download_24}"
                         Template="{StaticResource CustomToolBarButtomTemplate}"
                         Command="{Binding ImportDBCommand}" />
-                
+
             </ToolBar>
         </Border>
 
@@ -349,17 +350,18 @@
                     <!-- TargetObject="{Binding }" 表示目标对象是当前的数据上下文 -->
                     <b:CallMethodAction TargetObject="{Binding }" 
                                         MethodName="FdgDelivery_SelectionChanged" />
-
+                    <b:InvokeCommandAction Command="{Binding DeliverySelectionChangedCommand}"
+                                           CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}}"/>
                 </b:EventTrigger>
             </b:Interaction.Triggers>
 
             <!-- todo 为什么只能设置为绝对宽度,比例宽度列标题不显示? -->
             <!-- 数据结构 -->
             <fdg:FilterDataGrid.Columns>
-                <!--<fdg:FilterDataGridTextColumn Header="检验申请编号" Width="300"
-                                              IsColumnFiltered="True"
-                                              ElementStyle="{StaticResource TextColumnElementStyle}"
-                                              Binding="{Binding ApplyNo}" />-->
+                <fdg:FilterDataGridCheckBoxColumn Header="  " Width="30"
+                                                  ElementStyle="{StaticResource CheckBoxColumnElementStyle}"
+                                                  EditingElementStyle="{StaticResource CheckBoxColumnElementStyle}"
+                                                  Binding="{Binding IsSelected, UpdateSourceTrigger=PropertyChanged}"/>
                 <fdg:FilterDataGridTextColumn Header="合同编号" Width="200"
                                               IsColumnFiltered="True"
                                               ElementStyle="{StaticResource TextColumnElementStyle}"
@@ -429,6 +431,19 @@
                                               Binding="{Binding ReceivedStatus}" 
                                               Visibility="{Binding DataContext.MainColVisibility, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type fdg:FilterDataGrid}},
                     PresentationTraceSources.TraceLevel=High}"  />
+                <!-- 只读 -->
+                <fdg:FilterDataGridCheckBoxColumn Header="是否导出数据包" Width="100"
+                                                  Binding="{Binding IsExportDelivery}"
+                                                  IsReadOnly="True">
+                    <fdg:FilterDataGridCheckBoxColumn.ElementStyle>
+                        <Style TargetType="CheckBox">
+                            <Setter Property="HorizontalAlignment" Value="Center" />
+                            <Setter Property="VerticalAlignment" Value="Center" />
+                            <Setter Property="IsEnabled" Value="False" />
+                        </Style>
+                    </fdg:FilterDataGridCheckBoxColumn.ElementStyle>
+                </fdg:FilterDataGridCheckBoxColumn>
+
             </fdg:FilterDataGrid.Columns>
         </fdg:FilterDataGrid>
 
@@ -694,7 +709,8 @@
                         Content="新增"
                         Tag="{x:Static utils:RegularFontUtil.Add_Circle_32}"
                         Template="{StaticResource CustomToolBarButtomTemplate}"
-                        Command="{Binding AddDetailCommand}" />
+                        Command="{Binding AddDetailCommand}"
+                        CommandParameter="{Binding ElementName=fdgDeliveryDetail}" />
                 <Button x:Name="btnDeleteDtls"
                         Content="删除"
                         Tag="{x:Static utils:RegularFontUtil.Delete_32}"
@@ -774,7 +790,7 @@
                                               ElementStyle="{StaticResource TextColumnElementStyle}"
                                               EditingElementStyle="{StaticResource TextColumnEditingStyle}"
                                               Binding="{Binding BatchNo, UpdateSourceTrigger=PropertyChanged}" />
-                <fdg:FilterDataGridTextColumn Header="包号" Width="100"
+                <fdg:FilterDataGridTextColumn Header="包号" Width="200"
                                               ElementStyle="{StaticResource TextColumnElementStyle}"
                                               EditingElementStyle="{StaticResource TextColumnEditingStyle}"
                                               Binding="{Binding PacketNo, UpdateSourceTrigger=PropertyChanged}" />

+ 1 - 1
UniformMaterialManagementSystem/Views/MaterialReceiptPage.xaml

@@ -633,7 +633,7 @@
                                               EditingElementStyle="{StaticResource TextColumnEditingStyle}"
                                               Binding="{Binding BatchNo}"
                                               IsReadOnly="True" />
-                <fdg:FilterDataGridTextColumn Header="包号" Width="100"
+                <fdg:FilterDataGridTextColumn Header="包号" Width="200"
                                               ElementStyle="{StaticResource TextColumnElementStyle}"
                                               EditingElementStyle="{StaticResource TextColumnEditingStyle}"
                                               Binding="{Binding PacketNo}"