summaryrefslogtreecommitdiff
path: root/base_account_budget/models
diff options
context:
space:
mode:
authorstephanchrst <stephanchrst@gmail.com>2022-05-10 17:14:58 +0700
committerstephanchrst <stephanchrst@gmail.com>2022-05-10 17:14:58 +0700
commit1ca3b3df3421961caec3b747a364071c80f5c7da (patch)
tree6778a1f0f3f9b4c6e26d6d87ccde16e24da6c9d6 /base_account_budget/models
parentb57188be371d36d96caac4b8d65a40745c0e972c (diff)
initial commit
Diffstat (limited to 'base_account_budget/models')
-rw-r--r--base_account_budget/models/__init__.py24
-rw-r--r--base_account_budget/models/account_analytic_account.py28
-rw-r--r--base_account_budget/models/account_budget.py188
3 files changed, 240 insertions, 0 deletions
diff --git a/base_account_budget/models/__init__.py b/base_account_budget/models/__init__.py
new file mode 100644
index 0000000..2a08a54
--- /dev/null
+++ b/base_account_budget/models/__init__.py
@@ -0,0 +1,24 @@
+# -*- coding: utf-8 -*-
+#############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+#
+# Copyright (C) 2019-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
+# Author: Cybrosys Techno Solutions(<https://www.cybrosys.com>)
+#
+# You can modify it under the terms of the GNU LESSER
+# GENERAL PUBLIC LICENSE (LGPL v3), Version 3.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details.
+#
+# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
+# (LGPL v3) along with this program.
+# If not, see <http://www.gnu.org/licenses/>.
+#
+#############################################################################
+
+from . import account_budget
+from . import account_analytic_account
diff --git a/base_account_budget/models/account_analytic_account.py b/base_account_budget/models/account_analytic_account.py
new file mode 100644
index 0000000..73625d7
--- /dev/null
+++ b/base_account_budget/models/account_analytic_account.py
@@ -0,0 +1,28 @@
+# -*- coding: utf-8 -*-
+#############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+#
+# Copyright (C) 2019-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
+# Author: Cybrosys Techno Solutions(<https://www.cybrosys.com>)
+#
+# You can modify it under the terms of the GNU LESSER
+# GENERAL PUBLIC LICENSE (LGPL v3), Version 3.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details.
+#
+# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
+# (LGPL v3) along with this program.
+# If not, see <http://www.gnu.org/licenses/>.
+#
+#############################################################################
+from odoo import fields, models
+
+
+class AccountAnalyticAccount(models.Model):
+ _inherit = "account.analytic.account"
+
+ budget_line = fields.One2many('budget.lines', 'analytic_account_id', 'Budget Lines')
diff --git a/base_account_budget/models/account_budget.py b/base_account_budget/models/account_budget.py
new file mode 100644
index 0000000..ab9674d
--- /dev/null
+++ b/base_account_budget/models/account_budget.py
@@ -0,0 +1,188 @@
+# -*- coding: utf-8 -*-
+#############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+#
+# Copyright (C) 2019-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
+# Author: Cybrosys Techno Solutions(<https://www.cybrosys.com>)
+#
+# You can modify it under the terms of the GNU LESSER
+# GENERAL PUBLIC LICENSE (LGPL v3), Version 3.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details.
+#
+# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
+# (LGPL v3) along with this program.
+# If not, see <http://www.gnu.org/licenses/>.
+#
+#############################################################################
+
+from odoo import api, fields, models, _
+from odoo.exceptions import ValidationError
+
+
+class AccountBudgetPost(models.Model):
+ _name = "account.budget.post"
+ _order = "name"
+ _description = "Budgetary Position"
+
+ name = fields.Char('Name', required=True)
+ account_ids = fields.Many2many('account.account', 'account_budget_rel', 'budget_id', 'account_id', 'Accounts',
+ domain=[('deprecated', '=', False)])
+ budget_line = fields.One2many('budget.lines', 'general_budget_id', 'Budget Lines')
+ company_id = fields.Many2one('res.company', 'Company', required=True,
+ default=lambda self: self.env['res.company']._company_default_get(
+ 'account.budget.post'))
+
+ def _check_account_ids(self, vals):
+ if 'account_ids' in vals:
+ account_ids = vals['account_ids']
+ # account_ids = self.resolve_2many_commands('account_ids', vals['account_ids'])
+ else:
+ account_ids = self.account_ids
+ if not account_ids:
+ raise ValidationError(_('The budget must have at least one account.'))
+
+ @api.model
+ def create(self, vals):
+ self._check_account_ids(vals)
+ return super(AccountBudgetPost, self).create(vals)
+
+ def write(self, vals):
+ self._check_account_ids(vals)
+ return super(AccountBudgetPost, self).write(vals)
+
+
+class Budget(models.Model):
+ _name = "budget.budget"
+ _description = "Budget"
+ _inherit = ['mail.thread']
+
+ name = fields.Char('Budget Name', required=True, states={'done': [('readonly', True)]})
+ creating_user_id = fields.Many2one('res.users', 'Responsible', default=lambda self: self.env.user)
+ date_from = fields.Date('Start Date', required=True, states={'done': [('readonly', True)]})
+ date_to = fields.Date('End Date', required=True, states={'done': [('readonly', True)]})
+ state = fields.Selection([
+ ('draft', 'Draft'),
+ ('cancel', 'Cancelled'),
+ ('confirm', 'Confirmed'),
+ ('validate', 'Validated'),
+ ('done', 'Done')
+ ], 'Status', default='draft', index=True, required=True, readonly=True, copy=False, track_visibility='always')
+ budget_line = fields.One2many('budget.lines', 'budget_id', 'Budget Lines',
+ states={'done': [('readonly', True)]}, copy=True)
+ company_id = fields.Many2one('res.company', 'Company', required=True,
+ default=lambda self: self.env['res.company']._company_default_get(
+ 'account.budget.post'))
+
+ def action_budget_confirm(self):
+ self.write({'state': 'confirm'})
+
+ def action_budget_draft(self):
+ self.write({'state': 'draft'})
+
+ def action_budget_validate(self):
+ self.write({'state': 'validate'})
+
+ def action_budget_cancel(self):
+ self.write({'state': 'cancel'})
+
+ def action_budget_done(self):
+ self.write({'state': 'done'})
+
+
+class BudgetLines(models.Model):
+ _name = "budget.lines"
+ _rec_name = "budget_id"
+ _description = "Budget Line"
+
+ budget_id = fields.Many2one('budget.budget', 'Budget', ondelete='cascade', index=True, required=True)
+ analytic_account_id = fields.Many2one('account.analytic.account', 'Analytic Account')
+ general_budget_id = fields.Many2one('account.budget.post', 'Budgetary Position', required=True)
+ date_from = fields.Date('Start Date', required=True)
+ date_to = fields.Date('End Date', required=True)
+ paid_date = fields.Date('Paid Date')
+ planned_amount = fields.Float('Planned Amount', required=True, digits=0)
+ practical_amount = fields.Float(compute='_compute_practical_amount', string='Practical Amount', digits=0)
+ theoretical_amount = fields.Float(compute='_compute_theoretical_amount', string='Theoretical Amount', digits=0)
+ percentage = fields.Float(compute='_compute_percentage', string='Achievement')
+ company_id = fields.Many2one(related='budget_id.company_id', comodel_name='res.company',
+ string='Company', store=True, readonly=True)
+
+ def _compute_practical_amount(self):
+ for line in self:
+ result = 0.0
+ acc_ids = line.general_budget_id.account_ids.ids
+ date_to = self.env.context.get('wizard_date_to') or line.date_to
+ date_from = self.env.context.get('wizard_date_from') or line.date_from
+ if line.analytic_account_id.id:
+ self.env.cr.execute("""
+ SELECT SUM(amount)
+ FROM account_analytic_line
+ WHERE account_id=%s
+ AND date between %s AND %s
+ AND general_account_id=ANY(%s)""",
+ (line.analytic_account_id.id, date_from, date_to, acc_ids,))
+ result = self.env.cr.fetchone()[0] or 0.0
+ line.practical_amount = result
+
+ def _compute_theoretical_amount(self):
+ today = fields.Datetime.now()
+ for line in self:
+ # Used for the report
+
+ if self.env.context.get('wizard_date_from') and self.env.context.get('wizard_date_to'):
+ date_from = fields.Datetime.from_string(self.env.context.get('wizard_date_from'))
+ date_to = fields.Datetime.from_string(self.env.context.get('wizard_date_to'))
+ if date_from < fields.Datetime.from_string(line.date_from):
+ date_from = fields.Datetime.from_string(line.date_from)
+ elif date_from > fields.Datetime.from_string(line.date_to):
+ date_from = False
+
+ if date_to > fields.Datetime.from_string(line.date_to):
+ date_to = fields.Datetime.from_string(line.date_to)
+ elif date_to < fields.Datetime.from_string(line.date_from):
+ date_to = False
+
+ theo_amt = 0.00
+ if date_from and date_to:
+ line_timedelta = fields.Datetime.from_string(line.date_to) - fields.Datetime.from_string(
+ line.date_from)
+ elapsed_timedelta = date_to - date_from
+ if elapsed_timedelta.days > 0:
+ theo_amt = (
+ elapsed_timedelta.total_seconds() / line_timedelta.total_seconds()) * line.planned_amount
+ else:
+ if line.paid_date:
+ if fields.Datetime.from_string(line.date_to) <= fields.Datetime.from_string(line.paid_date):
+ theo_amt = 0.00
+ else:
+ theo_amt = line.planned_amount
+ else:
+ line_timedelta = fields.Datetime.from_string(line.date_to) - fields.Datetime.from_string(
+ line.date_from)
+ elapsed_timedelta = fields.Datetime.from_string(today) - (
+ fields.Datetime.from_string(line.date_from))
+
+ if elapsed_timedelta.days < 0:
+ # If the budget line has not started yet, theoretical amount should be zero
+ theo_amt = 0.00
+ elif line_timedelta.days > 0 and fields.Datetime.from_string(today) < fields.Datetime.from_string(
+ line.date_to):
+ # If today is between the budget line date_from and date_to
+ theo_amt = (
+ elapsed_timedelta.total_seconds() / line_timedelta.total_seconds()) * line.planned_amount
+ else:
+ theo_amt = line.planned_amount
+
+ line.theoretical_amount = theo_amt
+
+ def _compute_percentage(self):
+ for line in self:
+ if line.theoretical_amount != 0.00:
+ line.percentage = float((line.practical_amount or 0.0) / line.theoretical_amount) * 100
+ else:
+ line.percentage = 0.00