From 1b2971d5b8cae7b2bc44917d73022a0d76499b62 Mon Sep 17 00:00:00 2001 From: Haresh Chavda Date: Tue, 24 Jul 2018 16:45:11 +0530 Subject: [PATCH 1/5] [ADD] Add Fiscal year concept and Asset report and misc --- addons/account_asset/__manifest__.py | 10 +- .../account_asset/data/account_asset_data.xml | 2 +- .../account_asset/data/account_asset_demo.yml | 25 ++- addons/account_asset/models/account.py | 7 + addons/account_asset/models/account_asset.py | 143 ++++++++++++++-- .../account_asset/models/account_invoice.py | 15 +- addons/account_asset/report/__init__.py | 2 + .../report/account_asset_report.py | 1 + .../report/asset_depreciation_report.py | 104 ++++++++++++ .../asset_depreciation_report_template.xml | 90 ++++++++++ addons/account_asset/report/asset_reports.xml | 12 ++ .../report/report_paperformat.xml | 18 ++ .../test/account_asset_demo_test.xml | 67 +++++++- .../account_asset/tests/test_account_asset.py | 86 ++++++++++ .../views/account_asset_views.xml | 62 +++++-- .../views/account_invoice_views.xml | 12 ++ addons/account_asset/wizard/__init__.py | 3 + .../wizard/asset_depreciation_summary.py | 35 ++++ ...asset_depreciation_summary_wizard_view.xml | 35 ++++ .../wizard/asset_modify_views.xml | 4 +- .../account_asset/wizard/sale_asset_wizard.py | 159 ++++++++++++++++++ .../wizard/sale_asset_wizard_view.xml | 36 ++++ .../wizard/scrap_asset_wizard.py | 44 +++++ .../wizard/scrap_asset_wizard_view.xml | 36 ++++ 24 files changed, 972 insertions(+), 36 deletions(-) create mode 100644 addons/account_asset/report/asset_depreciation_report.py create mode 100644 addons/account_asset/report/asset_depreciation_report_template.xml create mode 100644 addons/account_asset/report/asset_reports.xml create mode 100644 addons/account_asset/report/report_paperformat.xml create mode 100644 addons/account_asset/wizard/asset_depreciation_summary.py create mode 100644 addons/account_asset/wizard/asset_depreciation_summary_wizard_view.xml create mode 100644 addons/account_asset/wizard/sale_asset_wizard.py create mode 100644 addons/account_asset/wizard/sale_asset_wizard_view.xml create mode 100644 addons/account_asset/wizard/scrap_asset_wizard.py create mode 100644 addons/account_asset/wizard/scrap_asset_wizard_view.xml diff --git a/addons/account_asset/__manifest__.py b/addons/account_asset/__manifest__.py index 64393208..4af77a7d 100644 --- a/addons/account_asset/__manifest__.py +++ b/addons/account_asset/__manifest__.py @@ -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", diff --git a/addons/account_asset/data/account_asset_data.xml b/addons/account_asset/data/account_asset_data.xml index 5e8c0fad..e32ce245 100644 --- a/addons/account_asset/data/account_asset_data.xml +++ b/addons/account_asset/data/account_asset_data.xml @@ -1,6 +1,6 @@ - + Account Asset: Generate asset entries code diff --git a/addons/account_asset/data/account_asset_demo.yml b/addons/account_asset/data/account_asset_demo.yml index 89e0120a..fe2cf670 100644 --- a/addons/account_asset/data/account_asset_demo.yml +++ b/addons/account_asset/data/account_asset_demo.yml @@ -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') \ No newline at end of file diff --git a/addons/account_asset/models/account.py b/addons/account_asset/models/account.py index f5d13b52..260f3240 100644 --- a/addons/account_asset/models/account.py +++ b/addons/account_asset/models/account.py @@ -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") diff --git a/addons/account_asset/models/account_asset.py b/addons/account_asset/models/account_asset.py index 45bf685d..9a1dfa45 100644 --- a/addons/account_asset/models/account_asset.py +++ b/addons/account_asset/models/account_asset.py @@ -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) diff --git a/addons/account_asset/models/account_invoice.py b/addons/account_asset/models/account_invoice.py index b2960c28..5dc40d0f 100644 --- a/addons/account_asset/models/account_invoice.py +++ b/addons/account_asset/models/account_invoice.py @@ -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 diff --git a/addons/account_asset/report/__init__.py b/addons/account_asset/report/__init__.py index 60ded679..9f3273b9 100644 --- a/addons/account_asset/report/__init__.py +++ b/addons/account_asset/report/__init__.py @@ -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 + diff --git a/addons/account_asset/report/account_asset_report.py b/addons/account_asset/report/account_asset_report.py index 697976ba..6659777e 100644 --- a/addons/account_asset/report/account_asset_report.py +++ b/addons/account_asset/report/account_asset_report.py @@ -3,6 +3,7 @@ from flectra import api, fields, models, tools + class AssetAssetReport(models.Model): _name = "asset.asset.report" _description = "Assets Analysis" diff --git a/addons/account_asset/report/asset_depreciation_report.py b/addons/account_asset/report/asset_depreciation_report.py new file mode 100644 index 00000000..528497e1 --- /dev/null +++ b/addons/account_asset/report/asset_depreciation_report.py @@ -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} diff --git a/addons/account_asset/report/asset_depreciation_report_template.xml b/addons/account_asset/report/asset_depreciation_report_template.xml new file mode 100644 index 00000000..d2d614ba --- /dev/null +++ b/addons/account_asset/report/asset_depreciation_report_template.xml @@ -0,0 +1,90 @@ + + + + diff --git a/addons/account_asset/report/asset_reports.xml b/addons/account_asset/report/asset_reports.xml new file mode 100644 index 00000000..6785c2e0 --- /dev/null +++ b/addons/account_asset/report/asset_reports.xml @@ -0,0 +1,12 @@ + + + + diff --git a/addons/account_asset/report/report_paperformat.xml b/addons/account_asset/report/report_paperformat.xml new file mode 100644 index 00000000..8a5dca5e --- /dev/null +++ b/addons/account_asset/report/report_paperformat.xml @@ -0,0 +1,18 @@ + + + + Asset Depreciation Report Format + + A4 + 0 + 0 + Landscape + 40 + 20 + 7 + 7 + + 43 + 90 + + diff --git a/addons/account_asset/test/account_asset_demo_test.xml b/addons/account_asset/test/account_asset_demo_test.xml index 51106efd..5ad6ddf3 100644 --- a/addons/account_asset/test/account_asset_demo_test.xml +++ b/addons/account_asset/test/account_asset_demo_test.xml @@ -26,6 +26,32 @@ 12 + + Furniture + + + + + number + 5 + 12 + linear + + + + + Electronics + + + + + number + 6 + 12 + linear + + + @@ -50,7 +76,7 @@ - + purchase_date open @@ -61,6 +87,45 @@ + + Asset Product + + 100 + 150 + + + Asset Product + AP + + + + Asset 1 + + + + + 50000 + 10000 + linear + 5 + 12 + first_january + + + + Asset 2 + + + + + 40000 + 10000 + linear + 5 + 12 + fiscal_year + + diff --git a/addons/account_asset/tests/test_account_asset.py b/addons/account_asset/tests/test_account_asset.py index 58faf9f4..1c066945 100644 --- a/addons/account_asset/tests/test_account_asset.py +++ b/addons/account_asset/tests/test_account_asset.py @@ -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) diff --git a/addons/account_asset/views/account_asset_views.xml b/addons/account_asset/views/account_asset_views.xml index a023d5e7..51c420b2 100644 --- a/addons/account_asset/views/account_asset_views.xml +++ b/addons/account_asset/views/account_asset_views.xml @@ -43,9 +43,9 @@ - -