diff --git a/frappe/integration_broker/doctype/integration_request/integration_request.json b/frappe/integration_broker/doctype/integration_request/integration_request.json index 542d5e7d71..e32450d9bb 100644 --- a/frappe/integration_broker/doctype/integration_request/integration_request.json +++ b/frappe/integration_broker/doctype/integration_request/integration_request.json @@ -9,11 +9,13 @@ "doctype": "DocType", "document_type": "", "editable_grid": 1, + "engine": "InnoDB", "fields": [ { "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "integration_type", "fieldtype": "Select", "hidden": 0, @@ -40,6 +42,7 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "integration_request_service", "fieldtype": "Data", "hidden": 0, @@ -66,6 +69,7 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "default": "Queued", "fieldname": "status", "fieldtype": "Select", @@ -73,7 +77,7 @@ "ignore_user_permissions": 0, "ignore_xss_filter": 0, "in_filter": 0, - "in_list_view": 0, + "in_list_view": 1, "label": "Status", "length": 0, "no_copy": 0, @@ -93,6 +97,7 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "data", "fieldtype": "Code", "hidden": 0, @@ -118,6 +123,7 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "output", "fieldtype": "Code", "hidden": 0, @@ -143,6 +149,7 @@ "allow_on_submit": 0, "bold": 0, "collapsible": 0, + "columns": 0, "fieldname": "error", "fieldtype": "Code", "hidden": 0, @@ -175,7 +182,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2016-08-11 10:40:32.231331", + "modified": "2016-10-13 05:01:14.913553", "modified_by": "Administrator", "module": "Integration Broker", "name": "Integration Request", @@ -192,6 +199,7 @@ "export": 1, "if_owner": 0, "import": 0, + "is_custom": 0, "permlevel": 0, "print": 1, "read": 1, @@ -208,5 +216,6 @@ "read_only_onload": 0, "sort_field": "modified", "sort_order": "DESC", + "title_field": "integration_request_service", "track_seen": 0 } \ No newline at end of file diff --git a/frappe/integration_broker/doctype/integration_service/integration_service.py b/frappe/integration_broker/doctype/integration_service/integration_service.py index 9b79d0307f..65755c6e11 100644 --- a/frappe/integration_broker/doctype/integration_service/integration_service.py +++ b/frappe/integration_broker/doctype/integration_service/integration_service.py @@ -6,7 +6,6 @@ from __future__ import unicode_literals import frappe from frappe import _ from frappe.model.document import Document -from frappe.utils.background_jobs import enqueue, get_jobs import json, urlparse from frappe.utils import get_request_session @@ -17,6 +16,8 @@ class IntegrationService(Document): self.enable_service() self.install_fixtures() + frappe.cache().delete_value('scheduler_events') + def install_fixtures(self): pass @@ -96,13 +97,15 @@ def get_integration_services(): return services -def trigger_integration_service_events(): - for service in frappe.get_all("Integration Service", filters={"enabled": 1}, fields=["name"]): +def get_integration_service_events(): + '''Get scheduler events for enabled integrations''' + events = {} + for service in frappe.get_all("Integration Service", filters={"enabled": 1}, + fields=["name"]): controller = get_integration_controller(service.name) - if hasattr(controller, "scheduled_jobs"): - for job in controller.scheduled_jobs: - for event, handlers in job.items(): - for handler in handlers: - if handler not in get_jobs(): - enqueue(handler, queue='short', event=event) \ No newline at end of file + if hasattr(controller, "scheduler_events"): + for key, handlers in controller.scheduler_events: + events.setdefault(key, []).extend(handlers) + + return events diff --git a/frappe/integration_broker/doctype/integration_service/test_integration_service.py b/frappe/integration_broker/doctype/integration_service/test_integration_service.py index 0db29654cc..e9f662e69f 100644 --- a/frappe/integration_broker/doctype/integration_service/test_integration_service.py +++ b/frappe/integration_broker/doctype/integration_service/test_integration_service.py @@ -5,8 +5,16 @@ from __future__ import unicode_literals import frappe import unittest +from frappe.utils.scheduler import get_scheduler_events # test_records = frappe.get_test_records('Integration Service') class TestIntegrationService(unittest.TestCase): - pass + def test_scheudler_events(self): + dropbox_settings = frappe.get_doc('Dropbox Settings') + dropbox_settings.db_set('enabled', 1) + + events = get_scheduler_events('daily_long') + self.assertTrue('frappe.integrations.dropbox_integration.take_backups_daily' in events) + + dropbox_settings.db_set('enabled', 0) diff --git a/frappe/integrations/doctype/dropbox_settings/dropbox_settings.py b/frappe/integrations/doctype/dropbox_settings/dropbox_settings.py index 3400971087..2c54c09882 100644 --- a/frappe/integrations/doctype/dropbox_settings/dropbox_settings.py +++ b/frappe/integrations/doctype/dropbox_settings/dropbox_settings.py @@ -15,17 +15,15 @@ from frappe.integration_broker.doctype.integration_service.integration_service i ignore_list = [".DS_Store"] class DropboxSettings(IntegrationService): - scheduled_jobs = [ - { - "daily_long": [ - "frappe.integrations.dropbox_integration.take_backups_daily" - ], - "weekly_long": [ - "frappe.integrations.dropbox_integration.take_backups_weekly" - ] - } - ] - + scheduler_events = { + "daily_long": [ + "frappe.integrations.dropbox_integration.take_backups_daily" + ], + "weekly_long": [ + "frappe.integrations.dropbox_integration.take_backups_weekly" + ] + } + def validate(self): if not self.flags.ignore_mandatory: self.validate_dropbox_credentails() @@ -49,10 +47,10 @@ class DropboxSettings(IntegrationService): from dropbox import session except: raise Exception(_("Please install dropbox python module")) - + if not (self.app_access_key or self.app_secret_key): raise Exception(_("Please set Dropbox access keys in your site config")) - + sess = session.DropboxSession(self.app_access_key, self.get_password(fieldname="app_secret_key", raise_exception=False), "app_folder") @@ -64,13 +62,13 @@ def get_service_details():
Steps to enable dropbox backup service:
    -
  1. Create a dropbox app then get App Key and App Secret, +
  2. Create a dropbox app then get App Key and App Secret, https://www.dropbox.com/developers/apps

  3. -
  4. Setup credentials on Dropbox Settings doctype. +
  5. Setup credentials on Dropbox Settings doctype. Click on top right corner @@ -109,7 +107,7 @@ def get_dropbox_authorize_url(): "dropbox_access_key": request_token.key, "dropbox_access_secret": request_token.secret }) - + doc.save(ignore_permissions=False) return_address = get_request_site_address(True) \ diff --git a/frappe/integrations/doctype/razorpay_settings/razorpay_settings.py b/frappe/integrations/doctype/razorpay_settings/razorpay_settings.py index ca2aa4e7e5..c7b9549cab 100644 --- a/frappe/integrations/doctype/razorpay_settings/razorpay_settings.py +++ b/frappe/integrations/doctype/razorpay_settings/razorpay_settings.py @@ -61,28 +61,26 @@ For razorpay payment status is Authorized class RazorpaySettings(IntegrationService): service_name = "Razorpay" supported_currencies = ["INR"] - - scheduled_jobs = [ - { - "all": [ - "frappe.integrations.razorpay.capture_payment" - ] - } - ] - + + scheduler_events = { + "all": [ + "frappe.integrations.razorpay.capture_payment" + ] + } + def validate(self): if not self.flags.ignore_mandatory: self.validate_razorpay_credentails() - + def on_update(self): pass - + def enable(self): call_hook_method('payment_gateway_enabled', gateway='Razorpay') if not self.flags.ignore_mandatory: self.validate_razorpay_credentails() - + def validate_razorpay_credentails(self): if self.api_key and self.api_secret: try: @@ -90,14 +88,14 @@ class RazorpaySettings(IntegrationService): auth=(self.api_key, self.get_password(fieldname="api_secret", raise_exception=False))) except Exception: frappe.throw(_("Seems API Key or API Secret is wrong !!!")) - + def validate_transaction_currency(self, currency): if currency not in self.supported_currencies: frappe.throw(_("Please select another payment method. {0} does not support transactions in currency '{1}'").format(self.service_name, currency)) def get_payment_url(self, **kwargs): return get_url("./integrations/razorpay_checkout?{0}".format(urllib.urlencode(kwargs))) - + def create_request(self, data): self.data = frappe._dict(data) @@ -168,7 +166,7 @@ class RazorpaySettings(IntegrationService): "redirect_to": redirect_url, "status": status } - + def get_settings(self): return frappe._dict({ "api_key": self.api_key, @@ -212,7 +210,7 @@ def get_checkout_url(**kwargs): _("Looks like something is wrong with this site's Razorpay configuration. Don't worry! No payment has been made."), success=False, http_status_code=frappe.ValidationError.http_status_code) - + @frappe.whitelist() def get_service_details(): @@ -220,13 +218,13 @@ def get_service_details():

    Steps to configure Service

      -
    1. Get Razorpay api credentials by login to: +
    2. Get Razorpay api credentials by login to: https://razorpay.com/

    3. -
    4. Setup credentials on Razorpay Settings doctype. +
    5. Setup credentials on Razorpay Settings doctype. Click on top right corner diff --git a/frappe/model/base_document.py b/frappe/model/base_document.py index 1346f19250..630d76e6de 100644 --- a/frappe/model/base_document.py +++ b/frappe/model/base_document.py @@ -22,6 +22,8 @@ def get_controller(doctype): :param doctype: DocType name as string.""" from frappe.model.document import Document + global _classes + if not doctype in _classes: module_name, custom = frappe.db.get_value("DocType", doctype, ["module", "custom"]) \ or ["Core", False] diff --git a/frappe/sessions.py b/frappe/sessions.py index 56033dece0..a4a4fc2245 100644 --- a/frappe/sessions.py +++ b/frappe/sessions.py @@ -48,7 +48,8 @@ def clear_cache(user=None): def clear_global_cache(): frappe.model.meta.clear_cache() frappe.cache().delete_value(["app_hooks", "installed_apps", - "app_modules", "module_app", "notification_config", 'system_settings']) + "app_modules", "module_app", "notification_config", 'system_settings' + 'scheduler_events']) frappe.setup_module_map() def clear_sessions(user=None, keep_current=False, device=None): diff --git a/frappe/utils/scheduler.py b/frappe/utils/scheduler.py index d42ce14185..cb6502b899 100755 --- a/frappe/utils/scheduler.py +++ b/frappe/utils/scheduler.py @@ -23,6 +23,7 @@ from frappe.limits import has_expired from frappe.utils.data import get_datetime, now_datetime from frappe.core.doctype.user.user import STANDARD_USERS from frappe.installer import update_site_config +from frappe.integration_broker.doctype.integration_service.integration_service import get_integration_service_events DATETIME_FORMAT = '%Y-%m-%d %H:%M:%S' @@ -142,7 +143,11 @@ def trigger(site, event, queued_jobs=(), now=False): if not queued_jobs and not now: queued_jobs = get_jobs(site=site, queue=queue) - for handler in frappe.get_hooks("scheduler_events").get(event, []): + events = get_scheduler_events(event) + if not events: + return + + for handler in events: if not now: if handler not in queued_jobs: enqueue(handler, queue, timeout, event) @@ -152,6 +157,20 @@ def trigger(site, event, queued_jobs=(), now=False): if frappe.flags.in_test: frappe.flags.ran_schedulers.append(event) +def get_scheduler_events(event): + '''Get scheduler events from hooks and integrations''' + scheduler_events = frappe.cache().get_value('scheduler_events') + if not scheduler_events: + scheduler_events = frappe.get_hooks("scheduler_events") + integration_events = get_integration_service_events() + for key, handlers in integration_events: + scheduler_events.setdefault(key, []).extend(handlers) + frappe.cache().set_value('scheduler_events', scheduler_events) + + return scheduler_events.get(event) or [] + + + def log(method, message=None): """log error in patch_log""" message = frappe.utils.cstr(message) + "\n" if message else ""