[MOV] account_asset: move to enterprise
This commit is contained in:
@@ -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
|
||||
@@ -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
@@ -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
|
||||
@@ -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> • <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)
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
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>
|
||||
@@ -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'),'&',('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>
|
||||
@@ -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
Reference in New Issue
Block a user