Skip to content

Master ke multisite#368

Closed
basoro wants to merge 10 commits into
multisitefrom
master
Closed

Master ke multisite#368
basoro wants to merge 10 commits into
multisitefrom
master

Conversation

@basoro
Copy link
Copy Markdown
Owner

@basoro basoro commented May 27, 2026

Summary by Sourcery

Enhance financial reporting, cashier, and letter management modules with improved period handling, summaries, printing/exports, and safer schema defaults.

New Features:

  • Allow filtering and viewing opening balances by arbitrary year in the financial Rekening Tahun screen.
  • Add per-account and cross-account opening/closing balance rows and summary totals to the Buku Besar report and print view, including an optional closing balance display toggle.
  • Introduce a more accurate cash flow calculation by deriving cash movements from journals involving cash accounts and aggregating inflows/outflows by activity type and account.
  • Rework balance sheet calculations to base opening balances on yearly Rekening Tahun plus pre-period mutations and display current-period profit/loss as a separate equity line.
  • Add dummy financial data seeding for activity accounts and track inserted/updated Rekening Tahun and activity mappings with detailed notifications.
  • Provide a printable letterhead (kop) for the outpatient cashier report and a brand-new Rekap Shift Kasir screen with on-page totals, print-friendly header, and CSV export.
  • Expose print actions in referral, sick, and healthy letter management lists and pass prebuilt print URLs from the controller with safe pagination handling.

Bug Fixes:

  • Correct BPJS EMR device table definitions and migrations to use proper identifier quoting, nullable manufacture/expiration dates, and simplified utf8mb4 collation, keeping schema consistent between install and upgrade paths.
  • Fix indentation and HTML non‑breaking space handling for compounded drug ingredients in inpatient and outpatient cashier views so they render correctly in HTML.
  • Ensure outpatient cashier report templates receive settings data required for printing the institutional header.
  • Hide the e‑Signature button on printed sick letters and fix pagination data being lost when sanitizing surat listing payloads.

Enhancements:

  • Improve Buku Besar sorting, account metadata selection, and reporting of running balances, including support for multi-account views.
  • Refine balance sheet profit/loss computation to use net credit minus debit without relying on account balance flags.
  • Keep the financial year filter and report filters stable across normal and print views, including passing through kd_rek and saldo akhir flags.
  • Adjust DEV_MODE configuration to be unconditionally enabled for easier development and debugging.

basoro added 10 commits May 24, 2026 10:07
update three instances across both inpatient and outpatient kasir plugin admin files to use str_repeat for non-breaking space indentation instead of hardcoded HTML   sequences, improving maintainability and compatibility
- Add year filter for rekening tahun annual account management page
- Rework buku besar general ledger report: add conditional akun column, saldo normal column, opening/closing balance rows, summary statistics, and toggle to show final balances
- Fix buku besar print view to pass all required parameters and include summary data
- Simplify periode display logic for general ledger print view
- Improve cash flow statement calculation and allocation logic
- Update balance sheet calculations to use annual opening balances from rekeningtahun table
- Add new akun kegiatan dummy data and improved dummy data handling
update the database upgrade script to set manufacture_date and expiration_date columns for mlite_bpjs_emr_device as nullable with default null, and fix SQL syntax by using backticks instead of single quotes for column names
Add print URL generation for health and referral certificates in the backend admin controller, add print action buttons to their respective management tables, fix trailing newlines in template files, and update print styling in the sick certificate view to hide the e-signature button alongside save and print buttons when printing.
…puts

Add new menu entry for shift recap report
Add new shift recap report page with date range filtering
Implement CSV export for shift report data
Update existing cashier report to include institution branding header when printing
Pass site settings to all report templates for dynamic header content
Refactor print JavaScript function to reuse the institution header template
@sourcery-ai
Copy link
Copy Markdown
Contributor

sourcery-ai Bot commented May 27, 2026

Reviewer's Guide

Enhances keuangan reporting (Buku Besar, Cash Flow, Neraca) with year filtering, saldo awal/akhir correctness and summaries, improves dummy data seeding, adds shift recap reporting and printable headers for kasir reports, fixes several schema/upgrade issues, and improves surat listing/printing UX while enabling dev mode explicitly.

