8000 fixup! chapter 5 - connect the dots · odoo/documentation@caaf822 · GitHub
[go: up one dir, main page]

Skip to content

Commit caaf822

Browse files
committed
fixup! chapter 5 - connect the dots
1 parent 6dfac46 commit caaf822

File tree

5 files changed

+162
-33
lines changed

5 files changed

+162
-33
lines changed

content/developer/tutorials/server_framework_101/04_relational_fields.rst

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -476,28 +476,32 @@ of the property and the salesperson managing the property.
476476
.. exercise::
477477
#. Add the following fields to the `real.estate.property` model:
478478

479-
- Seller (required): The person putting their property on sale; it can be any individual.
480-
- Salesperson: The employee of the real estate agency overseeing the sale of the property.
479+
- **Seller** (required): The person putting their property on sale; it can be any individual.
480+
- **Salesperson**: The employee of the real estate agency overseeing the sale of the property.
481+
- **Address** (required): The address of the property.
481482

482483
#. Modify the form view of properties to include a notebook component. The property description
483-
should be in the first page, and the two new fields should be in the second page.
484+
should be in the first page, and the three new fields should be in the second page.
484485

485486
.. tip::
486-
You don't need to define any new UI component to browse the seller you assigned to your
487-
default properties! Just go to :menuselection:`Apps` and install the :guilabel:`Contacts` app.
487+
- You don't need to define any new UI component to browse the seller you assigned to your
488+
default properties! Just go to :menuselection:`Apps` and install the :guilabel:`Contacts`
489+
app.
490+
- In Odoo, addresses are usually represented by a partner.
488491

489492
.. spoiler:: Solution
490493

491494
.. code-block:: python
492495
:caption: `real_estate_property.py`
493-
:emphasize-lines: 1-2
496+
:emphasize-lines: 1-3
494497
498+
address_id = fields.Many2one(string="Address", comodel_name='res.partner', required=True)
495499
seller_id = fields.Many2one(string="Seller", comodel_name='res.partner', required=True)
496500
salesperson_id = fields.Many2one(string="Salesperson", comodel_name='res.users')
497501
498502
.. code-block:: xml
499503
:caption: `real_estate_property_views.xml`
500-
:emphasize-lines: 3-18
504+
:emphasize-lines: 3-19
501505
502506
<record id="real_estate.property_form" model="ir.ui.view">
503507
[...]
@@ -511,6 +515,7 @@ of the property and the salesperson managing the property.
511515
<page string="Other Info">
512516
<group>
513517
<group>
518+
<field name="address_id"/>
514519
<field name="seller_id"/>
515520
<field name="salesperson_id"/>
516521
</group>
@@ -526,6 +531,30 @@ of the property and the salesperson managing the property.
526531
<?xml version="1.0" encoding="utf-8"?>
527532
<odoo>
528533
534+
<record id="real_estate.country_house_address" model="res.partner">
535+
<field name="name">Country House</field>
536+
<field name="street">Chaussée de Namur 40</field>
537< B422 code class="diff-text syntax-highlighted-line addition">+
<field name="city">Grand-Rosière-Hottomont</field>
538+
<field name="zip">1367</field>
539+
<field name="country_id" ref="base.be"/>
540+
</record>
541+
542+
<record id="real_estate.loft_address" model="res.partner">
543+
<field name="name">Loft</field>
544+
<field name="street">Rue des Bourlottes 9</field>
545+
<field name="city">Grand-Rosière-Hottomont</field>
546+
<field name="zip">1367</field>
547+
<field name="country_id" ref="base.be"/>
548+
</record>
549+
550+
<record id="real_estate.mixed_use_commercial_address" model="res.partner">
551+
<field name="name">Mixed use commercial building</field>
552+
<field name="street">Rue de Ramillies 1</field>
553+
<field name="city">Grand-Rosière-Hottomont</field>
554+
<field name="zip">1367</field>
555+
<field name="country_id" ref="base.be"/>
556+
</record>
557+
529558
<record id="real_estate.bafien_carpink" model="res.partner">
530559
<field name="name">Bafien Carpink</field>
531560
</record>
@@ -542,20 +571,23 @@ of the property and the salesperson managing the property.
542571
543572
.. code-block:: xml
544573
:caption: `real_estate_property_data.xml`
545-
:emphasize-lines: 3,8,13
574+
:emphasize-lines: 3-4,9-10,15-16
546575
547576
<record id="real_estate.country_house" model="real.estate.property">
548577
[...]
578+
<field name="address_id" ref="real_estate.country_house_address"/>
549579
<field name="seller_id" ref="real_estate.amyfromthevideos"/>
550580
</record>
551581
552582
<record id="real_estate.loft" model="real.estate.property">
553583
[...]
584+
<field name="address_id" ref="real_estate.loft_address"/>
554585
<field name="seller_id" ref="real_estate.antony_petisuix"/>
555586
</record>
556587
557588
<record id="real_estate.mixed_use_commercial" model="real.estate.property">
558589
[...]
590+
<field name="address_id" ref="real_estate.mixed_use_commercial_address"/>
559591
<field name="seller_id" ref="real_estate.bafien_carpink"/>
560592
</record>
561593

