1149 lines
54 KiB
C#
1149 lines
54 KiB
C#
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;
|
||
|
||
namespace KellyReport_D.Utils
|
||
{
|
||
internal static class WorkBookUtils
|
||
{
|
||
public static void importSalesDetailFromWorkBook(Workbook workbook)
|
||
{
|
||
var importContext = new ImportContext()
|
||
{
|
||
Application = Globals.ThisAddIn.Application,
|
||
ImportWorkbook = workbook,
|
||
SalesWorksheets = new List<Worksheet>(),
|
||
};
|
||
|
||
// 获取「客户资料」工作表
|
||
ReadClientContact(importContext);
|
||
// 读取「销售明细」工作表
|
||
ReadSalesDetails(importContext);
|
||
foreach (var userGroupedSalesDetail in importContext.GroupedSalesDetailBySalesName)
|
||
{
|
||
var userSheet = GenUserSalesDetailSheet(importContext, userGroupedSalesDetail);
|
||
PrepareTotalHeader(userSheet);
|
||
WriteSalesDetailsData(importContext, userGroupedSalesDetail, userSheet);
|
||
|
||
importContext.SalesWorksheets.Add(userSheet);
|
||
}
|
||
|
||
GenSalesTotal(importContext);
|
||
|
||
// 更新业务预估表
|
||
UpdateEstimatedTable(importContext);
|
||
UpdateDeptartmentSummary(importContext);
|
||
|
||
GenProductSummarySheet(importContext);
|
||
}
|
||
|
||
private static void UpdateEstimatedTable(ImportContext importContext)
|
||
{
|
||
var app = importContext.Application;
|
||
Worksheet bussenessWorksheet = null;
|
||
|
||
foreach (Worksheet item in app.Worksheets)
|
||
{
|
||
if (item.Name == "業務月達成率")
|
||
{
|
||
bussenessWorksheet = item;
|
||
break;
|
||
}
|
||
};
|
||
|
||
if (bussenessWorksheet == null)
|
||
{
|
||
throw new EntryPointNotFoundException("未找到「業務月達成率」工作表,请先生成预估表。");
|
||
}
|
||
|
||
bussenessWorksheet.Activate();
|
||
Range usedRange = bussenessWorksheet.UsedRange;
|
||
int maxColIndex = usedRange.Columns.Count;
|
||
|
||
for (int i = 2; i < maxColIndex; i += 4)
|
||
{
|
||
String salesName = bussenessWorksheet.Cells[1, i].Value2;
|
||
if (string.IsNullOrWhiteSpace(salesName))
|
||
{
|
||
continue;
|
||
}
|
||
|
||
var salesDetails = salesName.ToUpper() == "TOTAL" ?
|
||
importContext.SalesDetails :
|
||
importContext.GroupedSalesDetailBySalesName.FirstOrDefault(x => x.SalesName.ToUpper() == salesName.ToUpper())?.Details;
|
||
|
||
if (salesDetails == null)
|
||
continue;
|
||
|
||
salesDetails.GroupBy(x => x.Month)
|
||
.Select(grouped => new
|
||
{
|
||
Month = grouped.Key,
|
||
TotalAmount = grouped.Sum(x => x.TotalAmount ?? 0),
|
||
})
|
||
.ToList()
|
||
.ForEach(monthlySales =>
|
||
{
|
||
int startRowIndex = 3;
|
||
for (int rowIndex = startRowIndex; rowIndex < startRowIndex + 12; rowIndex++)
|
||
{
|
||
var monthCell = bussenessWorksheet.Cells[rowIndex, 1];
|
||
if (monthCell.Value2 != null && monthCell.Value2.ToString() == monthlySales.Month)
|
||
{
|
||
var forecsastColLetter = GetColumnLetter(i);
|
||
|
||
var turnoverCell = bussenessWorksheet.Cells[rowIndex, i + 1];
|
||
var turnoverColLetter = GetColumnLetter(i + 1);
|
||
|
||
turnoverCell.Value2 = monthlySales.TotalAmount;
|
||
turnoverCell.NumberFormat = "#,##0";
|
||
|
||
var completionCell = bussenessWorksheet.Cells[rowIndex, i + 2];
|
||
completionCell.formula = $"={turnoverColLetter}{rowIndex}/{forecsastColLetter}{rowIndex}";
|
||
completionCell.NumberFormat = "0.00%";
|
||
|
||
var accCompletionCell = bussenessWorksheet.Cells[rowIndex, i + 3];
|
||
accCompletionCell.formula = $"=SUM(${turnoverColLetter}${startRowIndex}:{turnoverColLetter}{rowIndex})/SUM(${forecsastColLetter}${startRowIndex}:{forecsastColLetter}{rowIndex})";
|
||
accCompletionCell.NumberFormat = "0.00%";
|
||
|
||
break;
|
||
}
|
||
}
|
||
});
|
||
|
||
}
|
||
|
||
}
|
||
|
||
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);
|
||
|
||
totalWorksheet.Cells[4, 12].Select();
|
||
totalWorksheet.Application.ActiveWindow.FreezePanes = true;
|
||
}
|
||
|
||
private static void FormatSheetStyle(Worksheet worksheet)
|
||
{
|
||
worksheet.Activate();
|
||
|
||
// 自适应所有已用列宽
|
||
Range usedRange2 = worksheet.UsedRange;
|
||
if (usedRange2 != null)
|
||
{
|
||
usedRange2.Columns.AutoFit();
|
||
usedRange2.Borders.LineStyle = XlLineStyle.xlContinuous;
|
||
usedRange2.Borders.Weight = XlBorderWeight.xlThin;
|
||
}
|
||
}
|
||
|
||
|
||
// 列号转字母方法
|
||
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(
|
||
ImportContext context,
|
||
ImportContext.GroupedSalesDetailModel userGroupedSalesDetail,
|
||
Worksheet userSheet
|
||
)
|
||
{
|
||
int rowIndex = 4; // 从第四行开始写入数据
|
||
var clientSalesList = context.GetGroupedSalesDetailByClientName(userGroupedSalesDetail.Details);
|
||
foreach (var clientSalesDetail in clientSalesList)
|
||
{
|
||
ClientContact clientContact = context.ClientContactList.FirstOrDefault(x => x.Name == clientSalesDetail.ClientName) ?? new ClientContact
|
||
{
|
||
Name = clientSalesDetail.ClientName,
|
||
};
|
||
|
||
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<ImportContext.GroupedSalesDetailModel>()
|
||
{
|
||
new ImportContext.GroupedSalesDetailModel
|
||
{
|
||
SalesName = clientSalesDetail.SalesName,
|
||
ClientName = clientSalesDetail.ClientName,
|
||
ProductNameEN = "總銷售額",
|
||
TotalAmount = clientSalesDetail.TotalAmount,
|
||
Quantity = clientSalesDetail.Quantity,
|
||
Details = clientSalesDetail.Details.Aggregate(
|
||
new List<SalesDetail>(),
|
||
(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);
|
||
|
||
userSheet.Cells[4, 12].Select();
|
||
userSheet.Application.ActiveWindow.FreezePanes = true;
|
||
}
|
||
|
||
private static int WriteSalesDetailToSheet(Worksheet userSheet, int rowIndex, ClientContact clientContact, IEnumerable<ImportContext.GroupedSalesDetailModel> 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;
|
||
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 = 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)
|
||
{
|
||
// 合并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(
|
||
ImportContext context,
|
||
ImportContext.GroupedSalesDetailModel groupedSalesDetail
|
||
)
|
||
{
|
||
var app = context.Application;
|
||
var salesName = groupedSalesDetail.SalesName ?? "UNKONW";
|
||
string sheetName = $"JQ Total({salesName.ToUpper()})";
|
||
Worksheet userSheet = CreateSheetIfNotExisted(app, sheetName);
|
||
Range usedRange = userSheet.UsedRange;
|
||
if (usedRange != null && usedRange.Cells.Count > 1)
|
||
{
|
||
usedRange.Clear();
|
||
}
|
||
|
||
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)
|
||
{
|
||
try
|
||
{
|
||
// 新建工作表并命名
|
||
userSheet = app.Worksheets.Add();
|
||
userSheet.Name = sheetName;
|
||
}
|
||
catch
|
||
{
|
||
throw new FormatException("创建或获取用户工作表失败,请检查是否存在同名工作表。");
|
||
}
|
||
}
|
||
|
||
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() ?? "UNKNOWN",
|
||
Month = rawSalesDetailData[i, 2]?.ToString() ?? "",
|
||
DeliveryDate = rawSalesDetailData[i, 3] is double invoiceDate ? DateTime.FromOADate(invoiceDate) : (DateTime?)null,
|
||
OrderNumber = rawSalesDetailData[i, 4]?.ToString() ?? "",
|
||
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() ?? "",
|
||
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 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);
|
||
GenDepartmentSummary(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 = "@"; // 文本格式
|
||
|
||
int startRowIndex = 1;
|
||
// 填入月份
|
||
for (int i = 0; i < 12; i++)
|
||
{
|
||
int rowOffset = startRowIndex + 2;
|
||
sheet.Cells[i + rowOffset, 1] = $"{i + 1}月";
|
||
}
|
||
sheet.Cells[startRowIndex + 14, 1].value2 = "Total";
|
||
|
||
// B列开始填 salesName 及相关数据
|
||
int col = 2; // B列
|
||
foreach (var salesForcastData in context.SalesForecastList)
|
||
{
|
||
int rowIndex = startRowIndex; // 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 + 1, startCol + 2]
|
||
];
|
||
finishRange.Merge();
|
||
finishRange.Value2 = "完成%";
|
||
|
||
// 合并并填入“累積達成率”
|
||
Range accRange = sheet.Range[
|
||
sheet.Cells[rowIndex, startCol + 3],
|
||
sheet.Cells[rowIndex + 1, 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++;
|
||
}
|
||
var forecastColLetter = GetColumnLetter(col);
|
||
var turnoverColLetter = GetColumnLetter(col + 1);
|
||
|
||
sheet.Cells[rowIndex, col].formula = $"=SUM({forecastColLetter}{startRowIndex}:{forecastColLetter}{rowIndex - 1})";
|
||
sheet.Cells[rowIndex, col + 1].formula = $"=SUM({turnoverColLetter}{startRowIndex}:{turnoverColLetter}{rowIndex - 1})";
|
||
|
||
sheet.Cells[rowIndex, col + 2].formula = $"=SUM({turnoverColLetter}{rowIndex}/{forecastColLetter}{rowIndex})";
|
||
sheet.Cells[rowIndex, col + 2].NumberFormat = "0.00%";
|
||
|
||
col = endCol;
|
||
}
|
||
|
||
|
||
// 自适应所有已用列宽
|
||
FormatSheetStyle(sheet);
|
||
}
|
||
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;
|
||
}
|
||
|
||
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})";
|
||
});
|
||
}
|
||
}
|
||
}
|