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

[ADD] estate: added estate module #203

Draft
wants to merge 17 commits into
base: 18.0
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
5936cb3
[ADD] estate: develop module as a part of technical training
djip-odoo Nov 13, 2024
800fdd6
[IMP] estate: revised relation mapping and learned actions and constr…
djip-odoo Nov 14, 2024
0c128c2
[IMP] estate: revised computeed field, action. learned sprinkle
djip-odoo Nov 15, 2024
4ef302f
[IMP] estate: sprinkles, actions and some part of inheritance
djip-odoo Nov 18, 2024
b70fbf6
[ADD] estate_account: module to generate ionvoices for sold properties
djip-odoo Nov 19, 2024
3ef4f7e
[IMP] estate: created kanban view, defined demo data for both modules
djip-odoo Nov 20, 2024
b413bdd
[IMP] estate: reports and report template create and updated demo data
djip-odoo Nov 21, 2024
6ce5b2b
[IMP] estate: security part, created groups for agent and manager
djip-odoo Nov 22, 2024
51f40b8
[IMP] estate: updated security constraints by company and group
djip-odoo Nov 25, 2024
4538aa3
[IMP] estate: revised security, learned new - website, controller, wi…
djip-odoo Nov 26, 2024
275224e
[ADD] warranty_configuration: added new model for apply warranty whil…
djip-odoo Dec 2, 2024
6058b9a
[IMP] warranty_configuration: created transient model for wizard
djip-odoo Dec 3, 2024
18cdf11
[IMP] warranty_configuration: wizard view and action updated
djip-odoo Dec 4, 2024
ee354fb
[ADD] budget_management: new module created
djip-odoo Dec 10, 2024
abbcce9
[IMP] budget_management: improved form view, added analytic line
djip-odoo Dec 11, 2024
173f7c2
[IMP] budget_management: added analytic account and updated accordingly
djip-odoo Dec 12, 2024
5c4fe40
[IMP] budget_management: updated constraints and views
djip-odoo Dec 13, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions budget_management/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from . import models
from . import wizards
23 changes: 23 additions & 0 deletions budget_management/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"name": "Budget Management",
"category": "Budget",
"version": "1.0",
"depends": ["base", "account", "accountant"],
"author": "djip-odoo",
"description": """
Part of technical training
Creating Budget Management module as review task
""",
"data": [
"security/ir.model.access.csv",
"views/budget_line_views.xml",
"views/actions_menu_and_button.xml",
"views/menu_views.xml",
"views/budget_views.xml",
"wizards/wizard_add_budgets_view.xml",
],
"application": True,
"installable": True,
"auto_install": False,
"license": "LGPL-3",
}
3 changes: 3 additions & 0 deletions budget_management/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from . import budget
from . import budget_line
from . import account_analytic_line
144 changes: 144 additions & 0 deletions budget_management/models/account_analytic_line.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
from odoo import models, api
from odoo.exceptions import ValidationError


class AccountAnalyticLine(models.Model):
_inherit = "account.analytic.line"

@api.model_create_multi
def create(self, vals_list):
# print("* " * 100)
# print(vals_list)
# print("* " * 100)

for vals in vals_list:
entry_date = vals.get("date")
if not entry_date:
raise ValidationError(
"The date field is required to determine the appropriate budget."
)

budget_line = self.env["budget.management.budget.lines"].search(
[
("budget_id.date_start", "<=", entry_date),
("budget_id.date_end", ">=", entry_date),
("budget_id.active", "=", True),
("analytic_account_id", "=", vals.get("account_id")),
],
limit=1,
)

if budget_line:
budget = budget_line.budget_id

analytic_account_lines = self.env["account.analytic.line"].search_read(
[
("account_id", "=", vals.get("account_id")),
("date", ">=", budget.date_start),
("date", "<=", budget.date_end),
("amount", "<", 0),
],
fields=["amount"],
)
# print(list(line.get("amount") for line in analytic_account_lines))
achieved = sum(line.get("amount") for line in analytic_account_lines)
# print(budget.on_over_budget, abs(achieved + vals.get("amount")), budget_line.budget_amount)

if budget.on_over_budget == "restriction":
if abs(achieved + vals.get("amount")) > budget_line.budget_amount:
raise ValidationError(
"You cannot create a budget line because it exceeds the allowed budget!"
)
budget_line.achieved_amount = abs(achieved + vals.get("amount"))
budget_line.count_analytic_lines = len(analytic_account_lines) + 1
return super(AccountAnalyticLine, self).create(vals_list)

def write(self, vals):
if "date" in vals or "amount" in vals or "account_id" in vals:
for record in self:
entry_date = vals.get("date", record.date)

budget_line = self.env["budget.management.budget.lines"].search(
[
("budget_id.date_start", "<=", entry_date),
("budget_id.date_end", ">=", entry_date),
("budget_id.active", "=", True),
(
"analytic_account_id",
"=",
vals.get("account_id", record.account_id.id),
),
],
limit=1,
)

if budget_line:
budget = budget_line.budget_id

analytic_account_lines = self.env[
"account.analytic.line"
].search_read(
[
(
"account_id",
"=",
vals.get("account_id", record.account_id.id),
),
("date", ">=", budget.date_start),
("date", "<=", budget.date_end),
("amount", "<", 0),
("id", "!=", record.id),
],
fields=["amount"],
)
achieved = sum(
line.get("amount") for line in analytic_account_lines
)

new_amount = vals.get("amount", record.amount)
# print(budget.on_over_budget, abs(achieved - record.amount + new_amount), record.amount , new_amount, budget_line.budget_amount)

total_achieved_amount_will_be = abs(achieved + new_amount)

