[Enhancement] Work Order Material Consumption (#13384)
* Work Order Material Consumption * Test cases and other minor fixes * Test cases fixes * Travis Fixes * Work Order Material Consumption Request Changes * Update work_order.js
This commit is contained in:
parent
e9638be032
commit
ad76f9ad70
Binary file not shown.
After Width: | Height: | Size: 112 KiB |
Binary file not shown.
After Width: | Height: | Size: 296 KiB |
BIN
erpnext/docs/assets/img/manufacturing/consumed-qty.png
Normal file
BIN
erpnext/docs/assets/img/manufacturing/consumed-qty.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 145 KiB |
Binary file not shown.
After Width: | Height: | Size: 127 KiB |
Binary file not shown.
After Width: | Height: | Size: 209 KiB |
Binary file not shown.
After Width: | Height: | Size: 134 KiB |
@ -0,0 +1,34 @@
|
||||
#Material consumption
|
||||
|
||||
Material Consumption functionality allows you to have multiple consumption `Stock Entry` against a Work Order. To enable this, go to Manufacturing > Manufacturing Settings.
|
||||
|
||||
<img class="screenshot" alt="Item Alternative" src="{{docs_base_url}}/assets/img/manufacturing/allow-material-consumption.png">
|
||||
|
||||
Once enabled, a `Material Consumption` button will be available in Work Order once started.
|
||||
|
||||
<img class="screenshot" alt="Item Alternative" src="{{docs_base_url}}/assets/img/manufacturing/material-consumption-button.png">
|
||||
|
||||
When button is clicked, it will do the following:
|
||||
|
||||
1. It will create Stock Entry with purpose `Material Consumption for Manufacture`.
|
||||
|
||||
<img class="screenshot" alt="Item Alternative" src="{{docs_base_url}}/assets/img/manufacturing/material-consumption-for-manufacture.png">
|
||||
|
||||
2. If the "Backflush Raw Materials Based On" in the Manufacturing Settings is set to `BOM`, if will propose to consume all required qty for manufacture.
|
||||
3. If the "Backflush Raw Materials Based On" in the Manufacturing Settings is set to `Material Transferred for Manufacture`, if will propose to consume all transferred qty for manufacture.
|
||||
4. Once submitted, it will update `Consumed Qty` column in the Work Order.
|
||||
|
||||
<img class="screenshot" alt="Item Alternative" src="{{docs_base_url}}/assets/img/manufacturing/consumed-qty.png">
|
||||
|
||||
5. In succeeding Material Consumption, it will suggest unconsumed qty.
|
||||
6. Once "Finish" button is clicked in Work Order, it will take into account consumed qty.
|
||||
|
||||
### Validations
|
||||
|
||||
* If "Allow Multiple Material Consumption" is not set in Manufacturing Settings but "Material Consumption for Manufacture" is use in Stock Entry.
|
||||
|
||||
<img class="screenshot" alt="Item Alternative" src="{{docs_base_url}}/assets/img/manufacturing/material-consumption-stock-entry.gif">
|
||||
|
||||
* Cannot cancel "Material Consumption for Manufacture" for completed Work Order.
|
||||
|
||||
<img class="screenshot" alt="Item Alternative" src="{{docs_base_url}}/assets/img/manufacturing/cancel-material-consumption-stock-entry.gif">
|
@ -0,0 +1,5 @@
|
||||
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
frappe.ui.form.on('Manufacturing Settings', {
|
||||
});
|
@ -1,493 +1,539 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
"beta": 0,
|
||||
"creation": "2014-11-27 14:12:07.542534",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "Document",
|
||||
"editable_grid": 0,
|
||||
"engine": "InnoDB",
|
||||
"allow_copy": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
"beta": 0,
|
||||
"creation": "2014-11-27 14:12:07.542534",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "Document",
|
||||
"editable_grid": 0,
|
||||
"engine": "InnoDB",
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "capacity_planning",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Capacity Planning",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "capacity_planning",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Capacity Planning",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"description": "Disables creation of time logs against Work Orders. Operations shall not be tracked against Work Order",
|
||||
"fieldname": "disable_capacity_planning",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Disable Capacity Planning and Time Tracking",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"fieldname": "disable_capacity_planning",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Disable Capacity Planning and Time Tracking",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"description": "Plan time logs outside Workstation Working Hours.",
|
||||
"fieldname": "allow_overtime",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Allow Overtime",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"description": "Plan time logs outside Workstation Working Hours.",
|
||||
"fieldname": "allow_overtime",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Allow Overtime",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "",
|
||||
"fieldname": "allow_production_on_holidays",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Allow Production on Holidays",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "",
|
||||
"fieldname": "allow_production_on_holidays",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Allow Production on Holidays",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "column_break_3",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "column_break_3",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "30",
|
||||
"description": "Try planning operations for X days in advance.",
|
||||
"fieldname": "capacity_planning_for_days",
|
||||
"fieldtype": "Int",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Capacity Planning For (Days)",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "30",
|
||||
"description": "Try planning operations for X days in advance.",
|
||||
"fieldname": "capacity_planning_for_days",
|
||||
"fieldtype": "Int",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Capacity Planning For (Days)",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"description": "Default 10 mins",
|
||||
"fieldname": "mins_between_operations",
|
||||
"fieldtype": "Int",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Time Between Operations (in mins)",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"description": "Default 10 mins",
|
||||
"fieldname": "mins_between_operations",
|
||||
"fieldtype": "Int",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Time Between Operations (in mins)",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "section_break_6",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "section_break_6",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "over_production_allowance_percentage",
|
||||
"fieldtype": "Percent",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Over Production Allowance Percentage",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "over_production_allowance_percentage",
|
||||
"fieldtype": "Percent",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Over Production Allowance Percentage",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "BOM",
|
||||
"fieldname": "backflush_raw_materials_based_on",
|
||||
"fieldtype": "Select",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Backflush Raw Materials Based On",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "BOM\nMaterial Transferred for Manufacture",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "BOM",
|
||||
"fieldname": "backflush_raw_materials_based_on",
|
||||
"fieldtype": "Select",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Backflush Raw Materials Based On",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "BOM\nMaterial Transferred for Manufacture",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"description": "Update BOM cost automatically via Scheduler, based on latest valuation rate / price list rate / last purchase rate of raw materials.",
|
||||
"fieldname": "update_bom_costs_automatically",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Update BOM Cost Automatically",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"description": "Allow multiple Material Consumption against a Work Order",
|
||||
"fieldname": "material_consumption",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Allow Multiple Material Consumption",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "column_break_11",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"description": "Update BOM cost automatically via Scheduler, based on latest valuation rate / price list rate / last purchase rate of raw materials.",
|
||||
"fieldname": "update_bom_costs_automatically",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Update BOM Cost Automatically",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "default_wip_warehouse",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Default Work In Progress Warehouse",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Warehouse",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "column_break_11",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "default_fg_warehouse",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Default Finished Goods Warehouse",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Warehouse",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "default_wip_warehouse",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Default Work In Progress Warehouse",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Warehouse",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "default_fg_warehouse",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Default Finished Goods Warehouse",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Warehouse",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
}
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"icon": "icon-wrench",
|
||||
"idx": 0,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
"is_submittable": 0,
|
||||
"issingle": 1,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"menu_index": 0,
|
||||
"modified": "2018-02-16 13:18:17.964103",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Manufacturing",
|
||||
"name": "Manufacturing Settings",
|
||||
"name_case": "",
|
||||
"owner": "Administrator",
|
||||
],
|
||||
"has_web_view": 0,
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"icon": "icon-wrench",
|
||||
"idx": 0,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
"is_submittable": 0,
|
||||
"issingle": 1,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"menu_index": 0,
|
||||
"modified": "2018-03-28 13:56:31.187520",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Manufacturing",
|
||||
"name": "Manufacturing Settings",
|
||||
"name_case": "",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"amend": 0,
|
||||
"apply_user_permissions": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 0,
|
||||
"email": 0,
|
||||
"export": 0,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 0,
|
||||
"read": 1,
|
||||
"report": 0,
|
||||
"role": "Manufacturing Manager",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"amend": 0,
|
||||
"apply_user_permissions": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 0,
|
||||
"email": 0,
|
||||
"export": 0,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 0,
|
||||
"read": 1,
|
||||
"report": 0,
|
||||
"role": "Manufacturing Manager",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 0,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1,
|
||||
],
|
||||
"quick_entry": 0,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1,
|
||||
"track_seen": 0
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
# See license.txt
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import unittest
|
||||
|
||||
class TestManufacturingSettings(unittest.TestCase):
|
||||
pass
|
@ -60,6 +60,7 @@ class TestWorkOrder(unittest.TestCase):
|
||||
|
||||
def test_over_production(self):
|
||||
from erpnext.manufacturing.doctype.work_order.work_order import StockOverProductionError
|
||||
|
||||
wo_doc = self.check_planned_qty()
|
||||
|
||||
test_stock_entry.make_stock_entry(item_code="_Test Item",
|
||||
@ -300,6 +301,7 @@ def make_wo_order_test_record(**args):
|
||||
wo_order.company = args.company or "_Test Company"
|
||||
wo_order.stock_uom = args.stock_uom or "_Test UOM"
|
||||
wo_order.use_multi_level_bom=0
|
||||
wo_order.skip_transfer=1
|
||||
wo_order.get_items_and_operations_from_bom()
|
||||
|
||||
if args.source_warehouse:
|
||||
|
@ -7,7 +7,7 @@ frappe.ui.form.on("Work Order", {
|
||||
'Timesheet': 'Make Timesheet',
|
||||
'Stock Entry': 'Make Stock Entry',
|
||||
}
|
||||
|
||||
|
||||
// Set query for warehouses
|
||||
frm.set_query("wip_warehouse", function(doc) {
|
||||
return {
|
||||
@ -16,7 +16,7 @@ frappe.ui.form.on("Work Order", {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
frm.set_query("source_warehouse", function() {
|
||||
return {
|
||||
filters: {
|
||||
@ -24,7 +24,7 @@ frappe.ui.form.on("Work Order", {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
frm.set_query("source_warehouse", "required_items", function() {
|
||||
return {
|
||||
filters: {
|
||||
@ -32,7 +32,7 @@ frappe.ui.form.on("Work Order", {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
frm.set_query("fg_warehouse", function() {
|
||||
return {
|
||||
filters: {
|
||||
@ -41,7 +41,7 @@ frappe.ui.form.on("Work Order", {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
frm.set_query("scrap_warehouse", function() {
|
||||
return {
|
||||
filters: {
|
||||
@ -50,7 +50,7 @@ frappe.ui.form.on("Work Order", {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Set query for BOM
|
||||
frm.set_query("bom_no", function() {
|
||||
if (frm.doc.production_item) {
|
||||
@ -60,7 +60,7 @@ frappe.ui.form.on("Work Order", {
|
||||
}
|
||||
} else msgprint(__("Please enter Production Item first"));
|
||||
});
|
||||
|
||||
|
||||
// Set query for FG Item
|
||||
frm.set_query("production_item", function() {
|
||||
return {
|
||||
@ -84,7 +84,7 @@ frappe.ui.form.on("Work Order", {
|
||||
frm.set_indicator_formatter('operation',
|
||||
function(doc) { return (frm.doc.qty==doc.completed_qty) ? "green" : "orange" });
|
||||
},
|
||||
|
||||
|
||||
onload: function(frm) {
|
||||
if (!frm.doc.status)
|
||||
frm.doc.status = 'Draft';
|
||||
@ -122,7 +122,7 @@ frappe.ui.form.on("Work Order", {
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
show_progress: function(frm) {
|
||||
var bars = [];
|
||||
var message = '';
|
||||
@ -156,7 +156,7 @@ frappe.ui.form.on("Work Order", {
|
||||
}
|
||||
frm.dashboard.add_progress(__('Status'), bars, message);
|
||||
},
|
||||
|
||||
|
||||
production_item: function(frm) {
|
||||
if (frm.doc.production_item) {
|
||||
frappe.call({
|
||||
@ -184,13 +184,13 @@ frappe.ui.form.on("Work Order", {
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
project: function(frm) {
|
||||
if(!erpnext.in_production_item_onchange) {
|
||||
frm.trigger("production_item");
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
bom_no: function(frm) {
|
||||
return frm.call({
|
||||
doc: frm.doc,
|
||||
@ -203,7 +203,7 @@ frappe.ui.form.on("Work Order", {
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
use_multi_level_bom: function(frm) {
|
||||
if(frm.doc.bom_no) {
|
||||
frm.trigger("bom_no");
|
||||
@ -213,7 +213,7 @@ frappe.ui.form.on("Work Order", {
|
||||
qty: function(frm) {
|
||||
frm.trigger('bom_no');
|
||||
},
|
||||
|
||||
|
||||
before_submit: function(frm) {
|
||||
frm.toggle_reqd(["fg_warehouse", "wip_warehouse"], true);
|
||||
frm.fields_dict.required_items.grid.toggle_reqd("source_warehouse", true);
|
||||
@ -251,7 +251,7 @@ frappe.ui.form.on("Work Order Item", {
|
||||
item_code: row.item_code,
|
||||
warehouse: row.source_warehouse
|
||||
},
|
||||
callback: function (r) {
|
||||
callback: function (r) {
|
||||
frappe.model.set_value(row.doctype, row.name,
|
||||
"available_qty_at_source_warehouse", r.message);
|
||||
}
|
||||
@ -310,21 +310,42 @@ erpnext.work_order = {
|
||||
}
|
||||
|
||||
if(!frm.doc.skip_transfer){
|
||||
if ((flt(doc.produced_qty) < flt(doc.material_transferred_for_manufacturing))
|
||||
&& frm.doc.status != 'Stopped') {
|
||||
frm.has_finish_btn = true;
|
||||
var finish_btn = frm.add_custom_button(__('Finish'), function() {
|
||||
erpnext.work_order.make_se(frm, 'Manufacture');
|
||||
});
|
||||
// If "Material Consumption is check in Manufacturing Settings, allow Material Consumption
|
||||
frappe.model.get_value('Manufacturing Settings', {'name': 'Manufacturing Settings'}, 'material_consumption', function(d) {
|
||||
if ((flt(doc.produced_qty) < flt(doc.material_transferred_for_manufacturing))
|
||||
&& frm.doc.status != 'Stopped') {
|
||||
frm.has_finish_btn = true;
|
||||
|
||||
if(doc.material_transferred_for_manufacturing==doc.qty) {
|
||||
// all materials transferred for manufacturing, make this primary
|
||||
finish_btn.addClass('btn-primary');
|
||||
if (d.material_consumption == 1) {
|
||||
// Only show "Material Consumption" when required_qty > consumed_qty
|
||||
var counter = 0;
|
||||
var tbl = frm.doc.required_items || [];
|
||||
var tbl_lenght = tbl.length;
|
||||
for (var i = 0, len = tbl_lenght; i < len; i++) {
|
||||
if (flt(frm.doc.required_items[i].required_qty) > flt(frm.doc.required_items[i].consumed_qty)) {
|
||||
counter += 1;
|
||||
}
|
||||
}
|
||||
if (counter > 0) {
|
||||
var consumption_btn = frm.add_custom_button(__('Material Consumption'), function() {
|
||||
erpnext.work_order.make_consumption_se(frm, d.backflush_raw_materials_based_on);
|
||||
});
|
||||
consumption_btn.addClass('btn-primary');
|
||||
}
|
||||
}
|
||||
|
||||
var finish_btn = frm.add_custom_button(__('Finish'), function() {
|
||||
erpnext.work_order.make_se(frm, 'Manufacture');
|
||||
});
|
||||
|
||||
if(doc.material_transferred_for_manufacturing==doc.qty) {
|
||||
// all materials transferred for manufacturing, make this primary
|
||||
finish_btn.addClass('btn-primary');
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
} else {
|
||||
if ((flt(doc.produced_qty) < flt(doc.qty)) && frm.doc.status != 'Stopped') {
|
||||
frm.has_finish_btn = true;
|
||||
var finish_btn = frm.add_custom_button(__('Finish'), function() {
|
||||
erpnext.work_order.make_se(frm, 'Manufacture');
|
||||
});
|
||||
@ -367,7 +388,7 @@ erpnext.work_order = {
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
make_se: function(frm, purpose) {
|
||||
if(!frm.doc.skip_transfer){
|
||||
var max = (purpose === "Manufacture") ?
|
||||
@ -399,7 +420,31 @@ erpnext.work_order = {
|
||||
});
|
||||
}, __("Select Quantity"), __("Make"));
|
||||
},
|
||||
|
||||
|
||||
make_consumption_se: function(frm, backflush_raw_materials_based_on) {
|
||||
if(!frm.doc.skip_transfer){
|
||||
var max = (backflush_raw_materials_based_on === "Material Transferred for Manufacture") ?
|
||||
flt(frm.doc.material_transferred_for_manufacturing) - flt(frm.doc.produced_qty) :
|
||||
flt(frm.doc.qty) - flt(frm.doc.produced_qty);
|
||||
// flt(frm.doc.qty) - flt(frm.doc.material_transferred_for_manufacturing);
|
||||
} else {
|
||||
var max = flt(frm.doc.qty) - flt(frm.doc.produced_qty);
|
||||
}
|
||||
|
||||
frappe.call({
|
||||
method:"erpnext.manufacturing.doctype.work_order.work_order.make_stock_entry",
|
||||
args: {
|
||||
"work_order_id": frm.doc.name,
|
||||
"purpose": "Material Consumption for Manufacture",
|
||||
"qty": max
|
||||
},
|
||||
callback: function(r) {
|
||||
var doclist = frappe.model.sync(r.message);
|
||||
frappe.set_route("Form", doclist[0].doctype, doclist[0].name);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
stop_work_order: function(frm, status) {
|
||||
frappe.call({
|
||||
method: "erpnext.manufacturing.doctype.work_order.work_order.stop_unstop",
|
||||
|
@ -64,7 +64,7 @@ class WorkOrder(Document):
|
||||
so.name, so_item.delivery_date, so.project
|
||||
from
|
||||
`tabSales Order` so, `tabSales Order Item` so_item, `tabPacked Item` packed_item
|
||||
where so.name=%s
|
||||
where so.name=%s
|
||||
and so.name=so_item.parent
|
||||
and so.name=packed_item.parent
|
||||
and so_item.item_code = packed_item.parent_item
|
||||
@ -88,7 +88,7 @@ class WorkOrder(Document):
|
||||
self.wip_warehouse = frappe.db.get_single_value("Manufacturing Settings", "default_wip_warehouse")
|
||||
if not self.fg_warehouse:
|
||||
self.fg_warehouse = frappe.db.get_single_value("Manufacturing Settings", "default_fg_warehouse")
|
||||
|
||||
|
||||
def validate_warehouse_belongs_to_company(self):
|
||||
warehouses = [self.fg_warehouse, self.wip_warehouse]
|
||||
for d in self.get("required_items"):
|
||||
@ -184,7 +184,7 @@ class WorkOrder(Document):
|
||||
and purpose=%s""", (self.name, purpose))[0][0])
|
||||
|
||||
if qty > self.qty:
|
||||
frappe.throw(_("{0} ({1}) cannot be greater than planned quanitity ({2}) in Work Order {3}").format(\
|
||||
frappe.throw(_("{0} ({1}) cannot be greater than planned quantity ({2}) in Work Order {3}").format(\
|
||||
self.meta.get_label(fieldname), qty, self.qty, self.name), StockOverProductionError)
|
||||
|
||||
self.db_set(fieldname, qty)
|
||||
@ -449,6 +449,9 @@ class WorkOrder(Document):
|
||||
# update in bin
|
||||
self.update_reserved_qty_for_production()
|
||||
|
||||
# calculate consumed qty based on submitted stock entries
|
||||
self.update_consumed_qty_for_required_items()
|
||||
|
||||
def update_reserved_qty_for_production(self, items=None):
|
||||
'''update reserved_qty_for_production in bins'''
|
||||
for d in self.required_items:
|
||||
@ -515,6 +518,24 @@ class WorkOrder(Document):
|
||||
|
||||
d.db_set('transferred_qty', flt(transferred_qty), update_modified = False)
|
||||
|
||||
def update_consumed_qty_for_required_items(self):
|
||||
'''update consumed qty from submitted stock entries for that item against
|
||||
the work order'''
|
||||
|
||||
for d in self.required_items:
|
||||
consumed_qty = frappe.db.sql('''select sum(qty)
|
||||
from `tabStock Entry` entry, `tabStock Entry Detail` detail
|
||||
where
|
||||
entry.work_order = %s
|
||||
and (entry.purpose = "Material Consumption for Manufacture"
|
||||
or entry.purpose = "Manufacture")
|
||||
and entry.docstatus = 1
|
||||
and detail.parent = entry.name
|
||||
and detail.item_code = %s''', (self.name, d.item_code))[0][0]
|
||||
|
||||
d.db_set('consumed_qty', flt(consumed_qty), update_modified = False)
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_item_details(item, project = None):
|
||||
res = frappe.db.sql("""
|
||||
@ -600,9 +621,10 @@ def make_stock_entry(work_order_id, purpose, qty=None):
|
||||
else:
|
||||
stock_entry.from_warehouse = wip_warehouse
|
||||
stock_entry.to_warehouse = work_order.fg_warehouse
|
||||
additional_costs = get_additional_costs(work_order, fg_qty=stock_entry.fg_completed_qty)
|
||||
stock_entry.project = work_order.project
|
||||
stock_entry.set("additional_costs", additional_costs)
|
||||
if purpose=="Manufacture":
|
||||
additional_costs = get_additional_costs(work_order, fg_qty=stock_entry.fg_completed_qty)
|
||||
stock_entry.set("additional_costs", additional_costs)
|
||||
|
||||
stock_entry.get_items()
|
||||
return stock_entry.as_dict()
|
||||
@ -668,5 +690,5 @@ def query_sales_order(production_item):
|
||||
select distinct so.name from `tabSales Order` so, `tabPacked Item` pi_item
|
||||
where pi_item.parent=so.name and pi_item.item_code=%s and so.docstatus=1
|
||||
""", (production_item, production_item))
|
||||
|
||||
|
||||
return out
|
||||
|
@ -1,16 +1,16 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
"beta": 0,
|
||||
"creation": "2016-04-18 07:38:26.314642",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"allow_copy": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
"beta": 0,
|
||||
"creation": "2016-04-18 07:38:26.314642",
|
||||
"custom": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"fields": [
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
@ -41,9 +41,9 @@
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
@ -73,9 +73,9 @@
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
@ -103,9 +103,9 @@
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
@ -134,9 +134,9 @@
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
@ -165,9 +165,9 @@
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
@ -196,9 +196,9 @@
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
@ -227,9 +227,9 @@
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
@ -290,39 +290,41 @@
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "column_break_9",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "eval:!parent.skip_transfer",
|
||||
"fieldname": "consumed_qty",
|
||||
"fieldtype": "Float",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Consumed Qty",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 1,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
@ -351,14 +353,14 @@
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "available_qty_at_wip_warehouse",
|
||||
"fieldtype": "Float",
|
||||
@ -398,17 +400,17 @@
|
||||
"max_attachments": 0,
|
||||
"modified": "2018-03-05 13:07:07.530725",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Manufacturing",
|
||||
"module": "Manufacturing",
|
||||
"name": "Work Order Item",
|
||||
"name_case": "",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"quick_entry": 1,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1,
|
||||
"name_case": "",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"quick_entry": 1,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1,
|
||||
"track_seen": 0
|
||||
}
|
@ -95,6 +95,7 @@ frappe.ui.form.on('Stock Entry', {
|
||||
|
||||
refresh: function(frm) {
|
||||
if(!frm.doc.docstatus) {
|
||||
frm.trigger('validate_purpose_consumption');
|
||||
frm.add_custom_button(__('Make Material Request'), function() {
|
||||
frappe.model.with_doctype('Material Request', function() {
|
||||
var mr = frappe.model.get_new_doc('Material Request');
|
||||
@ -168,10 +169,20 @@ frappe.ui.form.on('Stock Entry', {
|
||||
},
|
||||
|
||||
purpose: function(frm) {
|
||||
frm.trigger('validate_purpose_consumption');
|
||||
frm.fields_dict.items.grid.refresh();
|
||||
frm.cscript.toggle_related_fields(frm.doc);
|
||||
},
|
||||
|
||||
validate_purpose_consumption: function(frm) {
|
||||
frappe.model.get_value('Manufacturing Settings', {'name': 'Manufacturing Settings'}, 'material_consumption', function(d) {
|
||||
if (d.material_consumption==0 && frm.doc.purpose=="Material Consumption for Manufacture") {
|
||||
frm.set_value("purpose", 'Manufacture');
|
||||
frappe.throw(__('Material Consumption is not set in Manufacturing Settings.'));
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
company: function(frm) {
|
||||
if(frm.doc.company) {
|
||||
var company_doc = frappe.get_doc(":Company", frm.doc.company);
|
||||
@ -519,11 +530,11 @@ erpnext.stock.StockEntry = erpnext.stock.StockController.extend({
|
||||
}
|
||||
|
||||
this.frm.set_indicator_formatter('item_code',
|
||||
function(doc) {
|
||||
function(doc) {
|
||||
if (!doc.s_warehouse) {
|
||||
return 'blue';
|
||||
} else {
|
||||
return (doc.qty<=doc.actual_qty) ? "green" : "orange"
|
||||
return (doc.qty<=doc.actual_qty) ? "green" : "orange"
|
||||
}
|
||||
})
|
||||
|
||||
@ -592,7 +603,8 @@ erpnext.stock.StockEntry = erpnext.stock.StockController.extend({
|
||||
clean_up: function() {
|
||||
// Clear Work Order record from locals, because it is updated via Stock Entry
|
||||
if(this.frm.doc.work_order &&
|
||||
in_list(["Manufacture", "Material Transfer for Manufacture"], this.frm.doc.purpose)) {
|
||||
in_list(["Manufacture", "Material Transfer for Manufacture", "Material Consumption for Manufacture"],
|
||||
this.frm.doc.purpose)) {
|
||||
frappe.model.remove_from_locals("Work Order",
|
||||
this.frm.doc.work_order);
|
||||
}
|
||||
@ -637,16 +649,17 @@ erpnext.stock.StockEntry = erpnext.stock.StockController.extend({
|
||||
me.frm.set_value("to_warehouse", r.message["wip_warehouse"]);
|
||||
|
||||
|
||||
if (me.frm.doc.purpose == "Manufacture") {
|
||||
if(r.message["additional_costs"].length) {
|
||||
$.each(r.message["additional_costs"], function(i, row) {
|
||||
me.frm.add_child("additional_costs", row);
|
||||
})
|
||||
refresh_field("additional_costs");
|
||||
if (me.frm.doc.purpose == "Manufacture" || me.frm.doc.purpose == "Material Consumption for Manufacture" ) {
|
||||
if (me.frm.doc.purpose == "Manufacture") {
|
||||
if (!me.frm.doc.to_warehouse) me.frm.set_value("to_warehouse", r.message["fg_warehouse"]);
|
||||
if (r.message["additional_costs"].length) {
|
||||
$.each(r.message["additional_costs"], function(i, row) {
|
||||
me.frm.add_child("additional_costs", row);
|
||||
})
|
||||
refresh_field("additional_costs");
|
||||
}
|
||||
}
|
||||
|
||||
if (!me.frm.doc.from_warehouse) me.frm.set_value("from_warehouse", r.message["wip_warehouse"]);
|
||||
if (!me.frm.doc.to_warehouse) me.frm.set_value("to_warehouse", r.message["fg_warehouse"]);
|
||||
}
|
||||
me.get_items()
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -43,6 +43,7 @@ class StockEntry(StockController):
|
||||
self.validate_posting_time()
|
||||
self.validate_purpose()
|
||||
self.validate_item()
|
||||
self.validate_qty()
|
||||
self.set_transfer_qty()
|
||||
self.validate_uom_is_integer("uom", "qty")
|
||||
self.validate_uom_is_integer("stock_uom", "transfer_qty")
|
||||
@ -80,15 +81,26 @@ class StockEntry(StockController):
|
||||
self.update_cost_in_project()
|
||||
|
||||
def on_cancel(self):
|
||||
self.update_stock_ledger()
|
||||
self.update_work_order()
|
||||
|
||||
if self.purchase_order and self.purpose == "Subcontract":
|
||||
self.update_purchase_order_supplied_items()
|
||||
|
||||
if self.work_order and self.purpose == "Material Consumption for Manufacture":
|
||||
self.validate_work_order_status()
|
||||
else:
|
||||
self.update_work_order()
|
||||
|
||||
self.update_stock_ledger()
|
||||
self.make_gl_entries_on_cancel()
|
||||
|
||||
def validate_work_order_status(self):
|
||||
pro_doc = frappe.get_doc("Work Order", self.work_order)
|
||||
if pro_doc.status == 'Completed':
|
||||
frappe.throw(_("Cannot cancel transaction for Completed Work Order."))
|
||||
|
||||
def validate_purpose(self):
|
||||
valid_purposes = ["Material Issue", "Material Receipt", "Material Transfer", "Material Transfer for Manufacture",
|
||||
"Manufacture", "Repack", "Subcontract"]
|
||||
"Manufacture", "Repack", "Subcontract", "Material Consumption for Manufacture"]
|
||||
if self.purpose not in valid_purposes:
|
||||
frappe.throw(_("Purpose must be one of {0}").format(comma_or(valid_purposes)))
|
||||
|
||||
@ -139,11 +151,39 @@ class StockEntry(StockController):
|
||||
frappe.throw(_("Row #{0}: Please specify Serial No for Item {1}").format(item.idx, item.item_code),
|
||||
frappe.MandatoryError)
|
||||
|
||||
def validate_qty(self):
|
||||
manufacture_purpose = ["Manufacture", "Material Consumption for Manufacture"]
|
||||
|
||||
if self.purpose in manufacture_purpose and self.work_order:
|
||||
if not frappe.get_value('Work Order', self.work_order, 'skip_transfer'):
|
||||
item_code = []
|
||||
for item in self.items:
|
||||
if cstr(item.t_warehouse) == '':
|
||||
req_items = frappe.get_all('Work Order Item',
|
||||
filters={'parent': self.work_order, 'item_code': item.item_code}, fields=["item_code"])
|
||||
|
||||
transferred_materials = frappe.db.sql("""
|
||||
select
|
||||
sum(qty) as qty
|
||||
from `tabStock Entry` se,`tabStock Entry Detail` sed
|
||||
where
|
||||
se.name = sed.parent and se.docstatus=1 and
|
||||
(se.purpose='Material Transfer for Manufacture' or se.purpose='Manufacture')
|
||||
and sed.item_code=%s and se.work_order= %s and ifnull(sed.t_warehouse, '') != ''
|
||||
""", (item.item_code, self.work_order), as_dict=1)
|
||||
|
||||
stock_qty = flt(item.qty)
|
||||
trans_qty = flt(transferred_materials[0].qty)
|
||||
if req_items:
|
||||
if stock_qty > trans_qty:
|
||||
item_code.append(item.item_code)
|
||||
|
||||
def validate_warehouse(self):
|
||||
"""perform various (sometimes conditional) validations on warehouse"""
|
||||
|
||||
source_mandatory = ["Material Issue", "Material Transfer", "Subcontract", "Material Transfer for Manufacture"]
|
||||
target_mandatory = ["Material Receipt", "Material Transfer", "Subcontract", "Material Transfer for Manufacture"]
|
||||
source_mandatory = ["Material Issue", "Material Transfer", "Subcontract", "Material Transfer for Manufacture",
|
||||
"Material Consumption for Manufacture"]
|
||||
target_mandatory = ["Material Receipt", "Material Transfer", "Subcontract", "Material Transfer for Manufacture",]
|
||||
|
||||
validate_for_manufacture_repack = any([d.bom_no for d in self.get("items")])
|
||||
|
||||
@ -196,10 +236,11 @@ class StockEntry(StockController):
|
||||
frappe.throw(_("Source and target warehouse cannot be same for row {0}").format(d.idx))
|
||||
|
||||
def validate_work_order(self):
|
||||
if self.purpose in ("Manufacture", "Material Transfer for Manufacture"):
|
||||
if self.purpose in ("Manufacture", "Material Transfer for Manufacture", "Material Consumption for Manufacture"):
|
||||
# check if work order is entered
|
||||
|
||||
if self.purpose=="Manufacture" and self.work_order:
|
||||
if (self.purpose=="Manufacture" or self.purpose=="Material Consumption for Manufacture") \
|
||||
and self.work_order:
|
||||
if not self.fg_completed_qty:
|
||||
frappe.throw(_("For Quantity (Manufactured Qty) is mandatory"))
|
||||
self.check_if_operations_completed()
|
||||
@ -234,8 +275,7 @@ class StockEntry(StockController):
|
||||
where parent in (%s)
|
||||
and item_code = %s
|
||||
and ifnull(s_warehouse,'')='' """ % (", ".join(["%s" * len(other_ste)]), "%s"), args)[0][0]
|
||||
|
||||
if fg_qty_already_entered >= qty:
|
||||
if fg_qty_already_entered and fg_qty_already_entered >= qty:
|
||||
frappe.throw(_("Stock Entries already created for Work Order ")
|
||||
+ self.work_order + ":" + ", ".join(other_ste), DuplicateEntryForWorkOrderError)
|
||||
|
||||
@ -590,8 +630,10 @@ class StockEntry(StockController):
|
||||
self.set_work_order_details()
|
||||
|
||||
if self.bom_no:
|
||||
|
||||
if self.purpose in ["Material Issue", "Material Transfer", "Manufacture", "Repack",
|
||||
"Subcontract", "Material Transfer for Manufacture"]:
|
||||
"Subcontract", "Material Transfer for Manufacture", "Material Consumption for Manufacture"]:
|
||||
|
||||
if self.work_order and self.purpose == "Material Transfer for Manufacture":
|
||||
item_dict = self.get_pending_raw_materials()
|
||||
if self.to_warehouse and self.pro_doc:
|
||||
@ -599,10 +641,15 @@ class StockEntry(StockController):
|
||||
item["to_warehouse"] = self.pro_doc.wip_warehouse
|
||||
self.add_to_stock_entry_detail(item_dict)
|
||||
|
||||
elif self.work_order and self.purpose == "Manufacture" and \
|
||||
elif self.work_order and (self.purpose == "Manufacture" or self.purpose == "Material Consumption for Manufacture") and \
|
||||
frappe.db.get_single_value("Manufacturing Settings", "backflush_raw_materials_based_on")== "Material Transferred for Manufacture":
|
||||
self.get_transfered_raw_materials()
|
||||
|
||||
elif self.work_order and (self.purpose == "Manufacture" or self.purpose == "Material Consumption for Manufacture") and \
|
||||
frappe.db.get_single_value("Manufacturing Settings", "backflush_raw_materials_based_on")== "BOM" and \
|
||||
frappe.db.get_single_value("Manufacturing Settings", "material_consumption")== 1:
|
||||
self.get_unconsumed_raw_materials()
|
||||
|
||||
else:
|
||||
if not self.fg_completed_qty:
|
||||
frappe.throw(_("Manufacturing Quantity is mandatory"))
|
||||
@ -613,7 +660,7 @@ class StockEntry(StockController):
|
||||
if self.purchase_order and self.purpose == "Subcontract":
|
||||
#Get PO Supplied Items Details
|
||||
item_wh = frappe._dict(frappe.db.sql("""
|
||||
select rm_item_code, reserve_warehouse
|
||||
select rm_item_code, reserve_warehouse
|
||||
from `tabPurchase Order` po, `tabPurchase Order Item Supplied` poitemsup
|
||||
where po.name = poitemsup.parent
|
||||
and po.name = %s""",self.purchase_order))
|
||||
@ -726,6 +773,45 @@ class StockEntry(StockController):
|
||||
item.from_warehouse = ""
|
||||
return item_dict
|
||||
|
||||
def get_unconsumed_raw_materials(self):
|
||||
wo = frappe.get_doc("Work Order", self.work_order)
|
||||
wo_items = frappe.get_all('Work Order Item',
|
||||
filters={'parent': self.work_order},
|
||||
fields=["item_code", "required_qty", "consumed_qty"]
|
||||
)
|
||||
|
||||
for item in wo_items:
|
||||
qty = item.required_qty
|
||||
item_account_details = frappe.db.get_value("Item", item.item_code, ["item_name",
|
||||
"description", "stock_uom", "expense_account", "buying_cost_center", "name", "default_warehouse"], as_dict=1)
|
||||
# Take into account consumption if there are any.
|
||||
if self.purpose == 'Manufacture':
|
||||
req_qty_each = flt(item.required_qty / wo.qty)
|
||||
if (flt(item.consumed_qty) != 0):
|
||||
remaining_qty = flt(item.consumed_qty) - (flt(wo.produced_qty) * req_qty_each)
|
||||
exhaust_qty = req_qty_each * wo.produced_qty
|
||||
if remaining_qty > exhaust_qty :
|
||||
if (remaining_qty/(req_qty_each * flt(self.fg_completed_qty))) >= 1:
|
||||
qty =0
|
||||
else:
|
||||
qty = (req_qty_each * flt(self.fg_completed_qty)) - remaining_qty
|
||||
else:
|
||||
qty = req_qty_each * flt(self.fg_completed_qty)
|
||||
|
||||
if qty > 0:
|
||||
self.add_to_stock_entry_detail({
|
||||
item.item_code: {
|
||||
"from_warehouse": wo.wip_warehouse,
|
||||
"to_warehouse": "",
|
||||
"qty": qty,
|
||||
"item_name": item.item_name,
|
||||
"description": item.description,
|
||||
"stock_uom": item_account_details.stock_uom,
|
||||
"expense_account": item_account_details.expense_account,
|
||||
"cost_center": item_account_details.buying_cost_center,
|
||||
}
|
||||
})
|
||||
|
||||
def get_transfered_raw_materials(self):
|
||||
transferred_materials = frappe.db.sql("""
|
||||
select
|
||||
@ -744,7 +830,8 @@ class StockEntry(StockController):
|
||||
from
|
||||
`tabStock Entry` se, `tabStock Entry Detail` sed
|
||||
where
|
||||
se.name = sed.parent and se.docstatus=1 and se.purpose='Manufacture'
|
||||
se.name = sed.parent and se.docstatus=1
|
||||
and (se.purpose='Manufacture' or se.purpose='Material Consumption for Manufacture')
|
||||
and se.work_order= %s and ifnull(sed.s_warehouse, '') != ''
|
||||
group by sed.item_code, sed.s_warehouse
|
||||
""", self.work_order, as_dict=1)
|
||||
@ -755,20 +842,47 @@ class StockEntry(StockController):
|
||||
|
||||
po_qty = frappe.db.sql("""select qty, produced_qty, material_transferred_for_manufacturing from
|
||||
`tabWork Order` where name=%s""", self.work_order, as_dict=1)[0]
|
||||
|
||||
manufacturing_qty = flt(po_qty.qty)
|
||||
produced_qty = flt(po_qty.produced_qty)
|
||||
trans_qty = flt(po_qty.material_transferred_for_manufacturing)
|
||||
|
||||
for item in transferred_materials:
|
||||
qty= item.qty
|
||||
req_items = frappe.get_all('Work Order Item',
|
||||
filters={'parent': self.work_order, 'item_code': item.item_code},
|
||||
fields=["required_qty", "consumed_qty"]
|
||||
)
|
||||
req_qty = flt(req_items[0].required_qty)
|
||||
req_qty_each = flt(req_qty / manufacturing_qty)
|
||||
consumed_qty = flt(req_items[0].consumed_qty)
|
||||
|
||||
if trans_qty and manufacturing_qty >= (produced_qty + flt(self.fg_completed_qty)):
|
||||
if qty >= req_qty:
|
||||
qty = (req_qty/trans_qty) * flt(self.fg_completed_qty)
|
||||
else:
|
||||
qty = qty - consumed_qty
|
||||
|
||||
if self.purpose == 'Manufacture':
|
||||
# If Material Consumption is booked, must pull only remaining components to finish product
|
||||
if consumed_qty != 0:
|
||||
remaining_qty = consumed_qty - (produced_qty * req_qty_each)
|
||||
exhaust_qty = req_qty_each * produced_qty
|
||||
if remaining_qty > exhaust_qty :
|
||||
if (remaining_qty/(req_qty_each * flt(self.fg_completed_qty))) >= 1:
|
||||
qty =0
|
||||
else:
|
||||
qty = (req_qty_each * flt(self.fg_completed_qty)) - remaining_qty
|
||||
else:
|
||||
qty = req_qty_each * flt(self.fg_completed_qty)
|
||||
|
||||
if trans_qty and manufacturing_qty > (produced_qty + flt(self.fg_completed_qty)):
|
||||
qty = (qty/trans_qty) * flt(self.fg_completed_qty)
|
||||
|
||||
elif backflushed_materials.get(item.item_code):
|
||||
for d in backflushed_materials.get(item.item_code):
|
||||
if d.get(item.warehouse):
|
||||
qty-= d.get(item.warehouse)
|
||||
if (qty > req_qty):
|
||||
qty = req_qty
|
||||
qty-= d.get(item.warehouse)
|
||||
|
||||
if qty > 0:
|
||||
self.add_to_stock_entry_detail({
|
||||
@ -841,7 +955,7 @@ class StockEntry(StockController):
|
||||
|
||||
for d in item_dict:
|
||||
stock_uom = item_dict[d].get("stock_uom") or frappe.db.get_value("Item", d, "stock_uom")
|
||||
|
||||
|
||||
se_child = self.append('items')
|
||||
se_child.s_warehouse = item_dict[d].get("from_warehouse")
|
||||
se_child.t_warehouse = item_dict[d].get("to_warehouse")
|
||||
@ -894,7 +1008,7 @@ class StockEntry(StockController):
|
||||
def update_purchase_order_supplied_items(self):
|
||||
#Get PO Supplied Items Details
|
||||
item_wh = frappe._dict(frappe.db.sql("""
|
||||
select rm_item_code, reserve_warehouse
|
||||
select rm_item_code, reserve_warehouse
|
||||
from `tabPurchase Order` po, `tabPurchase Order Item Supplied` poitemsup
|
||||
where po.name = poitemsup.parent
|
||||
and po.name = %s""", self.purchase_order))
|
||||
@ -905,7 +1019,7 @@ class StockEntry(StockController):
|
||||
reserve_warehouse = item_wh.get(item_code)
|
||||
stock_bin = get_bin(item_code, reserve_warehouse)
|
||||
stock_bin.update_reserved_qty_for_sub_contracting()
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def move_sample_to_retention_warehouse(company, items):
|
||||
if isinstance(items, string_types):
|
||||
@ -1075,4 +1189,4 @@ def validate_sample_quantity(item_code, sample_quantity, qty, batch_no = None):
|
||||
frappe.msgprint(_("Maximum Samples - {0} can be retained for Batch {1} and Item {2}.").
|
||||
format(max_retain_qty, batch_no, item_code), alert=True)
|
||||
sample_quantity = qty_diff
|
||||
return sample_quantity
|
||||
return sample_quantity
|
||||
|
@ -575,7 +575,8 @@ class TestStockEntry(unittest.TestCase):
|
||||
"bom_no": bom_no,
|
||||
"qty": 1.0,
|
||||
"stock_uom": "_Test UOM",
|
||||
"wip_warehouse": "_Test Warehouse - _TC"
|
||||
"wip_warehouse": "_Test Warehouse - _TC",
|
||||
"skip_transfer": 1
|
||||
})
|
||||
work_order.insert()
|
||||
work_order.submit()
|
||||
@ -680,6 +681,34 @@ class TestStockEntry(unittest.TestCase):
|
||||
repack.insert()
|
||||
self.assertRaises(frappe.ValidationError, repack.submit)
|
||||
|
||||
def test_material_consumption(self):
|
||||
from erpnext.manufacturing.doctype.work_order.work_order \
|
||||
import make_stock_entry as _make_stock_entry
|
||||
bom_no = frappe.db.get_value("BOM", {"item": "_Test FG Item 2",
|
||||
"is_default": 1, "docstatus": 1}, ["name", "operating_cost"])
|
||||
|
||||
work_order = frappe.new_doc("Work Order")
|
||||
work_order.update({
|
||||
"company": "_Test Company",
|
||||
"fg_warehouse": "_Test Warehouse 1 - _TC",
|
||||
"production_item": "_Test FG Item 2",
|
||||
"bom_no": bom_no,
|
||||
"qty": 4.0,
|
||||
"stock_uom": "_Test UOM",
|
||||
"wip_warehouse": "_Test Warehouse - _TC",
|
||||
"additional_operating_cost": 1000
|
||||
})
|
||||
work_order.insert()
|
||||
work_order.submit()
|
||||
|
||||
make_stock_entry(item_code="_Test Serialized Item With Series", target="_Test Warehouse - _TC", qty=50, basic_rate=100)
|
||||
make_stock_entry(item_code="_Test Item 2", target="_Test Warehouse - _TC", qty=50, basic_rate=20)
|
||||
|
||||
stock_entry = frappe.get_doc(_make_stock_entry(work_order.name, "Material Consumption for Manufacture", 2))
|
||||
self.assertEqual(stock_entry.get("items")[0].qty, 10)
|
||||
self.assertEqual(stock_entry.get("items")[1].qty, 6)
|
||||
|
||||
|
||||
def make_serialized_item(item_code=None, serial_no=None, target_warehouse=None):
|
||||
se = frappe.copy_doc(test_records[0])
|
||||
se.get("items")[0].item_code = item_code or "_Test Serialized Item With Series"
|
||||
|
Loading…
x
Reference in New Issue
Block a user