Add MCU report endpoint and deployment tooling
This commit is contained in:
BIN
docs/akses-tabel-cpone-middleware.docx
Normal file
BIN
docs/akses-tabel-cpone-middleware.docx
Normal file
Binary file not shown.
133
docs/akses-tabel-cpone-middleware.html
Normal file
133
docs/akses-tabel-cpone-middleware.html
Normal file
@@ -0,0 +1,133 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="id">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Daftar Akses Tabel CPONE Middleware</title>
|
||||
<style>
|
||||
@page { size: Letter; margin: 1in; }
|
||||
body { font-family: Calibri, Arial, sans-serif; color: #1f2937; font-size: 10.5pt; line-height: 1.25; margin: 0; }
|
||||
h1 { color: #0b2545; font-size: 24pt; line-height: 1.05; margin: 0 0 6pt 0; }
|
||||
h2 { color: #1f4d78; font-size: 15pt; margin: 18pt 0 7pt 0; border-bottom: 1px solid #cbd5e1; padding-bottom: 3pt; }
|
||||
h3 { color: #1f4d78; font-size: 12pt; margin: 12pt 0 5pt 0; }
|
||||
p { margin: 0 0 6pt 0; }
|
||||
.kicker { color: #2e74b5; text-transform: uppercase; letter-spacing: 1.2pt; font-size: 9pt; font-weight: bold; margin-bottom: 7pt; }
|
||||
.subtitle { color: #475569; font-size: 12pt; margin-bottom: 14pt; }
|
||||
.meta { width: 100%; border-collapse: collapse; margin: 0 0 12pt 0; }
|
||||
.meta td { padding: 3pt 8pt 3pt 0; vertical-align: top; border: none; }
|
||||
.meta .label { width: 1.25in; color: #475569; font-weight: bold; }
|
||||
.callout { border-left: 4px solid #2e74b5; background: #f4f6f9; padding: 8pt 10pt; margin: 8pt 0 12pt 0; }
|
||||
.callout strong { color: #0b2545; }
|
||||
table.data { width: 100%; border-collapse: collapse; table-layout: fixed; margin: 6pt 0 10pt 0; }
|
||||
table.data th { background: #e8eef5; color: #0b2545; font-weight: bold; text-align: left; padding: 5pt 7pt; border: 1px solid #aebdcd; }
|
||||
table.data td { padding: 4pt 7pt; border: 1px solid #cbd5e1; vertical-align: top; }
|
||||
table.data tr { page-break-inside: avoid; }
|
||||
table.data th:nth-child(1) { width: 38%; }
|
||||
table.data th:nth-child(2) { width: 14%; text-align: center; }
|
||||
table.data th:nth-child(3) { width: 20%; text-align: center; }
|
||||
table.data th:nth-child(4) { width: 28%; }
|
||||
table.data td:nth-child(2), table.data td:nth-child(3) { text-align: center; }
|
||||
table.compact th:first-child, table.compact td:first-child { width: 42%; }
|
||||
table.compact th:last-child, table.compact td:last-child { width: 58%; }
|
||||
.mono { font-family: Consolas, "Courier New", monospace; font-size: 9.2pt; color: #111827; }
|
||||
.small { font-size: 9pt; color: #475569; }
|
||||
.pill { font-weight: bold; color: #1f3a5f; }
|
||||
pre { font-family: Consolas, "Courier New", monospace; font-size: 8.6pt; line-height: 1.2; background: #f8fafc; border: 1px solid #cbd5e1; padding: 8pt; white-space: pre-wrap; margin: 5pt 0 10pt 0; }
|
||||
ul { margin: 4pt 0 8pt 18pt; padding: 0; }
|
||||
li { margin: 0 0 3pt 0; }
|
||||
.footer { color: #64748b; font-size: 8.5pt; border-top: 1px solid #cbd5e1; padding-top: 5pt; margin-top: 18pt; }
|
||||
.pagebreak { page-break-before: always; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="kicker">CPONE Middleware • Database Access Reference</div>
|
||||
<h1>Daftar Akses Tabel</h1>
|
||||
<div class="subtitle">Kebutuhan privilege database untuk service CPONE Middleware</div>
|
||||
|
||||
<table class="meta">
|
||||
<tr><td class="label">Database target</td><td>Database HIS yang dikonfigurasi pada <span class="mono">CPONE_DB_DATABASE</span></td></tr>
|
||||
<tr><td class="label">Database user</td><td>User yang dikonfigurasi pada <span class="mono">CPONE_DB_USERNAME</span></td></tr>
|
||||
<tr><td class="label">Dasar pemetaan</td><td>Query SQL pada folder <span class="mono">internal/repository</span></td></tr>
|
||||
<tr><td class="label">Tanggal</td><td>17 September 2026</td></tr>
|
||||
</table>
|
||||
|
||||
<div class="callout"><strong>Ringkasan:</strong> service membutuhkan akses <strong>SELECT</strong> pada tabel master dan tabel transaksi yang dibaca. Akses write diperlukan hanya pada tabel yang dipakai endpoint POST untuk membuat paket, pasien, registrasi, layanan laboratorium, nominal, dan diagnosis.</div>
|
||||
|
||||
<h2>1. Tabel dengan READ dan WRITE</h2>
|
||||
<p>Tabel berikut membutuhkan akses <span class="pill">SELECT</span> dan operasi write seperti tercantum.</p>
|
||||
<table class="data">
|
||||
<tr><th>Nama tabel</th><th>READ</th><th>WRITE</th><th>Kegunaan utama</th></tr>
|
||||
<tr><td class="mono">medrec</td><td>SELECT</td><td>INSERT</td><td>Pencarian dan pembuatan data pasien/medical record.</td></tr>
|
||||
<tr><td class="mono">regpas</td><td>SELECT</td><td>INSERT</td><td>Pembuatan dan pengecekan registrasi pasien.</td></tr>
|
||||
<tr><td class="mono">regpas_nominal</td><td>SELECT</td><td>INSERT, UPDATE</td><td>Nominal administrasi pada level registrasi pasien.</td></tr>
|
||||
<tr><td class="mono">trxdepartemen</td><td>SELECT</td><td>INSERT</td><td>Pembuatan transaksi departemen.</td></tr>
|
||||
<tr><td class="mono">trxdepartemen_nominal</td><td>SELECT</td><td>INSERT, UPDATE</td><td>Rekap nominal layanan/item/tempat tidur dan total transaksi.</td></tr>
|
||||
<tr><td class="mono">trxidlaboratorium</td><td>SELECT</td><td>INSERT</td><td>Pembuatan nomor/transaksi laboratorium.</td></tr>
|
||||
<tr><td class="mono">trxlayanan</td><td>SELECT</td><td>INSERT</td><td>Penambahan layanan pada transaksi.</td></tr>
|
||||
<tr><td class="mono">trxlayanan_detail</td><td>SELECT</td><td>INSERT</td><td>Relasi detail layanan dengan paket dispenser.</td></tr>
|
||||
<tr><td class="mono">trxlayanan_penunjang</td><td>SELECT</td><td>INSERT</td><td>Relasi layanan penunjang/header laboratorium.</td></tr>
|
||||
<tr><td class="mono">lab_trxspesimen</td><td>SELECT</td><td>INSERT</td><td>Pencatatan spesimen laboratorium.</td></tr>
|
||||
<tr><td class="mono">paket_header</td><td>SELECT</td><td>INSERT, UPDATE, DELETE</td><td>Pembuatan paket; DELETE hanya untuk cleanup saat transaksi gagal.</td></tr>
|
||||
<tr><td class="mono">paket_layanan</td><td>SELECT</td><td>INSERT, DELETE</td><td>Detail layanan paket; DELETE hanya untuk cleanup.</td></tr>
|
||||
<tr><td class="mono">paket_departemen</td><td>SELECT</td><td>INSERT, DELETE</td><td>Departemen yang terkait dengan paket; DELETE hanya untuk cleanup.</td></tr>
|
||||
<tr><td class="mono">paket_dispenser_header</td><td>SELECT</td><td>INSERT</td><td>Header paket dispenser pada kunjungan pasien.</td></tr>
|
||||
<tr><td class="mono">paket_dispenser_episode_rj</td><td>SELECT</td><td>INSERT</td><td>Episode kunjungan rawat jalan paket dispenser.</td></tr>
|
||||
<tr><td class="mono">paket_dispenser_layanan</td><td>SELECT</td><td>INSERT</td><td>Layanan yang dihasilkan dari paket dispenser.</td></tr>
|
||||
<tr><td class="mono">paket_dispenser_item</td><td>SELECT</td><td>INSERT</td><td>Item paket dispenser.</td></tr>
|
||||
<tr><td class="mono">paket_dispenser_adm</td><td>SELECT</td><td>INSERT</td><td>Administrasi paket dispenser.</td></tr>
|
||||
</table>
|
||||
|
||||
<h2>2. Tabel dengan WRITE saja</h2>
|
||||
<table class="data compact">
|
||||
<tr><th>Nama tabel</th><th>Operasi</th></tr>
|
||||
<tr><td class="mono">diagnosa_log</td><td>INSERT — menyimpan log diagnosis kerja pada registrasi laboratorium.</td></tr>
|
||||
<tr><td class="mono">regpas_diagnosa</td><td>INSERT — menyimpan diagnosis kerja yang terkait dengan pasien/registrasi.</td></tr>
|
||||
</table>
|
||||
<p class="small">Kedua tabel di atas tidak dibaca kembali oleh service dalam query saat ini, tetapi harus dapat menerima INSERT ketika endpoint registrasi laboratorium menyimpan diagnosis.</p>
|
||||
|
||||
<h2>3. Tabel dengan READ saja</h2>
|
||||
<p>Tabel master dan referensi berikut hanya dibaca oleh service, sehingga cukup diberikan privilege <span class="pill">SELECT</span>.</p>
|
||||
<table class="data compact">
|
||||
<tr><th>Kelompok</th><th>Nama tabel</th></tr>
|
||||
<tr><td>Tarif dan layanan</td><td class="mono">adm_periode, harga_layanan_diskon, layanandepartemen, masterlayanan, jenislayanan, periode_tarif, perusahaan_grouptarif, perusahaan_tarif, perusahaan</td></tr>
|
||||
<tr><td>Master rumah sakit</td><td class="mono">departemen, dokter, rs, kelas, satuan, satuanlab, shiftharian</td></tr>
|
||||
<tr><td>Master paket</td><td class="mono">paket_adm, paket_item, paket_operasi_header, paket_tt, paket_dispenser_operasi_header</td></tr>
|
||||
<tr><td>Master operasi dan referensi</td><td class="mono">golonganoperasi, jenisanestesi, kasusoperasi, mastertindakan, konversisatuan, margin_alkes, margin_obat, sys_setting</td></tr>
|
||||
<tr><td>Master laboratorium</td><td class="mono">grouplayanan, lab_jenisspesimen, lab_masterlayanan, lab_multiple, lab_reference, lab_spesimentest, lab_trxlayanan_setup, trxlayananlaboratorium, trxlayanan_proses</td></tr>
|
||||
<tr><td>Master pasien/registrasi</td><td class="mono">jenispaket, jenispasien, jenisreg</td></tr>
|
||||
<tr><td>Metadata MySQL</td><td class="mono">information_schema.tables, information_schema.columns</td></tr>
|
||||
</table>
|
||||
|
||||
<h2>4. Tabel dinamis</h2>
|
||||
<table class="data compact">
|
||||
<tr><th>Pola nama tabel</th><th>Kebutuhan akses</th></tr>
|
||||
<tr><td class="mono">harga_layanan_{PeriodeTarifID}</td><td>SELECT. Contoh: <span class="mono">harga_layanan_10</span>. Dipakai untuk membaca tarif layanan berdasarkan periode tarif.</td></tr>
|
||||
<tr><td class="mono">perusahaan_tarif_layanan_{GroupTarifID}</td><td>SELECT. Dipakai untuk membaca detail tarif kerja sama berdasarkan group tarif.</td></tr>
|
||||
</table>
|
||||
|
||||
<h2>5. Rekomendasi grant</h2>
|
||||
<p>Untuk koneksi service, berikan privilege secara eksplisit pada database HIS. Gunakan nama database dan host user sesuai lingkungan server.</p>
|
||||
<pre>-- Ganti nama_database_his, cpone, dan host_user sesuai environment.
|
||||
GRANT SELECT ON `nama_database_his`.`adm_periode` TO 'cpone'@'host_user';
|
||||
|
||||
-- Contoh tabel yang membutuhkan write:
|
||||
GRANT SELECT, INSERT ON `nama_database_his`.`medrec` TO 'cpone'@'host_user';
|
||||
GRANT SELECT, INSERT ON `nama_database_his`.`regpas` TO 'cpone'@'host_user';
|
||||
GRANT SELECT, INSERT, UPDATE ON `nama_database_his`.`regpas_nominal` TO 'cpone'@'host_user';
|
||||
GRANT SELECT, INSERT, UPDATE ON `nama_database_his`.`trxdepartemen_nominal` TO 'cpone'@'host_user';
|
||||
GRANT SELECT, INSERT, UPDATE, DELETE ON `nama_database_his`.`paket_header` TO 'cpone'@'host_user';
|
||||
|
||||
-- Ulangi pola di atas untuk seluruh tabel pada daftar dokumen ini.
|
||||
-- Tabel dinamis memerlukan SELECT pada setiap tabel yang benar-benar digunakan.</pre>
|
||||
|
||||
<h2>6. Catatan penting</h2>
|
||||
<ul>
|
||||
<li>Service hanya membuka koneksi ke database HIS melalui konfigurasi <span class="mono">CPONE_DB_*</span>.</li>
|
||||
<li>Privilege <span class="mono">DELETE</span> pada <span class="mono">paket_header</span>, <span class="mono">paket_layanan</span>, dan <span class="mono">paket_departemen</span> diperlukan untuk cleanup jika proses pembuatan paket gagal sebagian.</li>
|
||||
<li><span class="mono">regpas_nominal</span> dibuat saat registrasi laboratorium untuk inisialisasi nominal administrasi dengan nilai awal nol dan metode <span class="mono">Otomatis</span>.</li>
|
||||
<li>Tabel <span class="mono">hospitals</span> dan <span class="mono">hospital_databases</span> pada migration <span class="mono">cpone_middleware</span> belum digunakan oleh runtime Go service saat ini.</li>
|
||||
<li>Daftar ini dipetakan dari kode aplikasi; validasi final tetap perlu disesuaikan dengan struktur tabel dan policy keamanan database HIS.</li>
|
||||
</ul>
|
||||
|
||||
<div class="footer">Dokumen internal • Sumber pemetaan: repository CPONE Middleware • Versi berdasarkan kode yang tersedia pada 17 September 2026</div>
|
||||
</body>
|
||||
</html>
|
||||
209
docs/build_akses_docx.py
Normal file
209
docs/build_akses_docx.py
Normal file
@@ -0,0 +1,209 @@
|
||||
from zipfile import ZipFile, ZIP_DEFLATED
|
||||
from xml.sax.saxutils import escape
|
||||
from pathlib import Path
|
||||
|
||||
OUT = Path(__file__).with_name("akses-tabel-cpone-middleware.docx")
|
||||
|
||||
W = "http://schemas.openxmlformats.org/wordprocessingml/2006/main"
|
||||
R = "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
|
||||
CT = "http://schemas.openxmlformats.org/package/2006/content-types"
|
||||
PR = "http://schemas.openxmlformats.org/package/2006/relationships"
|
||||
|
||||
def qn(tag):
|
||||
prefix, local = tag.split(":", 1)
|
||||
return f"{{{ {'w': W, 'r': R, 'ct': CT, 'pr': PR}[prefix] }}}{local}"
|
||||
|
||||
def attr(name, value):
|
||||
return f' {name}="{escape(str(value))}"'
|
||||
|
||||
def run(text, bold=False, color=None, size=21, font="Calibri", italic=False):
|
||||
rpr = [f'<w:rFonts w:ascii="{font}" w:hAnsi="{font}"/>', f'<w:sz w:val="{size}"/>', f'<w:szCs w:val="{size}"/>']
|
||||
if bold:
|
||||
rpr.append('<w:b/><w:bCs/>')
|
||||
if italic:
|
||||
rpr.append('<w:i/><w:iCs/>')
|
||||
if color:
|
||||
rpr.append(f'<w:color w:val="{color}"/>')
|
||||
return f'<w:r><w:rPr>{"".join(rpr)}</w:rPr><w:t xml:space="preserve">{escape(text)}</w:t></w:r>'
|
||||
|
||||
def paragraph(text="", style="Normal", before=0, after=120, color=None, bold=False, size=21, align=None, keep=False, page_break=False):
|
||||
ppr = [f'<w:pStyle w:val="{style}"/>', f'<w:spacing w:before="{before}" w:after="{after}" w:line="300" w:lineRule="auto"/>']
|
||||
if align:
|
||||
ppr.append(f'<w:jc w:val="{align}"/>')
|
||||
if keep:
|
||||
ppr.append('<w:keepNext/>')
|
||||
if page_break:
|
||||
ppr.append('<w:pageBreakBefore/>')
|
||||
body = run(text, bold=bold, color=color, size=size) if text else ''
|
||||
return f'<w:p><w:pPr>{"".join(ppr)}</w:pPr>{body}</w:p>'
|
||||
|
||||
def code_paragraph(text, before=80, after=160):
|
||||
ppr = [
|
||||
'<w:pStyle w:val="CodeBlock"/>',
|
||||
f'<w:spacing w:before="{before}" w:after="{after}" w:line="240" w:lineRule="auto"/>',
|
||||
]
|
||||
content = []
|
||||
for index, line in enumerate(text.splitlines()):
|
||||
if index:
|
||||
content.append('<w:br/>')
|
||||
content.append(run(line, size=16, font="Consolas"))
|
||||
return f'<w:p><w:pPr>{"".join(ppr)}</w:pPr>{"".join(content)}</w:p>'
|
||||
|
||||
def rich_paragraph(parts, style="Normal", before=0, after=120, align=None):
|
||||
ppr = [f'<w:pStyle w:val="{style}"/>', f'<w:spacing w:before="{before}" w:after="{after}" w:line="300" w:lineRule="auto"/>']
|
||||
if align:
|
||||
ppr.append(f'<w:jc w:val="{align}"/>')
|
||||
content = ''.join(run(text, bold=bold, color=color, size=size) for text, bold, color, size in parts)
|
||||
return f'<w:p><w:pPr>{"".join(ppr)}</w:pPr>{content}</w:p>'
|
||||
|
||||
def cell(text, width, header=False, align="left"):
|
||||
fill = 'E8EEF5' if header else 'FFFFFF'
|
||||
color = '0B2545' if header else '1F2937'
|
||||
size = 18 if header else 18
|
||||
tcpr = f'<w:tcW w:w="{width}" w:type="dxa"/><w:shd w:fill="{fill}"/><w:vAlign w:val="center"/>'
|
||||
ppr = f'<w:jc w:val="{align}"/><w:spacing w:before="0" w:after="0" w:line="240" w:lineRule="auto"/>'
|
||||
text_xml = run(text, bold=header, color=color, size=size, font="Consolas" if (not header and ("_" in text or "{" in text or "}" in text)) else "Calibri")
|
||||
return f'<w:tc><w:tcPr>{tcpr}</w:tcPr><w:p><w:pPr>{ppr}</w:pPr>{text_xml}</w:p></w:tc>'
|
||||
|
||||
def table(headers, rows, widths, aligns=None):
|
||||
aligns = aligns or ["left"] * len(widths)
|
||||
grid = ''.join(f'<w:gridCol w:w="{w}"/>' for w in widths)
|
||||
borders = '<w:tblBorders><w:top w:val="single" w:sz="6" w:color="AEB DCD"/><w:left w:val="single" w:sz="6" w:color="AEBDCD"/><w:bottom w:val="single" w:sz="6" w:color="AEBDCD"/><w:right w:val="single" w:sz="6" w:color="AEBDCD"/><w:insideH w:val="single" w:sz="4" w:color="CBD5E1"/><w:insideV w:val="single" w:sz="4" w:color="CBD5E1"/></w:tblBorders>'
|
||||
borders = borders.replace("AEB DCD", "AEBDCD")
|
||||
cellmar = '<w:tblCellMar><w:top w:w="80" w:type="dxa"/><w:left w:w="120" w:type="dxa"/><w:bottom w:w="80" w:type="dxa"/><w:right w:w="120" w:type="dxa"/></w:tblCellMar>'
|
||||
tblpr = f'<w:tblW w:w="9360" w:type="dxa"/><w:tblInd w:w="120" w:type="dxa"/><w:tblLayout w:type="fixed"/>{borders}{cellmar}'
|
||||
head = '<w:tr><w:trPr><w:tblHeader/></w:trPr>' + ''.join(cell(h, w, True, aligns[i]) for i, (h, w) in enumerate(zip(headers, widths))) + '</w:tr>'
|
||||
body = ''.join('<w:tr>' + ''.join(cell(str(value), w, False, aligns[i]) for i, (value, w) in enumerate(zip(row, widths))) + '</w:tr>' for row in rows)
|
||||
return f'<w:tbl><w:tblPr>{tblpr}</w:tblPr><w:tblGrid>{grid}</w:tblGrid>{head}{body}</w:tbl>'
|
||||
|
||||
def bullet(text):
|
||||
return '<w:p><w:pPr><w:pStyle w:val="Normal"/><w:numPr><w:ilvl w:val="0"/><w:numId w:val="1"/></w:numPr><w:spacing w:after="80" w:line="300" w:lineRule="auto"/></w:pPr>' + run(text, size=20) + '</w:p>'
|
||||
|
||||
body = []
|
||||
body.append(paragraph("CPONE MIDDLEWARE • DATABASE ACCESS REFERENCE", color="2E74B5", bold=True, size=16, after=100))
|
||||
body.append(paragraph("Daftar Akses Tabel", style="DocTitle", size=48, color="0B2545", after=80))
|
||||
body.append(paragraph("Kebutuhan privilege database untuk service CPONE Middleware", color="475569", size=24, after=220))
|
||||
body.append(table(["Informasi", "Nilai"], [
|
||||
("Database target", "Database HIS pada CPONE_DB_DATABASE"),
|
||||
("Database user", "User pada CPONE_DB_USERNAME"),
|
||||
("Dasar pemetaan", "Query SQL pada folder internal/repository"),
|
||||
("Tanggal", "17 September 2026"),
|
||||
], [1900, 7460], ["left", "left"]))
|
||||
body.append(rich_paragraph([("Ringkasan: ", True, "0B2545", 20), ("service membutuhkan SELECT pada tabel master dan tabel transaksi yang dibaca. Akses write hanya diperlukan pada tabel yang digunakan endpoint POST untuk membuat paket, pasien, registrasi, layanan laboratorium, nominal, dan diagnosis.", False, "1F2937", 20)], after=180))
|
||||
|
||||
body.append(paragraph("1. Tabel dengan READ dan WRITE", style="Heading1", before=260, after=100, keep=True))
|
||||
body.append(paragraph("Tabel berikut membutuhkan SELECT dan operasi write seperti tercantum.", after=100))
|
||||
body.append(table(["Nama tabel", "READ", "WRITE", "Kegunaan utama"], [
|
||||
("medrec", "SELECT", "INSERT", "Pencarian dan pembuatan data pasien/medical record."),
|
||||
("regpas", "SELECT", "INSERT", "Pembuatan dan pengecekan registrasi pasien."),
|
||||
("regpas_nominal", "SELECT", "INSERT, UPDATE", "Nominal administrasi pada level registrasi pasien."),
|
||||
("trxdepartemen", "SELECT", "INSERT", "Pembuatan transaksi departemen."),
|
||||
("trxdepartemen_nominal", "SELECT", "INSERT, UPDATE", "Rekap nominal layanan/item/tempat tidur dan total transaksi."),
|
||||
("trxidlaboratorium", "SELECT", "INSERT", "Pembuatan nomor/transaksi laboratorium."),
|
||||
("trxlayanan", "SELECT", "INSERT", "Penambahan layanan pada transaksi."),
|
||||
("trxlayanan_detail", "SELECT", "INSERT", "Relasi detail layanan dengan paket dispenser."),
|
||||
("trxlayanan_penunjang", "SELECT", "INSERT", "Relasi layanan penunjang/header laboratorium."),
|
||||
("lab_trxspesimen", "SELECT", "INSERT", "Pencatatan spesimen laboratorium."),
|
||||
("paket_header", "SELECT", "INSERT, UPDATE, DELETE", "Pembuatan paket; DELETE hanya untuk cleanup saat transaksi gagal."),
|
||||
("paket_layanan", "SELECT", "INSERT, DELETE", "Detail layanan paket; DELETE hanya untuk cleanup."),
|
||||
("paket_departemen", "SELECT", "INSERT, DELETE", "Departemen terkait paket; DELETE hanya untuk cleanup."),
|
||||
("paket_dispenser_header", "SELECT", "INSERT", "Header paket dispenser pada kunjungan pasien."),
|
||||
("paket_dispenser_episode_rj", "SELECT", "INSERT", "Episode kunjungan rawat jalan paket dispenser."),
|
||||
("paket_dispenser_layanan", "SELECT", "INSERT", "Layanan yang dihasilkan dari paket dispenser."),
|
||||
("paket_dispenser_item", "SELECT", "INSERT", "Item paket dispenser."),
|
||||
("paket_dispenser_adm", "SELECT", "INSERT", "Administrasi paket dispenser."),
|
||||
], [2600, 1000, 1600, 4160], ["left", "center", "center", "left"]))
|
||||
|
||||
body.append(paragraph("2. Tabel dengan WRITE saja", style="Heading1", before=260, after=100, keep=True))
|
||||
body.append(table(["Nama tabel", "Operasi dan kegunaan"], [
|
||||
("diagnosa_log", "INSERT — log diagnosis kerja pada registrasi laboratorium."),
|
||||
("regpas_diagnosa", "INSERT — diagnosis kerja yang terkait dengan pasien/registrasi."),
|
||||
], [2600, 6760], ["left", "left"]))
|
||||
body.append(paragraph("Kedua tabel ini tidak dibaca kembali oleh service dalam query saat ini, tetapi harus dapat menerima INSERT ketika endpoint registrasi laboratorium menyimpan diagnosis.", color="475569", size=18, after=100))
|
||||
|
||||
body.append(paragraph("3. Tabel dengan READ saja", style="Heading1", before=260, after=100, keep=True))
|
||||
body.append(paragraph("Tabel master dan referensi berikut hanya dibaca oleh service, sehingga cukup diberikan privilege SELECT.", after=100))
|
||||
body.append(table(["Kelompok", "Nama tabel"], [
|
||||
("Tarif dan layanan", "adm_periode, harga_layanan_diskon, layanandepartemen, masterlayanan, jenislayanan, periode_tarif, perusahaan_grouptarif, perusahaan_tarif, perusahaan"),
|
||||
("Master rumah sakit", "departemen, dokter, rs, kelas, satuan, satuanlab, shiftharian"),
|
||||
("Master paket", "paket_adm, paket_item, paket_operasi_header, paket_tt, paket_dispenser_operasi_header"),
|
||||
("Master operasi dan referensi", "golonganoperasi, jenisanestesi, kasusoperasi, mastertindakan, konversisatuan, margin_alkes, margin_obat, sys_setting"),
|
||||
("Master laboratorium", "grouplayanan, lab_jenisspesimen, lab_masterlayanan, lab_multiple, lab_reference, lab_spesimentest, lab_trxlayanan_setup, trxlayananlaboratorium, trxlayanan_proses"),
|
||||
("Master pasien/registrasi", "jenispaket, jenispasien, jenisreg"),
|
||||
("Metadata MySQL", "information_schema.tables, information_schema.columns"),
|
||||
], [2500, 6860], ["left", "left"]))
|
||||
|
||||
body.append(paragraph("4. Tabel dinamis", style="Heading1", before=260, after=100, keep=True))
|
||||
body.append(table(["Pola nama tabel", "Kebutuhan akses"], [
|
||||
("harga_layanan_{PeriodeTarifID}", "SELECT. Contoh: harga_layanan_10. Dipakai untuk membaca tarif layanan berdasarkan periode tarif."),
|
||||
("perusahaan_tarif_layanan_{GroupTarifID}", "SELECT. Dipakai untuk membaca detail tarif kerja sama berdasarkan group tarif."),
|
||||
], [3000, 6360], ["left", "left"]))
|
||||
|
||||
body.append(paragraph("5. Rekomendasi grant", style="Heading1", before=260, after=100, keep=True))
|
||||
body.append(paragraph("Berikan privilege secara eksplisit pada database HIS. Ganti nama database, user, dan host sesuai environment server.", after=100))
|
||||
grant_text = """-- Ganti nama_database_his, cpone, dan host_user sesuai environment.
|
||||
GRANT SELECT ON `nama_database_his`.`adm_periode` TO 'cpone'@'host_user';
|
||||
|
||||
-- Contoh tabel yang membutuhkan write:
|
||||
GRANT SELECT, INSERT ON `nama_database_his`.`medrec` TO 'cpone'@'host_user';
|
||||
GRANT SELECT, INSERT ON `nama_database_his`.`regpas` TO 'cpone'@'host_user';
|
||||
GRANT SELECT, INSERT, UPDATE ON `nama_database_his`.`regpas_nominal` TO 'cpone'@'host_user';
|
||||
GRANT SELECT, INSERT, UPDATE ON `nama_database_his`.`trxdepartemen_nominal` TO 'cpone'@'host_user';
|
||||
GRANT SELECT, INSERT, UPDATE, DELETE ON `nama_database_his`.`paket_header` TO 'cpone'@'host_user';
|
||||
|
||||
-- Ulangi pola di atas untuk seluruh tabel pada daftar ini.
|
||||
-- Tabel dinamis memerlukan SELECT pada setiap tabel yang benar-benar digunakan."""
|
||||
body.append(code_paragraph(grant_text))
|
||||
|
||||
body.append(paragraph("6. Catatan penting", style="Heading1", before=260, after=100, keep=True))
|
||||
for item in [
|
||||
"Service hanya membuka koneksi ke database HIS melalui konfigurasi CPONE_DB_*.",
|
||||
"Privilege DELETE pada paket_header, paket_layanan, dan paket_departemen diperlukan untuk cleanup jika proses pembuatan paket gagal sebagian.",
|
||||
"regpas_nominal dibuat saat registrasi laboratorium untuk inisialisasi nominal administrasi dengan nilai awal nol dan metode Otomatis.",
|
||||
"Tabel hospitals dan hospital_databases pada migration cpone_middleware belum digunakan oleh runtime Go service saat ini.",
|
||||
"Daftar ini dipetakan dari kode aplikasi; validasi final tetap perlu disesuaikan dengan struktur tabel dan policy keamanan database HIS.",
|
||||
]:
|
||||
body.append(bullet(item))
|
||||
|
||||
body.append(paragraph("Dokumen internal • Sumber pemetaan: repository CPONE Middleware • Versi berdasarkan kode yang tersedia pada 17 September 2026", color="64748B", size=16, before=240, after=0))
|
||||
|
||||
document = f'''<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<w:document xmlns:w="{W}" xmlns:r="{R}"><w:body>{''.join(body)}<w:sectPr><w:headerReference w:type="default" r:id="rId4"/><w:footerReference w:type="default" r:id="rId3"/><w:pgSz w:w="12240" w:h="15840"/><w:pgMar w:top="1440" w:right="1440" w:bottom="1440" w:left="1440" w:header="708" w:footer="708"/><w:cols w:space="708"/><w:docGrid w:linePitch="360"/></w:sectPr></w:body></w:document>'''
|
||||
|
||||
styles = f'''<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<w:styles xmlns:w="{W}">
|
||||
<w:docDefaults><w:rPrDefault><w:rPr><w:rFonts w:ascii="Calibri" w:hAnsi="Calibri"/><w:sz w:val="21"/><w:szCs w:val="21"/><w:color w:val="1F2937"/></w:rPr></w:rPrDefault><w:pPrDefault><w:pPr><w:spacing w:after="120" w:line="300" w:lineRule="auto"/></w:pPr></w:pPrDefault></w:docDefaults>
|
||||
<w:style w:type="paragraph" w:default="1" w:styleId="Normal"><w:name w:val="Normal"/><w:qFormat/><w:rPr><w:rFonts w:ascii="Calibri" w:hAnsi="Calibri"/><w:sz w:val="21"/><w:szCs w:val="21"/><w:color w:val="1F2937"/></w:rPr></w:style>
|
||||
<w:style w:type="paragraph" w:styleId="DocTitle"><w:name w:val="Document Title"/><w:qFormat/><w:pPr><w:spacing w:before="0" w:after="80" w:line="300" w:lineRule="auto"/></w:pPr><w:rPr><w:rFonts w:ascii="Calibri" w:hAnsi="Calibri"/><w:sz w:val="48"/><w:szCs w:val="48"/><w:b/><w:color w:val="0B2545"/></w:rPr></w:style>
|
||||
<w:style w:type="paragraph" w:styleId="Heading1"><w:name w:val="heading 1"/><w:basedOn w:val="Normal"/><w:next w:val="Normal"/><w:qFormat/><w:pPr><w:keepNext/><w:spacing w:before="360" w:after="200" w:line="300" w:lineRule="auto"/></w:pPr><w:rPr><w:rFonts w:ascii="Calibri" w:hAnsi="Calibri"/><w:sz w:val="32"/><w:szCs w:val="32"/><w:b/><w:color w:val="2E74B5"/></w:rPr></w:style>
|
||||
<w:style w:type="paragraph" w:styleId="CodeBlock"><w:name w:val="Code Block"/><w:basedOn w:val="Normal"/><w:pPr><w:shd w:fill="F4F6F9"/><w:spacing w:before="80" w:after="160" w:line="240" w:lineRule="auto"/></w:pPr><w:rPr><w:rFonts w:ascii="Consolas" w:hAnsi="Consolas"/><w:sz w:val="16"/><w:szCs w:val="16"/><w:color w:val="111827"/></w:rPr></w:style>
|
||||
<w:style w:type="character" w:styleId="DefaultParagraphFont"><w:name w:val="Default Paragraph Font"/><w:uiPriority w:val="1"/><w:semiHidden/></w:style>
|
||||
</w:styles>'''
|
||||
|
||||
numbering = f'''<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<w:numbering xmlns:w="{W}"><w:abstractNum w:abstractNumId="0"><w:multiLevelType w:val="hybridMultilevel"/><w:lvl w:ilvl="0"><w:start w:val="1"/><w:numFmt w:val="bullet"/><w:lvlText w:val="•"/><w:lvlJc w:val="left"/><w:pPr><w:tabs><w:tab w:val="num" w:pos="540"/></w:tabs><w:ind w:left="540" w:hanging="270"/></w:pPr><w:rPr><w:rFonts w:ascii="Symbol" w:hAnsi="Symbol"/></w:rPr></w:lvl></w:abstractNum><w:num w:numId="1"><w:abstractNumId w:val="0"/></w:num></w:numbering>'''
|
||||
|
||||
document_rels = f'''<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<Relationships xmlns="{PR}"><Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" Target="styles.xml"/><Relationship Id="rId2" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering" Target="numbering.xml"/><Relationship Id="rId3" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/footer" Target="footer1.xml"/><Relationship Id="rId4" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/header" Target="header1.xml"/></Relationships>'''
|
||||
|
||||
footer = f'''<?xml version="1.0" encoding="UTF-8" standalone="yes"?><w:ftr xmlns:w="{W}" xmlns:r="{R}"><w:p><w:pPr><w:jc w:val="right"/><w:spacing w:before="0" w:after="0"/></w:pPr>{run("CPONE Middleware • ", color="64748B", size=16)}<w:fldSimple w:instr="PAGE"><w:r><w:rPr><w:sz w:val="16"/></w:rPr><w:t>1</w:t></w:r></w:fldSimple></w:p></w:ftr>'''
|
||||
header = f'''<?xml version="1.0" encoding="UTF-8" standalone="yes"?><w:hdr xmlns:w="{W}"><w:p><w:pPr><w:spacing w:before="0" w:after="0"/></w:pPr>{run("CPONE Middleware | Daftar Akses Tabel", color="64748B", size=16)}</w:p></w:hdr>'''
|
||||
|
||||
content_types = f'''<?xml version="1.0" encoding="UTF-8" standalone="yes"?><Types xmlns="{CT}"><Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/><Default Extension="xml" ContentType="application/xml"/><Override PartName="/word/document.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml"/><Override PartName="/word/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml"/><Override PartName="/word/numbering.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml"/><Override PartName="/word/header1.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.header+xml"/><Override PartName="/word/footer1.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml"/><Override PartName="/docProps/core.xml" ContentType="application/vnd.openxmlformats-package.core-properties+xml"/><Override PartName="/docProps/app.xml" ContentType="application/vnd.openxmlformats-officedocument.extended-properties+xml"/></Types>'''
|
||||
root_rels = f'''<?xml version="1.0" encoding="UTF-8" standalone="yes"?><Relationships xmlns="{PR}"><Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="word/document.xml"/><Relationship Id="rId2" Type="http://schemas.openxmlformats.org/package/2006/metadata/core-properties" Target="docProps/core.xml"/><Relationship Id="rId3" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties" Target="docProps/app.xml"/></Relationships>'''
|
||||
core = f'''<?xml version="1.0" encoding="UTF-8" standalone="yes"?><cp:coreProperties xmlns:cp="http://schemas.openxmlformats.org/package/2006/metadata/core-properties" xmlns:dc="http://purl.org/dc/elements/1.1/"><dc:title>Daftar Akses Tabel CPONE Middleware</dc:title><dc:creator>CPONE Middleware</dc:creator><dc:subject>Database access reference</dc:subject></cp:coreProperties>'''
|
||||
app = f'''<?xml version="1.0" encoding="UTF-8" standalone="yes"?><Properties xmlns="http://schemas.openxmlformats.org/officeDocument/2006/extended-properties"><Application>CPONE Middleware</Application></Properties>'''
|
||||
|
||||
with ZipFile(OUT, "w", ZIP_DEFLATED) as z:
|
||||
z.writestr("[Content_Types].xml", content_types)
|
||||
z.writestr("_rels/.rels", root_rels)
|
||||
z.writestr("word/document.xml", document)
|
||||
z.writestr("word/styles.xml", styles)
|
||||
z.writestr("word/numbering.xml", numbering)
|
||||
z.writestr("word/header1.xml", header)
|
||||
z.writestr("word/footer1.xml", footer)
|
||||
z.writestr("word/_rels/document.xml.rels", document_rels)
|
||||
z.writestr("docProps/core.xml", core)
|
||||
z.writestr("docProps/app.xml", app)
|
||||
|
||||
print(OUT)
|
||||
1417
docs/lap_mcu.php
Normal file
1417
docs/lap_mcu.php
Normal file
File diff suppressed because it is too large
Load Diff
1258
docs/resume_mcu.php
Normal file
1258
docs/resume_mcu.php
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user