{"action":"created","comment":{"url":"https://api.github.com/repos/odoo/odoo/pulls/comments/26931142","id":26931142,"diff_hunk":"@@ -0,0 +1,347 @@\n+# -*- coding: utf-8 -*-\n+import logging\n+import time\n+from datetime import datetime, timedelta\n+\n+import openerp\n+from openerp import api, fields, models\n+from openerp import SUPERUSER_ID\n+from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT\n+\n+_logger = logging.getLogger(__name__)\n+\n+DATE_RANGE_FUNCTION = {\n+    'minutes': lambda interval: timedelta(minutes=interval),\n+    'hour': lambda interval: timedelta(hours=interval),\n+    'day': lambda interval: timedelta(days=interval),\n+    'month': lambda interval: timedelta(months=interval),\n+    False: lambda interval: timedelta(0),\n+}\n+\n+\n+def get_datetime(date_str):\n+    '''Return a datetime from a date string or a datetime string'''\n+    # complete date time if date_str contains only a date\n+    if ' ' not in date_str:\n+        date_str = date_str + \" 00:00:00\"\n+    return datetime.strptime(date_str, DEFAULT_SERVER_DATETIME_FORMAT)\n+\n+\n+class BaseActionRule(models.Model):\n+    \"\"\" Base Action Rules \"\"\"\n+\n+    _name = 'base.action.rule'\n+    _description = 'Action Rules'\n+    _order = 'sequence'\n+\n+    name = fields.Char('Rule Name', required=True)\n+    model_id = fields.Many2one(\n+        'ir.model', string='Related Document Model',\n+        required=True, domain=[('osv_memory', '=', False)])\n+    model = fields.Char(related='model_id.model')\n+    create_date = fields.Datetime(string='Create Date', readonly=True)\n+    active = fields.Boolean(\n+        default=True,\n+        help=\"When unchecked, the rule is hidden and will not be executed.\")\n+    sequence = fields.Integer(help=\"Gives the sequence order when displaying a list of rules.\")\n+    kind = fields.Selection([\n+        ('on_create', 'On Creation'),\n+        ('on_write', 'On Update'),\n+        ('on_create_or_write', 'On Creation & Update'),\n+        ('on_time', 'Based on Timed Condition')],\n+        string='When to Run')\n+    trg_date_id = fields.Many2one(\n+        'ir.model.fields', string='Trigger Date',\n+        help=\"When should the condition be triggered. If present, will be checked by the scheduler. If empty, will be checked at creation and update.\",\n+        domain=\"[('model_id', '=', model_id), ('ttype', 'in', ('date', 'datetime'))]\")\n+    trg_date_range = fields.Integer(\n+        'Delay after trigger date',\n+        help=\"Delay after the trigger date.\"\n+        \"You can put a negative number if you need as delay before the\"\n+        \"trigger date, like sending a reminder 15 minutes before a meeting.\")\n+    trg_date_range_type = fields.Selection([\n+        ('minutes', 'Minutes'), ('hour', 'Hours'),\n+        ('day', 'Days'), ('month', 'Months')],\n+        'Delay type', default='day')\n+    trg_date_calendar_id = fields.Many2one(\n+        'resource.calendar', string='Use Calendar',\n+        help='When calculating a day-based timed condition, it is possible to use a calendar to compute the date based on working days.',\n+        ondelete='set null')\n+    act_user_id = fields.Many2one('res.users', string='Set Responsible')\n+    act_followers = fields.Many2many(\"res.partner\", string=\"Add Followers\")\n+    server_action_ids = fields.Many2many(\n+        'ir.actions.server', string='Server Actions',\n+        domain=\"[('model_id', '=', model_id)]\",\n+        help=\"Examples: email reminders, call object service, etc.\")\n+    filter_pre_id = fields.Many2one(\n+        'ir.filters', string='Before Update Filter',\n+        ondelete='restrict', domain=\"[('model_id', '=', model_id.model)]\",\n+        help=\"If present, this condition must be satisfied before the update of the record.\")\n+    filter_pre_domain = fields.Char(string='Before Update Domain', help=\"If present, this condition must be satisfied before the update of the record.\")\n+    filter_id = fields.Many2one(\n+        'ir.filters', string='Filter',\n+        ondelete='restrict', domain=\"[('model_id', '=', model_id.model)]\",\n+        help=\"If present, this condition must be satisfied before executing the action rule.\")\n+    filter_domain = fields.Char(string='Domain', help=\"If present, this condition must be satisfied before executing the action rule.\")\n+    last_run = fields.Datetime(string='Last Run', readonly=True, copy=False)\n+\n+    @api.onchange('kind')\n+    def _onchange_kind(self):\n+        if self.kind in ['on_create', 'on_create_or_write']:\n+            self.filter_pre_id = False\n+            self.trg_date_id = False\n+            self.trg_date_range = False\n+            self.trg_date_range_type = False\n+        elif self.kind in ['on_write', 'on_create_or_write']:\n+            self.trg_date_id = False\n+            self.trg_date_range = False\n+            self.trg_date_range_type = False\n+        elif self.kind == 'on_time':\n+            self.filter_pre_id = False\n+\n+    @api.onchange('filter_pre_id')\n+    def _onchange_filter_pre_id(self):\n+        self.filter_pre_domain = self.env['ir.filters'].browse(self.filter_pre_id.id).domain\n+\n+    @api.onchange('filter_id')\n+    def _onchange_filter_id(self):\n+        self.filter_domain = self.env['ir.filters'].browse(self.filter_id.id).domain\n+\n+    @api.model\n+    def _filter(self, action, action_filter, record_ids, domain=False):\n+        \"\"\" Filter the list record_ids that satisfy the domain or the action filter. \"\"\"\n+        if record_ids and (domain is not False or action_filter):\n+            if domain is not False:\n+                new_domain = [('id', 'in', record_ids)] + eval(domain)\n+                ctx = dict(self.env.context)\n+            elif action_filter:\n+                assert action.model == action_filter.model_id, \"Filter model different from action rule model\"\n+                new_domain = [('id', 'in', record_ids)] + eval(action_filter.domain)\n+                ctx = dict(self.env.context)\n+                ctx.update(dict(action_filter.env.context))\n+            record_ids = self.with_context(ctx).env[action.model].search(new_domain).ids\n+        return record_ids\n+\n+    @api.model\n+    def _process(self, action, record_ids):\n+        \"\"\" process the given action on the records \"\"\"\n+        Model = self.env[action.model_id.model]\n+        # modify records\n+        values = {}\n+        if 'date_action_last' in Model._fields:\n+            values['date_action_last'] = time.strftime(DEFAULT_SERVER_DATETIME_FORMAT)\n+        if action.act_user_id and 'user_id' in Model._fields:\n+            values['user_id'] = action.act_user_id.id\n+        if values:\n+            Model.browse(record_ids).write(values)\n+\n+        if action.act_followers and hasattr(Model, 'message_subscribe'):\n+            follower_ids = map(int, action.act_followers)\n+            Model.message_subscribe(record_ids, follower_ids)\n+\n+        # execute server actions\n+        if action.server_action_ids:\n+            server_action_ids = map(int, action.server_action_ids)\n+            for record in Model.browse(record_ids):\n+                ActionServer = self.env['ir.actions.server'].with_context(dict(self.env.context, active_model=Model._name, active_ids=[record.id], active_id=record.id)).browse(server_action_ids)\n+                ActionServer.run()\n+\n+        return True\n+\n+    @api.v7\n+    def _register_hook(self, cr, ids=None):\n+        \"\"\" Wrap the methods `create` and `write` of the models specified by\n+            the rules given by `ids` (or all existing rules if `ids` is `None`.)\n+        \"\"\"\n+        #\n+        # Note: the patched methods create and write must be defined inside\n+        # another function, otherwise their closure may be wrong. For instance,\n+        # the function create refers to the outer variable 'create', which you\n+        # expect to be bound to create itself. But that expectation is wrong if\n+        # create is defined inside a loop; in that case, the variable 'create'\n+        # is bound to the last function defined by the loop.\n+        #\n+\n+        def make_create():\n+            \"\"\" instanciate a create method that processes action rules \"\"\"\n+            def create(self, cr, uid, vals, context=None, **kwargs):\n+                # avoid loops or cascading actions\n+                if context and context.get('action'):\n+                    return create.origin(self, cr, uid, vals, context=context)\n+\n+                # call original method with a modified context\n+                context = dict(context or {}, action=True)\n+                new_id = create.origin(self, cr, uid, vals, context=context, **kwargs)\n+\n+                # as it is a new record, we do not consider the actions that have a prefilter\n+                action_model = self.pool.get('base.action.rule')\n+                action_dom = [('model', '=', self._name),\n+                              ('kind', 'in', ['on_create', 'on_create_or_write'])]\n+                action_ids = action_model.search(cr, uid, action_dom, context=context)\n+\n+                # check postconditions, and execute actions on the records that satisfy them\n+                for action in action_model.browse(cr, uid, action_ids, context=context):\n+                    if action_model._filter(cr, uid, action, action.filter_id, [new_id], domain=action.filter_domain, context=context):\n+                        action_model._process(cr, uid, action, [new_id], context=context)\n+                return new_id\n+\n+            return create\n+\n+        def make_write():\n+            \"\"\" instanciate a write method that processes action rules \"\"\"\n+            def write(self, cr, uid, ids, vals, context=None, **kwargs):\n+                # avoid loops or cascading actions\n+                if context and context.get('action'):\n+                    return write.origin(self, cr, uid, ids, vals, context=context)\n+\n+                # modify context\n+                context = dict(context or {}, action=True)\n+                ids = [ids] if isinstance(ids, (int, long, str)) else ids\n+\n+                # retrieve the action rules to possibly execute\n+                action_model = self.pool.get('base.action.rule')\n+                action_dom = [('model', '=', self._name),\n+                              ('kind', 'in', ['on_write', 'on_create_or_write'])]\n+                action_ids = action_model.search(cr, uid, action_dom, context=context)\n+                actions = action_model.browse(cr, uid, action_ids, context=context)\n+\n+                # check preconditions\n+                pre_ids = {}\n+                for action in actions:\n+                    pre_ids[action] = action_model._filter(cr, uid, action, action.filter_pre_id, ids, domain=action.filter_pre_domain, context=context)\n+\n+                # call original method\n+                write.origin(self, cr, uid, ids, vals, context=context, **kwargs)\n+\n+                # check postconditions, and execute actions on the records that satisfy them\n+                for action in actions:\n+                    post_ids = action_model._filter(cr, uid, action, action.filter_id, pre_ids[action], domain=action.filter_domain, context=context)\n+                    if post_ids:\n+                        action_model._process(cr, uid, action, post_ids, context=context)\n+                return True\n+\n+            return write\n+\n+        updated = False\n+        if ids is None:\n+            ids = self.search(cr, SUPERUSER_ID, [])\n+        for action_rule in self.browse(cr, SUPERUSER_ID, ids):\n+            model = action_rule.model_id.model\n+            model_obj = self.pool.get(model)\n+            if model_obj and not hasattr(model_obj, 'base_action_ruled'):\n+                # monkey-patch methods create and write\n+                model_obj._patch_method('create', make_create())\n+                model_obj._patch_method('write', make_write())\n+                model_obj.base_action_ruled = True\n+                updated = True\n+\n+        return updated\n+\n+    @api.v8\n+    def _register_hook(self):\n+        return self._model._register_hook(self.env.cr, self.ids)\n+\n+    @api.model\n+    def _update_cron(self):\n+        try:\n+            Cron = self.env['ir.model.data'].get_object('BaseActionRule', 'ir_cron_crm_action')\n+        except ValueError:\n+            return False\n+\n+        return Cron.toggle(model=self._name, domain=[('kind', '=', 'on_time')])\n+\n+    @api.model\n+    def create(self, vals):\n+        res_id = super(BaseActionRule, self).create(vals)\n+        if res_id._register_hook():\n+            openerp.modules.registry.RegistryManager.signal_registry_change(self.env.cr.dbname)\n+        self._update_cron()\n+        return res_id\n+\n+    @api.multi\n+    def write(self, vals):\n+        super(BaseActionRule, self).write(vals)\n+        if self._register_hook():\n+            openerp.modules.registry.RegistryManager.signal_registry_change(self.env.cr.dbname)\n+        self._update_cron()\n+        return True\n+\n+    @api.multi\n+    def unlink(self):\n+        res = super(BaseActionRule, self).unlink()\n+        self._update_cron()\n+        return res\n+\n+    @api.onchange('model_id')\n+    def _onchange_model_id(self):\n+        if self.model_id:\n+            self.model = self.env['ir.model'].browse(self.model_id.id).model","path":"addons/base_action_rule/models/base_action_rule.py","position":null,"original_position":278,"commit_id":"1587f11d41f3c23adad158bc1ceac3bec009943b","original_commit_id":"349c3d11b1340ddabfc36a2dee56f0a82703c6e2","user":{"login":"htr-odoo","id":7599690,"avatar_url":"https://avatars.githubusercontent.com/u/7599690?v=3","gravatar_id":"","url":"https://api.github.com/users/htr-odoo","html_url":"https://github.com/htr-odoo","followers_url":"https://api.github.com/users/htr-odoo/followers","following_url":"https://api.github.com/users/htr-odoo/following{/other_user}","gists_url":"https://api.github.com/users/htr-odoo/gists{/gist_id}","starred_url":"https://api.github.com/users/htr-odoo/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/htr-odoo/subscriptions","organizations_url":"https://api.github.com/users/htr-odoo/orgs","repos_url":"https://api.github.com/users/htr-odoo/repos","events_url":"https://api.github.com/users/htr-odoo/events{/privacy}","received_events_url":"https://api.github.com/users/htr-odoo/received_events","type":"User","site_admin":false},"body":"Done.","created_at":"2015-03-23T12:10:37Z","updated_at":"2015-03-23T12:10:37Z","html_url":"https://github.com/odoo/odoo/pull/5837#discussion_r26931142","pull_request_url":"https://api.github.com/repos/odoo/odoo/pulls/5837","_links":{"self":{"href":"https://api.github.com/repos/odoo/odoo/pulls/comments/26931142"},"html":{"href":"https://github.com/odoo/odoo/pull/5837#discussion_r26931142"},"pull_request":{"href":"https://api.github.com/repos/odoo/odoo/pulls/5837"}}},"pull_request":{"url":"https://api.github.com/repos/odoo/odoo/pulls/5837","id":31498549,"html_url":"https://github.com/odoo/odoo/pull/5837","diff_url":"https://github.com/odoo/odoo/pull/5837.diff","patch_url":"https://github.com/odoo/odoo/pull/5837.patch","issue_url":"https://api.github.com/repos/odoo/odoo/issues/5837","number":5837,"state":"open","locked":false,"title":"[IMP] base_action_rule : Convert to new api","user":{"login":"ara-odoo","id":7600008,"avatar_url":"https://avatars.githubusercontent.com/u/7600008?v=3","gravatar_id":"","url":"https://api.github.com/users/ara-odoo","html_url":"https://github.com/ara-odoo","followers_url":"https://api.github.com/users/ara-odoo/followers","following_url":"https://api.github.com/users/ara-odoo/following{/other_user}","gists_url":"https://api.github.com/users/ara-odoo/gists{/gist_id}","starred_url":"https://api.github.com/users/ara-odoo/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ara-odoo/subscriptions","organizations_url":"https://api.github.com/users/ara-odoo/orgs","repos_url":"https://api.github.com/users/ara-odoo/repos","events_url":"https://api.github.com/users/ara-odoo/events{/privacy}","received_events_url":"https://api.github.com/users/ara-odoo/received_events","type":"User","site_admin":false},"body":"Task:https://www.odoo.com/web#id=12030&view_type=form&model=project.task&action=327\r\nPad: https://pad.odoo.com/p/r.j21wAI25Ei3COXst","created_at":"2015-03-19T06:32:30Z","updated_at":"2015-03-23T12:10:37Z","closed_at":null,"merged_at":null,"merge_commit_sha":"a82acaa12b0e43156a5c1fad5a8dd379e0c4367c","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/odoo/odoo/pulls/5837/commits","review_comments_url":"https://api.github.com/repos/odoo/odoo/pulls/5837/comments","review_comment_url":"https://api.github.com/repos/odoo/odoo/pulls/comments{/number}","comments_url":"https://api.github.com/repos/odoo/odoo/issues/5837/comments","statuses_url":"https://api.github.com/repos/odoo/odoo/statuses/1587f11d41f3c23adad158bc1ceac3bec009943b","head":{"label":"odoo-dev:master-base_action_rule-newapi-htr","ref":"master-base_action_rule-newapi-htr","sha":"1587f11d41f3c23adad158bc1ceac3bec009943b","user":{"login":"odoo-dev","id":7466976,"avatar_url":"https://avatars.githubusercontent.com/u/7466976?v=3","gravatar_id":"","url":"https://api.github.com/users/odoo-dev","html_url":"https://github.com/odoo-dev","followers_url":"https://api.github.com/users/odoo-dev/followers","following_url":"https://api.github.com/users/odoo-dev/following{/other_user}","gists_url":"https://api.github.com/users/odoo-dev/gists{/gist_id}","starred_url":"https://api.github.com/users/odoo-dev/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/odoo-dev/subscriptions","organizations_url":"https://api.github.com/users/odoo-dev/orgs","repos_url":"https://api.github.com/users/odoo-dev/repos","events_url":"https://api.github.com/users/odoo-dev/events{/privacy}","received_events_url":"https://api.github.com/users/odoo-dev/received_events","type":"Organization","site_admin":false},"repo":{"id":19853934,"name":"odoo","full_name":"odoo-dev/odoo","owner":{"login":"odoo-dev","id":7466976,"avatar_url":"https://avatars.githubusercontent.com/u/7466976?v=3","gravatar_id":"","url":"https://api.github.com/users/odoo-dev","html_url":"https://github.com/odoo-dev","followers_url":"https://api.github.com/users/odoo-dev/followers","following_url":"https://api.github.com/users/odoo-dev/following{/other_user}","gists_url":"https://api.github.com/users/odoo-dev/gists{/gist_id}","starred_url":"https://api.github.com/users/odoo-dev/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/odoo-dev/subscriptions","organizations_url":"https://api.github.com/users/odoo-dev/orgs","repos_url":"https://api.github.com/users/odoo-dev/repos","events_url":"https://api.github.com/users/odoo-dev/events{/privacy}","received_events_url":"https://api.github.com/users/odoo-dev/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/odoo-dev/odoo","description":"RD Dev Repository","fork":true,"url":"https://api.github.com/repos/odoo-dev/odoo","forks_url":"https://api.github.com/repos/odoo-dev/odoo/forks","keys_url":"https://api.github.com/repos/odoo-dev/odoo/keys{/key_id}","collaborators_url":"https://api.github.com/repos/odoo-dev/odoo/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/odoo-dev/odoo/teams","hooks_url":"https://api.github.com/repos/odoo-dev/odoo/hooks","issue_events_url":"https://api.github.com/repos/odoo-dev/odoo/issues/events{/number}","events_url":"https://api.github.com/repos/odoo-dev/odoo/events","assignees_url":"https://api.github.com/repos/odoo-dev/odoo/assignees{/user}","branches_url":"https://api.github.com/repos/odoo-dev/odoo/branches{/branch}","tags_url":"https://api.github.com/repos/odoo-dev/odoo/tags","blobs_url":"https://api.github.com/repos/odoo-dev/odoo/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/odoo-dev/odoo/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/odoo-dev/odoo/git/refs{/sha}","trees_url":"https://api.github.com/repos/odoo-dev/odoo/git/trees{/sha}","statuses_url":"https://api.github.com/repos/odoo-dev/odoo/statuses/{sha}","languages_url":"https://api.github.com/repos/odoo-dev/odoo/languages","stargazers_url":"https://api.github.com/repos/odoo-dev/odoo/stargazers","contributors_url":"https://api.github.com/repos/odoo-dev/odoo/contributors","subscribers_url":"https://api.github.com/repos/odoo-dev/odoo/subscribers","subscription_url":"https://api.github.com/repos/odoo-dev/odoo/subscription","commits_url":"https://api.github.com/repos/odoo-dev/odoo/commits{/sha}","git_commits_url":"https://api.github.com/repos/odoo-dev/odoo/git/commits{/sha}","comments_url":"https://api.github.com/repos/odoo-dev/odoo/comments{/number}","issue_comment_url":"https://api.github.com/repos/odoo-dev/odoo/issues/comments{/number}","contents_url":"https://api.github.com/repos/odoo-dev/odoo/contents/{+path}","compare_url":"https://api.github.com/repos/odoo-dev/odoo/compare/{base}...{head}","merges_url":"https://api.github.com/repos/odoo-dev/odoo/merges","archive_url":"https://api.github.com/repos/odoo-dev/odoo/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/odoo-dev/odoo/downloads","issues_url":"https://api.github.com/repos/odoo-dev/odoo/issues{/number}","pulls_url":"https://api.github.com/repos/odoo-dev/odoo/pulls{/number}","milestones_url":"https://api.github.com/repos/odoo-dev/odoo/milestones{/number}","notifications_url":"https://api.github.com/repos/odoo-dev/odoo/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/odoo-dev/odoo/labels{/name}","releases_url":"https://api.github.com/repos/odoo-dev/odoo/releases{/id}","created_at":"2014-05-16T11:16:19Z","updated_at":"2015-03-17T10:53:55Z","pushed_at":"2015-03-23T12:08:18Z","git_url":"git://github.com/odoo-dev/odoo.git","ssh_url":"git@github.com:odoo-dev/odoo.git","clone_url":"https://github.com/odoo-dev/odoo.git","svn_url":"https://github.com/odoo-dev/odoo","homepage":"https://www.odoo.com","size":1084570,"stargazers_count":45,"watchers_count":45,"language":null,"has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":18,"mirror_url":null,"open_issues_count":11,"forks":18,"open_issues":11,"watchers":45,"default_branch":"master"}},"base":{"label":"odoo:master","ref":"master","sha":"573341c906e56d05a0c6ba001a82af40055bae63","user":{"login":"odoo","id":6368483,"avatar_url":"https://avatars.githubusercontent.com/u/6368483?v=3","gravatar_id":"","url":"https://api.github.com/users/odoo","html_url":"https://github.com/odoo","followers_url":"https://api.github.com/users/odoo/followers","following_url":"https://api.github.com/users/odoo/following{/other_user}","gists_url":"https://api.github.com/users/odoo/gists{/gist_id}","starred_url":"https://api.github.com/users/odoo/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/odoo/subscriptions","organizations_url":"https://api.github.com/users/odoo/orgs","repos_url":"https://api.github.com/users/odoo/repos","events_url":"https://api.github.com/users/odoo/events{/privacy}","received_events_url":"https://api.github.com/users/odoo/received_events","type":"Organization","site_admin":false},"repo":{"id":19745004,"name":"odoo","full_name":"odoo/odoo","owner":{"login":"odoo","id":6368483,"avatar_url":"https://avatars.githubusercontent.com/u/6368483?v=3","gravatar_id":"","url":"https://api.github.com/users/odoo","html_url":"https://github.com/odoo","followers_url":"https://api.github.com/users/odoo/followers","following_url":"https://api.github.com/users/odoo/following{/other_user}","gists_url":"https://api.github.com/users/odoo/gists{/gist_id}","starred_url":"https://api.github.com/users/odoo/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/odoo/subscriptions","organizations_url":"https://api.github.com/users/odoo/orgs","repos_url":"https://api.github.com/users/odoo/repos","events_url":"https://api.github.com/users/odoo/events{/privacy}","received_events_url":"https://api.github.com/users/odoo/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/odoo/odoo","description":"Odoo (formerly OpenERP). Open Source Apps To Grow Your Business.","fork":false,"url":"https://api.github.com/repos/odoo/odoo","forks_url":"https://api.github.com/repos/odoo/odoo/forks","keys_url":"https://api.github.com/repos/odoo/odoo/keys{/key_id}","collaborators_url":"https://api.github.com/repos/odoo/odoo/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/odoo/odoo/teams","hooks_url":"https://api.github.com/repos/odoo/odoo/hooks","issue_events_url":"https://api.github.com/repos/odoo/odoo/issues/events{/number}","events_url":"https://api.github.com/repos/odoo/odoo/events","assignees_url":"https://api.github.com/repos/odoo/odoo/assignees{/user}","branches_url":"https://api.github.com/repos/odoo/odoo/branches{/branch}","tags_url":"https://api.github.com/repos/odoo/odoo/tags","blobs_url":"https://api.github.com/repos/odoo/odoo/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/odoo/odoo/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/odoo/odoo/git/refs{/sha}","trees_url":"https://api.github.com/repos/odoo/odoo/git/trees{/sha}","statuses_url":"https://api.github.com/repos/odoo/odoo/statuses/{sha}","languages_url":"https://api.github.com/repos/odoo/odoo/languages","stargazers_url":"https://api.github.com/repos/odoo/odoo/stargazers","contributors_url":"https://api.github.com/repos/odoo/odoo/contributors","subscribers_url":"https://api.github.com/repos/odoo/odoo/subscribers","subscription_url":"https://api.github.com/repos/odoo/odoo/subscription","commits_url":"https://api.github.com/repos/odoo/odoo/commits{/sha}","git_commits_url":"https://api.github.com/repos/odoo/odoo/git/commits{/sha}","comments_url":"https://api.github.com/repos/odoo/odoo/comments{/number}","issue_comment_url":"https://api.github.com/repos/odoo/odoo/issues/comments{/number}","contents_url":"https://api.github.com/repos/odoo/odoo/contents/{+path}","compare_url":"https://api.github.com/repos/odoo/odoo/compare/{base}...{head}","merges_url":"https://api.github.com/repos/odoo/odoo/merges","archive_url":"https://api.github.com/repos/odoo/odoo/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/odoo/odoo/downloads","issues_url":"https://api.github.com/repos/odoo/odoo/issues{/number}","pulls_url":"https://api.github.com/repos/odoo/odoo/pulls{/number}","milestones_url":"https://api.github.com/repos/odoo/odoo/milestones{/number}","notifications_url":"https://api.github.com/repos/odoo/odoo/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/odoo/odoo/labels{/name}","releases_url":"https://api.github.com/repos/odoo/odoo/releases{/id}","created_at":"2014-05-13T15:38:58Z","updated_at":"2015-03-23T12:07:04Z","pushed_at":"2015-03-23T12:08:20Z","git_url":"git://github.com/odoo/odoo.git","ssh_url":"git@github.com:odoo/odoo.git","clone_url":"https://github.com/odoo/odoo.git","svn_url":"https://github.com/odoo/odoo","homepage":"https://www.odoo.com","size":1121336,"stargazers_count":2305,"watchers_count":2305,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":1773,"mirror_url":null,"open_issues_count":2091,"forks":1773,"open_issues":2091,"watchers":2305,"default_branch":"8.0"}},"_links":{"self":{"href":"https://api.github.com/repos/odoo/odoo/pulls/5837"},"html":{"href":"https://github.com/odoo/odoo/pull/5837"},"issue":{"href":"https://api.github.com/repos/odoo/odoo/issues/5837"},"comments":{"href":"https://api.github.com/repos/odoo/odoo/issues/5837/comments"},"review_comments":{"href":"https://api.github.com/repos/odoo/odoo/pulls/5837/comments"},"review_comment":{"href":"https://api.github.com/repos/odoo/odoo/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/odoo/odoo/pulls/5837/commits"},"statuses":{"href":"https://api.github.com/repos/odoo/odoo/statuses/1587f11d41f3c23adad158bc1ceac3bec009943b"}}}}