GitHub PullRequestReviewCommentEvent at 2014-12-19 12:30:42
Repository: odoo
Actor: tde-banana-odoo
Payload: {"action":"created","comment":{"url":"https://api.github.com/repos/odoo/odoo/pulls/comments/22102206","id":22102206,"diff_hunk":"@@ -0,0 +1,306 @@\n+# -*- coding: utf-8 -*-\n+import base64\n+import re\n+import time\n+\n+from openerp import api, fields, models\n+from openerp.tools.translate import _\n+from itertools import groupby\n+\n+class print_provider(models.Model):\n+    \"\"\" Print Provider Base Model. Each specific provider can extend the model by adding\n+        its own fields, using the provider_name (provider field) as a prefix for the new\n+        fields and method.\n+    \"\"\"\n+\n+    _name = 'print.provider'\n+    _rec_name = 'name'\n+    _description = 'Postal Provider'\n+\n+\n+    @api.model\n+    def _get_providers(self):\n+        return []\n+\n+    # --------------------------------------------------\n+    # MODEL FIELDS\n+    # --------------------------------------------------\n+    name = fields.Char(\"Name\", required=True)\n+    environment = fields.Selection([('test', 'Test'),('production', 'Production')], \"Environment\", default='test')\n+    provider = fields.Selection(selection='_get_providers', string='Provider', required=True)\n+    balance = fields.Float(\"Credit\", digits=(16,2))\n+\n+\n+    # --------------------------------------------------\n+    # METHOD to be redefined in the provider implemenation\n+    # --------------------------------------------------\n+    @api.one\n+    def update_account_data(self):\n+        \"\"\" Update the provider account data. Requires a fetch to the provider server. \"\"\"\n+        if hasattr(self, '%s_update_account_data' % self.provider):\n+            return getattr(self, '%s_update_account_data' % self.provider)()\n+\n+    @api.one\n+    def check_configuration(self):\n+        \"\"\" Check if the credentials of the current provider are filled. If not, raise a warning. \"\"\"\n+        if hasattr(self, '%s_check_configuration' % self.provider):\n+            return getattr(self, '%s_check_configuration' % self.provider)()\n+\n+\n+class print_order(models.Model):\n+    \"\"\" Print Order Model. Each specific provider can extend the model by adding\n+        its own fields, using the same convertion of the print.provider model.\n+    \"\"\"\n+\n+    _name = 'print.order'\n+    _rec_name = 'id'\n+    _description = 'Postal Order'\n+    _order = 'send_date desc'\n+\n+    @api.model\n+    def _default_currency(self):\n+        return self.env.user.company_id.currency_id\n+\n+    @api.model\n+    def _default_print_provider(self):\n+        return self.env['ir.values'].get_default('print.order', 'provider_id')\n+\n+    # --------------------------------------------------\n+    # MODEL FIELDS\n+    # --------------------------------------------------\n+    create_date = fields.Datetime('Creation Date', readonly=True)\n+    send_date = fields.Datetime('Sending Date', default=False, readonly=True)\n+    currency_id = fields.Many2one('res.currency', 'Currency', required=True, default=_default_currency, readonly=True, states={'draft':[('readonly',False)]})\n+    user_id = fields.Many2one('res.users', 'Author', default=lambda self: self.env.user, readonly=True)\n+    provider_id = fields.Many2one('print.provider', 'Print Provider', required=True, default=_default_print_provider, readonly=True, states={'draft':[('readonly',False)]})\n+\n+    ink = fields.Selection([('BW', 'Black & White'),('CL', 'Colour')], \"Ink\", default='BW', states={'sent':[('readonly',True)]})\n+    paper = fields.Integer(\"Paper Weight\", default=80, readonly=True)\n+    res_id = fields.Integer('Object ID')\n+    res_model = fields.Char('Model Name')\n+\n+    attachment_id = fields.Many2one('ir.attachment', 'PDF', states={'sent':[('readonly',True)]}, domain=[('mimetype', '=', 'application/pdf')])\n+    nbr_pages = fields.Integer(\"Number of Pages\", readonly=True, default=0)\n+    price = fields.Float(\"Cost to Deliver\", digits=(16,2), readonly=True, default=0.0)\n+\n+    error_message = fields.Text('Error Message', readonly=True)\n+\n+    state = fields.Selection([\n+            ('draft', 'Draft'),\n+            ('ready_to_send', 'Ready'),\n+            ('sent', 'Sent'),\n+            ('error', 'Failed'),\n+        ], string='Status', default='draft', readonly=True, required=True)\n+\n+    # duplicate partner infos to keep trace of where the documents was sent\n+    partner_id = fields.Many2one('res.partner', 'Recipient partner', states={'sent':[('readonly',True)]})\n+    partner_name = fields.Char('Name', required=True, states={'sent':[('readonly',True)]})\n+    partner_street = fields.Char('Street', required=True, states={'sent':[('readonly',True)]})\n+    partner_street2 = fields.Char('Street2', states={'sent':[('readonly',True)]})\n+    partner_state_id = fields.Many2one(\"res.country.state\", 'State', states={'sent':[('readonly',True)]})\n+    partner_zip = fields.Char('Zip', required=True, states={'sent':[('readonly',True)]})\n+    partner_city = fields.Char('City', required=True, states={'sent':[('readonly',True)]})\n+    partner_country_id = fields.Many2one('res.country', 'Country', required=True, states={'sent':[('readonly',True)]})\n+\n+\n+    # --------------------------------------------------\n+    # Methods\n+    # --------------------------------------------------\n+    @api.model\n+    def _count_pages_pdf(self, bin_pdf):\n+        \"\"\" Count the number of pages of the given pdf file.\n+            :param bin_pdf : binary content of the pdf file\n+        \"\"\"\n+        pages = 0\n+        for match in re.compile(r\"/Count\\s+(\\d+)\").finditer(bin_pdf):\n+            pages = int(match.group(1))\n+        return pages\n+\n+    @api.multi\n+    def _generate_attachment(self):\n+        \"\"\" For the given recordset, compute the number of page in the attachment.\n+            If no attachment, one will be generated with the res_model/res_id\n+        \"\"\"\n+        Attachment = self.env['ir.attachment']\n+        ReportXml = self.env['ir.actions.report.xml']\n+        Report = self.pool['report'] # old api, see below\n+        pages = {}\n+        for record in self:\n+            if not record.attachment_id:\n+                if record.res_model and record.res_id:\n+                    # check if a report exists for current res_model\n+                    report = ReportXml.search([('model', '=', record.res_model)], limit=1)\n+                    if report:\n+                        object_to_print = self.env[record.res_model].browse(record.res_id)\n+\n+                        # get the binary pdf content\n+                        # Call the v7 version without context (!important) to avoid \"'update' not supported on frozendict\".\n+                        # TODO : when report.py in v8, change this call (and test it !)\n+                        bin_pdf = Report.get_pdf(self._cr, self._uid, [record.res_id], report.report_name)\n+\n+                        # compute the name of the new attachment\n+                        filename = False\n+                        if report.attachment:\n+                            filename = eval(report.attachment, {'object': object_to_print, 'time': time})\n+                        if not filename:\n+                            filename = '%s-%s' % (record.res_model.replace(\".\", \"_\"),record.res_id)\n+\n+                        # create the new ir_attachment\n+                        attachment_value = {\n+                            'name': filename,\n+                            'res_name': filename,\n+                            'res_model': record.res_model,\n+                            'res_id': record.res_id,\n+                            'datas': base64.b64encode(bin_pdf),\n+                            'datas_fname': filename+'.pdf',\n+                        }\n+                        new_attachment = Attachment.create(attachment_value)\n+\n+                        # add the new attachment to the print order\n+                        record.write({\n+                            'nbr_pages' : self._count_pages_pdf(bin_pdf),\n+                            'attachment_id' : new_attachment.id\n+                        })\n+                    else:\n+                        # no ir.actions.report.xml found for res_model\n+                        record.write({\n+                            'state' : 'error',\n+                            'error_message' : _('The document you want to print and send is not printable. There is no report action (ir.actions.report.xml) for the model %s.') % (record.res_model,)\n+                        })\n+                else:\n+                    # error : not attachament can be generate, no attach_id or no res_model/res_id\n+                    record.write({\n+                        'state' : 'error',\n+                        'error_message' : _('The document has no associated PDF : you have to give select an Attachment file, or set up the Object ID and Model Name fields.')\n+                    })\n+            else:\n+                # avoid to recompute the number of page each time for the attachment\n+                nbr_pages = pages.get(record.attachment_id.id)\n+                if not nbr_pages:\n+                    nbr_pages = self._count_pages_pdf(record.attachment_id.datas.decode('base64'))\n+                    pages[record.attachment_id.id] = nbr_pages\n+                record.write({\n+                    'nbr_pages' : nbr_pages\n+                })\n+\n+\n+    @api.multi\n+    def _prepare_printing(self):\n+        \"\"\" Prepare the orders for delivery. It executes the operations to put\n+            them into the 'ready' state (or 'error' if something wrong happens).\n+            /!\\ Self must be print.order having the same provider, to stay the optimized.\n+            To allow optimizations in the provider implementation, the orders\n+            are grouped by provider.\n+        \"\"\"\n+        # generate PDF for the recordset\n+        self._generate_attachment()\n+\n+        # call provider implementation\n+        provider_name = self[0].provider_id.provider\n+        if hasattr(self, '_%s_prepare_printing' % provider_name):\n+                getattr(self, '_%s_prepare_printing' % provider_name)()\n+\n+    @api.multi\n+    def _deliver_printing(self):\n+        \"\"\" Send the orders for delivery to the Provider. It executes the operations to put\n+            them into the 'sent' state (or 'error' if something wrong happens).\n+            /!\\ Self must be print.order having the same provider, to stay the optimized.\n+        \"\"\"\n+        # call provider implementation\n+        provider_name = self[0].provider_id.provider\n+        if hasattr(self, '_%s_deliver_printing' % provider_name):\n+            getattr(self, '_%s_deliver_printing' % provider_name)()\n+\n+    @api.multi\n+    def _validate_printing(self):\n+        \"\"\" For the given recordset, apply the action on the printable objects when the sending\n+            is correctly done. This call the 'print_validate_sending' method of the printable object.\n+            This method group the PO by res_model to optimize the browse.\n+        \"\"\"\n+        # group the PO by res_model\n+        group_by_res_model = dict((k, list(g)) for k, g in groupby(self, lambda record : record.res_model))\n+        for model in group_by_res_model.keys():\n+            if model: # res_model is optional field\n+                if hasattr(self.env[model], 'print_validate_sending'):\n+                    # take only the correctly sent\n+                    objects = self.env[model].browse([rec.res_id for rec in group_by_res_model[model] if rec.state == 'sent'])\n+                    objects.print_validate_sending()\n+\n+    @api.model\n+    def process_order_queue(self, order_ids=None):\n+        \"\"\" Immediately send the queue, or the list of given order_ids.\n+            If the sending failed, it send a mail_message to the author of the print order, and the PO state\n+            is set to 'error'. If sending is successful, the state will be 'sent'.\n+            This method is called by the sendnow wizard, but also by the ir_cron.\n+            :param order_ids : optinal list of order ids\n+        \"\"\"\n+        # find ids if not given, and only keep the not sent orders\n+        if not order_ids:\n+            orders = self.search([('state', 'not in', ['sent'])])\n+        else:\n+            orders = self.browse(order_ids)\n+            orders.filtered(lambda r: not r.state in ['sent'])\n+\n+        # Treat the Print Orders, grouped by provider\n+        group_by_provider = dict((k, list(g)) for k, g in groupby(orders, lambda record : record.provider_id.id))\n+        for provider_id in group_by_provider.keys():\n+            current_orders = self.browse([rec.id for rec in group_by_provider[provider_id]])\n+            current_orders._prepare_printing()\n+            current_orders._deliver_printing()\n+\n+        # Validate the sending, on all the treated Print Orders\n+        orders._validate_printing()\n+\n+        # error controll : built the list of user to notify\n+        # create a dict 'user_to_notify' where\n+        #   key = user_id\n+        #   value = list of tuple (order_id, error_message) for all order not sent correctly\n+        user_to_notify = {}\n+        for record in orders:\n+            if record.state == 'error':\n+                if not record.user_id.id in user_to_notify:\n+                    user_to_notify[record.user_id.id] = []\n+                user_to_notify[record.user_id.id].append((record.id, record.error_message))\n+\n+        # send a message to the author of the failed print orders\n+        Mail_message = self.env['mail.message']\n+        for user in self.env['res.users'].browse(user_to_notify.keys()):\n+            errors = [\"   %s      |  %s\" % (code, msg) for code, msg in  user_to_notify[user.id]]\n+            body = _(\"Dear %s,<br/> \\","path":"addons/print/models/models.py","position":269,"original_position":269,"commit_id":"e311b760cd56962c4e73aacece934ca6d4cf1d5d","original_commit_id":"e311b760cd56962c4e73aacece934ca6d4cf1d5d","user":{"login":"tde-banana-odoo","id":7501424,"avatar_url":"https://avatars.githubusercontent.com/u/7501424?v=3","gravatar_id":"","url":"https://api.github.com/users/tde-banana-odoo","html_url":"https://github.com/tde-banana-odoo","followers_url":"https://api.github.com/users/tde-banana-odoo/followers","following_url":"https://api.github.com/users/tde-banana-odoo/following{/other_user}","gists_url":"https://api.github.com/users/tde-banana-odoo/gists{/gist_id}","starred_url":"https://api.github.com/users/tde-banana-odoo/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/tde-banana-odoo/subscriptions","organizations_url":"https://api.github.com/users/tde-banana-odoo/orgs","repos_url":"https://api.github.com/users/tde-banana-odoo/repos","events_url":"https://api.github.com/users/tde-banana-odoo/events{/privacy}","received_events_url":"https://api.github.com/users/tde-banana-odoo/received_events","type":"User","site_admin":false},"body":"Maybe define and use an email.template ? This way people will be able to modify them.","created_at":"2014-12-19T12:30:42Z","updated_at":"2014-12-19T12:30:42Z","html_url":"https://github.com/odoo/odoo/pull/3050#discussion_r22102206","pull_request_url":"https://api.github.com/repos/odoo/odoo/pulls/3050","_links":{"self":{"href":"https://api.github.com/repos/odoo/odoo/pulls/comments/22102206"},"html":{"href":"https://github.com/odoo/odoo/pull/3050#discussion_r22102206"},"pull_request":{"href":"https://api.github.com/repos/odoo/odoo/pulls/3050"}}},"pull_request":{"url":"https://api.github.com/repos/odoo/odoo/pulls/3050","id":22645928,"html_url":"https://github.com/odoo/odoo/pull/3050","diff_url":"https://github.com/odoo/odoo/pull/3050.diff","patch_url":"https://github.com/odoo/odoo/pull/3050.patch","issue_url":"https://api.github.com/repos/odoo/odoo/issues/3050","number":3050,"state":"open","locked":false,"title":"[ADD] print, print_docsaway, print_sale : module to print and send docum...","user":{"login":"jem-odoo","id":7429139,"avatar_url":"https://avatars.githubusercontent.com/u/7429139?v=3","gravatar_id":"","url":"https://api.github.com/users/jem-odoo","html_url":"https://github.com/jem-odoo","followers_url":"https://api.github.com/users/jem-odoo/followers","following_url":"https://api.github.com/users/jem-odoo/following{/other_user}","gists_url":"https://api.github.com/users/jem-odoo/gists{/gist_id}","starred_url":"https://api.github.com/users/jem-odoo/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jem-odoo/subscriptions","organizations_url":"https://api.github.com/users/jem-odoo/orgs","repos_url":"https://api.github.com/users/jem-odoo/repos","events_url":"https://api.github.com/users/jem-odoo/events{/privacy}","received_events_url":"https://api.github.com/users/jem-odoo/received_events","type":"User","site_admin":false},"body":"...ents by post, implementation for docsaway webservices.\r\n\r\nPrint and send documents by post\r\nprint : provider base module to print account.invoice\r\nprint_sale : print and send sale.order\r\nprint_docsaway : implementation of docsAway Provider","created_at":"2014-10-13T13:48:19Z","updated_at":"2014-12-19T12:30:42Z","closed_at":null,"merged_at":null,"merge_commit_sha":"b8a8e73f2f02bb0b0f1fe120823ece831a5ef85f","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/odoo/odoo/pulls/3050/commits","review_comments_url":"https://api.github.com/repos/odoo/odoo/pulls/3050/comments","review_comment_url":"https://api.github.com/repos/odoo/odoo/pulls/comments/{number}","comments_url":"https://api.github.com/repos/odoo/odoo/issues/3050/comments","statuses_url":"https://api.github.com/repos/odoo/odoo/statuses/e311b760cd56962c4e73aacece934ca6d4cf1d5d","head":{"label":"odoo-dev:master-docsaway-jem","ref":"master-docsaway-jem","sha":"e311b760cd56962c4e73aacece934ca6d4cf1d5d","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":"2014-12-16T17:15:21Z","pushed_at":"2014-12-19T12:30:20Z","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":960469,"stargazers_count":37,"watchers_count":37,"language":"Python","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":16,"mirror_url":null,"open_issues_count":4,"forks":16,"open_issues":4,"watchers":37,"default_branch":"master"}},"base":{"label":"odoo:master","ref":"master","sha":"e06adc7e08e76e0414194d166cfd09e883779f51","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":"2014-12-19T11:00:42Z","pushed_at":"2014-12-19T12:29:43Z","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":953326,"stargazers_count":1701,"watchers_count":1701,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":1360,"mirror_url":null,"open_issues_count":1631,"forks":1360,"open_issues":1631,"watchers":1701,"default_branch":"8.0"}},"_links":{"self":{"href":"https://api.github.com/repos/odoo/odoo/pulls/3050"},"html":{"href":"https://github.com/odoo/odoo/pull/3050"},"issue":{"href":"https://api.github.com/repos/odoo/odoo/issues/3050"},"comments":{"href":"https://api.github.com/repos/odoo/odoo/issues/3050/comments"},"review_comments":{"href":"https://api.github.com/repos/odoo/odoo/pulls/3050/comments"},"review_comment":{"href":"https://api.github.com/repos/odoo/odoo/pulls/comments/{number}"},"commits":{"href":"https://api.github.com/repos/odoo/odoo/pulls/3050/commits"},"statuses":{"href":"https://api.github.com/repos/odoo/odoo/statuses/e311b760cd56962c4e73aacece934ca6d4cf1d5d"}}}}