From 362455e7495be5169d1dc2d9c1973ebd13190152 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Wed, 13 Feb 2013 15:50:39 +0530 Subject: [PATCH 1/8] fix outstanding and floating point issue in gl entry --- .../purchase_invoice/purchase_invoice.py | 2 +- .../purchase_taxes_and_charges_master.js | 5 +++-- accounts/general_ledger.py | 4 ++++ .../purchase_common/purchase_common.js | 4 ++-- patches/february_2013/fix_outstanding.py | 15 +++++++++++++ .../gle_floating_point_issue_revisited.py | 22 +++++++++++++++++++ patches/patch_list.py | 2 +- 7 files changed, 48 insertions(+), 6 deletions(-) create mode 100644 patches/february_2013/fix_outstanding.py create mode 100644 patches/february_2013/gle_floating_point_issue_revisited.py diff --git a/accounts/doctype/purchase_invoice/purchase_invoice.py b/accounts/doctype/purchase_invoice/purchase_invoice.py index db0ddd807d..f1c5758617 100644 --- a/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -423,7 +423,7 @@ class DocType(BuyingController): self.get_gl_dict({ "account": self.doc.credit_to, "against": self.doc.against_expense_account, - "credit": self.doc.grand_total, + "credit": self.doc.total_amount_to_pay, "remarks": self.doc.remarks, "against_voucher": self.doc.name, "against_voucher_type": self.doc.doctype, diff --git a/accounts/doctype/purchase_taxes_and_charges_master/purchase_taxes_and_charges_master.js b/accounts/doctype/purchase_taxes_and_charges_master/purchase_taxes_and_charges_master.js index 6158e26d8f..53588e0629 100644 --- a/accounts/doctype/purchase_taxes_and_charges_master/purchase_taxes_and_charges_master.js +++ b/accounts/doctype/purchase_taxes_and_charges_master/purchase_taxes_and_charges_master.js @@ -76,8 +76,9 @@ cur_frm.cscript.add_deduct_tax = function(doc, cdt, cdn) { alert("Please select Category first"); d.add_deduct_tax = ''; } - else if(d.category != 'Total' && d.add_deduct_tax == 'Deduct'){ - alert("You cannot Deduct when category is for valuation or for both(i.e total and valuation)"); + else if(d.category != 'Total' && d.add_deduct_tax == 'Deduct') { + console.log([d.category, d.add_deduct_tax]); + msgprint("You cannot deduct when category is for 'Valuation' or 'Valuation and Total'"); d.add_deduct_tax = ''; } diff --git a/accounts/general_ledger.py b/accounts/general_ledger.py index f7932bf60c..06c101b6b5 100644 --- a/accounts/general_ledger.py +++ b/accounts/general_ledger.py @@ -70,6 +70,10 @@ def save_entries(gl_map, cancel, adv_adj, update_outstanding): for entry in gl_map: gle = Document('GL Entry', fielddata=entry) + # round off upto 2 decimal + gle.debit = flt(gle.debit, 2) + gle.credit = flt(gle.credit, 2) + # toggle debit, credit if negative entry if flt(gle.debit) < 0 or flt(gle.credit) < 0: _swap(gle) diff --git a/buying/doctype/purchase_common/purchase_common.js b/buying/doctype/purchase_common/purchase_common.js index 3a9d89110f..b3f62d58b9 100644 --- a/buying/doctype/purchase_common/purchase_common.js +++ b/buying/doctype/purchase_common/purchase_common.js @@ -778,10 +778,10 @@ cur_frm.cscript.calc_doc_values = function(doc, tname, fname, other_fname) { var calculate_outstanding = function(doc) { // total amount to pay - doc.total_amount_to_pay = flt(flt(doc.net_total) + flt(doc.other_charges_added) - flt(doc.other_charges_deducted)); + doc.total_amount_to_pay = flt(doc.grand_total) - flt(doc.write_off_amount); // outstanding amount - if(doc.docstatus==0) doc.outstanding_amount = flt(doc.net_total) + flt(doc.other_charges_added) - flt(doc.other_charges_deducted) - flt(doc.total_advance); + if(doc.docstatus==0) doc.outstanding_amount = doc.total_amount_to_pay - flt(doc.total_advance); refresh_many(['total_amount_to_pay', 'outstanding_amount']); } diff --git a/patches/february_2013/fix_outstanding.py b/patches/february_2013/fix_outstanding.py new file mode 100644 index 0000000000..226b360a29 --- /dev/null +++ b/patches/february_2013/fix_outstanding.py @@ -0,0 +1,15 @@ +def execute(): + import webnotes + from webnotes.utils import flt + for dt in ["Sales Invoice", "Purchase Invoice"]: + records = webnotes.conn.sql("""select name, outstanding_amount from `tab%s` + where docstatus = 1""" % dt) + for r in records: + outstanding = webnotes.conn.sql(""" + select sum(ifnull(debit, 0)) - sum(ifnull(credit, 0)) from `tabGL Entry` + where against_voucher = %s and against_voucher_type = %s + and ifnull(is_cancelled, 'No') = 'No'""", (r[0], dt)) + if flt(r[1]) != abs(flt(outstanding[0][0])): + # print r, outstanding + webnotes.conn.sql("update `tab%s` set outstanding_amount = %s where name = %s" % + (dt, '%s', '%s'), (abs(flt(outstanding[0][0])), si[0])) \ No newline at end of file diff --git a/patches/february_2013/gle_floating_point_issue_revisited.py b/patches/february_2013/gle_floating_point_issue_revisited.py new file mode 100644 index 0000000000..3fc57bd4e5 --- /dev/null +++ b/patches/february_2013/gle_floating_point_issue_revisited.py @@ -0,0 +1,22 @@ +def execute(): + import webnotes + from webnotes.utils import flt + + records = webnotes.conn.sql("""select name, grand_total, debit_to from `tabSales Invoice` + where docstatus = 1""", as_dict=1) + + for r in records: + gle = webnotes.conn.sql("""select name, debit from `tabGL Entry` + where account = %s and voucher_type = 'Sales Invoice' and voucher_no = %s + and ifnull(is_cancelled, 'No') = 'No' limit 1""", (r.debit_to, r.name), as_dict=1) + if gle: + diff = round((flt(r.grand_total) - flt(gle[0]['debit'])), 2) + + if abs(diff) == 0.01: + # print r.name, r.grand_total, gle[0]['debit'] + webnotes.conn.sql("""update `tabGL Entry` set debit = debit + %s + where name = %s""", (diff, gle[0]['name'])) + + webnotes.conn.sql("""update `tabGL Entry` set credit = credit - %s + where voucher_type = 'Sales Invoice' and voucher_no = %s + and credit > 0 limit 1""", (diff, r.name)) \ No newline at end of file diff --git a/patches/patch_list.py b/patches/patch_list.py index c1fa08f24e..97bdc52e79 100644 --- a/patches/patch_list.py +++ b/patches/patch_list.py @@ -167,5 +167,5 @@ patch_list = [ "patches.february_2013.account_negative_balance", "patches.february_2013.remove_account_utils_folder", "patches.february_2013.update_company_in_leave_application", - "execute:webnotes.conn.sql_ddl('alter table tabSeries change `name` `name` varchar(100)')" + "execute:webnotes.conn.sql_ddl('alter table tabSeries change `name` `name` varchar(100)')", ] \ No newline at end of file From 86af352bf3bde1f84715f00eba1c9633e7c8bf86 Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Wed, 13 Feb 2013 18:04:21 +0530 Subject: [PATCH 2/8] fixes in parentfield of userrole --- patches/patch_list.py | 1 + 1 file changed, 1 insertion(+) diff --git a/patches/patch_list.py b/patches/patch_list.py index 97bdc52e79..c00744ea36 100644 --- a/patches/patch_list.py +++ b/patches/patch_list.py @@ -168,4 +168,5 @@ patch_list = [ "patches.february_2013.remove_account_utils_folder", "patches.february_2013.update_company_in_leave_application", "execute:webnotes.conn.sql_ddl('alter table tabSeries change `name` `name` varchar(100)')", + "execute:webnotes.conn.sql('update tabUserRole set parentfield=\"user_roles\" where parentfield=\"userroles\"')", ] \ No newline at end of file From eb92b52817667a2e0b20417f88a3242fadd2ae6f Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Wed, 13 Feb 2013 18:30:53 +0530 Subject: [PATCH 3/8] fixes in employee form --- hr/doctype/employee/employee.py | 45 ++++++++++++++++++++++++++------- 1 file changed, 36 insertions(+), 9 deletions(-) diff --git a/hr/doctype/employee/employee.py b/hr/doctype/employee/employee.py index 6846c5efba..16d8bff3ba 100644 --- a/hr/doctype/employee/employee.py +++ b/hr/doctype/employee/employee.py @@ -63,18 +63,45 @@ class DocType: return ret_sal_struct and ret_sal_struct[0][0] or '' def on_update(self): - self.update_user_default() + if self.doc.user_id: + self.update_user_default() + self.update_profile() def update_user_default(self): - if self.doc.user_id: - webnotes.conn.set_default("employee", self.doc.name, self.doc.user_id) - webnotes.conn.set_default("employee_name", self.doc.employee_name, self.doc.user_id) - webnotes.conn.set_default("company", self.doc.company, self.doc.user_id) - - # add employee role if missing - if not "Employee" in webnotes.conn.sql_list("""select role from tabUserRole + webnotes.conn.set_default("employee", self.doc.name, self.doc.user_id) + webnotes.conn.set_default("employee_name", self.doc.employee_name, self.doc.user_id) + webnotes.conn.set_default("company", self.doc.company, self.doc.user_id) + + def update_profile(self): + profile_wrapper = webnotes.model_wrapper("Profile", self.doc.user_id) + + # add employee role if missing + if not "Employee" in webnotes.conn.sql_list("""select role from tabUserRole where parent=%s""", self.doc.user_id): - webnotes.get_obj("Profile", self.doc.user_id).add_role("Employee") + profile_wrapper.doclist.append({ + "doctype": "UserRole", + "parentfield": "user_roles", + "role": "Employee" + }) + + # copy details like Fullname, DOB and Image to Profile + if self.doc.employee_name: + employee_name = self.doc.employee_name.split(" ") + if len(employee_name) >= 3: + profile_wrapper.doc.last_name = " ".join(employee_name[2:]) + profile_wrapper.doc.middle_name = employee_name[1] + elif len(employee_name) == 2: + profile_wrapper.doc.last_name = employee_name[1] + + profile_wrapper.doc.first_name = employee_name[0] + + if self.doc.date_of_birth: + profile_wrapper.doc.birth_date = self.doc.date_of_birth + + if self.doc.gender: + profile_wrapper.doc.gender = self.doc.gender + + profile_wrapper.save() def validate_date(self): import datetime From c45630faf893bc8d35cbd35ac576efb5f6849042 Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Wed, 13 Feb 2013 18:35:33 +0530 Subject: [PATCH 4/8] added add_role method in profile --- hr/doctype/employee/employee.py | 7 ++----- hr/doctype/leave_application/test_leave_application.py | 5 ++++- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/hr/doctype/employee/employee.py b/hr/doctype/employee/employee.py index 16d8bff3ba..ff030780fc 100644 --- a/hr/doctype/employee/employee.py +++ b/hr/doctype/employee/employee.py @@ -78,11 +78,8 @@ class DocType: # add employee role if missing if not "Employee" in webnotes.conn.sql_list("""select role from tabUserRole where parent=%s""", self.doc.user_id): - profile_wrapper.doclist.append({ - "doctype": "UserRole", - "parentfield": "user_roles", - "role": "Employee" - }) + from core.doctype.profile.profile import add_role + add_role(self.doc.user_id, "HR User") # copy details like Fullname, DOB and Image to Profile if self.doc.employee_name: diff --git a/hr/doctype/leave_application/test_leave_application.py b/hr/doctype/leave_application/test_leave_application.py index 7195826bf9..ead0d0cddd 100644 --- a/hr/doctype/leave_application/test_leave_application.py +++ b/hr/doctype/leave_application/test_leave_application.py @@ -19,7 +19,10 @@ class TestLeaveApplication(unittest.TestCase): self.assertRaises(LeaveDayBlockedError, application.insert) webnotes.session.user = "test1@erpnext.com" - webnotes.get_obj("Profile", "test1@erpnext.com").add_role("HR User") + + from core.doctype.profile.profile import add_role + add_role("test1@erpnext.com", "HR User") + self.assertTrue(application.insert()) def test_global_block_list(self): From 223072be022f42b72105a6d61bb582c5c9752e9d Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Wed, 13 Feb 2013 18:53:08 +0530 Subject: [PATCH 5/8] when saving employee add employee image to profile --- hr/doctype/employee/employee.py | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/hr/doctype/employee/employee.py b/hr/doctype/employee/employee.py index ff030780fc..e357ff4907 100644 --- a/hr/doctype/employee/employee.py +++ b/hr/doctype/employee/employee.py @@ -73,13 +73,13 @@ class DocType: webnotes.conn.set_default("company", self.doc.company, self.doc.user_id) def update_profile(self): - profile_wrapper = webnotes.model_wrapper("Profile", self.doc.user_id) - # add employee role if missing if not "Employee" in webnotes.conn.sql_list("""select role from tabUserRole where parent=%s""", self.doc.user_id): from core.doctype.profile.profile import add_role add_role(self.doc.user_id, "HR User") + + profile_wrapper = webnotes.model_wrapper("Profile", self.doc.user_id) # copy details like Fullname, DOB and Image to Profile if self.doc.employee_name: @@ -97,9 +97,22 @@ class DocType: if self.doc.gender: profile_wrapper.doc.gender = self.doc.gender - - profile_wrapper.save() - + + if self.doc.image and self.doc.file_list: + # add to file list and user_image + for file_args in self.doc.file_list.split("\n"): + fname, fid = file_args.split(",") + if self.doc.image == fname: + new_file_args = fname + "," + fid + file_list = profile_wrapper.doc.file_list.split("\n") + if new_file_args not in file_list: + file_list += [new_file_args] + profile_wrapper.doc.file_list = "\n".join(file_list) + profile_wrapper.doc.user_image = fname + break + + profile_wrapper.save() + def validate_date(self): import datetime if self.doc.date_of_birth and self.doc.date_of_joining and getdate(self.doc.date_of_birth) >= getdate(self.doc.date_of_joining): From 5070224079cd9527581e3aee9857759a33c9dd26 Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Wed, 13 Feb 2013 19:49:42 +0530 Subject: [PATCH 6/8] select leave approver by fullname in leave application --- home/page/latest_updates/latest_updates.js | 5 +++++ hr/doctype/leave_application/leave_application.js | 6 +++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/home/page/latest_updates/latest_updates.js b/home/page/latest_updates/latest_updates.js index 7e28824229..dea571d177 100644 --- a/home/page/latest_updates/latest_updates.js +++ b/home/page/latest_updates/latest_updates.js @@ -1,4 +1,9 @@ erpnext.updates = [ + ["13th February, 2013", [ + "Employee: If Employee is linked to a Profile, copy Full Name, Date of Birth, \ + Image and Gender to Profile", + "Leave Application: Select Leave Approver by their Full Name", + ]], ["6th February, 2013", [ "Bookmarks: Add bookmarks via toolbar by clicking on the sign.", ]], diff --git a/hr/doctype/leave_application/leave_application.js b/hr/doctype/leave_application/leave_application.js index 3c26a51d25..9df348a17e 100755 --- a/hr/doctype/leave_application/leave_application.js +++ b/hr/doctype/leave_application/leave_application.js @@ -23,10 +23,14 @@ cur_frm.cscript.onload = function(doc, dt, dn) { if(doc.__islocal) { cur_frm.set_value("status", "Open") } + cur_frm.set_df_property("leave_approver", "options", ""); cur_frm.call({ method:"get_approver_list", callback: function(r) { - cur_frm.set_df_property("leave_approver", "options", r.message); + cur_frm.set_df_property("leave_approver", "options", $.map(r.message, + function(profile) { + return {value: profile, label: wn.user_info(profile).fullname}; + })); cur_frm.cscript.get_leave_balance(cur_frm.doc); } }); From 798c6b4fdb5b63d94ef41680e8a1b9017d5f1362 Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Wed, 13 Feb 2013 19:57:58 +0530 Subject: [PATCH 7/8] fixes in test runner and add role for profile --- hr/doctype/employee/employee.py | 2 +- hr/doctype/leave_application/leave_application.py | 4 +++- hr/doctype/leave_application/test_leave_application.py | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/hr/doctype/employee/employee.py b/hr/doctype/employee/employee.py index e357ff4907..cef6fdc697 100644 --- a/hr/doctype/employee/employee.py +++ b/hr/doctype/employee/employee.py @@ -76,7 +76,7 @@ class DocType: # add employee role if missing if not "Employee" in webnotes.conn.sql_list("""select role from tabUserRole where parent=%s""", self.doc.user_id): - from core.doctype.profile.profile import add_role + from webnotes.profile import add_role add_role(self.doc.user_id, "HR User") profile_wrapper = webnotes.model_wrapper("Profile", self.doc.user_id) diff --git a/hr/doctype/leave_application/leave_application.py b/hr/doctype/leave_application/leave_application.py index 204514789e..bc685dfd55 100755 --- a/hr/doctype/leave_application/leave_application.py +++ b/hr/doctype/leave_application/leave_application.py @@ -78,7 +78,9 @@ class DocType: if block_date > from_date and block_date < to_date: webnotes.msgprint(_("You cannot apply for a leave on the following date because it is blocked") + ": " + formatdate(d.block_date) + _(" Reason: ") + d.reason) - raise LeaveDayBlockedError + if self.doc.docstatus == 1: + # throw exception only when submitting + raise LeaveDayBlockedError def is_user_in_allow_list(self, block_list): return webnotes.session.user in webnotes.conn.sql_list("""select allow_user diff --git a/hr/doctype/leave_application/test_leave_application.py b/hr/doctype/leave_application/test_leave_application.py index ead0d0cddd..8fe11d66cc 100644 --- a/hr/doctype/leave_application/test_leave_application.py +++ b/hr/doctype/leave_application/test_leave_application.py @@ -20,7 +20,7 @@ class TestLeaveApplication(unittest.TestCase): webnotes.session.user = "test1@erpnext.com" - from core.doctype.profile.profile import add_role + from webnotes.profile import add_role add_role("test1@erpnext.com", "HR User") self.assertTrue(application.insert()) From 9c35b2897cc2bcf8b65b9ee9850603255e6f7e5b Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Wed, 13 Feb 2013 20:26:45 +0530 Subject: [PATCH 8/8] raise holiday block list exception only when submitting --- hr/doctype/employee/test_employee.py | 18 +++++-- .../test_holiday_block_list.py | 2 +- .../test_leave_application.py | 53 +++++++++++++++---- 3 files changed, 58 insertions(+), 15 deletions(-) diff --git a/hr/doctype/employee/test_employee.py b/hr/doctype/employee/test_employee.py index a9c715b9d8..01c2087ec0 100644 --- a/hr/doctype/employee/test_employee.py +++ b/hr/doctype/employee/test_employee.py @@ -7,7 +7,7 @@ test_records = [[{ "gender": "Female", "status": "Active", "company": "_Test Company", - "user_id": "test@erpnext.com" + "user_id": "test@example.com" }], [{ "doctype":"Employee", @@ -18,5 +18,17 @@ test_records = [[{ "gender": "Male", "status": "Active", "company": "_Test Company", - "user_id": "test1@erpnext.com" -}]] \ No newline at end of file + "user_id": "test1@example.com" +}], +[{ + "doctype":"Employee", + "employee_name": "_Test Employee 2", + "naming_series": "_T-Employee-", + "date_of_joining": "2010-01-01", + "date_of_birth": "1980-01-01", + "gender": "Male", + "status": "Active", + "company": "_Test Company", + "user_id": "test2@example.com" +}] +] \ No newline at end of file diff --git a/hr/doctype/holiday_block_list/test_holiday_block_list.py b/hr/doctype/holiday_block_list/test_holiday_block_list.py index 5ec4dd1af5..e9f3b78472 100644 --- a/hr/doctype/holiday_block_list/test_holiday_block_list.py +++ b/hr/doctype/holiday_block_list/test_holiday_block_list.py @@ -15,6 +15,6 @@ test_records = [[{ "parent": "_Test Holiday Block List", "parenttype": "Holiday Block List", "parentfield": "holiday_block_list_allowed", - "allow_user": "test1@erpnext.com", + "allow_user": "test1@example.com", } ]] \ No newline at end of file diff --git a/hr/doctype/leave_application/test_leave_application.py b/hr/doctype/leave_application/test_leave_application.py index 8fe11d66cc..cd74d01399 100644 --- a/hr/doctype/leave_application/test_leave_application.py +++ b/hr/doctype/leave_application/test_leave_application.py @@ -4,8 +4,8 @@ import unittest from hr.doctype.leave_application.leave_application import LeaveDayBlockedError class TestLeaveApplication(unittest.TestCase): - def get_application(self): - application = webnotes.model_wrapper(test_records[1]) + def get_application(self, doclist): + application = webnotes.model_wrapper(doclist) application.doc.from_date = "2013-01-01" application.doc.to_date = "2013-01-05" return application @@ -15,25 +15,37 @@ class TestLeaveApplication(unittest.TestCase): webnotes.conn.set_value("Employee", "_T-Employee-0001", "department", "_Test Department with Block List") - application = self.get_application() - self.assertRaises(LeaveDayBlockedError, application.insert) + application = self.get_application(test_records[1]) + application.insert() + self.assertRaises(LeaveDayBlockedError, application.submit) - webnotes.session.user = "test1@erpnext.com" + webnotes.session.user = "test1@example.com" from webnotes.profile import add_role - add_role("test1@erpnext.com", "HR User") + add_role("test1@example.com", "HR User") + application = self.get_application(test_records[1]) self.assertTrue(application.insert()) def test_global_block_list(self): - application = self.get_application() + application = self.get_application(test_records[3]) + application.doc.leave_approver = "test@example.com" webnotes.conn.set_value("Holiday Block List", "_Test Holiday Block List", "applies_to_all_departments", 1) - webnotes.conn.set_value("Employee", "_T-Employee-0001", "department", + webnotes.conn.set_value("Employee", "_T-Employee-0002", "department", "_Test Department") - webnotes.session.user = "test@erpnext.com" + + webnotes.session.user = "test2@example.com" + from webnotes.profile import add_role + add_role("test2@example.com", "Employee") - self.assertRaises(LeaveDayBlockedError, application.insert) + application.insert() + + webnotes.session.user = "test@example.com" + from webnotes.profile import add_role + add_role("test@example.com", "Leave Approver") + + self.assertRaises(LeaveDayBlockedError, application.submit) test_records = [ [{ @@ -53,4 +65,23 @@ test_records = [ "fiscal_year": "_Test Fiscal Year 2013", "employee": "_T-Employee-0001", "company": "_Test Company" - }]] + }], + [{ + "doctype": "Leave Allocation", + "leave_type": "_Test Leave Type", + "fiscal_year": "_Test Fiscal Year 2013", + "employee":"_T-Employee-0002", + "new_leaves_allocated": 15, + "docstatus": 1 + }], + [{ + "doctype": "Leave Application", + "leave_type": "_Test Leave Type", + "from_date": "2013-05-01", + "to_date": "2013-05-05", + "posting_date": "2013-01-02", + "fiscal_year": "_Test Fiscal Year 2013", + "employee": "_T-Employee-0002", + "company": "_Test Company" + }] +]