Merge lp:~openerp-dev/openobject-addons/7.0-account-assets_fixes-acl into lp:openobject-addons/7.0

Proposed by Anaël Closson (openerp)
Status: Needs review
Proposed branch: lp:~openerp-dev/openobject-addons/7.0-account-assets_fixes-acl
Merge into: lp:openobject-addons/7.0
Diff against target: 267 lines (+142/-23)
4 files modified
account_asset/account_asset.py (+33/-22)
account_asset/test/account_asset_wizard.yml (+1/-1)
account_asset/tests/__init__.py (+26/-0)
account_asset/tests/test_depreciation.py (+82/-0)
To merge this branch: bzr merge lp:~openerp-dev/openobject-addons/7.0-account-assets_fixes-acl
Reviewer Review Type Date Requested Status
OpenERP Core Team Pending
Review via email: mp+211361@code.launchpad.net
To post a comment you must log in.
9907. By Anaël Closson (openerp)

[FIX] account assets: prorata temporis tooltip should match the fix from revision 9906.

9908. By Martin Trigaux (OpenERP)

[IMP] use finds method account.fiscalyear

9909. By Martin Trigaux (OpenERP)

[FIX] copy should not keep history and move lines of previous asset

9910. By Martin Trigaux (OpenERP)

[FIX] compute correctly the depreciation lines to recreate in 'Ending Date' method

9911. By Martin Trigaux (OpenERP)

[ADD] some tests, fixed the test account_asset_wizard as the number of depreciation was fixed

Unmerged revisions

9911. By Martin Trigaux (OpenERP)

[ADD] some tests, fixed the test account_asset_wizard as the number of depreciation was fixed

9910. By Martin Trigaux (OpenERP)

[FIX] compute correctly the depreciation lines to recreate in 'Ending Date' method

9909. By Martin Trigaux (OpenERP)

[FIX] copy should not keep history and move lines of previous asset

9908. By Martin Trigaux (OpenERP)

[IMP] use finds method account.fiscalyear

9907. By Anaël Closson (openerp)

[FIX] account assets: prorata temporis tooltip should match the fix from revision 9906.

9906. By Anaël Closson (openerp)

