From 0aec0e1a63ee29ea2368d779d1b7fa064d905f2f Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Tue, 10 Jul 2012 14:24:45 +0530 Subject: [PATCH 01/21] 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 1b59bc616e..184df70c15 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 c70745e7e2..f56c1b0c93 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 02/21] 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 c4288a40b5..a27eccef52 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 184df70c15..f4cf47d23e 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 03/21] 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 c852230ad4..bf80d8f3ee 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 74963fbc07..a658209596 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 ad95cf1e9e..490051bcc0 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 7db951328b..a0c2df0e9c 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 51001fc9a0..db512c64c0 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 0cb4b96c3e..42ad6f6df7 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 04/21] 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 82314ca133..eb869e5d08 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 969a7dc6d7..a2b341fd4f 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 81297b4f1b..bc166ceb86 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 e57267f79a077dc440e5a07d130bc7cc4e2cc1bc Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Wed, 11 Jul 2012 13:18:58 +0530 Subject: [PATCH 05/21] added patch for account and cleanups to breadcrumbs and msgprint --- erpnext/accounts/doctype/account/account.js | 52 ++++++++++-------- .../doctype/cost_center/cost_center.js | 22 +++++--- .../doctype/cost_center/cost_center.py | 48 +++++------------ .../accounts/doctype/gl_control/gl_control.py | 1 + .../page/accounts_browser/accounts_browser.js | 5 +- .../july_2012/default_freeze_account.py | 3 ++ erpnext/patches/patch_list.py | 5 ++ erpnext/setup/doctype/company/company.py | 1 + erpnext/stock/doctype/item/item.txt | 17 ++---- erpnext/stock/doctype/warehouse/warehouse.js | 4 ++ erpnext/stock/doctype/warehouse/warehouse.txt | 48 ++++++----------- public/css/all-app.css | 10 ++++ public/css/all-web.css | 10 ++++ public/js/all-app.js | 54 +++++++++---------- public/js/all-web.js | 32 +++++------ 15 files changed, 159 insertions(+), 153 deletions(-) create mode 100644 erpnext/patches/july_2012/default_freeze_account.py diff --git a/erpnext/accounts/doctype/account/account.js b/erpnext/accounts/doctype/account/account.js index 79c15bf1ae..18b58948bc 100644 --- a/erpnext/accounts/doctype/account/account.js +++ b/erpnext/accounts/doctype/account/account.js @@ -20,33 +20,39 @@ cur_frm.cscript.onload = function(doc, cdt, cdn) { } +cur_frm.cscript.set_breadcrumbs = function(barea) { + cur_frm.frm_head.appframe.add_breadcrumb(cur_frm.docname); + cur_frm.frm_head.appframe.add_breadcrumb(' in \ + Chart of Accounts'); + cur_frm.frm_head.appframe.add_breadcrumb(' in Accounts'); +} + // Refresh // ----------------------------------------- cur_frm.cscript.refresh = function(doc, cdt, cdn) { - // read-only for root accounts - root_acc = ['Application of Funds (Assets)','Expenses','Income','Source of Funds (Liabilities)']; - if(inList(root_acc, doc.account_name)) - cur_frm.perm = [[1,0,0], [1,0,0]]; - // hide fields if group cur_frm.toggle_fields(['account_type', 'master_type', 'master_name', 'freeze_account', - 'credit_days', 'credit_limit'], doc.group_or_ledger=='Ledger') + 'credit_days', 'credit_limit', 'tax_rate'], doc.group_or_ledger=='Ledger') - // credit days and type if customer or supplier - cur_frm.toggle_fields(['credit_days', 'credit_limit'], - in_list(['Customer', 'Supplier'], doc.master_type)) + cur_frm.toggle_fields('account_name', doc.__islocal) - // hide tax_rate - cur_frm.cscript.account_type(doc, cdt, cdn); + // read-only for root accounts + root_acc = ['Application of Funds (Assets)','Expenses','Income','Source of Funds (Liabilities)']; + if(in_list(root_acc, doc.account_name)) { + cur_frm.perm = [[1,0,0], [1,0,0]]; + cur_frm.set_intro("This is a root account and cannot be edited."); + } else { + // credit days and type if customer or supplier + cur_frm.set_intro(null); + cur_frm.toggle_fields(['credit_days', 'credit_limit'], + in_list(['Customer', 'Supplier'], doc.master_type)) - // show / hide convert buttons - cur_frm.cscript.hide_unhide_group_ledger(doc); - - // back to chart of accounts - cur_frm.add_custom_button('Back To Chart of Accounts', function() { - wn.set_route('Accounts Browser', 'Account'); - }, 'icon-arrow-left') - + // hide tax_rate + cur_frm.cscript.account_type(doc, cdt, cdn); + + // show / hide convert buttons + cur_frm.cscript.hide_unhide_group_ledger(doc); + } } // Fetch parent details @@ -57,8 +63,12 @@ cur_frm.add_fetch('parent_account', 'is_pl_account', 'is_pl_account'); // Hide tax rate based on account type // ----------------------------------------- cur_frm.cscript.account_type = function(doc, cdt, cdn) { - cur_frm.toggle_fields(['tax_rate'], doc.account_type == 'Tax') - cur_frm.toggle_fields(['master_type', 'master_name'], cstr(doc.account_type)=='') + if(doc.group_or_ledger=='Ledger') { + cur_frm.toggle_fields(['tax_rate'], + doc.account_type == 'Tax'); + cur_frm.toggle_fields(['master_type', 'master_name'], + cstr(doc.account_type)==''); + } } // Hide/unhide group or ledger diff --git a/erpnext/accounts/doctype/cost_center/cost_center.js b/erpnext/accounts/doctype/cost_center/cost_center.js index f721e42f2d..9b6670454c 100644 --- a/erpnext/accounts/doctype/cost_center/cost_center.js +++ b/erpnext/accounts/doctype/cost_center/cost_center.js @@ -26,17 +26,25 @@ cur_frm.cscript.onload = function(doc, cdt, cdn) { } +cur_frm.cscript.set_breadcrumbs = function(barea) { + cur_frm.frm_head.appframe.add_breadcrumb(cur_frm.docname); + cur_frm.frm_head.appframe.add_breadcrumb(' in \ + Chart of Cost Centers'); + cur_frm.frm_head.appframe.add_breadcrumb(' in Accounts'); +} + cur_frm.cscript.refresh = function(doc, cdt, cdn) { - cur_frm.cscript.hide_unhide_group_ledger(doc); - cur_frm.add_custom_button('Back To Chart of Cost Centers', function() { - wn.set_route('Accounts Browser', 'Cost Center'); - }, 'icon-arrow-left') + cur_frm.toggle_fields('cost_center_name', doc.__islocal) var intro_txt = ''; if(!doc.__islocal && doc.group_or_ledger=='Group') { intro_txt += '

