Asset Depreciation By Category

Membuat Depresiasi Aset Secara Masif Berdasarkan Kategori

Assalamu'alaikum Warohmatullah..

Perkenalkan saya Agus Priyanto,  pada kesempatan kali ini saya ingin membahas tentang depresiasi aset. Secara default, odoo sudah memiliki fitur depresiasi aset seperti gambar di bawah ini 

Pada gambar di atas, kita dapat melakukan depresiasi dengan cara klik tombol merah yang ada pada Depreciation Board, dan tombol merah akan berubah warna menjadi kuning tanda bahwa depresiasi pada periode tersebut telah sukses. Akan tetapi pada artikel ini saya akan modifikasi fungsi depresiasi tersebut sehingga kita dapat melakukan depresiasi secara masal berdasarkan kategori aset.


Berikut adalah langkah-langkahnya :

1. Buat modul bernama "mass_depreciation_asset" (nama modul bebas),

2. Buka aplikasi text editor dan pilih modul yang sudah kita buat tadi dan edit file "__manifest__.py" dengan menambahkan depends "account_asset",

3. Buka file models/models.py dan masukkan kode di bawah ini 

import calendar
from datetime import date, datetime
from dateutil.relativedelta import relativedelta

from odoo import api, fields, models, _
from odoo.exceptions import UserError, ValidationError
from odoo.tools import DEFAULT_SERVER_DATE_FORMAT as DF
from odoo.tools import float_compare, float_is_zero

class AssetCategoryWizard(models.TransientModel):
_name = 'asset.category.wizard'

@api.depends('depreciation_view_ids.amount')
def _hitung_total_amount(self):
for records in self:
total = sum(record['amount'] for record in records.depreciation_view_ids)
records.update({
'total_amount' : total
})

@api.depends('depreciation_view_ids.amount')
def _hitung_total_item(self):
total = len(self.depreciation_view_ids)
self.update({
'total_item' : total
})

category_id = fields.Many2one('account.asset.category',string='Category Assets')
depreciation_ids = fields.Many2many('account.asset.depreciation.line', string='Depreciation List')
depreciation_view_ids = fields.Many2many('account.asset.depreciation.line', string='Depreciation List', store=False)
total_amount = fields.Float(string='Total Cost', readonly=True, compute='_hitung_total_amount')
total_item = fields.Integer(string='Total Item', readonly=True, compute='_hitung_total_item')

    pada kode di atas, terdapat field depreciation_ids yang akan kita gunakan untuk memproses depresiasi aset, sedangkan field depreciation_view_ids untuk menampilkan detail     aset yang ada pada depreciation_ids.  


4. Berikan kondisi onchange pada field category_id untuk memilih kategori aset


@api.onchange('category_id')
def select_depreciation(self):
asset_id = self.env['account.asset.asset'].search([('category_id','=',self.category_id.id)])
if self.po_location_id:
asset_id = self.env['account.asset.asset'].search([('category_id', '=', self.category_id.id),('po_location_id', '=', self.po_location_id.id)])
current_period = datetime.now().strftime('%Y-%m')
listings = []

for records in asset_id:
items = self.env['account.asset.depreciation.line'].search([('asset_id','=',records.id), ('move_id','=',False), ('move_check','=',False)], order='depreciation_date asc', limit=1)
for item in items:
depreciation_period = datetime.strptime(item.depreciation_date, '%Y-%m-%d').strftime('%Y-%m')
if depreciation_period <= current_period:
listings.append(items.id)

res = {
'value' : {
'depreciation_view_ids' : [(6,0,listings)]
},
}
return res

@api.onchange('depreciation_view_ids')
def change_view_line(self):
listings = []
for line in self.depreciation_view_ids:
listings.append(line.id)

return {
'value' : {
'depreciation_ids' : [(6,0,listings)]
}
}


5. Kemudian kita override method create_move() sehingga kita dapat memproses depresiasi secara masal.


@api.multi
@api.depends('move_id')
def _get_move_check(self):
for records in self.depreciation_ids:
for line in records:
line.move_check = bool(line.move_id)

