diff --git a/CODEOWNERS b/CODEOWNERS index 6e751cc9aa6..77761dd14e2 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -4,7 +4,7 @@ # the repo. Unless a later match takes precedence, erpnext/accounts/ @nextchamp-saqib @deepeshgarg007 @ruthra-kumar -erpnext/assets/ @nextchamp-saqib @deepeshgarg007 @ruthra-kumar +erpnext/assets/ @anandbaburajan @deepeshgarg007 erpnext/erpnext_integrations/ @nextchamp-saqib erpnext/loan_management/ @nextchamp-saqib @deepeshgarg007 erpnext/regional @nextchamp-saqib @deepeshgarg007 @ruthra-kumar diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py index c50336e1e61..9ea93f90e03 100644 --- a/erpnext/accounts/doctype/journal_entry/journal_entry.py +++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py @@ -248,21 +248,16 @@ class JournalEntry(AccountsController): ): processed_assets.append(d.reference_name) - asset = frappe.db.get_value( - "Asset", d.reference_name, ["calculate_depreciation", "value_after_depreciation"], as_dict=1 - ) + asset = frappe.get_doc("Asset", d.reference_name) if asset.calculate_depreciation: continue depr_value = d.debit or d.credit - frappe.db.set_value( - "Asset", - d.reference_name, - "value_after_depreciation", - asset.value_after_depreciation - depr_value, - ) + asset.db_set("value_after_depreciation", asset.value_after_depreciation - depr_value) + + asset.set_status() def update_inter_company_jv(self): if ( @@ -351,12 +346,9 @@ class JournalEntry(AccountsController): else: depr_value = d.debit or d.credit - frappe.db.set_value( - "Asset", - d.reference_name, - "value_after_depreciation", - asset.value_after_depreciation + depr_value, - ) + asset.db_set("value_after_depreciation", asset.value_after_depreciation + depr_value) + + asset.set_status() def unlink_inter_company_jv(self): if ( diff --git a/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.py b/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.py index 655c4ec0035..115b415eeda 100644 --- a/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.py +++ b/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.py @@ -21,8 +21,24 @@ class POSClosingEntry(StatusUpdater): if frappe.db.get_value("POS Opening Entry", self.pos_opening_entry, "status") != "Open": frappe.throw(_("Selected POS Opening Entry should be open."), title=_("Invalid Opening Entry")) + self.validate_duplicate_pos_invoices() self.validate_pos_invoices() + def validate_duplicate_pos_invoices(self): + pos_occurences = {} + for idx, inv in enumerate(self.pos_transactions, 1): + pos_occurences.setdefault(inv.pos_invoice, []).append(idx) + + error_list = [] + for key, value in pos_occurences.items(): + if len(value) > 1: + error_list.append( + _("{} is added multiple times on rows: {}".format(frappe.bold(key), frappe.bold(value))) + ) + + if error_list: + frappe.throw(error_list, title=_("Duplicate POS Invoices found"), as_list=True) + def validate_pos_invoices(self): invalid_rows = [] for d in self.pos_transactions: diff --git a/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py b/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py index fc356f2378d..3cfffc8d368 100644 --- a/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py +++ b/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py @@ -18,6 +18,22 @@ class POSInvoiceMergeLog(Document): def validate(self): self.validate_customer() self.validate_pos_invoice_status() + self.validate_duplicate_pos_invoices() + + def validate_duplicate_pos_invoices(self): + pos_occurences = {} + for idx, inv in enumerate(self.pos_invoices, 1): + pos_occurences.setdefault(inv.pos_invoice, []).append(idx) + + error_list = [] + for key, value in pos_occurences.items(): + if len(value) > 1: + error_list.append( + _("{} is added multiple times on rows: {}".format(frappe.bold(key), frappe.bold(value))) + ) + + if error_list: + frappe.throw(error_list, title=_("Duplicate POS Invoices found"), as_list=True) def validate_customer(self): if self.merge_invoices_based_on == "Customer Group": @@ -427,6 +443,8 @@ def create_merge_logs(invoice_by_customer, closing_entry=None): if closing_entry: closing_entry.set_status(update=True, status="Failed") + if type(error_message) == list: + error_message = frappe.json.dumps(error_message) closing_entry.db_set("error_message", error_message) raise diff --git a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py index 08ca96afb9f..ea3ec5fc606 100644 --- a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py +++ b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py @@ -256,7 +256,7 @@ def get_tax_amount(party_type, parties, inv, tax_details, posting_date, pan_no=N tax_amount = get_tcs_amount(parties, inv, tax_details, vouchers, advance_vouchers) if cint(tax_details.round_off_tax_amount): - tax_amount = round(tax_amount) + tax_amount = normal_round(tax_amount) return tax_amount, tax_deducted, tax_deducted_on_advances, voucher_wise_amount @@ -555,3 +555,20 @@ def is_valid_certificate( valid = True return valid + + +def normal_round(number): + """ + Rounds a number to the nearest integer. + :param number: The number to round. + """ + decimal_part = number - int(number) + + if decimal_part >= 0.5: + decimal_part = 1 + else: + decimal_part = 0 + + number = int(number) + decimal_part + + return number diff --git a/erpnext/assets/doctype/asset/asset.js b/erpnext/assets/doctype/asset/asset.js index 1f158a3a942..ccd8d8171a8 100644 --- a/erpnext/assets/doctype/asset/asset.js +++ b/erpnext/assets/doctype/asset/asset.js @@ -246,7 +246,7 @@ frappe.ui.form.on('Asset', { $.each(depr_entries || [], function(i, v) { x_intervals.push(frappe.format(v.posting_date, { fieldtype: 'Date' })); let last_asset_value = asset_values[asset_values.length - 1] - asset_values.push(last_asset_value - v.value); + asset_values.push(flt(last_asset_value - v.value, precision('gross_purchase_amount'))); }); } diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py index 9033710b324..2bd30c6cbd4 100644 --- a/erpnext/assets/doctype/asset/asset.py +++ b/erpnext/assets/doctype/asset/asset.py @@ -667,11 +667,15 @@ class Asset(AccountsController): if self.journal_entry_for_scrap: status = "Scrapped" - elif self.finance_books: - idx = self.get_default_finance_book_idx() or 0 + else: + expected_value_after_useful_life = 0 + value_after_depreciation = self.value_after_depreciation - 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.calculate_depreciation: + idx = self.get_default_finance_book_idx() or 0 + + 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 flt(value_after_depreciation) <= expected_value_after_useful_life: status = "Fully Depreciated" @@ -703,24 +707,6 @@ class Asset(AccountsController): if d.finance_book == self.default_finance_book: return cint(d.idx) - 1 - @frappe.whitelist() - def get_manual_depreciation_entries(self): - (_, _, depreciation_expense_account) = get_depreciation_accounts(self) - - gle = frappe.qb.DocType("GL Entry") - - records = ( - frappe.qb.from_(gle) - .select(gle.voucher_no.as_("name"), gle.debit.as_("value"), gle.posting_date) - .where(gle.against_voucher == self.name) - .where(gle.account == depreciation_expense_account) - .where(gle.debit != 0) - .where(gle.is_cancelled == 0) - .orderby(gle.posting_date) - ).run(as_dict=True) - - return records - def validate_make_gl_entry(self): purchase_document = self.get_purchase_document() if not purchase_document: @@ -837,6 +823,25 @@ class Asset(AccountsController): make_gl_entries(gl_entries) self.db_set("booked_fixed_asset", 1) + @frappe.whitelist() + def get_manual_depreciation_entries(self): + (_, _, depreciation_expense_account) = get_depreciation_accounts(self) + + gle = frappe.qb.DocType("GL Entry") + + records = ( + frappe.qb.from_(gle) + .select(gle.voucher_no.as_("name"), gle.debit.as_("value"), gle.posting_date) + .where(gle.against_voucher == self.name) + .where(gle.account == depreciation_expense_account) + .where(gle.debit != 0) + .where(gle.is_cancelled == 0) + .orderby(gle.posting_date) + .orderby(gle.creation) + ).run(as_dict=True) + + return records + @frappe.whitelist() def get_depreciation_rate(self, args, on_validate=False): if isinstance(args, string_types): diff --git a/erpnext/assets/doctype/asset/depreciation.py b/erpnext/assets/doctype/asset/depreciation.py index e83b9b2080a..fc3af44947d 100644 --- a/erpnext/assets/doctype/asset/depreciation.py +++ b/erpnext/assets/doctype/asset/depreciation.py @@ -144,7 +144,7 @@ def make_depreciation_entry(asset_name, date=None): finance_books.value_after_depreciation -= d.depreciation_amount finance_books.db_update() - frappe.db.set_value("Asset", asset_name, "depr_entry_posting_status", "Successful") + asset.db_set("depr_entry_posting_status", "Successful") asset.set_status() diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.py b/erpnext/assets/doctype/asset_repair/asset_repair.py index 94b4c641333..cd8fe5b18b7 100644 --- a/erpnext/assets/doctype/asset_repair/asset_repair.py +++ b/erpnext/assets/doctype/asset_repair/asset_repair.py @@ -82,6 +82,9 @@ class AssetRepair(AccountsController): self.asset_doc.prepare_depreciation_data() self.asset_doc.save() + def after_delete(self): + frappe.get_doc("Asset", self.asset).set_status() + def check_repair_status(self): if self.repair_status == "Pending": frappe.throw(_("Please update Repair Status.")) 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 0ab3e16e424..ae99c491a93 100644 --- a/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py +++ b/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py @@ -151,6 +151,7 @@ def prepare_chart_data(data, filters): filters.filter_based_on, "Monthly", company=filters.company, + ignore_fiscal_year=True, ) for d in period_list: diff --git a/erpnext/hr/report/employee_leave_balance/employee_leave_balance.js b/erpnext/hr/report/employee_leave_balance/employee_leave_balance.js index 2339350d065..62cc7385560 100644 --- a/erpnext/hr/report/employee_leave_balance/employee_leave_balance.js +++ b/erpnext/hr/report/employee_leave_balance/employee_leave_balance.js @@ -2,53 +2,60 @@ // License: GNU General Public License v3. See license.txt frappe.query_reports["Employee Leave Balance"] = { - "filters": [ + filters: [ { - "fieldname": "from_date", - "label": __("From Date"), - "fieldtype": "Date", - "reqd": 1, - "default": frappe.defaults.get_default("year_start_date") + fieldname: "from_date", + label: __("From Date"), + fieldtype: "Date", + reqd: 1, + default: frappe.defaults.get_default("year_start_date") }, { - "fieldname": "to_date", - "label": __("To Date"), - "fieldtype": "Date", - "reqd": 1, - "default": frappe.defaults.get_default("year_end_date") + fieldname: "to_date", + label: __("To Date"), + fieldtype: "Date", + reqd: 1, + default: frappe.defaults.get_default("year_end_date") }, { - "fieldname": "company", - "label": __("Company"), - "fieldtype": "Link", - "options": "Company", - "reqd": 1, - "default": frappe.defaults.get_user_default("Company") + label: __("Company"), + fieldname: "company", + fieldtype: "Link", + options: "Company", + reqd: 1, + default: frappe.defaults.get_user_default("Company") }, { - "fieldname": "department", - "label": __("Department"), - "fieldtype": "Link", - "options": "Department", + fieldname: "department", + label: __("Department"), + fieldtype: "Link", + options: "Department", }, { - "fieldname": "employee", - "label": __("Employee"), - "fieldtype": "Link", - "options": "Employee", + fieldname: "employee", + label: __("Employee"), + fieldtype: "Link", + options: "Employee", }, { - "fieldname": "employee_status", - "label": __("Employee Status"), - "fieldtype": "Select", - "options": [ + fieldname: "employee_status", + label: __("Employee Status"), + fieldtype: "Select", + options: [ "", { "value": "Active", "label": __("Active") }, { "value": "Inactive", "label": __("Inactive") }, { "value": "Suspended", "label": __("Suspended") }, { "value": "Left", "label": __("Left") }, ], - "default": "Active", + default: "Active", + }, + { + fieldname: "consolidate_leave_types", + label: __("Consolidate Leave Types"), + fieldtype: "Check", + default: 1, + depends_on: "eval: !doc.employee", } ], diff --git a/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py b/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py index fccf722939e..192b255f3e0 100644 --- a/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py +++ b/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py @@ -7,7 +7,7 @@ from typing import Dict, List, Optional, Tuple import frappe from frappe import _ -from frappe.utils import add_days, getdate +from frappe.utils import add_days, cint, getdate from erpnext.hr.doctype.leave_allocation.leave_allocation import get_previous_allocation from erpnext.hr.doctype.leave_application.leave_application import ( @@ -24,7 +24,7 @@ def execute(filters: Optional[Filters] = None) -> Tuple: columns = get_columns() data = get_data(filters) - charts = get_chart_data(data) + charts = get_chart_data(data, filters) return columns, data, None, charts @@ -89,7 +89,7 @@ def get_data(filters: Filters) -> List: conditions = get_conditions(filters) user = frappe.session.user - department_approver_map = get_department_leave_approver_map(filters.get("department")) + department_approver_map = get_department_leave_approver_map(filters.department) active_employees = frappe.get_list( "Employee", @@ -97,22 +97,27 @@ def get_data(filters: Filters) -> List: fields=["name", "employee_name", "department", "user_id", "leave_approver"], ) + precision = cint(frappe.db.get_single_value("System Settings", "float_precision", cache=True)) + consolidate_leave_types = len(active_employees) > 1 and filters.consolidate_leave_types + row = None + data = [] for leave_type in leave_types: - if len(active_employees) > 1: + if consolidate_leave_types: data.append({"leave_type": leave_type}) else: row = frappe._dict({"leave_type": leave_type}) for employee in active_employees: - leave_approvers = department_approver_map.get(employee.department_name, []).append( employee.leave_approver ) - if len(active_employees) > 1: + if consolidate_leave_types: row = frappe._dict() + else: + row = frappe._dict({"leave_type": leave_type}) row.employee = employee.name row.employee_name = employee.employee_name @@ -166,17 +171,17 @@ def get_opening_balance( def get_conditions(filters: Filters) -> Dict: conditions = {} - if filters.get("employee"): - conditions["name"] = filters.get("employee") + if filters.employee: + conditions["name"] = filters.employee - if filters.get("company"): - conditions["company"] = filters.get("company") + if filters.company: + conditions["company"] = filters.company - if filters.get("department"): - conditions["department"] = filters.get("department") + if filters.department: + conditions["department"] = filters.department - if filters.get("employee_status"): - conditions["status"] = filters.get("employee_status") + if filters.employee_status: + conditions["status"] = filters.employee_status return conditions @@ -268,12 +273,15 @@ def get_leave_ledger_entries( return records -def get_chart_data(data: List) -> Dict: +def get_chart_data(data: List, filters: Filters) -> Dict: labels = [] datasets = [] employee_data = data - if data and data[0].get("employee_name"): + if not data: + return None + + if data and filters.employee: get_dataset_for_chart(employee_data, datasets, labels) chart = { diff --git a/erpnext/public/js/controllers/taxes_and_totals.js b/erpnext/public/js/controllers/taxes_and_totals.js index 92796073be7..be4eab03386 100644 --- a/erpnext/public/js/controllers/taxes_and_totals.js +++ b/erpnext/public/js/controllers/taxes_and_totals.js @@ -119,7 +119,16 @@ erpnext.taxes_and_totals = erpnext.payments.extend({ frappe.model.round_floats_in(item); item.net_rate = item.rate; item.qty = item.qty === undefined ? (me.frm.doc.is_return ? -1 : 1) : item.qty; - item.net_amount = item.amount = flt(item.rate * item.qty, precision("amount", item)); + + if (!(me.frm.doc.is_return || me.frm.doc.is_debit_note)) { + item.net_amount = item.amount = flt(item.rate * item.qty, precision("amount", item)); + } + else { + let qty = item.qty || 1; + qty = me.frm.doc.is_return ? -1 * qty : qty; + item.net_amount = item.amount = flt(item.rate * qty, precision("amount", item)); + } + item.item_tax_amount = 0.0; item.total_weight = flt(item.weight_per_unit * item.stock_qty); diff --git a/erpnext/selling/report/item_wise_sales_history/item_wise_sales_history.py b/erpnext/selling/report/item_wise_sales_history/item_wise_sales_history.py index aa9ccc06099..fcfd77c0182 100644 --- a/erpnext/selling/report/item_wise_sales_history/item_wise_sales_history.py +++ b/erpnext/selling/report/item_wise_sales_history/item_wise_sales_history.py @@ -216,7 +216,7 @@ def get_sales_order_details(company_list, filters): ) if filters.get("item_group"): - query = query.where(db_so_item.item_group == frappe.db.escape(filters.item_group)) + query = query.where(db_so_item.item_group == filters.item_group) if filters.get("from_date"): query = query.where(db_so.transaction_date >= filters.from_date) @@ -225,7 +225,7 @@ def get_sales_order_details(company_list, filters): query = query.where(db_so.transaction_date <= filters.to_date) if filters.get("item_code"): - query = query.where(db_so_item.item_group == frappe.db.escape(filters.item_code)) + query = query.where(db_so_item.item_code == filters.item_code) if filters.get("customer"): query = query.where(db_so.customer == filters.customer) diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.js b/erpnext/stock/doctype/delivery_note/delivery_note.js index cb4161f3f1d..120161e3f72 100644 --- a/erpnext/stock/doctype/delivery_note/delivery_note.js +++ b/erpnext/stock/doctype/delivery_note/delivery_note.js @@ -97,12 +97,12 @@ frappe.ui.form.on("Delivery Note", { } if (frm.doc.docstatus == 1 && !frm.doc.inter_company_reference) { - let internal = me.frm.doc.is_internal_customer; + let internal = frm.doc.is_internal_customer; if (internal) { - let button_label = (me.frm.doc.company === me.frm.doc.represents_company) ? "Internal Purchase Receipt" : + let button_label = (frm.doc.company === frm.doc.represents_company) ? "Internal Purchase Receipt" : "Inter Company Purchase Receipt"; - me.frm.add_custom_button(button_label, function() { + frm.add_custom_button(__(button_label), function() { frappe.model.open_mapped_doc({ method: 'erpnext.stock.doctype.delivery_note.delivery_note.make_inter_company_purchase_receipt', frm: frm, diff --git a/erpnext/stock/doctype/item_price/test_records.json b/erpnext/stock/doctype/item_price/test_records.json index 0a3d7e81985..afe5ad65b75 100644 --- a/erpnext/stock/doctype/item_price/test_records.json +++ b/erpnext/stock/doctype/item_price/test_records.json @@ -38,5 +38,19 @@ "price_list_rate": 1000, "valid_from": "2017-04-10", "valid_upto": "2017-04-17" + }, + { + "doctype": "Item Price", + "item_code": "_Test Item", + "price_list": "_Test Buying Price List", + "price_list_rate": 100, + "supplier": "_Test Supplier" + }, + { + "doctype": "Item Price", + "item_code": "_Test Item", + "price_list": "_Test Selling Price List", + "price_list_rate": 200, + "customer": "_Test Customer" } ] diff --git a/erpnext/stock/doctype/price_list/test_records.json b/erpnext/stock/doctype/price_list/test_records.json index 7ca949c4026..e02a7adbd8b 100644 --- a/erpnext/stock/doctype/price_list/test_records.json +++ b/erpnext/stock/doctype/price_list/test_records.json @@ -31,5 +31,21 @@ "enabled": 1, "price_list_name": "_Test Price List Rest of the World", "selling": 1 + }, + { + "buying": 0, + "currency": "USD", + "doctype": "Price List", + "enabled": 1, + "price_list_name": "_Test Selling Price List", + "selling": 1 + }, + { + "buying": 1, + "currency": "USD", + "doctype": "Price List", + "enabled": 1, + "price_list_name": "_Test Buying Price List", + "selling": 0 } ] diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py index 15d77544236..c6243a81dbf 100644 --- a/erpnext/stock/get_item_details.py +++ b/erpnext/stock/get_item_details.py @@ -88,8 +88,15 @@ def get_item_details(args, doc=None, for_validate=False, overwrite_warehouse=Tru update_party_blanket_order(args, out) + # Never try to find a customer price if customer is set in these Doctype + current_customer = args.customer + if args.get("doctype") in ["Purchase Order", "Purchase Receipt", "Purchase Invoice"]: + args.customer = None + out.update(get_price_list_rate(args, item)) + args.customer = current_customer + if args.customer and cint(args.is_pos): out.update(get_pos_profile_item_details(args.company, args, update_data=True)) diff --git a/erpnext/stock/stock_balance.py b/erpnext/stock/stock_balance.py index 9a7d8bbfe42..c505cae3813 100644 --- a/erpnext/stock/stock_balance.py +++ b/erpnext/stock/stock_balance.py @@ -122,7 +122,7 @@ def get_reserved_qty(item_code, warehouse): and parenttype="Sales Order" and item_code != parent_item and exists (select * from `tabSales Order` so - where name = dnpi_in.parent and docstatus = 1 and status != 'Closed') + where name = dnpi_in.parent and docstatus = 1 and status not in ('On Hold', 'Closed')) ) dnpi) union (select stock_qty as dnpi_qty, qty as so_item_qty, @@ -132,7 +132,7 @@ def get_reserved_qty(item_code, warehouse): and (so_item.delivered_by_supplier is null or so_item.delivered_by_supplier = 0) and exists(select * from `tabSales Order` so where so.name = so_item.parent and so.docstatus = 1 - and so.status != 'Closed')) + and so.status not in ('On Hold', 'Closed'))) ) tab where so_item_qty >= so_item_delivered_qty diff --git a/erpnext/stock/tests/test_get_item_details.py b/erpnext/stock/tests/test_get_item_details.py new file mode 100644 index 00000000000..b53e29e9e8e --- /dev/null +++ b/erpnext/stock/tests/test_get_item_details.py @@ -0,0 +1,40 @@ +import json + +import frappe +from frappe.test_runner import make_test_records +from frappe.tests.utils import FrappeTestCase + +from erpnext.stock.get_item_details import get_item_details + +test_ignore = ["BOM"] +test_dependencies = ["Customer", "Supplier", "Item", "Price List", "Item Price"] + + +class TestGetItemDetail(FrappeTestCase): + def setUp(self): + make_test_records("Price List") + super().setUp() + + def test_get_item_detail_purchase_order(self): + + args = frappe._dict( + { + "item_code": "_Test Item", + "company": "_Test Company", + "customer": "_Test Customer", + "conversion_rate": 1.0, + "price_list_currency": "USD", + "plc_conversion_rate": 1.0, + "doctype": "Purchase Order", + "name": None, + "supplier": "_Test Supplier", + "transaction_date": None, + "conversion_rate": 1.0, + "price_list": "_Test Buying Price List", + "is_subcontracted": 0, + "ignore_pricing_rule": 1, + "qty": 1, + } + ) + details = get_item_details(args) + self.assertEqual(details.get("price_list_rate"), 100) diff --git a/erpnext/www/shop-by-category/index.py b/erpnext/www/shop-by-category/index.py index 7b493c3c288..219747c9f8a 100644 --- a/erpnext/www/shop-by-category/index.py +++ b/erpnext/www/shop-by-category/index.py @@ -51,36 +51,31 @@ def get_tabs(categories): return tab_values -def get_category_records(categories): +def get_category_records(categories: list): categorical_data = {} - for category in categories: - if category == "item_group": - categorical_data["item_group"] = frappe.db.sql( - """ - Select - name, parent_item_group, is_group, image, route - from - `tabItem Group` - where - parent_item_group = 'All Item Groups' - and show_in_website = 1 - """, - as_dict=1, + + for c in categories: + if c == "item_group": + categorical_data["item_group"] = frappe.db.get_all( + "Item Group", + filters={"parent_item_group": "All Item Groups", "show_in_website": 1}, + fields=["name", "parent_item_group", "is_group", "image", "route"], ) - else: - doctype = frappe.unscrub(category) - fields = ["name"] - if frappe.get_meta(doctype, cached=True).get_field("image"): + + continue + + doctype = frappe.unscrub(c) + fields = ["name"] + + try: + meta = frappe.get_meta(doctype, cached=True) + if meta.get_field("image"): fields += ["image"] - categorical_data[category] = frappe.db.sql( - f""" - Select - {",".join(fields)} - from - `tab{doctype}` - """, - as_dict=1, - ) + data = frappe.db.get_all(doctype, fields=fields) + categorical_data[c] = data + except BaseException: + frappe.throw(_("DocType {} not found").format(doctype)) + continue return categorical_data