mirror of
https://github.com/frappe/erpnext.git
synced 2026-06-03 12:19:12 +00:00
refactor!: Purchase Receipt
This commit is contained in:
@@ -298,9 +298,6 @@ cur_frm.fields_dict['items'].grid.get_field('bom').get_query = function(doc, cdt
|
|||||||
frappe.provide("erpnext.buying");
|
frappe.provide("erpnext.buying");
|
||||||
|
|
||||||
frappe.ui.form.on("Purchase Receipt", "is_subcontracted", function(frm) {
|
frappe.ui.form.on("Purchase Receipt", "is_subcontracted", function(frm) {
|
||||||
if (frm.doc.is_subcontracted) {
|
|
||||||
erpnext.buying.get_default_bom(frm);
|
|
||||||
}
|
|
||||||
frm.toggle_reqd("supplier_warehouse", frm.doc.is_subcontracted);
|
frm.toggle_reqd("supplier_warehouse", frm.doc.is_subcontracted);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -231,7 +231,6 @@ class PurchaseReceipt(BuyingController):
|
|||||||
|
|
||||||
self.make_gl_entries()
|
self.make_gl_entries()
|
||||||
self.repost_future_sle_and_gle()
|
self.repost_future_sle_and_gle()
|
||||||
self.set_consumed_qty_in_po()
|
|
||||||
|
|
||||||
def check_next_docstatus(self):
|
def check_next_docstatus(self):
|
||||||
submit_rv = frappe.db.sql(
|
submit_rv = frappe.db.sql(
|
||||||
@@ -267,18 +266,6 @@ class PurchaseReceipt(BuyingController):
|
|||||||
self.repost_future_sle_and_gle()
|
self.repost_future_sle_and_gle()
|
||||||
self.ignore_linked_doctypes = ("GL Entry", "Stock Ledger Entry", "Repost Item Valuation")
|
self.ignore_linked_doctypes = ("GL Entry", "Stock Ledger Entry", "Repost Item Valuation")
|
||||||
self.delete_auto_created_batches()
|
self.delete_auto_created_batches()
|
||||||
self.set_consumed_qty_in_po()
|
|
||||||
|
|
||||||
@frappe.whitelist()
|
|
||||||
def get_current_stock(self):
|
|
||||||
for d in self.get("supplied_items"):
|
|
||||||
if self.supplier_warehouse:
|
|
||||||
bin = frappe.db.sql(
|
|
||||||
"select actual_qty from `tabBin` where item_code = %s and warehouse = %s",
|
|
||||||
(d.rm_item_code, self.supplier_warehouse),
|
|
||||||
as_dict=1,
|
|
||||||
)
|
|
||||||
d.current_stock = bin and flt(bin[0]["actual_qty"]) or 0
|
|
||||||
|
|
||||||
def get_gl_entries(self, warehouse_account=None):
|
def get_gl_entries(self, warehouse_account=None):
|
||||||
from erpnext.accounts.general_ledger import process_gl_map
|
from erpnext.accounts.general_ledger import process_gl_map
|
||||||
|
|||||||
@@ -2,10 +2,6 @@
|
|||||||
# License: GNU General Public License v3. See license.txt
|
# License: GNU General Public License v3. See license.txt
|
||||||
|
|
||||||
|
|
||||||
import json
|
|
||||||
import unittest
|
|
||||||
from collections import defaultdict
|
|
||||||
|
|
||||||
import frappe
|
import frappe
|
||||||
from frappe.tests.utils import FrappeTestCase, change_settings
|
from frappe.tests.utils import FrappeTestCase, change_settings
|
||||||
from frappe.utils import add_days, cint, cstr, flt, today
|
from frappe.utils import add_days, cint, cstr, flt, today
|
||||||
@@ -311,142 +307,6 @@ class TestPurchaseReceipt(FrappeTestCase):
|
|||||||
pr.cancel()
|
pr.cancel()
|
||||||
self.assertTrue(get_gl_entries("Purchase Receipt", pr.name))
|
self.assertTrue(get_gl_entries("Purchase Receipt", pr.name))
|
||||||
|
|
||||||
def test_subcontracting(self):
|
|
||||||
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
|
|
||||||
|
|
||||||
frappe.db.set_value(
|
|
||||||
"Buying Settings", None, "backflush_raw_materials_of_subcontract_based_on", "BOM"
|
|
||||||
)
|
|
||||||
|
|
||||||
make_stock_entry(
|
|
||||||
item_code="_Test Item", qty=100, target="_Test Warehouse 1 - _TC", basic_rate=100
|
|
||||||
)
|
|
||||||
make_stock_entry(
|
|
||||||
item_code="_Test Item Home Desktop 100",
|
|
||||||
qty=100,
|
|
||||||
target="_Test Warehouse 1 - _TC",
|
|
||||||
basic_rate=100,
|
|
||||||
)
|
|
||||||
pr = make_purchase_receipt(item_code="_Test FG Item", qty=10, rate=500, is_subcontracted=1)
|
|
||||||
self.assertEqual(len(pr.get("supplied_items")), 2)
|
|
||||||
|
|
||||||
rm_supp_cost = sum(d.amount for d in pr.get("supplied_items"))
|
|
||||||
self.assertEqual(pr.get("items")[0].rm_supp_cost, flt(rm_supp_cost, 2))
|
|
||||||
|
|
||||||
pr.cancel()
|
|
||||||
|
|
||||||
def test_subcontracting_gle_fg_item_rate_zero(self):
|
|
||||||
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
|
|
||||||
|
|
||||||
frappe.db.set_value(
|
|
||||||
"Buying Settings", None, "backflush_raw_materials_of_subcontract_based_on", "BOM"
|
|
||||||
)
|
|
||||||
|
|
||||||
se1 = make_stock_entry(
|
|
||||||
item_code="_Test Item",
|
|
||||||
target="Work In Progress - TCP1",
|
|
||||||
qty=100,
|
|
||||||
basic_rate=100,
|
|
||||||
company="_Test Company with perpetual inventory",
|
|
||||||
)
|
|
||||||
|
|
||||||
se2 = make_stock_entry(
|
|
||||||
item_code="_Test Item Home Desktop 100",
|
|
||||||
target="Work In Progress - TCP1",
|
|
||||||
qty=100,
|
|
||||||
basic_rate=100,
|
|
||||||
company="_Test Company with perpetual inventory",
|
|
||||||
)
|
|
||||||
|
|
||||||
pr = make_purchase_receipt(
|
|
||||||
item_code="_Test FG Item",
|
|
||||||
qty=10,
|
|
||||||
rate=0,
|
|
||||||
is_subcontracted=1,
|
|
||||||
company="_Test Company with perpetual inventory",
|
|
||||||
warehouse="Stores - TCP1",
|
|
||||||
supplier_warehouse="Work In Progress - TCP1",
|
|
||||||
)
|
|
||||||
|
|
||||||
gl_entries = get_gl_entries("Purchase Receipt", pr.name)
|
|
||||||
|
|
||||||
self.assertFalse(gl_entries)
|
|
||||||
|
|
||||||
pr.cancel()
|
|
||||||
se1.cancel()
|
|
||||||
se2.cancel()
|
|
||||||
|
|
||||||
def test_subcontracting_over_receipt(self):
|
|
||||||
"""
|
|
||||||
Behaviour: Raise multiple PRs against one PO that in total
|
|
||||||
receive more than the required qty in the PO.
|
|
||||||
Expected Result: Error Raised for Over Receipt against PO.
|
|
||||||
"""
|
|
||||||
from erpnext.buying.doctype.purchase_order.purchase_order import make_purchase_receipt
|
|
||||||
from erpnext.buying.doctype.purchase_order.purchase_order import (
|
|
||||||
make_rm_stock_entry as make_subcontract_transfer_entry,
|
|
||||||
)
|
|
||||||
from erpnext.buying.doctype.purchase_order.test_purchase_order import (
|
|
||||||
create_purchase_order,
|
|
||||||
make_subcontracted_item,
|
|
||||||
update_backflush_based_on,
|
|
||||||
)
|
|
||||||
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
|
|
||||||
|
|
||||||
update_backflush_based_on("Material Transferred for Subcontract")
|
|
||||||
item_code = "_Test Subcontracted FG Item 1"
|
|
||||||
make_subcontracted_item(item_code=item_code)
|
|
||||||
|
|
||||||
po = create_purchase_order(
|
|
||||||
item_code=item_code,
|
|
||||||
qty=1,
|
|
||||||
include_exploded_items=0,
|
|
||||||
is_subcontracted=1,
|
|
||||||
supplier_warehouse="_Test Warehouse 1 - _TC",
|
|
||||||
)
|
|
||||||
|
|
||||||
# stock raw materials in a warehouse before transfer
|
|
||||||
make_stock_entry(
|
|
||||||
target="_Test Warehouse - _TC", item_code="Test Extra Item 1", qty=10, basic_rate=100
|
|
||||||
)
|
|
||||||
make_stock_entry(
|
|
||||||
target="_Test Warehouse - _TC", item_code="_Test FG Item", qty=1, basic_rate=100
|
|
||||||
)
|
|
||||||
make_stock_entry(
|
|
||||||
target="_Test Warehouse - _TC", item_code="Test Extra Item 2", qty=1, basic_rate=100
|
|
||||||
)
|
|
||||||
|
|
||||||
rm_items = [
|
|
||||||
{
|
|
||||||
"item_code": item_code,
|
|
||||||
"rm_item_code": po.supplied_items[0].rm_item_code,
|
|
||||||
"item_name": "_Test FG Item",
|
|
||||||
"qty": po.supplied_items[0].required_qty,
|
|
||||||
"warehouse": "_Test Warehouse - _TC",
|
|
||||||
"stock_uom": "Nos",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"item_code": item_code,
|
|
||||||
"rm_item_code": po.supplied_items[1].rm_item_code,
|
|
||||||
"item_name": "Test Extra Item 1",
|
|
||||||
"qty": po.supplied_items[1].required_qty,
|
|
||||||
"warehouse": "_Test Warehouse - _TC",
|
|
||||||
"stock_uom": "Nos",
|
|
||||||
},
|
|
||||||
]
|
|
||||||
rm_item_string = json.dumps(rm_items)
|
|
||||||
se = frappe.get_doc(make_subcontract_transfer_entry(po.name, rm_item_string))
|
|
||||||
se.to_warehouse = "_Test Warehouse 1 - _TC"
|
|
||||||
se.save()
|
|
||||||
se.submit()
|
|
||||||
|
|
||||||
pr1 = make_purchase_receipt(po.name)
|
|
||||||
pr2 = make_purchase_receipt(po.name)
|
|
||||||
|
|
||||||
pr1.submit()
|
|
||||||
self.assertRaises(frappe.ValidationError, pr2.submit)
|
|
||||||
frappe.db.rollback()
|
|
||||||
|
|
||||||
def test_serial_no_supplier(self):
|
def test_serial_no_supplier(self):
|
||||||
pr = make_purchase_receipt(item_code="_Test Serialized Item With Series", qty=1)
|
pr = make_purchase_receipt(item_code="_Test Serialized Item With Series", qty=1)
|
||||||
pr_row_1_serial_no = pr.get("items")[0].serial_no
|
pr_row_1_serial_no = pr.get("items")[0].serial_no
|
||||||
@@ -1095,103 +955,6 @@ class TestPurchaseReceipt(FrappeTestCase):
|
|||||||
pr.cancel()
|
pr.cancel()
|
||||||
pr1.cancel()
|
pr1.cancel()
|
||||||
|
|
||||||
def test_subcontracted_pr_for_multi_transfer_batches(self):
|
|
||||||
from erpnext.buying.doctype.purchase_order.purchase_order import (
|
|
||||||
make_purchase_receipt,
|
|
||||||
make_rm_stock_entry,
|
|
||||||
)
|
|
||||||
from erpnext.buying.doctype.purchase_order.test_purchase_order import (
|
|
||||||
create_purchase_order,
|
|
||||||
update_backflush_based_on,
|
|
||||||
)
|
|
||||||
from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
|
|
||||||
|
|
||||||
update_backflush_based_on("Material Transferred for Subcontract")
|
|
||||||
item_code = "_Test Subcontracted FG Item 3"
|
|
||||||
|
|
||||||
make_item(
|
|
||||||
"Sub Contracted Raw Material 3",
|
|
||||||
{"is_stock_item": 1, "is_sub_contracted_item": 1, "has_batch_no": 1, "create_new_batch": 1},
|
|
||||||
)
|
|
||||||
|
|
||||||
create_subcontracted_item(
|
|
||||||
item_code=item_code, has_batch_no=1, raw_materials=["Sub Contracted Raw Material 3"]
|
|
||||||
)
|
|
||||||
|
|
||||||
order_qty = 500
|
|
||||||
po = create_purchase_order(
|
|
||||||
item_code=item_code,
|
|
||||||
qty=order_qty,
|
|
||||||
is_subcontracted=1,
|
|
||||||
supplier_warehouse="_Test Warehouse 1 - _TC",
|
|
||||||
)
|
|
||||||
|
|
||||||
ste1 = make_stock_entry(
|
|
||||||
target="_Test Warehouse - _TC",
|
|
||||||
item_code="Sub Contracted Raw Material 3",
|
|
||||||
qty=300,
|
|
||||||
basic_rate=100,
|
|
||||||
)
|
|
||||||
ste2 = make_stock_entry(
|
|
||||||
target="_Test Warehouse - _TC",
|
|
||||||
item_code="Sub Contracted Raw Material 3",
|
|
||||||
qty=200,
|
|
||||||
basic_rate=100,
|
|
||||||
)
|
|
||||||
|
|
||||||
transferred_batch = {ste1.items[0].batch_no: 300, ste2.items[0].batch_no: 200}
|
|
||||||
|
|
||||||
rm_items = [
|
|
||||||
{
|
|
||||||
"item_code": item_code,
|
|
||||||
"rm_item_code": "Sub Contracted Raw Material 3",
|
|
||||||
"item_name": "_Test Item",
|
|
||||||
"qty": 300,
|
|
||||||
"warehouse": "_Test Warehouse - _TC",
|
|
||||||
"stock_uom": "Nos",
|
|
||||||
"name": po.supplied_items[0].name,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"item_code": item_code,
|
|
||||||
"rm_item_code": "Sub Contracted Raw Material 3",
|
|
||||||
"item_name": "_Test Item",
|
|
||||||
"qty": 200,
|
|
||||||
"warehouse": "_Test Warehouse - _TC",
|
|
||||||
"stock_uom": "Nos",
|
|
||||||
"name": po.supplied_items[0].name,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
rm_item_string = json.dumps(rm_items)
|
|
||||||
se = frappe.get_doc(make_rm_stock_entry(po.name, rm_item_string))
|
|
||||||
self.assertEqual(len(se.items), 2)
|
|
||||||
se.items[0].batch_no = ste1.items[0].batch_no
|
|
||||||
se.items[1].batch_no = ste2.items[0].batch_no
|
|
||||||
se.submit()
|
|
||||||
|
|
||||||
supplied_qty = frappe.db.get_value(
|
|
||||||
"Purchase Order Item Supplied",
|
|
||||||
{"parent": po.name, "rm_item_code": "Sub Contracted Raw Material 3"},
|
|
||||||
"supplied_qty",
|
|
||||||
)
|
|
||||||
|
|
||||||
self.assertEqual(supplied_qty, 500.00)
|
|
||||||
|
|
||||||
pr = make_purchase_receipt(po.name)
|
|
||||||
pr.save()
|
|
||||||
self.assertEqual(len(pr.supplied_items), 2)
|
|
||||||
|
|
||||||
for row in pr.supplied_items:
|
|
||||||
self.assertEqual(transferred_batch.get(row.batch_no), row.consumed_qty)
|
|
||||||
|
|
||||||
update_backflush_based_on("BOM")
|
|
||||||
|
|
||||||
pr.delete()
|
|
||||||
se.cancel()
|
|
||||||
ste2.cancel()
|
|
||||||
ste1.cancel()
|
|
||||||
po.cancel()
|
|
||||||
|
|
||||||
def test_po_to_pi_and_po_to_pr_worflow_full(self):
|
def test_po_to_pi_and_po_to_pr_worflow_full(self):
|
||||||
"""Test following behaviour:
|
"""Test following behaviour:
|
||||||
- Create PO
|
- Create PO
|
||||||
@@ -1520,44 +1283,5 @@ def make_purchase_receipt(**args):
|
|||||||
pr.submit()
|
pr.submit()
|
||||||
return pr
|
return pr
|
||||||
|
|
||||||
|
|
||||||
def create_subcontracted_item(**args):
|
|
||||||
from erpnext.manufacturing.doctype.production_plan.test_production_plan import make_bom
|
|
||||||
|
|
||||||
args = frappe._dict(args)
|
|
||||||
|
|
||||||
if not frappe.db.exists("Item", args.item_code):
|
|
||||||
make_item(
|
|
||||||
args.item_code,
|
|
||||||
{
|
|
||||||
"is_stock_item": 1,
|
|
||||||
"is_sub_contracted_item": 1,
|
|
||||||
"has_batch_no": args.get("has_batch_no") or 0,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
if not args.raw_materials:
|
|
||||||
if not frappe.db.exists("Item", "Test Extra Item 1"):
|
|
||||||
make_item(
|
|
||||||
"Test Extra Item 1",
|
|
||||||
{
|
|
||||||
"is_stock_item": 1,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
if not frappe.db.exists("Item", "Test Extra Item 2"):
|
|
||||||
make_item(
|
|
||||||
"Test Extra Item 2",
|
|
||||||
{
|
|
||||||
"is_stock_item": 1,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
args.raw_materials = ["_Test FG Item", "Test Extra Item 1"]
|
|
||||||
|
|
||||||
if not frappe.db.get_value("BOM", {"item": args.item_code}, "name"):
|
|
||||||
make_bom(item=args.item_code, raw_materials=args.get("raw_materials"))
|
|
||||||
|
|
||||||
|
|
||||||
test_dependencies = ["BOM", "Item Price", "Location"]
|
test_dependencies = ["BOM", "Item Price", "Location"]
|
||||||
test_records = frappe.get_test_records("Purchase Receipt")
|
test_records = frappe.get_test_records("Purchase Receipt")
|
||||||
|
|||||||
@@ -83,37 +83,5 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"supplier": "_Test Supplier"
|
"supplier": "_Test Supplier"
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
"buying_price_list": "_Test Price List",
|
|
||||||
"company": "_Test Company",
|
|
||||||
"conversion_rate": 1.0,
|
|
||||||
"currency": "INR",
|
|
||||||
"doctype": "Purchase Receipt",
|
|
||||||
"base_grand_total": 5000.0,
|
|
||||||
"is_subcontracted": 1,
|
|
||||||
"base_net_total": 5000.0,
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"base_amount": 5000.0,
|
|
||||||
"conversion_factor": 1.0,
|
|
||||||
"description": "_Test FG Item",
|
|
||||||
"doctype": "Purchase Receipt Item",
|
|
||||||
"item_code": "_Test FG Item",
|
|
||||||
"item_name": "_Test FG Item",
|
|
||||||
"parentfield": "items",
|
|
||||||
"qty": 10.0,
|
|
||||||
"rate": 500.0,
|
|
||||||
"received_qty": 10.0,
|
|
||||||
"rejected_qty": 0.0,
|
|
||||||
"stock_uom": "_Test UOM",
|
|
||||||
"uom": "_Test UOM",
|
|
||||||
"warehouse": "_Test Warehouse - _TC",
|
|
||||||
"cost_center": "Main - _TC"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"supplier": "_Test Supplier",
|
|
||||||
"supplier_warehouse": "_Test Warehouse - _TC"
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -644,7 +644,8 @@
|
|||||||
"label": "BOM",
|
"label": "BOM",
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"options": "BOM",
|
"options": "BOM",
|
||||||
"print_hide": 1
|
"print_hide": 1,
|
||||||
|
"read_only": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"default": "0",
|
"default": "0",
|
||||||
|
|||||||
Reference in New Issue
Block a user