feat: composite WIP asset (copy #37352) (#37353)

* feat: wip composite asset

(cherry picked from commit 4907e7acd4ff549f34f6c9d0144af83db0ad9cc1)

# Conflicts:
#	erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json
#	erpnext/assets/doctype/asset/asset.json
#	erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json

* chore: resolving conflicts

---------

Co-authored-by: anandbaburajan <anandbaburajan@gmail.com>
This commit is contained in:
mergify[bot] 2023-10-04 10:29:18 +05:30 committed by GitHub
parent 9be554a147
commit f4f40cc776
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 404 additions and 52 deletions

View File

@ -479,6 +479,12 @@ cur_frm.set_query("expense_account", "items", function(doc) {
}
});
cur_frm.set_query("wip_composite_asset", "items", function() {
return {
filters: {'is_composite_asset': 1, 'docstatus': 0 }
}
});
cur_frm.cscript.expense_account = function(doc, cdt, cdn){
var d = locals[cdt][cdn];
if(d.idx == 1 && d.expense_account){

View File

@ -77,6 +77,7 @@
"manufacturer_part_no",
"accounting",
"expense_account",
"wip_composite_asset",
"col_break5",
"is_fixed_asset",
"asset_location",
@ -903,12 +904,18 @@
"no_copy": 1,
"options": "Serial and Batch Bundle",
"print_hide": 1
},
{
"fieldname": "wip_composite_asset",
"fieldtype": "Link",
"label": "WIP Composite Asset",
"options": "Asset"
}
],
"idx": 1,
"istable": 1,
"links": [],
"modified": "2023-07-26 12:54:53.178156",
"modified": "2023-10-03 21:01:01.824892",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Purchase Invoice Item",

View File

