From 0aec0e1a63ee29ea2368d779d1b7fa064d905f2f Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Tue, 10 Jul 2012 14:24:45 +0530 Subject: [PATCH 1/9] repost balance button removed from period closing voucher --- .../period_closing_voucher.py | 288 ++++++++---------- .../period_closing_voucher.txt | 41 +-- 2 files changed, 130 insertions(+), 199 deletions(-) diff --git a/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.py b/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.py index 1b59bc616ed..184df70c15c 100644 --- a/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.py +++ b/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.py @@ -8,11 +8,11 @@ # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with this program. If not, see . +# along with this program. If not, see . # Please edit this list and import only required elements import webnotes @@ -34,179 +34,147 @@ convert_to_lists = webnotes.conn.convert_to_lists class DocType: - def __init__(self,d,dl): - self.doc, self.doclist = d, dl - self.td, self.tc = 0, 0 - self.year_start_date = '' - self.year_end_date = '' + def __init__(self,d,dl): + self.doc, self.doclist = d, dl + self.td, self.tc = 0, 0 + self.year_start_date = '' + self.year_end_date = '' - # Validate Account Head - #============================================================ - def validate_account_head(self): - acc_det = sql("select debit_or_credit, is_pl_account, group_or_ledger, company from `tabAccount` where name = '%s'" % (self.doc.closing_account_head)) + def validate_account_head(self): + acc_det = sql("select debit_or_credit, is_pl_account, group_or_ledger, company from `tabAccount` where name = '%s'" % (self.doc.closing_account_head)) - # Account should be under liability - if cstr(acc_det[0][0]) != 'Credit' or cstr(acc_det[0][1]) != 'No': - msgprint("Account: %s must be created under 'Source of Funds'" % self.doc.closing_account_head) - raise Exception - - # Account must be a ledger - if cstr(acc_det[0][2]) != 'Ledger': - msgprint("Account %s must be a ledger" % self.doc.closing_account_head) - raise Exception - - # Account should belong to company selected - if cstr(acc_det[0][3]) != self.doc.company: - msgprint("Account %s does not belong to Company %s ." % (self.doc.closing_account_head, self.doc.company)) - raise Exception + # Account should be under liability + if cstr(acc_det[0][0]) != 'Credit' or cstr(acc_det[0][1]) != 'No': + msgprint("Account: %s must be created under 'Source of Funds'" % self.doc.closing_account_head) + raise Exception + + # Account must be a ledger + if cstr(acc_det[0][2]) != 'Ledger': + msgprint("Account %s must be a ledger" % self.doc.closing_account_head) + raise Exception + + # Account should belong to company selected + if cstr(acc_det[0][3]) != self.doc.company: + msgprint("Account %s does not belong to Company %s ." % (self.doc.closing_account_head, self.doc.company)) + raise Exception - # validate posting date - #============================================================= - def validate_posting_date(self): - yr = sql("select start_date, end_date from `tabPeriod` where period_name = '%s'" % (self.doc.fiscal_year)) - self.year_start_date = yr and yr[0][0] or '' - self.year_end_date = yr and yr[0][1] or '' - - # Posting Date should be within closing year - if getdate(self.doc.posting_date) < self.year_start_date or getdate(self.doc.posting_date) > self.year_end_date: - msgprint("Posting Date should be within Closing Fiscal Year") - raise Exception - # Period Closing Entry - pce = sql("select name from `tabPeriod Closing Voucher` where posting_date > '%s' and fiscal_year = '%s' and docstatus = 1" % (self.doc.posting_date, self.doc.fiscal_year)) - if pce and pce[0][0]: - msgprint("Another Period Closing Entry: %s has been made after posting date: %s" % (cstr(pce[0][0]), self.doc.posting_date)) - raise Exception - - # Validate closing entry requirement - #========================================================== - def validate_pl_balances(self): - income_bal = sql("select sum(ifnull(t1.debit,0))-sum(ifnull(t1.credit,0)) from `tabGL Entry` t1, tabAccount t2 where t1.account = t2.name and t1.posting_date between '%s' and '%s' and t2.debit_or_credit = 'Credit' and t2.group_or_ledger = 'Ledger' and ifnull(t2.freeze_account, 'No') = 'No' and t2.is_pl_account = 'Yes' and t2.docstatus < 2 and t2.company = '%s'" % (self.year_start_date, self.doc.posting_date, self.doc.company)) - expense_bal = sql("select sum(ifnull(t1.debit,0))-sum(ifnull(t1.credit,0)) from `tabGL Entry` t1, tabAccount t2 where t1.account = t2.name and t1.posting_date between '%s' and '%s' and t2.debit_or_credit = 'Debit' and t2.group_or_ledger = 'Ledger' and ifnull(t2.freeze_account, 'No') = 'No' and t2.is_pl_account = 'Yes' and t2.docstatus < 2 and t2.company = '%s'" % (self.year_start_date, self.doc.posting_date, self.doc.company)) - - income_bal = income_bal and income_bal[0][0] or 0 - expense_bal = expense_bal and expense_bal[0][0] or 0 - - if not income_bal and not expense_bal: - msgprint("Both Income and Expense balances are zero. No Need to make Period Closing Entry.") - raise Exception - - # Get account (pl) specific balance - #=========================================================== - def get_pl_balances(self, d_or_c): - acc_bal = sql("select t1.account, sum(ifnull(t1.debit,0))-sum(ifnull(t1.credit,0)) from `tabGL Entry` t1, `tabAccount` t2 where t1.account = t2.name and t2.group_or_ledger = 'Ledger' and ifnull(t2.freeze_account, 'No') = 'No' and ifnull(t2.is_pl_account, 'No') = 'Yes' and ifnull(is_cancelled, 'No') = 'No' and t2.debit_or_credit = '%s' and t2.docstatus < 2 and t2.company = '%s' and t1.posting_date between '%s' and '%s' group by t1.account " % (d_or_c, self.doc.company, self.year_start_date, self.doc.posting_date)) - return acc_bal + def validate_posting_date(self): + yr = sql("select start_date, end_date from `tabPeriod` where period_name = '%s'" % (self.doc.fiscal_year)) + self.year_start_date = yr and yr[0][0] or '' + self.year_end_date = yr and yr[0][1] or '' + + # Posting Date should be within closing year + if getdate(self.doc.posting_date) < self.year_start_date or getdate(self.doc.posting_date) > self.year_end_date: + msgprint("Posting Date should be within Closing Fiscal Year") + raise Exception - - # Makes GL Entries - # ========================================================== - def make_gl_entries(self, acc_det): - for a in acc_det: - if flt(a[1]): - fdict = { - 'account': a[0], - 'cost_center': '', - 'against': '', - 'debit': flt(a[1]) < 0 and -1*flt(a[1]) or 0, - 'credit': flt(a[1]) > 0 and flt(a[1]) or 0, - 'remarks': self.doc.remarks, - 'voucher_type': self.doc.doctype, - 'voucher_no': self.doc.name, - 'transaction_date': self.doc.transaction_date, - 'posting_date': self.doc.posting_date, - 'fiscal_year': self.doc.fiscal_year, - 'against_voucher': '', - 'against_voucher_type': '', - 'company': self.doc.company, - 'is_opening': 'No', - 'aging_date': self.doc.posting_date - } - - self.save_entry(fdict) - + # Period Closing Entry + pce = sql("select name from `tabPeriod Closing Voucher` where posting_date > '%s' and fiscal_year = '%s' and docstatus = 1" % (self.doc.posting_date, self.doc.fiscal_year)) + if pce and pce[0][0]: + msgprint("Another Period Closing Entry: %s has been made after posting date: %s" % (cstr(pce[0][0]), self.doc.posting_date)) + raise Exception + + + def validate_pl_balances(self): + income_bal = sql("select sum(ifnull(t1.debit,0))-sum(ifnull(t1.credit,0)) from `tabGL Entry` t1, tabAccount t2 where t1.account = t2.name and t1.posting_date between '%s' and '%s' and t2.debit_or_credit = 'Credit' and t2.group_or_ledger = 'Ledger' and ifnull(t2.freeze_account, 'No') = 'No' and t2.is_pl_account = 'Yes' and t2.docstatus < 2 and t2.company = '%s'" % (self.year_start_date, self.doc.posting_date, self.doc.company)) + expense_bal = sql("select sum(ifnull(t1.debit,0))-sum(ifnull(t1.credit,0)) from `tabGL Entry` t1, tabAccount t2 where t1.account = t2.name and t1.posting_date between '%s' and '%s' and t2.debit_or_credit = 'Debit' and t2.group_or_ledger = 'Ledger' and ifnull(t2.freeze_account, 'No') = 'No' and t2.is_pl_account = 'Yes' and t2.docstatus < 2 and t2.company = '%s'" % (self.year_start_date, self.doc.posting_date, self.doc.company)) + + income_bal = income_bal and income_bal[0][0] or 0 + expense_bal = expense_bal and expense_bal[0][0] or 0 + + if not income_bal and not expense_bal: + msgprint("Both Income and Expense balances are zero. No Need to make Period Closing Entry.") + raise Exception + + + def get_pl_balances(self, d_or_c): + """Get account (pl) specific balance""" + acc_bal = sql("select t1.account, sum(ifnull(t1.debit,0))-sum(ifnull(t1.credit,0)) from `tabGL Entry` t1, `tabAccount` t2 where t1.account = t2.name and t2.group_or_ledger = 'Ledger' and ifnull(t2.freeze_account, 'No') = 'No' and ifnull(t2.is_pl_account, 'No') = 'Yes' and ifnull(is_cancelled, 'No') = 'No' and t2.debit_or_credit = '%s' and t2.docstatus < 2 and t2.company = '%s' and t1.posting_date between '%s' and '%s' group by t1.account " % (d_or_c, self.doc.company, self.year_start_date, self.doc.posting_date)) + return acc_bal + + + def make_gl_entries(self, acc_det): + for a in acc_det: + if flt(a[1]): + fdict = { + 'account': a[0], + 'cost_center': '', + 'against': '', + 'debit': flt(a[1]) < 0 and -1*flt(a[1]) or 0, + 'credit': flt(a[1]) > 0 and flt(a[1]) or 0, + 'remarks': self.doc.remarks, + 'voucher_type': self.doc.doctype, + 'voucher_no': self.doc.name, + 'transaction_date': self.doc.transaction_date, + 'posting_date': self.doc.posting_date, + 'fiscal_year': self.doc.fiscal_year, + 'against_voucher': '', + 'against_voucher_type': '', + 'company': self.doc.company, + 'is_opening': 'No', + 'aging_date': self.doc.posting_date + } + + self.save_entry(fdict) + + + def save_entry(self, fdict, is_cancel = 'No'): + # Create new GL entry object and map values + le = Document('GL Entry') + for k in fdict: + le.fields[k] = fdict[k] + + le_obj = get_obj(doc=le) + # validate except on_cancel + if is_cancel == 'No': + le_obj.validate() + + # update total debit / credit except on_cancel + self.td += flt(le.credit) + self.tc += flt(le.debit) + + # save + le.save(1) + le_obj.on_update(adv_adj = '', cancel = '') - # Save GL Entry - # ========================================================== - def save_entry(self, fdict, is_cancel = 'No'): - # Create new GL entry object and map values - le = Document('GL Entry') - for k in fdict: - le.fields[k] = fdict[k] - - le_obj = get_obj(doc=le) - # validate except on_cancel - if is_cancel == 'No': - le_obj.validate() - - # update total debit / credit except on_cancel - self.td += flt(le.credit) - self.tc += flt(le.debit) + + def validate(self): + # validate account head + self.validate_account_head() - # save - le.save(1) - le_obj.on_update(adv_adj = '', cancel = '') - + # validate posting date + self.validate_posting_date() - # Reposting Balances - # ========================================================== - def repost_account_balances(self): - # Get Next Fiscal Year - fy = sql("select name, is_fiscal_year_closed from `tabFiscal Year` where name = '%s' and past_year = '%s'" % (self.doc.next_fiscal_year, self.doc.fiscal_year)) - if not fy: - msgprint("There is no Fiscal Year with Name " + cstr(self.doc.next_fiscal_year) + " and Past Year " + cstr(self.doc.fiscal_year)) - raise Exception - - if fy and fy[0][1] == 'Yes': - msgprint("Fiscal Year %s has been closed." % cstr(fy[1])) - raise Exception - - # Repost Balances - get_obj('Fiscal Year', fy[0][0]).repost() - - - # Validation - # =========================================================== - def validate(self): - - # validate account head - self.validate_account_head() - - # validate posting date - self.validate_posting_date() - - # check if pl balance: - self.validate_pl_balances() + # check if pl balance: + self.validate_pl_balances() - # On Submit - # =========================================================== - def on_submit(self): - - # Makes closing entries for Expense Account - in_acc_det = self.get_pl_balances('Credit') - self.make_gl_entries(in_acc_det) + def on_submit(self): + + # Makes closing entries for Expense Account + in_acc_det = self.get_pl_balances('Credit') + self.make_gl_entries(in_acc_det) - # Makes closing entries for Expense Account - ex_acc_det = self.get_pl_balances('Debit') - self.make_gl_entries(ex_acc_det) + # Makes closing entries for Expense Account + ex_acc_det = self.get_pl_balances('Debit') + self.make_gl_entries(ex_acc_det) - # Makes Closing entry for Closing Account Head - bal = self.tc - self.td - self.make_gl_entries([[self.doc.closing_account_head, flt(bal)]]) + # Makes Closing entry for Closing Account Head + bal = self.tc - self.td + self.make_gl_entries([[self.doc.closing_account_head, flt(bal)]]) - # On Cancel - # ============================================================= - def on_cancel(self): - # get all submit entries of current closing entry voucher - gl_entries = sql("select account, debit, credit from `tabGL Entry` where voucher_type = 'Period Closing Voucher' and voucher_no = '%s' and ifnull(is_cancelled, 'No') = 'No'" % (self.doc.name)) + def on_cancel(self): + # get all submit entries of current closing entry voucher + gl_entries = sql("select account, debit, credit from `tabGL Entry` where voucher_type = 'Period Closing Voucher' and voucher_no = '%s' and ifnull(is_cancelled, 'No') = 'No'" % (self.doc.name)) - # Swap Debit & Credit Column and make gl entry - for gl in gl_entries: - fdict = {'account': gl[0], 'cost_center': '', 'against': '', 'debit': flt(gl[2]), 'credit' : flt(gl[1]), 'remarks': self.doc.cancel_reason, 'voucher_type': self.doc.doctype, 'voucher_no': self.doc.name, 'transaction_date': self.doc.transaction_date, 'posting_date': self.doc.posting_date, 'fiscal_year': self.doc.fiscal_year, 'against_voucher': '', 'against_voucher_type': '', 'company': self.doc.company, 'is_opening': 'No', 'aging_date': 'self.doc.posting_date'} - self.save_entry(fdict, is_cancel = 'Yes') + # Swap Debit & Credit Column and make gl entry + for gl in gl_entries: + fdict = {'account': gl[0], 'cost_center': '', 'against': '', 'debit': flt(gl[2]), 'credit' : flt(gl[1]), 'remarks': self.doc.cancel_reason, 'voucher_type': self.doc.doctype, 'voucher_no': self.doc.name, 'transaction_date': self.doc.transaction_date, 'posting_date': self.doc.posting_date, 'fiscal_year': self.doc.fiscal_year, 'against_voucher': '', 'against_voucher_type': '', 'company': self.doc.company, 'is_opening': 'No', 'aging_date': 'self.doc.posting_date'} + self.save_entry(fdict, is_cancel = 'Yes') - # Update is_cancelled = 'Yes' to all gl entries for current voucher - sql("update `tabGL Entry` set is_cancelled = 'Yes' where voucher_type = '%s' and voucher_no = '%s'" % (self.doc.doctype, self.doc.name)) + # Update is_cancelled = 'Yes' to all gl entries for current voucher + sql("update `tabGL Entry` set is_cancelled = 'Yes' where voucher_type = '%s' and voucher_no = '%s'" % (self.doc.doctype, self.doc.name)) \ No newline at end of file diff --git a/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.txt b/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.txt index c70745e7e22..f56c1b0c938 100644 --- a/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.txt +++ b/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.txt @@ -3,9 +3,9 @@ # These values are common in all dictionaries { - 'creation': '2012-04-13 11:56:17', + 'creation': '2012-06-11 12:09:52', 'docstatus': 0, - 'modified': '2012-05-31 11:38:17', + 'modified': '2012-07-10 14:21:21', 'modified_by': u'Administrator', 'owner': u'jai@webnotestech.com' }, @@ -273,42 +273,5 @@ 'permlevel': 0, 'print_hide': 1, 'search_index': 0 - }, - - # DocField - { - 'doctype': u'DocField', - 'fieldname': u'repost_account_balances', - 'fieldtype': u'Section Break', - 'label': u'Repost Account Balances', - 'oldfieldtype': u'Section Break', - 'options': u'Simple', - 'permlevel': 0 - }, - - # DocField - { - 'allow_on_submit': 1, - 'doctype': u'DocField', - 'fieldname': u'next_fiscal_year', - 'fieldtype': u'Select', - 'label': u'Fiscal Year (For Reposting)', - 'oldfieldname': u'next_fiscal_year', - 'oldfieldtype': u'Select', - 'options': u'link:Fiscal Year', - 'permlevel': 0 - }, - - # DocField - { - 'allow_on_submit': 1, - 'colour': u'White:FFF', - 'doctype': u'DocField', - 'fieldname': u'repost', - 'fieldtype': u'Button', - 'label': u'Repost', - 'oldfieldtype': u'Button', - 'options': u'repost_account_balances', - 'permlevel': 0 } ] \ No newline at end of file From 29d76412063915c068462cc441e844e6cb9cf9fd Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Tue, 10 Jul 2012 18:12:00 +0530 Subject: [PATCH 2/9] fixed issue in period closing voucher: consider freezed account for closing --- .../period_closing_voucher.js | 2 +- .../period_closing_voucher.py | 30 +++++++++++++++---- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.js b/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.js index c4288a40b55..a27eccef528 100644 --- a/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.js +++ b/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.js @@ -34,5 +34,5 @@ cur_frm.cscript.refresh = function(doc, cdt, cdn) { // ***************** Get Account Head ***************** cur_frm.fields_dict['closing_account_head'].get_query = function(doc, cdt, cdn) { - return 'SELECT `tabAccount`.name FROM `tabAccount` WHERE `tabAccount`.is_pl_account = "No" AND `tabAccount`.debit_or_credit = "Credit" AND `tabAccount`.company = "'+ cstr(doc.company) +'" AND `tabAccount`.freeze_account = "No" AND `tabAccount`.group_or_ledger = "Ledger" AND `tabAccount`.%(key)s LIKE "%s" ORDER BY `tabAccount`.name ASC LIMIT 50'; + return 'SELECT `tabAccount`.name FROM `tabAccount` WHERE `tabAccount`.is_pl_account = "No" AND `tabAccount`.debit_or_credit = "Credit" AND `tabAccount`.company = "'+ cstr(doc.company) +'" AND ifnull(`tabAccount`.freeze_account, "No") = "No" AND `tabAccount`.group_or_ledger = "Ledger" AND `tabAccount`.%(key)s LIKE "%s" ORDER BY `tabAccount`.name ASC LIMIT 50'; } diff --git a/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.py b/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.py index 184df70c15c..f4cf47d23ee 100644 --- a/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.py +++ b/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.py @@ -42,7 +42,8 @@ class DocType: def validate_account_head(self): - acc_det = sql("select debit_or_credit, is_pl_account, group_or_ledger, company from `tabAccount` where name = '%s'" % (self.doc.closing_account_head)) + acc_det = sql("select debit_or_credit, is_pl_account, group_or_ledger, company \ + from `tabAccount` where name = '%s'" % (self.doc.closing_account_head)) # Account should be under liability if cstr(acc_det[0][0]) != 'Credit' or cstr(acc_det[0][1]) != 'No': @@ -71,15 +72,27 @@ class DocType: raise Exception # Period Closing Entry - pce = sql("select name from `tabPeriod Closing Voucher` where posting_date > '%s' and fiscal_year = '%s' and docstatus = 1" % (self.doc.posting_date, self.doc.fiscal_year)) + pce = sql("select name from `tabPeriod Closing Voucher` \ + where posting_date > '%s' and fiscal_year = '%s' and docstatus = 1" \ + % (self.doc.posting_date, self.doc.fiscal_year)) if pce and pce[0][0]: - msgprint("Another Period Closing Entry: %s has been made after posting date: %s" % (cstr(pce[0][0]), self.doc.posting_date)) + msgprint("Another Period Closing Entry: %s has been made after posting date: %s"\ + % (cstr(pce[0][0]), self.doc.posting_date)) raise Exception def validate_pl_balances(self): - income_bal = sql("select sum(ifnull(t1.debit,0))-sum(ifnull(t1.credit,0)) from `tabGL Entry` t1, tabAccount t2 where t1.account = t2.name and t1.posting_date between '%s' and '%s' and t2.debit_or_credit = 'Credit' and t2.group_or_ledger = 'Ledger' and ifnull(t2.freeze_account, 'No') = 'No' and t2.is_pl_account = 'Yes' and t2.docstatus < 2 and t2.company = '%s'" % (self.year_start_date, self.doc.posting_date, self.doc.company)) - expense_bal = sql("select sum(ifnull(t1.debit,0))-sum(ifnull(t1.credit,0)) from `tabGL Entry` t1, tabAccount t2 where t1.account = t2.name and t1.posting_date between '%s' and '%s' and t2.debit_or_credit = 'Debit' and t2.group_or_ledger = 'Ledger' and ifnull(t2.freeze_account, 'No') = 'No' and t2.is_pl_account = 'Yes' and t2.docstatus < 2 and t2.company = '%s'" % (self.year_start_date, self.doc.posting_date, self.doc.company)) + income_bal = sql("select sum(ifnull(t1.debit,0))-sum(ifnull(t1.credit,0)) \ + from `tabGL Entry` t1, tabAccount t2 where t1.account = t2.name \ + and t1.posting_date between '%s' and '%s' and t2.debit_or_credit = 'Credit' \ + and t2.group_or_ledger = 'Ledger' and t2.is_pl_account = 'Yes' and t2.docstatus < 2 \ + and t2.company = '%s'" % (self.year_start_date, self.doc.posting_date, self.doc.company)) + + expense_bal = sql("select sum(ifnull(t1.debit,0))-sum(ifnull(t1.credit,0)) \ + from `tabGL Entry` t1, tabAccount t2 where t1.account = t2.name \ + and t1.posting_date between '%s' and '%s' and t2.debit_or_credit = 'Debit' \ + and t2.group_or_ledger = 'Ledger' and t2.is_pl_account = 'Yes' and t2.docstatus < 2 \ + and t2.company = '%s'" % (self.year_start_date, self.doc.posting_date, self.doc.company)) income_bal = income_bal and income_bal[0][0] or 0 expense_bal = expense_bal and expense_bal[0][0] or 0 @@ -91,7 +104,12 @@ class DocType: def get_pl_balances(self, d_or_c): """Get account (pl) specific balance""" - acc_bal = sql("select t1.account, sum(ifnull(t1.debit,0))-sum(ifnull(t1.credit,0)) from `tabGL Entry` t1, `tabAccount` t2 where t1.account = t2.name and t2.group_or_ledger = 'Ledger' and ifnull(t2.freeze_account, 'No') = 'No' and ifnull(t2.is_pl_account, 'No') = 'Yes' and ifnull(is_cancelled, 'No') = 'No' and t2.debit_or_credit = '%s' and t2.docstatus < 2 and t2.company = '%s' and t1.posting_date between '%s' and '%s' group by t1.account " % (d_or_c, self.doc.company, self.year_start_date, self.doc.posting_date)) + acc_bal = sql("select t1.account, sum(ifnull(t1.debit,0))-sum(ifnull(t1.credit,0)) \ + from `tabGL Entry` t1, `tabAccount` t2 where t1.account = t2.name and t2.group_or_ledger = 'Ledger' \ + and ifnull(t2.is_pl_account, 'No') = 'Yes' and ifnull(is_cancelled, 'No') = 'No' \ + and t2.debit_or_credit = '%s' and t2.docstatus < 2 and t2.company = '%s' \ + and t1.posting_date between '%s' and '%s' group by t1.account " \ + % (d_or_c, self.doc.company, self.year_start_date, self.doc.posting_date)) return acc_bal From cfc6bb1d6ce075f9420236a07610e2ecfd2c74ee Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Wed, 11 Jul 2012 13:14:52 +0530 Subject: [PATCH 3/9] consider warehouse, serial no and batch no from packing list for sales bom item and populate packing list only for sales bom items --- .../doctype/sales_common/sales_common.js | 24 +++++ .../doctype/sales_common/sales_common.py | 25 ++--- .../doctype/delivery_note/delivery_note.py | 69 ++++-------- .../doctype/delivery_note/delivery_note.txt | 101 ++++++++++++++---- .../delivery_note_packing_item.txt | 6 +- .../doctype/stock_ledger/stock_ledger.py | 51 ++------- 6 files changed, 144 insertions(+), 132 deletions(-) diff --git a/erpnext/selling/doctype/sales_common/sales_common.js b/erpnext/selling/doctype/sales_common/sales_common.js index c852230ad4c..bf80d8f3eeb 100644 --- a/erpnext/selling/doctype/sales_common/sales_common.js +++ b/erpnext/selling/doctype/sales_common/sales_common.js @@ -127,10 +127,34 @@ cur_frm.cscript.dynamic_label = function(doc, cdt, cdn, base_curr, callback) { cur_frm.cscript.base_currency = base_curr; set_dynamic_label_par(doc, cdt, cdn, base_curr); set_dynamic_label_child(doc, cdt, cdn, base_curr); + set_sales_bom_help(doc); if (callback) callback(doc, cdt, cdn); } +// Help for Sales BOM items +var set_sales_bom_help = function(doc) { + if (getchildren('Delivery Note Packing Item', doc.name, 'packing_details').length) { + $(cur_frm.fields_dict.packing_list.row.wrapper).toggle(true); + + if (inList(['Delivery Note', 'Sales Invoice'], doc.doctype)) { + help_msg = "
\ + For 'Sales BOM' items, warehouse, serial no and batch no \ + will be considered from the 'Packing List' table. \ + If warehouse and batch no are same for all packing items for any 'Sales BOM' item, \ + those values can be entered in the main item table, values will be copied to 'Packing List' table. \ +
"; + get_field(doc.doctype, 'sales_bom_help', doc.name).options = help_msg; + } + } else { + $(cur_frm.fields_dict.packing_list.row.wrapper).toggle(false); + if (inList(['Delivery Note', 'Sales Invoice'], doc.doctype)) { + get_field(doc.doctype, 'sales_bom_help', doc.name).options = ''; + } + } + refresh_field('sales_bom_help'); +} + // hide / unhide price list currency based on availability of price list in customer's currency //--------------------------------------------------------------------------------------------------- diff --git a/erpnext/selling/doctype/sales_common/sales_common.py b/erpnext/selling/doctype/sales_common/sales_common.py index 74963fbc07e..a6582095963 100644 --- a/erpnext/selling/doctype/sales_common/sales_common.py +++ b/erpnext/selling/doctype/sales_common/sales_common.py @@ -385,7 +385,7 @@ class DocType(TransactionBase): return ret - def get_item_list(self, obj, is_stopped): + def get_item_list(self, obj, is_stopped=0): """get item list""" il = [] for d in getlist(obj.doclist,obj.fname): @@ -394,7 +394,7 @@ class DocType(TransactionBase): if is_stopped: qty = flt(d.qty) > flt(d.delivered_qty) and flt(flt(d.qty) - flt(d.delivered_qty)) or 0 - if d.prevdoc_doctype == 'Sales Order': + if d.prevdoc_doctype == 'Sales Order': # used in delivery note to reduce reserved_qty # Eg.: if SO qty is 10 and there is tolerance of 20%, then it will allow DN of 12. # But in this case reserved qty should only be reduced by 10 and not 12. @@ -413,7 +413,7 @@ class DocType(TransactionBase): if p.parent_detail_docname == d.name: # the packing details table's qty is already multiplied with parent's qty il.append({ - 'warehouse': d.warehouse, + 'warehouse': p.warehouse, 'reserved_warehouse': reserved_wh, 'item_code': p.item_code, 'qty': flt(p.qty), @@ -496,23 +496,21 @@ class DocType(TransactionBase): pi.qty = flt(qty) pi.actual_qty = bin and flt(bin['actual_qty']) or 0 pi.projected_qty = bin and flt(bin['projected_qty']) or 0 - pi.warehouse = warehouse pi.prevdoc_doctype = line.prevdoc_doctype - if packing_item_code == line.item_code: - pi.serial_no = cstr(line.serial_no) + if not pi.warehouse: + pi.warehouse = warehouse + if not pi.batch_no: pi.batch_no = cstr(line.batch_no) pi.idx = self.packing_list_idx - # has to be saved, since this function is called on_update of delivery note + # saved, since this function is called on_update of delivery note pi.save() self.packing_list_idx += 1 - # ------------------ - # make packing list from sales bom if exists or directly copy item with balance - # ------------------ def make_packing_list(self, obj, fname): + """make packing list for sales bom item""" self.packing_list_idx = 0 parent_items = [] for d in getlist(obj.doclist, fname): @@ -520,10 +518,9 @@ class DocType(TransactionBase): if self.has_sales_bom(d.item_code): for i in self.get_sales_bom_items(d.item_code): self.update_packing_list_item(obj, i['item_code'], flt(i['qty'])*flt(d.qty), warehouse, d) - else: - self.update_packing_list_item(obj, d.item_code, d.qty, warehouse, d) - if [d.item_code, d.name] not in parent_items: - parent_items.append([d.item_code, d.name]) + + if [d.item_code, d.name] not in parent_items: + parent_items.append([d.item_code, d.name]) self.cleanup_packing_list(obj, parent_items) diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.py b/erpnext/stock/doctype/delivery_note/delivery_note.py index ad95cf1e9e4..490051bcc0c 100644 --- a/erpnext/stock/doctype/delivery_note/delivery_note.py +++ b/erpnext/stock/doctype/delivery_note/delivery_note.py @@ -197,51 +197,6 @@ class DocType(TransactionBase): get_obj('DocType Mapper', 'Sales Order-Delivery Note', with_children = 1).validate_reference_value(self, self.doc.name) - def validate_prevdoc_details(self): - for d in getlist(self.doclist,'delivery_note_details'): - prevdoc = d.prevdoc_doctype - prevdoc_docname = d.prevdoc_docname - - if prevdoc_docname and prevdoc: - # Validates Transaction Date of DN and previous doc (i.e. SO , PO, PR) - trans_date = sql("select posting_date from `tab%s` where name = '%s'" %(prevdoc,prevdoc_docname))[0][0] - if trans_date and getdate(self.doc.posting_date) < (trans_date): - msgprint("Your Posting Date cannot be before "+cstr(prevdoc)+" Date.") - raise Exception - # Validates DN and previous doc details - get_name = sql("select name from `tab%s` where name = '%s'" % (prevdoc, prevdoc_docname)) - name = get_name and get_name[0][0] or '' - if name: #check for incorrect docname - if prevdoc == 'Sales Order': - dt = sql("select company, docstatus, customer, currency, sales_partner from `tab%s` where name = '%s'" % (prevdoc, name)) - cust_name = dt and dt[0][2] or '' - if cust_name != self.doc.customer: - msgprint(cstr(prevdoc) + ": " + cstr(prevdoc_docname) + " customer :" + cstr(cust_name) + " does not match with customer : " + cstr(self.doc.customer) + " of current document.") - raise Exception, "Validation Error. " - sal_partner = dt and dt[0][4] or '' - if sal_partner != self.doc.sales_partner: - msgprint(cstr(prevdoc) + ": " + cstr(prevdoc_docname) + " sales partner name :" + cstr(sal_partner) + " does not match with sales partner name : " + cstr(self.doc.sales_partner_name) + " of current document.") - raise Exception, "Validation Error. " - else: - dt = sql("select company, docstatus, supplier, currency from `tab%s` where name = '%s'" % (prevdoc, name)) - supp_name = dt and dt[0][2] or '' - company_name = dt and dt[0][0] or '' - docstatus = dt and dt[0][1] or 0 - currency = dt and dt[0][3] or '' - if (currency != self.doc.currency): - msgprint(cstr(prevdoc) + ": " + cstr(prevdoc_docname) + " currency : "+ cstr(currency) + "does not match with Currency: " + cstr(self.doc.currency) + "of current document") - raise Exception, "Validation Error." - if (company_name != self.doc.company): - msgprint(cstr(prevdoc) + ": " + cstr(prevdoc_docname) + " does not belong to the Company: " + cstr(self.doc.company_name)) - raise Exception, "Validation Error." - if (docstatus != 1): - msgprint(cstr(prevdoc) + ": " + cstr(prevdoc_docname) + " is not Submitted Document.") - raise Exception, "Validation Error." - else: - msgprint(cstr(prevdoc) + ": " + cstr(prevdoc_docname) + " is not a valid " + cstr(prevdoc)) - raise Exception, "Validation Error." - - def validate_for_items(self): check_list, chk_dupl_itm = [], [] for d in getlist(self.doclist,'delivery_note_details'): @@ -292,11 +247,22 @@ class DocType(TransactionBase): set(self.doc, 'message', 'Items against your Order #%s have been delivered. Delivery #%s: ' % (self.doc.po_no, self.doc.name)) # Check for Approving Authority get_obj('Authorization Control').validate_approving_authority(self.doc.doctype, self.doc.company, self.doc.grand_total, self) + + # validate serial no for item table (non-sales-bom item) and packing list (sales-bom item) sl_obj = get_obj("Stock Ledger") + sl_obj.validate_serial_no(self, 'delivery_note_details') + sl_obj.validate_serial_no_warehouse(self, 'delivery_note_details') sl_obj.validate_serial_no(self, 'packing_details') sl_obj.validate_serial_no_warehouse(self, 'packing_details') + + # update delivery details in serial no + sl_obj.update_serial_record(self, 'delivery_note_details', is_submit = 1, is_incoming = 0) sl_obj.update_serial_record(self, 'packing_details', is_submit = 1, is_incoming = 0) + + # update delivered qty in sales order get_obj("Sales Common").update_prevdoc_detail(1,self) + + # create stock ledger entry self.update_stock_ledger(update_stock = 1) self.credit_limit() @@ -332,10 +298,14 @@ class DocType(TransactionBase): sales_com_obj = get_obj(dt = 'Sales Common') sales_com_obj.check_stop_sales_order(self) self.check_next_docstatus() - get_obj('Stock Ledger').update_serial_record(self, 'packing_details', is_submit = 0, is_incoming = 0) + + # remove delivery details from serial no + sl = get_obj('Stock Ledger') + sl.update_serial_record(self, 'delivery_note_details', is_submit = 0, is_incoming = 0) + sl.update_serial_record(self, 'packing_details', is_submit = 0, is_incoming = 0) + sales_com_obj.update_prevdoc_detail(0,self) self.update_stock_ledger(update_stock = -1) - # :::::: set DN status ::::::: set(self.doc, 'status', 'Cancelled') self.cancel_packing_slips() @@ -435,7 +405,8 @@ class DocType(TransactionBase): def on_update(self): get_obj('Sales Common').make_packing_list(self,'delivery_note_details') - self.set_actual_qty() - get_obj('Stock Ledger').scrub_serial_nos(self) + sl = get_obj('Stock Ledger') + sl.scrub_serial_nos(self) + sl.scrub_serial_nos(self, 'packing_details') diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.txt b/erpnext/stock/doctype/delivery_note/delivery_note.txt index 7db951328be..a0c2df0e9ce 100644 --- a/erpnext/stock/doctype/delivery_note/delivery_note.txt +++ b/erpnext/stock/doctype/delivery_note/delivery_note.txt @@ -3,9 +3,9 @@ # These values are common in all dictionaries { - 'creation': '2012-05-15 12:15:05', + 'creation': '2012-06-11 12:10:09', 'docstatus': 0, - 'modified': '2012-05-18 18:06:26', + 'modified': '2012-07-11 11:56:53', 'modified_by': u'Administrator', 'owner': u'Administrator' }, @@ -72,26 +72,14 @@ # DocPerm { - 'amend': 1, - 'cancel': 1, - 'create': 1, + 'amend': 0, + 'cancel': 0, + 'create': 0, 'doctype': u'DocPerm', - 'permlevel': 0, - 'role': u'Sales User', - 'submit': 1, - 'write': 1 - }, - - # DocPerm - { - 'amend': 1, - 'cancel': 1, - 'create': 1, - 'doctype': u'DocPerm', - 'permlevel': 0, - 'role': u'Material Master Manager', - 'submit': 1, - 'write': 1 + 'permlevel': 1, + 'role': u'Material User', + 'submit': 0, + 'write': 0 }, # DocPerm @@ -108,16 +96,72 @@ # DocPerm { + 'amend': 0, + 'cancel': 0, + 'create': 0, 'doctype': u'DocPerm', 'permlevel': 1, - 'role': u'All' + 'role': u'Material Manager', + 'submit': 0, + 'write': 0 + }, + + # DocPerm + { + 'amend': 1, + 'cancel': 1, + 'create': 1, + 'doctype': u'DocPerm', + 'permlevel': 0, + 'role': u'Sales User', + 'submit': 1, + 'write': 1 + }, + + # DocPerm + { + 'amend': 0, + 'cancel': 0, + 'create': 0, + 'doctype': u'DocPerm', + 'permlevel': 1, + 'role': u'Sales User', + 'submit': 0, + 'write': 0 + }, + + # DocPerm + { + 'cancel': 0, + 'create': 0, + 'doctype': u'DocPerm', + 'permlevel': 0, + 'role': u'Accounts User', + 'submit': 0, + 'write': 0 + }, + + # DocPerm + { + 'doctype': u'DocPerm', + 'permlevel': 1, + 'role': u'Accounts User' + }, + + # DocPerm + { + 'doctype': u'DocPerm', + 'match': u'customer_name', + 'permlevel': 0, + 'role': u'Customer' }, # DocPerm { 'doctype': u'DocPerm', 'permlevel': 2, - 'role': u'All' + 'role': u'All', + 'write': 1 }, # DocField @@ -340,6 +384,7 @@ # DocField { 'allow_on_submit': 1, + 'colour': u'White:FFF', 'doctype': u'DocField', 'fieldname': u'delivery_note_details', 'fieldtype': u'Table', @@ -352,6 +397,16 @@ 'print_hide': 0 }, + # DocField + { + 'doctype': u'DocField', + 'fieldname': u'sales_bom_help', + 'fieldtype': u'HTML', + 'label': u'Sales BOM Help', + 'permlevel': 0, + 'print_hide': 1 + }, + # DocField { 'doctype': u'DocField', diff --git a/erpnext/stock/doctype/delivery_note_packing_item/delivery_note_packing_item.txt b/erpnext/stock/doctype/delivery_note_packing_item/delivery_note_packing_item.txt index 51001fc9a0f..db512c64c04 100644 --- a/erpnext/stock/doctype/delivery_note_packing_item/delivery_note_packing_item.txt +++ b/erpnext/stock/doctype/delivery_note_packing_item/delivery_note_packing_item.txt @@ -3,9 +3,9 @@ # These values are common in all dictionaries { - 'creation': '2012-04-13 11:56:35', + 'creation': '2012-06-11 12:10:10', 'docstatus': 0, - 'modified': '2012-05-09 12:55:23', + 'modified': '2012-07-10 12:05:31', 'modified_by': u'Administrator', 'owner': u'Administrator' }, @@ -111,7 +111,7 @@ 'oldfieldname': u'warehouse', 'oldfieldtype': u'Link', 'options': u'Warehouse', - 'permlevel': 1 + 'permlevel': 0 }, # DocField diff --git a/erpnext/stock/doctype/stock_ledger/stock_ledger.py b/erpnext/stock/doctype/stock_ledger/stock_ledger.py index 0cb4b96c3e6..42ad6f6df77 100644 --- a/erpnext/stock/doctype/stock_ledger/stock_ledger.py +++ b/erpnext/stock/doctype/stock_ledger/stock_ledger.py @@ -51,19 +51,16 @@ class DocType: self.doclist = doclist - # ----------------- - # scrub serial nos - # ----------------- - def scrub_serial_nos(self, obj): - for d in getlist(obj.doclist, obj.fname): + def scrub_serial_nos(self, obj, table_name = ''): + if not table_name: + table_name = obj.fname + + for d in getlist(obj.doclist, table_name): if d.serial_no: d.serial_no = d.serial_no.replace(',', '\n') d.save() - # ----------------------------- - # validate serial no warehouse - # ----------------------------- def validate_serial_no_warehouse(self, obj, fname): for d in getlist(obj.doclist, fname): wh = d.warehouse or d.s_warehouse @@ -80,10 +77,8 @@ class DocType: msgprint("Serial No : %s for Item : %s doesn't exists in Warehouse : %s" % (s, d.item_code, wh), raise_exception = 1) - # ------------------------------------ - # check whether serial no is required - # ------------------------------------ def validate_serial_no(self, obj, fname): + """check whether serial no is required""" for d in getlist(obj.doclist, fname): is_stock_item = get_value('Item', d.item_code, 'is_stock_item') ar_required = get_value('Item', d.item_code, 'has_serial_no') @@ -101,18 +96,10 @@ class DocType: msgprint("Rejected serial no is mandatory for rejected qty of item: "+ d.item_code, raise_exception = 1) - - - - # ------------------- - # get serial no list - # ------------------- def get_sr_no_list(self, sr_nos, qty = 0, item_code = ''): return get_sr_no_list(sr_nos, qty, item_code) - # --------------------- - # set serial no values - # --------------------- + def set_pur_serial_no_values(self, obj, serial_no, d, s, new_rec): item_details = sql("select item_group, warranty_period from `tabItem` where name = '%s' and \ (ifnull(end_of_life,'')='' or end_of_life = '0000-00-00' or end_of_life > now()) " %(d.item_code), as_dict=1) @@ -143,9 +130,6 @@ class DocType: s.save(new_rec) - # ---------------------------------- - # update serial no purchase details - # ---------------------------------- def update_serial_purchase_details(self, obj, d, serial_no, is_submit, purpose = ''): exists = sql("select name, status, docstatus from `tabSerial No` where name = '%s'" % (serial_no)) if is_submit: @@ -168,9 +152,6 @@ class DocType: sql("update `tabSerial No` set docstatus = 2, status = 'Not in Use', purchase_document_type = '', purchase_document_no = '', purchase_date = null, purchase_rate = 0, supplier = null, supplier_name = '', supplier_address = '', warehouse = '' where name = '%s'" % serial_no) - # ------------------------------- - # check whether serial no exists - # ------------------------------- def check_serial_no_exists(self, serial_no, item_code): chk = sql("select name, status, docstatus, item_code from `tabSerial No` where name = %s", (serial_no), as_dict=1) if not chk: @@ -182,9 +163,7 @@ class DocType: elif chk and chk[0]['status'] == 'Delivered': msgprint("Serial No: %s of Item : %s is already delivered." % (serial_no, item_code), raise_exception = 1) - # --------------------- - # set serial no values - # --------------------- + def set_delivery_serial_no_values(self, obj, serial_no): s = Document('Serial No', serial_no) s.delivery_document_type = obj.doc.doctype @@ -203,9 +182,6 @@ class DocType: s.save() - # ---------------------------------- - # update serial no delivery details - # ---------------------------------- def update_serial_delivery_details(self, obj, d, serial_no, is_submit): if is_submit: self.check_serial_no_exists(serial_no, d.item_code) @@ -214,9 +190,6 @@ class DocType: sql("update `tabSerial No` set docstatus = 0, status = 'In Store', delivery_document_type = '', delivery_document_no = '', delivery_date = null, customer = null, customer_name = '', delivery_address = '', territory = null where name = '%s'" % (serial_no)) - # --------------------- - # update serial record - # --------------------- def update_serial_record(self, obj, fname, is_submit = 1, is_incoming = 0): import datetime for d in getlist(obj.doclist, fname): @@ -235,11 +208,6 @@ class DocType: self.update_serial_purchase_details(obj, d, a, is_submit) - - - # ------------- - # update stock - # ------------- def update_stock(self, values, is_amended = 'No'): for v in values: sle_id, serial_nos = '', '' @@ -261,9 +229,6 @@ class DocType: v["posting_date"], sle_id, v["posting_time"], '', v["is_cancelled"],v["voucher_type"],v["voucher_no"], is_amended) - # ----------- - # make entry - # ----------- def make_entry(self, args): sle = Document(doctype = 'Stock Ledger Entry') for k in args.keys(): From 9e5059f6b9f2594231f459be441ce8cf4845da4c Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Wed, 11 Jul 2012 13:15:57 +0530 Subject: [PATCH 4/9] packing list introduced in pos invoice --- .../doctype/sales_invoice/sales_invoice.py | 338 ++++++++---------- .../doctype/sales_invoice/sales_invoice.txt | 35 +- erpnext/production/doctype/bom/bom.py | 4 - 3 files changed, 181 insertions(+), 196 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index 82314ca1331..eb869e5d084 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -40,18 +40,12 @@ class DocType(TransactionBase): self.fname = 'entries' - # Autoname - # --------- def autoname(self): self.doc.name = make_autoname(self.doc.naming_series+ '.#####') - -# ********************************* Trigger Functions ****************************** - - #Set retail related fields from pos settings - #------------------------------------------------------------------------- def set_pos_fields(self): + """Set retail related fields from pos settings""" pos = webnotes.conn.sql("select * from `tabPOS Setting` where ifnull(user,'') = '%s' and company = '%s'" % (session['user'], self.doc.company), as_dict=1) if not pos: pos = webnotes.conn.sql("select * from `tabPOS Setting` where ifnull(user,'') = '' and company = '%s'" % (self.doc.company), as_dict=1) @@ -79,9 +73,8 @@ class DocType(TransactionBase): if self.doc.charge: self.get_other_charges() - # Set default values related to pos for previously created sales invoice. - # -------------------------------------------------------------------------- def set_pos_item_values(self): + """Set default values related to pos for previously created sales invoice.""" if cint(self.doc.is_pos) ==1: dtl = webnotes.conn.sql("select income_account, warehouse, cost_center from `tabPOS Setting` where ifnull(user,'') = '%s' and company = '%s'" % (session['user'], self.doc.company), as_dict=1) if not dtl: @@ -94,10 +87,8 @@ class DocType(TransactionBase): d.warehouse = item and item[0]['default_warehouse'] or dtl and dtl[0]['warehouse'] or d.warehouse - - # Get Account Head to which amount needs to be Debited based on Customer - # ---------------------------------------------------------------------- def get_customer_account(self): + """Get Account Head to which amount needs to be Debited based on Customer""" if not self.doc.company: msgprint("Please select company first and re-select the customer after doing so", raise_exception=1) @@ -115,10 +106,8 @@ class DocType(TransactionBase): return acc_head and {'debit_to' : acc_head} or {} - - # Set Due Date = Posting Date + Credit Days - # ----------------------------------------- def get_cust_and_due_date(self): + """Set Due Date = Posting Date + Credit Days""" credit_days = 0 if self.doc.debit_to: credit_days = webnotes.conn.sql("select credit_days from `tabAccount` where name='%s' and docstatus != 2" % self.doc.debit_to) @@ -134,9 +123,8 @@ class DocType(TransactionBase): self.doc.customer = webnotes.conn.get_value('Account',self.doc.debit_to,'master_name') - # Pull Details of Delivery Note or Sales Order Selected - # ------------------------------------------------------ def pull_details(self): + """Pull Details of Delivery Note or Sales Order Selected""" # Delivery Note if self.doc.delivery_note_main: self.validate_prev_docname('delivery note') @@ -153,14 +141,14 @@ class DocType(TransactionBase): ret = self.get_debit_to() self.doc.debit_to = ret.get('debit_to') - # onload pull income account - # -------------------------- + def load_default_accounts(self): """ Loads default accounts from items, customer when called from mapper """ self.get_income_account('entries') + def get_income_account(self,doctype): for d in getlist(self.doclist, doctype): if d.item_code: @@ -168,8 +156,7 @@ class DocType(TransactionBase): d.income_account = item and item[0]['default_income_account'] or '' d.cost_center = item and item[0]['default_sales_cost_center'] or '' - # Item Details - # ------------- + def get_item_details(self, args=None): import json args = args and json.loads(args) or {} @@ -215,61 +202,49 @@ class DocType(TransactionBase): return get_obj('Sales Common').get_barcode_details(barcode) - # Fetch ref rate from item master as per selected price list def get_adj_percent(self, arg=''): + """Fetch ref rate from item master as per selected price list""" get_obj('Sales Common').get_adj_percent(self) - # Get tax rate if account type is tax - # ------------------------------------ def get_rate(self,arg): + """Get tax rate if account type is tax""" get_obj('Sales Common').get_rate(arg) - # Get Commission rate of Sales Partner - # ------------------------------------- def get_comm_rate(self, sales_partner): + """Get Commission rate of Sales Partner""" return get_obj('Sales Common').get_comm_rate(sales_partner, self) - - # GET TERMS & CONDITIONS - # ------------------------------------- + def get_tc_details(self): return get_obj('Sales Common').get_tc_details(self) - # Load Default Charges - # ---------------------------------------------------------- + def load_default_taxes(self): self.doclist = get_obj('Sales Common').load_default_taxes(self) - # Get Sales Taxes and Charges Master Details - # -------------------------- + def get_other_charges(self): self.doclist = get_obj('Sales Common').get_other_charges(self) - # Get Advances - # ------------- + def get_advances(self): self.doclist = get_obj('GL Control').get_advances(self, self.doc.debit_to, 'Sales Invoice Advance', 'advance_adjustment_details', 'credit') - #pull project customer - #------------------------- + def pull_project_customer(self): res = webnotes.conn.sql("select customer from `tabProject` where name = '%s'"%self.doc.project_name) if res: get_obj('DocType Mapper', 'Project-Sales Invoice').dt_map('Project', 'Sales Invoice', self.doc.project_name, self.doc, self.doclist, "[['Project', 'Sales Invoice']]") -# ********************************** Server Utility Functions ****************************** - - # Get Company Abbr. - # ------------------ + def get_company_abbr(self): return webnotes.conn.sql("select abbr from tabCompany where name=%s", self.doc.company)[0][0] - - # Check whether sales order / delivery note items already pulled - #---------------------------------------------------------------- + def validate_prev_docname(self,doctype): + """Check whether sales order / delivery note items already pulled""" for d in getlist(self.doclist, 'entries'): if doctype == 'delivery note' and self.doc.delivery_note_main == d.delivery_note: msgprint(cstr(self.doc.delivery_note_main) + " delivery note details have already been pulled.") @@ -279,7 +254,6 @@ class DocType(TransactionBase): raise Exception , "Validation Error. Sales order details have already been pulled." - #----------------------------------------------------------------- def update_against_document_in_jv(self): """ Links invoice and advance voucher: @@ -308,11 +282,8 @@ class DocType(TransactionBase): get_obj('GL Control').reconcile_against_document(lst) - # ------------------------------------------------------------------------ def validate_customer(self): - """ - Validate customer name with SO and DN - """ + """ Validate customer name with SO and DN""" for d in getlist(self.doclist,'entries'): dt = d.delivery_note and 'Delivery Note' or d.sales_order and 'Sales Order' or '' if dt: @@ -322,9 +293,8 @@ class DocType(TransactionBase): msgprint("Customer %s does not match with customer of %s: %s." %(self.doc.customer, dt, dt_no), raise_exception=1) - # Validates Debit To Account and Customer Matches - # ------------------------------------------------ - def validate_debit_to_acc(self): + def validate_customer_account(self): + """Validates Debit To Account and Customer Matches""" if self.doc.customer and self.doc.debit_to and not cint(self.doc.is_pos): acc_head = webnotes.conn.sql("select master_name from `tabAccount` where name = %s and docstatus != 2", self.doc.debit_to) @@ -334,11 +304,6 @@ class DocType(TransactionBase): and Master Name in account master." %(self.doc.debit_to, self.doc.customer,self.doc.company), raise_exception=1) - # Validate Debit To Account - # 1. Account Exists - # 2. Is a Debit Account - # 3. Is a PL Account - # --------------------------- def validate_debit_acc(self): acc = webnotes.conn.sql("select debit_or_credit, is_pl_account from tabAccount where name = '%s' and docstatus != 2" % self.doc.debit_to) if not acc: @@ -352,9 +317,8 @@ class DocType(TransactionBase): raise Exception - # Validate Fixed Asset Account and whether Income Account Entered Exists - # ----------------------------------------------------------------------- def validate_fixed_asset_account(self): + """Validate Fixed Asset Account and whether Income Account Entered Exists""" for d in getlist(self.doclist,'entries'): item = webnotes.conn.sql("select name,is_asset_item,is_sales_item from `tabItem` where name = '%s' and (ifnull(end_of_life,'')='' or end_of_life = '0000-00-00' or end_of_life > now())"% d.item_code) acc = webnotes.conn.sql("select account_type from `tabAccount` where name = '%s' and docstatus != 2" % d.income_account) @@ -366,22 +330,16 @@ class DocType(TransactionBase): raise Exception - - # Set totals in words - #-------------------- def set_in_words(self): dcc = TransactionBase().get_company_currency(self.doc.company) self.doc.in_words = get_obj('Sales Common').get_total_in_words(dcc, self.doc.rounded_total) self.doc.in_words_export = get_obj('Sales Common').get_total_in_words(self.doc.currency, self.doc.rounded_total_export) - # Clear Advances - # -------------- + def clear_advances(self): get_obj('GL Control').clear_advances(self, 'Sales Invoice Advance','advance_adjustment_details') - # set aging date - #------------------- def set_aging_date(self): if self.doc.is_opening != 'Yes': self.doc.aging_date = self.doc.posting_date @@ -390,20 +348,21 @@ class DocType(TransactionBase): raise Exception - # Set against account for debit to account - #------------------------------------------ def set_against_income_account(self): + """Set against account for debit to account""" against_acc = [] for d in getlist(self.doclist, 'entries'): if d.income_account not in against_acc: against_acc.append(d.income_account) self.doc.against_income_account = ','.join(against_acc) + def add_remarks(self): if not self.doc.remarks: self.doc.remarks = 'No Remarks' - #check in manage account if sales order / delivery note required or not. + def so_dn_required(self): + """check in manage account if sales order / delivery note required or not.""" dict = {'Sales Order':'so_required','Delivery Note':'dn_required'} for i in dict: res = webnotes.conn.sql("select value from `tabSingles` where doctype = 'Global Defaults' and field = '%s'"%dict[i]) @@ -413,9 +372,9 @@ class DocType(TransactionBase): msgprint("%s No. required against item %s"%(i,d.item_code)) raise Exception - #check for does customer belong to same project as entered.. - #------------------------------------------------------------------------------------------------- + def validate_proj_cust(self): + """check for does customer belong to same project as entered..""" if self.doc.project_name and self.doc.customer: res = webnotes.conn.sql("select name from `tabProject` where name = '%s' and (customer = '%s' or ifnull(customer,'')='')"%(self.doc.project_name, self.doc.customer)) if not res: @@ -431,20 +390,13 @@ class DocType(TransactionBase): raise Exception - # ********* UPDATE CURRENT STOCK ***************************** - def update_current_stock(self): - for d in getlist(self.doclist, 'entries'): - bin = webnotes.conn.sql("select actual_qty from `tabBin` where item_code = %s and warehouse = %s", (d.item_code, d.warehouse), as_dict = 1) - d.actual_qty = bin and flt(bin[0]['actual_qty']) or 0 - def validate_item_code(self): for d in getlist(self.doclist, 'entries'): if not d.item_code: msgprint("Please enter Item Code at line no : %s to update stock for POS or remove check from Update Stock in Basic Info Tab." % (d.idx)) raise Exception - # Validate Write Off Account - # ------------------------------- + def validate_write_off_account(self): if flt(self.doc.write_off_amount) and not self.doc.write_off_account: msgprint("Please enter Write Off Account", raise_exception=1) @@ -457,12 +409,22 @@ class DocType(TransactionBase): and parent = %s""", (self.doc.amended_from, self.doc.c_form_no)) webnotes.conn.set(self.doc, 'c_form_no', '') + + + def update_current_stock(self): + for d in getlist(self.doclist, 'entries'): + if d.item_code and d.warehouse: + bin = webnotes.conn.sql("select actual_qty from `tabBin` where item_code = %s and warehouse = %s", (d.item_code, d.warehouse), as_dict = 1) + d.actual_qty = bin and flt(bin[0]['actual_qty']) or 0 + + for d in getlist(self.doclist, 'packing_details'): + bin = sql("select actual_qty, projected_qty from `tabBin` where item_code = %s and warehouse = %s", (d.item_code, d.warehouse), as_dict = 1) + d.actual_qty = bin and flt(bin[0]['actual_qty']) or 0 + d.projected_qty = bin and flt(bin[0]['projected_qty']) or 0 - # VALIDATE - # ==================================================================================== + def validate(self): self.so_dn_required() - #self.dn_required() self.validate_proj_cust() sales_com_obj = get_obj('Sales Common') sales_com_obj.check_stop_sales_order(self) @@ -472,7 +434,7 @@ class DocType(TransactionBase): sales_com_obj.get_allocated_sum(self) # this is to verify that the allocated % of sales persons is 100% sales_com_obj.validate_fiscal_year(self.doc.fiscal_year,self.doc.posting_date,'Posting Date') self.validate_customer() - self.validate_debit_to_acc() + self.validate_customer_account() self.validate_debit_acc() self.validate_fixed_asset_account() self.add_remarks() @@ -480,7 +442,9 @@ class DocType(TransactionBase): self.validate_pos() self.validate_write_off_account() if cint(self.doc.update_stock): - get_obj('Stock Ledger').validate_serial_no(self, 'entries') + sl = get_obj('Stock Ledger') + sl.validate_serial_no(self, 'entries') + sl.validate_serial_no(self, 'packing_details') self.validate_item_code() self.update_current_stock() self.set_in_words() @@ -488,14 +452,62 @@ class DocType(TransactionBase): self.doc.is_opening = 'No' self.set_aging_date() self.clear_advances() - # Set against account self.set_against_income_account() self.validate_c_form() + + def get_warehouse(self): + w = webnotes.conn.sql("select warehouse from `tabPOS Setting` where ifnull(user,'') = '%s' and company = '%s'" % (session['user'], self.doc.company)) + w = w and w[0][0] or '' + if not w: + ps = webnotes.conn.sql("select name, warehouse from `tabPOS Setting` where ifnull(user,'') = '' and company = '%s'" % self.doc.company) + if not ps: + msgprint("To make POS entry, please create POS Setting from Accounts --> POS Setting page and refresh the system.") + raise Exception + elif not ps[0][1]: + msgprint("Please enter warehouse in POS Setting") + else: + w = ps[0][1] + return w + + + def make_packing_list(self): + get_obj('Sales Common').make_packing_list(self,'entries') + sl = get_obj('Stock Ledger') + sl.scrub_serial_nos(self) + sl.scrub_serial_nos(self, 'packing_details') + + + def on_update(self): + # Set default warehouse from pos setting + if cint(self.doc.is_pos) == 1: + if cint(self.doc.update_stock) == 1: + w = self.get_warehouse() + if w: + for d in getlist(self.doclist, 'entries'): + if not d.warehouse: + d.warehouse = cstr(w) + + self.make_packing_list() + else: + self.doclist = self.doc.clear_table(self.doclist, 'packing_details') + + if flt(self.doc.paid_amount) == 0: + if self.doc.cash_bank_account: + webnotes.conn.set(self.doc, 'paid_amount', + (flt(self.doc.grand_total) - flt(self.doc.write_off_amount))) + else: + # show message that the amount is not paid + webnotes.conn.set(self.doc,'paid_amount',0) + webnotes.msgprint("Note: Payment Entry will not be created since 'Cash/Bank Account' was not specified.") + + else: + self.doclist = self.doc.clear_table(self.doclist, 'packing_details') + webnotes.conn.set(self.doc,'paid_amount',0) + + webnotes.conn.set(self.doc,'outstanding_amount',flt(self.doc.grand_total) - flt(self.doc.total_advance) - flt(self.doc.paid_amount) - flt(self.doc.write_off_amount)) + -# *************************************************** ON SUBMIT ********************************************** - # Check Ref Document's docstatus - # ------------------------------- def check_prev_docstatus(self): for d in getlist(self.doclist,'entries'): if d.sales_order: @@ -511,56 +523,45 @@ class DocType(TransactionBase): raise Exception , "Validation Error." - #Set Actual Qty based on item code and warehouse - #------------------------------------------------------ - def set_actual_qty(self): - for d in getlist(self.doclist, 'entries'): - if d.item_code and d.warehouse: - actual_qty = webnotes.conn.sql("select actual_qty from `tabBin` where item_code = '%s' and warehouse = '%s'" % (d.item_code, d.warehouse)) - d.actual_qty = actual_qty and flt(actual_qty[0][0]) or 0 - - - - # ********************** Make Stock Entry ************************************ def make_sl_entry(self, d, wh, qty, in_value, update_stock): - st_uom = webnotes.conn.sql("select stock_uom from `tabItem` where name = '%s'"%d.item_code) + st_uom = webnotes.conn.sql("select stock_uom from `tabItem` where name = '%s'"%d['item_code']) self.values.append({ - 'item_code' : d.item_code, + 'item_code' : d['item_code'], 'warehouse' : wh, 'transaction_date' : getdate(self.doc.modified).strftime('%Y-%m-%d'), 'posting_date' : self.doc.posting_date, 'posting_time' : self.doc.posting_time, 'voucher_type' : 'Sales Invoice', 'voucher_no' : cstr(self.doc.name), - 'voucher_detail_no' : cstr(d.name), + 'voucher_detail_no' : cstr(d['name']), 'actual_qty' : qty, 'stock_uom' : st_uom and st_uom[0][0] or '', 'incoming_rate' : in_value, 'company' : self.doc.company, 'fiscal_year' : self.doc.fiscal_year, 'is_cancelled' : (update_stock==1) and 'No' or 'Yes', - 'batch_no' : cstr(d.batch_no), - 'serial_no' : d.serial_no - }) + 'batch_no' : cstr(d['batch_no']), + 'serial_no' : d['serial_no'] + }) - # UPDATE STOCK LEDGER - # --------------------------------------------------------------------------- - def update_stock_ledger(self, update_stock, clear = 0): + def update_stock_ledger(self, update_stock): self.values = [] - for d in getlist(self.doclist, 'entries'): - stock_item = webnotes.conn.sql("SELECT is_stock_item, is_sample_item FROM tabItem where name = '%s'"%(d.item_code), as_dict = 1) # stock ledger will be updated only if it is a stock item + items = get_obj('Sales Common').get_item_list(self) + for d in items: + stock_item = webnotes.conn.sql("SELECT is_stock_item, is_sample_item \ + FROM tabItem where name = '%s'"%(d['item_code']), as_dict = 1) if stock_item[0]['is_stock_item'] == "Yes": + if not d['warehouse']: + msgprint("Message: Please enter Warehouse for item %s as it is stock item." \ + % d['item_code'], raise_exception=1) + # Reduce actual qty from warehouse - self.make_sl_entry( d, d.warehouse, - flt(d.qty) , 0, update_stock) - get_obj('Stock Ledger', 'Stock Ledger').update_stock(self.values, self.doc.amended_from and 'Yes' or 'No') - - - #-------------------POS Stock Updatation Part---------------------------------------------- - def pos_update_stock(self): - self.update_stock_ledger(update_stock = 1) + self.make_sl_entry( d, d['warehouse'], - flt(d['qty']) , 0, update_stock) + + get_obj('Stock Ledger', 'Stock Ledger').update_stock(self.values) - # ********** Get Actual Qty of item in warehouse selected ************* + def get_actual_qty(self,args): args = eval(args) actual_qty = webnotes.conn.sql("select actual_qty from `tabBin` where item_code = '%s' and warehouse = '%s'" % (args['item_code'], args['warehouse']), as_dict=1) @@ -569,23 +570,39 @@ class DocType(TransactionBase): } return ret - # Make GL Entries - # ------------------------- + def make_gl_entries(self, is_cancel=0): mapper = self.doc.is_pos and self.doc.write_off_account and 'POS with write off' or self.doc.is_pos and not self.doc.write_off_account and 'POS' or '' update_outstanding = self.doc.is_pos and self.doc.write_off_account and 'No' or 'Yes' get_obj(dt='GL Control').make_gl_entries(self.doc, self.doclist,cancel = is_cancel, use_mapper = mapper, update_outstanding = update_outstanding, merge_entries = cint(self.doc.is_pos) != 1 and 1 or 0) - # On Submit - # --------- + def update_c_form(self): + """Update amended id in C-form""" + if self.doc.c_form_no and self.doc.amended_from: + webnotes.conn.sql("""update `tabC-Form Invoice Detail` set invoice_no = %s, + invoice_date = %s, territory = %s, net_total = %s, + grand_total = %s where invoice_no = %s and parent = %s""", (self.doc.name, self.doc.amended_from, self.doc.c_form_no)) + + + def check_next_docstatus(self): + submit_jv = webnotes.conn.sql("select t1.name from `tabJournal Voucher` t1,`tabJournal Voucher Detail` t2 where t1.name = t2.parent and t2.against_invoice = '%s' and t1.docstatus = 1" % (self.doc.name)) + if submit_jv: + msgprint("Journal Voucher : " + cstr(submit_jv[0][0]) + " has been created against " + cstr(self.doc.doctype) + ". So " + cstr(self.doc.doctype) + " cannot be Cancelled.") + raise Exception, "Validation Error." + + def on_submit(self): if cint(self.doc.is_pos) == 1: if cint(self.doc.update_stock) == 1: sl_obj = get_obj("Stock Ledger") sl_obj.validate_serial_no_warehouse(self, 'entries') + sl_obj.validate_serial_no_warehouse(self, 'packing_details') + sl_obj.update_serial_record(self, 'entries', is_submit = 1, is_incoming = 0) - self.pos_update_stock() + sl_obj.update_serial_record(self, 'packing_details', is_submit = 1, is_incoming = 0) + + self.update_stock_ledger(update_stock=1) else: self.check_prev_docstatus() get_obj("Sales Common").update_prevdoc_detail(1,self) @@ -603,31 +620,13 @@ class DocType(TransactionBase): self.update_c_form() - def update_c_form(self): - """Update amended id in C-form""" - if self.doc.c_form_no and self.doc.amended_from: - webnotes.conn.sql("""update `tabC-Form Invoice Detail` set invoice_no = %s, - invoice_date = %s, territory = %s, net_total = %s, - grand_total = %s where invoice_no = %s and parent = %s""", (self.doc.name, self.doc.amended_from, self.doc.c_form_no)) - - - -# *************************************************** ON CANCEL ********************************************** - # Check Next Document's docstatus - # -------------------------------- - def check_next_docstatus(self): - submit_jv = webnotes.conn.sql("select t1.name from `tabJournal Voucher` t1,`tabJournal Voucher Detail` t2 where t1.name = t2.parent and t2.against_invoice = '%s' and t1.docstatus = 1" % (self.doc.name)) - if submit_jv: - msgprint("Journal Voucher : " + cstr(submit_jv[0][0]) + " has been created against " + cstr(self.doc.doctype) + ". So " + cstr(self.doc.doctype) + " cannot be Cancelled.") - raise Exception, "Validation Error." - - - # On Cancel - # ---------- def on_cancel(self): if cint(self.doc.is_pos) == 1: if cint(self.doc.update_stock) == 1: - get_obj('Stock Ledger').update_serial_record(self, 'entries', is_submit = 0, is_incoming = 0) + sl = get_obj('Stock Ledger') + sl.update_serial_record(self, 'entries', is_submit = 0, is_incoming = 0) + sl.update_serial_record(self, 'packing_details', is_submit = 0, is_incoming = 0) + self.update_stock_ledger(update_stock = -1) else: sales_com_obj = get_obj(dt = 'Sales Common') @@ -636,51 +635,6 @@ class DocType(TransactionBase): sales_com_obj.update_prevdoc_detail(0,self) self.make_gl_entries(is_cancel=1) - - # Get Warehouse - def get_warehouse(self): - w = webnotes.conn.sql("select warehouse from `tabPOS Setting` where ifnull(user,'') = '%s' and company = '%s'" % (session['user'], self.doc.company)) - w = w and w[0][0] or '' - if not w: - ps = webnotes.conn.sql("select name, warehouse from `tabPOS Setting` where ifnull(user,'') = '' and company = '%s'" % self.doc.company) - if not ps: - msgprint("To make POS entry, please create POS Setting from Setup --> Accounts --> POS Setting and refresh the system.") - raise Exception - elif not ps[0][1]: - msgprint("Please enter warehouse in POS Setting") - else: - w = ps[0][1] - return w - - # on update - def on_update(self): - # Set default warehouse from pos setting - #---------------------------------------- - if cint(self.doc.is_pos) == 1: - self.set_actual_qty() - w = self.get_warehouse() - if w: - for d in getlist(self.doclist, 'entries'): - if not d.warehouse: - d.warehouse = cstr(w) - - if flt(self.doc.paid_amount) == 0: - if self.doc.cash_bank_account: - webnotes.conn.set(self.doc, 'paid_amount', - (flt(self.doc.grand_total) - flt(self.doc.write_off_amount))) - else: - # show message that the amount is not paid - webnotes.conn.set(self.doc,'paid_amount',0) - webnotes.msgprint("Note: Payment Entry not created since 'Cash/Bank Account' was not specified.") - - else: - webnotes.conn.set(self.doc,'paid_amount',0) - - webnotes.conn.set(self.doc,'outstanding_amount',flt(self.doc.grand_total) - flt(self.doc.total_advance) - flt(self.doc.paid_amount) - flt(self.doc.write_off_amount)) - - #------------------------------------------------------------------------------------- - def on_update_after_submit(self): - self.convert_into_recurring() def convert_into_recurring(self): @@ -717,3 +671,7 @@ class DocType(TransactionBase): next_date = next_date.strftime("%Y-%m-%d") webnotes.conn.set(self.doc, 'next_date', next_date) + + + def on_update_after_submit(self): + self.convert_into_recurring() \ No newline at end of file diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.txt b/erpnext/accounts/doctype/sales_invoice/sales_invoice.txt index 969a7dc6d73..a2b341fd4fe 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.txt +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.txt @@ -3,9 +3,9 @@ # These values are common in all dictionaries { - 'creation': '2012-06-11 12:09:54', + 'creation': '2012-07-05 11:04:09', 'docstatus': 0, - 'modified': '2012-06-17 21:37:40', + 'modified': '2012-07-11 12:19:49', 'modified_by': u'Administrator', 'owner': u'Administrator' }, @@ -350,6 +350,16 @@ 'permlevel': 0 }, + # DocField + { + 'doctype': u'DocField', + 'fieldname': u'sales_bom_help', + 'fieldtype': u'HTML', + 'label': u'Sales BOM Help', + 'permlevel': 0, + 'print_hide': 1 + }, + # DocField { 'doctype': u'DocField', @@ -1343,6 +1353,27 @@ 'print_hide': 1 }, + # DocField + { + 'doctype': u'DocField', + 'fieldname': u'packing_list', + 'fieldtype': u'Section Break', + 'label': u'Packing List', + 'permlevel': 0, + 'print_hide': 1 + }, + + # DocField + { + 'doctype': u'DocField', + 'fieldname': u'packing_details', + 'fieldtype': u'Table', + 'label': u'Packing Details', + 'options': u'Delivery Note Packing Item', + 'permlevel': 0, + 'print_hide': 1 + }, + # DocField { 'doctype': u'DocField', diff --git a/erpnext/production/doctype/bom/bom.py b/erpnext/production/doctype/bom/bom.py index 81297b4f1b7..bc166ceb860 100644 --- a/erpnext/production/doctype/bom/bom.py +++ b/erpnext/production/doctype/bom/bom.py @@ -106,7 +106,6 @@ class DocType: return ret_item - def get_rm_rate(self, arg): """ Get raw material rate as per selected method, if bom exists takes bom cost """ @@ -293,7 +292,6 @@ class DocType: self.validate_main_item() self.validate_operations() self.validate_materials() - self.validate_operations() @@ -353,8 +351,6 @@ class DocType: }) - - # Get Current Flat BOM Items # ----------------------------- def get_current_flat_bom_items(self): From 3b0f5dddea2f22a5352a8432ac9dbe11dccac669 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Wed, 11 Jul 2012 15:14:06 +0530 Subject: [PATCH 5/9] fiscal_year_closed and abbr removed from code --- erpnext/accounts/doctype/fiscal_year/fiscal_year.py | 3 --- erpnext/setup/doctype/setup_control/setup_control.py | 4 +--- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/erpnext/accounts/doctype/fiscal_year/fiscal_year.py b/erpnext/accounts/doctype/fiscal_year/fiscal_year.py index a44b75670ca..c1b4663631b 100644 --- a/erpnext/accounts/doctype/fiscal_year/fiscal_year.py +++ b/erpnext/accounts/doctype/fiscal_year/fiscal_year.py @@ -204,9 +204,6 @@ class DocType: if sql("select name from `tabFiscal Year` where year_start_date < %s", self.doc.year_start_date) and not self.doc.past_year: msgprint("Please enter Past Year", raise_exception=1) - if not self.doc.is_fiscal_year_closed: - self.doc.is_fiscal_year_closed = 'No' - # on update def on_update(self): diff --git a/erpnext/setup/doctype/setup_control/setup_control.py b/erpnext/setup/doctype/setup_control/setup_control.py index 444b796f3cc..ee1cb7e4ab9 100644 --- a/erpnext/setup/doctype/setup_control/setup_control.py +++ b/erpnext/setup/doctype/setup_control/setup_control.py @@ -49,9 +49,7 @@ class DocType: master_dict = {'Fiscal Year':{ 'year': curr_fiscal_year, 'year_start_date': fy_start_date, - 'abbreviation': fy_abbr, - 'company': args.get('company_name'), - 'is_fiscal_year_closed': 'No'}} + 'company': args.get('company_name')}} self.create_records(master_dict) # Company From 42e1273c4c4ed950869f43c761ebcc955a5c6dd7 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Wed, 11 Jul 2012 16:38:00 +0530 Subject: [PATCH 6/9] listview for salary structure --- .../hr/doctype/salary_structure/listview.js | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 erpnext/hr/doctype/salary_structure/listview.js diff --git a/erpnext/hr/doctype/salary_structure/listview.js b/erpnext/hr/doctype/salary_structure/listview.js new file mode 100644 index 00000000000..77259b5d138 --- /dev/null +++ b/erpnext/hr/doctype/salary_structure/listview.js @@ -0,0 +1,47 @@ +// render +wn.doclistviews['Salary Structure'] = wn.views.ListView.extend({ + init: function(d) { + this._super(d) + this.fields = this.fields.concat([ + "`tabSalary Structure`.employee_name", + "`tabSalary Structure`.designation", + "`tabSalary Structure`.branch", + "`tabSalary Structure`.net_pay", + "`tabSalary Structure`.from_date", + "`tabSalary Structure`.to_date", + "`tabSalary Structure`.company" + ]); + this.stats = this.stats.concat(['company']); + }, + + prepare_data: function(data) { + this._super(data); + var concat_list = []; + data.designation && concat_list.push(data.designation); + data.branch && concat_list.push(data.branch); + data.description = concat_list.join(", "); + data.period = data.from_date + (data.to_date && ' to ' + data.to_date); + }, + + columns: [ + {width: '2%', content: 'check'}, + {width: '2%', content: 'docstatus'}, + {width: '13%', content: 'name'}, + {width: '18%', content: 'employee_name'}, + {width: '24%', content: 'description+tags', css: {'color': '#aaa'}}, + {width: '26%', content:'period', css: {'text-align': 'right', 'color':'#aaa'}}, + { + width: '15%', + content: function(parent, data) { + $(parent).html( + ( + data.company + ? wn.boot.company[data.company].default_currency + : sys_defaults.currency + ) + + ' ' + fmt_money(data.net_pay)); + }, + css: {'text-align': 'right'}, + }, +] +}); \ No newline at end of file From 0cd057ce94e3c56d034ea9bbdb6a6c32db1f33b8 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Wed, 11 Jul 2012 18:39:28 +0530 Subject: [PATCH 7/9] Hong kong timezone added --- erpnext/startup/js/complete_setup.js | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/erpnext/startup/js/complete_setup.js b/erpnext/startup/js/complete_setup.js index 9180dfa1197..ff512827e6e 100644 --- a/erpnext/startup/js/complete_setup.js +++ b/erpnext/startup/js/complete_setup.js @@ -138,7 +138,7 @@ $.extend(erpnext.complete_setup, { 'Dominican Republic', 'East Timor', 'Ecuador', 'Egypt', 'El Salvador', 'Equatorial Guinea', 'Eritrea', 'Estonia', 'Ethiopia', 'Federated States of Micronesia', 'Fiji', 'Finland', 'France', 'Gabon', 'Georgia', 'Germany', 'Ghana', 'Greece', - 'Grenada', 'Guatemala', 'Guinea', 'Guinea-Bissau', 'Guyana', 'Haiti', 'Honduras', + 'Grenada', 'Guatemala', 'Guinea', 'Guinea-Bissau', 'Guyana', 'Haiti', 'Honduras', 'Hong Kong' 'Hungary', 'Iceland', 'India', 'Indonesia', 'Iran', 'Iraq', 'Israel', 'Italy', 'Jamaica', 'Japan', 'Jordan', 'Kazakhstan', 'Kenya', 'Kingdom of the Netherlands', 'Kiribati', 'Kuwait', 'Kyrgyzstan', 'Laos', 'Latvia', 'Lebanon', 'Lesotho', 'Liberia', @@ -147,7 +147,7 @@ $.extend(erpnext.complete_setup, { 'Mexico', 'Moldova', 'Monaco', 'Mongolia', 'Montenegro', 'Morocco', 'Mozambique', 'Myanmar', 'Namibia', 'Nauru', 'Nepal', 'New Zealand', 'Nicaragua', 'Niger', 'Nigeria', 'North Korea', 'Norway', 'Oman', 'Pakistan', 'Palau', 'Panama', 'Papua New Guinea', - 'Paraguay', "People's Republic of China", 'Peru', 'Philippines', 'Poland', 'Portugal', + 'Paraguay', "China", 'Peru', 'Philippines', 'Poland', 'Portugal', 'Qatar', 'Republic of Ireland', 'Republic of the Congo', 'Romania', 'Russia', 'Rwanda', 'Saint Kitts and Nevis', 'Saint Lucia', 'Saint Vincent and the Grenadines', 'Samoa', 'San Marino', 'Saudi Arabia', 'Senegal', 'Serbia', 'Seychelles', 'Sierra Leone', @@ -252,6 +252,11 @@ $.extend(erpnext.complete_setup, { 'Cape Verde': ['Atlantic/Cape_Verde'], 'Central African Republic': ['Africa/Bangui'], 'Chad': ['Africa/Ndjamena'], + 'China': ['Asia/Shanghai', + 'Asia/Harbin', + 'Asia/Chongqing', + 'Asia/Urumqi', + 'Asia/Kashgar'], 'Chile': ['America/Santiago', 'Pacific/Easter'], 'Colombia': ['America/Bogota'], 'Comoros': ['Indian/Comoro'], @@ -292,6 +297,7 @@ $.extend(erpnext.complete_setup, { 'Guyana': ['America/Guyana'], 'Haiti': ['America/Guatemala'], 'Honduras': ['America/Tegucigalpa'], + 'Hong Kong': ['Asia/Hong_Kong'], 'Hungary': ['Europe/Budapest'], 'Iceland': ['Atlantic/Reykjavik'], 'India': ['Asia/Calcutta'], @@ -365,11 +371,6 @@ $.extend(erpnext.complete_setup, { 'Panama': ['America/Panama'], 'Papua New Guinea': ['Pacific/Port_Moresby'], 'Paraguay': ['America/Asuncion'], - "People's Republic of China": ['Asia/Shanghai', - 'Asia/Harbin', - 'Asia/Chongqing', - 'Asia/Urumqi', - 'Asia/Kashgar'], 'Peru': ['America/Lima'], 'Philippines': ['Asia/Manila'], 'Poland': ['Europe/Warsaw'], From e9c19369a9c3837313f4dd889c425adbfd103171 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Thu, 12 Jul 2012 10:33:45 +0530 Subject: [PATCH 8/9] salary slip will not submitted through salary manager if Send email checked and invalid email id --- .../doctype/salary_manager/salary_manager.py | 64 ++++++++++++------- erpnext/hr/doctype/salary_slip/salary_slip.py | 2 +- 2 files changed, 43 insertions(+), 23 deletions(-) diff --git a/erpnext/hr/doctype/salary_manager/salary_manager.py b/erpnext/hr/doctype/salary_manager/salary_manager.py index 111366b9186..660890a3c89 100644 --- a/erpnext/hr/doctype/salary_manager/salary_manager.py +++ b/erpnext/hr/doctype/salary_manager/salary_manager.py @@ -24,7 +24,6 @@ from webnotes.model.doclist import getlist, copy_doclist from webnotes.model.code import get_obj, get_server_obj, run_server_obj, updatedb, check_syntax from webnotes import session, form, is_testing, msgprint, errprint -set = webnotes.conn.set sql = webnotes.conn.sql get_value = webnotes.conn.get_value in_transaction = webnotes.conn.in_transaction @@ -84,7 +83,7 @@ class DocType: emp_list = self.get_emp_list() log = "" if emp_list: - log = "" + log = "
Following Salary Slip has been created:
SAL SLIP IDEMPLOYEE NAME
" else: log = "
Following Salary Slip has been created:
SAL SLIP IDEMPLOYEE NAME
" @@ -111,7 +110,7 @@ class DocType: for d in getlist(ss_obj.doclist, 'deduction_details'): d.save() - log += '' + log += '' log += '
No employee found for the above selected criteria
' + ss.name + '' + ss_obj.doc.employee_name + '
' + ss.name + '' + ss_obj.doc.employee_name + '
' return log @@ -132,28 +131,49 @@ class DocType: """ Submit all salary slips based on selected criteria """ - ss_list = self.get_sal_slip_list() - log = "" - if ss_list: - log = """ - - - - - - - - """ - else: - log = "
Following Salary Slip has been submitted:
SAL SLIP IDEMPLOYEE NAME
" - + ss_list = self.get_sal_slip_list() + not_submitted_ss = [] for ss in ss_list: ss_obj = get_obj("Salary Slip",ss[0],with_children=1) - set(ss_obj.doc, 'docstatus', 1) - ss_obj.on_submit() + try: + webnotes.conn.set(ss_obj.doc, 'email_check', cint(self.doc.send_mail)) + if cint(self.doc.send_email) == 1: + ss_obj.send_mail_funct() + + webnotes.conn.set(ss_obj.doc, 'docstatus', 1) + except Exception,e: + not_submitted_ss.append(ss[0]) + msgprint(e) + continue + + return self.create_log(ss_list, not_submitted_ss) + + + def create_log(self, all_ss, not_submitted_ss): + log = '' + if not all_ss: + log = "No salary slip found to submit for the above selected criteria" + else: + all_ss = [d[0] for d in all_ss] - log += '' - log += '
No salary slip found to submit for the above selected criteria
' + ss[0] + '' + ss_obj.doc.employee_name + '
' + submitted_ss = list(set(all_ss) - set(not_submitted_ss)) + if submitted_ss: + mail_sent_msg = self.doc.send_email and " (Mail has been sent to the employee)" or "" + log = """ + Submitted Salary Slips%s:\ +

