128 lines
5.7 KiB
Python
128 lines
5.7 KiB
Python
# -*- coding: utf-8 -*-
|
|
from odoo import models, _, api
|
|
from odoo.exceptions import ValidationError
|
|
|
|
class PurchaseOrder(models.Model):
|
|
_inherit = 'purchase.order'
|
|
|
|
def action_budget(self):
|
|
confirmation_lines = []
|
|
amount = 0
|
|
|
|
if self.amount_total <= 0:
|
|
raise ValidationError(_("Total Amount MUST be greater than 0 !!!"))
|
|
|
|
analytic_account = False
|
|
if self.purchase_cost == 'default':
|
|
analytic_account = self.env.user.company_id.purchase_analytic_account
|
|
elif self.purchase_cost == 'department':
|
|
analytic_account = self.department_id.analytic_account_id
|
|
elif self.purchase_cost == 'project':
|
|
analytic_account = self.project_id.analytic_account_id
|
|
if not analytic_account:
|
|
raise ValidationError(_("No analytic account for the project"))
|
|
elif self.purchase_cost == 'product_line':
|
|
pass
|
|
else:
|
|
raise ValidationError(_("No analytic account for the purchase"))
|
|
|
|
for order in self:
|
|
for rec in order.order_line:
|
|
if rec.choosen:
|
|
if self.purchase_cost == 'product_line':
|
|
analytic_account = rec.account_analytic_id
|
|
if not analytic_account:
|
|
raise ValidationError(
|
|
_("Please put cost center to the product line") + ': {}'.format(rec.product_id.name)
|
|
)
|
|
|
|
account_id = rec.product_id.property_account_expense_id or rec.product_id.categ_id.property_account_expense_categ_id
|
|
if not account_id:
|
|
raise ValidationError(
|
|
_("This product has no expense account") + ': {}'.format(rec.product_id.name)
|
|
)
|
|
|
|
if not analytic_account:
|
|
raise ValidationError(_("Analytic account not set"))
|
|
|
|
budget_lines = self.env['crossovered.budget.lines'].search([
|
|
('analytic_account_id', '=', analytic_account.id),
|
|
('crossovered_budget_id.state', '=', 'done'),
|
|
('crossovered_budget_id.date_from', '<=', self.date_order),
|
|
('crossovered_budget_id.date_to', '>=', self.date_order)
|
|
])
|
|
|
|
if not budget_lines:
|
|
raise ValidationError(
|
|
_("No approved budget found for analytic account: %s on date: %s")
|
|
% (analytic_account.name, self.date_order)
|
|
)
|
|
|
|
valid_budget_positions = budget_lines.mapped('general_budget_id').filtered(
|
|
lambda x: account_id in x.account_ids
|
|
)
|
|
|
|
if not valid_budget_positions:
|
|
raise ValidationError(
|
|
_("No budget position found that contains:\n"
|
|
"- Expense Account: %s\n"
|
|
"- For Analytic Account: %s\n"
|
|
"- Product: %s")
|
|
% (account_id.name, analytic_account.name, rec.product_id.name)
|
|
)
|
|
final_budget_line = False
|
|
remaining_amount = rec.price_subtotal
|
|
|
|
for budget_position in valid_budget_positions:
|
|
candidate_lines = budget_lines.filtered(
|
|
lambda x: x.general_budget_id.id == budget_position.id
|
|
)
|
|
for line in candidate_lines:
|
|
line_remain = abs(line.remain)
|
|
if line_remain <= 0:
|
|
continue
|
|
|
|
used_amount = min(line_remain, remaining_amount)
|
|
|
|
confirmation_lines.append((0, 0, {
|
|
'amount': used_amount,
|
|
'analytic_account_id': analytic_account.id,
|
|
'description': f"{rec.product_id.name} ({budget_position.name})",
|
|
'budget_line_id': line.id,
|
|
'remain': line_remain,
|
|
'new_balance': line_remain - used_amount,
|
|
'account_id': account_id.id
|
|
}))
|
|
remaining_amount -= used_amount
|
|
amount += used_amount
|
|
final_budget_line = line
|
|
|
|
if remaining_amount <= 0:
|
|
break
|
|
if remaining_amount <= 0:
|
|
break
|
|
|
|
if remaining_amount > 0:
|
|
raise ValidationError(_(
|
|
"Not enough budget available for analytic account '%s' (Expense account: %s).\n"
|
|
"Remaining unallocated amount: %.2f"
|
|
) % (analytic_account.name, account_id.name, remaining_amount))
|
|
|
|
if final_budget_line:
|
|
self.budget_id = final_budget_line.crossovered_budget_id.id
|
|
|
|
data = {
|
|
'name': self.name,
|
|
'date': self.date_order,
|
|
'beneficiary_id': self.partner_id.id,
|
|
'department_id': self.department_id.id,
|
|
'type': 'purchase.order',
|
|
'ref': self.name,
|
|
'description': self.purpose,
|
|
'total_amount': self.amount_untaxed,
|
|
'lines_ids': confirmation_lines,
|
|
'po_id': self.id
|
|
}
|
|
self.env['budget.confirmation'].with_context({}).create(data)
|
|
self.write({'state': 'waiting'})
|