mirror of
https://github.com/frappe/erpnext.git
synced 2026-02-13 01:34:10 +00:00
fix: validate over ordering of quotation
(cherry picked from commit 4cc306d2d8)
# Conflicts:
# erpnext/controllers/status_updater.py
# erpnext/patches.txt
# erpnext/selling/doctype/quotation/quotation.py
# erpnext/selling/doctype/quotation_item/quotation_item.json
This commit is contained in:
@@ -341,10 +341,22 @@ class StatusUpdater(Document):
|
||||
):
|
||||
return
|
||||
|
||||
<<<<<<< HEAD
|
||||
if qty_or_amount == "qty":
|
||||
action_msg = _(
|
||||
'To allow over receipt / delivery, update "Over Receipt/Delivery Allowance" in Stock Settings or the Item.'
|
||||
)
|
||||
=======
|
||||
if args["source_dt"] != "Pick List Item" and args["target_dt"] != "Quotation Item":
|
||||
if qty_or_amount == "qty":
|
||||
action_msg = _(
|
||||
'To allow over receipt / delivery, update "Over Receipt/Delivery Allowance" in Stock Settings or the Item.'
|
||||
)
|
||||
else:
|
||||
action_msg = _(
|
||||
'To allow over billing, update "Over Billing Allowance" in Accounts Settings or the Item.'
|
||||
)
|
||||
>>>>>>> 4cc306d2d8 (fix: validate over ordering of quotation)
|
||||
else:
|
||||
action_msg = _(
|
||||
'To allow over billing, update "Over Billing Allowance" in Accounts Settings or the Item.'
|
||||
|
||||
@@ -428,3 +428,9 @@ execute:frappe.db.set_single_value("Accounts Settings", "show_party_balance", 1)
|
||||
execute:frappe.db.set_single_value("Accounts Settings", "show_account_balance", 1)
|
||||
erpnext.patches.v16_0.update_currency_exchange_settings_for_frankfurter #2025-12-11
|
||||
erpnext.patches.v15_0.create_accounting_dimensions_in_advance_taxes_and_charges
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
execute:frappe.delete_doc_if_exists("Workspace Sidebar", "Opening & Closing")
|
||||
erpnext.patches.v16_0.migrate_transaction_deletion_task_flags_to_status # 2
|
||||
erpnext.patches.v16_0.set_ordered_qty_in_quotation_item
|
||||
>>>>>>> 4cc306d2d8 (fix: validate over ordering of quotation)
|
||||
|
||||
16
erpnext/patches/v16_0/set_ordered_qty_in_quotation_item.py
Normal file
16
erpnext/patches/v16_0/set_ordered_qty_in_quotation_item.py
Normal file
@@ -0,0 +1,16 @@
|
||||
import frappe
|
||||
|
||||
|
||||
def execute():
|
||||
data = frappe.get_all(
|
||||
"Sales Order Item",
|
||||
filters={"quotation_item": ["is", "set"], "docstatus": 1},
|
||||
fields=["quotation_item", {"SUM": "stock_qty", "as": "ordered_qty"}],
|
||||
group_by="quotation_item",
|
||||
)
|
||||
if data:
|
||||
frappe.db.auto_commit_on_many_writes = 1
|
||||
frappe.db.bulk_update(
|
||||
"Quotation Item", {d.quotation_item: {"ordered_qty": d.ordered_qty} for d in data}
|
||||
)
|
||||
frappe.db.auto_commit_on_many_writes = 0
|
||||
@@ -446,7 +446,10 @@ def _make_sales_order(source_name, target_doc=None, ignore_permissions=False, ar
|
||||
"Quotation",
|
||||
source_name,
|
||||
{
|
||||
"Quotation": {"doctype": "Sales Order", "validation": {"docstatus": ["=", 1]}},
|
||||
"Quotation": {
|
||||
"doctype": "Sales Order",
|
||||
"validation": {"docstatus": ["=", 1]},
|
||||
},
|
||||
"Quotation Item": {
|
||||
"doctype": "Sales Order Item",
|
||||
"field_map": {"parent": "prevdoc_docname", "name": "quotation_item"},
|
||||
@@ -549,6 +552,8 @@ def _make_customer(source_name, ignore_permissions=False):
|
||||
|
||||
if quotation.quotation_to == "Customer":
|
||||
return frappe.get_doc("Customer", quotation.party_name)
|
||||
elif quotation.quotation_to == "CRM Deal":
|
||||
return frappe.get_doc("Customer", {"crm_deal": quotation.party_name})
|
||||
|
||||
# Check if a Customer already exists for the Lead or Prospect.
|
||||
existing_customer = None
|
||||
@@ -610,25 +615,16 @@ def handle_mandatory_error(e, customer, lead_name):
|
||||
|
||||
|
||||
def get_ordered_items(quotation: str):
|
||||
"""
|
||||
Returns a dict of ordered items with their total qty based on quotation row name.
|
||||
|
||||
In `Sales Order Item`, `quotation_item` is the row name of `Quotation Item`.
|
||||
|
||||
Example:
|
||||
```
|
||||
{
|
||||
"refsdjhd2": 10,
|
||||
"ygdhdshrt": 5,
|
||||
}
|
||||
```
|
||||
"""
|
||||
return frappe._dict(
|
||||
frappe.get_all(
|
||||
<<<<<<< HEAD
|
||||
"Sales Order Item",
|
||||
filters={"prevdoc_docname": quotation, "docstatus": 1},
|
||||
fields=["quotation_item", "sum(qty)"],
|
||||
group_by="quotation_item",
|
||||
as_list=1,
|
||||
=======
|
||||
"Quotation Item", {"docstatus": 1, "parent": quotation}, ["name", "ordered_qty"], as_list=True
|
||||
>>>>>>> 4cc306d2d8 (fix: validate over ordering of quotation)
|
||||
)
|
||||
)
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
"uom",
|
||||
"conversion_factor",
|
||||
"stock_qty",
|
||||
"ordered_qty",
|
||||
"available_quantity_section",
|
||||
"actual_qty",
|
||||
"column_break_ylrv",
|
||||
@@ -694,18 +695,34 @@
|
||||
"print_hide": 1,
|
||||
"read_only": 1,
|
||||
"report_hide": 1
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "ordered_qty",
|
||||
"fieldtype": "Float",
|
||||
"hidden": 1,
|
||||
"label": "Ordered Qty",
|
||||
"no_copy": 1,
|
||||
"non_negative": 1,
|
||||
"read_only": 1,
|
||||
"reqd": 1
|
||||
}
|
||||
],
|
||||
"idx": 1,
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2025-08-26 20:31:47.775890",
|
||||
"modified": "2026-01-30 12:56:08.320190",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Selling",
|
||||
"name": "Quotation Item",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
<<<<<<< HEAD
|
||||
"sort_field": "modified",
|
||||
=======
|
||||
"row_format": "Dynamic",
|
||||
"sort_field": "creation",
|
||||
>>>>>>> 4cc306d2d8 (fix: validate over ordering of quotation)
|
||||
"sort_order": "DESC",
|
||||
"states": [],
|
||||
"track_changes": 1
|
||||
|
||||
@@ -48,6 +48,7 @@ class QuotationItem(Document):
|
||||
margin_type: DF.Literal["", "Percentage", "Amount"]
|
||||
net_amount: DF.Currency
|
||||
net_rate: DF.Currency
|
||||
ordered_qty: DF.Float
|
||||
page_break: DF.Check
|
||||
parent: DF.Data
|
||||
parentfield: DF.Data
|
||||
|
||||
@@ -185,6 +185,16 @@ class SalesOrder(SellingController):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.status_updater = [
|
||||
{
|
||||
"source_dt": "Sales Order Item",
|
||||
"target_dt": "Quotation Item",
|
||||
"join_field": "quotation_item",
|
||||
"target_field": "ordered_qty",
|
||||
"target_ref_field": "stock_qty",
|
||||
"source_field": "stock_qty",
|
||||
}
|
||||
]
|
||||
|
||||
def onload(self) -> None:
|
||||
super().onload()
|
||||
@@ -419,6 +429,7 @@ class SalesOrder(SellingController):
|
||||
frappe.throw(_("Row #{0}: Set Supplier for item {1}").format(d.idx, d.item_code))
|
||||
|
||||
def on_submit(self):
|
||||
super().update_prevdoc_status()
|
||||
self.check_credit_limit()
|
||||
self.update_reserved_qty()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user