%s

+ """ % (mail_sent_msg, '
'.join(submitted_ss)) + + if not_submitted_ss: + log += """ + Not Submitted Salary Slips: \ +

%s

\ + Reason:
\ + May be company email id specified in employee master is not valid.
\ + Please mention correct email id in employee master or if you don't want to \ + send mail, uncheck 'Send Email' checkbox.
\ + Then try to submit Salary Slip again. + """% ('
'.join(not_submitted_ss)) return log diff --git a/erpnext/hr/doctype/salary_slip/salary_slip.py b/erpnext/hr/doctype/salary_slip/salary_slip.py index 3439fc861fd..3187eb43ffd 100644 --- a/erpnext/hr/doctype/salary_slip/salary_slip.py +++ b/erpnext/hr/doctype/salary_slip/salary_slip.py @@ -281,4 +281,4 @@ class DocType(TransactionBase): '''%(cstr(letter_head[0][0]),cstr(self.doc.employee), cstr(self.doc.employee_name), cstr(self.doc.month), cstr(self.doc.fiscal_year), cstr(self.doc.department), cstr(self.doc.branch), cstr(self.doc.designation), cstr(self.doc.grade), cstr(self.doc.bank_account_no), cstr(self.doc.bank_name), cstr(self.doc.arrear_amount), cstr(self.doc.payment_days), earn_table, ded_table, cstr(flt(self.doc.gross_pay)), cstr(flt(self.doc.total_deduction)), cstr(flt(self.doc.net_pay)), cstr(self.doc.total_in_words)) sendmail([receiver], subject=subj, msg = msg) else: - msgprint("Company Email ID not found.") + msgprint("Company Email ID not found, hence mail not sent") From 51f8a6d0d505448c4fa25d31574ea49fe0531935 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Thu, 12 Jul 2012 16:25:13 +0530 Subject: [PATCH 9/9] select employee based on joining and relieving date in salary maanger --- .../doctype/salary_manager/salary_manager.py | 66 ++++++++++--- erpnext/hr/doctype/salary_slip/salary_slip.js | 10 +- erpnext/hr/doctype/salary_slip/salary_slip.py | 99 +++++++++---------- 3 files changed, 106 insertions(+), 69 deletions(-) diff --git a/erpnext/hr/doctype/salary_manager/salary_manager.py b/erpnext/hr/doctype/salary_manager/salary_manager.py index 660890a3c89..a0cbb70e1d7 100644 --- a/erpnext/hr/doctype/salary_manager/salary_manager.py +++ b/erpnext/hr/doctype/salary_manager/salary_manager.py @@ -45,14 +45,14 @@ class DocType: """ cond = self.get_filter_condition() + cond += self.get_joining_releiving_condition() emp_list = sql(""" select t1.name from `tabEmployee` t1, `tabSalary Structure` t2 where t1.docstatus!=2 and t2.docstatus != 2 - and ifnull(t1.status, 'Left') = 'Active' and ifnull(t2.is_active, 'No') = 'Yes' and t1.name = t2.employee - %s """% cond) + %s """% cond, debug=1) return emp_list @@ -63,9 +63,19 @@ class DocType: cond = '' for f in ['company', 'branch', 'department', 'designation', 'grade']: if self.doc.fields.get(f): - cond += " and t1." + f + " = '" + self.doc.fields.get(f) + "'" - + cond += " and t1." + f + " = '" + self.doc.fields.get(f) + "'" + return cond + + + def get_joining_releiving_condition(self): + m = self.get_month_details(self.doc.fiscal_year, self.doc.month) + cond = """ + and ifnull(t1.date_of_joining, '0000-00-00') <= '%(month_end_date)s' + and ifnull(t1.relieving_date, '2199-12-31') >= '%(month_start_date)s' + """ % m + return cond + def check_mandatory(self): @@ -73,6 +83,26 @@ class DocType: if not self.doc.fields[f]: msgprint("Please select %s to proceed" % f, raise_exception=1) + + def get_month_details(self, year, month): + ysd = sql("select year_start_date from `tabFiscal Year` where name ='%s'"%year)[0][0] + if ysd: + from dateutil.relativedelta import relativedelta + import calendar, datetime + diff_mnt = cint(month)-cint(ysd.month) + if diff_mnt<0: + diff_mnt = 12-int(ysd.month)+cint(month) + msd = ysd + relativedelta(months=diff_mnt) # month start date + month_days = cint(calendar.monthrange(cint(msd.year) ,cint(month))[1]) # days in month + med = datetime.date(msd.year, cint(month), month_days) # month end date + return { + 'year': msd.year, + 'month_start_date': msd, + 'month_end_date': med, + 'month_days': month_days + } + + def create_sal_slip(self): """ @@ -81,12 +111,7 @@ class DocType: """ emp_list = self.get_emp_list() - log = "" - if emp_list: - log = "" - else: - log = "
Following Salary Slip has been created:
SAL SLIP IDEMPLOYEE NAME
" - + ss_list = [] for emp in emp_list: if not sql("""select name from `tabSalary Slip` where docstatus!= 2 and employee = %s and month = %s and fiscal_year = %s and company = %s @@ -110,9 +135,18 @@ class DocType: for d in getlist(ss_obj.doclist, 'deduction_details'): d.save() - log += '' - log += '
No employee found for the above selected criteria
' + ss.name + '' + ss_obj.doc.employee_name + '
' - return log + ss_list.append(ss.name) + + return self.create_log(ss_list) + + + def create_log(self, ss_list): + log = "No employee for the above selected criteria OR salary slip already created" + if ss_list: + log = "Created Salary Slip has been created: \ +

