mirror of
https://gitlab.com/flectra-community/account-closing.git
synced 2024-11-25 15:12:04 +00:00
193 lines
7.5 KiB
Python
193 lines
7.5 KiB
Python
|
# Copyright 2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
|
||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||
|
|
||
|
from flectra import models, fields, api, _
|
||
|
from flectra.exceptions import UserError, ValidationError
|
||
|
|
||
|
|
||
|
class AccountCutoff(models.Model):
|
||
|
_inherit = 'account.cutoff'
|
||
|
|
||
|
@api.model
|
||
|
def _get_default_source_journals(self):
|
||
|
res = []
|
||
|
cutoff_type = self.env.context.get('cutoff_type')
|
||
|
mapping = {
|
||
|
'prepaid_expense': 'purchase',
|
||
|
'prepaid_revenue': 'sale',
|
||
|
}
|
||
|
if cutoff_type in mapping:
|
||
|
src_journals = self.env['account.journal'].search(
|
||
|
[('type', '=', mapping[cutoff_type])])
|
||
|
if src_journals:
|
||
|
res = src_journals.ids
|
||
|
return res
|
||
|
|
||
|
source_journal_ids = fields.Many2many(
|
||
|
'account.journal', column1='cutoff_id', column2='journal_id',
|
||
|
string='Source Journals', readonly=True,
|
||
|
default=lambda self: self._get_default_source_journals(),
|
||
|
states={'draft': [('readonly', False)]})
|
||
|
forecast = fields.Boolean(
|
||
|
string='Forecast',
|
||
|
readonly=True, states={'draft': [('readonly', False)]},
|
||
|
help="The Forecast mode allows the user to compute "
|
||
|
"the prepaid revenue/expense between 2 dates in the future.")
|
||
|
start_date = fields.Date(string='Start Date')
|
||
|
end_date = fields.Date(string='End Date')
|
||
|
|
||
|
_sql_constraints = [(
|
||
|
'date_type_forecast_company_uniq',
|
||
|
'unique('
|
||
|
'cutoff_date, company_id, cutoff_type,'
|
||
|
' forecast, start_date, end_date)',
|
||
|
'A cut-off of the same type already exists with the same date(s) !'
|
||
|
)]
|
||
|
|
||
|
@api.multi
|
||
|
@api.constrains('start_date', 'end_date', 'forecast')
|
||
|
def _check_start_end_dates(self):
|
||
|
for prepaid in self:
|
||
|
if prepaid.forecast and prepaid.start_date and prepaid.end_date \
|
||
|
and prepaid.start_date > prepaid.end_date:
|
||
|
raise ValidationError(_(
|
||
|
'The start date is after the end date!'))
|
||
|
|
||
|
@api.onchange('forecast')
|
||
|
def onchange_forecast(self):
|
||
|
return {'warning': {
|
||
|
'title': _('Warning'),
|
||
|
'message': _(
|
||
|
"Don't forget to Re-Generate Lines after entering or "
|
||
|
"leaving forecast mode.")}}
|
||
|
|
||
|
@api.multi
|
||
|
def _prepare_prepaid_lines(self, aml, mapping):
|
||
|
self.ensure_one()
|
||
|
start_date_dt = fields.Date.from_string(aml.start_date)
|
||
|
end_date_dt = fields.Date.from_string(aml.end_date)
|
||
|
# Here, we compute the amount of the cutoff
|
||
|
# That's the important part !
|
||
|
total_days = (end_date_dt - start_date_dt).days + 1
|
||
|
if self.forecast:
|
||
|
out_days = 0
|
||
|
forecast_start_date_dt = fields.Date.from_string(self.start_date)
|
||
|
forecast_end_date_dt = fields.Date.from_string(self.end_date)
|
||
|
if end_date_dt > forecast_end_date_dt:
|
||
|
out_days += (end_date_dt - forecast_end_date_dt).days
|
||
|
if start_date_dt < forecast_start_date_dt:
|
||
|
out_days += (forecast_start_date_dt - start_date_dt).days
|
||
|
prepaid_days = total_days - out_days
|
||
|
else:
|
||
|
cutoff_date_str = self.cutoff_date
|
||
|
cutoff_date_dt = fields.Date.from_string(cutoff_date_str)
|
||
|
if start_date_dt > cutoff_date_dt:
|
||
|
prepaid_days = total_days
|
||
|
else:
|
||
|
prepaid_days = (end_date_dt - cutoff_date_dt).days
|
||
|
assert total_days > 0,\
|
||
|
'Should never happen. Total days should always be > 0'
|
||
|
cutoff_amount = (aml.debit - aml.credit) *\
|
||
|
prepaid_days / float(total_days)
|
||
|
# we use account mapping here
|
||
|
if aml.account_id.id in mapping:
|
||
|
cutoff_account_id = mapping[aml.account_id.id]
|
||
|
else:
|
||
|
cutoff_account_id = aml.account_id.id
|
||
|
|
||
|
res = {
|
||
|
'parent_id': self.id,
|
||
|
'move_line_id': aml.id,
|
||
|
'partner_id': aml.partner_id.id or False,
|
||
|
'name': aml.name,
|
||
|
'start_date': start_date_dt,
|
||
|
'end_date': end_date_dt,
|
||
|
'account_id': aml.account_id.id,
|
||
|
'cutoff_account_id': cutoff_account_id,
|
||
|
'analytic_account_id': aml.analytic_account_id.id or False,
|
||
|
'total_days': total_days,
|
||
|
'prepaid_days': prepaid_days,
|
||
|
'amount': aml.credit - aml.debit,
|
||
|
'currency_id': self.company_currency_id.id,
|
||
|
'cutoff_amount': cutoff_amount,
|
||
|
}
|
||
|
return res
|
||
|
|
||
|
@api.multi
|
||
|
def get_prepaid_lines(self):
|
||
|
self.ensure_one()
|
||
|
aml_obj = self.env['account.move.line']
|
||
|
line_obj = self.env['account.cutoff.line']
|
||
|
mapping_obj = self.env['account.cutoff.mapping']
|
||
|
if not self.source_journal_ids:
|
||
|
raise UserError(
|
||
|
_("You should set at least one Source Journal."))
|
||
|
cutoff_date_str = self.cutoff_date
|
||
|
# Delete existing lines
|
||
|
self.line_ids.unlink()
|
||
|
|
||
|
if self.forecast:
|
||
|
domain = [
|
||
|
('start_date', '<=', self.end_date),
|
||
|
('end_date', '>=', self.start_date),
|
||
|
('journal_id', 'in', self.source_journal_ids.ids)
|
||
|
]
|
||
|
else:
|
||
|
domain = [
|
||
|
('start_date', '!=', False),
|
||
|
('journal_id', 'in', self.source_journal_ids.ids),
|
||
|
('end_date', '>', cutoff_date_str),
|
||
|
('date', '<=', cutoff_date_str)
|
||
|
]
|
||
|
|
||
|
# Search for account move lines in the source journals
|
||
|
amls = aml_obj.search(domain)
|
||
|
# Create mapping dict
|
||
|
mapping = mapping_obj._get_mapping_dict(
|
||
|
self.company_id.id,
|
||
|
self.cutoff_type
|
||
|
)
|
||
|
|
||
|
# Loop on selected account move lines to create the cutoff lines
|
||
|
for aml in amls:
|
||
|
line_obj.create(self._prepare_prepaid_lines(aml, mapping))
|
||
|
return True
|
||
|
|
||
|
@api.model
|
||
|
def _default_cutoff_account_id(self):
|
||
|
account_id = super()._default_cutoff_account_id()
|
||
|
cutoff_type = self.env.context.get('cutoff_type')
|
||
|
company = self.env.user.company_id
|
||
|
if cutoff_type == 'prepaid_revenue':
|
||
|
account_id = company.default_prepaid_revenue_account_id.id or False
|
||
|
elif cutoff_type == 'prepaid_expense':
|
||
|
account_id = company.default_prepaid_expense_account_id.id or False
|
||
|
return account_id
|
||
|
|
||
|
@api.model
|
||
|
def create(self, vals):
|
||
|
res = super(AccountCutoff, self).create(vals)
|
||
|
if not res.source_journal_ids:
|
||
|
journals = self.env["account.journal"].search([])
|
||
|
res.source_journal_ids = journals
|
||
|
return res
|
||
|
|
||
|
|
||
|
class AccountCutoffLine(models.Model):
|
||
|
_inherit = 'account.cutoff.line'
|
||
|
|
||
|
move_line_id = fields.Many2one(
|
||
|
'account.move.line', string='Account Move Line', readonly=True)
|
||
|
move_date = fields.Date(
|
||
|
related='move_line_id.date', string='Account Move Date', readonly=True)
|
||
|
invoice_id = fields.Many2one(
|
||
|
related='move_line_id.invoice_id', string='Invoice', readonly=True)
|
||
|
start_date = fields.Date(string='Start Date', readonly=True)
|
||
|
end_date = fields.Date(string='End Date', readonly=True)
|
||
|
total_days = fields.Integer('Total Number of Days', readonly=True)
|
||
|
prepaid_days = fields.Integer(
|
||
|
string='Prepaid Days', readonly=True,
|
||
|
help="In regular mode, this is the number of days after the "
|
||
|
"cut-off date. In forecast mode, this is the number of days "
|
||
|
"between the start date and the end date.")
|