Merge branch 'master' into edge
diff --git a/accounts/general_ledger.py b/accounts/general_ledger.py
index 215c351..8e0f408 100644
--- a/accounts/general_ledger.py
+++ b/accounts/general_ledger.py
@@ -16,7 +16,7 @@
from __future__ import unicode_literals
import webnotes
-from webnotes.utils import flt, cstr
+from webnotes.utils import flt, cstr, now
from webnotes.model.doc import Document
def make_gl_entries(gl_map, cancel=False, adv_adj=False, merge_entries=True,
@@ -109,5 +109,7 @@
(total_debit - total_credit), raise_exception=1)
def set_as_cancel(voucher_type, voucher_no):
- webnotes.conn.sql("""update `tabGL Entry` set is_cancelled='Yes'
- where voucher_type=%s and voucher_no=%s""", (voucher_type, voucher_no))
\ No newline at end of file
+ webnotes.conn.sql("""update `tabGL Entry` set is_cancelled='Yes',
+ modified=%s, modified_by=%s
+ where voucher_type=%s and voucher_no=%s""",
+ (now(), webnotes.session.user, voucher_type, voucher_no))
\ No newline at end of file
diff --git a/accounts/page/financial_analytics/financial_analytics.js b/accounts/page/financial_analytics/financial_analytics.js
index f0bafdb..f714549 100644
--- a/accounts/page/financial_analytics/financial_analytics.js
+++ b/accounts/page/financial_analytics/financial_analytics.js
@@ -71,9 +71,11 @@
setup_filters: function() {
var me = this;
this._super();
- this.filter_inputs.pl_or_bs.change(function() {
- me.filter_inputs.refresh.click();
- }).add_options($.map(wn.report_dump.data["Cost Center"], function(v) {return v.name;}));
+ this.trigger_refresh_on_change(["pl_or_bs"]);
+
+ this.filter_inputs.pl_or_bs
+ .add_options($.map(wn.report_dump.data["Cost Center"], function(v) {return v.name;}));
+
this.setup_plot_check();
},
init_filter_values: function() {
diff --git a/accounts/page/general_ledger/general_ledger.js b/accounts/page/general_ledger/general_ledger.js
index 8f6b598..4a3f21e 100644
--- a/accounts/page/general_ledger/general_ledger.js
+++ b/accounts/page/general_ledger/general_ledger.js
@@ -108,7 +108,7 @@
// filter accounts options by company
this.filter_inputs.company.change(function() {
me.setup_account_filter(this);
- me.filter_inputs.refresh.click();
+ me.set_route()
});
this.filter_inputs.account.change(function() {
diff --git a/buying/page/purchase_analytics/purchase_analytics.js b/buying/page/purchase_analytics/purchase_analytics.js
index 7d8171e..fc082ea 100644
--- a/buying/page/purchase_analytics/purchase_analytics.js
+++ b/buying/page/purchase_analytics/purchase_analytics.js
@@ -120,19 +120,9 @@
setup_filters: function() {
var me = this;
this._super();
-
- this.filter_inputs.value_or_qty.change(function() {
- me.filter_inputs.refresh.click();
- });
-
- this.filter_inputs.tree_type.change(function() {
- me.filter_inputs.refresh.click();
- });
- this.filter_inputs.based_on.change(function() {
- me.filter_inputs.refresh.click();
- });
-
+ this.trigger_refresh_on_change(["value_or_qty", "tree_type", "based_on"]);
+
this.show_zero_check()
this.setup_plot_check();
},
diff --git a/patches/patch_list.py b/patches/patch_list.py
index d6b8f18..d136820 100644
--- a/patches/patch_list.py
+++ b/patches/patch_list.py
@@ -16,6 +16,7 @@
from __future__ import unicode_literals
patch_list = [
+ "execute:webnotes.reload_doc('core', 'doctype', 'report') # 2013-03-07",
"patches.mar_2012.so_rv_mapper_fix",
"patches.mar_2012.clean_property_setter",
"patches.april_2012.naming_series_patch",
diff --git a/selling/page/sales_analytics/sales_analytics.js b/selling/page/sales_analytics/sales_analytics.js
index 499c6c0..0b35af5 100644
--- a/selling/page/sales_analytics/sales_analytics.js
+++ b/selling/page/sales_analytics/sales_analytics.js
@@ -122,18 +122,8 @@
setup_filters: function() {
var me = this;
this._super();
-
- this.filter_inputs.value_or_qty.change(function() {
- me.filter_inputs.refresh.click();
- });
-
- this.filter_inputs.tree_type.change(function() {
- me.filter_inputs.refresh.click();
- });
- this.filter_inputs.based_on.change(function() {
- me.filter_inputs.refresh.click();
- });
+ this.trigger_refresh_on_change(["value_or_qty", "tree_type", "based_on"]);
this.show_zero_check()
this.setup_plot_check();
diff --git a/setup/doctype/backup_manager/backup_dropbox.py b/setup/doctype/backup_manager/backup_dropbox.py
new file mode 100644
index 0000000..3b0857f
--- /dev/null
+++ b/setup/doctype/backup_manager/backup_dropbox.py
@@ -0,0 +1,115 @@
+import os
+import webnotes
+from webnotes.utils import get_request_site_address
+
+@webnotes.whitelist()
+def get_dropbox_authorize_url():
+ sess = get_dropbox_session()
+ request_token = sess.obtain_request_token()
+ return_address = get_request_site_address(True) \
+ + "?cmd=setup.doctype.backup_manager.backup_dropbox.dropbox_callback"
+
+ url = sess.build_authorize_url(request_token, return_address)
+
+ return {
+ "url": url,
+ "key": request_token.key,
+ "secret": request_token.secret,
+ }
+
+@webnotes.whitelist(allow_guest=True)
+def dropbox_callback(oauth_token=None, not_approved=False):
+ if not not_approved:
+ if webnotes.conn.get_value("Backup Manager", None, "dropbox_access_key")==oauth_token:
+ webnotes.conn.set_value("Backup Manager", "Backup Manager", "dropbox_access_allowed", 1)
+ message = "Dropbox access allowed."
+
+ sess = get_dropbox_session()
+ sess.set_request_token(webnotes.conn.get_value("Backup Manager", None, "dropbox_access_key"),
+ webnotes.conn.get_value("Backup Manager", None, "dropbox_access_secret"))
+ access_token = sess.obtain_access_token()
+
+ webnotes.conn.set_value("Backup Manager", "Backup Manager", "dropbox_access_key",
+ access_token.key)
+ webnotes.conn.set_value("Backup Manager", "Backup Manager", "dropbox_access_secret",
+ access_token.secret)
+
+ else:
+ webnotes.conn.set_value("Backup Manager", "Backup Manager", "dropbox_access_allowed", 0)
+ message = "Illegal Access Token Please try again."
+ else:
+ webnotes.conn.set_value("Backup Manager", "Backup Manager", "dropbox_access_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.conn.commit()
+ webnotes.response['type'] = 'page'
+ webnotes.response['page_name'] = 'message.html'
+
+def backup_to_dropbox():
+ from dropbox import client, session
+ from conf import dropbox_access_key, dropbox_secret_key
+ from webnotes.utils.backups import new_backup
+ if not webnotes.conn:
+ webnotes.connect()
+
+
+ sess = session.DropboxSession(dropbox_access_key, dropbox_secret_key, "app_folder")
+
+ sess.set_token(webnotes.conn.get_value("Backup Manager", None, "dropbox_access_key"),
+ webnotes.conn.get_value("Backup Manager", None, "dropbox_access_secret"))
+
+ dropbox_client = client.DropboxClient(sess)
+
+ # upload database
+ backup = new_backup()
+ filename = backup.backup_path_db
+ upload_file_to_dropbox(filename, "database", dropbox_client)
+
+ # upload files
+ response = dropbox_client.metadata("files")
+
+
+ # add missing files
+ for filename in os.listdir(os.path.join("public", "files")):
+ found = False
+ for file_metadata in response["contents"]:
+ if filename==os.path.basename(file_metadata["path"]):
+ if os.stat(os.path.join("public", "files", filename)).st_size==file_metadata["bytes"]:
+ found=True
+
+ if not found:
+ upload_file_to_dropbox(os.path.join("public", "files", filename), "files", dropbox_client)
+
+
+def get_dropbox_session():
+ from dropbox import session
+ try:
+ from conf import dropbox_access_key, dropbox_secret_key
+ except ImportError, e:
+ webnotes.msgprint(_("Please set Dropbox access keys in") + " conf.py",
+ raise_exception=True)
+
+ sess = session.DropboxSession(dropbox_access_key, dropbox_secret_key, "app_folder")
+ return sess
+
+def upload_file_to_dropbox(filename, folder, dropbox_client):
+ if __name__=="__main__":
+ print "Uploading " + filename
+ size = os.stat(filename).st_size
+ f = open(filename,'r')
+
+ if size > 4194304:
+ uploader = dropbox_client.get_chunked_uploader(f, size)
+ while uploader.offset < size:
+ try:
+ uploader.upload_chunked()
+ except rest.ErrorResponse, e:
+ pass
+ else:
+ response = dropbox_client.put_file(folder + "/" + os.path.basename(filename), f, overwrite=True)
+
+if __name__=="__main__":
+ backup_to_dropbox()
\ No newline at end of file
diff --git a/setup/doctype/backup_manager/backup_manager.js b/setup/doctype/backup_manager/backup_manager.js
index a0f7f71..154c72e 100644
--- a/setup/doctype/backup_manager/backup_manager.js
+++ b/setup/doctype/backup_manager/backup_manager.js
@@ -1,6 +1,6 @@
cur_frm.cscript.allow_dropbox_access = function(doc) {
wn.call({
- method: "setup.doctype.backup_manager.backup_manager.get_dropbox_authorize_url",
+ method: "setup.doctype.backup_manager.backup_dropbox.get_dropbox_authorize_url",
callback: function(r) {
if(!r.exc) {
cur_frm.set_value("dropbox_access_secret", r.message.secret);
@@ -11,4 +11,14 @@
}
}
})
+}
+
+cur_frm.cscript.backup_right_now = function(doc) {
+ msgprint("Backing up and uploading. This may take a few minutes.")
+ wn.call({
+ method: "setup.doctype.backup_manager.backup_manager.take_backups",
+ callback: function(r) {
+ msgprint("Backups taken. Please check your email for the response.")
+ }
+ })
}
\ No newline at end of file
diff --git a/setup/doctype/backup_manager/backup_manager.py b/setup/doctype/backup_manager/backup_manager.py
index fc41654..48d48e8 100644
--- a/setup/doctype/backup_manager/backup_manager.py
+++ b/setup/doctype/backup_manager/backup_manager.py
@@ -3,51 +3,46 @@
from __future__ import unicode_literals
import webnotes
from webnotes import _
-from webnotes.utils import get_request_site_address
class DocType:
def __init__(self, d, dl):
self.doc, self.doclist = d, dl
-@webnotes.whitelist()
-def get_dropbox_authorize_url():
- from dropbox import session
+def take_backups_daily():
+ take_backups_if("Daily")
+def take_backups_weekly():
+ take_backups_if("Weekly")
+
+def take_backups_if(freq):
+ if webnotes.conn.get_value("Backup Manager", None, "upload_backups_to_dropbox")==freq:
+ take_backups()
+
+@webnotes.whitelist()
+def take_backups():
try:
- from conf import dropbox_access_key, dropbox_secret_key
- except ImportError, e:
- webnotes.msgprint(_("Please set Dropbox access keys in") + " conf.py",
- raise_exception=True)
-
- sess = session.DropboxSession(dropbox_access_key, dropbox_secret_key, "app_folder")
- request_token = sess.obtain_request_token()
- return_address = get_request_site_address(True) \
- + "?cmd=setup.doctype.backup_manager.backup_manager.dropbox_callback"
-
- url = sess.build_authorize_url(request_token, return_address)
-
- return {
- "url": url,
- "key": request_token.key,
- "secret": request_token.secret,
- }
-
-@webnotes.whitelist(allow_guest=True)
-def dropbox_callback(oauth_token=None, not_approved=False):
- if not not_approved:
- if webnotes.conn.get_value("Backup Manager", None, "dropbox_access_key")==oauth_token:
- webnotes.conn.set_value("Backup Manager", "Backup Manager", "dropbox_access_allowed", 1)
- message = "Dropbox access allowed."
- else:
- webnotes.conn.set_value("Backup Manager", "Backup Manager", "dropbox_access_allowed", 0)
- message = "Illegal Access Token Please try again."
+ from setup.doctype.backup_manager.backup_dropbox import backup_to_dropbox
+ backup_to_dropbox()
+ send_email(True, "Dropbox")
+ except Exception, e:
+ send_email(False, "Dropbox", e)
+
+def send_email(success, service_name, error_status=None):
+ if success:
+ subject = "Backup Upload Successful"
+ message ="""<h3>Backup Uploaded Successfully</h3><p>Hi there, this is just to inform you
+ that your backup was successfully uploaded to your %s account. So relax!</p>
+ """ % service_name
+
else:
- webnotes.conn.set_value("Backup Manager", "Backup Manager", "dropbox_access_allowed", 0)
- message = "Dropbox Access not approved."
+ subject = "[Warning] Backup Upload Failed"
+ message ="""<h3>Backup Upload Failed</h3><p>Oops, your automated backup to %s
+ failed.</p>
+ <p>Error message: %s</p>
+ <p>Please contact your system manager for more information.</p>
+ """ % (service_name, error_status)
- webnotes.message_title = "Dropbox Approval"
- webnotes.message = "<h3>%s</h3><p>Please close this window.</p>" % message
-
- webnotes.conn.commit()
- webnotes.response['type'] = 'page'
- webnotes.response['page_name'] = 'message.html'
+ # email system managers
+ from webnotes.utils.email_lib import sendmail
+ sendmail(webnotes.conn.get_value("Backup Manager", None, "send_notifications_to").split(","),
+ subject=subject, msg=message)
diff --git a/setup/doctype/backup_manager/backup_manager.txt b/setup/doctype/backup_manager/backup_manager.txt
index bf5d686..a994e7d 100644
--- a/setup/doctype/backup_manager/backup_manager.txt
+++ b/setup/doctype/backup_manager/backup_manager.txt
@@ -2,7 +2,7 @@
{
"creation": "2013-03-05 16:35:50",
"docstatus": 0,
- "modified": "2013-03-05 18:05:05",
+ "modified": "2013-03-07 12:18:07",
"modified_by": "Administrator",
"owner": "Administrator"
},
@@ -40,6 +40,27 @@
},
{
"doctype": "DocField",
+ "fieldname": "setup",
+ "fieldtype": "Section Break",
+ "label": "Setup"
+ },
+ {
+ "description": "Email ids separated by commas.",
+ "doctype": "DocField",
+ "fieldname": "send_notifications_to",
+ "fieldtype": "Data",
+ "label": "Send Notifications To",
+ "reqd": 1
+ },
+ {
+ "doctype": "DocField",
+ "fieldname": "backup_right_now",
+ "fieldtype": "Button",
+ "label": "Backup Right Now"
+ },
+ {
+ "description": "Note: Backups and files are not deleted from Dropbox, you will have to delete them manually.",
+ "doctype": "DocField",
"fieldname": "sync_with_dropbox",
"fieldtype": "Section Break",
"label": "Sync with Dropbox"
@@ -47,27 +68,31 @@
{
"doctype": "DocField",
"fieldname": "upload_backups_to_dropbox",
- "fieldtype": "Check",
- "label": "Upload Backups to Dropbox"
+ "fieldtype": "Select",
+ "label": "Upload Backups to Dropbox",
+ "options": "Never\nWeekly\nDaily"
},
{
"doctype": "DocField",
"fieldname": "dropbox_access_key",
"fieldtype": "Data",
"hidden": 1,
- "label": "Dropbox Access Key"
+ "label": "Dropbox Access Key",
+ "read_only": 1
},
{
"doctype": "DocField",
"fieldname": "dropbox_access_secret",
"fieldtype": "Data",
"hidden": 1,
- "label": "Dropbox Access Secret"
+ "label": "Dropbox Access Secret",
+ "read_only": 1
},
{
"doctype": "DocField",
"fieldname": "dropbox_access_allowed",
"fieldtype": "Check",
+ "hidden": 1,
"label": "Dropbox Access Allowed",
"read_only": 1
},
diff --git a/setup/page/setup/setup.js b/setup/page/setup/setup.js
index 1d8a5ba..e970a60 100644
--- a/setup/page/setup/setup.js
+++ b/setup/page/setup/setup.js
@@ -186,19 +186,19 @@
},
]
},
- // {
- // title: wn._("Backups"),
- // icon: "icon-cloud-upload",
- // right: true,
- // items: [
- // {
- // "route":"Form/Backup Manager",
- // doctype:"Backup Manager",
- // label: wn._("Backup Manager"),
- // "description":wn._("Sync backups with remote tools like Dropbox etc.")
- // },
- // ]
- // },
+ {
+ title: wn._("Backups"),
+ icon: "icon-cloud-upload",
+ right: true,
+ items: [
+ {
+ "route":"Form/Backup Manager",
+ doctype:"Backup Manager",
+ label: wn._("Backup Manager"),
+ "description":wn._("Sync backups with remote tools like Dropbox etc.")
+ },
+ ]
+ },
]
pscript['onload_Setup'] = function(wrapper) {
diff --git a/startup/schedule_handlers.py b/startup/schedule_handlers.py
index c710c54..0799817 100644
--- a/startup/schedule_handlers.py
+++ b/startup/schedule_handlers.py
@@ -51,8 +51,13 @@
from webnotes.utils.email_lib.bulk import clear_outbox
run_fn(clear_outbox)
+ # daily backup
+ from setup.doctype.backup_manager.backup_manager import take_backups_daily
+ take_backups_daily()
+
def execute_weekly():
- pass
+ from setup.doctype.backup_manager.backup_manager import take_backups_weekly
+ take_backups_weekly()
def execute_monthly():
pass
diff --git a/utilities/transaction_base.py b/utilities/transaction_base.py
index 61486c5..905e98f 100644
--- a/utilities/transaction_base.py
+++ b/utilities/transaction_base.py
@@ -153,7 +153,7 @@
# Get Lead Details
# -----------------------
def get_lead_details(self, name):
- details = webnotes.conn.sql("select name, lead_name, address_line1, address_line2, city, country, state, pincode, territory, contact_no, mobile_no, email_id, company_name from `tabLead` where name = '%s'" %(name), as_dict = 1)
+ details = webnotes.conn.sql("select name, lead_name, address_line1, address_line2, city, country, state, pincode, territory, phone, mobile_no, email_id, company_name from `tabLead` where name = '%s'" %(name), as_dict = 1)
extract = lambda x: details and details[0] and details[0].get(x,'') or ''
address_fields = [('','address_line1'),('\n','address_line2'),('\n','city'),(' ','pincode'),('\n','state'),('\n','country'),('\nPhone: ','contact_no')]