You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

217 lines
9.6 KiB

# -*- 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):
for val in vals:
if 'account_ids' in val:
account_ids = val['account_ids']
else:
account_ids = self.account_ids
if not account_ids:
raise ValidationError(
_('The budget must have at least one account.'))
@api.model_create_multi
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)
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