[FIX] Assets depreciation: several fixes:
 - first depreciation always starts on 01/01/asset_purchase_year
 - prorata temporis is always computed against start of year

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'account_asset/account_asset.py'
2--- account_asset/account_asset.py 2014-01-17 10:40:37 +0000
3+++ account_asset/account_asset.py 2014-03-26 15:52:48 +0000
4@@ -51,7 +51,7 @@
5 " * Number of Depreciations: Fix the number of depreciation lines and the time between 2 depreciations.\n" \
6 " * Ending Date: Choose the time between 2 depreciations and the date the depreciations won't go beyond."),
7 'method_end': fields.date('Ending date'),
8- 'prorata':fields.boolean('Prorata Temporis', help='Indicates that the first depreciation entry for this asset have to be done from the purchase date instead of the first January'),
9+ 'prorata':fields.boolean('Prorata Temporis', help='Indicates that the first depreciation entry for this asset have to be done from the purchase date instead of the first day of depreciation period.'),
10 'open_asset': fields.boolean('Skip Draft State', help="Check this if you want to automatically confirm the assets of this category when created by invoices."),
11 }
12
13@@ -105,19 +105,16 @@
14
15 def _compute_board_amount(self, cr, uid, asset, i, residual_amount, amount_to_depr, undone_dotation_number, posted_depreciation_line_ids, total_days, depreciation_date, context=None):
16 #by default amount = 0
17+ assert undone_dotation_number > len(posted_depreciation_line_ids)
18 amount = 0
19 if i == undone_dotation_number:
20 amount = residual_amount
21 else:
22 if asset.method == 'linear':
23 amount = amount_to_depr / (undone_dotation_number - len(posted_depreciation_line_ids))
24- if asset.prorata:
25- amount = amount_to_depr / asset.method_number
26- days = total_days - float(depreciation_date.strftime('%j'))
27+ if asset.prorata and i == 1:
28 if i == 1:
29- amount = (amount_to_depr / asset.method_number) / total_days * days
30- elif i == undone_dotation_number:
31- amount = (amount_to_depr / asset.method_number) / total_days * (total_days - days)
32+ amount = amount * (30 - float(depreciation_date.strftime('%j')) % 30) / 30
33 elif asset.method == 'degressive':
34 amount = residual_amount * asset.method_progress_factor
35 if asset.prorata:
36@@ -128,21 +125,29 @@
37 amount = (residual_amount * asset.method_progress_factor) / total_days * (total_days - days)
38 return amount
39
40+ # TODO in trunk: rename total_days into number_posted_lines
41 def _compute_board_undone_dotation_nb(self, cr, uid, asset, depreciation_date, total_days, context=None):
42- undone_dotation_number = asset.method_number
43+ """Compute the number of remaining depreciation line to compute (skipping posted one)
44+ asset: browse record (account.asset) of the current asset
45+ depreciation_date: date of the next depreciation
46+ total_days: the number
47+ """
48 if asset.method_time == 'end':
49 end_date = datetime.strptime(asset.method_end, '%Y-%m-%d')
50 undone_dotation_number = 0
51 while depreciation_date <= end_date:
52 depreciation_date = (datetime(depreciation_date.year, depreciation_date.month, depreciation_date.day) + relativedelta(months=+asset.method_period))
53 undone_dotation_number += 1
54- if asset.prorata:
55- undone_dotation_number += 1
56+ undone_dotation_number += self.pool.get('account.asset.depreciation.line').search(cr, uid, [('asset_id', '=', asset.id), ('move_id', '!=', False)], count=True)
57+ else:
58+ undone_dotation_number = asset.method_number
59 return undone_dotation_number
60
61 def compute_depreciation_board(self, cr, uid, ids, context=None):
62+ """Generate depreciation lines, skip posted entries and recreate unposted"""
63 depreciation_lin_obj = self.pool.get('account.asset.depreciation.line')
64 currency_obj = self.pool.get('res.currency')
65+ fy_obj = self.pool.get('account.fiscalyear')
66 for asset in self.browse(cr, uid, ids, context=context):
67 if asset.value_residual == 0.0:
68 continue
69@@ -155,23 +160,29 @@
70 if asset.prorata:
71 depreciation_date = datetime.strptime(self._get_last_depreciation_date(cr, uid, [asset.id], context)[asset.id], '%Y-%m-%d')
72 else:
73- # depreciation_date = 1st January of purchase year
74+ # depreciation_date = first day of current period
75 purchase_date = datetime.strptime(asset.purchase_date, '%Y-%m-%d')
76- #if we already have some previous validated entries, starting date isn't 1st January but last entry + method period
77+
78+ #if we already have some previous validated entries, starting date isn't 1st day of period but last entry + method period
79 if (len(posted_depreciation_line_ids)>0):
80 last_depreciation_date = datetime.strptime(depreciation_lin_obj.browse(cr,uid,posted_depreciation_line_ids[0],context=context).depreciation_date, '%Y-%m-%d')
81 depreciation_date = (last_depreciation_date+relativedelta(months=+asset.method_period))
82 else:
83- depreciation_date = datetime(purchase_date.year, 1, 1)
84+ # else we should start at the first day of the period, relative to the start of fiscal year
85+ fiscal_year_ids = fy_obj.finds(cr, uid, purchase_date, context=context)
86+ fiscal_year = fiscal_year_ids and fy_obj.browse(cr, uid, fiscal_year_ids[0], context=context)
87+ delta = relativedelta(purchase_date, (fiscal_year and datetime.strptime(fiscal_year.date_start, '%Y-%m-%d') or datetime(purchase_date.year, 1, 1)))
88+ period_start = purchase_date + relativedelta(months=-((delta.years * 12 + delta.months) % asset.method_period))
89+ depreciation_date = datetime(period_start.year, period_start.month, 1)
90+
91 day = depreciation_date.day
92 month = depreciation_date.month
93 year = depreciation_date.year
94- total_days = (year % 4) and 365 or 366
95+ total_days = asset.method_period * 30 # we use month of 30 days for accounting
96
97- undone_dotation_number = self._compute_board_undone_dotation_nb(cr, uid, asset, depreciation_date, total_days, context=context)
98- for x in range(len(posted_depreciation_line_ids), undone_dotation_number):
99- i = x + 1
100- amount = self._compute_board_amount(cr, uid, asset, i, residual_amount, amount_to_depr, undone_dotation_number, posted_depreciation_line_ids, total_days, depreciation_date, context=context)
101+ undone_dotation_number = self._compute_board_undone_dotation_nb(cr, uid, asset, depreciation_date, len(posted_depreciation_line_ids), context=context)
102+ for sequence in range(len(posted_depreciation_line_ids) + 1, undone_dotation_number + 1):
103+ amount = self._compute_board_amount(cr, uid, asset, sequence, residual_amount, amount_to_depr, undone_dotation_number, posted_depreciation_line_ids, total_days, depreciation_date, context=context)
104 company_currency = asset.company_id.currency_id.id
105 current_currency = asset.currency_id.id
106 # compute amount into company currency
107@@ -180,8 +191,8 @@
108 vals = {
109 'amount': amount,
110 'asset_id': asset.id,
111- 'sequence': i,
112- 'name': str(asset.id) +'/' + str(i),
113+ 'sequence': sequence,
114+ 'name': str(asset.id) +'/' + str(sequence),
115 'remaining_value': residual_amount,
116 'depreciated_value': (asset.purchase_value - asset.salvage_value) - (residual_amount + amount),
117 'depreciation_date': depreciation_date.strftime('%Y-%m-%d'),
118@@ -270,7 +281,7 @@
119 help="Choose the method to use to compute the dates and number of depreciation lines.\n"\
120 " * Number of Depreciations: Fix the number of depreciation lines and the time between 2 depreciations.\n" \
121 " * Ending Date: Choose the time between 2 depreciations and the date the depreciations won't go beyond."),
122- 'prorata':fields.boolean('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'),
123+ 'prorata':fields.boolean('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 day of depreciation period.'),
124 'history_ids': fields.one2many('account.asset.history', 'asset_id', 'History', readonly=True),
125 'depreciation_line_ids': fields.one2many('account.asset.depreciation.line', 'asset_id', 'Depreciation Lines', readonly=True, states={'draft':[('readonly',False)],'open':[('readonly',False)]}),
126 'salvage_value': fields.float('Salvage Value', digits_compute=dp.get_precision('Account'), help="It is the amount you plan to have that you cannot depreciate.", readonly=True, states={'draft':[('readonly',False)]}),
127@@ -330,7 +341,7 @@
128 default = {}
129 if context is None:
130 context = {}
131- default.update({'depreciation_line_ids': [], 'state': 'draft'})
132+ default.update({'depreciation_line_ids': [], 'account_move_line_ids': [], 'history_ids': [], 'state': 'draft'})
133 return super(account_asset_asset, self).copy(cr, uid, id, default, context=context)
134
135 def _compute_entries(self, cr, uid, ids, period_id, context=None):
136
137=== modified file 'account_asset/test/account_asset_wizard.yml'
138--- account_asset/test/account_asset_wizard.yml 2011-12-20 10:08:42 +0000
139+++ account_asset/test/account_asset_wizard.yml 2014-03-26 15:52:48 +0000
140@@ -13,7 +13,7 @@
141 I check the proper depreciation lines created.
142 -
143 !assert {model: account.asset.asset, id: account_asset.account_asset_asset_office0}:
144- - method_number == len(depreciation_line_ids) -1
145+ - method_number == len(depreciation_line_ids)
146 -
147 I create a period to compute a asset on period.
148 -
149
150=== added directory 'account_asset/tests'
151=== added file 'account_asset/tests/__init__.py'
152--- account_asset/tests/__init__.py 1970-01-01 00:00:00 +0000
153+++ account_asset/tests/__init__.py 2014-03-26 15:52:48 +0000
154@@ -0,0 +1,26 @@
155+# -*- coding: utf-8 -*-
156+##############################################################################
157+#
158+# OpenERP, Open Source Business Applications
159+# Copyright (c) 2014-TODAY OpenERP S.A. <http://openerp.com>
160+#
161+# This program is free software: you can redistribute it and/or modify
162+# it under the terms of the GNU Affero General Public License as
163+# published by the Free Software Foundation, either version 3 of the
164+# License, or (at your option) any later version.
165+#
166+# This program is distributed in the hope that it will be useful,
167+# but WITHOUT ANY WARRANTY; without even the implied warranty of
168+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
169+# GNU Affero General Public License for more details.
170+#
171+# You should have received a copy of the GNU Affero General Public License
172+# along with this program. If not, see <http://www.gnu.org/licenses/>.
173+#
174+##############################################################################
175+
176+from . import test_depreciation
177+
178+checks = [
179+ test_depreciation,
180+]
181
182=== added file 'account_asset/tests/test_depreciation.py'
183--- account_asset/tests/test_depreciation.py 1970-01-01 00:00:00 +0000
184+++ account_asset/tests/test_depreciation.py 2014-03-26 15:52:48 +0000
185@@ -0,0 +1,82 @@
186+# -*- coding: utf-8 -*-
187+##############################################################################
188+#
189+# OpenERP, Open Source Business Applications
190+# Copyright (c) 2012-TODAY OpenERP S.A. <http://openerp.com>
191+#
192+# This program is free software: you can redistribute it and/or modify
193+# it under the terms of the GNU Affero General Public License as
194+# published by the Free Software Foundation, either version 3 of the
195+# License, or (at your option) any later version.
196+#
197+# This program is distributed in the hope that it will be useful,
198+# but WITHOUT ANY WARRANTY; without even the implied warranty of
199+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
200+# GNU Affero General Public License for more details.
201+#
202+# You should have received a copy of the GNU Affero General Public License
203+# along with this program. If not, see <http://www.gnu.org/licenses/>.
204+#
205+##############################################################################
206+
207+from openerp.tests import common
208+
209+import time
210+
211+class TestDepreciation(common.TransactionCase):
212+
213+ def setUp(self):
214+ super(TestDepreciation, self).setUp()
215+
216+ # Usefull models
217+ self.ir_model_data = self.registry('ir.model.data')
218+ self.asset = self.registry('account.asset.asset')
219+ self.asset_line = self.registry('account.asset.depreciation.line')
220+ self.useless_category_id = self.ir_model_data.get_object_reference(self.cr, self.uid, 'account_asset', 'account_asset_category_fixedassets0')[1]
221+
222+ def test_yearly(self):
223+ cr, uid, context = self.cr, self.uid, {}
224+ asset_id = self.asset.create(cr, uid, {
225+ 'name': 'A 5 years car',
226+ 'category_id': self.useless_category_id,
227+ 'purchase_value': 10000,
228+ 'method': 'linear',
229+ 'method_number': 5,
230+ 'method_period': 12,
231+ 'purchase_date': time.strftime('%Y-01-01')
232+ }, context=context)
233+ asset = self.asset.browse(cr, uid, asset_id, context=context)
234+
235+ self.assertEquals(len(asset.depreciation_line_ids), 5, 'Incorrect number of depreciations for created asset')
236+ # make sure lines are sorted by sequence
237+ lines = sorted([line for line in asset.depreciation_line_ids], key=lambda line: line.sequence)
238+ remanining_value = asset.purchase_value
239+ depreciation_amount = asset.purchase_value/asset.method_number
240+ for line in lines:
241+ self.assertEquals(line.amount, depreciation_amount, "Linear depreciation does not have equal depreciation")
242+ self.assertEquals(line.remaining_value, remanining_value-depreciation_amount, "Remaining value should be decreased of the depreciation amount")
243+ remanining_value -= depreciation_amount
244+
245+ def test_monthly(self):
246+ cr, uid, context = self.cr, self.uid, {}
247+
248+ asset_id = self.asset.create(cr, uid, {
249+ 'name': 'A 4 months coffee machine',
250+ 'category_id': self.useless_category_id,
251+ 'purchase_value': 24,
252+ 'method': 'linear',
253+ 'method_number': 4,
254+ 'method_period': 1,
255+ 'purchase_date': time.strftime('%Y-05-15')
256+ }, context=context)
257+ asset = self.asset.browse(cr, uid, asset_id, context=context)
258+
259+ self.assertEquals(len(asset.depreciation_line_ids), 4, "Incorrect number of depreciations for created asset")
260+ lines = sorted([line for line in asset.depreciation_line_ids], key=lambda line: line.sequence)
261+ self.assertEquals(lines[0].depreciation_date, time.strftime('%Y-05-01'), "First depreciation should be the first day of the current period")
262+
263+ self.asset_line.create_move(cr, uid, [lines[0].id], context=context)
264+ self.asset_line.create_move(cr, uid, [lines[1].id], context=context)
265+
266+ self.asset.compute_depreciation_board(cr, uid, [asset_id], context=context)
267+ self.assertEquals(len(asset.depreciation_line_ids), 4, "The number of depreciation lines has changed when some are posted")