# 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
