Skip to content

18.0 tutorial module data aras #5

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 10 commits into
base: 18.0-tutorial-aras
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 9 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
Binary file added estate.zip
Binary file not shown.
9 changes: 7 additions & 2 deletions estate/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,16 @@
'data': [
'security/ir.model.access.csv',
'views/estate_property_views.xml',
'views/estate_property_type_views.xml',
'views/estate_property_tag_views.xml',
'views/estate_property_offer_views.xml',
'views/estate_property_type_views.xml',
'views/estate_menus.xml',
'views/res_users_views.xml'
'views/res_users_views.xml',
],
'demo': [
'demo/estate.property.type.csv',
'demo/estate_property.xml',
'demo/estate_property_offer.xml'
],
'installable': True,
'application': True,
Expand Down
5 changes: 5 additions & 0 deletions estate/demo/estate.property.type.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
"id","name"
"data_property_type_residential","Residential"
"data_property_type_commerial","Commerial"
"data_property_type_industrial","Industrial"
"data_property_type_land","Land"
62 changes: 62 additions & 0 deletions estate/demo/estate_property.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<odoo>
<record id="estate_property_1" model="estate.property">
<field name="name">Big Villa</field>
<field name="state">new</field>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As it is the default value, you're not forced to provide it

Suggested change
<field name="state">new</field>

<field name="description">A nice and big villa</field>
<field name="postcode">12345</field>
<field name="date_availability">2020-02-02</field>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should preferably be relative to the date of install (see codebase for examples)

<field name="expected_price">1600000</field>
<field name="bedrooms">6</field>
<field name="living_area">100</field>
<field name="facades">4</field>
<field name="garage">True</field>
<field name="garden">True</field>
<field name="garden_area">100000</field>
<field name="garden_orientation">south</field>
<field name="property_type_id" ref="data_property_type_residential"/>
</record>

<record id="estate_property_2" model="estate.property">
<field name="name">Trailer home</field>
<field name="state">cancelled</field>
<field name="description">Home in a trailer park</field>
<field name="postcode">54321</field>
<field name="date_availability">1970-01-01</field>
<field name="expected_price">100000</field>
<field name="selling_price">120000</field>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why a selling_price if the state is cancelled?

<field name="bedrooms">1</field>
<field name="living_area">10</field>
<field name="facades">4</field>
<field name="garage">False</field>
<field name="property_type_id" ref="data_property_type_residential"/>
</record>

<record id="estate_property_3" model="estate.property">
<field name="name">Tutorial House</field>
<field name="state">offer_received</field>
<field name="description">X2many tutorial</field>
<field name="postcode">13579</field>
<field name="date_availability">2011-11-11</field>
<field name="expected_price">123456</field>
<field name="selling_price">135791</field>
<field name="bedrooms">2</field>
<field name="living_area">30</field>
<field name="facades">4</field>
<field name="garage">False</field>
<field name="property_type_id" ref="data_property_type_residential"/>
<field name="offer_ids" eval="[
Command.clear(),
Command.create({
'partner_id': ref('base.res_partner_12'),
'price': 10000,
'validity': 14,
}),
Command.create({
'partner_id': ref('base.res_partner_2'),
'price': 10002,
'validity': 14,
}),
]"/>
</record>
</odoo>

29 changes: 29 additions & 0 deletions estate/demo/estate_property_offer.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<odoo>
<record id="estate_property_offer_1" model="estate.property.offer">
<field name="partner_id" ref="base.res_partner_12"/>
<field name="property_id" ref="estate_property_1"/>
<field name="price">10000</field>
<field name="validity">14</field>
<field name="create_date" eval="datetime.now()"/>
</record>

<record id="estate_property_offer_2" model="estate.property.offer">
<field name="partner_id" ref="base.res_partner_12"/>
<field name="property_id" ref="estate_property_1"/>
<field name="price">1500000</field>
<field name="validity">14</field>
<field name="create_date" eval="datetime.now()"/>
</record>

<record id="estate_property_offer_3" model="estate.property.offer">
<field name="partner_id" ref="base.res_partner_2"/>
<field name="property_id" ref="estate_property_1"/>
<field name="price">1500001</field>
<field name="validity">14</field>
<field name="create_date" eval="datetime.now()"/>
</record>

<function model="estate.property.offer" name="action_offer_refuse" eval="[ref('estate_property_offer_1')]"/>
<function model="estate.property.offer" name="action_offer_refuse" eval="[ref('estate_property_offer_2')]"/>
<function model="estate.property.offer" name="action_offer_accept" eval="[ref('estate_property_offer_3')]"/>
</odoo>
10 changes: 6 additions & 4 deletions estate/models/estate_property.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,19 +57,21 @@ def _compute_best_price(self):
record.state = 'offer_received'

@api.onchange("garden")
def _onchange_partner_id(self):
def _onchange_garden(self):
for record in self:
if record.garden:
record.garden_area = 10
record.garden_orientation = 'north'
else:
record.garden_area = None
record.garden_orientation = None
record.garden_area = 0
record.garden_orientation = False

