diff --git a/accounts/general_ledger.py b/accounts/general_ledger.py index 215c351421..8e0f4082bc 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 @@ def validate_total_debit_credit(total_debit, total_credit): (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 f0bafdb07b..f7145490a1 100644 --- a/accounts/page/financial_analytics/financial_analytics.js +++ b/accounts/page/financial_analytics/financial_analytics.js @@ -71,9 +71,11 @@ erpnext.FinancialAnalytics = erpnext.AccountTreeGrid.extend({ 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 8f6b598d56..4a3f21ea92 100644 --- a/accounts/page/general_ledger/general_ledger.js +++ b/accounts/page/general_ledger/general_ledger.js @@ -108,7 +108,7 @@ erpnext.GeneralLedger = wn.views.GridReport.extend({ // 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 7d8171ebbd..fc082eae13 100644 --- a/buying/page/purchase_analytics/purchase_analytics.js +++ b/buying/page/purchase_analytics/purchase_analytics.js @@ -120,19 +120,9 @@ erpnext.PurchaseAnalytics = wn.views.TreeGridReport.extend({ 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 d6b8f183bb..d136820c2e 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 499c6c0156..0b35af5f31 100644 --- a/selling/page/sales_analytics/sales_analytics.js +++ b/selling/page/sales_analytics/sales_analytics.js @@ -122,18 +122,8 @@ erpnext.SalesAnalytics = wn.views.TreeGridReport.extend({ 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 0000000000..3b0857fdd9 --- /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 = "

%s

Please close this window.

" % 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 a0f7f71dcc..154c72ec0e 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.allow_dropbox_access = function(doc) { } } }) +} + +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 fc41654985..48d48e817c 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 ="""

Backup Uploaded Successfully

Hi there, this is just to inform you + that your backup was successfully uploaded to your %s account. So relax!

+ """ % 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 ="""

Backup Upload Failed

Oops, your automated backup to %s + failed.

+

Error message: %s

+

Please contact your system manager for more information.

+ """ % (service_name, error_status) - webnotes.message_title = "Dropbox Approval" - webnotes.message = "

%s

Please close this window.

" % 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 bf5d6867f4..a994e7da53 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" }, @@ -39,6 +39,27 @@ "name": "Backup Manager" }, { + "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", @@ -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 1d8a5ba822..e970a60c24 100644 --- a/setup/page/setup/setup.js +++ b/setup/page/setup/setup.js @@ -186,19 +186,19 @@ wn.module_page["Setup"] = [ }, ] }, - // { - // 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 c710c54086..0799817206 100644 --- a/startup/schedule_handlers.py +++ b/startup/schedule_handlers.py @@ -51,8 +51,13 @@ def execute_daily(): 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 61486c50d5..905e98f4bc 100644 --- a/utilities/transaction_base.py +++ b/utilities/transaction_base.py @@ -153,7 +153,7 @@ class TransactionBase(DocListController): # 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')]