@ -148,6 +148,15 @@ frappe.ui.form.on('Asset', {
if (frm.doc.docstatus == 0) {
frm.toggle_reqd("finance_books", frm.doc.calculate_depreciation);
if (frm.doc.is_composite_asset && !frm.doc.capitalized_in) {
$('.primary-action').prop('hidden', true);
$('.form-message').text('Capitalize this asset to confirm');
frm.add_custom_button(__("Capitalize Asset"), function() {
frm.trigger("create_asset_capitalization");
});
}
}
},
@ -169,7 +178,7 @@ frappe.ui.form.on('Asset', {
frm.set_df_property('purchase_invoice', 'read_only', 1);
frm.set_df_property('purchase_receipt', 'read_only', 1);
}
else if (frm.doc.is_existing_asset) {
else if (frm.doc.is_existing_asset || frm.doc.is_composite_asset) {
frm.toggle_reqd('purchase_receipt', 0);
frm.toggle_reqd('purchase_invoice', 0);
}
@ -353,7 +362,17 @@ frappe.ui.form.on('Asset', {
is_existing_asset: function(frm) {
frm.trigger("toggle_reference_doc");
// frm.toggle_reqd("next_depreciation_date", (!frm.doc.is_existing_asset && frm.doc.calculate_depreciation));
},
is_composite_asset: function(frm) {
if(frm.doc.is_composite_asset) {
frm.set_value('gross_purchase_amount', 0);
frm.set_df_property('gross_purchase_amount', 'read_only', 1);
} else {
frm.set_df_property('gross_purchase_amount', 'read_only', 0);
}
frm.trigger("toggle_reference_doc");
},
make_sales_invoice: function(frm) {
@ -403,6 +422,19 @@ frappe.ui.form.on('Asset', {
});
},
create_asset_capitalization: function(frm) {
frappe.call({
args: {
"asset": frm.doc.name,
},
method: "erpnext.assets.doctype.asset.asset.create_asset_capitalization",
callback: function(r) {
var doclist = frappe.model.sync(r.message);
frappe.set_route("Form", doclist[0].doctype, doclist[0].name);
}
});
},
split_asset: function(frm) {
const title = __('Split Asset');
@ -466,9 +498,11 @@ frappe.ui.form.on('Asset', {
},
gross_purchase_amount: function(frm) {
frm.doc.finance_books.forEach(d => {
frm.events.set_depreciation_rate(frm, d);
})
if (frm.doc.finance_books) {
frm.doc.finance_books.forEach(d => {
frm.events.set_depreciation_rate(frm, d);
})
}
},
purchase_receipt: (frm) => {

View File

@ -14,6 +14,7 @@
"asset_owner",
"asset_owner_company",
"is_existing_asset",
"is_composite_asset",
"supplier",
"customer",
"image",
@ -72,7 +73,8 @@
"purchase_receipt_amount",
"default_finance_book",
"depr_entry_posting_status",
"amended_from"
"amended_from",
"capitalized_in"
],
"fields": [
{
@ -199,7 +201,7 @@
"fieldtype": "Date",
"label": "Purchase Date",
"read_only": 1,
"read_only_depends_on": "eval:!doc.is_existing_asset",
"read_only_depends_on": "eval:!doc.is_existing_asset && !doc.is_composite_asset",
"reqd": 1
},
{
@ -237,10 +239,12 @@
"default": "0",
"fieldname": "calculate_depreciation",
"fieldtype": "Check",
"label": "Calculate Depreciation"
"label": "Calculate Depreciation",
"read_only_depends_on": "eval:doc.is_composite_asset && !doc.gross_purchase_amount"
},
{
"default": "0",
"depends_on": "eval:!doc.is_composite_asset",
"fieldname": "is_existing_asset",
"fieldtype": "Check",
"label": "Is Existing Asset"
@ -478,7 +482,7 @@
"fieldname": "asset_quantity",
"fieldtype": "Int",
"label": "Asset Quantity",
"read_only_depends_on": "eval:!doc.is_existing_asset"
"read_only_depends_on": "eval:!doc.is_existing_asset && !doc.is_composite_asset"
},
{
"fieldname": "depr_entry_posting_status",
@ -507,6 +511,21 @@
"fieldname": "is_fully_depreciated",
"fieldtype": "Check",
"label": "Is Fully Depreciated"
},
{
"default": "0",
"depends_on": "eval:!doc.is_existing_asset",
"fieldname": "is_composite_asset",
"fieldtype": "Check",
"label": "Is Composite Asset"
},
{
"fieldname": "capitalized_in",
"fieldtype": "Link",
"hidden": 1,
"label": "Capitalized In",
"options": "Asset Capitalization",
"read_only": 1
}
],
"idx": 72,
@ -545,7 +564,7 @@
"table_fieldname": "accounts"
}
],
"modified": "2023-07-28 20:12:44.819616",
"modified": "2023-10-03 23:28:26.732269",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset",

View File

@ -228,7 +228,7 @@ class Asset(AccountsController):
if not self.asset_category:
self.asset_category = frappe.get_cached_value("Item", self.item_code, "asset_category")
if not flt(self.gross_purchase_amount):
if not flt(self.gross_purchase_amount) and not self.is_composite_asset:
frappe.throw(_("Gross Purchase Amount is mandatory"), frappe.MandatoryError)
if is_cwip_accounting_enabled(self.asset_category):
@ -768,6 +768,15 @@ def create_asset_repair(asset, asset_name):
return asset_repair
@frappe.whitelist()
def create_asset_capitalization(asset):
asset_capitalization = frappe.new_doc("Asset Capitalization")
asset_capitalization.update(
{"target_asset": asset, "capitalization_method": "Choose a WIP composite asset"}
)
return asset_capitalization
@frappe.whitelist()
def create_asset_value_adjustment(asset, asset_category, company):
asset_value_adjustment = frappe.new_doc("Asset Value Adjustment")

View File

@ -1744,6 +1744,7 @@ def create_asset(**args):
"location": args.location or "Test Location",
"asset_owner": args.asset_owner or "Company",
"is_existing_asset": args.is_existing_asset or 1,
"is_composite_asset": args.is_composite_asset or 0,
"asset_quantity": args.get("asset_quantity") or 1,
"depr_entry_posting_status": args.depr_entry_posting_status or "",
}

View File

@ -16,9 +16,15 @@ erpnext.assets.AssetCapitalization = class AssetCapitalization extends erpnext.s
refresh() {
this.show_general_ledger();
if ((this.frm.doc.stock_items && this.frm.doc.stock_items.length) || !this.frm.doc.target_is_fixed_asset) {
this.show_stock_ledger();
}
if (this.frm.doc.stock_items && !this.frm.doc.stock_items.length && this.frm.doc.target_asset && this.frm.doc.capitalization_method === "Choose a WIP composite asset") {
this.set_consumed_stock_items_tagged_to_wip_composite_asset(this.frm.doc.target_asset);
this.get_target_asset_details();
}
}
setup_queries() {
@ -35,18 +41,9 @@ erpnext.assets.AssetCapitalization = class AssetCapitalization extends erpnext.s
});
me.frm.set_query("target_asset", function() {
var filters = {};
if (me.frm.doc.target_item_code) {
filters['item_code'] = me.frm.doc.target_item_code;
}
filters['status'] = ["not in", ["Draft", "Scrapped", "Sold", "Capitalized", "Decapitalized"]];
filters['docstatus'] = 1;
return {
filters: filters
};
filters: {'is_composite_asset': 1, 'docstatus': 0 }
}
});
me.frm.set_query("asset", "asset_items", function() {
@ -128,6 +125,39 @@ erpnext.assets.AssetCapitalization = class AssetCapitalization extends erpnext.s
return this.get_target_item_details();
}
target_asset() {
if (this.frm.doc.target_asset && this.frm.doc.capitalization_method === "Choose a WIP composite asset") {
this.set_consumed_stock_items_tagged_to_wip_composite_asset(this.frm.doc.target_asset);
this.get_target_asset_details();
}
}
set_consumed_stock_items_tagged_to_wip_composite_asset(asset) {
var me = this;
if (asset) {
return me.frm.call({
method: "erpnext.assets.doctype.asset_capitalization.asset_capitalization.get_items_tagged_to_wip_composite_asset",
args: {
asset: asset,
},
callback: function (r) {
if (!r.exc && r.message) {
me.frm.clear_table("stock_items");
for (let item of r.message) {
me.frm.add_child("stock_items", item);
}
refresh_field("stock_items");
me.calculate_totals();
}
}
});
}
}
item_code(doc, cdt, cdn) {
var row = frappe.get_doc(cdt, cdn);
if (cdt === "Asset Capitalization Stock Item") {
@ -242,6 +272,26 @@ erpnext.assets.AssetCapitalization = class AssetCapitalization extends erpnext.s
}
}
get_target_asset_details() {
var me = this;
if (me.frm.doc.target_asset) {
return me.frm.call({
method: "erpnext.assets.doctype.asset_capitalization.asset_capitalization.get_target_asset_details",
child: me.frm.doc,
args: {
asset: me.frm.doc.target_asset,
company: me.frm.doc.company,
},
callback: function (r) {
if (!r.exc) {
me.frm.refresh_fields();
}
}
});
}
}
get_consumed_stock_item_details(row) {
var me = this;

View File

@ -8,24 +8,25 @@
"engine": "InnoDB",
"field_order": [
"title",
"company",
"naming_series",
"entry_type",
"target_item_code",
"target_asset",
"target_item_name",
"target_is_fixed_asset",
"target_has_batch_no",
"target_has_serial_no",
"column_break_9",
"target_asset_name",
"capitalization_method",
"target_item_code",
"target_asset_location",
"target_asset",
"target_asset_name",
"target_warehouse",
"target_qty",
"target_stock_uom",
"target_batch_no",
"target_serial_no",
"column_break_5",
"company",
"finance_book",
"posting_date",
"posting_time",
@ -57,12 +58,13 @@
"label": "Title"
},
{
"depends_on": "eval:(doc.target_item_code && !doc.__islocal && doc.capitalization_method !== 'Choose a WIP composite asset') || ((doc.entry_type=='Capitalization' && doc.capitalization_method=='Create a new composite asset') || doc.entry_type=='Decapitalization')",
"fieldname": "target_item_code",
"fieldtype": "Link",
"in_standard_filter": 1,
"label": "Target Item Code",
"options": "Item",
"reqd": 1
"mandatory_depends_on": "eval:(doc.entry_type=='Capitalization' && doc.capitalization_method=='Create a new composite asset') || doc.entry_type=='Decapitalization'",
"options": "Item"
},
{
"depends_on": "eval:doc.target_item_code && doc.target_item_name != doc.target_item_code",
@ -86,16 +88,18 @@
"fieldtype": "Column Break"
},
{
"depends_on": "eval:(doc.target_asset && !doc.__islocal) || (doc.entry_type=='Capitalization' && doc.capitalization_method=='Choose a WIP composite asset')",
"fieldname": "target_asset",
"fieldtype": "Link",
"in_standard_filter": 1,
"label": "Target Asset",
"mandatory_depends_on": "eval:doc.entry_type=='Capitalization' && doc.capitalization_method=='Choose a WIP composite asset'",
"no_copy": 1,
"options": "Asset",
"read_only": 1
"read_only_depends_on": "eval:(doc.entry_type=='Decapitalization') || (doc.entry_type=='Capitalization' && doc.capitalization_method=='Create a new composite asset')"
},
{
"depends_on": "eval:doc.entry_type=='Capitalization'",
"depends_on": "eval:(doc.target_asset_name && !doc.__islocal) || (doc.target_asset && doc.entry_type=='Capitalization' && doc.capitalization_method=='Choose a WIP composite asset')",
"fetch_from": "target_asset.asset_name",
"fieldname": "target_asset_name",
"fieldtype": "Data",
@ -186,12 +190,14 @@
},
{
"default": "1",
"depends_on": "eval:doc.entry_type=='Decapitalization'",
"fieldname": "target_qty",
"fieldtype": "Float",
"label": "Target Qty",
"read_only_depends_on": "eval:doc.entry_type=='Capitalization'"
},
{
"depends_on": "eval:doc.entry_type=='Decapitalization'",
"fetch_from": "target_item_code.stock_uom",
"fieldname": "target_stock_uom",
"fieldtype": "Link",
@ -331,18 +337,26 @@
"read_only": 1
},
{
"depends_on": "eval:doc.entry_type=='Capitalization'",
"depends_on": "eval:doc.entry_type=='Capitalization' && doc.capitalization_method=='Create a new composite asset'",
"fieldname": "target_asset_location",
"fieldtype": "Link",
"label": "Target Asset Location",
"mandatory_depends_on": "eval:doc.entry_type=='Capitalization'",
"mandatory_depends_on": "eval:doc.entry_type=='Capitalization' && doc.capitalization_method=='Create a new composite asset'",
"options": "Location"
},
{
"depends_on": "eval:doc.entry_type=='Capitalization'",
"fieldname": "capitalization_method",
"fieldtype": "Select",
"label": "Capitalization Method",
"mandatory_depends_on": "eval:doc.entry_type=='Capitalization'",
"options": "\nCreate a new composite asset\nChoose a WIP composite asset"
}
],
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
"modified": "2023-06-22 14:17:07.995120",
"modified": "2023-10-03 22:55:59.461456",
"modified_by": "Administrator",
"module": "Assets",
"name": "Asset Capitalization",

View File

@ -53,6 +53,7 @@ class AssetCapitalization(StockController):
self.validate_posting_time()
self.set_missing_values(for_validate=True)
self.validate_target_item()
self.validate_target_asset()
self.validate_consumed_stock_item()
self.validate_consumed_asset_item()
self.validate_service_item()
@ -67,12 +68,12 @@ class AssetCapitalization(StockController):
def before_submit(self):
self.validate_source_mandatory()
if self.entry_type == "Capitalization":
self.create_target_asset()
self.create_target_asset()
def on_submit(self):
self.update_stock_ledger()
self.make_gl_entries()
self.update_target_asset()
def on_cancel(self):
self.ignore_linked_doctypes = (
@ -94,6 +95,11 @@ class AssetCapitalization(StockController):
if self.meta.has_field(k) and (not self.get(k) or k in force_fields):
self.set(k, v)
target_asset_details = get_target_asset_details(self.target_asset, self.company)
for k, v in target_asset_details.items():
if self.meta.has_field(k) and (not self.get(k) or k in force_fields):
self.set(k, v)
for d in self.stock_items:
args = self.as_dict()
args.update(d.as_dict())
@ -155,6 +161,33 @@ class AssetCapitalization(StockController):
self.validate_item(target_item)
def validate_target_asset(self):
if self.target_asset:
target_asset = self.get_asset_for_validation(self.target_asset)
if not target_asset.is_composite_asset:
frappe.throw(_("Target Asset {0} needs to be composite asset").format(target_asset.name))
if target_asset.item_code != self.target_item_code:
frappe.throw(
_("Asset {0} does not belong to Item {1}").format(self.target_asset, self.target_item_code)
)
if target_asset.status in ("Scrapped", "Sold", "Capitalized", "Decapitalized"):
frappe.throw(
_("Target Asset {0} cannot be {1}").format(target_asset.name, target_asset.status)
)
if target_asset.docstatus == 1:
frappe.throw(_("Target Asset {0} cannot be submitted").format(target_asset.name))
elif target_asset.docstatus == 2:
frappe.throw(_("Target Asset {0} cannot be cancelled").format(target_asset.name))
if target_asset.company != self.company:
frappe.throw(
_("Target Asset {0} does not belong to company {1}").format(target_asset.name, self.company)
)
def validate_consumed_stock_item(self):
for d in self.stock_items:
if d.item_code:
@ -179,7 +212,23 @@ class AssetCapitalization(StockController):
)
asset = self.get_asset_for_validation(d.asset)
self.validate_asset(asset)
if asset.status in ("Draft", "Scrapped", "Sold", "Capitalized", "Decapitalized"):
frappe.throw(
_("Row #{0}: Consumed Asset {1} cannot be {2}").format(d.idx, asset.name, asset.status)
)
if asset.docstatus == 0:
frappe.throw(_("Row #{0}: Consumed Asset {1} cannot be Draft").format(d.idx, asset.name))
elif asset.docstatus == 2:
frappe.throw(_("Row #{0}: Consumed Asset {1} cannot be cancelled").format(d.idx, asset.name))
if asset.company != self.company:
frappe.throw(
_("Row #{0}: Consumed Asset {1} does not belong to company {2}").format(
d.idx, asset.name, self.company
)
)
def validate_service_item(self):
for d in self.service_items:
@ -214,21 +263,12 @@ class AssetCapitalization(StockController):
def get_asset_for_validation(self, asset):
return frappe.db.get_value(
"Asset", asset, ["name", "item_code", "company", "status", "docstatus"], as_dict=1
"Asset",
asset,
["name", "item_code", "company", "status", "docstatus", "is_composite_asset"],
as_dict=1,
)
def validate_asset(self, asset):
if asset.status in ("Draft", "Scrapped", "Sold", "Capitalized", "Decapitalized"):
frappe.throw(_("Asset {0} is {1}").format(asset.name, asset.status))
if asset.docstatus == 0:
frappe.throw(_("Asset {0} is Draft").format(asset.name))
if asset.docstatus == 2:
frappe.throw(_("Asset {0} is cancelled").format(asset.name))
if asset.company != self.company:
frappe.throw(_("Asset {0} does not belong to company {1}").format(asset.name, self.company))
@frappe.whitelist()
def set_warehouse_details(self):
for d in self.get("stock_items"):
@ -495,16 +535,25 @@ class AssetCapitalization(StockController):
)
def create_target_asset(self):
if (
self.entry_type != "Capitalization"
or self.capitalization_method != "Create a new composite asset"
):
return
total_target_asset_value = flt(self.total_value, self.precision("total_value"))
asset_doc = frappe.new_doc("Asset")
asset_doc.company = self.company
asset_doc.item_code = self.target_item_code
asset_doc.is_existing_asset = 1
asset_doc.is_composite_asset = 1
asset_doc.location = self.target_asset_location
asset_doc.available_for_use_date = self.posting_date
asset_doc.purchase_date = self.posting_date
asset_doc.gross_purchase_amount = total_target_asset_value
asset_doc.purchase_receipt_amount = total_target_asset_value
asset_doc.purchase_receipt_amount = total_target_asset_value
asset_doc.capitalized_in = self.name
asset_doc.flags.ignore_validate = True
asset_doc.flags.asset_created_via_asset_capitalization = True
asset_doc.insert()
@ -528,6 +577,28 @@ class AssetCapitalization(StockController):
).format(get_link_to_form("Asset", asset_doc.name))
)
def update_target_asset(self):
if (
self.entry_type != "Capitalization"
or self.capitalization_method != "Choose a WIP composite asset"
):
return
total_target_asset_value = flt(self.total_value, self.precision("total_value"))
asset_doc = frappe.get_doc("Asset", self.target_asset)
asset_doc.gross_purchase_amount = total_target_asset_value
asset_doc.purchase_receipt_amount = total_target_asset_value
asset_doc.capitalized_in = self.name
asset_doc.flags.ignore_validate = True
asset_doc.save()
frappe.msgprint(
_(
"Asset {0} has been updated. Please set the depreciation details if any and submit it."
).format(get_link_to_form("Asset", asset_doc.name))
)
def restore_consumed_asset_items(self):
for item in self.asset_items:
asset = frappe.get_doc("Asset", item.asset)
@ -612,6 +683,33 @@ def get_target_item_details(item_code=None, company=None):
return out
@frappe.whitelist()
def get_target_asset_details(asset=None, company=None):
out = frappe._dict()
# Get Asset Details
asset_details = frappe._dict()
if asset:
asset_details = frappe.db.get_value("Asset", asset, ["asset_name", "item_code"], as_dict=1)
if not asset_details:
frappe.throw(_("Asset {0} does not exist").format(asset))
# Re-set item code from Asset
out.target_item_code = asset_details.item_code
# Set Asset Details
out.asset_name = asset_details.asset_name
if asset_details.item_code:
out.target_fixed_asset_account = get_asset_category_account(
"fixed_asset_account", item=asset_details.item_code, company=company
)
else:
out.target_fixed_asset_account = None
return out
@frappe.whitelist()
def get_consumed_stock_item_details(args):
if isinstance(args, str):
@ -760,3 +858,30 @@ def get_service_item_details(args):
)
return out
@frappe.whitelist()
def get_items_tagged_to_wip_composite_asset(asset):
fields = [
"item_code",
"item_name",
"batch_no",
"serial_no",
"stock_qty",
"stock_uom",
"warehouse",
"cost_center",
"qty",
"valuation_rate",
"amount",
]
pi_items = frappe.get_all(
"Purchase Invoice Item", filters={"wip_composite_asset": asset}, fields=fields
)
pr_items = frappe.get_all(
"Purchase Receipt Item", filters={"wip_composite_asset": asset}, fields=fields
)
return pi_items + pr_items