def action_property_sold(self):
for record in self:
if record.state == 'cancelled':
raise UserError("Cancelled properties cannot be sold.")
elif record.state != 'offer_accepted':
raise UserError("You cannot sell a property without an accepted offer.")
else:
record.state = 'sold'
return True
Expand All @@ -92,6 +94,6 @@ def _check_selling_price(self):
def unlink_if_new_or_cancelled(self):
for record in self:
if record.state not in ('new', 'cancelled'):
raise UserError("Only new and cancelled properties can be sold.")
raise UserError("Only new and cancelled properties can be deleted.")
if record.offer_ids:
record.offer_ids.unlink()
3 changes: 3 additions & 0 deletions estate/models/estate_property_offer.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ def action_offer_refuse(self):
@api.model_create_multi
def create(self, vals_list):
for vals in vals_list:
property = self.env['estate.property'].browse(vals.get('property_id'))
if property.state in ('sold', 'cancelled'):
raise UserError(f"Cannot create an offer in a {property.state} property.")
price = vals.get('price')
estate_property = self.env['estate.property'].browse(vals.get('property_id'))
if estate_property.best_price and price <= estate_property.best_price:
Expand Down
1 change: 1 addition & 0 deletions estate/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import test_estate_property
105 changes: 105 additions & 0 deletions estate/tests/test_estate_property.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
from odoo.tests.common import TransactionCase
from odoo.exceptions import UserError
from odoo.tests import Form, tagged


@tagged('post_install', '-at_install')
class EstateTestCase(TransactionCase):

@classmethod
def setUpClass(cls):
# add env on cls and many other things
super().setUpClass()

cls.properties = cls.env['estate.property'].create([{'name': 'test_house'}])

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Plural is misleading

Suggested change
cls.properties = cls.env['estate.property'].create([{'name': 'test_house'}])
cls.property = cls.env['estate.property'].create([{'name': 'test_house'}])

cls.partner = cls.env['res.partner'].create([{
'id': 'test_partner',

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

id?! don't touch this 😄

Suggested change
'id': 'test_partner',

'name': 'test_person',
'company_name': 'test_company',
'street': 'test_street',
'city': 'test_city',
'zip': '12345',
'country_id': cls.env.ref('base.us').id,
'state_id': cls.env.ref('base.state_us_39').id,
'phone': '+1 555-555-5555',
'email': '[email protected]',
'tz': 'Europe/Brussels',

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you need all this? I bet a name is sufficient for your case

Suggested change
'company_name': 'test_company',
'street': 'test_street',
'city': 'test_city',
'zip': '12345',
'country_id': cls.env.ref('base.us').id,
'state_id': cls.env.ref('base.state_us_39').id,
'phone': '+1 555-555-5555',
'email': '[email protected]',
'tz': 'Europe/Brussels',

}])

def test_creation_area(self):
"""Test that the total_area is computed like it should."""
self.properties.living_area = 20
self.properties.garden = True
self.properties.garden_area = 15
self.properties.garden_orientation = 'north'

self.assertRecordValues(self.properties, [
{'total_area': 35},
])

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

assertEqual if only one value to check, no?


def test_action_sell_without_accepted_offer(self):
"""Test that everything behaves like it should when selling an invalid property."""

self.assertRecordValues(self.properties, [
{'state': 'new'},
])

with self.assertRaises(UserError):
self.properties.action_property_sold()

def test_action_sell_with_accepted_offer(self):
"""Test that everything behaves like it should when selling a valid property."""

self.properties.offer_ids.create({

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Weird way to create an offer. Either use self.env['property.offer'].create(...), either create it while editing the field offer_ids with Command

'property_id': self.properties.id,
'partner_id': self.partner.id,
'price': 124,
'validity': 14,
})
self.properties.offer_ids.action_offer_accept()
self.properties.action_property_sold()

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not related to tests, but I have the feeling that action_offer_accept should mark the property as sold, so why do you need the call to action_property_sold?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the estate tutorial accepting the offer and selling the property are two different states.
After accepting an offer you can still cancel the property, not sell it.


self.assertRecordValues(self.properties, [
{'state': 'sold'},
])

def test_creation_offer_for_sold_property(self):
"""Test that everything behaves like it should when property is sold."""

self.properties.offer_ids.create({
'property_id': self.properties.id,
'partner_id': self.partner.id,
'price': 124,
'validity': 14,
})
self.properties.offer_ids.action_offer_accept()
self.properties.action_property_sold()

with self.assertRaises(UserError):
self.properties.offer_ids.create({
'property_id': self.properties.id,
'partner_id': self.partner.id,
'price': 130,
'validity': 14,
})

def test_enable_garden(self):
"""Test that default values are assigned to garden area and orientation when garden is enabled"""

form = Form(self.env['estate.property'])
form.garden = True

self.assertEqual(form.garden_area, 10)
self.assertEqual(form.garden_orientation, 'north')

def test_disable_garden(self):
"""Test that values are removed from garden area and orientation when garden is disabled"""

form = Form(self.env['estate.property'])
form.garden = True
form.garden_area = 15
form.garden_orientation = 'south'
form.garden = False

self.assertEqual(form.garden_area, 0)
self.assertEqual(form.garden_orientation, False)