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;