diff --git a/estate.zip b/estate.zip new file mode 100644 index 0000000000..5446237138 Binary files /dev/null and b/estate.zip differ diff --git a/estate/__manifest__.py b/estate/__manifest__.py index ab40a80f40..bddb9a613a 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -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, diff --git a/estate/demo/estate.property.type.csv b/estate/demo/estate.property.type.csv new file mode 100644 index 0000000000..17f4695bb6 --- /dev/null +++ b/estate/demo/estate.property.type.csv @@ -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" diff --git a/estate/demo/estate_property.xml b/estate/demo/estate_property.xml new file mode 100644 index 0000000000..8359e8af29 --- /dev/null +++ b/estate/demo/estate_property.xml @@ -0,0 +1,62 @@ + + + Big Villa + new + A nice and big villa + 12345 + 2020-02-02 + 1600000 + 6 + 100 + 4 + True + True + 100000 + south + + + + + Trailer home + cancelled + Home in a trailer park + 54321 + 1970-01-01 + 100000 + 120000 + 1 + 10 + 4 + False + + + + + Tutorial House + offer_received + X2many tutorial + 13579 + 2011-11-11 + 123456 + 135791 + 2 + 30 + 4 + False + + + + + \ No newline at end of file diff --git a/estate/demo/estate_property_offer.xml b/estate/demo/estate_property_offer.xml new file mode 100644 index 0000000000..87c01d263e --- /dev/null +++ b/estate/demo/estate_property_offer.xml @@ -0,0 +1,29 @@ + + + + + 10000 + 14 + + + + + + + 1500000 + 14 + + + + + + + 1500001 + 14 + + + + + + + diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index a816fd33d3..6971e731d1 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -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 @@ -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() diff --git a/estate/models/estate_property_offer.py b/estate/models/estate_property_offer.py index 8df062241a..3334e5a0ce 100644 --- a/estate/models/estate_property_offer.py +++ b/estate/models/estate_property_offer.py @@ -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: diff --git a/estate/tests/__init__.py b/estate/tests/__init__.py new file mode 100644 index 0000000000..576617cccf --- /dev/null +++ b/estate/tests/__init__.py @@ -0,0 +1 @@ +from . import test_estate_property diff --git a/estate/tests/test_estate_property.py b/estate/tests/test_estate_property.py new file mode 100644 index 0000000000..2ac0c5e682 --- /dev/null +++ b/estate/tests/test_estate_property.py @@ -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'}]) + cls.partner = cls.env['res.partner'].create([{ + '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': 'test@testing.example.com', + '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}, + ]) + + 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({ + '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() + + 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)