From 7076246a69b27308fee3c620de376bd3ad12ee83 Mon Sep 17 00:00:00 2001 From: matho-odoo Date: Mon, 20 Oct 2025 13:48:29 +0200 Subject: [PATCH 1/8] [ADD] estate: create the app --- estate/__init__.py | 0 estate/__manifest__.py | 13 +++++++++++++ 2 files changed, 13 insertions(+) create mode 100644 estate/__init__.py create mode 100644 estate/__manifest__.py diff --git a/estate/__init__.py b/estate/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/estate/__manifest__.py b/estate/__manifest__.py new file mode 100644 index 00000000000..1995f85d2fd --- /dev/null +++ b/estate/__manifest__.py @@ -0,0 +1,13 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + + +{ + 'name': 'Estate', + 'version': '0.1', + 'application': True, + 'author': 'matho', + 'depends': [ + 'base', + ], +} \ No newline at end of file From 8f82d4d26ee3589347619968302e5265bb75bdb9 Mon Sep 17 00:00:00 2001 From: matho-odoo Date: Tue, 21 Oct 2025 13:56:04 +0200 Subject: [PATCH 2/8] [IMP] estate: create the list, form and search view --- estate/__init__.py | 1 + estate/__manifest__.py | 5 ++ estate/models/__init__.py | 1 + estate/models/estate_property.py | 28 +++++++++ estate/security/ir.model.access.csv | 2 + estate/views/estate_menus.xml | 9 +++ estate/views/estate_property_views.xml | 81 ++++++++++++++++++++++++++ 7 files changed, 127 insertions(+) create mode 100644 estate/models/__init__.py create mode 100644 estate/models/estate_property.py create mode 100644 estate/security/ir.model.access.csv create mode 100644 estate/views/estate_menus.xml create mode 100644 estate/views/estate_property_views.xml diff --git a/estate/__init__.py b/estate/__init__.py index e69de29bb2d..9a7e03eded3 100644 --- a/estate/__init__.py +++ b/estate/__init__.py @@ -0,0 +1 @@ +from . import models \ No newline at end of file diff --git a/estate/__manifest__.py b/estate/__manifest__.py index 1995f85d2fd..7edad70926c 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -10,4 +10,9 @@ 'depends': [ 'base', ], + 'data': [ + 'security/ir.model.access.csv', + 'views/estate_property_views.xml', + 'views/estate_menus.xml', + ] } \ No newline at end of file diff --git a/estate/models/__init__.py b/estate/models/__init__.py new file mode 100644 index 00000000000..f23bb1d5ea9 --- /dev/null +++ b/estate/models/__init__.py @@ -0,0 +1 @@ +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..427276f6d88 --- /dev/null +++ b/estate/models/estate_property.py @@ -0,0 +1,28 @@ +from odoo import fields, models + +class EstateProperty(models.Model): + _name = "estate.property" + _description = "ici je mets une phrase" + + name = fields.Char(required=True) + description = fields.Text() + postcode = fields.Char() + date_availability = fields.Date(default=fields.Date.add(fields.Date.today(), months=3), 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='Garden orientation', + selection=[('North', 'N'), ('South', 'S'),('East', 'E'),('West', 'W')], + help="Specify the orientation of the garden to know when you're gonna enjoy the sun") + state = fields.Selection( + selection=[('New','New'), ('Offer Received', 'Offer Received'),('Offer Accepted', 'Offer Accepted'),('Sold', 'Sold'),('Cancelled', 'Cancelled')], + default='New' + ) + active = fields.Boolean(default=True) + diff --git a/estate/security/ir.model.access.csv b/estate/security/ir.model.access.csv new file mode 100644 index 00000000000..98f4671fb0d --- /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 +estate.access_estate_property,access_estate_property,estate.model_estate_property,base.group_user,1,1,1,1 diff --git a/estate/views/estate_menus.xml b/estate/views/estate_menus.xml new file mode 100644 index 00000000000..6701ec47195 --- /dev/null +++ b/estate/views/estate_menus.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ 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..c1ce91a7081 --- /dev/null +++ b/estate/views/estate_property_views.xml @@ -0,0 +1,81 @@ + + + + + Properties + estate.property + list,form + + + + + estate.property.view.list + estate.property + + + + + + + + + + + + + + + estate.property.view.form + estate.property + +
+ +

