diff --git a/KellyReport_D.csproj b/KellyReport_D.csproj
index 8363d7e..cb2fa5f 100644
--- a/KellyReport_D.csproj
+++ b/KellyReport_D.csproj
@@ -34,7 +34,7 @@
publish\
zh-chs
- 1.0.0.1
+ 1.0.0.2
true
true
7
diff --git a/Model/ImportContext.cs b/Model/ImportContext.cs
index 7e9221c..6dbfa3d 100644
--- a/Model/ImportContext.cs
+++ b/Model/ImportContext.cs
@@ -10,6 +10,7 @@ namespace KellyReport_D.Model
internal class ImportContext
{
public Workbook ImportWorkbook { get; set; }
+ public List SalesWorksheets { get; set; }
public Microsoft.Office.Interop.Excel.Application Application { get; set; }
public IList ClientContactList { get; set; }
public IList SalesDetails { get; set; }
@@ -19,6 +20,7 @@ namespace KellyReport_D.Model
public string ClientName { get; set; }
public string ProductNameEN { get; set; }
public decimal TotalAmount { get; set; }
+ public decimal Quantity { get; set; }
public List Details { get; set; }
}
@@ -28,18 +30,18 @@ namespace KellyReport_D.Model
{
SalesName = grouped.Key,
TotalAmount = grouped.Sum(x => x.TotalAmount ?? 0),
+ Quantity = grouped.Sum(x => x.Quantity ?? 0),
Details = grouped.ToList()
});
public IEnumerable GetGroupedSalesDetailByClientName(IList salesDetails)
{
return salesDetails
- .GroupBy(x => new { SalesName = x.SalesName.ToUpper(), x.ClientName, x.ProductNameEN })
+ .GroupBy(x => new { SalesName = x.SalesName.ToUpper(), x.ClientName })
.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/Utils/WorkBookUtils.cs b/Utils/WorkBookUtils.cs
index 6b76981..17d79b4 100644
--- a/Utils/WorkBookUtils.cs
+++ b/Utils/WorkBookUtils.cs
@@ -7,7 +7,6 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
using KellyReport_D.Model;
-using System.Windows.Input;
namespace KellyReport_D.Utils
{
@@ -18,11 +17,12 @@ namespace KellyReport_D.Utils
var importContext = new ImportContext()
{
Application = Globals.ThisAddIn.Application,
- ImportWorkbook = workbook
+ ImportWorkbook = workbook,
+ SalesWorksheets = new List(),
};
// 获取「客户资料」工作表
- readClientContact(importContext);
+ ReadClientContact(importContext);
// 读取「销售明细」工作表
ReadSalesDetails(importContext);
foreach (var userGroupedSalesDetail in importContext.GroupedSalesDetailBySalesName)
@@ -30,7 +30,146 @@ namespace KellyReport_D.Utils
var userSheet = GenUserSalesDetailSheet(importContext, userGroupedSalesDetail);
PrepareTotalHeader(userSheet);
WriteSalesDetailsData(importContext, userGroupedSalesDetail, userSheet);
+
+ importContext.SalesWorksheets.Add(userSheet);
}
+
+ GenSalesTotal(importContext);
+ }
+
+ private static void GenSalesTotal(ImportContext context)
+ {
+ var app = context.Application;
+ var totalWorksheet = CreateSheetIfNotExisted(app, "JQ Total(Total)");
+
+ PrepareTotalHeader(totalWorksheet);
+ int totalRowIndex = 4;
+ foreach (var userSheet in context.SalesWorksheets)
+ {
+ Range usedRange = userSheet.UsedRange;
+ int rowIndexStart = 4;
+ int rowIndexEnd = usedRange.Rows.Count;
+
+ int rowCount = rowIndexEnd - rowIndexStart + 1;
+ if (rowCount > 1)
+ {
+ Range sourceRange = userSheet.Range[
+ userSheet.Cells[rowIndexStart, 1],
+ userSheet.Cells[rowIndexEnd, usedRange.Columns.Count]
+ ];
+
+ int totalRowIndexEnd = totalRowIndex + rowCount;
+ Range targetRange = totalWorksheet.Range[
+ totalWorksheet.Cells[totalRowIndex, 1],
+ totalWorksheet.Cells[totalRowIndexEnd, usedRange.Columns.Count]
+ ];
+ sourceRange.Copy(targetRange);
+ totalRowIndex = totalRowIndexEnd;
+ }
+ }
+
+ totalWorksheet.Cells[totalRowIndex, 1].Value = "總結";
+ var sumRange = totalWorksheet.Range[
+ totalWorksheet.Cells[totalRowIndex, 1],
+ totalWorksheet.Cells[totalRowIndex + 4, 5]
+ ];
+ sumRange.Merge();
+
+ int sumColStart = 13; // L列是第12列
+ totalWorksheet.Cells[totalRowIndex, 11].Value2 = "總銷量及金額(未稅)";
+ for (int i = 0; i < 12; i++)
+ {
+ int quantityColIndex = sumColStart + i * 3 + 1;
+ string quantityColLetter = GetColumnLetter(quantityColIndex);
+ totalWorksheet.Cells[totalRowIndex, quantityColIndex].formula = $"=(SUM({quantityColLetter}4:{quantityColLetter}{totalRowIndex - 1})/2)";
+
+ int amountColIndex = sumColStart + i * 3 + 2;
+ string amountColLetter = GetColumnLetter(amountColIndex);
+ totalWorksheet.Cells[totalRowIndex, amountColIndex].formula = $"=((SUM({amountColLetter}4:{amountColLetter}{totalRowIndex - 1})/2) - {amountColLetter}{totalRowIndex + 2})/1.13";
+ }
+ string totalQuantityColLetter = GetColumnLetter(49);
+ string totalAmountColLetter = GetColumnLetter(50);
+
+ totalWorksheet.Cells[totalRowIndex, 49].formula = $"=(SUM({totalQuantityColLetter}4:{totalAmountColLetter}{totalRowIndex - 1})/2)";
+ totalWorksheet.Cells[totalRowIndex, 50].formula = $"=((SUM({totalAmountColLetter}4:{totalAmountColLetter}{totalRowIndex - 1})/2) - {totalAmountColLetter}{totalRowIndex + 2})/1.13";
+
+
+ totalRowIndex++;
+ totalWorksheet.Cells[totalRowIndex, 11].Value2 = "總銷量及金額(含稅)";
+ for (int i = 0; i < 12; i++)
+ {
+ int quantityColIndex = sumColStart + i * 3 + 1;
+ string quantityColLetter = GetColumnLetter(quantityColIndex);
+ totalWorksheet.Cells[totalRowIndex, quantityColIndex].formula = $"=(SUM({quantityColLetter}4:{quantityColLetter}{totalRowIndex - 1})/2)";
+
+ int amountColIndex = sumColStart + i * 3 + 2;
+ string amountColLetter = GetColumnLetter(amountColIndex);
+ totalWorksheet.Cells[totalRowIndex, amountColIndex].formula = $"=(SUM({amountColLetter}4:{amountColLetter}{totalRowIndex - 1})/2)";
+ }
+ totalWorksheet.Cells[totalRowIndex, 49].formula = $"=(SUM({totalQuantityColLetter}4:{totalQuantityColLetter}{totalRowIndex - 1})/2)";
+ totalWorksheet.Cells[totalRowIndex, 50].formula = $"=(SUM({totalAmountColLetter}4:{totalAmountColLetter}{totalRowIndex - 1})/2)";
+
+ totalRowIndex++;
+ totalWorksheet.Cells[totalRowIndex, 11].Value2 = "總銷量及金額(外銷)";
+ for (int i = 0; i < 12; i++)
+ {
+ int quantityColIndex = sumColStart + i * 3 + 1;
+ totalWorksheet.Cells[totalRowIndex, quantityColIndex].Value2 = 0;
+
+ int amountColIndex = sumColStart + i * 3 + 2;
+ totalWorksheet.Cells[totalRowIndex, amountColIndex].Value2 = 0;
+ }
+ totalWorksheet.Cells[totalRowIndex, 49].Value2 = 0;
+ totalWorksheet.Cells[totalRowIndex, 50].Value2 = 0;
+
+ totalRowIndex++;
+ totalWorksheet.Cells[totalRowIndex, 11].Value2 = "總銷量及金額(內外銷)";
+ for (int i = 0; i < 12; i++)
+ {
+ int quantityColIndex = sumColStart + i * 3 + 1;
+ string quantityColLetter = GetColumnLetter(quantityColIndex);
+ totalWorksheet.Cells[totalRowIndex, quantityColIndex].formula = $"={quantityColLetter}{totalRowIndex - 3}+{quantityColLetter}{totalRowIndex - 1}";
+
+ int amountColIndex = sumColStart + i * 3 + 2;
+ string amountColLetter = GetColumnLetter(amountColIndex);
+ totalWorksheet.Cells[totalRowIndex, amountColIndex].formula = $"={amountColLetter}{totalRowIndex - 3}+{amountColLetter}{totalRowIndex - 1}";
+ }
+ totalWorksheet.Cells[totalRowIndex, 49].formula = $"={totalQuantityColLetter}{totalRowIndex - 3}+{totalQuantityColLetter}{totalRowIndex - 1}";
+ totalWorksheet.Cells[totalRowIndex, 50].formula = $"={totalAmountColLetter}{totalRowIndex - 3}+{totalAmountColLetter}{totalRowIndex - 1}";
+
+ // 自适应所有已用列宽
+ FormatSheetStyle(totalWorksheet);
+ }
+
+ private static void FormatSheetStyle(Worksheet worksheet)
+ {
+ // 自适应所有已用列宽
+ Range usedRange2 = worksheet.UsedRange;
+ if (usedRange2 != null)
+ {
+ usedRange2.Columns.AutoFit();
+ usedRange2.Borders.LineStyle = XlLineStyle.xlContinuous;
+ usedRange2.Borders.Weight = XlBorderWeight.xlThin;
+ }
+ worksheet.Cells[4, 12].Select();
+
+ //worksheet.Application.ActiveWindow.SplitRow = 3;
+ //worksheet.Application.ActiveWindow.SplitColumn = 10;
+ worksheet.Application.ActiveWindow.FreezePanes = true;
+ }
+
+
+ // 列号转字母方法
+ private static string GetColumnLetter(int col)
+ {
+ string colLetter = "";
+ while (col > 0)
+ {
+ int mod = (col - 1) % 26;
+ colLetter = (char)(65 + mod) + colLetter;
+ col = (col - mod - 1) / 26;
+ }
+ return colLetter;
}
public static void WriteSalesDetailsData(
@@ -40,15 +179,79 @@ namespace KellyReport_D.Utils
)
{
int rowIndex = 4; // 从第四行开始写入数据
- var clientGroupedSalesDetail = context.GetGroupedSalesDetailByClientName(userGroupedSalesDetail.Details);
- foreach (var salesDetail in clientGroupedSalesDetail)
+ var clientSalesList = context.GetGroupedSalesDetailByClientName(userGroupedSalesDetail.Details);
+ foreach (var clientSalesDetail in clientSalesList)
{
- ClientContact clientContact = context.ClientContactList.FirstOrDefault(x => x.Name == salesDetail.ClientName) ?? new ClientContact
+ ClientContact clientContact = context.ClientContactList.FirstOrDefault(x => x.Name == clientSalesDetail.ClientName) ?? new ClientContact
{
- Name = salesDetail.ClientName,
+ Name = clientSalesDetail.ClientName,
};
- userSheet.Cells[rowIndex, 1].Value2 = salesDetail.SalesName;
+ var productSalesList = clientSalesDetail.Details
+ .GroupBy(x => x.ProductNameEN)
+ .Select(grouped => new ImportContext.GroupedSalesDetailModel
+ {
+ SalesName = clientSalesDetail.SalesName,
+ ClientName = clientSalesDetail.ClientName,
+ ProductNameEN = grouped.Key,
+ TotalAmount = grouped.Sum(x => x.TotalAmount ?? 0),
+ Quantity = grouped.Sum(x => x.Quantity ?? 0),
+ Details = grouped.ToList()
+ });
+ rowIndex = WriteSalesDetailToSheet(userSheet, rowIndex, clientContact, productSalesList);
+
+ // 客户销量汇总
+ var totalSales = new List()
+ {
+ new ImportContext.GroupedSalesDetailModel
+ {
+ SalesName = clientSalesDetail.SalesName,
+ ClientName = clientSalesDetail.ClientName,
+ ProductNameEN = "總銷售額",
+ TotalAmount = clientSalesDetail.TotalAmount,
+ Quantity = clientSalesDetail.Quantity,
+ Details = clientSalesDetail.Details.Aggregate(
+ new List(),
+ (accDetail, curDetail) => {
+ var monthSales = accDetail.FirstOrDefault(x => x.Month == curDetail.Month);
+ if (monthSales == null)
+ {
+ monthSales = new SalesDetail
+ {
+ Month = curDetail.Month,
+ SalesName = curDetail.SalesName,
+ ProductNameEN = "總銷售額",
+ Quantity = 0,
+ Tax = 0,
+ TotalAmount = 0,
+ PriceWithTax = 0,
+ AmountWithoutTax = 0
+ };
+ accDetail.Add(monthSales);
+ }
+
+ monthSales.Quantity += curDetail.Quantity;
+ monthSales.Tax += curDetail.Tax;
+ monthSales.TotalAmount += curDetail.TotalAmount;
+ //monthSales.PriceWithTax += curDetail.PriceWithTax;
+ monthSales.AmountWithoutTax += curDetail.AmountWithoutTax;
+
+ return accDetail;
+ })
+ }
+ };
+
+ rowIndex = WriteSalesDetailToSheet(userSheet, rowIndex, clientContact, totalSales);
+ }
+
+ FormatSheetStyle(userSheet);
+ }
+
+ private static int WriteSalesDetailToSheet(Worksheet userSheet, int rowIndex, ClientContact clientContact, IEnumerable salesDetailList)
+ {
+ foreach (var productSalesDetail in salesDetailList)
+ {
+ userSheet.Cells[rowIndex, 1].Value2 = productSalesDetail.SalesName;
userSheet.Cells[rowIndex, 2].Value2 = clientContact.Region;
userSheet.Cells[rowIndex, 3].Value2 = clientContact.Industry;
userSheet.Cells[rowIndex, 4].Value2 = clientContact.AnnualCapacity;
@@ -58,9 +261,57 @@ namespace KellyReport_D.Utils
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;
+ userSheet.Cells[rowIndex, 11].Value2 = productSalesDetail.ProductNameEN;
+
+ // 计算每月的数量和金额
+ int monthCol = 13; // L列是第12列
+ for (int i = 1; i < 13; i++)
+ {
+ int monthCounter = 0;
+ var monthDetail = productSalesDetail.Details.Where(x => x.Month == $"{i}月")
+ .Aggregate(new SalesDetail()
+ {
+ Month = $"{i}月",
+ Quantity = 0,
+ TotalAmount = 0,
+ PriceWithTax = 0,
+ AmountWithoutTax = 0,
+ Tax = 0
+ }, (accSalesModel, curSalesModel) =>
+ {
+ accSalesModel.Quantity += (curSalesModel.Quantity ?? 0);
+ accSalesModel.TotalAmount += (curSalesModel.TotalAmount ?? 0);
+ accSalesModel.PriceWithTax += (curSalesModel.PriceWithTax ?? 0);
+ monthCounter++;
+
+ return accSalesModel;
+ });
+ if (monthCounter > 1)
+ {
+ monthDetail.PriceWithTax = monthDetail.PriceWithTax / monthCounter;
+ }
+
+ if (monthDetail == null)
+ {
+ userSheet.Cells[rowIndex, monthCol + (i - 1) * 3].Value2 = 0; // 單價
+ userSheet.Cells[rowIndex, monthCol + (i - 1) * 3 + 1].Value2 = 0; // 數量
+ userSheet.Cells[rowIndex, monthCol + (i - 1) * 3 + 2].Value2 = 0; // 金額
+ }
+ else
+ {
+ userSheet.Cells[rowIndex, monthCol + (i - 1) * 3].Value2 = monthDetail.PriceWithTax ?? 0; // 單價
+ userSheet.Cells[rowIndex, monthCol + (i - 1) * 3 + 1].Value2 = monthDetail.Quantity ?? 0; // 數量
+ userSheet.Cells[rowIndex, monthCol + (i - 1) * 3 + 2].Value2 = monthDetail.TotalAmount ?? 0; // 总额
+ }
+ }
+ userSheet.Cells[rowIndex, 49].Value = productSalesDetail.Quantity;
+ userSheet.Cells[rowIndex, 50].Value = productSalesDetail.TotalAmount;
+
+
rowIndex++;
}
+
+ return rowIndex;
}
public static void PrepareTotalHeader(Worksheet userSheet)
@@ -126,36 +377,46 @@ namespace KellyReport_D.Utils
private static Worksheet GenUserSalesDetailSheet(
- Model.ImportContext context,
- Model.ImportContext.GroupedSalesDetailModel groupedSalesDetail
+ ImportContext context,
+ ImportContext.GroupedSalesDetailModel groupedSalesDetail
)
{
var app = context.Application;
var salesName = groupedSalesDetail.SalesName ?? "UNKONW";
string sheetName = $"JQ Total({salesName.ToUpper()})";
- Worksheet userSheet = null;
-
- try
+ Worksheet userSheet = CreateSheetIfNotExisted(app, sheetName);
+ Range usedRange = userSheet.UsedRange;
+ if (usedRange != null && usedRange.Cells.Count > 1)
{
- // 新建工作表并命名
- userSheet = app.Worksheets.Add();
- userSheet.Name = sheetName;
+ usedRange.Clear();
}
- catch
+
+ return userSheet;
+ }
+
+ private static Worksheet CreateSheetIfNotExisted(Microsoft.Office.Interop.Excel.Application app, string sheetName)
+ {
+ Worksheet userSheet = null;
+ foreach (Worksheet item in app.Worksheets)
+ {
+ if (item.Name == sheetName)
+ {
+ userSheet = item;
+ break;
+ }
+ };
+
+ if (userSheet == null)
{
- // 已存在则获取
- userSheet = app.Worksheets[sheetName] as Worksheet;
try
{
- Range usedRange = userSheet.UsedRange;
- if (usedRange != null && usedRange.Cells.Count > 1)
- {
- usedRange.Clear();
- }
+ // 新建工作表并命名
+ userSheet = app.Worksheets.Add();
+ userSheet.Name = sheetName;
}
catch
{
- // 无 UsedRange 可忽略
+ throw new FormatException("创建或获取用户工作表失败,请检查是否存在同名工作表。");
}
}
@@ -176,7 +437,7 @@ namespace KellyReport_D.Utils
{
SalesDetail item = new SalesDetail
{
- SalesName = rawSalesDetailData[i, 1]?.ToString() ?? "",
+ SalesName = rawSalesDetailData[i, 1]?.ToString() ?? "UNKNOWN",
Month = rawSalesDetailData[i, 2]?.ToString() ?? "",
InvoiceDate = rawSalesDetailData[i, 3] is double invoiceDate ? DateTime.FromOADate(invoiceDate) : (DateTime?)null,
OrderNumber = rawSalesDetailData[i, 4]?.ToString() ?? "",
@@ -233,9 +494,9 @@ namespace KellyReport_D.Utils
try
{
// 获取「銷售年度預估」工作表
- readSalesForecastData(context);
+ ReadSalesForecastData(context);
// 获取「產品年度預估」工作表
- readProductForecastData(context);
+ ReadProductForecastData(context);
GenBussenessSheet(context);
}
@@ -361,7 +622,7 @@ namespace KellyReport_D.Utils
}
- private static void readClientContact(ImportContext context)
+ private static void ReadClientContact(ImportContext context)
{
var app = context.Application;
@@ -396,7 +657,7 @@ namespace KellyReport_D.Utils
context.ClientContactList = clientContactList;
}
- private static void readProductForecastData(GenForecaseContext context)
+ private static void ReadProductForecastData(GenForecaseContext context)
{
var app = context.Application;
@@ -434,7 +695,7 @@ namespace KellyReport_D.Utils
context.ProductForecastList = productForecastList;
}
- private static void readSalesForecastData(GenForecaseContext context)
+ private static void ReadSalesForecastData(GenForecaseContext context)
{
var app = context.Application;