Sequence diagram for enhanced Buku Besar generation with saldo awal/akhir and summary

sequenceDiagram
    participant AdminKeuangan as Admin_keuangan
    participant DB as Database
    participant Template as Template_engine

    AdminKeuangan->>AdminKeuangan: getBukuBesar()
    AdminKeuangan->>AdminKeuangan: read $_GET[tgl_awal], $_GET[tgl_akhir], $_GET[kd_rek], $_GET[show_saldo_akhir]
    AdminKeuangan->>AdminKeuangan: build $sql (detailjurnal + rekening + jurnal)
    AdminKeuangan->>DB: db()->pdo()->prepare($sql)
    AdminKeuangan->>DB: execute($params)
    DB-->>AdminKeuangan: $rows = fetchAll(\PDO::FETCH_ASSOC)

    alt kd_rek is set
        AdminKeuangan->>DB: db('mlite_rekeningtahun')->where('thn',$tahun)->where('kd_rek',$kd_rek)->oneArray()
        DB-->>AdminKeuangan: $saldoAwalRow
        AdminKeuangan->>DB: db('mlite_rekening')->where('kd_rek',$kd_rek)->oneArray()
        DB-->>AdminKeuangan: $rekeningRow (nm_rek, balance)
        AdminKeuangan->>DB: db()->pdo()->prepare($sqlMutasi)
        AdminKeuangan->>DB: execute([$kd_rek,$awalTahun,$tgl_awal])
        DB-->>AdminKeuangan: $mutasi
        AdminKeuangan->>AdminKeuangan: hitung saldo awal + mutasi
        AdminKeuangan->>AdminKeuangan: loop $rows, hitung saldo, saldo_normal, saldo_sisi
        AdminKeuangan->>AdminKeuangan: optionally append row "Saldo akhir"
        AdminKeuangan->>AdminKeuangan: isi summary (total_debet, total_kredit, saldo_akhir_*)
    else kd_rek kosong (semua rekening)
        AdminKeuangan->>DB: db('mlite_rekeningtahun')->where('thn',$tahun)->toArray()
        DB-->>AdminKeuangan: $saldoAwalRows
        AdminKeuangan->>DB: db()->pdo()->prepare($sqlMutasiAll)
        AdminKeuangan->>DB: execute([$awalTahun,$tgl_awal])
        DB-->>AdminKeuangan: mutasi per kd_rek
        AdminKeuangan->>AdminKeuangan: kelompokkan $rows by kd_rek
        AdminKeuangan->>AdminKeuangan: untuk tiap kd_rek: saldo awal + mutasi, loop transaksi
        AdminKeuangan->>AdminKeuangan: optionally append "Saldo akhir" per kd_rek
        AdminKeuangan->>AdminKeuangan: akumulasi summary (rekening_count, total_debet, total_kredit, saldo_akhir_d/k, saldo_akhir_net)
    end

    AdminKeuangan->>DB: db('mlite_rekening')->toArray()
    DB-->>AdminKeuangan: $akunrekening

    alt action == 'print'
        AdminKeuangan->>Template: draw('buku.besar.print.html', bukubesar, kd_rek_filter, show_saldo_akhir, summary)
        Template-->>AdminKeuangan: HTML
        AdminKeuangan->>AdminKeuangan: echo HTML and exit
    else tampilan normal
        AdminKeuangan->>Template: draw('buku.besar.html', bukubesar, akunrekening, kd_rek_filter, show_saldo_akhir, tgl_awal, tgl_akhir, summary)
        Template-->>AdminKeuangan: HTML
    end
Loading

Sequence diagram for new kasir rawat jalan shift recap reporting