+ +

+ + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ + + estate.property.view.search + estate.property + + + + + + + + + + + + +
+
\ No newline at end of file From 3ebb0c4dc8f05f2f63783e2bc689476bf7fa6156 Mon Sep 17 00:00:00 2001 From: matho-odoo Date: Wed, 22 Oct 2025 09:14:32 +0200 Subject: [PATCH 3/8] [IMP] estate: chapters until 7 --- estate/__init__.py | 2 +- estate/__manifest__.py | 11 +++--- estate/models/__init__.py | 5 ++- estate/models/estate_property.py | 10 ++++-- estate/models/estate_property_offer.py | 10 ++++++ estate/models/estate_property_tag.py | 7 ++++ estate/models/estate_property_type.py | 7 ++++ estate/security/ir.model.access.csv | 3 ++ estate/views/estate_menus.xml | 8 +++-- estate/views/estate_property_offer_views.xml | 22 ++++++++++++ estate/views/estate_property_tag_views.xml | 11 ++++++ estate/views/estate_property_type_views.xml | 11 ++++++ estate/views/estate_property_views.xml | 36 ++++++++++++++++---- 13 files changed, 123 insertions(+), 20 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/views/estate_property_offer_views.xml create mode 100644 estate/views/estate_property_tag_views.xml create mode 100644 estate/views/estate_property_type_views.xml diff --git a/estate/__init__.py b/estate/__init__.py index 9a7e03eded3..0650744f6bc 100644 --- a/estate/__init__.py +++ b/estate/__init__.py @@ -1 +1 @@ -from . import models \ No newline at end of file +from . import models diff --git a/estate/__manifest__.py b/estate/__manifest__.py index 7edad70926c..6d34ec4fcba 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -1,7 +1,3 @@ -# -*- coding: utf-8 -*- -# Part of Odoo. See LICENSE file for full copyright and licensing details. - - { 'name': 'Estate', 'version': '0.1', @@ -13,6 +9,9 @@ '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_menus.xml', - ] -} \ No newline at end of file + ] +} diff --git a/estate/models/__init__.py b/estate/models/__init__.py index f23bb1d5ea9..3b4e0f595da 100644 --- a/estate/models/__init__.py +++ b/estate/models/__init__.py @@ -1 +1,4 @@ -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 diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index 427276f6d88..fb646803a3b 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -1,8 +1,9 @@ from odoo import fields, models + class EstateProperty(models.Model): _name = "estate.property" - _description = "ici je mets une phrase" + _description = "Estate Property" name = fields.Char(required=True) description = fields.Text() @@ -21,8 +22,11 @@ class EstateProperty(models.Model): selection=[('North', 'N'), ('South', 'S'),('East', 'E'),('West', 'W')], help="Specify the orientation of the garden to know when you're gonna enjoy the sun") state = fields.Selection( - selection=[('New','New'), ('Offer Received', 'Offer Received'),('Offer Accepted', 'Offer Accepted'),('Sold', 'Sold'),('Cancelled', 'Cancelled')], + selection=[('New', 'New'), ('Offer Received', 'Offer Received'), ('Offer Accepted', 'Offer Accepted'), ('Sold', 'Sold'), ('Cancelled', 'Cancelled')], default='New' ) active = fields.Boolean(default=True) - + salesman = fields.Many2one("res.users") + buyer = fields.Many2one("res.partner", copy=False) + tag_ids=fields.Many2many("estate.property.tag", string="Tags") + 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..e087f94c7a8 --- /dev/null +++ b/estate/models/estate_property_offer.py @@ -0,0 +1,10 @@ +from odoo import fields, models + +class EstatePropertyOffer(models.Model): + _name = "estate.property.offer" + _description = "ici je mets une phrase 4" + + price = fields.Float() + status = fields.Selection(copy=False, selection=[('Accepted', 'Accepted'), ('Refused', 'Refused')],) + partner_id = fields.Many2one("res.partner", required=True) + property_id = fields.Many2one("estate.property", required=True) diff --git a/estate/models/estate_property_tag.py b/estate/models/estate_property_tag.py new file mode 100644 index 00000000000..30f1dfb7315 --- /dev/null +++ b/estate/models/estate_property_tag.py @@ -0,0 +1,7 @@ +from odoo import fields, models + +class EstatePropertyTag(models.Model): + _name = "estate.property.tag" + _description = "ici je mets une phrase 3" + + name = fields.Char(required=True) diff --git a/estate/models/estate_property_type.py b/estate/models/estate_property_type.py new file mode 100644 index 00000000000..e80997c85bb --- /dev/null +++ b/estate/models/estate_property_type.py @@ -0,0 +1,7 @@ +from odoo import fields, models + +class EstatePropertyType(models.Model): + _name = "estate.property.type" + _description = "ici je mets une phrase 2" + + name = fields.Char(required=True) diff --git a/estate/security/ir.model.access.csv b/estate/security/ir.model.access.csv index 98f4671fb0d..0c0b62b7fee 100644 --- a/estate/security/ir.model.access.csv +++ b/estate/security/ir.model.access.csv @@ -1,2 +1,5 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink estate.access_estate_property,access_estate_property,estate.model_estate_property,base.group_user,1,1,1,1 +estate.access_estate_property_type,access_estate_property_type,estate.model_estate_property_type,base.group_user,1,1,1,1 +estate.access_estate_property_tag,access_estate_property_tag,estate.model_estate_property_tag,base.group_user,1,1,1,1 +estate.access_estate_property_offer,access_estate_property_offer,estate.model_estate_property_offer,base.group_user,1,1,1,1 diff --git a/estate/views/estate_menus.xml b/estate/views/estate_menus.xml index 6701ec47195..3ae25cf97d8 100644 --- a/estate/views/estate_menus.xml +++ b/estate/views/estate_menus.xml @@ -1,9 +1,13 @@ - + + + + + - \ No newline at end of file + diff --git a/estate/views/estate_property_offer_views.xml b/estate/views/estate_property_offer_views.xml new file mode 100644 index 00000000000..8048cb251c2 --- /dev/null +++ b/estate/views/estate_property_offer_views.xml @@ -0,0 +1,22 @@ + + + + + estate.property.offer.view.form + estate.property.offer + +
+ + + + + + + +
+
+
+ + +
+
diff --git a/estate/views/estate_property_tag_views.xml b/estate/views/estate_property_tag_views.xml new file mode 100644 index 00000000000..7d7ed6bfd4f --- /dev/null +++ b/estate/views/estate_property_tag_views.xml @@ -0,0 +1,11 @@ + + + + Property Tags + estate.property.tag + list,form + + + + + diff --git a/estate/views/estate_property_type_views.xml b/estate/views/estate_property_type_views.xml new file mode 100644 index 00000000000..2ff0061f4a1 --- /dev/null +++ b/estate/views/estate_property_type_views.xml @@ -0,0 +1,11 @@ + + + + Property Types + estate.property.type + list,form + + + + + diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index c1ce91a7081..099a827f94b 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -5,11 +5,10 @@ Properties estate.property list,form - - - estate.property.view.list + + estate.property.view.list estate.property @@ -21,18 +20,21 @@ - + estate.property.view.form estate.property -
+

+ + + @@ -54,15 +56,32 @@ + + + + + + + + + + + + + + + + +
- + estate.property.view.search estate.property @@ -73,9 +92,12 @@ + + + - \ No newline at end of file + From af442003fa90e6dc35f1bfd60115ee8ced289480 Mon Sep 17 00:00:00 2001 From: matho-odoo Date: Wed, 22 Oct 2025 11:20:59 +0200 Subject: [PATCH 4/8] [IMP] estate: chapter 8 --- estate/__manifest__.py | 2 +- estate/models/__init__.py | 4 +-- estate/models/estate_property.py | 29 ++++++++++++++++---- estate/models/estate_property_offer.py | 16 +++++++++-- estate/models/estate_property_tag.py | 1 + estate/models/estate_property_type.py | 1 + estate/views/estate_property_offer_views.xml | 2 ++ estate/views/estate_property_views.xml | 2 ++ 8 files changed, 47 insertions(+), 10 deletions(-) diff --git a/estate/__manifest__.py b/estate/__manifest__.py index 6d34ec4fcba..d2404521341 100644 --- a/estate/__manifest__.py +++ b/estate/__manifest__.py @@ -7,7 +7,7 @@ 'base', ], 'data': [ - 'security/ir.model.access.csv', + 'security/ir.model.access.csv', 'views/estate_property_views.xml', 'views/estate_property_type_views.xml', 'views/estate_property_tag_views.xml', diff --git a/estate/models/__init__.py b/estate/models/__init__.py index 3b4e0f595da..2f1821a39c1 100644 --- a/estate/models/__init__.py +++ b/estate/models/__init__.py @@ -1,4 +1,4 @@ -from . import estate_property -from . import estate_property_type +from . import estate_property +from . import estate_property_type from . import estate_property_tag from . import estate_property_offer diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index fb646803a3b..2a70120a491 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -1,4 +1,4 @@ -from odoo import fields, models +from odoo import api, fields, models class EstateProperty(models.Model): @@ -10,7 +10,7 @@ class EstateProperty(models.Model): postcode = fields.Char() date_availability = fields.Date(default=fields.Date.add(fields.Date.today(), months=3), copy=False) expected_price = fields.Float(required=True) - selling_price = fields.Float(readonly=True,copy=False) + selling_price = fields.Float(readonly=True, copy=False) bedrooms = fields.Integer(default=2) living_area = fields.Integer() facades = fields.Integer() @@ -19,7 +19,7 @@ class EstateProperty(models.Model): garden_area = fields.Integer() garden_orientation = fields.Selection( string='Garden orientation', - selection=[('North', 'N'), ('South', 'S'),('East', 'E'),('West', 'W')], + selection=[('North', 'N'), ('South', 'S'), ('East', 'E'), ('West', 'W')], help="Specify the orientation of the garden to know when you're gonna enjoy the sun") state = fields.Selection( selection=[('New', 'New'), ('Offer Received', 'Offer Received'), ('Offer Accepted', 'Offer Accepted'), ('Sold', 'Sold'), ('Cancelled', 'Cancelled')], @@ -28,5 +28,24 @@ class EstateProperty(models.Model): active = fields.Boolean(default=True) salesman = fields.Many2one("res.users") buyer = fields.Many2one("res.partner", copy=False) - tag_ids=fields.Many2many("estate.property.tag", string="Tags") - offer_ids=fields.One2many("estate.property.offer","property_id") + tag_ids = fields.Many2many("estate.property.tag", string="Tags") + offer_ids = fields.One2many("estate.property.offer", "property_id") + total_area = fields.Float(compute="_compute_total") + best_price = fields.Float(compute="_compute_highest_price") + + @api.depends("living_area", "garden_area") + def _compute_total(self): + for record in self: + record.total_area = record.living_area + record.garden_area + + @api.depends("offer_ids") + def _compute_highest_price(self): + for record in self: + record.best_price=max(record.offer_ids.mapped("price")) if record.offer_ids else 0 + + @api.onchange("garden") + def _onchange_garden(self): + self.garden_area = 10 if self.garden else 0 + self.garden_orientation = "North" if self.garden else None + + diff --git a/estate/models/estate_property_offer.py b/estate/models/estate_property_offer.py index e087f94c7a8..9a7f910df71 100644 --- a/estate/models/estate_property_offer.py +++ b/estate/models/estate_property_offer.py @@ -1,10 +1,22 @@ -from odoo import fields, models +from odoo import api, fields, models + class EstatePropertyOffer(models.Model): _name = "estate.property.offer" _description = "ici je mets une phrase 4" price = fields.Float() - status = fields.Selection(copy=False, selection=[('Accepted', 'Accepted'), ('Refused', 'Refused')],) + status = fields.Selection(copy=False, selection=[('Accepted', 'Accepted'), ('Refused', 'Refused')]) partner_id = fields.Many2one("res.partner", required=True) property_id = fields.Many2one("estate.property", required=True) + validity = fields.Integer(default=7) + date_deadline = fields.Date(compute="_compute_deadline", inverse="_inverse_deadline") + + @api.depends("validity") + def _compute_deadline(self): + for record in self: + record.date_deadline = fields.Date.add(record.create_date or fields.Date.today(), days=record.validity) + + def _inverse_deadline(self): + for record in self : + record.validity = (record.date_deadline - fields.Date.to_date(record.create_date)).days diff --git a/estate/models/estate_property_tag.py b/estate/models/estate_property_tag.py index 30f1dfb7315..ad23d81eaf9 100644 --- a/estate/models/estate_property_tag.py +++ b/estate/models/estate_property_tag.py @@ -1,5 +1,6 @@ from odoo import fields, models + class EstatePropertyTag(models.Model): _name = "estate.property.tag" _description = "ici je mets une phrase 3" diff --git a/estate/models/estate_property_type.py b/estate/models/estate_property_type.py index e80997c85bb..d05d51731a4 100644 --- a/estate/models/estate_property_type.py +++ b/estate/models/estate_property_type.py @@ -1,5 +1,6 @@ from odoo import fields, models + class EstatePropertyType(models.Model): _name = "estate.property.type" _description = "ici je mets une phrase 2" diff --git a/estate/views/estate_property_offer_views.xml b/estate/views/estate_property_offer_views.xml index 8048cb251c2..9bf8fd5c062 100644 --- a/estate/views/estate_property_offer_views.xml +++ b/estate/views/estate_property_offer_views.xml @@ -11,6 +11,8 @@ + + diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index 099a827f94b..a2791d5d44d 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -42,6 +42,7 @@ + @@ -57,6 +58,7 @@ + From cda8d013c8fac3bae45eed36e3517e752233a200 Mon Sep 17 00:00:00 2001 From: matho-odoo Date: Wed, 22 Oct 2025 13:37:51 +0200 Subject: [PATCH 5/8] [IMP] estate: chapter 9 --- estate/models/estate_property.py | 19 +++++++++++++++---- estate/models/estate_property_offer.py | 12 +++++++++++- estate/views/estate_property_views.xml | 6 ++++++ 3 files changed, 32 insertions(+), 5 deletions(-) diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py index 2a70120a491..fa4a40cea8e 100644 --- a/estate/models/estate_property.py +++ b/estate/models/estate_property.py @@ -1,4 +1,5 @@ from odoo import api, fields, models +from odoo.exceptions import UserError class EstateProperty(models.Model): @@ -37,15 +38,25 @@ class EstateProperty(models.Model): def _compute_total(self): for record in self: record.total_area = record.living_area + record.garden_area - + @api.depends("offer_ids") def _compute_highest_price(self): for record in self: - record.best_price=max(record.offer_ids.mapped("price")) if record.offer_ids else 0 - + record.best_price = max(record.offer_ids.mapped("price")) if record.offer_ids else 0 + @api.onchange("garden") def _onchange_garden(self): self.garden_area = 10 if self.garden else 0 self.garden_orientation = "North" if self.garden else None - + def action_mark_as_sold(self): + if self.state == "Cancelled": + raise UserError("Cette vente a été annulée") + self.state = "Sold" + return True + + def action_mark_as_cancelled(self): + if self.state == "Sold": + raise UserError("Cette maison a déjà été vendue") + self.state = "Cancelled" + return True diff --git a/estate/models/estate_property_offer.py b/estate/models/estate_property_offer.py index 9a7f910df71..e7f815136d4 100644 --- a/estate/models/estate_property_offer.py +++ b/estate/models/estate_property_offer.py @@ -18,5 +18,15 @@ def _compute_deadline(self): record.date_deadline = fields.Date.add(record.create_date or fields.Date.today(), days=record.validity) def _inverse_deadline(self): - for record in self : + for record in self: record.validity = (record.date_deadline - fields.Date.to_date(record.create_date)).days + + def action_accept(self): + self.status = "Accepted" + self.property_id.buyer = self.partner_id + self.property_id.selling_price = self.price + return True + + def action_refuse(self): + self.status = "Refused" + return True diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index a2791d5d44d..f8a1a251733 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -28,6 +28,10 @@ estate.property
+
+

@@ -66,6 +70,8 @@ + +

diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml index a1e8a5e92be..16cc44f3f90 100644 --- a/estate/views/estate_property_views.xml +++ b/estate/views/estate_property_views.xml @@ -5,13 +5,14 @@ Properties estate.property list,form + {'search_default_availibility': True} estate.property.view.list estate.property - + @@ -67,12 +68,12 @@ - + -