%s" % '
'.join(ss_list) + return log + def get_sal_slip_list(self): """ @@ -146,10 +180,10 @@ class DocType: msgprint(e) continue - return self.create_log(ss_list, not_submitted_ss) + return self.create_submit_log(ss_list, not_submitted_ss) - def create_log(self, all_ss, not_submitted_ss): + def create_submit_log(self, all_ss, not_submitted_ss): log = '' if not all_ss: log = "No salary slip found to submit for the above selected criteria" @@ -188,7 +222,7 @@ class DocType: """ % (self.doc.month, self.doc.fiscal_year, cond)) return flt(tot[0][0]) - + def get_acc_details(self): """ diff --git a/erpnext/hr/doctype/salary_slip/salary_slip.js b/erpnext/hr/doctype/salary_slip/salary_slip.js index 5fe93a68a58..3e61665a2bb 100644 --- a/erpnext/hr/doctype/salary_slip/salary_slip.js +++ b/erpnext/hr/doctype/salary_slip/salary_slip.js @@ -45,9 +45,13 @@ cur_frm.cscript.month = cur_frm.cscript.employee = cur_frm.cscript.fiscal_year; // Calculate total if lwp exists // ------------------------------------------------------------------------ cur_frm.cscript.leave_without_pay = function(doc,dt,dn){ - doc.payment_days = flt(doc.total_days_in_month) - flt(doc.leave_without_pay); - refresh_field('payment_days'); - calculate_all(doc, dt, dn); + if (doc.employee && doc.fiscal_year && doc.month) { + $c_obj(make_doclist(doc.doctype,doc.name), 'get_leave_details',doc.leave_without_pay,function(r, rt) { + var doc = locals[dt][dn]; + cur_frm.refresh(); + calculate_all(doc, dt, dn); + }); + } } // Calculate all diff --git a/erpnext/hr/doctype/salary_slip/salary_slip.py b/erpnext/hr/doctype/salary_slip/salary_slip.py index 3187eb43ffd..9860eab7502 100644 --- a/erpnext/hr/doctype/salary_slip/salary_slip.py +++ b/erpnext/hr/doctype/salary_slip/salary_slip.py @@ -39,27 +39,22 @@ class DocType(TransactionBase): self.doclist = doclist - # autoname - #======================================================= def autoname(self): self.doc.name = make_autoname('Sal Slip/' +self.doc.employee + '/.#####') - # Get employee details - #======================================================= - def get_emp_and_leave_details(self): - # Get payment days - if self.doc.fiscal_year and self.doc.month: - self.get_leave_details() - # check sal structure + def get_emp_and_leave_details(self): if self.doc.employee: + # Get payment days + if self.doc.fiscal_year and self.doc.month: + self.get_leave_details() + + # check sal structure struct = self.check_sal_struct() if struct: self.pull_sal_struct(struct) - # Check sal structure - #======================================================= def check_sal_struct(self): struct = sql("select name from `tabSalary Structure` where employee ='%s' and is_active = 'Yes' "%self.doc.employee) if not struct: @@ -67,8 +62,7 @@ class DocType(TransactionBase): self.doc.employee = '' return struct and struct[0][0] or '' - # Pull struct details - #======================================================= + def pull_sal_struct(self, struct): self.doclist = self.doc.clear_table(self.doclist, 'earning_details') self.doclist = self.doc.clear_table(self.doclist, 'deduction_details') @@ -81,41 +75,48 @@ class DocType(TransactionBase): self.doc.esic_no = basic_info[0][2] self.doc.pf_no = basic_info[0][3] - # Get leave details - #======================================================= - def get_leave_details(self): - m = self.get_month_details() - lwp = self.calculate_lwp(m) - self.doc.total_days_in_month = m[3] + + def get_leave_details(self, lwp=None): + m = get_obj('Salary Manager').get_month_details(self.doc.fiscal_year, self.doc.month) + + if not lwp: + lwp = self.calculate_lwp(m) + self.doc.total_days_in_month = m['month_days'] self.doc.leave_without_pay = lwp - self.doc.payment_days = flt(m[3]) - flt(lwp) + payment_days = flt(self.get_payment_days(m)) - flt(lwp) + self.doc.payment_days = payment_days > 0 and payment_days or 0 + + + def get_payment_days(self, m): + payment_days = m['month_days'] + emp = webnotes.conn.sql("select date_of_joining, relieving_date from `tabEmployee` \ + where name = %s", self.doc.employee, as_dict=1)[0] + + 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']: + payment_days = 0 + + 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']: + payment_days = 0 + + return payment_days + + - # Get month details - #======================================================= - def get_month_details(self): - ysd = sql("select year_start_date from `tabFiscal Year` where name ='%s'"%self.doc.fiscal_year)[0][0] - if ysd: - from dateutil.relativedelta import relativedelta - import calendar, datetime - mnt = int(self.doc.month) - diff_mnt = int(mnt)-int(ysd.month) - if diff_mnt<0: - diff_mnt = 12-int(ysd.month)+int(mnt) - msd = ysd + relativedelta(months=diff_mnt) # month start date - month_days = cint(calendar.monthrange(cint(msd.year) ,cint(self.doc.month))[1]) # days in month - med = datetime.date(msd.year, cint(self.doc.month), month_days) # month end date - return msd.year, msd, med, month_days - # Calculate LWP - #======================================================= def calculate_lwp(self, m): - holidays = 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.doc.employee, m[1], m[2])) + holidays = 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.doc.employee, m['month_start_date'], m['month_end_date'])) if not holidays: holidays = sql("select t1.holiday_date from `tabHoliday` t1, `tabHoliday List` t2 where t1.parent = t2.name and ifnull(t2.is_default, 0) = 1 and t2.fiscal_year = '%s'" % self.doc.fiscal_year) holidays = [cstr(i[0]) for i in holidays] lwp = 0 - for d in range(m[3]): - dt = add_days(cstr(m[1]), d) + for d in range(m['month_days']): + dt = add_days(cstr(m['month_start_date']), d) if dt not in holidays: leave = sql(""" select t1.name, t1.half_day @@ -130,8 +131,7 @@ class DocType(TransactionBase): lwp = cint(leave[0][1]) and lwp + 0.5 or lwp + 1 return lwp - # Check existing - #======================================================= + def check_existing(self): ret_exist = sql("select name from `tabSalary Slip` where month = '%s' and fiscal_year = '%s' and docstatus != 2 and employee = '%s' and name !='%s'" % (self.doc.month,self.doc.fiscal_year,self.doc.employee,self.doc.name)) if ret_exist: @@ -139,8 +139,7 @@ class DocType(TransactionBase): self.doc.employee = '' raise Exception - # Validate - #======================================================= + def validate(self): self.check_existing() dcc = TransactionBase().get_company_currency(self.doc.company) @@ -155,6 +154,8 @@ class DocType(TransactionBase): for d in getlist(self.doclist, 'earning_details'): if cint(d.e_depends_on_lwp) == 1: d.e_modified_amount = round(flt(d.e_amount)*flt(self.doc.payment_days)/cint(self.doc.total_days_in_month), 2) + elif not self.doc.payment_days: + d.e_modified_amount = 0 self.doc.gross_pay += d.e_modified_amount def calculate_ded_total(self): @@ -165,6 +166,9 @@ class DocType(TransactionBase): for d in getlist(self.doclist, 'deduction_details'): if cint(d.d_depends_on_lwp) == 1: d.d_modified_amount = round(flt(d.d_amount)*flt(self.doc.payment_days)/cint(self.doc.total_days_in_month), 2) + elif not self.doc.payment_days: + d.d_modified_amount = 0 + self.doc.total_deduction += d.d_modified_amount def calculate_net_pay(self): @@ -176,17 +180,12 @@ class DocType(TransactionBase): self.doc.net_pay = flt(self.doc.gross_pay) - flt(self.doc.total_deduction) self.doc.rounded_total = round(self.doc.net_pay) - # ON SUBMIT - #======================================================= + def on_submit(self): if(self.doc.email_check == 1): self.send_mail_funct() - - - # Send mail - #======================================================= def send_mail_funct(self): from webnotes.utils.email_lib import sendmail emailid_ret=sql("select company_email from `tabEmployee` where name = '%s'"%self.doc.employee)