diff --git a/.github/workflows/patch.yml b/.github/workflows/patch.yml index d6a03af535f5..c39b4be9acba 100644 --- a/.github/workflows/patch.yml +++ b/.github/workflows/patch.yml @@ -16,7 +16,7 @@ concurrency: jobs: test: - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 timeout-minutes: 60 name: Patch Test diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.js b/erpnext/accounts/doctype/payment_entry/payment_entry.js index 5da1c0d35d96..f4819aaea594 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.js +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.js @@ -1088,6 +1088,24 @@ frappe.ui.form.on('Payment Entry', { if (r.message) { if (!frm.doc.mode_of_payment) { frm.set_value(field, r.message.account); + } else { + frappe.call({ + method: "frappe.client.get_value", + args: { + doctype: "Mode of Payment Account", + filters: { + parent: frm.doc.mode_of_payment, + company: frm.doc.company, + }, + fieldname: "default_account", + parent: "Mode of Payment", + }, + callback: function (res) { + if (!res.message.default_account) { + frm.set_value(field, r.message.account); + } + }, + }); } frm.set_value('bank', r.message.bank); frm.set_value('bank_account_no', r.message.bank_account_no); diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py index 902af5c2a772..2f8332377630 100644 --- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py +++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py @@ -328,6 +328,8 @@ def get_pricing_rule_for_item(args, doc=None, for_validate=False): "parent": args.parent, "parenttype": args.parenttype, "child_docname": args.get("child_docname"), + "discount_percentage": 0.0, + "discount_amount": 0, } ) diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py index 7868b06fe331..f488b1a5832f 100644 --- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py +++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py @@ -529,9 +529,7 @@ def get_payment_terms(self, row): self.append_payment_term(row, d, term) def append_payment_term(self, row, d, term): - if ( - self.filters.get("customer") or self.filters.get("supplier") - ) and d.currency == d.party_account_currency: + if d.currency == d.party_account_currency: invoiced = d.payment_amount else: invoiced = d.base_payment_amount diff --git a/erpnext/accounts/report/financial_statements.py b/erpnext/accounts/report/financial_statements.py index 16886cd939a4..cd0f7e90e04e 100644 --- a/erpnext/accounts/report/financial_statements.py +++ b/erpnext/accounts/report/financial_statements.py @@ -526,9 +526,16 @@ def get_accounting_entries( query = apply_additional_conditions(doctype, query, from_date, ignore_closing_entries, filters) query = query.where(gl_entry.account.isin(accounts)) - entries = query.run(as_dict=True) + from frappe.desk.reportview import build_match_conditions - return entries + match_conditions = build_match_conditions(doctype) + + if match_conditions: + query += "and" + match_conditions + + query, params = query.walk() + + return frappe.db.sql(query, params, as_dict=True) def apply_additional_conditions(doctype, query, from_date, ignore_closing_entries, filters): diff --git a/erpnext/accounts/report/gross_profit/gross_profit.py b/erpnext/accounts/report/gross_profit/gross_profit.py index 833bb78a329f..15617a53cdff 100644 --- a/erpnext/accounts/report/gross_profit/gross_profit.py +++ b/erpnext/accounts/report/gross_profit/gross_profit.py @@ -768,7 +768,10 @@ def load_invoice_items(self): """ if self.filters.group_by == "Sales Person": - sales_person_cols = ", sales.sales_person, sales.allocated_amount, sales.incentives" + sales_person_cols = """, sales.sales_person, + sales.allocated_percentage * `tabSales Invoice Item`.base_net_amount / 100 as allocated_amount, + sales.incentives + """ sales_team_table = "left join `tabSales Team` sales on sales.parent = `tabSales Invoice`.name" else: sales_person_cols = "" diff --git a/erpnext/accounts/report/tds_payable_monthly/tds_payable_monthly.py b/erpnext/accounts/report/tds_payable_monthly/tds_payable_monthly.py index 465c300a8efe..03a5259b96f4 100644 --- a/erpnext/accounts/report/tds_payable_monthly/tds_payable_monthly.py +++ b/erpnext/accounts/report/tds_payable_monthly/tds_payable_monthly.py @@ -72,8 +72,8 @@ def get_result(filters, tds_docs, tds_accounts, tax_category_map, journal_entry_ if net_total_map.get((voucher_type, name)): if voucher_type == "Journal Entry" and tax_amount and rate: # back calcalute total amount from rate and tax_amount - if rate: - total_amount = grand_total = base_total = tax_amount / (rate / 100) + base_total = min(tax_amount / (rate / 100), net_total_map.get((voucher_type, name))[0]) + total_amount = grand_total = base_total elif voucher_type == "Purchase Invoice": total_amount, grand_total, base_total, bill_no, bill_date = net_total_map.get( (voucher_type, name) @@ -405,7 +405,7 @@ def get_doc_info(vouchers, doctype, tax_category_map, net_total_map=None): "paid_amount_after_tax", "base_paid_amount", ], - "Journal Entry": ["total_amount"], + "Journal Entry": ["total_debit"], } entries = frappe.get_all( @@ -427,7 +427,7 @@ def get_doc_info(vouchers, doctype, tax_category_map, net_total_map=None): elif doctype == "Payment Entry": value = [entry.paid_amount, entry.paid_amount_after_tax, entry.base_paid_amount] else: - value = [entry.total_amount] * 3 + value = [entry.total_debit] * 3 net_total_map[(doctype, entry.name)] = value diff --git a/erpnext/controllers/sales_and_purchase_return.py b/erpnext/controllers/sales_and_purchase_return.py index c26644c870b5..f661cc33c63b 100644 --- a/erpnext/controllers/sales_and_purchase_return.py +++ b/erpnext/controllers/sales_and_purchase_return.py @@ -71,16 +71,13 @@ def validate_returned_items(doc): valid_items = frappe._dict() - select_fields = "item_code, qty, stock_qty, rate, parenttype, conversion_factor" + select_fields = "item_code, qty, stock_qty, rate, parenttype, conversion_factor, name" if doc.doctype != "Purchase Invoice": select_fields += ",serial_no, batch_no" if doc.doctype in ["Purchase Invoice", "Purchase Receipt", "Subcontracting Receipt"]: select_fields += ",rejected_qty, received_qty" - if doc.doctype in ["Purchase Receipt", "Purchase Invoice"]: - select_fields += ",name" - for d in frappe.db.sql( f"""select {select_fields} from `tab{doc.doctype} Item` where parent = %s""", doc.return_against, @@ -108,11 +105,13 @@ def validate_returned_items(doc): for d in doc.get("items"): key = d.item_code raise_exception = False - if doc.doctype in ["Purchase Receipt", "Purchase Invoice"]: + if doc.doctype in ["Purchase Receipt", "Purchase Invoice", "Sales Invoice"]: field = frappe.scrub(doc.doctype) + "_item" if d.get(field): key = (d.item_code, d.get(field)) raise_exception = True + elif doc.doctype == "Delivery Note": + key = (d.item_code, d.get("dn_detail")) if d.item_code and (flt(d.qty) < 0 or flt(d.get("received_qty")) < 0): if key not in valid_items: @@ -124,7 +123,7 @@ def validate_returned_items(doc): ) else: ref = valid_items.get(key, frappe._dict()) - validate_quantity(doc, d, ref, valid_items, already_returned_items) + validate_quantity(doc, key, d, ref, valid_items, already_returned_items) if ( ref.rate @@ -174,12 +173,12 @@ def validate_returned_items(doc): frappe.throw(_("Atleast one item should be entered with negative quantity in return document")) -def validate_quantity(doc, args, ref, valid_items, already_returned_items): +def validate_quantity(doc, key, args, ref, valid_items, already_returned_items): fields = ["stock_qty"] if doc.doctype in ["Purchase Receipt", "Purchase Invoice", "Subcontracting Receipt"]: fields.extend(["received_qty", "rejected_qty"]) - already_returned_data = already_returned_items.get(args.item_code) or {} + already_returned_data = already_returned_items.get(key) or {} company_currency = erpnext.get_company_currency(doc.company) stock_qty_precision = get_field_precision( @@ -262,15 +261,20 @@ def get_already_returned_items(doc): column += """, sum(abs(child.rejected_qty) * child.conversion_factor) as rejected_qty, sum(abs(child.received_qty) * child.conversion_factor) as received_qty""" + field = ( + frappe.scrub(doc.doctype) + "_item" + if doc.doctype in ["Purchase Invoice", "Purchase Receipt", "Sales Invoice"] + else "dn_detail" + ) data = frappe.db.sql( f""" - select {column} + select {column}, {field} from `tab{doc.doctype} Item` child, `tab{doc.doctype}` par where child.parent = par.name and par.docstatus = 1 and par.is_return = 1 and par.return_against = %s - group by item_code + group by item_code, {field} """, doc.return_against, as_dict=1, @@ -280,7 +284,7 @@ def get_already_returned_items(doc): for d in data: items.setdefault( - d.item_code, + (d.item_code, d.get(field)), frappe._dict( { "qty": d.get("qty"), diff --git a/erpnext/controllers/status_updater.py b/erpnext/controllers/status_updater.py index e04618c857fa..db3bb16bc02e 100644 --- a/erpnext/controllers/status_updater.py +++ b/erpnext/controllers/status_updater.py @@ -94,7 +94,10 @@ def validate_status(status, options): ["To Bill", "eval:self.per_billed == 0 and self.docstatus == 1"], ["Partly Billed", "eval:self.per_billed > 0 and self.per_billed < 100 and self.docstatus == 1"], ["Return Issued", "eval:self.per_returned == 100 and self.docstatus == 1"], - ["Completed", "eval:self.per_billed == 100 and self.docstatus == 1"], + [ + "Completed", + "eval:(self.per_billed == 100 and self.docstatus == 1) or (self.docstatus == 1 and self.grand_total == 0 and self.per_returned != 100 and self.is_return == 0)", + ], ["Cancelled", "eval:self.docstatus==2"], ["Closed", "eval:self.status=='Closed' and self.docstatus != 2"], ], diff --git a/erpnext/public/js/queries.js b/erpnext/public/js/queries.js index f014e6303ff2..14d07230d0da 100644 --- a/erpnext/public/js/queries.js +++ b/erpnext/public/js/queries.js @@ -107,9 +107,12 @@ $.extend(erpnext.queries, { }, dispatch_address_query: function (doc) { + var filters = { link_doctype: "Company", link_name: doc.company || "" }; + var is_drop_ship = doc.items.some((item) => item.delivered_by_supplier); + if (is_drop_ship) filters = {}; return { query: "frappe.contacts.doctype.address.address.address_query", - filters: { link_doctype: "Company", link_name: doc.company || "" }, + filters: filters, }; }, diff --git a/erpnext/stock/doctype/pick_list/pick_list.py b/erpnext/stock/doctype/pick_list/pick_list.py index 948437a82879..2176d75ee97f 100644 --- a/erpnext/stock/doctype/pick_list/pick_list.py +++ b/erpnext/stock/doctype/pick_list/pick_list.py @@ -982,6 +982,7 @@ def create_stock_entry(pick_list): stock_entry = frappe.new_doc("Stock Entry") stock_entry.pick_list = pick_list.get("name") stock_entry.purpose = pick_list.get("purpose") + stock_entry.company = pick_list.get("company") stock_entry.set_stock_entry_type() if pick_list.get("work_order"):