diff --git a/addons/account/__manifest__.py b/addons/account/__manifest__.py
index 62f0f56f91b..5f46c40a8e8 100644
--- a/addons/account/__manifest__.py
+++ b/addons/account/__manifest__.py
@@ -56,7 +56,7 @@ You could use this simplified accounting in case you work with an (external) acc
'views/report_payment_receipt_templates.xml',
'data/payment_receipt_data.xml',
'views/account_onboarding_templates.xml',
- 'data/service_cron_reverse.xml',
+ 'data/service_cron.xml',
'views/account_fiscal_year_view.xml',
'views/account_incoterms_view.xml',
'data/account_incoterms_data.xml',
diff --git a/addons/account/data/service_cron.xml b/addons/account/data/service_cron.xml
new file mode 100644
index 00000000000..6436692b2d5
--- /dev/null
+++ b/addons/account/data/service_cron.xml
@@ -0,0 +1,14 @@
+
+
+
+ Account; Post draft entries with auto_post set to True up to today
+ 1
+ days
+ -1
+
+
+
+ model._run_post_draft_to_post()
+ code
+
+
diff --git a/addons/account/data/service_cron_reverse.xml b/addons/account/data/service_cron_reverse.xml
deleted file mode 100644
index 982abbeea1f..00000000000
--- a/addons/account/data/service_cron_reverse.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
- Account; Reverse entries
- 1
- days
- -1
-
-
- model._run_reverses_entries()
- code
-
-
diff --git a/addons/account/models/account_move.py b/addons/account/models/account_move.py
index 0685a70bcb1..9c7164299b2 100644
--- a/addons/account/models/account_move.py
+++ b/addons/account/models/account_move.py
@@ -43,13 +43,38 @@ class AccountMove(models.Model):
return result
@api.multi
- @api.depends('line_ids.debit', 'line_ids.credit')
+ @api.depends('line_ids.debit', 'line_ids.credit', 'line_ids.amount_currency', 'line_ids.currency_id')
def _amount_compute(self):
for move in self:
total = 0.0
- for line in move.line_ids:
+ total_currency = 0.0
+ currency_id = move.line_ids and move.line_ids[0].currency_id.id or False
+ for line in move.line_ids.filtered(lambda l: l.debit):
total += line.debit
- move.amount = total
+ if currency_id and line.currency_id.id == currency_id:
+ total_currency += line.amount_currency
+ elif currency_id:
+ currency_id = False
+
+ if currency_id and total_currency:
+ move.amount = total_currency
+ move.currency_id = currency_id
+ else:
+ move.currency_id = move.company_id.currency_id or self.env.user.company_id.currency_id
+ move.amount = total
+
+ @api.multi
+ def _set_amount(self):
+ for move in self:
+ if len(move.line_ids) == 2 and move.amount != 0:
+ amount_in_company_currency = move.amount
+ if move.currency_id and move.currency_id != move.company_id.currency_id:
+ amount_in_company_currency = move.currency_id._convert(move.amount, move.company_id.currency_id, move.company_id, move.date)
+ for line in move.line_ids:
+ line.amount_currency = line.debit and move.amount or -move.amount
+ for line in move.with_context(check_move_validity=False).line_ids:
+ line.debit = line.debit and amount_in_company_currency or 0.0
+ line.credit = line.credit and amount_in_company_currency or 0.0
@api.depends('line_ids.debit', 'line_ids.credit', 'line_ids.matched_debit_ids.amount', 'line_ids.matched_credit_ids.amount', 'line_ids.account_id.user_type_id.type')
def _compute_matched_percentage(self):
@@ -88,11 +113,6 @@ class AccountMove(models.Model):
return [('id', 'in', rmi.ids)]
return [('id', '=', False)]
- @api.one
- @api.depends('company_id')
- def _compute_currency(self):
- self.currency_id = self.company_id.currency_id or self.env.user.company_id.currency_id
-
@api.multi
def _get_default_journal(self):
if self.env.context.get('default_journal_type'):
@@ -117,7 +137,6 @@ class AccountMove(models.Model):
ref = fields.Char(string='Reference', copy=False)
date = fields.Date(required=True, states={'posted': [('readonly', True)]}, index=True, default=fields.Date.context_today)
journal_id = fields.Many2one('account.journal', string='Journal', required=True, states={'posted': [('readonly', True)]}, default=_get_default_journal)
- currency_id = fields.Many2one('res.currency', compute='_compute_currency', store=True, string="Currency")
state = fields.Selection([('draft', 'Unposted'), ('posted', 'Posted')], string='Status',
required=True, readonly=True, copy=False, default='draft',
help='All manually created new journal entries are usually in the status \'Unposted\', '
@@ -128,7 +147,8 @@ class AccountMove(models.Model):
line_ids = fields.One2many('account.move.line', 'move_id', string='Journal Items',
states={'posted': [('readonly', True)]}, copy=True)
partner_id = fields.Many2one('res.partner', compute='_compute_partner_id', string="Partner", store=True, readonly=True)
- amount = fields.Monetary(compute='_amount_compute', store=True)
+ amount = fields.Monetary(compute='_amount_compute', inverse="_set_amount", store=True)
+ currency_id = fields.Many2one('res.currency', compute='_amount_compute', store=True, string="Currency")
narration = fields.Text(string='Internal Note')
company_id = fields.Many2one('res.company', related='journal_id.company_id', string='Company', store=True, readonly=True)
matched_percentage = fields.Float('Percentage Matched', compute='_compute_matched_percentage', digits=0, store=True, readonly=True, help="Technical field used in cash basis method")
@@ -140,13 +160,12 @@ class AccountMove(models.Model):
string='Tax Cash Basis Entry of',
help="Technical field used to keep track of the tax cash basis reconciliation. "
"This is needed when cancelling the source: it will post the inverse journal entry to cancel that part too.")
- auto_reverse = fields.Boolean(string='Reverse Automatically', default=False, help='If this checkbox is ticked, this entry will be automatically reversed at the reversal date you defined.')
- reverse_date = fields.Date(string='Reversal Date', help='Date of the reverse accounting entry.')
+ auto_post = fields.Boolean(string='Post Automatically', default=False, help='If this checkbox is ticked, this entry will be automatically posted at its date.')
reverse_entry_id = fields.Many2one('account.move', String="Reverse entry", store=True, readonly=True)
to_check = fields.Boolean(string='To Check', default=False, help='If this checkbox is ticked, it means that the user was not sure of all the related informations at the time of the creation of the move and that the move needs to be checked again.')
tax_type_domain = fields.Char(store=False, help='Technical field used to have a dynamic taxes domain on the form view.')
- @api.constrains('line_ids', 'journal_id', 'auto_reverse', 'reverse_date')
+ @api.constrains('line_ids', 'journal_id')
def _validate_move_modification(self):
if 'posted' in self.mapped('line_ids.payment_id.state'):
raise ValidationError(_("You cannot modify a journal entry linked to a posted payment."))
@@ -315,6 +334,9 @@ class AccountMove(models.Model):
# Create the analytic lines in batch is faster as it leads to less cache invalidation.
self.mapped('line_ids').create_analytic_lines()
for move in self:
+ if move.auto_post and move.date > fields.Date.today():
+ raise UserError(_("This move is configured to be auto-posted on {}".format(move.date.strftime(self.env['res.lang']._lang_get(self.env.user.lang).date_format))))
+
if move.name == '/':
new_name = False
journal = move.journal_id
@@ -417,14 +439,14 @@ class AccountMove(models.Model):
return True
@api.multi
- def _reverse_move(self, date=None, journal_id=None, auto=False):
+ def _reverse_move(self, date=None, journal_id=None):
self.ensure_one()
with self.env.norecompute():
reversed_move = self.copy(default={
'date': date,
'journal_id': journal_id.id if journal_id else self.journal_id.id,
- 'ref': (_('Automatic reversal of: %s') if auto else _('Reversal of: %s')) % (self.name),
- 'auto_reverse': False})
+ 'ref': _('Reversal of: %s') % (self.name),
+ })
for acm_line in reversed_move.line_ids.with_context(check_move_validity=False):
acm_line.write({
'debit': acm_line.credit,
@@ -436,16 +458,14 @@ class AccountMove(models.Model):
return reversed_move
@api.multi
- def reverse_moves(self, date=None, journal_id=None, auto=False):
+ def reverse_moves(self, date=None, journal_id=None):
date = date or fields.Date.today()
reversed_moves = self.env['account.move']
for ac_move in self:
#unreconcile all lines reversed
aml = ac_move.line_ids.filtered(lambda x: x.account_id.reconcile or x.account_id.internal_type == 'liquidity')
aml.remove_move_reconcile()
- reversed_move = ac_move._reverse_move(date=date,
- journal_id=journal_id,
- auto=auto)
+ reversed_move = ac_move._reverse_move(date=date, journal_id=journal_id)
reversed_moves |= reversed_move
#reconcile together the reconcilable (or the liquidity aml) and their newly created counterpart
for account in set([x.account_id for x in aml]):
@@ -476,18 +496,17 @@ class AccountMove(models.Model):
return action
@api.model
- def _run_reverses_entries(self):
- ''' This method is called from a cron job. '''
+ def _run_post_draft_to_post(self):
+ ''' This method is called from a cron job.
+ It is used to post entries such as those created by the module
+ account_asset.
+ '''
records = self.search([
- ('state', '=', 'posted'),
- ('auto_reverse', '=', True),
- ('reverse_date', '<=', fields.Date.today()),
- ('reverse_entry_id', '=', False)])
- for move in records:
- date = None
- if move.reverse_date and (not self.env.user.company_id.period_lock_date or move.reverse_date > self.env.user.company_id.period_lock_date):
- date = move.reverse_date
- move.reverse_moves(date=date, auto=True)
+ ('state', '=', 'draft'),
+ ('date', '<=', fields.Date.today()),
+ ('auto_post', '=', True),
+ ])
+ records.post()
@api.multi
def action_view_reverse_entry(self):
diff --git a/addons/account/tests/test_reconciliation.py b/addons/account/tests/test_reconciliation.py
index 0fc4c2bc7dd..02d13111b31 100644
--- a/addons/account/tests/test_reconciliation.py
+++ b/addons/account/tests/test_reconciliation.py
@@ -227,7 +227,7 @@ class TestReconciliationExec(TestReconciliation):
{'debit': 10.74, 'credit': 0.0, 'account_id': self.diff_expense_account.id},
{'debit': 0.0, 'credit': 10.74, 'account_id': self.account_rcv.id},
])
-
+
self.assertRecordValues(supplier_move_lines, [
{'debit': 0.0, 'credit': 27.47, 'amount_currency': -42, 'currency_id': self.currency_usd_id},
{'debit': 27.47, 'credit': 0.0, 'amount_currency': 50, 'currency_id': self.currency_swiss_id},
@@ -249,7 +249,7 @@ class TestReconciliationExec(TestReconciliation):
{'debit': 0.0, 'credit': 7.30, 'account_id': self.diff_income_account.id},
{'debit': 7.30, 'credit': 0.0, 'account_id': self.account_rcv.id},
])
-
+
self.assertRecordValues(supplier_move_lines, [
{'debit': 0.0, 'credit': 40.0, 'amount_currency': -50, 'currency_id': self.currency_usd_id},
{'debit': 40.0, 'credit': 0.0, 'amount_currency': 50, 'currency_id': self.currency_usd_id},
@@ -643,12 +643,12 @@ class TestReconciliationExec(TestReconciliation):
'currency_id': self.currency_usd_id,
'company_id': self.env.ref('base.main_company').id})
- self.env['res.currency.rate'].create({'name': time.strftime('%Y') + '-' + '08' + '-01',
+ self.env['res.currency.rate'].create({'name': time.strftime('%Y') + '-' + '08' + '-01',
'rate': 0.75,
'currency_id': self.currency_usd_id,
'company_id': self.env.ref('base.main_company').id})
- self.env['res.currency.rate'].create({'name': time.strftime('%Y') + '-' + '09' + '-01',
+ self.env['res.currency.rate'].create({'name': time.strftime('%Y') + '-' + '09' + '-01',
'rate': 0.80,
'currency_id': self.currency_usd_id,
'company_id': self.env.ref('base.main_company').id})
@@ -1520,18 +1520,18 @@ class TestReconciliationExec(TestReconciliation):
expected['tax_10']
)
index += 1
-
+
def test_reconciliation_to_check(self):
partner = self.env['res.partner'].create({'name': 'UncertainPartner'})
currency = self.env.user.company_id.currency_id
invoice = self.create_invoice_partner(currency_id=currency.id, partner_id=partner.id)
journal = self.env['account.journal'].create({'name': 'Bank', 'type': 'bank', 'code': 'THE', 'update_posted':True})
-
+
statement = self.make_payment(invoice, journal, 50)
st_line = statement.line_ids
previous_move_lines = st_line.journal_entry_ids.ids
previous_name = st_line.move_name
-
+
with self.assertRaises(UserError): #you need edition mode to be able to change it
st_line.with_context(edition_mode=False).process_reconciliation(
counterpart_aml_dicts=[],
@@ -1542,7 +1542,7 @@ class TestReconciliationExec(TestReconciliation):
'account_id': self.diff_income_account.id
}],
)
-
+
st_line.with_context(edition_mode=True).process_reconciliation(
counterpart_aml_dicts=[],
new_aml_dicts = [{
@@ -1697,8 +1697,7 @@ class TestReconciliationExec(TestReconciliation):
self.assertEqual(len(cash_basis_aml_ids), 4)
# check amounts
- cash_basis_move1 = cash_basis_moves.filtered(
- lambda m: m.amount == 123936.31)
+ cash_basis_move1 = cash_basis_moves.filtered(lambda m: m.currency_id.is_zero(sum(line.credit for line in m.line_ids) - 123936.31))
self.assertTrue(cash_basis_move1.exists())
@@ -1893,8 +1892,7 @@ class TestReconciliationExec(TestReconciliation):
self.assertEqual(len(cash_basis_aml_ids), 4)
# check amounts
- cash_basis_move1 = cash_basis_moves.filtered(
- lambda m: m.amount == 123936.31)
+ cash_basis_move1 = cash_basis_moves.filtered(lambda m: m.currency_id.is_zero(sum(line.credit for line in m.line_ids) - 123936.31))
self.assertTrue(cash_basis_move1.exists())
diff --git a/addons/account/views/account_move_views.xml b/addons/account/views/account_move_views.xml
index 69956a6f349..faecd55cb87 100644
--- a/addons/account/views/account_move_views.xml
+++ b/addons/account/views/account_move_views.xml
@@ -328,7 +328,7 @@
-
+
@@ -363,8 +363,7 @@
-
-
+