Merge branch 'Party-Ledger-Summary' of https://saifi0102@github.com/SaiFi0102/erpnext.git into Party-Ledger-Summary

This commit is contained in:
Saif Ur Rehman 2019-01-19 13:18:23 +05:00
commit fcaed12a53
170 changed files with 19949 additions and 18216 deletions

View File

@ -33,7 +33,7 @@ before_script:
- cd ~/frappe-bench - cd ~/frappe-bench
- bench get-app erpnext $TRAVIS_BUILD_DIR - bench get-app erpnext $TRAVIS_BUILD_DIR
- bench use test_site - bench use test_site
- bench reinstall --yes - bench reinstall --mariadb-root-username root --mariadb-root-password travis --yes
- bench build - bench build
- bench scheduler disable - bench scheduler disable
- sed -i 's/9000/9001/g' sites/common_site_config.json - sed -i 's/9000/9001/g' sites/common_site_config.json

View File

@ -5,7 +5,7 @@ import frappe
from erpnext.hooks import regional_overrides from erpnext.hooks import regional_overrides
from frappe.utils import getdate from frappe.utils import getdate
__version__ = '10.1.74' __version__ = '10.1.77'
def get_default_company(user=None): def get_default_company(user=None):
'''Get default company for user''' '''Get default company for user'''

View File

@ -1,5 +1,6 @@
{ {
"allow_copy": 1, "allow_copy": 1,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0, "allow_guest_to_view": 0,
"allow_import": 1, "allow_import": 1,
"allow_rename": 0, "allow_rename": 0,
@ -14,6 +15,7 @@
"fields": [ "fields": [
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -45,6 +47,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -75,6 +78,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -107,6 +111,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -138,6 +143,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -170,6 +176,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -203,6 +210,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -234,6 +242,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -265,6 +274,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -298,6 +308,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -330,6 +341,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -360,6 +372,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -393,6 +406,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -427,6 +441,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -460,6 +475,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -494,6 +510,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -525,6 +542,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -555,6 +573,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -585,6 +604,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -625,7 +645,7 @@
"issingle": 0, "issingle": 0,
"istable": 0, "istable": 0,
"max_attachments": 0, "max_attachments": 0,
"modified": "2018-09-05 09:47:04.287841", "modified": "2019-01-07 16:52:02.557837",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Account", "name": "Account",
@ -734,5 +754,6 @@
"show_name_in_global_search": 1, "show_name_in_global_search": 1,
"sort_order": "ASC", "sort_order": "ASC",
"track_changes": 1, "track_changes": 1,
"track_seen": 0 "track_seen": 0,
"track_views": 0
} }

View File

@ -1,5 +1,6 @@
{ {
"allow_copy": 0, "allow_copy": 0,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0, "allow_guest_to_view": 0,
"allow_import": 0, "allow_import": 0,
"allow_rename": 0, "allow_rename": 0,
@ -15,6 +16,7 @@
"fields": [ "fields": [
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -47,6 +49,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -78,6 +81,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -110,6 +114,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -140,6 +145,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -172,6 +178,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -203,6 +210,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -234,6 +242,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -266,6 +275,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -298,6 +308,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -329,6 +340,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -360,6 +372,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -391,6 +404,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -421,6 +435,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -452,6 +467,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -483,6 +499,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -515,6 +532,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -548,6 +566,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -579,6 +598,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -622,7 +642,7 @@
"issingle": 1, "issingle": 1,
"istable": 0, "istable": 0,
"max_attachments": 0, "max_attachments": 0,
"modified": "2018-05-14 15:58:27.638576", "modified": "2019-01-07 16:52:03.869199",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Accounts Settings", "name": "Accounts Settings",
@ -692,5 +712,6 @@
"show_name_in_global_search": 0, "show_name_in_global_search": 0,
"sort_order": "ASC", "sort_order": "ASC",
"track_changes": 1, "track_changes": 1,
"track_seen": 0 "track_seen": 0,
"track_views": 0
} }

View File

@ -1,5 +1,6 @@
{ {
"allow_copy": 0, "allow_copy": 0,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0, "allow_guest_to_view": 0,
"allow_import": 0, "allow_import": 0,
"allow_rename": 0, "allow_rename": 0,
@ -12,6 +13,7 @@
"fields": [ "fields": [
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -39,10 +41,12 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -71,11 +75,13 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0, "unique": 0,
"width": "50" "width": "50"
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -103,11 +109,13 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0, "unique": 0,
"width": "15" "width": "15"
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -136,10 +144,12 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -165,11 +175,13 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0, "unique": 0,
"width": "50%" "width": "50%"
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -197,10 +209,12 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -228,10 +242,12 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -259,10 +275,12 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -290,6 +308,7 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
} }
], ],
@ -304,7 +323,7 @@
"istable": 1, "istable": 1,
"max_attachments": 0, "max_attachments": 0,
"menu_index": 0, "menu_index": 0,
"modified": "2017-06-23 12:07:50.883515", "modified": "2019-01-07 16:52:07.174687",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Bank Reconciliation Detail", "name": "Bank Reconciliation Detail",
@ -316,5 +335,6 @@
"show_name_in_global_search": 0, "show_name_in_global_search": 0,
"sort_order": "ASC", "sort_order": "ASC",
"track_changes": 0, "track_changes": 0,
"track_seen": 0 "track_seen": 0,
"track_views": 0
} }

View File

@ -39,6 +39,8 @@ frappe.ui.form.on('Exchange Rate Revaluation', {
}); });
frm.events.get_total_gain_loss(frm); frm.events.get_total_gain_loss(frm);
refresh_field("accounts"); refresh_field("accounts");
} else {
frappe.msgprint(__("No records found"));
} }
} }
}); });

View File

@ -67,6 +67,8 @@ class ExchangeRateRevaluation(Document):
and account_currency != %s and account_currency != %s
order by name""",(self.company, company_currency)) order by name""",(self.company, company_currency))
account_details = []
if accounts:
account_details = frappe.db.sql(""" account_details = frappe.db.sql("""
select select
account, party_type, party, account_currency, account, party_type, party, account_currency,

View File

@ -1,5 +1,6 @@
{ {
"allow_copy": 0, "allow_copy": 0,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0, "allow_guest_to_view": 0,
"allow_import": 0, "allow_import": 0,
"allow_rename": 0, "allow_rename": 0,
@ -14,6 +15,7 @@
"fields": [ "fields": [
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -46,6 +48,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -78,6 +81,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -110,6 +114,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -140,6 +145,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -172,6 +178,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -203,6 +210,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -234,6 +242,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -265,6 +274,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -296,6 +306,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -326,6 +337,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -357,6 +369,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -388,6 +401,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -428,7 +442,7 @@
"issingle": 0, "issingle": 0,
"istable": 1, "istable": 1,
"max_attachments": 0, "max_attachments": 0,
"modified": "2018-05-05 17:03:03.512559", "modified": "2019-01-07 16:52:07.327930",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Exchange Rate Revaluation Account", "name": "Exchange Rate Revaluation Account",
@ -442,5 +456,6 @@
"sort_field": "modified", "sort_field": "modified",
"sort_order": "DESC", "sort_order": "DESC",
"track_changes": 1, "track_changes": 1,
"track_seen": 0 "track_seen": 0,
"track_views": 0
} }

View File

@ -18,15 +18,14 @@ class GLEntry(Document):
self.flags.ignore_submit_comment = True self.flags.ignore_submit_comment = True
self.check_mandatory() self.check_mandatory()
self.validate_and_set_fiscal_year() self.validate_and_set_fiscal_year()
self.pl_must_have_cost_center()
self.validate_cost_center()
if not self.flags.from_repost: if not self.flags.from_repost:
self.pl_must_have_cost_center()
self.check_pl_account() self.check_pl_account()
self.validate_cost_center()
self.validate_party() self.validate_party()
self.validate_currency() self.validate_currency()
def on_update_with_args(self, adv_adj, update_outstanding = 'Yes', from_repost=False): def on_update_with_args(self, adv_adj, update_outstanding = 'Yes', from_repost=False):
if not from_repost: if not from_repost:
self.validate_account_details(adv_adj) self.validate_account_details(adv_adj)

View File

@ -1,5 +1,6 @@
{ {
"allow_copy": 0, "allow_copy": 0,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0, "allow_guest_to_view": 0,
"allow_import": 1, "allow_import": 1,
"allow_rename": 0, "allow_rename": 0,
@ -1701,7 +1702,7 @@
"istable": 0, "istable": 0,
"max_attachments": 0, "max_attachments": 0,
"menu_index": 0, "menu_index": 0,
"modified": "2018-09-06 06:30:32.703311", "modified": "2019-01-07 16:52:02.838365",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Journal Entry", "name": "Journal Entry",

View File

@ -7,6 +7,7 @@ import frappe
import unittest import unittest
from frappe.utils import today, cint, flt, getdate from frappe.utils import today, cint, flt, getdate
from erpnext.accounts.doctype.loyalty_program.loyalty_program import get_loyalty_program_details_with_points from erpnext.accounts.doctype.loyalty_program.loyalty_program import get_loyalty_program_details_with_points
from erpnext.accounts.party import get_dashboard_info
class TestLoyaltyProgram(unittest.TestCase): class TestLoyaltyProgram(unittest.TestCase):
@classmethod @classmethod
@ -144,6 +145,13 @@ class TestLoyaltyProgram(unittest.TestCase):
frappe.get_doc('Sales Invoice', d.name).cancel() frappe.get_doc('Sales Invoice', d.name).cancel()
frappe.delete_doc('Sales Invoice', d.name) frappe.delete_doc('Sales Invoice', d.name)
def test_loyalty_points_for_dashboard(self):
doc = frappe.get_doc('Customer', 'Test Loyalty Customer')
company_wise_info = get_dashboard_info("Customer", doc.name, doc.loyalty_program)
for d in company_wise_info:
self.assertTrue(d.loyalty_points)
def get_points_earned(self): def get_points_earned(self):
def get_returned_amount(): def get_returned_amount():
returned_amount = frappe.db.sql(""" returned_amount = frappe.db.sql("""

View File

@ -1,5 +1,7 @@
{ {
"allow_copy": 0, "allow_copy": 0,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0,
"allow_import": 0, "allow_import": 0,
"allow_rename": 0, "allow_rename": 0,
"beta": 0, "beta": 0,
@ -11,16 +13,21 @@
"editable_grid": 1, "editable_grid": 1,
"fields": [ "fields": [
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0,
"fieldname": "account", "fieldname": "account",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_global_search": 0,
"in_list_view": 1, "in_list_view": 1,
"in_standard_filter": 0,
"label": "Account", "label": "Account",
"length": 0, "length": 0,
"no_copy": 0, "no_copy": 0,
@ -30,23 +37,30 @@
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0, "print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 1, "reqd": 1,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0,
"fieldname": "cost_center", "fieldname": "cost_center",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_global_search": 0,
"in_list_view": 1, "in_list_view": 1,
"in_standard_filter": 0,
"label": "Cost Center", "label": "Cost Center",
"length": 0, "length": 0,
"no_copy": 0, "no_copy": 0,
@ -56,23 +70,30 @@
"print_hide": 1, "print_hide": 1,
"print_hide_if_no_value": 0, "print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 1, "reqd": 1,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0,
"fieldname": "amount", "fieldname": "amount",
"fieldtype": "Currency", "fieldtype": "Currency",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_global_search": 0,
"in_list_view": 1, "in_list_view": 1,
"in_standard_filter": 0,
"label": "Amount", "label": "Amount",
"length": 0, "length": 0,
"no_copy": 0, "no_copy": 0,
@ -81,24 +102,26 @@
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0, "print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 1, "reqd": 1,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
} }
], ],
"has_web_view": 0,
"hide_heading": 0, "hide_heading": 0,
"hide_toolbar": 0, "hide_toolbar": 0,
"idx": 0, "idx": 0,
"image_view": 0, "image_view": 0,
"in_create": 0, "in_create": 0,
"is_submittable": 0, "is_submittable": 0,
"issingle": 0, "issingle": 0,
"istable": 1, "istable": 1,
"max_attachments": 0, "max_attachments": 0,
"modified": "2018-02-21 03:28:03.420683", "modified": "2019-01-07 16:52:07.040146",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Payment Entry Deduction", "name": "Payment Entry Deduction",
@ -108,7 +131,10 @@
"quick_entry": 1, "quick_entry": 1,
"read_only": 0, "read_only": 0,
"read_only_onload": 0, "read_only_onload": 0,
"show_name_in_global_search": 0,
"sort_field": "modified", "sort_field": "modified",
"sort_order": "DESC", "sort_order": "DESC",
"track_seen": 0 "track_changes": 0,
"track_seen": 0,
"track_views": 0
} }

View File

@ -1,5 +1,6 @@
{ {
"allow_copy": 0, "allow_copy": 0,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0, "allow_guest_to_view": 0,
"allow_import": 0, "allow_import": 0,
"allow_rename": 0, "allow_rename": 0,
@ -14,6 +15,7 @@
"fields": [ "fields": [
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -41,10 +43,12 @@
"reqd": 1, "reqd": 1,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -72,10 +76,12 @@
"reqd": 1, "reqd": 1,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -102,10 +108,12 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -133,10 +141,12 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -162,10 +172,12 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -192,10 +204,12 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -222,10 +236,12 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -252,10 +268,12 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -283,6 +301,7 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
} }
], ],
@ -296,7 +315,7 @@
"issingle": 0, "issingle": 0,
"istable": 1, "istable": 1,
"max_attachments": 0, "max_attachments": 0,
"modified": "2017-10-16 17:37:01.192312", "modified": "2019-01-07 16:52:06.884796",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Payment Entry Reference", "name": "Payment Entry Reference",
@ -310,5 +329,6 @@
"sort_field": "modified", "sort_field": "modified",
"sort_order": "DESC", "sort_order": "DESC",
"track_changes": 1, "track_changes": 1,
"track_seen": 0 "track_seen": 0,
"track_views": 0
} }

View File

@ -1,5 +1,7 @@
{ {
"allow_copy": 0, "allow_copy": 0,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0,
"allow_import": 0, "allow_import": 0,
"allow_rename": 0, "allow_rename": 0,
"beta": 0, "beta": 0,
@ -11,6 +13,8 @@
"editable_grid": 1, "editable_grid": 1,
"fields": [ "fields": [
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -21,6 +25,7 @@
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 0, "in_standard_filter": 0,
"label": "Reference Type", "label": "Reference Type",
@ -36,9 +41,12 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -49,6 +57,7 @@
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_global_search": 0,
"in_list_view": 1, "in_list_view": 1,
"in_standard_filter": 0, "in_standard_filter": 0,
"label": "Reference Name", "label": "Reference Name",
@ -65,9 +74,12 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -78,6 +90,7 @@
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 0, "in_standard_filter": 0,
"label": "Posting Date", "label": "Posting Date",
@ -92,9 +105,12 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -105,6 +121,7 @@
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 0, "in_standard_filter": 0,
"label": "Is Advance", "label": "Is Advance",
@ -119,9 +136,12 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -132,6 +152,7 @@
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 0, "in_standard_filter": 0,
"label": "Reference Row", "label": "Reference Row",
@ -146,9 +167,12 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -159,6 +183,7 @@
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 0, "in_standard_filter": 0,
"label": "", "label": "",
@ -173,9 +198,12 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -186,6 +214,7 @@
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_global_search": 0,
"in_list_view": 1, "in_list_view": 1,
"in_standard_filter": 0, "in_standard_filter": 0,
"label": "Invoice Number", "label": "Invoice Number",
@ -201,9 +230,12 @@
"reqd": 1, "reqd": 1,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -214,6 +246,7 @@
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_global_search": 0,
"in_list_view": 1, "in_list_view": 1,
"in_standard_filter": 0, "in_standard_filter": 0,
"label": "Amount", "label": "Amount",
@ -228,9 +261,12 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -241,6 +277,7 @@
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_global_search": 0,
"in_list_view": 1, "in_list_view": 1,
"in_standard_filter": 0, "in_standard_filter": 0,
"label": "Allocated amount", "label": "Allocated amount",
@ -256,9 +293,12 @@
"reqd": 1, "reqd": 1,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -269,6 +309,7 @@
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 0, "in_standard_filter": 0,
"label": "", "label": "",
@ -283,9 +324,12 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -296,6 +340,7 @@
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
"in_filter": 0, "in_filter": 0,
"in_global_search": 0,
"in_list_view": 1, "in_list_view": 1,
"in_standard_filter": 0, "in_standard_filter": 0,
"label": "Remark", "label": "Remark",
@ -310,21 +355,22 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
} }
], ],
"has_web_view": 0,
"hide_heading": 0, "hide_heading": 0,
"hide_toolbar": 0, "hide_toolbar": 0,
"idx": 0, "idx": 0,
"image_view": 0, "image_view": 0,
"in_create": 0, "in_create": 0,
"is_submittable": 0, "is_submittable": 0,
"issingle": 0, "issingle": 0,
"istable": 1, "istable": 1,
"max_attachments": 0, "max_attachments": 0,
"menu_index": 0, "menu_index": 0,
"modified": "2017-01-30 01:04:22.557237", "modified": "2019-01-07 16:52:07.567027",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Payment Reconciliation Payment", "name": "Payment Reconciliation Payment",
@ -334,8 +380,10 @@
"quick_entry": 1, "quick_entry": 1,
"read_only": 0, "read_only": 0,
"read_only_onload": 0, "read_only_onload": 0,
"show_name_in_global_search": 0,
"sort_field": "modified", "sort_field": "modified",
"sort_order": "DESC", "sort_order": "DESC",
"track_changes": 0, "track_changes": 0,
"track_seen": 0 "track_seen": 0,
"track_views": 0
} }

View File

@ -37,8 +37,8 @@ frappe.ui.form.on('POS Profile', {
return { filters: { doc_type: "Sales Invoice", print_format_type: "Js"} }; 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) => { frappe.db.get_value('POS Settings', 'POS Settings', 'use_pos_in_offline_mode', (r) => {
is_offline = r && cint(r.use_pos_in_offline_mode) const is_offline = r && cint(r.use_pos_in_offline_mode)
frm.toggle_display('offline_pos_section', is_offline); frm.toggle_display('offline_pos_section', is_offline);
frm.toggle_display('print_format_for_online', !is_offline); frm.toggle_display('print_format_for_online', !is_offline);
}); });

View File

@ -4,7 +4,7 @@
"allow_guest_to_view": 0, "allow_guest_to_view": 0,
"allow_import": 0, "allow_import": 0,
"allow_rename": 1, "allow_rename": 1,
"autoname": "field:pos_profile_name", "autoname": "Prompt",
"beta": 0, "beta": 0,
"creation": "2013-05-24 12:15:51", "creation": "2013-05-24 12:15:51",
"custom": 0, "custom": 0,
@ -52,6 +52,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "",
"fieldname": "section_break_2", "fieldname": "section_break_2",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
@ -76,38 +77,6 @@
"translatable": 0, "translatable": 0,
"unique": 0 "unique": 0
}, },
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 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": 1
},
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0, "allow_in_quick_entry": 0,
@ -142,6 +111,240 @@
"translatable": 0, "translatable": 0,
"unique": 0 "unique": 0
}, },
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "customer",
"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": "Customer",
"length": 0,
"no_copy": 0,
"oldfieldname": "customer_account",
"oldfieldtype": "Link",
"options": "Customer",
"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": "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,
"oldfieldname": "company",
"oldfieldtype": "Link",
"options": "Company",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 1,
"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,
"fetch_from": "company.country",
"fieldname": "country",
"fieldtype": "Read Only",
"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": "Country",
"length": 0,
"no_copy": 0,
"options": "",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "update_stock",
"fieldname": "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": "Warehouse",
"length": 0,
"no_copy": 0,
"oldfieldname": "warehouse",
"oldfieldtype": "Link",
"options": "Warehouse",
"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": "campaign",
"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": "Campaign",
"length": 0,
"no_copy": 0,
"options": "Campaign",
"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": "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_bulk_edit": 0,
"allow_in_quick_entry": 0, "allow_in_quick_entry": 0,
@ -374,207 +577,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fieldname": "column_break_4", "depends_on": "",
"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": "customer",
"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": "Customer",
"length": 0,
"no_copy": 0,
"oldfieldname": "customer_account",
"oldfieldtype": "Link",
"options": "Customer",
"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": "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,
"oldfieldname": "company",
"oldfieldtype": "Link",
"options": "Company",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 1,
"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,
"fetch_from": "company.country",
"fieldname": "country",
"fieldtype": "Read Only",
"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": "Country",
"length": 0,
"no_copy": 0,
"options": "",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "update_stock",
"fieldname": "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": "Warehouse",
"length": 0,
"no_copy": 0,
"oldfieldname": "warehouse",
"oldfieldtype": "Link",
"options": "Warehouse",
"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": "campaign",
"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": "Campaign",
"length": 0,
"no_copy": 0,
"options": "Campaign",
"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": "section_break_15", "fieldname": "section_break_15",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
@ -649,6 +652,7 @@
"in_global_search": 0, "in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 0, "in_standard_filter": 0,
"label": "Mode of Payment",
"length": 0, "length": 0,
"no_copy": 0, "no_copy": 0,
"permlevel": 0, "permlevel": 0,
@ -714,6 +718,7 @@
"in_global_search": 0, "in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 0, "in_standard_filter": 0,
"label": "",
"length": 0, "length": 0,
"no_copy": 0, "no_copy": 0,
"permlevel": 0, "permlevel": 0,
@ -736,6 +741,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"description": "Only show Items from these Item Groups",
"fieldname": "item_groups", "fieldname": "item_groups",
"fieldtype": "Table", "fieldtype": "Table",
"hidden": 0, "hidden": 0,
@ -800,6 +806,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"description": "Only show Customer of these Customer Groups",
"fieldname": "customer_groups", "fieldname": "customer_groups",
"fieldtype": "Table", "fieldtype": "Table",
"hidden": 0, "hidden": 0,
@ -843,6 +850,7 @@
"in_global_search": 0, "in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 0, "in_standard_filter": 0,
"label": "Print Settings",
"length": 0, "length": 0,
"no_copy": 0, "no_copy": 0,
"permlevel": 0, "permlevel": 0,
@ -925,40 +933,6 @@
"translatable": 0, "translatable": 0,
"unique": 0 "unique": 0
}, },
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 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_bulk_edit": 0,
"allow_in_quick_entry": 0, "allow_in_quick_entry": 0,
@ -990,40 +964,6 @@
"translatable": 0, "translatable": 0,
"unique": 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_bulk_edit": 0,
"allow_in_quick_entry": 0, "allow_in_quick_entry": 0,
@ -1061,110 +1001,11 @@
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0, "allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 1,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fieldname": "apply_discount", "fieldname": "select_print_heading",
"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_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
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "company_address_section",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Company Address",
"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": "company_address",
"fieldtype": "Link", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
@ -1173,12 +1014,13 @@
"in_global_search": 0, "in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 0, "in_standard_filter": 0,
"label": "Company Address Name", "label": "Print Heading",
"length": 0, "length": 0,
"no_copy": 0, "no_copy": 0,
"options": "Address", "oldfieldname": "select_print_heading",
"oldfieldtype": "Select",
"options": "Print Heading",
"permlevel": 0, "permlevel": 0,
"precision": "",
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0, "print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
@ -1207,7 +1049,7 @@
"in_global_search": 0, "in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 0, "in_standard_filter": 0,
"label": "Offline POS Section", "label": "Offline POS Settings",
"length": 0, "length": 0,
"no_copy": 0, "no_copy": 0,
"permlevel": 0, "permlevel": 0,
@ -1389,6 +1231,40 @@
"translatable": 0, "translatable": 0,
"unique": 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_bulk_edit": 0,
"allow_in_quick_entry": 0, "allow_in_quick_entry": 0,
@ -1688,6 +1564,41 @@
"set_only_once": 0, "set_only_once": 0,
"translatable": 0, "translatable": 0,
"unique": 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
} }
], ],
"has_web_view": 0, "has_web_view": 0,
@ -1701,7 +1612,7 @@
"issingle": 0, "issingle": 0,
"istable": 0, "istable": 0,
"max_attachments": 0, "max_attachments": 0,
"modified": "2018-12-03 14:16:08.589778", "modified": "2018-12-13 13:36:22.045519",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "POS Profile", "name": "POS Profile",
@ -1749,11 +1660,11 @@
"quick_entry": 0, "quick_entry": 0,
"read_only": 0, "read_only": 0,
"read_only_onload": 0, "read_only_onload": 0,
"search_fields": "pos_profile_name", "search_fields": "",
"show_name_in_global_search": 0, "show_name_in_global_search": 0,
"sort_field": "modified", "sort_field": "modified",
"sort_order": "DESC", "sort_order": "DESC",
"title_field": "pos_profile_name", "title_field": "",
"track_changes": 0, "track_changes": 0,
"track_seen": 0, "track_seen": 0,
"track_views": 0 "track_views": 0

