def remove(self, ids, **kwargs): """ Removes a web-based image attachment if it is used by no view (template) Returns a dict mapping attachments which would not be removed (if any) mapped to the views preventing their removal """ Attachment = attachments_to_remove = request.env['ir.attachment'] Views = request.env['ir.ui.view'] # views blocking removal of the attachment removal_blocked_by = {} for attachment in Attachment.browse(ids): # in-document URLs are html-escaped, a straight search will not # find them url = tools.html_escape(attachment.local_url) views = Views.search([ "|", ('arch_db', 'like', '"%s"' % url), ('arch_db', 'like', "'%s'" % url) ]) if views: removal_blocked_by[attachment.id] = views.read(['name']) else: attachments_to_remove += attachment if attachments_to_remove: attachments_to_remove.unlink() return removal_blocked_by
def _check_contents(self, values): mimetype = values['mimetype'] = self._compute_mimetype(values) needs_escape = 'htm' in mimetype or '/ht' in mimetype # hta, html, xhtml, etc. if needs_escape and not self.env.user._is_admin(): if 'datas' in values: values['datas'] = html_escape(values['datas'].decode('base64')).encode('base64') else: values['mimetype'] = 'text/plain' return values
def report_download(self, data, token): """This function is used by 'qwebactionmanager.js' in order to trigger the download of a pdf/controller report. :param data: a javascript array JSON.stringified containg report internal url ([0]) and type [1] :returns: Response with a filetoken cookie and an attachment header """ requestcontent = json.loads(data) url, type = requestcontent[0], requestcontent[1] try: if type == 'qweb-pdf': reportname = url.split('/report/pdf/')[1].split('?')[0] docids = None if '/' in reportname: reportname, docids = reportname.split('/') if docids: # Generic report: response = self.report_routes(reportname, docids=docids, converter='pdf') else: # Particular report: data = url_decode(url.split('?')[1]).items() # decoding the args represented in JSON response = self.report_routes(reportname, converter='pdf', **dict(data)) report = request.env['report']._get_report_from_name(reportname) filename = "%s.%s" % (report.name, "pdf") if docids: ids = [int(x) for x in docids.split(",")] obj = request.env[report.model].browse(ids) if report.print_report_name and not len(obj) > 1: report_name = safe_eval(report.print_report_name, {'object': obj, 'time': time}) filename = "%s.%s" % (report_name, "pdf") response.headers.add('Content-Disposition', content_disposition(filename)) response.set_cookie('fileToken', token) return response elif type == 'controller': reqheaders = Headers(request.httprequest.headers) response = Client(request.httprequest.app, BaseResponse).get(url, headers=reqheaders, follow_redirects=True) response.set_cookie('fileToken', token) return response else: return except Exception as e: se = _serialize_exception(e) error = { 'code': 200, 'message': "Odoo Server Error", 'data': se } return request.make_response(html_escape(json.dumps(error)))
def report(self, output_format, report_name, token, report_id=False, **kw): uid = request.session.uid coa = request.env['account.open.chart'].sudo(uid).browse(report_id) try: if output_format == 'pdf': response = request.make_response( coa.with_context(active_id=report_id).get_pdf(report_id), headers=[ ('Content-Type', 'application/pdf'), ('Content-Disposition', 'attachment; filename=coa_report.pdf;') ] ) response.set_cookie('fileToken', token) return response except Exception as e: se = serialize_exception(e) error = { 'code': 200, 'message': 'Odoo Server Error', 'data': se } return request.make_response(html_escape(json.dumps(error)))
def report_download(self, data, token): """This function is used by 'qwebactionmanager.js' in order to trigger the download of a py3o/controller report. :param data: a javascript array JSON.stringified containg report internal url ([0]) and type [1] :returns: Response with a filetoken cookie and an attachment header """ requestcontent = json.loads(data) url, report_type = requestcontent[0], requestcontent[1] if 'py3o' not in report_type: return super(ReportController, self).report_download(data, token) try: reportname = url.split('/report/py3o/')[1].split('?')[0] docids = None if '/' in reportname: reportname, docids = reportname.split('/') if docids: # Generic report: response = self.report_routes( reportname, docids=docids, converter='py3o') else: # Particular report: # decoding the args represented in JSON data = list(url_decode(url.split('?')[1]).items()) response = self.report_routes( reportname, converter='py3o', **dict(data)) response.set_cookie('fileToken', token) return response except Exception as e: exc_info = sys.exc_info() se = traceback.format_exception(*exc_info) error = { 'code': 200, 'message': "Odoo Server Error", 'data': se } return request.make_response(html_escape(json.dumps(error)))
def download_report_xlsx(self, model, options, output_format, token, report_name, **kw): uid = request.session.uid report_obj = request.env[model].with_user(uid) options = json.loads(options) try: if output_format == 'xlsx': response = request.make_response( None, headers=[('Content-Type', 'application/vnd.ms-excel'), ('Content-Disposition', content_disposition(report_name + '.xlsx'))]) report_obj.get_xlsx_report(options, response) response.set_cookie('fileToken', token) return response except Exception as e: error = { 'code': 200, 'message': 'Odoo Server Error', 'data': str(e) } return request.make_response(html_escape(json.dumps(error)))
def partner_desinterested(self, comment=False, contacted=False, spam=False): if contacted: message = '<p>%s</p>' % _('I am not interested by this lead. I contacted the lead.') else: message = '<p>%s</p>' % _('I am not interested by this lead. I have not contacted the lead.') partner_ids = self.env['res.partner'].search( [('id', 'child_of', self.env.user.partner_id.commercial_partner_id.id)]) self.message_unsubscribe(partner_ids=partner_ids.ids) if comment: message += '<p>%s</p>' % html_escape(comment) self.message_post(body=message) values = { 'partner_assigned_id': False, } if spam: tag_spam = self.env.ref('website_crm_partner_assign.tag_portal_lead_is_spam', False) if tag_spam and tag_spam not in self.tag_ids: values['tag_ids'] = [(4, tag_spam.id, False)] if partner_ids: values['partner_declined_ids'] = [(4, p, 0) for p in partner_ids.ids] self.sudo().write(values)
def _get_lead_days(self, product): """Returns the cumulative delay and its description encountered by a procurement going through the rules in `self`. :param product: the product of the procurement :type product: :class:`~odoo.addons.product.models.product.ProductProduct` :return: the cumulative delay and cumulative delay's description :rtype: tuple """ delay = sum( self.filtered(lambda r: r.action in ['pull', 'pull_push']).mapped( 'delay')) if self.env.context.get('bypass_delay_description'): delay_description = "" else: delay_description = ''.join([ '<tr><td>%s %s</td><td class="text-right">+ %d %s</td></tr>' % (_('Delay on'), html_escape( rule.name), rule.delay, _('day(s)')) for rule in self if rule.action in ['pull', 'pull_push'] and rule.delay ]) return delay, delay_description
def report_download(self, data, token, context=None): """ print reports on report_download """ user = request.env.user if not user.has_group(SECURITY_GROUP) \ or not user.company_id.printnode_enabled or not user.printnode_enabled: return super(ReportControllerProxy, self).report_download(data, token, context) requestcontent = json.loads(data) if requestcontent[1] not in PDF + RAW: return super(ReportControllerProxy, self).report_download(data, token, context) ext = requestcontent[1].split('-')[1] report_name, object_ids = requestcontent[0].\ split('/report/{}/'.format(ext))[1].split('?')[0].split('/') report_id = request.env['ir.actions.report']._get_report_from_name(report_name) printer_id = user._get_report_printer(report_id.id) if not printer_id: return super(ReportControllerProxy, self).report_download(data, token, context) try: ids = [int(x) for x in object_ids.split(',')] obj = request.env[report_id.model].browse(ids) super(ReportControllerProxy, self).printnode_print(printer_id, report_id, obj) except Exception as e: return request.make_response(html_escape(json.dumps({ 'code': 200, 'message': 'Odoo Server Error', 'data': _serialize_exception(e), }))) index = user.company_id.im_a_teapot raise PrintNodeSuccess(['', _('Sent to PrintNode')][index])
def followup(self, partners, token, **kw): uid = request.session.uid try: context_obj = request.env['account.report.context.followup'] partners = request.env['res.partner'].browse([int(i) for i in partners.split(',')]) context_ids = context_obj.search([('partner_id', 'in', partners.ids), ('create_uid', '=', uid)]) response = request.make_response( context_ids.with_context(public=True).get_pdf(log=True), headers=[ ('Content-Type', 'application/pdf'), ('Content-Disposition', 'attachment; filename=payment_reminder.pdf;') ] ) response.set_cookie('fileToken', token) return response except Exception, e: se = _serialize_exception(e) error = { 'code': 200, 'message': 'Odoo Server Error', 'data': se } return request.make_response(html_escape(json.dumps(error)))
def report_download(self, data, token, context=None): """This function is used by 'qwebactionmanager.js' in order to trigger the download of a py3o/controller report. :param data: a javascript array JSON.stringified containg report internal url ([0]) and type [1] :returns: Response with a filetoken cookie and an attachment header """ requestcontent = json.loads(data) url, report_type = requestcontent[0], requestcontent[1] if "py3o" not in report_type: return super(ReportController, self).report_download(data, token, context) try: reportname = url.split("/report/py3o/")[1].split("?")[0] docids = None if "/" in reportname: reportname, docids = reportname.split("/") if docids: # Generic report: response = self.report_routes(reportname, docids=docids, converter="py3o") else: # Particular report: # decoding the args represented in JSON data = list(url_decode(url.split("?")[1]).items()) response = self.report_routes(reportname, converter="py3o", **dict(data)) response.set_cookie("fileToken", token) return response except Exception as e: se = _serialize_exception(e) error = {"code": 200, "message": "Odoo Server Error", "data": se} return request.make_response(html_escape(json.dumps(error)))
def get_statement_report_custom(self, model, **kw): if not request.env.user.partner_id.allow_print_statement_portal: return request.redirect("/") if kw.get('report_type') == 'excel': uid = request.session.uid account_report_model = request.env['account.report'] options = self._get_statement_report_options_custom(**kw) cids = request.httprequest.cookies.get( 'cids', str(request.website.company_id.id or request.env.user.company_id.id)) allowed_company_ids = [int(cid) for cid in cids.split(',')] report_obj = request.env[model].with_user(uid).with_context( allowed_company_ids=allowed_company_ids).sudo() report_name = report_obj.get_report_filename(options) try: response = request.make_response( report_obj.get_xlsx(options), headers=[ ('Content-Type', account_report_model.get_export_mime_type('xlsx')), ('Content-Disposition', content_disposition(report_name + '.xlsx')) ]) return response except Exception as e: se = _serialize_exception(e) error = { 'code': 200, 'message': 'Odoo Server Error', 'data': se } return request.make_response(html_escape(json.dumps(error))) else: return super(CustomerPortal, self).get_statement_report_custom(model, **kw)
def get_report(self, model, options, output_format, token, financial_id=None, **kw): uid = request.session.uid account_report_model = request.env['account.report'] options = json.loads(options) cids = request.httprequest.cookies.get( 'cids', str(request.env.user.company_id.id)) allowed_company_ids = [int(cid) for cid in cids.split(',')] report_obj = request.env[model].with_user(uid).with_context( allowed_company_ids=allowed_company_ids) if financial_id and financial_id != 'null': report_obj = report_obj.browse(int(financial_id)) report_name = report_obj.get_report_filename(options) try: response = None if output_format == 'xlsx': response = request.make_response( None, headers=[ ('Content-Type', account_report_model.get_export_mime_type('xlsx')), ('Content-Disposition', content_disposition(report_name + '.xlsx')) ]) response.stream.write(report_obj.advanced_get_xlsx(options)) response.set_cookie('fileToken', token) return response except Exception as e: se = _serialize_exception(e) error = {'code': 200, 'message': 'Odoo Server Error', 'data': se} return request.make_response(html_escape(json.dumps(error)))
def report(self, output_format, report_name, token, report_id=False, **kw): uid = request.session.uid domain = [('create_uid', '=', uid)] stock_traceability = request.env['stock.traceability.report'].sudo(uid).search(domain, limit=1) line_data = json.loads(kw['data']) try: if output_format == 'pdf': response = request.make_response( stock_traceability.with_context(active_id=report_id).get_pdf(line_data), headers=[ ('Content-Type', 'application/pdf'), ('Content-Disposition', 'attachment; filename=' + 'stock_traceability' + '.pdf;') ] ) response.set_cookie('fileToken', token) return response except Exception as e: se = _serialize_exception(e) error = { 'code': 200, 'message': 'Odoo Server Error', 'data': se } return request.make_response(html_escape(json.dumps(error)))
def report(self, output_format, report_name, token, report_id=False, **kw): uid = request.session.uid domain = [('create_uid', '=', uid)] stock_traceability = request.env['stock.traceability.report'].sudo(uid).search(domain, limit=1) line_data = json.loads(kw['data']) try: if output_format == 'pdf': response = request.make_response( stock_traceability.with_context(active_id=report_id).get_pdf(line_data), headers=[ ('Content-Type', 'application/pdf'), ('Content-Disposition', 'attachment; filename=' + 'stock_traceability' + '.pdf;') ] ) response.set_cookie('fileToken', token) return response except Exception as e: se = _serialize_exception(e) error = { 'code': 200, 'message': 'QuikHR Server Error', 'data': se } return request.make_response(html_escape(json.dumps(error)))
def _format_error_message(self, error_title, errors): bullet_list_msg = ''.join('<li>%s</li>' % html_escape(msg) for msg in errors) return '%s<ul>%s</ul>' % (error_title, bullet_list_msg)
def _execute_command_lead(self, **kwargs): partner = self.env.user.partner_id key = kwargs['body'] channel_partners = self.env['mail.channel.partner'].search([ ('partner_id', '!=', partner.id), ('channel_id', '=', self.id)], limit=1 ) if key.strip() == '/lead': msg = self._define_command_lead()['help'] else: lead = self._convert_visitor_to_lead(partner, channel_partners, key) msg = _('Created a new lead: <a href="#" data-oe-id="%s" data-oe-model="crm.lead">%s</a>') % (lead.id, html_escape(lead.name)) self._send_transient_message(partner, msg)
def shape(self, module, filename, **kwargs): """ Returns a color-customized svg (background shape or illustration). """ svg = None if module == 'illustration': attachment = request.env['ir.attachment'].sudo().search( [('url', '=like', request.httprequest.path), ('public', '=', True)], limit=1) if not attachment: raise werkzeug.exceptions.NotFound() svg = b64decode(attachment.datas).decode('utf-8') else: shape_path = get_resource_path(module, 'static', 'shapes', filename) if not shape_path: raise werkzeug.exceptions.NotFound() with tools.file_open(shape_path, 'r') as file: svg = file.read() user_colors = [] for key, value in kwargs.items(): colorMatch = re.match('^c([1-5])$', key) if colorMatch: # Check that color is hex or rgb(a) to prevent arbitrary injection if not re.match( r'(?i)^#[0-9A-F]{6,8}$|^rgba?\(\d{1,3},\d{1,3},\d{1,3}(?:,[0-9.]{1,4})?\)$', value.replace(' ', '')): raise werkzeug.exceptions.BadRequest() user_colors.append( [tools.html_escape(value), colorMatch.group(1)]) elif key == 'flip': if value == 'x': svg = svg.replace('<svg ', '<svg style="transform: scaleX(-1);" ') elif value == 'y': svg = svg.replace('<svg ', '<svg style="transform: scaleY(-1)" ') elif value == 'xy': svg = svg.replace('<svg ', '<svg style="transform: scale(-1)" ') default_palette = { '1': '#3AADAA', '2': '#7C6576', '3': '#F6F6F6', '4': '#FFFFFF', '5': '#383E45', } color_mapping = { default_palette[palette_number]: color for color, palette_number in user_colors } # create a case-insensitive regex to match all the colors to replace, eg: '(?i)(#3AADAA)|(#7C6576)' regex = '(?i)%s' % '|'.join('(%s)' % color for color in color_mapping.keys()) def subber(match): key = match.group().upper() return color_mapping[key] if key in color_mapping else key svg = re.sub(regex, subber, svg) return request.make_response(svg, [ ('Content-type', 'image/svg+xml'), ('Cache-control', 'max-age=%s' % http.STATIC_CACHE_LONG), ])
def report(self, output_format, report_name, token, report_id=False, **kw): accounts_hierarchy_obj = request.env['accounts.hierarchy'].sudo( ).browse(report_id) try: if output_format == 'pdf': response = request.make_response( accounts_hierarchy_obj.with_context( active_id=report_id).get_pdf(), headers=[('Content-Type', 'application/pdf'), ('Content-Disposition', 'attachment; filename=' + 'accounts_hierarchy' + '.pdf;')]) response.set_cookie('fileToken', token) return response if output_format == "xls": wizard_obj = request.env['accounts.hierarchy'].sudo().browse( report_id) heading = request.env['res.company'].browse( wizard_obj.company_id.id).name lines = request.env['accounts.hierarchy'].with_context( print_mode=True, output_format=output_format).sudo().get_pdf_lines( report_id) if lines: if len(lines) > 65535: raise UserError( _('There are too many rows (%s rows, limit: 65535) to export as Excel 97-2003 (.xls) format.' ) % len(lines)) workbook = xlwt.Workbook() sheet = workbook.add_sheet('Chart of Account') normal = xlwt.easyxf( 'font: name Times New Roman ;align: horiz left;', num_format_str='#,##0.00') bold = xlwt.easyxf( 'font: name Times New Roman bold ;align: horiz left;', num_format_str='#,##0.00') head = xlwt.easyxf( 'font: name Times New Roman bold ;align: horiz centre, vert centre;', num_format_str='#,##0.00') if heading: sheet.write_merge( 0, 1, 0, 5, 'Chart of Account Hierarchy for ' + heading + '', bold) else: sheet.write_merge(0, 1, 0, 5, 'Chart of Account Hierarchy', head) sheet.write(3, 0, 'Code', bold) sheet.write(3, 1, 'Name', bold) sheet.write(3, 2, 'Type', bold) sheet.write(3, 3, 'Debit', bold) sheet.write(3, 4, 'Credit', bold) sheet.write(3, 5, 'Balance', bold) i = 4 for line in lines: sheet.write(i, 0, line['columns'][0] or '', normal) sheet.write(i, 1, line['columns'][1] or '', normal) sheet.write(i, 2, line['columns'][2] or '', normal) sheet.write(i, 3, html2plaintext(line['columns'][3]) or '0', normal) sheet.write(i, 4, html2plaintext(line['columns'][4]) or '0', normal) sheet.write(i, 5, html2plaintext(line['columns'][5]) or '0', normal) i += 1 fp = io.BytesIO() workbook.save(fp) data = fp.getvalue() fp.close() response = request.make_response( data, headers=[('Content-Type', 'application/vnd.ms-excel'), ('Content-Disposition', 'attachment; filename=coahiearchy.xls')], cookies={'fileToken': token}) return response except Exception as e: se = _serialize_exception(e) error = {'code': 200, 'message': 'Odoo Server Error', 'data': se} return request.make_response(html_escape(json.dumps(error)))
def report_download(self, data, context=None, token=None): # pylint: disable=unused-argument """This function is used by 'action_manager_report.js' in order to trigger the download of a pdf/controller report. :param data: a javascript array JSON.stringified containg report internal url ([0]) and type [1] :returns: Response with an attachment header """ requestcontent = json.loads(data) url, type_ = requestcontent[0], requestcontent[1] reportname = '???' try: if type_ in ['qweb-pdf', 'qweb-text']: converter = 'pdf' if type_ == 'qweb-pdf' else 'text' extension = 'pdf' if type_ == 'qweb-pdf' else 'txt' pattern = '/report/pdf/' if type_ == 'qweb-pdf' else '/report/text/' reportname = url.split(pattern)[1].split('?')[0] docids = None if '/' in reportname: reportname, docids = reportname.split('/') if docids: # Generic report: response = self.report_routes(reportname, docids=docids, converter=converter, context=context) else: # Particular report: data = url_parse(url).decode_query( cls=dict) # decoding the args represented in JSON if 'context' in data: context, data_context = json.loads( context or '{}'), json.loads(data.pop('context')) context = json.dumps({**context, **data_context}) response = self.report_routes(reportname, converter=converter, context=context, **data) report = request.env[ 'ir.actions.report']._get_report_from_name(reportname) filename = "%s.%s" % (report.name, extension) if docids: ids = [int(x) for x in docids.split(",")] obj = request.env[report.model].browse(ids) if report.print_report_name and not len(obj) > 1: report_name = safe_eval(report.print_report_name, { 'object': obj, 'time': time }) filename = "%s.%s" % (report_name, extension) response.headers.add('Content-Disposition', content_disposition(filename)) return response else: return except Exception as e: _logger.exception("Error while generating report %s", reportname) se = http.serialize_exception(e) error = {'code': 200, 'message': "Odoo Server Error", 'data': se} return request.make_response(html_escape(json.dumps(error)))
def apply_inheritance_specs(source, specs_tree, inherit_branding=False, pre_locate=lambda s: True): """ Apply an inheriting view (a descendant of the base view) Apply to a source architecture all the spec nodes (i.e. nodes describing where and what changes to apply to some parent architecture) given by an inheriting view. :param Element source: a parent architecture to modify :param Element specs_tree: a modifying architecture in an inheriting view :param bool inherit_branding: :param pre_locate: function that is executed before locating a node. This function receives an arch as argument. This is required by studio to properly handle group_ids. :return: a modified source where the specs are applied :rtype: Element """ # Queue of specification nodes (i.e. nodes describing where and # changes to apply to some parent architecture). specs = specs_tree if isinstance(specs_tree, list) else [specs_tree] def extract(spec): """ Utility function that locates a node given a specification, remove it from the source and returns it. """ if len(spec): raise ValueError( _("Invalid specification for moved nodes: %r", etree.tostring(spec, encoding='unicode'))) pre_locate(spec) to_extract = locate_node(source, spec) if to_extract is not None: remove_element(to_extract) return to_extract else: raise ValueError( _("Element %r cannot be located in parent view", etree.tostring(spec, encoding='unicode'))) while len(specs): spec = specs.pop(0) if isinstance(spec, SKIPPED_ELEMENT_TYPES): continue if spec.tag == 'data': specs += [c for c in spec] continue pre_locate(spec) node = locate_node(source, spec) if node is not None: pos = spec.get('position', 'inside') if pos == 'replace': mode = spec.get('mode', 'outer') if mode == "outer": for loc in spec.xpath(".//*[text()='$0']"): loc.text = '' loc.append(copy.deepcopy(node)) if node.getparent() is None: spec_content = None comment = None for content in spec: if content.tag is not etree.Comment: spec_content = content break else: comment = content source = copy.deepcopy(spec_content) # only keep the t-name of a template root node t_name = node.get('t-name') if t_name: source.set('t-name', t_name) if comment is not None: text = source.text source.text = None comment.tail = text source.insert(0, comment) else: replaced_node_tag = None for child in spec: if child.get('position') == 'move': child = extract(child) if inherit_branding and not replaced_node_tag and child.tag is not etree.Comment: # To make a correct branding, we need to # - know exactly which node has been replaced # - store it before anything else has altered the Tree # Do it exactly here :D child.set('meta-oe-xpath-replacing', node.tag) # We just store the replaced node tag on the first # child of the xpath replacing it replaced_node_tag = node.tag node.addprevious(child) node.getparent().remove(node) elif mode == "inner": # Replace the entire content of an element for child in node: node.remove(child) node.text = None for child in spec: node.append(copy.deepcopy(child)) node.text = spec.text else: raise ValueError( _("Invalid mode attribute:") + " '%s'" % mode) elif pos == 'attributes': for child in spec.getiterator('attribute'): attribute = child.get('name') value = child.text or '' if child.get('add') or child.get('remove'): assert not child.text separator = child.get('separator', ',') if separator == ' ': separator = None # squash spaces to_add = (s for s in ( s.strip() for s in child.get('add', '').split(separator)) if s) to_remove = { s.strip() for s in child.get('remove', '').split(separator) } values = ( s.strip() for s in node.get(attribute, '').split(separator)) value = (separator or ' ').join( itertools.chain( (v for v in values if v not in to_remove), to_add)) if value: node.set(attribute, value) elif attribute in node.attrib: del node.attrib[attribute] elif pos == 'inside': # add a sentinel element at the end, insert content of spec # before the sentinel, then remove the sentinel element sentinel = E.sentinel() node.append(sentinel) add_stripped_items_before(sentinel, spec, extract) remove_element(sentinel) elif pos == 'after': # add a sentinel element right after node, insert content of # spec before the sentinel, then remove the sentinel element sentinel = E.sentinel() node.addnext(sentinel) add_stripped_items_before(sentinel, spec, extract) remove_element(sentinel) elif pos == 'before': add_stripped_items_before(node, spec, extract) else: raise ValueError(_("Invalid position attribute: '%s'") % pos) else: attrs = ''.join([ ' %s="%s"' % (attr, html_escape(spec.get(attr))) for attr in spec.attrib if attr != 'position' ]) tag = "<%s%s>" % (spec.tag, attrs) raise ValueError( _("Element '%s' cannot be located in parent view", tag)) return source
def report(self, output_format, report_name, token, report_id=None, aging_filter_cmp=False, aging_due_filter_cmp=False, filter_local_currency=False, filter_original_currency=False, **kw): aging_filter_cmp = eval(aging_filter_cmp.capitalize()) aging_due_filter_cmp = eval(aging_due_filter_cmp.capitalize()) filter_local_currency = eval(filter_local_currency.capitalize()) filter_original_currency = eval(filter_original_currency.capitalize()) uid = request.session.uid domain = [('create_uid', '=', uid)] report_model = request.env[ 'account.report.context.common'].get_full_report_name_by_report_name( report_name) report_obj = request.env[report_model].sudo(uid) if report_name == 'financial_report': report_id = int(report_id) domain.append(('report_id', '=', report_id)) report_obj = report_obj.browse(report_id) context_obj = request.env[ 'account.report.context.common'].get_context_by_report_name( report_name) context_id = context_obj.sudo(uid).search(domain, limit=1) try: if output_format == 'xlsx': response = request.make_response( None, headers=[('Content-Type', 'application/vnd.ms-excel'), ('Content-Disposition', 'attachment; filename=' + report_obj.get_name() + '.xlsx;')]) context_id.with_context( aging_filter_cmp=aging_filter_cmp, aging_due_filter_cmp=aging_due_filter_cmp, filter_local_currency=filter_local_currency, filter_original_currency=filter_original_currency ).get_xlsx(response) response.set_cookie('fileToken', token) return response if output_format == 'pdf': response = request.make_response( context_id.with_context( aging_filter_cmp=aging_filter_cmp, aging_due_filter_cmp=aging_due_filter_cmp, filter_local_currency=filter_local_currency, filter_original_currency=filter_original_currency). get_pdf(), headers=[('Content-Type', 'application/pdf'), ('Content-Disposition', 'attachment; filename=' + report_obj.get_name() + '.pdf;')]) response.set_cookie('fileToken', token) return response if output_format == 'xml': content = context_id.with_context( aging_filter_cmp=aging_filter_cmp, aging_due_filter_cmp=aging_due_filter_cmp, filter_local_currency=filter_local_currency, filter_original_currency=filter_original_currency).get_xml( ) response = request.make_response( content, headers=[('Content-Type', 'application/vnd.sun.xml.writer'), ('Content-Disposition', 'attachment; filename=' + report_obj.get_name() + '.xml;'), ('Content-Length', len(content))]) response.set_cookie('fileToken', token) return response except Exception, e: se = _serialize_exception(e) error = {'code': 200, 'message': 'Odoo Server Error', 'data': se} return request.make_response(html_escape(json.dumps(error)))
def _l10n_es_edi_call_web_service_sign(self, invoices, info_list): company = invoices.company_id # All are sharing the same value, see '_get_batch_key'. csv_number = invoices.mapped('l10n_es_edi_csv')[0] # Set registration date invoices.filtered(lambda inv: not inv.l10n_es_registration_date).write( { 'l10n_es_registration_date': fields.Date.context_today(self), }) # === Call the web service === # Get connection data. l10n_es_edi_tax_agency = company.mapped('l10n_es_edi_tax_agency')[0] connection_vals = getattr( self, f'_l10n_es_edi_web_service_{l10n_es_edi_tax_agency}_vals')( invoices) header = { 'IDVersionSii': '1.1', 'Titular': { 'NombreRazon': company.name[:120], 'NIF': company.vat[2:], }, 'TipoComunicacion': 'A1' if csv_number else 'A0', } session = requests.Session() session.cert = company.l10n_es_edi_certificate_id session.mount('https://', PatchedHTTPAdapter()) transport = Transport(operation_timeout=60, timeout=60, session=session) client = zeep.Client(connection_vals['url'], transport=transport) if invoices[0].is_sale_document(): service_name = 'SuministroFactEmitidas' else: service_name = 'SuministroFactRecibidas' if company.l10n_es_edi_test_env and not connection_vals.get( 'test_url'): service_name += 'Pruebas' # Establish the connection. serv = client.bind('siiService', service_name) if company.l10n_es_edi_test_env and connection_vals.get('test_url'): serv._binding_options['address'] = connection_vals['test_url'] msg = '' try: if invoices[0].is_sale_document(): res = serv.SuministroLRFacturasEmitidas(header, info_list) else: res = serv.SuministroLRFacturasRecibidas(header, info_list) except requests.exceptions.SSLError as error: msg = _("The SSL certificate could not be validated.") except zeep.exceptions.Error as error: msg = _("Networking error:\n%s") % error except Exception as error: msg = str(error) finally: if msg: return { inv: { 'error': msg, 'blocking_level': 'warning', } for inv in invoices } # Process response. if not res or not res.RespuestaLinea: return { inv: { 'error': _("The web service is not responding"), 'blocking_level': 'warning', } for inv in invoices } resp_state = res["EstadoEnvio"] l10n_es_edi_csv = res['CSV'] if resp_state == 'Correcto': invoices.write({'l10n_es_edi_csv': l10n_es_edi_csv}) return {inv: {'success': True} for inv in invoices} results = {} for respl in res.RespuestaLinea: invoice_number = respl.IDFactura.NumSerieFacturaEmisor # Retrieve the corresponding invoice. # Note: ref can be the same for different partners but there is no enough information on the response # to match the partner. # Note: Invoices are batched per move_type. if invoices[0].is_sale_document(): inv = invoices.filtered( lambda x: x.name[:60] == invoice_number) else: # 'ref' can be the same for different partners. candidates = invoices.filtered( lambda x: x.ref[:60] == invoice_number) if len(candidates) >= 1: respl_partner_info = respl.IDFactura.IDEmisorFactura inv = None for candidate in candidates: partner_info = self._l10n_es_edi_get_partner_info( candidate.commercial_partner_id) if partner_info.get('NIF') and partner_info[ 'NIF'] == respl_partner_info.NIF: inv = candidate break if partner_info.get('IDOtro') and all( getattr(respl_partner_info.IDOtro, k) == v for k, v in partner_info['IDOtro'].items()): inv = candidate break if not inv: # This case shouldn't happen and means there is something wrong in this code. However, we can't # raise anything since the document has already been approved by the government. The result # will only be a badly logged message into the chatter so, not a big deal. inv = candidates[0] else: inv = candidates resp_line_state = respl.EstadoRegistro if resp_line_state in ('Correcto', 'AceptadoConErrores'): inv.l10n_es_edi_csv = l10n_es_edi_csv results[inv] = {'success': True} if resp_line_state == 'AceptadoConErrores': inv.message_post( body=_("This was accepted with errors: ") + html_escape(respl.DescripcionErrorRegistro)) elif respl.RegistroDuplicado: results[inv] = {'success': True} inv.message_post(body=_( "We saw that this invoice was sent correctly before, but we did not treat " "the response. Make sure it is not because of a wrong configuration." )) else: results[inv] = { 'error': _("[%s] %s", respl.CodigoErrorRegistro, respl.DescripcionErrorRegistro), 'blocking_level': 'error', } return results
def get_report(self, model, options, output_format, token, financial_id=None, **kw): uid = request.session.uid report_obj = request.env[model].sudo(uid) options = json.loads(options) if financial_id and financial_id != 'null': report_obj = report_obj.browse(int(financial_id)) report_name = report_obj.get_report_filename(options) try: if output_format == 'xlsx': response = request.make_response( None, headers=[('Content-Type', 'application/vnd.ms-excel'), ('Content-Disposition', content_disposition(report_name + '.xlsx'))]) report_obj.get_xlsx(options, response) if output_format == 'pdf': response = request.make_response( report_obj.get_pdf(options), headers=[('Content-Type', 'application/pdf'), ('Content-Disposition', content_disposition(report_name + '.pdf'))]) if output_format == 'xml': content = report_obj.get_xml(options) response = request.make_response( content, headers=[('Content-Type', 'application/vnd.sun.xml.writer'), ('Content-Disposition', content_disposition(report_name + '.xml')), ('Content-Length', len(content))]) if output_format == 'xaf': content = report_obj.get_xaf(options) response = request.make_response( content, headers=[('Content-Type', 'application/vnd.sun.xml.writer'), ('Content-Disposition', content_disposition(report_name + '.xaf')), ('Content-Length', len(content))]) if output_format == 'txt': content = report_obj.get_txt(options) response = request.make_response( content, headers=[('Content-Type', 'text/plain'), ('Content-Disposition', content_disposition(report_name + '.txt')), ('Content-Length', len(content))]) if output_format == 'csv': content = report_obj.get_csv(options) response = request.make_response( content, headers=[('Content-Type', 'text/csv'), ('Content-Disposition', content_disposition(report_name + '.csv')), ('Content-Length', len(content))]) if output_format == 'zip': content = report_obj._get_zip(options) response = request.make_response( content, headers=[ ('Content-Type', 'application/zip'), ('Content-Disposition', content_disposition(report_name + '.zip')), ]) # Adding direct_passthrough to the response and giving it a file # as content means that we will stream the content of the file to the user # Which will prevent having the whole file in memory response.direct_passthrough = True response.set_cookie('fileToken', token) return response except Exception as e: se = _serialize_exception(e) error = {'code': 200, 'message': 'Odoo Server Error', 'data': se} return request.make_response(html_escape(json.dumps(error)))
def get_report(self, model, options, output_format, token, financial_id=None, **kw): uid = request.session.uid account_report_model = request.env['account.report'] options = json.loads(options) report_obj = request.env[model].with_user(uid) if not options.get('multi_company'): cids = request.httprequest.cookies.get( 'cids', str(request.env.user.company_id.id)) allowed_company_ids = [int(cid) for cid in cids.split(',')] report_obj = report_obj.with_context( allowed_company_ids=allowed_company_ids) if financial_id and financial_id != 'null': report_obj = report_obj.browse(int(financial_id)) report_name = report_obj.get_report_filename(options) try: if output_format == 'xlsx': response = request.make_response( None, headers=[ ('Content-Type', account_report_model.get_export_mime_type('xlsx')), ('Content-Disposition', content_disposition(report_name + '.xlsx')) ]) response.stream.write(report_obj.get_xlsx(options)) if output_format == 'pdf': response = request.make_response( report_obj.get_pdf(options), headers=[ ('Content-Type', account_report_model.get_export_mime_type('pdf')), ('Content-Disposition', content_disposition(report_name + '.pdf')) ]) if output_format == 'xml': content = report_obj.get_xml(options) response = request.make_response( content, headers=[ ('Content-Type', account_report_model.get_export_mime_type('xml')), ('Content-Disposition', content_disposition(report_name + '.xml')), ('Content-Length', len(content)) ]) if output_format == 'xaf': content = report_obj.get_xaf(options) response = request.make_response( content, headers=[ ('Content-Type', account_report_model.get_export_mime_type('xaf')), ('Content-Disposition', content_disposition(report_name + '.xaf')), ('Content-Length', len(content)) ]) if output_format == 'txt': content = report_obj.get_txt(options) response = request.make_response( content, headers=[ ('Content-Type', account_report_model.get_export_mime_type('txt')), ('Content-Disposition', content_disposition(report_name + '.txt')), ('Content-Length', len(content)) ]) if output_format == 'csv': content = report_obj.get_csv(options) response = request.make_response( content, headers=[ ('Content-Type', account_report_model.get_export_mime_type('csv')), ('Content-Disposition', content_disposition(report_name + '.csv')), ('Content-Length', len(content)) ]) if output_format == 'zip': content = report_obj.get_zip(options) response = request.make_response( content, headers=[ ('Content-Type', account_report_model.get_export_mime_type('zip')), ('Content-Disposition', content_disposition(report_name + '.zip')), ]) # Adding direct_passthrough to the response and giving it a file # as content means that we will stream the content of the file to the user # Which will prevent having the whole file in memory response.direct_passthrough = True response.set_cookie('fileToken', token) return response except Exception as e: se = _serialize_exception(e) error = {'code': 200, 'message': 'Odoo Server Error', 'data': se} return request.make_response(html_escape(json.dumps(error)))
def get_report(self, model, options, output_format, token, financial_id=None, **kw): uid = request.session.uid report_obj = request.env[model].sudo(uid) options = json.loads(options) if financial_id: report_obj = report_obj.browse(int(financial_id)) report_name = report_obj.get_report_filename(options) try: if output_format == 'xlsx': response = request.make_response( None, headers=[('Content-Type', 'application/vnd.ms-excel'), ('Content-Disposition', content_disposition(report_name + '.xlsx'))]) report_obj.get_xlsx(options, response) if output_format == 'pdf': response = request.make_response( report_obj.get_pdf(options), headers=[('Content-Type', 'application/pdf'), ('Content-Disposition', content_disposition(report_name + '.pdf'))]) if output_format == 'xml': content = report_obj.get_xml(options) response = request.make_response( content, headers=[('Content-Type', 'application/vnd.sun.xml.writer'), ('Content-Disposition', content_disposition(report_name + '.xml')), ('Content-Length', len(content))]) if output_format == 'xaf': content = report_obj.get_xaf(options) response = request.make_response( content, headers=[('Content-Type', 'application/vnd.sun.xml.writer'), ('Content-Disposition', 'attachment; filename=' + report_name + '.xaf;'), ('Content-Length', len(content))]) if output_format == 'txt': content = report_obj.get_txt(options) response = request.make_response( content, headers=[('Content-Type', 'text/plain'), ('Content-Disposition', content_disposition(report_name + '.txt')), ('Content-Length', len(content))]) if output_format == 'csv': content = report_obj.get_csv(options) response = request.make_response( content, headers=[('Content-Type', 'text/csv'), ('Content-Disposition', 'attachment; filename=' + report_name + '.csv;'), ('Content-Length', len(content))]) response.set_cookie('fileToken', token) return response except Exception as e: se = _serialize_exception(e) error = {'code': 200, 'message': 'ERP Server Error', 'data': se} return request.make_response(html_escape(json.dumps(error)))
def report_download(self, data, token): """This function is used by 'qwebactionmanager.js' in order to trigger the download of a pdf/controller report. :param data: a javascript array JSON.stringified containg report internal url ([0]) and type [1] :returns: Response with a filetoken cookie and an attachment header """ requestcontent = json.loads(data) url, type = requestcontent[0], requestcontent[1] try: if type == 'qweb-pdf': reportname = url.split('/report/pdf/')[1].split('?')[0] docids = None if '/' in reportname: reportname, docids = reportname.split('/') if docids: # Generic report: response = self.report_routes(reportname, docids=docids, converter='pdf') else: # Particular report: data = url_decode(url.split('?')[1]).items() # decoding the args represented in JSON response = self.report_routes(reportname, converter='pdf', **dict(data)) report = request.env['report']._get_report_from_name(reportname) filename = "%s.%s" % (report.name, "pdf") #Sale Order if report.report_name == 'solum_sale.sol_quotation_report_template_id': so_pool = request.env['sale.order'] lst_so = [] lst_so = docids.split(",") for ele_inv in lst_so: so_obj = so_pool.browse([int(ele_inv)]) filename = so_obj.name +'-'+'Sol Luminaire' if report.report_name == 'solum_sale.idesign_quotation_report_template_id': so_pool = request.env['sale.order'] lst_so = [] lst_so = docids.split(",") for ele_inv in lst_so: so_obj = so_pool.browse([int(ele_inv)]) filename = so_obj.name +'-'+'iDesign' #Invoice if report.report_name == 'solum_invoice.sol_invoice_report_template_id': inv_pool = request.env['account.invoice'] lst_inv = [] lst_inv = docids.split(",") for ele_inv in lst_inv: inv_obj = inv_pool.browse([int(ele_inv)]) if inv_obj.number: filename = inv_obj.number +'-'+'Sol Luminaire Customer' else: filename = inv_obj.partner_id.name +'-'+'Sol Luminaire Customer' if report.report_name == 'solum_invoice.idesign_invoice_report_template_id': inv_pool = request.env['account.invoice'] lst_inv = [] lst_inv = docids.split(",") for ele_inv in lst_inv: inv_obj = inv_pool.browse([int(ele_inv)]) if inv_obj.number: filename = inv_obj.number +'-'+'iDesign' else: filename = inv_obj.partner_id.name +'-'+'iDesign' if report.report_name == 'solum_invoice.sol_commission_invoice_report_template_id': inv_pool = request.env['account.invoice'] lst_inv = [] lst_inv = docids.split(",") for ele_inv in lst_inv: inv_obj = inv_pool.browse([int(ele_inv)]) if inv_obj.number: filename = inv_obj.number +'-'+'Sol Luminaire Commission' else: filename = inv_obj.partner_id.name +'-'+'Sol Luminaire Commission' #Delivery Order if report.report_name == 'solum_delivery_order.sol_do_report_template_id': picking_pool = request.env['stock.picking'] lst_picking = [] lst_picking = docids.split(",") for ele_picking in lst_picking: picking_obj = picking_pool.browse([int(ele_picking)]) filename = picking_obj.name +'-'+'Sol Luminaire' if report.report_name == 'solum_delivery_order.idesign_do_report_template_id': picking_pool = request.env['stock.picking'] lst_picking = [] lst_picking = docids.split(",") for ele_picking in lst_picking: picking_obj = picking_pool.browse([int(ele_picking)]) filename = picking_obj.name +'-'+'iDesign' filename = "%s.%s" % (filename, "pdf") if docids: ids = [int(x) for x in docids.split(",")] obj = request.env[report.model].browse(ids) if report.print_report_name and not len(obj) > 1: filename = safe_eval(report.print_report_name, {'object': obj, 'time': time}) response.headers.add('Content-Disposition', content_disposition(filename)) response.set_cookie('fileToken', token) return response elif type == 'controller': reqheaders = Headers(request.httprequest.headers) response = Client(request.httprequest.app, BaseResponse).get(url, headers=reqheaders, follow_redirects=True) response.set_cookie('fileToken', token) return response else: return except Exception, e: se = _serialize_exception(e) error = { 'code': 200, 'message': "Odoo Server Error", 'data': se } return request.make_response(html_escape(json.dumps(error)))
def value_to_html(self, value, options): """ Escapes the value and converts newlines to br. This is bullshit. """ return nl2br(html_escape(value)) if value else ''
def apply_inheritance_specs(source, specs_tree, inherit_branding=False, pre_locate=lambda s: True): """ Apply an inheriting view (a descendant of the base view) Apply to a source architecture all the spec nodes (i.e. nodes describing where and what changes to apply to some parent architecture) given by an inheriting view. :param Element source: a parent architecture to modify :param Element specs_tree: a modifying architecture in an inheriting view :param bool inherit_branding: :param pre_locate: function that is executed before locating a node. This function receives an arch as argument. This is required by studio to properly handle group_ids. :return: a modified source where the specs are applied :rtype: Element """ # Queue of specification nodes (i.e. nodes describing where and # changes to apply to some parent architecture). specs = specs_tree if isinstance(specs_tree, list) else [specs_tree] def extract(spec): """ Utility function that locates a node given a specification, remove it from the source and returns it. """ if len(spec): raise ValueError( _("Invalid specification for moved nodes: %r", etree.tostring(spec, encoding='unicode'))) pre_locate(spec) to_extract = locate_node(source, spec) if to_extract is not None: remove_element(to_extract) return to_extract else: raise ValueError( _("Element %r cannot be located in parent view", etree.tostring(spec, encoding='unicode'))) while len(specs): spec = specs.pop(0) if isinstance(spec, SKIPPED_ELEMENT_TYPES): continue if spec.tag == 'data': specs += [c for c in spec] continue pre_locate(spec) node = locate_node(source, spec) if node is not None: pos = spec.get('position', 'inside') if pos == 'replace': mode = spec.get('mode', 'outer') if mode == "outer": for loc in spec.xpath(".//*[text()='$0']"): loc.text = '' loc.append(copy.deepcopy(node)) if node.getparent() is None: spec_content = None comment = None for content in spec: if content.tag is not etree.Comment: spec_content = content break else: comment = content source = copy.deepcopy(spec_content) # only keep the t-name of a template root node t_name = node.get('t-name') if t_name: source.set('t-name', t_name) if comment is not None: text = source.text source.text = None comment.tail = text source.insert(0, comment) else: # TODO ideally the notion of 'inherit_branding' should # not exist in this function. Given the current state of # the code, it is however necessary to know where nodes # were removed when distributing branding. As a stable # fix, this solution was chosen: the location is marked # with a "ProcessingInstruction" which will not impact # the "Element" structure of the resulting tree. # Exception: if we happen to replace a node that already # has xpath branding (root level nodes), do not mark the # location of the removal as it will mess up the branding # of siblings elements coming from other views, after the # branding is distributed (and those processing instructions # removed). if inherit_branding and not node.get('data-oe-xpath'): node.addprevious( etree.ProcessingInstruction( 'apply-inheritance-specs-node-removal', node.tag)) for child in spec: if child.get('position') == 'move': child = extract(child) node.addprevious(child) node.getparent().remove(node) elif mode == "inner": # Replace the entire content of an element for child in node: node.remove(child) node.text = None for child in spec: node.append(copy.deepcopy(child)) node.text = spec.text else: raise ValueError( _("Invalid mode attribute:") + " '%s'" % mode) elif pos == 'attributes': for child in spec.getiterator('attribute'): attribute = child.get('name') value = child.text or '' if child.get('add') or child.get('remove'): assert not child.text separator = child.get('separator', ',') if separator == ' ': separator = None # squash spaces to_add = (s for s in ( s.strip() for s in child.get('add', '').split(separator)) if s) to_remove = { s.strip() for s in child.get('remove', '').split(separator) } values = ( s.strip() for s in node.get(attribute, '').split(separator)) value = (separator or ' ').join( itertools.chain( (v for v in values if v not in to_remove), to_add)) if value: node.set(attribute, value) elif attribute in node.attrib: del node.attrib[attribute] elif pos == 'inside': # add a sentinel element at the end, insert content of spec # before the sentinel, then remove the sentinel element sentinel = E.sentinel() node.append(sentinel) add_stripped_items_before(sentinel, spec, extract) remove_element(sentinel) elif pos == 'after': # add a sentinel element right after node, insert content of # spec before the sentinel, then remove the sentinel element sentinel = E.sentinel() node.addnext(sentinel) add_stripped_items_before(sentinel, spec, extract) remove_element(sentinel) elif pos == 'before': add_stripped_items_before(node, spec, extract) else: raise ValueError(_("Invalid position attribute: '%s'") % pos) else: attrs = ''.join([ ' %s="%s"' % (attr, html_escape(spec.get(attr))) for attr in spec.attrib if attr != 'position' ]) tag = "<%s%s>" % (spec.tag, attrs) raise ValueError( _("Element '%s' cannot be located in parent view", tag)) return source
def report_download(self, data, token): """This function is used by 'qwebactionmanager.js' in order to trigger the download of a pdf/controller report. :param data: a javascript array JSON.stringified containg report internal url ([0]) and type [1] :returns: Response with a filetoken cookie and an attachment header """ requestcontent = json.loads(data) url, type = requestcontent[0], requestcontent[1] try: if type == "qweb-pdf": reportname = url.split("/report/pdf/")[1].split("?")[0] docids = None active_model = "" NewReportName = "" if "/" in reportname: reportname, docids = reportname.split("/") if docids: # Generic report: response = self.report_routes(reportname, docids=docids, converter="pdf") else: # Particular report: data = url_decode( url.split("?") [1]).items() # decoding the args represented in JSON dictData = dict(data) active_model = json.loads( dictData.get("context")).get("active_model") NewReportName = (json.loads( dictData.get("options")).get("form").get("name")) response = self.report_routes(reportname, converter="pdf", **dictData) report = request.env[ "ir.actions.report"]._get_report_from_name(reportname) filename = "%s.%s" % (report.name, "pdf") if active_model == "payroll.register": filename = "%s.%s" % (NewReportName, "pdf") if docids: ids = [int(x) for x in docids.split(",")] obj = request.env[report.model].browse(ids) if report.print_report_name and not len(obj) > 1: report_name = safe_eval( report.print_report_name, { "object": obj, "time": time }, ) filename = "%s.%s" % (report_name, "pdf") if report.model == "payroll.register": filename = "%s.%s" % (obj.name, "pdf") response.headers.add("Content-Disposition", content_disposition(filename)) response.set_cookie("fileToken", token) return response else: return except Exception as e: se = _serialize_exception(e) error = {"code": 200, "message": "Odoo Server Error", "data": se} return request.make_response(html_escape(json.dumps(error)))
def report_download(self, data, token): # This method has been overwrite """This function is used by 'qwebactionmanager.js' in order to trigger the download of a pdf/controller report. :param data: a javascript array JSON.stringified containg report internal url ([0]) and type [1] :returns: Response with a filetoken cookie and an attachment header """ requestcontent = json.loads(data) url, type = requestcontent[0], requestcontent[1] try: if type == 'qweb-pdf': reportname = url.split('/report/pdf/')[1].split('?')[0] docids = None if '/' in reportname: reportname, docids = reportname.split('/') if docids: # Generic report: response = self.report_routes(reportname, docids=docids, converter='pdf') else: # Particular report: data = url_decode( url.split('?') [1]).items() # decoding the args represented in JSON response = self.report_routes(reportname, converter='pdf', **dict(data)) report = request.env['report']._get_report_from_name( reportname) filename = "%s.%s" % (report.name, "pdf") if docids: ids = [int(x) for x in docids.split(",")] obj = request.env[report.model].browse(ids) # will search the model where reports will get printed search_model = request.env['dynamic.reportname'].search([ ('model_id.model', '=', report.model) ]) # Will bring the list of fields that belongs to the selected model if search_model: if search_model.field_id.ttype == 'many2one': field = obj.read([ search_model.field_id.name ])[0][search_model.field_id.name][1] else: field = obj.read([search_model.field_id.name ])[0][search_model.field_id.name] # will print the dynamic names for pdf reports filename = (str(field) or report.name) + '.pdf' if report.print_report_name and not len(obj) > 1: filename = safe_eval(report.print_report_name, { 'object': obj, 'time': time }) response.headers.add('Content-Disposition', content_disposition(filename)) response.set_cookie('fileToken', token) return response elif type == 'controller': reqheaders = Headers(request.httprequest.headers) response = Client(request.httprequest.app, BaseResponse).get(url, headers=reqheaders, follow_redirects=True) response.set_cookie('fileToken', token) return response else: return except Exception, e: se = _serialize_exception(e) error = {'code': 200, 'message': "Odoo Server Error", 'data': se} return request.make_response(html_escape(json.dumps(error)))
def value_to_html(self, value, options): if not value: return False text = ', '.join(value.sudo().mapped('display_name')) return nl2br(html_escape(text))
def value_to_html(self, value, options): if not value: return '' return html_escape( pycompat.to_text(options['selection'][value]) or u'')
def insert_record(self, request, model, values, custom, meta=None): if model.model != 'crm.lead': return super(ContactController, self).insert_record(request, model, values, custom, meta) lead_model = request.env["crm.lead"] lead_id = lead_model.decode(request) # domain: leads that are still open: # NOT [ on_change AND (proba = 0 OR proba = 100) ] # the condition on the lead_id is prepended domain = [('id', '=', lead_id), '|', ('stage_id.on_change', '=', False), '&', ('stage_id.probability', '!=', 0), ('stage_id.probability', '!=', 100)] lead_instance = lead_model.sudo().search(domain) if lead_instance: # a lead_id cookie exists and it has not been altered and the lead is not closed lead = lead_model.sudo().browse(lead_id) # NOTE: the following should be changed when dynamic forms exist changed_values = {} for fieldname, fieldvalue in values.items(): if fieldname in lead and fieldvalue: if lead[fieldname] and lead[fieldname] != fieldvalue: changed_values[fieldname] = fieldvalue else: lead[fieldname] = fieldvalue # Post a message to indicate the updated field (if any) if changed_values: body = 'Other value given for field ' for fieldname in changed_values.keys(): body += '<br/><b>%s</b>: <b>%s</b>' % ( fieldname, html_escape(changed_values[fieldname])) request.env['crm.lead'].browse(lead_id).sudo().message_post( body=body, subject="Field value changed") return lead_id else: # either no lead_id cookie OR the lead_id doesn't exist in db OR the current one is closed -> a lead is created lang = request.context.get('lang', False) lang_id = request.env["res.lang"].sudo().search( [('code', '=', lang)], limit=1).id values['lang_id'] = lang_id body = None if 'pages_viewed' in request.session: score_pageview_ids = [] url_list = [] pages_viewed = request.session['pages_viewed'] for url, date in pages_viewed.iteritems(): vals = { 'user_id': request.session.get('uid'), 'url': url, 'view_date': date } score_pageview_ids.append((0, 0, vals)) url_list.append(url) del request.session['pages_viewed'] values['score_pageview_ids'] = score_pageview_ids urls = [] for url in url_list: url_encoded = html_escape(url) urls.append('<a href="%s" target="_blank"><b>%s</b></a>' % (url_encoded, url_encoded)) body = '<br/>'.join(urls) new_lead_id = self.create_real_lead(request, model, values, custom, meta) # if pages were seen, a message is posted if body: request.env['crm.lead'].browse( new_lead_id).sudo().message_post(body=body, subject="Pages visited") return new_lead_id