|
|
@@ -52,11 +52,11 @@ public class ReportController : Controller |
|
|
|
|
|
|
|
|
private async Task<IActionResult> LoadReportData(DateTime? startDate, DateTime? endDate) |
|
|
private async Task<IActionResult> LoadReportData(DateTime? startDate, DateTime? endDate) |
|
|
{ |
|
|
{ |
|
|
var query = _couponContext.Logs.AsQueryable().Where(x => x.LogType == "Consume" && x.LogInfo.Contains("耗用成功")); |
|
|
|
|
|
var serialNo = query.GroupBy(x => x.SerialNo).Select(g => g.Key).ToList(); |
|
|
|
|
|
var carEnter = _parkingEyesContext.CarEnters.Where(x => serialNo.Contains(x.SerialNo)).ToList(); |
|
|
|
|
|
|
|
|
// 建立包含日期篩選的查詢 |
|
|
|
|
|
var query = _couponContext.Logs.AsQueryable() |
|
|
|
|
|
.Where(x => x.LogType == "Consume" && x.LogInfo.Contains("耗用成功")); |
|
|
|
|
|
|
|
|
if (startDate.HasValue) |
|
|
|
|
|
|
|
|
if (startDate.HasValue) |
|
|
{ |
|
|
{ |
|
|
query = query.Where(x => x.LogTime >= startDate.Value); |
|
|
query = query.Where(x => x.LogTime >= startDate.Value); |
|
|
} |
|
|
} |
|
|
@@ -66,21 +66,30 @@ public class ReportController : Controller |
|
|
query = query.Where(x => x.LogTime <= endDate.Value.AddDays(1).AddSeconds(-1)); |
|
|
query = query.Where(x => x.LogTime <= endDate.Value.AddDays(1).AddSeconds(-1)); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
var logs = await query.OrderBy(x => x.LogTime).ToListAsync(); |
|
|
|
|
|
|
|
|
var consumeLogs = await query.OrderBy(x => x.LogTime).ToListAsync(); |
|
|
|
|
|
var serialNo = consumeLogs.Select(x => x.SerialNo).Distinct().ToList(); |
|
|
|
|
|
|
|
|
|
|
|
var evaluateLogsQuery = await _couponContext.Logs |
|
|
|
|
|
.Where(x => serialNo.Contains(x.SerialNo) && x.LogType == "Evaluate" && x.LogInfo.Contains("評估成功")) |
|
|
|
|
|
.ToListAsync(); |
|
|
|
|
|
|
|
|
|
|
|
// 建立 SerialNo 到 Evaluate Log 的映射 |
|
|
|
|
|
var evaluateLogDict = evaluateLogsQuery |
|
|
|
|
|
.GroupBy(x => x.SerialNo) |
|
|
|
|
|
.ToDictionary(g => g.Key, g => g.FirstOrDefault()); |
|
|
|
|
|
|
|
|
|
|
|
//var carEnter = _parkingEyesContext.CarEnters.Where(x => serialNo.Contains(x.SerialNo)).ToList(); |
|
|
|
|
|
//var carEnter = _mySqlContext.Cario.Where(x => serialNo.Contains(x.SerialNo)).ToList(); |
|
|
|
|
|
|
|
|
// 建立 SerialNo 到編號的映射 |
|
|
// 建立 SerialNo 到編號的映射 |
|
|
var serialNoToRowNumber = new Dictionary<string, int>(); |
|
|
var serialNoToRowNumber = new Dictionary<string, int>(); |
|
|
int currentRowNumber = 1; |
|
|
int currentRowNumber = 1; |
|
|
|
|
|
|
|
|
// 建立 SerialNo 到 CarEnter 的映射,方便快速查找 |
|
|
// 建立 SerialNo 到 CarEnter 的映射,方便快速查找 |
|
|
var carEnterDict = carEnter.GroupBy(x => x.SerialNo) |
|
|
|
|
|
.ToDictionary(g => g.Key, g => g.FirstOrDefault()); |
|
|
|
|
|
|
|
|
//var carEnterDict = carEnter.GroupBy(x => x.SerialNo) |
|
|
|
|
|
// .ToDictionary(g => g.Key, g => g.FirstOrDefault()); |
|
|
|
|
|
|
|
|
var viewModel = new CouponReportViewModel |
|
|
|
|
|
{ |
|
|
|
|
|
StartDate = startDate, |
|
|
|
|
|
EndDate = endDate, |
|
|
|
|
|
ReportItems = logs.Select(log => |
|
|
|
|
|
|
|
|
var reportItems = consumeLogs.Select(log => |
|
|
{ |
|
|
{ |
|
|
// 如果這個 SerialNo 還沒出現過,給它一個新編號 |
|
|
// 如果這個 SerialNo 還沒出現過,給它一個新編號 |
|
|
if (!string.IsNullOrEmpty(log.SerialNo) && !serialNoToRowNumber.ContainsKey(log.SerialNo)) |
|
|
if (!string.IsNullOrEmpty(log.SerialNo) && !serialNoToRowNumber.ContainsKey(log.SerialNo)) |
|
|
@@ -88,17 +97,22 @@ public class ReportController : Controller |
|
|
serialNoToRowNumber[log.SerialNo] = currentRowNumber++; |
|
|
serialNoToRowNumber[log.SerialNo] = currentRowNumber++; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// 從 CarEnter 取得出場時間 |
|
|
|
|
|
|
|
|
// 從 evaluateLogDict 取得出場時間 |
|
|
DateTime? exitTime = null; |
|
|
DateTime? exitTime = null; |
|
|
|
|
|
if (!string.IsNullOrEmpty(log.SerialNo) && evaluateLogDict.ContainsKey(log.SerialNo)) |
|
|
|
|
|
{ |
|
|
|
|
|
exitTime = evaluateLogDict[log.SerialNo]?.LogTime; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
var tenantCode = string.Empty; |
|
|
var tenantCode = string.Empty; |
|
|
DateTime? invoiceDate = null; |
|
|
DateTime? invoiceDate = null; |
|
|
var invoiceNo = string.Empty; |
|
|
var invoiceNo = string.Empty; |
|
|
var invoiceAmount = 0m; |
|
|
var invoiceAmount = 0m; |
|
|
|
|
|
|
|
|
if (!string.IsNullOrEmpty(log.SerialNo) && carEnterDict.ContainsKey(log.SerialNo)) |
|
|
|
|
|
{ |
|
|
|
|
|
exitTime = carEnterDict[log.SerialNo]?.DepartureDateTime; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
//if (!string.IsNullOrEmpty(log.SerialNo) && carEnterDict.ContainsKey(log.SerialNo)) |
|
|
|
|
|
// { |
|
|
|
|
|
// exitTime = carEnterDict[log.SerialNo]?.OutTime; |
|
|
|
|
|
// } |
|
|
|
|
|
|
|
|
invoiceDate = _reportService.GetInvoiceDateTime(log.ExternalSystemKey); |
|
|
invoiceDate = _reportService.GetInvoiceDateTime(log.ExternalSystemKey); |
|
|
invoiceNo = _reportService.GetInvoiceNo(log.ExternalSystemKey); |
|
|
invoiceNo = _reportService.GetInvoiceNo(log.ExternalSystemKey); |
|
|
@@ -113,7 +127,7 @@ public class ReportController : Controller |
|
|
InvoiceDate = invoiceDate, |
|
|
InvoiceDate = invoiceDate, |
|
|
InvoiceNumber = invoiceNo, |
|
|
InvoiceNumber = invoiceNo, |
|
|
InvoiceAmount = invoiceAmount, |
|
|
InvoiceAmount = invoiceAmount, |
|
|
DiscountUnit = "新台幣", |
|
|
|
|
|
|
|
|
DiscountUnit = "金額", |
|
|
DiscountAmount = log.DiscountAmount, |
|
|
DiscountAmount = log.DiscountAmount, |
|
|
DiscountTime = log.LogTime, |
|
|
DiscountTime = log.LogTime, |
|
|
EnterTime = log.EnterTime, |
|
|
EnterTime = log.EnterTime, |
|
|
@@ -121,7 +135,13 @@ public class ReportController : Controller |
|
|
ParkingAmount = log.TotalAmount, |
|
|
ParkingAmount = log.TotalAmount, |
|
|
ClaimAmount = log.DiscountAmount |
|
|
ClaimAmount = log.DiscountAmount |
|
|
}; |
|
|
}; |
|
|
}).ToList() |
|
|
|
|
|
|
|
|
}).OrderBy(x => x.RowNumber).ThenBy(x => x.DiscountTime).ToList(); |
|
|
|
|
|
|
|
|
|
|
|
var viewModel = new CouponReportViewModel |
|
|
|
|
|
{ |
|
|
|
|
|
StartDate = startDate, |
|
|
|
|
|
EndDate = endDate, |
|
|
|
|
|
ReportItems = reportItems |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
return View(viewModel); |
|
|
return View(viewModel); |
|
|
@@ -129,9 +149,8 @@ public class ReportController : Controller |
|
|
|
|
|
|
|
|
public async Task<IActionResult> ExportToExcel(DateTime? startDate, DateTime? endDate) |
|
|
public async Task<IActionResult> ExportToExcel(DateTime? startDate, DateTime? endDate) |
|
|
{ |
|
|
{ |
|
|
var query = _couponContext.Logs.AsQueryable().Where(x => x.LogType == "Consume" && x.LogInfo.Contains("耗用成功")); |
|
|
|
|
|
var serialNo = query.GroupBy(x => x.SerialNo).Select(g => g.Key).ToList(); |
|
|
|
|
|
var carEnter = _parkingEyesContext.CarEnters.Where(x => serialNo.Contains(x.SerialNo)).ToList(); |
|
|
|
|
|
|
|
|
var query = _couponContext.Logs.AsQueryable() |
|
|
|
|
|
.Where(x => x.LogType == "Consume" && x.LogInfo.Contains("耗用成功")); |
|
|
|
|
|
|
|
|
if (startDate.HasValue) |
|
|
if (startDate.HasValue) |
|
|
{ |
|
|
{ |
|
|
@@ -143,23 +162,29 @@ public class ReportController : Controller |
|
|
query = query.Where(x => x.LogTime <= endDate.Value.AddDays(1).AddSeconds(-1)); |
|
|
query = query.Where(x => x.LogTime <= endDate.Value.AddDays(1).AddSeconds(-1)); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
var logs = await query.OrderBy(x => x.LogTime).ToListAsync(); |
|
|
|
|
|
|
|
|
var consumeLogs = await query.OrderBy(x => x.LogTime).ToListAsync(); |
|
|
|
|
|
var serialNo = consumeLogs.Select(x => x.SerialNo).Distinct().ToList(); |
|
|
|
|
|
|
|
|
|
|
|
var evaluateLogsQuery = await _couponContext.Logs |
|
|
|
|
|
.Where(x => serialNo.Contains(x.SerialNo) && x.LogType == "Evaluate" && x.LogInfo.Contains("評估成功")) |
|
|
|
|
|
.ToListAsync(); |
|
|
|
|
|
|
|
|
|
|
|
// 建立 SerialNo 到 Evaluate Log 的映射 |
|
|
|
|
|
var evaluateLogDict = evaluateLogsQuery |
|
|
|
|
|
.GroupBy(x => x.SerialNo) |
|
|
|
|
|
.ToDictionary(g => g.Key, g => g.FirstOrDefault()); |
|
|
|
|
|
|
|
|
// 建立 SerialNo 到編號的映射 |
|
|
// 建立 SerialNo 到編號的映射 |
|
|
var serialNoToRowNumber = new Dictionary<string, int>(); |
|
|
var serialNoToRowNumber = new Dictionary<string, int>(); |
|
|
int currentRowNumber = 1; |
|
|
int currentRowNumber = 1; |
|
|
|
|
|
|
|
|
// 建立 SerialNo 到 CarEnter 的映射,方便快速查找 |
|
|
|
|
|
var carEnterDict = carEnter.GroupBy(x => x.SerialNo) |
|
|
|
|
|
.ToDictionary(g => g.Key, g => g.FirstOrDefault()); |
|
|
|
|
|
|
|
|
|
|
|
// 建立報表資料列表 |
|
|
// 建立報表資料列表 |
|
|
var reportItems = new List<(int rowNumber, string tenantCode, string carNumber, DateTime? invoiceDate, |
|
|
var reportItems = new List<(int rowNumber, string tenantCode, string carNumber, DateTime? invoiceDate, |
|
|
string invoiceNo, decimal invoiceAmount, string discountUnit, decimal? discountAmount, |
|
|
string invoiceNo, decimal invoiceAmount, string discountUnit, decimal? discountAmount, |
|
|
DateTime discountTime, DateTime? enterTime, DateTime? exitTime, |
|
|
DateTime discountTime, DateTime? enterTime, DateTime? exitTime, |
|
|
decimal? parkingAmount, decimal? claimAmount)>(); |
|
|
decimal? parkingAmount, decimal? claimAmount)>(); |
|
|
|
|
|
|
|
|
foreach (var log in logs) |
|
|
|
|
|
|
|
|
foreach (var log in consumeLogs) |
|
|
{ |
|
|
{ |
|
|
if (!string.IsNullOrEmpty(log.SerialNo) && !serialNoToRowNumber.ContainsKey(log.SerialNo)) |
|
|
if (!string.IsNullOrEmpty(log.SerialNo) && !serialNoToRowNumber.ContainsKey(log.SerialNo)) |
|
|
{ |
|
|
{ |
|
|
@@ -167,9 +192,9 @@ public class ReportController : Controller |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
DateTime? exitTime = null; |
|
|
DateTime? exitTime = null; |
|
|
if (!string.IsNullOrEmpty(log.SerialNo) && carEnterDict.ContainsKey(log.SerialNo)) |
|
|
|
|
|
|
|
|
if (!string.IsNullOrEmpty(log.SerialNo) && evaluateLogDict.ContainsKey(log.SerialNo)) |
|
|
{ |
|
|
{ |
|
|
exitTime = carEnterDict[log.SerialNo]?.DepartureDateTime; |
|
|
|
|
|
|
|
|
exitTime = evaluateLogDict[log.SerialNo]?.LogTime; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
var invoiceDate = _reportService.GetInvoiceDateTime(log.ExternalSystemKey); |
|
|
var invoiceDate = _reportService.GetInvoiceDateTime(log.ExternalSystemKey); |
|
|
@@ -180,37 +205,47 @@ public class ReportController : Controller |
|
|
int rowNumber = !string.IsNullOrEmpty(log.SerialNo) ? serialNoToRowNumber[log.SerialNo] : 0; |
|
|
int rowNumber = !string.IsNullOrEmpty(log.SerialNo) ? serialNoToRowNumber[log.SerialNo] : 0; |
|
|
|
|
|
|
|
|
reportItems.Add((rowNumber, tenantCode, log.PlateNo, invoiceDate, invoiceNo, invoiceAmount, |
|
|
reportItems.Add((rowNumber, tenantCode, log.PlateNo, invoiceDate, invoiceNo, invoiceAmount, |
|
|
"新台幣", log.DiscountAmount, log.LogTime, log.EnterTime, exitTime, |
|
|
|
|
|
|
|
|
"金額", log.DiscountAmount, log.LogTime, log.EnterTime, exitTime, |
|
|
log.TotalAmount, log.DiscountAmount)); |
|
|
log.TotalAmount, log.DiscountAmount)); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 按 RowNumber 排序,確保相同編號的資料連續,避免合併儲存格錯誤 |
|
|
|
|
|
reportItems = reportItems.OrderBy(x => x.rowNumber).ThenBy(x => x.discountTime).ToList(); |
|
|
|
|
|
|
|
|
using var workbook = new XLWorkbook(); |
|
|
using var workbook = new XLWorkbook(); |
|
|
var worksheet = workbook.Worksheets.Add("折扣報表"); |
|
|
var worksheet = workbook.Worksheets.Add("折扣報表"); |
|
|
|
|
|
|
|
|
|
|
|
// 匯出資訊(合併儲存格以避免影響欄寬) |
|
|
|
|
|
worksheet.Range(1, 1, 1, 13).Merge(); |
|
|
|
|
|
worksheet.Cell(1, 1).Value = $"匯出時間:{DateTime.Now:yyyy-MM-dd HH:mm:ss}"; |
|
|
|
|
|
|
|
|
|
|
|
worksheet.Range(2, 1, 2, 13).Merge(); |
|
|
|
|
|
worksheet.Cell(2, 1).Value = $"篩選條件:{startDate?.ToString("yyyy-MM-dd")} ~ {endDate?.ToString("yyyy-MM-dd")}"; |
|
|
|
|
|
|
|
|
// 標題列 |
|
|
// 標題列 |
|
|
worksheet.Cell(1, 1).Value = "編號"; |
|
|
|
|
|
worksheet.Cell(1, 2).Value = "店別(統編)"; |
|
|
|
|
|
worksheet.Cell(1, 3).Value = "車號"; |
|
|
|
|
|
worksheet.Cell(1, 4).Value = "發票日期"; |
|
|
|
|
|
worksheet.Cell(1, 5).Value = "發票號碼"; |
|
|
|
|
|
worksheet.Cell(1, 6).Value = "發票金額"; |
|
|
|
|
|
worksheet.Cell(1, 7).Value = "折扣單位"; |
|
|
|
|
|
worksheet.Cell(1, 8).Value = "折扣金額"; |
|
|
|
|
|
worksheet.Cell(1, 9).Value = "折扣時間"; |
|
|
|
|
|
worksheet.Cell(1, 10).Value = "入場時間"; |
|
|
|
|
|
worksheet.Cell(1, 11).Value = "出場時間"; |
|
|
|
|
|
worksheet.Cell(1, 12).Value = "停車金額"; |
|
|
|
|
|
worksheet.Cell(1, 13).Value = "請款金額"; |
|
|
|
|
|
|
|
|
worksheet.Cell(4, 1).Value = "編號"; |
|
|
|
|
|
worksheet.Cell(4, 2).Value = "店別(統編)"; |
|
|
|
|
|
worksheet.Cell(4, 3).Value = "車號"; |
|
|
|
|
|
worksheet.Cell(4, 4).Value = "發票日期"; |
|
|
|
|
|
worksheet.Cell(4, 5).Value = "發票號碼"; |
|
|
|
|
|
worksheet.Cell(4, 6).Value = "發票金額"; |
|
|
|
|
|
worksheet.Cell(4, 7).Value = "折扣單位"; |
|
|
|
|
|
worksheet.Cell(4, 8).Value = "折扣金額"; |
|
|
|
|
|
worksheet.Cell(4, 9).Value = "折扣時間"; |
|
|
|
|
|
worksheet.Cell(4, 10).Value = "入場時間"; |
|
|
|
|
|
worksheet.Cell(4, 11).Value = "出場時間"; |
|
|
|
|
|
worksheet.Cell(4, 12).Value = "停車金額"; |
|
|
|
|
|
worksheet.Cell(4, 13).Value = "請款金額"; |
|
|
|
|
|
|
|
|
// 設定標題列樣式 |
|
|
// 設定標題列樣式 |
|
|
var headerRange = worksheet.Range(1, 1, 1, 13); |
|
|
|
|
|
|
|
|
var headerRange = worksheet.Range(4, 1, 4, 13); |
|
|
headerRange.Style.Font.Bold = true; |
|
|
headerRange.Style.Font.Bold = true; |
|
|
headerRange.Style.Fill.BackgroundColor = XLColor.LightGray; |
|
|
headerRange.Style.Fill.BackgroundColor = XLColor.LightGray; |
|
|
headerRange.Style.Alignment.Horizontal = XLAlignmentHorizontalValues.Center; |
|
|
headerRange.Style.Alignment.Horizontal = XLAlignmentHorizontalValues.Center; |
|
|
headerRange.Style.Alignment.Vertical = XLAlignmentVerticalValues.Center; |
|
|
headerRange.Style.Alignment.Vertical = XLAlignmentVerticalValues.Center; |
|
|
|
|
|
|
|
|
// 填入資料並記錄合併範圍 |
|
|
// 填入資料並記錄合併範圍 |
|
|
int row = 2; |
|
|
|
|
|
|
|
|
int row = 5; |
|
|
var mergedCells = new Dictionary<int, (int startRow, int endRow)>(); |
|
|
var mergedCells = new Dictionary<int, (int startRow, int endRow)>(); |
|
|
|
|
|
|
|
|
foreach (var item in reportItems) |
|
|
foreach (var item in reportItems) |
|
|
@@ -219,16 +254,16 @@ public class ReportController : Controller |
|
|
worksheet.Cell(row, 1).Value = item.rowNumber; |
|
|
worksheet.Cell(row, 1).Value = item.rowNumber; |
|
|
worksheet.Cell(row, 2).Value = item.tenantCode; |
|
|
worksheet.Cell(row, 2).Value = item.tenantCode; |
|
|
worksheet.Cell(row, 3).Value = item.carNumber; |
|
|
worksheet.Cell(row, 3).Value = item.carNumber; |
|
|
worksheet.Cell(row, 4).Value = item.invoiceDate?.ToString("yyyy-MM-dd HH:mm:ss"); |
|
|
|
|
|
|
|
|
worksheet.Cell(row, 4).Value = item.invoiceDate?.ToString("yyyy-MM-dd"); |
|
|
worksheet.Cell(row, 5).Value = item.invoiceNo; |
|
|
worksheet.Cell(row, 5).Value = item.invoiceNo; |
|
|
worksheet.Cell(row, 6).Value = item.invoiceAmount; |
|
|
|
|
|
|
|
|
worksheet.Cell(row, 6).Value = $"NT$ {item.invoiceAmount:N0}"; |
|
|
worksheet.Cell(row, 7).Value = item.discountUnit; |
|
|
worksheet.Cell(row, 7).Value = item.discountUnit; |
|
|
worksheet.Cell(row, 8).Value = item.discountAmount; |
|
|
|
|
|
|
|
|
worksheet.Cell(row, 8).Value = $"NT$ {item.discountAmount:N0}"; |
|
|
worksheet.Cell(row, 9).Value = item.discountTime.ToString("yyyy-MM-dd HH:mm:ss"); |
|
|
worksheet.Cell(row, 9).Value = item.discountTime.ToString("yyyy-MM-dd HH:mm:ss"); |
|
|
worksheet.Cell(row, 10).Value = item.enterTime?.ToString("yyyy-MM-dd HH:mm:ss"); |
|
|
worksheet.Cell(row, 10).Value = item.enterTime?.ToString("yyyy-MM-dd HH:mm:ss"); |
|
|
worksheet.Cell(row, 11).Value = item.exitTime?.ToString("yyyy-MM-dd HH:mm:ss"); |
|
|
worksheet.Cell(row, 11).Value = item.exitTime?.ToString("yyyy-MM-dd HH:mm:ss"); |
|
|
worksheet.Cell(row, 12).Value = item.parkingAmount; |
|
|
|
|
|
worksheet.Cell(row, 13).Value = item.claimAmount; |
|
|
|
|
|
|
|
|
worksheet.Cell(row, 12).Value = $"NT$ {item.parkingAmount:N0}"; |
|
|
|
|
|
worksheet.Cell(row, 13).Value = $"NT$ {item.claimAmount:N0}"; |
|
|
|
|
|
|
|
|
// 記錄需要合併的儲存格範圍(按 rowNumber 分組) |
|
|
// 記錄需要合併的儲存格範圍(按 rowNumber 分組) |
|
|
if (item.rowNumber > 0) |
|
|
if (item.rowNumber > 0) |
|
|
@@ -274,7 +309,7 @@ public class ReportController : Controller |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// 將所有資料儲存格置中 |
|
|
// 將所有資料儲存格置中 |
|
|
var dataRange = worksheet.Range(2, 1, row - 1, 13); |
|
|
|
|
|
|
|
|
var dataRange = worksheet.Range(5, 1, row - 1, 13); |
|
|
dataRange.Style.Alignment.Horizontal = XLAlignmentHorizontalValues.Center; |
|
|
dataRange.Style.Alignment.Horizontal = XLAlignmentHorizontalValues.Center; |
|
|
dataRange.Style.Alignment.Vertical = XLAlignmentVerticalValues.Center; |
|
|
dataRange.Style.Alignment.Vertical = XLAlignmentVerticalValues.Center; |
|
|
|
|
|
|
|
|
@@ -288,9 +323,8 @@ public class ReportController : Controller |
|
|
|
|
|
|
|
|
public async Task<IActionResult> ExportToPdf(DateTime? startDate, DateTime? endDate) |
|
|
public async Task<IActionResult> ExportToPdf(DateTime? startDate, DateTime? endDate) |
|
|
{ |
|
|
{ |
|
|
var query = _couponContext.Logs.AsQueryable().Where(x => x.LogType == "Consume" && x.LogInfo.Contains("耗用成功")); |
|
|
|
|
|
var serialNo = query.GroupBy(x => x.SerialNo).Select(g => g.Key).ToList(); |
|
|
|
|
|
var carEnter = _parkingEyesContext.CarEnters.Where(x => serialNo.Contains(x.SerialNo)).ToList(); |
|
|
|
|
|
|
|
|
var query = _couponContext.Logs.AsQueryable() |
|
|
|
|
|
.Where(x => x.LogType == "Consume" && x.LogInfo.Contains("耗用成功")); |
|
|
|
|
|
|
|
|
if (startDate.HasValue) |
|
|
if (startDate.HasValue) |
|
|
{ |
|
|
{ |
|
|
@@ -302,23 +336,29 @@ public class ReportController : Controller |
|
|
query = query.Where(x => x.LogTime <= endDate.Value.AddDays(1).AddSeconds(-1)); |
|
|
query = query.Where(x => x.LogTime <= endDate.Value.AddDays(1).AddSeconds(-1)); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
var logs = await query.OrderBy(x => x.LogTime).ToListAsync(); |
|
|
|
|
|
|
|
|
var consumeLogs = await query.OrderBy(x => x.LogTime).ToListAsync(); |
|
|
|
|
|
var serialNo = consumeLogs.Select(x => x.SerialNo).Distinct().ToList(); |
|
|
|
|
|
|
|
|
|
|
|
var evaluateLogsQuery = await _couponContext.Logs |
|
|
|
|
|
.Where(x => serialNo.Contains(x.SerialNo) && x.LogType == "Evaluate" && x.LogInfo.Contains("評估成功")) |
|
|
|
|
|
.ToListAsync(); |
|
|
|
|
|
|
|
|
|
|
|
// 建立 SerialNo 到 Evaluate Log 的映射 |
|
|
|
|
|
var evaluateLogDict = evaluateLogsQuery |
|
|
|
|
|
.GroupBy(x => x.SerialNo) |
|
|
|
|
|
.ToDictionary(g => g.Key, g => g.FirstOrDefault()); |
|
|
|
|
|
|
|
|
// 建立 SerialNo 到編號的映射 |
|
|
// 建立 SerialNo 到編號的映射 |
|
|
var serialNoToRowNumber = new Dictionary<string, int>(); |
|
|
var serialNoToRowNumber = new Dictionary<string, int>(); |
|
|
int currentRowNumber = 1; |
|
|
int currentRowNumber = 1; |
|
|
|
|
|
|
|
|
// 建立 SerialNo 到 CarEnter 的映射,方便快速查找 |
|
|
|
|
|
var carEnterDict = carEnter.GroupBy(x => x.SerialNo) |
|
|
|
|
|
.ToDictionary(g => g.Key, g => g.FirstOrDefault()); |
|
|
|
|
|
|
|
|
// 建立臨時資料列表以便排序 |
|
|
|
|
|
var tempReportItems = new List<(int rowNumber, string tenantCode, string carNumber, DateTime? invoiceDate, |
|
|
|
|
|
string invoiceNo, decimal invoiceAmount, string discountUnit, decimal? discountAmount, |
|
|
|
|
|
DateTime discountTime, DateTime? enterTime, DateTime? exitTime, |
|
|
|
|
|
decimal? parkingAmount, decimal? claimAmount)>(); |
|
|
|
|
|
|
|
|
// 建立報表資料並分組 |
|
|
|
|
|
var reportGroups = new Dictionary<int, List<(string tenantCode, DateTime? invoiceDate, string invoiceNo, decimal invoiceAmount)>>(); |
|
|
|
|
|
var groupData = new Dictionary<int, (int rowNumber, string carNumber, string discountUnit, decimal? discountAmount, |
|
|
|
|
|
DateTime discountTime, DateTime? enterTime, DateTime? exitTime, |
|
|
|
|
|
decimal? parkingAmount, decimal? claimAmount)>(); |
|
|
|
|
|
|
|
|
|
|
|
foreach (var log in logs) |
|
|
|
|
|
|
|
|
foreach (var log in consumeLogs) |
|
|
{ |
|
|
{ |
|
|
if (!string.IsNullOrEmpty(log.SerialNo) && !serialNoToRowNumber.ContainsKey(log.SerialNo)) |
|
|
if (!string.IsNullOrEmpty(log.SerialNo) && !serialNoToRowNumber.ContainsKey(log.SerialNo)) |
|
|
{ |
|
|
{ |
|
|
@@ -326,9 +366,9 @@ public class ReportController : Controller |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
DateTime? exitTime = null; |
|
|
DateTime? exitTime = null; |
|
|
if (!string.IsNullOrEmpty(log.SerialNo) && carEnterDict.ContainsKey(log.SerialNo)) |
|
|
|
|
|
|
|
|
if (!string.IsNullOrEmpty(log.SerialNo) && evaluateLogDict.ContainsKey(log.SerialNo)) |
|
|
{ |
|
|
{ |
|
|
exitTime = carEnterDict[log.SerialNo]?.DepartureDateTime; |
|
|
|
|
|
|
|
|
exitTime = evaluateLogDict[log.SerialNo]?.LogTime; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
var invoiceDate = _reportService.GetInvoiceDateTime(log.ExternalSystemKey); |
|
|
var invoiceDate = _reportService.GetInvoiceDateTime(log.ExternalSystemKey); |
|
|
@@ -338,15 +378,31 @@ public class ReportController : Controller |
|
|
|
|
|
|
|
|
int rowNumber = !string.IsNullOrEmpty(log.SerialNo) ? serialNoToRowNumber[log.SerialNo] : 0; |
|
|
int rowNumber = !string.IsNullOrEmpty(log.SerialNo) ? serialNoToRowNumber[log.SerialNo] : 0; |
|
|
|
|
|
|
|
|
|
|
|
tempReportItems.Add((rowNumber, tenantCode, log.PlateNo, invoiceDate, invoiceNo, invoiceAmount, |
|
|
|
|
|
"金額", log.DiscountAmount, log.LogTime, log.EnterTime, exitTime, |
|
|
|
|
|
log.TotalAmount, log.DiscountAmount)); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 按 RowNumber 排序,確保相同編號的資料連續,避免合併儲存格錯誤 |
|
|
|
|
|
tempReportItems = tempReportItems.OrderBy(x => x.rowNumber).ThenBy(x => x.discountTime).ToList(); |
|
|
|
|
|
|
|
|
|
|
|
// 建立報表資料並分組 |
|
|
|
|
|
var reportGroups = new Dictionary<int, List<(string tenantCode, DateTime? invoiceDate, string invoiceNo, decimal invoiceAmount)>>(); |
|
|
|
|
|
var groupData = new Dictionary<int, (int rowNumber, string carNumber, string discountUnit, decimal? discountAmount, |
|
|
|
|
|
DateTime discountTime, DateTime? enterTime, DateTime? exitTime, |
|
|
|
|
|
decimal? parkingAmount, decimal? claimAmount)>(); |
|
|
|
|
|
|
|
|
|
|
|
foreach (var item in tempReportItems) |
|
|
|
|
|
{ |
|
|
// 記錄群組資料 |
|
|
// 記錄群組資料 |
|
|
if (!groupData.ContainsKey(rowNumber)) |
|
|
|
|
|
|
|
|
if (!groupData.ContainsKey(item.rowNumber)) |
|
|
{ |
|
|
{ |
|
|
groupData[rowNumber] = (rowNumber, log.PlateNo, "新台幣", log.DiscountAmount, log.LogTime, |
|
|
|
|
|
log.EnterTime, exitTime, log.TotalAmount, log.DiscountAmount); |
|
|
|
|
|
reportGroups[rowNumber] = new List<(string, DateTime?, string, decimal)>(); |
|
|
|
|
|
|
|
|
groupData[item.rowNumber] = (item.rowNumber, item.carNumber, item.discountUnit, item.discountAmount, item.discountTime, |
|
|
|
|
|
item.enterTime, item.exitTime, item.parkingAmount, item.claimAmount); |
|
|
|
|
|
reportGroups[item.rowNumber] = new List<(string, DateTime?, string, decimal)>(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
reportGroups[rowNumber].Add((tenantCode, invoiceDate, invoiceNo, invoiceAmount)); |
|
|
|
|
|
|
|
|
reportGroups[item.rowNumber].Add((item.tenantCode, item.invoiceDate, item.invoiceNo, item.invoiceAmount)); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
var stream = new MemoryStream(); |
|
|
var stream = new MemoryStream(); |
|
|
@@ -380,6 +436,17 @@ public class ReportController : Controller |
|
|
.SetFontSize(18); |
|
|
.SetFontSize(18); |
|
|
document.Add(title); |
|
|
document.Add(title); |
|
|
|
|
|
|
|
|
|
|
|
// 匯出資訊 |
|
|
|
|
|
var exportInfo = new Paragraph($"匯出時間:{DateTime.Now:yyyy-MM-dd HH:mm:ss}") |
|
|
|
|
|
.SetFontSize(10) |
|
|
|
|
|
.SetMarginTop(10); |
|
|
|
|
|
document.Add(exportInfo); |
|
|
|
|
|
|
|
|
|
|
|
var filterInfo = new Paragraph($"篩選條件:{startDate?.ToString("yyyy-MM-dd")} ~ {endDate?.ToString("yyyy-MM-dd")}") |
|
|
|
|
|
.SetFontSize(10) |
|
|
|
|
|
.SetMarginBottom(10); |
|
|
|
|
|
document.Add(filterInfo); |
|
|
|
|
|
|
|
|
// 建立表格 |
|
|
// 建立表格 |
|
|
var table = new Table(13).UseAllAvailableWidth(); |
|
|
var table = new Table(13).UseAllAvailableWidth(); |
|
|
table.SetFontSize(8); |
|
|
table.SetFontSize(8); |
|
|
@@ -428,18 +495,18 @@ public class ReportController : Controller |
|
|
// 每一行:發票日期、發票號碼、發票金額 |
|
|
// 每一行:發票日期、發票號碼、發票金額 |
|
|
table.AddCell(new Cell().Add(new Paragraph(invoice.invoiceDate?.ToString("yyyy-MM-dd") ?? "")).SetTextAlignment(TextAlignment.CENTER)); |
|
|
table.AddCell(new Cell().Add(new Paragraph(invoice.invoiceDate?.ToString("yyyy-MM-dd") ?? "")).SetTextAlignment(TextAlignment.CENTER)); |
|
|
table.AddCell(new Cell().Add(new Paragraph(invoice.invoiceNo ?? "")).SetTextAlignment(TextAlignment.CENTER)); |
|
|
table.AddCell(new Cell().Add(new Paragraph(invoice.invoiceNo ?? "")).SetTextAlignment(TextAlignment.CENTER)); |
|
|
table.AddCell(new Cell().Add(new Paragraph(invoice.invoiceAmount.ToString("N0"))).SetTextAlignment(TextAlignment.CENTER)); |
|
|
|
|
|
|
|
|
table.AddCell(new Cell().Add(new Paragraph($"NT$ {invoice.invoiceAmount:N0}")).SetTextAlignment(TextAlignment.CENTER)); |
|
|
|
|
|
|
|
|
if (isFirstRow) |
|
|
if (isFirstRow) |
|
|
{ |
|
|
{ |
|
|
// 合併欄位:折扣單位、折扣金額、折扣時間、入場時間、出場時間、停車金額、請款金額 |
|
|
// 合併欄位:折扣單位、折扣金額、折扣時間、入場時間、出場時間、停車金額、請款金額 |
|
|
table.AddCell(new Cell(rowSpan, 1).Add(new Paragraph(group.discountUnit ?? "")).SetTextAlignment(TextAlignment.CENTER).SetVerticalAlignment(VerticalAlignment.MIDDLE)); |
|
|
table.AddCell(new Cell(rowSpan, 1).Add(new Paragraph(group.discountUnit ?? "")).SetTextAlignment(TextAlignment.CENTER).SetVerticalAlignment(VerticalAlignment.MIDDLE)); |
|
|
table.AddCell(new Cell(rowSpan, 1).Add(new Paragraph(group.discountAmount?.ToString("N0") ?? "")).SetTextAlignment(TextAlignment.CENTER).SetVerticalAlignment(VerticalAlignment.MIDDLE)); |
|
|
|
|
|
|
|
|
table.AddCell(new Cell(rowSpan, 1).Add(new Paragraph($"NT$ {group.discountAmount:N0}")).SetTextAlignment(TextAlignment.CENTER).SetVerticalAlignment(VerticalAlignment.MIDDLE)); |
|
|
table.AddCell(new Cell(rowSpan, 1).Add(new Paragraph(group.discountTime.ToString("yyyy-MM-dd HH:mm"))).SetTextAlignment(TextAlignment.CENTER).SetVerticalAlignment(VerticalAlignment.MIDDLE)); |
|
|
table.AddCell(new Cell(rowSpan, 1).Add(new Paragraph(group.discountTime.ToString("yyyy-MM-dd HH:mm"))).SetTextAlignment(TextAlignment.CENTER).SetVerticalAlignment(VerticalAlignment.MIDDLE)); |
|
|
table.AddCell(new Cell(rowSpan, 1).Add(new Paragraph(group.enterTime?.ToString("yyyy-MM-dd HH:mm") ?? "")).SetTextAlignment(TextAlignment.CENTER).SetVerticalAlignment(VerticalAlignment.MIDDLE)); |
|
|
table.AddCell(new Cell(rowSpan, 1).Add(new Paragraph(group.enterTime?.ToString("yyyy-MM-dd HH:mm") ?? "")).SetTextAlignment(TextAlignment.CENTER).SetVerticalAlignment(VerticalAlignment.MIDDLE)); |
|
|
table.AddCell(new Cell(rowSpan, 1).Add(new Paragraph(group.exitTime?.ToString("yyyy-MM-dd HH:mm") ?? "")).SetTextAlignment(TextAlignment.CENTER).SetVerticalAlignment(VerticalAlignment.MIDDLE)); |
|
|
table.AddCell(new Cell(rowSpan, 1).Add(new Paragraph(group.exitTime?.ToString("yyyy-MM-dd HH:mm") ?? "")).SetTextAlignment(TextAlignment.CENTER).SetVerticalAlignment(VerticalAlignment.MIDDLE)); |
|
|
table.AddCell(new Cell(rowSpan, 1).Add(new Paragraph(group.parkingAmount?.ToString("N0") ?? "")).SetTextAlignment(TextAlignment.CENTER).SetVerticalAlignment(VerticalAlignment.MIDDLE)); |
|
|
|
|
|
table.AddCell(new Cell(rowSpan, 1).Add(new Paragraph(group.claimAmount?.ToString("N0") ?? "")).SetTextAlignment(TextAlignment.CENTER).SetVerticalAlignment(VerticalAlignment.MIDDLE)); |
|
|
|
|
|
|
|
|
table.AddCell(new Cell(rowSpan, 1).Add(new Paragraph($"NT$ {group.parkingAmount:N0}")).SetTextAlignment(TextAlignment.CENTER).SetVerticalAlignment(VerticalAlignment.MIDDLE)); |
|
|
|
|
|
table.AddCell(new Cell(rowSpan, 1).Add(new Paragraph($"NT$ {group.claimAmount:N0}")).SetTextAlignment(TextAlignment.CENTER).SetVerticalAlignment(VerticalAlignment.MIDDLE)); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|