|  | @ -19,7 +19,6 @@ | 
			
		
	
		
		
			
				
					|  |  | #    If not, see <http://www.gnu.org/licenses/>. |  |  | #    If not, see <http://www.gnu.org/licenses/>. | 
			
		
	
		
		
			
				
					|  |  | # |  |  | # | 
			
		
	
		
		
			
				
					|  |  | ############################################################################# |  |  | ############################################################################# | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  |  | 
			
		
	
		
		
			
				
					|  |  | from odoo import api, fields, models, _ |  |  | from odoo import api, fields, models, _ | 
			
		
	
		
		
			
				
					|  |  | from odoo.exceptions import ValidationError |  |  | from odoo.exceptions import ValidationError | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
	
		
		
			
				
					|  | @ -30,20 +29,25 @@ class AccountBudgetPost(models.Model): | 
			
		
	
		
		
			
				
					|  |  |     _description = "Budgetary Position" |  |  |     _description = "Budgetary Position" | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  |     name = fields.Char('Name', required=True) |  |  |     name = fields.Char('Name', required=True) | 
			
		
	
		
		
			
				
					
					|  |  |     account_ids = fields.Many2many('account.account', 'account_budget_rel', 'budget_id', 'account_id', 'Accounts', |  |  |     account_ids = fields.Many2many('account.account', 'account_budget_rel', | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					|  |  |  |  |  |                                    'budget_id', 'account_id', 'Accounts', | 
			
		
	
		
		
			
				
					|  |  |                                    domain=[('deprecated', '=', False)]) |  |  |                                    domain=[('deprecated', '=', False)]) | 
			
		
	
		
		
			
				
					
					|  |  |     budget_line = fields.One2many('budget.lines', 'general_budget_id', 'Budget Lines') |  |  |     budget_line = fields.One2many('budget.lines', 'general_budget_id', | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					|  |  |  |  |  |                                   'Budget Lines') | 
			
		
	
		
		
			
				
					|  |  |     company_id = fields.Many2one('res.company', 'Company', required=True, |  |  |     company_id = fields.Many2one('res.company', 'Company', required=True, | 
			
		
	
		
		
			
				
					
					|  |  |                                  default=lambda self: self.env['res.company']._company_default_get( |  |  |                                  default=lambda self: self.env[ | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					|  |  |  |  |  |                                      'res.company']._company_default_get( | 
			
		
	
		
		
			
				
					|  |  |                                      'account.budget.post')) |  |  |                                      'account.budget.post')) | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  |     def _check_account_ids(self, vals): |  |  |     def _check_account_ids(self, vals): | 
			
		
	
		
		
			
				
					
					|  |  |         if 'account_ids' in vals: |  |  |         for val in vals: | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |             account_ids = vals['account_ids'] |  |  |             if 'account_ids' in val: | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					|  |  |  |  |  |                 account_ids = val['account_ids'] | 
			
		
	
		
		
			
				
					|  |  |             else: |  |  |             else: | 
			
		
	
		
		
			
				
					|  |  |                 account_ids = self.account_ids |  |  |                 account_ids = self.account_ids | 
			
		
	
		
		
			
				
					|  |  |             if not account_ids: |  |  |             if not account_ids: | 
			
		
	
		
		
			
				
					
					|  |  |             raise ValidationError(_('The budget must have at least one account.')) |  |  |                 raise ValidationError( | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					|  |  |  |  |  |                     _('The budget must have at least one account.')) | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  |     @api.model_create_multi |  |  |     @api.model_create_multi | 
			
		
	
		
		
			
				
					|  |  |     def create(self, vals): |  |  |     def create(self, vals): | 
			
		
	
	
		
		
			
				
					|  | @ -60,21 +64,28 @@ class Budget(models.Model): | 
			
		
	
		
		
			
				
					|  |  |     _description = "Budget" |  |  |     _description = "Budget" | 
			
		
	
		
		
			
				
					|  |  |     _inherit = ['mail.thread'] |  |  |     _inherit = ['mail.thread'] | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |     name = fields.Char('Budget Name', required=True, states={'done': [('readonly', True)]}) |  |  |     name = fields.Char('Budget Name', required=True, | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |     creating_user_id = fields.Many2one('res.users', 'Responsible', default=lambda self: self.env.user) |  |  |                        states={'done': [('readonly', True)]}) | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |     date_from = fields.Date('Start Date', required=True, states={'done': [('readonly', True)]}) |  |  |     creating_user_id = fields.Many2one('res.users', 'Responsible', | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |     date_to = fields.Date('End Date', required=True, states={'done': [('readonly', True)]}) |  |  |                                        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([ |  |  |     state = fields.Selection([ | 
			
		
	
		
		
			
				
					|  |  |         ('draft', 'Draft'), |  |  |         ('draft', 'Draft'), | 
			
		
	
		
		
			
				
					|  |  |         ('cancel', 'Cancelled'), |  |  |         ('cancel', 'Cancelled'), | 
			
		
	
		
		
			
				
					|  |  |         ('confirm', 'Confirmed'), |  |  |         ('confirm', 'Confirmed'), | 
			
		
	
		
		
			
				
					|  |  |         ('validate', 'Validated'), |  |  |         ('validate', 'Validated'), | 
			
		
	
		
		
			
				
					|  |  |         ('done', 'Done') |  |  |         ('done', 'Done') | 
			
		
	
		
		
			
				
					
					|  |  |     ], 'Status', default='draft', index=True, required=True, readonly=True, copy=False) |  |  |     ], 'Status', default='draft', index=True, required=True, readonly=True, | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					|  |  |  |  |  |         copy=False) | 
			
		
	
		
		
			
				
					|  |  |     budget_line = fields.One2many('budget.lines', 'budget_id', 'Budget Lines', |  |  |     budget_line = fields.One2many('budget.lines', 'budget_id', 'Budget Lines', | 
			
		
	
		
		
			
				
					
					|  |  |                                   states={'done': [('readonly', True)]}, copy=True) |  |  |                                   states={'done': [('readonly', True)]}, | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					|  |  |  |  |  |                                   copy=True) | 
			
		
	
		
		
			
				
					|  |  |     company_id = fields.Many2one('res.company', 'Company', required=True, |  |  |     company_id = fields.Many2one('res.company', 'Company', required=True, | 
			
		
	
		
		
			
				
					
					|  |  |                                  default=lambda self: self.env['res.company']._company_default_get( |  |  |                                  default=lambda self: self.env[ | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					|  |  |  |  |  |                                      'res.company']._company_default_get( | 
			
		
	
		
		
			
				
					|  |  |                                      'account.budget.post')) |  |  |                                      'account.budget.post')) | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  |     def action_budget_confirm(self): |  |  |     def action_budget_confirm(self): | 
			
		
	
	
		
		
			
				
					|  | @ -98,17 +109,24 @@ class BudgetLines(models.Model): | 
			
		
	
		
		
			
				
					|  |  |     _rec_name = "budget_id" |  |  |     _rec_name = "budget_id" | 
			
		
	
		
		
			
				
					|  |  |     _description = "Budget Line" |  |  |     _description = "Budget Line" | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |     budget_id = fields.Many2one('budget.budget', 'Budget', ondelete='cascade', index=True, required=True) |  |  |     budget_id = fields.Many2one('budget.budget', 'Budget', ondelete='cascade', | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |     analytic_account_id = fields.Many2one('account.analytic.account', 'Analytic Account') |  |  |                                 index=True, required=True) | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |     general_budget_id = fields.Many2one('account.budget.post', 'Budgetary Position', 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_from = fields.Date('Start Date', required=True) | 
			
		
	
		
		
			
				
					|  |  |     date_to = fields.Date('End Date', required=True) |  |  |     date_to = fields.Date('End Date', required=True) | 
			
		
	
		
		
			
				
					|  |  |     paid_date = fields.Date('Paid Date') |  |  |     paid_date = fields.Date('Paid Date') | 
			
		
	
		
		
			
				
					|  |  |     planned_amount = fields.Float('Planned Amount', required=True, digits=0) |  |  |     planned_amount = fields.Float('Planned Amount', required=True, digits=0) | 
			
		
	
		
		
			
				
					
					|  |  |     practical_amount = fields.Float(compute='_compute_practical_amount', string='Practical Amount', digits=0) |  |  |     practical_amount = fields.Float(compute='_compute_practical_amount', | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |     theoretical_amount = fields.Float(compute='_compute_theoretical_amount', string='Theoretical Amount', digits=0) |  |  |                                     string='Practical Amount', digits=0) | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |     percentage = fields.Float(compute='_compute_percentage', string='Achievement') |  |  |     theoretical_amount = fields.Float(compute='_compute_theoretical_amount', | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |     company_id = fields.Many2one(related='budget_id.company_id', comodel_name='res.company', |  |  |                                       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) |  |  |                                  string='Company', store=True, readonly=True) | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  |     def _compute_practical_amount(self): |  |  |     def _compute_practical_amount(self): | 
			
		
	
	
		
		
			
				
					|  | @ -116,7 +134,8 @@ class BudgetLines(models.Model): | 
			
		
	
		
		
			
				
					|  |  |             result = 0.0 |  |  |             result = 0.0 | 
			
		
	
		
		
			
				
					|  |  |             acc_ids = line.general_budget_id.account_ids.ids |  |  |             acc_ids = line.general_budget_id.account_ids.ids | 
			
		
	
		
		
			
				
					|  |  |             date_to = self.env.context.get('wizard_date_to') or line.date_to |  |  |             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 |  |  |             date_from = self.env.context.get( | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					|  |  |  |  |  |                 'wizard_date_from') or line.date_from | 
			
		
	
		
		
			
				
					|  |  |             if line.analytic_account_id.id: |  |  |             if line.analytic_account_id.id: | 
			
		
	
		
		
			
				
					|  |  |                 self.env.cr.execute(""" |  |  |                 self.env.cr.execute(""" | 
			
		
	
		
		
			
				
					|  |  |                     SELECT SUM(amount) |  |  |                     SELECT SUM(amount) | 
			
		
	
	
		
		
			
				
					|  | @ -124,7 +143,8 @@ class BudgetLines(models.Model): | 
			
		
	
		
		
			
				
					|  |  |                     WHERE account_id=%s |  |  |                     WHERE account_id=%s | 
			
		
	
		
		
			
				
					|  |  |                         AND date between %s AND %s |  |  |                         AND date between %s AND %s | 
			
		
	
		
		
			
				
					|  |  |                         AND general_account_id=ANY(%s)""", |  |  |                         AND general_account_id=ANY(%s)""", | 
			
		
	
		
		
			
				
					
					|  |  |                                     (line.analytic_account_id.id, date_from, date_to, acc_ids,)) |  |  |                                     (line.analytic_account_id.id, date_from, | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					|  |  |  |  |  |                                      date_to, acc_ids,)) | 
			
		
	
		
		
			
				
					|  |  |                 result = self.env.cr.fetchone()[0] or 0.0 |  |  |                 result = self.env.cr.fetchone()[0] or 0.0 | 
			
		
	
		
		
			
				
					|  |  |             line.practical_amount = result |  |  |             line.practical_amount = result | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
	
		
		
			
				
					|  | @ -133,9 +153,13 @@ class BudgetLines(models.Model): | 
			
		
	
		
		
			
				
					|  |  |         for line in self: |  |  |         for line in self: | 
			
		
	
		
		
			
				
					|  |  |             # Used for the report |  |  |             # Used for the report | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |             if self.env.context.get('wizard_date_from') and self.env.context.get('wizard_date_to'): |  |  |             if self.env.context.get( | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |                 date_from = fields.Datetime.from_string(self.env.context.get('wizard_date_from')) |  |  |                     'wizard_date_from') and self.env.context.get( | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |                 date_to = fields.Datetime.from_string(self.env.context.get('wizard_date_to')) |  |  |                     '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): |  |  |                 if date_from < fields.Datetime.from_string(line.date_from): | 
			
		
	
		
		
			
				
					|  |  |                     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): |  |  |                 elif date_from > fields.Datetime.from_string(line.date_to): | 
			
		
	
	
		
		
			
				
					|  | @ -148,7 +172,8 @@ class BudgetLines(models.Model): | 
			
		
	
		
		
			
				
					|  |  | 
 |  |  | 
 | 
			
		
	
		
		
			
				
					|  |  |                 theo_amt = 0.00 |  |  |                 theo_amt = 0.00 | 
			
		
	
		
		
			
				
					|  |  |                 if date_from and date_to: |  |  |                 if date_from and date_to: | 
			
		
	
		
		
			
				
					
					|  |  |                     line_timedelta = fields.Datetime.from_string(line.date_to) - fields.Datetime.from_string( |  |  |                     line_timedelta = fields.Datetime.from_string( | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					|  |  |  |  |  |                         line.date_to) - fields.Datetime.from_string( | 
			
		
	
		
		
			
				
					|  |  |                         line.date_from) |  |  |                         line.date_from) | 
			
		
	
		
		
			
				
					|  |  |                     elapsed_timedelta = date_to - date_from |  |  |                     elapsed_timedelta = date_to - date_from | 
			
		
	
		
		
			
				
					|  |  |                     if elapsed_timedelta.days > 0: |  |  |                     if elapsed_timedelta.days > 0: | 
			
		
	
	
		
		
			
				
					|  | @ -156,12 +181,15 @@ class BudgetLines(models.Model): | 
			
		
	
		
		
			
				
					|  |  |                                            elapsed_timedelta.total_seconds() / line_timedelta.total_seconds()) * line.planned_amount |  |  |                                            elapsed_timedelta.total_seconds() / line_timedelta.total_seconds()) * line.planned_amount | 
			
		
	
		
		
			
				
					|  |  |             else: |  |  |             else: | 
			
		
	
		
		
			
				
					|  |  |                 if line.paid_date: |  |  |                 if line.paid_date: | 
			
		
	
		
		
			
				
					
					|  |  |                     if fields.Datetime.from_string(line.date_to) <= fields.Datetime.from_string(line.paid_date): |  |  |                     if fields.Datetime.from_string( | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					|  |  |  |  |  |                             line.date_to) <= fields.Datetime.from_string( | 
			
		
	
		
		
			
				
					|  |  |  |  |  |                             line.paid_date): | 
			
		
	
		
		
			
				
					|  |  |                         theo_amt = 0.00 |  |  |                         theo_amt = 0.00 | 
			
		
	
		
		
			
				
					|  |  |                     else: |  |  |                     else: | 
			
		
	
		
		
			
				
					|  |  |                         theo_amt = line.planned_amount |  |  |                         theo_amt = line.planned_amount | 
			
		
	
		
		
			
				
					|  |  |                 else: |  |  |                 else: | 
			
		
	
		
		
			
				
					
					|  |  |                     line_timedelta = fields.Datetime.from_string(line.date_to) - fields.Datetime.from_string( |  |  |                     line_timedelta = fields.Datetime.from_string( | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					|  |  |  |  |  |                         line.date_to) - fields.Datetime.from_string( | 
			
		
	
		
		
			
				
					|  |  |                         line.date_from) |  |  |                         line.date_from) | 
			
		
	
		
		
			
				
					|  |  |                     elapsed_timedelta = fields.Datetime.from_string(today) - ( |  |  |                     elapsed_timedelta = fields.Datetime.from_string(today) - ( | 
			
		
	
		
		
			
				
					|  |  |                         fields.Datetime.from_string(line.date_from)) |  |  |                         fields.Datetime.from_string(line.date_from)) | 
			
		
	
	
		
		
			
				
					|  | @ -169,7 +197,8 @@ class BudgetLines(models.Model): | 
			
		
	
		
		
			
				
					|  |  |                     if elapsed_timedelta.days < 0: |  |  |                     if elapsed_timedelta.days < 0: | 
			
		
	
		
		
			
				
					|  |  |                         # If the budget line has not started yet, theoretical amount should be zero |  |  |                         # If the budget line has not started yet, theoretical amount should be zero | 
			
		
	
		
		
			
				
					|  |  |                         theo_amt = 0.00 |  |  |                         theo_amt = 0.00 | 
			
		
	
		
		
			
				
					
					|  |  |                     elif line_timedelta.days > 0 and fields.Datetime.from_string(today) < fields.Datetime.from_string( |  |  |                     elif line_timedelta.days > 0 and fields.Datetime.from_string( | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					|  |  |  |  |  |                             today) < fields.Datetime.from_string( | 
			
		
	
		
		
			
				
					|  |  |                             line.date_to): |  |  |                             line.date_to): | 
			
		
	
		
		
			
				
					|  |  |                         # If today is between the budget line date_from and date_to |  |  |                         # If today is between the budget line date_from and date_to | 
			
		
	
		
		
			
				
					|  |  |                         theo_amt = ( |  |  |                         theo_amt = ( | 
			
		
	
	
		
		
			
				
					|  | @ -182,6 +211,7 @@ class BudgetLines(models.Model): | 
			
		
	
		
		
			
				
					|  |  |     def _compute_percentage(self): |  |  |     def _compute_percentage(self): | 
			
		
	
		
		
			
				
					|  |  |         for line in self: |  |  |         for line in self: | 
			
		
	
		
		
			
				
					|  |  |             if line.theoretical_amount != 0.00: |  |  |             if line.theoretical_amount != 0.00: | 
			
		
	
		
		
			
				
					
					|  |  |                 line.percentage = float((line.practical_amount or 0.0) / line.theoretical_amount) * 100 |  |  |                 line.percentage = float(( | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					|  |  |  |  |  |                                                     line.practical_amount or 0.0) / line.theoretical_amount) * 100 | 
			
		
	
		
		
			
				
					|  |  |             else: |  |  |             else: | 
			
		
	
		
		
			
				
					|  |  |                 line.percentage = 0.00 |  |  |                 line.percentage = 0.00 | 
			
		
	
	
		
		
			
				
					|  | 
 |