sequenceDiagram
    actor Admin as Admin_user
    participant KasirRJ as KasirRawatJalan_Admin
    participant DB as Database
    participant Template as Template_engine

    Admin->>KasirRJ: GET anyShiftReport(awal, akhir)
    KasirRJ->>KasirRJ: _addHeaderFiles()
    KasirRJ->>KasirRJ: tentukan $awal, $akhir (default hari ini)
    KasirRJ->>DB: db()->pdo()->prepare(SELECT ... FROM mlite_kasir_shift ...)
    KasirRJ->>DB: execute([$awal,$akhir,$awal,$akhir,$awal,$akhir])
    DB-->>KasirRJ: $rows = fetchAll(\PDO::FETCH_ASSOC)
    KasirRJ->>KasirRJ: $settings = settings('settings')
    KasirRJ->>Template: draw('shift.report.html', awal, akhir, rows, settings)
    Template-->>KasirRJ: HTML
    KasirRJ-->>Admin: halaman Rekap Shift Kasir

    Admin->>KasirRJ: GET anyShiftReportExport(awal, akhir)
    KasirRJ->>DB: db()->pdo()->prepare(SELECT ... FROM mlite_kasir_shift ...)
    KasirRJ->>DB: execute([$awal,$akhir,$awal,$akhir,$awal,$akhir])
    DB-->>KasirRJ: cursor rows
    KasirRJ->>KasirRJ: header('Content-Type: text/csv')
    KasirRJ->>KasirRJ: echo CSV header
    KasirRJ->>KasirRJ: loop fetch(\PDO::FETCH_ASSOC) echo baris CSV
    KasirRJ-->>Admin: file rekap_shift_kasir.csv untuk diunduh
Loading

File-Level Changes

Change Details Files
Add year filtering and richer saldo/summary logic to Buku Besar plus UI support.
  • Use validated ?tahun parameter in getRekeningTahun and pass tahun_filter to the template; add year filter form in rekening.tahun.html.
  • Extend getBukuBesar SQL to include kd_rek/nm_rek and different ordering when kd_rek is empty, and compute saldo awal, running saldo, saldo sisi/normal per-row, with separate logic for single-account vs all-account views.
  • Introduce summary aggregation for total debet/kredit and saldo akhir (per account and net), controlled by show_saldo_akhir query flag and passed to both HTML and print templates.
  • Update buku.besar*.html to include akun column when no filter, show saldo normal, visually distinguish saldo_awal/saldo_akhir rows, persist filters in Print link, add summary block, and prevent dropdown menu clicks from closing the filter prematurely.
plugins/keuangan/Admin.php
plugins/keuangan/view/admin/rekening.tahun.html
plugins/keuangan/view/admin/buku.besar.html
plugins/keuangan/view/admin/buku.besar.print.html
Rework Cash Flow computation to be cash-ledger-consistent and Neraca to use opening balances + period movements correctly.
  • Refactor getCashFlow to first compute opening cash balance for the cash account set via parameterized IN list, then derive cash-related journals, group them by no_jurnal, and distribute cash inflow/outflow amounts proportionally across non-cash accounts per type (R/N/M).
  • Replace previous per-type SUM queries with in-memory aggregation buckets for masuk/keluar per kd_rek, computing kredit_all/debet_all and totals for each arus kas row, and reuse results for totals.
  • Change getNeraca to take saldo_awal from mlite_rekeningtahun plus movements from beginning-of-year to tgl_awal, and separate mutasi_periode for the requested range before building balances per account class.
  • Simplify laba rugi for modal adjustment to raw kredit-debet sum and explicitly append a synthetic 'Laba/Rugi Periode' row to modal when non-zero.
plugins/keuangan/Admin.php
Improve dummy financial data seeding and add documentation for manual (non-dummy) setup.
  • Introduce akunKegiatan definitions mapped to kd_rek and ensure their rekening are included in requiredRekening set during dummy insert.
  • Track counts of inserted and updated mlite_rekeningtahun rows (only updating saldo_awal when changed) and inserted akun_kegiatan rows, and reflect these in the success notification message.
  • Extend README with a detailed 2026-from-scratch scenario: minimal accounts, Rekening Tahun setup, kegiatan mapping, sample journals, and validation steps for Buku Besar, Neraca, and Cash Flow.
