Skip to content
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

mcou - Technical Training #58

Closed
wants to merge 28 commits into from
Closed
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
51147c4
Changed the readme
Apr 16, 2024
d67d73f
End of chapter 2
Apr 16, 2024
e238151
End of chapter 3
Apr 16, 2024
de6873b
End of chapter 4
Apr 16, 2024
b25e0a5
End of chapter 5
Apr 16, 2024
21898ca
Real end of chapter 5
Apr 16, 2024
33ebdd3
End of chapter 6
Apr 16, 2024
cca64cf
End of chapter 7
Apr 17, 2024
f90a0c9
End of chapter 8
Apr 17, 2024
3ad4658
End of chapter 9
Apr 17, 2024
21b8cc7
End of chapter 10
Apr 17, 2024
6b765b3
End of chapter 11
Apr 18, 2024
d1d0eb3
[IMP] Training: correcting style of python files
Apr 18, 2024
45fc109
[IMP] Training: corrected the last 3 style problems
Apr 18, 2024
6d1fffa
[IMP] Training: End of chapter 12
Apr 18, 2024
ef37ef7
[IMP] Training: End of chapter 13
Apr 18, 2024
e7f6404
[IMP] Training: End of chapter 14
Apr 18, 2024
2d88ae4
[IMP] Training: End of chapter 15
Apr 19, 2024
9d69f34
[IMP] Training: Add the demo data loading
Apr 22, 2024
3728804
[IMP] Training: Chapter 1 of web framework
Apr 22, 2024
094299f
[IMP] Training: Finished point 8 of chapter 2 of the web framework
Apr 24, 2024
53cb9d6
[IMP] Training: End of point 10
Apr 24, 2024
12d80f3
[IMP] Training: End of point 11 (web, chapter 2)
Apr 25, 2024
9cf7f59
[IMP] Training: implemented translation
Apr 25, 2024
d6472fa
[IMP] Training: Click on pie chart opens the tree view of orders
Apr 26, 2024
ee40a6b
[IMP] Training: Beginning of clicker game
Apr 26, 2024
35488f7
[IMP] Training: clicker game end of point 7
Apr 26, 2024
6ad83f9
[IMP] Training: Clicker end of point 12
Apr 29, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,5 @@ It has 3 branches for each Odoo version: one for the bases, one for
The first contains the code of the modules that serve as base for the tutorials,
and the others contains the code of each chapter with the complete
solution.

Just adding something to commit. Don't mind.
1 change: 1 addition & 0 deletions estate/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import models
12 changes: 12 additions & 0 deletions estate/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
'name': "Estate",
'application': True,
'data': [
'security/ir.model.access.csv',
'views/actions.xml',
'views/property_views.xml',
'views/property_type_views.xml',
'views/menus.xml',
'views/property_tag_views.xml',
]
}
4 changes: 4 additions & 0 deletions estate/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from . import property
from . import property_type
from . import property_tag
from . import property_offer
91 changes: 91 additions & 0 deletions estate/models/property.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
from odoo import api, fields, models
from odoo.tools import date_utils
from odoo.exceptions import UserError, ValidationError
from odoo.tools.float_utils import float_compare

def date_in_3_months(*args):
return date_utils.add(fields.Date.today(), months=3)

class EstateProperty(models.Model):
_name = "estate.property"
_description = "App to handle your real estate."

