# POS Payload Checklist (Strict Compile)

Dokumen ini untuk tim POS agar payload selalu lolos `compileFilesV2`, `compileFilesDataV2`, dan `compileFilesDataRegistryV2` tanpa fallback dinamis di server.

## 1) Aturan Umum

- Jangan kirim `null` untuk kolom `NOT NULL`.
- Jika field numerik tidak dipakai: kirim `0`.
- Jika field string tidak dipakai: kirim string (`""` atau sentinel seperti `"none"` sesuai aturan di bawah).
- Field kunci transaksi wajib ada dan tidak kosong: `machine_id`, `nomer`, `fulldate`, `dtime`, `x_id`.

## 2) Wajib Non-Empty (string) untuk `transaksi`

Field berikut wajib string terisi (bukan `null`, bukan `""`) karena validasi strict compile saat ini:

- `kontainer_size` (`varchar(255)`), default DB = `""`
- `ekspedisi_status` (`varchar(32)`), default DB = `""`
- `print_oleh_nama` (`varchar(255)`), default DB = `""`

Rekomendasi nilai jika tidak digunakan:

- `kontainer_size`: `"none"`
- `ekspedisi_status`: `"none"`
- `print_oleh_nama`: nama user POS, fallback `"system"`

## 3) Wajib Non-Null (numerik/flag) untuk `transaksi`

Field di bawah `NOT NULL` dengan default DB non-kosong. POS **tetap harus kirim non-null** (jika `null`, DB akan menolak insert).

| Field | Type | Default aman jika null |
|---|---|---|
| `cabang_id` | `int(11)` | `0` |
| `cli` | `tinyint(3)` | `0` |
| `inv` | `varchar(46)` | `0` |
| `customers_id` | `int(11)` | `0` |
| `suppliers_id` | `int(11)` | `0` |
| `bank_id` | `int(11)` | `0` |
| `bank_rekening_id` | `int(11)` | `0` |
| `jatuh_tempo` | `int(11)` | `0` |
| `ekspedisi_id` | `int(11)` | `0` |
| `kontainer_size_id` | `tinyint(3)` | `0` |
| `kontainer_status` | `tinyint(1)` | `0` |
| `kontainer_approve_id` | `int(11)` | `0` |
| `bank_id_from` | `int(11)` | `0` |
| `bank_rekening_id_from` | `int(11)` | `0` |
| `referensi_id2` | `int(11)` | `0` |
| `seller_id` | `int(11)` | `0` |
| `tpl_alamat_id` | `int(11)` | `0` |
| `inv_dollar` | `tinyint(3)` | `0` |
| `next_step_num` | `tinyint(3)` | `0` |
| `returned` | `tinyint(1)` | `0` |
| `status` | `tinyint(1)` | `1` |
| `returns` | `tinyint(1)` | `0` |
| `penerima_id` | `int(11)` | `0` |
| `approvals_batal_id` | `int(11)` | `0` |
| `orders_id` | `int(11)` | `0` |
| `deposit_persen_in` | `decimal(6,3)` | `0.000` |
| `transaksi_nilai_ori` | `decimal(24,10)` | `0.0000000000` |
| `trash2` | `tinyint(1)` | `0` |
| `r_jenis` | `tinyint(1)` | `0` |
| `_temp` | `tinyint(1)` | `0` |
| `cli_loop` | `tinyint(4)` | `0` |
| `status_edit` | `tinyint(1)` | `0` |
| `print_counter` | `tinyint(3)` | `0` |
| `print_status` | `tinyint(1)` | `0` |
| `print_oleh_id` | `int(11)` | `0` |
| `setor_status` | `tinyint(3)` | `0` |
| `sinkron_cache` | `tinyint(1)` | `0` |
| `auto_pemindahan` | `tinyint(1)` | `0` |
| `counters_customers_id` | `int(11)` | `0` |
| `counters_customers_id_all` | `int(11)` | `0` |
| `counters_suppliers_id` | `int(11)` | `0` |
| `counters_approvals_id` | `int(11)` | `0` |
| `counters_gudang_id` | `int(11)` | `0` |
| `counters_gudang_id_all` | `int(11)` | `0` |
| `approvals_harga_id` | `int(11)` | `0` |
| `batal_kirim` | `tinyint(1)` | `0` |
| `approvals_batal_kirim_id` | `int(11)` | `0` |
| `kontainer_valas_nilai` | `decimal(24,10)` | `0.0000000000` |
| `tambahan_nilai` | `decimal(24,10)` | `0.0000000000` |
| `cek` | `tinyint(1)` | `0` |
| `status_4` | `tinyint(3)` | `0` |
| `trash_4` | `tinyint(3)` | `0` |
| `r_sales` | `tinyint(1)` | `0` |
| `r_maju` | `tinyint(1)` | `0` |
| `r_mundur` | `tinyint(1)` | `0` |

## 4) Wajib Khusus (tanpa default DB)

- `counters` (`mediumblob`) tidak punya default DB. Wajib kirim non-null.

Rekomendasi untuk POS:
- `counters`: kirim object/array counters valid. Minimal jangan `null` (contoh fallback paling aman: `{}` lalu serialize sesuai format export POS).

## 5) Kontrak Minimal Endpoint Lain

