Merge branch 'staging-fixes' into staging
This commit is contained in:
commit
25a74b8283
@ -5,7 +5,7 @@ import frappe
|
||||
from erpnext.hooks import regional_overrides
|
||||
from frappe.utils import getdate
|
||||
|
||||
__version__ = '10.1.70'
|
||||
__version__ = '10.1.71'
|
||||
|
||||
def get_default_company(user=None):
|
||||
'''Get default company for user'''
|
||||
|
@ -514,25 +514,9 @@ frappe.ui.form.on("Purchase Invoice", {
|
||||
me.frm.set_df_property("apply_tds", "read_only", 1);
|
||||
}
|
||||
|
||||
$.each(["warehouse", "rejected_warehouse"], function(i, field) {
|
||||
frm.set_query(field, "items", function() {
|
||||
return {
|
||||
filters: [
|
||||
["Warehouse", "company", "in", ["", cstr(frm.doc.company)]],
|
||||
["Warehouse", "is_group", "=", 0]
|
||||
]
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
frm.set_query("supplier_warehouse", function() {
|
||||
return {
|
||||
filters: [
|
||||
["Warehouse", "company", "in", ["", cstr(frm.doc.company)]],
|
||||
["Warehouse", "is_group", "=", 0]
|
||||
]
|
||||
}
|
||||
})
|
||||
erpnext.queries.setup_queries(frm, "Warehouse", function() {
|
||||
return erpnext.queries.warehouse(frm.doc);
|
||||
});
|
||||
},
|
||||
|
||||
is_subcontracted: function(frm) {
|
||||
|
@ -1,5 +1,6 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_events_in_timeline": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 1,
|
||||
"allow_rename": 0,
|
||||
@ -1485,6 +1486,207 @@
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "sec_warehouse",
|
||||
"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_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "update_stock",
|
||||
"fieldname": "set_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": "Set Accepted Warehouse",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Warehouse",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 1,
|
||||
"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_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "update_stock",
|
||||
"description": "Warehouse where you are maintaining stock of rejected items",
|
||||
"fieldname": "rejected_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": "Rejected Warehouse",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"options": "Warehouse",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 1,
|
||||
"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_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "col_break_warehouse",
|
||||
"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_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "No",
|
||||
"fieldname": "is_subcontracted",
|
||||
"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": "Raw Materials Supplied",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "No\nYes",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 1,
|
||||
"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_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "eval:doc.is_subcontracted==\"Yes\"",
|
||||
"fieldname": "supplier_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": "Supplier Warehouse",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"options": "Warehouse",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 1,
|
||||
"print_hide_if_no_value": 0,
|
||||
"print_width": "50px",
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0,
|
||||
"width": "50px"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
@ -1551,6 +1753,38 @@
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "scan_barcode",
|
||||
"fieldtype": "Data",
|
||||
"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": "Scan Barcode",
|
||||
"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": 1,
|
||||
"allow_in_quick_entry": 0,
|
||||
@ -1585,6 +1819,73 @@
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"collapsible_depends_on": "supplied_items",
|
||||
"columns": 0,
|
||||
"depends_on": "",
|
||||
"fieldname": "raw_materials_supplied",
|
||||
"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": "Raw Materials Supplied",
|
||||
"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_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "supplied_items",
|
||||
"fieldtype": "Table",
|
||||
"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": "Supplied Items",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Purchase Receipt Item Supplied",
|
||||
"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_in_quick_entry": 0,
|
||||
@ -3723,140 +4024,6 @@
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "raw_materials_supplied",
|
||||
"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": "Raw Materials Supplied",
|
||||
"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_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "No",
|
||||
"fieldname": "is_subcontracted",
|
||||
"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": "Raw Materials Supplied",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "No\nYes",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 1,
|
||||
"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_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "supplier_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": "Supplier Warehouse",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"options": "Warehouse",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 1,
|
||||
"print_hide_if_no_value": 0,
|
||||
"print_width": "50px",
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0,
|
||||
"width": "50px"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "supplied_items",
|
||||
"fieldtype": "Table",
|
||||
"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": "Supplied Items",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Purchase Receipt Item Supplied",
|
||||
"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_in_quick_entry": 0,
|
||||
@ -4351,40 +4518,6 @@
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"description": "Warehouse where you are maintaining stock of rejected items",
|
||||
"fieldname": "rejected_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": "Rejected Warehouse",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"options": "Warehouse",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 1,
|
||||
"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_in_quick_entry": 0,
|
||||
@ -4593,7 +4726,7 @@
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"menu_index": 0,
|
||||
"modified": "2018-09-11 14:44:31.220376",
|
||||
"modified": "2018-11-13 19:55:58.018816",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Purchase Invoice",
|
||||
|
@ -165,9 +165,12 @@ def get_items_list(pos_profile, company):
|
||||
select
|
||||
i.name, i.item_code, i.item_name, i.description, i.item_group, i.has_batch_no,
|
||||
i.has_serial_no, i.is_stock_item, i.brand, i.stock_uom, i.image,
|
||||
id.expense_account, id.selling_cost_center, id.default_warehouse
|
||||
id.expense_account, id.selling_cost_center, id.default_warehouse,
|
||||
i.sales_uom, c.conversion_factor
|
||||
from
|
||||
`tabItem` i LEFT JOIN `tabItem Default` id ON id.parent = i.name and id.company = %s
|
||||
`tabItem` i
|
||||
left join `tabItem Default` id on id.parent = i.name and id.company = %s
|
||||
left join `tabUOM Conversion Detail` c on i.name = c.parent and i.sales_uom = c.uom
|
||||
where
|
||||
i.disabled = 0 and i.has_variants = 0 and i.is_sales_item = 1
|
||||
{cond}
|
||||
@ -534,6 +537,7 @@ def validate_item(doc):
|
||||
item_doc.item_name = item.get('item_name')
|
||||
item_doc.description = item.get('description')
|
||||
item_doc.stock_uom = item.get('stock_uom')
|
||||
item_doc.uom = item.get('uom')
|
||||
item_doc.item_group = item.get('item_group')
|
||||
item_doc.append('item_defaults', {
|
||||
"company": doc.get("company"),
|
||||
|
@ -939,7 +939,9 @@ var set_primary_action= function(frm, dialog, $results, invoice_healthcare_servi
|
||||
dialog.set_primary_action(__('Add'), function() {
|
||||
let checked_values = get_checked_values($results);
|
||||
if(checked_values.length > 0){
|
||||
frm.set_value("patient", dialog.fields_dict.patient.input.value);
|
||||
if(invoice_healthcare_services) {
|
||||
frm.set_value("patient", dialog.fields_dict.patient.input.value);
|
||||
}
|
||||
frm.set_value("items", []);
|
||||
add_to_item_line(frm, checked_values, invoice_healthcare_services);
|
||||
dialog.hide();
|
||||
|
@ -1,5 +1,6 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_events_in_timeline": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 1,
|
||||
"allow_rename": 0,
|
||||
@ -1585,6 +1586,71 @@
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "sec_warehouse",
|
||||
"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_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "update_stock",
|
||||
"fieldname": "set_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": "Set Source Warehouse",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Warehouse",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 1,
|
||||
"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_in_quick_entry": 0,
|
||||
@ -1651,6 +1717,38 @@
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "scan_barcode",
|
||||
"fieldtype": "Data",
|
||||
"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": "Scan Barcode",
|
||||
"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": 1,
|
||||
"allow_in_quick_entry": 0,
|
||||
@ -5546,7 +5644,7 @@
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"menu_index": 0,
|
||||
"modified": "2018-09-07 14:24:58.854289",
|
||||
"modified": "2018-11-12 20:01:21.289303",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Sales Invoice",
|
||||
|
@ -1407,6 +1407,8 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
|
||||
this.child.item_code = this.items[0].item_code;
|
||||
this.child.item_name = this.items[0].item_name;
|
||||
this.child.stock_uom = this.items[0].stock_uom;
|
||||
this.child.uom = this.items[0].sales_uom || this.items[0].stock_uom;
|
||||
this.child.conversion_factor = this.items[0].conversion_factor || 1;
|
||||
this.child.brand = this.items[0].brand;
|
||||
this.child.description = this.items[0].description || this.items[0].item_name;
|
||||
this.child.discount_percentage = 0.0;
|
||||
@ -1416,8 +1418,8 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
|
||||
this.child.income_account = this.pos_profile_data['income_account'] || this.items[0].income_account;
|
||||
this.child.warehouse = (this.item_serial_no[this.child.item_code]
|
||||
? this.item_serial_no[this.child.item_code][1] : (this.pos_profile_data['warehouse'] || this.items[0].default_warehouse));
|
||||
this.child.price_list_rate = flt(this.price_list_data[this.child.item_code], 9) / flt(this.frm.doc.conversion_rate, 9);
|
||||
this.child.rate = flt(this.price_list_data[this.child.item_code], 9) / flt(this.frm.doc.conversion_rate, 9);
|
||||
this.child.price_list_rate = flt(this.price_list_data[this.child.item_code] * this.child.conversion_factor, 9) / flt(this.frm.doc.conversion_rate, 9);
|
||||
this.child.rate = flt(this.price_list_data[this.child.item_code] * this.child.conversion_factor, 9) / flt(this.frm.doc.conversion_rate, 9);
|
||||
this.child.actual_qty = me.get_actual_qty(this.items[0]);
|
||||
this.child.amount = flt(this.child.qty) * flt(this.child.rate);
|
||||
this.child.batch_no = this.item_batch_no[this.child.item_code];
|
||||
|
@ -196,8 +196,9 @@ frappe.query_reports["General Ledger"] = {
|
||||
"fieldname":"group_by",
|
||||
"label": __("Group by"),
|
||||
"fieldtype": "Select",
|
||||
"options": ["", "Group by Voucher", "Group by Account", "Group by Party"],
|
||||
"default": "Group by Voucher"
|
||||
"options": ["", __("Group by Voucher"), __("Group by Voucher (Consolidated)"),
|
||||
__("Group by Account"), __("Group by Party")],
|
||||
"default": __("Group by Voucher (Consolidated)")
|
||||
},
|
||||
{
|
||||
"fieldname":"tax_id",
|
||||
|
@ -16,6 +16,8 @@ def execute(filters=None):
|
||||
return [], []
|
||||
|
||||
account_details = {}
|
||||
if not filters.get("group_by"):
|
||||
filters['group_by'] = _('Group by Voucher (Consolidated)')
|
||||
|
||||
if filters and filters.get('print_in_account_currency') and \
|
||||
not filters.get('account'):
|
||||
@ -48,11 +50,12 @@ def validate_filters(filters, account_details):
|
||||
if filters.get("account") and not account_details.get(filters.account):
|
||||
frappe.throw(_("Account {0} does not exists").format(filters.account))
|
||||
|
||||
if (filters.get("account") and filters.get("group_by") == 'Group by Account'
|
||||
if (filters.get("account") and filters.get("group_by") == _('Group by Account')
|
||||
and account_details[filters.account].is_group == 0):
|
||||
frappe.throw(_("Can not filter based on Account, if grouped by Account"))
|
||||
|
||||
if (filters.get("voucher_no") and filters.get("group_by") == 'Group by Voucher'):
|
||||
if (filters.get("voucher_no")
|
||||
and filters.get("group_by") in [_('Group by Voucher'), _('Group by Voucher (Consolidated)')]):
|
||||
frappe.throw(_("Can not filter based on Voucher No, if grouped by Voucher"))
|
||||
|
||||
if filters.from_date > filters.to_date:
|
||||
@ -114,30 +117,37 @@ def get_result(filters, account_details):
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def get_gl_entries(filters):
|
||||
currency_map = get_currency(filters)
|
||||
select_fields = """, debit_in_account_currency,
|
||||
credit_in_account_currency""" \
|
||||
select_fields = """, debit, credit, debit_in_account_currency,
|
||||
credit_in_account_currency """
|
||||
|
||||
order_by_fields = "posting_date, account"
|
||||
if filters.get("group_by") == "Group by Voucher":
|
||||
order_by_fields = "posting_date, voucher_type, voucher_no"
|
||||
group_by_statement = ''
|
||||
order_by_statement = "order by posting_date, account"
|
||||
|
||||
if filters.get("group_by") == _("Group by Voucher"):
|
||||
order_by_statement = "order by posting_date, voucher_type, voucher_no"
|
||||
|
||||
if filters.get("group_by") == _("Group by Voucher (Consolidated)"):
|
||||
group_by_statement = "group by voucher_type, voucher_no, account, cost_center"
|
||||
select_fields = """, sum(debit) as debit, sum(credit) as credit,
|
||||
sum(debit_in_account_currency) as debit_in_account_currency,
|
||||
sum(credit_in_account_currency) as credit_in_account_currency"""
|
||||
|
||||
gl_entries = frappe.db.sql(
|
||||
"""
|
||||
select
|
||||
posting_date, account, party_type, party,
|
||||
debit, credit,
|
||||
voucher_type, voucher_no, cost_center, project,
|
||||
against_voucher_type, against_voucher, account_currency,
|
||||
remarks, against, is_opening {select_fields}
|
||||
from `tabGL Entry`
|
||||
where company=%(company)s {conditions}
|
||||
order by {order_by_fields}
|
||||
where company=%(company)s {conditions} {group_by_statement}
|
||||
{order_by_statement}
|
||||
""".format(
|
||||
select_fields=select_fields, conditions=get_conditions(filters),
|
||||
order_by_fields=order_by_fields
|
||||
group_by_statement=group_by_statement,
|
||||
order_by_statement=order_by_statement
|
||||
),
|
||||
filters, as_dict=1)
|
||||
|
||||
@ -204,13 +214,13 @@ def get_data_with_opening_closing(filters, account_details, gl_entries):
|
||||
# Opening for filtered account
|
||||
data.append(totals.opening)
|
||||
|
||||
if filters.get("group_by"):
|
||||
if filters.get("group_by") != _('Group by Voucher (Consolidated)'):
|
||||
for acc, acc_dict in iteritems(gle_map):
|
||||
# acc
|
||||
if acc_dict.entries:
|
||||
# opening
|
||||
data.append({})
|
||||
if filters.get("group_by") != "Group by Voucher":
|
||||
if filters.get("group_by") != _("Group by Voucher"):
|
||||
data.append(acc_dict.totals.opening)
|
||||
|
||||
data += acc_dict.entries
|
||||
@ -219,10 +229,9 @@ def get_data_with_opening_closing(filters, account_details, gl_entries):
|
||||
data.append(acc_dict.totals.total)
|
||||
|
||||
# closing
|
||||
if filters.get("group_by") != "Group by Voucher":
|
||||
if filters.get("group_by") != _("Group by Voucher"):
|
||||
data.append(acc_dict.totals.closing)
|
||||
data.append({})
|
||||
|
||||
else:
|
||||
data += entries
|
||||
|
||||
@ -234,7 +243,6 @@ def get_data_with_opening_closing(filters, account_details, gl_entries):
|
||||
|
||||
return data
|
||||
|
||||
|
||||
def get_totals_dict():
|
||||
def _get_debit_credit_dict(label):
|
||||
return _dict(
|
||||
@ -251,12 +259,12 @@ def get_totals_dict():
|
||||
)
|
||||
|
||||
def group_by_field(group_by):
|
||||
if group_by == 'Group by Party':
|
||||
if group_by == _('Group by Party'):
|
||||
return 'party'
|
||||
elif group_by == 'Group by Voucher':
|
||||
return 'voucher_no'
|
||||
else:
|
||||
elif group_by in [_('Group by Voucher (Consolidated)'), _('Group by Account')]:
|
||||
return 'account'
|
||||
else:
|
||||
return 'voucher_no'
|
||||
|
||||
def initialize_gle_map(gl_entries, filters):
|
||||
gle_map = frappe._dict()
|
||||
@ -291,7 +299,7 @@ def get_accountwise_gle(filters, gl_entries, gle_map):
|
||||
elif gle.posting_date <= to_date:
|
||||
update_value_in_dict(gle_map[gle.get(group_by)].totals, 'total', gle)
|
||||
update_value_in_dict(totals, 'total', gle)
|
||||
if filters.get("group_by"):
|
||||
if filters.get("group_by") != _('Group by Voucher (Consolidated)'):
|
||||
gle_map[gle.get(group_by)].entries.append(gle)
|
||||
else:
|
||||
entries.append(gle)
|
||||
@ -301,7 +309,6 @@ def get_accountwise_gle(filters, gl_entries, gle_map):
|
||||
|
||||
return totals, entries
|
||||
|
||||
|
||||
def get_result_as_list(data, filters):
|
||||
balance, balance_in_account_currency = 0, 0
|
||||
inv_details = get_supplier_invoice_details()
|
||||
|
@ -13,7 +13,11 @@ frappe.ui.form.on('Asset Value Adjustment', {
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
onload: function(frm) {
|
||||
if(frm.is_new() && frm.doc.asset) {
|
||||
frm.trigger("set_current_asset_value");
|
||||
}
|
||||
},
|
||||
asset: function(frm) {
|
||||
frm.trigger("set_current_asset_value");
|
||||
},
|
||||
|
@ -1,5 +1,6 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_events_in_timeline": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 1,
|
||||
"allow_rename": 0,
|
||||
@ -180,39 +181,6 @@
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "No",
|
||||
"fieldname": "is_subcontracted",
|
||||
"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": 1,
|
||||
"label": "Supply Raw Materials",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "No\nYes",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"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_in_quick_entry": 0,
|
||||
@ -246,40 +214,6 @@
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "eval:doc.is_subcontracted==\"Yes\"",
|
||||
"fieldname": "supplier_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": "Supplier 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_in_quick_entry": 0,
|
||||
@ -1353,6 +1287,168 @@
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "sec_warehouse",
|
||||
"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_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "set_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": "Set Target Warehouse",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Warehouse",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 1,
|
||||
"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_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "col_break_warehouse",
|
||||
"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_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "No",
|
||||
"fieldname": "is_subcontracted",
|
||||
"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": 1,
|
||||
"label": "Supply Raw Materials",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "No\nYes",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"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_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "eval:doc.is_subcontracted==\"Yes\"",
|
||||
"fieldname": "supplier_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": "Supplier 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_in_quick_entry": 0,
|
||||
@ -1386,6 +1482,38 @@
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "scan_barcode",
|
||||
"fieldtype": "Data",
|
||||
"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": "Scan Barcode",
|
||||
"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": 1,
|
||||
"allow_in_quick_entry": 0,
|
||||
@ -1420,6 +1548,74 @@
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"collapsible_depends_on": "supplied_items",
|
||||
"columns": 0,
|
||||
"fieldname": "raw_material_details",
|
||||
"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": "Raw Materials Supplied",
|
||||
"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_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "",
|
||||
"fieldname": "supplied_items",
|
||||
"fieldtype": "Table",
|
||||
"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": "Supplied Items",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"oldfieldname": "po_raw_material_details",
|
||||
"oldfieldtype": "Table",
|
||||
"options": "Purchase Order Item Supplied",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"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_in_quick_entry": 0,
|
||||
@ -3428,107 +3624,6 @@
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"collapsible_depends_on": "supplied_items",
|
||||
"columns": 0,
|
||||
"fieldname": "raw_material_details",
|
||||
"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": "Raw Materials Supplied",
|
||||
"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_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "eval:doc.is_subcontracted",
|
||||
"fieldname": "supplied_items_section",
|
||||
"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": "Supplied Items",
|
||||
"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_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "",
|
||||
"fieldname": "supplied_items",
|
||||
"fieldtype": "Table",
|
||||
"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": "Supplied Items",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"oldfieldname": "po_raw_material_details",
|
||||
"oldfieldtype": "Table",
|
||||
"options": "Purchase Order Item Supplied",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"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_in_quick_entry": 0,
|
||||
@ -3736,8 +3831,8 @@
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2018-08-29 12:16:12.886021",
|
||||
"modified_by": "nabinhait@gmail.com",
|
||||
"modified": "2018-11-12 19:59:49.211145",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Buying",
|
||||
"name": "Purchase Order",
|
||||
"owner": "Administrator",
|
||||
|
128
erpnext/buying/report/purchase_analytics/purchase_analytics.js
Normal file
128
erpnext/buying/report/purchase_analytics/purchase_analytics.js
Normal file
@ -0,0 +1,128 @@
|
||||
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
/* eslint-disable */
|
||||
|
||||
frappe.query_reports["Purchase Analytics"] = {
|
||||
"filters": [
|
||||
{
|
||||
fieldname: "tree_type",
|
||||
label: __("Tree Type"),
|
||||
fieldtype: "Select",
|
||||
options: ["Supplier Group","Supplier","Item Group","Item"],
|
||||
default: "Supplier",
|
||||
reqd: 1
|
||||
},
|
||||
{
|
||||
fieldname: "doc_type",
|
||||
label: __("based_on"),
|
||||
fieldtype: "Select",
|
||||
options: ["Purchase Order","Purchase Receipt","Purchase Invoice"],
|
||||
default: "Purchase Invoice",
|
||||
reqd: 1
|
||||
},
|
||||
{
|
||||
fieldname: "value_quantity",
|
||||
label: __("Value Or Qty"),
|
||||
fieldtype: "Select",
|
||||
options: [
|
||||
{ "value": "Value", "label": __("Value") },
|
||||
{ "value": "Quantity", "label": __("Quantity") },
|
||||
],
|
||||
default: "Value",
|
||||
reqd: 1
|
||||
},
|
||||
{
|
||||
fieldname: "from_date",
|
||||
label: __("From Date"),
|
||||
fieldtype: "Date",
|
||||
default: frappe.defaults.get_user_default("year_start_date"),
|
||||
reqd: 1
|
||||
},
|
||||
{
|
||||
fieldname:"to_date",
|
||||
label: __("To Date"),
|
||||
fieldtype: "Date",
|
||||
default: frappe.defaults.get_user_default("year_end_date"),
|
||||
reqd: 1
|
||||
},
|
||||
{
|
||||
fieldname: "company",
|
||||
label: __("Company"),
|
||||
fieldtype: "Link",
|
||||
options: "Company",
|
||||
default: frappe.defaults.get_user_default("Company"),
|
||||
reqd: 1
|
||||
},
|
||||
{
|
||||
fieldname: "range",
|
||||
label: __("Range"),
|
||||
fieldtype: "Select",
|
||||
options: [
|
||||
{ "value": "Weekly", "label": __("Weekly") },
|
||||
{ "value": "Monthly", "label": __("Monthly") },
|
||||
{ "value": "Quarterly", "label": __("Quarterly") },
|
||||
{ "value": "Yearly", "label": __("Yearly") }
|
||||
],
|
||||
default: "Monthly",
|
||||
reqd: 1
|
||||
}
|
||||
|
||||
],
|
||||
"formatter": function(value, row, column, data) {
|
||||
if(!value){
|
||||
value = 0
|
||||
}
|
||||
return value;
|
||||
},
|
||||
get_datatable_options(options) {
|
||||
return Object.assign(options, {
|
||||
checkboxColumn: true,
|
||||
events: {
|
||||
onCheckRow: function(data) {
|
||||
row_name = data[2].content;
|
||||
row_values = data.slice(5).map(function (column) {
|
||||
return column.content;
|
||||
})
|
||||
|
||||
entry = {
|
||||
'name':row_name,
|
||||
'values':row_values
|
||||
}
|
||||
|
||||
let raw_data = frappe.query_report.chart.data;
|
||||
let new_datasets = raw_data.datasets;
|
||||
|
||||
var found = false;
|
||||
|
||||
for(var i=0; i < new_datasets.length;i++){
|
||||
if(new_datasets[i].name == row_name){
|
||||
found = true;
|
||||
new_datasets.splice(i,1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!found){
|
||||
new_datasets.push(entry);
|
||||
}
|
||||
|
||||
let new_data = {
|
||||
labels: raw_data.labels,
|
||||
datasets: new_datasets
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
frappe.query_report.chart.update(new_data)
|
||||
},200)
|
||||
|
||||
|
||||
setTimeout(() => {
|
||||
frappe.query_report.chart.draw(true);
|
||||
}, 800)
|
||||
|
||||
frappe.query_report.raw_chart_data = new_data;
|
||||
},
|
||||
}
|
||||
})
|
||||
},
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
{
|
||||
"add_total_row": 0,
|
||||
"creation": "2018-10-05 16:08:24.156448",
|
||||
"disabled": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "Report",
|
||||
"idx": 0,
|
||||
"is_standard": "Yes",
|
||||
"modified": "2018-10-05 16:08:33.272201",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Buying",
|
||||
"name": "Purchase Analytics",
|
||||
"owner": "Administrator",
|
||||
"prepared_report": 0,
|
||||
"ref_doctype": "Purchase Order",
|
||||
"report_name": "Purchase Analytics",
|
||||
"report_type": "Script Report",
|
||||
"roles": [
|
||||
{
|
||||
"role": "Purchase Manager"
|
||||
},
|
||||
{
|
||||
"role": "Purchase User"
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
from erpnext.selling.report.sales_analytics.sales_analytics import Analytics
|
||||
|
||||
def execute(filters=None):
|
||||
return Analytics(filters).run()
|
@ -122,10 +122,10 @@ def get_data():
|
||||
"icon": "fa fa-table",
|
||||
"items": [
|
||||
{
|
||||
"type": "page",
|
||||
"name": "purchase-analytics",
|
||||
"label": _("Purchase Analytics"),
|
||||
"icon": "fa fa-bar-chart",
|
||||
"type": "report",
|
||||
"is_query_report": True,
|
||||
"name": "Purchase Analytics",
|
||||
"doctype": "Purchase Order"
|
||||
},
|
||||
{
|
||||
"type": "report",
|
||||
|
@ -112,11 +112,12 @@ def get_data():
|
||||
"is_query_report": True,
|
||||
"name": "Completed Work Orders",
|
||||
"doctype": "Work Order"
|
||||
},{
|
||||
"type": "page",
|
||||
"name": "production-analytics",
|
||||
"label": _("Production Analytics"),
|
||||
"icon": "fa fa-bar-chart",
|
||||
},
|
||||
{
|
||||
"type": "report",
|
||||
"is_query_report": True,
|
||||
"name": "Production Analytics",
|
||||
"doctype": "Work Order"
|
||||
},
|
||||
{
|
||||
"type": "report",
|
||||
|
@ -185,10 +185,10 @@ def get_data():
|
||||
"icon": "fa fa-table",
|
||||
"items": [
|
||||
{
|
||||
"type": "page",
|
||||
"name": "sales-analytics",
|
||||
"label": _("Sales Analytics"),
|
||||
"icon": "fa fa-bar-chart",
|
||||
"type": "report",
|
||||
"is_query_report": True,
|
||||
"name": "Sales Analytics",
|
||||
"doctype": "Sales Order"
|
||||
},
|
||||
{
|
||||
"type": "page",
|
||||
|
@ -64,7 +64,7 @@ def get_data():
|
||||
{
|
||||
"type": "help",
|
||||
"label": _("Users and Permissions"),
|
||||
"youtube_id": "fnBoRhBrwR4"
|
||||
"youtube_id": "8Slw1hsTmUI"
|
||||
},
|
||||
{
|
||||
"type": "help",
|
||||
|
@ -218,10 +218,10 @@ def get_data():
|
||||
"doctype": "Item Price",
|
||||
},
|
||||
{
|
||||
"type": "page",
|
||||
"name": "stock-analytics",
|
||||
"label": _("Stock Analytics"),
|
||||
"icon": "fa fa-bar-chart"
|
||||
"type": "report",
|
||||
"is_query_report": True,
|
||||
"name": "Stock Analytics",
|
||||
"doctype": "Stock Entry"
|
||||
},
|
||||
{
|
||||
"type": "report",
|
||||
|
@ -12,7 +12,7 @@ app_license = "GNU General Public License (v3)"
|
||||
source_link = "https://github.com/frappe/erpnext"
|
||||
|
||||
develop_version = '12.x.x-develop'
|
||||
staging_version = '11.0.3-beta.20'
|
||||
staging_version = '11.0.3-beta.21'
|
||||
|
||||
error_report_email = "support@erpnext.com"
|
||||
|
||||
|
@ -104,13 +104,26 @@ frappe.ui.form.on('Production Plan', {
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
get_items_for_mr: function(frm) {
|
||||
frappe.call({
|
||||
method: "get_items_for_material_requests",
|
||||
method: "erpnext.manufacturing.doctype.production_plan.production_plan.get_items_for_material_requests",
|
||||
freeze: true,
|
||||
doc: frm.doc,
|
||||
callback: function() {
|
||||
args: {doc: frm.doc},
|
||||
callback: function(r) {
|
||||
if(r.message) {
|
||||
frm.set_value('mr_items', []);
|
||||
$.each(r.message, function(i, d) {
|
||||
var item = frm.add_child('mr_items');
|
||||
item.actual_qty = d.actual_qty;
|
||||
item.item_code = d.item_code;
|
||||
item.item_name = d.item_name;
|
||||
item.min_order_qty = d.min_order_qty;
|
||||
item.quantity = d.quantity;
|
||||
item.sales_order = d.sales_order;
|
||||
item.warehouse = d.warehouse;
|
||||
});
|
||||
}
|
||||
refresh_field('mr_items');
|
||||
}
|
||||
});
|
||||
|
@ -10,6 +10,7 @@ from erpnext.manufacturing.doctype.bom.bom import validate_bom_no
|
||||
from frappe.utils import cstr, flt, cint, nowdate, add_days, comma_and, now_datetime
|
||||
from erpnext.manufacturing.doctype.work_order.work_order import get_item_details
|
||||
from six import string_types
|
||||
from erpnext.setup.doctype.item_group.item_group import get_item_group_defaults
|
||||
|
||||
class ProductionPlan(Document):
|
||||
def validate(self):
|
||||
@ -209,9 +210,10 @@ class ProductionPlan(Document):
|
||||
|
||||
def set_status(self):
|
||||
self.status = {
|
||||
'0': 'Draft',
|
||||
'1': 'Submitted'
|
||||
}[cstr(self.docstatus or 0)]
|
||||
0: 'Draft',
|
||||
1: 'Submitted',
|
||||
2: 'Cancelled'
|
||||
}.get(self.docstatus)
|
||||
|
||||
if self.total_produced_qty > 0:
|
||||
self.status = "In Process"
|
||||
@ -281,102 +283,6 @@ class ProductionPlan(Document):
|
||||
|
||||
return item_dict
|
||||
|
||||
def get_items_for_material_requests(self):
|
||||
self.mr_items = []
|
||||
|
||||
for data in self.po_items:
|
||||
bom_wise_item_details = {}
|
||||
if not data.planned_qty:
|
||||
frappe.throw(_("For row {0}: Enter planned qty").format(data.idx))
|
||||
|
||||
if data.include_exploded_items and data.bom_no and self.include_subcontracted_items:
|
||||
for d in frappe.db.sql("""select bei.item_code, item.default_bom as bom,
|
||||
ifnull(sum(bei.stock_qty/ifnull(bom.quantity, 1)), 0) as qty, item.item_name,
|
||||
bei.description, bei.stock_uom, item.min_order_qty, bei.source_warehouse,
|
||||
item.default_material_request_type, item.min_order_qty, item_default.default_warehouse
|
||||
from
|
||||
`tabBOM Explosion Item` bei
|
||||
JOIN `tabBOM` bom ON bom.name = bei.parent
|
||||
JOIN `tabItem` item ON item.name = bei.item_code
|
||||
LEFT JOIN `tabItem Default` item_default
|
||||
ON item_default.parent = item.name and item_default.company=%s
|
||||
where
|
||||
bei.docstatus < 2
|
||||
and bom.name=%s and item.is_stock_item in (1, {0})
|
||||
group by bei.item_code, bei.stock_uom""".format(0 if self.include_non_stock_items else 1),
|
||||
(self.company, data.bom_no), as_dict=1):
|
||||
bom_wise_item_details.setdefault(d.item_code, d)
|
||||
else:
|
||||
bom_wise_item_details = self.get_subitems(data, bom_wise_item_details, data.bom_no, 1)
|
||||
|
||||
for item, item_details in bom_wise_item_details.items():
|
||||
if item_details.qty > 0:
|
||||
self.add_item_in_material_request_items(item, item_details, data)
|
||||
|
||||
def get_subitems(self, data, bom_wise_item_details, bom_no, parent_qty):
|
||||
items = frappe.db.sql("""
|
||||
SELECT
|
||||
bom_item.item_code, default_material_request_type, item.item_name,
|
||||
ifnull(%(parent_qty)s * sum(bom_item.stock_qty/ifnull(bom.quantity, 1)), 0) as qty,
|
||||
item.is_sub_contracted_item as is_sub_contracted, bom_item.source_warehouse,
|
||||
item.default_bom as default_bom, bom_item.description as description,
|
||||
bom_item.stock_uom as stock_uom, item.min_order_qty as min_order_qty,
|
||||
item_default.default_warehouse
|
||||
FROM
|
||||
`tabBOM Item` bom_item
|
||||
JOIN `tabBOM` bom ON bom.name = bom_item.parent
|
||||
JOIN tabItem item ON bom_item.item_code = item.name
|
||||
LEFT JOIN `tabItem Default` item_default
|
||||
ON item.name = item_default.parent and item_default.company = %(company)s
|
||||
where
|
||||
bom.name = %(bom)s
|
||||
and bom_item.docstatus < 2
|
||||
and item.is_stock_item in (1, {0})
|
||||
group by bom_item.item_code""".format(0 if self.include_non_stock_items else 1),{
|
||||
'bom': bom_no,
|
||||
'parent_qty': parent_qty,
|
||||
'company': self.company
|
||||
}, as_dict=1)
|
||||
|
||||
for d in items:
|
||||
if not data.include_exploded_items or not d.default_bom:
|
||||
if d.item_code in bom_wise_item_details:
|
||||
bom_wise_item_details[d.item_code].qty = bom_wise_item_details[d.item_code].qty + d.qty
|
||||
else:
|
||||
bom_wise_item_details[d.item_code] = d
|
||||
|
||||
if data.include_exploded_items and d.default_bom:
|
||||
if ((d.default_material_request_type in ["Manufacture", "Purchase"] and
|
||||
not d.is_sub_contracted) or (d.is_sub_contracted and self.include_subcontracted_items)):
|
||||
if d.qty > 0:
|
||||
self.get_subitems(data, bom_wise_item_details, d.default_bom, d.qty)
|
||||
|
||||
return bom_wise_item_details
|
||||
|
||||
def add_item_in_material_request_items(self, item, row, data):
|
||||
total_qty = row.qty * data.planned_qty
|
||||
projected_qty, actual_qty = get_bin_details(row)
|
||||
|
||||
requested_qty = 0
|
||||
if self.ignore_existing_ordered_qty:
|
||||
requested_qty = total_qty
|
||||
else:
|
||||
requested_qty = total_qty - projected_qty
|
||||
|
||||
if requested_qty > 0 and requested_qty < row.min_order_qty:
|
||||
requested_qty = row.min_order_qty
|
||||
|
||||
if requested_qty > 0:
|
||||
self.append('mr_items', {
|
||||
'item_code': item,
|
||||
'item_name': row.item_name,
|
||||
'quantity': requested_qty,
|
||||
'warehouse': row.source_warehouse or row.default_warehouse,
|
||||
'actual_qty': actual_qty,
|
||||
'min_order_qty': row.min_order_qty,
|
||||
'sales_order': data.sales_order
|
||||
})
|
||||
|
||||
def make_work_order(self):
|
||||
wo_list = []
|
||||
self.validate_data()
|
||||
@ -466,6 +372,87 @@ class ProductionPlan(Document):
|
||||
else :
|
||||
msgprint(_("No material request created"))
|
||||
|
||||
def get_exploded_items(bom_wise_item_details, company, bom_no, include_non_stock_items):
|
||||
for d in frappe.db.sql("""select bei.item_code, item.default_bom as bom,
|
||||
ifnull(sum(bei.stock_qty/ifnull(bom.quantity, 1)), 0) as qty, item.item_name,
|
||||
bei.description, bei.stock_uom, item.min_order_qty, bei.source_warehouse,
|
||||
item.default_material_request_type, item.min_order_qty, item_default.default_warehouse
|
||||
from
|
||||
`tabBOM Explosion Item` bei
|
||||
JOIN `tabBOM` bom ON bom.name = bei.parent
|
||||
JOIN `tabItem` item ON item.name = bei.item_code
|
||||
LEFT JOIN `tabItem Default` item_default
|
||||
ON item_default.parent = item.name and item_default.company=%s
|
||||
where
|
||||
bei.docstatus < 2
|
||||
and bom.name=%s and item.is_stock_item in (1, {0})
|
||||
group by bei.item_code, bei.stock_uom""".format(0 if include_non_stock_items else 1),
|
||||
(company, bom_no), as_dict=1):
|
||||
bom_wise_item_details.setdefault(d.get('item_code'), d)
|
||||
return bom_wise_item_details
|
||||
|
||||
def get_subitems(doc, data, bom_wise_item_details, bom_no, company, include_non_stock_items, include_subcontracted_items, parent_qty):
|
||||
items = frappe.db.sql("""
|
||||
SELECT
|
||||
bom_item.item_code, default_material_request_type, item.item_name,
|
||||
ifnull(%(parent_qty)s * sum(bom_item.stock_qty/ifnull(bom.quantity, 1)), 0) as qty,
|
||||
item.is_sub_contracted_item as is_sub_contracted, bom_item.source_warehouse,
|
||||
item.default_bom as default_bom, bom_item.description as description,
|
||||
bom_item.stock_uom as stock_uom, item.min_order_qty as min_order_qty,
|
||||
item_default.default_warehouse
|
||||
FROM
|
||||
`tabBOM Item` bom_item
|
||||
JOIN `tabBOM` bom ON bom.name = bom_item.parent
|
||||
JOIN tabItem item ON bom_item.item_code = item.name
|
||||
LEFT JOIN `tabItem Default` item_default
|
||||
ON item.name = item_default.parent and item_default.company = %(company)s
|
||||
where
|
||||
bom.name = %(bom)s
|
||||
and bom_item.docstatus < 2
|
||||
and item.is_stock_item in (1, {0})
|
||||
group by bom_item.item_code""".format(0 if include_non_stock_items else 1),{
|
||||
'bom': bom_no,
|
||||
'parent_qty': parent_qty,
|
||||
'company': company
|
||||
}, as_dict=1)
|
||||
|
||||
for d in items:
|
||||
if not data.get('include_exploded_items') or not d.default_bom:
|
||||
if d.item_code in bom_wise_item_details:
|
||||
bom_wise_item_details[d.item_code].qty = bom_wise_item_details[d.item_code].qty + d.qty
|
||||
else:
|
||||
bom_wise_item_details[d.item_code] = d
|
||||
|
||||
if data.get('include_exploded_items') and d.default_bom:
|
||||
if ((d.default_material_request_type in ["Manufacture", "Purchase"] and
|
||||
not d.is_sub_contracted) or (d.is_sub_contracted and include_subcontracted_items)):
|
||||
if d.qty > 0:
|
||||
get_subitems(doc, data, bom_wise_item_details, d.default_bom, company, include_non_stock_items, include_subcontracted_items, d.qty)
|
||||
return bom_wise_item_details
|
||||
|
||||
def add_item_in_material_request_items(doc, planned_qty, ignore_existing_ordered_qty, item, row, data, warehouse, company):
|
||||
total_qty = row.qty * planned_qty
|
||||
projected_qty, actual_qty = get_bin_details(row)
|
||||
|
||||
requested_qty = 0
|
||||
if ignore_existing_ordered_qty:
|
||||
requested_qty = total_qty
|
||||
else:
|
||||
requested_qty = total_qty - projected_qty
|
||||
if requested_qty > 0 and requested_qty < row.min_order_qty:
|
||||
requested_qty = row.min_order_qty
|
||||
item_group_defaults = get_item_group_defaults(item, company)
|
||||
if requested_qty > 0:
|
||||
doc.setdefault('mr_items', []).append({
|
||||
'item_code': item,
|
||||
'item_name': row.item_name,
|
||||
'quantity': requested_qty,
|
||||
'warehouse': warehouse or row.source_warehouse or row.default_warehouse or item_group_defaults.get("default_warehouse"),
|
||||
'actual_qty': actual_qty,
|
||||
'min_order_qty': row.min_order_qty,
|
||||
'sales_order': data.get('sales_order')
|
||||
})
|
||||
|
||||
def get_sales_orders(self):
|
||||
so_filter = item_filter = ""
|
||||
if self.from_date:
|
||||
@ -520,3 +507,46 @@ def get_bin_details(row):
|
||||
""".format(conditions=conditions), { "item_code": row.item_code }, as_list=1)
|
||||
|
||||
return item_projected_qty and item_projected_qty[0] or (0,0)
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_items_for_material_requests(doc, company=None):
|
||||
if isinstance(doc, string_types):
|
||||
doc = frappe._dict(json.loads(doc))
|
||||
|
||||
doc['mr_items'] = []
|
||||
po_items = doc['po_items'] if doc.get('po_items') else doc['items']
|
||||
|
||||
for data in po_items:
|
||||
warehouse = None
|
||||
bom_wise_item_details = {}
|
||||
|
||||
if data.get('required_qty'):
|
||||
planned_qty = data.get('required_qty')
|
||||
bom_no = data.get('bom')
|
||||
ignore_existing_ordered_qty = data.get('ignore_existing_ordered_qty')
|
||||
include_non_stock_items = 1
|
||||
warehouse = data.get('for_warehouse')
|
||||
if data.get('include_exploded_items'):
|
||||
include_subcontracted_items = 1
|
||||
else:
|
||||
include_subcontracted_items = 0
|
||||
else:
|
||||
planned_qty = data.get('planned_qty')
|
||||
bom_no = data.get('bom_no')
|
||||
include_subcontracted_items = doc['include_subcontracted_items']
|
||||
company = doc['company']
|
||||
include_non_stock_items = doc['include_non_stock_items']
|
||||
ignore_existing_ordered_qty = doc['ignore_existing_ordered_qty']
|
||||
if not planned_qty:
|
||||
frappe.throw(_("For row {0}: Enter Planned Qty").format(data.get('idx')))
|
||||
|
||||
if data.get('include_exploded_items') and bom_no and include_subcontracted_items:
|
||||
# fetch exploded items from BOM
|
||||
bom_wise_item_details = get_exploded_items(bom_wise_item_details, company, bom_no, include_non_stock_items)
|
||||
else:
|
||||
bom_wise_item_details = get_subitems(doc, data, bom_wise_item_details, bom_no, company, include_non_stock_items, include_subcontracted_items, 1)
|
||||
for item, item_details in bom_wise_item_details.items():
|
||||
if item_details.qty > 0:
|
||||
add_item_in_material_request_items(doc, planned_qty, ignore_existing_ordered_qty, item, item_details, data, warehouse, company)
|
||||
|
||||
return doc['mr_items']
|
||||
|
@ -10,6 +10,7 @@ from erpnext.stock.doctype.item.test_item import create_item
|
||||
from erpnext.manufacturing.doctype.production_plan.production_plan import get_sales_orders
|
||||
from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import create_stock_reconciliation
|
||||
from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order
|
||||
from erpnext.manufacturing.doctype.production_plan.production_plan import get_items_for_material_requests
|
||||
|
||||
class TestProductionPlan(unittest.TestCase):
|
||||
def setUp(self):
|
||||
@ -160,7 +161,9 @@ def create_production_plan(**args):
|
||||
'planned_start_date': args.planned_start_date or now_datetime()
|
||||
}]
|
||||
})
|
||||
pln.get_items_for_material_requests()
|
||||
mr_items = get_items_for_material_requests(pln.as_dict())
|
||||
for d in mr_items:
|
||||
pln.append('mr_items', d)
|
||||
|
||||
if not args.do_not_save:
|
||||
pln.insert()
|
||||
|
@ -448,7 +448,9 @@ class WorkOrder(Document):
|
||||
if item_dict.get(d.item_code):
|
||||
d.required_qty = item_dict.get(d.item_code).get("qty")
|
||||
else:
|
||||
for item in sorted(item_dict.values(), key=lambda d: d['idx']):
|
||||
# Attribute a big number (999) to idx for sorting putpose in case idx is NULL
|
||||
# For instance in BOM Explosion Item child table, the items coming from sub assembly items
|
||||
for item in sorted(item_dict.values(), key=lambda d: d['idx'] or 9999):
|
||||
self.append('required_items', {
|
||||
'operation': item.operation,
|
||||
'item_code': item.item_code,
|
||||
|
@ -16,6 +16,22 @@ frappe.query_reports["BOM Stock Report"] = {
|
||||
"fieldname": "show_exploded_view",
|
||||
"label": __("Show exploded view"),
|
||||
"fieldtype": "Check"
|
||||
}, {
|
||||
"fieldname": "qty_to_produce",
|
||||
"label": __("Quantity to Produce"),
|
||||
"fieldtype": "Int",
|
||||
"default": "1"
|
||||
},
|
||||
],
|
||||
"formatter": function(value, row, column, data, default_formatter) {
|
||||
value = default_formatter(value, row, column, data);
|
||||
if (column.id == "Item"){
|
||||
if (data["Enough Parts to Build"] > 0){
|
||||
value = `<a style='color:green' href="#Form/Item/${data['Item']}" data-doctype="Item">${data['Item']}</a>`
|
||||
} else {
|
||||
value = `<a style='color:red' href="#Form/Item/${data['Item']}" data-doctype="Item">${data['Item']}</a>`
|
||||
}
|
||||
}
|
||||
]
|
||||
return value
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ from frappe import _
|
||||
|
||||
def execute(filters=None):
|
||||
if not filters: filters = {}
|
||||
|
||||
columns = get_columns()
|
||||
|
||||
data = get_bom_stock(filters)
|
||||
@ -18,6 +19,7 @@ def get_columns():
|
||||
columns = [
|
||||
_("Item") + ":Link/Item:150",
|
||||
_("Description") + "::500",
|
||||
_("Qty per BOM Line") + ":Float:100",
|
||||
_("Required Qty") + ":Float:100",
|
||||
_("In Stock Qty") + ":Float:100",
|
||||
_("Enough Parts to Build") + ":Float:200",
|
||||
@ -32,6 +34,10 @@ def get_bom_stock(filters):
|
||||
table = "`tabBOM Item`"
|
||||
qty_field = "qty"
|
||||
|
||||
qty_to_produce = filters.get("qty_to_produce", 1)
|
||||
if int(qty_to_produce) <= 0:
|
||||
frappe.throw(_("Quantity to Produce can not be less than Zero"))
|
||||
|
||||
if filters.get("show_exploded_view"):
|
||||
table = "`tabBOM Explosion Item`"
|
||||
qty_field = "stock_qty"
|
||||
@ -50,11 +56,12 @@ def get_bom_stock(filters):
|
||||
|
||||
return frappe.db.sql("""
|
||||
SELECT
|
||||
bom_item.item_code ,
|
||||
bom_item.item_code,
|
||||
bom_item.description ,
|
||||
bom_item.{qty_field},
|
||||
bom_item.{qty_field} * {qty_to_produce},
|
||||
sum(ledger.actual_qty) as actual_qty,
|
||||
sum(FLOOR(ledger.actual_qty / bom_item.{qty_field}))as to_build
|
||||
sum(FLOOR(ledger.actual_qty / (bom_item.{qty_field} * {qty_to_produce})))
|
||||
FROM
|
||||
{table} AS bom_item
|
||||
LEFT JOIN `tabBin` AS ledger
|
||||
@ -63,4 +70,10 @@ def get_bom_stock(filters):
|
||||
WHERE
|
||||
bom_item.parent = '{bom}' and bom_item.parenttype='BOM'
|
||||
|
||||
GROUP BY bom_item.item_code""".format(qty_field=qty_field, table=table, conditions=conditions, bom=bom))
|
||||
GROUP BY bom_item.item_code""".format(
|
||||
qty_field=qty_field,
|
||||
table=table,
|
||||
conditions=conditions,
|
||||
bom=bom,
|
||||
qty_to_produce=qty_to_produce or 1)
|
||||
)
|
||||
|
@ -3,17 +3,16 @@
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe import _
|
||||
from frappe import _, scrub
|
||||
from frappe.utils import getdate
|
||||
from erpnext.selling.report.sales_analytics.sales_analytics import (get_period_date_ranges,get_period)
|
||||
from erpnext.stock.report.stock_analytics.stock_analytics import (get_period_date_ranges, get_period)
|
||||
|
||||
def execute(filters=None):
|
||||
columns = get_columns(filters)
|
||||
data, chart = get_data(filters,columns)
|
||||
return columns, data,None ,chart
|
||||
data, chart = get_data(filters, columns)
|
||||
return columns, data, None , chart
|
||||
|
||||
def get_columns(filters):
|
||||
|
||||
columns =[
|
||||
{
|
||||
"label": _("Status"),
|
||||
@ -22,122 +21,113 @@ def get_columns(filters):
|
||||
"width": 140
|
||||
}]
|
||||
|
||||
ranges = get_period_date_ranges(period=filters["range"], year_start_date = filters["from_date"],year_end_date=filters["to_date"])
|
||||
ranges = get_period_date_ranges(filters)
|
||||
|
||||
for dummy, end_date in ranges:
|
||||
|
||||
label = field_name = get_period(end_date,filters["range"])
|
||||
period = get_period(end_date, filters)
|
||||
|
||||
columns.append(
|
||||
{
|
||||
"label": _(label),
|
||||
"fieldname": field_name,
|
||||
columns.append({
|
||||
"label": _(period),
|
||||
"fieldname": scrub(period),
|
||||
"fieldtype": "Float",
|
||||
"width": 120
|
||||
},
|
||||
)
|
||||
})
|
||||
|
||||
return columns
|
||||
|
||||
def get_data_list(filters,entry):
|
||||
|
||||
data_list = {
|
||||
"All Work Orders" : {},
|
||||
"Not Started" : {},
|
||||
"Overdue" : {},
|
||||
"Pending" : {},
|
||||
"Completed" : {}
|
||||
def get_periodic_data(filters, entry):
|
||||
periodic_data = {
|
||||
"All Work Orders": {},
|
||||
"Not Started": {},
|
||||
"Overdue": {},
|
||||
"Pending": {},
|
||||
"Completed": {}
|
||||
}
|
||||
|
||||
ranges = get_period_date_ranges(period=filters["range"], year_start_date = filters["from_date"],year_end_date=filters["to_date"])
|
||||
ranges = get_period_date_ranges(filters)
|
||||
|
||||
for from_date,end_date in ranges:
|
||||
period = get_period(end_date,filters["range"])
|
||||
for from_date, end_date in ranges:
|
||||
period = get_period(end_date, filters)
|
||||
for d in entry:
|
||||
if getdate(d.creation) <= getdate(from_date) or getdate(d.creation) <= getdate(end_date) :
|
||||
data_list = update_data_list(data_list,"All Work Orders",period)
|
||||
|
||||
periodic_data = update_periodic_data(periodic_data, "All Work Orders", period)
|
||||
if d.status == 'Completed':
|
||||
if getdate(d.actual_end_date) < getdate(from_date) or getdate(d.modified) < getdate(from_date):
|
||||
data_list = update_data_list(data_list, "Completed",period)
|
||||
periodic_data = update_periodic_data(periodic_data, "Completed", period)
|
||||
|
||||
elif getdate(d.actual_start_date) < getdate(from_date) :
|
||||
data_list = update_data_list(data_list, "Pending", period)
|
||||
periodic_data = update_periodic_data(periodic_data, "Pending", period)
|
||||
|
||||
elif getdate(d.planned_start_date) < getdate(from_date) :
|
||||
data_list = update_data_list(data_list, "Overdue", period)
|
||||
periodic_data = update_periodic_data(periodic_data, "Overdue", period)
|
||||
|
||||
else:
|
||||
data_list = update_data_list(data_list, "Not Started", period)
|
||||
periodic_data = update_periodic_data(periodic_data, "Not Started", period)
|
||||
|
||||
elif d.status == 'In Process':
|
||||
if getdate(d.actual_start_date) < getdate(from_date) :
|
||||
data_list = update_data_list(data_list, "Pending", period)
|
||||
periodic_data = update_periodic_data(periodic_data, "Pending", period)
|
||||
|
||||
elif getdate(d.planned_start_date) < getdate(from_date) :
|
||||
data_list = update_data_list(data_list, "Overdue", period)
|
||||
periodic_data = update_periodic_data(periodic_data, "Overdue", period)
|
||||
|
||||
else:
|
||||
data_list = update_data_list(data_list, "Not Started", period)
|
||||
periodic_data = update_periodic_data(periodic_data, "Not Started", period)
|
||||
|
||||
elif d.status == 'Not Started':
|
||||
if getdate(d.planned_start_date) < getdate(from_date) :
|
||||
data_list = update_data_list(data_list, "Overdue", period)
|
||||
periodic_data = update_periodic_data(periodic_data, "Overdue", period)
|
||||
|
||||
else:
|
||||
data_list = update_data_list(data_list, "Not Started", period)
|
||||
return data_list
|
||||
periodic_data = update_periodic_data(periodic_data, "Not Started", period)
|
||||
return periodic_data
|
||||
|
||||
def update_data_list(data_list, status, period):
|
||||
if data_list.get(status).get(period):
|
||||
data_list[status][period] += 1
|
||||
def update_periodic_data(periodic_data, status, period):
|
||||
if periodic_data.get(status).get(period):
|
||||
periodic_data[status][period] += 1
|
||||
else:
|
||||
data_list[status][period] = 1
|
||||
periodic_data[status][period] = 1
|
||||
|
||||
return data_list
|
||||
|
||||
def get_data(filters,columns):
|
||||
return periodic_data
|
||||
|
||||
def get_data(filters, columns):
|
||||
data = []
|
||||
|
||||
entry = frappe.get_all("Work Order",
|
||||
fields=["creation", "modified", "actual_start_date", "actual_end_date", "planned_start_date", "planned_end_date", "status"],
|
||||
filters={"docstatus" : 1, "company" : filters["company"] })
|
||||
filters={"docstatus": 1, "company": filters["company"] })
|
||||
|
||||
data_list = get_data_list(filters,entry)
|
||||
periodic_data = get_periodic_data(filters,entry)
|
||||
|
||||
labels = ["All Work Orders", "Not Started", "Overdue", "Pending", "Completed"]
|
||||
|
||||
chart_data = get_chart_data(data_list,columns)
|
||||
|
||||
ranges = get_period_date_ranges(period=filters["range"], year_start_date = filters["from_date"],year_end_date=filters["to_date"])
|
||||
chart_data = get_chart_data(periodic_data,columns)
|
||||
ranges = get_period_date_ranges(filters)
|
||||
|
||||
for label in labels:
|
||||
work = {}
|
||||
work["Status"] = label
|
||||
for dummy,end_date in ranges:
|
||||
period = get_period(end_date,filters["range"])
|
||||
if data_list.get(label).get(period):
|
||||
work[period] = data_list.get(label).get(period)
|
||||
period = get_period(end_date, filters)
|
||||
if periodic_data.get(label).get(period):
|
||||
work[scrub(period)] = periodic_data.get(label).get(period)
|
||||
else:
|
||||
work[period] = 0.0
|
||||
work[scrub(period)] = 0.0
|
||||
data.append(work)
|
||||
|
||||
return data, chart_data
|
||||
|
||||
def get_chart_data(data_list,columns):
|
||||
|
||||
def get_chart_data(periodic_data, columns):
|
||||
labels = [d.get("label") for d in columns[1:]]
|
||||
|
||||
all_data, not_start, overdue, pending, completed = [], [], [] , [], []
|
||||
datasets = []
|
||||
|
||||
for d in labels:
|
||||
all_data.append(data_list.get("All Work Orders").get(d))
|
||||
not_start.append(data_list.get("Not Started").get(d))
|
||||
overdue.append(data_list.get("Overdue").get(d))
|
||||
pending.append(data_list.get("Pending").get(d))
|
||||
completed.append(data_list.get("Completed").get(d))
|
||||
all_data.append(periodic_data.get("All Work Orders").get(d))
|
||||
not_start.append(periodic_data.get("Not Started").get(d))
|
||||
overdue.append(periodic_data.get("Overdue").get(d))
|
||||
pending.append(periodic_data.get("Pending").get(d))
|
||||
completed.append(periodic_data.get("Completed").get(d))
|
||||
|
||||
datasets.append({'name':'All Work Orders', 'values': all_data})
|
||||
datasets.append({'name':'Not Started', 'values': not_start})
|
||||
@ -148,10 +138,9 @@ def get_chart_data(data_list,columns):
|
||||
chart = {
|
||||
"data": {
|
||||
'labels': labels,
|
||||
'datasets':datasets
|
||||
'datasets': datasets
|
||||
}
|
||||
}
|
||||
|
||||
chart["type"] = "line"
|
||||
|
||||
return chart
|
||||
|
6
erpnext/patches.txt
Normal file → Executable file
6
erpnext/patches.txt
Normal file → Executable file
@ -568,7 +568,13 @@ erpnext.patches.v11_0.remove_land_unit_icon
|
||||
erpnext.patches.v11_0.add_default_dispatch_notification_template
|
||||
erpnext.patches.v11_0.add_market_segments
|
||||
erpnext.patches.v11_0.add_sales_stages
|
||||
execute:frappe.delete_doc("Page", "Sales Analytics")
|
||||
execute:frappe.delete_doc("Page", "Purchase Analytics")
|
||||
execute:frappe.delete_doc("Page", "Stock Analytics")
|
||||
execute:frappe.delete_doc("Page", "Production Analytics")
|
||||
erpnext.patches.v11_0.ewaybill_fields_gst_india
|
||||
erpnext.patches.v11_0.drop_column_max_days_allowed
|
||||
erpnext.patches.v11_0.change_healthcare_desktop_icons
|
||||
erpnext.patches.v10_0.update_user_image_in_employee
|
||||
erpnext.patches.v11_0.update_delivery_trip_status
|
||||
erpnext.patches.v10_0.repost_gle_for_purchase_receipts_with_rejected_items
|
||||
|
@ -0,0 +1,32 @@
|
||||
# Copyright (c) 2017, Frappe and Contributors
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe, erpnext
|
||||
|
||||
def execute():
|
||||
for company in frappe.get_all("Company"):
|
||||
if not erpnext.is_perpetual_inventory_enabled(company.name):
|
||||
continue
|
||||
|
||||
acc_frozen_upto = frappe.db.get_value("Accounts Settings", None, "acc_frozen_upto") or "1900-01-01"
|
||||
pr_with_rejected_warehouse = frappe.db.sql("""
|
||||
select pr.name
|
||||
from `tabPurchase Receipt` pr, `tabPurchase Receipt Item` pr_item
|
||||
where pr.name = pr_item.parent
|
||||
and pr.posting_date > %s
|
||||
and pr.docstatus=1
|
||||
and pr.company = %s
|
||||
and pr_item.rejected_qty > 0
|
||||
""", (acc_frozen_upto, company.name), as_dict=1)
|
||||
|
||||
for d in pr_with_rejected_warehouse:
|
||||
doc = frappe.get_doc("Purchase Receipt", d.name)
|
||||
|
||||
doc.docstatus = 2
|
||||
doc.make_gl_entries_on_cancel(repost_future_gle=False)
|
||||
|
||||
|
||||
# update gl entries for submit state of PR
|
||||
doc.docstatus = 1
|
||||
doc.make_gl_entries(repost_future_gle=False)
|
27
erpnext/patches/v11_0/update_delivery_trip_status.py
Executable file
27
erpnext/patches/v11_0/update_delivery_trip_status.py
Executable file
@ -0,0 +1,27 @@
|
||||
# Copyright (c) 2017, Frappe and Contributors
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
|
||||
def execute():
|
||||
frappe.reload_doc('stock', 'doctype', 'delivery_trip')
|
||||
frappe.reload_doc('stock', 'doctype', 'delivery_stop', force=True)
|
||||
|
||||
for trip in frappe.get_all("Delivery Trip"):
|
||||
trip_doc = frappe.get_doc("Delivery Trip", trip.name)
|
||||
|
||||
status = {
|
||||
0: "Draft",
|
||||
1: "Scheduled",
|
||||
2: "Cancelled"
|
||||
}[trip_doc.docstatus]
|
||||
|
||||
if trip_doc.docstatus == 1:
|
||||
visited_stops = [stop.visited for stop in trip_doc.delivery_stops]
|
||||
if all(visited_stops):
|
||||
status = "Completed"
|
||||
elif any(visited_stops):
|
||||
status = "In Transit"
|
||||
|
||||
frappe.db.set_value("Delivery Trip", trip.name, "status", status, update_modified=False)
|
@ -128,6 +128,50 @@ class TestTimesheet(unittest.TestCase):
|
||||
settings.ignore_employee_time_overlap = initial_setting
|
||||
settings.save()
|
||||
|
||||
def test_timesheet_std_working_hours(self):
|
||||
company = frappe.get_doc('Company', "_Test Company")
|
||||
company.standard_working_hours = 8
|
||||
company.save()
|
||||
|
||||
timesheet = frappe.new_doc("Timesheet")
|
||||
timesheet.employee = "_T-Employee-00001"
|
||||
timesheet.company = '_Test Company'
|
||||
timesheet.append(
|
||||
'time_logs',
|
||||
{
|
||||
"activity_type": "_Test Activity Type",
|
||||
"from_time": now_datetime(),
|
||||
"to_time": now_datetime() + datetime.timedelta(days= 4)
|
||||
}
|
||||
)
|
||||
timesheet.save()
|
||||
|
||||
ts = frappe.get_doc('Timesheet', timesheet.name)
|
||||
self.assertEqual(ts.total_hours, 32)
|
||||
ts.submit()
|
||||
ts.cancel()
|
||||
|
||||
company = frappe.get_doc('Company', "_Test Company")
|
||||
company.standard_working_hours = 0
|
||||
company.save()
|
||||
|
||||
timesheet = frappe.new_doc("Timesheet")
|
||||
timesheet.employee = "_T-Employee-00001"
|
||||
timesheet.company = '_Test Company'
|
||||
timesheet.append(
|
||||
'time_logs',
|
||||
{
|
||||
"activity_type": "_Test Activity Type",
|
||||
"from_time": now_datetime(),
|
||||
"to_time": now_datetime() + datetime.timedelta(days= 4)
|
||||
}
|
||||
)
|
||||
timesheet.save()
|
||||
|
||||
ts = frappe.get_doc('Timesheet', timesheet.name)
|
||||
self.assertEqual(ts.total_hours, 96)
|
||||
ts.submit()
|
||||
ts.cancel()
|
||||
|
||||
def make_salary_structure_for_timesheet(employee):
|
||||
salary_structure_name = "Timesheet Salary Structure Test"
|
||||
|
@ -90,6 +90,13 @@ frappe.ui.form.on("Timesheet", {
|
||||
}
|
||||
},
|
||||
|
||||
company: function(frm) {
|
||||
frappe.db.get_value('Company', { 'company_name' : frm.doc.company }, 'standard_working_hours')
|
||||
.then(({ message }) => {
|
||||
(frappe.working_hours = message.standard_working_hours || 0);
|
||||
});
|
||||
},
|
||||
|
||||
make_invoice: function(frm) {
|
||||
let dialog = new frappe.ui.Dialog({
|
||||
title: __("Select Item (optional)"),
|
||||
@ -142,11 +149,21 @@ frappe.ui.form.on("Timesheet Detail", {
|
||||
|
||||
to_time: function(frm, cdt, cdn) {
|
||||
var child = locals[cdt][cdn];
|
||||
var time_diff = (moment(child.to_time).diff(moment(child.from_time),"seconds")) / ( 60 * 60 * 24);
|
||||
var std_working_hours = 0;
|
||||
|
||||
if(frm._setting_hours) return;
|
||||
frappe.model.set_value(cdt, cdn, "hours", moment(child.to_time).diff(moment(child.from_time),
|
||||
"seconds") / 3600);
|
||||
|
||||
var hours = moment(child.to_time).diff(moment(child.from_time), "seconds") / 3600;
|
||||
std_working_hours = time_diff * frappe.working_hours;
|
||||
|
||||
if (std_working_hours < hours && std_working_hours > 0) {
|
||||
frappe.model.set_value(cdt, cdn, "hours", std_working_hours);
|
||||
} else {
|
||||
frappe.model.set_value(cdt, cdn, "hours", hours);
|
||||
}
|
||||
},
|
||||
|
||||
time_logs_add: function(frm) {
|
||||
var $trigger_again = $('.form-grid').find('.grid-row').find('.btn-open-row');
|
||||
$trigger_again.on('click', () => {
|
||||
@ -209,17 +226,23 @@ var calculate_end_time = function(frm, cdt, cdn) {
|
||||
|
||||
let d = moment(child.from_time);
|
||||
if(child.hours) {
|
||||
d.add(child.hours, "hours");
|
||||
frm._setting_hours = true;
|
||||
frappe.model.set_value(cdt, cdn, "to_time",
|
||||
d.format(frappe.defaultDatetimeFormat)).then(() => {
|
||||
frm._setting_hours = false;
|
||||
});
|
||||
}
|
||||
var time_diff = (moment(child.to_time).diff(moment(child.from_time),"seconds")) / (60 * 60 * 24);
|
||||
var std_working_hours = 0;
|
||||
var hours = moment(child.to_time).diff(moment(child.from_time), "seconds") / 3600;
|
||||
|
||||
std_working_hours = time_diff * frappe.working_hours;
|
||||
|
||||
if((frm.doc.__islocal || frm.doc.__onload.maintain_bill_work_hours_same) && child.hours){
|
||||
frappe.model.set_value(cdt, cdn, "billing_hours", child.hours);
|
||||
if (std_working_hours < hours && std_working_hours > 0) {
|
||||
frappe.model.set_value(cdt, cdn, "hours", std_working_hours);
|
||||
frappe.model.set_value(cdt, cdn, "to_time", d.add(hours, "hours").format(frappe.defaultDatetimeFormat));
|
||||
} else {
|
||||
d.add(child.hours, "hours");
|
||||
frm._setting_hours = true;
|
||||
frappe.model.set_value(cdt, cdn, "to_time",
|
||||
d.format(frappe.defaultDatetimeFormat)).then(() => {
|
||||
frm._setting_hours = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,7 @@ from frappe import _
|
||||
import json
|
||||
from datetime import timedelta
|
||||
from erpnext.controllers.queries import get_match_cond
|
||||
from frappe.utils import flt, time_diff_in_hours, get_datetime, getdate, cint
|
||||
from frappe.utils import flt, time_diff_in_hours, get_datetime, getdate, cint, date_diff, add_to_date
|
||||
from frappe.model.document import Document
|
||||
from erpnext.manufacturing.doctype.workstation.workstation import (check_if_within_operating_hours,
|
||||
WorkstationHolidayError)
|
||||
@ -27,6 +27,7 @@ class Timesheet(Document):
|
||||
self.set_status()
|
||||
self.validate_dates()
|
||||
self.validate_time_logs()
|
||||
self.calculate_std_hours()
|
||||
self.update_cost()
|
||||
self.calculate_total_amounts()
|
||||
self.calculate_percentage_billed()
|
||||
@ -93,6 +94,17 @@ class Timesheet(Document):
|
||||
self.start_date = getdate(start_date)
|
||||
self.end_date = getdate(end_date)
|
||||
|
||||
def calculate_std_hours(self):
|
||||
std_working_hours = frappe.get_value("Company", self.company, 'standard_working_hours')
|
||||
|
||||
for time in self.time_logs:
|
||||
if time.from_time and time.to_time:
|
||||
if flt(std_working_hours) > 0:
|
||||
time.hours = flt(std_working_hours) * date_diff(time.to_time, time.from_time)
|
||||
else:
|
||||
if not time.hours:
|
||||
time.hours = time_diff_in_hours(time.to_time, time.from_time)
|
||||
|
||||
def before_cancel(self):
|
||||
self.set_status()
|
||||
|
||||
|
@ -98,6 +98,15 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
||||
frm.cscript.calculate_taxes_and_totals();
|
||||
});
|
||||
|
||||
frappe.ui.form.on(this.frm.doctype + " Item", {
|
||||
items_add: function(frm, cdt, cdn) {
|
||||
var item = frappe.get_doc(cdt, cdn);
|
||||
if(!item.warehouse && frm.doc.set_warehouse) {
|
||||
item.warehouse = frm.doc.set_warehouse;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var me = this;
|
||||
if(this.frm.fields_dict["items"].grid.get_field('batch_no')) {
|
||||
this.frm.set_query("batch_no", "items", function(doc, cdt, cdn) {
|
||||
@ -253,6 +262,62 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
||||
this.set_dynamic_labels();
|
||||
this.setup_sms();
|
||||
this.setup_quality_inspection();
|
||||
this.frm.fields_dict["scan_barcode"] && this.frm.fields_dict["scan_barcode"].set_value("");
|
||||
this.frm.fields_dict["scan_barcode"] && this.frm.fields_dict["scan_barcode"].set_new_description("");
|
||||
},
|
||||
|
||||
scan_barcode: function() {
|
||||
let scan_barcode_field = this.frm.fields_dict["scan_barcode"];
|
||||
|
||||
let show_description = function(idx, item_code, exist=null) {
|
||||
if(exist) {
|
||||
scan_barcode_field.set_new_description(__('Row : ') + idx + ' ' +
|
||||
item_code + __(' Qty increased by 1'));
|
||||
} else {
|
||||
scan_barcode_field.set_new_description(__('New row : ') + idx + ' ' +
|
||||
item_code + __(' Created'));
|
||||
}
|
||||
}
|
||||
|
||||
if(this.frm.doc.scan_barcode) {
|
||||
frappe.call({
|
||||
method: "erpnext.selling.page.point_of_sale.point_of_sale.search_serial_or_batch_or_barcode_number",
|
||||
args: { search_value: this.frm.doc.scan_barcode }
|
||||
}).then(r => {
|
||||
|
||||
if(r && r.message && r.message.item_code) {
|
||||
let child = "";
|
||||
let add_row_index = -1;
|
||||
let cur_grid= this.frm.fields_dict["items"].grid;
|
||||
|
||||
this.frm.doc.items.map(d => {
|
||||
if(d.item_code==r.message.item_code){
|
||||
add_row_index = d.idx;
|
||||
return;
|
||||
} else if(!d.item_code && add_row_index==-1) {
|
||||
add_row_index = d.idx;
|
||||
}
|
||||
});
|
||||
|
||||
if(add_row_index == -1) {
|
||||
child = frappe.model.add_child(this.frm.doc, cur_grid.doctype, "items", add_row_index);
|
||||
} else {
|
||||
child = cur_grid.get_grid_row(add_row_index-1).doc;
|
||||
}
|
||||
show_description(child.idx, r.message.item_code, child.item_code);
|
||||
|
||||
frappe.model.set_value(child.doctype, child.name, {
|
||||
"item_code": r.message.item_code,
|
||||
"qty": (child.qty || 0) + 1
|
||||
});
|
||||
}
|
||||
else{
|
||||
scan_barcode_field.set_new_description(this.frm.doc.scan_barcode +__(' does not exist!'));
|
||||
}
|
||||
});
|
||||
scan_barcode_field.set_value("");
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
apply_default_taxes: function() {
|
||||
@ -1407,6 +1472,15 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
set_warehouse: function() {
|
||||
var me = this;
|
||||
if(this.frm.doc.set_warehouse) {
|
||||
$.each(this.frm.doc.items || [], function(i, item) {
|
||||
frappe.model.set_value(me.frm.doctype + " Item", item.name, "warehouse", me.frm.doc.set_warehouse);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -150,6 +150,8 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend(
|
||||
&& flt(doc.per_delivered, 6) < 100) {
|
||||
this.frm.add_custom_button(__('Material Request'),
|
||||
function() { me.make_material_request() }, __("Make"));
|
||||
this.frm.add_custom_button(__('Request for Raw Materials'),
|
||||
function() { me.make_raw_material_request() }, __("Make"));
|
||||
}
|
||||
|
||||
// make purchase order
|
||||
@ -313,6 +315,86 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend(
|
||||
})
|
||||
},
|
||||
|
||||
make_raw_material_request: function() {
|
||||
var me = this;
|
||||
this.frm.call({
|
||||
doc: this.frm.doc,
|
||||
method: 'get_work_order_items',
|
||||
args: {
|
||||
for_raw_material_request: 1
|
||||
},
|
||||
callback: function(r) {
|
||||
if(!r.message) {
|
||||
frappe.msgprint({
|
||||
message: __('No Items with Bill of Materials.'),
|
||||
indicator: 'orange'
|
||||
});
|
||||
return;
|
||||
}
|
||||
else {
|
||||
me.make_raw_material_request_dialog(r);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
make_raw_material_request_dialog: function(r) {
|
||||
var fields = [
|
||||
{fieldtype:'Check', fieldname:'include_exploded_items',
|
||||
label: __('Include Exploded Items')},
|
||||
{fieldtype:'Check', fieldname:'ignore_existing_ordered_qty',
|
||||
label: __('Ignore Existing Ordered Qty')},
|
||||
{
|
||||
fieldtype:'Table', fieldname: 'items',
|
||||
description: __('Select BOM, Qty and For Warehouse'),
|
||||
fields: [
|
||||
{fieldtype:'Read Only', fieldname:'item_code',
|
||||
label: __('Item Code'), in_list_view:1},
|
||||
{fieldtype:'Link', fieldname:'bom', options: 'BOM', reqd: 1,
|
||||
label: __('BOM'), in_list_view:1, get_query: function(doc) {
|
||||
return {filters: {item: doc.item_code}};
|
||||
}
|
||||
},
|
||||
{fieldtype:'Float', fieldname:'required_qty', reqd: 1,
|
||||
label: __('Qty'), in_list_view:1},
|
||||
{fieldtype:'Link', fieldname:'for_warehouse', options: 'Warehouse',
|
||||
label: __('For Warehouse')}
|
||||
],
|
||||
data: r.message,
|
||||
get_data: function() {
|
||||
return r.message
|
||||
}
|
||||
}
|
||||
]
|
||||
var d = new frappe.ui.Dialog({
|
||||
title: __("Select from Items having BOM"),
|
||||
fields: fields,
|
||||
primary_action: function() {
|
||||
var data = d.get_values();
|
||||
me.frm.call({
|
||||
method: 'erpnext.selling.doctype.sales_order.sales_order.make_raw_material_request',
|
||||
args: {
|
||||
items: data,
|
||||
company: me.frm.doc.company,
|
||||
sales_order: me.frm.docname,
|
||||
project: me.frm.project
|
||||
},
|
||||
freeze: true,
|
||||
callback: function(r) {
|
||||
if(r.message) {
|
||||
frappe.msgprint(__('Material Request {0} submitted.',
|
||||
['<a href="#Form/Material Request/'+r.message.name+'">' + r.message.name+ '</a>']));
|
||||
}
|
||||
d.hide();
|
||||
me.frm.reload_doc();
|
||||
}
|
||||
});
|
||||
},
|
||||
primary_action_label: __('Make')
|
||||
});
|
||||
d.show();
|
||||
},
|
||||
|
||||
make_delivery_note_based_on_delivery_date: function() {
|
||||
var me = this;
|
||||
|
||||
@ -423,7 +505,7 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend(
|
||||
filters: {'parent': me.frm.doc.name}
|
||||
}
|
||||
}},
|
||||
|
||||
|
||||
{"fieldtype": "Button", "label": __("Make Purchase Order"), "fieldname": "make_purchase_order", "cssClass": "btn-primary"},
|
||||
]
|
||||
});
|
||||
|
@ -1,5 +1,6 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_events_in_timeline": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 1,
|
||||
"allow_rename": 0,
|
||||
@ -1171,6 +1172,70 @@
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "sec_warehouse",
|
||||
"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_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "set_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": "Set Source Warehouse",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Warehouse",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 1,
|
||||
"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_in_quick_entry": 0,
|
||||
@ -1204,6 +1269,38 @@
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "scan_barcode",
|
||||
"fieldtype": "Data",
|
||||
"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": "Scan Barcode",
|
||||
"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": 1,
|
||||
"allow_in_quick_entry": 0,
|
||||
@ -3918,7 +4015,7 @@
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2018-08-21 14:44:44.011356",
|
||||
"modified": "2018-11-12 20:00:35.272747",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Selling",
|
||||
"name": "Sales Order",
|
||||
|
@ -5,8 +5,9 @@ from __future__ import unicode_literals
|
||||
import frappe
|
||||
import json
|
||||
import frappe.utils
|
||||
from frappe.utils import cstr, flt, getdate, comma_and, cint, nowdate
|
||||
from frappe.utils import cstr, flt, getdate, comma_and, cint, nowdate, add_days
|
||||
from frappe import _
|
||||
from six import string_types
|
||||
from frappe.model.utils import get_fetch_values
|
||||
from frappe.model.mapper import get_mapped_doc
|
||||
from erpnext.stock.stock_balance import update_bin_qty, get_reserved_qty
|
||||
@ -17,6 +18,7 @@ from frappe.desk.doctype.auto_repeat.auto_repeat import get_next_schedule_date
|
||||
from erpnext.selling.doctype.customer.customer import check_credit_limit
|
||||
from erpnext.stock.doctype.item.item import get_item_defaults
|
||||
from erpnext.setup.doctype.item_group.item_group import get_item_group_defaults
|
||||
from erpnext.manufacturing.doctype.production_plan.production_plan import get_items_for_material_requests
|
||||
|
||||
form_grid_templates = {
|
||||
"items": "templates/form_grid/item_grid.html"
|
||||
@ -366,7 +368,7 @@ class SalesOrder(SellingController):
|
||||
self.indicator_color = "green"
|
||||
self.indicator_title = _("Paid")
|
||||
|
||||
def get_work_order_items(self):
|
||||
def get_work_order_items(self, for_raw_material_request=0):
|
||||
'''Returns items with BOM that already do not have a linked work order'''
|
||||
items = []
|
||||
|
||||
@ -375,8 +377,13 @@ class SalesOrder(SellingController):
|
||||
bom = get_default_bom_item(i.item_code)
|
||||
if bom:
|
||||
stock_qty = i.qty if i.doctype == 'Packed Item' else i.stock_qty
|
||||
pending_qty= stock_qty - flt(frappe.db.sql('''select sum(qty) from `tabWork Order`
|
||||
if not for_raw_material_request:
|
||||
total_work_order_qty = flt(frappe.db.sql('''select sum(qty) from `tabWork Order`
|
||||
where production_item=%s and sales_order=%s and sales_order_item = %s and docstatus<2''', (i.item_code, self.name, i.name))[0][0])
|
||||
pending_qty = stock_qty - total_work_order_qty
|
||||
else:
|
||||
pending_qty = stock_qty
|
||||
|
||||
if pending_qty:
|
||||
items.append(dict(
|
||||
name= i.name,
|
||||
@ -384,6 +391,7 @@ class SalesOrder(SellingController):
|
||||
bom = bom,
|
||||
warehouse = i.warehouse,
|
||||
pending_qty = pending_qty,
|
||||
required_qty = pending_qty if for_raw_material_request else 0,
|
||||
sales_order_item = i.name
|
||||
))
|
||||
return items
|
||||
@ -846,7 +854,7 @@ def get_supplier(doctype, txt, searchfield, start, page_len, filters):
|
||||
or supplier_name like %(txt)s)
|
||||
and name in (select supplier from `tabSales Order Item` where parent = %(parent)s)
|
||||
and name not in (select supplier from `tabPurchase Order` po inner join `tabPurchase Order Item` poi
|
||||
on po.name=poi.parent where po.docstatus<2 and poi.sales_order=%(parent)s)
|
||||
on po.name=poi.parent where po.docstatus<2 and poi.sales_order=%(parent)s)
|
||||
order by
|
||||
if(locate(%(_txt)s, name), locate(%(_txt)s, name), 99999),
|
||||
if(locate(%(_txt)s, supplier_name), locate(%(_txt)s, supplier_name), 99999),
|
||||
@ -902,3 +910,44 @@ def get_default_bom_item(item_code):
|
||||
bom = bom[0].name if bom else None
|
||||
|
||||
return bom
|
||||
|
||||
@frappe.whitelist()
|
||||
def make_raw_material_request(items, company, sales_order, project=None):
|
||||
if not frappe.has_permission("Sales Order", "write"):
|
||||
frappe.throw(_("Not permitted"), frappe.PermissionError)
|
||||
|
||||
if isinstance(items, string_types):
|
||||
items = frappe._dict(json.loads(items))
|
||||
|
||||
for item in items.get('items'):
|
||||
item["include_exploded_items"] = items.get('include_exploded_items')
|
||||
item["ignore_existing_ordered_qty"] = items.get('ignore_existing_ordered_qty')
|
||||
|
||||
raw_materials = get_items_for_material_requests(items, company)
|
||||
if not raw_materials:
|
||||
frappe.msgprint(_("Material Request not created, as quantity for Raw Materials already available."))
|
||||
|
||||
material_request = frappe.new_doc('Material Request')
|
||||
material_request.update(dict(
|
||||
doctype = 'Material Request',
|
||||
transaction_date = nowdate(),
|
||||
company = company,
|
||||
requested_by = frappe.session.user,
|
||||
material_request_type = 'Purchase'
|
||||
))
|
||||
for item in raw_materials:
|
||||
item_doc = frappe.get_cached_doc('Item', item.get('item_code'))
|
||||
schedule_date = add_days(nowdate(), cint(item_doc.lead_time_days))
|
||||
material_request.append('items', {
|
||||
'item_code': item.get('item_code'),
|
||||
'qty': item.get('quantity'),
|
||||
'schedule_date': schedule_date,
|
||||
'warehouse': item.get('warehouse'),
|
||||
'sales_order': sales_order,
|
||||
'project': project
|
||||
})
|
||||
material_request.insert()
|
||||
material_request.flags.ignore_permissions = 1
|
||||
material_request.run_method("set_missing_values")
|
||||
material_request.submit()
|
||||
return material_request
|
@ -11,8 +11,7 @@ from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
|
||||
from erpnext.selling.doctype.sales_order.sales_order import make_work_orders
|
||||
from erpnext.controllers.accounts_controller import update_child_qty_rate
|
||||
import json
|
||||
|
||||
|
||||
from erpnext.selling.doctype.sales_order.sales_order import make_raw_material_request
|
||||
class TestSalesOrder(unittest.TestCase):
|
||||
def tearDown(self):
|
||||
frappe.set_user("Administrator")
|
||||
@ -327,9 +326,8 @@ class TestSalesOrder(unittest.TestCase):
|
||||
self.assertRaises(frappe.CancelledLinkError, dn.submit)
|
||||
|
||||
def test_service_type_product_bundle(self):
|
||||
from erpnext.stock.doctype.item.test_item import make_item
|
||||
from erpnext.selling.doctype.product_bundle.test_product_bundle import make_product_bundle
|
||||
|
||||
from erpnext.stock.doctype.item.test_item import make_item
|
||||
make_item("_Test Service Product Bundle", {"is_stock_item": 0})
|
||||
make_item("_Test Service Product Bundle Item 1", {"is_stock_item": 0})
|
||||
make_item("_Test Service Product Bundle Item 2", {"is_stock_item": 0})
|
||||
@ -343,9 +341,8 @@ class TestSalesOrder(unittest.TestCase):
|
||||
self.assertTrue("_Test Service Product Bundle Item 2" in [d.item_code for d in so.packed_items])
|
||||
|
||||
def test_mix_type_product_bundle(self):
|
||||
from erpnext.stock.doctype.item.test_item import make_item
|
||||
from erpnext.selling.doctype.product_bundle.test_product_bundle import make_product_bundle
|
||||
|
||||
from erpnext.stock.doctype.item.test_item import make_item
|
||||
make_item("_Test Mix Product Bundle", {"is_stock_item": 0})
|
||||
make_item("_Test Mix Product Bundle Item 1", {"is_stock_item": 1})
|
||||
make_item("_Test Mix Product Bundle Item 2", {"is_stock_item": 0})
|
||||
@ -388,11 +385,10 @@ class TestSalesOrder(unittest.TestCase):
|
||||
|
||||
def test_drop_shipping(self):
|
||||
from erpnext.selling.doctype.sales_order.sales_order import make_purchase_order_for_drop_shipment
|
||||
from erpnext.stock.doctype.item.test_item import make_item
|
||||
from erpnext.buying.doctype.purchase_order.purchase_order import update_status
|
||||
|
||||
make_stock_entry(target="_Test Warehouse - _TC", qty=10, rate=100)
|
||||
|
||||
from erpnext.stock.doctype.item.test_item import make_item
|
||||
po_item = make_item("_Test Item for Drop Shipping", {"is_stock_item": 1, "delivered_by_supplier": 1})
|
||||
|
||||
dn_item = make_item("_Test Regular Item", {"is_stock_item": 1})
|
||||
@ -585,8 +581,8 @@ class TestSalesOrder(unittest.TestCase):
|
||||
self.assertEquals(wo_qty[0][0], so_item_name.get(item))
|
||||
|
||||
def test_serial_no_based_delivery(self):
|
||||
from erpnext.stock.doctype.item.test_item import make_item
|
||||
frappe.set_value("Stock Settings", None, "automatically_set_serial_nos_based_on_fifo", 1)
|
||||
from erpnext.stock.doctype.item.test_item import make_item
|
||||
item = make_item("_Reserved_Serialized_Item", {"is_stock_item": 1,
|
||||
"maintain_stock": 1,
|
||||
"has_serial_no": 1,
|
||||
@ -685,12 +681,62 @@ class TestSalesOrder(unittest.TestCase):
|
||||
se.cancel()
|
||||
self.assertFalse(frappe.db.exists("Serial No", {"sales_order": so.name}))
|
||||
|
||||
def test_request_for_raw_materials(self):
|
||||
from erpnext.stock.doctype.item.test_item import make_item
|
||||
item = make_item("_Test Finished Item", {"is_stock_item": 1,
|
||||
"maintain_stock": 1,
|
||||
"valuation_rate": 500,
|
||||
"item_defaults": [
|
||||
{
|
||||
"default_warehouse": "_Test Warehouse - _TC",
|
||||
"company": "_Test Company"
|
||||
}]
|
||||
})
|
||||
make_item("_Test Raw Item A", {"maintain_stock": 1,
|
||||
"valuation_rate": 100,
|
||||
"item_defaults": [
|
||||
{
|
||||
"default_warehouse": "_Test Warehouse - _TC",
|
||||
"company": "_Test Company"
|
||||
}]
|
||||
})
|
||||
make_item("_Test Raw Item B", {"maintain_stock": 1,
|
||||
"valuation_rate": 200,
|
||||
"item_defaults": [
|
||||
{
|
||||
"default_warehouse": "_Test Warehouse - _TC",
|
||||
"company": "_Test Company"
|
||||
}]
|
||||
})
|
||||
from erpnext.manufacturing.doctype.production_plan.test_production_plan import make_bom
|
||||
make_bom(item=item.item_code, rate=1000,
|
||||
raw_materials = ['_Test Raw Item A', '_Test Raw Item B'])
|
||||
|
||||
so = make_sales_order(**{
|
||||
"item_list": [{
|
||||
"item_code": item.item_code,
|
||||
"qty": 1,
|
||||
"rate":1000
|
||||
}]
|
||||
})
|
||||
so.submit()
|
||||
mr_dict = frappe._dict()
|
||||
items = so.get_work_order_items(1)
|
||||
mr_dict['items'] = items
|
||||
mr_dict['include_exploded_items'] = 0
|
||||
mr_dict['ignore_existing_ordered_qty'] = 1
|
||||
make_raw_material_request(mr_dict, so.company, so.name)
|
||||
mr = frappe.db.sql("""select name from `tabMaterial Request` ORDER BY creation DESC LIMIT 1""", as_dict=1)[0]
|
||||
mr_doc = frappe.get_doc('Material Request',mr.get('name'))
|
||||
self.assertEqual(mr_doc.items[0].sales_order, so.name)
|
||||
|
||||
def make_sales_order(**args):
|
||||
so = frappe.new_doc("Sales Order")
|
||||
args = frappe._dict(args)
|
||||
if args.transaction_date:
|
||||
so.transaction_date = args.transaction_date
|
||||
|
||||
so.set_warehouse = "" # no need to test set_warehouse permission since it only affects the client
|
||||
so.company = args.company or "_Test Company"
|
||||
so.customer = args.customer or "_Test Customer"
|
||||
so.currency = args.currency or "INR"
|
||||
@ -714,7 +760,7 @@ def make_sales_order(**args):
|
||||
})
|
||||
|
||||
so.delivery_date = add_days(so.transaction_date, 10)
|
||||
|
||||
|
||||
if not args.do_not_save:
|
||||
so.insert()
|
||||
if not args.do_not_submit:
|
||||
|
@ -11,12 +11,9 @@ from six import string_types
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_items(start, page_length, price_list, item_group, search_value="", pos_profile=None):
|
||||
serial_no = ""
|
||||
batch_no = ""
|
||||
barcode = ""
|
||||
data = dict()
|
||||
warehouse = ""
|
||||
display_items_in_stock = 0
|
||||
item_code = search_value
|
||||
|
||||
if pos_profile:
|
||||
warehouse, display_items_in_stock = frappe.db.get_value('POS Profile', pos_profile, ['warehouse', 'display_items_in_stock'])
|
||||
@ -25,20 +22,12 @@ def get_items(start, page_length, price_list, item_group, search_value="", pos_p
|
||||
item_group = get_root_of('Item Group')
|
||||
|
||||
if search_value:
|
||||
# search serial no
|
||||
serial_no_data = frappe.db.get_value('Serial No', search_value, ['name', 'item_code'])
|
||||
if serial_no_data:
|
||||
serial_no, item_code = serial_no_data
|
||||
data = search_serial_or_batch_or_barcode_number(search_value)
|
||||
|
||||
if not serial_no:
|
||||
batch_no_data = frappe.db.get_value('Batch', search_value, ['name', 'item'])
|
||||
if batch_no_data:
|
||||
batch_no, item_code = batch_no_data
|
||||
|
||||
if not serial_no and not batch_no:
|
||||
barcode_data = frappe.db.get_value('Item Barcode', {'barcode': search_value}, ['parent', 'barcode'])
|
||||
if barcode_data:
|
||||
item_code, barcode = barcode_data
|
||||
item_code = data.get("item_code") if data.get("item_code") else search_value
|
||||
serial_no = data.get("serial_no") if data.get("serial_no") else ""
|
||||
batch_no = data.get("batch_no") if data.get("batch_no") else ""
|
||||
barcode = data.get("barcode") if data.get("barcode") else ""
|
||||
|
||||
item_code, condition = get_conditions(item_code, serial_no, batch_no, barcode)
|
||||
|
||||
@ -119,6 +108,23 @@ def get_items(start, page_length, price_list, item_group, search_value="", pos_p
|
||||
|
||||
return res
|
||||
|
||||
@frappe.whitelist()
|
||||
def search_serial_or_batch_or_barcode_number(search_value):
|
||||
# search barcode no
|
||||
barcode_data = frappe.db.get_value('Item Barcode', {'barcode': search_value}, ['barcode', 'parent as item_code'], as_dict=True)
|
||||
if barcode_data:
|
||||
return barcode_data
|
||||
|
||||
# search serial no
|
||||
serial_no_data = frappe.db.get_value('Serial No', search_value, ['name as serial_no', 'item_code'], as_dict=True)
|
||||
if serial_no_data:
|
||||
return serial_no_data
|
||||
|
||||
# search batch no
|
||||
batch_no_data = frappe.db.get_value('Batch', search_value, ['name as batch_no', 'item as item_code'], as_dict=True)
|
||||
if batch_no_data:
|
||||
return batch_no_data
|
||||
|
||||
def get_conditions(item_code, serial_no, batch_no, barcode):
|
||||
if serial_no or batch_no or barcode:
|
||||
return frappe.db.escape(item_code), "i.name = %(item_code)s"
|
||||
|
0
erpnext/selling/report/sales_analytics/__init__.py
Normal file
0
erpnext/selling/report/sales_analytics/__init__.py
Normal file
129
erpnext/selling/report/sales_analytics/sales_analytics.js
Normal file
129
erpnext/selling/report/sales_analytics/sales_analytics.js
Normal file
@ -0,0 +1,129 @@
|
||||
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
/* eslint-disable */
|
||||
|
||||
frappe.query_reports["Sales Analytics"] = {
|
||||
"filters": [
|
||||
{
|
||||
fieldname: "tree_type",
|
||||
label: __("Tree Type"),
|
||||
fieldtype: "Select",
|
||||
options: ["Customer Group","Customer","Item Group","Item","Territory"],
|
||||
default: "Customer",
|
||||
reqd: 1
|
||||
},
|
||||
{
|
||||
fieldname: "doc_type",
|
||||
label: __("based_on"),
|
||||
fieldtype: "Select",
|
||||
options: ["Sales Order","Delivery Note","Sales Invoice"],
|
||||
default: "Sales Invoice",
|
||||
reqd: 1
|
||||
},
|
||||
{
|
||||
fieldname: "value_quantity",
|
||||
label: __("Value Or Qty"),
|
||||
fieldtype: "Select",
|
||||
options: [
|
||||
{ "value": "Value", "label": __("Value") },
|
||||
{ "value": "Quantity", "label": __("Quantity") },
|
||||
],
|
||||
default: "Value",
|
||||
reqd: 1
|
||||
},
|
||||
{
|
||||
fieldname: "from_date",
|
||||
label: __("From Date"),
|
||||
fieldtype: "Date",
|
||||
default: frappe.defaults.get_user_default("year_start_date"),
|
||||
reqd: 1
|
||||
},
|
||||
{
|
||||
fieldname:"to_date",
|
||||
label: __("To Date"),
|
||||
fieldtype: "Date",
|
||||
default: frappe.defaults.get_user_default("year_end_date"),
|
||||
reqd: 1
|
||||
},
|
||||
{
|
||||
fieldname: "company",
|
||||
label: __("Company"),
|
||||
fieldtype: "Link",
|
||||
options: "Company",
|
||||
default: frappe.defaults.get_user_default("Company"),
|
||||
reqd: 1
|
||||
},
|
||||
{
|
||||
fieldname: "range",
|
||||
label: __("Range"),
|
||||
fieldtype: "Select",
|
||||
options: [
|
||||
{ "value": "Weekly", "label": __("Weekly") },
|
||||
{ "value": "Monthly", "label": __("Monthly") },
|
||||
{ "value": "Quarterly", "label": __("Quarterly") },
|
||||
{ "value": "Yearly", "label": __("Yearly") }
|
||||
],
|
||||
default: "Monthly",
|
||||
reqd: 1
|
||||
}
|
||||
],
|
||||
"formatter": function(value, row, column, data) {
|
||||
if(!value){
|
||||
value = 0
|
||||
}
|
||||
return value;
|
||||
},
|
||||
get_datatable_options(options) {
|
||||
return Object.assign(options, {
|
||||
checkboxColumn: true,
|
||||
events: {
|
||||
onCheckRow: function(data) {
|
||||
row_name = data[2].content;
|
||||
row_values = data.slice(5).map(function (column) {
|
||||
return column.content;
|
||||
})
|
||||
|
||||
entry = {
|
||||
'name':row_name,
|
||||
'values':row_values
|
||||
}
|
||||
|
||||
let raw_data = frappe.query_report.chart.data;
|
||||
let new_datasets = raw_data.datasets;
|
||||
|
||||
var found = false;
|
||||
|
||||
for(var i=0; i < new_datasets.length;i++){
|
||||
if(new_datasets[i].name == row_name){
|
||||
found = true;
|
||||
new_datasets.splice(i,1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!found){
|
||||
new_datasets.push(entry);
|
||||
}
|
||||
|
||||
let new_data = {
|
||||
labels: raw_data.labels,
|
||||
datasets: new_datasets
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
frappe.query_report.chart.update(new_data)
|
||||
},200)
|
||||
|
||||
|
||||
setTimeout(() => {
|
||||
frappe.query_report.chart.draw(true);
|
||||
}, 800)
|
||||
|
||||
frappe.query_report.raw_chart_data = new_data;
|
||||
},
|
||||
}
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
|
32
erpnext/selling/report/sales_analytics/sales_analytics.json
Normal file
32
erpnext/selling/report/sales_analytics/sales_analytics.json
Normal file
@ -0,0 +1,32 @@
|
||||
{
|
||||
"add_total_row": 0,
|
||||
"creation": "2018-09-21 12:46:29.451048",
|
||||
"disabled": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "Report",
|
||||
"idx": 0,
|
||||
"is_standard": "Yes",
|
||||
"modified": "2018-09-21 12:46:29.451048",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Selling",
|
||||
"name": "Sales Analytics",
|
||||
"owner": "Administrator",
|
||||
"prepared_report": 0,
|
||||
"ref_doctype": "Sales Order",
|
||||
"report_name": "Sales Analytics",
|
||||
"report_type": "Script Report",
|
||||
"roles": [
|
||||
{
|
||||
"role": "Stock User"
|
||||
},
|
||||
{
|
||||
"role": "Maintenance User"
|
||||
},
|
||||
{
|
||||
"role": "Accounts User"
|
||||
},
|
||||
{
|
||||
"role": "Sales Manager"
|
||||
}
|
||||
]
|
||||
}
|
286
erpnext/selling/report/sales_analytics/sales_analytics.py
Normal file
286
erpnext/selling/report/sales_analytics/sales_analytics.py
Normal file
@ -0,0 +1,286 @@
|
||||
# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe import _, scrub
|
||||
from frappe.utils import getdate, flt
|
||||
from six import iteritems
|
||||
from erpnext.accounts.utils import get_fiscal_year
|
||||
|
||||
def execute(filters=None):
|
||||
return Analytics(filters).run()
|
||||
|
||||
class Analytics(object):
|
||||
def __init__(self, filters=None):
|
||||
self.filters = frappe._dict(filters or {})
|
||||
self.date_field = 'transaction_date' \
|
||||
if self.filters.doc_type in ['Sales Order', 'Purchase Order'] else 'posting_date'
|
||||
self.months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
|
||||
self.get_period_date_ranges()
|
||||
|
||||
def run(self):
|
||||
self.get_columns()
|
||||
self.get_data()
|
||||
self.get_chart_data()
|
||||
return self.columns, self.data , None, self.chart
|
||||
|
||||
def get_columns(self):
|
||||
self.columns =[{
|
||||
"label": _(self.filters.tree_type + " ID"),
|
||||
"options": self.filters.tree_type,
|
||||
"fieldname": "entity",
|
||||
"fieldtype": "Link",
|
||||
"width": 140
|
||||
}]
|
||||
if self.filters.tree_type in ["Customer", "Supplier", "Item"]:
|
||||
self.columns.append({
|
||||
"label": _(self.filters.tree_type + " Name"),
|
||||
"fieldname": "entity_name",
|
||||
"fieldtype": "Data",
|
||||
"width": 140
|
||||
})
|
||||
for dummy, end_date in self.periodic_daterange:
|
||||
period = self.get_period(end_date)
|
||||
self.columns.append({
|
||||
"label": _(period),
|
||||
"fieldname": scrub(period),
|
||||
"fieldtype": "Float",
|
||||
"width": 120
|
||||
})
|
||||
|
||||
self.columns.append({
|
||||
"label": _("Total"),
|
||||
"fieldname": "total",
|
||||
"fieldtype": "Float",
|
||||
"width": 120
|
||||
})
|
||||
|
||||
def get_data(self):
|
||||
if self.filters.tree_type in ["Customer", "Supplier"]:
|
||||
self.get_sales_transactions_based_on_customers_or_suppliers()
|
||||
self.get_rows()
|
||||
|
||||
elif self.filters.tree_type == 'Item':
|
||||
self.get_sales_transactions_based_on_items()
|
||||
self.get_rows()
|
||||
|
||||
elif self.filters.tree_type in ["Customer Group", "Supplier Group", "Territory"]:
|
||||
self.get_sales_transactions_based_on_customer_or_territory_group()
|
||||
self.get_rows_by_group()
|
||||
|
||||
elif self.filters.tree_type == 'Item Group':
|
||||
self.get_sales_transactions_based_on_item_group()
|
||||
self.get_rows_by_group()
|
||||
|
||||
def get_sales_transactions_based_on_customers_or_suppliers(self):
|
||||
if self.filters["value_quantity"] == 'Value':
|
||||
value_field = "base_net_total as value_field"
|
||||
else:
|
||||
value_field = "total_qty as value_field"
|
||||
|
||||
if self.filters.tree_type == 'Customer':
|
||||
entity = "customer as entity"
|
||||
entity_name = "customer_name as entity_name"
|
||||
else:
|
||||
entity = "supplier as entity"
|
||||
entity_name = "supplier_name as entity_name"
|
||||
|
||||
self.entries = frappe.get_all(self.filters.doc_type,
|
||||
fields=[entity, entity_name, value_field, self.date_field],
|
||||
filters = {
|
||||
"docstatus": 1,
|
||||
"company": self.filters.company,
|
||||
self.date_field: ('between', [self.filters.from_date, self.filters.to_date])
|
||||
}
|
||||
)
|
||||
|
||||
self.entity_names = {}
|
||||
for d in self.entries:
|
||||
self.entity_names.setdefault(d.entity, d.entity_name)
|
||||
|
||||
def get_sales_transactions_based_on_items(self):
|
||||
|
||||
if self.filters["value_quantity"] == 'Value':
|
||||
value_field = 'base_amount'
|
||||
else:
|
||||
value_field = 'qty'
|
||||
|
||||
self.entries = frappe.db.sql("""
|
||||
select i.item_code as entity, i.item_name as entity_name, i.{value_field} as value_field, s.{date_field}
|
||||
from `tab{doctype} Item` i , `tab{doctype}` s
|
||||
where s.name = i.parent and i.docstatus = 1 and s.company = %s
|
||||
and s.{date_field} between %s and %s
|
||||
"""
|
||||
.format(date_field=self.date_field, value_field = value_field, doctype=self.filters.doc_type),
|
||||
(self.filters.company, self.filters.from_date, self.filters.to_date), as_dict=1)
|
||||
|
||||
self.entity_names = {}
|
||||
for d in self.entries:
|
||||
self.entity_names.setdefault(d.entity, d.entity_name)
|
||||
|
||||
def get_sales_transactions_based_on_customer_or_territory_group(self):
|
||||
if self.filters["value_quantity"] == 'Value':
|
||||
value_field = "base_net_total as value_field"
|
||||
else:
|
||||
value_field = "total_qty as value_field"
|
||||
|
||||
if self.filters.tree_type == 'Customer Group':
|
||||
entity_field = 'customer_group as entity'
|
||||
elif self.filters.tree_type == 'Supplier Group':
|
||||
entity_field = "supplier as entity"
|
||||
self.get_supplier_parent_child_map()
|
||||
else:
|
||||
entity_field = "territory as entity"
|
||||
|
||||
self.entries = frappe.get_all(self.filters.doc_type,
|
||||
fields=[entity_field, value_field, self.date_field],
|
||||
filters = {
|
||||
"docstatus": 1,
|
||||
"company": self.filters.company,
|
||||
self.date_field: ('between', [self.filters.from_date, self.filters.to_date])
|
||||
}
|
||||
)
|
||||
self.get_groups()
|
||||
|
||||
def get_sales_transactions_based_on_item_group(self):
|
||||
if self.filters["value_quantity"] == 'Value':
|
||||
value_field = "base_amount"
|
||||
else:
|
||||
value_field = "qty"
|
||||
|
||||
self.entries = frappe.db.sql("""
|
||||
select i.item_group as entity, i.{value_field} as value_field, s.{date_field}
|
||||
from `tab{doctype} Item` i , `tab{doctype}` s
|
||||
where s.name = i.parent and i.docstatus = 1 and s.company = %s
|
||||
and s.{date_field} between %s and %s
|
||||
""".format(date_field=self.date_field, value_field = value_field, doctype=self.filters.doc_type),
|
||||
(self.filters.company, self.filters.from_date, self.filters.to_date), as_dict=1)
|
||||
|
||||
self.get_groups()
|
||||
|
||||
def get_rows(self):
|
||||
self.data=[]
|
||||
self.get_periodic_data()
|
||||
|
||||
for entity, period_data in iteritems(self.entity_periodic_data):
|
||||
row = {
|
||||
"entity": entity,
|
||||
"entity_name": self.entity_names.get(entity)
|
||||
}
|
||||
total = 0
|
||||
for dummy, end_date in self.periodic_daterange:
|
||||
period = self.get_period(end_date)
|
||||
amount = flt(period_data.get(period, 0.0))
|
||||
row[scrub(period)] = amount
|
||||
total += amount
|
||||
|
||||
row["total"] = total
|
||||
self.data.append(row)
|
||||
|
||||
def get_rows_by_group(self):
|
||||
self.get_periodic_data()
|
||||
out = []
|
||||
|
||||
for d in reversed(self.group_entries):
|
||||
row = {
|
||||
"entity": d.name,
|
||||
"indent": self.depth_map.get(d.name)
|
||||
}
|
||||
total = 0
|
||||
for dummy, end_date in self.periodic_daterange:
|
||||
period = self.get_period(end_date)
|
||||
amount = flt(self.entity_periodic_data.get(d.name, {}).get(period, 0.0))
|
||||
row[scrub(period)] = amount
|
||||
if d.parent:
|
||||
self.entity_periodic_data.setdefault(d.parent, frappe._dict()).setdefault(period, 0.0)
|
||||
self.entity_periodic_data[d.parent][period] += amount
|
||||
total += amount
|
||||
row["total"] = total
|
||||
out = [row] + out
|
||||
self.data = out
|
||||
|
||||
def get_periodic_data(self):
|
||||
self.entity_periodic_data = frappe._dict()
|
||||
|
||||
for d in self.entries:
|
||||
if self.filters.tree_type == "Supplier Group":
|
||||
d.entity = self.parent_child_map.get(d.entity)
|
||||
period = self.get_period(d.get(self.date_field))
|
||||
self.entity_periodic_data.setdefault(d.entity, frappe._dict()).setdefault(period, 0.0)
|
||||
self.entity_periodic_data[d.entity][period] += flt(d.value_field)
|
||||
|
||||
def get_period(self, posting_date):
|
||||
if self.filters.range == 'Weekly':
|
||||
period = "Week " + str(posting_date.isocalendar()[1])
|
||||
elif self.filters.range == 'Monthly':
|
||||
period = self.months[posting_date.month - 1]
|
||||
elif self.filters.range == 'Quarterly':
|
||||
period = "Quarter " + str(((posting_date.month-1)//3)+1)
|
||||
else:
|
||||
year = get_fiscal_year(posting_date, company=self.filters.company)
|
||||
period = str(year[2])
|
||||
|
||||
return period
|
||||
|
||||
def get_period_date_ranges(self):
|
||||
from dateutil.relativedelta import relativedelta
|
||||
from_date, to_date = getdate(self.filters.from_date), getdate(self.filters.to_date)
|
||||
|
||||
increment = {
|
||||
"Monthly": 1,
|
||||
"Quarterly": 3,
|
||||
"Half-Yearly": 6,
|
||||
"Yearly": 12
|
||||
}.get(self.filters.range, 1)
|
||||
|
||||
self.periodic_daterange = []
|
||||
for dummy in range(1, 53, increment):
|
||||
if self.filters.range == "Weekly":
|
||||
period_end_date = from_date + relativedelta(days=6)
|
||||
else:
|
||||
period_end_date = from_date + relativedelta(months=increment, days=-1)
|
||||
|
||||
if period_end_date > to_date:
|
||||
period_end_date = to_date
|
||||
self.periodic_daterange.append([from_date, period_end_date])
|
||||
|
||||
from_date = period_end_date + relativedelta(days=1)
|
||||
if period_end_date == to_date:
|
||||
break
|
||||
|
||||
def get_groups(self):
|
||||
if self.filters.tree_type == "Territory":
|
||||
parent = 'parent_territory'
|
||||
if self.filters.tree_type == "Customer Group":
|
||||
parent = 'parent_customer_group'
|
||||
if self.filters.tree_type == "Item Group":
|
||||
parent = 'parent_item_group'
|
||||
if self.filters.tree_type == "Supplier Group":
|
||||
parent = 'parent_supplier_group'
|
||||
|
||||
self.depth_map = frappe._dict()
|
||||
|
||||
self.group_entries = frappe.db.sql("""select name, lft, rgt , {parent} as parent
|
||||
from `tab{tree}` order by lft"""
|
||||
.format(tree=self.filters.tree_type, parent=parent), as_dict=1)
|
||||
|
||||
for d in self.group_entries:
|
||||
if d.parent:
|
||||
self.depth_map.setdefault(d.name, self.depth_map.get(d.parent) + 1)
|
||||
else:
|
||||
self.depth_map.setdefault(d.name, 0)
|
||||
|
||||
def get_supplier_parent_child_map(self):
|
||||
self.parent_child_map = frappe._dict(frappe.db.sql(""" select name, supplier_group from `tabSupplier`"""))
|
||||
|
||||
def get_chart_data(self):
|
||||
labels = [d.get("label") for d in self.columns[3:]]
|
||||
self.chart = {
|
||||
"data": {
|
||||
'labels': labels,
|
||||
'datasets':[
|
||||
]
|
||||
},
|
||||
"type": "line"
|
||||
}
|
250
erpnext/selling/report/sales_analytics/test_analytics.py
Normal file
250
erpnext/selling/report/sales_analytics/test_analytics.py
Normal file
@ -0,0 +1,250 @@
|
||||
# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
import frappe
|
||||
import frappe.defaults
|
||||
import unittest
|
||||
from erpnext.selling.report.sales_analytics.sales_analytics import execute
|
||||
from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order
|
||||
|
||||
class TestAnalytics(unittest.TestCase):
|
||||
|
||||
def tearDown(self):
|
||||
frappe.db.sql(""" DELETE FROM `tabSales Order` """)
|
||||
|
||||
def test_by_entity(self):
|
||||
create_sales_order()
|
||||
|
||||
filters = {
|
||||
'doc_type': 'Sales Order',
|
||||
'range': 'Monthly',
|
||||
'to_date': '2018-03-31',
|
||||
'tree_type': 'Customer',
|
||||
'company': '_Test Company',
|
||||
'from_date': '2017-04-01',
|
||||
'value_quantity': 'Value'
|
||||
}
|
||||
|
||||
report = execute(filters)
|
||||
|
||||
expected_data = [
|
||||
{
|
||||
"entity": "_Test Customer 1",
|
||||
"entity_name": "_Test Customer 1",
|
||||
"apr": 0.0,
|
||||
"may": 0.0,
|
||||
"jun": 0.0,
|
||||
"jul": 0.0,
|
||||
"aug": 0.0,
|
||||
"sep": 0.0,
|
||||
"oct": 0.0,
|
||||
"nov": 0.0,
|
||||
"dec": 0.0,
|
||||
"jan": 0.0,
|
||||
"feb": 2000.0,
|
||||
"mar": 0.0,
|
||||
"total":2000.0
|
||||
},
|
||||
{
|
||||
"entity": "_Test Customer 3",
|
||||
"entity_name": "_Test Customer 3",
|
||||
"apr": 0.0,
|
||||
"may": 0.0,
|
||||
"jun": 2000.0,
|
||||
"jul": 1000.0,
|
||||
"aug": 0.0,
|
||||
"sep": 0.0,
|
||||
"oct": 0.0,
|
||||
"nov": 0.0,
|
||||
"dec": 0.0,
|
||||
"jan": 0.0,
|
||||
"feb": 0.0,
|
||||
"mar": 0.0,
|
||||
"total": 3000.0
|
||||
},
|
||||
{
|
||||
"entity": "_Test Customer 2",
|
||||
"entity_name": "_Test Customer 2",
|
||||
"apr": 0.0,
|
||||
"may": 0.0,
|
||||
"jun": 0.0,
|
||||
"jul": 0.0,
|
||||
"aug": 0.0,
|
||||
"sep": 1500.0,
|
||||
"oct": 1000.0,
|
||||
"nov": 0.0,
|
||||
"dec": 0.0,
|
||||
"jan": 0.0,
|
||||
"feb": 0.0,
|
||||
"mar": 0.0,
|
||||
"total":2500.0
|
||||
}
|
||||
]
|
||||
self.assertEqual(expected_data, report[1])
|
||||
|
||||
def test_by_group(self):
|
||||
create_sales_order()
|
||||
|
||||
filters = {
|
||||
'doc_type': 'Sales Order',
|
||||
'range': 'Monthly',
|
||||
'to_date': '2018-03-31',
|
||||
'tree_type': 'Customer Group',
|
||||
'company': '_Test Company',
|
||||
'from_date': '2017-04-01',
|
||||
'value_quantity': 'Value'
|
||||
}
|
||||
|
||||
report = execute(filters)
|
||||
|
||||
expected_data = [
|
||||
{
|
||||
"entity": "All Customer Groups",
|
||||
"indent": 0,
|
||||
"apr": 0.0,
|
||||
"may": 0.0,
|
||||
"jun": 2000.0,
|
||||
"jul": 1000.0,
|
||||
"aug": 0.0,
|
||||
"sep": 1500.0,
|
||||
"oct": 1000.0,
|
||||
"nov": 0.0,
|
||||
"dec": 0.0,
|
||||
"jan": 0.0,
|
||||
"feb": 2000.0,
|
||||
"mar": 0.0,
|
||||
"total":7500.0
|
||||
},
|
||||
{
|
||||
"entity": "Individual",
|
||||
"indent": 1,
|
||||
"apr": 0.0,
|
||||
"may": 0.0,
|
||||
"jun": 0.0,
|
||||
"jul": 0.0,
|
||||
"aug": 0.0,
|
||||
"sep": 0.0,
|
||||
"oct": 0.0,
|
||||
"nov": 0.0,
|
||||
"dec": 0.0,
|
||||
"jan": 0.0,
|
||||
"feb": 0.0,
|
||||
"mar": 0.0,
|
||||
"total": 0.0
|
||||
},
|
||||
{
|
||||
"entity": "_Test Customer Group",
|
||||
"indent": 1,
|
||||
"apr": 0.0,
|
||||
"may": 0.0,
|
||||
"jun": 0.0,
|
||||
"jul": 0.0,
|
||||
"aug": 0.0,
|
||||
"sep": 0.0,
|
||||
"oct": 0.0,
|
||||
"nov": 0.0,
|
||||
"dec": 0.0,
|
||||
"jan": 0.0,
|
||||
"feb": 0.0,
|
||||
"mar": 0.0,
|
||||
"total":0.0
|
||||
},
|
||||
{
|
||||
"entity": "_Test Customer Group 1",
|
||||
"indent": 1,
|
||||
"apr": 0.0,
|
||||
"may": 0.0,
|
||||
"jun": 0.0,
|
||||
"jul": 0.0,
|
||||
"aug": 0.0,
|
||||
"sep": 0.0,
|
||||
"oct": 0.0,
|
||||
"nov": 0.0,
|
||||
"dec": 0.0,
|
||||
"jan": 0.0,
|
||||
"feb": 0.0,
|
||||
"mar": 0.0,
|
||||
"total":0.0
|
||||
}
|
||||
]
|
||||
self.assertEqual(expected_data, report[1])
|
||||
|
||||
def test_by_quantity(self):
|
||||
create_sales_order()
|
||||
|
||||
filters = {
|
||||
'doc_type': 'Sales Order',
|
||||
'range': 'Monthly',
|
||||
'to_date': '2018-03-31',
|
||||
'tree_type': 'Customer',
|
||||
'company': '_Test Company',
|
||||
'from_date': '2017-04-01',
|
||||
'value_quantity': 'Quantity'
|
||||
}
|
||||
|
||||
report = execute(filters)
|
||||
|
||||
expected_data = [
|
||||
{
|
||||
"entity": "_Test Customer 1",
|
||||
"entity_name": "_Test Customer 1",
|
||||
"apr": 0.0,
|
||||
"may": 0.0,
|
||||
"jun": 0.0,
|
||||
"jul": 0.0,
|
||||
"aug": 0.0,
|
||||
"sep": 0.0,
|
||||
"oct": 0.0,
|
||||
"nov": 0.0,
|
||||
"dec": 0.0,
|
||||
"jan": 0.0,
|
||||
"feb": 20.0,
|
||||
"mar": 0.0,
|
||||
"total":20.0
|
||||
},
|
||||
{
|
||||
"entity": "_Test Customer 3",
|
||||
"entity_name": "_Test Customer 3",
|
||||
"apr": 0.0,
|
||||
"may": 0.0,
|
||||
"jun": 20.0,
|
||||
"jul": 10.0,
|
||||
"aug": 0.0,
|
||||
"sep": 0.0,
|
||||
"oct": 0.0,
|
||||
"nov": 0.0,
|
||||
"dec": 0.0,
|
||||
"jan": 0.0,
|
||||
"feb": 0.0,
|
||||
"mar": 0.0,
|
||||
"total": 30.0
|
||||
},
|
||||
{
|
||||
"entity": "_Test Customer 2",
|
||||
"entity_name": "_Test Customer 2",
|
||||
"apr": 0.0,
|
||||
"may": 0.0,
|
||||
"jun": 0.0,
|
||||
"jul": 0.0,
|
||||
"aug": 0.0,
|
||||
"sep": 15.0,
|
||||
"oct": 10.0,
|
||||
"nov": 0.0,
|
||||
"dec": 0.0,
|
||||
"jan": 0.0,
|
||||
"feb": 0.0,
|
||||
"mar": 0.0,
|
||||
"total":25.0
|
||||
}
|
||||
]
|
||||
self.assertEqual(expected_data, report[1])
|
||||
|
||||
def create_sales_order():
|
||||
frappe.set_user("Administrator")
|
||||
|
||||
make_sales_order(qty=10, customer = "_Test Customer 1", transaction_date='2018-02-10')
|
||||
make_sales_order(qty=10, customer = "_Test Customer 1", transaction_date='2018-02-15')
|
||||
make_sales_order(qty=15, customer = "_Test Customer 2", transaction_date='2017-09-23')
|
||||
make_sales_order(qty=10, customer = "_Test Customer 2", transaction_date='2017-10-10')
|
||||
make_sales_order(qty=20, customer = "_Test Customer 3", transaction_date='2017-06-15')
|
||||
make_sales_order(qty=10, customer = "_Test Customer 3", transaction_date='2017-07-10')
|
@ -1,5 +1,6 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_events_in_timeline": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 1,
|
||||
"allow_rename": 1,
|
||||
@ -723,6 +724,38 @@
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "standard_working_hours",
|
||||
"fieldtype": "Float",
|
||||
"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": "Standard Working Hours",
|
||||
"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_in_quick_entry": 0,
|
||||
@ -837,7 +870,7 @@
|
||||
"label": "Create Chart Of Accounts Based On",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "\nStandard Template\nExisting Company",
|
||||
"options": "\nStandard Template\nExisting Company",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
@ -871,7 +904,7 @@
|
||||
"label": "Chart Of Accounts Template",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"options": "",
|
||||
"options": "",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
@ -1158,39 +1191,39 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "round_off_cost_center",
|
||||
"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": "Round Off Cost Center",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Cost Center",
|
||||
"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,
|
||||
"fieldname": "round_off_cost_center",
|
||||
"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": "Round Off Cost Center",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Cost Center",
|
||||
"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_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "write_off_account",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
@ -1491,7 +1524,7 @@
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "eval:!doc.__islocal",
|
||||
"fieldname": "default_deferred_expense_account",
|
||||
"fieldname": "default_deferred_expense_account",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 1,
|
||||
@ -1500,7 +1533,7 @@
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Default Deferred Expense Account",
|
||||
"label": "Default Deferred Expense Account",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"options": "Account",
|
||||
@ -1525,7 +1558,7 @@
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "eval:!doc.__islocal",
|
||||
"fieldname": "default_payroll_payable_account",
|
||||
"fieldname": "default_payroll_payable_account",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 1,
|
||||
@ -1534,7 +1567,7 @@
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Default Payroll Payable Account",
|
||||
"label": "Default Payroll Payable Account",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"options": "Account",
|
||||
@ -1558,20 +1591,20 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "eval:!doc.__islocal",
|
||||
"fieldname": "default_expense_claim_payable_account",
|
||||
"depends_on": "eval:!doc.__islocal",
|
||||
"fieldname": "default_expense_claim_payable_account",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 1,
|
||||
"ignore_user_permissions": 1,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Default Expense Claim Payable Account",
|
||||
"label": "Default Expense Claim Payable Account",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"options": "Account",
|
||||
"no_copy": 1,
|
||||
"options": "Account",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
@ -2870,8 +2903,8 @@
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"menu_index": 0,
|
||||
"modified": "2018-09-13 10:00:47.915706",
|
||||
"modified_by": "Administrator",
|
||||
"modified": "2018-10-24 12:57:46.776452",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Setup",
|
||||
"name": "Company",
|
||||
"owner": "Administrator",
|
||||
|
@ -13,7 +13,7 @@ def get_data():
|
||||
'goal_doctype_link': 'company',
|
||||
'goal_field': 'base_grand_total',
|
||||
'date_field': 'posting_date',
|
||||
'filter_str': 'status != "Draft"',
|
||||
'filter_str': 'docstatus = 1',
|
||||
'aggregation': 'sum'
|
||||
},
|
||||
|
||||
|
@ -98,7 +98,7 @@ def get_exchange_rate(from_currency, to_currency, transaction_date=None, args=No
|
||||
|
||||
if not value:
|
||||
import requests
|
||||
api_url = "https://frankfurter.erpnext.org/{0}".format(transaction_date)
|
||||
api_url = "https://frankfurter.app/{0}".format(transaction_date)
|
||||
response = requests.get(api_url, params={
|
||||
"base": from_currency,
|
||||
"symbols": to_currency
|
||||
|
@ -21,6 +21,9 @@ frappe.ui.form.on("Delivery Note", {
|
||||
return (doc.docstatus==1 || doc.qty<=doc.actual_qty) ? "green" : "orange"
|
||||
})
|
||||
|
||||
erpnext.queries.setup_queries(frm, "Warehouse", function() {
|
||||
return erpnext.queries.warehouse(frm.doc);
|
||||
});
|
||||
erpnext.queries.setup_warehouse_query(frm);
|
||||
|
||||
frm.set_query('project', function(doc) {
|
||||
|
@ -1,5 +1,6 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_events_in_timeline": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 1,
|
||||
"allow_rename": 0,
|
||||
@ -1333,6 +1334,169 @@
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "sec_warehouse",
|
||||
"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_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "set_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": "Set Source Warehouse",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Warehouse",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 1,
|
||||
"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_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "col_break_warehouse",
|
||||
"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_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"description": "Required only for sample item.",
|
||||
"fieldname": "to_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": 1,
|
||||
"label": "To Warehouse",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "to_warehouse",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Warehouse",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"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_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "items_section",
|
||||
"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": "",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"oldfieldtype": "Section Break",
|
||||
"options": "fa fa-shopping-cart",
|
||||
"permlevel": 0,
|
||||
"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,
|
||||
@ -1341,8 +1505,8 @@
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "items_section",
|
||||
"fieldtype": "Section Break",
|
||||
"fieldname": "scan_barcode",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
@ -1350,12 +1514,11 @@
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "",
|
||||
"label": "Scan Barcode",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"oldfieldtype": "Section Break",
|
||||
"options": "fa fa-shopping-cart",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
@ -3751,73 +3914,38 @@
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"description": "Required only for sample item.",
|
||||
"fieldname": "to_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": 1,
|
||||
"label": "To Warehouse",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "to_warehouse",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Warehouse",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"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_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "excise_page",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 1,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Excise Page Number",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"oldfieldname": "excise_page",
|
||||
"oldfieldtype": "Data",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"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_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "excise_page",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 1,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_global_search": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Excise Page Number",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"oldfieldname": "excise_page",
|
||||
"oldfieldtype": "Data",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"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
|
||||
},
|
||||
{
|
||||
@ -4168,7 +4296,7 @@
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"menu_index": 0,
|
||||
"modified": "2018-10-06 14:25:15.326772",
|
||||
"modified": "2018-11-12 20:01:34.432403",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Delivery Note",
|
||||
@ -4282,4 +4410,4 @@
|
||||
"track_changes": 1,
|
||||
"track_seen": 1,
|
||||
"track_views": 0
|
||||
}
|
||||
}
|
||||
|
@ -10,5 +10,47 @@ frappe.listview_settings['Delivery Note'] = {
|
||||
} else if (doc.grand_total === 0 || flt(doc.per_billed, 2) == 100) {
|
||||
return [__("Completed"), "green", "per_billed,=,100"];
|
||||
}
|
||||
},
|
||||
onload: function (doclist) {
|
||||
const action = () => {
|
||||
const selected_docs = doclist.get_checked_items();
|
||||
const docnames = doclist.get_checked_items(true);
|
||||
|
||||
if (selected_docs.length > 0) {
|
||||
for (let doc of selected_docs) {
|
||||
if (!doc.docstatus) {
|
||||
frappe.throw(__("Cannot create a Delivery Trip from Draft documents."));
|
||||
}
|
||||
};
|
||||
|
||||
frappe.new_doc("Delivery Trip")
|
||||
.then(() => {
|
||||
// Empty out the child table before inserting new ones
|
||||
cur_frm.set_value("delivery_stops", []);
|
||||
|
||||
// We don't want to use `map_current_doc` since it brings up
|
||||
// the dialog to select more items. We just want the mapper
|
||||
// function to be called.
|
||||
frappe.call({
|
||||
type: "POST",
|
||||
method: "frappe.model.mapper.map_docs",
|
||||
args: {
|
||||
"method": "erpnext.stock.doctype.delivery_note.delivery_note.make_delivery_trip",
|
||||
"source_names": docnames,
|
||||
"target_doc": cur_frm.doc
|
||||
},
|
||||
callback: function (r) {
|
||||
if (!r.exc) {
|
||||
frappe.model.sync(r.message);
|
||||
cur_frm.dirty();
|
||||
cur_frm.refresh();
|
||||
}
|
||||
}
|
||||
});
|
||||
})
|
||||
};
|
||||
};
|
||||
|
||||
doclist.page.add_actions_menu_item(__('Create Delivery Trip'), action, false);
|
||||
}
|
||||
};
|
||||
|
@ -1,5 +1,6 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_events_in_timeline": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
@ -173,6 +174,39 @@
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 1,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "eval:doc.docstatus==1",
|
||||
"fieldname": "visited",
|
||||
"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": "Visited",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 1,
|
||||
"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_in_quick_entry": 0,
|
||||
@ -762,7 +796,7 @@
|
||||
"issingle": 0,
|
||||
"istable": 1,
|
||||
"max_attachments": 0,
|
||||
"modified": "2018-10-11 22:32:27.450906",
|
||||
"modified": "2018-10-16 05:23:25.661542",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Delivery Stop",
|
||||
|
@ -3,6 +3,8 @@
|
||||
|
||||
frappe.ui.form.on('Delivery Trip', {
|
||||
setup: function (frm) {
|
||||
frm.set_indicator_formatter('customer', (stop) => (stop.visited) ? "green" : "orange");
|
||||
|
||||
frm.set_query("driver", function () {
|
||||
return {
|
||||
filters: {
|
||||
|
@ -1,5 +1,6 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_events_in_timeline": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
@ -540,7 +541,7 @@
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"allow_on_submit": 1,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
@ -568,6 +569,70 @@
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "status",
|
||||
"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": 1,
|
||||
"label": "Status",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"options": "Draft\nScheduled\nIn Transit\nCompleted\nCancelled",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 1,
|
||||
"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_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "cb_more_info",
|
||||
"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_in_quick_entry": 0,
|
||||
@ -611,7 +676,7 @@
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2018-10-11 22:32:04.355068",
|
||||
"modified": "2018-10-22 08:25:42.323147",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Delivery Trip",
|
||||
@ -663,6 +728,7 @@
|
||||
"show_name_in_global_search": 0,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"title_field": "driver_name",
|
||||
"track_changes": 0,
|
||||
"track_seen": 0,
|
||||
"track_views": 0
|
||||
|
@ -27,9 +27,14 @@ class DeliveryTrip(Document):
|
||||
self.validate_stop_addresses()
|
||||
|
||||
def on_submit(self):
|
||||
self.update_status()
|
||||
self.update_delivery_notes()
|
||||
|
||||
def on_update_after_submit(self):
|
||||
self.update_status()
|
||||
|
||||
def on_cancel(self):
|
||||
self.update_status()
|
||||
self.update_delivery_notes(delete=True)
|
||||
|
||||
def validate_stop_addresses(self):
|
||||
@ -37,6 +42,22 @@ class DeliveryTrip(Document):
|
||||
if not stop.customer_address:
|
||||
stop.customer_address = get_address_display(frappe.get_doc("Address", stop.address).as_dict())
|
||||
|
||||
def update_status(self):
|
||||
status = {
|
||||
0: "Draft",
|
||||
1: "Scheduled",
|
||||
2: "Cancelled"
|
||||
}[self.docstatus]
|
||||
|
||||
if self.docstatus == 1:
|
||||
visited_stops = [stop.visited for stop in self.delivery_stops]
|
||||
if all(visited_stops):
|
||||
status = "Completed"
|
||||
elif any(visited_stops):
|
||||
status = "In Transit"
|
||||
|
||||
self.db_set("status", status)
|
||||
|
||||
def update_delivery_notes(self, delete=False):
|
||||
"""
|
||||
Update all connected Delivery Notes with Delivery Trip details
|
||||
|
12
erpnext/stock/doctype/delivery_trip/delivery_trip_list.js
Normal file
12
erpnext/stock/doctype/delivery_trip/delivery_trip_list.js
Normal file
@ -0,0 +1,12 @@
|
||||
frappe.listview_settings['Delivery Trip'] = {
|
||||
add_fields: ["status"],
|
||||
get_indicator: function (doc) {
|
||||
if (in_list(["Cancelled", "Draft"], doc.status)) {
|
||||
return [__(doc.status), "red", "status,=," + doc.status];
|
||||
} else if (in_list(["In Transit", "Scheduled"], doc.status)) {
|
||||
return [__(doc.status), "orange", "status,=," + doc.status];
|
||||
} else if (doc.status === "Completed") {
|
||||
return [__(doc.status), "green", "status,=," + doc.status];
|
||||
}
|
||||
}
|
||||
};
|
@ -9,7 +9,7 @@ import erpnext
|
||||
import frappe
|
||||
from erpnext.stock.doctype.delivery_trip.delivery_trip import get_contact_and_address, notify_customers
|
||||
from erpnext.tests.utils import create_test_contact_and_address
|
||||
from frappe.utils import add_days, now_datetime
|
||||
from frappe.utils import add_days, flt, now_datetime, nowdate
|
||||
|
||||
|
||||
class TestDeliveryTrip(unittest.TestCase):
|
||||
@ -72,6 +72,33 @@ class TestDeliveryTrip(unittest.TestCase):
|
||||
self.assertEqual(len(route_list[0]), 2) # [home_address, locked_stop]
|
||||
self.assertEqual(len(route_list[1]), 3) # [locked_stop, second_stop, home_address]
|
||||
|
||||
def test_delivery_trip_status_draft(self):
|
||||
self.assertEqual(self.delivery_trip.status, "Draft")
|
||||
|
||||
def test_delivery_trip_status_scheduled(self):
|
||||
self.delivery_trip.submit()
|
||||
self.assertEqual(self.delivery_trip.status, "Scheduled")
|
||||
|
||||
def test_delivery_trip_status_cancelled(self):
|
||||
self.delivery_trip.submit()
|
||||
self.delivery_trip.cancel()
|
||||
self.assertEqual(self.delivery_trip.status, "Cancelled")
|
||||
|
||||
def test_delivery_trip_status_in_transit(self):
|
||||
self.delivery_trip.submit()
|
||||
self.delivery_trip.delivery_stops[0].visited = 1
|
||||
self.delivery_trip.save()
|
||||
self.assertEqual(self.delivery_trip.status, "In Transit")
|
||||
|
||||
def test_delivery_trip_status_completed(self):
|
||||
self.delivery_trip.submit()
|
||||
|
||||
for stop in self.delivery_trip.delivery_stops:
|
||||
stop.visited = 1
|
||||
|
||||
self.delivery_trip.save()
|
||||
self.assertEqual(self.delivery_trip.status, "Completed")
|
||||
|
||||
|
||||
def create_driver():
|
||||
if not frappe.db.exists("Driver", "Newton Scmander"):
|
||||
@ -108,11 +135,11 @@ def create_vehicle():
|
||||
"make": "Maruti",
|
||||
"model": "PCM",
|
||||
"last_odometer": 5000,
|
||||
"acquisition_date": frappe.utils.nowdate(),
|
||||
"acquisition_date": nowdate(),
|
||||
"location": "Mumbai",
|
||||
"chassis_no": "1234ABCD",
|
||||
"uom": "Litre",
|
||||
"vehicle_value": frappe.utils.flt(500000)
|
||||
"vehicle_value": flt(500000)
|
||||
})
|
||||
vehicle.insert()
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_events_in_timeline": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 1,
|
||||
"allow_rename": 0,
|
||||
@ -312,6 +313,38 @@
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "scan_barcode",
|
||||
"fieldtype": "Data",
|
||||
"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": "Scan Barcode",
|
||||
"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": 1,
|
||||
"allow_in_quick_entry": 0,
|
||||
@ -826,7 +859,7 @@
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"menu_index": 0,
|
||||
"modified": "2018-09-05 07:28:01.070112",
|
||||
"modified": "2018-10-18 04:41:56.818108",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Material Request",
|
||||
|
@ -21,26 +21,9 @@ frappe.ui.form.on("Purchase Receipt", {
|
||||
})
|
||||
},
|
||||
onload: function(frm) {
|
||||
$.each(["warehouse", "rejected_warehouse"], function(i, field) {
|
||||
frm.set_query(field, "items", function() {
|
||||
return {
|
||||
filters: [
|
||||
["Warehouse", "company", "in", ["", cstr(frm.doc.company)]],
|
||||
["Warehouse", "is_group", "=", 0]
|
||||
]
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
frm.set_query("supplier_warehouse", function() {
|
||||
return {
|
||||
filters: [
|
||||
["Warehouse", "company", "in", ["", cstr(frm.doc.company)]],
|
||||
["Warehouse", "is_group", "=", 0]
|
||||
]
|
||||
}
|
||||
erpnext.queries.setup_queries(frm, "Warehouse", function() {
|
||||
return erpnext.queries.warehouse(frm.doc);
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
onload_post_render: function(frm) {
|
||||
|
@ -1,5 +1,6 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_events_in_timeline": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 1,
|
||||
"allow_rename": 0,
|
||||
@ -1071,6 +1072,211 @@
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "sec_warehouse",
|
||||
"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_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "set_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": "Set Accepted Warehouse",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "Warehouse",
|
||||
"permlevel": 0,
|
||||
"precision": "",
|
||||
"print_hide": 1,
|
||||
"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_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"description": "Warehouse where you are maintaining stock of rejected items",
|
||||
"fieldname": "rejected_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": "Rejected Warehouse",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "rejected_warehouse",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Warehouse",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"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_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "col_break_warehouse",
|
||||
"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,
|
||||
"label": "",
|
||||
"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_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "No",
|
||||
"description": "",
|
||||
"fieldname": "is_subcontracted",
|
||||
"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": "Raw Materials Supplied",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"oldfieldname": "is_subcontracted",
|
||||
"oldfieldtype": "Select",
|
||||
"options": "No\nYes",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"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_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "eval:doc.is_subcontracted==\"Yes\"",
|
||||
"description": "",
|
||||
"fieldname": "supplier_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": "Supplier Warehouse",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "supplier_warehouse",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Warehouse",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"print_hide_if_no_value": 0,
|
||||
"print_width": "50px",
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0,
|
||||
"width": "50px"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
@ -1171,6 +1377,75 @@
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 1,
|
||||
"collapsible_depends_on": "supplied_items",
|
||||
"columns": 0,
|
||||
"description": "",
|
||||
"fieldname": "raw_material_details",
|
||||
"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": "Raw Materials Supplied",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"oldfieldtype": "Section Break",
|
||||
"options": "fa fa-table",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"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_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "supplied_items",
|
||||
"fieldtype": "Table",
|
||||
"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": "Supplied Items",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "pr_raw_material_details",
|
||||
"oldfieldtype": "Table",
|
||||
"options": "Purchase Receipt Item Supplied",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"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_in_quick_entry": 0,
|
||||
@ -2623,148 +2898,6 @@
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 1,
|
||||
"collapsible_depends_on": "supplied_items",
|
||||
"columns": 0,
|
||||
"description": "",
|
||||
"fieldname": "raw_material_details",
|
||||
"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": "Raw Materials Supplied",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"oldfieldtype": "Section Break",
|
||||
"options": "fa fa-table",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"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_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"default": "No",
|
||||
"description": "",
|
||||
"fieldname": "is_subcontracted",
|
||||
"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": "Raw Materials Supplied",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"oldfieldname": "is_subcontracted",
|
||||
"oldfieldtype": "Select",
|
||||
"options": "No\nYes",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"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_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"description": "",
|
||||
"fieldname": "supplier_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": "Supplier Warehouse",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "supplier_warehouse",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Warehouse",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"print_hide_if_no_value": 0,
|
||||
"print_width": "50px",
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0,
|
||||
"width": "50px"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "supplied_items",
|
||||
"fieldtype": "Table",
|
||||
"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": "Supplied Items",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "pr_raw_material_details",
|
||||
"oldfieldtype": "Table",
|
||||
"options": "Purchase Receipt Item Supplied",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"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_in_quick_entry": 0,
|
||||
@ -2901,41 +3034,6 @@
|
||||
"unique": 0,
|
||||
"width": "150px"
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"description": "Warehouse where you are maintaining stock of rejected items",
|
||||
"fieldname": "rejected_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": "Rejected Warehouse",
|
||||
"length": 0,
|
||||
"no_copy": 1,
|
||||
"oldfieldname": "rejected_warehouse",
|
||||
"oldfieldtype": "Link",
|
||||
"options": "Warehouse",
|
||||
"permlevel": 0,
|
||||
"print_hide": 1,
|
||||
"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_in_quick_entry": 0,
|
||||
@ -3610,7 +3708,7 @@
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"menu_index": 0,
|
||||
"modified": "2018-08-21 14:44:34.419727",
|
||||
"modified": "2018-11-02 19:59:01.423485",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Purchase Receipt",
|
||||
|
@ -185,7 +185,8 @@ class PurchaseReceipt(BuyingController):
|
||||
if warehouse_account.get(d.warehouse):
|
||||
stock_value_diff = frappe.db.get_value("Stock Ledger Entry",
|
||||
{"voucher_type": "Purchase Receipt", "voucher_no": self.name,
|
||||
"voucher_detail_no": d.name}, "stock_value_difference")
|
||||
"voucher_detail_no": d.name, "warehouse": d.warehouse}, "stock_value_difference")
|
||||
|
||||
if not stock_value_diff:
|
||||
continue
|
||||
gl_entries.append(self.get_gl_dict({
|
||||
|
@ -594,6 +594,11 @@ erpnext.stock.StockEntry = erpnext.stock.StockController.extend({
|
||||
erpnext.utils.add_item(this.frm);
|
||||
},
|
||||
|
||||
scan_barcode: function() {
|
||||
let transaction_controller= new erpnext.TransactionController({frm:this.frm});
|
||||
transaction_controller.scan_barcode();
|
||||
},
|
||||
|
||||
on_submit: function() {
|
||||
this.clean_up();
|
||||
},
|
||||
|
@ -1,5 +1,6 @@
|
||||
{
|
||||
"allow_copy": 0,
|
||||
"allow_events_in_timeline": 0,
|
||||
"allow_guest_to_view": 0,
|
||||
"allow_import": 1,
|
||||
"allow_rename": 0,
|
||||
@ -1044,6 +1045,38 @@
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
"allow_bulk_edit": 0,
|
||||
"allow_in_quick_entry": 0,
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "scan_barcode",
|
||||
"fieldtype": "Data",
|
||||
"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": "Scan Barcode",
|
||||
"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_in_quick_entry": 0,
|
||||
@ -1965,7 +1998,7 @@
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
@ -2048,7 +2081,7 @@
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2018-09-05 06:27:59.630826",
|
||||
"modified": "2018-10-18 04:42:41.452572",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Stock Entry",
|
||||
|
@ -634,19 +634,19 @@ class StockEntry(StockController):
|
||||
|
||||
ret = frappe._dict({
|
||||
'uom' : item.stock_uom,
|
||||
'stock_uom' : item.stock_uom,
|
||||
'stock_uom' : item.stock_uom,
|
||||
'description' : item.description,
|
||||
'image' : item.image,
|
||||
'image' : item.image,
|
||||
'item_name' : item.item_name,
|
||||
'expense_account' : args.get("expense_account"),
|
||||
'cost_center' : get_default_cost_center(args, item, item_group_defaults),
|
||||
'qty' : 0,
|
||||
'transfer_qty' : 0,
|
||||
'qty' : args.get("qty"),
|
||||
'transfer_qty' : args.get('qty'),
|
||||
'conversion_factor' : 1,
|
||||
'batch_no' : '',
|
||||
'batch_no' : '',
|
||||
'actual_qty' : 0,
|
||||
'basic_rate' : 0,
|
||||
'serial_no' : '',
|
||||
'serial_no' : '',
|
||||
'has_serial_no' : item.has_serial_no,
|
||||
'has_batch_no' : item.has_batch_no,
|
||||
'sample_quantity' : item.sample_quantity
|
||||
|
@ -26,8 +26,9 @@ class StockSettings(Document):
|
||||
frappe.msgprint (_("`Freeze Stocks Older Than` should be smaller than %d days.") %stock_frozen_limit)
|
||||
|
||||
# show/hide barcode field
|
||||
frappe.make_property_setter({'fieldname': 'barcodes', 'property': 'hidden',
|
||||
'value': 0 if self.show_barcode_field else 1})
|
||||
for name in ["barcode", "barcodes", "scan_barcode"]:
|
||||
frappe.make_property_setter({'fieldname': name, 'property': 'hidden',
|
||||
'value': 0 if self.show_barcode_field else 1})
|
||||
|
||||
self.cant_change_valuation_method()
|
||||
self.validate_clean_description_html()
|
||||
|
0
erpnext/stock/report/stock_analytics/__init__.py
Normal file
0
erpnext/stock/report/stock_analytics/__init__.py
Normal file
136
erpnext/stock/report/stock_analytics/stock_analytics.js
Normal file
136
erpnext/stock/report/stock_analytics/stock_analytics.js
Normal file
@ -0,0 +1,136 @@
|
||||
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
|
||||
// For license information, please see license.txt
|
||||
/* eslint-disable */
|
||||
|
||||
frappe.query_reports["Stock Analytics"] = {
|
||||
"filters": [
|
||||
{
|
||||
fieldname: "item_group",
|
||||
label: __("Item Group"),
|
||||
fieldtype: "Link",
|
||||
options:"Item Group",
|
||||
default: "",
|
||||
},
|
||||
{
|
||||
fieldname: "item_code",
|
||||
label: __("Item"),
|
||||
fieldtype: "Link",
|
||||
options:"Item",
|
||||
default: "",
|
||||
},
|
||||
{
|
||||
fieldname: "value_quantity",
|
||||
label: __("Value Or Qty"),
|
||||
fieldtype: "Select",
|
||||
options: [
|
||||
{ "value": "Value", "label": __("Value") },
|
||||
{ "value": "Quantity", "label": __("Quantity") }
|
||||
],
|
||||
default: "Value",
|
||||
reqd: 1
|
||||
},
|
||||
{
|
||||
fieldname: "brand",
|
||||
label: __("Brand"),
|
||||
fieldtype: "Link",
|
||||
options:"Brand",
|
||||
default: "",
|
||||
},
|
||||
{
|
||||
fieldname: "warehouse",
|
||||
label: __("Warehouse"),
|
||||
fieldtype: "Link",
|
||||
options:"Warehouse",
|
||||
default: "",
|
||||
},
|
||||
{
|
||||
fieldname: "from_date",
|
||||
label: __("From Date"),
|
||||
fieldtype: "Date",
|
||||
default: frappe.defaults.get_global_default("year_start_date"),
|
||||
reqd: 1
|
||||
},
|
||||
{
|
||||
fieldname:"to_date",
|
||||
label: __("To Date"),
|
||||
fieldtype: "Date",
|
||||
default: frappe.defaults.get_global_default("year_end_date"),
|
||||
reqd: 1
|
||||
},
|
||||
{
|
||||
fieldname: "range",
|
||||
label: __("Range"),
|
||||
fieldtype: "Select",
|
||||
options: [
|
||||
{ "value": "Weekly", "label": __("Weekly") },
|
||||
{ "value": "Monthly", "label": __("Monthly") },
|
||||
{ "value": "Quarterly", "label": __("Quarterly") },
|
||||
{ "value": "Yearly", "label": __("Yearly") }
|
||||
],
|
||||
default: "Monthly",
|
||||
reqd: 1
|
||||
}
|
||||
],
|
||||
"formatter": function(value, row, column, data) {
|
||||
if(!value && (column.fieldname == 'brand' || column.fieldname == 'uom')){
|
||||
value = ""
|
||||
}
|
||||
|
||||
if(Number(value)){
|
||||
value = value.toFixed(2)
|
||||
}
|
||||
|
||||
return value;
|
||||
},
|
||||
get_datatable_options(options) {
|
||||
return Object.assign(options, {
|
||||
checkboxColumn: true,
|
||||
events: {
|
||||
onCheckRow: function(data) {
|
||||
row_name = data[2].content;
|
||||
row_values = data.slice(6).map(function (column) {
|
||||
return column.content;
|
||||
})
|
||||
|
||||
entry = {
|
||||
'name':row_name,
|
||||
'values':row_values
|
||||
}
|
||||
|
||||
let raw_data = frappe.query_report.chart.data;
|
||||
let new_datasets = raw_data.datasets;
|
||||
|
||||
var found = false;
|
||||
|
||||
for(var i=0; i < new_datasets.length;i++){
|
||||
if(new_datasets[i].name == row_name){
|
||||
found = true;
|
||||
new_datasets.splice(i,1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!found){
|
||||
new_datasets.push(entry);
|
||||
}
|
||||
|
||||
let new_data = {
|
||||
labels: raw_data.labels,
|
||||
datasets: new_datasets
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
frappe.query_report.chart.update(new_data)
|
||||
},200)
|
||||
|
||||
|
||||
setTimeout(() => {
|
||||
frappe.query_report.chart.draw(true);
|
||||
}, 800)
|
||||
|
||||
frappe.query_report.raw_chart_data = new_data;
|
||||
},
|
||||
}
|
||||
})
|
||||
},
|
||||
}
|
32
erpnext/stock/report/stock_analytics/stock_analytics.json
Normal file
32
erpnext/stock/report/stock_analytics/stock_analytics.json
Normal file
@ -0,0 +1,32 @@
|
||||
{
|
||||
"add_total_row": 0,
|
||||
"creation": "2018-10-08 12:11:32.133020",
|
||||
"disabled": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "Report",
|
||||
"idx": 0,
|
||||
"is_standard": "Yes",
|
||||
"modified": "2018-10-08 12:18:42.834270",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Stock Analytics",
|
||||
"owner": "Administrator",
|
||||
"prepared_report": 0,
|
||||
"ref_doctype": "Stock Entry",
|
||||
"report_name": "Stock Analytics",
|
||||
"report_type": "Script Report",
|
||||
"roles": [
|
||||
{
|
||||
"role": "Manufacturing Manager"
|
||||
},
|
||||
{
|
||||
"role": "Stock Manager"
|
||||
},
|
||||
{
|
||||
"role": "Stock User"
|
||||
},
|
||||
{
|
||||
"role": "Manufacturing User"
|
||||
}
|
||||
]
|
||||
}
|
185
erpnext/stock/report/stock_analytics/stock_analytics.py
Normal file
185
erpnext/stock/report/stock_analytics/stock_analytics.py
Normal file
@ -0,0 +1,185 @@
|
||||
# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe import _, scrub
|
||||
from frappe.utils import getdate, flt
|
||||
from erpnext.stock.report.stock_balance.stock_balance import (get_items, get_stock_ledger_entries, get_item_details)
|
||||
from erpnext.accounts.utils import get_fiscal_year
|
||||
from six import iteritems
|
||||
|
||||
def execute(filters=None):
|
||||
filters = frappe._dict(filters or {})
|
||||
columns = get_columns(filters)
|
||||
data = get_data(filters)
|
||||
chart = get_chart_data(columns)
|
||||
|
||||
return columns, data, None, chart
|
||||
|
||||
def get_columns(filters):
|
||||
columns = [
|
||||
{
|
||||
"label": _("Item"),
|
||||
"options":"Item",
|
||||
"fieldname": "name",
|
||||
"fieldtype": "Link",
|
||||
"width": 140
|
||||
},
|
||||
{
|
||||
"label": _("Item Name"),
|
||||
"options":"Item",
|
||||
"fieldname": "item_name",
|
||||
"fieldtype": "Link",
|
||||
"width": 140
|
||||
},
|
||||
{
|
||||
"label": _("Item Group"),
|
||||
"options":"Item Group",
|
||||
"fieldname": "item_group",
|
||||
"fieldtype": "Link",
|
||||
"width": 140
|
||||
},
|
||||
{
|
||||
"label": _("Brand"),
|
||||
"fieldname": "brand",
|
||||
"fieldtype": "Data",
|
||||
"width": 120
|
||||
},
|
||||
{
|
||||
"label": _("UOM"),
|
||||
"fieldname": "uom",
|
||||
"fieldtype": "Data",
|
||||
"width": 120
|
||||
}]
|
||||
|
||||
ranges = get_period_date_ranges(filters)
|
||||
|
||||
for dummy, end_date in ranges:
|
||||
period = get_period(end_date, filters)
|
||||
|
||||
columns.append({
|
||||
"label": _(period),
|
||||
"fieldname":scrub(period),
|
||||
"fieldtype": "Float",
|
||||
"width": 120
|
||||
})
|
||||
|
||||
return columns
|
||||
|
||||
def get_period_date_ranges(filters):
|
||||
from dateutil.relativedelta import relativedelta
|
||||
from_date, to_date = getdate(filters.from_date), getdate(filters.to_date)
|
||||
|
||||
increment = {
|
||||
"Monthly": 1,
|
||||
"Quarterly": 3,
|
||||
"Half-Yearly": 6,
|
||||
"Yearly": 12
|
||||
}.get(filters.range,1)
|
||||
|
||||
periodic_daterange = []
|
||||
for dummy in range(1, 53, increment):
|
||||
if filters.range == "Weekly":
|
||||
period_end_date = from_date + relativedelta(days=6)
|
||||
else:
|
||||
period_end_date = from_date + relativedelta(months=increment, days=-1)
|
||||
|
||||
if period_end_date > to_date:
|
||||
period_end_date = to_date
|
||||
periodic_daterange.append([from_date, period_end_date])
|
||||
|
||||
from_date = period_end_date + relativedelta(days=1)
|
||||
if period_end_date == to_date:
|
||||
break
|
||||
|
||||
return periodic_daterange
|
||||
|
||||
def get_period(posting_date, filters):
|
||||
months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
|
||||
|
||||
if filters.range == 'Weekly':
|
||||
period = "Week " + str(posting_date.isocalendar()[1])
|
||||
elif filters.range == 'Monthly':
|
||||
period = months[posting_date.month - 1]
|
||||
elif filters.range == 'Quarterly':
|
||||
period = "Quarter " + str(((posting_date.month-1)//3)+1)
|
||||
else:
|
||||
year = get_fiscal_year(posting_date, company=filters.company)
|
||||
period = str(year[2])
|
||||
|
||||
return period
|
||||
|
||||
|
||||
def get_periodic_data(entry, filters):
|
||||
periodic_data = {}
|
||||
for d in entry:
|
||||
period = get_period(d.posting_date, filters)
|
||||
bal_qty = 0
|
||||
|
||||
if d.voucher_type == "Stock Reconciliation":
|
||||
if periodic_data.get(d.item_code):
|
||||
bal_qty = periodic_data[d.item_code]["balance"]
|
||||
|
||||
qty_diff = d.qty_after_transaction - bal_qty
|
||||
else:
|
||||
qty_diff = d.actual_qty
|
||||
|
||||
if filters["value_quantity"] == 'Quantity':
|
||||
value = qty_diff
|
||||
else:
|
||||
value = d.stock_value_difference
|
||||
|
||||
periodic_data.setdefault(d.item_code, {}).setdefault(period, 0.0)
|
||||
periodic_data.setdefault(d.item_code, {}).setdefault("balance", 0.0)
|
||||
|
||||
periodic_data[d.item_code]["balance"] += value
|
||||
periodic_data[d.item_code][period] = periodic_data[d.item_code]["balance"]
|
||||
|
||||
|
||||
return periodic_data
|
||||
|
||||
def get_data(filters):
|
||||
data = []
|
||||
items = get_items(filters)
|
||||
sle = get_stock_ledger_entries(filters, items)
|
||||
item_details = get_item_details(items, sle, filters)
|
||||
periodic_data = get_periodic_data(sle, filters)
|
||||
ranges = get_period_date_ranges(filters)
|
||||
|
||||
for dummy, item_data in iteritems(item_details):
|
||||
row = {
|
||||
"name": item_data.name,
|
||||
"item_name": item_data.item_name,
|
||||
"item_group": item_data.item_group,
|
||||
"uom": item_data.stock_uom,
|
||||
"brand": item_data.brand,
|
||||
}
|
||||
total = 0
|
||||
for dummy, end_date in ranges:
|
||||
period = get_period(end_date, filters)
|
||||
amount = flt(periodic_data.get(item_data.name, {}).get(period))
|
||||
row[scrub(period)] = amount
|
||||
total += amount
|
||||
row["total"] = total
|
||||
data.append(row)
|
||||
|
||||
return data
|
||||
|
||||
def get_chart_data(columns):
|
||||
labels = [d.get("label") for d in columns[4:]]
|
||||
chart = {
|
||||
"data": {
|
||||
'labels': labels,
|
||||
'datasets':[
|
||||
{ "values": ['0' for d in columns[4:]] }
|
||||
]
|
||||
}
|
||||
}
|
||||
chart["type"] = "line"
|
||||
|
||||
return chart
|
||||
|
||||
|
||||
|
||||
|
@ -108,8 +108,8 @@ def get_price(item_code, price_list, customer_group, company, qty=1):
|
||||
|
||||
uom_conversion_factor = frappe.db.sql("""select C.conversion_factor
|
||||
from `tabUOM Conversion Detail` C
|
||||
inner join `tabItem` I on C.uom = I.sales_uom
|
||||
where C.parent = %s""", item_code)
|
||||
inner join `tabItem` I on C.parent = I.name and C.uom = I.sales_uom
|
||||
where I.name = %s""", item_code)
|
||||
|
||||
uom_conversion_factor = uom_conversion_factor[0][0] if uom_conversion_factor else 1
|
||||
price_obj["formatted_price_sales_uom"] = fmt_money(price_obj["price_list_rate"] * uom_conversion_factor, currency=price_obj["currency"])
|
||||
|
Loading…
x
Reference in New Issue
Block a user