content/developer/tutorials/server_framework_101/05_connect_the_dots.rst

Lines changed: 114 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,6 @@ In this chapter, we'll add business logic to the models to automate the processe
66
and turn it into a dynamic and useful tool. This will involve defining actions, constraints,
77
automatic computations, and other model methods.
88

9-
.. todo: explain the env (self.env.uid, self.env.user, self.env.ref(xml_id), self.env[model_name])
10-
.. todo: explain magic commands
11-
.. todo: 6,0,0 to associate tags to properties in data
12-
.. todo: create (create offer -> offer received state) and write methods
13-
.. todo: auto-update property state based on received offers state (write)
14-
159
.. _tutorials/server_framework_101/computed_fields:
1610

1711
Automate field computations
@@ -95,6 +89,7 @@ that computed fields remain consistent.
9589
.. seealso::
9690
- :ref:`Reference documentation for computed fields <reference/fields/compute>`
9791
- :ref:`Reference documentation for recordsets <reference/orm/recordsets>`
92+
- Reference documentation for the :meth:`@api.depends() <odoo.api.depends>` decorator
9893
- :ref:`Coding guidelines on naming and ordering the members of model classes
9994
<contributing/coding_guidelines/model_members>`
10095

@@ -109,9 +104,9 @@ Let's implement them.
109104
- **Best Offer** (`real.estate.property`): The maximum amount of all offers.
110105

111106
.. tip::
112-
- Import the `odoo.tools.date_utils` package to simplify operations on `Date` fields.
113107
- Use the :meth:`mapped <odoo.models.Model.mapped>` method to extract a recordset's field
114108
values into a list.
109+
- Import the `odoo.tools.date_utils` package to simplify operations on `Date` fields.
115110

116111
.. spoiler:: Solution
117112

@@ -178,6 +173,50 @@ Let's implement them.
178173
[...]
179174
</record>
180175
176+
.. code-block:: python
177+
:caption: `real_estate_offer.py`
178+
:emphasize-lines: 1-2,9,12-15
179+
180+
from odoo import api, fields, models
181+
from odoo.tools import date_utils
182+
183+
class RealEstateOffer(models.Model):
184+
[...]
185+
validity = fields.Integer(
186+
string="Validity", help="The number of days before the offer expires.", default=7
187+
)
188+
expiry_date = fields.Date(string="Expiry Date", compute='_compute_expiry_date')
189+
[...]
190+
191+
@api.depends('date', 'validity')
192+
def _compute_expiry_date(self):
193+
for offer in self:
194+
offer.expiry_date = date_utils.add(offer.date, days=offer.validity)
195+
196+
.. code-block:: xml
197+
:caption: `real_estate_offer_views.xml`
198+
:emphasize-lines: 5,16
199+
200+
<record id="real_estate.offer_list" model="ir.ui.view">
201+
[...]
202+
<list>
203+
[...]
204+
<field name="expiry_date"/>
205+
<field name="state"/>
206+
</list>
207+
[...]
208+
</record>
209+
210+
<record id="real_estate.offer_form" model="ir.ui.view">
211+
[...]
212+
<group>
213+
[...]
214+
<field name="validity"/>
215+
<field name="expiry_date"/>
216+
</group>
217+
[...]
218+
</record>
219+
181220
.. _tutorials/server_framework_101/inverse_methods:
182221

