# Purchase Realization Design ## Tujuan Menyediakan model data dan alur kalkulasi untuk melacak satu purchase dari: - pembelian awal - receipt menjadi lot - washing - regrade / mix / split - regular sale - consignment - office buyout sampai status akhir purchase dapat dinyatakan `CLOSED` dan laba/rugi agent dapat dihitung final. ## Prinsip - `Purchase Analysis` tetap dipakai sebagai snapshot awal pembelian. - `Purchase Realization` dipakai sebagai hasil aktual setelah barang bergerak dan terjual. - Setiap lot harus bisa dilacak asal purchase-nya, termasuk jika hasil mix atau regrade. - Setiap event yang memengaruhi qty atau nilai harus menulis jurnal realization. ## Model Baru ### `lot_purchase_allocations` Menyimpan komposisi asal purchase untuk setiap lot. Contoh: - Lot `LOT-A` berasal 100% dari purchase `P-1` - Lot `LOT-B` hasil mix dari `P-1` 40% dan `P-2` 60% Maka `LOT-B` memiliki 2 allocation rows. Kolom penting: - `lot_id` - `purchase_id` - `purchase_line_id` - `source_type` - `source_ref_id` - `qty_allocated` - `cost_total_allocated` - `unit_cost_snapshot` - `agent_id_snapshot` - `profit_share_scheme_id_snapshot` ### `purchase_realization_entries` Ledger event yang memengaruhi hasil akhir purchase. Kolom penting: - `purchase_id` - `lot_id` - `allocation_id` - `event_type` - `reference_type` - `reference_id` - `occurred_at` - `qty_in` - `qty_out` - `qty_shrinkage` - `amount_cost` - `amount_revenue` - `amount_expense` - `amount_profit` - `agent_share_percent_snapshot` - `agent_amount` Event type awal yang direkomendasikan: - `OPENING_COST` - `WASHING_COST` - `WASHING_SHRINKAGE` - `TRANSFORMATION_SHRINKAGE` - `SALE_REVENUE` - `SALE_RETURN` - `SALE_SHRINKAGE` - `CONSIGNMENT_REVENUE` - `CONSIGNMENT_RETURN` - `CONSIGNMENT_SHRINKAGE` - `OFFICE_BUYOUT_REVENUE` - `OFFICE_BUYOUT_TRANSFER_OUT` - `STOCK_ADJUSTMENT_LOSS` - `STOCK_ADJUSTMENT_GAIN` - `MANUAL_ADJUSTMENT` ### `purchase_realization_summaries` Cache summary per purchase untuk kebutuhan UI dan closing. Kolom penting: - `status` - `qty_opening` - `qty_remaining` - `qty_sold` - `qty_returned` - `qty_shrinkage` - `cost_opening_total` - `cost_additional_total` - `revenue_total` - `profit_loss_total` - `agent_share_percent` - `agent_profit_total` - `closed_at` Status yang direkomendasikan: - `OPEN` - `PARTIAL` - `READY_TO_CLOSE` - `CLOSED` ## Aturan Alokasi ### Purchase submit - Buat lot seperti implementasi saat ini. - Buat 1 allocation row per lot: - `source_type = PURCHASE` - `qty_allocated = lot.original_qty` - `cost_total_allocated = qty * unit_cost` - Buat 1 realization entry: - `event_type = OPENING_COST` ### Washing selesai - Allocation lot tidak berubah. - Jika ada biaya cuci, tulis `WASHING_COST`. - Jika ada susut, tulis `WASHING_SHRINKAGE`. - Semua entry dibagi ke purchase asal berdasarkan allocation aktif lot tersebut. ### Transformation / regrade / mix - Baca allocation dari semua source lots. - Bentuk allocation baru pada output lots dengan distribusi proporsional terhadap qty / cost input. - Jika ada processing loss, buat `TRANSFORMATION_SHRINKAGE`. - Output lot mewarisi allocation campuran dari input. ### Regular sale close - Baca allocation lot pada line yang dijual. - Revenue aktual dibagi ke purchase asal sesuai allocation. - Tulis: - `SALE_REVENUE` - `SALE_RETURN` - `SALE_SHRINKAGE` ### Consignment close - Perlakuan sama seperti regular sale, tetapi sumber event adalah consignment line. ### Office buyout Untuk purchase lama: - Tulis `OFFICE_BUYOUT_REVENUE` - `qty_out` sebesar qty yang dibeli kantor - `amount_revenue = qty * buyout_unit_price` Untuk lot baru hasil buyout: - Buat allocation baru yang menunjuk purchase buyout / jalur kantor - Setelah itu hasil jual berikutnya tidak lagi menjadi hak agent lama ## Rumus Summary - `cost_opening_total` = total opening cost - `cost_additional_total` = washing cost + biaya tambahan + adjustment - `revenue_total` = sale + consignment + office buyout - `profit_loss_total = revenue_total - cost_opening_total - cost_additional_total` - `agent_profit_total = akumulasi agent_amount` atau fallback `profit_loss_total * share_agent / 100` ## Rule Closing Purchase Purchase dapat `CLOSED` jika seluruh qty asal purchase sudah terselesaikan menjadi salah satu: - terjual - susut - dibuyout kantor - habis masuk transformasi dan seluruh descendant lots-nya selesai Artinya closing harus melihat seluruh lineage lot, bukan hanya lot awal purchase. ## Scope Implementasi Bertahap ### Tahap 1 - Tambah schema baru - Isi allocation + opening realization saat purchase submit - Tambah summary recalculation dasar ### Tahap 2 - Integrasi office buyout - Integrasi washing cost dan shrinkage ### Tahap 3 - Integrasi transformation / mix / regrade allocation propagation ### Tahap 4 - Integrasi regular sale dan consignment revenue realization ### Tahap 5 - UI `Purchase Realization` - closing otomatis ### Tahap 6 - JIT sale, jika nanti ingin ditautkan ke lineage purchase