257 lines
8.6 KiB
Markdown
257 lines
8.6 KiB
Markdown
# Aplikasi Catat Jual-Beli Saham — Odoo 17 + Flutter
|
||
|
||
Backend Odoo ERP (Community 17) untuk mencatat pembelian & penjualan saham,
|
||
diakses dari aplikasi **Flutter** (Android).
|
||
|
||
## Arsitektur
|
||
```
|
||
Flutter app (Android) ──JSON-RPC──► Odoo 17 (Python)
|
||
│ custom addon: saat_invest
|
||
▼
|
||
PostgreSQL 16
|
||
```
|
||
|
||
## Stack
|
||
|
||
| Layer | Teknologi | Port |
|
||
|---|---|---|
|
||
| Backend | Odoo 17 Community (`odoo:17.0`) | `18069` (host) |
|
||
| Database | PostgreSQL 16 (`postgres:16`) | internal (5432, tdk di-publish) |
|
||
| Mobile | Flutter (Android) | — |
|
||
|
||
## Struktur proyek
|
||
```
|
||
saat-app/
|
||
├── docker-compose.yml # Odoo 17 + PostgreSQL 16
|
||
├── .env # RAHASIA: password (jangan commit)
|
||
├── addons/ # custom addon buatan sendiri (saat_invest)
|
||
└── README.md
|
||
```
|
||
|
||
## Cara menjalankan
|
||
```bash
|
||
cd /home/ardhi/workspace/erp/odoo-app/saat-app
|
||
docker compose config # validasi
|
||
docker compose up -d # start
|
||
```
|
||
|
||
Akses UI: http://localhost:18069 — login `admin` dengan password
|
||
`ODOO_ADMIN_PASSWORD` di `.env`.
|
||
|
||
## Status
|
||
- ✅ Odoo 17 container jalan (port 18069), DB PostgreSQL 16 healthy
|
||
- ✅ JSON-RPC aktif (uid `admin` verified) — endpoint yang akan dipakai Flutter
|
||
- ✅ **Addon `saat_invest` terinstal** (model saham, transaksi, portofolio + seed 5 saham IDX)
|
||
- ✅ **Portofolio auto-sync**: otomatis diperbarui tiap transaksi ditambah/ubah/hapus
|
||
(tidak perlu tombol manual; buka menu Portofolio selalu datanya segar)
|
||
- ✅ **Live harga pasar (cron)**: ambil & update harga dari Yahoo Finance (.JK)
|
||
tiap 6 menit SAAT jam bursa IDX (08:45–16:00 WIB). Update hanya bila berubah.
|
||
- ✅ End-to-end teruji: buat beli/jual → portofolio ter-update → hitung avg cost & realized/unrealized P/L
|
||
- ⏳ Aplikasi Flutter (login, catat jual/beli, portfolio, P/L)
|
||
|
||
## Install / upgrade addon saat_invest
|
||
```bash
|
||
cd /home/ardhi/Application/saat-app
|
||
set -a && source .env && set +a
|
||
# install pertama kali
|
||
docker exec -e PASSWORD="$POSTGRES_PASSWORD" saat-odoo odoo \
|
||
-d "$POSTGRES_DB" --db_host=db --db_user="$POSTGRES_USER" \
|
||
--db_password="$POSTGRES_PASSWORD" --no-http --stop-after-init -i saat_invest
|
||
# upgrade setelah ubah kode
|
||
docker exec -e PASSWORD="$POSTGRES_PASSWORD" saat-odoo odoo \
|
||
-d "$POSTGRES_DB" --db_host=db --db_user="$POSTGRES_USER" \
|
||
--db_password="$POSTGRES_PASSWORD" --no-http --stop-after-init -u saat_invest
|
||
docker restart saat-odoo
|
||
```
|
||
|
||
> Catatan Odoo: `<list>` view di Odoo 17 kadang bermasalah, pakai `<tree>`
|
||
> (kompatibel lintas versi) seperti yang sudah dilakukan.
|
||
|
||
## Troubleshooting PermissionError sessions
|
||
|
||
Jika muncul:
|
||
|
||
```text
|
||
PermissionError: [Errno 13] Permission denied: '/var/lib/odoo/sessions'
|
||
```
|
||
|
||
Odoo 17 berjalan sebagai user `odoo` dengan UID/GID `101`. Perbaiki
|
||
ownership seluruh volume data Odoo dari container yang sedang berjalan:
|
||
|
||
```bash
|
||
cid=$(docker compose ps -q odoo)
|
||
docker exec --user root "$cid" sh -c \
|
||
'chown -R 101:101 /var/lib/odoo && \
|
||
chmod 755 /var/lib/odoo && chmod 700 /var/lib/odoo/sessions'
|
||
```
|
||
|
||
Verifikasi write access sebagai user Odoo, lalu restart dan cek log:
|
||
|
||
```bash
|
||
docker exec --user odoo "$cid" sh -c \
|
||
'touch /var/lib/odoo/sessions/.write-check && \
|
||
rm /var/lib/odoo/sessions/.write-check'
|
||
docker compose restart odoo
|
||
docker compose logs --since=30s odoo
|
||
```
|
||
|
||
Gunakan hanya satu mount volume utama berikut pada Compose:
|
||
|
||
```yaml
|
||
volumes:
|
||
- saat_odoo_filestore:/var/lib/odoo
|
||
```
|
||
|
||
Jangan menambahkan mount terpisah ke `/var/lib/odoo/session` (singular).
|
||
Path yang dipakai Odoo adalah `/var/lib/odoo/sessions` (plural). Jangan
|
||
menggunakan `chmod 777`; cukup berikan ownership kepada user Odoo.
|
||
|
||
## Rencana migrasi Odoo 17 ke Odoo 18
|
||
|
||
Migrasi major version harus mengubah schema database. Mengganti image secara
|
||
langsung dari `odoo:17.0` ke `odoo:18.0` **bukan** prosedur migrasi dan dapat
|
||
menyebabkan error seperti `column res_lang.short_time_format does not exist`.
|
||
Compose harus tetap menggunakan `odoo:17.0` sampai database selesai dimigrasi.
|
||
|
||
### 1. Persiapan dan backup
|
||
|
||
Pastikan `.env` terisi dan jangan commit file tersebut. Hentikan penulisan data,
|
||
lalu buat backup database dan filestore:
|
||
|
||
```bash
|
||
set -a && source .env && set +a
|
||
backup_dir="backups/odoo17-$(date +%Y%m%d-%H%M%S)"
|
||
mkdir -p "$backup_dir"
|
||
docker compose exec -T db pg_dump -U "$POSTGRES_USER" -d "$POSTGRES_DB" -Fc \
|
||
> "$backup_dir/database.dump"
|
||
volume=$(docker inspect saat-odoo --format '{{range .Mounts}}{{if eq .Destination "/var/lib/odoo"}}{{.Name}}{{end}}{{end}}')
|
||
docker run --rm -v "$volume:/source:ro" -v "$PWD/$backup_dir:/backup" alpine \
|
||
sh -c 'tar czf /backup/filestore.tar.gz -C /source .'
|
||
```
|
||
|
||
Validasi backup dengan `pg_restore --list` dari image PostgreSQL 16 dan pastikan
|
||
arsip filestore berisi direktori `filestore/`.
|
||
|
||
### 2. Migrasi pada salinan
|
||
|
||
Jangan menguji migrasi pada volume produksi. Restore `database.dump` dan
|
||
`filestore.tar.gz` ke environment staging yang terpisah, lalu gunakan salah
|
||
satu jalur resmi berikut:
|
||
|
||
- Odoo Upgrade Service untuk database Enterprise.
|
||
- OpenUpgrade dengan branch yang sesuai untuk migrasi Community 17 ke 18.
|
||
|
||
Migrasikan database terlebih dahulu. Sesuaikan custom addon `saat_invest`
|
||
dengan API, view, security, dan dependency Odoo 18, lalu install/upgrade addon
|
||
di database staging hasil migrasi.
|
||
|
||
### 3. Validasi staging
|
||
|
||
Uji login, menu saham, create/update/delete transaksi, kalkulasi portofolio,
|
||
cron harga pasar, attachment/filestore, dan seluruh endpoint JSON-RPC yang
|
||
dipakai Flutter. Periksa log untuk `ERROR`, `Traceback`, `UndefinedColumn`, dan
|
||
`PermissionError`.
|
||
|
||
### 4. Cutover produksi
|
||
|
||
Setelah staging lulus, hentikan Odoo 17, buat backup final, restore atau jalankan
|
||
migrasi pada database produksi sesuai prosedur tool migrasi, kemudian ubah:
|
||
|
||
```yaml
|
||
image: odoo:18.0
|
||
```
|
||
|
||
Pastikan ownership volume sesuai user Odoo 18 sebelum start, jalankan
|
||
`docker compose up -d`, dan ulangi seluruh validasi staging.
|
||
|
||
### 5. Rollback
|
||
|
||
Jika migrasi gagal, jangan menjalankan Odoo 17 pada database yang sudah sebagian
|
||
dimigrasi. Hentikan stack, restore database dan filestore dari backup Odoo 17
|
||
ke volume/database terpisah, ubah image kembali ke `odoo:17.0`, lalu validasi
|
||
aplikasi sebelum cutover ulang.
|
||
|
||
## Cara menyelesaikan merge conflict Git
|
||
|
||
Contoh berikut menggabungkan branch `odoo18` ke `master`. Pastikan perubahan
|
||
lokal sudah disimpan atau di-commit sebelum memulai:
|
||
|
||
```bash
|
||
git status
|
||
git fetch origin
|
||
git switch master
|
||
git pull --ff-only origin master
|
||
git merge --no-ff odoo18
|
||
```
|
||
|
||
Jika merge conflict terjadi, lihat file yang belum terselesaikan:
|
||
|
||
```bash
|
||
git status
|
||
git diff --name-only --diff-filter=U
|
||
```
|
||
|
||
Buka setiap file tersebut dan cari marker berikut:
|
||
|
||
```text
|
||
[marker pembuka] perubahan dari branch saat ini
|
||
[marker pemisah] perubahan dari branch yang sedang di-merge
|
||
[marker penutup]
|
||
```
|
||
|
||
Hapus marker dan gabungkan isi yang benar secara manual. Jangan langsung
|
||
memilih seluruh file dari salah satu branch jika kedua perubahan diperlukan.
|
||
Untuk memilih satu sisi secara sengaja, gunakan:
|
||
|
||
```bash
|
||
# Pilih isi dari branch saat ini
|
||
git checkout --ours -- path/to/file
|
||
|
||
# Pilih isi dari branch yang sedang di-merge
|
||
git checkout --theirs -- path/to/file
|
||
```
|
||
|
||
Setelah semua conflict diperbaiki, validasi proyek sebelum commit:
|
||
|
||
```bash
|
||
git diff --check
|
||
docker compose config
|
||
git diff --name-only --diff-filter=U
|
||
```
|
||
|
||
Perintah terakhir harus menghasilkan output kosong. Kemudian stage file yang
|
||
sudah diselesaikan dan buat merge commit:
|
||
|
||
```bash
|
||
git add path/to/resolved-file
|
||
git add -u
|
||
git commit -m "Merge odoo18 branch into master"
|
||
git status --short --branch
|
||
git push origin master
|
||
```
|
||
|
||
Jika ingin membatalkan merge sebelum commit:
|
||
|
||
```bash
|
||
git merge --abort
|
||
```
|
||
|
||
Jangan commit `.env`, backup database, password, atau token ketika menyelesaikan
|
||
conflict. Periksa `git diff --cached` sebelum commit untuk memastikan rahasia
|
||
tidak ikut ter-stage.
|
||
|
||
## API untuk Flutter (via JSON-RPC `execute_kw`)
|
||
Semua melalui `POST /jsonrpc` dengan `{service:'object', method:'execute_kw'}`.
|
||
Login: `common.authenticate(db, user, pass)` → `uid`.
|
||
- List saham: `saat.saham search_read [domain] {fields}`
|
||
- Catat transaksi: `saat.transaksi create [{vals}]`
|
||
- List transaksi: `saat.transaksi search_read [domain] {fields}`
|
||
- **Rekalkulasi portofolio**: `saat.portofolio action_recalculate [[]]`
|
||
- Baca portofolio: `saat.portofolio search_read [domain] {fields}`
|
||
(sisa_lembar, avg_cost, total_beli_biaya, realized_pl, unrealized_pl, nilai_sekarang)
|
||
|
||
## Catatan keamanan
|
||
- `.env` berisi rahasia → **tidak boleh di-commit** (sudah di `.gitignore`)
|
||
- PostgreSQL tidak di-publish ke host, hanya akses antar-container
|
||
- Ganti `ADMIN_PASSWD` segera setelah setup awal
|