我使用的是这位大佬的模块:
git clone https://github.com/block-cat/payment_alipay
测试这个模块的功能,折腾了一天,踩了不少的坑,还好有了点眉目,现在记录下:
关于公钥私钥的设置
- 在支付宝中设置好密钥以后,需要在odoo中进行设置,在odoo中设置的公钥是支付宝公钥,不是应用公钥,不然后边验签失败
- 在odoo 中上传的密钥文档首尾需要添加虚线:类似下图密钥格式,不然支付宝页面都打不开:
关于支付宝反馈支付成功的信息:
- 支付宝调用notify接口:
调用这个接口会将payment.transations 的记录标为完成,但是并不会马上生成付款记录,也不会处理订单和发票,在odoo 中有一个Post process payment transactions
的定时任务,每10分钟跑一次,跑的时候会把10分钟之前创建的交易记录处理掉,生成付款单,发票,并确认订单. - 支付宝调用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)]
总的流程:
订单--> 交易记录完成--> 订单确认--> 创建发票并确认 --> 创建付款并提交