fix: prevent extra transfer against inter transfer transaction (#39213)
* fix: prevent extra transfer against inter transfer transaction * fix: internal transfer dashboard
This commit is contained in:
parent
5be868c7f6
commit
8fdc244e16
@ -6,7 +6,7 @@ from collections import defaultdict
|
|||||||
from typing import List, Tuple
|
from typing import List, Tuple
|
||||||
|
|
||||||
import frappe
|
import frappe
|
||||||
from frappe import _
|
from frappe import _, bold
|
||||||
from frappe.utils import cint, flt, get_link_to_form, getdate
|
from frappe.utils import cint, flt, get_link_to_form, getdate
|
||||||
|
|
||||||
import erpnext
|
import erpnext
|
||||||
@ -697,6 +697,9 @@ class StockController(AccountsController):
|
|||||||
self.validate_in_transit_warehouses()
|
self.validate_in_transit_warehouses()
|
||||||
self.validate_multi_currency()
|
self.validate_multi_currency()
|
||||||
self.validate_packed_items()
|
self.validate_packed_items()
|
||||||
|
|
||||||
|
if self.get("is_internal_supplier"):
|
||||||
|
self.validate_internal_transfer_qty()
|
||||||
else:
|
else:
|
||||||
self.validate_internal_transfer_warehouse()
|
self.validate_internal_transfer_warehouse()
|
||||||
|
|
||||||
@ -735,6 +738,116 @@ class StockController(AccountsController):
|
|||||||
if self.doctype in ("Sales Invoice", "Delivery Note Item") and self.get("packed_items"):
|
if self.doctype in ("Sales Invoice", "Delivery Note Item") and self.get("packed_items"):
|
||||||
frappe.throw(_("Packed Items cannot be transferred internally"))
|
frappe.throw(_("Packed Items cannot be transferred internally"))
|
||||||
|
|
||||||
|
def validate_internal_transfer_qty(self):
|
||||||
|
if self.doctype not in ["Purchase Invoice", "Purchase Receipt"]:
|
||||||
|
return
|
||||||
|
|
||||||
|
item_wise_transfer_qty = self.get_item_wise_inter_transfer_qty()
|
||||||
|
if not item_wise_transfer_qty:
|
||||||
|
return
|
||||||
|
|
||||||
|
item_wise_received_qty = self.get_item_wise_inter_received_qty()
|
||||||
|
precision = frappe.get_precision(self.doctype + " Item", "qty")
|
||||||
|
|
||||||
|
over_receipt_allowance = frappe.db.get_single_value(
|
||||||
|
"Stock Settings", "over_delivery_receipt_allowance"
|
||||||
|
)
|
||||||
|
|
||||||
|
parent_doctype = {
|
||||||
|
"Purchase Receipt": "Delivery Note",
|
||||||
|
"Purchase Invoice": "Sales Invoice",
|
||||||
|
}.get(self.doctype)
|
||||||
|
|
||||||
|
for key, transferred_qty in item_wise_transfer_qty.items():
|
||||||
|
recevied_qty = flt(item_wise_received_qty.get(key), precision)
|
||||||
|
if over_receipt_allowance:
|
||||||
|
transferred_qty = transferred_qty + flt(
|
||||||
|
transferred_qty * over_receipt_allowance / 100, precision
|
||||||
|
)
|
||||||
|
|
||||||
|
if recevied_qty > flt(transferred_qty, precision):
|
||||||
|
frappe.throw(
|
||||||
|
_("For Item {0} cannot be received more than {1} qty against the {2} {3}").format(
|
||||||
|
bold(key[1]),
|
||||||
|
bold(flt(transferred_qty, precision)),
|
||||||
|
bold(parent_doctype),
|
||||||
|
get_link_to_form(parent_doctype, self.get("inter_company_reference")),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_item_wise_inter_transfer_qty(self):
|
||||||
|
reference_field = "inter_company_reference"
|
||||||
|
if self.doctype == "Purchase Invoice":
|
||||||
|
reference_field = "inter_company_invoice_reference"
|
||||||
|
|
||||||
|
parent_doctype = {
|
||||||
|
"Purchase Receipt": "Delivery Note",
|
||||||
|
"Purchase Invoice": "Sales Invoice",
|
||||||
|
}.get(self.doctype)
|
||||||
|
|
||||||
|
child_doctype = parent_doctype + " Item"
|
||||||
|
|
||||||
|
parent_tab = frappe.qb.DocType(parent_doctype)
|
||||||
|
child_tab = frappe.qb.DocType(child_doctype)
|
||||||
|
|
||||||
|
query = (
|
||||||
|
frappe.qb.from_(parent_doctype)
|
||||||
|
.inner_join(child_tab)
|
||||||
|
.on(child_tab.parent == parent_tab.name)
|
||||||
|
.select(
|
||||||
|
child_tab.name,
|
||||||
|
child_tab.item_code,
|
||||||
|
child_tab.qty,
|
||||||
|
)
|
||||||
|
.where((parent_tab.name == self.get(reference_field)) & (parent_tab.docstatus == 1))
|
||||||
|
)
|
||||||
|
|
||||||
|
data = query.run(as_dict=True)
|
||||||
|
item_wise_transfer_qty = defaultdict(float)
|
||||||
|
for row in data:
|
||||||
|
item_wise_transfer_qty[(row.name, row.item_code)] += flt(row.qty)
|
||||||
|
|
||||||
|
return item_wise_transfer_qty
|
||||||
|
|
||||||
|
def get_item_wise_inter_received_qty(self):
|
||||||
|
child_doctype = self.doctype + " Item"
|
||||||
|
|
||||||
|
parent_tab = frappe.qb.DocType(self.doctype)
|
||||||
|
child_tab = frappe.qb.DocType(child_doctype)
|
||||||
|
|
||||||
|
query = (
|
||||||
|
frappe.qb.from_(self.doctype)
|
||||||
|
.inner_join(child_tab)
|
||||||
|
.on(child_tab.parent == parent_tab.name)
|
||||||
|
.select(
|
||||||
|
child_tab.item_code,
|
||||||
|
child_tab.qty,
|
||||||
|
)
|
||||||
|
.where(parent_tab.docstatus < 2)
|
||||||
|
)
|
||||||
|
|
||||||
|
if self.doctype == "Purchase Invoice":
|
||||||
|
query = query.select(
|
||||||
|
child_tab.sales_invoice_item.as_("name"),
|
||||||
|
)
|
||||||
|
|
||||||
|
query = query.where(
|
||||||
|
parent_tab.inter_company_invoice_reference == self.inter_company_invoice_reference
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
query = query.select(
|
||||||
|
child_tab.delivery_note_item.as_("name"),
|
||||||
|
)
|
||||||
|
|
||||||
|
query = query.where(parent_tab.inter_company_reference == self.inter_company_reference)
|
||||||
|
|
||||||
|
data = query.run(as_dict=True)
|
||||||
|
item_wise_transfer_qty = defaultdict(float)
|
||||||
|
for row in data:
|
||||||
|
item_wise_transfer_qty[(row.name, row.item_code)] += flt(row.qty)
|
||||||
|
|
||||||
|
return item_wise_transfer_qty
|
||||||
|
|
||||||
def validate_putaway_capacity(self):
|
def validate_putaway_capacity(self):
|
||||||
# if over receipt is attempted while 'apply putaway rule' is disabled
|
# if over receipt is attempted while 'apply putaway rule' is disabled
|
||||||
# and if rule was applied on the transaction, validate it.
|
# and if rule was applied on the transaction, validate it.
|
||||||
|
|||||||
@ -8,6 +8,7 @@ def get_data():
|
|||||||
"Stock Entry": "delivery_note_no",
|
"Stock Entry": "delivery_note_no",
|
||||||
"Quality Inspection": "reference_name",
|
"Quality Inspection": "reference_name",
|
||||||
"Auto Repeat": "reference_document",
|
"Auto Repeat": "reference_document",
|
||||||
|
"Purchase Receipt": "inter_company_reference",
|
||||||
},
|
},
|
||||||
"internal_links": {
|
"internal_links": {
|
||||||
"Sales Order": ["items", "against_sales_order"],
|
"Sales Order": ["items", "against_sales_order"],
|
||||||
@ -22,6 +23,9 @@ def get_data():
|
|||||||
{"label": _("Reference"), "items": ["Sales Order", "Shipment", "Quality Inspection"]},
|
{"label": _("Reference"), "items": ["Sales Order", "Shipment", "Quality Inspection"]},
|
||||||
{"label": _("Returns"), "items": ["Stock Entry"]},
|
{"label": _("Returns"), "items": ["Stock Entry"]},
|
||||||
{"label": _("Subscription"), "items": ["Auto Repeat"]},
|
{"label": _("Subscription"), "items": ["Auto Repeat"]},
|
||||||
{"label": _("Internal Transfer"), "items": ["Material Request", "Purchase Order"]},
|
{
|
||||||
|
"label": _("Internal Transfer"),
|
||||||
|
"items": ["Material Request", "Purchase Order", "Purchase Receipt"],
|
||||||
|
},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1706,7 +1706,7 @@ class TestPurchaseReceipt(FrappeTestCase):
|
|||||||
pr.items[0].rejected_warehouse = from_warehouse
|
pr.items[0].rejected_warehouse = from_warehouse
|
||||||
pr.save()
|
pr.save()
|
||||||
|
|
||||||
self.assertRaises(OverAllowanceError, pr.submit)
|
self.assertRaises(frappe.ValidationError, pr.submit)
|
||||||
|
|
||||||
# Step 5: Test Over Receipt Allowance
|
# Step 5: Test Over Receipt Allowance
|
||||||
frappe.db.set_single_value("Stock Settings", "over_delivery_receipt_allowance", 50)
|
frappe.db.set_single_value("Stock Settings", "over_delivery_receipt_allowance", 50)
|
||||||
@ -1720,6 +1720,7 @@ class TestPurchaseReceipt(FrappeTestCase):
|
|||||||
to_warehouse=target_warehouse,
|
to_warehouse=target_warehouse,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
pr.reload()
|
||||||
pr.submit()
|
pr.submit()
|
||||||
|
|
||||||
frappe.db.set_single_value("Stock Settings", "over_delivery_receipt_allowance", 0)
|
frappe.db.set_single_value("Stock Settings", "over_delivery_receipt_allowance", 0)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user