Files
thinkyu/branches/1150807/Services/領據處理.asmx.cs
T
sryang 577060bc78 chore: 首次簽入 Thinkyu ASP.NET 專案
- 加入 Visual Studio / ASP.NET .gitignore
- 排除建置輸出、IDE 設定、NuGet packages、大型 MSI 安裝檔
2026-09-10 09:42:37 +08:00

1471 lines
61 KiB
C#

using Education.Forms.領據系統;
using Education.Report;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Script.Services;
using System.Web.Services;
using WebLib;
namespace Education.Services
{
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
[ScriptService]
public class 領據處理 : ServiceBase
{
[WebMethod(EnableSession = true)]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public ServiceResponse SelectPage(
int pageIndex = 1,
int pageSize = 20,
DateTime? 活動日期_1 = null,
DateTime? 活動日期_2 = null,
string 身分別 = null,
string 講師_非講師編號 = null,
string 憑證類別 = null,
string 計畫代號 = null,
string 計畫名稱 = null,
string 活動類別 = null,
string 付款方式 = null,
string 領款人姓名 = null,
string orderBy = "")
{
try
{
DAC_領據 dac = new DAC_領據();
int startRowIndex = (pageIndex - 1) * pageSize;
var data = dac.SelectPageWithRelations(
noInputReturnAll: true,
startRowIndex: startRowIndex,
maximumRows: pageSize,
活動日期_1: 活動日期_1,
活動日期_2: 活動日期_2,
身分別: 身分別,
講師_非講師編號: 講師_非講師編號,
憑證類別: 憑證類別,
計畫代號: 計畫代號,
計畫名稱: 計畫名稱,
活動類別: 活動類別,
付款方式: 付款方式,
領款人姓名: 領款人姓名,
orderBy: orderBy
);
int totalCount = dac.SelectCount(
noInputReturnAll: true,
活動日期_1: 活動日期_1,
活動日期_2: 活動日期_2,
身分別: 身分別,
講師_非講師編號: 講師_非講師編號,
憑證類別: 憑證類別,
計畫代號: 計畫代號,
計畫名稱: 計畫名稱,
活動類別: 活動類別,
付款方式: 付款方式,
領款人姓名: 領款人姓名
);
return ServiceResponse.CreateSuccess("查詢成功", data, totalCount);
}
catch (Exception ex)
{
return ServiceResponse.CreateError($"查詢失敗:{ex.Message}");
}
}
[WebMethod(EnableSession = true)]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public ServiceResponse GetOne(int no)
{
try
{
using (var conn = DAC.NewConnection()) {
DAC_領據 dacMain = new DAC_領據(conn);
DAC_勞務費 dacLabor = new DAC_勞務費(conn);
DAC_差旅費 dacTravel = new DAC_差旅費(conn);
DAC_BPSN dacBPSN = new DAC_BPSN(conn);
var mainRec = dacMain.SelectOne(no).FirstOrDefault();
if (mainRec == null) {
return ServiceResponse.CreateError("沒有此筆資料");
}
mainRec.DB_CRUSR_NAME = dacBPSN.Get員工姓名(mainRec.DB_CRUSR);
mainRec.DB_TRUSR_NAME = dacBPSN.Get員工姓名(mainRec.DB_TRUSR);
var existingLabor = dacLabor.SelectOne(no).FirstOrDefault();
if (existingLabor != null)
{
mainRec.勞務費_編號 = existingLabor.編號;
mainRec.勞務費_費用別 = existingLabor.費用別;
mainRec.勞務費_單價 = existingLabor.單價;
mainRec.勞務費_數量 = existingLabor.數量;
mainRec.勞務費_單位 = existingLabor.單位;
mainRec.勞務費_扣繳類別 = existingLabor.扣繳類別;
mainRec.勞務費_合計金額 = existingLabor.合計金額;
mainRec.勞務費_應扣繳稅額 = existingLabor.應扣繳稅額;
mainRec.勞務費_服務費 = existingLabor.服務費;
mainRec.勞務費_作廢 = existingLabor.作廢;
}
var existingTravel = dacTravel.SelectOne(no).FirstOrDefault();
if (existingTravel != null)
{
mainRec.差旅費_編號 = existingTravel.編號;
mainRec.差旅費_票價資訊 = existingTravel.票價資訊;
mainRec.差旅費_費用別 = existingTravel.費用別;
mainRec.差旅費_起點 = existingTravel.起點;
mainRec.差旅費_訖點 = existingTravel.訖點;
mainRec.差旅費_捷運公車 = existingTravel.捷運公車;
mainRec.差旅費_火車 = existingTravel.火車;
mainRec.差旅費_計程車 = existingTravel.計程車;
mainRec.差旅費_高鐵飛機 = existingTravel.高鐵飛機;
mainRec.差旅費_自行開車 = existingTravel.自行開車;
mainRec.差旅費_過路費停車費 = existingTravel.過路費停車費;
mainRec.差旅費_住宿費 = existingTravel.住宿費;
mainRec.差旅費_合計 = existingTravel.合計;
mainRec.差旅費_作廢 = existingTravel.作廢;
}
return ServiceResponse.CreateSuccess("OK", data: mainRec);
}
}
catch (Exception ex)
{
return ServiceResponse.CreateError($"取得資料失敗:{ex.Message}");
}
}
[WebMethod(EnableSession = true)]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public ServiceResponse Save(bool isNew, 領據Item mainItem, 勞務費Item laborItem, 差旅費Item travelItem)
{
try
{
using (var ts = DAC.NewTransactionScope())
{
using (var conn = DAC.NewConnection())
{
DAC_領據 dacMain = new DAC_領據(conn);
DAC_勞務費 dacLabor = new DAC_勞務費(conn);
DAC_差旅費 dacTravel = new DAC_差旅費(conn);
// 後端驗證:勞務費有金額但費用別或單位未填
if (laborItem != null && !dacLabor.IsEmpty(laborItem))
{
if (string.IsNullOrEmpty(laborItem.費用別))
return ServiceResponse.CreateError("勞務費已輸入金額,請選擇費用別");
if (string.IsNullOrEmpty(laborItem.單位))
return ServiceResponse.CreateError("勞務費已輸入金額,請選擇單位");
}
if (isNew)
{
mainItem = dacMain.InsertOne(mainItem);
if (laborItem != null && !dacLabor.IsEmpty(laborItem))
{
laborItem.領據編號 = mainItem.編號;
dacLabor.InsertOne(laborItem);
}
if (travelItem != null && !dacTravel.IsEmpty(travelItem))
{
travelItem.領據編號 = mainItem.編號;
dacTravel.InsertOne(travelItem);
}
ts.Complete();
return ServiceResponse.CreateSuccess("新增成功", mainItem);
}
else
{
dacMain.UpdateOne(mainItem);
if (laborItem != null && laborItem.領據編號 > 0)
{
var existingLabor = dacLabor.SelectOne(mainItem.編號);
if (existingLabor.Count > 0)
{
laborItem.DB_APPNO = existingLabor.FirstOrDefault().DB_APPNO;
dacLabor.UpdateOne(laborItem);
}
else if (!dacLabor.IsEmpty(laborItem))
{
dacLabor.InsertOne(laborItem);
}
}
if (travelItem != null && travelItem.領據編號 > 0)
{
var existingTravel = dacTravel.SelectOne(mainItem.編號);
if (existingTravel.Count > 0)
{
travelItem.DB_APPNO = existingTravel.FirstOrDefault().DB_APPNO;
dacTravel.UpdateOne(travelItem);
}
else if (!dacTravel.IsEmpty(travelItem))
{
dacTravel.InsertOne(travelItem);
}
}
ts.Complete();
return ServiceResponse.CreateSuccess("修改成功");
}
}
}
}
catch (Exception ex)
{
return ServiceResponse.CreateError($"儲存失敗:{ex.Message}");
}
}
[WebMethod(EnableSession = true)]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public ServiceResponse Delete(int no, int dbAppNo)
{
try
{
using (var ts = DAC.NewTransactionScope())
{
using (var conn = DAC.NewConnection())
{
DAC_領據 dacMain = new DAC_領據(conn);
DAC_勞務費 dacLabor = new DAC_勞務費(conn);
DAC_差旅費 dacTravel = new DAC_差旅費(conn);
var existingLabor = dacLabor.SelectOne(no);
if (existingLabor.Count > 0)
{
dacLabor.DeleteOne(no, existingLabor[0].DB_APPNO);
}
var existingTravel = dacTravel.SelectOne(no);
if (existingTravel.Count > 0)
{
dacTravel.DeleteOne(no, existingTravel[0].DB_APPNO);
}
dacMain.DeleteOne(no, dbAppNo);
ts.Complete();
return ServiceResponse.CreateSuccess("刪除成功");
}
}
}
catch (Exception ex)
{
return ServiceResponse.CreateError($"刪除失敗:{ex.Message}");
}
}
[WebMethod(EnableSession = true)]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public ServiceResponse Void(int no)
{
try
{
using (var conn = DAC.NewConnection()) {
DAC_領據 dacMain = new DAC_領據(conn);
DAC_勞務費 dacLabor = new DAC_勞務費(conn);
DAC_差旅費 dacTravel = new DAC_差旅費(conn);
DAC_組織人員 dacOrgnization = new DAC_組織人員(conn);
var mainItem = dacMain.SelectOne(no).FirstOrDefault();
if (mainItem == null)
{
return ServiceResponse.CreateError("找不到指定的領據");
}
mainItem.作廢 = (mainItem.作廢 == 1) ? 0 : 1;
// 取消作廢只有總管理處財務部可以執行
if (mainItem.作廢 == 0 && !dacOrgnization.Is人員屬於組織(PublicVariable.財務部ID, CurrentUserId))
{
return ServiceResponse.CreateError("財務部人員才可以取消作廢");
}
var laborItem = dacLabor.SelectOne(no).FirstOrDefault();
var travelItem = dacTravel.SelectOne(no).FirstOrDefault();
dacMain.UpdateOne(mainItem);
if (laborItem != null)
{
laborItem.作廢 = mainItem.作廢;
dacLabor.UpdateOne(laborItem);
}
if (travelItem != null)
{
travelItem.作廢 = mainItem.作廢;
dacTravel.UpdateOne(travelItem);
}
string action = mainItem.作廢 == 1 ? "作廢" : "取消作廢";
return ServiceResponse.CreateSuccess($"{action}成功");
}
}
catch (Exception ex)
{
return ServiceResponse.CreateError($"作廢操作失敗:{ex.Message}");
}
}
[WebMethod(EnableSession = true)]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public ServiceResponse VoidLaborFee(int receiptNo)
{
try
{
using (var conn = DAC.NewConnection())
{
DAC_勞務費 dacLabor = new DAC_勞務費(conn);
DAC_組織人員 dacOrgnization = new DAC_組織人員(conn);
var item = dacLabor.SelectOne(receiptNo).FirstOrDefault();
if (item == null)
{
return ServiceResponse.CreateError("找不到指定的勞務費資料");
}
item.作廢 = (item.作廢 == 1) ? 0 : 1;
// 取消作廢只有總管理處財務部可以執行
if (item.作廢 == 0 && !dacOrgnization.Is人員屬於組織(PublicVariable.財務部ID, CurrentUserId))
{
return ServiceResponse.CreateError("財務部人員才可以取消作廢");
}
dacLabor.UpdateOne(item);
string action = item.作廢 == 1 ? "作廢" : "取消作廢";
return ServiceResponse.CreateSuccess($"勞務費{action}成功");
}
}
catch (Exception ex)
{
return ServiceResponse.CreateError($"勞務費作廢操作失敗:{ex.Message}");
}
}
[WebMethod(EnableSession = true)]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public ServiceResponse VoidTravelFee(int receiptNo)
{
try
{
using (var conn = DAC.NewConnection())
{
DAC_差旅費 dacTravel = new DAC_差旅費(conn);
DAC_組織人員 dacOrgnization = new DAC_組織人員(conn);
var item = dacTravel.SelectOne(receiptNo).FirstOrDefault();
if (item == null)
{
return ServiceResponse.CreateError("找不到指定的差旅費資料");
}
item.作廢 = (item.作廢 == 1) ? 0 : 1;
// 取消作廢只有總管理處財務部可以執行
if (item.作廢 == 0 && !dacOrgnization.Is人員屬於組織(PublicVariable.財務部ID, CurrentUserId))
{
return ServiceResponse.CreateError("財務部人員才可以取消作廢");
}
dacTravel.UpdateOne(item);
string action = item.作廢 == 1 ? "作廢" : "取消作廢";
return ServiceResponse.CreateSuccess($"差旅費{action}成功");
}
}
catch (Exception ex)
{
return ServiceResponse.CreateError($"差旅費作廢操作失敗:{ex.Message}");
}
}
[WebMethod(EnableSession = true)]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public ServiceResponse CalcTax(int laborFee, string category)
{
try
{
int tax = 0;
if (category != null)
{
if ((category.StartsWith("9A") || category.StartsWith("9B")) && laborFee > PublicVariable.領據執行業務所得課稅門檻)
{
tax = (int)Math.Round(laborFee * PublicVariable.領據執行業務所得稅率, MidpointRounding.AwayFromZero);
}
else if (category.StartsWith("50") && laborFee >= PublicVariable.領據薪資課稅門檻)
{
tax = (int)Math.Round(laborFee * PublicVariable.領據薪資稅率, MidpointRounding.AwayFromZero);
}
}
return ServiceResponse.CreateSuccess("計算成功", tax);
}
catch (Exception ex)
{
return ServiceResponse.CreateError($"計算稅額失敗:{ex.Message}");
}
}
[WebMethod(EnableSession = true)]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public ServiceResponse SearchRecipient(string key, string identity, DateTime? activationDate)
{
try
{
if (string.IsNullOrEmpty(key))
{
return ServiceResponse.CreateSuccess("查詢成功", new List<dynamic>());
}
var result = new List<dynamic>();
using (var conn = DAC.NewConnection()) {
if (identity == "講師")
{
DAC_講師 dacInstructor = new DAC_講師(conn);
DAC_付款設定 dacPaymentSetting = new DAC_付款設定(conn);
var instructors = dacInstructor.SelectByKeyword(key);
foreach (var item in instructors)
{
var paymentSetting = dacPaymentSetting.SelectRecentlyActivated(item.付款設定講師編號, activationDate);
result.Add(new
{
Name = item.姓名,
IdNumber = item.身份證字號,
Value = item.編號.ToString(),
VoucherType = paymentSetting?.憑證類別,
ConductType = paymentSetting?.扣繳類別,
});
}
}
else if (identity == "非講師")
{
DAC_非講師 dacNonInstructor = new DAC_非講師(conn);
DAC_付款設定 dacPaymentSetting = new DAC_付款設定(conn);
var nonInstructors = dacNonInstructor.SelectByKeyword(key);
foreach (var item in nonInstructors)
{
var paymentSetting = dacPaymentSetting.SelectRecentlyActivated(item.編號, activationDate);
result.Add(new
{
Name = item.姓名,
IdNumber = item.身分證字號,
Value = item.編號,
VoucherType = paymentSetting?.憑證類別,
ConductType = paymentSetting?.扣繳類別,
});
}
}
}
if (result.Count > 0)
return ServiceResponse.CreateSuccess("查詢成功", result);
return ServiceResponse.CreateError($"無符合資料");
}
catch (Exception ex)
{
return ServiceResponse.CreateError($"搜尋失敗:{ex.Message}");
}
}
[WebMethod(EnableSession = true)]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public ServiceResponse SearchPlan(string key, int year = 0)
{
try
{
if (string.IsNullOrEmpty(key))
{
return ServiceResponse.CreateSuccess("查詢成功", new List<dynamic>());
}
key = key.ToUpper();
var result = new List<dynamic>();
DAC_BPAA dac = new DAC_BPAA();
DataTable dtPlans, dtPlansAdditional = null;
if (year > 0)
{
dtPlans = dac.GetBpaaWithTYPlusNone(year);
if (year == 115)
{
dtPlansAdditional = dac.GetBpaaWithTYPlusNone(114);
}
}
else
{
dtPlans = dac.GetBpaaWithTYPlusNone();
}
if (dtPlans != null && dtPlans.Rows.Count > 0)
{
if (dtPlansAdditional != null)
{
foreach (DataRow row in dtPlansAdditional.Select("BPPYN = '114AG114003'"))
{
dtPlans.ImportRow(row);
}
}
foreach (DataRow row in dtPlans.Rows)
{
string planCode = row["BPPYN"].ToString();
string planName = row["BPPYM"].ToString();
if (planCode.Contains(key) || planName.Contains(key))
{
result.Add(new
{
Name = planName,
Code = planCode,
Value = planCode
});
}
}
}
if (result.Count > 0)
return ServiceResponse.CreateSuccess("查詢成功", result);
return ServiceResponse.CreateError($"無符合資料");
}
catch (Exception ex)
{
return ServiceResponse.CreateError($"搜尋計畫失敗:{ex.Message}");
}
}
[WebMethod(EnableSession = true)]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public ServiceResponse GetDropdownLists(string key)
{
try
{
NameValueList result = null;
switch (key)
{
case "身分別":
result = 身分別.InputSelectList; break;
case "憑證類別":
result = 憑證類別.InputSelectList; break;
case "付款方式":
result = 付款方式.InputSelectList; break;
case "扣繳類別":
result = 扣繳類別.InputSelectList; break;
case "勞務費_費用別":
result = 勞務費_費用別.InputSelectList; break;
case "差旅費_費用別":
result = 差旅費_費用別.InputSelectList; break;
case "單位別":
result = 單位別.InputSelectList; break;
}
if (result != null)
return ServiceResponse.CreateSuccess("取得下拉選單資料成功", result);
return ServiceResponse.CreateError($"取得下拉選單資料失敗:找不到對應的下拉選單");
}
catch (Exception ex)
{
return ServiceResponse.CreateError($"取得下拉選單資料失敗:{ex.Message}");
}
}
[WebMethod(EnableSession = true)]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public ServiceResponse GetSearchDropdownLists(string key)
{
try
{
NameValueList result = null;
switch (key)
{
case "身分別":
result = 身分別.SearchSelectList; break;
case "憑證類別":
result = 憑證類別.SearchSelectList; break;
case "付款方式":
result = 付款方式.SearchSelectList; break;
case "扣繳類別":
result = 扣繳類別.SearchSelectList; break;
case "勞務費_費用別":
result = 勞務費_費用別.SearchSelectList; break;
case "差旅費_費用別":
result = 差旅費_費用別.SearchSelectList; break;
case "單位別":
result = 單位別.SearchSelectList; break;
}
if (result != null)
return ServiceResponse.CreateSuccess("取得下拉選單資料成功", result);
return ServiceResponse.CreateError($"取得下拉選單資料失敗:找不到對應的下拉選單");
}
catch (Exception ex)
{
return ServiceResponse.CreateError($"取得查詢下拉選單資料失敗:{ex.Message}");
}
}
[WebMethod(EnableSession = true)]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public ServiceResponse GetPhraseLists()
{
try
{
using (var conn = DAC.NewConnection()) {
var daoPhrase = new DAC_片語(conn);
var result = new
{
activityLocation = daoPhrase.SelectBy適用欄位("活動地點").Select(p => p.片語內容).ToList(),
activityCategory = daoPhrase.SelectBy適用欄位("活動類別").Select(p => p.片語內容).ToList(),
ticketPrice = daoPhrase.SelectBy適用欄位("票價資訊").Select(p => p.片語內容).ToList()
};
return ServiceResponse.CreateSuccess("取得片語清單成功", result);
}
}
catch (Exception ex)
{
return ServiceResponse.CreateError($"取得片語清單失敗:{ex.Message}");
}
}
[WebMethod(EnableSession = true)]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public ServiceResponse GetClosingMonth()
{
try
{
// 返回預設值,實際實作應該從 BWEX 表查詢
// BSNUM = '領據關帳年月', BSITM = ' 1', BSNAM = 關帳年月 (YYYY-MM 格式)
var result = new
{
currentClosingMonth = new DAC_BWEX().ReadSetting("領據關帳年月", 1)
};
return ServiceResponse.CreateSuccess("取得關帳年月成功", result);
}
catch (Exception ex)
{
return ServiceResponse.CreateError($"取得關帳年月失敗:{ex.Message}");
}
}
[WebMethod(EnableSession = true)]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public ServiceResponse UpdateClosingMonth(string closingMonth)
{
try
{
if (string.IsNullOrEmpty(closingMonth))
{
return ServiceResponse.CreateError("關帳年月不能為空");
}
// 驗證格式 YYYY-MM
if (!System.Text.RegularExpressions.Regex.IsMatch(closingMonth, @"^\d{4}-\d{2}$"))
{
return ServiceResponse.CreateError("關帳年月格式不正確,請使用 YYYY-MM 格式");
}
// 實作應該在此處更新 BWEX 表
PublicVariable.領據關帳年月 = closingMonth;
return ServiceResponse.CreateSuccess("關帳年月已成功更新");
}
catch (Exception ex)
{
return ServiceResponse.CreateError($"更新關帳年月失敗:{ex.Message}");
}
}
[WebMethod(EnableSession = true)]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public ServiceResponse Print(List<int> idList)
{
try
{
if (idList == null || idList.Count == 0)
{
return ServiceResponse.CreateError("未指定要列印的領據");
}
try
{
using (var ts = DAC.NewTransactionScope())
{
using (var conn = DAC.NewConnection())
{
DAC_領據 dacMain = new DAC_領據(conn);
DAC_勞務費 dacLabor = new DAC_勞務費(conn);
DAC_差旅費 dacTravel = new DAC_差旅費(conn);
DAC_講師 dac講師 = new DAC_講師(conn);
DAC_非講師 dac非講師 = new DAC_非講師(conn);
// 收集所有要列印的領據資料
List<PrintData> printDataList = new List<PrintData>();
// 無資料清單
List<string> noDataList = new List<string>();
foreach (var id in idList)
{
var mainRec = dacMain.SelectOne(id).FirstOrDefault();
if (mainRec == null)
{
continue;
}
if (mainRec.作廢 != 0)
{
noDataList.Add(mainRec.表單編號);
continue;
}
// 取得講師非講師資料
講師 講師 = null;
非講師Item 非講師 = null;
if (mainRec.身分別 == "講師")
{
講師 = dac講師.SelectOne(DAC.GetInt32(mainRec.講師_非講師編號)).FirstOrDefault();
}
else
{
非講師 = dac非講師.SelectOne(mainRec.講師_非講師編號).FirstOrDefault();
}
// 取得勞務費資料
var laborItem = dacLabor.SelectOne(id).Where(p => p.作廢 != 1).FirstOrDefault();
if (laborItem != null)
{
// 若勞務費編號為空,需要給勞務費自動編號
if (string.IsNullOrEmpty(laborItem.編號) && !laborItem.IsEmpty)
{
laborItem.編號 = dacLabor.Next單號(mainRec.活動日期, "勞務費", "編號", "'T'CCCMM<9999>", "");
dacLabor.UpdateOne(laborItem);
}
}
// 取得差旅費資料
var travelItem = dacTravel.SelectOne(id).Where(p => p.作廢 != 1).FirstOrDefault();
if (travelItem != null && travelItem.合計.HasValue && travelItem.合計 > 0)
{
// 若差旅費編號為空,需要給差旅費自動編號
if (string.IsNullOrEmpty(travelItem.編號) && !travelItem.IsEmpty)
{
travelItem.編號 = dacTravel.Next單號(mainRec.活動日期, "差旅費", "編號", "'E'CCCMM<9999>", "");
dacTravel.UpdateOne(travelItem);
}
}
if (laborItem != null && !laborItem.IsEmpty || travelItem != null && !travelItem.IsEmpty)
{
if (mainRec.憑證類別 == 憑證類別.憑證類別_領據)
{
mainRec.列印次數 = mainRec.列印次數.HasValue ? mainRec.列印次數.Value + 1 : 1;
dacMain.UpdateOne(mainRec);
printDataList.Add(new PrintData
{
Main = mainRec,
Labor = laborItem,
Travel = travelItem,
講師 = 講師,
非講師 = 非講師
});
}
else
{
noDataList.Add($"{mainRec.表單編號} 憑證類別不是領據");
}
}
else
{
noDataList.Add($"{mainRec.表單編號} 無資料或已作廢");
}
}
// 更新單據欄位
ts.Complete();
if (printDataList.Count == 0)
{
return ServiceResponse.CreateSuccess($"{string.Join("", noDataList.ToArray())}");
}
// 生成 Excel 檔案
Report.領據列印 report = new Report.領據列印();
System.IO.MemoryStream ms = report.DoReport(printDataList);
// 轉換為 Base64 編碼
string excelBase64 = Convert.ToBase64String(ms.ToArray());
// 生成檔案名稱
string fileName = string.Format("領據{0}_{1:yyyyMMddHHmmss}.xlsx"
, (printDataList.Count > 0 ? string.Format("_{0}_{1}", printDataList[0].Main.領款人姓名, printDataList[0].Main.表單編號) : String.Empty)
, PublicVariable.TaiwanNow);
return ServiceResponse.CreateSuccess("列印成功", new
{
fileName = fileName,
excelData = excelBase64,
count = printDataList.Count
});
}
}
}
catch (Exception innerEx)
{
return ServiceResponse.CreateError(string.Format("列印處理失敗:{0}", innerEx.Message));
}
}
catch (Exception ex)
{
return ServiceResponse.CreateError(string.Format("列印失敗:{0}", ex.Message));
}
}
[WebMethod(EnableSession = true)]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public ServiceResponse Export(
DateTime? 活動日期_1 = null,
DateTime? 活動日期_2 = null,
string 身分別 = null,
string 講師_非講師編號 = null,
string 憑證類別 = null,
string 計畫代號 = null,
string 計畫名稱 = null,
string 活動類別 = null,
string 付款方式 = null,
string 領款人姓名 = null,
string orderBy = "")
{
try
{
using (var conn = DAC.NewConnection())
{
DAC_領據 dacMain = new DAC_領據(conn);
var data = dacMain.SelectPageWithRelations(
noInputReturnAll: true,
startRowIndex: 0,
maximumRows: Int32.MaxValue,
活動日期_1: 活動日期_1,
活動日期_2: 活動日期_2,
身分別: 身分別,
講師_非講師編號: 講師_非講師編號,
憑證類別: 憑證類別,
計畫代號: 計畫代號,
計畫名稱: 計畫名稱,
活動類別: 活動類別,
付款方式: 付款方式,
orderBy: orderBy
);
// 生成 Excel 檔案
Report.領據匯出 report = new Report.領據匯出();
report.data = data;
System.IO.MemoryStream ms = report.DoReport();
// 轉換為 Base64 編碼
string excelBase64 = Convert.ToBase64String(ms.ToArray());
// 生成檔案名稱
string fileName = string.Format("領據匯出_{0:yyyyMMdd_HHmmss}.xlsx", PublicVariable.TaiwanNow);
return ServiceResponse.CreateSuccess("匯出成功", new
{
fileName = fileName,
excelData = excelBase64
});
}
}
catch (Exception ex)
{
return ServiceResponse.CreateError(string.Format("匯出失敗:{0}", ex.Message));
}
}
[WebMethod(EnableSession = true)]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public ServiceResponse GetVariables()
{
return ServiceResponse.CreateSuccess("OK", data: new {
領據執行業務所得課稅門檻 = PublicVariable.領據執行業務所得課稅門檻,
領據薪資課稅門檻 = PublicVariable.領據薪資課稅門檻,
領據基本工資 = PublicVariable.領據基本工資,
領據執行業務所得稅率 = PublicVariable.領據執行業務所得稅率,
領據薪資稅率 = PublicVariable.領據薪資稅率
});
}
[WebMethod(EnableSession = true)]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public ServiceResponse SearchSummaryTable(
string 起日,
string 迄日,
string 身分別,
string 付款方式,
string 輸出方式)
{
try
{
// 解析日期參數
DateTime? startDate = null;
DateTime? endDate = null;
if (!string.IsNullOrEmpty(起日))
{
if (DateTime.TryParse(起日, out var parsedStartDate))
{
startDate = parsedStartDate;
}
}
if (!string.IsNullOrEmpty(迄日))
{
if (DateTime.TryParse(迄日, out var parsedEndDate))
{
endDate = parsedEndDate;
}
}
// 驗證輸出方式
if (string.IsNullOrEmpty(輸出方式) || (輸出方式 != "DATA" && 輸出方式 != "EXPORT"))
{
return ServiceResponse.CreateError("輸出方式無效");
}
using (var conn = DAC.NewConnection())
{
var dao領據 = new DAC_領據(conn);
var summaryData = dao領據.SelectSummary(true, 0, int.MaxValue, startDate, endDate, 身分別, 付款方式);
if (輸出方式 == "DATA")
{
return ServiceResponse.CreateSuccess("查詢成功", summaryData);
}
else
{
var report = new 講師個人費用彙整表();
report.起日 = startDate;
report.迄日 = endDate;
report.身分別 = 身分別;
report.付款方式 = 付款方式;
report.data = summaryData;
var ms = report.DoReport();
// 轉換為 Base64 編碼
string excelBase64 = Convert.ToBase64String(ms.ToArray());
var excelResult = new
{
excelData = excelBase64,
fileName = $"講師個人費用彙整表_{DateTime.Now:yyyyMMdd_HHmmss}.xlsx"
};
return ServiceResponse.CreateSuccess("匯出成功", excelResult);
}
}
}
catch (Exception ex)
{
return ServiceResponse.CreateError($"查詢失敗:{ex.Message}");
}
}
[WebMethod(EnableSession = true)]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public ServiceResponse SearchDetailTable(
string 起日,
string 迄日,
string 身分別,
string 憑證類別,
string 輸出方式)
{
try
{
// 解析日期參數
DateTime? startDate = null;
DateTime? endDate = null;
if (!string.IsNullOrEmpty(起日))
{
if (DateTime.TryParse(起日, out var parsedStartDate))
{
startDate = parsedStartDate;
}
}
if (!string.IsNullOrEmpty(迄日))
{
if (DateTime.TryParse(迄日, out var parsedEndDate))
{
endDate = parsedEndDate;
}
}
// 驗證輸出方式
if (string.IsNullOrEmpty(輸出方式) || (輸出方式 != "DATA" && 輸出方式 != "EXPORT_SUMMARY" && 輸出方式 != "EXPORT_DETAIL"))
{
return ServiceResponse.CreateError("輸出方式無效");
}
using (var conn = DAC.NewConnection())
{
var dao領據 = new DAC_領據(conn);
if (輸出方式 == "EXPORT_SUMMARY")
{
var detailData = dao領據.SelectDetail(true, 0, int.MaxValue, startDate, endDate, 身分別, 憑證類別);
var report = new 扣繳彙整表();
report.起日 = startDate;
report.迄日 = endDate;
report.身分別 = 身分別;
report.憑證類別 = 憑證類別;
report.data = detailData;
var ms = report.DoReport();
// 轉換為 Base64 編碼
string excelBase64 = Convert.ToBase64String(ms.ToArray());
var excelResult = new
{
excelData = excelBase64,
fileName = $"扣繳彙整表_{DateTime.Now:yyyyMMdd_HHmmss}.xlsx"
};
return ServiceResponse.CreateSuccess("匯出成功", excelResult);
}
else if (輸出方式 == "EXPORT_DETAIL")
{
var detailData = dao領據.SelectDetail(true, 0, int.MaxValue, startDate, endDate, 身分別, 憑證類別);
var reportData = new List<扣繳明細Item>();
foreach (var d in detailData)
{
reportData.AddRange(d.明細);
}
var report = new 扣繳明細表();
report.起日 = startDate;
report.迄日 = endDate;
report.身分別 = 身分別;
report.憑證類別 = 憑證類別;
report.data = reportData;
var ms = report.DoReport();
// 轉換為 Base64 編碼
string excelBase64 = Convert.ToBase64String(ms.ToArray());
var excelResult = new
{
excelData = excelBase64,
fileName = $"扣繳明細表_{DateTime.Now:yyyyMMdd_HHmmss}.xlsx"
};
return ServiceResponse.CreateSuccess("匯出成功", excelResult);
}
else
{
var detailData = dao領據.SelectDetail(true, 0, int.MaxValue, startDate, endDate, 身分別, 憑證類別);
return ServiceResponse.CreateSuccess("查詢成功", detailData);
}
}
}
catch (Exception ex)
{
return ServiceResponse.CreateError($"查詢失敗:{ex.Message}");
}
}
[WebMethod(EnableSession = true)]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public ServiceResponse SendEmail(
string 起日,
string 迄日,
string 身分別,
string 憑證類別,
string 輸出方式,
List<string> 講師非講師編號,
string 寄件人郵箱,
string 郵件主旨,
string 郵件內文)
{
try
{
// 解析日期參數
DateTime? startDate = null;
DateTime? endDate = null;
if (!string.IsNullOrEmpty(起日))
{
if (DateTime.TryParse(起日, out var parsedStartDate))
{
startDate = parsedStartDate;
}
}
if (!string.IsNullOrEmpty(迄日))
{
if (DateTime.TryParse(迄日, out var parsedEndDate))
{
endDate = parsedEndDate;
}
}
// 驗證輸出方式
if (string.IsNullOrEmpty(輸出方式) || (輸出方式 != "PREVIEW" && 輸出方式 != "SENDMAIL"))
{
return ServiceResponse.CreateError("輸出方式無效");
}
// 驗證輸入參數
if (講師非講師編號 == null || 講師非講師編號.Count == 0)
{
return ServiceResponse.CreateError("請選擇至少一個收件者");
}
if (string.IsNullOrEmpty(寄件人郵箱))
{
return ServiceResponse.CreateError("請輸入寄件人郵箱");
}
if (string.IsNullOrEmpty(郵件主旨))
{
return ServiceResponse.CreateError("請輸入郵件主旨");
}
if (string.IsNullOrEmpty(郵件內文))
{
return ServiceResponse.CreateError("請輸入郵件內文");
}
using (var conn = DAC.NewConnection())
{
var dao領據 = new DAC_領據(conn);
var detailData = dao領據.SelectDetail(true, 0, int.MaxValue, startDate, endDate, 身分別, 憑證類別);
var previewData = new List<扣繳匯總郵件Item>();
foreach (var d in detailData)
{
if (講師非講師編號.FirstOrDefault(x => x == d.講師_非講師編號) == null)
continue;
var p = new 扣繳匯總郵件Item();
p.收件人姓名 = d.領款人姓名;
p.收件人郵箱 = d.電子郵件;
p.主旨 = 郵件主旨;
p.內文 = 郵件內文;
p.明細 = d.明細;
p.講師勞務費合計 = p.明細.Sum(x => x.講師勞務費);
p.應扣繳稅額合計 = p.明細.Sum(x => x.應扣繳稅額);
p.服務費合計 = p.明細.Sum(x => x.服務費);
previewData.Add(p);
}
if (輸出方式 == "PREVIEW")
{
return ServiceResponse.CreateSuccess("預覽成功", previewData);
}
else
{
var 發送郵件 = new 發送郵件();
發送郵件.Context = this.Context;
var successCount = 0;
var failCount = 0;
var failMessages = new List<string>();
foreach (var d in previewData)
{
var sendResult = 發送郵件.發送扣繳明細表郵件(寄件人郵箱, startDate, endDate, d, out string message);
if (!sendResult)
{
failCount++;
failMessages.Add(message);
}
else
{
successCount++;
}
}
if (failCount == 0)
return ServiceResponse.CreateSuccess($"郵件已成功發送給 {successCount} 位收件者");
else
return ServiceResponse.CreateSuccess($"郵件已成功發送給 {successCount} 位收件者,但有 {failCount} 封發送失敗");
}
}
}
catch (Exception ex)
{
return ServiceResponse.CreateError($"處理失敗:{ex.Message}");
}
}
[WebMethod(EnableSession = true)]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public ServiceResponse ValidateImportFile(string filePath)
{
try
{
if (string.IsNullOrEmpty(filePath) || !File.Exists(filePath))
{
return ServiceResponse.CreateError("檔案不存在");
}
// 驗證副檔名
string extension = System.IO.Path.GetExtension(filePath).ToLower();
if (extension != ".xls" && extension != ".xlsx")
{
return ServiceResponse.CreateError("只允許上傳 .xls 或 .xlsx 檔案");
}
try
{
// 驗證欄位格式
var importer = new 領據匯入();
List<string> errors = importer.Validate(filePath, typeof(領據匯入Item), out int rowCount);
if (errors.Count > 0)
{
// 清除臨時檔案
if (System.IO.File.Exists(filePath))
System.IO.File.Delete(filePath);
return ServiceResponse.CreateSuccess("檔案驗證失敗", new
{
Success = false,
Errors = errors,
RowCount = 0
});
}
// 驗證欄位內容
List<string> contentErrors = importer.ValidateContent(filePath);
if (contentErrors.Count > 0)
{
// 清除臨時檔案
if (System.IO.File.Exists(filePath))
System.IO.File.Delete(filePath);
return ServiceResponse.CreateSuccess("檔案驗證失敗", new
{
Success = false,
Errors = contentErrors,
RowCount = 0
});
}
// 驗證重複資料
List<string> duplicateErrors;
List<string> duplicateWarnings;
using (var conn = DAC.NewConnection())
{
importer.ValidateDuplicates(filePath, conn, out duplicateErrors, out duplicateWarnings);
}
if (duplicateErrors.Count > 0)
{
// 與資料庫重複超過 5 筆,不允許匯入
if (System.IO.File.Exists(filePath))
System.IO.File.Delete(filePath);
return ServiceResponse.CreateSuccess("檔案驗證失敗", new
{
Success = false,
Errors = duplicateErrors,
RowCount = 0
});
}
// 儲存檔案路徑到 Session,以便匯入時使用
HttpContext.Current.Session["ImportFilePath"] = filePath;
return ServiceResponse.CreateSuccess("驗證成功", new
{
Success = true,
Errors = new List<string>(),
Warnings = duplicateWarnings,
RowCount = rowCount
});
}
catch (Exception ex)
{
// 清除臨時檔案
if (System.IO.File.Exists(filePath))
System.IO.File.Delete(filePath);
return ServiceResponse.CreateError($"驗證過程中發生錯誤:{ex.Message}");
}
}
catch (Exception ex)
{
return ServiceResponse.CreateError($"驗證失敗:{ex.Message}");
}
}
[WebMethod(EnableSession = true)]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public ServiceResponse ImportReceiptData()
{
try
{
// 從 Session 中取得檔案路徑
string filePath = HttpContext.Current?.Session?["ImportFilePath"]?.ToString();
if (string.IsNullOrEmpty(filePath) || !System.IO.File.Exists(filePath))
{
return ServiceResponse.CreateError("檔案不存在或已過期,請重新上傳");
}
try
{
var importer = new 領據匯入();
using (var conn = DAC.NewConnection())
{
importer.Connection = conn;
// 讀取資料列表
var items = importer.ReadRows<領據匯入Item>(filePath, 1);
if (items.Count == 0)
{
return ServiceResponse.CreateError("沒有可匯入的資料");
}
// 逐筆插入資料
int successCount = 0;
int failCount = 0;
List<string> failedRows = new List<string>();
for (int i = 0; i < items.Count; i++)
{
try
{
importer.InsertOne<領據匯入Item>(items[i]);
successCount++;
}
catch (Exception ex)
{
failCount++;
string errorMsg = importer.ImportRowErrorMessage<領據匯入Item>(items[i], ex.Message);
failedRows.Add($"第 {i + 2} 列:{errorMsg}");
}
}
// 清除 Session
HttpContext.Current.Session["ImportFilePath"] = null;
// 刪除臨時檔案
if (System.IO.File.Exists(filePath))
System.IO.File.Delete(filePath);
return ServiceResponse.CreateSuccess("匯入完成", new
{
successCount = successCount,
failCount = failCount,
failedRows = failedRows,
totalCount = items.Count
});
}
}
catch (Exception ex)
{
// 清除臨時檔案
if (System.IO.File.Exists(filePath))
System.IO.File.Delete(filePath);
return ServiceResponse.CreateError($"匯入過程中發生錯誤:{ex.Message}");
}
}
catch (Exception ex)
{
return ServiceResponse.CreateError($"匯入失敗:{ex.Message}");
}
}
[WebMethod(EnableSession = true)]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public ServiceResponse DownloadImportTemplate()
{
try
{
var report = new 領據匯出();
report.範本 = true;
// 查詢活動類別片語清單,填入儲存格註釋
using (var conn = DAC.NewConnection())
{
var daoPhrase = new DAC_片語(conn);
var phrases = daoPhrase.SelectBy適用欄位("活動類別");
if (phrases.Count > 0)
{
var 活動類別Comment = string.Join("\n", phrases.Select(p => p.片語內容).ToArray());
var col = report.Columns.FirstOrDefault(x => x.Key == "活動類別");
if (col != null) col.Comment = 活動類別Comment;
}
// 查詢單位別下拉選單,填入儲存格註釋(排除「請選擇」)
var 單位別List = 單位別.InputSelectList;
if (單位別List != null && 單位別List.Count > 0)
{
var 單位Comment = string.Join("\n", 單位別List.Where(x => !string.IsNullOrEmpty(x.Value.ToString())).Select(x => x.Name).ToArray());
var col = report.Columns.FirstOrDefault(x => x.Key == "單位");
if (col != null) col.Comment = 單位Comment;
}
}
var ms = report.DoReport();
// 轉換為 Base64 編碼
string excelBase64 = Convert.ToBase64String(ms.ToArray());
return ServiceResponse.CreateSuccess("下載成功", new
{
excelData = excelBase64,
fileName = "領據資料匯入格式.xlsx"
});
}
catch (Exception ex)
{
return ServiceResponse.CreateError($"下載失敗:{ex.Message}");
}
}
}
[Serializable]
public class 領據處理Dropdowns
{
public NameValueList 身分別 { get; set; }
public NameValueList 憑證類別 { get; set; }
public NameValueList 付款方式 { get; set; }
public NameValueList 扣繳類別 { get; set; }
public NameValueList 勞務費_費用別 { get; set; }
public NameValueList 差旅費_費用別 { get; set; }
public NameValueList 單位別 { get; set; }
}
public class PrintData
{
public 領據Item Main { get; set; }
public 講師 講師 { get; set; }
public 非講師Item 非講師 { get; set; }
public 勞務費Item Labor { get; set; }
public 差旅費Item Travel { get; set; }
}
}