View File

@ -127,25 +127,26 @@ def pos_profile_query(doctype, txt, searchfield, start, page_len, filters):
'txt': '%%%s%%' % txt 'txt': '%%%s%%' % txt
} }
pos_profile = frappe.db.sql("""select pf.name, pf.pos_profile_name pos_profile = frappe.db.sql("""select pf.name
from from
`tabPOS Profile` pf, `tabPOS Profile User` pfu `tabPOS Profile` pf, `tabPOS Profile User` pfu
where where
pfu.parent = pf.name and pfu.user = %(user)s and pf.company = %(company)s 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) and pf.disabled = 0 limit %(start)s, %(page_len)s""", args)
if not pos_profile: if not pos_profile:
del args['user'] del args['user']
pos_profile = frappe.db.sql("""select pf.name, pf.pos_profile_name pos_profile = frappe.db.sql("""select pf.name
from from
`tabPOS Profile` pf left join `tabPOS Profile User` pfu `tabPOS Profile` pf left join `tabPOS Profile User` pfu
on on
pf.name = pfu.parent pf.name = pfu.parent
where where
ifnull(pfu.user, '') = '' and pf.company = %(company)s and ifnull(pfu.user, '') = ''
(pf.name like %(txt)s or pf.pos_profile_name like %(txt)s) and pf.company = %(company)s
and pf.name like %(txt)s
and pf.disabled = 0""", args) and pf.disabled = 0""", args)
return pos_profile return pos_profile

View File

@ -40,7 +40,6 @@ def make_pos_profile():
"expense_account": "_Test Account Cost for Goods Sold - _TC", "expense_account": "_Test Account Cost for Goods Sold - _TC",
"income_account": "Sales - _TC", "income_account": "Sales - _TC",
"name": "_Test POS Profile", "name": "_Test POS Profile",
"pos_profile_name": "_Test POS Profile",
"naming_series": "_T-POS Profile-", "naming_series": "_T-POS Profile-",
"selling_price_list": "_Test Price List", "selling_price_list": "_Test Price List",
"territory": "_Test Territory", "territory": "_Test Territory",

View File

@ -4726,7 +4726,7 @@
"istable": 0, "istable": 0,
"max_attachments": 0, "max_attachments": 0,
"menu_index": 0, "menu_index": 0,
"modified": "2018-11-13 19:55:58.018816", "modified": "2019-01-07 16:51:59.800081",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Purchase Invoice", "name": "Purchase Invoice",

View File

@ -206,6 +206,10 @@ class PurchaseInvoice(BuyingController):
stock_not_billed_account = self.get_company_default("stock_received_but_not_billed") stock_not_billed_account = self.get_company_default("stock_received_but_not_billed")
stock_items = self.get_stock_items() stock_items = self.get_stock_items()
asset_items = [d.is_fixed_asset for d in self.items if d.is_fixed_asset]
if len(asset_items) > 0:
asset_received_but_not_billed = self.get_company_default("asset_received_but_not_billed")
if self.update_stock: if self.update_stock:
self.validate_item_code() self.validate_item_code()
self.validate_warehouse() self.validate_warehouse()
@ -226,7 +230,8 @@ class PurchaseInvoice(BuyingController):
item.expense_account = warehouse_account[item.warehouse]["account"] item.expense_account = warehouse_account[item.warehouse]["account"]
else: else:
item.expense_account = stock_not_billed_account item.expense_account = stock_not_billed_account
elif item.is_fixed_asset and d.pr_detail:
item.expense_account = asset_received_but_not_billed
elif not item.expense_account and for_validate: elif not item.expense_account and for_validate:
throw(_("Expense account is mandatory for item {0}").format(item.item_code or item.item_name)) throw(_("Expense account is mandatory for item {0}").format(item.item_code or item.item_name))
@ -360,7 +365,10 @@ class PurchaseInvoice(BuyingController):
def get_gl_entries(self, warehouse_account=None): def get_gl_entries(self, warehouse_account=None):
self.auto_accounting_for_stock = erpnext.is_perpetual_inventory_enabled(self.company) self.auto_accounting_for_stock = erpnext.is_perpetual_inventory_enabled(self.company)
if self.auto_accounting_for_stock:
self.stock_received_but_not_billed = self.get_company_default("stock_received_but_not_billed") self.stock_received_but_not_billed = self.get_company_default("stock_received_but_not_billed")
else:
self.stock_received_but_not_billed = None
self.expenses_included_in_valuation = self.get_company_default("expenses_included_in_valuation") self.expenses_included_in_valuation = self.get_company_default("expenses_included_in_valuation")
self.negative_expense_to_be_booked = 0.0 self.negative_expense_to_be_booked = 0.0
gl_entries = [] gl_entries = []
@ -830,6 +838,10 @@ class PurchaseInvoice(BuyingController):
return return
tax_withholding_details = get_party_tax_withholding_details(self) tax_withholding_details = get_party_tax_withholding_details(self)
if not tax_withholding_details:
return
accounts = [] accounts = []
for d in self.taxes: for d in self.taxes:
if d.account_head == tax_withholding_details.get("account_head"): if d.account_head == tax_withholding_details.get("account_head"):
@ -839,6 +851,12 @@ class PurchaseInvoice(BuyingController):
if not accounts or tax_withholding_details.get("account_head") not in accounts: if not accounts or tax_withholding_details.get("account_head") not in accounts:
self.append("taxes", tax_withholding_details) 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 # calculate totals again after applying TDS
self.calculate_taxes_and_totals() self.calculate_taxes_and_totals()

View File

@ -1,5 +1,6 @@
{ {
"allow_copy": 0, "allow_copy": 0,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0, "allow_guest_to_view": 0,
"allow_import": 0, "allow_import": 0,
"allow_rename": 0, "allow_rename": 0,
@ -14,6 +15,7 @@
"fields": [ "fields": [
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 1, "bold": 1,
"collapsible": 0, "collapsible": 0,
@ -47,6 +49,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -76,6 +79,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -108,6 +112,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 1, "collapsible": 1,
@ -139,6 +144,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -173,6 +179,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -204,6 +211,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -236,6 +244,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -266,6 +275,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -297,6 +307,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 1, "bold": 1,
"collapsible": 0, "collapsible": 0,
@ -329,6 +340,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -360,6 +372,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -392,6 +405,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -421,6 +435,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -453,6 +468,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -484,6 +500,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -515,6 +532,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -544,6 +562,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -575,6 +594,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -606,6 +626,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -634,10 +655,12 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -667,6 +690,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -698,6 +722,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -727,6 +752,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 1, "bold": 1,
"collapsible": 0, "collapsible": 0,
@ -760,6 +786,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -793,6 +820,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -822,6 +850,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -855,6 +884,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -888,6 +918,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -919,6 +950,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -949,6 +981,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -981,6 +1014,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1013,6 +1047,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1043,6 +1078,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1075,6 +1111,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1107,6 +1144,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 1, "collapsible": 1,
@ -1138,6 +1176,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1169,6 +1208,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1200,6 +1240,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1230,6 +1271,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1262,6 +1304,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1293,6 +1336,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1326,6 +1370,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1358,6 +1403,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1391,6 +1437,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1423,6 +1470,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1454,6 +1502,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1485,6 +1534,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1516,6 +1566,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1546,6 +1597,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1581,6 +1633,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1610,6 +1663,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1641,6 +1695,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1678,6 +1733,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 1, "collapsible": 1,
@ -1709,6 +1765,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1742,6 +1799,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 1, "allow_on_submit": 1,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1774,6 +1832,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1805,6 +1864,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1835,6 +1895,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1867,6 +1928,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1899,6 +1961,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1929,6 +1992,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1960,6 +2024,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1992,6 +2057,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -2026,6 +2092,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -2059,6 +2126,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -2092,6 +2160,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -2125,6 +2194,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -2157,6 +2227,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -2189,6 +2260,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -2218,6 +2290,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -2249,6 +2322,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -2282,6 +2356,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -2315,6 +2390,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -2347,6 +2423,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -2380,6 +2457,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 1, "allow_on_submit": 1,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -2410,6 +2488,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -2442,6 +2521,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 1, "allow_on_submit": 1,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -2473,6 +2553,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -2504,6 +2585,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 1, "allow_on_submit": 1,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -2544,7 +2626,7 @@
"issingle": 0, "issingle": 0,
"istable": 1, "istable": 1,
"max_attachments": 0, "max_attachments": 0,
"modified": "2018-10-04 09:05:43.166721", "modified": "2019-01-07 16:52:00.749414",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Purchase Invoice Item", "name": "Purchase Invoice Item",

View File

@ -5644,7 +5644,7 @@
"istable": 0, "istable": 0,
"max_attachments": 0, "max_attachments": 0,
"menu_index": 0, "menu_index": 0,
"modified": "2018-11-12 20:01:21.289303", "modified": "2019-01-07 16:51:53.914523",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Sales Invoice", "name": "Sales Invoice",

View File

@ -324,7 +324,8 @@ class SalesInvoice(SellingController):
return { return {
"print_format": print_format, "print_format": print_format,
"allow_edit_rate": pos.get("allow_user_to_edit_rate"), "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): def update_time_sheet(self, sales_invoice):

View File

@ -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 # License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals from __future__ import unicode_literals
@ -763,6 +763,20 @@ class TestSalesInvoice(unittest.TestCase):
frappe.db.sql("delete from `tabPOS Profile`") 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): def test_sales_invoice_gl_entry_with_perpetual_inventory_no_item_code(self):
set_perpetual_inventory() set_perpetual_inventory()
@ -1524,9 +1538,9 @@ def create_sales_invoice(**args):
"warehouse": args.warehouse or "_Test Warehouse - _TC", "warehouse": args.warehouse or "_Test Warehouse - _TC",
"qty": args.qty or 1, "qty": args.qty or 1,
"rate": args.rate or 100, "rate": args.rate or 100,
"income_account": "Sales - _TC", "income_account": args.income_account or "Sales - _TC",
"expense_account": "Cost of Goods Sold - _TC", "expense_account": args.expense_account or "Cost of Goods Sold - _TC",
"cost_center": "_Test Cost Center - _TC", "cost_center": args.cost_center or "_Test Cost Center - _TC",
"serial_no": args.serial_no "serial_no": args.serial_no
}) })

View File

@ -1,5 +1,6 @@
{ {
"allow_copy": 0, "allow_copy": 0,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0, "allow_guest_to_view": 0,
"allow_import": 0, "allow_import": 0,
"allow_rename": 0, "allow_rename": 0,
@ -15,6 +16,7 @@
"fields": [ "fields": [
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -45,6 +47,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 1, "bold": 1,
"collapsible": 0, "collapsible": 0,
@ -78,6 +81,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -107,6 +111,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -139,6 +144,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -169,6 +175,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 1, "collapsible": 1,
@ -200,6 +207,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -234,6 +242,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -264,6 +273,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -296,6 +306,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -327,6 +338,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -357,6 +369,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 1, "bold": 1,
"collapsible": 0, "collapsible": 0,
@ -389,6 +402,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -420,6 +434,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -449,6 +464,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -481,6 +497,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -512,6 +529,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -543,6 +561,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -573,6 +592,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -606,6 +626,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -639,6 +660,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 1, "collapsible": 1,
@ -670,6 +692,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -703,6 +726,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -735,6 +759,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -768,6 +793,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -798,6 +824,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -832,6 +859,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -860,10 +888,12 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -897,6 +927,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -926,6 +957,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 1, "bold": 1,
"collapsible": 0, "collapsible": 0,
@ -959,6 +991,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -992,6 +1025,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1021,6 +1055,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1054,6 +1089,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1087,6 +1123,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1118,6 +1155,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1148,6 +1186,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1180,6 +1219,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1212,6 +1252,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1242,6 +1283,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1274,6 +1316,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1306,6 +1349,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 1, "collapsible": 1,
@ -1338,6 +1382,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1369,6 +1414,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 1, "collapsible": 1,
@ -1399,6 +1445,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1434,6 +1481,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1466,6 +1514,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1495,6 +1544,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1531,6 +1581,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 1, "collapsible": 1,
@ -1562,6 +1613,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1595,6 +1647,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 1, "allow_on_submit": 1,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1627,6 +1680,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1659,6 +1713,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1689,6 +1744,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1721,6 +1777,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1753,6 +1810,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 1, "collapsible": 1,
@ -1784,6 +1842,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1816,6 +1875,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1847,6 +1907,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1877,6 +1938,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1909,6 +1971,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 1, "collapsible": 1,
@ -1941,6 +2004,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1974,6 +2038,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -2006,6 +2071,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -2039,6 +2105,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -2070,6 +2137,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -2099,6 +2167,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -2130,6 +2199,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -2162,6 +2232,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -2196,6 +2267,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -2228,6 +2300,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -2260,6 +2333,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 1, "allow_on_submit": 1,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -2293,6 +2367,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 1, "allow_on_submit": 1,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -2325,6 +2400,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 1, "collapsible": 1,
@ -2356,6 +2432,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -2389,6 +2466,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -2421,6 +2499,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -2451,6 +2530,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -2484,6 +2564,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -2516,6 +2597,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -2548,6 +2630,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -2579,6 +2662,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -2611,6 +2695,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -2641,6 +2726,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 1, "allow_on_submit": 1,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -2680,7 +2766,7 @@
"issingle": 0, "issingle": 0,
"istable": 1, "istable": 1,
"max_attachments": 0, "max_attachments": 0,
"modified": "2018-08-29 15:22:58.455304", "modified": "2019-01-07 16:51:55.018091",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Sales Invoice Item", "name": "Sales Invoice Item",

View File

@ -24,6 +24,7 @@ def get_party_tax_withholding_details(ref_doc):
.format(tax_withholding_category, ref_doc.company)) .format(tax_withholding_category, ref_doc.company))
tds_amount = get_tds_amount(ref_doc, tax_details, fy) tds_amount = get_tds_amount(ref_doc, tax_details, fy)
tax_row = get_tax_row(tax_details, tds_amount) tax_row = get_tax_row(tax_details, tds_amount)
return tax_row return tax_row
def get_tax_withholding_details(tax_withholding_category, fiscal_year, company): def get_tax_withholding_details(tax_withholding_category, fiscal_year, company):
@ -62,46 +63,64 @@ def get_tax_row(tax_details, tds_amount):
def get_tds_amount(ref_doc, tax_details, fiscal_year_details): def get_tds_amount(ref_doc, tax_details, fiscal_year_details):
fiscal_year, year_start_date, year_end_date = fiscal_year_details fiscal_year, year_start_date, year_end_date = fiscal_year_details
tds_amount = 0 tds_amount = 0
tds_deducted = 0
def _get_tds(): def _get_tds(amount):
tds_amount = 0 if amount <= 0:
if not tax_details.threshold or ref_doc.net_total >= tax_details.threshold: return 0
tds_amount = ref_doc.net_total * tax_details.rate / 100
return tds_amount return amount * tax_details.rate / 100
if tax_details.cumulative_threshold:
entries = frappe.db.sql(""" entries = frappe.db.sql("""
select voucher_no, credit select voucher_no, credit
from `tabGL Entry` from `tabGL Entry`
where party=%s and fiscal_year=%s and credit > 0 where party=%s and fiscal_year=%s and credit > 0
""", (ref_doc.supplier, fiscal_year), as_dict=1) """, (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] vouchers = [d.voucher_no for d in entries]
vouchers += get_advance_vouchers(ref_doc.supplier, fiscal_year) advance_vouchers = get_advance_vouchers(ref_doc.supplier, fiscal_year)
tds_deducted = 0 tds_vouchers = vouchers + advance_vouchers
if vouchers:
tds_deducted = flt(frappe.db.sql(""" if tds_vouchers:
select sum(credit) tds_deducted = frappe.db.sql("""
from `tabGL Entry` SELECT sum(credit) FROM `tabGL Entry`
where account=%s and fiscal_year=%s and credit > 0 WHERE
and voucher_no in ({0}) account=%s and fiscal_year=%s and credit > 0
""".format(', '.join(["'%s'" % d for d in vouchers])), and voucher_no in ({0})""". format(','.join(['%s'] * len(tds_vouchers))),
(tax_details.account_head, fiscal_year))[0][0]) ((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) 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 \ if ((tax_details.get('threshold', 0) and supplier_credit_amount >= tax_details.threshold)
+ flt(ref_doc.net_total) - debit_note_amount or (tax_details.get('cumulative_threshold', 0) and supplier_credit_amount >= tax_details.cumulative_threshold)):
if total_invoiced_amount >= tax_details.cumulative_threshold: tds_amount = _get_tds(supplier_credit_amount)
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()
return tds_amount return tds_amount
@ -114,7 +133,7 @@ def get_advance_vouchers(supplier, fiscal_year=None, company=None, from_date=Non
select distinct voucher_no select distinct voucher_no
from `tabGL Entry` from `tabGL Entry`
where party=%s and %s and debit > 0 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): def get_debit_note_amount(supplier, year_start_date, year_end_date, company=None):
condition = "" condition = ""

View File

@ -6,6 +6,7 @@ from __future__ import unicode_literals
import frappe import frappe
import unittest import unittest
from frappe.utils import today from frappe.utils import today
from erpnext.accounts.utils import get_fiscal_year
test_dependencies = ["Supplier Group"] test_dependencies = ["Supplier Group"]
@ -14,65 +15,105 @@ class TestTaxWithholdingCategory(unittest.TestCase):
def setUpClass(self): def setUpClass(self):
# create relevant supplier, etc # create relevant supplier, etc
create_records() create_records()
create_tax_with_holding_category()
def test_single_threshold_tds(self): def test_cumulative_threshold_tds(self):
frappe.db.set_value("Supplier", "Test TDS Supplier", "tax_withholding_category", "TDS - 194D - Individual") frappe.db.set_value("Supplier", "Test TDS Supplier", "tax_withholding_category", "Cumulative Threshold TDS")
pi = create_purchase_invoice() 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() pi.submit()
self.assertEqual(pi.taxes_and_charges_deducted, 800) # assert equal tax deduction on total invoice amount uptil now
self.assertEqual(pi.grand_total, 15200) 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 # check gl entry for the purchase invoice
gl_entries = frappe.db.get_all('GL Entry', filters={'voucher_no': pi.name}, fields=["*"]) gl_entries = frappe.db.get_all('GL Entry', filters={'voucher_no': pi.name}, fields=["*"])
self.assertEqual(len(gl_entries), 3) self.assertEqual(len(gl_entries), 3)
for d in gl_entries: for d in gl_entries:
if d.account == pi.credit_to: 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"): 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"): elif d.account == pi.taxes[0].get("account_head"):
self.assertEqual(d.credit, 800) self.assertEqual(d.credit, 2000)
else: else:
raise ValueError("Account head does not match.") raise ValueError("Account head does not match.")
# delete purchase invoice to avoid it interefering in other tests pi = create_purchase_invoice(supplier = "Test TDS Supplier1")
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() pi.submit()
invoices.append(pi) invoices.append(pi)
# create another invoice whose total when added to previously created invoice, # TDS amount is 1000 because in previous invoices it's already deducted
# surpasses cumulative threshhold self.assertEqual(pi.taxes_and_charges_deducted, 1000)
pi = create_purchase_invoice()
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)
# delete invoices to avoid clashing # delete invoices to avoid clashing
for d in invoices: for d in invoices:
d.cancel() d.cancel()
frappe.delete_doc("Purchase Invoice", d.name) 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 # return sales invoice doc object
item = frappe.get_doc('Item', {'item_name': 'TDS Item'}) item = frappe.get_doc('Item', {'item_name': 'TDS Item'})
args = frappe._dict(args)
pi = frappe.get_doc({ pi = frappe.get_doc({
"doctype": "Purchase Invoice", "doctype": "Purchase Invoice",
"posting_date": today(), "posting_date": today(),
"apply_tds": 1, "apply_tds": 1,
"supplier": frappe.get_doc('Supplier', {"supplier_name": "Test TDS Supplier"}).name, "supplier": args.supplier,
"company": '_Test Company', "company": '_Test Company',
"taxes_and_charges": "", "taxes_and_charges": "",
"currency": "INR", "currency": "INR",
@ -81,8 +122,8 @@ def create_purchase_invoice(qty=1):
"items": [{ "items": [{
'doctype': 'Purchase Invoice Item', 'doctype': 'Purchase Invoice Item',
'item_code': item.name, 'item_code': item.name,
'qty': qty, 'qty': args.qty or 1,
'rate': 16000, 'rate': args.rate or 10000,
'cost_center': 'Main - _TC', 'cost_center': 'Main - _TC',
'expense_account': 'Stock Received But Not Billed - _TC' 'expense_account': 'Stock Received But Not Billed - _TC'
}] }]
@ -92,20 +133,73 @@ def create_purchase_invoice(qty=1):
return pi return pi
def create_records(): def create_records():
# create a new supplier # 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({ frappe.get_doc({
"supplier_group": "_Test Supplier Group", "supplier_group": "_Test Supplier Group",
"supplier_name": "Test TDS Supplier", "supplier_name": name,
"doctype": "Supplier", "doctype": "Supplier",
"tax_withholding_category": "TDS - 194D - Individual"
}).insert() }).insert()
# create an item # create an item
if not frappe.db.exists('Item', "TDS Item"):
frappe.get_doc({ frappe.get_doc({
"doctype": "Item", "doctype": "Item",
"item_code": "TDS Item", "item_code": "TDS Item",
"item_name": "TDS Item", "item_name": "TDS Item",
"item_group": "All Item Groups", "item_group": "All Item Groups",
"company": "_Test Company",
"is_stock_item": 0, "is_stock_item": 0,
}).insert() }).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()

View File

@ -1135,16 +1135,18 @@ erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
}, },
apply_category: function() { apply_category: function() {
var me = this; frappe.db.get_value("Item Group", {lft: 1, is_group: 1}, "name", (r) => {
category = this.selected_item_group || "All Item Groups"; category = this.selected_item_group || r.name;
if(category == 'All Item Groups') { if(category == r.name) {
return this.item_data return this.item_data
} else { } else {
return this.item_data.filter(function(element, index, array){ return this.item_data.filter(function(element, index, array){
return element.item_group == category; return element.item_group == category;
}); });
} }
})
}, },
bind_items_event: function() { bind_items_event: function() {

View File

@ -5,7 +5,7 @@ from __future__ import unicode_literals
import frappe, erpnext import frappe, erpnext
from frappe import _, msgprint, scrub 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.model.utils import get_fetch_values
from frappe.utils import (add_days, getdate, formatdate, date_diff, from frappe.utils import (add_days, getdate, formatdate, date_diff,
add_years, get_timestamp, nowdate, flt, add_months, get_last_day) add_years, get_timestamp, nowdate, flt, add_months, get_last_day)
@ -151,10 +151,7 @@ def get_default_price_list(party):
def set_price_list(out, party, party_type, given_price_list): def set_price_list(out, party, party_type, given_price_list):
# price list # price list
price_list = filter(None, get_user_permissions() price_list = get_permitted_documents('Price List')
.get("Price List", {})
.get("docs", []))
price_list = list(price_list)
if price_list: if price_list:
price_list = price_list[0] price_list = price_list[0]
@ -457,7 +454,7 @@ def get_timeline_data(doctype, name):
return out return out
def get_dashboard_info(party_type, party): def get_dashboard_info(party_type, party, loyalty_program=None):
current_fiscal_year = get_fiscal_year(nowdate(), as_dict=True) current_fiscal_year = get_fiscal_year(nowdate(), as_dict=True)
doctype = "Sales Invoice" if party_type=="Customer" else "Purchase Invoice" doctype = "Sales Invoice" if party_type=="Customer" else "Purchase Invoice"
@ -479,6 +476,19 @@ def get_dashboard_info(party_type, party):
fields=["company", "sum(grand_total) as grand_total", "sum(base_grand_total) as base_grand_total"] fields=["company", "sum(grand_total) as grand_total", "sum(base_grand_total) as base_grand_total"]
) )
loyalty_point_details = []
if party_type == "Customer":
loyalty_point_details = frappe._dict(frappe.get_all("Loyalty Point Entry",
filters={
'customer': party,
'expiry_date': ('>=', getdate()),
},
group_by="company",
fields=["company", "sum(loyalty_points) as loyalty_points"],
as_list =1
))
company_wise_billing_this_year = frappe._dict() company_wise_billing_this_year = frappe._dict()
for d in company_wise_grand_total: for d in company_wise_grand_total:
@ -506,12 +516,18 @@ def get_dashboard_info(party_type, party):
total_unpaid = flt(company_wise_total_unpaid.get(d.company)) total_unpaid = flt(company_wise_total_unpaid.get(d.company))
if loyalty_point_details:
loyalty_points = loyalty_point_details.get(d.company)
info = {} info = {}
info["billing_this_year"] = flt(billing_this_year) if billing_this_year else 0 info["billing_this_year"] = flt(billing_this_year) if billing_this_year else 0
info["currency"] = party_account_currency info["currency"] = party_account_currency
info["total_unpaid"] = flt(total_unpaid) if total_unpaid else 0 info["total_unpaid"] = flt(total_unpaid) if total_unpaid else 0
info["company"] = d.company info["company"] = d.company
if party_type == "Customer" and loyalty_point_details:
info["loyalty_points"] = loyalty_points
if party_type == "Supplier": if party_type == "Supplier":
info["total_unpaid"] = -1 * info["total_unpaid"] info["total_unpaid"] = -1 * info["total_unpaid"]

View File

@ -107,6 +107,11 @@ frappe.query_reports["Accounts Receivable"] = {
"label": __("Show PDC in Print"), "label": __("Show PDC in Print"),
"fieldtype": "Check", "fieldtype": "Check",
}, },
{
"fieldname":"based_on_payment_terms",
"label": __("Based On Payment Terms"),
"fieldtype": "Check",
},
{ {
"fieldname":"tax_id", "fieldname":"tax_id",
"label": __("Tax Id"), "label": __("Tax Id"),

View File

@ -4,7 +4,7 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import frappe, erpnext import frappe, erpnext
from frappe import _, scrub 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): class ReceivablePayableReport(object):
def __init__(self, filters=None): def __init__(self, filters=None):
@ -32,6 +32,15 @@ class ReceivablePayableReport(object):
columns += [_(args.get("party_type")) + ":Link/" + args.get("party_type") + ":200"] columns += [_(args.get("party_type")) + ":Link/" + args.get("party_type") + ":200"]
if args.get("party_type") == 'Customer':
columns.append({
"label": _("Customer Contact"),
"fieldtype": "Link",
"fieldname": "contact",
"options":"Contact",
"width": 100
})
if party_naming_by == "Naming Series": if party_naming_by == "Naming Series":
columns += [args.get("party_type") + " Name::110"] columns += [args.get("party_type") + " Name::110"]
@ -57,6 +66,21 @@ class ReceivablePayableReport(object):
credit_or_debit_note = "Credit Note" if args.get("party_type") == "Customer" else "Debit Note" 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"): for label in ("Invoiced Amount", "Paid Amount", credit_or_debit_note, "Outstanding Amount"):
columns.append({ columns.append({
"label": label, "label": label,
@ -97,12 +121,6 @@ class ReceivablePayableReport(object):
"options": "Currency", "options": "Currency",
"width": 100 "width": 100
}, },
{
"fieldname": "pdc/lc_date",
"label": _("PDC/LC Date"),
"fieldtype": "Date",
"width": 110
},
{ {
"fieldname": "pdc/lc_ref", "fieldname": "pdc/lc_ref",
"label": _("PDC/LC Ref"), "label": _("PDC/LC Ref"),
@ -113,14 +131,14 @@ class ReceivablePayableReport(object):
"fieldname": "pdc/lc_amount", "fieldname": "pdc/lc_amount",
"label": _("PDC/LC Amount"), "label": _("PDC/LC Amount"),
"fieldtype": "Currency", "fieldtype": "Currency",
"options": "Currency", "options": "currency",
"width": 130 "width": 130
}, },
{ {
"fieldname": "remaining_balance", "fieldname": "remaining_balance",
"label": _("Remaining Balance"), "label": _("Remaining Balance"),
"fieldtype": "Currency", "fieldtype": "Currency",
"options": "Currency", "options": "currency",
"width": 130 "width": 130
}] }]
@ -151,53 +169,154 @@ class ReceivablePayableReport(object):
def get_data(self, party_naming_by, args): def get_data(self, party_naming_by, args):
from erpnext.accounts.utils import get_currency_precision from erpnext.accounts.utils import get_currency_precision
currency_precision = get_currency_precision() or 2 self.currency_precision = get_currency_precision() or 2
dr_or_cr = "debit" if args.get("party_type") == "Customer" else "credit" 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")) future_vouchers = self.get_entries_after(self.filters.report_date, args.get("party_type"))
if not self.filters.get("company"): if not self.filters.get("company"):
self.filters["company"] = frappe.db.get_single_value('Global Defaults', 'default_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")) return_entries = self.get_return_entries(args.get("party_type"))
data = [] 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")) gl_entries_data = self.get_entries_till(self.filters.report_date, args.get("party_type"))
if gl_entries_data: if gl_entries_data:
voucher_nos = [d.voucher_no for d in gl_entries_data] or [] voucher_nos = [d.voucher_no for d in gl_entries_data] or []
dn_details = get_dn_details(args.get("party_type"), voucher_nos) 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: for gle in gl_entries_data:
if self.is_receivable_or_payable(gle, dr_or_cr, future_vouchers): if self.is_receivable_or_payable(gle, self.dr_or_cr, future_vouchers):
outstanding_amount, credit_note_amount = self.get_outstanding_amount(gle, outstanding_amount, credit_note_amount, payment_amount = self.get_outstanding_amount(
self.filters.report_date, dr_or_cr, return_entries, currency_precision) gle,self.filters.report_date, self.dr_or_cr, return_entries)
if abs(outstanding_amount) > 0.1/10**currency_precision:
temp_outstanding_amt = outstanding_amount
temp_credit_note_amt = credit_note_amount
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)
term_outstanding_amount = d.payment_term_amount - d.payment_amount
# 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)
term_outstanding_amount -= d.credit_note_amount
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:
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] row = [gle.posting_date, gle.party]
# customer / supplier name # customer / supplier name
if party_naming_by == "Naming Series": if party_naming_by == "Naming Series":
row += [self.get_party_name(gle.party_type, gle.party)] row += [self.get_party_name(gle.party_type, gle.party)]
if args.get("party_type") == 'Customer':
row += [self.get_customer_contact(gle.party_type, gle.party)]
# get due date # get due date
due_date = voucher_details.get(gle.voucher_no, {}).get("due_date", "") if not due_date:
bill_date = voucher_details.get(gle.voucher_no, {}).get("bill_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] row += [gle.voucher_type, gle.voucher_no, due_date]
# get supplier bill details # get supplier bill details
if args.get("party_type") == "Supplier": if args.get("party_type") == "Supplier":
row += [ row += [
voucher_details.get(gle.voucher_no, {}).get("bill_no", ""), self.voucher_details.get(gle.voucher_no, {}).get("bill_no", ""),
voucher_details.get(gle.voucher_no, {}).get("bill_date", "") self.voucher_details.get(gle.voucher_no, {}).get("bill_date", "")
] ]
# invoiced and paid amounts # invoiced and paid amounts
invoiced_amount = gle.get(dr_or_cr) if (gle.get(dr_or_cr) > 0) else 0 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 paid_amt = invoiced_amount - outstanding_amount - credit_note_amount
row += [invoiced_amount, paid_amt, credit_note_amount, outstanding_amount] row += [invoiced_amount, paid_amt, credit_note_amount, outstanding_amount]
@ -226,32 +345,29 @@ class ReceivablePayableReport(object):
if self.filters.get(scrub(args.get("party_type"))): if self.filters.get(scrub(args.get("party_type"))):
row.append(gle.account_currency) row.append(gle.account_currency)
else: else:
row.append(company_currency) row.append(self.company_currency)
pdc = pdc_details.get((gle.voucher_no, gle.party), {}) remaining_balance = outstanding_amount - flt(pdc_amount)
pdc_details = ", ".join(pdc_details)
remaining_balance = outstanding_amount - flt(pdc.get("pdc_amount")) row += [pdc_details, pdc_amount, remaining_balance]
row += [pdc.get("pdc_date"), pdc.get("pdc_ref"),
flt(pdc.get("pdc_amount")), remaining_balance]
if args.get('party_type') == 'Customer': if args.get('party_type') == 'Customer':
# customer LPO # customer LPO
row += [voucher_details.get(gle.voucher_no, {}).get("po_no")] row += [self.voucher_details.get(gle.voucher_no, {}).get("po_no")]
# Delivery Note # Delivery Note
row += [voucher_details.get(gle.voucher_no, {}).get("delivery_note")] row += [self.voucher_details.get(gle.voucher_no, {}).get("delivery_note")]
# customer territory / supplier group # customer territory / supplier group
if args.get("party_type") == "Customer": if args.get("party_type") == "Customer":
row += [self.get_territory(gle.party), self.get_customer_group(gle.party), row += [self.get_territory(gle.party), self.get_customer_group(gle.party),
voucher_details.get(gle.voucher_no, {}).get("sales_person")] self.voucher_details.get(gle.voucher_no, {}).get("sales_person")]
if args.get("party_type") == "Supplier": if args.get("party_type") == "Supplier":
row += [self.get_supplier_group(gle.party)] row += [self.get_supplier_group(gle.party)]
row.append(gle.remarks) row.append(gle.remarks)
data.append(row)
return data return row
def get_entries_after(self, report_date, party_type): def get_entries_after(self, report_date, party_type):
# returns a distinct list # returns a distinct list
@ -280,29 +396,32 @@ class ReceivablePayableReport(object):
doctype = "Sales Invoice" if party_type=="Customer" else "Purchase Invoice" 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})] 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 payment_amount, credit_note_amount = 0.0, 0.0
reverse_dr_or_cr = "credit" if dr_or_cr=="debit" else "debit" 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): 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: 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: if e.voucher_no not in return_entries:
payment_amount += amount payment_amount += amount
else: else:
credit_note_amount += amount credit_note_amount += amount
outstanding_amount = (flt((flt(gle.get(dr_or_cr), currency_precision) outstanding_amount = (flt((flt(gle.get(dr_or_cr), self.currency_precision)
- flt(gle.get(reverse_dr_or_cr), currency_precision) - flt(gle.get(reverse_dr_or_cr), self.currency_precision)
- payment_amount - credit_note_amount), 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): 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 "" return self.get_party_map(party_type).get(party_name, {}).get("customer_name" if party_type == "Customer" else "supplier_name") or ""
def get_customer_contact(self, party_type, party_name):
return self.get_party_map(party_type).get(party_name, {}).get("customer_primary_contact")
def get_territory(self, party_name): def get_territory(self, party_name):
return self.get_party_map("Customer").get(party_name, {}).get("territory") or "" return self.get_party_map("Customer").get(party_name, {}).get("territory") or ""
@ -315,7 +434,7 @@ class ReceivablePayableReport(object):
def get_party_map(self, party_type): def get_party_map(self, party_type):
if not hasattr(self, "party_map"): if not hasattr(self, "party_map"):
if party_type == "Customer": if party_type == "Customer":
select_fields = "name, customer_name, territory, customer_group" select_fields = "name, customer_name, territory, customer_group, customer_primary_contact"
elif party_type == "Supplier": elif party_type == "Supplier":
select_fields = "name, supplier_name, supplier_group" select_fields = "name, supplier_name, supplier_group"
@ -432,6 +551,31 @@ class ReceivablePayableReport(object):
.get(against_voucher_type, {})\ .get(against_voucher_type, {})\
.get(against_voucher, []) .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): def get_chart_data(self, columns, data):
ageing_columns = columns[self.ageing_col_idx_start : self.ageing_col_idx_start+4] ageing_columns = columns[self.ageing_col_idx_start : self.ageing_col_idx_start+4]
@ -479,12 +623,11 @@ def get_ageing_data(first_range, second_range, third_range, age_as_on, entry_dat
def get_pdc_details(party_type, report_date): def get_pdc_details(party_type, report_date):
pdc_details = frappe._dict() pdc_details = frappe._dict()
pdc_via_pe = frappe.db.sql("""
for pdc in frappe.db.sql("""
select select
pref.reference_name as invoice_no, pent.party, pent.party_type, 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, pent.posting_date as pdc_date, ifnull(pref.allocated_amount,0) as pdc_amount,
GROUP_CONCAT(pent.reference_no SEPARATOR ', ') as pdc_ref pent.reference_no as pdc_ref
from from
`tabPayment Entry` as pent inner join `tabPayment Entry Reference` as pref `tabPayment Entry` as pent inner join `tabPayment Entry Reference` as pref
on on
@ -492,19 +635,22 @@ def get_pdc_details(party_type, report_date):
where where
pent.docstatus < 2 and pent.posting_date > %s pent.docstatus < 2 and pent.posting_date > %s
and pent.party_type = %s and pent.party_type = %s
group by pent.party, pref.reference_name""", (report_date, party_type), as_dict=1): """, (report_date, party_type), as_dict=1)
pdc_details.setdefault((pdc.invoice_no, pdc.party), pdc)
for pdc in pdc_via_pe:
pdc_details.setdefault((pdc.invoice_no, pdc.party), []).append(pdc)
if scrub(party_type): if scrub(party_type):
amount_field = ("jea.debit_in_account_currency" amount_field = ("jea.debit_in_account_currency"
if party_type == 'Supplier' else "jea.credit_in_account_currency") if party_type == 'Supplier' else "jea.credit_in_account_currency")
else: else:
amount_field = "jea.debit + jea.credit" amount_field = "jea.debit + jea.credit"
for pdc in frappe.db.sql(""" pdc_via_je = frappe.db.sql("""
select select
jea.reference_name as invoice_no, jea.party, jea.party_type, 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, je.posting_date as pdc_date, ifnull({0},0) as pdc_amount,
GROUP_CONCAT(je.cheque_no SEPARATOR ', ') as pdc_ref je.cheque_no as pdc_ref
from from
`tabJournal Entry` as je inner join `tabJournal Entry Account` as jea `tabJournal Entry` as je inner join `tabJournal Entry Account` as jea
on on
@ -512,16 +658,10 @@ def get_pdc_details(party_type, report_date):
where where
je.docstatus < 2 and je.posting_date > %s je.docstatus < 2 and je.posting_date > %s
and jea.party_type = %s and jea.party_type = %s
group by jea.party, jea.reference_name""".format(amount_field), (report_date, party_type), as_dict=1): """.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) for pdc in pdc_via_je:
pdc_details[key]["pdc_amount"] += pdc.pdc_amount pdc_details.setdefault((pdc.invoice_no, pdc.party), []).append(pdc)
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)
return pdc_details return pdc_details

View File

@ -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][7:9])
self.assertEqual(expected_data[1], report[1][1][7:9])
self.assertEqual(expected_data[2], report[1][2][7:9])
make_payment(name)
report = execute(filters)
expected_data_after_payment = [[100,50], [100,20]]
self.assertEqual(expected_data_after_payment[0], report[1][0][7:9])
self.assertEqual(expected_data_after_payment[1], report[1][1][7:9])
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][7:12])
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)

View File

@ -35,16 +35,22 @@ def get_conditions(filters):
def get_entries(filters): def get_entries(filters):
conditions = get_conditions(filters) conditions = get_conditions(filters)
journal_entries = frappe.db.sql("""select "Journal Entry", jv.name, jv.posting_date, journal_entries = frappe.db.sql("""SELECT
jv.cheque_no, jv.clearance_date, jvd.against_account, (jvd.debit - jvd.credit) "Journal Entry", jv.name, jv.posting_date, jv.cheque_no, jv.clearance_date, jvd.against_account,
from `tabJournal Entry Account` jvd, `tabJournal Entry` jv if((jvd.debit - jvd.credit) < 0, (jvd.debit - jvd.credit) * -1, (jvd.debit - jvd.credit))
where jvd.parent = jv.name and jv.docstatus=1 and jvd.account = %(account)s {0} FROM
`tabJournal Entry Account` jvd, `tabJournal Entry` jv
WHERE
jvd.parent = jv.name and jv.docstatus=1 and jvd.account = %(account)s {0}
order by posting_date DESC, jv.name DESC""".format(conditions), filters, as_list=1) order by posting_date DESC, jv.name DESC""".format(conditions), filters, as_list=1)
payment_entries = frappe.db.sql("""select "Payment Entry", name, posting_date, payment_entries = frappe.db.sql("""SELECT
reference_no, clearance_date, party, if(paid_from=%(account)s, paid_amount, received_amount) "Payment Entry", name, posting_date, reference_no, clearance_date, party,
from `tabPayment Entry` if(paid_from=%(account)s, paid_amount, received_amount)
where docstatus=1 and (paid_from = %(account)s or paid_to = %(account)s) {0} FROM
`tabPayment Entry`
WHERE
docstatus=1 and (paid_from = %(account)s or paid_to = %(account)s) {0}
order by posting_date DESC, name DESC""".format(conditions), filters, as_list=1) order by posting_date DESC, name DESC""".format(conditions), filters, as_list=1)
return sorted(journal_entries + payment_entries, key=lambda k: k[2] or getdate(nowdate())) return sorted(journal_entries + payment_entries, key=lambda k: k[2] or getdate(nowdate()))

View File

@ -213,7 +213,7 @@ def prepare_data(accounts, balance_must_be, period_list, company_currency):
total = 0 total = 0
row = frappe._dict({ row = frappe._dict({
"account": _(d.name), "account": _(d.name),
"parent_account": _(d.parent_account), "parent_account": _(d.parent_account) if d.parent_account else '',
"indent": flt(d.indent), "indent": flt(d.indent),
"year_start_date": year_start_date, "year_start_date": year_start_date,
"year_end_date": year_end_date, "year_end_date": year_end_date,

View File

@ -25,7 +25,7 @@ def execute(filters=None):
account_details.setdefault(acc.name, acc) account_details.setdefault(acc.name, acc)
if filters.get('party'): if filters.get('party'):
parties = str(filters.get("party")).strip() parties = cstr(filters.get("party")).strip()
filters.party = [d.strip() for d in parties.split(',') if d] filters.party = [d.strip() for d in parties.split(',') if d]
validate_filters(filters, account_details) validate_filters(filters, account_details)
@ -60,11 +60,11 @@ def validate_filters(filters, account_details):
frappe.throw(_("From Date must be before To Date")) frappe.throw(_("From Date must be before To Date"))
if filters.get('project'): if filters.get('project'):
projects = str(filters.get("project")).strip() projects = cstr(filters.get("project")).strip()
filters.project = [d.strip() for d in projects.split(',') if d] filters.project = [d.strip() for d in projects.split(',') if d]
if filters.get('cost_center'): if filters.get('cost_center'):
cost_centers = str(filters.get("cost_center")).strip() cost_centers = cstr(filters.get("cost_center")).strip()
filters.cost_center = [d.strip() for d in cost_centers.split(',') if d] filters.cost_center = [d.strip() for d in cost_centers.split(',') if d]

View File

@ -200,7 +200,7 @@ class GrossProfitGenerator(object):
def skip_row(self, row, product_bundles): def skip_row(self, row, product_bundles):
if self.filters.get("group_by") != "Invoice": if self.filters.get("group_by") != "Invoice":
if not row.get(scrub(self.filters.get("group_by"))): if not row.get(scrub(self.filters.get("group_by", ""))):
return True return True
elif row.get("is_return") == 1: elif row.get("is_return") == 1:
return True return True
@ -316,7 +316,7 @@ class GrossProfitGenerator(object):
on `tabSales Invoice Item`.parent = `tabSales Invoice`.name on `tabSales Invoice Item`.parent = `tabSales Invoice`.name
{sales_team_table} {sales_team_table}
where where
`tabSales Invoice`.docstatus=1 {conditions} {match_cond} `tabSales Invoice`.docstatus=1 and `tabSales Invoice`.is_opening!='Yes' {conditions} {match_cond}
order by order by
`tabSales Invoice`.posting_date desc, `tabSales Invoice`.posting_time desc""" `tabSales Invoice`.posting_date desc, `tabSales Invoice`.posting_time desc"""
.format(conditions=conditions, sales_person_cols=sales_person_cols, .format(conditions=conditions, sales_person_cols=sales_person_cols,

View File

@ -34,6 +34,9 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum
data = [] data = []
for d in item_list: for d in item_list:
if not d.stock_qty:
continue
purchase_receipt = None purchase_receipt = None
if d.purchase_receipt: if d.purchase_receipt:
purchase_receipt = d.purchase_receipt purchase_receipt = d.purchase_receipt

View File

@ -156,7 +156,6 @@ def get_sales_invoice_data(filters):
def get_mode_of_payments(filters): def get_mode_of_payments(filters):
frappe.log_error(filters, 'filters')
mode_of_payments = {} mode_of_payments = {}
invoice_list = get_invoices(filters) invoice_list = get_invoices(filters)
invoice_list_names = ",".join(['"' + invoice['name'] + '"' for invoice in invoice_list]) invoice_list_names = ",".join(['"' + invoice['name'] + '"' for invoice in invoice_list])
@ -164,12 +163,14 @@ def get_mode_of_payments(filters):
inv_mop = frappe.db.sql("""select a.owner,a.posting_date, ifnull(b.mode_of_payment, '') as mode_of_payment inv_mop = frappe.db.sql("""select a.owner,a.posting_date, ifnull(b.mode_of_payment, '') as mode_of_payment
from `tabSales Invoice` a, `tabSales Invoice Payment` b from `tabSales Invoice` a, `tabSales Invoice Payment` b
where a.name = b.parent where a.name = b.parent
and a.docstatus = 1
and a.name in ({invoice_list_names}) and a.name in ({invoice_list_names})
union union
select a.owner,a.posting_date, ifnull(b.mode_of_payment, '') as mode_of_payment select a.owner,a.posting_date, ifnull(b.mode_of_payment, '') as mode_of_payment
from `tabSales Invoice` a, `tabPayment Entry` b,`tabPayment Entry Reference` c from `tabSales Invoice` a, `tabPayment Entry` b,`tabPayment Entry Reference` c
where a.name = c.reference_name where a.name = c.reference_name
and b.name = c.parent and b.name = c.parent
and b.docstatus = 1
and a.name in ({invoice_list_names}) and a.name in ({invoice_list_names})
union union
select a.owner, a.posting_date, select a.owner, a.posting_date,
@ -196,13 +197,13 @@ def get_invoices(filters):
def get_mode_of_payment_details(filters): def get_mode_of_payment_details(filters):
mode_of_payment_details = {} mode_of_payment_details = {}
invoice_list = get_invoices(filters) invoice_list = get_invoices(filters)
frappe.log_error(invoice_list, 'invoice_list')
invoice_list_names = ",".join(['"' + invoice['name'] + '"' for invoice in invoice_list]) invoice_list_names = ",".join(['"' + invoice['name'] + '"' for invoice in invoice_list])
if invoice_list: if invoice_list:
inv_mop_detail = frappe.db.sql("""select a.owner, a.posting_date, inv_mop_detail = frappe.db.sql("""select a.owner, a.posting_date,
ifnull(b.mode_of_payment, '') as mode_of_payment, sum(b.base_amount) as paid_amount ifnull(b.mode_of_payment, '') as mode_of_payment, sum(b.base_amount) as paid_amount
from `tabSales Invoice` a, `tabSales Invoice Payment` b from `tabSales Invoice` a, `tabSales Invoice Payment` b
where a.name = b.parent where a.name = b.parent
and a.docstatus = 1
and a.name in ({invoice_list_names}) and a.name in ({invoice_list_names})
group by a.owner, a.posting_date, mode_of_payment group by a.owner, a.posting_date, mode_of_payment
union union
@ -211,6 +212,7 @@ def get_mode_of_payment_details(filters):
from `tabSales Invoice` a, `tabPayment Entry` b,`tabPayment Entry Reference` c from `tabSales Invoice` a, `tabPayment Entry` b,`tabPayment Entry Reference` c
where a.name = c.reference_name where a.name = c.reference_name
and b.name = c.parent and b.name = c.parent
and b.docstatus = 1
and a.name in ({invoice_list_names}) and a.name in ({invoice_list_names})
group by a.owner, a.posting_date, mode_of_payment group by a.owner, a.posting_date, mode_of_payment
union union

View File

@ -0,0 +1,165 @@
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
import unittest
import frappe
from erpnext.accounts.report.sales_payment_summary.sales_payment_summary import get_mode_of_payments, get_mode_of_payment_details
from frappe.utils import today
from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry
test_dependencies = ["Sales Invoice"]
class TestSalesPaymentSummary(unittest.TestCase):
@classmethod
def setUpClass(self):
create_records()
pes = frappe.get_all("Payment Entry")
jes = frappe.get_all("Journal Entry")
sis = frappe.get_all("Sales Invoice")
for pe in pes:
frappe.db.set_value("Payment Entry", pe.name, "docstatus", 2)
for je in jes:
frappe.db.set_value("Journal Entry", je.name, "docstatus", 2)
for si in sis:
frappe.db.set_value("Sales Invoice", si.name, "docstatus", 2)
def test_get_mode_of_payments(self):
filters = get_filters()
for dummy in range(2):
si = create_sales_invoice_record()
si.insert()
si.submit()
if int(si.name[-3:])%2 == 0:
bank_account = "_Test Cash - _TC"
mode_of_payment = "Cash"
else:
bank_account = "_Test Bank - _TC"
mode_of_payment = "Credit Card"
pe = get_payment_entry("Sales Invoice", si.name, bank_account=bank_account)
pe.reference_no = "_Test"
pe.reference_date = today()
pe.mode_of_payment = mode_of_payment
pe.insert()
pe.submit()
mop = get_mode_of_payments(filters)
self.assertTrue('Credit Card' in mop.values()[0])
self.assertTrue('Cash' in mop.values()[0])
# Cancel all Cash payment entry and check if this mode of payment is still fetched.
payment_entries = frappe.get_all("Payment Entry", filters={"mode_of_payment": "Cash", "docstatus": 1}, fields=["name", "docstatus"])
for payment_entry in payment_entries:
pe = frappe.get_doc("Payment Entry", payment_entry.name)
pe.cancel()
mop = get_mode_of_payments(filters)
self.assertTrue('Credit Card' in mop.values()[0])
self.assertTrue('Cash' not in mop.values()[0])
def test_get_mode_of_payments_details(self):
filters = get_filters()
for dummy in range(2):
si = create_sales_invoice_record()
si.insert()
si.submit()
if int(si.name[-3:])%2 == 0:
bank_account = "_Test Cash - _TC"
mode_of_payment = "Cash"
else:
bank_account = "_Test Bank - _TC"
mode_of_payment = "Credit Card"
pe = get_payment_entry("Sales Invoice", si.name, bank_account=bank_account)
pe.reference_no = "_Test"
pe.reference_date = today()
pe.mode_of_payment = mode_of_payment
pe.insert()
pe.submit()
mopd = get_mode_of_payment_details(filters)
mopd_values = mopd.values()[0]
for mopd_value in mopd_values:
if mopd_value[0] == "Credit Card":
cc_init_amount = mopd_value[1]
# Cancel one Credit Card Payment Entry and check that it is not fetched in mode of payment details.
payment_entries = frappe.get_all("Payment Entry", filters={"mode_of_payment": "Credit Card", "docstatus": 1}, fields=["name", "docstatus"])
for payment_entry in payment_entries[:1]:
pe = frappe.get_doc("Payment Entry", payment_entry.name)
pe.cancel()
mopd = get_mode_of_payment_details(filters)
mopd_values = mopd.values()[0]
for mopd_value in mopd_values:
if mopd_value[0] == "Credit Card":
cc_final_amount = mopd_value[1]
self.assertTrue(cc_init_amount > cc_final_amount)
def get_filters():
return {
"from_date": "1900-01-01",
"to_date": today(),
"company": "_Test Company"
}
def create_sales_invoice_record(qty=1):
# return sales invoice doc object
return frappe.get_doc({
"doctype": "Sales Invoice",
"customer": frappe.get_doc('Customer', {"customer_name": "Prestiga-Biz"}).name,
"company": '_Test Company',
"due_date": today(),
"posting_date": today(),
"currency": "INR",
"taxes_and_charges": "",
"debit_to": "Debtors - _TC",
"taxes": [],
"items": [{
'doctype': 'Sales Invoice Item',
'item_code': frappe.get_doc('Item', {'item_name': 'Consulting'}).name,
'qty': qty,
"rate": 10000,
'income_account': 'Sales - _TC',
'cost_center': 'Main - _TC',
'expense_account': 'Cost of Goods Sold - _TC'
}]
})
def create_records():
if frappe.db.exists("Customer", "Prestiga-Biz"):
return
#customer
frappe.get_doc({
"customer_group": "_Test Customer Group",
"customer_name": "Prestiga-Biz",
"customer_type": "Company",
"doctype": "Customer",
"territory": "_Test Territory"
}).insert()
# item
item = frappe.get_doc({
"doctype": "Item",
"item_code": "Consulting",
"item_name": "Consulting",
"item_group": "All Item Groups",
"company": "_Test Company",
"is_stock_item": 0
}).insert()
# item price
frappe.get_doc({
"doctype": "Item Price",
"price_list": "Standard Selling",
"item_code": item.item_code,
"price_list_rate": 10000
}).insert()

View File

@ -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"
}
]
}

View File

@ -1,5 +1,6 @@
{ {
"allow_copy": 0, "allow_copy": 0,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0, "allow_guest_to_view": 0,
"allow_import": 1, "allow_import": 1,
"allow_rename": 1, "allow_rename": 1,
@ -154,7 +155,7 @@
"columns": 0, "columns": 0,
"fetch_from": "item_code.asset_category", "fetch_from": "item_code.asset_category",
"fieldname": "asset_category", "fieldname": "asset_category",
"fieldtype": "Read Only", "fieldtype": "Link",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
@ -165,12 +166,12 @@
"label": "Asset Category", "label": "Asset Category",
"length": 0, "length": 0,
"no_copy": 0, "no_copy": 0,
"options": "", "options": "Asset Category",
"permlevel": 0, "permlevel": 0,
"precision": "", "precision": "",
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0, "print_hide_if_no_value": 0,
"read_only": 0, "read_only": 1,
"remember_last_selected_value": 0, "remember_last_selected_value": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
@ -1881,7 +1882,7 @@
"issingle": 0, "issingle": 0,
"istable": 0, "istable": 0,
"max_attachments": 0, "max_attachments": 0,
"modified": "2018-08-21 14:44:24.507215", "modified": "2019-01-15 16:12:48.314196",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Assets", "module": "Assets",
"name": "Asset", "name": "Asset",

View File

@ -9,6 +9,7 @@ from frappe.utils import cstr, nowdate, getdate, flt, get_last_day, add_days, ad
from erpnext.assets.doctype.asset.depreciation import post_depreciation_entries, scrap_asset, restore_asset from erpnext.assets.doctype.asset.depreciation import post_depreciation_entries, scrap_asset, restore_asset
from erpnext.assets.doctype.asset.asset import make_sales_invoice, make_purchase_invoice from erpnext.assets.doctype.asset.asset import make_sales_invoice, make_purchase_invoice
from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt
from erpnext.stock.doctype.purchase_receipt.purchase_receipt import make_purchase_invoice as make_invoice
class TestAsset(unittest.TestCase): class TestAsset(unittest.TestCase):
def setUp(self): def setUp(self):
@ -494,6 +495,15 @@ class TestAsset(unittest.TestCase):
self.assertEqual(gle, expected_gle) self.assertEqual(gle, expected_gle)
def test_expense_head(self):
pr = make_purchase_receipt(item_code="Macbook Pro",
qty=2, rate=200000.0, location="Test Location")
doc = make_invoice(pr.name)
self.assertEquals('Asset Received But Not Billed - _TC', doc.items[0].expense_account)
def create_asset_data(): def create_asset_data():
if not frappe.db.exists("Asset Category", "Computers"): if not frappe.db.exists("Asset Category", "Computers"):
create_asset_category() create_asset_category()

View File

@ -315,7 +315,6 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend(
method: "erpnext.stock.doctype.material_request.material_request.make_purchase_order", method: "erpnext.stock.doctype.material_request.material_request.make_purchase_order",
source_doctype: "Material Request", source_doctype: "Material Request",
target: me.frm, target: me.frm,
args: args,
setters: { setters: {
company: me.frm.doc.company company: me.frm.doc.company
}, },

View File

@ -3831,7 +3831,7 @@
"issingle": 0, "issingle": 0,
"istable": 0, "istable": 0,
"max_attachments": 0, "max_attachments": 0,
"modified": "2018-11-12 19:59:49.211145", "modified": "2019-01-07 16:51:56.739693",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Buying", "module": "Buying",
"name": "Purchase Order", "name": "Purchase Order",

View File

@ -91,6 +91,7 @@ class PurchaseOrder(BuyingController):
self.party_account_currency = get_party_account_currency("Supplier", self.supplier, self.company) self.party_account_currency = get_party_account_currency("Supplier", self.supplier, self.company)
def validate_minimum_order_qty(self): def validate_minimum_order_qty(self):
if not self.get("items"): return
items = list(set([d.item_code for d in self.get("items")])) 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 itemwise_min_order_qty = frappe._dict(frappe.db.sql("""select name, min_order_qty

View File

@ -1,5 +1,6 @@
{ {
"allow_copy": 0, "allow_copy": 0,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0, "allow_guest_to_view": 0,
"allow_import": 0, "allow_import": 0,
"allow_rename": 0, "allow_rename": 0,
@ -700,10 +701,12 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -2341,7 +2344,7 @@
"issingle": 0, "issingle": 0,
"istable": 1, "istable": 1,
"max_attachments": 0, "max_attachments": 0,
"modified": "2018-09-07 07:16:58.258276", "modified": "2019-01-07 16:51:57.546323",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Buying", "module": "Buying",
"name": "Purchase Order Item", "name": "Purchase Order Item",
@ -2354,5 +2357,6 @@
"sort_field": "modified", "sort_field": "modified",
"sort_order": "DESC", "sort_order": "DESC",
"track_changes": 1, "track_changes": 1,
"track_seen": 0 "track_seen": 0,
"track_views": 0
} }

View File

@ -1,5 +1,6 @@
{ {
"allow_copy": 0, "allow_copy": 0,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0, "allow_guest_to_view": 0,
"allow_import": 0, "allow_import": 0,
"allow_rename": 0, "allow_rename": 0,
@ -12,6 +13,7 @@
"fields": [ "fields": [
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -45,6 +47,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -78,6 +81,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -110,6 +114,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -143,6 +148,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -176,6 +182,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -206,6 +213,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -238,6 +246,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -270,6 +279,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -302,6 +312,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -335,6 +346,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -376,7 +388,7 @@
"issingle": 0, "issingle": 0,
"istable": 1, "istable": 1,
"max_attachments": 0, "max_attachments": 0,
"modified": "2018-03-13 12:37:57.150914", "modified": "2019-01-07 16:51:58.016007",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Buying", "module": "Buying",
"name": "Purchase Order Item Supplied", "name": "Purchase Order Item Supplied",
@ -387,5 +399,6 @@
"read_only_onload": 0, "read_only_onload": 0,
"show_name_in_global_search": 0, "show_name_in_global_search": 0,
"track_changes": 0, "track_changes": 0,
"track_seen": 0 "track_seen": 0,
"track_views": 0
} }

View File

@ -1,5 +1,6 @@
{ {
"allow_copy": 0, "allow_copy": 0,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0, "allow_guest_to_view": 0,
"allow_import": 0, "allow_import": 0,
"allow_rename": 0, "allow_rename": 0,
@ -13,6 +14,7 @@
"fields": [ "fields": [
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -46,6 +48,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -79,6 +82,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -113,6 +117,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -144,6 +149,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -174,6 +180,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -203,6 +210,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -235,6 +243,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -267,6 +276,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -300,6 +310,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -333,6 +344,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -366,6 +378,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -398,6 +411,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -430,6 +444,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -462,6 +477,7 @@
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -503,7 +519,7 @@
"issingle": 0, "issingle": 0,
"istable": 1, "istable": 1,
"max_attachments": 0, "max_attachments": 0,
"modified": "2018-03-13 12:38:40.807453", "modified": "2019-01-07 16:51:59.536291",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Buying", "module": "Buying",
"name": "Purchase Receipt Item Supplied", "name": "Purchase Receipt Item Supplied",
@ -516,5 +532,6 @@
"sort_field": "modified", "sort_field": "modified",
"sort_order": "DESC", "sort_order": "DESC",
"track_changes": 1, "track_changes": 1,
"track_seen": 0 "track_seen": 0,
"track_views": 0
} }

View File

@ -1463,7 +1463,7 @@
"issingle": 0, "issingle": 0,
"istable": 0, "istable": 0,
"max_attachments": 0, "max_attachments": 0,
"modified": "2018-10-06 14:31:46.378758", "modified": "2019-01-07 16:52:04.660271",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Buying", "module": "Buying",
"name": "Supplier", "name": "Supplier",

View File

@ -1,5 +1,6 @@
{ {
"allow_copy": 0, "allow_copy": 0,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0, "allow_guest_to_view": 0,
"allow_import": 1, "allow_import": 1,
"allow_rename": 0, "allow_rename": 0,
@ -2844,8 +2845,8 @@
"istable": 0, "istable": 0,
"max_attachments": 0, "max_attachments": 0,
"menu_index": 0, "menu_index": 0,
"modified": "2018-08-29 12:14:31.329035", "modified": "2019-01-07 16:52:01.505553",
"modified_by": "nabinhait@gmail.com", "modified_by": "Administrator",
"module": "Buying", "module": "Buying",
"name": "Supplier Quotation", "name": "Supplier Quotation",
"owner": "Administrator", "owner": "Administrator",
@ -2956,5 +2957,6 @@
"timeline_field": "supplier", "timeline_field": "supplier",
"title_field": "title", "title_field": "title",
"track_changes": 0, "track_changes": 0,
"track_seen": 0 "track_seen": 0,
"track_views": 0
} }

View File

@ -1,5 +1,6 @@
{ {
"allow_copy": 0, "allow_copy": 0,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0, "allow_guest_to_view": 0,
"allow_import": 0, "allow_import": 0,
"allow_rename": 0, "allow_rename": 0,
@ -15,6 +16,7 @@
"fields": [ "fields": [
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 1, "bold": 1,
"collapsible": 0, "collapsible": 0,
@ -43,10 +45,12 @@
"reqd": 1, "reqd": 1,
"search_index": 1, "search_index": 1,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -73,10 +77,12 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -104,10 +110,12 @@
"reqd": 0, "reqd": 0,
"search_index": 1, "search_index": 1,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -133,10 +141,12 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -163,10 +173,12 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 1, "collapsible": 1,
@ -193,10 +205,12 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -225,11 +239,13 @@
"reqd": 1, "reqd": 1,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0, "unique": 0,
"width": "300px" "width": "300px"
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -254,10 +270,12 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -284,10 +302,12 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -315,10 +335,12 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -344,10 +366,12 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 1, "bold": 1,
"collapsible": 0, "collapsible": 0,
@ -376,11 +400,13 @@
"reqd": 1, "reqd": 1,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0, "unique": 0,
"width": "60px" "width": "60px"
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -408,10 +434,12 @@
"reqd": 1, "reqd": 1,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -438,10 +466,12 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -468,10 +498,12 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -500,10 +532,12 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -528,10 +562,12 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -560,11 +596,13 @@
"reqd": 1, "reqd": 1,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0, "unique": 0,
"width": "100px" "width": "100px"
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -591,10 +629,12 @@
"reqd": 1, "reqd": 1,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -621,10 +661,12 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -652,10 +694,12 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -680,10 +724,12 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 1, "bold": 1,
"collapsible": 0, "collapsible": 0,
@ -712,10 +758,12 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -744,10 +792,12 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -772,10 +822,12 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -806,11 +858,13 @@
"reqd": 1, "reqd": 1,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0, "unique": 0,
"width": "100px" "width": "100px"
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -839,10 +893,12 @@
"reqd": 1, "reqd": 1,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -869,10 +925,12 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -898,10 +956,12 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -928,10 +988,12 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -959,10 +1021,12 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -988,10 +1052,12 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1019,10 +1085,12 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1050,10 +1118,12 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 1, "collapsible": 1,
@ -1080,10 +1150,12 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1110,10 +1182,12 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1140,10 +1214,12 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1169,10 +1245,12 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1200,10 +1278,12 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1229,10 +1309,12 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1261,10 +1343,12 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1291,10 +1375,12 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1322,10 +1408,12 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1355,11 +1443,13 @@
"reqd": 0, "reqd": 0,
"search_index": 1, "search_index": 1,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0, "unique": 0,
"width": "120px" "width": "120px"
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1387,10 +1477,12 @@
"reqd": 0, "reqd": 0,
"search_index": 1, "search_index": 1,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1418,10 +1510,12 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1446,10 +1540,12 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1477,10 +1573,12 @@
"reqd": 0, "reqd": 0,
"search_index": 1, "search_index": 1,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1507,10 +1605,12 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1539,10 +1639,12 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1572,10 +1674,12 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1604,10 +1708,12 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1633,10 +1739,12 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
}, },
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 1, "allow_on_submit": 1,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
@ -1664,6 +1772,7 @@
"reqd": 0, "reqd": 0,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0,
"unique": 0 "unique": 0
} }
], ],
@ -1677,7 +1786,7 @@
"issingle": 0, "issingle": 0,
"istable": 1, "istable": 1,
"max_attachments": 0, "max_attachments": 0,
"modified": "2018-08-06 05:33:07.404385", "modified": "2019-01-07 16:52:02.125715",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Buying", "module": "Buying",
"name": "Supplier Quotation Item", "name": "Supplier Quotation Item",
@ -1690,5 +1799,6 @@
"sort_field": "modified", "sort_field": "modified",
"sort_order": "DESC", "sort_order": "DESC",
"track_changes": 1, "track_changes": 1,
"track_seen": 0 "track_seen": 0,
"track_views": 0
} }

View File

@ -77,9 +77,20 @@ frappe.query_reports["Purchase Analytics"] = {
events: { events: {
onCheckRow: function(data) { onCheckRow: function(data) {
row_name = data[2].content; row_name = data[2].content;
row_values = data.slice(5).map(function (column) { 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; return column.content;
}) })
}
else {
row_values = data.slice(3,length-1).map(function (column) {
return column.content;
})
}
entry = { entry = {
'name':row_name, 'name':row_name,

View File

@ -65,8 +65,8 @@ def get_quantity_list(item):
if item: if item:
qty_list = frappe.db.sql("""select distinct qty from `tabSupplier Quotation Item` qty_list = frappe.db.sql("""select distinct qty from `tabSupplier Quotation Item`
where ifnull(item_code,'')=%s and docstatus < 2""", item, as_dict=1) where ifnull(item_code,'')=%s and docstatus < 2 order by qty""", item, as_dict=1)
qty_list.sort(reverse=False)
for qt in qty_list: for qt in qty_list:
col = frappe._dict({ col = frappe._dict({
"key": str(qt.qty), "key": str(qt.qty),

View File

@ -573,10 +573,6 @@ def get_data():
"label": _("Subscription Management"), "label": _("Subscription Management"),
"icon": "fa fa-microchip ", "icon": "fa fa-microchip ",
"items": [ "items": [
{
"type": "doctype",
"name": "Subscriber",
},
{ {
"type": "doctype", "type": "doctype",
"name": "Subscription Plan", "name": "Subscription Plan",

View File

@ -604,12 +604,13 @@ class AccountsController(TransactionBase):
advance.account_currency) advance.account_currency)
if advance.account_currency == self.currency: if advance.account_currency == self.currency:
order_total = self.grand_total order_total = self.get("rounded_total") or self.grand_total
formatted_order_total = fmt_money(order_total, precision=self.precision("grand_total"), precision = "rounded_total" if self.get("rounded_total") else "grand_total"
currency=advance.account_currency)
else: else:
order_total = self.base_grand_total order_total = self.get("base_rounded_total") or self.base_grand_total
formatted_order_total = fmt_money(order_total, precision=self.precision("base_grand_total"), precision = "base_rounded_total" if self.get("base_rounded_total") else "base_grand_total"
formatted_order_total = fmt_money(order_total, precision=self.precision(precision),
currency=advance.account_currency) currency=advance.account_currency)
if self.currency == self.company_currency and advance_paid > order_total: if self.currency == self.company_currency and advance_paid > order_total:
@ -1073,6 +1074,13 @@ def update_child_qty_rate(parent_doctype, trans_items, parent_doctype_name):
data = json.loads(trans_items) data = json.loads(trans_items)
for d in data: for d in data:
child_item = frappe.get_doc(parent_doctype + ' Item', d.get("docname")) child_item = frappe.get_doc(parent_doctype + ' Item', d.get("docname"))
if parent_doctype == "Sales Order" and flt(d.get("qty")) < child_item.delivered_qty:
frappe.throw(_("Cannot set quantity less than delivered quantity"))
if parent_doctype == "Purchase Order" and flt(d.get("qty")) < child_item.received_qty:
frappe.throw(_("Cannot set quantity less than received quantity"))
child_item.qty = flt(d.get("qty")) child_item.qty = flt(d.get("qty"))
if child_item.billed_amt > (flt(d.get("rate")) * flt(d.get("qty"))): if child_item.billed_amt > (flt(d.get("rate")) * flt(d.get("qty"))):

View File

@ -678,6 +678,8 @@ class BuyingController(StockController):
frappe.db.sql("delete from `tabSerial No` where purchase_document_no=%s", self.name) frappe.db.sql("delete from `tabSerial No` where purchase_document_no=%s", self.name)
def validate_schedule_date(self): def validate_schedule_date(self):
if not self.get("items"):
return
if not self.schedule_date: if not self.schedule_date:
self.schedule_date = min([d.schedule_date for d in self.get("items")]) self.schedule_date = min([d.schedule_date for d in self.get("items")])

View File

@ -12,6 +12,9 @@ from erpnext.controllers.accounts_controller import AccountsController
from erpnext.stock.stock_ledger import get_valuation_rate from erpnext.stock.stock_ledger import get_valuation_rate
from erpnext.stock import get_warehouse_account_map from erpnext.stock import get_warehouse_account_map
class QualityInspectionRequiredError(frappe.ValidationError): pass
class QualityInspectionRejectedError(frappe.ValidationError): pass
class StockController(AccountsController): class StockController(AccountsController):
def validate(self): def validate(self):
super(StockController, self).validate() super(StockController, self).validate()
@ -317,7 +320,6 @@ class StockController(AccountsController):
def validate_inspection(self): def validate_inspection(self):
'''Checks if quality inspection is set for Items that require inspection. '''Checks if quality inspection is set for Items that require inspection.
On submit, throw an exception''' On submit, throw an exception'''
inspection_required_fieldname = None inspection_required_fieldname = None
if self.doctype in ["Purchase Receipt", "Purchase Invoice"]: if self.doctype in ["Purchase Receipt", "Purchase Invoice"]:
inspection_required_fieldname = "inspection_required_before_purchase" inspection_required_fieldname = "inspection_required_before_purchase"
@ -330,17 +332,25 @@ class StockController(AccountsController):
return return
for d in self.get('items'): for d in self.get('items'):
raise_exception = False qa_required = False
if (inspection_required_fieldname and not d.quality_inspection and if (inspection_required_fieldname and not d.quality_inspection and
frappe.db.get_value("Item", d.item_code, inspection_required_fieldname)): 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: 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)) frappe.msgprint(_("Quality Inspection required for Item {0}").format(d.item_code))
if self.docstatus==1: 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): def update_blanket_order(self):
blanket_orders = list(set([d.blanket_order for d in self.items if d.blanket_order])) blanket_orders = list(set([d.blanket_order for d in self.items if d.blanket_order]))

View File

@ -376,7 +376,7 @@ def setup_pos_profile():
company_abbr = frappe.get_cached_value('Company', erpnext.get_default_company(), "abbr") company_abbr = frappe.get_cached_value('Company', erpnext.get_default_company(), "abbr")
pos = frappe.new_doc('POS Profile') pos = frappe.new_doc('POS Profile')
pos.user = frappe.db.get_global('demo_accounts_user') 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.naming_series = 'SINV-'
pos.update_stock = 0 pos.update_stock = 0
pos.write_off_account = 'Cost of Goods Sold - '+ company_abbr pos.write_off_account = 'Cost of Goods Sold - '+ company_abbr

View File

@ -1,18 +1,18 @@
{ {
"add_total_row": 0, "add_total_row": 0,
"apply_user_permissions": 1,
"creation": "2016-06-22 02:58:41.024538", "creation": "2016-06-22 02:58:41.024538",
"disabled": 0, "disabled": 0,
"docstatus": 0, "docstatus": 0,
"doctype": "Report", "doctype": "Report",
"idx": 3, "idx": 3,
"is_standard": "Yes", "is_standard": "Yes",
"modified": "2017-11-10 19:41:37.320224", "modified": "2018-12-17 16:46:46.176620",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Education", "module": "Education",
"name": "Student Fee Collection", "name": "Student Fee Collection",
"owner": "Administrator", "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", "ref_doctype": "Fees",
"report_name": "Student Fee Collection", "report_name": "Student Fee Collection",
"report_type": "Query Report", "report_type": "Query Report",

View File

@ -12,7 +12,7 @@ app_license = "GNU General Public License (v3)"
source_link = "https://github.com/frappe/erpnext" source_link = "https://github.com/frappe/erpnext"
develop_version = '12.x.x-develop' develop_version = '12.x.x-develop'
staging_version = '11.0.3-beta.28' staging_version = '11.0.3-beta.34'
error_report_email = "support@erpnext.com" error_report_email = "support@erpnext.com"

View File

@ -1,9 +1,24 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt # License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals from __future__ import unicode_literals
import frappe
import unittest
test_ignore = ["Leave Block List"] test_ignore = ["Leave Block List"]
class TestDepartment(unittest.TestCase):
def test_remove_department_data(self):
doc = create_department("Test Department")
frappe.delete_doc('Department', doc.name)
def create_department(department_name, parent_department=None):
doc = frappe.get_doc({
'doctype': 'Department',
'is_group': 0,
'parent_department': parent_department,
'department_name': department_name,
'company': frappe.defaults.get_defaults().company
}).insert()
return doc
import frappe
test_records = frappe.get_test_records('Department') test_records = frappe.get_test_records('Department')

View File

@ -13,8 +13,8 @@ from frappe.model.document import Document
from erpnext.utilities.transaction_base import delete_events from erpnext.utilities.transaction_base import delete_events
from frappe.utils.nestedset import NestedSet from frappe.utils.nestedset import NestedSet
class EmployeeUserDisabledError(frappe.ValidationError): class EmployeeUserDisabledError(frappe.ValidationError): pass
pass class EmployeeLeftValidationError(frappe.ValidationError): pass
class Employee(NestedSet): class Employee(NestedSet):
nsm_parent_field = 'reports_to' nsm_parent_field = 'reports_to'
@ -62,7 +62,7 @@ class Employee(NestedSet):
def validate_user_details(self): def validate_user_details(self):
data = frappe.db.get_value('User', data = frappe.db.get_value('User',
self.user_id, ['enabled', 'user_image'], as_dict=1) self.user_id, ['enabled', 'user_image'], as_dict=1)
if data.get("user_image"):
self.image = data.get("user_image") self.image = data.get("user_image")
self.validate_for_enabled_user_id(data.get("enabled", 0)) self.validate_for_enabled_user_id(data.get("enabled", 0))
self.validate_duplicate_user_id() self.validate_duplicate_user_id()
@ -147,7 +147,15 @@ class Employee(NestedSet):
validate_email_add(self.personal_email, True) validate_email_add(self.personal_email, True)
def validate_status(self): def validate_status(self):
if self.status == 'Left' and not self.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:&nbsp;")
+ ', '.join(link_to_employees), EmployeeLeftValidationError)
if not self.relieving_date:
throw(_("Please enter relieving date.")) throw(_("Please enter relieving date."))
def validate_for_enabled_user_id(self, enabled): def validate_for_enabled_user_id(self, enabled):

View File

@ -7,6 +7,7 @@ import frappe
import erpnext import erpnext
import unittest import unittest
import frappe.utils import frappe.utils
from erpnext.hr.doctype.employee.employee import EmployeeLeftValidationError
test_records = frappe.get_test_records('Employee') test_records = frappe.get_test_records('Employee')
@ -32,6 +33,18 @@ class TestEmployee(unittest.TestCase):
email_queue = frappe.db.sql("""select * from `tabEmail Queue`""", as_dict=True) email_queue = frappe.db.sql("""select * from `tabEmail Queue`""", as_dict=True)
self.assertTrue("Subject: Birthday Reminder" in email_queue[0].message) 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): def make_employee(user):
if not frappe.db.get_value("User", user): if not frappe.db.get_value("User", user):
frappe.get_doc({ frappe.get_doc({

View File

@ -78,12 +78,17 @@ def get_benefit_pro_rata_ratio_amount(employee, on_date, sal_struct):
total_pro_rata_max = 0 total_pro_rata_max = 0
benefit_amount_total = 0 benefit_amount_total = 0
for sal_struct_row in sal_struct.get("earnings"): for sal_struct_row in sal_struct.get("earnings"):
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"]) 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: if sal_struct_row.is_flexible_benefit == 1 and pay_against_benefit_claim != 1:
total_pro_rata_max += max_benefit_amount total_pro_rata_max += max_benefit_amount
if total_pro_rata_max > 0: if total_pro_rata_max > 0:
for sal_struct_row in sal_struct.get("earnings"): 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"]) 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: if sal_struct_row.is_flexible_benefit == 1 and pay_against_benefit_claim != 1:
component_max = max_benefit_amount component_max = max_benefit_amount
benefit_amount = component_max * sal_struct.max_benefits / total_pro_rata_max benefit_amount = component_max * sal_struct.max_benefits / total_pro_rata_max

View File

@ -1,5 +1,5 @@
frappe.listview_settings['Employee Separation'] = { 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"]], filters:[["boarding_status","=", "Pending"]],
get_indicator: function(doc) { get_indicator: function(doc) {
return [__(doc.boarding_status), frappe.utils.guess_colour(doc.boarding_status), "status,=," + doc.boarding_status]; return [__(doc.boarding_status), frappe.utils.guess_colour(doc.boarding_status), "status,=," + doc.boarding_status];

View File

@ -83,7 +83,7 @@ frappe.ui.form.on("Leave Application", {
if (!frm.doc.employee && frappe.defaults.get_user_permissions()) { if (!frm.doc.employee && frappe.defaults.get_user_permissions()) {
const perm = frappe.defaults.get_user_permissions(); const perm = frappe.defaults.get_user_permissions();
if (perm && perm['Employee']) { 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]);
} }
} }
}, },

View File

@ -187,7 +187,7 @@ class LeaveApplication(Document):
self.total_leave_days = get_number_of_leave_days(self.employee, self.leave_type, 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) 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.")) 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): if not is_lwp(self.leave_type):

View File

@ -457,7 +457,7 @@ def get_leave_period():
return frappe.get_doc(dict( return frappe.get_doc(dict(
name = 'Test Leave Period', name = 'Test Leave Period',
doctype = 'Leave Period', doctype = 'Leave Period',
from_date = "{0}-01-01".format(now_datetime().year), from_date = "{0}-12-01".format(now_datetime().year - 1),
to_date = "{0}-12-31".format(now_datetime().year), to_date = "{0}-12-31".format(now_datetime().year),
company = "_Test Company", company = "_Test Company",
is_active = 1 is_active = 1

View File

@ -256,6 +256,9 @@ class TestSalarySlip(unittest.TestCase):
raise raise
frappe.db.sql("""delete from `tabAdditional Salary` where employee=%s""", (employee)) frappe.db.sql("""delete from `tabAdditional Salary` where employee=%s""", (employee))
# undelete fixture data
frappe.db.rollback()
def make_holiday_list(self): def make_holiday_list(self):
fiscal_year = get_fiscal_year(nowdate(), company=erpnext.get_default_company()) fiscal_year = get_fiscal_year(nowdate(), company=erpnext.get_default_company())
if not frappe.db.get_value("Holiday List", "Salary Slip Test Holiday List"): if not frappe.db.get_value("Holiday List", "Salary Slip Test Holiday List"):

View File

@ -124,6 +124,7 @@ frappe.ui.form.on('Salary Structure', {
"label":__("Employee"), "label":__("Employee"),
"fieldname":"employee", "fieldname":"employee",
"fieldtype":"Select", "fieldtype":"Select",
"reqd": true,
options: employees options: employees
}, { }, {
fieldname:"fetch", fieldname:"fetch",

View File

@ -4,7 +4,7 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import frappe import frappe
from frappe.utils import flt, cint from frappe.utils import flt, cint, cstr
from frappe import _ from frappe import _
from frappe.model.mapper import get_mapped_doc from frappe.model.mapper import get_mapped_doc
from frappe.model.document import Document from frappe.model.document import Document
@ -22,7 +22,7 @@ class SalaryStructure(Document):
overwritten_fields_if_missing = ["amount_based_on_formula", "formula", "amount"] overwritten_fields_if_missing = ["amount_based_on_formula", "formula", "amount"]
for table in ["earnings", "deductions"]: for table in ["earnings", "deductions"]:
for d in self.get(table): 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) overwritten_fields + overwritten_fields_if_missing, as_dict=1)
if component_default_value: if component_default_value:
for fieldname in overwritten_fields: for fieldname in overwritten_fields:

View File

@ -0,0 +1,33 @@
# -*- 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)
for row in filtered_data:
self.assertTrue(getdate(row[3]) >= getdate(date_of_joining) and getdate(row[3]) <= getdate(relieving_date))

View File

@ -41,16 +41,28 @@ def add_header(w):
return w return w
def add_data(w, args): def add_data(w, args):
data = get_data(args)
writedata(w, data)
return w
def get_data(args):
dates = get_dates(args) dates = get_dates(args)
employees = get_active_employees() employees = get_active_employees()
existing_attendance_records = get_existing_attendance_records(args) existing_attendance_records = get_existing_attendance_records(args)
data = []
for date in dates: for date in dates:
for employee in employees: 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 = {} existing_attendance = {}
if existing_attendance_records \ 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])] existing_attendance = existing_attendance_records[tuple([getdate(date), employee.name])]
row = [ row = [
existing_attendance and existing_attendance.name or "", existing_attendance and existing_attendance.name or "",
employee.name, employee.employee_name, date, employee.name, employee.employee_name, date,
@ -58,8 +70,12 @@ def add_data(w, args):
existing_attendance and existing_attendance.leave_type or "", employee.company, existing_attendance and existing_attendance.leave_type or "", employee.company,
existing_attendance and existing_attendance.naming_series or get_naming_series(), existing_attendance and existing_attendance.naming_series or get_naming_series(),
] ]
data.append(row)
return data
def writedata(w, data):
for row in data:
w.writerow(row) w.writerow(row)
return w
def get_dates(args): def get_dates(args):
"""get list of dates in between from date and to date""" """get list of dates in between from date and to date"""
@ -68,8 +84,13 @@ def get_dates(args):
return dates return dates
def get_active_employees(): def get_active_employees():
employees = frappe.db.sql("""select name, employee_name, company employees = frappe.db.get_all('Employee',
from tabEmployee where docstatus < 2 and status = 'Active'""", as_dict=1) fields=['name', 'employee_name', 'date_of_joining', 'company', 'relieving_date'],
filters={
'docstatus': ['<', 2],
'status': 'Active'
}
)
return employees return employees
def get_existing_attendance_records(args): def get_existing_attendance_records(args):

View File

@ -54,6 +54,9 @@ class EmployeeBoardingController(Document):
where parenttype='User' and role=%s''', activity.role) where parenttype='User' and role=%s''', activity.role)
users = users + user_list users = users + user_list
if "Administrator" in users:
users.remove("Administrator")
# assign the task the users # assign the task the users
if users: if users:
self.assign_task_to_users(task, set(users)) self.assign_task_to_users(task, set(users))

View File

@ -121,9 +121,11 @@ frappe.ui.form.on("BOM", {
freeze: true, freeze: true,
args: { args: {
update_parent: true, update_parent: true,
from_child_bom:false from_child_bom:false,
save: false
}, },
callback: function(r) { callback: function(r) {
refresh_field("items");
if(!r.exc) frm.refresh_fields(); if(!r.exc) frm.refresh_fields();
} }
}); });
@ -402,6 +404,8 @@ frappe.ui.form.on("BOM Item", "items_remove", function(frm) {
var toggle_operations = function(frm) { var toggle_operations = function(frm) {
frm.toggle_display("operations_section", cint(frm.doc.with_operations) == 1); 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) { frappe.ui.form.on("BOM", "with_operations", function(frm) {

View File

@ -80,41 +80,6 @@
"translatable": 0, "translatable": 0,
"unique": 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": "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_bulk_edit": 0,
"allow_in_quick_entry": 0, "allow_in_quick_entry": 0,
@ -154,8 +119,10 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fieldname": "inspection_required", "default": "1",
"fieldtype": "Check", "description": "Quantity of item obtained after manufacturing / repacking from given quantities of raw materials",
"fieldname": "quantity",
"fieldtype": "Float",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
@ -163,51 +130,18 @@
"in_global_search": 0, "in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 0, "in_standard_filter": 0,
"label": "Inspection Required", "label": "Quantity",
"length": 0, "length": 0,
"no_copy": 0, "no_copy": 0,
"oldfieldname": "quantity",
"oldfieldtype": "Currency",
"permlevel": 0, "permlevel": 0,
"precision": "",
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0, "print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"remember_last_selected_value": 0, "remember_last_selected_value": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 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,
"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, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0, "translatable": 0,
@ -346,77 +280,11 @@
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0, "allow_in_quick_entry": 0,
"allow_on_submit": 1, "allow_on_submit": 0,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fieldname": "rm_cost_as_per", "fieldname": "inspection_required",
"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",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
@ -425,7 +293,7 @@
"in_global_search": 0, "in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 0, "in_standard_filter": 0,
"label": "Set rate of sub-assembly item based on BOM", "label": "Inspection Required",
"length": 0, "length": 0,
"no_copy": 0, "no_copy": 0,
"permlevel": 0, "permlevel": 0,
@ -481,7 +349,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fieldname": "allow_same_item_multiple_times", "fieldname": "allow_same_item_multiple_times",
"fieldtype": "Data", "fieldtype": "Check",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
@ -508,12 +376,12 @@
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0, "allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 1,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "with_operations", "default": "1",
"fieldname": "transfer_material_against_job_card", "fieldname": "set_rate_of_sub_assembly_item_based_on_bom",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
@ -522,7 +390,7 @@
"in_global_search": 0, "in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 0, "in_standard_filter": 0,
"label": "Transfer Material Against Job Card", "label": "Set rate of sub-assembly item based on BOM",
"length": 0, "length": 0,
"no_copy": 0, "no_copy": 0,
"permlevel": 0, "permlevel": 0,
@ -538,6 +406,40 @@
"translatable": 0, "translatable": 0,
"unique": 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,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0, "allow_in_quick_entry": 0,
@ -603,6 +505,72 @@
"translatable": 0, "translatable": 0,
"unique": 0 "unique": 0
}, },
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"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_bulk_edit": 0,
"allow_in_quick_entry": 0, "allow_in_quick_entry": 0,
@ -670,12 +638,12 @@
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0, "allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 1,
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fieldname": "conversion_rate", "fieldname": "rm_cost_as_per",
"fieldtype": "Float", "fieldtype": "Select",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
@ -683,17 +651,50 @@
"in_global_search": 0, "in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 0, "in_standard_filter": 0,
"label": "Conversion Rate", "label": "Rate Of Materials Based On",
"length": 0, "length": 0,
"no_copy": 0, "no_copy": 0,
"options": "Valuation Rate\nLast Purchase Rate\nPrice List",
"permlevel": 0, "permlevel": 0,
"precision": "9",
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0, "print_hide_if_no_value": 0,
"read_only": 0, "read_only": 0,
"remember_last_selected_value": 0, "remember_last_selected_value": 0,
"report_hide": 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, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0, "translatable": 0,
@ -707,7 +708,7 @@
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"depends_on": "", "depends_on": "",
"description": "Specify the operations, operating cost and give a unique Operation no to your operations.", "description": "",
"fieldname": "operations_section", "fieldname": "operations_section",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hidden": 0, "hidden": 0,
@ -1976,7 +1977,7 @@
"issingle": 0, "issingle": 0,
"istable": 0, "istable": 0,
"max_attachments": 0, "max_attachments": 0,
"modified": "2018-10-24 02:07:21.618275", "modified": "2018-12-13 17:45:44.843197",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Manufacturing", "module": "Manufacturing",
"name": "BOM", "name": "BOM",

View File

@ -8,6 +8,7 @@ from frappe import _
from erpnext.setup.utils import get_exchange_rate from erpnext.setup.utils import get_exchange_rate
from frappe.website.website_generator import WebsiteGenerator from frappe.website.website_generator import WebsiteGenerator
from erpnext.stock.get_item_details import get_conversion_factor from erpnext.stock.get_item_details import get_conversion_factor
from erpnext.stock.get_item_details import get_price_list_rate
import functools import functools
@ -81,7 +82,7 @@ class BOM(WebsiteGenerator):
def get_item_det(self, item_code): def get_item_det(self, item_code):
item = frappe.db.sql("""select name, item_name, docstatus, description, image, 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) from `tabItem` where name=%s""", item_code, as_dict = 1)
if not item: if not item:
@ -109,7 +110,11 @@ class BOM(WebsiteGenerator):
"item_name": item.item_name, "item_name": item.item_name,
"bom_no": item.bom_no, "bom_no": item.bom_no,
"stock_qty": item.stock_qty, "stock_qty": item.stock_qty,
"allow_transfer_for_manufacture": item.allow_transfer_for_manufacture "include_item_in_manufacturing": item.include_item_in_manufacturing,
"qty": item.qty,
"uom": item.uom,
"stock_uom": item.stock_uom,
"conversion_factor": item.conversion_factor
}) })
for r in ret: for r in ret:
if not item.get(r): if not item.get(r):
@ -128,8 +133,8 @@ class BOM(WebsiteGenerator):
self.validate_rm_item(item) self.validate_rm_item(item)
args['bom_no'] = args['bom_no'] or item and cstr(item[0]['default_bom']) or '' 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 args['transfer_for_manufacture'] = (cstr(args.get('include_item_in_manufacturing', '')) or
item and item[0].allow_transfer_for_manufacture or 0) item and item[0].include_item_in_manufacturing or 0)
args.update(item[0]) args.update(item[0])
rate = self.get_rm_rate(args) rate = self.get_rm_rate(args)
@ -141,11 +146,11 @@ class BOM(WebsiteGenerator):
'uom' : item and args['stock_uom'] or '', 'uom' : item and args['stock_uom'] or '',
'conversion_factor': 1, 'conversion_factor': 1,
'bom_no' : args['bom_no'], 'bom_no' : args['bom_no'],
'rate' : rate / self.conversion_rate if self.conversion_rate else rate, 'rate' : rate,
'qty' : args.get("qty") or args.get("stock_qty") or 1, 'qty' : args.get("qty") or args.get("stock_qty") or 1,
'stock_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, '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 return ret_item
@ -173,34 +178,55 @@ class BOM(WebsiteGenerator):
elif self.rm_cost_as_per == "Price List": elif self.rm_cost_as_per == "Price List":
if not self.buying_price_list: if not self.buying_price_list:
frappe.throw(_("Please select Price List")) frappe.throw(_("Please select Price List"))
rate = frappe.db.get_value("Item Price", {"price_list": self.buying_price_list, args = frappe._dict({
"item_code": arg["item_code"]}, "price_list_rate") or 0.0 "doctype": "BOM",
"price_list": self.buying_price_list,
price_list_currency = frappe.db.get_value("Price List", "qty": arg.get("qty"),
self.buying_price_list, "currency") "uom": arg.get("uom") or arg.get("stock_uom"),
if price_list_currency != self.company_currency(): "stock_uom": arg.get("stock_uom"),
rate = flt(rate * self.conversion_rate) "transaction_type": "buying",
"company": self.company,
"currency": self.currency,
"conversion_rate": self.conversion_rate or 1,
"conversion_factor": arg.get("conversion_factor") or 1,
"plc_conversion_rate": 1
})
item_doc = frappe.get_doc("Item", arg.get("item_code"))
out = frappe._dict()
get_price_list_rate(args, item_doc, out)
rate = out.price_list_rate
if not rate: if not rate:
frappe.msgprint(_("{0} not found for Item {1}") if self.rm_cost_as_per == "Price List":
frappe.msgprint(_("Price not found for item {0} and price list {1}")
.format(arg["item_code"], self.buying_price_list), alert=True)
else:
frappe.msgprint(_("{0} not found for item {1}")
.format(self.rm_cost_as_per, arg["item_code"]), alert=True) .format(self.rm_cost_as_per, arg["item_code"]), alert=True)
return flt(rate) return flt(rate)
def update_cost(self, update_parent=True, from_child_bom=False): def update_cost(self, update_parent=True, from_child_bom=False, save=True):
if self.docstatus == 2: if self.docstatus == 2:
return return
existing_bom_cost = self.total_cost existing_bom_cost = self.total_cost
for d in self.get("items"): for d in self.get("items"):
rate = self.get_rm_rate({"item_code": d.item_code, "bom_no": d.bom_no}) d.rate = self.get_rm_rate({
if rate: "item_code": d.item_code,
d.rate = rate * flt(d.conversion_factor) / flt(self.conversion_rate) "bom_no": d.bom_no,
"qty": d.qty,
"uom": d.uom,
"stock_uom": d.stock_uom,
"conversion_factor": d.conversion_factor
})
d.amount = flt(d.rate) * flt(d.qty)
if self.docstatus == 1: if self.docstatus == 1:
self.flags.ignore_validate_update_after_submit = True self.flags.ignore_validate_update_after_submit = True
self.calculate_cost() self.calculate_cost()
if save:
self.save() self.save()
self.update_exploded_items() self.update_exploded_items()
@ -477,7 +503,7 @@ class BOM(WebsiteGenerator):
'stock_uom' : d.stock_uom, 'stock_uom' : d.stock_uom,
'stock_qty' : flt(d.stock_qty), 'stock_qty' : flt(d.stock_qty),
'rate' : d.base_rate, '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): def company_currency(self):
@ -494,7 +520,7 @@ class BOM(WebsiteGenerator):
# Did not use qty_consumed_per_unit in the query, as it leads to rounding loss # 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, 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.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 bom_item.stock_qty / ifnull(bom.quantity, 1) as qty_consumed_per_unit
from `tabBOM Explosion Item` bom_item, tabBOM bom 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) where bom_item.parent = bom.name and bom.name = %s and bom.docstatus = 1""", bom_no, as_dict = 1)
@ -509,7 +535,7 @@ class BOM(WebsiteGenerator):
'stock_uom' : d['stock_uom'], 'stock_uom' : d['stock_uom'],
'stock_qty' : d['qty_consumed_per_unit'] * stock_qty, 'stock_qty' : d['qty_consumed_per_unit'] * stock_qty,
'rate' : flt(d['rate']), '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): def add_exploded_items(self):
@ -585,7 +611,7 @@ def get_bom_items_as_dict(bom, company, qty=1, fetch_exploded=1, fetch_scrap_ite
query = query.format(table="BOM Explosion Item", query = query.format(table="BOM Explosion Item",
where_conditions="", where_conditions="",
is_stock_item=is_stock_item, 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""") (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) items = frappe.db.sql(query, { "parent": bom, "qty": qty, "bom": bom, "company": company }, as_dict=True)
@ -594,7 +620,7 @@ def get_bom_items_as_dict(bom, company, qty=1, fetch_exploded=1, fetch_scrap_ite
items = frappe.db.sql(query, { "qty": qty, "bom": bom, "company": company }, as_dict=True) items = frappe.db.sql(query, { "qty": qty, "bom": bom, "company": company }, as_dict=True)
else: else:
query = query.format(table="BOM Item", where_conditions="", is_stock_item=is_stock_item, 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) items = frappe.db.sql(query, { "qty": qty, "bom": bom, "company": company }, as_dict=True)
for item in items: for item in items:

View File

@ -97,6 +97,7 @@ class TestBOM(unittest.TestCase):
self.assertEqual(bom.base_total_cost, 486000) self.assertEqual(bom.base_total_cost, 486000)
def test_bom_cost_multi_uom_multi_currency(self): def test_bom_cost_multi_uom_multi_currency(self):
frappe.db.set_value("Price List", "_Test Price List", "price_not_uom_dependant", 1)
for item_code, rate in (("_Test Item", 3600), ("_Test Item Home Desktop Manufactured", 3000)): for item_code, rate in (("_Test Item", 3600), ("_Test Item Home Desktop Manufactured", 3000)):
frappe.db.sql("delete from `tabItem Price` where price_list='_Test Price List' and item_code=%s", frappe.db.sql("delete from `tabItem Price` where price_list='_Test Price List' and item_code=%s",
item_code) item_code)

View File

@ -11,7 +11,7 @@
"uom": "_Test UOM", "uom": "_Test UOM",
"stock_uom": "_Test UOM", "stock_uom": "_Test UOM",
"source_warehouse": "_Test Warehouse - _TC", "source_warehouse": "_Test Warehouse - _TC",
"allow_transfer_for_manufacture": 1 "include_item_in_manufacturing": 1
}, },
{ {
"amount": 2000.0, "amount": 2000.0,
@ -23,7 +23,7 @@
"uom": "_Test UOM", "uom": "_Test UOM",
"stock_uom": "_Test UOM", "stock_uom": "_Test UOM",
"source_warehouse": "_Test Warehouse - _TC", "source_warehouse": "_Test Warehouse - _TC",
"allow_transfer_for_manufacture": 1 "include_item_in_manufacturing": 1
} }
], ],
"docstatus": 1, "docstatus": 1,
@ -57,7 +57,7 @@
"uom": "_Test UOM", "uom": "_Test UOM",
"stock_uom": "_Test UOM", "stock_uom": "_Test UOM",
"source_warehouse": "_Test Warehouse - _TC", "source_warehouse": "_Test Warehouse - _TC",
"allow_transfer_for_manufacture": 1 "include_item_in_manufacturing": 1
}, },
{ {
"amount": 2000.0, "amount": 2000.0,
@ -69,7 +69,7 @@
"uom": "_Test UOM", "uom": "_Test UOM",
"stock_uom": "_Test UOM", "stock_uom": "_Test UOM",
"source_warehouse": "_Test Warehouse - _TC", "source_warehouse": "_Test Warehouse - _TC",
"allow_transfer_for_manufacture": 1 "include_item_in_manufacturing": 1
} }
], ],
"docstatus": 1, "docstatus": 1,
@ -102,7 +102,7 @@
"uom": "_Test UOM", "uom": "_Test UOM",
"stock_uom": "_Test UOM", "stock_uom": "_Test UOM",
"source_warehouse": "_Test Warehouse - _TC", "source_warehouse": "_Test Warehouse - _TC",
"allow_transfer_for_manufacture": 1 "include_item_in_manufacturing": 1
}, },
{ {
"amount": 3000.0, "amount": 3000.0,
@ -115,7 +115,7 @@
"uom": "_Test UOM", "uom": "_Test UOM",
"stock_uom": "_Test UOM", "stock_uom": "_Test UOM",
"source_warehouse": "_Test Warehouse - _TC", "source_warehouse": "_Test Warehouse - _TC",
"allow_transfer_for_manufacture": 1 "include_item_in_manufacturing": 1
} }
], ],
"docstatus": 1, "docstatus": 1,
@ -150,7 +150,7 @@
"uom": "_Test UOM", "uom": "_Test UOM",
"stock_uom": "_Test UOM", "stock_uom": "_Test UOM",
"source_warehouse": "_Test Warehouse - _TC", "source_warehouse": "_Test Warehouse - _TC",
"allow_transfer_for_manufacture": 1 "include_item_in_manufacturing": 1
} }
], ],
"docstatus": 1, "docstatus": 1,

