# Porting tools dan integrasi pendukung ke CI4

Pembaruan: 16 Oktober 2026.

Seluruh 17 URL `pos/tools/*.php` mempunyai route CI4 GET/POST, termasuk varian `.php`. Implementasi memakai controller, koneksi database, response, dan layout CI4; tidak mengeksekusi file PHP dari folder `pos`.

| Kelompok | Path di bawah `tools/` |
| --- | --- |
| Produk | `import_massal_product`, `update_massal_product` (redirect), `update_status_product` |
| Transaksi | `import_transaksi_pembelian`, `import_transaksi_penjualan` |
| Marketplace | `import_shopee_pesanan`, `import_tiktok_pesanan`, `shopee_pesanan`, `tiktok_pesanan`, `audit_marketplace` |
| Pemeliharaan | `rekonsiliasi_stok`, `perbaiki_harga_snapshot` |
| WhatsApp | `blast_chat`, `whatsapp_messages` |
| Database | `sync_export`, `sync_import` |
| Worker | `cron_shopee_stock_sync` |

Controller berada di `app/Controllers/Tools*`, dengan 14 view di `app/Views/tools`. Template XLSX disalin ke `public/template/`. Helper integrasi yang sudah ada tetap digunakan.

## Perilaku dan pembatasan

- Halaman operasional menggunakan filter `auth`. Koreksi stok dan harga snapshot memerlukan Super Admin toko. Impor dan ekspor seluruh database memerlukan admin sistem; ekspor juga dapat menggunakan secret mesin.
- Pratinjau impor transaksi disimpan per toko **dan pengguna**. Saat apply, produk diperiksa ulang berdasarkan toko, status aktif, jumlah, dan harga. Produk bundle ditolak pada importer transaksi sederhana ini. Setiap invoice memakai transaksi database, penguncian toko, pemeriksaan ulang invoice duplikat, serta rollback bila detail gagal.
- Pilihan menambah/mengurangi stok tetap tersedia. Pergerakan stok menghormati pause produk dan memasukkan antrean Shopee. Importer historis ini tidak merekonstruksi batch FEFO atau snapshot biaya historis; jangan menggunakannya untuk mengarang histori batch yang tidak tersedia.
- Impor produk memakai transaksi per baris, termasuk pembuatan satuan/kategori. Kegagalan insert/update membatalkan pembuatan master terkait dan memulihkan cache mapping lokal.
- Impor marketplace memeriksa marketplace aktif milik toko dan menyimpan perubahan/audit dalam transaksi. Impor pesanan marketplace merupakan data pendukung audit; bukan otomatis membuat transaksi POS.
- Rekonsiliasi menghitung ulang angka di server, mengabaikan `correct_stock`/`fix_stocks` dari browser, dan membatalkan koreksi jika query mutasi gagal. Perhitungan mencakup konversi pembelian, komponen bundle keluar, retur customer kondisi baik, dan barang keluar yang tidak dibatalkan. Produk bundle dilewati.
- Rekonsiliasi tetap membutuhkan histori lengkap: stok awal, mutasi produk pause, dan impor historis tanpa pergerakan stok tidak bisa dibedakan sempurna dari data lama. Cocokkan dengan stok fisik sebelum menggunakan koreksi. Peringatan tersedia pada halaman.
- Perbaikan harga menggunakan harga produk saat ini sesuai perilaku sumber; ini bukan pemulihan histori harga yang tidak tersimpan.

## Konfigurasi sinkronisasi

Tambahkan secret yang berbeda dan kuat pada `.env` untuk endpoint mesin:

```dotenv
SYNC_KEY = 'isi-secret-ekspor-database'
CRON_KEY = 'isi-secret-worker-shopee'
```

`sync_export` menerima header `X-Sync-Key` atau parameter `key`; `cron_shopee_stock_sync` menerima `X-Cron-Key` atau `key`. Secret kosong menonaktifkan akses melalui key. Tidak ada key bawaan. `sync_import` hanya tersedia bagi admin sistem karena cakupannya seluruh database, lintas toko.

`App\Libraries\DatabaseSync` menangani dump milik aplikasi ini. Parser mempertahankan tanda titik koma dalam string SQL dan memvalidasi seluruh dump sebelum eksekusi. Dump SQL umum dengan format/perintah lain dapat ditolak. Sebelum restore, backup database saat ini disimpan ke `writable/sync_backups/before_*.sql`; kegagalan membuat backup membatalkan restore. DDL MySQL tidak dapat di-rollback: restore berhenti pada kegagalan, mengaktifkan kembali foreign key checks, dan melaporkan error. Dump dibangun dalam memori, sehingga database besar perlu strategi backup terpisah. Backup lama tidak dihapus otomatis.

Worker juga tersedia melalui CLI:

```sh
php spark tools:shopee-stock-sync
```

Worker memakai lock MySQL untuk mencegah proses ganda, mengambil maksimal 500 baris, mengelompokkan produk/toko, mengirim maksimal 100 SKU per batch, serta membatasi retry sampai lima kegagalan. Produk pause dikirim dengan stok nol. ID antrean ditandai processing sebelum stok dibaca agar perubahan baru saat request berlangsung tetap memiliki antrean sendiri. Baris processing akibat worker berhenti dapat diproses ulang. Tidak ada scheduler sistem yang dipasang pada tahap ini.

## Verifikasi

- PHPUnit seluruh aplikasi: **113 tes, 1.494 assertion**, lulus; termasuk 19 tes tools untuk route, render HTML, otorisasi, unduhan CSV, isolasi pengguna, rollback, kepemilikan marketplace, perhitungan stok server, parser SQL, dan worker dengan callback tiruan.
- Lint **286 file PHP**: tidak ada kesalahan sintaks.
- `spark list --simple`: perintah `tools:shopee-stock-sync` terdaftar; worker tidak dijalankan ke antrean nyata.
- Tes menggunakan koneksi database tiruan. Tidak ada restore SQL, perubahan data produksi, pengiriman WhatsApp, atau request marketplace yang dilakukan. Uji browser, database MySQL nyata, dan integrasi eksternal masih diperlukan.

## Tahap berikutnya

Modul deposit/reseller, endpoint API dan webhook, cron lain (termasuk antrean WhatsApp), area CRM/admin, serta halaman publik belum dinyatakan selesai oleh tahap tools ini. Dokumen tahap sebelumnya: `PORTING_MASTER.md`, `PORTING_TRANSAKSI.md`, `PORTING_STOK.md`, `PORTING_LAPORAN.md`, dan `PORTING_PENGATURAN.md`.
