def _payulatam_generate_sign(self, values, incoming=True): """ Generate the signature for incoming or outgoing communications. :param dict values: The values used to generate the signature :param bool incoming: Whether the signature must be generated for an incoming (PayU Latam to Odoo) or outgoing (Odoo to PayU Latam) communication. :return: The signature :rtype: str """ if incoming: data_string = '~'.join([ self.payulatam_api_key, self.payulatam_merchant_id, values['referenceCode'], # http://developers.payulatam.com/en/web_checkout/integration.html # Section: 2. Response page > Signature validation # PayU Latam use the "Round half to even" rounding method # to generate their signature. This happens to be Python 3's # default rounding method. float_repr(float(values.get('TX_VALUE')), 1), values['currency'], values.get('transactionState'), ]) else: data_string = '~'.join([ self.payulatam_api_key, self.payulatam_merchant_id, values['referenceCode'], float_repr(float(values['amount']), 1), values['currency'], ]) return md5(data_string.encode('utf-8')).hexdigest()
def _payulatam_generate_sign(self, values, incoming=True): """ Generate the signature for incoming or outgoing communications. :param dict values: The values used to generate the signature :param bool incoming: Whether the signature must be generated for an incoming (PayU Latam to Odoo) or outgoing (Odoo to PayU Latam) communication. :return: The signature :rtype: str """ if incoming: data_string = '~'.join([ self.payulatam_api_key, self.payulatam_merchant_id, values['referenceCode'], # Observation from the sandbox: PayU Latam is using a rounded value to generate # their signature despite saying otherwise in the doc: # http://developers.payulatam.com/en/web_checkout/integration.html float_repr(float(values.get('TX_VALUE')), 1), values['currency'], values.get('transactionState'), ]) else: data_string = '~'.join([ self.payulatam_api_key, self.payulatam_merchant_id, values['referenceCode'], float_repr(float(values['amount']), 1), values['currency'], ]) return md5(data_string.encode('utf-8')).hexdigest()
def _compute_draft_quantity_count(self, product_template_ids, product_variant_ids, wh_location_ids): """ Overrides to computes the valuations of the stock. """ res = super()._compute_draft_quantity_count(product_template_ids, product_variant_ids, wh_location_ids) domain = self._product_domain(product_template_ids, product_variant_ids) company = self.env['stock.location'].browse(wh_location_ids).mapped( 'company_id') svl = self.env['stock.valuation.layer'].search(domain + [('company_id', '=', company.id)]) currency = svl.currency_id or self.env.company.currency_id quantity = sum( svl.filtered(lambda layer: layer.stock_move_id.location_dest_id.id in wh_location_ids).mapped('quantity')) if quantity: total_quantity = sum(svl.mapped('quantity')) value = sum(svl.mapped('value')) * (quantity / total_quantity) else: value = 0 value = float_repr(value, precision_digits=currency.decimal_places) if currency.position == 'after': value = '%s %s' % (value, currency.symbol) else: value = '%s %s' % (currency.symbol, value) res['value'] = value return res
def confirm(self, **kw): tx_id = int(kw.get('tx_id', 0)) access_token = kw.get('access_token') if tx_id: if access_token: tx = request.env['payment.transaction'].sudo().browse(tx_id) secret = request.env['ir.config_parameter'].sudo().get_param('database.secret') valid_token_str = '%s%s%s' % (tx.id, tx.reference, float_repr(tx.amount, precision_digits=tx.currency_id.decimal_places)) valid_token = hmac.new(secret.encode('utf-8'), valid_token_str.encode('utf-8'), hashlib.sha256).hexdigest() if not consteq(ustr(valid_token), access_token): raise werkzeug.exceptions.NotFound else: tx = request.env['payment.transaction'].browse(tx_id) if tx.state in ['done', 'authorized']: status = 'success' message = tx.acquirer_id.done_msg elif tx.state == 'pending': status = 'warning' message = tx.acquirer_id.pending_msg else: status = 'danger' message = tx.state_message or _('An error occured during the processing of this payment') PaymentProcessing.remove_payment_transaction(tx) return request.render('payment.confirm', {'tx': tx, 'status': status, 'message': message}) else: return request.redirect('/my/home')
def _sdd_xml_gen_payment_group(self, company_id, required_collection_date, askBatchBooking, payment_info_counter, journal, CstmrDrctDbtInitn): """ Generates a group of payments in the same PmtInfo node, provided that they share the same journal.""" PmtInf = create_xml_node(CstmrDrctDbtInitn, 'PmtInf') create_xml_node(PmtInf, 'PmtInfId', str(payment_info_counter)) create_xml_node(PmtInf, 'PmtMtd', 'DD') create_xml_node(PmtInf, 'BtchBookg',askBatchBooking and '1' or '0') create_xml_node(PmtInf, 'NbOfTxs', str(len(self))) create_xml_node(PmtInf, 'CtrlSum', float_repr(sum(x.amount for x in self), precision_digits=2)) # This sum ignores the currency, it is used as a checksum (see SEPA rulebook) PmtTpInf = create_xml_node_chain(PmtInf, ['PmtTpInf','SvcLvl','Cd'], 'SEPA')[0] create_xml_node_chain(PmtTpInf, ['LclInstrm','Cd'], 'CORE') create_xml_node(PmtTpInf, 'SeqTp', 'FRST') #Note: FRST refers to the COLLECTION of payments, not the type of mandate used #This value is only used for informatory purpose. create_xml_node(PmtInf, 'ReqdColltnDt', fields.Date.from_string(required_collection_date).strftime("%Y-%m-%d")) create_xml_node_chain(PmtInf, ['Cdtr','Nm'], company_id.name[:70]) # SEPA regulation gives a maximum size of 70 characters for this field create_xml_node_chain(PmtInf, ['CdtrAcct','Id','IBAN'], journal.bank_account_id.sanitized_acc_number) create_xml_node_chain(PmtInf, ['CdtrAgt', 'FinInstnId', 'BIC'], (journal.bank_id.bic or '').replace(' ', '').upper()) CdtrSchmeId_Othr = create_xml_node_chain(PmtInf, ['CdtrSchmeId','Id','PrvtId','Othr','Id'], company_id.sdd_creditor_identifier)[-2] create_xml_node_chain(CdtrSchmeId_Othr, ['SchmeNm','Prtry'], 'SEPA') for payment in self: payment.sdd_xml_gen_payment(company_id, payment.partner_id, payment.name[:35], PmtInf)
def ogone_form_generate_values(self, values): base_url = self.env['ir.config_parameter'].get_param('web.base.url') ogone_tx_values = dict(values) temp_ogone_tx_values = { 'PSPID': self.ogone_pspid, 'ORDERID': values['reference'], 'AMOUNT': float_repr(float_round(values['amount'], 2) * 100, 0), 'CURRENCY': values['currency'] and values['currency'].name or '', 'LANGUAGE': values.get('partner_lang'), 'CN': values.get('partner_name'), 'EMAIL': values.get('partner_email'), 'OWNERZIP': values.get('partner_zip'), 'OWNERADDRESS': values.get('partner_address'), 'OWNERTOWN': values.get('partner_city'), 'OWNERCTY': values.get('partner_country') and values.get('partner_country').code or '', 'OWNERTELNO': values.get('partner_phone'), 'ACCEPTURL': '%s' % urlparse.urljoin(base_url, OgoneController._accept_url), 'DECLINEURL': '%s' % urlparse.urljoin(base_url, OgoneController._decline_url), 'EXCEPTIONURL': '%s' % urlparse.urljoin(base_url, OgoneController._exception_url), 'CANCELURL': '%s' % urlparse.urljoin(base_url, OgoneController._cancel_url), 'PARAMPLUS': 'return_url=%s' % ogone_tx_values.pop('return_url') if ogone_tx_values.get('return_url') else False, } if values.get('type') == 'form_save': temp_ogone_tx_values.update({ 'ALIAS': 'ODOO-NEW-ALIAS-%s' % time.time(), # something unique, 'ALIASUSAGE': values.get('alias_usage') or self.ogone_alias_usage, }) shasign = self._ogone_generate_shasign('in', temp_ogone_tx_values) temp_ogone_tx_values['SHASIGN'] = shasign ogone_tx_values.update(temp_ogone_tx_values) return ogone_tx_values
def transaction(self, acquirer_id, reference, amount, currency_id, partner_id=False, **kwargs): acquirer = request.env['payment.acquirer'].browse(acquirer_id) order_id = kwargs.get('order_id') reference_values = order_id and {'sale_order_ids': [(4, order_id)]} or {} reference = request.env['payment.transaction']._compute_reference(values=reference_values, prefix=reference) values = { 'acquirer_id': int(acquirer_id), 'reference': reference, 'amount': float(amount), 'currency_id': int(currency_id), 'partner_id': partner_id, 'type': 'form_save' if acquirer.save_token != 'none' and partner_id else 'form', } if order_id: values['sale_order_ids'] = [(6, 0, [order_id])] reference_values = order_id and {'sale_order_ids': [(4, order_id)]} or {} reference_values.update(acquirer_id=int(acquirer_id)) values['reference'] = request.env['payment.transaction']._compute_reference(values=reference_values, prefix=reference) tx = request.env['payment.transaction'].sudo().with_context(lang=None).create(values) secret = request.env['ir.config_parameter'].sudo().get_param('database.secret') token_str = '%s%s%s' % (tx.id, tx.reference, float_repr(tx.amount, precision_digits=tx.currency_id.decimal_places)) token = hmac.new(secret.encode('utf-8'), token_str.encode('utf-8'), hashlib.sha256).hexdigest() tx.return_url = '/website_payment/confirm?tx_id=%d&access_token=%s' % (tx.id, token) PaymentProcessing.add_payment_transaction(tx) render_values = { 'partner_id': partner_id, } return acquirer.sudo().render(tx.reference, float(amount), int(currency_id), values=render_values)
def _compute_json_forecast(self): self.json_forecast = False if not any(self._ids): # onchange return # compute precision = self.env['decimal.precision'].precision_get('Product Unit of Measure') for so_line in self: if any(move.state == 'done' for move in so_line.move_ids) or not so_line.move_ids.picking_id: qty_delivered = float_repr(so_line.qty_delivered, precision) so_line.json_forecast = json.dumps({'reservedAvailability': qty_delivered}) else: # For waiting deliveries, take the info from the report line. delivery = so_line.move_ids.picking_id.filtered(lambda picking: picking.state in ['confirmed', 'waiting']) if delivery.exists(): moves_to_process = so_line.move_ids.filtered(lambda move: move.id in delivery.move_lines.ids and move.state not in ['cancel', 'done']) if moves_to_process.exists(): so_line.json_forecast = moves_to_process[0].json_forecast else: # For assigned deliveries, take the delivery's date. delivery = so_line.move_ids.picking_id.filtered(lambda picking: picking.state == 'assigned') if delivery.exists(): date_expected = delivery.scheduled_date so_line.json_forecast = json.dumps({ 'expectedDate': format_date(self.env, date_expected), 'isLate': date_expected > so_line.order_id.expected_date, })
def _compute_draft_quantity_count(self, product_template_ids, product_variant_ids, wh_location_ids): """ Overrides to computes the valuations of the stock. """ res = super()._compute_draft_quantity_count(product_template_ids, product_variant_ids, wh_location_ids) domain = self._product_domain(product_template_ids, product_variant_ids) company = self.env['stock.location'].browse(wh_location_ids).mapped( 'company_id') svl = self.env['stock.valuation.layer'].search(domain + [('company_id', '=', company.id)]) currency = svl.currency_id or self.env.company.currency_id total_quantity = sum(svl.mapped('quantity')) # Because we can have negative quantities, `total_quantity` may be equal to zero even if the warehouse's `quantity` is positive. if svl and not float_is_zero( total_quantity, precision_rounding=svl.product_id.uom_id.rounding): def filter_on_locations(layer): return layer.stock_move_id.location_dest_id.id in wh_location_ids or layer.stock_move_id.location_id.id in wh_location_ids quantity = sum( svl.filtered(filter_on_locations).mapped('quantity')) value = sum(svl.mapped('value')) * (quantity / total_quantity) else: value = 0 value = float_repr(value, precision_digits=currency.decimal_places) if currency.position == 'after': value = '%s %s' % (value, currency.symbol) else: value = '%s %s' % (currency.symbol, value) res['value'] = value return res
def payment_token(self, pm_id, reference, amount, currency_id, partner_id=False, return_url=None, **kwargs): token = request.env['payment.token'].browse(int(pm_id)) order_id = kwargs.get('order_id') if not token: return request.redirect('/website_payment/pay?error_msg=%s' % _('Cannot setup the payment.')) values = { 'acquirer_id': token.acquirer_id.id, 'reference': reference, 'amount': float(amount), 'currency_id': int(currency_id), 'partner_id': int(partner_id), 'payment_token_id': int(pm_id), 'type': 'server2server', 'return_url': return_url, } if order_id: values['sale_order_ids'] = [(6, 0, [int(order_id)])] tx = request.env['payment.transaction'].sudo().with_context(lang=None).create(values) PaymentProcessing.add_payment_transaction(tx) try: tx.s2s_do_transaction() secret = request.env['ir.config_parameter'].sudo().get_param('database.secret') token_str = '%s%s%s' % (tx.id, tx.reference, float_repr(tx.amount, precision_digits=tx.currency_id.decimal_places)) token = hmac.new(secret.encode('utf-8'), token_str.encode('utf-8'), hashlib.sha256).hexdigest() tx.return_url = return_url or '/website_payment/confirm?tx_id=%d&access_token=%s' % (tx.id, token) except Exception as e: _logger.exception(e) return request.redirect('/payment/process')
def ogone_form_generate_values(self, values): base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url') ogone_tx_values = dict(values) temp_ogone_tx_values = { 'PSPID': self.ogone_pspid, 'ORDERID': values['reference'], 'AMOUNT': float_repr(float_round(values['amount'], 2) * 100, 0), 'CURRENCY': values['currency'] and values['currency'].name or '', 'LANGUAGE': values.get('partner_lang'), 'CN': values.get('partner_name'), 'EMAIL': values.get('partner_email'), 'OWNERZIP': values.get('partner_zip'), 'OWNERADDRESS': values.get('partner_address'), 'OWNERTOWN': values.get('partner_city'), 'OWNERCTY': values.get('partner_country') and values.get('partner_country').code or '', 'OWNERTELNO': values.get('partner_phone'), 'ACCEPTURL': urls.url_join(base_url, OgoneController._accept_url), 'DECLINEURL': urls.url_join(base_url, OgoneController._decline_url), 'EXCEPTIONURL': urls.url_join(base_url, OgoneController._exception_url), 'CANCELURL': urls.url_join(base_url, OgoneController._cancel_url), 'PARAMPLUS': 'return_url=%s' % ogone_tx_values.pop('return_url') if ogone_tx_values.get('return_url') else False, } if self.save_token in ['ask', 'always']: temp_ogone_tx_values.update({ 'ALIAS': 'ODOO-NEW-ALIAS-%s' % time.time(), # something unique, 'ALIASUSAGE': values.get('alias_usage') or self.ogone_alias_usage, }) shasign = self._ogone_generate_shasign('in', temp_ogone_tx_values) temp_ogone_tx_values['SHASIGN'] = shasign ogone_tx_values.update(temp_ogone_tx_values) return ogone_tx_values
def _sdd_xml_gen_partner(self, company_id, required_collection_date, payment_info_counter, mandate, CstmrDrctDbtInitn): """ Appends to a SDD XML file being generated all the data related to a partner and his payments. self must be a recordset whose payments share the same partner. /!\ => Grouping the payments by mandate caused problems with Dutch banks, because of the too large number of distinct transactions in the file. We fixed that so that we now group on payment journal. This function is not used anymore and will be removed. It has been replaced by _sdd_xml_gen_payment_group. """ PmtInf = create_xml_node(CstmrDrctDbtInitn, 'PmtInf') create_xml_node(PmtInf, 'PmtInfId', str(payment_info_counter)) create_xml_node(PmtInf, 'PmtMtd', 'DD') create_xml_node(PmtInf, 'NbOfTxs', str(len(self))) create_xml_node( PmtInf, 'CtrlSum', float_repr(sum(x.amount for x in self), precision_digits=2) ) # This sum ignores the currency, it is used as a checksum (see SEPA rulebook) PmtTpInf = create_xml_node_chain(PmtInf, ['PmtTpInf', 'SvcLvl', 'Cd'], 'SEPA')[0] create_xml_node_chain(PmtTpInf, ['LclInstrm', 'Cd'], 'CORE') create_xml_node(PmtTpInf, 'SeqTp', 'FRST') #Note: FRST refers to the COLLECTION of payments, not the type of mandate used #This value is only used for informatory purpose. create_xml_node( PmtInf, 'ReqdColltnDt', fields.Date.from_string(required_collection_date).strftime( "%Y-%m-%d")) create_xml_node_chain( PmtInf, ['Cdtr', 'Nm'], company_id.name[:70] ) # SEPA regulation gives a maximum size of 70 characters for this field create_xml_node_chain( PmtInf, ['CdtrAcct', 'Id', 'IBAN'], mandate.payment_journal_id.bank_account_id.sanitized_acc_number) create_xml_node_chain(PmtInf, ['CdtrAgt', 'FinInstnId', 'BIC'], (mandate.payment_journal_id.bank_id.bic or '').replace(' ', '').upper()) CdtrSchmeId_Othr = create_xml_node_chain( PmtInf, ['CdtrSchmeId', 'Id', 'PrvtId', 'Othr', 'Id'], company_id.sdd_creditor_identifier)[-2] create_xml_node_chain(CdtrSchmeId_Othr, ['SchmeNm', 'Prtry'], 'SEPA') partner = None for partner_payment in self: if not partner: partner = partner_payment.partner_id elif partner != partner_payment.partner_id: raise UserError( "Trying to generate a single XML payment group for payments with different partners." ) partner_payment.sdd_xml_gen_payment(company_id, mandate.partner_id, partner_payment.name[:35], PmtInf)
def mx_pac_edi_update_sat_status(self): '''Synchronize both systems: Odoo & SAT to make sure the invoice is valid. ''' url = 'https://consultaqr.facturaelectronica.sat.gob.mx/ConsultaCFDIService.svc?wsdl' headers = { 'SOAPAction': 'http://tempuri.org/IConsultaCFDIService/Consulta', 'Content-Type': 'text/xml; charset=utf-8' } template = """<?xml version="1.0" encoding="UTF-8"?> <SOAP-ENV:Envelope xmlns:ns0="http://tempuri.org/" xmlns:ns1="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"> <SOAP-ENV:Header/> <ns1:Body> <ns0:Consulta> <ns0:expresionImpresa>${data}</ns0:expresionImpresa> </ns0:Consulta> </ns1:Body> </SOAP-ENV:Envelope>""" namespace = { 'a': 'http://schemas.datacontract.org/2004/07/Sat.Cfdi.Negocio.ConsultaCfdi.Servicio' } for move in self: supplier_rfc = move.mx_pac_edi_cfdi_supplier_rfc customer_rfc = move.mx_pac_edi_cfdi_customer_rfc total = float_repr( move.mx_pac_edi_cfdi_amount, precision_digits=move.currency_id.decimal_places) uuid = move.mx_pac_edi_cfdi_uuid params = '?re=%s&rr=%s&tt=%s&id=%s' % ( tools.html_escape(tools.html_escape(supplier_rfc or '')), tools.html_escape(tools.html_escape( customer_rfc or '')), total or 0.0, uuid or '') soap_env = template.format(data=params) try: soap_xml = requests.post(url, data=soap_env, headers=headers, timeout=20) response = fromstring(soap_xml.text) fetched_status = response.xpath('//a:Estado', namespaces=namespace) status = fetched_status[0] if fetched_status else '' except Exception as e: move.message_post( body=_("Failure during update of the SAT status: %(msg)s", msg=str(e))) continue if status == 'Vigente': move.mx_pac_edi_sat_status = 'valid' elif status == 'Cancelado': move.mx_pac_edi_sat_status = 'cancelled' elif status == 'No Encontrado': move.mx_pac_edi_sat_status = 'not_found' else: move.mx_pac_edi_sat_status = 'none'
def ogone_form_generate_values(self, values): """ Replace return urls with current domain to avoid changing domain for the website visitor. Code copied from ogone module. """ base_url = request.httprequest.host_url ogone_tx_values = dict(values) temp_ogone_tx_values = { "PSPID": self.ogone_pspid, "ORDERID": values["reference"], "AMOUNT": float_repr(float_round(values["amount"], 2) * 100, 0), "CURRENCY": values["currency"] and values["currency"].name or "", "LANGUAGE": values.get("partner_lang"), "CN": values.get("partner_name"), "EMAIL": values.get("partner_email"), "OWNERZIP": values.get("partner_zip"), "OWNERADDRESS": values.get("partner_address"), "OWNERTOWN": values.get("partner_city"), "OWNERCTY": values.get("partner_country") and values.get("partner_country").code or "", "OWNERTELNO": values.get("partner_phone"), "ACCEPTURL": "%s" % urllib.parse.urljoin(base_url, OgoneCompassion._accept_url), "DECLINEURL": "%s" % urllib.parse.urljoin(base_url, OgoneCompassion._decline_url), "EXCEPTIONURL": "%s" % urllib.parse.urljoin(base_url, OgoneCompassion._exception_url), "CANCELURL": "%s" % urllib.parse.urljoin(base_url, OgoneCompassion._cancel_url), "PARAMPLUS": "return_url=%s" % ogone_tx_values.pop("return_url") if ogone_tx_values.get("return_url") else False, } if self.save_token in ["ask", "always"]: temp_ogone_tx_values.update({ "ALIAS": f"ODOO-NEW-ALIAS-{time.time()}", # something unique, "ALIASUSAGE": values.get("alias_usage") or self.ogone_alias_usage, }) shasign = self._ogone_generate_shasign("in", temp_ogone_tx_values) temp_ogone_tx_values["SHASIGN"] = shasign ogone_tx_values.update(temp_ogone_tx_values) return ogone_tx_values
def ogone_form_generate_values(self, values): """ Replace return urls with current domain to avoid changing domain for the website visitor. Code copied from ogone module. """ base_url = request.httprequest.host_url ogone_tx_values = dict(values) temp_ogone_tx_values = { 'PSPID': self.ogone_pspid, 'ORDERID': values['reference'], 'AMOUNT': float_repr(float_round(values['amount'], 2) * 100, 0), 'CURRENCY': values['currency'] and values['currency'].name or '', 'LANGUAGE': values.get('partner_lang'), 'CN': values.get('partner_name'), 'EMAIL': values.get('partner_email'), 'OWNERZIP': values.get('partner_zip'), 'OWNERADDRESS': values.get('partner_address'), 'OWNERTOWN': values.get('partner_city'), 'OWNERCTY': values.get('partner_country') and values.get('partner_country').code or '', 'OWNERTELNO': values.get('partner_phone'), 'ACCEPTURL': '%s' % urlparse.urljoin(base_url, OgoneCompassion._accept_url), 'DECLINEURL': '%s' % urlparse.urljoin(base_url, OgoneCompassion._decline_url), 'EXCEPTIONURL': '%s' % urlparse.urljoin(base_url, OgoneCompassion._exception_url), 'CANCELURL': '%s' % urlparse.urljoin(base_url, OgoneCompassion._cancel_url), 'PARAMPLUS': 'return_url=%s' % ogone_tx_values.pop('return_url') if ogone_tx_values.get('return_url') else False, } if self.save_token in ['ask', 'always']: temp_ogone_tx_values.update({ 'ALIAS': 'ODOO-NEW-ALIAS-%s' % time.time(), # something unique, 'ALIASUSAGE': values.get('alias_usage') or self.ogone_alias_usage, }) shasign = self._ogone_generate_shasign('in', temp_ogone_tx_values) temp_ogone_tx_values['SHASIGN'] = shasign ogone_tx_values.update(temp_ogone_tx_values) return ogone_tx_values
def _sdd_xml_gen_header(self, company_id, CstmrDrctDbtInitn): """ Generates the header of the SDD XML file. """ GrpHdr = create_xml_node(CstmrDrctDbtInitn, 'GrpHdr') create_xml_node(GrpHdr, 'MsgId', str(time.time())) # Using time makes sure the identifier is unique in an easy way create_xml_node(GrpHdr, 'CreDtTm', datetime.now().strftime('%Y-%m-%dT%H:%M:%S')) create_xml_node(GrpHdr, 'NbOfTxs', str(len(self))) create_xml_node(GrpHdr, 'CtrlSum', float_repr(sum(x.amount for x in self), precision_digits=2)) # This sum ignores the currency, it is used as a checksum (see SEPA rulebook) InitgPty = create_xml_node(GrpHdr, 'InitgPty') create_xml_node(InitgPty, 'Nm', company_id.name[:140]) create_xml_node_chain(InitgPty, ['Id','OrgId','Othr','Id'], company_id.sdd_creditor_identifier)
def _get_specific_rendering_values(self, processing_values): """ Override of payment to return Payulatam-specific rendering values. Note: self.ensure_one() from `_get_processing_values` :param dict processing_values: The generic and specific processing values of the transaction :return: The dict of acquirer-specific processing values :rtype: dict """ res = super()._get_specific_rendering_values(processing_values) if self.provider != 'payulatam': return res api_url = 'https://checkout.payulatam.com/ppp-web-gateway-payu/' \ if self.acquirer_id.state == 'enabled' \ else 'https://sandbox.checkout.payulatam.com/ppp-web-gateway-payu/' payulatam_values = { 'merchantId': self.acquirer_id.payulatam_merchant_id, 'referenceCode': self.reference, 'description': self.reference, 'amount': float_repr(processing_values['amount'], self.currency_id.decimal_places or 2), 'tax': 0, 'taxReturnBase': 0, 'currency': self.currency_id.name, 'accountId': self.acquirer_id.payulatam_account_id, 'buyerFullName': self.partner_name, 'buyerEmail': self.partner_email, 'responseUrl': urls.url_join(self.get_base_url(), PayuLatamController._return_url), 'confirmationUrl': urls.url_join(self.get_base_url(), PayuLatamController._webhook_url), 'api_url': api_url, } if self.acquirer_id.state != 'enabled': payulatam_values['test'] = 1 payulatam_values[ 'signature'] = self.acquirer_id._payulatam_generate_sign( payulatam_values, incoming=False) return payulatam_values
def sdd_xml_gen_payment(self, company_id, partner, end2end_counter, PmtInf): """ Appends to a SDD XML file being generated all the data related to the payments of a given partner. """ #The two following conditions should never execute. #They are here to be sure future modifications won't ever break everything. if self.company_id != company_id: raise UserError( _("Trying to generate a Direct Debit XML file containing payments from another company than that file's creditor." )) if self.payment_method_id.code != 'sdd': raise UserError( _("Trying to generate a Direct Debit XML for payments coming from another payment method than SEPA Direct Debit." )) DrctDbtTxInf = create_xml_node_chain( PmtInf, ['DrctDbtTxInf', 'PmtId', 'EndToEndId'], str(end2end_counter))[0] InstdAmt = create_xml_node(DrctDbtTxInf, 'InstdAmt', float_repr(self.amount, precision_digits=2)) InstdAmt.attrib['Ccy'] = self.currency_id.name MndtRltdInf = create_xml_node_chain( DrctDbtTxInf, ['DrctDbtTx', 'MndtRltdInf', 'MndtId'], self.sdd_mandate_id.name)[-2] create_xml_node(MndtRltdInf, 'DtOfSgntr', self.sdd_mandate_id.start_date) create_xml_node_chain(DrctDbtTxInf, ['DbtrAgt', 'FinInstnId', 'BIC'], self.sdd_mandate_id.partner_bank_id.bank_id.bic) Dbtr = create_xml_node_chain(DrctDbtTxInf, ['Dbtr', 'Nm'], partner.name)[0] if self.sdd_mandate_id.debtor_id_code: create_xml_node(Dbtr, 'Id', self.sdd_mandate_id.debtor_id_code) if partner.contact_address: PstlAdr = create_xml_node(Dbtr, 'PstlAdr') if partner.country_id and partner.country_id.code: create_xml_node(PstlAdr, 'Ctry', partner.country_id.code) n_line = 0 contact_address = partner.contact_address.replace('\n', ' ').strip() while contact_address and n_line < 2: create_xml_node(PstlAdr, 'AdrLine', contact_address[:70]) contact_address = contact_address[70:] n_line = n_line + 1 create_xml_node_chain( DrctDbtTxInf, ['DbtrAcct', 'Id', 'IBAN'], self.sdd_mandate_id.partner_bank_id.sanitized_acc_number)
def l10n_mx_edi_update_sat_status_xml(self, xml): """Check SAT WS to make sure the invoice is valid. inv: dict containing values to check SAT WS correctly. """ template = """<?xml version="1.0" encoding="UTF-8"?> <SOAP-ENV:Envelope xmlns:ns0="http://tempuri.org/" xmlns:ns1="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"> <SOAP-ENV:Header/> <ns1:Body> <ns0:Consulta> <ns0:expresionImpresa>${data}</ns0:expresionImpresa> </ns0:Consulta> </ns1:Body> </SOAP-ENV:Envelope>""" supplier_rfc = xml.Emisor.get('Rfc', '').upper() customer_rfc = xml.Receptor.get('Rfc', '').upper() amount = float(xml.get('Total', 0.0)) uuid = xml.get('UUID', '') currency = self.env['res.currency'].search([('name', '=', xml.get('Moneda', 'MXN'))]) precision = currency.decimal_places if currency else 0 tfd = self.env['account.move'].l10n_mx_edi_get_tfd_etree(xml) uuid = tfd.get('UUID', '') total = float_repr(amount, precision_digits=precision) params = '?re=%s&rr=%s&tt=%s&id=%s' % ( tools.html_escape(tools.html_escape(supplier_rfc or '')), tools.html_escape(tools.html_escape( customer_rfc or '')), total or 0.0, uuid or '') soap_env = template.format(data=params) try: soap_xml = requests.post( 'https://consultaqr.facturaelectronica.sat.gob.mx/ConsultaCFDIService.svc?wsdl', data=soap_env, timeout=20, headers={ 'SOAPAction': 'http://tempuri.org/IConsultaCFDIService/Consulta', 'Content-Type': 'text/xml; charset=utf-8' }) response = objectify.fromstring(soap_xml.text) status = response.xpath( '//a:Estado', namespaces={ 'a': 'http://schemas.datacontract.org/2004/07/Sat.Cfdi.Negocio.ConsultaCfdi.Servicio' }) except Exception as e: raise ValidationError(str(e)) return CFDI_SAT_QR_STATE.get(status[0] if status else '', 'none')
def l10n_mx_edi_update_sat_status(self): res = super(AccountInvoice, self).l10n_mx_edi_update_sat_status() url = 'https://consultaqr.facturaelectronica.sat.gob.mx/ConsultaCFDIService.svc?wsdl' # noqa headers = { 'SOAPAction': 'http://tempuri.org/IConsultaCFDIService/Consulta', 'Content-Type': 'text/xml; charset=utf-8' } template = """<?xml version="1.0" encoding="UTF-8"?> <SOAP-ENV:Envelope xmlns:ns0="http://tempuri.org/" xmlns:ns1="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"> <SOAP-ENV:Header/> <ns1:Body> <ns0:Consulta> <ns0:expresionImpresa>?%s</ns0:expresionImpresa> </ns0:Consulta> </ns1:Body> </SOAP-ENV:Envelope>""" namespace = { 'a': 'http://schemas.datacontract.org/2004/07/' 'Sat.Cfdi.Negocio.ConsultaCfdi.Servicio' } for inv in self.filtered( lambda r: r.type == 'in_invoice' and r.l10n_mx_edi_cfdi_uuid): supplier_rfc = inv.l10n_mx_edi_cfdi_supplier_rfc customer_rfc = inv.l10n_mx_edi_cfdi_customer_rfc total = float_repr(inv.l10n_mx_edi_cfdi_amount, precision_digits=inv.currency_id.decimal_places) uuid = inv.l10n_mx_edi_cfdi_uuid params = url_encode( { 're': supplier_rfc, 'rr': customer_rfc, 'tt': total, 'id': uuid }, separator='&') soap_env = template % (params) try: soap_xml = requests.post(url, data=soap_env, headers=headers) response = objectify.fromstring(soap_xml.text) status = response.xpath('//a:Estado', namespaces=namespace) except BaseException as e: inv.l10n_mx_edi_log_error(str(e)) continue inv.l10n_mx_edi_sat_status = CFDI_SAT_QR_STATE.get( status[0] if status else False, 'none') return res
def authorize_form_generate_values(self, values): self.ensure_one() # State code is only supported in US, use state name by default # See https://developer.authorize.net/api/reference/ state = values['partner_state'].name if values.get('partner_state') else '' if values.get('partner_country') and values.get('partner_country') == self.env.ref('base.us', False): state = values['partner_state'].code if values.get('partner_state') else '' billing_state = values['billing_partner_state'].name if values.get('billing_partner_state') else '' if values.get('billing_partner_country') and values.get('billing_partner_country') == self.env.ref('base.us', False): billing_state = values['billing_partner_state'].code if values.get('billing_partner_state') else '' base_url = self.env['ir.config_parameter'].get_param('web.base.url') authorize_tx_values = dict(values) temp_authorize_tx_values = { 'x_login': self.authorize_login, 'x_trans_key': self.authorize_transaction_key, 'x_amount': float_repr(values['amount'], values['currency'].decimal_places if values['currency'] else 2), 'x_show_form': 'PAYMENT_FORM', 'x_type': 'AUTH_CAPTURE' if not self.capture_manually else 'AUTH_ONLY', 'x_method': 'CC', 'x_fp_sequence': '%s%s' % (self.id, int(time.time())), 'x_version': '3.1', 'x_relay_response': 'TRUE', 'x_fp_timestamp': str(int(time.time())), 'x_relay_url': urls.url_join(base_url, AuthorizeController._return_url), 'x_cancel_url': urls.url_join(base_url, AuthorizeController._cancel_url), 'x_currency_code': values['currency'] and values['currency'].name or '', 'address': values.get('partner_address'), 'city': values.get('partner_city'), 'country': values.get('partner_country') and values.get('partner_country').name or '', 'email': values.get('partner_email'), 'zip_code': values.get('partner_zip'), 'first_name': values.get('partner_first_name'), 'last_name': values.get('partner_last_name'), 'phone': values.get('partner_phone'), 'state': state, 'billing_address': values.get('billing_partner_address'), 'billing_city': values.get('billing_partner_city'), 'billing_country': values.get('billing_partner_country') and values.get('billing_partner_country').name or '', 'billing_email': values.get('billing_partner_email'), 'billing_zip_code': values.get('billing_partner_zip'), 'billing_first_name': values.get('billing_partner_first_name'), 'billing_last_name': values.get('billing_partner_last_name'), 'billing_phone': values.get('billing_partner_phone'), 'billing_state': billing_state, } temp_authorize_tx_values['returndata'] = authorize_tx_values.pop('return_url', '') temp_authorize_tx_values['x_fp_hash'] = self._authorize_generate_hashing(temp_authorize_tx_values) temp_authorize_tx_values.pop('x_trans_key') # We remove this value since it is secret and isn't needed on the form authorize_tx_values.update(temp_authorize_tx_values) return authorize_tx_values
def razorpay_form_generate_values(self, values): self.ensure_one() currency = self.env['res.currency'].sudo().browse(values['currency_id']) if currency != self.env.ref('base.INR'): raise ValidationError(_('Currency not supported by Razorpay')) values.update({ 'key': self.razorpay_key_id, 'amount': float_repr(float_round(values.get('amount'), 2) * 100, 0), 'name': values.get('partner_name'), 'contact': values.get('partner_phone'), 'email': values.get('partner_email'), 'order_id': values.get('reference'), }) return values
def _compute_draft_quantity_count(self, product_template_ids, product_variant_ids, wh_location_ids): """ Overrides to computes the valuations of the stock. """ res = super()._compute_draft_quantity_count(product_template_ids, product_variant_ids, wh_location_ids) domain = self._product_domain(product_template_ids, product_variant_ids) svl = self.env['stock.valuation.layer'].search(domain) currency = svl.currency_id or self.env.company.currency_id value = float_repr(sum(svl.mapped('value')), precision_digits=currency.decimal_places) if currency.position == 'after': value = '%s %s' % (value, currency.symbol) else: value = '%s %s' % (currency.symbol, value) res['value'] = value return res
def _get_purchases_infos(self, date_from, date_to): """ Generate purchases informations for the IRAS Audit File """ purchases_lines = [] purchase_total_sgd = 0.0 gst_total_sgd = 0.0 transaction_count_total = 0 invoice_ids = self.env['account.move'].search([ ('company_id', '=', self.env.company.id), ('type', 'in', ['in_invoice', 'in_refund']), ('state', '=', 'posted'), ('date', '>=', date_from), ('date', '<=', date_to) ]) for invoice in invoice_ids: lines_number = 0 for lines in invoice.invoice_line_ids: lines_number += 1 sign = -1 if invoice.type == 'in_refund' else 1 tax_amount = lines.price_total - lines.price_subtotal tax_amount_company = invoice.currency_id._convert(tax_amount, invoice.company_id.currency_id, invoice.company_id, invoice.invoice_date or invoice.date) transaction_count_total += 1 purchase_total_sgd += lines.balance gst_total_sgd += tax_amount if not invoice.partner_id.l10n_sg_unique_entity_number: raise UserError(_('Your partner (%s) must have a UEN.') % invoice.partner_id.name) purchases_lines.append({ 'SupplierName': (invoice.partner_id.name or '')[:100], 'SupplierUEN': (invoice.partner_id.l10n_sg_unique_entity_number or '')[:16], 'InvoiceDate': invoice.l10n_sg_permit_number_date if invoice.l10n_sg_permit_number and invoice.l10n_sg_permit_number_date else invoice.invoice_date, 'InvoiceNo': (invoice.name or '')[:50], 'PermitNo': invoice.l10n_sg_permit_number[:20] if invoice.l10n_sg_permit_number else False, 'LineNo': str(lines_number), 'ProductDescription': ('[' + lines.product_id.default_code + '] ' + lines.product_id.name if lines.product_id.default_code else lines.product_id.name or '')[:250], 'PurchaseValueSGD': float_repr(lines.balance, IRAS_DIGITS), 'GSTValueSGD': float_repr((lines.price_total - lines.price_subtotal) / (lines.quantity or 1), IRAS_DIGITS), 'TaxCode': (lines.tax_ids and lines.tax_ids[0].name or ' ')[:20], 'FCYCode': (lines.currency_id.name if lines.currency_id.name != 'SGD' else 'XXX')[:3], 'PurchaseFCY': float_repr(lines.price_subtotal, IRAS_DIGITS) if lines.currency_id.name != 'SGD' else '0', 'GSTFCY': float_repr(sign * tax_amount_company, IRAS_DIGITS) if lines.currency_id.name != 'SGD' else '0' }) return { 'lines': purchases_lines, 'PurchaseTotalSGD': float_repr(purchase_total_sgd, IRAS_DIGITS), 'GSTTotalSGD': float_repr(gst_total_sgd, IRAS_DIGITS), 'TransactionCountTotal': str(transaction_count_total) }
def _get_purchases_infos(self, date_from, date_to): """ Generate purchases informations for the IRAS Audit File """ purchases_lines = [] purchase_total_sgd = 0.0 gst_total_sgd = 0.0 transaction_count_total = 0 invoice_ids = self.env['account.invoice'].search([ ('company_id', '=', self.env.user.company_id.id), ('type', 'in', ['in_invoice', 'in_refund']), ('state', 'in', ['open', 'in_payment', 'paid']), ('date', '>=', date_from), ('date', '<=', date_to) ]) for invoice in invoice_ids: lines_number = 0 for lines in invoice.invoice_line_ids: lines_number += 1 transaction_count_total += 1 purchase_total_sgd += lines.price_subtotal_signed gst_total_sgd += lines.l10n_sg_reports_amount_tax if not invoice.partner_id.l10n_sg_unique_entity_number: raise UserError(_('Your partner (%s) must have a UEN.') % invoice.partner_id.name) purchases_lines.append({ 'SupplierName': invoice.partner_id.name, 'SupplierUEN': invoice.partner_id.l10n_sg_unique_entity_number, 'InvoiceDate': invoice.l10n_sg_permit_number_date if invoice.l10n_sg_permit_number and invoice.l10n_sg_permit_number_date else invoice.date_invoice, 'InvoiceNo': invoice.number, 'PermitNo': invoice.l10n_sg_permit_number if invoice.l10n_sg_permit_number else False, 'LineNo': str(lines_number), 'ProductDescription': '[' + lines.product_id.default_code + '] ' + lines.product_id.name if lines.product_id.default_code else lines.product_id.name, 'PurchaseValueSGD': float_repr(lines.price_subtotal_signed, IRAS_DIGITS), 'GSTValueSGD': float_repr(lines.l10n_sg_reports_amount_tax, IRAS_DIGITS), 'TaxCode': lines.l10n_sg_reports_tax.name if lines.l10n_sg_reports_tax else ' ', 'FCYCode': lines.currency_id.name if lines.currency_id.name != 'SGD' else 'XXX', 'PurchaseFCY': float_repr(lines.price_subtotal, IRAS_DIGITS) if lines.currency_id.name != 'SGD' else '0', 'GSTFCY': float_repr(lines.l10n_sg_reports_amount_tax_no_change, IRAS_DIGITS) if lines.currency_id.name != 'SGD' else '0' }) return { 'lines': purchases_lines, 'PurchaseTotalSGD': float_repr(purchase_total_sgd, IRAS_DIGITS), 'GSTTotalSGD': float_repr(gst_total_sgd, IRAS_DIGITS), 'TransactionCountTotal': str(transaction_count_total) }
def ogone_form_generate_values(self, values): """ Replace return urls with current domain to avoid changing domain for the website visitor. Code copied from ogone module. """ base_url = request.httprequest.host_url ogone_tx_values = dict(values) temp_ogone_tx_values = { 'PSPID': self.ogone_pspid, 'ORDERID': values['reference'], 'AMOUNT': float_repr(float_round(values['amount'], 2) * 100, 0), 'CURRENCY': values['currency'] and values['currency'].name or '', 'LANGUAGE': values.get('partner_lang'), 'CN': values.get('partner_name'), 'EMAIL': values.get('partner_email'), 'OWNERZIP': values.get('partner_zip'), 'OWNERADDRESS': values.get('partner_address'), 'OWNERTOWN': values.get('partner_city'), 'OWNERCTY': values.get('partner_country') and values.get( 'partner_country').code or '', 'OWNERTELNO': values.get('partner_phone'), 'ACCEPTURL': '%s' % urlparse.urljoin( base_url, OgoneCompassion._accept_url), 'DECLINEURL': '%s' % urlparse.urljoin( base_url, OgoneCompassion._decline_url), 'EXCEPTIONURL': '%s' % urlparse.urljoin( base_url, OgoneCompassion._exception_url), 'CANCELURL': '%s' % urlparse.urljoin( base_url, OgoneCompassion._cancel_url), 'PARAMPLUS': 'return_url=%s' % ogone_tx_values.pop( 'return_url') if ogone_tx_values.get('return_url') else False, } if self.save_token in ['ask', 'always']: temp_ogone_tx_values.update({ 'ALIAS': 'ODOO-NEW-ALIAS-%s' % time.time(), # something unique, 'ALIASUSAGE': values.get( 'alias_usage') or self.ogone_alias_usage, }) shasign = self._ogone_generate_shasign('in', temp_ogone_tx_values) temp_ogone_tx_values['SHASIGN'] = shasign ogone_tx_values.update(temp_ogone_tx_values) return ogone_tx_values
def authorize_form_generate_values(self, values): self.ensure_one() base_url = self.env['ir.config_parameter'].get_param('web.base.url') authorize_tx_values = dict(values) temp_authorize_tx_values = { 'x_login': self.authorize_login, 'x_trans_key': self.authorize_transaction_key, 'x_amount': float_repr(values['amount'], values['currency'].decimal_places if values['currency'] else 2), 'x_show_form': 'PAYMENT_FORM', 'x_type': 'AUTH_CAPTURE' if not self.capture_manually else 'AUTH_ONLY', 'x_method': 'CC', 'x_fp_sequence': '%s%s' % (self.id, int(time.time())), 'x_version': '3.1', 'x_relay_response': 'TRUE', 'x_fp_timestamp': str(int(time.time())), 'x_relay_url': urls.url_join(base_url, AuthorizeController._return_url), 'x_cancel_url': urls.url_join(base_url, AuthorizeController._cancel_url), 'x_currency_code': values['currency'] and values['currency'].name or '', 'address': values.get('partner_address'), 'city': values.get('partner_city'), 'country': values.get('partner_country') and values.get('partner_country').name or '', 'email': values.get('partner_email'), 'zip_code': values.get('partner_zip'), 'first_name': values.get('partner_first_name'), 'last_name': values.get('partner_last_name'), 'phone': values.get('partner_phone'), 'state': values.get('partner_state') and values['partner_state'].code or '', 'billing_address': values.get('billing_partner_address'), 'billing_city': values.get('billing_partner_city'), 'billing_country': values.get('billing_partner_country') and values.get('billing_partner_country').name or '', 'billing_email': values.get('billing_partner_email'), 'billing_zip_code': values.get('billing_partner_zip'), 'billing_first_name': values.get('billing_partner_first_name'), 'billing_last_name': values.get('billing_partner_last_name'), 'billing_phone': values.get('billing_partner_phone'), 'billing_state': values.get('billing_partner_state') and values['billing_partner_state'].code or '', } temp_authorize_tx_values['returndata'] = authorize_tx_values.pop('return_url', '') temp_authorize_tx_values['x_fp_hash'] = self._authorize_generate_hashing(temp_authorize_tx_values) authorize_tx_values.update(temp_authorize_tx_values) return authorize_tx_values
def _compute_draft_quantity_count(self, product_template_ids, product_variant_ids, wh_location_ids): """ Overrides to computes the valuations of the stock. """ res = super()._compute_draft_quantity_count(product_template_ids, product_variant_ids, wh_location_ids) if not self.user_has_groups('stock.group_stock_manager'): return res domain = self._product_domain(product_template_ids, product_variant_ids) company = self.env['stock.location'].browse( wh_location_ids[0]).company_id svl = self.env['stock.valuation.layer'].search(domain + [('company_id', '=', company.id)]) domain_quants = [('company_id', '=', company.id), ('location_id', 'in', wh_location_ids)] if product_template_ids: domain_quants += [('product_id.product_tmpl_id', 'in', product_template_ids)] else: domain_quants += [('product_id', 'in', product_variant_ids)] quants = self.env['stock.quant'].search(domain_quants) currency = svl.currency_id or self.env.company.currency_id total_quantity = sum(svl.mapped('quantity')) # Because we can have negative quantities, `total_quantity` may be equal to zero even if the warehouse's `quantity` is positive. if svl and not float_is_zero( total_quantity, precision_rounding=svl.product_id.uom_id.rounding): value = sum(svl.mapped('value')) * ( sum(quants.mapped('quantity')) / total_quantity) else: value = 0 value = float_repr(value, precision_digits=currency.decimal_places) if currency.position == 'after': value = '%s %s' % (value, currency.symbol) else: value = '%s %s' % (currency.symbol, value) res['value'] = value return res
def l10n_mx_edi_update_sat_status(self): res = super(AccountInvoice, self).l10n_mx_edi_update_sat_status() url = 'https://consultaqr.facturaelectronica.sat.gob.mx/ConsultaCFDIService.svc?wsdl' # noqa for inv in self.filtered( lambda r: r.type == 'in_invoice' and r.l10n_mx_edi_cfdi_uuid): supplier_rfc = inv.l10n_mx_edi_cfdi_supplier_rfc customer_rfc = inv.l10n_mx_edi_cfdi_customer_rfc total = float_repr(inv.l10n_mx_edi_cfdi_amount, precision_digits=inv.currency_id.decimal_places) uuid = inv.l10n_mx_edi_cfdi_uuid params = '"?re=%s&rr=%s&tt=%s&id=%s' % ( tools.html_escape(tools.html_escape(supplier_rfc or '')), tools.html_escape(tools.html_escape( customer_rfc or '')), total or 0.0, uuid or '') try: response = Client(url).service.Consulta(params).Estado except BaseException as e: inv.l10n_mx_edi_log_error(str(e)) continue inv.l10n_mx_edi_sat_status = CFDI_SAT_QR_STATE.get( response.__repr__(), 'none') return res
def l10n_mx_edi_update_sat_status(self): '''Synchronize both systems: Odoo & SAT to make sure the invoice is valid. ''' url = 'https://consultaqr.facturaelectronica.sat.gob.mx/ConsultaCFDIService.svc?wsdl' for inv in self.filtered(lambda r: r.l10n_mx_edi_is_required()): if inv.l10n_mx_edi_pac_status not in ['signed', 'cancelled']: continue supplier_rfc = inv.l10n_mx_edi_cfdi_supplier_rfc customer_rfc = inv.l10n_mx_edi_cfdi_customer_rfc total = float_repr(inv.l10n_mx_edi_cfdi_amount, precision_digits=inv.currency_id.decimal_places) uuid = inv.l10n_mx_edi_cfdi_uuid params = '"?re=%s&rr=%s&tt=%s&id=%s' % ( tools.html_escape(tools.html_escape(supplier_rfc or '')), tools.html_escape(tools.html_escape(customer_rfc or '')), total or 0.0, uuid or '') try: response = Client(url).service.Consulta(params).Estado except Exception as e: inv.l10n_mx_edi_log_error(str(e)) continue inv.l10n_mx_edi_sat_status = CFDI_SAT_QR_STATE.get(response.__repr__(), 'none')
def aasmes_yieldreport_export(self, meslineid, workorderidstr=None, workdate=None, productcode=None, workorder=None): mesline = request.env['aas.mes.line'].browse(int(meslineid)) badmodelist, badmodeids = self.action_loading_badmodelist( mesline, workdate), [] if workorderidstr: workorderids = [ int(workorderid) for workorderid in workorderidstr.split('-') ] workorderlist = request.env['aas.mes.workorder'].browse( workorderids) else: tempdomain = [('mesline_id', '=', mesline.id), ('state', '!=', 'draft')] if productcode: pproduct = request.env['product.product'].search( [('default_code', '=', productcode)], limit=1) if pproduct: tempdomain.append(('product_id', '=', pproduct.id)) if workorder: tempdomain.append(('name', 'ilike', '%' + workorder + '%')) if workdate: tempdates = workdate.split('~') tempdomain += [('plan_date', '>=', tempdates[0]), ('plan_date', '<=', tempdates[1])] workorderlist = request.env['aas.mes.workorder'].search(tempdomain) workbook = xlwt.Workbook(style_compression=2) worksheet = workbook.add_sheet(u'良率报表') base_style = xlwt.easyxf('align: wrap yes') wkcolumnindex = 0 worksheet.write(0, wkcolumnindex, u'日期', base_style) wkcolumnindex += 1 worksheet.write(0, wkcolumnindex, u'班次', base_style) wkcolumnindex += 1 if mesline.id == 5: worksheet.write(0, wkcolumnindex, u'员工', base_style) wkcolumnindex += 1 worksheet.write(0, wkcolumnindex, u'设备', base_style) wkcolumnindex += 1 worksheet.write(0, wkcolumnindex, u'主工单', base_style) wkcolumnindex += 1 worksheet.write(0, wkcolumnindex, u'子工单', base_style) wkcolumnindex += 1 worksheet.write(0, wkcolumnindex, u'生产品种', base_style) wkcolumnindex += 1 worksheet.write(0, wkcolumnindex, u'开始时间', base_style) wkcolumnindex += 1 worksheet.write(0, wkcolumnindex, u'结束时间', base_style) wkcolumnindex += 1 worksheet.write(0, wkcolumnindex, u'计划产出', base_style) wkcolumnindex += 1 worksheet.write(0, wkcolumnindex, u'实际产出', base_style) wkcolumnindex += 1 worksheet.write(0, wkcolumnindex, u'达成率', base_style) wkcolumnindex += 1 worksheet.write(0, wkcolumnindex, u'不良数量', base_style) wkcolumnindex += 1 worksheet.write(0, wkcolumnindex, u'工单良率', base_style) wkcolumnindex += 1 if mesline.line_type == 'flowing': worksheet.write(0, wkcolumnindex, u'一次不良', base_style) wkcolumnindex += 1 worksheet.write(0, wkcolumnindex, u'二次不良', base_style) wkcolumnindex += 1 worksheet.write(0, wkcolumnindex, u'三次不良', base_style) badcolumnindex = 1 if badmodelist and len(badmodelist) > 0: for badmode in badmodelist: worksheet.write(0, wkcolumnindex + badcolumnindex, badmode['badmode_name'], base_style) badcolumnindex += 1 badmodeids.append(badmode['badmode_id']) rowindex = 1 if workorderlist and len(workorderlist) > 0: for workorder in workorderlist: mainorder_name = '' if not workorder.mainorder_id else workorder.mainorder_id.name, plan_date = '' if not workorder.plan_date else workorder.plan_date plan_schedule = '' if not workorder.plan_schedule else workorder.plan_schedule.name produce_start = '' if not workorder.produce_start else fields.Datetime.to_china_string( workorder.produce_start) produce_finish = '' if not workorder.produce_finish else fields.Datetime.to_china_string( workorder.produce_finish) reach_rate = workorder.output_qty / workorder.input_qty * 100.0 employee_name, equipment_name, producer, equipment = '', '', workorder.producer_id, workorder.equipment_id if producer: employee_name = producer.name + '[' + producer.code + ']' if equipment: equipment_name = equipment.name + '[' + equipment.code + ']' wkcolumnindex = 0 worksheet.write(rowindex, wkcolumnindex, plan_date, base_style) wkcolumnindex += 1 worksheet.write(rowindex, wkcolumnindex, plan_schedule, base_style) wkcolumnindex += 1 if mesline.id == 5: worksheet.write(rowindex, wkcolumnindex, employee_name, base_style) wkcolumnindex += 1 worksheet.write(rowindex, wkcolumnindex, equipment_name, base_style) wkcolumnindex += 1 worksheet.write(rowindex, wkcolumnindex, mainorder_name, base_style) wkcolumnindex += 1 worksheet.write(rowindex, wkcolumnindex, workorder.name, base_style) wkcolumnindex += 1 worksheet.write(rowindex, wkcolumnindex, workorder.product_code, base_style) wkcolumnindex += 1 worksheet.write(rowindex, wkcolumnindex, produce_start, base_style) wkcolumnindex += 1 worksheet.write(rowindex, wkcolumnindex, produce_finish, base_style) wkcolumnindex += 1 worksheet.write(rowindex, wkcolumnindex, workorder.input_qty, base_style) wkcolumnindex += 1 worksheet.write(rowindex, wkcolumnindex, workorder.output_qty, base_style) wkcolumnindex += 1 worksheet.write(rowindex, wkcolumnindex, float_repr(reach_rate, 2), base_style) wkcolumnindex += 1 tempbadmodevals = self.action_loading_workorder_badmodelist( workorder) badmode_qty = tempbadmodevals['total_qty'] worksheet.write(rowindex, wkcolumnindex, badmode_qty, base_style) wkcolumnindex += 1 if float_compare(workorder.output_qty, 0.0, precision_rounding=0.000001) <= 0.0: yield_actual = 0.0 else: yield_actual = workorder.output_qty / ( badmode_qty + workorder.output_qty) * 100.0 worksheet.write(rowindex, wkcolumnindex, float_repr(yield_actual, 2), base_style) wkcolumnindex += 1 if mesline.line_type == 'flowing': worksheet.write(rowindex, wkcolumnindex, tempbadmodevals['once_qty'], base_style) wkcolumnindex += 1 worksheet.write(rowindex, wkcolumnindex, tempbadmodevals['twice_qty'], base_style) wkcolumnindex += 1 worksheet.write(rowindex, wkcolumnindex, tempbadmodevals['more_qty'], base_style) badcolumnindex = 1 badmodes = tempbadmodevals['badmodes'] if not badmodeids or len(badmodeids) <= 0: rowindex += 1 continue for badmodeid in badmodeids: temp_qty = 0.0 if badmodeid in badmodes: temp_qty = badmodes[badmodeid] worksheet.write(rowindex, wkcolumnindex + badcolumnindex, temp_qty, base_style) badcolumnindex += 1 rowindex += 1 stream = StringIO() workbook.save(stream) outvalues = stream.getvalue() filename = mesline.name + fields.Datetime.to_china_today().replace( '-', '') xlshttpheaders = [('Content-Type', 'application/vnd.ms-excel'), ('Content-Length', len(outvalues)), ('Content-Disposition', 'attachment; filename=%s.xls;' % filename)] return request.make_response(outvalues, headers=xlshttpheaders)
def _get_gldata(self, date_from, date_to): """ Generate gldata for IRAS Audit File """ gldata_lines = [] total_debit = 0.0 total_credit = 0.0 transaction_count_total = 0 glt_currency = 'SGD' company_id = self.env.company move_line_ids = self.env['account.move.line'].search([ ('company_id', '=', company_id.id), ('date', '>=', date_from), ('date', '<=', date_to) ]) initial_bal_results = self.with_context( date_to=fields.Date.from_string(date_from) + timedelta(days=-1) )._do_query_group_by_account({}, None) all_accounts = self.env['account.account'].search([ ('company_id', '=', company_id.id) ]) for account in all_accounts: initial_bal = initial_bal_results.get(account.id, {'balance': 0, 'amount_currency': 0, 'debit': 0, 'credit': 0}) gldata_lines.append({ 'TransactionDate': date_from, 'AccountID': account.code, 'AccountName': account.name, 'TransactionDescription': 'OPENING BALANCE', 'Name': False, 'TransactionID': False, 'SourceDocumentID': False, 'SourceType': False, 'Debit': float_repr(initial_bal['debit'], IRAS_DIGITS), 'Credit': float_repr(initial_bal['credit'], IRAS_DIGITS), 'Balance': float_repr(initial_bal['balance'], IRAS_DIGITS) }) balance = initial_bal['balance'] for move_line_id in move_line_ids: if move_line_id.account_id.code == account.code: balance = company_id.currency_id.round(balance + move_line_id.debit - move_line_id.credit) total_credit += move_line_id.credit total_debit += move_line_id.debit transaction_count_total += 1 gldata_lines.append({ 'TransactionDate': move_line_id.date, 'AccountID': move_line_id.account_id.code, 'AccountName': move_line_id.account_id.name, 'TransactionDescription': move_line_id.name, 'Name': move_line_id.partner_id.name if move_line_id.partner_id else False, 'TransactionID': move_line_id.move_id.name, 'SourceDocumentID': move_line_id.invoice_id.origin if move_line_id.invoice_id else False, 'SourceType': move_line_id.account_id.user_type_id.name, 'Debit': float_repr(move_line_id.debit, IRAS_DIGITS), 'Credit': float_repr(move_line_id.credit, IRAS_DIGITS), 'Balance': float_repr(balance, IRAS_DIGITS) }) return { 'lines': gldata_lines, 'TotalDebit': float_repr(total_debit, IRAS_DIGITS), 'TotalCredit': float_repr(total_credit, IRAS_DIGITS), 'TransactionCountTotal': str(transaction_count_total), 'GLTCurrency': glt_currency }