View File

@ -1,5 +1,6 @@
{ {
"allow_copy": 0, "allow_copy": 0,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0, "allow_guest_to_view": 0,
"allow_import": 0, "allow_import": 0,
"allow_rename": 0, "allow_rename": 0,
@ -573,7 +574,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fieldname": "allow_transfer_for_manufacture", "fieldname": "include_item_in_manufacturing",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
@ -582,7 +583,7 @@
"in_global_search": 0, "in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 0, "in_standard_filter": 0,
"label": "Allow Transfer for Manufacture", "label": "Include Item In Manufacturing",
"length": 0, "length": 0,
"no_copy": 0, "no_copy": 0,
"permlevel": 0, "permlevel": 0,
@ -609,7 +610,7 @@
"issingle": 0, "issingle": 0,
"istable": 1, "istable": 1,
"max_attachments": 0, "max_attachments": 0,
"modified": "2018-08-27 16:32:35.152139", "modified": "2018-11-20 19:04:59.813773",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Manufacturing", "module": "Manufacturing",
"name": "BOM Explosion Item", "name": "BOM Explosion Item",

View File

@ -78,6 +78,39 @@
"translatable": 0, "translatable": 0,
"unique": 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
},
{ {
"allow_bulk_edit": 0, "allow_bulk_edit": 0,
"allow_in_quick_entry": 0, "allow_in_quick_entry": 0,
@ -932,8 +965,8 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fetch_from": "item_code.allow_transfer_for_manufacture", "fetch_from": "item_code.include_item_in_manufacturing",
"fieldname": "allow_transfer_for_manufacture", "fieldname": "include_item_in_manufacturing",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
@ -942,7 +975,7 @@
"in_global_search": 0, "in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 0, "in_standard_filter": 0,
"label": "Allow Transfer for Manufacture", "label": "Include Item In Manufacturing",
"length": 0, "length": 0,
"no_copy": 0, "no_copy": 0,
"permlevel": 0, "permlevel": 0,
@ -1023,6 +1056,38 @@
"set_only_once": 0, "set_only_once": 0,
"translatable": 0, "translatable": 0,
"unique": 0 "unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "allow_alternative_item",
"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": "Allow Alternative Item",
"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
} }
], ],
"has_web_view": 0, "has_web_view": 0,
@ -1035,7 +1100,7 @@
"issingle": 0, "issingle": 0,
"istable": 1, "istable": 1,
"max_attachments": 0, "max_attachments": 0,
"modified": "2018-11-22 15:04:55.187136", "modified": "2018-11-23 15:05:55.187136",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Manufacturing", "module": "Manufacturing",
"name": "BOM Item", "name": "BOM Item",

