Merge branch 'develop' of github.com:frappe/erpnext into call-summary-dialog
This commit is contained in:
commit
19e4fde737
25
.travis.yml
25
.travis.yml
@ -3,6 +3,11 @@ dist: trusty
|
|||||||
|
|
||||||
python:
|
python:
|
||||||
- "2.7"
|
- "2.7"
|
||||||
|
- "3.6"
|
||||||
|
|
||||||
|
env:
|
||||||
|
- TEST_TYPE="Server Side Test"
|
||||||
|
- TEST_TYPE="Patch Test"
|
||||||
|
|
||||||
services:
|
services:
|
||||||
- mysql
|
- mysql
|
||||||
@ -39,18 +44,8 @@ before_script:
|
|||||||
- bench start &
|
- bench start &
|
||||||
- sleep 10
|
- sleep 10
|
||||||
|
|
||||||
jobs:
|
script:
|
||||||
include:
|
- bash $TRAVIS_BUILD_DIR/travis/run-tests.sh
|
||||||
- stage: test
|
|
||||||
script:
|
after_script:
|
||||||
- set -e
|
- coveralls -b apps/erpnext -d ../../sites/.coverage
|
||||||
- bench run-tests --app erpnext --coverage
|
|
||||||
after_script:
|
|
||||||
- coveralls -b apps/erpnext -d ../../sites/.coverage
|
|
||||||
env: Server Side Test
|
|
||||||
- # stage
|
|
||||||
script:
|
|
||||||
- wget http://build.erpnext.com/20171108_190013_955977f8_database.sql.gz
|
|
||||||
- bench --force restore ~/frappe-bench/20171108_190013_955977f8_database.sql.gz --mariadb-root-password travis
|
|
||||||
- bench migrate
|
|
||||||
env: Patch Testing
|
|
||||||
|
@ -49,7 +49,7 @@ The ERPNext code is licensed as GNU General Public License (v3) and the Document
|
|||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
1. [Issue Guidelines](https://github.com/frappe/erpnext/wiki/Issue-Guidelines)
|
1. [Issue Guidelines](https://github.com/frappe/erpnext/wiki/Issue-Guidelines)
|
||||||
1. [Report Security Vulnerabilities](https://erpnext.com/report)
|
1. [Report Security Vulnerabilities](https://erpnext.com/security)
|
||||||
1. [Pull Request Requirements](https://github.com/frappe/erpnext/wiki/Contribution-Guidelines)
|
1. [Pull Request Requirements](https://github.com/frappe/erpnext/wiki/Contribution-Guidelines)
|
||||||
1. [Translations](https://translate.erpnext.com)
|
1. [Translations](https://translate.erpnext.com)
|
||||||
1. [Chart of Accounts](https://charts.erpnext.com)
|
1. [Chart of Accounts](https://charts.erpnext.com)
|
||||||
|
@ -43,8 +43,13 @@ frappe.ui.form.on('Bank Guarantee', {
|
|||||||
|
|
||||||
reference_docname: function(frm) {
|
reference_docname: function(frm) {
|
||||||
if (frm.doc.reference_docname && frm.doc.reference_doctype) {
|
if (frm.doc.reference_docname && frm.doc.reference_doctype) {
|
||||||
let fields_to_fetch = ["project", "grand_total"];
|
let fields_to_fetch = ["grand_total"];
|
||||||
let party_field = frm.doc.reference_doctype == "Sales Order" ? "customer" : "supplier";
|
let party_field = frm.doc.reference_doctype == "Sales Order" ? "customer" : "supplier";
|
||||||
|
|
||||||
|
if (frm.doc.reference_doctype == "Sales Order") {
|
||||||
|
fields_to_fetch.push("project");
|
||||||
|
}
|
||||||
|
|
||||||
fields_to_fetch.push(party_field);
|
fields_to_fetch.push(party_field);
|
||||||
frappe.call({
|
frappe.call({
|
||||||
method: "erpnext.accounts.doctype.bank_guarantee.bank_guarantee.get_vouchar_detials",
|
method: "erpnext.accounts.doctype.bank_guarantee.bank_guarantee.get_vouchar_detials",
|
||||||
|
@ -39,8 +39,6 @@ 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"));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -22,7 +22,7 @@ class ExchangeRateRevaluation(Document):
|
|||||||
- flt(d.balance_in_base_currency, d.precision("balance_in_base_currency"))
|
- flt(d.balance_in_base_currency, d.precision("balance_in_base_currency"))
|
||||||
total_gain_loss += flt(d.gain_loss, d.precision("gain_loss"))
|
total_gain_loss += flt(d.gain_loss, d.precision("gain_loss"))
|
||||||
self.total_gain_loss = flt(total_gain_loss, self.precision("total_gain_loss"))
|
self.total_gain_loss = flt(total_gain_loss, self.precision("total_gain_loss"))
|
||||||
|
|
||||||
def validate_mandatory(self):
|
def validate_mandatory(self):
|
||||||
if not (self.company and self.posting_date):
|
if not (self.company and self.posting_date):
|
||||||
frappe.throw(_("Please select Company and Posting Date to getting entries"))
|
frappe.throw(_("Please select Company and Posting Date to getting entries"))
|
||||||
@ -33,8 +33,9 @@ class ExchangeRateRevaluation(Document):
|
|||||||
company_currency = erpnext.get_company_currency(self.company)
|
company_currency = erpnext.get_company_currency(self.company)
|
||||||
precision = get_field_precision(frappe.get_meta("Exchange Rate Revaluation Account")
|
precision = get_field_precision(frappe.get_meta("Exchange Rate Revaluation Account")
|
||||||
.get_field("new_balance_in_base_currency"), company_currency)
|
.get_field("new_balance_in_base_currency"), company_currency)
|
||||||
for d in self.get_accounts_from_gle():
|
|
||||||
|
account_details = self.get_accounts_from_gle()
|
||||||
|
for d in account_details:
|
||||||
current_exchange_rate = d.balance / d.balance_in_account_currency \
|
current_exchange_rate = d.balance / d.balance_in_account_currency \
|
||||||
if d.balance_in_account_currency else 0
|
if d.balance_in_account_currency else 0
|
||||||
new_exchange_rate = get_exchange_rate(d.account_currency, company_currency, self.posting_date)
|
new_exchange_rate = get_exchange_rate(d.account_currency, company_currency, self.posting_date)
|
||||||
@ -52,6 +53,10 @@ class ExchangeRateRevaluation(Document):
|
|||||||
"new_exchange_rate": new_exchange_rate,
|
"new_exchange_rate": new_exchange_rate,
|
||||||
"new_balance_in_base_currency": new_balance_in_base_currency
|
"new_balance_in_base_currency": new_balance_in_base_currency
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if not accounts:
|
||||||
|
self.throw_invalid_response_message(account_details)
|
||||||
|
|
||||||
return accounts
|
return accounts
|
||||||
|
|
||||||
def get_accounts_from_gle(self):
|
def get_accounts_from_gle(self):
|
||||||
@ -83,11 +88,18 @@ class ExchangeRateRevaluation(Document):
|
|||||||
|
|
||||||
return account_details
|
return account_details
|
||||||
|
|
||||||
|
def throw_invalid_response_message(self, account_details):
|
||||||
|
if account_details:
|
||||||
|
message = _("No outstanding invoices require exchange rate revaluation")
|
||||||
|
else:
|
||||||
|
message = _("No outstanding invoices found")
|
||||||
|
frappe.msgprint(message)
|
||||||
|
|
||||||
def make_jv_entry(self):
|
def make_jv_entry(self):
|
||||||
if self.total_gain_loss == 0:
|
if self.total_gain_loss == 0:
|
||||||
return
|
return
|
||||||
|
|
||||||
unrealized_exchange_gain_loss_account = frappe.get_cached_value('Company', self.company,
|
unrealized_exchange_gain_loss_account = frappe.get_cached_value('Company', self.company,
|
||||||
"unrealized_exchange_gain_loss_account")
|
"unrealized_exchange_gain_loss_account")
|
||||||
if not unrealized_exchange_gain_loss_account:
|
if not unrealized_exchange_gain_loss_account:
|
||||||
frappe.throw(_("Please set Unrealized Exchange Gain/Loss Account in Company {0}")
|
frappe.throw(_("Please set Unrealized Exchange Gain/Loss Account in Company {0}")
|
||||||
|
@ -1,461 +1,475 @@
|
|||||||
{
|
{
|
||||||
"allow_copy": 0,
|
"allow_copy": 0,
|
||||||
"allow_events_in_timeline": 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,
|
||||||
"beta": 0,
|
"beta": 0,
|
||||||
"creation": "2018-04-13 18:30:06.110433",
|
"creation": "2018-04-13 18:30:06.110433",
|
||||||
"custom": 0,
|
"custom": 0,
|
||||||
"docstatus": 0,
|
"docstatus": 0,
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"document_type": "",
|
"document_type": "",
|
||||||
"editable_grid": 1,
|
"editable_grid": 1,
|
||||||
"engine": "InnoDB",
|
"engine": "InnoDB",
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"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": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"fieldname": "account",
|
"fetch_if_empty": 0,
|
||||||
"fieldtype": "Link",
|
"fieldname": "account",
|
||||||
"hidden": 0,
|
"fieldtype": "Link",
|
||||||
"ignore_user_permissions": 0,
|
"hidden": 0,
|
||||||
"ignore_xss_filter": 0,
|
"ignore_user_permissions": 0,
|
||||||
"in_filter": 0,
|
"ignore_xss_filter": 0,
|
||||||
"in_global_search": 0,
|
"in_filter": 0,
|
||||||
"in_list_view": 1,
|
"in_global_search": 0,
|
||||||
"in_standard_filter": 0,
|
"in_list_view": 1,
|
||||||
"label": "Account",
|
"in_standard_filter": 0,
|
||||||
"length": 0,
|
"label": "Account",
|
||||||
"no_copy": 0,
|
"length": 0,
|
||||||
"options": "Account",
|
"no_copy": 0,
|
||||||
"permlevel": 0,
|
"options": "Account",
|
||||||
"precision": "",
|
"permlevel": 0,
|
||||||
"print_hide": 0,
|
"precision": "",
|
||||||
"print_hide_if_no_value": 0,
|
"print_hide": 0,
|
||||||
"read_only": 0,
|
"print_hide_if_no_value": 0,
|
||||||
"remember_last_selected_value": 0,
|
"read_only": 0,
|
||||||
"report_hide": 0,
|
"remember_last_selected_value": 0,
|
||||||
"reqd": 1,
|
"report_hide": 0,
|
||||||
"search_index": 0,
|
"reqd": 1,
|
||||||
"set_only_once": 0,
|
"search_index": 0,
|
||||||
"translatable": 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_in_quick_entry": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"fieldname": "party_type",
|
"fetch_if_empty": 0,
|
||||||
"fieldtype": "Link",
|
"fieldname": "party_type",
|
||||||
"hidden": 0,
|
"fieldtype": "Link",
|
||||||
"ignore_user_permissions": 0,
|
"hidden": 0,
|
||||||
"ignore_xss_filter": 0,
|
"ignore_user_permissions": 0,
|
||||||
"in_filter": 0,
|
"ignore_xss_filter": 0,
|
||||||
"in_global_search": 0,
|
"in_filter": 0,
|
||||||
"in_list_view": 0,
|
"in_global_search": 0,
|
||||||
"in_standard_filter": 0,
|
"in_list_view": 0,
|
||||||
"label": "Party Type",
|
"in_standard_filter": 0,
|
||||||
"length": 0,
|
"label": "Party Type",
|
||||||
"no_copy": 0,
|
"length": 0,
|
||||||
"options": "DocType",
|
"no_copy": 0,
|
||||||
"permlevel": 0,
|
"options": "DocType",
|
||||||
"precision": "",
|
"permlevel": 0,
|
||||||
"print_hide": 0,
|
"precision": "",
|
||||||
"print_hide_if_no_value": 0,
|
"print_hide": 0,
|
||||||
"read_only": 0,
|
"print_hide_if_no_value": 0,
|
||||||
"remember_last_selected_value": 0,
|
"read_only": 0,
|
||||||
"report_hide": 0,
|
"remember_last_selected_value": 0,
|
||||||
"reqd": 0,
|
"report_hide": 0,
|
||||||
"search_index": 0,
|
"reqd": 0,
|
||||||
"set_only_once": 0,
|
"search_index": 0,
|
||||||
"translatable": 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_in_quick_entry": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"fieldname": "party",
|
"fetch_if_empty": 0,
|
||||||
"fieldtype": "Dynamic Link",
|
"fieldname": "party",
|
||||||
"hidden": 0,
|
"fieldtype": "Dynamic Link",
|
||||||
"ignore_user_permissions": 0,
|
"hidden": 0,
|
||||||
"ignore_xss_filter": 0,
|
"ignore_user_permissions": 0,
|
||||||
"in_filter": 0,
|
"ignore_xss_filter": 0,
|
||||||
"in_global_search": 0,
|
"in_filter": 0,
|
||||||
"in_list_view": 0,
|
"in_global_search": 0,
|
||||||
"in_standard_filter": 0,
|
"in_list_view": 0,
|
||||||
"label": "Party",
|
"in_standard_filter": 0,
|
||||||
"length": 0,
|
"label": "Party",
|
||||||
"no_copy": 0,
|
"length": 0,
|
||||||
"options": "party_type",
|
"no_copy": 0,
|
||||||
"permlevel": 0,
|
"options": "party_type",
|
||||||
"precision": "",
|
"permlevel": 0,
|
||||||
"print_hide": 0,
|
"precision": "",
|
||||||
"print_hide_if_no_value": 0,
|
"print_hide": 0,
|
||||||
"read_only": 0,
|
"print_hide_if_no_value": 0,
|
||||||
"remember_last_selected_value": 0,
|
"read_only": 0,
|
||||||
"report_hide": 0,
|
"remember_last_selected_value": 0,
|
||||||
"reqd": 0,
|
"report_hide": 0,
|
||||||
"search_index": 0,
|
"reqd": 0,
|
||||||
"set_only_once": 0,
|
"search_index": 0,
|
||||||
"translatable": 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_in_quick_entry": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"fieldname": "column_break_2",
|
"fetch_if_empty": 0,
|
||||||
"fieldtype": "Column Break",
|
"fieldname": "column_break_2",
|
||||||
"hidden": 0,
|
"fieldtype": "Column Break",
|
||||||
"ignore_user_permissions": 0,
|
"hidden": 0,
|
||||||
"ignore_xss_filter": 0,
|
"ignore_user_permissions": 0,
|
||||||
"in_filter": 0,
|
"ignore_xss_filter": 0,
|
||||||
"in_global_search": 0,
|
"in_filter": 0,
|
||||||
"in_list_view": 0,
|
"in_global_search": 0,
|
||||||
"in_standard_filter": 0,
|
"in_list_view": 0,
|
||||||
"length": 0,
|
"in_standard_filter": 0,
|
||||||
"no_copy": 0,
|
"length": 0,
|
||||||
"permlevel": 0,
|
"no_copy": 0,
|
||||||
"precision": "",
|
"permlevel": 0,
|
||||||
"print_hide": 0,
|
"precision": "",
|
||||||
"print_hide_if_no_value": 0,
|
"print_hide": 0,
|
||||||
"read_only": 0,
|
"print_hide_if_no_value": 0,
|
||||||
"remember_last_selected_value": 0,
|
"read_only": 0,
|
||||||
"report_hide": 0,
|
"remember_last_selected_value": 0,
|
||||||
"reqd": 0,
|
"report_hide": 0,
|
||||||
"search_index": 0,
|
"reqd": 0,
|
||||||
"set_only_once": 0,
|
"search_index": 0,
|
||||||
"translatable": 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_in_quick_entry": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"fieldname": "account_currency",
|
"fetch_if_empty": 0,
|
||||||
"fieldtype": "Link",
|
"fieldname": "account_currency",
|
||||||
"hidden": 0,
|
"fieldtype": "Link",
|
||||||
"ignore_user_permissions": 0,
|
"hidden": 0,
|
||||||
"ignore_xss_filter": 0,
|
"ignore_user_permissions": 0,
|
||||||
"in_filter": 0,
|
"ignore_xss_filter": 0,
|
||||||
"in_global_search": 0,
|
"in_filter": 0,
|
||||||
"in_list_view": 0,
|
"in_global_search": 0,
|
||||||
"in_standard_filter": 0,
|
"in_list_view": 0,
|
||||||
"label": "Account Currency",
|
"in_standard_filter": 0,
|
||||||
"length": 0,
|
"label": "Account Currency",
|
||||||
"no_copy": 0,
|
"length": 0,
|
||||||
"options": "Currency",
|
"no_copy": 0,
|
||||||
"permlevel": 0,
|
"options": "Currency",
|
||||||
"precision": "",
|
"permlevel": 0,
|
||||||
"print_hide": 0,
|
"precision": "",
|
||||||
"print_hide_if_no_value": 0,
|
"print_hide": 0,
|
||||||
"read_only": 1,
|
"print_hide_if_no_value": 0,
|
||||||
"remember_last_selected_value": 0,
|
"read_only": 1,
|
||||||
"report_hide": 0,
|
"remember_last_selected_value": 0,
|
||||||
"reqd": 0,
|
"report_hide": 0,
|
||||||
"search_index": 0,
|
"reqd": 0,
|
||||||
"set_only_once": 0,
|
"search_index": 0,
|
||||||
"translatable": 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_in_quick_entry": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"fieldname": "balance_in_account_currency",
|
"fetch_if_empty": 0,
|
||||||
"fieldtype": "Currency",
|
"fieldname": "balance_in_account_currency",
|
||||||
"hidden": 0,
|
"fieldtype": "Currency",
|
||||||
"ignore_user_permissions": 0,
|
"hidden": 0,
|
||||||
"ignore_xss_filter": 0,
|
"ignore_user_permissions": 0,
|
||||||
"in_filter": 0,
|
"ignore_xss_filter": 0,
|
||||||
"in_global_search": 0,
|
"in_filter": 0,
|
||||||
"in_list_view": 0,
|
"in_global_search": 0,
|
||||||
"in_standard_filter": 0,
|
"in_list_view": 0,
|
||||||
"label": "Balance In Account Currency",
|
"in_standard_filter": 0,
|
||||||
"length": 0,
|
"label": "Balance In Account Currency",
|
||||||
"no_copy": 0,
|
"length": 0,
|
||||||
"permlevel": 0,
|
"no_copy": 0,
|
||||||
"precision": "",
|
"options": "account_currency",
|
||||||
"print_hide": 0,
|
"permlevel": 0,
|
||||||
"print_hide_if_no_value": 0,
|
"precision": "",
|
||||||
"read_only": 1,
|
"print_hide": 0,
|
||||||
"remember_last_selected_value": 0,
|
"print_hide_if_no_value": 0,
|
||||||
"report_hide": 0,
|
"read_only": 1,
|
||||||
"reqd": 0,
|
"remember_last_selected_value": 0,
|
||||||
"search_index": 0,
|
"report_hide": 0,
|
||||||
"set_only_once": 0,
|
"reqd": 0,
|
||||||
"translatable": 0,
|
"search_index": 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_in_quick_entry": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"fieldname": "balances",
|
"fetch_if_empty": 0,
|
||||||
"fieldtype": "Section Break",
|
"fieldname": "balances",
|
||||||
"hidden": 0,
|
"fieldtype": "Section Break",
|
||||||
"ignore_user_permissions": 0,
|
"hidden": 0,
|
||||||
"ignore_xss_filter": 0,
|
"ignore_user_permissions": 0,
|
||||||
"in_filter": 0,
|
"ignore_xss_filter": 0,
|
||||||
"in_global_search": 0,
|
"in_filter": 0,
|
||||||
"in_list_view": 0,
|
"in_global_search": 0,
|
||||||
"in_standard_filter": 0,
|
"in_list_view": 0,
|
||||||
"label": "",
|
"in_standard_filter": 0,
|
||||||
"length": 0,
|
"label": "",
|
||||||
"no_copy": 0,
|
"length": 0,
|
||||||
"permlevel": 0,
|
"no_copy": 0,
|
||||||
"precision": "",
|
"permlevel": 0,
|
||||||
"print_hide": 0,
|
"precision": "",
|
||||||
"print_hide_if_no_value": 0,
|
"print_hide": 0,
|
||||||
"read_only": 0,
|
"print_hide_if_no_value": 0,
|
||||||
"remember_last_selected_value": 0,
|
"read_only": 0,
|
||||||
"report_hide": 0,
|
"remember_last_selected_value": 0,
|
||||||
"reqd": 0,
|
"report_hide": 0,
|
||||||
"search_index": 0,
|
"reqd": 0,
|
||||||
"set_only_once": 0,
|
"search_index": 0,
|
||||||
"translatable": 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_in_quick_entry": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"fieldname": "current_exchange_rate",
|
"fetch_if_empty": 0,
|
||||||
"fieldtype": "Float",
|
"fieldname": "current_exchange_rate",
|
||||||
"hidden": 0,
|
"fieldtype": "Float",
|
||||||
"ignore_user_permissions": 0,
|
"hidden": 0,
|
||||||
"ignore_xss_filter": 0,
|
"ignore_user_permissions": 0,
|
||||||
"in_filter": 0,
|
"ignore_xss_filter": 0,
|
||||||
"in_global_search": 0,
|
"in_filter": 0,
|
||||||
"in_list_view": 0,
|
"in_global_search": 0,
|
||||||
"in_standard_filter": 0,
|
"in_list_view": 0,
|
||||||
"label": "Current Exchange Rate",
|
"in_standard_filter": 0,
|
||||||
"length": 0,
|
"label": "Current Exchange Rate",
|
||||||
"no_copy": 0,
|
"length": 0,
|
||||||
"permlevel": 0,
|
"no_copy": 0,
|
||||||
"precision": "",
|
"permlevel": 0,
|
||||||
"print_hide": 0,
|
"precision": "",
|
||||||
"print_hide_if_no_value": 0,
|
"print_hide": 0,
|
||||||
"read_only": 1,
|
"print_hide_if_no_value": 0,
|
||||||
"remember_last_selected_value": 0,
|
"read_only": 1,
|
||||||
"report_hide": 0,
|
"remember_last_selected_value": 0,
|
||||||
"reqd": 0,
|
"report_hide": 0,
|
||||||
"search_index": 0,
|
"reqd": 0,
|
||||||
"set_only_once": 0,
|
"search_index": 0,
|
||||||
"translatable": 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_in_quick_entry": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"fieldname": "balance_in_base_currency",
|
"fetch_if_empty": 0,
|
||||||
"fieldtype": "Currency",
|
"fieldname": "balance_in_base_currency",
|
||||||
"hidden": 0,
|
"fieldtype": "Currency",
|
||||||
"ignore_user_permissions": 0,
|
"hidden": 0,
|
||||||
"ignore_xss_filter": 0,
|
"ignore_user_permissions": 0,
|
||||||
"in_filter": 0,
|
"ignore_xss_filter": 0,
|
||||||
"in_global_search": 0,
|
"in_filter": 0,
|
||||||
"in_list_view": 1,
|
"in_global_search": 0,
|
||||||
"in_standard_filter": 0,
|
"in_list_view": 1,
|
||||||
"label": "Balance In Base Currency",
|
"in_standard_filter": 0,
|
||||||
"length": 0,
|
"label": "Balance In Base Currency",
|
||||||
"no_copy": 0,
|
"length": 0,
|
||||||
"permlevel": 0,
|
"no_copy": 0,
|
||||||
"precision": "",
|
"permlevel": 0,
|
||||||
"print_hide": 0,
|
"precision": "",
|
||||||
"print_hide_if_no_value": 0,
|
"print_hide": 0,
|
||||||
"read_only": 1,
|
"print_hide_if_no_value": 0,
|
||||||
"remember_last_selected_value": 0,
|
"read_only": 1,
|
||||||
"report_hide": 0,
|
"remember_last_selected_value": 0,
|
||||||
"reqd": 0,
|
"report_hide": 0,
|
||||||
"search_index": 0,
|
"reqd": 0,
|
||||||
"set_only_once": 0,
|
"search_index": 0,
|
||||||
"translatable": 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_in_quick_entry": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"fieldname": "column_break_9",
|
"fetch_if_empty": 0,
|
||||||
"fieldtype": "Column Break",
|
"fieldname": "column_break_9",
|
||||||
"hidden": 0,
|
"fieldtype": "Column Break",
|
||||||
"ignore_user_permissions": 0,
|
"hidden": 0,
|
||||||
"ignore_xss_filter": 0,
|
"ignore_user_permissions": 0,
|
||||||
"in_filter": 0,
|
"ignore_xss_filter": 0,
|
||||||
"in_global_search": 0,
|
"in_filter": 0,
|
||||||
"in_list_view": 0,
|
"in_global_search": 0,
|
||||||
"in_standard_filter": 0,
|
"in_list_view": 0,
|
||||||
"length": 0,
|
"in_standard_filter": 0,
|
||||||
"no_copy": 0,
|
"length": 0,
|
||||||
"permlevel": 0,
|
"no_copy": 0,
|
||||||
"precision": "",
|
"permlevel": 0,
|
||||||
"print_hide": 0,
|
"precision": "",
|
||||||
"print_hide_if_no_value": 0,
|
"print_hide": 0,
|
||||||
"read_only": 0,
|
"print_hide_if_no_value": 0,
|
||||||
"remember_last_selected_value": 0,
|
"read_only": 0,
|
||||||
"report_hide": 0,
|
"remember_last_selected_value": 0,
|
||||||
"reqd": 0,
|
"report_hide": 0,
|
||||||
"search_index": 0,
|
"reqd": 0,
|
||||||
"set_only_once": 0,
|
"search_index": 0,
|
||||||
"translatable": 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_in_quick_entry": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"fieldname": "new_exchange_rate",
|
"fetch_if_empty": 0,
|
||||||
"fieldtype": "Float",
|
"fieldname": "new_exchange_rate",
|
||||||
"hidden": 0,
|
"fieldtype": "Float",
|
||||||
"ignore_user_permissions": 0,
|
"hidden": 0,
|
||||||
"ignore_xss_filter": 0,
|
"ignore_user_permissions": 0,
|
||||||
"in_filter": 0,
|
"ignore_xss_filter": 0,
|
||||||
"in_global_search": 0,
|
"in_filter": 0,
|
||||||
"in_list_view": 1,
|
"in_global_search": 0,
|
||||||
"in_standard_filter": 0,
|
"in_list_view": 1,
|
||||||
"label": "New Exchange Rate",
|
"in_standard_filter": 0,
|
||||||
"length": 0,
|
"label": "New Exchange Rate",
|
||||||
"no_copy": 0,
|
"length": 0,
|
||||||
"permlevel": 0,
|
"no_copy": 0,
|
||||||
"precision": "",
|
"permlevel": 0,
|
||||||
"print_hide": 0,
|
"precision": "",
|
||||||
"print_hide_if_no_value": 0,
|
"print_hide": 0,
|
||||||
"read_only": 0,
|
"print_hide_if_no_value": 0,
|
||||||
"remember_last_selected_value": 0,
|
"read_only": 0,
|
||||||
"report_hide": 0,
|
"remember_last_selected_value": 0,
|
||||||
"reqd": 1,
|
"report_hide": 0,
|
||||||
"search_index": 0,
|
"reqd": 1,
|
||||||
"set_only_once": 0,
|
"search_index": 0,
|
||||||
"translatable": 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_in_quick_entry": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"fieldname": "new_balance_in_base_currency",
|
"fetch_if_empty": 0,
|
||||||
"fieldtype": "Currency",
|
"fieldname": "new_balance_in_base_currency",
|
||||||
"hidden": 0,
|
"fieldtype": "Currency",
|
||||||
"ignore_user_permissions": 0,
|
"hidden": 0,
|
||||||
"ignore_xss_filter": 0,
|
"ignore_user_permissions": 0,
|
||||||
"in_filter": 0,
|
"ignore_xss_filter": 0,
|
||||||
"in_global_search": 0,
|
"in_filter": 0,
|
||||||
"in_list_view": 1,
|
"in_global_search": 0,
|
||||||
"in_standard_filter": 0,
|
"in_list_view": 1,
|
||||||
"label": "New Balance In Base Currency",
|
"in_standard_filter": 0,
|
||||||
"length": 0,
|
"label": "New Balance In Base Currency",
|
||||||
"no_copy": 0,
|
"length": 0,
|
||||||
"permlevel": 0,
|
"no_copy": 0,
|
||||||
"precision": "",
|
"permlevel": 0,
|
||||||
"print_hide": 0,
|
"precision": "",
|
||||||
"print_hide_if_no_value": 0,
|
"print_hide": 0,
|
||||||
"read_only": 1,
|
"print_hide_if_no_value": 0,
|
||||||
"remember_last_selected_value": 0,
|
"read_only": 1,
|
||||||
"report_hide": 0,
|
"remember_last_selected_value": 0,
|
||||||
"reqd": 0,
|
"report_hide": 0,
|
||||||
"search_index": 0,
|
"reqd": 0,
|
||||||
"set_only_once": 0,
|
"search_index": 0,
|
||||||
"translatable": 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_in_quick_entry": 0,
|
||||||
"allow_on_submit": 0,
|
"allow_on_submit": 0,
|
||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"fieldname": "gain_loss",
|
"fetch_if_empty": 0,
|
||||||
"fieldtype": "Currency",
|
"fieldname": "gain_loss",
|
||||||
"hidden": 0,
|
"fieldtype": "Currency",
|
||||||
"ignore_user_permissions": 0,
|
"hidden": 0,
|
||||||
"ignore_xss_filter": 0,
|
"ignore_user_permissions": 0,
|
||||||
"in_filter": 0,
|
"ignore_xss_filter": 0,
|
||||||
"in_global_search": 0,
|
"in_filter": 0,
|
||||||
"in_list_view": 1,
|
"in_global_search": 0,
|
||||||
"in_standard_filter": 0,
|
"in_list_view": 1,
|
||||||
"label": "Gain/Loss",
|
"in_standard_filter": 0,
|
||||||
"length": 0,
|
"label": "Gain/Loss",
|
||||||
"no_copy": 0,
|
"length": 0,
|
||||||
"permlevel": 0,
|
"no_copy": 0,
|
||||||
"precision": "",
|
"permlevel": 0,
|
||||||
"print_hide": 0,
|
"precision": "",
|
||||||
"print_hide_if_no_value": 0,
|
"print_hide": 0,
|
||||||
"read_only": 1,
|
"print_hide_if_no_value": 0,
|
||||||
"remember_last_selected_value": 0,
|
"read_only": 1,
|
||||||
"report_hide": 0,
|
"remember_last_selected_value": 0,
|
||||||
"reqd": 0,
|
"report_hide": 0,
|
||||||
"search_index": 0,
|
"reqd": 0,
|
||||||
"set_only_once": 0,
|
"search_index": 0,
|
||||||
"translatable": 0,
|
"set_only_once": 0,
|
||||||
|
"translatable": 0,
|
||||||
"unique": 0
|
"unique": 0
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"has_web_view": 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": "2019-01-07 16:52:07.327930",
|
"modified": "2019-06-26 18:57:51.762345",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Accounts",
|
"module": "Accounts",
|
||||||
"name": "Exchange Rate Revaluation Account",
|
"name": "Exchange Rate Revaluation Account",
|
||||||
"name_case": "",
|
"name_case": "",
|
||||||
"owner": "Administrator",
|
"owner": "Administrator",
|
||||||
"permissions": [],
|
"permissions": [],
|
||||||
"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,
|
"show_name_in_global_search": 0,
|
||||||
"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
|
"track_views": 0
|
||||||
}
|
}
|
@ -232,7 +232,7 @@ def filter_pricing_rules(args, pricing_rules, doc=None):
|
|||||||
if len(pricing_rules) > 1:
|
if len(pricing_rules) > 1:
|
||||||
rate_or_discount = list(set([d.rate_or_discount for d in pricing_rules]))
|
rate_or_discount = list(set([d.rate_or_discount for d in pricing_rules]))
|
||||||
if len(rate_or_discount) == 1 and rate_or_discount[0] == "Discount Percentage":
|
if len(rate_or_discount) == 1 and rate_or_discount[0] == "Discount Percentage":
|
||||||
pricing_rules = filter(lambda x: x.for_price_list==args.price_list, pricing_rules) \
|
pricing_rules = list(filter(lambda x: x.for_price_list==args.price_list, pricing_rules)) \
|
||||||
or pricing_rules
|
or pricing_rules
|
||||||
|
|
||||||
if len(pricing_rules) > 1 and not args.for_shopping_cart:
|
if len(pricing_rules) > 1 and not args.for_shopping_cart:
|
||||||
|
@ -485,7 +485,7 @@ class SalesInvoice(SellingController):
|
|||||||
"""Set against account for debit to account"""
|
"""Set against account for debit to account"""
|
||||||
against_acc = []
|
against_acc = []
|
||||||
for d in self.get('items'):
|
for d in self.get('items'):
|
||||||
if d.income_account not in against_acc:
|
if d.income_account and d.income_account not in against_acc:
|
||||||
against_acc.append(d.income_account)
|
against_acc.append(d.income_account)
|
||||||
self.against_income_account = ','.join(against_acc)
|
self.against_income_account = ','.join(against_acc)
|
||||||
|
|
||||||
|
@ -10,4 +10,10 @@ frappe.require("assets/erpnext/js/financial_statements.js", function() {
|
|||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"default": 1
|
"default": 1
|
||||||
});
|
});
|
||||||
|
|
||||||
|
frappe.query_reports["Balance Sheet"]["filters"].push({
|
||||||
|
"fieldname": "include_default_book_entries",
|
||||||
|
"label": __("Include Default Book Entries"),
|
||||||
|
"fieldtype": "Check"
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -15,4 +15,10 @@ frappe.require("assets/erpnext/js/financial_statements.js", function() {
|
|||||||
"label": __("Accumulated Values"),
|
"label": __("Accumulated Values"),
|
||||||
"fieldtype": "Check"
|
"fieldtype": "Check"
|
||||||
});
|
});
|
||||||
|
|
||||||
|
frappe.query_reports["Cash Flow"]["filters"].push({
|
||||||
|
"fieldname": "include_default_book_entries",
|
||||||
|
"label": __("Include Default Book Entries"),
|
||||||
|
"fieldtype": "Check"
|
||||||
|
});
|
||||||
});
|
});
|
@ -14,8 +14,8 @@ def execute(filters=None):
|
|||||||
if cint(frappe.db.get_single_value('Accounts Settings', 'use_custom_cash_flow')):
|
if cint(frappe.db.get_single_value('Accounts Settings', 'use_custom_cash_flow')):
|
||||||
from erpnext.accounts.report.cash_flow.custom_cash_flow import execute as execute_custom
|
from erpnext.accounts.report.cash_flow.custom_cash_flow import execute as execute_custom
|
||||||
return execute_custom(filters=filters)
|
return execute_custom(filters=filters)
|
||||||
|
|
||||||
period_list = get_period_list(filters.from_fiscal_year, filters.to_fiscal_year,
|
period_list = get_period_list(filters.from_fiscal_year, filters.to_fiscal_year,
|
||||||
filters.periodicity, filters.accumulated_values, filters.company)
|
filters.periodicity, filters.accumulated_values, filters.company)
|
||||||
|
|
||||||
cash_flow_accounts = get_cash_flow_accounts()
|
cash_flow_accounts = get_cash_flow_accounts()
|
||||||
@ -25,18 +25,18 @@ def execute(filters=None):
|
|||||||
accumulated_values=filters.accumulated_values, ignore_closing_entries=True, ignore_accumulated_values_for_fy= True)
|
accumulated_values=filters.accumulated_values, ignore_closing_entries=True, ignore_accumulated_values_for_fy= True)
|
||||||
expense = get_data(filters.company, "Expense", "Debit", period_list, filters=filters,
|
expense = get_data(filters.company, "Expense", "Debit", period_list, filters=filters,
|
||||||
accumulated_values=filters.accumulated_values, ignore_closing_entries=True, ignore_accumulated_values_for_fy= True)
|
accumulated_values=filters.accumulated_values, ignore_closing_entries=True, ignore_accumulated_values_for_fy= True)
|
||||||
|
|
||||||
net_profit_loss = get_net_profit_loss(income, expense, period_list, filters.company)
|
net_profit_loss = get_net_profit_loss(income, expense, period_list, filters.company)
|
||||||
|
|
||||||
data = []
|
data = []
|
||||||
company_currency = frappe.get_cached_value('Company', filters.company, "default_currency")
|
company_currency = frappe.get_cached_value('Company', filters.company, "default_currency")
|
||||||
|
|
||||||
for cash_flow_account in cash_flow_accounts:
|
for cash_flow_account in cash_flow_accounts:
|
||||||
section_data = []
|
section_data = []
|
||||||
data.append({
|
data.append({
|
||||||
"account_name": cash_flow_account['section_header'],
|
"account_name": cash_flow_account['section_header'],
|
||||||
"parent_account": None,
|
"parent_account": None,
|
||||||
"indent": 0.0,
|
"indent": 0.0,
|
||||||
"account": cash_flow_account['section_header']
|
"account": cash_flow_account['section_header']
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -44,18 +44,18 @@ def execute(filters=None):
|
|||||||
# add first net income in operations section
|
# add first net income in operations section
|
||||||
if net_profit_loss:
|
if net_profit_loss:
|
||||||
net_profit_loss.update({
|
net_profit_loss.update({
|
||||||
"indent": 1,
|
"indent": 1,
|
||||||
"parent_account": cash_flow_accounts[0]['section_header']
|
"parent_account": cash_flow_accounts[0]['section_header']
|
||||||
})
|
})
|
||||||
data.append(net_profit_loss)
|
data.append(net_profit_loss)
|
||||||
section_data.append(net_profit_loss)
|
section_data.append(net_profit_loss)
|
||||||
|
|
||||||
for account in cash_flow_account['account_types']:
|
for account in cash_flow_account['account_types']:
|
||||||
account_data = get_account_type_based_data(filters.company,
|
account_data = get_account_type_based_data(filters.company,
|
||||||
account['account_type'], period_list, filters.accumulated_values)
|
account['account_type'], period_list, filters.accumulated_values, filters)
|
||||||
account_data.update({
|
account_data.update({
|
||||||
"account_name": account['label'],
|
"account_name": account['label'],
|
||||||
"account": account['label'],
|
"account": account['label'],
|
||||||
"indent": 1,
|
"indent": 1,
|
||||||
"parent_account": cash_flow_account['section_header'],
|
"parent_account": cash_flow_account['section_header'],
|
||||||
"currency": company_currency
|
"currency": company_currency
|
||||||
@ -63,7 +63,7 @@ def execute(filters=None):
|
|||||||
data.append(account_data)
|
data.append(account_data)
|
||||||
section_data.append(account_data)
|
section_data.append(account_data)
|
||||||
|
|
||||||
add_total_row_account(data, section_data, cash_flow_account['section_footer'],
|
add_total_row_account(data, section_data, cash_flow_account['section_footer'],
|
||||||
period_list, company_currency)
|
period_list, company_currency)
|
||||||
|
|
||||||
add_total_row_account(data, data, _("Net Change in Cash"), period_list, company_currency)
|
add_total_row_account(data, data, _("Net Change in Cash"), period_list, company_currency)
|
||||||
@ -105,13 +105,15 @@ def get_cash_flow_accounts():
|
|||||||
# combine all cash flow accounts for iteration
|
# combine all cash flow accounts for iteration
|
||||||
return [operation_accounts, investing_accounts, financing_accounts]
|
return [operation_accounts, investing_accounts, financing_accounts]
|
||||||
|
|
||||||
def get_account_type_based_data(company, account_type, period_list, accumulated_values):
|
def get_account_type_based_data(company, account_type, period_list, accumulated_values, filters):
|
||||||
data = {}
|
data = {}
|
||||||
total = 0
|
total = 0
|
||||||
for period in period_list:
|
for period in period_list:
|
||||||
start_date = get_start_date(period, accumulated_values, company)
|
start_date = get_start_date(period, accumulated_values, company)
|
||||||
|
|
||||||
amount = get_account_type_based_gl_data(company, start_date, period['to_date'], account_type)
|
amount = get_account_type_based_gl_data(company, start_date,
|
||||||
|
period['to_date'], account_type, filters)
|
||||||
|
|
||||||
if amount and account_type == "Depreciation":
|
if amount and account_type == "Depreciation":
|
||||||
amount *= -1
|
amount *= -1
|
||||||
|
|
||||||
@ -121,14 +123,24 @@ def get_account_type_based_data(company, account_type, period_list, accumulated_
|
|||||||
data["total"] = total
|
data["total"] = total
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def get_account_type_based_gl_data(company, start_date, end_date, account_type):
|
def get_account_type_based_gl_data(company, start_date, end_date, account_type, filters):
|
||||||
|
cond = ""
|
||||||
|
|
||||||
|
if filters.finance_book:
|
||||||
|
cond = " and finance_book = %s" %(frappe.db.escape(filters.finance_book))
|
||||||
|
if filters.include_default_book_entries:
|
||||||
|
company_fb = frappe.db.get_value("Company", company, 'default_finance_book')
|
||||||
|
|
||||||
|
cond = """ and finance_book in (%s, %s)
|
||||||
|
""" %(frappe.db.escape(filters.finance_book), frappe.db.escape(company_fb))
|
||||||
|
|
||||||
gl_sum = frappe.db.sql_list("""
|
gl_sum = frappe.db.sql_list("""
|
||||||
select sum(credit) - sum(debit)
|
select sum(credit) - sum(debit)
|
||||||
from `tabGL Entry`
|
from `tabGL Entry`
|
||||||
where company=%s and posting_date >= %s and posting_date <= %s
|
where company=%s and posting_date >= %s and posting_date <= %s
|
||||||
and voucher_type != 'Period Closing Voucher'
|
and voucher_type != 'Period Closing Voucher'
|
||||||
and account in ( SELECT name FROM tabAccount WHERE account_type = %s)
|
and account in ( SELECT name FROM tabAccount WHERE account_type = %s) {cond}
|
||||||
""", (company, start_date, end_date, account_type))
|
""".format(cond=cond), (company, start_date, end_date, account_type))
|
||||||
|
|
||||||
return gl_sum[0] if gl_sum and gl_sum[0] else 0
|
return gl_sum[0] if gl_sum and gl_sum[0] else 0
|
||||||
|
|
||||||
@ -154,7 +166,7 @@ def add_total_row_account(out, data, label, period_list, currency, consolidated
|
|||||||
key = period if consolidated else period['key']
|
key = period if consolidated else period['key']
|
||||||
total_row.setdefault(key, 0.0)
|
total_row.setdefault(key, 0.0)
|
||||||
total_row[key] += row.get(key, 0.0)
|
total_row[key] += row.get(key, 0.0)
|
||||||
|
|
||||||
total_row.setdefault("total", 0.0)
|
total_row.setdefault("total", 0.0)
|
||||||
total_row["total"] += row["total"]
|
total_row["total"] += row["total"]
|
||||||
|
|
||||||
|
@ -55,5 +55,10 @@ frappe.query_reports["Consolidated Financial Statement"] = {
|
|||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"default": 0
|
"default": 0
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "include_default_book_entries",
|
||||||
|
"label": __("Include Default Book Entries"),
|
||||||
|
"fieldtype": "Check"
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -356,7 +356,8 @@ def set_gl_entries_by_account(from_date, to_date, root_lft, root_rgt, filters, g
|
|||||||
"lft": root_lft,
|
"lft": root_lft,
|
||||||
"rgt": root_rgt,
|
"rgt": root_rgt,
|
||||||
"company": d.name,
|
"company": d.name,
|
||||||
"finance_book": filters.get("finance_book")
|
"finance_book": filters.get("finance_book"),
|
||||||
|
"company_fb": frappe.db.get_value("Company", d.name, 'default_finance_book')
|
||||||
},
|
},
|
||||||
as_dict=True)
|
as_dict=True)
|
||||||
|
|
||||||
@ -387,7 +388,10 @@ def get_additional_conditions(from_date, ignore_closing_entries, filters):
|
|||||||
additional_conditions.append("gl.posting_date >= %(from_date)s")
|
additional_conditions.append("gl.posting_date >= %(from_date)s")
|
||||||
|
|
||||||
if filters.get("finance_book"):
|
if filters.get("finance_book"):
|
||||||
additional_conditions.append("ifnull(finance_book, '') in (%(finance_book)s, '')")
|
if filters.get("include_default_book_entries"):
|
||||||
|
additional_conditions.append("finance_book in (%(finance_book)s, %(company_fb)s)")
|
||||||
|
else:
|
||||||
|
additional_conditions.append("finance_book in (%(finance_book)s)")
|
||||||
|
|
||||||
return " and {}".format(" and ".join(additional_conditions)) if additional_conditions else ""
|
return " and {}".format(" and ".join(additional_conditions)) if additional_conditions else ""
|
||||||
|
|
||||||
|
@ -355,6 +355,10 @@ def set_gl_entries_by_account(
|
|||||||
"to_date": to_date,
|
"to_date": to_date,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if filters.get("include_default_book_entries"):
|
||||||
|
gl_filters["company_fb"] = frappe.db.get_value("Company",
|
||||||
|
company, 'default_finance_book')
|
||||||
|
|
||||||
for key, value in filters.items():
|
for key, value in filters.items():
|
||||||
if value:
|
if value:
|
||||||
gl_filters.update({
|
gl_filters.update({
|
||||||
@ -390,8 +394,8 @@ def get_additional_conditions(from_date, ignore_closing_entries, filters):
|
|||||||
if filters:
|
if filters:
|
||||||
if filters.get("project"):
|
if filters.get("project"):
|
||||||
if not isinstance(filters.get("project"), list):
|
if not isinstance(filters.get("project"), list):
|
||||||
projects = frappe.safe_encode(filters.get("project"))
|
filters.project = frappe.parse_json(filters.get("project"))
|
||||||
filters.project = [d.strip() for d in projects.strip().split(',') if d]
|
|
||||||
additional_conditions.append("project in %(project)s")
|
additional_conditions.append("project in %(project)s")
|
||||||
|
|
||||||
if filters.get("cost_center"):
|
if filters.get("cost_center"):
|
||||||
@ -399,7 +403,10 @@ def get_additional_conditions(from_date, ignore_closing_entries, filters):
|
|||||||
additional_conditions.append("cost_center in %(cost_center)s")
|
additional_conditions.append("cost_center in %(cost_center)s")
|
||||||
|
|
||||||
if filters.get("finance_book"):
|
if filters.get("finance_book"):
|
||||||
additional_conditions.append("ifnull(finance_book, '') in (%(finance_book)s, '')")
|
if filters.get("include_default_book_entries"):
|
||||||
|
additional_conditions.append("finance_book in (%(finance_book)s, %(company_fb)s)")
|
||||||
|
else:
|
||||||
|
additional_conditions.append("finance_book in (%(finance_book)s)")
|
||||||
|
|
||||||
if accounting_dimensions:
|
if accounting_dimensions:
|
||||||
for dimension in accounting_dimensions:
|
for dimension in accounting_dimensions:
|
||||||
|
@ -72,46 +72,25 @@ frappe.query_reports["General Ledger"] = {
|
|||||||
{
|
{
|
||||||
"fieldname":"party",
|
"fieldname":"party",
|
||||||
"label": __("Party"),
|
"label": __("Party"),
|
||||||
"fieldtype": "MultiSelect",
|
"fieldtype": "MultiSelectList",
|
||||||
get_data: function() {
|
get_data: function(txt) {
|
||||||
if (!frappe.query_report.filters) return;
|
if (!frappe.query_report.filters) return;
|
||||||
var party_type = frappe.query_report.get_filter_value('party_type');
|
|
||||||
var parties = frappe.query_report.get_filter_value('party');
|
|
||||||
if(!party_type) return;
|
|
||||||
|
|
||||||
const values = parties.split(/\s*,\s*/).filter(d => d);
|
let party_type = frappe.query_report.get_filter_value('party_type');
|
||||||
const txt = parties.match(/[^,\s*]*$/)[0] || '';
|
if (!party_type) return;
|
||||||
let data = [];
|
|
||||||
|
|
||||||
frappe.call({
|
return frappe.db.get_link_options(party_type, txt);
|
||||||
type: "GET",
|
|
||||||
method:'frappe.desk.search.search_link',
|
|
||||||
async: false,
|
|
||||||
no_spinner: true,
|
|
||||||
args: {
|
|
||||||
doctype: frappe.query_report.get_filter_value('party_type'),
|
|
||||||
txt: txt,
|
|
||||||
filters: {
|
|
||||||
"name": ["not in", values]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
callback: function(r) {
|
|
||||||
data = r.results;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return data;
|
|
||||||
},
|
},
|
||||||
on_change: function() {
|
on_change: function() {
|
||||||
var party_type = frappe.query_report.get_filter_value('party_type');
|
var party_type = frappe.query_report.get_filter_value('party_type');
|
||||||
var parties = frappe.query_report.get_filter_value('party');
|
var parties = frappe.query_report.get_filter_value('party');
|
||||||
const values = parties.split(/\s*,\s*/).filter(d => d);
|
|
||||||
|
|
||||||
if(!party_type || !parties || values.length>1) {
|
if(!party_type || parties.length === 0 || parties.length > 1) {
|
||||||
frappe.query_report.set_filter_value('party_name', "");
|
frappe.query_report.set_filter_value('party_name', "");
|
||||||
frappe.query_report.set_filter_value('tax_id', "");
|
frappe.query_report.set_filter_value('tax_id', "");
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
var party = values[0];
|
var party = parties[0];
|
||||||
var fieldname = erpnext.utils.get_party_name(party_type) || "name";
|
var fieldname = erpnext.utils.get_party_name(party_type) || "name";
|
||||||
frappe.db.get_value(party_type, party, fieldname, function(value) {
|
frappe.db.get_value(party_type, party, fieldname, function(value) {
|
||||||
frappe.query_report.set_filter_value('party_name', value[fieldname]);
|
frappe.query_report.set_filter_value('party_name', value[fieldname]);
|
||||||
@ -154,62 +133,17 @@ frappe.query_reports["General Ledger"] = {
|
|||||||
{
|
{
|
||||||
"fieldname":"cost_center",
|
"fieldname":"cost_center",
|
||||||
"label": __("Cost Center"),
|
"label": __("Cost Center"),
|
||||||
"fieldtype": "MultiSelect",
|
"fieldtype": "MultiSelectList",
|
||||||
get_data: function() {
|
get_data: function(txt) {
|
||||||
var cost_centers = frappe.query_report.get_filter_value("cost_center") || "";
|
return frappe.db.get_link_options('Cost Center', txt);
|
||||||
|
|
||||||
const values = cost_centers.split(/\s*,\s*/).filter(d => d);
|
|
||||||
const txt = cost_centers.match(/[^,\s*]*$/)[0] || '';
|
|
||||||
let data = [];
|
|
||||||
|
|
||||||
frappe.call({
|
|
||||||
type: "GET",
|
|
||||||
method:'frappe.desk.search.search_link',
|
|
||||||
async: false,
|
|
||||||
no_spinner: true,
|
|
||||||
args: {
|
|
||||||
doctype: "Cost Center",
|
|
||||||
txt: txt,
|
|
||||||
filters: {
|
|
||||||
"company": frappe.query_report.get_filter_value("company"),
|
|
||||||
"name": ["not in", values]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
callback: function(r) {
|
|
||||||
data = r.results;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return data;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname":"project",
|
"fieldname":"project",
|
||||||
"label": __("Project"),
|
"label": __("Project"),
|
||||||
"fieldtype": "MultiSelect",
|
"fieldtype": "MultiSelectList",
|
||||||
get_data: function() {
|
get_data: function(txt) {
|
||||||
var projects = frappe.query_report.get_filter_value("project") || "";
|
return frappe.db.get_link_options('Project', txt);
|
||||||
|
|
||||||
const values = projects.split(/\s*,\s*/).filter(d => d);
|
|
||||||
const txt = projects.match(/[^,\s*]*$/)[0] || '';
|
|
||||||
let data = [];
|
|
||||||
|
|
||||||
frappe.call({
|
|
||||||
type: "GET",
|
|
||||||
method:'frappe.desk.search.search_link',
|
|
||||||
async: false,
|
|
||||||
no_spinner: true,
|
|
||||||
args: {
|
|
||||||
doctype: "Project",
|
|
||||||
txt: txt,
|
|
||||||
filters: {
|
|
||||||
"name": ["not in", values]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
callback: function(r) {
|
|
||||||
data = r.results;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return data;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -217,6 +151,11 @@ frappe.query_reports["General Ledger"] = {
|
|||||||
"label": __("Show Opening Entries"),
|
"label": __("Show Opening Entries"),
|
||||||
"fieldtype": "Check"
|
"fieldtype": "Check"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "include_default_book_entries",
|
||||||
|
"label": __("Include Default Book Entries"),
|
||||||
|
"fieldtype": "Check"
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,8 +26,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 = cstr(filters.get("party")).strip()
|
filters.party = frappe.parse_json(filters.get("party"))
|
||||||
filters.party = [d.strip() for d in parties.split(',') if d]
|
|
||||||
|
|
||||||
validate_filters(filters, account_details)
|
validate_filters(filters, account_details)
|
||||||
|
|
||||||
@ -61,12 +60,10 @@ 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 = cstr(filters.get("project")).strip()
|
filters.project = frappe.parse_json(filters.get('project'))
|
||||||
filters.project = [d.strip() for d in projects.split(',') if d]
|
|
||||||
|
|
||||||
if filters.get('cost_center'):
|
if filters.get('cost_center'):
|
||||||
cost_centers = cstr(filters.get("cost_center")).strip()
|
filters.cost_center = frappe.parse_json(filters.get('cost_center'))
|
||||||
filters.cost_center = [d.strip() for d in cost_centers.split(',') if d]
|
|
||||||
|
|
||||||
|
|
||||||
def validate_party(filters):
|
def validate_party(filters):
|
||||||
@ -134,6 +131,10 @@ def get_gl_entries(filters):
|
|||||||
sum(debit_in_account_currency) as debit_in_account_currency,
|
sum(debit_in_account_currency) as debit_in_account_currency,
|
||||||
sum(credit_in_account_currency) as credit_in_account_currency"""
|
sum(credit_in_account_currency) as credit_in_account_currency"""
|
||||||
|
|
||||||
|
if filters.get("include_default_book_entries"):
|
||||||
|
filters['company_fb'] = frappe.db.get_value("Company",
|
||||||
|
filters.get("company"), 'default_finance_book')
|
||||||
|
|
||||||
gl_entries = frappe.db.sql(
|
gl_entries = frappe.db.sql(
|
||||||
"""
|
"""
|
||||||
select
|
select
|
||||||
@ -189,7 +190,10 @@ def get_conditions(filters):
|
|||||||
conditions.append("project in %(project)s")
|
conditions.append("project in %(project)s")
|
||||||
|
|
||||||
if filters.get("finance_book"):
|
if filters.get("finance_book"):
|
||||||
conditions.append("ifnull(finance_book, '') in (%(finance_book)s, '')")
|
if filters.get("include_default_book_entries"):
|
||||||
|
conditions.append("finance_book in (%(finance_book)s, %(company_fb)s)")
|
||||||
|
else:
|
||||||
|
conditions.append("finance_book in (%(finance_book)s)")
|
||||||
|
|
||||||
from frappe.desk.reportview import build_match_conditions
|
from frappe.desk.reportview import build_match_conditions
|
||||||
match_conditions = build_match_conditions("GL Entry")
|
match_conditions = build_match_conditions("GL Entry")
|
||||||
|
@ -13,33 +13,11 @@ frappe.require("assets/erpnext/js/financial_statements.js", function() {
|
|||||||
|
|
||||||
frappe.query_reports["Gross and Net Profit Report"]["filters"].push(
|
frappe.query_reports["Gross and Net Profit Report"]["filters"].push(
|
||||||
{
|
{
|
||||||
"fieldname":"project",
|
"fieldname": "project",
|
||||||
"label": __("Project"),
|
"label": __("Project"),
|
||||||
"fieldtype": "MultiSelect",
|
"fieldtype": "MultiSelectList",
|
||||||
get_data: function() {
|
get_data: function(txt) {
|
||||||
var projects = frappe.query_report.get_filter_value("project") || "";
|
return frappe.db.get_link_options('Project', txt);
|
||||||
|
|
||||||
const values = projects.split(/\s*,\s*/).filter(d => d);
|
|
||||||
const txt = projects.match(/[^,\s*]*$/)[0] || '';
|
|
||||||
let data = [];
|
|
||||||
|
|
||||||
frappe.call({
|
|
||||||
type: "GET",
|
|
||||||
method:'frappe.desk.search.search_link',
|
|
||||||
async: false,
|
|
||||||
no_spinner: true,
|
|
||||||
args: {
|
|
||||||
doctype: "Project",
|
|
||||||
txt: txt,
|
|
||||||
filters: {
|
|
||||||
"name": ["not in", values]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
callback: function(r) {
|
|
||||||
data = r.results;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return data;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -25,7 +25,8 @@ def get_ordered_to_be_billed_data(args):
|
|||||||
from
|
from
|
||||||
`{parent_tab}`, `{child_tab}`
|
`{parent_tab}`, `{child_tab}`
|
||||||
where
|
where
|
||||||
`{parent_tab}`.name = `{child_tab}`.parent and `{parent_tab}`.docstatus = 1 and `{parent_tab}`.status != 'Closed'
|
`{parent_tab}`.name = `{child_tab}`.parent and `{parent_tab}`.docstatus = 1
|
||||||
|
and `{parent_tab}`.status not in ('Closed', 'Completed')
|
||||||
and `{child_tab}`.amount > 0 and round(`{child_tab}`.billed_amt *
|
and `{child_tab}`.amount > 0 and round(`{child_tab}`.billed_amt *
|
||||||
ifnull(`{parent_tab}`.conversion_rate, 1), {precision}) < `{child_tab}`.base_amount
|
ifnull(`{parent_tab}`.conversion_rate, 1), {precision}) < `{child_tab}`.base_amount
|
||||||
order by
|
order by
|
||||||
|
@ -8,39 +8,22 @@ frappe.require("assets/erpnext/js/financial_statements.js", function() {
|
|||||||
|
|
||||||
frappe.query_reports["Profit and Loss Statement"]["filters"].push(
|
frappe.query_reports["Profit and Loss Statement"]["filters"].push(
|
||||||
{
|
{
|
||||||
"fieldname":"project",
|
"fieldname": "project",
|
||||||
"label": __("Project"),
|
"label": __("Project"),
|
||||||
"fieldtype": "MultiSelect",
|
"fieldtype": "MultiSelectList",
|
||||||
get_data: function() {
|
get_data: function(txt) {
|
||||||
var projects = frappe.query_report.get_filter_value("project") || "";
|
return frappe.db.get_link_options('Project', txt);
|
||||||
|
|
||||||
const values = projects.split(/\s*,\s*/).filter(d => d);
|
|
||||||
const txt = projects.match(/[^,\s*]*$/)[0] || '';
|
|
||||||
let data = [];
|
|
||||||
|
|
||||||
frappe.call({
|
|
||||||
type: "GET",
|
|
||||||
method:'frappe.desk.search.search_link',
|
|
||||||
async: false,
|
|
||||||
no_spinner: true,
|
|
||||||
args: {
|
|
||||||
doctype: "Project",
|
|
||||||
txt: txt,
|
|
||||||
filters: {
|
|
||||||
"name": ["not in", values]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
callback: function(r) {
|
|
||||||
data = r.results;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return data;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "accumulated_values",
|
"fieldname": "accumulated_values",
|
||||||
"label": __("Accumulated Values"),
|
"label": __("Accumulated Values"),
|
||||||
"fieldtype": "Check"
|
"fieldtype": "Check"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "include_default_book_entries",
|
||||||
|
"label": __("Include Default Book Entries"),
|
||||||
|
"fieldtype": "Check"
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -105,7 +105,7 @@ def get_rootwise_opening_balances(filters, report_type):
|
|||||||
if filters.finance_book:
|
if filters.finance_book:
|
||||||
fb_conditions = " and finance_book = %(finance_book)s"
|
fb_conditions = " and finance_book = %(finance_book)s"
|
||||||
if filters.include_default_book_entries:
|
if filters.include_default_book_entries:
|
||||||
fb_conditions = " and (finance_book in (%(finance_book)s, %(company_fb)s) or finance_book is null)"
|
fb_conditions = " and (finance_book in (%(finance_book)s, %(company_fb)s))"
|
||||||
|
|
||||||
additional_conditions += fb_conditions
|
additional_conditions += fb_conditions
|
||||||
|
|
||||||
|
@ -291,16 +291,19 @@ class Asset(AccountsController):
|
|||||||
|
|
||||||
def validate_expected_value_after_useful_life(self):
|
def validate_expected_value_after_useful_life(self):
|
||||||
for row in self.get('finance_books'):
|
for row in self.get('finance_books'):
|
||||||
accumulated_depreciation_after_full_schedule = max([d.accumulated_depreciation_amount
|
accumulated_depreciation_after_full_schedule = [d.accumulated_depreciation_amount
|
||||||
for d in self.get("schedules") if cint(d.finance_book_id) == row.idx])
|
for d in self.get("schedules") if cint(d.finance_book_id) == row.idx]
|
||||||
|
|
||||||
asset_value_after_full_schedule = flt(flt(self.gross_purchase_amount) -
|
if accumulated_depreciation_after_full_schedule:
|
||||||
flt(accumulated_depreciation_after_full_schedule),
|
accumulated_depreciation_after_full_schedule = max(accumulated_depreciation_after_full_schedule)
|
||||||
self.precision('gross_purchase_amount'))
|
|
||||||
|
|
||||||
if row.expected_value_after_useful_life < asset_value_after_full_schedule:
|
asset_value_after_full_schedule = flt(flt(self.gross_purchase_amount) -
|
||||||
frappe.throw(_("Depreciation Row {0}: Expected value after useful life must be greater than or equal to {1}")
|
flt(accumulated_depreciation_after_full_schedule),
|
||||||
.format(row.idx, asset_value_after_full_schedule))
|
self.precision('gross_purchase_amount'))
|
||||||
|
|
||||||
|
if row.expected_value_after_useful_life < asset_value_after_full_schedule:
|
||||||
|
frappe.throw(_("Depreciation Row {0}: Expected value after useful life must be greater than or equal to {1}")
|
||||||
|
.format(row.idx, asset_value_after_full_schedule))
|
||||||
|
|
||||||
def validate_cancellation(self):
|
def validate_cancellation(self):
|
||||||
if self.status not in ("Submitted", "Partially Depreciated", "Fully Depreciated"):
|
if self.status not in ("Submitted", "Partially Depreciated", "Fully Depreciated"):
|
||||||
|
@ -25,9 +25,12 @@ class TestLocation(unittest.TestCase):
|
|||||||
temp['features'][0]['properties']['feature_of'] = location
|
temp['features'][0]['properties']['feature_of'] = location
|
||||||
formatted_locations.extend(temp['features'])
|
formatted_locations.extend(temp['features'])
|
||||||
|
|
||||||
formatted_location_string = str(formatted_locations)
|
|
||||||
test_location = frappe.get_doc('Location', 'Test Location Area')
|
test_location = frappe.get_doc('Location', 'Test Location Area')
|
||||||
test_location.save()
|
test_location.save()
|
||||||
|
|
||||||
self.assertEqual(formatted_location_string, str(json.loads(test_location.get('location'))['features']))
|
test_location_features = json.loads(test_location.get('location'))['features']
|
||||||
|
ordered_test_location_features = sorted(test_location_features, key=lambda x: x['properties']['feature_of'])
|
||||||
|
ordered_formatted_locations = sorted(formatted_locations, key=lambda x: x['properties']['feature_of'])
|
||||||
|
|
||||||
|
self.assertEqual(ordered_formatted_locations, ordered_test_location_features)
|
||||||
self.assertEqual(area, test_location.get('area'))
|
self.assertEqual(area, test_location.get('area'))
|
||||||
|
@ -107,7 +107,7 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend(
|
|||||||
if(doc.docstatus == 1) {
|
if(doc.docstatus == 1) {
|
||||||
if(!in_list(["Closed", "Delivered"], doc.status)) {
|
if(!in_list(["Closed", "Delivered"], doc.status)) {
|
||||||
if (this.frm.has_perm("submit")) {
|
if (this.frm.has_perm("submit")) {
|
||||||
if(flt(doc.per_billed, 2) < 100 || doc.per_received < 100) {
|
if(flt(doc.per_billed, 6) < 100 || flt(doc.per_received, 6) < 100) {
|
||||||
if (doc.status != "On Hold") {
|
if (doc.status != "On Hold") {
|
||||||
this.frm.add_custom_button(__('Hold'), () => this.hold_purchase_order(), __("Status"));
|
this.frm.add_custom_button(__('Hold'), () => this.hold_purchase_order(), __("Status"));
|
||||||
} else{
|
} else{
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -557,7 +557,7 @@
|
|||||||
"print_hide": 1
|
"print_hide": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"default": "1",
|
"default": "0",
|
||||||
"depends_on": "eval:parent.is_subcontracted == 'Yes'",
|
"depends_on": "eval:parent.is_subcontracted == 'Yes'",
|
||||||
"fieldname": "include_exploded_items",
|
"fieldname": "include_exploded_items",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
@ -701,7 +701,7 @@
|
|||||||
],
|
],
|
||||||
"idx": 1,
|
"idx": 1,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"modified": "2019-06-02 06:34:47.495730",
|
"modified": "2019-06-23 20:03:13.818917",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "Buying",
|
"module": "Buying",
|
||||||
"name": "Purchase Order Item",
|
"name": "Purchase Order Item",
|
||||||
@ -712,4 +712,4 @@
|
|||||||
"sort_field": "modified",
|
"sort_field": "modified",
|
||||||
"sort_order": "DESC",
|
"sort_order": "DESC",
|
||||||
"track_changes": 1
|
"track_changes": 1
|
||||||
}
|
}
|
||||||
|
@ -40,17 +40,6 @@ def get_data():
|
|||||||
"description": _("Tree of financial accounts."),
|
"description": _("Tree of financial accounts."),
|
||||||
"onboard": 1,
|
"onboard": 1,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"type": "doctype",
|
|
||||||
"name": "Journal Entry",
|
|
||||||
"description": _("Accounting journal entries."),
|
|
||||||
"onboard": 1,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "doctype",
|
|
||||||
"name": "Opening Invoice Creation Tool",
|
|
||||||
"description": _("Create Opening Sales and Purchase Invoices")
|
|
||||||
},
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -73,11 +62,6 @@ def get_data():
|
|||||||
"name": "Payment Request",
|
"name": "Payment Request",
|
||||||
"description": _("Payment Request"),
|
"description": _("Payment Request"),
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"type": "doctype",
|
|
||||||
"name": "Payment Entry",
|
|
||||||
"description": _("Bank/Cash transactions against party or for internal transfer")
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"type": "doctype",
|
"type": "doctype",
|
||||||
"name": "Payment Term",
|
"name": "Payment Term",
|
||||||
@ -179,6 +163,26 @@ def get_data():
|
|||||||
"name": "Accounting Dimension",
|
"name": "Accounting Dimension",
|
||||||
"description": _("Setup custom dimensions for accounting")
|
"description": _("Setup custom dimensions for accounting")
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "doctype",
|
||||||
|
"name": "Opening Invoice Creation Tool",
|
||||||
|
"description": _("Create Opening Sales and Purchase Invoices")
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": _("Accounting Entries"),
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"type": "doctype",
|
||||||
|
"name": "Payment Entry",
|
||||||
|
"description": _("Bank/Cash transactions against party or for internal transfer")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "doctype",
|
||||||
|
"name": "Journal Entry",
|
||||||
|
"description": _("Accounting journal entries.")
|
||||||
|
},
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -220,7 +220,7 @@ def get_data():
|
|||||||
"type": "report",
|
"type": "report",
|
||||||
"is_query_report": True,
|
"is_query_report": True,
|
||||||
"name": "Address And Contacts",
|
"name": "Address And Contacts",
|
||||||
"label": "Supplier Addresses And Contacts",
|
"label": _("Supplier Addresses And Contacts"),
|
||||||
"reference_doctype": "Address",
|
"reference_doctype": "Address",
|
||||||
"route_options": {
|
"route_options": {
|
||||||
"party_type": "Supplier"
|
"party_type": "Supplier"
|
||||||
|
@ -18,6 +18,11 @@ def get_data():
|
|||||||
"onboard": 1,
|
"onboard": 1,
|
||||||
"dependencies": ["Employee"]
|
"dependencies": ["Employee"]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "doctype",
|
||||||
|
"name": "Employee Group",
|
||||||
|
"dependencies": ["Employee"]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "doctype",
|
"type": "doctype",
|
||||||
"name": "Attendance",
|
"name": "Attendance",
|
||||||
@ -34,6 +39,13 @@ def get_data():
|
|||||||
"name": "Upload Attendance",
|
"name": "Upload Attendance",
|
||||||
"hide_count": True,
|
"hide_count": True,
|
||||||
"dependencies": ["Employee"]
|
"dependencies": ["Employee"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "doctype",
|
||||||
|
"name": "Employee Checkin",
|
||||||
|
"hide_count": True,
|
||||||
|
"onboard": 1,
|
||||||
|
"dependencies": ["Employee"]
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -12,6 +12,16 @@ def get_data():
|
|||||||
"description": _("Support queries from customers."),
|
"description": _("Support queries from customers."),
|
||||||
"onboard": 1,
|
"onboard": 1,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "doctype",
|
||||||
|
"name": "Issue Type",
|
||||||
|
"description": _("Issue Type."),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "doctype",
|
||||||
|
"name": "Issue Priority",
|
||||||
|
"description": _("Issue Priority."),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "doctype",
|
"type": "doctype",
|
||||||
"name": "Communication",
|
"name": "Communication",
|
||||||
@ -38,11 +48,6 @@ def get_data():
|
|||||||
{
|
{
|
||||||
"label": _("Service Level Agreement"),
|
"label": _("Service Level Agreement"),
|
||||||
"items": [
|
"items": [
|
||||||
{
|
|
||||||
"type": "doctype",
|
|
||||||
"name": "Employee Group",
|
|
||||||
"description": _("Support Team."),
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"type": "doctype",
|
"type": "doctype",
|
||||||
"name": "Service Level",
|
"name": "Service Level",
|
||||||
|
@ -778,7 +778,12 @@ class AccountsController(TransactionBase):
|
|||||||
count += 1
|
count += 1
|
||||||
item.qty = group_item_qty[item.item_code]
|
item.qty = group_item_qty[item.item_code]
|
||||||
item.amount = group_item_amount[item.item_code]
|
item.amount = group_item_amount[item.item_code]
|
||||||
item.rate = flt(flt(item.amount) / flt(item.qty), item.precision("rate"))
|
|
||||||
|
if item.qty:
|
||||||
|
item.rate = flt(flt(item.amount) / flt(item.qty), item.precision("rate"))
|
||||||
|
else:
|
||||||
|
item.rate = 0
|
||||||
|
|
||||||
item.idx = count
|
item.idx = count
|
||||||
del group_item_qty[item.item_code]
|
del group_item_qty[item.item_code]
|
||||||
else:
|
else:
|
||||||
|
@ -428,8 +428,9 @@ class BuyingController(StockController):
|
|||||||
elif not flt(d.rejected_qty):
|
elif not flt(d.rejected_qty):
|
||||||
d.rejected_qty = flt(d.received_qty) - flt(d.qty)
|
d.rejected_qty = flt(d.received_qty) - flt(d.qty)
|
||||||
|
|
||||||
|
val = flt(d.qty) + flt(d.rejected_qty)
|
||||||
# Check Received Qty = Accepted Qty + Rejected Qty
|
# Check Received Qty = Accepted Qty + Rejected Qty
|
||||||
if ((flt(d.qty) + flt(d.rejected_qty)) != flt(d.received_qty)):
|
if (flt(val, d.precision("received_qty")) != flt(d.received_qty, d.precision("received_qty"))):
|
||||||
frappe.throw(_("Accepted + Rejected Qty must be equal to Received quantity for Item {0}").format(d.item_code))
|
frappe.throw(_("Accepted + Rejected Qty must be equal to Received quantity for Item {0}").format(d.item_code))
|
||||||
|
|
||||||
def validate_negative_quantity(self, item_row, field_list):
|
def validate_negative_quantity(self, item_row, field_list):
|
||||||
|
@ -27,7 +27,7 @@ status_map = {
|
|||||||
],
|
],
|
||||||
"Quotation": [
|
"Quotation": [
|
||||||
["Draft", None],
|
["Draft", None],
|
||||||
["Submitted", "eval:self.docstatus==1"],
|
["Open", "eval:self.docstatus==1"],
|
||||||
["Lost", "eval:self.status=='Lost'"],
|
["Lost", "eval:self.status=='Lost'"],
|
||||||
["Ordered", "has_sales_order"],
|
["Ordered", "has_sales_order"],
|
||||||
["Cancelled", "eval:self.docstatus==2"],
|
["Cancelled", "eval:self.docstatus==2"],
|
||||||
|
@ -342,7 +342,7 @@ def assign_to_user(doc, subject_field):
|
|||||||
elif doc.lead:
|
elif doc.lead:
|
||||||
assign_user = frappe.db.get_value('Lead', doc.lead, 'lead_owner')
|
assign_user = frappe.db.get_value('Lead', doc.lead, 'lead_owner')
|
||||||
|
|
||||||
if assign_user and assign_user != 'Administrator':
|
if assign_user and assign_user not in ['Administrator', 'Guest']:
|
||||||
if not assign_to.get(dict(doctype = doc.doctype, name = doc.name)):
|
if not assign_to.get(dict(doctype = doc.doctype, name = doc.name)):
|
||||||
assign_to.add({
|
assign_to.add({
|
||||||
"assign_to": assign_user,
|
"assign_to": assign_user,
|
||||||
|
@ -97,7 +97,7 @@ def get_expenses():
|
|||||||
"expense_date": frappe.flags.current_date,
|
"expense_date": frappe.flags.current_date,
|
||||||
"expense_type": expense_type.name,
|
"expense_type": expense_type.name,
|
||||||
"default_account": expense_type.default_account or "Miscellaneous Expenses - WPL",
|
"default_account": expense_type.default_account or "Miscellaneous Expenses - WPL",
|
||||||
"claim_amount": claim_amount,
|
"amount": claim_amount,
|
||||||
"sanctioned_amount": claim_amount
|
"sanctioned_amount": claim_amount
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -107,7 +107,7 @@ def update_sanctioned_amount(expense_claim):
|
|||||||
for expense in expense_claim.expenses:
|
for expense in expense_claim.expenses:
|
||||||
sanctioned_amount = random.randint(1,20)*10
|
sanctioned_amount = random.randint(1,20)*10
|
||||||
|
|
||||||
if sanctioned_amount < expense.claim_amount:
|
if sanctioned_amount < expense.amount:
|
||||||
expense.sanctioned_amount = sanctioned_amount
|
expense.sanctioned_amount = sanctioned_amount
|
||||||
|
|
||||||
def get_timesheet_based_salary_slip_employee():
|
def get_timesheet_based_salary_slip_employee():
|
||||||
|
@ -22,7 +22,16 @@ def verify_request():
|
|||||||
frappe.set_user(woocommerce_settings.creation_user)
|
frappe.set_user(woocommerce_settings.creation_user)
|
||||||
|
|
||||||
@frappe.whitelist(allow_guest=True)
|
@frappe.whitelist(allow_guest=True)
|
||||||
def order():
|
def order(*args, **kwargs):
|
||||||
|
try:
|
||||||
|
_order(*args, **kwargs)
|
||||||
|
except Exception:
|
||||||
|
error_message = frappe.get_traceback()+"\n\n Request Data: \n"+json.loads(frappe.request.data).__str__()
|
||||||
|
frappe.log_error(error_message, "WooCommerce Error")
|
||||||
|
raise
|
||||||
|
|
||||||
|
|
||||||
|
def _order(*args, **kwargs):
|
||||||
woocommerce_settings = frappe.get_doc("Woocommerce Settings")
|
woocommerce_settings = frappe.get_doc("Woocommerce Settings")
|
||||||
if frappe.flags.woocomm_test_order_data:
|
if frappe.flags.woocomm_test_order_data:
|
||||||
fd = frappe.flags.woocomm_test_order_data
|
fd = frappe.flags.woocomm_test_order_data
|
||||||
|
@ -10,6 +10,7 @@ app_color = "#e74c3c"
|
|||||||
app_email = "info@erpnext.com"
|
app_email = "info@erpnext.com"
|
||||||
app_license = "GNU General Public License (v3)"
|
app_license = "GNU General Public License (v3)"
|
||||||
source_link = "https://github.com/frappe/erpnext"
|
source_link = "https://github.com/frappe/erpnext"
|
||||||
|
app_logo_url = '/assets/erpnext/images/erp-icon.svg'
|
||||||
|
|
||||||
|
|
||||||
develop_version = '12.x.x-develop'
|
develop_version = '12.x.x-develop'
|
||||||
@ -45,7 +46,7 @@ update_and_get_user_progress = "erpnext.utilities.user_progress_utils.update_def
|
|||||||
on_session_creation = "erpnext.shopping_cart.utils.set_cart_count"
|
on_session_creation = "erpnext.shopping_cart.utils.set_cart_count"
|
||||||
on_logout = "erpnext.shopping_cart.utils.clear_cart_count"
|
on_logout = "erpnext.shopping_cart.utils.clear_cart_count"
|
||||||
|
|
||||||
treeviews = ['Account', 'Cost Center', 'Warehouse', 'Item Group', 'Customer Group', 'Sales Person', 'Territory', 'Assessment Group']
|
treeviews = ['Account', 'Cost Center', 'Warehouse', 'Item Group', 'Customer Group', 'Sales Person', 'Territory', 'Assessment Group', 'Department']
|
||||||
|
|
||||||
# website
|
# website
|
||||||
update_website_context = ["erpnext.shopping_cart.utils.update_website_context", "erpnext.education.doctype.education_settings.education_settings.update_website_context"]
|
update_website_context = ["erpnext.shopping_cart.utils.update_website_context", "erpnext.education.doctype.education_settings.education_settings.update_website_context"]
|
||||||
@ -245,7 +246,9 @@ scheduler_events = {
|
|||||||
"erpnext.erpnext_integrations.doctype.amazon_mws_settings.amazon_mws_settings.schedule_get_order_details",
|
"erpnext.erpnext_integrations.doctype.amazon_mws_settings.amazon_mws_settings.schedule_get_order_details",
|
||||||
"erpnext.accounts.doctype.gl_entry.gl_entry.rename_gle_sle_docs",
|
"erpnext.accounts.doctype.gl_entry.gl_entry.rename_gle_sle_docs",
|
||||||
"erpnext.projects.doctype.project.project.hourly_reminder",
|
"erpnext.projects.doctype.project.project.hourly_reminder",
|
||||||
"erpnext.projects.doctype.project.project.collect_project_status"
|
"erpnext.projects.doctype.project.project.collect_project_status",
|
||||||
|
"erpnext.hr.doctype.shift_type.shift_type.process_auto_attendance_for_all_shifts",
|
||||||
|
"erpnext.support.doctype.issue.issue.set_service_level_agreement_variance",
|
||||||
],
|
],
|
||||||
"daily": [
|
"daily": [
|
||||||
"erpnext.stock.reorder_item.reorder_item",
|
"erpnext.stock.reorder_item.reorder_item",
|
||||||
@ -267,7 +270,7 @@ scheduler_events = {
|
|||||||
"erpnext.projects.doctype.project.project.update_project_sales_billing",
|
"erpnext.projects.doctype.project.project.update_project_sales_billing",
|
||||||
"erpnext.projects.doctype.project.project.send_project_status_email_to_users",
|
"erpnext.projects.doctype.project.project.send_project_status_email_to_users",
|
||||||
"erpnext.quality_management.doctype.quality_review.quality_review.review",
|
"erpnext.quality_management.doctype.quality_review.quality_review.review",
|
||||||
"erpnext.support.doctype.service_level_agreement.service_level_agreement.check_agreement_status"
|
"erpnext.support.doctype.service_level_agreement.service_level_agreement.check_agreement_status",
|
||||||
],
|
],
|
||||||
"daily_long": [
|
"daily_long": [
|
||||||
"erpnext.manufacturing.doctype.bom_update_tool.bom_update_tool.update_latest_price_in_all_boms"
|
"erpnext.manufacturing.doctype.bom_update_tool.bom_update_tool.update_latest_price_in_all_boms"
|
||||||
|
@ -1,540 +1,213 @@
|
|||||||
{
|
{
|
||||||
"allow_copy": 0,
|
|
||||||
"allow_events_in_timeline": 0,
|
|
||||||
"allow_guest_to_view": 0,
|
|
||||||
"allow_import": 1,
|
"allow_import": 1,
|
||||||
"allow_rename": 0,
|
|
||||||
"autoname": "naming_series:",
|
"autoname": "naming_series:",
|
||||||
"beta": 0,
|
|
||||||
"creation": "2013-01-10 16:34:13",
|
"creation": "2013-01-10 16:34:13",
|
||||||
"custom": 0,
|
|
||||||
"docstatus": 0,
|
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"document_type": "Setup",
|
"document_type": "Setup",
|
||||||
"editable_grid": 0,
|
"field_order": [
|
||||||
|
"attendance_details",
|
||||||
|
"naming_series",
|
||||||
|
"employee",
|
||||||
|
"employee_name",
|
||||||
|
"working_hours",
|
||||||
|
"status",
|
||||||
|
"leave_type",
|
||||||
|
"leave_application",
|
||||||
|
"column_break0",
|
||||||
|
"attendance_date",
|
||||||
|
"company",
|
||||||
|
"department",
|
||||||
|
"shift",
|
||||||
|
"attendance_request",
|
||||||
|
"amended_from"
|
||||||
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "attendance_details",
|
"fieldname": "attendance_details",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"oldfieldtype": "Section Break",
|
"oldfieldtype": "Section Break",
|
||||||
"options": "Simple",
|
"options": "Simple"
|
||||||
"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,
|
|
||||||
"default": "",
|
|
||||||
"fieldname": "naming_series",
|
"fieldname": "naming_series",
|
||||||
"fieldtype": "Select",
|
"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": "Series",
|
"label": "Series",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"oldfieldname": "naming_series",
|
"oldfieldname": "naming_series",
|
||||||
"oldfieldtype": "Select",
|
"oldfieldtype": "Select",
|
||||||
"options": "HR-ATT-.YYYY.-",
|
"options": "HR-ATT-.YYYY.-",
|
||||||
"permlevel": 0,
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 1,
|
"reqd": 1,
|
||||||
"search_index": 0,
|
"set_only_once": 1
|
||||||
"set_only_once": 1,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "employee",
|
"fieldname": "employee",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 1,
|
"in_global_search": 1,
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 1,
|
"in_standard_filter": 1,
|
||||||
"label": "Employee",
|
"label": "Employee",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"oldfieldname": "employee",
|
"oldfieldname": "employee",
|
||||||
"oldfieldtype": "Link",
|
"oldfieldtype": "Link",
|
||||||
"options": "Employee",
|
"options": "Employee",
|
||||||
"permlevel": 0,
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 1,
|
"reqd": 1,
|
||||||
"search_index": 1,
|
"search_index": 1
|
||||||
"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": "employee.employee_name",
|
"fetch_from": "employee.employee_name",
|
||||||
"fieldname": "employee_name",
|
"fieldname": "employee_name",
|
||||||
"fieldtype": "Read Only",
|
"fieldtype": "Read Only",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 1,
|
"in_global_search": 1,
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Employee Name",
|
"label": "Employee Name",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"oldfieldname": "employee_name",
|
"oldfieldname": "employee_name",
|
||||||
"oldfieldtype": "Data",
|
"oldfieldtype": "Data"
|
||||||
"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,
|
|
||||||
"default": "Present",
|
"default": "Present",
|
||||||
"fieldname": "status",
|
"fieldname": "status",
|
||||||
"fieldtype": "Select",
|
"fieldtype": "Select",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 1,
|
"in_standard_filter": 1,
|
||||||
"label": "Status",
|
"label": "Status",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"oldfieldname": "status",
|
"oldfieldname": "status",
|
||||||
"oldfieldtype": "Select",
|
"oldfieldtype": "Select",
|
||||||
"options": "\nPresent\nAbsent\nOn Leave\nHalf Day",
|
"options": "\nPresent\nAbsent\nOn Leave\nHalf Day",
|
||||||
"permlevel": 0,
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 1,
|
"reqd": 1,
|
||||||
"search_index": 1,
|
"search_index": 1
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"depends_on": "eval:doc.status==\"On Leave\"",
|
"depends_on": "eval:doc.status==\"On Leave\"",
|
||||||
"fieldname": "leave_type",
|
"fieldname": "leave_type",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 1,
|
"in_standard_filter": 1,
|
||||||
"label": "Leave Type",
|
"label": "Leave Type",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"oldfieldname": "leave_type",
|
"oldfieldname": "leave_type",
|
||||||
"oldfieldtype": "Link",
|
"oldfieldtype": "Link",
|
||||||
"options": "Leave Type",
|
"options": "Leave Type"
|
||||||
"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": "leave_application",
|
"fieldname": "leave_application",
|
||||||
"fieldtype": "Link",
|
"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": "Leave Application",
|
"label": "Leave Application",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Leave Application",
|
"options": "Leave Application",
|
||||||
"permlevel": 0,
|
"read_only": 1
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 1,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "column_break0",
|
"fieldname": "column_break0",
|
||||||
"fieldtype": "Column Break",
|
"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,
|
|
||||||
"oldfieldtype": "Column Break",
|
"oldfieldtype": "Column Break",
|
||||||
"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,
|
|
||||||
"width": "50%"
|
"width": "50%"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "attendance_date",
|
"fieldname": "attendance_date",
|
||||||
"fieldtype": "Date",
|
"fieldtype": "Date",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Attendance Date",
|
"label": "Attendance Date",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"oldfieldname": "attendance_date",
|
"oldfieldname": "attendance_date",
|
||||||
"oldfieldtype": "Date",
|
"oldfieldtype": "Date",
|
||||||
"permlevel": 0,
|
"reqd": 1
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 1,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "company",
|
"fieldname": "company",
|
||||||
"fieldtype": "Link",
|
"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",
|
"label": "Company",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"oldfieldname": "company",
|
"oldfieldname": "company",
|
||||||
"oldfieldtype": "Link",
|
"oldfieldtype": "Link",
|
||||||
"options": "Company",
|
"options": "Company",
|
||||||
"permlevel": 0,
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 1,
|
"remember_last_selected_value": 1,
|
||||||
"report_hide": 0,
|
"reqd": 1
|
||||||
"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": "employee.department",
|
"fetch_from": "employee.department",
|
||||||
"fieldname": "department",
|
"fieldname": "department",
|
||||||
"fieldtype": "Link",
|
"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": "Department",
|
"label": "Department",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Department",
|
"options": "Department",
|
||||||
"permlevel": 0,
|
"read_only": 1
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 1,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "attendance_request",
|
"fieldname": "attendance_request",
|
||||||
"fieldtype": "Link",
|
"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": "Attendance Request",
|
"label": "Attendance Request",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Attendance Request",
|
"options": "Attendance Request",
|
||||||
"permlevel": 0,
|
"read_only": 1
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 1,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "amended_from",
|
"fieldname": "amended_from",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 1,
|
"ignore_user_permissions": 1,
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Amended From",
|
"label": "Amended From",
|
||||||
"length": 0,
|
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"options": "Attendance",
|
"options": "Attendance",
|
||||||
"permlevel": 0,
|
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"print_hide_if_no_value": 0,
|
"read_only": 1
|
||||||
"read_only": 1,
|
},
|
||||||
"remember_last_selected_value": 0,
|
{
|
||||||
"report_hide": 0,
|
"depends_on": "working_hours",
|
||||||
"reqd": 0,
|
"fieldname": "working_hours",
|
||||||
"search_index": 0,
|
"fieldtype": "Float",
|
||||||
"set_only_once": 0,
|
"label": "Working Hours",
|
||||||
"translatable": 0,
|
"precision": "1",
|
||||||
"unique": 0
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "shift",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"label": "Shift",
|
||||||
|
"options": "Shift Type"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"has_web_view": 0,
|
|
||||||
"hide_heading": 0,
|
|
||||||
"hide_toolbar": 0,
|
|
||||||
"icon": "fa fa-ok",
|
"icon": "fa fa-ok",
|
||||||
"idx": 1,
|
"idx": 1,
|
||||||
"image_view": 0,
|
|
||||||
"in_create": 0,
|
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"issingle": 0,
|
"modified": "2019-06-05 19:37:30.410071",
|
||||||
"istable": 0,
|
|
||||||
"max_attachments": 0,
|
|
||||||
"modified": "2019-06-05 12:00:14.043535",
|
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "HR",
|
"module": "HR",
|
||||||
"name": "Attendance",
|
"name": "Attendance",
|
||||||
"owner": "ashwini@webnotestech.com",
|
"owner": "ashwini@webnotestech.com",
|
||||||
"permissions": [
|
"permissions": [
|
||||||
{
|
{
|
||||||
"amend": 0,
|
|
||||||
"cancel": 1,
|
"cancel": 1,
|
||||||
"create": 1,
|
"create": 1,
|
||||||
"delete": 1,
|
"delete": 1,
|
||||||
"email": 1,
|
"email": 1,
|
||||||
"export": 0,
|
|
||||||
"if_owner": 0,
|
|
||||||
"import": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"print": 1,
|
"print": 1,
|
||||||
"read": 1,
|
"read": 1,
|
||||||
"report": 1,
|
"report": 1,
|
||||||
"role": "System Manager",
|
"role": "System Manager",
|
||||||
"set_user_permissions": 0,
|
|
||||||
"share": 1,
|
"share": 1,
|
||||||
"submit": 1,
|
"submit": 1,
|
||||||
"write": 1
|
"write": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"amend": 0,
|
|
||||||
"cancel": 1,
|
"cancel": 1,
|
||||||
"create": 1,
|
"create": 1,
|
||||||
"delete": 1,
|
"delete": 1,
|
||||||
"email": 1,
|
"email": 1,
|
||||||
"export": 1,
|
"export": 1,
|
||||||
"if_owner": 0,
|
|
||||||
"import": 1,
|
"import": 1,
|
||||||
"permlevel": 0,
|
|
||||||
"print": 1,
|
"print": 1,
|
||||||
"read": 1,
|
"read": 1,
|
||||||
"report": 1,
|
"report": 1,
|
||||||
"role": "HR User",
|
"role": "HR User",
|
||||||
"set_user_permissions": 0,
|
|
||||||
"share": 1,
|
"share": 1,
|
||||||
"submit": 1,
|
"submit": 1,
|
||||||
"write": 1
|
"write": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"amend": 0,
|
|
||||||
"cancel": 1,
|
"cancel": 1,
|
||||||
"create": 1,
|
"create": 1,
|
||||||
"delete": 1,
|
"delete": 1,
|
||||||
"email": 1,
|
"email": 1,
|
||||||
"export": 0,
|
|
||||||
"if_owner": 0,
|
|
||||||
"import": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"print": 1,
|
"print": 1,
|
||||||
"read": 1,
|
"read": 1,
|
||||||
"report": 1,
|
"report": 1,
|
||||||
"role": "HR Manager",
|
"role": "HR Manager",
|
||||||
"set_user_permissions": 0,
|
|
||||||
"share": 1,
|
"share": 1,
|
||||||
"submit": 1,
|
"submit": 1,
|
||||||
"write": 1
|
"write": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"quick_entry": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"read_only_onload": 0,
|
|
||||||
"search_fields": "employee,employee_name,attendance_date,status",
|
"search_fields": "employee,employee_name,attendance_date,status",
|
||||||
"show_name_in_global_search": 0,
|
|
||||||
"sort_field": "modified",
|
"sort_field": "modified",
|
||||||
"sort_order": "DESC",
|
"sort_order": "DESC",
|
||||||
"title_field": "employee_name",
|
"title_field": "employee_name"
|
||||||
"track_changes": 0,
|
|
||||||
"track_seen": 0,
|
|
||||||
"track_views": 0
|
|
||||||
}
|
}
|
@ -88,3 +88,18 @@ def add_attendance(events, start, end, conditions=None):
|
|||||||
}
|
}
|
||||||
if e not in events:
|
if e not in events:
|
||||||
events.append(e)
|
events.append(e)
|
||||||
|
|
||||||
|
def mark_absent(employee, attendance_date, shift=None):
|
||||||
|
employee_doc = frappe.get_doc('Employee', employee)
|
||||||
|
if not frappe.db.exists('Attendance', {'employee':employee, 'attendance_date':attendance_date, 'docstatus':('!=', '2')}):
|
||||||
|
doc_dict = {
|
||||||
|
'doctype': 'Attendance',
|
||||||
|
'employee': employee,
|
||||||
|
'attendance_date': attendance_date,
|
||||||
|
'status': 'Absent',
|
||||||
|
'company': employee_doc.company,
|
||||||
|
'shift': shift
|
||||||
|
}
|
||||||
|
attendance = frappe.get_doc(doc_dict).insert()
|
||||||
|
attendance.submit()
|
||||||
|
return attendance.name
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
// For license information, please see license.txt
|
// For license information, please see license.txt
|
||||||
frappe.views.calendar["Attendance"] = {
|
frappe.views.calendar["Attendance"] = {
|
||||||
field_map: {
|
field_map: {
|
||||||
"start": "date",
|
"start": "attendance_date",
|
||||||
"end": "date",
|
"end": "attendance_date",
|
||||||
"id": "name",
|
"id": "name",
|
||||||
"docstatus": 1
|
"docstatus": 1
|
||||||
},
|
},
|
||||||
|
13
erpnext/hr/doctype/attendance/attendance_dashboard.py
Normal file
13
erpnext/hr/doctype/attendance/attendance_dashboard.py
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
from __future__ import unicode_literals
|
||||||
|
from frappe import _
|
||||||
|
|
||||||
|
def get_data():
|
||||||
|
return {
|
||||||
|
'fieldname': 'attendance',
|
||||||
|
'transactions': [
|
||||||
|
{
|
||||||
|
'label': '',
|
||||||
|
'items': ['Employee Checkin']
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -4,8 +4,17 @@ from __future__ import unicode_literals
|
|||||||
|
|
||||||
import frappe
|
import frappe
|
||||||
import unittest
|
import unittest
|
||||||
|
from frappe.utils import nowdate
|
||||||
|
|
||||||
test_records = frappe.get_test_records('Attendance')
|
test_records = frappe.get_test_records('Attendance')
|
||||||
|
|
||||||
class TestAttendance(unittest.TestCase):
|
class TestAttendance(unittest.TestCase):
|
||||||
pass
|
def test_mark_absent(self):
|
||||||
|
from erpnext.hr.doctype.employee.test_employee import make_employee
|
||||||
|
employee = make_employee("test_mark_absent@example.com")
|
||||||
|
date = nowdate()
|
||||||
|
frappe.db.delete('Attendance', {'employee':employee, 'attendance_date':date})
|
||||||
|
from erpnext.hr.doctype.attendance.attendance import mark_absent
|
||||||
|
attendance = mark_absent(employee, date)
|
||||||
|
fetch_attendance = frappe.get_value('Attendance', {'employee':employee, 'attendance_date':date, 'status':'Absent'})
|
||||||
|
self.assertEqual(attendance, fetch_attendance)
|
||||||
|
@ -8,6 +8,7 @@ from frappe.model.document import Document
|
|||||||
import frappe.utils
|
import frappe.utils
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from erpnext.hr.doctype.daily_work_summary.daily_work_summary import get_user_emails_from_group
|
from erpnext.hr.doctype.daily_work_summary.daily_work_summary import get_user_emails_from_group
|
||||||
|
from erpnext.hr.doctype.holiday_list.holiday_list import is_holiday
|
||||||
|
|
||||||
class DailyWorkSummaryGroup(Document):
|
class DailyWorkSummaryGroup(Document):
|
||||||
def validate(self):
|
def validate(self):
|
||||||
@ -23,7 +24,7 @@ def trigger_emails():
|
|||||||
for d in groups:
|
for d in groups:
|
||||||
group_doc = frappe.get_doc("Daily Work Summary Group", d)
|
group_doc = frappe.get_doc("Daily Work Summary Group", d)
|
||||||
if (is_current_hour(group_doc.send_emails_at)
|
if (is_current_hour(group_doc.send_emails_at)
|
||||||
and not is_holiday_today(group_doc.holiday_list)
|
and not is_holiday(group_doc.holiday_list)
|
||||||
and group_doc.enabled):
|
and group_doc.enabled):
|
||||||
emails = get_user_emails_from_group(group_doc)
|
emails = get_user_emails_from_group(group_doc)
|
||||||
# find emails relating to a company
|
# find emails relating to a company
|
||||||
@ -38,15 +39,6 @@ def is_current_hour(hour):
|
|||||||
return frappe.utils.nowtime().split(':')[0] == hour.split(':')[0]
|
return frappe.utils.nowtime().split(':')[0] == hour.split(':')[0]
|
||||||
|
|
||||||
|
|
||||||
def is_holiday_today(holiday_list):
|
|
||||||
date = frappe.utils.today()
|
|
||||||
if holiday_list:
|
|
||||||
return frappe.get_all('Holiday List',
|
|
||||||
dict(name=holiday_list, holiday_date=date)) and True or False
|
|
||||||
else:
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def send_summary():
|
def send_summary():
|
||||||
'''Send summary to everyone'''
|
'''Send summary to everyone'''
|
||||||
for d in frappe.get_all('Daily Work Summary', dict(status='Open')):
|
for d in frappe.get_all('Daily Work Summary', dict(status='Open')):
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
frappe.ui.form.on('Department', {
|
frappe.ui.form.on('Department', {
|
||||||
refresh: function(frm) {
|
refresh: function(frm) {
|
||||||
// read-only for root department
|
// read-only for root department
|
||||||
if(!frm.doc.parent_department) {
|
if(!frm.doc.parent_department && !frm.is_new()) {
|
||||||
frm.set_read_only();
|
frm.set_read_only();
|
||||||
frm.set_intro(__("This is a root department and cannot be edited."));
|
frm.set_intro(__("This is a root department and cannot be edited."));
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
@ -19,6 +20,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "department_name",
|
"fieldname": "department_name",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -52,6 +54,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "parent_department",
|
"fieldname": "parent_department",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -85,6 +88,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "company",
|
"fieldname": "company",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -118,6 +122,7 @@
|
|||||||
"bold": 1,
|
"bold": 1,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "is_group",
|
"fieldname": "is_group",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -150,6 +155,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "disabled",
|
"fieldname": "disabled",
|
||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -182,6 +188,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "section_break_4",
|
"fieldname": "section_break_4",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -214,6 +221,7 @@
|
|||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"description": "Days for which Holidays are blocked for this department.",
|
"description": "Days for which Holidays are blocked for this department.",
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "leave_block_list",
|
"fieldname": "leave_block_list",
|
||||||
"fieldtype": "Link",
|
"fieldtype": "Link",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -246,6 +254,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "leave_section",
|
"fieldname": "leave_section",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -279,6 +288,7 @@
|
|||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"description": "The first Leave Approver in the list will be set as the default Leave Approver.",
|
"description": "The first Leave Approver in the list will be set as the default Leave Approver.",
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "leave_approvers",
|
"fieldname": "leave_approvers",
|
||||||
"fieldtype": "Table",
|
"fieldtype": "Table",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -312,6 +322,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "expense_section",
|
"fieldname": "expense_section",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -345,6 +356,7 @@
|
|||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"description": "The first Expense Approver in the list will be set as the default Expense Approver.",
|
"description": "The first Expense Approver in the list will be set as the default Expense Approver.",
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "expense_approvers",
|
"fieldname": "expense_approvers",
|
||||||
"fieldtype": "Table",
|
"fieldtype": "Table",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
@ -378,6 +390,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "lft",
|
"fieldname": "lft",
|
||||||
"fieldtype": "Int",
|
"fieldtype": "Int",
|
||||||
"hidden": 1,
|
"hidden": 1,
|
||||||
@ -410,6 +423,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "rgt",
|
"fieldname": "rgt",
|
||||||
"fieldtype": "Int",
|
"fieldtype": "Int",
|
||||||
"hidden": 1,
|
"hidden": 1,
|
||||||
@ -442,6 +456,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
|
"fetch_if_empty": 0,
|
||||||
"fieldname": "old_parent",
|
"fieldname": "old_parent",
|
||||||
"fieldtype": "Data",
|
"fieldtype": "Data",
|
||||||
"hidden": 1,
|
"hidden": 1,
|
||||||
@ -479,7 +494,7 @@
|
|||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 0,
|
"istable": 0,
|
||||||
"max_attachments": 0,
|
"max_attachments": 0,
|
||||||
"modified": "2018-08-29 06:26:12.995703",
|
"modified": "2019-06-25 18:43:05.550387",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "HR",
|
"module": "HR",
|
||||||
"name": "Department",
|
"name": "Department",
|
||||||
@ -543,7 +558,7 @@
|
|||||||
"write": 1
|
"write": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"quick_entry": 1,
|
"quick_entry": 0,
|
||||||
"read_only": 0,
|
"read_only": 0,
|
||||||
"read_only_onload": 0,
|
"read_only_onload": 0,
|
||||||
"show_name_in_global_search": 1,
|
"show_name_in_global_search": 1,
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -319,12 +319,12 @@ def get_holiday_list_for_employee(employee, raise_exception=True):
|
|||||||
|
|
||||||
return holiday_list
|
return holiday_list
|
||||||
|
|
||||||
def is_holiday(employee, date=None):
|
def is_holiday(employee, date=None, raise_exception=True):
|
||||||
'''Returns True if given Employee has an holiday on the given date
|
'''Returns True if given Employee has an holiday on the given date
|
||||||
:param employee: Employee `name`
|
:param employee: Employee `name`
|
||||||
:param date: Date to check. Will check for today if None'''
|
:param date: Date to check. Will check for today if None'''
|
||||||
|
|
||||||
holiday_list = get_holiday_list_for_employee(employee)
|
holiday_list = get_holiday_list_for_employee(employee, raise_exception)
|
||||||
if not date:
|
if not date:
|
||||||
date = today()
|
date = today()
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ def get_data():
|
|||||||
'transactions': [
|
'transactions': [
|
||||||
{
|
{
|
||||||
'label': _('Leave and Attendance'),
|
'label': _('Leave and Attendance'),
|
||||||
'items': ['Attendance', 'Attendance Request', 'Leave Application', 'Leave Allocation']
|
'items': ['Attendance', 'Attendance Request', 'Leave Application', 'Leave Allocation', 'Employee Checkin']
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'label': _('Lifecycle'),
|
'label': _('Lifecycle'),
|
||||||
@ -40,4 +40,4 @@ def get_data():
|
|||||||
'items': ['Training Event', 'Training Result', 'Training Feedback', 'Employee Skill Map']
|
'items': ['Training Event', 'Training Result', 'Training Feedback', 'Employee Skill Map']
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -2,9 +2,8 @@ frappe.ui.form.on("Employee Attendance Tool", {
|
|||||||
refresh: function(frm) {
|
refresh: function(frm) {
|
||||||
frm.disable_save();
|
frm.disable_save();
|
||||||
},
|
},
|
||||||
|
|
||||||
onload: function(frm) {
|
onload: function(frm) {
|
||||||
frm.doc.department = frm.doc.branch = frm.doc.company = "All";
|
|
||||||
frm.set_value("date", frappe.datetime.get_today());
|
frm.set_value("date", frappe.datetime.get_today());
|
||||||
erpnext.employee_attendance_tool.load_employees(frm);
|
erpnext.employee_attendance_tool.load_employees(frm);
|
||||||
},
|
},
|
||||||
@ -24,7 +23,7 @@ frappe.ui.form.on("Employee Attendance Tool", {
|
|||||||
company: function(frm) {
|
company: function(frm) {
|
||||||
erpnext.employee_attendance_tool.load_employees(frm);
|
erpnext.employee_attendance_tool.load_employees(frm);
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
@ -17,12 +17,11 @@ def get_employees(date, department = None, branch = None, company = None):
|
|||||||
attendance_not_marked = []
|
attendance_not_marked = []
|
||||||
attendance_marked = []
|
attendance_marked = []
|
||||||
filters = {"status": "Active", "date_of_joining": ["<=", date]}
|
filters = {"status": "Active", "date_of_joining": ["<=", date]}
|
||||||
if department != "All":
|
|
||||||
filters["department"] = department
|
for field, value in {'department': department,
|
||||||
if branch != "All":
|
'branch': branch, 'company': company}.items():
|
||||||
filters["branch"] = branch
|
if value:
|
||||||
if company != "All":
|
filters[field] = value
|
||||||
filters["company"] = company
|
|
||||||
|
|
||||||
employee_list = frappe.get_list("Employee", fields=["employee", "employee_name"], filters=filters, order_by="employee_name")
|
employee_list = frappe.get_list("Employee", fields=["employee", "employee_name"], filters=filters, order_by="employee_name")
|
||||||
marked_employee = {}
|
marked_employee = {}
|
||||||
|
@ -2,20 +2,8 @@
|
|||||||
// For license information, please see license.txt
|
// For license information, please see license.txt
|
||||||
|
|
||||||
frappe.ui.form.on('Employee Benefit Application', {
|
frappe.ui.form.on('Employee Benefit Application', {
|
||||||
setup: function(frm) {
|
|
||||||
if(!frm.doc.employee || !frm.doc.date) {
|
|
||||||
frappe.throw(__("Please select Employee and Date first"));
|
|
||||||
} else {
|
|
||||||
frm.set_query("earning_component", "employee_benefits", function() {
|
|
||||||
return {
|
|
||||||
query : "erpnext.hr.doctype.employee_benefit_application.employee_benefit_application.get_earning_components",
|
|
||||||
filters: {date: frm.doc.date, employee: frm.doc.employee}
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
employee: function(frm) {
|
employee: function(frm) {
|
||||||
|
frm.trigger('set_earning_component');
|
||||||
var method, args;
|
var method, args;
|
||||||
if(frm.doc.employee && frm.doc.date && frm.doc.payroll_period){
|
if(frm.doc.employee && frm.doc.date && frm.doc.payroll_period){
|
||||||
method = "erpnext.hr.doctype.employee_benefit_application.employee_benefit_application.get_max_benefits_remaining";
|
method = "erpnext.hr.doctype.employee_benefit_application.employee_benefit_application.get_max_benefits_remaining";
|
||||||
@ -35,6 +23,21 @@ frappe.ui.form.on('Employee Benefit Application', {
|
|||||||
get_max_benefits(frm, method, args);
|
get_max_benefits(frm, method, args);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
date: function(frm) {
|
||||||
|
frm.trigger('set_earning_component');
|
||||||
|
},
|
||||||
|
|
||||||
|
set_earning_component: function(frm) {
|
||||||
|
if(!frm.doc.employee && !frm.doc.date) return;
|
||||||
|
frm.set_query("earning_component", "employee_benefits", function() {
|
||||||
|
return {
|
||||||
|
query : "erpnext.hr.doctype.employee_benefit_application.employee_benefit_application.get_earning_components",
|
||||||
|
filters: {date: frm.doc.date, employee: frm.doc.employee}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
payroll_period: function(frm) {
|
payroll_period: function(frm) {
|
||||||
var method, args;
|
var method, args;
|
||||||
if(frm.doc.employee && frm.doc.date && frm.doc.payroll_period){
|
if(frm.doc.employee && frm.doc.date && frm.doc.payroll_period){
|
||||||
|
0
erpnext/hr/doctype/employee_checkin/__init__.py
Normal file
0
erpnext/hr/doctype/employee_checkin/__init__.py
Normal file
8
erpnext/hr/doctype/employee_checkin/employee_checkin.js
Normal file
8
erpnext/hr/doctype/employee_checkin/employee_checkin.js
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
// Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors
|
||||||
|
// For license information, please see license.txt
|
||||||
|
|
||||||
|
frappe.ui.form.on('Employee Checkin', {
|
||||||
|
// refresh: function(frm) {
|
||||||
|
|
||||||
|
// }
|
||||||
|
});
|
171
erpnext/hr/doctype/employee_checkin/employee_checkin.json
Normal file
171
erpnext/hr/doctype/employee_checkin/employee_checkin.json
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
{
|
||||||
|
"allow_import": 1,
|
||||||
|
"autoname": "EMP-CKIN-.MM.-.YYYY.-.######",
|
||||||
|
"creation": "2019-06-10 11:56:34.536413",
|
||||||
|
"doctype": "DocType",
|
||||||
|
"engine": "InnoDB",
|
||||||
|
"field_order": [
|
||||||
|
"employee",
|
||||||
|
"employee_name",
|
||||||
|
"log_type",
|
||||||
|
"shift",
|
||||||
|
"column_break_4",
|
||||||
|
"time",
|
||||||
|
"device_id",
|
||||||
|
"skip_auto_attendance",
|
||||||
|
"attendance",
|
||||||
|
"entry_grace_period_consequence",
|
||||||
|
"exit_grace_period_consequence",
|
||||||
|
"shift_start",
|
||||||
|
"shift_end",
|
||||||
|
"shift_actual_start",
|
||||||
|
"shift_actual_end"
|
||||||
|
],
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldname": "employee",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Employee",
|
||||||
|
"options": "Employee",
|
||||||
|
"reqd": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fetch_from": "employee.employee_name",
|
||||||
|
"fieldname": "employee_name",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"label": "Employee Name",
|
||||||
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "log_type",
|
||||||
|
"fieldtype": "Select",
|
||||||
|
"label": "Log Type",
|
||||||
|
"options": "\nIN\nOUT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "shift",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"label": "Shift",
|
||||||
|
"options": "Shift Type",
|
||||||
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "column_break_4",
|
||||||
|
"fieldtype": "Column Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "Now",
|
||||||
|
"fieldname": "time",
|
||||||
|
"fieldtype": "Datetime",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Time",
|
||||||
|
"reqd": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "device_id",
|
||||||
|
"fieldtype": "Data",
|
||||||
|
"label": "Location / Device ID"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "0",
|
||||||
|
"fieldname": "skip_auto_attendance",
|
||||||
|
"fieldtype": "Check",
|
||||||
|
"label": "Skip Auto Attendance"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "attendance",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"label": "Attendance Marked",
|
||||||
|
"options": "Attendance",
|
||||||
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "0",
|
||||||
|
"fieldname": "entry_grace_period_consequence",
|
||||||
|
"fieldtype": "Check",
|
||||||
|
"hidden": 1,
|
||||||
|
"label": "Entry Grace Period Consequence"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "0",
|
||||||
|
"fieldname": "exit_grace_period_consequence",
|
||||||
|
"fieldtype": "Check",
|
||||||
|
"hidden": 1,
|
||||||
|
"label": "Exit Grace Period Consequence"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "shift_start",
|
||||||
|
"fieldtype": "Datetime",
|
||||||
|
"hidden": 1,
|
||||||
|
"label": "Shift Start"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "shift_end",
|
||||||
|
"fieldtype": "Datetime",
|
||||||
|
"hidden": 1,
|
||||||
|
"label": "Shift End"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "shift_actual_start",
|
||||||
|
"fieldtype": "Datetime",
|
||||||
|
"hidden": 1,
|
||||||
|
"label": "Shift Actual Start"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "shift_actual_end",
|
||||||
|
"fieldtype": "Datetime",
|
||||||
|
"hidden": 1,
|
||||||
|
"label": "Shift Actual End"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"modified": "2019-06-10 15:33:22.731697",
|
||||||
|
"modified_by": "Administrator",
|
||||||
|
"module": "HR",
|
||||||
|
"name": "Employee Checkin",
|
||||||
|
"owner": "Administrator",
|
||||||
|
"permissions": [
|
||||||
|
{
|
||||||
|
"create": 1,
|
||||||
|
"delete": 1,
|
||||||
|
"email": 1,
|
||||||
|
"export": 1,
|
||||||
|
"import": 1,
|
||||||
|
"print": 1,
|
||||||
|
"read": 1,
|
||||||
|
"report": 1,
|
||||||
|
"role": "System Manager",
|
||||||
|
"share": 1,
|
||||||
|
"write": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"create": 1,
|
||||||
|
"delete": 1,
|
||||||
|
"email": 1,
|
||||||
|
"export": 1,
|
||||||
|
"import": 1,
|
||||||
|
"print": 1,
|
||||||
|
"read": 1,
|
||||||
|
"report": 1,
|
||||||
|
"role": "HR Manager",
|
||||||
|
"share": 1,
|
||||||
|
"write": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"create": 1,
|
||||||
|
"delete": 1,
|
||||||
|
"email": 1,
|
||||||
|
"export": 1,
|
||||||
|
"import": 1,
|
||||||
|
"print": 1,
|
||||||
|
"read": 1,
|
||||||
|
"report": 1,
|
||||||
|
"role": "HR User",
|
||||||
|
"share": 1,
|
||||||
|
"write": 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"sort_field": "modified",
|
||||||
|
"sort_order": "ASC",
|
||||||
|
"track_changes": 1
|
||||||
|
}
|
161
erpnext/hr/doctype/employee_checkin/employee_checkin.py
Normal file
161
erpnext/hr/doctype/employee_checkin/employee_checkin.py
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors
|
||||||
|
# For license information, please see license.txt
|
||||||
|
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
import frappe
|
||||||
|
from frappe.utils import now, cint, get_datetime
|
||||||
|
from frappe.model.document import Document
|
||||||
|
from frappe import _
|
||||||
|
|
||||||
|
from erpnext.hr.doctype.shift_assignment.shift_assignment import get_actual_start_end_datetime_of_shift
|
||||||
|
|
||||||
|
class EmployeeCheckin(Document):
|
||||||
|
def validate(self):
|
||||||
|
self.validate_duplicate_log()
|
||||||
|
self.fetch_shift()
|
||||||
|
|
||||||
|
def validate_duplicate_log(self):
|
||||||
|
doc = frappe.db.exists('Employee Checkin', {
|
||||||
|
'employee': self.employee,
|
||||||
|
'time': self.time,
|
||||||
|
'name': ['!=', self.name]})
|
||||||
|
if doc:
|
||||||
|
doc_link = frappe.get_desk_link('Employee Checkin', doc)
|
||||||
|
frappe.throw(_('This employee already has a log with the same timestamp.{0}')
|
||||||
|
.format("<Br>" + doc_link))
|
||||||
|
|
||||||
|
def fetch_shift(self):
|
||||||
|
shift_actual_timings = get_actual_start_end_datetime_of_shift(self.employee, get_datetime(self.time), True)
|
||||||
|
if shift_actual_timings[0] and shift_actual_timings[1]:
|
||||||
|
if shift_actual_timings[2].shift_type.determine_check_in_and_check_out == 'Strictly based on Log Type in Employee Checkin' and not self.log_type and not self.skip_auto_attendance:
|
||||||
|
frappe.throw(_('Log Type is required for check-ins falling in the shift: {0}.').format(shift_actual_timings[2].shift_type.name))
|
||||||
|
if not self.attendance:
|
||||||
|
self.shift = shift_actual_timings[2].shift_type.name
|
||||||
|
self.shift_actual_start = shift_actual_timings[0]
|
||||||
|
self.shift_actual_end = shift_actual_timings[1]
|
||||||
|
self.shift_start = shift_actual_timings[2].start_datetime
|
||||||
|
self.shift_end = shift_actual_timings[2].end_datetime
|
||||||
|
else:
|
||||||
|
self.shift = None
|
||||||
|
|
||||||
|
@frappe.whitelist()
|
||||||
|
def add_log_based_on_employee_field(employee_field_value, timestamp, device_id=None, log_type=None, skip_auto_attendance=0, employee_fieldname='attendance_device_id'):
|
||||||
|
"""Finds the relevant Employee using the employee field value and creates a Employee Checkin.
|
||||||
|
|
||||||
|
:param employee_field_value: The value to look for in employee field.
|
||||||
|
:param timestamp: The timestamp of the Log. Currently expected in the following format as string: '2019-05-08 10:48:08.000000'
|
||||||
|
:param device_id: (optional)Location / Device ID. A short string is expected.
|
||||||
|
:param log_type: (optional)Direction of the Punch if available (IN/OUT).
|
||||||
|
:param skip_auto_attendance: (optional)Skip auto attendance field will be set for this log(0/1).
|
||||||
|
:param employee_fieldname: (Default: attendance_device_id)Name of the field in Employee DocType based on which employee lookup will happen.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if not employee_field_value or not timestamp:
|
||||||
|
frappe.throw(_("'employee_field_value' and 'timestamp' are required."))
|
||||||
|
|
||||||
|
employee = frappe.db.get_values("Employee", {employee_fieldname: employee_field_value}, ["name", "employee_name", employee_fieldname], as_dict=True)
|
||||||
|
if employee:
|
||||||
|
employee = employee[0]
|
||||||
|
else:
|
||||||
|
frappe.throw(_("No Employee found for the given employee field value. '{}': {}").format(employee_fieldname,employee_field_value))
|
||||||
|
|
||||||
|
doc = frappe.new_doc("Employee Checkin")
|
||||||
|
doc.employee = employee.name
|
||||||
|
doc.employee_name = employee.employee_name
|
||||||
|
doc.time = timestamp
|
||||||
|
doc.device_id = device_id
|
||||||
|
doc.log_type = log_type
|
||||||
|
if cint(skip_auto_attendance) == 1: doc.skip_auto_attendance = '1'
|
||||||
|
doc.insert()
|
||||||
|
|
||||||
|
return doc
|
||||||
|
|
||||||
|
|
||||||
|
def mark_attendance_and_link_log(logs, attendance_status, attendance_date, working_hours=None, shift=None):
|
||||||
|
"""Creates an attendance and links the attendance to the Employee Checkin.
|
||||||
|
Note: If attendance is already present for the given date, the logs are marked as skipped and no exception is thrown.
|
||||||
|
|
||||||
|
:param logs: The List of 'Employee Checkin'.
|
||||||
|
:param attendance_status: Attendance status to be marked. One of: (Present, Absent, Half Day, Skip). Note: 'On Leave' is not supported by this function.
|
||||||
|
:param attendance_date: Date of the attendance to be created.
|
||||||
|
:param working_hours: (optional)Number of working hours for the given date.
|
||||||
|
"""
|
||||||
|
log_names = [x.name for x in logs]
|
||||||
|
employee = logs[0].employee
|
||||||
|
if attendance_status == 'Skip':
|
||||||
|
frappe.db.sql("""update `tabEmployee Checkin`
|
||||||
|
set skip_auto_attendance = %s
|
||||||
|
where name in %s""", ('1', log_names))
|
||||||
|
return None
|
||||||
|
elif attendance_status in ('Present', 'Absent', 'Half Day'):
|
||||||
|
employee_doc = frappe.get_doc('Employee', employee)
|
||||||
|
if not frappe.db.exists('Attendance', {'employee':employee, 'attendance_date':attendance_date, 'docstatus':('!=', '2')}):
|
||||||
|
doc_dict = {
|
||||||
|
'doctype': 'Attendance',
|
||||||
|
'employee': employee,
|
||||||
|
'attendance_date': attendance_date,
|
||||||
|
'status': attendance_status,
|
||||||
|
'working_hours': working_hours,
|
||||||
|
'company': employee_doc.company,
|
||||||
|
'shift': shift
|
||||||
|
}
|
||||||
|
attendance = frappe.get_doc(doc_dict).insert()
|
||||||
|
attendance.submit()
|
||||||
|
frappe.db.sql("""update `tabEmployee Checkin`
|
||||||
|
set attendance = %s
|
||||||
|
where name in %s""", (attendance.name, log_names))
|
||||||
|
return attendance
|
||||||
|
else:
|
||||||
|
frappe.db.sql("""update `tabEmployee Checkin`
|
||||||
|
set skip_auto_attendance = %s
|
||||||
|
where name in %s""", ('1', log_names))
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
frappe.throw(_('{} is an invalid Attendance Status.').format(attendance_status))
|
||||||
|
|
||||||
|
|
||||||
|
def calculate_working_hours(logs, check_in_out_type, working_hours_calc_type):
|
||||||
|
"""Given a set of logs in chronological order calculates the total working hours based on the parameters.
|
||||||
|
Zero is returned for all invalid cases.
|
||||||
|
|
||||||
|
:param logs: The List of 'Employee Checkin'.
|
||||||
|
:param check_in_out_type: One of: 'Alternating entries as IN and OUT during the same shift', 'Strictly based on Log Type in Employee Checkin'
|
||||||
|
:param working_hours_calc_type: One of: 'First Check-in and Last Check-out', 'Every Valid Check-in and Check-out'
|
||||||
|
"""
|
||||||
|
total_hours = 0
|
||||||
|
if check_in_out_type == 'Alternating entries as IN and OUT during the same shift':
|
||||||
|
if working_hours_calc_type == 'First Check-in and Last Check-out':
|
||||||
|
# assumption in this case: First log always taken as IN, Last log always taken as OUT
|
||||||
|
total_hours = time_diff_in_hours(logs[0].time, logs[-1].time)
|
||||||
|
elif working_hours_calc_type == 'Every Valid Check-in and Check-out':
|
||||||
|
while len(logs) >= 2:
|
||||||
|
total_hours += time_diff_in_hours(logs[0].time, logs[1].time)
|
||||||
|
del logs[:2]
|
||||||
|
|
||||||
|
elif check_in_out_type == 'Strictly based on Log Type in Employee Checkin':
|
||||||
|
if working_hours_calc_type == 'First Check-in and Last Check-out':
|
||||||
|
first_in_log = logs[find_index_in_dict(logs, 'log_type', 'IN')]
|
||||||
|
last_out_log = logs[len(logs)-1-find_index_in_dict(reversed(logs), 'log_type', 'OUT')]
|
||||||
|
if first_in_log and last_out_log:
|
||||||
|
total_hours = time_diff_in_hours(first_in_log.time, last_out_log.time)
|
||||||
|
elif working_hours_calc_type == 'Every Valid Check-in and Check-out':
|
||||||
|
in_log = out_log = None
|
||||||
|
for log in logs:
|
||||||
|
if in_log and out_log:
|
||||||
|
total_hours += time_diff_in_hours(in_log.time, out_log.time)
|
||||||
|
in_log = out_log = None
|
||||||
|
if not in_log:
|
||||||
|
in_log = log if log.log_type == 'IN' else None
|
||||||
|
elif not out_log:
|
||||||
|
out_log = log if log.log_type == 'OUT' else None
|
||||||
|
if in_log and out_log:
|
||||||
|
total_hours += time_diff_in_hours(in_log.time, out_log.time)
|
||||||
|
return total_hours
|
||||||
|
|
||||||
|
def time_diff_in_hours(start, end):
|
||||||
|
return round((end-start).total_seconds() / 3600, 1)
|
||||||
|
|
||||||
|
def find_index_in_dict(dict_list, key, value):
|
||||||
|
return next((index for (index, d) in enumerate(dict_list) if d[key] == value), None)
|
||||||
|
|
99
erpnext/hr/doctype/employee_checkin/test_employee_checkin.py
Normal file
99
erpnext/hr/doctype/employee_checkin/test_employee_checkin.py
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and Contributors
|
||||||
|
# See license.txt
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import frappe
|
||||||
|
from frappe.utils import now_datetime, nowdate, to_timedelta
|
||||||
|
import unittest
|
||||||
|
from datetime import timedelta
|
||||||
|
|
||||||
|
from erpnext.hr.doctype.employee_checkin.employee_checkin import add_log_based_on_employee_field, mark_attendance_and_link_log, calculate_working_hours
|
||||||
|
from erpnext.hr.doctype.employee.test_employee import make_employee
|
||||||
|
|
||||||
|
class TestEmployeeCheckin(unittest.TestCase):
|
||||||
|
def test_add_log_based_on_employee_field(self):
|
||||||
|
employee = make_employee("test_add_log_based_on_employee_field@example.com")
|
||||||
|
employee = frappe.get_doc("Employee", employee)
|
||||||
|
employee.attendance_device_id = '3344'
|
||||||
|
employee.save()
|
||||||
|
|
||||||
|
time_now = now_datetime().__str__()[:-7]
|
||||||
|
employee_checkin = add_log_based_on_employee_field('3344', time_now, 'mumbai_first_floor', 'IN')
|
||||||
|
self.assertEqual(employee_checkin.employee, employee.name)
|
||||||
|
self.assertEqual(employee_checkin.time, time_now)
|
||||||
|
self.assertEqual(employee_checkin.device_id, 'mumbai_first_floor')
|
||||||
|
self.assertEqual(employee_checkin.log_type, 'IN')
|
||||||
|
|
||||||
|
def test_mark_attendance_and_link_log(self):
|
||||||
|
employee = make_employee("test_mark_attendance_and_link_log@example.com")
|
||||||
|
logs = make_n_checkins(employee, 3)
|
||||||
|
mark_attendance_and_link_log(logs, 'Skip', nowdate())
|
||||||
|
log_names = [log.name for log in logs]
|
||||||
|
logs_count = frappe.db.count('Employee Checkin', {'name':['in', log_names], 'skip_auto_attendance':1})
|
||||||
|
self.assertEqual(logs_count, 3)
|
||||||
|
|
||||||
|
logs = make_n_checkins(employee, 4, 2)
|
||||||
|
now_date = nowdate()
|
||||||
|
frappe.db.delete('Attendance', {'employee':employee})
|
||||||
|
attendance = mark_attendance_and_link_log(logs, 'Present', now_date, 8.2)
|
||||||
|
log_names = [log.name for log in logs]
|
||||||
|
logs_count = frappe.db.count('Employee Checkin', {'name':['in', log_names], 'attendance':attendance.name})
|
||||||
|
self.assertEqual(logs_count, 4)
|
||||||
|
attendance_count = frappe.db.count('Attendance', {'status':'Present', 'working_hours':8.2,
|
||||||
|
'employee':employee, 'attendance_date':now_date})
|
||||||
|
self.assertEqual(attendance_count, 1)
|
||||||
|
|
||||||
|
def test_calculate_working_hours(self):
|
||||||
|
check_in_out_type = ['Alternating entries as IN and OUT during the same shift',
|
||||||
|
'Strictly based on Log Type in Employee Checkin']
|
||||||
|
working_hours_calc_type = ['First Check-in and Last Check-out',
|
||||||
|
'Every Valid Check-in and Check-out']
|
||||||
|
logs_type_1 = [
|
||||||
|
{'time':now_datetime()-timedelta(minutes=390)},
|
||||||
|
{'time':now_datetime()-timedelta(minutes=300)},
|
||||||
|
{'time':now_datetime()-timedelta(minutes=270)},
|
||||||
|
{'time':now_datetime()-timedelta(minutes=90)},
|
||||||
|
{'time':now_datetime()-timedelta(minutes=0)}
|
||||||
|
]
|
||||||
|
logs_type_2 = [
|
||||||
|
{'time':now_datetime()-timedelta(minutes=390),'log_type':'OUT'},
|
||||||
|
{'time':now_datetime()-timedelta(minutes=360),'log_type':'IN'},
|
||||||
|
{'time':now_datetime()-timedelta(minutes=300),'log_type':'OUT'},
|
||||||
|
{'time':now_datetime()-timedelta(minutes=290),'log_type':'IN'},
|
||||||
|
{'time':now_datetime()-timedelta(minutes=260),'log_type':'OUT'},
|
||||||
|
{'time':now_datetime()-timedelta(minutes=240),'log_type':'IN'},
|
||||||
|
{'time':now_datetime()-timedelta(minutes=150),'log_type':'IN'},
|
||||||
|
{'time':now_datetime()-timedelta(minutes=60),'log_type':'OUT'}
|
||||||
|
]
|
||||||
|
logs_type_1 = [frappe._dict(x) for x in logs_type_1]
|
||||||
|
logs_type_2 = [frappe._dict(x) for x in logs_type_2]
|
||||||
|
|
||||||
|
working_hours = calculate_working_hours(logs_type_1,check_in_out_type[0],working_hours_calc_type[0])
|
||||||
|
self.assertEqual(working_hours, 6.5)
|
||||||
|
|
||||||
|
working_hours = calculate_working_hours(logs_type_1,check_in_out_type[0],working_hours_calc_type[1])
|
||||||
|
self.assertEqual(working_hours, 4.5)
|
||||||
|
|
||||||
|
working_hours = calculate_working_hours(logs_type_2,check_in_out_type[1],working_hours_calc_type[0])
|
||||||
|
self.assertEqual(working_hours, 5)
|
||||||
|
|
||||||
|
working_hours = calculate_working_hours(logs_type_2,check_in_out_type[1],working_hours_calc_type[1])
|
||||||
|
self.assertEqual(working_hours, 4.5)
|
||||||
|
|
||||||
|
def make_n_checkins(employee, n, hours_to_reverse=1):
|
||||||
|
logs = [make_checkin(employee, now_datetime() - timedelta(hours=hours_to_reverse, minutes=n+1))]
|
||||||
|
for i in range(n-1):
|
||||||
|
logs.append(make_checkin(employee, now_datetime() - timedelta(hours=hours_to_reverse, minutes=n-i)))
|
||||||
|
return logs
|
||||||
|
|
||||||
|
|
||||||
|
def make_checkin(employee, time=now_datetime()):
|
||||||
|
log = frappe.get_doc({
|
||||||
|
"doctype": "Employee Checkin",
|
||||||
|
"employee" : employee,
|
||||||
|
"time" : time,
|
||||||
|
"device_id" : "device1",
|
||||||
|
"log_type" : "IN"
|
||||||
|
}).insert()
|
||||||
|
return log
|
@ -109,12 +109,9 @@ cur_frm.cscript.calculate_total = function(doc){
|
|||||||
doc.total_claimed_amount = 0;
|
doc.total_claimed_amount = 0;
|
||||||
doc.total_sanctioned_amount = 0;
|
doc.total_sanctioned_amount = 0;
|
||||||
$.each((doc.expenses || []), function(i, d) {
|
$.each((doc.expenses || []), function(i, d) {
|
||||||
doc.total_claimed_amount += d.claim_amount;
|
doc.total_claimed_amount += d.amount;
|
||||||
doc.total_sanctioned_amount += d.sanctioned_amount;
|
doc.total_sanctioned_amount += d.sanctioned_amount;
|
||||||
});
|
});
|
||||||
|
|
||||||
refresh_field("total_claimed_amount");
|
|
||||||
refresh_field('total_sanctioned_amount');
|
|
||||||
};
|
};
|
||||||
|
|
||||||
cur_frm.cscript.calculate_total_amount = function(doc,cdt,cdn){
|
cur_frm.cscript.calculate_total_amount = function(doc,cdt,cdn){
|
||||||
@ -157,6 +154,14 @@ frappe.ui.form.on("Expense Claim", {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
frm.set_query("account_head", "taxes", function(doc) {
|
||||||
|
return {
|
||||||
|
filters: [
|
||||||
|
['company', '=', doc.company],
|
||||||
|
['account_type', 'in', ["Tax", "Chargeable", "Income Account", "Expenses Included In Valuation"]]
|
||||||
|
]
|
||||||
|
};
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
onload: function(frm) {
|
onload: function(frm) {
|
||||||
@ -197,6 +202,12 @@ frappe.ui.form.on("Expense Claim", {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
calculate_grand_total: function(frm) {
|
||||||
|
var grand_total = flt(frm.doc.total_sanctioned_amount) + flt(frm.doc.total_taxes_and_charges) - flt(frm.doc.total_advance_amount);
|
||||||
|
frm.set_value("grand_total", grand_total);
|
||||||
|
frm.refresh_fields();
|
||||||
|
},
|
||||||
|
|
||||||
make_payment_entry: function(frm) {
|
make_payment_entry: function(frm) {
|
||||||
var method = "erpnext.accounts.doctype.payment_entry.payment_entry.get_payment_entry";
|
var method = "erpnext.accounts.doctype.payment_entry.payment_entry.get_payment_entry";
|
||||||
if(frm.doc.__onload && frm.doc.__onload.make_payment_via_journal_entry) {
|
if(frm.doc.__onload && frm.doc.__onload.make_payment_via_journal_entry) {
|
||||||
@ -259,6 +270,18 @@ frappe.ui.form.on("Expense Claim", {
|
|||||||
frm.events.get_advances(frm);
|
frm.events.get_advances(frm);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
get_taxes: function(frm) {
|
||||||
|
if(frm.doc.taxes) {
|
||||||
|
frappe.call({
|
||||||
|
method: "calculate_taxes",
|
||||||
|
doc: frm.doc,
|
||||||
|
callback: () => {
|
||||||
|
refresh_field("taxes");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
get_advances: function(frm) {
|
get_advances: function(frm) {
|
||||||
frappe.model.clear_table(frm.doc, "advances");
|
frappe.model.clear_table(frm.doc, "advances");
|
||||||
if (frm.doc.employee) {
|
if (frm.doc.employee) {
|
||||||
@ -288,16 +311,18 @@ frappe.ui.form.on("Expense Claim", {
|
|||||||
});
|
});
|
||||||
|
|
||||||
frappe.ui.form.on("Expense Claim Detail", {
|
frappe.ui.form.on("Expense Claim Detail", {
|
||||||
claim_amount: function(frm, cdt, cdn) {
|
amount: function(frm, cdt, cdn) {
|
||||||
var child = locals[cdt][cdn];
|
var child = locals[cdt][cdn];
|
||||||
var doc = frm.doc;
|
var doc = frm.doc;
|
||||||
frappe.model.set_value(cdt, cdn, 'sanctioned_amount', child.claim_amount);
|
frappe.model.set_value(cdt, cdn, 'sanctioned_amount', child.amount);
|
||||||
cur_frm.cscript.calculate_total(doc,cdt,cdn);
|
cur_frm.cscript.calculate_total(doc,cdt,cdn);
|
||||||
},
|
},
|
||||||
|
|
||||||
sanctioned_amount: function(frm, cdt, cdn) {
|
sanctioned_amount: function(frm, cdt, cdn) {
|
||||||
var doc = frm.doc;
|
var doc = frm.doc;
|
||||||
cur_frm.cscript.calculate_total(doc,cdt,cdn);
|
cur_frm.cscript.calculate_total(doc,cdt,cdn);
|
||||||
|
frm.trigger("get_taxes");
|
||||||
|
frm.trigger("calculate_grand_total");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -324,6 +349,7 @@ frappe.ui.form.on("Expense Claim Advance", {
|
|||||||
child.advance_paid = r.message[0].paid_amount;
|
child.advance_paid = r.message[0].paid_amount;
|
||||||
child.unclaimed_amount = flt(r.message[0].paid_amount) - flt(r.message[0].claimed_amount);
|
child.unclaimed_amount = flt(r.message[0].paid_amount) - flt(r.message[0].claimed_amount);
|
||||||
child.allocated_amount = flt(r.message[0].paid_amount) - flt(r.message[0].claimed_amount);
|
child.allocated_amount = flt(r.message[0].paid_amount) - flt(r.message[0].claimed_amount);
|
||||||
|
frm.trigger('calculate_grand_total');
|
||||||
refresh_field("advances");
|
refresh_field("advances");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -332,6 +358,43 @@ frappe.ui.form.on("Expense Claim Advance", {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
frappe.ui.form.on("Expense Taxes and Charges", {
|
||||||
|
account_head: function(frm, cdt, cdn) {
|
||||||
|
var child = locals[cdt][cdn];
|
||||||
|
if(child.account_head && !child.description) {
|
||||||
|
// set description from account head
|
||||||
|
child.description = child.account_head.split(' - ').slice(0, -1).join(' - ');
|
||||||
|
refresh_field("taxes");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
calculate_total_tax: function(frm, cdt, cdn) {
|
||||||
|
var child = locals[cdt][cdn];
|
||||||
|
child.total = flt(frm.doc.total_sanctioned_amount) + flt(child.tax_amount);
|
||||||
|
frm.trigger("calculate_tax_amount", cdt, cdn);
|
||||||
|
},
|
||||||
|
|
||||||
|
calculate_tax_amount: function(frm) {
|
||||||
|
frm.doc.total_taxes_and_charges = 0;
|
||||||
|
(frm.doc.taxes || []).forEach(function(d) {
|
||||||
|
frm.doc.total_taxes_and_charges += d.tax_amount;
|
||||||
|
});
|
||||||
|
frm.trigger("calculate_grand_total");
|
||||||
|
},
|
||||||
|
|
||||||
|
rate: function(frm, cdt, cdn) {
|
||||||
|
var child = locals[cdt][cdn];
|
||||||
|
if(!child.amount) {
|
||||||
|
child.tax_amount = flt(frm.doc.total_sanctioned_amount) * (flt(child.rate)/100);
|
||||||
|
}
|
||||||
|
frm.trigger("calculate_total_tax", cdt, cdn);
|
||||||
|
},
|
||||||
|
|
||||||
|
tax_amount: function(frm, cdt, cdn) {
|
||||||
|
frm.trigger("calculate_total_tax", cdt, cdn);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
cur_frm.fields_dict['task'].get_query = function(doc) {
|
cur_frm.fields_dict['task'].get_query = function(doc) {
|
||||||
return {
|
return {
|
||||||
filters:{
|
filters:{
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
"creation": "2013-01-10 16:34:14",
|
"creation": "2013-01-10 16:34:14",
|
||||||
"doctype": "DocType",
|
"doctype": "DocType",
|
||||||
"document_type": "Setup",
|
"document_type": "Setup",
|
||||||
|
"engine": "InnoDB",
|
||||||
"field_order": [
|
"field_order": [
|
||||||
"naming_series",
|
"naming_series",
|
||||||
"employee",
|
"employee",
|
||||||
@ -12,17 +13,24 @@
|
|||||||
"column_break_5",
|
"column_break_5",
|
||||||
"expense_approver",
|
"expense_approver",
|
||||||
"approval_status",
|
"approval_status",
|
||||||
"total_claimed_amount",
|
|
||||||
"total_sanctioned_amount",
|
|
||||||
"is_paid",
|
"is_paid",
|
||||||
"expense_details",
|
"expense_details",
|
||||||
"expenses",
|
"expenses",
|
||||||
"sb1",
|
"sb1",
|
||||||
|
"taxes",
|
||||||
|
"transactions_section",
|
||||||
|
"total_sanctioned_amount",
|
||||||
|
"total_taxes_and_charges",
|
||||||
|
"total_advance_amount",
|
||||||
|
"column_break_17",
|
||||||
|
"grand_total",
|
||||||
|
"total_claimed_amount",
|
||||||
|
"total_amount_reimbursed",
|
||||||
|
"section_break_16",
|
||||||
"posting_date",
|
"posting_date",
|
||||||
"vehicle_log",
|
"vehicle_log",
|
||||||
"task",
|
"task",
|
||||||
"cb1",
|
"cb1",
|
||||||
"total_amount_reimbursed",
|
|
||||||
"remark",
|
"remark",
|
||||||
"title",
|
"title",
|
||||||
"email_id",
|
"email_id",
|
||||||
@ -39,8 +47,7 @@
|
|||||||
"status",
|
"status",
|
||||||
"amended_from",
|
"amended_from",
|
||||||
"advance_payments",
|
"advance_payments",
|
||||||
"advances",
|
"advances"
|
||||||
"total_advance_amount"
|
|
||||||
],
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
@ -117,7 +124,6 @@
|
|||||||
{
|
{
|
||||||
"fieldname": "total_sanctioned_amount",
|
"fieldname": "total_sanctioned_amount",
|
||||||
"fieldtype": "Currency",
|
"fieldtype": "Currency",
|
||||||
"in_list_view": 1,
|
|
||||||
"label": "Total Sanctioned Amount",
|
"label": "Total Sanctioned Amount",
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"oldfieldname": "total_sanctioned_amount",
|
"oldfieldname": "total_sanctioned_amount",
|
||||||
@ -315,12 +321,45 @@
|
|||||||
{
|
{
|
||||||
"fieldname": "dimension_col_break",
|
"fieldname": "dimension_col_break",
|
||||||
"fieldtype": "Column Break"
|
"fieldtype": "Column Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "taxes",
|
||||||
|
"fieldtype": "Table",
|
||||||
|
"label": "Expense Taxes and Charges",
|
||||||
|
"options": "Expense Taxes and Charges"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "section_break_16",
|
||||||
|
"fieldtype": "Section Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "transactions_section",
|
||||||
|
"fieldtype": "Section Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "grand_total",
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Grand Total",
|
||||||
|
"options": "Company:company:default_currency",
|
||||||
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "column_break_17",
|
||||||
|
"fieldtype": "Column Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "total_taxes_and_charges",
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"label": "Total Taxes and Charges",
|
||||||
|
"options": "Company:company:default_currency",
|
||||||
|
"read_only": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"icon": "fa fa-money",
|
"icon": "fa fa-money",
|
||||||
"idx": 1,
|
"idx": 1,
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
"modified": "2019-05-25 22:53:31.682151",
|
"modified": "2019-06-13 18:05:52.530462",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "HR",
|
"module": "HR",
|
||||||
"name": "Expense Claim",
|
"name": "Expense Claim",
|
||||||
|
@ -12,6 +12,7 @@ from erpnext.accounts.general_ledger import make_gl_entries
|
|||||||
from erpnext.accounts.doctype.sales_invoice.sales_invoice import get_bank_cash_account
|
from erpnext.accounts.doctype.sales_invoice.sales_invoice import get_bank_cash_account
|
||||||
from erpnext.controllers.accounts_controller import AccountsController
|
from erpnext.controllers.accounts_controller import AccountsController
|
||||||
from frappe.utils.csvutils import getlink
|
from frappe.utils.csvutils import getlink
|
||||||
|
from erpnext.accounts.utils import get_account_currency
|
||||||
|
|
||||||
class InvalidExpenseApproverError(frappe.ValidationError): pass
|
class InvalidExpenseApproverError(frappe.ValidationError): pass
|
||||||
class ExpenseApproverIdentityError(frappe.ValidationError): pass
|
class ExpenseApproverIdentityError(frappe.ValidationError): pass
|
||||||
@ -29,6 +30,7 @@ class ExpenseClaim(AccountsController):
|
|||||||
self.set_expense_account(validate=True)
|
self.set_expense_account(validate=True)
|
||||||
self.set_payable_account()
|
self.set_payable_account()
|
||||||
self.set_cost_center()
|
self.set_cost_center()
|
||||||
|
self.calculate_taxes()
|
||||||
self.set_status()
|
self.set_status()
|
||||||
if self.task and not self.project:
|
if self.task and not self.project:
|
||||||
self.project = frappe.db.get_value("Task", self.task, "project")
|
self.project = frappe.db.get_value("Task", self.task, "project")
|
||||||
@ -93,7 +95,7 @@ class ExpenseClaim(AccountsController):
|
|||||||
elif self.project:
|
elif self.project:
|
||||||
frappe.get_doc("Project", self.project).update_project()
|
frappe.get_doc("Project", self.project).update_project()
|
||||||
|
|
||||||
def make_gl_entries(self, cancel = False):
|
def make_gl_entries(self, cancel=False):
|
||||||
if flt(self.total_sanctioned_amount) > 0:
|
if flt(self.total_sanctioned_amount) > 0:
|
||||||
gl_entries = self.get_gl_entries()
|
gl_entries = self.get_gl_entries()
|
||||||
make_gl_entries(gl_entries, cancel)
|
make_gl_entries(gl_entries, cancel)
|
||||||
@ -102,15 +104,13 @@ class ExpenseClaim(AccountsController):
|
|||||||
gl_entry = []
|
gl_entry = []
|
||||||
self.validate_account_details()
|
self.validate_account_details()
|
||||||
|
|
||||||
payable_amount = flt(self.total_sanctioned_amount) - flt(self.total_advance_amount)
|
|
||||||
|
|
||||||
# payable entry
|
# payable entry
|
||||||
if payable_amount:
|
if self.grand_total:
|
||||||
gl_entry.append(
|
gl_entry.append(
|
||||||
self.get_gl_dict({
|
self.get_gl_dict({
|
||||||
"account": self.payable_account,
|
"account": self.payable_account,
|
||||||
"credit": payable_amount,
|
"credit": self.grand_total,
|
||||||
"credit_in_account_currency": payable_amount,
|
"credit_in_account_currency": self.grand_total,
|
||||||
"against": ",".join([d.default_account for d in self.expenses]),
|
"against": ",".join([d.default_account for d in self.expenses]),
|
||||||
"party_type": "Employee",
|
"party_type": "Employee",
|
||||||
"party": self.employee,
|
"party": self.employee,
|
||||||
@ -144,15 +144,16 @@ class ExpenseClaim(AccountsController):
|
|||||||
"against_voucher": self.name
|
"against_voucher": self.name
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
self.add_tax_gl_entries(gl_entry)
|
||||||
|
|
||||||
if self.is_paid and payable_amount:
|
if self.is_paid and self.grand_total:
|
||||||
# payment entry
|
# payment entry
|
||||||
payment_account = get_bank_cash_account(self.mode_of_payment, self.company).get("account")
|
payment_account = get_bank_cash_account(self.mode_of_payment, self.company).get("account")
|
||||||
gl_entry.append(
|
gl_entry.append(
|
||||||
self.get_gl_dict({
|
self.get_gl_dict({
|
||||||
"account": payment_account,
|
"account": payment_account,
|
||||||
"credit": payable_amount,
|
"credit": self.grand_total,
|
||||||
"credit_in_account_currency": payable_amount,
|
"credit_in_account_currency": self.grand_total,
|
||||||
"against": self.employee
|
"against": self.employee
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
@ -163,8 +164,8 @@ class ExpenseClaim(AccountsController):
|
|||||||
"party_type": "Employee",
|
"party_type": "Employee",
|
||||||
"party": self.employee,
|
"party": self.employee,
|
||||||
"against": payment_account,
|
"against": payment_account,
|
||||||
"debit": payable_amount,
|
"debit": self.grand_total,
|
||||||
"debit_in_account_currency": payable_amount,
|
"debit_in_account_currency": self.grand_total,
|
||||||
"against_voucher": self.name,
|
"against_voucher": self.name,
|
||||||
"against_voucher_type": self.doctype,
|
"against_voucher_type": self.doctype,
|
||||||
})
|
})
|
||||||
@ -172,6 +173,21 @@ class ExpenseClaim(AccountsController):
|
|||||||
|
|
||||||
return gl_entry
|
return gl_entry
|
||||||
|
|
||||||
|
def add_tax_gl_entries(self, gl_entries):
|
||||||
|
# tax table gl entries
|
||||||
|
for tax in self.get("taxes"):
|
||||||
|
gl_entries.append(
|
||||||
|
self.get_gl_dict({
|
||||||
|
"account": tax.account_head,
|
||||||
|
"debit": tax.tax_amount,
|
||||||
|
"debit_in_account_currency": tax.tax_amount,
|
||||||
|
"against": self.employee,
|
||||||
|
"cost_center": self.cost_center,
|
||||||
|
"against_voucher_type": self.doctype,
|
||||||
|
"against_voucher": self.name
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
def validate_account_details(self):
|
def validate_account_details(self):
|
||||||
if not self.cost_center:
|
if not self.cost_center:
|
||||||
frappe.throw(_("Cost center is required to book an expense claim"))
|
frappe.throw(_("Cost center is required to book an expense claim"))
|
||||||
@ -190,9 +206,20 @@ class ExpenseClaim(AccountsController):
|
|||||||
if self.approval_status == 'Rejected':
|
if self.approval_status == 'Rejected':
|
||||||
d.sanctioned_amount = 0.0
|
d.sanctioned_amount = 0.0
|
||||||
|
|
||||||
self.total_claimed_amount += flt(d.claim_amount)
|
self.total_claimed_amount += flt(d.amount)
|
||||||
self.total_sanctioned_amount += flt(d.sanctioned_amount)
|
self.total_sanctioned_amount += flt(d.sanctioned_amount)
|
||||||
|
|
||||||
|
def calculate_taxes(self):
|
||||||
|
self.total_taxes_and_charges = 0
|
||||||
|
for tax in self.taxes:
|
||||||
|
if tax.rate:
|
||||||
|
tax.tax_amount = flt(self.total_sanctioned_amount) * flt(tax.rate/100)
|
||||||
|
|
||||||
|
tax.total = flt(tax.tax_amount) + flt(self.total_sanctioned_amount)
|
||||||
|
self.total_taxes_and_charges += flt(tax.tax_amount)
|
||||||
|
|
||||||
|
self.grand_total = flt(self.total_sanctioned_amount) + flt(self.total_taxes_and_charges) - flt(self.total_advance_amount)
|
||||||
|
|
||||||
def update_task(self):
|
def update_task(self):
|
||||||
task = frappe.get_doc("Task", self.task)
|
task = frappe.get_doc("Task", self.task)
|
||||||
task.update_total_expense_claim()
|
task.update_total_expense_claim()
|
||||||
@ -224,7 +251,7 @@ class ExpenseClaim(AccountsController):
|
|||||||
|
|
||||||
def validate_sanctioned_amount(self):
|
def validate_sanctioned_amount(self):
|
||||||
for d in self.get('expenses'):
|
for d in self.get('expenses'):
|
||||||
if flt(d.sanctioned_amount) > flt(d.claim_amount):
|
if flt(d.sanctioned_amount) > flt(d.amount):
|
||||||
frappe.throw(_("Sanctioned Amount cannot be greater than Claim Amount in Row {0}.").format(d.idx))
|
frappe.throw(_("Sanctioned Amount cannot be greater than Claim Amount in Row {0}.").format(d.idx))
|
||||||
|
|
||||||
def set_expense_account(self, validate=False):
|
def set_expense_account(self, validate=False):
|
||||||
|
@ -17,7 +17,7 @@ QUnit.test("Test: Expense Claim [HR]", function (assert) {
|
|||||||
d.expense_date = '2017-08-01',
|
d.expense_date = '2017-08-01',
|
||||||
d.expense_type = 'Test Expense Type 1',
|
d.expense_type = 'Test Expense Type 1',
|
||||||
d.description = 'This is just to test Expense Claim',
|
d.description = 'This is just to test Expense Claim',
|
||||||
d.claim_amount = 2000,
|
d.amount = 2000,
|
||||||
d.sanctioned_amount=2000,
|
d.sanctioned_amount=2000,
|
||||||
refresh_field('expenses');
|
refresh_field('expenses');
|
||||||
},
|
},
|
||||||
|
@ -6,6 +6,7 @@ import frappe
|
|||||||
import unittest
|
import unittest
|
||||||
from frappe.utils import random_string, nowdate
|
from frappe.utils import random_string, nowdate
|
||||||
from erpnext.hr.doctype.expense_claim.expense_claim import make_bank_entry
|
from erpnext.hr.doctype.expense_claim.expense_claim import make_bank_entry
|
||||||
|
from erpnext.accounts.doctype.account.test_account import create_account
|
||||||
|
|
||||||
test_records = frappe.get_test_records('Expense Claim')
|
test_records = frappe.get_test_records('Expense Claim')
|
||||||
test_dependencies = ['Employee']
|
test_dependencies = ['Employee']
|
||||||
@ -26,7 +27,7 @@ class TestExpenseClaim(unittest.TestCase):
|
|||||||
task_name = frappe.db.get_value("Task", {"project": "_Test Project 1"})
|
task_name = frappe.db.get_value("Task", {"project": "_Test Project 1"})
|
||||||
payable_account = get_payable_account("Wind Power LLC")
|
payable_account = get_payable_account("Wind Power LLC")
|
||||||
|
|
||||||
make_expense_claim(payable_account, 300, 200, "Wind Power LLC","Travel Expenses - WP", "_Test Project 1", task_name)
|
make_expense_claim(payable_account, 300, 200, "Wind Power LLC", "Travel Expenses - WP", "_Test Project 1", task_name)
|
||||||
|
|
||||||
self.assertEqual(frappe.db.get_value("Task", task_name, "total_expense_claim"), 200)
|
self.assertEqual(frappe.db.get_value("Task", task_name, "total_expense_claim"), 200)
|
||||||
self.assertEqual(frappe.db.get_value("Project", "_Test Project 1", "total_expense_claim"), 200)
|
self.assertEqual(frappe.db.get_value("Project", "_Test Project 1", "total_expense_claim"), 200)
|
||||||
@ -62,7 +63,8 @@ class TestExpenseClaim(unittest.TestCase):
|
|||||||
|
|
||||||
def test_expense_claim_gl_entry(self):
|
def test_expense_claim_gl_entry(self):
|
||||||
payable_account = get_payable_account("Wind Power LLC")
|
payable_account = get_payable_account("Wind Power LLC")
|
||||||
expense_claim = make_expense_claim(payable_account, 300, 200, "Wind Power LLC", "Travel Expenses - WP")
|
taxes = generate_taxes()
|
||||||
|
expense_claim = make_expense_claim(payable_account, 300, 200, "Wind Power LLC", "Travel Expenses - WP", do_not_submit=True, taxes=taxes)
|
||||||
expense_claim.submit()
|
expense_claim.submit()
|
||||||
|
|
||||||
gl_entries = frappe.db.sql("""select account, debit, credit
|
gl_entries = frappe.db.sql("""select account, debit, credit
|
||||||
@ -72,7 +74,8 @@ class TestExpenseClaim(unittest.TestCase):
|
|||||||
self.assertTrue(gl_entries)
|
self.assertTrue(gl_entries)
|
||||||
|
|
||||||
expected_values = dict((d[0], d) for d in [
|
expected_values = dict((d[0], d) for d in [
|
||||||
[payable_account, 0.0, 200.0],
|
['CGST - WP',10.0, 0.0],
|
||||||
|
[payable_account, 0.0, 210.0],
|
||||||
["Travel Expenses - WP", 200.0, 0.0]
|
["Travel Expenses - WP", 200.0, 0.0]
|
||||||
])
|
])
|
||||||
|
|
||||||
@ -89,7 +92,7 @@ class TestExpenseClaim(unittest.TestCase):
|
|||||||
"payable_account": payable_account,
|
"payable_account": payable_account,
|
||||||
"approval_status": "Rejected",
|
"approval_status": "Rejected",
|
||||||
"expenses":
|
"expenses":
|
||||||
[{ "expense_type": "Travel", "default_account": "Travel Expenses - WP", "claim_amount": 300, "sanctioned_amount": 200 }]
|
[{ "expense_type": "Travel", "default_account": "Travel Expenses - WP", "amount": 300, "sanctioned_amount": 200 }]
|
||||||
})
|
})
|
||||||
expense_claim.submit()
|
expense_claim.submit()
|
||||||
|
|
||||||
@ -100,22 +103,44 @@ class TestExpenseClaim(unittest.TestCase):
|
|||||||
self.assertEquals(len(gl_entry), 0)
|
self.assertEquals(len(gl_entry), 0)
|
||||||
|
|
||||||
def get_payable_account(company):
|
def get_payable_account(company):
|
||||||
return frappe.get_cached_value('Company', company, 'default_payable_account')
|
return frappe.get_cached_value('Company', company, 'default_payable_account')
|
||||||
|
|
||||||
def make_expense_claim(payable_account,claim_amount, sanctioned_amount, company, account, project=None, task_name=None):
|
def generate_taxes():
|
||||||
expense_claim = frappe.get_doc({
|
parent_account = frappe.db.get_value('Account',
|
||||||
|
{'company': "Wind Power LLC", 'is_group':1, 'account_type': 'Tax'},
|
||||||
|
'name')
|
||||||
|
account = create_account(company="Wind Power LLC", account_name="CGST", account_type="Tax", parent_account=parent_account)
|
||||||
|
return {'taxes':[{
|
||||||
|
"account_head": account,
|
||||||
|
"rate": 0,
|
||||||
|
"description": "CGST",
|
||||||
|
"tax_amount": 10,
|
||||||
|
"total": 210
|
||||||
|
}]}
|
||||||
|
|
||||||
|
def make_expense_claim(payable_account, amount, sanctioned_amount, company, account, project=None, task_name=None, do_not_submit=False, taxes=None):
|
||||||
|
expense_claim = {
|
||||||
"doctype": "Expense Claim",
|
"doctype": "Expense Claim",
|
||||||
"employee": "_T-Employee-00001",
|
"employee": "_T-Employee-00001",
|
||||||
"payable_account": payable_account,
|
"payable_account": payable_account,
|
||||||
"approval_status": "Approved",
|
"approval_status": "Approved",
|
||||||
"company": company,
|
"company": company,
|
||||||
"expenses":
|
"expenses":
|
||||||
[{ "expense_type": "Travel", "default_account": account, "claim_amount": claim_amount, "sanctioned_amount": sanctioned_amount }]
|
[{"expense_type": "Travel",
|
||||||
})
|
"default_account": account,
|
||||||
|
"amount": amount,
|
||||||
|
"sanctioned_amount": sanctioned_amount}]}
|
||||||
|
if taxes:
|
||||||
|
expense_claim.update(taxes)
|
||||||
|
|
||||||
|
expense_claim = frappe.get_doc(expense_claim)
|
||||||
|
|
||||||
if project:
|
if project:
|
||||||
expense_claim.project = project
|
expense_claim.project = project
|
||||||
if task_name:
|
if task_name:
|
||||||
expense_claim.task = task_name
|
expense_claim.task = task_name
|
||||||
|
|
||||||
|
if do_not_submit:
|
||||||
|
return expense_claim
|
||||||
expense_claim.submit()
|
expense_claim.submit()
|
||||||
return expense_claim
|
return expense_claim
|
||||||
|
@ -253,7 +253,7 @@
|
|||||||
"bold": 0,
|
"bold": 0,
|
||||||
"collapsible": 0,
|
"collapsible": 0,
|
||||||
"columns": 0,
|
"columns": 0,
|
||||||
"fieldname": "claim_amount",
|
"fieldname": "amount",
|
||||||
"fieldtype": "Currency",
|
"fieldtype": "Currency",
|
||||||
"hidden": 0,
|
"hidden": 0,
|
||||||
"ignore_user_permissions": 0,
|
"ignore_user_permissions": 0,
|
||||||
@ -262,7 +262,7 @@
|
|||||||
"in_global_search": 0,
|
"in_global_search": 0,
|
||||||
"in_list_view": 1,
|
"in_list_view": 1,
|
||||||
"in_standard_filter": 0,
|
"in_standard_filter": 0,
|
||||||
"label": "Claim Amount",
|
"label": "Amount",
|
||||||
"length": 0,
|
"length": 0,
|
||||||
"no_copy": 0,
|
"no_copy": 0,
|
||||||
"oldfieldname": "claim_amount",
|
"oldfieldname": "claim_amount",
|
||||||
@ -360,7 +360,7 @@
|
|||||||
"issingle": 0,
|
"issingle": 0,
|
||||||
"istable": 1,
|
"istable": 1,
|
||||||
"max_attachments": 0,
|
"max_attachments": 0,
|
||||||
"modified": "2019-02-24 08:41:36.122565",
|
"modified": "2019-06-10 08:41:36.122565",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"module": "HR",
|
"module": "HR",
|
||||||
"name": "Expense Claim Detail",
|
"name": "Expense Claim Detail",
|
||||||
|
@ -0,0 +1,105 @@
|
|||||||
|
{
|
||||||
|
"autoname": "hash",
|
||||||
|
"creation": "2019-06-03 11:42:33.123976",
|
||||||
|
"doctype": "DocType",
|
||||||
|
"document_type": "Setup",
|
||||||
|
"editable_grid": 1,
|
||||||
|
"engine": "InnoDB",
|
||||||
|
"field_order": [
|
||||||
|
"account_head",
|
||||||
|
"cost_center",
|
||||||
|
"col_break1",
|
||||||
|
"rate",
|
||||||
|
"description",
|
||||||
|
"section_break_6",
|
||||||
|
"tax_amount",
|
||||||
|
"column_break_8",
|
||||||
|
"total"
|
||||||
|
],
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"fieldname": "col_break1",
|
||||||
|
"fieldtype": "Column Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"columns": 2,
|
||||||
|
"fieldname": "account_head",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Account Head",
|
||||||
|
"oldfieldname": "account_head",
|
||||||
|
"oldfieldtype": "Link",
|
||||||
|
"options": "Account",
|
||||||
|
"reqd": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": ":Company",
|
||||||
|
"fieldname": "cost_center",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"label": "Cost Center",
|
||||||
|
"oldfieldname": "cost_center",
|
||||||
|
"oldfieldtype": "Link",
|
||||||
|
"options": "Cost Center"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "description",
|
||||||
|
"fieldtype": "Small Text",
|
||||||
|
"label": "Description",
|
||||||
|
"oldfieldname": "description",
|
||||||
|
"oldfieldtype": "Small Text",
|
||||||
|
"print_width": "300px",
|
||||||
|
"reqd": 1,
|
||||||
|
"width": "300px"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"columns": 2,
|
||||||
|
"fetch_from": "account_head.tax_rate",
|
||||||
|
"fetch_if_empty": 1,
|
||||||
|
"fieldname": "rate",
|
||||||
|
"fieldtype": "Float",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Rate",
|
||||||
|
"oldfieldname": "rate",
|
||||||
|
"oldfieldtype": "Currency"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"columns": 2,
|
||||||
|
"fieldname": "tax_amount",
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Amount",
|
||||||
|
"oldfieldname": "tax_amount",
|
||||||
|
"oldfieldtype": "Currency",
|
||||||
|
"options": "currency"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"columns": 2,
|
||||||
|
"fieldname": "total",
|
||||||
|
"fieldtype": "Currency",
|
||||||
|
"in_list_view": 1,
|
||||||
|
"label": "Total",
|
||||||
|
"oldfieldname": "total",
|
||||||
|
"oldfieldtype": "Currency",
|
||||||
|
"options": "currency",
|
||||||
|
"read_only": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "section_break_6",
|
||||||
|
"fieldtype": "Section Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "column_break_8",
|
||||||
|
"fieldtype": "Column Break"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"istable": 1,
|
||||||
|
"modified": "2019-06-20 12:01:33.919555",
|
||||||
|
"modified_by": "Administrator",
|
||||||
|
"module": "HR",
|
||||||
|
"name": "Expense Taxes and Charges",
|
||||||
|
"owner": "Administrator",
|
||||||
|
"permissions": [],
|
||||||
|
"sort_field": "modified",
|
||||||
|
"sort_order": "ASC",
|
||||||
|
"track_changes": 1
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors
|
||||||
|
# For license information, please see license.txt
|
||||||
|
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
# import frappe
|
||||||
|
from frappe.model.document import Document
|
||||||
|
|
||||||
|
class ExpenseTaxesandCharges(Document):
|
||||||
|
pass
|
@ -4,7 +4,7 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe
|
import frappe
|
||||||
import json
|
import json
|
||||||
from frappe.utils import cint, getdate, formatdate
|
from frappe.utils import cint, getdate, formatdate, today
|
||||||
from frappe import throw, _
|
from frappe import throw, _
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
|
|
||||||
@ -84,3 +84,13 @@ def get_events(start, end, filters=None):
|
|||||||
fields=['name', '`tabHoliday`.holiday_date', '`tabHoliday`.description', '`tabHoliday List`.color'],
|
fields=['name', '`tabHoliday`.holiday_date', '`tabHoliday`.description', '`tabHoliday List`.color'],
|
||||||
filters = filters,
|
filters = filters,
|
||||||
update={"allDay": 1})
|
update={"allDay": 1})
|
||||||
|
|
||||||
|
|
||||||
|
def is_holiday(holiday_list, date=today()):
|
||||||
|
"""Returns true if the given date is a holiday in the given holiday list
|
||||||
|
"""
|
||||||
|
if holiday_list:
|
||||||
|
return bool(frappe.get_all('Holiday List',
|
||||||
|
dict(name=holiday_list, holiday_date=date)))
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
@ -4,6 +4,29 @@ from __future__ import unicode_literals
|
|||||||
|
|
||||||
import frappe
|
import frappe
|
||||||
import unittest
|
import unittest
|
||||||
|
from frappe.utils import getdate
|
||||||
|
from datetime import timedelta
|
||||||
|
|
||||||
|
|
||||||
class TestHolidayList(unittest.TestCase):
|
class TestHolidayList(unittest.TestCase):
|
||||||
pass
|
def test_holiday_list(self):
|
||||||
|
today_date = getdate()
|
||||||
|
test_holiday_dates = [today_date-timedelta(days=5), today_date-timedelta(days=4)]
|
||||||
|
holiday_list = make_holiday_list("test_holiday_list",
|
||||||
|
holiday_dates=[
|
||||||
|
{'holiday_date': test_holiday_dates[0], 'description': 'test holiday'},
|
||||||
|
{'holiday_date': test_holiday_dates[1], 'description': 'test holiday2'}
|
||||||
|
])
|
||||||
|
fetched_holiday_list = frappe.get_value('Holiday List', holiday_list.name)
|
||||||
|
self.assertEqual(holiday_list.name, fetched_holiday_list)
|
||||||
|
|
||||||
|
def make_holiday_list(name, from_date=getdate()-timedelta(days=10), to_date=getdate(), holiday_dates=None):
|
||||||
|
frappe.delete_doc_if_exists("Holiday List", name, force=1)
|
||||||
|
doc = frappe.get_doc({
|
||||||
|
"doctype": "Holiday List",
|
||||||
|
"holiday_list_name": name,
|
||||||
|
"from_date" : from_date,
|
||||||
|
"to_date" : to_date,
|
||||||
|
"holidays" : holiday_dates
|
||||||
|
}).insert()
|
||||||
|
return doc
|
||||||
|
@ -1,665 +1,162 @@
|
|||||||
{
|
{
|
||||||
"allow_copy": 0,
|
"creation": "2013-08-02 13:45:23",
|
||||||
"allow_events_in_timeline": 0,
|
"doctype": "DocType",
|
||||||
"allow_guest_to_view": 0,
|
"document_type": "Other",
|
||||||
"allow_import": 0,
|
"editable_grid": 1,
|
||||||
"allow_rename": 0,
|
"field_order": [
|
||||||
"beta": 0,
|
"employee_settings",
|
||||||
"creation": "2013-08-02 13:45:23",
|
"retirement_age",
|
||||||
"custom": 0,
|
"emp_created_by",
|
||||||
"docstatus": 0,
|
"column_break_4",
|
||||||
"doctype": "DocType",
|
"stop_birthday_reminders",
|
||||||
"document_type": "Other",
|
"expense_approver_mandatory_in_expense_claim",
|
||||||
"editable_grid": 1,
|
"payroll_settings",
|
||||||
|
"include_holidays_in_total_working_days",
|
||||||
|
"max_working_hours_against_timesheet",
|
||||||
|
"column_break_11",
|
||||||
|
"email_salary_slip_to_employee",
|
||||||
|
"encrypt_salary_slips_in_emails",
|
||||||
|
"password_policy",
|
||||||
|
"leave_settings",
|
||||||
|
"leave_approval_notification_template",
|
||||||
|
"leave_status_notification_template",
|
||||||
|
"column_break_18",
|
||||||
|
"leave_approver_mandatory_in_leave_application",
|
||||||
|
"show_leaves_of_all_department_members_in_calendar"
|
||||||
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"fieldname": "employee_settings",
|
||||||
"allow_in_quick_entry": 0,
|
"fieldtype": "Section Break",
|
||||||
"allow_on_submit": 0,
|
"label": "Employee Settings"
|
||||||
"bold": 0,
|
},
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fetch_if_empty": 0,
|
|
||||||
"fieldname": "employee_settings",
|
|
||||||
"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": "Employee Settings",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"description": "Enter retirement age in years",
|
||||||
"allow_in_quick_entry": 0,
|
"fieldname": "retirement_age",
|
||||||
"allow_on_submit": 0,
|
"fieldtype": "Data",
|
||||||
"bold": 0,
|
"label": "Retirement Age"
|
||||||
"collapsible": 0,
|
},
|
||||||
"columns": 0,
|
|
||||||
"default": "",
|
|
||||||
"description": "Enter retirement age in years",
|
|
||||||
"fetch_if_empty": 0,
|
|
||||||
"fieldname": "retirement_age",
|
|
||||||
"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": "Retirement Age",
|
|
||||||
"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,
|
"default": "Naming Series",
|
||||||
"allow_in_quick_entry": 0,
|
"description": "Employee record is created using selected field. ",
|
||||||
"allow_on_submit": 0,
|
"fieldname": "emp_created_by",
|
||||||
"bold": 0,
|
"fieldtype": "Select",
|
||||||
"collapsible": 0,
|
"label": "Employee Records to be created by",
|
||||||
"columns": 0,
|
"options": "Naming Series\nEmployee Number\nFull Name"
|
||||||
"default": "Naming Series",
|
},
|
||||||
"description": "Employee record is created using selected field. ",
|
|
||||||
"fetch_if_empty": 0,
|
|
||||||
"fieldname": "emp_created_by",
|
|
||||||
"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": "Employee Records to be created by",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Naming Series\nEmployee Number\nFull Name",
|
|
||||||
"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,
|
"fieldname": "leave_approval_notification_template",
|
||||||
"allow_in_quick_entry": 0,
|
"fieldtype": "Link",
|
||||||
"allow_on_submit": 0,
|
"label": "Leave Approval Notification Template",
|
||||||
"bold": 0,
|
"options": "Email Template"
|
||||||
"collapsible": 0,
|
},
|
||||||
"columns": 0,
|
|
||||||
"default": "",
|
|
||||||
"fetch_if_empty": 0,
|
|
||||||
"fieldname": "leave_approval_notification_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": "Leave Approval Notification Template",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Email 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,
|
"fieldname": "leave_status_notification_template",
|
||||||
"allow_in_quick_entry": 0,
|
"fieldtype": "Link",
|
||||||
"allow_on_submit": 0,
|
"label": "Leave Status Notification Template",
|
||||||
"bold": 0,
|
"options": "Email Template"
|
||||||
"collapsible": 0,
|
},
|
||||||
"columns": 0,
|
|
||||||
"fetch_if_empty": 0,
|
|
||||||
"fieldname": "leave_status_notification_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": "Leave Status Notification Template",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Email 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,
|
"fieldname": "column_break_4",
|
||||||
"allow_in_quick_entry": 0,
|
"fieldtype": "Column Break"
|
||||||
"allow_on_submit": 0,
|
},
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fetch_if_empty": 0,
|
|
||||||
"fieldname": "column_break_4",
|
|
||||||
"fieldtype": "Column Break",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"default": "0",
|
||||||
"allow_in_quick_entry": 0,
|
"description": "Don't send Employee Birthday Reminders",
|
||||||
"allow_on_submit": 0,
|
"fieldname": "stop_birthday_reminders",
|
||||||
"bold": 0,
|
"fieldtype": "Check",
|
||||||
"collapsible": 0,
|
"label": "Stop Birthday Reminders"
|
||||||
"columns": 0,
|
},
|
||||||
"description": "Don't send Employee Birthday Reminders",
|
|
||||||
"fetch_if_empty": 0,
|
|
||||||
"fieldname": "stop_birthday_reminders",
|
|
||||||
"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": "Stop Birthday Reminders",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"default": "1",
|
||||||
"allow_in_quick_entry": 0,
|
"fieldname": "leave_approver_mandatory_in_leave_application",
|
||||||
"allow_on_submit": 0,
|
"fieldtype": "Check",
|
||||||
"bold": 0,
|
"label": "Leave Approver Mandatory In Leave Application"
|
||||||
"collapsible": 0,
|
},
|
||||||
"columns": 0,
|
|
||||||
"fetch_if_empty": 0,
|
|
||||||
"fieldname": "maintain_bill_work_hours_same",
|
|
||||||
"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": "Maintain Billing Hours and Working Hours Same on Timesheet",
|
|
||||||
"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,
|
"default": "1",
|
||||||
"allow_in_quick_entry": 0,
|
"fieldname": "expense_approver_mandatory_in_expense_claim",
|
||||||
"allow_on_submit": 0,
|
"fieldtype": "Check",
|
||||||
"bold": 0,
|
"label": "Expense Approver Mandatory In Expense Claim"
|
||||||
"collapsible": 0,
|
},
|
||||||
"columns": 0,
|
|
||||||
"default": "1",
|
|
||||||
"fetch_if_empty": 0,
|
|
||||||
"fieldname": "leave_approver_mandatory_in_leave_application",
|
|
||||||
"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": "Leave Approver Mandatory In Leave Application",
|
|
||||||
"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,
|
"fieldname": "payroll_settings",
|
||||||
"allow_in_quick_entry": 0,
|
"fieldtype": "Section Break",
|
||||||
"allow_on_submit": 0,
|
"label": "Payroll Settings"
|
||||||
"bold": 0,
|
},
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"default": "1",
|
|
||||||
"fetch_if_empty": 0,
|
|
||||||
"fieldname": "expense_approver_mandatory_in_expense_claim",
|
|
||||||
"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": "Expense Approver Mandatory In Expense Claim",
|
|
||||||
"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,
|
"default": "0",
|
||||||
"allow_in_quick_entry": 0,
|
"description": "If checked, Total no. of Working Days will include holidays, and this will reduce the value of Salary Per Day",
|
||||||
"allow_on_submit": 0,
|
"fieldname": "include_holidays_in_total_working_days",
|
||||||
"bold": 0,
|
"fieldtype": "Check",
|
||||||
"collapsible": 0,
|
"label": "Include holidays in Total no. of Working Days"
|
||||||
"columns": 0,
|
},
|
||||||
"depends_on": "",
|
|
||||||
"fetch_if_empty": 0,
|
|
||||||
"fieldname": "payroll_settings",
|
|
||||||
"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": "Payroll Settings",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"default": "1",
|
||||||
"allow_in_quick_entry": 0,
|
"description": "Emails salary slip to employee based on preferred email selected in Employee",
|
||||||
"allow_on_submit": 0,
|
"fieldname": "email_salary_slip_to_employee",
|
||||||
"bold": 0,
|
"fieldtype": "Check",
|
||||||
"collapsible": 0,
|
"label": "Email Salary Slip to Employee"
|
||||||
"columns": 0,
|
},
|
||||||
"description": "If checked, Total no. of Working Days will include holidays, and this will reduce the value of Salary Per Day",
|
|
||||||
"fetch_if_empty": 0,
|
|
||||||
"fieldname": "include_holidays_in_total_working_days",
|
|
||||||
"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": "Include holidays in Total no. of Working Days",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"default": "0",
|
||||||
"allow_in_quick_entry": 0,
|
"depends_on": "eval: doc.email_salary_slip_to_employee == 1;",
|
||||||
"allow_on_submit": 0,
|
"description": "The salary slip emailed to the employee will be password protected, the password will be generated based on the password policy.",
|
||||||
"bold": 0,
|
"fieldname": "encrypt_salary_slips_in_emails",
|
||||||
"collapsible": 0,
|
"fieldtype": "Check",
|
||||||
"columns": 0,
|
"label": "Encrypt Salary Slips in Emails"
|
||||||
"default": "1",
|
},
|
||||||
"description": "Emails salary slip to employee based on preferred email selected in Employee",
|
|
||||||
"fetch_if_empty": 0,
|
|
||||||
"fieldname": "email_salary_slip_to_employee",
|
|
||||||
"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": "Email Salary Slip to Employee",
|
|
||||||
"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,
|
"depends_on": "eval: doc.encrypt_salary_slips_in_emails == 1",
|
||||||
"allow_in_quick_entry": 0,
|
"description": "<b>Example:</b> SAL-{first_name}-{date_of_birth.year} <br>This will generate a password like SAL-Jane-1972",
|
||||||
"allow_on_submit": 0,
|
"fieldname": "password_policy",
|
||||||
"bold": 0,
|
"fieldtype": "Data",
|
||||||
"collapsible": 0,
|
"in_list_view": 1,
|
||||||
"columns": 0,
|
"label": "Password Policy"
|
||||||
"depends_on": "eval: doc.email_salary_slip_to_employee == 1;",
|
},
|
||||||
"description": "The salary slip emailed to the employee will be password protected, the password will be generated based on the password policy.",
|
|
||||||
"fetch_if_empty": 0,
|
|
||||||
"fieldname": "encrypt_salary_slips_in_emails",
|
|
||||||
"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": "Encrypt Salary Slips in Emails",
|
|
||||||
"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,
|
"fieldname": "max_working_hours_against_timesheet",
|
||||||
"allow_in_quick_entry": 0,
|
"fieldtype": "Float",
|
||||||
"allow_on_submit": 0,
|
"label": "Max working hours against Timesheet"
|
||||||
"bold": 0,
|
},
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"depends_on": "eval: doc.encrypt_salary_slips_in_emails == 1",
|
|
||||||
"description": "<b>Example:</b> SAL-{first_name}-{date_of_birth.year} <br>This will generate a password like SAL-Jane-1972",
|
|
||||||
"fetch_if_empty": 0,
|
|
||||||
"fieldname": "password_policy",
|
|
||||||
"fieldtype": "Data",
|
|
||||||
"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": "Password Policy",
|
|
||||||
"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,
|
"fieldname": "leave_settings",
|
||||||
"allow_in_quick_entry": 0,
|
"fieldtype": "Section Break",
|
||||||
"allow_on_submit": 0,
|
"label": "Leave Settings"
|
||||||
"bold": 0,
|
},
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fetch_if_empty": 0,
|
|
||||||
"fieldname": "max_working_hours_against_timesheet",
|
|
||||||
"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": "Max working hours against Timesheet",
|
|
||||||
"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,
|
"default": "0",
|
||||||
"allow_in_quick_entry": 0,
|
"fieldname": "show_leaves_of_all_department_members_in_calendar",
|
||||||
"allow_on_submit": 0,
|
"fieldtype": "Check",
|
||||||
"bold": 0,
|
"label": "Show Leaves Of All Department Members In Calendar"
|
||||||
"collapsible": 0,
|
},
|
||||||
"columns": 0,
|
|
||||||
"fetch_if_empty": 0,
|
|
||||||
"fieldname": "leave_settings",
|
|
||||||
"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": "Leave Settings",
|
|
||||||
"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,
|
"fieldname": "column_break_11",
|
||||||
"allow_in_quick_entry": 0,
|
"fieldtype": "Column Break"
|
||||||
"allow_on_submit": 0,
|
},
|
||||||
"bold": 0,
|
{
|
||||||
"collapsible": 0,
|
"fieldname": "column_break_18",
|
||||||
"columns": 0,
|
"fieldtype": "Column Break"
|
||||||
"fetch_if_empty": 0,
|
|
||||||
"fieldname": "show_leaves_of_all_department_members_in_calendar",
|
|
||||||
"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": "Show Leaves Of All Department Members In Calendar",
|
|
||||||
"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
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"has_web_view": 0,
|
"icon": "fa fa-cog",
|
||||||
"hide_toolbar": 0,
|
"idx": 1,
|
||||||
"icon": "fa fa-cog",
|
"issingle": 1,
|
||||||
"idx": 1,
|
"modified": "2019-05-31 16:18:50.245872",
|
||||||
"in_create": 0,
|
"modified_by": "Administrator",
|
||||||
"is_submittable": 0,
|
"module": "HR",
|
||||||
"issingle": 1,
|
"name": "HR Settings",
|
||||||
"istable": 0,
|
"owner": "Administrator",
|
||||||
"max_attachments": 0,
|
|
||||||
"modified": "2019-04-25 15:08:12.983571",
|
|
||||||
"modified_by": "shivam@example.com",
|
|
||||||
"module": "HR",
|
|
||||||
"name": "HR Settings",
|
|
||||||
"owner": "Administrator",
|
|
||||||
"permissions": [
|
"permissions": [
|
||||||
{
|
{
|
||||||
"amend": 0,
|
"create": 1,
|
||||||
"cancel": 0,
|
"email": 1,
|
||||||
"create": 1,
|
"print": 1,
|
||||||
"delete": 0,
|
"read": 1,
|
||||||
"email": 1,
|
"role": "System Manager",
|
||||||
"export": 0,
|
"share": 1,
|
||||||
"if_owner": 0,
|
|
||||||
"import": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"print": 1,
|
|
||||||
"read": 1,
|
|
||||||
"report": 0,
|
|
||||||
"role": "System Manager",
|
|
||||||
"set_user_permissions": 0,
|
|
||||||
"share": 1,
|
|
||||||
"submit": 0,
|
|
||||||
"write": 1
|
"write": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"quick_entry": 0,
|
"sort_order": "ASC"
|
||||||
"read_only": 0,
|
|
||||||
"show_name_in_global_search": 0,
|
|
||||||
"sort_order": "ASC",
|
|
||||||
"track_changes": 0,
|
|
||||||
"track_seen": 0,
|
|
||||||
"track_views": 0
|
|
||||||
}
|
}
|
@ -6,7 +6,6 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe
|
import frappe
|
||||||
from frappe import _
|
from frappe import _
|
||||||
|
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
|
|
||||||
class HRSettings(Document):
|
class HRSettings(Document):
|
||||||
@ -22,4 +21,4 @@ class HRSettings(Document):
|
|||||||
def validate_password_policy(self):
|
def validate_password_policy(self):
|
||||||
if self.email_salary_slip_to_employee and self.encrypt_salary_slips_in_emails:
|
if self.email_salary_slip_to_employee and self.encrypt_salary_slips_in_emails:
|
||||||
if not self.password_policy:
|
if not self.password_policy:
|
||||||
frappe.throw(_("Password policy for Salary Slips is not set"))
|
frappe.throw(_("Password policy for Salary Slips is not set"))
|
||||||
|
@ -5,6 +5,9 @@ from __future__ import unicode_literals
|
|||||||
|
|
||||||
import frappe
|
import frappe
|
||||||
import unittest
|
import unittest
|
||||||
|
from erpnext.hr.doctype.employee.test_employee import make_employee
|
||||||
|
from frappe.utils import now_datetime
|
||||||
|
from datetime import timedelta
|
||||||
|
|
||||||
class TestHRSettings(unittest.TestCase):
|
class TestHRSettings(unittest.TestCase):
|
||||||
pass
|
pass
|
||||||
|
@ -25,5 +25,13 @@ frappe.ui.form.on("Job Applicant", {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
frm.set_query("job_title", function() {
|
||||||
|
return {
|
||||||
|
filters: {
|
||||||
|
'status': 'Open'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
@ -400,19 +400,6 @@ def get_leave_balance_on(employee, leave_type, date, allocation_records=None, do
|
|||||||
|
|
||||||
return flt(allocation.total_leaves_allocated) - (flt(leaves_taken) + flt(leaves_encashed))
|
return flt(allocation.total_leaves_allocated) - (flt(leaves_taken) + flt(leaves_encashed))
|
||||||
|
|
||||||
def get_total_allocated_leaves(employee, leave_type, date):
|
|
||||||
filters= {
|
|
||||||
'from_date': ['<=', date],
|
|
||||||
'to_date': ['>=', date],
|
|
||||||
'docstatus': 1,
|
|
||||||
'leave_type': leave_type,
|
|
||||||
'employee': employee
|
|
||||||
}
|
|
||||||
|
|
||||||
leave_allocation_records = frappe.db.get_all('Leave Allocation', filters=filters, fields=['total_leaves_allocated'])
|
|
||||||
|
|
||||||
return flt(leave_allocation_records[0]['total_leaves_allocated']) if leave_allocation_records else flt(0)
|
|
||||||
|
|
||||||
def get_leaves_for_period(employee, leave_type, from_date, to_date, status, docname=None):
|
def get_leaves_for_period(employee, leave_type, from_date, to_date, status, docname=None):
|
||||||
leave_applications = frappe.db.sql("""
|
leave_applications = frappe.db.sql("""
|
||||||
select name, employee, leave_type, from_date, to_date, total_leave_days
|
select name, employee, leave_type, from_date, to_date, total_leave_days
|
||||||
|
@ -281,7 +281,9 @@ class SalarySlip(TransactionBase):
|
|||||||
wages_row = {
|
wages_row = {
|
||||||
"salary_component": salary_component,
|
"salary_component": salary_component,
|
||||||
"abbr": frappe.db.get_value("Salary Component", salary_component, "salary_component_abbr"),
|
"abbr": frappe.db.get_value("Salary Component", salary_component, "salary_component_abbr"),
|
||||||
"amount": self.hour_rate * self.total_working_hours
|
"amount": self.hour_rate * self.total_working_hours,
|
||||||
|
"default_amount": 0.0,
|
||||||
|
"additional_amount": 0.0
|
||||||
}
|
}
|
||||||
doc.append('earnings', wages_row)
|
doc.append('earnings', wages_row)
|
||||||
|
|
||||||
|
@ -1,429 +1,132 @@
|
|||||||
{
|
{
|
||||||
"allow_copy": 0,
|
"allow_import": 1,
|
||||||
"allow_guest_to_view": 0,
|
"autoname": "HR-SHA-.YY.-.MM.-.#####",
|
||||||
"allow_import": 1,
|
"creation": "2018-04-13 16:25:04.562730",
|
||||||
"allow_rename": 0,
|
"doctype": "DocType",
|
||||||
"autoname": "HR-SHA-.YY.-.MM.-.#####",
|
"editable_grid": 1,
|
||||||
"beta": 0,
|
"engine": "InnoDB",
|
||||||
"creation": "2018-04-13 16:25:04.562730",
|
"field_order": [
|
||||||
"custom": 0,
|
"employee",
|
||||||
"docstatus": 0,
|
"employee_name",
|
||||||
"doctype": "DocType",
|
"department",
|
||||||
"document_type": "",
|
"shift_type",
|
||||||
"editable_grid": 1,
|
"column_break_3",
|
||||||
"engine": "InnoDB",
|
"company",
|
||||||
|
"date",
|
||||||
|
"shift_request",
|
||||||
|
"amended_from"
|
||||||
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"fieldname": "employee",
|
||||||
"allow_in_quick_entry": 0,
|
"fieldtype": "Link",
|
||||||
"allow_on_submit": 0,
|
"label": "Employee",
|
||||||
"bold": 0,
|
"options": "Employee",
|
||||||
"collapsible": 0,
|
"reqd": 1
|
||||||
"columns": 0,
|
},
|
||||||
"fieldname": "employee",
|
|
||||||
"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": "Employee",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Employee",
|
|
||||||
"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,
|
"fetch_from": "employee.employee_name",
|
||||||
"allow_in_quick_entry": 0,
|
"fieldname": "employee_name",
|
||||||
"allow_on_submit": 0,
|
"fieldtype": "Data",
|
||||||
"bold": 0,
|
"label": "Employee Name",
|
||||||
"collapsible": 0,
|
"read_only": 1
|
||||||
"columns": 0,
|
},
|
||||||
"fetch_from": "employee.employee_name",
|
|
||||||
"fieldname": "employee_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": "Employee Name",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "",
|
|
||||||
"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,
|
"fetch_from": "employee.department",
|
||||||
"allow_in_quick_entry": 0,
|
"fieldname": "department",
|
||||||
"allow_on_submit": 0,
|
"fieldtype": "Link",
|
||||||
"bold": 0,
|
"label": "Department",
|
||||||
"collapsible": 0,
|
"options": "Department",
|
||||||
"columns": 0,
|
"read_only": 1
|
||||||
"fetch_from": "employee.department",
|
},
|
||||||
"fieldname": "department",
|
|
||||||
"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": "Department",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Department",
|
|
||||||
"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,
|
"fieldname": "shift_type",
|
||||||
"allow_in_quick_entry": 0,
|
"fieldtype": "Link",
|
||||||
"allow_on_submit": 0,
|
"in_list_view": 1,
|
||||||
"bold": 0,
|
"label": "Shift Type",
|
||||||
"collapsible": 0,
|
"options": "Shift Type",
|
||||||
"columns": 0,
|
"reqd": 1
|
||||||
"fieldname": "shift_type",
|
},
|
||||||
"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": "Shift Type",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Shift Type",
|
|
||||||
"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,
|
"fieldname": "column_break_3",
|
||||||
"allow_in_quick_entry": 0,
|
"fieldtype": "Column Break"
|
||||||
"allow_on_submit": 0,
|
},
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "present",
|
|
||||||
"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": "Present",
|
|
||||||
"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,
|
"fieldname": "company",
|
||||||
"allow_in_quick_entry": 0,
|
"fieldtype": "Link",
|
||||||
"allow_on_submit": 0,
|
"label": "Company",
|
||||||
"bold": 0,
|
"options": "Company",
|
||||||
"collapsible": 0,
|
"reqd": 1
|
||||||
"columns": 0,
|
},
|
||||||
"fieldname": "column_break_3",
|
|
||||||
"fieldtype": "Column Break",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"fieldname": "date",
|
||||||
"allow_in_quick_entry": 0,
|
"fieldtype": "Date",
|
||||||
"allow_on_submit": 0,
|
"in_list_view": 1,
|
||||||
"bold": 0,
|
"label": "Date"
|
||||||
"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": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Company",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Company",
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 1,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"fieldname": "shift_request",
|
||||||
"allow_in_quick_entry": 0,
|
"fieldtype": "Link",
|
||||||
"allow_on_submit": 0,
|
"label": "Shift Request",
|
||||||
"bold": 0,
|
"options": "Shift Request",
|
||||||
"collapsible": 0,
|
"read_only": 1
|
||||||
"columns": 0,
|
},
|
||||||
"fieldname": "date",
|
|
||||||
"fieldtype": "Date",
|
|
||||||
"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": "Date",
|
|
||||||
"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,
|
"fieldname": "amended_from",
|
||||||
"allow_in_quick_entry": 0,
|
"fieldtype": "Link",
|
||||||
"allow_on_submit": 0,
|
"label": "Amended From",
|
||||||
"bold": 0,
|
"no_copy": 1,
|
||||||
"collapsible": 0,
|
"options": "Shift Assignment",
|
||||||
"columns": 0,
|
"print_hide": 1,
|
||||||
"fieldname": "shift_request",
|
"read_only": 1
|
||||||
"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": "Shift Request",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Shift Request",
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 1,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"allow_bulk_edit": 0,
|
|
||||||
"allow_in_quick_entry": 0,
|
|
||||||
"allow_on_submit": 0,
|
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "amended_from",
|
|
||||||
"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": "Amended From",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 1,
|
|
||||||
"options": "Shift Assignment",
|
|
||||||
"permlevel": 0,
|
|
||||||
"print_hide": 1,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 1,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"has_web_view": 0,
|
"is_submittable": 1,
|
||||||
"hide_heading": 0,
|
"modified": "2019-05-30 15:40:54.418427",
|
||||||
"hide_toolbar": 0,
|
"modified_by": "Administrator",
|
||||||
"idx": 0,
|
"module": "HR",
|
||||||
"image_view": 0,
|
"name": "Shift Assignment",
|
||||||
"in_create": 0,
|
"owner": "Administrator",
|
||||||
"is_submittable": 1,
|
|
||||||
"issingle": 0,
|
|
||||||
"istable": 0,
|
|
||||||
"max_attachments": 0,
|
|
||||||
"modified": "2018-08-21 16:15:41.155464",
|
|
||||||
"modified_by": "Administrator",
|
|
||||||
"module": "HR",
|
|
||||||
"name": "Shift Assignment",
|
|
||||||
"name_case": "",
|
|
||||||
"owner": "Administrator",
|
|
||||||
"permissions": [
|
"permissions": [
|
||||||
{
|
{
|
||||||
"amend": 0,
|
"email": 1,
|
||||||
"cancel": 0,
|
"export": 1,
|
||||||
"create": 0,
|
"print": 1,
|
||||||
"delete": 0,
|
"read": 1,
|
||||||
"email": 1,
|
"report": 1,
|
||||||
"export": 1,
|
"role": "Employee",
|
||||||
"if_owner": 0,
|
"share": 1
|
||||||
"import": 0,
|
},
|
||||||
"permlevel": 0,
|
|
||||||
"print": 1,
|
|
||||||
"read": 1,
|
|
||||||
"report": 1,
|
|
||||||
"role": "Employee",
|
|
||||||
"set_user_permissions": 0,
|
|
||||||
"share": 1,
|
|
||||||
"submit": 0,
|
|
||||||
"write": 0
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"amend": 1,
|
"amend": 1,
|
||||||
"cancel": 1,
|
"cancel": 1,
|
||||||
"create": 1,
|
"create": 1,
|
||||||
"delete": 1,
|
"delete": 1,
|
||||||
"email": 1,
|
"email": 1,
|
||||||
"export": 1,
|
"export": 1,
|
||||||
"if_owner": 0,
|
"print": 1,
|
||||||
"import": 0,
|
"read": 1,
|
||||||
"permlevel": 0,
|
"report": 1,
|
||||||
"print": 1,
|
"role": "HR Manager",
|
||||||
"read": 1,
|
"share": 1,
|
||||||
"report": 1,
|
"submit": 1,
|
||||||
"role": "HR Manager",
|
|
||||||
"set_user_permissions": 0,
|
|
||||||
"share": 1,
|
|
||||||
"submit": 1,
|
|
||||||
"write": 1
|
"write": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"amend": 0,
|
"create": 1,
|
||||||
"cancel": 0,
|
"email": 1,
|
||||||
"create": 1,
|
"export": 1,
|
||||||
"delete": 0,
|
"print": 1,
|
||||||
"email": 1,
|
"read": 1,
|
||||||
"export": 1,
|
"report": 1,
|
||||||
"if_owner": 0,
|
"role": "HR User",
|
||||||
"import": 0,
|
"share": 1,
|
||||||
"permlevel": 0,
|
"submit": 1,
|
||||||
"print": 1,
|
|
||||||
"read": 1,
|
|
||||||
"report": 1,
|
|
||||||
"role": "HR User",
|
|
||||||
"set_user_permissions": 0,
|
|
||||||
"share": 1,
|
|
||||||
"submit": 1,
|
|
||||||
"write": 1
|
"write": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"quick_entry": 0,
|
"sort_field": "modified",
|
||||||
"read_only": 0,
|
"sort_order": "DESC",
|
||||||
"read_only_onload": 0,
|
"title_field": "employee_name",
|
||||||
"show_name_in_global_search": 0,
|
"track_changes": 1
|
||||||
"sort_field": "modified",
|
|
||||||
"sort_order": "DESC",
|
|
||||||
"title_field": "employee_name",
|
|
||||||
"track_changes": 1,
|
|
||||||
"track_seen": 0,
|
|
||||||
"track_views": 0
|
|
||||||
}
|
}
|
@ -6,7 +6,10 @@ from __future__ import unicode_literals
|
|||||||
import frappe
|
import frappe
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
from frappe.utils import cint, cstr, date_diff, flt, formatdate, getdate
|
from frappe.utils import cint, cstr, date_diff, flt, formatdate, getdate, now_datetime, nowdate
|
||||||
|
from erpnext.hr.doctype.employee.employee import get_holiday_list_for_employee
|
||||||
|
from erpnext.hr.doctype.holiday_list.holiday_list import is_holiday
|
||||||
|
from datetime import timedelta, datetime
|
||||||
|
|
||||||
class OverlapError(frappe.ValidationError): pass
|
class OverlapError(frappe.ValidationError): pass
|
||||||
|
|
||||||
@ -78,3 +81,130 @@ def add_assignments(events, start, end, conditions=None):
|
|||||||
}
|
}
|
||||||
if e not in events:
|
if e not in events:
|
||||||
events.append(e)
|
events.append(e)
|
||||||
|
|
||||||
|
|
||||||
|
def get_employee_shift(employee, for_date=nowdate(), consider_default_shift=False, next_shift_direction=None):
|
||||||
|
"""Returns a Shift Type for the given employee on the given date. (excluding the holidays)
|
||||||
|
|
||||||
|
:param employee: Employee for which shift is required.
|
||||||
|
:param for_date: Date on which shift are required
|
||||||
|
:param consider_default_shift: If set to true, default shift is taken when no shift assignment is found.
|
||||||
|
:param next_shift_direction: One of: None, 'forward', 'reverse'. Direction to look for next shift if shift not found on given date.
|
||||||
|
"""
|
||||||
|
default_shift = frappe.db.get_value('Employee', employee, 'default_shift')
|
||||||
|
shift_type_name = frappe.db.get_value('Shift Assignment', {'employee':employee, 'date': for_date, 'docstatus': '1'}, 'shift_type')
|
||||||
|
if not shift_type_name and consider_default_shift:
|
||||||
|
shift_type_name = default_shift
|
||||||
|
if shift_type_name:
|
||||||
|
holiday_list_name = frappe.db.get_value('Shift Type', shift_type_name, 'holiday_list')
|
||||||
|
if not holiday_list_name:
|
||||||
|
holiday_list_name = get_holiday_list_for_employee(employee, False)
|
||||||
|
if holiday_list_name and is_holiday(holiday_list_name, for_date):
|
||||||
|
shift_type_name = None
|
||||||
|
|
||||||
|
if not shift_type_name and next_shift_direction:
|
||||||
|
MAX_DAYS = 366
|
||||||
|
if consider_default_shift and default_shift:
|
||||||
|
direction = -1 if next_shift_direction == 'reverse' else +1
|
||||||
|
for i in range(MAX_DAYS):
|
||||||
|
date = for_date+timedelta(days=direction*(i+1))
|
||||||
|
shift_details = get_employee_shift(employee, date, consider_default_shift, None)
|
||||||
|
if shift_details:
|
||||||
|
shift_type_name = shift_details.shift_type.name
|
||||||
|
for_date = date
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
direction = '<' if next_shift_direction == 'reverse' else '>'
|
||||||
|
sort_order = 'desc' if next_shift_direction == 'reverse' else 'asc'
|
||||||
|
dates = frappe.db.get_all('Shift Assignment',
|
||||||
|
'date',
|
||||||
|
{'employee':employee, 'date':(direction, for_date), 'docstatus': '1'},
|
||||||
|
as_list=True,
|
||||||
|
limit=MAX_DAYS, order_by="date "+sort_order)
|
||||||
|
for date in dates:
|
||||||
|
shift_details = get_employee_shift(employee, date[0], consider_default_shift, None)
|
||||||
|
if shift_details:
|
||||||
|
shift_type_name = shift_details.shift_type.name
|
||||||
|
for_date = date[0]
|
||||||
|
break
|
||||||
|
|
||||||
|
return get_shift_details(shift_type_name, for_date)
|
||||||
|
|
||||||
|
|
||||||
|
def get_employee_shift_timings(employee, for_timestamp=now_datetime(), consider_default_shift=False):
|
||||||
|
"""Returns previous shift, current/upcoming shift, next_shift for the given timestamp and employee
|
||||||
|
"""
|
||||||
|
# write and verify a test case for midnight shift.
|
||||||
|
prev_shift = curr_shift = next_shift = None
|
||||||
|
curr_shift = get_employee_shift(employee, for_timestamp.date(), consider_default_shift, 'forward')
|
||||||
|
if curr_shift:
|
||||||
|
next_shift = get_employee_shift(employee, curr_shift.start_datetime.date()+timedelta(days=1), consider_default_shift, 'forward')
|
||||||
|
prev_shift = get_employee_shift(employee, for_timestamp.date()+timedelta(days=-1), consider_default_shift, 'reverse')
|
||||||
|
|
||||||
|
if curr_shift:
|
||||||
|
if prev_shift:
|
||||||
|
curr_shift.actual_start = prev_shift.end_datetime if curr_shift.actual_start < prev_shift.end_datetime else curr_shift.actual_start
|
||||||
|
prev_shift.actual_end = curr_shift.actual_start if prev_shift.actual_end > curr_shift.actual_start else prev_shift.actual_end
|
||||||
|
if next_shift:
|
||||||
|
next_shift.actual_start = curr_shift.end_datetime if next_shift.actual_start < curr_shift.end_datetime else next_shift.actual_start
|
||||||
|
curr_shift.actual_end = next_shift.actual_start if curr_shift.actual_end > next_shift.actual_start else curr_shift.actual_end
|
||||||
|
return prev_shift, curr_shift, next_shift
|
||||||
|
|
||||||
|
|
||||||
|
def get_shift_details(shift_type_name, for_date=nowdate()):
|
||||||
|
"""Returns Shift Details which contain some additional information as described below.
|
||||||
|
'shift_details' contains the following keys:
|
||||||
|
'shift_type' - Object of DocType Shift Type,
|
||||||
|
'start_datetime' - Date and Time of shift start on given date,
|
||||||
|
'end_datetime' - Date and Time of shift end on given date,
|
||||||
|
'actual_start' - datetime of shift start after adding 'begin_check_in_before_shift_start_time',
|
||||||
|
'actual_end' - datetime of shift end after adding 'allow_check_out_after_shift_end_time'(None is returned if this is zero)
|
||||||
|
|
||||||
|
:param shift_type_name: shift type name for which shift_details is required.
|
||||||
|
:param for_date: Date on which shift_details are required
|
||||||
|
"""
|
||||||
|
if not shift_type_name:
|
||||||
|
return None
|
||||||
|
shift_type = frappe.get_doc('Shift Type', shift_type_name)
|
||||||
|
start_datetime = datetime.combine(for_date, datetime.min.time()) + shift_type.start_time
|
||||||
|
for_date = for_date + timedelta(days=1) if shift_type.start_time > shift_type.end_time else for_date
|
||||||
|
end_datetime = datetime.combine(for_date, datetime.min.time()) + shift_type.end_time
|
||||||
|
actual_start = start_datetime - timedelta(minutes=shift_type.begin_check_in_before_shift_start_time)
|
||||||
|
actual_end = end_datetime + timedelta(minutes=shift_type.allow_check_out_after_shift_end_time)
|
||||||
|
|
||||||
|
return frappe._dict({
|
||||||
|
'shift_type': shift_type,
|
||||||
|
'start_datetime': start_datetime,
|
||||||
|
'end_datetime': end_datetime,
|
||||||
|
'actual_start': actual_start,
|
||||||
|
'actual_end': actual_end
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
def get_actual_start_end_datetime_of_shift(employee, for_datetime, consider_default_shift=False):
|
||||||
|
"""Takes a datetime and returns the 'actual' start datetime and end datetime of the shift in which the timestamp belongs.
|
||||||
|
Here 'actual' means - taking in to account the "begin_check_in_before_shift_start_time" and "allow_check_out_after_shift_end_time".
|
||||||
|
None is returned if the timestamp is outside any actual shift timings.
|
||||||
|
Shift Details is also returned(current/upcoming i.e. if timestamp not in any actual shift then details of next shift returned)
|
||||||
|
"""
|
||||||
|
actual_shift_start = actual_shift_end = shift_details = None
|
||||||
|
shift_timings_as_per_timestamp = get_employee_shift_timings(employee, for_datetime, consider_default_shift)
|
||||||
|
timestamp_list = []
|
||||||
|
for shift in shift_timings_as_per_timestamp:
|
||||||
|
if shift:
|
||||||
|
timestamp_list.extend([shift.actual_start, shift.actual_end])
|
||||||
|
else:
|
||||||
|
timestamp_list.extend([None, None])
|
||||||
|
timestamp_index = None
|
||||||
|
for index, timestamp in enumerate(timestamp_list):
|
||||||
|
if timestamp and for_datetime <= timestamp:
|
||||||
|
timestamp_index = index
|
||||||
|
break
|
||||||
|
if timestamp_index and timestamp_index%2 == 1:
|
||||||
|
shift_details = shift_timings_as_per_timestamp[int((timestamp_index-1)/2)]
|
||||||
|
actual_shift_start = shift_details.actual_start
|
||||||
|
actual_shift_end = shift_details.actual_end
|
||||||
|
elif timestamp_index:
|
||||||
|
shift_details = shift_timings_as_per_timestamp[int(timestamp_index/2)]
|
||||||
|
|
||||||
|
return actual_shift_start, actual_shift_end, shift_details
|
||||||
|
@ -3,6 +3,16 @@
|
|||||||
|
|
||||||
frappe.ui.form.on('Shift Type', {
|
frappe.ui.form.on('Shift Type', {
|
||||||
refresh: function(frm) {
|
refresh: function(frm) {
|
||||||
|
frm.add_custom_button(
|
||||||
|
'Mark Auto Attendance',
|
||||||
|
() => frm.call({
|
||||||
|
doc: frm.doc,
|
||||||
|
method: 'process_auto_attendance',
|
||||||
|
freeze: true,
|
||||||
|
callback: () => {
|
||||||
|
frappe.msgprint(__("Attendance has been marked as per employee check-ins"));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1,194 +1,247 @@
|
|||||||
{
|
{
|
||||||
"allow_copy": 0,
|
"autoname": "prompt",
|
||||||
"allow_guest_to_view": 0,
|
"creation": "2018-04-13 16:22:52.954783",
|
||||||
"allow_import": 0,
|
"doctype": "DocType",
|
||||||
"allow_rename": 0,
|
"editable_grid": 1,
|
||||||
"autoname": "prompt",
|
"engine": "InnoDB",
|
||||||
"beta": 0,
|
"field_order": [
|
||||||
"creation": "2018-04-13 16:22:52.954783",
|
"start_time",
|
||||||
"custom": 0,
|
"end_time",
|
||||||
"docstatus": 0,
|
"column_break_3",
|
||||||
"doctype": "DocType",
|
"holiday_list",
|
||||||
"document_type": "",
|
"enable_auto_attendance",
|
||||||
"editable_grid": 1,
|
"auto_attendance_settings_section",
|
||||||
"engine": "InnoDB",
|
"determine_check_in_and_check_out",
|
||||||
|
"working_hours_calculation_based_on",
|
||||||
|
"begin_check_in_before_shift_start_time",
|
||||||
|
"allow_check_out_after_shift_end_time",
|
||||||
|
"column_break_10",
|
||||||
|
"working_hours_threshold_for_half_day",
|
||||||
|
"working_hours_threshold_for_absent",
|
||||||
|
"process_attendance_after",
|
||||||
|
"last_sync_of_checkin",
|
||||||
|
"grace_period_settings_auto_attendance_section",
|
||||||
|
"enable_entry_grace_period",
|
||||||
|
"late_entry_grace_period",
|
||||||
|
"consequence_after",
|
||||||
|
"consequence",
|
||||||
|
"column_break_18",
|
||||||
|
"enable_exit_grace_period",
|
||||||
|
"enable_different_consequence_for_early_exit",
|
||||||
|
"early_exit_grace_period",
|
||||||
|
"early_exit_consequence_after",
|
||||||
|
"early_exit_consequence"
|
||||||
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"fieldname": "start_time",
|
||||||
"allow_on_submit": 0,
|
"fieldtype": "Time",
|
||||||
"bold": 0,
|
"in_list_view": 1,
|
||||||
"collapsible": 0,
|
"label": "Start Time",
|
||||||
"columns": 0,
|
"reqd": 1
|
||||||
"fieldname": "start_time",
|
},
|
||||||
"fieldtype": "Time",
|
|
||||||
"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": "Start Time",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 1,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"fieldname": "end_time",
|
||||||
"allow_on_submit": 0,
|
"fieldtype": "Time",
|
||||||
"bold": 0,
|
"in_list_view": 1,
|
||||||
"collapsible": 0,
|
"label": "End Time",
|
||||||
"columns": 0,
|
"reqd": 1
|
||||||
"fieldname": "end_time",
|
},
|
||||||
"fieldtype": "Time",
|
|
||||||
"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": "End Time",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 1,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"fieldname": "holiday_list",
|
||||||
"allow_on_submit": 0,
|
"fieldtype": "Link",
|
||||||
"bold": 0,
|
"label": "Holiday List",
|
||||||
"collapsible": 0,
|
"options": "Holiday List"
|
||||||
"columns": 0,
|
},
|
||||||
"fieldname": "holiday_list",
|
{
|
||||||
"fieldtype": "Link",
|
"fieldname": "column_break_3",
|
||||||
"hidden": 0,
|
"fieldtype": "Column Break"
|
||||||
"ignore_user_permissions": 0,
|
},
|
||||||
"ignore_xss_filter": 0,
|
{
|
||||||
"in_filter": 0,
|
"fieldname": "column_break_10",
|
||||||
"in_global_search": 0,
|
"fieldtype": "Column Break"
|
||||||
"in_list_view": 0,
|
},
|
||||||
"in_standard_filter": 0,
|
{
|
||||||
"label": "Holiday List",
|
"fieldname": "determine_check_in_and_check_out",
|
||||||
"length": 0,
|
"fieldtype": "Select",
|
||||||
"no_copy": 0,
|
"label": "Determine Check-in and Check-out",
|
||||||
"options": "Holiday List",
|
"options": "Alternating entries as IN and OUT during the same shift\nStrictly based on Log Type in Employee Checkin"
|
||||||
"permlevel": 0,
|
},
|
||||||
"precision": "",
|
{
|
||||||
"print_hide": 0,
|
"fieldname": "working_hours_calculation_based_on",
|
||||||
"print_hide_if_no_value": 0,
|
"fieldtype": "Select",
|
||||||
"read_only": 0,
|
"label": "Working Hours Calculation Based On",
|
||||||
"remember_last_selected_value": 0,
|
"options": "First Check-in and Last Check-out\nEvery Valid Check-in and Check-out"
|
||||||
"report_hide": 0,
|
},
|
||||||
"reqd": 0,
|
{
|
||||||
"search_index": 0,
|
"description": "Working hours below which Half Day is marked. (Zero to disable)",
|
||||||
"set_only_once": 0,
|
"fieldname": "working_hours_threshold_for_half_day",
|
||||||
"translatable": 0,
|
"fieldtype": "Float",
|
||||||
"unique": 0
|
"label": "Working Hours Threshold for Half Day",
|
||||||
|
"precision": "1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Working hours below which Absent is marked. (Zero to disable)",
|
||||||
|
"fieldname": "working_hours_threshold_for_absent",
|
||||||
|
"fieldtype": "Float",
|
||||||
|
"label": "Working Hours Threshold for Absent",
|
||||||
|
"precision": "1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "60",
|
||||||
|
"description": "The time before the shift start time during which Employee Check-in is considered for attendance.",
|
||||||
|
"fieldname": "begin_check_in_before_shift_start_time",
|
||||||
|
"fieldtype": "Int",
|
||||||
|
"label": "Begin check-in before shift start time (in minutes)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "0",
|
||||||
|
"fieldname": "enable_entry_grace_period",
|
||||||
|
"fieldtype": "Check",
|
||||||
|
"label": "Enable Entry Grace Period"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"depends_on": "enable_entry_grace_period",
|
||||||
|
"description": "The time after the shift start time when check-in is considered as late (in minutes).",
|
||||||
|
"fieldname": "late_entry_grace_period",
|
||||||
|
"fieldtype": "Int",
|
||||||
|
"label": "Late Entry Grace Period"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"depends_on": "enable_entry_grace_period",
|
||||||
|
"description": "The number of occurrence after which the consequence is executed.",
|
||||||
|
"fieldname": "consequence_after",
|
||||||
|
"fieldtype": "Int",
|
||||||
|
"label": "Consequence after"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "Half Day",
|
||||||
|
"depends_on": "enable_entry_grace_period",
|
||||||
|
"fieldname": "consequence",
|
||||||
|
"fieldtype": "Select",
|
||||||
|
"label": "Consequence",
|
||||||
|
"options": "Half Day\nAbsent"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "column_break_18",
|
||||||
|
"fieldtype": "Column Break"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "0",
|
||||||
|
"fieldname": "enable_exit_grace_period",
|
||||||
|
"fieldtype": "Check",
|
||||||
|
"label": "Enable Exit Grace Period"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "0",
|
||||||
|
"depends_on": "enable_exit_grace_period",
|
||||||
|
"fieldname": "enable_different_consequence_for_early_exit",
|
||||||
|
"fieldtype": "Check",
|
||||||
|
"label": "Enable Different Consequence for Early Exit"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"depends_on": "eval:doc.enable_exit_grace_period",
|
||||||
|
"description": "The time before the shift end time when check-out is considered as early (in minutes).",
|
||||||
|
"fieldname": "early_exit_grace_period",
|
||||||
|
"fieldtype": "Int",
|
||||||
|
"label": "Early Exit Grace Period"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"depends_on": "eval:doc.enable_exit_grace_period && doc.enable_different_consequence_for_early_exit",
|
||||||
|
"description": "The number of occurrence after which the consequence is executed.",
|
||||||
|
"fieldname": "early_exit_consequence_after",
|
||||||
|
"fieldtype": "Int",
|
||||||
|
"label": "Early Exit Consequence after"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "Half Day",
|
||||||
|
"depends_on": "eval:doc.enable_exit_grace_period && doc.enable_different_consequence_for_early_exit",
|
||||||
|
"fieldname": "early_exit_consequence",
|
||||||
|
"fieldtype": "Select",
|
||||||
|
"label": "Early Exit Consequence",
|
||||||
|
"options": "Half Day\nAbsent"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "60",
|
||||||
|
"description": "Time after the end of shift during which check-out is considered for attendance.",
|
||||||
|
"fieldname": "allow_check_out_after_shift_end_time",
|
||||||
|
"fieldtype": "Int",
|
||||||
|
"label": "Allow check-out after shift end time (in minutes)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"depends_on": "enable_auto_attendance",
|
||||||
|
"fieldname": "auto_attendance_settings_section",
|
||||||
|
"fieldtype": "Section Break",
|
||||||
|
"label": "Auto Attendance Settings"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"depends_on": "enable_auto_attendance",
|
||||||
|
"fieldname": "grace_period_settings_auto_attendance_section",
|
||||||
|
"fieldtype": "Section Break",
|
||||||
|
"hidden": 1,
|
||||||
|
"label": "Grace Period Settings For Auto Attendance"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"default": "0",
|
||||||
|
"description": "Mark attendance based on 'Employee Checkin' for Employees assigned to this shift.",
|
||||||
|
"fieldname": "enable_auto_attendance",
|
||||||
|
"fieldtype": "Check",
|
||||||
|
"label": "Enable Auto Attendance"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Attendance will be marked automatically only after this date.",
|
||||||
|
"fieldname": "process_attendance_after",
|
||||||
|
"fieldtype": "Date",
|
||||||
|
"label": "Process Attendance After"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Last Known Successful Sync of Employee Checkin. Reset this only if you are sure that all Logs are synced from all the locations. Please don't modify this if you are unsure.",
|
||||||
|
"fieldname": "last_sync_of_checkin",
|
||||||
|
"fieldtype": "Datetime",
|
||||||
|
"label": "Last Sync of Checkin"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"has_web_view": 0,
|
"modified": "2019-06-10 06:02:44.272036",
|
||||||
"hide_heading": 0,
|
"modified_by": "Administrator",
|
||||||
"hide_toolbar": 0,
|
"module": "HR",
|
||||||
"idx": 0,
|
"name": "Shift Type",
|
||||||
"image_view": 0,
|
"owner": "Administrator",
|
||||||
"in_create": 0,
|
|
||||||
"is_submittable": 0,
|
|
||||||
"issingle": 0,
|
|
||||||
"istable": 0,
|
|
||||||
"max_attachments": 0,
|
|
||||||
"modified": "2018-04-13 17:48:00.309273",
|
|
||||||
"modified_by": "Administrator",
|
|
||||||
"module": "HR",
|
|
||||||
"name": "Shift Type",
|
|
||||||
"name_case": "",
|
|
||||||
"owner": "Administrator",
|
|
||||||
"permissions": [
|
"permissions": [
|
||||||
{
|
{
|
||||||
"amend": 0,
|
"create": 1,
|
||||||
"cancel": 0,
|
"delete": 1,
|
||||||
"create": 1,
|
"email": 1,
|
||||||
"delete": 1,
|
"export": 1,
|
||||||
"email": 1,
|
"print": 1,
|
||||||
"export": 1,
|
"read": 1,
|
||||||
"if_owner": 0,
|
"report": 1,
|
||||||
"import": 0,
|
"role": "HR Manager",
|
||||||
"permlevel": 0,
|
"share": 1,
|
||||||
"print": 1,
|
|
||||||
"read": 1,
|
|
||||||
"report": 1,
|
|
||||||
"role": "HR Manager",
|
|
||||||
"set_user_permissions": 0,
|
|
||||||
"share": 1,
|
|
||||||
"submit": 0,
|
|
||||||
"write": 1
|
"write": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"amend": 0,
|
"email": 1,
|
||||||
"cancel": 0,
|
"export": 1,
|
||||||
"create": 0,
|
"print": 1,
|
||||||
"delete": 0,
|
"read": 1,
|
||||||
"email": 1,
|
"report": 1,
|
||||||
"export": 1,
|
"role": "Employee",
|
||||||
"if_owner": 0,
|
"share": 1
|
||||||
"import": 0,
|
},
|
||||||
"permlevel": 0,
|
|
||||||
"print": 1,
|
|
||||||
"read": 1,
|
|
||||||
"report": 1,
|
|
||||||
"role": "Employee",
|
|
||||||
"set_user_permissions": 0,
|
|
||||||
"share": 1,
|
|
||||||
"submit": 0,
|
|
||||||
"write": 0
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"amend": 0,
|
"create": 1,
|
||||||
"cancel": 0,
|
"email": 1,
|
||||||
"create": 1,
|
"export": 1,
|
||||||
"delete": 0,
|
"print": 1,
|
||||||
"email": 1,
|
"read": 1,
|
||||||
"export": 1,
|
"report": 1,
|
||||||
"if_owner": 0,
|
"role": "HR User",
|
||||||
"import": 0,
|
"share": 1,
|
||||||
"permlevel": 0,
|
|
||||||
"print": 1,
|
|
||||||
"read": 1,
|
|
||||||
"report": 1,
|
|
||||||
"role": "HR User",
|
|
||||||
"set_user_permissions": 0,
|
|
||||||
"share": 1,
|
|
||||||
"submit": 0,
|
|
||||||
"write": 1
|
"write": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"quick_entry": 1,
|
"quick_entry": 1,
|
||||||
"read_only": 0,
|
"sort_field": "modified",
|
||||||
"read_only_onload": 0,
|
"sort_order": "DESC",
|
||||||
"show_name_in_global_search": 0,
|
"track_changes": 1
|
||||||
"sort_field": "modified",
|
|
||||||
"sort_order": "DESC",
|
|
||||||
"track_changes": 1,
|
|
||||||
"track_seen": 0
|
|
||||||
}
|
}
|
@ -3,8 +3,116 @@
|
|||||||
# For license information, please see license.txt
|
# For license information, please see license.txt
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
import itertools
|
||||||
|
from datetime import timedelta
|
||||||
|
|
||||||
import frappe
|
import frappe
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
|
from frappe.utils import cint, getdate, get_datetime
|
||||||
|
from erpnext.hr.doctype.shift_assignment.shift_assignment import get_actual_start_end_datetime_of_shift, get_employee_shift
|
||||||
|
from erpnext.hr.doctype.employee_checkin.employee_checkin import mark_attendance_and_link_log, calculate_working_hours
|
||||||
|
from erpnext.hr.doctype.attendance.attendance import mark_absent
|
||||||
|
from erpnext.hr.doctype.employee.employee import get_holiday_list_for_employee
|
||||||
|
|
||||||
class ShiftType(Document):
|
class ShiftType(Document):
|
||||||
pass
|
def process_auto_attendance(self):
|
||||||
|
if not cint(self.enable_auto_attendance) or not self.process_attendance_after or not self.last_sync_of_checkin:
|
||||||
|
return
|
||||||
|
filters = {
|
||||||
|
'skip_auto_attendance':'0',
|
||||||
|
'attendance':('is', 'not set'),
|
||||||
|
'time':('>=', self.process_attendance_after),
|
||||||
|
'shift_actual_start': ('<', self.last_sync_of_checkin),
|
||||||
|
'shift': self.name
|
||||||
|
}
|
||||||
|
logs = frappe.db.get_list('Employee Checkin', fields="*", filters=filters, order_by="employee,time")
|
||||||
|
for key, group in itertools.groupby(logs, key=lambda x: (x['employee'], x['shift_actual_start'])):
|
||||||
|
single_shift_logs = list(group)
|
||||||
|
attendance_status, working_hours = self.get_attendance(single_shift_logs)
|
||||||
|
mark_attendance_and_link_log(single_shift_logs, attendance_status, key[1].date(), working_hours, self.name)
|
||||||
|
for employee in self.get_assigned_employee(self.process_attendance_after, True):
|
||||||
|
self.mark_absent_for_dates_with_no_attendance(employee)
|
||||||
|
|
||||||
|
def get_attendance(self, logs):
|
||||||
|
"""Return attendance_status, working_hours for a set of logs belonging to a single shift.
|
||||||
|
Assumtion:
|
||||||
|
1. These logs belongs to an single shift, single employee and is not in a holiday date.
|
||||||
|
2. Logs are in chronological order
|
||||||
|
"""
|
||||||
|
total_working_hours = calculate_working_hours(logs, self.determine_check_in_and_check_out, self.working_hours_calculation_based_on)
|
||||||
|
if self.working_hours_threshold_for_absent and total_working_hours < self.working_hours_threshold_for_absent:
|
||||||
|
return 'Absent', total_working_hours
|
||||||
|
if self.working_hours_threshold_for_half_day and total_working_hours < self.working_hours_threshold_for_half_day:
|
||||||
|
return 'Half Day', total_working_hours
|
||||||
|
return 'Present', total_working_hours
|
||||||
|
|
||||||
|
def mark_absent_for_dates_with_no_attendance(self, employee):
|
||||||
|
"""Marks Absents for the given employee on working days in this shift which have no attendance marked.
|
||||||
|
The Absent is marked starting from 'process_attendance_after' or employee creation date.
|
||||||
|
"""
|
||||||
|
date_of_joining, relieving_date, employee_creation = frappe.db.get_value("Employee", employee, ["date_of_joining", "relieving_date", "creation"])
|
||||||
|
if not date_of_joining:
|
||||||
|
date_of_joining = employee_creation.date()
|
||||||
|
start_date = max(getdate(self.process_attendance_after), date_of_joining)
|
||||||
|
actual_shift_datetime = get_actual_start_end_datetime_of_shift(employee, get_datetime(self.last_sync_of_checkin), True)
|
||||||
|
last_shift_time = actual_shift_datetime[0] if actual_shift_datetime[0] else get_datetime(self.last_sync_of_checkin)
|
||||||
|
prev_shift = get_employee_shift(employee, last_shift_time.date()-timedelta(days=1), True, 'reverse')
|
||||||
|
if prev_shift:
|
||||||
|
end_date = min(prev_shift.start_datetime.date(), relieving_date) if relieving_date else prev_shift.start_datetime.date()
|
||||||
|
else:
|
||||||
|
return
|
||||||
|
holiday_list_name = self.holiday_list
|
||||||
|
if not holiday_list_name:
|
||||||
|
holiday_list_name = get_holiday_list_for_employee(employee, False)
|
||||||
|
dates = get_filtered_date_list(employee, start_date, end_date, holiday_list=holiday_list_name)
|
||||||
|
for date in dates:
|
||||||
|
shift_details = get_employee_shift(employee, date, True)
|
||||||
|
if shift_details and shift_details.shift_type.name == self.name:
|
||||||
|
mark_absent(employee, date, self.name)
|
||||||
|
|
||||||
|
def get_assigned_employee(self, from_date=None, consider_default_shift=False):
|
||||||
|
filters = {'date':('>=', from_date), 'shift_type': self.name, 'docstatus': '1'}
|
||||||
|
if not from_date:
|
||||||
|
del filters['date']
|
||||||
|
assigned_employees = frappe.get_all('Shift Assignment', 'employee', filters, as_list=True)
|
||||||
|
assigned_employees = [x[0] for x in assigned_employees]
|
||||||
|
|
||||||
|
if consider_default_shift:
|
||||||
|
filters = {'default_shift': self.name}
|
||||||
|
default_shift_employees = frappe.get_all('Employee', 'name', filters, as_list=True)
|
||||||
|
default_shift_employees = [x[0] for x in default_shift_employees]
|
||||||
|
return list(set(assigned_employees+default_shift_employees))
|
||||||
|
return assigned_employees
|
||||||
|
|
||||||
|
def process_auto_attendance_for_all_shifts():
|
||||||
|
shift_list = frappe.get_all('Shift Type', 'name', {'enable_auto_attendance':'1'}, as_list=True)
|
||||||
|
for shift in shift_list:
|
||||||
|
doc = frappe.get_doc('Shift Type', shift[0])
|
||||||
|
doc.process_auto_attendance()
|
||||||
|
|
||||||
|
def get_filtered_date_list(employee, start_date, end_date, filter_attendance=True, holiday_list=None):
|
||||||
|
"""Returns a list of dates after removing the dates with attendance and holidays
|
||||||
|
"""
|
||||||
|
base_dates_query = """select adddate(%(start_date)s, t2.i*100 + t1.i*10 + t0.i) selected_date from
|
||||||
|
(select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t0,
|
||||||
|
(select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t1,
|
||||||
|
(select 0 i union select 1 union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9) t2"""
|
||||||
|
condition_query = ''
|
||||||
|
if filter_attendance:
|
||||||
|
condition_query += """ and a.selected_date not in (
|
||||||
|
select attendance_date from `tabAttendance`
|
||||||
|
where docstatus = '1' and employee = %(employee)s
|
||||||
|
and attendance_date between %(start_date)s and %(end_date)s)"""
|
||||||
|
if holiday_list:
|
||||||
|
condition_query += """ and a.selected_date not in (
|
||||||
|
select holiday_date from `tabHoliday` where parenttype = 'Holiday List' and
|
||||||
|
parentfield = 'holidays' and parent = %(holiday_list)s
|
||||||
|
and holiday_date between %(start_date)s and %(end_date)s)"""
|
||||||
|
|
||||||
|
dates = frappe.db.sql("""select * from
|
||||||
|
({base_dates_query}) as a
|
||||||
|
where a.selected_date <= %(end_date)s {condition_query}
|
||||||
|
""".format(base_dates_query=base_dates_query, condition_query=condition_query),
|
||||||
|
{"employee":employee, "start_date":start_date, "end_date":end_date, "holiday_list":holiday_list}, as_list=True)
|
||||||
|
|
||||||
|
return [getdate(date[0]) for date in dates]
|
||||||
|
@ -2,11 +2,15 @@ from __future__ import unicode_literals
|
|||||||
from frappe import _
|
from frappe import _
|
||||||
|
|
||||||
def get_data():
|
def get_data():
|
||||||
return {
|
return {
|
||||||
'fieldname': 'shift_type',
|
'fieldname': 'shift',
|
||||||
'transactions': [
|
'non_standard_fieldnames': {
|
||||||
{
|
'Shift Request': 'shift_type',
|
||||||
'items': ['Shift Request', 'Shift Assignment']
|
'Shift Assignment': 'shift_type'
|
||||||
}
|
},
|
||||||
],
|
'transactions': [
|
||||||
}
|
{
|
||||||
|
'items': ['Attendance', 'Employee Checkin', 'Shift Request', 'Shift Assignment']
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
@ -18,11 +18,11 @@ class VehicleLog(Document):
|
|||||||
if (service_detail.service_item or service_detail.type or service_detail.frequency or service_detail.expense_amount):
|
if (service_detail.service_item or service_detail.type or service_detail.frequency or service_detail.expense_amount):
|
||||||
if not (service_detail.service_item and service_detail.type and service_detail.frequency and service_detail.expense_amount):
|
if not (service_detail.service_item and service_detail.type and service_detail.frequency and service_detail.expense_amount):
|
||||||
frappe.throw(_("Service Item,Type,frequency and expense amount are required"))
|
frappe.throw(_("Service Item,Type,frequency and expense amount are required"))
|
||||||
|
|
||||||
def on_submit(self):
|
def on_submit(self):
|
||||||
frappe.db.sql("update `tabVehicle` set last_odometer=%s where license_plate=%s",
|
frappe.db.sql("update `tabVehicle` set last_odometer=%s where license_plate=%s",
|
||||||
(self.odometer, self.license_plate))
|
(self.odometer, self.license_plate))
|
||||||
|
|
||||||
@frappe.whitelist()
|
@frappe.whitelist()
|
||||||
def get_make_model(license_plate):
|
def get_make_model(license_plate):
|
||||||
vehicle=frappe.get_doc("Vehicle",license_plate)
|
vehicle=frappe.get_doc("Vehicle",license_plate)
|
||||||
@ -41,7 +41,7 @@ def make_expense_claim(docname):
|
|||||||
for serdetail in vehicle_log.service_detail:
|
for serdetail in vehicle_log.service_detail:
|
||||||
total_exp_amt = total_exp_amt + serdetail.expense_amount
|
total_exp_amt = total_exp_amt + serdetail.expense_amount
|
||||||
return total_exp_amt
|
return total_exp_amt
|
||||||
|
|
||||||
vehicle_log = frappe.get_doc("Vehicle Log", docname)
|
vehicle_log = frappe.get_doc("Vehicle Log", docname)
|
||||||
exp_claim = frappe.new_doc("Expense Claim")
|
exp_claim = frappe.new_doc("Expense Claim")
|
||||||
exp_claim.employee=vehicle_log.employee
|
exp_claim.employee=vehicle_log.employee
|
||||||
@ -52,6 +52,6 @@ def make_expense_claim(docname):
|
|||||||
exp_claim.append("expenses",{
|
exp_claim.append("expenses",{
|
||||||
"expense_date":vehicle_log.date,
|
"expense_date":vehicle_log.date,
|
||||||
"description":_("Vehicle Expenses"),
|
"description":_("Vehicle Expenses"),
|
||||||
"claim_amount":total_claim_amt
|
"amount":total_claim_amt
|
||||||
})
|
})
|
||||||
return exp_claim.as_dict()
|
return exp_claim.as_dict()
|
||||||
|
@ -5,7 +5,7 @@ from __future__ import unicode_literals
|
|||||||
import frappe
|
import frappe
|
||||||
from frappe import _
|
from frappe import _
|
||||||
from erpnext.hr.doctype.leave_application.leave_application \
|
from erpnext.hr.doctype.leave_application.leave_application \
|
||||||
import get_leave_allocation_records, get_leave_balance_on, get_approved_leaves_for_period, get_total_allocated_leaves
|
import get_leave_allocation_records, get_leave_balance_on, get_approved_leaves_for_period
|
||||||
|
|
||||||
|
|
||||||
def execute(filters=None):
|
def execute(filters=None):
|
||||||
@ -35,6 +35,9 @@ def get_data(filters, leave_types):
|
|||||||
allocation_records_based_on_to_date = get_leave_allocation_records(filters.to_date)
|
allocation_records_based_on_to_date = get_leave_allocation_records(filters.to_date)
|
||||||
allocation_records_based_on_from_date = get_leave_allocation_records(filters.from_date)
|
allocation_records_based_on_from_date = get_leave_allocation_records(filters.from_date)
|
||||||
|
|
||||||
|
if filters.to_date <= filters.from_date:
|
||||||
|
frappe.throw(_("From date can not be greater than than To date"))
|
||||||
|
|
||||||
active_employees = frappe.get_all("Employee",
|
active_employees = frappe.get_all("Employee",
|
||||||
filters = { "status": "Active", "company": filters.company},
|
filters = { "status": "Active", "company": filters.company},
|
||||||
fields = ["name", "employee_name", "department", "user_id"])
|
fields = ["name", "employee_name", "department", "user_id"])
|
||||||
@ -51,7 +54,8 @@ def get_data(filters, leave_types):
|
|||||||
filters.from_date, filters.to_date)
|
filters.from_date, filters.to_date)
|
||||||
|
|
||||||
# opening balance
|
# opening balance
|
||||||
opening = get_total_allocated_leaves(employee.name, leave_type, filters.to_date)
|
opening = get_leave_balance_on(employee.name, leave_type, filters.from_date,
|
||||||
|
allocation_records_based_on_to_date.get(employee.name, frappe._dict()))
|
||||||
|
|
||||||
# closing balance
|
# closing balance
|
||||||
closing = get_leave_balance_on(employee.name, leave_type, filters.to_date,
|
closing = get_leave_balance_on(employee.name, leave_type, filters.to_date,
|
||||||
|
@ -35,5 +35,13 @@ frappe.ui.form.on('Blanket Order', {
|
|||||||
|
|
||||||
onload_post_render: function(frm) {
|
onload_post_render: function(frm) {
|
||||||
frm.get_field("items").grid.set_multiple_add("item_code", "qty");
|
frm.get_field("items").grid.set_multiple_add("item_code", "qty");
|
||||||
}
|
},
|
||||||
|
|
||||||
|
tc_name: function (frm) {
|
||||||
|
erpnext.utils.get_terms(frm.doc.tc_name, frm.doc, function (r) {
|
||||||
|
if (!r.exc) {
|
||||||
|
frm.set_value("terms", r.message);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
@ -1,493 +1,157 @@
|
|||||||
{
|
{
|
||||||
"allow_copy": 0,
|
"autoname": "naming_series:",
|
||||||
"allow_guest_to_view": 0,
|
"creation": "2018-05-24 07:18:08.256060",
|
||||||
"allow_import": 0,
|
"doctype": "DocType",
|
||||||
"allow_rename": 0,
|
"editable_grid": 1,
|
||||||
"autoname": "naming_series:",
|
"engine": "InnoDB",
|
||||||
"beta": 0,
|
"field_order": [
|
||||||
"creation": "2018-05-24 07:18:08.256060",
|
"naming_series",
|
||||||
"custom": 0,
|
"blanket_order_type",
|
||||||
"docstatus": 0,
|
"customer",
|
||||||
"doctype": "DocType",
|
"customer_name",
|
||||||
"document_type": "",
|
"supplier",
|
||||||
"editable_grid": 1,
|
"supplier_name",
|
||||||
"engine": "InnoDB",
|
"column_break_8",
|
||||||
|
"from_date",
|
||||||
|
"to_date",
|
||||||
|
"company",
|
||||||
|
"section_break_12",
|
||||||
|
"items",
|
||||||
|
"amended_from",
|
||||||
|
"terms_and_conditions_section",
|
||||||
|
"tc_name",
|
||||||
|
"terms"
|
||||||
|
],
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"fieldname": "naming_series",
|
||||||
"allow_in_quick_entry": 0,
|
"fieldtype": "Select",
|
||||||
"allow_on_submit": 0,
|
"label": "Series",
|
||||||
"bold": 0,
|
"options": "MFG-BLR-.YYYY.-",
|
||||||
"collapsible": 0,
|
"reqd": 1
|
||||||
"columns": 0,
|
},
|
||||||
"default": "",
|
|
||||||
"fieldname": "naming_series",
|
|
||||||
"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": "Series",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "MFG-BLR-.YYYY.-",
|
|
||||||
"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,
|
"fieldname": "blanket_order_type",
|
||||||
"allow_in_quick_entry": 0,
|
"fieldtype": "Select",
|
||||||
"allow_on_submit": 0,
|
"in_list_view": 1,
|
||||||
"bold": 0,
|
"label": "Order Type",
|
||||||
"collapsible": 0,
|
"options": "\nSelling\nPurchasing",
|
||||||
"columns": 0,
|
"reqd": 1
|
||||||
"fieldname": "blanket_order_type",
|
},
|
||||||
"fieldtype": "Select",
|
|
||||||
"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": "Order Type",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "\nSelling\nPurchasing",
|
|
||||||
"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,
|
"depends_on": "eval:doc.blanket_order_type == \"Selling\"",
|
||||||
"allow_in_quick_entry": 0,
|
"fieldname": "customer",
|
||||||
"allow_on_submit": 0,
|
"fieldtype": "Link",
|
||||||
"bold": 0,
|
"label": "Customer",
|
||||||
"collapsible": 0,
|
"options": "Customer"
|
||||||
"columns": 0,
|
},
|
||||||
"depends_on": "eval:doc.blanket_order_type == \"Selling\"",
|
|
||||||
"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,
|
|
||||||
"options": "Customer",
|
|
||||||
"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,
|
"depends_on": "eval:doc.blanket_order_type == \"Selling\"",
|
||||||
"allow_in_quick_entry": 0,
|
"fetch_from": "customer.customer_name",
|
||||||
"allow_on_submit": 0,
|
"fieldname": "customer_name",
|
||||||
"bold": 0,
|
"fieldtype": "Data",
|
||||||
"collapsible": 0,
|
"label": "Customer Name",
|
||||||
"columns": 0,
|
"read_only": 1
|
||||||
"depends_on": "eval:doc.blanket_order_type == \"Selling\"",
|
},
|
||||||
"fetch_from": "customer.customer_name",
|
|
||||||
"fieldname": "customer_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": "Customer Name",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "",
|
|
||||||
"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,
|
"depends_on": "eval:doc.blanket_order_type == \"Purchasing\"",
|
||||||
"allow_in_quick_entry": 0,
|
"fieldname": "supplier",
|
||||||
"allow_on_submit": 0,
|
"fieldtype": "Link",
|
||||||
"bold": 0,
|
"label": "Supplier",
|
||||||
"collapsible": 0,
|
"options": "Supplier"
|
||||||
"columns": 0,
|
},
|
||||||
"depends_on": "eval:doc.blanket_order_type == \"Purchasing\"",
|
|
||||||
"fieldname": "supplier",
|
|
||||||
"fieldtype": "Link",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Supplier",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Supplier",
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"depends_on": "eval:doc.blanket_order_type == \"Purchasing\"",
|
||||||
"allow_in_quick_entry": 0,
|
"fetch_from": "supplier.supplier_name",
|
||||||
"allow_on_submit": 0,
|
"fieldname": "supplier_name",
|
||||||
"bold": 0,
|
"fieldtype": "Data",
|
||||||
"collapsible": 0,
|
"label": "Supplier Name",
|
||||||
"columns": 0,
|
"read_only": 1
|
||||||
"depends_on": "eval:doc.blanket_order_type == \"Purchasing\"",
|
},
|
||||||
"fetch_from": "supplier.supplier_name",
|
|
||||||
"fieldname": "supplier_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": "Supplier Name",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "",
|
|
||||||
"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,
|
"fieldname": "column_break_8",
|
||||||
"allow_in_quick_entry": 0,
|
"fieldtype": "Column Break"
|
||||||
"allow_on_submit": 0,
|
},
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "column_break_8",
|
|
||||||
"fieldtype": "Column Break",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"fieldname": "from_date",
|
||||||
"allow_in_quick_entry": 0,
|
"fieldtype": "Date",
|
||||||
"allow_on_submit": 0,
|
"label": "From Date",
|
||||||
"bold": 0,
|
"reqd": 1
|
||||||
"collapsible": 0,
|
},
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "from_date",
|
|
||||||
"fieldtype": "Date",
|
|
||||||
"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": "From Date",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 1,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"fieldname": "to_date",
|
||||||
"allow_in_quick_entry": 0,
|
"fieldtype": "Date",
|
||||||
"allow_on_submit": 0,
|
"label": "To Date",
|
||||||
"bold": 0,
|
"reqd": 1
|
||||||
"collapsible": 0,
|
},
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "to_date",
|
|
||||||
"fieldtype": "Date",
|
|
||||||
"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": "To Date",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 1,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"fieldname": "company",
|
||||||
"allow_in_quick_entry": 0,
|
"fieldtype": "Link",
|
||||||
"allow_on_submit": 0,
|
"label": "Company",
|
||||||
"bold": 0,
|
"options": "Company"
|
||||||
"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": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Company",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Company",
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"fieldname": "section_break_12",
|
||||||
"allow_in_quick_entry": 0,
|
"fieldtype": "Section Break"
|
||||||
"allow_on_submit": 0,
|
},
|
||||||
"bold": 0,
|
|
||||||
"collapsible": 0,
|
|
||||||
"columns": 0,
|
|
||||||
"fieldname": "section_break_12",
|
|
||||||
"fieldtype": "Section Break",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"permlevel": 0,
|
|
||||||
"precision": "",
|
|
||||||
"print_hide": 0,
|
|
||||||
"print_hide_if_no_value": 0,
|
|
||||||
"read_only": 0,
|
|
||||||
"remember_last_selected_value": 0,
|
|
||||||
"report_hide": 0,
|
|
||||||
"reqd": 0,
|
|
||||||
"search_index": 0,
|
|
||||||
"set_only_once": 0,
|
|
||||||
"translatable": 0,
|
|
||||||
"unique": 0
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"allow_bulk_edit": 0,
|
"fieldname": "items",
|
||||||
"allow_in_quick_entry": 0,
|
"fieldtype": "Table",
|
||||||
"allow_on_submit": 0,
|
"label": "Item",
|
||||||
"bold": 0,
|
"options": "Blanket Order Item",
|
||||||
"collapsible": 0,
|
"reqd": 1
|
||||||
"columns": 0,
|
},
|
||||||
"fieldname": "items",
|
|
||||||
"fieldtype": "Table",
|
|
||||||
"hidden": 0,
|
|
||||||
"ignore_user_permissions": 0,
|
|
||||||
"ignore_xss_filter": 0,
|
|
||||||
"in_filter": 0,
|
|
||||||
"in_global_search": 0,
|
|
||||||
"in_list_view": 0,
|
|
||||||
"in_standard_filter": 0,
|
|
||||||
"label": "Item",
|
|
||||||
"length": 0,
|
|
||||||
"no_copy": 0,
|
|
||||||
"options": "Blanket Order Item",
|
|
||||||
"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,
|
"fieldname": "amended_from",
|
||||||
"allow_in_quick_entry": 0,
|
"fieldtype": "Link",
|
||||||
"allow_on_submit": 0,
|
"label": "Amended From",
|
||||||
"bold": 0,
|
"no_copy": 1,
|
||||||
"collapsible": 0,
|
"options": "Blanket Order",
|
||||||
"columns": 0,
|
"print_hide": 1,
|
||||||
"fieldname": "amended_from",
|
"read_only": 1
|
||||||
"fieldtype": "Link",
|
},
|
||||||
"hidden": 0,
|
{
|
||||||
"ignore_user_permissions": 0,
|
"fieldname": "terms_and_conditions_section",
|
||||||
"ignore_xss_filter": 0,
|
"fieldtype": "Section Break",
|
||||||
"in_filter": 0,
|
"label": "Terms and Conditions"
|
||||||
"in_global_search": 0,
|
},
|
||||||
"in_list_view": 0,
|
{
|
||||||
"in_standard_filter": 0,
|
"fieldname": "tc_name",
|
||||||
"label": "Amended From",
|
"fieldtype": "Link",
|
||||||
"length": 0,
|
"label": "Terms",
|
||||||
"no_copy": 1,
|
"options": "Terms and Conditions"
|
||||||
"options": "Blanket Order",
|
},
|
||||||
"permlevel": 0,
|
{
|
||||||
"print_hide": 1,
|
"fieldname": "terms",
|
||||||
"print_hide_if_no_value": 0,
|
"fieldtype": "Text Editor",
|
||||||
"read_only": 1,
|
"label": "Terms and Conditions Details"
|
||||||
"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,
|
"is_submittable": 1,
|
||||||
"hide_heading": 0,
|
"modified": "2019-06-19 11:59:09.279607",
|
||||||
"hide_toolbar": 0,
|
"modified_by": "Administrator",
|
||||||
"idx": 0,
|
"module": "Manufacturing",
|
||||||
"image_view": 0,
|
"name": "Blanket Order",
|
||||||
"in_create": 0,
|
"owner": "Administrator",
|
||||||
"is_submittable": 1,
|
|
||||||
"issingle": 0,
|
|
||||||
"istable": 0,
|
|
||||||
"max_attachments": 0,
|
|
||||||
"modified": "2018-08-21 14:44:28.347534",
|
|
||||||
"modified_by": "Administrator",
|
|
||||||
"module": "Manufacturing",
|
|
||||||
"name": "Blanket Order",
|
|
||||||
"name_case": "",
|
|
||||||
"owner": "Administrator",
|
|
||||||
"permissions": [
|
"permissions": [
|
||||||
{
|
{
|
||||||
"amend": 0,
|
"cancel": 1,
|
||||||
"cancel": 1,
|
"create": 1,
|
||||||
"create": 1,
|
"delete": 1,
|
||||||
"delete": 1,
|
"email": 1,
|
||||||
"email": 1,
|
"export": 1,
|
||||||
"export": 1,
|
"print": 1,
|
||||||
"if_owner": 0,
|
"read": 1,
|
||||||
"import": 0,
|
"report": 1,
|
||||||
"permlevel": 0,
|
"role": "System Manager",
|
||||||
"print": 1,
|
"share": 1,
|
||||||
"read": 1,
|
"submit": 1,
|
||||||
"report": 1,
|
|
||||||
"role": "System Manager",
|
|
||||||
"set_user_permissions": 0,
|
|
||||||
"share": 1,
|
|
||||||
"submit": 1,
|
|
||||||
"write": 1
|
"write": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"quick_entry": 1,
|
"quick_entry": 1,
|
||||||
"read_only": 0,
|
"search_fields": "blanket_order_type, to_date",
|
||||||
"read_only_onload": 0,
|
"sort_field": "modified",
|
||||||
"search_fields": "blanket_order_type, to_date",
|
"sort_order": "DESC",
|
||||||
"show_name_in_global_search": 0,
|
"track_changes": 1
|
||||||
"sort_field": "modified",
|
|
||||||
"sort_order": "DESC",
|
|
||||||
"track_changes": 1,
|
|
||||||
"track_seen": 0,
|
|
||||||
"track_views": 0
|
|
||||||
}
|
}
|
@ -381,7 +381,7 @@ class BOM(WebsiteGenerator):
|
|||||||
|
|
||||||
frappe.throw(_("Same item has been entered multiple times. {0}").format(duplicate_list))
|
frappe.throw(_("Same item has been entered multiple times. {0}").format(duplicate_list))
|
||||||
|
|
||||||
def check_recursion(self):
|
def check_recursion(self, bom_list=[]):
|
||||||
""" Check whether recursion occurs in any bom"""
|
""" Check whether recursion occurs in any bom"""
|
||||||
bom_list = self.traverse_tree()
|
bom_list = self.traverse_tree()
|
||||||
bom_nos = frappe.get_all('BOM Item', fields=["bom_no"],
|
bom_nos = frappe.get_all('BOM Item', fields=["bom_no"],
|
||||||
@ -399,21 +399,21 @@ class BOM(WebsiteGenerator):
|
|||||||
raise_exception = True
|
raise_exception = True
|
||||||
|
|
||||||
if raise_exception:
|
if raise_exception:
|
||||||
frappe.throw(_("BOM recursion: {0} cannot be parent or child of {2}").format(self.name, self.name))
|
frappe.throw(_("BOM recursion: {0} cannot be parent or child of {1}").format(self.name, self.name))
|
||||||
|
|
||||||
def update_cost_and_exploded_items(self, bom_list=[]):
|
def update_cost_and_exploded_items(self, bom_list=[]):
|
||||||
bom_list = self.traverse_tree(bom_list)
|
bom_list = self.traverse_tree(bom_list)
|
||||||
for bom in bom_list:
|
for bom in bom_list:
|
||||||
bom_obj = frappe.get_doc("BOM", bom)
|
bom_obj = frappe.get_doc("BOM", bom)
|
||||||
bom_obj.check_recursion()
|
bom_obj.check_recursion(bom_list=bom_list)
|
||||||
bom_obj.update_exploded_items()
|
bom_obj.update_exploded_items()
|
||||||
|
|
||||||
return bom_list
|
return bom_list
|
||||||
|
|
||||||
def traverse_tree(self, bom_list=None):
|
def traverse_tree(self, bom_list=None):
|
||||||
def _get_children(bom_no):
|
def _get_children(bom_no):
|
||||||
return [cstr(d[0]) for d in frappe.db.sql("""select bom_no from `tabBOM Item`
|
return frappe.db.sql_list("""select bom_no from `tabBOM Item`
|
||||||
where parent = %s and ifnull(bom_no, '') != '' and parenttype='BOM'""", bom_no)]
|
where parent = %s and ifnull(bom_no, '') != '' and parenttype='BOM'""", bom_no)
|
||||||
|
|
||||||
count = 0
|
count = 0
|
||||||
if not bom_list:
|
if not bom_list:
|
||||||
|
@ -90,7 +90,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_based_on_price_list(self):
|
def test_bom_cost_multi_uom_multi_currency_based_on_price_list(self):
|
||||||
frappe.db.set_value("Price List", "_Test Price List", "price_not_uom_dependant", 1)
|
frappe.db.set_value("Price List", "_Test Price List", "price_not_uom_dependent", 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)
|
||||||
|
@ -55,7 +55,7 @@ class BOMUpdateTool(Document):
|
|||||||
bom_list = []
|
bom_list = []
|
||||||
|
|
||||||
data = frappe.db.sql(""" select distinct parent from `tabBOM Item`
|
data = frappe.db.sql(""" select distinct parent from `tabBOM Item`
|
||||||
where ifnull(bom_no, '') = %s and docstatus < 2 and parenttype='BOM'""", bom)
|
where bom_no = %s and docstatus < 2 and parenttype='BOM'""", bom)
|
||||||
|
|
||||||
for d in data:
|
for d in data:
|
||||||
bom_list.append(d[0])
|
bom_list.append(d[0])
|
||||||
|
@ -126,6 +126,20 @@ frappe.ui.form.on('Production Plan', {
|
|||||||
},
|
},
|
||||||
|
|
||||||
make_material_request: function(frm) {
|
make_material_request: function(frm) {
|
||||||
|
|
||||||
|
frappe.confirm(__("Do you want to submit the material request"),
|
||||||
|
function() {
|
||||||
|
frm.events.create_material_request(frm, 1);
|
||||||
|
},
|
||||||
|
function() {
|
||||||
|
frm.events.create_material_request(frm, 0);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
create_material_request: function(frm, submit) {
|
||||||
|
frm.doc.submit_material_request = submit;
|
||||||
|
|
||||||
frappe.call({
|
frappe.call({
|
||||||
method: "make_material_request",
|
method: "make_material_request",
|
||||||
freeze: true,
|
freeze: true,
|
||||||
|
@ -395,7 +395,11 @@ class ProductionPlan(Document):
|
|||||||
# submit
|
# submit
|
||||||
material_request.flags.ignore_permissions = 1
|
material_request.flags.ignore_permissions = 1
|
||||||
material_request.run_method("set_missing_values")
|
material_request.run_method("set_missing_values")
|
||||||
material_request.submit()
|
|
||||||
|
if self.get('submit_material_request'):
|
||||||
|
material_request.submit()
|
||||||
|
else:
|
||||||
|
material_request.save()
|
||||||
|
|
||||||
frappe.flags.mute_messages = False
|
frappe.flags.mute_messages = False
|
||||||
|
|
||||||
|
@ -51,7 +51,8 @@ class TestProductionPlan(unittest.TestCase):
|
|||||||
|
|
||||||
for name in material_requests:
|
for name in material_requests:
|
||||||
mr = frappe.get_doc('Material Request', name[0])
|
mr = frappe.get_doc('Material Request', name[0])
|
||||||
mr.cancel()
|
if mr.docstatus != 0:
|
||||||
|
mr.cancel()
|
||||||
|
|
||||||
for name in work_orders:
|
for name in work_orders:
|
||||||
mr = frappe.delete_doc('Work Order', name[0])
|
mr = frappe.delete_doc('Work Order', name[0])
|
||||||
@ -152,7 +153,7 @@ class TestProductionPlan(unittest.TestCase):
|
|||||||
make_bom(item = item, raw_materials = raw_materials)
|
make_bom(item = item, raw_materials = raw_materials)
|
||||||
production_plan = create_production_plan(item_code = 'Production Item CUST')
|
production_plan = create_production_plan(item_code = 'Production Item CUST')
|
||||||
production_plan.make_material_request()
|
production_plan.make_material_request()
|
||||||
material_request = frappe.get_value('Material Request Item', {'production_plan': production_plan.name}, 'parent')
|
material_request = frappe.db.get_value('Material Request Item', {'production_plan': production_plan.name, 'item_code': 'CUST-0987'}, 'parent')
|
||||||
mr = frappe.get_doc('Material Request', material_request)
|
mr = frappe.get_doc('Material Request', material_request)
|
||||||
self.assertTrue(mr.material_request_type, 'Customer Provided')
|
self.assertTrue(mr.material_request_type, 'Customer Provided')
|
||||||
self.assertTrue(mr.customer, '_Test Customer')
|
self.assertTrue(mr.customer, '_Test Customer')
|
||||||
|
@ -594,7 +594,7 @@ erpnext.patches.v11_1.make_job_card_time_logs
|
|||||||
erpnext.patches.v12_0.rename_pricing_rule_child_doctypes
|
erpnext.patches.v12_0.rename_pricing_rule_child_doctypes
|
||||||
erpnext.patches.v12_0.move_target_distribution_from_parent_to_child
|
erpnext.patches.v12_0.move_target_distribution_from_parent_to_child
|
||||||
erpnext.patches.v12_0.stock_entry_enhancements
|
erpnext.patches.v12_0.stock_entry_enhancements
|
||||||
erpnext.patches.v10_0.item_barcode_childtable_migrate # 16-02-2019
|
erpnext.patches.v10_0.item_barcode_childtable_migrate # 16-02-2019 #25-06-2019
|
||||||
erpnext.patches.v12_0.move_item_tax_to_item_tax_template
|
erpnext.patches.v12_0.move_item_tax_to_item_tax_template
|
||||||
erpnext.patches.v11_1.set_variant_based_on
|
erpnext.patches.v11_1.set_variant_based_on
|
||||||
erpnext.patches.v11_1.woocommerce_set_creation_user
|
erpnext.patches.v11_1.woocommerce_set_creation_user
|
||||||
@ -604,4 +604,7 @@ execute:frappe.delete_doc("Report", "Inactive Items")
|
|||||||
erpnext.patches.v11_1.delete_scheduling_tool
|
erpnext.patches.v11_1.delete_scheduling_tool
|
||||||
erpnext.patches.v12_0.make_custom_fields_for_bank_remittance #14-06-2019
|
erpnext.patches.v12_0.make_custom_fields_for_bank_remittance #14-06-2019
|
||||||
execute:frappe.delete_doc_if_exists("Page", "support-analytics")
|
execute:frappe.delete_doc_if_exists("Page", "support-analytics")
|
||||||
erpnext.patches.v12_0.make_item_manufacturer
|
erpnext.patches.v12_0.make_item_manufacturer
|
||||||
|
erpnext.patches.v12_0.set_quotation_status
|
||||||
|
erpnext.patches.v12_0.set_priority_for_support
|
||||||
|
erpnext.patches.v12_0.delete_priority_property_setter
|
||||||
|
@ -8,8 +8,10 @@ import frappe
|
|||||||
|
|
||||||
def execute():
|
def execute():
|
||||||
frappe.reload_doc("stock", "doctype", "item_barcode")
|
frappe.reload_doc("stock", "doctype", "item_barcode")
|
||||||
|
if frappe.get_all("Item Barcode", limit=1): return
|
||||||
|
if "barcode" not in frappe.db.get_table_columns("Item"): return
|
||||||
|
|
||||||
items_barcode = frappe.get_all('Item', ['name', 'barcode'], { 'barcode': ('!=', '') })
|
items_barcode = frappe.db.sql("select name, barcode from tabItem where barcode is not null", as_dict=True)
|
||||||
frappe.reload_doc("stock", "doctype", "item")
|
frappe.reload_doc("stock", "doctype", "item")
|
||||||
|
|
||||||
|
|
||||||
|
9
erpnext/patches/v12_0/delete_priority_property_setter.py
Normal file
9
erpnext/patches/v12_0/delete_priority_property_setter.py
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import frappe
|
||||||
|
|
||||||
|
def execute():
|
||||||
|
frappe.db.sql("""
|
||||||
|
DELETE FROM `tabProperty Setter`
|
||||||
|
WHERE `tabProperty Setter`.doc_type='Issue'
|
||||||
|
AND `tabProperty Setter`.field_name='priority'
|
||||||
|
AND `tabProperty Setter`.property='options'
|
||||||
|
""")
|
78
erpnext/patches/v12_0/set_priority_for_support.py
Normal file
78
erpnext/patches/v12_0/set_priority_for_support.py
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
import frappe
|
||||||
|
|
||||||
|
def execute():
|
||||||
|
frappe.reload_doc("support", "doctype", "issue_priority")
|
||||||
|
frappe.reload_doc("support", "doctype", "service_level_priority")
|
||||||
|
|
||||||
|
set_issue_priority()
|
||||||
|
set_priority_for_issue()
|
||||||
|
set_priorities_service_level()
|
||||||
|
set_priorities_service_level_agreement()
|
||||||
|
|
||||||
|
def set_issue_priority():
|
||||||
|
# Adds priority from issue to Issue Priority DocType as Priority is a new DocType.
|
||||||
|
for priority in frappe.get_meta("Issue").get_field("priority").options.split("\n"):
|
||||||
|
if priority and not frappe.db.exists("Issue Priority", priority):
|
||||||
|
frappe.get_doc({
|
||||||
|
"doctype": "Issue Priority",
|
||||||
|
"name": priority
|
||||||
|
}).insert(ignore_permissions=True)
|
||||||
|
|
||||||
|
def set_priority_for_issue():
|
||||||
|
# Sets priority for Issues as Select field is changed to Link field.
|
||||||
|
issue_priority = frappe.get_list("Issue", fields=["name", "priority"])
|
||||||
|
frappe.reload_doc("support", "doctype", "issue")
|
||||||
|
|
||||||
|
for issue in issue_priority:
|
||||||
|
frappe.db.set_value("Issue", issue.name, "priority", issue.priority)
|
||||||
|
|
||||||
|
def set_priorities_service_level():
|
||||||
|
# Migrates "priority", "response_time", "response_time_period", "resolution_time", "resolution_time_period" to Child Table
|
||||||
|
# as a Service Level can have multiple priorities
|
||||||
|
try:
|
||||||
|
service_level_priorities = frappe.get_list("Service Level", fields=["name", "priority", "response_time", "response_time_period", "resolution_time", "resolution_time_period"])
|
||||||
|
|
||||||
|
frappe.reload_doc("support", "doctype", "service_level")
|
||||||
|
|
||||||
|
for service_level in service_level_priorities:
|
||||||
|
if service_level:
|
||||||
|
doc = frappe.get_doc("Service Level", service_level.name)
|
||||||
|
doc.append("priorities", {
|
||||||
|
"priority": service_level.priority,
|
||||||
|
"default_priority": 1,
|
||||||
|
"response_time": service_level.response_time,
|
||||||
|
"response_time_period": service_level.response_time_period,
|
||||||
|
"resolution_time": service_level.resolution_time,
|
||||||
|
"resolution_time_period": service_level.resolution_time_period
|
||||||
|
})
|
||||||
|
doc.save(ignore_permissions=True)
|
||||||
|
except frappe.db.TableMissingError:
|
||||||
|
frappe.reload_doc("support", "doctype", "service_level")
|
||||||
|
|
||||||
|
def set_priorities_service_level_agreement():
|
||||||
|
# Migrates "priority", "response_time", "response_time_period", "resolution_time", "resolution_time_period" to Child Table
|
||||||
|
# as a Service Level Agreement can have multiple priorities
|
||||||
|
try:
|
||||||
|
service_level_agreement_priorities = frappe.get_list("Service Level Agreement", fields=["name", "priority", "response_time", "response_time_period", "resolution_time", "resolution_time_period"])
|
||||||
|
|
||||||
|
frappe.reload_doc("support", "doctype", "service_level_agreement")
|
||||||
|
|
||||||
|
for service_level_agreement in service_level_agreement_priorities:
|
||||||
|
if service_level_agreement:
|
||||||
|
doc = frappe.get_doc("Service Level Agreement", service_level_agreement.name)
|
||||||
|
|
||||||
|
if doc.customer:
|
||||||
|
doc.entity_type = "Customer"
|
||||||
|
doc.entity = doc.customer
|
||||||
|
|
||||||
|
doc.append("priorities", {
|
||||||
|
"priority": service_level_agreement.priority,
|
||||||
|
"default_priority": 1,
|
||||||
|
"response_time": service_level_agreement.response_time,
|
||||||
|
"response_time_period": service_level_agreement.response_time_period,
|
||||||
|
"resolution_time": service_level_agreement.resolution_time,
|
||||||
|
"resolution_time_period": service_level_agreement.resolution_time_period
|
||||||
|
})
|
||||||
|
doc.save(ignore_permissions=True)
|
||||||
|
except frappe.db.TableMissingError:
|
||||||
|
frappe.reload_doc("support", "doctype", "service_level_agreement")
|
7
erpnext/patches/v12_0/set_quotation_status.py
Normal file
7
erpnext/patches/v12_0/set_quotation_status.py
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
from __future__ import unicode_literals
|
||||||
|
import frappe
|
||||||
|
|
||||||
|
def execute():
|
||||||
|
|
||||||
|
frappe.db.sql(""" UPDATE `tabQuotation` set status = 'Open'
|
||||||
|
where docstatus = 1 and status = 'Submitted' """)
|
@ -11,7 +11,7 @@ from frappe.utils import (flt, getdate, get_url, now,
|
|||||||
from erpnext.controllers.queries import get_filters_cond
|
from erpnext.controllers.queries import get_filters_cond
|
||||||
from frappe.desk.reportview import get_match_cond
|
from frappe.desk.reportview import get_match_cond
|
||||||
from erpnext.hr.doctype.daily_work_summary.daily_work_summary import get_users_email
|
from erpnext.hr.doctype.daily_work_summary.daily_work_summary import get_users_email
|
||||||
from erpnext.hr.doctype.daily_work_summary_group.daily_work_summary_group import is_holiday_today
|
from erpnext.hr.doctype.holiday_list.holiday_list import is_holiday
|
||||||
from frappe.model.document import Document
|
from frappe.model.document import Document
|
||||||
|
|
||||||
class Project(Document):
|
class Project(Document):
|
||||||
@ -530,7 +530,7 @@ def get_projects_for_collect_progress(frequency, fields):
|
|||||||
def send_project_update_email_to_users(project):
|
def send_project_update_email_to_users(project):
|
||||||
doc = frappe.get_doc('Project', project)
|
doc = frappe.get_doc('Project', project)
|
||||||
|
|
||||||
if is_holiday_today(doc.holiday_list) or not doc.users: return
|
if is_holiday(doc.holiday_list) or not doc.users: return
|
||||||
|
|
||||||
project_update = frappe.get_doc({
|
project_update = frappe.get_doc({
|
||||||
"doctype" : "Project Update",
|
"doctype" : "Project Update",
|
||||||
|
@ -103,8 +103,8 @@ class TestTimesheet(unittest.TestCase):
|
|||||||
{
|
{
|
||||||
"billable": 1,
|
"billable": 1,
|
||||||
"activity_type": "_Test Activity Type",
|
"activity_type": "_Test Activity Type",
|
||||||
"from_type": now_datetime(),
|
"from_time": now_datetime(),
|
||||||
"hours": 3,
|
"to_time": now_datetime() + datetime.timedelta(hours=3),
|
||||||
"company": "_Test Company"
|
"company": "_Test Company"
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ -113,8 +113,8 @@ class TestTimesheet(unittest.TestCase):
|
|||||||
{
|
{
|
||||||
"billable": 1,
|
"billable": 1,
|
||||||
"activity_type": "_Test Activity Type",
|
"activity_type": "_Test Activity Type",
|
||||||
"from_type": now_datetime(),
|
"from_time": now_datetime(),
|
||||||
"hours": 3,
|
"to_time": now_datetime() + datetime.timedelta(hours=3),
|
||||||
"company": "_Test Company"
|
"company": "_Test Company"
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -19,9 +19,6 @@ class OverlapError(frappe.ValidationError): pass
|
|||||||
class OverWorkLoggedError(frappe.ValidationError): pass
|
class OverWorkLoggedError(frappe.ValidationError): pass
|
||||||
|
|
||||||
class Timesheet(Document):
|
class Timesheet(Document):
|
||||||
def onload(self):
|
|
||||||
self.get("__onload").maintain_bill_work_hours_same = frappe.db.get_single_value('HR Settings', 'maintain_bill_work_hours_same')
|
|
||||||
|
|
||||||
def validate(self):
|
def validate(self):
|
||||||
self.set_employee_name()
|
self.set_employee_name()
|
||||||
self.set_status()
|
self.set_status()
|
||||||
|
@ -11,9 +11,6 @@ $(document).bind('toolbar_setup', function() {
|
|||||||
href="https://discuss.erpnext.com">Feedback</a></p>'
|
href="https://discuss.erpnext.com">Feedback</a></p>'
|
||||||
|
|
||||||
|
|
||||||
$('.navbar-home').html('<img class="erpnext-icon" src="'+
|
|
||||||
frappe.urllib.get_base_url()+'/assets/erpnext/images/erp-icon.svg" />');
|
|
||||||
|
|
||||||
$('[data-link="docs"]').attr("href", "https://erpnext.com/docs")
|
$('[data-link="docs"]').attr("href", "https://erpnext.com/docs")
|
||||||
$('[data-link="issues"]').attr("href", "https://github.com/frappe/erpnext/issues")
|
$('[data-link="issues"]').attr("href", "https://github.com/frappe/erpnext/issues")
|
||||||
|
|
||||||
@ -41,7 +38,8 @@ $.extend(frappe.create_routes, {
|
|||||||
"Item Group": "Tree/Item Group",
|
"Item Group": "Tree/Item Group",
|
||||||
"Sales Person": "Tree/Sales Person",
|
"Sales Person": "Tree/Sales Person",
|
||||||
"Account": "Tree/Account",
|
"Account": "Tree/Account",
|
||||||
"Cost Center": "Tree/Cost Center"
|
"Cost Center": "Tree/Cost Center",
|
||||||
|
"Department": "Tree/Department",
|
||||||
});
|
});
|
||||||
|
|
||||||
// preferred modules for breadcrumbs
|
// preferred modules for breadcrumbs
|
||||||
|
@ -144,7 +144,9 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({
|
|||||||
item.discount_amount = flt(item_rate) * flt(item.discount_percentage) / 100;
|
item.discount_amount = flt(item_rate) * flt(item.discount_percentage) / 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
item.rate = flt((item.price_list_rate) - (item.discount_amount), precision('rate', item));
|
if (item.discount_amount) {
|
||||||
|
item.rate = flt((item.price_list_rate) - (item.discount_amount), precision('rate', item));
|
||||||
|
}
|
||||||
|
|
||||||
this.calculate_taxes_and_totals();
|
this.calculate_taxes_and_totals();
|
||||||
},
|
},
|
||||||
|
@ -118,34 +118,13 @@ function get_filters(){
|
|||||||
"options": erpnext.get_presentation_currency_list()
|
"options": erpnext.get_presentation_currency_list()
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fieldname":"cost_center",
|
"fieldname": "cost_center",
|
||||||
"label": __("Cost Center"),
|
"label": __("Cost Center"),
|
||||||
"fieldtype": "MultiSelect",
|
"fieldtype": "MultiSelectList",
|
||||||
get_data: function() {
|
get_data: function(txt) {
|
||||||
var cost_centers = frappe.query_report.get_filter_value("cost_center") || "";
|
return frappe.db.get_link_options('Cost Center', txt, {
|
||||||
|
company: frappe.query_report.get_filter_value("company")
|
||||||
const values = cost_centers.split(/\s*,\s*/).filter(d => d);
|
|
||||||
const txt = cost_centers.match(/[^,\s*]*$/)[0] || '';
|
|
||||||
let data = [];
|
|
||||||
|
|
||||||
frappe.call({
|
|
||||||
type: "GET",
|
|
||||||
method:'frappe.desk.search.search_link',
|
|
||||||
async: false,
|
|
||||||
no_spinner: true,
|
|
||||||
args: {
|
|
||||||
doctype: "Cost Center",
|
|
||||||
txt: txt,
|
|
||||||
filters: {
|
|
||||||
"company": frappe.query_report.get_filter_value("company"),
|
|
||||||
"name": ["not in", values]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
callback: function(r) {
|
|
||||||
data = r.results;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
return data;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -65,6 +65,9 @@ $.extend(erpnext, {
|
|||||||
},
|
},
|
||||||
|
|
||||||
get_dimension_filters: async function() {
|
get_dimension_filters: async function() {
|
||||||
|
if (!frappe.model.can_read('Accounting Dimension')) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
let dimensions = await frappe.db.get_list('Accounting Dimension', {
|
let dimensions = await frappe.db.get_list('Accounting Dimension', {
|
||||||
fields: ['label', 'fieldname', 'document_type'],
|
fields: ['label', 'fieldname', 'document_type'],
|
||||||
filters: {
|
filters: {
|
||||||
@ -560,6 +563,7 @@ erpnext.utils.map_current_doc = function(opts) {
|
|||||||
if(!r.exc) {
|
if(!r.exc) {
|
||||||
var doc = frappe.model.sync(r.message);
|
var doc = frappe.model.sync(r.message);
|
||||||
cur_frm.dirty();
|
cur_frm.dirty();
|
||||||
|
erpnext.utils.clear_duplicates();
|
||||||
cur_frm.refresh();
|
cur_frm.refresh();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -590,6 +594,27 @@ erpnext.utils.map_current_doc = function(opts) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
erpnext.utils.clear_duplicates = function() {
|
||||||
|
const unique_items = new Map();
|
||||||
|
/*
|
||||||
|
Create a Map of items with
|
||||||
|
item_code => [qty, warehouse, batch_no]
|
||||||
|
*/
|
||||||
|
let items = [];
|
||||||
|
|
||||||
|
for (let item of cur_frm.doc.items) {
|
||||||
|
if (!(unique_items.has(item.item_code) && unique_items.get(item.item_code)[0] === item.qty &&
|
||||||
|
unique_items.get(item.item_code)[1] === item.warehouse && unique_items.get(item.item_code)[2] === item.batch_no &&
|
||||||
|
unique_items.get(item.item_code)[3] === item.delivery_date && unique_items.get(item.item_code)[4] === item.required_date &&
|
||||||
|
unique_items.get(item.item_code)[5] === item.rate)) {
|
||||||
|
|
||||||
|
unique_items.set(item.item_code, [item.qty, item.warehouse, item.batch_no, item.delivery_date, item.required_date, item.rate]);
|
||||||
|
items.push(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cur_frm.doc.items = items;
|
||||||
|
}
|
||||||
|
|
||||||
frappe.form.link_formatters['Item'] = function(value, doc) {
|
frappe.form.link_formatters['Item'] = function(value, doc) {
|
||||||
if(doc && doc.item_name && doc.item_name !== value) {
|
if(doc && doc.item_name && doc.item_name !== value) {
|
||||||
return value? value + ': ' + doc.item_name: doc.item_name;
|
return value? value + ': ' + doc.item_name: doc.item_name;
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user