plugins/keuangan/Admin.php
plugins/keuangan/README.md
Add shift recap reporting (HTML/CSV/printable with header) for kasir rawat jalan and improve existing kasir reports.
  • Extend kasir_rawat_jalan navigation with 'Rekap Shift' entry and implement anyShiftReport to query mlite_kasir_shift within a flexible time window and render shift.report.html with settings for header.
  • Implement anyShiftReportExport to export the same shift data to CSV with proper quoting, and add a new shift.report.html view that supports filter form, printable institutional header, per-shift rows and totals, and JS printing/datetimepicker integration.
  • Update kasir_rawat_jalan report.html to prepend a hidden kop_print header and modify printContent to print with header by concatenating kop_print and laporan content.
  • Ensure ingredient lines in rincian/faktur and rawat_inap kasir use non-breaking spaces via str_repeat("\u{00A0}", 4) instead of literal   entities before the dash.
plugins/kasir_rawat_jalan/Admin.php
plugins/kasir_rawat_jalan/view/admin/report.html
plugins/kasir_rawat_jalan/view/admin/shift.report.html
plugins/kasir_rawat_inap/Admin.php
Fix and normalize database schema and upgrade scripts for BPJS EMR device and esignature-related tables across engines.
  • Change mlite_bpjs_emr_device manufacture_date/expiration_date columns in SQL schema and upgrade paths from NOT NULL to DEFAULT NULL for both SQLite (TEXT) and MySQL (DATE), ensuring ALTER TABLE branches align.
  • Remove explicit utf8mb4_0900_ai_ci collations from mlite_esignatures and mlite_sertisign_webhook table DDL in both mlite_db.sql and upgrade.php, using default utf8mb4 with ROW_FORMAT=DYNAMIC instead.
  • Align SQLite/MySQL create/alter DDL variants in upgrade.php with the corrected definitions to avoid mismatches between fresh installs and upgrades.
systems/upgrade.php
mlite_db.sql
Enhance surat management listings with print actions and safe pagination, and adjust surat sakit UI for print-mode behaviour.
  • In surat Admin, add per-row printURL for rujukan, sakit, sehat listings and pass it into the manage templates; ensure pagination key is preserved after htmlspecialchars_array by copying it from the original assign.
  • Update rujukan.manage.html, sakit.manage.html, sehat.manage.html to include a 'Cetak' button targeting the respective print URLs alongside Edit and Hapus actions.
  • Hide the e-Signature button in surat.sakit print media via CSS (adding #signButton to @media print exclusion) so printouts do not include action controls, while still keeping the button functional on screen.
plugins/surat/Admin.php
plugins/surat/view/admin/rujukan.manage.html
plugins/surat/view/admin/sakit.manage.html
plugins/surat/view/admin/sehat.manage.html
plugins/surat/view/admin/surat.sakit.html
Force developer mode on unconditionally.
  • Change DEV_MODE definition to a hardcoded true instead of reading from the DEVMODE environment variable.
config.php

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@vercel
Copy link
Copy Markdown

vercel Bot commented May 27, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
mlite Ready Ready Preview, Comment May 27, 2026 1:08pm
mlite-3isz Ready Ready Preview, Comment May 27, 2026 1:08pm

Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 2 issues, and left some high level feedback:

  • In Admin::getBukuBesar() (branch without kd_rek filter), you perform a separate mlite_rekening query inside the loop for each account; consider preloading all rekening rows into an associative array keyed by kd_rek to avoid N+1 queries and reduce DB load.
  • In plugins/surat/Admin.php for anyRujukan/anySakit/anySehat, rows are passed through htmlspecialchars_array once when building $this->assign['list'] and then again when building $assign for the view, which risks double-escaping; it would be cleaner to escape only once at the boundary to the view.
  • In the DDL for mlite_bpjs_emr_device (both in upgrade.php and mlite_db.sql), the manufacture_date and expiration_date columns are still written with single quotes around the column names; updating these to backticks (like other identifiers) will avoid SQL syntax/compatibility issues across databases.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `Admin::getBukuBesar()` (branch without `kd_rek` filter), you perform a separate `mlite_rekening` query inside the loop for each account; consider preloading all rekening rows into an associative array keyed by `kd_rek` to avoid N+1 queries and reduce DB load.
- In `plugins/surat/Admin.php` for `anyRujukan/anySakit/anySehat`, rows are passed through `htmlspecialchars_array` once when building `$this->assign['list']` and then again when building `$assign` for the view, which risks double-escaping; it would be cleaner to escape only once at the boundary to the view.
- In the DDL for `mlite_bpjs_emr_device` (both in `upgrade.php` and `mlite_db.sql`), the `manufacture_date` and `expiration_date` columns are still written with single quotes around the column names; updating these to backticks (like other identifiers) will avoid SQL syntax/compatibility issues across databases.

## Individual Comments

### Comment 1
<location path="plugins/surat/Admin.php" line_range="82-83" />
<code_context>
         $this->assign['addURL'] = url([ADMIN, 'surat', 'rujukanadd']);
         $this->assign['phrase'] = $phrase;
-        return $this->draw('rujukan.manage.html', ['rujukan' => htmlspecialchars_array($this->assign)]);
+        $assign = htmlspecialchars_array($this->assign);
+        $assign['pagination'] = $this->assign['pagination'];
+        return $this->draw('rujukan.manage.html', ['rujukan' => $assign]);
     }
