[ADD] Add Fiscal year concept and Asset report and misc
This commit is contained in:
parent
488bb3d8e6
commit
1b2971d5b8
@ -22,14 +22,20 @@ Keeps track of depreciations, and creates corresponding journal entries.
|
||||
'security/account_asset_security.xml',
|
||||
'security/ir.model.access.csv',
|
||||
'wizard/asset_depreciation_confirmation_wizard_views.xml',
|
||||
'data/account_asset_data.xml',
|
||||
'wizard/asset_modify_views.xml',
|
||||
'wizard/sale_asset_wizard_view.xml',
|
||||
'wizard/scrap_asset_wizard_view.xml',
|
||||
'wizard/asset_depreciation_summary_wizard_view.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',
|
||||
'report/report_paperformat.xml',
|
||||
'report/asset_reports.xml',
|
||||
'report/asset_depreciation_report_template.xml',
|
||||
'report/account_asset_report_views.xml'
|
||||
],
|
||||
'qweb': [
|
||||
"static/src/xml/account_asset_template.xml",
|
||||
|
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding='UTF-8'?>
|
||||
<flectra>
|
||||
<record id="account_asset_cron" model="ir.cron">
|
||||
<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>
|
||||
|
@ -49,7 +49,7 @@
|
||||
}
|
||||
self._update('account.asset.asset', 'account_asset', vals, 'account_asset_asset_cab0')
|
||||
vals = {
|
||||
'prorata': 1,
|
||||
'prorata': 'purchase_date',
|
||||
'salvage_value': 100000.0,
|
||||
'state': 'open',
|
||||
'method_period': 12,
|
||||
@ -60,3 +60,26 @@
|
||||
'category_id': ref('account_asset_category_fixedassets0'),
|
||||
}
|
||||
self._update('account.asset.asset', 'account_asset', vals, 'account_asset_asset_office0')
|
||||
product_id = ref('product.consu_delivery_03')
|
||||
vals = {
|
||||
'journal_id': journal_id,
|
||||
'name': 'Electronics',
|
||||
'method_number': 6,
|
||||
'account_asset_id': xfa_account_id,
|
||||
'account_depreciation_id': xfa_account_id,
|
||||
'account_depreciation_expense_id': expense_account_id,
|
||||
}
|
||||
self._update('account.asset.category', 'account_asset', vals, 'account_asset_category_electronics')
|
||||
vals = {
|
||||
'prorata': 'fiscal_year',
|
||||
'product_id': product_id,
|
||||
'salvage_value': 1000.0,
|
||||
'state': 'open',
|
||||
'method_period': 12,
|
||||
'method_number': 6,
|
||||
'date': time.strftime('%Y-01-01'),
|
||||
'name': 'Basic Computer',
|
||||
'value': 23500.0,
|
||||
'category_id': ref('account_asset_category_electronics'),
|
||||
}
|
||||
self._update('account.asset.asset', 'account_asset', vals, 'account_asset_asset_electronics')
|
@ -8,6 +8,7 @@ class AccountMove(models.Model):
|
||||
_inherit = 'account.move'
|
||||
|
||||
asset_depreciation_ids = fields.One2many('account.asset.depreciation.line', 'move_id', string='Assets Depreciation Lines', ondelete="restrict")
|
||||
asset_id = fields.Many2one('account.asset.asset', string="Asset")
|
||||
|
||||
@api.multi
|
||||
def button_cancel(self):
|
||||
@ -22,3 +23,9 @@ class AccountMove(models.Model):
|
||||
for depreciation_line in move.asset_depreciation_ids:
|
||||
depreciation_line.post_lines_and_close_asset()
|
||||
return super(AccountMove, self).post()
|
||||
|
||||
|
||||
class AccountMoveLine(models.Model):
|
||||
_inherit = 'account.move.line'
|
||||
|
||||
asset_id = fields.Many2one(related='move_id.asset_id', string="Asset")
|
||||
|
@ -30,15 +30,20 @@ class AccountAssetCategory(models.Model):
|
||||
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',
|
||||
method_time = fields.Selection([('number', 'Number of Depreciations'), ('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')
|
||||
prorata = fields.Selection([('first_january', 'First of January'),
|
||||
('purchase_date', 'From the Purchase Date'),
|
||||
('fiscal_year', 'Fiscal Year')],
|
||||
help='Indicates that the first depreciation entry for this asset have to be done from the purchase date or first of January or fiscal year')
|
||||
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')
|
||||
asset_ids = fields.One2many('account.asset.asset', 'category_id',
|
||||
string='Asset Line')
|
||||
|
||||
@api.onchange('account_asset_id')
|
||||
def onchange_account_asset(self):
|
||||
@ -50,7 +55,7 @@ class AccountAssetCategory(models.Model):
|
||||
@api.onchange('type')
|
||||
def onchange_type(self):
|
||||
if self.type == 'sale':
|
||||
self.prorata = True
|
||||
self.prorata = 'purchase_date'
|
||||
self.method_period = 1
|
||||
else:
|
||||
self.method_period = 12
|
||||
@ -58,7 +63,12 @@ class AccountAssetCategory(models.Model):
|
||||
@api.onchange('method_time')
|
||||
def _onchange_method_time(self):
|
||||
if self.method_time != 'number':
|
||||
self.prorata = False
|
||||
self.prorata = 'first_january'
|
||||
|
||||
@api.onchange('prorata')
|
||||
def onchange_prorata(self):
|
||||
if self.prorata == 'fiscal_year':
|
||||
self.method_period = 12
|
||||
|
||||
|
||||
class AccountAssetAsset(models.Model):
|
||||
@ -83,6 +93,12 @@ class AccountAssetAsset(models.Model):
|
||||
"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)]})
|
||||
product_id = fields.Many2one('product.product', string='Product',
|
||||
track_visibility='onchange')
|
||||
invoice_count = fields.Integer(string="Invoice",
|
||||
compute="count_invoice")
|
||||
remaining_asset_value = fields.Float(string="Remaining Asset Value",
|
||||
compute="get_remaining_value")
|
||||
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")
|
||||
@ -92,18 +108,73 @@ class AccountAssetAsset(models.Model):
|
||||
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"
|
||||
method_time = fields.Selection([('number', 'Number of Entries'), ('end', 'Ending Date')], string='Time Method', required=True, readonly=True, default='number', states={'draft': [('readonly', False)]}, track_visibility='onchange',
|
||||
help="Choose the method to use to compute the dates and number of depreciation lines.\n"
|
||||
" * Number of Depreciation lines: Fix the number of depreciation lines 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 purchase date instead of the first January / Start date of fiscal year')
|
||||
sale_date = fields.Date(string='Sale Date')
|
||||
prorata = fields.Selection([('first_january', 'First of January'),
|
||||
('purchase_date', 'From the Purchase Date'),
|
||||
('fiscal_year', 'Fiscal Year')],
|
||||
readonly=True, states={'draft': [('readonly', False)]},
|
||||
help='Indicates that the first depreciation entry for this asset have to be done from the purchase date or first of January or 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)
|
||||
|
||||
@api.onchange('prorata')
|
||||
def onchange_prorata(self):
|
||||
if self.prorata == 'fiscal_year':
|
||||
self.method_period = 12
|
||||
|
||||
@api.multi
|
||||
def get_remaining_value(self):
|
||||
for record in self:
|
||||
posted_line_id = record.depreciation_line_ids.search(
|
||||
[('move_check', '=', True), ('asset_id', '=', record.id)],
|
||||
limit=1, order='id desc')
|
||||
record.remaining_asset_value = posted_line_id.remaining_value
|
||||
|
||||
@api.onchange('product_id')
|
||||
def on_product_id_change(self):
|
||||
self.category_id = self.product_id.asset_category_id
|
||||
self.value = self.product_id.list_price
|
||||
|
||||
@api.depends('prorata')
|
||||
def get_fiscal_date(self, date):
|
||||
if self.prorata == 'fiscal_year':
|
||||
last_day = self.company_id.fiscalyear_last_day
|
||||
last_month = self.company_id.fiscalyear_last_month
|
||||
if date:
|
||||
date = datetime.strptime(date, DF).date()
|
||||
else:
|
||||
date = datetime.now()
|
||||
if date.month <= 3 and date.day < 31:
|
||||
year = date.year
|
||||
else:
|
||||
year = date.year + 1
|
||||
date = date.replace(month=last_month, day=last_day, year=year)
|
||||
return datetime.strftime(date, '%Y-%m-%d')
|
||||
|
||||
@api.multi
|
||||
def count_invoice(self):
|
||||
for self_obj in self:
|
||||
count = self.env['account.invoice'].search_count(
|
||||
[('asset_id', '=', self_obj.id)])
|
||||
self_obj.invoice_count = count
|
||||
|
||||
def redirect_to_invoice(self):
|
||||
return {
|
||||
'name': (_('Invoices')),
|
||||
'type': 'ir.actions.act_window',
|
||||
'view_type': 'form',
|
||||
'view_mode': 'tree,form',
|
||||
'res_model': 'account.invoice',
|
||||
'domain': [('asset_id', '=', self.id)]
|
||||
}
|
||||
|
||||
@api.multi
|
||||
def unlink(self):
|
||||
for asset in self:
|
||||
@ -156,8 +227,11 @@ class AccountAssetAsset(models.Model):
|
||||
amount = residual_amount
|
||||
else:
|
||||
if self.method == 'linear':
|
||||
# Manage last line with remaining amount
|
||||
if self.prorata == 'fiscal_year':
|
||||
undone_dotation_number = undone_dotation_number - 1
|
||||
amount = amount_to_depr / (undone_dotation_number - len(posted_depreciation_line_ids))
|
||||
if self.prorata:
|
||||
if self.prorata == 'purchase_date':
|
||||
amount = amount_to_depr / self.method_number
|
||||
if sequence == 1:
|
||||
if self.method_period % 12 != 0:
|
||||
@ -168,9 +242,14 @@ class AccountAssetAsset(models.Model):
|
||||
else:
|
||||
days = (self.company_id.compute_fiscalyear_dates(depreciation_date)['date_to'] - depreciation_date).days + 1
|
||||
amount = (amount_to_depr / self.method_number) / total_days * days
|
||||
elif self.prorata == 'fiscal_year' and sequence == 1:
|
||||
fiscal_date = datetime.strptime(self.date or fields.Datetime.today(), '%Y-%m-%d')
|
||||
days = (self.company_id.compute_fiscalyear_dates(depreciation_date)['date_to'] - fiscal_date.date()).days
|
||||
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 self.prorata == 'purchase_date':
|
||||
if sequence == 1:
|
||||
if self.method_period % 12 != 0:
|
||||
date = datetime.strptime(self.date, '%Y-%m-%d')
|
||||
@ -180,6 +259,10 @@ class AccountAssetAsset(models.Model):
|
||||
else:
|
||||
days = (self.company_id.compute_fiscalyear_dates(depreciation_date)['date_to'] - depreciation_date).days + 1
|
||||
amount = (residual_amount * self.method_progress_factor) / total_days * days
|
||||
elif self.prorata == 'fiscal_year' and sequence == 1:
|
||||
fiscal_date = datetime.strptime(self.date or fields.Datetime.today(), '%Y-%m-%d')
|
||||
days = (self.company_id.compute_fiscalyear_dates(depreciation_date)['date_to'] - fiscal_date.date()).days
|
||||
amount = (residual_amount * self.method_progress_factor) / total_days * days
|
||||
return amount
|
||||
|
||||
def _compute_board_undone_dotation_nb(self, depreciation_date, total_days):
|
||||
@ -190,7 +273,7 @@ class AccountAssetAsset(models.Model):
|
||||
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:
|
||||
if self.prorata in ['purchase_date', 'fiscal_year']:
|
||||
undone_dotation_number += 1
|
||||
return undone_dotation_number
|
||||
|
||||
@ -206,13 +289,20 @@ class AccountAssetAsset(models.Model):
|
||||
|
||||
if self.value_residual != 0.0:
|
||||
amount_to_depr = residual_amount = self.value_residual
|
||||
if self.prorata:
|
||||
if self.prorata == 'purchase_date':
|
||||
# if we already have some previous validated entries, starting date is last entry + method perio
|
||||
if posted_depreciation_line_ids and posted_depreciation_line_ids[-1].depreciation_date:
|
||||
last_depreciation_date = datetime.strptime(posted_depreciation_line_ids[-1].depreciation_date, DF).date()
|
||||
depreciation_date = last_depreciation_date + relativedelta(months=+self.method_period)
|
||||
else:
|
||||
depreciation_date = datetime.strptime(self._get_last_depreciation_date()[self.id], DF).date()
|
||||
elif self.prorata == 'fiscal_year':
|
||||
if posted_depreciation_line_ids and posted_depreciation_line_ids[-1].depreciation_date:
|
||||
last_depreciation_date = datetime.strptime(posted_depreciation_line_ids[-1].depreciation_date, DF).date()
|
||||
depreciation_date = last_depreciation_date + relativedelta(months=+self.method_period)
|
||||
else:
|
||||
fiscal_date = self.get_fiscal_date(self.date)
|
||||
depreciation_date = datetime.strptime(fiscal_date, DF).date()
|
||||
else:
|
||||
# depreciation_date = 1st of January of purchase year if annual valuation, 1st of
|
||||
# purchase month in other cases
|
||||
@ -366,7 +456,7 @@ class AccountAssetAsset(models.Model):
|
||||
@api.one
|
||||
@api.constrains('prorata', 'method_time')
|
||||
def _check_prorata(self):
|
||||
if self.prorata and self.method_time != 'number':
|
||||
if self.prorata == 'purchase_date' and self.method_time != 'number':
|
||||
raise ValidationError(_('Prorata temporis can be applied only for time method "number of depreciations".'))
|
||||
|
||||
@api.onchange('category_id')
|
||||
@ -395,7 +485,7 @@ class AccountAssetAsset(models.Model):
|
||||
@api.onchange('method_time')
|
||||
def onchange_method_time(self):
|
||||
if self.method_time != 'number':
|
||||
self.prorata = False
|
||||
self.prorata = 'first_january'
|
||||
|
||||
@api.multi
|
||||
def copy_data(self, default=None):
|
||||
@ -416,7 +506,7 @@ class AccountAssetAsset(models.Model):
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
asset = super(AccountAssetAsset, self.with_context(mail_create_nolog=True)).create(vals)
|
||||
asset.compute_depreciation_board()
|
||||
asset.sudo().compute_depreciation_board()
|
||||
return asset
|
||||
|
||||
@api.multi
|
||||
@ -460,6 +550,14 @@ class AccountAssetDepreciationLine(models.Model):
|
||||
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)
|
||||
product_id = fields.Many2one(related='asset_id.product_id', relation="product.product", string="SID")
|
||||
begin_value = fields.Float(compute='_get_begin_value', string="Beginning Value", store=True)
|
||||
|
||||
@api.multi
|
||||
@api.depends('asset_id.value', 'asset_id.salvage_value')
|
||||
def _get_begin_value(self):
|
||||
for line in self:
|
||||
line.begin_value = line.asset_id.value - line.asset_id.salvage_value
|
||||
|
||||
@api.multi
|
||||
@api.depends('move_id')
|
||||
@ -473,13 +571,23 @@ class AccountAssetDepreciationLine(models.Model):
|
||||
for line in self:
|
||||
line.move_posted_check = True if line.move_id and line.move_id.state == 'posted' else False
|
||||
|
||||
@api.multi
|
||||
def action_move_cancel(self):
|
||||
for line in self.asset_id.depreciation_line_ids:
|
||||
if line.id >= self.id and line.move_check:
|
||||
line.move_check = False
|
||||
line.move_id.button_cancel()
|
||||
|
||||
@api.multi
|
||||
def create_move(self, post_move=True):
|
||||
created_moves = self.env['account.move']
|
||||
prec = self.env['decimal.precision'].precision_get('Account')
|
||||
for line in self:
|
||||
if line.move_id:
|
||||
raise UserError(_('This depreciation is already linked to a journal entry! Please post or delete it.'))
|
||||
# raise UserError(_('This depreciation is already linked to a journal entry! Please post or delete it.'))
|
||||
line.move_id.post()
|
||||
line.write({'move_check': True})
|
||||
return [x.id for x in line.move_id]
|
||||
category_id = line.asset_id.category_id
|
||||
depreciation_date = self.env.context.get('depreciation_date') or line.depreciation_date or fields.Date.context_today(self)
|
||||
company_currency = line.asset_id.company_id.currency_id
|
||||
@ -512,6 +620,7 @@ class AccountAssetDepreciationLine(models.Model):
|
||||
'ref': line.asset_id.code,
|
||||
'date': depreciation_date or False,
|
||||
'journal_id': category_id.journal_id.id,
|
||||
'asset_id': line.asset_id.id,
|
||||
'line_ids': [(0, 0, move_line_1), (0, 0, move_line_2)],
|
||||
}
|
||||
move = self.env['account.move'].create(move_vals)
|
||||
|
@ -3,7 +3,8 @@
|
||||
|
||||
from datetime import datetime
|
||||
from dateutil.relativedelta import relativedelta
|
||||
from flectra import api, fields, models
|
||||
from flectra.exceptions import UserError
|
||||
from flectra import api, fields, models, _
|
||||
from flectra.tools import DEFAULT_SERVER_DATE_FORMAT as DF
|
||||
|
||||
from flectra.addons import decimal_precision as dp
|
||||
@ -12,6 +13,9 @@ from flectra.addons import decimal_precision as dp
|
||||
class AccountInvoice(models.Model):
|
||||
_inherit = 'account.invoice'
|
||||
|
||||
asset_id = fields.Many2one('account.asset.asset')
|
||||
asset_bool = fields.Boolean(string="Asset")
|
||||
|
||||
@api.model
|
||||
def _refund_cleanup_lines(self, lines):
|
||||
result = super(AccountInvoice, self)._refund_cleanup_lines(lines)
|
||||
@ -45,6 +49,8 @@ class AccountInvoice(models.Model):
|
||||
class AccountInvoiceLine(models.Model):
|
||||
_inherit = 'account.invoice.line'
|
||||
|
||||
asset_id = fields.Many2one('account.asset.asset')
|
||||
asset_bool = fields.Boolean(string="Asset")
|
||||
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)
|
||||
@ -71,9 +77,13 @@ class AccountInvoiceLine(models.Model):
|
||||
|
||||
@api.one
|
||||
def asset_create(self):
|
||||
if self.asset_category_id:
|
||||
if not self.asset_category_id:
|
||||
self.write(
|
||||
{'asset_category_id': self.product_id.asset_category_id.id})
|
||||
if self.asset_category_id and not self.asset_bool:
|
||||
vals = {
|
||||
'name': self.name,
|
||||
'product_id': self.product_id.id,
|
||||
'code': self.invoice_id.number or False,
|
||||
'category_id': self.asset_category_id.id,
|
||||
'value': self.price_subtotal_signed,
|
||||
@ -86,6 +96,7 @@ class AccountInvoiceLine(models.Model):
|
||||
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)
|
||||
self.invoice_id.update({'asset_id': asset.id})
|
||||
if self.asset_category_id.open_asset:
|
||||
asset.validate()
|
||||
return True
|
||||
|
@ -2,3 +2,5 @@
|
||||
# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import account_asset_report
|
||||
from . import asset_depreciation_report
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
from flectra import api, fields, models, tools
|
||||
|
||||
|
||||
class AssetAssetReport(models.Model):
|
||||
_name = "asset.asset.report"
|
||||
_description = "Assets Analysis"
|
||||
|
104
addons/account_asset/report/asset_depreciation_report.py
Normal file
104
addons/account_asset/report/asset_depreciation_report.py
Normal file
@ -0,0 +1,104 @@
|
||||
# Part of Flectra. See LICENSE file for full copyright and licensing
|
||||
# details.
|
||||
|
||||
from flectra import api, models, _
|
||||
from datetime import datetime
|
||||
from flectra.exceptions import UserError
|
||||
|
||||
|
||||
class AssetDepreciation(models.AbstractModel):
|
||||
_name = "report.account_asset.asset_depreciation_template"
|
||||
|
||||
def get_date(self, data):
|
||||
date_lst = [{
|
||||
'start_date': data['start_date'],
|
||||
'end_date': data['end_date']
|
||||
}]
|
||||
return date_lst
|
||||
|
||||
def get_data(self, data):
|
||||
asset_dep_line_id_list = list()
|
||||
asset_dep_line_id_list = \
|
||||
self.env['account.asset.depreciation.line'].search([
|
||||
('depreciation_date', '>=', data['start_date']),
|
||||
('depreciation_date', '<=', data['end_date']),
|
||||
('move_check', '=', True),
|
||||
('move_id', '!=', False),
|
||||
('move_id.state', '=', 'posted')
|
||||
])
|
||||
if not asset_dep_line_id_list:
|
||||
raise UserError(_("No Depreciation Lines in this fiscal year.."))
|
||||
data_dict = {}
|
||||
for line_id in asset_dep_line_id_list:
|
||||
product_id = line_id.asset_id.product_id.id
|
||||
depre_date = datetime.strptime(
|
||||
line_id.depreciation_date, "%Y-%m-%d")
|
||||
purchase_date = datetime.strptime(
|
||||
line_id.asset_id.date, "%Y-%m-%d")
|
||||
if product_id not in data_dict:
|
||||
if depre_date.year == purchase_date.year \
|
||||
or line_id.sequence == 1:
|
||||
open_asset = 0.0
|
||||
open_dep = 0.0
|
||||
add_asset = line_id.asset_id.value_residual
|
||||
else:
|
||||
open_asset = line_id.asset_id.value_residual
|
||||
add_asset = 0.00
|
||||
open_dep = line_id.depreciated_value - line_id.amount
|
||||
add_dep = line_id.amount
|
||||
total_dep = open_dep + add_dep
|
||||
total_asset = open_asset + add_asset
|
||||
data_dict[product_id] = {
|
||||
'name': line_id.asset_id.name,
|
||||
'product_name': line_id.asset_id.product_id.name,
|
||||
'category': line_id.asset_id.category_id.name,
|
||||
'open_asset': open_asset,
|
||||
'add_asset': add_asset,
|
||||
'total_asset': total_asset,
|
||||
'open_dep': open_dep,
|
||||
'add_dep': add_dep,
|
||||
'total_dep': total_dep,
|
||||
'open_net': open_asset - open_dep,
|
||||
'add_net': add_asset - add_dep,
|
||||
'total_net': total_asset - total_dep
|
||||
}
|
||||
else:
|
||||
add_dep = line_id.amount
|
||||
if depre_date.year == purchase_date.year \
|
||||
or line_id.sequence == 1:
|
||||
open_asset = 0.0
|
||||
add_asset = line_id.asset_id.value_residual
|
||||
open_dep = 0.0
|
||||
else:
|
||||
open_asset = line_id.asset_id.value_residual
|
||||
add_asset = 0.00
|
||||
open_dep = line_id.depreciated_value - line_id.amount
|
||||
if line_id.asset_id.sale_date \
|
||||
and line_id.asset_id.sale_date >= data['start_date'] \
|
||||
and line_id.asset_id.sale_date <= data['end_date']:
|
||||
add_asset -= line_id.begin_value
|
||||
add_dep -= line_id.depreciated_value
|
||||
total_dep = open_dep + add_dep
|
||||
total_asset = open_asset + add_asset
|
||||
data_dict[product_id]['open_asset'] += open_asset
|
||||
data_dict[product_id]['add_asset'] += add_asset
|
||||
data_dict[product_id]['total_asset'] += total_asset
|
||||
data_dict[product_id]['open_dep'] += open_dep
|
||||
data_dict[product_id]['add_dep'] += add_dep
|
||||
data_dict[product_id]['total_dep'] += total_dep
|
||||
data_dict[product_id]['open_net'] += open_asset - open_dep
|
||||
data_dict[product_id]['add_net'] += add_asset - add_dep
|
||||
data_dict[product_id]['total_net'] += total_asset - total_dep
|
||||
|
||||
final_data = []
|
||||
for key in data_dict:
|
||||
final_data.append(data_dict[key])
|
||||
return final_data
|
||||
|
||||
@api.model
|
||||
def get_report_values(self, docids, data=None):
|
||||
report_lines = self.get_data(data.get('form'))
|
||||
model = self.env.context.get('active_model')
|
||||
docs = self.env[model].browse(self.env.context.get('active_id'))
|
||||
return {'doc_ids': docids, 'doc_model': model, 'data': data,
|
||||
'docs': docs, 'get_data': report_lines}
|
@ -0,0 +1,90 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<flectra>
|
||||
<template id="asset_depreciation_template">
|
||||
<t t-call="web.html_container">
|
||||
<t t-call="web.internal_layout">
|
||||
<div class="page">
|
||||
<h2>Asset Depreciation</h2>
|
||||
<div class="row mt32">
|
||||
<div class="col-xs-3">
|
||||
<strong>Start Date:</strong>
|
||||
<p t-esc="data['form']['start_date']"/>
|
||||
</div>
|
||||
<div class="col-xs-3">
|
||||
<strong>End Date:</strong>
|
||||
<p t-esc="data['form']['end_date']"/>
|
||||
</div>
|
||||
</div>
|
||||
<br/>
|
||||
<br/>
|
||||
<table class="table table-bordered">
|
||||
<tr>
|
||||
<th colspan="2"></th>
|
||||
<th colspan="3" class="text-center">Assets</th>
|
||||
<th colspan="3" class="text-center">Depreciation</th>
|
||||
<th colspan="3" class="text-center">Closing Balance</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="text-center">Asset Name</th>
|
||||
<th class="text-center">Category</th>
|
||||
<th class="text-center">Opening</th>
|
||||
<th class="text-center">Additional</th>
|
||||
<th class="text-center">Total</th>
|
||||
<th class="text-center">Opening</th>
|
||||
<th class="text-center">Additional</th>
|
||||
<th class="text-center">Total</th>
|
||||
<th class="text-center">Opening</th>
|
||||
<th class="text-center">Additional</th>
|
||||
<th class="text-center">Total</th>
|
||||
</tr>
|
||||
|
||||
<tr t-foreach="get_data" t-as="object">
|
||||
<td>
|
||||
<t t-esc="object['name']"/>
|
||||
</td>
|
||||
<td>
|
||||
<t t-esc="object['category']"/>
|
||||
</td>
|
||||
<td align="right">
|
||||
<t t-esc="object['open_asset']"
|
||||
t-options='{"widget": "monetary", "display_currency": res_company.currency_id}'/>
|
||||
</td>
|
||||
<td align="right">
|
||||
<t t-esc="object['add_asset']"
|
||||
t-options='{"widget": "monetary", "display_currency": res_company.currency_id}'/>
|
||||
</td>
|
||||
<td align="right">
|
||||
<t t-esc="object['total_asset']"
|
||||
t-options='{"widget": "monetary", "display_currency": res_company.currency_id}'/>
|
||||
</td>
|
||||
<td align="right">
|
||||
<t t-esc="object['open_dep']"
|
||||
t-options='{"widget": "monetary", "display_currency": res_company.currency_id}'/>
|
||||
</td>
|
||||
<td align="right">
|
||||
<t t-esc="object['add_dep']"
|
||||
t-options='{"widget": "monetary", "display_currency": res_company.currency_id}'/>
|
||||
</td>
|
||||
<td align="right">
|
||||
<t t-esc="object['total_dep']"
|
||||
t-options='{"widget": "monetary", "display_currency": res_company.currency_id}'/>
|
||||
</td>
|
||||
<td align="right">
|
||||
<t t-esc="object['open_net']"
|
||||
t-options='{"widget": "monetary", "display_currency": res_company.currency_id}'/>
|
||||
</td>
|
||||
<td align="right">
|
||||
<t t-esc="object['add_net']"
|
||||
t-options='{"widget": "monetary", "display_currency": res_company.currency_id}'/>
|
||||
</td>
|
||||
<td align="right">
|
||||
<t t-esc="object['total_net']"
|
||||
t-options='{"widget": "monetary", "display_currency": res_company.currency_id}'/>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
</template>
|
||||
</flectra>
|
12
addons/account_asset/report/asset_reports.xml
Normal file
12
addons/account_asset/report/asset_reports.xml
Normal file
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<flectra>
|
||||
<report
|
||||
id="asset_depreciation_report"
|
||||
model="account.asset.asset"
|
||||
string="Asset Depreciation Report"
|
||||
report_type="qweb-pdf"
|
||||
name="account_asset.asset_depreciation_template"
|
||||
file="account_asset.asset_depreciation_template"
|
||||
menu="False"
|
||||
/>
|
||||
</flectra>
|
18
addons/account_asset/report/report_paperformat.xml
Normal file
18
addons/account_asset/report/report_paperformat.xml
Normal file
@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<flectra>
|
||||
<record id="asset_depreciation_report_format" model="report.paperformat">
|
||||
<field name="name">Asset Depreciation Report Format</field>
|
||||
<field name="default" eval="True"/>
|
||||
<field name="format">A4</field>
|
||||
<field name="page_height">0</field>
|
||||
<field name="page_width">0</field>
|
||||
<field name="orientation">Landscape</field>
|
||||
<field name="margin_top">40</field>
|
||||
<field name="margin_bottom">20</field>
|
||||
<field name="margin_left">7</field>
|
||||
<field name="margin_right">7</field>
|
||||
<field name="header_line" eval="False"/>
|
||||
<field name="header_spacing">43</field>
|
||||
<field name="dpi">90</field>
|
||||
</record>
|
||||
</flectra>
|
@ -26,6 +26,32 @@
|
||||
<field name="method_period">12</field>
|
||||
</record>
|
||||
|
||||
<record id="account_asset_category_1" model="account.asset.category">
|
||||
<field name="name">Furniture</field>
|
||||
<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="method_time">number</field>
|
||||
<field name="method_number">5</field>
|
||||
<field name="method_period">12</field>
|
||||
<field name="method">linear</field>
|
||||
<field name="open_asset" eval="True"/>
|
||||
</record>
|
||||
|
||||
<record id="account_asset_category_2" model="account.asset.category">
|
||||
<field name="name">Electronics</field>
|
||||
<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="method_time">number</field>
|
||||
<field name="method_number">6</field>
|
||||
<field name="method_period">12</field>
|
||||
<field name="method">linear</field>
|
||||
<field name="open_asset" eval="True"/>
|
||||
</record>
|
||||
|
||||
<!--
|
||||
Assets Demo
|
||||
-->
|
||||
@ -50,7 +76,7 @@
|
||||
</record>
|
||||
|
||||
<record id="account_asset_asset_office_test0" model="account.asset.asset">
|
||||
<field eval="1" name="prorata"/>
|
||||
<field name="prorata">purchase_date</field>
|
||||
<field eval="100000.0" name="salvage_value"/>
|
||||
<field name="state">open</field>
|
||||
<field eval="12" name="method_period"/>
|
||||
@ -61,6 +87,45 @@
|
||||
<field name="category_id" ref="account_asset_category_fixedassets_test0"/>
|
||||
</record>
|
||||
|
||||
<record id="product_product_id_1" model="product.product">
|
||||
<field name="name">Asset Product</field>
|
||||
<field name="categ_id" ref="product.product_category_5"/>
|
||||
<field name="standard_price">100</field>
|
||||
<field name="list_price">150</field>
|
||||
<field name="uom_id" ref="product.product_uom_unit"/>
|
||||
<field name="uom_po_id" ref="product.product_uom_unit"/>
|
||||
<field name="description">Asset Product</field>
|
||||
<field name="default_code">AP</field>
|
||||
</record>
|
||||
|
||||
<record id="account_asset_1" model="account.asset.asset">
|
||||
<field name="name">Asset 1</field>
|
||||
<field name="product_id" ref="product_product_id_1"/>
|
||||
<field name="category_id" ref="account_asset_category_1"/>
|
||||
<field name="partner_id" ref="base.res_partner_1"/>
|
||||
<field name="date" eval="time.strftime('%Y-%m-%d')"/>
|
||||
<field name="value">50000</field>
|
||||
<field name="salvage_value">10000</field>
|
||||
<field name="method">linear</field>
|
||||
<field name="method_number">5</field>
|
||||
<field name="method_period">12</field>
|
||||
<field name="prorata">first_january</field>
|
||||
</record>
|
||||
|
||||
<record id="account_asset_2" model="account.asset.asset">
|
||||
<field name="name">Asset 2</field>
|
||||
<field name="product_id" ref="product_product_id_1"/>
|
||||
<field name="category_id" ref="account_asset_category_2"/>
|
||||
<field name="partner_id" ref="base.res_partner_1"/>
|
||||
<field name="date" eval="time.strftime('%Y-%m-%d')"/>
|
||||
<field name="value">40000</field>
|
||||
<field name="salvage_value">10000</field>
|
||||
<field name="method">linear</field>
|
||||
<field name="method_number">5</field>
|
||||
<field name="method_period">12</field>
|
||||
<field name="prorata">fiscal_year</field>
|
||||
</record>
|
||||
|
||||
|
||||
</data>
|
||||
</flectra>
|
||||
|
@ -4,6 +4,9 @@
|
||||
from flectra import tools
|
||||
from flectra.tests import common
|
||||
from flectra.modules.module import get_resource_path
|
||||
from datetime import date, datetime
|
||||
from flectra.tools import DEFAULT_SERVER_DATE_FORMAT as DF
|
||||
import logging
|
||||
|
||||
|
||||
class TestAccountAsset(common.TransactionCase):
|
||||
@ -17,6 +20,10 @@ class TestAccountAsset(common.TransactionCase):
|
||||
self._load('account', 'test', 'account_minimal_test.xml')
|
||||
self._load('account_asset', 'test', 'account_asset_demo_test.xml')
|
||||
|
||||
self.asset_id_1 = self.env.ref("account_asset.account_asset_1")
|
||||
self.asset_id_2 = self.env.ref("account_asset.account_asset_2")
|
||||
self.partner_id = self.env.ref("base.res_partner_2")
|
||||
|
||||
# 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()
|
||||
|
||||
@ -64,3 +71,82 @@ class TestAccountAsset(common.TransactionCase):
|
||||
}
|
||||
asset_compute_period_0 = self.env['asset.depreciation.confirmation.wizard'].create({})
|
||||
asset_compute_period_0.with_context(context).asset_compute()
|
||||
|
||||
assert self.asset_id_1.product_id, "Product is not there in %s" % \
|
||||
self.asset_id_1
|
||||
|
||||
assert self.asset_id_1.category_id, "Asset Category is not there " \
|
||||
"in %s" % self.asset_id_1
|
||||
|
||||
assert self.asset_id_1.partner_id, "Vendor is not defined in %s" % \
|
||||
self.asset_id_1
|
||||
|
||||
assert self.asset_id_1.date, "Asset Purchase date is not defined."
|
||||
|
||||
assert self.asset_id_1.value, "Definig an asset value is necessary"
|
||||
|
||||
if self.asset_id_1.method is 'degressive':
|
||||
assert self.asset_id_1.method_progress_factor, \
|
||||
"Degressive Factor is required for further calculation"
|
||||
|
||||
if self.asset_id_1.method_time is 'number':
|
||||
assert self.asset_id_1.method_number, "Method number is required"
|
||||
|
||||
if self.asset_id_1.method_time is 'end':
|
||||
assert self.asset_id_1.method_end, "Ending Date is required"
|
||||
|
||||
assert self.asset_id_1.method_period, "Field 'Number of months in " \
|
||||
"a period is blank'"
|
||||
|
||||
self.asset_id_1.validate()
|
||||
if self.asset_id_1.state != 'open':
|
||||
raise AssertionError("Asset state must be in open state!")
|
||||
|
||||
sale_asset_id = self.env['sale.asset.wizard'].create({
|
||||
'asset_id': self.asset_id_1.id,
|
||||
'product_id': self.asset_id_1.product_id.id,
|
||||
'asset_category_id': self.asset_id_1.category_id.id,
|
||||
'sale_date': date.today(),
|
||||
'partner_id': self.partner_id.id,
|
||||
})
|
||||
sale_asset_id.onchange_sale_date()
|
||||
sale_asset_id.with_context(
|
||||
{'active_id': self.asset_id_1.id}).sale_asset()
|
||||
|
||||
if self.asset_id_1.state != 'close':
|
||||
raise AssertionError("Asset is not sold")
|
||||
else:
|
||||
logging.info("Asset Sale Function successfully executed")
|
||||
|
||||
scrap_asset_id = self.env['scrap.asset.wizard'].create({
|
||||
'partner_id': self.asset_id_1.partner_id.id,
|
||||
'asset_id': self.asset_id_1.id,
|
||||
'product_id': self.asset_id_1.product_id.id,
|
||||
'asset_category_id': self.asset_id_1.category_id.id,
|
||||
'depreciated_amount': self.asset_id_1.remaining_asset_value,
|
||||
'sale_date': date.today(),
|
||||
})
|
||||
|
||||
scrap_asset_id.with_context(
|
||||
{'active_id': self.asset_id_1.id}).do_scrap()
|
||||
|
||||
if self.asset_id_1.state != 'close':
|
||||
raise AssertionError("Asset is not moved to scrap location")
|
||||
else:
|
||||
logging.info("Asset scrap function successfully executed")
|
||||
|
||||
# Check Fiscal Year
|
||||
account_config = self.env['res.config.settings'].create({
|
||||
'fiscalyear_last_month': 3,
|
||||
})
|
||||
account_config.execute()
|
||||
self.assertEqual(self.asset_id_2.prorata, 'fiscal_year')
|
||||
self.assertEqual(self.asset_id_2.method_period, 12)
|
||||
self.asset_id_2.compute_depreciation_board()
|
||||
self.asset_id_2.validate()
|
||||
fl_depreciation_date = self.asset_id_2.depreciation_line_ids[0].depreciation_date
|
||||
first_line_date = datetime.strptime(fl_depreciation_date, DF).date()
|
||||
self.assertEqual(first_line_date.month, 3)
|
||||
sl_depreciation_date = self.asset_id_2.depreciation_line_ids[1].depreciation_date
|
||||
second_line_date = datetime.strptime(sl_depreciation_date, DF).date()
|
||||
self.assertEqual(second_line_date.month, 3)
|
||||
|
@ -43,9 +43,9 @@
|
||||
</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_number" attrs="{'invisible':['|',('method_time','!=','number'),'&',('type','=', False)], 'required':[('method_time','=','number')]}"/>
|
||||
<label for="method_period" string="One Entry Every" attrs="{'invisible': [('prorata','=','fiscal_year')]}"/>
|
||||
<div attrs="{'invisible': [('prorata','=','fiscal_year')]}">
|
||||
<field name="method_period" nolabel="1" attrs="{'invisible': [('type','=', False)]}" class="oe_inline"/>
|
||||
months
|
||||
</div>
|
||||
@ -128,16 +128,44 @@
|
||||
<form string="Asset">
|
||||
<header>
|
||||
<button name="validate" states="draft" string="Confirm" type="object" class="oe_highlight"/>
|
||||
<button name="%(asset_sale_action)d" states="open" type="action" string="Customer Invoice"
|
||||
class="oe_highlight"
|
||||
context="{
|
||||
'default_product_id': product_id,
|
||||
'default_asset_category_id': category_id,
|
||||
'default_asset_id': active_id,
|
||||
'default_depreciated_amount': remaining_asset_value,
|
||||
'default_sale_value': remaining_asset_value,
|
||||
}"/>
|
||||
<button name="%(asset_scrap_action)d" type="action" string="Scrap" class="oe_highlight"
|
||||
context="{
|
||||
'default_product_id': product_id,
|
||||
'default_asset_category_id': category_id,
|
||||
'default_asset_id': active_id,
|
||||
'default_depreciated_amount': remaining_asset_value,
|
||||
'default_sale_value': remaining_asset_value,
|
||||
'default_partner_id': partner_id,
|
||||
}"
|
||||
attrs="{'invisible': [('state', '!=', 'open')]}"
|
||||
/>
|
||||
<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_close" states="open" string="Sell or Dispose" type="object" class="oe_highlight" invisible="1"/>
|
||||
<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"/>
|
||||
<button name="%(action_asset_modify)d" states="open" string="Modify Depreciation" type="action" context="{'prorata': prorata}"/>
|
||||
<field name="state" widget="statusbar" statusbar_visible="draft,open"/>
|
||||
</header>
|
||||
<sheet>
|
||||
<div class="oe_button_box" name="button_box">
|
||||
<button name="toggle_active" type="object"
|
||||
class="oe_stat_button" icon="fa-archive" attrs="{'invisible': [('state', '=', 'close')]}">
|
||||
<field name="active" widget="boolean_button"
|
||||
options='{"terminology": "archive"}'/>
|
||||
</button>
|
||||
<button class="oe_stat_button" name="open_entries" type="object" icon="fa-pencil">
|
||||
<field string="Items" name="entry_count" widget="statinfo" />
|
||||
<field string="Dep. Entries" name="entry_count" widget="statinfo" />
|
||||
</button>
|
||||
<button class="oe_inline oe_stat_button" name="redirect_to_invoice" type="object" icon="fa-pencil" attrs="{'invisible': [('invoice_count', '=', 0)]}">
|
||||
<field name="invoice_count" widget="statinfo"/>
|
||||
</button>
|
||||
</div>
|
||||
<div class="oe_title">
|
||||
@ -150,7 +178,12 @@
|
||||
<group>
|
||||
<field name="category_id" domain="[('type', '=', 'purchase')]" context="{'default_type': 'purchase'}" help="Category of asset"/>
|
||||
<field name="code"/>
|
||||
<field name="product_id"
|
||||
attrs="{'required': [('state','=','draft')],'readonly': [('state','!=','draft')]}"
|
||||
string="Asset"/>
|
||||
<field name="remaining_asset_value" invisible="1"/>
|
||||
<field name="date" help="Date of asset"/>
|
||||
<field name="sale_date" attrs="{'invisible': [('sale_date', '=', False)], 'readonly': [('sale_date', '!=', False)]}"/>
|
||||
<field name="type" invisible="1"/>
|
||||
</group>
|
||||
<group>
|
||||
@ -168,10 +201,12 @@
|
||||
<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="depreciated_value" readonly="1"/>
|
||||
<field name="begin_value"/>
|
||||
<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')]}"/>
|
||||
<button name="action_move_cancel" string="Cancel Entry" type="object" attrs="{'invisible': ['|', ('move_check', '=', False), ('parent_state', '=', 'close')]}"/>
|
||||
<field name="move_posted_check" invisible="1"/>
|
||||
<field name="parent_state" invisible="1"/>
|
||||
</tree>
|
||||
@ -204,7 +239,7 @@
|
||||
</group>
|
||||
<group>
|
||||
<field name="method_number" attrs="{'invisible':[('method_time','=','end')], 'required':[('method_time','=','number')]}"/>
|
||||
<field name="method_period"/>
|
||||
<field name="method_period" attrs="{'invisible': [('prorata','=','fiscal_year')]}"/>
|
||||
<field name="method_end" attrs="{'required': [('method_time','=','end')], 'invisible':[('method_time','=','number')]}"/>
|
||||
</group>
|
||||
</page>
|
||||
@ -284,9 +319,16 @@
|
||||
<filter string="Closed" domain="[('state','=', 'close')]" help="Assets in closed state"/>
|
||||
<field name="category_id"/>
|
||||
<field name="partner_id" filter_domain="[('partner_id','child_of',self)]"/>
|
||||
<filter string="Inactive" domain="[('active','=', False)]"/>
|
||||
<field name="product_id"/>
|
||||
<group expand="0" string="Group By...">
|
||||
<filter string="Month" domain="[]" context="{'group_by':'date'}"/>
|
||||
<filter string="Category" domain="[]" context="{'group_by':'category_id'}"/>
|
||||
<filter string="Month" domain="[]" context="{'group_by':'date'}"/>
|
||||
<filter string="State" icon="terp-folder-orange" domain="[]" context="{'group_by':'state'}"/>
|
||||
<filter string="Asset Category" icon="terp-folder-orange" domain="[]"
|
||||
context="{'group_by':'category_id'}"/>
|
||||
<filter string="Product" icon="terp-folder-orange" domain="[]" context="{'group_by':'product_id'}"/>
|
||||
<filter string="Partner" icon="terp-folder-orange" domain="[]"
|
||||
context="{'group_by':'partner_id'}"/>
|
||||
</group>
|
||||
</search>
|
||||
</field>
|
||||
|
@ -10,6 +10,18 @@
|
||||
<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>
|
||||
<xpath expr="//field[@name='partner_id']" position="after">
|
||||
<field name="asset_bool" invisible="1"/>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='partner_id']" position="attributes">
|
||||
<attribute name="attrs">{'readonly': [('asset_bool', '=', True)]}</attribute>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='invoice_line_ids']" position="inside">
|
||||
<field name="asset_bool" invisible="1"/>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='invoice_line_ids']" position="attributes">
|
||||
<attribute name="attrs">{'readonly': [('asset_bool', '=', True)]}</attribute>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
@ -3,3 +3,6 @@
|
||||
|
||||
from . import asset_depreciation_confirmation_wizard
|
||||
from . import asset_modify
|
||||
from . import sale_asset_wizard
|
||||
from . import scrap_asset_wizard
|
||||
from . import asset_depreciation_summary
|
35
addons/account_asset/wizard/asset_depreciation_summary.py
Normal file
35
addons/account_asset/wizard/asset_depreciation_summary.py
Normal file
@ -0,0 +1,35 @@
|
||||
# Part of Flectra. See LICENSE file for full copyright and licensing
|
||||
# details.
|
||||
|
||||
from flectra import api, fields, models
|
||||
from datetime import datetime
|
||||
from flectra.tools import DEFAULT_SERVER_DATE_FORMAT as DF
|
||||
|
||||
|
||||
class AssetDepreciationWizard(models.TransientModel):
|
||||
_name = "asset.depreciation.wizard"
|
||||
|
||||
@api.depends('start_date')
|
||||
def _compute_get_end_date(self):
|
||||
if self.start_date:
|
||||
last_day = self.env.user.company_id.fiscalyear_last_day
|
||||
last_month = self.env.user.company_id.fiscalyear_last_month
|
||||
date = datetime.strptime(self.start_date, DF).date()
|
||||
if date.month <= 3 and date.day < 31:
|
||||
year = date.year
|
||||
else:
|
||||
year = date.year + 1
|
||||
date = date.replace(month=last_month, day=last_day, year=year)
|
||||
self.end_date = datetime.strftime(date, '%Y-%m-%d')
|
||||
|
||||
start_date = fields.Date(string="Start Date", required=True)
|
||||
end_date = fields.Date(compute='_compute_get_end_date', store=True)
|
||||
|
||||
@api.multi
|
||||
def print_depreciation_lines(self):
|
||||
data = {'form': self.read(['start_date', 'end_date'])[0]}
|
||||
return self.env.ref(
|
||||
'account_asset.asset_depreciation_report').report_action(
|
||||
self,
|
||||
data=data,
|
||||
config=False)
|
@ -0,0 +1,35 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<flectra>
|
||||
<record id="asset_depreciation_summary_report_form_view" model="ir.ui.view">
|
||||
<field name="name">asset.depreciation.summary.report.form</field>
|
||||
<field name="model">asset.depreciation.wizard</field>
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<group col="4">
|
||||
<field name="start_date"/>
|
||||
<field name="end_date"/>
|
||||
</group>
|
||||
<footer>
|
||||
<button name="print_depreciation_lines" type="object" class="oe_highlight" string="Print"/>
|
||||
<button string="Cancel" class="oe_link" special="cancel"/>
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="asset_depreciation_summary_report_action" model="ir.actions.act_window">
|
||||
<field name="name">Asset Depreciation Summary Report</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">asset.depreciation.wizard</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
|
||||
<menuitem
|
||||
id="asset_depreciation_summary_report_menu"
|
||||
name="Asset Depreciation Summary"
|
||||
parent="account.menu_finance_legal_statement"
|
||||
action="asset_depreciation_summary_report_action"
|
||||
/>
|
||||
</flectra>
|
@ -14,8 +14,8 @@
|
||||
</group>
|
||||
<group colspan="2" col="2">
|
||||
<field name="method_end" attrs="{'invisible': [('asset_method_time', '=', 'number')]}"/>
|
||||
<label for="method_period"/>
|
||||
<div>
|
||||
<label for="method_period" invisible="context.get('prorata') == 'fiscal_year'"/>
|
||||
<div invisible="context.get('prorata') == 'fiscal_year'">
|
||||
<field name="method_period" class="oe_inline"/> months
|
||||
</div>
|
||||
</group>
|
||||
|
159
addons/account_asset/wizard/sale_asset_wizard.py
Normal file
159
addons/account_asset/wizard/sale_asset_wizard.py
Normal file
@ -0,0 +1,159 @@
|
||||
# Part of Flectra. See LICENSE file for full copyright and licensing
|
||||
# details.
|
||||
|
||||
from flectra import fields, models, _, api
|
||||
from datetime import datetime
|
||||
from flectra.tools import DEFAULT_SERVER_DATE_FORMAT as DF
|
||||
|
||||
|
||||
class SaleAssetWizard(models.TransientModel):
|
||||
_name = "sale.asset.wizard"
|
||||
|
||||
asset_id = fields.Many2one("account.asset.asset", string="Asset")
|
||||
asset_category_id = fields.Many2one("account.asset.category",
|
||||
string="Asset Category", required=True)
|
||||
depreciated_amount = fields.Float(string="Depreciated Amount")
|
||||
product_id = fields.Many2one("product.product", string="Product",
|
||||
required=True)
|
||||
partner_id = fields.Many2one("res.partner", string="Customer",
|
||||
required=True)
|
||||
sale_value = fields.Float(string="Sale Value")
|
||||
sale_date = fields.Date(
|
||||
string="Date", default=lambda self: datetime.today(),
|
||||
required=True)
|
||||
|
||||
@api.onchange('sale_date')
|
||||
def onchange_sale_date(self):
|
||||
if self.sale_date:
|
||||
amount = 0.0
|
||||
last_date = False
|
||||
for line in self.asset_id.depreciation_line_ids:
|
||||
if self.sale_date >= line.depreciation_date:
|
||||
amount += line.amount
|
||||
last_date = line.depreciation_date
|
||||
else:
|
||||
if not last_date:
|
||||
last_date = line.depreciation_date
|
||||
delta, total_days = \
|
||||
self.get_days(last_date, self.sale_date)
|
||||
amount += (line.amount * delta.days) / total_days
|
||||
break
|
||||
self.depreciated_amount = amount
|
||||
self.sale_value = self.asset_id.value_residual - amount
|
||||
|
||||
@api.constrains('sale_date')
|
||||
def _check_sale_date(self):
|
||||
if self.sale_date:
|
||||
posted_line_ids = \
|
||||
self.env['account.asset.depreciation.line'].search([
|
||||
('asset_id', '=', self.asset_id.id),
|
||||
('move_check', '=', True)])
|
||||
if posted_line_ids:
|
||||
last_depreciation_date = \
|
||||
datetime.strptime(
|
||||
posted_line_ids[-1].depreciation_date, DF).date()
|
||||
if self.sale_date < str(last_depreciation_date):
|
||||
raise ValueError(_("Sale date must be greater than last "
|
||||
"Depreciated date!"))
|
||||
|
||||
@api.multi
|
||||
def get_days(self, last_date, sale_date):
|
||||
last_depreciation_date = datetime.strptime(last_date, DF).date()
|
||||
sale_date = datetime.strptime(sale_date, DF).date()
|
||||
delta = sale_date - last_depreciation_date
|
||||
year = last_depreciation_date.year
|
||||
total_days = (year % 4) and 365 or 366
|
||||
return delta, total_days
|
||||
|
||||
@api.multi
|
||||
def last_line_info(self):
|
||||
last_date = False
|
||||
last_line = False
|
||||
sale_date = self.sale_date
|
||||
for line in self.asset_id.depreciation_line_ids:
|
||||
if sale_date >= line.depreciation_date:
|
||||
line.create_move(post_move=True)
|
||||
last_date = line.depreciation_date
|
||||
last_line = line
|
||||
else:
|
||||
last_line = line
|
||||
if not last_date:
|
||||
last_date = line.depreciation_date
|
||||
break
|
||||
delta, total_days = self.get_days(last_date, sale_date)
|
||||
amount = (last_line.amount * delta.days) / total_days
|
||||
return last_line, amount
|
||||
|
||||
def sale_asset(self):
|
||||
if self.asset_id:
|
||||
self.asset_id.write({
|
||||
'state': 'close',
|
||||
'sale_date': self.sale_date,
|
||||
})
|
||||
last_line, amount = self.last_line_info()
|
||||
if last_line:
|
||||
depreciated_value = \
|
||||
(last_line.depreciated_value - last_line.amount) + amount
|
||||
last_line.update({
|
||||
'depreciation_date': self.sale_date,
|
||||
'amount': amount,
|
||||
'depreciated_value': depreciated_value,
|
||||
'remaining_value':
|
||||
last_line.begin_value - depreciated_value,
|
||||
})
|
||||
last_line.create_move(post_move=True)
|
||||
for line in self.asset_id.depreciation_line_ids:
|
||||
if not line.move_check:
|
||||
line.unlink()
|
||||
self.create_sale_invoice()
|
||||
|
||||
def create_sale_invoice(self):
|
||||
invoice_obj = self.env['account.invoice']
|
||||
invoice_line_obj = self.env['account.invoice.line']
|
||||
journal_id = self.env['account.journal'].search(
|
||||
[('code', '=', 'INV')])
|
||||
account_id = self.env['account.account'].search(
|
||||
[('internal_type', '=', 'receivable')])
|
||||
tax_ids = self.product_id.supplier_taxes_id.ids
|
||||
|
||||
invoice_id = invoice_obj.create({
|
||||
'partner_id': self.partner_id.id,
|
||||
'journal_id':
|
||||
journal_id and
|
||||
journal_id[0].id or
|
||||
self.asset_id.category_id.journal_id.id,
|
||||
'account_id':
|
||||
account_id and
|
||||
account_id[0].id or
|
||||
self.asset_id.category_id.account_asset_id.id,
|
||||
'company_id': self.partner_id.company_id.id,
|
||||
'type': 'out_invoice',
|
||||
'date_invoice': self.sale_date,
|
||||
'payment_term_id':
|
||||
self.partner_id.property_supplier_payment_term_id.id,
|
||||
'currency_id': self.partner_id.company_id.currency_id.id,
|
||||
'asset_id': self.asset_id.id,
|
||||
'asset_bool': True
|
||||
})
|
||||
invoice_line_obj.create({
|
||||
'product_id': self.product_id.id,
|
||||
'name': self.product_id.name,
|
||||
'asset_id': self.asset_id.id,
|
||||
'asset_category_id': self.asset_id.category_id.id,
|
||||
'account_id': self.asset_id.category_id.account_asset_id.id,
|
||||
'quantity': 1.0,
|
||||
'price_unit': self.sale_value,
|
||||
'partner_id': self.partner_id.id,
|
||||
'company_id': self.partner_id.company_id.id,
|
||||
'invoice_line_tax_ids': tax_ids and [[6, 0, tax_ids]] or False,
|
||||
'asset_bool': True,
|
||||
'invoice_id': invoice_id.id
|
||||
})
|
||||
return {
|
||||
'name': (_('Invoices')),
|
||||
'type': 'ir.actions.act_window',
|
||||
'view_type': 'form',
|
||||
'view_mode': 'tree,form',
|
||||
'res_model': 'account.invoice',
|
||||
'domain': [('asset_id', '=', self.asset_id.id)]
|
||||
}
|
36
addons/account_asset/wizard/sale_asset_wizard_view.xml
Normal file
36
addons/account_asset/wizard/sale_asset_wizard_view.xml
Normal file
@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<flectra>
|
||||
<record id="asset_sale_form_view" model="ir.ui.view">
|
||||
<field name="name">sale.asset.wizard</field>
|
||||
<field name="model">sale.asset.wizard</field>
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<group col="4">
|
||||
<field name="asset_id" readonly="1"/>
|
||||
<field name="product_id" readonly="1"/>
|
||||
<field name="asset_category_id" readonly="1"/>
|
||||
<field name="depreciated_amount" readonly="1" invisible="1"/>
|
||||
<field name="sale_date"/>
|
||||
<field name="partner_id"/>
|
||||
<field name="sale_value"/>
|
||||
</group>
|
||||
<footer>
|
||||
<button name="sale_asset" string="Confirm"
|
||||
type="object"
|
||||
class="oe_highlight" context="{}"/>
|
||||
<button string="Cancel" class="oe_highlight"
|
||||
special="cancel"/>
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="asset_sale_action" model="ir.actions.act_window">
|
||||
<field name="name">Sale</field>
|
||||
<field name="res_model">sale.asset.wizard</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
</flectra>
|
44
addons/account_asset/wizard/scrap_asset_wizard.py
Normal file
44
addons/account_asset/wizard/scrap_asset_wizard.py
Normal file
@ -0,0 +1,44 @@
|
||||
# Part of Flectra. See LICENSE file for full copyright and licensing
|
||||
# details.
|
||||
|
||||
from flectra import fields, models, api
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
class ScrapAssetWizard(models.TransientModel):
|
||||
_name = "scrap.asset.wizard"
|
||||
|
||||
partner_id = fields.Many2one('res.partner', 'Partner', required=True)
|
||||
asset_id = fields.Many2one("account.asset.asset", string="Asset")
|
||||
asset_category_id = fields.Many2one("account.asset.category",
|
||||
string="Asset Category", required=True)
|
||||
product_id = fields.Many2one("product.product", string="Product",
|
||||
required=True)
|
||||
depreciated_amount = fields.Float(string="Depreciated Amount",
|
||||
required=True)
|
||||
sale_date = fields.Date(
|
||||
string="Date", default=lambda self: datetime.today(),
|
||||
required=True)
|
||||
|
||||
financial_move = fields.Boolean(string="Create Financial Move")
|
||||
journal_id = fields.Many2one("account.journal", string="Payment Journal",
|
||||
domain=[('type', 'in', ('bank', 'cash'))])
|
||||
amount = fields.Float(string="Payment Amount")
|
||||
|
||||
@api.multi
|
||||
def do_scrap(self):
|
||||
asset_id = self.env['account.asset.asset'].browse(
|
||||
self._context['active_id'])
|
||||
|
||||
if asset_id:
|
||||
asset_id.write({
|
||||
'active': False,
|
||||
'state': 'close'
|
||||
})
|
||||
depreciation_line_ids = self.env[
|
||||
'account.asset.depreciation.line'].search(
|
||||
[('asset_id', '=', asset_id.id), ('move_check', '=', False)])
|
||||
|
||||
if depreciation_line_ids:
|
||||
depreciation_line_ids.unlink()
|
||||
return True
|
36
addons/account_asset/wizard/scrap_asset_wizard_view.xml
Normal file
36
addons/account_asset/wizard/scrap_asset_wizard_view.xml
Normal file
@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<flectra>
|
||||
<record id="asset_scrap_form_view" model="ir.ui.view">
|
||||
<field name="name">scrap.asset.wizard</field>
|
||||
<field name="model">scrap.asset.wizard</field>
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<group col="4">
|
||||
<field name="partner_id"/>
|
||||
<field name="asset_id" readonly="1"/>
|
||||
<field name="product_id"/>
|
||||
<field name="asset_category_id"/>
|
||||
<field name="depreciated_amount"/>
|
||||
<field name="sale_date"/>
|
||||
</group>
|
||||
<footer>
|
||||
<button name="do_scrap" string="Confirm"
|
||||
type="object"
|
||||
class="oe_highlight" context="{}"/>
|
||||
<button string="Cancel" class="oe_highlight"
|
||||
special="cancel"/>
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="asset_scrap_action" model="ir.actions.act_window">
|
||||
<field name="name">scrap.asset.wizard</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">scrap.asset.wizard</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
|
||||
</flectra>
|
Loading…
Reference in New Issue
Block a user