### `compileFilesDataV2` (`transaksi_data`)
- Wajib non-empty: `machine_id`, `x_id`, `transaksi_id`, `dtime`.
- Hindari `null` untuk field numerik/detail penting (`produk_id`, `produk_ord_jml`, `produk_ord_hrg`, dll) agar proses lanjutan stabil.

### `compileFilesDataRegistryV2` (`transaksi_data_registry`)
- Wajib non-empty: `machine_id`, `transaksi_id`, `main`.
- `main` harus bisa decode dan mengandung `dtime`.

## 6) Sanitizer POS (contoh pseudocode)

```js
function nzNum(v, d=0){ return (v===null || v===undefined || v==="") ? d : v; }
function nzStr(v, d=""){ return (v===null || v===undefined) ? d : String(v); }

function sanitizeTransaksi(row){
  row.machine_id = nzStr(row.machine_id);
  row.nomer = nzStr(row.nomer);
  row.fulldate = nzStr(row.fulldate);
  row.dtime = nzStr(row.dtime);
  row.x_id = nzNum(row.x_id, 0);

  row.kontainer_size = nzStr(row.kontainer_size, "none") || "none";
  row.ekspedisi_status = nzStr(row.ekspedisi_status, "none") || "none";
  row.print_oleh_nama = nzStr(row.print_oleh_nama, row.oleh_nama || "system") || "system";

  row.cabang_id = nzNum(row.cabang_id, 0);
  row.cli = nzNum(row.cli, 0);
  row.inv = nzStr(row.inv, "0");
  row.customers_id = nzNum(row.customers_id, 0);
  row.suppliers_id = nzNum(row.suppliers_id, 0);
  row.bank_id = nzNum(row.bank_id, 0);
  row.bank_rekening_id = nzNum(row.bank_rekening_id, 0);
  row.jatuh_tempo = nzNum(row.jatuh_tempo, 0);
  row.ekspedisi_id = nzNum(row.ekspedisi_id, 0);
  row.kontainer_size_id = nzNum(row.kontainer_size_id, 0);
  row.kontainer_status = nzNum(row.kontainer_status, 0);
  row.kontainer_approve_id = nzNum(row.kontainer_approve_id, 0);
  row.bank_id_from = nzNum(row.bank_id_from, 0);
  row.bank_rekening_id_from = nzNum(row.bank_rekening_id_from, 0);
  row.referensi_id2 = nzNum(row.referensi_id2, 0);
  row.seller_id = nzNum(row.seller_id, 0);
  row.tpl_alamat_id = nzNum(row.tpl_alamat_id, 0);
  row.inv_dollar = nzNum(row.inv_dollar, 0);
  row.next_step_num = nzNum(row.next_step_num, 0);
  row.returned = nzNum(row.returned, 0);
  row.status = nzNum(row.status, 1);
  row.returns = nzNum(row.returns, 0);
  row.penerima_id = nzNum(row.penerima_id, 0);
  row.approvals_batal_id = nzNum(row.approvals_batal_id, 0);
  row.orders_id = nzNum(row.orders_id, 0);
  row.deposit_persen_in = nzNum(row.deposit_persen_in, 0.000);
  row.transaksi_nilai_ori = nzNum(row.transaksi_nilai_ori, 0.0000000000);
  row.trash2 = nzNum(row.trash2, 0);
  row.r_jenis = nzNum(row.r_jenis, 0);
  row._temp = nzNum(row._temp, 0);
  row.cli_loop = nzNum(row.cli_loop, 0);
  row.status_edit = nzNum(row.status_edit, 0);
  row.print_counter = nzNum(row.print_counter, 0);
  row.print_status = nzNum(row.print_status, 0);
  row.print_oleh_id = nzNum(row.print_oleh_id, 0);
  row.setor_status = nzNum(row.setor_status, 0);
  row.sinkron_cache = nzNum(row.sinkron_cache, 0);
  row.auto_pemindahan = nzNum(row.auto_pemindahan, 0);
  row.counters_customers_id = nzNum(row.counters_customers_id, 0);
  row.counters_customers_id_all = nzNum(row.counters_customers_id_all, 0);
  row.counters_suppliers_id = nzNum(row.counters_suppliers_id, 0);
  row.counters_approvals_id = nzNum(row.counters_approvals_id, 0);
  row.counters_gudang_id = nzNum(row.counters_gudang_id, 0);
  row.counters_gudang_id_all = nzNum(row.counters_gudang_id_all, 0);
  row.approvals_harga_id = nzNum(row.approvals_harga_id, 0);
  row.batal_kirim = nzNum(row.batal_kirim, 0);
  row.approvals_batal_kirim_id = nzNum(row.approvals_batal_kirim_id, 0);
  row.kontainer_valas_nilai = nzNum(row.kontainer_valas_nilai, 0.0000000000);
  row.tambahan_nilai = nzNum(row.tambahan_nilai, 0.0000000000);
  row.cek = nzNum(row.cek, 0);
  row.status_4 = nzNum(row.status_4, 0);
  row.trash_4 = nzNum(row.trash_4, 0);
  row.r_sales = nzNum(row.r_sales, 0);
  row.r_maju = nzNum(row.r_maju, 0);
  row.r_mundur = nzNum(row.r_mundur, 0);

  if (row.counters === null || row.counters === undefined) row.counters = {};
  return row;
}
```