修正
This commit is contained in:
@@ -138,7 +138,14 @@ def run_auto_migration():
|
|||||||
print("=" * 80 + "\n")
|
print("=" * 80 + "\n")
|
||||||
|
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
# ── ねんきんポータル テーブル作成 ──
|
||||||
|
try:
|
||||||
|
from app.modules.nenkin_portal.migration import create_nenkin_tables
|
||||||
|
create_nenkin_tables()
|
||||||
|
except Exception as e:
|
||||||
|
print(f"⚠️ ねんきんポータル テーブル作成エラー(無視): {e}")
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"\n❌ 無法連接到數據庫或執行遷移: {e}")
|
print(f"\n❌ 無法連接到數據庫或執行遷移: {e}")
|
||||||
print("\n提示:")
|
print("\n提示:")
|
||||||
|
|||||||
@@ -124,6 +124,8 @@ app.include_router(payroll_vouchers_router)
|
|||||||
from app.payroll.withholding_slip.router import router as withholding_slip_router
|
from app.payroll.withholding_slip.router import router as withholding_slip_router
|
||||||
app.include_router(withholding_slip_router)
|
app.include_router(withholding_slip_router)
|
||||||
|
|
||||||
|
from app.modules.nenkin_portal.router import router as nenkin_portal_router
|
||||||
|
app.include_router(nenkin_portal_router)
|
||||||
|
|
||||||
from fastapi.staticfiles import StaticFiles
|
from fastapi.staticfiles import StaticFiles
|
||||||
import os
|
import os
|
||||||
|
|||||||
0
backend/app/modules/nenkin_portal/__init__.py
Normal file
0
backend/app/modules/nenkin_portal/__init__.py
Normal file
119
backend/app/modules/nenkin_portal/migration.py
Normal file
119
backend/app/modules/nenkin_portal/migration.py
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
"""
|
||||||
|
ねんきんポータル DB テーブル作成マイグレーション
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
from psycopg import connect
|
||||||
|
|
||||||
|
|
||||||
|
def create_nenkin_tables():
|
||||||
|
conn = connect(
|
||||||
|
host=os.getenv("DB_HOST"),
|
||||||
|
port=int(os.getenv("DB_PORT", 5432)),
|
||||||
|
dbname=os.getenv("DB_NAME"),
|
||||||
|
user=os.getenv("DB_USER"),
|
||||||
|
password=os.getenv("DB_PASSWORD"),
|
||||||
|
)
|
||||||
|
|
||||||
|
with conn.cursor() as cur:
|
||||||
|
# ──────────────────────────────────
|
||||||
|
# 文書ヘッダーマスター(全種別共通)
|
||||||
|
# ──────────────────────────────────
|
||||||
|
cur.execute("""
|
||||||
|
CREATE TABLE IF NOT EXISTS nenkin_documents (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
document_no VARCHAR(50) UNIQUE NOT NULL,
|
||||||
|
document_type VARCHAR(10) NOT NULL,
|
||||||
|
document_type_name VARCHAR(100),
|
||||||
|
zip_filename VARCHAR(255),
|
||||||
|
office_name VARCHAR(200),
|
||||||
|
office_number VARCHAR(20),
|
||||||
|
office_kigo VARCHAR(50),
|
||||||
|
nenkin_jimusho VARCHAR(100),
|
||||||
|
purpose_year INTEGER,
|
||||||
|
purpose_month INTEGER,
|
||||||
|
issue_date DATE,
|
||||||
|
uploaded_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
|
||||||
|
# ──────────────────────────────────
|
||||||
|
# 社会保険料額情報 (SHAKAI)
|
||||||
|
# ──────────────────────────────────
|
||||||
|
cur.execute("""
|
||||||
|
CREATE TABLE IF NOT EXISTS nenkin_shakai_hokenryo (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
document_id INTEGER REFERENCES nenkin_documents(id) ON DELETE CASCADE,
|
||||||
|
kenkou_hokenryo NUMERIC,
|
||||||
|
kousei_nenkin_hokenryo NUMERIC,
|
||||||
|
kodomo_kyoshutsukin NUMERIC,
|
||||||
|
total NUMERIC,
|
||||||
|
nofu_kigen_date DATE,
|
||||||
|
office_postcode VARCHAR(10),
|
||||||
|
office_address VARCHAR(300)
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
|
||||||
|
# ──────────────────────────────────
|
||||||
|
# 保険料納入告知額・領収済額通知書 (NOUNYU)
|
||||||
|
# ──────────────────────────────────
|
||||||
|
cur.execute("""
|
||||||
|
CREATE TABLE IF NOT EXISTS nenkin_nounyu_tsuchi (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
document_id INTEGER REFERENCES nenkin_documents(id) ON DELETE CASCADE,
|
||||||
|
kokuchi_kenkou NUMERIC,
|
||||||
|
kokuchi_kounen NUMERIC,
|
||||||
|
kokuchi_kodomo NUMERIC,
|
||||||
|
kokuchi_total NUMERIC,
|
||||||
|
kokuchi_nofu_kigen DATE,
|
||||||
|
ryoshu_kenkou NUMERIC,
|
||||||
|
ryoshu_kounen NUMERIC,
|
||||||
|
ryoshu_kodomo NUMERIC,
|
||||||
|
ryoshu_total NUMERIC,
|
||||||
|
ryoshu_date DATE,
|
||||||
|
ryoshu_nofu_year INTEGER,
|
||||||
|
ryoshu_nofu_month INTEGER,
|
||||||
|
office_postcode VARCHAR(10),
|
||||||
|
office_address VARCHAR(300),
|
||||||
|
office_name_line1 VARCHAR(200),
|
||||||
|
office_name_line2 VARCHAR(200)
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
|
||||||
|
# ──────────────────────────────────
|
||||||
|
# 賞与保険料算出内訳書 ヘッダー (SHOYO)
|
||||||
|
# ──────────────────────────────────
|
||||||
|
cur.execute("""
|
||||||
|
CREATE TABLE IF NOT EXISTS nenkin_shoyo_header (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
document_id INTEGER REFERENCES nenkin_documents(id) ON DELETE CASCADE,
|
||||||
|
jin_in_num INTEGER,
|
||||||
|
menjyo_hokenryo_ritsu VARCHAR(50),
|
||||||
|
page_num INTEGER
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
|
||||||
|
# ──────────────────────────────────
|
||||||
|
# 賞与保険料算出内訳書 明細 (SHOYO)
|
||||||
|
# ──────────────────────────────────
|
||||||
|
cur.execute("""
|
||||||
|
CREATE TABLE IF NOT EXISTS nenkin_shoyo_detail (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
document_id INTEGER REFERENCES nenkin_documents(id) ON DELETE CASCADE,
|
||||||
|
header_id INTEGER REFERENCES nenkin_shoyo_header(id) ON DELETE CASCADE,
|
||||||
|
seiri_num VARCHAR(20),
|
||||||
|
shimei VARCHAR(100),
|
||||||
|
shori_ymd VARCHAR(20),
|
||||||
|
hassei_ymd VARCHAR(20),
|
||||||
|
hyojun_shoyo_kenpo NUMERIC,
|
||||||
|
hyojun_shoyo_kounen NUMERIC,
|
||||||
|
kenpo_hongetsu NUMERIC,
|
||||||
|
kenpo_zengetsu NUMERIC,
|
||||||
|
kounen_hongetsu NUMERIC,
|
||||||
|
kounen_zengetsu NUMERIC,
|
||||||
|
page_num INTEGER
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
|
||||||
|
conn.commit()
|
||||||
|
conn.close()
|
||||||
|
print("✓ ねんきんポータル テーブル作成完了")
|
||||||
281
backend/app/modules/nenkin_portal/router.py
Normal file
281
backend/app/modules/nenkin_portal/router.py
Normal file
@@ -0,0 +1,281 @@
|
|||||||
|
"""
|
||||||
|
ねんきんポータル API ルーター
|
||||||
|
"""
|
||||||
|
from fastapi import APIRouter, UploadFile, File, HTTPException
|
||||||
|
from app.core.database import get_connection
|
||||||
|
from app.modules.nenkin_portal.service import parse_zip
|
||||||
|
|
||||||
|
router = APIRouter(prefix="/nenkin", tags=["ねんきんポータル"])
|
||||||
|
|
||||||
|
|
||||||
|
# ──────────────────────────────────────
|
||||||
|
# POST /nenkin/upload
|
||||||
|
# ──────────────────────────────────────
|
||||||
|
|
||||||
|
@router.post("/upload", summary="社会保険電子文書 ZIPアップロード")
|
||||||
|
async def upload_nenkin_zip(file: UploadFile = File(...)):
|
||||||
|
if not file.filename.lower().endswith('.zip'):
|
||||||
|
raise HTTPException(status_code=400, detail="ZIPファイルを選択してください")
|
||||||
|
|
||||||
|
data = await file.read()
|
||||||
|
|
||||||
|
try:
|
||||||
|
parsed = parse_zip(data, file.filename)
|
||||||
|
except ValueError as e:
|
||||||
|
raise HTTPException(status_code=400, detail=str(e))
|
||||||
|
except Exception as e:
|
||||||
|
raise HTTPException(status_code=400, detail=f"ZIPの解析に失敗しました: {e}")
|
||||||
|
|
||||||
|
doc_no = parsed['document_no']
|
||||||
|
if not doc_no:
|
||||||
|
raise HTTPException(status_code=400, detail="文書番号が取得できませんでした")
|
||||||
|
|
||||||
|
with get_connection() as conn, conn.cursor() as cur:
|
||||||
|
# 重複チェック
|
||||||
|
cur.execute(
|
||||||
|
"SELECT id FROM nenkin_documents WHERE document_no = %s",
|
||||||
|
(doc_no,)
|
||||||
|
)
|
||||||
|
if cur.fetchone():
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=409,
|
||||||
|
detail=f"文書番号 {doc_no} は既に登録されています"
|
||||||
|
)
|
||||||
|
|
||||||
|
# nenkin_documents に挿入
|
||||||
|
cur.execute("""
|
||||||
|
INSERT INTO nenkin_documents
|
||||||
|
(document_no, document_type, document_type_name, zip_filename,
|
||||||
|
office_name, office_number, office_kigo, nenkin_jimusho,
|
||||||
|
purpose_year, purpose_month, issue_date)
|
||||||
|
VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)
|
||||||
|
RETURNING id
|
||||||
|
""", (
|
||||||
|
parsed['document_no'],
|
||||||
|
parsed['document_type'],
|
||||||
|
parsed['document_type_name'],
|
||||||
|
parsed['zip_filename'],
|
||||||
|
parsed['office_name'],
|
||||||
|
parsed['office_number'],
|
||||||
|
parsed['office_kigo'],
|
||||||
|
parsed['nenkin_jimusho'],
|
||||||
|
parsed['purpose_year'],
|
||||||
|
parsed['purpose_month'],
|
||||||
|
parsed['issue_date'],
|
||||||
|
))
|
||||||
|
doc_id = cur.fetchone()['id']
|
||||||
|
|
||||||
|
detail = parsed['detail']
|
||||||
|
|
||||||
|
if parsed['document_type'] == 'SHAKAI':
|
||||||
|
cur.execute("""
|
||||||
|
INSERT INTO nenkin_shakai_hokenryo
|
||||||
|
(document_id, kenkou_hokenryo, kousei_nenkin_hokenryo,
|
||||||
|
kodomo_kyoshutsukin, total, nofu_kigen_date,
|
||||||
|
office_postcode, office_address)
|
||||||
|
VALUES (%s,%s,%s,%s,%s,%s,%s,%s)
|
||||||
|
""", (
|
||||||
|
doc_id,
|
||||||
|
detail['kenkou_hokenryo'],
|
||||||
|
detail['kousei_nenkin_hokenryo'],
|
||||||
|
detail['kodomo_kyoshutsukin'],
|
||||||
|
detail['total'],
|
||||||
|
detail['nofu_kigen_date'],
|
||||||
|
detail['office_postcode'],
|
||||||
|
detail['office_address'],
|
||||||
|
))
|
||||||
|
|
||||||
|
elif parsed['document_type'] == 'NOUNYU':
|
||||||
|
cur.execute("""
|
||||||
|
INSERT INTO nenkin_nounyu_tsuchi
|
||||||
|
(document_id,
|
||||||
|
kokuchi_kenkou, kokuchi_kounen, kokuchi_kodomo, kokuchi_total, kokuchi_nofu_kigen,
|
||||||
|
ryoshu_kenkou, ryoshu_kounen, ryoshu_kodomo, ryoshu_total, ryoshu_date,
|
||||||
|
ryoshu_nofu_year, ryoshu_nofu_month,
|
||||||
|
office_postcode, office_address, office_name_line1, office_name_line2)
|
||||||
|
VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)
|
||||||
|
""", (
|
||||||
|
doc_id,
|
||||||
|
detail['kokuchi_kenkou'], detail['kokuchi_kounen'],
|
||||||
|
detail['kokuchi_kodomo'], detail['kokuchi_total'],
|
||||||
|
detail['kokuchi_nofu_kigen'],
|
||||||
|
detail['ryoshu_kenkou'], detail['ryoshu_kounen'],
|
||||||
|
detail['ryoshu_kodomo'], detail['ryoshu_total'],
|
||||||
|
detail['ryoshu_date'],
|
||||||
|
detail['ryoshu_nofu_year'], detail['ryoshu_nofu_month'],
|
||||||
|
detail['office_postcode'], detail['office_address'],
|
||||||
|
detail['office_name_line1'], detail['office_name_line2'],
|
||||||
|
))
|
||||||
|
|
||||||
|
elif parsed['document_type'] == 'SHOYO':
|
||||||
|
cur.execute("""
|
||||||
|
INSERT INTO nenkin_shoyo_header
|
||||||
|
(document_id, jin_in_num, menjyo_hokenryo_ritsu, page_num)
|
||||||
|
VALUES (%s,%s,%s,%s)
|
||||||
|
RETURNING id
|
||||||
|
""", (
|
||||||
|
doc_id,
|
||||||
|
detail['jin_in_num'],
|
||||||
|
detail['menjyo_hokenryo_ritsu'],
|
||||||
|
detail['page_num'],
|
||||||
|
))
|
||||||
|
header_id = cur.fetchone()['id']
|
||||||
|
|
||||||
|
for item in detail['items']:
|
||||||
|
cur.execute("""
|
||||||
|
INSERT INTO nenkin_shoyo_detail
|
||||||
|
(document_id, header_id, seiri_num, shimei, shori_ymd, hassei_ymd,
|
||||||
|
hyojun_shoyo_kenpo, hyojun_shoyo_kounen,
|
||||||
|
kenpo_hongetsu, kenpo_zengetsu,
|
||||||
|
kounen_hongetsu, kounen_zengetsu, page_num)
|
||||||
|
VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)
|
||||||
|
""", (
|
||||||
|
doc_id, header_id,
|
||||||
|
item['seiri_num'], item['shimei'],
|
||||||
|
item['shori_ymd'], item['hassei_ymd'],
|
||||||
|
item['hyojun_shoyo_kenpo'], item['hyojun_shoyo_kounen'],
|
||||||
|
item['kenpo_hongetsu'], item['kenpo_zengetsu'],
|
||||||
|
item['kounen_hongetsu'], item['kounen_zengetsu'],
|
||||||
|
item['page_num'],
|
||||||
|
))
|
||||||
|
|
||||||
|
conn.commit()
|
||||||
|
|
||||||
|
return {
|
||||||
|
'id': doc_id,
|
||||||
|
'document_no': parsed['document_no'],
|
||||||
|
'document_type': parsed['document_type'],
|
||||||
|
'document_type_name': parsed['document_type_name'],
|
||||||
|
'message': f"{parsed['document_type_name']} を登録しました",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# ──────────────────────────────────────
|
||||||
|
# GET /nenkin/documents
|
||||||
|
# ──────────────────────────────────────
|
||||||
|
|
||||||
|
@router.get("/documents", summary="文書一覧取得")
|
||||||
|
def list_documents(doc_type: str = None, year: int = None, month: int = None):
|
||||||
|
conditions = []
|
||||||
|
params = []
|
||||||
|
|
||||||
|
if doc_type:
|
||||||
|
conditions.append("document_type = %s")
|
||||||
|
params.append(doc_type)
|
||||||
|
if year:
|
||||||
|
conditions.append("purpose_year = %s")
|
||||||
|
params.append(year)
|
||||||
|
if month:
|
||||||
|
conditions.append("purpose_month = %s")
|
||||||
|
params.append(month)
|
||||||
|
|
||||||
|
where = ("WHERE " + " AND ".join(conditions)) if conditions else ""
|
||||||
|
|
||||||
|
with get_connection() as conn, conn.cursor() as cur:
|
||||||
|
cur.execute(f"""
|
||||||
|
SELECT id, document_no, document_type, document_type_name,
|
||||||
|
zip_filename, office_name, office_number, office_kigo,
|
||||||
|
nenkin_jimusho, purpose_year, purpose_month,
|
||||||
|
issue_date, uploaded_at
|
||||||
|
FROM nenkin_documents
|
||||||
|
{where}
|
||||||
|
ORDER BY purpose_year DESC, purpose_month DESC, document_type, uploaded_at DESC
|
||||||
|
""", params)
|
||||||
|
rows = cur.fetchall()
|
||||||
|
|
||||||
|
result = []
|
||||||
|
for r in rows:
|
||||||
|
item = dict(r)
|
||||||
|
if item.get('issue_date'):
|
||||||
|
item['issue_date'] = item['issue_date'].isoformat()
|
||||||
|
if item.get('uploaded_at'):
|
||||||
|
item['uploaded_at'] = item['uploaded_at'].isoformat()
|
||||||
|
result.append(item)
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
# ──────────────────────────────────────
|
||||||
|
# GET /nenkin/documents/{doc_id}
|
||||||
|
# ──────────────────────────────────────
|
||||||
|
|
||||||
|
@router.get("/documents/{doc_id}", summary="文書詳細取得")
|
||||||
|
def get_document(doc_id: int):
|
||||||
|
with get_connection() as conn, conn.cursor() as cur:
|
||||||
|
cur.execute("SELECT * FROM nenkin_documents WHERE id = %s", (doc_id,))
|
||||||
|
doc = cur.fetchone()
|
||||||
|
if not doc:
|
||||||
|
raise HTTPException(status_code=404, detail="文書が見つかりません")
|
||||||
|
|
||||||
|
doc = dict(doc)
|
||||||
|
if doc.get('issue_date'):
|
||||||
|
doc['issue_date'] = doc['issue_date'].isoformat()
|
||||||
|
if doc.get('uploaded_at'):
|
||||||
|
doc['uploaded_at'] = doc['uploaded_at'].isoformat()
|
||||||
|
|
||||||
|
detail = {}
|
||||||
|
dtype = doc['document_type']
|
||||||
|
|
||||||
|
if dtype == 'SHAKAI':
|
||||||
|
cur.execute(
|
||||||
|
"SELECT * FROM nenkin_shakai_hokenryo WHERE document_id = %s",
|
||||||
|
(doc_id,)
|
||||||
|
)
|
||||||
|
row = cur.fetchone()
|
||||||
|
if row:
|
||||||
|
detail = dict(row)
|
||||||
|
if detail.get('nofu_kigen_date'):
|
||||||
|
detail['nofu_kigen_date'] = detail['nofu_kigen_date'].isoformat()
|
||||||
|
|
||||||
|
elif dtype == 'NOUNYU':
|
||||||
|
cur.execute(
|
||||||
|
"SELECT * FROM nenkin_nounyu_tsuchi WHERE document_id = %s",
|
||||||
|
(doc_id,)
|
||||||
|
)
|
||||||
|
row = cur.fetchone()
|
||||||
|
if row:
|
||||||
|
detail = dict(row)
|
||||||
|
for df in ('kokuchi_nofu_kigen', 'ryoshu_date'):
|
||||||
|
if detail.get(df):
|
||||||
|
detail[df] = detail[df].isoformat()
|
||||||
|
|
||||||
|
elif dtype == 'SHOYO':
|
||||||
|
cur.execute(
|
||||||
|
"SELECT * FROM nenkin_shoyo_header WHERE document_id = %s",
|
||||||
|
(doc_id,)
|
||||||
|
)
|
||||||
|
hdr = cur.fetchone()
|
||||||
|
if hdr:
|
||||||
|
detail = dict(hdr)
|
||||||
|
cur.execute("""
|
||||||
|
SELECT * FROM nenkin_shoyo_detail
|
||||||
|
WHERE document_id = %s
|
||||||
|
ORDER BY CAST(NULLIF(TRIM(seiri_num), '') AS INTEGER) NULLS LAST
|
||||||
|
""", (doc_id,))
|
||||||
|
detail['items'] = [dict(r) for r in cur.fetchall()]
|
||||||
|
|
||||||
|
return {'document': doc, 'detail': detail}
|
||||||
|
|
||||||
|
|
||||||
|
# ──────────────────────────────────────
|
||||||
|
# GET /nenkin/filter-options
|
||||||
|
# ──────────────────────────────────────
|
||||||
|
|
||||||
|
@router.get("/filter-options", summary="フィルター選択肢取得")
|
||||||
|
def get_filter_options():
|
||||||
|
with get_connection() as conn, conn.cursor() as cur:
|
||||||
|
cur.execute("""
|
||||||
|
SELECT DISTINCT purpose_year, purpose_month
|
||||||
|
FROM nenkin_documents
|
||||||
|
WHERE purpose_year IS NOT NULL
|
||||||
|
ORDER BY purpose_year DESC, purpose_month DESC
|
||||||
|
""")
|
||||||
|
periods = [dict(r) for r in cur.fetchall()]
|
||||||
|
|
||||||
|
cur.execute("""
|
||||||
|
SELECT DISTINCT document_type, document_type_name
|
||||||
|
FROM nenkin_documents
|
||||||
|
ORDER BY document_type
|
||||||
|
""")
|
||||||
|
types = [dict(r) for r in cur.fetchall()]
|
||||||
|
|
||||||
|
return {'periods': periods, 'types': types}
|
||||||
351
backend/app/modules/nenkin_portal/service.py
Normal file
351
backend/app/modules/nenkin_portal/service.py
Normal file
@@ -0,0 +1,351 @@
|
|||||||
|
"""
|
||||||
|
ねんきんポータル ZIPパーサー
|
||||||
|
対応文書種別:
|
||||||
|
SHAKAI - 社会保険料額情報
|
||||||
|
NOUNYU - 保険料納入告知額・領収済額通知書
|
||||||
|
SHOYO - 賞与保険料算出内訳書
|
||||||
|
"""
|
||||||
|
import zipfile
|
||||||
|
import io
|
||||||
|
import re
|
||||||
|
import xml.etree.ElementTree as ET
|
||||||
|
from datetime import date
|
||||||
|
from typing import Optional, Dict, Any
|
||||||
|
|
||||||
|
# ──────────────────────────────────────
|
||||||
|
# 元号オフセット
|
||||||
|
# ──────────────────────────────────────
|
||||||
|
GENGOU_OFFSETS = {
|
||||||
|
'令和': 2018, 'R': 2018,
|
||||||
|
'平成': 1988, 'H': 1988,
|
||||||
|
'昭和': 1925, 'S': 1925,
|
||||||
|
'大正': 1911, 'T': 1911,
|
||||||
|
'明治': 1867, 'M': 1867,
|
||||||
|
}
|
||||||
|
|
||||||
|
# XSLファイル名 → 文書種別
|
||||||
|
XSL_TYPE_MAP = {
|
||||||
|
'yoshiki_04_shakai_003.xsl': 'SHAKAI',
|
||||||
|
'yoshiki_29_zumitsu_001.xsl': 'NOUNYU',
|
||||||
|
'yoshiki_03_shoyo_002.xsl': 'SHOYO',
|
||||||
|
}
|
||||||
|
|
||||||
|
TYPE_NAMES = {
|
||||||
|
'SHAKAI': '社会保険料額情報',
|
||||||
|
'NOUNYU': '保険料納入告知額・領収済額通知書',
|
||||||
|
'SHOYO': '賞与保険料算出内訳書',
|
||||||
|
'HIHOKEN': '被保険者データ',
|
||||||
|
'ZOGENS': '保険料増減内訳書',
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# ──────────────────────────────────────
|
||||||
|
# ユーティリティ
|
||||||
|
# ──────────────────────────────────────
|
||||||
|
|
||||||
|
def gengou_to_western(gengou: str, year_str) -> Optional[int]:
|
||||||
|
try:
|
||||||
|
offset = GENGOU_OFFSETS.get(str(gengou), 0)
|
||||||
|
return int(str(year_str)) + offset if offset else None
|
||||||
|
except Exception:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def make_date(gengou: str, year_str, month_str, day_str='1') -> Optional[date]:
|
||||||
|
try:
|
||||||
|
western = gengou_to_western(gengou, year_str)
|
||||||
|
if not western:
|
||||||
|
return None
|
||||||
|
return date(western, int(month_str), int(day_str or 1))
|
||||||
|
except Exception:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def parse_reki_date(s: str) -> Optional[date]:
|
||||||
|
"""R080430 → date(2026,4,30)"""
|
||||||
|
if not s or len(s) < 7:
|
||||||
|
return None
|
||||||
|
prefix = s[0].upper()
|
||||||
|
try:
|
||||||
|
yy = int(s[1:3])
|
||||||
|
mm = int(s[3:5])
|
||||||
|
dd = int(s[5:7])
|
||||||
|
offset = GENGOU_OFFSETS.get(prefix, 0)
|
||||||
|
if not offset:
|
||||||
|
return None
|
||||||
|
return date(yy + offset, mm, dd)
|
||||||
|
except Exception:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def parse_amount(s) -> Optional[float]:
|
||||||
|
"""'94,054' / '\\247,066' → float"""
|
||||||
|
if s is None:
|
||||||
|
return None
|
||||||
|
cleaned = str(s).replace(',', '').replace('\\', '').replace('¥', '').replace('¥', '').strip()
|
||||||
|
if not cleaned:
|
||||||
|
return None
|
||||||
|
try:
|
||||||
|
return float(cleaned)
|
||||||
|
except Exception:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def get_text(elem, tag: str) -> str:
|
||||||
|
if elem is None:
|
||||||
|
return ''
|
||||||
|
child = elem.find(tag)
|
||||||
|
return child.text.strip() if child is not None and child.text else ''
|
||||||
|
|
||||||
|
|
||||||
|
# ──────────────────────────────────────
|
||||||
|
# 文書種別の自動判定
|
||||||
|
# ──────────────────────────────────────
|
||||||
|
|
||||||
|
def detect_doc_type(names: list) -> str:
|
||||||
|
for name in names:
|
||||||
|
basename = name.split('/')[-1]
|
||||||
|
if basename in XSL_TYPE_MAP:
|
||||||
|
return XSL_TYPE_MAP[basename]
|
||||||
|
return 'UNKNOWN'
|
||||||
|
|
||||||
|
|
||||||
|
def get_document_no(zf, names: list) -> str:
|
||||||
|
"""封筒XML から文書番号を取得"""
|
||||||
|
envelope_name = next(
|
||||||
|
(n for n in names if re.match(r'.*/\d+\.xml$', n)),
|
||||||
|
None
|
||||||
|
)
|
||||||
|
if not envelope_name:
|
||||||
|
return ''
|
||||||
|
with zf.open(envelope_name) as f:
|
||||||
|
etree = ET.parse(f)
|
||||||
|
elem = etree.getroot().find('.//DOCNO')
|
||||||
|
return elem.text.strip() if elem is not None and elem.text else ''
|
||||||
|
|
||||||
|
|
||||||
|
# ──────────────────────────────────────
|
||||||
|
# メインエントリー
|
||||||
|
# ──────────────────────────────────────
|
||||||
|
|
||||||
|
def parse_zip(zip_bytes: bytes, zip_filename: str) -> Dict[str, Any]:
|
||||||
|
zf = zipfile.ZipFile(io.BytesIO(zip_bytes))
|
||||||
|
names = zf.namelist()
|
||||||
|
doc_type = detect_doc_type(names)
|
||||||
|
|
||||||
|
if doc_type == 'SHAKAI':
|
||||||
|
return _parse_shakai(zf, names, zip_filename)
|
||||||
|
elif doc_type == 'NOUNYU':
|
||||||
|
return _parse_nounyu(zf, names, zip_filename)
|
||||||
|
elif doc_type == 'SHOYO':
|
||||||
|
return _parse_shoyo(zf, names, zip_filename)
|
||||||
|
else:
|
||||||
|
raise ValueError(f"未対応の文書種別です(XSLが不明): {[n.split('/')[-1] for n in names]}")
|
||||||
|
|
||||||
|
|
||||||
|
# ──────────────────────────────────────
|
||||||
|
# 社会保険料額情報 (SHAKAI)
|
||||||
|
# ──────────────────────────────────────
|
||||||
|
|
||||||
|
def _parse_shakai(zf, names: list, zip_filename: str) -> Dict[str, Any]:
|
||||||
|
xml_name = next(
|
||||||
|
n for n in names
|
||||||
|
if '社会保険料額情報' in n.split('/')[-1] and n.endswith('.xml')
|
||||||
|
)
|
||||||
|
with zf.open(xml_name) as f:
|
||||||
|
root = ET.parse(f).getroot()
|
||||||
|
|
||||||
|
lst = root.find('shakaiHokenRyougakuList')
|
||||||
|
header = lst.find('header')
|
||||||
|
|
||||||
|
jigyosho_name = get_text(header, 'jigyoshoName').replace('<br/>', ' ')
|
||||||
|
jigyosho_num = get_text(header, 'jigyoshoNum')
|
||||||
|
jigyosho_kigo = get_text(header, 'jigyoshoSeiriKigo')
|
||||||
|
nenkin_jimusho = get_text(header, 'nenkinJimusho1')
|
||||||
|
nofu_gengou = get_text(header, 'nouhuMokutekiYearGengou')
|
||||||
|
nofu_year = get_text(header, 'nouhuMokutekiYear')
|
||||||
|
nofu_month = get_text(header, 'nouhuMokutekiMonth')
|
||||||
|
|
||||||
|
hakkou_gengou = get_text(lst, 'hakkouYmdGengou')
|
||||||
|
hakkou_year = get_text(lst, 'hakkouYmdYear')
|
||||||
|
hakkou_month = get_text(lst, 'hakkouYmdMonth')
|
||||||
|
hakkou_day = get_text(lst, 'hakkouYmdDate')
|
||||||
|
|
||||||
|
nofu_kigen_gengou = get_text(lst, 'nouhuKigenGengou')
|
||||||
|
nofu_kigen_year = get_text(lst, 'nouhuKigenYear')
|
||||||
|
nofu_kigen_month = get_text(lst, 'nouhuKigenMonth')
|
||||||
|
nofu_kigen_day = get_text(lst, 'nouhuKigenDate')
|
||||||
|
|
||||||
|
return {
|
||||||
|
'document_no': get_document_no(zf, names),
|
||||||
|
'document_type': 'SHAKAI',
|
||||||
|
'document_type_name': TYPE_NAMES['SHAKAI'],
|
||||||
|
'zip_filename': zip_filename,
|
||||||
|
'office_name': jigyosho_name,
|
||||||
|
'office_number': jigyosho_num,
|
||||||
|
'office_kigo': jigyosho_kigo,
|
||||||
|
'nenkin_jimusho': nenkin_jimusho,
|
||||||
|
'purpose_year': gengou_to_western(nofu_gengou, nofu_year),
|
||||||
|
'purpose_month': int(nofu_month) if nofu_month else None,
|
||||||
|
'issue_date': make_date(hakkou_gengou, hakkou_year, hakkou_month, hakkou_day),
|
||||||
|
'detail': {
|
||||||
|
'kenkou_hokenryo': parse_amount(get_text(lst, 'kenkouHokenRyou')),
|
||||||
|
'kousei_nenkin_hokenryo': parse_amount(get_text(lst, 'kouseiNenkinHokenRyou')),
|
||||||
|
'kodomo_kyoshutsukin': parse_amount(get_text(lst, 'kodomoKosodateKyoshutsuKin')),
|
||||||
|
'total': parse_amount(get_text(lst, 'total')),
|
||||||
|
'nofu_kigen_date': make_date(nofu_kigen_gengou, nofu_kigen_year, nofu_kigen_month, nofu_kigen_day),
|
||||||
|
'office_postcode': get_text(lst, 'jigyoushoPostCode'),
|
||||||
|
'office_address': get_text(lst, 'jigyoushoShozaichi').replace('<br/>', ' '),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# ──────────────────────────────────────
|
||||||
|
# 保険料納入告知額・領収済額通知書 (NOUNYU)
|
||||||
|
# ──────────────────────────────────────
|
||||||
|
|
||||||
|
def _parse_nounyu(zf, names: list, zip_filename: str) -> Dict[str, Any]:
|
||||||
|
xml_name = next(
|
||||||
|
n for n in names
|
||||||
|
if '保険料納入告知額' in n.split('/')[-1] and n.endswith('.xml')
|
||||||
|
)
|
||||||
|
with zf.open(xml_name) as f:
|
||||||
|
root = ET.parse(f).getroot()
|
||||||
|
|
||||||
|
lst = root.find('hokenRyouRyoshuzumigakutsuchiShoList')
|
||||||
|
header = lst.find('header')
|
||||||
|
|
||||||
|
jigyosho_num = get_text(header, 'jigyoshoNum')
|
||||||
|
jigyosho_kigo = get_text(header, 'jigyoshoSeiriKigo')
|
||||||
|
nenkin_jimusho = get_text(header, 'nenkinJimusho1')
|
||||||
|
nofu_gengou = get_text(header, 'nouhuMokutekiYearGengou')
|
||||||
|
nofu_year = get_text(header, 'nouhuMokutekiYear')
|
||||||
|
nofu_month = get_text(header, 'nouhuMokutekiMonth')
|
||||||
|
|
||||||
|
hakkou_gengou = get_text(lst, 'hakkouYmdGengou')
|
||||||
|
hakkou_year = get_text(lst, 'hakkouYmdYear')
|
||||||
|
hakkou_month = get_text(lst, 'hakkouYmdMonth')
|
||||||
|
hakkou_day = get_text(lst, 'hakkouYmdDate')
|
||||||
|
|
||||||
|
nofu_kigen_gengou = get_text(lst, 'nouhuKigenGengou')
|
||||||
|
nofu_kigen_year = get_text(lst, 'nouhuKigenYear')
|
||||||
|
nofu_kigen_month = get_text(lst, 'nouhuKigenMonth')
|
||||||
|
nofu_kigen_day = get_text(lst, 'nouhuKigenDate')
|
||||||
|
|
||||||
|
ryoshu_gengou = get_text(lst, 'ryoshuDtGengo')
|
||||||
|
ryoshu_year = get_text(lst, 'ryoshuDtYear')
|
||||||
|
ryoshu_month = get_text(lst, 'ryoshuDtMonth')
|
||||||
|
ryoshu_day = get_text(lst, 'ryoshuDtDate')
|
||||||
|
|
||||||
|
ryoshu_nofu_gengou = get_text(lst, 'ryoshuNouhuMokutekiYmGengou')
|
||||||
|
ryoshu_nofu_year = get_text(lst, 'ryoshuNouhuMokutekiYmYear')
|
||||||
|
ryoshu_nofu_month = get_text(lst, 'ryoshuNouhuMokutekiYmMonth')
|
||||||
|
|
||||||
|
name1 = get_text(lst, 'jigyoshoNameLine1')
|
||||||
|
name2 = get_text(lst, 'jigyoshoNameLine2')
|
||||||
|
office_name = (name1 + ' ' + name2).strip()
|
||||||
|
|
||||||
|
return {
|
||||||
|
'document_no': get_document_no(zf, names),
|
||||||
|
'document_type': 'NOUNYU',
|
||||||
|
'document_type_name': TYPE_NAMES['NOUNYU'],
|
||||||
|
'zip_filename': zip_filename,
|
||||||
|
'office_name': office_name,
|
||||||
|
'office_number': jigyosho_num,
|
||||||
|
'office_kigo': jigyosho_kigo,
|
||||||
|
'nenkin_jimusho': nenkin_jimusho,
|
||||||
|
'purpose_year': gengou_to_western(nofu_gengou, nofu_year),
|
||||||
|
'purpose_month': int(nofu_month) if nofu_month else None,
|
||||||
|
'issue_date': make_date(hakkou_gengou, hakkou_year, hakkou_month, hakkou_day),
|
||||||
|
'detail': {
|
||||||
|
'kokuchi_kenkou': parse_amount(get_text(lst, 'kenkouHokenRyou')),
|
||||||
|
'kokuchi_kounen': parse_amount(get_text(lst, 'kouseiNenkinHokenRyou')),
|
||||||
|
'kokuchi_kodomo': parse_amount(get_text(lst, 'kodomoKosodateKyoshutsuKin')),
|
||||||
|
'kokuchi_total': parse_amount(get_text(lst, 'total')),
|
||||||
|
'kokuchi_nofu_kigen': make_date(nofu_kigen_gengou, nofu_kigen_year, nofu_kigen_month, nofu_kigen_day),
|
||||||
|
'ryoshu_kenkou': parse_amount(get_text(lst, 'ryoshuKenkouHokenRyou')),
|
||||||
|
'ryoshu_kounen': parse_amount(get_text(lst, 'ryoshuKouseiNenkinHokenRyou')),
|
||||||
|
'ryoshu_kodomo': parse_amount(get_text(lst, 'ryoshuKodomoKosodateKyoshutsuKin')),
|
||||||
|
'ryoshu_total': parse_amount(get_text(lst, 'ryoshuTotal')),
|
||||||
|
'ryoshu_date': make_date(ryoshu_gengou, ryoshu_year, ryoshu_month, ryoshu_day),
|
||||||
|
'ryoshu_nofu_year': gengou_to_western(ryoshu_nofu_gengou, ryoshu_nofu_year),
|
||||||
|
'ryoshu_nofu_month': int(ryoshu_nofu_month) if ryoshu_nofu_month else None,
|
||||||
|
'office_postcode': get_text(lst, 'jigyoushoPostCode'),
|
||||||
|
'office_address': (get_text(lst, 'jigyoushoShozaichiLine1') + ' ' + get_text(lst, 'jigyoushoShozaichiLine2')).strip(),
|
||||||
|
'office_name_line1': name1,
|
||||||
|
'office_name_line2': name2,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# ──────────────────────────────────────
|
||||||
|
# 賞与保険料算出内訳書 (SHOYO)
|
||||||
|
# ──────────────────────────────────────
|
||||||
|
|
||||||
|
def _parse_shoyo(zf, names: list, zip_filename: str) -> Dict[str, Any]:
|
||||||
|
# メインXML(.xmlかつ「賞与保険料算出内訳書」を含むもの)
|
||||||
|
xml_name = next(
|
||||||
|
n for n in names
|
||||||
|
if '賞与保険料算出内訳書' in n.split('/')[-1]
|
||||||
|
and n.endswith('.xml')
|
||||||
|
)
|
||||||
|
with zf.open(xml_name) as f:
|
||||||
|
root = ET.parse(f).getroot()
|
||||||
|
|
||||||
|
shoyo_list = root.find('shouyoList')
|
||||||
|
header = shoyo_list.find('header')
|
||||||
|
|
||||||
|
jigyosho_name = get_text(header, 'jigyoshoName')
|
||||||
|
jigyosho_num = get_text(header, 'jigyoshoNum')
|
||||||
|
jigyosho_kigo = get_text(header, 'jigyoshoSeiriKigo')
|
||||||
|
nenkin_jimusho = get_text(header, 'nenkinJimusho2').replace('\u3000', ' ').strip()
|
||||||
|
nofu_gengou = get_text(header, 'nouhuMokutekiYearGengou')
|
||||||
|
nofu_year = get_text(header, 'nouhuMokutekiYear')
|
||||||
|
nofu_month = get_text(header, 'nouhuMokutekiMonth')
|
||||||
|
jin_in = get_text(header, 'jinInNum')
|
||||||
|
menjyo = get_text(header, 'menjyoHokenRyouRitu')
|
||||||
|
|
||||||
|
# 各被保険者の明細
|
||||||
|
items = []
|
||||||
|
for uchiwake in shoyo_list.findall('uchiwake'):
|
||||||
|
hyojun = uchiwake.find('hyoujyunShouyoGaku')
|
||||||
|
kenpo_ryou = uchiwake.find('kenKouHokenRyou')
|
||||||
|
kounen_ryou = uchiwake.find('kouseiNenkinHokenRyou')
|
||||||
|
|
||||||
|
hassei_ymd = get_text(hyojun, 'hasseiYMD') if hyojun is not None else ''
|
||||||
|
parsed_hassei = parse_reki_date(hassei_ymd)
|
||||||
|
|
||||||
|
items.append({
|
||||||
|
'seiri_num': get_text(uchiwake, 'seiriNum').strip(),
|
||||||
|
'shimei': get_text(uchiwake, 'shimei'),
|
||||||
|
'shori_ymd': get_text(uchiwake, 'shoriYMD'),
|
||||||
|
'hassei_ymd': hassei_ymd,
|
||||||
|
'hassei_date_iso': parsed_hassei.isoformat() if parsed_hassei else None,
|
||||||
|
'hyojun_shoyo_kenpo': parse_amount(get_text(hyojun, 'getsuGakuKenpo') if hyojun is not None else ''),
|
||||||
|
'hyojun_shoyo_kounen': parse_amount(get_text(hyojun, 'getsuGakuKounen') if hyojun is not None else ''),
|
||||||
|
'kenpo_hongetsu': parse_amount(get_text(kenpo_ryou, 'hongetsuGaku') if kenpo_ryou is not None else ''),
|
||||||
|
'kenpo_zengetsu': parse_amount(get_text(kenpo_ryou, 'zengetsuIzenMonth') if kenpo_ryou is not None else ''),
|
||||||
|
'kounen_hongetsu': parse_amount(get_text(kounen_ryou, 'hongetsuGaku') if kounen_ryou is not None else ''),
|
||||||
|
'kounen_zengetsu': parse_amount(get_text(kounen_ryou, 'zengetsuIzenMonth') if kounen_ryou is not None else ''),
|
||||||
|
'page_num': int(get_text(uchiwake, 'pageNum') or 0),
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
'document_no': get_document_no(zf, names),
|
||||||
|
'document_type': 'SHOYO',
|
||||||
|
'document_type_name': TYPE_NAMES['SHOYO'],
|
||||||
|
'zip_filename': zip_filename,
|
||||||
|
'office_name': jigyosho_name,
|
||||||
|
'office_number': jigyosho_num,
|
||||||
|
'office_kigo': jigyosho_kigo,
|
||||||
|
'nenkin_jimusho': nenkin_jimusho,
|
||||||
|
'purpose_year': gengou_to_western(nofu_gengou, nofu_year),
|
||||||
|
'purpose_month': int(nofu_month) if nofu_month else None,
|
||||||
|
'issue_date': None,
|
||||||
|
'detail': {
|
||||||
|
'jin_in_num': int(jin_in) if jin_in else 0,
|
||||||
|
'menjyo_hokenryo_ritsu': menjyo,
|
||||||
|
'page_num': int(get_text(shoyo_list, 'pageNum') or 1),
|
||||||
|
'items': items,
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
docs/1381260411286271_20260520233507.zip
Normal file
BIN
docs/1381260411286271_20260520233507.zip
Normal file
Binary file not shown.
BIN
docs/1381260411410876_20260520233324.zip
Normal file
BIN
docs/1381260411410876_20260520233324.zip
Normal file
Binary file not shown.
BIN
docs/1381260511867049_20260520233223.zip
Normal file
BIN
docs/1381260511867049_20260520233223.zip
Normal file
Binary file not shown.
87
docs/1381260511954054/202605200027318947.xml
Normal file
87
docs/1381260511954054/202605200027318947.xml
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?><?xml-stylesheet type="text/xsl" href="kagami.xsl" ?><DOC>
|
||||||
|
<FRONT>
|
||||||
|
<SECRECY>親展</SECRECY>
|
||||||
|
<STAMP>要</STAMP>
|
||||||
|
</FRONT>
|
||||||
|
<BODY ID="DOCBODY">
|
||||||
|
<STYLESHEET>kagami.xsl</STYLESHEET>
|
||||||
|
<DOCNO>202605200027318947</DOCNO>
|
||||||
|
<DATE>令和8年5月20日</DATE>
|
||||||
|
<TO>
|
||||||
|
<NAME/>
|
||||||
|
<HONORIFC/>
|
||||||
|
</TO>
|
||||||
|
<AUTHOR>
|
||||||
|
<NAME>日本年金機構理事長</NAME>
|
||||||
|
<AFF>日本年金機構</AFF>
|
||||||
|
</AUTHOR>
|
||||||
|
<TITLE>日本年金機構からのお知らせ</TITLE>
|
||||||
|
<MAINTXT>
|
||||||
|
<P>電子送付希望をいただいた賞与保険料算出内訳書を送付します。以下のファイルをご確認ください。</P>
|
||||||
|
<P>なお、ファイルにはPDF形式が含まれる場合があります。</P>
|
||||||
|
</MAINTXT>
|
||||||
|
<APPENDIX>
|
||||||
|
<DOCLINK>賞与保険料算出内訳書_令和8年4月分(202605200027318947).xml</DOCLINK>
|
||||||
|
<APPTITLE>賞与保険料算出内訳書_令和8年4月分.xml</APPTITLE>
|
||||||
|
</APPENDIX>
|
||||||
|
<MAINTXT2>
|
||||||
|
<P>CSV形式のファイルを合わせて送付しますので、必要に応じてご活用ください。</P>
|
||||||
|
</MAINTXT2>
|
||||||
|
<APPENDIX2>
|
||||||
|
<DOCLINK>賞与保険料算出内訳書_令和8年4月分_1_ヘッダー(202605200027318947).csv</DOCLINK>
|
||||||
|
<APPTITLE>賞与保険料算出内訳書_令和8年4月分_1_ヘッダー.csv</APPTITLE>
|
||||||
|
</APPENDIX2>
|
||||||
|
<APPENDIX2>
|
||||||
|
<DOCLINK>賞与保険料算出内訳書_令和8年4月分_2_内訳(202605200027318947).csv</DOCLINK>
|
||||||
|
<APPTITLE>賞与保険料算出内訳書_令和8年4月分_2_内訳.csv</APPTITLE>
|
||||||
|
</APPENDIX2>
|
||||||
|
<MAINTXT3>
|
||||||
|
<P>【事業主の皆さまへのご案内】<br/><br/>オンライン事業所年金情報サービスでは、社会保険料を口座振替で納付している事業主の方に「保険料納入告知額・領収済額通知書」の電子送付をしていますので、ぜひこの機会に電子送付の希望登録をお願いします。<br/><br/>また、オンライン事業所年金情報サービスを利用した被保険者データの受け取りは、これまで算定月・賞与支払予定月のみ可能でしたが、令和7年1月から希望する月で被保険者データを受け取ることができるようになりました。<br/><br/>詳細については、日本年金機構ホームページをご覧ください。<br/><a href="https://www.nenkin.go.jp/tokusetsu/online_jigyousho.html">https://www.nenkin.go.jp/tokusetsu/online_jigyousho.html</a><br/><br/>※上記は、既に保険料納入告知額・領収済額通知書の電子送付や被保険者データの送付希望月の登録を行っていただいている事業主の方にもご案内しています。</P>
|
||||||
|
</MAINTXT3>
|
||||||
|
</BODY>
|
||||||
|
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#" Id="mhlw.go.jp"><SignedInfo><CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/><SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/><Reference URI="#DOCBODY"><Transforms><Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/></Transforms><DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/><DigestValue>kz6HKaSL017rn++5J8seilL/xWG8cAPeePZkufBJwuQ=</DigestValue></Reference><Reference URI="yoshiki_03_shoyo_002.xsl"><DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/><DigestValue>kIv90NbjStXFCBW8Xch7MB/B/u7ryi8JyNGlCWTxqpQ=</DigestValue></Reference><Reference URI="賞与保険料算出内訳書_令和8年4月分(202605200027318947).xml"><DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/><DigestValue>Nb2dzuuBriFQwaOFg1d4/MYPi25u944Wv2M2gVhuhpk=</DigestValue></Reference><Reference URI="賞与保険料算出内訳書_令和8年4月分_1_ヘッダー(202605200027318947).csv"><DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/><DigestValue>YEkZRD1HOwh5VgACxlE/WVJiDHjeOn90ow9QRUEf4uc=</DigestValue></Reference><Reference URI="賞与保険料算出内訳書_令和8年4月分_2_内訳(202605200027318947).csv"><DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/><DigestValue>PEzU/pDPTyMB6nn245NqWLWp6sBoLTkk3Q8ZwQ1uPIw=</DigestValue></Reference></SignedInfo><SignatureValue>qEcnefe23+rBZ+MpPw3qeEvePnoOJMtQyGJL/Bwjtaz+WPXVCdO6y+qPZJbjWetUo6iwi1TLrIwO
|
||||||
|
SUkctAOYG+tshpaDkMVhsP/LWKrLIuZS9aVHB9+XDr5wUUQzs/rcTEiVMf/v9RuZ3lFZ91uObHQW
|
||||||
|
RZuv3s27LMLgJm/3iJUWyLVjQV0jfHeG/qSIfJTihY68eId8zEVNdLu6FS/SeFX81UHJbhNOaFJH
|
||||||
|
9wveJyLcd8Sdqtw09V31cvgHo1O4mMyYCB+97OfIPk6eRUaw6groo1dGJIX+rhkq7NWC0SOoDRmT
|
||||||
|
hKRhC8epW/URlHa+uIvEtKomszXf2eCiJk1QQA==</SignatureValue><KeyInfo><X509Data><X509Certificate>MIIFKTCCBBGgAwIBAgIPODUzNDEzNDYzOTk4NzA5MA0GCSqGSIb3DQEBCwUAMEYxCzAJBgNVBAYT
|
||||||
|
AkpQMRwwGgYDVQQKDBNKYXBhbmVzZSBHb3Zlcm5tZW50MRkwFwYDVQQLDBBPZmZpY2lhbFN0YXR1
|
||||||
|
c0NBMB4XDTIyMDUzMTE1MDAwMFoXDTI3MDUzMTE0NTk1OVowgYkxCzAJBgNVBAYTAkpQMRwwGgYD
|
||||||
|
VQQKDBNKYXBhbmVzZSBHb3Zlcm5tZW50MS8wLQYDVQQLDCZNaW5pc3RyeSBvZiBIZWFsdGgsIExh
|
||||||
|
Ym91ciBhbmQgV2VsZmFyZTErMCkGA1UEAwwiUHJlc2lkZW50IG9mIEphcGFuIFBlbnNpb24gU2Vy
|
||||||
|
dmljZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALFcx67Yj+R7aDJLXozKT+D6ajGM
|
||||||
|
eSLL46Zu/KLrcADNR2/4/kvznDy+cC6ekizUtR3j9JPC0UHt1ECmUAvmyX/KKQToNfFRguqkH30X
|
||||||
|
nCm0LgE0yzoocreCLHb4Q5HL82ThM0hICUQRhE5/nKn6BPVEMVIi4WvkrF56LIhsxh9yiqbQzcMh
|
||||||
|
2gbKJ9qwbXlf2t57vR5HrXuQxVmzhwh2miI/8tGBDRte6xBmQQ9iMStx/M7pC2FWuULAThA9zIop
|
||||||
|
S7G8M2c9Quz3da7rfSWQX+Cr29G2geym2wGwBiZSLOr9Haua6kyT/38i6kWnjFz+V7f90ETGGIzP
|
||||||
|
0s4mEBboG/8CAwEAAaOCAc4wggHKMB8GA1UdIwQYMBaAFFIm8Y7mfjbpZKQk94zYbSJcqFWZMB0G
|
||||||
|
A1UdDgQWBBTtZSAS2Of86iDljw/HbL63ufMtezAOBgNVHQ8BAf8EBAMCBsAwVwYDVR0gAQH/BE0w
|
||||||
|
SzBJBgsCgziGjjEIAwEBbjA6MDgGCCsGAQUFBwIBFixodHRwczovL3d3dy5ncGtpLmdvLmpwL29z
|
||||||
|
Y2EvY3BjcHMvaW5kZXguaHRtbDB0BgNVHREEbTBrpGkwZzELMAkGA1UEBhMCSlAxGDAWBgNVBAoM
|
||||||
|
D+aXpeacrOWbveaUv+W6nDEYMBYGA1UECwwP5Y6a55Sf5Yq05YON55yBMSQwIgYDVQQDDBvml6Xm
|
||||||
|
nKzlubTph5HmqZ/mp4vnkIbkuovplbcwTgYDVR0SBEcwRaRDMEExCzAJBgNVBAYTAkpQMRgwFgYD
|
||||||
|
VQQKDA/ml6XmnKzlm73mlL/lupwxGDAWBgNVBAsMD+WumOiBt+iqjeiovOWxgDBZBgNVHR8EUjBQ
|
||||||
|
ME6gTKBKpEgwRjELMAkGA1UEBhMCSlAxHDAaBgNVBAoME0phcGFuZXNlIEdvdmVybm1lbnQxGTAX
|
||||||
|
BgNVBAsMEE9mZmljaWFsU3RhdHVzQ0EwDQYJKoZIhvcNAQELBQADggEBAJapGHTU0z30nXPccxUf
|
||||||
|
JHriV0vVs8RZaSm5gwXZKJDdsEG/pfjDYze28aNVzL496zqmCZED0XIdZlI5vfWR2QY0xUwzldYG
|
||||||
|
phx0pyG1OzlQN8W247S5XsJ3eYXqcgc0qO8399vtKSHVCa4OjvFH3kEn/IfmsxWBT+10roe4HyDK
|
||||||
|
ddkT1eMGu8ccCc8WCd2SoEwQmCERtV85+Jbf0AQ95opqGUQWxAT+0n6x1Gyi9ggKyU7ifonxGUOY
|
||||||
|
nvAEIb2U+rebwvNwRN8V9G2W/LNIkiV57/Hs6H8P8ugfoNGWeAU1pzD4MfC4zuJg8veLELs+G6Xh
|
||||||
|
cG+ewK5GiwhySdvKexs=</X509Certificate><X509Certificate>MIIEBDCCAuygAwIBAgIPNzI4MDQyMzYwNDg2MzczMA0GCSqGSIb3DQEBCwUAMEYxCzAJBgNVBAYT
|
||||||
|
AkpQMRwwGgYDVQQKDBNKYXBhbmVzZSBHb3Zlcm5tZW50MRkwFwYDVQQLDBBPZmZpY2lhbFN0YXR1
|
||||||
|
c0NBMB4XDTE5MDgyMzE1MDAwMFoXDTI5MDgyMzE0NTk1OVowRjELMAkGA1UEBhMCSlAxHDAaBgNV
|
||||||
|
BAoME0phcGFuZXNlIEdvdmVybm1lbnQxGTAXBgNVBAsMEE9mZmljaWFsU3RhdHVzQ0EwggEiMA0G
|
||||||
|
CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkaCKUqxDTGx50NrhjVYKvvAYTlrmidWexGpna7JXx
|
||||||
|
SQFi0umtGe904ZbZOwSld8gxXqRJCxLx64ZUtPG25hHgYnCfxhkIA+p3nomgkwGrauSHsdBU9co9
|
||||||
|
ioKUAHPWpsp1CR2EFhE13NBBX2anxnqxil1KvInGOOl/Hf9mJ5Jz85oLgZHWxMDtRrKL2fPgXZ72
|
||||||
|
+YHv5QsyqZwFy3J9qPnQueUM7lSoYNidlyiIyhbtC8/68OH513nnksv+w65qEuXJh/LNj/y0ruAB
|
||||||
|
V3EyjHbd4oWyf7HHD4JO8ITa5ABMt2kSc91IxaSeJDBvD0rUbf4bOSnshTyQaN/gJL7Wc4xZAgMB
|
||||||
|
AAGjge4wgeswHQYDVR0OBBYEFFIm8Y7mfjbpZKQk94zYbSJcqFWZMA4GA1UdDwEB/wQEAwIBBjBO
|
||||||
|
BgNVHREERzBFpEMwQTELMAkGA1UEBhMCSlAxGDAWBgNVBAoMD+aXpeacrOWbveaUv+W6nDEYMBYG
|
||||||
|
A1UECwwP5a6Y6IG36KqN6Ki85bGAMFkGA1UdHwRSMFAwTqBMoEqkSDBGMQswCQYDVQQGEwJKUDEc
|
||||||
|
MBoGA1UECgwTSmFwYW5lc2UgR292ZXJubWVudDEZMBcGA1UECwwQT2ZmaWNpYWxTdGF0dXNDQTAP
|
||||||
|
BgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCjy1OYTCLtF1mViU3uLdA2BtbOH+qa
|
||||||
|
RqQkhJTT5Mbqblwhp+I1TaHwO7kT0Tnw74f4e2nkUd5ByMyodojFk3+/Xj1CMG56dYjDkC8GBR8+
|
||||||
|
QdrEzDF4o6nui9xqMfzyevMFasaRdMSyWpeSjCquMJjkgc5l691Rwn2ixoEUol+tfhwmKVkQttUq
|
||||||
|
Bwu5ofnwTF814RTMh4IJFQL4UloXRkRBduNh+xLvWf7sBjirI7FrLfkvkkz7YAS1ToGkEGSb+CU3
|
||||||
|
8GHXwH3oul8/5SUZriNXUexKwLqzCjjqUsca2bDDP8A7myX7zdMNKWMhweSbOpedzaR+gF2Lrsx4
|
||||||
|
wU0AP+AY</X509Certificate></X509Data></KeyInfo></Signature></DOC>
|
||||||
148
docs/1381260511954054/kagami.xsl
Normal file
148
docs/1381260511954054/kagami.xsl
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.w3.org/1999/xhtml" version="1.0">
|
||||||
|
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes" doctype-public="-//W3C/DTD XHTML 1.0 Strict//EN" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"/>
|
||||||
|
|
||||||
|
<xsl:template match="DOC">
|
||||||
|
<xsl:apply-templates select="BODY"/>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template match="BODY">
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title><xsl:value-of select="TITLE"/></title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<p align="right"><xsl:value-of select="DOCNO"/></p>
|
||||||
|
<xsl:if test="DATE!=''">
|
||||||
|
<p align="right">
|
||||||
|
<!--
|
||||||
|
<xsl:value-of select="substring(DATE,1,2)"/>
|
||||||
|
<xsl:value-of select="format-number(substring(DATE,3,2),'##')"/>
|
||||||
|
<xsl:value-of select="substring(DATE,5,1)"/>
|
||||||
|
<xsl:value-of select="format-number(substring(DATE,6,2),'##')"/>
|
||||||
|
<xsl:value-of select="substring(DATE,8,1)"/>
|
||||||
|
<xsl:value-of select="format-number(substring(DATE,9,2),'##')"/>
|
||||||
|
<xsl:value-of select="substring(DATE,11,1)"/>
|
||||||
|
-->
|
||||||
|
<xsl:value-of select="DATE"/>
|
||||||
|
</p>
|
||||||
|
</xsl:if>
|
||||||
|
<xsl:apply-templates select="TO"/>
|
||||||
|
<xsl:apply-templates select="AUTHOR"/>
|
||||||
|
|
||||||
|
<xsl:apply-templates select="TITLE"/>
|
||||||
|
|
||||||
|
<xsl:apply-templates select="MAINTXT"/>
|
||||||
|
<xsl:apply-templates select="APPENDIX"/>
|
||||||
|
<br/>
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
<xsl:apply-templates select="MAINTXT2"/>
|
||||||
|
<xsl:apply-templates select="APPENDIX2"/>
|
||||||
|
<br/>
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
<xsl:apply-templates select="MAINTXT3"/>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template match="TO" >
|
||||||
|
<xsl:if test="AFF!='' and NAME!=''">
|
||||||
|
<p>
|
||||||
|
<xsl:value-of select="AFF" disable-output-escaping="no"/>
|
||||||
|
</p>
|
||||||
|
</xsl:if>
|
||||||
|
<xsl:if test="NAME!=''">
|
||||||
|
<p>
|
||||||
|
<xsl:value-of select="NAME" disable-output-escaping="no"/>
|
||||||
|
<xsl:if test="HONORIFC!='' and NAME!=''">
|
||||||
|
<xsl:value-of select="concat(' ',HONORIFC)" />
|
||||||
|
</xsl:if>
|
||||||
|
</p>
|
||||||
|
</xsl:if>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template match="AUTHOR" >
|
||||||
|
<p align="right">
|
||||||
|
<xsl:value-of select="AFF" />
|
||||||
|
</p>
|
||||||
|
<xsl:if test="NAME!=''">
|
||||||
|
<p align="right">
|
||||||
|
<xsl:value-of select="NAME" />
|
||||||
|
</p>
|
||||||
|
</xsl:if>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template match="TITLE">
|
||||||
|
<p align="center">
|
||||||
|
<xsl:value-of select="."/>
|
||||||
|
</p>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template match="MAINTXT">
|
||||||
|
<xsl:for-each select=".">
|
||||||
|
<xsl:apply-templates select="P"/>
|
||||||
|
</xsl:for-each>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template match="MAINTXT2">
|
||||||
|
<xsl:for-each select=".">
|
||||||
|
<xsl:apply-templates select="P"/>
|
||||||
|
</xsl:for-each>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template match="MAINTXT3">
|
||||||
|
<xsl:for-each select=".">
|
||||||
|
<xsl:apply-templates select="P"/>
|
||||||
|
</xsl:for-each>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template match="P">
|
||||||
|
<p>
|
||||||
|
<xsl:value-of disable-output-escaping="yes" select="."/>
|
||||||
|
</p>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template match="APPENDIX">
|
||||||
|
<xsl:for-each select=".">
|
||||||
|
<xsl:if test="DOCLINK">
|
||||||
|
<xsl:apply-templates select="DOCLINK"/>
|
||||||
|
<br/>
|
||||||
|
</xsl:if>
|
||||||
|
<xsl:if test="not(DOCLINK)">
|
||||||
|
<xsl:apply-templates select="APPTITLE"/>
|
||||||
|
<br/>
|
||||||
|
</xsl:if>
|
||||||
|
</xsl:for-each>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template match="APPENDIX2">
|
||||||
|
<xsl:for-each select=".">
|
||||||
|
<xsl:apply-templates select="DOCLINK"/>
|
||||||
|
<br/>
|
||||||
|
</xsl:for-each>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template match="DOCLINK">
|
||||||
|
<a>
|
||||||
|
<xsl:attribute name="href">
|
||||||
|
<xsl:value-of select="." />
|
||||||
|
</xsl:attribute>
|
||||||
|
<xsl:attribute name="target">_blank</xsl:attribute>
|
||||||
|
<xsl:value-of select="../APPTITLE" />
|
||||||
|
<xsl:value-of select="@REF" />
|
||||||
|
</a>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template match="APPTITLE">
|
||||||
|
<span>
|
||||||
|
<xsl:attribute name="style">
|
||||||
|
font-weight:bold; text-decoration:underline;
|
||||||
|
</xsl:attribute>
|
||||||
|
<xsl:value-of select="." />
|
||||||
|
</span>
|
||||||
|
</xsl:template>
|
||||||
|
</xsl:stylesheet>
|
||||||
733
docs/1381260511954054/yoshiki_03_shoyo_002.xsl
Normal file
733
docs/1381260511954054/yoshiki_03_shoyo_002.xsl
Normal file
@@ -0,0 +1,733 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
||||||
|
|
||||||
|
<xsl:template match="ShouyoHokenRyouSanshutsuUchiwakeShoList">
|
||||||
|
<html>
|
||||||
|
<!-- HTMLヘッダ出力 -->
|
||||||
|
<xsl:call-template name="htmlHeader"/>
|
||||||
|
<body style="word-break:break-all;">
|
||||||
|
<xsl:variable name="itemLineNum" select="38"/>
|
||||||
|
<xsl:variable name="listCount" select="count(shouyoList)"/>
|
||||||
|
|
||||||
|
<!-- 表面出力 -->
|
||||||
|
<xsl:call-template name="frontPage">
|
||||||
|
<xsl:with-param name="listCount" select="$listCount"/>
|
||||||
|
<xsl:with-param name="itemLineNum" select="$itemLineNum"/>
|
||||||
|
</xsl:call-template>
|
||||||
|
|
||||||
|
<!-- 裏面出力 -->
|
||||||
|
<xsl:call-template name="backPage"/>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template name="frontPage">
|
||||||
|
<xsl:param name="listNum" select="1"/>
|
||||||
|
<xsl:param name="listCount"/>
|
||||||
|
<xsl:param name="pageNum" select="1"/>
|
||||||
|
<xsl:param name="itemLineNum"/>
|
||||||
|
<xsl:if test="$listNum <= $listCount">
|
||||||
|
<xsl:variable name="uchiwakeNum" select="count(shouyoList[$listNum]/uchiwake)"/>
|
||||||
|
<xsl:variable name="maxPage" select="ceiling($uchiwakeNum div $itemLineNum)"/>
|
||||||
|
<xsl:call-template name="frontList">
|
||||||
|
<xsl:with-param name="listNum" select="$listNum"/>
|
||||||
|
<xsl:with-param name="totalPageNum" select="$pageNum"/>
|
||||||
|
<xsl:with-param name="maxPage" select="$maxPage"/>
|
||||||
|
<xsl:with-param name="itemLineNum" select="$itemLineNum"/>
|
||||||
|
</xsl:call-template>
|
||||||
|
|
||||||
|
<xsl:call-template name="frontPage">
|
||||||
|
<xsl:with-param name="listNum" select="$listNum + 1"/>
|
||||||
|
<xsl:with-param name="listCount" select="$listCount"/>
|
||||||
|
<xsl:with-param name="pageNum" select="$pageNum + $maxPage"/>
|
||||||
|
<xsl:with-param name="itemLineNum" select="$itemLineNum"/>
|
||||||
|
</xsl:call-template>
|
||||||
|
</xsl:if>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template name="frontList">
|
||||||
|
<xsl:param name="listNum"/>
|
||||||
|
<xsl:param name="pageNum" select="1"/>
|
||||||
|
<xsl:param name="totalPageNum"/>
|
||||||
|
<xsl:param name="maxPage"/>
|
||||||
|
<xsl:param name="itemLineNum"/>
|
||||||
|
<xsl:variable name="startItem" select="(($pageNum - 1) * $itemLineNum) + 1"/>
|
||||||
|
<xsl:variable name="endItem" select="$itemLineNum * $pageNum"/>
|
||||||
|
<xsl:if test="$pageNum <= $maxPage">
|
||||||
|
<div>
|
||||||
|
<table class="Rterritory" cellpadding="3" cellspacing="0">
|
||||||
|
<colgroup>
|
||||||
|
<col width="975px" />
|
||||||
|
<col width="434px" />
|
||||||
|
<col width="40px" />
|
||||||
|
<col width="24px" />
|
||||||
|
<col width="16px" />
|
||||||
|
</colgroup>
|
||||||
|
<!-- ページ番号出力 -->
|
||||||
|
<xsl:variable name="outPageNum">
|
||||||
|
<xsl:choose>
|
||||||
|
<xsl:when test="shouyoList[$listNum]/uchiwake[$startItem]/pageNum and shouyoList[$listNum]/uchiwake[$startItem]/pageNum != ''"><xsl:value-of select="shouyoList[$listNum]/uchiwake[$startItem]/pageNum"/></xsl:when>
|
||||||
|
<xsl:when test="shouyoList[$listNum]/pageNum and shouyoList[$listNum]/pageNum != ''"><xsl:value-of select="shouyoList[$listNum]/pageNum"/></xsl:when>
|
||||||
|
<xsl:otherwise><xsl:value-of select="$totalPageNum"/></xsl:otherwise>
|
||||||
|
</xsl:choose>
|
||||||
|
</xsl:variable>
|
||||||
|
<xsl:call-template name="page">
|
||||||
|
<xsl:with-param name="outPageNum" select="$outPageNum"/>
|
||||||
|
</xsl:call-template>
|
||||||
|
<!-- お知らせ出力 -->
|
||||||
|
<xsl:call-template name="oshirase">
|
||||||
|
<xsl:with-param name="listNum" select="$listNum"/>
|
||||||
|
</xsl:call-template>
|
||||||
|
</table>
|
||||||
|
<!-- タイトル出力 -->
|
||||||
|
<xsl:call-template name="title">
|
||||||
|
<xsl:with-param name="listNum" select="$listNum"/>
|
||||||
|
</xsl:call-template>
|
||||||
|
<!-- 内訳出力 -->
|
||||||
|
<table class="uchiwake" cellpadding="0" cellspacing="0">
|
||||||
|
<colgroup>
|
||||||
|
<col width="85px"/>
|
||||||
|
<col width="75px"/>
|
||||||
|
<col width="60px"/>
|
||||||
|
<col width="200px"/>
|
||||||
|
<col width="90px"/>
|
||||||
|
<col width="70px"/>
|
||||||
|
<col width="70px"/>
|
||||||
|
<col width="160px"/>
|
||||||
|
<col width="160px"/>
|
||||||
|
<col width="160px"/>
|
||||||
|
<col width="160px"/>
|
||||||
|
</colgroup>
|
||||||
|
<xsl:call-template name="itemHeader"/>
|
||||||
|
<xsl:call-template name="itemBody">
|
||||||
|
<xsl:with-param name="listNum" select="$listNum"/>
|
||||||
|
<xsl:with-param name="line" select="$startItem"/>
|
||||||
|
<xsl:with-param name="end" select="$endItem"/>
|
||||||
|
</xsl:call-template>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<xsl:call-template name="frontList">
|
||||||
|
<xsl:with-param name="listNum" select="$listNum"/>
|
||||||
|
<xsl:with-param name="pageNum" select="$pageNum + 1"/>
|
||||||
|
<xsl:with-param name="totalPageNum" select="$totalPageNum + 1"/>
|
||||||
|
<xsl:with-param name="maxPage" select="$maxPage"/>
|
||||||
|
<xsl:with-param name="itemLineNum" select="$itemLineNum"/>
|
||||||
|
</xsl:call-template>
|
||||||
|
</xsl:if>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template name="page">
|
||||||
|
<xsl:param name="outPageNum"/>
|
||||||
|
<tr>
|
||||||
|
<td align="right" colspan="3" style="font-size: 12px"><xsl:value-of select="$outPageNum"/></td>
|
||||||
|
<td align="right" style="font-size: 12px">頁</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template name="oshirase">
|
||||||
|
<xsl:param name="listNum"/>
|
||||||
|
<tr>
|
||||||
|
<td></td>
|
||||||
|
<td colspan="4" class="oshirase solid" style="height:115px;line-height:11px;">
|
||||||
|
<xsl:call-template name="loop">
|
||||||
|
<xsl:with-param name="str" select="shouyoList[$listNum]/header/oshirase"/>
|
||||||
|
</xsl:call-template>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template name="title">
|
||||||
|
<xsl:param name="listNum"/>
|
||||||
|
<xsl:variable name="header" select="shouyoList[$listNum]/header"/>
|
||||||
|
<table class="title" cellspacing="0" cellpadding="0">
|
||||||
|
<colgroup>
|
||||||
|
<col width="440px" />
|
||||||
|
<col width="150px" />
|
||||||
|
<col width="40px" />
|
||||||
|
<col width="418px" />
|
||||||
|
<col width="440px" />
|
||||||
|
</colgroup>
|
||||||
|
<tr>
|
||||||
|
<td></td>
|
||||||
|
<td>
|
||||||
|
<p class="txtJust"><span>健</span><span>康</span><span>保</span><span>険</span></p>
|
||||||
|
</td>
|
||||||
|
<td rowspan="2"></td>
|
||||||
|
<td class="mainTitle" rowspan="2">
|
||||||
|
<p class="txtJust"><span>賞</span><span>与</span><span>保</span><span>険</span><span>料</span><span>算</span><span>出</span><span>内</span><span>訳</span><span>書</span></p>
|
||||||
|
</td>
|
||||||
|
<td align="right"><xsl:value-of select="$header/nenkinJimusho1"/></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td></td>
|
||||||
|
<td>
|
||||||
|
<p class="txtJust"><span>厚</span><span>生</span><span>年</span><span>金</span><span>保</span><span>険</span></p>
|
||||||
|
</td>
|
||||||
|
<td align="right"><xsl:value-of select="$header/nenkinJimusho2"/></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<table class="header" cellpadding="0" cellspacing="0">
|
||||||
|
<colgroup>
|
||||||
|
<col width="14" span="2" />
|
||||||
|
<col width="15" span="6" />
|
||||||
|
<col width="14" span="13" />
|
||||||
|
<col width="14" span="14" />
|
||||||
|
<col width="14" span="14" />
|
||||||
|
<col width="14" span="13" />
|
||||||
|
<col width="14" span="11" />
|
||||||
|
<col width="14" span="9" />
|
||||||
|
<col width="14" span="13" />
|
||||||
|
<col width="14" span="11" />
|
||||||
|
</colgroup>
|
||||||
|
<tr>
|
||||||
|
<td colspan="3" align="right"><xsl:value-of select="$header/sakuseiNendoGengou"/></td>
|
||||||
|
<td colspan="2"><xsl:if test="$header/sakuseiNendo = '1'">元</xsl:if><xsl:if test="$header/sakuseiNendo != '1'"><xsl:value-of select="$header/sakuseiNendo"/></xsl:if></td>
|
||||||
|
<td colspan="3" align="left">年度</td>
|
||||||
|
<td colspan="1"> </td>
|
||||||
|
<td colspan="3" align="right"><xsl:value-of select="$header/nouhuMokutekiYearGengou"/></td>
|
||||||
|
<td colspan="2" align="right"><xsl:if test="$header/nouhuMokutekiYear = '1'">元</xsl:if><xsl:if test="$header/nouhuMokutekiYear != '1'"><xsl:value-of select="$header/nouhuMokutekiYear"/></xsl:if></td>
|
||||||
|
<td colspan="2">年</td>
|
||||||
|
<td colspan="2"><xsl:value-of select="$header/nouhuMokutekiMonth"/></td>
|
||||||
|
<td colspan="3" align="left">月分</td>
|
||||||
|
<td colspan="6">事業所名</td>
|
||||||
|
<td colspan="32" align="left"><xsl:value-of select="$header/jigyoshoName"/></td>
|
||||||
|
<td colspan="10">事業所整理記号</td>
|
||||||
|
<td colspan="5"><xsl:value-of select="$header/jigyoshoSeiriKigo"/></td>
|
||||||
|
<td colspan="7">事業所番号</td>
|
||||||
|
<td colspan="4"><xsl:value-of select="$header/jigyoshoNum"/></td>
|
||||||
|
<td colspan="4">人員</td>
|
||||||
|
<td colspan="5"><xsl:value-of select="$header/jinInNum"/></td>
|
||||||
|
<td colspan="8">免除保険料率</td>
|
||||||
|
<td colspan="4"><xsl:value-of select="$header/menjyoHokenRyouRate"/></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template name="itemHeader">
|
||||||
|
<tr>
|
||||||
|
<td rowspan="2" class="midashiS_C allline">処理年月日</td>
|
||||||
|
<td rowspan="2" class="midashiS_C allline">整 理 番 号</td>
|
||||||
|
<td rowspan="2" class="midashiS_C allline">表 示</td>
|
||||||
|
<td rowspan="2" class="midashiS_C allline">氏 名</td>
|
||||||
|
<td rowspan="2" class="midashiS_C allline">発生年月日<br/><font class="small">(賞与支払年月日)</font></td>
|
||||||
|
<td colspan="2" class="midashiS_C allline">標 準 賞 与 額</td>
|
||||||
|
<td colspan="2" class="midashiS_C allline">健 康 保 険 料</td>
|
||||||
|
<td colspan="2" class="midashiS_C allline">厚 生 年 金 保 険 料</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="midashiS_C allline">健保<font class="small">[千円]</font></td>
|
||||||
|
<td class="midashiS_C allline">厚年<font class="small">[千円]</font></td>
|
||||||
|
<td class="midashiS_C allline">本 月 額<font class="small">[円]</font></td>
|
||||||
|
<td class="midashiS_C allline">前 月 以 前 額<font class="small">[円]</font></td>
|
||||||
|
<td class="midashiS_C allline">本 月 額<font class="small">[円]</font></td>
|
||||||
|
<td class="midashiS_C allline">前 月 以 前 額<font class="small">[円]</font></td>
|
||||||
|
</tr>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template name="itemBody">
|
||||||
|
<xsl:param name="listNum"/>
|
||||||
|
<xsl:param name="line" select="1"/>
|
||||||
|
<xsl:param name="end"/>
|
||||||
|
<xsl:if test="$end >= $line">
|
||||||
|
<xsl:variable name="contents" select="shouyoList[$listNum]/uchiwake[$line]"/>
|
||||||
|
<tr>
|
||||||
|
<td class="normalM_C allline"><xsl:value-of select="$contents/shoriYMD" /></td>
|
||||||
|
<td class="normalM_C allline"><xsl:value-of select="$contents/seiriNum" /></td>
|
||||||
|
<td class="normalM_C allline">
|
||||||
|
<xsl:call-template name="halfSpace">
|
||||||
|
<xsl:with-param name="str" select="$contents/hyouji" />
|
||||||
|
</xsl:call-template>
|
||||||
|
</td>
|
||||||
|
<td class="normalM_C allline" align="left"><xsl:value-of select="$contents/shimei" /></td>
|
||||||
|
<td class="normalM_C allline"><xsl:value-of select="$contents/hyoujyunShouyoGaku/hasseiYMD" /></td>
|
||||||
|
<td class="normalM_C allline"><xsl:value-of select="$contents/hyoujyunShouyoGaku/getsuGakuKenpo" /></td>
|
||||||
|
<td class="normalM_C allline"><xsl:value-of select="$contents/hyoujyunShouyoGaku/getsuGakuKounen" /></td>
|
||||||
|
<td class="normalM_C allline" align="right"><xsl:if test="$contents/kenKouHokenRyou/hongetsuGaku != ''"><xsl:value-of select="format-number($contents/kenKouHokenRyou/hongetsuGaku, '###,###,###,##0.0')" /><xsl:text disable-output-escaping="yes">&nbsp;&nbsp;</xsl:text></xsl:if></td>
|
||||||
|
<td class="normalM_C allline" align="right"><xsl:if test="$contents/kenKouHokenRyou/zengetsuIzenKingaku != ''"><xsl:value-of select="format-number($contents/kenKouHokenRyou/zengetsuIzenKingaku, '###,###,###,##0.0')" /><xsl:text disable-output-escaping="yes">&nbsp;&nbsp;</xsl:text></xsl:if></td>
|
||||||
|
<td class="normalM_C allline" align="right"><xsl:if test="$contents/kouseiNenkinHokenRyou/hongetsuGaku != ''"><xsl:value-of select="format-number($contents/kouseiNenkinHokenRyou/hongetsuGaku, '###,###,###,##0.00')" /></xsl:if></td>
|
||||||
|
<td class="normalM_C allline" align="right"><xsl:if test="$contents/kouseiNenkinHokenRyou/zengetsuIzenKingaku != ''"><xsl:value-of select="format-number($contents/kouseiNenkinHokenRyou/zengetsuIzenKingaku, '###,###,###,##0.00')" /></xsl:if></td>
|
||||||
|
</tr>
|
||||||
|
<xsl:call-template name="itemBody">
|
||||||
|
<xsl:with-param name="listNum" select="$listNum"/>
|
||||||
|
<xsl:with-param name="line" select="$line + 1"/>
|
||||||
|
<xsl:with-param name="end" select="$end"/>
|
||||||
|
</xsl:call-template>
|
||||||
|
</xsl:if>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template name="backPage">
|
||||||
|
<xsl:if test="uragamiFlg = 'true'">
|
||||||
|
<div class="ura">
|
||||||
|
<table class="ura title">
|
||||||
|
<colgroup>
|
||||||
|
<col width="330px" />
|
||||||
|
<col width="150px" />
|
||||||
|
<col width="40px" />
|
||||||
|
<col width="438px" />
|
||||||
|
<col width="330px" />
|
||||||
|
</colgroup>
|
||||||
|
<tr>
|
||||||
|
<td></td>
|
||||||
|
<td>
|
||||||
|
<p class="txtJust"><span>健</span><span>康</span><span>保</span><span>険</span></p>
|
||||||
|
</td>
|
||||||
|
<td rowspan="2"></td>
|
||||||
|
<td class="mainTitle" rowspan="2">
|
||||||
|
<p class="txtJust"><span>賞</span><span>与</span><span>保</span><span>険</span><span>料</span><span>算</span><span>出</span><span>内</span><span>訳</span><span>書</span><span>の</span><span>み</span><span>か</span><span>た</span></p>
|
||||||
|
</td>
|
||||||
|
<td rowspan="2"></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td></td>
|
||||||
|
<td>
|
||||||
|
<p class="txtJust"><span>厚</span><span>生</span><span>年</span><span>金</span><span>保</span><span>険</span></p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<table class="ura">
|
||||||
|
<colgroup>
|
||||||
|
<col width="1288px" />
|
||||||
|
</colgroup>
|
||||||
|
<tr>
|
||||||
|
<td class="ura normalM_L">
|
||||||
|
1.表題の下には、年度、年月分、事業所名称、年金事務所名、事業所整理記号、事業所番号、人員及び頁を記入してあります。
|
||||||
|
<br/> なお、事業所名称が長い時は25字まで記入してあります。また人員には保険料計算時の現存被保険者数(健保法118条該当者、厚年法適用除外者、育児休業取得者、
|
||||||
|
<br/> 産前産後休業取得者を含む。)を記入してあります。
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="ura normalM_L">
|
||||||
|
2.賞与保険料算出内訳書には、健康保険料と厚生年金保険料別に被保険者個人ごとの被保険者賞与支払届等をもとに算出した賞与保険料を記入してあります。
|
||||||
|
<br/> なお、「二以上事業所勤務被保険者賞与保険料登録票」で登録された賞与保険料については出力されません。
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="ura">
|
||||||
|
<table>
|
||||||
|
<colgroup>
|
||||||
|
<col width="200px"/>
|
||||||
|
<col width="1088px"/>
|
||||||
|
</colgroup>
|
||||||
|
<tr>
|
||||||
|
<td class="ura normalM_L allline">(1)処理年月日</td>
|
||||||
|
<td class="ura normalM_L allline">「処理年月日」欄は年金事務所で事務処理上使用する欄です。</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="ura normalM_L allline">(2)整理番号</td>
|
||||||
|
<td class="ura normalM_L allline">被保険者整理番号を記入してあります。</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="ura normalM_L allline">(3)表示</td>
|
||||||
|
<td class="ura normalM_L allline">
|
||||||
|
①#:「随時保険料」の対象となった事を示してあります。<br/>
|
||||||
|
②2: 厚生年金保険法適用除外者を示してあります。<br/>
|
||||||
|
③3: 健康保険法適用除外者を示してあります。<br/>
|
||||||
|
④4: 介護保険料徴収者を示してあります。
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="ura normalM_L allline">(4)資格</td>
|
||||||
|
<td class="ura normalM_L allline">
|
||||||
|
①発生年月日 (賞与支払年月日):賞与が支払われた年月日を記入してあります。<br/>
|
||||||
|
②標準賞与額:発生年月日現在における標準賞与額を健康保険と厚生年金保険別に記入してあります。<br/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="ura normalM_L allline">(5)「健康保険料」及び「厚生年金保険料」の欄</td>
|
||||||
|
<td class="ura normalM_L allline">
|
||||||
|
①本 月 額:発生年月日(賞与支払年月日)が当月の賞与保険料(標準賞与額×保険料率)を、被保険者賞与支払届は符号なしで、被保険者<br/>
|
||||||
|
賞与支払届(取消)は「-」を付して記入してあります。<br/>
|
||||||
|
②前月以前額:発生年月日(賞与支払年月日)が前月以前の賞与保険料(標準賞与額×保険料率)を、被保険者賞与支払届は符号なしで、被保<br/>
|
||||||
|
険者賞与支払届(取消)は「-」を付して記入してあります。</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="ura normalM_L">
|
||||||
|
3.記載内容について、わからないことがあるときは管轄の年金事務所に照会して下さい。
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</xsl:if>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<xsl:template name="htmlHeader">
|
||||||
|
<head>
|
||||||
|
<META http-equiv="X-UA-Compatible" content="IE=11" />
|
||||||
|
<title>賞与保険料算出内訳書</title>
|
||||||
|
<style type="text/css">
|
||||||
|
<!-- reset.css Start -->
|
||||||
|
/* http://meyerweb.com/eric/tools/css/reset/
|
||||||
|
v2.0 | 20110126
|
||||||
|
License: none (public domain)
|
||||||
|
*/
|
||||||
|
|
||||||
|
html, body, div, span, applet, object, iframe,
|
||||||
|
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
|
||||||
|
a, abbr, acronym, address, big, cite, code,
|
||||||
|
del, dfn, em, img, ins, kbd, q, s, samp,
|
||||||
|
small, strike, strong, sub, sup, tt, var,
|
||||||
|
b, u, i, center,
|
||||||
|
dl, dt, dd, ol, ul, li,
|
||||||
|
fieldset, form, label, legend,
|
||||||
|
table, caption, tbody, tfoot, thead, tr, th, td,
|
||||||
|
article, aside, canvas, details, embed,
|
||||||
|
figure, figcaption, footer, header, hgroup,
|
||||||
|
menu, nav, output, ruby, section, summary,
|
||||||
|
time, mark, audio, video {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
border: 0;
|
||||||
|
font-size: 100%;
|
||||||
|
font: inherit;
|
||||||
|
/*vertical-align: baseline; */
|
||||||
|
}
|
||||||
|
/* HTML5 display-role reset for older browsers */
|
||||||
|
article, aside, details, figcaption, figure,
|
||||||
|
footer, header, hgroup, menu, nav, section {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
ol, ul {
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
blockquote, q {
|
||||||
|
quotes: none;
|
||||||
|
}
|
||||||
|
blockquote:before, blockquote:after,
|
||||||
|
q:before, q:after {
|
||||||
|
content: '';
|
||||||
|
content: none;
|
||||||
|
}
|
||||||
|
table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
border-spacing: 0;
|
||||||
|
}
|
||||||
|
<!-- reset.css End -->
|
||||||
|
body {
|
||||||
|
font-family: "Yu Mincho", serif;
|
||||||
|
}
|
||||||
|
table.title {
|
||||||
|
border-collapse: collapse;
|
||||||
|
font-size: 16px;
|
||||||
|
text-align: right;
|
||||||
|
width: 1489px;
|
||||||
|
table-layout: fixed;
|
||||||
|
margin: 40px;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
table.header {
|
||||||
|
border-collapse: collapse;
|
||||||
|
font-size: 12px;
|
||||||
|
text-align: right;
|
||||||
|
width: 1489px;
|
||||||
|
table-layout: fixed;
|
||||||
|
margin: 40px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
table.uchiwake {
|
||||||
|
border-collapse: collapse;
|
||||||
|
font-size: 12px;
|
||||||
|
text-align: right;
|
||||||
|
width: 1489px;
|
||||||
|
table-layout: fixed;
|
||||||
|
margin-left: 40px;
|
||||||
|
margin-right: 40px;
|
||||||
|
margin-bottom: 40px;
|
||||||
|
}
|
||||||
|
td {
|
||||||
|
padding-top: 2px;
|
||||||
|
padding-left: 5px;
|
||||||
|
padding-right: 5px;
|
||||||
|
}
|
||||||
|
table.ura {
|
||||||
|
border-collapse: collapse;
|
||||||
|
text-align: left;
|
||||||
|
width: 1288px;
|
||||||
|
}
|
||||||
|
/* テーブル属性 */
|
||||||
|
div { /*外枠*/
|
||||||
|
border: 1px solid;
|
||||||
|
width: 1560px;
|
||||||
|
height: 1075px;
|
||||||
|
margin: 50px;
|
||||||
|
margin-bottom: 100px;
|
||||||
|
}
|
||||||
|
div.ura {
|
||||||
|
width: 1360px;
|
||||||
|
padding-top: 50px;
|
||||||
|
padding-left: 100px;
|
||||||
|
padding-right: 100px;
|
||||||
|
}
|
||||||
|
td.solid { /* 全ての線を表示 */
|
||||||
|
border-top: 2px solid;
|
||||||
|
border-right: 2px solid;
|
||||||
|
border-bottom: 2px solid;
|
||||||
|
border-left: 2px solid;
|
||||||
|
}
|
||||||
|
td.tdTopLeft2px {
|
||||||
|
border-top: 2px solid;
|
||||||
|
border-right: 2px solid;
|
||||||
|
border-bottom: 2px solid;
|
||||||
|
border-left: 2px solid;
|
||||||
|
}
|
||||||
|
td.tdBottomLeft2px {
|
||||||
|
border-top: 2px solid;
|
||||||
|
border-right: 2px solid;
|
||||||
|
border-bottom: 2px solid;
|
||||||
|
border-left: 2px solid;
|
||||||
|
}
|
||||||
|
td.tdBottomRight2px {
|
||||||
|
border-right: 2px solid;
|
||||||
|
border-bottom: 2px solid;
|
||||||
|
border-left: 2px solid;
|
||||||
|
}
|
||||||
|
td.tdTopRight2px {
|
||||||
|
border-top: 2px solid;
|
||||||
|
border-right: 2px solid;
|
||||||
|
border-bottom: 2px solid;
|
||||||
|
border-left: 2px solid;
|
||||||
|
}
|
||||||
|
td.tdTop2px {
|
||||||
|
border-top: 2px solid;
|
||||||
|
border-right: 2px solid;
|
||||||
|
border-bottom: 2px solid;
|
||||||
|
border-left: 2px solid;
|
||||||
|
}
|
||||||
|
td.tdLeft2px {
|
||||||
|
border-top: 2px solid;
|
||||||
|
border-right: 2px solid;
|
||||||
|
border-bottom: 2px solid;
|
||||||
|
border-left: 2px solid;
|
||||||
|
}
|
||||||
|
td.tdLeftOnly2px {
|
||||||
|
border-left: 2px solid;
|
||||||
|
}
|
||||||
|
td.tdRightOnly2px {
|
||||||
|
border-right: 2px solid;
|
||||||
|
}
|
||||||
|
td.tdRight2px {
|
||||||
|
border-right: 2px solid;
|
||||||
|
border-left: 2px solid;
|
||||||
|
}
|
||||||
|
td.tdRight2pxSolid {
|
||||||
|
border-top: 2px solid;
|
||||||
|
border-right: 2px solid;
|
||||||
|
border-left: 2px solid;
|
||||||
|
border-bottom: 2px solid;
|
||||||
|
}
|
||||||
|
td.tdBottom2px {
|
||||||
|
border-top: none;
|
||||||
|
border-right: 2px solid;
|
||||||
|
border-bottom: 2px solid;
|
||||||
|
border-left: 2px solid;
|
||||||
|
}
|
||||||
|
td.tdTopBottomNone {
|
||||||
|
border-top: none; /* 上線なし */
|
||||||
|
border-bottom: none; /* 下線なし */
|
||||||
|
border-right: 2px solid;
|
||||||
|
border-left: 2px solid;
|
||||||
|
}
|
||||||
|
td.tdTop1px {
|
||||||
|
border-top: 1px solid; /* 上線1px */
|
||||||
|
}
|
||||||
|
td.tdBottom1px {
|
||||||
|
border-bottom: 1px solid; /* 下線1px */
|
||||||
|
}
|
||||||
|
td.allline {
|
||||||
|
border-top: 1px solid #000000;
|
||||||
|
border-left: 1px solid #000000;
|
||||||
|
border-right: 1px solid #000000;
|
||||||
|
border-bottom: 1px solid #000000;
|
||||||
|
}
|
||||||
|
td.linetb {
|
||||||
|
border-top: 1px solid #000000;
|
||||||
|
border-bottom: 1px solid #000000;
|
||||||
|
}
|
||||||
|
td.linetrb {
|
||||||
|
border-top: 1px solid #000000;
|
||||||
|
border-right: 1px solid #000000;
|
||||||
|
border-bottom: 1px solid #000000;
|
||||||
|
}
|
||||||
|
td.linetlb {
|
||||||
|
border-top: 1px solid #000000;
|
||||||
|
border-left: 1px solid #000000;
|
||||||
|
border-bottom: 1px solid #000000;
|
||||||
|
}
|
||||||
|
td.linetlr {
|
||||||
|
border-top: 1px solid #000000;
|
||||||
|
border-left: 1px solid #000000;
|
||||||
|
border-right: 1px solid #000000;
|
||||||
|
}
|
||||||
|
td.linelrb {
|
||||||
|
border-left: 1px solid #000000;
|
||||||
|
border-right: 1px solid #000000;
|
||||||
|
border-bottom: 1px solid #000000;
|
||||||
|
}
|
||||||
|
td.linetl {
|
||||||
|
border-top: 1px solid #000000;
|
||||||
|
border-left: 1px solid #000000;
|
||||||
|
}
|
||||||
|
td.linetr {
|
||||||
|
border-top: 1px solid #000000;
|
||||||
|
border-right: 1px solid #000000;
|
||||||
|
}
|
||||||
|
td.linerb {
|
||||||
|
border-right: 1px solid #000000;
|
||||||
|
border-bottom: 1px solid #000000;
|
||||||
|
}
|
||||||
|
td.linelb {
|
||||||
|
border-left: 1px solid #000000;
|
||||||
|
border-bottom: 1px solid #000000;
|
||||||
|
}
|
||||||
|
td.linet {
|
||||||
|
border-top: 1px solid #000000;
|
||||||
|
}
|
||||||
|
td.lineb {
|
||||||
|
border-bottom: 1px solid #000000;
|
||||||
|
}
|
||||||
|
td.liner {
|
||||||
|
border-right: 1px solid #000000;
|
||||||
|
}
|
||||||
|
td.linel {
|
||||||
|
border-left: 1px solid #000000;
|
||||||
|
}
|
||||||
|
td.linelr {
|
||||||
|
border-left: 1px solid #000000;
|
||||||
|
border-right: 1px solid #000000;
|
||||||
|
}
|
||||||
|
.mainTitle {
|
||||||
|
font-size: 28px;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
.normalS_C {
|
||||||
|
font-size: 7pt;
|
||||||
|
}
|
||||||
|
.normalSS_C {
|
||||||
|
font-size: 6pt;
|
||||||
|
}
|
||||||
|
.normalSM_C {
|
||||||
|
font-size: 7.5pt;
|
||||||
|
}
|
||||||
|
.normalSM_TC {
|
||||||
|
font-size: 7.5pt;
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
.normalML_C {
|
||||||
|
font-size: 8.5pt;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.normalL_C {
|
||||||
|
font-size: 9pt;
|
||||||
|
}
|
||||||
|
.normalL_TL {
|
||||||
|
font-size: 9pt;
|
||||||
|
vertical-align : top;
|
||||||
|
text-align : left;
|
||||||
|
}
|
||||||
|
.normalL_TR {
|
||||||
|
font-size: 9pt;
|
||||||
|
vertical-align: top;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
.normalLL_LG {
|
||||||
|
font-size: 12pt;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
.txtJust {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
/* 見出し項目 */
|
||||||
|
.oshirase {
|
||||||
|
font-size: 7.5pt;
|
||||||
|
line-height: 11px;
|
||||||
|
vertical-align: top;
|
||||||
|
text-align: left;
|
||||||
|
word-wrap: break-word;
|
||||||
|
overflow-wrap: break-word;
|
||||||
|
}
|
||||||
|
table.Rterritory {
|
||||||
|
width: 230px;
|
||||||
|
table-layout: fixed;
|
||||||
|
margin: 40px;
|
||||||
|
margin-top: 20px;
|
||||||
|
margin-bottom: 0px;
|
||||||
|
}
|
||||||
|
font.small {
|
||||||
|
font-size: 10px;
|
||||||
|
}
|
||||||
|
.midashiS_C { /* 見出し項目 */
|
||||||
|
font-size: 14px;
|
||||||
|
text-align: center;
|
||||||
|
height: 20px;
|
||||||
|
}
|
||||||
|
.headerM_C { /* ヘッダデータ(文字項目) */
|
||||||
|
font-size: 10pt;
|
||||||
|
text-align: center;
|
||||||
|
height: 50px;
|
||||||
|
}
|
||||||
|
.normalM_C { /* 明細データ(文字項目) */
|
||||||
|
font-size: 10pt;
|
||||||
|
height: 18px;
|
||||||
|
}
|
||||||
|
.ura {
|
||||||
|
font-size: 12pt;
|
||||||
|
line-height: 20px;
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
.ura_title {
|
||||||
|
font-size: 12pt;
|
||||||
|
}
|
||||||
|
.ura_normalM_C { /* 明細データ(文字項目) */
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<!--br対応-->
|
||||||
|
<xsl:template name="loop">
|
||||||
|
<xsl:param name="str"/>
|
||||||
|
<xsl:choose>
|
||||||
|
<xsl:when test="contains($str,'<br/>')">
|
||||||
|
<xsl:variable name="sub" select="substring-before($str,'<br/>')"/>
|
||||||
|
<xsl:value-of select="$sub" disable-output-escaping="yes" />
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
<xsl:call-template name="loop">
|
||||||
|
<xsl:with-param name="str" select="substring-after($str,'<br/>')"/>
|
||||||
|
</xsl:call-template>
|
||||||
|
</xsl:when>
|
||||||
|
|
||||||
|
<xsl:otherwise>
|
||||||
|
<xsl:value-of select="$str" disable-output-escaping="yes" />
|
||||||
|
</xsl:otherwise>
|
||||||
|
</xsl:choose>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
<!--半角スペース対応-->
|
||||||
|
<xsl:template name="halfSpace">
|
||||||
|
<xsl:param name="str"/>
|
||||||
|
<xsl:choose>
|
||||||
|
<xsl:when test="contains($str,' ')">
|
||||||
|
<xsl:variable name="sub" select="substring-before($str,' ')"/>
|
||||||
|
<xsl:value-of select="$sub" disable-output-escaping="yes" />
|
||||||
|
<xsl:text disable-output-escaping="yes">&nbsp;&nbsp;</xsl:text>
|
||||||
|
<xsl:call-template name="halfSpace">
|
||||||
|
<xsl:with-param name="str" select="substring-after($str,' ')"/>
|
||||||
|
</xsl:call-template>
|
||||||
|
</xsl:when>
|
||||||
|
<xsl:otherwise>
|
||||||
|
<xsl:value-of select="$str" disable-output-escaping="yes" />
|
||||||
|
</xsl:otherwise>
|
||||||
|
</xsl:choose>
|
||||||
|
</xsl:template>
|
||||||
|
|
||||||
|
</xsl:stylesheet>
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><?xml-stylesheet type="text/xsl" href="yoshiki_03_shoyo_002.xsl" ?>
|
||||||
|
|
||||||
|
<ShouyoHokenRyouSanshutsuUchiwakeShoList>
|
||||||
|
<shouyoList>
|
||||||
|
<header>
|
||||||
|
<jigyoshoName>新日本テクノソリューションズ 株式会社</jigyoshoName>
|
||||||
|
<jigyoshoNum>23090</jigyoshoNum>
|
||||||
|
<jigyoshoSeiriKigo>41-シサメ</jigyoshoSeiriKigo>
|
||||||
|
<jinInNum>2</jinInNum>
|
||||||
|
<nenkinJimusho2> 墨田 年金事務所</nenkinJimusho2>
|
||||||
|
<nouhuMokutekiMonth>4</nouhuMokutekiMonth>
|
||||||
|
<nouhuMokutekiYear>8</nouhuMokutekiYear>
|
||||||
|
<nouhuMokutekiYearGengou>令和</nouhuMokutekiYearGengou>
|
||||||
|
<oshirase>賞与保険料算出内訳書の概要や見方については日本年金機構ホームページをご確認ください。<br/>【概要・見方】<br/><a href="https://www.nenkin.go.jp/denshibenri/online_jigyousho/denshidata/tsuchisho.html#cms04">https://www.nenkin.go.jp/denshibenri/online_jigyousho/denshidata/tsuchisho.html#cms04</a></oshirase>
|
||||||
|
<pageNum>1</pageNum>
|
||||||
|
<sakuseiNendo>8</sakuseiNendo>
|
||||||
|
<sakuseiNendoGengou>令和</sakuseiNendoGengou>
|
||||||
|
</header>
|
||||||
|
<pageNum>1</pageNum>
|
||||||
|
<uchiwake>
|
||||||
|
<hyouji> 4</hyouji>
|
||||||
|
<hyoujyunShouyoGaku>
|
||||||
|
<getsuGakuKenpo>4300</getsuGakuKenpo>
|
||||||
|
<getsuGakuKounen>1500</getsuGakuKounen>
|
||||||
|
<hasseiYMD>R080430</hasseiYMD>
|
||||||
|
</hyoujyunShouyoGaku>
|
||||||
|
<kenKouHokenRyou>
|
||||||
|
<hongetsuGaku>503100.0</hongetsuGaku>
|
||||||
|
<zengetsuIzenMonth></zengetsuIzenMonth>
|
||||||
|
</kenKouHokenRyou>
|
||||||
|
<kouseiNenkinHokenRyou>
|
||||||
|
<hongetsuGaku>274500.00</hongetsuGaku>
|
||||||
|
<zengetsuIzenMonth></zengetsuIzenMonth>
|
||||||
|
</kouseiNenkinHokenRyou>
|
||||||
|
<pageNum>1</pageNum>
|
||||||
|
<seiriNum>2</seiriNum>
|
||||||
|
<shimei>張 翔鶴</shimei>
|
||||||
|
<shoriYMD>R080501</shoriYMD>
|
||||||
|
</uchiwake>
|
||||||
|
<uragamiFlg>false</uragamiFlg>
|
||||||
|
</shouyoList>
|
||||||
|
<uragamiFlg>true</uragamiFlg>
|
||||||
|
</ShouyoHokenRyouSanshutsuUchiwakeShoList>
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
"ページ番号","機構からのお知らせ","年金事務所名1","年金事務所名2","作成年度元号","作成年度","納付目的年元号","納付目的年","納付目的月","事業所名称","事業所整理記号","事業所番号","人員","免除保険料率"
|
||||||
|
"1","賞与保険料算出内訳書の概要や見方については日本年金機構ホームページをご確認ください。<br/>【概要・見方】<br/><a href=""https://www.nenkin.go.jp/denshibenri/online_jigyousho/denshidata/tsuchisho.html#cms04"">https://www.nenkin.go.jp/denshibenri/online_jigyousho/denshidata/tsuchisho.html#cms04</a>",""," 墨田 年金事務所","令和","8","令和","8","4","新日本テクノソリューションズ 株式会社","41-シサメ","23090","2",""
|
||||||
|
@@ -0,0 +1,2 @@
|
|||||||
|
"納付目的年月","処理年月日","整理番号","表示","被保険者氏名","発生年月日(賞与支払年月日)","標準賞与額_健保","標準賞与額_厚年","健康保険料_本月額","健康保険料_前月以前額","厚生年金保険料_本月額","厚生年金保険料_前月以前額"
|
||||||
|
"令和8年4月","R080501","2"," 4","張 翔鶴","R080430","4300","1500","503,100.0","","274,500.00",""
|
||||||
|
@@ -119,6 +119,16 @@
|
|||||||
<p><a class="btn" href="payroll.html">給与システムを開く</a></p>
|
<p><a class="btn" href="payroll.html">給与システムを開く</a></p>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<section class="card">
|
||||||
|
<h2>📋 社会保険電子文書</h2>
|
||||||
|
<p>
|
||||||
|
日本年金機構からダウンロードした ZIP ファイルを読み込み、社会保険料額・納入告知・賞与算出内訳などを確認できます。
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<a class="btn" href="nenkin-portal.html" style="background: #17a2b8">文書ポータルを開く</a>
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
<section class="card">
|
<section class="card">
|
||||||
<h2>🏛 e-Gov 電子送達</h2>
|
<h2>🏛 e-Gov 電子送達</h2>
|
||||||
<p>
|
<p>
|
||||||
|
|||||||
735
frontend/nenkin-portal.html
Normal file
735
frontend/nenkin-portal.html
Normal file
@@ -0,0 +1,735 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="ja">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>社会保険電子文書ポータル</title>
|
||||||
|
<script src="js/auth.js"></script>
|
||||||
|
<link rel="stylesheet" href="css/style.css" />
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: system-ui, -apple-system, "Yu Gothic UI", "Hiragino Kaku Gothic ProN", "メイリオ", sans-serif;
|
||||||
|
padding: 24px;
|
||||||
|
background: #f5f7fa;
|
||||||
|
}
|
||||||
|
.page-header {
|
||||||
|
max-width: 1100px;
|
||||||
|
margin: 0 auto 20px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.page-header h1 { margin: 0; font-size: 20px; }
|
||||||
|
.back-link {
|
||||||
|
padding: 8px 16px;
|
||||||
|
background: #007bff;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 14px;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
.back-link:hover { background: #0056b3; }
|
||||||
|
|
||||||
|
/* ── アップロードゾーン ── */
|
||||||
|
.upload-zone {
|
||||||
|
max-width: 1100px;
|
||||||
|
margin: 0 auto 24px;
|
||||||
|
border: 2px dashed #adb5bd;
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 28px 24px;
|
||||||
|
text-align: center;
|
||||||
|
background: #fff;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: border-color 0.2s, background 0.2s;
|
||||||
|
}
|
||||||
|
.upload-zone.dragover {
|
||||||
|
border-color: #007bff;
|
||||||
|
background: #e8f4ff;
|
||||||
|
}
|
||||||
|
.upload-zone h3 { margin: 0 0 8px; font-size: 16px; color: #495057; }
|
||||||
|
.upload-zone p { margin: 0; color: #6c757d; font-size: 13px; }
|
||||||
|
.upload-zone input[type=file] { display: none; }
|
||||||
|
.upload-btn {
|
||||||
|
display: inline-block;
|
||||||
|
margin-top: 12px;
|
||||||
|
padding: 8px 20px;
|
||||||
|
background: #007bff;
|
||||||
|
color: #fff;
|
||||||
|
border-radius: 5px;
|
||||||
|
font-size: 14px;
|
||||||
|
cursor: pointer;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
.upload-btn:hover { background: #0056b3; }
|
||||||
|
#upload-status {
|
||||||
|
max-width: 1100px;
|
||||||
|
margin: 0 auto 12px;
|
||||||
|
font-size: 14px;
|
||||||
|
min-height: 24px;
|
||||||
|
}
|
||||||
|
.status-ok { color: #28a745; font-weight: bold; }
|
||||||
|
.status-err { color: #dc3545; font-weight: bold; }
|
||||||
|
|
||||||
|
/* ── フィルターバー ── */
|
||||||
|
.filter-bar {
|
||||||
|
max-width: 1100px;
|
||||||
|
margin: 0 auto 16px;
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
.type-tabs { display: flex; gap: 6px; flex-wrap: wrap; }
|
||||||
|
.type-tab {
|
||||||
|
padding: 5px 14px;
|
||||||
|
border-radius: 20px;
|
||||||
|
border: 1px solid #ced4da;
|
||||||
|
background: #fff;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 13px;
|
||||||
|
color: #495057;
|
||||||
|
transition: all 0.15s;
|
||||||
|
}
|
||||||
|
.type-tab:hover { border-color: #007bff; color: #007bff; }
|
||||||
|
.type-tab.active { background: #007bff; color: #fff; border-color: #007bff; }
|
||||||
|
.filter-select {
|
||||||
|
padding: 5px 10px;
|
||||||
|
border: 1px solid #ced4da;
|
||||||
|
border-radius: 5px;
|
||||||
|
font-size: 13px;
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── 文書一覧テーブル ── */
|
||||||
|
.doc-table-wrap {
|
||||||
|
max-width: 1100px;
|
||||||
|
margin: 0 auto;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 1px 4px rgba(0,0,0,0.07);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.doc-table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
.doc-table thead th {
|
||||||
|
background: #f8f9fa;
|
||||||
|
padding: 10px 12px;
|
||||||
|
text-align: left;
|
||||||
|
font-weight: 600;
|
||||||
|
border-bottom: 2px solid #dee2e6;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.doc-table tbody tr {
|
||||||
|
border-bottom: 1px solid #f0f0f0;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 0.1s;
|
||||||
|
}
|
||||||
|
.doc-table tbody tr:hover { background: #f0f7ff; }
|
||||||
|
.doc-table tbody tr.selected { background: #dbeafe; }
|
||||||
|
.doc-table tbody td { padding: 10px 12px; }
|
||||||
|
.badge {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 2px 8px;
|
||||||
|
border-radius: 10px;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
.badge-shakai { background: #d1ecf1; color: #0c5460; }
|
||||||
|
.badge-nounyu { background: #d4edda; color: #155724; }
|
||||||
|
.badge-shoyo { background: #fff3cd; color: #856404; }
|
||||||
|
.badge-unknown { background: #e2e3e5; color: #383d41; }
|
||||||
|
.no-data { text-align: center; color: #aaa; padding: 40px; }
|
||||||
|
|
||||||
|
/* ── 詳細パネル ── */
|
||||||
|
#detail-panel {
|
||||||
|
max-width: 1100px;
|
||||||
|
margin: 16px auto 0;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 1px 4px rgba(0,0,0,0.07);
|
||||||
|
padding: 24px;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
#detail-panel.visible { display: block; }
|
||||||
|
.detail-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: flex-start;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
.detail-header h2 { margin: 0; font-size: 18px; }
|
||||||
|
.detail-close {
|
||||||
|
background: none;
|
||||||
|
border: 1px solid #ced4da;
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 4px 10px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 13px;
|
||||||
|
color: #6c757d;
|
||||||
|
}
|
||||||
|
.detail-close:hover { background: #f8f9fa; }
|
||||||
|
|
||||||
|
/* 事業所情報カード */
|
||||||
|
.info-cards {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
.info-card {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 180px;
|
||||||
|
background: #f8f9fa;
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 12px 16px;
|
||||||
|
}
|
||||||
|
.info-card .label { font-size: 11px; color: #6c757d; margin-bottom: 4px; }
|
||||||
|
.info-card .value { font-size: 14px; font-weight: 600; color: #212529; }
|
||||||
|
|
||||||
|
/* 金額テーブル */
|
||||||
|
.amount-section { margin-bottom: 20px; }
|
||||||
|
.amount-section h3 { font-size: 15px; margin: 0 0 12px; border-left: 3px solid #007bff; padding-left: 8px; }
|
||||||
|
.amount-grid {
|
||||||
|
display: grid;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
.amount-row {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 8px 14px;
|
||||||
|
background: #f8f9fa;
|
||||||
|
border-radius: 5px;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
.amount-row.total {
|
||||||
|
background: #e8f4ff;
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 15px;
|
||||||
|
}
|
||||||
|
.amount-row .amt { font-family: monospace; font-size: 15px; }
|
||||||
|
|
||||||
|
/* 告知額 vs 領収済額 サイドバイサイド */
|
||||||
|
.nounyu-compare {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
gap: 16px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
@media (max-width: 640px) { .nounyu-compare { grid-template-columns: 1fr; } }
|
||||||
|
.nounyu-box {
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
.nounyu-box.kokuchi { background: #fff3cd; border: 1px solid #ffc107; }
|
||||||
|
.nounyu-box.ryoshu { background: #d4edda; border: 1px solid #28a745; }
|
||||||
|
.nounyu-box h4 { margin: 0 0 12px; font-size: 14px; }
|
||||||
|
|
||||||
|
/* 賞与明細テーブル */
|
||||||
|
.shoyo-table-wrap { overflow-x: auto; }
|
||||||
|
.shoyo-table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
.shoyo-table th {
|
||||||
|
background: #f8f9fa;
|
||||||
|
padding: 8px 10px;
|
||||||
|
text-align: center;
|
||||||
|
border: 1px solid #dee2e6;
|
||||||
|
white-space: nowrap;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
.shoyo-table td {
|
||||||
|
padding: 7px 10px;
|
||||||
|
border: 1px solid #f0f0f0;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
.shoyo-table td.name { text-align: left; font-weight: 600; }
|
||||||
|
.shoyo-table tfoot td {
|
||||||
|
background: #e8f4ff;
|
||||||
|
font-weight: 700;
|
||||||
|
border-top: 2px solid #007bff;
|
||||||
|
}
|
||||||
|
.shoyo-table .empty-cell { color: #ccc; text-align: center; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div class="page-header">
|
||||||
|
<h1>社会保険電子文書ポータル</h1>
|
||||||
|
<a class="back-link" href="payroll.html">← 給与管理メニューに戻る</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- アップロードゾーン -->
|
||||||
|
<div class="upload-zone" id="upload-zone">
|
||||||
|
<h3>📥 社会保険 ZIP ファイルをここにドロップ</h3>
|
||||||
|
<p>またはボタンから選択してください(複数ファイル対応)</p>
|
||||||
|
<input type="file" id="zip-input" accept=".zip" multiple />
|
||||||
|
<br>
|
||||||
|
<button class="upload-btn" onclick="document.getElementById('zip-input').click()">
|
||||||
|
ファイルを選択
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div id="upload-status"></div>
|
||||||
|
|
||||||
|
<!-- フィルターバー -->
|
||||||
|
<div class="filter-bar">
|
||||||
|
<div class="type-tabs" id="type-tabs">
|
||||||
|
<button class="type-tab active" data-type="">すべて</button>
|
||||||
|
<button class="type-tab" data-type="SHAKAI">社会保険料額情報</button>
|
||||||
|
<button class="type-tab" data-type="NOUNYU">納入告知・領収</button>
|
||||||
|
<button class="type-tab" data-type="SHOYO">賞与保険料算出</button>
|
||||||
|
</div>
|
||||||
|
<select class="filter-select" id="year-select">
|
||||||
|
<option value="">年度(すべて)</option>
|
||||||
|
</select>
|
||||||
|
<select class="filter-select" id="month-select">
|
||||||
|
<option value="">月(すべて)</option>
|
||||||
|
<option value="1">1月</option><option value="2">2月</option>
|
||||||
|
<option value="3">3月</option><option value="4">4月</option>
|
||||||
|
<option value="5">5月</option><option value="6">6月</option>
|
||||||
|
<option value="7">7月</option><option value="8">8月</option>
|
||||||
|
<option value="9">9月</option><option value="10">10月</option>
|
||||||
|
<option value="11">11月</option><option value="12">12月</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 文書一覧テーブル -->
|
||||||
|
<div class="doc-table-wrap">
|
||||||
|
<table class="doc-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>種別</th>
|
||||||
|
<th>対象年月</th>
|
||||||
|
<th>事業所名</th>
|
||||||
|
<th>整理記号・番号</th>
|
||||||
|
<th>年金事務所</th>
|
||||||
|
<th>発行日</th>
|
||||||
|
<th>登録日時</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="doc-list-body">
|
||||||
|
<tr><td colspan="7" class="no-data">データを読み込んでいます...</td></tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 詳細パネル -->
|
||||||
|
<div id="detail-panel">
|
||||||
|
<div class="detail-header">
|
||||||
|
<h2 id="detail-title">詳細</h2>
|
||||||
|
<button class="detail-close" onclick="closeDetail()">✕ 閉じる</button>
|
||||||
|
</div>
|
||||||
|
<div id="detail-body"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const API = "";
|
||||||
|
let currentFilter = { type: "", year: "", month: "" };
|
||||||
|
let selectedDocId = null;
|
||||||
|
|
||||||
|
// ──────────────────────────────────
|
||||||
|
// ページ初期化
|
||||||
|
// ──────────────────────────────────
|
||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
checkAuth();
|
||||||
|
loadDocuments();
|
||||||
|
loadFilterOptions();
|
||||||
|
initUploadZone();
|
||||||
|
|
||||||
|
document.getElementById('type-tabs').addEventListener('click', e => {
|
||||||
|
const tab = e.target.closest('.type-tab');
|
||||||
|
if (!tab) return;
|
||||||
|
document.querySelectorAll('.type-tab').forEach(t => t.classList.remove('active'));
|
||||||
|
tab.classList.add('active');
|
||||||
|
currentFilter.type = tab.dataset.type;
|
||||||
|
loadDocuments();
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById('year-select').addEventListener('change', e => {
|
||||||
|
currentFilter.year = e.target.value;
|
||||||
|
loadDocuments();
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById('month-select').addEventListener('change', e => {
|
||||||
|
currentFilter.month = e.target.value;
|
||||||
|
loadDocuments();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// ──────────────────────────────────
|
||||||
|
// 文書一覧ロード
|
||||||
|
// ──────────────────────────────────
|
||||||
|
async function loadDocuments() {
|
||||||
|
const params = new URLSearchParams();
|
||||||
|
if (currentFilter.type) params.set('doc_type', currentFilter.type);
|
||||||
|
if (currentFilter.year) params.set('year', currentFilter.year);
|
||||||
|
if (currentFilter.month) params.set('month', currentFilter.month);
|
||||||
|
|
||||||
|
const url = `${API}/nenkin/documents${params.toString() ? '?' + params : ''}`;
|
||||||
|
try {
|
||||||
|
const res = await fetch(url);
|
||||||
|
const docs = await res.json();
|
||||||
|
renderDocList(docs);
|
||||||
|
} catch (e) {
|
||||||
|
document.getElementById('doc-list-body').innerHTML =
|
||||||
|
`<tr><td colspan="7" class="no-data" style="color:#dc3545">読み込みエラー: ${e.message}</td></tr>`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderDocList(docs) {
|
||||||
|
const tbody = document.getElementById('doc-list-body');
|
||||||
|
if (!docs.length) {
|
||||||
|
tbody.innerHTML = '<tr><td colspan="7" class="no-data">文書が登録されていません</td></tr>';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
tbody.innerHTML = docs.map(d => {
|
||||||
|
const period = d.purpose_year && d.purpose_month
|
||||||
|
? `${d.purpose_year}年${d.purpose_month}月`
|
||||||
|
: '−';
|
||||||
|
const issueDate = d.issue_date ? d.issue_date.replace(/-/g, '/') : '−';
|
||||||
|
const uploadedAt = d.uploaded_at ? d.uploaded_at.slice(0, 16).replace('T', ' ') : '−';
|
||||||
|
const selected = d.id === selectedDocId ? 'selected' : '';
|
||||||
|
return `<tr class="${selected}" onclick="loadDetail(${d.id})" data-id="${d.id}">
|
||||||
|
<td>${badgeHtml(d.document_type, d.document_type_name)}</td>
|
||||||
|
<td>${period}</td>
|
||||||
|
<td>${escHtml(d.office_name || '−')}</td>
|
||||||
|
<td><small>${escHtml(d.office_kigo || '')} ${escHtml(d.office_number || '')}</small></td>
|
||||||
|
<td>${escHtml(d.nenkin_jimusho || '−')}</td>
|
||||||
|
<td>${issueDate}</td>
|
||||||
|
<td><small>${uploadedAt}</small></td>
|
||||||
|
</tr>`;
|
||||||
|
}).join('');
|
||||||
|
}
|
||||||
|
|
||||||
|
function badgeHtml(type, name) {
|
||||||
|
const cls = {SHAKAI:'badge-shakai', NOUNYU:'badge-nounyu', SHOYO:'badge-shoyo'}[type] || 'badge-unknown';
|
||||||
|
return `<span class="badge ${cls}">${escHtml(name || type)}</span>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ──────────────────────────────────
|
||||||
|
// フィルター選択肢(年度)
|
||||||
|
// ──────────────────────────────────
|
||||||
|
async function loadFilterOptions() {
|
||||||
|
try {
|
||||||
|
const res = await fetch(`${API}/nenkin/filter-options`);
|
||||||
|
const data = await res.json();
|
||||||
|
const sel = document.getElementById('year-select');
|
||||||
|
const years = [...new Set(data.periods.map(p => p.purpose_year))].sort((a,b) => b-a);
|
||||||
|
years.forEach(y => {
|
||||||
|
const opt = document.createElement('option');
|
||||||
|
opt.value = y; opt.textContent = `${y}年`;
|
||||||
|
sel.appendChild(opt);
|
||||||
|
});
|
||||||
|
} catch (_) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ──────────────────────────────────
|
||||||
|
// 詳細ロード
|
||||||
|
// ──────────────────────────────────
|
||||||
|
async function loadDetail(docId) {
|
||||||
|
// 選択行のハイライト
|
||||||
|
selectedDocId = docId;
|
||||||
|
document.querySelectorAll('.doc-table tbody tr').forEach(tr => {
|
||||||
|
tr.classList.toggle('selected', parseInt(tr.dataset.id) === docId);
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await fetch(`${API}/nenkin/documents/${docId}`);
|
||||||
|
const data = await res.json();
|
||||||
|
renderDetail(data);
|
||||||
|
} catch (e) {
|
||||||
|
showDetailError(e.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeDetail() {
|
||||||
|
selectedDocId = null;
|
||||||
|
document.getElementById('detail-panel').classList.remove('visible');
|
||||||
|
document.querySelectorAll('.doc-table tbody tr').forEach(tr => tr.classList.remove('selected'));
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderDetail({ document: doc, detail }) {
|
||||||
|
const panel = document.getElementById('detail-panel');
|
||||||
|
const title = document.getElementById('detail-title');
|
||||||
|
const body = document.getElementById('detail-body');
|
||||||
|
|
||||||
|
const period = doc.purpose_year && doc.purpose_month
|
||||||
|
? `${doc.purpose_year}年${doc.purpose_month}月分`
|
||||||
|
: '';
|
||||||
|
title.textContent = `${doc.document_type_name} ${period}`;
|
||||||
|
|
||||||
|
// 共通事業所カード
|
||||||
|
const infoHtml = `
|
||||||
|
<div class="info-cards">
|
||||||
|
<div class="info-card">
|
||||||
|
<div class="label">事業所名</div>
|
||||||
|
<div class="value">${escHtml(doc.office_name || '−')}</div>
|
||||||
|
</div>
|
||||||
|
<div class="info-card">
|
||||||
|
<div class="label">事業所番号 / 整理記号</div>
|
||||||
|
<div class="value">${escHtml(doc.office_number || '')} / ${escHtml(doc.office_kigo || '')}</div>
|
||||||
|
</div>
|
||||||
|
<div class="info-card">
|
||||||
|
<div class="label">担当年金事務所</div>
|
||||||
|
<div class="value">${escHtml(doc.nenkin_jimusho || '−')}</div>
|
||||||
|
</div>
|
||||||
|
${doc.issue_date ? `<div class="info-card">
|
||||||
|
<div class="label">発行日</div>
|
||||||
|
<div class="value">${doc.issue_date.replace(/-/g,'/')}</div>
|
||||||
|
</div>` : ''}
|
||||||
|
</div>`;
|
||||||
|
|
||||||
|
let typeHtml = '';
|
||||||
|
if (doc.document_type === 'SHAKAI') {
|
||||||
|
typeHtml = renderShakai(detail);
|
||||||
|
} else if (doc.document_type === 'NOUNYU') {
|
||||||
|
typeHtml = renderNounyu(detail);
|
||||||
|
} else if (doc.document_type === 'SHOYO') {
|
||||||
|
typeHtml = renderShoyo(detail);
|
||||||
|
}
|
||||||
|
|
||||||
|
body.innerHTML = infoHtml + typeHtml;
|
||||||
|
panel.classList.add('visible');
|
||||||
|
panel.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
||||||
|
}
|
||||||
|
|
||||||
|
// ──────────────────────────────────
|
||||||
|
// 社会保険料額情報 (SHAKAI)
|
||||||
|
// ──────────────────────────────────
|
||||||
|
function renderShakai(d) {
|
||||||
|
const kigen = d.nofu_kigen_date ? d.nofu_kigen_date.replace(/-/g, '/') : '−';
|
||||||
|
const addr = [d.office_postcode ? `〒${d.office_postcode}` : '', d.office_address].filter(Boolean).join(' ');
|
||||||
|
return `
|
||||||
|
<div class="amount-section">
|
||||||
|
<h3>保険料額</h3>
|
||||||
|
<div class="amount-grid">
|
||||||
|
${amtRow('健康保険料', d.kenkou_hokenryo)}
|
||||||
|
${amtRow('厚生年金保険料', d.kousei_nenkin_hokenryo)}
|
||||||
|
${amtRow('子ども・子育て拠出金', d.kodomo_kyoshutsukin)}
|
||||||
|
${amtRow('合 計', d.total, true)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="info-cards">
|
||||||
|
<div class="info-card">
|
||||||
|
<div class="label">納付期限</div>
|
||||||
|
<div class="value">${kigen}</div>
|
||||||
|
</div>
|
||||||
|
${addr ? `<div class="info-card" style="flex:2">
|
||||||
|
<div class="label">事業所所在地</div>
|
||||||
|
<div class="value">${escHtml(addr)}</div>
|
||||||
|
</div>` : ''}
|
||||||
|
</div>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ──────────────────────────────────
|
||||||
|
// 保険料納入告知額・領収済額 (NOUNYU)
|
||||||
|
// ──────────────────────────────────
|
||||||
|
function renderNounyu(d) {
|
||||||
|
const kigen = d.kokuchi_nofu_kigen ? d.kokuchi_nofu_kigen.replace(/-/g, '/') : '−';
|
||||||
|
const ryoshuDt = d.ryoshu_date ? d.ryoshu_date.replace(/-/g, '/') : '−';
|
||||||
|
const ryoshuPeriod = d.ryoshu_nofu_year && d.ryoshu_nofu_month
|
||||||
|
? `${d.ryoshu_nofu_year}年${d.ryoshu_nofu_month}月分`
|
||||||
|
: '−';
|
||||||
|
return `
|
||||||
|
<div class="nounyu-compare">
|
||||||
|
<div class="nounyu-box kokuchi">
|
||||||
|
<h4>📋 今月の保険料告知額(納付期限: ${kigen})</h4>
|
||||||
|
<div class="amount-grid">
|
||||||
|
${amtRow('健康保険料', d.kokuchi_kenkou)}
|
||||||
|
${amtRow('厚生年金保険料', d.kokuchi_kounen)}
|
||||||
|
${amtRow('子ども・子育て拠出金', d.kokuchi_kodomo)}
|
||||||
|
${amtRow('合 計', d.kokuchi_total, true)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="nounyu-box ryoshu">
|
||||||
|
<h4>✅ 前月分領収済額(${ryoshuPeriod}・領収日: ${ryoshuDt})</h4>
|
||||||
|
<div class="amount-grid">
|
||||||
|
${amtRow('健康保険料', d.ryoshu_kenkou)}
|
||||||
|
${amtRow('厚生年金保険料', d.ryoshu_kounen)}
|
||||||
|
${amtRow('子ども・子育て拠出金', d.ryoshu_kodomo)}
|
||||||
|
${amtRow('合 計', d.ryoshu_total, true)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="info-cards">
|
||||||
|
<div class="info-card">
|
||||||
|
<div class="label">事業所所在地</div>
|
||||||
|
<div class="value">${escHtml([d.office_postcode ? '〒'+d.office_postcode : '', d.office_address].filter(Boolean).join(' '))}</div>
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ──────────────────────────────────
|
||||||
|
// 賞与保険料算出内訳書 (SHOYO)
|
||||||
|
// ──────────────────────────────────
|
||||||
|
function renderShoyo(d) {
|
||||||
|
if (!d || !d.items) return '<p>詳細データなし</p>';
|
||||||
|
|
||||||
|
const totKenpo = sum(d.items, 'kenpo_hongetsu');
|
||||||
|
const totKounen = sum(d.items, 'kounen_hongetsu');
|
||||||
|
const totHKenpo = sum(d.items, 'hyojun_shoyo_kenpo');
|
||||||
|
const totHKounen = sum(d.items, 'hyojun_shoyo_kounen');
|
||||||
|
|
||||||
|
const rows = d.items.map(it => {
|
||||||
|
const hassei = it.hassei_date_iso
|
||||||
|
? it.hassei_date_iso.replace(/-/g, '/')
|
||||||
|
: (it.hassei_ymd || '−');
|
||||||
|
return `<tr>
|
||||||
|
<td>${escHtml(it.seiri_num || '')}</td>
|
||||||
|
<td class="name">${escHtml(it.shimei || '')}</td>
|
||||||
|
<td>${hassei}</td>
|
||||||
|
<td>${fmtAmt(it.hyojun_shoyo_kenpo)}</td>
|
||||||
|
<td>${fmtAmt(it.hyojun_shoyo_kounen)}</td>
|
||||||
|
<td>${fmtAmt(it.kenpo_hongetsu)}</td>
|
||||||
|
<td>${it.kenpo_zengetsu ? fmtAmt(it.kenpo_zengetsu) : '<span class="empty-cell">−</span>'}</td>
|
||||||
|
<td>${fmtAmt(it.kounen_hongetsu)}</td>
|
||||||
|
<td>${it.kounen_zengetsu ? fmtAmt(it.kounen_zengetsu) : '<span class="empty-cell">−</span>'}</td>
|
||||||
|
</tr>`;
|
||||||
|
}).join('');
|
||||||
|
|
||||||
|
return `
|
||||||
|
<div class="info-cards" style="margin-bottom:16px">
|
||||||
|
<div class="info-card">
|
||||||
|
<div class="label">対象人員</div>
|
||||||
|
<div class="value">${d.jin_in_num} 名</div>
|
||||||
|
</div>
|
||||||
|
${d.menjyo_hokenryo_ritsu ? `<div class="info-card">
|
||||||
|
<div class="label">免除保険料率</div>
|
||||||
|
<div class="value">${escHtml(d.menjyo_hokenryo_ritsu)}</div>
|
||||||
|
</div>` : ''}
|
||||||
|
</div>
|
||||||
|
<div class="shoyo-table-wrap">
|
||||||
|
<table class="shoyo-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th rowspan="2">#</th>
|
||||||
|
<th rowspan="2">氏名</th>
|
||||||
|
<th rowspan="2">賞与支払日</th>
|
||||||
|
<th colspan="2" style="background:#fff8e1">標準賞与額</th>
|
||||||
|
<th colspan="2" style="background:#e3f2fd">健康保険料</th>
|
||||||
|
<th colspan="2" style="background:#e8f5e9">厚生年金保険料</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th style="background:#fff8e1">健保</th>
|
||||||
|
<th style="background:#fff8e1">厚年</th>
|
||||||
|
<th style="background:#e3f2fd">本月額</th>
|
||||||
|
<th style="background:#e3f2fd">前月以前</th>
|
||||||
|
<th style="background:#e8f5e9">本月額</th>
|
||||||
|
<th style="background:#e8f5e9">前月以前</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>${rows}</tbody>
|
||||||
|
<tfoot>
|
||||||
|
<tr>
|
||||||
|
<td colspan="3" style="text-align:center">合 計</td>
|
||||||
|
<td>${fmtAmt(totHKenpo)}</td>
|
||||||
|
<td>${fmtAmt(totHKounen)}</td>
|
||||||
|
<td>${fmtAmt(totKenpo)}</td>
|
||||||
|
<td>−</td>
|
||||||
|
<td>${fmtAmt(totKounen)}</td>
|
||||||
|
<td>−</td>
|
||||||
|
</tr>
|
||||||
|
</tfoot>
|
||||||
|
</table>
|
||||||
|
</div>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ──────────────────────────────────
|
||||||
|
// アップロードゾーン
|
||||||
|
// ──────────────────────────────────
|
||||||
|
function initUploadZone() {
|
||||||
|
const zone = document.getElementById('upload-zone');
|
||||||
|
const input = document.getElementById('zip-input');
|
||||||
|
|
||||||
|
zone.addEventListener('dragover', e => { e.preventDefault(); zone.classList.add('dragover'); });
|
||||||
|
zone.addEventListener('dragleave', () => zone.classList.remove('dragover'));
|
||||||
|
zone.addEventListener('drop', e => {
|
||||||
|
e.preventDefault();
|
||||||
|
zone.classList.remove('dragover');
|
||||||
|
const files = [...e.dataTransfer.files].filter(f => f.name.endsWith('.zip'));
|
||||||
|
if (files.length) uploadFiles(files);
|
||||||
|
});
|
||||||
|
|
||||||
|
input.addEventListener('change', () => {
|
||||||
|
const files = [...input.files];
|
||||||
|
if (files.length) uploadFiles(files);
|
||||||
|
input.value = '';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function uploadFiles(files) {
|
||||||
|
const status = document.getElementById('upload-status');
|
||||||
|
status.innerHTML = `<span style="color:#6c757d">アップロード中... (${files.length}件)</span>`;
|
||||||
|
|
||||||
|
let ok = 0, skipped = 0, errors = [];
|
||||||
|
|
||||||
|
for (const file of files) {
|
||||||
|
const fd = new FormData();
|
||||||
|
fd.append('file', file);
|
||||||
|
try {
|
||||||
|
const res = await fetch(`${API}/nenkin/upload`, { method: 'POST', body: fd });
|
||||||
|
const json = await res.json();
|
||||||
|
if (res.status === 409) {
|
||||||
|
skipped++;
|
||||||
|
} else if (!res.ok) {
|
||||||
|
errors.push(`${file.name}: ${json.detail || res.statusText}`);
|
||||||
|
} else {
|
||||||
|
ok++;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
errors.push(`${file.name}: ${e.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let msg = '';
|
||||||
|
if (ok > 0) msg += `<span class="status-ok">✓ ${ok}件登録完了</span> `;
|
||||||
|
if (skipped > 0) msg += `<span style="color:#856404">⚠ ${skipped}件は既登録のためスキップ</span> `;
|
||||||
|
if (errors.length) msg += `<span class="status-err">✗ エラー: ${errors.join(' / ')}</span>`;
|
||||||
|
status.innerHTML = msg;
|
||||||
|
|
||||||
|
if (ok > 0) {
|
||||||
|
loadDocuments();
|
||||||
|
loadFilterOptions();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ──────────────────────────────────
|
||||||
|
// ユーティリティ
|
||||||
|
// ──────────────────────────────────
|
||||||
|
function escHtml(s) {
|
||||||
|
return String(s).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"');
|
||||||
|
}
|
||||||
|
|
||||||
|
function fmtAmt(v) {
|
||||||
|
if (v == null || v === '') return '<span class="empty-cell">−</span>';
|
||||||
|
return '¥' + Number(v).toLocaleString('ja-JP', { minimumFractionDigits: 0, maximumFractionDigits: 0 });
|
||||||
|
}
|
||||||
|
|
||||||
|
function amtRow(label, value, isTotal = false) {
|
||||||
|
return `<div class="amount-row${isTotal ? ' total' : ''}">
|
||||||
|
<span>${label}</span>
|
||||||
|
<span class="amt">${fmtAmt(value)}</span>
|
||||||
|
</div>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function sum(items, key) {
|
||||||
|
return items.reduce((acc, it) => acc + (Number(it[key]) || 0), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function showDetailError(msg) {
|
||||||
|
const panel = document.getElementById('detail-panel');
|
||||||
|
document.getElementById('detail-body').innerHTML =
|
||||||
|
`<p style="color:#dc3545">エラー: ${escHtml(msg)}</p>`;
|
||||||
|
panel.classList.add('visible');
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -119,6 +119,15 @@
|
|||||||
<h2>源泉徴収票</h2>
|
<h2>源泉徴収票</h2>
|
||||||
<p>給与所得の源泉徴収票を発行します(本人用・区役所用・税務署用 各1部)</p>
|
<p>給与所得の源泉徴収票を発行します(本人用・区役所用・税務署用 各1部)</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="menu-card"
|
||||||
|
onclick="location.href = 'nenkin-portal.html'"
|
||||||
|
>
|
||||||
|
<div class="icon">📋</div>
|
||||||
|
<h2>社会保険電子文書</h2>
|
||||||
|
<p>日本年金機構からの電子文書(保険料通知・賞与内訳等)を管理します</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
|
|||||||
Reference in New Issue
Block a user