diff --git a/addons/account/models/account_invoice.py b/addons/account/models/account_invoice.py
index ee56ff2567b..caf6358fcca 100644
--- a/addons/account/models/account_invoice.py
+++ b/addons/account/models/account_invoice.py
@@ -1222,7 +1222,6 @@ class AccountInvoiceLine(models.Model):
def _onchange_uom_id(self):
warning = {}
result = {}
- self._onchange_product_id()
if not self.uom_id:
self.price_unit = 0.0
if self.product_id and self.uom_id:
diff --git a/addons/account_asset/account_asset.py b/addons/account_asset/account_asset.py
index 373b44922b3..4c96d4aee67 100644
--- a/addons/account_asset/account_asset.py
+++ b/addons/account_asset/account_asset.py
@@ -15,9 +15,9 @@ class AccountAssetCategory(models.Model):
active = fields.Boolean(default=True)
name = fields.Char(required=True, index=True, string="Asset Type")
account_analytic_id = fields.Many2one('account.analytic.account', string='Analytic Account')
- account_asset_id = fields.Many2one('account.account', string='Expense Account', required=True, domain=[('internal_type','=','other'), ('deprecated', '=', False)])
- account_income_recognition_id = fields.Many2one('account.account', string='Recognition Income Account', domain=[('internal_type','=','other'), ('deprecated', '=', False)], oldname='account_expense_depreciation_id')
- account_depreciation_id = fields.Many2one('account.account', string='Depreciation Account', required=True, domain=[('internal_type','=','other'), ('deprecated', '=', False)])
+ account_asset_id = fields.Many2one('account.account', string='Asset Account', required=True, domain=[('internal_type','=','other'), ('deprecated', '=', False)], help="Account used to record the purchase of the asset at its original price.")
+ account_depreciation_id = fields.Many2one('account.account', string='Depreciation Entries: Asset Account', required=True, domain=[('internal_type','=','other'), ('deprecated', '=', False)], help="Account used in the depreciation entries, to decrease the asset value.")
+ account_depreciation_expense_id = fields.Many2one('account.account', string='Depreciation Entries: Expense Account', required=True, domain=[('internal_type','=','other'), ('deprecated', '=', False)], oldname='account_income_recognition_id', help="Account used in the periodical entries, to record a part of the asset as expense.")
journal_id = fields.Many2one('account.journal', string='Journal', required=True)
company_id = fields.Many2one('res.company', string='Company', required=True, default=lambda self: self.env['res.company']._company_default_get('account.asset.category'))
method = fields.Selection([('linear', 'Linear'), ('degressive', 'Degressive')], string='Computation Method', required=True, default='linear',
@@ -33,9 +33,14 @@ class AccountAssetCategory(models.Model):
" * Ending Date: Choose the time between 2 depreciations and the date the depreciations won't go beyond.")
method_end = fields.Date('Ending date')
prorata = fields.Boolean(string='Prorata Temporis', help='Indicates that the first depreciation entry for this asset have to be done from the purchase date instead of the first of January')
- open_asset = fields.Boolean(string='Post Journal Entries', help="Check this if you want to automatically confirm the assets of this category when created by invoices.")
+ open_asset = fields.Boolean(string='Auto-confirm Assets', help="Check this if you want to automatically confirm the assets of this category when created by invoices.")
+ group_entries = fields.Boolean(string='Group Journal Entries', help="Check this if you want to group the generated entries by categories.")
type = fields.Selection([('sale', 'Sale: Revenue Recognition'), ('purchase', 'Purchase: Asset')], required=True, index=True, default='purchase')
+ @api.onchange('account_asset_id')
+ def onchange_account_asset(self):
+ self.account_depreciation_id = self.account_asset_id
+
@api.onchange('type')
def onchange_type(self):
if self.type == 'sale':
@@ -50,7 +55,6 @@ class AccountAssetAsset(models.Model):
_description = 'Asset/Revenue Recognition'
_inherit = ['mail.thread', 'ir.needaction_mixin']
- account_move_ids = fields.One2many('account.move', 'asset_id', string='Entries', readonly=True, states={'draft': [('readonly', False)]})
entry_count = fields.Integer(compute='_entry_count', string='# Asset Entries')
name = fields.Char(string='Asset Name', required=True, readonly=True, states={'draft': [('readonly', False)]})
code = fields.Char(string='Reference', size=32, readonly=True, states={'draft': [('readonly', False)]})
@@ -94,8 +98,9 @@ class AccountAssetAsset(models.Model):
for asset in self:
if asset.state in ['open', 'close']:
raise UserError(_('You cannot delete a document is in %s state.') % (asset.state,))
- if asset.account_move_ids:
- raise UserError(_('You cannot delete a document that contains posted entries.'))
+ for depreciation_line in asset.depreciation_line_ids:
+ if depreciation_line.move_id:
+ raise UserError(_('You cannot delete a document that contains posted entries.'))
return super(AccountAssetAsset, self).unlink()
@api.multi
@@ -107,16 +112,32 @@ class AccountAssetAsset(models.Model):
self.env.cr.execute("""
SELECT a.id as id, COALESCE(MAX(m.date),a.date) AS date
FROM account_asset_asset a
- LEFT JOIN account_move m ON (m.asset_id = a.id)
+ LEFT JOIN account_asset_depreciation_line rel ON (rel.asset_id = a.id)
+ LEFT JOIN account_move m ON (rel.move_id = m.id)
WHERE a.id IN %s
- GROUP BY a.id, a.date """, (tuple(self.ids),))
+ GROUP BY a.id, m.date """, (tuple(self.ids),))
result = dict(self.env.cr.fetchall())
return result
@api.model
def _cron_generate_entries(self):
- assets = self.env['account.asset.asset'].search([('state', '=', 'open')])
- assets._compute_entries(datetime.today())
+ self.compute_generated_entries(datetime.today())
+
+ @api.model
+ def compute_generated_entries(self, date, asset_type=None):
+ # Entries generated : one by grouped category and one by asset from ungrouped category
+ created_move_ids = []
+ type_domain = []
+ if asset_type:
+ type_domain = [('type', '=', asset_type)]
+
+ ungrouped_assets = self.env['account.asset.asset'].search(type_domain + [('state', '=', 'open'), ('category_id.group_entries', '=', False)])
+ created_move_ids += ungrouped_assets._compute_entries(date, group_entries=False)
+
+ for grouped_category in self.env['account.asset.category'].search(type_domain + [('group_entries', '=', True)]):
+ assets = self.env['account.asset.asset'].search([('state', '=', 'open'), ('category_id', '=', grouped_category.id)])
+ created_move_ids += assets._compute_entries(date, group_entries=True)
+ return created_move_ids
def _compute_board_amount(self, sequence, residual_amount, amount_to_depr, undone_dotation_number, posted_depreciation_line_ids, total_days, depreciation_date):
amount = 0
@@ -300,10 +321,11 @@ class AccountAssetAsset(models.Model):
self.currency_id = self.company_id.currency_id.id
@api.multi
- @api.depends('account_move_ids')
+ @api.depends('depreciation_line_ids.move_id')
def _entry_count(self):
for asset in self:
- asset.entry_count = self.env['account.move'].search_count([('asset_id', '=', asset.id)])
+ res = self.env['account.asset.depreciation.line'].search_count([('asset_id', '=', asset.id), ('move_id', '!=', False)])
+ asset.entry_count = res or 0
@api.one
@api.constrains('prorata', 'method_time')
@@ -347,10 +369,12 @@ class AccountAssetAsset(models.Model):
return super(AccountAssetAsset, self).copy_data(default)[0]
@api.multi
- def _compute_entries(self, date):
- depreciation_ids = self.env['account.asset.depreciation.line'].search([
+ def _compute_entries(self, date, group_entries=False):
+ depreciation_ids = self.env['account.asset.depreciation.line'].with_context(depreciation_date=date).search([
('asset_id', 'in', self.ids), ('depreciation_date', '<=', date),
('move_check', '=', False)])
+ if group_entries:
+ return depreciation_ids.create_grouped_move()
return depreciation_ids.create_move()
@api.model
@@ -368,6 +392,11 @@ class AccountAssetAsset(models.Model):
@api.multi
def open_entries(self):
+ move_ids = []
+ for asset in self:
+ for depreciation_line in asset.depreciation_line_ids:
+ if depreciation_line.move_id:
+ move_ids.append(depreciation_line.move_id.id)
return {
'name': _('Journal Entries'),
'view_type': 'form',
@@ -375,7 +404,7 @@ class AccountAssetAsset(models.Model):
'res_model': 'account.move',
'view_id': False,
'type': 'ir.actions.act_window',
- 'context': dict(self.env.context or {}, search_default_asset_id=self.id, default_asset_id=self.id),
+ 'domain': [('id', 'in', move_ids)]
}
@@ -403,49 +432,41 @@ class AccountAssetDepreciationLine(models.Model):
def create_move(self, post_move=True):
created_moves = self.env['account.move']
for line in self:
+ category_id = line.asset_id.category_id
depreciation_date = self.env.context.get('depreciation_date') or line.depreciation_date or fields.Date.context_today(self)
company_currency = line.asset_id.company_id.currency_id
current_currency = line.asset_id.currency_id
amount = current_currency.compute(line.amount, company_currency)
- sign = (line.asset_id.category_id.journal_id.type == 'purchase' or line.asset_id.category_id.journal_id.type == 'sale' and 1) or -1
+ sign = (category_id.journal_id.type == 'purchase' or category_id.journal_id.type == 'sale' and 1) or -1
asset_name = line.asset_id.name + ' (%s/%s)' % (line.sequence, line.asset_id.method_number)
- reference = line.asset_id.code
- journal_id = line.asset_id.category_id.journal_id.id
- partner_id = line.asset_id.partner_id.id
- categ_type = line.asset_id.category_id.type
- debit_account = line.asset_id.category_id.account_asset_id.id
- credit_account = line.asset_id.category_id.account_depreciation_id.id
move_line_1 = {
'name': asset_name,
- 'account_id': credit_account,
+ 'account_id': category_id.account_depreciation_id.id,
'debit': 0.0,
'credit': amount,
- 'journal_id': journal_id,
- 'partner_id': partner_id,
+ 'journal_id': category_id.journal_id.id,
+ 'partner_id': line.asset_id.partner_id.id,
+ 'analytic_account_id': category_id.account_analytic_id.id if category_id.type == 'sale' else False,
'currency_id': company_currency != current_currency and current_currency.id or False,
'amount_currency': company_currency != current_currency and - sign * line.amount or 0.0,
- 'analytic_account_id': line.asset_id.category_id.account_analytic_id.id if categ_type == 'sale' else False,
- 'date': depreciation_date,
}
move_line_2 = {
'name': asset_name,
- 'account_id': debit_account,
+ 'account_id': category_id.account_depreciation_expense_id.id,
'credit': 0.0,
'debit': amount,
- 'journal_id': journal_id,
- 'partner_id': partner_id,
+ 'journal_id': category_id.journal_id.id,
+ 'partner_id': line.asset_id.partner_id.id,
+ 'analytic_account_id': category_id.account_analytic_id.id if category_id.type == 'purchase' else False,
'currency_id': company_currency != current_currency and current_currency.id or False,
'amount_currency': company_currency != current_currency and sign * line.amount or 0.0,
- 'analytic_account_id': line.asset_id.category_id.account_analytic_id.id if categ_type == 'purchase' else False,
- 'date': depreciation_date,
}
move_vals = {
- 'ref': reference,
+ 'ref': line.asset_id.code,
'date': depreciation_date or False,
- 'journal_id': line.asset_id.category_id.journal_id.id,
+ 'journal_id': category_id.journal_id.id,
'line_ids': [(0, 0, move_line_1), (0, 0, move_line_2)],
- 'asset_id': line.asset_id.id,
- }
+ }
move = self.env['account.move'].create(move_vals)
line.write({'move_id': move.id, 'move_check': True})
created_moves |= move
@@ -455,6 +476,53 @@ class AccountAssetDepreciationLine(models.Model):
return [x.id for x in created_moves]
@api.multi
+ def create_grouped_move(self, post_move=True):
+ if not self.exists():
+ return []
+
+ created_moves = self.env['account.move']
+ category_id = self[0].asset_id.category_id # we can suppose that all lines have the same category
+ depreciation_date = self.env.context.get('depreciation_date') or fields.Date.context_today(self)
+ amount = 0.0
+ for line in self:
+ # Sum amount of all depreciation lines
+ company_currency = line.asset_id.company_id.currency_id
+ current_currency = line.asset_id.currency_id
+ amount += current_currency.compute(line.amount, company_currency)
+
+ name = category_id.name + _(' (grouped)')
+ move_line_1 = {
+ 'name': name,
+ 'account_id': category_id.account_depreciation_id.id,
+ 'debit': 0.0,
+ 'credit': amount,
+ 'journal_id': category_id.journal_id.id,
+ 'analytic_account_id': category_id.account_analytic_id.id if category_id.type == 'sale' else False,
+ }
+ move_line_2 = {
+ 'name': name,
+ 'account_id': category_id.account_depreciation_expense_id.id,
+ 'credit': 0.0,
+ 'debit': amount,
+ 'journal_id': category_id.journal_id.id,
+ 'analytic_account_id': category_id.account_analytic_id.id if category_id.type == 'purchase' else False,
+ }
+ move_vals = {
+ 'ref': category_id.name,
+ 'date': depreciation_date or False,
+ 'journal_id': category_id.journal_id.id,
+ 'line_ids': [(0, 0, move_line_1), (0, 0, move_line_2)],
+ }
+ move = self.env['account.move'].create(move_vals)
+ self.write({'move_id': move.id, 'move_check': True})
+ created_moves |= move
+
+ if post_move and created_moves:
+ self.post_lines_and_close_asset()
+ created_moves.post()
+ return [x.id for x in created_moves]
+
+ api.multi
def post_lines_and_close_asset(self):
# we re-evaluate the assets to determine whether we can close them
for line in self:
@@ -500,11 +568,11 @@ class AccountAssetDepreciationLine(models.Model):
class AccountMove(models.Model):
_inherit = 'account.move'
- asset_id = fields.Many2one('account.asset.asset', string='Asset', ondelete="restrict")
+ asset_depreciation_ids = fields.One2many('account.asset.depreciation.line', 'move_id', string='Assets Depreciation Lines', ondelete="restrict")
@api.multi
def post(self):
for move in self:
- if move.asset_id:
- move.asset_id.depreciation_line_ids.post_lines_and_close_asset()
+ for depreciation_line in move.asset_depreciation_ids:
+ depreciation_line.post_lines_and_close_asset()
return super(AccountMove, self).post()
diff --git a/addons/account_asset/account_asset_demo.yml b/addons/account_asset/account_asset_demo.yml
index 5fa541ca2bb..22cfc0cff35 100644
--- a/addons/account_asset/account_asset_demo.yml
+++ b/addons/account_asset/account_asset_demo.yml
@@ -15,18 +15,18 @@
'journal_id': journal_id[0],
'name': 'Hardware - 3 Years',
'method_number': 3,
- 'account_asset_id': expense_account_id[0],
+ 'account_asset_id': xfa_account_id[0],
'account_depreciation_id': xfa_account_id[0],
- 'account_income_recognition_id': expense_account_id[0],
+ 'account_depreciation_expense_id': expense_account_id[0],
}
self._update(cr, uid, 'account.asset.category', 'account_asset', vals, 'account_asset_category_fixedassets0')
vals = {
'journal_id': journal_id[0],
'name': 'Cars - 5 Years',
'method_number': 5,
- 'account_asset_id': expense_account_id[0],
+ 'account_asset_id': xfa_account_id[0],
'account_depreciation_id': xfa_account_id[0],
- 'account_income_recognition_id': expense_account_id[0],
+ 'account_depreciation_expense_id': expense_account_id[0],
}
self._update(cr, uid, 'account.asset.category', 'account_asset', vals, 'account_asset_category_fixedassets1')
vals = {
diff --git a/addons/account_asset/account_asset_invoice.py b/addons/account_asset/account_asset_invoice.py
index 0312063c907..26c35dd7903 100644
--- a/addons/account_asset/account_asset_invoice.py
+++ b/addons/account_asset/account_asset_invoice.py
@@ -70,12 +70,19 @@ class AccountInvoiceLine(models.Model):
return True
@api.onchange('product_id')
- def onchange_product_id(self):
+ def _onchange_product_id(self):
+ vals = super(AccountInvoiceLine, self)._onchange_product_id()
if self.product_id:
if self.invoice_id.type == 'out_invoice':
self.asset_category_id = self.product_id.product_tmpl_id.deferred_revenue_category_id
elif self.invoice_id.type == 'in_invoice':
self.asset_category_id = self.product_id.product_tmpl_id.asset_category_id
+ return vals
+
+ @api.onchange('asset_category_id')
+ def onchange_asset_category_id(self):
+ if self.asset_category_id:
+ self.account_id = self.asset_category_id.account_asset_id
def _set_additional_fields(self, invoice):
if not self.asset_category_id:
@@ -90,13 +97,3 @@ class ProductTemplate(models.Model):
_inherit = 'product.template'
asset_category_id = fields.Many2one('account.asset.category', string='Asset Type', ondelete="restrict")
deferred_revenue_category_id = fields.Many2one('account.asset.category', string='Deferred Revenue Type', ondelete="restrict")
-
- @api.onchange('deferred_revenue_category_id')
- def onchange_revenue_category_id(self):
- if self.deferred_revenue_category_id:
- self.property_account_income_id = self.deferred_revenue_category_id.account_depreciation_id.id
-
- @api.onchange('asset_category_id')
- def onchange_asset(self):
- if self.asset_category_id:
- self.property_account_expense_id = self.asset_category_id.account_asset_id
diff --git a/addons/account_asset/test/account_asset_demo_test.xml b/addons/account_asset/test/account_asset_demo_test.xml
index 55951f7d817..bba5a04a20a 100644
--- a/addons/account_asset/test/account_asset_demo_test.xml
+++ b/addons/account_asset/test/account_asset_demo_test.xml
@@ -6,7 +6,8 @@
-->