diff --git a/account_asset_management/README.rst b/account_asset_management/README.rst index 51da1743e..615fb150c 100644 --- a/account_asset_management/README.rst +++ b/account_asset_management/README.rst @@ -58,6 +58,11 @@ The module in NOT compatible with the standard account_asset module. Changelog ========= +12.0.1.1.0 (2019-07-08) +~~~~~~~~~~~~~~~~~~~~~~~ + +* [IMP] Add option to calculate depreciation table by days + 12.0.1.0.0 (2019-01-13) ~~~~~~~~~~~~~~~~~~~~~~~ @@ -94,6 +99,8 @@ Contributors - Akim Juillerat - Henrik Norlin (Apps2GROW) - Maxence Groine +- Kitti Upariphutthiphong +- Saran Lim. Maintainers ~~~~~~~~~~~ diff --git a/account_asset_management/__manifest__.py b/account_asset_management/__manifest__.py index 32d504301..57385e6cd 100644 --- a/account_asset_management/__manifest__.py +++ b/account_asset_management/__manifest__.py @@ -4,7 +4,7 @@ { 'name': 'Assets Management', - 'version': '12.0.2.0.0', + 'version': '12.0.2.1.0', 'license': 'AGPL-3', 'depends': [ 'account', diff --git a/account_asset_management/models/account_asset.py b/account_asset_management/models/account_asset.py index c2ef18192..ed280dfcd 100644 --- a/account_asset_management/models/account_asset.py +++ b/account_asset_management/models/account_asset.py @@ -162,6 +162,23 @@ class AccountAsset(models.Model): # " * Ending Date: Choose the time between 2 depreciations " # "and the date the depreciations won't go beyond." ) + days_calc = fields.Boolean( + string='Calculate by days', + default=False, + help="Use number of days to calculate depreciation amount", + ) + use_leap_years = fields.Boolean( + string='Use leap years', + default=False, + help="If not set, the system will distribute evenly the amount to " + "amortize across the years, based on the number of years. " + "So the amount per year will be the " + "depreciation base / number of years.\n " + "If set, the system will consider if the current year " + "is a leap year. The amount to depreciate per year will be " + "calculated as depreciation base / (depreciation end date - " + "start date + 1) * days in the current year.", + ) prorata = fields.Boolean( string='Prorata Temporis', readonly=True, states={'draft': [('readonly', False)]}, @@ -276,6 +293,8 @@ class AccountAsset(models.Model): 'method_number': profile.method_number, 'method_time': profile.method_time, 'method_period': profile.method_period, + 'days_calc': profile.days_calc, + 'use_leap_years': profile.use_leap_years, 'method_progress_factor': profile.method_progress_factor, 'prorata': profile.prorata, 'account_analytic_id': profile.account_analytic_id, @@ -287,6 +306,16 @@ class AccountAsset(models.Model): if self.method_time != 'year': self.prorata = True + @api.onchange('method_number') + def _onchange_method_number(self): + if self.method_number and self.method_end: + self.method_end = False + + @api.onchange('method_end') + def _onchange_method_end(self): + if self.method_end and self.method_number: + self.method_number = 0 + @api.model def create(self, vals): if vals.get('method_time') != 'year' and not vals.get('prorata'): @@ -554,13 +583,14 @@ class AccountAsset(models.Model): if amount: vals = { 'previous_id': depr_line.id, - 'amount': amount, + 'amount': round(amount, digits), 'asset_id': asset.id, 'name': name, 'line_date': line['date'], + 'line_days': line['days'], 'init_entry': entry['init'], } - depreciated_value += amount + depreciated_value += round(amount, digits) depr_line = line_obj.create(vals) else: seq -= 1 @@ -645,7 +675,7 @@ class AccountAsset(models.Model): return depreciation_start_date def _get_depreciation_stop_date(self, depreciation_start_date): - if self.method_time == 'year': + if self.method_time == 'year' and not self.method_end: depreciation_stop_date = depreciation_start_date + \ relativedelta(years=self.method_number, days=-1) elif self.method_time == 'number': @@ -663,7 +693,7 @@ class AccountAsset(models.Model): elif self.method_period == 'year': depreciation_stop_date = depreciation_start_date + \ relativedelta(years=self.method_number, days=-1) - elif self.method_time == 'end': + elif self.method_time == 'year' and self.method_end: depreciation_stop_date = self.method_end return depreciation_stop_date @@ -680,7 +710,21 @@ class AccountAsset(models.Model): amount = entry['fy_amount'] - amount * full_periods return amount - def _compute_year_amount(self, residual_amount): + def _get_amount_linear( + self, depreciation_start_date, depreciation_stop_date, entry): + """ + Override this method if you want to compute differently the + yearly amount. + """ + if not self.use_leap_years and self.method_number: + return self.depreciation_base / self.method_number + year = entry['date_stop'].year + cy_days = calendar.isleap(year) and 366 or 365 + days = (depreciation_stop_date - depreciation_start_date).days + 1 + return (self.depreciation_base / days) * cy_days + + def _compute_year_amount(self, residual_amount, depreciation_start_date, + depreciation_stop_date, entry): """ Localization: override this method to change the degressive-linear calculation logic according to local legislation. @@ -689,8 +733,8 @@ class AccountAsset(models.Model): raise UserError( _("The '_compute_year_amount' method is only intended for " "Time Method 'Number of Years.")) - - year_amount_linear = self.depreciation_base / self.method_number + year_amount_linear = self._get_amount_linear( + depreciation_start_date, depreciation_stop_date, entry) if self.method == 'linear': return year_amount_linear if self.method == 'linear-limit': @@ -750,18 +794,30 @@ class AccountAsset(models.Model): # last entry if not (self.method_time == 'number' and len(line_dates) == self.method_number): - line_dates.append(line_date) + if self.days_calc: + line_dates.append(stop_date) + else: + line_dates.append(line_date) return line_dates - def _compute_depreciation_amount_per_fiscal_year(self, table, line_dates): + def _compute_depreciation_amount_per_fiscal_year( + self, table, line_dates, depreciation_start_date, + depreciation_stop_date): digits = self.env['decimal.precision'].precision_get('Account') fy_residual_amount = self.depreciation_base i_max = len(table) - 1 asset_sign = self.depreciation_base >= 0 and 1 or -1 + day_amount = 0.0 + if self.days_calc: + days = (depreciation_stop_date - depreciation_start_date).days + 1 + day_amount = self.depreciation_base / days + for i, entry in enumerate(table): if self.method_time == 'year': - year_amount = self._compute_year_amount(fy_residual_amount) + year_amount = self._compute_year_amount( + fy_residual_amount, depreciation_start_date, + depreciation_stop_date, entry) if self.method_period == 'year': period_amount = year_amount elif self.method_period == 'quarter': @@ -792,6 +848,7 @@ class AccountAsset(models.Model): entry.update({ 'period_amount': period_amount, 'fy_amount': fy_amount, + 'day_amount': day_amount, }) if self.method_time == 'year': fy_residual_amount -= fy_amount @@ -816,26 +873,36 @@ class AccountAsset(models.Model): fy_amount_check = 0.0 fy_amount = entry['fy_amount'] li_max = len(line_dates) - 1 + prev_date = max(entry['date_start'], depreciation_start_date) for li, line_date in enumerate(line_dates): - + line_days = (line_date - prev_date).days + 1 if round(remaining_value, digits) == 0.0: break if (line_date > min(entry['date_stop'], depreciation_stop_date) and not (i == i_max and li == li_max)): + prev_date = line_date break + else: + prev_date = line_date + relativedelta(days=1) if self.method == 'degr-linear' \ and asset_sign * (fy_amount - fy_amount_check) < 0: break if i == 0 and li == 0: - amount = self._get_first_period_amount( - table, entry, depreciation_start_date, line_dates) - amount = round(amount, digits) + if entry.get('day_amount') > 0.0: + amount = line_days * entry.get('day_amount') + else: + amount = self._get_first_period_amount( + table, entry, depreciation_start_date, line_dates) + amount = round(amount, digits) else: - amount = entry.get('period_amount') + if entry.get('day_amount') > 0.0: + amount = line_days * entry.get('day_amount') + else: + amount = entry.get('period_amount') # last year, last entry # Handle rounding deviations. @@ -847,6 +914,7 @@ class AccountAsset(models.Model): fy_amount_check += amount line = { 'date': line_date, + 'days': line_days, 'amount': amount, 'depreciated_value': depreciated_value, 'remaining_value': remaining_value, @@ -862,7 +930,7 @@ class AccountAsset(models.Model): # was compensated in the first FY depreciation line. # The code has now been simplified with compensation # always in last FT depreciation line. - if self.method_time == 'year': + if self.method_time == 'year' and not entry.get('day_amount'): if round(fy_amount_check - fy_amount, digits) != 0: diff = fy_amount_check - fy_amount amount = amount - diff @@ -896,7 +964,8 @@ class AccountAsset(models.Model): def _compute_depreciation_table(self): table = [] - if self.method_time in ['year', 'number'] and not self.method_number: + if self.method_time in ['year', 'number'] \ + and not self.method_number and not self.method_end: return table company = self.company_id asset_date_start = self.date_start @@ -922,7 +991,7 @@ class AccountAsset(models.Model): line_dates = self._compute_line_dates( table, depreciation_start_date, depreciation_stop_date) table = self._compute_depreciation_amount_per_fiscal_year( - table, line_dates, + table, line_dates, depreciation_start_date, depreciation_stop_date ) # Step 2: # Spread depreciation amount per fiscal year diff --git a/account_asset_management/models/account_asset_line.py b/account_asset_management/models/account_asset_line.py index 5fda7e66a..326f9c7a2 100644 --- a/account_asset_management/models/account_asset_line.py +++ b/account_asset_management/models/account_asset_line.py @@ -43,6 +43,10 @@ class AccountAssetLine(models.Model): string='Amount Already Depreciated', store=True) line_date = fields.Date(string='Date', required=True) + line_days = fields.Integer( + string='Days', + readonly=True, + ) move_id = fields.Many2one( comodel_name='account.move', string='Depreciation Entry', readonly=True) diff --git a/account_asset_management/models/account_asset_profile.py b/account_asset_management/models/account_asset_profile.py index f2f03fa17..cd3b1f659 100644 --- a/account_asset_management/models/account_asset_profile.py +++ b/account_asset_management/models/account_asset_profile.py @@ -90,6 +90,22 @@ class AccountAssetProfile(models.Model): "number of depreciation lines.\n" " * Number of Years: Specify the number of years " "for the depreciation.\n") + days_calc = fields.Boolean( + string='Calculate by days', + default=False, + help="Use number of days to calculate depreciation amount") + use_leap_years = fields.Boolean( + string='Use leap years', + default=False, + help="If not set, the system will distribute evenly the amount to " + "amortize across the years, based on the number of years. " + "So the amount per year will be the " + "depreciation base / number of years.\n " + "If set, the system will consider if the current year " + "is a leap year. The amount to depreciate per year will be " + "calculated as depreciation base / (depreciation end date - " + "start date + 1) * days in the current year.", + ) prorata = fields.Boolean( string='Prorata Temporis', help="Indicates that the first depreciation entry for this asset " @@ -137,7 +153,7 @@ class AccountAssetProfile(models.Model): 'Number' and 'End' Time Methods. """ return [ - ('year', _('Number of Years')), + ('year', _('Number of Years or end date')), ] @api.multi diff --git a/account_asset_management/readme/CONTRIBUTORS.rst b/account_asset_management/readme/CONTRIBUTORS.rst index bf16c0bbd..6afc965f8 100644 --- a/account_asset_management/readme/CONTRIBUTORS.rst +++ b/account_asset_management/readme/CONTRIBUTORS.rst @@ -7,3 +7,5 @@ - Akim Juillerat - Henrik Norlin (Apps2GROW) - Maxence Groine +- Kitti Upariphutthiphong +- Saran Lim. diff --git a/account_asset_management/readme/HISTORY.rst b/account_asset_management/readme/HISTORY.rst index c192efa62..d68c9d780 100644 --- a/account_asset_management/readme/HISTORY.rst +++ b/account_asset_management/readme/HISTORY.rst @@ -1,3 +1,8 @@ +12.0.2.1.0 (2019-10-21) +~~~~~~~~~~~~~~~~~~~~~~~ + +* [IMP] Add option to calculate depreciation table by days + 12.0.1.0.0 (2019-01-13) ~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/account_asset_management/static/description/index.html b/account_asset_management/static/description/index.html index 02e2eba13..20dd2d65e 100644 --- a/account_asset_management/static/description/index.html +++ b/account_asset_management/static/description/index.html @@ -380,34 +380,41 @@ the standard account_asset module from Odoo.

Table of contents

-

Configuration

+

Configuration

It is recommended to configure your Purchase Journal with “Group Invoice Lines” to avoid the creation of separate assets per Supplier Invoice Line.

-

Usage

+

Usage

The module in NOT compatible with the standard account_asset module.

-

Changelog

+

Changelog

-

12.0.1.0.0 (2019-01-13)

+

12.0.1.1.0 (2019-07-08)

+
    +
  • [IMP] Add option to calculate depreciation table by days
  • +
+
+
+

12.0.1.0.0 (2019-01-13)

  • [BREAKING] account.asset: parent_path has replaced parent_left & parent_right (TODO: migration script)
  • [BREAKING] account.asset.recompute.trigger: depends on date_range.py (TODO: re-implement in account_fiscal_year.py)
  • @@ -415,7 +422,7 @@ creation of separate assets per Supplier Invoice Line.

-

Bug Tracker

+

Bug Tracker

Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us smashing it by providing a detailed and welcomed @@ -423,15 +430,15 @@ If you spotted it first, help us smashing it by providing a detailed and welcome

Do not contact contributors directly about support or help with technical issues.

-

Credits

+

Credits

-

Authors

+

Authors

  • Noviat
-

Contributors

+

Contributors

-

Maintainers

+

Maintainers

This module is maintained by the OCA.

Odoo Community Association

OCA, or the Odoo Community Association, is a nonprofit organization whose diff --git a/account_asset_management/tests/test_account_asset_management.py b/account_asset_management/tests/test_account_asset_management.py index 2cc5622b0..a53d58b26 100644 --- a/account_asset_management/tests/test_account_asset_management.py +++ b/account_asset_management/tests/test_account_asset_management.py @@ -515,3 +515,96 @@ class TestAssetManagement(SavepointCase): dlines = dlines.sorted(key=lambda l: l.line_date) self.assertAlmostEqual(dlines[0].depreciated_value, 0.0) self.assertAlmostEqual(dlines[-1].remaining_value, 0.0) + + def test_12_prorata_days_calc(self): + """Prorata temporis depreciation with days calc option.""" + asset = self.asset_model.create({ + 'name': 'test asset', + 'profile_id': self.ref('account_asset_management.' + 'account_asset_profile_car_5Y'), + 'purchase_value': 3333, + 'salvage_value': 0, + 'date_start': time.strftime('%Y-07-07'), + 'method_time': 'year', + 'method_number': 5, + 'method_period': 'month', + 'prorata': True, + 'days_calc': True, + 'use_leap_years': False, + }) + asset.compute_depreciation_board() + asset.refresh() + if calendar.isleap(date.today().year) or \ + calendar.isleap(date.today().year + 1): + day_rate = 3333 / 1827 # 3333 / 1827 depreciation days + else: + day_rate = 3333 / 1826 # 3333 / 1826 depreciation days + for i in range(1, 10): + self.assertAlmostEqual( + asset.depreciation_line_ids[i].amount, + asset.depreciation_line_ids[i].line_days * day_rate, places=2) + + # Last depreciation remaining + if calendar.isleap(date.today().year) or \ + calendar.isleap(date.today().year + 1): + self.assertAlmostEqual( + asset.depreciation_line_ids[-1].amount, 11.05, places=2) + else: + self.assertAlmostEqual( + asset.depreciation_line_ids[-1].amount, 11.05, places=2) + + def test_13_use_leap_year(self): + # When you use the depreciation with years method and using lap years, + # the depreciation amount is calculated as 10000 / 1826 days * 365 days + # = yearly depreciation amount of 1998.90. + # Then 1998.90 / 12 = 166.58 + asset = self.asset_model.create({ + 'name': 'test asset', + 'profile_id': self.ref('account_asset_management.' + 'account_asset_profile_car_5Y'), + 'purchase_value': 10000, + 'salvage_value': 0, + 'date_start': time.strftime('2019-01-01'), + 'method_time': 'year', + 'method_number': 5, + 'method_period': 'month', + 'prorata': False, + 'days_calc': False, + 'use_leap_years': True, + }) + asset.compute_depreciation_board() + asset.refresh() + for i in range(2, 11): + self.assertAlmostEqual( + asset.depreciation_line_ids[i].amount, 166.58, places=2) + self.assertAlmostEqual( + asset.depreciation_line_ids[13].depreciated_value, 1998.90, + places=2) + + def test_14_not_use_leap_year(self): + # When you run a depreciation with method = 'year' and no not use + # lap years you divide 1000 / 5 years = 2000, then divided by 12 months + # to get 166.67 per month, equal for all periods. + asset = self.asset_model.create({ + 'name': 'test asset', + 'profile_id': self.ref('account_asset_management.' + 'account_asset_profile_car_5Y'), + 'purchase_value': 10000, + 'salvage_value': 0, + 'date_start': time.strftime('2019-01-01'), + 'method_time': 'year', + 'method_number': 5, + 'method_period': 'month', + 'prorata': False, + 'days_calc': False, + 'use_leap_years': False, + }) + asset.compute_depreciation_board() + asset.refresh() + for i in range(1, 11): + self.assertAlmostEqual( + asset.depreciation_line_ids[1].amount, 166.67, places=2) + # In the last month of the fiscal year we compensate for the small + # deviations if that is necessary. + self.assertAlmostEqual( + asset.depreciation_line_ids[12].amount, 166.63, places=2) diff --git a/account_asset_management/views/account_asset.xml b/account_asset_management/views/account_asset.xml index 8c28fe939..182470eb2 100644 --- a/account_asset_management/views/account_asset.xml +++ b/account_asset_management/views/account_asset.xml @@ -65,7 +65,10 @@ attrs="{'invisible': [('method_time', 'not in', ['number', 'year'])], 'required': [('method_time', 'in', ['number', 'year'])]}"/> + attrs="{'required': [('method_time', '=', 'end')], 'invisible': [('method_time', 'in', ['number'])]}"/> + + @@ -86,6 +89,7 @@ + diff --git a/account_asset_management/views/account_asset_profile.xml b/account_asset_management/views/account_asset_profile.xml index b6053505b..2f684a17d 100644 --- a/account_asset_management/views/account_asset_profile.xml +++ b/account_asset_management/views/account_asset_profile.xml @@ -29,6 +29,7 @@ +