Tulis satu class Python. Odoo membuat tabel dan form-nya.
Kursus interaktif untuk Odoo 19. Pahami cara kerja framework-nya, jalankan lewat stack Docker kita, lalu bangun aplikasi Real Estate dari tutorial resmi Server Framework 101, satu chapter demi satu chapter.
class EstateProperty(models.Model):
_name = "estate.property"
name = fields.Char(required=True)
expected_price = fields.Float()
bedrooms = fields.Integer(default=2)
garden = fields.Boolean()
estate_property1 barisidserial1namevarcharBig Villaexpected_pricefloat81600000bedroomsint42gardenbooltrue→ lanjut, ← kembali, Space putar atau jeda, O daftar scene. Kata bergaris titik membuka definisi.
Tiga tier, satu bahasa per tier
Odoo adalah aplikasi multitier klasik. Tier presentasi berupa HTML, CSS, dan JavaScript (framework OWL). Tier logika hanya Python. Tier data hanya PostgreSQL; database lain tidak didukung.
Ingat: kamu menulis Python untuk tier tengah. Browser dan PostgreSQL digerakkan untukmu.
Web client
- Komponen OWL me-render view
- View dikirim server dalam bentuk XML
- Berkomunikasi lewat JSON-RPC di atas HTTP
odoo-bin (Python)
- HTTP controller
- ORM: model, field, hak akses
- Registry module yang terinstal
PostgreSQL
- Setiap model adalah tabel
- Setiap field adalah kolom
- View, menu, action juga berupa baris
Lihat satu klik berjalan melewati semua tier.
1. User menekan Save di form. OWL mengumpulkan field yang berubah.
2. Python menerima panggilan dan meneruskannya ke method model lewat ORM.
3. ORM menulis SQL. PostgreSQL menyimpan baris di dalam transaksi request.
4. Python melakukan commit dan mengubah hasilnya menjadi JSON.
5. Browser me-render ulang dengan nilai terbaru. Semua kode yang kamu tulis ada di tier tengah.
Apa yang terjadi saat kamu menekan Save
Satu HTTP request adalah satu transaksi database. Jika ada exception di tengah jalan, PostgreSQL membatalkan (rollback) semuanya dan user melihat pesan error.
Ingat: satu request adalah satu transaksi. Exception di mana pun membatalkan seluruh request.
Form view
Save ditekan
JSON-RPC
/web/dataset/call_kw
call_kw
mencari model + method
write()
cek hak akses, hitung ulang
UPDATE
lalu COMMIT
Re-render
hasil JSON
Semuanya dimulai dan diakhiri dengan module
Odoo sendiri adalah kumpulan module (disebut juga addons). Setiap module dideklarasikan oleh manifest-nya. Server mencarinya di folder-folder yang tercantum di addons_path. Module dengan application: True tampil sebagai App. Enterprise bukan fork, hanya module tambahan di atas Community.
Ingat: semuanya adalah module. Pekerjaanmu selalu dikirim sebagai module di dalam addons_path.
Business object
Class Python; field dipetakan ke kolom DB lewat ORM.
File data (XML / CSV)
View, action, menu, aturan keamanan, data demo.
Web controller
Route yang menjawab HTTP request dari browser.
Data web statis
JS, SCSS, gambar untuk web client atau website.
Keempatnya opsional. Module lokalisasi bisa saja hanya berisi data; tutorial ini memakai A dan B.
Apa yang sebenarnya dilakukan -i estate
Instalasi bekerja seperti package manager Linux: dependency dulu, lalu kodemu, lalu datamu. Jika sebuah dependency di-uninstall, semua module yang bergantung padanya ikut ter-uninstall.
Ingat: dependency dulu, lalu Python, lalu skema, lalu file data sesuai urutan di manifest.
Pindai addons_path
Setiap folder yang punya __manifest__.py adalah kandidat.
Selesaikan depends
Bangun graph-nya, instal base dan kawan-kawan lebih dulu.
Impor Python ke registry
Class dengan _name/_inherit yang sama digabung menjadi satu class model akhir.
Sinkronkan skema
Buat atau ubah tabel estate_property beserta kolomnya.
Muat file data sesuai urutan
Security, view, action, menu menjadi baris di tabel ir_*.
Tandai terinstal
ir_module_module.state = 'installed'
Urutan penting. Menu merujuk ke action, jadi file yang mendefinisikan action harus dimuat sebelum file menu. Hak akses paling awal.
Restart, atau upgrade dengan -u?
Python tinggal di memori server; view dan menu tinggal di database. Fakta ini menjelaskan hampir semua momen "kenapa perubahanku tidak muncul?".
Ingat: perubahan Python: restart. Field baru, perubahan XML atau CSV: -u estate.
| Yang kamu ubah | Tempatnya | Yang harus dilakukan |
|---|---|---|
| Isi method, logika compute | Python di memori | Restart server |
| Field baru atau model baru | Python + skema DB | Restart dengan -u estate |
| View XML, action, menu, CSV | Baris di ir_ui_view, ir_ui_menu... | -u estate (atau --dev xml saat merapikan view) |
__manifest__.py module baru | Daftar module | Apps, lalu Update Apps List (developer mode) |
JS / SCSS di static/ | Asset bundle | Muat ulang browser dengan ?debug=assets |
Aktifkan developer mode dengan ?debug=1 di URL. Kamu butuh ini untuk Update Apps List, menu teknis, dan tooltip field.
Cek pemahamanmu
Pilih jawaban untuk melihat penjelasannya. Tidak ada nilai; jawabanmu hanya tersimpan di browser ini.
1. Kamu mengubah XML sebuah form view lalu me-refresh browser. Tidak ada yang berubah. Kenapa?
View, menu, dan action adalah record yang dimuat dari XML saat instal atau upgrade. File di disk baru dibaca ulang saat -u (atau dengan --dev xml).
2. Di mana kode Python module-mu dijalankan?
Tier logika hanya Python. Browser menjalankan OWL (JavaScript) dan PostgreSQL hanya menyimpan data.
3. Apa fungsi depends di __manifest__.py?
Cara kerjanya seperti package manager: dependency diinstal lebih dulu, dan meng-uninstall salah satunya ikut menghapus semua module yang bergantung padanya. File yang dimuat ditulis di data.
Dua container, banyak project
Repo odoo-containers menjalankan project apa pun di versi Odoo mana pun dari satu docker-compose.yml. Tidak ada yang di-hardcode: .env project yang aktif menentukan versi, folder addons, dan database-nya.
Ingat: satu container Odoo, satu container Postgres opsional, keduanya diatur oleh .env.
odoo-<project>-19.0
Di-build dari Dockerfile.bundled, diberi tag ${REGISTRY_HOST}/${IMAGE_NAME}:${ODOO_VERSION} supaya rekan tim bisa melakukan pull.
odoo-<project>-db
Opsional. Hanya jalan dengan profile local-db. Jika tidak, set DB_HOST=host.docker.internal untuk memakai Postgres di host-mu.
Kodemu tetap tinggal di host
Bind mount memasukkan folder host ke dalam container, jadi kamu mengedit dengan editor biasa dan Odoo langsung melihat perubahannya. Named volume menyimpan filestore dan database di antara restart.
Ingat: edit file di mesinmu; container melihat file yang sama lewat bind mount.
workers = 0estate/ ditaruh.Urutan pencarian. Jika nama module ada di dua folder, path pertama di addons_path yang dipakai. workers = 0 membuat Odoo berjalan dalam satu proses ber-thread, sehingga debugger bisa attach dan berhenti di breakpoint.
Satu .env per project, satu perintah untuk berpindah
Setiap project menyimpan file env-nya sendiri di projects/<name>/.env. switch.sh menyalinnya ke root repo, menghentikan project lama, dan menjalankan project baru.
Ingat: pindah project dengan ./switch.sh <name>. Setiap project menyimpan datanya sendiri.
./switch.sh tutorial
Membaca projects/tutorial/.env (atau .env.<variant>).
Salin ke ./.env
Perintah docker compose biasa sekarang melihat project yang sama.
docker compose down project lama
Diambil dari .current-project.
docker compose up -d
Mem-build image saat pertama kali, lalu menjalankannya.
Karena COMPOSE_PROJECT_NAME berubah, setiap project punya volume odoo-web-data dan odoo-db-data sendiri. Pindah project berarti pindah filestore dan database.
Apa yang dilakukan container sebelum Odoo jalan
Image sengaja dijalankan sebagai root, memperbaiki permission, lalu turun ke user odoo. Setelah itu env var diubah menjadi flag CLI dan menunggu Postgres siap.
Ingat: entrypoint menambahkan flag database untukmu, jadi selalu lewati entrypoint.
Petakan ulang uid/gid
odoo memakai id pemilik /mnt/extra-addons, jadi file yang ditulis Odoo (scaffold) tetap milikmu di host.
Perbaiki /var/lib/odoo
Cek cepat; chown -R hanya jika ada kepemilikan yang salah.
Turunkan hak akses
setpriv --reuid=odoo menjalankan ulang script sebagai odoo.
Env menjadi flag
HOST PORT USER PASSWORD menjadi --db_host .... Nilai di odoo.conf yang menang.
Tunggu Postgres
wait-for-psql.py --timeout=30. Dilewati untuk odoo scaffold.
Jalankan Odoo
Biasa, atau dibungkus debugpy sesuai DEBUG_MODE.
Dari folder kosong sampai Odoo berjalan
Jalankan dari root odoo-containers. up pertama kali mem-build image, butuh beberapa menit.
Buka http://localhost:8069, buat database bernama tutorial dengan master password dari config/odoo.conf, lalu tambahkan ?debug=1 di URL.
Lakukan ini
- Buat
projects/tutorial/addonsdan.envproject-nya. - Jalankan
./switch.sh tutorial. - Buka
http://localhost:8069dan buat databasetutorial.
Berhasil jika
Log menampilkan HTTP service (werkzeug) running dan browser menampilkan database manager.
Jika gagal
wait-for-psqltimeout- Container db tidak jalan. Tambahkan
COMPOSE_PROFILES=local-dbke.envproject. port is already allocated- Ada Odoo lain yang memakai 8069. Hentikan, atau ganti
ODOO_PORT. - Build gagal di
COPY src/odoo-19e - Checkout Enterprise tidak ada di
ENTERPRISE_SRC.
Perintah yang akan kamu ketik sepanjang minggu
Pakai docker compose run --rm odoo ... untuk perintah Odoo sekali jalan. Perintah ini lewat entrypoint.sh, jadi flag database otomatis ditambahkan.
Ingat: run --rm untuk perintah sekali jalan, restart untuk Python, -u untuk XML.
Di VS Code, petakan /mnt/extra-addons ke ${workspaceFolder}/projects/tutorial/addons di pathMappings debugpy supaya breakpoint cocok.
Dari laptop baru sampai kembali coding
Snippet ini mengikuti repo odoo-containers: Odoo 19.0, PostgreSQL 15, project tutorial, dan terminal Bash. Buka langkah yang dibutuhkan lalu tekan Salin; tidak perlu memutar animasi.
Pilih alurnya: project baru: 01–04. Kembali coding: 05–06. Pindah laptop: 07 di laptop lama, lalu 01–02 dan 08 di laptop baru. Tidak punya akses Enterprise? Pakai . Ada yang error? Buka .
01Cek alat di laptop baru
Gunakan terminal Bash di Linux / WSL2, atau Bash di macOS. Instal Git, OpenSSL, serta Docker Engine + Compose plugin atau Docker Desktop. Docker harus sedang berjalan. Semua langkah berikut memakai project tutorial dan Odoo 19.0; migrasi harus memakai versi Odoo yang sama dengan laptop lama.
02Ambil repo dan source Enterprise
Untuk checkout baru. Masukkan URL repo odoo-containers milikmu saat diminta. Akses GitHub Enterprise Odoo diperlukan. Layout Enterprise di bawah mengikuti bind mount dan Dockerfile repo ini. Setelah cd, jalankan semua snippet berikut dari root odoo-containers. Untuk migrasi, gunakan commit repo, addons, dan Enterprise yang sama dengan laptop lama.
03Buat konfigurasi untuk project baru
Hanya untuk instalasi baru: snippet ini menulis projects/tutorial/.env dan config/odoo.conf. Untuk migrasi, pulihkan file konfigurasi lama dari arsip pada langkah 08. Password PostgreSQL dibuat acak; master password di odoo.conf berbeda dari password database dan login Odoo. Simpan master password di password manager. Port 5432, 8069, 8072, dan 5678 harus tersedia.
04Build, jalankan, lalu buat database
Build memakai ENTERPRISE_SRC secara eksplisit karena Compose repo ini hanya meneruskan ODOO_VERSION sebagai build arg. Setelah kedua service berjalan, buka http://localhost:8069/web/database/manager. Untuk instalasi baru, buat database tutorial memakai admin_passwd dari config/odoo.conf. Untuk migrasi, jangan buat database kosong; lanjutkan restore langkah 08.
05Kembali coding: scaffold, instal, upgrade, shell
Jalankan hanya blok yang dibutuhkan, dari root repo dengan project tutorial aktif. Scaffold hanya sekali jika folder estate belum ada. Instal/upgrade menghentikan web sementara untuk menghindari dua proses menulis schema yang sama. Jika perintah gagal, baca log lalu jalankan docker compose up -d odoo setelah masalah selesai.
06Pasang breakpoint di VS Code
Buka root odoo-containers sebagai workspace VS Code, instal ekstensi Python Debugger, lalu simpan JSON ini sebagai .vscode/launch.json (gabungkan configurations jika file sudah ada). Ubah DEBUG_MODE=on di projects/tutorial/.env dan jalankan bash ./switch.sh tutorial. Pilih Attach Odoo lalu F5. Port 5678 di sini sesuai contoh .env.
07Laptop lama: backup database, filestore, dan kode
Khusus project tutorial dengan database tutorial dan Postgres local-db yang sedang berjalan. Aktifkan project itu dulu. ZIP Odoo menyertakan database dan filestore; arsip kedua menyimpan addons (termasuk perubahan belum di-commit) serta konfigurasi. Web dihentikan sementara agar backup konsisten. Folder backup berisi data dan password: pindahkan secara privat. Jika ADDONS_DIR menunjuk folder lain, sertakan folder tersebut secara terpisah. Jangan gunakan docker compose down -v untuk migrasi.
08Laptop baru: pulihkan dan lanjutkan pekerjaan
Siapkan tools dan checkout source yang sama lewat langkah 01–02. Salin seluruh isi folder backup bertanggal dari laptop lama ke backups/migration/ di root repo baru. Jalankan di checkout baru: ekstraksi menimpa konfigurasi contoh dengan konfigurasi lama. Source Enterprise harus sesuai commit di enterprise-commit.txt; jika ada modifikasi Enterprise lokal di laptop lama, pindahkan juga. Restore memakai nama tutorial_restored sehingga tidak menimpa database tutorial. --neutralize menonaktifkan aktivitas otomatis untuk salinan development. Ini migrasi laptop pada versi Odoo yang sama, bukan upgrade database lintas versi.
09Opsional: ubah view XML tanpa -u
Dengan --dev xml, Odoo membaca arch view langsung dari file, jadi perubahan tampilan cukup di-refresh. File ini berlaku untuk semua project di repo; hapus jika tidak dipakai. Perubahan field Python tetap butuh -u.
Referensi: Instalasi Docker Compose · Odoo 19 CLI: backup dan restore · Debug Python di VS Code.
Tidak punya akses Enterprise? Pakai image jadi
Jalur B memakai docker-compose.simple.yml: image yang sudah di-build tim ditarik dari registry, tanpa source Enterprise di laptopmu. Cocok untuk mulai belajar. Untuk debugging dengan breakpoint, pakai Jalur A.
Ingat: jalur ini tidak memakai switch.sh. Setiap perintah compose butuh -f docker-compose.simple.yml --env-file projects/tutorial/.env.pull; alias dcs di langkah B4 menyingkatnya.
| Hal | Jalur A · build lokal | Jalur B · pull image |
|---|---|---|
| Source Enterprise di laptop | Wajib (src/odoo-19e) | Tidak perlu |
| Postgres | Container db (profile local-db) | Di host, port 5432 |
| Port yang dibuka | 8069, 8072, 5678 | 8069 saja (tanpa debugpy) |
| Config | ./config di-mount | odoo.conf bawaan image |
| Perintah | ./switch.sh tutorial | dcs up -d (alias di bawah) |
B1Siapkan folder dan login ke registry
Jalankan dari root odoo-containers. Alamat registry dan akun login diberikan tim; registry.example.com hanya contoh.
Berhasil jika: muncul Login Succeeded.
B2Siapkan Postgres di port 5432
docker-compose.simple.yml tidak meneruskan DB_PORT, jadi Odoo selalu menghubungi port 5432 di host. Cek dulu apakah port itu sudah dipakai:
Opsi 1, port kosong: jalankan Postgres 15 sebagai container terpisah. Datanya tersimpan di volume pg-tutorial-data.
Opsi 2, sudah ada Postgres di host: pakai Postgres itu dan buat role odoo. Postgres juga harus menerima koneksi dari network Docker: set listen_addresses = '*' di postgresql.conf, tambahkan baris host all odoo 172.16.0.0/12 scram-sha-256 di pg_hba.conf, lalu restart Postgres.
Berhasil jika: ss -ltn | grep ':5432 ' menampilkan satu baris.
B3Simpan file env Jalur B
Ganti REGISTRY_HOST dan IMAGE_NAME sesuai info tim. Tombol Salin perintah buat file menghasilkan satu perintah untuk ditempel di terminal; file yang sudah ada tidak ditimpa.
B4Pull image dan jalankan
Alias dcs berlaku di terminal yang sedang terbuka. Tambahkan baris alias ke ~/.bashrc jika ingin permanen.
Berhasil jika: log memuat HTTP service (werkzeug) running dan http://localhost:8069 menampilkan database manager. Master password adalah admin_passwd di odoo.conf yang dipakai saat image di-build; tanyakan ke tim.
B5Coding: instal dan upgrade module
Sama seperti resep 05, tetapi lewat dcs. Perintah run tetap melewati entrypoint.sh, jadi flag database ditambahkan otomatis.
Ada yang tidak jalan? Mulai dari sini
Jalankan odoo-doctor dulu: script ini hanya membaca (tidak menjalankan up, down, atau build) dan menunjuk langkah yang rusak. Setelah itu cocokkan gejala di bawah.
Jalankan odoo-doctor
Simpan script di root odoo-containers, lalu jalankan sesuai jalurmu. Setiap baris [GAGAL] diikuti saran perbaikan.
01Odoo restart terus atau wait-for-psql timeout
Odoo tidak menemukan Postgres dalam 30 detik.
Solusi: Jalur A: pastikan COMPOSE_PROFILES=local-db ada di projects/tutorial/.env, lalu ./switch.sh tutorial. Jalur B: pastikan Postgres jalan di port 5432 (resep B2) dan menerima koneksi dari network Docker.
02port is already allocated
Container lain sudah memakai port yang sama.
Solusi: hentikan project lain dengan docker compose down (data aman di volume), atau ganti ODOO_PORT di env file lalu jalankan ulang.
03Module tidak muncul di Apps
Pastikan folder module terlihat di dalam container:
Solusi: aktifkan developer mode (?debug=1), klik Update Apps List, hapus filter Apps bawaan. Jika folder tidak terlihat, PROJECT_DIR di env file salah.
04Perubahan kode tidak muncul
Python ada di memori server, view dan menu ada di database.
Solusi: ubah method Python: docker compose restart odoo. Tambah field, ubah XML atau CSV: upgrade dengan -u estate (resep 05). Lihat juga scene
05Permission denied di folder addons
entrypoint.sh menyesuaikan user odoo dengan pemilik folder addons. Jika folder dibuat dengan sudo, pemiliknya root.
Solusi: kembalikan kepemilikan ke user-mu, lalu restart:
06Build gagal: source Enterprise tidak ditemukan
Dockerfile.bundled menyalin src/odoo-19e/odoo/addons ke dalam image.
Solusi: ambil source lewat resep 02, atau pakai jika tidak punya akses.
07Breakpoint tidak pernah berhenti
Debugger hanya bisa attach ke container web yang jalan dengan DEBUG_MODE=on.
Solusi: set DEBUG_MODE=on di projects/tutorial/.env, jalankan ./switch.sh tutorial, lalu F5 di VS Code (resep 06). Pastikan pathMappings menunjuk ke projects/tutorial/addons. Jalur B tidak membuka port debugpy.
08docker compose exec odoo odoo ... tidak bisa ke database
exec melewati entrypoint.sh, padahal di situlah flag --db_host dan kawan-kawannya ditambahkan.
Solusi: pakai docker compose run --rm odoo ... seperti di resep 05.
Hati-hati: docker compose down -v menghapus volume, termasuk database dan filestore. Untuk berhenti biasa, pakai docker compose down tanpa -v.
Empat hal yang sering bikin tersandung di hari pertama
exec melewati entrypoint
docker compose exec odoo odoo -u estate berjalan tanpa flag --db_*, dan odoo.conf tidak punya db_host, jadi tidak bisa terhubung ke Postgres. Pakai run --rm.
Container database tidak ada?
Service db hanya jalan dengan profile local-db, sedangkan switch.sh menjalankan up -d biasa. Tambahkan COMPOSE_PROFILES=local-db di .env project, atau jalankan docker compose --profile local-db up -d.
Enterprise di-mount :ro
Jangan pernah mengubah core atau Enterprise. Perluas dari module-mu sendiri dengan _inherit dan view inheritance (chapter 12).
Versi harus cocok dengan source
ODOO_VERSION harus sama dengan versi mayor ENTERPRISE_SRC. Image 19.0 dengan src/odoo-18e akan gagal memuat module.
Cek pemahamanmu
Pilih jawaban untuk melihat penjelasannya. Tidak ada nilai; jawabanmu hanya tersimpan di browser ini.
1. Di mana folder estate ditaruh?
Folder itu di-bind-mount ke /mnt/extra-addons, yang ada di addons_path. Folder Enterprise read-only.
2. docker compose exec odoo odoo -u estate tidak bisa terhubung ke database. Apa solusinya?
exec melewati entrypoint.sh, padahal di situlah flag --db_host dan kawan-kawannya ditambahkan.
3. Setelah ./switch.sh tutorial, container db tidak pernah jalan. Kenapa?
Service db termasuk profile local-db. Tambahkan COMPOSE_PROFILES=local-db ke .env project.
Lima belas chapter, satu aplikasi Real Estate
Tutorial resmi ini membangun estate: properti yang dijual, tipe dan tag-nya, serta penawaran dari pembeli. Setiap chapter menambah satu konsep framework. Klik sebuah chapter untuk langsung ke sana.
Chapter 2 Aplikasi baru
Dua file sudah jadi module
Buat estate/ di dalam projects/tutorial/addons. __init__.py boleh kosong dulu; __manifest__.py minimal berisi name. application: True membuatnya muncul di filter Apps bawaan.
Restart, buka Apps, klik Update Apps List (hanya di developer mode), cari estate, lalu instal. Isinya masih kosong: belum ada menu.
Lakukan ini
- Buat
estate/__init__.py(kosong) danestate/__manifest__.py. - Restart:
docker compose restart odoo. - Apps, lalu Update Apps List, cari
estate, Activate.
Berhasil jika
Real Estate muncul di Apps dan terinstal tanpa error.
Jika gagal
- Module tidak muncul
- Aktifkan developer mode (
?debug=1), klik Update Apps List, hapus filter Apps bawaan. - Masih tidak muncul
- Pastikan folder ada di
projects/tutorial/addons, folder yang di-mount ke/mnt/extra-addons.
Chapter 3 Model dan field dasar
Class Python menjadi tabel
Class yang mewarisi models.Model dipetakan ORM ke tabel PostgreSQL. _name estate.property menjadi tabel estate_property; setiap field menjadi kolom.
Hubungkan: estate/__init__.py berisi from . import models, dan models/__init__.py berisi from . import estate_property. Lalu restart dengan -u estate.
\d estate_property | ||
|---|---|---|
name | varchar | not null |
description | text | |
postcode | varchar | |
date_availability | date | |
expected_price | double precision | not null |
selling_price | double precision | |
bedrooms ... garden_area | integer / boolean | |
garden_orientation | varchar | |
id | integer (serial) | otomatis |
create_uid, create_date | int / timestamp | otomatis |
write_uid, write_date | int / timestamp | otomatis |
Lakukan ini
- Tulis
models/estate_property.pydengan ke-13 field-nya. - Impor:
from . import models, lalufrom . import estate_property. - Upgrade:
docker compose run --rm odoo -d tutorial -u estate --stop-after-init.
Berhasil jika
docker compose exec db psql -U odoo tutorial -c '\d estate_property' menampilkan kolom-kolomnya, dengan name dan expected_price not null.
Jika gagal
- Tabel tidak terbentuk
- Ada import yang terlewat di salah satu dari dua file
__init__.py. The model estate.property has no _description- Tambahkan
_descriptionke class.
Chapter 4 Security, pengenalan singkat
Tanpa hak akses, tanpa akses
Model tanpa record ir.model.access tidak bisa dilihat siapa pun, dan log akan memberitahumu. Hak akses adalah data, dimuat dari CSV yang tercantum di manifest.
model_estate_property | External ID model: model_ + _name dengan titik diganti underscore. |
base.group_user | User internal. Kosongkan untuk akses global. |
1,1,1,1 | read, write, create, unlink (hapus). |
Tambahkan "security/ir.model.access.csv" ke data di manifest, restart dengan -u estate, dan warning-nya hilang.
Lakukan ini
- Buat
security/ir.model.access.csvdengan satu baris untukestate.property. - Cantumkan paling awal di
datamanifest. - Upgrade dengan
-u estate.
Berhasil jika
Warning have no access rules tidak muncul lagi di docker compose logs odoo.
Jika gagal
- Warning masih muncul
- CSV belum dicantumkan di
data, jadi tidak pernah dimuat. No matching record found for external id 'model_estate_property'- Salah ketik di
model_id/id: formatnyamodel_ditambah nama model dengan underscore.
Chapter 5 Akhirnya, ada UI untuk dicoba
Menu, lalu action, lalu model
Sebuah menu item membuka window action; action menentukan model mana yang ditampilkan dan dengan view mode apa. Selama belum ada view custom, Odoo membuat view default.
Real Estate / Advertisements / Properties
estate_property_action
estate.property
Lakukan ini
- Tambahkan action di
views/estate_property_views.xml. - Tambahkan tiga level menu di
views/estate_menus.xml. - Tambahkan atribut field,
active, danstate, lalu-u estate.
Berhasil jika
Aplikasi Real Estate muncul, kamu bisa membuat properti, dan hasil duplikat punya tanggal ketersediaan yang kosong.
Jika gagal
External ID not found in the system: estate.estate_property_action- File menu dimuat sebelum file view. Tukar urutannya di
data. - Menu tidak muncul
- Refresh browser setelah upgrade.
Chapter 6 View dasar
View list, form, dan search
View adalah record ir.ui.view dengan arch XML. Sejak Odoo 18, tag root list view adalah <list>; kode dan tutorial lama memakai <tree>. Filter memakai domain; group by memakai context.
| Title | Postcode | Bedrooms | Living (m²) | Expected |
|---|---|---|---|---|
| Big Villa | 12345 | 6 | 100 | 1,600,000 |
| Trailer home | 54321 | 1 | 10 | 100,000 |
| Canal house | 12345 | 3 | 140 | 780,000 |
Big Villa
| 12345 (2) | |
| Big Villa | 1,600,000 |
| Canal house | 780,000 |
| 54321 (1) | |
| Trailer home | 100,000 |
Sedang bolak-balik merapikan form? Jalankan server dengan --dev xml supaya perubahan view dibaca langsung dari file tanpa -u. Di stack kita: buat docker-compose.override.yml dengan command: ["odoo", "--dev", "xml"] pada service odoo.
Lakukan ini
- Tambahkan view list, form, dan search ke
estate_property_views.xml. - Tambahkan filter Available dan group by Postcode.
- Upgrade dengan
-u estate, atau pakai--dev xmlselama iterasi.
Berhasil jika
List menampilkan kolom-kolommu, form punya tab, dan filter Available serta Group by Postcode berfungsi.
Jika gagal
- Halaman masih menampilkan view default
- XML belum dimuat ulang. Upgrade dengan
-u estate. - Error XML saat upgrade
- Log menyebutkan file dan barisnya. Biasanya tag yang belum ditutup atau field yang tidak ada di model.
Chapter 7 Relasi antar model
Empat tetangga baru untuk estate.property
Tiga jenis field relasi, tiga bentuk yang sangat berbeda di database.
estate.property
Semua relasi di bawah dideklarasikan di sini.
estate.property.type
property_type_id di estate_propertyres.partner · res.users
self.env.user.estate.property.tag
estate_property_estate_property_tag_relestate.property.offer
property_id di offerSetiap model baru butuh barisnya sendiri di ir.model.access.csv, plus menu dan view-nya. Tutorial menjadikan ini latihan rangkuman.
Lakukan ini
- Buat model
estate.property.type,.tag, dan.offerbeserta view-nya. - Tambahkan lima field relasi ke
estate.property. - Satu baris hak akses per model baru, lalu
-u estate.
Berhasil jika
Form properti punya type, buyer, salesperson (default-nya kamu), tag berbentuk chip, dan tab Offers.
Jika gagal
You are not allowed to accesspada model baru- Model itu butuh barisnya sendiri di
ir.model.access.csv. - Tag tampil sebagai tabel
- Tambahkan
widget="many2many_tags"di view.
Chapter 8 Computed field dan onchange
Field yang terisi sendiri
Computed field dihitung ulang saat field yang tercantum di @api.depends berubah. Onchange hanya jalan di form, saat user mengetik, dan mengusulkan nilai yang masih bisa diubah user. Method compute menerima recordset, itu sebabnya ada loop atas self.
Properti baru yang masih kosong.
Living area diisi: total_area dihitung ulang.
Garden dicentang: onchange mengisi 10 m² dan North, total ikut berubah.
Dua penawaran masuk: best_price mengikuti offer_ids.price.
Offer memakai ide yang sama dengan inverse: isi validity atau date_deadline, yang satunya menyesuaikan.
Lakukan ini
- Tambahkan compute
total_areadanbest_price. - Tambahkan
validitydandate_deadlinedi offer, dengan inverse. - Tambahkan onchange
garden, lalu restart.
Berhasil jika
Total area dan best offer ter-update saat kamu mengetik; mencentang Garden mengisi 10 m² dan North.
Jika gagal
- Nilai compute tidak pernah berubah
- Ada field yang dipakai tapi tidak tercantum di
@api.depends. column ... does not exist- Kamu menambah stored field tanpa upgrade. Jalankan
-u estate.
Chapter 9 Siap beraksi?
Tombol yang menjalankan logika bisnis
Tombol dengan type="object" memanggil method Python publik yang disebut di name. Sedangkan type="action" membuka action berdasarkan external ID.
New
Offer Received
Offer Accepted
Sold
Cancelled
Siklus hidup sebuah properti.
Diiklankan.
Seorang pembeli mengajukan penawaran.
Accept pada offer menyalin harganya ke selling_price dan partner-nya ke buyer_id.
Tombol Sold, action_sold().
Properti lain, dibatalkan saat masih New. Menjualnya sekarang memunculkan error kebalikannya.
Lakukan ini
- Tambahkan tombol Sold dan Cancel di
<header>form. - Tulis
action_solddanaction_cancel, yang me-raiseUserError. - Tambahkan Accept dan Refuse di offer.
Berhasil jika
Properti yang dibatalkan tidak bisa dijual, yang terjual tidak bisa dibatalkan, dan menerima offer mengisi buyer serta selling price.
Jika gagal
Private methods ... cannot be called remotely- Method tombol tidak boleh diawali underscore.
action_sold is not a valid action on estate.propertynametombol harus sama dengan method publik di model. Odoo memeriksanya saat view dimuat, jadi upgrade-nya gagal.
Chapter 10 Constraint
Dua gerbang untuk data yang salah
SQL constraint dijaga oleh PostgreSQL dan paling cepat. Python constraint menangani aturan yang tidak bisa diungkapkan SQL. Di Odoo 19, SQL constraint dideklarasikan sebagai atribut models.Constraint, menggantikan list _sql_constraints yang lama.
Lakukan ini
- Tambahkan
models.Constraintuntuk harga positif dan nama unik. - Tambahkan
@api.constrains90% denganfloat_compare. - Upgrade dengan
-u estate.
Berhasil jika
Harga negatif, tag ganda, dan offer di bawah 90% semuanya ditolak dengan pesan yang jelas.
Jika gagal
- Upgrade mencatat error constraint
- Ada baris lama yang melanggar aturan baru. Perbaiki atau hapus, lalu upgrade lagi.
- Aturan Python tidak terpicu
- Cantumkan semua field yang dicek di
@api.constrains.
Chapter 11 Tambahkan pemanis
Mempercantik tanpa model baru
Widget, tampilan bersyarat, urutan, warna, dan stat button. Sejak Odoo 17, kondisi ditulis sebagai ekspresi mirip Python langsung di invisible dan readonly; attrs yang lama sudah dihapus.
statusbar widget
Tampilan bersyarat
Urutan
Decoration dan opsi list
Filter default
Di action: filter Available dari chapter 6 langsung aktif saat list dibuka.
Stat button
Lakukan ini
- Statusbar,
invisible, danreadonlydi tombol dan field. - Urutan, decoration, filter default, kolom opsional.
- Inline list dan stat button di property type.
Berhasil jika
Tombol tersembunyi sesuai state, baris list berwarna, dan Available aktif saat list dibuka.
Jika gagal
- Error
attrs - Sejak Odoo 17, tulis kondisinya langsung:
invisible="not garden". - Stat button tidak menampilkan apa-apa
offer_countbutuh compute dan harus ada di view.
Chapter 12 Inheritance
Perluas, jangan pernah edit
Tiga level: override method CRUD dengan super(), perluas model yang sudah ada dengan _inherit, dan tambal view yang sudah ada dengan inherit_id + xpath. Registry menumpuk semua perluasan menjadi satu class akhir.
basemailestatesatu class, semua fieldSelalu panggil super() dan kembalikan apa yang dikembalikan parent. Teks tutorial menulis create dengan @api.model; core Odoo 19 memakai @api.model_create_multi untuk create sekaligus banyak, seperti di atas.
Lakukan ini
- Tambahkan pengaman
@api.ondeletedan overridecreatedi offer. - Perluas
res.usersdimodels/res_users.py. - Inherit
base.view_users_formdengan xpath.
Berhasil jika
Properti yang terjual tidak bisa dihapus, offer baru mengubah status jadi Offer Received, dan form user menampilkan tab properti.
Jika gagal
- Record tidak lagi terbentuk
- Override lupa
return super().create(vals_list). cannot be located in parent view- Xpath tidak menemukan apa pun. Cek arch view parent di developer mode.
Chapter 13 Berinteraksi dengan module lain
Module penghubung menambahkan invoicing
Sebagian agensi butuh invoicing, sebagian tidak. Jadi estate tetap mandiri, dan module kecil estate_account bergantung pada estate dan account, lalu meng-override action_sold.
Lakukan ini
- Buat
estate_accountyang bergantung padaestatedanaccount. _inheritestate.propertydan overrideaction_sold.- Instal, lalu jual sebuah properti.
Berhasil jika
Menjual properti membuat draft customer invoice berisi baris 6% dan biaya 100.00.
Jika gagal
- Override tidak pernah jalan
- Module belum terinstal, atau
modelsbelum diimpor di__init__.py-nya. partner_idkosong- Terima sebuah offer dulu supaya properti punya buyer.
Chapter 14 Sekilas tentang QWeb
Kartu kanban dengan QWeb
QWeb adalah bahasa template XML milik Odoo, dipakai untuk report, website, dan kartu kanban. Kanban view mendefinisikan template bernama card; t-if hanya menampilkan bagian yang relevan.
House 2
Apartment 1
Tambahkan kanban ke view_mode action: list,form,kanban.
Lakukan ini
- Tambahkan kanban view dengan template
card. - Tampilkan harga dengan
t-if, tambahkan tag. - Tambahkan
kanbankeview_mode, group by type, matikan drag.
Berhasil jika
Tombol Kanban muncul dan kartu dikelompokkan per property type.
Jika gagal
- Tidak ada tombol kanban
kanbanbelum ada diview_modeaction.t-iftidak pernah bernilai true- Bandingkan
record.state.raw_value, dan deklarasikanstatesebagai field di view.
Cek pemahamanmu
Pilih jawaban untuk melihat penjelasannya. Tidak ada nilai; jawabanmu hanya tersimpan di browser ini.
1. Decorator mana yang membuat total_area dihitung ulang saat living_area berubah?
@api.depends menyatakan dari field apa sebuah computed field dibentuk. @api.onchange hanya jalan di form saat user mengedit.
2. Setiap nama tag harus unik. Alat apa yang paling tepat?
PostgreSQL menjaga SQL constraint di setiap penulisan, termasuk impor dan user yang bekerja bersamaan, dan lebih cepat daripada Python.
3. Bagaimana cara menambah field ke res.users?
_inherit tanpa _name baru memperluas model yang sudah ada di tempatnya. Core tetap utuh dan upgrade tetap lancar.
Chapter 15 Penutup
Yang sudah kamu bangun
Dua module, lima model, alur kerja lengkap dengan penawaran, validasi, invoicing, dan papan kanban. Seperti itulah sebagian besar pekerjaan backend Odoo sehari-hari.
Tulis test
TransactionCase di estate/tests/, jalankan dengan docker compose run --rm odoo -d tutorial -u estate --test-tags /estate --stop-after-init.
Pelajari framework JS
Tutorial resmi berikutnya: komponen OWL dan web client.
Baca module core
Buka src/odoo-19e/odoo/addons/crm atau sale. Semua tips di tutorial mengarah ke sana.