@api.multi
def create_move(self, post_move=True):
for records in self.depreciation_ids:
created_moves = self.env['account.move']
prec = self.env['decimal.precision'].precision_get('Account')
for line in records:
if line.move_id:
raise UserError(_('This depreciation is already linked to a journal entry! Please post or delete it.'))
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
current_currency = line.asset_id.currency_id
amount = current_currency.with_context(date=depreciation_date).compute(line.amount, company_currency)
asset_name = line.asset_id.name + ' (%s/%s)' % (line.sequence, len(line.asset_id.depreciation_line_ids))
move_line_1 = {
'name': asset_name,
'account_id': category_id.account_depreciation_id.id,
'debit': 0.0 if float_compare(amount, 0.0, precision_digits=prec) > 0 else -amount,
'credit': amount if float_compare(amount, 0.0, precision_digits=prec) > 0 else 0.0,
'journal_id': category_id.journal_id.id,
'partner_id': line.asset_id.partner_id.id,
'analytic_account_id': category_id.account_analytic_id.id if category_id.type == 'sale' else False,
'currency_id': company_currency != current_currency and current_currency.id or False,
'amount_currency': company_currency != current_currency and - 1.0 * line.amount or 0.0,
}
move_line_2 = {
'name': asset_name,
'account_id': category_id.account_depreciation_expense_id.id,
'credit': 0.0 if float_compare(amount, 0.0, precision_digits=prec) > 0 else -amount,
'debit': amount if float_compare(amount, 0.0, precision_digits=prec) > 0 else 0.0,
'journal_id': category_id.journal_id.id,
'partner_id': line.asset_id.partner_id.id,
'analytic_account_id': category_id.account_analytic_id.id if category_id.type == 'purchase' else False,
'currency_id': company_currency != current_currency and current_currency.id or False,
'amount_currency': company_currency != current_currency and line.amount or 0.0,
}
move_vals = {
'ref': line.asset_id.code,
'date': depreciation_date or False,
'journal_id': category_id.journal_id.id,
'line_ids': [(0, 0, move_line_1), (0, 0, move_line_2)],
}
move = self.env['account.move'].create(move_vals)
line.write({'move_id': move.id, 'move_check': True})
created_moves |= move


6. Setelah file python selesai, sekarang kita akan membuat tampilannya pada views/views.xml


7. Kita buat view dengan copas kode di bawah ini,


<record model="ir.ui.view" id="asset_category_wizard">
<field name="name">asset.category.wizard.form</field>
<field name="model">asset.category.wizard</field>
<field name="arch" type="xml">
<form string="Asset By Category">
<group>
<field name="category_id"/>
<field name="po_location_id"/>
<field name="total_amount"/>
<field name="total_item"/>
<field name="depreciation_ids" widget='many2many_tags' invisible='1'/>
<field name="depreciation_view_ids">
<tree editable='bottom'>
<field name="depreciation_date"/>
<field name="depreciated_value" readonly="1"/>
<field name="amount" widget="monetary" string="Depreciation"/>
<field name="remaining_value" readonly="1" widget="monetary" string="Residual"/>
<field name="move_check" invisible="1"/>
<field name="move_posted_check" invisible="1"/>
<field name="parent_state" invisible="1"/>
</tree>
</field>
</group>
<footer>
<button string="Confirm Depreciation" name="create_move" type="object" class="btn-primary"/>
<button string="Cancel" class="btn-default" special="cancel"/>
</footer>
</form>
</field>
</record>


8. Lalu kita buat menu dan action untuk menjalankan view di atas, letakkan posisi menu di paling bawah, atau setelah record xml dibuat, karena jika kita letakkan di atas record xml yang kita buat akan terjadi error.


<!-- Action Window For Asset Category -->
<act_window
id="asset_category_wizard_action"
name="Mass Depreciation"
res_model="asset.category.wizard"
view_mode="form"
view_id="asset_category_wizard"
target="new"
/>
<!-- Action Window For Asset Category -->
  <menuitem
id="asset_category_wizard_menu"
name="Mass Depreciation"
parent="account.menu_finance_entries"
sequence="80"
action="asset_category_wizard_action"
  />



Setelah itu mari kita install modul dan mencobanya. Selamat mencoba...


Sekian artikel dari saya, kurang-lebihnya saya mohon maaf.


Wassalamu’alaikum Warohmatullah Wabarokatuh.