修正
This commit is contained in:
@@ -7,8 +7,8 @@ class VoucherExportRequest(BaseModel):
|
|||||||
"""账票エクスポート要求"""
|
"""账票エクスポート要求"""
|
||||||
start_year: int = Field(..., ge=2000, le=2099)
|
start_year: int = Field(..., ge=2000, le=2099)
|
||||||
start_month: int = Field(..., ge=1, le=12)
|
start_month: int = Field(..., ge=1, le=12)
|
||||||
end_year: int = Field(default=None, ge=2000, le=2099)
|
end_year: Optional[int] = Field(default=None)
|
||||||
end_month: int = Field(default=None, ge=1, le=12)
|
end_month: Optional[int] = Field(default=None)
|
||||||
employee_ids: List[int] = Field(..., min_items=1)
|
employee_ids: List[int] = Field(..., min_items=1)
|
||||||
voucher_type: str = Field(default="all", pattern="^(all|salary|bonus)$")
|
voucher_type: str = Field(default="all", pattern="^(all|salary|bonus)$")
|
||||||
format: str = Field(default="preview", pattern="^(preview|csv|pdf)$")
|
format: str = Field(default="preview", pattern="^(preview|csv|pdf)$")
|
||||||
|
|||||||
@@ -78,6 +78,8 @@ def get_salary_data_for_period(
|
|||||||
start_ym = start_year * 100 + start_month
|
start_ym = start_year * 100 + start_month
|
||||||
end_ym = end_year * 100 + end_month
|
end_ym = end_year * 100 + end_month
|
||||||
|
|
||||||
|
logger.info(f"給与検索: employee_id={employee_id}, start_ym={start_ym}, end_ym={end_ym}")
|
||||||
|
|
||||||
cur.execute("""
|
cur.execute("""
|
||||||
SELECT
|
SELECT
|
||||||
e.employee_id, e.employee_code, e.name,
|
e.employee_id, e.employee_code, e.name,
|
||||||
@@ -96,6 +98,7 @@ def get_salary_data_for_period(
|
|||||||
""", (employee_id, start_ym, end_ym))
|
""", (employee_id, start_ym, end_ym))
|
||||||
|
|
||||||
rows = cur.fetchall()
|
rows = cur.fetchall()
|
||||||
|
logger.info(f"給与データ件数: {len(rows)}")
|
||||||
data = []
|
data = []
|
||||||
for row in rows:
|
for row in rows:
|
||||||
# Handle both dict and tuple formats
|
# Handle both dict and tuple formats
|
||||||
@@ -192,6 +195,8 @@ def get_bonus_data_for_period(
|
|||||||
start_ym = start_year * 100 + start_month
|
start_ym = start_year * 100 + start_month
|
||||||
end_ym = end_year * 100 + end_month
|
end_ym = end_year * 100 + end_month
|
||||||
|
|
||||||
|
logger.info(f"賞与検索: employee_id={employee_id}, start_ym={start_ym}, end_ym={end_ym}")
|
||||||
|
|
||||||
cur.execute("""
|
cur.execute("""
|
||||||
SELECT
|
SELECT
|
||||||
e.employee_id, e.employee_code, e.name,
|
e.employee_id, e.employee_code, e.name,
|
||||||
@@ -209,6 +214,7 @@ def get_bonus_data_for_period(
|
|||||||
""", (employee_id, start_ym, end_ym))
|
""", (employee_id, start_ym, end_ym))
|
||||||
|
|
||||||
rows = cur.fetchall()
|
rows = cur.fetchall()
|
||||||
|
logger.info(f"賞与データ件数: {len(rows)}")
|
||||||
data = []
|
data = []
|
||||||
for row in rows:
|
for row in rows:
|
||||||
# Handle both dict and tuple formats
|
# Handle both dict and tuple formats
|
||||||
@@ -342,11 +348,18 @@ def build_voucher_summary(
|
|||||||
def export_vouchers(request: VoucherExportRequest) -> VoucherExportResponse:
|
def export_vouchers(request: VoucherExportRequest) -> VoucherExportResponse:
|
||||||
"""账票エクスポート処理(メイン)"""
|
"""账票エクスポート処理(メイン)"""
|
||||||
try:
|
try:
|
||||||
|
# リクエストログ
|
||||||
|
end_label = f"{request.end_year:04d}-{request.end_month:02d}" if request.end_year else "None"
|
||||||
|
logger.info(f"エクスポート要求: start={request.start_year:04d}-{request.start_month:02d}, "
|
||||||
|
f"end={end_label}, "
|
||||||
|
f"type={request.voucher_type}, employees={request.employee_ids}")
|
||||||
|
|
||||||
# 日付範囲検証
|
# 日付範囲検証
|
||||||
start_year, start_month, end_year, end_month = validate_date_range(
|
start_year, start_month, end_year, end_month = validate_date_range(
|
||||||
request.start_year, request.start_month,
|
request.start_year, request.start_month,
|
||||||
request.end_year, request.end_month
|
request.end_year, request.end_month
|
||||||
)
|
)
|
||||||
|
logger.info(f"検証後の日付範囲: {start_year:04d}-{start_month:02d} ~ {end_year:04d}-{end_month:02d}")
|
||||||
|
|
||||||
# 給与・賞与データ取得
|
# 給与・賞与データ取得
|
||||||
salary_data = {}
|
salary_data = {}
|
||||||
@@ -358,6 +371,7 @@ def export_vouchers(request: VoucherExportRequest) -> VoucherExportResponse:
|
|||||||
emp_id, start_year, start_month, end_year, end_month
|
emp_id, start_year, start_month, end_year, end_month
|
||||||
)
|
)
|
||||||
salary_data[emp_id] = data
|
salary_data[emp_id] = data
|
||||||
|
logger.info(f"給与データ (emp_id={emp_id}): {len(data)}件")
|
||||||
|
|
||||||
if request.voucher_type in ["all", "bonus"]:
|
if request.voucher_type in ["all", "bonus"]:
|
||||||
for emp_id in request.employee_ids:
|
for emp_id in request.employee_ids:
|
||||||
@@ -365,8 +379,13 @@ def export_vouchers(request: VoucherExportRequest) -> VoucherExportResponse:
|
|||||||
emp_id, start_year, start_month, end_year, end_month
|
emp_id, start_year, start_month, end_year, end_month
|
||||||
)
|
)
|
||||||
bonus_data[emp_id] = data
|
bonus_data[emp_id] = data
|
||||||
|
logger.info(f"賞与データ (emp_id={emp_id}): {len(data)}件")
|
||||||
|
|
||||||
# データの存在判定
|
# データの存在判定
|
||||||
|
total_salary = sum(len(v) for v in salary_data.values())
|
||||||
|
total_bonus = sum(len(v) for v in bonus_data.values())
|
||||||
|
logger.info(f"合計: 給与={total_salary}件, 賞与={total_bonus}件")
|
||||||
|
|
||||||
has_any_data = any(
|
has_any_data = any(
|
||||||
salary_data.get(emp_id, []) or bonus_data.get(emp_id, [])
|
salary_data.get(emp_id, []) or bonus_data.get(emp_id, [])
|
||||||
for emp_id in request.employee_ids
|
for emp_id in request.employee_ids
|
||||||
@@ -376,7 +395,7 @@ def export_vouchers(request: VoucherExportRequest) -> VoucherExportResponse:
|
|||||||
return VoucherExportResponse(
|
return VoucherExportResponse(
|
||||||
status="no_data",
|
status="no_data",
|
||||||
has_data=False,
|
has_data=False,
|
||||||
message="選定條件下、沒有找到任何數據。請檢查日期範圍和従業員選擇。"
|
message="選定条件下にデータが見つかりません。日付範囲と従業員選択を確認してください。"
|
||||||
)
|
)
|
||||||
|
|
||||||
# 摘要構築
|
# 摘要構築
|
||||||
@@ -401,7 +420,7 @@ def export_vouchers(request: VoucherExportRequest) -> VoucherExportResponse:
|
|||||||
|
|
||||||
# メッセージ構築
|
# メッセージ構築
|
||||||
emp_with_data = len([s for s in summary if s.has_salary_data or s.has_bonus_data])
|
emp_with_data = len([s for s in summary if s.has_salary_data or s.has_bonus_data])
|
||||||
message = f"✓ 成功查詢: {emp_with_data}位従業員有數據"
|
message = f"✓ 検索成功: {emp_with_data}人の従業員がデータを持ちます"
|
||||||
|
|
||||||
return VoucherExportResponse(
|
return VoucherExportResponse(
|
||||||
status="success",
|
status="success",
|
||||||
|
|||||||
@@ -1731,9 +1731,9 @@
|
|||||||
// 年月を解析
|
// 年月を解析
|
||||||
const [startYear, startMonth] = startYM.split("-").map(Number);
|
const [startYear, startMonth] = startYM.split("-").map(Number);
|
||||||
const endYM = document.getElementById("voucherEndYearMonth").value;
|
const endYM = document.getElementById("voucherEndYearMonth").value;
|
||||||
const [endYear, endMonth] = endYM
|
const endParts = endYM ? endYM.split("-").map(Number) : null;
|
||||||
? endYM.split("-").map(Number)
|
const endYear = endParts ? endParts[0] : null;
|
||||||
: [startYear, startMonth];
|
const endMonth = endParts ? endParts[1] : null;
|
||||||
|
|
||||||
const voucherType = document.querySelector(
|
const voucherType = document.querySelector(
|
||||||
"input[name='voucherType']:checked",
|
"input[name='voucherType']:checked",
|
||||||
@@ -1751,6 +1751,8 @@
|
|||||||
format: "preview",
|
format: "preview",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
console.log("送信ペイロード:", JSON.stringify(payload, null, 2));
|
||||||
|
|
||||||
const response = await fetch(`${API_BASE}/payroll/vouchers/export`, {
|
const response = await fetch(`${API_BASE}/payroll/vouchers/export`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: { "Content-Type": "application/json" },
|
headers: { "Content-Type": "application/json" },
|
||||||
@@ -1758,6 +1760,7 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
const result = await response.json();
|
const result = await response.json();
|
||||||
|
console.log("レスポンス:", result);
|
||||||
|
|
||||||
if (!result.has_data) {
|
if (!result.has_data) {
|
||||||
alert(result.message || "データが見つかりません");
|
alert(result.message || "データが見つかりません");
|
||||||
@@ -1845,9 +1848,8 @@
|
|||||||
|
|
||||||
const generationDate = new Date().toLocaleDateString("ja-JP");
|
const generationDate = new Date().toLocaleDateString("ja-JP");
|
||||||
|
|
||||||
// グループ化: 従業員ごと、年月ごと
|
// グループ化: 従業員ごと、年月ごと、給与/賞与ごと
|
||||||
let currentEmployeeId = null;
|
let currentKey = null;
|
||||||
let currentYearMonth = null;
|
|
||||||
let pageOpen = false;
|
let pageOpen = false;
|
||||||
|
|
||||||
if (result.summary && Array.isArray(result.summary)) {
|
if (result.summary && Array.isArray(result.summary)) {
|
||||||
@@ -1864,16 +1866,15 @@
|
|||||||
// 給与データの処理
|
// 給与データの処理
|
||||||
salaries.forEach((salary) => {
|
salaries.forEach((salary) => {
|
||||||
const salaryYearMonth = `${salary.payroll_year}-${salary.payroll_month}`;
|
const salaryYearMonth = `${salary.payroll_year}-${salary.payroll_month}`;
|
||||||
|
const currentKey_new = `${emp.employee_id}-${salaryYearMonth}-salary`;
|
||||||
const paymentDate = `${salary.payroll_year}年${String(salary.payroll_month).padStart(2, "0")}月${getLastDayOfMonth(salary.payroll_year, salary.payroll_month)}日`;
|
const paymentDate = `${salary.payroll_year}年${String(salary.payroll_month).padStart(2, "0")}月${getLastDayOfMonth(salary.payroll_year, salary.payroll_month)}日`;
|
||||||
if (
|
|
||||||
currentEmployeeId !== emp.employee_id ||
|
// 新しいキーが異なる場合は新しいページを開く
|
||||||
currentYearMonth !== salaryYearMonth
|
if (currentKey !== currentKey_new) {
|
||||||
) {
|
|
||||||
if (pageOpen) {
|
if (pageOpen) {
|
||||||
printHtml += "</div>";
|
printHtml += "</div>";
|
||||||
}
|
}
|
||||||
currentEmployeeId = emp.employee_id;
|
currentKey = currentKey_new;
|
||||||
currentYearMonth = salaryYearMonth;
|
|
||||||
printHtml += '<div class="page">';
|
printHtml += '<div class="page">';
|
||||||
printHtml += `<div style="font-size: 11px; color: #999; margin-bottom: 10px; text-align: right;">帳票生成日: ${generationDate}</div>`;
|
printHtml += `<div style="font-size: 11px; color: #999; margin-bottom: 10px; text-align: right;">帳票生成日: ${generationDate}</div>`;
|
||||||
pageOpen = true;
|
pageOpen = true;
|
||||||
@@ -1978,16 +1979,15 @@
|
|||||||
// 賞与データの処理
|
// 賞与データの処理
|
||||||
bonuses.forEach((bonus) => {
|
bonuses.forEach((bonus) => {
|
||||||
const bonusYearMonth = `${bonus.bonus_year}-${bonus.bonus_month}`;
|
const bonusYearMonth = `${bonus.bonus_year}-${bonus.bonus_month}`;
|
||||||
|
const currentKey_new = `${emp.employee_id}-${bonusYearMonth}-bonus`;
|
||||||
const bonusPaymentDate = `${bonus.bonus_year}年${String(bonus.bonus_month).padStart(2, "0")}月${getLastDayOfMonth(bonus.bonus_year, bonus.bonus_month)}日`;
|
const bonusPaymentDate = `${bonus.bonus_year}年${String(bonus.bonus_month).padStart(2, "0")}月${getLastDayOfMonth(bonus.bonus_year, bonus.bonus_month)}日`;
|
||||||
if (
|
|
||||||
currentEmployeeId !== emp.employee_id ||
|
// 新しいキーが異なる場合は新しいページを開く
|
||||||
currentYearMonth !== bonusYearMonth
|
if (currentKey !== currentKey_new) {
|
||||||
) {
|
|
||||||
if (pageOpen) {
|
if (pageOpen) {
|
||||||
printHtml += "</div>";
|
printHtml += "</div>";
|
||||||
}
|
}
|
||||||
currentEmployeeId = emp.employee_id;
|
currentKey = currentKey_new;
|
||||||
currentYearMonth = bonusYearMonth;
|
|
||||||
printHtml += '<div class="page">';
|
printHtml += '<div class="page">';
|
||||||
printHtml += `<div style="font-size: 11px; color: #999; margin-bottom: 10px; text-align: right;">帳票生成日: ${generationDate}</div>`;
|
printHtml += `<div style="font-size: 11px; color: #999; margin-bottom: 10px; text-align: right;">帳票生成日: ${generationDate}</div>`;
|
||||||
pageOpen = true;
|
pageOpen = true;
|
||||||
@@ -2101,9 +2101,9 @@
|
|||||||
|
|
||||||
const [startYear, startMonth] = startYM.split("-").map(Number);
|
const [startYear, startMonth] = startYM.split("-").map(Number);
|
||||||
const endYM = document.getElementById("voucherEndYearMonth").value;
|
const endYM = document.getElementById("voucherEndYearMonth").value;
|
||||||
const [endYear, endMonth] = endYM
|
const endParts = endYM ? endYM.split("-").map(Number) : null;
|
||||||
? endYM.split("-").map(Number)
|
const endYear = endParts ? endParts[0] : null;
|
||||||
: [startYear, startMonth];
|
const endMonth = endParts ? endParts[1] : null;
|
||||||
const voucherType = document.querySelector(
|
const voucherType = document.querySelector(
|
||||||
"input[name='voucherType']:checked",
|
"input[name='voucherType']:checked",
|
||||||
).value;
|
).value;
|
||||||
|
|||||||
Reference in New Issue
Block a user