diff --git a/JQSalesSummaryPanel.cs b/JQSalesSummaryPanel.cs index c0b2a77..e5daa1b 100644 --- a/JQSalesSummaryPanel.cs +++ b/JQSalesSummaryPanel.cs @@ -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; } } } diff --git a/KellyReport_D.csproj b/KellyReport_D.csproj index 7b147fc..455ac76 100644 --- a/KellyReport_D.csproj +++ b/KellyReport_D.csproj @@ -34,7 +34,7 @@ publish\ zh-chs - 1.0.0.7 + 1.0.0.9 true true 7 diff --git a/Properties/AssemblyInfo.cs b/Properties/AssemblyInfo.cs index 54a36a3..7ba2652 100644 --- a/Properties/AssemblyInfo.cs +++ b/Properties/AssemblyInfo.cs @@ -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")] diff --git a/Utils/WorkBookUtils.cs b/Utils/WorkBookUtils.cs index 84a62c9..83213b8 100644 --- a/Utils/WorkBookUtils.cs +++ b/Utils/WorkBookUtils.cs @@ -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() { @@ -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 salesDetailList) + private static int WriteSalesDetailToSheet(Worksheet userSheet, Range clientNameRange, int rowIndex, int yearColIndex, ClientContact clientContact, IEnumerable 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 clientContactList = new List(); @@ -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 productList = new List(); + + // 第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) {