zoukankan      html  css  js  c++  java
  • odoo12 支付宝在线支付

    我使用的是这位大佬的模块:
    git clone https://github.com/block-cat/payment_alipay

    测试这个模块的功能,折腾了一天,踩了不少的坑,还好有了点眉目,现在记录下:

    关于公钥私钥的设置

    1. 在支付宝中设置好密钥以后,需要在odoo中进行设置,在odoo中设置的公钥是支付宝公钥,不是应用公钥,不然后边验签失败
    2. 在odoo 中上传的密钥文档首尾需要添加虚线:类似下图密钥格式,不然支付宝页面都打不开:
      image

    关于支付宝反馈支付成功的信息:

    1. 支付宝调用notify接口:
      调用这个接口会将payment.transations 的记录标为完成,但是并不会马上生成付款记录,也不会处理订单和发票,在odoo 中有一个Post process payment transactions的定时任务,每10分钟跑一次,跑的时候会把10分钟之前创建的交易记录处理掉,生成付款单,发票,并确认订单.
    2. 支付宝调用validate 接口:
      这个接口在支付完成后会跳转到该地址,验证通过后会再次跳转到/payment/process/接口,直接处理掉用户对应的订单付款信息,相对第一种速度较实时,,但是,存在用户直接关闭页面的情况,所以两种方式都必须存在.

    自动开票付款的代码:

    # 首先调用定时任务方法:
        @api.multi
        def _cron_post_process_after_done(self):
            if not self:
                ten_minutes_ago = datetime.now() - relativedelta.relativedelta(minutes=10)
                # we don't want to forever try to process a transaction that doesn't go through
                retry_limit_date = datetime.now() - relativedelta.relativedelta(days=2)
                # we retrieve all the payment tx that need to be post processed
                self = self.search([('state', '=', 'done'),
                                    ('is_processed', '=', False),
                                    ('date', '<=', ten_minutes_ago),
                                    ('date', '>=', retry_limit_date),
                                ])
            for tx in self:
                try:
                    tx._post_process_after_done()
                    self.env.cr.commit()
                except Exception as e:
                    _logger.exception("Transaction post processing failed")
                    self.env.cr.rollback()
    # 2. _post_process_after_done
        @api.multi
        def _post_process_after_done(self):
            self._reconcile_after_transaction_done()
            self._log_payment_transaction_received()
            self.write({'is_processed': True})
            return True
    # 3. _reconcile_after_transaction_done
        @api.multi
        def _reconcile_after_transaction_done(self):
            # Validate invoices automatically upon the transaction is posted.
            invoices = self.mapped('invoice_ids').filtered(lambda inv: inv.state == 'draft')
            invoices.action_invoice_open()
    
            # Create & Post the payments.
            payments = defaultdict(lambda: self.env['account.payment'])
            for trans in self:
                if trans.payment_id:
                    payments[trans.acquirer_id.company_id.id] += trans.payment_id
                    continue
    
                payment_vals = trans._prepare_account_payment_vals()
                payment = self.env['account.payment'].create(payment_vals)
                payments[trans.acquirer_id.company_id.id] += payment
    
                # Track the payment to make a one2one.
                trans.payment_id = payment
    
            for company in payments:
                payments[company].with_context(force_company=company, company_id=company).post()
    #  sale 模块重写了
        @api.multi
        def _reconcile_after_transaction_done(self):
            # Override of '_set_transaction_done' in the 'payment' module
            # to confirm the quotations automatically and to generate the invoices if needed.
            sales_orders = self.mapped('sale_order_ids').filtered(lambda so: so.state in ('draft', 'sent'))
            for so in sales_orders:
                # For loop because some override of action_confirm are ensure_one.
                so.with_context(send_email=True).action_confirm()
            # invoice the sale orders if needed
            self._invoice_sale_orders()
            res = super(PaymentTransaction, self)._reconcile_after_transaction_done()
            if self.env['ir.config_parameter'].sudo().get_param('sale.automatic_invoice'):
                default_template = self.env['ir.config_parameter'].sudo().get_param('sale.default_email_template')
                if default_template:
                    for trans in self.filtered(lambda t: t.sale_order_ids):
                        ctx_company = {'company_id': trans.acquirer_id.company_id.id,
                                       'force_company': trans.acquirer_id.company_id.id,
                                       'mark_invoice_as_sent': True,
                                       }
                        trans = trans.with_context(ctx_company)
                        for invoice in trans.invoice_ids:
                            invoice.message_post_with_template(int(default_template), notif_layout="mail.mail_notification_paynow")
            return res
    
    # 发票创建确认
        @api.multi
        def _invoice_sale_orders(self):
            if self.env['ir.config_parameter'].sudo().get_param('sale.automatic_invoice'):
                for trans in self.filtered(lambda t: t.sale_order_ids):
                    ctx_company = {'company_id': trans.acquirer_id.company_id.id,
                                   'force_company': trans.acquirer_id.company_id.id}
                    trans = trans.with_context(**ctx_company)
                    trans.sale_order_ids._force_lines_to_invoice_policy_order()
                    invoices = trans.sale_order_ids.action_invoice_create()
                    trans.invoice_ids = [(6, 0, invoices)]
    				
    

    总的流程:
    订单--> 交易记录完成--> 订单确认--> 创建发票并确认 --> 创建付款并提交


    懂得,原来世界如此简单!

  • 相关阅读:
    php 面向对象编程实例 __construct 和 __destruct 区别
    php 数组 类对象 值传递 引用传递 区别
    WebHttpBinding.ReaderQuotas 无法设置或者无法点出来
    XP IE8 安装失败
    把XML保存为ANSI编码
    更新RDL文件中的数据集(DataSets)
    真实赛车3,FERRARI之魂不买FERRARI 599 GTO可以解锁顶点系列。
    [转]一大波“关于BUG的类型”的图片 + 一小波笑话
    sdk manager 代理,解决下载速度慢的问题
    错误 1 缺少编译器要求的成员“System.Runtime.CompilerServices.ExtensionAttrib
  • 原文地址:https://www.cnblogs.com/qianxunman/p/15339618.html
Copyright © 2011-2022 走看看