-
Notifications
You must be signed in to change notification settings - Fork 2.7k
MATHO Onboarding #999
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
base: 19.0
Are you sure you want to change the base?
MATHO Onboarding #999
Changes from all commits
7076246
8f82d4d
3ebb0c4
af44200
cda8d01
b1080de
a1c6851
46f5af8
c9a5f70
501c609
546c566
c2570ab
878b856
804d83a
3234ee9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| from . import models |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| { | ||
| 'name': 'Estate', | ||
| 'version': '0.1', | ||
| 'license': 'LGPL-3', | ||
| 'application': True, | ||
| 'author': 'matho', | ||
| 'depends': [ | ||
| 'base', | ||
| ], | ||
| 'data': [ | ||
| 'security/ir.model.access.csv', | ||
| 'views/estate_property_offer_views.xml', | ||
| 'views/estate_property_views.xml', | ||
| 'views/estate_property_type_views.xml', | ||
| 'views/estate_property_tag_views.xml', | ||
| 'views/res_users_views.xml', | ||
| 'views/estate_menus.xml', | ||
| ] | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| from . import estate_property | ||
| from . import estate_property_type | ||
| from . import estate_property_tag | ||
| from . import estate_property_offer | ||
| from . import res_users |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,82 @@ | ||
| from odoo import api, fields, models, _ | ||
| from odoo.exceptions import UserError, ValidationError | ||
| from odoo.tools.float_utils import float_compare | ||
|
|
||
|
|
||
| class EstateProperty(models.Model): | ||
| _name = "estate.property" | ||
| _description = "Estate Property" | ||
| _order = "id desc" | ||
| _check_expected_price = models.Constraint("CHECK(expected_price>0)", "Le prix doit être strictement positif.") | ||
| _check_selling_price = models.Constraint("CHECK(selling_price>=0)", "Le prix doit être positif.") | ||
|
|
||
| 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) | ||
| salesman_id = fields.Many2one("res.users") | ||
| buyer_id = fields.Many2one("res.partner", copy=False) | ||
| tag_ids = fields.Many2many("estate.property.tag", string="Tags") | ||
| property_type_id = fields.Many2one("estate.property.type") | ||
| offer_ids = fields.One2many("estate.property.offer", "property_id") | ||
| total_area = fields.Float(compute="_compute_total_area") | ||
| best_price = fields.Float(compute="_compute_best_price") | ||
|
|
||
| @api.depends("living_area", "garden_area") | ||
| def _compute_total_area(self): | ||
| for record in self: | ||
| record.total_area = record.living_area + record.garden_area | ||
|
|
||
| @api.depends("offer_ids") | ||
| def _compute_best_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): | ||
| for record in self: | ||
| record.garden_area = 10 if record.garden else 0 | ||
| record.garden_orientation = "North" if record.garden else None | ||
|
|
||
| @api.ondelete(at_uninstall=False) | ||
| def _unlink_if_new_or_cancelled(self): | ||
| for record in self: | ||
| if record.state not in ['New', 'Cancelled']: | ||
| raise UserError(_("Seules les propriétés 'New' ou 'Cancelled' peuvent être supprimées.")) | ||
|
|
||
| def action_mark_as_sold(self): | ||
| self.ensure_one() | ||
| if self.state == "Cancelled": | ||
| raise UserError(_("Cette vente a été annulée")) | ||
| self.state = "Sold" | ||
| return True | ||
|
|
||
| def action_mark_as_cancelled(self): | ||
| self.ensure_one() | ||
| if self.state == "Sold": | ||
| raise UserError(_("Cette maison a déjà été vendue")) | ||
| self.state = "Cancelled" | ||
| return True | ||
|
|
||
| @api.constrains("selling_price", "expected_price") | ||
| def _check_selling_price_is_ok(self): | ||
| for record in self: | ||
| if record.selling_price and float_compare(record.selling_price, 0.9 * record.expected_price, 2) == -1: | ||
| raise ValidationError("Le prix de vente doit valoir au moins 90 pourcents du prix attendu.") | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,59 @@ | ||
| from odoo import api, fields, models, _ | ||
| from odoo.exceptions import UserError, ValidationError | ||
| from odoo.tools.float_utils import float_compare | ||
|
|
||
|
|
||
| class EstatePropertyOffer(models.Model): | ||
| _name = "estate.property.offer" | ||
| _description = "Estate Property Offer" | ||
| _order = "price desc" | ||
| _check_price = models.Constraint("CHECK(price>0)", "Le prix doit être strictement positif.") | ||
|
|
||
| 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) | ||
| property_type_id = fields.Many2one(related="property_id.property_type_id", store=True) | ||
| validity = fields.Integer(default=7) | ||
| date_deadline = fields.Date(compute="_compute_date_deadline", inverse="_inverse_date_deadline") | ||
|
|
||
| @api.depends("validity") | ||
| def _compute_date_deadline(self): | ||
| for record in self: | ||
| record.date_deadline = fields.Date.add(record.create_date or fields.Date.today(), days=record.validity) | ||
|
|
||
| def _inverse_date_deadline(self): | ||
| for record in self: | ||
| record.validity = (record.date_deadline - fields.Date.to_date(record.create_date)).days | ||
|
|
||
| def action_accept(self): | ||
| self.ensure_one() | ||
| if float_compare(self.price, self.property_id.best_price, 2) == -1: | ||
| raise ValidationError(_("Cette offre ne peut pas être acceptée car son montant est inférieur à %d", self.property_id.best_price)) | ||
| self.status = "Accepted" | ||
| self.property_id.state = "Offer Accepted" | ||
| self.property_id.buyer_id = self.partner_id | ||
| self.property_id.selling_price = self.price | ||
| return True | ||
|
|
||
| def action_refuse(self): | ||
matho-odoo marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| self.ensure_one() | ||
| self.status = "Refused" | ||
| return True | ||
|
|
||
| @api.constrains("price") | ||
| def _check_offer_price_is_ok(self): | ||
| for record in self: | ||
| if float_compare(record.price, record.property_id.best_price, 2) == -1: | ||
| raise ValidationError(_("Le prix de vente doit être supérieur à %d", record.property_id.best_price)) | ||
|
|
||
| @api.model_create_multi | ||
| def create(self, vals_list): | ||
| property_ids =[offer['property_id'] for offer in vals_list] | ||
| properties = self.env["estate.property"].browse(property_ids) | ||
| for property in properties: | ||
| if property.state in ['Offer Accepted', 'Sold', 'Cancelled']: | ||
| raise ValidationError(_("Aucune n'offre ne peut être réalisée sur cette propriété actuellement.")) | ||
| offers = super().create(vals_list) | ||
| offers.property_id.state = 'Offer Received' | ||
| return offers | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| from odoo import fields, models | ||
|
|
||
|
|
||
| class EstatePropertyTag(models.Model): | ||
| _name = "estate.property.tag" | ||
| _description = "Estate Property Tag" | ||
| _order = "name" | ||
| _name_unique = models.Constraint("unique (name)", "Ce tag existe déjà.") | ||
|
|
||
| name = fields.Char(required=True) | ||
| color = fields.Integer() |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| from odoo import api, fields, models | ||
|
|
||
|
|
||
| class EstatePropertyType(models.Model): | ||
| _name = "estate.property.type" | ||
| _description = "Estate Property Type" | ||
| _order = "name" | ||
| _name_unique = models.Constraint("unique (name)", "Ce type de propriété existe déjà.") | ||
|
|
||
| name = fields.Char(required=True) | ||
| property_ids = fields.One2many("estate.property", "property_type_id") | ||
| sequence = fields.Integer('Sequence', default=1, help="Used to order stages. Lower is better.") | ||
| offer_ids = fields.One2many("estate.property.offer", "property_type_id") | ||
| offer_count = fields.Integer(compute="_compute_count") | ||
|
|
||
| @api.depends("offer_ids") | ||
| def _compute_count(self): | ||
| for record in self: | ||
| record.offer_count = len(record.offer_ids) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| from odoo import fields, models | ||
|
|
||
|
|
||
| class ResUsers(models.Model): | ||
| _inherit = "res.users" | ||
|
|
||
| property_ids = fields.One2many("estate.property", "salesman_id", domain=[('state', 'in', ['New', 'Offer Received'])]) |
| 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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| <odoo> | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The file should be named estate_property_menus.xml as it must contains the name of your model which is estate.property. |
||
| <data> | ||
| <menuitem id="test_menu_root" name="Real Estate"> | ||
| <menuitem id="advertisements_menu" name="Advertisements"> | ||
| <menuitem id="test_model_menu_action" action="mon_action"/> | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The id should be estate_property_menu and the action should be estate_property_action. |
||
| </menuitem> | ||
| <menuitem id="settings_menu" name="Settings"> | ||
| <menuitem id="test_model_menu_action2" action="estate_property_type_action"/> | ||
| <menuitem id="test_model_menu_action3" action="mon_action3"/> | ||
| </menuitem> | ||
| </menuitem> | ||
| </data> | ||
| </odoo> | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| <odoo> | ||
| <data> | ||
|
|
||
| <record id="estate_property_offer_view_form" model="ir.ui.view"> | ||
| <field name="name">estate.property.offer.view.form</field> | ||
| <field name="model">estate.property.offer</field> | ||
| <field name="arch" type="xml"> | ||
| <form string="Test"> | ||
| <sheet> | ||
| <group> | ||
| <field name="price"/> | ||
| <field name="partner_id"/> | ||
| <field name="status"/> | ||
| <field name="validity"/> | ||
| <field name="date_deadline"/> | ||
| <field name="property_type_id"/> | ||
| </group> | ||
| </sheet> | ||
| </form> | ||
| </field> | ||
| </record> | ||
|
|
||
| <record id="estate_property_offer_action" model="ir.actions.act_window"> | ||
| <field name="name">Offres</field> | ||
| <field name="res_model">estate.property.offer</field> | ||
| <field name="view_mode">list,form</field> | ||
| <field name="domain">[('property_type_id', '=', active_id)]</field> | ||
| </record> | ||
|
|
||
| <record id="estate_property_offer_view_list" model="ir.ui.view"> | ||
| <field name="name">estate.property.offer.view.list</field> | ||
| <field name="model">estate.property.offer</field> | ||
| <field name="arch" type="xml"> | ||
| <list string="Test"> | ||
| <field name="price"/> | ||
| <field name="partner_id"/> | ||
| <field name="status"/> | ||
| <field name="validity"/> | ||
| <field name="date_deadline"/> | ||
| <field name="property_type_id"/> | ||
| </list> | ||
| </field> | ||
| </record> | ||
|
|
||
| </data> | ||
| </odoo> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| <odoo> | ||
| <data> | ||
| <record id="mon_action3" model="ir.actions.act_window"> | ||
| <field name="name">Property Tags</field> | ||
| <field name="res_model">estate.property.tag</field> | ||
| <field name="view_mode">list,form</field> | ||
| </record> | ||
|
|
||
| <record id="estate_property_tag_view_list" model="ir.ui.view"> | ||
| <field name="name">estate.property.tag.view.list</field> | ||
| <field name="model">estate.property.tag</field> | ||
| <field name="arch" type="xml"> | ||
| <list editable="bottom"> | ||
| <field name="name"/> | ||
| </list> | ||
| </field> | ||
| </record> | ||
|
|
||
|
|
||
| </data> | ||
| </odoo> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,57 @@ | ||
| <odoo> | ||
| <data> | ||
| <record id="estate_property_type_action" model="ir.actions.act_window"> | ||
| <field name="name">Property Types</field> | ||
| <field name="res_model">estate.property.type</field> | ||
| <field name="view_mode">list,form</field> | ||
| </record> | ||
|
|
||
| <record id="estate_property_type_view_list" model="ir.ui.view"> | ||
| <field name="name">estate.property.type.view.list</field> | ||
| <field name="model">estate.property.type</field> | ||
| <field name="arch" type="xml"> | ||
| <list> | ||
| <field name="name"/> | ||
| <field name="sequence" widget="handle"/> | ||
| </list> | ||
| </field> | ||
| </record> | ||
|
|
||
| <record id="estate_property_type_view_form" model="ir.ui.view"> | ||
| <field name="name">estate.property.type.view.form</field> | ||
| <field name="model">estate.property.type</field> | ||
| <field name="arch" type="xml"> | ||
| <form string="Property Type"> | ||
| <sheet> | ||
| <div class="oe_button_box" name="button_box"> | ||
| <button name="%(estate.estate_property_offer_action)d" type="action" class="oe_stat_button" string="Offers" icon="fa-money"> | ||
| <div class="o_stat_info"> | ||
| <field name="offer_count" class="o_stat_value"></field> | ||
| <span class="o_stat_text"> | ||
| Offres | ||
| </span> | ||
| </div> | ||
| </button> | ||
| </div> | ||
| <h1> | ||
| <field name="name"/> | ||
| </h1> | ||
| <notebook> | ||
| <page string="Properties"> | ||
| <field name="property_ids"> | ||
| <list> | ||
| <field name="name" string="Title"/> | ||
| <field name="expected_price"/> | ||
| <field name="state"/> | ||
| </list> | ||
| </field> | ||
| </page> | ||
| </notebook> | ||
| </sheet> | ||
| </form> | ||
| </field> | ||
| </record> | ||
|
|
||
|
|
||
| </data> | ||
| </odoo> |
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One blank line is missing here. There must be two blank line above a class. It is in the pep8 😃 . This are the guidelines to have a clean python code.