diff --git a/erpnext/assets/doctype/asset_movement/asset_movement.py b/erpnext/assets/doctype/asset_movement/asset_movement.py index a90b45d442d..0737a88d319 100644 --- a/erpnext/assets/doctype/asset_movement/asset_movement.py +++ b/erpnext/assets/doctype/asset_movement/asset_movement.py @@ -63,20 +63,21 @@ class AssetMovement(Document): frappe.throw(_("Source and Target Location cannot be same")) if self.purpose == "Receipt": - if not (d.source_location or d.from_employee) and not (d.target_location or d.to_employee): + if not (d.source_location) and not (d.target_location or d.to_employee): frappe.throw( _("Target Location or To Employee is required while receiving Asset {0}").format(d.asset) ) - elif d.from_employee and not d.target_location: - frappe.throw( - _("Target Location is required while receiving Asset {0} from an employee").format(d.asset) - ) - elif d.to_employee and d.target_location: - frappe.throw( - _( - "Asset {0} cannot be received at a location and given to an employee in a single movement" - ).format(d.asset) - ) + elif d.source_location: + if d.from_employee and not d.target_location: + frappe.throw( + _("Target Location is required while receiving Asset {0} from an employee").format(d.asset) + ) + elif d.to_employee and d.target_location: + frappe.throw( + _( + "Asset {0} cannot be received at a location and given to an employee in a single movement" + ).format(d.asset) + ) def validate_employee(self): for d in self.assets: diff --git a/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py b/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py index 6911f94bbbb..94c77ea517c 100644 --- a/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py +++ b/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py @@ -54,12 +54,12 @@ def get_conditions(filters): conditions["cost_center"] = filters.get("cost_center") if status: - # In Store assets are those that are not sold or scrapped + # In Store assets are those that are not sold or scrapped or capitalized or decapitalized operand = "not in" if status not in "In Location": operand = "in" - conditions["status"] = (operand, ["Sold", "Scrapped"]) + conditions["status"] = (operand, ["Sold", "Scrapped", "Capitalized", "Decapitalized"]) return conditions @@ -71,36 +71,6 @@ def get_data(filters): pr_supplier_map = get_purchase_receipt_supplier_map() pi_supplier_map = get_purchase_invoice_supplier_map() - group_by = frappe.scrub(filters.get("group_by")) - - if group_by == "asset_category": - fields = ["asset_category", "gross_purchase_amount", "opening_accumulated_depreciation"] - assets_record = frappe.db.get_all("Asset", filters=conditions, fields=fields, group_by=group_by) - - elif group_by == "location": - fields = ["location", "gross_purchase_amount", "opening_accumulated_depreciation"] - assets_record = frappe.db.get_all("Asset", filters=conditions, fields=fields, group_by=group_by) - - else: - fields = [ - "name as asset_id", - "asset_name", - "status", - "department", - "company", - "cost_center", - "calculate_depreciation", - "purchase_receipt", - "asset_category", - "purchase_date", - "gross_purchase_amount", - "location", - "available_for_use_date", - "purchase_invoice", - "opening_accumulated_depreciation", - ] - assets_record = frappe.db.get_all("Asset", filters=conditions, fields=fields) - assets_linked_to_fb = get_assets_linked_to_fb(filters) company_fb = frappe.get_cached_value("Company", filters.company, "default_finance_book") @@ -114,6 +84,31 @@ def get_data(filters): depreciation_amount_map = get_asset_depreciation_amount_map(filters, finance_book) + group_by = frappe.scrub(filters.get("group_by")) + + if group_by in ("asset_category", "location"): + data = get_group_by_data(group_by, conditions, assets_linked_to_fb, depreciation_amount_map) + return data + + fields = [ + "name as asset_id", + "asset_name", + "status", + "department", + "company", + "cost_center", + "calculate_depreciation", + "purchase_receipt", + "asset_category", + "purchase_date", + "gross_purchase_amount", + "location", + "available_for_use_date", + "purchase_invoice", + "opening_accumulated_depreciation", + ] + assets_record = frappe.db.get_all("Asset", filters=conditions, fields=fields) + for asset in assets_record: if ( assets_linked_to_fb @@ -136,7 +131,7 @@ def get_data(filters): or pi_supplier_map.get(asset.purchase_invoice), "gross_purchase_amount": asset.gross_purchase_amount, "opening_accumulated_depreciation": asset.opening_accumulated_depreciation, - "depreciated_amount": get_depreciation_amount_of_asset(asset, depreciation_amount_map), + "depreciated_amount": depreciation_amount_map.get(asset.asset_id) or 0.0, "available_for_use_date": asset.available_for_use_date, "location": asset.location, "asset_category": asset.asset_category, @@ -230,12 +225,11 @@ def get_assets_linked_to_fb(filters): return assets_linked_to_fb -def get_depreciation_amount_of_asset(asset, depreciation_amount_map): - return depreciation_amount_map.get(asset.asset_id) or 0.0 - - def get_asset_depreciation_amount_map(filters, finance_book): - date = filters.to_date if filters.filter_based_on == "Date Range" else filters.year_end_date + start_date = ( + filters.from_date if filters.filter_based_on == "Date Range" else filters.year_start_date + ) + end_date = filters.to_date if filters.filter_based_on == "Date Range" else filters.year_end_date asset = frappe.qb.DocType("Asset") gle = frappe.qb.DocType("GL Entry") @@ -256,25 +250,77 @@ def get_asset_depreciation_amount_map(filters, finance_book): ) .where(gle.debit != 0) .where(gle.is_cancelled == 0) + .where(company.name == filters.company) .where(asset.docstatus == 1) - .groupby(asset.name) ) + if filters.only_existing_assets: + query = query.where(asset.is_existing_asset == 1) + if filters.asset_category: + query = query.where(asset.asset_category == filters.asset_category) + if filters.cost_center: + query = query.where(asset.cost_center == filters.cost_center) + if filters.status: + if filters.status == "In Location": + query = query.where(asset.status.notin(["Sold", "Scrapped", "Capitalized", "Decapitalized"])) + else: + query = query.where(asset.status.isin(["Sold", "Scrapped", "Capitalized", "Decapitalized"])) if finance_book: query = query.where( (gle.finance_book.isin([cstr(finance_book), ""])) | (gle.finance_book.isnull()) ) else: query = query.where((gle.finance_book.isin([""])) | (gle.finance_book.isnull())) - if filters.filter_based_on in ("Date Range", "Fiscal Year"): - query = query.where(gle.posting_date <= date) + query = query.where(gle.posting_date >= start_date) + query = query.where(gle.posting_date <= end_date) + + query = query.groupby(asset.name) asset_depr_amount_map = query.run() return dict(asset_depr_amount_map) +def get_group_by_data(group_by, conditions, assets_linked_to_fb, depreciation_amount_map): + fields = [ + group_by, + "name", + "gross_purchase_amount", + "opening_accumulated_depreciation", + "calculate_depreciation", + ] + assets = frappe.db.get_all("Asset", filters=conditions, fields=fields) + + data = [] + + for a in assets: + if assets_linked_to_fb and a.calculate_depreciation and a.name not in assets_linked_to_fb: + continue + + a["depreciated_amount"] = depreciation_amount_map.get(a["name"], 0.0) + a["asset_value"] = ( + a["gross_purchase_amount"] - a["opening_accumulated_depreciation"] - a["depreciated_amount"] + ) + + del a["name"] + del a["calculate_depreciation"] + + idx = ([i for i, d in enumerate(data) if a[group_by] == d[group_by]] or [None])[0] + if idx is None: + data.append(a) + else: + for field in ( + "gross_purchase_amount", + "opening_accumulated_depreciation", + "depreciated_amount", + "asset_value", + ): + data[idx][field] = data[idx][field] + a[field] + + return data + + def get_purchase_receipt_supplier_map(): return frappe._dict( frappe.db.sql( @@ -313,35 +359,35 @@ def get_columns(filters): "fieldtype": "Link", "fieldname": frappe.scrub(filters.get("group_by")), "options": filters.get("group_by"), - "width": 120, + "width": 216, }, { "label": _("Gross Purchase Amount"), "fieldname": "gross_purchase_amount", "fieldtype": "Currency", "options": "company:currency", - "width": 100, + "width": 250, }, { "label": _("Opening Accumulated Depreciation"), "fieldname": "opening_accumulated_depreciation", "fieldtype": "Currency", "options": "company:currency", - "width": 90, + "width": 250, }, { "label": _("Depreciated Amount"), "fieldname": "depreciated_amount", "fieldtype": "Currency", "options": "company:currency", - "width": 100, + "width": 250, }, { "label": _("Asset Value"), "fieldname": "asset_value", "fieldtype": "Currency", "options": "company:currency", - "width": 100, + "width": 250, }, ] diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js index a00911540ab..5ae00c34088 100644 --- a/erpnext/public/js/controllers/transaction.js +++ b/erpnext/public/js/controllers/transaction.js @@ -1068,6 +1068,16 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({ this.frm.set_df_property("conversion_rate", "read_only", erpnext.stale_rate_allowed() ? 0 : 1); }, + apply_discount_on_item: function(doc, cdt, cdn, field) { + var item = frappe.get_doc(cdt, cdn); + if(!item.price_list_rate) { + item[field] = 0.0; + } else { + this.price_list_rate(doc, cdt, cdn); + } + this.set_gross_profit(item); + }, + shipping_rule: function() { var me = this; if(this.frm.doc.shipping_rule) { @@ -1720,6 +1730,9 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({ () => { if(args.items.length) { me._set_values_for_item_list(r.message.children); + $.each(r.message.children || [], function(i, d) { + me.apply_discount_on_item(d, d.doctype, d.name, 'discount_percentage'); + }); } }, () => { me.in_apply_price_list = false; } diff --git a/erpnext/selling/sales_common.js b/erpnext/selling/sales_common.js index cf1d19192a1..f4e5f8a37f7 100644 --- a/erpnext/selling/sales_common.js +++ b/erpnext/selling/sales_common.js @@ -145,16 +145,6 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({ this.apply_discount_on_item(doc, cdt, cdn, 'discount_amount'); }, - apply_discount_on_item: function(doc, cdt, cdn, field) { - var item = frappe.get_doc(cdt, cdn); - if(!item.price_list_rate) { - item[field] = 0.0; - } else { - this.price_list_rate(doc, cdt, cdn); - } - this.set_gross_profit(item); - }, - commission_rate: function() { this.calculate_commission(); },