[MOV] account_asset: move to enterprise

This commit is contained in:
Antony Lesuisse
2018-10-01 16:38:00 +02:00
parent 62644f93fe
commit 2e63ead842
102 changed files with 0 additions and 84287 deletions
-6
View File
@@ -1,6 +0,0 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import models
from . import wizard
from . import report
-32
View File
@@ -1,32 +0,0 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
{
'name': 'Assets Management',
'depends': ['account'],
'description': """
Assets management
=================
Manage assets owned by a company or a person.
Keeps track of depreciations, and creates corresponding journal entries.
""",
'category': 'Accounting',
'sequence': 32,
'data': [
'security/account_asset_security.xml',
'security/ir.model.access.csv',
'wizard/asset_depreciation_confirmation_wizard_views.xml',
'wizard/asset_modify_views.xml',
'views/account_asset_views.xml',
'views/account_invoice_views.xml',
'views/account_asset_templates.xml',
'views/product_views.xml',
'views/res_config_settings_views.xml',
'report/account_asset_report_views.xml',
'data/account_asset_data.xml',
],
'qweb': [
"static/src/xml/account_asset_template.xml",
],
}
@@ -1,13 +0,0 @@
<?xml version="1.0" encoding='UTF-8'?>
<odoo>
<record id="account_asset_cron" model="ir.cron">
<field name="name">Account Asset: Generate asset entries</field>
<field name="model_id" ref="model_account_asset_asset"/>
<field name="state">code</field>
<field name="code">model._cron_generate_entries()</field>
<field name="interval_number">1</field>
<field name="interval_type">months</field>
<field name="numbercall">-1</field>
<field name="doall" eval="False"/>
</record>
</odoo>
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
-7
View File
@@ -1,7 +0,0 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import account
from . import account_asset
from . import account_invoice
from . import product
-24
View File
@@ -1,24 +0,0 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import api, fields, models
class AccountMove(models.Model):
_inherit = 'account.move'
asset_depreciation_ids = fields.One2many('account.asset.depreciation.line', 'move_id', string='Assets Depreciation Lines', ondelete="restrict")
@api.multi
def button_cancel(self):
for move in self:
for line in move.asset_depreciation_ids:
line.move_posted_check = False
return super(AccountMove, self).button_cancel()
@api.multi
def post(self, invoice=False):
for move in self:
for depreciation_line in move.asset_depreciation_ids:
depreciation_line.post_lines_and_close_asset()
return super(AccountMove, self).post(invoice=invoice)
@@ -1,654 +0,0 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import calendar
from datetime import date, datetime
from dateutil.relativedelta import relativedelta
from odoo import api, fields, models, _
from odoo.exceptions import UserError, ValidationError
from odoo.tools import float_compare, float_is_zero
class AccountAssetCategory(models.Model):
_name = 'account.asset.category'
_description = 'Asset Category'
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')
analytic_tag_ids = fields.Many2many('account.analytic.tag', string='Analytic Tag')
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',
help="Choose the method to use to compute the amount of depreciation lines.\n"
" * Linear: Calculated on basis of: Gross Value / Number of Depreciations\n"
" * Degressive: Calculated on basis of: Residual Value * Degressive Factor")
method_number = fields.Integer(string='Number of Depreciations', default=5, help="The number of depreciations needed to depreciate your asset")
method_period = fields.Integer(string='Period Length', default=1, help="State here the time between 2 depreciations, in months", required=True)
method_progress_factor = fields.Float('Degressive Factor', default=0.3)
method_time = fields.Selection([('number', 'Number of Entries'), ('end', 'Ending Date')], string='Time Method', required=True, default='number',
help="Choose the method to use to compute the dates and number of entries.\n"
" * Number of Entries: Fix the number of entries and the time between 2 depreciations.\n"
" * 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='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')
date_first_depreciation = fields.Selection([
('last_day_period', 'Based on Last Day of Purchase Period'),
('manual', 'Manual (Defaulted on Purchase Date)')],
string='Depreciation Dates', default='manual', required=True,
help='The way to compute the date of the first depreciation.\n'
' * Based on last day of purchase period: The depreciation dates will be based on the last day of the purchase month or the purchase year (depending on the periodicity of the depreciations).\n'
' * Based on purchase date: The depreciation dates will be based on the purchase date.')
@api.onchange('account_asset_id')
def onchange_account_asset(self):
if self.type == "purchase":
self.account_depreciation_id = self.account_asset_id
elif self.type == "sale":
self.account_depreciation_expense_id = self.account_asset_id
@api.onchange('type')
def onchange_type(self):
if self.type == 'sale':
self.prorata = True
self.method_period = 1
else:
self.method_period = 12
@api.onchange('method_time')
def _onchange_method_time(self):
if self.method_time != 'number':
self.prorata = False
class AccountAssetAsset(models.Model):
_name = 'account.asset.asset'
_description = 'Asset/Revenue Recognition'
_inherit = ['mail.thread']
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)]})
value = fields.Float(string='Gross Value', required=True, readonly=True, digits=0, states={'draft': [('readonly', False)]}, oldname='purchase_value')
currency_id = fields.Many2one('res.currency', string='Currency', required=True, readonly=True, states={'draft': [('readonly', False)]},
default=lambda self: self.env.user.company_id.currency_id.id)
company_id = fields.Many2one('res.company', string='Company', required=True, readonly=True, states={'draft': [('readonly', False)]},
default=lambda self: self.env['res.company']._company_default_get('account.asset.asset'))
note = fields.Text()
category_id = fields.Many2one('account.asset.category', string='Category', required=True, change_default=True, readonly=True, states={'draft': [('readonly', False)]})
date = fields.Date(string='Date', required=True, readonly=True, states={'draft': [('readonly', False)]}, default=fields.Date.context_today, oldname="purchase_date")
state = fields.Selection([('draft', 'Draft'), ('open', 'Running'), ('close', 'Close')], 'Status', required=True, copy=False, default='draft',
help="When an asset is created, the status is 'Draft'.\n"
"If the asset is confirmed, the status goes in 'Running' and the depreciation lines can be posted in the accounting.\n"
"You can manually close an asset when the depreciation is over. If the last line of depreciation is posted, the asset automatically goes in that status.")
active = fields.Boolean(default=True)
partner_id = fields.Many2one('res.partner', string='Partner', readonly=True, states={'draft': [('readonly', False)]})
method = fields.Selection([('linear', 'Linear'), ('degressive', 'Degressive')], string='Computation Method', required=True, readonly=True, states={'draft': [('readonly', False)]}, default='linear',
help="Choose the method to use to compute the amount of depreciation lines.\n * Linear: Calculated on basis of: Gross Value / Number of Depreciations\n"
" * Degressive: Calculated on basis of: Residual Value * Degressive Factor")
method_number = fields.Integer(string='Number of Depreciations', readonly=True, states={'draft': [('readonly', False)]}, default=5, help="The number of depreciations needed to depreciate your asset")
method_period = fields.Integer(string='Number of Months in a Period', required=True, readonly=True, default=12, states={'draft': [('readonly', False)]},
help="The amount of time between two depreciations, in months")
method_end = fields.Date(string='Ending Date', readonly=True, states={'draft': [('readonly', False)]})
method_progress_factor = fields.Float(string='Degressive Factor', readonly=True, default=0.3, states={'draft': [('readonly', False)]})
value_residual = fields.Float(compute='_amount_residual', method=True, digits=0, string='Residual Value')
method_time = fields.Selection([('number', 'Number of Entries'), ('end', 'Ending Date')], string='Time Method', required=True, readonly=True, default='number', states={'draft': [('readonly', False)]},
help="Choose the method to use to compute the dates and number of entries.\n"
" * Number of Entries: Fix the number of entries and the time between 2 depreciations.\n"
" * Ending Date: Choose the time between 2 depreciations and the date the depreciations won't go beyond.")
prorata = fields.Boolean(string='Prorata Temporis', readonly=True, states={'draft': [('readonly', False)]},
help='Indicates that the first depreciation entry for this asset have to be done from the asset date (purchase date) instead of the first January / Start date of fiscal year')
depreciation_line_ids = fields.One2many('account.asset.depreciation.line', 'asset_id', string='Depreciation Lines', readonly=True, states={'draft': [('readonly', False)], 'open': [('readonly', False)]})
salvage_value = fields.Float(string='Salvage Value', digits=0, readonly=True, states={'draft': [('readonly', False)]},
help="It is the amount you plan to have that you cannot depreciate.")
invoice_id = fields.Many2one('account.invoice', string='Invoice', states={'draft': [('readonly', False)]}, copy=False)
type = fields.Selection(related="category_id.type", string='Type', required=True, readonly=False)
account_analytic_id = fields.Many2one('account.analytic.account', string='Analytic Account')
analytic_tag_ids = fields.Many2many('account.analytic.tag', string='Analytic Tag')
date_first_depreciation = fields.Selection([
('last_day_period', 'Based on Last Day of Purchase Period'),
('manual', 'Manual')],
string='Depreciation Dates', default='manual',
readonly=True, states={'draft': [('readonly', False)]}, required=True,
help='The way to compute the date of the first depreciation.\n'
' * Based on last day of purchase period: The depreciation dates will be based on the last day of the purchase month or the purchase year (depending on the periodicity of the depreciations).\n'
' * Based on purchase date: The depreciation dates will be based on the purchase date.\n')
first_depreciation_manual_date = fields.Date(
string='First Depreciation Date',
readonly=True, states={'draft': [('readonly', False)]},
help='Note that this date does not alter the computation of the first journal entry in case of prorata temporis assets. It simply changes its accounting date'
)
@api.multi
def unlink(self):
for asset in self:
if asset.state in ['open', 'close']:
raise UserError(_('You cannot delete a document that is in %s state.') % (asset.state,))
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.model
def _cron_generate_entries(self):
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
if sequence == undone_dotation_number:
amount = residual_amount
else:
if self.method == 'linear':
amount = amount_to_depr / (undone_dotation_number - len(posted_depreciation_line_ids))
if self.prorata:
amount = amount_to_depr / self.method_number
if sequence == 1:
date = self.date
if self.method_period % 12 != 0:
month_days = calendar.monthrange(date.year, date.month)[1]
days = month_days - date.day + 1
amount = (amount_to_depr / self.method_number) / month_days * days
else:
days = (self.company_id.compute_fiscalyear_dates(date)['date_to'] - date).days + 1
amount = (amount_to_depr / self.method_number) / total_days * days
elif self.method == 'degressive':
amount = residual_amount * self.method_progress_factor
if self.prorata:
if sequence == 1:
date = self.date
if self.method_period % 12 != 0:
month_days = calendar.monthrange(date.year, date.month)[1]
days = month_days - date.day + 1
amount = (residual_amount * self.method_progress_factor) / month_days * days
else:
days = (self.company_id.compute_fiscalyear_dates(date)['date_to'] - date).days + 1
amount = (residual_amount * self.method_progress_factor) / total_days * days
return amount
def _compute_board_undone_dotation_nb(self, depreciation_date, total_days):
undone_dotation_number = self.method_number
if self.method_time == 'end':
end_date = self.method_end
undone_dotation_number = 0
while depreciation_date <= end_date:
depreciation_date = date(depreciation_date.year, depreciation_date.month, depreciation_date.day) + relativedelta(months=+self.method_period)
undone_dotation_number += 1
if self.prorata:
undone_dotation_number += 1
return undone_dotation_number
@api.multi
def compute_depreciation_board(self):
self.ensure_one()
posted_depreciation_line_ids = self.depreciation_line_ids.filtered(lambda x: x.move_check).sorted(key=lambda l: l.depreciation_date)
unposted_depreciation_line_ids = self.depreciation_line_ids.filtered(lambda x: not x.move_check)
# Remove old unposted depreciation lines. We cannot use unlink() with One2many field
commands = [(2, line_id.id, False) for line_id in unposted_depreciation_line_ids]
if self.value_residual != 0.0:
amount_to_depr = residual_amount = self.value_residual
# if we already have some previous validated entries, starting date is last entry + method period
if posted_depreciation_line_ids and posted_depreciation_line_ids[-1].depreciation_date:
last_depreciation_date = fields.Date.from_string(posted_depreciation_line_ids[-1].depreciation_date)
depreciation_date = last_depreciation_date + relativedelta(months=+self.method_period)
else:
# depreciation_date computed from the purchase date
depreciation_date = self.date
if self.date_first_depreciation == 'last_day_period':
# depreciation_date = the last day of the month
depreciation_date = depreciation_date + relativedelta(day=31)
# ... or fiscalyear depending the number of period
if self.method_period == 12:
depreciation_date = depreciation_date + relativedelta(month=self.company_id.fiscalyear_last_month)
depreciation_date = depreciation_date + relativedelta(day=self.company_id.fiscalyear_last_day)
if depreciation_date < self.date:
depreciation_date = depreciation_date + relativedelta(years=1)
elif self.first_depreciation_manual_date and self.first_depreciation_manual_date != self.date:
# depreciation_date set manually from the 'first_depreciation_manual_date' field
depreciation_date = self.first_depreciation_manual_date
total_days = (depreciation_date.year % 4) and 365 or 366
month_day = depreciation_date.day
undone_dotation_number = self._compute_board_undone_dotation_nb(depreciation_date, total_days)
for x in range(len(posted_depreciation_line_ids), undone_dotation_number):
sequence = x + 1
amount = self._compute_board_amount(sequence, residual_amount, amount_to_depr, undone_dotation_number, posted_depreciation_line_ids, total_days, depreciation_date)
amount = self.currency_id.round(amount)
if float_is_zero(amount, precision_rounding=self.currency_id.rounding):
continue
residual_amount -= amount
vals = {
'amount': amount,
'asset_id': self.id,
'sequence': sequence,
'name': (self.code or '') + '/' + str(sequence),
'remaining_value': residual_amount,
'depreciated_value': self.value - (self.salvage_value + residual_amount),
'depreciation_date': depreciation_date,
}
commands.append((0, False, vals))
depreciation_date = depreciation_date + relativedelta(months=+self.method_period)
if month_day > 28 and self.date_first_depreciation == 'manual':
max_day_in_month = calendar.monthrange(depreciation_date.year, depreciation_date.month)[1]
depreciation_date = depreciation_date.replace(day=min(max_day_in_month, month_day))
# datetime doesn't take into account that the number of days is not the same for each month
if not self.prorata and self.method_period % 12 != 0 and self.date_first_depreciation == 'last_day_period':
max_day_in_month = calendar.monthrange(depreciation_date.year, depreciation_date.month)[1]
depreciation_date = depreciation_date.replace(day=max_day_in_month)
self.write({'depreciation_line_ids': commands})
return True
@api.multi
def validate(self):
self.write({'state': 'open'})
fields = [
'method',
'method_number',
'method_period',
'method_end',
'method_progress_factor',
'method_time',
'salvage_value',
'invoice_id',
]
ref_tracked_fields = self.env['account.asset.asset'].fields_get(fields)
for asset in self:
tracked_fields = ref_tracked_fields.copy()
if asset.method == 'linear':
del(tracked_fields['method_progress_factor'])
if asset.method_time != 'end':
del(tracked_fields['method_end'])
else:
del(tracked_fields['method_number'])
dummy, tracking_value_ids = asset._message_track(tracked_fields, dict.fromkeys(fields))
asset.message_post(subject=_('Asset created'), tracking_value_ids=tracking_value_ids)
def _return_disposal_view(self, move_ids):
name = _('Disposal Move')
view_mode = 'form'
if len(move_ids) > 1:
name = _('Disposal Moves')
view_mode = 'tree,form'
return {
'name': name,
'view_type': 'form',
'view_mode': view_mode,
'res_model': 'account.move',
'type': 'ir.actions.act_window',
'target': 'current',
'res_id': move_ids[0],
}
def _get_disposal_moves(self):
move_ids = []
for asset in self:
unposted_depreciation_line_ids = asset.depreciation_line_ids.filtered(lambda x: not x.move_check)
if unposted_depreciation_line_ids:
old_values = {
'method_end': asset.method_end,
'method_number': asset.method_number,
}
# Remove all unposted depr. lines
commands = [(2, line_id.id, False) for line_id in unposted_depreciation_line_ids]
# Create a new depr. line with the residual amount and post it
sequence = len(asset.depreciation_line_ids) - len(unposted_depreciation_line_ids) + 1
today = fields.Datetime.today()
vals = {
'amount': asset.value_residual,
'asset_id': asset.id,
'sequence': sequence,
'name': (asset.code or '') + '/' + str(sequence),
'remaining_value': 0,
'depreciated_value': asset.value - asset.salvage_value, # the asset is completely depreciated
'depreciation_date': today,
}
commands.append((0, False, vals))
asset.write({'depreciation_line_ids': commands, 'method_end': today, 'method_number': sequence})
tracked_fields = self.env['account.asset.asset'].fields_get(['method_number', 'method_end'])
changes, tracking_value_ids = asset._message_track(tracked_fields, old_values)
if changes:
asset.message_post(subject=_('Asset sold or disposed. Accounting entry awaiting for validation.'), tracking_value_ids=tracking_value_ids)
move_ids += asset.depreciation_line_ids[-1].create_move(post_move=False)
return move_ids
@api.multi
def set_to_close(self):
move_ids = self._get_disposal_moves()
if move_ids:
return self._return_disposal_view(move_ids)
# Fallback, as if we just clicked on the smartbutton
return self.open_entries()
@api.multi
def set_to_draft(self):
self.write({'state': 'draft'})
@api.one
@api.depends('value', 'salvage_value', 'depreciation_line_ids.move_check', 'depreciation_line_ids.amount')
def _amount_residual(self):
total_amount = 0.0
for line in self.depreciation_line_ids:
if line.move_check:
total_amount += line.amount
self.value_residual = self.value - total_amount - self.salvage_value
@api.onchange('company_id')
def onchange_company_id(self):
self.currency_id = self.company_id.currency_id.id
@api.multi
@api.onchange('date_first_depreciation')
def onchange_date_first_depreciation(self):
for record in self:
if record.date_first_depreciation == 'manual':
record.first_depreciation_manual_date = record.date
@api.multi
@api.depends('depreciation_line_ids.move_id')
def _entry_count(self):
for asset in self:
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')
def _check_prorata(self):
if self.prorata and self.method_time != 'number':
raise ValidationError(_('Prorata temporis can be applied only for the "number of depreciations" time method.'))
@api.onchange('category_id')
def onchange_category_id(self):
vals = self.onchange_category_id_values(self.category_id.id)
# We cannot use 'write' on an object that doesn't exist yet
if vals:
for k, v in vals['value'].items():
setattr(self, k, v)
def onchange_category_id_values(self, category_id):
if category_id:
category = self.env['account.asset.category'].browse(category_id)
return {
'value': {
'method': category.method,
'method_number': category.method_number,
'method_time': category.method_time,
'method_period': category.method_period,
'method_progress_factor': category.method_progress_factor,
'method_end': category.method_end,
'prorata': category.prorata,
'date_first_depreciation': category.date_first_depreciation,
'account_analytic_id': category.account_analytic_id.id,
'analytic_tag_ids': [(6, 0, category.analytic_tag_ids.ids)],
}
}
@api.onchange('method_time')
def onchange_method_time(self):
if self.method_time != 'number':
self.prorata = False
@api.multi
def copy_data(self, default=None):
if default is None:
default = {}
default['name'] = self.name + _(' (copy)')
return super(AccountAssetAsset, self).copy_data(default)
@api.multi
def _compute_entries(self, date, group_entries=False):
depreciation_ids = self.env['account.asset.depreciation.line'].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
def create(self, vals):
asset = super(AccountAssetAsset, self.with_context(mail_create_nolog=True)).create(vals)
asset.sudo().compute_depreciation_board()
return asset
@api.multi
def write(self, vals):
res = super(AccountAssetAsset, self).write(vals)
if 'depreciation_line_ids' not in vals and 'state' not in vals:
for rec in self:
rec.compute_depreciation_board()
return res
@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',
'view_mode': 'tree,form',
'res_model': 'account.move',
'view_id': False,
'type': 'ir.actions.act_window',
'domain': [('id', 'in', move_ids)],
}
class AccountAssetDepreciationLine(models.Model):
_name = 'account.asset.depreciation.line'
_description = 'Asset Depreciation Line'
name = fields.Char(string='Depreciation Name', required=True, index=True)
sequence = fields.Integer(required=True)
asset_id = fields.Many2one('account.asset.asset', string='Asset', required=True, ondelete='cascade')
parent_state = fields.Selection(related='asset_id.state', string='State of Asset', readonly=False)
amount = fields.Float(string='Current Depreciation', digits=0, required=True)
remaining_value = fields.Float(string='Next Period Depreciation', digits=0, required=True)
depreciated_value = fields.Float(string='Cumulative Depreciation', required=True)
depreciation_date = fields.Date('Depreciation Date', index=True)
move_id = fields.Many2one('account.move', string='Depreciation Entry')
move_check = fields.Boolean(compute='_get_move_check', string='Linked', track_visibility='always', store=True)
move_posted_check = fields.Boolean(compute='_get_move_posted_check', string='Posted', track_visibility='always', store=True)
@api.multi
@api.depends('move_id')
def _get_move_check(self):
for line in self:
line.move_check = bool(line.move_id)
@api.multi
@api.depends('move_id.state')
def _get_move_posted_check(self):
for line in self:
line.move_posted_check = True if line.move_id and line.move_id.state == 'posted' else False
@api.multi
def create_move(self, post_move=True):
created_moves = self.env['account.move']
for line in self:
if line.move_id:
raise UserError(_('This depreciation is already linked to a journal entry. Please post or delete it.'))
move_vals = self._prepare_move(line)
move = self.env['account.move'].create(move_vals)
line.write({'move_id': move.id, 'move_check': True})
created_moves |= move
if post_move and created_moves:
created_moves.filtered(lambda m: any(m.asset_depreciation_ids.mapped('asset_id.category_id.open_asset'))).post()
return [x.id for x in created_moves]
def _prepare_move(self, line):
category_id = line.asset_id.category_id
account_analytic_id = line.asset_id.account_analytic_id
analytic_tag_ids = line.asset_id.analytic_tag_ids
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
prec = company_currency.decimal_places
amount = current_currency._convert(
line.amount, company_currency, line.asset_id.company_id, depreciation_date)
asset_name = line.asset_id.name + ' (%s/%s)' % (line.sequence, len(line.asset_id.depreciation_line_ids))
move_line_1 = {
'name': asset_name,
'account_id': category_id.account_depreciation_id.id,
'debit': 0.0 if float_compare(amount, 0.0, precision_digits=prec) > 0 else -amount,
'credit': amount if float_compare(amount, 0.0, precision_digits=prec) > 0 else 0.0,
'partner_id': line.asset_id.partner_id.id,
'analytic_account_id': account_analytic_id.id if category_id.type == 'sale' else False,
'analytic_tag_ids': [(6, 0, analytic_tag_ids.ids)] 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 - 1.0 * line.amount or 0.0,
}
move_line_2 = {
'name': asset_name,
'account_id': category_id.account_depreciation_expense_id.id,
'credit': 0.0 if float_compare(amount, 0.0, precision_digits=prec) > 0 else -amount,
'debit': amount if float_compare(amount, 0.0, precision_digits=prec) > 0 else 0.0,
'partner_id': line.asset_id.partner_id.id,
'analytic_account_id': account_analytic_id.id if category_id.type == 'purchase' else False,
'analytic_tag_ids': [(6, 0, analytic_tag_ids.ids)] 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 line.amount or 0.0,
}
move_vals = {
'ref': line.asset_id.code,
'date': depreciation_date or False,
'journal_id': category_id.journal_id.id,
'line_ids': [(0, 0, move_line_1), (0, 0, move_line_2)],
}
return move_vals
def _prepare_move_grouped(self):
asset_id = self[0].asset_id
category_id = asset_id.category_id # we can suppose that all lines have the same category
account_analytic_id = asset_id.account_analytic_id
analytic_tag_ids = asset_id.analytic_tag_ids
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
company = line.asset_id.company_id
amount += current_currency._convert(line.amount, company_currency, company, fields.Date.today())
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': account_analytic_id.id if category_id.type == 'sale' else False,
'analytic_tag_ids': [(6, 0, analytic_tag_ids.ids)] 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': account_analytic_id.id if category_id.type == 'purchase' else False,
'analytic_tag_ids': [(6, 0, analytic_tag_ids.ids)] 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)],
}
return move_vals
@api.multi
def create_grouped_move(self, post_move=True):
if not self.exists():
return []
created_moves = self.env['account.move']
move = self.env['account.move'].create(self._prepare_move_grouped())
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:
line.log_message_when_posted()
asset = line.asset_id
if asset.currency_id.is_zero(asset.value_residual):
asset.message_post(body=_("Document closed."))
asset.write({'state': 'close'})
@api.multi
def log_message_when_posted(self):
def _format_message(message_description, tracked_values):
message = ''
if message_description:
message = '<span>%s</span>' % message_description
for name, values in tracked_values.items():
message += '<div> &nbsp; &nbsp; &bull; <b>%s</b>: ' % name
message += '%s</div>' % values
return message
for line in self:
if line.move_id and line.move_id.state == 'draft':
partner_name = line.asset_id.partner_id.name
currency_name = line.asset_id.currency_id.name
msg_values = {_('Currency'): currency_name, _('Amount'): line.amount}
if partner_name:
msg_values[_('Partner')] = partner_name
msg = _format_message(_('Depreciation line posted.'), msg_values)
line.asset_id.message_post(body=msg)
@api.multi
def unlink(self):
for record in self:
if record.move_check:
if record.asset_id.category_id.type == 'purchase':
msg = _("You cannot delete posted depreciation lines.")
else:
msg = _("You cannot delete posted installment lines.")
raise UserError(msg)
return super(AccountAssetDepreciationLine, self).unlink()
@@ -1,126 +0,0 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from datetime import datetime
from dateutil.relativedelta import relativedelta
from odoo import api, fields, models, _
from odoo.exceptions import UserError
from odoo.addons import decimal_precision as dp
class AccountInvoice(models.Model):
_inherit = 'account.invoice'
@api.model
def _refund_cleanup_lines(self, lines):
result = super(AccountInvoice, self)._refund_cleanup_lines(lines)
for i, line in enumerate(lines):
for name, field in line._fields.items():
if name == 'asset_category_id':
result[i][2][name] = False
break
return result
@api.multi
def action_cancel(self):
res = super(AccountInvoice, self).action_cancel()
self.env['account.asset.asset'].sudo().search([('invoice_id', 'in', self.ids)]).write({'active': False})
return res
@api.multi
def action_move_create(self):
result = super(AccountInvoice, self).action_move_create()
for inv in self:
context = dict(self.env.context)
# Within the context of an invoice,
# this default value is for the type of the invoice, not the type of the asset.
# This has to be cleaned from the context before creating the asset,
# otherwise it tries to create the asset with the type of the invoice.
context.pop('default_type', None)
inv.invoice_line_ids.with_context(context).asset_create()
return result
class AccountInvoiceLine(models.Model):
_inherit = 'account.invoice.line'
asset_category_id = fields.Many2one('account.asset.category', string='Asset Category')
asset_start_date = fields.Date(string='Asset Start Date', compute='_get_asset_date', readonly=True, store=True)
asset_end_date = fields.Date(string='Asset End Date', compute='_get_asset_date', readonly=True, store=True)
asset_mrr = fields.Float(string='Monthly Recurring Revenue', compute='_get_asset_date', readonly=True, digits=dp.get_precision('Account'), store=True)
@api.one
@api.depends('asset_category_id', 'invoice_id.date_invoice')
def _get_asset_date(self):
self.asset_mrr = 0
self.asset_start_date = False
self.asset_end_date = False
cat = self.asset_category_id
if cat:
if cat.method_number == 0 or cat.method_period == 0:
raise UserError(_('The number of depreciations or the period length of your asset category cannot be 0.'))
months = cat.method_number * cat.method_period
if self.invoice_id.type in ['out_invoice', 'out_refund']:
self.asset_mrr = self.price_subtotal_signed / months
if self.invoice_id.date_invoice:
start_date = self.invoice_id.date_invoice.replace(day=1)
end_date = (start_date + relativedelta(months=months, days=-1))
self.asset_start_date = start_date
self.asset_end_date = end_date
@api.one
def asset_create(self):
if self.asset_category_id:
vals = {
'name': self.name,
'code': self.invoice_id.number or False,
'category_id': self.asset_category_id.id,
'value': self.price_subtotal_signed,
'partner_id': self.invoice_id.partner_id.id,
'company_id': self.invoice_id.company_id.id,
'currency_id': self.invoice_id.company_currency_id.id,
'date': self.invoice_id.date_invoice,
'invoice_id': self.invoice_id.id,
}
changed_vals = self.env['account.asset.asset'].onchange_category_id_values(vals['category_id'])
vals.update(changed_vals['value'])
asset = self.env['account.asset.asset'].create(vals)
if self.asset_category_id.open_asset:
asset.validate()
return True
@api.onchange('asset_category_id')
def onchange_asset_category_id(self):
if self.invoice_id.type == 'out_invoice' and self.asset_category_id:
self.account_id = self.asset_category_id.account_asset_id.id
elif self.invoice_id.type == 'in_invoice' and self.asset_category_id:
self.account_id = self.asset_category_id.account_asset_id.id
@api.onchange('uom_id')
def _onchange_uom_id(self):
result = super(AccountInvoiceLine, self)._onchange_uom_id()
self.onchange_asset_category_id()
return result
@api.onchange('product_id')
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
def _set_additional_fields(self, invoice):
if not self.asset_category_id:
if invoice.type == 'out_invoice':
self.asset_category_id = self.product_id.product_tmpl_id.deferred_revenue_category_id.id
elif invoice.type == 'in_invoice':
self.asset_category_id = self.product_id.product_tmpl_id.asset_category_id.id
self.onchange_asset_category_id()
super(AccountInvoiceLine, self)._set_additional_fields(invoice)
def get_invoice_line_account(self, type, product, fpos, company):
return product.asset_category_id.account_asset_id or super(AccountInvoiceLine, self).get_invoice_line_account(type, product, fpos, company)
-20
View File
@@ -1,20 +0,0 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import api, fields, models
class ProductTemplate(models.Model):
_inherit = 'product.template'
asset_category_id = fields.Many2one('account.asset.category', string='Asset Type', company_dependent=True, ondelete="restrict")
deferred_revenue_category_id = fields.Many2one('account.asset.category', string='Deferred Revenue Type', company_dependent=True, ondelete="restrict")
@api.multi
def _get_asset_accounts(self):
res = super(ProductTemplate, self)._get_asset_accounts()
if self.asset_category_id:
res['stock_input'] = self.property_account_expense_id
if self.deferred_revenue_category_id:
res['stock_output'] = self.property_account_income_id
return res
-4
View File
@@ -1,4 +0,0 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import account_asset_report
@@ -1,68 +0,0 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import api, fields, models, tools
class AssetAssetReport(models.Model):
_name = "asset.asset.report"
_description = "Assets Analysis"
_auto = False
name = fields.Char(string='Year', required=False, readonly=True)
date = fields.Date(readonly=True)
depreciation_date = fields.Date(string='Depreciation Date', readonly=True)
asset_id = fields.Many2one('account.asset.asset', string='Asset', readonly=True)
asset_category_id = fields.Many2one('account.asset.category', string='Asset category', readonly=True)
partner_id = fields.Many2one('res.partner', string='Partner', readonly=True)
state = fields.Selection([('draft', 'Draft'), ('open', 'Running'), ('close', 'Close')], string='Status', readonly=True)
depreciation_value = fields.Float(string='Amount of Depreciation Lines', readonly=True)
installment_value = fields.Float(string='Amount of Installment Lines', readonly=True)
move_check = fields.Boolean(string='Posted', readonly=True)
installment_nbr = fields.Integer(string='Installment Count', readonly=True)
depreciation_nbr = fields.Integer(string='Depreciation Count', readonly=True)
gross_value = fields.Float(string='Gross Amount', readonly=True)
posted_value = fields.Float(string='Posted Amount', readonly=True)
unposted_value = fields.Float(string='Unposted Amount', readonly=True)
company_id = fields.Many2one('res.company', string='Company', readonly=True)
@api.model_cr
def init(self):
tools.drop_view_if_exists(self._cr, 'asset_asset_report')
self._cr.execute("""
create or replace view asset_asset_report as (
select
min(dl.id) as id,
dl.name as name,
dl.depreciation_date as depreciation_date,
a.date as date,
(CASE WHEN dlmin.id = min(dl.id)
THEN a.value
ELSE 0
END) as gross_value,
dl.amount as depreciation_value,
dl.amount as installment_value,
(CASE WHEN dl.move_check
THEN dl.amount
ELSE 0
END) as posted_value,
(CASE WHEN NOT dl.move_check
THEN dl.amount
ELSE 0
END) as unposted_value,
dl.asset_id as asset_id,
dl.move_check as move_check,
a.category_id as asset_category_id,
a.partner_id as partner_id,
a.state as state,
count(dl.*) as installment_nbr,
count(dl.*) as depreciation_nbr,
a.company_id as company_id
from account_asset_depreciation_line dl
left join account_asset_asset a on (dl.asset_id=a.id)
left join (select min(d.id) as id,ac.id as ac_id from account_asset_depreciation_line as d inner join account_asset_asset as ac ON (ac.id=d.asset_id) group by ac_id) as dlmin on dlmin.ac_id=a.id
where a.active is true
group by
dl.amount,dl.asset_id,dl.depreciation_date,dl.name,
a.date, dl.move_check, a.state, a.category_id, a.partner_id, a.company_id,
a.value, a.id, a.salvage_value, dlmin.id
)""")
@@ -1,79 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record model="ir.ui.view" id="action_account_asset_report_pivot">
<field name="name">asset.asset.report.pivot</field>
<field name="model">asset.asset.report</field>
<field name="arch" type="xml">
<pivot string="Assets Analysis" disable_linking="True">
<field name="asset_category_id" type="row"/>
<field name="gross_value" type="measure"/>
<field name="unposted_value" type="measure"/>
</pivot>
</field>
</record>
<record model="ir.ui.view" id="action_account_asset_report_graph">
<field name="name">asset.asset.report.graph</field>
<field name="model">asset.asset.report</field>
<field name="arch" type="xml">
<graph string="Assets Analysis">
<field name="asset_category_id" type="row"/>
<field name="gross_value" type="measure"/>
<field name="unposted_value" type="measure"/>
</graph>
</field>
</record>
<record id="view_asset_asset_report_search" model="ir.ui.view">
<field name="name">asset.asset.report.search</field>
<field name="model">asset.asset.report</field>
<field name="arch" type="xml">
<search string="Assets Analysis">
<field name="date"/>
<field name="depreciation_date"/>
<filter string="Draft" name="draft" domain="[('state','=','draft')]" help="Assets in draft state"/>
<filter string="Running" name="running" domain="[('state','=','open')]" help="Assets in running state"/>
<separator/>
<filter string="Posted" name="posted" domain="[('move_check','=',True)]" help="Posted depreciation lines" context="{'unposted_value_visible': 0}"/>
<field name="asset_id"/>
<field name="asset_category_id"/>
<group expand="0" string="Extended Filters...">
<field name="partner_id" filter_domain="[('partner_id','child_of',self)]"/>
<field name="company_id" groups="base.group_multi_company"/>
</group>
<group expand="1" string="Group By">
<filter string="Asset" name="asset" context="{'group_by':'asset_id'}"/>
<filter string="Asset Category" name="asset_category" context="{'group_by':'asset_category_id'}"/>
<filter string="Company" name="company" context="{'group_by':'company_id'}" groups="base.group_multi_company"/>
<separator/>
<filter string="Purchase Month" name="purchase_month" help="Date of asset purchase"
context="{'group_by':'date:month'}"/>
<filter string="Depreciation Month" name="deprecation_month" help="Date of depreciation"
context="{'group_by':'depreciation_date:month'}"/>
</group>
</search>
</field>
</record>
<record model="ir.actions.act_window" id="action_asset_asset_report">
<field name="name">Assets Analysis</field>
<field name="res_model">asset.asset.report</field>
<field name="view_type">form</field>
<field name="view_mode">graph,pivot</field>
<field name="search_view_id" ref="view_asset_asset_report_search"/>
<field name="domain">[('asset_category_id.type', '=', 'purchase')]</field>
<field name="context">{}</field> <!-- force empty -->
<field name="help" type="html">
<p class="o_view_nocontent_empty_folder">
No content
</p><p>
From this report, you can have an overview on all depreciations. The
search bar can also be used to personalize your assets depreciation reporting.
</p>
</field>
</record>
<menuitem name="Assets" action="action_asset_asset_report"
id="menu_action_asset_asset_report"
parent="account.account_reports_management_menu" sequence="21"/>
</odoo>
@@ -1,19 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="1">
<record id="account_asset_category_multi_company_rule" model="ir.rule">
<field name="name">Account Asset Category multi-company</field>
<field ref="model_account_asset_category" name="model_id"/>
<field eval="True" name="global"/>
<field name="domain_force">['|',('company_id','=',False),('company_id','child_of',[user.company_id.id])]</field>
</record>
<record id="account_asset_asset_multi_company_rule" model="ir.rule">
<field name="name">Account Asset multi-company</field>
<field ref="model_account_asset_asset" name="model_id"/>
<field eval="True" name="global"/>
<field name="domain_force">['|',('company_id','=',False),('company_id','child_of',[user.company_id.id])]</field>
</record>
</data>
</odoo>
@@ -1,12 +0,0 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_account_asset_category,account.asset.category,model_account_asset_category,account.group_account_user,1,0,0,0
access_account_asset_asset,account.asset.asset,model_account_asset_asset,account.group_account_user,1,0,0,0
access_account_asset_category_manager,account.asset.category,model_account_asset_category,account.group_account_manager,1,1,1,1
access_account_asset_asset_manager,account.asset.asset,model_account_asset_asset,account.group_account_manager,1,1,1,1
access_account_asset_depreciation_line,account.asset.depreciation.line,model_account_asset_depreciation_line,account.group_account_user,1,0,0,0
access_account_asset_depreciation_line_manager,account.asset.depreciation.line,model_account_asset_depreciation_line,account.group_account_manager,1,1,1,1
access_asset_asset_report,asset.asset.report,model_asset_asset_report,account.group_account_user,1,0,0,0
access_asset_asset_report_manager,asset.asset.report,model_asset_asset_report,account.group_account_manager,1,1,1,1
access_account_asset_category_invoicing_payment,account.asset.category,model_account_asset_category,account.group_account_invoice,1,0,0,0
access_account_asset_asset_invoicing_payment,account.asset.asset,model_account_asset_asset,account.group_account_invoice,1,0,1,0
access_account_asset_depreciation_line_invoicing_payment,account.asset.depreciation.line,model_account_asset_depreciation_line,account.group_account_invoice,1,0,1,0
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_account_asset_category account.asset.category model_account_asset_category account.group_account_user 1 0 0 0
3 access_account_asset_asset account.asset.asset model_account_asset_asset account.group_account_user 1 0 0 0
4 access_account_asset_category_manager account.asset.category model_account_asset_category account.group_account_manager 1 1 1 1
5 access_account_asset_asset_manager account.asset.asset model_account_asset_asset account.group_account_manager 1 1 1 1
6 access_account_asset_depreciation_line account.asset.depreciation.line model_account_asset_depreciation_line account.group_account_user 1 0 0 0
7 access_account_asset_depreciation_line_manager account.asset.depreciation.line model_account_asset_depreciation_line account.group_account_manager 1 1 1 1
8 access_asset_asset_report asset.asset.report model_asset_asset_report account.group_account_user 1 0 0 0
9 access_asset_asset_report_manager asset.asset.report model_asset_asset_report account.group_account_manager 1 1 1 1
10 access_account_asset_category_invoicing_payment account.asset.category model_account_asset_category account.group_account_invoice 1 0 0 0
11 access_account_asset_asset_invoicing_payment account.asset.asset model_account_asset_asset account.group_account_invoice 1 0 1 0
12 access_account_asset_depreciation_line_invoicing_payment account.asset.depreciation.line model_account_asset_depreciation_line account.group_account_invoice 1 0 1 0
Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="70" height="70" viewBox="0 0 70 70"><defs><path id="a" d="M4 0h61c4 0 5 1 5 5v60c0 4-1 5-5 5H4c-3 0-4-1-4-5V5c0-4 1-5 4-5z"/><linearGradient id="c" x1="100%" x2="0%" y1="0%" y2="100%"><stop offset="0%" stop-color="#DA956B"/><stop offset="100%" stop-color="#CC7039"/></linearGradient></defs><g fill="none" fill-rule="evenodd"><mask id="b" fill="#fff"><use xlink:href="#a"/></mask><g mask="url(#b)"><path fill="url(#c)" d="M0 0H70V70H0z"/><path fill="#FFF" fill-opacity=".383" d="M4 1h61c2.667 0 4.333.667 5 2V0H0v3c.667-1.333 2-2 4-2z"/><path fill="#393939" d="M4 69c-2 0-4-.146-4-4.09V40.738L18.16 24H52l1 2.045v6.137l-10.585 11.3 10.05 4.09L37.071 69H4z" opacity=".324"/><path fill="#000" fill-opacity=".383" d="M4 69h61c2.667 0 4.333-1 5-3v4H0v-4c.667 2 2 3 4 3z"/><path fill="#000" d="M53 42.084v5.66c0 1.837-1.111 3.34-3.556 3.34h-28c-2.466 0-4.444-1.503-4.444-3.34V28.34c0-1.837 1.978-3.34 4.444-3.34H49c2.444 0 4 1.368 4 3.205v5.88H37c-2.667 0-4 1.857-4 3.957 0 2.1 1.333 4.042 4 4.042h16zm-15-1.39a2.656 2.656 0 0 1-2.667-2.652A2.656 2.656 0 0 1 38 35.39a2.656 2.656 0 0 1 2.667 2.653A2.656 2.656 0 0 1 38 40.695z" opacity=".3"/><path fill="#FFF" d="M53 40.084v5.66c0 1.837-1.111 3.34-3.556 3.34h-28c-2.466 0-4.444-1.503-4.444-3.34V26.34c0-1.837 1.978-3.34 4.444-3.34H49c2.444 0 4 1.368 4 3.205v5.88H37c-2.667 0-4 1.857-4 3.957 0 2.1 1.333 4.042 4 4.042h16zm-15-1.39a2.656 2.656 0 0 1-2.667-2.652A2.656 2.656 0 0 1 38 33.39a2.656 2.656 0 0 1 2.667 2.653A2.656 2.656 0 0 1 38 38.695z"/></g></g></svg>

