From 1f3f54573428d3358ff78fa9f286411707ba35b7 Mon Sep 17 00:00:00 2001 From: sahm-odoo Date: Tue, 8 Oct 2024 18:54:14 +0530 Subject: [PATCH 01/16] Cover chepter1 to chepter5 --- estate/__init__.py | 3 ++ estate/__manifest__.py | 21 ++++++++++ estate/models/__init__.py | 2 + estate/models/estate_property.py | 36 ++++++++++++++++ estate/models/test_model.py | 7 ++++ estate/security/ir.model.access.csv | 2 + estate/views/estate_menu.xml | 57 ++++++++++++++++++++++++++ estate/views/estate_property_views.xml | 41 ++++++++++++++++++ 8 files changed, 169 insertions(+) create mode 100644 estate/__init__.py create mode 100644 estate/__manifest__.py create mode 100644 estate/models/__init__.py create mode 100644 estate/models/estate_property.py create mode 100644 estate/models/test_model.py create mode 100644 estate/security/ir.model.access.csv create mode 100644 estate/views/estate_menu.xml create mode 100644 estate/views/estate_property_views.xml diff --git a/estate/__init__.py b/estate/__init__.py new file mode 100644 index 00000000000..5305644df14 --- /dev/null +++ b/estate/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- + +from . import models \ No newline at end of file diff --git a/estate/__manifest__.py b/estate/__manifest__.py new file mode 100644 index 00000000000..f3b3ee5a62e --- /dev/null +++ b/estate/__manifest__.py @@ -0,0 +1,21 @@ +{ + 'name': "Real State", + # 'version': '1.0', + 'depends': ['base'], + 'author': "Sahil Mangukiya", + # 'category': 'Category', + 'description': "This is my First tutorial module.", + # data files always loaded at installation + 'data': [ + 'security/ir.model.access.csv', + + 'views/estate_property_views.xml', + 'views/estate_menu.xml' + ], + # data files containing optionally loaded demonstration data + 'demo': [ + ], + 'installable': True, + 'application': True, + 'auto_install': False +} \ No newline at end of file diff --git a/estate/models/__init__.py b/estate/models/__init__.py new file mode 100644 index 00000000000..88d10acbe55 --- /dev/null +++ b/estate/models/__init__.py @@ -0,0 +1,2 @@ +from . import test_model +from . import estate_property \ No newline at end of file diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py new file mode 100644 index 00000000000..8522c180dbd --- /dev/null +++ b/estate/models/estate_property.py @@ -0,0 +1,36 @@ +from odoo import models, fields +from datetime import timedelta + +class estateProperty(models.Model): + _name = "estate_property" + _description = "This is property Table." + + name = fields.Char(required=True) + description = fields.Text() + postcode = fields.Char() + data_availability = fields.Date( + default=lambda self: fields.Date.today() + timedelta(days=90), + copy=False + ) + expected_price = fields.Float(required=True) + selling_price = fields.Float(readonly=True, copy=False) + bedrooms = fields.Integer(default=2) + living_area = fields.Integer() + facades = fields.Integer() + garage = fields.Boolean() + garden = fields.Boolean() + garden_area = fields.Integer() + garden_orientation = fields.Selection( + string = 'Orientation', + selection = [('north', 'North'), ('south', 'South'), ('east', 'East'), ('west', 'West')], + help = "Garden Orientation is avialable in four faces of direction." + ) + active = fields.Boolean(default=False) + state = fields.Selection( + string = 'State', + selection = [('new', 'New'), ('offer received', 'Offer Received'), ('offer accepted', 'offer Accepted'), ('sold', 'Sold'), ('cancelled', 'Cancelled')], + help = "Offer available in five type.", + required=True, + copy=False, + default='new' + ) \ No newline at end of file diff --git a/estate/models/test_model.py b/estate/models/test_model.py new file mode 100644 index 00000000000..fb4115d09ef --- /dev/null +++ b/estate/models/test_model.py @@ -0,0 +1,7 @@ +from odoo import models, fields + +class TestModel(models.Model): + _name = "test_model" + _description = "This is test Table." + + diff --git a/estate/security/ir.model.access.csv b/estate/security/ir.model.access.csv new file mode 100644 index 00000000000..0e11f47e58d --- /dev/null +++ b/estate/security/ir.model.access.csv @@ -0,0 +1,2 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_estate_property,access_estate_property,model_estate_property,base.group_user,1,1,1,1 \ No newline at end of file diff --git a/estate/views/estate_menu.xml b/estate/views/estate_menu.xml new file mode 100644 index 00000000000..ddb1c7aba7f --- /dev/null +++ b/estate/views/estate_menu.xml @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml new file mode 100644 index 00000000000..a958d74bded --- /dev/null +++ b/estate/views/estate_property_views.xml @@ -0,0 +1,41 @@ + + + + Private + estate_property + list,form + + + + Properties + estate_property + list,form + + + + Custom + estate_property + list,form + + + + + + Private34 + estate_property + list,form + + + + estate_property_view_tree + estate_property + + + + + + + + + + From 5f2df6c6402f8332f52af0335abe14b3b11b5ad7 Mon Sep 17 00:00:00 2001 From: sahm-odoo Date: Thu, 10 Oct 2024 16:57:28 +0530 Subject: [PATCH 02/16] [ADD] estate_property: implemented upto chapter-7 (Relations Between Models) Completed the first three chapters of the Odoo developer tutorials. Set up the development environment. Created the real estate module and model with various fields. Established access rights for the model. Developed initial XML views for the module. Added relational models for estate properties, offers, tags, and types: Implemented One2many, Many2many, and Many2one relationships in models () Created basic views (search, list, form) for these models Implemented filters, groupby, and domain functionalities. --- estate/__manifest__.py | 3 +- estate/models/__init__.py | 6 +- estate/models/estate_property.py | 28 ++++- estate/models/estate_property_offer.py | 23 ++++ estate/models/estate_property_tag.py | 8 ++ estate/models/estate_property_type.py | 11 ++ estate/models/test_estate_property_offer.py | 23 ++++ estate/models/test_model.py | 6 +- estate/security/ir.model.access.csv | 6 +- estate/views/estate_menu.xml | 31 +++-- estate/views/estate_property_tag_views.xml | 8 ++ estate/views/estate_property_type_views.xml | 32 +++++ estate/views/estate_property_views.xml | 129 +++++++++++++++++--- 13 files changed, 274 insertions(+), 40 deletions(-) create mode 100644 estate/models/estate_property_offer.py create mode 100644 estate/models/estate_property_tag.py create mode 100644 estate/models/estate_property_type.py create mode 100644 estate/models/test_estate_property_offer.py create mode 100644 estate/views/estate_property_tag_views.xml create mode 100644 estate/views/estate_property_type_views.xml diff --git a/estate/__manifest__.py b/estate/__manifest__.py index f3b3ee5a62e..b39f63e01ef 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -8,7 +8,8 @@ # data files always loaded at installation 'data': [ 'security/ir.model.access.csv', - + 'views/estate_property_type_views.xml', + 'views/estate_property_tag_views.xml', 'views/estate_property_views.xml', 'views/estate_menu.xml' ], diff --git a/estate/models/__init__.py b/estate/models/__init__.py index 88d10acbe55..b2693faef3e 100644 --- a/estate/models/__init__.py +++ b/estate/models/__init__.py @@ -1,2 +1,6 @@ from . import test_model -from . import estate_property \ No newline at end of file +from . import estate_property +from . import estate_property_type +from . import estate_property_tag +from . import estate_property_offer +from . import test_estate_property_offer \ No newline at end of file diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index 8522c180dbd..df6c9397463 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -1,8 +1,8 @@ -from odoo import models, fields +from odoo import models, fields # type: ignore from datetime import timedelta class estateProperty(models.Model): - _name = "estate_property" + _name = "estate.property" _description = "This is property Table." name = fields.Char(required=True) @@ -33,4 +33,26 @@ class estateProperty(models.Model): required=True, copy=False, default='new' - ) \ No newline at end of file + ) + property_type_id = fields.Many2one( + 'estate.property.type', + 'Property Type' + ) + seller_id = fields.Many2one( + 'res.users', + 'Salesman', + default=lambda self: self.env.user + ) + buyer_id = fields.Many2one( + 'res.partner', + 'Buyer' + ) + tag_ids = fields.Many2many( + comodel_name='estate.property.tag', + string='Tag' + ) + offer_ids = fields.One2many( + 'estate.property.offer', + 'property_id' + ) + diff --git a/estate/models/estate_property_offer.py b/estate/models/estate_property_offer.py new file mode 100644 index 00000000000..872d3e3add7 --- /dev/null +++ b/estate/models/estate_property_offer.py @@ -0,0 +1,23 @@ +from odoo import models, fields # type: ignore + +class estatePropertyOffer(models.Model): + + _name = "estate.property.offer" + _description = "This is offer table" + + price = fields.Float(required=True) + status = fields.Selection( + string='Status', + selection=[('accepted', 'Accepted'), ('refused', 'Refused')], + ) + partner_id = fields.Many2one( + 'res.partner', + string='Buyer', + required=True + ) + property_id = fields.Many2one( + 'estate.property', + string='Property', + required=True + ) + \ No newline at end of file diff --git a/estate/models/estate_property_tag.py b/estate/models/estate_property_tag.py new file mode 100644 index 00000000000..6f72ed5f7c3 --- /dev/null +++ b/estate/models/estate_property_tag.py @@ -0,0 +1,8 @@ +from odoo import models, fields # type: ignore + +class estatePropertyTag(models.Model): + + _name = "estate.property.tag" + _description = "This is property Tag model" + + name = fields.Char(required=True, string="Tag") \ No newline at end of file diff --git a/estate/models/estate_property_type.py b/estate/models/estate_property_type.py new file mode 100644 index 00000000000..8eec044305e --- /dev/null +++ b/estate/models/estate_property_type.py @@ -0,0 +1,11 @@ +from odoo import models, fields # type: ignore + +class estatePropertyType(models.Model): + _name = "estate.property.type" + _description = "This is property Type table." + + name = fields.Char(required=True) + + + + diff --git a/estate/models/test_estate_property_offer.py b/estate/models/test_estate_property_offer.py new file mode 100644 index 00000000000..97ef8cfae5e --- /dev/null +++ b/estate/models/test_estate_property_offer.py @@ -0,0 +1,23 @@ +from odoo import models, fields # type: ignore + +class TestEstatePropertyOffer(models.Model): + _name = "test.estate.property.offer" + _description = "This is test offer Table." + + test_price = fields.Float(required=True) + test_status = fields.Selection( + string='Status', + selection=[('accepted', 'Accepted'), ('refused', 'Refused')], + copy=False, + help="status of offer" + ) + test_partner_id = fields.Many2one( + 'res.partner', + required=True + ) + test_property_id = fields.Many2one( + 'estate.property', + required=True + ) + + diff --git a/estate/models/test_model.py b/estate/models/test_model.py index fb4115d09ef..babc2190671 100644 --- a/estate/models/test_model.py +++ b/estate/models/test_model.py @@ -1,7 +1,5 @@ -from odoo import models, fields +from odoo import models, fields # type: ignore class TestModel(models.Model): - _name = "test_model" + _name = "test.model" _description = "This is test Table." - - diff --git a/estate/security/ir.model.access.csv b/estate/security/ir.model.access.csv index 0e11f47e58d..b85b3c5c846 100644 --- a/estate/security/ir.model.access.csv +++ b/estate/security/ir.model.access.csv @@ -1,2 +1,6 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink -access_estate_property,access_estate_property,model_estate_property,base.group_user,1,1,1,1 \ No newline at end of file +access_estate_property,access_estate_property,model_estate_property,base.group_user,1,1,1,1 +access_estate_property_type,access_estate_property_type,model_estate_property_type,base.group_user,1,1,1,1 +access_estate_property_tag,access_estate_property_tag,model_estate_property_tag,base.group_user,1,1,1,1 +access_estate_property_offer,access_estate_property_offer,model_estate_property_offer,base.group_user,1,1,1,1 +test_access_estate_property_offer,access_test_estate_property_offer,model_test_estate_property_offer,base.group_user,1,1,1,1 diff --git a/estate/views/estate_menu.xml b/estate/views/estate_menu.xml index ddb1c7aba7f..926e6466c19 100644 --- a/estate/views/estate_menu.xml +++ b/estate/views/estate_menu.xml @@ -2,8 +2,17 @@ - - + + + + + + + @@ -15,31 +24,27 @@ id="estate_third_level_setting_second_DFJDK" name="hello" action="estate_private34_action" sequence="1" /> - + - + - + - - + + - + - + - - - - diff --git a/estate/views/estate_property_tag_views.xml b/estate/views/estate_property_tag_views.xml new file mode 100644 index 00000000000..644626faad0 --- /dev/null +++ b/estate/views/estate_property_tag_views.xml @@ -0,0 +1,8 @@ + + + + Property Tag + estate.property.tag + tree,form + + \ No newline at end of file diff --git a/estate/views/estate_property_type_views.xml b/estate/views/estate_property_type_views.xml new file mode 100644 index 00000000000..8419f20b135 --- /dev/null +++ b/estate/views/estate_property_type_views.xml @@ -0,0 +1,32 @@ + + + + Properties Types + estate.property.type + tree,form + + + + + + \ No newline at end of file diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index a958d74bded..3ba3f69b7ab 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -1,41 +1,136 @@ + + Properties + estate.property + list,form + + - Private - estate_property + BreadCrums + estate.property list,form - - Properties - estate_property - list,form + + ijij + estate.property + list,form Custom - estate_property - list,form - - - - - - Private34 - estate_property + estate.property list,form estate_property_view_tree - estate_property + estate.property - + + + + + + + + estate_property_view_form + estate.property + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + + estate_property_view_search + estate.property + + + + + + + + + + + + + + + +
From 2f380fa7495c6b86601becd4398e6f0300948592 Mon Sep 17 00:00:00 2001 From: sahm-odoo Date: Thu, 17 Oct 2024 19:05:10 +0530 Subject: [PATCH 03/16] [IMP] estate_property: computed Fields And Onchanges - Added computed fields for total area and best offer in estate property model. - Implemented inverse method for offer validity date computation. - Created onchange method to auto-fill garden area and orientation based on garden field. --- estate/models/__init__.py | 2 +- estate/models/estate_property.py | 59 ++++++++++++++++++--- estate/models/estate_property_offer.py | 35 +++++++++++- estate/models/estate_property_tag.py | 14 ++++- estate/models/estate_property_type.py | 2 + estate/security/ir.model.access.csv | 1 + estate/views/estate_menu.xml | 6 +-- estate/views/estate_property_tag_views.xml | 15 ++++++ estate/views/estate_property_type_views.xml | 5 +- estate/views/estate_property_views.xml | 31 +++++------ 10 files changed, 140 insertions(+), 30 deletions(-) diff --git a/estate/models/__init__.py b/estate/models/__init__.py index b2693faef3e..525b3559722 100644 --- a/estate/models/__init__.py +++ b/estate/models/__init__.py @@ -3,4 +3,4 @@ from . import estate_property_type from . import estate_property_tag from . import estate_property_offer -from . import test_estate_property_offer \ No newline at end of file +from . import test_estate_property_offer diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index df6c9397463..2b20acf8b6a 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -1,4 +1,4 @@ -from odoo import models, fields # type: ignore +from odoo import models, fields, api # type: ignore from datetime import timedelta class estateProperty(models.Model): @@ -14,7 +14,7 @@ class estateProperty(models.Model): ) expected_price = fields.Float(required=True) selling_price = fields.Float(readonly=True, copy=False) - bedrooms = fields.Integer(default=2) + bedrooms = fields.Integer(change_default=True) living_area = fields.Integer() facades = fields.Integer() garage = fields.Boolean() @@ -25,7 +25,7 @@ class estateProperty(models.Model): selection = [('north', 'North'), ('south', 'South'), ('east', 'East'), ('west', 'West')], help = "Garden Orientation is avialable in four faces of direction." ) - active = fields.Boolean(default=False) + active = fields.Boolean(default=True) state = fields.Selection( string = 'State', selection = [('new', 'New'), ('offer received', 'Offer Received'), ('offer accepted', 'offer Accepted'), ('sold', 'Sold'), ('cancelled', 'Cancelled')], @@ -35,8 +35,12 @@ class estateProperty(models.Model): default='new' ) property_type_id = fields.Many2one( - 'estate.property.type', - 'Property Type' + comodel_name='estate.property.type', + string='Property Type', + domain="[('number', '>=', 0)]", + ondelete='cascade', + store=False # 3 option: cascade, set null, restrict + # index, traking, store, compute, related ) seller_id = fields.Many2one( 'res.users', @@ -49,10 +53,53 @@ class estateProperty(models.Model): ) tag_ids = fields.Many2many( comodel_name='estate.property.tag', - string='Tag' + string='Tag', + relation='property_join_tag', + column1='property_id', + column2='tag_id' ) + # estate_property_tag_rel automatically made offer_ids = fields.One2many( 'estate.property.offer', 'property_id' ) + number = fields.Integer(related='property_type_id.number') + totalArea = fields.Integer(compute='_compute_total_area', store=True) + percentage_garden = fields.Float(compute='_compute_total_area') + percentage_living = fields.Float(compute='_compute_total_area') + + best_offer = fields.Float(compute='_compute_best_offer') + + @api.depends('garden_area', 'living_area') + def _compute_total_area(self): + self.totalArea = self.garden_area + self.living_area + # self.percentage_garden = ((self.garden_area) / (self.totalArea)) * 100 + # self.percentage_living = ((self.living_area) / (self.totalArea)) * 100 + + @api.depends('offer_ids.price') + def _compute_best_offer(self): + # for record in self: + # if record.offer_ids: + # prices = [line.price for line in record.offer_ids] + # record.best_offer = max(prices) if prices else 0.0 + # else: + # record.best_offer = 0.0 # Set to 0 if there are no offers + for record in self: + if record.offer_ids: + record.best_offer = max(record.offer_ids.mapped('price')) + else: + record.best_offer = 0.0 + + @api.onchange('garden') + def _onchange_garden(self): + if self.garden: + self.garden_area = 10 + self.garden_orientation = 'north' + else: + self.garden_area = 0 + self.garden_orientation = False + + + # offer = fields.Integer(related='offer_ids.id') + # property_record = self.env['estate.property'].browse(1) diff --git a/estate/models/estate_property_offer.py b/estate/models/estate_property_offer.py index 872d3e3add7..10a1e1d49c2 100644 --- a/estate/models/estate_property_offer.py +++ b/estate/models/estate_property_offer.py @@ -1,4 +1,5 @@ -from odoo import models, fields # type: ignore +from odoo import models, fields, api # type: ignore +from datetime import timedelta, datetime class estatePropertyOffer(models.Model): @@ -18,6 +19,36 @@ class estatePropertyOffer(models.Model): property_id = fields.Many2one( 'estate.property', string='Property', - required=True + ondelete='set null' ) + validity = fields.Integer(default=7, string="Validity") + date_deadline = fields.Date(compute='_compute_date_deadline', inverse='_compute_validity', string="Date Deadline") + sum = fields.Integer(compute='_compute_sum', string="Sum") + sum2 = fields.Integer(compute='_compute_sum2', string="Sum2") + + @api.depends('validity') + def _compute_date_deadline(self): + for record in self: + if record.create_date: + record.date_deadline = record.create_date + timedelta(record.validity) + else: + record.date_deadline = datetime.today() + timedelta(record.validity) + + @api.depends('date_deadline') + def _compute_validity(self): + for record in self: + if record.date_deadline and record.create_date: + record.validity = (record.date_deadline - record.create_date.date()).days + else: + record.validity = (record.date_deadline - datetime.today()).days + + @api.depends('validity') + def _compute_sum(self): + for record in self: + record.sum = 7 + record.validity + + @api.depends('sum') + def _compute_sum2(self): + for record in self: + record.sum2 = 7 + record.sum \ No newline at end of file diff --git a/estate/models/estate_property_tag.py b/estate/models/estate_property_tag.py index 6f72ed5f7c3..5723f4e689a 100644 --- a/estate/models/estate_property_tag.py +++ b/estate/models/estate_property_tag.py @@ -5,4 +5,16 @@ class estatePropertyTag(models.Model): _name = "estate.property.tag" _description = "This is property Tag model" - name = fields.Char(required=True, string="Tag") \ No newline at end of file + name = fields.Char(required=True, string="Tag") + active = fields.Boolean(required=True) + # property_ids = fields.Many2many( + # comodel_name='estate.property', + # string='Properrrrty', + # relation='property_join_tag', + # column1='property_id', + # column2='tag_id' + # ) + property_ids = fields.Many2many( + comodel_name='estate.property', + string='properties' + ) \ No newline at end of file diff --git a/estate/models/estate_property_type.py b/estate/models/estate_property_type.py index 8eec044305e..25035550b48 100644 --- a/estate/models/estate_property_type.py +++ b/estate/models/estate_property_type.py @@ -5,6 +5,8 @@ class estatePropertyType(models.Model): _description = "This is property Type table." name = fields.Char(required=True) + active = fields.Boolean(Default=False) + number = fields.Integer() diff --git a/estate/security/ir.model.access.csv b/estate/security/ir.model.access.csv index b85b3c5c846..f5db56aa0bb 100644 --- a/estate/security/ir.model.access.csv +++ b/estate/security/ir.model.access.csv @@ -4,3 +4,4 @@ access_estate_property_type,access_estate_property_type,model_estate_property_ty access_estate_property_tag,access_estate_property_tag,model_estate_property_tag,base.group_user,1,1,1,1 access_estate_property_offer,access_estate_property_offer,model_estate_property_offer,base.group_user,1,1,1,1 test_access_estate_property_offer,access_test_estate_property_offer,model_test_estate_property_offer,base.group_user,1,1,1,1 + diff --git a/estate/views/estate_menu.xml b/estate/views/estate_menu.xml index 926e6466c19..cec9c7cf392 100644 --- a/estate/views/estate_menu.xml +++ b/estate/views/estate_menu.xml @@ -12,7 +12,7 @@ action="estate_property_tag_action"/>
- + - + diff --git a/estate/views/estate_property_tag_views.xml b/estate/views/estate_property_tag_views.xml index 644626faad0..3cbe63e898c 100644 --- a/estate/views/estate_property_tag_views.xml +++ b/estate/views/estate_property_tag_views.xml @@ -5,4 +5,19 @@ estate.property.tag tree,form + + estate_property_tag_view_form + estate.property.tag + +
+ + + + + + + +
+
+
\ No newline at end of file diff --git a/estate/views/estate_property_type_views.xml b/estate/views/estate_property_type_views.xml index 8419f20b135..2ab8c5b0349 100644 --- a/estate/views/estate_property_type_views.xml +++ b/estate/views/estate_property_type_views.xml @@ -6,15 +6,16 @@ tree,form - + @@ -52,24 +54,15 @@ - - - + + + + + @@ -80,11 +73,17 @@ + + + + + @@ -104,6 +103,8 @@ + + From 6152cae7cb576bfe951c150f3532bf17ae8d724e Mon Sep 17 00:00:00 2001 From: sahm-odoo Date: Fri, 18 Oct 2024 12:56:57 +0530 Subject: [PATCH 04/16] [IMP] estate_property: sql/python constraints and action buttons for property - Added 'Cancel' and 'Sold' buttons to estate.property model with business logic. - Ensured canceled properties cannot be sold and sold properties cannot be canceled. - Added 'Accept' and 'Refuse' buttons to estate.property.offer model. - Set buyer and selling price when an offer is accepted. - Added SQL constraints to enforce unique property tag and type names. - Ensured property expected price, selling price, and offer price are strictly positive using SQL constraints. - Added Python constraint to validate selling price is at least 90% of the expected price. --- estate/models/estate_property.py | 24 ++++++++++++++++++++++++ estate/models/estate_property_offer.py | 17 +++++++++++++++++ estate/models/estate_property_tag.py | 5 ++++- estate/models/estate_property_type.py | 4 ++++ estate/views/estate_property_views.xml | 9 +++++++-- 5 files changed, 56 insertions(+), 3 deletions(-) diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index 2b20acf8b6a..0005992079f 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -1,5 +1,6 @@ from odoo import models, fields, api # type: ignore from datetime import timedelta +from odoo.exceptions import UserError, ValidationError class estateProperty(models.Model): _name = "estate.property" @@ -70,6 +71,11 @@ class estateProperty(models.Model): best_offer = fields.Float(compute='_compute_best_offer') + _sql_constraints = [ + ('check_selling_price','CHECK(selling_price >= 0)','A property selling price must be positive.'), + ('check_expected_price','CHECK(expected_price > 0)','A property expected price must be strictly positive.') + ] + @api.depends('garden_area', 'living_area') def _compute_total_area(self): self.totalArea = self.garden_area + self.living_area @@ -102,4 +108,22 @@ def _onchange_garden(self): # offer = fields.Integer(related='offer_ids.id') # property_record = self.env['estate.property'].browse(1) + + def action_sold(self): + if(self.state == 'cancelled'): + raise UserError("You can not mark a cancelled property as sold.") + self.state = 'sold' + + def action_cancelled(self): + if(self.state == 'sold'): + raise UserError("You can not mark sold property as cancelled") + self.state = 'cancelled' + + @api.constrains('selling_price', 'expected_price') + def _check_selling_price(self): + for record in self: + if record.selling_price < (0.9 * record.expected_price) and (record.selling_price > 0): + raise ValidationError("Selling price cannot be lower than 90 percentage of the expected price.") + + diff --git a/estate/models/estate_property_offer.py b/estate/models/estate_property_offer.py index 10a1e1d49c2..2316f4be50d 100644 --- a/estate/models/estate_property_offer.py +++ b/estate/models/estate_property_offer.py @@ -26,6 +26,10 @@ class estatePropertyOffer(models.Model): sum = fields.Integer(compute='_compute_sum', string="Sum") sum2 = fields.Integer(compute='_compute_sum2', string="Sum2") + _sql_constraints = [ + ('check_offer_price','CHECK(price > 0)','A property offer price must be strictly positive.') + ] + @api.depends('validity') def _compute_date_deadline(self): for record in self: @@ -51,4 +55,17 @@ def _compute_sum(self): def _compute_sum2(self): for record in self: record.sum2 = 7 + record.sum + + def action_accept(self): + self.status = 'accepted' + self.property_id.buyer_id = self.partner_id + self.property_id.selling_price = self.price + + def action_refuse(self): + if(self.status == 'accepted'): + self.status = 'refused' + self.property_id.buyer_id = False + self.property_id.selling_price = False + else: + self.status = 'refused' \ No newline at end of file diff --git a/estate/models/estate_property_tag.py b/estate/models/estate_property_tag.py index 5723f4e689a..67726632318 100644 --- a/estate/models/estate_property_tag.py +++ b/estate/models/estate_property_tag.py @@ -17,4 +17,7 @@ class estatePropertyTag(models.Model): property_ids = fields.Many2many( comodel_name='estate.property', string='properties' - ) \ No newline at end of file + ) + _sql_constraints = [ + ('check_unique_tag_name','UNIQUE(name)','This tag is already exists.') + ] \ No newline at end of file diff --git a/estate/models/estate_property_type.py b/estate/models/estate_property_type.py index 25035550b48..ebb302904c6 100644 --- a/estate/models/estate_property_type.py +++ b/estate/models/estate_property_type.py @@ -8,6 +8,10 @@ class estatePropertyType(models.Model): active = fields.Boolean(Default=False) number = fields.Integer() + _sql_constraints = [ + ('check_unique_type_name','UNIQUE(name)','This type is already exists.') + ] + diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index a5935258971..75a59e28e15 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -46,7 +46,10 @@ estate.property
- +
+
@@ -100,11 +103,13 @@ - + -

+

-

- + + + + - - + + + + + diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index 57f48df453e..f82debdabef 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -7,171 +7,137 @@ {'search_default_state' : True} - - estate_property_view_tree estate.property - - - - - - - - - - + + + + + + + - estate_property_view_form - estate.property - -
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + estate_property_view_form + estate.property + + +
+
+ +

+ Name: + +

+ + + + + + + + + + + + + + - - - - - + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - -