Skip to content

Commit

Permalink
[ADD] estate: Add Inheritance And Interact With Other Modules
Browse files Browse the repository at this point in the history
Add business logic and view inheritance for real estate module

- Implemented business logic to prevent deletion of properties unless their
state is 'New' or 'Canceled'.
- Added a new field `property_ids` to the `res.users` model to list
properties associated with a salesperson.
- Extended the user form view to display the new `property_ids` field in a
new notebook page.
Completed till chapter 12

Implement invoice creation upon property sale

- Created `estate_account` module as a link module with dependencies on
`estate` and `account`.
- Inherited `estate.property` model in `estate_account` to extend the property
sale action.
- Overrode the `action_sold` method to call super and initiate invoice creation.
- Added logic to create a customer invoice when a property is set to 'Sold'.
- Included invoice lines with 6% of the selling price and an additional
100.00 for administrative fees.
The new functionality ensures that invoices are generated automatically in
the Invoicing module when a property sale is confirmed.
Completed till chapter 13
  • Loading branch information
irah-odoo committed Aug 14, 2024
1 parent 3dfbbeb commit 4593aab
Show file tree
Hide file tree
Showing 13 changed files with 265 additions and 66 deletions.
1 change: 1 addition & 0 deletions estate/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

'data': [
'security/ir.model.access.csv',
'view/res_user_views.xml',
'view/estate_property_views.xml',
'view/estate_property_offer_views.xml',
'view/estate_property_type_views.xml',
Expand Down
2 changes: 1 addition & 1 deletion estate/models/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

from . import estate_property
from . import estate_property_type
from . import estate_property_tag
from . import estate_property_offer
from . import res_user
72 changes: 53 additions & 19 deletions estate/models/estate_property.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@ class estate_property(models.Model):
_name = "estate_property"
_description = "Estate Property"
_order = "sequence, id desc"
_inherit = ['mail.thread', 'mail.activity.mixin']
_inherit = ["mail.thread", "mail.activity.mixin"]

name = fields.Char(required=True)
description = fields.Text()
sequence = fields.Integer('Sequence')
sequence = fields.Integer("Sequence")
postcode = fields.Char()
date_availability = fields.Date(default=date.today() + relativedelta(month=3))
expected_price = fields.Float(required=True)
Expand All @@ -23,42 +24,67 @@ class estate_property(models.Model):
garden = fields.Boolean()
garden_area = fields.Integer()
active = fields.Boolean(default=True)
state = fields.Selection(default='new', selection=[('new', 'New'), ('offer_received', 'Offer Received'), ('offer_accepted', 'Offer Accepted'), ('sold', 'Sold'), ('canceled', 'Canceled')], tracking=True)
garden_orientation = fields.Selection(selection=[('north', 'North'), ('south', 'South'), ('east', 'East'), ('west', 'West')])
state = fields.Selection(
default="new",
selection=[
("new", "New"),
("offer_received", "Offer Received"),
("offer_accepted", "Offer Accepted"),
("sold", "Sold"),
("canceled", "Canceled"),
],
tracking=True,
)
garden_orientation = fields.Selection(
selection=[
("north", "North"),
("south", "South"),
("east", "East"),
("west", "West"),
]
)
property_type = fields.Many2one("estate_property_type", string="Property Type")
salesperson_id = fields.Many2one('res.users', string='Selesperson', default=lambda self: self.env.user)
buyer_id = fields.Many2one('res.partner', string='Buyer', copy=False, ondelete='cascade')
salesperson_id = fields.Many2one(
"res.users", string="Selesperson", default=lambda self: self.env.user
)
buyer_id = fields.Many2one(
"res.partner", string="Buyer", copy=False, ondelete="cascade"
)
tag_ids = fields.Many2many("estate_property_tag", string="Tags")
offer_ids = fields.One2many('estate_property_offer', 'property_id')
offer_ids = fields.One2many("estate_property_offer", "property_id")
total_area = fields.Float(compute="_compute_total")
best_offer = fields.Float(compute="_best_offer")
_sql_constraints = [
('check_Expected_price', 'CHECK(expected_price > 0)', 'Expected Price must be strictly positive'),
('check_selling_price', 'CHECK(selling_price >= 0)', 'Selling Price selling price must be positive'),
('unique_name', 'UNIQUE(name)', 'Property type name must be unique')
(
"check_Expected_price",
"CHECK(expected_price > 0)",
"Expected Price must be strictly positive",
),
(
"check_selling_price",
"CHECK(selling_price >= 0)",
"Selling Price selling price must be positive",
),
("unique_name", "UNIQUE(name)", "Property type name must be unique"),
]

@api.depends()
def _compute_total(self):
for record in self:
record.total_area = record.garden_area + record.livingArea

@api.depends('offer_ids')
@api.depends("offer_ids")
def _best_offer(self):
maximum_price = 0
for record in self.offer_ids:
if record.price > maximum_price:
maximum_price = record.price
self.best_offer = maximum_price

@api.onchange('garden')
@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 = ''
self.garden_area = 0.00

def button_action_sold(self):
if self.state == "canceled":
Expand All @@ -72,11 +98,19 @@ def button_action_cancled(self):
else:
self.state = "canceled"

@api.constrains('selling_price', 'expected_price')
@api.constrains("selling_price", "expected_price")
def _price_constrains(self):
for record in self:
if record.selling_price > 0:
if record.selling_price < 0.9 * record.expected_price:
raise ValidationError("Selling price cannot be lower than 90% of the expected price")
raise ValidationError(
"Selling price cannot be lower than 90% of the expected price"
)
else:
pass

@api.ondelete(at_uninstall=False)
def _delete_state(self):
for record in self:
if record.state != "new" and record.state != "canceled":
raise ValidationError("can't be deleted")
53 changes: 40 additions & 13 deletions estate/models/estate_property_offer.py
Original file line number Diff line number Diff line change
@@ -1,26 +1,30 @@
from odoo import models, fields, api
from datetime import date
from datetime import timedelta
from odoo.exceptions import UserError
from odoo.exceptions import UserError, ValidationError


class estate_property_offer(models.Model):
_name = "estate_property_offer"
_description = "Estate Property offer"
price = fields.Float()
_order = "sequence, price desc"
sequence = fields.Integer('Sequence')
sequence = fields.Integer("Sequence")
_sql_constraints = [
('offer_price', 'CHECK(price > 0)', 'offer price must be strictly positive')
("offer_price", "CHECK(price > 0)", "offer price must be strictly positive")
]
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_validity", string="Deadline")
date_deadline = fields.Date(
compute="_compute_deadline", inverse="_inverse_validity", string="Deadline"
)
property_type_id = fields.Many2one(related="property_id.property_type", store=True)

@api.depends('validity')
@api.depends("validity")
def _compute_deadline(self):
for record in self:
today = record.create_date
Expand All @@ -29,14 +33,16 @@ def _compute_deadline(self):
else:
today = date.today()
if record.date_deadline:
record.date_deadline = today + (record.validity - (record.date_deadline - today).days)
record.date_deadline = today + (
record.validity - (record.date_deadline - today).days
)
else:
record.date_deadline = timedelta(days=record.validity) + today

@api.ondelete(at_uninstall=False)
def _deletion_check(self):
for record in self:
if record.status == 'accepted':
if record.status == "accepted":
record.property_id.buyer_id = None
record.property_id.selling_price = 0

Expand All @@ -52,14 +58,35 @@ def action_confirm(self):
else:
self.property_id.selling_price = self.price
self.property_id.buyer_id = self.partner_id
self.status = 'accepted'
self.property_id.state = 'offer_accepted'
self.status = "accepted"
self.property_id.state = "offer_accepted"

def action_refused(self):
if self.status == 'accepted' and self.property_id.buyer_id == self.partner_id:
self.status = 'refused'
if self.status == "accepted" and self.property_id.buyer_id == self.partner_id:
self.status = "refused"
self.property_id.buyer_id = None
self.property_id.selling_price = 0
self.property_id.state = 'new'
self.property_id.state = "new"
else:
self.status = "refused"

@api.model
def create(self, vals):
property_id = vals.get("property_id")
offer_amount = vals.get("price")
property_record = self.env["estate_property"].browse(property_id)
if not property_record:
raise ValidationError("record not found")
existing_offers = self.search([("property_id", "=", property_id)])
highest_offer = 0
for offer in existing_offers:
if offer.price >= highest_offer:
highest_offer = offer.price
# Check if the new offer amount is lower than the highest existing offer
if offer_amount < highest_offer:
raise ValidationError(
"The new offer amount must be higher than the existing highest offer."
)
if property_record.state != "offer_received":
property_record.state = "offer_received"
return super(estate_property_offer, self).create(vals)
4 changes: 2 additions & 2 deletions estate/models/estate_property_tag.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ class estate_property_tag(models.Model):
_description = "Estate Property Tag"
name = fields.Char(required=True)
_order = " sequence, name"
sequence = fields.Integer('Sequence')
sequence = fields.Integer("Sequence")
color = fields.Integer()

_sql_constraints = [
('unique_tag', 'UNIQUE(name)', 'Property Tag name must be unique')
("unique_tag", "UNIQUE(name)", "Property Tag name must be unique")
]
14 changes: 9 additions & 5 deletions estate/models/estate_property_type.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,16 @@ class estate_property_type(models.Model):
_description = "Estate Property Type"
name = fields.Char(required=True)
_order = "sequence, name"
sequence = fields.Integer('Sequence')
property_list_id = fields.One2many('estate_property', 'property_type')
offer_ids = fields.One2many("estate_property_offer", "property_type_id", string="offers")
offer_count = fields.Integer(string="Numbers of offer", compute='_compute_offer_count', store=True)
sequence = fields.Integer("Sequence")
property_list_id = fields.One2many("estate_property", "property_type")
offer_ids = fields.One2many(
"estate_property_offer", "property_type_id", string="offers"
)
offer_count = fields.Integer(
string="Numbers of offer", compute="_compute_offer_count", store=True
)

@api.depends('offer_ids')
@api.depends("offer_ids")
def _compute_offer_count(self):
for record in self:
record.offer_count = len(record.offer_ids)
12 changes: 12 additions & 0 deletions estate/models/res_user.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from odoo import models, fields


class resUser(models.Model):
_inherit = "res.users"

property_ids = fields.One2many(
"estate_property",
"salesperson_id",
string="Properties",
domain="['|',('state', '=', 'new'),('state', '=', 'offer_received')]",
)
Loading

0 comments on commit 4593aab

Please sign in to comment.