name = fields.Char(required=True)
description = fields.Text()
postcode = fields.Char()
date_availability = fields.Date(string="Available From", default=date_in_3_months, 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(string="Living Area (sqm)")
facades = fields.Integer()
garage = fields.Boolean()
garden = fields.Boolean()
garden_area = fields.Integer()
garden_orientation = fields.Selection(
selection=[('north', 'North'), ('south', 'South'), ('east', 'East'), ('west', 'West')]
)
active = fields.Boolean(default=True)
state = fields.Selection(
required=True,
selection=[('new', 'New'), ('offer_received', 'Offer Received'), ('offer_accepted', 'Offer Accepted'), ('sold', 'Sold'), ('canceled', 'Canceled')],
default = 'new',
copy=False
)
property_type_id = fields.Many2one("estate.property.type", string="Property Type")
salesperson = fields.Many2one("res.users", default=lambda self: self.env.user)
buyer = fields.Many2one("res.partner", copy=False)
tag_ids = fields.Many2many("estate.property.tag")
offer_ids = fields.One2many("estate.property.offer", "property_id", string="Offers")
total_area = fields.Integer(compute="_compute_total_area")
best_price = fields.Float(compute="_compute_best_price")
_sql_constraints = [

Choose a reason for hiding this comment

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

put your constraint at the top of your class, after _description

('check_expected_price', 'CHECK(expected_price > 0)',
'A property expected price must be strictly positive.'),
('check_selling_price', 'CHECK(selling_price >= 0)',
'A property selling price must be positive.')
]

@api.depends("living_area", "garden_area")
def _compute_total_area(self):
for property in self:
property.total_area = property.living_area + property.garden_area

@api.depends("offer_ids")
def _compute_best_price(self):
for property in self:
if len(property.offer_ids) == 0:
property.best_price = False
continue
property.best_price = max(property.offer_ids.mapped('price'))

@api.onchange("garden")
def _onchange_partner_id(self):
if(self.garden):
self.garden_area = 10
self.garden_orientation = "south"
else:
self.garden_area = False
self.garden_orientation = False

def action_set_sold_property(self):
for property in self:
if(property.state == "canceled"):
raise UserError("Canceled properties cannot be sold.")
continue

Choose a reason for hiding this comment

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

with a raise continue is useless

property.state = "sold"
return True

def action_set_canceled_property(self):
for property in self:
if(property.state == "sold"):
raise UserError("Sold properties cannot be canceled.")
continue
property.state = "canceled"
return True

@api.constrains('selling_price', 'expected_price')
def _check_date_end(self):
for property in self:
if float_compare(property.selling_price, property.expected_price * 0.9, 2) < 0 and float_compare(property.selling_price, 0, 2) > 0:
raise ValidationError('The selling price cannot be lower than 90% of the expected price.')
52 changes: 52 additions & 0 deletions estate/models/property_offer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
from odoo import api, fields, models
from odoo.tools import date_utils
from odoo.exceptions import UserError

class PropertyOffer(models.Model):
_name = "estate.property.offer"
_description = "describes an offer made on a property"

price = fields.Float()
status = fields.Selection(
selection=[('accepted', 'Accepted'), ('refused', 'Refused')],
copy = False
)
partner_id = fields.Many2one("res.partner", required = True)
property_id = fields.Many2one("estate.property", required = True)
validity = fields.Integer()
date_deadline = fields.Date(compute="_compute_date_deadline", inverse="_inverse_date_deadline", string="Deadline")
_sql_constraints = [
('check_price', 'CHECK(price > 0)',
'An offer price must be strictly positive.')
]

@api.depends("validity")
def _compute_date_deadline(self):
for offer in self:
if(not offer.create_date): # When creating an offer create_date is not defined yet
offer.date_deadline = date_utils.add(fields.Date.today(), days=offer.validity)
continue
offer.date_deadline = date_utils.add(offer.create_date, days=offer.validity)

def _inverse_date_deadline(self):
for offer in self:
if(not offer.create_date): # When creating an offer create_date is not defined yet
offer.validity = (offer.date_deadline - fields.Date.today()).days
continue
offer.validity = (offer.date_deadline - offer.create_date.date()).days

def action_confirm_offer(self):
if "accepted" in self.mapped("property_id.offer_ids.status"):
raise UserError("Another offer is accepted.")
return True
self.status = "accepted"
self.property_id.buyer = self.partner_id
self.property_id.selling_price = self.price
return True

def action_refuse_offer(self):
for offer in self:
offer.status = "refused"
offer.property_id.buyer = False
offer.property_id.selling_price = False
return True
10 changes: 10 additions & 0 deletions estate/models/property_tag.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from odoo import fields, models

class PropertyTag(models.Model):
_name = "estate.property.tag"
_description = "tag of a property"

name = fields.Char(required=True)
_sql_constraints = [('name_unique', 'unique(name)', 'A property tag name must be unique')]


8 changes: 8 additions & 0 deletions estate/models/property_type.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from odoo import fields, models

class PropertyType(models.Model):
_name = "estate.property.type"
_description = "describes the type of a property"

name = fields.Char(required=True)
_sql_constraints = [('name_unique', 'unique(name)', 'A property type name must be unique')]
5 changes: 5 additions & 0 deletions estate/security/ir.model.access.csv
Original file line number Diff line number Diff line change
@@ -0,0 +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
22 changes: 22 additions & 0 deletions estate/views/actions.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<data>
<record id="estate_property" model="ir.actions.act_window">
<field name="name">Properties</field>
<field name="res_model">estate.property</field>
<field name="view_mode">tree,form,search</field>
</record>

<record id="estate_property_type" model="ir.actions.act_window">
<field name="name">Property Types</field>
<field name="res_model">estate.property.type</field>
<field name="view_mode">tree,form,search</field>
</record>

<record id="estate_property_tag" model="ir.actions.act_window">
<field name="name">Property Tags</field>
<field name="res_model">estate.property.tag</field>
<field name="view_mode">tree,form,search</field>
</record>
</data>
</odoo>
14 changes: 14 additions & 0 deletions estate/views/menus.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<data>
<menuitem id="estate_menu_root" name="Estate">
<menuitem id="estate_first_level_menu_advertisements" name="Advertisements">
<menuitem id="estate_model_menu_property" action="estate_property"/>
</menuitem>
<menuitem id="estate_first_level_menu_settings" name="Settings">
<menuitem id="estate_model_menu_property_type" action="estate_property_type"/>
<menuitem id="estate_model_menu_property_tag" action="estate_property_tag"/>
</menuitem>
</menuitem>
</data>
</odoo>
34 changes: 34 additions & 0 deletions estate/views/property_offer_views.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<data>
<record id="property_offer_view_tree" model="ir.ui.view">
<field name="name">property.offers.view.tree</field>
<field name="model">estate.property.offer</field>
<field name="arch" type="xml">
<tree string="Estate">
<field name="price"/>
<field name="partner_id"/>
<field name="validity"/>
<field name="date_deadline"/>
<field name="status"/>
</tree>
</field>
</record>

<record id="property_offer_view_form" model="ir.ui.view">
<field name="name">property.offers.view.form</field>
<field name="model">estate.property.offer</field>
<field name="arch" type="xml">
<form string="Estate">
<sheet>
<field name="price"/>
<field name="partner_id"/>
<field name="validity"/>
<field name="date_deadline"/>
<field name="status"/>
</sheet>
</form>
</field>
</record>
</data>
</odoo>
36 changes: 36 additions & 0 deletions estate/views/property_tag_views.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<data>
<record id="property_tag_view_tree" model="ir.ui.view">
<field name="name">property.tags.view.tree</field>
<field name="model">estate.property.tag</field>
<field name="arch" type="xml">
<tree string="Estate">
<field name="name"/>
</tree>
</field>
</record>

<record id="property_tag_view_form" model="ir.ui.view">
<field name="name">property.tags.view.form</field>
<field name="model">estate.property.tag</field>
<field name="arch" type="xml">
<form string="Estate">
<sheet>
<h1><field name="name"/></h1>
</sheet>
</form>
</field>
</record>

<record id="property_tag_view_search" model="ir.ui.view">
<field name="name">property.tags.view.search</field>
<field name="model">estate.property.tag</field>
<field name="arch" type="xml">
<search string="Estate">
<field name="name"/>
</search>
</field>
</record>
</data>
</odoo>
36 changes: 36 additions & 0 deletions estate/views/property_type_views.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<data>
<record id="property_type_view_tree" model="ir.ui.view">
<field name="name">property.types.view.tree</field>
<field name="model">estate.property.type</field>
<field name="arch" type="xml">
<tree string="Estate">
<field name="name"/>
</tree>
</field>
</record>

<record id="property_type_view_form" model="ir.ui.view">
<field name="name">property.types.view.form</field>
<field name="model">estate.property.type</field>
<field name="arch" type="xml">
<form string="Estate">
<sheet>
<h1><field name="name"/></h1>
</sheet>
</form>
</field>
</record>

<record id="property_type_view_search" model="ir.ui.view">
<field name="name">property.types.view.search</field>
<field name="model">estate.property.type</field>
<field name="arch" type="xml">
<search string="Estate">
<field name="name"/>
</search>
</field>
</record>
</data>
</odoo>