diff --git a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py
index ac033f7db6..13712cee01 100644
--- a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py
+++ b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py
@@ -471,6 +471,7 @@ class PaymentReconciliation(Document):
def build_qb_filter_conditions(self, get_invoices=False, get_return_invoices=False):
self.common_filter_conditions.clear()
+ self.accounting_dimension_filter_conditions.clear()
self.ple_posting_date_filter.clear()
ple = qb.DocType("Payment Ledger Entry")
diff --git a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.html b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.html
index 0da44a464e..3920d4cf09 100644
--- a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.html
+++ b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.html
@@ -49,7 +49,6 @@
{% endif %}
- {{ _("Against") }}: {{ row.against }}
{{ _("Remarks") }}: {{ row.remarks }}
{% if row.bill_no %}
{{ _("Supplier Invoice No") }}: {{ row.bill_no }}
diff --git a/erpnext/accounts/doctype/repost_payment_ledger/repost_payment_ledger.py b/erpnext/accounts/doctype/repost_payment_ledger/repost_payment_ledger.py
index 9f6828fb73..209cad4f90 100644
--- a/erpnext/accounts/doctype/repost_payment_ledger/repost_payment_ledger.py
+++ b/erpnext/accounts/doctype/repost_payment_ledger/repost_payment_ledger.py
@@ -7,7 +7,6 @@ import frappe
from frappe import _, qb
from frappe.model.document import Document
from frappe.query_builder.custom import ConstantColumn
-from frappe.utils.background_jobs import is_job_queued
from erpnext.accounts.utils import _delete_pl_entries, create_payment_ledger_entry
@@ -27,7 +26,7 @@ def start_payment_ledger_repost(docname=None):
"""
if docname:
repost_doc = frappe.get_doc("Repost Payment Ledger", docname)
- if repost_doc.docstatus == 1 and repost_doc.repost_status in ["Queued", "Failed"]:
+ if repost_doc.docstatus.is_submitted() and repost_doc.repost_status in ["Queued", "Failed"]:
try:
for entry in repost_doc.repost_vouchers:
doc = frappe.get_doc(entry.voucher_type, entry.voucher_no)
@@ -102,10 +101,9 @@ def execute_repost_payment_ledger(docname):
job_name = "payment_ledger_repost_" + docname
- if not is_job_queued(job_name):
- frappe.enqueue(
- method="erpnext.accounts.doctype.repost_payment_ledger.repost_payment_ledger.start_payment_ledger_repost",
- docname=docname,
- is_async=True,
- job_name=job_name,
- )
+ frappe.enqueue(
+ method="erpnext.accounts.doctype.repost_payment_ledger.repost_payment_ledger.start_payment_ledger_repost",
+ docname=docname,
+ is_async=True,
+ job_name=job_name,
+ )
diff --git a/erpnext/accounts/report/general_ledger/general_ledger.html b/erpnext/accounts/report/general_ledger/general_ledger.html
index c04f518d7e..475be92add 100644
--- a/erpnext/accounts/report/general_ledger/general_ledger.html
+++ b/erpnext/accounts/report/general_ledger/general_ledger.html
@@ -25,8 +25,8 @@
{%= __("Date") %} |
- {%= __("Ref") %} |
- {%= __("Party") %} |
+ {%= __("Reference") %} |
+ {%= __("Remarks") %} |
{%= __("Debit") %} |
{%= __("Credit") %} |
{%= __("Balance (Dr - Cr)") %} |
@@ -45,7 +45,6 @@
{% } %}
- {{ __("Against") }}: {%= data[i].against %}
{%= __("Remarks") %}: {%= data[i].remarks %}
{% if(data[i].bill_no) { %}
{%= __("Supplier Invoice No") %}: {%= data[i].bill_no %}
diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py
index 445dcc53c6..a03de9e194 100644
--- a/erpnext/accounts/utils.py
+++ b/erpnext/accounts/utils.py
@@ -439,8 +439,7 @@ def reconcile_against_document(args): # nosemgrep
# cancel advance entry
doc = frappe.get_doc(voucher_type, voucher_no)
frappe.flags.ignore_party_validation = True
- gl_map = doc.build_gl_map()
- create_payment_ledger_entry(gl_map, cancel=1, adv_adj=1)
+ _delete_pl_entries(voucher_type, voucher_no)
for entry in entries:
check_if_advance_entry_modified(entry)
@@ -452,11 +451,23 @@ def reconcile_against_document(args): # nosemgrep
else:
update_reference_in_payment_entry(entry, doc, do_not_save=True)
+ if doc.doctype == "Journal Entry":
+ try:
+ doc.validate_total_debit_and_credit()
+ except Exception as validation_exception:
+ raise frappe.ValidationError(_(f"Validation Error for {doc.name}")) from validation_exception
+
doc.save(ignore_permissions=True)
# re-submit advance entry
doc = frappe.get_doc(entry.voucher_type, entry.voucher_no)
gl_map = doc.build_gl_map()
- create_payment_ledger_entry(gl_map, cancel=0, adv_adj=1)
+ create_payment_ledger_entry(gl_map, update_outstanding="No", cancel=0, adv_adj=1)
+
+ # Only update outstanding for newly linked vouchers
+ for entry in entries:
+ update_voucher_outstanding(
+ entry.against_voucher_type, entry.against_voucher, entry.account, entry.party_type, entry.party
+ )
frappe.flags.ignore_party_validation = False
diff --git a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py
index 7d3b645be7..62a3483629 100644
--- a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py
+++ b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py
@@ -8,7 +8,6 @@ import frappe
# import erpnext
from frappe import _
from frappe.utils import cint, flt, get_link_to_form
-from six import string_types
import erpnext
from erpnext.assets.doctype.asset.depreciation import (
@@ -626,7 +625,7 @@ def get_target_asset_details(asset=None, company=None):
@frappe.whitelist()
def get_consumed_stock_item_details(args):
- if isinstance(args, string_types):
+ if isinstance(args, str):
args = json.loads(args)
args = frappe._dict(args)
@@ -678,7 +677,7 @@ def get_consumed_stock_item_details(args):
@frappe.whitelist()
def get_warehouse_details(args):
- if isinstance(args, string_types):
+ if isinstance(args, str):
args = json.loads(args)
args = frappe._dict(args)
@@ -694,7 +693,7 @@ def get_warehouse_details(args):
@frappe.whitelist()
def get_consumed_asset_details(args):
- if isinstance(args, string_types):
+ if isinstance(args, str):
args = json.loads(args)
args = frappe._dict(args)
@@ -746,7 +745,7 @@ def get_consumed_asset_details(args):
@frappe.whitelist()
def get_service_item_details(args):
- if isinstance(args, string_types):
+ if isinstance(args, str):
args = json.loads(args)
args = frappe._dict(args)
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index 788dc4982e..6fa44c93c2 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -394,7 +394,7 @@ class AccountsController(TransactionBase):
self.get("inter_company_reference")
or self.get("inter_company_invoice_reference")
or self.get("inter_company_order_reference")
- ):
+ ) and not self.get("is_return"):
msg = _("Internal Sale or Delivery Reference missing.")
msg += _("Please create purchase from internal sale or delivery document itself")
frappe.throw(msg, title=_("Internal Sales Reference Missing"))
diff --git a/erpnext/controllers/sales_and_purchase_return.py b/erpnext/controllers/sales_and_purchase_return.py
index 15c82af856..8bd09982bf 100644
--- a/erpnext/controllers/sales_and_purchase_return.py
+++ b/erpnext/controllers/sales_and_purchase_return.py
@@ -37,7 +37,7 @@ def validate_return_against(doc):
if (
ref_doc.company == doc.company
and ref_doc.get(party_type) == doc.get(party_type)
- and ref_doc.docstatus == 1
+ and ref_doc.docstatus.is_submitted()
):
# validate posting date time
return_posting_datetime = "%s %s" % (doc.posting_date, doc.get("posting_time") or "00:00:00")
diff --git a/erpnext/controllers/taxes_and_totals.py b/erpnext/controllers/taxes_and_totals.py
index c6a634ba80..8c403aa9bf 100644
--- a/erpnext/controllers/taxes_and_totals.py
+++ b/erpnext/controllers/taxes_and_totals.py
@@ -6,6 +6,7 @@ import json
import frappe
from frappe import _, scrub
+from frappe.model.document import Document
from frappe.utils import cint, flt, round_based_on_smallest_currency_fraction
import erpnext
@@ -20,7 +21,7 @@ from erpnext.stock.get_item_details import _get_item_tax_template
class calculate_taxes_and_totals(object):
- def __init__(self, doc):
+ def __init__(self, doc: Document):
self.doc = doc
frappe.flags.round_off_applicable_accounts = []
get_round_off_applicable_accounts(self.doc.company, frappe.flags.round_off_applicable_accounts)
@@ -677,7 +678,7 @@ class calculate_taxes_and_totals(object):
)
def calculate_total_advance(self):
- if self.doc.docstatus < 2:
+ if not self.doc.docstatus.is_cancelled():
total_allocated_amount = sum(
flt(adv.allocated_amount, adv.precision("allocated_amount"))
for adv in self.doc.get("advances")
@@ -708,7 +709,7 @@ class calculate_taxes_and_totals(object):
)
)
- if self.doc.docstatus == 0:
+ if self.doc.docstatus.is_draft():
if self.doc.get("write_off_outstanding_amount_automatically"):
self.doc.write_off_amount = 0
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 7495ab8d0b..cba1ecc2cf 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -269,6 +269,7 @@ erpnext.patches.v13_0.reset_corrupt_defaults
erpnext.patches.v13_0.create_accounting_dimensions_for_asset_repair
erpnext.patches.v15_0.delete_taxjar_doctypes
erpnext.patches.v15_0.create_asset_depreciation_schedules_from_assets
+erpnext.patches.v14_0.update_reference_due_date_in_journal_entry
[post_model_sync]
execute:frappe.delete_doc_if_exists('Workspace', 'ERPNext Integrations Settings')
diff --git a/erpnext/patches/v14_0/update_reference_due_date_in_journal_entry.py b/erpnext/patches/v14_0/update_reference_due_date_in_journal_entry.py
new file mode 100644
index 0000000000..70003125a5
--- /dev/null
+++ b/erpnext/patches/v14_0/update_reference_due_date_in_journal_entry.py
@@ -0,0 +1,12 @@
+import frappe
+
+
+def execute():
+ if frappe.db.get_value("Journal Entry Account", {"reference_due_date": ""}):
+ frappe.db.sql(
+ """
+ UPDATE `tabJournal Entry Account`
+ SET reference_due_date = NULL
+ WHERE reference_due_date = ''
+ """
+ )
diff --git a/erpnext/selling/doctype/quotation/quotation.py b/erpnext/selling/doctype/quotation/quotation.py
index 484b8c9f08..6836d56647 100644
--- a/erpnext/selling/doctype/quotation/quotation.py
+++ b/erpnext/selling/doctype/quotation/quotation.py
@@ -194,14 +194,7 @@ def get_list_context(context=None):
@frappe.whitelist()
-def make_sales_order(source_name, target_doc=None):
- quotation = frappe.db.get_value(
- "Quotation", source_name, ["transaction_date", "valid_till"], as_dict=1
- )
- if quotation.valid_till and (
- quotation.valid_till < quotation.transaction_date or quotation.valid_till < getdate(nowdate())
- ):
- frappe.throw(_("Validity period of this quotation has ended."))
+def make_sales_order(source_name: str, target_doc=None):
return _make_sales_order(source_name, target_doc)
diff --git a/erpnext/selling/doctype/quotation/test_quotation.py b/erpnext/selling/doctype/quotation/test_quotation.py
index b151dd5e79..5aaba4fa43 100644
--- a/erpnext/selling/doctype/quotation/test_quotation.py
+++ b/erpnext/selling/doctype/quotation/test_quotation.py
@@ -136,17 +136,20 @@ class TestQuotation(FrappeTestCase):
sales_order.payment_schedule[1].due_date, getdate(add_days(quotation.transaction_date, 30))
)
- def test_valid_till(self):
- from erpnext.selling.doctype.quotation.quotation import make_sales_order
-
+ def test_valid_till_before_transaction_date(self):
quotation = frappe.copy_doc(test_records[0])
quotation.valid_till = add_days(quotation.transaction_date, -1)
self.assertRaises(frappe.ValidationError, quotation.validate)
+ def test_so_from_expired_quotation(self):
+ from erpnext.selling.doctype.quotation.quotation import make_sales_order
+
+ quotation = frappe.copy_doc(test_records[0])
quotation.valid_till = add_days(nowdate(), -1)
quotation.insert()
quotation.submit()
- self.assertRaises(frappe.ValidationError, make_sales_order, quotation.name)
+
+ make_sales_order(quotation.name)
def test_shopping_cart_without_website_item(self):
if frappe.db.exists("Website Item", {"item_code": "_Test Item Home Desktop 100"}):
diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py
index 7c0601e3dd..accf5f22a6 100755
--- a/erpnext/selling/doctype/sales_order/sales_order.py
+++ b/erpnext/selling/doctype/sales_order/sales_order.py
@@ -208,7 +208,7 @@ class SalesOrder(SellingController):
for quotation in set(d.prevdoc_docname for d in self.get("items")):
if quotation:
doc = frappe.get_doc("Quotation", quotation)
- if doc.docstatus == 2:
+ if doc.docstatus.is_cancelled():
frappe.throw(_("Quotation {0} is cancelled").format(quotation))
doc.set_status(update=True)
diff --git a/erpnext/selling/doctype/sales_order_item/sales_order_item.json b/erpnext/selling/doctype/sales_order_item/sales_order_item.json
index 134b5eafd0..d0dabad5c9 100644
--- a/erpnext/selling/doctype/sales_order_item/sales_order_item.json
+++ b/erpnext/selling/doctype/sales_order_item/sales_order_item.json
@@ -638,7 +638,6 @@
"width": "70px"
},
{
- "allow_on_submit": 1,
"fieldname": "ordered_qty",
"fieldtype": "Float",
"label": "Ordered Qty",
@@ -865,7 +864,7 @@
"idx": 1,
"istable": 1,
"links": [],
- "modified": "2023-01-12 13:13:28.691585",
+ "modified": "2022-12-25 02:51:10.247569",
"modified_by": "Administrator",
"module": "Selling",
"name": "Sales Order Item",
diff --git a/erpnext/stock/doctype/item/test_item.py b/erpnext/stock/doctype/item/test_item.py
index 7e426ae4af..53f6b7f8f1 100644
--- a/erpnext/stock/doctype/item/test_item.py
+++ b/erpnext/stock/doctype/item/test_item.py
@@ -106,7 +106,6 @@ class TestItem(FrappeTestCase):
"conversion_factor": 1.0,
"reserved_qty": 1,
"actual_qty": 5,
- "ordered_qty": 10,
"projected_qty": 14,
}
diff --git a/erpnext/stock/doctype/pick_list/pick_list_dashboard.py b/erpnext/stock/doctype/pick_list/pick_list_dashboard.py
index 92e57bed22..7fbcbafbac 100644
--- a/erpnext/stock/doctype/pick_list/pick_list_dashboard.py
+++ b/erpnext/stock/doctype/pick_list/pick_list_dashboard.py
@@ -1,7 +1,10 @@
def get_data():
return {
"fieldname": "pick_list",
+ "internal_links": {
+ "Sales Order": ["locations", "sales_order"],
+ },
"transactions": [
- {"items": ["Stock Entry", "Delivery Note"]},
+ {"items": ["Stock Entry", "Sales Order", "Delivery Note"]},
],
}
diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py
index f7fcb30acd..363dc0a63f 100644
--- a/erpnext/stock/get_item_details.py
+++ b/erpnext/stock/get_item_details.py
@@ -1181,7 +1181,7 @@ def get_projected_qty(item_code, warehouse):
@frappe.whitelist()
def get_bin_details(item_code, warehouse, company=None, include_child_warehouses=False):
- bin_details = {"projected_qty": 0, "actual_qty": 0, "reserved_qty": 0, "ordered_qty": 0}
+ bin_details = {"projected_qty": 0, "actual_qty": 0, "reserved_qty": 0}
if warehouse:
from frappe.query_builder.functions import Coalesce, Sum
@@ -1197,7 +1197,6 @@ def get_bin_details(item_code, warehouse, company=None, include_child_warehouses
Coalesce(Sum(bin.projected_qty), 0).as_("projected_qty"),
Coalesce(Sum(bin.actual_qty), 0).as_("actual_qty"),
Coalesce(Sum(bin.reserved_qty), 0).as_("reserved_qty"),
- Coalesce(Sum(bin.ordered_qty), 0).as_("ordered_qty"),
)
.where((bin.item_code == item_code) & (bin.warehouse.isin(warehouses)))
).run(as_dict=True)[0]
diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py
index 7e1915bb71..e8faa4868f 100644
--- a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py
+++ b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py
@@ -63,6 +63,11 @@ class SubcontractingReceipt(SubcontractingController):
self.set_items_expense_account()
def validate(self):
+ if (
+ frappe.db.get_single_value("Buying Settings", "backflush_raw_materials_of_subcontract_based_on")
+ == "BOM"
+ ):
+ self.supplied_items = []
super(SubcontractingReceipt, self).validate()
self.set_missing_values()
self.validate_posting_time()