if budget.on_over_budget == "restriction":
if total_achieved_amount_will_be > budget_line.budget_amount:
raise ValidationError(
"You cannot modify the budget line because it exceeds the allowed budget!"
)
budget_line.achieved_amount = total_achieved_amount_will_be
budget_line.count_analytic_lines = len(analytic_account_lines) + 1
return super(AccountAnalyticLine, self).write(vals)

def unlink(self):
for record in self:
entry_date = record.date

budget_line = self.env["budget.management.budget.lines"].search(
[
("budget_id.date_start", "<=", entry_date),
("budget_id.date_end", ">=", entry_date),
("budget_id.active", "=", True),
("analytic_account_id", "=", record.account_id.id),
],
limit=1,
)

if budget_line:
budget = budget_line.budget_id

# Recalculate achieved amount excluding the current record
analytic_account_lines = self.env["account.analytic.line"].search_read(
[
("account_id", "=", record.account_id.id),
("date", ">=", budget.date_start),
("date", "<=", budget.date_end),
("amount", "<", 0),
("id", "!=", record.id), # Exclude the current record
],
fields=["amount"],
)
achieved = sum(line.get("amount") for line in analytic_account_lines)

budget_line.achieved_amount = abs(achieved)
budget_line.count_analytic_lines = len(analytic_account_lines)
return super(AccountAnalyticLine, self).unlink()
160 changes: 160 additions & 0 deletions budget_management/models/budget.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
from odoo import models, fields, api
from odoo.exceptions import ValidationError, UserError
from markupsafe import escape, Markup


class Budget(models.Model):
_name = "budget.budget"
_inherit = ["mail.thread", "mail.activity.mixin"]
_description = " "

name = fields.Char(compute="_compute_budget_name", store=True, readonly=True)
active = fields.Boolean(default=True)
is_favorite = fields.Boolean(default=False)
color = fields.Integer(string="Color Index")
state = fields.Selection(
selection=[
("draft", "Draft"),
("confirmed", "Confirmed"),
("revised", "Revised"),
("done", "Done"),
],
required=True,
default="draft",
tracking=True,
)
on_over_budget = fields.Selection(
selection=[("warning", "Warning"), ("restriction", "Restriction")],
tracking=True,
)
responsible = fields.Many2one(
comodel_name="res.users", # Assuming you want a link to Odoo users
string="Responsible",
tracking=True,
)
revision_id = fields.Many2one(
comodel_name="res.users", # Assuming you want a link to Odoo users
tracking=True,
readonly=True,
string="Revised by"
)
date_start = fields.Date(string="Start Date", required=True)
date_end = fields.Date(string="Expiration Date", required=True, index=True)
company_id = fields.Many2one(
"res.company",
string="Company",
default=lambda self: self.env.company,
)
budget_line_ids = fields.One2many(
comodel_name="budget.management.budget.lines", inverse_name="budget_id"
)
warnings = fields.Text(compute="_check_over_budget")
currency_id = fields.Many2one(
comodel_name="res.currency",
string="Currency",
required=True,
default=lambda self: self.env.company.currency_id,
)

@api.depends("date_start", "date_end")
def _compute_budget_name(self):
for record in self:
if record.date_start and record.date_end:
start_date = record.date_start
end_date = record.date_end
if (
start_date.year == end_date.year
and start_date.month == end_date.month
):
record.name = f"Budget - {start_date.strftime('%B %Y')}"
else:
record.name = f"Budget - {start_date.strftime('%d %B, %Y')} to {end_date.strftime('%d %B, %Y')}"
else:
record.name = "Unknown Budget"

def onclick_reset_to_draft(self):
for record in self:
if record.state != "draft":
record.state = "draft"

def onclick_confirmed(self):
for record in self:
if record.state == "draft":
record.state = "confirmed"

def onclick_revise(self):
for record in self:
if record.state != "confirmed":
raise UserError("Only confirmed budgets can be revised.")

if record.state == "confirmed":
record.revision_id = self.env.user
record.state = "revised"
record.active = False

new_budget = record.copy(
{"revision_id": None, "state": "draft", "active": True}
)

for budget_line in record.budget_line_ids:
self.env["budget.management.budget.lines"].create(
{
"budget_id": new_budget.id,
"name": budget_line.name,
"budget_amount": budget_line.budget_amount,
"achieved_amount": budget_line.achieved_amount,
"achieved_percentage": budget_line.achieved_percentage,
"analytic_account_id": budget_line.analytic_account_id.id,
"currency_id": budget_line.currency_id.id,
}
)

action = self.env.ref(
"budget_management.action_budget_management_menu_budget"
)
record.message_post(
body=Markup(
f'<a href="odoo/action-{action.id}/{new_budget.id}">{new_budget.name}</a>.'
)
)

def onclick_done(self):
for record in self:
if record.state in ["confirmed", "revised"]:
record.state = "done"

@api.constrains("date_start", "date_end")
def _check_period_overlap(self):
for record in self:
overlapping_budgets = self.search(
[
("id", "!=", record.id),
("date_start", "<=", record.date_start),
("date_end", ">=", record.date_end),
("company_id", "=", record.company_id.id),
]
)
overlapping_non_revised = False

for budget in overlapping_budgets:
if budget.state != "revised":
overlapping_non_revised = True
break

if overlapping_non_revised:
raise ValidationError(
"Cannot create overlapping budgets for the same period and company. If not displayed your selected period budget! please check archived budgets"
)

@api.depends("budget_line_ids.over_budget")
def _check_over_budget(self):
# print("* "*100)
for record in self:
# print(list(ob > 0 for ob in record.budget_line_ids.mapped("over_budget")))
if (
record.on_over_budget == "warning"
and any(ob > 0 for ob in record.budget_line_ids.mapped("over_budget"))
):
record.warnings = "Achieved amount exceeds the budget!"
else:
record.warnings = False
Loading