# Risk Register Modul Penjualan

Scope:
- `application/modules/penjualan/controllers/Create.php`
- `application/modules/penjualan/controllers/FollowUp.php`
- Revisi koding dibatasi hanya di modul `penjualan`.
- Tidak melibatkan file di luar modul `penjualan`.

Status:
- Analisis ini masih tahap ngobrol / review awal.
- Belum ada revisi koding.
- Belum membaca semua model dan view modul `penjualan`, jadi temuan di bawah fokus ke controller dan alur transaksi yang terlihat dari dua file ini.

Definisi singkat:
- Risiko persisten: risiko yang cenderung bertahan di session, state UI, atau lock sehingga efeknya bisa terbawa ke request berikutnya.
- Risiko laten: risiko yang tidak langsung meledak di happy path, tetapi muncul ketika ada cabang transaksi, follow-up, revert, mobile flow, atau connector antar cabang.

## Prioritas Eksekusi Tertinggi

Urutan di bawah disusun dari yang paling berbahaya untuk transaksi sampai yang paling struktural.

### P0 - Mutasi session dari GET

- File: `Create.php`
- Titik: `syncPihakMainExecFromRequest()` di sekitar [line 73](z:/san_sarana_staging/application/modules/penjualan/controllers/Create.php#L73) dan `updateMainSession()` di sekitar [line 18067](z:/san_sarana_staging/application/modules/penjualan/controllers/Create.php#L18067)
- Jenis risiko: persisten
- Kenapa berbahaya:
  - GET dipakai untuk mengubah session transaksi.
  - State transaksi bisa berubah hanya karena URL dipanggil ulang, dibuka dari tab lain, atau di-restore browser.
  - Ini membuat transaksi sulit diprediksi karena session menjadi sumber kebenaran yang bisa dipengaruhi request ringan.
- Dampak:
  - salah pihak/cabang yang terbawa ke transaksi berikutnya
  - session nyangkut di state lama
  - preview dan save membaca state yang tidak sinkron

### P0 - `save()` terlalu besar dan terlalu banyak cabang

- File: `Create.php`
- Titik: `save()` di sekitar [line 1444](z:/san_sarana_staging/application/modules/penjualan/controllers/Create.php#L1444)
- Jenis risiko: laten
- Kenapa berbahaya:
  - Alur save panjang, bercabang, dan menulis banyak entitas pendamping.
  - Ada banyak titik perubahan state, bukan satu gate tunggal yang menutup seluruh proses.
  - Jika satu cabang berjalan dan cabang lain tidak, hasil akhir transaksi bisa tidak seragam.
- Dampak:
  - transaksi utama tersimpan tetapi data pendamping tidak lengkap
  - payment source / registry / ext step bisa berbeda antar jalur
  - bug hanya muncul di skenario tertentu, bukan di test sederhana

### P0 - Follow-up action yang mengubah state transaksi

- File: `FollowUp.php`
- Titik: `doFollowup()` di sekitar [line 14241](z:/san_sarana_staging/application/modules/penjualan/controllers/FollowUp.php#L14241), `doRevert()` di sekitar [line 19203](z:/san_sarana_staging/application/modules/penjualan/controllers/FollowUp.php#L19203), dan `doCancelPacking()` di sekitar [line 31920](z:/san_sarana_staging/application/modules/penjualan/controllers/FollowUp.php#L31920)
- Jenis risiko: laten
- Kenapa berbahaya:
  - Tiga aksi ini mengubah state transaksi pada fase yang berbeda.
  - Jika urutan aksi sudah bergeser, revert/cancel dapat bekerja di atas state yang tidak lagi sama dengan asumsi awal.
  - Ini klasik high-risk flow karena efek sampingnya luas.
- Dampak:
  - state transaksi tidak balik sempurna
  - sebagian item sudah berubah tetapi header belum
  - approval / cancel / follow-up saling mengganggu

### P1 - Session dijadikan sumber kebenaran utama untuk preview dan flow berikutnya

- File: `Create.php` dan `FollowUp.php`
- Titik:
  - `Create.php` di sekitar [line 871](z:/san_sarana_staging/application/modules/penjualan/controllers/Create.php#L871)
  - `FollowUp.php` di sekitar [line 11104](z:/san_sarana_staging/application/modules/penjualan/controllers/FollowUp.php#L11104)
- Jenis risiko: persisten
- Kenapa berbahaya:
  - Preview membaca `step_number`, `main`, dan state session sebagai dasar tampilan.
  - Jika session lama belum dibersihkan, user melihat state transaksi yang sudah basi.
  - Ini bukan sekadar UI issue, karena preview biasanya menjadi gerbang sebelum save/follow-up.
- Dampak:
  - user mengira data valid padahal state sudah berubah
  - transaksi salah langkah
  - validasi visual tidak lagi dipercaya

### P1 - Banyak endpoint mobile yang menulis state yang sama

- File: `FollowUp.php`
- Titik:
  - `doScan()` di sekitar [line 5676](z:/san_sarana_staging/application/modules/penjualan/controllers/FollowUp.php#L5676)
  - `doDeleteMobile()` di sekitar [line 7553](z:/san_sarana_staging/application/modules/penjualan/controllers/FollowUp.php#L7553)
  - `doReloadSesi()` di sekitar [line 7602](z:/san_sarana_staging/application/modules/penjualan/controllers/FollowUp.php#L7602)
- Jenis risiko: persisten
- Kenapa berbahaya:
  - Beberapa endpoint bisa menyentuh state sesi / transaksi yang sama.
  - Kalau satu endpoint gagal di tengah, endpoint berikutnya bisa melanjutkan state yang tidak bersih.
  - Mobile flow biasanya lebih rawan retry, refresh, dan request dobel.
- Dampak:
  - duplikasi aksi
  - sesi parsial
  - state transaksi sulit dipulihkan manual

### P1 - Penulisan data pendamping di beberapa cabang

- File: `Create.php`
- Titik:
  - `writeDataRegistries()` di sekitar [line 3979](z:/san_sarana_staging/application/modules/penjualan/controllers/Create.php#L3979)
  - `writePaymentSrc()` di sekitar [line 3745](z:/san_sarana_staging/application/modules/penjualan/controllers/Create.php#L3745), [line 4009](z:/san_sarana_staging/application/modules/penjualan/controllers/Create.php#L4009), [line 7216](z:/san_sarana_staging/application/modules/penjualan/controllers/Create.php#L7216), [line 7977](z:/san_sarana_staging/application/modules/penjualan/controllers/Create.php#L7977)
  - `writeExtStep()` di sekitar [line 4061](z:/san_sarana_staging/application/modules/penjualan/controllers/Create.php#L4061), [line 10836](z:/san_sarana_staging/application/modules/penjualan/controllers/Create.php#L10836), [line 16081](z:/san_sarana_staging/application/modules/penjualan/controllers/Create.php#L16081)
- Jenis risiko: laten
- Kenapa berbahaya:
  - Data transaksi utama dan data pendamping tidak ditulis pada satu jalur tunggal.
  - Ada potensi satu entitas tersimpan, entitas lain belum, atau tertulis dua kali.
  - Ini bisa lolos dari pengujian sederhana karena hanya muncul di kombinasi langkah tertentu.
- Dampak:
  - payment source tidak lengkap
  - registry tidak sinkron dengan transaksi
  - ext step dobel atau hilang

### P1 - Commit / cleanup session tidak terlihat seragam di semua entry point

- File: `Create.php` dan `FollowUp.php`
- Titik:
  - `Create.php` punya beberapa jalur commit dan cleanup session, tetapi tidak terlihat sebagai pola tunggal
  - `FollowUp.php` juga punya banyak aksi yang menutup transaksi dan membersihkan locker/session di titik berbeda
- Jenis risiko: persisten
- Kenapa berbahaya:
  - Jika cleanup hanya dilakukan di sebagian jalur, session bisa tertinggal dalam kondisi lama.
  - State lama ini biasanya baru terasa saat user buka transaksi berikutnya.
- Dampak:
  - stale session
  - salah nomor / salah step / salah relasi
  - transaksi baru mewarisi residu transaksi lama

### P2 - Connector / cabang antar transaksi memperbanyak state turunan

- File: `Create.php`
- Titik:
  - alur `connectTo` dan cloning session / item di berbagai bagian `save()`
- Jenis risiko: laten
- Kenapa berbahaya:
  - Connector membuat satu transaksi utama menghasilkan transaksi turunan.
  - Kalau state awal tidak bersih, state turunan ikut tercemar.
  - Kalau clone dilakukan dari session yang sudah parsial, hasil cabang berikutnya makin sulit ditebak.
- Dampak:
  - transaksi cabang tidak sama dengan transaksi asal
  - numbering / step / detail bisa beda
  - problem lintas cabang sulit dilacak

### P2 - Validasi tampak tersebar, bukan satu pintu 3-way matching

- File: `Create.php` dan `FollowUp.php`
- Titik:
  - preview, save, follow-up, revert, cancel, mobile actions
- Jenis risiko: laten
- Kenapa berbahaya:
  - Tidak terlihat satu pintu tunggal yang selalu membandingkan input user, session state, dan database state sebelum aksi lanjut.
  - Kalau salah satu sumber tidak sinkron, proses masih bisa lanjut di jalur tertentu.
- Dampak:
  - transaksi lolos walau state tidak sinkron
  - mismatch input vs session vs database
  - validasi jadi tergantung cabang yang kebetulan dipakai

### P2 - Endpoint yang terlihat administratif tetapi menyentuh state transaksi

- File: `Create.php`
- Titik:
  - `updateMainSession()` di [line 18067](z:/san_sarana_staging/application/modules/penjualan/controllers/Create.php#L18067)
- Jenis risiko: persisten
- Kenapa berbahaya:
  - Endpoint yang kelihatannya hanya helper/UI ternyata dapat mengubah state transaksi.
  - Ini memperbesar permukaan serangan logika dan kebingungan debugging.
- Dampak:
  - perubahan state tanpa jejak transaksi yang jelas
  - sulit dibedakan mana aksi user, mana helper UI

### P2 - Mobile flow rawan retry dan request dobel

- File: `FollowUp.php`
- Titik:
  - `doScan()`, `doDeleteMobile()`, `doReloadSesi()`
- Jenis risiko: laten
- Kenapa berbahaya:
  - Mobile flow biasanya lebih gampang retry karena jaringan atau refresh.
  - Kalau endpoint tidak idempotent, request kedua bisa mengulang aksi yang sama.
- Dampak:
  - item terhapus dua kali
  - scan dobel
  - session reload menggeser state

### P3 - Risiko observabilitas rendah

- File: `Create.php` dan `FollowUp.php`
- Jenis risiko: laten
- Kenapa berbahaya:
  - Alur sangat panjang dan bercabang, sehingga kalau ada bug, akar masalahnya tidak mudah dilihat dari satu log.
  - Banyak aksi memakai session, GET, dan helper internal.
- Dampak:
  - debugging lambat
  - perbaikan sering hanya menambal gejala

## Ringkasan Per File

### Create.php

Karakter risiko dominan:
- persisten, karena session sangat kuat sebagai state transaksi
- laten, karena `save()` dan cabang connector menulis banyak data pendamping

Risiko paling kritis:
1. Mutasi session dari GET
2. `save()` yang terlalu besar
3. penulisan data pendamping di banyak cabang
4. state preview bergantung pada session lama
5. connector / cloning yang memperbanyak state turunan

### FollowUp.php

Karakter risiko dominan:
- persisten, karena banyak endpoint mobile dan utility yang menyentuh state transaksi
- laten, karena follow-up / revert / cancel packing adalah aksi transisi state yang sensitif

Risiko paling kritis:
1. doFollowup / doRevert / doCancelPacking
2. session yang dipakai ulang di preview dan flow lanjutan
3. endpoint mobile yang memperbanyak perubahan state
4. cleanup locker/session yang tidak seragam
5. kemungkinan request dobel atau replay di flow mobile

## Kesimpulan Praktis

Kalau tujuan kita adalah mengurangi risiko paling besar tanpa langsung refactor besar-besaran, prioritas review berikutnya sebaiknya:
- cek semua titik mutasi session dari GET
- cek semua jalur commit dan cleanup session
- cek semua write pendamping di `save()`
- cek semua jalur follow-up, revert, dan cancel packing
- cek konsistensi antara input user, session, dan database sebelum transaksi lanjut

## Catatan Lanjutan

Dokumen ini dibuat dari pembacaan controller saja.
Kalau nanti kita baca model dan view yang dipakai dua controller ini, daftar risikonya kemungkinan akan bertambah, terutama di bagian:
- query builder / lookup transaksi
- helper yang menyusun session
- view yang memicu request tersembunyi

## Checklist Revisi Koding

Checklist ini disusun supaya tim bisa langsung pakai saat mulai revisi. Urutannya dibuat dari yang paling aman dikerjakan dulu sampai ke area yang lebih besar.

### Batas Scope Revisi

- [ ] Semua perubahan harus tetap berada di dalam modul `penjualan`.
- [ ] Jangan menambah file baru di luar modul `penjualan`.
- [ ] Jangan memindahkan logic ke helper/library global di luar modul jika tidak benar-benar wajib.
- [ ] Jika ada logic bersama yang dipakai ulang, letakkan tetap dalam struktur modul `penjualan`.
- [ ] Pastikan review dan testing hanya mengacu ke file-file dalam modul `penjualan`.

### A. Guard dan Validasi Inti

- [ ] Tambahkan satu fungsi guard terpusat untuk validasi konteks transaksi sebelum aksi penting dijalankan.
- [ ] Pastikan guard membandingkan minimal tiga sumber: input user, session transaksi, dan state database.
- [ ] Jika hasil pembanding tidak sinkron, hentikan proses dengan status `VOID` atau `INDETERMINATE`.
- [ ] Terapkan guard yang sama di `Create.php` dan `FollowUp.php`, jangan dibuat beda per controller.
- [ ] Pastikan GET tetap dipakai sebagai input, tetapi tidak boleh langsung mengubah state tanpa validasi.

### B. Perbaikan Prioritas Tinggi di `Create.php`

- [ ] Audit semua fungsi yang menulis ke `$_SESSION` dari parameter `$_GET`.
- [ ] Batasi `syncPihakMainExecFromRequest()` agar hanya menerima nilai yang sah dan tervalidasi.
- [ ] Refactor `updateMainSession()` supaya tidak langsung menulis session dari `$_GET["id"]` tanpa pengecekan konteks.
- [ ] Buat mekanisme reset session transaksi yang konsisten setelah transaksi sukses atau gagal.
- [ ] Pastikan `preview()` hanya membaca state yang sudah lolos validasi, bukan state session mentah.
- [ ] Pecah `save()` menjadi fase yang jelas: validasi, finalisasi numbering, write master, write detail, write pendamping, cleanup.
- [ ] Pastikan `writeDataRegistries()`, `writePaymentSrc()`, dan `writeExtStep()` tidak menulis dobel saat request diulang.
- [ ] Tambahkan pengecekan idempotent sebelum insert data pendamping.
- [ ] Pastikan connector atau cloning antar cabang memakai state yang sudah bersih.

### C. Perbaikan Prioritas Tinggi di `FollowUp.php`

- [ ] Audit semua action yang mengubah state transaksi: `doFollowup()`, `doRevert()`, `doCancelPacking()`.
- [ ] Tambahkan validasi state awal dan state tujuan sebelum transition dijalankan.
- [ ] Pastikan revert hanya bisa berjalan jika state transaksi masih memenuhi prasyarat yang sama dengan asumsi awal.
- [ ] Pastikan cancel packing tidak bisa menimpa state yang sudah berubah oleh follow-up lain.
- [ ] Tambahkan validasi locker / ownership sebelum action mobile dijalankan.
- [ ] Audit `doScan()`, `doDeleteMobile()`, dan `doReloadSesi()` agar tidak menimbulkan request dobel atau replay.
- [ ] Pastikan endpoint mobile bersifat idempotent atau setidaknya aman jika dipanggil berulang.
- [ ] Pastikan session dan locker dibersihkan konsisten setelah aksi sukses maupun gagal.

### D. Konsistensi Transaction Boundary

- [ ] Pastikan semua aksi krusial dibungkus transaction boundary yang jelas.
- [ ] Pastikan `trans_start()` dan `trans_complete()` tidak dipakai tanpa pemeriksaan hasil akhir.
- [ ] Setelah commit gagal, hentikan alur dan jangan lanjut ke cleanup parsial yang bisa menutupi error.
- [ ] Setelah commit sukses, hapus session transaksi yang relevan secara lengkap.
- [ ] Pastikan tidak ada jalur yang menulis sebagian data lalu keluar tanpa rollback yang jelas.

### E. Standardisasi State dan Naming

- [ ] Konsolidasikan key session yang dipakai oleh `Create.php` dan `FollowUp.php`.
- [ ] Hindari penambahan key session baru tanpa daftar resmi supaya tidak muncul state liar.
- [ ] Kelompokkan state transaksi ke dalam struktur yang konsisten: `main`, `items`, `tableIn_*`, `revert`, `locker`.
- [ ] Pastikan nilai default untuk key penting selalu eksplisit dan menggunakan `array()` untuk kompatibilitas PHP 5.6.
- [ ] Hindari syntax PHP 7+ / 8+ di seluruh revisi.

### F. Logging dan Audit

- [ ] Tambahkan log khusus untuk state transition penting.
- [ ] Catat input user, session state, dan state database sebelum aksi dijalankan.
- [ ] Catat hasil akhir setelah aksi selesai, termasuk status commit dan cleanup session.
- [ ] Tambahkan log yang mudah dicari saat terjadi mismatch 3-way matching.
- [ ] Pastikan log tidak hanya menyimpan “gagal” atau “sukses”, tetapi juga alasan kegagalan.

### G. Pengujian Wajib

- [ ] Uji skenario GET yang mengubah konteks transaksi.
- [ ] Uji transaksi normal dari awal sampai commit.
- [ ] Uji refresh halaman sebelum save.
- [ ] Uji buka transaksi dari dua tab browser.
- [ ] Uji follow-up lalu revert.
- [ ] Uji cancel packing setelah state sebagian berubah.
- [ ] Uji flow mobile: scan, reload, delete, dan retry request.
- [ ] Uji konektor antar cabang jika transaksi memakai `connectTo`.
- [ ] Uji kondisi session lama yang belum dibersihkan.
- [ ] Uji skenario mismatch antara input user, session, dan database.

### H. Kriteria Selesai

- [ ] Tidak ada action krusial yang lolos tanpa 3-way matching.
- [ ] Tidak ada mutasi session dari GET yang berjalan tanpa guard.
- [ ] Tidak ada data pendamping yang dobel insert saat request diulang.
- [ ] Tidak ada session transaksi yang tertinggal setelah commit atau rollback.
- [ ] Tidak ada jalur follow-up / revert / cancel packing yang bisa jalan pada state yang salah.
- [ ] Hasil revisi tetap kompatibel dengan PHP 5.6 dan CodeIgniter 3.

### I. Urutan Eksekusi Yang Disarankan

1. Pasang guard 3-way matching.
2. Kunci mutasi session dari GET.
3. Rapikan cleanup session dan locker.
4. Pecah `save()` menjadi fase yang lebih kecil.
5. Jadikan data pendamping idempotent.
6. Tegaskan state transition di `FollowUp.php`.
7. Jalankan pengujian ulang untuk refresh, retry, mobile, dan multi-tab.

### J. Progress Implementasi Awal

- [x] `Create.php` sudah dibatasi untuk mutasi session dari GET yang tervalidasi.
- [x] `FollowUp.php` sudah mendapat guard konteks transaksi untuk `doFollowup()`, `doRevert()`, dan `doCancelPacking()`.
- [x] Flow mobile di `FollowUp.php` sudah diberi validasi dasar untuk scan, delete, dan reload sesi.
- [x] Preflight awal `save()` di `Create.php` sudah dipindah ke helper `validateSavePreflightContext()`.
- [x] Cleanup dan feedback sukses setelah commit `save()` sudah dipindah ke helper terpisah.
- [x] Helper feedback sukses sudah diberi fallback aman jika config step tidak ditemukan.
- [x] Cleanup booking number sebelum commit `save()` sudah dipindah ke helper terpisah.
- [x] Output akhir `save()` sudah dialihkan ke helper `emitSaveSuccessOutput()`.
- [x] Dead block lama setelah output `save()` sudah dinetralkan agar tidak ikut dibaca sebagai alur aktif.
- [x] Write registries pertama di `save()` sudah dipindah ke helper `persistSaveDataRegistries()`.
- [x] Write registries di jalur connector/save lanjutan sudah ikut memakai helper yang sama.
- [x] Payment source standar di `save()` sudah mulai dipindah ke helper `persistSavePaymentSource()` pada jalur insert reguler dan connector.
- [x] Cabang payment source dengan payload khusus yang memakai `_key` dan `main_inputs` juga sudah dipindah ke helper dengan override nilai yang setara.
- [x] Beberapa cabang payment source tambahan yang masih seragam sudah ikut memakai helper yang sama.
- [x] Dua cabang `arrPymSrc` terakhir yang berisi override field tambahan juga sudah dipindah ke helper yang sama.
- [x] `writeExtStep()` di `Create.php` juga sudah dipusatkan lewat helper `persistSaveExtStep()` agar penulisan data pendamping lebih seragam.
- [x] Eksekusi model `Com*` yang berulang di cabang `save()` sudah dipusatkan lewat helper `executeSaveComponentProcessor()`.
- [x] Fase finalisasi nomor dan identitas master di awal `save()` sudah dipindah ke helper `finalizeSaveMasterIdentity()`.
- [x] Fase payload detail tambahan di `save()` sudah dipindah ke helper `persistSaveDetailAuxPayloads()`.
- [x] Fase detail utama di `save()` sudah dipindah ke helper `persistSaveDetailMainPayloads()`.
- [x] Fase registry fisik dan turunan item di `save()` sudah dipindah ke helper `persistSavePhysicalRegistryPayloads()`.
- [x] Fase `main_inputs` yang memicu payment source dan ext step sudah dipindah ke helper `persistSaveMainInputPayloads()`.
- [x] Jalur gagal untuk fase save yang baru dipisah sudah memakai helper `abortSaveTransaction()` agar rollback dan cleanup tidak tercecer.
- [x] Tiga cabang duplicate payment source di `save()` yang masih memakai `matiHEre()` sudah diarahkan ke `abortSaveTransaction()` supaya rollback konsisten.
- [x] Validasi `extern_label2` pada cabang payment source `save()` juga sudah diarahkan ke rollback terpusat saat data tidak valid.
- [x] Cabang post-processor, registry write failure, dan connectToStep debug-stop di `save()` sudah dibersihkan dari hard-stop tersembunyi.
- [x] `save()` sekarang punya shutdown rollback guard supaya hard-stop explicit yang tersisa tetap memicu rollback dan cleanup.
- [x] Blok akhir `save()` untuk commit, cleanup session, dan output sukses sudah dipindah ke helper `finalizeSaveCommitFlow()`.
- [x] Bootstrap awal `save()` sudah dipindah ke helper `prepareSaveBootstrapContext()` agar setup awal tidak menumpuk di controller.
- [x] `save()` di `Create.php` sudah jauh dipisah; sisa tinggal verifikasi lint, konsistensi, dan pengecekan cabang lain bila diperlukan.
- [ ] Data pendamping seperti `writePaymentSrc()` dan `writeExtStep()` masih perlu dijadikan idempotent penuh.
- [ ] Cleanup session dan locker masih perlu dirapikan dan diseragamkan di semua jalur commit/fail.

### K. Rekomendasi Pecah `save()` Menjadi Fase Kecil

Tujuan pemecahan ini bukan mengubah perilaku bisnis, tetapi membuat alur save lebih mudah diaudit, lebih aman terhadap retry, dan lebih jelas saat terjadi mismatch data.

Prinsip yang harus dijaga:
- `GET` tetap `GET`.
- Semua revisi tetap di modul `penjualan`.
- Tidak pindah ke model umum `MdlTransaksi` atau `MdlMother`.
- Tetap kompatibel dengan PHP 5.6, jadi gunakan `array()` dan pola CI3 biasa.
- Setiap fase harus bisa gagal dengan alasan yang jelas, bukan gagal diam-diam.

#### 1. Fase preflight / guard konteks

Target fungsi bantu:
- `guardSaveTransactionContext()`
- `resolveSaveSessionContext()`
- `validateSaveAgainstDbState()`

Tugas fase ini:
- baca input request yang relevan dari `$_GET`
- baca session transaksi yang sedang aktif
- baca state database minimum yang dibutuhkan untuk memastikan transaksi masih layak dilanjutkan
- lakukan 3-way matching antara input user, session, dan database
- tolak proses jika salah satu sumber tidak sinkron atau masih `INDETERMINATE`

Output yang diharapkan:
- status boleh lanjut atau tidak
- konteks transaksi yang sudah dinormalisasi
- pesan error yang bisa langsung dipakai user / log

#### 2. Fase finalisasi nomor dan identitas transaksi

Target fungsi bantu:
- `prepareSaveTransactionHeader()`
- `finalizeSaveNumbering()`
- `resolveSaveMainIds()`

Tugas fase ini:
- pastikan nomor transaksi, step, dan referensi utama sudah pasti
- pastikan tidak ada perubahan numbering setelah fase ini lewat
- pisahkan identitas transaksi utama dari data turunan

Catatan risiko:
- fase ini harus selesai sebelum insert data detail atau data pendamping
- kalau numbering gagal, proses harus berhenti sebelum mutasi lain berjalan

#### 3. Fase simpan header / master

Target fungsi bantu:
- `writeSaveMaster()`
- `prepareMasterPayload()`

Tugas fase ini:
- susun payload header transaksi
- simpan baris master terlebih dahulu
- pastikan ID hasil insert valid sebelum lanjut ke detail

Aturan penting:
- jangan campur insert master dengan write data pendamping
- jangan lanjut ke detail kalau master belum valid

#### 4. Fase simpan detail inti

Target fungsi bantu:
- `writeSaveDetails()`
- `prepareDetailPayloads()`
- `persistSingleDetailRow()`

Tugas fase ini:
- simpan item / detail transaksi
- validasi ulang setiap detail yang kritis sebelum insert
- jika ada satu detail gagal, seluruh transaksi harus tetap punya jalur rollback yang jelas

Yang perlu dijaga:
- urutan detail tidak berubah sembarangan
- data hasil clone / connector tidak boleh ikut bocor ke item lain

#### 5. Fase simpan data pendamping

Target fungsi bantu:
- `writeSaveRegistries()`
- `writeSavePaymentSource()`
- `writeSaveExtStep()`
- `writeSaveSignature()`
- `prepareAncillaryPayloads()`

Tugas fase ini:
- simpan registry transaksi
- simpan payment source
- simpan ext step
- simpan signature atau jejak legalisasi bila memang diperlukan jalur transaksi

Aturan penting:
- data pendamping harus diperlakukan idempotent sejauh mungkin
- kalau request diulang, jangan sampai payload yang sama menulis dobel
- semua write pendamping harus bisa dilacak dari ID master yang sama

#### 6. Fase validasi hasil akhir

Target fungsi bantu:
- `validateSaveWriteResult()`
- `verifySaveConsistency()`

Tugas fase ini:
- cocokkan apakah master, detail, dan pendamping benar-benar terbentuk
- cocokkan hasil insert dengan state session akhir
- pastikan tidak ada mismatch antara apa yang ditulis dan apa yang dianggap sukses

Ini adalah lapisan kedua dari 3-way matching:
- input user
- session transaksi
- database hasil insert

#### 7. Fase commit dan cleanup

Target fungsi bantu:
- `commitSaveTransaction()`
- `cleanupSaveSessionState()`
- `resetSaveRuntimeLocks()`

Tugas fase ini:
- commit hanya jika semua fase sebelumnya berhasil
- bersihkan session yang sudah dipakai transaksi
- reset locker / helper state yang menempel ke request sebelumnya

Aturan penting:
- cleanup tidak boleh menutupi error sebelumnya
- kalau commit gagal, proses harus berhenti dengan status yang jelas

#### 8. Fase rollback / failure handling

Target fungsi bantu:
- `rollbackSaveTransaction()`
- `reportSaveFailure()`
- `buildSaveFailureResponse()`

Tugas fase ini:
- rollback seluruh transaksi jika ada kegagalan di tengah
- simpan alasan kegagalan dalam log yang mudah dicari
- pastikan response gagal tidak meninggalkan session setengah jadi

#### Urutan Eksekusi Yang Disarankan

Urutan implementasi yang paling aman:
1. Pisahkan guard konteks transaksi.
2. Pisahkan finalisasi numbering.
3. Pisahkan write master.
4. Pisahkan write detail.
5. Pisahkan write data pendamping.
6. Pisahkan commit dan cleanup.
7. Tambahkan rollback/failure handler yang eksplisit.
8. Baru setelah itu rapikan idempotensi data pendamping.

#### Mapping Risiko ke Refactor

- Risiko session dari GET berkurang kalau guard ditempatkan di awal `save()`.
- Risiko save terlalu besar berkurang kalau setiap fase punya fungsi bantu sendiri.
- Risiko data pendamping dobel berkurang kalau write registry/payment/ext step dipisah dan dicek idempotent.
- Risiko transaksi parsial berkurang kalau commit dan cleanup dipisah dari write phase.
- Risiko mismatch input-session-db berkurang kalau 3-way matching dijadikan pintu awal yang wajib.

#### Checklist Teknis untuk Tim

- [ ] Buat satu entry guard yang selalu dipanggil sebelum save lanjut.
- [ ] Pecah `save()` dari blok terbesar menjadi fungsi bantu yang kecil dan spesifik.
- [ ] Pastikan setiap fungsi bantu menerima parameter eksplisit, bukan membaca state global terlalu banyak.
- [ ] Pastikan hasil setiap fase divalidasi sebelum masuk fase berikutnya.
- [ ] Pastikan helper baru tetap berada di `Create.php` atau struktur modul `penjualan`.
- [ ] Pastikan tidak ada perubahan perilaku bisnis yang tidak disengaja saat refactor.
- [x] Tambahkan verifikasi konsistensi hasil save sebelum commit, dengan sumber minimal input user, session, dan database.
- [ ] Satukan cleanup session dan locker ke satu jalur sukses dan satu jalur gagal agar tidak ada state tertinggal.
- [ ] Inventarisasi cabang `save()` yang masih panjang dan tandai mana yang aman dipindah ke helper baru.

### L. Checkpoint Lanjutan

Checkpoint per `2026-06-13`:
- Selesai: `Create.php` sudah dipilah untuk helper bootstrap, payment source, ext step, main_inputs, master identity, payload detail tambahan, detail utama, registry fisik, rollback/failure, commit, dan cleanup akhir.
- Selesai: `save()` utama sudah terurai jauh; sisa fokus sekarang ada pada lint/syntax final dan review cabang lain yang masih panjang bila tim ingin lanjut.
- Selesai: Duplicate payment source yang tadinya hard-stop via `matiHEre()` sudah dipindah ke rollback terpusat `abortSaveTransaction()` di tiga cabang `save()`.
- Selesai: Validasi input payment source yang bergantung pada `extern_label2` juga sudah memakai rollback terpusat saat data tidak lolos validasi.
- Selesai: Cabang debug-stop aktif di post-processor, write-registry failure, dan connectToStep di `save()` sudah dibersihkan.
- Selesai: Guard shutdown rollback pada `save()` menutup risiko hard-stop explicit `or die()` yang masih tersisa sebelum commit sukses.
- Selesai: Eksekusi `Com*` pada cabang `save()` sudah mulai dipusatkan lewat helper agar blok inline lebih pendek dan lebih konsisten.
- Sebagian selesai: `writePaymentSrc()` dan `writeExtStep()` sudah lebih terpusat, tetapi idempotensi penuh masih perlu dibenahi.
- Selesai: Enam cabang prioritas 1 untuk pola `pair(0, $tmpOutParams[$cCtr])` sudah dipindah ke helper pre-processor terpusat.
- Sebagian selesai: Prioritas 2 untuk pola `pair($masterID, $tmpOutParams[$cCtr])` sudah mulai dipindah ke helper yang sama dan masih perlu verifikasi sisa cabang.
- Selesai untuk cabang aktif: blok komponen berulang yang masih memakai `pair()` / `exec()` langsung sudah dipusatkan ke helper.
- Catatan: sisa `pair()` / `exec()` yang masih terlihat sekarang hanya komentar lama dan tidak ikut alur aktif.
- Scope kerja tetap aman di modul `penjualan` saja, tanpa perubahan file di luar modul.

Status kerja saat ini:
1. Prioritas 1 sudah selesai.
2. Prioritas 2 sudah selesai untuk cabang aktif; sisa yang terlihat sekarang hanya jejak komentar lama.
3. Prioritas 3 untuk cabang aktif sudah selesai.
4. Selesai: validasi konsistensi sebelum commit save sudah dipasang sebagai guard terpusat.
5. Selesai: komentar lama yang masih menampilkan `pair()/exec()` di jalur aktif sudah dibersihkan.
6. Selesai: cleanup session dan locker pada jalur save sukses, gagal, dan shutdown guard sudah diseragamkan.
7. Sisa pekerjaan tinggal audit cabang lain yang masih panjang bila tim ingin refactor penuh.

#### Fokus Kerja Berikutnya

1. Audit cabang `save()` yang masih panjang.
   - Cari cabang inline yang masih banyak `pair()` / `exec()` / write pendamping.
   - Tandai cabang yang masih aman ditunda dan cabang yang perlu dipindah ke helper dulu.
2. Jadikan blok pre-processor sebagai kandidat refactor berikutnya.
   - Beberapa blok masih memakai `pair()` / `exec()` langsung di dalam loop komponen.
   - Pola yang paling sering muncul ada di area sebelum finalisasi master dan sebelum write pendamping utama.

#### Checkpoint Handoff

Checkpoint kerja terakhir:
- `save()` di `Create.php` sudah terurai ke helper untuk bootstrap, finalisasi identitas, detail, registry, payment source, ext step, commit, rollback, dan cleanup.
- Guard konsistensi sebelum commit sudah aktif.
- Cleanup locker dan session sudah diseragamkan di jalur sukses, gagal, dan shutdown guard.
- Cabang prioritas 1, prioritas 2, dan prioritas 3 yang aktif sudah dipindah ke helper terpusat.
- Sisa `pair()/exec()` yang masih terlihat di file aktif sudah dibersihkan atau tinggal komentar lama.

Yang masih terbuka:
- Audit cabang `save()` lain yang masih panjang kalau tim ingin refactor penuh.
- Verifikasi manual akhir untuk memastikan helper baru tidak mengubah perilaku bisnis.
- Lint/syntax check di environment runtime yang lebih lengkap karena CLI di sesi ini belum bisa membuka file workspace.

Urutan lanjut paling aman:
1. Review cabang save lain yang belum disentuh.
2. Cari cabang yang masih punya write pendamping atau commit boundary tambahan.
3. Baru lanjut jika memang diperlukan ke penyederhanaan helper lebih lanjut.

- [ ] Pastikan seluruh refactor tetap aman untuk PHP 5.6 dan CI3.

#### Audit Sisa `save()`

Hasil audit teknis sementara:
- Blok post-processor yang paling sering diulang sudah mulai terpusat lewat `executeSaveComponentProcessor()`.
- Sisa paling berisiko sekarang ada di blok pre-processor yang masih inline dan masih punya `or die()` langsung.
- Jalur yang paling layak dipecah berikutnya adalah pola komponen pre-processor yang memakai `pair(0, ...)`, `pair($masterID, ...)`, dan `exec()` berulang.

Urutan kandidat refactor berikutnya:
1. Pre-processor berbasis `pair(0, $tmpOutParams[$cCtr])`.
2. Pre-processor berbasis `pair($masterID, $tmpOutParams[$cCtr])`.
3. Blok komponen berulang yang masih melakukan `pair()` / `exec()` langsung tanpa helper seragam.

#### Checklist Refactor Per Blok

1. `Pre-processor pair(0, ...)`
   - Pindahkan logika pasangan input ke helper kecil yang hanya menerima parameter eksplisit.
   - Pertahankan urutan data masuk dan keluar agar tidak mengubah hasil bisnis.
   - Pastikan kalau `exec()` gagal, rollback tetap lewat jalur terpusat.
   - Jadikan helper ini seragam untuk semua cabang yang memanggil pola `pair(0, ...)`.
2. `Pre-processor pair($masterID, ...)`
   - Pecah langkah persiapan `masterID` dari langkah eksekusi komponen.
   - Hindari akses langsung ke state global di dalam helper baru.
   - Pastikan nilai `masterID` divalidasi sebelum dipakai di loop berikutnya.
   - Samakan format error message agar audit cabang lebih mudah dilacak.
3. `Komponen berulang`
   - Gabungkan blok `pair()` / `exec()` yang polanya sama ke satu helper yang konsisten.
   - Bedakan data tunggal dan data array secara eksplisit supaya tidak tertukar.
   - Jangan gabungkan logika debug dengan logika transaksi utama.
   - Pastikan helper baru tidak mengubah cabang yang memang punya perlakuan khusus.
4. `Write pendamping`
   - Audit `writePaymentSrc()` dan `writeExtStep()` untuk memastikan hasilnya idempotent.
   - Tambahkan pengecekan sebelum insert agar request ulang tidak menulis dobel.
   - Pastikan validasi pendamping tetap memakai sumber data yang sama dengan master transaksi.
   - Jika data tidak sinkron, hentikan proses sebelum commit.
5. `Commit dan cleanup`
   - Satukan semua cleanup session ke satu helper yang dipanggil hanya dari jalur sukses atau rollback.
   - Pastikan locker dan session tidak tertinggal setelah transisi selesai.
   - Jangan biarkan cleanup menutupi error yang lebih dulu terjadi.
   - Verifikasi hasil akhir dengan 3-way matching sebelum `trans_complete()`.

#### Urutan Prioritas Pecah Pre-processor

Prioritas di bawah disusun dari yang paling aman dipindah dulu sampai yang paling besar efeknya ke alur transaksi.

1. `pair(0, $tmpOutParams[$cCtr])`
   - Ini prioritas pertama karena polanya paling seragam dan paling mudah dijadikan helper bersama.
   - Risiko bisnisnya lebih kecil dibanding cabang yang sudah tergantung pada `masterID`.
   - Cocok untuk memvalidasi apakah helper baru bisa menjaga urutan input-output tanpa mengubah hasil.
2. `pair($masterID, $tmpOutParams[$cCtr])`
   - Ini masuk setelah helper dasar stabil.
   - Cabang ini lebih sensitif karena sudah menempel ke identitas transaksi yang aktif.
   - Setelah `pair(0, ...)` aman, pola ini bisa dipindah dengan risiko lebih terkontrol.
3. Cabang komponen berulang dengan `pair()` / `exec()` langsung
   - Ini prioritas terakhir karena biasanya lebih banyak variasi dan perlakuan khusus.
   - Setelah dua pola pertama stabil, cabang ini bisa dipecah dengan acuan helper yang sudah ada.
   - Cocok untuk membersihkan sisa inline yang masih menumpuk di blok panjang.
4. Cabang yang masih punya `or die()` langsung di dalam loop
   - Ini jangan dikerjakan dulu kalau pola helper inti belum stabil.
   - Biasanya lebih aman dibersihkan setelah struktur helper komponen sudah mapan.
   - Prioritaskan hanya kalau cabangnya ikut menyentuh rollback / transaksi utama.

#### Cabang Prioritas 1 di `Create.php`

Daftar berikut adalah cabang yang paling cocok dijadikan target awal untuk pola `pair(0, $tmpOutParams[$cCtr])`:

- [x] Blok pre-processor sekitar [Create.php](z:/san_sarana_staging/application/modules/penjualan/controllers/Create.php#L2715)
- [x] Blok pre-processor sekitar [Create.php](z:/san_sarana_staging/application/modules/penjualan/controllers/Create.php#L3059)
- [x] Blok pre-processor sekitar [Create.php](z:/san_sarana_staging/application/modules/penjualan/controllers/Create.php#L9819)
- [x] Blok pre-processor sekitar [Create.php](z:/san_sarana_staging/application/modules/penjualan/controllers/Create.php#L9955)
- [x] Blok pre-processor sekitar [Create.php](z:/san_sarana_staging/application/modules/penjualan/controllers/Create.php#L14941)
- [x] Blok pre-processor sekitar [Create.php](z:/san_sarana_staging/application/modules/penjualan/controllers/Create.php#L15059)

Catatan:
- Enam titik di atas adalah kandidat prioritas 1 karena polanya seragam dan paling dekat dengan helper dasar.
- Kalau saat review manual ternyata ada cabang lain yang juga memakai `pair(0, ...)`, masukkan ke kelompok ini sebelum menyentuh `pair($masterID, ...)`.
- Cabang yang sudah memakai `executeSaveComponentProcessor()` tidak masuk prioritas 1 ini karena statusnya sudah lebih terpusat.

#### Prioritas 2 Masih Perlu Verifikasi

Titik kandidat yang sempat perlu dicek ulang untuk pola `pair($masterID, $tmpOutParams[$cCtr])`:

- [x] Blok pre-processor sekitar [Create.php](z:/san_sarana_staging/application/modules/penjualan/controllers/Create.php#L11605)
- [x] Blok pre-processor sekitar [Create.php](z:/san_sarana_staging/application/modules/penjualan/controllers/Create.php#L11747)
- [x] Blok pre-processor sekitar [Create.php](z:/san_sarana_staging/application/modules/penjualan/controllers/Create.php#L11889)

Catatan:
- Tiga titik ini sekarang sudah masuk helper pre-processor terpusat.
- Kalau masih ada blok lain dengan pola yang sama, tambahkan ke daftar ini sebelum lanjut ke komponen berulang.

- [x] Blok komponen berulang aktif yang masih memakai `pair()` / `exec()` langsung sudah dipusatkan ke helper.
- [ ] Sisa `pair()` / `exec()` yang masih terlihat sekarang hanya komentar lama dan tidak ikut alur aktif.