Note: This is Cost Center is a Group, \ Accounting Entries are not allowed against groups.

'; } + + cur_frm.cscript.hide_unhide_group_ledger(doc); + + cur_frm.toggle_fields('sb1', doc.group_or_ledger=='Ledger') cur_frm.set_intro(intro_txt); } @@ -80,8 +88,7 @@ cur_frm.cscript.hide_unhide_group_ledger = function(doc) { cur_frm.cscript.convert_to_ledger = function(doc, cdt, cdn) { $c_obj(cur_frm.get_doclist(),'convert_group_to_ledger','',function(r,rt) { if(r.message == 1) { - refresh_field('group_or_ledger'); - cur_frm.cscript.hide_unhide_group_ledger(cur_frm.get_doc()); + cur_frm.refresh(); } }); } @@ -91,8 +98,7 @@ cur_frm.cscript.convert_to_ledger = function(doc, cdt, cdn) { cur_frm.cscript.convert_to_group = function(doc, cdt, cdn) { $c_obj(cur_frm.get_doclist(),'convert_ledger_to_group','',function(r,rt) { if(r.message == 1) { - refresh_field('group_or_ledger'); - cur_frm.cscript.hide_unhide_group_ledger(cur_frm.get_doc()); + cur_frm.refresh(); } }); } diff --git a/erpnext/accounts/doctype/cost_center/cost_center.py b/erpnext/accounts/doctype/cost_center/cost_center.py index 83ad9d23cd..99b4bac157 100644 --- a/erpnext/accounts/doctype/cost_center/cost_center.py +++ b/erpnext/accounts/doctype/cost_center/cost_center.py @@ -14,24 +14,10 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -# Please edit this list and import only required elements import webnotes - -from webnotes.utils import add_days, add_months, add_years, cint, cstr, date_diff, default_fields, flt, fmt_money, formatdate, generate_hash, getTraceback, get_defaults, get_first_day, get_last_day, getdate, has_common, month_name, now, nowdate, replace_newlines, sendmail, set_default, str_esc_quote, user_format, validate_email_add -from webnotes.model import db_exists -from webnotes.model.doc import Document, addchild, getchildren, make_autoname -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 -convert_to_lists = webnotes.conn.convert_to_lists +from webnotes.model.doclist import getlist +from webnotes import msgprint -# ----------------------------------------------------------------------------------------- - class DocType: def __init__(self,d,dl): @@ -41,9 +27,9 @@ class DocType: def autoname(self): self.doc.name = self.doc.cost_center_name + ' - ' + self.doc.company_abbr - #------------------------------------------------------------------------- def get_abbr(self): - abbr = sql("select abbr from tabCompany where company_name='%s'"%(self.doc.company_name))[0][0] or '' + abbr = webnotes.conn.sql("select abbr from tabCompany where company_name=%s", + self.doc.company_name)[0][0] or '' ret = { 'company_abbr' : abbr } @@ -56,7 +42,6 @@ class DocType: if self.doc.cost_center_name != 'Root' and not self.doc.parent_cost_center: msgprint("Please enter parent cost center", raise_exception=1) - #------------------------------------------------------------------------- def convert_group_to_ledger(self): if self.check_if_child_exists(): msgprint("Cost Center: %s has existing child. You can not convert this cost center to ledger" % (self.doc.name), raise_exception=1) @@ -67,7 +52,6 @@ class DocType: self.doc.save() return 1 - #------------------------------------------------------------------------- def convert_ledger_to_group(self): if self.check_gle_exists(): msgprint("Cost Center with existing transaction can not be converted to group.", raise_exception=1) @@ -76,37 +60,36 @@ class DocType: self.doc.save() return 1 - #------------------------------------------------------------------------- def check_gle_exists(self): - return sql("select name from `tabGL Entry` where cost_center = %s and ifnull(is_cancelled, 'No') = 'No'", (self.doc.name)) + return webnotes.conn.sql("select name from `tabGL Entry` where cost_center = %s and \ + ifnull(is_cancelled, 'No') = 'No'", (self.doc.name)) - - #------------------------------------------------------------------------- def check_if_child_exists(self): - return sql("select name from `tabCost Center` where parent_cost_center = %s and docstatus != 2", self.doc.name) - + return webnotes.conn.sql("select name from `tabCost Center` where \ + parent_cost_center = %s and docstatus != 2", self.doc.name) def validate_budget_details(self): check_acc_list = [] for d in getlist(self.doclist, 'budget_details'): + if doc.group_or_ledger=="Group": + msgprint("Budget cannot be set for Group Cost Centers", raise_exception=1) + if [d.account, d.fiscal_year] in check_acc_list: - msgprint("Account " + cstr(d.account) + "has been entered more than once for fiscal year " + cstr(d.fiscal_year), raise_exception=1) + msgprint("Account " + d.account + "has been entered more than once for fiscal year " + d.fiscal_year, raise_exception=1) else: check_acc_list.append([d.account, d.fiscal_year]) - #------------------------------------------------------------------------- def validate(self): """ Cost Center name must be unique """ - if (self.doc.__islocal or not self.doc.name) and sql("select name from `tabCost Center` where cost_center_name = %s and company_name=%s", (self.doc.cost_center_name, self.doc.company_name)): + if (self.doc.__islocal or not self.doc.name) and webnotes.conn.sql("select name from `tabCost Center` where cost_center_name = %s and company_name=%s", (self.doc.cost_center_name, self.doc.company_name)): msgprint("Cost Center Name already exists, please rename", raise_exception=1) self.validate_mandatory() self.validate_budget_details() - #------------------------------------------------------------------------- def update_nsm_model(self): """ update Nested Set Model @@ -114,16 +97,13 @@ class DocType: import webnotes.utils.nestedset webnotes.utils.nestedset.update_nsm(self) - #------------------------------------------------------------------------- def on_update(self): self.update_nsm_model() - # On Trash - #------------------------------------------------------------------------- def on_trash(self): if self.check_if_child_exists(): msgprint("Child exists for this cost center. You can not trash this account.", raise_exception=1) # rebuild tree - set(self.doc,'old_parent', '') + webnotes.conn.set_value(self.doc,'old_parent', '') self.update_nsm_model() diff --git a/erpnext/accounts/doctype/gl_control/gl_control.py b/erpnext/accounts/doctype/gl_control/gl_control.py index bfeddb0c52..ef8960c35d 100644 --- a/erpnext/accounts/doctype/gl_control/gl_control.py +++ b/erpnext/accounts/doctype/gl_control/gl_control.py @@ -123,6 +123,7 @@ class DocType: ac.fields[d] = arg[d] ac.old_parent = '' ac_obj = get_obj(doc=ac) + ac_obj.doc.freeze_account='No' ac_obj.validate() ac_obj.doc.save(1) ac_obj.on_update() diff --git a/erpnext/accounts/page/accounts_browser/accounts_browser.js b/erpnext/accounts/page/accounts_browser/accounts_browser.js index 734e4de18a..793ee595fb 100644 --- a/erpnext/accounts/page/accounts_browser/accounts_browser.js +++ b/erpnext/accounts/page/accounts_browser/accounts_browser.js @@ -62,7 +62,10 @@ pscript['onload_Accounts Browser'] = function(wrapper){ pscript['onshow_Accounts Browser'] = function(wrapper){ // set route var ctype = wn.get_route()[1] || 'Account'; - wrapper.appframe.title('Chart of '+ctype+'s'); + + wrapper.appframe.clear_breadcrumbs(); + wrapper.appframe.add_breadcrumb('Chart of '+ctype+'s') + wrapper.appframe.add_breadcrumb(' in Accounts'); if(erpnext.account_chart && erpnext.account_chart.ctype != ctype) { wrapper.$company_select.change(); diff --git a/erpnext/patches/july_2012/default_freeze_account.py b/erpnext/patches/july_2012/default_freeze_account.py new file mode 100644 index 0000000000..f5b3cc6e8a --- /dev/null +++ b/erpnext/patches/july_2012/default_freeze_account.py @@ -0,0 +1,3 @@ +def execute(): + import webnotes + webnotes.conn.sql("""update tabAccount set freeze_account='No' where freeze_account is null""") diff --git a/erpnext/patches/patch_list.py b/erpnext/patches/patch_list.py index ab95e9553d..6cd73cd71e 100644 --- a/erpnext/patches/patch_list.py +++ b/erpnext/patches/patch_list.py @@ -487,4 +487,9 @@ patch_list = [ 'patch_file': 'deprecate_import_data_control', 'description': "deprecate doctype - Import Data Control and page - Import Data" }, + { + 'patch_module': 'patches.july_2012', + 'patch_file': 'default_freeze_account', + 'description': "set default freeze_account as 'No' where NULL" + }, ] \ No newline at end of file diff --git a/erpnext/setup/doctype/company/company.py b/erpnext/setup/doctype/company/company.py index 11ed655ce4..f5ca6ac1a5 100644 --- a/erpnext/setup/doctype/company/company.py +++ b/erpnext/setup/doctype/company/company.py @@ -166,6 +166,7 @@ class DocType: ac.fields[d] = (d == 'parent_account' and lst[self.fld_dict[d]]) and lst[self.fld_dict[d]] +' - '+ self.doc.abbr or lst[self.fld_dict[d]] ac.old_parent = '' ac_obj = get_obj(doc=ac) + ac_obj.doc.freeze_account='No' ac_obj.validate() ac_obj.doc.save(1) ac_obj.on_update() diff --git a/erpnext/stock/doctype/item/item.txt b/erpnext/stock/doctype/item/item.txt index 8a079b815d..b531e53265 100644 --- a/erpnext/stock/doctype/item/item.txt +++ b/erpnext/stock/doctype/item/item.txt @@ -3,9 +3,9 @@ # These values are common in all dictionaries { - 'creation': '2012-04-30 18:33:53', + 'creation': '2012-07-03 13:30:46', 'docstatus': 0, - 'modified': '2012-06-07 16:16:24', + 'modified': '2012-07-11 09:57:40', 'modified_by': u'Administrator', 'owner': u'Administrator' }, @@ -196,7 +196,7 @@ # DocField { 'colour': u'White:FFF', - 'description': u'Classify your item in any one item group by clicking on the magnifying glass', + 'description': u'Manage Item Groups', 'doctype': u'DocField', 'fieldname': u'item_group', 'fieldtype': u'Link', @@ -209,17 +209,6 @@ 'reqd': 1 }, - # DocField - { - 'doctype': u'DocField', - 'fieldname': u'ighelp', - 'fieldtype': u'HTML', - 'label': u'IGHelp', - 'oldfieldtype': u'HTML', - 'options': u'To manage Item Groups, click here', - 'permlevel': 0 - }, - # DocField { 'doctype': u'DocField', diff --git a/erpnext/stock/doctype/warehouse/warehouse.js b/erpnext/stock/doctype/warehouse/warehouse.js index b218063b4a..4ad95f494f 100644 --- a/erpnext/stock/doctype/warehouse/warehouse.js +++ b/erpnext/stock/doctype/warehouse/warehouse.js @@ -14,6 +14,10 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +cur_frm.cscript.refresh = function(doc) { + cur_frm.toggle_fields('warehouse_name', doc.__islocal); +} + cur_frm.cscript.country = function(doc, cdt, cdn) { var mydoc=doc; $c('runserverobj', args={'method':'check_state', 'docs':compress_doclist(make_doclist(doc.doctype, doc.name))}, diff --git a/erpnext/stock/doctype/warehouse/warehouse.txt b/erpnext/stock/doctype/warehouse/warehouse.txt index 16bf59d9d5..844e3f326c 100644 --- a/erpnext/stock/doctype/warehouse/warehouse.txt +++ b/erpnext/stock/doctype/warehouse/warehouse.txt @@ -3,9 +3,9 @@ # These values are common in all dictionaries { - 'creation': '2012-05-15 12:15:13', + 'creation': '2012-07-03 13:30:45', 'docstatus': 0, - 'modified': '2012-05-21 18:02:46', + 'modified': '2012-07-11 10:18:07', 'modified_by': u'Administrator', 'owner': u'Administrator' }, @@ -17,6 +17,7 @@ 'autoname': u'field:warehouse_name', 'colour': u'White:FFF', 'default_print_format': u'Standard', + 'description': u'A logical Warehouse against which stock entries are made.\n\nThere are two main Warehouse Types that are significant in ERPNext.\n\n1. **Stores:** These are where your incoming **Items** are kept before they are consumed or sold. You can have as many \u201cStores\u201d type **Warehouses** as you wish. Stores type warehouses are significant because if you set an Item for automatic re-order, ERPNext will check its quantities in all \u201cStores\u201d type **Warehouses** when deciding whether to re-order or not.\n\n2. **Asset**: **Items** marked as type \u201cFixed Asset\u201d are maintained in Asset Type **Warehouses**. This helps you separate them for the **Items** that are consumed as a part of your regular operations or \u201cCost of Goods Sold\u201d.\n', 'doctype': 'DocType', 'document_type': u'Master', 'module': u'Stock', @@ -170,17 +171,6 @@ 'write': 1 }, - # DocField - { - 'doctype': u'DocField', - 'fieldname': u'trash_reason', - 'fieldtype': u'Small Text', - 'label': u'Trash Reason', - 'oldfieldname': u'trash_reason', - 'oldfieldtype': u'Small Text', - 'permlevel': 1 - }, - # DocField { 'doctype': u'DocField', @@ -220,7 +210,6 @@ # DocField { 'colour': u'White:FFF', - 'description': u'The valuation of items in this warehouse will be considered for the company that is specified', 'doctype': u'DocField', 'fieldname': u'company', 'fieldtype': u'Link', @@ -233,6 +222,17 @@ 'search_index': 1 }, + # DocField + { + 'colour': u'White:FFF', + 'description': u'For Reference Only.', + 'doctype': u'DocField', + 'fieldname': u'warehouse_contact_info', + 'fieldtype': u'Section Break', + 'label': u'Warehouse Contact Info', + 'permlevel': 0 + }, + # DocField { 'doctype': u'DocField', @@ -246,24 +246,6 @@ 'print_hide': 0 }, - # DocField - { - 'doctype': u'DocField', - 'fieldname': u'auto_indent_mail', - 'fieldtype': u'Select', - 'hidden': 1, - 'label': u'Send Reorder Alert Mail ', - 'no_copy': 1, - 'oldfieldname': u'auto_indent_mail', - 'oldfieldtype': u'Select', - 'options': u'No\nYes', - 'permlevel': 0, - 'print_hide': 1, - 'report_hide': 1, - 'reqd': 0, - 'trigger': u'Client' - }, - # DocField { 'doctype': u'DocField', @@ -357,6 +339,8 @@ # DocField { + 'colour': u'White:FFF', + 'description': u'For Admin use only. Please report errors to support@erpnext.com', 'doctype': u'DocField', 'fieldname': u'repost_stock', 'fieldtype': u'Section Break', diff --git a/public/css/all-app.css b/public/css/all-app.css index 6bd1d58037..5cfd39104d 100644 --- a/public/css/all-app.css +++ b/public/css/all-app.css @@ -2259,6 +2259,14 @@ div.std-footer-item { div.fetching { color: #888; text-align:right; } +.msgprint { + min-height: 60px; + max-height: 500px; + padding: 9px; + color: #333; + overflow: auto; +} + div.notice { postion: absolute; background-color: #000; @@ -3276,6 +3284,8 @@ div.appframe-toolbar { border-bottom: 1px solid #ccc; } + + /* * lib/css/ui/fonts.css */ diff --git a/public/css/all-web.css b/public/css/all-web.css index e1311c4baa..b32cff8403 100644 --- a/public/css/all-web.css +++ b/public/css/all-web.css @@ -2120,6 +2120,14 @@ div.std-footer-item { div.fetching { color: #888; text-align:right; } +.msgprint { + min-height: 60px; + max-height: 500px; + padding: 9px; + color: #333; + overflow: auto; +} + div.notice { postion: absolute; background-color: #000; @@ -2525,6 +2533,8 @@ div.appframe-toolbar { border-bottom: 1px solid #ccc; } + + /* * erpnext/startup/startup.css */ diff --git a/public/js/all-app.js b/public/js/all-app.js index d0e4771658..91da926f99 100644 --- a/public/js/all-app.js +++ b/public/js/all-app.js @@ -605,16 +605,12 @@ document.body.appendChild(temp);temp.submit();return temp;} /* * lib/js/legacy/utils/msgprint.js */ -var msg_dialog;function msgprint(msg,issmall,callback){if(!msg)return;if(typeof(msg)!='string') -msg=JSON.stringify(msg);if(issmall){show_alert(msg);return;} -if(msg.substr(0,8)=='__small:'){show_alert(msg.substr(8));return;} -if(!msg_dialog){msg_dialog=new Dialog(500,200,"Message");msg_dialog.make_body([['HTML','Msg']]) -msg_dialog.onhide=function(){msg_dialog.msg_area.innerHTML='';$dh(msg_dialog.msg_icon);if(msg_dialog.custom_onhide)msg_dialog.custom_onhide();} -$y(msg_dialog.rows['Msg'],{fontSize:'14px',lineHeight:'1.5em',padding:'16px'}) -var t=make_table(msg_dialog.rows['Msg'],1,2,'100%',['20px','250px'],{padding:'2px',verticalAlign:'Top'});msg_dialog.msg_area=$td(t,0,1);msg_dialog.msg_icon=$a($td(t,0,0),'img');} -if(!msg_dialog.display)msg_dialog.show();var has_msg=msg_dialog.msg_area.innerHTML?1:0;var m=$a(msg_dialog.msg_area,'div','');if(has_msg)$y(m,{marginTop:'4px'});$dh(msg_dialog.msg_icon);if(msg.substr(0,6).toLowerCase()=='error:'){msg_dialog.msg_icon.src='images/lib/icons/error.gif';$di(msg_dialog.msg_icon);msg=msg.substr(6);}else if(msg.substr(0,8).toLowerCase()=='message:'){msg_dialog.msg_icon.src='images/lib/icons/application.gif';$di(msg_dialog.msg_icon);msg=msg.substr(8);}else if(msg.substr(0,3).toLowerCase()=='ok:'){msg_dialog.msg_icon.src='images/lib/icons/accept.gif';$di(msg_dialog.msg_icon);msg=msg.substr(3);} -m.innerHTML=replace_newlines(msg);if(m.offsetHeight>200){$y(m,{height:'200px',width:'400px',overflow:'auto'})} -msg_dialog.custom_onhide=callback;} +var msg_dialog;function msgprint(msg,title){if(!msg)return;if(typeof(msg)!='string') +msg=JSON.stringify(msg);if(msg.substr(0,8)=='__small:'){show_alert(msg.substr(8));return;} +if(!msg_dialog){msg_dialog=new wn.ui.Dialog({title:"Message",onhide:function(){msg_dialog.msg_area.empty();}});msg_dialog.msg_area=$('
').appendTo(msg_dialog.body);} +if(msg.search(/
|

