Merge pull request #16253 from chdecultot/sales_summary_correction
[Fix] Filter cancelled and draft payments in sales payment summary
diff --git a/.travis.yml b/.travis.yml
index d77f9ef..f20128d 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -33,7 +33,7 @@
- cd ~/frappe-bench
- bench get-app erpnext $TRAVIS_BUILD_DIR
- bench use test_site
- - bench reinstall --yes
+ - bench reinstall --mariadb-root-username root --mariadb-root-password travis --yes
- bench build
- bench scheduler disable
- sed -i 's/9000/9001/g' sites/common_site_config.json
diff --git a/erpnext/__init__.py b/erpnext/__init__.py
index 0d5ac9d..4197d54 100644
--- a/erpnext/__init__.py
+++ b/erpnext/__init__.py
@@ -5,7 +5,7 @@
from erpnext.hooks import regional_overrides
from frappe.utils import getdate
-__version__ = '10.1.74'
+__version__ = '10.1.76'
def get_default_company(user=None):
'''Get default company for user'''
diff --git a/erpnext/accounts/doctype/pos_profile/pos_profile.js b/erpnext/accounts/doctype/pos_profile/pos_profile.js
index b62d9b0..13d53d1 100755
--- a/erpnext/accounts/doctype/pos_profile/pos_profile.js
+++ b/erpnext/accounts/doctype/pos_profile/pos_profile.js
@@ -37,11 +37,25 @@
return { filters: { doc_type: "Sales Invoice", print_format_type: "Js"} };
});
- frappe.db.get_value('POS Settings', {name: 'POS Settings'}, 'use_pos_in_offline_mode', (r) => {
- is_offline = r && cint(r.use_pos_in_offline_mode)
+ frappe.db.get_value('POS Settings', 'POS Settings', 'use_pos_in_offline_mode', (r) => {
+ const is_offline = r && cint(r.use_pos_in_offline_mode)
frm.toggle_display('offline_pos_section', is_offline);
frm.toggle_display('print_format_for_online', !is_offline);
});
+
+ frm.set_query('company_address', function(doc) {
+ if(!doc.company) {
+ frappe.throw(__('Please set Company'));
+ }
+
+ return {
+ query: 'frappe.contacts.doctype.address.address.address_query',
+ filters: {
+ link_doctype: 'Company',
+ link_name: doc.company
+ }
+ };
+ });
},
refresh: function(frm) {
@@ -49,11 +63,11 @@
frm.trigger("toggle_display_account_head");
}
},
-
+
company: function(frm) {
frm.trigger("toggle_display_account_head");
},
-
+
toggle_display_account_head: function(frm) {
frm.toggle_display('expense_account',
erpnext.is_perpetual_inventory_enabled(frm.doc.company));
diff --git a/erpnext/accounts/doctype/pos_profile/pos_profile.json b/erpnext/accounts/doctype/pos_profile/pos_profile.json
index 610ed51..077c396 100644
--- a/erpnext/accounts/doctype/pos_profile/pos_profile.json
+++ b/erpnext/accounts/doctype/pos_profile/pos_profile.json
@@ -1,9 +1,10 @@
{
"allow_copy": 0,
+ "allow_events_in_timeline": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 1,
- "autoname": "field:pos_profile_name",
+ "autoname": "Prompt",
"beta": 0,
"creation": "2013-05-24 12:15:51",
"custom": 0,
@@ -13,6 +14,7 @@
"fields": [
{
"allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -40,15 +42,17 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 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": "section_break_2",
"fieldtype": "Section Break",
"hidden": 0,
@@ -70,42 +74,12 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
+ "translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "pos_profile_name",
- "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": "POS Profile Name",
- "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": 1,
- "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,
@@ -134,258 +108,12 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
+ "translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "1",
- "description": "",
- "fieldname": "update_stock",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Update Stock",
- "length": 0,
- "no_copy": 0,
- "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,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "ignore_pricing_rule",
- "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": "Ignore Pricing Rule",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "allow_delete",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Allow Delete",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "allow_user_to_edit_rate",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Allow user to edit Rate",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "allow_user_to_edit_discount",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Allow user to edit Discount",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "allow_print_before_pay",
- "fieldtype": "Check",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Allow Print Before Pay",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "display_items_in_stock",
- "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": "Display Items In Stock",
- "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,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_4",
- "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,
@@ -414,11 +142,12 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
+ "translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -447,16 +176,17 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
+ "translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
- "fetch_from": "company.country",
+ "fetch_from": "company.country",
"fieldname": "country",
"fieldtype": "Read Only",
"hidden": 0,
@@ -480,11 +210,12 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
+ "translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -514,11 +245,12 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
+ "translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -546,15 +278,306 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 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": "company_address",
+ "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": "Company Address",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Address",
+ "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": "column_break_9",
+ "fieldtype": "Column Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "default": "1",
+ "description": "",
+ "fieldname": "update_stock",
+ "fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Update Stock",
+ "length": 0,
+ "no_copy": 0,
+ "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,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "ignore_pricing_rule",
+ "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": "Ignore Pricing Rule",
+ "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": "allow_delete",
+ "fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Allow Delete",
+ "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": "allow_user_to_edit_rate",
+ "fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Allow user to edit Rate",
+ "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": "allow_user_to_edit_discount",
+ "fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Allow user to edit Discount",
+ "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": "allow_print_before_pay",
+ "fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Allow Print Before Pay",
+ "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": "display_items_in_stock",
+ "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": "Display Items In Stock",
+ "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": "section_break_15",
"fieldtype": "Section Break",
"hidden": 0,
@@ -577,11 +600,12 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
+ "translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -609,11 +633,12 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
+ "translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -627,6 +652,7 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
+ "label": "Mode of Payment",
"length": 0,
"no_copy": 0,
"permlevel": 0,
@@ -639,11 +665,12 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
+ "translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -671,11 +698,12 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
+ "translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -690,6 +718,7 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
+ "label": "",
"length": 0,
"no_copy": 0,
"permlevel": 0,
@@ -702,15 +731,17 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 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": "Only show Items from these Item Groups",
"fieldname": "item_groups",
"fieldtype": "Table",
"hidden": 0,
@@ -734,11 +765,12 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
+ "translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -764,15 +796,17 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 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": "Only show Customer of these Customer Groups",
"fieldname": "customer_groups",
"fieldtype": "Table",
"hidden": 0,
@@ -796,11 +830,12 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
+ "translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -815,6 +850,7 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
+ "label": "Print Settings",
"length": 0,
"no_copy": 0,
"permlevel": 0,
@@ -827,11 +863,12 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
+ "translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -859,11 +896,12 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
+ "translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
@@ -892,44 +930,12 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
+ "translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "select_print_heading",
- "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": "Print Heading",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "select_print_heading",
- "oldfieldtype": "Select",
- "options": "Print Heading",
- "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,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -955,44 +961,12 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
+ "translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "selling_price_list",
- "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": "Price List",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "price_list_name",
- "oldfieldtype": "Select",
- "options": "Price List",
- "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,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1021,50 +995,18 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
+ "translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
- "allow_on_submit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"columns": 0,
- "fieldname": "apply_discount",
- "fieldtype": "Check",
- "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": "Apply Discount",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "Grand Total",
- "depends_on": "",
- "fieldname": "apply_discount_on",
- "fieldtype": "Select",
+ "fieldname": "select_print_heading",
+ "fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
@@ -1072,12 +1014,13 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
- "label": "Apply Discount On",
+ "label": "Print Heading",
"length": 0,
"no_copy": 0,
- "options": "Grand Total\nNet Total",
+ "oldfieldname": "select_print_heading",
+ "oldfieldtype": "Select",
+ "options": "Print Heading",
"permlevel": 0,
- "precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
@@ -1086,11 +1029,12 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
+ "translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1105,7 +1049,7 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
- "label": "Offline POS Section",
+ "label": "Offline POS Settings",
"length": 0,
"no_copy": 0,
"permlevel": 0,
@@ -1118,11 +1062,12 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
+ "translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1152,11 +1097,12 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
+ "translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1182,11 +1128,12 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
+ "translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1215,11 +1162,12 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
+ "translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1247,11 +1195,12 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
+ "translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1279,11 +1228,46 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 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": "selling_price_list",
+ "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": "Price List",
+ "length": 0,
+ "no_copy": 0,
+ "oldfieldname": "price_list_name",
+ "oldfieldtype": "Select",
+ "options": "Price List",
+ "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,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1312,11 +1296,12 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
+ "translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1345,11 +1330,12 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
+ "translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1377,11 +1363,12 @@
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
+ "translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1409,11 +1396,12 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
+ "translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1439,11 +1427,12 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
+ "translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1472,11 +1461,12 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
+ "translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1504,11 +1494,12 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
+ "translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1537,11 +1528,12 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 0,
+ "translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
@@ -1570,7 +1562,42 @@
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
- "translatable": 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": "Grand Total",
+ "depends_on": "",
+ "fieldname": "apply_discount_on",
+ "fieldtype": "Select",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Apply Discount On",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Grand Total\nNet Total",
+ "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
}
],
@@ -1585,7 +1612,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2018-09-05 12:43:37.272875",
+ "modified": "2018-12-13 13:36:22.045519",
"modified_by": "Administrator",
"module": "Accounts",
"name": "POS Profile",
@@ -1633,11 +1660,12 @@
"quick_entry": 0,
"read_only": 0,
"read_only_onload": 0,
- "search_fields": "pos_profile_name",
+ "search_fields": "",
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
- "title_field": "pos_profile_name",
+ "title_field": "",
"track_changes": 0,
- "track_seen": 0
-}
+ "track_seen": 0,
+ "track_views": 0
+}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/pos_profile/pos_profile.py b/erpnext/accounts/doctype/pos_profile/pos_profile.py
index bf2e20c..723ef43 100644
--- a/erpnext/accounts/doctype/pos_profile/pos_profile.py
+++ b/erpnext/accounts/doctype/pos_profile/pos_profile.py
@@ -127,25 +127,26 @@
'txt': '%%%s%%' % txt
}
- pos_profile = frappe.db.sql("""select pf.name, pf.pos_profile_name
+ pos_profile = frappe.db.sql("""select pf.name
from
`tabPOS Profile` pf, `tabPOS Profile User` pfu
where
pfu.parent = pf.name and pfu.user = %(user)s and pf.company = %(company)s
- and (pf.name like %(txt)s or pf.pos_profile_name like %(txt)s)
+ and (pf.name like %(txt)s)
and pf.disabled = 0 limit %(start)s, %(page_len)s""", args)
if not pos_profile:
del args['user']
- pos_profile = frappe.db.sql("""select pf.name, pf.pos_profile_name
+ pos_profile = frappe.db.sql("""select pf.name
from
`tabPOS Profile` pf left join `tabPOS Profile User` pfu
on
pf.name = pfu.parent
where
- ifnull(pfu.user, '') = '' and pf.company = %(company)s and
- (pf.name like %(txt)s or pf.pos_profile_name like %(txt)s)
+ ifnull(pfu.user, '') = ''
+ and pf.company = %(company)s
+ and pf.name like %(txt)s
and pf.disabled = 0""", args)
return pos_profile
diff --git a/erpnext/accounts/doctype/pos_profile/test_pos_profile.py b/erpnext/accounts/doctype/pos_profile/test_pos_profile.py
index c1b033c..58f1216 100644
--- a/erpnext/accounts/doctype/pos_profile/test_pos_profile.py
+++ b/erpnext/accounts/doctype/pos_profile/test_pos_profile.py
@@ -40,7 +40,6 @@
"expense_account": "_Test Account Cost for Goods Sold - _TC",
"income_account": "Sales - _TC",
"name": "_Test POS Profile",
- "pos_profile_name": "_Test POS Profile",
"naming_series": "_T-POS Profile-",
"selling_price_list": "_Test Price List",
"territory": "_Test Territory",
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
index 1bb7c97..bfdf451 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
@@ -830,6 +830,10 @@
return
tax_withholding_details = get_party_tax_withholding_details(self)
+
+ if not tax_withholding_details:
+ return
+
accounts = []
for d in self.taxes:
if d.account_head == tax_withholding_details.get("account_head"):
@@ -839,6 +843,12 @@
if not accounts or tax_withholding_details.get("account_head") not in accounts:
self.append("taxes", tax_withholding_details)
+ to_remove = [d for d in self.taxes
+ if not d.tax_amount and d.account_head == tax_withholding_details.get("account_head")]
+
+ for d in to_remove:
+ self.remove(d)
+
# calculate totals again after applying TDS
self.calculate_taxes_and_totals()
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
index a4588b3..91a44b3 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
@@ -313,6 +313,10 @@
erpnext.setup_serial_no();
},
+ packed_items_on_form_rendered: function(doc, grid_row) {
+ erpnext.setup_serial_no();
+ },
+
make_sales_return: function() {
frappe.model.open_mapped_doc({
method: "erpnext.accounts.doctype.sales_invoice.sales_invoice.make_sales_return",
@@ -585,7 +589,7 @@
frm.set_query('company_address', function(doc) {
if(!doc.company) {
- frappe.throw(_('Please set Company'));
+ frappe.throw(__('Please set Company'));
}
return {
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index 6387003..6072fb8 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -131,7 +131,7 @@
#validate amount in mode of payments for returned invoices for pos must be negative
if self.is_pos and self.is_return:
self.verify_payment_amount_is_negative()
-
+
if self.redeem_loyalty_points and self.loyalty_program and self.loyalty_points:
validate_loyalty_points(self, self.loyalty_points)
@@ -324,7 +324,8 @@
return {
"print_format": print_format,
"allow_edit_rate": pos.get("allow_user_to_edit_rate"),
- "allow_edit_discount": pos.get("allow_user_to_edit_discount")
+ "allow_edit_discount": pos.get("allow_user_to_edit_discount"),
+ "campaign": pos.get("campaign")
}
def update_time_sheet(self, sales_invoice):
@@ -397,7 +398,7 @@
self.account_for_change_amount = pos.get('account_for_change_amount')
for fieldname in ('territory', 'naming_series', 'currency', 'taxes_and_charges', 'letter_head', 'tc_name',
- 'selling_price_list', 'company', 'select_print_heading', 'cash_bank_account',
+ 'selling_price_list', 'company', 'select_print_heading', 'cash_bank_account', 'company_address',
'write_off_account', 'write_off_cost_center', 'apply_discount_on'):
if (not for_validate) or (for_validate and not self.get(fieldname)):
self.set(fieldname, pos.get(fieldname))
@@ -713,7 +714,7 @@
return gl_entries
def make_customer_gl_entry(self, gl_entries):
- # Checked both rounding_adjustment and rounded_total
+ # Checked both rounding_adjustment and rounded_total
# because rounded_total had value even before introcution of posting GLE based on rounded total
grand_total = self.rounded_total if (self.rounding_adjustment and self.rounded_total) else self.grand_total
if grand_total:
@@ -1026,7 +1027,7 @@
def verify_payment_amount_is_negative(self):
for entry in self.payments:
if entry.amount > 0:
- frappe.throw(_("Row #{0} (Payment Table): Amount must be negative").format(entry.idx))
+ frappe.throw(_("Row #{0} (Payment Table): Amount must be negative").format(entry.idx))
# collection of the loyalty points, create the ledger entry for that.
def make_loyalty_point_entry(self):
diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
index 94037c7..f9364e2 100644
--- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
+# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
@@ -375,7 +375,7 @@
si.insert()
self.assertEqual(si.net_total, 4600)
-
+
self.assertEqual(si.get("taxes")[0].tax_amount, 874.0)
self.assertEqual(si.get("taxes")[0].total, 5474.0)
@@ -405,12 +405,12 @@
self.assertEqual(si.total, 975)
self.assertEqual(si.net_total, 900)
-
+
self.assertEqual(si.get("taxes")[0].tax_amount, 216.0)
self.assertEqual(si.get("taxes")[0].total, 1116.0)
self.assertEqual(si.grand_total, 1116.0)
-
+
def test_inclusive_rate_validations(self):
si = frappe.copy_doc(test_records[2])
for i, tax in enumerate(si.get("taxes")):
@@ -552,7 +552,7 @@
self.assertEqual(si.grand_total, 1215.90)
self.assertEqual(si.rounding_adjustment, 0.01)
self.assertEqual(si.base_rounding_adjustment, 0.50)
-
+
def test_outstanding(self):
w = self.make()
@@ -762,6 +762,20 @@
set_perpetual_inventory(0)
frappe.db.sql("delete from `tabPOS Profile`")
+
+ def test_pos_si_without_payment(self):
+ set_perpetual_inventory()
+ make_pos_profile()
+
+ pos = copy.deepcopy(test_records[1])
+ pos["is_pos"] = 1
+ pos["update_stock"] = 1
+
+ si = frappe.copy_doc(pos)
+ si.insert()
+
+ # Check that the invoice cannot be submitted without payments
+ self.assertRaises(frappe.ValidationError, si.submit)
def test_sales_invoice_gl_entry_with_perpetual_inventory_no_item_code(self):
set_perpetual_inventory()
@@ -923,7 +937,7 @@
self.assertRaises(SerialNoWarehouseError, si.submit)
def test_serial_numbers_against_delivery_note(self):
- """
+ """
check if the sales invoice item serial numbers and the delivery note items
serial numbers are same
"""
@@ -1238,7 +1252,7 @@
def test_item_wise_tax_breakup_india(self):
frappe.flags.country = "India"
-
+
si = self.create_si_to_test_tax_breakup()
itemised_tax, itemised_taxable_amount = get_itemised_tax_breakup_data(si)
@@ -1256,12 +1270,12 @@
self.assertEqual(itemised_tax, expected_itemised_tax)
self.assertEqual(itemised_taxable_amount, expected_itemised_taxable_amount)
-
+
frappe.flags.country = None
def test_item_wise_tax_breakup_outside_india(self):
frappe.flags.country = "United States"
-
+
si = self.create_si_to_test_tax_breakup()
itemised_tax, itemised_taxable_amount = get_itemised_tax_breakup_data(si)
@@ -1287,7 +1301,7 @@
self.assertEqual(itemised_tax, expected_itemised_tax)
self.assertEqual(itemised_taxable_amount, expected_itemised_taxable_amount)
-
+
frappe.flags.country = None
def create_si_to_test_tax_breakup(self):
@@ -1375,7 +1389,7 @@
shipping_rule = create_shipping_rule(shipping_rule_type = "Selling", shipping_rule_name = "Shipping Rule - Sales Invoice Test")
si = frappe.copy_doc(test_records[2])
-
+
si.shipping_rule = shipping_rule.name
si.insert()
@@ -1392,14 +1406,14 @@
"cost_center": shipping_rule.cost_center,
"tax_amount": shipping_amount,
"description": shipping_rule.name
- }
+ }
si.append("taxes", shipping_charge)
si.save()
self.assertEqual(si.net_total, 1250)
self.assertEqual(si.total_taxes_and_charges, 577.05)
- self.assertEqual(si.grand_total, 1827.05)
+ self.assertEqual(si.grand_total, 1827.05)
def test_create_invoice_without_terms(self):
si = create_sales_invoice(do_not_save=1)
@@ -1496,7 +1510,7 @@
for gle in gl_entries:
self.assertEqual(expected_values[gle.account]["cost_center"], gle.cost_center)
-
+
accounts_settings.allow_cost_center_in_entry_of_bs_account = 0
accounts_settings.save()
@@ -1524,9 +1538,9 @@
"warehouse": args.warehouse or "_Test Warehouse - _TC",
"qty": args.qty or 1,
"rate": args.rate or 100,
- "income_account": "Sales - _TC",
- "expense_account": "Cost of Goods Sold - _TC",
- "cost_center": "_Test Cost Center - _TC",
+ "income_account": args.income_account or "Sales - _TC",
+ "expense_account": args.expense_account or "Cost of Goods Sold - _TC",
+ "cost_center": args.cost_center or "_Test Cost Center - _TC",
"serial_no": args.serial_no
})
diff --git a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py
index f553cc0..6c31e9e 100644
--- a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py
+++ b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py
@@ -24,6 +24,7 @@
.format(tax_withholding_category, ref_doc.company))
tds_amount = get_tds_amount(ref_doc, tax_details, fy)
tax_row = get_tax_row(tax_details, tds_amount)
+
return tax_row
def get_tax_withholding_details(tax_withholding_category, fiscal_year, company):
@@ -62,46 +63,64 @@
def get_tds_amount(ref_doc, tax_details, fiscal_year_details):
fiscal_year, year_start_date, year_end_date = fiscal_year_details
tds_amount = 0
+ tds_deducted = 0
- def _get_tds():
- tds_amount = 0
- if not tax_details.threshold or ref_doc.net_total >= tax_details.threshold:
- tds_amount = ref_doc.net_total * tax_details.rate / 100
- return tds_amount
+ def _get_tds(amount):
+ if amount <= 0:
+ return 0
- if tax_details.cumulative_threshold:
- entries = frappe.db.sql("""
+ return amount * tax_details.rate / 100
+
+ entries = frappe.db.sql("""
select voucher_no, credit
from `tabGL Entry`
where party=%s and fiscal_year=%s and credit > 0
""", (ref_doc.supplier, fiscal_year), as_dict=1)
- supplier_credit_amount = flt(sum([d.credit for d in entries]))
+ vouchers = [d.voucher_no for d in entries]
+ advance_vouchers = get_advance_vouchers(ref_doc.supplier, fiscal_year)
- vouchers = [d.voucher_no for d in entries]
- vouchers += get_advance_vouchers(ref_doc.supplier, fiscal_year)
+ tds_vouchers = vouchers + advance_vouchers
- tds_deducted = 0
- if vouchers:
- tds_deducted = flt(frappe.db.sql("""
- select sum(credit)
- from `tabGL Entry`
- where account=%s and fiscal_year=%s and credit > 0
- and voucher_no in ({0})
- """.format(', '.join(["'%s'" % d for d in vouchers])),
- (tax_details.account_head, fiscal_year))[0][0])
+ if tds_vouchers:
+ tds_deducted = frappe.db.sql("""
+ SELECT sum(credit) FROM `tabGL Entry`
+ WHERE
+ account=%s and fiscal_year=%s and credit > 0
+ and voucher_no in ({0})""". format(','.join(['%s'] * len(tds_vouchers))),
+ ((tax_details.account_head, fiscal_year) + tuple(tds_vouchers)))
+
+ tds_deducted = tds_deducted[0][0] if tds_deducted and tds_deducted[0][0] else 0
+
+ if tds_deducted:
+ tds_amount = _get_tds(ref_doc.net_total)
+ else:
+ supplier_credit_amount = frappe.get_all('Purchase Invoice Item',
+ fields = ['sum(net_amount)'],
+ filters = {'parent': ('in', vouchers), 'docstatus': 1}, as_list=1)
+
+ supplier_credit_amount = (supplier_credit_amount[0][0]
+ if supplier_credit_amount and supplier_credit_amount[0][0] else 0)
+
+ jv_supplier_credit_amt = frappe.get_all('Journal Entry Account',
+ fields = ['sum(credit_in_account_currency)'],
+ filters = {
+ 'parent': ('in', vouchers), 'docstatus': 1,
+ 'party': ref_doc.supplier,
+ 'reference_type': ('not in', ['Purchase Invoice'])
+ }, as_list=1)
+
+ supplier_credit_amount += (jv_supplier_credit_amt[0][0]
+ if jv_supplier_credit_amt and jv_supplier_credit_amt[0][0] else 0)
+
+ supplier_credit_amount += ref_doc.net_total
debit_note_amount = get_debit_note_amount(ref_doc.supplier, year_start_date, year_end_date)
+ supplier_credit_amount -= debit_note_amount
- total_invoiced_amount = supplier_credit_amount + tds_deducted \
- + flt(ref_doc.net_total) - debit_note_amount
- if total_invoiced_amount >= tax_details.cumulative_threshold:
- total_applicable_tds = total_invoiced_amount * tax_details.rate / 100
- tds_amount = min(total_applicable_tds - tds_deducted, ref_doc.net_total)
- else:
- tds_amount = _get_tds()
- else:
- tds_amount = _get_tds()
+ if ((tax_details.get('threshold', 0) and supplier_credit_amount >= tax_details.threshold)
+ or (tax_details.get('cumulative_threshold', 0) and supplier_credit_amount >= tax_details.cumulative_threshold)):
+ tds_amount = _get_tds(supplier_credit_amount)
return tds_amount
@@ -114,7 +133,7 @@
select distinct voucher_no
from `tabGL Entry`
where party=%s and %s and debit > 0
- """, (supplier, condition))
+ """, (supplier, condition)) or []
def get_debit_note_amount(supplier, year_start_date, year_end_date, company=None):
condition = ""
@@ -126,4 +145,4 @@
from `tabPurchase Invoice`
where supplier=%s %s and is_return=1 and docstatus=1
and posting_date between %s and %s
- """, (supplier, condition, year_start_date, year_end_date)))
+ """, (supplier, condition, year_start_date, year_end_date)))
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py b/erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py
index 20e1746..2530196 100644
--- a/erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py
+++ b/erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py
@@ -6,6 +6,7 @@
import frappe
import unittest
from frappe.utils import today
+from erpnext.accounts.utils import get_fiscal_year
test_dependencies = ["Supplier Group"]
@@ -14,65 +15,105 @@
def setUpClass(self):
# create relevant supplier, etc
create_records()
+ create_tax_with_holding_category()
- def test_single_threshold_tds(self):
- frappe.db.set_value("Supplier", "Test TDS Supplier", "tax_withholding_category", "TDS - 194D - Individual")
- pi = create_purchase_invoice()
+ def test_cumulative_threshold_tds(self):
+ frappe.db.set_value("Supplier", "Test TDS Supplier", "tax_withholding_category", "Cumulative Threshold TDS")
+ invoices = []
+
+ # create invoices for lower than single threshold tax rate
+ for _ in xrange(2):
+ pi = create_purchase_invoice(supplier = "Test TDS Supplier")
+ pi.submit()
+ invoices.append(pi)
+
+ # create another invoice whose total when added to previously created invoice,
+ # surpasses cumulative threshhold
+ pi = create_purchase_invoice(supplier = "Test TDS Supplier")
pi.submit()
- self.assertEqual(pi.taxes_and_charges_deducted, 800)
- self.assertEqual(pi.grand_total, 15200)
+ # assert equal tax deduction on total invoice amount uptil now
+ self.assertEqual(pi.taxes_and_charges_deducted, 3000)
+ self.assertEqual(pi.grand_total, 7000)
+ invoices.append(pi)
+
+ # TDS is already deducted, so from onward system will deduct the TDS on every invoice
+ pi = create_purchase_invoice(supplier = "Test TDS Supplier", rate=5000)
+ pi.submit()
+
+ # assert equal tax deduction on total invoice amount uptil now
+ self.assertEqual(pi.taxes_and_charges_deducted, 500)
+ invoices.append(pi)
+
+ #delete invoices to avoid clashing
+ for d in invoices:
+ d.cancel()
+ frappe.delete_doc("Purchase Invoice", d.name)
+
+ def test_single_threshold_tds(self):
+ invoices = []
+ frappe.db.set_value("Supplier", "Test TDS Supplier1", "tax_withholding_category", "Single Threshold TDS")
+ pi = create_purchase_invoice(supplier = "Test TDS Supplier1", rate = 20000)
+ pi.submit()
+ invoices.append(pi)
+
+ self.assertEqual(pi.taxes_and_charges_deducted, 2000)
+ self.assertEqual(pi.grand_total, 18000)
# check gl entry for the purchase invoice
gl_entries = frappe.db.get_all('GL Entry', filters={'voucher_no': pi.name}, fields=["*"])
self.assertEqual(len(gl_entries), 3)
for d in gl_entries:
if d.account == pi.credit_to:
- self.assertEqual(d.credit, 15200)
+ self.assertEqual(d.credit, 18000)
elif d.account == pi.items[0].get("expense_account"):
- self.assertEqual(d.debit, 16000)
+ self.assertEqual(d.debit, 20000)
elif d.account == pi.taxes[0].get("account_head"):
- self.assertEqual(d.credit, 800)
+ self.assertEqual(d.credit, 2000)
else:
raise ValueError("Account head does not match.")
- # delete purchase invoice to avoid it interefering in other tests
- pi.cancel()
- frappe.delete_doc('Purchase Invoice', pi.name)
-
- def test_cumulative_threshold_tds(self):
- frappe.db.set_value("Supplier", "Test TDS Supplier", "tax_withholding_category", "TDS - 194C - Individual")
- invoices = []
-
- # create invoices for lower than single threshold tax rate
- for _ in xrange(6):
- pi = create_purchase_invoice()
- pi.submit()
- invoices.append(pi)
-
- # create another invoice whose total when added to previously created invoice,
- # surpasses cumulative threshhold
- pi = create_purchase_invoice()
+ pi = create_purchase_invoice(supplier = "Test TDS Supplier1")
pi.submit()
-
- # assert equal tax deduction on total invoice amount uptil now
- self.assertEqual(pi.taxes_and_charges_deducted, 1120)
- self.assertEqual(pi.grand_total, 14880)
invoices.append(pi)
+ # TDS amount is 1000 because in previous invoices it's already deducted
+ self.assertEqual(pi.taxes_and_charges_deducted, 1000)
+
# delete invoices to avoid clashing
for d in invoices:
d.cancel()
frappe.delete_doc("Purchase Invoice", d.name)
-def create_purchase_invoice(qty=1):
+ def test_single_threshold_tds_with_previous_vouchers(self):
+ invoices = []
+ frappe.db.set_value("Supplier", "Test TDS Supplier2", "tax_withholding_category", "Single Threshold TDS")
+ pi = create_purchase_invoice(supplier="Test TDS Supplier2")
+ pi.submit()
+ invoices.append(pi)
+
+ pi = create_purchase_invoice(supplier="Test TDS Supplier2")
+ pi.submit()
+ invoices.append(pi)
+
+ self.assertEqual(pi.taxes_and_charges_deducted, 2000)
+ self.assertEqual(pi.grand_total, 8000)
+
+ # delete invoices to avoid clashing
+ for d in invoices:
+ d.cancel()
+ frappe.delete_doc("Purchase Invoice", d.name)
+
+def create_purchase_invoice(**args):
# return sales invoice doc object
item = frappe.get_doc('Item', {'item_name': 'TDS Item'})
+
+ args = frappe._dict(args)
pi = frappe.get_doc({
"doctype": "Purchase Invoice",
"posting_date": today(),
"apply_tds": 1,
- "supplier": frappe.get_doc('Supplier', {"supplier_name": "Test TDS Supplier"}).name,
+ "supplier": args.supplier,
"company": '_Test Company',
"taxes_and_charges": "",
"currency": "INR",
@@ -81,8 +122,8 @@
"items": [{
'doctype': 'Purchase Invoice Item',
'item_code': item.name,
- 'qty': qty,
- 'rate': 16000,
+ 'qty': args.qty or 1,
+ 'rate': args.rate or 10000,
'cost_center': 'Main - _TC',
'expense_account': 'Stock Received But Not Billed - _TC'
}]
@@ -92,20 +133,73 @@
return pi
def create_records():
- # create a new supplier
- frappe.get_doc({
- "supplier_group": "_Test Supplier Group",
- "supplier_name": "Test TDS Supplier",
- "doctype": "Supplier",
- "tax_withholding_category": "TDS - 194D - Individual"
- }).insert()
+ # create a new suppliers
+ for name in ['Test TDS Supplier', 'Test TDS Supplier1', 'Test TDS Supplier2']:
+ if frappe.db.exists('Supplier', name):
+ continue
+
+ frappe.get_doc({
+ "supplier_group": "_Test Supplier Group",
+ "supplier_name": name,
+ "doctype": "Supplier",
+ }).insert()
# create an item
- frappe.get_doc({
- "doctype": "Item",
- "item_code": "TDS Item",
- "item_name": "TDS Item",
- "item_group": "All Item Groups",
- "company": "_Test Company",
- "is_stock_item": 0,
- }).insert()
\ No newline at end of file
+ if not frappe.db.exists('Item', "TDS Item"):
+ frappe.get_doc({
+ "doctype": "Item",
+ "item_code": "TDS Item",
+ "item_name": "TDS Item",
+ "item_group": "All Item Groups",
+ "is_stock_item": 0,
+ }).insert()
+
+ # create an account
+ if not frappe.db.exists("Account", "TDS - _TC"):
+ frappe.get_doc({
+ 'doctype': 'Account',
+ 'company': '_Test Company',
+ 'account_name': 'TDS',
+ 'parent_account': 'Tax Assets - _TC',
+ 'report_type': 'Balance Sheet',
+ 'root_type': 'Asset'
+ }).insert()
+
+def create_tax_with_holding_category():
+ fiscal_year = get_fiscal_year(today(), company="_Test Company")[0]
+
+ # Cummulative thresold
+ if not frappe.db.exists("Tax Withholding Category", "Cumulative Threshold TDS"):
+ frappe.get_doc({
+ "doctype": "Tax Withholding Category",
+ "name": "Cumulative Threshold TDS",
+ "category_name": "10% TDS",
+ "rates": [{
+ 'fiscal_year': fiscal_year,
+ 'tax_withholding_rate': 10,
+ 'single_threshold': 0,
+ 'cumulative_threshold': 30000.00
+ }],
+ "accounts": [{
+ 'company': '_Test Company',
+ 'account': 'TDS - _TC'
+ }]
+ }).insert()
+
+ # Single thresold
+ if not frappe.db.exists("Tax Withholding Category", "Single Threshold TDS"):
+ frappe.get_doc({
+ "doctype": "Tax Withholding Category",
+ "name": "Single Threshold TDS",
+ "category_name": "10% TDS",
+ "rates": [{
+ 'fiscal_year': fiscal_year,
+ 'tax_withholding_rate': 10,
+ 'single_threshold': 20000.00,
+ 'cumulative_threshold': 0
+ }],
+ "accounts": [{
+ 'company': '_Test Company',
+ 'account': 'TDS - _TC'
+ }]
+ }).insert()
\ No newline at end of file
diff --git a/erpnext/accounts/page/pos/pos.js b/erpnext/accounts/page/pos/pos.js
index 91f3711..04c8718 100755
--- a/erpnext/accounts/page/pos/pos.js
+++ b/erpnext/accounts/page/pos/pos.js
@@ -1135,16 +1135,18 @@
},
apply_category: function() {
- var me = this;
- category = this.selected_item_group || "All Item Groups";
+ frappe.db.get_value("Item Group", {lft: 1, is_group: 1}, "name", (r) => {
+ category = this.selected_item_group || r.name;
- if(category == 'All Item Groups') {
- return this.item_data
- } else {
- return this.item_data.filter(function(element, index, array){
- return element.item_group == category;
- });
- }
+ if(category == r.name) {
+ return this.item_data
+ } else {
+ return this.item_data.filter(function(element, index, array){
+ return element.item_group == category;
+ });
+ }
+ })
+
},
bind_items_event: function() {
diff --git a/erpnext/accounts/party.py b/erpnext/accounts/party.py
index e5cdad1..1085cdd 100644
--- a/erpnext/accounts/party.py
+++ b/erpnext/accounts/party.py
@@ -5,7 +5,7 @@
import frappe, erpnext
from frappe import _, msgprint, scrub
-from frappe.defaults import get_user_permissions
+from frappe.core.doctype.user_permission.user_permission import get_permitted_documents
from frappe.model.utils import get_fetch_values
from frappe.utils import (add_days, getdate, formatdate, date_diff,
add_years, get_timestamp, nowdate, flt, add_months, get_last_day)
@@ -151,10 +151,7 @@
def set_price_list(out, party, party_type, given_price_list):
# price list
- price_list = filter(None, get_user_permissions()
- .get("Price List", {})
- .get("docs", []))
- price_list = list(price_list)
+ price_list = get_permitted_documents('Price List')
if price_list:
price_list = price_list[0]
@@ -537,7 +534,7 @@
'dl.link_doctype=%s '
'and dl.link_name=%s '
'and dl.parenttype="Address" '
- 'and '
+ 'and ifnull(ta.disabled, 0) = 0 and'
'(ta.address_type="Shipping" or ta.is_shipping_address=1) '
'order by ta.is_shipping_address desc, ta.address_type desc limit 1',
(doctype, name)
diff --git a/erpnext/accounts/report/accounts_payable/accounts_payable.js b/erpnext/accounts/report/accounts_payable/accounts_payable.js
index 9370f04..0a025f6 100644
--- a/erpnext/accounts/report/accounts_payable/accounts_payable.js
+++ b/erpnext/accounts/report/accounts_payable/accounts_payable.js
@@ -11,36 +11,6 @@
"default": frappe.defaults.get_user_default("Company")
},
{
- "fieldname":"finance_book",
- "label": __("Finance Book"),
- "fieldtype": "Link",
- "options": "Finance Book"
- },
- {
- "fieldname":"supplier",
- "label": __("Supplier"),
- "fieldtype": "Link",
- "options": "Supplier",
- on_change: () => {
- var supplier = frappe.query_report.get_filter_value('supplier');
- frappe.db.get_value('Supplier', supplier, "tax_id", function(value) {
- frappe.query_report.set_filter_value('tax_id', value["tax_id"]);
- });
- }
- },
- {
- "fieldname":"supplier_group",
- "label": __("Supplier Group"),
- "fieldtype": "Link",
- "options": "Supplier Group"
- },
- {
- "fieldname":"report_date",
- "label": __("As on Date"),
- "fieldtype": "Date",
- "default": frappe.datetime.get_today()
- },
- {
"fieldname":"ageing_based_on",
"label": __("Ageing Based On"),
"fieldtype": "Select",
@@ -48,7 +18,10 @@
"default": "Posting Date"
},
{
- "fieldtype": "Break",
+ "fieldname":"report_date",
+ "label": __("As on Date"),
+ "fieldtype": "Date",
+ "default": frappe.datetime.get_today()
},
{
"fieldname":"range1",
@@ -72,6 +45,34 @@
"reqd": 1
},
{
+ "fieldname":"finance_book",
+ "label": __("Finance Book"),
+ "fieldtype": "Link",
+ "options": "Finance Book"
+ },
+ {
+ "fieldname":"supplier",
+ "label": __("Supplier"),
+ "fieldtype": "Link",
+ "options": "Supplier",
+ on_change: () => {
+ var supplier = frappe.query_report.get_filter_value('supplier');
+ if (supplier) {
+ frappe.db.get_value('Supplier', supplier, "tax_id", function(value) {
+ frappe.query_report.set_filter_value('tax_id', value["tax_id"]);
+ });
+ } else {
+ frappe.query_report.set_filter_value('tax_id', "");
+ }
+ }
+ },
+ {
+ "fieldname":"supplier_group",
+ "label": __("Supplier Group"),
+ "fieldtype": "Link",
+ "options": "Supplier Group"
+ },
+ {
"fieldname":"tax_id",
"label": __("Tax Id"),
"fieldtype": "Data",
diff --git a/erpnext/accounts/report/accounts_payable_summary/accounts_payable_summary.js b/erpnext/accounts/report/accounts_payable_summary/accounts_payable_summary.js
index 77b099f..7823cac 100644
--- a/erpnext/accounts/report/accounts_payable_summary/accounts_payable_summary.js
+++ b/erpnext/accounts/report/accounts_payable_summary/accounts_payable_summary.js
@@ -11,24 +11,6 @@
"default": frappe.defaults.get_user_default("Company")
},
{
- "fieldname":"supplier",
- "label": __("Supplier"),
- "fieldtype": "Link",
- "options": "Supplier"
- },
- {
- "fieldname":"supplier_group",
- "label": __("Supplier Group"),
- "fieldtype": "Link",
- "options": "Supplier Group"
- },
- {
- "fieldname":"report_date",
- "label": __("Date"),
- "fieldtype": "Date",
- "default": frappe.datetime.get_today()
- },
- {
"fieldname":"ageing_based_on",
"label": __("Ageing Based On"),
"fieldtype": "Select",
@@ -36,7 +18,10 @@
"default": "Posting Date"
},
{
- "fieldtype": "Break",
+ "fieldname":"report_date",
+ "label": __("Date"),
+ "fieldtype": "Date",
+ "default": frappe.datetime.get_today()
},
{
"fieldname":"range1",
@@ -58,6 +43,24 @@
"fieldtype": "Int",
"default": "90",
"reqd": 1
+ },
+ {
+ "fieldname":"finance_book",
+ "label": __("Finance Book"),
+ "fieldtype": "Link",
+ "options": "Finance Book"
+ },
+ {
+ "fieldname":"supplier",
+ "label": __("Supplier"),
+ "fieldtype": "Link",
+ "options": "Supplier"
+ },
+ {
+ "fieldname":"supplier_group",
+ "label": __("Supplier Group"),
+ "fieldtype": "Link",
+ "options": "Supplier Group"
}
],
diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.html b/erpnext/accounts/report/accounts_receivable/accounts_receivable.html
index 4930207..fd462a6 100644
--- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.html
+++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.html
@@ -1,24 +1,14 @@
-{% if(filters.show_pdc_in_print) { %}
- <style>
- @media screen {
- .print-format {
- padding: 4mm;
- font-size: 8.0pt !important;
- font-family: Tahoma, sans-serif;
- }
- }
- </style>
-{% } %}
<style>
- .print-format {
- padding: 4mm;
- font-size: 8.0pt !important;
- font-family: Tahoma, sans-serif;
- }
+.print-format {
+ padding: 4mm;
+ font-size: 8.0pt !important;
+}
+.print-format td {
+ vertical-align:middle !important;
+}
</style>
-
-<h2 class="text-center">{%= __(report.report_name) %}</h2>
+<h2 class="text-center" style="margin-top:0">{%= __(report.report_name) %}</h2>
<h4 class="text-center">
{% if (filters.customer_name) { %}
{%= filters.customer_name %}
@@ -36,7 +26,20 @@
{%= __("Until") %}
{%= frappe.datetime.str_to_user(filters.report_date) %}
</h5>
-<hr>
+
+<div class="clearfix">
+ <div class="pull-left">
+ {% if(filters.payment_terms) { %}
+ <strong>{%= __("Payment Terms") %}:</strong> {%= filters.payment_terms %}
+ {% } %}
+ </div>
+ <div class="pull-right">
+ {% if(filters.credit_limit) { %}
+ <strong>{%= __("Credit Limit") %}:</strong> {%= format_currency(filters.credit_limit) %}
+ {% } %}
+ </div>
+</div>
+
{% if(filters.show_pdc_in_print) { %}
{% var balance_row = data.slice(-1).pop();
var range1 = report.columns[11].label;
@@ -104,17 +107,21 @@
<thead>
<tr>
{% if(report.report_name === "Accounts Receivable" || report.report_name === "Accounts Payable") { %}
- <th style="width: 18%">{%= __("Date") %}</th>
- <th style="width: 17%">{%= __("Reference") %}</th>
+ <th style="width: 7%">{%= __("Date") %}</th>
+ <th style="width: 7%">{%= __("Age (Days)") %}</th>
+ <th style="width: 13%">{%= __("Reference") %}</th>
+ {% if(report.report_name === "Accounts Receivable") { %}
+ <th style="width: 10%">{%= __("Sales Person") %}</th>
+ {% } %}
{% if(!filters.show_pdc_in_print) { %}
<th style="width: 20%">{%= (filters.customer || filters.supplier) ? __("Remarks"): __("Party") %}</th>
{% } %}
- <th style="width: 10%">{%= __("Invoiced Amount") %}</th>
+ <th style="width: 10%; text-align: right">{%= __("Invoiced Amount") %}</th>
{% if(!filters.show_pdc_in_print) { %}
- <th style="width: 10%">{%= __("Paid Amount") %}</th>
- <th style="width: 10%">{%= report.report_name === "Accounts Receivable" ? __('Credit Note') : __('Debit Note') %}</th>
+ <th style="width: 10%; text-align: right">{%= __("Paid Amount") %}</th>
+ <th style="width: 10%; text-align: right">{%= report.report_name === "Accounts Receivable" ? __('Credit Note') : __('Debit Note') %}</th>
{% } %}
- <th style="width: 15%">{%= __("Outstanding Amount") %}</th>
+ <th style="width: 15%; text-align: right">{%= __("Outstanding Amount") %}</th>
{% if(filters.show_pdc_in_print) { %}
{% if(report.report_name === "Accounts Receivable") { %}
<th style="width: 10%">{%= __("Customer LPO No.") %}</th>
@@ -139,6 +146,7 @@
{% if(report.report_name === "Accounts Receivable" || report.report_name === "Accounts Payable") { %}
{% if(data[i][__("Customer")] || data[i][__("Supplier")]) { %}
<td>{%= frappe.datetime.str_to_user(data[i]["posting_date"]) %}</td>
+ <td style="text-align: right">{%= data[i][__("Age (Days)")] %}</td>
<td>
{% if(!filters.show_pdc_in_print) { %}
{%= data[i]["voucher_type"] %}
@@ -146,6 +154,11 @@
{% } %}
{%= data[i]["voucher_no"] %}
</td>
+
+ {% if(report.report_name === "Accounts Receivable") { %}
+ <td>{%= data[i]["sales_person"] %}</td>
+ {% } %}
+
{% if(!filters.show_pdc_in_print) { %}
<td>
{% if(!(filters.customer || filters.supplier)) { %}
@@ -156,10 +169,15 @@
<br> {%= data[i][__("Supplier Name")] %}
{% } %}
{% } %}
- <br>{%= __("Remarks") %}:
- {%= data[i][__("Remarks")] %}
+ <div>
+ {% if data[i][__("Remarks")] %}
+ {%= __("Remarks") %}:
+ {%= data[i][__("Remarks")] %}
+ {% } %}
+ </div>
</td>
{% } %}
+
<td style="text-align: right">
{%= format_currency(data[i]["invoiced_amount"], data[i]["currency"]) %}</td>
@@ -187,7 +205,11 @@
{% if(!filters.show_pdc_in_print) { %}
<td></td>
{% } %}
- <td><b>{%= __("Total") %}</b></td>
+ {% if(report.report_name === "Accounts Receivable") { %}
+ <td></td>
+ {% } %}
+ <td></td>
+ <td style="text-align: right"><b>{%= __("Total") %}</b></td>
<td style="text-align: right">
{%= format_currency(data[i]["invoiced_amount"], data[i]["currency"] ) %}</td>
diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.js b/erpnext/accounts/report/accounts_receivable/accounts_receivable.js
index fda4960..bbfee11 100644
--- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.js
+++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.js
@@ -11,6 +11,40 @@
"default": frappe.defaults.get_user_default("Company")
},
{
+ "fieldname":"ageing_based_on",
+ "label": __("Ageing Based On"),
+ "fieldtype": "Select",
+ "options": 'Posting Date\nDue Date',
+ "default": "Posting Date"
+ },
+ {
+ "fieldname":"report_date",
+ "label": __("As on Date"),
+ "fieldtype": "Date",
+ "default": frappe.datetime.get_today()
+ },
+ {
+ "fieldname":"range1",
+ "label": __("Ageing Range 1"),
+ "fieldtype": "Int",
+ "default": "30",
+ "reqd": 1
+ },
+ {
+ "fieldname":"range2",
+ "label": __("Ageing Range 2"),
+ "fieldtype": "Int",
+ "default": "60",
+ "reqd": 1
+ },
+ {
+ "fieldname":"range3",
+ "label": __("Ageing Range 3"),
+ "fieldtype": "Int",
+ "default": "90",
+ "reqd": 1
+ },
+ {
"fieldname":"finance_book",
"label": __("Finance Book"),
"fieldtype": "Link",
@@ -23,10 +57,19 @@
"options": "Customer",
on_change: () => {
var customer = frappe.query_report.get_filter_value('customer');
- frappe.db.get_value('Customer', customer, ["tax_id", "customer_name"], function(value) {
- frappe.query_report.set_filter_value('tax_id', value["tax_id"]);
- frappe.query_report.set_filter_value('customer_name', value["customer_name"]);
- });
+ if (customer) {
+ frappe.db.get_value('Customer', customer, ["tax_id", "customer_name", "credit_limit", "payment_terms"], function(value) {
+ frappe.query_report.set_filter_value('tax_id', value["tax_id"]);
+ frappe.query_report.set_filter_value('customer_name', value["customer_name"]);
+ frappe.query_report.set_filter_value('credit_limit', value["credit_limit"]);
+ frappe.query_report.set_filter_value('payment_terms', value["payment_terms"]);
+ });
+ } else {
+ frappe.query_report.set_filter_value('tax_id', "");
+ frappe.query_report.set_filter_value('customer_name', "");
+ frappe.query_report.set_filter_value('credit_limit', "");
+ frappe.query_report.set_filter_value('payment_terms', "");
+ }
}
},
{
@@ -60,48 +103,16 @@
"options": "Sales Person"
},
{
- "fieldtype": "Break",
- },
- {
- "fieldname":"report_date",
- "label": __("As on Date"),
- "fieldtype": "Date",
- "default": frappe.datetime.get_today()
- },
- {
- "fieldname":"ageing_based_on",
- "label": __("Ageing Based On"),
- "fieldtype": "Select",
- "options": 'Posting Date\nDue Date',
- "default": "Posting Date"
- },
- {
- "fieldname":"range1",
- "label": __("Ageing Range 1"),
- "fieldtype": "Int",
- "default": "30",
- "reqd": 1
- },
- {
- "fieldname":"range2",
- "label": __("Ageing Range 2"),
- "fieldtype": "Int",
- "default": "60",
- "reqd": 1
- },
- {
- "fieldname":"range3",
- "label": __("Ageing Range 3"),
- "fieldtype": "Int",
- "default": "90",
- "reqd": 1
- },
- {
"fieldname":"show_pdc_in_print",
"label": __("Show PDC in Print"),
"fieldtype": "Check",
},
{
+ "fieldname":"based_on_payment_terms",
+ "label": __("Based On Payment Terms"),
+ "fieldtype": "Check",
+ },
+ {
"fieldname":"tax_id",
"label": __("Tax Id"),
"fieldtype": "Data",
@@ -112,6 +123,18 @@
"label": __("Customer Name"),
"fieldtype": "Data",
"hidden": 1
+ },
+ {
+ "fieldname":"payment_terms",
+ "label": __("Payment Tems"),
+ "fieldtype": "Data",
+ "hidden": 1
+ },
+ {
+ "fieldname":"credit_limit",
+ "label": __("Credit Limit"),
+ "fieldtype": "Currency",
+ "hidden": 1
}
],
diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
index 572f81d..121d5b0 100755
--- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
+++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
@@ -4,7 +4,7 @@
from __future__ import unicode_literals
import frappe, erpnext
from frappe import _, scrub
-from frappe.utils import getdate, nowdate, flt, cint
+from frappe.utils import getdate, nowdate, flt, cint, formatdate, cstr
class ReceivablePayableReport(object):
def __init__(self, filters=None):
@@ -57,6 +57,21 @@
credit_or_debit_note = "Credit Note" if args.get("party_type") == "Customer" else "Debit Note"
+ if self.filters.based_on_payment_terms:
+ columns.append({
+ "label": "Payment Term",
+ "fieldname": "payment_term",
+ "fieldtype": "Data",
+ "width": 120
+ })
+ columns.append({
+ "label": "Invoice Grand Total",
+ "fieldname": "invoice_grand_total",
+ "fieldtype": "Currency",
+ "options": "currency",
+ "width": 120
+ })
+
for label in ("Invoiced Amount", "Paid Amount", credit_or_debit_note, "Outstanding Amount"):
columns.append({
"label": label,
@@ -98,12 +113,6 @@
"width": 100
},
{
- "fieldname": "pdc/lc_date",
- "label": _("PDC/LC Date"),
- "fieldtype": "Date",
- "width": 110
- },
- {
"fieldname": "pdc/lc_ref",
"label": _("PDC/LC Ref"),
"fieldtype": "Data",
@@ -113,29 +122,34 @@
"fieldname": "pdc/lc_amount",
"label": _("PDC/LC Amount"),
"fieldtype": "Currency",
- "options": "Currency",
+ "options": "currency",
"width": 130
},
{
"fieldname": "remaining_balance",
"label": _("Remaining Balance"),
"fieldtype": "Currency",
- "options": "Currency",
+ "options": "currency",
"width": 130
}]
if args.get('party_type') == 'Customer':
- columns.append({
- "label": _("Customer LPO"),
- "fieldtype": "Data",
- "fieldname": "po_no",
- "width": 100,
- })
- columns += [_("Delivery Note") + ":Data:100"]
- if args.get("party_type") == "Customer":
columns += [
+ {
+ "label": _("Customer LPO"),
+ "fieldtype": "Data",
+ "fieldname": "po_no",
+ "width": 100,
+ },
+ _("Delivery Note") + ":Data:100",
_("Territory") + ":Link/Territory:80",
- _("Customer Group") + ":Link/Customer Group:120"
+ _("Customer Group") + ":Link/Customer Group:120",
+ {
+ "label": _("Sales Person"),
+ "fieldtype": "Data",
+ "fieldname": "sales_person",
+ "width": 120,
+ }
]
if args.get("party_type") == "Supplier":
columns += [_("Supplier Group") + ":Link/Supplier Group:80"]
@@ -146,107 +160,203 @@
def get_data(self, party_naming_by, args):
from erpnext.accounts.utils import get_currency_precision
- currency_precision = get_currency_precision() or 2
- dr_or_cr = "debit" if args.get("party_type") == "Customer" else "credit"
+ self.currency_precision = get_currency_precision() or 2
+ self.dr_or_cr = "debit" if args.get("party_type") == "Customer" else "credit"
future_vouchers = self.get_entries_after(self.filters.report_date, args.get("party_type"))
if not self.filters.get("company"):
self.filters["company"] = frappe.db.get_single_value('Global Defaults', 'default_company')
- company_currency = frappe.get_cached_value('Company', self.filters.get("company"), "default_currency")
+ self.company_currency = frappe.get_cached_value('Company', self.filters.get("company"), "default_currency")
return_entries = self.get_return_entries(args.get("party_type"))
data = []
- pdc_details = get_pdc_details(args.get("party_type"), self.filters.report_date)
+ self.pdc_details = get_pdc_details(args.get("party_type"), self.filters.report_date)
gl_entries_data = self.get_entries_till(self.filters.report_date, args.get("party_type"))
if gl_entries_data:
voucher_nos = [d.voucher_no for d in gl_entries_data] or []
dn_details = get_dn_details(args.get("party_type"), voucher_nos)
- voucher_details = get_voucher_details(args.get("party_type"), voucher_nos, dn_details)
+ self.voucher_details = get_voucher_details(args.get("party_type"), voucher_nos, dn_details)
+
+ if self.filters.based_on_payment_terms:
+ self.payment_term_map = self.get_payment_term_detail(voucher_nos)
for gle in gl_entries_data:
- if self.is_receivable_or_payable(gle, dr_or_cr, future_vouchers):
- outstanding_amount, credit_note_amount = self.get_outstanding_amount(gle,
- self.filters.report_date, dr_or_cr, return_entries, currency_precision)
- if abs(outstanding_amount) > 0.1/10**currency_precision:
- row = [gle.posting_date, gle.party]
+ if self.is_receivable_or_payable(gle, self.dr_or_cr, future_vouchers):
+ outstanding_amount, credit_note_amount, payment_amount = self.get_outstanding_amount(
+ gle,self.filters.report_date, self.dr_or_cr, return_entries)
- # customer / supplier name
- if party_naming_by == "Naming Series":
- row += [self.get_party_name(gle.party_type, gle.party)]
+ temp_outstanding_amt = outstanding_amount
+ temp_credit_note_amt = credit_note_amount
- # get due date
- due_date = voucher_details.get(gle.voucher_no, {}).get("due_date", "")
- bill_date = voucher_details.get(gle.voucher_no, {}).get("bill_date", "")
+ if abs(outstanding_amount) > 0.1/10**self.currency_precision:
+ if self.filters.based_on_payment_terms and self.payment_term_map.get(gle.voucher_no):
+ for d in self.payment_term_map.get(gle.voucher_no):
+ # Allocate payment amount based on payment terms(FIFO order)
+ payment_amount, d.payment_amount = self.allocate_based_on_fifo(payment_amount, d.payment_term_amount)
- row += [gle.voucher_type, gle.voucher_no, due_date]
+ term_outstanding_amount = d.payment_term_amount - d.payment_amount
- # get supplier bill details
- if args.get("party_type") == "Supplier":
- row += [
- voucher_details.get(gle.voucher_no, {}).get("bill_no", ""),
- voucher_details.get(gle.voucher_no, {}).get("bill_date", "")
- ]
+ # Allocate credit note based on payment terms(FIFO order)
+ credit_note_amount, d.credit_note_amount = self.allocate_based_on_fifo(credit_note_amount, term_outstanding_amount)
- # invoiced and paid amounts
- invoiced_amount = gle.get(dr_or_cr) if (gle.get(dr_or_cr) > 0) else 0
- paid_amt = invoiced_amount - outstanding_amount - credit_note_amount
- row += [invoiced_amount, paid_amt, credit_note_amount, outstanding_amount]
+ term_outstanding_amount -= d.credit_note_amount
- # ageing data
- if self.filters.ageing_based_on == "Due Date":
- entry_date = due_date
- elif self.filters.ageing_based_on == "Supplier Invoice Date":
- entry_date = bill_date
+ row_outstanding = term_outstanding_amount
+ # Allocate PDC based on payment terms(FIFO order)
+ d.pdc_details, d.pdc_amount = self.allocate_pdc_amount_in_fifo(gle, row_outstanding)
+
+ if term_outstanding_amount > 0:
+ row = self.prepare_row(party_naming_by, args, gle, term_outstanding_amount,
+ d.credit_note_amount, d.due_date, d.payment_amount , d.payment_term_amount,
+ d.description, d.pdc_amount, d.pdc_details)
+ data.append(row)
+
+ if credit_note_amount:
+ row = self.prepare_row_without_payment_terms(party_naming_by, args, gle, temp_outstanding_amt,
+ temp_credit_note_amt)
+ data.append(row)
+
else:
- entry_date = gle.posting_date
-
- row += get_ageing_data(cint(self.filters.range1), cint(self.filters.range2),
- cint(self.filters.range3), self.age_as_on, entry_date, outstanding_amount)
-
-
- # issue 6371-Ageing buckets should not have amounts if due date is not reached
- if self.filters.ageing_based_on == "Due Date" \
- and getdate(due_date) > getdate(self.filters.report_date):
- row[-1]=row[-2]=row[-3]=row[-4]=0
-
- if self.filters.ageing_based_on == "Supplier Invoice Date" \
- and getdate(bill_date) > getdate(self.filters.report_date):
-
- row[-1]=row[-2]=row[-3]=row[-4]=0
-
- if self.filters.get(scrub(args.get("party_type"))):
- row.append(gle.account_currency)
- else:
- row.append(company_currency)
-
- pdc = pdc_details.get((gle.voucher_no, gle.party), {})
-
- remaining_balance = outstanding_amount - flt(pdc.get("pdc_amount"))
- row += [pdc.get("pdc_date"), pdc.get("pdc_ref"),
- flt(pdc.get("pdc_amount")), remaining_balance]
-
- if args.get('party_type') == 'Customer':
- # customer LPO
- row += [voucher_details.get(gle.voucher_no, {}).get("po_no")]
-
- # Delivery Note
- row += [voucher_details.get(gle.voucher_no, {}).get("delivery_note")]
-
- # customer territory / supplier group
- if args.get("party_type") == "Customer":
- row += [self.get_territory(gle.party), self.get_customer_group(gle.party)]
- if args.get("party_type") == "Supplier":
- row += [self.get_supplier_group(gle.party)]
-
- row.append(gle.remarks)
- data.append(row)
-
+ row = self.prepare_row_without_payment_terms(party_naming_by, args, gle, outstanding_amount,
+ credit_note_amount)
+ data.append(row)
return data
+ def allocate_pdc_amount_in_fifo(self, gle, row_outstanding):
+ pdc_list = self.pdc_details.get((gle.voucher_no, gle.party), [])
+
+ pdc_details = []
+ pdc_amount = 0
+ for pdc in pdc_list:
+ if row_outstanding <= pdc.pdc_amount:
+ pdc_amount += row_outstanding
+ pdc.pdc_amount -= row_outstanding
+ if row_outstanding and pdc.pdc_ref and pdc.pdc_date:
+ pdc_details.append(cstr(pdc.pdc_ref) + "/" + formatdate(pdc.pdc_date))
+ row_outstanding = 0
+
+ else:
+ pdc_amount = pdc.pdc_amount
+ if pdc.pdc_amount and pdc.pdc_ref and pdc.pdc_date:
+ pdc_details.append(cstr(pdc.pdc_ref) + "/" + formatdate(pdc.pdc_date))
+ pdc.pdc_amount = 0
+ row_outstanding -= pdc_amount
+
+ return pdc_details, pdc_amount
+
+ def prepare_row_without_payment_terms(self, party_naming_by, args, gle, outstanding_amount, credit_note_amount):
+ pdc_list = self.pdc_details.get((gle.voucher_no, gle.party), [])
+ pdc_amount = 0
+ pdc_details = []
+ for d in pdc_list:
+ pdc_amount += flt(d.pdc_amount)
+ if pdc_amount and d.pdc_ref and d.pdc_date:
+ pdc_details.append(cstr(d.pdc_ref) + "/" + formatdate(d.pdc_date))
+
+ row = self.prepare_row(party_naming_by, args, gle, outstanding_amount,
+ credit_note_amount, pdc_amount=pdc_amount, pdc_details=pdc_details)
+
+ return row
+
+
+ def allocate_based_on_fifo(self, total_amount, row_amount):
+ allocated_amount = 0
+ if row_amount <= total_amount:
+ allocated_amount = row_amount
+ total_amount -= row_amount
+ else:
+ allocated_amount = total_amount
+ total_amount = 0
+
+ return total_amount, allocated_amount
+
+ def prepare_row(self, party_naming_by, args, gle, outstanding_amount, credit_note_amount,
+ due_date=None, paid_amt=None, payment_term_amount=None, payment_term=None, pdc_amount=None, pdc_details=None):
+ row = [gle.posting_date, gle.party]
+
+ # customer / supplier name
+ if party_naming_by == "Naming Series":
+ row += [self.get_party_name(gle.party_type, gle.party)]
+
+ # get due date
+ if not due_date:
+ due_date = self.voucher_details.get(gle.voucher_no, {}).get("due_date", "")
+ bill_date = self.voucher_details.get(gle.voucher_no, {}).get("bill_date", "")
+
+ row += [gle.voucher_type, gle.voucher_no, due_date]
+
+ # get supplier bill details
+ if args.get("party_type") == "Supplier":
+ row += [
+ self.voucher_details.get(gle.voucher_no, {}).get("bill_no", ""),
+ self.voucher_details.get(gle.voucher_no, {}).get("bill_date", "")
+ ]
+
+ # invoiced and paid amounts
+ invoiced_amount = gle.get(self.dr_or_cr) if (gle.get(self.dr_or_cr) > 0) else 0
+
+ if self.filters.based_on_payment_terms:
+ row+=[payment_term, invoiced_amount]
+ if payment_term_amount:
+ invoiced_amount = payment_term_amount
+
+ if not payment_term_amount:
+ paid_amt = invoiced_amount - outstanding_amount - credit_note_amount
+ row += [invoiced_amount, paid_amt, credit_note_amount, outstanding_amount]
+
+ # ageing data
+ if self.filters.ageing_based_on == "Due Date":
+ entry_date = due_date
+ elif self.filters.ageing_based_on == "Supplier Invoice Date":
+ entry_date = bill_date
+ else:
+ entry_date = gle.posting_date
+
+ row += get_ageing_data(cint(self.filters.range1), cint(self.filters.range2),
+ cint(self.filters.range3), self.age_as_on, entry_date, outstanding_amount)
+
+
+ # issue 6371-Ageing buckets should not have amounts if due date is not reached
+ if self.filters.ageing_based_on == "Due Date" \
+ and getdate(due_date) > getdate(self.filters.report_date):
+ row[-1]=row[-2]=row[-3]=row[-4]=0
+
+ if self.filters.ageing_based_on == "Supplier Invoice Date" \
+ and getdate(bill_date) > getdate(self.filters.report_date):
+
+ row[-1]=row[-2]=row[-3]=row[-4]=0
+
+ if self.filters.get(scrub(args.get("party_type"))):
+ row.append(gle.account_currency)
+ else:
+ row.append(self.company_currency)
+
+ remaining_balance = outstanding_amount - flt(pdc_amount)
+ pdc_details = ", ".join(pdc_details)
+ row += [pdc_details, pdc_amount, remaining_balance]
+
+ if args.get('party_type') == 'Customer':
+ # customer LPO
+ row += [self.voucher_details.get(gle.voucher_no, {}).get("po_no")]
+
+ # Delivery Note
+ row += [self.voucher_details.get(gle.voucher_no, {}).get("delivery_note")]
+
+ # customer territory / supplier group
+ if args.get("party_type") == "Customer":
+ row += [self.get_territory(gle.party), self.get_customer_group(gle.party),
+ self.voucher_details.get(gle.voucher_no, {}).get("sales_person")]
+ if args.get("party_type") == "Supplier":
+ row += [self.get_supplier_group(gle.party)]
+
+ row.append(gle.remarks)
+
+ return row
+
def get_entries_after(self, report_date, party_type):
# returns a distinct list
return list(set([(e.voucher_type, e.voucher_no) for e in self.get_gl_entries(party_type, report_date, for_future=True)]))
@@ -274,25 +384,25 @@
doctype = "Sales Invoice" if party_type=="Customer" else "Purchase Invoice"
return [d.name for d in frappe.get_all(doctype, filters={"is_return": 1, "docstatus": 1})]
- def get_outstanding_amount(self, gle, report_date, dr_or_cr, return_entries, currency_precision):
+ def get_outstanding_amount(self, gle, report_date, dr_or_cr, return_entries):
payment_amount, credit_note_amount = 0.0, 0.0
reverse_dr_or_cr = "credit" if dr_or_cr=="debit" else "debit"
for e in self.get_gl_entries_for(gle.party, gle.party_type, gle.voucher_type, gle.voucher_no):
if getdate(e.posting_date) <= report_date and e.name!=gle.name:
- amount = flt(e.get(reverse_dr_or_cr), currency_precision) - flt(e.get(dr_or_cr), currency_precision)
+ amount = flt(e.get(reverse_dr_or_cr), self.currency_precision) - flt(e.get(dr_or_cr), self.currency_precision)
if e.voucher_no not in return_entries:
payment_amount += amount
else:
credit_note_amount += amount
- outstanding_amount = (flt((flt(gle.get(dr_or_cr), currency_precision)
- - flt(gle.get(reverse_dr_or_cr), currency_precision)
- - payment_amount - credit_note_amount), currency_precision))
+ outstanding_amount = (flt((flt(gle.get(dr_or_cr), self.currency_precision)
+ - flt(gle.get(reverse_dr_or_cr), self.currency_precision)
+ - payment_amount - credit_note_amount), self.currency_precision))
- credit_note_amount = flt(credit_note_amount, currency_precision)
+ credit_note_amount = flt(credit_note_amount, self.currency_precision)
- return outstanding_amount, credit_note_amount
+ return outstanding_amount, credit_note_amount, payment_amount
def get_party_name(self, party_type, party_name):
return self.get_party_map(party_type).get(party_name, {}).get("customer_name" if party_type == "Customer" else "supplier_name") or ""
@@ -377,7 +487,7 @@
conditions.append("""party in (select name from tabCustomer
where exists(select name from `tabCustomer Group` where lft >= {0} and rgt <= {1}
and name=tabCustomer.customer_group))""".format(lft, rgt))
-
+
if self.filters.get("territory"):
lft, rgt = frappe.db.get_value("Territory",
self.filters.get("territory"), ["lft", "rgt"])
@@ -395,16 +505,21 @@
values.append(self.filters.get("sales_partner"))
if self.filters.get("sales_person"):
- conditions.append("""party in (select parent
- from `tabSales Team` where sales_person=%s and parenttype = 'Customer')""")
- values.append(self.filters.get("sales_person"))
+ lft, rgt = frappe.db.get_value("Sales Person",
+ self.filters.get("sales_person"), ["lft", "rgt"])
+
+ conditions.append("""exists(select name from `tabSales Team` steam where
+ steam.sales_person in (select name from `tabSales Person` where lft >= {0} and rgt <= {1})
+ and ((steam.parent = voucher_no and steam.parenttype = voucher_type)
+ or (steam.parent = against_voucher and steam.parenttype = against_voucher_type)
+ or (steam.parent = party and steam.parenttype = 'Customer')))""".format(lft, rgt))
if party_type_field=="supplier":
if self.filters.get("supplier_group"):
conditions.append("""party in (select name from tabSupplier
where supplier_group=%s)""")
values.append(self.filters.get("supplier_group"))
-
+
return " and ".join(conditions), values
def get_gl_entries_for(self, party, party_type, against_voucher_type, against_voucher):
@@ -421,6 +536,31 @@
.get(against_voucher_type, {})\
.get(against_voucher, [])
+ def get_payment_term_detail(self, voucher_nos):
+ payment_term_map = frappe._dict()
+ payment_terms_details = frappe.db.sql(""" select si.name,
+ party_account_currency, currency, si.conversion_rate,
+ ps.due_date, ps.payment_amount, ps.description
+ from `tabSales Invoice` si, `tabPayment Schedule` ps
+ where si.name = ps.parent and
+ si.docstatus = 1 and si.company = '%s' and
+ si.name in (%s) order by ps.due_date
+ """ % (frappe.db.escape(self.filters.company), ','.join(['%s'] *len(voucher_nos))),
+ (tuple(voucher_nos)), as_dict = 1)
+
+ for d in payment_terms_details:
+ if self.filters.get("customer") and d.currency == d.party_account_currency:
+ payment_term_amount = d.payment_amount
+ else:
+ payment_term_amount = flt(flt(d.payment_amount) * flt(d.conversion_rate), self.currency_precision)
+
+ payment_term_map.setdefault(d.name, []).append(frappe._dict({
+ "due_date": d.due_date,
+ "payment_term_amount": payment_term_amount,
+ "description": d.description
+ }))
+ return payment_term_map
+
def get_chart_data(self, columns, data):
ageing_columns = columns[self.ageing_col_idx_start : self.ageing_col_idx_start+4]
@@ -468,12 +608,11 @@
def get_pdc_details(party_type, report_date):
pdc_details = frappe._dict()
-
- for pdc in frappe.db.sql("""
+ pdc_via_pe = frappe.db.sql("""
select
pref.reference_name as invoice_no, pent.party, pent.party_type,
- max(pent.posting_date) as pdc_date, sum(ifnull(pref.allocated_amount,0)) as pdc_amount,
- GROUP_CONCAT(pent.reference_no SEPARATOR ', ') as pdc_ref
+ pent.posting_date as pdc_date, ifnull(pref.allocated_amount,0) as pdc_amount,
+ pent.reference_no as pdc_ref
from
`tabPayment Entry` as pent inner join `tabPayment Entry Reference` as pref
on
@@ -481,19 +620,22 @@
where
pent.docstatus < 2 and pent.posting_date > %s
and pent.party_type = %s
- group by pent.party, pref.reference_name""", (report_date, party_type), as_dict=1):
- pdc_details.setdefault((pdc.invoice_no, pdc.party), pdc)
+ """, (report_date, party_type), as_dict=1)
+
+ for pdc in pdc_via_pe:
+ pdc_details.setdefault((pdc.invoice_no, pdc.party), []).append(pdc)
+
if scrub(party_type):
amount_field = ("jea.debit_in_account_currency"
if party_type == 'Supplier' else "jea.credit_in_account_currency")
else:
amount_field = "jea.debit + jea.credit"
- for pdc in frappe.db.sql("""
+ pdc_via_je = frappe.db.sql("""
select
jea.reference_name as invoice_no, jea.party, jea.party_type,
- max(je.posting_date) as pdc_date, sum(ifnull({0},0)) as pdc_amount,
- GROUP_CONCAT(je.cheque_no SEPARATOR ', ') as pdc_ref
+ je.posting_date as pdc_date, ifnull({0},0) as pdc_amount,
+ je.cheque_no as pdc_ref
from
`tabJournal Entry` as je inner join `tabJournal Entry Account` as jea
on
@@ -501,16 +643,10 @@
where
je.docstatus < 2 and je.posting_date > %s
and jea.party_type = %s
- group by jea.party, jea.reference_name""".format(amount_field), (report_date, party_type), as_dict=1):
- if (pdc.invoice_no, pdc.party) in pdc_details:
- key = (pdc.invoice_no, pdc.party)
- pdc_details[key]["pdc_amount"] += pdc.pdc_amount
- if pdc.pdc_ref:
- pdc_details[key]["pdc_ref"] += ", " + pdc.pdc_ref
- if pdc.pdc_date:
- pdc_details[key]["pdc_date"] = max(pdc_details[key]["pdc_date"], pdc.pdc_date)
- else:
- pdc_details.setdefault((pdc.invoice_no, pdc.party), pdc)
+ """.format(amount_field), (report_date, party_type), as_dict=1)
+
+ for pdc in pdc_via_je:
+ pdc_details.setdefault((pdc.invoice_no, pdc.party), []).append(pdc)
return pdc_details
@@ -550,8 +686,12 @@
voucher_details = frappe._dict()
if party_type == "Customer":
- for si in frappe.db.sql("""select name, due_date, po_no
- from `tabSales Invoice` where docstatus=1 and name in (%s)
+ for si in frappe.db.sql("""
+ select inv.name, inv.due_date, inv.po_no, GROUP_CONCAT(steam.sales_person SEPARATOR ', ') as sales_person
+ from `tabSales Invoice` inv
+ left join `tabSales Team` steam on steam.parent = inv.name and steam.parenttype = 'Sales Invoice'
+ where inv.docstatus=1 and inv.name in (%s)
+ group by inv.name
""" %(','.join(['%s'] *len(voucher_nos))), (tuple(voucher_nos)), as_dict=1):
si['delivery_note'] = dn_details.get(si.name)
voucher_details.setdefault(si.name, si)
diff --git a/erpnext/accounts/report/accounts_receivable/test_accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/test_accounts_receivable.py
new file mode 100644
index 0000000..34e6c83
--- /dev/null
+++ b/erpnext/accounts/report/accounts_receivable/test_accounts_receivable.py
@@ -0,0 +1,84 @@
+import frappe
+import frappe.defaults
+import unittest
+from frappe.utils import today, getdate, add_days
+from erpnext.accounts.report.accounts_receivable.accounts_receivable import execute
+from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
+from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry
+
+class TestAccountsReceivable(unittest.TestCase):
+ def test_accounts_receivable(self):
+ frappe.db.sql("delete from `tabSales Invoice` where company='_Test Company 2'")
+ frappe.db.sql("delete from `tabGL Entry` where company='_Test Company 2'")
+
+ filters = {
+ 'company': '_Test Company 2',
+ 'based_on_payment_terms': 1
+ }
+
+ name = make_sales_invoice()
+ report = execute(filters)
+
+ expected_data = [[100,30], [100,50], [100,20]]
+
+ self.assertEqual(expected_data[0], report[1][0][6:8])
+ self.assertEqual(expected_data[1], report[1][1][6:8])
+ self.assertEqual(expected_data[2], report[1][2][6:8])
+
+ make_payment(name)
+ report = execute(filters)
+
+ expected_data_after_payment = [[100,50], [100,20]]
+
+ self.assertEqual(expected_data_after_payment[0], report[1][0][6:8])
+ self.assertEqual(expected_data_after_payment[1], report[1][1][6:8])
+
+ make_credit_note(name)
+ report = execute(filters)
+
+ expected_data_after_credit_note = [[100,100,30,100,-30]]
+
+ self.assertEqual(expected_data_after_credit_note[0], report[1][0][6:11])
+
+
+def make_sales_invoice():
+ frappe.set_user("Administrator")
+
+ si = create_sales_invoice(company="_Test Company 2",
+ customer = '_Test Customer 2',
+ currency = 'EUR',
+ warehouse = 'Finished Goods - _TC2',
+ debit_to = 'Debtors - _TC2',
+ income_account = 'Sales - _TC2',
+ expense_account = 'Cost of Goods Sold - _TC2',
+ cost_center = '_Test Company 2 - _TC2',
+ do_not_save=1)
+
+ si.append('payment_schedule', dict(due_date=getdate(add_days(today(), 30)), invoice_portion=30.00, payment_amount=30))
+ si.append('payment_schedule', dict(due_date=getdate(add_days(today(), 60)), invoice_portion=50.00, payment_amount=50))
+ si.append('payment_schedule', dict(due_date=getdate(add_days(today(), 90)), invoice_portion=20.00, payment_amount=20))
+
+ si.submit()
+
+ return si.name
+
+def make_payment(docname):
+ pe = get_payment_entry("Sales Invoice", docname, bank_account="Cash - _TC2", party_amount=30)
+ pe.paid_from = "Debtors - _TC2"
+ pe.insert()
+ pe.submit()
+
+
+def make_credit_note(docname):
+ create_sales_invoice(company="_Test Company 2",
+ customer = '_Test Customer 2',
+ currency = 'EUR',
+ qty = -1,
+ warehouse = 'Finished Goods - _TC2',
+ debit_to = 'Debtors - _TC2',
+ income_account = 'Sales - _TC2',
+ expense_account = 'Cost of Goods Sold - _TC2',
+ cost_center = '_Test Company 2 - _TC2',
+ is_return = 1,
+ return_against = docname)
+
diff --git a/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.js b/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.js
index 96e5d18..a6f1457 100644
--- a/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.js
+++ b/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.js
@@ -11,25 +11,11 @@
"default": frappe.defaults.get_user_default("Company")
},
{
- "fieldname":"customer",
- "label": __("Customer"),
- "fieldtype": "Link",
- "options": "Customer"
- },
- {
- "fieldname":"customer_group",
- "label": __("Customer Group"),
- "fieldtype": "Link",
- "options": "Customer Group"
- },
- {
- "fieldname":"payment_terms_template",
- "label": __("Payment Terms Template"),
- "fieldtype": "Link",
- "options": "Payment Terms Template"
- },
- {
- "fieldtype": "Break",
+ "fieldname":"ageing_based_on",
+ "label": __("Ageing Based On"),
+ "fieldtype": "Select",
+ "options": 'Posting Date\nDue Date',
+ "default": "Posting Date"
},
{
"fieldname":"report_date",
@@ -38,13 +24,6 @@
"default": frappe.datetime.get_today()
},
{
- "fieldname":"ageing_based_on",
- "label": __("Ageing Based On"),
- "fieldtype": "Select",
- "options": 'Posting Date\nDue Date',
- "default": "Posting Date"
- },
- {
"fieldname":"range1",
"label": __("Ageing Range 1"),
"fieldtype": "Int",
@@ -64,6 +43,48 @@
"fieldtype": "Int",
"default": "90",
"reqd": 1
+ },
+ {
+ "fieldname":"finance_book",
+ "label": __("Finance Book"),
+ "fieldtype": "Link",
+ "options": "Finance Book"
+ },
+ {
+ "fieldname":"customer",
+ "label": __("Customer"),
+ "fieldtype": "Link",
+ "options": "Customer"
+ },
+ {
+ "fieldname":"customer_group",
+ "label": __("Customer Group"),
+ "fieldtype": "Link",
+ "options": "Customer Group"
+ },
+ {
+ "fieldname":"payment_terms_template",
+ "label": __("Payment Terms Template"),
+ "fieldtype": "Link",
+ "options": "Payment Terms Template"
+ },
+ {
+ "fieldname":"territory",
+ "label": __("Territory"),
+ "fieldtype": "Link",
+ "options": "Territory"
+ },
+ {
+ "fieldname":"sales_partner",
+ "label": __("Sales Partner"),
+ "fieldtype": "Link",
+ "options": "Sales Partner"
+ },
+ {
+ "fieldname":"sales_person",
+ "label": __("Sales Person"),
+ "fieldtype": "Link",
+ "options": "Sales Person"
}
],
diff --git a/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py b/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py
index 7bf9972..190031a 100644
--- a/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py
+++ b/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py
@@ -97,6 +97,12 @@
"fieldtype": "Link",
"options": "Customer Group",
"width": 80
+ },
+ {
+ "label": _("Sales Person"),
+ "fieldtype": "Data",
+ "fieldname": "sales_person",
+ "width": 120,
}]
if args.get("party_type") == "Supplier":
@@ -135,7 +141,7 @@
]
if args.get("party_type") == "Customer":
- row += [self.get_territory(party), self.get_customer_group(party)]
+ row += [self.get_territory(party), self.get_customer_group(party), ", ".join(set(party_dict.sales_person))]
if args.get("party_type") == "Supplier":
row += [self.get_supplier_group(party)]
@@ -156,15 +162,19 @@
"range1": 0,
"range2": 0,
"range3": 0,
- "range4": 0
+ "range4": 0,
+ "sales_person": []
})
)
for k in list(party_total[d.party]):
- if k != "currency":
+ if k not in ["currency", "sales_person"]:
party_total[d.party][k] += flt(d.get(k, 0))
party_total[d.party].currency = d.currency
+ if d.sales_person:
+ party_total[d.party].sales_person.append(d.sales_person)
+
return party_total
def get_voucherwise_data(self, party_naming_by, args):
@@ -181,12 +191,13 @@
cols += ["bill_no", "bill_date"]
cols += ["invoiced_amt", "paid_amt", "credit_amt",
- "outstanding_amt", "age", "range1", "range2", "range3", "range4", "currency"]
+ "outstanding_amt", "age", "range1", "range2", "range3", "range4", "currency", "pdc/lc_date", "pdc/lc_ref",
+ "pdc/lc_amount", "remaining_balance"]
if args.get("party_type") == "Supplier":
cols += ["supplier_group", "remarks"]
if args.get("party_type") == "Customer":
- cols += ["territory", "customer_group", "remarks"]
+ cols += ["po_no", "do_no", "territory", "customer_group", "sales_person", "remarks"]
return self.make_data_dict(cols, voucherwise_data)
diff --git a/erpnext/accounts/report/trial_balance_simple/trial_balance_simple.json b/erpnext/accounts/report/trial_balance_simple/trial_balance_simple.json
new file mode 100644
index 0000000..ea5a97b
--- /dev/null
+++ b/erpnext/accounts/report/trial_balance_simple/trial_balance_simple.json
@@ -0,0 +1,30 @@
+{
+ "add_total_row": 1,
+ "creation": "2018-11-22 16:53:19.167935",
+ "disabled": 0,
+ "docstatus": 0,
+ "doctype": "Report",
+ "idx": 0,
+ "is_standard": "Yes",
+ "modified": "2018-11-22 17:40:11.317567",
+ "modified_by": "Administrator",
+ "module": "Accounts",
+ "name": "Trial Balance (Simple)",
+ "owner": "Administrator",
+ "prepared_report": 0,
+ "query": "select fiscal_year as \"Fiscal Year:Data:80\",\n\tcompany as \"Company:Data:220\",\n\tposting_date as \"Posting Date:Date:100\",\n\taccount as \"Account:Data:380\",\n\tsum(debit) as \"Debit:Currency:140\",\n\tsum(credit) as \"Credit:Currency:140\"\nfrom `tabGL Entry`\ngroup by fiscal_year, company, posting_date, account\norder by fiscal_year, company, posting_date, account",
+ "ref_doctype": "GL Entry",
+ "report_name": "Trial Balance (Simple)",
+ "report_type": "Query Report",
+ "roles": [
+ {
+ "role": "Accounts User"
+ },
+ {
+ "role": "Accounts Manager"
+ },
+ {
+ "role": "Auditor"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.js b/erpnext/buying/doctype/purchase_order/purchase_order.js
index a505e49..019d0de 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.js
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.js
@@ -315,7 +315,6 @@
method: "erpnext.stock.doctype.material_request.material_request.make_purchase_order",
source_doctype: "Material Request",
target: me.frm,
- args: args,
setters: {
company: me.frm.doc.company
},
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py
index ed761ce..3c4ef2b 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.py
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.py
@@ -91,6 +91,7 @@
self.party_account_currency = get_party_account_currency("Supplier", self.supplier, self.company)
def validate_minimum_order_qty(self):
+ if not self.get("items"): return
items = list(set([d.item_code for d in self.get("items")]))
itemwise_min_order_qty = frappe._dict(frappe.db.sql("""select name, min_order_qty
diff --git a/erpnext/buying/report/purchase_analytics/purchase_analytics.js b/erpnext/buying/report/purchase_analytics/purchase_analytics.js
index b55046e..e17973c 100644
--- a/erpnext/buying/report/purchase_analytics/purchase_analytics.js
+++ b/erpnext/buying/report/purchase_analytics/purchase_analytics.js
@@ -77,9 +77,20 @@
events: {
onCheckRow: function(data) {
row_name = data[2].content;
- row_values = data.slice(5).map(function (column) {
- return column.content;
- })
+ length = data.length;
+
+ var tree_type = frappe.query_report.filters[0].value;
+
+ if(tree_type == "Supplier" || tree_type == "Item") {
+ row_values = data.slice(4,length-1).map(function (column) {
+ return column.content;
+ })
+ }
+ else {
+ row_values = data.slice(3,length-1).map(function (column) {
+ return column.content;
+ })
+ }
entry = {
'name':row_name,
diff --git a/erpnext/config/accounts.py b/erpnext/config/accounts.py
index d9ffced..9d8e1bf 100644
--- a/erpnext/config/accounts.py
+++ b/erpnext/config/accounts.py
@@ -1,8 +1,10 @@
from __future__ import unicode_literals
from frappe import _
+import frappe
+
def get_data():
- return [
+ config = [
{
"label": _("Billing"),
"items": [
@@ -25,48 +27,7 @@
"type": "doctype",
"name": "Payment Entry",
"description": _("Bank/Cash transactions against party or for internal transfer")
- },
- {
- "type": "page",
- "name": "pos",
- "label": _("POS"),
- "description": _("Point of Sale")
- },
- {
- "type": "doctype",
- "name": "Cashier Closing",
- "description": _("Cashier Closing")
- },
- {
- "type": "doctype",
- "name": "Auto Repeat",
- "label": _("Auto Repeat"),
- "description": _("To make recurring documents")
- },
- {
- "type": "doctype",
- "name": "Loyalty Program",
- "label": _("Loyalty Program"),
- "description": _("To make Customer based incentive schemes.")
- },
- {
- "type": "doctype",
- "name": "Loyalty Point Entry",
- "label": _("Loyalty Point Entry"),
- "description": _("To view logs of Loyalty Points assigned to a Customer.")
- },
- {
- "type": "report",
- "name": "Accounts Receivable",
- "doctype": "Sales Invoice",
- "is_query_report": True
- },
- {
- "type": "report",
- "name": "Accounts Payable",
- "doctype": "Purchase Invoice",
- "is_query_report": True
- },
+ }
]
},
@@ -93,7 +54,7 @@
},
{
"type": "report",
- "name":"General Ledger",
+ "name": "General Ledger",
"doctype": "GL Entry",
"is_query_report": True,
},
@@ -123,6 +84,18 @@
"items": [
{
"type": "report",
+ "name": "Accounts Receivable",
+ "doctype": "Sales Invoice",
+ "is_query_report": True
+ },
+ {
+ "type": "report",
+ "name": "Accounts Payable",
+ "doctype": "Purchase Invoice",
+ "is_query_report": True
+ },
+ {
+ "type": "report",
"name": "Trial Balance",
"doctype": "GL Entry",
"is_query_report": True,
@@ -225,49 +198,6 @@
]
},
{
- "label": _("Goods and Services Tax (GST India)"),
- "items": [
- {
- "type": "doctype",
- "name": "GST Settings",
- },
- {
- "type": "doctype",
- "name": "GST HSN Code",
- },
- {
- "type": "report",
- "name": "GSTR-1",
- "is_query_report": True
- },
- {
- "type": "report",
- "name": "GSTR-2",
- "is_query_report": True
- },
- {
- "type": "report",
- "name": "GST Sales Register",
- "is_query_report": True
- },
- {
- "type": "report",
- "name": "GST Purchase Register",
- "is_query_report": True
- },
- {
- "type": "report",
- "name": "GST Itemised Sales Register",
- "is_query_report": True
- },
- {
- "type": "report",
- "name": "GST Itemised Purchase Register",
- "is_query_report": True
- },
- ]
- },
- {
"label": _("Budget and Cost Center"),
"items": [
{
@@ -290,7 +220,7 @@
"doctype": "Cost Center"
},
{
- "type":"doctype",
+ "type": "doctype",
"name": "Monthly Distribution",
"description": _("Seasonality for setting budgets, targets etc.")
},
@@ -347,29 +277,24 @@
},
{
"type": "doctype",
- "name": "POS Settings",
- "description": _("Setup mode of POS (Online / Offline)")
- },
- {
- "type": "doctype",
- "name": "POS Profile",
- "label": _("Point-of-Sale Profile"),
- "description": _("Setup default values for POS Invoices")
- },
- {
- "type": "doctype",
- "name":"Terms and Conditions",
+ "name": "Terms and Conditions",
"label": _("Terms and Conditions Template"),
"description": _("Template of terms or contract.")
},
{
"type": "doctype",
- "name":"Mode of Payment",
+ "name": "Mode of Payment",
"description": _("e.g. Bank, Cash, Credit Card")
},
{
"type": "doctype",
- "name":"C-Form",
+ "name": "Auto Repeat",
+ "label": _("Auto Repeat"),
+ "description": _("To make recurring documents")
+ },
+ {
+ "type": "doctype",
+ "name": "C-Form",
"description": _("C-Form records"),
"country": "India"
}
@@ -506,12 +431,12 @@
"items": [
{
"type": "doctype",
- "name":"Shareholder",
+ "name": "Shareholder",
"description": _("List of available Shareholders with folio numbers")
},
{
"type": "doctype",
- "name":"Share Transfer",
+ "name": "Share Transfer",
"description": _("List of all share transactions"),
},
{
@@ -529,28 +454,6 @@
]
},
{
- "label": _("Subscription Management"),
- "icon": "fa fa-microchip ",
- "items": [
- {
- "type": "doctype",
- "name":"Subscriber",
- },
- {
- "type": "doctype",
- "name":"Subscription Plan",
- },
- {
- "type": "doctype",
- "name":"Subscription"
- },
- {
- "type": "doctype",
- "name": "Subscription Settings"
- }
- ]
- },
- {
"label": _("Help"),
"icon": "fa fa-facetime-video",
"items": [
@@ -572,3 +475,117 @@
]
}
]
+ gst = {
+ "label": _("Goods and Services Tax (GST India)"),
+ "items": [
+ {
+ "type": "doctype",
+ "name": "GST Settings",
+ },
+ {
+ "type": "doctype",
+ "name": "GST HSN Code",
+ },
+ {
+ "type": "report",
+ "name": "GSTR-1",
+ "is_query_report": True
+ },
+ {
+ "type": "report",
+ "name": "GSTR-2",
+ "is_query_report": True
+ },
+ {
+ "type": "report",
+ "name": "GST Sales Register",
+ "is_query_report": True
+ },
+ {
+ "type": "report",
+ "name": "GST Purchase Register",
+ "is_query_report": True
+ },
+ {
+ "type": "report",
+ "name": "GST Itemised Sales Register",
+ "is_query_report": True
+ },
+ {
+ "type": "report",
+ "name": "GST Itemised Purchase Register",
+ "is_query_report": True
+ },
+ ]
+ }
+ retail = {
+ "label": _("Retail Operations"),
+ "items": [
+ {
+ "type": "page",
+ "name": "pos",
+ "label": _("POS"),
+ "description": _("Point of Sale")
+ },
+ {
+ "type": "doctype",
+ "name": "Cashier Closing",
+ "description": _("Cashier Closing")
+ },
+ {
+ "type": "doctype",
+ "name": "POS Settings",
+ "description": _("Setup mode of POS (Online / Offline)")
+ },
+ {
+ "type": "doctype",
+ "name": "POS Profile",
+ "label": _("Point-of-Sale Profile"),
+ "description": _("Setup default values for POS Invoices")
+ },
+ {
+ "type": "doctype",
+ "name": "Loyalty Program",
+ "label": _("Loyalty Program"),
+ "description": _("To make Customer based incentive schemes.")
+ },
+ {
+ "type": "doctype",
+ "name": "Loyalty Point Entry",
+ "label": _("Loyalty Point Entry"),
+ "description": _("To view logs of Loyalty Points assigned to a Customer.")
+ }
+ ]
+ }
+ subscriptions = {
+ "label": _("Subscription Management"),
+ "icon": "fa fa-microchip ",
+ "items": [
+ {
+ "type": "doctype",
+ "name": "Subscription Plan",
+ },
+ {
+ "type": "doctype",
+ "name": "Subscription"
+ },
+ {
+ "type": "doctype",
+ "name": "Subscription Settings"
+ }
+ ]
+ }
+ countries = frappe.get_all("Company", fields="country")
+ countries = [country["country"] for country in countries]
+ if "India" in countries:
+ config.insert(7, gst)
+ domains = frappe.get_active_domains()
+ if "Retail" in domains:
+ config.insert(2, retail)
+ else:
+ config.insert(7, retail)
+ if "Services" in domains:
+ config.insert(2, subscriptions)
+ else:
+ config.insert(7, subscriptions)
+ return config
diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py
index ee6dc2a..541e56d 100644
--- a/erpnext/controllers/buying_controller.py
+++ b/erpnext/controllers/buying_controller.py
@@ -678,7 +678,7 @@
frappe.db.sql("delete from `tabSerial No` where purchase_document_no=%s", self.name)
def validate_schedule_date(self):
- if not self.schedule_date:
+ if not self.schedule_date and self.get("items"):
self.schedule_date = min([d.schedule_date for d in self.get("items")])
if self.schedule_date:
diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py
index 7b3f740..63e89ab 100644
--- a/erpnext/controllers/stock_controller.py
+++ b/erpnext/controllers/stock_controller.py
@@ -12,6 +12,9 @@
from erpnext.stock.stock_ledger import get_valuation_rate
from erpnext.stock import get_warehouse_account_map
+class QualityInspectionRequiredError(frappe.ValidationError): pass
+class QualityInspectionRejectedError(frappe.ValidationError): pass
+
class StockController(AccountsController):
def validate(self):
super(StockController, self).validate()
@@ -317,7 +320,6 @@
def validate_inspection(self):
'''Checks if quality inspection is set for Items that require inspection.
On submit, throw an exception'''
-
inspection_required_fieldname = None
if self.doctype in ["Purchase Receipt", "Purchase Invoice"]:
inspection_required_fieldname = "inspection_required_before_purchase"
@@ -330,17 +332,25 @@
return
for d in self.get('items'):
- raise_exception = False
+ qa_required = False
if (inspection_required_fieldname and not d.quality_inspection and
frappe.db.get_value("Item", d.item_code, inspection_required_fieldname)):
- raise_exception = True
+ qa_required = True
elif self.doctype == "Stock Entry" and not d.quality_inspection and d.t_warehouse:
- raise_exception = True
+ qa_required = True
- if raise_exception:
+ if qa_required:
frappe.msgprint(_("Quality Inspection required for Item {0}").format(d.item_code))
if self.docstatus==1:
- raise frappe.ValidationError
+ raise QualityInspectionRequiredError
+ elif self.docstatus == 1:
+ if d.quality_inspection:
+ qa_doc = frappe.get_doc("Quality Inspection", d.quality_inspection)
+ qa_failed = any([r.status=="Rejected" for r in qa_doc.readings])
+ if qa_failed:
+ frappe.throw(_("Row {0}: Quality Inspection rejected for item {1}")
+ .format(d.idx, d.item_code), QualityInspectionRejectedError)
+
def update_blanket_order(self):
blanket_orders = list(set([d.blanket_order for d in self.items if d.blanket_order]))
diff --git a/erpnext/demo/setup/setup_data.py b/erpnext/demo/setup/setup_data.py
index 0fd7bb7..48dcdbe 100644
--- a/erpnext/demo/setup/setup_data.py
+++ b/erpnext/demo/setup/setup_data.py
@@ -376,7 +376,7 @@
company_abbr = frappe.get_cached_value('Company', erpnext.get_default_company(), "abbr")
pos = frappe.new_doc('POS Profile')
pos.user = frappe.db.get_global('demo_accounts_user')
- pos.pos_profile_name = "Demo POS Profile"
+ pos.name = "Demo POS Profile"
pos.naming_series = 'SINV-'
pos.update_stock = 0
pos.write_off_account = 'Cost of Goods Sold - '+ company_abbr
diff --git a/erpnext/education/report/student_fee_collection/student_fee_collection.json b/erpnext/education/report/student_fee_collection/student_fee_collection.json
index 07fc27c..eb945cf 100644
--- a/erpnext/education/report/student_fee_collection/student_fee_collection.json
+++ b/erpnext/education/report/student_fee_collection/student_fee_collection.json
@@ -1,18 +1,18 @@
{
"add_total_row": 0,
- "apply_user_permissions": 1,
"creation": "2016-06-22 02:58:41.024538",
"disabled": 0,
"docstatus": 0,
"doctype": "Report",
"idx": 3,
"is_standard": "Yes",
- "modified": "2017-11-10 19:41:37.320224",
+ "modified": "2018-12-17 16:46:46.176620",
"modified_by": "Administrator",
"module": "Education",
"name": "Student Fee Collection",
"owner": "Administrator",
- "query": "SELECT\n student as \"Student:Link/Student:200\",\n student_name as \"Student Name::200\",\n sum(paid_amount) as \"Paid Amount:Currency:150\",\n sum(outstanding_amount) as \"Outstanding Amount:Currency:150\",\n sum(grand_total) as \"Grand Total:Currency:150\"\nFROM\n `tabFees` \nGROUP BY\n student",
+ "prepared_report": 0,
+ "query": "SELECT\n student as \"Student:Link/Student:200\",\n student_name as \"Student Name::200\",\n sum(grand_total) - sum(outstanding_amount) as \"Paid Amount:Currency:150\",\n sum(outstanding_amount) as \"Outstanding Amount:Currency:150\",\n sum(grand_total) as \"Grand Total:Currency:150\"\nFROM\n `tabFees` \nGROUP BY\n student",
"ref_doctype": "Fees",
"report_name": "Student Fee Collection",
"report_type": "Query Report",
diff --git a/erpnext/hooks.py b/erpnext/hooks.py
index c1bb41b..14e4f68 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -12,7 +12,7 @@
source_link = "https://github.com/frappe/erpnext"
develop_version = '12.x.x-develop'
-staging_version = '11.0.3-beta.26'
+staging_version = '11.0.3-beta.32'
error_report_email = "support@erpnext.com"
diff --git a/erpnext/hr/doctype/employee/employee.py b/erpnext/hr/doctype/employee/employee.py
index cb4c190..d518cd8 100755
--- a/erpnext/hr/doctype/employee/employee.py
+++ b/erpnext/hr/doctype/employee/employee.py
@@ -13,8 +13,8 @@
from erpnext.utilities.transaction_base import delete_events
from frappe.utils.nestedset import NestedSet
-class EmployeeUserDisabledError(frappe.ValidationError):
- pass
+class EmployeeUserDisabledError(frappe.ValidationError): pass
+class EmployeeLeftValidationError(frappe.ValidationError): pass
class Employee(NestedSet):
nsm_parent_field = 'reports_to'
@@ -62,8 +62,8 @@
def validate_user_details(self):
data = frappe.db.get_value('User',
self.user_id, ['enabled', 'user_image'], as_dict=1)
-
- self.image = data.get("user_image")
+ if data.get("user_image"):
+ self.image = data.get("user_image")
self.validate_for_enabled_user_id(data.get("enabled", 0))
self.validate_duplicate_user_id()
@@ -147,8 +147,16 @@
validate_email_add(self.personal_email, True)
def validate_status(self):
- if self.status == 'Left' and not self.relieving_date:
- throw(_("Please enter relieving date."))
+ if self.status == 'Left':
+ reports_to = frappe.db.get_all('Employee',
+ filters={'reports_to': self.name}
+ )
+ if reports_to:
+ link_to_employees = [frappe.utils.get_link_to_form('Employee', employee.name) for employee in reports_to]
+ throw(_("Employee status cannot be set to 'Left' as following employees are currently reporting to this employee: ")
+ + ', '.join(link_to_employees), EmployeeLeftValidationError)
+ if not self.relieving_date:
+ throw(_("Please enter relieving date."))
def validate_for_enabled_user_id(self, enabled):
if not self.status == 'Active':
diff --git a/erpnext/hr/doctype/employee/test_employee.py b/erpnext/hr/doctype/employee/test_employee.py
index 1afb8f4..5a63beb 100644
--- a/erpnext/hr/doctype/employee/test_employee.py
+++ b/erpnext/hr/doctype/employee/test_employee.py
@@ -7,6 +7,7 @@
import erpnext
import unittest
import frappe.utils
+from erpnext.hr.doctype.employee.employee import EmployeeLeftValidationError
test_records = frappe.get_test_records('Employee')
@@ -32,6 +33,18 @@
email_queue = frappe.db.sql("""select * from `tabEmail Queue`""", as_dict=True)
self.assertTrue("Subject: Birthday Reminder" in email_queue[0].message)
+ def test_employee_status_left(self):
+ employee1 = make_employee("test_employee_1@company.com")
+ employee2 = make_employee("test_employee_2@company.com")
+ employee1_doc = frappe.get_doc("Employee", employee1)
+ employee2_doc = frappe.get_doc("Employee", employee2)
+ employee2_doc.reload()
+ employee2_doc.reports_to = employee1_doc.name
+ employee2_doc.save()
+ employee1_doc.reload()
+ employee1_doc.status = 'Left'
+ self.assertRaises(EmployeeLeftValidationError, employee1_doc.save)
+
def make_employee(user):
if not frappe.db.get_value("User", user):
frappe.get_doc({
diff --git a/erpnext/hr/doctype/employee_benefit_claim/employee_benefit_claim.py b/erpnext/hr/doctype/employee_benefit_claim/employee_benefit_claim.py
index 9a0c5f7..bf150b1 100644
--- a/erpnext/hr/doctype/employee_benefit_claim/employee_benefit_claim.py
+++ b/erpnext/hr/doctype/employee_benefit_claim/employee_benefit_claim.py
@@ -78,12 +78,17 @@
total_pro_rata_max = 0
benefit_amount_total = 0
for sal_struct_row in sal_struct.get("earnings"):
- pay_against_benefit_claim, max_benefit_amount = frappe.db.get_value("Salary Component", sal_struct_row.salary_component, ["pay_against_benefit_claim", "max_benefit_amount"])
+ try:
+ pay_against_benefit_claim, max_benefit_amount = frappe.db.get_value("Salary Component", sal_struct_row.salary_component, ["pay_against_benefit_claim", "max_benefit_amount"])
+ except TypeError:
+ # show the error in tests?
+ frappe.throw("Unable to find Salary Component {0}".format(sal_struct_row.salary_component))
if sal_struct_row.is_flexible_benefit == 1 and pay_against_benefit_claim != 1:
total_pro_rata_max += max_benefit_amount
if total_pro_rata_max > 0:
for sal_struct_row in sal_struct.get("earnings"):
pay_against_benefit_claim, max_benefit_amount = frappe.db.get_value("Salary Component", sal_struct_row.salary_component, ["pay_against_benefit_claim", "max_benefit_amount"])
+
if sal_struct_row.is_flexible_benefit == 1 and pay_against_benefit_claim != 1:
component_max = max_benefit_amount
benefit_amount = component_max * sal_struct.max_benefits / total_pro_rata_max
diff --git a/erpnext/hr/doctype/employee_separation/employee_separation_list.js b/erpnext/hr/doctype/employee_separation/employee_separation_list.js
index 11487cc..76c58f5 100644
--- a/erpnext/hr/doctype/employee_separation/employee_separation_list.js
+++ b/erpnext/hr/doctype/employee_separation/employee_separation_list.js
@@ -1,5 +1,5 @@
frappe.listview_settings['Employee Separation'] = {
- add_fields: ["boarding_status", "employee_name", "date_of_joining", "department"],
+ add_fields: ["boarding_status", "employee_name", "department"],
filters:[["boarding_status","=", "Pending"]],
get_indicator: function(doc) {
return [__(doc.boarding_status), frappe.utils.guess_colour(doc.boarding_status), "status,=," + doc.boarding_status];
diff --git a/erpnext/hr/doctype/leave_application/leave_application.js b/erpnext/hr/doctype/leave_application/leave_application.js
index a77dd32..5bce348 100755
--- a/erpnext/hr/doctype/leave_application/leave_application.js
+++ b/erpnext/hr/doctype/leave_application/leave_application.js
@@ -14,7 +14,7 @@
doctype: frm.doc.doctype
}
};
- });
+ });
frm.set_query("employee", erpnext.queries.employee);
},
@@ -83,7 +83,7 @@
if (!frm.doc.employee && frappe.defaults.get_user_permissions()) {
const perm = frappe.defaults.get_user_permissions();
if (perm && perm['Employee']) {
- frm.set_value('employee', perm['Employee']["docs"][0])
+ frm.set_value('employee', perm['Employee'].map(perm_doc => perm_doc.doc)[0]);
}
}
},
diff --git a/erpnext/hr/doctype/leave_application/leave_application.py b/erpnext/hr/doctype/leave_application/leave_application.py
index aca277e..6b7c0f7 100755
--- a/erpnext/hr/doctype/leave_application/leave_application.py
+++ b/erpnext/hr/doctype/leave_application/leave_application.py
@@ -187,7 +187,7 @@
self.total_leave_days = get_number_of_leave_days(self.employee, self.leave_type,
self.from_date, self.to_date, self.half_day, self.half_day_date)
- if self.total_leave_days == 0:
+ if self.total_leave_days <= 0:
frappe.throw(_("The day(s) on which you are applying for leave are holidays. You need not apply for leave."))
if not is_lwp(self.leave_type):
diff --git a/erpnext/hr/doctype/salary_slip/test_salary_slip.py b/erpnext/hr/doctype/salary_slip/test_salary_slip.py
index 208a733..079bec5 100644
--- a/erpnext/hr/doctype/salary_slip/test_salary_slip.py
+++ b/erpnext/hr/doctype/salary_slip/test_salary_slip.py
@@ -256,6 +256,9 @@
raise
frappe.db.sql("""delete from `tabAdditional Salary` where employee=%s""", (employee))
+ # undelete fixture data
+ frappe.db.rollback()
+
def make_holiday_list(self):
fiscal_year = get_fiscal_year(nowdate(), company=erpnext.get_default_company())
if not frappe.db.get_value("Holiday List", "Salary Slip Test Holiday List"):
diff --git a/erpnext/hr/doctype/salary_structure/salary_structure.py b/erpnext/hr/doctype/salary_structure/salary_structure.py
index 7ead140..202ae9b 100644
--- a/erpnext/hr/doctype/salary_structure/salary_structure.py
+++ b/erpnext/hr/doctype/salary_structure/salary_structure.py
@@ -4,7 +4,7 @@
from __future__ import unicode_literals
import frappe
-from frappe.utils import flt, cint
+from frappe.utils import flt, cint, cstr
from frappe import _
from frappe.model.mapper import get_mapped_doc
from frappe.model.document import Document
@@ -22,7 +22,7 @@
overwritten_fields_if_missing = ["amount_based_on_formula", "formula", "amount"]
for table in ["earnings", "deductions"]:
for d in self.get(table):
- component_default_value = frappe.db.get_value("Salary Component", str(d.salary_component),
+ component_default_value = frappe.db.get_value("Salary Component", cstr(d.salary_component),
overwritten_fields + overwritten_fields_if_missing, as_dict=1)
if component_default_value:
for fieldname in overwritten_fields:
diff --git a/erpnext/hr/doctype/upload_attendance/test_upload_attendance.py b/erpnext/hr/doctype/upload_attendance/test_upload_attendance.py
new file mode 100644
index 0000000..5ab2847
--- /dev/null
+++ b/erpnext/hr/doctype/upload_attendance/test_upload_attendance.py
@@ -0,0 +1,34 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+import frappe
+import unittest
+from frappe.utils import getdate
+from erpnext.hr.doctype.upload_attendance.upload_attendance import get_data
+from erpnext.hr.doctype.employee.test_employee import make_employee
+
+class TestUploadAttendance(unittest.TestCase):
+ def test_date_range(self):
+ employee = make_employee("test_employee@company.com")
+ employee_doc = frappe.get_doc("Employee", employee)
+ date_of_joining = "2018-01-02"
+ relieving_date = "2018-01-03"
+ from_date = "2018-01-01"
+ to_date = "2018-01-04"
+ employee_doc.date_of_joining = date_of_joining
+ employee_doc.relieving_date = relieving_date
+ employee_doc.save()
+ args = {
+ "from_date": from_date,
+ "to_date": to_date
+ }
+ data = get_data(args)
+ filtered_data = []
+ for row in data:
+ if row[1] == employee:
+ filtered_data.append(row)
+ print(filtered_data)
+ for row in filtered_data:
+ self.assertTrue(getdate(row[3]) >= getdate(date_of_joining) and getdate(row[3]) <= getdate(relieving_date))
diff --git a/erpnext/hr/doctype/upload_attendance/upload_attendance.py b/erpnext/hr/doctype/upload_attendance/upload_attendance.py
index 3d080a7..db74b10 100644
--- a/erpnext/hr/doctype/upload_attendance/upload_attendance.py
+++ b/erpnext/hr/doctype/upload_attendance/upload_attendance.py
@@ -41,16 +41,28 @@
return w
def add_data(w, args):
+ data = get_data(args)
+ writedata(w, data)
+ return w
+
+def get_data(args):
dates = get_dates(args)
employees = get_active_employees()
existing_attendance_records = get_existing_attendance_records(args)
+ data = []
for date in dates:
for employee in employees:
+ if getdate(date) < getdate(employee.date_of_joining):
+ continue
+ if employee.relieving_date:
+ if getdate(date) > getdate(employee.relieving_date):
+ continue
existing_attendance = {}
if existing_attendance_records \
- and tuple([getdate(date), employee.name]) in existing_attendance_records:
+ and tuple([getdate(date), employee.name]) in existing_attendance_records \
+ and getdate(employee.date_of_joining) >= getdate(date) \
+ and getdate(employee.relieving_date) <= getdate(date):
existing_attendance = existing_attendance_records[tuple([getdate(date), employee.name])]
-
row = [
existing_attendance and existing_attendance.name or "",
employee.name, employee.employee_name, date,
@@ -58,8 +70,12 @@
existing_attendance and existing_attendance.leave_type or "", employee.company,
existing_attendance and existing_attendance.naming_series or get_naming_series(),
]
- w.writerow(row)
- return w
+ data.append(row)
+ return data
+
+def writedata(w, data):
+ for row in data:
+ w.writerow(row)
def get_dates(args):
"""get list of dates in between from date and to date"""
@@ -68,8 +84,13 @@
return dates
def get_active_employees():
- employees = frappe.db.sql("""select name, employee_name, company
- from tabEmployee where docstatus < 2 and status = 'Active'""", as_dict=1)
+ employees = frappe.db.get_all('Employee',
+ fields=['name', 'employee_name', 'date_of_joining', 'company', 'relieving_date'],
+ filters={
+ 'docstatus': ['<', 2],
+ 'status': 'Active'
+ }
+ )
return employees
def get_existing_attendance_records(args):
diff --git a/erpnext/manufacturing/doctype/bom/bom.js b/erpnext/manufacturing/doctype/bom/bom.js
index a01011a..2615b31 100644
--- a/erpnext/manufacturing/doctype/bom/bom.js
+++ b/erpnext/manufacturing/doctype/bom/bom.js
@@ -402,6 +402,8 @@
var toggle_operations = function(frm) {
frm.toggle_display("operations_section", cint(frm.doc.with_operations) == 1);
+ frm.toggle_display("transfer_material_against", cint(frm.doc.with_operations) == 1);
+ frm.toggle_reqd("transfer_material_against", cint(frm.doc.with_operations) == 1);
};
frappe.ui.form.on("BOM", "with_operations", function(frm) {
diff --git a/erpnext/manufacturing/doctype/bom/bom.json b/erpnext/manufacturing/doctype/bom/bom.json
index 8c5f2af..0cf7dc4 100644
--- a/erpnext/manufacturing/doctype/bom/bom.json
+++ b/erpnext/manufacturing/doctype/bom/bom.json
@@ -87,41 +87,6 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
- "default": "1",
- "description": "Quantity of item obtained after manufacturing / repacking from given quantities of raw materials",
- "fieldname": "quantity",
- "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": "Quantity",
- "length": 0,
- "no_copy": 0,
- "oldfieldname": "quantity",
- "oldfieldtype": "Currency",
- "permlevel": 0,
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "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": "uom",
"fieldtype": "Link",
"hidden": 0,
@@ -154,8 +119,10 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
- "fieldname": "inspection_required",
- "fieldtype": "Check",
+ "default": "1",
+ "description": "Quantity of item obtained after manufacturing / repacking from given quantities of raw materials",
+ "fieldname": "quantity",
+ "fieldtype": "Float",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
@@ -163,51 +130,18 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
- "label": "Inspection Required",
+ "label": "Quantity",
"length": 0,
"no_copy": 0,
+ "oldfieldname": "quantity",
+ "oldfieldtype": "Currency",
"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": "inspection_required",
- "fieldname": "quality_inspection_template",
- "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": "Quality Inspection Template",
- "length": 0,
- "no_copy": 0,
- "options": "Quality Inspection Template",
- "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,
+ "reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
@@ -346,77 +280,11 @@
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
- "allow_on_submit": 1,
+ "allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
- "fieldname": "rm_cost_as_per",
- "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": "Rate Of Materials Based On",
- "length": 0,
- "no_copy": 0,
- "options": "Valuation Rate\nLast Purchase Rate\nPrice List",
- "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,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "depends_on": "eval:doc.rm_cost_as_per===\"Price List\"",
- "fieldname": "buying_price_list",
- "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": "Price List",
- "length": 0,
- "no_copy": 0,
- "options": "Price List",
- "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,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 1,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "default": "1",
- "fieldname": "set_rate_of_sub_assembly_item_based_on_bom",
+ "fieldname": "inspection_required",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
@@ -425,7 +293,7 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
- "label": "Set rate of sub-assembly item based on BOM",
+ "label": "Inspection Required",
"length": 0,
"no_copy": 0,
"permlevel": 0,
@@ -481,7 +349,7 @@
"collapsible": 0,
"columns": 0,
"fieldname": "allow_same_item_multiple_times",
- "fieldtype": "Data",
+ "fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
@@ -508,12 +376,12 @@
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
- "allow_on_submit": 0,
+ "allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"columns": 0,
- "depends_on": "with_operations",
- "fieldname": "transfer_material_against_job_card",
+ "default": "1",
+ "fieldname": "set_rate_of_sub_assembly_item_based_on_bom",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
@@ -522,7 +390,7 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
- "label": "Transfer Material Against Job Card",
+ "label": "Set rate of sub-assembly item based on BOM",
"length": 0,
"no_copy": 0,
"permlevel": 0,
@@ -545,6 +413,40 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "depends_on": "inspection_required",
+ "fieldname": "quality_inspection_template",
+ "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": "Quality Inspection Template",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Quality Inspection Template",
+ "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": "currency_detail",
"fieldtype": "Section Break",
"hidden": 0,
@@ -610,6 +512,72 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "default": "",
+ "fieldname": "transfer_material_against",
+ "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": "Transfer Material Against",
+ "length": 0,
+ "no_copy": 0,
+ "options": "\nWork Order\nJob Card",
+ "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": "conversion_rate",
+ "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": "Conversion Rate",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "9",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "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": "column_break_12",
"fieldtype": "Column Break",
"hidden": 0,
@@ -670,12 +638,12 @@
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
- "allow_on_submit": 0,
+ "allow_on_submit": 1,
"bold": 0,
"collapsible": 0,
"columns": 0,
- "fieldname": "conversion_rate",
- "fieldtype": "Float",
+ "fieldname": "rm_cost_as_per",
+ "fieldtype": "Select",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
@@ -683,17 +651,50 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
- "label": "Conversion Rate",
+ "label": "Rate Of Materials Based On",
"length": 0,
"no_copy": 0,
+ "options": "Valuation Rate\nLast Purchase Rate\nPrice List",
"permlevel": 0,
- "precision": "9",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
- "reqd": 1,
+ "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": 1,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "depends_on": "eval:doc.rm_cost_as_per===\"Price List\"",
+ "fieldname": "buying_price_list",
+ "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": "Price List",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Price List",
+ "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,
@@ -707,7 +708,7 @@
"collapsible": 0,
"columns": 0,
"depends_on": "",
- "description": "Specify the operations, operating cost and give a unique Operation no to your operations.",
+ "description": "",
"fieldname": "operations_section",
"fieldtype": "Section Break",
"hidden": 0,
@@ -1976,7 +1977,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2018-10-24 02:07:21.618275",
+ "modified": "2018-12-13 17:45:44.843197",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "BOM",
diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py
index d72f00a..54ffa06 100644
--- a/erpnext/manufacturing/doctype/bom/bom.py
+++ b/erpnext/manufacturing/doctype/bom/bom.py
@@ -81,7 +81,7 @@
def get_item_det(self, item_code):
item = frappe.db.sql("""select name, item_name, docstatus, description, image,
- is_sub_contracted_item, stock_uom, default_bom, last_purchase_rate, allow_transfer_for_manufacture
+ is_sub_contracted_item, stock_uom, default_bom, last_purchase_rate, include_item_in_manufacturing
from `tabItem` where name=%s""", item_code, as_dict = 1)
if not item:
@@ -109,7 +109,7 @@
"item_name": item.item_name,
"bom_no": item.bom_no,
"stock_qty": item.stock_qty,
- "allow_transfer_for_manufacture": item.allow_transfer_for_manufacture
+ "include_item_in_manufacturing": item.include_item_in_manufacturing
})
for r in ret:
if not item.get(r):
@@ -128,8 +128,8 @@
self.validate_rm_item(item)
args['bom_no'] = args['bom_no'] or item and cstr(item[0]['default_bom']) or ''
- args['transfer_for_manufacture'] = (cstr(args.get('allow_transfer_for_manufacture', '')) or
- item and item[0].allow_transfer_for_manufacture or 0)
+ args['transfer_for_manufacture'] = (cstr(args.get('include_item_in_manufacturing', '')) or
+ item and item[0].include_item_in_manufacturing or 0)
args.update(item[0])
rate = self.get_rm_rate(args)
@@ -145,7 +145,7 @@
'qty' : args.get("qty") or args.get("stock_qty") or 1,
'stock_qty' : args.get("qty") or args.get("stock_qty") or 1,
'base_rate' : rate,
- 'allow_transfer_for_manufacture': cint(args['transfer_for_manufacture']) or 0
+ 'include_item_in_manufacturing': cint(args['transfer_for_manufacture']) or 0
}
return ret_item
@@ -477,7 +477,7 @@
'stock_uom' : d.stock_uom,
'stock_qty' : flt(d.stock_qty),
'rate' : d.base_rate,
- 'allow_transfer_for_manufacture': d.allow_transfer_for_manufacture
+ 'include_item_in_manufacturing': d.include_item_in_manufacturing
}))
def company_currency(self):
@@ -494,7 +494,7 @@
# Did not use qty_consumed_per_unit in the query, as it leads to rounding loss
child_fb_items = frappe.db.sql("""select bom_item.item_code, bom_item.item_name,
bom_item.description, bom_item.source_warehouse, bom_item.operation,
- bom_item.stock_uom, bom_item.stock_qty, bom_item.rate, bom_item.allow_transfer_for_manufacture,
+ bom_item.stock_uom, bom_item.stock_qty, bom_item.rate, bom_item.include_item_in_manufacturing,
bom_item.stock_qty / ifnull(bom.quantity, 1) as qty_consumed_per_unit
from `tabBOM Explosion Item` bom_item, tabBOM bom
where bom_item.parent = bom.name and bom.name = %s and bom.docstatus = 1""", bom_no, as_dict = 1)
@@ -509,7 +509,7 @@
'stock_uom' : d['stock_uom'],
'stock_qty' : d['qty_consumed_per_unit'] * stock_qty,
'rate' : flt(d['rate']),
- 'allow_transfer_for_manufacture': d.get('allow_transfer_for_manufacture', 0)
+ 'include_item_in_manufacturing': d.get('include_item_in_manufacturing', 0)
}))
def add_exploded_items(self):
@@ -585,7 +585,7 @@
query = query.format(table="BOM Explosion Item",
where_conditions="",
is_stock_item=is_stock_item,
- select_columns = """, bom_item.source_warehouse, bom_item.operation, bom_item.allow_transfer_for_manufacture,
+ select_columns = """, bom_item.source_warehouse, bom_item.operation, bom_item.include_item_in_manufacturing,
(Select idx from `tabBOM Item` where item_code = bom_item.item_code and parent = %(parent)s ) as idx""")
items = frappe.db.sql(query, { "parent": bom, "qty": qty, "bom": bom, "company": company }, as_dict=True)
@@ -594,7 +594,7 @@
items = frappe.db.sql(query, { "qty": qty, "bom": bom, "company": company }, as_dict=True)
else:
query = query.format(table="BOM Item", where_conditions="", is_stock_item=is_stock_item,
- select_columns = ", bom_item.source_warehouse, bom_item.idx, bom_item.operation, bom_item.allow_transfer_for_manufacture")
+ select_columns = ", bom_item.source_warehouse, bom_item.idx, bom_item.operation, bom_item.include_item_in_manufacturing")
items = frappe.db.sql(query, { "qty": qty, "bom": bom, "company": company }, as_dict=True)
for item in items:
diff --git a/erpnext/manufacturing/doctype/bom/test_records.json b/erpnext/manufacturing/doctype/bom/test_records.json
index 1a7e594..25730f9 100644
--- a/erpnext/manufacturing/doctype/bom/test_records.json
+++ b/erpnext/manufacturing/doctype/bom/test_records.json
@@ -11,7 +11,7 @@
"uom": "_Test UOM",
"stock_uom": "_Test UOM",
"source_warehouse": "_Test Warehouse - _TC",
- "allow_transfer_for_manufacture": 1
+ "include_item_in_manufacturing": 1
},
{
"amount": 2000.0,
@@ -23,7 +23,7 @@
"uom": "_Test UOM",
"stock_uom": "_Test UOM",
"source_warehouse": "_Test Warehouse - _TC",
- "allow_transfer_for_manufacture": 1
+ "include_item_in_manufacturing": 1
}
],
"docstatus": 1,
@@ -57,7 +57,7 @@
"uom": "_Test UOM",
"stock_uom": "_Test UOM",
"source_warehouse": "_Test Warehouse - _TC",
- "allow_transfer_for_manufacture": 1
+ "include_item_in_manufacturing": 1
},
{
"amount": 2000.0,
@@ -69,7 +69,7 @@
"uom": "_Test UOM",
"stock_uom": "_Test UOM",
"source_warehouse": "_Test Warehouse - _TC",
- "allow_transfer_for_manufacture": 1
+ "include_item_in_manufacturing": 1
}
],
"docstatus": 1,
@@ -102,7 +102,7 @@
"uom": "_Test UOM",
"stock_uom": "_Test UOM",
"source_warehouse": "_Test Warehouse - _TC",
- "allow_transfer_for_manufacture": 1
+ "include_item_in_manufacturing": 1
},
{
"amount": 3000.0,
@@ -115,7 +115,7 @@
"uom": "_Test UOM",
"stock_uom": "_Test UOM",
"source_warehouse": "_Test Warehouse - _TC",
- "allow_transfer_for_manufacture": 1
+ "include_item_in_manufacturing": 1
}
],
"docstatus": 1,
@@ -150,7 +150,7 @@
"uom": "_Test UOM",
"stock_uom": "_Test UOM",
"source_warehouse": "_Test Warehouse - _TC",
- "allow_transfer_for_manufacture": 1
+ "include_item_in_manufacturing": 1
}
],
"docstatus": 1,
diff --git a/erpnext/manufacturing/doctype/bom_explosion_item/bom_explosion_item.json b/erpnext/manufacturing/doctype/bom_explosion_item/bom_explosion_item.json
index ab3c5a1..9fadbef 100644
--- a/erpnext/manufacturing/doctype/bom_explosion_item/bom_explosion_item.json
+++ b/erpnext/manufacturing/doctype/bom_explosion_item/bom_explosion_item.json
@@ -1,5 +1,6 @@
{
"allow_copy": 0,
+ "allow_events_in_timeline": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
@@ -573,7 +574,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
- "fieldname": "allow_transfer_for_manufacture",
+ "fieldname": "include_item_in_manufacturing",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
@@ -582,7 +583,7 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
- "label": "Allow Transfer for Manufacture",
+ "label": "Include Item In Manufacturing",
"length": 0,
"no_copy": 0,
"permlevel": 0,
@@ -609,7 +610,7 @@
"issingle": 0,
"istable": 1,
"max_attachments": 0,
- "modified": "2018-08-27 16:32:35.152139",
+ "modified": "2018-11-20 19:04:59.813773",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "BOM Explosion Item",
diff --git a/erpnext/manufacturing/doctype/bom_item/bom_item.json b/erpnext/manufacturing/doctype/bom_item/bom_item.json
index cc69471..8d4d69b 100644
--- a/erpnext/manufacturing/doctype/bom_item/bom_item.json
+++ b/erpnext/manufacturing/doctype/bom_item/bom_item.json
@@ -85,6 +85,39 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fieldname": "operation",
+ "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": "Item operation",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Operation",
+ "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": "column_break_3",
"fieldtype": "Column Break",
"hidden": 0,
@@ -932,8 +965,8 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
- "fetch_from": "item_code.allow_transfer_for_manufacture",
- "fieldname": "allow_transfer_for_manufacture",
+ "fetch_from": "item_code.include_item_in_manufacturing",
+ "fieldname": "include_item_in_manufacturing",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
@@ -942,7 +975,7 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
- "label": "Allow Transfer for Manufacture",
+ "label": "Include Item In Manufacturing",
"length": 0,
"no_copy": 0,
"permlevel": 0,
@@ -990,39 +1023,6 @@
"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": "operation",
- "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": "Item operation",
- "length": 0,
- "no_copy": 0,
- "options": "Operation",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
- "unique": 0
}
],
"has_web_view": 0,
@@ -1035,7 +1035,7 @@
"issingle": 0,
"istable": 1,
"max_attachments": 0,
- "modified": "2018-11-22 15:04:55.187136",
+ "modified": "2018-12-28 16:38:56.529079",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "BOM Item",
diff --git a/erpnext/manufacturing/doctype/job_card/job_card.js b/erpnext/manufacturing/doctype/job_card/job_card.js
index 6f5290e..3fe9b8a 100644
--- a/erpnext/manufacturing/doctype/job_card/job_card.js
+++ b/erpnext/manufacturing/doctype/job_card/job_card.js
@@ -3,7 +3,7 @@
frappe.ui.form.on('Job Card', {
refresh: function(frm) {
- if (frm.doc.items && frm.doc.docstatus==1) {
+ if(!frm.doc.__islocal && frm.doc.items && frm.doc.items.length) {
if (frm.doc.for_quantity != frm.doc.transferred_qty) {
frm.add_custom_button(__("Material Request"), () => {
frm.trigger("make_material_request");
@@ -31,6 +31,7 @@
frm.add_custom_button(__("Complete Job"), () => {
frm.set_value('actual_end_date', frappe.datetime.now_datetime());
frm.save();
+ frm.savesubmit();
});
}
}
diff --git a/erpnext/manufacturing/doctype/job_card/job_card.json b/erpnext/manufacturing/doctype/job_card/job_card.json
index 443cad8..b020c89 100644
--- a/erpnext/manufacturing/doctype/job_card/job_card.json
+++ b/erpnext/manufacturing/doctype/job_card/job_card.json
@@ -1,5 +1,6 @@
{
"allow_copy": 0,
+ "allow_events_in_timeline": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
@@ -53,6 +54,39 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fieldname": "bom_no",
+ "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": "BOM No",
+ "length": 0,
+ "no_copy": 0,
+ "options": "BOM",
+ "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,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
"fieldname": "workstation",
"fieldtype": "Link",
"hidden": 0,
@@ -119,39 +153,6 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
- "fieldname": "wip_warehouse",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "WIP 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": 1,
- "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": "column_break_4",
"fieldtype": "Column Break",
"hidden": 0,
@@ -281,9 +282,8 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
- "default": "0",
- "fieldname": "transferred_qty",
- "fieldtype": "Float",
+ "fieldname": "wip_warehouse",
+ "fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
@@ -291,17 +291,18 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
- "label": "Transferred Qty",
+ "label": "WIP Warehouse",
"length": 0,
"no_copy": 0,
+ "options": "Warehouse",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
- "read_only": 1,
+ "read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
- "reqd": 0,
+ "reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
@@ -635,8 +636,9 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
- "fieldname": "bom_no",
- "fieldtype": "Link",
+ "default": "0",
+ "fieldname": "transferred_qty",
+ "fieldtype": "Float",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
@@ -644,10 +646,42 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
- "label": "BOM No",
+ "label": "Transferred Qty",
"length": 0,
"no_copy": 0,
- "options": "BOM",
+ "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,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "default": "0",
+ "fieldname": "requested_qty",
+ "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": "Requested Qty",
+ "length": 0,
+ "no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
@@ -701,8 +735,8 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
- "fieldname": "column_break_20",
- "fieldtype": "Column Break",
+ "fieldname": "remarks",
+ "fieldtype": "Small Text",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
@@ -710,6 +744,7 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
+ "label": "Remarks",
"length": 0,
"no_copy": 0,
"permlevel": 0,
@@ -732,8 +767,8 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
- "fieldname": "remarks",
- "fieldtype": "Small Text",
+ "fieldname": "column_break_20",
+ "fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
@@ -741,7 +776,6 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
- "label": "Remarks",
"length": 0,
"no_copy": 0,
"permlevel": 0,
@@ -776,13 +810,13 @@
"in_standard_filter": 0,
"label": "Status",
"length": 0,
- "no_copy": 0,
- "options": "Open\nWork In Progress\nCancelled\nCompleted",
+ "no_copy": 1,
+ "options": "Open\nWork In Progress\nMaterial Transferred\nSubmitted\nCancelled\nCompleted",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
- "read_only": 0,
+ "read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
@@ -834,7 +868,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2018-08-28 16:50:43.576151",
+ "modified": "2018-12-13 17:23:57.986381",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "Job Card",
diff --git a/erpnext/manufacturing/doctype/job_card/job_card.py b/erpnext/manufacturing/doctype/job_card/job_card.py
index 81c5eb9..5343a28 100644
--- a/erpnext/manufacturing/doctype/job_card/job_card.py
+++ b/erpnext/manufacturing/doctype/job_card/job_card.py
@@ -11,9 +11,9 @@
class JobCard(Document):
def validate(self):
- self.status = 'Open'
self.validate_actual_dates()
self.set_time_in_mins()
+ self.set_status()
def validate_actual_dates(self):
if get_datetime(self.actual_start_date) > get_datetime(self.actual_end_date):
@@ -48,7 +48,7 @@
return
doc = frappe.get_doc('Work Order', self.get('work_order'))
- if not doc.transfer_material_against_job_card and doc.skip_transfer:
+ if doc.transfer_material_against == 'Work Order' and doc.skip_transfer:
return
for d in doc.required_items:
@@ -104,20 +104,23 @@
wo.set_actual_dates()
wo.save()
- def set_transferred_qty(self):
+ def set_transferred_qty(self, update_status=False):
if not self.items:
self.transferred_qty = self.for_quantity if self.docstatus == 1 else 0
if self.items:
- self.transferred_qty = frappe.db.get_value('Stock Entry', {'job_card': self.name,
- 'work_order': self.work_order, 'docstatus': 1}, 'sum(fg_completed_qty)')
+ self.transferred_qty = frappe.db.get_value('Stock Entry', {
+ 'job_card': self.name,
+ 'work_order': self.work_order,
+ 'docstatus': 1
+ }, 'sum(fg_completed_qty)') or 0
self.db_set("transferred_qty", self.transferred_qty)
qty = 0
if self.work_order:
doc = frappe.get_doc('Work Order', self.work_order)
- if doc.transfer_material_against_job_card and not doc.skip_transfer:
+ if doc.transfer_material_against == 'Job Card' and not doc.skip_transfer:
completed = True
for d in doc.operations:
if d.status != 'Completed':
@@ -131,15 +134,28 @@
doc.db_set('material_transferred_for_manufacturing', qty)
- self.set_status()
+ self.set_status(update_status)
- def set_status(self):
- status = 'Cancelled' if self.docstatus == 2 else 'Work In Progress'
+ def set_status(self, update_status=False):
+ self.status = {
+ 0: "Open",
+ 1: "Submitted",
+ 2: "Cancelled"
+ }[self.docstatus or 0]
- if self.for_quantity == self.transferred_qty:
- status = 'Completed'
+ if self.actual_start_date:
+ self.status = 'Work In Progress'
- self.db_set('status', status)
+ if (self.docstatus == 1 and
+ (self.for_quantity == self.transferred_qty or not self.items)):
+ self.status = 'Completed'
+
+ if self.status != 'Completed':
+ if self.for_quantity == self.transferred_qty:
+ self.status = 'Material Transferred'
+
+ if update_status:
+ self.db_set('status', self.status)
@frappe.whitelist()
def make_material_request(source_name, target_doc=None):
diff --git a/erpnext/manufacturing/doctype/job_card/job_card_list.js b/erpnext/manufacturing/doctype/job_card/job_card_list.js
index d40a9fa..ed851eb 100644
--- a/erpnext/manufacturing/doctype/job_card/job_card_list.js
+++ b/erpnext/manufacturing/doctype/job_card/job_card_list.js
@@ -6,6 +6,8 @@
return [__("Completed"), "green", "status,=,Completed"];
} else if (doc.docstatus == 2) {
return [__("Cancelled"), "red", "status,=,Cancelled"];
+ } else if (doc.status === "Material Transferred") {
+ return [__('Material Transferred'), "blue", "status,=,Material Transferred"];
} else {
return [__("Open"), "red", "status,=,Open"];
}
diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.py b/erpnext/manufacturing/doctype/production_plan/production_plan.py
index 7d11ae4..24ce7d4 100644
--- a/erpnext/manufacturing/doctype/production_plan/production_plan.py
+++ b/erpnext/manufacturing/doctype/production_plan/production_plan.py
@@ -514,7 +514,7 @@
doc = frappe._dict(json.loads(doc))
doc['mr_items'] = []
- po_items = doc['po_items'] if doc.get('po_items') else doc['items']
+ po_items = doc.get('po_items') if doc.get('po_items') else doc.get('items')
for data in po_items:
warehouse = None
@@ -533,10 +533,10 @@
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']
+ include_subcontracted_items = doc.get('include_subcontracted_items')
+ company = doc.get('company')
+ include_non_stock_items = doc.get('include_non_stock_items')
+ ignore_existing_ordered_qty = doc.get('ignore_existing_ordered_qty')
if not planned_qty:
frappe.throw(_("For row {0}: Enter Planned Qty").format(data.get('idx')))
diff --git a/erpnext/manufacturing/doctype/work_order/test_work_order.py b/erpnext/manufacturing/doctype/work_order/test_work_order.py
index 431ad32..69381c5 100644
--- a/erpnext/manufacturing/doctype/work_order/test_work_order.py
+++ b/erpnext/manufacturing/doctype/work_order/test_work_order.py
@@ -306,7 +306,7 @@
items = {'Finished Good Transfer Item': 1, '_Test FG Item': 1, '_Test FG Item 1': 0}
for item, allow_transfer in items.items():
make_item(item, {
- 'allow_transfer_for_manufacture': allow_transfer
+ 'include_item_in_manufacturing': allow_transfer
})
fg_item = 'Finished Good Transfer Item'
diff --git a/erpnext/manufacturing/doctype/work_order/work_order.js b/erpnext/manufacturing/doctype/work_order/work_order.js
index e85b0a5..7b2f9a4 100644
--- a/erpnext/manufacturing/doctype/work_order/work_order.js
+++ b/erpnext/manufacturing/doctype/work_order/work_order.js
@@ -112,11 +112,20 @@
frm.trigger('show_progress');
}
- if (frm.doc.docstatus === 1 && frm.doc.operations
+ if (frm.doc.docstatus === 1
+ && frm.doc.operations && frm.doc.operations.length
&& frm.doc.qty != frm.doc.material_transferred_for_manufacturing) {
- frm.add_custom_button(__('Make Job Card'), () => {
- frm.trigger("make_job_card")
- }).addClass('btn-primary');
+ const not_completed = frm.doc.operations.filter(d => {
+ if(d.status != 'Completed') {
+ return true;
+ }
+ });
+
+ if(not_completed && not_completed.length) {
+ frm.add_custom_button(__('Make Job Card'), () => {
+ frm.trigger("make_job_card")
+ }).addClass('btn-primary');
+ }
}
if(frm.doc.required_items && frm.doc.allow_alternative_item) {
@@ -294,7 +303,7 @@
frm.trigger('set_sales_order');
erpnext.in_production_item_onchange = true;
$.each(["description", "stock_uom", "project", "bom_no",
- "allow_alternative_item", "transfer_material_against_job_card"], function(i, field) {
+ "allow_alternative_item", "transfer_material_against"], function(i, field) {
frm.set_value(field, r.message[field]);
});
@@ -340,9 +349,8 @@
before_submit: function(frm) {
frm.toggle_reqd(["fg_warehouse", "wip_warehouse"], true);
frm.fields_dict.required_items.grid.toggle_reqd("source_warehouse", true);
- if (frm.doc.operations) {
- frm.fields_dict.operations.grid.toggle_reqd("workstation", true);
- }
+ frm.toggle_reqd("transfer_material_against", frm.doc.operations);
+ frm.fields_dict.operations.grid.toggle_reqd("workstation", frm.doc.operations);
},
set_sales_order: function(frm) {
@@ -425,7 +433,7 @@
}
const show_start_btn = (frm.doc.skip_transfer
- || frm.doc.transfer_material_against_job_card) ? 0 : 1;
+ || frm.doc.transfer_material_against == 'Job Card') ? 0 : 1;
if (show_start_btn){
if ((flt(doc.material_transferred_for_manufacturing) < flt(doc.qty))
diff --git a/erpnext/manufacturing/doctype/work_order/work_order.json b/erpnext/manufacturing/doctype/work_order/work_order.json
index df9dd83..a65d04f 100644
--- a/erpnext/manufacturing/doctype/work_order/work_order.json
+++ b/erpnext/manufacturing/doctype/work_order/work_order.json
@@ -1,5 +1,6 @@
{
"allow_copy": 0,
+ "allow_events_in_timeline": 0,
"allow_guest_to_view": 0,
"allow_import": 1,
"allow_rename": 0,
@@ -190,6 +191,38 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fieldname": "allow_alternative_item",
+ "fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Allow Alternative Item",
+ "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": "1",
"description": "Plan material for sub-assemblies",
"fieldname": "use_multi_level_bom",
@@ -223,7 +256,8 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
- "fieldname": "allow_alternative_item",
+ "description": "Check if material transfer entry is not required",
+ "fieldname": "skip_transfer",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
@@ -232,7 +266,7 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
- "label": "Allow Alternative Item",
+ "label": "Skip Material Transfer",
"length": 0,
"no_copy": 0,
"permlevel": 0,
@@ -493,39 +527,6 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
- "description": "Check if material transfer entry is not required",
- "fieldname": "skip_transfer",
- "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": "Skip Material Transfer",
- "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": "skip_transfer",
"fieldname": "from_wip_warehouse",
"fieldtype": "Check",
@@ -559,39 +560,6 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
- "depends_on": "operations",
- "fieldname": "transfer_material_against_job_card",
- "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": "Transfer Material Against Job Card",
- "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": "warehouses",
"fieldtype": "Section Break",
"hidden": 0,
@@ -1077,6 +1045,41 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "default": "Work Order",
+ "depends_on": "operations",
+ "fieldname": "transfer_material_against",
+ "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": "Transfer Material Against",
+ "length": 0,
+ "no_copy": 0,
+ "options": "\nWork Order\nJob Card",
+ "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": "operations",
"fieldtype": "Table",
@@ -1672,7 +1675,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2018-09-05 06:28:22.983369",
+ "modified": "2018-12-13 15:33:12.490710",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "Work Order",
diff --git a/erpnext/manufacturing/doctype/work_order/work_order.py b/erpnext/manufacturing/doctype/work_order/work_order.py
index e73328f..9873efa 100644
--- a/erpnext/manufacturing/doctype/work_order/work_order.py
+++ b/erpnext/manufacturing/doctype/work_order/work_order.py
@@ -191,7 +191,7 @@
for purpose, fieldname in (("Manufacture", "produced_qty"),
("Material Transfer for Manufacture", "material_transferred_for_manufacturing")):
if (purpose == 'Material Transfer for Manufacture' and
- self.operations and self.transfer_material_against_job_card):
+ self.operations and self.transfer_material_against == 'Job Card'):
continue
qty = flt(frappe.db.sql("""select sum(fg_completed_qty)
@@ -459,7 +459,7 @@
'allow_alternative_item': item.allow_alternative_item,
'required_qty': item.qty,
'source_warehouse': item.source_warehouse or item.default_warehouse,
- 'allow_transfer_for_manufacture': item.allow_transfer_for_manufacture
+ 'include_item_in_manufacturing': item.include_item_in_manufacturing
})
self.set_available_qty()
@@ -564,11 +564,11 @@
frappe.throw(_("Default BOM for {0} not found").format(item))
bom_data = frappe.db.get_value('BOM', res['bom_no'],
- ['project', 'allow_alternative_item', 'transfer_material_against_job_card'], as_dict=1)
+ ['project', 'allow_alternative_item', 'transfer_material_against'], as_dict=1)
res['project'] = project or bom_data.project
res['allow_alternative_item'] = bom_data.allow_alternative_item
- res['transfer_material_against_job_card'] = bom_data.transfer_material_against_job_card
+ res['transfer_material_against'] = bom_data.transfer_material_against
res.update(check_if_scrap_warehouse_mandatory(res["bom_no"]))
return res
@@ -682,7 +682,7 @@
'wip_warehouse': work_order.wip_warehouse
})
- if work_order.transfer_material_against_job_card and not work_order.skip_transfer:
+ if work_order.transfer_material_against == 'Job Card' and not work_order.skip_transfer:
doc.get_required_items()
if auto_create:
diff --git a/erpnext/manufacturing/doctype/work_order_item/work_order_item.json b/erpnext/manufacturing/doctype/work_order_item/work_order_item.json
index 1db11f7..4442162 100644
--- a/erpnext/manufacturing/doctype/work_order_item/work_order_item.json
+++ b/erpnext/manufacturing/doctype/work_order_item/work_order_item.json
@@ -1,5 +1,6 @@
{
"allow_copy": 0,
+ "allow_events_in_timeline": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
@@ -342,7 +343,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
- "fieldname": "allow_transfer_for_manufacture",
+ "fieldname": "include_item_in_manufacturing",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
@@ -351,7 +352,7 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
- "label": "Allow Transfer for Manufacture",
+ "label": "Include Item In Manufacturing",
"length": 0,
"no_copy": 0,
"permlevel": 0,
@@ -506,7 +507,7 @@
"issingle": 0,
"istable": 1,
"max_attachments": 0,
- "modified": "2018-10-04 16:16:54.237829",
+ "modified": "2018-11-20 19:04:38.508839",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "Work Order Item",
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 4a67eb4..9b8a69d 100755
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -495,7 +495,7 @@
erpnext.patches.v10_0.update_translatable_fields
erpnext.patches.v10_0.rename_offer_letter_to_job_offer
execute:frappe.delete_doc('DocType', 'Production Planning Tool', ignore_missing=True)
-erpnext.patches.v10_0.migrate_daily_work_summary_settings_to_daily_work_summary_group
+erpnext.patches.v10_0.migrate_daily_work_summary_settings_to_daily_work_summary_group # 24-12-2018
erpnext.patches.v10_0.add_default_cash_flow_mappers
erpnext.patches.v11_0.make_quality_inspection_template
erpnext.patches.v10_0.update_status_for_multiple_source_in_po
@@ -579,3 +579,4 @@
erpnext.patches.v11_0.update_delivery_trip_status
erpnext.patches.v10_0.repost_gle_for_purchase_receipts_with_rejected_items
erpnext.patches.v11_0.set_missing_gst_hsn_code
+erpnext.patches.v11_0.rename_bom_wo_fields
diff --git a/erpnext/patches/v10_0/migrate_daily_work_summary_settings_to_daily_work_summary_group.py b/erpnext/patches/v10_0/migrate_daily_work_summary_settings_to_daily_work_summary_group.py
index 3d15bbc..102b6da 100644
--- a/erpnext/patches/v10_0/migrate_daily_work_summary_settings_to_daily_work_summary_group.py
+++ b/erpnext/patches/v10_0/migrate_daily_work_summary_settings_to_daily_work_summary_group.py
@@ -6,37 +6,36 @@
def execute():
- frappe.reload_doc("hr", "doctype", "daily_work_summary_group")
- frappe.reload_doc("hr", "doctype", "daily_work_summary_group_user")
+ if not frappe.db.table_exists('Daily Work Summary Group'):
+ frappe.reload_doc("hr", "doctype", "daily_work_summary_group")
+ frappe.reload_doc("hr", "doctype", "daily_work_summary_group_user")
- # check if Daily Work Summary Settings Company table exists
- try:
- frappe.db.sql('DESC `tabDaily Work Summary Settings Company`')
- except Exception:
- return
+ # check if Daily Work Summary Settings Company table exists
+ try:
+ frappe.db.sql('DESC `tabDaily Work Summary Settings Company`')
+ except Exception:
+ return
- # get the previously saved settings
- previous_setting = get_previous_setting()
- if previous_setting["companies"]:
- for d in previous_setting["companies"]:
- users = frappe.get_list("Employee", dict(
- company=d.company, user_id=("!=", " ")), "user_id as user")
- if(len(users)):
- # create new group entry for each company entry
- new_group = frappe.get_doc(dict(doctype="Daily Work Summary Group",
- name="Daily Work Summary for " + d.company,
- users=users,
- send_emails_at=d.send_emails_at,
- subject=previous_setting["subject"],
- message=previous_setting["message"]))
- new_group.flags.ignore_permissions = True
- new_group.flags.ignore_validate = True
- new_group.insert(ignore_if_duplicate = True)
- frappe.delete_doc("Daily Work Summary Settings")
- frappe.delete_doc("Daily Work Summary Settings Company")
+ # get the previously saved settings
+ previous_setting = get_previous_setting()
+ if previous_setting["companies"]:
+ for d in previous_setting["companies"]:
+ users = frappe.get_list("Employee", dict(
+ company=d.company, user_id=("!=", " ")), "user_id as user")
+ if(len(users)):
+ # create new group entry for each company entry
+ new_group = frappe.get_doc(dict(doctype="Daily Work Summary Group",
+ name="Daily Work Summary for " + d.company,
+ users=users,
+ send_emails_at=d.send_emails_at,
+ subject=previous_setting["subject"],
+ message=previous_setting["message"]))
+ new_group.flags.ignore_permissions = True
+ new_group.flags.ignore_validate = True
+ new_group.insert(ignore_if_duplicate = True)
-def get_setting_companies():
- return frappe.db.sql("select * from `tabDaily Work Summary Settings Company`", as_dict=True)
+ frappe.delete_doc("DocType", "Daily Work Summary Settings")
+ frappe.delete_doc("DocType", "Daily Work Summary Settings Company")
def get_previous_setting():
@@ -47,3 +46,6 @@
obj[field] = value
obj["companies"] = get_setting_companies()
return obj
+
+def get_setting_companies():
+ return frappe.db.sql("select * from `tabDaily Work Summary Settings Company`", as_dict=True)
\ No newline at end of file
diff --git a/erpnext/patches/v11_0/rename_bom_wo_fields.py b/erpnext/patches/v11_0/rename_bom_wo_fields.py
new file mode 100644
index 0000000..c8106a6
--- /dev/null
+++ b/erpnext/patches/v11_0/rename_bom_wo_fields.py
@@ -0,0 +1,36 @@
+# Copyright (c) 2018, Frappe and Contributors
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+import frappe
+from frappe.model.utils.rename_field import rename_field
+
+def execute():
+ for doctype in ['BOM Explosion Item', 'BOM Item', 'Work Order Item', 'Item']:
+ if frappe.db.has_column(doctype, 'allow_transfer_for_manufacture'):
+ if doctype != 'Item':
+ frappe.reload_doc('manufacturing', 'doctype', frappe.scrub(doctype))
+ else:
+ frappe.reload_doc('stock', 'doctype', frappe.scrub(doctype))
+
+ rename_field(doctype, "allow_transfer_for_manufacture", "include_item_in_manufacturing")
+
+ if frappe.db.has_column('BOM', 'allow_same_item_multiple_times'):
+ frappe.db.sql(""" UPDATE tabBOM
+ SET
+ allow_same_item_multiple_times = 0
+ WHERE
+ trim(coalesce(allow_same_item_multiple_times, '')) = '' """)
+
+ for doctype in ['BOM', 'Work Order']:
+ frappe.reload_doc('manufacturing', 'doctype', frappe.scrub(doctype))
+
+ if frappe.db.has_column(doctype, 'transfer_material_against_job_card'):
+ frappe.db.sql(""" UPDATE `tab%s`
+ SET transfer_material_against = CASE WHEN
+ transfer_material_against_job_card = 1 then 'Job Card' Else 'Work Order' END
+ WHERE docstatus < 2""" % (doctype))
+ else:
+ frappe.db.sql(""" UPDATE `tab%s`
+ SET transfer_material_against = 'Work Order'
+ WHERE docstatus < 2""" % (doctype))
\ No newline at end of file
diff --git a/erpnext/patches/v11_0/skip_user_permission_check_for_department.py b/erpnext/patches/v11_0/skip_user_permission_check_for_department.py
index 123eed5..7f7cfc1 100644
--- a/erpnext/patches/v11_0/skip_user_permission_check_for_department.py
+++ b/erpnext/patches/v11_0/skip_user_permission_check_for_department.py
@@ -1,28 +1,60 @@
import frappe
+from frappe.desk.form.linked_with import get_linked_doctypes
# Skips user permission check for doctypes where department link field was recently added
# https://github.com/frappe/erpnext/pull/14121
def execute():
- user_permissions = frappe.get_all("User Permission",
- filters=[['allow', '=', 'Department']],
- fields=['name', 'skip_for_doctype'])
+ doctypes_to_skip = []
+ for doctype in ['Appraisal', 'Leave Allocation', 'Expense Claim', 'Instructor', 'Salary Slip',
+ 'Attendance', 'Training Feedback', 'Training Result Employee',
+ 'Leave Application', 'Employee Advance', 'Activity Cost', 'Training Event Employee',
+ 'Timesheet', 'Sales Person', 'Payroll Employee Detail']:
+ if frappe.db.exists('Custom Field', { 'dt': doctype, 'fieldname': 'department'}): continue
+ doctypes_to_skip.append(doctype)
- doctypes_to_skip = []
+ frappe.reload_doctype('User Permission')
- for doctype in ['Appraisal', 'Leave Allocation', 'Expense Claim', 'Instructor', 'Salary Slip',
- 'Attendance', 'Training Feedback', 'Training Result Employee',
- 'Leave Application', 'Employee Advance', 'Activity Cost', 'Training Event Employee',
- 'Timesheet', 'Sales Person', 'Payroll Employee Detail']:
- if frappe.db.exists('Custom Field', { 'dt': doctype, 'fieldname': 'department'}): continue
- doctypes_to_skip.append(doctype)
+ user_permissions = frappe.get_all("User Permission",
+ filters=[['allow', '=', 'Department'], ['applicable_for', 'in', [None] + doctypes_to_skip]],
+ fields=['name', 'applicable_for'])
- for perm in user_permissions:
- skip_for_doctype = perm.get('skip_for_doctype')
+ user_permissions_to_delete = []
+ new_user_permissions_list = []
- skip_for_doctype = skip_for_doctype.split('\n') + doctypes_to_skip
- skip_for_doctype = set(skip_for_doctype) # to remove duplicates
- skip_for_doctype = '\n'.join(skip_for_doctype) # convert back to string
+ for user_permission in user_permissions:
+ if user_permission.applicable_for:
+ # simply delete user permission record since it needs to be skipped.
+ user_permissions_to_delete.append(user_permission.name)
+ else:
+ # if applicable_for is `None` it means that user permission is applicable for every doctype
+ # to avoid this we need to create other user permission records and only skip the listed doctypes in this patch
+ linked_doctypes = get_linked_doctypes(user_permission.allow, True).keys()
+ applicable_for_doctypes = list(set(linked_doctypes) - set(doctypes_to_skip))
- frappe.set_value('User Permission', perm.name, 'skip_for_doctype', skip_for_doctype)
+ user_permissions_to_delete.append(user_permission.name)
+ for doctype in applicable_for_doctypes:
+ if doctype:
+ # Maintain sequence (name, user, allow, for_value, applicable_for, apply_to_all_doctypes)
+ new_user_permissions_list.append((
+ frappe.generate_hash("", 10),
+ user_permission.user,
+ user_permission.allow,
+ user_permission.for_value,
+ doctype,
+ 0
+ ))
+
+ if new_user_permissions_list:
+ frappe.db.sql('''
+ INSERT INTO `tabUser Permission`
+ (`name`, `user`, `allow`, `for_value`, `applicable_for`, `apply_to_all_doctypes`)
+ VALUES {}'''.format(', '.join(['%s'] * len(new_user_permissions_list))), # nosec
+ tuple(new_user_permissions_list)
+ )
+
+ if user_permissions_to_delete:
+ frappe.db.sql('DELETE FROM `tabUser Permission` WHERE `name` IN ({})'.format( # nosec
+ ','.join(['%s'] * len(user_permissions_to_delete))
+ ), tuple(user_permissions_to_delete))
\ No newline at end of file
diff --git a/erpnext/patches/v11_0/update_allow_transfer_for_manufacture.py b/erpnext/patches/v11_0/update_allow_transfer_for_manufacture.py
index 9c94dee..1b58c97 100644
--- a/erpnext/patches/v11_0/update_allow_transfer_for_manufacture.py
+++ b/erpnext/patches/v11_0/update_allow_transfer_for_manufacture.py
@@ -6,7 +6,7 @@
def execute():
frappe.reload_doc('stock', 'doctype', 'item')
- frappe.db.sql(""" update `tabItem` set allow_transfer_for_manufacture = 1
+ frappe.db.sql(""" update `tabItem` set include_item_in_manufacturing = 1
where ifnull(is_stock_item, 0) = 1""")
for doctype in ['BOM Item', 'Work Order Item', 'BOM Explosion Item']:
@@ -14,7 +14,7 @@
frappe.db.sql(""" update `tab{0}` child, tabItem item
set
- child.allow_transfer_for_manufacture = 1
+ child.include_item_in_manufacturing = 1
where
child.item_code = item.name and ifnull(item.is_stock_item, 0) = 1
""".format(doctype))
\ No newline at end of file
diff --git a/erpnext/patches/v9_0/add_user_to_child_table_in_pos_profile.py b/erpnext/patches/v9_0/add_user_to_child_table_in_pos_profile.py
index 942f089..8a8c806 100644
--- a/erpnext/patches/v9_0/add_user_to_child_table_in_pos_profile.py
+++ b/erpnext/patches/v9_0/add_user_to_child_table_in_pos_profile.py
@@ -32,7 +32,7 @@
'user': user,
'default': 1
})
- _doc.pos_profile_name = user + ' - ' + _doc.company
+
_doc.flags.ignore_validate = True
_doc.flags.ignore_mandatory = True
_doc.save()
\ No newline at end of file
diff --git a/erpnext/patches/v9_0/set_pos_profile_name.py b/erpnext/patches/v9_0/set_pos_profile_name.py
index 1958e2c..a3a9735 100644
--- a/erpnext/patches/v9_0/set_pos_profile_name.py
+++ b/erpnext/patches/v9_0/set_pos_profile_name.py
@@ -11,14 +11,14 @@
for pos in frappe.get_all(doctype, filters={'disabled': 0}):
doc = frappe.get_doc(doctype, pos.name)
- if not doc.user or doc.pos_profile_name: continue
+ if not doc.user: continue
try:
- doc.pos_profile_name = doc.user + ' - ' + doc.company
+ pos_profile_name = doc.user + ' - ' + doc.company
doc.flags.ignore_validate = True
doc.flags.ignore_mandatory = True
doc.save()
- frappe.rename_doc(doctype, doc.name, doc.pos_profile_name, force=True)
+ frappe.rename_doc(doctype, doc.name, pos_profile_name, force=True)
except frappe.LinkValidationError:
frappe.db.set_value("POS Profile", doc.name, 'disabled', 1)
diff --git a/erpnext/projects/doctype/project/project.js b/erpnext/projects/doctype/project/project.js
index 40b065d..faa445a 100644
--- a/erpnext/projects/doctype/project/project.js
+++ b/erpnext/projects/doctype/project/project.js
@@ -120,28 +120,3 @@
frm.trigger('tasks_refresh');
},
});
-
-frappe.ui.form.on("Project", "validate", function (frm) {
- if (frm.doc.collect_progress == 1) {
- frappe.call({
- method: "erpnext.projects.doctype.project.project.times_check",
- args: {
- "from1": frm.doc.from,
- "to": frm.doc.to,
- "first_email": frm.doc.first_email,
- "second_email": frm.doc.second_email,
- "daily_time_to_send": frm.doc.daily_time_to_send,
- "weekly_time_to_send": frm.doc.weekly_time_to_send
-
- },
- callback: function (r) {
- frm.set_value("from", r.message.from1);
- frm.set_value("to", r.message.to);
- frm.set_value("first_email", r.message.first_email);
- frm.set_value("second_email", r.message.second_email);
- frm.set_value("daily_time_to_send", r.message.daily_time_to_send);
- frm.set_value("weekly_time_to_send", r.message.weekly_time_to_send);
- }
- });
- }
-});
\ No newline at end of file
diff --git a/erpnext/projects/doctype/project/project.py b/erpnext/projects/doctype/project/project.py
index ff69870..de45ec3 100644
--- a/erpnext/projects/doctype/project/project.py
+++ b/erpnext/projects/doctype/project/project.py
@@ -16,7 +16,7 @@
class Project(Document):
def get_feed(self):
- return '{0}: {1}'.format(_(self.status), self.project_name)
+ return '{0}: {1}'.format(_(self.status), frappe.safe_decode(self.project_name))
def onload(self):
"""Load project tasks for quick view"""
@@ -76,7 +76,7 @@
def validate_project_name(self):
if self.get("__islocal") and frappe.db.exists("Project", self.project_name):
- frappe.throw(_("Project {0} already exists").format(self.project_name))
+ frappe.throw(_("Project {0} already exists").format(frappe.safe_decode(self.project_name)))
def validate_dates(self):
if self.expected_start_date and self.expected_end_date:
@@ -258,13 +258,13 @@
self.total_purchase_cost = total_purchase_cost and total_purchase_cost[0][0] or 0
def update_sales_amount(self):
- total_sales_amount = frappe.db.sql("""select sum(base_grand_total)
+ total_sales_amount = frappe.db.sql("""select sum(base_net_total)
from `tabSales Order` where project = %s and docstatus=1""", self.name)
self.total_sales_amount = total_sales_amount and total_sales_amount[0][0] or 0
def update_billed_amount(self):
- total_billed_amount = frappe.db.sql("""select sum(base_grand_total)
+ total_billed_amount = frappe.db.sql("""select sum(base_net_total)
from `tabSales Invoice` where project = %s and docstatus=1""", self.name)
self.total_billed_amount = total_billed_amount and total_billed_amount[0][0] or 0
@@ -427,23 +427,6 @@
project = frappe.db.sql("""SELECT `tabProject User`.user FROM `tabProject User` INNER JOIN `tabProject` ON `tabProject`.project_name = `tabProject User`.parent WHERE (`tabProject`.frequency = "Weekly") AND (`tabProject`.day_to_send = %s) AND (`tabProject`.weekly_time_to_send BETWEEN DATE_ADD(curtime(), INTERVAL -15 MINUTE) AND DATE_ADD(curtime(), INTERVAL 15 MINUTE)) AND `tabProject`.collect_progress = 1""", today)
create_project_update(project)
-@frappe.whitelist()
-def times_check(from1, to, first_email, second_email, daily_time_to_send, weekly_time_to_send):
- from1 = datetime.datetime.strptime(from1, "%H:%M:%S.%f")
- from1 = from1.strftime("%H:00:00")
- to = datetime.datetime.strptime(to, "%H:%M:%S.%f")
- to = to.strftime("%H:00:00")
- first_email = datetime.datetime.strptime(first_email, "%H:%M:%S.%f")
- first_email = first_email.strftime("%H:00:00")
- second_email = datetime.datetime.strptime(second_email, "%H:%M:%S.%f")
- second_email = second_email.strftime("%H:00:00")
- daily_time_to_send = datetime.datetime.strptime(daily_time_to_send, "%H:%M:%S.%f")
- daily_time_to_send = daily_time_to_send.strftime("%H:00:00")
- weekly_time_to_send = datetime.datetime.strptime(weekly_time_to_send, "%H:%M:%S.%f")
- weekly_time_to_send = weekly_time_to_send.strftime("%H:00:00")
- return {"from1": from1, "to": to, "first_email": first_email, "second_email": second_email,"daily_time_to_send": daily_time_to_send, "weekly_time_to_send": weekly_time_to_send}
-
-
#Call this function in order to generate the Project Update for a specific project
def create_project_update(project):
data = []
diff --git a/erpnext/public/js/conf.js b/erpnext/public/js/conf.js
index 08f8d43..3208155 100644
--- a/erpnext/public/js/conf.js
+++ b/erpnext/public/js/conf.js
@@ -26,8 +26,8 @@
$('<li><a data-link-type="forum" href="https://discuss.erpnext.com" \
target="_blank">'+__('User Forum')+'</a></li>').insertBefore($help_menu);
- $('<li><a href="https://gitter.im/frappe/erpnext" \
- target="_blank">'+__('Chat')+'</a></li>').insertBefore($help_menu);
+ $('<li class="gitter-chat-link"><a href="https://gitter.im/frappe/erpnext" \
+ target="_blank">'+__('Gitter Chat')+'</a></li>').insertBefore($help_menu);
$('<li><a href="https://github.com/frappe/erpnext/issues" \
target="_blank">'+__('Report an Issue')+'</a></li>').insertBefore($help_menu);
diff --git a/erpnext/public/js/setup_wizard.js b/erpnext/public/js/setup_wizard.js
index 82d6f6e..9beba6a 100644
--- a/erpnext/public/js/setup_wizard.js
+++ b/erpnext/public/js/setup_wizard.js
@@ -97,6 +97,9 @@
if (!this.values.company_abbr) {
return false;
}
+ if (this.values.company_abbr.length > 5) {
+ return false;
+ }
return true;
}
},
diff --git a/erpnext/public/js/utils.js b/erpnext/public/js/utils.js
old mode 100644
new mode 100755
index e293321..adb7c6d
--- a/erpnext/public/js/utils.js
+++ b/erpnext/public/js/utils.js
@@ -120,13 +120,13 @@
);
});
}
- else {
+ else if (company_wise_info.length === 1) {
frm.dashboard.stats_area.removeClass('hidden');
frm.dashboard.stats_area_row.append(
'</div><div class="col-xs-6 small" style="margin-bottom:10px">Annual Billing: <b>'
+format_currency(company_wise_info[0].billing_this_year, company_wise_info[0].currency)+'</b></div>' +
'<div class="col-xs-6 small" style="margin-bottom:10px">Total Unpaid: <b>'
- +format_currency(company_wise_info[0].billing_this_year, company_wise_info[0].currency)+'</b></div>'
+ +format_currency(company_wise_info[0].total_unpaid, company_wise_info[0].currency)+'</b></div>'
);
}
}
@@ -237,7 +237,7 @@
let unscrub_option = frappe.model.unscrub(option);
let user_permission = frappe.defaults.get_user_permissions();
if(user_permission && user_permission[unscrub_option]) {
- return user_permission[unscrub_option]["docs"];
+ return user_permission[unscrub_option].map(perm => perm.doc);
} else {
return $.map(locals[`:${unscrub_option}`], function(c) { return c.name; }).sort();
}
diff --git a/erpnext/regional/india/setup.py b/erpnext/regional/india/setup.py
index 5fc06ea..7813cc0 100644
--- a/erpnext/regional/india/setup.py
+++ b/erpnext/regional/india/setup.py
@@ -11,14 +11,18 @@
from frappe.utils import today
def setup(company=None, patch=True):
+ setup_company_independent_fixtures()
+ if not patch:
+ update_address_template()
+ make_fixtures(company)
+
+# TODO: for all countries
+def setup_company_independent_fixtures():
make_custom_fields()
add_permissions()
add_custom_roles_for_reports()
frappe.enqueue('erpnext.regional.india.setup.add_hsn_sac_codes', now=frappe.flags.in_test)
add_print_formats()
- if not patch:
- update_address_template()
- make_fixtures(company)
def update_address_template():
with open(os.path.join(os.path.dirname(__file__), 'address_template.html'), 'r') as f:
diff --git "a/erpnext/regional/report/fichier_des_ecritures_comptables_\133fec\135/fichier_des_ecritures_comptables_\133fec\135.js" "b/erpnext/regional/report/fichier_des_ecritures_comptables_\133fec\135/fichier_des_ecritures_comptables_\133fec\135.js"
index 8606a3b..a4c7640 100644
--- "a/erpnext/regional/report/fichier_des_ecritures_comptables_\133fec\135/fichier_des_ecritures_comptables_\133fec\135.js"
+++ "b/erpnext/regional/report/fichier_des_ecritures_comptables_\133fec\135/fichier_des_ecritures_comptables_\133fec\135.js"
@@ -1,85 +1,75 @@
-// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
+// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
-/* eslint-disable */
frappe.query_reports["Fichier des Ecritures Comptables [FEC]"] = {
- "filters": [{
- "fieldname": "company",
- "label": __("Company"),
- "fieldtype": "Link",
- "options": "Company",
- "default": frappe.defaults.get_user_default("Company"),
- "reqd": 1
- },
- {
- "fieldname": "fiscal_year",
- "label": __("Fiscal Year"),
- "fieldtype": "Link",
- "options": "Fiscal Year",
- "default": frappe.defaults.get_user_default("fiscal_year"),
- "reqd": 1
- }],
-
+ "filters": [
+ {
+ "fieldname": "company",
+ "label": __("Company"),
+ "fieldtype": "Link",
+ "options": "Company",
+ "default": frappe.defaults.get_user_default("Company"),
+ "reqd": 1
+ },
+ {
+ "fieldname": "fiscal_year",
+ "label": __("Fiscal Year"),
+ "fieldtype": "Link",
+ "options": "Fiscal Year",
+ "default": frappe.defaults.get_user_default("fiscal_year"),
+ "reqd": 1
+ }
+ ],
onload: function(query_report) {
query_report.page.add_inner_button(__("Export"), function() {
- var fiscal_year = query_report.get_values().fiscal_year;
- var company = query_report.get_values().company;
+ fec_export(query_report);
+ });
- frappe.call({
- method: "frappe.client.get_value",
- args: {
- 'doctype': "Company",
- 'fieldname': ['siren_number'],
- 'filters': {
- 'name': company
- }
- },
- callback: function(data) {
- var company_data = data.message.siren_number;
- if (company_data === null || company_data === undefined) {
- frappe.msgprint(__("Please register the SIREN number in the company information file"))
- } else {
- frappe.call({
- method: "frappe.client.get_value",
- args: {
- 'doctype': "Fiscal Year",
- 'fieldname': ['year_end_date'],
- 'filters': {
- 'name': fiscal_year
- }
- },
- callback: function(data) {
- var fy = data.message.year_end_date;
- var title = company_data + "FEC" + moment(fy).format('YYYYMMDD');
- var result = $.map(frappe.slickgrid_tools.get_view_data(query_report.columns, query_report.dataView),
- function(row) {
- return [row.splice(1)];
- });
- downloadify(result, null, title);
- }
- });
+ query_report.add_make_chart_button = function() {
+ //
+ };
- }
- }
+ query_report.export_report = function() {
+ fec_export(query_report);
+ };
+ }
+};
+
+let fec_export = function(query_report) {
+ const fiscal_year = query_report.get_values().fiscal_year;
+ const company = query_report.get_values().company;
+
+ frappe.db.get_value("Company", company, "siren_number", (value) => {
+ const company_data = value.siren_number;
+ if (company_data === null || company_data === undefined) {
+ frappe.msgprint(__("Please register the SIREN number in the company information file"));
+ } else {
+ frappe.db.get_value("Fiscal Year", fiscal_year, "year_end_date", (r) => {
+ const fy = r.year_end_date;
+ const title = company_data + "FEC" + moment(fy).format('YYYYMMDD');
+ const column_row = query_report.columns.map(col => col.label);
+ const column_data = query_report.get_data_for_csv(false);
+ const result = [column_row].concat(column_data);
+ downloadify(result, null, title);
});
- });
- }
-}
+ }
+ });
+};
-var downloadify = function(data, roles, title) {
+let downloadify = function(data, roles, title) {
if (roles && roles.length && !has_common(roles, roles)) {
frappe.msgprint(__("Export not allowed. You need {0} role to export.", [frappe.utils.comma_or(roles)]));
return;
}
- var filename = title + ".csv";
- var csv_data = to_tab_csv(data);
- var a = document.createElement('a');
+ const filename = title + ".txt";
+ let csv_data = to_tab_csv(data);
+ const a = document.createElement('a');
if ("download" in a) {
// Used Blob object, because it can handle large files
- var blob_object = new Blob([csv_data], {
+ let blob_object = new Blob([csv_data], {
type: 'text/csv;charset=UTF-8'
});
a.href = URL.createObjectURL(blob_object);
@@ -98,8 +88,8 @@
document.body.removeChild(a);
};
-var to_tab_csv = function(data) {
- var res = [];
+let to_tab_csv = function(data) {
+ let res = [];
$.each(data, function(i, row) {
res.push(row.join("\t"));
});
diff --git a/erpnext/selling/README.md b/erpnext/selling/README.md
index db05132..d186133 100644
--- a/erpnext/selling/README.md
+++ b/erpnext/selling/README.md
@@ -1,6 +1,11 @@
-Selling management module. Includes forms for capturing / managing the sales process.
+Selling management module. Includes forms for capturing / managing the sales process:
+
+- Customer
+- Campaign
+- Quotation
+- Sales Order
+
+Moved to CRM Module:
- Lead
- Opportunity
-- Quotation
-- Sales Order
\ No newline at end of file
diff --git a/erpnext/selling/doctype/quotation/quotation.js b/erpnext/selling/doctype/quotation/quotation.js
index c708de0..6f7bfb3 100644
--- a/erpnext/selling/doctype/quotation/quotation.js
+++ b/erpnext/selling/doctype/quotation/quotation.js
@@ -206,7 +206,7 @@
}
-frappe.ui.form.on("Quotation Item", "items_on_form_rendered", function(frm, cdt, cdn) {
+frappe.ui.form.on("Quotation Item", "items_on_form_rendered", "packed_items_on_form_rendered", function(frm, cdt, cdn) {
// enable tax_amount field if Actual
})
diff --git a/erpnext/selling/doctype/quotation_item/quotation_item.json b/erpnext/selling/doctype/quotation_item/quotation_item.json
index 3b1c480..7ea8397 100644
--- a/erpnext/selling/doctype/quotation_item/quotation_item.json
+++ b/erpnext/selling/doctype/quotation_item/quotation_item.json
@@ -871,10 +871,12 @@
"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,
@@ -993,6 +995,7 @@
"label": "Net Rate",
"length": 0,
"no_copy": 0,
+ "options": "currency",
"permlevel": 0,
"precision": "",
"print_hide": 1,
@@ -1910,7 +1913,7 @@
"istable": 1,
"max_attachments": 0,
"menu_index": 0,
- "modified": "2018-08-22 16:15:52.750381",
+ "modified": "2018-12-12 05:52:46.135944",
"modified_by": "Administrator",
"module": "Selling",
"name": "Quotation Item",
@@ -1925,4 +1928,4 @@
"track_changes": 1,
"track_seen": 0,
"track_views": 0
-}
\ No newline at end of file
+}
diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py
index 9a35aed..229f4f6 100755
--- a/erpnext/selling/doctype/sales_order/sales_order.py
+++ b/erpnext/selling/doctype/sales_order/sales_order.py
@@ -623,7 +623,7 @@
def update_item(source, target, source_parent):
target.amount = flt(source.amount) - flt(source.billed_amt)
target.base_amount = target.amount * flt(source_parent.conversion_rate)
- target.qty = target.amount / flt(source.rate) if (source.rate and source.billed_amt) else source.qty
+ target.qty = target.amount / flt(source.rate) if (source.rate and source.billed_amt) else source.qty - source.returned_qty
if source_parent.project:
target.cost_center = frappe.db.get_value("Project", source_parent.project, "cost_center")
diff --git a/erpnext/selling/page/point_of_sale/point_of_sale.js b/erpnext/selling/page/point_of_sale/point_of_sale.js
index a6f7a28..1ee5971 100644
--- a/erpnext/selling/page/point_of_sale/point_of_sale.js
+++ b/erpnext/selling/page/point_of_sale/point_of_sale.js
@@ -394,7 +394,7 @@
}
}
- frappe.prompt(this.get_promopt_fields(),
+ frappe.prompt(this.get_prompt_fields(),
on_submit,
__('Select POS Profile')
);
@@ -417,11 +417,12 @@
]);
}
- get_promopt_fields() {
+ get_prompt_fields() {
return [{
fieldtype: 'Link',
label: __('POS Profile'),
options: 'POS Profile',
+ fieldname: 'pos_profile',
reqd: 1,
get_query: () => {
return {
@@ -433,7 +434,8 @@
}
}, {
fieldtype: 'Check',
- label: __('Set as default')
+ label: __('Set as default'),
+ fieldname: 'set_as_default'
}];
}
@@ -522,6 +524,7 @@
this.frm.meta.default_print_format = r.message.print_format || "";
this.frm.allow_edit_rate = r.message.allow_edit_rate;
this.frm.allow_edit_discount = r.message.allow_edit_discount;
+ this.frm.doc.campaign = r.message.campaign;
}
}
@@ -1128,12 +1131,15 @@
this.events = events;
this.currency = this.frm.doc.currency;
- this.make_dom();
- this.make_fields();
+ frappe.db.get_value("Item Group", {lft: 1, is_group: 1}, "name", (r) => {
+ this.parent_item_group = r.name;
+ this.make_dom();
+ this.make_fields();
- this.init_clusterize();
- this.bind_events();
- this.load_items_data();
+ this.init_clusterize();
+ this.bind_events();
+ this.load_items_data();
+ })
}
load_items_data() {
@@ -1175,6 +1181,7 @@
make_fields() {
// Search field
+ const me = this;
this.search_field = frappe.ui.form.make_control({
df: {
fieldtype: 'Data',
@@ -1202,7 +1209,7 @@
fieldtype: 'Link',
label: 'Item Group',
options: 'Item Group',
- default: 'All Item Groups',
+ default: me.parent_item_group,
onchange: () => {
const item_group = this.item_group_field.get_value();
if (item_group) {
@@ -1258,7 +1265,7 @@
this.clusterize.update(row_items);
}
- filter_items({ search_term='', item_group='All Item Groups' }={}) {
+ filter_items({ search_term='', item_group=this.parent_item_group }={}) {
if (search_term) {
search_term = search_term.toLowerCase();
@@ -1271,7 +1278,7 @@
this.set_item_in_the_cart(items);
return;
}
- } else if (item_group == "All Item Groups") {
+ } else if (item_group == this.parent_item_group) {
this.items = this.all_items;
return this.render_items(this.all_items);
}
@@ -1376,7 +1383,7 @@
return template;
}
- get_items({start = 0, page_length = 40, search_value='', item_group="All Item Groups"}={}) {
+ get_items({start = 0, page_length = 40, search_value='', item_group=this.parent_item_group}={}) {
return new Promise(res => {
frappe.call({
method: "erpnext.selling.page.point_of_sale.point_of_sale.get_items",
diff --git a/erpnext/selling/page/point_of_sale/point_of_sale.py b/erpnext/selling/page/point_of_sale/point_of_sale.py
index daec5b5..56d9151 100644
--- a/erpnext/selling/page/point_of_sale/point_of_sale.py
+++ b/erpnext/selling/page/point_of_sale/point_of_sale.py
@@ -125,6 +125,8 @@
if batch_no_data:
return batch_no_data
+ return {}
+
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"
diff --git a/erpnext/selling/report/pending_so_items_for_purchase_request/pending_so_items_for_purchase_request.js b/erpnext/selling/report/pending_so_items_for_purchase_request/pending_so_items_for_purchase_request.js
new file mode 100644
index 0000000..37634ef
--- /dev/null
+++ b/erpnext/selling/report/pending_so_items_for_purchase_request/pending_so_items_for_purchase_request.js
@@ -0,0 +1,6 @@
+// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+/* eslint-disable */
+
+frappe.query_reports["Pending SO Items For Purchase Request"] = {
+}
diff --git a/erpnext/selling/report/pending_so_items_for_purchase_request/pending_so_items_for_purchase_request.json b/erpnext/selling/report/pending_so_items_for_purchase_request/pending_so_items_for_purchase_request.json
index 128544b..3cf3235 100644
--- a/erpnext/selling/report/pending_so_items_for_purchase_request/pending_so_items_for_purchase_request.json
+++ b/erpnext/selling/report/pending_so_items_for_purchase_request/pending_so_items_for_purchase_request.json
@@ -1,36 +1,35 @@
{
- "add_total_row": 0,
- "apply_user_permissions": 1,
- "creation": "2013-06-21 16:46:45",
- "disabled": 0,
- "docstatus": 0,
- "doctype": "Report",
- "idx": 3,
- "is_standard": "Yes",
- "modified": "2017-02-24 20:08:11.744036",
- "modified_by": "Administrator",
- "module": "Selling",
- "name": "Pending SO Items For Purchase Request",
- "owner": "Administrator",
- "query": "select so_item.item_code as \"Item Code:Link/Item:120\",\n so_item.item_name as \"Item Name::120\",\n so_item.description as \"Description::120\",\n so.`name` as \"S.O. No.:Link/Sales Order:120\",\n so.`transaction_date` as \"Date:Date:120\",\n mr.name as \"Material Request:Link/Material Request:120\",\n so.customer as \"Customer:Link/Customer:120\",\n so.territory as \"Terretory:Link/Territory:120\",\n sum(so_item.qty) as \"SO Qty:Float:100 \",\n sum(mr_item.qty) as \"Requested Qty:Float:100\",\n sum(so_item.qty) - sum(mr_item.qty) as \"Pending Qty:Float:100 \", \n so.company as \"Company:Link/Company:\"\nfrom\n `tabSales Order` so, `tabSales Order Item` so_item, \n `tabMaterial Request` mr, `tabMaterial Request Item` mr_item\nwhere \n so_item.`parent` = so.`name` \n and mr_item.parent = mr.name\n and mr_item.sales_order = so.name\n and mr_item.item_code = so_item.item_code\n and so.docstatus = 1 and so.status != \"Closed\" \n and mr.docstatus = 1 and mr.status != \"Stopped\"\ngroup by so.name, so_item.item_code\nhaving sum(so_item.qty) > sum(mr_item.qty)\norder by so.name desc, so_item.item_code asc",
- "ref_doctype": "Sales Order",
- "report_name": "Pending SO Items For Purchase Request",
- "report_type": "Query Report",
+ "add_total_row": 0,
+ "creation": "2018-11-12 14:08:27.241332",
+ "disabled": 0,
+ "docstatus": 0,
+ "doctype": "Report",
+ "idx": 0,
+ "is_standard": "Yes",
+ "modified": "2018-11-12 14:08:27.241332",
+ "modified_by": "Administrator",
+ "module": "Selling",
+ "name": "Pending SO Items For Purchase Request",
+ "owner": "Administrator",
+ "prepared_report": 0,
+ "ref_doctype": "Sales Order",
+ "report_name": "Pending SO Items For Purchase Request",
+ "report_type": "Script Report",
"roles": [
{
- "role": "Sales User"
- },
+ "role": "Stock User"
+ },
{
"role": "Sales Manager"
- },
+ },
{
"role": "Maintenance User"
- },
+ },
{
"role": "Accounts User"
- },
+ },
{
- "role": "Stock User"
+ "role": "Sales User"
}
]
}
\ No newline at end of file
diff --git a/erpnext/selling/report/pending_so_items_for_purchase_request/pending_so_items_for_purchase_request.py b/erpnext/selling/report/pending_so_items_for_purchase_request/pending_so_items_for_purchase_request.py
new file mode 100644
index 0000000..8721651
--- /dev/null
+++ b/erpnext/selling/report/pending_so_items_for_purchase_request/pending_so_items_for_purchase_request.py
@@ -0,0 +1,148 @@
+# 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 _
+from frappe.utils import cint,cstr
+
+def execute(filters=None):
+ columns = get_columns()
+ data = get_data()
+ return columns, data
+
+def get_columns():
+ columns = [
+ {
+ "label": _("Item Code"),
+ "options": "Item",
+ "fieldname": "item_code",
+ "fieldtype": "Link",
+ "width": 200
+ },
+ {
+ "label": _("Item Name"),
+ "fieldname": "item_name",
+ "fieldtype": "Data",
+ "width": 200
+ },
+ {
+ "label": _("Description"),
+ "fieldname": "description",
+ "fieldtype": "Data",
+ "width": 140
+ },
+ {
+ "label": _("S.O. No."),
+ "options": "Sales Order",
+ "fieldname": "sales_order_no",
+ "fieldtype": "Link",
+ "width": 140
+ },
+ {
+ "label": _("Date"),
+ "fieldname": "date",
+ "fieldtype": "Date",
+ "width": 140
+ },
+ {
+ "label": _("Material Request"),
+ "options": "Material Request",
+ "fieldname": "material_request",
+ "fieldtype": "Link",
+ "width": 140
+ },
+ {
+ "label": _("Customer"),
+ "fieldname": "customer",
+ "fieldtype": "Data",
+ "width": 140
+ },
+ {
+ "label": _("Territory"),
+ "fieldname": "territory",
+ "fieldtype": "Data",
+ "width": 140
+ },
+ {
+ "label": _("SO Qty"),
+ "fieldname": "so_qty",
+ "fieldtype": "Float",
+ "width": 140
+ },
+ {
+ "label": _("Requested Qty"),
+ "fieldname": "requested_qty",
+ "fieldtype": "Float",
+ "width": 140
+ },
+ {
+ "label": _("Pending Qty"),
+ "fieldname": "pending_qty",
+ "fieldtype": "Float",
+ "width": 140
+ },
+ {
+ "label": _("Company"),
+ "fieldname": "company",
+ "fieldtype": "Data",
+ "width": 140
+ }
+ ]
+ return columns
+
+def get_data():
+ sales_order_entry = frappe.db.sql("""
+ SELECT
+ so_item.item_code,
+ so_item.item_name,
+ so_item.description,
+ so.name,
+ so.transaction_date,
+ so.customer,
+ so.territory,
+ sum(so_item.qty) as net_qty,
+ so.company
+ FROM `tabSales Order` so, `tabSales Order Item` so_item
+ WHERE
+ so.docstatus = 1
+ and so.name = so_item.parent
+ and so.status not in ("Closed","Completed","Cancelled")
+ GROUP BY
+ so.name,so_item.item_code
+ """, as_dict = 1)
+
+ mr_records = frappe.get_all("Material Request Item",
+ {"sales_order_item": ("!=",""), "docstatus": 1},
+ ["parent", "qty", "sales_order", "item_code"])
+
+ grouped_records = {}
+
+ for record in mr_records:
+ grouped_records.setdefault(record.sales_order, []).append(record)
+
+ pending_so=[]
+ for so in sales_order_entry:
+ # fetch all the material request records for a sales order item
+ mr_list = grouped_records.get(so.name) or [{}]
+ mr_item_record = ([mr for mr in mr_list if mr.get('item_code') == so.item_code] or [{}])
+
+ for mr in mr_item_record:
+ # check for pending sales order
+ if cint(so.net_qty) > cint(mr.get('qty')):
+ so_record = {
+ "item_code": so.item_code,
+ "item_name": so.item_name,
+ "description": so.description,
+ "sales_order_no": so.name,
+ "date": so.transaction_date,
+ "material_request": cstr(mr.get('parent')),
+ "customer": so.customer,
+ "territory": so.territory,
+ "so_qty": so.net_qty,
+ "requested_qty": cint(mr.get('qty')),
+ "pending_qty": so.net_qty - cint(mr.get('qty')),
+ "company": so.company
+ }
+ pending_so.append(so_record)
+ return pending_so
\ No newline at end of file
diff --git a/erpnext/selling/report/pending_so_items_for_purchase_request/test_pending_so_items_for_purchase_request.py b/erpnext/selling/report/pending_so_items_for_purchase_request/test_pending_so_items_for_purchase_request.py
new file mode 100644
index 0000000..f2b7701
--- /dev/null
+++ b/erpnext/selling/report/pending_so_items_for_purchase_request/test_pending_so_items_for_purchase_request.py
@@ -0,0 +1,27 @@
+# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+import unittest
+from frappe.utils import nowdate, add_months
+from erpnext.selling.report.pending_so_items_for_purchase_request.pending_so_items_for_purchase_request\
+ import execute
+from erpnext.selling.doctype.sales_order.sales_order import make_material_request
+from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order
+
+
+class TestPendingSOItemsForPurchaseRequest(unittest.TestCase):
+ def test_result_for_partial_material_request(self):
+ so = make_sales_order()
+ mr=make_material_request(so.name)
+ mr.items[0].qty = 4
+ mr.schedule_date = add_months(nowdate(),1)
+ mr.submit()
+ report = execute()
+ l = len(report[1])
+ self.assertEqual((so.items[0].qty - mr.items[0].qty), report[1][l-1]['pending_qty'])
+
+ def test_result_for_so_item(self):
+ so = make_sales_order()
+ report = execute()
+ l = len(report[1])
+ self.assertEqual(so.items[0].qty, report[1][l-1]['pending_qty'])
diff --git a/erpnext/selling/report/sales_analytics/sales_analytics.js b/erpnext/selling/report/sales_analytics/sales_analytics.js
index 0df425d..fbe045b 100644
--- a/erpnext/selling/report/sales_analytics/sales_analytics.js
+++ b/erpnext/selling/report/sales_analytics/sales_analytics.js
@@ -76,10 +76,21 @@
events: {
onCheckRow: function(data) {
row_name = data[2].content;
- length = data.length
- row_values = data.slice(4,length-1).map(function (column) {
- return column.content;
- })
+ length = data.length;
+
+ var tree_type = frappe.query_report.filters[0].value;
+
+ if(tree_type == "Customer" || tree_type == "Item") {
+ row_values = data.slice(4,length-1).map(function (column) {
+ return column.content;
+ })
+ }
+ else {
+ row_values = data.slice(3,length-1).map(function (column) {
+ return column.content;
+ })
+ }
+
entry = {
'name':row_name,
'values':row_values
diff --git a/erpnext/selling/report/sales_analytics/sales_analytics.py b/erpnext/selling/report/sales_analytics/sales_analytics.py
index 9cc6c40..c078a08 100644
--- a/erpnext/selling/report/sales_analytics/sales_analytics.py
+++ b/erpnext/selling/report/sales_analytics/sales_analytics.py
@@ -276,7 +276,11 @@
def get_chart_data(self):
length = len(self.columns)
- labels = [d.get("label") for d in self.columns[2:length-1]]
+
+ if self.filters.tree_type in ["Customer", "Supplier", "Item"]:
+ labels = [d.get("label") for d in self.columns[2:length-1]]
+ else:
+ labels = [d.get("label") for d in self.columns[1:length-1]]
self.chart = {
"data": {
'labels': labels,
diff --git a/erpnext/setup/doctype/company/company.py b/erpnext/setup/doctype/company/company.py
index 40bbc2c..09ff5a8 100644
--- a/erpnext/setup/doctype/company/company.py
+++ b/erpnext/setup/doctype/company/company.py
@@ -97,7 +97,7 @@
if not frappe.db.get_value("Department", {"company": self.name}):
from erpnext.setup.setup_wizard.operations.install_fixtures import install_post_company_fixtures
- install_post_company_fixtures(self.name)
+ install_post_company_fixtures(frappe._dict({'company_name': self.name}))
if not frappe.db.get_value("Cost Center", {"is_group": 0, "company": self.name}):
self.create_default_cost_center()
diff --git a/erpnext/setup/setup_wizard/operations/install_fixtures.py b/erpnext/setup/setup_wizard/operations/install_fixtures.py
index f7e2906..c732c4b 100644
--- a/erpnext/setup/setup_wizard/operations/install_fixtures.py
+++ b/erpnext/setup/setup_wizard/operations/install_fixtures.py
@@ -6,6 +6,9 @@
import frappe, os, json
from frappe import _
+from frappe.desk.page.setup_wizard.setup_wizard import make_records
+from frappe.utils import cstr, getdate
+from erpnext.accounts.doctype.account.account import RootNotEditable
default_lead_sources = ["Existing Customer", "Reference", "Advertisement",
"Cold Calling", "Exhibition", "Supplier Reference", "Mass Mailing",
@@ -26,34 +29,6 @@
{ 'doctype': 'Domain', 'domain': 'Agriculture'},
{ 'doctype': 'Domain', 'domain': 'Non Profit'},
- # Setup Progress
- {'doctype': "Setup Progress", "actions": [
- {"action_name": "Add Company", "action_doctype": "Company", "min_doc_count": 1, "is_completed": 1,
- "domains": '[]' },
- {"action_name": "Set Sales Target", "action_doctype": "Company", "min_doc_count": 99,
- "action_document": frappe.defaults.get_defaults().get("company") or '',
- "action_field": "monthly_sales_target", "is_completed": 0,
- "domains": '["Manufacturing", "Services", "Retail", "Distribution"]' },
- {"action_name": "Add Customers", "action_doctype": "Customer", "min_doc_count": 1, "is_completed": 0,
- "domains": '["Manufacturing", "Services", "Retail", "Distribution"]' },
- {"action_name": "Add Suppliers", "action_doctype": "Supplier", "min_doc_count": 1, "is_completed": 0,
- "domains": '["Manufacturing", "Services", "Retail", "Distribution"]' },
- {"action_name": "Add Products", "action_doctype": "Item", "min_doc_count": 1, "is_completed": 0,
- "domains": '["Manufacturing", "Services", "Retail", "Distribution"]' },
- {"action_name": "Add Programs", "action_doctype": "Program", "min_doc_count": 1, "is_completed": 0,
- "domains": '["Education"]' },
- {"action_name": "Add Instructors", "action_doctype": "Instructor", "min_doc_count": 1, "is_completed": 0,
- "domains": '["Education"]' },
- {"action_name": "Add Courses", "action_doctype": "Course", "min_doc_count": 1, "is_completed": 0,
- "domains": '["Education"]' },
- {"action_name": "Add Rooms", "action_doctype": "Room", "min_doc_count": 1, "is_completed": 0,
- "domains": '["Education"]' },
- {"action_name": "Add Users", "action_doctype": "User", "min_doc_count": 4, "is_completed": 0,
- "domains": '[]' },
- {"action_name": "Add Letterhead", "action_doctype": "Letter Head", "min_doc_count": 1, "is_completed": 0,
- "domains": '[]' }
- ]},
-
# address template
{'doctype':"Address Template", "country": country},
@@ -124,8 +99,10 @@
{'doctype': 'Designation', 'designation_name': _('Designer')},
{'doctype': 'Designation', 'designation_name': _('Researcher')},
- # territory
+ # territory: with two default territories, one for home country and one named Rest of the World
{'doctype': 'Territory', 'territory_name': _('All Territories'), 'is_group': 1, 'name': _('All Territories'), 'parent_territory': ''},
+ {'doctype': 'Territory', 'territory_name': country.replace("'", ""), 'is_group': 0, 'parent_territory': _('All Territories')},
+ {'doctype': 'Territory', 'territory_name': _("Rest Of The World"), 'is_group': 0, 'parent_territory': _('All Territories')},
# customer group
{'doctype': 'Customer Group', 'customer_group_name': _('All Customer Groups'), 'is_group': 1, 'name': _('All Customer Groups'), 'parent_customer_group': ''},
@@ -231,7 +208,22 @@
# Share Management
{"doctype": "Share Type", "title": _("Equity")},
- {"doctype": "Share Type", "title": _("Preference")}
+ {"doctype": "Share Type", "title": _("Preference")},
+
+ # Market Segments
+ {"doctype": "Market Segment", "market_segment": _("Lower Income")},
+ {"doctype": "Market Segment", "market_segment": _("Middle Income")},
+ {"doctype": "Market Segment", "market_segment": _("Upper Income")},
+
+ # Sales Stages
+ {"doctype": "Sales Stage", "stage_name": _("Prospecting")},
+ {"doctype": "Sales Stage", "stage_name": _("Qualification")},
+ {"doctype": "Sales Stage", "stage_name": _("Needs Analysis")},
+ {"doctype": "Sales Stage", "stage_name": _("Value Proposition")},
+ {"doctype": "Sales Stage", "stage_name": _("Identifying Decision Makers")},
+ {"doctype": "Sales Stage", "stage_name": _("Perception Analysis")},
+ {"doctype": "Sales Stage", "stage_name": _("Proposal/Price Quote")},
+ {"doctype": "Sales Stage", "stage_name": _("Negotiation/Review")}
]
from erpnext.setup.setup_wizard.data.industry_type import get_industry_types
@@ -260,7 +252,17 @@
from erpnext.buying.doctype.supplier_scorecard.supplier_scorecard import make_default_records
make_default_records()
- make_fixture_records(records)
+ make_records(records, True)
+
+ set_more_defaults()
+
+ # path = frappe.get_app_path('erpnext', 'regional', frappe.scrub(country))
+ # if os.path.exists(path.encode("utf-8")):
+ # frappe.get_attr("erpnext.regional.{0}.setup.setup_company_independent_fixtures".format(frappe.scrub(country)))()
+
+
+def set_more_defaults():
+ # Do more setup stuff that can be done here with no dependencies
# set default customer group and territory
selling_settings = frappe.get_doc("Selling Settings")
@@ -269,6 +271,33 @@
add_uom_data()
+ # set no copy fields of an item doctype to item variant settings
+ doc = frappe.get_doc('Item Variant Settings')
+ doc.set_default_fields()
+ doc.save()
+
+ selling_settings = frappe.get_doc("Selling Settings")
+ selling_settings.cust_master_name = "Customer Name"
+ selling_settings.so_required = "No"
+ selling_settings.dn_required = "No"
+ selling_settings.allow_multiple_items = 1
+ selling_settings.sales_update_frequency = "Each Transaction"
+ selling_settings.save()
+
+ buying_settings = frappe.get_doc("Buying Settings")
+ buying_settings.supp_master_name = "Supplier Name"
+ buying_settings.po_required = "No"
+ buying_settings.pr_required = "No"
+ buying_settings.maintain_same_rate = 1
+ buying_settings.allow_multiple_items = 1
+ buying_settings.save()
+
+ hr_settings = frappe.get_doc("HR Settings")
+ hr_settings.emp_created_by = "Naming Series"
+ hr_settings.leave_approval_notification_template = _("Leave Approval Notification")
+ hr_settings.leave_status_notification_template = _("Leave Status Notification")
+ hr_settings.save()
+
def add_uom_data():
# add UOMs
uoms = json.loads(open(frappe.get_app_path("erpnext", "setup", "setup_wizard", "data", "uom_data.json")).read())
@@ -306,7 +335,7 @@
{"doctype": "Market Segment", "market_segment": _("Upper Income")}
]
- make_fixture_records(records)
+ make_records(records)
def add_sale_stages():
# Sale Stages
@@ -320,46 +349,143 @@
{"doctype": "Sales Stage", "stage_name": _("Proposal/Price Quote")},
{"doctype": "Sales Stage", "stage_name": _("Negotiation/Review")}
]
- make_fixture_records(records)
-def make_fixture_records(records):
- from frappe.modules import scrub
- for r in records:
- doc = frappe.new_doc(r.get("doctype"))
- doc.update(r)
+ make_records(records)
- # ignore mandatory for root
- parent_link_field = ("parent_" + scrub(doc.doctype))
- if doc.meta.get_field(parent_link_field) and not doc.get(parent_link_field):
- doc.flags.ignore_mandatory = True
+def install_company(args):
+ records = [
+ # Fiscal Year
+ { "doctype": "Fiscal Year", 'year': get_fy_details(args.fy_start_date, args.fy_end_date), 'year_start_date': args.fy_start_date, 'year_end_date': args.fy_end_date },
- try:
- doc.insert(ignore_permissions=True)
- except frappe.DuplicateEntryError as e:
- # pass DuplicateEntryError and continue
- if e.args and e.args[0]==doc.doctype and e.args[1]==doc.name:
- # make sure DuplicateEntryError is for the exact same doc and not a related doc
- pass
- else:
- raise
+ # Company
+ {
+ "doctype":"Company",
+ 'company_name': args.company_name,
+ 'enable_perpetual_inventory': 1,
+ 'abbr': args.company_abbr,
+ 'default_currency': args.currency,
+ 'country': args.country,
+ 'create_chart_of_accounts_based_on': 'Standard Template',
+ 'chart_of_accounts': args.chart_of_accounts,
+ 'domain': args.domain
+ }
+ ]
-def install_post_company_fixtures(company=None):
+ make_records(records, True)
+
+
+def install_post_company_fixtures(args=None):
records = [
# Department
{'doctype': 'Department', 'department_name': _('All Departments'), 'is_group': 1, 'parent_department': ''},
- {'doctype': 'Department', 'department_name': _('Accounts'), 'parent_department': _('All Departments'), 'company': company},
- {'doctype': 'Department', 'department_name': _('Marketing'), 'parent_department': _('All Departments'), 'company': company},
- {'doctype': 'Department', 'department_name': _('Sales'), 'parent_department': _('All Departments'), 'company': company},
- {'doctype': 'Department', 'department_name': _('Purchase'), 'parent_department': _('All Departments'), 'company': company},
- {'doctype': 'Department', 'department_name': _('Operations'), 'parent_department': _('All Departments'), 'company': company},
- {'doctype': 'Department', 'department_name': _('Production'), 'parent_department': _('All Departments'), 'company': company},
- {'doctype': 'Department', 'department_name': _('Dispatch'), 'parent_department': _('All Departments'), 'company': company},
- {'doctype': 'Department', 'department_name': _('Customer Service'), 'parent_department': _('All Departments'), 'company': company},
- {'doctype': 'Department', 'department_name': _('Human Resources'), 'parent_department': _('All Departments'), 'company': company},
- {'doctype': 'Department', 'department_name': _('Management'), 'parent_department': _('All Departments'), 'company': company},
- {'doctype': 'Department', 'department_name': _('Quality Management'), 'parent_department': _('All Departments'), 'company': company},
- {'doctype': 'Department', 'department_name': _('Research & Development'), 'parent_department': _('All Departments'), 'company': company},
- {'doctype': 'Department', 'department_name': _('Legal'), 'parent_department': _('All Departments'), 'company': company},
+ {'doctype': 'Department', 'department_name': _('Accounts'), 'parent_department': _('All Departments'), 'company': args.company_name},
+ {'doctype': 'Department', 'department_name': _('Marketing'), 'parent_department': _('All Departments'), 'company': args.company_name},
+ {'doctype': 'Department', 'department_name': _('Sales'), 'parent_department': _('All Departments'), 'company': args.company_name},
+ {'doctype': 'Department', 'department_name': _('Purchase'), 'parent_department': _('All Departments'), 'company': args.company_name},
+ {'doctype': 'Department', 'department_name': _('Operations'), 'parent_department': _('All Departments'), 'company': args.company_name},
+ {'doctype': 'Department', 'department_name': _('Production'), 'parent_department': _('All Departments'), 'company': args.company_name},
+ {'doctype': 'Department', 'department_name': _('Dispatch'), 'parent_department': _('All Departments'), 'company': args.company_name},
+ {'doctype': 'Department', 'department_name': _('Customer Service'), 'parent_department': _('All Departments'), 'company': args.company_name},
+ {'doctype': 'Department', 'department_name': _('Human Resources'), 'parent_department': _('All Departments'), 'company': args.company_name},
+ {'doctype': 'Department', 'department_name': _('Management'), 'parent_department': _('All Departments'), 'company': args.company_name},
+ {'doctype': 'Department', 'department_name': _('Quality Management'), 'parent_department': _('All Departments'), 'company': args.company_name},
+ {'doctype': 'Department', 'department_name': _('Research & Development'), 'parent_department': _('All Departments'), 'company': args.company_name},
+ {'doctype': 'Department', 'department_name': _('Legal'), 'parent_department': _('All Departments'), 'company': args.company_name},
]
- make_fixture_records(records)
\ No newline at end of file
+ make_records(records)
+
+
+def install_defaults(args=None):
+ records = [
+ # Price Lists
+ { "doctype": "Price List", "price_list_name": _("Standard Buying"), "enabled": 1, "buying": 1, "selling": 0, "currency": args.currency },
+ { "doctype": "Price List", "price_list_name": _("Standard Selling"), "enabled": 1, "buying": 0, "selling": 1, "currency": args.currency },
+ ]
+
+ make_records(records)
+
+ # enable default currency
+ frappe.db.set_value("Currency", args.get("currency"), "enabled", 1)
+
+ global_defaults = frappe.get_doc("Global Defaults", "Global Defaults")
+ current_fiscal_year = frappe.get_all("Fiscal Year")[0]
+
+ global_defaults.update({
+ 'current_fiscal_year': current_fiscal_year.name,
+ 'default_currency': args.get('currency'),
+ 'default_company':args.get('company_name') ,
+ "country": args.get("country"),
+ })
+
+ global_defaults.save()
+
+ system_settings = frappe.get_doc("System Settings")
+ system_settings.email_footer_address = args.get("company_name")
+ system_settings.save()
+
+ domain_settings = frappe.get_single('Domain Settings')
+ domain_settings.set_active_domains(args.get('domains'))
+
+ stock_settings = frappe.get_doc("Stock Settings")
+ stock_settings.item_naming_by = "Item Code"
+ stock_settings.valuation_method = "FIFO"
+ stock_settings.default_warehouse = frappe.db.get_value('Warehouse', {'warehouse_name': _('Stores')})
+ stock_settings.stock_uom = _("Nos")
+ stock_settings.auto_indent = 1
+ stock_settings.auto_insert_price_list_rate_if_missing = 1
+ stock_settings.automatically_set_serial_nos_based_on_fifo = 1
+ stock_settings.set_qty_in_transactions_based_on_serial_no_input = 1
+ stock_settings.save()
+
+ if args.bank_account:
+ company_name = args.company_name
+ bank_account_group = frappe.db.get_value("Account",
+ {"account_type": "Bank", "is_group": 1, "root_type": "Asset",
+ "company": company_name})
+ if bank_account_group:
+ bank_account = frappe.get_doc({
+ "doctype": "Account",
+ 'account_name': args.bank_account,
+ 'parent_account': bank_account_group,
+ 'is_group':0,
+ 'company': company_name,
+ "account_type": "Bank",
+ })
+ try:
+ doc = bank_account.insert()
+
+ frappe.db.set_value("Company", args.company_name, "default_bank_account", bank_account.name, update_modified=False)
+
+ return doc
+ except RootNotEditable:
+ frappe.throw(_("Bank account cannot be named as {0}").format(args.bank_account))
+ except frappe.DuplicateEntryError:
+ # bank account same as a CoA entry
+ pass
+
+ # Now, with fixtures out of the way, onto concrete stuff
+ records = [
+
+ # Shopping cart: needs price lists
+ {
+ "doctype": "Shopping Cart Settings",
+ "enabled": 1,
+ 'company': args.company_name,
+ # uh oh
+ 'price_list': frappe.db.get_value("Price List", {"selling": 1}),
+ 'default_customer_group': _("Individual"),
+ 'quotation_series': "QTN-",
+ },
+ ]
+
+ make_records(records, True)
+
+
+def get_fy_details(fy_start_date, fy_end_date):
+ start_year = getdate(fy_start_date).year
+ if start_year == getdate(fy_end_date).year:
+ fy = cstr(start_year)
+ else:
+ fy = cstr(start_year) + '-' + cstr(start_year + 1)
+ return fy
diff --git a/erpnext/setup/setup_wizard/setup_wizard.py b/erpnext/setup/setup_wizard/setup_wizard.py
index af28e4f..e062e28 100644
--- a/erpnext/setup/setup_wizard/setup_wizard.py
+++ b/erpnext/setup/setup_wizard/setup_wizard.py
@@ -5,7 +5,8 @@
import frappe
from frappe import _
-from .operations import install_fixtures, taxes_setup, defaults_setup, company_setup, sample_data
+
+from .operations import install_fixtures as fixtures, company_setup, taxes_setup, sample_data
def get_setup_stages(args=None):
if frappe.db.sql("select name from tabCompany"):
@@ -61,16 +62,10 @@
'fail_msg': _("Failed to setup post company fixtures")
},
{
- 'fn': stage_three,
+ 'fn': setup_defaults,
'args': args,
- 'fail_msg': _("Failed to set defaults")
- }
- ]
- },
- {
- 'status': _('Making website'),
- 'fail_msg': _('Failed to create website'),
- 'tasks': [
+ 'fail_msg': _("Failed to setup defaults")
+ },
{
'fn': stage_four,
'args': args,
@@ -93,38 +88,20 @@
return stages
-def setup_complete(args=None):
- stage_fixtures(args)
- setup_company(args)
- setup_taxes(args)
- setup_post_company_fixtures(args)
- stage_three(args)
- stage_four(args)
- fin(args)
-
def stage_fixtures(args):
- install_fixtures.install(args.get("country"))
- install_fixtures.add_market_segments()
- install_fixtures.add_sale_stages()
+ fixtures.install(args.get('country'))
def setup_company(args):
- defaults_setup.create_price_lists(args)
- company_setup.create_fiscal_year_and_company(args)
- company_setup.enable_shopping_cart(args)
- company_setup.create_bank_account(args)
+ fixtures.install_company(args)
def setup_taxes(args):
taxes_setup.create_sales_tax(args)
def setup_post_company_fixtures(args):
- install_fixtures.install_post_company_fixtures(args.get("company_name"))
+ fixtures.install_post_company_fixtures(args)
-def stage_three(args):
- defaults_setup.create_employee_for_self(args)
- defaults_setup.set_default_settings(args)
- defaults_setup.create_territories()
- defaults_setup.create_feed_and_todo()
- defaults_setup.set_no_copy_fields_in_variant_settings()
+def setup_defaults(args):
+ fixtures.install_defaults(frappe._dict(args))
def stage_four(args):
company_setup.create_website(args)
@@ -149,3 +126,14 @@
def login_as_first_user(args):
if args.get("email") and hasattr(frappe.local, "login_manager"):
frappe.local.login_manager.login_as(args.get("email"))
+
+
+# Only for programmatical use
+def setup_complete(args=None):
+ stage_fixtures(args)
+ setup_company(args)
+ setup_taxes(args)
+ setup_post_company_fixtures(args)
+ setup_defaults(args)
+ stage_four(args)
+ fin(args)
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.js b/erpnext/stock/doctype/delivery_note/delivery_note.js
index 9a15484..f8a3497 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note.js
+++ b/erpnext/stock/doctype/delivery_note/delivery_note.js
@@ -223,6 +223,10 @@
erpnext.setup_serial_no();
},
+ packed_items_on_form_rendered: function(doc, grid_row) {
+ erpnext.setup_serial_no();
+ },
+
close_delivery_note: function(doc){
this.update_status("Closed")
},
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.py b/erpnext/stock/doctype/delivery_note/delivery_note.py
index ab624d1..50996ed 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note.py
+++ b/erpnext/stock/doctype/delivery_note/delivery_note.py
@@ -391,8 +391,24 @@
return invoiced_qty_map
+def get_returned_qty_map(sales_orders):
+ """returns a map: {so_detail: returned_qty}"""
+ returned_qty_map = {}
+
+ for name, returned_qty in frappe.get_all('Sales Order Item', fields = ["name", "returned_qty"],
+ filters = {'parent': ('in', sales_orders), 'docstatus': 1}, as_list=1):
+ if not returned_qty_map.get(name):
+ returned_qty_map[name] = 0
+ returned_qty_map[name] += returned_qty
+
+ return returned_qty_map
+
@frappe.whitelist()
def make_sales_invoice(source_name, target_doc=None):
+ doc = frappe.get_doc('Delivery Note', source_name)
+ sales_orders = [d.against_sales_order for d in doc.items]
+ returned_qty_map = get_returned_qty_map(sales_orders)
+
invoiced_qty_map = get_invoiced_qty_map(source_name)
def set_missing_values(source, target):
@@ -412,7 +428,9 @@
target.update(get_fetch_values("Sales Invoice", 'company_address', target.company_address))
def update_item(source_doc, target_doc, source_parent):
- target_doc.qty = source_doc.qty - invoiced_qty_map.get(source_doc.name, 0)
+ target_doc.qty = (source_doc.qty -
+ invoiced_qty_map.get(source_doc.name, 0) - returned_qty_map.get(source_doc.so_detail, 0))
+
if source_doc.serial_no and source_parent.per_billed > 0:
target_doc.serial_no = get_delivery_note_serial_no(source_doc.item_code,
target_doc.qty, source_parent.name)
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note_list.js b/erpnext/stock/doctype/delivery_note/delivery_note_list.js
index 9631264..6fc51ec 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note_list.js
+++ b/erpnext/stock/doctype/delivery_note/delivery_note_list.js
@@ -1,7 +1,8 @@
frappe.listview_settings['Delivery Note'] = {
- add_fields: ["grand_total", "is_return", "per_billed", "status"],
- get_indicator: function (doc) {
- if (cint(doc.is_return) == 1) {
+ add_fields: ["customer", "customer_name", "base_grand_total", "per_installed", "per_billed",
+ "transporter_name", "grand_total", "is_return", "status", "currency"],
+ get_indicator: function(doc) {
+ if(cint(doc.is_return)==1) {
return [__("Return"), "darkgrey", "is_return,=,Yes"];
} else if (doc.status === "Closed") {
return [__("Closed"), "green", "status,=,Closed"];
diff --git a/erpnext/stock/doctype/delivery_note/test_delivery_note.py b/erpnext/stock/doctype/delivery_note/test_delivery_note.py
index 026d83c..0c5a71c 100644
--- a/erpnext/stock/doctype/delivery_note/test_delivery_note.py
+++ b/erpnext/stock/doctype/delivery_note/test_delivery_note.py
@@ -636,6 +636,24 @@
self.assertEqual(expected_values[gle.account]["cost_center"], gle.cost_center)
set_perpetual_inventory(0, company)
+
+ def test_make_sales_invoice_from_dn_for_returned_qty(self):
+ from erpnext.selling.doctype.sales_order.sales_order import make_delivery_note
+ from erpnext.stock.doctype.delivery_note.delivery_note import make_sales_invoice
+
+ so = make_sales_order(qty=2)
+ so.submit()
+
+ dn = make_delivery_note(so.name)
+ dn.submit()
+
+ dn1 = create_delivery_note(is_return=1, return_against=dn.name, qty=-1, do_not_submit=True)
+ dn1.items[0].against_sales_order = so.name
+ dn1.items[0].so_detail = so.items[0].name
+ dn1.submit()
+
+ si = make_sales_invoice(dn.name)
+ self.assertEquals(si.items[0].qty, 1)
def create_delivery_note(**args):
dn = frappe.new_doc("Delivery Note")
diff --git a/erpnext/stock/doctype/item/item.js b/erpnext/stock/doctype/item/item.js
index a26da7f..388b643 100644
--- a/erpnext/stock/doctype/item/item.js
+++ b/erpnext/stock/doctype/item/item.js
@@ -651,7 +651,7 @@
frappe.call({
method:"erpnext.stock.doctype.item.item.get_item_attribute",
args:{
- parent: "Item Attribute",
+ parent: i,
attribute_value: term
},
callback: function(r) {
diff --git a/erpnext/stock/doctype/item/item.json b/erpnext/stock/doctype/item/item.json
index 7d1bb6d..0d2dd2c 100644
--- a/erpnext/stock/doctype/item/item.json
+++ b/erpnext/stock/doctype/item/item.json
@@ -1,5 +1,6 @@
{
"allow_copy": 0,
+ "allow_events_in_timeline": 0,
"allow_guest_to_view": 0,
"allow_import": 1,
"allow_rename": 1,
@@ -453,7 +454,7 @@
"collapsible": 0,
"columns": 0,
"default": "1",
- "fieldname": "allow_transfer_for_manufacture",
+ "fieldname": "include_item_in_manufacturing",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
@@ -462,7 +463,7 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
- "label": "Allow Transfer for Manufacture",
+ "label": "Include Item In Manufacturing",
"length": 0,
"no_copy": 0,
"permlevel": 0,
@@ -1459,7 +1460,7 @@
"collapsible": 0,
"columns": 0,
"depends_on": "eval:doc.has_batch_no==1 && doc.create_new_batch==1",
- "description": "Example: ABCD.#####. If series is set and Batch No is not mentioned in transactions, then automatic batch number will be created based on this series. If you always want to explicitly mention Batch No for this item, leave this blank. Note: this setting will take priority over the Naming Series Prefix in Stock Settings.",
+ "description": "Example: ABCD.#####. If series is set and Batch No is not mentioned in transactions,then automatic batch number will be created based on this series. If you always want to explicitly mention Batch No for this item,leave this blank. Note: this setting will take priority over the Naming Series Prefix in Stock Settings.",
"fieldname": "batch_number_series",
"fieldtype": "Data",
"hidden": 0,
@@ -1661,7 +1662,7 @@
"collapsible": 0,
"columns": 0,
"depends_on": "eval:doc.is_stock_item || doc.is_fixed_asset",
- "description": "Example: ABCD.#####\nIf series is set and Serial No is not mentioned in transactions, then automatic serial number will be created based on this series. If you always want to explicitly mention Serial Nos for this item. leave this blank.",
+ "description": "Example: ABCD.#####\nIf series is set and Serial No is not mentioned in transactions,then automatic serial number will be created based on this series. If you always want to explicitly mention Serial Nos for this item. leave this blank.",
"fieldname": "serial_no_series",
"fieldtype": "Data",
"hidden": 0,
@@ -1729,7 +1730,7 @@
"columns": 0,
"default": "0",
"depends_on": "eval:!doc.variant_of",
- "description": "If this item has variants, then it cannot be selected in sales orders etc.",
+ "description": "If this item has variants,then it cannot be selected in sales orders etc.",
"fieldname": "has_variants",
"fieldtype": "Check",
"hidden": 0,
@@ -1841,7 +1842,7 @@
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
- "label": "Sales, Purchase, Accounting Defaults",
+ "label": "Sales,Purchase,Accounting Defaults",
"length": 0,
"no_copy": 0,
"permlevel": 0,
@@ -4113,7 +4114,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 1,
- "modified": "2018-09-20 11:14:21.031369",
+ "modified": "2018-11-20 19:04:22.568410",
"modified_by": "Administrator",
"module": "Stock",
"name": "Item",
diff --git a/erpnext/stock/doctype/item/test_item.py b/erpnext/stock/doctype/item/test_item.py
index 24292f7..abdd676 100644
--- a/erpnext/stock/doctype/item/test_item.py
+++ b/erpnext/stock/doctype/item/test_item.py
@@ -392,4 +392,3 @@
"company": "_Test Company"
})
item.save()
-
diff --git a/erpnext/stock/doctype/item_default/item_default.json b/erpnext/stock/doctype/item_default/item_default.json
index 21e9355..96b5dfd 100644
--- a/erpnext/stock/doctype/item_default/item_default.json
+++ b/erpnext/stock/doctype/item_default/item_default.json
@@ -1,463 +1,464 @@
{
- "allow_copy": 0,
- "allow_guest_to_view": 0,
- "allow_import": 0,
- "allow_rename": 0,
- "beta": 0,
- "creation": "2018-05-03 02:29:24.444341",
- "custom": 0,
- "docstatus": 0,
- "doctype": "DocType",
- "document_type": "",
- "editable_grid": 1,
- "engine": "InnoDB",
+ "allow_copy": 0,
+ "allow_events_in_timeline": 0,
+ "allow_guest_to_view": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
+ "beta": 0,
+ "creation": "2018-05-03 02:29:24.444341",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "",
+ "editable_grid": 1,
+ "engine": "InnoDB",
"fields": [
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "company",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Company",
- "length": 0,
- "no_copy": 0,
- "options": "Company",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 1,
- "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": "company",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 1,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Company",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Company",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 1,
+ "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": "default_warehouse",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Default 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,
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "default_warehouse",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Default 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,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_3",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "column_break_3",
+ "fieldtype": "Column Break",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
"unique": 0
- },
+ },
{
- "allow_bulk_edit": 0,
- "allow_in_quick_entry": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "default_price_list",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 1,
- "in_standard_filter": 0,
- "label": "Default Price List",
- "length": 0,
- "no_copy": 0,
- "options": "Price List",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "default_price_list",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 1,
+ "in_standard_filter": 0,
+ "label": "Default Price List",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Price List",
+ "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": "purchase_defaults",
- "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": "Purchase Defaults",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "purchase_defaults",
+ "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": "Purchase Defaults",
+ "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": "buying_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": "Default Buying 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,
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "buying_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": "Default Buying 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,
- "fieldname": "default_supplier",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Default Supplier",
- "length": 0,
- "no_copy": 0,
- "options": "Supplier",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "default_supplier",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Default Supplier",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Supplier",
+ "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": "column_break_8",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "column_break_8",
+ "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,
- "fieldname": "expense_account",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Default Expense Account",
- "length": 0,
- "no_copy": 0,
- "options": "Account",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "expense_account",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Default Expense Account",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Account",
+ "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": "selling_defaults",
- "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": "Sales Defaults",
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "selling_defaults",
+ "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": "Sales Defaults",
+ "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": "selling_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": "Default Selling 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,
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "selling_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": "Default Selling 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,
- "fieldname": "column_break_12",
- "fieldtype": "Column Break",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "length": 0,
- "no_copy": 0,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "column_break_12",
+ "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,
- "fieldname": "income_account",
- "fieldtype": "Link",
- "hidden": 0,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Default Income Account",
- "length": 0,
- "no_copy": 0,
- "options": "Account",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 0,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "translatable": 0,
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "income_account",
+ "fieldtype": "Link",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Default Income Account",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Account",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 0,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
"unique": 0
}
- ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 0,
- "istable": 1,
- "max_attachments": 0,
- "modified": "2018-09-19 16:17:52.562232",
- "modified_by": "Administrator",
- "module": "Stock",
- "name": "Item Default",
- "name_case": "",
- "owner": "Administrator",
- "permissions": [],
- "quick_entry": 1,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1,
- "track_seen": 0,
+ ],
+ "has_web_view": 0,
+ "hide_heading": 0,
+ "hide_toolbar": 0,
+ "idx": 0,
+ "image_view": 0,
+ "in_create": 0,
+ "is_submittable": 0,
+ "issingle": 0,
+ "istable": 1,
+ "max_attachments": 0,
+ "modified": "2018-12-07 11:48:07.638935",
+ "modified_by": "Administrator",
+ "module": "Stock",
+ "name": "Item Default",
+ "name_case": "",
+ "owner": "Administrator",
+ "permissions": [],
+ "quick_entry": 1,
+ "read_only": 0,
+ "read_only_onload": 0,
+ "show_name_in_global_search": 0,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1,
+ "track_seen": 0,
"track_views": 0
}
\ No newline at end of file
diff --git a/erpnext/stock/doctype/material_request/material_request.js b/erpnext/stock/doctype/material_request/material_request.js
index 5fd7a6a..2b0ed38 100644
--- a/erpnext/stock/doctype/material_request/material_request.js
+++ b/erpnext/stock/doctype/material_request/material_request.js
@@ -102,7 +102,7 @@
update_status: function(frm, stop_status) {
frappe.call({
- method: 'erpnext.stock.material_request.material_request.update_status',
+ method: 'erpnext.stock.doctype.material_request.material_request.update_status',
args: { name: frm.doc.name, status: stop_status },
callback(r) {
if (!r.exc) {
diff --git a/erpnext/stock/doctype/material_request/material_request.py b/erpnext/stock/doctype/material_request/material_request.py
index df27a59..f3e3abf 100644
--- a/erpnext/stock/doctype/material_request/material_request.py
+++ b/erpnext/stock/doctype/material_request/material_request.py
@@ -441,31 +441,40 @@
errors =[]
work_orders = []
default_wip_warehouse = frappe.db.get_single_value("Manufacturing Settings", "default_wip_warehouse")
+
for d in mr.items:
if (d.qty - d.ordered_qty) >0:
- if frappe.db.get_value("BOM", {"item": d.item_code, "is_default": 1}):
+ if frappe.db.exists("BOM", {"item": d.item_code, "is_default": 1}):
wo_order = frappe.new_doc("Work Order")
- wo_order.production_item = d.item_code
- wo_order.qty = d.qty - d.ordered_qty
- wo_order.fg_warehouse = d.warehouse
- wo_order.wip_warehouse = default_wip_warehouse
- wo_order.description = d.description
- wo_order.stock_uom = d.stock_uom
- wo_order.expected_delivery_date = d.schedule_date
- wo_order.sales_order = d.sales_order
- wo_order.bom_no = get_item_details(d.item_code).bom_no
- wo_order.material_request = mr.name
- wo_order.material_request_item = d.name
- wo_order.planned_start_date = mr.transaction_date
- wo_order.company = mr.company
+ wo_order.update({
+ "production_item": d.item_code,
+ "qty": d.qty - d.ordered_qty,
+ "fg_warehouse": d.warehouse,
+ "wip_warehouse": default_wip_warehouse,
+ "description": d.description,
+ "stock_uom": d.stock_uom,
+ "expected_delivery_date": d.schedule_date,
+ "sales_order": d.sales_order,
+ "bom_no": get_item_details(d.item_code).bom_no,
+ "material_request": mr.name,
+ "material_request_item": d.name,
+ "planned_start_date": mr.transaction_date,
+ "company": mr.company
+ })
+
+ wo_order.set_work_order_operations()
wo_order.save()
+
work_orders.append(wo_order.name)
else:
errors.append(_("Row {0}: Bill of Materials not found for the Item {1}").format(d.idx, d.item_code))
+
if work_orders:
message = ["""<a href="#Form/Work Order/%s" target="_blank">%s</a>""" % \
(p, p) for p in work_orders]
msgprint(_("The following Work Orders were created:") + '\n' + new_line_sep(message))
+
if errors:
frappe.throw(_("Productions Orders cannot be raised for:") + '\n' + new_line_sep(errors))
+
return work_orders
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt_list.js b/erpnext/stock/doctype/purchase_receipt/purchase_receipt_list.js
index e1d5b08..e81f323 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt_list.js
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt_list.js
@@ -1,7 +1,8 @@
frappe.listview_settings['Purchase Receipt'] = {
- add_fields: ["is_return", "grand_total", "status", "per_billed"],
- get_indicator: function (doc) {
- if (cint(doc.is_return) == 1) {
+ add_fields: ["supplier", "supplier_name", "base_grand_total", "is_subcontracted",
+ "transporter_name", "is_return", "status", "per_billed", "currency"],
+ get_indicator: function(doc) {
+ if(cint(doc.is_return)==1) {
return [__("Return"), "darkgrey", "is_return,=,Yes"];
} else if (doc.status === "Closed") {
return [__("Closed"), "green", "status,=,Closed"];
diff --git a/erpnext/stock/doctype/quality_inspection/quality_inspection.py b/erpnext/stock/doctype/quality_inspection/quality_inspection.py
index 36f6405..e0b7382 100644
--- a/erpnext/stock/doctype/quality_inspection/quality_inspection.py
+++ b/erpnext/stock/doctype/quality_inspection/quality_inspection.py
@@ -61,7 +61,7 @@
if filters.get("from"):
from frappe.desk.reportview import get_match_cond
mcond = get_match_cond(filters["from"])
- cond = ""
+ cond, qi_condition = "", "and (quality_inspection is null or quality_inspection = '')"
if filters.get('from') in ['Purchase Invoice Item', 'Purchase Receipt Item']:
cond = """and item_code in (select name from `tabItem` where
@@ -72,9 +72,13 @@
elif filters.get('from') == 'Stock Entry Detail':
cond = """and s_warehouse is null"""
+ if filters.get('from') in ['Supplier Quotation Item']:
+ qi_condition = ""
+
return frappe.db.sql(""" select item_code from `tab{doc}`
where parent=%(parent)s and docstatus < 2 and item_code like %(txt)s
- and (quality_inspection is null or quality_inspection = '')
- {cond} {mcond} order by item_code limit {start}, {page_len}""".format(doc=filters.get('from'),
- parent=filters.get('parent'), cond=cond, mcond=mcond, start=start, page_len = page_len),
+ {qi_condition} {cond} {mcond}
+ order by item_code limit {start}, {page_len}""".format(doc=filters.get('from'),
+ parent=filters.get('parent'), cond = cond, mcond = mcond, start = start,
+ page_len = page_len, qi_condition = qi_condition),
{'parent': filters.get('parent'), 'txt': "%%%s%%" % txt})
diff --git a/erpnext/stock/doctype/quality_inspection/test_quality_inspection.py b/erpnext/stock/doctype/quality_inspection/test_quality_inspection.py
index 1c8ec23..60cc9a0 100644
--- a/erpnext/stock/doctype/quality_inspection/test_quality_inspection.py
+++ b/erpnext/stock/doctype/quality_inspection/test_quality_inspection.py
@@ -3,8 +3,45 @@
import frappe
import unittest
+from frappe.utils import nowdate
+from erpnext.stock.doctype.item.test_item import create_item
+from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note
+from erpnext.controllers.stock_controller import QualityInspectionRejectedError, QualityInspectionRequiredError
# test_records = frappe.get_test_records('Quality Inspection')
class TestQualityInspection(unittest.TestCase):
- pass
+ def setUp(self):
+ create_item("_Test Item with QA")
+ frappe.db.set_value("Item", "_Test Item with QA", "inspection_required_before_delivery", 1)
+
+ def test_qa_for_delivery(self):
+ dn = create_delivery_note(item_code="_Test Item with QA", do_not_submit=True)
+ self.assertRaises(QualityInspectionRequiredError, dn.submit)
+
+ qa = create_quality_inspection(reference_type="Delivery Note", reference_name=dn.name, status="Rejected")
+ dn.reload()
+ self.assertRaises(QualityInspectionRejectedError, dn.submit)
+
+ frappe.db.set_value("Quality Inspection Reading", {"parent": qa.name}, "status", "Accepted")
+ dn.reload()
+ dn.submit()
+
+def create_quality_inspection(**args):
+ args = frappe._dict(args)
+ qa = frappe.new_doc("Quality Inspection")
+ qa.report_date = nowdate()
+ qa.inspection_type = args.inspection_type or "Outgoing"
+ qa.reference_type = args.reference_type
+ qa.reference_name = args.reference_name
+ qa.item_code = args.item_code or "_Test Item with QA"
+ qa.sample_size = 1
+ qa.inspected_by = frappe.session.user
+ qa.append("readings", {
+ "specification": "Size",
+ "status": args.status
+ })
+ qa.save()
+ qa.submit()
+
+ return qa
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py
index d8e4656..5d3c6c4 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.py
@@ -605,7 +605,7 @@
if self.job_card:
job_doc = frappe.get_doc('Job Card', self.job_card)
- job_doc.set_transferred_qty()
+ job_doc.set_transferred_qty(update_status=True)
if self.work_order:
pro_doc = frappe.get_doc("Work Order", self.work_order)
@@ -999,7 +999,7 @@
for d in pro_order.get("required_items"):
if (flt(d.required_qty) > flt(d.transferred_qty) and
- (d.allow_transfer_for_manufacture or self.purpose != "Material Transfer for Manufacture")):
+ (d.include_item_in_manufacturing or self.purpose != "Material Transfer for Manufacture")):
item_row = d.as_dict()
if d.source_warehouse and not frappe.db.get_value("Warehouse", d.source_warehouse, "is_group"):
item_row["from_warehouse"] = d.source_warehouse
diff --git a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.js b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.js
index 4d34d96..ed9d770 100644
--- a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.js
+++ b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.js
@@ -42,7 +42,7 @@
},
get_items: function(frm) {
- frappe.prompt({label:"Warehouse", fieldtype:"Link", options:"Warehouse", reqd: 1,
+ frappe.prompt({label:"Warehouse", fieldname: "warehouse", fieldtype:"Link", options:"Warehouse", reqd: 1,
"get_query": function() {
return {
"filters": {
diff --git a/erpnext/stock/report/warehouse_wise_item_balance_age_and_value/warehouse_wise_item_balance_age_and_value.js b/erpnext/stock/report/warehouse_wise_item_balance_age_and_value/warehouse_wise_item_balance_age_and_value.js
index 21884d8..39cfd72 100644
--- a/erpnext/stock/report/warehouse_wise_item_balance_age_and_value/warehouse_wise_item_balance_age_and_value.js
+++ b/erpnext/stock/report/warehouse_wise_item_balance_age_and_value/warehouse_wise_item_balance_age_and_value.js
@@ -10,7 +10,7 @@
"fieldtype": "Date",
"width": "80",
"reqd": 1,
- "default": frappe.sys_defaults.year_start_date,
+ "default": frappe.datetime.add_months(frappe.datetime.get_today(), -1),
},
{
"fieldname":"to_date",
diff --git a/erpnext/stock/report/warehouse_wise_item_balance_age_and_value/warehouse_wise_item_balance_age_and_value.py b/erpnext/stock/report/warehouse_wise_item_balance_age_and_value/warehouse_wise_item_balance_age_and_value.py
index 676cf54..ebcb106 100644
--- a/erpnext/stock/report/warehouse_wise_item_balance_age_and_value/warehouse_wise_item_balance_age_and_value.py
+++ b/erpnext/stock/report/warehouse_wise_item_balance_age_and_value/warehouse_wise_item_balance_age_and_value.py
@@ -8,7 +8,8 @@
import frappe
from frappe import _
from frappe.utils import flt, cint, getdate
-from erpnext.stock.report.stock_balance.stock_balance import get_item_details, get_item_reorder_details, get_item_warehouse_map
+from erpnext.stock.report.stock_balance.stock_balance import (get_item_details,
+ get_item_reorder_details, get_item_warehouse_map, get_items, get_stock_ledger_entries)
from erpnext.stock.report.stock_ageing.stock_ageing import get_fifo_queue, get_average_age
from six import iteritems
@@ -18,8 +19,12 @@
validate_filters(filters)
columns = get_columns(filters)
- item_map = get_item_details(filters)
- iwb_map = get_item_warehouse_map(filters)
+
+ items = get_items(filters)
+ sle = get_stock_ledger_entries(filters, items)
+
+ item_map = get_item_details(items, sle, filters)
+ iwb_map = get_item_warehouse_map(filters, sle)
warehouse_list = get_warehouse_list(filters)
item_ageing = get_fifo_queue(filters)
data = []
@@ -27,6 +32,8 @@
item_value = {}
for (company, item, warehouse) in sorted(iwb_map):
+ if not item_map.get(item): continue
+
row = []
qty_dict = iwb_map[(company, item, warehouse)]
item_balance.setdefault((item, item_map[item]["item_group"]), [])
@@ -42,6 +49,8 @@
# sum bal_qty by item
for (item, item_group), wh_balance in iteritems(item_balance):
+ if not item_ageing.get(item): continue
+
total_stock_value = sum(item_value[(item, item_group)])
row = [item, item_group, total_stock_value]
@@ -85,11 +94,10 @@
filters["company"] = frappe.defaults.get_user_default("Company")
def get_warehouse_list(filters):
- from frappe.defaults import get_user_permissions
+ from frappe.core.doctype.user_permission.user_permission import get_permitted_documents
+
condition = ''
- user_permitted_warehouse = filter(None, get_user_permissions()
- .get("Warehouse", {})
- .get("docs", []))
+ user_permitted_warehouse = get_permitted_documents('Warehouse')
value = ()
if user_permitted_warehouse:
condition = "and name in %s"
diff --git a/erpnext/templates/includes/itemised_tax_breakup.html b/erpnext/templates/includes/itemised_tax_breakup.html
index 982397e..c27e4ce 100644
--- a/erpnext/templates/includes/itemised_tax_breakup.html
+++ b/erpnext/templates/includes/itemised_tax_breakup.html
@@ -16,7 +16,7 @@
<tr>
<td>{{ item }}</td>
<td class='text-right'>
- {{ frappe.utils.fmt_money(itemised_taxable_amount.get(item), None, currency) }}
+ {{ frappe.utils.fmt_money(itemised_taxable_amount.get(item, 0), None, currency) }}
</td>
{% for tax_account in tax_accounts %}
{% set tax_details = taxes.get(tax_account) %}
diff --git a/erpnext/templates/pages/product_search.py b/erpnext/templates/pages/product_search.py
index d503490..c34001b 100644
--- a/erpnext/templates/pages/product_search.py
+++ b/erpnext/templates/pages/product_search.py
@@ -26,7 +26,6 @@
left join tabBin S on I.item_code = S.item_code and I.website_warehouse = S.warehouse
where (I.show_in_website = 1)
and I.disabled = 0
- and (I.variant_of is null or I.variant_of='')
and (I.end_of_life is null or I.end_of_life='0000-00-00' or I.end_of_life > %(today)s)"""
# search term condition