diff --git a/erpnext/accounts/doctype/accounting_dimension_filter/accounting_dimension_filter.js b/erpnext/accounts/doctype/accounting_dimension_filter/accounting_dimension_filter.js index 750e129ba78..8a6b021b8ad 100644 --- a/erpnext/accounts/doctype/accounting_dimension_filter/accounting_dimension_filter.js +++ b/erpnext/accounts/doctype/accounting_dimension_filter/accounting_dimension_filter.js @@ -3,10 +3,6 @@ frappe.ui.form.on('Accounting Dimension Filter', { refresh: function(frm, cdt, cdn) { - if (frm.doc.accounting_dimension) { - frm.set_df_property('dimensions', 'label', frm.doc.accounting_dimension, cdn, 'dimension_value'); - } - let help_content = `
|
@@ -68,6 +64,7 @@ frappe.ui.form.on('Accounting Dimension Filter', {
frm.clear_table("dimensions");
let row = frm.add_child("dimensions");
row.accounting_dimension = frm.doc.accounting_dimension;
+ frm.fields_dict["dimensions"].grid.update_docfield_property("dimension_value", "label", frm.doc.accounting_dimension);
frm.refresh_field("dimensions");
frm.trigger('setup_filters');
},
diff --git a/erpnext/accounts/doctype/bank_guarantee/bank_guarantee.js b/erpnext/accounts/doctype/bank_guarantee/bank_guarantee.js
index febf85ca6c1..99cc0a72fb3 100644
--- a/erpnext/accounts/doctype/bank_guarantee/bank_guarantee.js
+++ b/erpnext/accounts/doctype/bank_guarantee/bank_guarantee.js
@@ -43,20 +43,13 @@ frappe.ui.form.on('Bank Guarantee', {
reference_docname: function(frm) {
if (frm.doc.reference_docname && frm.doc.reference_doctype) {
- let fields_to_fetch = ["grand_total"];
let party_field = frm.doc.reference_doctype == "Sales Order" ? "customer" : "supplier";
- if (frm.doc.reference_doctype == "Sales Order") {
- fields_to_fetch.push("project");
- }
-
- fields_to_fetch.push(party_field);
frappe.call({
- method: "erpnext.accounts.doctype.bank_guarantee.bank_guarantee.get_vouchar_detials",
+ method: "erpnext.accounts.doctype.bank_guarantee.bank_guarantee.get_voucher_details",
args: {
- "column_list": fields_to_fetch,
- "doctype": frm.doc.reference_doctype,
- "docname": frm.doc.reference_docname
+ "bank_guarantee_type": frm.doc.bg_type,
+ "reference_name": frm.doc.reference_docname
},
callback: function(r) {
if (r.message) {
diff --git a/erpnext/accounts/doctype/bank_guarantee/bank_guarantee.py b/erpnext/accounts/doctype/bank_guarantee/bank_guarantee.py
index 9144a29c6ef..02eb599acc8 100644
--- a/erpnext/accounts/doctype/bank_guarantee/bank_guarantee.py
+++ b/erpnext/accounts/doctype/bank_guarantee/bank_guarantee.py
@@ -2,11 +2,8 @@
# For license information, please see license.txt
-import json
-
import frappe
from frappe import _
-from frappe.desk.search import sanitize_searchfield
from frappe.model.document import Document
@@ -25,14 +22,18 @@ class BankGuarantee(Document):
@frappe.whitelist()
-def get_vouchar_detials(column_list, doctype, docname):
- column_list = json.loads(column_list)
- for col in column_list:
- sanitize_searchfield(col)
- return frappe.db.sql(
- """ select {columns} from `tab{doctype}` where name=%s""".format(
- columns=", ".join(column_list), doctype=doctype
- ),
- docname,
- as_dict=1,
- )[0]
+def get_voucher_details(bank_guarantee_type: str, reference_name: str):
+ if not isinstance(reference_name, str):
+ raise TypeError("reference_name must be a string")
+
+ fields_to_fetch = ["grand_total"]
+
+ if bank_guarantee_type == "Receiving":
+ doctype = "Sales Order"
+ fields_to_fetch.append("customer")
+ fields_to_fetch.append("project")
+ else:
+ doctype = "Purchase Order"
+ fields_to_fetch.append("supplier")
+
+ return frappe.db.get_value(doctype, reference_name, fields_to_fetch, as_dict=True)
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py
index 904d7af757f..70a5f9e526c 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.py
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py
@@ -67,7 +67,6 @@ class PaymentEntry(AccountsController):
self.set_missing_values()
self.validate_payment_type()
self.validate_party_details()
- self.validate_bank_accounts()
self.set_exchange_rate()
self.validate_mandatory()
self.validate_reference_documents()
@@ -250,23 +249,6 @@ class PaymentEntry(AccountsController):
if not frappe.db.exists(self.party_type, self.party):
frappe.throw(_("Invalid {0}: {1}").format(self.party_type, self.party))
- if self.party_account and self.party_type in ("Customer", "Supplier"):
- self.validate_account_type(
- self.party_account, [erpnext.get_party_account_type(self.party_type)]
- )
-
- def validate_bank_accounts(self):
- if self.payment_type in ("Pay", "Internal Transfer"):
- self.validate_account_type(self.paid_from, ["Bank", "Cash"])
-
- if self.payment_type in ("Receive", "Internal Transfer"):
- self.validate_account_type(self.paid_to, ["Bank", "Cash"])
-
- def validate_account_type(self, account, account_types):
- account_type = frappe.db.get_value("Account", account, "account_type")
- # if account_type not in account_types:
- # frappe.throw(_("Account Type for {0} must be {1}").format(account, comma_or(account_types)))
-
def set_exchange_rate(self, ref_doc=None):
self.set_source_exchange_rate(ref_doc)
self.set_target_exchange_rate(ref_doc)
diff --git a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py
index f7b8a77efa9..ee12fce7a94 100644
--- a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py
+++ b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py
@@ -47,6 +47,10 @@ class PaymentReconciliation(Document):
def get_payment_entries(self):
order_doctype = "Sales Order" if self.party_type == "Customer" else "Purchase Order"
condition = self.get_conditions(get_payments=True)
+
+ if self.get("cost_center"):
+ condition += " and cost_center = '{0}' ".format(self.cost_center)
+
payment_entries = get_advance_payment_entries(
self.party_type,
self.party,
@@ -61,6 +65,10 @@ class PaymentReconciliation(Document):
def get_jv_entries(self):
condition = self.get_conditions()
+
+ if self.get("cost_center"):
+ condition += " and t2.cost_center = '{0}' ".format(self.cost_center)
+
dr_or_cr = (
"credit_in_account_currency"
if erpnext.get_party_account_type(self.party_type) == "Receivable"
@@ -113,6 +121,10 @@ class PaymentReconciliation(Document):
def get_dr_or_cr_notes(self):
condition = self.get_conditions(get_return_invoices=True)
+
+ if self.get("cost_center"):
+ condition += " and doc.cost_center = '{0}' ".format(self.cost_center)
+
dr_or_cr = (
"credit_in_account_currency"
if erpnext.get_party_account_type(self.party_type) == "Receivable"
@@ -172,6 +184,9 @@ class PaymentReconciliation(Document):
condition = self.get_conditions(get_invoices=True)
+ if self.get("cost_center"):
+ condition += " and cost_center = '{0}' ".format(self.cost_center)
+
non_reconciled_invoices = get_outstanding_invoices(
self.party_type, self.party, self.receivable_payable_account, condition=condition
)
@@ -357,9 +372,6 @@ class PaymentReconciliation(Document):
def get_conditions(self, get_invoices=False, get_payments=False, get_return_invoices=False):
condition = " and company = '{0}' ".format(self.company)
- if self.get("cost_center"):
- condition = " and cost_center = '{0}' ".format(self.cost_center)
-
if get_invoices:
condition += (
" and posting_date >= {0}".format(frappe.db.escape(self.from_invoice_date))
diff --git a/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py b/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py
index c5dac722bad..4b4bfb18188 100644
--- a/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py
+++ b/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py
@@ -712,6 +712,140 @@ class TestPricingRule(unittest.TestCase):
item.delete()
+ def test_item_group_price_with_blank_uom_pricing_rule(self):
+ group = frappe.get_doc(
+ doctype="Item Group",
+ item_group_name="_Test Pricing Rule Item Group",
+ parent_item_group="All Item Groups",
+ )
+ group.save()
+ properties = {
+ "item_code": "Item with Group Blank UOM",
+ "item_group": "_Test Pricing Rule Item Group",
+ "stock_uom": "Nos",
+ "sales_uom": "Box",
+ "uoms": [dict(uom="Box", conversion_factor=10)],
+ }
+ item = make_item(properties=properties)
+
+ make_item_price("Item with Group Blank UOM", "_Test Price List", 100)
+
+ pricing_rule_record = {
+ "doctype": "Pricing Rule",
+ "title": "_Test Item with Group Blank UOM Rule",
+ "apply_on": "Item Group",
+ "item_groups": [
+ {
+ "item_group": "_Test Pricing Rule Item Group",
+ }
+ ],
+ "selling": 1,
+ "currency": "INR",
+ "rate_or_discount": "Rate",
+ "rate": 101,
+ "company": "_Test Company",
+ }
+ rule = frappe.get_doc(pricing_rule_record)
+ rule.insert()
+
+ si = create_sales_invoice(
+ do_not_save=True, item_code="Item with Group Blank UOM", uom="Box", conversion_factor=10
+ )
+ si.selling_price_list = "_Test Price List"
+ si.save()
+
+ # If UOM is blank consider it as stock UOM and apply pricing_rule on all UOM.
+ # rate is 101, Selling UOM is Box that have conversion_factor of 10 so 101 * 10 = 1010
+ self.assertEqual(si.items[0].price_list_rate, 1010)
+ self.assertEqual(si.items[0].rate, 1010)
+
+ si.delete()
+
+ si = create_sales_invoice(do_not_save=True, item_code="Item with Group Blank UOM", uom="Nos")
+ si.selling_price_list = "_Test Price List"
+ si.save()
+
+ # UOM is blank so consider it as stock UOM and apply pricing_rule on all UOM.
+ # rate is 101, Selling UOM is Nos that have conversion_factor of 1 so 101 * 1 = 101
+ self.assertEqual(si.items[0].price_list_rate, 101)
+ self.assertEqual(si.items[0].rate, 101)
+
+ si.delete()
+ rule.delete()
+ frappe.get_doc("Item Price", {"item_code": "Item with Group Blank UOM"}).delete()
+ item.delete()
+ group.delete()
+
+ def test_item_group_price_with_selling_uom_pricing_rule(self):
+ group = frappe.get_doc(
+ doctype="Item Group",
+ item_group_name="_Test Pricing Rule Item Group UOM",
+ parent_item_group="All Item Groups",
+ )
+ group.save()
+ properties = {
+ "item_code": "Item with Group UOM other than Stock",
+ "item_group": "_Test Pricing Rule Item Group UOM",
+ "stock_uom": "Nos",
+ "sales_uom": "Box",
+ "uoms": [dict(uom="Box", conversion_factor=10)],
+ }
+ item = make_item(properties=properties)
+
+ make_item_price("Item with Group UOM other than Stock", "_Test Price List", 100)
+
+ pricing_rule_record = {
+ "doctype": "Pricing Rule",
+ "title": "_Test Item with Group UOM other than Stock Rule",
+ "apply_on": "Item Group",
+ "item_groups": [
+ {
+ "item_group": "_Test Pricing Rule Item Group UOM",
+ "uom": "Box",
+ }
+ ],
+ "selling": 1,
+ "currency": "INR",
+ "rate_or_discount": "Rate",
+ "rate": 101,
+ "company": "_Test Company",
+ }
+ rule = frappe.get_doc(pricing_rule_record)
+ rule.insert()
+
+ si = create_sales_invoice(
+ do_not_save=True,
+ item_code="Item with Group UOM other than Stock",
+ uom="Box",
+ conversion_factor=10,
+ )
+ si.selling_price_list = "_Test Price List"
+ si.save()
+
+ # UOM is Box so apply pricing_rule only on Box UOM.
+ # Selling UOM is Box and as both UOM are same no need to multiply by conversion_factor.
+ self.assertEqual(si.items[0].price_list_rate, 101)
+ self.assertEqual(si.items[0].rate, 101)
+
+ si.delete()
+
+ si = create_sales_invoice(
+ do_not_save=True, item_code="Item with Group UOM other than Stock", uom="Nos"
+ )
+ si.selling_price_list = "_Test Price List"
+ si.save()
+
+ # UOM is Box so pricing_rule won't apply as selling_uom is Nos.
+ # As Pricing Rule is not applied price of 100 will be fetched from Item Price List.
+ self.assertEqual(si.items[0].price_list_rate, 100)
+ self.assertEqual(si.items[0].rate, 100)
+
+ si.delete()
+ rule.delete()
+ frappe.get_doc("Item Price", {"item_code": "Item with Group UOM other than Stock"}).delete()
+ item.delete()
+ group.delete()
+
def test_pricing_rule_for_different_currency(self):
make_item("Test Sanitizer Item")
diff --git a/erpnext/accounts/doctype/pricing_rule/utils.py b/erpnext/accounts/doctype/pricing_rule/utils.py
index 25f5492d0d1..984a8bae008 100644
--- a/erpnext/accounts/doctype/pricing_rule/utils.py
+++ b/erpnext/accounts/doctype/pricing_rule/utils.py
@@ -127,7 +127,12 @@ def _get_pricing_rules(apply_on, args, values):
values["variant_of"] = args.variant_of
elif apply_on_field == "item_group":
item_conditions = _get_tree_conditions(args, "Item Group", child_doc, False)
-
+ if args.get("uom", None):
+ item_conditions += (
+ " and ({child_doc}.uom='{item_uom}' or IFNULL({child_doc}.uom, '')='')".format(
+ child_doc=child_doc, item_uom=args.get("uom")
+ )
+ )
conditions += get_other_conditions(conditions, values, args)
warehouse_conditions = _get_tree_conditions(args, "Warehouse", "`tabPricing Rule`")
if warehouse_conditions:
diff --git a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.js b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.js
index 29f2e98e779..7dd5ef36f29 100644
--- a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.js
+++ b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.js
@@ -8,7 +8,8 @@ frappe.ui.form.on('Process Statement Of Accounts', {
},
refresh: function(frm){
if(!frm.doc.__islocal) {
- frm.add_custom_button('Send Emails',function(){
+ frm.add_custom_button(__('Send Emails'), function(){
+ if (frm.is_dirty()) frappe.throw(__("Please save before proceeding."))
frappe.call({
method: "erpnext.accounts.doctype.process_statement_of_accounts.process_statement_of_accounts.send_emails",
args: {
@@ -24,8 +25,9 @@ frappe.ui.form.on('Process Statement Of Accounts', {
}
});
});
- frm.add_custom_button('Download',function(){
- var url = frappe.urllib.get_full_url(
+ frm.add_custom_button(__('Download'), function(){
+ if (frm.is_dirty()) frappe.throw(__("Please save before proceeding."))
+ let url = frappe.urllib.get_full_url(
'/api/method/erpnext.accounts.doctype.process_statement_of_accounts.process_statement_of_accounts.download_statements?'
+ 'document_name='+encodeURIComponent(frm.doc.name))
$.ajax({
diff --git a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.json b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.json
index a35374c6242..2f62a0295fb 100644
--- a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.json
+++ b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.json
@@ -27,6 +27,7 @@
"customers",
"preferences",
"orientation",
+ "include_break",
"include_ageing",
"ageing_based_on",
"section_break_14",
@@ -284,10 +285,16 @@
"fieldtype": "Link",
"label": "Terms and Conditions",
"options": "Terms and Conditions"
+ },
+ {
+ "default": "1",
+ "fieldname": "include_break",
+ "fieldtype": "Check",
+ "label": "Page Break After Each SoA"
}
],
"links": [],
- "modified": "2021-09-06 21:00:45.732505",
+ "modified": "2022-10-17 17:47:08.662475",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Process Statement Of Accounts",
@@ -320,5 +327,6 @@
],
"sort_field": "modified",
"sort_order": "DESC",
+ "states": [],
"track_changes": 1
}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py
index 01f716daa21..c6b0c57ce5c 100644
--- a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py
+++ b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py
@@ -6,6 +6,7 @@ import copy
import frappe
from frappe import _
+from frappe.desk.reportview import get_match_cond
from frappe.model.document import Document
from frappe.utils import add_days, add_months, format_date, getdate, today
from frappe.utils.jinja import validate_template
@@ -128,7 +129,8 @@ def get_report_pdf(doc, consolidated=True):
if not bool(statement_dict):
return False
elif consolidated:
- result = "".join(list(statement_dict.values()))
+ delimiter = '' if doc.include_break else ""
+ result = delimiter.join(list(statement_dict.values()))
return get_pdf(result, {"orientation": doc.orientation})
else:
for customer, statement_html in statement_dict.items():
@@ -240,8 +242,6 @@ def fetch_customers(customer_collection, collection_name, primary_mandatory):
if int(primary_mandatory):
if primary_email == "":
continue
- elif (billing_email == "") and (primary_email == ""):
- continue
customer_list.append(
{"name": customer.name, "primary_email": primary_email, "billing_email": billing_email}
@@ -273,8 +273,12 @@ def get_customer_emails(customer_name, primary_mandatory, billing_and_primary=Tr
link.link_doctype='Customer'
and link.link_name=%s
and contact.is_billing_contact=1
+ {mcond}
ORDER BY
- contact.creation desc""",
+ contact.creation desc
+ """.format(
+ mcond=get_match_cond("Contact")
+ ),
customer_name,
)
@@ -313,6 +317,8 @@ def send_emails(document_name, from_scheduler=False):
attachments = [{"fname": customer + ".pdf", "fcontent": report_pdf}]
recipients, cc = get_recipients_and_cc(customer, doc)
+ if not recipients:
+ continue
context = get_context(customer, doc)
subject = frappe.render_template(doc.subject, context)
message = frappe.render_template(doc.body, context)
diff --git a/erpnext/accounts/print_format/gst_e_invoice/gst_e_invoice.html b/erpnext/accounts/print_format/gst_e_invoice/gst_e_invoice.html
index 605ce8383e4..e1b2def2dae 100644
--- a/erpnext/accounts/print_format/gst_e_invoice/gst_e_invoice.html
+++ b/erpnext/accounts/print_format/gst_e_invoice/gst_e_invoice.html
@@ -50,6 +50,10 @@
{{ einvoice.DocDtls.No }}
+
+
+
{{ einvoice.DocDtls.Dt }}
+ |