/)==-1) +msg=replace_newlines(msg);msg_dialog.set_title(title||'Message') +msg_dialog.msg_area.append(msg);msg_dialog.show();} var growl_area;function show_alert(txt,id){if(!growl_area){if(!$('#dialog-container').length){$('

').appendTo('body');} growl_area=$a($i('dialog-container'),'div','',{position:'fixed',bottom:'8px',right:'8px',width:'320px',zIndex:10});} var wrapper=$a(growl_area,'div','',{position:'relative'});var body=$a(wrapper,'div','notice');var c=$a(body,'i','icon-remove-sign',{cssFloat:'right',cursor:'pointer'});$(c).click(function(){$dh(this.wrapper)});c.wrapper=wrapper;var t=$a(body,'div','',{color:'#FFF'});$(t).html(txt);if(id){$(t).attr('id',id);} @@ -854,10 +850,14 @@ wn.ui.AppFrame=Class.extend({init:function(parent,title){this.buttons={};this.$w \ ×\
').appendTo(this.$w);this.$w.find('.close').click(function(){window.history.back();}) -if(title)this.title(title);},title:function(txt){this.$titlebar.find('.appframe-title').html(txt);},add_button:function(label,click,icon){if(!this.$w.find('.appframe-toolbar').length) -this.$w.append('
');args={label:label,icon:''};if(icon){args.icon='';} +if(title)this.title(title);},title:function(txt){this.$titlebar.find('.appframe-title').html(txt);},make_toolbar:function(){if(!this.$w.find('.appframe-toolbar').length) +this.$w.append('
');},add_button:function(label,click,icon){this.make_toolbar();args={label:label,icon:''};if(icon){args.icon='';} this.buttons[label]=$(repl('',args)).click(click).appendTo(this.$w.find('.appframe-toolbar'));return this.buttons[label];},clear_buttons:function(){this.$w.find('.appframe-toolbar').empty();}});wn.ui.make_app_page=function(opts){if(opts.single_column){$(opts.parent).html('
\ + %(icon)s %(label)s',args)).click(click).appendTo(this.$w.find('.appframe-toolbar'));return this.buttons[label];},add_help_button:function(txt){this.make_toolbar();$('').data('help-text',txt).click(function(){msgprint($(this).data('help-text'),'Help');}).appendTo(this.$w.find('.appframe-toolbar'));},clear_buttons:function(){this.$w.find('.appframe-toolbar').empty();},add_breadcrumb:function(html){if(!this.$breadcrumbs) +this.$breadcrumbs=$('\ + ').appendTo(this.$titlebar);var crumb=$('').html(html);if(!this.$breadcrumbs.find('span').length){crumb.addClass('appframe-title');} +crumb.appendTo(this.$breadcrumbs);},clear_breadcrumbs:function(){this.$breadcrumbs&&this.$breadcrumbs.empty();}});wn.ui.make_app_page=function(opts){if(opts.single_column){$(opts.parent).html('
\
\
\
');}else{$(opts.parent).html('
\ @@ -881,8 +881,8 @@ return ret;} this.set_value=function(key,val){var f=this.fields_dict[key];if(f){f.set_input(val);f.refresh_mandatory();}} this.set_values=function(dict){for(var key in dict){if(this.fields_dict[key]){this.set_value(key,dict[key]);}}} this.clear=function(){for(key in this.fields_dict){var f=this.fields_dict[key];if(f){f.set_input(f.df['default']||'');}}}} -wn.widgets.Dialog=function(opts){this.opts=opts;this.display=false;this.make=function(opts){if(opts) -this.opts=opts;if(!this.opts.width)this.opts.width=480;if(!$('#dialog-container').length){$('
').appendTo('body');} +wn.widgets.Dialog=function(opts){this.display=false;this.make=function(opts){if(opts){this.opts=opts;$.extend(this,opts);} +if(!this.opts.width)this.opts.width=480;if(!$('#dialog-container').length){$('
').appendTo('body');} this.wrapper=$('
').appendTo('#dialog-container').get(0);if(this.opts.width) this.wrapper.style.width=this.opts.width+'px';this.make_head();this.body=$a(this.wrapper,'div','dialog_body');if(this.opts.fields) this.make_fields(this.body,this.opts.fields);} @@ -893,7 +893,7 @@ this.show=function(){if(this.display)return;this.set_postion() $ds(this.wrapper);freeze();this.display=true;cur_dialog=this;if(this.onshow)this.onshow();} this.hide=function(){if(this.onhide)this.onhide();unfreeze();$dh(this.wrapper);this.display=false;cur_dialog=null;} this.no_cancel=function(){this.appframe.$titlebar.find('.close').toggle(false);} -if(opts)this.make();} +if(opts)this.make(opts);} wn.widgets.Dialog.prototype=new wn.widgets.FieldGroup();wn.provide('wn.ui');wn.ui.Dialog=wn.widgets.Dialog $(document).bind('keydown',function(e){if(cur_dialog&&!cur_dialog.no_cancel_flag&&e.which==27){cur_dialog.hide();}}); /* @@ -966,7 +966,7 @@ wn.views.DocListView=wn.ui.Listing.extend({init:function(doctype){this.doctype=d
\
\
\ -
');this.appframe=new wn.ui.AppFrame(this.$page.find('.appframe-area'));wn.views.breadcrumbs($('').appendTo(this.appframe.$titlebar),locals.DocType[this.doctype].module,this.doctype);},setup:function(){var me=this;me.can_delete=wn.model.can_delete(me.doctype);me.meta=locals.DocType[me.doctype];me.$page.find('.wnlist-area').empty(),me.setup_docstatus_filter();me.setup_listview();me.init_list();me.init_stats();me.make_report_button();me.add_delete_option();},make_report_button:function(){var me=this;if(wn.boot.profile.can_get_report.indexOf(this.doctype)!=-1){this.appframe.add_button('Build Report',function(){wn.set_route('Report2',me.doctype);},'icon-th')}},setup_docstatus_filter:function(){var me=this;this.can_submit=$.map(locals.DocPerm,function(d){if(d.parent==me.meta.name&&d.submit)return 1 +
');this.appframe=new wn.ui.AppFrame(this.$page.find('.appframe-area'));wn.views.breadcrumbs(this.appframe,locals.DocType[this.doctype].module,this.doctype);},setup:function(){var me=this;me.can_delete=wn.model.can_delete(me.doctype);me.meta=locals.DocType[me.doctype];me.$page.find('.wnlist-area').empty(),me.setup_docstatus_filter();me.setup_listview();me.init_list();me.init_stats();me.make_report_button();me.add_delete_option();},make_report_button:function(){var me=this;if(wn.boot.profile.can_get_report.indexOf(this.doctype)!=-1){this.appframe.add_button('Build Report',function(){wn.set_route('Report2',me.doctype);},'icon-th')}},setup_docstatus_filter:function(){var me=this;this.can_submit=$.map(locals.DocPerm,function(d){if(d.parent==me.meta.name&&d.submit)return 1 else return null;}).length;if(this.can_submit){this.$page.find('.show-docstatus').removeClass('hide');this.$page.find('.show-docstatus input').click(function(){me.run();})}},setup_listview:function(){if(this.meta.__listjs){eval(this.meta.__listjs);this.listview=new wn.doclistviews[this.doctype](this);}else{this.listview=new wn.views.ListView(this);} this.listview.parent=this;this.wrapper=this.$page.find('.wnlist-area');this.page_length=20;this.allow_delete=true;},init_list:function(auto_run){var me=this;this.make({method:'webnotes.widgets.doclistview.get',get_args:this.get_args,parent:this.wrapper,start:0,page_length:this.page_length,show_filters:true,show_grid:true,new_doctype:this.doctype,allow_delete:this.allow_delete,no_result_message:this.make_no_result(),columns:this.listview.fields});$(this.wrapper).find('button[list_view_doc="'+me.doctype+'"]').click(function(){me.make_new_doc(me.doctype);});if((auto_run!==false)&&(auto_run!==0))this.run();},make_no_result:function(){var no_result_message=repl('
\

No %(doctype_label)s found

\ @@ -1460,8 +1460,8 @@ return false;} /* * lib/js/wn/views/breadcrumbs.js */ -wn.provide('wn.views');wn.views.breadcrumbs=function(parent,module,doctype,name){$(parent).empty();var $bspan=$(parent);if(name){$bspan.append(''+name+'');}else if(doctype){$bspan.append(''+doctype+' List ');}else if(module){$bspan.append(''+module+'');} -if(name&&doctype&&(!locals['DocType'][doctype].issingle)){$bspan.append(repl(' in %(doctype)s List',{doctype:doctype}))};if(doctype&&module&&wn.modules&&wn.modules[module]){$bspan.append(repl(' in %(module)s',{module:module,module_page:wn.modules[module]}))}} +wn.provide('wn.views');wn.views.breadcrumbs=function(appframe,module,doctype,name){appframe.clear_breadcrumbs();if(name){appframe.add_breadcrumb(name);}else if(doctype){appframe.add_breadcrumb(doctype+' List');}else if(module){appframe.add_breadcrumb(module);} +if(name&&doctype&&(!locals['DocType'][doctype].issingle)){appframe.add_breadcrumb(repl(' in %(doctype)s List',{doctype:doctype}))};if(doctype&&module&&wn.modules&&wn.modules[module]){appframe.add_breadcrumb(repl(' in %(module)s',{module:module,module_page:wn.modules[module]}))}} /* * lib/js/legacy/widgets/form/fields.js */ @@ -1694,8 +1694,8 @@ d.cur_frm=f;d.dn=dn;d.table_form=f.meta.istable;f.refresh(dn);$(f.page_layout.wr * lib/js/legacy/widgets/form/form_header.js */ _f.FrmHeader=Class.extend({init:function(parent,frm){this.appframe=new wn.ui.AppFrame(parent) -this.appframe.$titlebar.append('\ - ');this.$w=this.appframe.$w;},refresh:function(){wn.views.breadcrumbs($(this.$w.find('.breadcrumb-area')),cur_frm.meta.module,cur_frm.meta.name,cur_frm.docname);this.refresh_labels();this.refresh_toolbar();},refresh_labels:function(){var labinfo={0:['Saved','label-success'],1:['Submitted','label-info'],2:['Cancelled','label-important']}[cint(cur_frm.doc.docstatus)];if(labinfo[0]=='Saved'&&cur_frm.meta.is_submittable){labinfo[0]='Saved, to Submit';} +this.$w=this.appframe.$w;},refresh:function(){if(cur_frm.cscript.set_breadcrumbs){this.appframe.clear_breadcrumbs();cur_frm.cscript.set_breadcrumbs();}else{wn.views.breadcrumbs(this.appframe,cur_frm.meta.module,cur_frm.meta.name,cur_frm.docname);} +this.refresh_labels();this.refresh_toolbar();},refresh_labels:function(){var labinfo={0:['Saved','label-success'],1:['Submitted','label-info'],2:['Cancelled','label-important']}[cint(cur_frm.doc.docstatus)];if(labinfo[0]=='Saved'&&cur_frm.meta.is_submittable){labinfo[0]='Saved, to Submit';} if(cur_frm.doc.__unsaved||cur_frm.doc.__islocal){labinfo[0]='Not Saved';labinfo[1]='label-warning'} this.set_label(labinfo);if(cur_frm.doc.__unsaved&&cint(cur_frm.doc.docstatus)==1&&this.appframe.buttons['Update']){this.appframe.buttons['Update'].toggle(true);}},set_label:function(labinfo){this.$w.find('.label').remove();$(repl('\ %(lab_status)s',{lab_status:labinfo[0],lab_class:labinfo[1]})).insertBefore(this.$w.find('.breadcrumb-area'))},refresh_toolbar:function(){this.appframe.clear_buttons();var p=cur_frm.get_doc_perms();if(cur_frm.meta.read_only_onload&&!cur_frm.doc.__islocal){if(!cur_frm.editable) @@ -1706,7 +1706,8 @@ if(docstatus==0&&p[SUBMIT]&&(!cur_frm.doc.__islocal)) this.appframe.add_button('Submit',function(){cur_frm.savesubmit();},'icon-lock');if(docstatus==1&&p[SUBMIT]){this.appframe.add_button('Update',function(){cur_frm.saveupdate();},'');if(!cur_frm.doc.__unsaved)this.appframe.buttons['Update'].toggle(false);} if(docstatus==1&&p[CANCEL]) this.appframe.add_button('Cancel',function(){cur_frm.savecancel()},'icon-remove');if(docstatus==2&&p[AMEND]) -this.appframe.add_button('Amend',function(){cur_frm.amend_doc()},'icon-pencil');},show:function(){},hide:function(){},hide_close:function(){this.$w.find('.close').toggle(false);}}) +this.appframe.add_button('Amend',function(){cur_frm.amend_doc()},'icon-pencil');if(cur_frm.meta.description){this.appframe.add_help_button(wn.markdown('## '+cur_frm.doctype+'\n
\n' ++cur_frm.meta.description));}},show:function(){},hide:function(){},hide_close:function(){this.$w.find('.close').toggle(false);}}) /* * lib/js/legacy/widgets/form/form.js */ @@ -1744,7 +1745,7 @@ _f.Frm.prototype.setup_sidebar=function(){this.sidebar=new wn.widgets.form.sideb _f.Frm.prototype.setup_footer=function(){var me=this;var f=this.page_layout.footer;f.save_area=$a(this.page_layout.footer,'div','',{display:'none',marginTop:'11px'});f.help_area=$a(this.page_layout.footer,'div');var b=$btn(f.save_area,'Save',function(){cur_frm.save('Save');},{marginLeft:'0px'},'green');f.show_save=function(){$ds(me.page_layout.footer.save_area);} f.hide_save=function(){$dh(me.page_layout.footer.save_area);}} _f.Frm.prototype.set_intro=function(txt){if(!this.intro_area){this.intro_area=$('
').insertBefore(this.page_layout.body.firstChild);} -if(txt){this.intro_area.html(txt);}else{this.intro_area.remove();this.intro_area=null;}} +if(txt){if(txt.search(/

/)==-1)txt='

'+txt+'

';this.intro_area.html(txt);}else{this.intro_area.remove();this.intro_area=null;}} _f.Frm.prototype.setup_fields_std=function(){var fl=wn.meta.docfield_list[this.doctype];fl.sort(function(a,b){return a.idx-b.idx});if(fl[0]&&fl[0].fieldtype!="Section Break"||get_url_arg('embed')){this.layout.addrow();if(fl[0].fieldtype!="Column Break"){var c=this.layout.addcell();$y(c.wrapper,{padding:'8px'});}} var sec;for(var i=0;i