mirror of
https://github.com/frappe/erpnext.git
synced 2026-05-16 19:49:18 +00:00
Added test cases for asset accounting, asset value adjustment (#14572)
* Added test cases for asset accounting, asset value adjustment * Accounting entry for the asset created manually * Added asset movement test cases and validation * Added validation to make asset from purchase receupt, invoice only
This commit is contained in:
committed by
Nabin Hait
parent
ce26610d39
commit
d3fb0fbb20
@@ -58,7 +58,7 @@ frappe.ui.form.on('Asset', {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (frm.doc.purchase_receipt) {
|
if (frm.doc.purchase_receipt || !frm.doc.is_existing_asset) {
|
||||||
frm.add_custom_button("General Ledger", function() {
|
frm.add_custom_button("General Ledger", function() {
|
||||||
frappe.route_options = {
|
frappe.route_options = {
|
||||||
"voucher_no": frm.doc.name,
|
"voucher_no": frm.doc.name,
|
||||||
@@ -89,6 +89,10 @@ frappe.ui.form.on('Asset', {
|
|||||||
frm.page.set_inner_btn_group_as_primary(__("Make"));
|
frm.page.set_inner_btn_group_as_primary(__("Make"));
|
||||||
frm.trigger("setup_chart");
|
frm.trigger("setup_chart");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (frm.doc.docstatus == 0) {
|
||||||
|
frm.toggle_reqd("finance_books", frm.doc.calculate_depreciation);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
setup_chart: function(frm) {
|
setup_chart: function(frm) {
|
||||||
@@ -261,6 +265,8 @@ frappe.ui.form.on('Asset', {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
frm.toggle_reqd("finance_books", frm.doc.calculate_depreciation);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1628,7 +1628,7 @@
|
|||||||
"in_standard_filter": 0,
|
"in_standard_filter": 0,
|
||||||
"label": "Booked Fixed Asset",
|
"label": "Booked Fixed Asset",
|
||||||
"length": 0,
|
"length": 0,
|
||||||
"no_copy": 0,
|
"no_copy": 1,
|
||||||
"permlevel": 0,
|
"permlevel": 0,
|
||||||
"precision": "",
|
"precision": "",
|
||||||
"print_hide": 0,
|
"print_hide": 0,
|
||||||
@@ -1771,6 +1771,39 @@
|
|||||||
"translatable": 0,
|
"translatable": 0,
|
||||||
"unique": 0
|
"unique": 0
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"allow_bulk_edit": 0,
|
||||||
|
"allow_in_quick_entry": 0,
|
||||||
|
"allow_on_submit": 0,
|
||||||
|
"bold": 0,
|
||||||
|
"collapsible": 0,
|
||||||
|
"columns": 0,
|
||||||
|
"fieldname": "default_finance_book",
|
||||||
|
"fieldtype": "Read Only",
|
||||||
|
"hidden": 1,
|
||||||
|
"ignore_user_permissions": 0,
|
||||||
|
"ignore_xss_filter": 0,
|
||||||
|
"in_filter": 0,
|
||||||
|
"in_global_search": 0,
|
||||||
|
"in_list_view": 0,
|
||||||
|
"in_standard_filter": 0,
|
||||||
|
"label": "Default Finance Book",
|
||||||
|
"length": 0,
|
||||||
|
"no_copy": 0,
|
||||||
|
"options": "company.default_finance_book",
|
||||||
|
"permlevel": 0,
|
||||||
|
"precision": "",
|
||||||
|
"print_hide": 0,
|
||||||
|
"print_hide_if_no_value": 0,
|
||||||
|
"read_only": 0,
|
||||||
|
"remember_last_selected_value": 0,
|
||||||
|
"report_hide": 0,
|
||||||
|
"reqd": 0,
|
||||||
|
"search_index": 0,
|
||||||
|
"set_only_once": 0,
|
||||||
|
"translatable": 0,
|
||||||
|
"unique": 0
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"allow_bulk_edit": 0,
|
||||||
"allow_in_quick_entry": 0,
|
"allow_in_quick_entry": 0,
|
||||||
@@ -1815,7 +1848,7 @@
|
|||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"max_attachments": 0,
|
"max_attachments": 0,
|
||||||
"modified": "2018-06-15 13:56:35.211418",
|
"modified": "2018-06-18 19:20:27.668745",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Assets",
|
"module": "Assets",
|
||||||
"name": "Asset",
|
"name": "Asset",
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
# For license information, please see license.txt
|
# For license information, please see license.txt
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe
|
import frappe, erpnext
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.utils import flt, add_months, cint, nowdate, getdate, today, date_diff
|
from frappe.utils import flt, add_months, cint, nowdate, getdate, today, date_diff
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
@@ -16,19 +16,19 @@ from erpnext.controllers.accounts_controller import AccountsController
|
|||||||
|
|
||||||
class Asset(AccountsController):
|
class Asset(AccountsController):
|
||||||
def validate(self):
|
def validate(self):
|
||||||
self.status = self.get_status()
|
self.validate_asset_values()
|
||||||
self.validate_item()
|
self.validate_item()
|
||||||
self.set_missing_values()
|
self.set_missing_values()
|
||||||
self.validate_asset_values()
|
|
||||||
if self.calculate_depreciation:
|
if self.calculate_depreciation:
|
||||||
self.make_depreciation_schedule()
|
self.make_depreciation_schedule()
|
||||||
self.set_accumulated_depreciation()
|
self.set_accumulated_depreciation()
|
||||||
get_depreciation_accounts(self)
|
|
||||||
else:
|
else:
|
||||||
self.finance_books = []
|
self.finance_books = []
|
||||||
if self.get("schedules"):
|
if self.get("schedules"):
|
||||||
self.validate_expected_value_after_useful_life()
|
self.validate_expected_value_after_useful_life()
|
||||||
|
|
||||||
|
self.status = self.get_status()
|
||||||
|
|
||||||
def on_submit(self):
|
def on_submit(self):
|
||||||
self.validate_in_use_date()
|
self.validate_in_use_date()
|
||||||
self.set_status()
|
self.set_status()
|
||||||
@@ -71,8 +71,19 @@ class Asset(AccountsController):
|
|||||||
if not flt(self.gross_purchase_amount):
|
if not flt(self.gross_purchase_amount):
|
||||||
frappe.throw(_("Gross Purchase Amount is mandatory"), frappe.MandatoryError)
|
frappe.throw(_("Gross Purchase Amount is mandatory"), frappe.MandatoryError)
|
||||||
|
|
||||||
|
if not self.is_existing_asset and not (self.purchase_receipt or self.purchase_invoice):
|
||||||
|
frappe.throw(_("Please create purchase receipt or purchase invoice for the item {0}").
|
||||||
|
format(self.item_code))
|
||||||
|
|
||||||
|
if (not self.purchase_receipt and self.purchase_invoice
|
||||||
|
and not frappe.db.get_value('Purchase Invoice', self.purchase_invoice, 'update_stock')):
|
||||||
|
frappe.throw(_("Update stock must be enable for the purchase invoice {0}").
|
||||||
|
format(self.purchase_invoice))
|
||||||
|
|
||||||
if not self.calculate_depreciation:
|
if not self.calculate_depreciation:
|
||||||
return
|
return
|
||||||
|
elif not self.finance_books:
|
||||||
|
frappe.throw(_("Enter depreciation details"))
|
||||||
|
|
||||||
if self.available_for_use_date and getdate(self.available_for_use_date) < getdate(nowdate()):
|
if self.available_for_use_date and getdate(self.available_for_use_date) < getdate(nowdate()):
|
||||||
frappe.throw(_("Available-for-use Date is entered as past date"))
|
frappe.throw(_("Available-for-use Date is entered as past date"))
|
||||||
@@ -303,23 +314,32 @@ class Asset(AccountsController):
|
|||||||
status = "Draft"
|
status = "Draft"
|
||||||
elif self.docstatus == 1:
|
elif self.docstatus == 1:
|
||||||
status = "Submitted"
|
status = "Submitted"
|
||||||
expected_value_after_useful_life = flt(sum([d.expected_value_after_useful_life
|
|
||||||
for d in self.get('finance_books')]))
|
|
||||||
|
|
||||||
value_after_depreciation = flt(sum([d.value_after_depreciation
|
idx = self.get_default_finance_book_idx() or 0
|
||||||
for d in self.get('finance_books')]))
|
|
||||||
|
expected_value_after_useful_life = self.finance_books[idx].expected_value_after_useful_life
|
||||||
|
value_after_depreciation = self.finance_books[idx].value_after_depreciation
|
||||||
|
|
||||||
if self.journal_entry_for_scrap:
|
if self.journal_entry_for_scrap:
|
||||||
status = "Scrapped"
|
status = "Scrapped"
|
||||||
elif self.finance_books:
|
elif self.finance_books:
|
||||||
if flt(value_after_depreciation) <= expected_value_after_useful_life:
|
if flt(value_after_depreciation) <= expected_value_after_useful_life:
|
||||||
status = "Fully Depreciated"
|
status = "Fully Depreciated"
|
||||||
elif flt(self.value_after_depreciation) < flt(self.gross_purchase_amount):
|
elif flt(value_after_depreciation) < flt(self.gross_purchase_amount):
|
||||||
status = 'Partially Depreciated'
|
status = 'Partially Depreciated'
|
||||||
elif self.docstatus == 2:
|
elif self.docstatus == 2:
|
||||||
status = "Cancelled"
|
status = "Cancelled"
|
||||||
return status
|
return status
|
||||||
|
|
||||||
|
def get_default_finance_book_idx(self):
|
||||||
|
if not self.get('default_finance_book') and self.company:
|
||||||
|
self.default_finance_book = erpnext.get_default_finance_book(self.company)
|
||||||
|
|
||||||
|
if self.get('default_finance_book'):
|
||||||
|
for d in self.get('finance_books'):
|
||||||
|
if d.finance_books == self.default_finance_book:
|
||||||
|
return cint(d.idx) - 1
|
||||||
|
|
||||||
def update_stock_movement(self):
|
def update_stock_movement(self):
|
||||||
asset_movement = frappe.db.get_value('Asset Movement',
|
asset_movement = frappe.db.get_value('Asset Movement',
|
||||||
{'asset': self.name, 'reference_name': self.purchase_receipt, 'docstatus': 0}, 'name')
|
{'asset': self.name, 'reference_name': self.purchase_receipt, 'docstatus': 0}, 'name')
|
||||||
@@ -329,17 +349,17 @@ class Asset(AccountsController):
|
|||||||
doc.submit()
|
doc.submit()
|
||||||
|
|
||||||
def make_gl_entries(self):
|
def make_gl_entries(self):
|
||||||
if self.purchase_receipt and self.purchase_receipt_amount and self.available_for_use_date <= nowdate():
|
gl_entries = []
|
||||||
from erpnext.accounts.general_ledger import make_gl_entries
|
|
||||||
|
|
||||||
gl_entries = []
|
if ((self.purchase_receipt or (self.purchase_invoice and
|
||||||
|
frappe.db.get_value('Purchase Invoice', self.purchase_invoice, 'update_stock')))
|
||||||
|
and self.purchase_receipt_amount and self.available_for_use_date <= nowdate()):
|
||||||
|
fixed_aseet_account = get_asset_category_account(self.name, 'fixed_asset_account',
|
||||||
|
asset_category = self.asset_category, company = self.company)
|
||||||
|
|
||||||
cwip_account = get_asset_account("capital_work_in_progress_account",
|
cwip_account = get_asset_account("capital_work_in_progress_account",
|
||||||
self.name, self.asset_category, self.company)
|
self.name, self.asset_category, self.company)
|
||||||
|
|
||||||
fixed_aseet_account = get_asset_category_account(self.name, 'fixed_asset_account',
|
|
||||||
asset_category = self.asset_category, company = self.company)
|
|
||||||
|
|
||||||
gl_entries.append(self.get_gl_dict({
|
gl_entries.append(self.get_gl_dict({
|
||||||
"account": cwip_account,
|
"account": cwip_account,
|
||||||
"against": fixed_aseet_account,
|
"against": fixed_aseet_account,
|
||||||
@@ -358,6 +378,9 @@ class Asset(AccountsController):
|
|||||||
"debit_in_account_currency": self.purchase_receipt_amount
|
"debit_in_account_currency": self.purchase_receipt_amount
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
if gl_entries:
|
||||||
|
from erpnext.accounts.general_ledger import make_gl_entries
|
||||||
|
|
||||||
make_gl_entries(gl_entries)
|
make_gl_entries(gl_entries)
|
||||||
self.db_set('booked_fixed_asset', 1)
|
self.db_set('booked_fixed_asset', 1)
|
||||||
|
|
||||||
|
|||||||
@@ -5,19 +5,38 @@ from __future__ import unicode_literals
|
|||||||
|
|
||||||
import frappe
|
import frappe
|
||||||
import unittest
|
import unittest
|
||||||
from frappe.utils import cstr, nowdate, getdate, flt
|
from frappe.utils import cstr, nowdate, getdate, flt, get_last_day, add_days, add_months
|
||||||
from erpnext.assets.doctype.asset.depreciation import post_depreciation_entries, scrap_asset, restore_asset
|
from erpnext.assets.doctype.asset.depreciation import post_depreciation_entries, scrap_asset, restore_asset
|
||||||
from erpnext.assets.doctype.asset.asset import make_sales_invoice, make_purchase_invoice
|
from erpnext.assets.doctype.asset.asset import make_sales_invoice, make_purchase_invoice
|
||||||
|
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt
|
||||||
|
|
||||||
class TestAsset(unittest.TestCase):
|
class TestAsset(unittest.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
set_depreciation_settings_in_company()
|
set_depreciation_settings_in_company()
|
||||||
remove_prorated_depreciation_schedule()
|
remove_prorated_depreciation_schedule()
|
||||||
create_asset()
|
create_asset_data()
|
||||||
frappe.db.sql("delete from `tabTax Rule`")
|
frappe.db.sql("delete from `tabTax Rule`")
|
||||||
|
|
||||||
def test_purchase_asset(self):
|
def test_purchase_asset(self):
|
||||||
asset = frappe.get_doc("Asset", {"asset_name": "Macbook Pro 1"})
|
pr = make_purchase_receipt(item_code="Macbook Pro",
|
||||||
|
qty=1, rate=100000.0, location="Test Location")
|
||||||
|
|
||||||
|
asset_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, 'name')
|
||||||
|
asset = frappe.get_doc('Asset', asset_name)
|
||||||
|
asset.calculate_depreciation = 1
|
||||||
|
|
||||||
|
month_end_date = get_last_day(nowdate())
|
||||||
|
purchase_date = nowdate() if nowdate() != month_end_date else add_days(nowdate(), -15)
|
||||||
|
|
||||||
|
asset.available_for_use_date = purchase_date
|
||||||
|
asset.purchase_date = purchase_date
|
||||||
|
asset.append("finance_books", {
|
||||||
|
"expected_value_after_useful_life": 10000,
|
||||||
|
"depreciation_method": "Straight Line",
|
||||||
|
"total_number_of_depreciations": 3,
|
||||||
|
"frequency_of_depreciation": 10,
|
||||||
|
"depreciation_start_date": month_end_date
|
||||||
|
})
|
||||||
asset.submit()
|
asset.submit()
|
||||||
|
|
||||||
pi = make_purchase_invoice(asset.name, asset.item_code, asset.gross_purchase_amount,
|
pi = make_purchase_invoice(asset.name, asset.item_code, asset.gross_purchase_amount,
|
||||||
@@ -27,7 +46,7 @@ class TestAsset(unittest.TestCase):
|
|||||||
pi.submit()
|
pi.submit()
|
||||||
asset.load_from_db()
|
asset.load_from_db()
|
||||||
self.assertEqual(asset.supplier, "_Test Supplier")
|
self.assertEqual(asset.supplier, "_Test Supplier")
|
||||||
self.assertEqual(asset.purchase_date, getdate("2015-01-01"))
|
self.assertEqual(asset.purchase_date, getdate(purchase_date))
|
||||||
self.assertEqual(asset.purchase_invoice, pi.name)
|
self.assertEqual(asset.purchase_invoice, pi.name)
|
||||||
|
|
||||||
expected_gle = (
|
expected_gle = (
|
||||||
@@ -51,8 +70,15 @@ class TestAsset(unittest.TestCase):
|
|||||||
|
|
||||||
|
|
||||||
def test_schedule_for_straight_line_method(self):
|
def test_schedule_for_straight_line_method(self):
|
||||||
asset = frappe.get_doc("Asset", {"asset_name": "Macbook Pro 1"})
|
pr = make_purchase_receipt(item_code="Macbook Pro",
|
||||||
|
qty=1, rate=100000.0, location="Test Location")
|
||||||
|
|
||||||
|
asset_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, 'name')
|
||||||
|
asset = frappe.get_doc('Asset', asset_name)
|
||||||
asset.calculate_depreciation = 1
|
asset.calculate_depreciation = 1
|
||||||
|
asset.available_for_use_date = '2020-06-06'
|
||||||
|
asset.purchase_date = '2020-06-06'
|
||||||
|
|
||||||
asset.append("finance_books", {
|
asset.append("finance_books", {
|
||||||
"expected_value_after_useful_life": 10000,
|
"expected_value_after_useful_life": 10000,
|
||||||
"next_depreciation_date": "2020-12-31",
|
"next_depreciation_date": "2020-12-31",
|
||||||
@@ -61,7 +87,7 @@ class TestAsset(unittest.TestCase):
|
|||||||
"frequency_of_depreciation": 10,
|
"frequency_of_depreciation": 10,
|
||||||
"depreciation_start_date": "2020-06-06"
|
"depreciation_start_date": "2020-06-06"
|
||||||
})
|
})
|
||||||
asset.insert()
|
asset.save()
|
||||||
self.assertEqual(asset.status, "Draft")
|
self.assertEqual(asset.status, "Draft")
|
||||||
expected_schedules = [
|
expected_schedules = [
|
||||||
["2020-06-06", 163.93, 163.93],
|
["2020-06-06", 163.93, 163.93],
|
||||||
@@ -75,8 +101,8 @@ class TestAsset(unittest.TestCase):
|
|||||||
self.assertEqual(schedules, expected_schedules)
|
self.assertEqual(schedules, expected_schedules)
|
||||||
|
|
||||||
def test_schedule_for_straight_line_method_for_existing_asset(self):
|
def test_schedule_for_straight_line_method_for_existing_asset(self):
|
||||||
|
create_asset(is_existing_asset=1)
|
||||||
asset = frappe.get_doc("Asset", {"asset_name": "Macbook Pro 1"})
|
asset = frappe.get_doc("Asset", {"asset_name": "Macbook Pro 1"})
|
||||||
asset.is_existing_asset = 1
|
|
||||||
asset.calculate_depreciation = 1
|
asset.calculate_depreciation = 1
|
||||||
asset.number_of_depreciations_booked = 1
|
asset.number_of_depreciations_booked = 1
|
||||||
asset.opening_accumulated_depreciation = 40000
|
asset.opening_accumulated_depreciation = 40000
|
||||||
@@ -101,8 +127,14 @@ class TestAsset(unittest.TestCase):
|
|||||||
self.assertEqual(schedules, expected_schedules)
|
self.assertEqual(schedules, expected_schedules)
|
||||||
|
|
||||||
def test_schedule_for_double_declining_method(self):
|
def test_schedule_for_double_declining_method(self):
|
||||||
asset = frappe.get_doc("Asset", {"asset_name": "Macbook Pro 1"})
|
pr = make_purchase_receipt(item_code="Macbook Pro",
|
||||||
|
qty=1, rate=100000.0, location="Test Location")
|
||||||
|
|
||||||
|
asset_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, 'name')
|
||||||
|
asset = frappe.get_doc('Asset', asset_name)
|
||||||
asset.calculate_depreciation = 1
|
asset.calculate_depreciation = 1
|
||||||
|
asset.available_for_use_date = '2020-06-06'
|
||||||
|
asset.purchase_date = '2020-06-06'
|
||||||
asset.append("finance_books", {
|
asset.append("finance_books", {
|
||||||
"expected_value_after_useful_life": 10000,
|
"expected_value_after_useful_life": 10000,
|
||||||
"next_depreciation_date": "2020-12-31",
|
"next_depreciation_date": "2020-12-31",
|
||||||
@@ -127,6 +159,7 @@ class TestAsset(unittest.TestCase):
|
|||||||
self.assertEqual(schedules, expected_schedules)
|
self.assertEqual(schedules, expected_schedules)
|
||||||
|
|
||||||
def test_schedule_for_double_declining_method_for_existing_asset(self):
|
def test_schedule_for_double_declining_method_for_existing_asset(self):
|
||||||
|
create_asset(is_existing_asset = 1)
|
||||||
asset = frappe.get_doc("Asset", {"asset_name": "Macbook Pro 1"})
|
asset = frappe.get_doc("Asset", {"asset_name": "Macbook Pro 1"})
|
||||||
asset.calculate_depreciation = 1
|
asset.calculate_depreciation = 1
|
||||||
asset.is_existing_asset = 1
|
asset.is_existing_asset = 1
|
||||||
@@ -158,8 +191,13 @@ class TestAsset(unittest.TestCase):
|
|||||||
|
|
||||||
def test_schedule_for_prorated_straight_line_method(self):
|
def test_schedule_for_prorated_straight_line_method(self):
|
||||||
set_prorated_depreciation_schedule()
|
set_prorated_depreciation_schedule()
|
||||||
asset = frappe.get_doc("Asset", {"asset_name": "Macbook Pro 1"})
|
pr = make_purchase_receipt(item_code="Macbook Pro",
|
||||||
|
qty=1, rate=100000.0, location="Test Location")
|
||||||
|
|
||||||
|
asset_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, 'name')
|
||||||
|
asset = frappe.get_doc('Asset', asset_name)
|
||||||
asset.calculate_depreciation = 1
|
asset.calculate_depreciation = 1
|
||||||
|
asset.purchase_date = '2020-06-06'
|
||||||
asset.is_existing_asset = 0
|
asset.is_existing_asset = 0
|
||||||
asset.available_for_use_date = "2020-01-30"
|
asset.available_for_use_date = "2020-01-30"
|
||||||
asset.append("finance_books", {
|
asset.append("finance_books", {
|
||||||
@@ -188,8 +226,13 @@ class TestAsset(unittest.TestCase):
|
|||||||
remove_prorated_depreciation_schedule()
|
remove_prorated_depreciation_schedule()
|
||||||
|
|
||||||
def test_depreciation(self):
|
def test_depreciation(self):
|
||||||
asset = frappe.get_doc("Asset", {"asset_name": "Macbook Pro 1"})
|
pr = make_purchase_receipt(item_code="Macbook Pro",
|
||||||
|
qty=1, rate=100000.0, location="Test Location")
|
||||||
|
|
||||||
|
asset_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, 'name')
|
||||||
|
asset = frappe.get_doc('Asset', asset_name)
|
||||||
asset.calculate_depreciation = 1
|
asset.calculate_depreciation = 1
|
||||||
|
asset.purchase_date = '2020-06-06'
|
||||||
asset.available_for_use_date = "2020-01-30"
|
asset.available_for_use_date = "2020-01-30"
|
||||||
asset.append("finance_books", {
|
asset.append("finance_books", {
|
||||||
"expected_value_after_useful_life": 10000,
|
"expected_value_after_useful_life": 10000,
|
||||||
@@ -201,7 +244,7 @@ class TestAsset(unittest.TestCase):
|
|||||||
asset.insert()
|
asset.insert()
|
||||||
asset.submit()
|
asset.submit()
|
||||||
asset.load_from_db()
|
asset.load_from_db()
|
||||||
self.assertEqual(asset.status, "Partially Depreciated")
|
self.assertEqual(asset.status, "Submitted")
|
||||||
|
|
||||||
frappe.db.set_value("Company", "_Test Company", "series_for_depreciation_entry", "DEPR-")
|
frappe.db.set_value("Company", "_Test Company", "series_for_depreciation_entry", "DEPR-")
|
||||||
post_depreciation_entries(date="2021-01-01")
|
post_depreciation_entries(date="2021-01-01")
|
||||||
@@ -223,8 +266,14 @@ class TestAsset(unittest.TestCase):
|
|||||||
self.assertEqual(asset.get("value_after_depreciation"), 0)
|
self.assertEqual(asset.get("value_after_depreciation"), 0)
|
||||||
|
|
||||||
def test_depreciation_entry_cancellation(self):
|
def test_depreciation_entry_cancellation(self):
|
||||||
asset = frappe.get_doc("Asset", {"asset_name": "Macbook Pro 1"})
|
pr = make_purchase_receipt(item_code="Macbook Pro",
|
||||||
|
qty=1, rate=100000.0, location="Test Location")
|
||||||
|
|
||||||
|
asset_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, 'name')
|
||||||
|
asset = frappe.get_doc('Asset', asset_name)
|
||||||
asset.calculate_depreciation = 1
|
asset.calculate_depreciation = 1
|
||||||
|
asset.available_for_use_date = '2020-06-06'
|
||||||
|
asset.purchase_date = '2020-06-06'
|
||||||
asset.append("finance_books", {
|
asset.append("finance_books", {
|
||||||
"expected_value_after_useful_life": 10000,
|
"expected_value_after_useful_life": 10000,
|
||||||
"depreciation_method": "Straight Line",
|
"depreciation_method": "Straight Line",
|
||||||
@@ -248,8 +297,14 @@ class TestAsset(unittest.TestCase):
|
|||||||
self.assertFalse(depr_entry)
|
self.assertFalse(depr_entry)
|
||||||
|
|
||||||
def test_scrap_asset(self):
|
def test_scrap_asset(self):
|
||||||
asset = frappe.get_doc("Asset", {"asset_name": "Macbook Pro 1"})
|
pr = make_purchase_receipt(item_code="Macbook Pro",
|
||||||
|
qty=1, rate=100000.0, location="Test Location")
|
||||||
|
|
||||||
|
asset_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, 'name')
|
||||||
|
asset = frappe.get_doc('Asset', asset_name)
|
||||||
asset.calculate_depreciation = 1
|
asset.calculate_depreciation = 1
|
||||||
|
asset.available_for_use_date = '2020-06-06'
|
||||||
|
asset.purchase_date = '2020-06-06'
|
||||||
asset.append("finance_books", {
|
asset.append("finance_books", {
|
||||||
"expected_value_after_useful_life": 10000,
|
"expected_value_after_useful_life": 10000,
|
||||||
"depreciation_method": "Straight Line",
|
"depreciation_method": "Straight Line",
|
||||||
@@ -284,8 +339,14 @@ class TestAsset(unittest.TestCase):
|
|||||||
self.assertEqual(asset.status, "Partially Depreciated")
|
self.assertEqual(asset.status, "Partially Depreciated")
|
||||||
|
|
||||||
def test_asset_sale(self):
|
def test_asset_sale(self):
|
||||||
asset = frappe.get_doc("Asset", {"asset_name": "Macbook Pro 1"})
|
pr = make_purchase_receipt(item_code="Macbook Pro",
|
||||||
|
qty=1, rate=100000.0, location="Test Location")
|
||||||
|
|
||||||
|
asset_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, 'name')
|
||||||
|
asset = frappe.get_doc('Asset', asset_name)
|
||||||
asset.calculate_depreciation = 1
|
asset.calculate_depreciation = 1
|
||||||
|
asset.available_for_use_date = '2020-06-06'
|
||||||
|
asset.purchase_date = '2020-06-06'
|
||||||
asset.append("finance_books", {
|
asset.append("finance_books", {
|
||||||
"expected_value_after_useful_life": 10000,
|
"expected_value_after_useful_life": 10000,
|
||||||
"depreciation_method": "Straight Line",
|
"depreciation_method": "Straight Line",
|
||||||
@@ -325,8 +386,14 @@ class TestAsset(unittest.TestCase):
|
|||||||
self.assertEqual(frappe.db.get_value("Asset", asset.name, "status"), "Partially Depreciated")
|
self.assertEqual(frappe.db.get_value("Asset", asset.name, "status"), "Partially Depreciated")
|
||||||
|
|
||||||
def test_asset_expected_value_after_useful_life(self):
|
def test_asset_expected_value_after_useful_life(self):
|
||||||
asset = frappe.get_doc("Asset", {"asset_name": "Macbook Pro 1"})
|
pr = make_purchase_receipt(item_code="Macbook Pro",
|
||||||
|
qty=1, rate=100000.0, location="Test Location")
|
||||||
|
|
||||||
|
asset_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, 'name')
|
||||||
|
asset = frappe.get_doc('Asset', asset_name)
|
||||||
asset.calculate_depreciation = 1
|
asset.calculate_depreciation = 1
|
||||||
|
asset.available_for_use_date = '2020-06-06'
|
||||||
|
asset.purchase_date = '2020-06-06'
|
||||||
asset.append("finance_books", {
|
asset.append("finance_books", {
|
||||||
"expected_value_after_useful_life": 10000,
|
"expected_value_after_useful_life": 10000,
|
||||||
"depreciation_method": "Straight Line",
|
"depreciation_method": "Straight Line",
|
||||||
@@ -343,16 +410,91 @@ class TestAsset(unittest.TestCase):
|
|||||||
|
|
||||||
self.assertTrue(asset.finance_books[0].expected_value_after_useful_life >= asset_value_after_full_schedule)
|
self.assertTrue(asset.finance_books[0].expected_value_after_useful_life >= asset_value_after_full_schedule)
|
||||||
|
|
||||||
def tearDown(self):
|
def test_cwip_accounting(self):
|
||||||
asset = frappe.get_doc("Asset", {"asset_name": "Macbook Pro 1"})
|
from erpnext.stock.doctype.purchase_receipt.purchase_receipt import (
|
||||||
if asset.docstatus == 1 and asset.status not in ("Scrapped", "Sold", "Draft", "Cancelled"):
|
make_purchase_invoice as make_purchase_invoice_from_pr)
|
||||||
asset.cancel()
|
|
||||||
|
|
||||||
self.assertEqual(frappe.db.get_value("Asset", {"asset_name": "Macbook Pro 1"}, "status"), "Cancelled")
|
pr = make_purchase_receipt(item_code="Macbook Pro",
|
||||||
|
qty=1, rate=5000, do_not_submit=True, location="Test Location")
|
||||||
|
|
||||||
frappe.delete_doc("Asset", {"asset_name": "Macbook Pro 1"})
|
pr.set('taxes', [{
|
||||||
|
'category': 'Total',
|
||||||
|
'add_deduct_tax': 'Add',
|
||||||
|
'charge_type': 'On Net Total',
|
||||||
|
'account_head': '_Test Account Service Tax - _TC',
|
||||||
|
'description': '_Test Account Service Tax',
|
||||||
|
'cost_center': 'Main - _TC',
|
||||||
|
'rate': 5.0
|
||||||
|
}, {
|
||||||
|
'category': 'Valuation and Total',
|
||||||
|
'add_deduct_tax': 'Add',
|
||||||
|
'charge_type': 'On Net Total',
|
||||||
|
'account_head': '_Test Account Shipping Charges - _TC',
|
||||||
|
'description': '_Test Account Shipping Charges',
|
||||||
|
'cost_center': 'Main - _TC',
|
||||||
|
'rate': 5.0
|
||||||
|
}])
|
||||||
|
|
||||||
def create_asset():
|
pr.submit()
|
||||||
|
|
||||||
|
expected_gle = (
|
||||||
|
("Asset Received But Not Billed - _TC", 0.0, 5250.0),
|
||||||
|
("CWIP Account - _TC", 5250.0, 0.0)
|
||||||
|
)
|
||||||
|
|
||||||
|
gle = frappe.db.sql("""select account, debit, credit from `tabGL Entry`
|
||||||
|
where voucher_type='Purchase Receipt' and voucher_no = %s
|
||||||
|
order by account""", pr.name)
|
||||||
|
|
||||||
|
self.assertEqual(gle, expected_gle)
|
||||||
|
|
||||||
|
pi = make_purchase_invoice_from_pr(pr.name)
|
||||||
|
pi.submit()
|
||||||
|
|
||||||
|
expected_gle = (
|
||||||
|
("_Test Account Service Tax - _TC", 250.0, 0.0),
|
||||||
|
("_Test Account Shipping Charges - _TC", 250.0, 0.0),
|
||||||
|
("Asset Received But Not Billed - _TC", 5250.0, 0.0),
|
||||||
|
("Creditors - _TC", 0.0, 5500.0),
|
||||||
|
("Expenses Included In Asset Valuation - _TC", 0.0, 250.0),
|
||||||
|
)
|
||||||
|
|
||||||
|
gle = frappe.db.sql("""select account, debit, credit from `tabGL Entry`
|
||||||
|
where voucher_type='Purchase Invoice' and voucher_no = %s
|
||||||
|
order by account""", pi.name)
|
||||||
|
|
||||||
|
self.assertEqual(gle, expected_gle)
|
||||||
|
|
||||||
|
asset = frappe.db.get_value('Asset',
|
||||||
|
{'purchase_receipt': pr.name, 'docstatus': 0}, 'name')
|
||||||
|
|
||||||
|
asset_doc = frappe.get_doc('Asset', asset)
|
||||||
|
|
||||||
|
month_end_date = get_last_day(nowdate())
|
||||||
|
asset_doc.available_for_use_date = nowdate() if nowdate() != month_end_date else add_days(nowdate(), -15)
|
||||||
|
self.assertEqual(asset_doc.gross_purchase_amount, 5250.0)
|
||||||
|
|
||||||
|
asset_doc.append("finance_books", {
|
||||||
|
"expected_value_after_useful_life": 200,
|
||||||
|
"depreciation_method": "Straight Line",
|
||||||
|
"total_number_of_depreciations": 3,
|
||||||
|
"frequency_of_depreciation": 10,
|
||||||
|
"depreciation_start_date": month_end_date
|
||||||
|
})
|
||||||
|
asset_doc.submit()
|
||||||
|
|
||||||
|
expected_gle = (
|
||||||
|
("_Test Fixed Asset - _TC", 5250.0, 0.0),
|
||||||
|
("CWIP Account - _TC", 0.0, 5250.0)
|
||||||
|
)
|
||||||
|
|
||||||
|
gle = frappe.db.sql("""select account, debit, credit from `tabGL Entry`
|
||||||
|
where voucher_type='Asset' and voucher_no = %s
|
||||||
|
order by account""", asset_doc.name)
|
||||||
|
|
||||||
|
self.assertEqual(gle, expected_gle)
|
||||||
|
|
||||||
|
def create_asset_data():
|
||||||
if not frappe.db.exists("Asset Category", "Computers"):
|
if not frappe.db.exists("Asset Category", "Computers"):
|
||||||
create_asset_category()
|
create_asset_category()
|
||||||
|
|
||||||
@@ -365,6 +507,11 @@ def create_asset():
|
|||||||
'location_name': 'Test Location'
|
'location_name': 'Test Location'
|
||||||
}).insert()
|
}).insert()
|
||||||
|
|
||||||
|
def create_asset(**args):
|
||||||
|
args = frappe._dict(args)
|
||||||
|
|
||||||
|
create_asset_data()
|
||||||
|
|
||||||
asset = frappe.get_doc({
|
asset = frappe.get_doc({
|
||||||
"doctype": "Asset",
|
"doctype": "Asset",
|
||||||
"asset_name": "Macbook Pro 1",
|
"asset_name": "Macbook Pro 1",
|
||||||
@@ -378,7 +525,8 @@ def create_asset():
|
|||||||
"warehouse": "_Test Warehouse - _TC",
|
"warehouse": "_Test Warehouse - _TC",
|
||||||
"available_for_use_date": "2020-06-06",
|
"available_for_use_date": "2020-06-06",
|
||||||
"location": "Test Location",
|
"location": "Test Location",
|
||||||
"asset_owner": "Company"
|
"asset_owner": "Company",
|
||||||
|
"is_existing_asset": args.is_existing_asset or 0
|
||||||
})
|
})
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -5,16 +5,40 @@ from __future__ import unicode_literals
|
|||||||
|
|
||||||
import frappe
|
import frappe
|
||||||
import unittest
|
import unittest
|
||||||
from frappe.utils import nowdate, add_days
|
from frappe.utils import nowdate, get_last_day, add_days
|
||||||
|
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt
|
||||||
from erpnext.assets.doctype.asset_maintenance.asset_maintenance import calculate_next_due_date
|
from erpnext.assets.doctype.asset_maintenance.asset_maintenance import calculate_next_due_date
|
||||||
|
|
||||||
class TestAssetMaintenance(unittest.TestCase):
|
class TestAssetMaintenance(unittest.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
set_depreciation_settings_in_company()
|
set_depreciation_settings_in_company()
|
||||||
create_asset()
|
create_asset_data()
|
||||||
create_maintenance_team()
|
create_maintenance_team()
|
||||||
|
|
||||||
def test_create_asset_maintenance(self):
|
def test_create_asset_maintenance(self):
|
||||||
|
pr = make_purchase_receipt(item_code="Photocopier",
|
||||||
|
qty=1, rate=100000.0, location="Test Location")
|
||||||
|
|
||||||
|
asset_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, 'name')
|
||||||
|
asset_doc = frappe.get_doc('Asset', asset_name)
|
||||||
|
month_end_date = get_last_day(nowdate())
|
||||||
|
|
||||||
|
purchase_date = nowdate() if nowdate() != month_end_date else add_days(nowdate(), -15)
|
||||||
|
|
||||||
|
asset_doc.available_for_use_date = purchase_date
|
||||||
|
asset_doc.purchase_date = purchase_date
|
||||||
|
|
||||||
|
asset_doc.calculate_depreciation = 1
|
||||||
|
asset_doc.append("finance_books", {
|
||||||
|
"expected_value_after_useful_life": 200,
|
||||||
|
"depreciation_method": "Straight Line",
|
||||||
|
"total_number_of_depreciations": 3,
|
||||||
|
"frequency_of_depreciation": 10,
|
||||||
|
"depreciation_start_date": month_end_date
|
||||||
|
})
|
||||||
|
|
||||||
|
asset_doc.save()
|
||||||
|
|
||||||
if not frappe.db.exists("Asset Maintenance", "Photocopier"):
|
if not frappe.db.exists("Asset Maintenance", "Photocopier"):
|
||||||
asset_maintenance = frappe.get_doc({
|
asset_maintenance = frappe.get_doc({
|
||||||
"doctype": "Asset Maintenance",
|
"doctype": "Asset Maintenance",
|
||||||
@@ -40,7 +64,7 @@ class TestAssetMaintenance(unittest.TestCase):
|
|||||||
next_due_date = calculate_next_due_date(asset_maintenance_log.completion_date, "Monthly")
|
next_due_date = calculate_next_due_date(asset_maintenance_log.completion_date, "Monthly")
|
||||||
self.assertEqual(asset_maintenance.asset_maintenance_tasks[0].next_due_date, next_due_date)
|
self.assertEqual(asset_maintenance.asset_maintenance_tasks[0].next_due_date, next_due_date)
|
||||||
|
|
||||||
def create_asset():
|
def create_asset_data():
|
||||||
if not frappe.db.exists("Asset Category", "Equipment"):
|
if not frappe.db.exists("Asset Category", "Equipment"):
|
||||||
create_asset_category()
|
create_asset_category()
|
||||||
|
|
||||||
@@ -62,23 +86,6 @@ def create_asset():
|
|||||||
"asset_category": "Equipment"
|
"asset_category": "Equipment"
|
||||||
}).insert()
|
}).insert()
|
||||||
|
|
||||||
if not frappe.db.exists("Asset", "Photocopier"):
|
|
||||||
frappe.get_doc({
|
|
||||||
"doctype": "Asset",
|
|
||||||
"asset_name": "Photocopier",
|
|
||||||
"item_code": "Photocopier",
|
|
||||||
"asset_category": "Equipment",
|
|
||||||
"gross_purchase_amount": 100000,
|
|
||||||
"expected_value_after_useful_life": 10000,
|
|
||||||
"warehouse": "_Test Warehouse - _TC",
|
|
||||||
"location": "Test Location",
|
|
||||||
"available_for_use_date": add_days(nowdate(),3),
|
|
||||||
"company": "_Test Company",
|
|
||||||
"purchase_date": nowdate(),
|
|
||||||
"maintenance_required": 1,
|
|
||||||
"asset_owner": "Company"
|
|
||||||
}).insert()
|
|
||||||
|
|
||||||
def create_maintenance_team():
|
def create_maintenance_team():
|
||||||
user_list = ["marcus@abc.com", "thalia@abc.com", "mathias@abc.com"]
|
user_list = ["marcus@abc.com", "thalia@abc.com", "mathias@abc.com"]
|
||||||
if not frappe.db.exists("Role", "Technician"):
|
if not frappe.db.exists("Role", "Technician"):
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ from frappe.model.document import Document
|
|||||||
class AssetMovement(Document):
|
class AssetMovement(Document):
|
||||||
def validate(self):
|
def validate(self):
|
||||||
self.validate_asset()
|
self.validate_asset()
|
||||||
self.validate_warehouses()
|
self.validate_location()
|
||||||
|
|
||||||
def validate_asset(self):
|
def validate_asset(self):
|
||||||
status, company = frappe.db.get_value("Asset", self.asset, ["status", "company"])
|
status, company = frappe.db.get_value("Asset", self.asset, ["status", "company"])
|
||||||
@@ -27,13 +27,33 @@ class AssetMovement(Document):
|
|||||||
if not(self.source_location or self.target_location or self.from_employee or self.to_employee):
|
if not(self.source_location or self.target_location or self.from_employee or self.to_employee):
|
||||||
frappe.throw(_("Either location or employee must be required"))
|
frappe.throw(_("Either location or employee must be required"))
|
||||||
|
|
||||||
def validate_warehouses(self):
|
if (not self.serial_no and
|
||||||
if self.purpose in ['Transfer', 'Issue']:
|
frappe.db.get_value('Serial No', {'asset': self.asset}, 'name')):
|
||||||
self.source_location = frappe.db.get_value("Asset", self.asset, "location")
|
frappe.throw(_("Serial no is required for the asset {0}").format(self.asset))
|
||||||
|
|
||||||
if self.source_location == self.target_location and self.purpose == 'Transfer':
|
def validate_location(self):
|
||||||
|
if self.purpose in ['Transfer', 'Issue']:
|
||||||
|
if not self.serial_no and not (self.from_employee or self.to_employee):
|
||||||
|
self.source_location = frappe.db.get_value("Asset", self.asset, "location")
|
||||||
|
|
||||||
|
if self.purpose == 'Issue' and not self.source_location:
|
||||||
|
frappe.throw(_("Source Location is required for the asset {0}").format(self.asset))
|
||||||
|
|
||||||
|
if self.serial_no and self.source_location:
|
||||||
|
s_nos = get_serial_nos(self.serial_no)
|
||||||
|
serial_nos = frappe.db.sql_list(""" select name from `tabSerial No` where location != '%s'
|
||||||
|
and name in (%s)""" %(self.source_location, ','.join(['%s'] * len(s_nos))), tuple(s_nos))
|
||||||
|
|
||||||
|
if serial_nos:
|
||||||
|
frappe.throw(_("Serial nos {0} does not belongs to the location {1}").
|
||||||
|
format(','.join(serial_nos), self.source_location))
|
||||||
|
|
||||||
|
if self.source_location and self.source_location == self.target_location and self.purpose == 'Transfer':
|
||||||
frappe.throw(_("Source and Target Location cannot be same"))
|
frappe.throw(_("Source and Target Location cannot be same"))
|
||||||
|
|
||||||
|
if self.purpose == 'Receipt' and not self.target_location:
|
||||||
|
frappe.throw(_("Target Location is required for the asset {0}").format(self.asset))
|
||||||
|
|
||||||
def on_submit(self):
|
def on_submit(self):
|
||||||
self.set_latest_location_in_asset()
|
self.set_latest_location_in_asset()
|
||||||
|
|
||||||
@@ -41,19 +61,42 @@ class AssetMovement(Document):
|
|||||||
self.set_latest_location_in_asset()
|
self.set_latest_location_in_asset()
|
||||||
|
|
||||||
def set_latest_location_in_asset(self):
|
def set_latest_location_in_asset(self):
|
||||||
latest_movement_entry = frappe.db.sql("""select target_location from `tabAsset Movement`
|
location, employee = '', ''
|
||||||
where asset=%s and docstatus=1 and company=%s
|
cond = "1=1"
|
||||||
order by transaction_date desc limit 1""", (self.asset, self.company))
|
|
||||||
|
args = {
|
||||||
|
'asset': self.asset,
|
||||||
|
'company': self.company
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.serial_no:
|
||||||
|
cond = "serial_no like %(txt)s"
|
||||||
|
args.update({
|
||||||
|
'txt': "%%%s%%" % self.serial_no
|
||||||
|
})
|
||||||
|
|
||||||
|
latest_movement_entry = frappe.db.sql("""select target_location, to_employee from `tabAsset Movement`
|
||||||
|
where asset=%(asset)s and docstatus=1 and company=%(company)s and {0}
|
||||||
|
order by transaction_date desc limit 1""".format(cond), args)
|
||||||
|
|
||||||
if latest_movement_entry:
|
if latest_movement_entry:
|
||||||
location = latest_movement_entry[0][0]
|
location = latest_movement_entry[0][0]
|
||||||
else:
|
employee = latest_movement_entry[0][1]
|
||||||
location = frappe.db.sql("""select source_location from `tabAsset Movement`
|
elif self.purpose in ['Transfer', 'Receipt']:
|
||||||
where asset=%s and docstatus=2 and company=%s
|
movement_entry = frappe.db.sql("""select source_location, from_employee from `tabAsset Movement`
|
||||||
order by transaction_date asc limit 1""", (self.asset, self.company))[0][0]
|
where asset=%(asset)s and docstatus=2 and company=%(company)s and {0}
|
||||||
|
order by transaction_date asc limit 1""".format(cond), args)
|
||||||
|
if movement_entry:
|
||||||
|
location = movement_entry[0][0]
|
||||||
|
employee = movement_entry[0][1]
|
||||||
|
|
||||||
frappe.db.set_value("Asset", self.asset, "location", location)
|
if not self.serial_no:
|
||||||
|
frappe.db.set_value("Asset", self.asset, "location", location)
|
||||||
|
|
||||||
if self.serial_no:
|
if self.serial_no:
|
||||||
for d in get_serial_nos(self.serial_no):
|
for d in get_serial_nos(self.serial_no):
|
||||||
frappe.db.set_value('Serial No', d, 'location', location)
|
if (location or self.purpose == 'Issue'):
|
||||||
|
frappe.db.set_value('Serial No', d, 'location', location)
|
||||||
|
|
||||||
|
if employee:
|
||||||
|
frappe.db.set_value('Serial No', d, 'employee', employee)
|
||||||
|
|||||||
@@ -4,14 +4,37 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
import frappe
|
import frappe
|
||||||
from frappe.utils import now
|
|
||||||
import unittest
|
import unittest
|
||||||
from erpnext.assets.doctype.asset.test_asset import create_asset
|
from erpnext.stock.doctype.item.test_item import make_item
|
||||||
|
from frappe.utils import now, nowdate, get_last_day, add_days
|
||||||
|
from erpnext.assets.doctype.asset.test_asset import create_asset_data
|
||||||
|
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
|
||||||
|
from erpnext.hr.doctype.employee.test_employee import make_employee
|
||||||
|
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt
|
||||||
|
|
||||||
class TestAssetMovement(unittest.TestCase):
|
class TestAssetMovement(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
create_asset_data()
|
||||||
|
make_location()
|
||||||
|
make_serialized_item()
|
||||||
|
|
||||||
def test_movement(self):
|
def test_movement(self):
|
||||||
asset = create_asset()
|
pr = make_purchase_receipt(item_code="Macbook Pro",
|
||||||
|
qty=1, rate=100000.0, location="Test Location")
|
||||||
|
|
||||||
|
asset_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, 'name')
|
||||||
|
asset = frappe.get_doc('Asset', asset_name)
|
||||||
|
asset.calculate_depreciation = 1
|
||||||
|
asset.available_for_use_date = '2020-06-06'
|
||||||
|
asset.purchase_date = '2020-06-06'
|
||||||
|
asset.append("finance_books", {
|
||||||
|
"expected_value_after_useful_life": 10000,
|
||||||
|
"next_depreciation_date": "2020-12-31",
|
||||||
|
"depreciation_method": "Straight Line",
|
||||||
|
"total_number_of_depreciations": 3,
|
||||||
|
"frequency_of_depreciation": 10,
|
||||||
|
"depreciation_start_date": "2020-06-06"
|
||||||
|
})
|
||||||
|
|
||||||
if asset.docstatus == 0:
|
if asset.docstatus == 0:
|
||||||
asset.submit()
|
asset.submit()
|
||||||
@@ -21,10 +44,12 @@ class TestAssetMovement(unittest.TestCase):
|
|||||||
'location_name': 'Test Location 2'
|
'location_name': 'Test Location 2'
|
||||||
}).insert()
|
}).insert()
|
||||||
|
|
||||||
movement1 = create_asset_movement(asset, target_location="Test Location 2")
|
movement1 = create_asset_movement(asset= asset.name, purpose = 'Transfer',
|
||||||
|
company=asset.company, source_location="Test Location", target_location="Test Location 2")
|
||||||
self.assertEqual(frappe.db.get_value("Asset", asset.name, "location"), "Test Location 2")
|
self.assertEqual(frappe.db.get_value("Asset", asset.name, "location"), "Test Location 2")
|
||||||
|
|
||||||
movement2 = create_asset_movement(asset, target_location="Test Location")
|
movement2 = create_asset_movement(asset= asset.name, purpose = 'Transfer',
|
||||||
|
company=asset.company, source_location = "Test Location 2", target_location="Test Location")
|
||||||
self.assertEqual(frappe.db.get_value("Asset", asset.name, "location"), "Test Location")
|
self.assertEqual(frappe.db.get_value("Asset", asset.name, "location"), "Test Location")
|
||||||
|
|
||||||
movement1.cancel()
|
movement1.cancel()
|
||||||
@@ -33,23 +58,112 @@ class TestAssetMovement(unittest.TestCase):
|
|||||||
movement2.cancel()
|
movement2.cancel()
|
||||||
self.assertEqual(frappe.db.get_value("Asset", asset.name, "location"), "Test Location")
|
self.assertEqual(frappe.db.get_value("Asset", asset.name, "location"), "Test Location")
|
||||||
|
|
||||||
asset.load_from_db()
|
def test_movement_for_serialized_asset(self):
|
||||||
asset.cancel()
|
asset_item = "Test Serialized Asset Item"
|
||||||
frappe.delete_doc("Asset", asset.name)
|
pr = make_purchase_receipt(item_code=asset_item, rate = 1000, qty=3, location = "Mumbai")
|
||||||
|
asset_name = frappe.db.get_value('Asset', {'purchase_receipt': pr.name}, 'name')
|
||||||
|
|
||||||
def create_asset_movement(asset, target_location, transaction_date=None):
|
asset = frappe.get_doc('Asset', asset_name)
|
||||||
if not transaction_date:
|
month_end_date = get_last_day(nowdate())
|
||||||
transaction_date = now()
|
asset.available_for_use_date = nowdate() if nowdate() != month_end_date else add_days(nowdate(), -15)
|
||||||
|
|
||||||
|
asset.calculate_depreciation = 1
|
||||||
|
asset.append("finance_books", {
|
||||||
|
"expected_value_after_useful_life": 200,
|
||||||
|
"depreciation_method": "Straight Line",
|
||||||
|
"total_number_of_depreciations": 3,
|
||||||
|
"frequency_of_depreciation": 10,
|
||||||
|
"depreciation_start_date": month_end_date
|
||||||
|
})
|
||||||
|
asset.submit()
|
||||||
|
serial_nos = frappe.db.get_value('Asset Movement', {'reference_name': pr.name}, 'serial_no')
|
||||||
|
|
||||||
|
mov1 = create_asset_movement(asset=asset_name, purpose = 'Transfer',
|
||||||
|
company=asset.company, source_location = "Mumbai", target_location="Pune", serial_no=serial_nos)
|
||||||
|
self.assertEqual(mov1.target_location, "Pune")
|
||||||
|
|
||||||
|
serial_no = frappe.db.get_value('Serial No', {'asset': asset_name}, 'name')
|
||||||
|
|
||||||
|
employee = make_employee("testassetemp@example.com")
|
||||||
|
create_asset_movement(asset=asset_name, purpose = 'Transfer',
|
||||||
|
company=asset.company, serial_no=serial_no, to_employee=employee)
|
||||||
|
|
||||||
|
self.assertEqual(frappe.db.get_value('Serial No', serial_no, 'employee'), employee)
|
||||||
|
|
||||||
|
create_asset_movement(asset=asset_name, purpose = 'Transfer', company=asset.company,
|
||||||
|
serial_no=serial_no, from_employee=employee, to_employee="_T-Employee-00001")
|
||||||
|
|
||||||
|
self.assertEqual(frappe.db.get_value('Serial No', serial_no, 'location'), "Pune")
|
||||||
|
|
||||||
|
mov4 = create_asset_movement(asset=asset_name, purpose = 'Transfer',
|
||||||
|
company=asset.company, source_location = "Pune", target_location="Nagpur", serial_no=serial_nos)
|
||||||
|
self.assertEqual(mov4.target_location, "Nagpur")
|
||||||
|
self.assertEqual(frappe.db.get_value('Serial No', serial_no, 'location'), "Nagpur")
|
||||||
|
self.assertEqual(frappe.db.get_value('Serial No', serial_no, 'employee'), "_T-Employee-00001")
|
||||||
|
|
||||||
|
def create_asset_movement(**args):
|
||||||
|
args = frappe._dict(args)
|
||||||
|
|
||||||
|
if not args.transaction_date:
|
||||||
|
args.transaction_date = now()
|
||||||
|
|
||||||
movement = frappe.new_doc("Asset Movement")
|
movement = frappe.new_doc("Asset Movement")
|
||||||
movement.update({
|
movement.update({
|
||||||
"asset": asset.name,
|
"asset": args.asset,
|
||||||
"transaction_date": transaction_date,
|
"transaction_date": args.transaction_date,
|
||||||
"target_location": target_location,
|
"target_location": args.target_location,
|
||||||
"company": asset.company
|
"company": args.company,
|
||||||
|
'purpose': args.purpose or 'Receipt',
|
||||||
|
'serial_no': args.serial_no,
|
||||||
|
'quantity': len(get_serial_nos(args.serial_no)) if args.serial_no else 1,
|
||||||
|
'from_employee': "_T-Employee-00001" or args.from_employee,
|
||||||
|
'to_employee': args.to_employee
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if args.source_location:
|
||||||
|
movement.update({
|
||||||
|
'source_location': args.source_location
|
||||||
|
})
|
||||||
|
|
||||||
movement.insert()
|
movement.insert()
|
||||||
movement.submit()
|
movement.submit()
|
||||||
|
|
||||||
return movement
|
return movement
|
||||||
|
|
||||||
|
def make_location():
|
||||||
|
for location in ['Pune', 'Mumbai', 'Nagpur']:
|
||||||
|
if not frappe.db.exists('Location', location):
|
||||||
|
frappe.get_doc({
|
||||||
|
'doctype': 'Location',
|
||||||
|
'location_name': location
|
||||||
|
}).insert(ignore_permissions = True)
|
||||||
|
|
||||||
|
def make_serialized_item():
|
||||||
|
asset_item = "Test Serialized Asset Item"
|
||||||
|
|
||||||
|
if not frappe.db.exists('Item', asset_item):
|
||||||
|
asset_category = frappe.get_all('Asset Category')
|
||||||
|
|
||||||
|
if asset_category:
|
||||||
|
asset_category = asset_category[0].name
|
||||||
|
|
||||||
|
if not asset_category:
|
||||||
|
doc = frappe.get_doc({
|
||||||
|
'doctype': 'Asset Category',
|
||||||
|
'asset_category_name': 'Test Asset Category',
|
||||||
|
'depreciation_method': 'Straight Line',
|
||||||
|
'total_number_of_depreciations': 12,
|
||||||
|
'frequency_of_depreciation': 1,
|
||||||
|
'accounts': [{
|
||||||
|
'company_name': '_Test Company',
|
||||||
|
'fixed_asset_account': '_Test Fixed Asset - _TC',
|
||||||
|
'accumulated_depreciation_account': 'Depreciation - _TC',
|
||||||
|
'depreciation_expense_account': 'Depreciation - _TC'
|
||||||
|
}]
|
||||||
|
}).insert()
|
||||||
|
|
||||||
|
asset_category = doc.name
|
||||||
|
|
||||||
|
make_item(asset_item, {'is_stock_item':0,
|
||||||
|
'stock_uom': 'Box', 'is_fixed_asset': 1, 'has_serial_no': 1,
|
||||||
|
'asset_category': asset_category, 'serial_no_series': 'ABC.###'})
|
||||||
|
|||||||
@@ -23,9 +23,9 @@ frappe.ui.form.on('Asset Value Adjustment', {
|
|||||||
},
|
},
|
||||||
|
|
||||||
set_current_asset_value: function(frm) {
|
set_current_asset_value: function(frm) {
|
||||||
if (frm.doc.finance_book && frm.doc.asset) {
|
if (frm.doc.asset) {
|
||||||
frm.call({
|
frm.call({
|
||||||
method: "erpnext.assets.doctype.asset_adjustment.asset_adjustment.get_current_asset_value",
|
method: "erpnext.assets.doctype.asset_value_adjustment.asset_value_adjustment.get_current_asset_value",
|
||||||
args: {
|
args: {
|
||||||
asset: frm.doc.asset,
|
asset: frm.doc.asset,
|
||||||
finance_book: frm.doc.finance_book
|
finance_book: frm.doc.finance_book
|
||||||
|
|||||||
@@ -139,7 +139,7 @@
|
|||||||
"read_only": 0,
|
"read_only": 0,
|
||||||
"remember_last_selected_value": 0,
|
"remember_last_selected_value": 0,
|
||||||
"report_hide": 0,
|
"report_hide": 0,
|
||||||
"reqd": 1,
|
"reqd": 0,
|
||||||
"search_index": 0,
|
"search_index": 0,
|
||||||
"set_only_once": 0,
|
"set_only_once": 0,
|
||||||
"translatable": 0,
|
"translatable": 0,
|
||||||
@@ -413,7 +413,7 @@
|
|||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"max_attachments": 0,
|
"max_attachments": 0,
|
||||||
"modified": "2018-06-15 11:48:52.880894",
|
"modified": "2018-06-18 17:44:42.383087",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Assets",
|
"module": "Assets",
|
||||||
"name": "Asset Value Adjustment",
|
"name": "Asset Value Adjustment",
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ class AssetValueAdjustment(Document):
|
|||||||
self.difference_amount = flt(self.current_asset_value - self.new_asset_value)
|
self.difference_amount = flt(self.current_asset_value - self.new_asset_value)
|
||||||
|
|
||||||
def set_current_asset_value(self):
|
def set_current_asset_value(self):
|
||||||
if not self.current_asset_value and self.asset and self.finance_book:
|
if not self.current_asset_value and self.asset:
|
||||||
self.current_asset_value = get_current_asset_value(self.asset, self.finance_book)
|
self.current_asset_value = get_current_asset_value(self.asset, self.finance_book)
|
||||||
|
|
||||||
def make_depreciation_entry(self):
|
def make_depreciation_entry(self):
|
||||||
@@ -101,6 +101,9 @@ class AssetValueAdjustment(Document):
|
|||||||
asset_data.db_update()
|
asset_data.db_update()
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_current_asset_value(asset, finance_book):
|
def get_current_asset_value(asset, finance_book=None):
|
||||||
return frappe.db.get_value('Asset Finance Book',
|
cond = {'parent': asset, 'parenttype': 'Asset'}
|
||||||
{'parent': asset, 'parenttype': 'Asset', 'finance_book': finance_book}, 'value_after_depreciation', debug=1)
|
if finance_book:
|
||||||
|
cond.update({'finance_book': finance_book})
|
||||||
|
|
||||||
|
return frappe.db.get_value('Asset Finance Book', cond, 'value_after_depreciation')
|
||||||
|
|||||||
@@ -5,6 +5,90 @@ from __future__ import unicode_literals
|
|||||||
|
|
||||||
import frappe
|
import frappe
|
||||||
import unittest
|
import unittest
|
||||||
|
from frappe.utils import nowdate, get_last_day, add_days
|
||||||
|
from erpnext.assets.doctype.asset.test_asset import create_asset_data
|
||||||
|
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt
|
||||||
|
from erpnext.assets.doctype.asset_value_adjustment.asset_value_adjustment import get_current_asset_value
|
||||||
|
|
||||||
class TestAssetValueAdjustment(unittest.TestCase):
|
class TestAssetValueAdjustment(unittest.TestCase):
|
||||||
pass
|
def setUp(self):
|
||||||
|
create_asset_data()
|
||||||
|
|
||||||
|
def test_current_asset_value(self):
|
||||||
|
pr = make_purchase_receipt(item_code="Macbook Pro",
|
||||||
|
qty=1, rate=100000.0, location="Test Location")
|
||||||
|
|
||||||
|
asset_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, 'name')
|
||||||
|
asset_doc = frappe.get_doc('Asset', asset_name)
|
||||||
|
|
||||||
|
month_end_date = get_last_day(nowdate())
|
||||||
|
purchase_date = nowdate() if nowdate() != month_end_date else add_days(nowdate(), -15)
|
||||||
|
|
||||||
|
asset_doc.available_for_use_date = purchase_date
|
||||||
|
asset_doc.purchase_date = purchase_date
|
||||||
|
asset_doc.calculate_depreciation = 1
|
||||||
|
asset_doc.append("finance_books", {
|
||||||
|
"expected_value_after_useful_life": 200,
|
||||||
|
"depreciation_method": "Straight Line",
|
||||||
|
"total_number_of_depreciations": 3,
|
||||||
|
"frequency_of_depreciation": 10,
|
||||||
|
"depreciation_start_date": month_end_date
|
||||||
|
})
|
||||||
|
asset_doc.submit()
|
||||||
|
|
||||||
|
current_value = get_current_asset_value(asset_doc.name)
|
||||||
|
self.assertEqual(current_value, 100000.0)
|
||||||
|
|
||||||
|
def test_asset_depreciation_value_adjustment(self):
|
||||||
|
pr = make_purchase_receipt(item_code="Macbook Pro",
|
||||||
|
qty=1, rate=100000.0, location="Test Location")
|
||||||
|
|
||||||
|
asset_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, 'name')
|
||||||
|
asset_doc = frappe.get_doc('Asset', asset_name)
|
||||||
|
asset_doc.calculate_depreciation = 1
|
||||||
|
|
||||||
|
month_end_date = get_last_day(nowdate())
|
||||||
|
purchase_date = nowdate() if nowdate() != month_end_date else add_days(nowdate(), -15)
|
||||||
|
|
||||||
|
asset_doc.available_for_use_date = purchase_date
|
||||||
|
asset_doc.purchase_date = purchase_date
|
||||||
|
asset_doc.calculate_depreciation = 1
|
||||||
|
asset_doc.append("finance_books", {
|
||||||
|
"expected_value_after_useful_life": 200,
|
||||||
|
"depreciation_method": "Straight Line",
|
||||||
|
"total_number_of_depreciations": 3,
|
||||||
|
"frequency_of_depreciation": 10,
|
||||||
|
"depreciation_start_date": month_end_date
|
||||||
|
})
|
||||||
|
asset_doc.submit()
|
||||||
|
|
||||||
|
current_value = get_current_asset_value(asset_doc.name)
|
||||||
|
adj_doc = make_asset_value_adjustment(asset = asset_doc.name,
|
||||||
|
current_asset_value = current_value, new_asset_value = 50000.0)
|
||||||
|
adj_doc.submit()
|
||||||
|
|
||||||
|
expected_gle = (
|
||||||
|
("_Test Accumulated Depreciations - _TC", 0.0, 50000.0),
|
||||||
|
("_Test Depreciations - _TC", 50000.0, 0.0)
|
||||||
|
)
|
||||||
|
|
||||||
|
gle = frappe.db.sql("""select account, debit, credit from `tabGL Entry`
|
||||||
|
where voucher_type='Journal Entry' and voucher_no = %s
|
||||||
|
order by account""", adj_doc.journal_entry)
|
||||||
|
|
||||||
|
self.assertEqual(gle, expected_gle)
|
||||||
|
|
||||||
|
def make_asset_value_adjustment(**args):
|
||||||
|
args = frappe._dict(args)
|
||||||
|
|
||||||
|
doc = frappe.get_doc({
|
||||||
|
"doctype": "Asset Value Adjustment",
|
||||||
|
"company": args.company or "_Test Company",
|
||||||
|
"asset": args.asset,
|
||||||
|
"date": args.date or nowdate(),
|
||||||
|
"new_asset_value": args.new_asset_value,
|
||||||
|
"current_asset_value": args.current_asset_value,
|
||||||
|
"cost_center": args.cost_center or "Main - _TC"
|
||||||
|
}).insert()
|
||||||
|
|
||||||
|
return doc
|
||||||
@@ -578,7 +578,6 @@ class BuyingController(StockController):
|
|||||||
'doctype': 'Asset',
|
'doctype': 'Asset',
|
||||||
'item_code': row.item_code,
|
'item_code': row.item_code,
|
||||||
'asset_name': row.item_name,
|
'asset_name': row.item_name,
|
||||||
'status': 'Receipt',
|
|
||||||
'naming_series': item_data.get('asset_naming_series') or 'AST',
|
'naming_series': item_data.get('asset_naming_series') or 'AST',
|
||||||
'asset_category': item_data.get('asset_category'),
|
'asset_category': item_data.get('asset_category'),
|
||||||
'location': row.asset_location,
|
'location': row.asset_location,
|
||||||
|
|||||||
@@ -33,8 +33,6 @@ class TestEmployee(unittest.TestCase):
|
|||||||
self.assertTrue("Subject: Birthday Reminder for {0}".format(employee.employee_name) \
|
self.assertTrue("Subject: Birthday Reminder for {0}".format(employee.employee_name) \
|
||||||
in email_queue[0].message)
|
in email_queue[0].message)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def make_employee(user):
|
def make_employee(user):
|
||||||
if not frappe.db.get_value("User", user):
|
if not frappe.db.get_value("User", user):
|
||||||
frappe.get_doc({
|
frappe.get_doc({
|
||||||
|
|||||||
@@ -332,6 +332,10 @@ class TestPurchaseReceipt(unittest.TestCase):
|
|||||||
serial_nos = frappe.get_all('Serial No', {'asset': asset}, 'name')
|
serial_nos = frappe.get_all('Serial No', {'asset': asset}, 'name')
|
||||||
|
|
||||||
self.assertEquals(len(serial_nos), 3)
|
self.assertEquals(len(serial_nos), 3)
|
||||||
|
|
||||||
|
location = frappe.db.get_value('Serial No', serial_nos[0].name, 'location')
|
||||||
|
self.assertEquals(location, "Test Location")
|
||||||
|
|
||||||
pr.cancel()
|
pr.cancel()
|
||||||
serial_nos = frappe.get_all('Serial No', {'asset': asset}, 'name') or []
|
serial_nos = frappe.get_all('Serial No', {'asset': asset}, 'name') or []
|
||||||
self.assertEquals(len(serial_nos), 0)
|
self.assertEquals(len(serial_nos), 0)
|
||||||
@@ -373,7 +377,8 @@ def make_purchase_receipt(**args):
|
|||||||
"serial_no": args.serial_no,
|
"serial_no": args.serial_no,
|
||||||
"stock_uom": args.stock_uom or "_Test UOM",
|
"stock_uom": args.stock_uom or "_Test UOM",
|
||||||
"uom": args.uom or "_Test UOM",
|
"uom": args.uom or "_Test UOM",
|
||||||
"asset_location": "Test Location" if args.item_code == "Test Serialized Asset Item" else ""
|
"cost_center": args.cost_center or frappe.db.get_value('Company', pr.company, 'cost_center'),
|
||||||
|
"asset_location": args.location or "Test Location"
|
||||||
})
|
})
|
||||||
|
|
||||||
if not args.do_not_save:
|
if not args.do_not_save:
|
||||||
|
|||||||
Reference in New Issue
Block a user