KellyReport_D/Utils/WorkBookUtils.cs

491 lines
21 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using KellyReport_D.Properties;
using System.Windows.Forms;
using Microsoft.Office.Interop.Excel;
using System;
using System.Collections.Generic;
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<SalesDetail> salesDatailList = new List<SalesDetail>();
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;
if (button != null)
{
button.Text = Resources.GENERATING;
}
var app = Globals.ThisAddIn.Application;
var context = new GenForecaseContext
{
Application = app
};
try
{
// 获取「銷售年度預估」工作表
readSalesForecastData(context);
// 获取「產品年度預估」工作表
readProductForecastData(context);
GenBussenessSheet(context);
}
catch (Exception ex)
{
Console.WriteLine("Error generating forecast:" + ex.Message);
MessageBox.Show("分析预估表失败: " + ex.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
button.Text = originLabel;
}
public static void GenBussenessSheet(GenForecaseContext context)
{
var app = context.Application;
// 假设 app 是 Excel.Application
Worksheet sheet = null;
string sheetName = "業務月達成率";
try
{
// 新增工作表
sheet = app.Worksheets.Add();
sheet.Name = sheetName;
}
catch
{
// 已存在则获取
sheet = app.Worksheets[sheetName] as Worksheet;
try
{
Range usedRange = sheet.UsedRange;
if (usedRange != null && usedRange.Cells.Count > 1)
{
usedRange.Clear();
}
}
catch
{
// 无 UsedRange 可忽略
}
}
// 合并A1:A2并填入年份
try
{
var monthData = context.MonthData;
var yearValue = monthData[0];
Range yearRange = sheet.Range["A1", "A2"];
yearRange.Merge();
yearRange.Value2 = yearValue.ToString();
yearRange.NumberFormat = "@"; // 文本格式
// 填入月份
for (int i = 1; i < monthData.Length; i++)
{
sheet.Cells[i + 2, 1] = monthData[i];
}
// B列开始填 salesName 及相关数据
int col = 2; // B列
foreach (var salesForcastData in context.SalesForecastList)
{
int rowIndex = 1; // Excel 行号从1开始
int startCol = col;
int endCol = col + 4;
// 合并并填入 salesName
Range salesNameRange = sheet.Range[
sheet.Cells[rowIndex, startCol],
sheet.Cells[rowIndex, startCol + 1]
];
salesNameRange.Merge();
salesNameRange.Value2 = salesForcastData.Name;
// 合并并填入“完成%”
Range finishRange = sheet.Range[
sheet.Cells[rowIndex, startCol + 2],
sheet.Cells[rowIndex, startCol + 2]
];
finishRange.Merge();
finishRange.Value2 = "完成%";
// 合并并填入“累積達成率”
Range accRange = sheet.Range[
sheet.Cells[rowIndex, startCol + 3],
sheet.Cells[rowIndex, startCol + 3]
];
accRange.Merge();
accRange.Value2 = "累積達成率";
// 第二行填入 Y-forecast 和 turnover
rowIndex++;
sheet.Cells[rowIndex, startCol] = "Y-forecast";
sheet.Cells[rowIndex, startCol + 1] = "turnover";
// 填入每月数据
rowIndex++;
foreach (var forcastMonth in salesForcastData.MonthlyForecast)
{
var cell = sheet.Cells[rowIndex, startCol];
cell.Value2 = forcastMonth;
cell.NumberFormat = "#,##0";
rowIndex++;
}
col = endCol;
}
// 自适应所有已用列宽
Range usedRange2 = sheet.UsedRange;
if (usedRange2 != null)
{
usedRange2.Columns.AutoFit();
}
}
catch (Exception ex)
{
MessageBox.Show("写入业绩月达成率时发生错误:" + ex.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private static void readClientContact(ImportContext context)
{
var app = context.Application;
var clientContactSheet = app.Worksheets["客戶資料"] as Worksheet;
var clientContactRange = clientContactSheet.UsedRange;
IList<ClientContact> clientContactList = new List<ClientContact>();
if (clientContactRange.Value2 is object[,] rawContactData)
{
int rowCount = rawContactData.GetLength(0);
int colCount = rawContactData.GetLength(1);
// 模板第二行开始是数据
for (int i = 2; i <= rowCount; i++)
{
var input = new ClientContact
{
Region = rawContactData[i, 1]?.ToString() ?? "",
Industry = rawContactData[i, 2]?.ToString() ?? "",
AnnualCapacity = rawContactData[i, 3]?.ToString() ?? "",
Name = rawContactData[i, 4]?.ToString() ?? "",
PurchasingManager = rawContactData[i, 5]?.ToString() ?? "",
PurchasingManagerPhone = rawContactData[i, 6]?.ToString() ?? "",
Purchaser = rawContactData[i, 7]?.ToString() ?? "",
PurchaserPhone = rawContactData[i, 8]?.ToString() ?? "",
Address = rawContactData[i, 9]?.ToString() ?? ""
};
clientContactList.Add(input);
}
}
context.ClientContactList = clientContactList;
}
private static void readProductForecastData(GenForecaseContext context)
{
var app = context.Application;
var productForecastSheet = app.Worksheets["產品年度預估"] as Worksheet;
var productRange = productForecastSheet.UsedRange;
IList<ProductForecastInput> productForecastList = new List<ProductForecastInput>();
if (productRange.Value2 is object[,] rawProductData)
{
int rowCount = rawProductData.GetLength(0);
int colCount = rawProductData.GetLength(1);
if (rawProductData[1, 2] == null)
{
throw new MissingMemberException("「產品年度預估」工作表的(年份)不能为空,请检查数据格式。");
}
var year = Convert.ToInt32(rawProductData[1, 2]);
// 模板第三行开始是数据
for (int i = 3; i <= rowCount; i++)
{
var input = new ProductForecastInput
{
Year = year,
Name = rawProductData[i, 1]?.ToString() ?? "",
Quantity = rawProductData[i, 2] != null ? Convert.ToDecimal(rawProductData[i, 2]) : 0,
AmountTax = rawProductData[i, 3] != null ? Convert.ToDecimal(rawProductData[i, 3]) : 0,
Amount = rawProductData[i, 4] != null ? Convert.ToDecimal(rawProductData[i, 4]) : 0,
PriceAvg = rawProductData[i, 5] != null ? Convert.ToDecimal(rawProductData[i, 5]) : 0,
};
productForecastList.Add(input);
}
}
context.ProductForecastList = productForecastList;
}
private static void readSalesForecastData(GenForecaseContext context)
{
var app = context.Application;
var salesForecastSheet = app.Worksheets["銷售年度預估"] as Worksheet;
var salesRange = salesForecastSheet.UsedRange;
IList<SalesForecastInput> salesForecastInputList = new List<SalesForecastInput>();
string[] monthData = new string[13];
if (salesRange.Value2 is object[,] rawSalesData)
{
int rowCount = rawSalesData.GetLength(0);
int colCount = rawSalesData.GetLength(1);
if (rawSalesData[1, 2] == null)
{
throw new MissingMemberException("「銷售年度預估」工作表的(年份)不能为空,请检查数据格式。");
}
var year = Convert.ToInt32(rawSalesData[1, 2]);
monthData[0] = year.ToString();
for (int i = 1; i <= 12; i++)
{
monthData[i] = rawSalesData[2, i + 1].ToString();
}
// 模板第三行开始是数据
for (int i = 3; i <= rowCount; i++)
{
var input = new SalesForecastInput
{
Year = year,
Name = rawSalesData[i, 1]?.ToString() ?? "",
January = rawSalesData[i, 2] != null ? Convert.ToDecimal(rawSalesData[i, 2]) : 0,
February = rawSalesData[i, 3] != null ? Convert.ToDecimal(rawSalesData[i, 3]) : 0,
March = rawSalesData[i, 4] != null ? Convert.ToDecimal(rawSalesData[i, 4]) : 0,
April = rawSalesData[i, 5] != null ? Convert.ToDecimal(rawSalesData[i, 5]) : 0,
May = rawSalesData[i, 6] != null ? Convert.ToDecimal(rawSalesData[i, 6]) : 0,
June = rawSalesData[i, 7] != null ? Convert.ToDecimal(rawSalesData[i, 7]) : 0,
July = rawSalesData[i, 8] != null ? Convert.ToDecimal(rawSalesData[i, 8]) : 0,
August = rawSalesData[i, 9] != null ? Convert.ToDecimal(rawSalesData[i, 9]) : 0,
September = rawSalesData[i, 10] != null ? Convert.ToDecimal(rawSalesData[i, 10]) : 0,
October = rawSalesData[i, 11] != null ? Convert.ToDecimal(rawSalesData[i, 11]) : 0,
November = rawSalesData[i, 12] != null ? Convert.ToDecimal(rawSalesData[i, 12]) : 0,
December = rawSalesData[i, 13] != null ? Convert.ToDecimal(rawSalesData[i, 13]) : 0,
Total = rawSalesData[i, 14] != null ? Convert.ToDecimal(rawSalesData[i, 14]) : 0,
};
salesForecastInputList.Add(input);
}
}
context.SalesForecastList = salesForecastInputList;
context.MonthData = monthData;
}
}
}