Merge pull request #38290 from s-aga-r/FIX-36704
feat: auto create PR on SCR submission
diff --git a/erpnext/buying/doctype/buying_settings/buying_settings.json b/erpnext/buying/doctype/buying_settings/buying_settings.json
index 0af93bf..3f8559e 100644
--- a/erpnext/buying/doctype/buying_settings/buying_settings.json
+++ b/erpnext/buying/doctype/buying_settings/buying_settings.json
@@ -29,7 +29,11 @@
"subcontract",
"backflush_raw_materials_of_subcontract_based_on",
"column_break_11",
- "over_transfer_allowance"
+ "over_transfer_allowance",
+ "section_break_xcug",
+ "auto_create_subcontracting_order",
+ "column_break_izrr",
+ "auto_create_purchase_receipt"
],
"fields": [
{
@@ -175,6 +179,28 @@
"label": "Blanket Order Allowance (%)"
},
{
+ "fieldname": "section_break_xcug",
+ "fieldtype": "Section Break"
+ },
+ {
+ "fieldname": "column_break_izrr",
+ "fieldtype": "Column Break"
+ },
+ {
+ "default": "0",
+ "description": "Subcontracting Order (Draft) will be auto-created on submission of Purchase Order.",
+ "fieldname": "auto_create_subcontracting_order",
+ "fieldtype": "Check",
+ "label": "Auto Create Subcontracting Order"
+ },
+ {
+ "default": "0",
+ "description": "Purchase Receipt (Draft) will be auto-created on submission of Subcontracting Receipt.",
+ "fieldname": "auto_create_purchase_receipt",
+ "fieldtype": "Check",
+ "label": "Auto Create Purchase Receipt"
+ },
+ {
"default": "Each Transaction",
"description": "How often should Project be updated of Total Purchase Cost ?",
"fieldname": "project_update_frequency",
@@ -188,7 +214,7 @@
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
- "modified": "2023-11-24 10:55:51.287327",
+ "modified": "2023-11-28 13:01:18.403492",
"modified_by": "Administrator",
"module": "Buying",
"name": "Buying Settings",
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py
index 961697c..f000185 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.py
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.py
@@ -8,7 +8,7 @@
from frappe import _, msgprint
from frappe.desk.notifications import clear_doctype_notifications
from frappe.model.mapper import get_mapped_doc
-from frappe.utils import cint, cstr, flt
+from frappe.utils import cint, cstr, flt, get_link_to_form
from erpnext.accounts.doctype.sales_invoice.sales_invoice import (
unlink_inter_company_doc,
@@ -357,6 +357,8 @@
update_linked_doc(self.doctype, self.name, self.inter_company_order_reference)
+ self.auto_create_subcontracting_order()
+
def on_cancel(self):
self.ignore_linked_doctypes = ("GL Entry", "Payment Ledger Entry")
super(PurchaseOrder, self).on_cancel()
@@ -484,6 +486,11 @@
return result
+ def auto_create_subcontracting_order(self):
+ if self.is_subcontracted and not self.is_old_subcontracting_flow:
+ if frappe.db.get_single_value("Buying Settings", "auto_create_subcontracting_order"):
+ make_subcontracting_order(self.name, save=True, notify=True)
+
def item_last_purchase_rate(name, conversion_rate, item_code, conversion_factor=1.0):
"""get last purchase rate for an item"""
@@ -686,8 +693,30 @@
@frappe.whitelist()
-def make_subcontracting_order(source_name, target_doc=None):
- return get_mapped_subcontracting_order(source_name, target_doc)
+def make_subcontracting_order(
+ source_name, target_doc=None, save=False, submit=False, notify=False
+):
+ target_doc = get_mapped_subcontracting_order(source_name, target_doc)
+
+ if (save or submit) and frappe.has_permission(target_doc.doctype, "create"):
+ target_doc.save()
+
+ if submit and frappe.has_permission(target_doc.doctype, "submit", target_doc):
+ try:
+ target_doc.submit()
+ except Exception as e:
+ target_doc.add_comment("Comment", _("Submit Action Failed") + "<br><br>" + str(e))
+
+ if notify:
+ frappe.msgprint(
+ _("Subcontracting Order {0} created.").format(
+ get_link_to_form(target_doc.doctype, target_doc.name)
+ ),
+ indicator="green",
+ alert=True,
+ )
+
+ return target_doc
def get_mapped_subcontracting_order(source_name, target_doc=None):
@@ -713,7 +742,9 @@
},
"Purchase Order Item": {
"doctype": "Subcontracting Order Service Item",
- "field_map": {},
+ "field_map": {
+ "name": "purchase_order_item",
+ },
"field_no_map": [],
},
},
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order_dashboard.py b/erpnext/buying/doctype/purchase_order/purchase_order_dashboard.py
index 05b5a8e..36fe079 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order_dashboard.py
+++ b/erpnext/buying/doctype/purchase_order/purchase_order_dashboard.py
@@ -22,7 +22,10 @@
"label": _("Reference"),
"items": ["Material Request", "Supplier Quotation", "Project", "Auto Repeat"],
},
- {"label": _("Sub-contracting"), "items": ["Subcontracting Order", "Stock Entry"]},
+ {
+ "label": _("Sub-contracting"),
+ "items": ["Subcontracting Order", "Subcontracting Receipt", "Stock Entry"],
+ },
{"label": _("Internal"), "items": ["Sales Order"]},
],
}
diff --git a/erpnext/buying/doctype/purchase_order/test_purchase_order.py b/erpnext/buying/doctype/purchase_order/test_purchase_order.py
index 0f8574c..f80a00a 100644
--- a/erpnext/buying/doctype/purchase_order/test_purchase_order.py
+++ b/erpnext/buying/doctype/purchase_order/test_purchase_order.py
@@ -981,6 +981,38 @@
self.assertEqual(po.items[0].qty, 30)
self.assertEqual(po.items[0].fg_item_qty, 30)
+ @change_settings("Buying Settings", {"auto_create_subcontracting_order": 1})
+ def test_auto_create_subcontracting_order(self):
+ from erpnext.controllers.tests.test_subcontracting_controller import (
+ make_bom_for_subcontracted_items,
+ make_raw_materials,
+ make_service_items,
+ make_subcontracted_items,
+ )
+
+ make_subcontracted_items()
+ make_raw_materials()
+ make_service_items()
+ make_bom_for_subcontracted_items()
+
+ service_items = [
+ {
+ "warehouse": "_Test Warehouse - _TC",
+ "item_code": "Subcontracted Service Item 7",
+ "qty": 10,
+ "rate": 100,
+ "fg_item": "Subcontracted Item SA7",
+ "fg_item_qty": 10,
+ },
+ ]
+ po = create_purchase_order(
+ rm_items=service_items,
+ is_subcontracted=1,
+ supplier_warehouse="_Test Warehouse 1 - _TC",
+ )
+
+ self.assertTrue(frappe.db.get_value("Subcontracting Order", {"purchase_order": po.name}))
+
def prepare_data_for_internal_transfer():
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_internal_supplier
diff --git a/erpnext/controllers/sales_and_purchase_return.py b/erpnext/controllers/sales_and_purchase_return.py
index e91212b..8e3a15a 100644
--- a/erpnext/controllers/sales_and_purchase_return.py
+++ b/erpnext/controllers/sales_and_purchase_return.py
@@ -391,7 +391,10 @@
if doc.get("discount_amount"):
doc.discount_amount = -1 * source.discount_amount
- if doctype != "Subcontracting Receipt":
+ if doctype == "Subcontracting Receipt":
+ doc.set_warehouse = source.set_warehouse
+ doc.supplier_warehouse = source.supplier_warehouse
+ else:
doc.run_method("calculate_taxes_and_totals")
def update_item(source_doc, target_doc, source_parent):
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js
index 6552cd7..6c9d339 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js
@@ -49,6 +49,14 @@
}
});
+ frm.set_query("subcontracting_receipt", function() {
+ return {
+ filters: {
+ 'docstatus': 1,
+ 'supplier': frm.doc.supplier,
+ }
+ }
+ });
},
onload: function(frm) {
erpnext.queries.setup_queries(frm, "Warehouse", function() {
@@ -114,6 +122,20 @@
erpnext.accounts.dimensions.update_dimension(frm, frm.doctype);
},
+ subcontracting_receipt: (frm) => {
+ if (frm.doc.is_subcontracted === 1 && frm.doc.is_old_subcontracting_flow === 0 && frm.doc.subcontracting_receipt) {
+ frm.set_value('items', null);
+
+ erpnext.utils.map_current_doc({
+ method: 'erpnext.subcontracting.doctype.subcontracting_receipt.subcontracting_receipt.make_purchase_receipt',
+ source_name: frm.doc.subcontracting_receipt,
+ target_doc: frm,
+ freeze: true,
+ freeze_message: __('Mapping Purchase Receipt ...'),
+ });
+ }
+ },
+
toggle_display_account_head: function(frm) {
var enabled = erpnext.is_perpetual_inventory_enabled(frm.doc.company)
frm.fields_dict["items"].grid.set_column_disp(["cost_center"], enabled);
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json
index c8a9e3e..c7ad660 100755
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.json
@@ -16,6 +16,7 @@
"supplier",
"supplier_name",
"supplier_delivery_note",
+ "subcontracting_receipt",
"column_break1",
"posting_date",
"posting_time",
@@ -1236,13 +1237,21 @@
"fieldname": "named_place",
"fieldtype": "Data",
"label": "Named Place"
+ },
+ {
+ "depends_on": "eval: (doc.is_subcontracted && !doc.is_old_subcontracting_flow)",
+ "fieldname": "subcontracting_receipt",
+ "fieldtype": "Link",
+ "label": "Subcontracting Receipt",
+ "options": "Subcontracting Receipt",
+ "search_index": 1
}
],
"icon": "fa fa-truck",
"idx": 261,
"is_submittable": 1,
"links": [],
- "modified": "2023-10-01 21:00:44.556816",
+ "modified": "2023-11-28 13:14:15.243474",
"modified_by": "Administrator",
"module": "Stock",
"name": "Purchase Receipt",
diff --git a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json
index ce2e5d7..a86e63d 100644
--- a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json
+++ b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json
@@ -127,7 +127,8 @@
"section_break_80",
"page_break",
"sales_order",
- "sales_order_item"
+ "sales_order_item",
+ "subcontracting_receipt_item"
],
"fields": [
{
@@ -1086,12 +1087,23 @@
"print_hide": 1,
"read_only": 1,
"search_index": 1
+ },
+ {
+ "fieldname": "subcontracting_receipt_item",
+ "fieldtype": "Data",
+ "hidden": 1,
+ "label": "Subcontracting Receipt Item",
+ "no_copy": 1,
+ "print_hide": 1,
+ "read_only": 1,
+ "report_hide": 1,
+ "search_index": 1
}
],
"idx": 1,
"istable": 1,
"links": [],
- "modified": "2023-11-14 18:38:15.251994",
+ "modified": "2023-11-28 13:37:29.245204",
"modified_by": "Administrator",
"module": "Stock",
"name": "Purchase Receipt Item",
diff --git a/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.py b/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.py
index 70ca1c3..6a65846 100644
--- a/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.py
+++ b/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.py
@@ -159,6 +159,7 @@
)
or item.default_bom
)
+
items.append(
{
"item_code": item.item_code,
@@ -168,7 +169,8 @@
"qty": si.fg_item_qty,
"stock_uom": item.stock_uom,
"bom": bom,
- },
+ "purchase_order_item": si.purchase_order_item,
+ }
)
else:
frappe.throw(
@@ -176,11 +178,12 @@
si.item_name or si.item_code
)
)
- else:
+
+ if items:
for item in items:
self.append("items", item)
- else:
- self.set_missing_values()
+
+ self.set_missing_values()
def update_status(self, status=None, update_modified=True):
if self.docstatus >= 1 and not status:
@@ -222,9 +225,11 @@
def get_mapped_subcontracting_receipt(source_name, target_doc=None):
- def update_item(obj, target, source_parent):
- target.qty = flt(obj.qty) - flt(obj.received_qty)
- target.amount = (flt(obj.qty) - flt(obj.received_qty)) * flt(obj.rate)
+ def update_item(source, target, source_parent):
+ target.purchase_order = source_parent.purchase_order
+ target.purchase_order_item = source.purchase_order_item
+ target.qty = flt(source.qty) - flt(source.received_qty)
+ target.amount = (flt(source.qty) - flt(source.received_qty)) * flt(source.rate)
target_doc = get_mapped_doc(
"Subcontracting Order",
diff --git a/erpnext/subcontracting/doctype/subcontracting_order_item/subcontracting_order_item.json b/erpnext/subcontracting/doctype/subcontracting_order_item/subcontracting_order_item.json
index 46c229b..911e903 100644
--- a/erpnext/subcontracting/doctype/subcontracting_order_item/subcontracting_order_item.json
+++ b/erpnext/subcontracting/doctype/subcontracting_order_item/subcontracting_order_item.json
@@ -45,7 +45,8 @@
"dimension_col_break",
"project",
"section_break_34",
- "page_break"
+ "page_break",
+ "purchase_order_item"
],
"fields": [
{
@@ -332,13 +333,22 @@
"fieldtype": "Link",
"label": "Project",
"options": "Project"
+ },
+ {
+ "fieldname": "purchase_order_item",
+ "fieldtype": "Data",
+ "hidden": 1,
+ "label": "Purchase Order Item",
+ "no_copy": 1,
+ "read_only": 1,
+ "search_index": 1
}
],
"idx": 1,
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
- "modified": "2023-11-14 18:38:37.640677",
+ "modified": "2023-11-23 16:56:22.182698",
"modified_by": "Administrator",
"module": "Subcontracting",
"name": "Subcontracting Order Item",
diff --git a/erpnext/subcontracting/doctype/subcontracting_order_service_item/subcontracting_order_service_item.json b/erpnext/subcontracting/doctype/subcontracting_order_service_item/subcontracting_order_service_item.json
index f213313..dc18543 100644
--- a/erpnext/subcontracting/doctype/subcontracting_order_service_item/subcontracting_order_service_item.json
+++ b/erpnext/subcontracting/doctype/subcontracting_order_service_item/subcontracting_order_service_item.json
@@ -1,131 +1,141 @@
{
- "actions": [],
- "autoname": "hash",
- "creation": "2022-04-01 19:23:05.728354",
- "doctype": "DocType",
- "editable_grid": 1,
- "engine": "InnoDB",
- "field_order": [
- "item_code",
- "column_break_2",
- "item_name",
- "section_break_4",
- "qty",
- "column_break_6",
- "rate",
- "column_break_8",
- "amount",
- "section_break_10",
- "fg_item",
- "column_break_12",
- "fg_item_qty"
- ],
- "fields": [
- {
- "bold": 1,
- "columns": 2,
- "fieldname": "item_code",
- "fieldtype": "Link",
- "in_list_view": 1,
- "label": "Item Code",
- "options": "Item",
- "reqd": 1,
- "search_index": 1
- },
- {
- "fetch_from": "item_code.item_name",
- "fieldname": "item_name",
- "fieldtype": "Data",
- "in_global_search": 1,
- "in_list_view": 1,
- "label": "Item Name",
- "print_hide": 1,
- "reqd": 1
- },
- {
- "bold": 1,
- "columns": 1,
- "fieldname": "qty",
- "fieldtype": "Float",
- "in_list_view": 1,
- "label": "Quantity",
- "print_width": "60px",
- "reqd": 1,
- "width": "60px"
- },
- {
- "bold": 1,
- "columns": 2,
- "fetch_from": "item_code.standard_rate",
- "fetch_if_empty": 1,
- "fieldname": "rate",
- "fieldtype": "Currency",
- "in_list_view": 1,
- "label": "Rate",
- "options": "currency",
- "reqd": 1
- },
- {
- "columns": 2,
- "fieldname": "amount",
- "fieldtype": "Currency",
- "in_list_view": 1,
- "label": "Amount",
- "options": "currency",
- "read_only": 1,
- "reqd": 1
- },
- {
- "fieldname": "fg_item",
- "fieldtype": "Link",
- "label": "Finished Good Item",
- "options": "Item",
- "reqd": 1
- },
- {
- "default": "1",
- "fieldname": "fg_item_qty",
- "fieldtype": "Float",
- "label": "Finished Good Item Quantity",
- "reqd": 1
- },
- {
- "fieldname": "column_break_2",
- "fieldtype": "Column Break"
- },
- {
- "fieldname": "section_break_4",
- "fieldtype": "Section Break"
- },
- {
- "fieldname": "column_break_6",
- "fieldtype": "Column Break"
- },
- {
- "fieldname": "column_break_8",
- "fieldtype": "Column Break"
- },
- {
- "fieldname": "section_break_10",
- "fieldtype": "Section Break"
- },
- {
- "fieldname": "column_break_12",
- "fieldtype": "Column Break"
- }
- ],
- "istable": 1,
- "links": [],
- "modified": "2022-04-07 11:43:43.094867",
- "modified_by": "Administrator",
- "module": "Subcontracting",
- "name": "Subcontracting Order Service Item",
- "naming_rule": "Random",
- "owner": "Administrator",
- "permissions": [],
- "quick_entry": 1,
- "search_fields": "item_name",
- "sort_field": "modified",
- "sort_order": "DESC",
- "states": []
+ "actions": [],
+ "autoname": "hash",
+ "creation": "2022-04-01 19:23:05.728354",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "item_code",
+ "column_break_2",
+ "item_name",
+ "section_break_4",
+ "qty",
+ "column_break_6",
+ "rate",
+ "column_break_8",
+ "amount",
+ "section_break_10",
+ "fg_item",
+ "column_break_12",
+ "fg_item_qty",
+ "purchase_order_item"
+ ],
+ "fields": [
+ {
+ "bold": 1,
+ "columns": 2,
+ "fieldname": "item_code",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Item Code",
+ "options": "Item",
+ "reqd": 1,
+ "search_index": 1
+ },
+ {
+ "fetch_from": "item_code.item_name",
+ "fieldname": "item_name",
+ "fieldtype": "Data",
+ "in_global_search": 1,
+ "in_list_view": 1,
+ "label": "Item Name",
+ "print_hide": 1,
+ "reqd": 1
+ },
+ {
+ "bold": 1,
+ "columns": 1,
+ "fieldname": "qty",
+ "fieldtype": "Float",
+ "in_list_view": 1,
+ "label": "Quantity",
+ "print_width": "60px",
+ "reqd": 1,
+ "width": "60px"
+ },
+ {
+ "bold": 1,
+ "columns": 2,
+ "fetch_from": "item_code.standard_rate",
+ "fetch_if_empty": 1,
+ "fieldname": "rate",
+ "fieldtype": "Currency",
+ "in_list_view": 1,
+ "label": "Rate",
+ "options": "currency",
+ "reqd": 1
+ },
+ {
+ "columns": 2,
+ "fieldname": "amount",
+ "fieldtype": "Currency",
+ "in_list_view": 1,
+ "label": "Amount",
+ "options": "currency",
+ "read_only": 1,
+ "reqd": 1
+ },
+ {
+ "fieldname": "fg_item",
+ "fieldtype": "Link",
+ "label": "Finished Good Item",
+ "options": "Item",
+ "reqd": 1
+ },
+ {
+ "default": "1",
+ "fieldname": "fg_item_qty",
+ "fieldtype": "Float",
+ "label": "Finished Good Item Quantity",
+ "reqd": 1
+ },
+ {
+ "fieldname": "column_break_2",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "section_break_4",
+ "fieldtype": "Section Break"
+ },
+ {
+ "fieldname": "column_break_6",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "column_break_8",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "section_break_10",
+ "fieldtype": "Section Break"
+ },
+ {
+ "fieldname": "column_break_12",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "purchase_order_item",
+ "fieldtype": "Data",
+ "hidden": 1,
+ "label": "Purchase Order Item",
+ "no_copy": 1,
+ "read_only": 1,
+ "search_index": 1
+ }
+ ],
+ "istable": 1,
+ "links": [],
+ "modified": "2023-11-23 17:05:04.561948",
+ "modified_by": "Administrator",
+ "module": "Subcontracting",
+ "name": "Subcontracting Order Service Item",
+ "naming_rule": "Random",
+ "owner": "Administrator",
+ "permissions": [],
+ "quick_entry": 1,
+ "search_fields": "item_name",
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "states": []
}
\ No newline at end of file
diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.js b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.js
index 36001eb..575c4ed 100644
--- a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.js
+++ b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.js
@@ -11,6 +11,10 @@
frm.get_field('supplied_items').grid.cannot_add_rows = true;
frm.get_field('supplied_items').grid.only_sortable();
frm.trigger('set_queries');
+
+ frm.custom_make_buttons = {
+ 'Purchase Receipt': 'Purchase Receipt',
+ }
},
on_submit(frm) {
@@ -24,64 +28,75 @@
},
refresh: (frm) => {
- if (frm.doc.docstatus > 0) {
+ if (frm.doc.docstatus === 1) {
frm.add_custom_button(__('Stock Ledger'), () => {
- frappe.route_options = {
- voucher_no: frm.doc.name,
- from_date: frm.doc.posting_date,
- to_date: moment(frm.doc.modified).format('YYYY-MM-DD'),
- company: frm.doc.company,
- show_cancelled_entries: frm.doc.docstatus === 2
- }
- frappe.set_route('query-report', 'Stock Ledger');
- }, __('View'));
+ frappe.route_options = {
+ voucher_no: frm.doc.name,
+ from_date: frm.doc.posting_date,
+ to_date: moment(frm.doc.modified).format('YYYY-MM-DD'),
+ company: frm.doc.company,
+ show_cancelled_entries: frm.doc.docstatus === 2
+ }
+ frappe.set_route('query-report', 'Stock Ledger');
+ }, __('View'));
frm.add_custom_button(__('Accounting Ledger'), () => {
- frappe.route_options = {
- voucher_no: frm.doc.name,
- from_date: frm.doc.posting_date,
- to_date: moment(frm.doc.modified).format('YYYY-MM-DD'),
- company: frm.doc.company,
- group_by: 'Group by Voucher (Consolidated)',
- show_cancelled_entries: frm.doc.docstatus === 2
- }
- frappe.set_route('query-report', 'General Ledger');
- }, __('View'));
+ frappe.route_options = {
+ voucher_no: frm.doc.name,
+ from_date: frm.doc.posting_date,
+ to_date: moment(frm.doc.modified).format('YYYY-MM-DD'),
+ company: frm.doc.company,
+ group_by: 'Group by Voucher (Consolidated)',
+ show_cancelled_entries: frm.doc.docstatus === 2
+ }
+ frappe.set_route('query-report', 'General Ledger');
+ }, __('View'));
+
+ if (frm.doc.is_return === 0) {
+ frm.add_custom_button(__('Purchase Receipt'), () => {
+ frappe.model.open_mapped_doc({
+ method: 'erpnext.subcontracting.doctype.subcontracting_receipt.subcontracting_receipt.make_purchase_receipt',
+ frm: frm,
+ freeze: true,
+ freeze_message: __('Creating Purchase Receipt ...')
+ });
+ }, __('Create'));
+ }
}
if (!frm.doc.is_return && frm.doc.docstatus === 1 && frm.doc.per_returned < 100) {
frm.add_custom_button(__('Subcontract Return'), () => {
- frappe.model.open_mapped_doc({
- method: 'erpnext.subcontracting.doctype.subcontracting_receipt.subcontracting_receipt.make_subcontract_return',
- frm: frm
- });
- }, __('Create'));
+ frappe.model.open_mapped_doc({
+ method: 'erpnext.subcontracting.doctype.subcontracting_receipt.subcontracting_receipt.make_subcontract_return',
+ frm: frm
+ });
+ }, __('Create'));
frm.page.set_inner_btn_group_as_primary(__('Create'));
}
if (frm.doc.docstatus === 0) {
frm.add_custom_button(__('Subcontracting Order'), () => {
- if (!frm.doc.supplier) {
- frappe.throw({
- title: __('Mandatory'),
- message: __('Please Select a Supplier')
- });
- }
-
- erpnext.utils.map_current_doc({
- method: 'erpnext.subcontracting.doctype.subcontracting_order.subcontracting_order.make_subcontracting_receipt',
- source_doctype: 'Subcontracting Order',
- target: frm,
- setters: {
- supplier: frm.doc.supplier,
- },
- get_query_filters: {
- docstatus: 1,
- per_received: ['<', 100],
- company: frm.doc.company
- }
+ if (!frm.doc.supplier) {
+ frappe.throw({
+ title: __('Mandatory'),
+ message: __('Please Select a Supplier')
});
- }, __('Get Items From'));
+ }
+
+ erpnext.utils.map_current_doc({
+ method: 'erpnext.subcontracting.doctype.subcontracting_order.subcontracting_order.make_subcontracting_receipt',
+ source_doctype: 'Subcontracting Order',
+ target: frm,
+ setters: {
+ supplier: frm.doc.supplier,
+ },
+ get_query_filters: {
+ docstatus: 1,
+ per_received: ['<', 100],
+ company: frm.doc.company
+ }
+ });
+ }, __('Get Items From'));
frm.fields_dict.supplied_items.grid.update_docfield_property('consumed_qty', 'read_only', frm.doc.__onload && frm.doc.__onload.backflush_based_on === 'BOM');
}
diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py
index ae64cc6..6df9129 100644
--- a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py
+++ b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py
@@ -3,7 +3,8 @@
import frappe
from frappe import _
-from frappe.utils import cint, flt, getdate, nowdate
+from frappe.model.mapper import get_mapped_doc
+from frappe.utils import cint, flt, get_link_to_form, getdate, nowdate
import erpnext
from erpnext.accounts.utils import get_account_currency
@@ -80,6 +81,7 @@
self.make_gl_entries()
self.repost_future_sle_and_gle()
self.update_status()
+ self.auto_create_purchase_receipt()
def on_update(self):
for table_field in ["items", "supplied_items"]:
@@ -528,9 +530,102 @@
+ "\n".join(warehouse_with_no_account)
)
+ def auto_create_purchase_receipt(self):
+ if frappe.db.get_single_value("Buying Settings", "auto_create_purchase_receipt"):
+ make_purchase_receipt(self, save=True, notify=True)
+
@frappe.whitelist()
def make_subcontract_return(source_name, target_doc=None):
from erpnext.controllers.sales_and_purchase_return import make_return_doc
return make_return_doc("Subcontracting Receipt", source_name, target_doc)
+
+
+@frappe.whitelist()
+def make_purchase_receipt(source_name, target_doc=None, save=False, submit=False, notify=False):
+ if isinstance(source_name, str):
+ source_doc = frappe.get_doc("Subcontracting Receipt", source_name)
+ else:
+ source_doc = source_name
+
+ if not source_doc.is_return:
+ if not target_doc:
+ target_doc = frappe.new_doc("Purchase Receipt")
+ target_doc.is_subcontracted = 1
+ target_doc.is_old_subcontracting_flow = 0
+
+ target_doc = get_mapped_doc(
+ "Subcontracting Receipt",
+ source_doc.name,
+ {
+ "Subcontracting Receipt": {
+ "doctype": "Purchase Receipt",
+ "field_map": {
+ "posting_date": "posting_date",
+ "posting_time": "posting_time",
+ "name": "subcontracting_receipt",
+ "supplier_warehouse": "supplier_warehouse",
+ },
+ "field_no_map": ["total_qty", "total"],
+ },
+ },
+ target_doc,
+ ignore_child_tables=True,
+ )
+
+ target_doc.currency = frappe.get_cached_value("Company", target_doc.company, "default_currency")
+
+ po_items_details = {}
+ for item in source_doc.items:
+ if item.purchase_order and item.purchase_order_item:
+ if item.purchase_order not in po_items_details:
+ po_doc = frappe.get_doc("Purchase Order", item.purchase_order)
+ po_items_details[item.purchase_order] = {po_item.name: po_item for po_item in po_doc.items}
+
+ if po_item := po_items_details[item.purchase_order].get(item.purchase_order_item):
+ conversion_factor = flt(po_item.qty) / flt(po_item.fg_item_qty)
+ item_row = {
+ "item_code": po_item.item_code,
+ "item_name": po_item.item_name,
+ "conversion_factor": conversion_factor,
+ "qty": flt(item.qty) * conversion_factor,
+ "rejected_qty": flt(item.rejected_qty) * conversion_factor,
+ "uom": po_item.uom,
+ "rate": po_item.rate,
+ "warehouse": item.warehouse,
+ "rejected_warehouse": item.rejected_warehouse,
+ "purchase_order": item.purchase_order,
+ "purchase_order_item": item.purchase_order_item,
+ "subcontracting_receipt_item": item.name,
+ }
+ target_doc.append("items", item_row)
+
+ if not target_doc.items:
+ frappe.throw(
+ _("Purchase Order Item reference is missing in Subcontracting Receipt {0}").format(
+ source_doc.name
+ )
+ )
+
+ target_doc.set_missing_values()
+
+ if (save or submit) and frappe.has_permission(target_doc.doctype, "create"):
+ target_doc.save()
+
+ if submit and frappe.has_permission(target_doc.doctype, "submit", target_doc):
+ try:
+ target_doc.submit()
+ except Exception as e:
+ target_doc.add_comment("Comment", _("Submit Action Failed") + "<br><br>" + str(e))
+
+ if notify:
+ frappe.msgprint(
+ _("Purchase Receipt {0} created.").format(
+ get_link_to_form(target_doc.doctype, target_doc.name)
+ ),
+ indicator="green",
+ alert=True,
+ )
+
+ return target_doc
diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt_dashboard.py b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt_dashboard.py
index deb8342..6b67a16 100644
--- a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt_dashboard.py
+++ b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt_dashboard.py
@@ -3,17 +3,27 @@
def get_data():
return {
- "fieldname": "subcontracting_receipt_no",
+ "fieldname": "subcontracting_receipt",
"non_standard_fieldnames": {
"Subcontracting Receipt": "return_against",
},
"internal_links": {
"Subcontracting Order": ["items", "subcontracting_order"],
+ "Purchase Order": ["items", "purchase_order"],
"Project": ["items", "project"],
"Quality Inspection": ["items", "quality_inspection"],
},
"transactions": [
- {"label": _("Reference"), "items": ["Subcontracting Order", "Quality Inspection", "Project"]},
+ {
+ "label": _("Reference"),
+ "items": [
+ "Purchase Order",
+ "Purchase Receipt",
+ "Subcontracting Order",
+ "Quality Inspection",
+ "Project",
+ ],
+ },
{"label": _("Returns"), "items": ["Subcontracting Receipt"]},
],
}
diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt/test_subcontracting_receipt.py b/erpnext/subcontracting/doctype/subcontracting_receipt/test_subcontracting_receipt.py
index f0e4e00..1d007fe 100644
--- a/erpnext/subcontracting/doctype/subcontracting_receipt/test_subcontracting_receipt.py
+++ b/erpnext/subcontracting/doctype/subcontracting_receipt/test_subcontracting_receipt.py
@@ -5,7 +5,7 @@
import copy
import frappe
-from frappe.tests.utils import FrappeTestCase
+from frappe.tests.utils import FrappeTestCase, change_settings
from frappe.utils import add_days, cint, cstr, flt, nowtime, today
import erpnext
@@ -953,6 +953,33 @@
scr.submit()
+ @change_settings("Buying Settings", {"auto_create_purchase_receipt": 1})
+ def test_auto_create_purchase_receipt(self):
+ fg_item = "Subcontracted Item SA1"
+ service_items = [
+ {
+ "warehouse": "_Test Warehouse - _TC",
+ "item_code": "Subcontracted Service Item 1",
+ "qty": 5,
+ "rate": 100,
+ "fg_item": fg_item,
+ "fg_item_qty": 5,
+ },
+ ]
+ sco = get_subcontracting_order(service_items=service_items)
+ rm_items = get_rm_items(sco.supplied_items)
+ itemwise_details = make_stock_in_entry(rm_items=rm_items)
+ make_stock_transfer_entry(
+ sco_no=sco.name,
+ rm_items=rm_items,
+ itemwise_details=copy.deepcopy(itemwise_details),
+ )
+ scr = make_subcontracting_receipt(sco.name)
+ scr.save()
+ scr.submit()
+
+ self.assertTrue(frappe.db.get_value("Purchase Receipt", {"subcontracting_receipt": scr.name}))
+
def make_return_subcontracting_receipt(**args):
args = frappe._dict(args)
diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt_item/subcontracting_receipt_item.json b/erpnext/subcontracting/doctype/subcontracting_receipt_item/subcontracting_receipt_item.json
index 26a29dd..35a79a9 100644
--- a/erpnext/subcontracting/doctype/subcontracting_receipt_item/subcontracting_receipt_item.json
+++ b/erpnext/subcontracting/doctype/subcontracting_receipt_item/subcontracting_receipt_item.json
@@ -63,7 +63,9 @@
"dimension_col_break",
"project",
"section_break_80",
- "page_break"
+ "page_break",
+ "purchase_order",
+ "purchase_order_item"
],
"fields": [
{
@@ -517,12 +519,31 @@
"label": "Reference Name",
"no_copy": 1,
"read_only": 1
+ },
+ {
+ "fieldname": "purchase_order_item",
+ "fieldtype": "Data",
+ "hidden": 1,
+ "label": "Purchase Order Item",
+ "no_copy": 1,
+ "read_only": 1,
+ "search_index": 1
+ },
+ {
+ "fieldname": "purchase_order",
+ "fieldtype": "Link",
+ "hidden": 1,
+ "label": "Purchase Order",
+ "no_copy": 1,
+ "options": "Purchase Order",
+ "read_only": 1,
+ "search_index": 1
}
],
"idx": 1,
"istable": 1,
"links": [],
- "modified": "2023-11-14 18:38:26.459669",
+ "modified": "2023-11-23 17:38:55.134685",
"modified_by": "Administrator",
"module": "Subcontracting",
"name": "Subcontracting Receipt Item",