diff --git a/JQSalesSummaryPanel.Designer.cs b/JQSalesSummaryPanel.Designer.cs index e324326..da416bb 100644 --- a/JQSalesSummaryPanel.Designer.cs +++ b/JQSalesSummaryPanel.Designer.cs @@ -176,6 +176,7 @@ this.importSalesBtn.TabIndex = 2; this.importSalesBtn.Text = "button1"; this.importSalesBtn.UseVisualStyleBackColor = true; + this.importSalesBtn.Click += new System.EventHandler(this.importSalesBtn_Click); // // JQSalesSummaryPanel // diff --git a/JQSalesSummaryPanel.cs b/JQSalesSummaryPanel.cs index 8c30393..b14870e 100644 --- a/JQSalesSummaryPanel.cs +++ b/JQSalesSummaryPanel.cs @@ -8,6 +8,7 @@ using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; +using Microsoft.Office.Interop.Excel; using System.Windows.Forms; namespace KellyReport_D @@ -58,7 +59,31 @@ namespace KellyReport_D private void initForecastBtn_Click(object sender, EventArgs e) { WorkBookUtils.GenForecast(this.initForecastBtn); + MessageBox.Show("生成年度预估表完成", "完成", MessageBoxButtons.OK, MessageBoxIcon.Information); + } + private void importSalesBtn_Click(object sender, EventArgs e) + { + var workBook = WorkBookUtils.SelectAndOpenExcelFile(); + + if (workBook == null) + { + MessageBox.Show("未选择文件或文件打开失败,请重试。", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); + return; + } + + try + { + WorkBookUtils.importSalesDetailFromWorkBook(workBook); + } + catch (Exception ex) + { + MessageBox.Show($"导入过程中发生错误:{ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + finally + { + workBook.Close(false); // 关闭工作簿 + } } } } diff --git a/KellyReport_D.csproj b/KellyReport_D.csproj index 575efa8..8363d7e 100644 --- a/KellyReport_D.csproj +++ b/KellyReport_D.csproj @@ -220,7 +220,9 @@ + + Code diff --git a/Model/ImportContext.cs b/Model/ImportContext.cs new file mode 100644 index 0000000..7e9221c --- /dev/null +++ b/Model/ImportContext.cs @@ -0,0 +1,48 @@ +using Microsoft.Office.Interop.Excel; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace KellyReport_D.Model +{ + internal class ImportContext + { + public Workbook ImportWorkbook { get; set; } + public Microsoft.Office.Interop.Excel.Application Application { get; set; } + public IList ClientContactList { get; set; } + public IList SalesDetails { get; set; } + public class GroupedSalesDetailModel + { + public string SalesName { get; set; } + public string ClientName { get; set; } + public string ProductNameEN { get; set; } + public decimal TotalAmount { get; set; } + public List Details { get; set; } + } + + public IEnumerable GroupedSalesDetailBySalesName => SalesDetails + .GroupBy(x => x.SalesName.ToUpper()) + .Select(grouped => new GroupedSalesDetailModel + { + SalesName = grouped.Key, + TotalAmount = grouped.Sum(x => x.TotalAmount ?? 0), + Details = grouped.ToList() + }); + + public IEnumerable GetGroupedSalesDetailByClientName(IList salesDetails) + { + return salesDetails + .GroupBy(x => new { SalesName = x.SalesName.ToUpper(), x.ClientName, x.ProductNameEN }) + .Select(grouped => new GroupedSalesDetailModel + { + SalesName = grouped.Key.SalesName, + ClientName = grouped.Key.ClientName, + ProductNameEN = grouped.Key.ProductNameEN, + TotalAmount = grouped.Sum(x => x.TotalAmount ?? 0), + Details = grouped.ToList() + }); + } + } +} diff --git a/Model/SalesDetail.cs b/Model/SalesDetail.cs new file mode 100644 index 0000000..8cd4f2f --- /dev/null +++ b/Model/SalesDetail.cs @@ -0,0 +1,81 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace KellyReport_D.Model +{ + internal class SalesDetail + { + /// + /// 业务 + /// + public string SalesName { get; set; } + + /// + /// 申报所属月份 + /// + public string Month { get; set; } + + /// + /// 发货日期 + /// + public DateTime? DeliveryDate { get; set; } + + /// + /// 订单号码 + /// + public string OrderNumber { get; set; } + + /// + /// 发票日期 + /// + public DateTime? InvoiceDate { get; set; } + + /// + /// 發票號碼 + /// + public string InvoiceNumber { get; set; } + + /// + /// 客户名称 + /// + public string ClientName { get; set; } + + /// + /// 英文品名 + /// + public string ProductNameEN { get; set; } + + /// + /// 数量(KG) + /// + public decimal? Quantity { get; set; } + + /// + /// 含税单价 + /// + public decimal? PriceWithTax { get; set; } + + /// + /// 未税金额 + /// + public decimal? AmountWithoutTax { get; set; } + + /// + /// 税金13% + /// + public decimal? Tax { get; set; } + + /// + /// 合計金額 + /// + public decimal? TotalAmount { get; set; } + + /// + /// 备注 + /// + public string Remark { get; set; } + } +} diff --git a/Properties/Resources.Designer.cs b/Properties/Resources.Designer.cs index c644985..e1f38d9 100644 --- a/Properties/Resources.Designer.cs +++ b/Properties/Resources.Designer.cs @@ -143,8 +143,8 @@ namespace KellyReport_D.Properties { } /// - /// 查找类似 請導入銷售數據表, 並點擊下方 "導入銷售表" 按鈕。 - ///程序將會根據銷售表的數據生成各個業務的JQ Total表。 的本地化字符串。 + /// 查找类似 請點擊下方 "導入銷售表" 按鈕,並選擇需要導入的年度銷售母表。 + ///程序將會根據銷售表的數據生成各個業務的JQ Total表。 的本地化字符串。 /// public static string STEP2_DESC { get { diff --git a/Properties/Resources.resx b/Properties/Resources.resx index 57e4eaa..01ab505 100644 --- a/Properties/Resources.resx +++ b/Properties/Resources.resx @@ -146,7 +146,7 @@ Step2: - 請導入銷售數據表, 並點擊下方 "導入銷售表" 按鈕。 -程序將會根據銷售表的數據生成各個業務的JQ Total表。 + 請點擊下方 "導入銷售表" 按鈕,並選擇需要導入的年度銷售母表。 +程序將會根據銷售表的數據生成各個業務的JQ Total表。 \ No newline at end of file diff --git a/Utils/WorkBookUtils.cs b/Utils/WorkBookUtils.cs index 3e7e3b8..6b76981 100644 --- a/Utils/WorkBookUtils.cs +++ b/Utils/WorkBookUtils.cs @@ -7,11 +7,216 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using KellyReport_D.Model; +using System.Windows.Input; namespace KellyReport_D.Utils { internal static class WorkBookUtils { + public static void importSalesDetailFromWorkBook(Workbook workbook) + { + var importContext = new ImportContext() + { + Application = Globals.ThisAddIn.Application, + ImportWorkbook = workbook + }; + + // 获取「客户资料」工作表 + readClientContact(importContext); + // 读取「销售明细」工作表 + ReadSalesDetails(importContext); + foreach (var userGroupedSalesDetail in importContext.GroupedSalesDetailBySalesName) + { + var userSheet = GenUserSalesDetailSheet(importContext, userGroupedSalesDetail); + PrepareTotalHeader(userSheet); + WriteSalesDetailsData(importContext, userGroupedSalesDetail, userSheet); + } + } + + public static void WriteSalesDetailsData( + ImportContext context, + ImportContext.GroupedSalesDetailModel userGroupedSalesDetail, + Worksheet userSheet + ) + { + int rowIndex = 4; // 从第四行开始写入数据 + var clientGroupedSalesDetail = context.GetGroupedSalesDetailByClientName(userGroupedSalesDetail.Details); + foreach (var salesDetail in clientGroupedSalesDetail) + { + ClientContact clientContact = context.ClientContactList.FirstOrDefault(x => x.Name == salesDetail.ClientName) ?? new ClientContact + { + Name = salesDetail.ClientName, + }; + + userSheet.Cells[rowIndex, 1].Value2 = salesDetail.SalesName; + userSheet.Cells[rowIndex, 2].Value2 = clientContact.Region; + userSheet.Cells[rowIndex, 3].Value2 = clientContact.Industry; + userSheet.Cells[rowIndex, 4].Value2 = clientContact.AnnualCapacity; + userSheet.Cells[rowIndex, 5].Value2 = clientContact.Name; + userSheet.Cells[rowIndex, 6].Value2 = clientContact.PurchasingManager; + userSheet.Cells[rowIndex, 7].Value2 = clientContact.PurchasingManagerPhone; + userSheet.Cells[rowIndex, 8].Value2 = clientContact.Purchaser; + userSheet.Cells[rowIndex, 9].Value2 = clientContact.PurchaserPhone; + userSheet.Cells[rowIndex, 10].Value2 = clientContact.Address; + userSheet.Cells[rowIndex, 11].Value2 = salesDetail.ProductNameEN; + rowIndex++; + } + } + + public static void PrepareTotalHeader(Worksheet userSheet) + { + // 合并A1:L1并设置标题 + userSheet.Range["A1", "L1"].Merge(); + userSheet.Range["A1"].Value2 = "客戶資料"; + + // 合并并设置各列标题 + userSheet.Range["A2", "A3"].Merge(); + userSheet.Range["A2"].Value2 = "業務"; + userSheet.Range["B2", "B3"].Merge(); + userSheet.Range["B2"].Value2 = "地區"; + userSheet.Range["C2", "C3"].Merge(); + userSheet.Range["C2"].Value2 = "行業"; + userSheet.Range["D2", "D3"].Merge(); + userSheet.Range["D2"].Value2 = "產能/年"; + userSheet.Range["E2", "E3"].Merge(); + userSheet.Range["E2"].Value2 = "名稱"; + userSheet.Range["F2", "F3"].Merge(); + userSheet.Range["F2"].Value2 = "採購主管"; + userSheet.Range["G2", "G3"].Merge(); + userSheet.Range["G2"].Value2 = "電話"; + userSheet.Range["H2", "H3"].Merge(); + userSheet.Range["H2"].Value2 = "採購"; + userSheet.Range["I2", "I3"].Merge(); + userSheet.Range["I2"].Value2 = "電話"; + userSheet.Range["J2", "J3"].Merge(); + userSheet.Range["J2"].Value2 = "地址"; + userSheet.Range["K2", "K3"].Merge(); + userSheet.Range["K2"].Value2 = "產品"; + userSheet.Range["L2", "L3"].Merge(); + userSheet.Range["L2"].Value2 = "需求/月"; + + // 计算起始列(L列后面,列号13) + int startCol = 13; + + // 合并年度销售表标题 + userSheet.Range[userSheet.Cells[1, startCol], userSheet.Cells[1, startCol + 37]].Merge(); + userSheet.Cells[1, startCol].Value2 = "年度销售表"; + + // 设置月份表头 + for (int i = 0; i < 12; i++) + { + int monthCol = startCol + i * 3; + userSheet.Range[userSheet.Cells[2, monthCol], userSheet.Cells[2, monthCol + 2]].Merge(); + userSheet.Cells[2, monthCol].Value2 = $"{i + 1}月"; + userSheet.Cells[3, monthCol].Value2 = "單價"; + userSheet.Cells[3, monthCol + 1].Value2 = "數量"; + userSheet.Cells[3, monthCol + 2].Value2 = "金額"; + } + + // 合并Total表头 + userSheet.Range[userSheet.Cells[2, startCol + 36], userSheet.Cells[2, startCol + 37]].Merge(); + userSheet.Cells[2, startCol + 36].Value2 = "Total"; + userSheet.Cells[3, startCol + 36].Value2 = "總數量"; + userSheet.Cells[3, startCol + 37].Value2 = "總金額"; + + // 设置所有已用单元格居中 + Range usedRange = userSheet.UsedRange; + usedRange.HorizontalAlignment = XlHAlign.xlHAlignCenter; + } + + + private static Worksheet GenUserSalesDetailSheet( + Model.ImportContext context, + Model.ImportContext.GroupedSalesDetailModel groupedSalesDetail + ) + { + var app = context.Application; + var salesName = groupedSalesDetail.SalesName ?? "UNKONW"; + string sheetName = $"JQ Total({salesName.ToUpper()})"; + Worksheet userSheet = null; + + try + { + // 新建工作表并命名 + userSheet = app.Worksheets.Add(); + userSheet.Name = sheetName; + } + catch + { + // 已存在则获取 + userSheet = app.Worksheets[sheetName] as Worksheet; + try + { + Range usedRange = userSheet.UsedRange; + if (usedRange != null && usedRange.Cells.Count > 1) + { + usedRange.Clear(); + } + } + catch + { + // 无 UsedRange 可忽略 + } + } + + return userSheet; + } + + private static void ReadSalesDetails(ImportContext context) + { + var dataRange = context.ImportWorkbook.Sheets[1].UsedRange; + IList salesDatailList = new List(); + + if (dataRange.Value2 is object[,] rawSalesDetailData) + { + int rowCount = rawSalesDetailData.GetLength(0); + int colCount = rawSalesDetailData.GetLength(1); + + for (int i = 3; i <= rowCount; i++) + { + SalesDetail item = new SalesDetail + { + SalesName = rawSalesDetailData[i, 1]?.ToString() ?? "", + Month = rawSalesDetailData[i, 2]?.ToString() ?? "", + InvoiceDate = rawSalesDetailData[i, 3] is double invoiceDate ? DateTime.FromOADate(invoiceDate) : (DateTime?)null, + OrderNumber = rawSalesDetailData[i, 4]?.ToString() ?? "", + DeliveryDate = rawSalesDetailData[i, 5] is double deliveryDate ? DateTime.FromOADate(deliveryDate) : (DateTime?)null, + InvoiceNumber = rawSalesDetailData[i, 6]?.ToString() ?? "", + ClientName = rawSalesDetailData[i, 7]?.ToString() ?? "", + ProductNameEN = rawSalesDetailData[i, 8]?.ToString() ?? "", + Quantity = rawSalesDetailData[i, 9] != null ? Convert.ToDecimal(rawSalesDetailData[i, 9]) : (decimal?)null, + PriceWithTax = rawSalesDetailData[i, 10] != null ? Convert.ToDecimal(rawSalesDetailData[i, 10]) : (decimal?)null, + AmountWithoutTax = rawSalesDetailData[i, 11] != null ? Convert.ToDecimal(rawSalesDetailData[i, 11]) : (decimal?)null, + Tax = rawSalesDetailData[i, 12] != null ? Convert.ToDecimal(rawSalesDetailData[i, 12]) : (decimal?)null, + TotalAmount = rawSalesDetailData[i, 13] != null ? Convert.ToDecimal(rawSalesDetailData[i, 13]) : (decimal?)null, + Remark = rawSalesDetailData[i, 14]?.ToString() ?? "", + }; + salesDatailList.Add(item); + } + } + context.SalesDetails = salesDatailList; + } + + public static Workbook SelectAndOpenExcelFile() + { + var app = Globals.ThisAddIn.Application; + var curWorkbook = app.ActiveWorkbook; + using (OpenFileDialog dialog = new OpenFileDialog()) + { + dialog.Filter = "Excel 文件 (*.xlsx)|*.xlsx"; + dialog.Title = "请选择要打开的 Excel 文件"; + if (dialog.ShowDialog() == DialogResult.OK) + { + string filePath = dialog.FileName; + Workbook workbook = app.Workbooks.Open(filePath); + + curWorkbook.Activate(); + return workbook; + } + } + return null; + } + public static async void GenForecast(System.Windows.Forms.Button button) { String originLabel = button.Text; @@ -31,8 +236,6 @@ namespace KellyReport_D.Utils readSalesForecastData(context); // 获取「產品年度預估」工作表 readProductForecastData(context); - // 获取「客户资料」工作表 - readClientContact(context); GenBussenessSheet(context); } @@ -158,7 +361,7 @@ namespace KellyReport_D.Utils } - private static void readClientContact(GenForecaseContext context) + private static void readClientContact(ImportContext context) { var app = context.Application;