diff --git a/.gitignore b/.gitignore
index b6e47617de1..c42b4c7a405 100644
--- a/.gitignore
+++ b/.gitignore
@@ -127,3 +127,5 @@ dmypy.json
# Pyre type checker
.pyre/
+
+.vscode
\ No newline at end of file
diff --git a/awesome_dashboard/__manifest__.py b/awesome_dashboard/__manifest__.py
index a1cd72893d7..a86d9bb991e 100644
--- a/awesome_dashboard/__manifest__.py
+++ b/awesome_dashboard/__manifest__.py
@@ -1,30 +1,26 @@
# -*- coding: utf-8 -*-
{
- 'name': "Awesome Dashboard",
-
- 'summary': """
+ "name": "Awesome Dashboard",
+ "summary": """
Starting module for "Discover the JS framework, chapter 2: Build a dashboard"
""",
-
- 'description': """
+ "description": """
Starting module for "Discover the JS framework, chapter 2: Build a dashboard"
""",
-
- 'author': "Odoo",
- 'website': "https://www.odoo.com/",
- 'category': 'Tutorials',
- 'version': '0.1',
- 'application': True,
- 'installable': True,
- 'depends': ['base', 'web', 'mail', 'crm'],
-
- 'data': [
- 'views/views.xml',
+ "author": "Odoo",
+ "website": "https://www.odoo.com/",
+ "category": "Tutorials",
+ "version": "0.1",
+ "application": True,
+ "installable": True,
+ "depends": ["base", "web", "mail", "crm"],
+ "data": [
+ "views/views.xml",
],
- 'assets': {
- 'web.assets_backend': [
- 'awesome_dashboard/static/src/**/*',
+ "assets": {
+ "web.assets_backend": [
+ "awesome_dashboard/static/src/**/*",
],
},
- 'license': 'AGPL-3'
+ "license": "AGPL-3",
}
diff --git a/estate/__init__.py b/estate/__init__.py
new file mode 100644
index 00000000000..0650744f6bc
--- /dev/null
+++ b/estate/__init__.py
@@ -0,0 +1 @@
+from . import models
diff --git a/estate/__manifest__.py b/estate/__manifest__.py
new file mode 100644
index 00000000000..18fa1afb8b0
--- /dev/null
+++ b/estate/__manifest__.py
@@ -0,0 +1,21 @@
+{
+ "name": "real estate",
+ "author": "Lokesh",
+ "version": "1.0.0",
+ "license": "LGPL-3",
+ # "depends": ["base"],
+ "application": True,
+ "installable": True,
+ "data": [
+ "security/ir.model.access.csv",
+ "views/estate_property_views.xml", # the order should be like this, first we need to define the views and then we need to define the action and then the menu if the order is not maintained then error will be thrown.
+ "views/estate_property_type_view.xml",
+ "views/estate_property_tag_view.xml",
+ "views/estate_property_menu.xml",
+ ],
+ "assets": {
+ "web.assets_backend": [
+ "estate/static/src/estate.css",
+ ],
+ },
+}
diff --git a/estate/models/__init__.py b/estate/models/__init__.py
new file mode 100644
index 00000000000..5f7fb776fd7
--- /dev/null
+++ b/estate/models/__init__.py
@@ -0,0 +1,4 @@
+from . import estate_property
+from . import estate_property_offers
+from . import estate_property_tag
+from . import estate_property_type
diff --git a/estate/models/estate_property.py b/estate/models/estate_property.py
new file mode 100644
index 00000000000..1bc6c395a06
--- /dev/null
+++ b/estate/models/estate_property.py
@@ -0,0 +1,85 @@
+from dateutil.relativedelta import relativedelta
+from odoo import api
+from odoo import fields
+from odoo import models
+from odoo.exceptions import ValidationError
+
+
+class EstateProperty(models.Model):
+ _name = "estate.property"
+ _description = "This is a dummy table"
+
+ name = fields.Char(translate=True, default="Unknown", required=True)
+ description = fields.Text()
+ postcode = fields.Char()
+ date_availability = fields.Date(
+ copy=False, default=lambda self: fields.Date.today() + relativedelta(months=3)
+ )
+ expected_price = fields.Float(required=True)
+ selling_price = fields.Float(readonly=True, copy=False)
+ bedrooms = fields.Integer()
+ living_area = fields.Integer()
+ facades = fields.Integer()
+ garage = fields.Boolean()
+ garden = fields.Boolean()
+ garden_area = fields.Integer()
+ garden_orientation = fields.Selection(
+ [
+ ("north", "North"),
+ ("south", "South"),
+ ("east", "East"),
+ ("west", "West"),
+ ],
+ string="Direction",
+ default="north",
+ )
+ state = fields.Selection(
+ [
+ ("new", "New"),
+ ("offer_received", "Offer Receeived"),
+ ("offer_accepted", "Offer Accepted"),
+ ("sold", "Sold"),
+ ("cancelled", "Cancelled"),
+ ]
+ )
+ active = fields.Boolean("Active", default=True)
+ property_type_id = fields.Many2one("estate.property.type", string="Property Type")
+ property_tag_ids = fields.Many2many(
+ "estate.property.tag",
+ relation="losbo_property_propertyTag",
+ string="Property_Tag",
+ column1="estate_property_id",
+ column2="estate_property_tag_id",
+ ondelete="cascade",
+ )
+ buyer = fields.Many2one("res.partner", string="buyer", copy=False)
+ user_id = fields.Many2one(
+ "res.users", string="salesperson", default=lambda self: self.env.user
+ )
+ offer_ids = fields.One2many("estate.property.offers", "property_id")
+ total_offers = fields.Integer(compute="_compute_offers")
+ total_area = fields.Float(compute="_compute_area")
+ best_price = fields.Integer(compute="_compute_price")
+
+ @api.depends("offer_ids")
+ def _compute_offers(self):
+ for record in self:
+ record.total_offers = len(record.offer_ids)
+
+ @api.constrains("name", "description")
+ def _check_description(self):
+ for record in self:
+ if record.name == record.description:
+ raise ValidationError("Fields name and description should not be equal")
+
+ @api.depends("living_area", "garden_area")
+ def _compute_area(self):
+ for record in self:
+ record.total_area = record.living_area + record.garden_area
+
+ @api.depends("offer_ids.price")
+ def _compute_price(self):
+ for records in self:
+ records.best_price = max(records.offer_ids.mapped("price"), default=0)
+
+ # @api.onchange('')
diff --git a/estate/models/estate_property_offers.py b/estate/models/estate_property_offers.py
new file mode 100644
index 00000000000..d1915c66922
--- /dev/null
+++ b/estate/models/estate_property_offers.py
@@ -0,0 +1,42 @@
+from datetime import date
+from dateutil.relativedelta import relativedelta
+from odoo import api
+from odoo import fields
+from odoo import models
+
+
+class PropertyOffer(models.Model):
+ _name = "estate.property.offers"
+ _description = "this model is used to define the offers received to the property"
+
+ price = fields.Float()
+ status = fields.Selection([("accepted", "Accepted"), ("refused", "Refused")])
+ partner_id = fields.Many2one("res.partner", required=True)
+ property_id = fields.Many2one("estate.property", required=True, ondelete="cascade")
+ deadline = fields.Date(
+ default=date.today(),
+ copy=False,
+ compute="_compute_deadline",
+ readonly=False,
+ # store=True,
+ )
+ validity_days = fields.Integer(
+ default=0,
+ copy=False,
+ compute="_compute_validity",
+ readonly=False,
+ # store=True
+ )
+
+ @api.depends("validity_days")
+ def _compute_deadline(self):
+ for records in self:
+ records.deadline = date.today() + relativedelta(days=records.validity_days)
+
+ @api.depends("deadline")
+ def _compute_validity(self):
+ for records in self:
+ diff = relativedelta(records.deadline, date.today())
+ records.validity_days = diff.days
+
+ # def inverse_func(self):
diff --git a/estate/models/estate_property_tag.py b/estate/models/estate_property_tag.py
new file mode 100644
index 00000000000..0eb50006c3d
--- /dev/null
+++ b/estate/models/estate_property_tag.py
@@ -0,0 +1,8 @@
+from odoo import fields, models
+
+
+class PropertyTag(models.Model):
+ _name = "estate.property.tag"
+ _description = "this model is used to define tags to the properties"
+
+ name = fields.Char(string="Tags")
diff --git a/estate/models/estate_property_type.py b/estate/models/estate_property_type.py
new file mode 100644
index 00000000000..b3b0d0094ee
--- /dev/null
+++ b/estate/models/estate_property_type.py
@@ -0,0 +1,8 @@
+from odoo import fields, models
+
+
+class PropertyType(models.Model):
+ _name = "estate.property.type"
+ _description = "this is used to define the types"
+
+ name = fields.Char(required=True, string="Type")
diff --git a/estate/security/ir.model.access.csv b/estate/security/ir.model.access.csv
new file mode 100644
index 00000000000..2b3daeb78ff
--- /dev/null
+++ b/estate/security/ir.model.access.csv
@@ -0,0 +1,7 @@
+id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
+access_estate_property_user1,estate.property.user,model_estate_property,base.group_user,1,0,0,0
+access_estate_property_user,estate.property.user,model_estate_property,base.group_system,1,1,1,1
+access_estate_property_type_user,estate.property.type.user,model_estate_property_type,base.group_user,1,1,1,1
+access_estate_property_tag_user,estate.property.tag.user,model_estate_property_tag,base.group_user,1,1,1,1
+access_estate_property_offer_user,estate.property.offer.user,model_estate_property_offers,base.group_user,1,1,1,1
+access_estate_property_tag,estate.property.tag.user,model_estate_property_tag,base.group_user,1,1,1,1
diff --git a/estate/static/src/estate.css b/estate/static/src/estate.css
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/estate/views/estate_property_menu.xml b/estate/views/estate_property_menu.xml
new file mode 100644
index 00000000000..943c120ea86
--- /dev/null
+++ b/estate/views/estate_property_menu.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/estate/views/estate_property_tag_view.xml b/estate/views/estate_property_tag_view.xml
new file mode 100644
index 00000000000..656b44d837d
--- /dev/null
+++ b/estate/views/estate_property_tag_view.xml
@@ -0,0 +1,10 @@
+
+
+
+
+ property tag
+ estate.property.tag
+ list,form
+
+
+
diff --git a/estate/views/estate_property_type_view.xml b/estate/views/estate_property_type_view.xml
new file mode 100644
index 00000000000..1340b665dd9
--- /dev/null
+++ b/estate/views/estate_property_type_view.xml
@@ -0,0 +1,23 @@
+
+
+
+
+ estate.property.type
+
+
+
+
+
+
+
+ Property Type
+ estate.property.type
+ list,form
+
+
diff --git a/estate/views/estate_property_views.xml b/estate/views/estate_property_views.xml
new file mode 100644
index 00000000000..ac1da370512
--- /dev/null
+++ b/estate/views/estate_property_views.xml
@@ -0,0 +1,106 @@
+
+
+
+ estate.property
+
+
+
+
+
+
+ estate property search view
+ estate.property
+
+
+
+
+
+
+
+
+
+
+
+ estate property views
+ estate.property
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Property
+ estate.property
+ list,form
+
+