ibms-dome/FrontendWebApi/ApiControllers/TenantBillController.cs

720 lines
33 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using FrontendWebApi.Models;
using Microsoft.AspNetCore.Mvc;
using Repository.BackendRepository.Interface;
using Repository.FrontendRepository.Interface;
using System.Collections.Generic;
using System.Threading.Tasks;
using System;
using System.IO;
using static FrontendWebApi.Models.Bill;
using Microsoft.Extensions.Logging;
using System.Text.Json;
using Newtonsoft.Json.Linq;
using System.Security.Cryptography;
using WkHtmlToPdfDotNet.Contracts;
using WkHtmlToPdfDotNet;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.SignalR;
using Microsoft.Extensions.Configuration;
using Serilog.Core;
using static FrontendWebApi.ApiControllers.TenantBillController;
using System.Reflection;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using System.Data.SqlTypes;
using System.Linq;
// For more information on enabling Web API for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860
namespace FrontendWebApi.ApiControllers
{
//[Route("api/[controller]")]
//[ApiController]
//public class TenantBillController
public class TenantBillController : MyBaseApiController<TenantBillController>
{
private readonly IBackendRepository backendRepository;
private readonly ILogger<TenantBillController> _logger;
private readonly IConfiguration Configuration;
private IWebHostEnvironment _webHostEnvironment;
private readonly IConverter _converter;
const string TenantListtable = "archive_electric_meter_tenant_list";
const string TenantBilltable = "archive_electric_meter_tenant_bill";
public TenantBillController(IBackendRepository backendRepository, IFrontendRepository frontendRepository, ILogger<TenantBillController> logger,
IConfiguration configuration,
IWebHostEnvironment webHostEnvironment,
IConverter converter)
{
this.backendRepository = backendRepository;
this._logger = logger;
Configuration = configuration;
_webHostEnvironment = webHostEnvironment;
_converter = converter;
}
[HttpPost]
public async Task<ApiResult<List<TenantList>>> GetTenantList()
{
ApiResult<List<TenantList>> apiResult = new ApiResult<List<TenantList>>();
List<TenantList> tenantList = new List<TenantList>();
try
{
var sqlString = $"SELECT tenant_guid,list_id,tenant_name,bill_perKWH,bill_perRCV " +
$"from {TenantListtable} order by created_at";
tenantList = await backendRepository.GetAllAsync<TenantList>(sqlString);
apiResult.Code = "0000";
apiResult.Data = tenantList;
}
catch (Exception exception)
{
apiResult.Code = "9999";
apiResult.Msg = "讀取不到用戶資料。";
Logger.LogError("【" + controllerName + "/" + actionName + "】" + exception.Message);
}
return apiResult;
}
[HttpPost]
public async Task<ApiResult<string>> AddOneTenantList([FromBody] TenantList tl)
{
ApiResult<string> apiResult = new ApiResult<string>();
try
{
var tenant_guid = Guid.NewGuid();
var tenant_name = tl.tenant_name;
var bill_perKWH = tl.bill_perKWH;
var bill_perRCV = tl.bill_perRCV;
var created_at = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
var sqlString = $"INSERT INTO {TenantListtable} (tenant_guid,list_id,tenant_name, bill_perKWH, bill_perRCV, created_by,created_at) " +
$"VALUES ('{tenant_guid}','{tl.list_id}','{tenant_name}', {bill_perKWH}, {bill_perRCV},'{tl.created_by}', '{created_at}')";
await backendRepository.ExecuteSql(sqlString);
apiResult.Code = "0000";
apiResult.Msg = "新增成功";
}
catch (Exception exception)
{
apiResult.Code = "9999";
apiResult.Msg = "新增用戶失敗。";
if (exception.Message.Contains($" for key 'PRIMARY'"))
{
apiResult.Code = "0001";
apiResult.Msg = "已有相同用戶。";
}
Logger.LogError("【" + controllerName + "/" + actionName + "】" + exception.Message);
}
return apiResult;
}
[HttpPost]
public async Task<ApiResult<string>> UpdateOneTenantList([FromBody] TenantList tl)
{
ApiResult<string> apiResult = new ApiResult<string>();
try
{
var updated_at = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
var sqlString = $"UPDATE {TenantListtable} SET " +
$"`tenant_name` = '{tl.tenant_name}', " +
$"`bill_perKWH` = {tl.bill_perKWH}, " +
$"`bill_perRCV` = {tl.bill_perRCV}, " +
$"`updated_at` = '{updated_at}' " +
$"WHERE `tenant_guid` = '{tl.tenant_guid}'";
await backendRepository.ExecuteSql(sqlString);
apiResult.Code = "0000";
apiResult.Msg = "修改用戶成功";
}
catch (Exception exception)
{
apiResult.Code = "9999";
apiResult.Msg = "修改失敗。";
if (exception.Message.Contains($"a foreign key constraint"))
{
apiResult.Code = "0001";
apiResult.Msg = "水電報表仍有該用戶,無法修改名稱。";
}
Logger.LogError("【" + controllerName + "/" + actionName + "】" + exception.Message);
}
return apiResult;
}
[HttpPost]
public async Task<ApiResult<string>> DelOneTenantList([FromBody] TenantList tl)
{
ApiResult<string> apiResult = new ApiResult<string>();
try
{
var sqlString = $"delete from {TenantListtable} WHERE tenant_guid = '{tl.tenant_guid}' ";
await backendRepository.ExecuteSql(sqlString);
apiResult.Code = "0000";
apiResult.Msg = "刪除成功";
}
catch (Exception exception)
{
apiResult.Code = "9999";
apiResult.Msg = "刪除用戶失敗。";
if (exception.Message.Contains($"a foreign key constraint"))
{
apiResult.Code = "0001";
apiResult.Msg = "水電報表仍有該用戶,無法刪除。";
}
Logger.LogError("【" + controllerName + "/" + actionName + "】" + exception.Message);
}
return apiResult;
}
[HttpPost]
public async Task<ApiResult<List<TenantBill>>> GetTenantBill([FromBody] TenantBill tb)
{
ApiResult<List<TenantBill>> apiResult = new ApiResult<List<TenantBill>>();
List<TenantBill> tenantBill = new List<TenantBill>();
try
{
string tableType = tb.tableType;
string building_tag = tb.building_tag;
string ElecOrWater = tableType == "elec" ? "E4" : "W1";
string sqlString = null;
#region
string checkDataSql = $@"SELECT device_number,device_name_tag,full_name
FROM device
WHERE device_name_tag = 'E4' and deleted = 0 and is_link = 1 or device_name_tag = 'W1' and deleted = 0 and is_link = 1; ";
var existData = await backendRepository.GetAllAsync<Device>(checkDataSql);
string checkDataSql2 = $@"select * from archive_electric_meter_tenant_bill; ";
var existData2 = await backendRepository.GetAllAsync<TenantBill>(checkDataSql2);
var commonValues = existData.Select(a => a.device_number)
.Intersect(existData2.Select(b => b.device_number))
.ToList();
if (commonValues.Any())
{
string updateSql = $@"UPDATE archive_electric_meter_tenant_bill
SET deleted = 0
WHERE device_number IN ('{string.Join("', '", commonValues)}')";
await backendRepository.ExecuteSql(updateSql);
}
var newValues = existData.Select(a => a.device_number)
.Except(existData2.Select(b => b.device_number))
.ToList();
if (newValues.Any())
{
string insertSql = $@"INSERT INTO archive_electric_meter_tenant_bill (device_number, device_name_tag, created_at)
SELECT device_number, device_name_tag, NOW()
FROM device
WHERE device_number IN ('{string.Join("', '", newValues)}')";
await backendRepository.ExecuteSql(insertSql);
}
var deletedValues = existData2.Select(a => a.device_number)
.Except(existData.Select(b => b.device_number))
.ToList();
if (deletedValues.Any())
{
string updateSql = $@"UPDATE archive_electric_meter_tenant_bill
SET deleted = 1
WHERE device_number IN ('{string.Join("', '", deletedValues)}')";
await backendRepository.ExecuteSql(updateSql);
}
#endregion
if (building_tag == "D2")
{
sqlString =
$"SELECT bill_id,a.device_number,b.full_name,start_timestamp,end_timestamp,result,bill,tenant_name,tenant_guid " +
$"from {TenantBilltable} a join device b on a.device_number =b.device_number " +
$"where device_building_tag = 'D1' and a.device_name_tag = '{ElecOrWater}' and a.deleted = 0 || device_building_tag = 'D2' and a.device_name_tag = '{ElecOrWater}' and a.deleted = 0";
}
else
{
sqlString =
$"SELECT bill_id,a.device_number,b.full_name,start_timestamp,end_timestamp,result,bill,tenant_name,tenant_guid " +
$"from {TenantBilltable} a join device b on a.device_number = b.device_number " +
$"where device_building_tag = '{building_tag}' and a.device_name_tag = '{ElecOrWater}' and a.deleted = 0";
}
tenantBill = await backendRepository.GetAllAsync<TenantBill>(sqlString);
apiResult.Code = "0000";
apiResult.Data = tenantBill;
}
catch (Exception exception)
{
apiResult.Code = "9999";
apiResult.Msg = "讀取水電參考報表失敗。";
Logger.LogError("【" + controllerName + "/" + actionName + "】" + exception.Message);
}
return apiResult;
}
[HttpPost]
public async Task<ApiResult<string>> UpdateTenantBill([FromBody] TenantBill tb)
{
ApiResult<string> apiResult = new ApiResult<string>();
try
{
string bill_per = tb.tableType == "elec" ? "bill_perKWH" : "bill_perRCV";
var updated_at = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
var start_timestamp = tb.start_timestamp;
var end_timestamp = tb.end_timestamp;
string sqlString = null;
string result = "0";
if (tb.start_timestamp == "" || tb.end_timestamp == "" || tb.tenant_guid == "" || tb.tenant_guid == null)
{
sqlString = $@"UPDATE {TenantBilltable}
set tenant_name = (SELECT tenant_name from archive_electric_meter_tenant_list
WHERE tenant_guid = '{tb.tenant_guid}'), start_timestamp = '{start_timestamp}',end_timestamp = '{end_timestamp}' ,
result= 0,
bill = 0,
updated_at = '{updated_at}',
tenant_guid = '{tb.tenant_guid}'
WHERE device_number = '{tb.device_number}'";
await backendRepository.ExecuteSql(sqlString);
apiResult.Code = "0000";
apiResult.Msg = "資料填寫不完整";
return apiResult;
}
else
{
List<string> howManyMonth = new List<string>();
List<string> existMonth = new List<string>();
DateTime date1 = DateTime.Parse(start_timestamp);
DateTime date2 = DateTime.Parse(end_timestamp);
int monthsApart = ((date2.Year - date1.Year) * 12) + date2.Month - date1.Month;
// 找出資料庫存在的水電月份表
string checkTabelSql = $@"SELECT TABLE_NAME
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA like 'ibms_dome_%' and TABLE_NAME like 'archive_electric_water_meter_day_%'";
var existTable = await backendRepository.GetAllAsync<string>(checkTabelSql);
for (var i = 0; i <= monthsApart; i++)
{
howManyMonth.Add($@"archive_electric_water_meter_day_{date1.AddMonths(i).ToString("yyyyMM")}");
}
foreach (var item in existTable)
{
foreach (var data in howManyMonth)
{
if (item == data)
{
existMonth.Add(data);
}
}
}
if (existMonth.Count == 0)
{
sqlString = $@"UPDATE {TenantBilltable}
set tenant_name = (SELECT tenant_name from archive_electric_meter_tenant_list
WHERE tenant_guid = '{tb.tenant_guid}'), start_timestamp = '{start_timestamp}',end_timestamp = '{end_timestamp}' ,
result= 0,
bill = 0,
updated_at = '{updated_at}',
tenant_guid = '{tb.tenant_guid}'
WHERE device_number = '{tb.device_number}'";
}
else
{
string month = $@"
SELECT start_timestamp,device_number, sub_result
FROM {existMonth[0]}
WHERE device_number = '{tb.device_number}'";
for (var i = 1; i < existMonth.Count; i++)
{
month += $@"UNION ALL
SELECT start_timestamp,device_number, sub_result
FROM {existMonth[i]}
WHERE device_number = '{tb.device_number}' ";
}
string checkDataSql = $@"(SELECT sum(sub_result)
FROM ( {month}
) combined_result
WHERE start_timestamp BETWEEN '{start_timestamp}' and '{end_timestamp}') ";
var existData = await backendRepository.GetAllAsync<string>(checkDataSql);
if (existData.Count != 0)
{
result = $@"(SELECT ROUND(sum(sub_result))
FROM ( {month}
) combined_result
WHERE start_timestamp BETWEEN '{start_timestamp}' and '{end_timestamp}') ";
}
sqlString =
$@"UPDATE {TenantBilltable}
set tenant_name = (SELECT tenant_name from archive_electric_meter_tenant_list WHERE tenant_guid = '{tb.tenant_guid}'), start_timestamp = '{start_timestamp}',end_timestamp = '{end_timestamp}' ,
result= {result},
bill = ROUND(result *(SELECT {bill_per} from {TenantListtable} WHERE tenant_guid = '{tb.tenant_guid}') ),
updated_at = '{updated_at}',
tenant_guid = '{tb.tenant_guid}'
WHERE device_number = '{tb.device_number}'";
}
await backendRepository.ExecuteSql(sqlString);
}
}
catch (Exception exception)
{
apiResult.Code = "9999";
apiResult.Msg = "修改水電參考報表失敗。";
Logger.LogError("【" + controllerName + "/" + actionName + "】" + exception.Message);
return apiResult;
}
apiResult = await CheckDay(tb);
return apiResult;
}
[HttpPost]
public async Task<ApiResult<string>> CheckDay([FromBody] TenantBill tb)
{
ApiResult<string> apiResult = new ApiResult<string>();
if (tb.start_timestamp != "" && tb.end_timestamp != "" && tb.tenant_guid != "")
{
List<TenantBill> tenantBill = new List<TenantBill>();
try
{
string sqlString = $@"select * from {TenantBilltable} WHERE tenant_guid= '{tb.tenant_guid}' and deleted = 0";
tenantBill = await backendRepository.GetAllAsync<TenantBill>(sqlString);
if (tenantBill.Count > 1)
{
foreach (TenantBill t in tenantBill)
{
if (t.start_timestamp == tb.start_timestamp && t.end_timestamp == tb.end_timestamp)
{
continue;
}
else
{
apiResult.Code = "0001";
apiResult.Msg = "該用戶設備的起訖日期不一致,是否將所有設備起訖日期調為一致?";
return apiResult;
}
}
apiResult.Code = "0000";
apiResult.Msg = "修改成功且該用戶的所有設備日期一致";
}
}
catch (Exception exception)
{
apiResult.Code = "9999";
apiResult.Msg = "確認日期失敗。";
Logger.LogError("【" + controllerName + "/" + actionName + "】" + exception.Message);
}
}
apiResult.Code = "0000";
apiResult.Msg = "修改成功且不執行CheckDay";
return apiResult;
}
[HttpPost]
public async Task<ApiResult<string>> ChangeDay([FromBody] TenantBill tb)
{
ApiResult<string> apiResult = new ApiResult<string>();
List<TenantBill> tenantBill = new List<TenantBill>();
try
{
string sqlString = $@"select * from {TenantBilltable} WHERE tenant_guid= '{tb.tenant_guid}' and deleted = 0";
tenantBill = await backendRepository.GetAllAsync<TenantBill>(sqlString);
foreach (TenantBill t in tenantBill)
{
if (t.start_timestamp == tb.start_timestamp && t.end_timestamp == tb.end_timestamp)
{
continue;
}
else
{
t.start_timestamp = tb.start_timestamp;
t.end_timestamp = tb.end_timestamp;
t.tableType = t.device_name_tag == "E4" ? "elec": "water";
await UpdateTenantBill(t);
}
}
apiResult.Code = "0000";
apiResult.Msg = "修改成功";
}
catch (Exception exception)
{
apiResult.Code = "9999";
apiResult.Msg = "更換日期失敗。";
Logger.LogError("【" + controllerName + "/" + actionName + "】" + exception.Message);
}
return apiResult;
}
[HttpPost]
public async Task<IActionResult> OutputTenantBill([FromBody] TenantBill tb)
{
List<OutputBill> outputBill = new List<OutputBill>();
try
{
List<string> buildings = tb.building_tag_list;
string building_tag = "";
foreach (var item in buildings)
{
if (item == buildings[0])
{
building_tag = item == "D2" ? $@"device_building_tag = 'D1' and a.deleted = 0 || device_building_tag = '{item}' and a.deleted = 0" : $@"device_building_tag = '{item}' and a.deleted = 0" ;
}
else
{
building_tag += item == "D2" ? $@"|| device_building_tag = 'D1' and a.deleted = 0 || device_building_tag = '{item}' and a.deleted = 0" : $@"|| device_building_tag = '{item}' and a.deleted = 0";
}
}
string checkDataSql = $@"select * from archive_electric_meter_tenant_bill a
join device c on a.device_number = c.device_number
WHERE tenant_name is not null and tenant_guid is not null and tenant_name != '' and tenant_guid !=''
AND ({building_tag})";
var existData = await backendRepository.GetAllAsync<string>(checkDataSql);
if (existData.Count != 0)
{
string sqlString =
$@"SELECT
tenant_name,
tenant_guid,
start_timestamp,
end_timestamp,
bill_perKWH,
bill_perRCV,
elec_result,
water_result,
elec_bill,
water_bill,
(elec_bill + water_bill) AS total_bill
FROM (
SELECT
a.tenant_name,
a.tenant_guid,
MIN(NULLIF(a.start_timestamp, '')) AS start_timestamp,
MAX(NULLIF(a.end_timestamp, '')) AS end_timestamp,
bill_perKWH,
bill_perRCV,
SUM(CASE WHEN a.device_name_tag = 'E4' THEN result ELSE 0 END) AS elec_result,
SUM(CASE WHEN a.device_name_tag = 'W1' THEN result ELSE 0 END) AS water_result,
ROUND(bill_perKWH * SUM(CASE WHEN a.device_name_tag = 'E4' THEN result ELSE 0 END)) AS elec_bill,
ROUND(bill_perRCV * SUM(CASE WHEN a.device_name_tag = 'W1' THEN result ELSE 0 END)) AS water_bill
FROM archive_electric_meter_tenant_bill a
JOIN archive_electric_meter_tenant_list b ON a.tenant_guid = b.tenant_guid
JOIN device c ON a.device_number = c.device_number
WHERE {building_tag}
GROUP BY a.tenant_name
) AS subquery_alias;";
outputBill = await backendRepository.GetAllAsync<OutputBill>(sqlString);
string deviceSql = @$"select a.tenant_guid,d.full_name from archive_electric_meter_tenant_bill a join device d on a.device_number = d.device_number";
var device = await backendRepository.GetAllAsync<TenantBill>(deviceSql);
string filePath = CreateOutputForm(outputBill, device);
byte[] file = System.IO.File.ReadAllBytes(filePath);
return new FileContentResult(file, "application/pdf")
{
FileDownloadName = "水電報表.pdf"
};
}
else
{
var data = new { Code = "0001",Msg = "還沒有選擇用戶,無法匯出檔案。"};
return StatusCode(400, data);
}
}
catch (Exception exception)
{
Logger.LogError("【" + controllerName + "/" + actionName + "】" + exception.Message);
}
return new FileContentResult(new byte[0], "application/pdf")
{
FileDownloadName = "Empty.pdf"
};
}
public string CreateOutputForm(List<OutputBill> outputBill, List<TenantBill> device)
{
try
{
string htmlStr = this.getOutputFormHtmlStr(outputBill, device);
string filepath = Configuration.GetValue<string>("FilePath:OutputForm");
if (!Directory.Exists(filepath))
{
Directory.CreateDirectory(filepath);
_logger.LogInformation("file CreateOutputForm path: " + filepath);
}
var nowString = DateTime.UtcNow.AddHours(8).ToString("yyyyMMdd_HHmmss");
//Random r1 = new System.Random();
//string r2 = r1.Next(0, 999).ToString("0000");
//string r2 = RandomNumberGenerator.GetInt32(0, 999).ToString("0000");
filepath += $"{nowString}_水電報表.pdf";
var doc = new HtmlToPdfDocument()
{
GlobalSettings = {
ColorMode = ColorMode.Color,
//Orientation = Orientation.Landscape,
PaperSize = PaperKind.A4,
Out = filepath,
Margins = new MarginSettings
{
Unit = Unit.Millimeters,
Top = 10,
Bottom = 10,
Right = 0,
Left = 0
},
},
Objects = {
new ObjectSettings() {
HtmlContent=htmlStr,
WebSettings = { DefaultEncoding = "utf-8"},
FooterSettings = new FooterSettings() {
Center = "第 [page] 頁 共 [topage] 頁",
FontName = "DFKai-sb",
},
LoadSettings = new LoadSettings() {
JSDelay = 1000,
StopSlowScript = false,
BlockLocalFileAccess = false,
DebugJavascript = true
}
//HeaderSettings = { FontSize = 9, Right = "Page [page] of [toPage]", Line = true, Spacing = 2.812 }
}
}
};
// _converter.Warning += ConvertWarning;
_converter.Convert(doc);
//IntPtr converter = _converter.CreateConverter(doc);
//_converter.Tools.DestroyConverter();
return filepath;
}
catch (Exception ex)
{
throw new Exception(ex.ToString());
}
}
private string getOutputFormHtmlStr(List<OutputBill> outputBill, List<TenantBill> device)
{
try
{
string path = Configuration.GetValue<string>("FilePath:OutputFormTemplate");
string image = Configuration.GetValue<string>("FilePath:Image");
//string path = _webHostEnvironment.ContentRootPath + "\\StaticFiles\\import.html";
if (!System.IO.File.Exists(path))
{
return "";
}
//string cssroot = _webHostEnvironment.ContentRootPath + "\\StaticFiles\\css\\";
string htmlStr = System.IO.File.ReadAllText(path);
//string vendorscss = System.IO.File.ReadAllText(cssroot + "vendors.bundle.css");
//string appBundelCss = System.IO.File.ReadAllText(cssroot + "app.bundle.css");
//string skinmasterCss = System.IO.File.ReadAllText(cssroot + "skins\\skin-master.css");
string bill = "";
foreach (var item in outputBill)
{
var devices = device.Where(x => x.tenant_guid == item.tenant_guid).Select(x => x.full_name).ToList();
string deviceList = string.Join(" , ", devices);
bill += @$" <div class='container a4-page'>
<div class='header'>
<img src='{image}' alt='Taipei Dome Logo' width='150'>
<h2>水電費用明細</h2>
</div>
<div class='statistics'>
<h3>費用資訊</h3>
<p><strong>用戶: </strong>{item.tenant_name}</p>
<p><strong>起訖時間: </strong>{item.start_timestamp} ~ {item.end_timestamp}</p>
<table class='br'>
<tr>
<td><strong>用電量: </strong>{item.elec_result}度</td>
<td><strong>單價: </strong>{item.bill_perKWH}元/度</td>
<td><strong>電費總計: </strong>{item.elec_bill.ToString("#,##0")}元</td>
</tr>
<tr>
<td><strong>: </strong>{item.water_result}</td>
<td><strong>: </strong>{item.bill_perRCV}/</td>
<td><strong>: </strong>{item.water_bill.ToString("#,##0")}</td>
</tr>
</table>
<p class='warnTxt'>
<strong>()/ * ()</strong>
</p>
</div>
<div class='total'>
<div class='total-area'>
<h3></h3>
<div class='total-box'>
<span class='total-money'>{item.total_bill.ToString("#,##0")}</span>
</div>
</div>
<div class='total-area'>
<h3></h3>
<div>
{deviceList}
</div>
</div>
</div>
</div>";
}
htmlStr = htmlStr.Replace("{{bill}}", bill);
return htmlStr;
}
catch (Exception ex)
{
throw new Exception(ex.ToString());
}
}
}
}