View File

@ -58,6 +58,7 @@ class TestAssetCapitalization(unittest.TestCase):
# Create and submit Asset Captitalization
asset_capitalization = create_asset_capitalization(
entry_type="Capitalization",
capitalization_method="Create a new composite asset",
target_item_code="Macbook Pro",
target_asset_location="Test Location",
stock_qty=stock_qty,
@ -147,6 +148,7 @@ class TestAssetCapitalization(unittest.TestCase):
# Create and submit Asset Captitalization
asset_capitalization = create_asset_capitalization(
entry_type="Capitalization",
capitalization_method="Create a new composite asset",
target_item_code="Macbook Pro",
target_asset_location="Test Location",
stock_qty=stock_qty,
@ -211,6 +213,77 @@ class TestAssetCapitalization(unittest.TestCase):
self.assertFalse(get_actual_gle_dict(asset_capitalization.name))
self.assertFalse(get_actual_sle_dict(asset_capitalization.name))
def test_capitalization_with_wip_composite_asset(self):
company = "_Test Company with perpetual inventory"
set_depreciation_settings_in_company(company=company)
stock_rate = 1000
stock_qty = 2
stock_amount = 2000
total_amount = 2000
wip_composite_asset = create_asset(
asset_name="Asset Capitalization WIP Composite Asset",
is_composite_asset=1,
warehouse="Stores - TCP1",
company=company,
)
# Create and submit Asset Captitalization
asset_capitalization = create_asset_capitalization(
entry_type="Capitalization",
capitalization_method="Choose a WIP composite asset",
target_asset=wip_composite_asset,
target_asset_location="Test Location",
stock_qty=stock_qty,
stock_rate=stock_rate,
service_expense_account="Expenses Included In Asset Valuation - TCP1",
company=company,
submit=1,
)
# Test Asset Capitalization values
self.assertEqual(asset_capitalization.entry_type, "Capitalization")
self.assertEqual(asset_capitalization.capitalization_method, "Choose a WIP composite asset")
self.assertEqual(asset_capitalization.target_qty, 1)
self.assertEqual(asset_capitalization.stock_items[0].valuation_rate, stock_rate)
self.assertEqual(asset_capitalization.stock_items[0].amount, stock_amount)
self.assertEqual(asset_capitalization.stock_items_total, stock_amount)
self.assertEqual(asset_capitalization.total_value, total_amount)
self.assertEqual(asset_capitalization.target_incoming_rate, total_amount)
# Test Target Asset values
target_asset = frappe.get_doc("Asset", asset_capitalization.target_asset)
self.assertEqual(target_asset.gross_purchase_amount, total_amount)
self.assertEqual(target_asset.purchase_receipt_amount, total_amount)
# Test General Ledger Entries
expected_gle = {
"_Test Fixed Asset - TCP1": 2000,
"_Test Warehouse - TCP1": -2000,
}
actual_gle = get_actual_gle_dict(asset_capitalization.name)
self.assertEqual(actual_gle, expected_gle)
# Test Stock Ledger Entries
expected_sle = {
("Capitalization Source Stock Item", "_Test Warehouse - TCP1"): {
"actual_qty": -stock_qty,
"stock_value_difference": -stock_amount,
}
}
actual_sle = get_actual_sle_dict(asset_capitalization.name)
self.assertEqual(actual_sle, expected_sle)
# Cancel Asset Capitalization and make test entries and status are reversed
asset_capitalization.cancel()
self.assertFalse(get_actual_gle_dict(asset_capitalization.name))
self.assertFalse(get_actual_sle_dict(asset_capitalization.name))
def test_decapitalization_with_depreciation(self):
# Variables
purchase_date = "2020-01-01"
@ -347,6 +420,7 @@ def create_asset_capitalization(**args):
asset_capitalization.update(
{
"entry_type": args.entry_type or "Capitalization",
"capitalization_method": args.capitalization_method or None,
"company": company,
"posting_date": args.posting_date or now.strftime("%Y-%m-%d"),
"posting_time": args.posting_time or now.strftime("%H:%M:%S.%f"),

View File

@ -37,6 +37,12 @@ frappe.ui.form.on("Purchase Receipt", {
}
});
frm.set_query("wip_composite_asset", "items", function() {
return {
filters: {'is_composite_asset': 1, 'docstatus': 0 }
}
});
frm.set_query("taxes_and_charges", function() {
return {
filters: {'company': frm.doc.company }

View File

@ -117,6 +117,7 @@
"accounting_details_section",
"expense_account",
"item_tax_rate",
"wip_composite_asset",
"column_break_102",
"provisional_expense_account",
"accounting_dimensions_section",
@ -1056,12 +1057,18 @@
"fieldname": "add_serial_batch_bundle",
"fieldtype": "Button",
"label": "Add Serial / Batch No"
},
{
"fieldname": "wip_composite_asset",
"fieldtype": "Link",
"label": "WIP Composite Asset",
"options": "Asset"
}
],
"idx": 1,
"istable": 1,
"links": [],
"modified": "2023-08-11 16:16:16.504549",
"modified": "2023-10-03 21:11:50.547261",
"modified_by": "Administrator",
"module": "Stock",
"name": "Purchase Receipt Item",