From 1c77506e80133cbfe6d72074c7611d702de34329 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Tue, 1 Dec 2015 18:59:34 +0530 Subject: [PATCH 1/9] [fix] Don't overwrite exchange rate on saving for bank transfer --- erpnext/accounts/doctype/journal_entry/journal_entry.js | 6 +----- erpnext/accounts/doctype/journal_entry/journal_entry.py | 2 +- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.js b/erpnext/accounts/doctype/journal_entry/journal_entry.js index b1c355b375..479eaafd23 100644 --- a/erpnext/accounts/doctype/journal_entry/journal_entry.js +++ b/erpnext/accounts/doctype/journal_entry/journal_entry.js @@ -368,10 +368,6 @@ frappe.ui.form.on("Journal Entry Account", { credit: function(frm, dt, dn) { cur_frm.cscript.update_totals(frm.doc); - }, - - exchange_rate: function(frm, cdt, cdn) { - erpnext.journal_entry.set_debit_credit_in_company_currency(frm, cdt, cdn); } }) @@ -418,7 +414,7 @@ $.extend(erpnext.journal_entry, { if(row.account_currency == company_currency || !frm.doc.multi_currency) { frappe.model.set_value(cdt, cdn, "exchange_rate", 1); - } else if (!row.exchange_rate || row.account_type == "Bank") { + } else if (!row.exchange_rate || row.exchange_rate == 1 || row.account_type == "Bank") { frappe.call({ method: "erpnext.accounts.doctype.journal_entry.journal_entry.get_exchange_rate", args: { diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py index eefa0db1bb..c540582802 100644 --- a/erpnext/accounts/doctype/journal_entry/journal_entry.py +++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py @@ -295,7 +295,7 @@ class JournalEntry(AccountsController): for d in self.get("accounts"): if d.account_currency == self.company_currency: d.exchange_rate = 1 - elif not d.exchange_rate or d.account_type=="Bank" or \ + elif not d.exchange_rate or d.exchange_rate == 1 or \ (d.reference_type in ("Sales Invoice", "Purchase Invoice") and d.reference_name): d.exchange_rate = get_exchange_rate(d.account, d.account_currency, self.company, d.reference_type, d.reference_name, d.debit, d.credit, d.exchange_rate) From f58a3726a796f5a43518ed8c08e2245579e1439a Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Wed, 2 Dec 2015 11:13:20 +0530 Subject: [PATCH 2/9] Balance in chart of accounts in both company and account currency --- erpnext/accounts/page/accounts_browser/accounts_browser.js | 5 ++++- erpnext/accounts/page/accounts_browser/accounts_browser.py | 7 ++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/page/accounts_browser/accounts_browser.js b/erpnext/accounts/page/accounts_browser/accounts_browser.js index 6a2a8312f2..403c1cea02 100644 --- a/erpnext/accounts/page/accounts_browser/accounts_browser.js +++ b/erpnext/accounts/page/accounts_browser/accounts_browser.js @@ -166,7 +166,10 @@ erpnext.AccountsChart = Class.extend({ var dr_or_cr = node.data.balance < 0 ? "Cr" : "Dr"; if (me.ctype == 'Account' && node.data && node.data.balance!==undefined) { $('' - + format_currency(Math.abs(node.data.balance), node.data.account_currency) + + (node.data.balance_in_account_currency ? + (format_currency(Math.abs(node.data.balance_in_account_currency), + node.data.account_currency) + " / ") : "") + + format_currency(Math.abs(node.data.balance), node.data.company_currency) + " " + dr_or_cr + '').insertBefore(node.$ul); } diff --git a/erpnext/accounts/page/accounts_browser/accounts_browser.py b/erpnext/accounts/page/accounts_browser/accounts_browser.py index 210c4bf729..891a05de7b 100644 --- a/erpnext/accounts/page/accounts_browser/accounts_browser.py +++ b/erpnext/accounts/page/accounts_browser/accounts_browser.py @@ -44,7 +44,12 @@ def get_children(): args['parent'], as_dict=1) if ctype == 'Account': + company_currency = frappe.db.get_value("Company", company, "default_currency") for each in acc: - each["balance"] = flt(get_balance_on(each.get("value"))) + each["company_currency"] = company_currency + each["balance"] = flt(get_balance_on(each.get("value"), in_account_currency=False)) + + if each.account_currency != company_currency: + each["balance_in_account_currency"] = flt(get_balance_on(each.get("value"))) return acc From f7911687a05e28205f6f70a901043f28cc54ffe2 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Thu, 3 Dec 2015 08:09:27 +0530 Subject: [PATCH 3/9] [minor] fixes to patch --- .../accounts/doctype/journal_entry/journal_entry.py | 7 ++++++- .../journal_entry_account/journal_entry_account.json | 12 ++++++------ erpnext/patches/v4_4/make_email_accounts.py | 4 ++-- erpnext/patches/v6_8/move_drop_ship_to_po_items.py | 3 +++ 4 files changed, 17 insertions(+), 9 deletions(-) diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py index eefa0db1bb..8eaef8bd01 100644 --- a/erpnext/accounts/doctype/journal_entry/journal_entry.py +++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py @@ -350,7 +350,7 @@ class JournalEntry(AccountsController): elif frappe.db.get_value("Account", d.account, "account_type") in ["Bank", "Cash"]: total_amount += (d.debit_in_account_currency or d.credit_in_account_currency) bank_account_currency = d.account_currency - + self.set_total_amount(total_amount, bank_account_currency) def set_total_amount(self, amt, currency): @@ -743,6 +743,11 @@ def get_account_balance_and_party_type(account, date, company, debit=None, credi "exchange_rate": get_exchange_rate(account, account_details.account_currency, company, debit=debit, credit=credit, exchange_rate=exchange_rate) } + + # un-set party if not party type + if not party_type: + grid_values["party"] = "" + return grid_values @frappe.whitelist() diff --git a/erpnext/accounts/doctype/journal_entry_account/journal_entry_account.json b/erpnext/accounts/doctype/journal_entry_account/journal_entry_account.json index 348c444771..9277da5905 100644 --- a/erpnext/accounts/doctype/journal_entry_account/journal_entry_account.json +++ b/erpnext/accounts/doctype/journal_entry_account/journal_entry_account.json @@ -10,7 +10,7 @@ "fields": [ { "allow_on_submit": 0, - "bold": 0, + "bold": 1, "collapsible": 0, "fieldname": "account", "fieldtype": "Link", @@ -334,7 +334,7 @@ }, { "allow_on_submit": 0, - "bold": 0, + "bold": 1, "collapsible": 0, "fieldname": "debit_in_account_currency", "fieldtype": "Currency", @@ -359,7 +359,7 @@ }, { "allow_on_submit": 0, - "bold": 0, + "bold": 1, "collapsible": 0, "fieldname": "debit", "fieldtype": "Currency", @@ -408,7 +408,7 @@ }, { "allow_on_submit": 0, - "bold": 0, + "bold": 1, "collapsible": 0, "fieldname": "credit_in_account_currency", "fieldtype": "Currency", @@ -433,7 +433,7 @@ }, { "allow_on_submit": 0, - "bold": 0, + "bold": 1, "collapsible": 0, "fieldname": "credit", "fieldtype": "Currency", @@ -614,7 +614,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2015-11-24 02:36:05.804010", + "modified": "2015-12-02 04:14:37.571883", "modified_by": "Administrator", "module": "Accounts", "name": "Journal Entry Account", diff --git a/erpnext/patches/v4_4/make_email_accounts.py b/erpnext/patches/v4_4/make_email_accounts.py index 1acd8de68c..126acfcd1e 100644 --- a/erpnext/patches/v4_4/make_email_accounts.py +++ b/erpnext/patches/v4_4/make_email_accounts.py @@ -35,7 +35,7 @@ def execute(): "enable_incoming": "sync_support_mails", "email_id": "mail_login", "password": "mail_password", - "pop3_server": "mail_server", + "email_server": "mail_server", "use_ssl": "use_ssl", "signature": "support_signature", "enable_auto_reply": "send_autoreply", @@ -59,7 +59,7 @@ def execute(): "enable_incoming": "extract_emails", "email_id": "username", "password": "password", - "pop3_server": "host", + "email_server": "host", "use_ssl": "use_ssl", } diff --git a/erpnext/patches/v6_8/move_drop_ship_to_po_items.py b/erpnext/patches/v6_8/move_drop_ship_to_po_items.py index 1c2a57a93b..06d158e4ec 100644 --- a/erpnext/patches/v6_8/move_drop_ship_to_po_items.py +++ b/erpnext/patches/v6_8/move_drop_ship_to_po_items.py @@ -4,6 +4,9 @@ def execute(): frappe.reload_doctype("Purchase Order") frappe.reload_doctype("Purchase Order Item") + if not frappe.db.has_column("Purchase Order", "delivered_by_supplier"): + return + for po in frappe.get_all("Purchase Order", filters={"delivered_by_supplier": 1}, fields=["name"]): purchase_order = frappe.get_doc("Purchase Order", po) From ba2596a7e0a65458f551fbf4f505bdd0a7e06452 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Thu, 3 Dec 2015 10:35:11 +0530 Subject: [PATCH 4/9] [minor] validate email id before inviting user --- erpnext/utilities/doctype/contact/contact.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/erpnext/utilities/doctype/contact/contact.py b/erpnext/utilities/doctype/contact/contact.py index bfab79f813..dff05bc462 100644 --- a/erpnext/utilities/doctype/contact/contact.py +++ b/erpnext/utilities/doctype/contact/contact.py @@ -4,6 +4,7 @@ from __future__ import unicode_literals import frappe from frappe.utils import cstr +from frappe import _ from erpnext.controllers.status_updater import StatusUpdater @@ -61,6 +62,10 @@ class Contact(StatusUpdater): @frappe.whitelist() def invite_user(contact): contact = frappe.get_doc("Contact", contact) + + if not contact.email_id: + frappe.throw(_("Please set Email ID")) + if contact.has_permission("write"): user = frappe.get_doc({ "doctype": "User", From 2c069a418a366734c3347387499fd97a211e5b2c Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Thu, 3 Dec 2015 11:10:23 +0530 Subject: [PATCH 5/9] [minor] allow stock entry for manufacture without production order --- .../stock/doctype/stock_entry/stock_entry.js | 18 +++++++++--------- .../stock/doctype/stock_entry/stock_entry.py | 6 ++---- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.js b/erpnext/stock/doctype/stock_entry/stock_entry.js index e9fc134152..3965417d23 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.js +++ b/erpnext/stock/doctype/stock_entry/stock_entry.js @@ -148,11 +148,11 @@ erpnext.stock.StockEntry = erpnext.stock.StockController.extend({ $.each(["from_bom", "bom_no", "fg_completed_qty", "use_multi_level_bom"], function(i, field) { me.frm.set_value(field, r.message[field]); }) - + if (me.frm.doc.purpose == "Material Transfer for Manufacture" && !me.frm.doc.to_warehouse) me.frm.set_value("to_warehouse", r.message["wip_warehouse"]); - - + + if (me.frm.doc.purpose == "Manufacture") { if(r.message["additional_costs"].length) { $.each(r.message["additional_costs"], function(i, row) { @@ -160,7 +160,7 @@ erpnext.stock.StockEntry = erpnext.stock.StockController.extend({ }) refresh_field("additional_costs"); } - + if (!me.frm.doc.from_warehouse) me.frm.set_value("from_warehouse", r.message["wip_warehouse"]); if (!me.frm.doc.to_warehouse) me.frm.set_value("to_warehouse", r.message["fg_warehouse"]); } @@ -171,7 +171,7 @@ erpnext.stock.StockEntry = erpnext.stock.StockController.extend({ }, toggle_enable_bom: function() { - this.frm.toggle_enable("bom_no", !in_list(["Manufacture", "Material Transfer for Manufacture"], this.frm.doc.purpose)); + this.frm.toggle_enable("bom_no", !!!this.frm.doc.production_order); }, add_excise_button: function() { @@ -252,11 +252,11 @@ cur_frm.cscript.toggle_related_fields = function(doc) { if(doc.purpose == "Material Receipt") { cur_frm.set_value("from_bom", 0); } - + // Addition costs based on purpose - cur_frm.toggle_display(["additional_costs", "total_additional_costs", "additional_costs_section"], + cur_frm.toggle_display(["additional_costs", "total_additional_costs", "additional_costs_section"], doc.purpose!='Material Issue'); - + cur_frm.fields_dict["items"].grid.set_column_disp("additional_cost", doc.purpose!='Material Issue'); } @@ -405,4 +405,4 @@ cur_frm.cscript.company = function(doc, cdt, cdn) { cur_frm.cscript.posting_date = function(doc, cdt, cdn){ erpnext.get_fiscal_year(doc.company, doc.posting_date); -} \ No newline at end of file +} diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py index 79cd8de9df..9702972604 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/stock_entry.py @@ -170,10 +170,8 @@ class StockEntry(StockController): def validate_production_order(self): if self.purpose in ("Manufacture", "Material Transfer for Manufacture"): # check if production order is entered - if not self.production_order: - frappe.throw(_("Production order number is mandatory for stock entry purpose manufacture")) - # check for double entry - if self.purpose=="Manufacture": + + if self.purpose=="Manufacture" and self.production_order: if not self.fg_completed_qty: frappe.throw(_("For Quantity (Manufactured Qty) is mandatory")) self.check_if_operations_completed() From 4c7a32e446669de6caa41dade89a25164c410b4a Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Thu, 3 Dec 2015 11:47:38 +0530 Subject: [PATCH 6/9] [fix] Toggle required for sales and purchase tax template based on tax type --- erpnext/accounts/doctype/tax_rule/tax_rule.js | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/erpnext/accounts/doctype/tax_rule/tax_rule.js b/erpnext/accounts/doctype/tax_rule/tax_rule.js index 4b059dc564..4c35370eae 100644 --- a/erpnext/accounts/doctype/tax_rule/tax_rule.js +++ b/erpnext/accounts/doctype/tax_rule/tax_rule.js @@ -4,19 +4,26 @@ cur_frm.add_fetch("customer", "customer_group", "customer_group" ); cur_frm.add_fetch("supplier", "supplier_type", "supplier_type" ); -cur_frm.toggle_reqd("sales_tax_template", cur_frm.doc.tax_type=="Sales"); -cur_frm.toggle_reqd("purchase_tax_template", cur_frm.doc.tax_type=="Purchase"); - +frappe.ui.form.on("Tax Rule", "tax_type", function(frm) { + frm.toggle_reqd("sales_tax_template", frm.doc.tax_type=="Sales"); + frm.toggle_reqd("purchase_tax_template", frm.doc.tax_type=="Purchase"); +}) frappe.ui.form.on("Tax Rule", "onload", function(frm) { - if(frm.doc.__islocal){ + if(frm.doc.__islocal) { frm.set_value("use_for_shopping_cart", 1); } }) +frappe.ui.form.on("Tax Rule", "refresh", function(frm) { + frappe.ui.form.trigger("Tax Rule", "tax_type"); +}) + frappe.ui.form.on("Tax Rule", "use_for_shopping_cart", function(frm) { - if(!frm.doc.use_for_shopping_cart && (frappe.get_list("Tax Rule", {"use_for_shopping_cart":1}).length == 0)){ - frappe.model.get_value("Shopping Cart Settings", "Shopping Cart Settings", "enabled", function(docfield) { + if(!frm.doc.use_for_shopping_cart && + (frappe.get_list("Tax Rule", {"use_for_shopping_cart":1}).length == 0)) { + frappe.model.get_value("Shopping Cart Settings", "Shopping Cart Settings", + "enabled", function(docfield) { if(docfield.enabled){ frm.set_value("use_for_shopping_cart", 1); frappe.throw(__("Shopping Cart is enabled")); From c4d9554a056a0e991388b272ec6468e8750b62f9 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Thu, 3 Dec 2015 10:44:21 +0530 Subject: [PATCH 7/9] [fix] Payment Days and holidays considering joining and relieving dates --- erpnext/hr/doctype/salary_slip/salary_slip.py | 75 ++++++++++--------- 1 file changed, 41 insertions(+), 34 deletions(-) diff --git a/erpnext/hr/doctype/salary_slip/salary_slip.py b/erpnext/hr/doctype/salary_slip/salary_slip.py index ea7c96e499..3eb0719adc 100644 --- a/erpnext/hr/doctype/salary_slip/salary_slip.py +++ b/erpnext/hr/doctype/salary_slip/salary_slip.py @@ -20,19 +20,20 @@ class SalarySlip(TransactionBase): def get_emp_and_leave_details(self): if self.employee: - self.get_leave_details() - struct = self.check_sal_struct() + joining_date, relieving_date = frappe.db.get_value("Employee", self.employee, + ["date_of_joining", "relieving_date"]) + + self.get_leave_details(joining_date, relieving_date) + + struct = self.check_sal_struct(joining_date, relieving_date) if struct: self.set("earnings", []) self.set("deduction", []) self.pull_sal_struct(struct) - def check_sal_struct(self): + def check_sal_struct(self, joining_date, relieving_date): m = get_month_details(self.fiscal_year, self.month) - joining_date, relieving_date = frappe.db.get_value("Employee", self.employee, - ["date_of_joining", "relieving_date"]) - struct = frappe.db.sql("""select name from `tabSalary Structure` where employee=%s and is_active = 'Yes' and (from_date <= %s or from_date <= %s) @@ -51,20 +52,23 @@ class SalarySlip(TransactionBase): make_salary_slip(struct, self) def pull_emp_details(self): - emp = frappe.db.get_value("Employee", self.employee, - ["bank_name", "bank_ac_no"], as_dict=1) + emp = frappe.db.get_value("Employee", self.employee, ["bank_name", "bank_ac_no"], as_dict=1) if emp: self.bank_name = emp.bank_name self.bank_account_no = emp.bank_ac_no - def get_leave_details(self, lwp=None): + def get_leave_details(self, joining_date=None, relieving_date=None, lwp=None): if not self.fiscal_year: self.fiscal_year = frappe.db.get_default("fiscal_year") if not self.month: self.month = "%02d" % getdate(nowdate()).month + + if not joining_date: + joining_date, relieving_date = frappe.db.get_value("Employee", self.employee, + ["date_of_joining", "relieving_date"]) m = get_month_details(self.fiscal_year, self.month) - holidays = self.get_holidays_for_employee(m) + holidays = self.get_holidays_for_employee(m, joining_date, relieving_date) if not cint(frappe.db.get_value("HR Settings", "HR Settings", "include_holidays_in_total_working_days")): @@ -76,44 +80,48 @@ class SalarySlip(TransactionBase): lwp = self.calculate_lwp(holidays, m) self.total_days_in_month = m['month_days'] self.leave_without_pay = lwp - payment_days = flt(self.get_payment_days(m)) - flt(lwp) + payment_days = flt(self.get_payment_days(m, joining_date, relieving_date)) - flt(lwp) self.payment_days = payment_days > 0 and payment_days or 0 - - def get_payment_days(self, m): + def get_payment_days(self, m, joining_date, relieving_date): payment_days = m['month_days'] - emp = frappe.db.sql("select date_of_joining, relieving_date from `tabEmployee` \ - where name = %s", self.employee, as_dict=1)[0] + if relieving_date: + if getdate(relieving_date) > m['month_start_date'] \ + and getdate(relieving_date) < m['month_end_date']: + payment_days = getdate(relieving_date).day + elif getdate(relieving_date) < m['month_start_date']: + frappe.throw(_("Employee relieved on {0} must be set as 'Left'").format(relieving_date)) - if emp['relieving_date']: - if getdate(emp['relieving_date']) > m['month_start_date'] and \ - getdate(emp['relieving_date']) < m['month_end_date']: - payment_days = getdate(emp['relieving_date']).day - elif getdate(emp['relieving_date']) < m['month_start_date']: - frappe.throw(_("Employee relieved on {0} must be set as 'Left'").format(emp["relieving_date"])) - - if emp['date_of_joining']: - if getdate(emp['date_of_joining']) > m['month_start_date'] and \ - getdate(emp['date_of_joining']) < m['month_end_date']: - payment_days = payment_days - getdate(emp['date_of_joining']).day + 1 - elif getdate(emp['date_of_joining']) > m['month_end_date']: + if joining_date: + if getdate(joining_date) > m['month_start_date'] and \ + getdate(joining_date) < m['month_end_date']: + payment_days = payment_days - getdate(joining_date).day + 1 + elif getdate(joining_date) > m['month_end_date']: payment_days = 0 return payment_days - def get_holidays_for_employee(self, m): + def get_holidays_for_employee(self, month, joining_date, relieving_date): + start_date = month['month_start_date'] \ + if joining_date < month['month_start_date'] else joining_date + + end_date = relieving_date \ + if (relieving_date and relieving_date < month['month_end_date']) else month['month_end_date'] + holidays = frappe.db.sql("""select t1.holiday_date from `tabHoliday` t1, tabEmployee t2 where t1.parent = t2.holiday_list and t2.name = %s and t1.holiday_date between %s and %s""", - (self.employee, m['month_start_date'], m['month_end_date'])) + (self.employee, start_date, end_date)) + if not holidays: holidays = frappe.db.sql("""select t1.holiday_date from `tabHoliday` t1, `tabHoliday List` t2 where t1.parent = t2.name and t2.is_default = 1 and t2.fiscal_year = %s - and t1.holiday_date between %s and %s""", (self.fiscal_year, - m['month_start_date'], m['month_end_date'])) + and t1.holiday_date between %s and %s""", + (self.fiscal_year, start_date, end_date)) + holidays = [cstr(i[0]) for i in holidays] return holidays @@ -148,9 +156,8 @@ class SalarySlip(TransactionBase): from frappe.utils import money_in_words self.check_existing() - if not (len(self.get("earnings")) or - len(self.get("deductions"))): - self.get_emp_and_leave_details() + if not (len(self.get("earnings")) or len(self.get("deductions"))): + self.get_emp_and_leave_details() else: self.get_leave_details(self.leave_without_pay) From a4eeb919e64661e5edbc679191c35c462727b121 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Thu, 3 Dec 2015 15:10:20 +0530 Subject: [PATCH 8/9] [fix] Set payment days considering joinging date, reliving date and applicable holidays --- .../hr/doctype/holiday_list/test_records.json | 4 ++ erpnext/hr/doctype/salary_slip/salary_slip.py | 62 +++++++++---------- .../doctype/salary_slip/test_salary_slip.py | 46 +++++++++++--- 3 files changed, 72 insertions(+), 40 deletions(-) diff --git a/erpnext/hr/doctype/holiday_list/test_records.json b/erpnext/hr/doctype/holiday_list/test_records.json index 342bacb583..a8cf56b771 100644 --- a/erpnext/hr/doctype/holiday_list/test_records.json +++ b/erpnext/hr/doctype/holiday_list/test_records.json @@ -7,6 +7,10 @@ "description": "New Year", "holiday_date": "2013-01-01" }, + { + "description": "Republic Day", + "holiday_date": "2013-01-26" + }, { "description": "Test Holiday", "holiday_date": "2013-02-01" diff --git a/erpnext/hr/doctype/salary_slip/salary_slip.py b/erpnext/hr/doctype/salary_slip/salary_slip.py index 3eb0719adc..818c95e324 100644 --- a/erpnext/hr/doctype/salary_slip/salary_slip.py +++ b/erpnext/hr/doctype/salary_slip/salary_slip.py @@ -4,7 +4,7 @@ from __future__ import unicode_literals import frappe -from frappe.utils import add_days, cint, cstr, flt, getdate, nowdate, rounded +from frappe.utils import add_days, cint, cstr, flt, getdate, nowdate, rounded, date_diff from frappe.model.naming import make_autoname from frappe import msgprint, _ @@ -68,46 +68,46 @@ class SalarySlip(TransactionBase): ["date_of_joining", "relieving_date"]) m = get_month_details(self.fiscal_year, self.month) - holidays = self.get_holidays_for_employee(m, joining_date, relieving_date) + holidays = self.get_holidays_for_employee(m['month_start_date'], m['month_end_date']) - if not cint(frappe.db.get_value("HR Settings", "HR Settings", - "include_holidays_in_total_working_days")): - m["month_days"] -= len(holidays) - if m["month_days"] < 0: - frappe.throw(_("There are more holidays than working days this month.")) + working_days = m["month_days"] + if not cint(frappe.db.get_value("HR Settings", None, "include_holidays_in_total_working_days")): + working_days -= len(holidays) + if working_days < 0: + frappe.throw(_("There are more holidays than working days this month.")) if not lwp: lwp = self.calculate_lwp(holidays, m) - self.total_days_in_month = m['month_days'] + self.total_days_in_month = working_days self.leave_without_pay = lwp payment_days = flt(self.get_payment_days(m, joining_date, relieving_date)) - flt(lwp) self.payment_days = payment_days > 0 and payment_days or 0 - - def get_payment_days(self, m, joining_date, relieving_date): - payment_days = m['month_days'] - if relieving_date: - if getdate(relieving_date) > m['month_start_date'] \ - and getdate(relieving_date) < m['month_end_date']: - payment_days = getdate(relieving_date).day - elif getdate(relieving_date) < m['month_start_date']: - frappe.throw(_("Employee relieved on {0} must be set as 'Left'").format(relieving_date)) - + + def get_payment_days(self, month, joining_date, relieving_date): + start_date = month['month_start_date'] if joining_date: - if getdate(joining_date) > m['month_start_date'] and \ - getdate(joining_date) < m['month_end_date']: - payment_days = payment_days - getdate(joining_date).day + 1 - elif getdate(joining_date) > m['month_end_date']: - payment_days = 0 + if joining_date > month['month_start_date']: + start_date = joining_date + elif joining_date > month['month_end_date']: + return + + if relieving_date: + if relieving_date > start_date and relieving_date < month['month_end_date']: + end_date = relieving_date + elif relieving_date < month['month_start_date']: + frappe.throw(_("Employee relieved on {0} must be set as 'Left'").format(relieving_date)) + else: + end_date = month['month_end_date'] + + payment_days = date_diff(end_date, start_date) + 1 + + if not cint(frappe.db.get_value("HR Settings", None, "include_holidays_in_total_working_days")): + holidays = self.get_holidays_for_employee(start_date, end_date) + payment_days -= len(holidays) return payment_days - def get_holidays_for_employee(self, month, joining_date, relieving_date): - start_date = month['month_start_date'] \ - if joining_date < month['month_start_date'] else joining_date - - end_date = relieving_date \ - if (relieving_date and relieving_date < month['month_end_date']) else month['month_end_date'] - + def get_holidays_for_employee(self, start_date, end_date): holidays = frappe.db.sql("""select t1.holiday_date from `tabHoliday` t1, tabEmployee t2 where t1.parent = t2.holiday_list and t2.name = %s @@ -159,7 +159,7 @@ class SalarySlip(TransactionBase): if not (len(self.get("earnings")) or len(self.get("deductions"))): self.get_emp_and_leave_details() else: - self.get_leave_details(self.leave_without_pay) + self.get_leave_details(lwp = self.leave_without_pay) if not self.net_pay: self.calculate_net_pay() diff --git a/erpnext/hr/doctype/salary_slip/test_salary_slip.py b/erpnext/hr/doctype/salary_slip/test_salary_slip.py index 9eda231f6f..387c593129 100644 --- a/erpnext/hr/doctype/salary_slip/test_salary_slip.py +++ b/erpnext/hr/doctype/salary_slip/test_salary_slip.py @@ -25,11 +25,11 @@ class TestSalarySlip(unittest.TestCase): la.submit() def tearDown(self): - frappe.db.set_value("HR Settings", "HR Settings", "include_holidays_in_total_working_days", 0) + frappe.db.set_value("HR Settings", None, "include_holidays_in_total_working_days", 0) frappe.set_user("Administrator") def test_salary_slip_with_holidays_included(self): - frappe.db.set_value("HR Settings", "HR Settings", "include_holidays_in_total_working_days", 1) + frappe.db.set_value("HR Settings", None, "include_holidays_in_total_working_days", 1) ss = frappe.copy_doc(test_records[0]) ss.insert() @@ -43,18 +43,46 @@ class TestSalarySlip(unittest.TestCase): self.assertEquals(ss.net_pay, 14867.74) def test_salary_slip_with_holidays_excluded(self): - frappe.db.set_value("HR Settings", "HR Settings", "include_holidays_in_total_working_days", 0) + frappe.db.set_value("HR Settings", None, "include_holidays_in_total_working_days", 0) ss = frappe.copy_doc(test_records[0]) ss.insert() - self.assertEquals(ss.total_days_in_month, 30) - self.assertEquals(ss.payment_days, 29) - self.assertEquals(ss.earnings[0].e_modified_amount, 14500) + self.assertEquals(ss.total_days_in_month, 29) + self.assertEquals(ss.payment_days, 28) + self.assertEquals(ss.earnings[0].e_modified_amount, 14482.76) self.assertEquals(ss.earnings[1].e_modified_amount, 500) self.assertEquals(ss.deductions[0].d_modified_amount, 100) - self.assertEquals(ss.deductions[1].d_modified_amount, 48.33) - self.assertEquals(ss.gross_pay, 15000) - self.assertEquals(ss.net_pay, 14851.67) + self.assertEquals(ss.deductions[1].d_modified_amount, 48.28) + self.assertEquals(ss.gross_pay, 14982.76) + self.assertEquals(ss.net_pay, 14834.48) + + def test_payment_days(self): + # Holidays not included in working days + frappe.db.set_value("HR Settings", None, "include_holidays_in_total_working_days", 0) + + # set joinng date in the same month + frappe.db.set_value("Employee", "_T-Employee-0001", "date_of_joining", "2013-01-11") + + ss = frappe.copy_doc(test_records[0]) + ss.insert() + + self.assertEquals(ss.total_days_in_month, 29) + self.assertEquals(ss.payment_days, 19) + + # set relieving date in the same month + frappe.db.set_value("Employee", "_T-Employee-0001", "relieving_date", "2013-01-28") + ss.save() + self.assertEquals(ss.total_days_in_month, 29) + self.assertEquals(ss.payment_days, 16) + + # Holidays included in working days + frappe.db.set_value("HR Settings", None, "include_holidays_in_total_working_days", 1) + ss.save() + self.assertEquals(ss.total_days_in_month, 31) + self.assertEquals(ss.payment_days, 17) + + frappe.db.set_value("Employee", "_T-Employee-0001", "date_of_joining", "2001-01-11") + frappe.db.set_value("Employee", "_T-Employee-0001", "relieving_date", None) def test_employee_salary_slip_read_permission(self): self.make_employee("test_employee@example.com") From 275b3eec0dbaef4f895c187ce118cb690dc211c7 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Thu, 3 Dec 2015 18:28:57 +0600 Subject: [PATCH 9/9] bumped to version 6.12.3 --- erpnext/__version__.py | 2 +- erpnext/hooks.py | 2 +- setup.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/erpnext/__version__.py b/erpnext/__version__.py index 4220bc7e6c..d004216dfe 100644 --- a/erpnext/__version__.py +++ b/erpnext/__version__.py @@ -1,2 +1,2 @@ from __future__ import unicode_literals -__version__ = '6.12.2' +__version__ = '6.12.3' diff --git a/erpnext/hooks.py b/erpnext/hooks.py index bb689783db..744db4456b 100644 --- a/erpnext/hooks.py +++ b/erpnext/hooks.py @@ -7,7 +7,7 @@ app_publisher = "Frappe Technologies Pvt. Ltd." app_description = """ERP made simple""" app_icon = "icon-th" app_color = "#e74c3c" -app_version = "6.12.2" +app_version = "6.12.3" app_email = "info@erpnext.com" app_license = "GNU General Public License (v3)" source_link = "https://github.com/frappe/erpnext" diff --git a/setup.py b/setup.py index ffaee6b7e7..66d4dcc2d3 100644 --- a/setup.py +++ b/setup.py @@ -1,6 +1,6 @@ from setuptools import setup, find_packages -version = "6.12.2" +version = "6.12.3" with open("requirements.txt", "r") as f: install_requires = f.readlines()