View File

@ -3,7 +3,7 @@
frappe.ui.form.on('Job Card', { frappe.ui.form.on('Job Card', {
refresh: function(frm) { 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) { if (frm.doc.for_quantity != frm.doc.transferred_qty) {
frm.add_custom_button(__("Material Request"), () => { frm.add_custom_button(__("Material Request"), () => {
frm.trigger("make_material_request"); frm.trigger("make_material_request");
@ -31,6 +31,7 @@ frappe.ui.form.on('Job Card', {
frm.add_custom_button(__("Complete Job"), () => { frm.add_custom_button(__("Complete Job"), () => {
frm.set_value('actual_end_date', frappe.datetime.now_datetime()); frm.set_value('actual_end_date', frappe.datetime.now_datetime());
frm.save(); frm.save();
frm.savesubmit();
}); });
} }
} }

View File

@ -1,5 +1,6 @@
{ {
"allow_copy": 0, "allow_copy": 0,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0, "allow_guest_to_view": 0,
"allow_import": 0, "allow_import": 0,
"allow_rename": 0, "allow_rename": 0,
@ -46,6 +47,39 @@
"translatable": 0, "translatable": 0,
"unique": 0 "unique": 0
}, },
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"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_bulk_edit": 0,
"allow_in_quick_entry": 0, "allow_in_quick_entry": 0,
@ -112,39 +146,6 @@
"translatable": 0, "translatable": 0,
"unique": 0 "unique": 0
}, },
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"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_bulk_edit": 0,
"allow_in_quick_entry": 0, "allow_in_quick_entry": 0,
@ -281,9 +282,8 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"default": "0", "fieldname": "wip_warehouse",
"fieldname": "transferred_qty", "fieldtype": "Link",
"fieldtype": "Float",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
@ -291,17 +291,18 @@
"in_global_search": 0, "in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 0, "in_standard_filter": 0,
"label": "Transferred Qty", "label": "WIP Warehouse",
"length": 0, "length": 0,
"no_copy": 0, "no_copy": 0,
"options": "Warehouse",
"permlevel": 0, "permlevel": 0,
"precision": "", "precision": "",
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0, "print_hide_if_no_value": 0,
"read_only": 1, "read_only": 0,
"remember_last_selected_value": 0, "remember_last_selected_value": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 1,
"search_index": 0, "search_index": 0,
"set_only_once": 0, "set_only_once": 0,
"translatable": 0, "translatable": 0,
@ -635,8 +636,9 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fieldname": "bom_no", "default": "0",
"fieldtype": "Link", "fieldname": "transferred_qty",
"fieldtype": "Float",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
@ -644,10 +646,42 @@
"in_global_search": 0, "in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 0, "in_standard_filter": 0,
"label": "BOM No", "label": "Transferred Qty",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_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, "length": 0,
"no_copy": 0, "no_copy": 0,
"options": "BOM",
"permlevel": 0, "permlevel": 0,
"precision": "", "precision": "",
"print_hide": 0, "print_hide": 0,
@ -701,8 +735,8 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fieldname": "column_break_20", "fieldname": "remarks",
"fieldtype": "Column Break", "fieldtype": "Small Text",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
@ -710,6 +744,7 @@
"in_global_search": 0, "in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 0, "in_standard_filter": 0,
"label": "Remarks",
"length": 0, "length": 0,
"no_copy": 0, "no_copy": 0,
"permlevel": 0, "permlevel": 0,
@ -732,8 +767,8 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fieldname": "remarks", "fieldname": "column_break_20",
"fieldtype": "Small Text", "fieldtype": "Column Break",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
"ignore_xss_filter": 0, "ignore_xss_filter": 0,
@ -741,7 +776,6 @@
"in_global_search": 0, "in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 0, "in_standard_filter": 0,
"label": "Remarks",
"length": 0, "length": 0,
"no_copy": 0, "no_copy": 0,
"permlevel": 0, "permlevel": 0,
@ -776,13 +810,13 @@
"in_standard_filter": 0, "in_standard_filter": 0,
"label": "Status", "label": "Status",
"length": 0, "length": 0,
"no_copy": 0, "no_copy": 1,
"options": "Open\nWork In Progress\nCancelled\nCompleted", "options": "Open\nWork In Progress\nMaterial Transferred\nSubmitted\nCancelled\nCompleted",
"permlevel": 0, "permlevel": 0,
"precision": "", "precision": "",
"print_hide": 0, "print_hide": 0,
"print_hide_if_no_value": 0, "print_hide_if_no_value": 0,
"read_only": 0, "read_only": 1,
"remember_last_selected_value": 0, "remember_last_selected_value": 0,
"report_hide": 0, "report_hide": 0,
"reqd": 0, "reqd": 0,
@ -834,7 +868,7 @@
"issingle": 0, "issingle": 0,
"istable": 0, "istable": 0,
"max_attachments": 0, "max_attachments": 0,
"modified": "2018-08-28 16:50:43.576151", "modified": "2018-12-13 17:23:57.986381",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Manufacturing", "module": "Manufacturing",
"name": "Job Card", "name": "Job Card",

View File

@ -11,9 +11,9 @@ from frappe.model.document import Document
class JobCard(Document): class JobCard(Document):
def validate(self): def validate(self):
self.status = 'Open'
self.validate_actual_dates() self.validate_actual_dates()
self.set_time_in_mins() self.set_time_in_mins()
self.set_status()
def validate_actual_dates(self): def validate_actual_dates(self):
if get_datetime(self.actual_start_date) > get_datetime(self.actual_end_date): if get_datetime(self.actual_start_date) > get_datetime(self.actual_end_date):
@ -48,7 +48,7 @@ class JobCard(Document):
return return
doc = frappe.get_doc('Work Order', self.get('work_order')) 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 return
for d in doc.required_items: for d in doc.required_items:
@ -104,20 +104,23 @@ class JobCard(Document):
wo.set_actual_dates() wo.set_actual_dates()
wo.save() wo.save()
def set_transferred_qty(self): def set_transferred_qty(self, update_status=False):
if not self.items: if not self.items:
self.transferred_qty = self.for_quantity if self.docstatus == 1 else 0 self.transferred_qty = self.for_quantity if self.docstatus == 1 else 0
if self.items: if self.items:
self.transferred_qty = frappe.db.get_value('Stock Entry', {'job_card': self.name, self.transferred_qty = frappe.db.get_value('Stock Entry', {
'work_order': self.work_order, 'docstatus': 1}, 'sum(fg_completed_qty)') or 0 '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) self.db_set("transferred_qty", self.transferred_qty)
qty = 0 qty = 0
if self.work_order: if self.work_order:
doc = frappe.get_doc('Work Order', 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 completed = True
for d in doc.operations: for d in doc.operations:
if d.status != 'Completed': if d.status != 'Completed':
@ -131,15 +134,28 @@ class JobCard(Document):
doc.db_set('material_transferred_for_manufacturing', qty) doc.db_set('material_transferred_for_manufacturing', qty)
self.set_status() self.set_status(update_status)
def set_status(self): def set_status(self, update_status=False):
status = 'Cancelled' if self.docstatus == 2 else 'Work In Progress' self.status = {
0: "Open",
1: "Submitted",
2: "Cancelled"
}[self.docstatus or 0]
if self.actual_start_date:
self.status = 'Work In Progress'
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: if self.for_quantity == self.transferred_qty:
status = 'Completed' self.status = 'Material Transferred'
self.db_set('status', status) if update_status:
self.db_set('status', self.status)
@frappe.whitelist() @frappe.whitelist()
def make_material_request(source_name, target_doc=None): def make_material_request(source_name, target_doc=None):

View File

@ -6,6 +6,8 @@ frappe.listview_settings['Job Card'] = {
return [__("Completed"), "green", "status,=,Completed"]; return [__("Completed"), "green", "status,=,Completed"];
} else if (doc.docstatus == 2) { } else if (doc.docstatus == 2) {
return [__("Cancelled"), "red", "status,=,Cancelled"]; return [__("Cancelled"), "red", "status,=,Cancelled"];
} else if (doc.status === "Material Transferred") {
return [__('Material Transferred'), "blue", "status,=,Material Transferred"];
} else { } else {
return [__("Open"), "red", "status,=,Open"]; return [__("Open"), "red", "status,=,Open"];
} }

View File

@ -7,9 +7,9 @@ import frappe, json
from frappe import msgprint, _ from frappe import msgprint, _
from frappe.model.document import Document from frappe.model.document import Document
from erpnext.manufacturing.doctype.bom.bom import validate_bom_no from erpnext.manufacturing.doctype.bom.bom import validate_bom_no
from frappe.utils import cstr, flt, cint, nowdate, add_days, comma_and, now_datetime from frappe.utils import cstr, flt, cint, nowdate, add_days, comma_and, now_datetime, ceil
from erpnext.manufacturing.doctype.work_order.work_order import get_item_details from erpnext.manufacturing.doctype.work_order.work_order import get_item_details
from six import string_types from six import string_types, iteritems
from erpnext.setup.doctype.item_group.item_group import get_item_group_defaults from erpnext.setup.doctype.item_group.item_group import get_item_group_defaults
class ProductionPlan(Document): class ProductionPlan(Document):
@ -372,40 +372,46 @@ class ProductionPlan(Document):
else : else :
msgprint(_("No material request created")) msgprint(_("No material request created"))
def get_exploded_items(bom_wise_item_details, company, bom_no, include_non_stock_items): def get_exploded_items(item_details, company, bom_no, include_non_stock_items, planned_qty=1):
for d in frappe.db.sql("""select bei.item_code, item.default_bom as bom, for d in frappe.db.sql("""select bei.item_code, item.default_bom as bom,
ifnull(sum(bei.stock_qty/ifnull(bom.quantity, 1)), 0) as qty, item.item_name, ifnull(sum(bei.stock_qty/ifnull(bom.quantity, 1)), 0)*%s as qty, item.item_name,
bei.description, bei.stock_uom, item.min_order_qty, bei.source_warehouse, bei.description, bei.stock_uom, item.min_order_qty, bei.source_warehouse,
item.default_material_request_type, item.min_order_qty, item_default.default_warehouse item.default_material_request_type, item.min_order_qty, item_default.default_warehouse,
item.purchase_uom, item_uom.conversion_factor
from from
`tabBOM Explosion Item` bei `tabBOM Explosion Item` bei
JOIN `tabBOM` bom ON bom.name = bei.parent JOIN `tabBOM` bom ON bom.name = bei.parent
JOIN `tabItem` item ON item.name = bei.item_code JOIN `tabItem` item ON item.name = bei.item_code
LEFT JOIN `tabItem Default` item_default LEFT JOIN `tabItem Default` item_default
ON item_default.parent = item.name and item_default.company=%s ON item_default.parent = item.name and item_default.company=%s
LEFT JOIN `tabUOM Conversion Detail` item_uom
ON item.name = item_uom.parent and item_uom.uom = item.purchase_uom
where where
bei.docstatus < 2 bei.docstatus < 2
and bom.name=%s and item.is_stock_item in (1, {0}) and bom.name=%s and item.is_stock_item in (1, {0})
group by bei.item_code, bei.stock_uom""".format(0 if include_non_stock_items else 1), group by bei.item_code, bei.stock_uom""".format(0 if include_non_stock_items else 1),
(company, bom_no), as_dict=1): (planned_qty, company, bom_no), as_dict=1):
bom_wise_item_details.setdefault(d.get('item_code'), d) item_details.setdefault(d.get('item_code'), d)
return bom_wise_item_details return item_details
def get_subitems(doc, data, bom_wise_item_details, bom_no, company, include_non_stock_items, include_subcontracted_items, parent_qty): def get_subitems(doc, data, item_details, bom_no, company, include_non_stock_items,
include_subcontracted_items, parent_qty, planned_qty=1):
items = frappe.db.sql(""" items = frappe.db.sql("""
SELECT SELECT
bom_item.item_code, default_material_request_type, item.item_name, bom_item.item_code, default_material_request_type, item.item_name,
ifnull(%(parent_qty)s * sum(bom_item.stock_qty/ifnull(bom.quantity, 1)), 0) as qty, ifnull(%(parent_qty)s * sum(bom_item.stock_qty/ifnull(bom.quantity, 1)) * %(planned_qty)s, 0) as qty,
item.is_sub_contracted_item as is_sub_contracted, bom_item.source_warehouse, item.is_sub_contracted_item as is_sub_contracted, bom_item.source_warehouse,
item.default_bom as default_bom, bom_item.description as description, item.default_bom as default_bom, bom_item.description as description,
bom_item.stock_uom as stock_uom, item.min_order_qty as min_order_qty, bom_item.stock_uom as stock_uom, item.min_order_qty as min_order_qty,
item_default.default_warehouse item_default.default_warehouse, item.purchase_uom, item_uom.conversion_factor
FROM FROM
`tabBOM Item` bom_item `tabBOM Item` bom_item
JOIN `tabBOM` bom ON bom.name = bom_item.parent JOIN `tabBOM` bom ON bom.name = bom_item.parent
JOIN tabItem item ON bom_item.item_code = item.name JOIN tabItem item ON bom_item.item_code = item.name
LEFT JOIN `tabItem Default` item_default LEFT JOIN `tabItem Default` item_default
ON item.name = item_default.parent and item_default.company = %(company)s ON item.name = item_default.parent and item_default.company = %(company)s
LEFT JOIN `tabUOM Conversion Detail` item_uom
ON item.name = item_uom.parent and item_uom.uom = item.purchase_uom
where where
bom.name = %(bom)s bom.name = %(bom)s
and bom_item.docstatus < 2 and bom_item.docstatus < 2
@ -413,45 +419,61 @@ def get_subitems(doc, data, bom_wise_item_details, bom_no, company, include_non_
group by bom_item.item_code""".format(0 if include_non_stock_items else 1),{ group by bom_item.item_code""".format(0 if include_non_stock_items else 1),{
'bom': bom_no, 'bom': bom_no,
'parent_qty': parent_qty, 'parent_qty': parent_qty,
'planned_qty': planned_qty,
'company': company 'company': company
}, as_dict=1) }, as_dict=1)
for d in items: for d in items:
if not data.get('include_exploded_items') or not d.default_bom: if not data.get('include_exploded_items') or not d.default_bom:
if d.item_code in bom_wise_item_details: if d.item_code in item_details:
bom_wise_item_details[d.item_code].qty = bom_wise_item_details[d.item_code].qty + d.qty item_details[d.item_code].qty = item_details[d.item_code].qty + d.qty
else: else:
bom_wise_item_details[d.item_code] = d item_details[d.item_code] = d
if data.get('include_exploded_items') and d.default_bom: if data.get('include_exploded_items') and d.default_bom:
if ((d.default_material_request_type in ["Manufacture", "Purchase"] and if ((d.default_material_request_type in ["Manufacture", "Purchase"] and
not d.is_sub_contracted) or (d.is_sub_contracted and include_subcontracted_items)): not d.is_sub_contracted) or (d.is_sub_contracted and include_subcontracted_items)):
if d.qty > 0: if d.qty > 0:
get_subitems(doc, data, bom_wise_item_details, d.default_bom, company, include_non_stock_items, include_subcontracted_items, d.qty) get_subitems(doc, data, item_details, d.default_bom, company,
return bom_wise_item_details include_non_stock_items, include_subcontracted_items, d.qty)
return item_details
def add_item_in_material_request_items(doc, planned_qty, ignore_existing_ordered_qty, item, row, data, warehouse, company): def get_material_request_items(row, sales_order, company, ignore_existing_ordered_qty, warehouse):
total_qty = row.qty * planned_qty total_qty = row['qty']
projected_qty, actual_qty = get_bin_details(row) projected_qty, actual_qty = get_bin_details(row)
requested_qty = 0 requested_qty = 0
if ignore_existing_ordered_qty: if ignore_existing_ordered_qty:
requested_qty = total_qty requested_qty = total_qty
else: elif total_qty > projected_qty:
requested_qty = total_qty - projected_qty requested_qty = total_qty - projected_qty
if requested_qty > 0 and requested_qty < row.min_order_qty: if requested_qty > 0 and requested_qty < row['min_order_qty']:
requested_qty = row.min_order_qty requested_qty = row['min_order_qty']
item_group_defaults = get_item_group_defaults(item, company) item_group_defaults = get_item_group_defaults(row.item_code, company)
if not row['purchase_uom']:
row['purchase_uom'] = row['stock_uom']
if row['purchase_uom'] != row['stock_uom']:
if not row['conversion_factor']:
frappe.throw(_("UOM Conversion factor ({0} -> {1}) not found for item: {2}")
.format(row['purchase_uom'], row['stock_uom'], row.item_code))
requested_qty = requested_qty / row['conversion_factor']
if frappe.db.get_value("UOM", row['purchase_uom'], "must_be_whole_number"):
requested_qty = ceil(requested_qty)
if requested_qty > 0: if requested_qty > 0:
doc.setdefault('mr_items', []).append({ return {
'item_code': item, 'item_code': row.item_code,
'item_name': row.item_name, 'item_name': row.item_name,
'quantity': requested_qty, 'quantity': requested_qty,
'warehouse': warehouse or row.source_warehouse or row.default_warehouse or item_group_defaults.get("default_warehouse"), 'warehouse': warehouse or row.get('source_warehouse') \
or row.get('default_warehouse') or item_group_defaults.get("default_warehouse"),
'actual_qty': actual_qty, 'actual_qty': actual_qty,
'min_order_qty': row.min_order_qty, 'min_order_qty': row['min_order_qty'],
'sales_order': data.get('sales_order') 'sales_order': sales_order
}) }
def get_sales_orders(self): def get_sales_orders(self):
so_filter = item_filter = "" so_filter = item_filter = ""
@ -487,8 +509,8 @@ def get_sales_orders(self):
"project": self.project, "project": self.project,
"item": self.item_code, "item": self.item_code,
"company": self.company "company": self.company
}, as_dict=1)
}, as_dict=1)
return open_so return open_so
@frappe.whitelist() @frappe.whitelist()
@ -497,56 +519,96 @@ def get_bin_details(row):
row = frappe._dict(json.loads(row)) row = frappe._dict(json.loads(row))
conditions = "" conditions = ""
warehouse = row.source_warehouse or row.default_warehouse or row.warehouse warehouse = row.get('source_warehouse') or row.get('default_warehouse')
if warehouse: if warehouse:
conditions = " and warehouse='{0}'".format(frappe.db.escape(warehouse)) lft, rgt = frappe.db.get_value("Warehouse", warehouse, ["lft", "rgt"])
conditions = " and exists(select name from `tabWarehouse` where lft >= {0} and rgt <= {1} and name=`tabBin`.warehouse)".format(lft, rgt)
item_projected_qty = frappe.db.sql(""" select ifnull(sum(projected_qty),0) as projected_qty, item_projected_qty = frappe.db.sql(""" select ifnull(sum(projected_qty),0) as projected_qty,
ifnull(sum(actual_qty),0) as actual_qty from `tabBin` ifnull(sum(actual_qty),0) as actual_qty from `tabBin`
where item_code = %(item_code)s {conditions} where item_code = %(item_code)s {conditions}
""".format(conditions=conditions), { "item_code": row.item_code }, as_list=1) """.format(conditions=conditions), { "item_code": row['item_code'] }, as_list=1)
return item_projected_qty and item_projected_qty[0] or (0,0) return item_projected_qty and item_projected_qty[0] or (0,0)
@frappe.whitelist() @frappe.whitelist()
def get_items_for_material_requests(doc, company=None): def get_items_for_material_requests(doc, sales_order=None, company=None):
if isinstance(doc, string_types): if isinstance(doc, string_types):
doc = frappe._dict(json.loads(doc)) doc = frappe._dict(json.loads(doc))
doc['mr_items'] = [] 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')
company = doc.get('company')
so_item_details = frappe._dict()
for data in po_items: for data in po_items:
warehouse = None
bom_wise_item_details = {}
if data.get('required_qty'):
planned_qty = data.get('required_qty')
bom_no = data.get('bom')
ignore_existing_ordered_qty = data.get('ignore_existing_ordered_qty')
include_non_stock_items = 1
warehouse = data.get('for_warehouse') warehouse = data.get('for_warehouse')
if data.get('include_exploded_items'): ignore_existing_ordered_qty = data.get('ignore_existing_ordered_qty') or doc.get('ignore_existing_ordered_qty')
include_subcontracted_items = 1 planned_qty = data.get('required_qty') or data.get('planned_qty')
item_details = {}
if data.get("bom") or data.get("bom_no"):
if data.get('required_qty'):
bom_no = data.get('bom')
include_non_stock_items = 1
include_subcontracted_items = 1 if data.get('include_exploded_items') else 0
else: else:
include_subcontracted_items = 0
else:
planned_qty = data.get('planned_qty')
bom_no = data.get('bom_no') bom_no = data.get('bom_no')
include_subcontracted_items = doc['include_subcontracted_items'] include_subcontracted_items = doc.get('include_subcontracted_items')
company = doc['company'] include_non_stock_items = doc.get('include_non_stock_items')
include_non_stock_items = doc['include_non_stock_items']
ignore_existing_ordered_qty = doc['ignore_existing_ordered_qty']
if not planned_qty: if not planned_qty:
frappe.throw(_("For row {0}: Enter Planned Qty").format(data.get('idx'))) frappe.throw(_("For row {0}: Enter Planned Qty").format(data.get('idx')))
if data.get('include_exploded_items') and bom_no and include_subcontracted_items: if bom_no:
if data.get('include_exploded_items') and include_subcontracted_items:
# fetch exploded items from BOM # fetch exploded items from BOM
bom_wise_item_details = get_exploded_items(bom_wise_item_details, company, bom_no, include_non_stock_items) item_details = get_exploded_items(item_details,
company, bom_no, include_non_stock_items, planned_qty=planned_qty)
else: else:
bom_wise_item_details = get_subitems(doc, data, bom_wise_item_details, bom_no, company, include_non_stock_items, include_subcontracted_items, 1) item_details = get_subitems(doc, data, item_details, bom_no, company,
for item, item_details in bom_wise_item_details.items(): include_non_stock_items, include_subcontracted_items, 1, planned_qty=planned_qty)
if item_details.qty > 0: else:
add_item_in_material_request_items(doc, planned_qty, ignore_existing_ordered_qty, item, item_details, data, warehouse, company) item_master = frappe.get_doc('Item', data['item_code']).as_dict()
purchase_uom = item_master.purchase_uom or item_master.stock_uom
conversion_factor = 0
for d in item_master.get("uoms"):
if d.uom == purchase_uom:
conversion_factor = d.conversion_factor
return doc['mr_items'] item_details[item_master.name] = frappe._dict(
{
'item_name' : item_master.item_name,
'default_bom' : doc.bom,
'purchase_uom' : purchase_uom,
'default_warehouse': item_master.default_warehouse,
'min_order_qty' : item_master.min_order_qty,
'default_material_request_type' : item_master.default_material_request_type,
'qty': planned_qty or 1,
'is_sub_contracted' : item_master.is_subcontracted_item,
'item_code' : item_master.name,
'description' : item_master.description,
'stock_uom' : item_master.stock_uom,
'conversion_factor' : conversion_factor,
}
)
if not sales_order:
sales_order = doc.get("sales_order")
for item_code, details in iteritems(item_details):
so_item_details.setdefault(sales_order, frappe._dict())
if item_code in so_item_details.get(sales_order, {}):
so_item_details[sales_order][item_code]['qty'] = so_item_details[sales_order][item_code].get("qty", 0) + flt(details.qty)
else:
so_item_details[sales_order][item_code] = details
mr_items = []
for sales_order, item_code in iteritems(so_item_details):
item_dict = so_item_details[sales_order]
for details in item_dict.values():
if details.qty > 0:
items = get_material_request_items(details, sales_order, company,
ignore_existing_ordered_qty, warehouse)
if items:
mr_items.append(items)
return mr_items

View File

@ -1,552 +0,0 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
import frappe
from frappe.utils import cstr, flt, cint, nowdate, add_days, comma_and
from frappe import msgprint, _
from frappe.model.document import Document
from erpnext.manufacturing.doctype.bom.bom import validate_bom_no
from erpnext.manufacturing.doctype.work_order.work_order import get_item_details
class ProductionPlanningTool(Document):
def clear_table(self, table_name):
self.set(table_name, [])
def validate_company(self):
if not self.company:
frappe.throw(_("Please enter Company"))
def get_open_sales_orders(self):
""" Pull sales orders which are pending to deliver based on criteria selected"""
so_filter = item_filter = ""
if self.from_date:
so_filter += " and so.transaction_date >= %(from_date)s"
if self.to_date:
so_filter += " and so.transaction_date <= %(to_date)s"
if self.customer:
so_filter += " and so.customer = %(customer)s"
if self.project:
so_filter += " and so.project = %(project)s"
if self.fg_item:
item_filter += " and so_item.item_code = %(item)s"
open_so = frappe.db.sql("""
select distinct so.name, so.transaction_date, so.customer, so.base_grand_total
from `tabSales Order` so, `tabSales Order Item` so_item
where so_item.parent = so.name
and so.docstatus = 1 and so.status not in ("Stopped", "Closed")
and so.company = %(company)s
and so_item.qty > so_item.delivered_qty {0} {1}
and (exists (select name from `tabBOM` bom where bom.item=so_item.item_code
and bom.is_active = 1)
or exists (select name from `tabPacked Item` pi
where pi.parent = so.name and pi.parent_item = so_item.item_code
and exists (select name from `tabBOM` bom where bom.item=pi.item_code
and bom.is_active = 1)))
""".format(so_filter, item_filter), {
"from_date": self.from_date,
"to_date": self.to_date,
"customer": self.customer,
"project": self.project,
"item": self.fg_item,
"company": self.company
}, as_dict=1)
self.add_so_in_table(open_so)
def add_so_in_table(self, open_so):
""" Add sales orders in the table"""
self.clear_table("sales_orders")
so_list = []
for r in open_so:
if cstr(r['name']) not in so_list:
pp_so = self.append('sales_orders', {})
pp_so.sales_order = r['name']
pp_so.sales_order_date = cstr(r['transaction_date'])
pp_so.customer = cstr(r['customer'])
pp_so.grand_total = flt(r['base_grand_total'])
def get_pending_material_requests(self):
""" Pull Material Requests that are pending based on criteria selected"""
mr_filter = item_filter = ""
if self.from_date:
mr_filter += " and mr.transaction_date >= %(from_date)s"
if self.to_date:
mr_filter += " and mr.transaction_date <= %(to_date)s"
if self.warehouse:
mr_filter += " and mr_item.warehouse = %(warehouse)s"
if self.fg_item:
item_filter += " and mr_item.item_code = %(item)s"
pending_mr = frappe.db.sql("""
select distinct mr.name, mr.transaction_date
from `tabMaterial Request` mr, `tabMaterial Request Item` mr_item
where mr_item.parent = mr.name
and mr.material_request_type = "Manufacture"
and mr.docstatus = 1
and mr_item.qty > ifnull(mr_item.ordered_qty,0) {0} {1}
and (exists (select name from `tabBOM` bom where bom.item=mr_item.item_code
and bom.is_active = 1))
""".format(mr_filter, item_filter), {
"from_date": self.from_date,
"to_date": self.to_date,
"warehouse": self.warehouse,
"item": self.fg_item
}, as_dict=1)
self.add_mr_in_table(pending_mr)
def add_mr_in_table(self, pending_mr):
""" Add Material Requests in the table"""
self.clear_table("material_requests")
mr_list = []
for r in pending_mr:
if cstr(r['name']) not in mr_list:
mr = self.append('material_requests', {})
mr.material_request = r['name']
mr.material_request_date = cstr(r['transaction_date'])
def get_items(self):
if self.get_items_from == "Sales Order":
self.get_so_items()
elif self.get_items_from == "Material Request":
self.get_mr_items()
def get_so_items(self):
so_list = [d.sales_order for d in self.get('sales_orders') if d.sales_order]
if not so_list:
msgprint(_("Please enter Sales Orders in the above table"))
return []
item_condition = ""
if self.fg_item:
item_condition = ' and so_item.item_code = "{0}"'.format(frappe.db.escape(self.fg_item))
items = frappe.db.sql("""select distinct parent, item_code, warehouse,
(qty - delivered_qty)*conversion_factor as pending_qty
from `tabSales Order Item` so_item
where parent in (%s) and docstatus = 1 and qty > delivered_qty
and exists (select name from `tabBOM` bom where bom.item=so_item.item_code
and bom.is_active = 1) %s""" % \
(", ".join(["%s"] * len(so_list)), item_condition), tuple(so_list), as_dict=1)
if self.fg_item:
item_condition = ' and pi.item_code = "{0}"'.format(frappe.db.escape(self.fg_item))
packed_items = frappe.db.sql("""select distinct pi.parent, pi.item_code, pi.warehouse as warehouse,
(((so_item.qty - so_item.delivered_qty) * pi.qty) / so_item.qty)
as pending_qty
from `tabSales Order Item` so_item, `tabPacked Item` pi
where so_item.parent = pi.parent and so_item.docstatus = 1
and pi.parent_item = so_item.item_code
and so_item.parent in (%s) and so_item.qty > so_item.delivered_qty
and exists (select name from `tabBOM` bom where bom.item=pi.item_code
and bom.is_active = 1) %s""" % \
(", ".join(["%s"] * len(so_list)), item_condition), tuple(so_list), as_dict=1)
self.add_items(items + packed_items)
def get_mr_items(self):
mr_list = [d.material_request for d in self.get('material_requests') if d.material_request]
if not mr_list:
msgprint(_("Please enter Material Requests in the above table"))
return []
item_condition = ""
if self.fg_item:
item_condition = ' and mr_item.item_code = "' + frappe.db.escape(self.fg_item, percent=False) + '"'
items = frappe.db.sql("""select distinct parent, name, item_code, warehouse,
(qty - ordered_qty) as pending_qty
from `tabMaterial Request Item` mr_item
where parent in (%s) and docstatus = 1 and qty > ordered_qty
and exists (select name from `tabBOM` bom where bom.item=mr_item.item_code
and bom.is_active = 1) %s""" % \
(", ".join(["%s"] * len(mr_list)), item_condition), tuple(mr_list), as_dict=1)
self.add_items(items)
def add_items(self, items):
self.clear_table("items")
for p in items:
item_details = get_item_details(p['item_code'])
pi = self.append('items', {})
pi.warehouse = p['warehouse']
pi.item_code = p['item_code']
pi.description = item_details and item_details.description or ''
pi.stock_uom = item_details and item_details.stock_uom or ''
pi.bom_no = item_details and item_details.bom_no or ''
pi.planned_qty = flt(p['pending_qty'])
pi.pending_qty = flt(p['pending_qty'])
if self.get_items_from == "Sales Order":
pi.sales_order = p['parent']
elif self.get_items_from == "Material Request":
pi.material_request = p['parent']
pi.material_request_item = p['name']
def validate_data(self):
self.validate_company()
for d in self.get('items'):
if not d.bom_no:
frappe.throw(_("Please select BOM for Item in Row {0}".format(d.idx)))
else:
validate_bom_no(d.item_code, d.bom_no)
if not flt(d.planned_qty):
frappe.throw(_("Please enter Planned Qty for Item {0} at row {1}").format(d.item_code, d.idx))
def raise_work_orders(self):
"""It will raise work order (Draft) for all distinct FG items"""
self.validate_data()
from erpnext.utilities.transaction_base import validate_uom_is_integer
validate_uom_is_integer(self, "stock_uom", "planned_qty")
items = self.get_production_items()
wo_list = []
frappe.flags.mute_messages = True
for key in items:
work_order = self.create_work_order(items[key])
if work_order:
wo_list.append(work_order)
frappe.flags.mute_messages = False
if wo_list:
wo_list = ["""<a href="#Form/Work Order/%s" target="_blank">%s</a>""" % \
(p, p) for p in wo_list]
msgprint(_("{0} created").format(comma_and(wo_list)))
else :
msgprint(_("No Work Orders created"))
def get_production_items(self):
item_dict = {}
for d in self.get("items"):
item_details= {
"production_item" : d.item_code,
"sales_order" : d.sales_order,
"material_request" : d.material_request,
"material_request_item" : d.material_request_item,
"bom_no" : d.bom_no,
"description" : d.description,
"stock_uom" : d.stock_uom,
"company" : self.company,
"wip_warehouse" : "",
"fg_warehouse" : d.warehouse,
"status" : "Draft",
"project" : frappe.db.get_value("Sales Order", d.sales_order, "project")
}
""" Club similar BOM and item for processing in case of Sales Orders """
if self.get_items_from == "Material Request":
item_details.update({
"qty": d.planned_qty
})
item_dict[(d.item_code, d.material_request_item, d.warehouse)] = item_details
else:
item_details.update({
"qty":flt(item_dict.get((d.item_code, d.sales_order, d.warehouse),{})
.get("qty")) + flt(d.planned_qty)
})
item_dict[(d.item_code, d.sales_order, d.warehouse)] = item_details
return item_dict
def create_work_order(self, item_dict):
"""Create work order. Called from Production Planning Tool"""
from erpnext.manufacturing.doctype.work_order.work_order import OverProductionError, get_default_warehouse
warehouse = get_default_warehouse()
wo = frappe.new_doc("Work Order")
wo.update(item_dict)
wo.set_work_order_operations()
if warehouse:
wo.wip_warehouse = warehouse.get('wip_warehouse')
if not wo.fg_warehouse:
wo.fg_warehouse = warehouse.get('fg_warehouse')
try:
wo.insert()
return wo.name
except OverProductionError:
pass
def get_so_wise_planned_qty(self):
"""
bom_dict {
bom_no: ['sales_order', 'qty']
}
"""
bom_dict = {}
for d in self.get("items"):
if self.get_items_from == "Material Request":
bom_dict.setdefault(d.bom_no, []).append([d.material_request_item, flt(d.planned_qty)])
else:
bom_dict.setdefault(d.bom_no, []).append([d.sales_order, flt(d.planned_qty)])
return bom_dict
def download_raw_materials(self):
""" Create csv data for required raw material to produce finished goods"""
self.validate_data()
bom_dict = self.get_so_wise_planned_qty()
self.get_raw_materials(bom_dict)
return self.get_csv()
def get_raw_materials(self, bom_dict,non_stock_item=0):
""" Get raw materials considering sub-assembly items
{
"item_code": [qty_required, description, stock_uom, min_order_qty]
}
"""
item_list = []
precision = frappe.get_precision("BOM Item", "stock_qty")
for bom, so_wise_qty in bom_dict.items():
bom_wise_item_details = {}
if self.use_multi_level_bom and self.only_raw_materials and self.include_subcontracted:
# get all raw materials with sub assembly childs
# Did not use qty_consumed_per_unit in the query, as it leads to rounding loss
for d in frappe.db.sql("""select fb.item_code,
ifnull(sum(fb.stock_qty/ifnull(bom.quantity, 1)), 0) as qty,
fb.description, fb.stock_uom, item.min_order_qty
from `tabBOM Explosion Item` fb, `tabBOM` bom, `tabItem` item
where bom.name = fb.parent and item.name = fb.item_code
and (item.is_sub_contracted_item = 0 or ifnull(item.default_bom, "")="")
""" + ("and item.is_stock_item = 1","")[non_stock_item] + """
and fb.docstatus<2 and bom.name=%(bom)s
group by fb.item_code, fb.stock_uom""", {"bom":bom}, as_dict=1):
bom_wise_item_details.setdefault(d.item_code, d)
else:
# Get all raw materials considering SA items as raw materials,
# so no childs of SA items
bom_wise_item_details = self.get_subitems(bom_wise_item_details, bom,1, \
self.use_multi_level_bom,self.only_raw_materials, self.include_subcontracted,non_stock_item)
for item, item_details in bom_wise_item_details.items():
for so_qty in so_wise_qty:
item_list.append([item, flt(flt(item_details.qty) * so_qty[1], precision),
item_details.description, item_details.stock_uom, item_details.min_order_qty,
so_qty[0]])
self.make_items_dict(item_list)
def get_subitems(self,bom_wise_item_details, bom, parent_qty, include_sublevel, only_raw, supply_subs,non_stock_item=0):
items = frappe.db.sql("""
SELECT
bom_item.item_code,
default_material_request_type,
ifnull(%(parent_qty)s * sum(bom_item.stock_qty/ifnull(bom.quantity, 1)), 0) as qty,
item.is_sub_contracted_item as is_sub_contracted,
item.default_bom as default_bom,
bom_item.description as description,
bom_item.stock_uom as stock_uom,
item.min_order_qty as min_order_qty
FROM
`tabBOM Item` bom_item,
`tabBOM` bom,
tabItem item
where
bom.name = bom_item.parent
and bom.name = %(bom)s
and bom_item.docstatus < 2
and bom_item.item_code = item.name
""" + ("and item.is_stock_item = 1", "")[non_stock_item] + """
group by bom_item.item_code""", {"bom": bom, "parent_qty": parent_qty}, as_dict=1)
for d in items:
if ((d.default_material_request_type == "Purchase"
and not (d.is_sub_contracted and only_raw and include_sublevel))
or (d.default_material_request_type == "Manufacture" and not only_raw)):
if d.item_code in bom_wise_item_details:
bom_wise_item_details[d.item_code].qty = bom_wise_item_details[d.item_code].qty + d.qty
else:
bom_wise_item_details[d.item_code] = d
if include_sublevel and d.default_bom:
if ((d.default_material_request_type == "Purchase" and d.is_sub_contracted and supply_subs)
or (d.default_material_request_type == "Manufacture")):
my_qty = 0
projected_qty = self.get_item_projected_qty(d.item_code)
if self.create_material_requests_for_all_required_qty:
my_qty = d.qty
else:
total_required_qty = flt(bom_wise_item_details.get(d.item_code, frappe._dict()).qty)
if (total_required_qty - d.qty) < projected_qty:
my_qty = total_required_qty - projected_qty
else:
my_qty = d.qty
if my_qty > 0:
self.get_subitems(bom_wise_item_details,
d.default_bom, my_qty, include_sublevel, only_raw, supply_subs)
return bom_wise_item_details
def make_items_dict(self, item_list):
if not getattr(self, "item_dict", None):
self.item_dict = {}
for i in item_list:
self.item_dict.setdefault(i[0], []).append([flt(i[1]), i[2], i[3], i[4], i[5]])
def get_csv(self):
item_list = [['Item Code', 'Description', 'Stock UOM', 'Required Qty', 'Warehouse',
'Quantity Requested for Purchase', 'Ordered Qty', 'Actual Qty']]
for item in self.item_dict:
total_qty = sum([flt(d[0]) for d in self.item_dict[item]])
item_list.append([item, self.item_dict[item][0][1], self.item_dict[item][0][2], total_qty])
item_qty = frappe.db.sql("""select warehouse, indented_qty, ordered_qty, actual_qty
from `tabBin` where item_code = %s""", item, as_dict=1)
i_qty, o_qty, a_qty = 0, 0, 0
for w in item_qty:
i_qty, o_qty, a_qty = i_qty + flt(w.indented_qty), o_qty + \
flt(w.ordered_qty), a_qty + flt(w.actual_qty)
item_list.append(['', '', '', '', w.warehouse, flt(w.indented_qty),
flt(w.ordered_qty), flt(w.actual_qty)])
if item_qty:
item_list.append(['', '', '', '', 'Total', i_qty, o_qty, a_qty])
else:
item_list.append(['', '', '', '', 'Total', 0, 0, 0])
return item_list
def raise_material_requests(self):
"""
Raise Material Request if projected qty is less than qty required
Requested qty should be shortage qty considering minimum order qty
"""
self.validate_data()
if not self.purchase_request_for_warehouse:
frappe.throw(_("Please enter Warehouse for which Material Request will be raised"))
bom_dict = self.get_so_wise_planned_qty()
self.get_raw_materials(bom_dict,self.create_material_requests_non_stock_request)
if self.item_dict:
self.create_material_request()
def get_requested_items(self):
items_to_be_requested = frappe._dict()
if not self.create_material_requests_for_all_required_qty:
item_projected_qty = self.get_projected_qty()
for item, so_item_qty in self.item_dict.items():
total_qty = sum([flt(d[0]) for d in so_item_qty])
requested_qty = 0
if self.create_material_requests_for_all_required_qty:
requested_qty = total_qty
elif total_qty > item_projected_qty.get(item, 0):
# shortage
requested_qty = total_qty - flt(item_projected_qty.get(item))
# consider minimum order qty
if requested_qty and requested_qty < flt(so_item_qty[0][3]):
requested_qty = flt(so_item_qty[0][3])
# distribute requested qty SO wise
for item_details in so_item_qty:
if requested_qty:
sales_order = item_details[4] or "No Sales Order"
if self.get_items_from == "Material Request":
sales_order = "No Sales Order"
if requested_qty <= item_details[0]:
adjusted_qty = requested_qty
else:
adjusted_qty = item_details[0]
items_to_be_requested.setdefault(item, {}).setdefault(sales_order, 0)
items_to_be_requested[item][sales_order] += adjusted_qty
requested_qty -= adjusted_qty
else:
break
# requested qty >= total so qty, due to minimum order qty
if requested_qty:
items_to_be_requested.setdefault(item, {}).setdefault("No Sales Order", 0)
items_to_be_requested[item]["No Sales Order"] += requested_qty
return items_to_be_requested
def get_item_projected_qty(self,item):
conditions = ""
if self.purchase_request_for_warehouse:
conditions = " and warehouse='{0}'".format(frappe.db.escape(self.purchase_request_for_warehouse))
item_projected_qty = frappe.db.sql("""
select ifnull(sum(projected_qty),0) as qty
from `tabBin`
where item_code = %(item_code)s {conditions}
""".format(conditions=conditions), { "item_code": item }, as_dict=1)
return item_projected_qty[0].qty
def get_projected_qty(self):
items = self.item_dict.keys()
item_projected_qty = frappe.db.sql("""select item_code, sum(projected_qty)
from `tabBin` where item_code in (%s) and warehouse=%s group by item_code""" %
(", ".join(["%s"]*len(items)), '%s'), tuple(items + [self.purchase_request_for_warehouse]))
return dict(item_projected_qty)
def create_material_request(self):
items_to_be_requested = self.get_requested_items()
material_request_list = []
if items_to_be_requested:
for item in items_to_be_requested:
item_wrapper = frappe.get_doc("Item", item)
material_request = frappe.new_doc("Material Request")
material_request.update({
"transaction_date": nowdate(),
"status": "Draft",
"company": self.company,
"requested_by": frappe.session.user,
"schedule_date": add_days(nowdate(), cint(item_wrapper.lead_time_days)),
})
material_request.update({"material_request_type": item_wrapper.default_material_request_type})
for sales_order, requested_qty in items_to_be_requested[item].items():
material_request.append("items", {
"doctype": "Material Request Item",
"__islocal": 1,
"item_code": item,
"item_name": item_wrapper.item_name,
"description": item_wrapper.description,
"uom": item_wrapper.stock_uom,
"item_group": item_wrapper.item_group,
"brand": item_wrapper.brand,
"qty": requested_qty,
"schedule_date": add_days(nowdate(), cint(item_wrapper.lead_time_days)),
"warehouse": self.purchase_request_for_warehouse,
"sales_order": sales_order if sales_order!="No Sales Order" else None,
"project": frappe.db.get_value("Sales Order", sales_order, "project") \
if sales_order!="No Sales Order" else None
})
material_request.flags.ignore_permissions = 1
material_request.submit()
material_request_list.append(material_request.name)
if material_request_list:
message = ["""<a href="#Form/Material Request/%s" target="_blank">%s</a>""" % \
(p, p) for p in material_request_list]
msgprint(_("Material Requests {0} created").format(comma_and(message)))
else:
msgprint(_("Nothing to request"))

View File

@ -306,7 +306,7 @@ class TestWorkOrder(unittest.TestCase):
items = {'Finished Good Transfer Item': 1, '_Test FG Item': 1, '_Test FG Item 1': 0} items = {'Finished Good Transfer Item': 1, '_Test FG Item': 1, '_Test FG Item 1': 0}
for item, allow_transfer in items.items(): for item, allow_transfer in items.items():
make_item(item, { make_item(item, {
'allow_transfer_for_manufacture': allow_transfer 'include_item_in_manufacturing': allow_transfer
}) })
fg_item = 'Finished Good Transfer Item' fg_item = 'Finished Good Transfer Item'

View File

@ -112,12 +112,21 @@ frappe.ui.form.on("Work Order", {
frm.trigger('show_progress'); 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.doc.qty != frm.doc.material_transferred_for_manufacturing) {
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.add_custom_button(__('Make Job Card'), () => {
frm.trigger("make_job_card") frm.trigger("make_job_card")
}).addClass('btn-primary'); }).addClass('btn-primary');
} }
}
if(frm.doc.required_items && frm.doc.allow_alternative_item) { if(frm.doc.required_items && frm.doc.allow_alternative_item) {
const has_alternative = frm.doc.required_items.find(i => i.allow_alternative_item === 1); const has_alternative = frm.doc.required_items.find(i => i.allow_alternative_item === 1);
@ -294,7 +303,7 @@ frappe.ui.form.on("Work Order", {
frm.trigger('set_sales_order'); frm.trigger('set_sales_order');
erpnext.in_production_item_onchange = true; erpnext.in_production_item_onchange = true;
$.each(["description", "stock_uom", "project", "bom_no", $.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]); frm.set_value(field, r.message[field]);
}); });
@ -340,9 +349,8 @@ frappe.ui.form.on("Work Order", {
before_submit: function(frm) { before_submit: function(frm) {
frm.toggle_reqd(["fg_warehouse", "wip_warehouse"], true); frm.toggle_reqd(["fg_warehouse", "wip_warehouse"], true);
frm.fields_dict.required_items.grid.toggle_reqd("source_warehouse", true); frm.fields_dict.required_items.grid.toggle_reqd("source_warehouse", true);
if (frm.doc.operations) { frm.toggle_reqd("transfer_material_against", frm.doc.operations);
frm.fields_dict.operations.grid.toggle_reqd("workstation", true); frm.fields_dict.operations.grid.toggle_reqd("workstation", frm.doc.operations);
}
}, },
set_sales_order: function(frm) { set_sales_order: function(frm) {
@ -425,7 +433,7 @@ erpnext.work_order = {
} }
const show_start_btn = (frm.doc.skip_transfer 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 (show_start_btn){
if ((flt(doc.material_transferred_for_manufacturing) < flt(doc.qty)) if ((flt(doc.material_transferred_for_manufacturing) < flt(doc.qty))

View File

@ -1,5 +1,6 @@
{ {
"allow_copy": 0, "allow_copy": 0,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0, "allow_guest_to_view": 0,
"allow_import": 1, "allow_import": 1,
"allow_rename": 0, "allow_rename": 0,
@ -183,6 +184,38 @@
"translatable": 0, "translatable": 0,
"unique": 0 "unique": 0
}, },
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"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_bulk_edit": 0,
"allow_in_quick_entry": 0, "allow_in_quick_entry": 0,
@ -223,7 +256,8 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fieldname": "allow_alternative_item", "description": "Check if material transfer entry is not required",
"fieldname": "skip_transfer",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
@ -232,7 +266,7 @@
"in_global_search": 0, "in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 0, "in_standard_filter": 0,
"label": "Allow Alternative Item", "label": "Skip Material Transfer",
"length": 0, "length": 0,
"no_copy": 0, "no_copy": 0,
"permlevel": 0, "permlevel": 0,
@ -486,39 +520,6 @@
"translatable": 0, "translatable": 0,
"unique": 0 "unique": 0
}, },
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"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_bulk_edit": 0,
"allow_in_quick_entry": 0, "allow_in_quick_entry": 0,
@ -552,39 +553,6 @@
"translatable": 0, "translatable": 0,
"unique": 0 "unique": 0
}, },
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"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_bulk_edit": 0,
"allow_in_quick_entry": 0, "allow_in_quick_entry": 0,
@ -1070,6 +1038,41 @@
"translatable": 0, "translatable": 0,
"unique": 0 "unique": 0
}, },
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"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_bulk_edit": 0,
"allow_in_quick_entry": 0, "allow_in_quick_entry": 0,
@ -1672,7 +1675,7 @@
"issingle": 0, "issingle": 0,
"istable": 0, "istable": 0,
"max_attachments": 0, "max_attachments": 0,
"modified": "2018-09-05 06:28:22.983369", "modified": "2018-12-13 15:33:12.490710",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Manufacturing", "module": "Manufacturing",
"name": "Work Order", "name": "Work Order",

View File

@ -191,7 +191,7 @@ class WorkOrder(Document):
for purpose, fieldname in (("Manufacture", "produced_qty"), for purpose, fieldname in (("Manufacture", "produced_qty"),
("Material Transfer for Manufacture", "material_transferred_for_manufacturing")): ("Material Transfer for Manufacture", "material_transferred_for_manufacturing")):
if (purpose == 'Material Transfer for Manufacture' and 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 continue
qty = flt(frappe.db.sql("""select sum(fg_completed_qty) qty = flt(frappe.db.sql("""select sum(fg_completed_qty)
@ -459,7 +459,7 @@ class WorkOrder(Document):
'allow_alternative_item': item.allow_alternative_item, 'allow_alternative_item': item.allow_alternative_item,
'required_qty': item.qty, 'required_qty': item.qty,
'source_warehouse': item.source_warehouse or item.default_warehouse, '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() self.set_available_qty()
@ -564,11 +564,11 @@ def get_item_details(item, project = None):
frappe.throw(_("Default BOM for {0} not found").format(item)) frappe.throw(_("Default BOM for {0} not found").format(item))
bom_data = frappe.db.get_value('BOM', res['bom_no'], 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['project'] = project or bom_data.project
res['allow_alternative_item'] = bom_data.allow_alternative_item 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"])) res.update(check_if_scrap_warehouse_mandatory(res["bom_no"]))
return res return res
@ -682,7 +682,7 @@ def create_job_card(work_order, row, qty=0, auto_create=False):
'wip_warehouse': work_order.wip_warehouse '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() doc.get_required_items()
if auto_create: if auto_create:

View File

@ -1,5 +1,6 @@
{ {
"allow_copy": 0, "allow_copy": 0,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0, "allow_guest_to_view": 0,
"allow_import": 0, "allow_import": 0,
"allow_rename": 0, "allow_rename": 0,
@ -342,7 +343,7 @@
"bold": 0, "bold": 0,
"collapsible": 0, "collapsible": 0,
"columns": 0, "columns": 0,
"fieldname": "allow_transfer_for_manufacture", "fieldname": "include_item_in_manufacturing",
"fieldtype": "Check", "fieldtype": "Check",
"hidden": 0, "hidden": 0,
"ignore_user_permissions": 0, "ignore_user_permissions": 0,
@ -351,7 +352,7 @@
"in_global_search": 0, "in_global_search": 0,
"in_list_view": 0, "in_list_view": 0,
"in_standard_filter": 0, "in_standard_filter": 0,
"label": "Allow Transfer for Manufacture", "label": "Include Item In Manufacturing",
"length": 0, "length": 0,
"no_copy": 0, "no_copy": 0,
"permlevel": 0, "permlevel": 0,
@ -506,7 +507,7 @@
"issingle": 0, "issingle": 0,
"istable": 1, "istable": 1,
"max_attachments": 0, "max_attachments": 0,
"modified": "2018-10-04 16:16:54.237829", "modified": "2018-11-20 19:04:38.508839",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Manufacturing", "module": "Manufacturing",
"name": "Work Order Item", "name": "Work Order Item",

View File

@ -1,9 +1,9 @@
execute:import unidecode # new requirement execute:import unidecode # new requirement
erpnext.patches.v8_0.move_perpetual_inventory_setting erpnext.patches.v8_0.move_perpetual_inventory_setting
erpnext.patches.v11_0.rename_production_order_to_work_order
erpnext.patches.v11_0.refactor_naming_series erpnext.patches.v11_0.refactor_naming_series
erpnext.patches.v11_0.refactor_autoname_naming erpnext.patches.v11_0.refactor_autoname_naming
erpnext.patches.v10_0.rename_schools_to_education erpnext.patches.v10_0.rename_schools_to_education
erpnext.patches.v11_0.rename_production_order_to_work_order
erpnext.patches.v4_0.validate_v3_patch erpnext.patches.v4_0.validate_v3_patch
erpnext.patches.v4_0.fix_employee_user_id erpnext.patches.v4_0.fix_employee_user_id
erpnext.patches.v4_0.remove_employee_role_if_no_employee erpnext.patches.v4_0.remove_employee_role_if_no_employee
@ -495,7 +495,7 @@ erpnext.patches.v10_0.set_b2c_limit
erpnext.patches.v10_0.update_translatable_fields erpnext.patches.v10_0.update_translatable_fields
erpnext.patches.v10_0.rename_offer_letter_to_job_offer erpnext.patches.v10_0.rename_offer_letter_to_job_offer
execute:frappe.delete_doc('DocType', 'Production Planning Tool', ignore_missing=True) 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.v10_0.add_default_cash_flow_mappers
erpnext.patches.v11_0.make_quality_inspection_template erpnext.patches.v11_0.make_quality_inspection_template
erpnext.patches.v10_0.update_status_for_multiple_source_in_po erpnext.patches.v10_0.update_status_for_multiple_source_in_po
@ -579,3 +579,5 @@ erpnext.patches.v10_0.update_user_image_in_employee
erpnext.patches.v11_0.update_delivery_trip_status erpnext.patches.v11_0.update_delivery_trip_status
erpnext.patches.v10_0.repost_gle_for_purchase_receipts_with_rejected_items 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.set_missing_gst_hsn_code
erpnext.patches.v11_0.rename_bom_wo_fields
erpnext.patches.v11_0.rename_additional_salary_component_additional_salary

View File

@ -6,6 +6,7 @@ import frappe
def execute(): def execute():
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")
frappe.reload_doc("hr", "doctype", "daily_work_summary_group_user") frappe.reload_doc("hr", "doctype", "daily_work_summary_group_user")
@ -32,11 +33,9 @@ def execute():
new_group.flags.ignore_permissions = True new_group.flags.ignore_permissions = True
new_group.flags.ignore_validate = True new_group.flags.ignore_validate = True
new_group.insert(ignore_if_duplicate = True) new_group.insert(ignore_if_duplicate = True)
frappe.delete_doc("Daily Work Summary Settings")
frappe.delete_doc("Daily Work Summary Settings Company")
def get_setting_companies(): frappe.delete_doc("DocType", "Daily Work Summary Settings")
return frappe.db.sql("select * from `tabDaily Work Summary Settings Company`", as_dict=True) frappe.delete_doc("DocType", "Daily Work Summary Settings Company")
def get_previous_setting(): def get_previous_setting():
@ -47,3 +46,6 @@ def get_previous_setting():
obj[field] = value obj[field] = value
obj["companies"] = get_setting_companies() obj["companies"] = get_setting_companies()
return obj return obj
def get_setting_companies():
return frappe.db.sql("select * from `tabDaily Work Summary Settings Company`", as_dict=True)

View File

@ -0,0 +1,10 @@
import frappe
# this patch should have been included with this PR https://github.com/frappe/erpnext/pull/14302
def execute():
if frappe.db.table_exists("Additional Salary Component"):
if not frappe.db.table_exists("Additional Salary"):
frappe.rename_doc("DocType", "Additional Salary Component", "Additional Salary")
frappe.delete_doc('DocType', "Additional Salary Component")

View File

@ -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))

View File

@ -1,3 +1,4 @@
from __future__ import unicode_literals
import frappe import frappe
from frappe.model.rename_doc import rename_doc from frappe.model.rename_doc import rename_doc
from frappe.model.utils.rename_field import rename_field from frappe.model.utils.rename_field import rename_field

View File

@ -1,15 +1,11 @@
import frappe 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 # Skips user permission check for doctypes where department link field was recently added
# https://github.com/frappe/erpnext/pull/14121 # https://github.com/frappe/erpnext/pull/14121
def execute(): def execute():
user_permissions = frappe.get_all("User Permission",
filters=[['allow', '=', 'Department']],
fields=['name', 'skip_for_doctype'])
doctypes_to_skip = [] doctypes_to_skip = []
for doctype in ['Appraisal', 'Leave Allocation', 'Expense Claim', 'Instructor', 'Salary Slip', for doctype in ['Appraisal', 'Leave Allocation', 'Expense Claim', 'Instructor', 'Salary Slip',
'Attendance', 'Training Feedback', 'Training Result Employee', 'Attendance', 'Training Feedback', 'Training Result Employee',
'Leave Application', 'Employee Advance', 'Activity Cost', 'Training Event Employee', 'Leave Application', 'Employee Advance', 'Activity Cost', 'Training Event Employee',
@ -17,12 +13,48 @@ def execute():
if frappe.db.exists('Custom Field', { 'dt': doctype, 'fieldname': 'department'}): continue if frappe.db.exists('Custom Field', { 'dt': doctype, 'fieldname': 'department'}): continue
doctypes_to_skip.append(doctype) doctypes_to_skip.append(doctype)
for perm in user_permissions: frappe.reload_doctype('User Permission')
skip_for_doctype = perm.get('skip_for_doctype')
skip_for_doctype = skip_for_doctype.split('\n') + doctypes_to_skip user_permissions = frappe.get_all("User Permission",
skip_for_doctype = set(skip_for_doctype) # to remove duplicates filters=[['allow', '=', 'Department'], ['applicable_for', 'in', [None] + doctypes_to_skip]],
skip_for_doctype = '\n'.join(skip_for_doctype) # convert back to string fields=['name', 'applicable_for'])
frappe.set_value('User Permission', perm.name, 'skip_for_doctype', skip_for_doctype) user_permissions_to_delete = []
new_user_permissions_list = []
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))
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))

View File

@ -6,7 +6,7 @@ import frappe
def execute(): def execute():
frappe.reload_doc('stock', 'doctype', 'item') 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""") where ifnull(is_stock_item, 0) = 1""")
for doctype in ['BOM Item', 'Work Order Item', 'BOM Explosion Item']: for doctype in ['BOM Item', 'Work Order Item', 'BOM Explosion Item']:
@ -14,7 +14,7 @@ def execute():
frappe.db.sql(""" update `tab{0}` child, tabItem item frappe.db.sql(""" update `tab{0}` child, tabItem item
set set
child.allow_transfer_for_manufacture = 1 child.include_item_in_manufacturing = 1
where where
child.item_code = item.name and ifnull(item.is_stock_item, 0) = 1 child.item_code = item.name and ifnull(item.is_stock_item, 0) = 1
""".format(doctype)) """.format(doctype))

View File

@ -32,7 +32,7 @@ def execute():
'user': user, 'user': user,
'default': 1 'default': 1
}) })
_doc.pos_profile_name = user + ' - ' + _doc.company
_doc.flags.ignore_validate = True _doc.flags.ignore_validate = True
_doc.flags.ignore_mandatory = True _doc.flags.ignore_mandatory = True
_doc.save() _doc.save()

Some files were not shown because too many files have changed in this diff Show More