183222
Make computed fields editable
@@ -193,10 +232,43 @@ To make a computed field editable, a Python method must be defined and linked to
193232
declaration using the `inverse` argument. This method specifies how updates to the computed field
194233
should be applied to its dependencies.
195234

196-
.. seealso::
197-
:ref:`Reference documentation for related fields <reference/fields/related>`
235+
.. example::
236+
In the example below, an inverse method is added to the `margin` field.
237+
238+
.. code-block:: python
239+
240+
margin = fields.Float(
241+
string="Profit Margin", compute='_compute_margin', inverse='_inverse_margin'
242+
)
243+
244+
def _inverse_margin(self):
245+
for product in self:
246+
# As the cost is fixed, the sales price is increased to match the desired margin.
247+
product.price = product.cost + product.margin
248+
249+
Now that we have seen how inverse methods make computed fields editable, let's put this concept in
250+
practice.
251+
252+
.. exercise::
253+
Make the Expiry Date field editable on real estate offers.
254+
255+
.. tip::
256+
You'll need to save the property form view to trigger the computation.
257+
258+
.. spoiler:: Solution
259+
260+
.. code-block:: python
261+
:caption: `real_estate_offer.py`
262+
:emphasize-lines: 1-3,6-8
198263
199-
.. todo: inverse: offer deadline
264+
expiry_date = fields.Date(
265+
string="Expiry Date", compute='_compute_expiry_date', inverse='_inverse_expiry_date'
266+
)
267+
[...]
268+
269+
def _inverse_expiry_date(self):
270+
for offer in self:
271+
offer.validity = date_utils.relativedelta(dt1=offer.expiry_date, dt2=offer.date).days
200272
201273
.. _tutorials/server_framework_101/store_computed_fields:
202274

@@ -221,9 +293,6 @@ large number of records.
221293
.. example::
222294
store `margin`
223295

224-
.. seealso::
225-
Reference documentation for the :meth:`@api.depends() <odoo.api.depends>` decorator
226-
227296
.. _tutorials/server_framework_101/search_methods:
228297

229298
Search computed fields
@@ -263,6 +332,9 @@ domain must be constructed using stored fields only.
263332
else:
264333
raise NotImplementedError()
265334
335+
.. todo: compute Stalled based on `today > availability date` -> search filter for stalled (below availability date)
336+
.. todo: compute Priority (star) == offer expires in <= 2 days -> search filter + groupby priority (separate group below for sale)
337+
266338
.. _tutorials/server_framework_101/related_fields:
267339

268340
Simplify related record access
@@ -281,7 +353,8 @@ argument, just like regular computed fields.
281353
.. seealso::
282354
:ref:`Reference documentation for related fields <reference/fields/related>`
283355

