优化Excel导入与年度预估表生成逻辑
- 客户/产品销售明细写入逻辑优化,支持动态插入产品行,合并单元格处理更严谨 - 销售明细导入支持“英文品名”列动态索引,兼容多种表格格式 - 启用产品年度预估表自动生成,支持“產品資料”批量导入 - 客户/产品查找新增特殊字符转义,查找更稳定 - “成長率”列标题改为“達成率” - 项目及程序集版本号提升
This commit is contained in:
parent
f839573712
commit
1d0d183d8a
@ -59,7 +59,7 @@ namespace KellyReport_D
|
||||
private void initForecastBtn_Click(object sender, EventArgs e)
|
||||
{
|
||||
WorkBookUtils.GenForecast(this.initForecastBtn);
|
||||
MessageBox.Show("生成年度预估表完成", "完成", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
MessageBox.Show("生成年度預估表完成", "完成", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
}
|
||||
|
||||
private void importSalesBtn_Click(object sender, EventArgs e)
|
||||
@ -68,21 +68,27 @@ namespace KellyReport_D
|
||||
|
||||
if (workBook == null)
|
||||
{
|
||||
MessageBox.Show("未选择文件或文件打开失败,请重试。", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
MessageBox.Show("未選擇文件或者文件無法打開,請重試。", "錯誤", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
String originLabel = this.importSalesBtn.Text;
|
||||
this.importSalesBtn.Text = Resources.GENERATING;
|
||||
|
||||
try
|
||||
{
|
||||
WorkBookUtils.ImportSalesDetailFromWorkBook(workBook);
|
||||
MessageBox.Show("導入銷售表完成", "完成", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show($"导入过程中发生错误:{ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
FileLogger.Error($"導入銷售表错误!", ex);
|
||||
MessageBox.Show($"導入銷售表過程中發生錯誤:{ex.Message}", "錯誤", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
}
|
||||
finally
|
||||
{
|
||||
workBook.Close(false); // 关闭工作簿
|
||||
this.importSalesBtn.Text = originLabel;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -34,7 +34,7 @@
|
||||
<PublishUrl>publish\</PublishUrl>
|
||||
<InstallUrl />
|
||||
<TargetCulture>zh-chs</TargetCulture>
|
||||
<ApplicationVersion>1.0.0.7</ApplicationVersion>
|
||||
<ApplicationVersion>1.0.0.9</ApplicationVersion>
|
||||
<AutoIncrementApplicationRevision>true</AutoIncrementApplicationRevision>
|
||||
<UpdateEnabled>true</UpdateEnabled>
|
||||
<UpdateInterval>7</UpdateInterval>
|
||||
|
||||
@ -34,5 +34,5 @@ using System.Security;
|
||||
// 方法是按如下所示使用“*”: :
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.6")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.8")]
|
||||
|
||||
|
||||
@ -375,27 +375,46 @@ namespace KellyReport_D.Utils
|
||||
}).ToList();
|
||||
|
||||
Range salesNameCell = userSheet.Cells[clientSalesRowIndex, 1];
|
||||
int curRowCount = 1;
|
||||
int clientSalesRowCount = productSalesList.Count + 1;
|
||||
int curRowCount = productSalesList.Count + 1;
|
||||
|
||||
if (salesNameCell.MergeCells)
|
||||
{
|
||||
Range mergedCell = salesNameCell.MergeArea;
|
||||
curRowCount = mergedCell.Rows.Count;
|
||||
}
|
||||
// 添加行数
|
||||
if (curRowCount < clientSalesRowCount)
|
||||
{
|
||||
for (var i = 0; i < clientSalesRowCount - curRowCount; i++)
|
||||
|
||||
foreach (var productSales in productSalesList)
|
||||
{
|
||||
userSheet.Rows[clientSalesRowIndex + curRowCount - 1].Insert(XlInsertShiftDirection.xlShiftDown);
|
||||
Range productNameRows = userSheet.Range[
|
||||
userSheet.Cells[mergedCell.Row, 11],
|
||||
userSheet.Cells[mergedCell.Row + curRowCount - 1, 11]
|
||||
];
|
||||
var targetProductName = productNameRows.Find(What: productSales.ProductNameEN, LookIn: XlFindLookIn.xlValues, LookAt: XlLookAt.xlWhole, SearchOrder: XlSearchOrder.xlByRows, SearchDirection: XlSearchDirection.xlNext, MatchCase: false);
|
||||
|
||||
if (targetProductName == null)
|
||||
{
|
||||
// 原有客户,新增产品行
|
||||
userSheet.Rows[clientSalesRowIndex + curRowCount - 1].Insert(XlInsertShiftDirection.xlShiftDown);
|
||||
|
||||
curRowCount++;
|
||||
summaryRowIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var productSales in productSalesList)
|
||||
{
|
||||
// 新的客户行
|
||||
userSheet.Rows[clientSalesRowIndex + 1].Insert(XlInsertShiftDirection.xlShiftDown);
|
||||
summaryRowIndex++;
|
||||
}
|
||||
}
|
||||
salesNameCell.Value2 = clientSalesDetail.SalesName;
|
||||
int totalRowIndex = clientSalesRowIndex + clientSalesRowCount - 1;
|
||||
userSheet.Range[userSheet.Cells[clientSalesRowIndex, 1], userSheet.Cells[totalRowIndex, 1]].Merge();
|
||||
int totalRowIndex = clientSalesRowIndex + curRowCount - 1;
|
||||
Range clientNameRange = userSheet.Range[userSheet.Cells[clientSalesRowIndex, 1], userSheet.Cells[totalRowIndex, 1]];
|
||||
clientNameRange.Merge();
|
||||
|
||||
WriteSalesDetailToSheet(userSheet, clientSalesRowIndex, yearColIndex, clientContact, productSalesList);
|
||||
WriteSalesDetailToSheet(userSheet, clientNameRange, clientSalesRowIndex, yearColIndex, clientContact, productSalesList);
|
||||
// 客户销量汇总
|
||||
var totalSales = new List<ImportContext.GroupedSalesDetailModel>()
|
||||
{
|
||||
@ -437,7 +456,7 @@ namespace KellyReport_D.Utils
|
||||
}
|
||||
};
|
||||
|
||||
WriteSalesDetailToSheet(userSheet, totalRowIndex, yearColIndex, clientContact, totalSales);
|
||||
WriteSalesDetailToSheet(userSheet, clientNameRange, totalRowIndex, yearColIndex, clientContact, totalSales);
|
||||
}
|
||||
|
||||
// 计算总结
|
||||
@ -459,11 +478,11 @@ namespace KellyReport_D.Utils
|
||||
userSheet.Application.ActiveWindow.FreezePanes = true;
|
||||
}
|
||||
|
||||
private static int WriteSalesDetailToSheet(Worksheet userSheet, int rowIndex, int yearColIndex, ClientContact clientContact, IEnumerable<ImportContext.GroupedSalesDetailModel> salesDetailList)
|
||||
private static int WriteSalesDetailToSheet(Worksheet userSheet, Range clientNameRange, int rowIndex, int yearColIndex, ClientContact clientContact, IEnumerable<ImportContext.GroupedSalesDetailModel> salesDetailList)
|
||||
{
|
||||
Range productNamesCellRange = userSheet.Range[
|
||||
userSheet.Cells[rowIndex, 11],
|
||||
userSheet.Cells[rowIndex + salesDetailList.Count(), 11]
|
||||
userSheet.Cells[clientNameRange.Row, 11],
|
||||
userSheet.Cells[clientNameRange.Row + clientNameRange.Rows.Count - 1, 11]
|
||||
];
|
||||
|
||||
foreach (var productSalesDetail in salesDetailList)
|
||||
@ -472,7 +491,6 @@ namespace KellyReport_D.Utils
|
||||
// 如果存在相同产品名称,则写入对应行
|
||||
if (productSalesDetail.ProductNameEN != "總銷售額")
|
||||
{
|
||||
|
||||
var targetProductCell = productNamesCellRange.Find(What: productSalesDetail.ProductNameEN, LookIn: XlFindLookIn.xlValues, LookAt: XlLookAt.xlWhole, SearchOrder: XlSearchOrder.xlByRows, SearchDirection: XlSearchDirection.xlNext, MatchCase: false);
|
||||
if (targetProductCell != null)
|
||||
{
|
||||
@ -516,6 +534,7 @@ namespace KellyReport_D.Utils
|
||||
userSheet.Cells[currentRowIndex, 9].Value2 = clientContact.PurchaserPhone;
|
||||
userSheet.Cells[currentRowIndex, 10].Value2 = clientContact.Address;
|
||||
userSheet.Cells[currentRowIndex, 11].Value2 = productSalesDetail.ProductNameEN;
|
||||
userSheet.Cells[currentRowIndex, 11].NumberFormat = "@";
|
||||
|
||||
// 计算每月的数量和金额
|
||||
int monthCol = yearColIndex;
|
||||
@ -640,8 +659,8 @@ namespace KellyReport_D.Utils
|
||||
userSheet.Cells[3, startCol + 37].Value2 = "總金額";
|
||||
|
||||
// 设置所有已用单元格居中
|
||||
Range usedRange = userSheet.UsedRange;
|
||||
usedRange.HorizontalAlignment = XlHAlign.xlHAlignCenter;
|
||||
Range headerRange = userSheet.Rows["1:3"];
|
||||
headerRange.HorizontalAlignment = XlHAlign.xlHAlignCenter;
|
||||
|
||||
return startCol;
|
||||
}
|
||||
@ -721,6 +740,8 @@ namespace KellyReport_D.Utils
|
||||
{
|
||||
int rowCount = rawSalesDetailData.GetLength(0);
|
||||
int colCount = rawSalesDetailData.GetLength(1);
|
||||
int colProductNameENIndex = rawSalesDetailData[2, 8].ToString() == "英文品名" ? 8 : 9;
|
||||
|
||||
|
||||
for (int i = 3; i <= rowCount; i++)
|
||||
{
|
||||
@ -733,13 +754,13 @@ namespace KellyReport_D.Utils
|
||||
InvoiceDate = ResolveExcelDate(rawSalesDetailData[i, 5]),
|
||||
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() ?? "",
|
||||
ProductNameEN = rawSalesDetailData[i, colProductNameENIndex]?.ToString() ?? "",
|
||||
Quantity = rawSalesDetailData[i, 9] != null ? Convert.ToDecimal(rawSalesDetailData[i, colProductNameENIndex + 1]) : (decimal?)null,
|
||||
PriceWithTax = rawSalesDetailData[i, 10] != null ? Convert.ToDecimal(rawSalesDetailData[i, colProductNameENIndex + 2]) : (decimal?)null,
|
||||
AmountWithoutTax = rawSalesDetailData[i, 11] != null ? Convert.ToDecimal(rawSalesDetailData[i, colProductNameENIndex + 3]) : (decimal?)null,
|
||||
Tax = rawSalesDetailData[i, 12] != null ? Convert.ToDecimal(rawSalesDetailData[i, colProductNameENIndex + 4]) : (decimal?)null,
|
||||
TotalAmount = rawSalesDetailData[i, 13] != null ? Convert.ToDecimal(rawSalesDetailData[i, colProductNameENIndex + 5]) : (decimal?)null,
|
||||
Remark = rawSalesDetailData[i, colProductNameENIndex + 6]?.ToString() ?? "",
|
||||
};
|
||||
salesDatailList.Add(item);
|
||||
}
|
||||
@ -789,7 +810,7 @@ namespace KellyReport_D.Utils
|
||||
// 获取「銷售年度預估」工作表
|
||||
ReadSalesForecastData(context);
|
||||
// 获取「產品年度預估」工作表
|
||||
// GenProductForecastData(context);
|
||||
GenProductForecastData(context);
|
||||
GenDepartmentSummary(context);
|
||||
|
||||
GenBussenessSheet(context);
|
||||
@ -965,6 +986,8 @@ namespace KellyReport_D.Utils
|
||||
var app = context.Application;
|
||||
|
||||
var clientContactSheet = app.Worksheets["客戶資料"] as Worksheet;
|
||||
clientContactSheet.Activate();
|
||||
|
||||
var clientContactRange = clientContactSheet.UsedRange;
|
||||
IList<ClientContact> clientContactList = new List<ClientContact>();
|
||||
|
||||
@ -1086,7 +1109,7 @@ namespace KellyReport_D.Utils
|
||||
productSheet.Cells[2, insertCol + 1].Value2 = "金額(含稅)";
|
||||
productSheet.Cells[2, insertCol + 2].Value2 = "金額(未稅)";
|
||||
productSheet.Cells[2, insertCol + 3].Value2 = "平均單價";
|
||||
productSheet.Cells[2, insertCol + 4].Value2 = "成長率";
|
||||
productSheet.Cells[2, insertCol + 4].Value2 = "達成率";
|
||||
var growthRange = productSheet.Range[
|
||||
productSheet.Cells[2, insertCol + 4],
|
||||
productSheet.Cells[2, insertCol + 5]
|
||||
@ -1147,6 +1170,7 @@ namespace KellyReport_D.Utils
|
||||
{
|
||||
productSheet.Rows[totalRowCount].Insert();
|
||||
productSheet.Cells[totalRowCount, 1].Value2 = curProductName;
|
||||
productSheet.Cells[totalRowCount, 1].NumberFormat = "@";
|
||||
productRange = productSheet.Cells[totalRowCount, 1];
|
||||
|
||||
totalRowCount += 1;
|
||||
@ -1183,6 +1207,19 @@ namespace KellyReport_D.Utils
|
||||
|
||||
FormatSheetStyle(productSheet);
|
||||
}
|
||||
private static string EscapeExcelFindValue(string input)
|
||||
{
|
||||
if (string.IsNullOrEmpty(input))
|
||||
{
|
||||
return input;
|
||||
}
|
||||
|
||||
return input
|
||||
.Replace("~", "~~")
|
||||
.Replace("*", "~*")
|
||||
.Replace("?", "~?");
|
||||
}
|
||||
|
||||
public static void GenClientSummarySheet(ImportContext context)
|
||||
{
|
||||
var app = context.Application;
|
||||
@ -1191,9 +1228,15 @@ namespace KellyReport_D.Utils
|
||||
Worksheet clientSheet = CreateSheetIfNotExisted(app, sheetName);
|
||||
clientSheet.Activate();
|
||||
|
||||
// 准备首行标题
|
||||
clientSheet.Cells[2, 1].Value2 = "客戶名稱";
|
||||
clientSheet.Cells[2, 2].Value2 = "產品名稱";
|
||||
|
||||
// 按年写入数据
|
||||
context.YearList.ForEach(yearNumber =>
|
||||
{
|
||||
Range turnOverRange = clientSheet.UsedRange.Find(What: $"{yearNumber}-Turnover", LookIn: XlFindLookIn.xlValues, LookAt: XlLookAt.xlWhole, SearchOrder: XlSearchOrder.xlByRows, SearchDirection: XlSearchDirection.xlNext, MatchCase: false);
|
||||
|
||||
var clientSalesList = context.SalesDetails
|
||||
.Where(x => x.InvoiceDate.HasValue && x.InvoiceDate.Value.Year == yearNumber)
|
||||
.GroupBy(x => x.ClientName)
|
||||
@ -1205,9 +1248,11 @@ namespace KellyReport_D.Utils
|
||||
Details = grouped.ToList()
|
||||
})
|
||||
.ToList();
|
||||
|
||||
// 目标年份列
|
||||
if (turnOverRange == null)
|
||||
{
|
||||
int insertCol = 2;
|
||||
int insertCol = 3;
|
||||
|
||||
Range insertRange = clientSheet.Columns[$"{GetColumnLetter(insertCol)}:{GetColumnLetter(insertCol + 5)}"];
|
||||
insertRange.EntireColumn.Insert(XlInsertShiftDirection.xlShiftToRight);
|
||||
@ -1253,16 +1298,17 @@ namespace KellyReport_D.Utils
|
||||
foreach (var clientSalesGroup in clientSalesList)
|
||||
{
|
||||
var curClientName = clientSalesGroup.ClientName;
|
||||
// look for the Client row
|
||||
// if not exists then create a new row
|
||||
Range clientRange = clientSheet.UsedRange.Find(
|
||||
What: curClientName,
|
||||
LookIn: XlFindLookIn.xlValues,
|
||||
LookAt: XlLookAt.xlWhole,
|
||||
SearchOrder: XlSearchOrder.xlByRows,
|
||||
SearchDirection: XlSearchDirection.xlNext,
|
||||
MatchCase: false
|
||||
);
|
||||
|
||||
var clientProductSalesGrouped = clientSalesGroup.Details.GroupBy(x => x.ProductNameEN).Select(grouped => new ImportContext.GroupedSalesDetailModel()
|
||||
{
|
||||
ClientName = curClientName,
|
||||
ProductNameEN = grouped.Key,
|
||||
Quantity = grouped.Sum(x => x.Quantity ?? 0),
|
||||
TotalAmount = grouped.Sum(x => x.TotalAmount ?? 0),
|
||||
Details = grouped.ToList()
|
||||
}).ToList();
|
||||
// 查找是否已经存在的客户,存在则直接写入, 否则创建新行
|
||||
Range clientRange = clientSheet.UsedRange.Find(What: EscapeExcelFindValue(curClientName));
|
||||
|
||||
if (clientRange == null)
|
||||
{
|
||||
@ -1273,18 +1319,97 @@ namespace KellyReport_D.Utils
|
||||
totalRowCount += 1;
|
||||
}
|
||||
|
||||
int curRowIndex = clientRange.Row;
|
||||
int clientTotalRowIndex = clientRange.Row;
|
||||
// 处理产品名称行以及总销售行
|
||||
if (clientRange.MergeCells)
|
||||
{
|
||||
Range clientSalesRows = clientRange.MergeArea;
|
||||
int endRowIndex = clientSalesRows.End[XlDirection.xlDown].Row - 1;
|
||||
|
||||
clientSheet.Cells[curRowIndex, startColIndex].Value2 = clientSalesGroup.Quantity;
|
||||
clientSheet.Cells[curRowIndex, startColIndex + 1].Value2 = clientSalesGroup.TotalAmount;
|
||||
clientSheet.Cells[curRowIndex, startColIndex + 2].formula = $"={amountColLetter}{curRowIndex}/1.13";
|
||||
clientSheet.Cells[curRowIndex, startColIndex + 3].formula = $"={amountColLetter}{curRowIndex}/${quantityColLetter}{curRowIndex}";
|
||||
foreach (var clientProductSales in clientProductSalesGrouped)
|
||||
{
|
||||
Range clientProductNameCells = clientSheet.Range[
|
||||
clientSheet.Cells[clientSalesRows.Row, 2],
|
||||
clientSheet.Cells[endRowIndex, 2]
|
||||
];
|
||||
|
||||
clientSheet.Cells[curRowIndex, startColIndex + 4].formula = $"={quantityColLetter}{curRowIndex}/${prevQuantityColLetter}{curRowIndex}";
|
||||
clientSheet.Cells[curRowIndex, startColIndex + 5].formula = $"={amountColLetter}{curRowIndex}/${prevAmountColLetter}{curRowIndex}";
|
||||
var targetProduct = clientProductNameCells.Find(What: clientProductSales.ProductNameEN);
|
||||
if (targetProduct == null)
|
||||
{
|
||||
clientSheet.Rows[endRowIndex].Insert(XlInsertShiftDirection.xlShiftDown);
|
||||
clientSheet.Cells[endRowIndex, 2].Value2 = clientProductSales.ProductNameEN;
|
||||
clientSheet.Cells[endRowIndex, 2].NumberFormat = "@";
|
||||
|
||||
clientSheet.Cells[curRowIndex, startColIndex + 4].NumberFormat = "0.00%";
|
||||
clientSheet.Cells[curRowIndex, startColIndex + 5].NumberFormat = "0.00%";
|
||||
endRowIndex++;
|
||||
totalRowCount++;
|
||||
}
|
||||
}
|
||||
clientTotalRowIndex = endRowIndex;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < clientProductSalesGrouped.Count(); i++)
|
||||
{
|
||||
var clientProductSales = clientProductSalesGrouped[i];
|
||||
|
||||
clientSheet.Cells[clientRange.Row + i, 2].Value2 = clientProductSales.ProductNameEN;
|
||||
clientSheet.Cells[clientRange.Row + i, 2].NumberFormat = "@";
|
||||
clientSheet.Rows[clientRange.Row + i + 1].Insert();
|
||||
|
||||
clientTotalRowIndex++;
|
||||
totalRowCount++;
|
||||
}
|
||||
}
|
||||
clientSheet.Cells[clientTotalRowIndex, 2].Value2 = "總銷售額";
|
||||
clientSheet.Range[
|
||||
clientSheet.Cells[clientRange.Row, 1],
|
||||
clientSheet.Cells[clientTotalRowIndex, 1]
|
||||
].Merge();
|
||||
|
||||
// 重新选择合并后单元格
|
||||
clientRange = clientSheet.Cells[clientRange.Row, 1];
|
||||
|
||||
foreach (var clientProductSales in clientProductSalesGrouped)
|
||||
{
|
||||
Range clientProductNameCells = clientSheet.Range[
|
||||
clientSheet.Cells[clientRange.Row, 2],
|
||||
clientSheet.Cells[clientTotalRowIndex, 2]
|
||||
];
|
||||
|
||||
var targetProduct = clientProductNameCells.Find(What: clientProductSales.ProductNameEN);
|
||||
if (targetProduct == null)
|
||||
{
|
||||
FileLogger.Error($"无法找到客户 {curClientName} 的产品行 {clientProductSales.ProductNameEN},请检查数据完整性。");
|
||||
|
||||
MessageBox.Show($"无法找到客户 {curClientName} 的产品行 {clientProductSales.ProductNameEN},请检查数据完整性。", "警告", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
||||
continue;
|
||||
}
|
||||
|
||||
int productRowIndex = targetProduct.Row;
|
||||
clientSheet.Cells[productRowIndex, startColIndex].Value2 = clientProductSales.Quantity;
|
||||
clientSheet.Cells[productRowIndex, startColIndex + 1].Value2 = clientProductSales.TotalAmount;
|
||||
clientSheet.Cells[productRowIndex, startColIndex + 2].formula = $"={amountColLetter}{productRowIndex}/1.13";
|
||||
clientSheet.Cells[productRowIndex, startColIndex + 3].formula = $"={amountColLetter}{productRowIndex}/${quantityColLetter}{productRowIndex}";
|
||||
|
||||
clientSheet.Cells[productRowIndex, startColIndex + 4].formula = $"={quantityColLetter}{productRowIndex}/${prevQuantityColLetter}{productRowIndex}";
|
||||
clientSheet.Cells[productRowIndex, startColIndex + 5].formula = $"={amountColLetter}{productRowIndex}/${prevAmountColLetter}{productRowIndex}";
|
||||
|
||||
clientSheet.Cells[productRowIndex, startColIndex + 4].NumberFormat = "0.00%";
|
||||
clientSheet.Cells[productRowIndex, startColIndex + 5].NumberFormat = "0.00%";
|
||||
}
|
||||
|
||||
// 填写总销售额行
|
||||
int totalRowIndex = clientRange.Row + clientProductSalesGrouped.Count();
|
||||
clientSheet.Cells[clientTotalRowIndex, startColIndex].Value2 = clientSalesGroup.Quantity;
|
||||
clientSheet.Cells[clientTotalRowIndex, startColIndex + 1].Value2 = clientSalesGroup.TotalAmount;
|
||||
clientSheet.Cells[clientTotalRowIndex, startColIndex + 2].formula = $"={amountColLetter}{clientTotalRowIndex}/1.13";
|
||||
clientSheet.Cells[clientTotalRowIndex, startColIndex + 3].formula = $"={amountColLetter}{clientTotalRowIndex}/${quantityColLetter}{clientTotalRowIndex}";
|
||||
|
||||
clientSheet.Cells[clientTotalRowIndex, startColIndex + 4].formula = $"={quantityColLetter}{clientTotalRowIndex}/${prevQuantityColLetter}{clientTotalRowIndex}";
|
||||
clientSheet.Cells[clientTotalRowIndex, startColIndex + 5].formula = $"={amountColLetter}{clientTotalRowIndex}/${prevAmountColLetter}{clientTotalRowIndex}";
|
||||
|
||||
clientSheet.Cells[clientTotalRowIndex, startColIndex + 4].NumberFormat = "0.00%";
|
||||
clientSheet.Cells[clientTotalRowIndex, startColIndex + 5].NumberFormat = "0.00%";
|
||||
}
|
||||
|
||||
clientSheet.Cells[totalRowCount, 1].Value2 = "總計";
|
||||
@ -1411,84 +1536,109 @@ namespace KellyReport_D.Utils
|
||||
FormatSheetStyle(deptSheet);
|
||||
}
|
||||
|
||||
/* public static void GenProductForecastData(GenForecaseContext context)
|
||||
public static void ReadProductData(GenForecaseContext context)
|
||||
{
|
||||
var app = context.Application;
|
||||
|
||||
var productDataSheet = app.Worksheets["產品資料"] as Worksheet;
|
||||
productDataSheet.Activate();
|
||||
|
||||
var productRange = productDataSheet.UsedRange;
|
||||
IList<ProductForecastInput> productList = new List<ProductForecastInput>();
|
||||
|
||||
// 第2行开始
|
||||
int rowIndex = 2;
|
||||
|
||||
while (rowIndex <= productRange.Rows.Count)
|
||||
{
|
||||
productList.Add(new ProductForecastInput() { Name = productDataSheet.Cells[rowIndex, 1].Value2.ToString() });
|
||||
rowIndex++;
|
||||
}
|
||||
|
||||
context.ProductForecastList = productList;
|
||||
}
|
||||
|
||||
public static void GenProductForecastData(GenForecaseContext context)
|
||||
{
|
||||
var app = context.Application;
|
||||
ReadProductData(context);
|
||||
|
||||
string sheetName = $"產品年度預估";
|
||||
Worksheet productSheet = CreateSheetIfNotExisted(app, sheetName);
|
||||
productSheet.Activate();
|
||||
|
||||
var yearList = context.SalesForecastList.Select(x => x.Year).Distinct().ToList();
|
||||
string yearNumber = yearList[0].ToString();
|
||||
int yearNumber = yearList[0];
|
||||
|
||||
// 准备标题行
|
||||
Range estimateRange = productSheet.UsedRange.Find(What: $"{yearNumber}-Estimate", LookIn: XlFindLookIn.xlValues, LookAt: XlLookAt.xlWhole, SearchOrder: XlSearchOrder.xlByRows, SearchDirection: XlSearchDirection.xlNext, MatchCase: false);
|
||||
|
||||
int insertCol = 2;
|
||||
int estimateColIndex = 2;
|
||||
if (estimateRange != null)
|
||||
{
|
||||
insertCol = estimateRange.Column;
|
||||
estimateColIndex = estimateRange.Column;
|
||||
}
|
||||
else
|
||||
{
|
||||
Range insertRange = productSheet.Columns[$"{GetColumnLetter(estimateColIndex)}:{GetColumnLetter(estimateColIndex + 5)}"];
|
||||
insertRange.EntireColumn.Insert(XlInsertShiftDirection.xlShiftToRight);
|
||||
insertRange = productSheet.Columns[$"{GetColumnLetter(estimateColIndex)}:{GetColumnLetter(estimateColIndex + 5)}"];
|
||||
insertRange.ClearFormats();
|
||||
}
|
||||
|
||||
*//*
|
||||
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}-Estimate";
|
||||
productSheet.Cells[1, estimateColIndex].Value2 = $"{yearNumber}-Estimate";
|
||||
|
||||
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 = "成長率";
|
||||
productSheet.Cells[2, estimateColIndex].Value2 = "數量";
|
||||
productSheet.Cells[2, estimateColIndex + 1].Value2 = "金額(含稅)";
|
||||
productSheet.Cells[2, estimateColIndex + 2].Value2 = "金額(未稅)";
|
||||
productSheet.Cells[2, estimateColIndex + 3].Value2 = "平均單價";
|
||||
productSheet.Cells[2, estimateColIndex + 4].Value2 = "成長率";
|
||||
var growthRange = productSheet.Range[
|
||||
productSheet.Cells[2, insertCol + 4],
|
||||
productSheet.Cells[2, insertCol + 5]
|
||||
productSheet.Cells[2, estimateColIndex + 4],
|
||||
productSheet.Cells[2, estimateColIndex + 5]
|
||||
];
|
||||
growthRange.Merge();
|
||||
|
||||
estimateRange = productSheet.Range[
|
||||
productSheet.Cells[1, insertCol],
|
||||
productSheet.Cells[1, insertCol + 5]
|
||||
productSheet.Cells[1, estimateColIndex],
|
||||
productSheet.Cells[1, estimateColIndex + 5]
|
||||
];
|
||||
estimateRange.Merge();
|
||||
|
||||
var productSalesList = context.SalesForecastList
|
||||
.Where(x => x..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 = productSheet.UsedRange.Find(What: $"總計", LookIn: XlFindLookIn.xlValues, LookAt: XlLookAt.xlWhole, SearchOrder: XlSearchOrder.xlByRows, SearchDirection: XlSearchDirection.xlNext, MatchCase: false);
|
||||
|
||||
Range totalRange = clientSheet.UsedRange.Find(What: $"總計", LookIn: XlFindLookIn.xlValues, LookAt: XlLookAt.xlWhole, SearchOrder: XlSearchOrder.xlByRows, SearchDirection: XlSearchDirection.xlNext, MatchCase: false);
|
||||
|
||||
int totalRowCount = clientSheet.UsedRange.Rows.Count + 1;
|
||||
int totalRowCount = productSheet.UsedRange.Rows.Count + 1;
|
||||
if (totalRange != null)
|
||||
{
|
||||
totalRowCount = totalRange.Row;
|
||||
}
|
||||
|
||||
int startColIndex = turnOverRange.Column;
|
||||
int startColIndex = estimateColIndex;
|
||||
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)
|
||||
Range lastYearEstimateRange = productSheet.UsedRange.Find(What: $"{yearNumber - 1}-Turnover", LookIn: XlFindLookIn.xlValues, LookAt: XlLookAt.xlWhole, SearchOrder: XlSearchOrder.xlByRows, SearchDirection: XlSearchDirection.xlNext, MatchCase: false);
|
||||
if (lastYearEstimateRange != null)
|
||||
{
|
||||
var curProductName = productSalesSummary.ProductNameEN;
|
||||
// look for the product row
|
||||
// if not exists then create a new row
|
||||
Range productRange = clientSheet.UsedRange.Find(
|
||||
prevQuantityColLetter = GetColumnLetter(lastYearEstimateRange.Column);
|
||||
prevAmountColLetter = GetColumnLetter(lastYearEstimateRange.Column + 1);
|
||||
prevAmountNoTaxColLetter = GetColumnLetter(lastYearEstimateRange.Column + 2);
|
||||
}
|
||||
|
||||
for (int i = 0; i < context.ProductForecastList.Count; i++)
|
||||
{
|
||||
ProductForecastInput productData = context.ProductForecastList[i];
|
||||
var curProductName = productData.Name;
|
||||
|
||||
// 查找产品列,如已存在,无需处理
|
||||
// 否则创建新的产品行,并初始化预算
|
||||
Range productRange = productSheet.UsedRange.Find(
|
||||
What: curProductName,
|
||||
LookIn: XlFindLookIn.xlValues,
|
||||
LookAt: XlLookAt.xlWhole,
|
||||
@ -1499,44 +1649,45 @@ namespace KellyReport_D.Utils
|
||||
|
||||
if (productRange == null)
|
||||
{
|
||||
clientSheet.Rows[totalRowCount].Insert();
|
||||
clientSheet.Cells[totalRowCount, 1].Value2 = curProductName;
|
||||
productRange = clientSheet.Cells[totalRowCount, 1];
|
||||
// 创建新的产品预算行
|
||||
productSheet.Rows[totalRowCount].Insert();
|
||||
productSheet.Cells[totalRowCount, 1].Value2 = curProductName;
|
||||
productRange = productSheet.Cells[totalRowCount, 1];
|
||||
|
||||
int curRowIndex = totalRowCount;
|
||||
|
||||
productSheet.Cells[curRowIndex, startColIndex].Value2 = 0;
|
||||
productSheet.Cells[curRowIndex, startColIndex + 1].Value2 = 0;
|
||||
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%";
|
||||
|
||||
totalRowCount += 1;
|
||||
}
|
||||
|
||||
int curRowIndex = productRange.Row;
|
||||
|
||||
clientSheet.Cells[curRowIndex, startColIndex].Value2 = productSalesSummary.Quantity;
|
||||
clientSheet.Cells[curRowIndex, startColIndex + 1].Value2 = productSalesSummary.TotalAmount;
|
||||
clientSheet.Cells[curRowIndex, startColIndex + 2].formula = $"={amountColLetter}{curRowIndex}/1.13";
|
||||
clientSheet.Cells[curRowIndex, startColIndex + 3].formula = $"={amountColLetter}{curRowIndex}/${quantityColLetter}{curRowIndex}";
|
||||
|
||||
clientSheet.Cells[curRowIndex, startColIndex + 4].formula = $"={quantityColLetter}{curRowIndex}/${prevQuantityColLetter}{curRowIndex}";
|
||||
clientSheet.Cells[curRowIndex, startColIndex + 5].formula = $"={amountColLetter}{curRowIndex}/${prevAmountColLetter}{curRowIndex}";
|
||||
|
||||
clientSheet.Cells[curRowIndex, startColIndex + 4].NumberFormat = "0.00%";
|
||||
clientSheet.Cells[curRowIndex, startColIndex + 5].NumberFormat = "0.00%";
|
||||
}
|
||||
|
||||
clientSheet.Cells[totalRowCount, 1].Value2 = "總計";
|
||||
clientSheet.Cells[totalRowCount, startColIndex].formula = $"=SUM({quantityColLetter}5:{quantityColLetter}{totalRowCount - 1})";
|
||||
clientSheet.Cells[totalRowCount, startColIndex + 1].formula = $"=SUM({amountColLetter}5:{amountColLetter}{totalRowCount - 1})";
|
||||
clientSheet.Cells[totalRowCount, startColIndex + 2].formula = $"=SUM({amountNoTaxColLetter}5:{amountNoTaxColLetter}{totalRowCount - 1})";
|
||||
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})";
|
||||
|
||||
clientSheet.Cells[totalRowCount + 1, 1].Value2 = "備註";
|
||||
clientSheet.Cells[totalRowCount + 1, startColIndex].formula = $"={quantityColLetter}{totalRowCount}/{prevQuantityColLetter}{totalRowCount}";
|
||||
clientSheet.Cells[totalRowCount + 1, startColIndex + 1].formula = $"={amountColLetter}{totalRowCount}/{prevAmountColLetter}{totalRowCount}";
|
||||
clientSheet.Cells[totalRowCount + 1, startColIndex + 2].formula = $"={amountNoTaxColLetter}{totalRowCount}/{prevAmountNoTaxColLetter}{totalRowCount}";
|
||||
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}";
|
||||
|
||||
clientSheet.Cells[totalRowCount + 1, startColIndex].NumberFormat = "0.00%";
|
||||
clientSheet.Cells[totalRowCount + 1, startColIndex + 1].NumberFormat = "0.00%";
|
||||
clientSheet.Cells[totalRowCount + 1, startColIndex + 2].NumberFormat = "0.00%";
|
||||
});
|
||||
FormatSheetStyle(clientSheet);
|
||||
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 UpdateDeptartmentSummary(ImportContext context)
|
||||
{
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user