</code_context>
<issue_to_address>
**issue (bug_risk):** Assignment data is being HTML-escaped twice, which can lead to double-encoded output.

`$this->assign` is escaped twice: once per row via `htmlspecialchars_array($row)` before adding to `$this->assign['list']`, and again when you build `$assign = htmlspecialchars_array($this->assign)`. This will double-encode entities (e.g. `&``&amp;``&amp;amp;`). Please escape only once, either at the final render step or by skipping the second `htmlspecialchars_array` when `$this->assign` is already sanitized.
</issue_to_address>

### Comment 2
<location path="mlite_db.sql" line_range="1654-1655" />
<code_context>
   `manufacturer` VARCHAR(255) DEFAULT NULL,
-  'manufacture_date' DATE NOT NULL, 
-  'expiration_date' DATE NOT NULL, 
+  'manufacture_date' DATE DEFAULT NULL, 
+  'expiration_date' DATE DEFAULT NULL, 
   `model` VARCHAR(255) DEFAULT NULL,
   PRIMARY KEY (`id`),
</code_context>
<issue_to_address>
**issue (bug_risk):** Column identifiers are quoted with single quotes, which are string literals in SQL, not identifier delimiters.

`manufacture_date` and `expiration_date` are written with single quotes (`'manufacture_date'` / `'expiration_date'`), which SQL interprets as string literals rather than column identifiers. This can cause syntax errors or unexpected behavior, depending on SQL mode. Please use identifier quoting (e.g., ``` `manufacture_date` ``` / ``` `expiration_date` ```), or leave them unquoted to match the other columns.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread plugins/surat/Admin.php
Comment on lines +82 to +83
$assign = htmlspecialchars_array($this->assign);
$assign['pagination'] = $this->assign['pagination'];
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): Assignment data is being HTML-escaped twice, which can lead to double-encoded output.

$this->assign is escaped twice: once per row via htmlspecialchars_array($row) before adding to $this->assign['list'], and again when you build $assign = htmlspecialchars_array($this->assign). This will double-encode entities (e.g. &&amp;&amp;amp;). Please escape only once, either at the final render step or by skipping the second htmlspecialchars_array when $this->assign is already sanitized.

Comment thread mlite_db.sql
Comment on lines +1654 to +1655
'manufacture_date' DATE DEFAULT NULL,
'expiration_date' DATE DEFAULT NULL,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): Column identifiers are quoted with single quotes, which are string literals in SQL, not identifier delimiters.

manufacture_date and expiration_date are written with single quotes ('manufacture_date' / 'expiration_date'), which SQL interprets as string literals rather than column identifiers. This can cause syntax errors or unexpected behavior, depending on SQL mode. Please use identifier quoting (e.g., `manufacture_date` / `expiration_date`), or leave them unquoted to match the other columns.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant