# -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. from odoo import models, fields, _ from odoo.tools.misc import DEFAULT_SERVER_DATE_FORMAT from datetime import timedelta from odoo.tools import date_utils class ResCompany(models.Model): _inherit = 'res.company' invoicing_switch_threshold = fields.Date(string="Invoicing Switch Threshold", help="Every payment and invoice before this date will receive the 'From Invoicing' status, hiding all the accounting entries related to it. Use this option after installing Accounting if you were using only Invoicing before, before importing all your actual accounting data in to Odoo.") def write(self, vals): old_threshold_vals = {} for record in self: old_threshold_vals[record] = record.invoicing_switch_threshold rslt = super(ResCompany, self).write(vals) for record in self: if 'invoicing_switch_threshold' in vals and old_threshold_vals[record] != vals['invoicing_switch_threshold']: self.env['account.move.line'].flush_model(['move_id', 'parent_state']) self.env['account.move'].flush_model(['company_id', 'date', 'state', 'payment_state', 'payment_state_before_switch']) if record.invoicing_switch_threshold: # If a new date was set as threshold, we switch all the # posted moves and payments before it to 'invoicing_legacy'. # We also reset to posted all the moves and payments that # were 'invoicing_legacy' and were posterior to the threshold self.env.cr.execute(""" update account_move_line aml set parent_state = 'posted' from account_move move where aml.move_id = move.id and move.payment_state = 'invoicing_legacy' and move.date >= %(switch_threshold)s and move.company_id = %(company_id)s; update account_move set state = 'posted', payment_state = payment_state_before_switch, payment_state_before_switch = null where payment_state = 'invoicing_legacy' and date >= %(switch_threshold)s and company_id = %(company_id)s; update account_move_line aml set parent_state = 'cancel' from account_move move where aml.move_id = move.id and move.state = 'posted' and move.date < %(switch_threshold)s and move.company_id = %(company_id)s; update account_move set state = 'cancel', payment_state_before_switch = payment_state, payment_state = 'invoicing_legacy' where state = 'posted' and date < %(switch_threshold)s and company_id = %(company_id)s; """, {'company_id': record.id, 'switch_threshold': record.invoicing_switch_threshold}) else: # If the threshold date has been emptied, we re-post all the # invoicing_legacy entries. self.env.cr.execute(""" update account_move_line aml set parent_state = 'posted' from account_move move where aml.move_id = move.id and move.payment_state = 'invoicing_legacy' and move.company_id = %(company_id)s; update account_move set state = 'posted', payment_state = payment_state_before_switch, payment_state_before_switch = null where payment_state = 'invoicing_legacy' and company_id = %(company_id)s; """, {'company_id': record.id}) self.env['account.move.line'].invalidate_model(['parent_state']) self.env['account.move'].invalidate_model(['state', 'payment_state', 'payment_state_before_switch']) return rslt def compute_fiscalyear_dates(self, current_date): """Compute the start and end dates of the fiscal year where the given 'date' belongs to. :param current_date: A datetime.date/datetime.datetime object. :return: A dictionary containing: * date_from * date_to * [Optionally] record: The fiscal year record. """ self.ensure_one() date_str = current_date.strftime(DEFAULT_SERVER_DATE_FORMAT) # Search a fiscal year record containing the date. # If a record is found, then no need further computation, we get the dates range directly. fiscalyear = self.env['account.fiscal.year'].search([ ('company_id', '=', self.id), ('date_from', '<=', date_str), ('date_to', '>=', date_str), ], limit=1) if fiscalyear: return { 'date_from': fiscalyear.date_from, 'date_to': fiscalyear.date_to, 'record': fiscalyear, } date_from, date_to = date_utils.get_fiscal_year( current_date, day=self.fiscalyear_last_day, month=int(self.fiscalyear_last_month)) date_from_str = date_from.strftime(DEFAULT_SERVER_DATE_FORMAT) date_to_str = date_to.strftime(DEFAULT_SERVER_DATE_FORMAT) # Search for fiscal year records reducing the delta between the date_from/date_to. # This case could happen if there is a gap between two fiscal year records. # E.g. two fiscal year records: 2017-01-01 -> 2017-02-01 and 2017-03-01 -> 2017-12-31. # => The period 2017-02-02 - 2017-02-30 is not covered by a fiscal year record. fiscalyear_from = self.env['account.fiscal.year'].search([ ('company_id', '=', self.id), ('date_from', '<=', date_from_str), ('date_to', '>=', date_from_str), ], limit=1) if fiscalyear_from: date_from = fiscalyear_from.date_to + timedelta(days=1) fiscalyear_to = self.env['account.fiscal.year'].search([ ('company_id', '=', self.id), ('date_from', '<=', date_to_str), ('date_to', '>=', date_to_str), ], limit=1) if fiscalyear_to: date_to = fiscalyear_to.date_from - timedelta(days=1) return {'date_from': date_from, 'date_to': date_to} def _get_fiscalyear_lock_statement_lines_redirect_action(self, unreconciled_statement_lines): # OVERRIDE account return self.env['account.bank.statement.line']._action_open_bank_reconciliation_widget( default_context={'search_default_not_matched': True}, extra_domain=[('id', 'in', unreconciled_statement_lines.ids)], name=_('Unreconciled statements lines'), )