Add support for depreciable assets

The analytic entries should not be created when posting the invoice for
depreciable assets. Instead entries must be created when the assets are
depreciated.

issue5909
review26731002
This commit is contained in:
Cédric Krier
2016-10-12 22:36:54 +02:00
parent fe4c725ef8
commit 43a7b9799f
9 changed files with 243 additions and 4 deletions
+2
View File
@@ -1,3 +1,5 @@
* Add support for depreciable assets
Version 4.0.0 - 2016-05-02
* Bug fixes (see mercurial logs for details)
* Add Python3 support
+2
View File
@@ -3,10 +3,12 @@
from trytond.pool import Pool
from .invoice import *
from . import asset
def register():
Pool.register(
InvoiceLine,
AnalyticAccountEntry,
asset.Asset,
module='analytic_invoice', type_='model')
+52
View File
@@ -0,0 +1,52 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
from trytond.pool import Pool, PoolMeta
from trytond.model import fields
from trytond.modules.analytic_account import AnalyticMixin
__all__ = ['Asset']
class Asset(AnalyticMixin):
__metaclass__ = PoolMeta
__name__ = 'account.asset'
@fields.depends('supplier_invoice_line', 'analytic_accounts')
def on_change_supplier_invoice_line(self):
pool = Pool()
Entry = pool.get('analytic.account.entry')
super(Asset, self).on_change_supplier_invoice_line()
if self.supplier_invoice_line:
entries = []
for entry in self.supplier_invoice_line.analytic_accounts:
new_entry = Entry()
for field in Entry._fields:
if field in {'origin', 'id'}:
continue
setattr(new_entry, field, getattr(entry, field))
entries.append(new_entry)
self.analytic_accounts = entries
def get_move(self, line):
move = super(Asset, self).get_move(line)
self.set_analytic_lines(move)
return move
def get_closing_move(self, account):
move = super(Asset, self).get_closing_move(account)
self.set_analytic_lines(move)
return move
def set_analytic_lines(self, move):
"Fill analytic lines on lines with expense account"
if self.analytic_accounts:
for line in move.lines:
if line.account != self.product.account_expense_used:
continue
analytic_lines = []
for entry in self.analytic_accounts:
analytic_lines.extend(
entry.get_analytic_lines(line, move.date))
line.analytic_lines = analytic_lines
+12
View File
@@ -0,0 +1,12 @@
<?xml version="1.0"?>
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
this repository contains the full copyright notices and license terms. -->
<tryton>
<data depends="account_asset">
<record model="ir.ui.view" id="asset_view_form">
<field name="model">account.asset</field>
<field name="inherit" ref="account_asset.asset_view_form"/>
<field name="name">asset_form</field>
</record>
</data>
</tryton>
+32 -4
View File
@@ -10,6 +10,7 @@ __all__ = ['InvoiceLine', 'AnalyticAccountEntry']
class InvoiceLine(AnalyticMixin):
__metaclass__ = PoolMeta
__name__ = 'account.invoice.line'
@classmethod
@@ -37,7 +38,14 @@ class InvoiceLine(AnalyticMixin):
def get_move_lines(self):
lines = super(InvoiceLine, self).get_move_lines()
if self.analytic_accounts:
if self.invoice and self.invoice.type:
type_ = self.invoice.type
else:
type_ = self.invoice_type
asset_depreciable = (self.product and type_ == 'in'
and self.product.type == 'assets'
and getattr(self.product, 'depreciable', False))
if self.analytic_accounts and not asset_depreciable:
date = self.invoice.accounting_date or self.invoice.invoice_date
for line in lines:
analytic_lines = []
@@ -54,24 +62,44 @@ class AnalyticAccountEntry:
@classmethod
def _get_origin(cls):
pool = Pool()
origins = super(AnalyticAccountEntry, cls)._get_origin()
return origins + ['account.invoice.line']
origins.append('account.invoice.line')
try:
pool.get('account.asset')
origins.append('account.asset')
except KeyError:
pass
return origins
@fields.depends('origin')
def on_change_with_company(self, name=None):
pool = Pool()
InvoiceLine = pool.get('account.invoice.line')
try:
Asset = pool.get('account.asset')
except KeyError:
Asset = None
company = super(AnalyticAccountEntry, self).on_change_with_company(
name)
if isinstance(self.origin, InvoiceLine):
if (isinstance(self.origin, InvoiceLine)
or (Asset and isinstance(self.origin, Asset))):
company = self.origin.company.id
return company
@classmethod
def search_company(cls, name, clause):
pool = Pool()
domain = super(AnalyticAccountEntry, cls).search_company(name, clause),
return ['OR',
domain = ['OR',
domain,
(('origin.company',) + tuple(clause[1:]) +
('account.invoice.line',)),
]
try:
pool.get('account.asset')
domain.append(
(('origin.company',) + tuple(clause[1:]) + ('account.asset',)))
except KeyError:
pass
return domain
+127
View File
@@ -0,0 +1,127 @@
=====================================
Analytic Invoice with Assets Scenario
=====================================
Imports::
>>> import datetime
>>> from dateutil.relativedelta import relativedelta
>>> from decimal import Decimal
>>> from operator import attrgetter
>>> from proteus import Model, Wizard
>>> from trytond.tests.tools import install_modules
>>> from trytond.modules.company.tests.tools import create_company, \
... get_company
>>> from trytond.modules.account.tests.tools import create_fiscalyear, \
... create_chart, get_accounts
>>> from trytond.modules.account_invoice.tests.tools import \
... set_fiscalyear_invoice_sequences, create_payment_term
>>> from trytond.modules.account_asset.tests.tools \
... import add_asset_accounts
>>> today = datetime.date.today()
Install analytic_invoice and account_asset::
>>> config = install_modules(['analytic_invoice', 'account_asset'])
Create company::
>>> _ = create_company()
>>> company = get_company()
Create fiscal year::
>>> fiscalyear = set_fiscalyear_invoice_sequences(
... create_fiscalyear(company))
>>> fiscalyear.click('create_period')
Create chart of accounts::
>>> _ = create_chart(company)
>>> accounts = add_asset_accounts(get_accounts(company), company)
>>> revenue = accounts['revenue']
>>> asset_account = accounts['asset']
>>> expense = accounts['expense']
>>> depreciation_account = accounts['depreciation']
Create analytic accounts::
>>> AnalyticAccount = Model.get('analytic_account.account')
>>> root = AnalyticAccount(type='root', name='Root')
>>> root.save()
>>> analytic_account = AnalyticAccount(root=root, parent=root,
... name='Analytic')
>>> analytic_account.save()
Create supplier::
>>> Party = Model.get('party.party')
>>> supplier = Party(name='Supplier')
>>> supplier.save()
Create an asset::
>>> ProductUom = Model.get('product.uom')
>>> unit, = ProductUom.find([('name', '=', 'Unit')])
>>> ProductTemplate = Model.get('product.template')
>>> Product = Model.get('product.product')
>>> asset_product = Product()
>>> asset_template = ProductTemplate()
>>> asset_template.name = 'Asset'
>>> asset_template.type = 'assets'
>>> asset_template.default_uom = unit
>>> asset_template.list_price = Decimal('1000')
>>> asset_template.cost_price = Decimal('1000')
>>> asset_template.depreciable = True
>>> asset_template.account_expense = expense
>>> asset_template.account_revenue = revenue
>>> asset_template.account_asset = asset_account
>>> asset_template.account_depreciation = depreciation_account
>>> asset_template.depreciation_duration = Decimal(10)
>>> asset_template.save()
>>> asset_product.template = asset_template
>>> asset_product.save()
Buy an asset::
>>> Invoice = Model.get('account.invoice')
>>> InvoiceLine = Model.get('account.invoice.line')
>>> supplier_invoice = Invoice(type='in')
>>> supplier_invoice.party = supplier
>>> invoice_line = supplier_invoice.lines.new()
>>> invoice_line.product = asset_product
>>> invoice_line.quantity = 1
>>> invoice_line.unit_price = Decimal('1000')
>>> entry, = invoice_line.analytic_accounts
>>> entry.account = analytic_account
>>> supplier_invoice.invoice_date = today + relativedelta(day=1, month=1)
>>> supplier_invoice.click('post')
>>> supplier_invoice.state
u'posted'
>>> invoice_line, = supplier_invoice.lines
>>> analytic_account.debit
Decimal('0.00')
>>> analytic_account.credit
Decimal('0.00')
Depreciate the asset::
>>> Asset = Model.get('account.asset')
>>> asset = Asset()
>>> asset.product = asset_product
>>> asset.supplier_invoice_line = invoice_line
>>> asset.residual_value = Decimal(0)
>>> asset.click('create_lines')
>>> asset.click('run')
Create Moves for 1 month::
>>> create_moves = Wizard('account.asset.create_moves')
>>> create_moves.form.date = (supplier_invoice.invoice_date
... + relativedelta(months=1))
>>> create_moves.execute('create_moves')
>>> analytic_account.reload()
>>> analytic_account.debit
Decimal('100.00')
>>> analytic_account.credit
Decimal('0.00')
+4
View File
@@ -21,4 +21,8 @@ def suite():
tearDown=doctest_teardown, encoding='utf-8',
checker=doctest_checker,
optionflags=doctest.REPORT_ONLY_FIRST_FAILURE))
suite.addTests(doctest.DocFileSuite('scenario_analytic_invoice_asset.rst',
tearDown=doctest_teardown, encoding='utf-8',
checker=doctest_checker,
optionflags=doctest.REPORT_ONLY_FIRST_FAILURE))
return suite
+2
View File
@@ -3,5 +3,7 @@ version=4.1.0
depends:
account_invoice
analytic_account
extras_depend:
account_asset
xml:
invoice.xml
+10
View File
@@ -0,0 +1,10 @@
<?xml version="1.0"?>
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
this repository contains the full copyright notices and license terms. -->
<data>
<xpath expr="/form/notebook/page[@id='lines']" position="after">
<page name="analytic_accounts" col="1">
<field name="analytic_accounts"/>
</page>
</xpath>
</data>