Merge branch 'master' of github.com:webnotes/erpnext into wsgi
Conflicts:
accounts/doctype/sales_invoice/test_sales_invoice.py
buying/doctype/purchase_order/test_purchase_order.py
stock/doctype/serial_no/serial_no.py
stock/doctype/stock_entry/stock_entry.py
stock/doctype/stock_entry/test_stock_entry.py
stock/doctype/stock_ledger_entry/stock_ledger_entry.py
diff --git a/accounts/doctype/account/account.py b/accounts/doctype/account/account.py
index fba51a9..4961d72 100644
--- a/accounts/doctype/account/account.py
+++ b/accounts/doctype/account/account.py
@@ -7,7 +7,6 @@
from webnotes.utils import flt, fmt_money, cstr, cint
from webnotes import msgprint, _
-sql = webnotes.conn.sql
get_value = webnotes.conn.get_value
class DocType:
@@ -31,17 +30,6 @@
self.validate_duplicate_account()
self.validate_root_details()
self.validate_mandatory()
- self.validate_warehouse_account()
-
- if not self.doc.parent_account:
- self.doc.parent_account = ''
-
- def validate(self):
- self.validate_master_name()
- self.validate_parent()
- self.validate_duplicate_account()
- self.validate_root_details()
- self.validate_mandatory()
self.validate_frozen_accounts_modifier()
if not self.doc.parent_account:
@@ -56,7 +44,7 @@
def validate_parent(self):
"""Fetch Parent Details and validation for account not to be created under ledger"""
if self.doc.parent_account:
- par = sql("""select name, group_or_ledger, is_pl_account, debit_or_credit
+ par = webnotes.conn.sql("""select name, group_or_ledger, is_pl_account, debit_or_credit
from tabAccount where name =%s""", self.doc.parent_account)
if not par:
msgprint("Parent account does not exists", raise_exception=1)
@@ -84,7 +72,7 @@
def validate_duplicate_account(self):
if self.doc.fields.get('__islocal') or not self.doc.name:
company_abbr = webnotes.conn.get_value("Company", self.doc.company, "abbr")
- if sql("""select name from tabAccount where name=%s""",
+ if webnotes.conn.sql("""select name from tabAccount where name=%s""",
(self.doc.account_name + " - " + company_abbr)):
msgprint("Account Name: %s already exists, please rename"
% self.doc.account_name, raise_exception=1)
@@ -133,7 +121,7 @@
return webnotes.conn.get_value("GL Entry", {"account": self.doc.name})
def check_if_child_exists(self):
- return sql("""select name from `tabAccount` where parent_account = %s
+ return webnotes.conn.sql("""select name from `tabAccount` where parent_account = %s
and docstatus != 2""", self.doc.name)
def validate_mandatory(self):
@@ -181,7 +169,7 @@
# Get credit limit
credit_limit_from = 'Customer'
- cr_limit = sql("""select t1.credit_limit from tabCustomer t1, `tabAccount` t2
+ cr_limit = webnotes.conn.sql("""select t1.credit_limit from tabCustomer t1, `tabAccount` t2
where t2.name=%s and t1.name = t2.master_name""", account)
credit_limit = cr_limit and flt(cr_limit[0][0]) or 0
if not credit_limit:
@@ -221,7 +209,7 @@
# rename account name
new_account_name = " - ".join(parts[:-1])
- sql("update `tabAccount` set account_name = %s where name = %s", (new_account_name, old))
+ webnotes.conn.sql("update `tabAccount` set account_name = %s where name = %s", (new_account_name, old))
if merge:
new_name = " - ".join(parts)
diff --git a/accounts/doctype/bank_reconciliation/bank_reconciliation.py b/accounts/doctype/bank_reconciliation/bank_reconciliation.py
index 479b579..132358e 100644
--- a/accounts/doctype/bank_reconciliation/bank_reconciliation.py
+++ b/accounts/doctype/bank_reconciliation/bank_reconciliation.py
@@ -10,7 +10,6 @@
from webnotes.model.bean import getlist, copy_doclist
from webnotes import msgprint
-sql = webnotes.conn.sql
@@ -23,7 +22,7 @@
msgprint("Bank Account, From Date and To Date are Mandatory")
return
- dl = sql("select t1.name, t1.cheque_no, t1.cheque_date, t2.debit, t2.credit, t1.posting_date, t2.against_account from `tabJournal Voucher` t1, `tabJournal Voucher Detail` t2 where t2.parent = t1.name and t2.account = %s and (clearance_date is null or clearance_date = '0000-00-00' or clearance_date = '') and t1.posting_date >= %s and t1.posting_date <= %s and t1.docstatus=1", (self.doc.bank_account, self.doc.from_date, self.doc.to_date))
+ dl = webnotes.conn.sql("select t1.name, t1.cheque_no, t1.cheque_date, t2.debit, t2.credit, t1.posting_date, t2.against_account from `tabJournal Voucher` t1, `tabJournal Voucher Detail` t2 where t2.parent = t1.name and t2.account = %s and (clearance_date is null or clearance_date = '0000-00-00' or clearance_date = '') and t1.posting_date >= %s and t1.posting_date <= %s and t1.docstatus=1", (self.doc.bank_account, self.doc.from_date, self.doc.to_date))
self.doclist = self.doc.clear_table(self.doclist, 'entries')
self.doc.total_amount = 0.0
@@ -47,7 +46,7 @@
msgprint("Clearance Date can not be before Cheque Date (Row #%s)" %
d.idx, raise_exception=1)
- sql("""update `tabJournal Voucher`
+ webnotes.conn.sql("""update `tabJournal Voucher`
set clearance_date = %s, modified = %s where name=%s""",
(d.clearance_date, nowdate(), d.voucher_id))
vouchers.append(d.voucher_id)
diff --git a/accounts/doctype/gl_entry/gl_entry.py b/accounts/doctype/gl_entry/gl_entry.py
index 0c11198..7a73b06 100644
--- a/accounts/doctype/gl_entry/gl_entry.py
+++ b/accounts/doctype/gl_entry/gl_entry.py
@@ -161,16 +161,6 @@
webnotes.conn.sql("update `tab%s` set outstanding_amount=%s where name='%s'" %
(against_voucher_type, bal, against_voucher))
-def validate_freezed_account(account, adv_adj=False):
- """Account has been freezed for other users except account manager"""
-
- freezed_account = webnotes.conn.get_value("Account", account, "freeze_account")
-
- if freezed_account == 'Yes' and not adv_adj \
- and 'Accounts Manager' not in webnotes.user.get_roles():
- webnotes.throw(_("Account") + ": " + account + _(" has been freezed. \
- Only Accounts Manager can do transaction against this account"))
-
def validate_frozen_account(account, adv_adj):
frozen_account = webnotes.conn.get_value("Account", account, "freeze_account")
if frozen_account == 'Yes' and not adv_adj:
@@ -183,4 +173,4 @@
elif frozen_accounts_modifier not in webnotes.user.get_roles():
webnotes.throw(account + _(" is a frozen account. ") +
_("To create / edit transactions against this account, you need role") + ": " +
- frozen_accounts_modifier)
\ No newline at end of file
+ frozen_accounts_modifier)
diff --git a/accounts/doctype/mis_control/mis_control.py b/accounts/doctype/mis_control/mis_control.py
index 84350dc..f10e3d7 100644
--- a/accounts/doctype/mis_control/mis_control.py
+++ b/accounts/doctype/mis_control/mis_control.py
@@ -11,7 +11,6 @@
import webnotes.defaults
-sql = webnotes.conn.sql
from accounts.utils import get_balance_on, get_fiscal_year
@@ -44,7 +43,7 @@
ret['company'] = get_companies()
#--- to get fiscal year and start_date of that fiscal year -----
- res = sql("select name, year_start_date from `tabFiscal Year`")
+ res = webnotes.conn.sql("select name, year_start_date from `tabFiscal Year`")
ret['fiscal_year'] = [r[0] for r in res]
ret['start_dates'] = {}
for r in res:
@@ -52,7 +51,7 @@
#--- from month and to month (for MIS - Comparison Report) -------
month_list = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec']
- fiscal_start_month = sql("select MONTH(year_start_date) from `tabFiscal Year` where name = %s",(webnotes.defaults.get_global_default("fiscal_year")))
+ fiscal_start_month = webnotes.conn.sql("select MONTH(year_start_date) from `tabFiscal Year` where name = %s",(webnotes.defaults.get_global_default("fiscal_year")))
fiscal_start_month = fiscal_start_month and fiscal_start_month[0][0] or 1
mon = ['']
for i in range(fiscal_start_month,13): mon.append(month_list[i-1])
@@ -107,7 +106,7 @@
def dates(self,fiscal_year,from_date,to_date):
import datetime
ret = ''
- start_date = cstr(sql("select year_start_date from `tabFiscal Year` where name = %s",fiscal_year)[0][0])
+ start_date = cstr(webnotes.conn.sql("select year_start_date from `tabFiscal Year` where name = %s",fiscal_year)[0][0])
st_mon = cint(from_date.split('-')[1])
ed_mon = cint(to_date.split('-')[1])
st_day = cint(from_date.split('-')[2])
@@ -152,7 +151,7 @@
def get_totals(self, args):
args = eval(args)
#msgprint(args)
- totals = sql("SELECT %s FROM %s WHERE %s %s %s %s" %(cstr(args['query_val']), cstr(args['tables']), cstr(args['company']), cstr(args['cond']), cstr(args['add_cond']), cstr(args['fil_cond'])), as_dict = 1)[0]
+ totals = webnotes.conn.sql("SELECT %s FROM %s WHERE %s %s %s %s" %(cstr(args['query_val']), cstr(args['tables']), cstr(args['company']), cstr(args['cond']), cstr(args['add_cond']), cstr(args['fil_cond'])), as_dict = 1)[0]
#msgprint(totals)
tot_keys = totals.keys()
# return in flt because JSON doesn't accept Decimal
@@ -185,7 +184,7 @@
# Get Children
# ------------
def get_children(self, parent_account, level, pl, company, fy):
- cl = sql("select distinct account_name, name, debit_or_credit, lft, rgt from `tabAccount` where ifnull(parent_account, '') = %s and ifnull(is_pl_account, 'No')=%s and company=%s and docstatus != 2 order by name asc", (parent_account, pl, company))
+ cl = webnotes.conn.sql("select distinct account_name, name, debit_or_credit, lft, rgt from `tabAccount` where ifnull(parent_account, '') = %s and ifnull(is_pl_account, 'No')=%s and company=%s and docstatus != 2 order by name asc", (parent_account, pl, company))
level0_diff = [0 for p in self.period_list]
if pl=='Yes' and level==0: # switch for income & expenses
cl = [c for c in cl]
@@ -238,7 +237,7 @@
def define_periods(self, year, period):
# get year start date
- ysd = sql("select year_start_date from `tabFiscal Year` where name=%s", year)
+ ysd = webnotes.conn.sql("select year_start_date from `tabFiscal Year` where name=%s", year)
ysd = ysd and ysd[0][0] or ''
self.ysd = ysd
diff --git a/accounts/doctype/period_closing_voucher/period_closing_voucher.py b/accounts/doctype/period_closing_voucher/period_closing_voucher.py
index 99282f5..70a4992 100644
--- a/accounts/doctype/period_closing_voucher/period_closing_voucher.py
+++ b/accounts/doctype/period_closing_voucher/period_closing_voucher.py
@@ -69,7 +69,6 @@
def get_pl_balances(self):
"""Get balance for pl accounts"""
-
return webnotes.conn.sql("""
select t1.account, sum(ifnull(t1.debit,0))-sum(ifnull(t1.credit,0)) as balance
from `tabGL Entry` t1, `tabAccount` t2
@@ -101,4 +100,4 @@
}))
from accounts.general_ledger import make_gl_entries
- make_gl_entries(gl_entries)
\ No newline at end of file
+ make_gl_entries(gl_entries)
diff --git a/accounts/doctype/purchase_invoice/purchase_invoice.py b/accounts/doctype/purchase_invoice/purchase_invoice.py
index 3c3bcb7..a562c67 100644
--- a/accounts/doctype/purchase_invoice/purchase_invoice.py
+++ b/accounts/doctype/purchase_invoice/purchase_invoice.py
@@ -12,7 +12,6 @@
import webnotes.defaults
-sql = webnotes.conn.sql
from controllers.buying_controller import BuyingController
class DocType(BuyingController):
@@ -64,18 +63,21 @@
def get_credit_to(self):
ret = {}
if self.doc.supplier:
- acc_head = sql("""select name, credit_days from `tabAccount`
+ acc_head = webnotes.conn.sql("""select name, credit_days from `tabAccount`
where (name = %s or (master_name = %s and master_type = 'supplier'))
and docstatus != 2 and company = %s""",
(cstr(self.doc.supplier) + " - " + self.company_abbr,
self.doc.supplier, self.doc.company))
-
+
if acc_head and acc_head[0][0]:
ret['credit_to'] = acc_head[0][0]
if not self.doc.due_date:
- ret['due_date'] = add_days(cstr(self.doc.posting_date), acc_head and cint(acc_head[0][1]) or 0)
+ ret['due_date'] = add_days(cstr(self.doc.posting_date),
+ acc_head and cint(acc_head[0][1]) or 0)
elif not acc_head:
- msgprint("%s does not have an Account Head in %s. You must first create it from the Supplier Master" % (self.doc.supplier, self.doc.company))
+ msgprint("%s does not have an Account Head in %s. \
+ You must first create it from the Supplier Master" % \
+ (self.doc.supplier, self.doc.company))
return ret
def set_supplier_defaults(self):
@@ -86,18 +88,10 @@
super(DocType, self).get_advances(self.doc.credit_to,
"Purchase Invoice Advance", "advance_allocation_details", "debit")
- def get_rate(self,arg):
- return get_obj('Purchase Common').get_rate(arg,self)
-
- def get_rate1(self,acc):
- rate = sql("select tax_rate from `tabAccount` where name='%s'"%(acc))
- ret={'add_tax_rate' :rate and flt(rate[0][0]) or 0 }
- return ret
-
def check_active_purchase_items(self):
for d in getlist(self.doclist, 'entries'):
if d.item_code: # extra condn coz item_code is not mandatory in PV
- valid_item = sql("select docstatus,is_purchase_item from tabItem where name = %s",d.item_code)
+ valid_item = webnotes.conn.sql("select docstatus,is_purchase_item from tabItem where name = %s",d.item_code)
if valid_item[0][0] == 2:
msgprint("Item : '%s' is Inactive, you can restore it from Trash" %(d.item_code))
raise Exception
@@ -117,7 +111,7 @@
def validate_bill_no(self):
if self.doc.bill_no and self.doc.bill_no.lower().strip() \
not in ['na', 'not applicable', 'none']:
- b_no = sql("""select bill_no, name, ifnull(is_opening,'') from `tabPurchase Invoice`
+ b_no = webnotes.conn.sql("""select bill_no, name, ifnull(is_opening,'') from `tabPurchase Invoice`
where bill_no = %s and credit_to = %s and docstatus = 1 and name != %s""",
(self.doc.bill_no, self.doc.credit_to, self.doc.name))
if b_no and cstr(b_no[0][2]) == cstr(self.doc.is_opening):
@@ -133,7 +127,7 @@
self.doc.remarks = "No Remarks"
def validate_credit_acc(self):
- acc = sql("select debit_or_credit, is_pl_account from tabAccount where name = %s",
+ acc = webnotes.conn.sql("select debit_or_credit, is_pl_account from tabAccount where name = %s",
self.doc.credit_to)
if not acc:
msgprint("Account: "+ self.doc.credit_to + "does not exist")
@@ -149,7 +143,7 @@
# ------------------------------------------------------------
def check_for_acc_head_of_supplier(self):
if self.doc.supplier and self.doc.credit_to:
- acc_head = sql("select master_name from `tabAccount` where name = %s", self.doc.credit_to)
+ acc_head = webnotes.conn.sql("select master_name from `tabAccount` where name = %s", self.doc.credit_to)
if (acc_head and cstr(acc_head[0][0]) != cstr(self.doc.supplier)) or (not acc_head and (self.doc.credit_to != cstr(self.doc.supplier) + " - " + self.company_abbr)):
msgprint("Credit To: %s do not match with Supplier: %s for Company: %s.\n If both correctly entered, please select Master Type and Master Name in account master." %(self.doc.credit_to,self.doc.supplier,self.doc.company), raise_exception=1)
@@ -161,7 +155,7 @@
for d in getlist(self.doclist,'entries'):
if d.purchase_order and not d.purchase_order in check_list and not d.purchase_receipt:
check_list.append(d.purhcase_order)
- stopped = sql("select name from `tabPurchase Order` where status = 'Stopped' and name = '%s'" % d.purchase_order)
+ stopped = webnotes.conn.sql("select name from `tabPurchase Order` where status = 'Stopped' and name = '%s'" % d.purchase_order)
if stopped:
msgprint("One cannot do any transaction against 'Purchase Order' : %s, it's status is 'Stopped'" % (d.purhcase_order))
raise Exception
@@ -261,11 +255,11 @@
def check_prev_docstatus(self):
for d in getlist(self.doclist,'entries'):
if d.purchase_order:
- submitted = sql("select name from `tabPurchase Order` where docstatus = 1 and name = '%s'" % d.purchase_order)
+ submitted = webnotes.conn.sql("select name from `tabPurchase Order` where docstatus = 1 and name = '%s'" % d.purchase_order)
if not submitted:
webnotes.throw("Purchase Order : "+ cstr(d.purchase_order) +" is not submitted")
if d.purchase_receipt:
- submitted = sql("select name from `tabPurchase Receipt` where docstatus = 1 and name = '%s'" % d.purchase_receipt)
+ submitted = webnotes.conn.sql("select name from `tabPurchase Receipt` where docstatus = 1 and name = '%s'" % d.purchase_receipt)
if not submitted:
webnotes.throw("Purchase Receipt : "+ cstr(d.purchase_receipt) +" is not submitted")
diff --git a/accounts/doctype/purchase_invoice/purchase_invoice.txt b/accounts/doctype/purchase_invoice/purchase_invoice.txt
index f5bdd93..8f77227 100755
--- a/accounts/doctype/purchase_invoice/purchase_invoice.txt
+++ b/accounts/doctype/purchase_invoice/purchase_invoice.txt
@@ -2,12 +2,13 @@
{
"creation": "2013-05-21 16:16:39",
"docstatus": 0,
- "modified": "2013-08-09 14:45:35",
+ "modified": "2013-10-02 14:24:55",
"modified_by": "Administrator",
"owner": "Administrator"
},
{
"allow_attach": 1,
+ "allow_import": 1,
"autoname": "naming_series:",
"doctype": "DocType",
"icon": "icon-file-text",
diff --git a/accounts/doctype/purchase_taxes_and_charges_master/purchase_taxes_and_charges_master.js b/accounts/doctype/purchase_taxes_and_charges_master/purchase_taxes_and_charges_master.js
index 423c4e4..3368773 100644
--- a/accounts/doctype/purchase_taxes_and_charges_master/purchase_taxes_and_charges_master.js
+++ b/accounts/doctype/purchase_taxes_and_charges_master/purchase_taxes_and_charges_master.js
@@ -4,6 +4,8 @@
//
//--------- ONLOAD -------------
+wn.require("app/js/controllers/accounts.js");
+
cur_frm.cscript.onload = function(doc, cdt, cdn) {
}
@@ -134,20 +136,6 @@
}
}
-cur_frm.cscript.account_head = function(doc, cdt, cdn) {
- var d = locals[cdt][cdn];
- if(!d.charge_type && d.account_head){
- alert("Please select Charge Type first");
- validated = false;
- d.account_head = '';
- }
- else if(d.account_head && d.charge_type) {
- arg = "{'charge_type' : '" + d.charge_type + "', 'account_head' : '" + d.account_head + "'}";
- return get_server_fields('get_rate', arg, 'purchase_tax_details', doc, cdt, cdn, 1);
- }
- refresh_field('account_head',d.name,'purchase_tax_details');
-}
-
cur_frm.cscript.rate = function(doc, cdt, cdn) {
var d = locals[cdt][cdn];
if(!d.charge_type && d.rate) {
diff --git a/accounts/doctype/purchase_taxes_and_charges_master/purchase_taxes_and_charges_master.py b/accounts/doctype/purchase_taxes_and_charges_master/purchase_taxes_and_charges_master.py
index a4534ae..3d003f6 100644
--- a/accounts/doctype/purchase_taxes_and_charges_master/purchase_taxes_and_charges_master.py
+++ b/accounts/doctype/purchase_taxes_and_charges_master/purchase_taxes_and_charges_master.py
@@ -8,16 +8,10 @@
from webnotes.model.bean import copy_doclist
from webnotes.model.code import get_obj
-sql = webnotes.conn.sql
class DocType:
def __init__(self, doc, doclist=[]):
self.doc = doc
- self.doclist = doclist
-
- # Get Tax Rate if account type is Tax
- # ===================================================================
- def get_rate(self, arg):
- return get_obj('Purchase Common').get_rate(arg, self)
\ No newline at end of file
+ self.doclist = doclist
\ No newline at end of file
diff --git a/accounts/doctype/sales_invoice/sales_invoice.py b/accounts/doctype/sales_invoice/sales_invoice.py
index daf01ab..92c1680 100644
--- a/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/accounts/doctype/sales_invoice/sales_invoice.py
@@ -264,13 +264,7 @@
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)
-
-
- def get_rate(self,arg):
- """Get tax rate if account type is tax"""
- get_obj('Sales Common').get_rate(arg)
-
+ get_obj('Sales Common').get_adj_percent(self)
def get_comm_rate(self, sales_partner):
"""Get Commission rate of Sales Partner"""
@@ -963,8 +957,7 @@
"doctype": "Delivery Note Item",
"field_map": {
"name": "prevdoc_detail_docname",
- "parent": "prevdoc_docname",
- "parenttype": "prevdoc_doctype",
+ "parent": "against_sales_invoice",
"serial_no": "serial_no"
},
"postprocess": update_item
diff --git a/accounts/doctype/sales_invoice/sales_invoice.txt b/accounts/doctype/sales_invoice/sales_invoice.txt
index b168ba6..331a503 100644
--- a/accounts/doctype/sales_invoice/sales_invoice.txt
+++ b/accounts/doctype/sales_invoice/sales_invoice.txt
@@ -8,6 +8,7 @@
},
{
"allow_attach": 1,
+ "allow_import": 1,
"autoname": "naming_series:",
"default_print_format": "Standard",
"doctype": "DocType",
diff --git a/accounts/doctype/sales_invoice/test_sales_invoice.py b/accounts/doctype/sales_invoice/test_sales_invoice.py
index fbb344e..9f5b95c 100644
--- a/accounts/doctype/sales_invoice/test_sales_invoice.py
+++ b/accounts/doctype/sales_invoice/test_sales_invoice.py
@@ -641,7 +641,7 @@
return new_si
- # if yearly, test 3 repetitions, else test 5 repetitions
+ # if yearly, test 1 repetition, else test 5 repetitions
count = 1 if (no_of_months == 12) else 5
for i in xrange(count):
base_si = _test(i)
diff --git a/accounts/doctype/sales_taxes_and_charges_master/sales_taxes_and_charges_master.js b/accounts/doctype/sales_taxes_and_charges_master/sales_taxes_and_charges_master.js
index f1a6027..d8f55fd 100644
--- a/accounts/doctype/sales_taxes_and_charges_master/sales_taxes_and_charges_master.js
+++ b/accounts/doctype/sales_taxes_and_charges_master/sales_taxes_and_charges_master.js
@@ -2,6 +2,9 @@
// License: GNU General Public License v3. See license.txt
//--------- ONLOAD -------------
+
+wn.require("app/js/controllers/accounts.js");
+
cur_frm.cscript.onload = function(doc, cdt, cdn) {
if(doc.doctype === "Sales Taxes and Charges Master")
erpnext.add_for_territory();
@@ -142,21 +145,6 @@
}
}
-
-cur_frm.cscript.account_head = function(doc, cdt, cdn) {
- var d = locals[cdt][cdn];
- if(!d.charge_type && d.account_head){
- alert("Please select Charge Type first");
- validated = false;
- d.account_head = '';
- }
- else if(d.account_head && d.charge_type) {
- arg = "{'charge_type' : '" + d.charge_type +"', 'account_head' : '" + d.account_head + "'}";
- return get_server_fields('get_rate', arg, 'other_charges', doc, cdt, cdn, 1);
- }
- refresh_field('account_head',d.name,'other_charges');
-}
-
cur_frm.cscript.rate = function(doc, cdt, cdn) {
var d = locals[cdt][cdn];
if(!d.charge_type && d.rate) {
diff --git a/accounts/doctype/sales_taxes_and_charges_master/sales_taxes_and_charges_master.py b/accounts/doctype/sales_taxes_and_charges_master/sales_taxes_and_charges_master.py
index 019edcb..67ba9cb 100644
--- a/accounts/doctype/sales_taxes_and_charges_master/sales_taxes_and_charges_master.py
+++ b/accounts/doctype/sales_taxes_and_charges_master/sales_taxes_and_charges_master.py
@@ -6,11 +6,7 @@
from webnotes.utils import cint
from webnotes.model.controller import DocListController
-class DocType(DocListController):
- def get_rate(self, arg):
- from webnotes.model.code import get_obj
- return get_obj('Sales Common').get_rate(arg)
-
+class DocType(DocListController):
def validate(self):
if self.doc.is_default == 1:
webnotes.conn.sql("""update `tabSales Taxes and Charges Master` set is_default = 0
diff --git a/accounts/page/accounts_browser/accounts_browser.py b/accounts/page/accounts_browser/accounts_browser.py
index 61f4bfc..7bc9549 100644
--- a/accounts/page/accounts_browser/accounts_browser.py
+++ b/accounts/page/accounts_browser/accounts_browser.py
@@ -15,7 +15,7 @@
@webnotes.whitelist()
def get_children():
- args = webnotes.form_dict
+ args = webnotes.local.form_dict
ctype, company = args['ctype'], args['comp']
# root
diff --git a/accounts/page/voucher_import_tool/voucher_import_tool.py b/accounts/page/voucher_import_tool/voucher_import_tool.py
index 9425afc..14e30be 100644
--- a/accounts/page/voucher_import_tool/voucher_import_tool.py
+++ b/accounts/page/voucher_import_tool/voucher_import_tool.py
@@ -64,10 +64,10 @@
data, start_idx = get_data(rows, company_abbr, rows[0][0])
except Exception, e:
- err_msg = webnotes.message_log and "<br>".join(webnotes.message_log) or cstr(e)
+ err_msg = webnotes.local.message_log and "<br>".join(webnotes.local.message_log) or cstr(e)
messages.append("""<p style='color: red'>%s</p>""" % (err_msg or "No message"))
webnotes.errprint(webnotes.getTraceback())
- webnotes.message_log = []
+ webnotes.local.message_log = []
return messages
return import_vouchers(common_values, data, start_idx, rows[0][0])
@@ -117,11 +117,11 @@
d = data[i][0]
if import_type == "Voucher Import: Two Accounts" and flt(d.get("amount")) == 0:
- webnotes.message_log = ["Amount not specified"]
+ webnotes.local.message_log = ["Amount not specified"]
raise Exception
elif import_type == "Voucher Import: Multiple Accounts" and \
(flt(d.get("total_debit")) == 0 or flt(d.get("total_credit")) == 0):
- webnotes.message_log = ["Total Debit and Total Credit amount can not be zero"]
+ webnotes.local.message_log = ["Total Debit and Total Credit amount can not be zero"]
raise Exception
else:
d.posting_date = parse_date(d.posting_date)
@@ -174,7 +174,7 @@
details.append(detail)
if not details:
- webnotes.message_log = ["""No accounts found.
+ webnotes.local.message_log = ["""No accounts found.
If you entered accounts correctly, please check template once"""]
raise Exception
@@ -193,12 +193,12 @@
webnotes.conn.commit()
except Exception, e:
webnotes.conn.rollback()
- err_msg = webnotes.message_log and "<br>".join(webnotes.message_log) or cstr(e)
+ err_msg = webnotes.local.message_log and "<br>".join(webnotes.local.message_log) or cstr(e)
messages.append("""<p style='color: red'>[row #%s] %s failed: %s</p>"""
% ((start_idx + 1) + i, jv.name or "", err_msg or "No message"))
messages.append("<p style='color: red'>All transactions rolled back</p>")
webnotes.errprint(webnotes.getTraceback())
- webnotes.message_log = []
+ webnotes.local.message_log = []
return messages
diff --git a/accounts/utils.py b/accounts/utils.py
index 5c6c16b..ac82312 100644
--- a/accounts/utils.py
+++ b/accounts/utils.py
@@ -108,7 +108,7 @@
@webnotes.whitelist()
def add_ac(args=None):
if not args:
- args = webnotes.form_dict
+ args = webnotes.local.form_dict
args.pop("cmd")
ac = webnotes.bean(args)
@@ -121,7 +121,7 @@
@webnotes.whitelist()
def add_cc(args=None):
if not args:
- args = webnotes.form_dict
+ args = webnotes.local.form_dict
args.pop("cmd")
cc = webnotes.bean(args)
diff --git a/buying/doctype/purchase_common/purchase_common.js b/buying/doctype/purchase_common/purchase_common.js
index 433a76f..023c7f3 100644
--- a/buying/doctype/purchase_common/purchase_common.js
+++ b/buying/doctype/purchase_common/purchase_common.js
@@ -8,6 +8,7 @@
wn.provide("erpnext.buying");
wn.require("app/js/transaction.js");
+wn.require("app/js/controllers/accounts.js");
erpnext.buying.BuyingController = erpnext.TransactionController.extend({
onload: function() {
diff --git a/buying/doctype/purchase_common/purchase_common.py b/buying/doctype/purchase_common/purchase_common.py
index 9b6dc6c..8637e5f 100644
--- a/buying/doctype/purchase_common/purchase_common.py
+++ b/buying/doctype/purchase_common/purchase_common.py
@@ -10,7 +10,6 @@
from buying.utils import get_last_purchase_details
-sql = webnotes.conn.sql
from controllers.buying_controller import BuyingController
class DocType(BuyingController):
@@ -23,27 +22,20 @@
msgprint(_("You need to put at least one item in the item table."), raise_exception=True)
def get_supplier_details(self, name = ''):
- details = sql("select supplier_name,address from `tabSupplier` where name = '%s' and docstatus != 2" %(name), as_dict = 1)
+ details = webnotes.conn.sql("select supplier_name,address from `tabSupplier` where name = '%s' and docstatus != 2" %(name), as_dict = 1)
if details:
ret = {
'supplier_name' : details and details[0]['supplier_name'] or '',
'supplier_address' : details and details[0]['address'] or ''
}
# ********** get primary contact details (this is done separately coz. , in case there is no primary contact thn it would not be able to fetch customer details in case of join query)
- contact_det = sql("select contact_name, contact_no, email_id from `tabContact` where supplier = '%s' and is_supplier = 1 and is_primary_contact = 'Yes' and docstatus != 2" %(name), as_dict = 1)
+ contact_det = webnotes.conn.sql("select contact_name, contact_no, email_id from `tabContact` where supplier = '%s' and is_supplier = 1 and is_primary_contact = 'Yes' and docstatus != 2" %(name), as_dict = 1)
ret['contact_person'] = contact_det and contact_det[0]['contact_name'] or ''
return ret
else:
msgprint("Supplier : %s does not exists" % (name))
raise Exception
- # Get Available Qty at Warehouse
- def get_bin_details( self, arg = ''):
- arg = eval(arg)
- bin = sql("select projected_qty from `tabBin` where item_code = %s and warehouse = %s", (arg['item_code'], arg['warehouse']), as_dict=1)
- ret = { 'projected_qty' : bin and flt(bin[0]['projected_qty']) or 0 }
- return ret
-
def update_last_purchase_rate(self, obj, is_submit):
"""updates last_purchase_rate in item table for each item"""
@@ -70,7 +62,7 @@
# update last purchsae rate
if last_purchase_rate:
- sql("update `tabItem` set last_purchase_rate = %s where name = %s",
+ webnotes.conn.sql("update `tabItem` set last_purchase_rate = %s where name = %s",
(flt(last_purchase_rate),d.item_code))
def get_last_purchase_rate(self, obj):
@@ -107,7 +99,7 @@
raise Exception
# udpate with latest quantities
- bin = sql("select projected_qty from `tabBin` where item_code = %s and warehouse = %s", (d.item_code, d.warehouse), as_dict = 1)
+ bin = webnotes.conn.sql("select projected_qty from `tabBin` where item_code = %s and warehouse = %s", (d.item_code, d.warehouse), as_dict = 1)
f_lst ={'projected_qty': bin and flt(bin[0]['projected_qty']) or 0, 'ordered_qty': 0, 'received_qty' : 0}
if d.doctype == 'Purchase Receipt Item':
@@ -116,7 +108,7 @@
if d.fields.has_key(x):
d.fields[x] = f_lst[x]
- item = sql("select is_stock_item, is_purchase_item, is_sub_contracted_item, end_of_life from tabItem where name=%s",
+ item = webnotes.conn.sql("select is_stock_item, is_purchase_item, is_sub_contracted_item, end_of_life from tabItem where name=%s",
d.item_code)
if not item:
msgprint("Item %s does not exist in Item Master." % cstr(d.item_code), raise_exception=True)
@@ -139,7 +131,7 @@
# if is not stock item
f = [d.schedule_date, d.item_code, d.description]
- ch = sql("select is_stock_item from `tabItem` where name = '%s'"%d.item_code)
+ ch = webnotes.conn.sql("select is_stock_item from `tabItem` where name = '%s'"%d.item_code)
if ch and ch[0][0] == 'Yes':
# check for same items
@@ -165,18 +157,18 @@
# but if in Material Request uom KG it can change in PO
get_qty = (transaction == 'Material Request - Purchase Order') and 'qty * conversion_factor' or 'qty'
- qty = sql("select sum(%s) from `tab%s` where %s = '%s' and docstatus = 1 and parent != '%s'"% ( get_qty, curr_doctype, ref_tab_fname, ref_tab_dn, curr_parent_name))
+ qty = webnotes.conn.sql("select sum(%s) from `tab%s` where %s = '%s' and docstatus = 1 and parent != '%s'"% ( get_qty, curr_doctype, ref_tab_fname, ref_tab_dn, curr_parent_name))
qty = qty and flt(qty[0][0]) or 0
# get total qty of ref doctype
#--------------------
- max_qty = sql("select qty from `tab%s` where name = '%s' and docstatus = 1"% (ref_doc_tname, ref_tab_dn))
+ max_qty = webnotes.conn.sql("select qty from `tab%s` where name = '%s' and docstatus = 1"% (ref_doc_tname, ref_tab_dn))
max_qty = max_qty and flt(max_qty[0][0]) or 0
return cstr(qty)+'~~~'+cstr(max_qty)
def check_for_stopped_status(self, doctype, docname):
- stopped = sql("select name from `tab%s` where name = '%s' and status = 'Stopped'" %
+ stopped = webnotes.conn.sql("select name from `tab%s` where name = '%s' and status = 'Stopped'" %
( doctype, docname))
if stopped:
msgprint("One cannot do any transaction against %s : %s, it's status is 'Stopped'" %
@@ -184,7 +176,7 @@
def check_docstatus(self, check, doctype, docname , detail_doctype = ''):
if check == 'Next':
- submitted = sql("""select t1.name from `tab%s` t1,`tab%s` t2
+ submitted = webnotes.conn.sql("""select t1.name from `tab%s` t1,`tab%s` t2
where t1.name = t2.parent and t2.prevdoc_docname = %s and t1.docstatus = 1"""
% (doctype, detail_doctype, '%s'), docname)
if submitted:
@@ -192,23 +184,8 @@
+ _(" has already been submitted."), raise_exception=1)
if check == 'Previous':
- submitted = sql("""select name from `tab%s`
+ submitted = webnotes.conn.sql("""select name from `tab%s`
where docstatus = 1 and name = %s"""% (doctype, '%s'), docname)
if not submitted:
msgprint(cstr(doctype) + ": " + cstr(submitted[0][0])
+ _(" not submitted"), raise_exception=1)
-
- def get_rate(self, arg, obj):
- arg = eval(arg)
- rate = sql("select account_type, tax_rate from `tabAccount` where name = %s"
- , (arg['account_head']), as_dict=1)
-
- return {'rate': rate and (rate[0]['account_type'] == 'Tax' \
- and not arg['charge_type'] == 'Actual') and flt(rate[0]['tax_rate']) or 0 }
-
- def get_prevdoc_date(self, obj):
- for d in getlist(obj.doclist, obj.fname):
- if d.prevdoc_doctype and d.prevdoc_docname:
- dt = sql("select transaction_date from `tab%s` where name = %s"
- % (d.prevdoc_doctype, '%s'), (d.prevdoc_docname))
- d.prevdoc_date = dt and dt[0][0].strftime('%Y-%m-%d') or ''
\ No newline at end of file
diff --git a/buying/doctype/purchase_order/purchase_order.js b/buying/doctype/purchase_order/purchase_order.js
index 9967f15..f32f11a 100644
--- a/buying/doctype/purchase_order/purchase_order.js
+++ b/buying/doctype/purchase_order/purchase_order.js
@@ -185,9 +185,9 @@
if(cl[i].prevdoc_doctype == 'Material Request' && cl[i].prevdoc_docname && prevdoc_list.indexOf(cl[i].prevdoc_docname) == -1) {
prevdoc_list.push(cl[i].prevdoc_docname);
if(prevdoc_list.length ==1)
- out += make_row(cl[i].prevdoc_doctype, cl[i].prevdoc_docname, cl[i].prevdoc_date,0);
+ out += make_row(cl[i].prevdoc_doctype, cl[i].prevdoc_docname, null,0);
else
- out += make_row('', cl[i].prevdoc_docname, cl[i].prevdoc_date,0);
+ out += make_row('', cl[i].prevdoc_docname,null,0);
}
}
}
diff --git a/buying/doctype/purchase_order/purchase_order.py b/buying/doctype/purchase_order/purchase_order.py
index 64f89e3..cf207bb 100644
--- a/buying/doctype/purchase_order/purchase_order.py
+++ b/buying/doctype/purchase_order/purchase_order.py
@@ -9,7 +9,6 @@
from webnotes.model.code import get_obj
from webnotes import msgprint
-sql = webnotes.conn.sql
from controllers.buying_controller import BuyingController
class DocType(BuyingController):
@@ -42,7 +41,6 @@
pc_obj = get_obj(dt='Purchase Common')
pc_obj.validate_for_items(self)
- pc_obj.get_prevdoc_date(self)
self.check_for_stopped_status(pc_obj)
self.validate_uom_is_integer("uom", "qty")
@@ -66,10 +64,6 @@
}
})
- # get available qty at warehouse
- def get_bin_details(self, arg = ''):
- return get_obj(dt='Purchase Common').get_bin_details(arg)
-
def get_schedule_dates(self):
for d in getlist(self.doclist, 'po_details'):
if d.prevdoc_detail_docname and not d.schedule_date:
@@ -133,8 +127,8 @@
update_bin(args)
def check_modified_date(self):
- mod_db = sql("select modified from `tabPurchase Order` where name = '%s'" % self.doc.name)
- date_diff = sql("select TIMEDIFF('%s', '%s')" % ( mod_db[0][0],cstr(self.doc.modified)))
+ mod_db = webnotes.conn.sql("select modified from `tabPurchase Order` where name = '%s'" % self.doc.name)
+ date_diff = webnotes.conn.sql("select TIMEDIFF('%s', '%s')" % ( mod_db[0][0],cstr(self.doc.modified)))
if date_diff and date_diff[0][0]:
msgprint(cstr(self.doc.doctype) +" => "+ cstr(self.doc.name) +" has been modified. Please Refresh. ")
@@ -173,7 +167,7 @@
pc_obj.check_docstatus(check = 'Next', doctype = 'Purchase Receipt', docname = self.doc.name, detail_doctype = 'Purchase Receipt Item')
# Check if Purchase Invoice has been submitted against current Purchase Order
- submitted = sql("select t1.name from `tabPurchase Invoice` t1,`tabPurchase Invoice Item` t2 where t1.name = t2.parent and t2.purchase_order = '%s' and t1.docstatus = 1" % self.doc.name)
+ submitted = webnotes.conn.sql("select t1.name from `tabPurchase Invoice` t1,`tabPurchase Invoice Item` t2 where t1.name = t2.parent and t2.purchase_order = '%s' and t1.docstatus = 1" % self.doc.name)
if submitted:
msgprint("Purchase Invoice : " + cstr(submitted[0][0]) + " has already been submitted !")
raise Exception
@@ -186,9 +180,6 @@
def on_update(self):
pass
- def get_rate(self,arg):
- return get_obj('Purchase Common').get_rate(arg,self)
-
@webnotes.whitelist()
def make_purchase_receipt(source_name, target_doclist=None):
from webnotes.model.mapper import get_mapped_doclist
diff --git a/buying/doctype/purchase_order/purchase_order.txt b/buying/doctype/purchase_order/purchase_order.txt
index d3c1620..7169aaf 100644
--- a/buying/doctype/purchase_order/purchase_order.txt
+++ b/buying/doctype/purchase_order/purchase_order.txt
@@ -2,12 +2,13 @@
{
"creation": "2013-05-21 16:16:39",
"docstatus": 0,
- "modified": "2013-09-12 18:34:54",
+ "modified": "2013-10-02 14:24:49",
"modified_by": "Administrator",
"owner": "Administrator"
},
{
"allow_attach": 1,
+ "allow_import": 1,
"autoname": "naming_series:",
"doctype": "DocType",
"document_type": "Transaction",
@@ -132,7 +133,6 @@
"fieldtype": "Date",
"in_filter": 1,
"label": "Purchase Order Date",
- "no_copy": 1,
"oldfieldname": "transaction_date",
"oldfieldtype": "Date",
"reqd": 1,
diff --git a/buying/doctype/purchase_order_item/purchase_order_item.txt b/buying/doctype/purchase_order_item/purchase_order_item.txt
index 36b81d2..fade98f 100755
--- a/buying/doctype/purchase_order_item/purchase_order_item.txt
+++ b/buying/doctype/purchase_order_item/purchase_order_item.txt
@@ -2,7 +2,7 @@
{
"creation": "2013-05-24 19:29:06",
"docstatus": 0,
- "modified": "2013-08-07 14:44:12",
+ "modified": "2013-10-10 17:01:57",
"modified_by": "Administrator",
"owner": "Administrator"
},
@@ -308,21 +308,6 @@
},
{
"doctype": "DocField",
- "fieldname": "prevdoc_date",
- "fieldtype": "Date",
- "hidden": 1,
- "in_filter": 1,
- "in_list_view": 0,
- "label": "Material Request Date",
- "no_copy": 1,
- "oldfieldname": "prevdoc_date",
- "oldfieldtype": "Date",
- "print_hide": 1,
- "read_only": 1,
- "search_index": 0
- },
- {
- "doctype": "DocField",
"fieldname": "prevdoc_detail_docname",
"fieldtype": "Data",
"hidden": 1,
diff --git a/buying/doctype/supplier/supplier.py b/buying/doctype/supplier/supplier.py
index 15e1d62..3c01633 100644
--- a/buying/doctype/supplier/supplier.py
+++ b/buying/doctype/supplier/supplier.py
@@ -9,7 +9,6 @@
from webnotes import msgprint, _
from webnotes.model.doc import make_autoname
-sql = webnotes.conn.sql
from utilities.transaction_base import TransactionBase
@@ -29,7 +28,7 @@
self.doc.name = make_autoname(self.doc.naming_series + '.#####')
def update_credit_days_limit(self):
- sql("""update tabAccount set credit_days = %s where name = %s""",
+ webnotes.conn.sql("""update tabAccount set credit_days = %s where name = %s""",
(cint(self.doc.credit_days), self.doc.name + " - " + self.get_company_abbr()))
def on_update(self):
@@ -43,7 +42,7 @@
self.update_credit_days_limit()
def get_payables_group(self):
- g = sql("select payables_group from tabCompany where name=%s", self.doc.company)
+ g = webnotes.conn.sql("select payables_group from tabCompany where name=%s", self.doc.company)
g = g and g[0][0] or ''
if not g:
msgprint("Update Company master, assign a default group for Payables")
@@ -65,14 +64,14 @@
msgprint(_("Created Group ") + ac)
def get_company_abbr(self):
- return sql("select abbr from tabCompany where name=%s", self.doc.company)[0][0]
+ return webnotes.conn.sql("select abbr from tabCompany where name=%s", self.doc.company)[0][0]
def get_parent_account(self, abbr):
if (not self.doc.supplier_type):
msgprint("Supplier Type is mandatory")
raise Exception
- if not sql("select name from tabAccount where name=%s and debit_or_credit = 'Credit' and ifnull(is_pl_account, 'No') = 'No'", (self.doc.supplier_type + " - " + abbr)):
+ if not webnotes.conn.sql("select name from tabAccount where name=%s and debit_or_credit = 'Credit' and ifnull(is_pl_account, 'No') = 'No'", (self.doc.supplier_type + " - " + abbr)):
# if not group created , create it
self.add_account(self.doc.supplier_type, self.get_payables_group(), abbr)
@@ -90,7 +89,7 @@
abbr = self.get_company_abbr()
parent_account = self.get_parent_account(abbr)
- if not sql("select name from tabAccount where name=%s", (self.doc.name + " - " + abbr)):
+ if not webnotes.conn.sql("select name from tabAccount where name=%s", (self.doc.name + " - " + abbr)):
ac_bean = webnotes.bean({
"doctype": "Account",
'account_name': self.doc.name,
@@ -121,15 +120,15 @@
def get_contacts(self,nm):
if nm:
- contact_details =webnotes.conn.convert_to_lists(sql("select name, CONCAT(IFNULL(first_name,''),' ',IFNULL(last_name,'')),contact_no,email_id from `tabContact` where supplier = '%s'"%nm))
+ contact_details =webnotes.conn.convert_to_lists(webnotes.conn.sql("select name, CONCAT(IFNULL(first_name,''),' ',IFNULL(last_name,'')),contact_no,email_id from `tabContact` where supplier = '%s'"%nm))
return contact_details
else:
return ''
def delete_supplier_address(self):
- for rec in sql("select * from `tabAddress` where supplier=%s", (self.doc.name,), as_dict=1):
- sql("delete from `tabAddress` where name=%s",(rec['name']))
+ for rec in webnotes.conn.sql("select * from `tabAddress` where supplier=%s", (self.doc.name,), as_dict=1):
+ webnotes.conn.sql("delete from `tabAddress` where name=%s",(rec['name']))
def delete_supplier_contact(self):
for contact in webnotes.conn.sql_list("""select name from `tabContact`
@@ -138,7 +137,7 @@
def delete_supplier_account(self):
"""delete supplier's ledger if exist and check balance before deletion"""
- acc = sql("select name from `tabAccount` where master_type = 'Supplier' \
+ acc = webnotes.conn.sql("select name from `tabAccount` where master_type = 'Supplier' \
and master_name = %s and docstatus < 2", self.doc.name)
if acc:
from webnotes.model import delete_doc
@@ -161,7 +160,7 @@
('Purchase Receipt', 'supplier'),
('Serial No', 'supplier')]
for rec in update_fields:
- sql("update `tab%s` set supplier_name = %s where `%s` = %s" % \
+ webnotes.conn.sql("update `tab%s` set supplier_name = %s where `%s` = %s" % \
(rec[0], '%s', rec[1], '%s'), (new, old))
for account in webnotes.conn.sql("""select name, account_name from
diff --git a/buying/doctype/supplier_quotation/supplier_quotation.py b/buying/doctype/supplier_quotation/supplier_quotation.py
index c3d2f78..8c5224e 100644
--- a/buying/doctype/supplier_quotation/supplier_quotation.py
+++ b/buying/doctype/supplier_quotation/supplier_quotation.py
@@ -54,7 +54,6 @@
def validate_common(self):
pc = get_obj('Purchase Common')
pc.validate_for_items(self)
- pc.get_prevdoc_date(self)
@webnotes.whitelist()
def make_purchase_order(source_name, target_doclist=None):
diff --git a/buying/doctype/supplier_quotation/supplier_quotation.txt b/buying/doctype/supplier_quotation/supplier_quotation.txt
index 36747d3..ddd1730 100644
--- a/buying/doctype/supplier_quotation/supplier_quotation.txt
+++ b/buying/doctype/supplier_quotation/supplier_quotation.txt
@@ -2,12 +2,13 @@
{
"creation": "2013-05-21 16:16:45",
"docstatus": 0,
- "modified": "2013-08-09 14:45:58",
+ "modified": "2013-10-02 14:24:44",
"modified_by": "Administrator",
"owner": "Administrator"
},
{
"allow_attach": 1,
+ "allow_import": 1,
"autoname": "naming_series:",
"doctype": "DocType",
"document_type": "Transaction",
diff --git a/buying/doctype/supplier_quotation_item/supplier_quotation_item.txt b/buying/doctype/supplier_quotation_item/supplier_quotation_item.txt
index 1d16291..515cdb2 100644
--- a/buying/doctype/supplier_quotation_item/supplier_quotation_item.txt
+++ b/buying/doctype/supplier_quotation_item/supplier_quotation_item.txt
@@ -2,7 +2,7 @@
{
"creation": "2013-05-22 12:43:10",
"docstatus": 0,
- "modified": "2013-08-07 14:44:18",
+ "modified": "2013-10-10 17:02:11",
"modified_by": "Administrator",
"owner": "Administrator"
},
@@ -261,21 +261,6 @@
},
{
"doctype": "DocField",
- "fieldname": "prevdoc_date",
- "fieldtype": "Date",
- "hidden": 1,
- "in_filter": 1,
- "in_list_view": 0,
- "label": "Material Request Date",
- "no_copy": 1,
- "oldfieldname": "prevdoc_date",
- "oldfieldtype": "Date",
- "print_hide": 1,
- "read_only": 1,
- "search_index": 0
- },
- {
- "doctype": "DocField",
"fieldname": "prevdoc_detail_docname",
"fieldtype": "Data",
"hidden": 1,
diff --git a/controllers/accounts_controller.py b/controllers/accounts_controller.py
index 3af9c7a..5121d69 100644
--- a/controllers/accounts_controller.py
+++ b/controllers/accounts_controller.py
@@ -422,3 +422,7 @@
self._abbr = webnotes.conn.get_value("Company", self.doc.company, "abbr")
return self._abbr
+
+@webnotes.whitelist()
+def get_tax_rate(account_head):
+ return webnotes.conn.get_value("Account", account_head, "tax_rate")
diff --git a/controllers/buying_controller.py b/controllers/buying_controller.py
index 2aa7c83..5176b16 100644
--- a/controllers/buying_controller.py
+++ b/controllers/buying_controller.py
@@ -2,7 +2,7 @@
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
-import webnotes
+import webnotes, json
from webnotes import _, msgprint
from webnotes.utils import flt, _round
@@ -12,6 +12,7 @@
from controllers.stock_controller import StockController
class BuyingController(StockController):
+
def onload_post_render(self):
# contact, address, item details
self.set_missing_values()
diff --git a/controllers/selling_controller.py b/controllers/selling_controller.py
index 845ba85..5c7b66c 100644
--- a/controllers/selling_controller.py
+++ b/controllers/selling_controller.py
@@ -14,7 +14,10 @@
def onload_post_render(self):
# contact, address, item details and pos details (if applicable)
self.set_missing_values()
-
+
+ def get_sender(self, comm):
+ return webnotes.conn.get_value('Sales Email Settings', None, 'email_id')
+
def set_missing_values(self, for_validate=False):
super(SellingController, self).set_missing_values(for_validate)
@@ -233,4 +236,4 @@
self.doc.order_type = "Sales"
elif self.doc.order_type not in valid_types:
msgprint(_(self.meta.get_label("order_type")) + " " +
- _("must be one of") + ": " + comma_or(valid_types), raise_exception=True)
\ No newline at end of file
+ _("must be one of") + ": " + comma_or(valid_types), raise_exception=True)
diff --git a/controllers/status_updater.py b/controllers/status_updater.py
index 070f200..b2a0e17 100644
--- a/controllers/status_updater.py
+++ b/controllers/status_updater.py
@@ -8,6 +8,51 @@
from webnotes.model.controller import DocListController
+status_map = {
+ "Contact": [
+ ["Replied", "communication_sent"],
+ ["Open", "communication_received"]
+ ],
+ "Job Applicant": [
+ ["Replied", "communication_sent"],
+ ["Open", "communication_received"]
+ ],
+ "Lead": [
+ ["Replied", "communication_sent"],
+ ["Converted", "has_customer"],
+ ["Opportunity", "has_opportunity"],
+ ["Open", "communication_received"],
+ ],
+ "Opportunity": [
+ ["Draft", None],
+ ["Submitted", "eval:self.doc.docstatus==1"],
+ ["Lost", "eval:self.doc.status=='Lost'"],
+ ["Quotation", "has_quotation"],
+ ["Replied", "communication_sent"],
+ ["Cancelled", "eval:self.doc.docstatus==2"],
+ ["Open", "communication_received"],
+ ],
+ "Quotation": [
+ ["Draft", None],
+ ["Submitted", "eval:self.doc.docstatus==1"],
+ ["Lost", "eval:self.doc.status=='Lost'"],
+ ["Ordered", "has_sales_order"],
+ ["Replied", "communication_sent"],
+ ["Cancelled", "eval:self.doc.docstatus==2"],
+ ["Open", "communication_received"],
+ ],
+ "Sales Order": [
+ ["Draft", None],
+ ["Submitted", "eval:self.doc.docstatus==1"],
+ ["Stopped", "eval:self.doc.status=='Stopped'"],
+ ["Cancelled", "eval:self.doc.docstatus==2"],
+ ],
+ "Support Ticket": [
+ ["Replied", "communication_sent"],
+ ["Open", "communication_received"]
+ ],
+}
+
class StatusUpdater(DocListController):
"""
Updates the status of the calling records
@@ -20,6 +65,45 @@
self.update_qty()
self.validate_qty()
+ def set_status(self, update=False):
+ if self.doc.get("__islocal"):
+ return
+
+ if self.doc.doctype in status_map:
+ sl = status_map[self.doc.doctype][:]
+ sl.reverse()
+ for s in sl:
+ if not s[1]:
+ self.doc.status = s[0]
+ break
+ elif s[1].startswith("eval:"):
+ if eval(s[1][5:]):
+ self.doc.status = s[0]
+ break
+ elif getattr(self, s[1])():
+ self.doc.status = s[0]
+ break
+
+ if update:
+ webnotes.conn.set_value(self.doc.doctype, self.doc.name, "status", self.doc.status)
+
+ def on_communication(self):
+ self.communication_set = True
+ self.set_status(update=True)
+ del self.communication_set
+
+ def communication_received(self):
+ if getattr(self, "communication_set", False):
+ last_comm = self.doclist.get({"doctype":"Communication"})
+ if last_comm:
+ return last_comm[-1].sent_or_received == "Received"
+
+ def communication_sent(self):
+ if getattr(self, "communication_set", False):
+ last_comm = self.doclist.get({"doctype":"Communication"})
+ if last_comm:
+ return last_comm[-1].sent_or_received == "Sent"
+
def validate_qty(self):
"""
Validates qty at row level
diff --git a/home/doctype/feed/feed.py b/home/doctype/feed/feed.py
index 25abf57..ebee5c4 100644
--- a/home/doctype/feed/feed.py
+++ b/home/doctype/feed/feed.py
@@ -7,7 +7,6 @@
from webnotes.model import db_exists
from webnotes.model.bean import copy_doclist
-sql = webnotes.conn.sql
diff --git a/hr/doctype/attendance/attendance.py b/hr/doctype/attendance/attendance.py
index 7b82bc5..6d52b57 100644
--- a/hr/doctype/attendance/attendance.py
+++ b/hr/doctype/attendance/attendance.py
@@ -7,7 +7,6 @@
from webnotes.utils import getdate, nowdate
from webnotes import msgprint, _
-sql = webnotes.conn.sql
class DocType:
def __init__(self, doc, doclist=[]):
@@ -15,7 +14,7 @@
self.doclist = doclist
def validate_duplicate_record(self):
- res = sql("""select name from `tabAttendance` where employee = %s and att_date = %s
+ res = webnotes.conn.sql("""select name from `tabAttendance` where employee = %s and att_date = %s
and name != %s and docstatus = 1""",
(self.doc.employee, self.doc.att_date, self.doc.name))
if res:
@@ -24,7 +23,7 @@
def check_leave_record(self):
if self.doc.status == 'Present':
- leave = sql("""select name from `tabLeave Application`
+ leave = webnotes.conn.sql("""select name from `tabLeave Application`
where employee = %s and %s between from_date and to_date and status = 'Approved'
and docstatus = 1""", (self.doc.employee, self.doc.att_date))
@@ -42,7 +41,7 @@
msgprint(_("Attendance can not be marked for future dates"), raise_exception=1)
def validate_employee(self):
- emp = sql("select name from `tabEmployee` where name = %s and status = 'Active'",
+ emp = webnotes.conn.sql("select name from `tabEmployee` where name = %s and status = 'Active'",
self.doc.employee)
if not emp:
msgprint(_("Employee: ") + self.doc.employee +
diff --git a/hr/doctype/employee/employee.py b/hr/doctype/employee/employee.py
index e28e02d..b46123a 100644
--- a/hr/doctype/employee/employee.py
+++ b/hr/doctype/employee/employee.py
@@ -4,11 +4,10 @@
from __future__ import unicode_literals
import webnotes
-from webnotes.utils import getdate, validate_email_add, cstr
+from webnotes.utils import getdate, validate_email_add, cstr, cint
from webnotes.model.doc import make_autoname
from webnotes import msgprint, _
-sql = webnotes.conn.sql
class DocType:
def __init__(self,doc,doclist=[]):
@@ -40,12 +39,12 @@
self.validate_email()
self.validate_status()
self.validate_employee_leave_approver()
+ self.update_dob_event()
def on_update(self):
if self.doc.user_id:
self.update_user_default()
self.update_profile()
- self.update_dob_event()
def update_user_default(self):
webnotes.conn.set_default("employee", self.doc.name, self.doc.user_id)
@@ -156,10 +155,11 @@
raise_exception=InvalidLeaveApproverError)
def update_dob_event(self):
- if self.doc.status == "Active" and self.doc.date_of_birth:
+ if self.doc.status == "Active" and self.doc.date_of_birth \
+ and not cint(webnotes.conn.get_value("HR Settings", None, "stop_birthday_reminders")):
birthday_event = webnotes.conn.sql("""select name from `tabEvent` where repeat_on='Every Year'
and ref_type='Employee' and ref_name=%s""", self.doc.name)
-
+
starts_on = self.doc.date_of_birth + " 00:00:00"
ends_on = self.doc.date_of_birth + " 00:15:00"
diff --git a/hr/doctype/employee/employee.txt b/hr/doctype/employee/employee.txt
index bbe87ad..4ed8732 100644
--- a/hr/doctype/employee/employee.txt
+++ b/hr/doctype/employee/employee.txt
@@ -2,12 +2,13 @@
{
"creation": "2013-03-07 09:04:18",
"docstatus": 0,
- "modified": "2013-08-08 14:22:11",
+ "modified": "2013-10-11 10:52:53",
"modified_by": "Administrator",
"owner": "Administrator"
},
{
"allow_attach": 1,
+ "allow_rename": 1,
"autoname": "naming_series:",
"doctype": "DocType",
"document_type": "Master",
diff --git a/hr/doctype/holiday_list/holiday_list.py b/hr/doctype/holiday_list/holiday_list.py
index 81d18f3..100c140 100644
--- a/hr/doctype/holiday_list/holiday_list.py
+++ b/hr/doctype/holiday_list/holiday_list.py
@@ -10,7 +10,6 @@
from webnotes.model.bean import copy_doclist
from webnotes import msgprint
-sql = webnotes.conn.sql
import datetime
diff --git a/hr/doctype/hr_settings/hr_settings.py b/hr/doctype/hr_settings/hr_settings.py
index 784339d..101905c 100644
--- a/hr/doctype/hr_settings/hr_settings.py
+++ b/hr/doctype/hr_settings/hr_settings.py
@@ -6,6 +6,24 @@
from __future__ import unicode_literals
import webnotes
+from webnotes.utils import cint
+
class DocType:
def __init__(self, d, dl):
- self.doc, self.doclist = d, dl
\ No newline at end of file
+ self.doc, self.doclist = d, dl
+
+ def validate(self):
+ self.original_stop_birthday_reminders = cint(webnotes.conn.get_value("HR Settings",
+ None, "stop_birthday_reminders"))
+
+ def on_update(self):
+ # reset birthday reminders
+ if cint(self.doc.stop_birthday_reminders) != self.original_stop_birthday_reminders:
+ webnotes.conn.sql("""delete from `tabEvent` where repeat_on='Every Year' and ref_type='Employee'""")
+
+ if not self.doc.stop_birthday_reminders:
+ for employee in webnotes.conn.sql_list("""select name from `tabEmployee` where status='Active' and
+ ifnull(date_of_birth, '')!=''"""):
+ webnotes.get_obj("Employee", employee).update_dob_event()
+
+ webnotes.msgprint(webnotes._("Updated Birthday Reminders"))
\ No newline at end of file
diff --git a/hr/doctype/hr_settings/hr_settings.txt b/hr/doctype/hr_settings/hr_settings.txt
index e3694d0..bf4b011 100644
--- a/hr/doctype/hr_settings/hr_settings.txt
+++ b/hr/doctype/hr_settings/hr_settings.txt
@@ -2,7 +2,7 @@
{
"creation": "2013-08-02 13:45:23",
"docstatus": 0,
- "modified": "2013-08-02 14:22:26",
+ "modified": "2013-10-02 15:44:38",
"modified_by": "Administrator",
"owner": "Administrator"
},
@@ -39,6 +39,12 @@
"name": "HR Settings"
},
{
+ "doctype": "DocField",
+ "fieldname": "employee_settings",
+ "fieldtype": "Section Break",
+ "label": "Employee Settings"
+ },
+ {
"description": "Employee record is created using selected field. ",
"doctype": "DocField",
"fieldname": "emp_created_by",
@@ -47,6 +53,19 @@
"options": "Naming Series\nEmployee Number"
},
{
+ "description": "Don't send Employee Birthday Reminders",
+ "doctype": "DocField",
+ "fieldname": "stop_birthday_reminders",
+ "fieldtype": "Check",
+ "label": "Stop Birthday Reminders"
+ },
+ {
+ "doctype": "DocField",
+ "fieldname": "payroll_settings",
+ "fieldtype": "Section Break",
+ "label": "Payroll Settings"
+ },
+ {
"description": "If checked, Total no. of Working Days will include holidays, and this will reduce the value of Salary Per Day",
"doctype": "DocField",
"fieldname": "include_holidays_in_total_working_days",
diff --git a/hr/doctype/job_applicant/get_job_applications.py b/hr/doctype/job_applicant/get_job_applications.py
index 2e01328..a929781 100644
--- a/hr/doctype/job_applicant/get_job_applications.py
+++ b/hr/doctype/job_applicant/get_job_applications.py
@@ -37,7 +37,7 @@
mail.save_attachments_in_doc(applicant.doc)
make(content=mail.content, sender=mail.from_email,
- doctype="Job Applicant", name=applicant.doc.name)
+ doctype="Job Applicant", name=applicant.doc.name, sent_or_received="Received")
def get_job_applications():
if cint(webnotes.conn.get_value('Jobs Email Settings', None, 'extract_emails')):
diff --git a/hr/doctype/job_applicant/job_applicant.py b/hr/doctype/job_applicant/job_applicant.py
index 9bf1b96..0ab4ba8 100644
--- a/hr/doctype/job_applicant/job_applicant.py
+++ b/hr/doctype/job_applicant/job_applicant.py
@@ -11,14 +11,9 @@
class DocType(TransactionBase):
def __init__(self, d, dl):
self.doc, self.doclist = d, dl
-
+
def get_sender(self, comm):
- return webnotes.conn.get_value('Jobs Email Settings',None,'email_id')
-
- def on_communication(self, comm):
- if webnotes.conn.get_value("Profile", extract_email_id(comm.sender), "user_type")=="System User":
- status = "Replied"
- else:
- status = "Open"
-
- webnotes.conn.set(self.doc, 'status', status)
\ No newline at end of file
+ return webnotes.conn.get_value('Jobs Email Settings',None,'email_id')
+
+ def validate(self):
+ self.set_status()
\ No newline at end of file
diff --git a/hr/doctype/leave_allocation/leave_allocation.py b/hr/doctype/leave_allocation/leave_allocation.py
index 1c856fa..a058e1d 100755
--- a/hr/doctype/leave_allocation/leave_allocation.py
+++ b/hr/doctype/leave_allocation/leave_allocation.py
@@ -5,7 +5,6 @@
import webnotes
from webnotes.utils import cint, flt
from webnotes import msgprint
-sql = webnotes.conn.sql
class DocType:
def __init__(self, doc, doclist):
@@ -37,7 +36,7 @@
def check_existing_leave_allocation(self):
"""check whether leave for same type is already allocated or not"""
- leave_allocation = sql("""select name from `tabLeave Allocation`
+ leave_allocation = webnotes.conn.sql("""select name from `tabLeave Allocation`
where employee=%s and leave_type=%s and fiscal_year=%s and docstatus=1""",
(self.doc.employee, self.doc.leave_type, self.doc.fiscal_year))
if leave_allocation:
@@ -64,14 +63,14 @@
return self.get_leaves_allocated(prev_fyear) - self.get_leaves_applied(prev_fyear)
def get_leaves_applied(self, fiscal_year):
- leaves_applied = sql("""select SUM(ifnull(total_leave_days, 0))
+ leaves_applied = webnotes.conn.sql("""select SUM(ifnull(total_leave_days, 0))
from `tabLeave Application` where employee=%s and leave_type=%s
and fiscal_year=%s and docstatus=1""",
(self.doc.employee, self.doc.leave_type, fiscal_year))
return leaves_applied and flt(leaves_applied[0][0]) or 0
def get_leaves_allocated(self, fiscal_year):
- leaves_allocated = sql("""select SUM(ifnull(total_leaves_allocated, 0))
+ leaves_allocated = webnotes.conn.sql("""select SUM(ifnull(total_leaves_allocated, 0))
from `tabLeave Allocation` where employee=%s and leave_type=%s
and fiscal_year=%s and docstatus=1 and name!=%s""",
(self.doc.employee, self.doc.leave_type, fiscal_year, self.doc.name))
@@ -79,7 +78,7 @@
def allow_carry_forward(self):
"""check whether carry forward is allowed or not for this leave type"""
- cf = sql("""select is_carry_forward from `tabLeave Type` where name = %s""",
+ cf = webnotes.conn.sql("""select is_carry_forward from `tabLeave Type` where name = %s""",
self.doc.leave_type)
cf = cf and cint(cf[0][0]) or 0
if not cf:
@@ -110,7 +109,7 @@
webnotes.conn.set(self.doc,'total_leaves_allocated',flt(leave_det['total_leaves_allocated']))
def check_for_leave_application(self):
- exists = sql("""select name from `tabLeave Application`
+ exists = webnotes.conn.sql("""select name from `tabLeave Application`
where employee=%s and leave_type=%s and fiscal_year=%s and docstatus=1""",
(self.doc.employee, self.doc.leave_type, self.doc.fiscal_year))
if exists:
diff --git a/hr/doctype/leave_control_panel/leave_control_panel.py b/hr/doctype/leave_control_panel/leave_control_panel.py
index 30b52ba..294701c 100644
--- a/hr/doctype/leave_control_panel/leave_control_panel.py
+++ b/hr/doctype/leave_control_panel/leave_control_panel.py
@@ -9,7 +9,6 @@
from webnotes.model.code import get_obj
from webnotes import msgprint
-sql = webnotes.conn.sql
@@ -34,7 +33,7 @@
emp_query = "select name from `tabEmployee` "
if flag == 1:
emp_query += condition
- e = sql(emp_query)
+ e = webnotes.conn.sql(emp_query)
return e
# ----------------
diff --git a/hr/doctype/salary_manager/salary_manager.py b/hr/doctype/salary_manager/salary_manager.py
index 0eadca1..48dcab1 100644
--- a/hr/doctype/salary_manager/salary_manager.py
+++ b/hr/doctype/salary_manager/salary_manager.py
@@ -11,7 +11,6 @@
from webnotes.model.code import get_obj
from webnotes import msgprint
-sql = webnotes.conn.sql
@@ -30,7 +29,7 @@
cond = self.get_filter_condition()
cond += self.get_joining_releiving_condition()
- emp_list = sql("""
+ emp_list = webnotes.conn.sql("""
select t1.name
from `tabEmployee` t1, `tabSalary Structure` t2
where t1.docstatus!=2 and t2.docstatus != 2
@@ -68,7 +67,7 @@
def get_month_details(self, year, month):
- ysd = sql("select year_start_date from `tabFiscal Year` where name ='%s'"%year)[0][0]
+ ysd = webnotes.conn.sql("select year_start_date from `tabFiscal Year` where name ='%s'"%year)[0][0]
if ysd:
from dateutil.relativedelta import relativedelta
import calendar, datetime
@@ -96,7 +95,7 @@
emp_list = self.get_emp_list()
ss_list = []
for emp in emp_list:
- if not sql("""select name from `tabSalary Slip`
+ if not webnotes.conn.sql("""select name from `tabSalary Slip`
where docstatus!= 2 and employee = %s and month = %s and fiscal_year = %s and company = %s
""", (emp[0], self.doc.month, self.doc.fiscal_year, self.doc.company)):
ss = webnotes.bean({
@@ -127,7 +126,7 @@
which are not submitted
"""
cond = self.get_filter_condition()
- ss_list = sql("""
+ ss_list = webnotes.conn.sql("""
select t1.name from `tabSalary Slip` t1
where t1.docstatus = 0 and month = '%s' and fiscal_year = '%s' %s
""" % (self.doc.month, self.doc.fiscal_year, cond))
@@ -189,7 +188,7 @@
Get total salary amount from submitted salary slip based on selected criteria
"""
cond = self.get_filter_condition()
- tot = sql("""
+ tot = webnotes.conn.sql("""
select sum(rounded_total) from `tabSalary Slip` t1
where t1.docstatus = 1 and month = '%s' and fiscal_year = '%s' %s
""" % (self.doc.month, self.doc.fiscal_year, cond))
@@ -202,7 +201,7 @@
get default bank account,default salary acount from company
"""
amt = self.get_total_salary()
- com = sql("select default_bank_account from `tabCompany` where name = '%s'" % self.doc.company)
+ com = webnotes.conn.sql("select default_bank_account from `tabCompany` where name = '%s'" % self.doc.company)
if not com[0][0] or not com[0][1]:
msgprint("You can set Default Bank Account in Company master.")
diff --git a/hr/doctype/salary_manager/test_salary_manager.py b/hr/doctype/salary_manager/test_salary_manager.py
index 04000f0..13815db 100644
--- a/hr/doctype/salary_manager/test_salary_manager.py
+++ b/hr/doctype/salary_manager/test_salary_manager.py
@@ -9,7 +9,7 @@
# from webnotes.model.doc import Document
# from webnotes.model.code import get_obj
-# sql = webnotes.conn.sql
+# webnotes.conn.sql = webnotes.conn.sql
#
# class TestSalaryManager(unittest.TestCase):
# def setUp(self):
@@ -20,15 +20,15 @@
# ss1[0].employee = emp1.name
# for s in ss1: s.save(1)
# for s in ss1[1:]:
-# sql("update `tabSalary Structure Earning` set parent = '%s' where name = '%s'" % (ss1[0].name, s.name))
-# sql("update `tabSalary Structure Deduction` set parent = '%s' where name = '%s'" % (ss1[0].name, s.name))
+# webnotes.conn.sql("update `tabSalary Structure Earning` set parent = '%s' where name = '%s'" % (ss1[0].name, s.name))
+# webnotes.conn.sql("update `tabSalary Structure Deduction` set parent = '%s' where name = '%s'" % (ss1[0].name, s.name))
#
#
# ss2[0].employee = emp2.name
# for s in ss2: s.save(1)
# for s in ss2[1:]:
-# sql("update `tabSalary Structure Earning` set parent = '%s' where name = '%s'" % (ss2[0].name, s.name))
-# sql("update `tabSalary Structure Deduction` set parent = '%s' where name = '%s'" % (ss2[0].name, s.name))
+# webnotes.conn.sql("update `tabSalary Structure Earning` set parent = '%s' where name = '%s'" % (ss2[0].name, s.name))
+# webnotes.conn.sql("update `tabSalary Structure Deduction` set parent = '%s' where name = '%s'" % (ss2[0].name, s.name))
#
# sman.save()
# self.sm = get_obj('Salary Manager')
@@ -36,7 +36,7 @@
# self.sm.create_sal_slip()
#
# def test_creation(self):
-# ssid = sql("""
+# ssid = webnotes.conn.sql("""
# select name, department
# from `tabSalary Slip`
# where month = '08' and fiscal_year='2011-2012'""")
@@ -46,7 +46,7 @@
#
#
# def test_lwp_calc(self):
-# ss = sql("""
+# ss = webnotes.conn.sql("""
# select payment_days
# from `tabSalary Slip`
# where month = '08' and fiscal_year='2011-2012' and employee = '%s'
diff --git a/hr/doctype/salary_slip/salary_slip.py b/hr/doctype/salary_slip/salary_slip.py
index 36d7ceb..dab026e 100644
--- a/hr/doctype/salary_slip/salary_slip.py
+++ b/hr/doctype/salary_slip/salary_slip.py
@@ -11,7 +11,6 @@
from webnotes import msgprint, _
from setup.utils import get_company_currency
-sql = webnotes.conn.sql
from utilities.transaction_base import TransactionBase
@@ -32,7 +31,7 @@
def check_sal_struct(self):
- struct = sql("select name from `tabSalary Structure` where employee ='%s' and is_active = 'Yes' "%self.doc.employee)
+ struct = webnotes.conn.sql("select name from `tabSalary Structure` where employee ='%s' and is_active = 'Yes' "%self.doc.employee)
if not struct:
msgprint("Please create Salary Structure for employee '%s'"%self.doc.employee)
self.doc.employee = ''
@@ -100,13 +99,13 @@
return payment_days
def get_holidays_for_employee(self, m):
- holidays = sql("""select t1.holiday_date
+ holidays = webnotes.conn.sql("""select t1.holiday_date
from `tabHoliday` t1, tabEmployee t2
where t1.parent = t2.holiday_list and t2.name = %s
and t1.holiday_date between %s and %s""",
(self.doc.employee, m['month_start_date'], m['month_end_date']))
if not holidays:
- holidays = sql("""select t1.holiday_date
+ holidays = webnotes.conn.sql("""select t1.holiday_date
from `tabHoliday` t1, `tabHoliday List` t2
where t1.parent = t2.name and ifnull(t2.is_default, 0) = 1
and t2.fiscal_year = %s
@@ -120,7 +119,7 @@
for d in range(m['month_days']):
dt = add_days(cstr(m['month_start_date']), d)
if dt not in holidays:
- leave = sql("""
+ leave = webnotes.conn.sql("""
select t1.name, t1.half_day
from `tabLeave Application` t1, `tabLeave Type` t2
where t2.name = t1.leave_type
@@ -134,7 +133,7 @@
return lwp
def check_existing(self):
- ret_exist = sql("""select name from `tabSalary Slip`
+ ret_exist = webnotes.conn.sql("""select name from `tabSalary Slip`
where month = %s and fiscal_year = %s and docstatus != 2
and employee = %s and name != %s""",
(self.doc.month, self.doc.fiscal_year, self.doc.employee, self.doc.name))
@@ -201,9 +200,9 @@
receiver = webnotes.conn.get_value("Employee", self.doc.employee, "company_email")
if receiver:
subj = 'Salary Slip - ' + cstr(self.doc.month) +'/'+cstr(self.doc.fiscal_year)
- earn_ret=sql("""select e_type, e_modified_amount from `tabSalary Slip Earning`
+ earn_ret=webnotes.conn.sql("""select e_type, e_modified_amount from `tabSalary Slip Earning`
where parent = %s""", self.doc.name)
- ded_ret=sql("""select d_type, d_modified_amount from `tabSalary Slip Deduction`
+ ded_ret=webnotes.conn.sql("""select d_type, d_modified_amount from `tabSalary Slip Deduction`
where parent = %s""", self.doc.name)
earn_table = ''
diff --git a/hr/doctype/salary_structure/salary_structure.py b/hr/doctype/salary_structure/salary_structure.py
index 50b0160..bfa7850 100644
--- a/hr/doctype/salary_structure/salary_structure.py
+++ b/hr/doctype/salary_structure/salary_structure.py
@@ -8,7 +8,6 @@
from webnotes.model.doc import addchild, make_autoname
from webnotes import msgprint, _
-sql = webnotes.conn.sql
class DocType:
def __init__(self,doc,doclist=[]):
@@ -20,7 +19,7 @@
def get_employee_details(self):
ret = {}
- det = sql("""select employee_name, branch, designation, department, grade
+ det = webnotes.conn.sql("""select employee_name, branch, designation, department, grade
from `tabEmployee` where name = %s""", self.doc.employee)
if det:
ret = {
@@ -34,7 +33,7 @@
return ret
def get_ss_values(self,employee):
- basic_info = sql("""select bank_name, bank_ac_no, esic_card_no, pf_number
+ basic_info = webnotes.conn.sql("""select bank_name, bank_ac_no, esic_card_no, pf_number
from `tabEmployee` where name =%s""", employee)
ret = {'bank_name': basic_info and basic_info[0][0] or '',
'bank_ac_no': basic_info and basic_info[0][1] or '',
@@ -43,7 +42,7 @@
return ret
def make_table(self, doct_name, tab_fname, tab_name):
- list1 = sql("select name from `tab%s` where docstatus != 2" % doct_name)
+ list1 = webnotes.conn.sql("select name from `tab%s` where docstatus != 2" % doct_name)
for li in list1:
child = addchild(self.doc, tab_fname, tab_name, self.doclist)
if(tab_fname == 'earning_details'):
@@ -58,7 +57,7 @@
self.make_table('Deduction Type','deduction_details', 'Salary Structure Deduction')
def check_existing(self):
- ret = sql("""select name from `tabSalary Structure` where is_active = 'Yes'
+ ret = webnotes.conn.sql("""select name from `tabSalary Structure` where is_active = 'Yes'
and employee = %s and name!=%s""", (self.doc.employee,self.doc.name))
if ret and self.doc.is_active=='Yes':
msgprint(_("""Another Salary Structure '%s' is active for employee '%s'.
diff --git a/hr/doctype/upload_attendance/upload_attendance.py b/hr/doctype/upload_attendance/upload_attendance.py
index c1344b9..56c8eed 100644
--- a/hr/doctype/upload_attendance/upload_attendance.py
+++ b/hr/doctype/upload_attendance/upload_attendance.py
@@ -9,7 +9,8 @@
from webnotes import msgprint, _
from webnotes.utils.datautils import UnicodeWriter
-doclist = None
+# doclist = None
+doclist = webnotes.local('uploadattendance_doclist')
class DocType():
def __init__(self, doc, doclist=[]):
@@ -21,9 +22,8 @@
if not webnotes.has_permission("Attendance", "create"):
raise webnotes.PermissionError
- args = webnotes.form_dict
- global doclist
- doclist = webnotes.model.doctype.get("Attendance")
+ args = webnotes.local.form_dict
+ webnotes.local.uploadattendance_doclist = webnotes.model.doctype.get("Attendance")
w = UnicodeWriter()
w = add_header(w)
@@ -144,4 +144,4 @@
webnotes.conn.rollback()
else:
webnotes.conn.commit()
- return {"messages": ret, "error": error}
\ No newline at end of file
+ return {"messages": ret, "error": error}
diff --git a/manufacturing/doctype/bom/bom.py b/manufacturing/doctype/bom/bom.py
index 9a56612..5954475 100644
--- a/manufacturing/doctype/bom/bom.py
+++ b/manufacturing/doctype/bom/bom.py
@@ -9,7 +9,6 @@
from webnotes.model.code import get_obj
from webnotes import msgprint, _
-sql = webnotes.conn.sql
class DocType:
@@ -18,7 +17,7 @@
self.doclist = doclist
def autoname(self):
- last_name = sql("""select max(name) from `tabBOM`
+ last_name = webnotes.conn.sql("""select max(name) from `tabBOM`
where name like "BOM/%s/%%" """ % cstr(self.doc.item).replace('"', '\\"'))
if last_name:
idx = cint(cstr(last_name[0][0]).split('/')[-1].split('-')[0]) + 1
@@ -144,7 +143,7 @@
webnotes.bean(self.doclist).update_after_submit()
def get_bom_unitcost(self, bom_no):
- bom = sql("""select name, total_cost/quantity as unit_cost from `tabBOM`
+ bom = webnotes.conn.sql("""select name, total_cost/quantity as unit_cost from `tabBOM`
where is_active = 1 and name = %s""", bom_no, as_dict=1)
return bom and bom[0]['unit_cost'] or 0
@@ -156,7 +155,7 @@
from stock.utils import get_incoming_rate
dt = self.doc.costing_date or nowdate()
time = self.doc.costing_date == nowdate() and now().split()[1] or '23:59'
- warehouse = sql("select warehouse from `tabBin` where item_code = %s", args['item_code'])
+ warehouse = webnotes.conn.sql("select warehouse from `tabBin` where item_code = %s", args['item_code'])
rate = []
for wh in warehouse:
r = get_incoming_rate({
@@ -184,7 +183,7 @@
if not self.doc.is_active:
webnotes.conn.set(self.doc, "is_default", 0)
- sql("update `tabItem` set default_bom = null where name = %s and default_bom = %s",
+ webnotes.conn.sql("update `tabItem` set default_bom = null where name = %s and default_bom = %s",
(self.doc.item, self.doc.name))
def clear_operations(self):
@@ -250,7 +249,7 @@
def validate_bom_no(self, item, bom_no, idx):
"""Validate BOM No of sub-contracted items"""
- bom = sql("""select name from `tabBOM` where name = %s and item = %s
+ bom = webnotes.conn.sql("""select name from `tabBOM` where name = %s and item = %s
and is_active=1 and docstatus=1""",
(bom_no, item), as_dict =1)
if not bom:
@@ -272,7 +271,7 @@
for d in check_list:
bom_list, count = [self.doc.name], 0
while (len(bom_list) > count ):
- boms = sql(" select %s from `tabBOM Item` where %s = '%s' " %
+ boms = webnotes.conn.sql(" select %s from `tabBOM Item` where %s = '%s' " %
(d[0], d[1], cstr(bom_list[count])))
count = count + 1
for b in boms:
@@ -364,7 +363,7 @@
def get_child_exploded_items(self, bom_no, qty):
""" Add all items from Flat BOM of child BOM"""
- child_fb_items = sql("""select item_code, description, stock_uom, qty, rate,
+ child_fb_items = webnotes.conn.sql("""select item_code, description, stock_uom, qty, rate,
qty_consumed_per_unit from `tabBOM Explosion Item`
where parent = %s and docstatus = 1""", bom_no, as_dict = 1)
@@ -390,12 +389,12 @@
ch.save(1)
def get_parent_bom_list(self, bom_no):
- p_bom = sql("select parent from `tabBOM Item` where bom_no = '%s'" % bom_no)
+ p_bom = webnotes.conn.sql("select parent from `tabBOM Item` where bom_no = '%s'" % bom_no)
return p_bom and [i[0] for i in p_bom] or []
def validate_bom_links(self):
if not self.doc.is_active:
- act_pbom = sql("""select distinct bom_item.parent from `tabBOM Item` bom_item
+ act_pbom = webnotes.conn.sql("""select distinct bom_item.parent from `tabBOM Item` bom_item
where bom_item.bom_no = %s and bom_item.docstatus = 1
and exists (select * from `tabBOM` where name = bom_item.parent
and docstatus = 1 and is_active = 1)""", self.doc.name)
@@ -403,4 +402,53 @@
if act_pbom and act_pbom[0][0]:
action = self.doc.docstatus < 2 and _("deactivate") or _("cancel")
msgprint(_("Cannot ") + action + _(": It is linked to other active BOM(s)"),
- raise_exception=1)
\ No newline at end of file
+ raise_exception=1)
+
+def get_bom_items_as_dict(bom, qty=1, fetch_exploded=1):
+ item_dict = {}
+
+ query = """select
+ bom_item.item_code,
+ ifnull(sum(bom_item.qty_consumed_per_unit),0) * %(qty)s as qty,
+ item.description,
+ item.stock_uom,
+ item.default_warehouse
+ from
+ `tab%(table)s` bom_item, `tabItem` item
+ where
+ bom_item.docstatus < 2
+ and bom_item.parent = "%(bom)s"
+ and item.name = bom_item.item_code
+ %(conditions)s
+ group by item_code, stock_uom"""
+
+ if fetch_exploded:
+ items = webnotes.conn.sql(query % {
+ "qty": qty,
+ "table": "BOM Explosion Item",
+ "bom": bom,
+ "conditions": """and ifnull(item.is_pro_applicable, 'No') = 'No'
+ and ifnull(item.is_sub_contracted_item, 'No') = 'No' """
+ }, as_dict=True)
+ else:
+ items = webnotes.conn.sql(query % {
+ "qty": qty,
+ "table": "BOM Item",
+ "bom": bom,
+ "conditions": ""
+ }, as_dict=True)
+
+ # make unique
+ for item in items:
+ if item_dict.has_key(item.item_code):
+ item_dict[item.item_code]["qty"] += flt(item.qty)
+ else:
+ item_dict[item.item_code] = item
+
+ return item_dict
+
+@webnotes.whitelist()
+def get_bom_items(bom, qty=1, fetch_exploded=1):
+ items = get_bom_items_as_dict(bom, qty, fetch_exploded).values()
+ items.sort(lambda a, b: a.item_code > b.item_code and 1 or -1)
+ return items
\ No newline at end of file
diff --git a/manufacturing/doctype/bom/test_bom.py b/manufacturing/doctype/bom/test_bom.py
index d0b394a..da98faf 100644
--- a/manufacturing/doctype/bom/test_bom.py
+++ b/manufacturing/doctype/bom/test_bom.py
@@ -10,6 +10,35 @@
[
{
"doctype": "BOM",
+ "item": "_Test Item Home Desktop 100",
+ "quantity": 1.0,
+ "is_active": 1,
+ "is_default": 1,
+ "docstatus": 1
+ },
+ {
+ "doctype": "BOM Item",
+ "item_code": "_Test Serialized Item With Series",
+ "parentfield": "bom_materials",
+ "qty": 1.0,
+ "rate": 5000.0,
+ "amount": 5000.0,
+ "stock_uom": "_Test UOM"
+ },
+ {
+ "doctype": "BOM Item",
+ "item_code": "_Test Item 2",
+ "parentfield": "bom_materials",
+ "qty": 2.0,
+ "rate": 1000.0,
+ "amount": 2000.0,
+ "stock_uom": "_Test UOM"
+ }
+ ],
+
+ [
+ {
+ "doctype": "BOM",
"item": "_Test FG Item",
"quantity": 1.0,
"is_active": 1,
@@ -29,10 +58,33 @@
"doctype": "BOM Item",
"item_code": "_Test Item Home Desktop 100",
"parentfield": "bom_materials",
+ "bom_no": "BOM/_Test Item Home Desktop 100/001",
"qty": 2.0,
"rate": 1000.0,
"amount": 2000.0,
"stock_uom": "_Test UOM"
}
- ]
-]
\ No newline at end of file
+ ],
+]
+
+class TestBOM(unittest.TestCase):
+ def test_get_items(self):
+ from manufacturing.doctype.bom.bom import get_bom_items_as_dict
+ items_dict = get_bom_items_as_dict(bom="BOM/_Test FG Item/001", qty=1, fetch_exploded=0)
+ self.assertTrue(test_records[1][1]["item_code"] in items_dict)
+ self.assertTrue(test_records[1][2]["item_code"] in items_dict)
+ self.assertEquals(len(items_dict.values()), 2)
+
+ def test_get_items_exploded(self):
+ from manufacturing.doctype.bom.bom import get_bom_items_as_dict
+ items_dict = get_bom_items_as_dict(bom="BOM/_Test FG Item/001", qty=1, fetch_exploded=1)
+ self.assertTrue(test_records[1][1]["item_code"] in items_dict)
+ self.assertFalse(test_records[1][2]["item_code"] in items_dict)
+ self.assertTrue(test_records[0][1]["item_code"] in items_dict)
+ self.assertTrue(test_records[0][2]["item_code"] in items_dict)
+ self.assertEquals(len(items_dict.values()), 3)
+
+ def test_get_items_list(self):
+ from manufacturing.doctype.bom.bom import get_bom_items
+ self.assertEquals(len(get_bom_items(bom="BOM/_Test FG Item/001", qty=1, fetch_exploded=1)), 3)
+
diff --git a/manufacturing/doctype/production_order/production_order.py b/manufacturing/doctype/production_order/production_order.py
index b29b0f1..36cbc64 100644
--- a/manufacturing/doctype/production_order/production_order.py
+++ b/manufacturing/doctype/production_order/production_order.py
@@ -8,7 +8,6 @@
from webnotes.model.code import get_obj
from webnotes import msgprint, _
-sql = webnotes.conn.sql
class OverProductionError(webnotes.ValidationError): pass
@@ -34,7 +33,7 @@
def validate_bom_no(self):
if self.doc.bom_no:
- bom = sql("""select name from `tabBOM` where name=%s and docstatus=1
+ bom = webnotes.conn.sql("""select name from `tabBOM` where name=%s and docstatus=1
and is_active=1 and item=%s"""
, (self.doc.bom_no, self.doc.production_item), as_dict =1)
if not bom:
@@ -112,7 +111,7 @@
def on_cancel(self):
# Check whether any stock entry exists against this Production Order
- stock_entry = sql("""select name from `tabStock Entry`
+ stock_entry = webnotes.conn.sql("""select name from `tabStock Entry`
where production_order = %s and docstatus = 1""", self.doc.name)
if stock_entry:
msgprint("""Submitted Stock Entry %s exists against this production order.
@@ -168,4 +167,4 @@
stock_entry.doc.to_warehouse = production_order.doc.fg_warehouse
stock_entry.run_method("get_items")
- return [d.fields for d in stock_entry.doclist]
\ No newline at end of file
+ return [d.fields for d in stock_entry.doclist]
diff --git a/manufacturing/doctype/production_order/production_order.txt b/manufacturing/doctype/production_order/production_order.txt
index 782c99f..81821f6 100644
--- a/manufacturing/doctype/production_order/production_order.txt
+++ b/manufacturing/doctype/production_order/production_order.txt
@@ -2,11 +2,12 @@
{
"creation": "2013-01-10 16:34:16",
"docstatus": 0,
- "modified": "2013-08-08 14:22:12",
+ "modified": "2013-10-02 14:25:03",
"modified_by": "Administrator",
"owner": "Administrator"
},
{
+ "allow_import": 1,
"autoname": "naming_series:",
"doctype": "DocType",
"icon": "icon-cogs",
diff --git a/manufacturing/doctype/production_planning_tool/production_planning_tool.py b/manufacturing/doctype/production_planning_tool/production_planning_tool.py
index 766f2ac..6f15d4c 100644
--- a/manufacturing/doctype/production_planning_tool/production_planning_tool.py
+++ b/manufacturing/doctype/production_planning_tool/production_planning_tool.py
@@ -9,7 +9,6 @@
from webnotes.model.code import get_obj
from webnotes import msgprint, _
-sql = webnotes.conn.sql
class DocType:
def __init__(self, doc, doclist=[]):
@@ -19,7 +18,7 @@
def get_so_details(self, so):
"""Pull other details from so"""
- so = sql("""select transaction_date, customer, grand_total
+ so = webnotes.conn.sql("""select transaction_date, customer, grand_total
from `tabSales Order` where name = %s""", so, as_dict = 1)
ret = {
'sales_order_date': so and so[0]['transaction_date'] or '',
@@ -31,7 +30,7 @@
def get_item_details(self, item_code):
""" Pull other item details from item master"""
- item = sql("""select description, stock_uom, default_bom
+ item = webnotes.conn.sql("""select description, stock_uom, default_bom
from `tabItem` where name = %s""", item_code, as_dict =1)
ret = {
'description' : item and item[0]['description'],
@@ -63,7 +62,7 @@
if self.doc.fg_item:
item_filter += ' and item.name = "' + self.doc.fg_item + '"'
- open_so = sql("""
+ open_so = webnotes.conn.sql("""
select distinct so.name, so.transaction_date, so.customer, so.grand_total
from `tabSales Order` so, `tabSales Order Item` so_item
where so_item.parent = so.name
@@ -108,7 +107,7 @@
msgprint("Please enter sales order in the above table")
return []
- items = sql("""select distinct parent, item_code, reserved_warehouse,
+ items = webnotes.conn.sql("""select distinct parent, item_code, reserved_warehouse,
(qty - ifnull(delivered_qty, 0)) as pending_qty
from `tabSales Order Item` so_item
where parent in (%s) and docstatus = 1 and ifnull(qty, 0) > ifnull(delivered_qty, 0)
@@ -117,7 +116,7 @@
or ifnull(item.is_sub_contracted_item, 'No') = 'Yes'))""" % \
(", ".join(["%s"] * len(so_list))), tuple(so_list), as_dict=1)
- dnpi_items = sql("""select distinct dnpi.parent, dnpi.item_code, dnpi.warehouse as reserved_warhouse,
+ dnpi_items = webnotes.conn.sql("""select distinct dnpi.parent, dnpi.item_code, dnpi.warehouse as reserved_warhouse,
(((so_item.qty - ifnull(so_item.delivered_qty, 0)) * dnpi.qty) / so_item.qty)
as pending_qty
from `tabSales Order Item` so_item, `tabDelivery Note Packing Item` dnpi
@@ -136,7 +135,7 @@
self.clear_item_table()
for p in items:
- item_details = sql("""select description, stock_uom, default_bom
+ item_details = webnotes.conn.sql("""select description, stock_uom, default_bom
from tabItem where name=%s""", p['item_code'])
pi = addchild(self.doc, 'pp_details', 'Production Plan Item', self.doclist)
pi.sales_order = p['parent']
@@ -162,7 +161,7 @@
msgprint("Please enter bom no for item: %s at row no: %s" %
(d.item_code, d.idx), raise_exception=1)
else:
- bom = sql("""select name from `tabBOM` where name = %s and item = %s
+ bom = webnotes.conn.sql("""select name from `tabBOM` where name = %s and item = %s
and docstatus = 1 and is_active = 1""",
(d.bom_no, d.item_code), as_dict = 1)
if not bom:
@@ -216,14 +215,14 @@
pro = webnotes.new_bean("Production Order")
pro.doc.fields.update(items[key])
- webnotes.mute_messages = True
+ webnotes.flags.mute_messages = True
try:
pro.insert()
pro_list.append(pro.doc.name)
except OverProductionError, e:
pass
- webnotes.mute_messages = False
+ webnotes.flags.mute_messages = False
return pro_list
@@ -243,7 +242,7 @@
for bom in bom_dict:
if self.doc.use_multi_level_bom:
# get all raw materials with sub assembly childs
- fl_bom_items = sql("""select fb.item_code,
+ fl_bom_items = webnotes.conn.sql("""select fb.item_code,
ifnull(sum(fb.qty_consumed_per_unit), 0)*%s as qty,
fb.description, fb.stock_uom, it.min_order_qty
from `tabBOM Explosion Item` fb,`tabItem` it
@@ -254,7 +253,7 @@
else:
# Get all raw materials considering SA items as raw materials,
# so no childs of SA items
- fl_bom_items = sql("""select bom_item.item_code,
+ fl_bom_items = webnotes.conn.sql("""select bom_item.item_code,
ifnull(sum(bom_item.qty_consumed_per_unit), 0) * %s,
bom_item.description, bom_item.stock_uom, item.min_order_qty
from `tabBOM Item` bom_item, tabItem item
@@ -274,7 +273,7 @@
'Quantity Requested for Purchase', 'Ordered Qty', 'Actual Qty']]
for d in self.item_dict:
item_list.append([d, self.item_dict[d][1], self.item_dict[d][2], self.item_dict[d][0]])
- item_qty= sql("""select warehouse, indented_qty, ordered_qty, actual_qty
+ item_qty= webnotes.conn.sql("""select warehouse, indented_qty, ordered_qty, actual_qty
from `tabBin` where item_code = %s""", d)
i_qty, o_qty, a_qty = 0, 0, 0
for w in item_qty:
diff --git a/manufacturing/doctype/workstation/workstation.py b/manufacturing/doctype/workstation/workstation.py
index 35e2c1f..cc12934 100644
--- a/manufacturing/doctype/workstation/workstation.py
+++ b/manufacturing/doctype/workstation/workstation.py
@@ -8,7 +8,6 @@
from webnotes.model import db_exists
from webnotes.model.bean import copy_doclist
-sql = webnotes.conn.sql
@@ -18,9 +17,9 @@
self.doclist = doclist
def update_bom_operation(self):
- bom_list = sql(" select DISTINCT parent from `tabBOM Operation` where workstation = '%s'" % self.doc.name)
+ bom_list = webnotes.conn.sql(" select DISTINCT parent from `tabBOM Operation` where workstation = '%s'" % self.doc.name)
for bom_no in bom_list:
- sql("update `tabBOM Operation` set hour_rate = '%s' where parent = '%s' and workstation = '%s'"%( self.doc.hour_rate, bom_no[0], self.doc.name))
+ webnotes.conn.sql("update `tabBOM Operation` set hour_rate = '%s' where parent = '%s' and workstation = '%s'"%( self.doc.hour_rate, bom_no[0], self.doc.name))
def on_update(self):
webnotes.conn.set(self.doc, 'overhead', flt(self.doc.hour_rate_electricity) + flt(self.doc.hour_rate_consumable) + flt(self.doc.hour_rate_rent))
diff --git a/patches/april_2013/p05_update_file_data.py b/patches/april_2013/p05_update_file_data.py
index e03abc6..47d6de9 100644
--- a/patches/april_2013/p05_update_file_data.py
+++ b/patches/april_2013/p05_update_file_data.py
@@ -52,7 +52,7 @@
exists = True
if not (filename.startswith("http://") or filename.startswith("https://")):
- if not os.path.exists(webnotes.utils.get_path("public", "files", filename)):
+ if not os.path.exists(webnotes.utils.get_site_path(webnotes.conf.files_path, filename)):
exists = False
if exists:
diff --git a/patches/april_2013/p06_update_file_size.py b/patches/april_2013/p06_update_file_size.py
index 6879625..973cea9 100644
--- a/patches/april_2013/p06_update_file_size.py
+++ b/patches/april_2013/p06_update_file_size.py
@@ -4,7 +4,7 @@
import webnotes, os, webnotes.utils
def execute():
- files_path = webnotes.utils.get_path("public", "files")
+ files_path = webnotes.utils.get_site_path(webnotes.conf.files_path)
webnotes.conn.auto_commit_on_many_writes = 1
for f in webnotes.conn.sql("""select name, file_name from
@@ -14,4 +14,4 @@
if os.path.exists(filepath):
webnotes.conn.set_value("File Data", f.name, "file_size", os.stat(filepath).st_size)
- webnotes.conn.auto_commit_on_many_writes = 0
\ No newline at end of file
+ webnotes.conn.auto_commit_on_many_writes = 0
diff --git a/patches/august_2013/p06_fix_sle_against_stock_entry.py b/patches/august_2013/p06_fix_sle_against_stock_entry.py
index 02588be..2e6c383 100644
--- a/patches/august_2013/p06_fix_sle_against_stock_entry.py
+++ b/patches/august_2013/p06_fix_sle_against_stock_entry.py
@@ -1,10 +1,9 @@
import webnotes
-cancelled = []
-uncancelled = []
-
def execute():
- global cancelled, uncancelled
+ cancelled = []
+ uncancelled = []
+
stock_entries = webnotes.conn.sql("""select * from `tabStock Entry`
where docstatus >= 1 and date(modified) >= "2013-08-16"
and ifnull(production_order, '') != '' and ifnull(bom_no, '') != ''
@@ -17,14 +16,12 @@
where voucher_type='Stock Entry' and voucher_no=%s
and is_cancelled='No'""", entry.name, as_dict=True)
if res:
- make_stock_entry_detail(entry, res)
+ make_stock_entry_detail(entry, res, cancelled, uncancelled)
if cancelled or uncancelled:
- send_email()
+ send_email(cancelled, uncancelled)
-def make_stock_entry_detail(entry, res):
- global cancelled, uncancelled
-
+def make_stock_entry_detail(entry, res, cancelled, uncancelled):
fg_item = webnotes.conn.get_value("Production Order", entry.production_order,
"production_item")
voucher_detail_entries_map = {}
@@ -87,9 +84,8 @@
uncancelled.append(se.doc.name)
-def send_email():
+def send_email(cancelled, uncancelled):
from webnotes.utils.email_lib import sendmail_to_system_managers
- global cancelled, uncancelled
uncancelled = "we have undone the cancellation of the following Stock Entries through a patch:\n" + \
"\n".join(uncancelled) if uncancelled else ""
cancelled = "and cancelled the following Stock Entries:\n" + "\n".join(cancelled) \
diff --git a/patches/june_2013/p08_shopping_cart_settings.py b/patches/june_2013/p08_shopping_cart_settings.py
index 479a696..677b62a 100644
--- a/patches/june_2013/p08_shopping_cart_settings.py
+++ b/patches/june_2013/p08_shopping_cart_settings.py
@@ -7,7 +7,7 @@
webnotes.reload_doc("selling", "doctype", "shopping_cart_settings")
# create two default territories, one for home country and one named Rest of the World
- from setup.doctype.setup_control.setup_control import create_territories
+ from setup.page.setup_wizard.setup_wizard import create_territories
create_territories()
webnotes.conn.set_value("Shopping Cart Settings", None, "default_territory", "Rest of the World")
diff --git a/patches/october_2013/p01_update_delivery_note_prevdocs.py b/patches/october_2013/p01_update_delivery_note_prevdocs.py
new file mode 100644
index 0000000..75ac53f
--- /dev/null
+++ b/patches/october_2013/p01_update_delivery_note_prevdocs.py
@@ -0,0 +1,13 @@
+# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+import webnotes
+
+def execute():
+ webnotes.reload_doc("stock", "doctype", "delivery_note_item")
+ webnotes.conn.sql("""update `tabDelivery Note Item` set against_sales_order=prevdoc_docname
+ where prevdoc_doctype='Sales Order' """)
+
+ webnotes.conn.sql("""update `tabDelivery Note Item` set against_sales_invoice=prevdoc_docname
+ where prevdoc_doctype='Sales Invoice' """)
\ No newline at end of file
diff --git a/patches/october_2013/p02_set_communication_status.py b/patches/october_2013/p02_set_communication_status.py
new file mode 100644
index 0000000..d67d08d
--- /dev/null
+++ b/patches/october_2013/p02_set_communication_status.py
@@ -0,0 +1,11 @@
+# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+import webnotes
+
+def execute():
+ webnotes.reload_doc("core", "doctype", "communication")
+
+ webnotes.conn.sql("""update tabCommunication
+ set sent_or_received= if(ifnull(recipients, '')='', "Received", "Sent")""")
\ No newline at end of file
diff --git a/patches/october_2013/p03_crm_update_status.py b/patches/october_2013/p03_crm_update_status.py
new file mode 100644
index 0000000..07a70c6
--- /dev/null
+++ b/patches/october_2013/p03_crm_update_status.py
@@ -0,0 +1,47 @@
+# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+import webnotes
+
+# reason field
+
+def execute():
+ change_map = {
+ "Lead": [
+ ["Lead Lost", "Lead"],
+ ["Not interested", "Do Not Contact"],
+ ["Opportunity Made", "Opportunity"],
+ ["Contacted", "Replied"],
+ ["Attempted to Contact", "Replied"],
+ ["Contact in Future", "Interested"],
+ ],
+ "Opportunity": [
+ ["Quotation Sent", "Quotation"],
+ ["Order Confirmed", "Quotation"],
+ ["Opportunity Lost", "Lost"],
+ ],
+ "Quotation": [
+ ["Order Confirmed", "Ordered"],
+ ["Order Lost", "Lost"]
+ ],
+ "Support Ticket": [
+ ["Waiting for Customer", "Replied"],
+ ["To Reply", "Open"],
+ ]
+ }
+
+ for dt, opts in change_map.items():
+ for status in opts:
+ webnotes.conn.sql("""update `tab%s` set status=%s where status=%s""" % \
+ (dt, "%s", "%s"), (status[1], status[0]))
+
+ for dt in ["Lead", "Opportunity"]:
+ for name in webnotes.conn.sql_list("""select name from `tab%s`""" % dt):
+ bean = webnotes.bean(dt, name)
+ before_status = bean.doc.status
+ bean.get_controller().set_status()
+
+ if bean.doc.status != before_status:
+ webnotes.conn.sql("""update `tab%s` set status=%s where name=%s""" % (dt, "%s", "%s"),
+ (bean.doc.status, name))
diff --git a/patches/october_2013/p04_wsgi_migration.py b/patches/october_2013/p04_wsgi_migration.py
new file mode 100644
index 0000000..ca73516
--- /dev/null
+++ b/patches/october_2013/p04_wsgi_migration.py
@@ -0,0 +1,30 @@
+# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+import webnotes
+import webnotes.utils
+import os
+
+def execute():
+ base_path = webnotes.utils.get_base_path()
+
+ # Remove symlinks from public folder:
+ # - server.py
+ # - web.py
+ # - unsupported.html
+ # - blank.html
+ # - rss.xml
+ # - sitemap.xml
+ for file in ("server.py", "web.py", "unsupported.html", "blank.html", "rss.xml", "sitemap.xml"):
+ file_path = os.path.join(base_path, "public", file)
+ if os.path.exists(file_path):
+ os.remove(file_path)
+
+ # Remove wn-web files
+ # - js/wn-web.js
+ # - css/wn-web.css
+ for file_path in (("js", "wn-web.js"), ("css", "wn-web.css")):
+ file_path = os.path.join(base_path, "public", *file_path)
+ if os.path.exists(file_path):
+ os.remove(file_path)
\ No newline at end of file
diff --git a/patches/october_2013/p05_server_custom_script_to_file.py b/patches/october_2013/p05_server_custom_script_to_file.py
new file mode 100644
index 0000000..3a7e770
--- /dev/null
+++ b/patches/october_2013/p05_server_custom_script_to_file.py
@@ -0,0 +1,36 @@
+# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+import webnotes
+
+def execute():
+ """
+ Assuming that some kind of indentation exists:
+ - Find indentation of server custom script
+ - replace indentation with tabs
+ - Add line:
+ class CustomDocType(DocType):
+ - Add tab indented code after this line
+ - Write to file
+ - Delete custom script record
+ """
+ import os
+ from webnotes.utils import get_site_base_path
+ from core.doctype.custom_script.custom_script import make_custom_server_script_file
+ for name, dt, script in webnotes.conn.sql("""select name, dt, script from `tabCustom Script`
+ where script_type='Server'"""):
+ if script.strip():
+ script = indent_using_tabs(script)
+ make_custom_server_script_file(dt, script)
+
+def indent_using_tabs(script):
+ for line in script.split("\n"):
+ try:
+ indentation_used = line[:line.index("def ")]
+ script = script.replace(indentation_used, "\t")
+ break
+ except ValueError:
+ pass
+
+ return script
\ No newline at end of file
diff --git a/patches/patch_list.py b/patches/patch_list.py
index 59e0b0c..f3fb5b3 100644
--- a/patches/patch_list.py
+++ b/patches/patch_list.py
@@ -220,6 +220,12 @@
"patches.september_2013.p04_unsubmit_serial_nos",
"patches.september_2013.p05_fix_customer_in_pos",
"patches.october_2013.fix_is_cancelled_in_sle",
+ "patches.october_2013.p01_update_delivery_note_prevdocs",
+ "patches.october_2013.p02_set_communication_status",
+ "patches.october_2013.p03_crm_update_status",
+ "execute:webnotes.delete_doc('DocType', 'Setup Control')",
+ "patches.october_2013.p04_wsgi_migration",
+ "patches.october_2013.p05_server_custom_script_to_file",
"patches.october_2013.repost_ordered_qty",
"patches.october_2013.repost_planned_qty",
]
\ No newline at end of file
diff --git a/portal/templates/pages/cart.py b/portal/templates/pages/cart.py
index 24b474a..ecf3163 100644
--- a/portal/templates/pages/cart.py
+++ b/portal/templates/pages/cart.py
@@ -3,4 +3,5 @@
from __future__ import unicode_literals
-no_cache = True
\ No newline at end of file
+no_cache = True
+no_sitemap = True
\ No newline at end of file
diff --git a/portal/templates/pages/profile.py b/portal/templates/pages/profile.py
index 8edd830..3a75cfb 100644
--- a/portal/templates/pages/profile.py
+++ b/portal/templates/pages/profile.py
@@ -7,6 +7,7 @@
from webnotes.utils import cstr
no_cache = True
+no_sitemap = True
def get_context():
from selling.utils.cart import get_lead_or_customer
@@ -33,7 +34,7 @@
return _("Name is required")
webnotes.conn.set_value("Profile", webnotes.session.user, "first_name", fullname)
- webnotes.add_cookies["full_name"] = fullname
+ webnotes._response.set_cookie("full_name", fullname)
return _("Updated")
\ No newline at end of file
diff --git a/projects/doctype/project/project.txt b/projects/doctype/project/project.txt
index 91dcfa1..fc8accf 100644
--- a/projects/doctype/project/project.txt
+++ b/projects/doctype/project/project.txt
@@ -2,12 +2,13 @@
{
"creation": "2013-03-07 11:55:07",
"docstatus": 0,
- "modified": "2013-07-05 14:51:41",
+ "modified": "2013-10-02 14:25:02",
"modified_by": "Administrator",
"owner": "Administrator"
},
{
"allow_attach": 1,
+ "allow_import": 1,
"autoname": "field:project_name",
"doctype": "DocType",
"document_type": "Master",
diff --git a/projects/doctype/task/task.py b/projects/doctype/task/task.py
index 6cd1ba8..fb9b6ab 100644
--- a/projects/doctype/task/task.py
+++ b/projects/doctype/task/task.py
@@ -9,7 +9,6 @@
from webnotes.model.bean import copy_doclist
from webnotes import msgprint
-sql = webnotes.conn.sql
class DocType:
def __init__(self,doc,doclist=[]):
@@ -17,13 +16,13 @@
self.doclist = doclist
def get_project_details(self):
- cust = sql("select customer, customer_name from `tabProject` where name = %s", self.doc.project)
+ cust = webnotes.conn.sql("select customer, customer_name from `tabProject` where name = %s", self.doc.project)
if cust:
ret = {'customer': cust and cust[0][0] or '', 'customer_name': cust and cust[0][1] or ''}
return ret
def get_customer_details(self):
- cust = sql("select customer_name from `tabCustomer` where name=%s", self.doc.customer)
+ cust = webnotes.conn.sql("select customer_name from `tabCustomer` where name=%s", self.doc.customer)
if cust:
ret = {'customer_name': cust and cust[0][0] or ''}
return ret
diff --git a/projects/doctype/task/task.txt b/projects/doctype/task/task.txt
index d890bd6..1c12c8a 100644
--- a/projects/doctype/task/task.txt
+++ b/projects/doctype/task/task.txt
@@ -2,12 +2,13 @@
{
"creation": "2013-01-29 19:25:50",
"docstatus": 0,
- "modified": "2013-07-05 14:57:57",
+ "modified": "2013-10-02 14:25:00",
"modified_by": "Administrator",
"owner": "Administrator"
},
{
"allow_attach": 1,
+ "allow_import": 1,
"autoname": "TASK.#####",
"doctype": "DocType",
"document_type": "Master",
diff --git a/public/js/complete_setup.js b/public/js/complete_setup.js
deleted file mode 100644
index e565621..0000000
--- a/public/js/complete_setup.js
+++ /dev/null
@@ -1,126 +0,0 @@
-// Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
-// License: GNU General Public License v3. See license.txt
-
-// complete my company registration
-// --------------------------------
-wn.provide('erpnext.complete_setup');
-
-$.extend(erpnext.complete_setup, {
- show: function() {
- d = erpnext.complete_setup.prepare_dialog();
- d.show();
- },
-
- prepare_dialog: function() {
- var d = new wn.ui.Dialog({
- title: "Setup",
- fields: [
- {fieldname:'first_name', label:'Your First Name', fieldtype:'Data', reqd: 1},
- {fieldname:'last_name', label:'Your Last Name', fieldtype:'Data'},
- {fieldname:'company_name', label:'Company Name', fieldtype:'Data', reqd:1,
- description: 'e.g. "My Company LLC"'},
- {fieldname:'company_abbr', label:'Company Abbreviation', fieldtype:'Data',
- description:'e.g. "MC"',reqd:1},
- {fieldname:'fy_start', label:'Financial Year Start Date', fieldtype:'Select',
- description:'Your financial year begins on"', reqd:1,
- options: erpnext.complete_setup.fy_start_list.join('\n')},
- {fieldname:'country', label: 'Country', reqd:1,
- options: "", fieldtype: 'Select'},
- {fieldname:'currency', label: 'Default Currency', reqd:1,
- options: "", fieldtype: 'Select'},
- {fieldname:'timezone', label: 'Time Zone', reqd:1,
- options: "", fieldtype: 'Select'},
- {fieldname:'industry', label: 'Industry', reqd:1,
- options: erpnext.complete_setup.domains.join('\n'), fieldtype: 'Select'},
- {fieldname:'update', label:'Setup',fieldtype:'Button'},
- ],
- });
-
- if(user != 'Administrator'){
- d.$wrapper.find('.close').toggle(false); // Hide close image
- $('header').toggle(false); // hide toolbar
- }
-
- wn.call({
- method:"webnotes.country_info.get_country_timezone_info",
- callback: function(data) {
- erpnext.country_info = data.message.country_info;
- erpnext.all_timezones = data.message.all_timezones;
- d.get_input("country").empty()
- .add_options([""].concat(keys(erpnext.country_info).sort()));
- d.get_input("currency").empty()
- .add_options(wn.utils.unique([""].concat($.map(erpnext.country_info,
- function(opts, country) { return opts.currency; }))).sort());
- d.get_input("timezone").empty()
- .add_options([""].concat(erpnext.all_timezones));
- }
- })
-
- // on clicking update
- d.fields_dict.update.input.onclick = function() {
- var data = d.get_values();
- if(!data) return;
- $(this).set_working();
- return $c_obj('Setup Control','setup_account',data,function(r, rt){
- $(this).done_working();
- if(!r.exc) {
- sys_defaults = r.message;
- user_fullname = r.message.user_fullname;
- wn.boot.user_info[user].fullname = user_fullname;
- d.hide();
- $('header').toggle(true);
- wn.container.wntoolbar.set_user_name();
-
- setTimeout(function() { window.location.reload(); }, 3000);
- }
- });
- };
-
- d.fields_dict.company_name.input.onchange = function() {
- var parts = d.get_input("company_name").val().split(" ");
- var abbr = $.map(parts, function(p) { return p ? p.substr(0,1) : null }).join("");
- d.get_input("company_abbr").val(abbr.toUpperCase());
- }
-
- d.fields_dict.country.input.onchange = function() {
- var country = d.fields_dict.country.input.value;
- var $timezone = $(d.fields_dict.timezone.input);
- $timezone.empty();
- // add country specific timezones first
- if(country){
- var timezone_list = erpnext.country_info[country].timezones || [];
- $timezone.add_options(timezone_list.sort());
-
- d.get_input("currency").val(erpnext.country_info[country].currency);
- }
- // add all timezones at the end, so that user has the option to change it to any timezone
- $timezone.add_options([""].concat(erpnext.all_timezones));
-
- };
-
- // company name already set
- if(wn.control_panel.company_name) {
- var inp = d.fields_dict.company_name.input;
- inp.value = wn.control_panel.company_name;
- inp.disabled = true;
- d.fields_dict.company_name.$input.trigger("change");
- }
-
- // set first name, last name
- if(user_fullname) {
- u = user_fullname.split(' ');
- if(u[0]) {
- d.fields_dict.first_name.input.value = u[0];
- }
- if(u[1]) {
- d.fields_dict.last_name.input.value = u[1];
- }
- }
-
- return d;
- },
-
- fy_start_list: ['', '1st Jan', '1st Apr', '1st Jul', '1st Oct'],
-
- domains: ['', "Manufacturing", "Retail", "Distribution", "Services", "Other"],
-});
\ No newline at end of file
diff --git a/public/js/controllers/accounts.js b/public/js/controllers/accounts.js
new file mode 100644
index 0000000..201c47e
--- /dev/null
+++ b/public/js/controllers/accounts.js
@@ -0,0 +1,18 @@
+
+// get tax rate
+cur_frm.cscript.account_head = function(doc, cdt, cdn) {
+ var d = locals[cdt][cdn];
+ if(!d.charge_type && d.account_head){
+ msgprint("Please select Charge Type first");
+ wn.model.set_value(cdt, cdn, "account_head", "");
+ } else if(d.account_head && d.charge_type!=="Actual") {
+ wn.call({
+ type:"GET",
+ method: "controllers.accounts_controller.get_tax_rate",
+ args: {"account_head":d.account_head},
+ callback: function(r) {
+ wn.model.set_value(cdt, cdn, "rate", r.message || 0);
+ }
+ })
+ }
+}
diff --git a/public/js/startup.js b/public/js/startup.js
index eee8a05..5a81d73 100644
--- a/public/js/startup.js
+++ b/public/js/startup.js
@@ -9,25 +9,10 @@
console.log('Starting up...');
$('#startup_div').html('Starting up...').toggle(true);
- if(user != 'Guest'){
- // setup toolbar
- erpnext.toolbar.setup();
-
- // complete registration
- if(in_list(user_roles,'System Manager') && (wn.boot.setup_complete==='No')) {
- wn.require("app/js/complete_setup.js");
- erpnext.complete_setup.show();
- } else if(!wn.boot.customer_count) {
- if(wn.get_route()[0]!=="Setup") {
- msgprint("<a class='btn btn-success' href='#Setup'>"
- + wn._("Proceed to Setup") + "</a>\
- <br><br><p class='text-muted'>"+
- wn._("This message goes away after you create your first customer.")+
- "</p>", wn._("Welcome"));
- }
- } else if(wn.boot.expires_on && in_list(user_roles, 'System Manager')) {
- erpnext.startup.show_expiry_banner();
- }
+ erpnext.toolbar.setup();
+
+ if(wn.boot.expires_on && in_list(user_roles, 'System Manager')) {
+ erpnext.startup.show_expiry_banner();
}
}
diff --git a/public/js/utils.js b/public/js/utils.js
index 61e613b..6879b69 100644
--- a/public/js/utils.js
+++ b/public/js/utils.js
@@ -20,7 +20,7 @@
hide_company: function() {
if(cur_frm.fields_dict.company) {
- var companies = Object.keys(locals[":Company"]);
+ var companies = Object.keys(locals[":Company"] || {});
if(companies.length === 1) {
if(!cur_frm.doc.company) cur_frm.set_value("company", companies[0]);
cur_frm.toggle_display("company", false);
diff --git a/selling/doctype/customer/customer.js b/selling/doctype/customer/customer.js
index d2c6325..a38ab9c 100644
--- a/selling/doctype/customer/customer.js
+++ b/selling/doctype/customer/customer.js
@@ -34,7 +34,6 @@
cur_frm.cscript.make_contact(doc,dt,dn);
cur_frm.communication_view = new wn.views.CommunicationList({
- list: wn.model.get("Communication", {"customer": doc.name}),
parent: cur_frm.fields_dict.communication_html.wrapper,
doc: doc,
});
diff --git a/selling/doctype/customer/customer.py b/selling/doctype/customer/customer.py
index 2b57da9..18c8a34 100644
--- a/selling/doctype/customer/customer.py
+++ b/selling/doctype/customer/customer.py
@@ -9,7 +9,6 @@
from webnotes import msgprint, _
import webnotes.defaults
-sql = webnotes.conn.sql
from utilities.transaction_base import TransactionBase
@@ -31,7 +30,7 @@
return webnotes.conn.get_value('Company', self.doc.company, 'abbr')
def get_receivables_group(self):
- g = sql("select receivables_group from tabCompany where name=%s", self.doc.company)
+ g = webnotes.conn.sql("select receivables_group from tabCompany where name=%s", self.doc.company)
g = g and g[0][0] or ''
if not g:
msgprint("Update Company master, assign a default group for Receivables")
@@ -47,7 +46,7 @@
def update_lead_status(self):
if self.doc.lead_name:
- sql("update `tabLead` set status='Converted' where name = %s", self.doc.lead_name)
+ webnotes.conn.sql("update `tabLead` set status='Converted' where name = %s", self.doc.lead_name)
def create_account_head(self):
if self.doc.company :
@@ -132,7 +131,7 @@
def delete_customer_account(self):
"""delete customer's ledger if exist and check balance before deletion"""
- acc = sql("select name from `tabAccount` where master_type = 'Customer' \
+ acc = webnotes.conn.sql("select name from `tabAccount` where master_type = 'Customer' \
and master_name = %s and docstatus < 2", self.doc.name)
if acc:
from webnotes.model import delete_doc
@@ -143,7 +142,7 @@
self.delete_customer_contact()
self.delete_customer_account()
if self.doc.lead_name:
- sql("update `tabLead` set status='Interested' where name=%s",self.doc.lead_name)
+ webnotes.conn.sql("update `tabLead` set status='Interested' where name=%s",self.doc.lead_name)
def on_rename(self, new, old, merge=False):
#update customer_name if not naming series
diff --git a/selling/doctype/installation_note/installation_note.py b/selling/doctype/installation_note/installation_note.py
index ca47043..02b7247 100644
--- a/selling/doctype/installation_note/installation_note.py
+++ b/selling/doctype/installation_note/installation_note.py
@@ -38,7 +38,6 @@
self.check_item_table()
sales_com_obj = get_obj(dt = 'Sales Common')
sales_com_obj.check_active_sales_items(self)
- sales_com_obj.get_prevdoc_date(self)
def validate_fiscal_year(self):
from accounts.utils import validate_fiscal_year
diff --git a/selling/doctype/installation_note_item/installation_note_item.txt b/selling/doctype/installation_note_item/installation_note_item.txt
index 02871ad..7435d46 100644
--- a/selling/doctype/installation_note_item/installation_note_item.txt
+++ b/selling/doctype/installation_note_item/installation_note_item.txt
@@ -2,7 +2,7 @@
{
"creation": "2013-02-22 01:27:51",
"docstatus": 0,
- "modified": "2013-07-10 14:54:09",
+ "modified": "2013-10-10 17:02:31",
"modified_by": "Administrator",
"owner": "Administrator"
},
@@ -50,18 +50,6 @@
},
{
"doctype": "DocField",
- "fieldname": "prevdoc_date",
- "fieldtype": "Date",
- "hidden": 0,
- "in_list_view": 1,
- "label": "Delivery Date",
- "oldfieldname": "prevdoc_date",
- "oldfieldtype": "Date",
- "print_hide": 0,
- "read_only": 1
- },
- {
- "doctype": "DocField",
"fieldname": "serial_no",
"fieldtype": "Small Text",
"in_list_view": 1,
diff --git a/selling/doctype/lead/get_leads.py b/selling/doctype/lead/get_leads.py
index 3305a3b..eaf837b 100644
--- a/selling/doctype/lead/get_leads.py
+++ b/selling/doctype/lead/get_leads.py
@@ -29,7 +29,7 @@
parent_name = contact_name or lead_name
message = make(content=content, sender=sender, subject=subject,
- doctype = parent_doctype, name = parent_name, date=date)
+ doctype = parent_doctype, name = parent_name, date=date, sent_or_received="Received")
if mail:
# save attachments to parent if from mail
diff --git a/selling/doctype/lead/lead.py b/selling/doctype/lead/lead.py
index 41387f4..a33ae35 100644
--- a/selling/doctype/lead/lead.py
+++ b/selling/doctype/lead/lead.py
@@ -7,7 +7,6 @@
from webnotes.utils import cstr, validate_email_add, cint, extract_email_id
from webnotes import session, msgprint
-sql = webnotes.conn.sql
from controllers.selling_controller import SellingController
@@ -27,24 +26,9 @@
customer = webnotes.conn.get_value("Customer", {"lead_name": self.doc.name})
if customer:
self.doc.fields["__is_customer"] = customer
-
- def on_communication(self, comm):
- if comm.sender == self.get_sender(comm) or \
- webnotes.conn.get_value("Profile", extract_email_id(comm.sender), "user_type")=="System User":
- status = "Replied"
- else:
- status = "Open"
-
- webnotes.conn.set(self.doc, 'status', status)
-
- def check_status(self):
- chk = sql("select status from `tabLead` where name=%s", self.doc.name)
- chk = chk and chk[0][0] or ''
- return cstr(chk)
def validate(self):
- if self.doc.status == 'Lead Lost' and not self.doc.order_lost_reason:
- webnotes.throw("Please Enter Lost Reason under More Info section")
+ self.set_status()
if self.doc.source == 'Campaign' and not self.doc.campaign_name and session['user'] != 'Guest':
webnotes.throw("Please specify campaign name")
@@ -76,14 +60,18 @@
webnotes.msgprint(_("""Email Id must be unique, already exists for: """) + \
", ".join(items), raise_exception=True)
- def get_sender(self, comm):
- return webnotes.conn.get_value('Sales Email Settings',None,'email_id')
-
def on_trash(self):
webnotes.conn.sql("""update `tabSupport Ticket` set lead='' where lead=%s""",
self.doc.name)
self.delete_events()
+
+ def has_customer(self):
+ return webnotes.conn.get_value("Customer", {"lead_name": self.doc.name})
+
+ def has_opportunity(self):
+ return webnotes.conn.get_value("Opportunity", {"lead": self.doc.name, "docstatus": 1,
+ "status": ["!=", "Lost"]})
@webnotes.whitelist()
def make_customer(source_name, target_doclist=None):
diff --git a/selling/doctype/lead/lead.txt b/selling/doctype/lead/lead.txt
index b969906..b700a2e 100644
--- a/selling/doctype/lead/lead.txt
+++ b/selling/doctype/lead/lead.txt
@@ -7,6 +7,7 @@
"owner": "Administrator"
},
{
+ "allow_import": 1,
"autoname": "naming_series:",
"doctype": "DocType",
"document_type": "Master",
@@ -101,7 +102,7 @@
"fieldtype": "Column Break"
},
{
- "default": "Open",
+ "default": "Lead",
"doctype": "DocField",
"fieldname": "status",
"fieldtype": "Select",
@@ -111,7 +112,7 @@
"no_copy": 1,
"oldfieldname": "status",
"oldfieldtype": "Select",
- "options": "\nOpen\nReplied\nAttempted to Contact\nContact in Future\nContacted\nOpportunity Made\nInterested\nNot interested\nLead Lost\nConverted\nPassive",
+ "options": "Lead\nOpen\nReplied\nOpportunity\nInterested\nConverted\nDo Not Contact",
"reqd": 1,
"search_index": 1
},
@@ -223,8 +224,7 @@
"fieldtype": "HTML",
"label": "Communication HTML",
"oldfieldname": "follow_up",
- "oldfieldtype": "Table",
- "print_hide": 1
+ "oldfieldtype": "Table"
},
{
"doctype": "DocField",
@@ -378,18 +378,6 @@
"width": "50%"
},
{
- "allow_on_submit": 0,
- "depends_on": "eval:doc.status == 'Lead Lost'",
- "doctype": "DocField",
- "fieldname": "order_lost_reason",
- "fieldtype": "Link",
- "hidden": 0,
- "label": "Lost Reason",
- "oldfieldname": "order_lost_reason",
- "oldfieldtype": "Link",
- "options": "Quotation Lost Reason"
- },
- {
"doctype": "DocField",
"fieldname": "company",
"fieldtype": "Link",
@@ -417,8 +405,7 @@
"fieldtype": "Table",
"hidden": 1,
"label": "Communications",
- "options": "Communication",
- "print_hide": 1
+ "options": "Communication"
},
{
"cancel": 1,
diff --git a/selling/doctype/opportunity/opportunity.js b/selling/doctype/opportunity/opportunity.js
index 25f28bf..d2b866c 100644
--- a/selling/doctype/opportunity/opportunity.js
+++ b/selling/doctype/opportunity/opportunity.js
@@ -101,20 +101,13 @@
cur_frm.cscript.refresh = function(doc, cdt, cdn){
erpnext.hide_naming_series();
-
- cur_frm.dashboard.reset(doc);
- if(!doc.__islocal) {
- if(doc.status=="Converted" || doc.status=="Order Confirmed") {
- cur_frm.dashboard.set_headline_alert(wn._(doc.status), "alert-success", "icon-ok-sign");
- } else if(doc.status=="Opportunity Lost") {
- cur_frm.dashboard.set_headline_alert(wn._(doc.status), "alert-danger", "icon-exclamation-sign");
- }
- }
cur_frm.clear_custom_buttons();
- if(doc.docstatus === 1 && doc.status!=="Opportunity Lost") {
+ if(doc.docstatus === 1 && doc.status!=="Lost") {
cur_frm.add_custom_button('Create Quotation', cur_frm.cscript.create_quotation);
- cur_frm.add_custom_button('Opportunity Lost', cur_frm.cscript['Declare Opportunity Lost']);
+ if(doc.status!=="Quotation") {
+ cur_frm.add_custom_button('Opportunity Lost', cur_frm.cscript['Declare Opportunity Lost']);
+ }
cur_frm.add_custom_button('Send SMS', cur_frm.cscript.send_sms);
}
diff --git a/selling/doctype/opportunity/opportunity.py b/selling/doctype/opportunity/opportunity.py
index 5854758..37672f2 100644
--- a/selling/doctype/opportunity/opportunity.py
+++ b/selling/doctype/opportunity/opportunity.py
@@ -6,9 +6,8 @@
from webnotes.utils import cstr, cint
from webnotes.model.bean import getlist
-from webnotes import msgprint
+from webnotes import msgprint, _
-sql = webnotes.conn.sql
from utilities.transaction_base import TransactionBase
@@ -27,7 +26,7 @@
})
def get_item_details(self, item_code):
- item = sql("""select item_name, stock_uom, description_html, description, item_group, brand
+ item = webnotes.conn.sql("""select item_name, stock_uom, description_html, description, item_group, brand
from `tabItem` where name = %s""", item_code, as_dict=1)
ret = {
'item_name': item and item[0]['item_name'] or '',
@@ -39,7 +38,7 @@
return ret
def get_cust_address(self,name):
- details = sql("select customer_name, address, territory, customer_group from `tabCustomer` where name = '%s' and docstatus != 2" %(name), as_dict = 1)
+ details = webnotes.conn.sql("select customer_name, address, territory, customer_group from `tabCustomer` where name = '%s' and docstatus != 2" %(name), as_dict = 1)
if details:
ret = {
'customer_name': details and details[0]['customer_name'] or '',
@@ -49,7 +48,7 @@
}
# ********** get primary contact details (this is done separately coz. , in case there is no primary contact thn it would not be able to fetch customer details in case of join query)
- contact_det = sql("select contact_name, contact_no, email_id from `tabContact` where customer = '%s' and is_customer = 1 and is_primary_contact = 'Yes' and docstatus != 2" %(name), as_dict = 1)
+ contact_det = webnotes.conn.sql("select contact_name, contact_no, email_id from `tabContact` where customer = '%s' and is_customer = 1 and is_primary_contact = 'Yes' and docstatus != 2" %(name), as_dict = 1)
ret['contact_person'] = contact_det and contact_det[0]['contact_name'] or ''
ret['contact_no'] = contact_det and contact_det[0]['contact_no'] or ''
@@ -62,13 +61,14 @@
def get_contact_details(self, arg):
arg = eval(arg)
- contact = sql("select contact_no, email_id from `tabContact` where contact_name = '%s' and customer_name = '%s'" %(arg['contact_person'],arg['customer']), as_dict = 1)
+ contact = webnotes.conn.sql("select contact_no, email_id from `tabContact` where contact_name = '%s' and customer_name = '%s'" %(arg['contact_person'],arg['customer']), as_dict = 1)
ret = {
'contact_no' : contact and contact[0]['contact_no'] or '',
'email_id' : contact and contact[0]['email_id'] or ''
}
return ret
-
+
+
def on_update(self):
self.add_calendar_event()
@@ -109,48 +109,36 @@
msgprint("Customer is mandatory if 'Opportunity From' is selected as Customer", raise_exception=1)
def validate(self):
+ self.set_status()
self.validate_item_details()
self.validate_uom_is_integer("uom", "qty")
self.validate_lead_cust()
from accounts.utils import validate_fiscal_year
validate_fiscal_year(self.doc.transaction_date, self.doc.fiscal_year, "Opportunity Date")
- self.doc.status = "Draft"
def on_submit(self):
- webnotes.conn.set(self.doc, 'status', 'Submitted')
- if self.doc.lead and webnotes.conn.get_value("Lead", self.doc.lead, "status")!="Converted":
- webnotes.conn.set_value("Lead", self.doc.lead, "status", "Opportunity Made")
+ if self.doc.lead:
+ webnotes.bean("Lead", self.doc.lead).get_controller().set_status(update=True)
def on_cancel(self):
- chk = sql("select t1.name from `tabQuotation` t1, `tabQuotation Item` t2 where t2.parent = t1.name and t1.docstatus=1 and (t1.status!='Order Lost' and t1.status!='Cancelled') and t2.prevdoc_docname = %s",self.doc.name)
- if chk:
- msgprint("Quotation No. "+cstr(chk[0][0])+" is submitted against this Opportunity. Thus can not be cancelled.")
- raise Exception
- else:
- webnotes.conn.set(self.doc, 'status', 'Cancelled')
- if self.doc.lead and webnotes.conn.get_value("Lead", self.doc.lead,
- "status")!="Converted":
- if webnotes.conn.get_value("Communication", {"parent": self.doc.lead}):
- status = "Contacted"
- else:
- status = "Open"
-
- webnotes.conn.set_value("Lead", self.doc.lead, "status", status)
+ if self.has_quotation():
+ webnotes.throw(_("Cannot Cancel Opportunity as Quotation Exists"))
+ self.set_status(update=True)
def declare_enquiry_lost(self,arg):
- chk = sql("select t1.name from `tabQuotation` t1, `tabQuotation Item` t2 where t2.parent = t1.name and t1.docstatus=1 and (t1.status!='Order Lost' and t1.status!='Cancelled') and t2.prevdoc_docname = %s",self.doc.name)
- if chk:
- msgprint("Quotation No. "+cstr(chk[0][0])+" is submitted against this Opportunity. Thus 'Opportunity Lost' can not be declared against it.")
- raise Exception
- else:
- webnotes.conn.set(self.doc, 'status', 'Opportunity Lost')
+ if not self.has_quotation():
+ webnotes.conn.set(self.doc, 'status', 'Lost')
webnotes.conn.set(self.doc, 'order_lost_reason', arg)
- return 'true'
+ else:
+ webnotes.throw(_("Cannot declare as lost, because Quotation has been made."))
def on_trash(self):
self.delete_events()
+ def has_quotation(self):
+ return webnotes.conn.get_value("Quotation Item", {"prevdoc_docname": self.doc.name, "docstatus": 1})
+
@webnotes.whitelist()
def make_quotation(source_name, target_doclist=None):
from webnotes.model.mapper import get_mapped_doclist
diff --git a/selling/doctype/opportunity/opportunity.txt b/selling/doctype/opportunity/opportunity.txt
index 8a68a31..3c860ad 100644
--- a/selling/doctype/opportunity/opportunity.txt
+++ b/selling/doctype/opportunity/opportunity.txt
@@ -7,6 +7,7 @@
"owner": "Administrator"
},
{
+ "allow_import": 1,
"autoname": "naming_series:",
"description": "Potential Sales Deal",
"doctype": "DocType",
@@ -125,7 +126,7 @@
"no_copy": 1,
"oldfieldname": "status",
"oldfieldtype": "Select",
- "options": "\nDraft\nSubmitted\nQuotation Sent\nOrder Confirmed\nOpportunity Lost\nCancelled",
+ "options": "Draft\nSubmitted\nQuotation\nLost\nCancelled\nReplied\nOpen",
"read_only": 1,
"reqd": 1
},
@@ -168,7 +169,6 @@
"label": "Communication History",
"oldfieldtype": "Section Break",
"options": "icon-comments",
- "print_hide": 1,
"read_only": 0
},
{
@@ -179,7 +179,6 @@
"label": "Communication HTML",
"oldfieldname": "follow_up",
"oldfieldtype": "Table",
- "print_hide": 1,
"read_only": 0
},
{
@@ -352,18 +351,6 @@
"read_only": 0
},
{
- "depends_on": "eval:!doc.__islocal",
- "doctype": "DocField",
- "fieldname": "order_lost_reason",
- "fieldtype": "Small Text",
- "label": "Quotation Lost Reason",
- "no_copy": 1,
- "oldfieldname": "order_lost_reason",
- "oldfieldtype": "Small Text",
- "read_only": 1,
- "report_hide": 0
- },
- {
"doctype": "DocField",
"fieldname": "company",
"fieldtype": "Link",
@@ -378,6 +365,15 @@
"search_index": 1
},
{
+ "depends_on": "eval:!doc.__islocal",
+ "doctype": "DocField",
+ "fieldname": "order_lost_reason",
+ "fieldtype": "Text",
+ "label": "Lost Reason",
+ "no_copy": 1,
+ "read_only": 1
+ },
+ {
"doctype": "DocField",
"fieldname": "column_break2",
"fieldtype": "Column Break",
@@ -436,8 +432,7 @@
"fieldtype": "Table",
"hidden": 1,
"label": "Communications",
- "options": "Communication",
- "print_hide": 1
+ "options": "Communication"
},
{
"doctype": "DocPerm",
diff --git a/selling/doctype/quotation/quotation.js b/selling/doctype/quotation/quotation.js
index e20308f..05feed0 100644
--- a/selling/doctype/quotation/quotation.js
+++ b/selling/doctype/quotation/quotation.js
@@ -24,19 +24,10 @@
},
refresh: function(doc, dt, dn) {
this._super(doc, dt, dn);
-
- cur_frm.dashboard.reset(doc);
- if(!doc.__islocal) {
- if(doc.status=="Converted" || doc.status=="Order Confirmed") {
- cur_frm.dashboard.set_headline_alert(wn._(doc.status), "alert-success", "icon-ok-sign");
- } else if(doc.status==="Order Lost") {
- cur_frm.dashboard.set_headline_alert(wn._(doc.status), "alert-danger", "icon-exclamation-sign");
- }
- }
- if(doc.docstatus == 1 && doc.status!=='Order Lost') {
+ if(doc.docstatus == 1 && doc.status!=='Lost') {
cur_frm.add_custom_button('Make Sales Order', cur_frm.cscript['Make Sales Order']);
- if(doc.status!=="Order Confirmed") {
+ if(doc.status!=="Ordered") {
cur_frm.add_custom_button('Set as Lost', cur_frm.cscript['Declare Order Lost']);
}
cur_frm.add_custom_button('Send SMS', cur_frm.cscript.send_sms);
diff --git a/selling/doctype/quotation/quotation.py b/selling/doctype/quotation/quotation.py
index 8eb3654..78afb97 100644
--- a/selling/doctype/quotation/quotation.py
+++ b/selling/doctype/quotation/quotation.py
@@ -9,7 +9,6 @@
from webnotes.model.code import get_obj
from webnotes import _, msgprint
-sql = webnotes.conn.sql
from controllers.selling_controller import SellingController
@@ -48,17 +47,16 @@
if not doc.fields.get(r):
doc.fields[r] = res[r]
+
+ def has_sales_order(self):
+ return webnotes.conn.get_value("Sales Order Item", {"prevdoc_docname": self.doc.name, "docstatus": 1})
+
+
# Re-calculates Basic Rate & amount based on Price List Selected
# --------------------------------------------------------------
def get_adj_percent(self, arg=''):
get_obj('Sales Common').get_adj_percent(self)
-
- # Get Tax rate if account type is TAX
- # -----------------------------------
- def get_rate(self,arg):
- return get_obj('Sales Common').get_rate(arg)
-
# Does not allow same item code to be entered twice
# -------------------------------------------------
def validate_for_items(self):
@@ -78,7 +76,7 @@
if self.doc.order_type in ['Maintenance', 'Service']:
for d in getlist(self.doclist, 'quotation_details'):
- is_service_item = sql("select is_service_item from `tabItem` where name=%s", d.item_code)
+ is_service_item = webnotes.conn.sql("select is_service_item from `tabItem` where name=%s", d.item_code)
is_service_item = is_service_item and is_service_item[0][0] or 'No'
if is_service_item == 'No':
@@ -86,7 +84,7 @@
raise Exception
else:
for d in getlist(self.doclist, 'quotation_details'):
- is_sales_item = sql("select is_sales_item from `tabItem` where name=%s", d.item_code)
+ is_sales_item = webnotes.conn.sql("select is_sales_item from `tabItem` where name=%s", d.item_code)
is_sales_item = is_sales_item and is_sales_item[0][0] or 'No'
if is_sales_item == 'No':
@@ -95,14 +93,7 @@
def validate(self):
super(DocType, self).validate()
-
- import utilities
- if not self.doc.status:
- self.doc.status = "Draft"
- else:
- utilities.validate_status(self.doc.status, ["Draft", "Submitted",
- "Order Confirmed", "Order Lost", "Cancelled"])
-
+ self.set_status()
self.validate_order_type()
self.validate_for_items()
@@ -112,42 +103,22 @@
sales_com_obj.check_active_sales_items(self)
sales_com_obj.validate_max_discount(self,'quotation_details')
sales_com_obj.check_conversion_rate(self)
-
-
- def on_update(self):
- # Set Quotation Status
- webnotes.conn.set(self.doc, 'status', 'Draft')
-
+
#update enquiry
#------------------
- def update_enquiry(self, flag):
- prevdoc=''
- for d in getlist(self.doclist, 'quotation_details'):
- if d.prevdoc_docname:
- prevdoc = d.prevdoc_docname
-
- if prevdoc:
- if flag == 'submit': #on submit
- sql("update `tabOpportunity` set status = 'Quotation Sent' where name = %s", prevdoc)
- elif flag == 'cancel': #on cancel
- sql("update `tabOpportunity` set status = 'Open' where name = %s", prevdoc)
- elif flag == 'order lost': #order lost
- sql("update `tabOpportunity` set status = 'Opportunity Lost' where name=%s", prevdoc)
- elif flag == 'order confirm': #order confirm
- sql("update `tabOpportunity` set status='Order Confirmed' where name=%s", prevdoc)
+ def update_opportunity(self):
+ for opportunity in self.doclist.get_distinct_values("prevdoc_docname"):
+ webnotes.bean("Opportunity", opportunity).get_controller().set_status(update=True)
# declare as order lost
#-------------------------
def declare_order_lost(self, arg):
- chk = sql("select t1.name from `tabSales Order` t1, `tabSales Order Item` t2 where t2.parent = t1.name and t1.docstatus=1 and t2.prevdoc_docname = %s",self.doc.name)
- if chk:
- msgprint("Sales Order No. "+cstr(chk[0][0])+" is submitted against this Quotation. Thus 'Order Lost' can not be declared against it.")
- raise Exception
- else:
- webnotes.conn.set(self.doc, 'status', 'Order Lost')
+ if not self.has_sales_order():
+ webnotes.conn.set(self.doc, 'status', 'Lost')
webnotes.conn.set(self.doc, 'order_lost_reason', arg)
- self.update_enquiry('order lost')
- return 'true'
+ self.update_opportunity()
+ else:
+ webnotes.throw(_("Cannot set as Lost as Sales Order is made."))
#check if value entered in item table
#--------------------------------------
@@ -163,21 +134,17 @@
# Check for Approving Authority
get_obj('Authorization Control').validate_approving_authority(self.doc.doctype, self.doc.company, self.doc.grand_total, self)
-
- # Set Quotation Status
- webnotes.conn.set(self.doc, 'status', 'Submitted')
-
+
#update enquiry status
- self.update_enquiry('submit')
+ self.update_opportunity()
# ON CANCEL
# ==========================================================================
def on_cancel(self):
#update enquiry status
- self.update_enquiry('cancel')
-
- webnotes.conn.set(self.doc,'status','Cancelled')
+ self.set_status()
+ self.update_opportunity()
# Print other charges
# ===========================================================================
@@ -189,6 +156,7 @@
lst1.append(d.total)
print_lst.append(lst1)
return print_lst
+
@webnotes.whitelist()
def make_sales_order(source_name, target_doclist=None):
diff --git a/selling/doctype/quotation/quotation.txt b/selling/doctype/quotation/quotation.txt
index 62c36b4..1620d91 100644
--- a/selling/doctype/quotation/quotation.txt
+++ b/selling/doctype/quotation/quotation.txt
@@ -9,6 +9,7 @@
{
"allow_attach": 1,
"allow_email": 0,
+ "allow_import": 1,
"autoname": "naming_series:",
"doctype": "DocType",
"document_type": "Transaction",
@@ -732,7 +733,7 @@
"no_copy": 1,
"oldfieldname": "status",
"oldfieldtype": "Select",
- "options": "\nDraft\nSubmitted\nOrder Confirmed\nOrder Lost\nCancelled",
+ "options": "Draft\nSubmitted\nOrdered\nLost\nCancelled",
"print_hide": 1,
"read_only": 1,
"reqd": 1,
@@ -840,8 +841,7 @@
"fieldtype": "Table",
"hidden": 1,
"label": "Communications",
- "options": "Communication",
- "print_hide": 1
+ "options": "Communication"
},
{
"amend": 1,
diff --git a/selling/doctype/sales_common/sales_common.js b/selling/doctype/sales_common/sales_common.js
index c87e823..f744faa 100644
--- a/selling/doctype/sales_common/sales_common.js
+++ b/selling/doctype/sales_common/sales_common.js
@@ -10,6 +10,7 @@
wn.provide("erpnext.selling");
wn.require("app/js/transaction.js");
+wn.require("app/js/controllers/accounts.js");
erpnext.selling.SellingController = erpnext.TransactionController.extend({
onload: function() {
diff --git a/selling/doctype/sales_common/sales_common.py b/selling/doctype/sales_common/sales_common.py
index 8271c82..01718dd 100644
--- a/selling/doctype/sales_common/sales_common.py
+++ b/selling/doctype/sales_common/sales_common.py
@@ -86,26 +86,6 @@
if (obj.doc.price_list_currency == default_currency and flt(obj.doc.plc_conversion_rate) != 1.00) or not obj.doc.plc_conversion_rate or (obj.doc.price_list_currency != default_currency and flt(obj.doc.plc_conversion_rate) == 1.00):
msgprint("Please Enter Appropriate Conversion Rate for Price List Currency to Base Currency (%s --> %s)" % (obj.doc.price_list_currency, default_currency), raise_exception = 1)
-
-
-
- # Get Tax rate if account type is TAX
- # =========================================================================
- def get_rate(self, arg):
- arg = eval(arg)
- rate = webnotes.conn.sql("select account_type, tax_rate from `tabAccount` where name = '%s' and docstatus != 2" %(arg['account_head']), as_dict=1)
- ret = {'rate' : 0}
- if arg['charge_type'] == 'Actual' and rate[0]['account_type'] == 'Tax':
- msgprint("You cannot select ACCOUNT HEAD of type TAX as your CHARGE TYPE is 'ACTUAL'")
- ret = {
- 'account_head' : ''
- }
- elif rate[0]['account_type'] in ['Tax', 'Chargeable'] and not arg['charge_type'] == 'Actual':
- ret = {
- 'rate' : rate and flt(rate[0]['tax_rate']) or 0
- }
- return ret
-
def get_item_list(self, obj, is_stopped=0):
"""get item list"""
@@ -123,12 +103,12 @@
if flt(d.qty) > flt(d.delivered_qty):
reserved_qty_for_main_item = flt(d.qty) - flt(d.delivered_qty)
- if obj.doc.doctype == "Delivery Note" and d.prevdoc_doctype == 'Sales Order':
+ if obj.doc.doctype == "Delivery Note" and d.against_sales_order:
# 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
already_delivered_qty = self.get_already_delivered_qty(obj.doc.name,
- d.prevdoc_docname, d.prevdoc_detail_docname)
+ d.against_sales_order, d.prevdoc_detail_docname)
so_qty, reserved_warehouse = self.get_so_qty_and_warehouse(d.prevdoc_detail_docname)
if already_delivered_qty + d.qty > so_qty:
@@ -168,7 +148,7 @@
def get_already_delivered_qty(self, dn, so, so_detail):
qty = webnotes.conn.sql("""select sum(qty) from `tabDelivery Note Item`
where prevdoc_detail_docname = %s and docstatus = 1
- and prevdoc_doctype = 'Sales Order' and prevdoc_docname = %s
+ and against_sales_order = %s
and parent != %s""", (so_detail, so, dn))
return qty and flt(qty[0][0]) or 0.0
@@ -218,7 +198,6 @@
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.prevdoc_doctype = line.prevdoc_doctype
if not pi.warehouse:
pi.warehouse = warehouse
if not pi.batch_no:
@@ -283,8 +262,8 @@
def check_stop_sales_order(self,obj):
for d in getlist(obj.doclist,obj.fname):
ref_doc_name = ''
- if d.fields.has_key('prevdoc_docname') and d.prevdoc_docname and d.prevdoc_doctype == 'Sales Order':
- ref_doc_name = d.prevdoc_docname
+ if d.fields.has_key('against_sales_order') and d.against_sales_order:
+ ref_doc_name = d.against_sales_order
elif d.fields.has_key('sales_order') and d.sales_order and not d.delivery_note:
ref_doc_name = d.sales_order
if ref_doc_name:
@@ -319,17 +298,6 @@
exact_outstanding = flt(tot_outstanding) + flt(grand_total)
get_obj('Account',acc_head[0][0]).check_credit_limit(acc_head[0][0], obj.doc.company, exact_outstanding)
- def get_prevdoc_date(self, obj):
- for d in getlist(obj.doclist, obj.fname):
- if d.prevdoc_doctype and d.prevdoc_docname:
- if d.prevdoc_doctype in ["Sales Invoice", "Delivery Note"]:
- date_field = "posting_date"
- else:
- date_field = "transaction_date"
-
- d.prevdoc_date = webnotes.conn.get_value(d.prevdoc_doctype,
- d.prevdoc_docname, date_field)
-
def get_batch_no(doctype, txt, searchfield, start, page_len, filters):
from controllers.queries import get_match_cond
diff --git a/selling/doctype/sales_order/sales_order.js b/selling/doctype/sales_order/sales_order.js
index 0c26179..bf23b9c 100644
--- a/selling/doctype/sales_order/sales_order.js
+++ b/selling/doctype/sales_order/sales_order.js
@@ -66,7 +66,7 @@
source_doctype: "Quotation",
get_query_filters: {
docstatus: 1,
- status: ["!=", "Order Lost"],
+ status: ["!=", "Lost"],
order_type: cur_frm.doc.order_type,
customer: cur_frm.doc.customer || undefined,
company: cur_frm.doc.company
diff --git a/selling/doctype/sales_order/sales_order.py b/selling/doctype/sales_order/sales_order.py
index 435a976..1c22c08 100644
--- a/selling/doctype/sales_order/sales_order.py
+++ b/selling/doctype/sales_order/sales_order.py
@@ -11,7 +11,6 @@
from webnotes import msgprint
from webnotes.model.mapper import get_mapped_doclist
-sql = webnotes.conn.sql
from controllers.selling_controller import SellingController
@@ -39,9 +38,6 @@
def get_available_qty(self,args):
return get_obj('Sales Common').get_available_qty(eval(args))
- def get_rate(self,arg):
- return get_obj('Sales Common').get_rate(arg)
-
def validate_mandatory(self):
# validate transaction date v/s delivery date
if self.doc.delivery_date:
@@ -88,14 +84,14 @@
# used for production plan
d.transaction_date = self.doc.transaction_date
- tot_avail_qty = sql("select projected_qty from `tabBin` \
+ tot_avail_qty = webnotes.conn.sql("select projected_qty from `tabBin` \
where item_code = '%s' and warehouse = '%s'" % (d.item_code,d.reserved_warehouse))
d.projected_qty = tot_avail_qty and flt(tot_avail_qty[0][0]) or 0
def validate_sales_mntc_quotation(self):
for d in getlist(self.doclist, 'sales_order_details'):
if d.prevdoc_docname:
- res = sql("select name from `tabQuotation` where name=%s and order_type = %s", (d.prevdoc_docname, self.doc.order_type))
+ res = webnotes.conn.sql("select name from `tabQuotation` where name=%s and order_type = %s", (d.prevdoc_docname, self.doc.order_type))
if not res:
msgprint("""Order Type (%s) should be same in Quotation: %s \
and current Sales Order""" % (self.doc.order_type, d.prevdoc_docname))
@@ -112,7 +108,7 @@
def validate_proj_cust(self):
if self.doc.project_name and self.doc.customer_name:
- res = sql("select name from `tabProject` where name = '%s' and (customer = '%s' or ifnull(customer,'')='')"%(self.doc.project_name, 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:
msgprint("Customer - %s does not belong to project - %s. \n\nIf you want to use project for multiple customers then please make customer details blank in project - %s."%(self.doc.customer,self.doc.project_name,self.doc.project_name))
raise Exception
@@ -167,36 +163,20 @@
})
- def check_prev_docstatus(self):
- for d in getlist(self.doclist, 'sales_order_details'):
- cancel_quo = sql("select name from `tabQuotation` where docstatus = 2 and name = '%s'" % d.prevdoc_docname)
- if cancel_quo:
- msgprint("Quotation :" + cstr(cancel_quo[0][0]) + " is already cancelled !")
- raise Exception , "Validation Error. "
-
def update_enquiry_status(self, prevdoc, flag):
- enq = sql("select t2.prevdoc_docname from `tabQuotation` t1, `tabQuotation Item` t2 where t2.parent = t1.name and t1.name=%s", prevdoc)
+ enq = webnotes.conn.sql("select t2.prevdoc_docname from `tabQuotation` t1, `tabQuotation Item` t2 where t2.parent = t1.name and t1.name=%s", prevdoc)
if enq:
- sql("update `tabOpportunity` set status = %s where name=%s",(flag,enq[0][0]))
+ webnotes.conn.sql("update `tabOpportunity` set status = %s where name=%s",(flag,enq[0][0]))
- def update_prevdoc_status(self, flag):
- for d in getlist(self.doclist, 'sales_order_details'):
- if d.prevdoc_docname:
- if flag=='submit':
- sql("update `tabQuotation` set status = 'Order Confirmed' where name=%s",d.prevdoc_docname)
-
- #update enquiry
- self.update_enquiry_status(d.prevdoc_docname, 'Order Confirmed')
- elif flag == 'cancel':
- chk = sql("select t1.name from `tabSales Order` t1, `tabSales Order Item` t2 where t2.parent = t1.name and t2.prevdoc_docname=%s and t1.name!=%s and t1.docstatus=1", (d.prevdoc_docname,self.doc.name))
- if not chk:
- sql("update `tabQuotation` set status = 'Submitted' where name=%s",d.prevdoc_docname)
-
- #update enquiry
- self.update_enquiry_status(d.prevdoc_docname, 'Quotation Sent')
+ def update_prevdoc_status(self, flag):
+ for quotation in self.doclist.get_distinct_values("prevdoc_docname"):
+ bean = webnotes.bean("Quotation", quotation)
+ if bean.doc.docstatus==2:
+ webnotes.throw(d.prevdoc_docname + ": " + webnotes._("Quotation is cancelled."))
+
+ bean.get_controller().set_status(update=True)
def on_submit(self):
- self.check_prev_docstatus()
self.update_stock_ledger(update_stock = 1)
get_obj('Sales Common').check_credit(self,self.doc.grand_total)
@@ -220,35 +200,35 @@
def check_nextdoc_docstatus(self):
# Checks Delivery Note
- submit_dn = sql("select t1.name from `tabDelivery Note` t1,`tabDelivery Note Item` t2 where t1.name = t2.parent and t2.prevdoc_docname = '%s' and t1.docstatus = 1" % (self.doc.name))
+ submit_dn = webnotes.conn.sql("select t1.name from `tabDelivery Note` t1,`tabDelivery Note Item` t2 where t1.name = t2.parent and t2.against_sales_order = %s and t1.docstatus = 1", self.doc.name)
if submit_dn:
msgprint("Delivery Note : " + cstr(submit_dn[0][0]) + " has been submitted against " + cstr(self.doc.doctype) + ". Please cancel Delivery Note : " + cstr(submit_dn[0][0]) + " first and then cancel "+ cstr(self.doc.doctype), raise_exception = 1)
# Checks Sales Invoice
- submit_rv = sql("select t1.name from `tabSales Invoice` t1,`tabSales Invoice Item` t2 where t1.name = t2.parent and t2.sales_order = '%s' and t1.docstatus = 1" % (self.doc.name))
+ submit_rv = webnotes.conn.sql("select t1.name from `tabSales Invoice` t1,`tabSales Invoice Item` t2 where t1.name = t2.parent and t2.sales_order = '%s' and t1.docstatus = 1" % (self.doc.name))
if submit_rv:
msgprint("Sales Invoice : " + cstr(submit_rv[0][0]) + " has already been submitted against " +cstr(self.doc.doctype)+ ". Please cancel Sales Invoice : "+ cstr(submit_rv[0][0]) + " first and then cancel "+ cstr(self.doc.doctype), raise_exception = 1)
#check maintenance schedule
- submit_ms = sql("select t1.name from `tabMaintenance Schedule` t1, `tabMaintenance Schedule Item` t2 where t2.parent=t1.name and t2.prevdoc_docname = %s and t1.docstatus = 1",self.doc.name)
+ submit_ms = webnotes.conn.sql("select t1.name from `tabMaintenance Schedule` t1, `tabMaintenance Schedule Item` t2 where t2.parent=t1.name and t2.prevdoc_docname = %s and t1.docstatus = 1",self.doc.name)
if submit_ms:
msgprint("Maintenance Schedule : " + cstr(submit_ms[0][0]) + " has already been submitted against " +cstr(self.doc.doctype)+ ". Please cancel Maintenance Schedule : "+ cstr(submit_ms[0][0]) + " first and then cancel "+ cstr(self.doc.doctype), raise_exception = 1)
# check maintenance visit
- submit_mv = sql("select t1.name from `tabMaintenance Visit` t1, `tabMaintenance Visit Purpose` t2 where t2.parent=t1.name and t2.prevdoc_docname = %s and t1.docstatus = 1",self.doc.name)
+ submit_mv = webnotes.conn.sql("select t1.name from `tabMaintenance Visit` t1, `tabMaintenance Visit Purpose` t2 where t2.parent=t1.name and t2.prevdoc_docname = %s and t1.docstatus = 1",self.doc.name)
if submit_mv:
msgprint("Maintenance Visit : " + cstr(submit_mv[0][0]) + " has already been submitted against " +cstr(self.doc.doctype)+ ". Please cancel Maintenance Visit : " + cstr(submit_mv[0][0]) + " first and then cancel "+ cstr(self.doc.doctype), raise_exception = 1)
# check production order
- pro_order = sql("""select name from `tabProduction Order` where sales_order = %s and docstatus = 1""", self.doc.name)
+ pro_order = webnotes.conn.sql("""select name from `tabProduction Order` where sales_order = %s and docstatus = 1""", self.doc.name)
if pro_order:
msgprint("""Production Order: %s exists against this sales order.
Please cancel production order first and then cancel this sales order""" %
pro_order[0][0], raise_exception=1)
def check_modified_date(self):
- mod_db = sql("select modified from `tabSales Order` where name = '%s'" % self.doc.name)
- date_diff = sql("select TIMEDIFF('%s', '%s')" % ( mod_db[0][0],cstr(self.doc.modified)))
+ mod_db = webnotes.conn.sql("select modified from `tabSales Order` where name = '%s'" % self.doc.name)
+ date_diff = webnotes.conn.sql("select TIMEDIFF('%s', '%s')" % ( mod_db[0][0],cstr(self.doc.modified)))
if date_diff and date_diff[0][0]:
msgprint("%s: %s has been modified after you have opened. Please Refresh"
% (self.doc.doctype, self.doc.name), raise_exception=1)
@@ -343,8 +323,7 @@
"field_map": {
"export_rate": "export_rate",
"name": "prevdoc_detail_docname",
- "parent": "prevdoc_docname",
- "parenttype": "prevdoc_doctype",
+ "parent": "against_sales_order",
"reserved_warehouse": "warehouse"
},
"postprocess": update_item,
diff --git a/selling/doctype/sales_order/sales_order.txt b/selling/doctype/sales_order/sales_order.txt
index 46a06b5..c27f8ff 100644
--- a/selling/doctype/sales_order/sales_order.txt
+++ b/selling/doctype/sales_order/sales_order.txt
@@ -8,6 +8,7 @@
},
{
"allow_attach": 1,
+ "allow_import": 1,
"autoname": "naming_series:",
"doctype": "DocType",
"document_type": "Transaction",
diff --git a/selling/doctype/sales_order/test_sales_order.py b/selling/doctype/sales_order/test_sales_order.py
index 7b72271..8bd759a 100644
--- a/selling/doctype/sales_order/test_sales_order.py
+++ b/selling/doctype/sales_order/test_sales_order.py
@@ -74,8 +74,7 @@
from stock.doctype.delivery_note.test_delivery_note import test_records as dn_test_records
dn = webnotes.bean(webnotes.copy_doclist(dn_test_records[0]))
dn.doclist[1].item_code = so.doclist[1].item_code
- dn.doclist[1].prevdoc_doctype = "Sales Order"
- dn.doclist[1].prevdoc_docname = so.doc.name
+ dn.doclist[1].against_sales_order = so.doc.name
dn.doclist[1].prevdoc_detail_docname = so.doclist[1].name
if delivered_qty:
dn.doclist[1].qty = delivered_qty
diff --git a/selling/doctype/sms_center/sms_center.py b/selling/doctype/sms_center/sms_center.py
index 29e793c..eb331c20 100644
--- a/selling/doctype/sms_center/sms_center.py
+++ b/selling/doctype/sms_center/sms_center.py
@@ -10,7 +10,6 @@
from webnotes.model.code import get_obj
from webnotes import msgprint
-sql = webnotes.conn.sql
# ----------
@@ -29,15 +28,15 @@
where_clause = self.doc.sales_partner and " and ifnull(is_sales_partner, 0) = 1 and sales_partner = '%s'" % self.doc.sales_partner or " and ifnull(sales_partner, '') != ''"
if self.doc.send_to in ['All Contact', 'All Customer Contact', 'All Supplier Contact', 'All Sales Partner Contact']:
- rec = sql("select CONCAT(ifnull(first_name,''),'',ifnull(last_name,'')), mobile_no from `tabContact` where ifnull(mobile_no,'')!='' and docstatus != 2 %s" % where_clause)
+ rec = webnotes.conn.sql("select CONCAT(ifnull(first_name,''),'',ifnull(last_name,'')), mobile_no from `tabContact` where ifnull(mobile_no,'')!='' and docstatus != 2 %s" % where_clause)
elif self.doc.send_to == 'All Lead (Open)':
- rec = sql("select lead_name, mobile_no from tabLead where ifnull(mobile_no,'')!='' and docstatus != 2 and status = 'Open'")
+ rec = webnotes.conn.sql("select lead_name, mobile_no from tabLead where ifnull(mobile_no,'')!='' and docstatus != 2 and status = 'Open'")
elif self.doc.send_to == 'All Employee (Active)':
where_clause = self.doc.department and " and department = '%s'" % self.doc.department or ""
where_clause += self.doc.branch and " and branch = '%s'" % self.doc.branch or ""
- rec = sql("select employee_name, cell_number from `tabEmployee` where status = 'Active' and docstatus < 2 and ifnull(cell_number,'')!='' %s" % where_clause)
+ rec = webnotes.conn.sql("select employee_name, cell_number from `tabEmployee` where status = 'Active' and docstatus < 2 and ifnull(cell_number,'')!='' %s" % where_clause)
elif self.doc.send_to == 'All Sales Person':
- rec = sql("select sales_person_name, mobile_no from `tabSales Person` where docstatus != 2 and ifnull(mobile_no,'')!=''")
+ rec = webnotes.conn.sql("select sales_person_name, mobile_no from `tabSales Person` where docstatus != 2 and ifnull(mobile_no,'')!=''")
rec_list = ''
for d in rec:
rec_list += d[0] + ' - ' + d[1] + '\n'
diff --git a/selling/page/sales_funnel/__init__.py b/selling/page/sales_funnel/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/selling/page/sales_funnel/__init__.py
diff --git a/selling/page/sales_funnel/sales_funnel.css b/selling/page/sales_funnel/sales_funnel.css
new file mode 100644
index 0000000..89e904f
--- /dev/null
+++ b/selling/page/sales_funnel/sales_funnel.css
@@ -0,0 +1,3 @@
+.funnel-wrapper {
+ margin: 15px;
+}
\ No newline at end of file
diff --git a/selling/page/sales_funnel/sales_funnel.js b/selling/page/sales_funnel/sales_funnel.js
new file mode 100644
index 0000000..e2c3a98
--- /dev/null
+++ b/selling/page/sales_funnel/sales_funnel.js
@@ -0,0 +1,189 @@
+// Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
+// License: GNU General Public License v3. See license.txt
+
+wn.pages['sales-funnel'].onload = function(wrapper) {
+ wn.ui.make_app_page({
+ parent: wrapper,
+ title: 'Sales Funnel',
+ single_column: true
+ });
+
+ wrapper.crm_funnel = new erpnext.CRMFunnel(wrapper);
+
+ wrapper.appframe.add_module_icon("Selling", "sales-funnel", function() {
+ wn.set_route("selling-home");
+ });
+}
+
+erpnext.CRMFunnel = Class.extend({
+ init: function(wrapper) {
+ var me = this;
+ // 0 setTimeout hack - this gives time for canvas to get width and height
+ setTimeout(function() {
+ me.setup(wrapper);
+ me.get_data();
+ }, 0);
+ },
+
+ setup: function(wrapper) {
+ var me = this;
+
+ this.elements = {
+ layout: $(wrapper).find(".layout-main"),
+ from_date: wrapper.appframe.add_date("From Date"),
+ to_date: wrapper.appframe.add_date("To Date"),
+ refresh_btn: wrapper.appframe.add_button("Refresh",
+ function() { me.get_data(); }, "icon-refresh"),
+ };
+
+ this.elements.no_data = $('<div class="alert alert-warning">No Data</div>')
+ .toggle(false)
+ .appendTo(this.elements.layout);
+
+ this.elements.funnel_wrapper = $('<div class="funnel-wrapper text-center"></div>')
+ .appendTo(this.elements.layout);
+
+ this.options = {
+ from_date: wn.datetime.add_months(wn.datetime.get_today(), -1),
+ to_date: wn.datetime.get_today()
+ };
+
+ // set defaults and bind on change
+ $.each(this.options, function(k, v) {
+ me.elements[k].val(wn.datetime.str_to_user(v));
+ me.elements[k].on("change", function() {
+ me.options[k] = wn.datetime.user_to_str($(this).val());
+ me.get_data();
+ });
+ });
+
+ // bind refresh
+ this.elements.refresh_btn.on("click", function() {
+ me.get_data(this);
+ });
+
+ // bind resize
+ $(window).resize(function() {
+ me.render();
+ });
+ },
+
+ get_data: function(btn) {
+ var me = this;
+ wn.call({
+ module: "selling",
+ page: "crm_funnel",
+ method: "get_funnel_data",
+ args: {
+ from_date: this.options.from_date,
+ to_date: this.options.to_date
+ },
+ btn: btn,
+ callback: function(r) {
+ if(!r.exc) {
+ me.options.data = r.message;
+ me.render();
+ }
+ }
+ });
+ },
+
+ render: function() {
+ var me = this;
+ this.prepare();
+
+ var context = this.elements.context,
+ x_start = 0.0,
+ x_end = this.options.width,
+ x_mid = (x_end - x_start) / 2.0,
+ y = 0,
+ y_old = 0.0;
+
+ if(this.options.total_value === 0) {
+ this.elements.no_data.toggle(true);
+ return;
+ }
+
+ this.options.data.forEach(function(d) {
+ context.fillStyle = d.color;
+ context.strokeStyle = d.color;
+ me.draw_triangle(x_start, x_mid, x_end, y, me.options.height);
+
+ y_old = y;
+
+ // new y
+ y = y + d.height;
+
+ // new x
+ var half_side = (me.options.height - y) / Math.sqrt(3);
+ x_start = x_mid - half_side;
+ x_end = x_mid + half_side;
+
+ var y_mid = y_old + (y - y_old) / 2.0;
+
+ me.draw_legend(x_mid, y_mid, me.options.width, me.options.height, d.value + " - " + d.title);
+ });
+ },
+
+ prepare: function() {
+ var me = this;
+
+ this.elements.no_data.toggle(false);
+
+ // calculate width and height options
+ this.options.width = $(this.elements.funnel_wrapper).width() * 2.0 / 3.0;
+ this.options.height = (Math.sqrt(3) * this.options.width) / 2.0;
+
+ // calculate total weightage
+ // as height decreases, area decreases by the square of the reduction
+ // hence, compensating by squaring the index value
+ this.options.total_weightage = this.options.data.reduce(
+ function(prev, curr, i) { return prev + Math.pow(i+1, 2) * curr.value; }, 0.0);
+
+ // calculate height for each data
+ $.each(this.options.data, function(i, d) {
+ d.height = me.options.height * d.value * Math.pow(i+1, 2) / me.options.total_weightage;
+ });
+
+ this.elements.canvas = $('<canvas></canvas>')
+ .appendTo(this.elements.funnel_wrapper.empty())
+ .attr("width", $(this.elements.funnel_wrapper).width())
+ .attr("height", this.options.height);
+
+ this.elements.context = this.elements.canvas.get(0).getContext("2d");
+ },
+
+ draw_triangle: function(x_start, x_mid, x_end, y, height) {
+ var context = this.elements.context;
+ context.beginPath();
+ context.moveTo(x_start, y);
+ context.lineTo(x_end, y);
+ context.lineTo(x_mid, height);
+ context.lineTo(x_start, y);
+ context.closePath();
+ context.fill();
+ },
+
+ draw_legend: function(x_mid, y_mid, width, height, title) {
+ var context = this.elements.context;
+
+ // draw line
+ context.beginPath();
+ context.moveTo(x_mid, y_mid);
+ context.lineTo(width, y_mid);
+ context.closePath();
+ context.stroke();
+
+ // draw circle
+ context.beginPath();
+ context.arc(width, y_mid, 5, 0, Math.PI * 2, false);
+ context.closePath();
+ context.fill();
+
+ // draw text
+ context.fillStyle = "black";
+ context.textBaseline = "middle";
+ context.font = "1.1em sans-serif";
+ context.fillText(title, width + 20, y_mid);
+ }
+});
\ No newline at end of file
diff --git a/selling/page/sales_funnel/sales_funnel.py b/selling/page/sales_funnel/sales_funnel.py
new file mode 100644
index 0000000..be0aebe
--- /dev/null
+++ b/selling/page/sales_funnel/sales_funnel.py
@@ -0,0 +1,33 @@
+# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+import webnotes
+
+@webnotes.whitelist()
+def get_funnel_data(from_date, to_date):
+ active_leads = webnotes.conn.sql("""select count(*) from `tabLead`
+ where (`modified` between %s and %s)
+ and status != "Do Not Contact" """, (from_date, to_date))[0][0]
+
+ active_leads += webnotes.conn.sql("""select count(distinct customer) from `tabContact`
+ where (`modified` between %s and %s)
+ and status != "Passive" """, (from_date, to_date))[0][0]
+
+ opportunities = webnotes.conn.sql("""select count(*) from `tabOpportunity`
+ where docstatus = 1 and (`modified` between %s and %s)
+ and status != "Lost" """, (from_date, to_date))[0][0]
+
+ quotations = webnotes.conn.sql("""select count(*) from `tabQuotation`
+ where docstatus = 1 and (`modified` between %s and %s)
+ and status != "Lost" """, (from_date, to_date))[0][0]
+
+ sales_orders = webnotes.conn.sql("""select count(*) from `tabQuotation`
+ where docstatus = 1 and (`modified` between %s and %s)""", (from_date, to_date))[0][0]
+
+ return [
+ { "title": "Active Leads / Customers", "value": active_leads, "color": "#B03B46" },
+ { "title": "Opportunities", "value": opportunities, "color": "#F09C00" },
+ { "title": "Quotations", "value": quotations, "color": "#006685" },
+ { "title": "Sales Orders", "value": sales_orders, "color": "#00AD65" }
+ ]
diff --git a/selling/page/sales_funnel/sales_funnel.txt b/selling/page/sales_funnel/sales_funnel.txt
new file mode 100644
index 0000000..b841f20
--- /dev/null
+++ b/selling/page/sales_funnel/sales_funnel.txt
@@ -0,0 +1,33 @@
+[
+ {
+ "creation": "2013-10-04 13:17:18",
+ "docstatus": 0,
+ "modified": "2013-10-04 13:17:18",
+ "modified_by": "Administrator",
+ "owner": "Administrator"
+ },
+ {
+ "doctype": "Page",
+ "icon": "icon-filter",
+ "module": "Selling",
+ "name": "__common__",
+ "page_name": "sales-funnel",
+ "standard": "Yes",
+ "title": "Sales Funnel"
+ },
+ {
+ "doctype": "Page Role",
+ "name": "__common__",
+ "parent": "sales-funnel",
+ "parentfield": "roles",
+ "parenttype": "Page",
+ "role": "Sales Manager"
+ },
+ {
+ "doctype": "Page",
+ "name": "sales-funnel"
+ },
+ {
+ "doctype": "Page Role"
+ }
+]
\ No newline at end of file
diff --git a/selling/page/selling_home/selling_home.js b/selling/page/selling_home/selling_home.js
index 9697ccf..5dd33e6 100644
--- a/selling/page/selling_home/selling_home.js
+++ b/selling/page/selling_home/selling_home.js
@@ -155,6 +155,10 @@
"label":wn._("Sales Analytics"),
page: "sales-analytics"
},
+ {
+ "label":wn._("Sales Funnel"),
+ page: "sales-funnel"
+ },
]
},
{
diff --git a/selling/utils/cart.py b/selling/utils/cart.py
index 7e7fb2e..e48059d 100644
--- a/selling/utils/cart.py
+++ b/selling/utils/cart.py
@@ -12,8 +12,8 @@
def set_cart_count(quotation=None):
if not quotation:
quotation = _get_cart_quotation()
- webnotes.add_cookies["cart_count"] = cstr(len(quotation.doclist.get(
- {"parentfield": "quotation_details"})) or "")
+ cart_count = cstr(len(quotation.doclist.get({"parentfield": "quotation_details"})))
+ webnotes._response.set_cookie("cart_count", cart_count)
@webnotes.whitelist()
def get_cart_quotation(doclist=None):
@@ -47,7 +47,7 @@
sales_order.ignore_permissions = True
sales_order.insert()
sales_order.submit()
- webnotes.add_cookies["cart_count"] = ""
+ webnotes._response.set_cookie("cart_count", "")
return sales_order.doc.name
diff --git a/setup/doctype/authorization_control/authorization_control.py b/setup/doctype/authorization_control/authorization_control.py
index ddf0791..533f398 100644
--- a/setup/doctype/authorization_control/authorization_control.py
+++ b/setup/doctype/authorization_control/authorization_control.py
@@ -9,7 +9,6 @@
from webnotes import session, msgprint
from setup.utils import get_company_currency
-sql = webnotes.conn.sql
from utilities.transaction_base import TransactionBase
@@ -28,10 +27,10 @@
amt_list.append(flt(x[0]))
max_amount = max(amt_list)
- app_dtl = sql("select approving_user, approving_role from `tabAuthorization Rule` where transaction = %s and (value = %s or value > %s) and docstatus != 2 and based_on = %s and company = %s %s" % ('%s', '%s', '%s', '%s', '%s', condition), (doctype_name, flt(max_amount), total, based_on, company))
+ app_dtl = webnotes.conn.sql("select approving_user, approving_role from `tabAuthorization Rule` where transaction = %s and (value = %s or value > %s) and docstatus != 2 and based_on = %s and company = %s %s" % ('%s', '%s', '%s', '%s', '%s', condition), (doctype_name, flt(max_amount), total, based_on, company))
if not app_dtl:
- app_dtl = sql("select approving_user, approving_role from `tabAuthorization Rule` where transaction = %s and (value = %s or value > %s) and docstatus != 2 and based_on = %s and ifnull(company,'') = '' %s" % ('%s', '%s', '%s', '%s', condition), (doctype_name, flt(max_amount), total, based_on))
+ app_dtl = webnotes.conn.sql("select approving_user, approving_role from `tabAuthorization Rule` where transaction = %s and (value = %s or value > %s) and docstatus != 2 and based_on = %s and ifnull(company,'') = '' %s" % ('%s', '%s', '%s', '%s', condition), (doctype_name, flt(max_amount), total, based_on))
for d in app_dtl:
if(d[0]): appr_users.append(d[0])
if(d[1]): appr_roles.append(d[1])
@@ -58,18 +57,18 @@
add_cond1,add_cond2 = '',''
if based_on == 'Itemwise Discount':
add_cond1 += " and master_name = '"+cstr(item)+"'"
- itemwise_exists = sql("select value from `tabAuthorization Rule` where transaction = %s and value <= %s and based_on = %s and company = %s and docstatus != 2 %s %s" % ('%s', '%s', '%s', '%s', cond, add_cond1), (doctype_name, total, based_on, company))
+ itemwise_exists = webnotes.conn.sql("select value from `tabAuthorization Rule` where transaction = %s and value <= %s and based_on = %s and company = %s and docstatus != 2 %s %s" % ('%s', '%s', '%s', '%s', cond, add_cond1), (doctype_name, total, based_on, company))
if not itemwise_exists:
- itemwise_exists = sql("select value from `tabAuthorization Rule` where transaction = %s and value <= %s and based_on = %s and ifnull(company,'') = '' and docstatus != 2 %s %s" % ('%s', '%s', '%s', cond, add_cond1), (doctype_name, total, based_on))
+ itemwise_exists = webnotes.conn.sql("select value from `tabAuthorization Rule` where transaction = %s and value <= %s and based_on = %s and ifnull(company,'') = '' and docstatus != 2 %s %s" % ('%s', '%s', '%s', cond, add_cond1), (doctype_name, total, based_on))
if itemwise_exists:
self.get_appr_user_role(itemwise_exists, doctype_name, total, based_on, cond+add_cond1, item,company)
chk = 0
if chk == 1:
if based_on == 'Itemwise Discount': add_cond2 += " and ifnull(master_name,'') = ''"
- appr = sql("select value from `tabAuthorization Rule` where transaction = %s and value <= %s and based_on = %s and company = %s and docstatus != 2 %s %s" % ('%s', '%s', '%s', '%s', cond, add_cond2), (doctype_name, total, based_on, company))
+ appr = webnotes.conn.sql("select value from `tabAuthorization Rule` where transaction = %s and value <= %s and based_on = %s and company = %s and docstatus != 2 %s %s" % ('%s', '%s', '%s', '%s', cond, add_cond2), (doctype_name, total, based_on, company))
if not appr:
- appr = sql("select value from `tabAuthorization Rule` where transaction = %s and value <= %s and based_on = %s and ifnull(company,'') = '' and docstatus != 2 %s %s"% ('%s', '%s', '%s', cond, add_cond2), (doctype_name, total, based_on))
+ appr = webnotes.conn.sql("select value from `tabAuthorization Rule` where transaction = %s and value <= %s and based_on = %s and ifnull(company,'') = '' and docstatus != 2 %s %s"% ('%s', '%s', '%s', cond, add_cond2), (doctype_name, total, based_on))
self.get_appr_user_role(appr, doctype_name, total, based_on, cond+add_cond2, item, company)
@@ -112,7 +111,7 @@
# ================
# Check for authorization set for individual user
- based_on = [x[0] for x in sql("select distinct based_on from `tabAuthorization Rule` where transaction = %s and system_user = %s and (company = %s or ifnull(company,'')='') and docstatus != 2", (doctype_name, session['user'], company))]
+ based_on = [x[0] for x in webnotes.conn.sql("select distinct based_on from `tabAuthorization Rule` where transaction = %s and system_user = %s and (company = %s or ifnull(company,'')='') and docstatus != 2", (doctype_name, session['user'], company))]
for d in based_on:
self.bifurcate_based_on_type(doctype_name, total, av_dis, d, doc_obj, 1, company)
@@ -124,7 +123,7 @@
# Specific Role
# ===============
# Check for authorization set on particular roles
- based_on = [x[0] for x in sql("""select based_on
+ based_on = [x[0] for x in webnotes.conn.sql("""select based_on
from `tabAuthorization Rule`
where transaction = %s and system_role IN (%s) and based_on IN (%s)
and (company = %s or ifnull(company,'')='')
@@ -148,9 +147,9 @@
# payroll related check
def get_value_based_rule(self,doctype_name,employee,total_claimed_amount,company):
val_lst =[]
- val = sql("select value from `tabAuthorization Rule` where transaction=%s and (to_emp=%s or to_designation IN (select designation from `tabEmployee` where name=%s)) and ifnull(value,0)< %s and company = %s and docstatus!=2",(doctype_name,employee,employee,total_claimed_amount,company))
+ val = webnotes.conn.sql("select value from `tabAuthorization Rule` where transaction=%s and (to_emp=%s or to_designation IN (select designation from `tabEmployee` where name=%s)) and ifnull(value,0)< %s and company = %s and docstatus!=2",(doctype_name,employee,employee,total_claimed_amount,company))
if not val:
- val = sql("select value from `tabAuthorization Rule` where transaction=%s and (to_emp=%s or to_designation IN (select designation from `tabEmployee` where name=%s)) and ifnull(value,0)< %s and ifnull(company,'') = '' and docstatus!=2",(doctype_name, employee, employee, total_claimed_amount))
+ val = webnotes.conn.sql("select value from `tabAuthorization Rule` where transaction=%s and (to_emp=%s or to_designation IN (select designation from `tabEmployee` where name=%s)) and ifnull(value,0)< %s and ifnull(company,'') = '' and docstatus!=2",(doctype_name, employee, employee, total_claimed_amount))
if val:
val_lst = [y[0] for y in val]
@@ -158,9 +157,9 @@
val_lst.append(0)
max_val = max(val_lst)
- rule = sql("select name, to_emp, to_designation, approving_role, approving_user from `tabAuthorization Rule` where transaction=%s and company = %s and (to_emp=%s or to_designation IN (select designation from `tabEmployee` where name=%s)) and ifnull(value,0)= %s and docstatus!=2",(doctype_name,company,employee,employee,flt(max_val)), as_dict=1)
+ rule = webnotes.conn.sql("select name, to_emp, to_designation, approving_role, approving_user from `tabAuthorization Rule` where transaction=%s and company = %s and (to_emp=%s or to_designation IN (select designation from `tabEmployee` where name=%s)) and ifnull(value,0)= %s and docstatus!=2",(doctype_name,company,employee,employee,flt(max_val)), as_dict=1)
if not rule:
- rule = sql("select name, to_emp, to_designation, approving_role, approving_user from `tabAuthorization Rule` where transaction=%s and ifnull(company,'') = '' and (to_emp=%s or to_designation IN (select designation from `tabEmployee` where name=%s)) and ifnull(value,0)= %s and docstatus!=2",(doctype_name,employee,employee,flt(max_val)), as_dict=1)
+ rule = webnotes.conn.sql("select name, to_emp, to_designation, approving_role, approving_user from `tabAuthorization Rule` where transaction=%s and ifnull(company,'') = '' and (to_emp=%s or to_designation IN (select designation from `tabEmployee` where name=%s)) and ifnull(value,0)= %s and docstatus!=2",(doctype_name,employee,employee,flt(max_val)), as_dict=1)
return rule
@@ -175,9 +174,9 @@
if doctype_name == 'Expense Claim':
rule = self.get_value_based_rule(doctype_name,doc_obj.doc.employee,doc_obj.doc.total_claimed_amount, doc_obj.doc.company)
elif doctype_name == 'Appraisal':
- rule = sql("select name, to_emp, to_designation, approving_role, approving_user from `tabAuthorization Rule` where transaction=%s and (to_emp=%s or to_designation IN (select designation from `tabEmployee` where name=%s)) and company = %s and docstatus!=2",(doctype_name,doc_obj.doc.employee, doc_obj.doc.employee, doc_obj.doc.company),as_dict=1)
+ rule = webnotes.conn.sql("select name, to_emp, to_designation, approving_role, approving_user from `tabAuthorization Rule` where transaction=%s and (to_emp=%s or to_designation IN (select designation from `tabEmployee` where name=%s)) and company = %s and docstatus!=2",(doctype_name,doc_obj.doc.employee, doc_obj.doc.employee, doc_obj.doc.company),as_dict=1)
if not rule:
- rule = sql("select name, to_emp, to_designation, approving_role, approving_user from `tabAuthorization Rule` where transaction=%s and (to_emp=%s or to_designation IN (select designation from `tabEmployee` where name=%s)) and ifnull(company,'') = '' and docstatus!=2",(doctype_name,doc_obj.doc.employee, doc_obj.doc.employee),as_dict=1)
+ rule = webnotes.conn.sql("select name, to_emp, to_designation, approving_role, approving_user from `tabAuthorization Rule` where transaction=%s and (to_emp=%s or to_designation IN (select designation from `tabEmployee` where name=%s)) and ifnull(company,'') = '' and docstatus!=2",(doctype_name,doc_obj.doc.employee, doc_obj.doc.employee),as_dict=1)
if rule:
for m in rule:
@@ -185,7 +184,7 @@
if m['approving_user']:
app_specific_user.append(m['approving_user'])
elif m['approving_role']:
- user_lst = [z[0] for z in sql("select distinct t1.name from `tabProfile` t1, `tabUserRole` t2 where t2.role=%s and t2.parent=t1.name and t1.name !='Administrator' and t1.name != 'Guest' and t1.docstatus !=2",m['approving_role'])]
+ user_lst = [z[0] for z in webnotes.conn.sql("select distinct t1.name from `tabProfile` t1, `tabUserRole` t2 where t2.role=%s and t2.parent=t1.name and t1.name !='Administrator' and t1.name != 'Guest' and t1.docstatus !=2",m['approving_role'])]
for x in user_lst:
if not x in app_user:
app_user.append(x)
diff --git a/setup/doctype/authorization_rule/authorization_rule.py b/setup/doctype/authorization_rule/authorization_rule.py
index 3d2de47..ea22b15 100644
--- a/setup/doctype/authorization_rule/authorization_rule.py
+++ b/setup/doctype/authorization_rule/authorization_rule.py
@@ -9,7 +9,6 @@
from webnotes.model.bean import copy_doclist
from webnotes import msgprint
-sql = webnotes.conn.sql
@@ -19,7 +18,7 @@
def check_duplicate_entry(self):
- exists = sql("""select name, docstatus from `tabAuthorization Rule`
+ exists = webnotes.conn.sql("""select name, docstatus from `tabAuthorization Rule`
where transaction = %s and based_on = %s and system_user = %s
and system_role = %s and approving_user = %s and approving_role = %s
and to_emp =%s and to_designation=%s and name != %s""",
@@ -39,12 +38,12 @@
def validate_master_name(self):
if self.doc.based_on == 'Customerwise Discount' and \
- not sql("select name from tabCustomer where name = '%s' and docstatus != 2" % \
+ not webnotes.conn.sql("select name from tabCustomer where name = '%s' and docstatus != 2" % \
(self.doc.master_name)):
msgprint("Please select valid Customer Name for Customerwise Discount",
raise_exception=1)
elif self.doc.based_on == 'Itemwise Discount' and \
- not sql("select name from tabItem where name = '%s' and docstatus != 2" % \
+ not webnotes.conn.sql("select name from tabItem where name = '%s' and docstatus != 2" % \
(self.doc.master_name)):
msgprint("Please select valid Item Name for Itemwise Discount", raise_exception=1)
elif (self.doc.based_on == 'Grand Total' or \
@@ -65,7 +64,7 @@
Applicable To (Role).", raise_exception=1)
elif self.doc.system_user and self.doc.approving_role and \
has_common([self.doc.approving_role], [x[0] for x in \
- sql("select role from `tabUserRole` where parent = '%s'" % \
+ webnotes.conn.sql("select role from `tabUserRole` where parent = '%s'" % \
(self.doc.system_user))]):
msgprint("System User : %s is assigned role : %s. So rule does not make sense" %
(self.doc.system_user,self.doc.approving_role), raise_exception=1)
diff --git a/setup/doctype/backup_manager/backup_dropbox.py b/setup/doctype/backup_manager/backup_dropbox.py
index b4a8f66..3d3f428 100644
--- a/setup/doctype/backup_manager/backup_dropbox.py
+++ b/setup/doctype/backup_manager/backup_dropbox.py
@@ -61,8 +61,8 @@
allowed = 0
message = "Dropbox Access not approved."
- webnotes.message_title = "Dropbox Approval"
- webnotes.message = "<h3>%s</h3><p>Please close this window.</p>" % message
+ webnotes.local.message_title = "Dropbox Approval"
+ webnotes.local.message = "<h3>%s</h3><p>Please close this window.</p>" % message
webnotes.conn.commit()
webnotes.response['type'] = 'page'
diff --git a/setup/doctype/backup_manager/backup_googledrive.py b/setup/doctype/backup_manager/backup_googledrive.py
index 440d907..c72295a 100644
--- a/setup/doctype/backup_manager/backup_googledrive.py
+++ b/setup/doctype/backup_manager/backup_googledrive.py
@@ -114,9 +114,9 @@
def get_gdrive_flow():
from oauth2client.client import OAuth2WebServerFlow
- import conf
+ from webnotes import conf
- if not hasattr(conf, "gdrive_client_id"):
+ if not "gdrive_client_id" in conf:
webnotes.msgprint(_("Please set Google Drive access keys in") + " conf.py",
raise_exception=True)
@@ -170,4 +170,4 @@
return database['id']
if __name__=="__main__":
- backup_to_gdrive()
\ No newline at end of file
+ backup_to_gdrive()
diff --git a/setup/doctype/company/company.py b/setup/doctype/company/company.py
index 9746eb2..da220cc 100644
--- a/setup/doctype/company/company.py
+++ b/setup/doctype/company/company.py
@@ -10,7 +10,6 @@
from webnotes.model.code import get_obj
import webnotes.defaults
-sql = webnotes.conn.sql
class DocType:
def __init__(self,d,dl):
diff --git a/setup/doctype/company/company.txt b/setup/doctype/company/company.txt
index 1ba1dde..eb6b9ad 100644
--- a/setup/doctype/company/company.txt
+++ b/setup/doctype/company/company.txt
@@ -2,7 +2,7 @@
{
"creation": "2013-04-10 08:35:39",
"docstatus": 0,
- "modified": "2013-08-28 19:15:04",
+ "modified": "2013-10-08 15:18:34",
"modified_by": "Administrator",
"owner": "Administrator"
},
@@ -80,7 +80,7 @@
"fieldtype": "Select",
"label": "Domain",
"options": "Distribution\nManufacturing\nRetail\nServices",
- "reqd": 1
+ "reqd": 0
},
{
"doctype": "DocField",
diff --git a/setup/doctype/customer_group/customer_group.py b/setup/doctype/customer_group/customer_group.py
index 0940e1f..1264c1b 100644
--- a/setup/doctype/customer_group/customer_group.py
+++ b/setup/doctype/customer_group/customer_group.py
@@ -5,7 +5,6 @@
import webnotes
from webnotes import msgprint
-sql = webnotes.conn.sql
from webnotes.utils.nestedset import DocTypeNestedSet
class DocType(DocTypeNestedSet):
@@ -15,7 +14,7 @@
self.nsm_parent_field = 'parent_customer_group';
def validate(self):
- if sql("select name from `tabCustomer Group` where name = %s and docstatus = 2",
+ if webnotes.conn.sql("select name from `tabCustomer Group` where name = %s and docstatus = 2",
(self.doc.customer_group_name)):
msgprint("""Another %s record is trashed.
To untrash please go to Setup -> Recycle Bin.""" %
@@ -33,7 +32,7 @@
self.doc.name, raise_exception=1)
def on_trash(self):
- cust = sql("select name from `tabCustomer` where ifnull(customer_group, '') = %s",
+ cust = webnotes.conn.sql("select name from `tabCustomer` where ifnull(customer_group, '') = %s",
self.doc.name)
cust = [d[0] for d in cust]
if cust:
@@ -42,7 +41,7 @@
To trash/delete this, remove/change customer group in customer master""" %
(self.doc.name, cust or ''), raise_exception=1)
- if sql("select name from `tabCustomer Group` where parent_customer_group = %s \
+ if webnotes.conn.sql("select name from `tabCustomer Group` where parent_customer_group = %s \
and docstatus != 2", self.doc.name):
msgprint("Child customer group exists for this customer group. \
You can not trash/cancel/delete this customer group.", raise_exception=1)
diff --git a/setup/doctype/email_digest/email_digest.py b/setup/doctype/email_digest/email_digest.py
index 07efd16..9a00723 100644
--- a/setup/doctype/email_digest/email_digest.py
+++ b/setup/doctype/email_digest/email_digest.py
@@ -457,8 +457,8 @@
from webnotes.utils import getdate
now_date = now_datetime().date()
- import conf
- if hasattr(conf, "expires_on") and now_date > getdate(conf.expires_on):
+ from webnotes import conf
+ if "expires_on" in conf and now_date > getdate(conf.expires_on):
# do not send email digests to expired accounts
return
diff --git a/setup/doctype/email_settings/email_settings.py b/setup/doctype/email_settings/email_settings.py
index 219501e..aa511ee 100644
--- a/setup/doctype/email_settings/email_settings.py
+++ b/setup/doctype/email_settings/email_settings.py
@@ -3,7 +3,6 @@
from __future__ import unicode_literals
import webnotes
-sql = webnotes.conn.sql
from webnotes.utils import cint
diff --git a/setup/doctype/item_group/item_group.js b/setup/doctype/item_group/item_group.js
index 31edef2..0c18db0 100644
--- a/setup/doctype/item_group/item_group.js
+++ b/setup/doctype/item_group/item_group.js
@@ -7,6 +7,12 @@
cur_frm.add_custom_button("Item Group Tree", function() {
wn.set_route("Sales Browser", "Item Group");
})
+
+ if(!doc.__islocal && doc.show_in_website) {
+ cur_frm.add_custom_button("View In Website", function() {
+ window.open(doc.page_name);
+ }, "icon-globe");
+ }
}
cur_frm.cscript.set_root_readonly = function(doc) {
diff --git a/setup/doctype/naming_series/naming_series.py b/setup/doctype/naming_series/naming_series.py
index 9cc4de2..4e85b15 100644
--- a/setup/doctype/naming_series/naming_series.py
+++ b/setup/doctype/naming_series/naming_series.py
@@ -8,7 +8,6 @@
from webnotes import msgprint
import webnotes.model.doctype
-sql = webnotes.conn.sql
class DocType:
def __init__(self, d, dl):
@@ -23,7 +22,7 @@
where fieldname='naming_series'""")
)))),
"prefixes": "\n".join([''] + [i[0] for i in
- sql("""select name from tabSeries""")])
+ webnotes.conn.sql("""select name from tabSeries""")])
}
def scrub_options_list(self, ol):
@@ -126,12 +125,12 @@
def insert_series(self, series):
"""insert series if missing"""
if not webnotes.conn.exists('Series', series):
- sql("insert into tabSeries (name, current) values (%s,0)", (series))
+ webnotes.conn.sql("insert into tabSeries (name, current) values (%s,0)", (series))
def update_series_start(self):
if self.doc.prefix:
self.insert_series(self.doc.prefix)
- sql("update `tabSeries` set current = '%s' where name = '%s'" % (self.doc.current_value,self.doc.prefix))
+ webnotes.conn.sql("update `tabSeries` set current = '%s' where name = '%s'" % (self.doc.current_value,self.doc.prefix))
msgprint("Series Updated Successfully")
else:
msgprint("Please select prefix first")
diff --git a/setup/doctype/notification_control/notification_control.py b/setup/doctype/notification_control/notification_control.py
index 6133d9b..0a15115 100644
--- a/setup/doctype/notification_control/notification_control.py
+++ b/setup/doctype/notification_control/notification_control.py
@@ -6,7 +6,6 @@
from webnotes import msgprint
-sql = webnotes.conn.sql
class DocType:
def __init__(self,d,dl):
@@ -14,7 +13,7 @@
def get_message(self, arg):
fn = arg.lower().replace(' ', '_') + '_message'
- v = sql("select value from tabSingles where field=%s and doctype=%s", (fn, 'Notification Control'))
+ v = webnotes.conn.sql("select value from tabSingles where field=%s and doctype=%s", (fn, 'Notification Control'))
return v and v[0][0] or ''
def set_message(self, arg = ''):
diff --git a/setup/doctype/print_heading/print_heading.py b/setup/doctype/print_heading/print_heading.py
index ba7114a..134aaaf 100644
--- a/setup/doctype/print_heading/print_heading.py
+++ b/setup/doctype/print_heading/print_heading.py
@@ -7,7 +7,6 @@
from webnotes.model import db_exists
from webnotes.model.bean import copy_doclist
-sql = webnotes.conn.sql
diff --git a/setup/doctype/sales_partner/sales_partner.py b/setup/doctype/sales_partner/sales_partner.py
index 0d7e12d..9e3e2a8 100644
--- a/setup/doctype/sales_partner/sales_partner.py
+++ b/setup/doctype/sales_partner/sales_partner.py
@@ -5,13 +5,16 @@
import webnotes
from webnotes.utils import cint, cstr, filter_strip_join
-sql = webnotes.conn.sql
class DocType:
def __init__(self, doc, doclist=None):
self.doc = doc
self.doclist = doclist
+ def validate(self):
+ if self.doc.partner_website and not self.doc.partner_website.startswith("http"):
+ self.doc.partner_website = "http://" + self.doc.partner_website
+
def on_update(self):
if cint(self.doc.show_in_website):
from webnotes.webutils import update_page_name
@@ -24,7 +27,7 @@
def get_contacts(self,nm):
if nm:
- contact_details =webnotes.conn.convert_to_lists(sql("select name, CONCAT(IFNULL(first_name,''),' ',IFNULL(last_name,'')),contact_no,email_id from `tabContact` where sales_partner = '%s'"%nm))
+ contact_details =webnotes.conn.convert_to_lists(webnotes.conn.sql("select name, CONCAT(IFNULL(first_name,''),' ',IFNULL(last_name,'')),contact_no,email_id from `tabContact` where sales_partner = '%s'"%nm))
return contact_details
else:
return ''
diff --git a/setup/doctype/setup_control/README.md b/setup/doctype/setup_control/README.md
deleted file mode 100644
index 909fea4..0000000
--- a/setup/doctype/setup_control/README.md
+++ /dev/null
@@ -1 +0,0 @@
-Account setup utility on first login.
\ No newline at end of file
diff --git a/setup/doctype/setup_control/__init__.py b/setup/doctype/setup_control/__init__.py
deleted file mode 100644
index baffc48..0000000
--- a/setup/doctype/setup_control/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-from __future__ import unicode_literals
diff --git a/setup/doctype/setup_control/setup_control.py b/setup/doctype/setup_control/setup_control.py
deleted file mode 100644
index b78bfcc..0000000
--- a/setup/doctype/setup_control/setup_control.py
+++ /dev/null
@@ -1,255 +0,0 @@
-# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
-# License: GNU General Public License v3. See license.txt
-
-from __future__ import unicode_literals
-import webnotes
-
-from webnotes.utils import cint, cstr, getdate, now, nowdate, get_defaults
-from webnotes.model.doc import Document, addchild
-from webnotes.model.code import get_obj
-from webnotes import session, form, msgprint
-
-class DocType:
- def __init__(self, d, dl):
- self.doc, self.doclist = d, dl
-
- def setup_account(self, args):
- import webnotes, json
- if isinstance(args, basestring):
- args = json.loads(args)
- webnotes.conn.begin()
-
- self.update_profile_name(args)
- add_all_roles_to(webnotes.session.user)
- self.create_fiscal_year_and_company(args)
- self.set_defaults(args)
- create_territories()
- self.create_price_lists(args)
- self.create_feed_and_todo()
- self.create_email_digest()
-
- webnotes.clear_cache()
- msgprint("Company setup is complete. This page will be refreshed in a moment.")
- webnotes.conn.commit()
-
- return {
- 'sys_defaults': get_defaults(),
- 'user_fullname': (args.get('first_name') or '') + (args.get('last_name')
- and (" " + args.get('last_name')) or '')
- }
-
- def update_profile_name(self, args):
- args['name'] = webnotes.session.get('user')
-
- # Update Profile
- if not args.get('last_name') or args.get('last_name')=='None': args['last_name'] = None
- webnotes.conn.sql("""\
- UPDATE `tabProfile` SET first_name=%(first_name)s,
- last_name=%(last_name)s
- WHERE name=%(name)s AND docstatus<2""", args)
-
- def create_fiscal_year_and_company(self, args):
- curr_fiscal_year, fy_start_date, fy_abbr = self.get_fy_details(args.get('fy_start'), True)
- webnotes.bean([{
- "doctype":"Fiscal Year",
- 'year': curr_fiscal_year,
- 'year_start_date': fy_start_date
- }]).insert()
-
- curr_fiscal_year, fy_start_date, fy_abbr = self.get_fy_details(args.get('fy_start'))
- webnotes.bean([{
- "doctype":"Fiscal Year",
- 'year': curr_fiscal_year,
- 'year_start_date': fy_start_date,
- }]).insert()
-
-
- # Company
- webnotes.bean([{
- "doctype":"Company",
- 'domain': args.get("industry"),
- 'company_name':args.get('company_name'),
- 'abbr':args.get('company_abbr'),
- 'default_currency':args.get('currency'),
- }]).insert()
-
- self.curr_fiscal_year = curr_fiscal_year
-
- def create_price_lists(self, args):
- for pl_type in ["Selling", "Buying"]:
- webnotes.bean([
- {
- "doctype": "Price List",
- "price_list_name": "Standard " + pl_type,
- "buying_or_selling": pl_type,
- "currency": args["currency"]
- },
- {
- "doctype": "For Territory",
- "parentfield": "valid_for_territories",
- "territory": "All Territories"
- }
- ]).insert()
-
- def set_defaults(self, args):
- # enable default currency
- webnotes.conn.set_value("Currency", args.get("currency"), "enabled", 1)
-
- global_defaults = webnotes.bean("Global Defaults", "Global Defaults")
- global_defaults.doc.fields.update({
- 'current_fiscal_year': self.curr_fiscal_year,
- 'default_currency': args.get('currency'),
- 'default_company':args.get('company_name'),
- 'date_format': webnotes.conn.get_value("Country", args.get("country"), "date_format"),
- "float_precision": 4
- })
- global_defaults.save()
-
- accounts_settings = webnotes.bean("Accounts Settings")
- accounts_settings.doc.auto_accounting_for_stock = 1
- accounts_settings.save()
-
- stock_settings = webnotes.bean("Stock Settings")
- stock_settings.doc.item_naming_by = "Item Code"
- stock_settings.doc.valuation_method = "FIFO"
- stock_settings.doc.stock_uom = "Nos"
- stock_settings.doc.auto_indent = 1
- stock_settings.save()
-
- selling_settings = webnotes.bean("Selling Settings")
- selling_settings.doc.cust_master_name = "Customer Name"
- selling_settings.doc.so_required = "No"
- selling_settings.doc.dn_required = "No"
- selling_settings.save()
-
- buying_settings = webnotes.bean("Buying Settings")
- buying_settings.doc.supp_master_name = "Supplier Name"
- buying_settings.doc.po_required = "No"
- buying_settings.doc.pr_required = "No"
- buying_settings.doc.maintain_same_rate = 1
- buying_settings.save()
-
- notification_control = webnotes.bean("Notification Control")
- notification_control.doc.quotation = 1
- notification_control.doc.sales_invoice = 1
- notification_control.doc.purchase_order = 1
- notification_control.save()
-
- hr_settings = webnotes.bean("HR Settings")
- hr_settings.doc.emp_created_by = "Naming Series"
- hr_settings.save()
-
- # control panel
- cp = webnotes.doc("Control Panel", "Control Panel")
- for k in ['country', 'timezone', 'company_name']:
- cp.fields[k] = args[k]
-
- cp.save()
-
- def create_feed_and_todo(self):
- """update activty feed and create todo for creation of item, customer, vendor"""
- import home
- home.make_feed('Comment', 'ToDo', '', webnotes.session['user'],
- '<i>"' + 'Setup Complete. Please check your <a href="#!todo">\
- To Do List</a>' + '"</i>', '#6B24B3')
-
- d = Document('ToDo')
- d.description = '<a href="#Setup">Complete ERPNext Setup</a>'
- d.priority = 'High'
- d.date = nowdate()
- d.save(1)
-
- def create_email_digest(self):
- """
- create a default weekly email digest
- * Weekly Digest
- * For all companies
- * Recipients: System Managers
- * Full content
- * Enabled by default
- """
- import webnotes
- companies_list = webnotes.conn.sql("SELECT company_name FROM `tabCompany`", as_list=1)
-
- from webnotes.profile import get_system_managers
- system_managers = get_system_managers()
- if not system_managers: return
-
- from webnotes.model.doc import Document
- for company in companies_list:
- if company and company[0]:
- edigest = webnotes.bean({
- "doctype": "Email Digest",
- "name": "Default Weekly Digest - " + company[0],
- "company": company[0],
- "frequency": "Weekly",
- "recipient_list": "\n".join(system_managers)
- })
-
- if webnotes.conn.sql("""select name from `tabEmail Digest` where name=%s""", edigest.doc.name):
- continue
-
- for fieldname in edigest.meta.get_fieldnames({"fieldtype": "Check"}):
- edigest.doc.fields[fieldname] = 1
-
- edigest.insert()
-
- # Get Fiscal year Details
- # ------------------------
- def get_fy_details(self, fy_start, last_year=False):
- st = {'1st Jan':'01-01','1st Apr':'04-01','1st Jul':'07-01', '1st Oct': '10-01'}
- if cint(getdate(nowdate()).month) < cint((st[fy_start].split('-'))[0]):
- curr_year = getdate(nowdate()).year - 1
- else:
- curr_year = getdate(nowdate()).year
-
- if last_year:
- curr_year = curr_year - 1
-
- stdt = cstr(curr_year)+'-'+cstr(st[fy_start])
-
- if(fy_start == '1st Jan'):
- fy = cstr(curr_year)
- abbr = cstr(fy)[-2:]
- else:
- fy = cstr(curr_year) + '-' + cstr(curr_year+1)
- abbr = cstr(curr_year)[-2:] + '-' + cstr(curr_year+1)[-2:]
- return fy, stdt, abbr
-
- def create_profile(self, user_email, user_fname, user_lname, pwd=None):
- pr = Document('Profile')
- pr.first_name = user_fname
- pr.last_name = user_lname
- pr.name = pr.email = user_email
- pr.enabled = 1
- pr.save(1)
- if pwd:
- webnotes.conn.sql("""insert into __Auth (user, `password`)
- values (%s, password(%s))
- on duplicate key update `password`=password(%s)""",
- (user_email, pwd, pwd))
-
- add_all_roles_to(pr.name)
-
-def add_all_roles_to(name):
- profile = webnotes.doc("Profile", name)
- for role in webnotes.conn.sql("""select name from tabRole"""):
- if role[0] not in ["Administrator", "Guest", "All", "Customer", "Supplier", "Partner"]:
- d = profile.addchild("user_roles", "UserRole")
- d.role = role[0]
- d.insert()
-
-def create_territories():
- """create two default territories, one for home country and one named Rest of the World"""
- from setup.utils import get_root_of
- country = webnotes.conn.get_value("Control Panel", None, "country")
- root_territory = get_root_of("Territory")
- for name in (country, "Rest Of The World"):
- if name and not webnotes.conn.exists("Territory", name):
- webnotes.bean({
- "doctype": "Territory",
- "territory_name": name.replace("'", ""),
- "parent_territory": root_territory,
- "is_group": "No"
- }).insert()
-
diff --git a/setup/doctype/setup_control/setup_control.txt b/setup/doctype/setup_control/setup_control.txt
deleted file mode 100644
index 7ebed3e..0000000
--- a/setup/doctype/setup_control/setup_control.txt
+++ /dev/null
@@ -1,24 +0,0 @@
-[
- {
- "creation": "2012-03-27 14:36:25",
- "docstatus": 0,
- "modified": "2012-03-27 14:36:25",
- "modified_by": "Administrator",
- "owner": "Administrator"
- },
- {
- "doctype": "DocType",
- "in_create": 1,
- "issingle": 1,
- "istable": 0,
- "module": "Setup",
- "name": "__common__",
- "read_only": 1,
- "section_style": "Simple",
- "version": 73
- },
- {
- "doctype": "DocType",
- "name": "Setup Control"
- }
-]
\ No newline at end of file
diff --git a/setup/doctype/uom/uom.txt b/setup/doctype/uom/uom.txt
index 6577f6c..51d9806 100644
--- a/setup/doctype/uom/uom.txt
+++ b/setup/doctype/uom/uom.txt
@@ -2,7 +2,7 @@
{
"creation": "2013-01-10 16:34:24",
"docstatus": 0,
- "modified": "2013-07-25 16:18:17",
+ "modified": "2013-10-10 15:06:53",
"modified_by": "Administrator",
"owner": "Administrator"
},
@@ -40,22 +40,6 @@
},
{
"doctype": "DocField",
- "fieldname": "trash_reason",
- "fieldtype": "Small Text",
- "label": "Trash Reason",
- "oldfieldname": "trash_reason",
- "oldfieldtype": "Small Text",
- "read_only": 1
- },
- {
- "doctype": "DocField",
- "fieldname": "uom_details",
- "fieldtype": "Section Break",
- "label": "UOM Details",
- "oldfieldtype": "Section Break"
- },
- {
- "doctype": "DocField",
"fieldname": "uom_name",
"fieldtype": "Data",
"label": "UOM Name",
diff --git a/setup/page/setup_wizard/__init__.py b/setup/page/setup_wizard/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/setup/page/setup_wizard/__init__.py
diff --git a/setup/page/setup_wizard/setup_wizard.css b/setup/page/setup_wizard/setup_wizard.css
new file mode 100644
index 0000000..ad49ef0
--- /dev/null
+++ b/setup/page/setup_wizard/setup_wizard.css
@@ -0,0 +1,8 @@
+#page-setup-wizard .panel {
+ -webkit-box-shadow: 0px 1px 8px rgba(0,0,0,0.6);
+ box-shadow: 0px 1px 8px rgba(0,0,0,0.6);
+}
+
+#page-setup-wizard .col-md-6 .control-input .btn {
+ width: 100%;
+}
diff --git a/setup/page/setup_wizard/setup_wizard.js b/setup/page/setup_wizard/setup_wizard.js
new file mode 100644
index 0000000..648958e
--- /dev/null
+++ b/setup/page/setup_wizard/setup_wizard.js
@@ -0,0 +1,499 @@
+wn.pages['setup-wizard'].onload = function(wrapper) {
+ if(sys_defaults.company) {
+ wn.set_route("desktop");
+ return;
+ }
+ $(".navbar:first").toggle(false);
+ $("body").css({"padding-top":"30px"});
+
+ erpnext.wiz = new wn.wiz.Wizard({
+ page_name: "setup-wizard",
+ parent: wrapper,
+ on_complete: function(wiz) {
+ var values = wiz.get_values();
+ wiz.show_working();
+ wn.call({
+ method: "setup.page.setup_wizard.setup_wizard.setup_account",
+ args: values,
+ callback: function(r) {
+ if(r.exc) {
+ var d = msgprint(wn._("There were errors."));
+ d.custom_onhide = function() {
+ wn.set_route(erpnext.wiz.page_name, "0");
+ }
+ } else {
+ wiz.show_complete();
+ setTimeout(function() {
+ if(user==="Administrator") {
+ msgprint(wn._("Login with your new User ID") + ":" + values.email);
+ setTimeout(function() {
+ wn.app.logout();
+ }, 2000);
+ } else {
+ window.location = "app.html";
+ }
+ }, 2000);
+ }
+ }
+ })
+ },
+ title: wn._("ERPNext Setup Guide"),
+ welcome_html: '<h1 class="text-muted text-center"><i class="icon-magic"></i></h1>\
+ <h2 class="text-center">'+wn._('ERPNext Setup')+'</h2>\
+ <p class="text-center">' +
+ wn._('Welcome to ERPNext. Over the next few minutes we will help you setup your ERPNext account. Try and fill in as much information as you have even if it takes a bit longer. It will save you a lot of time later. Good Luck!') +
+ '</p>',
+ working_html: '<h3 class="text-muted text-center"><i class="icon-refresh icon-spin"></i></h3>\
+ <h2 class="text-center">'+wn._('Setting up...')+'</h2>\
+ <p class="text-center">' +
+ wn._('Sit tight while your system is being setup. This may take a few moments.') +
+ '</p>',
+ complete_html: '<h1 class="text-muted text-center"><i class="icon-thumbs-up"></i></h1>\
+ <h2 class="text-center">'+wn._('Setup Complete!')+'</h2>\
+ <p class="text-center">' +
+ wn._('Your setup is complete. Refreshing...') +
+ '</p>',
+ slides: [
+ // User
+ {
+ title: wn._("The First User: You"),
+ icon: "icon-user",
+ fields: [
+ {"fieldname": "first_name", "label": wn._("First Name"), "fieldtype": "Data", reqd:1},
+ {"fieldname": "last_name", "label": wn._("Last Name"), "fieldtype": "Data", reqd:1},
+ {"fieldname": "email", "label": wn._("Email Id"), "fieldtype": "Data", reqd:1, "description":"Your Login Id"},
+ {"fieldname": "password", "label": wn._("Password"), "fieldtype": "Password", reqd:1},
+ {fieldtype:"Attach Image", fieldname:"attach_profile", label:"Attach Your Profile..."},
+ ],
+ help: wn._('The first user will become the System Manager (you can change that later).'),
+ onload: function(slide) {
+ if(user!=="Administrator") {
+ slide.form.fields_dict.password.$wrapper.toggle(false);
+ slide.form.fields_dict.email_id.$wrapper.toggle(false);
+ delete slide.form.fields_dict.email;
+ delete slide.form.fields_dict.password;
+ }
+ }
+ },
+
+ // Organization
+ {
+ title: wn._("The Organization"),
+ icon: "icon-building",
+ fields: [
+ {fieldname:'company_name', label: wn._('Company Name'), fieldtype:'Data', reqd:1,
+ placeholder: 'e.g. "My Company LLC"'},
+ {fieldname:'company_abbr', label: wn._('Company Abbreviation'), fieldtype:'Data',
+ placeholder:'e.g. "MC"',reqd:1},
+ {fieldname:'fy_start', label:'Financial Year Start Date', fieldtype:'Select',
+ description:'Your financial year begins on', reqd:1,
+ options: ['', '1st Jan', '1st Apr', '1st Jul', '1st Oct'] },
+ {fieldname:'company_tagline', label: wn._('What does it do?'), fieldtype:'Data',
+ placeholder:'e.g. "Build tools for builders"', reqd:1},
+ ],
+ help: wn._('The name of your company for which you are setting up this system.'),
+ onload: function(slide) {
+ slide.get_input("company_name").on("change", function() {
+ var parts = slide.get_input("company_name").val().split(" ");
+ var abbr = $.map(parts, function(p) { return p ? p.substr(0,1) : null }).join("");
+ slide.get_input("company_abbr").val(abbr.toUpperCase());
+ });
+ }
+ },
+
+ // Country
+ {
+ title: wn._("Country, Timezone and Currency"),
+ icon: "icon-flag",
+ fields: [
+ {fieldname:'country', label: wn._('Country'), reqd:1,
+ options: "", fieldtype: 'Select'},
+ {fieldname:'currency', label: wn._('Default Currency'), reqd:1,
+ options: "", fieldtype: 'Select'},
+ {fieldname:'timezone', label: wn._('Time Zone'), reqd:1,
+ options: "", fieldtype: 'Select'},
+ ],
+ help: wn._('Select your home country and check the timezone and currency.'),
+ onload: function(slide, form) {
+ wn.call({
+ method:"webnotes.country_info.get_country_timezone_info",
+ callback: function(data) {
+ erpnext.country_info = data.message.country_info;
+ erpnext.all_timezones = data.message.all_timezones;
+ slide.get_input("country").empty()
+ .add_options([""].concat(keys(erpnext.country_info).sort()));
+ slide.get_input("currency").empty()
+ .add_options(wn.utils.unique([""].concat($.map(erpnext.country_info,
+ function(opts, country) { return opts.currency; }))).sort());
+ slide.get_input("timezone").empty()
+ .add_options([""].concat(erpnext.all_timezones));
+ }
+ })
+
+ slide.get_input("country").on("change", function() {
+ var country = slide.get_input("country").val();
+ var $timezone = slide.get_input("timezone");
+ $timezone.empty();
+ // add country specific timezones first
+ if(country){
+ var timezone_list = erpnext.country_info[country].timezones || [];
+ $timezone.add_options(timezone_list.sort());
+ slide.get_input("currency").val(erpnext.country_info[country].currency);
+ }
+ // add all timezones at the end, so that user has the option to change it to any timezone
+ $timezone.add_options([""].concat(erpnext.all_timezones));
+
+ });
+ }
+ },
+
+ // Logo
+ {
+ icon: "icon-bookmark",
+ title: wn._("Logo and Letter Heads"),
+ help: wn._('Upload your letter head and logo - you can edit them later.'),
+ fields: [
+ {fieldtype:"Attach Image", fieldname:"attach_letterhead", label:"Attach Letterhead..."},
+ {fieldtype:"Attach Image", fieldname:"attach_logo", label:"Attach Logo..."},
+ ],
+ },
+
+ // Taxes
+ {
+ icon: "icon-money",
+ "title": wn._("Add Taxes"),
+ "help": wn._("List your tax heads (e.g. VAT, Excise) (upto 3) and their standard rates. This will create a standard template, you can edit and add more later."),
+ "fields": [
+ {fieldtype:"Data", fieldname:"tax_1", label:"Tax 1", placeholder:"e.g. VAT"},
+ {fieldtype:"Column Break"},
+ {fieldtype:"Data", fieldname:"tax_rate_1", label:"Rate (%)", placeholder:"e.g. 5"},
+ {fieldtype:"Section Break"},
+ {fieldtype:"Data", fieldname:"tax_2", label:"Tax 2", placeholder:"e.g. Customs Duty"},
+ {fieldtype:"Column Break"},
+ {fieldtype:"Data", fieldname:"tax_rate_2", label:"Rate (%)", placeholder:"e.g. 5"},
+ {fieldtype:"Section Break"},
+ {fieldtype:"Data", fieldname:"tax_3", label:"Tax 3", placeholder:"e.g. Excise"},
+ {fieldtype:"Column Break"},
+ {fieldtype:"Data", fieldname:"tax_rate_3", label:"Rate (%)", placeholder:"e.g. 5"},
+ ],
+ },
+
+ // Items to Sell
+ {
+ icon: "icon-barcode",
+ "title": wn._("Your Products or Services"),
+ "help": wn._("List your products or services that you sell to your customers. Make sure to check the Item Group, Unit of Measure and other properties when you start."),
+ "fields": [
+ {fieldtype:"Data", fieldname:"item_1", label:"Item 1", placeholder:"A Product or Service"},
+ {fieldtype:"Column Break"},
+ {fieldtype:"Attach", fieldname:"item_img_1", label:"Attach Image..."},
+ {fieldtype:"Section Break"},
+ {fieldtype:"Column Break"},
+ {fieldtype:"Column Break"},
+ {fieldtype:"Select", fieldname:"item_group_1", options:["Products", "Services", "Raw Material", "Sub Assemblies"]},
+ {fieldtype:"Column Break"},
+ {fieldtype:"Select", fieldname:"item_uom_1", options:["Unit", "Nos", "Box", "Pair", "Kg", "Set", "Hour", "Minute"]},
+ {fieldtype:"Section Break"},
+ {fieldtype:"Data", fieldname:"item_2", label:"Item 2", placeholder:"A Product or Service"},
+ {fieldtype:"Column Break"},
+ {fieldtype:"Attach", fieldname:"item_img_2", label:"Attach Image..."},
+ {fieldtype:"Section Break"},
+ {fieldtype:"Column Break"},
+ {fieldtype:"Column Break"},
+ {fieldtype:"Select", fieldname:"item_group_2", options:["Products", "Services", "Raw Material", "Sub Assemblies"]},
+ {fieldtype:"Column Break"},
+ {fieldtype:"Select", fieldname:"item_uom_2", options:["Unit", "Nos", "Box", "Pair", "Kg", "Set", "Hour", "Minute"]},
+ {fieldtype:"Section Break"},
+ {fieldtype:"Data", fieldname:"item_3", label:"Item 3", placeholder:"A Product or Service"},
+ {fieldtype:"Column Break"},
+ {fieldtype:"Attach", fieldname:"item_img_3", label:"Attach Image..."},
+ {fieldtype:"Section Break"},
+ {fieldtype:"Column Break"},
+ {fieldtype:"Column Break"},
+ {fieldtype:"Select", fieldname:"item_group_3", options:["Products", "Services", "Raw Material", "Sub Assemblies"]},
+ {fieldtype:"Column Break"},
+ {fieldtype:"Select", fieldname:"item_uom_3", options:["Unit", "Nos", "Box", "Pair", "Kg", "Set", "Hour", "Minute"]},
+ {fieldtype:"Section Break"},
+ {fieldtype:"Data", fieldname:"item_4", label:"Item 4", placeholder:"A Product or Service"},
+ {fieldtype:"Column Break"},
+ {fieldtype:"Attach", fieldname:"item_img_4", label:"Attach Image..."},
+ {fieldtype:"Section Break"},
+ {fieldtype:"Column Break"},
+ {fieldtype:"Column Break"},
+ {fieldtype:"Select", fieldname:"item_group_4", options:["Products", "Services", "Raw Material", "Sub Assemblies"]},
+ {fieldtype:"Column Break"},
+ {fieldtype:"Select", fieldname:"item_uom_4", options:["Unit", "Nos", "Box", "Pair", "Kg", "Set", "Hour", "Minute"]},
+ {fieldtype:"Section Break"},
+ {fieldtype:"Data", fieldname:"item_5", label:"Item 5", placeholder:"A Product or Service"},
+ {fieldtype:"Column Break"},
+ {fieldtype:"Attach", fieldname:"item_img_5", label:"Attach Image..."},
+ {fieldtype:"Section Break"},
+ {fieldtype:"Column Break"},
+ {fieldtype:"Column Break"},
+ {fieldtype:"Select", fieldname:"item_group_5", options:["Products", "Services", "Raw Material", "Sub Assemblies"]},
+ {fieldtype:"Column Break"},
+ {fieldtype:"Select", fieldname:"item_uom_5", options:["Unit", "Nos", "Box", "Pair", "Kg", "Set", "Hour", "Minute"]},
+ ],
+ },
+
+ // Items to Buy
+ {
+ icon: "icon-barcode",
+ "title": wn._("Products or Services You Buy"),
+ "help": wn._("List a few products or services you buy from your suppliers or vendors. If these are same as your products, then do not add them."),
+ "fields": [
+ {fieldtype:"Data", fieldname:"item_buy_1", label:"Item 1", placeholder:"A Product or Service"},
+ {fieldtype:"Section Break"},
+ {fieldtype:"Column Break"},
+ {fieldtype:"Column Break"},
+ {fieldtype:"Select", fieldname:"item_buy_group_1", options:["Raw Material", "Consumable", "Sub Assemblies", "Services", "Products"]},
+ {fieldtype:"Column Break"},
+ {fieldtype:"Select", fieldname:"item_buy_uom_1", options:["Unit", "Nos", "Box", "Pair", "Kg", "Set", "Hour", "Minute"]},
+ {fieldtype:"Section Break"},
+ {fieldtype:"Data", fieldname:"item_buy_2", label:"Item 2", placeholder:"A Product or Service"},
+ {fieldtype:"Section Break"},
+ {fieldtype:"Column Break"},
+ {fieldtype:"Column Break"},
+ {fieldtype:"Select", fieldname:"item_buy_group_2", options:["Raw Material", "Consumable", "Sub Assemblies", "Services", "Products"]},
+ {fieldtype:"Column Break"},
+ {fieldtype:"Select", fieldname:"item_buy_uom_2", options:["Unit", "Nos", "Box", "Pair", "Kg", "Set", "Hour", "Minute"]},
+ {fieldtype:"Section Break"},
+ {fieldtype:"Data", fieldname:"item_buy_3", label:"Item 3", placeholder:"A Product or Service"},
+ {fieldtype:"Section Break"},
+ {fieldtype:"Column Break"},
+ {fieldtype:"Column Break"},
+ {fieldtype:"Select", fieldname:"item_buy_group_3", options:["Raw Material", "Consumable", "Sub Assemblies", "Services", "Products"]},
+ {fieldtype:"Column Break"},
+ {fieldtype:"Select", fieldname:"item_buy_uom_3", options:["Unit", "Nos", "Box", "Pair", "Kg", "Set", "Hour", "Minute"]},
+ {fieldtype:"Section Break"},
+ {fieldtype:"Data", fieldname:"item_buy_4", label:"Item 4", placeholder:"A Product or Service"},
+ {fieldtype:"Section Break"},
+ {fieldtype:"Column Break"},
+ {fieldtype:"Column Break"},
+ {fieldtype:"Select", fieldname:"item_buy_group_4", options:["Raw Material", "Consumable", "Sub Assemblies", "Services", "Products"]},
+ {fieldtype:"Column Break"},
+ {fieldtype:"Select", fieldname:"item_buy_uom_4", options:["Unit", "Nos", "Box", "Pair", "Kg", "Set", "Hour", "Minute"]},
+ {fieldtype:"Section Break"},
+ {fieldtype:"Data", fieldname:"item_buy_5", label:"Item 5", placeholder:"A Product or Service"},
+ {fieldtype:"Section Break"},
+ {fieldtype:"Column Break"},
+ {fieldtype:"Column Break"},
+ {fieldtype:"Select", fieldname:"item_buy_group_5", options:["Raw Material", "Consumable", "Sub Assemblies", "Services", "Products"]},
+ {fieldtype:"Column Break"},
+ {fieldtype:"Select", fieldname:"item_buy_uom_5", options:["Unit", "Nos", "Box", "Pair", "Kg", "Set", "Hour", "Minute"]},
+ ],
+ },
+
+ // Customers
+ {
+ icon: "icon-group",
+ "title": wn._("Your Customers"),
+ "help": wn._("List a few of your customers. They could be organizations or individuals."),
+ "fields": [
+ {fieldtype:"Data", fieldname:"customer_1", label:"Customer 1", placeholder:"Customer Name"},
+ {fieldtype:"Column Break"},
+ {fieldtype:"Data", fieldname:"customer_contact_1", label:"", placeholder:"Contact Name"},
+ {fieldtype:"Section Break"},
+ {fieldtype:"Data", fieldname:"customer_2", label:"Customer 2", placeholder:"Customer Name"},
+ {fieldtype:"Column Break"},
+ {fieldtype:"Data", fieldname:"customer_contact_2", label:"", placeholder:"Contact Name"},
+ {fieldtype:"Section Break"},
+ {fieldtype:"Data", fieldname:"customer_3", label:"Customer 3", placeholder:"Customer Name"},
+ {fieldtype:"Column Break"},
+ {fieldtype:"Data", fieldname:"customer_contact_3", label:"", placeholder:"Contact Name"},
+ {fieldtype:"Section Break"},
+ {fieldtype:"Data", fieldname:"customer_4", label:"Customer 4", placeholder:"Customer Name"},
+ {fieldtype:"Column Break"},
+ {fieldtype:"Data", fieldname:"customer_contact_4", label:"", placeholder:"Contact Name"},
+ {fieldtype:"Section Break"},
+ {fieldtype:"Data", fieldname:"customer_5", label:"Customer 5", placeholder:"Customer Name"},
+ {fieldtype:"Column Break"},
+ {fieldtype:"Data", fieldname:"customer_contact_5", label:"", placeholder:"Contact Name"},
+ ],
+ },
+
+ // Suppliers
+ {
+ icon: "icon-group",
+ "title": wn._("Your Suppliers"),
+ "help": wn._("List a few of your suppliers. They could be organizations or individuals."),
+ "fields": [
+ {fieldtype:"Data", fieldname:"supplier_1", label:"Supplier 1", placeholder:"Supplier Name"},
+ {fieldtype:"Column Break"},
+ {fieldtype:"Data", fieldname:"supplier_contact_1", label:"", placeholder:"Contact Name"},
+ {fieldtype:"Section Break"},
+ {fieldtype:"Data", fieldname:"supplier_2", label:"Supplier 2", placeholder:"Supplier Name"},
+ {fieldtype:"Column Break"},
+ {fieldtype:"Data", fieldname:"supplier_contact_2", label:"", placeholder:"Contact Name"},
+ {fieldtype:"Section Break"},
+ {fieldtype:"Data", fieldname:"supplier_3", label:"Supplier 3", placeholder:"Supplier Name"},
+ {fieldtype:"Column Break"},
+ {fieldtype:"Data", fieldname:"supplier_contact_3", label:"", placeholder:"Contact Name"},
+ {fieldtype:"Section Break"},
+ {fieldtype:"Data", fieldname:"supplier_4", label:"Supplier 4", placeholder:"Supplier Name"},
+ {fieldtype:"Column Break"},
+ {fieldtype:"Data", fieldname:"supplier_contact_4", label:"", placeholder:"Contact Name"},
+ {fieldtype:"Section Break"},
+ {fieldtype:"Data", fieldname:"supplier_5", label:"Supplier 5", placeholder:"Supplier Name"},
+ {fieldtype:"Column Break"},
+ {fieldtype:"Data", fieldname:"supplier_contact_5", label:"", placeholder:"Contact Name"},
+ ],
+ }
+
+ ]
+
+ })
+}
+
+wn.pages['setup-wizard'].onshow = function(wrapper) {
+ if(wn.get_route()[1])
+ erpnext.wiz.show(wn.get_route()[1]);
+}
+
+wn.provide("wn.wiz");
+
+wn.wiz.Wizard = Class.extend({
+ init: function(opts) {
+ $.extend(this, opts);
+ this.slides = this.slides;
+ this.slide_dict = {};
+ this.show_welcome();
+ },
+ get_message: function(html) {
+ return $(repl('<div class="panel panel-default" style="max-width: 400px; margin: auto;">\
+ <div class="panel-body" style="padding: 40px;">%(html)s</div>\
+ </div>', {html:html}))
+ },
+ show_welcome: function() {
+ if(this.$welcome)
+ return;
+ var me = this;
+ this.$welcome = this.get_message(this.welcome_html +
+ '<br><p class="text-center"><button class="btn btn-primary">'+wn._("Start")+'</button></p>')
+ .appendTo(this.parent);
+
+ this.$welcome.find(".btn").click(function() {
+ me.$welcome.toggle(false);
+ me.welcomed = true;
+ wn.set_route(me.page_name, "0");
+ })
+
+ this.current_slide = {"$wrapper": this.$welcome};
+ },
+ show_working: function() {
+ this.hide_current_slide();
+ wn.set_route(this.page_name);
+ this.current_slide = {"$wrapper": this.get_message(this.working_html).appendTo(this.parent)};
+ },
+ show_complete: function() {
+ this.hide_current_slide();
+ this.current_slide = {"$wrapper": this.get_message(this.complete_html).appendTo(this.parent)};
+ },
+ show: function(id) {
+ if(!this.welcomed) {
+ wn.set_route(this.page_name);
+ return;
+ }
+ id = cint(id);
+ if(this.current_slide && this.current_slide.id===id)
+ return;
+ if(!this.slide_dict[id]) {
+ this.slide_dict[id] = new wn.wiz.WizardSlide($.extend(this.slides[id], {wiz:this, id:id}));
+ this.slide_dict[id].make();
+ }
+
+ this.hide_current_slide();
+
+ this.current_slide = this.slide_dict[id];
+ this.current_slide.$wrapper.toggle(true);
+ },
+ hide_current_slide: function() {
+ if(this.current_slide) {
+ this.current_slide.$wrapper.toggle(false);
+ this.current_slide = null;
+ }
+ },
+ get_values: function() {
+ var values = {};
+ $.each(this.slide_dict, function(id, slide) {
+ $.extend(values, slide.values)
+ })
+ return values;
+ }
+});
+
+wn.wiz.WizardSlide = Class.extend({
+ init: function(opts) {
+ $.extend(this, opts);
+ },
+ make: function() {
+ var me = this;
+ this.$wrapper = $(repl('<div class="panel panel-default" style="margin: 0px 30px;">\
+ <div class="panel-heading"><div class="panel-title">%(main_title)s: Step %(step)s</div></div>\
+ <div class="panel-body">\
+ <div class="progress">\
+ <div class="progress-bar" style="width: %(width)s%"></div>\
+ </div>\
+ <div class="row">\
+ <div class="col-sm-6 form"></div>\
+ <div class="col-sm-6 help">\
+ <h3><i class="%(icon)s text-muted"></i> %(title)s</h3><br>\
+ <p class="text-muted">%(help)s</p>\
+ </div>\
+ </div>\
+ <hr>\
+ <div class="footer"></div>\
+ </div>\
+ </div>', {help:this.help, title:this.title, main_title:this.wiz.title, step: this.id + 1,
+ width: (flt(this.id + 1) / (this.wiz.slides.length+1)) * 100, icon:this.icon}))
+ .appendTo(this.wiz.parent);
+
+ this.body = this.$wrapper.find(".form")[0];
+
+ if(this.fields) {
+ this.form = new wn.ui.FieldGroup({
+ fields: this.fields,
+ body: this.body,
+ no_submit_on_enter: true
+ });
+ this.form.make();
+ } else {
+ $(this.body).html(this.html)
+ }
+
+ if(this.id > 0) {
+ this.$prev = $("<button class='btn btn-default'>Previous</button>")
+ .click(function() {
+ wn.set_route(me.wiz.page_name, me.id-1 + "");
+ })
+ .appendTo(this.$wrapper.find(".footer"))
+ .css({"margin-right": "5px"});
+ }
+ if(this.id+1 < this.wiz.slides.length) {
+ this.$next = $("<button class='btn btn-primary'>Next</button>")
+ .click(function() {
+ me.values = me.form.get_values();
+ if(me.values===null)
+ return;
+ wn.set_route(me.wiz.page_name, me.id+1 + "");
+ })
+ .appendTo(this.$wrapper.find(".footer"));
+ } else {
+ this.$complete = $("<button class='btn btn-primary'>Complete Setup</button>")
+ .click(function() {
+ me.values = me.form.get_values();
+ if(me.values===null)
+ return;
+ me.wiz.on_complete(me.wiz);
+ }).appendTo(this.$wrapper.find(".footer"));
+ }
+
+ if(this.onload) {
+ this.onload(this);
+ }
+
+ },
+ get_input: function(fn) {
+ return this.form.get_input(fn);
+ }
+})
\ No newline at end of file
diff --git a/setup/page/setup_wizard/setup_wizard.py b/setup/page/setup_wizard/setup_wizard.py
new file mode 100644
index 0000000..d506d41
--- /dev/null
+++ b/setup/page/setup_wizard/setup_wizard.py
@@ -0,0 +1,354 @@
+# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+import webnotes, json, base64
+
+from webnotes.utils import cint, cstr, getdate, now, nowdate, get_defaults
+from webnotes import _
+from webnotes.utils.file_manager import save_file
+
+@webnotes.whitelist()
+def setup_account(args=None):
+ # if webnotes.conn.sql("select name from tabCompany"):
+ # webnotes.throw(_("Setup Already Complete!!"))
+
+ if not args:
+ args = webnotes.local.form_dict
+ if isinstance(args, basestring):
+ args = json.loads(args)
+ args = webnotes._dict(args)
+
+ update_profile_name(args)
+ create_fiscal_year_and_company(args)
+ set_defaults(args)
+ create_territories()
+ create_price_lists(args)
+ create_feed_and_todo()
+ create_email_digest()
+ create_letter_head(args)
+ create_taxes(args)
+ create_items(args)
+ create_customers(args)
+ create_suppliers(args)
+ webnotes.conn.set_value('Control Panel', None, 'home_page', 'desktop')
+
+ webnotes.clear_cache()
+ webnotes.conn.commit()
+
+ # suppress msgprints
+ webnotes.local.message_log = []
+
+ return "okay"
+
+def update_profile_name(args):
+ if args.get("email"):
+ args['name'] = args.get("email")
+ webnotes.flags.mute_emails = True
+ webnotes.bean({
+ "doctype":"Profile",
+ "email": args.get("email"),
+ "first_name": args.get("first_name"),
+ "last_name": args.get("last_name")
+ }).insert()
+ webnotes.flags.mute_emails = False
+ from webnotes.auth import _update_password
+ _update_password(args.get("email"), args.get("password"))
+
+ else:
+ args['name'] = webnotes.session.user
+
+ # Update Profile
+ if not args.get('last_name') or args.get('last_name')=='None':
+ args['last_name'] = None
+ webnotes.conn.sql("""update `tabProfile` SET first_name=%(first_name)s,
+ last_name=%(last_name)s WHERE name=%(name)s""", args)
+
+ if args.get("attach_profile"):
+ filename, filetype, content = args.get("attach_profile").split(",")
+ fileurl = save_file(filename, content, "Profile", args.get("name"), decode=True).file_name
+ webnotes.conn.set_value("Profile", args.get("name"), "user_image", fileurl)
+
+ add_all_roles_to(args.get("name"))
+
+def create_fiscal_year_and_company(args):
+ curr_fiscal_year, fy_start_date, fy_abbr = get_fy_details(args.get('fy_start'), True)
+ webnotes.bean([{
+ "doctype":"Fiscal Year",
+ 'year': curr_fiscal_year,
+ 'year_start_date': fy_start_date
+ }]).insert()
+
+ curr_fiscal_year, fy_start_date, fy_abbr = get_fy_details(args.get('fy_start'))
+ webnotes.bean([{
+ "doctype":"Fiscal Year",
+ 'year': curr_fiscal_year,
+ 'year_start_date': fy_start_date,
+ }]).insert()
+
+
+ # Company
+ webnotes.bean([{
+ "doctype":"Company",
+ 'domain': args.get("industry"),
+ 'company_name':args.get('company_name'),
+ 'abbr':args.get('company_abbr'),
+ 'default_currency':args.get('currency'),
+ }]).insert()
+
+ args["curr_fiscal_year"] = curr_fiscal_year
+
+def create_price_lists(args):
+ for pl_type in ["Selling", "Buying"]:
+ webnotes.bean([
+ {
+ "doctype": "Price List",
+ "price_list_name": "Standard " + pl_type,
+ "buying_or_selling": pl_type,
+ "currency": args["currency"]
+ },
+ {
+ "doctype": "For Territory",
+ "parentfield": "valid_for_territories",
+ "territory": "All Territories"
+ }
+ ]).insert()
+
+def set_defaults(args):
+ # enable default currency
+ webnotes.conn.set_value("Currency", args.get("currency"), "enabled", 1)
+
+ global_defaults = webnotes.bean("Global Defaults", "Global Defaults")
+ global_defaults.doc.fields.update({
+ 'current_fiscal_year': args.curr_fiscal_year,
+ 'default_currency': args.get('currency'),
+ 'default_company':args.get('company_name'),
+ 'date_format': webnotes.conn.get_value("Country", args.get("country"), "date_format"),
+ "float_precision": 4
+ })
+ global_defaults.save()
+
+ accounts_settings = webnotes.bean("Accounts Settings")
+ accounts_settings.doc.auto_accounting_for_stock = 1
+ accounts_settings.save()
+
+ stock_settings = webnotes.bean("Stock Settings")
+ stock_settings.doc.item_naming_by = "Item Code"
+ stock_settings.doc.valuation_method = "FIFO"
+ stock_settings.doc.stock_uom = "Nos"
+ stock_settings.doc.auto_indent = 1
+ stock_settings.save()
+
+ selling_settings = webnotes.bean("Selling Settings")
+ selling_settings.doc.cust_master_name = "Customer Name"
+ selling_settings.doc.so_required = "No"
+ selling_settings.doc.dn_required = "No"
+ selling_settings.save()
+
+ buying_settings = webnotes.bean("Buying Settings")
+ buying_settings.doc.supp_master_name = "Supplier Name"
+ buying_settings.doc.po_required = "No"
+ buying_settings.doc.pr_required = "No"
+ buying_settings.doc.maintain_same_rate = 1
+ buying_settings.save()
+
+ notification_control = webnotes.bean("Notification Control")
+ notification_control.doc.quotation = 1
+ notification_control.doc.sales_invoice = 1
+ notification_control.doc.purchase_order = 1
+ notification_control.save()
+
+ hr_settings = webnotes.bean("HR Settings")
+ hr_settings.doc.emp_created_by = "Naming Series"
+ hr_settings.save()
+
+ # control panel
+ cp = webnotes.doc("Control Panel", "Control Panel")
+ for k in ['country', 'timezone', 'company_name']:
+ cp.fields[k] = args[k]
+
+ cp.save()
+
+def create_feed_and_todo():
+ """update activty feed and create todo for creation of item, customer, vendor"""
+ import home
+ home.make_feed('Comment', 'ToDo', '', webnotes.session['user'],
+ 'ERNext Setup Complete!', '#6B24B3')
+
+def create_email_digest():
+ from webnotes.profile import get_system_managers
+ system_managers = get_system_managers()
+ if not system_managers:
+ return
+
+ for company in webnotes.conn.sql_list("select name FROM `tabCompany`"):
+ if not webnotes.conn.exists("Email Digest", "Default Weekly Digest - " + company):
+ edigest = webnotes.bean({
+ "doctype": "Email Digest",
+ "name": "Default Weekly Digest - " + company,
+ "company": company,
+ "frequency": "Weekly",
+ "recipient_list": "\n".join(system_managers)
+ })
+
+ for fieldname in edigest.meta.get_fieldnames({"fieldtype": "Check"}):
+ edigest.doc.fields[fieldname] = 1
+
+ edigest.insert()
+
+def get_fy_details(fy_start, last_year=False):
+ st = {'1st Jan':'01-01','1st Apr':'04-01','1st Jul':'07-01', '1st Oct': '10-01'}
+ if cint(getdate(nowdate()).month) < cint((st[fy_start].split('-'))[0]):
+ curr_year = getdate(nowdate()).year - 1
+ else:
+ curr_year = getdate(nowdate()).year
+
+ if last_year:
+ curr_year = curr_year - 1
+
+ stdt = cstr(curr_year)+'-'+cstr(st[fy_start])
+
+ if(fy_start == '1st Jan'):
+ fy = cstr(curr_year)
+ abbr = cstr(fy)[-2:]
+ else:
+ fy = cstr(curr_year) + '-' + cstr(curr_year+1)
+ abbr = cstr(curr_year)[-2:] + '-' + cstr(curr_year+1)[-2:]
+ return fy, stdt, abbr
+
+def create_taxes(args):
+ for i in xrange(1,6):
+ if args.get("tax_" + str(i)):
+ webnotes.bean({
+ "doctype":"Account",
+ "company": args.get("company_name"),
+ "parent_account": "Duties and Taxes - " + args.get("company_abbr"),
+ "account_name": args.get("tax_" + str(i)),
+ "group_or_ledger": "Ledger",
+ "is_pl_account": "No",
+ "account_type": "Tax",
+ "tax_rate": args.get("tax_rate_" + str(i))
+ }).insert()
+
+def create_items(args):
+ for i in xrange(1,6):
+ item = args.get("item_" + str(i))
+ if item:
+ item_group = args.get("item_group_" + str(i))
+ webnotes.bean({
+ "doctype":"Item",
+ "item_code": item,
+ "item_name": item,
+ "description": item,
+ "is_sales_item": "Yes",
+ "is_stock_item": item_group!="Services" and "Yes" or "No",
+ "item_group": item_group,
+ "stock_uom": args.get("item_uom_" + str(i)),
+ "default_warehouse": item_group!="Service" and ("Finished Goods - " + args.get("company_abbr")) or ""
+ }).insert()
+
+ if args.get("item_img_" + str(i)):
+ filename, filetype, content = args.get("item_img_" + str(i)).split(",")
+ fileurl = save_file(filename, content, "Item", item, decode=True).file_name
+ webnotes.conn.set_value("Item", item, "image", fileurl)
+
+ for i in xrange(1,6):
+ item = args.get("item_buy_" + str(i))
+ if item:
+ item_group = args.get("item_buy_group_" + str(i))
+ webnotes.bean({
+ "doctype":"Item",
+ "item_code": item,
+ "item_name": item,
+ "description": item,
+ "is_sales_item": "No",
+ "is_stock_item": item_group!="Services" and "Yes" or "No",
+ "item_group": item_group,
+ "stock_uom": args.get("item_buy_uom_" + str(i)),
+ "default_warehouse": item_group!="Service" and ("Stores - " + args.get("company_abbr")) or ""
+ }).insert()
+
+ if args.get("item_img_" + str(i)):
+ filename, filetype, content = args.get("item_img_" + str(i)).split(",")
+ fileurl = save_file(filename, content, "Item", item, decode=True).file_name
+ webnotes.conn.set_value("Item", item, "image", fileurl)
+
+
+def create_customers(args):
+ for i in xrange(1,6):
+ customer = args.get("customer_" + str(i))
+ if customer:
+ webnotes.bean({
+ "doctype":"Customer",
+ "customer_name": customer,
+ "customer_type": "Company",
+ "customer_group": "Commercial",
+ "territory": args.get("country"),
+ "company": args.get("company_name")
+ }).insert()
+
+ if args.get("customer_contact_" + str(i)):
+ contact = args.get("customer_contact_" + str(i)).split(" ")
+ webnotes.bean({
+ "doctype":"Contact",
+ "customer": customer,
+ "first_name":contact[0],
+ "last_name": len(contact) > 1 and contact[1] or ""
+ }).insert()
+
+def create_suppliers(args):
+ for i in xrange(1,6):
+ supplier = args.get("supplier_" + str(i))
+ if supplier:
+ webnotes.bean({
+ "doctype":"Supplier",
+ "supplier_name": supplier,
+ "supplier_type": "Local",
+ "company": args.get("company_name")
+ }).insert()
+
+ if args.get("supplier_contact_" + str(i)):
+ contact = args.get("supplier_contact_" + str(i)).split(" ")
+ webnotes.bean({
+ "doctype":"Contact",
+ "supplier": supplier,
+ "first_name":contact[0],
+ "last_name": len(contact) > 1 and contact[1] or ""
+ }).insert()
+
+
+def create_letter_head(args):
+ if args.get("attach_letterhead"):
+ lh = webnotes.bean({
+ "doctype":"Letter Head",
+ "letter_head_name": "Standard",
+ "is_default": 1
+ }).insert()
+
+ filename, filetype, content = args.get("attach_letterhead").split(",")
+ fileurl = save_file(filename, content, "Letter Head", "Standard", decode=True).file_name
+ webnotes.conn.set_value("Letter Head", "Standard", "content", "<img src='%s' style='max-width: 100%%;'>" % fileurl)
+
+
+
+def add_all_roles_to(name):
+ profile = webnotes.doc("Profile", name)
+ for role in webnotes.conn.sql("""select name from tabRole"""):
+ if role[0] not in ["Administrator", "Guest", "All", "Customer", "Supplier", "Partner"]:
+ d = profile.addchild("user_roles", "UserRole")
+ d.role = role[0]
+ d.insert()
+
+def create_territories():
+ """create two default territories, one for home country and one named Rest of the World"""
+ from setup.utils import get_root_of
+ country = webnotes.conn.get_value("Control Panel", None, "country")
+ root_territory = get_root_of("Territory")
+ for name in (country, "Rest Of The World"):
+ if name and not webnotes.conn.exists("Territory", name):
+ webnotes.bean({
+ "doctype": "Territory",
+ "territory_name": name.replace("'", ""),
+ "parent_territory": root_territory,
+ "is_group": "No"
+ }).insert()
\ No newline at end of file
diff --git a/setup/page/setup_wizard/setup_wizard.txt b/setup/page/setup_wizard/setup_wizard.txt
new file mode 100644
index 0000000..996fd1a
--- /dev/null
+++ b/setup/page/setup_wizard/setup_wizard.txt
@@ -0,0 +1,32 @@
+[
+ {
+ "creation": "2013-10-04 13:49:33",
+ "docstatus": 0,
+ "modified": "2013-10-04 13:49:33",
+ "modified_by": "Administrator",
+ "owner": "Administrator"
+ },
+ {
+ "doctype": "Page",
+ "module": "Setup",
+ "name": "__common__",
+ "page_name": "setup-wizard",
+ "standard": "Yes",
+ "title": "Setup Wizard"
+ },
+ {
+ "doctype": "Page Role",
+ "name": "__common__",
+ "parent": "setup-wizard",
+ "parentfield": "roles",
+ "parenttype": "Page",
+ "role": "System Manager"
+ },
+ {
+ "doctype": "Page",
+ "name": "setup-wizard"
+ },
+ {
+ "doctype": "Page Role"
+ }
+]
\ No newline at end of file
diff --git a/setup/page/setup_wizard/test_setup_data.py b/setup/page/setup_wizard/test_setup_data.py
new file mode 100644
index 0000000..b5b6359
--- /dev/null
+++ b/setup/page/setup_wizard/test_setup_data.py
@@ -0,0 +1,53 @@
+
+args = {
+"attach_letterhead": "erpnext.jpg,data:image/jpeg;base64,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WVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD+/igAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgBGZVBZmCgAsxYgAKvLMSeAAOSTwO9AHxV4x/4KU/8E6Ph5rl74Y+IH7ff7FPgbxLps8ttqPh7xj+1R8C/DOuWFzA2ya3vdJ1rx3ZX9rPC/ySxT28ckbHa6g8UAcv/wAPYf8Agln/ANJK/wBgH/xMj9nX8f8Amo1ACf8AD2H/AIJZf9JLP2AP/EyP2de//dRu+f1oAX/h7D/wSz/6SV/sA/8AiZH7Ov8A88agA/4ew/8ABLP/AKSV/sA/+Jkfs7f/ADxqAD/h7D/wSz7/APBSv9gH/wATI/Z1/wDnjUAH/D2H/gln/wBJK/2AeOv/ABmR+zrx/wCZGoAP+HsP/BLP/pJX+wD/AOJkfs6//PGoA+hvg1+1N+zH+0al7J+z3+0b8B/jummxLcai/wAGvi98PviglhA7KqTXreCPEOuC1idnVVknKIzMoDEsMgHvHXmgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAQkKCx6AEn6Dk0Af5wP/B1n/wAFovjN4n/aI8a/8E0v2evHOs+APgv8I7LRtO/aI1jwfqt7pGs/GL4ka/olh4ivPAmra1YPbXx+HHgDSdW03StS8L2s9taeI/Gs2vt4ni1Wz0LQIbUA/iMbnOV/75VRnkf3QM/U89SeaAGjrnB6senXI/yPegAHB6HkL+HH+c/jQApJOcqeAR9ckd/8+tAC55xg9euPf/Jz/wDroARuexPH/sw4/HH5c80AGfvHDc+31/yT7/mAL3A56k5xx/F/n/8AXQB6F8Kfi18TfgZ4/wDDHxU+Dvjvxb8MviN4N1ODV/C/jbwNruoeGfE+h39vIHjnsNY0qa3uowwXy7i3leW0u4Ge2vLe4tpZYmAP9ef/AIN/v+CpWs/8FUP2FdM+JXxLTS7b9oX4P+Kp/g98dl0i1i03T/EviPTdG0zW/DvxM03R7eNLXSbP4heG9St77UdPsUt9MsvGGm+LLPRrKz0a3sLaIA/cmgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgBCMgg9Dwfcd/wA6AP8AFM/4LVzzXH/BWv8A4KLvPI8rr+2J8d4VZzkiK28a6hbW8YP92GCGKJB/CiKO1AH5gc4P178Dkr1B555+vP8AeoAQZz/30Oo3Hjue+P0oAXn+R65PQc8fr/eHSgA556dPoOvcdc46n8KADnrjv3Pqf5eg659aAA5//Wf9rv6jB/DJHegBOfm6Z4789O/9emRmgBecj6nvx1bt6/5NABzx069zk/e556env2oA/wBDj/gx5mmf4Yf8FErdpGMEPjv9mqeKInKRzT+GPi/FPIo7PLHbQI57rEg/hoA/u7oAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKAP8AFF/4LS/8paf+CjPr/wANkfH3/wBTvVPf/wDX60AfmMc4Of8A638PU8H1/wA4oAQZyPXLc8dcc9+oP4GgAGc47kLnt0A98nvnj/64ApyScjsR147d+OvvjjmgAyc49we3r9c/Q9c8HrQAN7+/6sMDr7df60AHPzevGenp356EfzPXFABzkdcZPp1+b3z/AJ9aADnAHvknj+96e/8AkmgD/Q0/4Md/+Sb/APBRf/sdf2ZP/Ub+M1AH939ABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQB/ijf8ABaX/AJS0/wDBRn/s8j4+8/8Ac+ap3/zzQB+Y3+Prx1Ht/TqT60AIM+p/i53c+nPH5dcGgBec9+MdT+PoefXnoe+RQAvPX29ePr06/gaADBz1PXPX8x06fj+XWgBDn3/P1P8AnHXjIoAOeRz25z/9bvxnPqT9QA7g5PUjrx3P+fT8KADkfn1J56/5789OtAH+hn/wY7/8k3/4KL/9jr+zJ/6jfxmoA/u/oAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKAP8UX/AILS/wDKWn/gozxn/jMj4+9s/wDM+ap+fNAH5jEdeP8Ax0H+76/j+vpQAgHPT1/g/L3/AK9jQAd+hxx/APxoAO7cHv8AwD1/X/JoACOenf8AuZH59f8APFACkdePX+EH+L/D9OaAE7Hj0/gH4/8A1/060ALjnoOp/g7c9+n4/ie9ABj2/wDHPf8AT8e3PWgD/Q0/4Md/+Sb/APBRf/sdf2ZP/Ub+M3+fegD+7+gAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoA/xRf+C0v/KWn/goz/2eR8fffr481X/P55oA/Mc85P8AMH1HXuenP/6qAGjqOB1bnB75xn2Pbnp34NAC4Oc46Y7ZPAHTk/j+mTQAYPXA5z29wfm75/Dr3oAMHrhfXpz/ACz75657UABHt+nqwPPf/HnPNAAAeRgdeuODj/PPpk0AHcH/AGj2OepOeme/596ADHTgdR7H72eOvGPf1zQB/oaf8GO//JN/+Ci//Y6/syf+o38ZqAP7v6ACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKAMzWda0jw7pOp69r+qadomiaLp97q+saxq99a6ZpWk6VptvJeajqep6jfTQWWn6fY2sUtzeX15PDa2sEbzTyxxqWAB+H/AMUv+DlH/giz8JfE194T139trwp4k1bTbmW0vp/hl4A+LfxT8PRzRMysLXxf4D8C654U1WLKnFxo+s6hbE8CY9wDzP8A4io/+CIf/R2mu/8AiPH7RX/zsqAD/iKj/wCCIf8A0dprv/iPH7RX/wA7KgA/4io/+CIf/R2mu/8AiPH7RX/zsqAD/iKj/wCCIf8A0dprv/iPH7RX/wA7KgA/4io/+CIf/R2mu/8AiPH7RX/zsqAP8xH/AIKa/Gj4d/tF/wDBQn9s747/AAi1yTxN8MPi7+0n8XPiF4B8QTaVquhzaz4U8U+LL/VNE1J9H12007WdNa7sp45WstTsbS+t9xjubeGUFFAPho55+uc8e3v25/TnPUATJz27+mef+Bfn/XrQADIPYZx6c8fX/H+VAC5OfpnnjPb/AGvz6dqADJz/APqzj/vr8KAA5/rzj1Hv6fTmgBMnnp79P1+b+Z/+sALzkfU+nqff8+M9evQgCZP689P73+91/rn6gA/sV/4NaP8AgrL+wp/wTU8E/tm6P+2L8YNQ+F+o/FzxR8DtR8BwWXw3+JPjwazZ+C9F+Jdn4ilkl8BeFvEcWmmyuPEOkxqmpvaPdfaS9os6wzmIA/q//wCIqP8A4Ih/9Haa7/4jx+0V/wDOyoAP+IqP/giH/wBHaa7/AOI8ftFf/OyoAP8AiKj/AOCIf/R2mu/+I8ftFf8AzsqAD/iKj/4Ih/8AR2mu/wDiPH7RX/zsqAD/AIio/wDgiH/0dprv/iPH7RX/AM7KgD9Bf2O/+Ct3/BOn9vbWn8K/srftVfDn4l+N47O4v2+Hdx/b3gb4kS2VnE09/faf4B+IWj+FvFWtWGnwr5t/qGh6ZqdnZIQ91PEvzUAfo0CCAQcg8gjkEHuD3zQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQB/nWf8HiP/AAU2+KV78bPDP/BNL4aeJdU8LfCrwf4I8KfE39oO20e9udPm+JXjjxqJtZ8D+CfExt5EbUPBngnwpBpPi2LRJJDpWs+KfE9rqGr2N1deE9BltQD+GIsxxyxxwBvYAAdABngY6AdOBgdgBNxPdugP3m9/f/8AX3oANx9W7j7zYz83+HXH9MgBuOerf99H0z6/565oAAxI6nPPBdux/wA8/hQAbjjOW7fxNzkD3/zz60AJnJHBzzySeuM89Tz7/hkckAU9DkZH69R/nrQA3uOOct3PXH9aAAdeh/h55x2x75/ycc0AKe+fQ/Xtn/J70AKfcdxzn34/Xr7d6AEb3GevTOcZH/66AD+9x2Gffg9P1/zmgA9OO579+efx/rQAcenf1/2hn3680AKCR0yM57kZ5/yc9s8daAAs2T9/1+82D+v8s0AAY8ct1PVjnOM+v88evegA3Hj7/J/vNn69env/AJIABj1yevdm74/x+n55AAbj6t1P8ROeM/59DQB0/gvxv4v+HXi3w3488B+J/EPgzxp4P1iw8Q+FfFvhfV7/AEPxL4a13S7qK807WtB1vTZ7fUdJ1XT7qKK5tL2yuIZ4Zo0bdtBVgD/ZL/4IW/8ABQDxJ/wUk/4Jw/Bf9oL4hC0b4v6TP4g+EfxqudPt4rSx1X4lfDe5ttOvvFEFrbpFaWb+OfD174b8b3unWNvb6fpmpeIb7TtPgjsrWBQAfr/QAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAIeh+hoA/yKv8Ag6jZm/4LdftZbmZtuhfs8KuWJ2r/AMM8fDYhVznaoJJwOMknqSaAP549vuR9D/n6fSgBMZ7noDkHnv8Az6k9zzQAY57+n3h/tc/X09PwNABjJ79v4gf4Tz9ff8aAADp1HB6EevX684z6cUAAX6jp0PsP8/me9ABjkDk8nksM9B+P+HXvQAEcH8uoHofw/wDrn1oAQDnv1P8AED+P1/UdTQAoGSeT0HcHPHf/AOv1oAUjryehPXGMenp6Z7CgAI9z16Z45PT6e34UAIw6+49QO49fyz6cUAGPvcnIxzuGeh/L8aAFwMj6njIx359z+o/CgBMe56+o556n1P8A+qgBcc/Xd3756/Xnr26UANI5br0/vD8sdh9aAFA6devqD2z+OO350AJjgcnr/eHHXke/60AOx15J5A5PXOOv+HfJ9aAEIxnr3zlhz8vf/PHXvQAMMA8k8dz7j/H+negD/UY/4My2Y/8ABKv4nKWYqn7anxYCgkkKD8LfggxCgnABYknHUkk8mgD+tugAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgBryJGu6R1Rc43OwVcnoMsQMn60AQ/a7X/n5t/+/wBH/wDFUASpLFKCY5EkAOCUdXAPuVJwaAH0AFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAIeh+hoA/yKP8Ag6i/5Tdftaf9gP8AZ4/9Z4+GtAH88xOPT8c+o9Pr/nmgBAfp0X9Sfy68UANz349fb+P8f896AFH3u3UdP90/pQAKcAdOh6/X1/z2oAP4Tz6d/ZfrQAmeQeD9768Dvx1/DpQArHgj/wDX1X/H+XvQAgPPbq/8gev9fSgBVBYnAzwp4GfTnGP8P8ACQo5/hPQ/wnqfw6f55oANkn909R2PT8uv+fegBGSQj7p/75P94Y7Ht1oAjz9/p2/PGD/k/j3oAdnkf7zHrz/F2/rQAdu3Xt/vf5+vWgAz9P4zz9f5etADT95/93/D/PvQAo7dP69Pp+vpjk55AEB4X6j+bD/PfPNACg8dQef6r7cnnr/kACHv/wAC7eigfh/kc9aABiSD9AenqR3/AM59BQB/qL/8GZX/ACis+KH/AGer8V//AFVfwPoA/rdoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoA/gT/AOD2b9sfyNO/ZL/YJ8OariS/n1f9qP4rafDNtcWloNa+Gnwct7gRNmSC6upfi5qF3ZXWEE+m6BfLFI6QSxAH+fnQB/ow/wDBj/8A8m9/t6/9ll+Dv/qEeLKAP7l6ACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKAEPQ/Q0Af5FP8AwdQ5/wCH3X7Wn/YD/Z474/5t4+Gv+f1oA/nkP+P8WO/19z/KgBPc56L/ABEdc5PX+f8AWgAznHX6bj/te/PQc5/KgA6nqeo/iPPyk+v455z60AA6dznPfnr9R+J/x5ADPGec8dWxngH6f40AGeRyTkt0bPb1z179eP1oAUnr/wDFf7v+PP8A9egBM8jr1Yfez0H16/j+fWgD+rb/AINMP2QP2Yv2x/2v/wBpXwR+1H8Dvh38dPCnhj9miLxV4d0H4jaFHr+naN4i/wCFr+DNIOsWFvLIghv20u+u7Ezqd5t55I87HdWAP72v+HFf/BIP/pHj+y5/4bi1/wDkqgA/4cV/8Eg/+keP7Ln/AIbi1/8AkqgA/wCHFv8AwSDUq3/DvD9lw4ZeP+Fb2hz8w7Ncsp+jBge4IyCAf41/xY02w0f4ofEfStLtILDTdM8eeMtP0+xtgYrazsrLxPq1paWsCbjshtraGKCJSxKxxquTjNAHAdx16nvxxn39vSgA7Z5646n+9j1oAPU8/wAX8R7HHr/+r1oAQnluvT+9+PH6nvigBR269f72e2eeeen09qAGgjjJP/fZ9+v+e9AC5z+fqT3Xvn3P8vXIAmev/Au5OflHvz685xQAN0P0B+8T1P4/iaAP9Rf/AIMyv+UVnxQ/7PV+K/8A6qv4H0Af1u0AFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAf4rX/AAWx/bG/4br/AOCnn7Wfx703Vf7W8CP8R734bfCaeKbztPf4V/CaKP4feDdT0xQzLBa+LLPQZPHM8KMR/afijUJiS8rGgD8rKAP9GH/gx/8A+Te/29f+yy/B3/1CPFlAH9y9ABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFACHofoaAP8ij/g6i/5Tdftaf8AYD/Z4/8AWePhrQB/PKQT39ewPfP+H8z7ACDJ/JT0+v4Z/wA+9ACdx07g8f73Ufn0989qAD+L8s/XaevPXr04980AKBkD6Htnv7/oPxPSgBP4eo7ZyM9h1/8A1Ht70AHpznO7n6j2yOvX1P40AK3Q5/Hj6fn09fY9KAGgc9c8t24zjn+mentnrQB/aT/wZNf8n1ftZf8AZpMX/q6PANAH+lZQAUANbp/wJP8A0NaAP8Fz418/GD4rf9lI8eZ4z/zN2te9AHmOOQeOrdv949f88880AHPH1x04+99f/r+/NAC//Zds9/f+XfmgBpHzNz2547e/6dMn6UAKOq++T09u3oD+B9aAE+bjn6cDPQ//AF+p9e/UAB+HX0Hcp/jQAdOM/wB78flB5/r1yefegBCCM5Pb+o9+np+PTuAf6jH/AAZlf8orPih/2er8V/8A1VfwPoA/rdoAKACgAoAKACgAoAKACgAoAKACgAoA4j4gfEz4b/Cfw9c+L/in8QfBHw08J2eftnij4geK9B8G+HrXClz9p1rxHf6bpsGEVnPm3K4UFjwCaAPzC+Iv/Bev/gjn8Lrh7XxN/wAFC/2dtSljdo3Pw88S6h8Xody5ztufhNpPjW2deDh0mZD2Y5GQDxSL/g5q/wCCHE121kv7d2gCZSMvL8EP2m4LQ5JHy383wVjsX6clbkgdTgEEgH0p8LP+C3P/AASR+M11ZWPgb/goP+zGL/UXWKw0/wAa/EbTfhZqN3PJxHbQWHxRHg68ku5WISG0WE3MshEccTSEKQD9MfD3iTw74v0ex8ReE9f0XxR4f1OLz9N13w9qtjrWj6hASQJrHU9NnubK7iJBHmQTyISCN2RQBtUAFABQAUAFADSyjqy59yKADev95f8AvoUAKCDyCD9DmgBaACgDkvHHj7wL8MvDOpeNfiT418JfD3wdo0ay6v4t8ceI9H8J+GdKidgiSalr2vXlhpdjG7kIr3V3ErMQoJJxQB+T/wASv+Dgj/gjN8J9UvNH8U/8FA/ghqV5YErcP8OD4x+MmnMylgRa6z8IfCvjnSL4gqQRY31wen94ZAOB0T/g5S/4Ih+IJYYrD9vTwZbvO6Ih1z4WftA+GYlZyFBmn8SfCXSYbdAT88lxJFHGMs7KoJAB+nv7N37X/wCy3+2H4Z1fxh+y38fvhV8evDvh69tNN8R6h8MfGWjeKW8Nalf2z3ljp/iSy0+5l1Dw9f3trHJc2tnrNrZXFxDFLJDG6xSFQD6NJA5JA9ycUAJvX+8v/fQoAN6/3l/76FADqACgBkkkcUbyyukcUaNJJJIwSOONAWd3diFVFUFmZiAoBJOBQB+cvxr/AOCv3/BLz9ni91HSfi3+3l+zF4e1/SJHh1bwtpfxV8N+N/GOlzx/ft9S8HeA7vxN4osbkdre60iKZuqoc0AfIM//AAcy/wDBDu2vVsJP27/DjTsSBJB8Fv2lrqy4OPm1K2+DM2nJ14LXQB5IyATQB9FfCX/guB/wSP8AjbeWmn+Av+Cgn7NQ1G/nS2sdO8c+PLf4Taje3UjbIrWzsPivB4Ku7q6nchILeCGSad2VIUdmUEA/T7Rta0fxFpdjrnh/VtM13RNUt0vNM1jRr+11TS9RtJRmO6sdQspZ7S7t5Byk9vNJG45VjQBp0AFABQAUAFADd6/3l/76FABvX+8v/fQoAcCDyDn3BzQAUAFAHh/xr/ab/Zv/AGbNJh179oj4/fBf4E6Ncqz2mp/GD4n+CvhvZ320suywm8X63pC38rOpjjhszPNLL+6jR5CFIB+YvjL/AIOK/wDgir4EvrnT9b/b9+Fd9PakiWTwb4b+KvxFsnIJH+jan8Pvh/4n028HBw1pdzqRggkEZAKPhj/g48/4Im+LSg0r9vn4c2nmEBf+En8DfGjwUBnp5h8Z/DTQREPUylAOpIoA+8/gH/wUL/YU/alnhsf2d/2vf2dfi/rM8nlp4Y8E/FvwVqvjFXJwon8GLq6eK7YSnPkNc6PEs4BMJkAJAB9i0AFABQAUAFABQAUAFABQB8tfHX9uH9jP9mF2t/2iv2rP2ePgjfhd6aP8T/jD4B8G+ILrKeYFsfD2ua9Z65qMpjzIsNjp9xKyAuEKgmgD86vE/wDwcff8ETfCN1cWeq/t8/Du7mtWKyP4Y8CfGrxtasR1Nvf+DPhnr9jeL6PaXE6t2Y0AUfD3/Byf/wAERfE1xBbab+3r4JtpLlwkbeIfhh8ffCVurN0Nxd+K/hPotrap6yXU0Ma/xMKAP0A+Bn/BRD9g39pm6t9O+AP7Y37Nfxa1u5dI4vDPgv4y+A9W8X+ZLjykl8Hx64PFEDSk7YhPpMZlYMqbmVgAD7IoAKACgAoAQso6sAfcgUAJvX+8v/fQoAN6/wB5f++hQAoIPQg+uDmgBaACgAoAKACgAJA5Jx7k0AN3r/eX/voUAG9f7y/99CgA3r/eX/voUAOoA/Hb/gut+3t4T/YF/wCCbn7Snj0ePPD/AIa+Nfjr4a6/8MvgB4cn8Qadp/jPX/iF8Qhb+B4PEHg3RZ7qHUtal+Glp4jn+ImryWME8Gn6d4bllvCokijmAP8AGQoAKAP9GD/gyAIH7Pf7euSBn4y/B3qcf8yR4s9aAP7lt6/3l/76FABvX+8v/fQoAN6/3l/76FADgQeQc+4OaACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKAEPQ/Q0Af5FP/B1AM/8ABbv9rTqf+JH+zx0/7N4+GvrQB/PKefX8CPX60AJj69vTt/nnPXtQAY/3vzH+1+vP8vegAxznnt3HoR9e/PvQAYwOM9/TPX8v/rZ70AGOCOe3pnjH+H86ADHs3Ge47/j+Xv19aAAjOc5P/wCsep9v5nuKADHf5s5J7dSP849+tAH9o3/Bk1/yfV+1l/2aTF/6ujwDQB/pWUAFADW6f8CT/wBDWgD/AAXPjVz8YPit1/5KR486df8Akb9a9aAPM8c9+pPbGTn8e9ABjjv1z2z1z/n296ADH179/U5/P0/WgBCOSeeeO39aAADp14+npjnk/pQAY6deMdx6H39+ffHagBMYx169yPY/0/IHvigAxnqG5z6dx9fbAznnrQAEZByDnHXjsc+p59fXtQB/qLf8GZX/ACis+KH/AGer8V//AFVfwPoA/rdoAKACgAoAKACgAoAKACgAoAKAPm/9q39rr9nP9iL4NeIvj7+1D8U/Dvwm+GHhwx282ta5JPPf6zq9xHNJYeGvCXh7TYbzX/F/irU1t520/wAOeHNN1LVrmG3u7sWq2VleXMAB/nqf8FKf+Dw39qL406n4j+HH/BPLwtD+zB8KPPuLC1+MfjDTdF8WftBeK9PBMf2+w029Gs+APhZbX8LyobGys/G3ii0222oab430a7MlpCAfyNfGX48/G79orxld/EP4+fF74lfGjx1fbxceLfij428R+OtfMTuZPssWp+JdR1K6trGNji3sLaSGyto1SG3giijRFAPJ6ACgAoA+nf2aP20/2tP2N/E0fi79lv8AaJ+LfwN1f7ZDfXsPw/8AGmsaPoGvTW5QxxeLPCIuJfCfjGx/dxiTTPFWi6xps4jRZrSRUUAA/tk/4Ja/8HjlzqGr+Hfg/wD8FS/B+mWltf3FlpNh+1f8I/Dz2VtYPK0cJ1D4x/CfTDPELQyNLcah4q+FVtbpZRiC2g+F8sf2rVYgD+8rwH4+8D/FPwZ4Z+Ivw18X+G/H3gHxno9n4g8JeM/B+taf4i8MeJdD1CITWWraJrmlXF1p2pWF1GQ0VzaXEsTcjduVgADraACgAoA/xbv+C7n/ACmG/wCCh/8A2cv44/8AQrSgD8mKAP7+f+DHn4uYk/4KC/Ae9uvvJ8Bfi54bst/TY3xI8G+Nbryyec+Z4Ai3oOMYkPMdAH9/9AH8f/8AwWm/4Oo/hL+xXrXin9mr9hay8I/tCftN6Fd6h4f8efEXWJLnUvgd8FdatWltL7R1bSL2xuPij8QtIuUeC/0XSNUsfCXhfUU+za9rur6xp2s+DYQD/O2/ax/bn/a6/bl8c3PxC/au+P8A8R/jTr0l9c32m2XirXrj/hEPCzXZbzbTwP4C077D4J8C6bhmA03wloGj2RLSSPA0sssjgHyhQAUAf6cf/BlX4C/sT/gm7+0L8QJ4fKuvHn7Y/inSreQrzc6L4J+EHwgjs5g/8SrrPiHxFbheQrQOc5cgAH0B/wAHgn/KHrVP+zl/gf8A+g+MKAP8pygAoA/3FP8AgmZ+0I37Vn/BPj9jT9oS5vv7S1r4m/s6/C7WfF92ZPOLeP7LwvYaH8RITNktK1p460vxDaNI+JHMBaREkLIoB+a3/BZv/g4S/Zl/4JQ6bcfDLRbOy/aB/bD1XTYLvR/gZoeupp+leAbLU7QXWl+KfjV4mtYNQfwrp1xbSwalo/hCztp/Gfiq0ms54bbQvD+pR+LbYA/zWf29P+Cyv/BRD/go3rGrn9oz9oPxQfh1qF7Pc6f8CPh1c3XgD4IaJavIz2tgvgXRLtY/FJ05WeGy1z4hX/jLxUsTyJLr8yyOCAfl1QAUAFAH2r+x7/wUX/ba/YI8TweJ/wBk79o74lfCNRqEWpap4Q0vW5NU+Gnie4iZCf8AhL/hhr66p4C8T7408jz9Z8P3d5bxPJ9jubaRvMAB/oZ/8EYf+DqP4N/tv6/4U/Zs/ba0nwr+zl+094hu7LQPA/jfR7i7tPgT8Z9dudkFno1rPrd7fX/wv8eavcsLbS/DniDVtV8N+JL8x2eheKbbXdV0jwhKAf14UAFABQAUAf4N/wC0h/ycR8ev+y0fFL/1ONdoA8XoA/0sv+DKT9oT/hNP2Jv2of2bb+++06n8CP2gNK8f6XBJJ+8sfBvx08Hw29jYwRk/8eqeLvhX431JmUEi61mYSNhohQB/Tp+3Z/wUD/ZX/wCCcXwT1H47ftV/Emy8E+Gla5sfCnhuzSPVviD8TPEkFv8AaIvCPw48IxzwX3iTXZw0RuH8y00TQraYat4o1nQtEiudTgAP84j/AIKPf8HZv7fn7WOq614N/ZRvp/2IvgZIbuytf+EF1C21b49+KLByY477xH8W5bGG58G3MqpHeWun/Cuz8LX+jyzT2F34v8UwpHdsAfy5+LvGPi7x/wCItU8X+O/FXiPxt4s1y5e91rxR4u1zU/EniLWLyU5ku9U1vWbq91LULmQkl57u5mlcnLOTQBzlABQAqsyMrqxVlIZWUkMrA5DKRyCDyCDkHkUAftV/wT+/4OAf+CmP/BPC70zR/h18cNQ+Lfwfs5o/tPwJ/aAm1X4l/D4WYcGS28MXt7qlr42+How08sUPgTxVoOky30xvNW0jVyDE4B/pS/8ABIT/AILh/sqf8Fa/h8kHgu+g+FX7TPhfRor/AOKH7NninWLa48S6XHF5UN74r+HuqNFYp8Rvh2buRIv7d02ytdX0GSeztPGGg6BNqGkPqgB+1FABQAUAFABQB+Ev/BW3/g4B/Yz/AOCU1jf+BdfvJvjr+1Vc6TFqHh/9nLwBqtrb6hpC39v9o0vVPi54ya31LTPhfoV5C0NzbW9zY63421SyurPUdF8Gaho88urWwB/nfft4/wDBxv8A8FSP27NT1vTdQ+O2r/s6/CPUvPtrT4N/s13+r/DPRP7KlLo1n4n8Z2Gov8SPG73tr5UWsW2v+LJfDV5Ksslh4Y0i2uJLMAH4UXFxPdzz3V1PNc3NzNJcXNzcSPNPcTzO0k0880jNJLNLIzSSSSMzu7MzMWJJAIaACgBQSpDKSGBBBBIIIOQQRyCDyD1zQB+y/wCwv/wX1/4Kg/sCajpNr8NP2jfEvxO+GWnG3hl+CH7QV7q/xb+GUumW5BTS9Fg13VU8WeAbQctj4b+KvCBkkYtdfakZ4nAP9D7/AIJBf8HG/wCyH/wVGl0n4SeIoF/Zq/a4ks0z8F/GmvWd74e+I91BC0l/c/BPxzJFpsXi2WKNGvbjwXq2naJ44srb7XLYaX4k0fSNR8RKAf0RUAFAH8e3/B1v/wAEcf8Ahrb4Ev8At9/s/wDhX7X+0h+zX4UnX4r6Bolnu1P4v/s/6R9p1LULsW8CF9S8ZfCAS33iLSmAW91bwPP4o0YvqV9pHg7S4wD/ADEKACgD9Qf+CQf/AAUq8ff8Esf21vh5+0f4c/tPWfh1eOvgX4+/D6xnCr8Qfg7r99Zt4jsLeCWWG2bxN4cntrPxh4JuZpreOHxRoWnWt7cDRb/V7a6AP9nr4WfFDwD8bfhr4D+MHwr8T6Z41+G3xN8JaD458DeLNGlM2m+IPC/ibTbfVtG1S1Z1SVFurK6id7e4jhurWXzLa7hhuYpYkAO9oAKACgAoA/zK/wDg7O/4K+/8NPfHdf8Agnl8CPFH2r4C/s1eKZbr4161o15nT/id+0LpiXOn3Xh95oHZb7wz8F0nvtBWFmS3vPiJeeKJ7m1u08LeFtUAB/G3QAUAf1Pf8G5H/BO74L+IPEniv/grJ/wUC1/wr8MP2D/2LfEGnXvh3W/iZItj4S+J/wAfbW801vDdr9nmimm8R6D8O9U1HQ9QbRNOtry68ZfEfU/BPgzS7HxCF8VaGgB+pv8AwU0/4PKr+7/4SD4V/wDBLv4eHTYD9q06T9qb41+H4ptQkHzxDU/hZ8GtQEtpaDcEutM8QfFb7bJLFJJban8LLOZUuAAfw7fHf9oT44/tP/EjW/i9+0P8V/Hfxl+JfiF86p4y+IPiPUfEesPbpJJJb6bZS380sWk6JYebJFpWg6TFY6LpFsRaaZYWlqiQqAeO0AFABQAUAFABQB/rO/8ABpR/yha+Df8A2V39oD/1ZWq0Af0t0AFABQAUAFABQAUAFABQBy3jbxv4O+G3hHxH4++IPinw/wCCfBHhDRtQ8ReK/F3ivV7DQPDXhvQdKt3u9T1rXdb1Se107S9L0+1jkuLu+vbiKCCNSXfJAIB/Lb8ev+Dw7/glf8JvF2peFPh9oP7SX7RMGl3txZy+Nfhf8PfDOheBb5raZreWTRdQ+KXjfwR4h1W38xJDDfJ4Wt9PvIfLuLK6uIJUlIB4N/xGwf8ABPr/AKNc/bO/8FHwO/8Anu0AH/EbB/wT6/6Nc/bO/wDBR8Dv/nu0AH/EbB/wT6/6Nc/bO/8ABR8Dv/nu0AH/ABGwf8E+v+jXP2zv/BR8Dv8A57tAAf8Ag9g/4J9EH/jFz9s7/wAFPwO/+e6f60AfxB/8FlP25/hx/wAFHv8AgoT8bP2vPhP4S8ceCPAvxM034W2mkeG/iNFoMPi2xk8C/C7wl4F1J9Ri8M6vrujLHeanoF1d2C22q3TfYJoPtBjuPMjUA/L0j/d79R7/AP1+ff60AJ+XRevTvzjj8KAEHUdD/L+P9P59aAFHJ6dx29VPH/1qABeg6Hg9f971waAAdO3br/ujuQf5f40AHcdOrdBgHj8fx/KgAbgHp/nb/k/hQAg6jgdXH6d/zoA/tI/4Mmv+T6v2sv8As0mL/wBXR4BoA/0rKACgBrdP+BJ/6GtAH+C58a/+SwfFbp/yUjx4ef8Asb9aoA8y7j/ebnv/ABf560AHYcDr19Pm6f5//WAJ6/R/5nv/AJ60AIRy/Tt1Hr6e/wDM0AL3HTv268Dof5njPpQAmPu/d5x29j155/x/UAUfUde31Xvjr/X6cACevT+Lt/sj8vf3/OgAPQ9Og6Y9Rzn0OeM/p3AP7DP+CCv/AAcVfsrf8Eov2M/GH7N3xp+Cv7QvxC8XeIf2gPGnxbttd+Fll8N7rw5DofiXwZ8PPDlpps7eLfHXhnU11a3u/B9/PdrHYy2Zt7mzMN0ZRcRqAftp/wARsH/BPv8A6Nc/bO/8FHwP/wDnu0AH/EbB/wAE+v8Ao1z9s7/wUfA7/wCe7QAf8RsP/BPr/o139s7/AMFHwO/+e7QAf8RsH/BPr/o1z9s7/wAFHwO/+e7QA5f+D1//AIJ8l1D/ALL37Z6qWUMw0f4HsVUnDMF/4W8NxUZIXI3EYyM5oA/YD/gnZ/wcBf8ABOP/AIKV+LLf4X/Bv4i+Jfh58bL61lu9J+Cvx08PWngPxx4lhtYZbi+/4Qu9sNa8R+CvG15ZQQXN7caJ4b8VXviWHTLe41OXQksLe5uIQD9ss55ByDyD1znvQAUAFABQB8h/t1fttfA3/gnp+zJ8Rv2p/wBoPXX0vwP4CsFTT9F09raTxR4/8ZaissXhb4eeCdPup7dNU8V+Kb+M29nC80Nlp1lFqPiDW7vTvD2javqdkAf49f8AwVA/4Kk/tK/8FVP2hNW+NHx01250vwjpd1qNj8HPglpGqXlx8P8A4N+D7iZPK0jQbSUW8Wp+JNSgt7Ofxn44u7KDWfFuqQxySx6dolhoPh/RQD816ACgC9pumalrN7BpukaffarqN0xS10/TbS4vr25cKXKQWtrHLPMwRWYrHGxCqWPAJoA9avP2b/2iNP0lNfv/AIC/Gix0KUMYtbvPhb44ttJkCgMxTUptCSzcKCCxWY4BBPWgDxuaGW3llguIpIJ4JHhmhmRo5YZY2KSRSxuA8ckbhkdHAZWBVgCCKAI6ACgD+lX/AIN7f+C7Hj3/AIJk/Grw/wDA342+KtW1/wDYN+KniZbTxxoF8brV2+BXiPXZlgT4weArdfOvLHTLe9eGb4l+F9LSWDxDoJvtcsNLvPF2m6ct8Af6yGia3o/iXRtI8R+HdW03XvD+v6ZYa3oWuaNfW2p6RrOj6raxX2matpWpWcs1nqGm6jZTwXljfWk0ttd2s0U8EskUiuQDToAKAP8AFu/4Luf8phv+Ch//AGcv44/9CtKAPyYoA/q1/wCDOj4uf8K//wCCteoeAZ7rZa/Hb9mH4ueA7ezd8R3Gt+F9V8FfFuzuETI33Vpo3w88RRxnnbbXl7xzuUA/dP8A4Okv+C82ufs42esf8E4f2N/G93oXx08S6NbP+0z8WfDF61tq/wAJfBniTS473TvhZ4Q1W3YXOmfEbxrol/a6v4l8QWUkF54M8H32nWmj3B8R+Jpb7wiAf5vBJJJJJJJJJOSSeSSTyST1NACUAFABQB/rc/8ABqB4C/4Q3/gif+zxrbQ+TN8TviD+0D49mBXa8nkfGTxd8PreZwcH97ZeArV4mP37cwupKMpIB5T/AMHgn/KHrVP+zl/gf/6D4woA/wApygAoA/tS/wCCeP8AwcSeDv8Agn5/wQHu/gX4N16y1z9ubwR8YPix8Kv2ffAOpadc6jbeEvA3xDvI/ilF8dvEjXdpJod34X8HeIPHPjbTtD8O3FzdXeveMtL0jSbzRx4Vk1XUrQA/jd+IPxB8cfFfxz4t+JnxL8V6946+IPjzxBqnivxl4x8Ualc6x4h8S+I9bu5b/VdY1fU7ySW5vL6+u5pJppZXJy21QqKqgA4+gAoAKACgAoAUEqQykhgQQQSCCDkEEcgg8g9c0Af6V/8Awauf8FxvE/7WHh4f8E7v2sPFs3iH4+fDDwhcaz8Afih4i1OS58Q/GP4ZeG4l/tjwP4nvL52uNb+I3w20vytR0/V/PudU8XeALbUL7V4f7T8Ea1r3iIA/tIoAKACgD/Bv/aQ/5OI+PX/ZaPil/wCpxrtAHi9AH9IH/BtF/wAFRPgp/wAEwf2qf2hfGv7SnifVvD3wW+JP7Mfimxe20PQ9X8Q6rr3xW8BeItA8W/DjQtN07SbW6X+1fEGmjx14V0e61aTS9CtdV8R2U2ta7o+mrdXagH5kf8FMf+Ckf7QH/BUL9p3xX+0R8ctauodOa61DSPhL8L7W/muPCPwc+G/2+WfRvBfhq3KW8Et0sHk3PinxK1pb6l4u1/7TrGoLEjWdjYgH57UAFABQAUAFABQB7R+zt+0H8W/2U/jf8NP2ifgV4uvvA/xX+Evimx8W+DvEdid3kX1mXiudP1K0YiDVtA13TZ73QvEmhXqy6dr2galqWjalDPY31xC4B/s7f8Epv+CiHgT/AIKhfsUfC79q7wdpsXhnW9b+3+D/AIseAo7sXp+Hvxe8Ji2t/GXhiO53ySXGkz/a9O8UeE7q6KX974L8SeHL7Urez1G5urK3AP0aoAKACgD+U7/g48/4L7wf8E3vBsn7KH7Lmrabqn7bPxP8L/b9S8Sr9j1PT/2afAutxNFY+LtUsJhcW178T/Ets0tx8PPDOoQyWuk2Kp478TWsulv4Y0fxgAf5bPizxb4p8e+J/EHjbxx4k13xj4y8WaxqHiHxR4r8Uatf694j8R69q11Je6prWua1qk91qOq6rqN5NLdX1/fXM91dXEsk00ryOzEA56gAoA7bwh8NPiP8QZTD4C+H/jbxvMJfIMXhDwprviWUT4VvJMejWF64l2ujeWRvw6nGGBIBe8ZfCH4s/DkOfiF8L/iJ4ECOsbnxl4K8S+GAkjsERHOt6ZY7XdiFVThmYgAEmgDzugAoA0dI1fVvD+raXr2g6pqOia7omo2Wr6LrWkXtzpuraRq2m3MV7p2qaXqNnLDeWGo2F5DDd2V7aTRXNrcxRTwSxyxq4AP9R3/g2f8A+C7d/wD8FDPh7d/sjftW+LLO5/bM+EOg/wBo+GfFuoG3sbv9ov4WaXFBBN4ikVPKt7v4peCCY4fHdtbRQz+ItDmsPG9rBeTw+NptJAP6yqAGuiSI8ciLJHIrJIjqHR0cFWR1YFWVlJDKwIIJBBBoA/yeP+DmT/gjo/8AwTi/am/4Xv8ABTww1j+x3+1Dr+r6z4LtdMtWXSPg98VpRPrPjD4PSeSn2bTdDu1N14t+F8DC1R/C7ax4X0+C4HgC/v7kA/mQoAKAP7y/+DQj/gr1/wAI3rs//BK34+eKNmgeJ7vXPGH7IGv61ebYNI8Tzm613x78DluJ38uK08Ut/aPj3wFbt5Ea+JU8aaMs95qPirw3psQB/oW0AFABQB/PF/wcbf8ABXS2/wCCYn7G954Z+F/iCC2/a7/aWs9d8DfBCC1njbVPh9oaW0dt45+N1zBkm3Hgyy1C307wY04K3vxA1fQ7lbTVNJ0HxLDbgH+RXc3Nze3NxeXlxPd3l3PLc3V1cyyT3NzczyNLPcXE8rPLNPNK7SSyyO0kkjM7szMSQCCgD70/4JqfsAfFr/gph+198Mf2VfhNFNYv4ovTrfxG8cvZSXulfC74U6HcWr+NviDrKK0UTppVncw2GhafPc2a+IfF2q+HfDEN3b3WtQSqAf6MH/Bwx+zf8Jf2Q/8Ag3G+J/7NfwL8NQ+FPhX8H3/Zj8I+FNKQxyXc0Fr+0J8OZ9R1zW7yOKE6p4m8Tavcah4j8Ua1LGtxrXiHVdT1W5Hn3clAH+VXQAUAFABQAUAFABQAUAf6z3/BpT/yha+DP/ZXP2gP/Vl6tQB/S1QAUAFABQAUAFABQAUAFAH8BX/B6j+3B4/0HVP2bf8Agn34S1u70PwN4u8EP+0p8Y7GyuJbf/hOUXxlrngr4S6Dq5hmj+16B4d1zwZ438UT6PepPp994hi8L6s8JvfDdjJGAfwAMSx3HBJ5ZiWJJJPJOcknuTznjrgUAAx/s9+57j6n88/rQAgx146N3Oe/bP8AnmgAHX+HuOp649ckd/8A9RIyAHGO3Udzjoeeuf8APqDgAT/vn8z1/wC+v8ffGeAAP/AT+J/qf89enNADjg/3e/Un1J7Hv+f9ABDjnp0Xuefrz/8Aq7+tABxkdOh5yf8Aa9+nr/8AXoAXPP8AXPP3f979e+etAAMEduh6k46/Xj19/wA6ADII/LjJ9B2zn9D0oAOOOn8Xc4zj6+/P5jqMgCnHPQ/ie+3qc/rn+tADR1/h/i7nHTHr39+1AH9pH/Bkz/yfT+1l/wBmkRf+ro8A+tAH+lbQAUANbp/wJP8A0NaAP8Fv41/8lh+KvT/kpHjzgk8/8VfrXuP6/wBaAPMuNw6dT3Oc5Pv3/XPvQAnp06joT/ePbOTz7HvQAvHPTo3Un+99e/fue1ADT1bgdfU89ffr+H1xQA4fw9Ordz+nJx7g4PtQA38ufc+h6/N+H8+oBAFH4df9r1X1/wA5x2zQAfl/F3Pp9eff8x60AIcYPQ8DuT3Hv0/Ud+vIAdyeDwe/PT/eOf8APPoAKPvHp198/eHvj+ue2OoAccnj8zn7w7k9ffuehPNACDtwPfk9j67v54/GgBR34H6+jdyf1zjrzQAh7fd6epHc+pH60AdB4V8T+IvBXiTw/wCL/CGu6r4X8VeFtb0jxJ4Z8SaFf3el634d8R6Hfw6lomv6LqljNBe6bq+jalbW+o6bqFpNDd2l1bxSwyoy0Af7Xn/BI/8Aa5179uz/AIJvfskftUeLhbf8Jt8T/hiIfH89lBFa2d/8RPAPiPXvhn8QNWtLOEmKytdY8Z+Ddc1W3sYzssobxLVeIqAP0ZoAKACgD/Jd/wCDm7/gq3qX/BQf9t7W/gz8OPEU8/7LH7Iuu+Ivhx8P7SwvWfRfiF8TLG7fSfiZ8XZ44JHtNSivNVsZPCPgS98y7t08FaLFrmlNYy+NNdgmAP5qaACgD+0L/ghN/wAGtt9+2D4L8Jftff8ABQaTxX4C/Z38W6fp/iP4PfA7w1qTeG/iF8ZdAuzHd2PjPxtriQy6l4D+GOuWWG8P2Ojmx8deM9Ou18Q2GreENCGh6n4qAP8AQe/Zw/Yz/ZP/AGQfDdt4T/Zi/Z2+EHwO0i3sINNmk+HngbQdC1zWLe3RESXxP4qgsz4o8XahJ5aPdav4o1jV9VvZVE15ezzfOQD6YoA+B/2xv+CX37BX7e3hvW9C/af/AGZfhf4+1fWbVreL4lW3hyw8M/GLQpVTFteeHviz4ch03x3pkltKsU5sRrc2i6gYIrbWdL1Ow8y0kAP8zP8A4Ltf8G/vxR/4JNeJrb4ufDTWNb+MH7FHjrxFFoHhL4h6tHZt46+GPibUILm7sPAHxct9Ks7DTpZ76CzvP+EZ8eaPp9hoPiQ2stlfaZ4b1trLTNRAP5y6ACgD/Sb/AODOf/gpXrHxs+BPxL/4J6fFrxbda346/ZttLb4gfAWTWr03Op3n7P8ArV7a6Nr3gyyllZ7mfTvhN42u9NOnC4kkay0D4jaLoGmLDo3hm1trUA/tdoAKAP8AFu/4Luf8phv+Ch//AGcv44/9CtKAPyYoA+rf2IP2xfiv+wF+1J8Kv2ufghaeFL/4n/CC78T3Xhmw8c6fq2q+Er0eL/BHiXwBrVrrmnaHrnhvVLy0m8P+K9VRYrXW7E/aDC8rywrJBKAeFfEz4k+OvjJ8RPHPxZ+J3ibU/GfxF+JXizX/ABz448WazMJ9U8ReKvE+p3Osa5q99Iqonn32o3dxO0cUccEIcRW8UUKRxqAZHhPwj4r8e+JdE8GeBvDHiHxp4w8Tajb6P4c8KeE9F1LxH4l8QateOI7TS9E0LR7a81TVdRupCI7eysLW4uZ3IWKJmOKAP6n/ANjP/g0B/wCCkv7Reh+H/G3x88RfDH9jbwdrkMN2dD+IT6r47+Ndrp9zh4Lqf4X+Elt9D0yd7f8AezaJ4t+JPhXxHYSslpqej2V0LiO2AP238G/8GQv7L1jHEPiD+3J8e/E8oQCd/Bvw3+HngWOSTHzNFHrd78RWhQtkhHlnZR8pkY/NQBl+P/8AgyB/Z51DTrlPhb+3h8Z/CerHJtLnx/8ACTwR8QtOTAOEubLw74j+GNzJuOAZYr+LYMt5Mh+UgH9XP/BOD9kFv2B/2If2d/2QZPFln47ufgf4Mu/Dd/4y0/R5vD9l4m1PUvEuu+J9U1i30S4v9Um0xL3Uddupvskuo3rxMxBuZvvkA/Eb/g8E/wCUPWqf9nL/AAP/APQfGFAH+U5QAUAFAH6U/wDBMf8A4JV/tU/8FWfjbN8I/wBnPQbDT9B8M21rq3xU+MfjP+0rH4ZfCvQrt5ks5vEOq6fYahdX3iHXZLa5tvCfg/R7W71zxBc215dCKx8P6R4g1/RgD/Q5/Yz/AODSD/gl3+zxoHh2+/aA0Lxj+2T8VLGGG51rxD8RvEWveCfhs+srgyP4e+FHgLXNMtk0UAbE0jx54k+IfmlpZbi5fdBDbAH7J+Gf+CTn/BLvwfAYPD3/AATq/Yist0TQPcTfsu/BbUtQlhdSjxT6nqvgy91GeN1JDpNdOr5O4HJyAfP/AMdf+CBP/BH39oHw7qXh/wAUfsF/AbwQ9+Gkh8QfA3wrD8BPEml3m1hFe2Go/CJvCEbtA7eaLDUrXUdGunVV1DTLyHMRAP4kv+C0H/Bqn8T/ANiXwf4z/af/AGHvE3if4/fs0+DdKufEnxE+Hfi77BdfHb4SaBZJ5ureJIJ9B0rSdH+KHgTRoVm1DWdR0rR9C8VeFNHU3ep6Fr+j6Xrvi20AP496ACgD174BfHT4m/syfGr4X/tBfBrxHceE/ij8IPGmh+O/BWuwbnW11nQrxLqO3v7YOialouqQrNpWvaPclrLWtEvdQ0m/jlsr2eJwD/bZ/YB/a98Jft6/sa/s9ftc+DLWHTNM+Nfw803xHqmgQ3Yv08KeNLCe68O/ELwb9u2xtef8Ih470bxH4bF48UD3i6Wt20EBn8pQD7BoAKAP8G/9pD/k4j49f9lo+KX/AKnGu0AeL0AFAEkUUs8scMEck000iRQxRI0ksssjBI4440Bd5HchURQWZiAASaAP7XP+CUf/AAaDfFL4/wDhrwh8d/8Agov428R/s/8Aw38TaXZ+INB/Z78CRWsHx81fTL+FbrTpfiHrfiLStR0D4SrcQPb3MvhgaJ4s8Z/ZribTtch8Ba5bSRIAf17/AAK/4N5/+COPwA0WDSfDv7C/wi8f3SiJr3xB8dbXU/jrrep3MS7TdT/8LR1DxNo+nmXrLZeH9I0bSi3zLp6HOQD6wuf+CWP/AATHvNKTQ7n/AIJ1fsLy6REGEOnH9kv4Cra25YAF7aJPAKi3l4B86Dy5QQGD7gDQB+Vv7Zv/AAav/wDBJ/8Aal8Oa9J8N/hJc/shfFS/jkm0f4ifAPUdTsfDtjfqHa2i1b4N61qd58M73QfObdf6f4a0fwXrd1APItPE+mERyxgH+bZ/wVA/4JeftIf8EqP2ibz4F/HvT7bVtD1uG/174P8Axe8P286eCPjB4ItbtLb+3tD895p9I1zS5J7Wz8Y+DdRmk1bwtqk8CtNqeh6l4f8AEOuAH5u0AFAH9p//AAZeftl6/wCAP2vPjh+xHrWpb/h9+0H8Nb34r+ENPuLhj/Z3xf8AhG9kt6NJtiRHGfFfw01bxDceIZl3Tzj4feGUCGK2kdAD/SpoAKAPgX/gp1+3l4G/4JsfsUfGr9rXxrb22sXfgXQ49M+HXg24ufsz/ED4r+J5ho3w+8HIyOt0LK+1y4iv/El1ZLNd6R4P0zxFr0dvOulPGwB/iqfG/wCNPxL/AGjfi98R/jt8ZPFOoeNfij8V/F+teN/G/ibU5C9xqeu65dyXdz5MWTFY6bZq8en6PpNosWnaNpFrY6TptvbafZW1vGAeWUAe4fs3/s4/Gb9rf43fDz9nX9n3wRqXxD+LnxR11NA8I+F9NaCA3E4gmvdQ1HUtQvJYNP0XQNC0q1vdb8Q69qlza6Xomi2F9qmo3MFpayyKAf6dH/BLL/g1a/Yf/Y38LeFPiB+1v4W8M/tj/tOPp8F54h/4T3Tk179nvwPq86+ZcaR4D+F2s2MemeL4dNLrZ/8ACWfE/T9cvNSuLVdb0Xw74Ie4OlwAH9QPhfwp4W8D6Dp3hbwX4a0Dwh4Y0eAWuk+HPC+jadoGg6XbKSVt9O0jSba00+ygUkkQ21vFGCThaAL+raRpWv6ZfaLrumafrWj6nbS2epaTq1lbajpmo2c6lJrS+sLyOa1u7aZCVlguIpIpFJDqQaAP5x/+CnP/AAbG/wDBPr9uzwr4j8UfBr4f+GP2Pf2lV0y9m8MfEH4NeHdP8L/DbxHrqpJNZ2vxV+E2h2tp4X1fTr67eT+1PE3hWw8OePBNcLqN3rWvwWS6HeAH+XN+19+yL8d/2F/2hPiD+zJ+0f4Qfwb8UvhzqENtqVtDcDUND13SdQt47/QPFvhPWo0jg13wp4m0qe31PRtTiSGUwzPZ6laadrFnqOm2YB80UAes/An44/FD9mn4x/Df4+fBbxZqPgj4p/CfxZpXjPwV4n0yRkn0/WNJnEixXMWRFqGk6lbtcaVruj3iy6drmiX2oaPqdvc6ffXVvKAf7c37Bv7XXgb9vH9j/wCAP7Wnw+MEOh/Gj4faV4j1DR4LgXTeE/GVq02i/EDwRczgky3ngrxxpniDwvczHi5l0o3Ue6GaN2APrmgD5G/bq/Yv+D3/AAUE/ZZ+LH7KXxw037T4N+JugSWllrltbwTa74D8YWDfbfB/xC8LST4W38ReENditNVs1Z1tdSgiu9D1VLnRdV1OyuQD/Fl/bT/ZB+MX7B/7TfxZ/ZW+Omj/ANl+P/hT4kn0mW9t45xovi3w/col/wCFfHfhe4nSOS88L+M/D9zp/iDRZ5ES5itb4WWowWeqWl9ZWwB8tUAdJ4O8YeKfh74u8L+PfA+v6r4V8aeCfEWi+LfCPifQ7yXT9a8OeJvDuo22r6FrukX8DLPZ6npOqWdrf2N1EyyQXMEUqEMoNAH+yZ/wRB/4Kl+Fv+CrH7EvhH4v3Nzpen/H34efYfhx+0x4KsPJtv7F+Jen6ekieLdL0xSJLXwb8TNOjHizwwVR7Ownl13wjFe31/4R1SagD9iKAPIfj98dvhf+zF8Ffid+0F8afE1r4P8AhZ8IvB2s+OPGviC7w32TR9Gtmma3sbbcsupa1qtybfSdA0a133+ua5fafpGnRT319bwuAf4tX/BT/wD4KD/FD/gpv+2R8Uf2qfiS11ptj4hvR4d+FfgSW7N3ZfDD4Q6Bc3aeCPA1iyn7O9zaWtzcaz4nv7WO3g1zxprXiTxAttbf2r9niAPz6oAu6bpuo6zqNhpGkWF7qurare2um6Xpem2s99qOpajfTpa2VhYWVqktzeXt5cyxW9ra28Uk9xPIkUSPI6qQD/Xg/wCDd7/gkFp3/BLb9kG11j4laJZH9r79omy0Txn8edUdILm88DaclvJdeD/ghpl7HvRLLwNbX89x4sls5ZYNZ8fajrkq32p6JpXhdrMA/av47/AD4LftPfDPXPgz+0F8NPCfxd+FfiW40e71/wAB+NtMj1fw5q1z4f1ey17RZ72wlISaTTNZ06x1K0Yn91dWsMo5WgD4B/4cXf8ABH7/AKR2/sv/APhu7H/45QB/JR/wdu/8E9v2JP2Nf2Zv2T/Ff7LH7Mfwk+BHiPxj8dvFXh/xRrPw68MW+g32u6JafD+71K20zUZoXYz2kF+i3UcTcLMocc0AfweUAFAH90P/AAaM/wDBP/8AYr/bN+CP7Zev/tU/s0/Cf48az4H+Knwv0jwjqXxG8NQa9deHtM1bwj4jvdSsdMkmdTb297d21vPcIv8ArJIUY/doA/r5/wCHF3/BH7/pHb+y/wD+G7sf/jlAB/w4u/4I/f8ASO39l/8A8N3Y/wDxygA/4cXf8Efv+kdv7L//AIbux/8AjlAH3v8AAP8AZ2+B37LXw3074P8A7O3wu8IfB74YaRqGrarpngfwNpcej+HrHUddvZNR1i8t7GIsiT6jfSyXV04OZJnZzyaAPZ6ACgAoAKACgAoAKACgAoA/zB/+D1T/AJSm/ALp/wAmBfCzr/2cV+1T+JPPHp+JyAfyCcZ/hx9e2T/npzk80ALxnt+fbH+c+q9aAEHTtk54z9ehz/X1oAPb5e3fngfr/h160ABx/s9RyTx0P6/n6/QAXjdnjp1zz1+v05+nNACHHbb09cdwfUe5/wD18gDuO+PxOf5/Tn396AEGOvHQZ54zyfX6YoATjPbHse3ze/5/U0AL37dR35+6ff8A/WM/WgBBjAzjv3z3+p4/r70AHY9O3U5HQe5/D8KADuOB3yc/r7+/Hr26gCnoemfcn1HU5z/kUAJxn+HGW7/T3/P2+poA/tH/AODJr/k+r9rL/s0mL/1dHgGgD/SsoAKAGt0/4En/AKGtAH+C58av+Sw/Fb/spHjzr0/5G/WutAHmWBntnJ789/fP1H14oATtjjnHQ+/bn8RjuDQAvr/wI8n3+vT+9njNACcfN07Dk9Tg9ef8KAF646fn/wCg8/nQAccdOMZ56cH3/wAe596AE/7559Pw/L69c7aAA9+nOc889Aex9fvf5NAA3I7dO5xnnjoenXqetACnv05z36/L9fz9qAD8s89+fvfX6/8AAsUAHvx1/HtnPPXr+OKADuDx/F39T256mgBO5Py/UH6nnnr6+2aAFBA7r7c+/wD9YfjmgBD347evHf3xj8O5z1NAH+vt/wAGuf8Aygp/Ya+v7TX/AK2H+0F/n19eaAP39oAKAPx0/wCC9f7b91+wJ/wS6/aU+MfhrW5NC+KfjDQIfgd8Fb21nNtqlr8Tfi2Lnw7Z67os+QI9Y8C+Fv8AhK/iRYltymTwaVMcu7y3AP8AGTJJJJJJJJJJySTySSeSSepoASgD96/+Dc//AIJp6Z/wUm/4KJ+DfD/xJ8PRa/8As5/s/wCmj43fHjT7+Nm0rxPpei39vZeCPhreYKrcRePvGk+nW+taczo994G0jxoYZEmgQ0Af7A1ra21jbW9lZW8FnZ2cENraWlrDHb21rbW8axQW9vBEqRQwQRIscMMarHHGqoihQBQBPQAUAFAHhP7Tn7OXws/a5+AHxZ/Zr+Nfh628TfDL4xeDNW8G+J9OuIo5JreO/iEmm67pMsiubDxH4Y1iHT/EnhnVodt1o/iHStN1S0kjurSKRQD/AA8v2nv2fvG/7KX7RXxt/Zr+I8ca+N/gb8TvGPwy8QzwIyWepXfhPW7zSo9b03ezs+ka/a29vrekTF28/TNQtJgzCQEgHhVAH6e/8EZP2qdW/Y1/4Kefsa/G201yfQfDsPxq8I+APiXOs2y0uPhR8VNSh+HnxETUoHP2e8trDw14jvddtobkbIdW0jTdQgkt72ytbqAA/wBrugAoA/xbv+C7n/KYb/gof/2cv44/9CtKAPyYoAKAPVfgd8Evij+0j8Xvh38CPgr4Q1Tx78Vfir4p0zwd4I8J6PGHu9V1rVZvLj82aRkttP02xgWfUta1nUJrbS9D0azv9Y1a7tNNsbu6iAP9c3/gi5/wQt/Z1/4JL/DOz14WulfFb9r7xn4ftrf4s/H3UdPR5NM+1xQz6j8PPhFb3kX2jwj8O7K7HlXN0gh8R+PLm2h1jxXOlrBoPhrwyAfutQAUAFABQB/LV/weCf8AKHrVP+zl/gf/AOg+MKAP8pygAoA63wB4G8UfE/x34K+GngjSp9d8afEPxb4c8DeENEthm51jxR4t1mz0DQNKtwes+oatqFpaRDvJMtAH+2F/wS6/4J9fDf8A4JmfsY/CX9lnwDFpt/rPh3SU134teO7OzW2uvib8YNfhguvHXjS8keNL2Wzm1FRo/hS11B5rrRPBWkeHNAaaUaYJHAP0JoAKACgBkscc0ckM0aSxSo8csUqrJHLHIpV45EcFXR1JV1YFWUkEEE0Af5MP/Bzx/wAErtH/AOCdv7cMXxH+DfhK28MfsuftZ2mr/ED4caNo1r9n8PfD34iaRNZRfFj4Y6dbxgQabpVpqWqaX418KadDHa6dp/h3xjD4Z0WA2vhO48oA/mooAKAP9FP/AIMpP2y7rxR8If2of2EPE1/LcXXwq8RaZ+0J8K453aVo/B3j9rbwn8SdFtgSFtNN0DxjpXhTXoIQGNxqfxE1qcsu3DAH90tABQB/g3/tIf8AJxHx6/7LR8Uv/U412gDxegAoA/tW/wCDQb/glNoX7QXxf8Yf8FGPjf4X0zxD8Mv2dPEh8CfAXw/rtlb6hp+vftAjTNL13VvHc+n3sc1vNB8IvDetaNc+HJpraRP+E68VaXr2lXdrrHgFqAP9KKgAoAKACgD8Bv8Ag5S/YQ0D9tv/AIJafHTU7Tw9Z6h8Yv2XNA1X9pD4Q64Yl/tbT1+H9kdX+Kfhy0nQpc3Np4y+F1j4lsRoiym21HxRY+EdQltrm90TThGAf5AFABQB+sf/AAQp+Ler/BX/AILA/wDBPLxfos/kXOtftNeAPhNdN5jRq+jfHi7l+COvRORncsmjfEK+AVvlL7dxX7wAP9pWgAoA/wA3j/g9G/bgu/Hv7SXwI/YJ8Ka3K3hL4CeEY/jP8VtMtbgi0vPi58T7SW18Fafq9sSd2oeCvhfF/bOkzqEAsvi7qCMZWIEIB/EdQAUAf6cP/BoX/wAEydD+AP7JN/8At/fEnwtZt8b/ANqz7fYfC7UdRtlk1XwT+znompfYrJNOMoL6bc/FXxVpV74p1SWHP9p+EtI+HssckaPeRSgH9i9ABQAUAFAH8gP/AAeAf8E8dC+Pv7EOkftw+DPDVkfjN+yHq2k23jHW7S3VNY8R/s8eNdZXRNc0W8eLZNqaeBfHOt6B4z0j7U00Xh/RLz4iXFrHEdYvXYA/zBaACgD/AEOv+DJT9qnVtd+HX7Y37GXiLXJ7my8Aa94H+P3wv0e5m882eneN49S8F/FSOwEhMtpplprHh74c3/2OEmz/ALU8S6pfLFBd313LeAH931ABQB/LR/wc+/8ABHIf8FBf2ZP+GnfgZ4WF/wDte/st+GtU1HT9P0mz83WfjP8ABS0e61vxX8MhHbobrVPE/hmWTUPGfwztkF1cXGpy+JvCWn2ct943gubEA/ynyCCQQQQcEHqD3B96AEoA/Yf/AIIhf8FSvFP/AASn/bb8IfGC4udV1H4CfEL7D8OP2l/BVh5tz/bfw01DUI3TxZpemKTHdeMvhnqLjxb4XZUjvL+GHXPCMd7Y2Hi7VJiAf7Jvg3xh4W+IfhHwt4+8Da/pfivwV438O6L4u8I+KNDvItQ0XxH4Z8R6bbaxoWu6RfQM0N5puraXeWt/Y3UTNHPbTxSoSrCgD/OP/wCDuP8A4K+/8Lw+K6/8EzfgL4o8/wCEvwM8RW+s/tMa5o15m08d/HDSyzaX8NXuLZzHe+Hvg8JGn8Q2kkslvc/FC5ls76xt9T+G2n3c4B/E3QAUAf2+f8Gkn/BHD/hcfxCt/wDgp9+0P4V874W/CTxBd6Z+yr4b1qz3Wnjr4vaJO9rrPxca2uk8q88OfCe7WXTPCNykc0N38UFutStruy1H4bNDfAH+j5QAUAFAH8SP/B7r/wAmjfsVf9nHeMv/AFWV7QB/m60AFAH+jF/wY/8A/JvX7en/AGWb4Pf+oR4qoA/uWoAKACgAoAKACgAoAKACgAoAKACgAoA/zB/+D1T/AJSm/AL2/YB+Fh/82K/ap9jmgD+QTAzk9c+/qTnpz6jtjPoTQAuee/Xvn0/zx2+8eKAE7Y+vfjHfJxz169uvO00AA6jHtnk56Y5GB/nnpmgAPJz+PJIz77v6fj35AF7556e/rnpj+vNACNg++M9+/Hsfp9eOpoAcD/nBH8/8/wBQBB/T3J4z/nP8XagBO+e49fx4/HPGM/jj5gA753L2/QY6Z9+n457UAA47r+fv6/8A1vzzkABxjqp/H6d/w9OevfgAOMg5XjPf2x7k5/T3oACcjG5fz/z/AJHvwAHGc5HUnr6/z/THvQB/aN/wZNMv/Ddf7WQ3KSf2SIjgMCf+S0eAM+/G5c/7y+ooA/0raACgBrdP+BJ/6GtAH+C38aiG+L/xUKuhDfEjx5yCDwfF2snrnupBHqCD3zQB5l3+8vr178/zz/Lk45AEH+8ufr75659evr+tAB6/MvII/M59f/1e/WgAPf5hz79eCPw4PvmgA9PmXjPf2x68+2eaAD/gQ7d+nGPx/TPXtggCHOR9c9Dx0/PHT1/E0AHX/wAez27YyfT8enXocUAHU89xk8YHJz159OvOelACnJOee+eMdRjnrjp36de+KADnP69Cf4sn/wCv+XXmgBP/AK/bP8Q7duAOPQD1oAXr9f8AE5bA/ix3Hboc9aAE/mevUknDdfQ/57GgBOTjqfz9T+fXr70AO7de3PB7579up+bv+ByAf6+//Brn/wAoKf2Gv+7mf/Ww/wBoL/OO1AH7+0AFAH8BP/B73+0PeJB+wz+ydpt4VsLib4mftD+M9P8ANJE15Zppvw2+Gl55IICm2hvvizB5sgYv9r2QlNk/mAH+f7QAUAf6Z/8AwZZ/s7aX4F/YJ/aC/aRuLPy/Fn7QH7Qsng+O8aIDz/h98EPCum2/h1Ypm+c48afED4kpcImIz5FsSWkQiMA/spoAKACgAoAKAP8AJb/4OzPhHpXwv/4LNfF/X9Jg+yxfG34U/BT4u3lukax266rJ4PX4a6ncW6rwf7RvPhrLql5Ifmm1O9vpWyzkkA/mroAcjvG6yRuySIyujoxV0dSGV1ZSGVlYAqwIIIBBzQB/urfsQ/FnVvj3+xf+yL8c9enW5174zfsxfAT4q65cKSwm1n4hfCvwp4t1WTJ5y1/q9wWDfMGyGAYEUAfUFAH+Ld/wXc/5TDf8FD/+zl/HH/oVpQB+TFABQB/oa/8ABmN/wTp0/RvAvxc/4KX/ABE0O0udf8ZX+rfAf9nR762hnn0bwpoVxBJ8X/HemtKsy29z4m8RJp/w+03ULZrTU7Gy8JeO9NkMml+JnWYA/vDoAKACgAoAKAP5av8Ag8E/5Q9ap/2cv8D/AP0HxhQB/lOUAFAH9C//AAa4/s96T+0B/wAFlv2cZvEWlrq/h74F6N8Qv2hL+0kQNFFq3w/8NTWHgHVJCVby20P4n+JfBGt2zjB+2afbJuG+gD/XhoAKACgAoAKAP5p/+Dr/APZZsf2h/wDgkT8TfH9vaxyeMf2U/HXgT49+G51j/wBKl0hdU/4Vx4+0z7Qqs8dgfB3jzUvEt1Af3Nze+FNLaTD28MkYB/kv0AFAH9Ln/Bpd8cP+FRf8FlfhV4Unu/senftDfCT40fBS/kd9lu8ieFl+MGi282TgveeI/hHo9haDBZ728t4lx5hNAH+s5QAUAf4N/wC0h/ycR8ev+y0fFL/1ONdoA8XoAKAP9oz/AIIU/sxaV+yX/wAEm/2JfhlZ2q2+teIvgv4b+NHjmVofKvZ/HXx2g/4W14httRbG6e58Oy+LYPCEEr5I03w7YQJ+6hjAAP1soAKACgAoA53xf4W0bxz4S8UeCfEdqL3w94x8O634W16ybGLvRvEOm3Ok6pancrLi4sbueI7lYYflSOCAf4IXiLR5/DviDXfD9ySbnQtZ1PR7gldpM+mXs9lKSuTtJkgYlcnB4yaAMagD60/YG16bwr+3X+xZ4nt932jw5+1p+zlr0Gw4fztH+MPg7UItp7Nvt12nPBoA/wB0SgAoA/xDP+Crn7Q95+1Z/wAFJf21/jzc3hv7Hxt+0P8AEW18LXBlM5/4V/4M1mXwF8NrfzSSJPsfw/8AC/hqz3JtiPkfukSLYigH59UAdP4J8Jat4+8Z+EfAugRefrvjXxPoHhLRYMM3nat4j1W00fTotq5ZvMvLyFMKCxzgc0Af7v3wN+EXhX9n/wCCvwi+BPgWD7N4L+DPwz8C/CvwnCY0iZPDvgDwxpnhXRzKkeVEz2GlQPOQWLzM7szMxYgHqdABQAUAFAHyt+3P8I9K+Pv7Fv7WfwU1qD7Rp/xT/Zx+NHgZwI1klgufEXw88Q6dp9/aq3AvtN1Ge11Gwk4aK9tbeVSGQGgD/CwoAKAP6X/+DSf4uax8OP8AgtB8IfBunXPkad8fPhF8evhT4iiZ2VLrTNG+HWp/G6zjK52NIuv/AAe0Z4y/PDqh3PggH+szQAUAFAH+XR/wdSf8Ecf+GLP2hW/bc+AfhX7H+y7+0/4rvZfGei6NZ+VpHwZ+P+qLd6xrWjJbwIIdM8HfFFINS8XeEY4yLPS9ft/GHhmCDStKtPClneAH8j1ABQB/VX/wTg/4OXfi1+wz/wAEuPj7+xld2et+KfjX4Zsv7J/YZ+ItwsOo6f8ADXSfiDeXsPjew8VyX0rM9l8J5bi78dfCi0e01iDUNa1c+EdVisvCej6bbxgH8seqapqeuanqOta1qN9q+s6xf3mqatq2qXdxf6nqmp6hcSXd/qOo311JLdXt9e3U0tzd3dzLJcXNxLJNNI8jsxAKFAH6jf8ABIP/AIJmfEX/AIKqftm+Bf2d/C/9p6F8N9MMXjj4/wDxJs7cPD8O/hHo99ax65eW080U1o3izxNNPb+FPA2nzR3C3PiPVba+vLY6DpWuXlkAf7Nfwf8AhH8OvgJ8LPh98FfhH4V0zwR8Mvhb4S0TwP4G8KaRGY7HRPDnh6xh0/TrRGdnnup/JhE19qF5LPqGp30tzqOoXNzfXVxcSAHo9ABQAUAfxI/8Huv/ACaN+xV/2cd4y/8AVZXtAH+brQAUAf6MX/Bj/wD8m9ft6f8AZZvg9/6hHiqgD+5agAoAKACgAoAKACgAoAKACgAoAKACgD/MG/4PVf8AlKb8A+uf+GAfhbjgn/m4r9qrPRhQB/ILznoc/T3/AN73P+OMigA59D1zyOc9O7/5HNACZ46HAz2P4/x+/wDP3oAXnrg/iPw/vZ79yfbAoAQ5PGD7cfX1Yj1/D8KADJ9+noffr8/1xnn0oAD7g/kfb0f1x+PvmgBcn3/EH39X/wA8e1ACZPv07Dtz/t/XHr1oA/pJ/wCDUbRNG8Q/8FjPhFpev6RpWuadP8I/2hGl0/WdNstVspHi+Gt48TvaahDc2zPG3zIzRsRyM4ZgQD/Ve/4Uv8Iv+iX/AA6/8IXwl/8AKagA/wCFL/CL/ol/w6/8IXwl/wDKagA/4Uv8Iv8Aol/w6/8ACF8Jf/KagA/4Uv8ACL/ol/w6/wDCF8Jf/KagA/4Uv8Iv+iX/AA6/8IXwl/8AKagA/wCFL/CL/ol/w6/8IXwl/wDKagDf8PeAfA/hK6nvfC/g/wALeHby6txa3N3oPhzRdGubi2EgmFvPPpljaSzQCVVkEMjtGJFV9u8BqAOuoAKACgDzWT4NfCSV3kk+GPw8eSR3kkd/A3hR3kkkdpJJHdtHZnd3Zmd2JZmJZiWJJAGf8KX+EX/RL/h1/wCEL4S/+U1AB/wpf4Rf9Ev+HX/hC+Ev/lNQAf8ACl/hF/0S/wCHX/hC+Ev/AJTUAH/Cl/hF/wBEv+HX/hC+Ev8A5TUAH/Cl/hF/0S/4df8AhC+Ev/lNQB8zftqfCL4V2H7HX7WF5Z/Db4f213bfs0fHua3uYPBPhaGeCaP4T+L3jlhmi0hJIpEcBldGVgR1wSCAf4esn3l/3IT/AOQIj07/AOec8EAj/wADng9x3+b6fj1wTmgA9c56env/AL3+A9O+QAz169DnIPp3+Y0AL379SO/rz/Fnr36dfpQAn5/kc8kHs2c9M5OfU8gUAH4Hv2Prz/F+eOfXvkAPzz16cng+h+vX5u5PBwAHT14z0B9eejc4/wD180AL2/Dnr/tf7XT+ee3GAD/X2/4Nc/8AlBT+w1/3c17f83h/tBe5/nQB+/tABQB/lTf8HhfxEn8Z/wDBX648LvdtNB8JP2ZPgr4Eht9+Y7NtXuvGnxQmQIOFkmPxESeRiN7o8QZiiRhQD+WCgAoA/dz9iH/g4s/4KMf8E+v2cPBX7LH7Ot58DtO+FngS/wDFuqaQPFfwpj8R+JLq/wDGnivWPGGs3Wr622v2Rv5f7S1qe1sz9li+zaXbWNn8/wBm81wD6z/4jAP+CxP/AEHf2bv/AAx0P/zU0AH/ABGAf8Fif+g7+zd/4Y6H/wCamgA/4jAP+CxP/Qd/Zu/8MdD/APNTQAf8RgH/AAWJ/wCg7+zd/wCGOh/+amgA/wCIwD/gsT/0Hf2bv/DHQ/8AzU0Afi9/wUN/4KLftGf8FOvjfoP7Qf7T83ga4+Inh34aaF8KbGfwD4UXwfpMvhXw74j8XeKNNN5pq3+oi41RdR8a6xHLf+ehlsksLbyl+y75AD4RoAKAP9p3/ghl4obxf/wSA/4J26szs5tP2XPht4Xy2chfBGmt4LRef4UTQFRe21RjigD9W6AP8W7/AILuf8phv+Ch/wD2cv44/wDQrSgD8mKACgD/AGx/+CNHwO0f9nX/AIJV/sD/AAt0aEQLbfszfDPxvrSCIQg+Mfi5okXxc8dybBkkS+NPHGvyK7/vJFYPIFdmUAH6Y0AFABQAUAFAH8tX/B4J/wAoetU/7OX+B/8A6D4woA/ynKACgD+0r/gyV8L2t5+3R+1x4zktY5Lzw9+yfb+Gra8ZcyW8Hi74veA9TuoI2/hF03gy2d+7fZVGcBsgH+ldQAUAFABQAUAfF/8AwUd+Gtl8Yv8Agn3+298Lr9FaLx1+yd+0D4egkZPMNpqV98K/FK6RqMaYO6fTNWFlqNvkMPPtYyVYZBAP8NegAoA/TX/gi94ml8Jf8Fav+CcWqw3D2z3X7ZPwC8MtJG7Rs0XjT4h6H4OngLKQTHdQa9JbSoTtkimeNwyuVIB/th0AFAH+Df8AtIf8nEfHr/stHxS/9TjXaAPF6AOj8H+HZ/F/i7wt4TtpfJufFHiPRPDtvNsMnlT63qdrpsUvlgqZPLkuVfYGUvjbkZzQB/vceFvDmleDvDPh3wjoNuLTQ/CuhaR4c0a1GMW2laHp9vpmnW42hVxDZ2sMYwqj5eABxQBu0AFABQAUAFAH+DN+0GiR/Hz43xxqqRx/F/4lIiKAFRF8Z60qqoHAVQAABwAKAPIKAPpP9jP/AJPA/ZS/7OT+Bn/q0PC9AH+7LQB49+0N4/b4UfAH45fFNJxbP8Nfg98TPH6XJ24t28HeC9b8RLOdwK4iOnCQ7gV+XkEZoA/wa5JJJpJJppHllld5JZZHaSSSR2LPJI7Es7uxLO7EszEkkkk0AMoA9D+EXxN8RfBX4r/DD4yeEIdIuPFvwl+Ifgv4m+F7fX7D+1dCn8ReA/Emm+KdEh1vSzNb/wBpaRLqelWyalYGeH7ZZtNb+dH5m8AH9Jn/ABGAf8Fif+g7+zd/4Y6H/wCamgA/4jAP+CxP/Qd/Zu/8MdD/APNTQAf8RgH/AAWJ/wCg7+zd/wCGOh/+amgA/wCIwD/gsT/0Hf2bv/DHQ/8AzU0AH/EYB/wWJ/6Dv7N3/hjof/mpoAguv+Dvb/gsFe21zZ3Wsfs2TW13BNbXML/A2EpLBcRtFNE4/wCEp5WSN2Vh3BNAH8u9ABQB+0X/AAbu+KG8If8ABab9gDVldkN38XNa8LkrnJXxv8NPHXgt1OP4ZE19kbttY54zQB/srUAFABQB8+ftV/sxfCH9sz9nn4r/ALMfx28Op4m+F/xf8KXvhfxFZjyk1DT5JGju9F8TaBdzQzrpvinwlrtrpvibwvqohlbTNe0rT73ypRCY3AP8Wv8A4KL/ALB3xd/4Jt/tcfFL9lH4xW73Gp+CtSGoeC/GMNnLZ6N8TfhlrUtxP4I+Ivh8SNKn2HxBpsTR6jZRXN23h/xNY6/4WvbmTU9CvgoB8PUAFABQB0ng3wf4q+Ifi7wv4B8DeH9W8WeNfG3iHRvCXhHwvoVnNqOt+I/E3iLUbfSNC0PSLC3V573U9W1O7trGxtYUaW4uZ44kBZhQB/sY/wDBC/8A4JQeFf8AglD+xloPw61O10rU/wBpH4rjSviB+0143sfJuhf+N3sXXS/h/oupqGkufBXwtsL258P6CVl+yarrFx4o8Yw21jL4suLK3AP2joAKACgAoA/iR/4Pdf8Ak0b9ir/s47xl/wCqyvaAP83WgAoA/wBGL/gx/wD+Tev29P8Ass3we/8AUI8VUAf3LUAFABQAUAFABQAUAFABQAUAFABQAUAf5g//AAeqf8pTfgF6/wDDAPwtx9f+Giv2qf8AZNAH8gfGe3frjoCf9nHPX370AL9T/wCg9Mdfu/h9PagBOMDnse4zjn/Zz6//AF6AD8vzXOMf7vTH6UAHHrxkemM8/wCzjOOv8+lABxnqOnPI/D+HHp/9fFAAceoP4j29F6/59aAHEDue567fx/h6+tACcc89hnpj2z8uPx/+tQB/S3/waXf8pmvg9g/80i/aH/8AVZ3npQB/rMUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAfLv7b/wDyZj+1v/2bH8fv/VS+L6AP8LGT7y/7kH/omL/P/wBfFAEf/wBlnJ5zt78fn155PPFACeuc9O59x6A8enUdcUAL35z37j+77D0x6/iaAAnk9+vpk/MPbI5z+PQ96AEyeev6Zzkd8dfXv070AH/18cjrnnHy9Qf/AK3rQAuRjP59PRvYf1/LqAJnpxn/AL5/vH2P6dz78gDu3OenPPb5vbp6de34gH+vt/wa5/8AKCn9hv6/tNf+th/tBfSgD9/aACgD/IT/AODpjUHvf+C537aEDFiulWP7Nmnx5yPlb9lL4Iai2AecedqEvPQnLDIIJAP586ACgAoAKACgAoAKACgAoAKACgD/AGaP+DfP/lDH/wAE+/8AsiJ/9TTxZQB+yFAH+Ld/wXc/5TDf8FD/APs5fxx/6FaUAfkxQAUAf7x37NmmWmi/s6fALRrBPKsdJ+Cvws0yzj/552lh4G0K1t04AHyQxIvAHTpQB7VQAUAFABQAUAfy1f8AB4J/yh61T/s5f4H/APoPjCgD/KcoAKAP7mv+DH4W/wDw0B+3wzBPtY+DvwZEJP8ArPs7eNfGBugv+wZVtN/+0I6AP9F6gAoAKACgAoA81+M2n22rfB/4r6VeOkdpqfw18dafdSSf6tLa98L6pbTu/X5FilZm4PANAH+CjQAUAfZH/BOrVbrQv+Cgv7CmuWSSSXmjftkfsxaraRxcyyXWnfGzwReQJH/00eWFFT/aIoA/3MKACgD/AAb/ANpD/k4j49f9lo+KX/qca7QB4vQB9E/sg6QniD9rP9l7QZACmt/tE/BPSHDfdKal8SvDNmwbPGCJjnPagD/dvoAKACgAoAKACgD/AAaP2h/+S/8Axy/7LD8TP/U11ugDx6gD6T/Yz/5PA/ZS/wCzk/gZ/wCrQ8L0Af7stAHwd/wVO1B9J/4Ji/8ABRnVIywk079hH9ru9jK5Lebbfs//ABBmjxjODvReeg6sQATQB/h8UAFABQAUAFABQAUAFABQAUAFAH62/wDBBz/lMT/wTy/7OR8H/wDonUKAP9ougAoAKACgD+QH/g8Z+AH7J/iv9gXwd+0J8UvEdh4I/ac+F/xB0bwh+zldWNlDd+I/iva+Mb+CTx98KNSgSWG4m8KaX4dtL/4krrtyZIfCOr+GktLJ45fG17p2uAH+YLQAUAFAH9j3/Bmt8Av2Tvid+2v8Xfip8WPEdhqn7S3wL8A2HiD9m/4Va3ZQjT3sfEE1/oHxF+MOkXE0rpq/inwHa3Wi+G7DTDAh0G18dXPieBLy/trG/wDDgB/ptUAFABQAUAFAH8SP/B7r/wAmjfsVf9nHeMv/AFWV7QB/m60AFAH+jF/wY/8A/JvX7en/AGWb4Pf+oR4qoA/uWoAKACgAoAKACgAoAKACgAoAKACgAoA/zBv+D1U/8bTfgF15/YB+FnT/ALOK/ap9++fUfU0AfyC857//AK2+vt16YP4EAUZ756jr+fqep469e+OKAEySM898/hzz+Xp3577gABPHX6889+ee/wBT17cggASQf6fUk+/Xp0z9KADnOOehP55/2v6n8OtAAxI9e/T8B6+/+fvUAKPrnn1Pv/tHrnP9PQAOvftnrzzn3HI7/pigD+lv/g0v/wCUzfwe/wCyRftD/wDqs7ygD/WXoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoA+Xf23/+TMf2t/8As2P4/f8AqpfF9AH+FhL95P8Ach/9ERc/z/WgCPJ4OTxnn14BHfv7559RwAA+737evv06npn3/rQApOD1PGfXnjPc+/Gc89cjigAOc8k+mef72PX2yeenqeaAE/4Efrn1Iweo6j69D3HAAp+pHXnPTBx6/wBfxY0AHPqeOc5PcHnt9OpHPXrkAbyOpI659snvz36/49aAHZwOvT69eeP078dOOuQD/X3/AODXPn/ghT+w1/3cz/62H+0F/n+p60Afv7QAUAf5Gn/B1n4dudE/4LfftSanPAYovF/hD9nPxFZSEcXNtbfs9fDXwk86+oW88L3dtnn5rdh2oA/nSoAKAP7tv+CSn/Brf+wt/wAFDf8Agnl+zd+2J46/aA/ao8LeMvjHovjefxP4e8D618I4fCmla14J+KXjn4b39vosOvfCjXNXitTN4PaZkv8AVr6ZZpZf33l7FUA/Rn/iCd/4J1/9HP8A7af/AIP/AIG//OToAP8AiCd/4J1/9HP/ALaf/g/+Bv8A85OgA/4gnf8AgnX/ANHP/tp/+D/4G/8Azk6AD/iCd/4J1/8ARz/7af8A4P8A4G//ADk6AD/iCd/4J1/9HP8A7af/AIP/AIG//OToAP8AiCd/4J1/9HP/ALaf/g/+Bv8A85OgA/4gnf8AgnX/ANHP/tp/+D/4G/8Azk6AD/iCd/4J1/8ARz/7af8A4P8A4G//ADk6AP6i/wBi/wDZV8E/sQ/sufBj9lD4ca/4q8U+B/gj4T/4RDw54g8bTaTceK9UsP7U1HVvtOtzaFpWh6RJd+fqc0ebHSbGHykjHlbw7uAfT1AH+Ld/wXc/5TDf8FD/APs5fxx/6FaUAfkxQAUAf7z3wC/5IT8Ff+yS/Dj/ANQ7RqAPWqACgAoAKACgD+Wr/g8E/wCUPWqf9nL/AAP/APQfGFAH+U5QAUAf2uf8GR+trB+2j+2P4cMqh9V/Zf0LW1hLANIvh/4reGrB5QmcssJ8TIrMAQpnUEguMgH+k5QAUAFABQAUAfP37WniSDwb+yt+0x4vurmOztfCv7P3xm8SXN3K4jitYND+HPiTVJrmSQkBI4I7VpXckBVUsTxQB/hEUAFAH3//AMEoPD3/AAlX/BUL/gnRoLR+bDf/ALcX7K32xMbt2n2vxv8ABF7qXHfFhb3J544yeM0Af7fNABQB/g3/ALSH/JxHx6/7LR8Uv/U412gDxegD6l/Ya/5PY/Y9/wCzpf2ff/Vs+EqAP91OgAoAKACgAoAKAP8ABo/aH/5L/wDHL/ssPxM/9TXW6APHqAPpP9jP/k8D9lL/ALOT+Bn/AKtDwvQB/uy0AfF//BSDw7c+L/8Agnh+3p4SsoDc3nij9i/9qPw7aWyjLXFzrfwP8c6bBAo5yZZblIwO5agD/DXoAKAPrT9gv4GeAv2nv21/2Uv2bvifrniTwz4D+Pnx++Fnwb8Ra/4Pn0u28T6TbfErxhpXg+3vdEn1vTNa0mPUIr/WLUwnUNKvrYkkPA+RgA/0G/8AiCd/4J1/9HP/ALaf/g/+Bv8A85OgA/4gnf8AgnX/ANHP/tp/+D/4G/8Azk6AD/iCd/4J1/8ARz/7af8A4P8A4G//ADk6AD/iCd/4J1/9HP8A7af/AIP/AIG//OToAP8AiCd/4J1/9HP/ALaf/g/+Bv8A85OgA/4gnf8AgnX/ANHP/tp/+D/4G/8Azk6AD/iCd/4J1/8ARz/7af8A4P8A4G//ADk6AD/iCd/4J1/9HP8A7af/AIP/AIG//OToA+kf2P8A/g04/Yd/Yy/ac+Cn7U/w+/aC/at8TeNfgb450zx94b0DxlrXwhn8L6rqmlrOsFprkOifCbRtWksJPPYyrYarY3BwNlwnOQD+pigAoAKAOa8Z+MvCvw78IeKfH/jvxDpPhLwT4I8O614t8X+KdevYdO0Tw54Z8O6dc6vruu6vf3DJBZabpWmWl1fX11M6xwW0EkjkKpoA/wAc3/gud/wVe8Vf8FX/ANs3X/iRp1zq2l/s4fCo6r8P/wBmXwPf+dbNp/gZL5G1Px9rWmMRHbeNvilf2dt4h18NGbrS9Jt/C/g6a6v4fCdtezgH4vUAFABQB9A/srftOfF79jX9oT4U/tN/AnxHJ4Y+KPwg8V2Xinw3fHzZLC/SNZLTWfDev2kU0Dan4X8WaHdaj4a8UaS00SapoGq6hYtJH5/mKAf7SH/BOL9vb4Rf8FKP2Rvhf+1b8H7hLax8YaedL8deC5byK81n4YfFDRYbaLxv8O9eZFikN3oWoTpcaVfzW1mPEPhfUfD/AIptLWLT9dswQD7noAKACgAoA/iR/wCD3X/k0b9ir/s47xl/6rK9oA/zdaACgD/Ri/4Mf/8Ak3r9vT/ss3we/wDUI8VUAf3LUAFABQAUAFABQAUAFABQAUAFABQAUAf5g/8Aweqf8pTfgFxn/jAH4W98f83FftU/r/WgD+QTjPQenUY5J/Xj69c80ALx6d8c4/u59/5/pxQAnG0cdd3/ALNxnr6/4+oADGQMDnvkHqCcfTt9MevIAEgDpnn+np/Q+o+gAF4z07Z6jPU+/wD+rj0GABGx6evt3H9T1/oc0AO69RQAg+nZT/P6c0Afoz/wSv8A+Chmtf8ABL/9sDwn+1r4f+FulfGDUvCvhL4g+FYvBGs+Kr3wbY3iePPDk3h2W+fXNP0bXrmF9NWT7UkC6dILrDQma2YrOgB/Un/xHAfF/wD6R6/Dn/xInxb/APOvoAP+I4D4v/8ASPX4c/8AiRPi3/519AB/xHAfF7/pHt8Of/EifFv/AM6+gA/4jgPi/wD9I9fhz/4kT4t/+dfQAf8AEcB8X/8ApHr8Of8AxInxb/8AOvoAP+I4D4v/APSPX4c/+JE+Lf8A519AH7g/8ELP+DhDxz/wV++P/wAYPgx4p/Zj8KfA6y+GPwcT4oW2v6D8Udb8d3Wr3L+OfDvhH+x57DU/B/h2G0h8vXZL37XHdTyh7VIPJZZ2eEA/qFoAKAEJxz7gfmQP60Af58Xjf/g9f+LnhLxn4t8Kp/wT/wDh1fJ4a8T+IdAjvG/aE8WQPdR6LrN9paXLwr8MXWJ5xaea0au6qWwGxwADl/8AiOA+L/8A0j1+HP8A4kT4t/8AnX0AH/EcB8X/APpHr8Of/EifFv8A86+gA/4jgPi//wBI9fhz/wCJE+Lf/nX0AH/EcB8X/wDpHr8Of/EifFv/AM6+gA/4jgPi/wD9I9fhz/4kT4t/+dfQB5v8ZP8Ag86+Kvxg+EPxV+Et7+wR8PtFtPij8NfHnw6uNag+P/iq+n0eLxx4U1fwvJqsNlL8NII7yTTl1VrxbR7i3W6MPkfabYuLiMA/iaZixU9OEX1+7HGoP44yR69+M0AN/wDss+vTn+fvzySaAA+/90fjkjpyePw/AZoACDnrnGc5P+zn9R9emaAF5z29ef8Ae+vTIzj37nmgA5/X9QwPr15weecdT1oATGMdzzj22nJ/PHt7nvQAeo4HY+/Dc9sd+T/+sAOTjGORnjjoT7+p/H6igBecf8BBP0+b3+vr1HAxQB/r7/8ABrn/AMoKf2G/r+01/wCth/tBUAfv7QAUAf5j3/B6b8G7vwj/AMFE/gF8Z4YGTRPjL+yzo+iPOUwJ/F3wq+IPjWy1wLIMBxD4Z8XeA1KHMkbMSzFJIlUA/jooAKAP9T7/AIM7fj/p/wAUP+CUl78HmmjTXv2Zv2gPiX4MmsPM3zt4Y+Isth8X9C1pk3HyrfUNe8aeNNKgX5S03h67cr8wdwD+rqgAoAKACgAoAKACgAoAKACgD/Fu/wCC7n/KYb/gof8A9nL+OP8A0K0oA/JigAoA/wB574Bf8kJ+Cv8A2SX4cf8AqHaNQB61QAUAFABQAUAfy1f8Hgn/ACh61T/s5f4H/wDoPjCgD/KcoAKAP6e/+DRL4uRfDX/gsf4K8JzXsdpH8ePgJ8b/AITBJZViS8n07SNJ+M9taDewV5pJvhErQJy7yIEjBdgCAf6vtABQAUAFABQB+NX/AAcGfHCx+Af/AARy/bw8UXOpx6de+M/gxf8AwS0ZDJsudS1H476rpnwkm0+xRf3k0/8AY/i/Vr6dYwTDp1jfXkhSC2mkQA/xnKACgD9u/wDg3I+Dt58av+Cz/wCw3ocEcn2LwV8Q9e+MWsXaLujsbP4PeA/FXxDsZLg4bbHfeINA0XRY2x/x9apbjcgYyKAf7HtABQB/g3/tIf8AJxHx6/7LR8Uv/U412gDxegD6l/Ya/wCT2P2Pf+zpf2ff/Vs+EqAP91OgAoAKACgAoAKAP8Gj9of/AJL/APHL/ssPxM/9TXW6APHqAPpP9jP/AJPA/ZS/7OT+Bn/q0PC9AH+7LQBz/izw3pvjLwr4m8Iayhk0jxX4f1nw3qsa7S0mm67p1zpd8i7wy5a2upVG5WXJ5BGRQB/gw/FD4f658J/iX8RPhZ4nj8nxL8NPHXi34f8AiGLY0fla54N1/UPDurR+W5Lx7L/TbhdjEsuNrEkGgDhaAPYf2efizefAT4//AAN+Omn2rX1/8F/jD8M/izY2SP5b3l58OfGuieMLa1WTcmxribR0iV967S+7cMZoA/3efC3ibRPGvhjw54x8M6hDq3hvxboOkeJvD+qW5LW+paJr2n2+q6TqEBPJhvLC7t7mInkpIpoA3qACgAoAKACgAoAKACgAoAKACgD/AD/v+Dun/gsh5j3H/BKj9nXxV8kZ0bxD+2P4r0K94eQfZdc8H/AGG8t36Rn+zvGvxNjhJzJ/wiXhOS7DReNtEIB/ARQAUAfs5+x5/wAEQP2tv20P+Cf/AO1N+358M9LkXwj8AGj/AOEB8Cy6Rd3PiX9oCPwvv1H4zv8AD8pLGzj4Y+Gmgv4PKtNR/wCEz1+PVPBfh/zfEek3logB+MdABQB/Qz/wbq/8Fgr/AP4Jdftc2/hn4oa5dj9j39o3UNE8I/HGwmkmnsvh5raTPZ+D/jjplmu9op/B897LYeNo7NGm1jwDfaq5stV1vw/4VhtgD/XU0/ULDVrCy1XSr201PTNTtLbUNO1LT7mG8sNQsLyFLmzvbK8t3kt7u0u7eSOe2uYJJIZ4ZElid0dWIBboAKACgD+JH/g91/5NG/Yq/wCzjvGX/qsr2gD/ADdaACgD/Ri/4Mf/APk3r9vT/ss3we/9QjxVQB/ctQAUAFABQAUAFABQAUAFABQAUAFABQB/mD/8Hqn/AClN+AXXn9gH4W98f83FftU/56igD+QTvjn/AL69yM/XuT+FAC9+/X19R/hz1+hzxQA0dM89+/sf1P0HT8wBe4PPPvnHB75OfX/OCAB/4FyR3Oe+eOvbP4+2KADvj5umfve59+/1/LrQAHj+8evVsdx69ucf5zQAuM/3h+Pr36n/ACaAEH49B0P19x1/r2OaADvjnv0Pu3+e/Tv3ADqe/Ufxeq59f17+vagAXnHXkHq3v/n0/HqAAHI/i+uc9gfXv9O/4UAHcDnqe+T0/pn19+c0AKeM9e3fHXHf8ufc8+gA059/4uSSenGf1/8A1k8gH9o//Bk3/wAn0/tZf9mlQ/8Aq6vANAH+lbQAUANbp/wJP/Q1oA/wWvjT/wAlf+Kn/ZSPHffH/M3a1/n9e2aAPMuc9e59fV/f+v8A9cABnA/DnJ7t6Z578nH9aADnn6N/M54z+vJ56HFABz83J4wep44J9e/6Z70AHOR6jPXnPHXr+OOPxzQAvPHXnHc8/KT6+v8AnmgBuDx04Pv/ALPr36enXr1wAHr/AMC756qD1zzxx+vNACnIz9OuSe4569+Ppj3oAU9/x6k8fLnoTznmgBOc/n69d3Xr644zk/jmgA5zyP1PqO5x0455z79gBcHjqfvcZPY465460AJjGffnB/4F3+mefx57gAM/Xr3I7n+Rz1xnPfGaADn9PXn+Lv69fpnpxQB/r7/8Guf/ACgp/Yb+v7TXX/s8P9oKgD9/aACgD+Qf/g8n/ZIuvjN/wTy+Gf7Tnh3R5NR8SfsifF+C48Q3UMJll0/4RfGyHT/BXiy4/dgzFI/iHpXwgkmODDb2S393MY44WkAB/l/0AFAH9T//AAaa/wDBRSw/Y8/4KCXX7PHxF8Q2mh/Bj9tvS9H+HNzfardxWel6D8b/AAvNqd/8F9XuLq4fZAniK41nxP8ADJYIlT7brXjrw3c3kyW2kAqAf6rNABQAUAFABQAUAFABQAUAFAH+Ld/wXc/5TDf8FD/+zl/HH/oVpQB+TFABQB/vPfAL/khPwV/7JL8OP/UO0agD1qgAoAKACgAoA/lq/wCDwT/lD1qn/Zy/wP8A/QfGFAH+U5QAUAfTn7Fv7R2t/sg/tb/s4ftP6B9qkvvgZ8ZfAHxHubG0cJNrWheHfEVjd+KPDbEvHm38T+Ghq3h68TzI/MtNTnTzYy29QD/cn+G3xF8FfF/4eeBviv8ADfxDYeLfh98SvCPh3x54H8UaXIZdO8Q+E/Fmk2mu+H9ZsnZVc2+o6XfWt1GJESVFlCSokisgAO1oAKACgAoA/gD/AOD1D9vLQby1/Z4/4Jz+Cta+2a5petRftK/HO3sp18rSP+JPrfhL4OeF9ReBmLX1/aa1448X6no135TWlkPAmteTOup2E8AB/AHQAUAf2of8GUn7Omp+Lf2z/wBp/wDafvdJlm8LfBj4A2vwv0zVJowttB4++M3jPRtVtTYyuAZ7608HfDLxZa3qQFxZ2mv25vBGb+xMoB/pUUAFAH+Df+0h/wAnEfHr/stHxS/9TjXaAPF6APqX9hr/AJPY/Y9/7Ol/Z9/9Wz4SoA/3U6ACgAoAKACgAoA/waP2h/8Akv8A8cv+yw/Ez/1NdboA8eoA+k/2M/8Ak8D9lL/s5P4Gf+rQ8L0Af7stABQB/kFf8HN/7JF1+yj/AMFev2i7qx0eTTfAn7SkulftQeBbnySlvqL/ABSW4b4lyI6DyPOi+Muk/ETfAjebFZy6fNMiC6jZwD+fygAoA/1nP+DWf/gopYftq/8ABN3wd8HvF3iG0u/jv+xfDpPwO8X6XNdxHWdW+Fmm2AT4H+ODZ72uDp03g+0Pw+uL+ZpJ73xF8PNa1C6MZ1K2EgB/S5QAUAFABQAUAFABQAUAFABQB+K//BdX/grD4X/4JQ/sZ678QdJu9K1L9pT4tLq3gD9mXwTfCG6F340NjG2r/EPWtMcs9z4L+FljfWuv62rxG01bW7rwr4PnuLFvFcV9bAH+Ol4w8X+KPiD4t8T+PPHGv6t4r8aeNfEOs+LPFvijXr2fUtb8R+JfEOo3Gr67rusahcvJcX2p6tqd3dX9/dzu8txdTyyyMXcmgDnKAPvb/gmh+wF8VP8Agpf+2J8K/wBlP4WpPYDxXqB1v4j+NxZvead8MPhNoM9rN468f6qmUhb+y7CeLT9Bsbm4tItf8Yat4c8Mpd29zrUEqgH+01+zr+z98K/2Vfgb8Lv2dPgl4ag8JfCv4P8Ag/SvBXg3Q4Skksem6ZERNqOqXaxxNqniDXb+S813xLrVwn2zXPEGpalrF88l5fTyMAf5e/8Awc+/8Egf+HfH7Vp/aO+Cvhf+zv2R/wBq3xBq+t6DZaVaeVovwi+NEwn1rxt8LdlugtNK0DXQbvxv8NbQC0gTRX8R+FdKsvsfgGS6uAD+XegAoA/0g/8Ag0o/4LJf8Lo+Hdr/AMExP2iPFXnfFf4Q+HrrUf2WfEmt3m678ffB/Q7drnVvhO9xdP5l54l+Etmj6h4Ut0lmnvfhek9hbWlpY/Dae4vgD+3WgAoAKAP4pf8Ag9w0q5m/Ys/Y51xR/oenftRa3pU5weLnWfhR4ovLUZ6DMWhXhweTjI6GgD/NhoAKAP8ARH/4MeNdtLj4O/8ABQnwyjob/SfiX+z/AK7cRhwZFtPEPhf4n6fZu0edyo03hi/VHIw7I6g5RqAP7saACgAoAKACgAoAKACgAoAKACgAoAKAP8yf/g9c8Mazbf8ABST9mvxnNZzJ4f1z9h/wj4a02/MbiC51fwl8evj5qeu2cUpAjeays/G/hyaaNGLxJqEDSKFljLAH8cfp9PVuvzY5z+pPTPOKAF/+v1Jz933IP/1ueM5IAg6fge5x/F2z/TPU84yAA7n1xzy390nnJ9enfH0zQAHpz6jqTjp9fU9zjHPvQAdz+Hds/jz9cdz6c8gB/PHqx5z7E8f1+nAA5v8AHqSO/wBR78/T2yAJ6/RehP8Aj+X9c8gCenryep/2u+cfrnrzQAuOevcdzn7p69s/5PWgBOg4PY9yB97tkg/59+QAxwT9O5x0HUf596AFPb/gXUn09c8e+TkH0oAD1x7+/qv+P+eSQBPT3DZ5P+P58+/PWgD+0f8A4Mm/+T6f2sv+zSoff/mtXgGgD/StoAKAGt0/4En/AKGtAH+C38af+Sv/ABU/7KR469f+hu1r0/T396APMv4h079+erdvx649efUAAOB26dCcfe/HP/1+e1AB69+H9fX/AOvz/OgBD/Fz6dz39f6dfT2oAUfw/j3Pp2yc4/OgAA6fh3PPDf57dx7UAIO3Tr6+6+pz/wDqHrggB6/8C5yT2HX+vXn0PFAARweeoByST3/Hj0/Hk80AKR1/Hux/h7//AF/50AHf8+5zy3p/9bGepIoAMdfqRnJz1X36469ume4oAMcjnqW7nPXt/XP60AIMZP1/2s9G9ec/560AKO2fQ9CT39ic+/XtntQAoUkhR1baMdfvbgMn0yeue1AH+wp/wbL+GdY8J/8ABDr9hHS9cs5rG9u9A+N3ieGGeN43fR/Gv7TXxp8ZeHrwLIqsYtQ0DXtMv4JANk0FzHLEWjdWIB+71ABQB5B+0D8D/AX7S/wN+Lv7PfxR09tU+Hnxp+HXi74Z+MLSLyluxofjHRLzRLy702aaKZbTWNOS8/tHRtQEbS6dqtrZ38G2e3jYAH+If+25+yP8Tf2E/wBqr42/sofFu1ePxj8HPG2o+HP7VW0ms7Dxd4bk2al4N8d6LDOzyDQvHHhS90fxTpCyO00NlqsVtdbLyC4ijAPlagCSKaW3linglkhnhkSaGaJ2jliljYPHLFIhDxyRuA6OrBlYBlIIzQB/pdf8G/n/AAcwfDL9ozwX8Pv2NP2/PHWnfDn9pfwvo9h4T+H3x68ca3aaf4H/AGhrPTIls9HsvF3iTVJLa28K/GZ7GO2s7iTW7s6V8TNSge/0/VbfxfrEXhm9AP7OVZWUMrBlYBlZSCrKRkMCMggg5BBwRzQAtABQAUAFAHwv+2F/wUv/AGEf2CdFn1b9q79pv4Y/Cm/S2N3Z+CLrWW8RfFHWotm9H0H4V+E4dd+IWsQOWjja+svDkunWzzwG9vLaOVZCAfHf/BLD/gt/+z//AMFcPix+0z4J/Zy+GfxM8NeBf2c9G+Guoj4g/E1tC0bUvH1z8QtR8c6fjSvBGjXmvS6HpGnDwU11aX+r+Iv7V1KLVI0vPDuiT2skcoB+1lABQB/i3f8ABdz/AJTDf8FD/wDs5fxx/wChWlAH5MUAFAH+898Av+SE/BX/ALJL8OP/AFDtGoA9aoAKACgAoAKAP5av+DwT/lD1qn/Zy/wP/wDQfGFAH+U5QAUAFAH9z/8AwbGf8HCHgH9n3wp4c/4Jy/tyeM9K8EfCfTbvVG/Zs/aA8U6j9i8PeA5db1S61nUPhN8UNZvZTaaN4OudW1C/1HwN40v5bbTPCtxdXXhnX7m38OSaFdeHwD/RM03UtO1nTrDWNHv7LVdJ1WytdS0vVNNuoL7TtS0++gS5sr+wvbWSW2vLK8tpY7i1ureWSC4gkSWKR43ViAXaACgD8j/+Ctv/AAWF/Zm/4JP/AAN1vxf8RvEmh+K/j/4g8O383wL/AGdLDVVPjT4ja+xkstN1PV7WzFxd+E/hrp2oh5/E3jjVYbaxW0sL/SvD51rxXLpuhXoB/j1/tM/tH/Fz9rz49/FP9pX47eJX8W/Fj4weKrzxb4v1nyRa2n2maOGz07SNIsFZ49L8PeHNGs9O8O+G9Iid4dI0DS9N02FmitUJAPC6ACgD/X8/4Nov2IJf2J/+CUnwSh8TaJJovxV/aSlvP2mviZDe2rW2qWsnxHstNj+Heh3kdwiX1m+jfCjSPBAv9HuxG2l+JL3xGpt4Li4ut4B+/lABQB/g3/tIf8nEfHr/ALLR8Uv/AFONdoA8XoA+pf2Gv+T2P2Pf+zpf2ff/AFbPhKgD/dToAKACgAoAKACgD/Bo/aH/AOS//HL/ALLD8TP/AFNdboA8eoA+k/2M/wDk8D9lL/s5P4Gf+rQ8L0Af7stABQB/KX/wdm/8E2NQ/bE/YW0/9p/4Z6LLqnxp/YibxH44u9P0+1M+peK/gL4hh07/AIW1paJCglubrwUNE0X4lWLXEskdloXh7xva2FtJqGvoGAP8rugAoA+8v+Cbn/BQr43/APBMj9qvwL+1H8D7lL290LzdB8f/AA/1G+ubLwz8WPhrq89s3if4f+JntknaK21FbW11HRtWFpezeGvFGmaH4ltbO6udJjtpgD/Xa/4Jo/8ABV39kb/gqZ8HbD4k/s8+N7O08a2FhA3xN+BHijUdNtPi38K9XAhjurfX/D0Vy02qeGpbmZU0Dx5osd14X1+JhFFeWmtWuraJpYB+llABQAUAFAFW9vrLTbO61HUby10/T7G3mu72+vbiK1s7O1t0aWe5urmd44be3hjVpJppnSONFZ3YKCaAPwQ/bk/4OWf+CVH7Ef8AbHh6T42j9pb4raZ59v8A8Kx/Zjj034kyW+oRbojba/8AEYanp3wp0A2l4Bb6xYSeNLzxRpm2cjwzdzwG2cA/Wn9jz9oi0/a4/ZW/Z5/agsPCtx4Gsfj/APCDwJ8W7Pwdd6vHr934ZtfHXh+y8QW+i3OtQ6fpUOqXGnxXyW817FptlHPIjOlvGpAoA+kKAPNfjJ8X/hx+z/8ACn4hfG34v+KtN8EfDD4WeEtb8ceOfFWrSFLLRvDvh+xlv9QuSiK9xd3TxxfZ9P02zin1DVdQmtdN062ur+7t7eUA/wAZH/grv/wUx+I//BVL9szx3+0Z4s/tLQ/h5YtJ4J+Afw2u7kSQ/Dj4RaPfXUmg6dPFDLLaP4q8QzXFz4q8c6jDJMt54m1a8tbKddC03RLKyAPy/oAlggmuZoba2hluLi4ljggggjeWaeaVwkUMMSBnklkdlSONFZ3dgqgkgUAf64P/AAbdf8EiIf8AgmZ+x3beOviv4ditP2vf2nNP0Lxp8YmvrdDq3w18JrA954F+CUErrvs5vDdrfSa349jhCG78e6rqGmXFxqmm+E/Dd1EAf0ZUAfH37en7FXwi/wCChP7Kfxc/ZQ+NNlu8KfE3w/Jb6X4it7WG51vwB4205vt/gz4h+GjMyCPXfCOvw2mpww+dFb6tZpfaBqhm0bV9StbgA/xWf2vf2Vfi7+xJ+0j8W/2XPjnoh0T4k/CDxXeeG9X8pZjpeu6eUjv/AA54w8O3E8UMt74X8Z+HbvS/FHhu+khhludG1Wze4gtrnzreIA+bqAPR/g/8XPiN8A/in8P/AI1fCLxVqfgj4nfC3xbonjjwN4r0iUR3+ieI/D19DqGnXaK6vBdQGaEQ32n3kU9hqdjLc6dqNtc2N1cW8gB/s0/8Egf+Cm3w5/4Kq/sZ+B/2h/DH9maF8StKEXgj9oD4a2dwXm+Hfxb0mxtpNatbaCeWW7bwj4nhmg8VeBdQmkuDc+HdUg0+8uTr+ka7aWQB+pFABQB/KR/weOfCfVviD/wSR0jxvpcO+D4FftWfB/4j+IphGXMPhzxB4d+I3wcwWHESS+Kfil4VBduC6xx/ecUAf5X1ABQB/S5/wa3f8FKPAf7AH7f9/wCDvjZ4jsfCPwJ/a18Kab8JfFXi/VpzaaH4I+Iela1/avwm8XeI71nFvY+HRqV/4g8Gavqd4sen6FB43HiPVb7T9G0bUrgAH+szHJHLGksTpLFKiyRyRsHjkjcBkdHUlXR1IZWUkMCCCQaAH0AFABQAUAFABQAUAFABQAUAFABQB+Hv/BdX/gjr4Y/4K7/s0aL4T0XX9F+H37SHwY1HV/FPwD+I2uWc9zoIutbs7a28VfDjxw1jDcapB4G8eQ6do5vNW0mC51Xwt4g0TQPElrYaxZ2OqeH9ZAP8xD49f8EWv+CqX7OXi/UvCHxB/YT/AGktSmsLy4tIPEfwy+GHiT4xeBtXjhneOG80Xxv8L7HxT4dv7e7jCXECNeW1/HDMi3thaTh4UAPB/wDh3V/wUG/6MT/bM/8AEXvjZ/8AMV680AJ/w7p/4KD4x/wwn+2Z3z/xi/8AG3knPf8A4Qn3oAX/AId1f8FB/wDoxP8AbL/8Re+Nn/zFUAIf+CdP/BQbr/wwn+2Z1/6Ne+Nvv/1JXfNAB/w7p/4KDZJ/4YT/AGy+n/Rr3xt9/wDqSvf1oA+aviJ8NviN8I/FmpeAviv4A8bfDDx1oyWT6x4M+IfhTXfBPizSk1KzttT059S8OeJLHTtYsVv9OurbULJrqziF1ZXMF3AZIJY5GAOMLAdff17Z9v8AP8wBN3c/3V7HrzQAZ5B9c9j23f4igBAeRk+h7nPy4J6UAKp4GT2JPB9evv780AAbA59v/QR+H60AITnnPZvX+6OP6/8A16AFJ5PPGf6p/jQAm70POH7epyP8aAP7R/8Agyb/AOT6f2sv+zSof/V1eAaAP9K2gAoAa3T/AIEn/oa0Af4LXxqOPi/8VOcf8XI8d/8AqW63/wDr/wAehAPM88ge5P6vn+lACBicZPXH1zu/LpQAuTzz2Y/juPNACE8vz147+hH59P1oAUMSRzwSf0A9f1xQAm7pz09j/dI5/GgBdxOOe/p/uj+p9aAEz79Qc++FH49aAAtkHkfr6j1/z9ewB9BfC79k39qj44+Hbrxf8Ff2aP2gvjB4StdVuNCuvFHwt+DHxG+IPh221y0tbS7utGudb8KeHdV02DVbW0v7G6udOkuVvILe8tZpYliuIWcA9I/4d0/8FBv+jE/2zOpP/Jr3xt9c8/8AFFUAL/w7q/4KDf8ARif7Zn/iL3xt/XPgo0AJ/wAO6f8AgoP/ANGJ/tl9/wDm17429zn/AKEr/PvQAf8ADun/AIKDZz/wwn+2Z/4i98bff/qSvfNAD1/4Jz/8FCHdUT9hL9sxndgir/wy98bMszNhQP8AiiupJAHvQB+zX/BMb/g2D/b8/bI+J/hjVf2lfhZ47/Y//ZosdQsL/wAeeMPivoZ8KfFPxLoUdwJb7wt8L/hhroTxQPEetWq/ZLbxb4v0XSfCHhy3un1wnxJe2Ft4a1MA/wBVP4YfDbwT8G/hx4D+Enw28PWHhP4e/DPwh4d8B+CPDGloyafoHhTwppNromg6Rah2eRorDTLK2txLK7zTmMzTO8sjsQDuqACgAoA/lw/4OV/+CINx/wAFKfgtp/7R/wCzpoVo/wC2f+z74a1C30zRLeGKG6+P3wrtpLnWLv4Wy3RKf8Vp4fvptS1z4W3Nw5trrUdU17wjfeXH4msNX8PgH+VJqml6nomp6joutadfaRrGkX13peraTqlpcWGp6ZqdhcSWl/p2o2N3HFdWV9ZXUUttd2lzFFcW1xFJDNGkiMoAKNABQB+xP7FX/Bev/gqZ+wX4e0fwH8E/2m9c1v4UaEY0034R/GHR9H+LXgXTbGFVWLR/Dx8X2t54r8E6Gm0sujeAvFPhbTxLLNP9n86aSRgD92fA3/B7h+2RptpZR/En9jb9mrxfeRQxJf3XgzxN8T/h/HeSqoEs0FtrOsfEf7GJSCwjaa6EZbhmUAUAd1rf/B8F8frgN/wjf7A/wf0okfIdb+NHjTxAFPqwsPBvhkuM9gyfXvQB8t/FP/g9A/4KbeLoJbL4a/B/9kr4R28kZC6nB4K+InjnxNBKQRvhvPE/xMPhkoPvLHP4PnbcPmlZcoQD8h/2lP8Agvh/wV2/ass7rR/if+298WdG8M3aSW83hT4OyaH8BtCuLGbd5mm6pH8G9I8E3/iOwcMyyQeKNQ1szJtSZ5ERFUA/Im+vr3U7261HUry61DUL+4mu76/vria7vby7uJGlnubq6uHknuLieVmkmmmkeSSRmd2ZiSQD+8D/AIMcf+Sg/wDBR3/sTf2Yf/T38c6AP9C6gAoA/wAW7/gu5/ymG/4KH/8AZy/jj/0K0oA/JigAoA/3nvgF/wAkJ+Cv/ZJfhx/6h2jUAetUAFABQAUAFAH8tX/B4J/yh61T/s5f4H/+g+MKAP8AKcoAKAOqbwJ43TwRF8TX8G+Kl+G9x4quPAkHxBbw9q48ET+N7TSLXxBd+DYvFZs/7Bk8VWug31lrdx4eS/bV4dIvLXUpLNbO4imcA5WgD9PP2NP+Cy3/AAUt/YI07SvDP7NX7V3xC8NfDvR5nksvhN4sbSviZ8KbWG4na5vrPSvAfxD0/wASaH4Yh1GZ5Zb2fwjB4f1GSeWW7jvorx/tFAH7Y+Ev+D0P/gqbocS2/iP4Q/sU+NkCYa71D4Z/F7RtUeQLhXMvh/48afpYBb5pUXRhu6RtCKAPCfjz/wAHcv8AwWB+NHhzVPDXhfxV8CP2dItVVoZta+BXwnuYfE9vZyK6TW2na58WfF3xZn0qSZGx/amlJZa1auqzadqNjMA4AP5yfin8Wvil8cfHev8AxQ+M/wARvG/xX+JHim5S78SePPiL4o1rxl4u1yeKFLeB9T8QeIL3UNUuxbW0UNpaRzXLRWlpDDa2yRW8McagHn1ABQB/Rv8A8G1//BJef/gpN+2pp3j74qeGJdQ/ZJ/Zcv8ARPH/AMXH1Gzd9C+IvjFLk3fw9+Cyyyo1vfxeItRs28QeObILNGvgHRNU0q9k0688VaBcTAH+t+qqiqiKqIihURQFVVUYVVUYCqoAAAAAHAoAdQAUAf4N/wC0h/ycR8ev+y0fFL/1ONdoA8XoA+pf2Gv+T2P2Pf8As6X9n3/1bPhKgD/dToAKACgAoAKACgD/AAaP2h/+S/8Axy/7LD8TP/U11ugDx6gD6T/Yz/5PA/ZS/wCzk/gZ/wCrQ8L0Af7stABQBDcW9vd289pdwQ3VrdQy29zbXESTW9xbzI0c0E8MitHNDNGzRyxSKySIzK6lSQQD/KN/4OP/APght4j/AOCb/wAcNW/aT+Afhi5vv2Hfjj4svLzRE0iymkt/2ePH+tzzX918Jtf8pXSz8HX87XVz8KNamMcUmlRzeDNQZtY8P22p+JQD+X+gAoA7b4dfEr4ifCDxpoHxH+E/jvxh8M/iD4VvU1Lwz448BeJNY8I+LNAv0BVbzR/EOg3lhqunXGxmRpLW6iZ43eNyyOykA/pJ/Zq/4O5P+CuXwLt7LSPiN4o+D37U+g2kKWir8a/htb6Z4pitIkCReR4v+Eeo/DW+vr5dq+Zqfiq18U3lyDI1288zrOgB+jmg/wDB8D8f7e0dPFH7A/we1i/MeI7nQfjP418N2iy8fO9jqHg7xVM8fX90NQjbp++oA5nxB/we7/tY3KTDwt+xL+zxo0jK4gbxB46+JPiVI3IOxpk06Twm06q2C6JJblwCA6E7gAfB/wAXf+Dvb/gsX8SBdJ4M8V/s/fAOOfesJ+FXwQ0vWbi1RshTHN8bdZ+MCvMq9ZXhKl8ukcYwqgH4c/tLf8FAP22/2xrye6/ae/an+OHxptZrj7Unhzxn8QNeu/BGnziTzQ2i/D+1u7TwPoCiQCQR6J4f0+IOFYJuUEAHyBQB/tj/APBGP/lEv/wTh/7My/Z8/wDVbaBQB+mNAH+bz/wdsf8ABZD/AIXV8R7j/gmL+zz4q874T/B7xFbaj+1J4j0W93Wnj/4x6HOtxpXwpW4tZPLvPDXwju1W+8U20kk0F78UhFY3VnaX/wANba5vgD+I2gAoA/sP/wCDTr/gkD/w1b+0A37f/wAdvC/2v9nr9mHxVbx/CXRtZs92m/FP9onTUtdV0zUFhmQrf+GfgzHPp/ii+f8Ad29747vPB9jFLf2uj+K9MjAP9OmgAoAKAP5GP+DrL/gkB/w2T+zgP24fgX4X+2ftL/sr+Fb6XxxpOj2Xm6v8XP2eNPkutZ17TBDChm1HxP8ACia41Pxr4ZjQ/aL3w5deONDhh1TVbrwzZ2wB/l3UAFAH7N/8ENv+Crvi3/glB+2ZoHxLvbjVtV/Zz+KR0rwB+014FsPNuTqngR75307x1oumhjFceN/hffXlz4i8OkIt1qemTeJvB0d3YW3i28vIQD/Y28E+NfCXxJ8G+FPiH4C8RaT4u8D+OvDmi+L/AAd4q0G8i1DRPEnhjxHp1vq+ha7pF9AzQ3mm6rpl3bX1lcxsUmt543HDUAdPQB8U/wDBRz9ku0/bq/YY/af/AGTbi7t9PvvjR8KNe8P+FtTvQGsdJ+IGmNbeJ/hvrGoKUcvp2keP9C8NalqCRhZ3s7WdbeWGcxzIAf4fnivwt4i8DeKPEngrxfo994e8WeD9f1jwt4o0DU4Tb6lofiLw/qNzpOt6PqEBJMF9pmpWlzZXcJJMdxBIhJK0AYFABQB+8/7A/wDwch/8FQv+Cfvg7QvhZ4J+J3hf43/BrwxbWun+GPhZ+0Z4f1Hx9pPhPSLRfJi0fwn4r0fxB4T+I+h6Na2ojttK8PJ4yuPC+iRW8EelaDbQiaGcA/U/V/8Ag9m/4KBzafFHoP7K37HOm6qIyJ73V9P+Net6fJLzh4tMsvi34fuYY+mY31edup83nAAPjP42f8Hb3/BZD4uaZLpXhb4hfBP9nuK4WSO5u/gn8GNJbU5YJchootS+MWq/F+805gpKx3mkzafqMPDw3kcoEgAP6of+DRT9q39pf9rn9nb9sz4gftPfHf4qfHjxhYftB+E9N0nWvih4113xdLoGlTfDu0vZdH8NWurXlxY+GdFe8lluzo2gWunaX9qlluBaCaR3YA/rtoAKACgAoAKACgAoAKACgAoAaUXngjJydrMuSepO0jJPqcmgBNg9X/7+Sf8AxVABsHq//fyT/wCKoANg9X/7+Sf/ABVABsHq/wD38k/+KoAQoMHl+h/5aSf/ABVAH+RZ/wAHUTE/8Fuv2syxLY0L9ncDezPgD9nf4ahQCxJCqAAoBwAMAY4oA/nk+btj8c98/wBDz75oATnoMdB64xyP59PUUAHORwM+2ep3fp1zQAmTnoO3TPUrx+H9KAFBJHGO+OvXOT+H9eKAAZI4x+OQeg6d+/5fXkAOe+P4s9fbr+Y+goAD17Z/HuV6/l/L1oATnvj+Lu3rg559f8aAP7R/+DJv/k+n9rL/ALNKh/8AV1eAaAP9K2gAoAa3T/gSf+hrQB/gt/Gn/kr/AMVOn/JR/HfX/sbdb/z9M0AeZd+3U+uf4v8A69AB6fd7Z655bsfT+uaAD16chh3z1PJ9vfsaAE5y3A9TnPufz9fXnNACjqM4zk9M55H6n1z25oATnjhefr6Hr+HHegBfrjP4+q/mePzx68gCev3f4u5/ug8c/wCR0oACCAc46ds56jnn9T9M5oA/1F/+DMvLf8Eq/iepZ9o/bW+K5Ch3ABPwr+B+SAGABbA3Efe2rnO1cAH9bWwer/8AfyT/AOKoANg9X/7+Sf8AxVABsHq//fyT/wCKoANg9X/7+Sf/ABVABsHq/wD38k/+KoAcFAyQOT1Pc46ZPU4HqTQAtABQAUAFABQB/K3/AMFzP+Daf4T/APBSC58R/tM/swX3hz4GftotYvda+l5bfYPhV+0LcWsWIE+ISabazXXhf4gvGiW1l8TNMs7/APtKNI9O8aaPqqGw8QeHQD/M9/am/Y//AGmf2J/ijqPwa/an+DPjb4L/ABC0/wA2WLSvFmmhNP1/T4pjB/bng7xNYyXvhjxt4clmVooPEfhLWNZ0SeZJIY79popY0APm2gAoAKACgAoAKACgD/QU/wCDJT4NfF3wc37dHxW8XfDDx/4W+GXxK8Nfs9af8OviB4i8I69ong7x7eeHdV+MNxr8HgzxFqVhbaV4obRIdY0l9WbRLq+TT/7TsRdtE11CHAP75KACgD/Fu/4Luf8AKYb/AIKH/wDZy/jj/wBCtKAPyYoAKAP9574Bf8kJ+Cv/AGSX4cf+odo1AHrVABQAUAFABQB/LV/weCf8oetU/wCzl/gf/wCg+MKAP8pygAoA/vo/4NU/2dPgT/wUB/4Jf/8ABRn9hn9o3wwniz4aax8evBfjCaK3khtvEXhDxB42+Gdto+gePvBWqzW92dA8ZeHNQ+Gcd9omrLb3EDvbTadqtnqmiXuqaVegH82v/BXf/giP+1X/AMEmvibqC+NNE1L4l/sy6/rktp8KP2l/DmkTDwnrtvcmSfTfDfjy2t5Lz/hXfxGitlaO58OazcCx1uW0v77wbqviHTLS7ntAD8YaACgAoAKACgD9jP8Agkn/AMEVP2r/APgrJ8UbGx+HehX/AMPP2dPD+uQWfxb/AGlvE2kTnwV4TtIfLuNR0LwjDNLZf8LD+I8lnJGLDwhoV0UsJr3Tr3xfqfhnQ7pNUYA/1vf2Jv2LfgJ/wT+/Zx8A/swfs4+Fv+Eb+HngW0d5729a3uvFPjfxTfrE3iLx/wCOtZgtrT+3fGPie7iS51S/+z21pa28VjomiWOleHdJ0fSLAA+r6ACgAoA/wb/2kP8Ak4j49f8AZaPil/6nGu0AeL0AfUv7DX/J7H7Hv/Z0v7Pv/q2fCVAH+6nQAUAFABQAUAFAH+DR+0P/AMl/+OX/AGWH4mf+prrdAHj1AH0n+xn/AMngfspf9nJ/Az/1aHhegD/dloAKACgDg/ij8Lvh18bPh54x+E3xc8F+HfiL8NPiBoV94Z8aeCfFmmW+seHvEeh6jH5d1p+pWF0jxSoflmglXZcWl1FBeWk0F3bwzRgH+a//AMFkP+DUT49fsxav4m+PH/BOvRfFn7Rv7Ok8t/rerfBa1D698e/g7alpLmSx0TTogdR+M/gyzz5Ol3eg2918SLC1aC11vw/4hjsNR8aXYB/HZe2V5p15d6fqNpc2GoWFzPZX1jewS2t5ZXlrK8FzaXdtOqT29zbzo8M8EyJLDKjxyKrqQACtQAUAFABQAUAFAG/4W8KeKPHPiHSPCPgrw3r/AIw8WeIL2LTdB8MeFtH1HxB4h1vUZ8iGw0jRdJt7vUtSvZiD5VrZ2008mDsQ4oA/20/+CTvgTxp8MP8AgmT+wR8O/iN4U8QeBfHvgr9kz4GeG/GHgzxZpN7oPifwv4i0n4faHaaroXiDRNSht9R0jWNMu45bTUNNv7eC8srqKW3uYYpo3RQD87/+Din/AILAWH/BLr9kS48O/DDXLQftg/tG2GueD/gZYRSQ3F98PtGSBLTxj8cNSs33pFb+DIL2Ky8GR3qPDrHj/UNIP2LVdE0HxVFagH+RRqGoX+rX97quq3t3qeqand3OoalqWoXM15f6hf3kz3N5e3t5cvJcXd3d3Ekk9zczySTTzSPLK7u7MQCpQB9qf8E9v2G/i1/wUY/a2+Ev7J/wdtni1z4ha0snifxXNZy3ej/Dj4d6QUvPHHxF8QiN4lGl+GNFE09vayXNrJruuTaP4Y0+Y6vrmnwygH+1J+yt+zL8Jf2Nv2efhN+zH8DdAXw58MPg74RsPCfhuzbynv79oTJd6z4k166higTUfE/i3XbrU/E/ijVfJibVPEGrajftHGbjYoB9AUAFABQA10WRWR1V0dWR0cBldWBDKynIZWBIYEEEEg5oA/yZf+DmH/gkG3/BN/8Aa4k+Mfwd8MtYfsg/tTaxrXij4eQ6baldH+FPxLLNqnjv4Nv5KC303S4pbiTxX8NbZ1tYpPB95deHNNjvX8B6xesAfzR0AFAH99P/AAaMf8FkvsF1bf8ABKn9ovxViyv5tX179jjxZrt7hLS/la61vxd8AZ7y4fasWoyHUfGXwyimKY1E+K/CcV1NNqPgrRYgD/QPoAKAP8+//g6T/wCCCHjXVPHHin/gpd+xT8Nr7xRp/iWDUPEP7YPwo8F2H2rW9K8QWiCe8/aB8LeHLNTd6xp2vWolm+Ltjo9tNqOm6xaP8R7i11Cz1zxrq2ggH8C9ABQAUAFABQB/pF/8GRX/ACaJ+2p/2cf4O/8AVZWNAH9ttABQAUAFABQAUAFABQAUAFABQAUAFABQAUAIeh+hoA/yKf8Ag6hz/wAPuv2tMdf7D/Z4Pv8A8m8fDX/9dAH88hb0K/if/r/WgAB68j+HnPHfPOev/wBbNACZPqPzyP4vfpyM0AHIPJ4+uegOf16+9AACcDkZ5+8T6jr+H4/rQAZPrz05PHQdfxB/HPvQAE98jkN3/LoevH/oWKADPvz6Z56qfp0z+H40AGT6j+LPPHJ47/l7dKAP7Rv+DJv/AJPp/ay/7NKh/wDV1eAaAP8AStoAKAGt0/4En/oa0Af4LXxpOPi/8VOf+aj+O/8A1Ldb/wAj3xQB5nnkcjGTnnnvjv05H14oAM+/p0OR1JPJ56DmgAz156hu59cj9D9cYxQAZPzYPXp+ucc/yzzigBc9CSO+efw4HpkHrn16mgBM9OenXnnoc559SOvfr2oAM+pX3wT7e/8Ak/U0AGevPqBzyeOPr3z/ALVAAxOOvJGePqM/h6e2cmgD/UW/4Myv+UVnxQ/7PV+K/wD6qv4H0Af1u0AFABQAUAFABQAUAFABQAUAFABQB4V+0J+zD+zx+1j4Bu/hd+0r8F/hx8b/AAFeea//AAjnxH8K6V4ltdPu5Y/K/tTQri/t5L/w5rkKY+ya9oF3pus2TqktnfwSorgA/lQ/az/4Mwf2Fvipc6jr/wCyh8cPi9+ynrN5NNPD4U1+2t/j58LbFCzSRWWl6Z4i1jwn8SrJWLGBrzVPin4k8mIRSJYyPFIlyAfhT8XP+DL7/gpb4QvbuX4T/GX9lL4xaFHu+w+f4u8f/DnxbdBScfadB134fal4asy67doj8d3oDl1dkVVkcA+MNZ/4NS/+C3ulySpY/su+DvEaxuypLo37Rn7PkEc4UkCSIeIfiRoMoV/vKJ44XAPzojZFAFjSP+DUX/gtzqW37b+zR4G8P7sZ/tf9or4DT7M9d39g+P8AW8477N/tmgD6I+HP/Bm9/wAFaPGM6f8ACX+If2UPhLaBx57+L/i54p1698rI3NaWvw5+GnjW2nmwTsiudRsY2IIeePgkA/T34Af8GQRXUbbUP2pv26/N0mMxfbPCXwA+Fn2fUbtScz/ZviJ8RdaurbTygBji834X6kJS/nOYvL8mUA/os/Y5/wCDcT/gkp+xdqmmeK/CX7N9r8ZviJpPkPY/EP8AaW1X/hcerW1zbMJLfUrDwnqljp/wq0bWbecC5ttb0L4eaXq9pcBHtb2ERRLGAfuZDDFbxRQQRRwQQRpDDDCixxQxRqEjiijQBI440AREQBVUBVAAAoAkoAKAP4t/27v+DQb/AIbY/bD/AGiP2sP+Hhf/AArT/hffxM1z4i/8ID/wyb/wmf8Awin9tGE/2P8A8JT/AMNL+FP7d+zeV/yEP+Ec0fzt3/HjFjkA+S/+IGP/AKyif+aT/wD5W9AB/wAQMf8A1lE/80n/APyt6AP7z/APhb/hB/AngrwV9u/tT/hD/CXhzwt/af2b7F/aP/CP6PZ6T9u+x/aLv7J9r+yfaPs32u68jzPK+0TbPMYA62gAoAKACgAoA/lq/wCDwT/lD1qn/Zy/wP8A/QfGFAH+U5QAUAf3t/8ABjf4okg8V/8ABSHwU7s0Wp+Hv2W/FEEZOVik0LUvj1pN06DPDTr4is1lIHzC3hBPyjIB/fn448C+Cfib4S1/wD8SPB/hfx/4F8V6dNo/ijwZ410DSvFHhXxHpNzj7Rpmu+H9btb7SdWsJtqmW0v7SeByqlkJUEAH8l37c3/BnV+wj+0Bqes+Nv2S/iL42/Yy8Z6rcz38vhK200fFz4HPcTM080em+DNd1vQPGfhQXdwzqq6P8RLjw5o1u6RaR4OitraKzYA/nM+Mf/Bm9/wVX8A3l+/wy8T/ALMfx30ZJHOlv4a+Jmt+CPEl3bg4Q6jo3xI8HeGtD027bGWt7Xxhq9sgK4v3O4KAfK7f8Gqv/BcQXotR+yX4beA9dSX9o/8AZr+xDnHMbfFhdR568aeeOvPBAPp34P8A/BnJ/wAFYPH97ZH4ka1+zL8CdIeZf7Tl8W/FPVfGWvWtrn94+n6R8MfCHi/SNRuwOY7a68UaTbyc77+E4yAf0XfsN/8ABnD+w78CNT0jxr+198T/ABt+2P4t0y5t7+LwVFprfB34IpPEyzpBq/hrRNd1/wAdeLhaXKIA178QNH0DV7dZYNY8IXFtcyWiAH9bngH4feA/hV4O8P8Aw8+GPgvwp8O/APhPTotI8L+CfA/h/SvCvhTw7pcBYw6donh/Q7Sx0rS7ONmdlt7K1hiDu77dzsSAdfQAUAFABQB/Bv8AEj/gyS/4WD8RPHvj7/h5p/ZH/Cb+NPFPi/8Asr/hjL7f/Zn/AAkuuX2tf2f9u/4ausvtv2L7b9m+1/Y7T7T5fnfZoN/lKAcX/wAQMf8A1lE/80n/APyt6APU/gb/AMGV3/Cl/jZ8HvjF/wAPKv8AhJP+FT/FP4ffEv8A4R3/AIY4/sf+3/8AhBPFukeKf7F/tf8A4ao1X+yv7V/sr7D/AGl/ZmpfYfP+1fYLzyvs8gB/dTQAUAFABQAUAFAH8GnxD/4Mj/8AhPfH/jnxz/w81/sr/hNPGPibxZ/Zf/DGP27+zf8AhI9avdY+wfbv+Gr7P7Z9j+2fZ/tX2S1+0eX532aDf5SgHHf8QMf/AFlE/wDNJ/8A8regD0r4M/8ABlN/wqP4wfCn4r/8PLf+Eg/4Vj8SvAvxD/sH/hjb+yf7c/4QvxRpfiT+yP7U/wCGqtS/s3+0v7N+xf2h/Z2ofY/P+0/Yrry/IkAP7sqACgAoAKACgD8p/wBu3/gij/wTc/4KKG/1n9on9nPw2nxNvVJHxv8Ahk7fDP4wifbsjuNV8XeGo7dPGv2eMulpZfETTfGGlWm9nt9Pjm2yKAfywftIf8GQ0L3up6r+yJ+3E9vpzmQ6P4F/aO+HIu7y3HzNGNR+KvwzvLSK63ZWNzb/AActCm0yjzS4iQA/JH4hf8Gfv/BYbwZJKnhvR/2bPi2iOVSb4f8AxwXTFmXdgSIvxU8KfDSRQR82JURgOME0AeFS/wDBqz/wXGju1t1/ZF8PzQnOb+P9pH9mUWq4PVkm+LsV8c9Rts2OM5wcAgHc6N/waWf8Fp9UaNb74K/Cbw4HKhn1n9oH4YTrCGIBaT/hHtZ15yFzlvKWViAdoY4BAPsn4Y/8GVP/AAUR8RfZ7j4qftGfsk/DOym2mW10DWPip8R/ENoD98XFgPhv4P0F5F52ra+KrmN8czJQB+yH7M//AAZVfsX+BP7P1X9qb9pf43/tB6vb+VNceH/h9pfh74FeArqQ4aay1CFn+JPji+tUyYo7vSvGvhe6m2i4aK33/ZkAP6cP2P8A/gnH+w9+wR4f/sD9kr9mv4afB6Sa0FjqfizStJk1v4k+IbUFW8jxP8UfFNxrnxE8SW4kXzY7PWfE17ZW0jyG0t4A7LQB9sUAfx1/8FHf+DV74xf8FLf2tfiX+1d8Zv8AgqP/AGfqXi+7j0rwR4Ftf2OZ9U0L4V/DLRZLiPwb8OPDtzN+1fYi4stCs7ia51TVI9N0xvE3inUfEHiy70601DXruFQD4X/4gY/+son/AJpP/wDlb0AH/EDH/wBZRP8AzSf/APK3oA/og/4Im/8ABCn4Rf8ABG/wz8Wbyx+J3/DQ/wAcvi/qVlZ698ab/wCHEHwzm0n4b6Mlvc6N8OPDnhb/AITb4iy6Vp7a/wDbvEXibUo/FLN4qvx4fW+sIIvCmkbAD93KACgAoAKACgD4o/4KGfsK/CH/AIKPfsl/FX9k74zRfZdC8f6ULjwv4xttPh1HXPhn8RNH8y78FfEfw5DNPaGTU/DOrFZLrT0v9Pj8RaDc614V1C8i0nXdQDgH8bX/ABAx/wDWUT/zSf8A/K3oAP8AiBj/AOson/mk/wD+VvQBv+Ff+DI3xJ4G8UeHPG3g3/grDqvhfxf4P17SPFHhXxLoX7Gk+m634e8R6BqFvquia5o+o2v7Xcd1YappWp2ltf2F7byJPa3UEU8TrIisAD+6H4XaJ4+8NfDfwL4e+KnjrSvid8SdD8KaHpPjn4jaJ4MHw70rx14o0/T4LXWPFln4EXxH4uj8JR6/exS6m2gQeJdYtdNluZLa0u2tkiRADvKACgD+aX/go7/wa0/8E7P269S8RfEf4a6fqX7G3x68Q3t5q+p+O/g3pFnqHw78Ta1fzPcXmpeNvglfX2leGry4uZ5ri8u7zwHrHw31fU9Sne+1vVdVkLo4B/LJ8d/+DML/AIKP+A9Rlk+Bnxi/Zr+P3hsyvHbPea/4p+EfjQqu5lnvvDfiPw/rnhW2ikXaoFp8RdSmWVirQiJfPYA+KtX/AODUz/gt9pt6lrZ/st+D9fgZiralpP7Rn7PUNlGB/G6a78StF1Eq3YJYO/qg5wAej+Bf+DRT/gsv4uvY7XxB8P8A4EfC6B9u7UvHXx58MahZRbjz5ifDO1+IuonZ1fyrCXI+5vPFAH6i/s+f8GQ3xXv57O+/ar/bh+HvhS2ilR9Q8Mfs+/DrxJ8QJ9Qh3DzYLPx18Rrr4aR6PLsyUu5vh5rqBsBrMg7gAf2Of8Ezf+CWH7Lv/BKP4QeJfg/+zGvxCv7Hxz4js/F/jzxZ8TfFkfijxV4s8SWOkwaLbahdJpmleHvDGkRQWEAijsvDnhvR7ZtzSXKXM2JQAfpFQAUAFABQAUAFABQAUAFABQAUAFABQAUAFACHofoaAP8AIp/4Oof+U3X7WnJH/Ej/AGeOn/ZvHw19xQB/PIc9vfoM9/c9f580AHPqc4XqPX2z+dACZPqc/Tv83vjt+PFAC8569+/rtz6/j9fzoATJwOSeD2yev19/60AAzjjPbtnsvvQAEn17N2/+v+Xrx60AKTz17j+a/wCP60AJk8cn+Ptz19P8+negD+0b/gyb/wCT6f2sv+zSof8A1dXgGgD/AEraACgBrdP+BJ/6GKAP8Fv40Z/4XB8VMf8ARSPHfv8A8zdrX+TQB5lzkderduM5bv6+1AByR17jqMc7vr/n86AFz15/vn8j1oAQk/Pye34fTn8z+NAC5ORknn29u/PHf8c9qAEGfl+g/wDQT780AAJ7569wB6f4/kSe3IAc/N/wLPHsPf8ALrkUABzg5PYdsdT9fzoA/wBRb/gzK/5RWfFD/s9X4r/+qr+B9AH9btABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQB/LV/weCf8oetU/7OX+B//oPjCgD/ACnKACgD+6L/AIMfP+S7ft/f9kl+CH/qY+O6AP8ARWoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKAEPQ/Q0Af5FP/B1D/ym6/a0ycf8SP8AZ47Z/wCbePhrQB/PESD1K9+xPf1/z696ADj26Dkgnpn8fr6dOaAE4PGQevb/AHj+GM9O/H4AC5Ge2evTtt/ljnHrx70AAxgf4HJy2e2e4wB9TQAcdD39iT0Hp7YJ/wDrZIAce3RucEdcZ/Q8eucccZAAkZznv9f7v1z09e59KAD5fy3dj3Pf8On9DQB+in/BOH/gqB+05/wS1+Jfjz4r/svP8O08V/EbwGnw68RH4i+D5fGOm/8ACOp4j0rxSPsFnHrGim1vv7T0i03XLTzL9n8yIwbykyAH7Df8RgX/AAV5/wCe/wCy9/4Yy5/+bugBf+IwL/grz/z3/Ze/8MZc/wDzd0AA/wCDwP8A4K8ghvP/AGXvlIb/AJIZdgHDAjJHjwEA+oIPdSOoAP5fvEevX3inxBrviXVTb/2l4g1nVNc1D7NCYbf7dq9/c6ld+RAGbyYftN1N5UQZhHFtTc2NxAMbvnvk/T+LOT+f5e/AAgxwMgnjHHPXPXt/k98UAHryOjfqT378g4HfrQAHaS3v7Z6DnB+vOTjP60ALxkcjgn1H1yT3Hr3oATK8dP8Avk+h6+vJ7f8A16ADj1HX3GOR1zk9QB+J9KADjn8ex7gE49PUZ65I96AA4wcY/Ig8H1PXnGe/egD/AFF/+DMr/lFZ8UP+z1fiv/6qv4H0Af1u0AFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFAH8tX/B4J/yh61T/s5f4H/+g+MKAP8AKcoAKAP7ov8Agx8/5Lt+39/2SX4If+pj47oA/wBFagAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAQ9D9DQB/kU/8HUP/Kbr9rTk/wDID/Z46df+TePhr70Afzxt9SOv8/cj16/4jIAde56L69/x6n/9WSaAE/E9Dz/33nvz+f8AOgBe/U5z7/3OvXr+p9aAE7ZyenX/AIF9fpn+dAByR1PbPvlV65I/X+Z5AD8T/Gefpjpn6+/86AFPX3z9O6e+aAE9OT0Y9SfUdz/Ln1POaAD05P8AD79hjPPHOT+PGaADnJ5OcHsfUdOc/wBPegAx82cn73+e/wCHrjnGKAFPXqf8vzzQAmODyeo9fT6/17DHUUALn5hz3PH4t7/0/GgBB2OSeR69d3Xr1/P8yKAF9evR/wD0I579f85oAQ/xcng+/fPv/n3zQAo6jk9SR+X17dvX9SAJjpyeg9ePlPv/AJ6DvQAD6k88/mvuc/8A1z+IAc+pyN38h3ye/P19KAAjAPJ6D8ifXJoA/wBRf/gzK/5RWfFD/s9X4r/+qr+B9AH9btABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQB/LV/weCf8oetU/7OX+B//oPjCgD/ACnKACgD+6L/AIMfP+S7ft/f9kl+CH/qY+O6AP8ARWoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKAA8gj1oA/yZP+Ds/wCHfiPwZ/wWa+MvibWbC5ttJ+LXwq+Afj7wfdTRFYdT0PT/AIbaX8Nr+4tpCNsiWvinwFr+nzAHcktuQ+AylgD+ac/7v6A/4/5P1IAEx14/u8Hn1/z/ADxzgAMdsHp+P8ftnn6UAL36d/Qf3OnX9OnvQAg6Dg/5bPPBz+X4HnAAYyOmenbP8K/U/ofw60AGPb+9wPfH19f8M8ZAA8547/h1X3Pp6+vPoAGOnB/j6d+39e4Ht6EAOfTpjtyDgfT8f129aAFI5OB1HXAwec569+vXPqPUAMc5x/ETyP6+nf8AXJPFAAfp+ffLZ/zkj8eoAExweO47e3+c59TnGTgAX+IH3b+bf56/40AIOg47jk4z9716/p3oAX14PRh78k/5/lnnAAh/i45/D3+uPc859uoAF5yDg9Sew6gdfr74Pt2oATHTjqB2Hoffn1659cY5AD8D1z9eVPoPTPPoc85wAGOvH97t04H+ep/HrQAYJzxycAYGMknj8z7c9wvcA/1VP+DPn4d+IvBX/BIz/hI9csbmzsPi1+0/8aPiB4RlnjMaal4a0/TfAnw1bUbfcAXt5PEngLxHaJJ0drKQoSuCQD+qCgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoA/lq/4PBP+UPWqf9nL/A//ANB8YUAf5TlABQB/dF/wY+f8l2/b+/7JL8EP/Ux8d0Af6K1ABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAfiV/wAFrf8Agix8IP8Agr58GPD+kaj4hj+FP7RHwmXWrz4K/GWHSBq9tax60kEus/D74g6TBJbXuv8Aw98SXdlY3haxuote8Ia9bQeIvD73MMuv+HvEgB/n1fFL/g1b/wCC03w78S3uh6B+zX4Y+L2k29xLDZ+M/hj8bvhJJ4d1eKNmUXdpaePPFPgXxZZxSbcrDrXhvTrpchWiOC1AHmn/ABDN/wDBb3/oxjxD/wCHl/Z2/wDntd+p9TzQAf8AEM3/AMFvf+jGPEP/AIeX9nXr6/8AJWu3b0wPSgA/4hm/+C3v/RjHiH/w8v7Ov5/8laznPP15oAP+IZv/AILe/wDRjHiH/wAPL+zt1z1/5K117fTigA/4hm/+C33/AEYx4h/8PL+zr+ufi1+P1JPegD8a/jH8IPiN8Afir8Q/gl8XfDkvg/4n/Crxfr3gPx94Wn1DStVm8P8AizwzfS6brWkyanoV/qWjXz2N9FJC13pmoXllMV8y3uZoislAHmvPXnP/AOr2B6Z7dz3IyAKcn179sc9Rj+fX64NACZIH8j/P16nPXr1G7OKAA5I75/HPUc//AFwO56ZxQAvt7/pnp6dOevTtQAnQ/wCT3P8ATj1xx1wKAA55P5Hn0PT6nH4kdeKADHPsc8fnj+Y4I9PQ4ADnpyc4znv8xzk8jp79OMHsAffv7Ff/AAS7/bs/4KIab8QtX/Y5+Amo/GfTvhXe+G9O8e3Fj42+G3hIeH7zxfb6xd+HYnj8e+MPC8t82o22g6rIj6Yl6lsLQrdtA0sAlAPuH/iGc/4Lff8ARjHiH/w8n7Ov/wA9mgA/4hm/+C3vf9hfxCfr8Zf2dufr/wAXa/H680AH/EM5/wAFvv8AoxjxD/4eT9nX/wCezQAf8Qzf/Bb3/oxjxCf+6y/s6/8Az2f85PqaAD/iGb/4Le/9GMeIf/Dy/s7f/Pa7dR780AfpX+wR/wAGff7dHxa+I/h/Vf2577w1+y18FNPvYLzxTo3h/wAaeE/iT8bfFWnxSLLJo3hGz8H3PiPwL4Ul1ONJbJ/FPinxBeTeH3ljv7bwd4gkiFo4B/pO/Bn4PfDj9n34U/D34JfCHwppvgj4Y/CzwjofgfwP4V0lXFlovhzw9Yx2GnWgmmaS7vrpo4zcajqmoTXOp6tqM93qmpXVzf3lxPIAem0AFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFAH8tX/B4J/wAoetU/7OX+B/8A6D4woA/ynKACgD+6L/gx8/5Lt+39/wBkl+CH/qY+O6AP9FagAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgBCoPUA/UA/wA6AE2L/dX/AL5FABsX+6v/AHyKADYv91f++RQAbF/ur/3yKADYn91f++RQB/ij/wDBaQf8bZ/+CjP/AGeT8f8A1/6H3VPT/P40AfmN7/r36r6ZHb37deaAE9BgcBv7349vz6+3NAB/9bPXsB6jt1GSP9qgAOTn3HX5s4znsMH8M98HHFAC85/HP8XX67fz5xjt3oADn/O7+9n06/nnjjFACc4/EdN3p/u5/wAjOe4AvcHjqfX1bjOMf1oABnj8P73r7jucd+oHagD/AEM/+DHgA/Db/govkA/8Vt+zJ1H/AFLnxm9f59+tAH932xf7q/8AfIoANi/3V/75FABsX+6v/fIoANi/3V/75FABsX+6v/fIoAcAB0GPpQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQB+WP/AAWG/wCCasv/AAVd/Y6uv2T4vjNH8CHufiZ4H+In/CeSfD1viaqDwaNYB0j/AIRhfG3gAsdR/tbi/wD+EgX7J5H/AB53Pm/uwD+Ub/iBmvv+kndp/wCIaTf/AEVFAB/xAzX3/STu0/8AENJv/oqKAP3W/wCCHP8AwQKuP+CNPjz9oDxrN+1ZD+0WPjn4S8D+Fl02L4IP8JT4YPg3Wde1Y3xvH+LnxK/tn+0f7b8gWwtdK+yfZvN+0XPneXEAf0Y0AFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAf4ov8AwWk/5Sz/APBRrP8A0eT8f/8A1PdU/pn/ABoA/MY9fTnv/wAB75Pt/XvkATg9x/F+H6jr3yfpgcgAUfUdvqcYOP5YwfqTzQAHHJyffkZHPTOfU/8A1+xADj15znqM56Z69fXtj+HNAB+P5/73+POcYzjoOKADjnnuOhHp9evHHOOmckGgA79ecn69W/n3yMcn2AAAY459OMjHX6k/r168cUAf6Gn/AAY7/wDJN/8Agov/ANjr+zJ/6jfxmoA/u/oAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKACgAoAKAP8AFF/4LSf8pZ/+CjX/AGeT8f8A/wBT3VKAPzFJ5J9+/wBU70AGQe3Zsc+uc8Y/LP60AGf129+eAPbn8+DycA0AGeSe+PUdMj2wP1Pr2oAM8/8AAj375+np+GOPvUABP9T1/wBv/PJ/xoAM8Hp1Hf29+e3f8ehoAUfeHrk/zb/PX0oAQHgDscdSP73p1NAH+hr/AMGO/wDyTf8A4KL/APY6/syf+o38Zs0Af3f0AFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFAH+KL/wWj/5S0f8FGucf8Zk/H/r/wBj7qn/AOv9fqAfmOfbHXp+K+3uT+INADefUfxenb8PXk9c9aAF5yeR2z05yB7c5/Cg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BQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFAH/2Q==",
+"attach_logo": "logo-2013-color-small.png,data:image/png;base64,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",
+"attach_profile": "rushabh.jpeg,data:image/jpeg;base64,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",
+"company_abbr": "WN",
+"company_name": "Web Notes",
+"company_tagline": "Open Source ERP",
+"country": "India",
+"currency": "INR",
+"customer_1": "RIGPL",
+"customer_2": "Mahesh Engg",
+"customer_contact_1": "Aditya Duggal",
+"customer_contact_2": "Mahesh Malani",
+"first_name": "Rushabh",
+"fy_start": "1st Apr",
+"item_1": "Enterprise Plan",
+"item_2": "Small Business",
+"item_3": "Solo",
+"item_4": "Manual",
+"item_buy_1": "Server Hosting",
+"item_buy_2": "Adwords",
+"item_buy_group_1": "Services",
+"item_buy_group_2": "Services",
+"item_buy_group_3": "Raw Material",
+"item_buy_group_4": "Raw Material",
+"item_buy_group_5": "Raw Material",
+"item_buy_uom_1": "Unit",
+"item_buy_uom_2": "Unit",
+"item_buy_uom_3": "Unit",
+"item_buy_uom_4": "Unit",
+"item_buy_uom_5": "Unit",
+"item_group_1": "Services",
+"item_group_2": "Services",
+"item_group_3": "Services",
+"item_group_4": "Products",
+"item_group_5": "Products",
+"item_img_1": "logo-2013-color-small.png,data:image/png;base64,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",
+"item_uom_1": "Unit",
+"item_uom_2": "Unit",
+"item_uom_3": "Unit",
+"item_uom_4": "Unit",
+"item_uom_5": "Unit",
+"last_name": "Mehta",
+"supplier_1": "Google",
+"supplier_2": "Hetzner",
+"supplier_3": "Digital Ocean",
+"tax_1": "Service Tax",
+"tax_rate_1": "12.5",
+"timezone": "Asia/Calcutta",
+"password": "password",
+"email": "test@erpnext.com",
+}
\ No newline at end of file
diff --git a/setup/page/setup_wizard/test_setup_wizard.py b/setup/page/setup_wizard/test_setup_wizard.py
new file mode 100644
index 0000000..7f09a9b
--- /dev/null
+++ b/setup/page/setup_wizard/test_setup_wizard.py
@@ -0,0 +1,14 @@
+# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+import webnotes
+
+from setup.page.setup_wizard.test_setup_data import args
+from setup.page.setup_wizard.setup_wizard import setup_account
+
+if __name__=="__main__":
+ webnotes.connect()
+ webnotes.local.form_dict = webnotes._dict(args)
+ setup_account()
+
\ No newline at end of file
diff --git a/startup/__init__.py b/startup/__init__.py
index 227846c..802daac 100644
--- a/startup/__init__.py
+++ b/startup/__init__.py
@@ -27,8 +27,6 @@
"Territory": "territory"
}
-application_home_page = "desktop"
-
# add startup propertes
mail_footer = """<div style="padding: 7px; text-align: right; color: #888"><small>Sent via
<a style="color: #888" href="https://erpnext.com">ERPNext</a></div>"""
diff --git a/startup/boot.py b/startup/boot.py
index 886b805..d27c0b7 100644
--- a/startup/boot.py
+++ b/startup/boot.py
@@ -32,9 +32,9 @@
# load subscription info
- import conf
+ from webnotes import conf
for key in ['max_users', 'expires_on', 'max_space', 'status', 'commercial_support']:
- if hasattr(conf, key): bootinfo[key] = getattr(conf, key)
+ if key in conf: bootinfo[key] = conf.get(key)
bootinfo['docs'] += webnotes.conn.sql("""select name, default_currency, cost_center
from `tabCompany`""", as_dict=1, update={"doctype":":Company"})
@@ -53,4 +53,4 @@
ret = webnotes.conn.sql("""select name, content from `tabLetter Head`
where ifnull(disabled,0)=0""")
return dict(ret)
-
\ No newline at end of file
+
diff --git a/startup/event_handlers.py b/startup/event_handlers.py
index 57345f3..a012611 100644
--- a/startup/event_handlers.py
+++ b/startup/event_handlers.py
@@ -35,13 +35,13 @@
set_cart_count()
def on_logout(login_manager):
- webnotes.add_cookies["cart_count"] = ""
+ webnotes._response.set_cookie("cart_count", "")
def check_if_expired():
"""check if account is expired. If expired, do not allow login"""
- import conf
+ from webnotes import conf
# check if expires_on is specified
- if not hasattr(conf, 'expires_on'): return
+ if not 'expires_on' in conf: return
# check if expired
from datetime import datetime, date
@@ -65,9 +65,6 @@
raise webnotes.AuthenticationError
def on_build():
- from website.doctype.website_settings.make_web_include_files import make
- make()
-
from home.page.latest_updates import latest_updates
latest_updates.make()
@@ -75,4 +72,4 @@
"""add comment to feed"""
home.make_feed('Comment', doc.comment_doctype, doc.comment_docname, doc.comment_by,
'<i>"' + doc.comment + '"</i>', '#6B24B3')
-
\ No newline at end of file
+
diff --git a/startup/install.py b/startup/install.py
index d795594..fd72213 100644
--- a/startup/install.py
+++ b/startup/install.py
@@ -13,13 +13,13 @@
import_country_and_currency()
# home page
- webnotes.conn.set_value('Control Panel', None, 'home_page', 'desktop')
+ webnotes.conn.set_value('Control Panel', None, 'home_page', 'setup-wizard')
# features
feature_setup()
# all roles to Administrator
- from setup.doctype.setup_control.setup_control import add_all_roles_to
+ from setup.page.setup_wizard.setup_wizard import add_all_roles_to
add_all_roles_to("Administrator")
webnotes.conn.commit()
@@ -71,6 +71,7 @@
{'doctype': 'Item Group', 'item_group_name': 'Raw Material', 'is_group': 'No', 'parent_item_group': 'All Item Groups'},
{'doctype': 'Item Group', 'item_group_name': 'Services', 'is_group': 'No', 'parent_item_group': 'All Item Groups'},
{'doctype': 'Item Group', 'item_group_name': 'Sub Assemblies', 'is_group': 'No', 'parent_item_group': 'All Item Groups'},
+ {'doctype': 'Item Group', 'item_group_name': 'Consumable', 'is_group': 'No', 'parent_item_group': 'All Item Groups'},
# deduction type
{'doctype': 'Deduction Type', 'name': 'Income Tax', 'description': 'Income Tax', 'deduction_name': 'Income Tax'},
diff --git a/stock/doctype/bin/bin.py b/stock/doctype/bin/bin.py
index c419cad..014c47a 100644
--- a/stock/doctype/bin/bin.py
+++ b/stock/doctype/bin/bin.py
@@ -5,7 +5,6 @@
import webnotes
from webnotes.utils import add_days, cint,flt, nowdate, get_url_to_form, formatdate
from webnotes import msgprint, _
-sql = webnotes.conn.sql
import webnotes.defaults
@@ -61,7 +60,7 @@
self.doc.save()
def get_first_sle(self):
- sle = sql("""
+ sle = webnotes.conn.sql("""
select * from `tabStock Ledger Entry`
where item_code = %s
and warehouse = %s
diff --git a/stock/doctype/delivery_note/delivery_note.js b/stock/doctype/delivery_note/delivery_note.js
index 84e65da..29b3e47 100644
--- a/stock/doctype/delivery_note/delivery_note.js
+++ b/stock/doctype/delivery_note/delivery_note.js
@@ -22,7 +22,7 @@
var from_sales_invoice = false;
from_sales_invoice = cur_frm.get_doclist({parentfield: "delivery_note_details"})
.some(function(item) {
- return item.prevdoc_doctype==="Sales Invoice" ? true : false;
+ return item.against_sales_invoice ? true : false;
});
if(!from_sales_invoice)
@@ -181,12 +181,12 @@
if(cl.length){
prevdoc_list = new Array();
for(var i=0;i<cl.length;i++){
- if(cl[i].prevdoc_doctype == 'Sales Order' && cl[i].prevdoc_docname && prevdoc_list.indexOf(cl[i].prevdoc_docname) == -1) {
- prevdoc_list.push(cl[i].prevdoc_docname);
+ if(cl[i].against_sales_order && prevdoc_list.indexOf(cl[i].against_sales_order) == -1) {
+ prevdoc_list.push(cl[i].against_sales_order);
if(prevdoc_list.length ==1)
- out += make_row(cl[i].prevdoc_doctype, cl[i].prevdoc_docname, cl[i].prevdoc_date,0);
+ out += make_row("Sales Order", cl[i].against_sales_order, null, 0);
else
- out += make_row('', cl[i].prevdoc_docname, cl[i].prevdoc_date,0);
+ out += make_row('', cl[i].against_sales_order, null,0);
}
}
}
diff --git a/stock/doctype/delivery_note/delivery_note.py b/stock/doctype/delivery_note/delivery_note.py
index 2d1a3be..deaf024 100644
--- a/stock/doctype/delivery_note/delivery_note.py
+++ b/stock/doctype/delivery_note/delivery_note.py
@@ -28,7 +28,7 @@
'target_parent_field': 'per_delivered',
'target_ref_field': 'qty',
'source_field': 'qty',
- 'percent_join_field': 'prevdoc_docname',
+ 'percent_join_field': 'against_sales_order',
'status_field': 'delivery_status',
'keyword': 'Delivered'
}]
@@ -66,14 +66,11 @@
"""Re-calculates Basic Rate & amount based on Price List Selected"""
get_obj('Sales Common').get_adj_percent(self)
- def get_rate(self,arg):
- return get_obj('Sales Common').get_rate(arg)
-
def so_required(self):
"""check in manage account if sales order required or not"""
if webnotes.conn.get_value("Selling Settings", None, 'so_required') == 'Yes':
for d in getlist(self.doclist,'delivery_note_details'):
- if not d.prevdoc_docname:
+ if not d.against_sales_order:
msgprint("Sales Order No. required against item %s"%d.item_code)
raise Exception
@@ -89,7 +86,6 @@
sales_com_obj = get_obj(dt = 'Sales Common')
sales_com_obj.check_stop_sales_order(self)
sales_com_obj.check_active_sales_items(self)
- sales_com_obj.get_prevdoc_date(self)
self.validate_for_items()
self.validate_warehouse()
self.validate_uom_is_integer("stock_uom", "qty")
@@ -106,26 +102,27 @@
if not self.doc.installation_status: self.doc.installation_status = 'Not Installed'
def validate_with_previous_doc(self):
- prev_doctype = [d.prevdoc_doctype for d in self.doclist.get({
- "parentfield": "delivery_note_details"}) if cstr(d.prevdoc_doctype) != ""]
-
- if prev_doctype:
- super(DocType, self).validate_with_previous_doc(self.tname, {
- prev_doctype[0]: {
- "ref_dn_field": "prevdoc_docname",
- "compare_fields": [["customer", "="], ["company", "="], ["project_name", "="],
- ["currency", "="]],
- },
- })
- if cint(webnotes.defaults.get_global_default('maintain_same_sales_rate')):
+ items = self.doclist.get({"parentfield": "delivery_note_details"})
+
+ for fn in (("Sales Order", "against_sales_order"), ("Sales Invoice", "against_sales_invoice")):
+ if items.get_distinct_values(fn[1]):
super(DocType, self).validate_with_previous_doc(self.tname, {
- prev_doctype[0] + " Item": {
- "ref_dn_field": "prevdoc_detail_docname",
- "compare_fields": [["export_rate", "="]],
- "is_child_table": True
- }
+ fn[0]: {
+ "ref_dn_field": fn[1],
+ "compare_fields": [["customer", "="], ["company", "="], ["project_name", "="],
+ ["currency", "="]],
+ },
})
-
+
+ if cint(webnotes.defaults.get_global_default('maintain_same_sales_rate')):
+ super(DocType, self).validate_with_previous_doc(self.tname, {
+ fn[0] + " Item": {
+ "ref_dn_field": "prevdoc_detail_docname",
+ "compare_fields": [["export_rate", "="]],
+ "is_child_table": True
+ }
+ })
+
def validate_proj_cust(self):
"""check for does customer belong to same project as entered.."""
if self.doc.project_name and self.doc.customer:
@@ -137,8 +134,8 @@
def validate_for_items(self):
check_list, chk_dupl_itm = [], []
for d in getlist(self.doclist,'delivery_note_details'):
- e = [d.item_code, d.description, d.warehouse, d.prevdoc_docname or '', d.batch_no or '']
- f = [d.item_code, d.description, d.prevdoc_docname or '']
+ e = [d.item_code, d.description, d.warehouse, d.against_sales_order or d.against_sales_invoice, d.batch_no or '']
+ f = [d.item_code, d.description, d.against_sales_order or d.against_sales_invoice]
if webnotes.conn.get_value("Item", d.item_code, "is_stock_item") == 'Yes':
if e in check_list:
@@ -292,7 +289,7 @@
"""check credit limit of items in DN Detail which are not fetched from sales order"""
amount, total = 0, 0
for d in getlist(self.doclist, 'delivery_note_details'):
- if not d.prevdoc_docname:
+ if not (d.against_sales_order or d.against_sales_invoice):
amount += d.amount
if amount != 0:
total = (amount/self.doc.net_total)*self.doc.grand_total
@@ -344,7 +341,7 @@
"name": "dn_detail",
"parent": "delivery_note",
"prevdoc_detail_docname": "so_detail",
- "prevdoc_docname": "sales_order",
+ "against_sales_order": "sales_order",
"serial_no": "serial_no"
},
"postprocess": update_item
@@ -368,7 +365,6 @@
def make_installation_note(source_name, target_doclist=None):
def update_item(obj, target, source_parent):
target.qty = flt(obj.qty) - flt(obj.installed_qty)
- target.prevdoc_date = source_parent.posting_date
target.serial_no = obj.serial_no
doclist = get_mapped_doclist("Delivery Note", source_name, {
diff --git a/stock/doctype/delivery_note_item/delivery_note_item.txt b/stock/doctype/delivery_note_item/delivery_note_item.txt
index b74c33a..8d1792d 100644
--- a/stock/doctype/delivery_note_item/delivery_note_item.txt
+++ b/stock/doctype/delivery_note_item/delivery_note_item.txt
@@ -2,7 +2,7 @@
{
"creation": "2013-04-22 13:15:44",
"docstatus": 0,
- "modified": "2013-08-29 16:58:16",
+ "modified": "2013-10-10 17:03:11",
"modified_by": "Administrator",
"owner": "Administrator"
},
@@ -350,48 +350,17 @@
},
{
"doctype": "DocField",
- "fieldname": "prevdoc_doctype",
- "fieldtype": "Data",
- "hidden": 1,
- "in_filter": 1,
- "label": "Document Type",
- "no_copy": 1,
- "oldfieldname": "prevdoc_doctype",
- "oldfieldtype": "Data",
- "print_hide": 1,
- "print_width": "150px",
- "read_only": 1,
- "search_index": 1,
- "width": "150px"
+ "fieldname": "against_sales_order",
+ "fieldtype": "Link",
+ "label": "Against Sales Order",
+ "options": "Sales Order"
},
{
"doctype": "DocField",
- "fieldname": "prevdoc_docname",
- "fieldtype": "Data",
- "hidden": 0,
- "in_filter": 1,
- "label": "Against Document No",
- "no_copy": 1,
- "oldfieldname": "prevdoc_docname",
- "oldfieldtype": "Data",
- "print_hide": 1,
- "print_width": "150px",
- "read_only": 1,
- "search_index": 1,
- "width": "150px"
- },
- {
- "doctype": "DocField",
- "fieldname": "prevdoc_date",
- "fieldtype": "Date",
- "hidden": 1,
- "in_filter": 1,
- "label": "Against Document Date",
- "no_copy": 1,
- "oldfieldname": "prevdoc_date",
- "oldfieldtype": "Date",
- "print_hide": 1,
- "read_only": 1
+ "fieldname": "against_sales_invoice",
+ "fieldtype": "Link",
+ "label": "Against Sales Invoice",
+ "options": "Sales Invoice"
},
{
"doctype": "DocField",
@@ -421,6 +390,17 @@
"read_only": 1
},
{
+ "doctype": "DocField",
+ "fieldname": "buying_amount",
+ "fieldtype": "Currency",
+ "hidden": 1,
+ "label": "Buying Amount",
+ "no_copy": 1,
+ "options": "Company:company:default_currency",
+ "print_hide": 1,
+ "read_only": 1
+ },
+ {
"allow_on_submit": 1,
"doctype": "DocField",
"fieldname": "page_break",
diff --git a/stock/doctype/item/item.js b/stock/doctype/item/item.js
index a83032e..d0b8492 100644
--- a/stock/doctype/item/item.js
+++ b/stock/doctype/item/item.js
@@ -11,14 +11,16 @@
&& doc.__islocal)
cur_frm.toggle_display("item_code", sys_defaults.item_naming_by!="Naming Series"
&& doc.__islocal)
+
+ if(!doc.__islocal && doc.show_in_website) {
+ cur_frm.add_custom_button("View In Website", function() {
+ window.open(doc.page_name);
+ }, "icon-globe");
+ }
-
- if ((!doc.__islocal) && (doc.is_stock_item == 'Yes')) {
- var callback = function(r, rt) {
- var enabled = (r.message == 'exists') ? false : true;
- cur_frm.toggle_enable(['has_serial_no', 'is_stock_item', 'valuation_method'], enabled);
- }
- return $c_obj(make_doclist(doc.doctype, doc.name),'check_if_sle_exists','',callback);
+ if (!doc.__islocal && doc.is_stock_item == 'Yes') {
+ cur_frm.toggle_enable(['has_serial_no', 'is_stock_item', 'valuation_method'],
+ doc.__sle_exists=="exists" ? false : true);
}
}
diff --git a/stock/doctype/item/item.py b/stock/doctype/item/item.py
index aedb71c..595895f 100644
--- a/stock/doctype/item/item.py
+++ b/stock/doctype/item/item.py
@@ -14,6 +14,9 @@
class WarehouseNotSet(Exception): pass
class DocType(DocListController):
+ def onload(self):
+ self.doc.fields["__sle_exists"] = self.check_if_sle_exists()
+
def autoname(self):
if webnotes.conn.get_default("item_naming_by")=="Naming Series":
from webnotes.model.doc import make_autoname
diff --git a/stock/doctype/item/test_item.py b/stock/doctype/item/test_item.py
index 12bb4e0..ad88c8c 100644
--- a/stock/doctype/item/test_item.py
+++ b/stock/doctype/item/test_item.py
@@ -31,7 +31,7 @@
"is_sales_item": "Yes",
"is_service_item": "No",
"inspection_required": "No",
- "is_pro_applicable": "No",
+ "is_pro_applicable": "Yes",
"is_sub_contracted_item": "No",
"stock_uom": "_Test UOM",
"default_income_account": "Sales - _TC",
@@ -47,6 +47,26 @@
],
[{
"doctype": "Item",
+ "item_code": "_Test Item 2",
+ "item_name": "_Test Item 2",
+ "description": "_Test Item 2",
+ "item_group": "_Test Item Group",
+ "is_stock_item": "Yes",
+ "is_asset_item": "No",
+ "has_batch_no": "No",
+ "has_serial_no": "No",
+ "is_purchase_item": "Yes",
+ "is_sales_item": "Yes",
+ "is_service_item": "No",
+ "inspection_required": "No",
+ "is_pro_applicable": "Yes",
+ "is_sub_contracted_item": "No",
+ "stock_uom": "_Test UOM",
+ "default_income_account": "Sales - _TC",
+ "default_warehouse": "_Test Warehouse - _TC",
+ }],
+ [{
+ "doctype": "Item",
"item_code": "_Test Item Home Desktop 100",
"item_name": "_Test Item Home Desktop 100",
"description": "_Test Item Home Desktop 100",
@@ -61,8 +81,9 @@
"is_sales_item": "Yes",
"is_service_item": "No",
"inspection_required": "No",
- "is_pro_applicable": "No",
+ "is_pro_applicable": "Yes",
"is_sub_contracted_item": "No",
+ "is_manufactured_item": "Yes",
"stock_uom": "_Test UOM"
},
{
@@ -182,7 +203,7 @@
"is_sales_item": "Yes",
"is_service_item": "No",
"inspection_required": "No",
- "is_pro_applicable": "No",
+ "is_pro_applicable": "Yes",
"is_sub_contracted_item": "No",
"stock_uom": "_Test UOM"
}],
diff --git a/stock/doctype/material_request/material_request.js b/stock/doctype/material_request/material_request.js
index 6931181..99e8afb 100644
--- a/stock/doctype/material_request/material_request.js
+++ b/stock/doctype/material_request/material_request.js
@@ -21,7 +21,11 @@
+ wn._("Fulfilled"), cint(doc.per_ordered));
}
- if(doc.docstatus == 1 && doc.status != 'Stopped'){
+ if(doc.docstatus==0) {
+ cur_frm.add_custom_button(wn._("Get Items from BOM"), cur_frm.cscript.get_items_from_bom, "icon-sitemap");
+ }
+
+ if(doc.docstatus == 1 && doc.status != 'Stopped') {
if(doc.material_request_type === "Purchase")
cur_frm.add_custom_button("Make Supplier Quotation",
this.make_supplier_quotation);
@@ -63,6 +67,53 @@
},
+ schedule_date: function(doc, cdt, cdn) {
+ var val = locals[cdt][cdn].schedule_date;
+ if(val) {
+ $.each(wn.model.get("Material Request Item", { parent: cur_frm.doc.name }), function(i, d) {
+ if(!d.schedule_date) {
+ d.schedule_date = val;
+ }
+ });
+ refresh_field("indent_details");
+ }
+ },
+
+ get_items_from_bom: function() {
+ var d = new wn.ui.Dialog({
+ title: wn._("Get Items from BOM"),
+ fields: [
+ {"fieldname":"bom", "fieldtype":"Link", "label":wn._("BOM"),
+ options:"BOM"},
+ {"fieldname":"fetch_exploded", "fieldtype":"Check",
+ "label":wn._("Fetch exploded BOM (including sub-assemblies)"), "default":1},
+ {fieldname:"fetch", "label":wn._("Get Items from BOM"), "fieldtype":"Button"}
+ ]
+ });
+ d.get_input("fetch").on("click", function() {
+ var values = d.get_values();
+ if(!values) return;
+
+ wn.call({
+ method:"manufacturing.doctype.bom.bom.get_bom_items",
+ args: values,
+ callback: function(r) {
+ $.each(r.message, function(i, item) {
+ var d = wn.model.add_child(cur_frm.doc, "Material Request Item", "indent_details");
+ d.item_code = item.item_code;
+ d.description = item.description;
+ d.warehouse = item.default_warehouse;
+ d.uom = item.stock_uom;
+ d.qty = item.qty;
+ });
+ d.hide();
+ refresh_field("indent_details");
+ }
+ });
+ });
+ d.show();
+ },
+
tc_name: function() {
this.get_terms();
},
diff --git a/stock/doctype/material_request/material_request.py b/stock/doctype/material_request/material_request.py
index d1672ba..7aea336 100644
--- a/stock/doctype/material_request/material_request.py
+++ b/stock/doctype/material_request/material_request.py
@@ -20,10 +20,6 @@
self.tname = 'Material Request Item'
self.fname = 'indent_details'
- # get available qty at warehouse
- def get_bin_details(self, arg = ''):
- return get_obj(dt='Purchase Common').get_bin_details(arg)
-
def check_if_already_pulled(self):
pass#if self.[d.sales_order_no for d in getlist(self.doclist, 'indent_details')]
diff --git a/stock/doctype/material_request/material_request.txt b/stock/doctype/material_request/material_request.txt
index a5f092d..5fd576a 100644
--- a/stock/doctype/material_request/material_request.txt
+++ b/stock/doctype/material_request/material_request.txt
@@ -2,12 +2,13 @@
{
"creation": "2013-03-07 14:48:38",
"docstatus": 0,
- "modified": "2013-08-08 14:22:27",
+ "modified": "2013-10-02 14:24:42",
"modified_by": "Administrator",
"owner": "Administrator"
},
{
"allow_attach": 1,
+ "allow_import": 1,
"allow_print": 0,
"autoname": "naming_series:",
"doctype": "DocType",
diff --git a/stock/doctype/material_request_item/material_request_item.txt b/stock/doctype/material_request_item/material_request_item.txt
index dae97e0..2ef4acd 100644
--- a/stock/doctype/material_request_item/material_request_item.txt
+++ b/stock/doctype/material_request_item/material_request_item.txt
@@ -2,7 +2,7 @@
{
"creation": "2013-02-22 01:28:02",
"docstatus": 0,
- "modified": "2013-08-07 14:45:11",
+ "modified": "2013-10-11 14:21:32",
"modified_by": "Administrator",
"owner": "Administrator"
},
@@ -138,7 +138,7 @@
"oldfieldname": "item_name",
"oldfieldtype": "Data",
"print_width": "100px",
- "reqd": 1,
+ "reqd": 0,
"search_index": 1,
"width": "100px"
},
diff --git a/stock/doctype/purchase_receipt/purchase_receipt.py b/stock/doctype/purchase_receipt/purchase_receipt.py
index 6d4320f..1379406 100644
--- a/stock/doctype/purchase_receipt/purchase_receipt.py
+++ b/stock/doctype/purchase_receipt/purchase_receipt.py
@@ -38,10 +38,6 @@
total_qty = sum((item.qty for item in self.doclist.get({"parentfield": "purchase_receipt_details"})))
self.doc.fields["__billing_complete"] = billed_qty[0][0] == total_qty
- # get available qty at warehouse
- def get_bin_details(self, arg = ''):
- return get_obj(dt='Purchase Common').get_bin_details(arg)
-
def validate(self):
super(DocType, self).validate()
@@ -63,7 +59,6 @@
pc_obj = get_obj(dt='Purchase Common')
pc_obj.validate_for_items(self)
- pc_obj.get_prevdoc_date(self)
self.check_for_stopped_status(pc_obj)
# sub-contracting
@@ -290,10 +285,6 @@
bin = webnotes.conn.sql("select actual_qty from `tabBin` where item_code = %s and warehouse = %s", (d.rm_item_code, self.doc.supplier_warehouse), as_dict = 1)
d.current_stock = bin and flt(bin[0]['actual_qty']) or 0
-
- def get_rate(self,arg):
- return get_obj('Purchase Common').get_rate(arg,self)
-
def get_gl_entries_for_stock(self, warehouse_account=None):
against_stock_account = self.get_company_default("stock_received_but_not_billed")
diff --git a/stock/doctype/purchase_receipt/test_purchase_receipt.py b/stock/doctype/purchase_receipt/test_purchase_receipt.py
index 010c29b..613dfbc 100644
--- a/stock/doctype/purchase_receipt/test_purchase_receipt.py
+++ b/stock/doctype/purchase_receipt/test_purchase_receipt.py
@@ -104,6 +104,7 @@
pr.doclist[1].received_qty = 1
pr.insert()
pr.submit()
+
self.assertEquals(webnotes.conn.get_value("Serial No", pr.doclist[1].serial_no,
"supplier"), pr.doc.supplier)
@@ -112,7 +113,7 @@
def test_serial_no_cancel(self):
pr = self.test_serial_no_supplier()
pr.cancel()
-
+
self.assertFalse(webnotes.conn.get_value("Serial No", pr.doclist[1].serial_no,
"warehouse"))
diff --git a/stock/doctype/purchase_receipt_item/purchase_receipt_item.txt b/stock/doctype/purchase_receipt_item/purchase_receipt_item.txt
index ce49168..9c0d0fb 100755
--- a/stock/doctype/purchase_receipt_item/purchase_receipt_item.txt
+++ b/stock/doctype/purchase_receipt_item/purchase_receipt_item.txt
@@ -2,7 +2,7 @@
{
"creation": "2013-05-24 19:29:10",
"docstatus": 0,
- "modified": "2013-09-20 11:36:55",
+ "modified": "2013-10-10 17:02:51",
"modified_by": "Administrator",
"owner": "Administrator"
},
@@ -426,19 +426,6 @@
},
{
"doctype": "DocField",
- "fieldname": "prevdoc_date",
- "fieldtype": "Date",
- "hidden": 1,
- "in_filter": 1,
- "label": "Purchase Order Date",
- "no_copy": 1,
- "oldfieldname": "prevdoc_date",
- "oldfieldtype": "Date",
- "print_hide": 1,
- "read_only": 1
- },
- {
- "doctype": "DocField",
"fieldname": "rm_supp_cost",
"fieldtype": "Currency",
"hidden": 1,
diff --git a/stock/doctype/serial_no/serial_no.py b/stock/doctype/serial_no/serial_no.py
index f665abc..22a16b5 100644
--- a/stock/doctype/serial_no/serial_no.py
+++ b/stock/doctype/serial_no/serial_no.py
@@ -22,9 +22,9 @@
class SerialNoDuplicateError(ValidationError): pass
class DocType(StockController):
- def __init__(self, doc, doclist=[]):
+ def __init__(self, doc, doclist=None):
self.doc = doc
- self.doclist = doclist
+ self.doclist = doclist or []
self.via_stock_ledger = False
def validate(self):
@@ -36,7 +36,6 @@
self.validate_amc_status()
self.validate_warehouse()
self.validate_item()
-
self.on_stock_ledger_entry()
def validate_amc_status(self):
@@ -185,6 +184,12 @@
self.set_purchase_details()
self.set_sales_details()
+ def on_stock_ledger_entry(self):
+ if self.via_stock_ledger and not self.doc.fields.get("__islocal"):
+ self.set_status()
+ self.set_purchase_details()
+ self.set_sales_details()
+
def process_serial_no(sle):
item_det = get_item_details(sle.item_code)
validate_serial_no(sle, item_det)
@@ -241,7 +246,6 @@
serial_nos = []
for i in xrange(cint(sle.actual_qty)):
serial_nos.append(make_autoname(item_det.serial_no_series))
-
webnotes.conn.set(sle, "serial_no", "\n".join(serial_nos))
if sle.serial_no:
@@ -291,4 +295,4 @@
if d.serial_no != serial_no:
d.serial_no = serial_no
- webnotes.conn.set_value(d.doctype, d.name, "serial_no", serial_no)
\ No newline at end of file
+ webnotes.conn.set_value(d.doctype, d.name, "serial_no", serial_no)
diff --git a/stock/doctype/stock_entry/stock_entry.py b/stock/doctype/stock_entry/stock_entry.py
index c620bd9..217a0aa 100644
--- a/stock/doctype/stock_entry/stock_entry.py
+++ b/stock/doctype/stock_entry/stock_entry.py
@@ -15,7 +15,6 @@
from controllers.queries import get_match_cond
import json
-sql = webnotes.conn.sql
class NotUpdateStockError(webnotes.ValidationError): pass
class StockOverReturnError(webnotes.ValidationError): pass
@@ -56,7 +55,6 @@
from stock.doctype.serial_no.serial_no import update_serial_nos_after_submit
update_serial_nos_after_submit(self, "mtn_details")
-
self.update_production_order()
self.make_gl_entries()
@@ -369,7 +367,7 @@
def get_item_details(self, arg):
arg = json.loads(arg)
- item = sql("""select stock_uom, description, item_name from `tabItem`
+ item = webnotes.conn.sql("""select stock_uom, description, item_name from `tabItem`
where name = %s and (ifnull(end_of_life,'')='' or end_of_life ='0000-00-00'
or end_of_life > now())""", (arg.get('item_code')), as_dict = 1)
if not item:
@@ -393,7 +391,7 @@
def get_uom_details(self, arg = ''):
arg, ret = eval(arg), {}
- uom = sql("""select conversion_factor from `tabUOM Conversion Detail`
+ uom = webnotes.conn.sql("""select conversion_factor from `tabUOM Conversion Detail`
where parent = %s and uom = %s""", (arg['item_code'], arg['uom']), as_dict = 1)
if not uom or not flt(uom[0].conversion_factor):
msgprint("There is no Conversion Factor for UOM '%s' in Item '%s'" % (arg['uom'],
@@ -483,68 +481,16 @@
def get_bom_raw_materials(self, qty):
- """
- get all items from flat bom except
- child items of sub-contracted and sub assembly items
- and sub assembly items itself.
- """
+ from manufacturing.doctype.bom.bom import get_bom_items_as_dict
+
# item dict = { item_code: {qty, description, stock_uom} }
- item_dict = {}
+ item_dict = get_bom_items_as_dict(self.doc.bom_no, qty=qty, fetch_exploded = self.doc.use_multi_level_bom)
- def _make_items_dict(items_list):
- """makes dict of unique items with it's qty"""
- for item in items_list:
- if item_dict.has_key(item.item_code):
- item_dict[item.item_code]["qty"] += flt(item.qty)
- else:
- item_dict[item.item_code] = {
- "qty": flt(item.qty),
- "description": item.description,
- "stock_uom": item.stock_uom,
- "from_warehouse": item.default_warehouse
- }
-
- if self.doc.use_multi_level_bom:
- # get all raw materials with sub assembly childs
- fl_bom_sa_child_item = sql("""select
- fb.item_code,
- ifnull(sum(fb.qty_consumed_per_unit),0)*%s as qty,
- fb.description,
- fb.stock_uom,
- it.default_warehouse
- from
- `tabBOM Explosion Item` fb,`tabItem` it
- where
- it.name = fb.item_code
- and ifnull(it.is_pro_applicable, 'No') = 'No'
- and ifnull(it.is_sub_contracted_item, 'No') = 'No'
- and fb.docstatus < 2
- and fb.parent=%s group by item_code, stock_uom""",
- (qty, self.doc.bom_no), as_dict=1)
-
- if fl_bom_sa_child_item:
- _make_items_dict(fl_bom_sa_child_item)
- else:
- # get only BOM items
- fl_bom_sa_items = sql("""select
- `tabItem`.item_code,
- ifnull(sum(`tabBOM Item`.qty_consumed_per_unit), 0) *%s as qty,
- `tabItem`.description,
- `tabItem`.stock_uom,
- `tabItem`.default_warehouse
- from
- `tabBOM Item`, `tabItem`
- where
- `tabBOM Item`.parent = %s and
- `tabBOM Item`.item_code = tabItem.name and
- `tabBOM Item`.docstatus < 2
- group by item_code""", (qty, self.doc.bom_no), as_dict=1)
-
- if fl_bom_sa_items:
- _make_items_dict(fl_bom_sa_items)
+ for item in item_dict.values():
+ item.from_warehouse = item.default_warehouse
return item_dict
-
+
def get_pending_raw_materials(self, pro_obj):
"""
issue (item quantity) that is pending to issue or desire to transfer,
@@ -584,7 +530,7 @@
def get_issued_qty(self):
issued_item_qty = {}
- result = sql("""select t1.item_code, sum(t1.qty)
+ result = webnotes.conn.sql("""select t1.item_code, sum(t1.qty)
from `tabStock Entry Detail` t1, `tabStock Entry` t2
where t1.parent = t2.name and t2.production_order = %s and t2.docstatus = 1
and t2.purpose = 'Material Transfer'
@@ -630,7 +576,7 @@
def get_cust_addr(self):
from utilities.transaction_base import get_default_address, get_address_display
- res = sql("select customer_name from `tabCustomer` where name = '%s'"%self.doc.customer)
+ res = webnotes.conn.sql("select customer_name from `tabCustomer` where name = '%s'"%self.doc.customer)
address_display = None
customer_address = get_default_address("customer", self.doc.customer)
if customer_address:
@@ -651,7 +597,7 @@
def get_supp_addr(self):
from utilities.transaction_base import get_default_address, get_address_display
- res = sql("""select supplier_name from `tabSupplier`
+ res = webnotes.conn.sql("""select supplier_name from `tabSupplier`
where name=%s""", self.doc.supplier)
address_display = None
supplier_address = get_default_address("customer", self.doc.customer)
@@ -890,8 +836,7 @@
ref.doclist[0].name)
if not invoices_against_delivery:
- sales_orders_against_delivery = [d.prevdoc_docname for d in
- ref.doclist.get({"prevdoc_doctype": "Sales Order"}) if d.prevdoc_docname]
+ sales_orders_against_delivery = [d.against_sales_order for d in ref.doclist if d.against_sales_order]
if sales_orders_against_delivery:
invoices_against_delivery = get_invoice_list("Sales Invoice Item", "sales_order",
diff --git a/stock/doctype/stock_entry/test_stock_entry.py b/stock/doctype/stock_entry/test_stock_entry.py
index 2882072..b37f32c 100644
--- a/stock/doctype/stock_entry/test_stock_entry.py
+++ b/stock/doctype/stock_entry/test_stock_entry.py
@@ -1,9 +1,6 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
# License: GNU General Public License v3. See license.txt
-# ERPNext - web based ERP (http://erpnext.com)
-# For license information, please see license.txt
-
from __future__ import unicode_literals
import webnotes, unittest
from webnotes.utils import flt
@@ -46,7 +43,6 @@
self._clear_stock_account_balance()
webnotes.bean("Profile", "test2@example.com").get_controller()\
.add_roles("Sales User", "Sales Manager", "Material User", "Material Manager")
-
webnotes.session.user = "test2@example.com"
from stock.utils import InvalidWarehouseCompany
@@ -60,14 +56,12 @@
def test_warehouse_user(self):
from stock.utils import UserNotAllowedForWarehouse
- webnotes.session.user = "test@example.com"
webnotes.bean("Profile", "test@example.com").get_controller()\
.add_roles("Sales User", "Sales Manager", "Material User", "Material Manager")
webnotes.bean("Profile", "test2@example.com").get_controller()\
.add_roles("Sales User", "Sales Manager", "Material User", "Material Manager")
webnotes.session.user = "test@example.com"
-
st1 = webnotes.bean(copy=test_records[0])
st1.doc.company = "_Test Company 1"
st1.doclist[1].t_warehouse="_Test Warehouse 2 - _TC1"
diff --git a/stock/doctype/stock_ledger/stock_ledger.py b/stock/doctype/stock_ledger/stock_ledger.py
new file mode 100644
index 0000000..1624b00
--- /dev/null
+++ b/stock/doctype/stock_ledger/stock_ledger.py
@@ -0,0 +1,57 @@
+# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+import webnotes
+
+from webnotes.utils import add_days, cstr, flt, nowdate, cint, now
+from webnotes.model.doc import Document
+from webnotes.model.bean import getlist
+from webnotes.model.code import get_obj
+from webnotes import session, msgprint
+from stock.utils import get_valid_serial_nos
+
+
+class DocType:
+ def __init__(self, doc, doclist=[]):
+ self.doc = doc
+ self.doclist = doclist
+
+ def update_stock(self, values, is_amended = 'No'):
+ for v in values:
+ sle_id = ''
+
+ # reverse quantities for cancel
+ if v.get('is_cancelled') == 'Yes':
+ v['actual_qty'] = -flt(v['actual_qty'])
+ # cancel matching entry
+ webnotes.conn.sql("""update `tabStock Ledger Entry` set is_cancelled='Yes',
+ modified=%s, modified_by=%s
+ where voucher_no=%s and voucher_type=%s""",
+ (now(), webnotes.session.user, v['voucher_no'], v['voucher_type']))
+
+ if v.get("actual_qty"):
+ sle_id = self.make_entry(v)
+
+ args = v.copy()
+ args.update({
+ "sle_id": sle_id,
+ "is_amended": is_amended
+ })
+
+ get_obj('Warehouse', v["warehouse"]).update_bin(args)
+
+
+ def make_entry(self, args):
+ args.update({"doctype": "Stock Ledger Entry"})
+ sle = webnotes.bean([args])
+ sle.ignore_permissions = 1
+ sle.insert()
+ return sle.doc.name
+
+ def repost(self):
+ """
+ Repost everything!
+ """
+ for wh in webnotes.conn.sql("select name from tabWarehouse"):
+ get_obj('Warehouse', wh[0]).repost_stock()
diff --git a/stock/doctype/stock_ledger_entry/stock_ledger_entry.py b/stock/doctype/stock_ledger_entry/stock_ledger_entry.py
index 1738efc..d2f8704 100644
--- a/stock/doctype/stock_ledger_entry/stock_ledger_entry.py
+++ b/stock/doctype/stock_ledger_entry/stock_ledger_entry.py
@@ -14,7 +14,6 @@
def validate(self):
from stock.utils import validate_warehouse_user, validate_warehouse_company
-
self.validate_mandatory()
self.validate_item()
validate_warehouse_user(self.doc.warehouse)
diff --git a/stock/doctype/stock_uom_replace_utility/stock_uom_replace_utility.py b/stock/doctype/stock_uom_replace_utility/stock_uom_replace_utility.py
index 321e3c9..1f1bafa 100644
--- a/stock/doctype/stock_uom_replace_utility/stock_uom_replace_utility.py
+++ b/stock/doctype/stock_uom_replace_utility/stock_uom_replace_utility.py
@@ -10,7 +10,6 @@
from webnotes.model.code import get_obj
from webnotes import msgprint, _
-sql = webnotes.conn.sql
class DocType:
def __init__(self, d, dl=[]):
@@ -34,7 +33,7 @@
msgprint("Please Enter Conversion Factor.")
raise Exception
- stock_uom = sql("select stock_uom from `tabItem` where name = '%s'" % self.doc.item_code)
+ stock_uom = webnotes.conn.sql("select stock_uom from `tabItem` where name = '%s'" % self.doc.item_code)
stock_uom = stock_uom and stock_uom[0][0]
if cstr(self.doc.new_stock_uom) == cstr(stock_uom):
msgprint("Item Master is already updated with New Stock UOM " + cstr(self.doc.new_stock_uom))
@@ -50,9 +49,9 @@
def update_bin(self):
# update bin
if flt(self.doc.conversion_factor) != flt(1):
- sql("update `tabBin` set stock_uom = '%s' , indented_qty = ifnull(indented_qty,0) * %s, ordered_qty = ifnull(ordered_qty,0) * %s, reserved_qty = ifnull(reserved_qty,0) * %s, planned_qty = ifnull(planned_qty,0) * %s, projected_qty = actual_qty + ordered_qty + indented_qty + planned_qty - reserved_qty where item_code = '%s'" % (self.doc.new_stock_uom, self.doc.conversion_factor, self.doc.conversion_factor, self.doc.conversion_factor, self.doc.conversion_factor, self.doc.item_code) )
+ webnotes.conn.sql("update `tabBin` set stock_uom = '%s' , indented_qty = ifnull(indented_qty,0) * %s, ordered_qty = ifnull(ordered_qty,0) * %s, reserved_qty = ifnull(reserved_qty,0) * %s, planned_qty = ifnull(planned_qty,0) * %s, projected_qty = actual_qty + ordered_qty + indented_qty + planned_qty - reserved_qty where item_code = '%s'" % (self.doc.new_stock_uom, self.doc.conversion_factor, self.doc.conversion_factor, self.doc.conversion_factor, self.doc.conversion_factor, self.doc.item_code) )
else:
- sql("update `tabBin` set stock_uom = '%s' where item_code = '%s'" % (self.doc.new_stock_uom, self.doc.item_code) )
+ webnotes.conn.sql("update `tabBin` set stock_uom = '%s' where item_code = '%s'" % (self.doc.new_stock_uom, self.doc.item_code) )
# acknowledge user
msgprint(" All Bins Updated Successfully.")
@@ -62,16 +61,16 @@
from stock.stock_ledger import update_entries_after
if flt(self.doc.conversion_factor) != flt(1):
- sql("update `tabStock Ledger Entry` set stock_uom = '%s', actual_qty = ifnull(actual_qty,0) * '%s' where item_code = '%s' " % (self.doc.new_stock_uom, self.doc.conversion_factor, self.doc.item_code))
+ webnotes.conn.sql("update `tabStock Ledger Entry` set stock_uom = '%s', actual_qty = ifnull(actual_qty,0) * '%s' where item_code = '%s' " % (self.doc.new_stock_uom, self.doc.conversion_factor, self.doc.item_code))
else:
- sql("update `tabStock Ledger Entry` set stock_uom = '%s' where item_code = '%s' " % (self.doc.new_stock_uom, self.doc.item_code))
+ webnotes.conn.sql("update `tabStock Ledger Entry` set stock_uom = '%s' where item_code = '%s' " % (self.doc.new_stock_uom, self.doc.item_code))
# acknowledge user
msgprint("Stock Ledger Entries Updated Successfully.")
# update item valuation
if flt(self.doc.conversion_factor) != flt(1):
- wh = sql("select name from `tabWarehouse`")
+ wh = webnotes.conn.sql("select name from `tabWarehouse`")
for w in wh:
update_entries_after({"item_code": self.doc.item_code, "warehouse": w[0]})
diff --git a/stock/doctype/warehouse/warehouse.py b/stock/doctype/warehouse/warehouse.py
index 476a6f6..97a8826 100644
--- a/stock/doctype/warehouse/warehouse.py
+++ b/stock/doctype/warehouse/warehouse.py
@@ -7,7 +7,6 @@
from webnotes.utils import cint, flt, validate_email_add
from webnotes import msgprint, _
-sql = webnotes.conn.sql
class DocType:
def __init__(self, doc, doclist=[]):
@@ -31,7 +30,7 @@
if not webnotes.conn.get_value("Account", {"account_type": "Warehouse",
"master_name": self.doc.name}) and not webnotes.conn.get_value("Account",
{"account_name": self.doc.warehouse_name}):
- if self.doc.__islocal or not webnotes.conn.get_value("Stock Ledger Entry",
+ if self.doc.fields.get("__islocal") or not webnotes.conn.get_value("Stock Ledger Entry",
{"warehouse": self.doc.name}):
self.validate_parent_account()
ac_bean = webnotes.bean({
@@ -58,7 +57,16 @@
else:
webnotes.throw(_("Please enter account group under which account \
for warehouse ") + self.doc.name +_(" will be created"))
-
+
+ def on_rename(self, new, old, merge=False):
+ webnotes.conn.set_value("Account", {"account_type": "Warehouse", "master_name": old},
+ "master_name", new)
+
+ if merge:
+ from stock.stock_ledger import update_entries_after
+ for item_code in webnotes.conn.sql("""select item_code from `tabBin`
+ where warehouse=%s""", new):
+ update_entries_after({"item_code": item_code, "warehouse": new})
def merge_warehouses(self):
webnotes.conn.auto_commit_on_many_writes = 1
@@ -93,14 +101,14 @@
def on_trash(self):
# delete bin
- bins = sql("select * from `tabBin` where warehouse = %s", self.doc.name, as_dict=1)
+ bins = webnotes.conn.sql("select * from `tabBin` where warehouse = %s", self.doc.name, as_dict=1)
for d in bins:
if d['actual_qty'] or d['reserved_qty'] or d['ordered_qty'] or \
d['indented_qty'] or d['projected_qty'] or d['planned_qty']:
msgprint("""Warehouse: %s can not be deleted as qty exists for item: %s"""
% (self.doc.name, d['item_code']), raise_exception=1)
else:
- sql("delete from `tabBin` where name = %s", d['name'])
+ webnotes.conn.sql("delete from `tabBin` where name = %s", d['name'])
warehouse_account = webnotes.conn.get_value("Account",
{"account_type": "Warehosue", "master_name": self.doc.name})
@@ -108,18 +116,8 @@
webnotes.delete_doc("Account", warehouse_account)
# delete cancelled sle
- if sql("""select name from `tabStock Ledger Entry` where warehouse = %s""", self.doc.name):
+ if webnotes.conn.sql("""select name from `tabStock Ledger Entry` where warehouse = %s""", self.doc.name):
msgprint("""Warehosue can not be deleted as stock ledger entry
exists for this warehouse.""", raise_exception=1)
else:
- sql("delete from `tabStock Ledger Entry` where warehouse = %s", self.doc.name)
-
- def on_rename(self, newdn, olddn, merge=False):
- webnotes.conn.set_value("Account", {"account_type": "Warehouse", "master_name": olddn},
- "master_name", newdn)
-
- if merge:
- from stock.stock_ledger import update_entries_after
- for item_code in webnotes.conn.sql("""select item_code from `tabBin`
- where warehouse=%s""", newdn):
- update_entries_after({"item_code": item_code, "warehouse": newdn})
+ webnotes.conn.sql("delete from `tabStock Ledger Entry` where warehouse = %s", self.doc.name)
diff --git a/stock/stock_ledger.py b/stock/stock_ledger.py
index 197aa0d..1555dab 100644
--- a/stock/stock_ledger.py
+++ b/stock/stock_ledger.py
@@ -10,6 +10,9 @@
# future reposting
class NegativeStockError(webnotes.ValidationError): pass
+_exceptions = webnotes.local('stockledger_exceptions')
+# _exceptions = []
+
def make_sl_entries(sl_entries, is_amended=None):
if sl_entries:
from stock.utils import update_bin
@@ -55,7 +58,6 @@
webnotes.conn.sql("""delete from `tabStock Ledger Entry`
where voucher_type=%s and voucher_no=%s""", (voucher_type, voucher_no))
-_exceptions = []
def update_entries_after(args, verbose=1):
"""
update valution rate and qty after transaction
@@ -68,8 +70,8 @@
"posting_time": "12:00"
}
"""
- global _exceptions
- _exceptions = []
+ if not _exceptions:
+ webnotes.local.stockledger_exceptions = []
previous_sle = get_sle_before_datetime(args)
@@ -190,10 +192,12 @@
will not consider cancelled entries
"""
diff = qty_after_transaction + flt(sle.actual_qty)
+
+ if not _exceptions:
+ webnotes.local.stockledger_exceptions = []
if diff < 0 and abs(diff) > 0.0001:
# negative stock!
- global _exceptions
exc = sle.copy().update({"diff": diff})
_exceptions.append(exc)
return False
@@ -327,4 +331,4 @@
sle = get_stock_ledger_entries(args, ["name != %(sle)s",
"timestamp(posting_date, posting_time) <= timestamp(%(posting_date)s, %(posting_time)s)"],
"desc", "limit 1", for_update=for_update)
- return sle and sle[0] or {}
\ No newline at end of file
+ return sle and sle[0] or {}
diff --git a/stock/utils.py b/stock/utils.py
index 0f801c7..b3980e4 100644
--- a/stock/utils.py
+++ b/stock/utils.py
@@ -252,10 +252,10 @@
def reorder_item():
""" Reorder item if stock reaches reorder level"""
- if not hasattr(webnotes, "auto_indent"):
- webnotes.auto_indent = cint(webnotes.conn.get_value('Stock Settings', None, 'auto_indent'))
+ if getattr(webnotes.local, "auto_indent", None) is None:
+ webnotes.local.auto_indent = cint(webnotes.conn.get_value('Stock Settings', None, 'auto_indent'))
- if webnotes.auto_indent:
+ if webnotes.local.auto_indent:
material_requests = {}
bin_list = webnotes.conn.sql("""select item_code, warehouse, projected_qty
from tabBin where ifnull(item_code, '') != '' and ifnull(warehouse, '') != ''
@@ -340,18 +340,18 @@
mr_list.append(mr_bean)
except:
- if webnotes.message_log:
- exceptions_list.append([] + webnotes.message_log)
- webnotes.message_log = []
+ if webnotes.local.message_log:
+ exceptions_list.append([] + webnotes.local.message_log)
+ webnotes.local.message_log = []
else:
exceptions_list.append(webnotes.getTraceback())
if mr_list:
- if not hasattr(webnotes, "reorder_email_notify"):
- webnotes.reorder_email_notify = cint(webnotes.conn.get_value('Stock Settings', None,
+ if getattr(webnotes.local, "reorder_email_notify", None) is None:
+ webnotes.local.reorder_email_notify = cint(webnotes.conn.get_value('Stock Settings', None,
'reorder_email_notify'))
- if(webnotes.reorder_email_notify):
+ if(webnotes.local.reorder_email_notify):
send_email_notification(mr_list)
if exceptions_list:
@@ -393,4 +393,4 @@
Administrator""" % ("\n\n".join(["\n".join(msg) for msg in exceptions_list]),)
from webnotes.profile import get_system_managers
- sendmail(get_system_managers(), subject=subject, msg=msg)
\ No newline at end of file
+ sendmail(get_system_managers(), subject=subject, msg=msg)
diff --git a/support/doctype/customer_issue/customer_issue.py b/support/doctype/customer_issue/customer_issue.py
index 910e9b8..c099bf6 100644
--- a/support/doctype/customer_issue/customer_issue.py
+++ b/support/doctype/customer_issue/customer_issue.py
@@ -7,7 +7,6 @@
from webnotes import session, msgprint
from webnotes.utils import today
-sql = webnotes.conn.sql
from utilities.transaction_base import TransactionBase
@@ -28,7 +27,7 @@
self.doc.resolved_by = webnotes.session.user
def on_cancel(self):
- lst = sql("select t1.name from `tabMaintenance Visit` t1, `tabMaintenance Visit Purpose` t2 where t2.parent = t1.name and t2.prevdoc_docname = '%s' and t1.docstatus!=2"%(self.doc.name))
+ lst = webnotes.conn.sql("select t1.name from `tabMaintenance Visit` t1, `tabMaintenance Visit Purpose` t2 where t2.parent = t1.name and t2.prevdoc_docname = '%s' and t1.docstatus!=2"%(self.doc.name))
if lst:
lst1 = ','.join([x[0] for x in lst])
msgprint("Maintenance Visit No. "+lst1+" already created against this customer issue. So can not be Cancelled")
diff --git a/support/doctype/maintenance_schedule/maintenance_schedule.py b/support/doctype/maintenance_schedule/maintenance_schedule.py
index 59d3f8e..1682da5 100644
--- a/support/doctype/maintenance_schedule/maintenance_schedule.py
+++ b/support/doctype/maintenance_schedule/maintenance_schedule.py
@@ -9,7 +9,6 @@
from webnotes.model.bean import getlist
from webnotes import msgprint
-sql = webnotes.conn.sql
from utilities.transaction_base import TransactionBase, delete_events
@@ -20,7 +19,7 @@
self.doclist = doclist
def get_item_details(self, item_code):
- item = sql("select item_name, description from `tabItem` where name = '%s'" %(item_code), as_dict=1)
+ item = webnotes.conn.sql("select item_name, description from `tabItem` where name = '%s'" %(item_code), as_dict=1)
ret = {
'item_name': item and item[0]['item_name'] or '',
'description' : item and item[0]['description'] or ''
@@ -30,7 +29,7 @@
def generate_schedule(self):
self.doclist = self.doc.clear_table(self.doclist, 'maintenance_schedule_detail')
count = 0
- sql("delete from `tabMaintenance Schedule Detail` where parent='%s'" %(self.doc.name))
+ webnotes.conn.sql("delete from `tabMaintenance Schedule Detail` where parent='%s'" %(self.doc.name))
for d in getlist(self.doclist, 'item_maintenance_detail'):
self.validate_maintenance_detail()
s_list =[]
@@ -67,7 +66,7 @@
email_map[d.incharge_name] = webnotes.bean("Sales Person",
d.incharge_name).run_method("get_email_id")
- scheduled_date =sql("select scheduled_date from `tabMaintenance Schedule Detail` \
+ scheduled_date =webnotes.conn.sql("select scheduled_date from `tabMaintenance Schedule Detail` \
where incharge_name='%s' and item_code='%s' and parent='%s' " %(d.incharge_name, \
d.item_code, self.doc.name), as_dict=1)
@@ -172,7 +171,7 @@
def validate_sales_order(self):
for d in getlist(self.doclist, 'item_maintenance_detail'):
if d.prevdoc_docname:
- chk = sql("select t1.name from `tabMaintenance Schedule` t1, `tabMaintenance Schedule Item` t2 where t2.parent=t1.name and t2.prevdoc_docname=%s and t1.docstatus=1", d.prevdoc_docname)
+ chk = webnotes.conn.sql("select t1.name from `tabMaintenance Schedule` t1, `tabMaintenance Schedule Item` t2 where t2.parent=t1.name and t2.prevdoc_docname=%s and t1.docstatus=1", d.prevdoc_docname)
if chk:
msgprint("Maintenance Schedule against "+d.prevdoc_docname+" already exist")
raise Exception
@@ -186,7 +185,7 @@
cur_s_no = cur_serial_no.split(',')
for x in cur_s_no:
- chk = sql("select name, status from `tabSerial No` where docstatus!=2 and name=%s", (x))
+ chk = webnotes.conn.sql("select name, status from `tabSerial No` where docstatus!=2 and name=%s", (x))
chk1 = chk and chk[0][0] or ''
status = chk and chk[0][1] or ''
@@ -209,7 +208,7 @@
cur_s_no = cur_serial_no.split(',')
for x in cur_s_no:
- dt = sql("select delivery_date from `tabSerial No` where name = %s", x)
+ dt = webnotes.conn.sql("select delivery_date from `tabSerial No` where name = %s", x)
dt = dt and dt[0][0] or ''
if dt:
@@ -225,7 +224,7 @@
cur_s_no = cur_serial_no.split(',')
for x in cur_s_no:
- sql("update `tabSerial No` set amc_expiry_date = '%s', maintenance_status = 'Under AMC' where name = '%s'"% (amc_end_date,x))
+ webnotes.conn.sql("update `tabSerial No` set amc_expiry_date = '%s', maintenance_status = 'Under AMC' where name = '%s'"% (amc_end_date,x))
def on_update(self):
webnotes.conn.set(self.doc, 'status', 'Draft')
@@ -233,7 +232,7 @@
def validate_serial_no_warranty(self):
for d in getlist(self.doclist, 'item_maintenance_detail'):
if cstr(d.serial_no).strip():
- dt = sql("""select warranty_expiry_date, amc_expiry_date
+ dt = webnotes.conn.sql("""select warranty_expiry_date, amc_expiry_date
from `tabSerial No` where name = %s""", d.serial_no, as_dict=1)
if dt[0]['warranty_expiry_date'] and dt[0]['warranty_expiry_date'] >= d.start_date:
webnotes.msgprint("""Serial No: %s is already under warranty upto %s.
diff --git a/support/doctype/maintenance_visit/maintenance_visit.py b/support/doctype/maintenance_visit/maintenance_visit.py
index bf8767b..60cc371 100644
--- a/support/doctype/maintenance_visit/maintenance_visit.py
+++ b/support/doctype/maintenance_visit/maintenance_visit.py
@@ -8,7 +8,6 @@
from webnotes.model.bean import getlist
from webnotes import msgprint
-sql = webnotes.conn.sql
from utilities.transaction_base import TransactionBase
@@ -19,7 +18,7 @@
self.doclist = doclist
def get_item_details(self, item_code):
- item = sql("select item_name,description from `tabItem` where name = '%s'" %(item_code), as_dict=1)
+ item = webnotes.conn.sql("select item_name,description from `tabItem` where name = '%s'" %(item_code), as_dict=1)
ret = {
'item_name' : item and item[0]['item_name'] or '',
'description' : item and item[0]['description'] or ''
@@ -28,7 +27,7 @@
def validate_serial_no(self):
for d in getlist(self.doclist, 'maintenance_visit_details'):
- if d.serial_no and not sql("select name from `tabSerial No` where name = '%s' and docstatus != 2" % d.serial_no):
+ if d.serial_no and not webnotes.conn.sql("select name from `tabSerial No` where name = '%s' and docstatus != 2" % d.serial_no):
msgprint("Serial No: "+ d.serial_no + " not exists in the system")
raise Exception
@@ -52,7 +51,7 @@
elif self.doc.completion_status == 'Partially Completed':
status = 'Work In Progress'
else:
- nm = sql("select t1.name, t1.mntc_date, t2.service_person, t2.work_done from `tabMaintenance Visit` t1, `tabMaintenance Visit Purpose` t2 where t2.parent = t1.name and t1.completion_status = 'Partially Completed' and t2.prevdoc_docname = %s and t1.name!=%s and t1.docstatus = 1 order by t1.name desc limit 1", (d.prevdoc_docname, self.doc.name))
+ nm = webnotes.conn.sql("select t1.name, t1.mntc_date, t2.service_person, t2.work_done from `tabMaintenance Visit` t1, `tabMaintenance Visit Purpose` t2 where t2.parent = t1.name and t1.completion_status = 'Partially Completed' and t2.prevdoc_docname = %s and t1.name!=%s and t1.docstatus = 1 order by t1.name desc limit 1", (d.prevdoc_docname, self.doc.name))
if nm:
status = 'Work In Progress'
@@ -65,7 +64,7 @@
service_person = ''
work_done = ''
- sql("update `tabCustomer Issue` set resolution_date=%s, resolved_by=%s, resolution_details=%s, status=%s where name =%s",(mntc_date,service_person,work_done,status,d.prevdoc_docname))
+ webnotes.conn.sql("update `tabCustomer Issue` set resolution_date=%s, resolved_by=%s, resolution_details=%s, status=%s where name =%s",(mntc_date,service_person,work_done,status,d.prevdoc_docname))
def check_if_last_visit(self):
@@ -77,7 +76,7 @@
check_for_doctype = d.prevdoc_doctype
if check_for_docname:
- check = sql("select t1.name from `tabMaintenance Visit` t1, `tabMaintenance Visit Purpose` t2 where t2.parent = t1.name and t1.name!=%s and t2.prevdoc_docname=%s and t1.docstatus = 1 and (t1.mntc_date > %s or (t1.mntc_date = %s and t1.mntc_time > %s))", (self.doc.name, check_for_docname, self.doc.mntc_date, self.doc.mntc_date, self.doc.mntc_time))
+ check = webnotes.conn.sql("select t1.name from `tabMaintenance Visit` t1, `tabMaintenance Visit Purpose` t2 where t2.parent = t1.name and t1.name!=%s and t2.prevdoc_docname=%s and t1.docstatus = 1 and (t1.mntc_date > %s or (t1.mntc_date = %s and t1.mntc_time > %s))", (self.doc.name, check_for_docname, self.doc.mntc_date, self.doc.mntc_date, self.doc.mntc_time))
if check:
check_lst = [x[0] for x in check]
diff --git a/support/doctype/newsletter/newsletter.py b/support/doctype/newsletter/newsletter.py
index b201cc5..a6b5aa2 100644
--- a/support/doctype/newsletter/newsletter.py
+++ b/support/doctype/newsletter/newsletter.py
@@ -90,8 +90,8 @@
webnotes.msgprint(_("""Please save the Newsletter before sending."""),
raise_exception=1)
- import conf
- if getattr(conf, "status", None) == "Trial":
+ from webnotes import conf
+ if (conf.get("status") or None) == "Trial":
webnotes.msgprint(_("""Sending newsletters is not allowed for Trial users, \
to prevent abuse of this feature."""), raise_exception=1)
@@ -105,7 +105,6 @@
}
-lead_naming_series = None
def create_lead(email_id):
"""create a lead if it does not exist"""
from email.utils import parseaddr
@@ -119,7 +118,7 @@
"email_id": email_id,
"lead_name": real_name or email_id,
"status": "Contacted",
- "naming_series": lead_naming_series or get_lead_naming_series(),
+ "naming_series": get_lead_naming_series(),
"company": webnotes.conn.get_default("company"),
"source": "Email"
})
@@ -127,7 +126,7 @@
def get_lead_naming_series():
"""gets lead's default naming series"""
- global lead_naming_series
+ lead_naming_series = None
naming_series_field = webnotes.get_doctype("Lead").get_field("naming_series")
if naming_series_field.default:
lead_naming_series = naming_series_field.default
diff --git a/support/doctype/support_ticket/get_support_mails.py b/support/doctype/support_ticket/get_support_mails.py
index 4dcb59e..395052a 100644
--- a/support/doctype/support_ticket/get_support_mails.py
+++ b/support/doctype/support_ticket/get_support_mails.py
@@ -54,7 +54,7 @@
def auto_close_tickets(self):
webnotes.conn.sql("""update `tabSupport Ticket` set status = 'Closed'
- where status = 'Waiting for Customer'
+ where status = 'Replied'
and date_sub(curdate(),interval 15 Day) > modified""")
def get_support_mails():
@@ -81,7 +81,7 @@
make(content=content, sender=sender, subject = subject,
doctype="Support Ticket", name=ticket.doc.name,
- date=mail.date if mail else today())
+ date=mail.date if mail else today(), sent_or_received="Received")
if mail:
mail.save_attachments_in_doc(ticket.doc)
diff --git a/support/doctype/support_ticket/support_ticket.py b/support/doctype/support_ticket/support_ticket.py
index bf2a9fb..eb68ff3 100644
--- a/support/doctype/support_ticket/support_ticket.py
+++ b/support/doctype/support_ticket/support_ticket.py
@@ -14,7 +14,7 @@
def get_sender(self, comm):
return webnotes.conn.get_value('Email Settings',None,'support_email')
-
+
def get_subject(self, comm):
return '[' + self.doc.name + '] ' + (comm.subject or 'No Subject Specified')
@@ -35,16 +35,7 @@
if self.doc.status == "Closed":
from webnotes.widgets.form.assign_to import clear
clear(self.doc.doctype, self.doc.name)
-
- def on_communication(self, comm):
- if comm.sender == self.get_sender(comm) or \
- webnotes.conn.get_value("Profile", extract_email_id(comm.sender), "user_type")=="System User":
- self.doc.status = "Waiting for Customer"
- else:
- self.doc.status = "Open"
- self.update_status()
- self.doc.save()
-
+
def set_lead_contact(self, email_id):
import email.utils
email_id = email.utils.parseaddr(email_id)
diff --git a/support/doctype/support_ticket/support_ticket.txt b/support/doctype/support_ticket/support_ticket.txt
index 9f385b2..76d9dcf 100644
--- a/support/doctype/support_ticket/support_ticket.txt
+++ b/support/doctype/support_ticket/support_ticket.txt
@@ -2,7 +2,7 @@
{
"creation": "2013-02-01 10:36:25",
"docstatus": 0,
- "modified": "2013-09-10 10:54:02",
+ "modified": "2013-10-03 16:45:41",
"modified_by": "Administrator",
"owner": "Administrator"
},
@@ -71,7 +71,7 @@
"no_copy": 1,
"oldfieldname": "status",
"oldfieldtype": "Select",
- "options": "\nOpen\nTo Reply\nWaiting for Customer\nHold\nClosed",
+ "options": "Open\nReplied\nHold\nClosed",
"read_only": 0,
"reqd": 0,
"search_index": 1
diff --git a/utilities/demo/demo_control_panel.py b/utilities/demo/demo_control_panel.py
index 1f381d5..694f7d1 100644
--- a/utilities/demo/demo_control_panel.py
+++ b/utilities/demo/demo_control_panel.py
@@ -1,13 +1,16 @@
+from __future__ import unicode_literals
+import webnotes
- def on_login(self):
- from webnotes.utils import validate_email_add
- import conf
- if hasattr(conf, "demo_notify_url"):
- if webnotes.form_dict.lead_email and validate_email_add(webnotes.form_dict.lead_email):
- import requests
- response = requests.post(conf.demo_notify_url, data={
- "cmd":"portal.utils.send_message",
- "subject":"Logged into Demo",
- "sender": webnotes.form_dict.lead_email,
- "message": "via demo.erpnext.com"
- })
\ No newline at end of file
+class CustomDocType(DocType):
+ def on_login(self):
+ from webnotes.utils import validate_email_add
+ from webnotes import conf
+ if "demo_notify_url" in conf:
+ if webnotes.form_dict.lead_email and validate_email_add(webnotes.form_dict.lead_email):
+ import requests
+ response = requests.post(conf.demo_notify_url, data={
+ "cmd":"portal.utils.send_message",
+ "subject":"Logged into Demo",
+ "sender": webnotes.form_dict.lead_email,
+ "message": "via demo.erpnext.com"
+ })
diff --git a/utilities/demo/demo_docs/Lead.csv b/utilities/demo/demo_docs/Lead.csv
index c00ab44..a7004e4 100644
--- a/utilities/demo/demo_docs/Lead.csv
+++ b/utilities/demo/demo_docs/Lead.csv
@@ -1,68 +1,68 @@
-Data Import Template,,,,,,,,,,,,,,,,,,,,,,,,,,,
-Table:,Lead,,,,,,,,,,,,,,,,,,,,,,,,,,
-,,,,,,,,,,,,,,,,,,,,,,,,,,,
-,,,,,,,,,,,,,,,,,,,,,,,,,,,
-Notes:,,,,,,,,,,,,,,,,,,,,,,,,,,,
-Please do not change the template headings.,,,,,,,,,,,,,,,,,,,,,,,,,,,
-First data column must be blank.,,,,,,,,,,,,,,,,,,,,,,,,,,,
-Only mandatory fields are necessary for new records. You can delete non-mandatory columns if you wish.,,,,,,,,,,,,,,,,,,,,,,,,,,,
-"For updating, you can update only selective columns.",,,,,,,,,,,,,,,,,,,,,,,,,,,
-"If you are uploading new records, leave the ""name"" (ID) column blank.",,,,,,,,,,,,,,,,,,,,,,,,,,,
-"If you are uploading new records, ""Naming Series"" becomes mandatory, if present.",,,,,,,,,,,,,,,,,,,,,,,,,,,
-You can only upload upto 5000 records in one go. (may be less in some cases),,,,,,,,,,,,,,,,,,,,,,,,,,,
-,,,,,,,,,,,,,,,,,,,,,,,,,,,
-Column Labels,ID,Contact Name,Status,Naming Series,Company Name,Email Id,Source,From Customer,Campaign Name,Remark,Phone,Mobile No.,Fax,Website,Territory,Lead Type,Lead Owner,Market Segment,Industry,Request Type,Lost Reason,Next Contact By,Next Contact Date,Last Contact Date,Company,Unsubscribed,Blog Subscriber
-Column Name:,name,lead_name,status,naming_series,company_name,email_id,source,customer,campaign_name,remark,phone,mobile_no,fax,website,territory,type,lead_owner,market_segment,industry,request_type,order_lost_reason,contact_by,contact_date,last_contact_date,company,unsubscribed,blog_subscriber
-Mandatory:,Yes,Yes,Yes,No,No,No,No,No,No,No,No,No,No,No,No,No,No,No,No,No,No,No,No,No,No,No,No
-Type:,Data (text),Data,Select,Select,Data,Data,Select,Link,Link,Small Text,Data,Data,Data,Data,Link,Select,Link,Select,Link,Select,Link,Link,Date,Date,Link,Check,Check
-Info:,,,"One of: Open, Replied, Attempted to Contact, Contact in Future, Contacted, Interested, Not interested, Lead Lost, Converted","One of: LEAD, LEAD/10-11/, LEAD/MUMBAI/",,,"One of: Advertisement, Blog Post, Campaign, Call, Customer, Exhibition, Supplier, Website, Email",Valid Customer,Valid Campaign,,,,,,Valid Territory,"One of: Client, Channel Partner, Consultant",Valid Profile,"One of: Lower Income, Middle Income, Upper Income",Valid Industry Type,"One of: Product Enquiry, Request for Information, Suggestions, Other",Valid Quotation Lost Reason,Valid Profile,,,Valid Company,0 or 1,0 or 1
-Start entering data below this line,,,,,,,,,,,,,,,,,,,,,,,,,,,
-,,Mart Lakeman,Passive,,Zany Brainy,MartLakeman@einrot.com,,,,,,,,,,,,,,,,,,,,,
-,,Saga Lundqvist,Passive,,Patterson-Fletcher,SagaLundqvist@dayrep.com,,,,,,,,,,,,,,,,,,,,,
-,,Adna Sjöberg,Passive,,Griff's Hamburgers,AdnaSjoberg@gustr.com,,,,,,,,,,,,,,,,,,,,,
-,,Ida Svendsen,Passive,,Rhodes Furniture,IdaDSvendsen@superrito.com,,,,,,,,,,,,,,,,,,,,,
-,,Emppu Hämeenniemi,Passive,,Burger Chef,EmppuHameenniemi@teleworm.us,,,,,,,,,,,,,,,,,,,,,
-,,Eugenio Pisano,Passive,,Stratabiz,EugenioPisano@cuvox.de,,,,,,,,,,,,,,,,,,,,,
-,,Semhar Hagos,Passive,,Home Quarters Warehouse,SemharHagos@einrot.com,,,,,,,,,,,,,,,,,,,,,
-,,Branimira Ivanković,Passive,,Enviro Architectural Designs,BranimiraIvankovic@einrot.com,,,,,,,,,,,,,,,,,,,,,
-,,Shelly Fields,Passive,,Ideal Garden Management,ShellyLFields@superrito.com,,,,,,,,,,,,,,,,,,,,,
-,,Leo Mikulić,Passive,,Listen Up,LeoMikulic@gustr.com,,,,,,,,,,,,,,,,,,,,,
-,,Denisa Jarošová,Passive,,I. Magnin,DenisaJarosova@teleworm.us,,,,,,,,,,,,,,,,,,,,,
-,,Janek Rutkowski,Passive,,First Rate Choice,JanekRutkowski@dayrep.com,,,,,,,,,,,,,,,,,,,,,
-,,美月 宇藤,Passive,,Multi Tech Development,mm@gustr.com,,,,,,,,,,,,,,,,,,,,,
-,,Даниил Афанасьев,Passive,,National Auto Parts,dd@einrot.com,,,,,,,,,,,,,,,,,,,,,
-,,Zorislav Petković,Passive,,Integra Investment Plan,ZorislavPetkovic@cuvox.de,,,,,,,,,,,,,,,,,,,,,
-,,Nanao Niwa,Passive,,The Lawn Guru,NanaoNiwa@superrito.com,,,,,,,,,,,,,,,,,,,,,
-,,Hreiðar Jörundsson,Passive,,Buena Vista Realty Service,HreiarJorundsson@armyspy.com,,,,,,,,,,,,,,,,,,,,,
-,,Lai Chu,Passive,,Bountiful Harvest Health Food Store,ChuThiBichLai@einrot.com,,,,,,,,,,,,,,,,,,,,,
-,,Victor Aksakov,Passive,,P. Samuels Men's Clothiers,VictorAksakov@dayrep.com,,,,,,,,,,,,,,,,,,,,,
-,,Saidalim Bisliev,Passive,,Vinyl Fever,SaidalimBisliev@cuvox.de,,,,,,,,,,,,,,,,,,,,,
-,,Totte Jakobsson,Passive,,Garden Master,TotteJakobsson@armyspy.com,,,,,,,,,,,,,,,,,,,,,
-,,Naná Armas,Passive,,Big Apple,NanaArmasRobles@cuvox.de,,,,,,,,,,,,,,,,,,,,,
-,,Walerian Duda,Passive,,Monk House Sales,WalerianDuda@dayrep.com,,,,,,,,,,,,,,,,,,,,,
-,,Moarimikashi ,Passive,,ManCharm,Moarimikashi@teleworm.us,,,,,,,,,,,,,,,,,,,,,
-,,Dobromił Dąbrowski ,Passive,,Custom Lawn Care,DobromilDabrowski@dayrep.com,,,,,,,,,,,,,,,,,,,,,
-,,Teigan Sinclair,Passive,,The Serendipity Dip,TeiganSinclair@gustr.com,,,,,,,,,,,,,,,,,,,,,
-,,Fahad Guirguis,Passive,,Cavages,FahadSaidGuirguis@gustr.com,,,,,,,,,,,,,,,,,,,,,
-,,Morten Olsen,Passive,,Gallenkamp,MortenJOlsen@armyspy.com,,,,,,,,,,,,,,,,,,,,,
-,,Christian Baecker,Passive,,Webcom Business Services,ChristianBaecker@armyspy.com,,,,,,,,,,,,,,,,,,,,,
-,,Sebastianus Dohmen,Passive,,Accord Investments,SebastianusDohmen@cuvox.de,,,,,,,,,,,,,,,,,,,,,
-,,Eero Koskinen,Passive,,American Appliance,EeroKoskinen@superrito.com,,,,,,,,,,,,,,,,,,,,,
-,,富奎 盧,Passive,,Bettendorf's,LuFuKui@teleworm.us,,,,,,,,,,,,,,,,,,,,,
-,,Milica Jelić,Passive,,House Of Denmark,MilicaJelic@dayrep.com,,,,,,,,,,,,,,,,,,,,,
-,,Barbora Holubová,Passive,,10000 Auto Parts,BarboraHolubova@cuvox.de,,,,,,,,,,,,,,,,,,,,,
-,,Marta Kos,Passive,,Mages,MartaKos@einrot.com,,,,,,,,,,,,,,,,,,,,,
-,,Simret Zula,Passive,,CSK Auto,SimretZula@cuvox.de,,,,,,,,,,,,,,,,,,,,,
-,,Kamil Chlubna,Passive,,Eagle Hardware & Garden,KamilChlubna@einrot.com,,,,,,,,,,,,,,,,,,,,,
-,,Aceline Bolduc,Passive,,Rustler Steak House,AcelineBolduc@armyspy.com,,,,,,,,,,,,,,,,,,,,,
-,,Lucie Stupková,Passive,,ABCO Foods,LucieStupkova@gustr.com,,,,,,,,,,,,,,,,,,,,,
-,,Roland Solvik,Passive,,Trak Auto,RolandSolvik@cuvox.de,,,,,,,,,,,,,,,,,,,,,
-,,Mekirinzukushitakufu ,Passive,,Choices,Mekirinzukushitakufu@teleworm.us,,,,,,,,,,,,,,,,,,,,,
-,,Mukharbek Sultanovich,Passive,,Megatronic,MukharbekSultanovich@cuvox.de,,,,,,,,,,,,,,,,,,,,,
-,,Osman Amanuel,Passive,,Handy Dan,OsmanAmanuel@dayrep.com,,,,,,,,,,,,,,,,,,,,,
-,,幸子 阪部,Passive,,Channel Home Centers,dd@armyspy.com,,,,,,,,,,,,,,,,,,,,,
-,,Masakazu Kamitani,Passive,,Honest Air Group,MasakazuKamitani@superrito.com,,,,,,,,,,,,,,,,,,,,,
-,,Omran Sabbagh,Passive,,Pleasures and Pasttimes,OmranNuhaidSabbagh@einrot.com,,,,,,,,,,,,,,,,,,,,,
-,,Rikako Matsumura,Passive,,Lazysize,RikakoMatsumura@einrot.com,,,,,,,,,,,,,,,,,,,,,
-,,Anayolisa Chukwukadibia,Passive,,Prestiga-Biz,AnayolisaChukwukadibia@einrot.com,,,,,,,,,,,,,,,,,,,,,
-,,Gudmunda Hinna,Passive,,Childs Restaurants,GudmundaHinna@armyspy.com,,,,,,,,,,,,,,,,,,,,,
\ No newline at end of file
+Data Import Template,,,,,,,,,,,,,,,,,,,,,,,,,,
+Table:,Lead,,,,,,,,,,,,,,,,,,,,,,,,,
+,,,,,,,,,,,,,,,,,,,,,,,,,,
+,,,,,,,,,,,,,,,,,,,,,,,,,,
+Notes:,,,,,,,,,,,,,,,,,,,,,,,,,,
+Please do not change the template headings.,,,,,,,,,,,,,,,,,,,,,,,,,,
+First data column must be blank.,,,,,,,,,,,,,,,,,,,,,,,,,,
+Only mandatory fields are necessary for new records. You can delete non-mandatory columns if you wish.,,,,,,,,,,,,,,,,,,,,,,,,,,
+"For updating, you can update only selective columns.",,,,,,,,,,,,,,,,,,,,,,,,,,
+"If you are uploading new records, leave the ""name"" (ID) column blank.",,,,,,,,,,,,,,,,,,,,,,,,,,
+"If you are uploading new records, ""Naming Series"" becomes mandatory, if present.",,,,,,,,,,,,,,,,,,,,,,,,,,
+You can only upload upto 5000 records in one go. (may be less in some cases),,,,,,,,,,,,,,,,,,,,,,,,,,
+,,,,,,,,,,,,,,,,,,,,,,,,,,
+Column Labels,ID,Contact Name,Status,Naming Series,Company Name,Email Id,Source,From Customer,Campaign Name,Remark,Phone,Mobile No.,Fax,Website,Territory,Lead Type,Lead Owner,Market Segment,Industry,Request Type,Next Contact By,Next Contact Date,Company,Unsubscribed,Blog Subscriber,
+Column Name:,name,lead_name,status,naming_series,company_name,email_id,source,customer,campaign_name,remark,phone,mobile_no,fax,website,territory,type,lead_owner,market_segment,industry,request_type,contact_by,contact_date,company,unsubscribed,blog_subscriber,
+Mandatory:,Yes,Yes,Yes,No,No,No,No,No,No,No,No,No,No,No,No,No,No,No,No,No,No,No,No,No,No,
+Type:,Data (text),Data,Select,Select,Data,Data,Select,Link,Link,Small Text,Data,Data,Data,Data,Link,Select,Link,Select,Link,Select,Link,Date,Link,Check,Check,
+Info:,,,"Lead, Open, Replied, Opportunity, Interested, Converted, Do Not Contact","One of: LEAD, LEAD/10-11/, LEAD/MUMBAI/",,,"One of: Advertisement, Blog Post, Campaign, Call, Customer, Exhibition, Supplier, Website, Email",Valid Customer,Valid Campaign,,,,,,Valid Territory,"One of: Client, Channel Partner, Consultant",Valid Profile,"One of: Lower Income, Middle Income, Upper Income",Valid Industry Type,"One of: Product Enquiry, Request for Information, Suggestions, Other",Valid Profile,,Valid Company,0 or 1,0 or 1,
+Start entering data below this line,,,,,,,,,,,,,,,,,,,,,,,,,,
+,,Mart Lakeman,Lead,,Zany Brainy,MartLakeman@einrot.com,,,,,,,,,,,,,,,,,,,,
+,,Saga Lundqvist,Lead,,Patterson-Fletcher,SagaLundqvist@dayrep.com,,,,,,,,,,,,,,,,,,,,
+,,Adna Sjöberg,Lead,,Griff's Hamburgers,AdnaSjoberg@gustr.com,,,,,,,,,,,,,,,,,,,,
+,,Ida Svendsen,Lead,,Rhodes Furniture,IdaDSvendsen@superrito.com,,,,,,,,,,,,,,,,,,,,
+,,Emppu Hämeenniemi,Lead,,Burger Chef,EmppuHameenniemi@teleworm.us,,,,,,,,,,,,,,,,,,,,
+,,Eugenio Pisano,Lead,,Stratabiz,EugenioPisano@cuvox.de,,,,,,,,,,,,,,,,,,,,
+,,Semhar Hagos,Lead,,Home Quarters Warehouse,SemharHagos@einrot.com,,,,,,,,,,,,,,,,,,,,
+,,Branimira Ivanković,Lead,,Enviro Architectural Designs,BranimiraIvankovic@einrot.com,,,,,,,,,,,,,,,,,,,,
+,,Shelly Fields,Lead,,Ideal Garden Management,ShellyLFields@superrito.com,,,,,,,,,,,,,,,,,,,,
+,,Leo Mikulić,Lead,,Listen Up,LeoMikulic@gustr.com,,,,,,,,,,,,,,,,,,,,
+,,Denisa Jarošová,Lead,,I. Magnin,DenisaJarosova@teleworm.us,,,,,,,,,,,,,,,,,,,,
+,,Janek Rutkowski,Lead,,First Rate Choice,JanekRutkowski@dayrep.com,,,,,,,,,,,,,,,,,,,,
+,,美月 宇藤,Lead,,Multi Tech Development,mm@gustr.com,,,,,,,,,,,,,,,,,,,,
+,,Даниил Афанасьев,Lead,,National Auto Parts,dd@einrot.com,,,,,,,,,,,,,,,,,,,,
+,,Zorislav Petković,Lead,,Integra Investment Plan,ZorislavPetkovic@cuvox.de,,,,,,,,,,,,,,,,,,,,
+,,Nanao Niwa,Lead,,The Lawn Guru,NanaoNiwa@superrito.com,,,,,,,,,,,,,,,,,,,,
+,,Hreiðar Jörundsson,Lead,,Buena Vista Realty Service,HreiarJorundsson@armyspy.com,,,,,,,,,,,,,,,,,,,,
+,,Lai Chu,Lead,,Bountiful Harvest Health Food Store,ChuThiBichLai@einrot.com,,,,,,,,,,,,,,,,,,,,
+,,Victor Aksakov,Lead,,P. Samuels Men's Clothiers,VictorAksakov@dayrep.com,,,,,,,,,,,,,,,,,,,,
+,,Saidalim Bisliev,Lead,,Vinyl Fever,SaidalimBisliev@cuvox.de,,,,,,,,,,,,,,,,,,,,
+,,Totte Jakobsson,Lead,,Garden Master,TotteJakobsson@armyspy.com,,,,,,,,,,,,,,,,,,,,
+,,Naná Armas,Lead,,Big Apple,NanaArmasRobles@cuvox.de,,,,,,,,,,,,,,,,,,,,
+,,Walerian Duda,Lead,,Monk House Sales,WalerianDuda@dayrep.com,,,,,,,,,,,,,,,,,,,,
+,,Moarimikashi ,Lead,,ManCharm,Moarimikashi@teleworm.us,,,,,,,,,,,,,,,,,,,,
+,,Dobromił Dąbrowski ,Lead,,Custom Lawn Care,DobromilDabrowski@dayrep.com,,,,,,,,,,,,,,,,,,,,
+,,Teigan Sinclair,Lead,,The Serendipity Dip,TeiganSinclair@gustr.com,,,,,,,,,,,,,,,,,,,,
+,,Fahad Guirguis,Lead,,Cavages,FahadSaidGuirguis@gustr.com,,,,,,,,,,,,,,,,,,,,
+,,Morten Olsen,Lead,,Gallenkamp,MortenJOlsen@armyspy.com,,,,,,,,,,,,,,,,,,,,
+,,Christian Baecker,Lead,,Webcom Business Services,ChristianBaecker@armyspy.com,,,,,,,,,,,,,,,,,,,,
+,,Sebastianus Dohmen,Lead,,Accord Investments,SebastianusDohmen@cuvox.de,,,,,,,,,,,,,,,,,,,,
+,,Eero Koskinen,Lead,,American Appliance,EeroKoskinen@superrito.com,,,,,,,,,,,,,,,,,,,,
+,,富奎 盧,Lead,,Bettendorf's,LuFuKui@teleworm.us,,,,,,,,,,,,,,,,,,,,
+,,Milica Jelić,Lead,,House Of Denmark,MilicaJelic@dayrep.com,,,,,,,,,,,,,,,,,,,,
+,,Barbora Holubová,Lead,,10000 Auto Parts,BarboraHolubova@cuvox.de,,,,,,,,,,,,,,,,,,,,
+,,Marta Kos,Lead,,Mages,MartaKos@einrot.com,,,,,,,,,,,,,,,,,,,,
+,,Simret Zula,Lead,,CSK Auto,SimretZula@cuvox.de,,,,,,,,,,,,,,,,,,,,
+,,Kamil Chlubna,Lead,,Eagle Hardware & Garden,KamilChlubna@einrot.com,,,,,,,,,,,,,,,,,,,,
+,,Aceline Bolduc,Lead,,Rustler Steak House,AcelineBolduc@armyspy.com,,,,,,,,,,,,,,,,,,,,
+,,Lucie Stupková,Lead,,ABCO Foods,LucieStupkova@gustr.com,,,,,,,,,,,,,,,,,,,,
+,,Roland Solvik,Lead,,Trak Auto,RolandSolvik@cuvox.de,,,,,,,,,,,,,,,,,,,,
+,,Mekirinzukushitakufu ,Lead,,Choices,Mekirinzukushitakufu@teleworm.us,,,,,,,,,,,,,,,,,,,,
+,,Mukharbek Sultanovich,Lead,,Megatronic,MukharbekSultanovich@cuvox.de,,,,,,,,,,,,,,,,,,,,
+,,Osman Amanuel,Lead,,Handy Dan,OsmanAmanuel@dayrep.com,,,,,,,,,,,,,,,,,,,,
+,,幸子 阪部,Lead,,Channel Home Centers,dd@armyspy.com,,,,,,,,,,,,,,,,,,,,
+,,Masakazu Kamitani,Lead,,Honest Air Group,MasakazuKamitani@superrito.com,,,,,,,,,,,,,,,,,,,,
+,,Omran Sabbagh,Lead,,Pleasures and Pasttimes,OmranNuhaidSabbagh@einrot.com,,,,,,,,,,,,,,,,,,,,
+,,Rikako Matsumura,Lead,,Lazysize,RikakoMatsumura@einrot.com,,,,,,,,,,,,,,,,,,,,
+,,Anayolisa Chukwukadibia,Lead,,Prestiga-Biz,AnayolisaChukwukadibia@einrot.com,,,,,,,,,,,,,,,,,,,,
+,,Gudmunda Hinna,Lead,,Childs Restaurants,GudmundaHinna@armyspy.com,,,,,,,,,,,,,,,,,,,,
\ No newline at end of file
diff --git a/utilities/demo/demo_docs/Profile.csv b/utilities/demo/demo_docs/Profile.csv
index 2e7a2ce..eb456c1 100644
--- a/utilities/demo/demo_docs/Profile.csv
+++ b/utilities/demo/demo_docs/Profile.csv
@@ -1,40 +1,40 @@
-Data Import Template,,,,,,,,,,,,,,,,,,,,,
-Table:,Profile,,,,,,,,,,,,,,,,,,,,
-,,,,,,,,,,,,,,,,,,,,,
-,,,,,,,,,,,,,,,,,,,,,
-Notes:,,,,,,,,,,,,,,,,,,,,,
-Please do not change the template headings.,,,,,,,,,,,,,,,,,,,,,
-First data column must be blank.,,,,,,,,,,,,,,,,,,,,,
-"If you are uploading new records, leave the ""name"" (ID) column blank.",,,,,,,,,,,,,,,,,,,,,
-"If you are uploading new records, ""Naming Series"" becomes mandatory, if present.",,,,,,,,,,,,,,,,,,,,,
-Only mandatory fields are necessary for new records. You can delete non-mandatory columns if you wish.,,,,,,,,,,,,,,,,,,,,,
-"For updating, you can update only selective columns.",,,,,,,,,,,,,,,,,,,,,
-You can only upload upto 5000 records in one go. (may be less in some cases),,,,,,,,,,,,,,,,,,,,,
-,,,,,,,,,,,,,,,,,,,,,
-DocType:,Profile,,,,,,,,,,,,,,,,,,,,
-Column Labels:,ID,Email,First Name,User Type,Enabled,Middle Name (Optional),Last Name,Send Invite Email,Language,Birth Date,Gender,New Password,User Image,Background Image,Bio,Email Signature,Login After,Login Before,Restrict IP,Last Login,Last IP
-Column Name:,name,email,first_name,user_type,enabled,middle_name,last_name,send_invite_email,language,birth_date,gender,new_password,user_image,background_image,bio,email_signature,login_after,login_before,restrict_ip,last_login,last_ip
-Mandatory:,Yes,Yes,Yes,Yes,No,No,No,No,No,No,No,No,No,No,No,No,No,No,No,No,No
-Type:,Data (text),Data,Data,Select,Check,Data,Data,Check,Select,Date,Select,Password,Select,Select,Small Text,Small Text,Int,Int,Data,Read Only,Read Only
-Info:,,,,"One of: System User, Website User",0 or 1,,,0 or 1,"One of: العربية, Deutsch, english, español, français, हिंदी, Hrvatski, nederlands, português, português brasileiro, српски, தமிழ், ไทย",,"One of: Male, Female, Other",,One of: attach_files:,One of: attach_files:,,,Integer,Integer,,,
-Start entering data below this line,,,,,,,,,,,,,,,,,,,,,
-,,DikmanShervashidze@armyspy.com,Dikman,System User,1,V,Shervashidze,0,,,,testpass,,,,,,,,,
-,,Zukutakitoteka@teleworm.us,Zukutakitoteka,System User,1,,,0,,,,testpass,,,,,,,,,
-,,HatsueKashiwagi@cuvox.de,Hatsue,System User,1,H,Kashiwagi,0,,,,testpass,,,,,,,,,
-,,NuranVerkleij@einrot.com,Nuran,System User,1,T,Verkleij,0,,,,testpass,,,,,,,,,
-,,aromn@armyspy.com,Дмитрий,System User,1,З,Пирогов,0,,,,testpass,,,,,,,,,
-,,TildeLindqvist@cuvox.de,Tilde,System User,1,T,Lindqvist,0,,,,testpass,,,,,,,,,
-,,MichalSobczak@teleworm.us,Michał,System User,1,S,Sobczak,0,,,,testpass,,,,,,,,,
-,,GabrielleLoftus@superrito.com,Gabrielle,System User,1,J,Loftus,0,,,,testpass,,,,,,,,,
-,,VakhitaRyzaev@teleworm.us,Vakhita,System User,1,A,Ryzaev,0,,,,testpass,,,,,,,,,
-,,CharmaineGaudreau@cuvox.de,Charmaine,System User,1,D,Gaudreau,0,,,,testpass,,,,,,,,,
-,,RafaelaMaartens@cuvox.de,Rafaëla,System User,1,Z,Maartens,0,,,,testpass,,,,,,,,,
-,,NuguseYohannes@dayrep.com,Nuguse,System User,0,S,Yohannes,0,,,,testpass,,,,,,,,,
-,,panca@armyspy.com,Раиса,System User,0,В,Белякова,0,,,,testpass,,,,,,,,,
-,,CaYinLong@gustr.com,胤隆,System User,1,婷,蔡,0,,,,testpass,,,,,,,,,
-,,FreddieScott@armyspy.com,Freddie,System User,1,A,Scott,0,,,,testpass,,,,,,,,,
-,,BergoraVigfusdottir@superrito.com,Bergþóra,System User,1,Ö,Vigfúsdóttir,0,,,,testpass,,,,,,,,,
-,,WardNajmalDinKalb@cuvox.de,Ward,System User,1,N,Kalb,0,,,,testpass,,,,,,,,,
-,,WanMai@teleworm.us,Wan,System User,1,A,Mai,0,,,,testpass,,,,,,,,,
-,,LeonAbdulov@superrito.com,Leon,System User,1,A,Abdulov,0,,,,testpass,,,,,,,,,
-,,SabinaNovotna@superrito.com,Sabina,System User,1,J,Novotná,0,,,,testpass,,,,,,,,,
\ No newline at end of file
+Data Import Template,,,,,,,,,,,,,,,,,,,,
+Table:,Profile,,,,,,,,,,,,,,,,,,,
+,,,,,,,,,,,,,,,,,,,,
+,,,,,,,,,,,,,,,,,,,,
+Notes:,,,,,,,,,,,,,,,,,,,,
+Please do not change the template headings.,,,,,,,,,,,,,,,,,,,,
+First data column must be blank.,,,,,,,,,,,,,,,,,,,,
+"If you are uploading new records, leave the ""name"" (ID) column blank.",,,,,,,,,,,,,,,,,,,,
+"If you are uploading new records, ""Naming Series"" becomes mandatory, if present.",,,,,,,,,,,,,,,,,,,,
+Only mandatory fields are necessary for new records. You can delete non-mandatory columns if you wish.,,,,,,,,,,,,,,,,,,,,
+"For updating, you can update only selective columns.",,,,,,,,,,,,,,,,,,,,
+You can only upload upto 5000 records in one go. (may be less in some cases),,,,,,,,,,,,,,,,,,,,
+,,,,,,,,,,,,,,,,,,,,
+DocType:,Profile,,,,,,,,,,,,,,,,,,,
+Column Labels:,ID,Email,First Name,User Type,Enabled,Middle Name (Optional),Last Name,Language,Birth Date,Gender,New Password,User Image,Background Image,Bio,Email Signature,Login After,Login Before,Restrict IP,Last Login,Last IP
+Column Name:,name,email,first_name,user_type,enabled,middle_name,last_name,language,birth_date,gender,new_password,user_image,background_image,bio,email_signature,login_after,login_before,restrict_ip,last_login,last_ip
+Mandatory:,Yes,Yes,Yes,Yes,No,No,No,No,No,No,No,No,No,No,No,No,No,No,No,No
+Type:,Data (text),Data,Data,Select,Check,Data,Data,Select,Date,Select,Password,Select,Select,Small Text,Small Text,Int,Int,Data,Read Only,Read Only
+Info:,,,,"One of: System User, Website User",0 or 1,,,"One of: العربية, Deutsch, english, español, français, हिंदी, Hrvatski, nederlands, português, português brasileiro, српски, தமிழ், ไทย",,"One of: Male, Female, Other",,One of: attach_files:,One of: attach_files:,,,Integer,Integer,,,
+Start entering data below this line,,,,,,,,,,,,,,,,,,,,
+,,DikmanShervashidze@armyspy.com,Dikman,System User,1,V,Shervashidze,,,,testpass,,,,,,,,,
+,,Zukutakitoteka@teleworm.us,Zukutakitoteka,System User,1,,,,,,testpass,,,,,,,,,
+,,HatsueKashiwagi@cuvox.de,Hatsue,System User,1,H,Kashiwagi,,,,testpass,,,,,,,,,
+,,NuranVerkleij@einrot.com,Nuran,System User,1,T,Verkleij,,,,testpass,,,,,,,,,
+,,aromn@armyspy.com,Дмитрий,System User,1,З,Пирогов,,,,testpass,,,,,,,,,
+,,TildeLindqvist@cuvox.de,Tilde,System User,1,T,Lindqvist,,,,testpass,,,,,,,,,
+,,MichalSobczak@teleworm.us,Michał,System User,1,S,Sobczak,,,,testpass,,,,,,,,,
+,,GabrielleLoftus@superrito.com,Gabrielle,System User,1,J,Loftus,,,,testpass,,,,,,,,,
+,,VakhitaRyzaev@teleworm.us,Vakhita,System User,1,A,Ryzaev,,,,testpass,,,,,,,,,
+,,CharmaineGaudreau@cuvox.de,Charmaine,System User,1,D,Gaudreau,,,,testpass,,,,,,,,,
+,,RafaelaMaartens@cuvox.de,Rafaëla,System User,1,Z,Maartens,,,,testpass,,,,,,,,,
+,,NuguseYohannes@dayrep.com,Nuguse,System User,0,S,Yohannes,,,,testpass,,,,,,,,,
+,,panca@armyspy.com,Раиса,System User,0,В,Белякова,,,,testpass,,,,,,,,,
+,,CaYinLong@gustr.com,胤隆,System User,1,婷,蔡,,,,testpass,,,,,,,,,
+,,FreddieScott@armyspy.com,Freddie,System User,1,A,Scott,,,,testpass,,,,,,,,,
+,,BergoraVigfusdottir@superrito.com,Bergþóra,System User,1,Ö,Vigfúsdóttir,,,,testpass,,,,,,,,,
+,,WardNajmalDinKalb@cuvox.de,Ward,System User,1,N,Kalb,,,,testpass,,,,,,,,,
+,,WanMai@teleworm.us,Wan,System User,1,A,Mai,,,,testpass,,,,,,,,,
+,,LeonAbdulov@superrito.com,Leon,System User,1,A,Abdulov,,,,testpass,,,,,,,,,
+,,SabinaNovotna@superrito.com,Sabina,System User,1,J,Novotná,,,,testpass,,,,,,,,,
diff --git a/utilities/demo/make_demo.py b/utilities/demo/make_demo.py
index 046e81a..9df34c2 100644
--- a/utilities/demo/make_demo.py
+++ b/utilities/demo/make_demo.py
@@ -30,17 +30,27 @@
}
def make(reset=False, simulate=True):
- #webnotes.print_messages = True
- webnotes.mute_emails = True
- webnotes.rollback_on_exception = True
+ #webnotes.flags.print_messages = True
+ webnotes.flags.mute_emails = True
+ webnotes.flags.rollback_on_exception = True
+
+ if not webnotes.conf.demo_db_name:
+ raise Exception("conf.py does not have demo_db_name")
if reset:
setup()
+ else:
+ if webnotes.conn:
+ webnotes.conn.close()
+
+ webnotes.connect(db_name=webnotes.conf.demo_db_name)
+
if simulate:
_simulate()
-
+
def setup():
install()
+ webnotes.connect(db_name=webnotes.conf.demo_db_name)
complete_setup()
make_customers_suppliers_contacts()
make_items()
@@ -65,7 +75,7 @@
for i in xrange(runs_for):
print current_date.strftime("%Y-%m-%d")
- webnotes.utils.current_date = current_date
+ webnotes.local.current_date = current_date
if current_date.weekday() in (5, 6):
current_date = webnotes.utils.add_days(current_date, 1)
@@ -138,20 +148,23 @@
# make purchase requests
if can_make("Purchase Receipt"):
from buying.doctype.purchase_order.purchase_order import make_purchase_receipt
+ from stock.stock_ledger import NegativeStockError
report = "Purchase Order Items To Be Received"
for po in list(set([r[0] for r in query_report.run(report)["result"] if r[0]!="Total"]))[:how_many("Purchase Receipt")]:
pr = webnotes.bean(make_purchase_receipt(po))
pr.doc.posting_date = current_date
pr.doc.fiscal_year = "2013"
pr.insert()
- pr.submit()
- webnotes.conn.commit()
+ try:
+ pr.submit()
+ webnotes.conn.commit()
+ except NegativeStockError: pass
# make delivery notes (if possible)
if can_make("Delivery Note"):
from selling.doctype.sales_order.sales_order import make_delivery_note
from stock.stock_ledger import NegativeStockError
- from stock.doctype.stock_ledger_entry.stock_ledger_entry import SerialNoRequiredError, SerialNoQtyError
+ from stock.doctype.serial_no.serial_no import SerialNoRequiredError, SerialNoQtyError
report = "Ordered Items To Be Delivered"
for so in list(set([r[0] for r in query_report.run(report)["result"] if r[0]!="Total"]))[:how_many("Delivery Note")]:
dn = webnotes.bean(make_delivery_note(so))
@@ -357,13 +370,14 @@
def install():
print "Creating Fresh Database..."
from webnotes.install_lib.install import Installer
- import conf
+ from webnotes import conf
inst = Installer('root')
- inst.import_from_db(conf.demo_db_name, verbose = 1)
+ inst.install(conf.demo_db_name, verbose=1, force=1)
def complete_setup():
print "Complete Setup..."
- webnotes.get_obj("Setup Control").setup_account({
+ from setup.page.setup_wizard.setup_wizard import setup_account
+ setup_account({
"first_name": "Test",
"last_name": "User",
"fy_start": "1st Jan",
diff --git a/utilities/demo/make_erpnext_demo.py b/utilities/demo/make_erpnext_demo.py
index 766da26..cda38d6 100644
--- a/utilities/demo/make_erpnext_demo.py
+++ b/utilities/demo/make_erpnext_demo.py
@@ -5,17 +5,21 @@
import webnotes, os
import utilities.demo.make_demo
-def make_demo_app():
- webnotes.mute_emails = 1
- webnotes.connect()
+def make_demo_app(site=None):
+ webnotes.init(site=site)
+ webnotes.flags.mute_emails = 1
+
utilities.demo.make_demo.make(reset=True, simulate=False)
# setup demo user etc so that the site it up faster, while the data loads
make_demo_user()
make_demo_login_page()
make_demo_on_login_script()
utilities.demo.make_demo.make(reset=False, simulate=True)
+ webnotes.destroy()
def make_demo_user():
+ from webnotes.auth import _update_password
+
roles = ["Accounts Manager", "Analytics", "Expense Approver", "Accounts User",
"Leave Approver", "Blogger", "Customer", "Sales Manager", "Employee", "Support Manager",
"HR Manager", "HR User", "Maintenance Manager", "Maintenance User", "Material Manager",
@@ -42,11 +46,10 @@
p.doc.last_name = "User"
p.doc.enabled = 1
p.doc.user_type = "ERPNext Demo"
- p.doc.send_invite_email = 0
- p.doc.new_password = "demo"
p.insert()
add_roles(p)
p.save()
+ _update_password("demo@erpnext.com", "demo")
# make system manager user
if webnotes.conn.exists("Profile", "admin@erpnext.com"):
@@ -58,12 +61,11 @@
p.doc.last_name = "User"
p.doc.enabled = 1
p.doc.user_type = "System User"
- p.doc.send_invite_email = 0
- p.doc.new_password = "admin010123"
p.insert()
roles.append("System Manager")
add_roles(p)
p.save()
+ _update_password("admin@erpnext.com", "admin010123")
# only read for newsletter
webnotes.conn.sql("""update `tabDocPerm` set `write`=0, `create`=0, `cancel`=0
@@ -103,13 +105,12 @@
webnotes.conn.commit()
def make_demo_on_login_script():
- webnotes.conn.sql("""delete from `tabCustom Script` where dt='Control Panel'""")
- s = webnotes.new_bean("Custom Script")
- s.doc.dt = "Control Panel"
- s.doc.script_type = "Server"
- with open(os.path.join(os.path.dirname(__file__), "demo_control_panel.py"), "r") as dfile:
- s.doc.script = dfile.read()
- s.insert()
+ import shutil
+ from core.doctype.custom_script.custom_script import get_custom_server_script_path
+ custom_script_path = get_custom_server_script_path("Control Panel")
+ webnotes.create_folder(os.path.dirname(custom_script_path))
+
+ shutil.copyfile(os.path.join(os.path.dirname(__file__), "demo_control_panel.py"), custom_script_path)
cp = webnotes.bean("Control Panel")
cp.doc.custom_startup_code = """wn.ui.toolbar.show_banner('You are using ERPNext Demo. To start your own ERPNext Trial, <a href="https://erpnext.com/pricing-and-signup" target="_blank">click here</a>')"""
@@ -118,4 +119,6 @@
webnotes.conn.commit()
if __name__=="__main__":
- make_demo_app()
\ No newline at end of file
+ import sys
+ site = sys.argv[1:]
+ make_demo_app(site=site and site[0] or None)
diff --git a/utilities/doctype/contact/contact.py b/utilities/doctype/contact/contact.py
index 84c8a59..db233fb 100644
--- a/utilities/doctype/contact/contact.py
+++ b/utilities/doctype/contact/contact.py
@@ -12,14 +12,6 @@
self.doc = doc
self.doclist = doclist
- def on_communication(self, comm):
- if webnotes.conn.get_value("Profile", extract_email_id(comm.sender), "user_type")=="System User":
- status = "Replied"
- else:
- status = "Open"
-
- webnotes.conn.set(self.doc, 'status', status)
-
def autoname(self):
# concat first and last name
self.doc.name = " ".join(filter(None,
@@ -32,28 +24,28 @@
break
def validate(self):
+ self.set_status()
self.validate_primary_contact()
def validate_primary_contact(self):
- sql = webnotes.conn.sql
if self.doc.is_primary_contact == 1:
if self.doc.customer:
- sql("update tabContact set is_primary_contact=0 where customer = '%s'" % (self.doc.customer))
+ webnotes.conn.sql("update tabContact set is_primary_contact=0 where customer = '%s'" % (self.doc.customer))
elif self.doc.supplier:
- sql("update tabContact set is_primary_contact=0 where supplier = '%s'" % (self.doc.supplier))
+ webnotes.conn.sql("update tabContact set is_primary_contact=0 where supplier = '%s'" % (self.doc.supplier))
elif self.doc.sales_partner:
- sql("update tabContact set is_primary_contact=0 where sales_partner = '%s'" % (self.doc.sales_partner))
+ webnotes.conn.sql("update tabContact set is_primary_contact=0 where sales_partner = '%s'" % (self.doc.sales_partner))
else:
if self.doc.customer:
- if not sql("select name from tabContact where is_primary_contact=1 and customer = '%s'" % (self.doc.customer)):
+ if not webnotes.conn.sql("select name from tabContact where is_primary_contact=1 and customer = '%s'" % (self.doc.customer)):
self.doc.is_primary_contact = 1
elif self.doc.supplier:
- if not sql("select name from tabContact where is_primary_contact=1 and supplier = '%s'" % (self.doc.supplier)):
+ if not webnotes.conn.sql("select name from tabContact where is_primary_contact=1 and supplier = '%s'" % (self.doc.supplier)):
self.doc.is_primary_contact = 1
elif self.doc.sales_partner:
- if not sql("select name from tabContact where is_primary_contact=1 and sales_partner = '%s'" % (self.doc.sales_partner)):
+ if not webnotes.conn.sql("select name from tabContact where is_primary_contact=1 and sales_partner = '%s'" % (self.doc.sales_partner)):
self.doc.is_primary_contact = 1
def on_trash(self):
webnotes.conn.sql("""update `tabSupport Ticket` set contact='' where contact=%s""",
- self.doc.name)
\ No newline at end of file
+ self.doc.name)
diff --git a/utilities/doctype/contact/contact.txt b/utilities/doctype/contact/contact.txt
index 92dcf2e..199aaea 100644
--- a/utilities/doctype/contact/contact.txt
+++ b/utilities/doctype/contact/contact.txt
@@ -2,7 +2,7 @@
{
"creation": "2013-01-10 16:34:32",
"docstatus": 0,
- "modified": "2013-09-10 10:50:27",
+ "modified": "2013-10-08 16:48:50",
"modified_by": "Administrator",
"owner": "Administrator"
},
@@ -70,11 +70,12 @@
"fieldtype": "Column Break"
},
{
+ "default": "Passive",
"doctype": "DocField",
"fieldname": "status",
"fieldtype": "Select",
"label": "Status",
- "options": "\nOpen\nReplied"
+ "options": "Passive\nOpen\nReplied"
},
{
"doctype": "DocField",
@@ -84,7 +85,7 @@
"label": "Email Id",
"oldfieldname": "email_id",
"oldfieldtype": "Data",
- "reqd": 1,
+ "reqd": 0,
"search_index": 1
},
{
@@ -94,7 +95,7 @@
"label": "Phone",
"oldfieldname": "contact_no",
"oldfieldtype": "Data",
- "reqd": 1
+ "reqd": 0
},
{
"doctype": "DocField",
diff --git a/utilities/doctype/sms_control/sms_control.py b/utilities/doctype/sms_control/sms_control.py
index 9c2319f..f183920 100644
--- a/utilities/doctype/sms_control/sms_control.py
+++ b/utilities/doctype/sms_control/sms_control.py
@@ -10,8 +10,6 @@
from webnotes import msgprint
from webnotes.model.bean import getlist, copy_doclist
-sql = webnotes.conn.sql
-
class DocType:
def __init__(self, doc, doclist=[]):
self.doc = doc
@@ -50,7 +48,7 @@
def get_contact_number(self, arg):
"returns mobile number of the contact"
args = load_json(arg)
- number = sql("""select mobile_no, phone from tabContact where name=%s and %s=%s""" %
+ number = webnotes.conn.sql("""select mobile_no, phone from tabContact where name=%s and %s=%s""" %
('%s', args['key'], '%s'), (args['contact_name'], args['value']))
return number and (number[0][0] or number[0][1]) or ''
@@ -119,4 +117,4 @@
sl.message = arg['message']
sl.no_of_requested_sms = len(arg['receiver_list'])
sl.no_of_sent_sms = sent_sms
- sl.save(new=1)
\ No newline at end of file
+ sl.save(new=1)