284-
.. todo: related fields (buyer's phone)
356+
.. todo: related buyer's phone
357+
.. todo: related address's street depends=[partner_id]
285358
286359
.. _tutorials/server_framework_101/onchanges:
287360

@@ -301,14 +374,23 @@ the :code:`@api.onchange()` decorator. These methods are triggered when the spec
301374
are altered. They operate on the in-memory representation of a single-record recordset received
302375
through `self`. If field values are modified, the changes are automatically reflected in the UI.
303376

377+
.. todo: explain the env (self.env.uid, self.env.user, self.env.ref(xml_id), self.env[model_name])
378+
304379
.. seealso::
305380
- Reference documentation for the :meth:`@api.onchange() <odoo.api.onchange>` decorator
306381
- Reference documentation for the :class:`UserError <odoo.exceptions.UserError>` exception
307382

383+
.. todo: tip ref translation
384+
308385
.. todo: raise UserError + translation
309-
.. todo: if garden checked -> show total area
310-
.. todo: mention that the method is public so it can be called directly by the client.
311-
.. todo: always return something in public methods as they are part of the :ref:external API and can be called through XML-RPC
386+
.. todo: note: mention that the method is public so it can be called directly by the client.
387+
always return something in public methods as they are part of the :ref:external API and can be called through XML-RPC
388+
389+
.. exercise::
390+
tmp
391+
392+
.. todo: if garden unchecked -> set garden area to zero
393+
.. todo: if write in garden area -> set garden checked
312394
313395
.. _tutorials/server_framework_101/constraints:
314396

@@ -347,8 +429,9 @@ expression to validate, and the error message to display if the constraint is vi
347429
- `Reference documentation for PostgreSQL's constraints
348430
<https://www.postgresql.org/docs/current/ddl-constraints.html>`_
349431

350-
.. todo: price more than zero
351-
.. todo: unique tag constraint
432+
.. todo: property price strictly positive
433+
.. todo: offer amount strictly positive
434+
.. todo: unique tag
352435
353436
.. _tutorials/server_framework_101/python_constraints:
354437

@@ -371,7 +454,10 @@ the constraint is violated.
371454
- Reference documentation for the :class:`ValidationError <odoo.exceptions.ValidationError>`
372455
exception
373456

457+
.. todo: the offer amount must be at least 80% of the sales price
458+
.. todo: the availability date must be in less than 3 months
374459
.. todo: accept only one offer
460+
.. todo: new offers of given user must be more than offers (tip: filtered)
375461
376462
.. _tutorials/server_framework_101/defaults:
377463

@@ -388,9 +474,9 @@ as a model method or a lambda function. In both cases, the `self` argument provi
388474
environment but does not represent the current record, as no record exists yet during the creation
389475
process.
390476

477+
.. todo: real.estate.offer.amount::default -> property.selling_price
391478
.. todo: salesperson_id = fields.Many2one(default=lambda self: self.env.user)
392479
.. todo: availability_date = fields.Date(default=lambda self: date_utils.add(fields.Date.today(), months=2))
393-
.. todo: real.estate.offer.amount::default -> property.selling_price (add related?)
394480
.. todo: real.estate.tag.color -> default=_default_color ; def _default_color(self): return random.randint(1, 11) (check if lambda works)
395481
.. todo: copy=False on some fields
396482
@@ -404,11 +490,8 @@ buttons can be of type **action**, defined in XML, or **object**, implemented in
404490
Together, these types of buttons facilitate the integration of user interactions with business
405491
logic.
406492

407-
.. todo: "assign myself as salesperson" action
408-
.. todo: "view best offer" statbutton
409-
.. todo: accept/refuse offer buttons
410-
.. todo: accepting offer refuses others
411-
.. todo: action name=...
493+
.. todo: def create of offer -> write state of the property to offer received
494+
.. todo: def unlink: _unlink_if_state_is_valid (new or cancelled)
412495
413496
.. _tutorials/server_framework_101/action_type_actions:
414497

@@ -430,6 +513,8 @@ attribute should reference the XML ID of the action to execute.
430513
<reference/view_architectures/form/button>` and :ref:`headers
431514
<reference/view_architectures/form/header>` in form views.
432515

516+
.. todo: "view offers" statbutton with count + remove notebook page of offers
517+
433518
.. _tutorials/server_framework_101/object_type_actions:
434519

435520
Model-defined actions
@@ -444,6 +529,10 @@ To link a button to a model-defined action, its `type` attribute must be set to
444529
method receives the current recordset through `self` and should return a dictionary acting as an
445530
action descriptor.
446531

532+
.. todo: accept/refuse offer buttons -> auto refuse others when accepting (write)
533+
.. todo: multi-checkbox refuse offers in bulk
534+
.. todo: "assign myself as salesperson" action
535+
447536
----
448537

449538
.. todo: add incentive for chapter 6

content/developer/tutorials/server_framework_101/06_security.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ Chapter 6: Tighten security
44

55
tmp
66

7+
.. todo: restrict access through acl
8+
.. todo: rule to only see your properties or unassigned ones
9+
710
----
811

912
.. todo: add incentive for next chapter

content/developer/tutorials/server_framework_101/07_advanced_views.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ tmp
99
.. todo: widgets; eg, <widget name="web_ribbon" title="Archived" bg_color="text-bg-danger" invisible="active"/>
1010
.. todo: add Gantt view of properties availability
1111
.. todo: add Kanban view of properties
12+
.. todo: wizards
1213
1314
----
1415

content/developer/tutorials/server_framework_101/08_inheritance.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ tmp
66

77
.. todo: inherit from mail.tread mixin and add a chatter
88
.. todo: self.env._context
9+
.. todo: explain magic commands
10+
.. todo: inherit from account.move
11+
.. todo: ex: create invoice with lines (6, 0, 0)
12+
.. todo: ex: 6,0,0 to associate tags to properties in data
913
1014
----
1115

0 commit comments

Comments
 (0)
0