部门统计和产品汇总

This commit is contained in:
earo.lau 2025-09-21 15:40:06 +08:00
parent 4ce03e8fda
commit c3f2d905cf
2 changed files with 310 additions and 5 deletions

View File

@ -34,7 +34,7 @@
<PublishUrl>publish\</PublishUrl>
<InstallUrl />
<TargetCulture>zh-chs</TargetCulture>
<ApplicationVersion>1.0.0.2</ApplicationVersion>
<ApplicationVersion>1.0.0.4</ApplicationVersion>
<AutoIncrementApplicationRevision>true</AutoIncrementApplicationRevision>
<UpdateEnabled>true</UpdateEnabled>
<UpdateInterval>7</UpdateInterval>

View File

@ -38,6 +38,9 @@ namespace KellyReport_D.Utils
// 更新业务预估表
UpdateEstimatedTable(importContext);
UpdateDeptartmentSummary(importContext);
GenProductSummarySheet(importContext);
}
private static void UpdateEstimatedTable(ImportContext importContext)
@ -523,9 +526,9 @@ namespace KellyReport_D.Utils
{
SalesName = rawSalesDetailData[i, 1]?.ToString() ?? "UNKNOWN",
Month = rawSalesDetailData[i, 2]?.ToString() ?? "",
InvoiceDate = rawSalesDetailData[i, 3] is double invoiceDate ? DateTime.FromOADate(invoiceDate) : (DateTime?)null,
DeliveryDate = 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,
InvoiceDate = rawSalesDetailData[i, 5] != null ? DateTime.Parse(rawSalesDetailData[i, 5]?.ToString()) : (DateTime?)null,
InvoiceNumber = rawSalesDetailData[i, 6]?.ToString() ?? "",
ClientName = rawSalesDetailData[i, 7]?.ToString() ?? "",
ProductNameEN = rawSalesDetailData[i, 8]?.ToString() ?? "",
@ -562,7 +565,7 @@ namespace KellyReport_D.Utils
return null;
}
public static async void GenForecast(System.Windows.Forms.Button button)
public static void GenForecast(System.Windows.Forms.Button button)
{
String originLabel = button.Text;
if (button != null)
@ -580,7 +583,8 @@ namespace KellyReport_D.Utils
// 获取「銷售年度預估」工作表
ReadSalesForecastData(context);
// 获取「產品年度預估」工作表
ReadProductForecastData(context);
//ReadProductForecastData(context);
GenDepartmentSummary(context);
GenBussenessSheet(context);
}
@ -839,5 +843,306 @@ namespace KellyReport_D.Utils
context.SalesForecastList = salesForecastInputList;
context.MonthData = monthData;
}
public static void GenProductSummarySheet(ImportContext context)
{
var app = context.Application;
string sheetName = $"產品年度預估";
Worksheet productSheet = CreateSheetIfNotExisted(app, sheetName);
productSheet.Activate();
var yearList = context.SalesDetails
.Where(x => x.InvoiceDate.HasValue)
.Select(x => x.InvoiceDate.Value.Year)
.Distinct()
.ToList();
yearList.ForEach(yearNumber =>
{
Range usedRange = productSheet.UsedRange;
Range turnOverRange = usedRange.Find(What: $"{yearNumber}-Turnover", LookIn: XlFindLookIn.xlValues, LookAt: XlLookAt.xlWhole, SearchOrder: XlSearchOrder.xlByRows, SearchDirection: XlSearchDirection.xlNext, MatchCase: false);
if (turnOverRange == null)
{
Range estimateRange = usedRange.Find(What: $"{yearNumber}-Estimate", LookIn: XlFindLookIn.xlValues, LookAt: XlLookAt.xlWhole, SearchOrder: XlSearchOrder.xlByRows, SearchDirection: XlSearchDirection.xlNext, MatchCase: false);
int insertCol = 2;
if (estimateRange != null)
{
insertCol = estimateRange.Column;
}
Range insertRange = productSheet.Columns[$"{GetColumnLetter(insertCol)}:{GetColumnLetter(insertCol + 5)}"];
insertRange.EntireColumn.Insert(XlInsertShiftDirection.xlShiftToRight);
insertRange = productSheet.Columns[$"{GetColumnLetter(insertCol)}:{GetColumnLetter(insertCol + 5)}"];
insertRange.ClearFormats();
productSheet.Cells[1, insertCol].Value2 = $"{yearNumber}-Turnover";
productSheet.Cells[2, insertCol].Value2 = "數量";
productSheet.Cells[2, insertCol + 1].Value2 = "金額(含稅)";
productSheet.Cells[2, insertCol + 2].Value2 = "金額(未稅)";
productSheet.Cells[2, insertCol + 3].Value2 = "平均單價";
productSheet.Cells[2, insertCol + 4].Value2 = "成長率";
var growthRange = productSheet.Range[
productSheet.Cells[2, insertCol + 4],
productSheet.Cells[2, insertCol + 5]
];
growthRange.Merge();
turnOverRange = productSheet.Range[
productSheet.Cells[1, insertCol],
productSheet.Cells[1, insertCol + 5]
];
turnOverRange.Merge();
}
var productSalesList = context.SalesDetails
.Where(x => x.InvoiceDate.HasValue && x.InvoiceDate.Value.Year == yearNumber)
.GroupBy(x => x.ProductNameEN)
.Select(grouped => new ImportContext.GroupedSalesDetailModel()
{
ProductNameEN = grouped.Key,
Quantity = grouped.Sum(x => x.Quantity ?? 0),
TotalAmount = grouped.Sum(x => x.TotalAmount ?? 0),
Details = grouped.ToList()
})
.ToList();
Range totalRange = usedRange.Find(What: $"總計", LookIn: XlFindLookIn.xlValues, LookAt: XlLookAt.xlWhole, SearchOrder: XlSearchOrder.xlByRows, SearchDirection: XlSearchDirection.xlNext, MatchCase: false);
int totalRowCount = usedRange.Rows.Count + 1;
if (totalRange != null)
{
totalRowCount = totalRange.Row;
}
int startColIndex = turnOverRange.Column;
var quantityColLetter = GetColumnLetter(startColIndex);
var amountColLetter = GetColumnLetter(startColIndex + 1);
var amountNoTaxColLetter = GetColumnLetter(startColIndex + 2);
var prevQuantityColLetter = GetColumnLetter(startColIndex + 6);
var prevAmountColLetter = GetColumnLetter(startColIndex + 7);
var prevAmountNoTaxColLetter = GetColumnLetter(startColIndex + 8);
foreach (var productSalesSummary in productSalesList)
{
var curProductName = productSalesSummary.ProductNameEN;
// look for the product row
// if not exists then create a new row
Range productRange = usedRange.Find(
What: curProductName,
LookIn: XlFindLookIn.xlValues,
LookAt: XlLookAt.xlWhole,
SearchOrder: XlSearchOrder.xlByRows,
SearchDirection: XlSearchDirection.xlNext,
MatchCase: false
);
if (productRange == null)
{
productSheet.Rows[totalRowCount].Insert();
productSheet.Cells[totalRowCount, 1].Value2 = curProductName;
productRange = productSheet.Cells[totalRowCount, 1];
totalRowCount += 1;
}
int curRowIndex = productRange.Row;
productSheet.Cells[curRowIndex, startColIndex].Value2 = productSalesSummary.Quantity;
productSheet.Cells[curRowIndex, startColIndex + 1].Value2 = productSalesSummary.TotalAmount;
productSheet.Cells[curRowIndex, startColIndex + 2].formula = $"={amountColLetter}{curRowIndex}/1.13";
productSheet.Cells[curRowIndex, startColIndex + 3].formula = $"={amountColLetter}{curRowIndex}/${quantityColLetter}{curRowIndex}";
productSheet.Cells[curRowIndex, startColIndex + 4].formula = $"={quantityColLetter}{curRowIndex}/${prevQuantityColLetter}{curRowIndex}";
productSheet.Cells[curRowIndex, startColIndex + 5].formula = $"={amountColLetter}{curRowIndex}/${prevAmountColLetter}{curRowIndex}";
productSheet.Cells[curRowIndex, startColIndex + 4].NumberFormat = "0.00%";
productSheet.Cells[curRowIndex, startColIndex + 5].NumberFormat = "0.00%";
}
productSheet.Cells[totalRowCount, 1].Value2 = "總計";
productSheet.Cells[totalRowCount, startColIndex].formula = $"=SUM({quantityColLetter}5:{quantityColLetter}{totalRowCount - 1})";
productSheet.Cells[totalRowCount, startColIndex + 1].formula = $"=SUM({amountColLetter}5:{amountColLetter}{totalRowCount - 1})";
productSheet.Cells[totalRowCount, startColIndex + 2].formula = $"=SUM({amountNoTaxColLetter}5:{amountNoTaxColLetter}{totalRowCount - 1})";
productSheet.Cells[totalRowCount + 1, 1].Value2 = "備註";
productSheet.Cells[totalRowCount + 1, startColIndex].formula = $"={quantityColLetter}{totalRowCount}/{prevQuantityColLetter}{totalRowCount}";
productSheet.Cells[totalRowCount + 1, startColIndex + 1].formula = $"={amountColLetter}{totalRowCount}/{prevAmountColLetter}{totalRowCount}";
productSheet.Cells[totalRowCount + 1, startColIndex + 2].formula = $"={amountNoTaxColLetter}{totalRowCount}/{prevAmountNoTaxColLetter}{totalRowCount}";
productSheet.Cells[totalRowCount + 1, startColIndex].NumberFormat = "0.00%";
productSheet.Cells[totalRowCount + 1, startColIndex + 1].NumberFormat = "0.00%";
productSheet.Cells[totalRowCount + 1, startColIndex + 2].NumberFormat = "0.00%";
});
FormatSheetStyle(productSheet);
}
public static void GenDepartmentSummary(GenForecaseContext context)
{
var app = context.Application;
string sheetName = $"部门统计";
Worksheet deptSheet = CreateSheetIfNotExisted(app, sheetName);
deptSheet.Activate();
deptSheet.Cells[1, 1].Value2 = "鈞全";
deptSheet.Range[deptSheet.Cells[1, 1], deptSheet.Cells[2, 1]].Merge();
var yearList = context.SalesForecastList
.Select(x => x.Year)
.Distinct()
.ToList();
Range initUsedRange = deptSheet.UsedRange;
Range totalRange = initUsedRange.Find(What: $"Total", LookIn: XlFindLookIn.xlValues, LookAt: XlLookAt.xlWhole, SearchOrder: XlSearchOrder.xlByRows, SearchDirection: XlSearchDirection.xlNext, MatchCase: false);
int totalRowIndex = initUsedRange.Rows.Count + 1;
if (totalRange != null)
{
totalRowIndex = totalRange.Row;
}
yearList.ForEach(yearNumber =>
{
Range curYearRange = deptSheet.UsedRange.Find(What: $"{yearNumber}", LookIn: XlFindLookIn.xlValues, LookAt: XlLookAt.xlWhole, SearchOrder: XlSearchOrder.xlByRows, SearchDirection: XlSearchDirection.xlNext, MatchCase: false);
int startCol = deptSheet.UsedRange.Column + 1;
if (curYearRange != null)
{
startCol = curYearRange.Column;
}
var startColLetter = GetColumnLetter(startCol);
var endColLetter = GetColumnLetter(startCol + 3);
Range prevYearRange = deptSheet.UsedRange.Find(What: $"{yearNumber - 1}", LookIn: XlFindLookIn.xlValues, LookAt: XlLookAt.xlWhole, SearchOrder: XlSearchOrder.xlByRows, SearchDirection: XlSearchDirection.xlNext, MatchCase: false);
int prevStartCol = 0;
string prevForecastColLetter = "";
string prevTurnoverColLetter = "";
if (prevYearRange != null)
{
prevStartCol = prevYearRange.Column;
prevForecastColLetter = GetColumnLetter(prevStartCol);
prevTurnoverColLetter = GetColumnLetter(prevStartCol + 1);
}
deptSheet.Range[$"{startColLetter}:{endColLetter}"]
.EntireColumn
.Insert(XlInsertShiftDirection.xlShiftToRight);
deptSheet.Cells[1, 2].Value2 = $"{yearNumber}";
deptSheet.Range[deptSheet.Cells[1, startCol], deptSheet.Cells[1, startCol + 3]].Merge();
deptSheet.Cells[2, startCol].Value2 = "Forecast";
deptSheet.Cells[2, startCol + 1].Value2 = "Turnover";
deptSheet.Cells[2, startCol + 2].Value2 = "成長率";
deptSheet.Cells[2, startCol + 3].Value2 = "達成率";
var forcastColLetter = startColLetter;
var turnoverColLetter = GetColumnLetter(startCol + 1);
foreach (var salesForecast in context.SalesForecastList.Where(x => x.Name.ToUpper() != "TOTAL"))
{
var salesName = salesForecast.Name;
Range curUsedRange = deptSheet.UsedRange;
Range salesNameRange = curUsedRange.Find(What: $"{salesName}", LookIn: XlFindLookIn.xlValues, LookAt: XlLookAt.xlWhole, SearchOrder: XlSearchOrder.xlByRows, SearchDirection: XlSearchDirection.xlNext, MatchCase: false);
if (salesNameRange == null)
{
deptSheet.Rows[totalRowIndex].Insert();
deptSheet.Cells[curUsedRange.Rows.Count + 1, 1].Value2 = salesName;
salesNameRange = deptSheet.Cells[curUsedRange.Rows.Count + 1, 1];
totalRowIndex++;
}
deptSheet.Cells[salesNameRange.Row, startCol].Value2 = salesForecast.Total;
if (prevYearRange != null)
{
deptSheet.Cells[salesNameRange.Row, startCol + 2].formula = $"=SUM({forcastColLetter}{salesNameRange.Row} - {prevTurnoverColLetter}{salesNameRange.Row})/{forcastColLetter}{salesNameRange.Row}";
deptSheet.Cells[salesNameRange.Row, startCol + 2].NumberFormat = "0.00%";
}
deptSheet.Cells[salesNameRange.Row, startCol + 3].formula = $"={turnoverColLetter}{salesNameRange.Row}/{forcastColLetter}{salesNameRange.Row}";
deptSheet.Cells[salesNameRange.Row, startCol + 3].NumberFormat = "0.00%";
}
deptSheet.Cells[totalRowIndex, 1].Value2 = "Total";
deptSheet.Cells[totalRowIndex, startCol].formula = $"=SUM({forcastColLetter}3:{forcastColLetter}{totalRowIndex - 1})";
deptSheet.Cells[totalRowIndex, startCol + 1].formula = $"=SUM({turnoverColLetter}3:{turnoverColLetter}{totalRowIndex - 1})";
if (prevYearRange != null)
{
deptSheet.Cells[totalRowIndex, startCol + 2].formula = $"=SUM({forcastColLetter}{totalRowIndex} - {prevTurnoverColLetter}{totalRowIndex})/{forcastColLetter}{totalRowIndex}";
deptSheet.Cells[totalRowIndex, startCol + 2].NumberFormat = "0.00%";
}
deptSheet.Cells[totalRowIndex, startCol + 3].formula = $"={turnoverColLetter}{totalRowIndex}/{forcastColLetter}{totalRowIndex}";
deptSheet.Cells[totalRowIndex, startCol + 3].NumberFormat = "0.00%";
});
FormatSheetStyle(deptSheet);
}
public static void UpdateDeptartmentSummary(ImportContext context)
{
var app = context.Application;
string sheetName = $"部门统计";
Worksheet deptSheet = CreateSheetIfNotExisted(app, sheetName);
deptSheet.Activate();
var yearList = context.SalesDetails.Where(x => x.InvoiceDate.HasValue).Select(x => x.InvoiceDate.Value.Year).Distinct().ToList();
yearList.ForEach(yearoNumber =>
{
Range yearRange = deptSheet.UsedRange.Find(What: $"{yearoNumber}", LookIn: XlFindLookIn.xlValues, LookAt: XlLookAt.xlWhole, SearchOrder: XlSearchOrder.xlByRows, SearchDirection: XlSearchDirection.xlNext, MatchCase: false);
if (yearRange == null)
{
Console.WriteLine("Cannot find year column in department summary: {0}", yearoNumber);
return;
}
var startCol = yearRange.Column;
var startColLetter = GetColumnLetter(startCol);
var turnoverColLetter = GetColumnLetter(startCol + 1);
Range totalRange = deptSheet.UsedRange.Find(What: $"Total", LookIn: XlFindLookIn.xlValues, LookAt: XlLookAt.xlWhole, SearchOrder: XlSearchOrder.xlByRows, SearchDirection: XlSearchDirection.xlNext, MatchCase: false);
int totalRowIndex = deptSheet.UsedRange.Rows.Count + 1;
if (totalRange != null)
{
totalRowIndex = totalRange.Row;
}
var salesDetails = context.SalesDetails
.Where(x => x.InvoiceDate.HasValue && x.InvoiceDate.Value.Year == yearoNumber && x.SalesName.ToUpper() != "TOTAL")
.GroupBy(x => x.SalesName)
.Select(grouped => new
{
SalesName = grouped.Key,
Turnover = grouped.Sum(x => x.TotalAmount ?? 0)
})
.ToList();
foreach (var salesDetail in salesDetails)
{
var salesName = salesDetail.SalesName;
Range curUsedRange = deptSheet.UsedRange;
Range salesNameRange = curUsedRange.Find(What: $"{salesName}", LookIn: XlFindLookIn.xlValues, LookAt: XlLookAt.xlWhole, SearchOrder: XlSearchOrder.xlByRows, SearchDirection: XlSearchDirection.xlNext, MatchCase: false);
if (salesNameRange != null)
{
deptSheet.Cells[salesNameRange.Row, startCol + 1].Value2 = salesDetail.Turnover;
}
}
deptSheet.Cells[totalRowIndex, startCol + 1].formula = $"=SUM({turnoverColLetter}3:{turnoverColLetter}{totalRowIndex - 1})";
});
}
}
}