Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions awesome_estate/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import models
16 changes: 16 additions & 0 deletions awesome_estate/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
'name': 'Awesome Estate',
'version': '0.1',
'category': 'Tutorials',
'summary': 'Real Estate Advertisement tutorial module (empty shell)',
'author': 'Patja',
'license': 'LGPL-3',
'depends': ['base'],
'data': [
'security/ir.model.access.csv',
'views/awesome_estate_property_views.xml',
'views/awesome_estate_property_type_views.xml',
],
'application': True,
'installable': True,
}
25 changes: 25 additions & 0 deletions awesome_estate/docs/chapter_2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Chapter 2

## Module dependency

`base`

- My module needs Odoo core to be installed first.

### Where `base` lives in this repo

`community/odoo/addons/base/`

### What `base` provides

- Fundamental UI framework pieces and security bootstrap.
- Core records like languages, users, partners, currencies, companies, and countries.
- Base security, group, and access basics (Chapter 4).

### Why my module depends on it

Without `base`, Odoo is missing the required core models, configuration, and security layer, so my module cannot install safely.

### Notes

`application: true` suggests that this is an installable app, and `false` means it is a module.
56 changes: 56 additions & 0 deletions awesome_estate/docs/chapter_3.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# How fields are converted to the database

- `fields.Char` → `varchar` if a size is set, otherwise `text`
- `fields.Text` → `text`
- `fields.Integer` → `int4` (PostgreSQL integer)
- `fields.Float` → `numeric` with precision, or `float8` if no digits are set
- `fields.Boolean` → `bool`
- `fields.Date` → `date`
- `fields.Datetime` → `timestamp` without timezone (UTC)
- `fields.Selection` → `varchar` (stores the internal key string)
- `fields.Many2one` → `int4` (foreign key)
- `fields.Binary` → `bytea` if not attachment-backed, otherwise stored in `ir.attachment`
- `fields.Html` → `text`
- `fields.Monetary` → `numeric` linked to a currency

---

## Blueprint, methods, and required fields

- `class` = blueprint
- `methods` = functions
- `required=True` translates to `NOT NULL` in SQL

---

## Module namespace vs business concept

- `awesome_estate` is the module namespace prefix
- `property` is the business concept inside that module

So the technical model name becomes `awesome_estate.property`.

---

## Selection: key vs label

- **Key** / internal value stored in the database
- `"north"`, `"south"`, `"east"`, `"west"`

- **Label** / display value shown in the UI
- `"North"`, `"South"`, `"East"`, `"West"`

---

## Chapter 3 verification

### 1) Upgrade or install the module
`/home/odoo/odoo19/community/odoo-bin -d patja --addons-path=community/addons,enterprise,tutorials -u awesome_estate --stop-after-init`

### 2) Check the table and columns
`psql -d patja -c "\pset pager off" -c "\d awesome_estate_property"`

### 3) Check `required=True` becomes `NOT NULL`
`psql -d patja -c "\pset pager off" -c "SELECT column_name, is_nullable FROM information_schema.columns WHERE table_name='awesome_estate_property' AND column_name IN ('name', 'expected_price');"`

You should see `is_nullable = NO` for `name` and `expected_price`.
103 changes: 103 additions & 0 deletions awesome_estate/docs/chapter_4.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
# Security

- module: `awesome_estate`
- model: `awesome_estate.property`
- ACL file: `tutorials/awesome_estate/security/ir.model.access.csv`
- manifest entry: `data: ['security/ir.model.access.csv']`

If a model has no access rights, Odoo treats it as inaccessible and prints a warning in the logs.

---

1. **Access rights (ACLs)**
Model-level permissions:
- read
- write
- create
- unlink

2. **Groups**
ACLs are assigned to a group like `base.group_user`.

Common groups:
- `base.group_user` — internal backend users who can log into the Odoo backend
- `base.group_portal` — portal users who usually access the frontend and their own documents only
- `base.group_public` — public/anonymous users who are not logged in

Difference:
- internal users work in the backend and can use normal business screens
- portal users have limited frontend access
- public users have the least access and are typically anonymous visitors

3. **Record rules**
Used later to limit which records a group can see or edit.

For Chapter 4, the important part is ACLs.

---

## ACL file format

File: `tutorials/awesome_estate/security/ir.model.access.csv`

```csv
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_awesome_estate_property,access_awesome_estate_property,model_awesome_estate_property,base.group_user,1,1,1,1
```

### What each part means

- `id`
External ID of the access rule record.

- `name`
Human-readable name.

- `model_id:id`
Model the rule applies to.
For `awesome_estate.property`, the value is:
- `model_awesome_estate_property`

- `group_id:id`
Group that gets the permissions.
Here:
- `base.group_user`

- `perm_read`
Can read records.

- `perm_write`
Can edit records.

- `perm_create`
Can create records.

- `perm_unlink`
Can delete records.
In Odoo, `unlink` means delete.

### What this row gives

This row gives internal users in `base.group_user` full access to the model:

- read = 1
- write = 1
- create = 1
- unlink = 1

---

## Manifest wiring

File: `tutorials/awesome_estate/__manifest__.py`

```python
'data': ['security/ir.model.access.csv'],
```

Why this matters:

- Odoo only loads security data files if they are declared in the manifest.
- The file is loaded when the module is installed or upgraded.

---
48 changes: 48 additions & 0 deletions awesome_estate/docs/chapter_5.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Chapter 5 - First UI

