Files
AbelBirdNest-Stock/docs/purchase-realization-design.md

218 lines
4.9 KiB
Markdown

# 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