Before

Width:  |  Height:  |  Size: 1.6 KiB

@@ -1,87 +0,0 @@
odoo.define('account_asset.widget', function(require) {
"use strict";
/**
* The purpose of this widget is to shows a toggle button on depreciation and
* installment lines for posted/unposted line. When clicked, it calls the method
* create_move on the object account.asset.depreciation.line.
* Note that this widget can only work on the account.asset.depreciation.line
* model as some of its fields are harcoded.
*/
var AbstractField = require('web.AbstractField');
var core = require('web.core');
var registry = require('web.field_registry');
var _t = core._t;
var AccountAssetWidget = AbstractField.extend({
events: _.extend({}, AbstractField.prototype.events, {
'click': '_onClick',
}),
description: "",
//--------------------------------------------------------------------------
// Public
//--------------------------------------------------------------------------
/**
* @override
*/
isSet: function () {
return true; // it should always be displayed, whatever its value
},
//--------------------------------------------------------------------------
// Private
//--------------------------------------------------------------------------
/**
* @override
* @private
*/
_render: function () {
var className = '';
var disabled = true;
var title;
if (this.recordData.move_posted_check) {
className = 'o_is_posted';
title = _t('Posted');
} else if (this.recordData.move_check) {
className = 'o_unposted';
title = _t('Accounting entries waiting for manual verification');
} else {
disabled = false;
title = _t('Unposted');
}
var $button = $('<button/>', {
type: 'button',
title: title,
disabled: disabled,
}).addClass('btn btn-link fa fa-circle o_deprec_lines_toggler ' + className);
this.$el.html($button);
},
//--------------------------------------------------------------------------
// Handlers
//--------------------------------------------------------------------------
/**
* @private
* @param {MouseEvent} event
*/
_onClick: function (event) {
event.stopPropagation();
this.trigger_up('button_clicked', {
attrs: {
name: 'create_move',
type: 'object',
},
record: this.record,
});
},
});
registry.add("deprec_lines_toggler", AccountAssetWidget);
});
@@ -1,9 +0,0 @@
.o_web_client .o_deprec_lines_toggler {
color: theme-color('danger');
&.o_is_posted {
color: theme-color('success');
}
&.o_unposted {
color: theme-color('warning');
}
}
@@ -1,168 +0,0 @@
odoo.define('account_asset.widget_tests', function (require) {
"use strict";
var FormView = require('web.FormView');
var testUtils = require('web.test_utils');
var createView = testUtils.createView;
QUnit.module('fields', {}, function () {
QUnit.module('account_asset', {
beforeEach: function () {
this.data = {
asset: {
fields: {
display_name: { string: "Displayed name", type: "char" },
line_ids: {
string: "Lines",
type: "one2many",
relation: 'line',
relation_field: 'asset_id',
},
},
records: [{
id: 1,
display_name: "asset name",
line_ids: [1, 2, 3, 4],
}],
},
line: {
fields: {
move_check: {string: "Move Check", type: 'boolean'},
move_posted_check: {string: "Move Posted Check", type: 'boolean'},
asset_id: {string: "Asset", type: 'many2one', relation: 'asset'},
},
records: [{
id: 1,
move_check: true,
move_posted_check: true,
}, {
id: 2,
move_check: false,
move_posted_check: true,
}, {
id: 3,
move_check: true,
move_posted_check: false,
}, {
id: 4,
move_check: false,
move_posted_check: false,
}],
},
};
}
});
QUnit.test('basic rendering', function (assert) {
assert.expect(18);
var form = createView({
View: FormView,
model: 'asset',
data: this.data,
arch: '<form string="Asset">' +
'<sheet>' +
'<field name="display_name"/>' +
'<field name="line_ids">' +
'<tree>' +
'<field name="move_check" widget="deprec_lines_toggler"/>' +
'<field name="move_posted_check" invisible="1"/>' +
'</tree>' +
'</field>' +
'</sheet>' +
'</form>',
res_id: 1,
});
// check the header
assert.strictEqual(form.$('thead th').text(), "", "toggler column should have no title");
// check the classnames
assert.ok(form.$('.o_deprec_lines_toggler_cell:nth(0) button').hasClass('o_is_posted'),
"first line toggler should have classname 'o_is_posted'");
assert.ok(!form.$('.o_deprec_lines_toggler_cell:nth(0) button').hasClass('o_unposted'),
"first line toggler should not have classname 'o_unposted'");
assert.ok(form.$('.o_deprec_lines_toggler_cell:nth(1) button').hasClass('o_is_posted'),
"second line toggler should have classname 'o_is_posted'");
assert.ok(!form.$('.o_deprec_lines_toggler_cell:nth(1) button').hasClass('o_unposted'),
"second line toggler should not have classname 'o_unposted'");
assert.ok(!form.$('.o_deprec_lines_toggler_cell:nth(2) button').hasClass('o_is_posted'),
"third line toggler should not have classname 'o_is_posted'");
assert.ok(form.$('.o_deprec_lines_toggler_cell:nth(2) button').hasClass('o_unposted'),
"third line toggler should have classname 'o_unposted'");
assert.ok(!form.$('.o_deprec_lines_toggler_cell:nth(3) button').hasClass('o_is_posted'),
"fourth line toggler should not have classname 'o_is_posted'");
assert.ok(!form.$('.o_deprec_lines_toggler_cell:nth(3) button').hasClass('o_unposted'),
"fourth line toggler should not have classname 'o_unposted'");
// check the titles
assert.strictEqual(form.$('.o_deprec_lines_toggler_cell:nth(0) button').attr('title'),
'Posted', "first line toggler should have correct title");
assert.strictEqual(form.$('.o_deprec_lines_toggler_cell:nth(1) button').attr('title'),
'Posted', "second line toggler should have correct title");
assert.strictEqual(form.$('.o_deprec_lines_toggler_cell:nth(2) button').attr('title'),
'Accounting entries waiting for manual verification',
"third line toggler should have correct title");
assert.strictEqual(form.$('.o_deprec_lines_toggler_cell:nth(3) button').attr('title'),
'Unposted', "fourth line toggler should have correct title");
// check disabled property
assert.ok(form.$('.o_deprec_lines_toggler_cell:nth(0) button').attr('disabled'),
"first line toggle should be disabled");
assert.ok(form.$('.o_deprec_lines_toggler_cell:nth(1) button').attr('disabled'),
"second line toggle should be disabled");
assert.ok(form.$('.o_deprec_lines_toggler_cell:nth(2) button').attr('disabled'),
"third line toggle should be disabled");
assert.ok(!form.$('.o_deprec_lines_toggler_cell:nth(3) button').attr('disabled'),
"fourth line toggle should not be disabled");
// check the visibility: the widget should always be visible, regardless its value
assert.strictEqual(form.$('.o_deprec_lines_toggler:visible').length, 4,
"all togglers should be visible");
form.destroy();
});
QUnit.test('click events are correctly triggered', function (assert) {
assert.expect(2);
var form = createView({
View: FormView,
model: 'asset',
data: this.data,
arch: '<form string="Asset">' +
'<sheet>' +
'<field name="display_name"/>' +
'<field name="line_ids">' +
'<tree>' +
'<field name="move_check" widget="deprec_lines_toggler"/>' +
'<field name="move_posted_check" invisible="1"/>' +
'</tree>' +
'</field>' +
'</sheet>' +
'</form>',
res_id: 1,
intercepts: {
execute_action: function (event) {
var data = event.data;
assert.strictEqual(data.env.model, 'line', "should have correct model");
assert.strictEqual(data.action_data.name, 'create_move',
"should call correct method");
},
}
});
// click on last row toggler
form.$('.o_deprec_lines_toggler_cell:nth(3) button').click();
form.destroy();
});
});
});
@@ -1,66 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="1">
<!--
Asset Category Demo
-->
<record id="account_asset_category_fixedassets_test0" model="account.asset.category">
<field name="account_depreciation_id" ref="xfa"/>
<field name="account_depreciation_expense_id" ref="a_expense"/>
<field name="account_asset_id" ref="xfa"/>
<field name="journal_id" ref="expenses_journal"/>
<field name="name">Hardware - 3 Years</field>
<field name="method_number">3</field>
<field name="method_period">12</field>
<field name="open_asset">True</field>
</record>
<record id="account_asset_category_fixedassets_test1" model="account.asset.category">
<field name="account_depreciation_id" ref="xfa"/>
<field name="account_depreciation_expense_id" ref="a_expense"/>
<field name="account_asset_id" ref="xfa"/>
<field name="journal_id" ref="expenses_journal"/>
<field name="name">Cars - 5 Years</field>
<field name="method_number">5</field>
<field name="method_period">12</field>
</record>
<!--
Assets Demo
-->
<record id="account_asset_asset_vehicles_test0" model="account.asset.asset">
<field eval="2000.0" name="salvage_value"/>
<field name="state">open</field>
<field eval="12" name="method_period"/>
<field eval="5" name="method_number"/>
<field name="name">CEO's Car</field>
<field eval="12000.0" name="value"/>
<field name="category_id" ref="account_asset_category_fixedassets_test0"/>
</record>
<record id="account_asset_asset_cab_test0" model="account.asset.asset">
<field name="method_end" eval="(DateTime.now().replace(month=8, day=11) + timedelta(days=3*365)).strftime('%Y-%m-%d')"/>
<field eval="0.0" name="salvage_value"/>
<field name="method_time">end</field>
<field name="name">V6 Engine and 10 inches tires</field>
<field eval="2800.0" name="value"/>
<field name="category_id" ref="account_asset_category_fixedassets_test0"/>
</record>
<record id="account_asset_asset_office_test0" model="account.asset.asset">
<field eval="1" name="prorata"/>
<field eval="100000.0" name="salvage_value"/>
<field name="state">open</field>
<field eval="12" name="method_period"/>
<field eval="3" name="method_number"/>
<field name="date" eval="time.strftime('%Y-01-01')"/>
<field name="name">Office</field>
<field eval="500000.0" name="value"/>
<field name="category_id" ref="account_asset_category_fixedassets_test0"/>
</record>
</data>
</odoo>
-4
View File
@@ -1,4 +0,0 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import test_account_asset
@@ -1,66 +0,0 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import tools
from odoo.tests import common
from odoo.modules.module import get_resource_path
class TestAccountAsset(common.TransactionCase):
def _load(self, module, *args):
tools.convert_file(self.cr, 'account_asset',
get_resource_path(module, *args),
{}, 'init', False, 'test', self.registry._assertion_report)
def test_00_account_asset_asset(self):
self._load('account', 'test', 'account_minimal_test.xml')
self._load('account_asset', 'test', 'account_asset_demo_test.xml')
# In order to test the process of Account Asset, I perform a action to confirm Account Asset.
self.browse_ref("account_asset.account_asset_asset_vehicles_test0").validate()
# I check Asset is now in Open state.
self.assertEqual(self.browse_ref("account_asset.account_asset_asset_vehicles_test0").state, 'open',
'Asset should be in Open state')
# I compute depreciation lines for asset of CEOs Car.
self.browse_ref("account_asset.account_asset_asset_vehicles_test0").compute_depreciation_board()
value = self.browse_ref("account_asset.account_asset_asset_vehicles_test0")
self.assertEqual(value.method_number, len(value.depreciation_line_ids),
'Depreciation lines not created correctly')
# I create account move for all depreciation lines.
ids = self.env['account.asset.depreciation.line'].search([('asset_id', '=', self.ref('account_asset.account_asset_asset_vehicles_test0'))])
for line in ids:
line.create_move()
# I check the move line is created.
asset = self.env['account.asset.asset'].browse([self.ref("account_asset.account_asset_asset_vehicles_test0")])[0]
self.assertEqual(len(asset.depreciation_line_ids), asset.entry_count,
'Move lines not created correctly')
# I Check that After creating all the moves of depreciation lines the state "Close".
self.assertEqual(self.browse_ref("account_asset.account_asset_asset_vehicles_test0").state, 'close',
'State of asset should be close')
# WIZARD
# I create a record to change the duration of asset for calculating depreciation.
account_asset_asset_office0 = self.browse_ref('account_asset.account_asset_asset_office_test0')
asset_modify_number_0 = self.env['asset.modify'].create({
'name': 'Test reason',
'method_number': 10.0,
}).with_context({'active_id': account_asset_asset_office0.id})
# I change the duration.
asset_modify_number_0.with_context({'active_id': account_asset_asset_office0.id}).modify()
# I check the proper depreciation lines created.
self.assertEqual(account_asset_asset_office0.method_number, len(account_asset_asset_office0.depreciation_line_ids))
# I compute a asset on period.
context = {
"active_ids": [self.ref("account_asset.menu_asset_depreciation_confirmation_wizard")],
"active_id": self.ref('account_asset.menu_asset_depreciation_confirmation_wizard'),
'type': 'sale'
}
asset_compute_period_0 = self.env['asset.depreciation.confirmation.wizard'].create({})
asset_compute_period_0.with_context(context).asset_compute()
@@ -1,15 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template id="assets_backend" name="account assets" inherit_id="web.assets_backend">
<xpath expr="." position="inside">
<link rel="stylesheet" type="text/scss" href="/account_asset/static/src/scss/account_asset.scss"/>
<script type="text/javascript" src="/account_asset/static/src/js/account_asset.js"></script>
</xpath>
</template>
<template id="qunit_suite" name="account_asset_tests" inherit_id="web.qunit_suite">
<xpath expr="//t[@t-set='head']" position="inside">
<script type="text/javascript" src="/account_asset/static/tests/account_asset_tests.js"></script>
</xpath>
</template>
</odoo>
@@ -1,345 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!--
Asset Category
-->
<record model="ir.ui.view" id="view_account_asset_category_form">
<field name="name">account.asset.category.form</field>
<field name="model">account.asset.category</field>
<field name="arch" type="xml">
<form string="Asset category">
<sheet>
<group>
<div class="oe_title">
<label for="name" string="Asset Type" class="oe_edit_only" attrs="{'invisible': [('type','!=','purchase')]}"/>
<label for="name" string="Deferred Revenue Type" class="oe_edit_only" attrs="{'invisible': [('type','==','purchase')]}"/>
<h1>
<field name="name" placeholder="e.g. Computers"/>
</h1>
</div>
<group>
<field name="type" attrs="{'invisible': 1}"/>
<field name="company_id" options="{'no_create': True}" groups="base.group_multi_company"/>
</group>
<group string="Journal Entries">
<field name="journal_id"/>
<div>
<label for="account_asset_id"
attrs="{'invisible': [('type','!=','purchase')]}"
style="font-weight: bold" class="o_light_label"/>
<label for="account_asset_id" string="Deferred Revenue Account"
attrs="{'invisible': [('type','!=','sale')]}"
style="font-weight: bold" class="o_light_label"/>
</div>
<field name="account_asset_id" nolabel="1" attrs="{'invisible': [('type','=', False)]}"/>
<div>
<label for="account_depreciation_id"
attrs="{'invisible': [('type','!=','purchase')]}"
style="font-weight: bold" class="o_light_label"/>
<label for="account_depreciation_id" string="Recognition Income Account"
attrs="{'invisible': [('type','!=','sale')]}"
style="font-weight: bold" class="o_light_label"/>
</div>
<field name="account_depreciation_id" nolabel="1"/>
<div>
<label for="account_depreciation_expense_id"
attrs="{'invisible': [('type','!=','purchase')]}"
style="font-weight: bold" class="o_light_label"/>
<label for="account_depreciation_expense_id" string="Recognition Account"
attrs="{'invisible': [('type','!=','sale')]}"
style="font-weight: bold" class="o_light_label"/>
</div>
<field name="account_depreciation_expense_id" nolabel="1"/>
<field name="account_analytic_id" groups="analytic.group_analytic_accounting"/>
<field name="analytic_tag_ids" groups="analytic.group_analytic_accounting" widget="many2many_tags"/>
</group>
<group string="Periodicity">
<field name="method_time" string="Time Method Based On" widget="radio" attrs="{'invisible': [('type','!=','purchase')]}"/>
<field name="method_number" string="Number of Entries" attrs="{'invisible':['|',('method_time','!=','number'),'&amp;',('type','=', False)], 'required':[('method_time','=','number')]}"/>
<label for="method_period" string="One Entry Every"/>
<div>
<field name="method_period" nolabel="1" attrs="{'invisible': [('type','=', False)]}" class="oe_inline"/>
months
</div>
<field name="method_end" attrs="{'required': [('method_time','=','end')], 'invisible':[('method_time','!=','end')]}"/>
</group>
<group string="Additional Options">
<field name="open_asset"/>
<field name="group_entries"/>
<field name="date_first_depreciation"/>
</group>
<group attrs="{'invisible': [('type','=','sale')]}" string="Depreciation Method">
<field name="method" widget="radio"/>
<field name="method_progress_factor" attrs="{'invisible':[('method','=','linear')], 'required':[('method','=','degressive')]}"/>
<field name="prorata" attrs="{'invisible': [('method_time','=','end')]}"/>
</group>
</group>
</sheet>
</form>
</field>
</record>
<record id="view_account_asset_asset_category_kanban" model="ir.ui.view">
<field name="name">account.asset.category.kanban</field>
<field name="model">account.asset.category</field>
<field name="arch" type="xml">
<kanban class="o_kanban_mobile">
<field name="name"/>
<field name="journal_id"/>
<field name="method"/>
<templates>
<t t-name="kanban-box">
<div t-attf-class="oe_kanban_card oe_kanban_global_click">
<div class="row mb4">
<div class="col-6">
<strong><span><t t-esc="record.name.value"/></span></strong>
</div>
<div class="col-6 text-right">
<span class="badge badge-pill"><strong><t t-esc="record.method.value"/></strong></span>
</div>
</div>
<div> <t t-esc="record.journal_id.value"/></div>
</div>
</t>
</templates>
</kanban>
</field>
</record>
<record model="ir.ui.view" id="view_account_asset_category_tree">
<field name="name">account.asset.category.tree</field>
<field name="model">account.asset.category</field>
<field name="arch" type="xml">
<tree string="Asset category">
<field name="name"/>
<field name="journal_id"/>
<field name="method"/>
<field name="company_id" groups="base.group_multi_company"/>
</tree>
</field>
</record>
<record model="ir.ui.view" id="view_account_asset_category_search">
<field name="name">account.asset.category.search</field>
<field name="model">account.asset.category</field>
<field name="arch" type="xml">
<search string="Search Asset Category">
<filter string="Sales" name="sales" domain="[('type','=', 'sale')]" help="Deferred Revenues"/>
<filter string="Purchase" name="purchase" domain="[('type','=', 'purchase')]" help="Assets"/>
<field name="name" string="Category"/>
<field name="journal_id"/>
<group expand="0" string="Group By...">
<filter string="Type" name="type" domain="[]" context="{'group_by':'type'}"/>
</group>
</search>
</field>
</record>
<record model="ir.ui.view" id="view_account_asset_asset_form">
<field name="name">account.asset.asset.form</field>
<field name="model">account.asset.asset</field>
<field name="arch" type="xml">
<form string="Asset">
<header>
<button name="validate" states="draft" string="Confirm" type="object" class="oe_highlight"/>
<button type="object" name="compute_depreciation_board" string="Compute Depreciation" states="draft"/>
<button name="set_to_close" states="open" string="Sell or Dispose" type="object" class="oe_highlight"/>
<button name="set_to_draft" string="Set to Draft" type="object" attrs="{'invisible': ['|', ('entry_count', '!=', 0), ('state', '!=', 'open')]}"/>
<button name="%(action_asset_modify)d" states="open" string="Modify Depreciation" type="action"/>
<field name="state" widget="statusbar" statusbar_visible="draft,open"/>
</header>
<sheet>
<div class="oe_button_box" name="button_box">
<button class="oe_stat_button" name="open_entries" type="object" icon="fa-pencil">
<field string="Items" name="entry_count" widget="statinfo" />
</button>
</div>
<div class="oe_title">
<label for="name" class="oe_edit_only"/>
<h1>
<field name="name" placeholder="e.g. Laptop iBook"/>
</h1>
</div>
<group>
<group>
<field name="category_id" string="Asset Category" domain="[('type', '=', 'purchase')]" context="{'default_type': 'purchase'}" help="Category of asset"/>
<field name="code"/>
<field name="date" help="Date of asset"/>
<field name="date_first_depreciation"/>
<field name="first_depreciation_manual_date"
attrs="{'invisible': [('date_first_depreciation', '!=', 'manual')], 'required': [('date_first_depreciation', '=', 'manual')]}"/>
<field name="type" invisible="1"/>
<field name="account_analytic_id" groups="analytic.group_analytic_accounting" />
</group>
<group>
<field name="currency_id" groups="base.group_multi_currency"/>
<field name="company_id" options="{'no_create': True}" groups="base.group_multi_company"/>
<field name="value" widget="monetary" options="{'currency_field': 'currency_id'}" help="Gross value of asset"/>
<field name="salvage_value" widget="monetary" options="{'currency_field': 'currency_id'}" attrs="{'invisible': [('type','=','sale')]}"/>
<field name="value_residual" widget="monetary" options="{'currency_field': 'currency_id'}"/>
<field name="partner_id" string="Vendor" domain="[('supplier', '=', True)]"/>
<field name="invoice_id" string="Invoice" options="{'no_create': True}"/>
<field name="analytic_tag_ids" groups="analytic.group_analytic_accounting" widget="many2many_tags"/>
</group>
</group>
<notebook colspan="4">
<page string="Depreciation Board">
<field name="depreciation_line_ids" mode="tree" options="{'reload_whole_on_button': true}">
<tree string="Depreciation Lines" decoration-info="(move_check == False)" create="false">
<field name="depreciation_date"/>
<field name="amount" widget="monetary" string="Depreciation"/>
<field name="depreciated_value" readonly="1"/>
<field name="remaining_value" readonly="1" widget="monetary" string="Residual"/>
<field name="move_check" widget="deprec_lines_toggler" attrs="{'invisible': [('parent_state', '!=', 'open')]}"/>
<field name="move_posted_check" invisible="1"/>
<field name="parent_state" invisible="1"/>
</tree>
<form string="Depreciation Lines" create="false">
<group>
<group>
<field name="parent_state" invisible="1"/>
<field name="name"/>
<field name="sequence"/>
<field name="move_id"/>
<field name="move_check"/>
<field name="parent_state" invisible="1"/>
</group>
<group>
<field name="amount" widget="monetary"/>
<field name="depreciation_date"/>
<field name="depreciated_value"/>
<field name="remaining_value"/>
</group>
</group>
</form>
</field>
</page>
<page string="Depreciation Information">
<group>
<field name="method" widget="radio" attrs="{'invisible': [('type','=','sale')]}"/>
<field name="method_progress_factor" attrs="{'invisible':[('method','=','linear')], 'required':[('method','=','degressive')]}"/>
<field name="method_time" string="Time Method Based On" widget="radio" attrs="{'invisible': [('type','!=','purchase')]}"/>
<field name="prorata" attrs="{'invisible': [('method_time','=','end')]}"/>
</group>
<group>
<field name="method_number" attrs="{'invisible':[('method_time','=','end')], 'required':[('method_time','=','number')]}"/>
<field name="method_period"/>
<field name="method_end" attrs="{'required': [('method_time','=','end')], 'invisible':[('method_time','=','number')]}"/>
</group>
</page>
</notebook>
</sheet>
<div class="oe_chatter">
<field name="message_follower_ids" widget="mail_followers"/>
<field name="message_ids" widget="mail_thread"/>
</div>
</form>
</field>
</record>
<record id="view_account_asset_asset_kanban" model="ir.ui.view">
<field name="name">account.asset.asset.kanban</field>
<field name="model">account.asset.asset</field>
<field name="arch" type="xml">
<kanban class="o_kanban_mobile">
<field name="name"/>
<field name="category_id"/>
<field name="date"/>
<field name="state"/>
<templates>
<t t-name="kanban-box">
<div t-attf-class="oe_kanban_global_click">
<div class="row mb4">
<div class="col-6">
<strong><span><t t-esc="record.name.value"/></span></strong>
</div>
<div class="col-6 text-right">
<strong><t t-esc="record.date.value"/></strong>
</div>
</div>
<div class="row">
<div class="col-6 text-muted">
<span><t t-esc="record.category_id.value"/></span>
</div>
<div class="col-6">
<span class="float-right text-right">
<field name="state" widget="kanban_label_selection" options="{'classes': {'draft': 'primary', 'open': 'success', 'close': 'default'}}"/>
</span>
</div>
</div>
</div>
</t>
</templates>
</kanban>
</field>
</record>
<record model="ir.ui.view" id="view_account_asset_asset_purchase_tree">
<field name="name">account.asset.asset.purchase.tree</field>
<field name="model">account.asset.asset</field>
<field name="arch" type="xml">
<tree string="Assets" decoration-info="(state == 'draft')" decoration-muted="(state == 'close')">
<field name="name"/>
<field name="category_id" string="Asset Category"/>
<field name="date"/>
<field name="partner_id" string="Vendor"/>
<field name="value"/>
<field name="value_residual" widget="monetary"/>
<field name="currency_id" groups="base.group_multi_currency"/>
<field name="company_id" groups="base.group_multi_company"/>
<field name="state"/>
</tree>
</field>
</record>
<record id="view_account_asset_search" model="ir.ui.view">
<field name="name">account.asset.asset.search</field>
<field name="model">account.asset.asset</field>
<field name="arch" type="xml">
<search string="Asset Account">
<field name="name" string="Asset"/>
<field name="date"/>
<filter string="Current" name="current" domain="[('state','in', ('draft','open'))]" help="Assets in draft and open states"/>
<filter string="Closed" name="closed" domain="[('state','=', 'close')]" help="Assets in closed state"/>
<field name="category_id" string="Asset Category"/>
<field name="partner_id" filter_domain="[('partner_id','child_of',self)]"/>
<group expand="0" string="Group By...">
<filter string="Date" name="month" domain="[]" context="{'group_by':'date'}"/>
<filter string="Asset Category" name="category" domain="[]" context="{'group_by':'category_id'}"/>
</group>
</search>
</field>
</record>
<record model="ir.actions.act_window" id="action_account_asset_asset_form">
<field name="name">Assets</field>
<field name="res_model">account.asset.asset</field>
<field name="view_type">form</field>
<field name="view_mode">tree,kanban,form</field>
<field name="view_id" ref="view_account_asset_asset_purchase_tree"/>
<field name="domain">[('category_id.type', '=', 'purchase')]</field>
</record>
<menuitem parent="account.menu_finance_entries_management" id="menu_action_account_asset_asset_form" action="action_account_asset_asset_form" sequence="101" groups="account.group_account_manager"/>
<!-- Configuration -->
<menuitem id="menu_finance_config_assets" name="Assets and Revenues" parent="account.menu_finance_configuration" sequence="25"/>
<record model="ir.actions.act_window" id="action_account_asset_asset_list_normal_purchase">
<field name="name">Asset Types</field>
<field name="res_model">account.asset.category</field>
<field name="domain">[('type', '=', 'purchase')]</field>
<field name="view_type">form</field>
<field name="view_mode">tree,kanban,form</field>
<field name="context">{'default_type': 'purchase'}</field>
</record>
<menuitem parent="account.account_management_menu" id="menu_action_account_asset_asset_list_normal_purchase" action="action_account_asset_asset_list_normal_purchase" sequence="6"/>
</odoo>
@@ -1,16 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- Add "Asset Category" to supplier invoices -->
<record model="ir.ui.view" id="view_invoice_asset_category">
<field name="name">account.invoice.supplier.form</field>
<field name="model">account.invoice</field>
<field name="inherit_id" ref="account.invoice_supplier_form"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='invoice_line_ids']/tree/field[@name='account_id']" position="before">
<field string="Asset Category" name="asset_category_id" domain="[('type','=','purchase')]" context="{'default_type':'purchase'}"/>
</xpath>
</field>
</record>
</odoo>
@@ -1,17 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- Product Template -->
<record id="view_product_template_form_inherit" model="ir.ui.view">
<field name="name">Product Template (form)</field>
<field name="model">product.template</field>
<field name="inherit_id" ref="account.product_template_form_view"/>
<field name="arch" type="xml">
<field name="property_account_expense_id" position="after">
<field name="asset_category_id"
domain="[('type', '=', 'purchase')]"
context="{'default_type': 'purchase'}"
groups="account.group_account_user"/>
</field>
</field>
</record>
</odoo>
@@ -1,19 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="res_config_settings_view_form" model="ir.ui.view">
<field name="name">res.config.settings.view.form.inherit.account.asset</field>
<field name="model">res.config.settings</field>
<field name="inherit_id" ref="account.res_config_settings_view_form"/>
<field name="arch" type="xml">
<div id="msg_account_asset" position="replace">
<div class="content-group" attrs="{'invisible': [('module_account_asset', '=', False)]}">
<div class="mt16">
<button name="%(account_asset.action_account_asset_asset_list_normal_purchase)d" icon="fa-arrow-right" type="action" string="Asset Types" class="btn-link"/>
</div>
</div>
</div>
</field>
</record>
</odoo>
-5
View File
@@ -1,5 +0,0 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import asset_depreciation_confirmation_wizard
from . import asset_modify
@@ -1,27 +0,0 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import api, fields, models, _
class AssetDepreciationConfirmationWizard(models.TransientModel):
_name = "asset.depreciation.confirmation.wizard"
_description = "Assets Depreciation Confirmation wizard"
date = fields.Date('Account Date', required=True, help="Choose the period for which you want to automatically post the depreciation lines of running assets", default=fields.Date.context_today)
@api.multi
def asset_compute(self):
self.ensure_one()
context = self._context
created_move_ids = self.env['account.asset.asset'].compute_generated_entries(self.date, asset_type=context.get('asset_type'))
return {
'name': _('Created Asset Moves') if context.get('asset_type') == 'purchase' else _('Created Revenue Moves'),
'view_type': 'form',
'view_mode': 'tree,form',
'res_model': 'account.move',
'view_id': False,
'domain': "[('id','in',[" + ','.join(str(id) for id in created_move_ids) + "])]",
'type': 'ir.actions.act_window',
}
@@ -1,39 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="view_asset_depreciation_confirmation_wizard" model="ir.ui.view">
<field name="name">asset.depreciation.confirmation.wizard</field>
<field name="model">asset.depreciation.confirmation.wizard</field>
<field name="arch" type="xml">
<form string="Compute Asset">
<div>
<p>
This wizard will post installment/depreciation lines for the selected month.<br/>
This will generate journal entries for all related installment lines on this period of asset/revenue recognition as well.
</p>
</div>
<group>
<field name="date"/>
</group>
<footer>
<button string="Generate Entries" name="asset_compute" type="object" class="btn-primary"/>
<button string="Cancel" class="btn-secondary" special="cancel"/>
</footer>
</form>
</field>
</record>
<record id="action_asset_depreciation_confirmation_wizard" model="ir.actions.act_window">
<field name="name">Post Depreciation Lines</field>
<field name="res_model">asset.depreciation.confirmation.wizard</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="view_id" ref="view_asset_depreciation_confirmation_wizard"/>
<field name="target">new</field>
<field name="context">{'asset_type': 'purchase'}</field>
</record>
<menuitem name="Generate Assets Entries" action="action_asset_depreciation_confirmation_wizard"
id="menu_asset_depreciation_confirmation_wizard"
parent="account.menu_finance_entries_generate_entries" sequence="111" groups="account.group_account_manager"/>
</odoo>

Some files were not shown because too many files have changed in this diff Show More