## Action and Menus
- **Action (`ir.actions.act_window`)**: Connects a model to the UI, specifying view modes like `list,form`.
- **Menu Hierarchy**: 3 levels deep: Root Menu -> First Level Menu -> Action Menu.
- **Manifest Order**: XML files containing these UI definitions must be added to `__manifest__.py` under `data`. Data is loaded sequentially!

## Field Attributes
- `required=True`: Field cannot be empty. Translates to `NOT NULL` in the DB.
- `copy=False`: Prevents the field value from duplicating when a user clicks the "Duplicate" action on a record. Used for unique or situational data like `date_availability` or `selling_price`.
- `readonly=True`: Makes the field uneditable from the UI. E.g., `selling_price` updates programmatically when an offer is accepted, not by manual entry.

## Default Values
- Pre-populates a field logically when "New" is clicked.
- Can be a literal (`default=2`) or evaluated via an anonymous function.
- **Why use `lambda self:` for logic?**: If you say `default=date.today()`, Python computes it *once* when the Odoo server boots. Using `lambda self: date.today() + relativedelta(months=3)` evaluates dynamically at the *exact moment* the record is created.

## Reserved Fields
- **`active`**: Special boolean field. If `False`, the record is "Archived" and automatically hidden from standard searches (without deleting DB row).
- **`state`**: Selection field commonly used to drive business flow (e.g., New -> Offer Received -> Sold).

## Python / Odoo Conventions
- **String quotes (`''` vs `""`)**: Mechanically identical in Python. By Odoo / PEP 8 convention, use single quotes `''` for internal strings (keys, backend values) and double quotes `""` for UI text or docstrings.

## Selection Fields
Are lists of tuples acting as Key/Value pairs: `('north', 'North')`
- **Key (`'north'`)**: Backend identifier. Lower-case, internal logic, stored in DB.
- **Label (`'North'`)**: UI string. Shown to the user, can be translated easily.

## Date Imports
- `datetime.date`: Native module for server calendar dates (`date.today()`).
- `dateutil.relativedelta`: Robust utility that cleanly handles calendar leaps when calculating logic like `months=3`. Other periods supported: `years`, `months`, `weeks`, `days`, `hours`.

## Implementation Proof
All rules required by the Chapter 5 tutorial (readonly/copy overrides, dynamic default date, correctly formatted status options, active field implementation) have been applied exactly to specification in `awesome_estate_property.py`.

## Developer Setup Notes (`--dev`)
When executing and testing UI/view creations regularly, use the backend server command flag `--dev=all`. It auto-reloads your codebase so you bypass server restarts.
```bash
./odoo-bin -d patja -u awesome_estate --dev=all
```
**Common `--dev=` parameters:**
- `all`: Enables all developer configurations below.
- `reload`: Automatically bounces the python worker when Python code changes are detected.
- `qweb`: Forces QWeb templates/XML to read directly from disks instead of reading from the database caching engine. Highly recommended when editing views!
- `werkzeug`: Routes exceptions natively to the debug interactive debugger.
- `xml`: Validates XML files are structurally whole before trying to push them to PostgreSQL.

116 changes: 116 additions & 0 deletions awesome_estate/docs/chapter_6.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
# Chapter 6 - Basic Views

- Model file: `awesome_estate_property.py`
- View file: `awesome_estate_property_views.xml`
- Manifest file: `__manifest__.py`

The manifest loads the security file first and the views file after it.

---

## Odoo XML basics

- `<odoo>`: root tag of the XML file
- `<record>`: creates a database record
- `<field>`: sets a value on that record
- `model="ir.ui.view"`: this record is a view
- `arch`: XML layout of the view
- `type="xml"`: tells Odoo that `arch` is XML text

### View tags

- `<list>`: list view
- `<form>`: form view
- `<search>`: search view
- `<sheet>`: main form area
- `<group>`: field grouping
- `<notebook>`: tab container
- `<page>`: one tab inside a notebook

---

## Actions and menus

### Action
- XML ID: `awesome_estate_property_action`
- Model opened: `awesome.estate.property`
- View mode: `list,form`

An action tells Odoo which model to open and which views to use.

### Menus
Menu path:

- `Real Estate`
- `Properties`
- `Properties`

Menu IDs:

- `awesome_estate_root_menu`
- `awesome_estate_first_level_menu`
- `awesome_estate_property_menu`

The menu IDs are the technical names Odoo uses in XML.

### Database record example

| Record type | Example | What it does |
| --- | --- | --- |
| `ir.actions.act_window` | `awesome_estate_property_action` | Opens the property model |
| `ir.ui.menu` | `awesome_estate_property_menu` | Adds the menu entry |
| `ir.ui.view` | property list/form/search views | Defines the screen layout |

---

## `ir.ui.view`

`ir.ui.view` is the Odoo model that stores view definitions in the database.

### `arch`
`arch` is the actual XML layout stored inside the view record.

### Example
A view record like:

```xml
<record id="awesome_estate_property_view_list" model="ir.ui.view">
```

means:
- create a database record
- store it as a view
- give it an XML ID so other XML can reference it

---

## Inheritance

If we want to change an existing view, we use inheritance.

- `inherit_id`: points to the original view
- `xpath`: updates part of the XML without replacing the full view

That is how Odoo extends views cleanly.

---

## What I learned

- Python defines the model
- XML defines the UI
- `ir.ui.view` stores the UI in the database
- `arch` is the XML layout
- actions open models
- menus make the model reachable
- XML IDs connect records together
- inheritance lets us modify an existing view instead of rewriting it

---

## Quick verify

```bash
community/odoo-bin -d patja --addons-path=community/addons,enterprise,tutorials -u awesome_estate --dev xml
```

Loading