SoFunction
Updated on 2024-11-19

Python implementation of WeChat small program payment function

main body (of a book)

Because recently they are doing small program payments, here is a brief introduction to talk about using python to do small program payments this process. Of course, before proceeding with the development is still recommended to read the specific process, clear payment process.

1. Payment Interaction Flow

Of course, you can refer to the official documentation for specific parameter configurations/wiki/doc/api/wxa/wxa_api.php?chapter=7_3&index=1

2. Get openid (WeChat user identification)

 import requests
 from config import APPID, SECRET
 class OpenidUtils(object):
  def __init__(self, jscode):
    = "/sns/jscode2session"
    = APPID # applet id
    = SECRET # Don't confuse it with the key to pay later #
    = jscode # Dynamic jscode passed back from the front end
  def get_openid(self):
   # url must be spliced, not passed as a parameter
   url =  + "?app&secret=" +  + "&js_code=" +  + "&grant_type=authorization_code"
   r = (url)
   print(())
   openid = ()['openid']
   return openid

3. Payment requests

# -*- coding:utf-8 -*-
import requests
import hashlib
import xmltodict
import time
import random
import string
import urllib2
import sys
class WX_PayToolUtil():
 """ WeChat Payment Tools """
 def __init__(self, APP_ID, MCH_ID, API_KEY, NOTIFY_URL):
  self._APP_ID = APP_ID # Applet ID
  self._MCH_ID = MCH_ID # # Merchant number
  self._API_KEY = API_KEY
  self._UFDODER_URL = "/pay/unifiedorder" # Interface links
  self._NOTIFY_URL = NOTIFY_URL # Asynchronous notifications
 def generate_sign(self, param):
   '''Generate Signature'''
   stringA = ''
   ks = sorted(())
   # Parameter ordering
   for k in ks:
    stringA += (k + '=' + param[k] + '&')
   # Splice Merchant KEY
   stringSignTemp = stringA + "key=" + self._API_KEY
   # md5 encryption, or you can use other methods.
   hash_md5 = hashlib.md5(('utf8'))
   sign = hash_md5.hexdigest().upper()
   return sign
 '''
 # python2 another implementation
 def generate_sign(self, params):
  ret = []
  for k in sorted(()):
   if (k != 'sign') and (k != '') and (params[k] is not None):
    ('%s=%s' % (k, params[k]))
  params_str = '&'.join(ret)
  params_str = '%(params_str)s&key=%(partner_key)s' % {'params_str': params_str, 'partner_key': key}
  reload(sys)
  ('utf8')
  params_str = hashlib.md5(params_str.encode('utf-8')).hexdigest()
  sign = params_str.upper()
  return sign
 '''
 def getPayUrl(self, orderid, openid, goodsPrice, **kwargs):
  """Make a request to wechatpay to get the url"""
  key = self._API_KEY
  nonce_str = ''.join(( + , 30)) # Generate random strings, less than 32 bits
  params = {
   'appid': self._APP_ID, # Applet ID
   'mch_id': self._MCH_ID, # Merchant Number
   'nonce_str': nonce_str, # Random strings
   "body": 'Test Order', # Payment instructions
   'out_trade_no': orderid, # Order number generated
   'total_fee': str(goodsPrice), # Bid amount
   'spbill_create_ip': "127.0.0.1", # Applet can't get client ip, web implemented with socekt
   'notify_url': self._NOTIFY_URL,
   'trade_type': "JSAPI", # Type of payment
   "openid": openid, # user id
   }
  # Signature generation
  params['sign'] = self.generate_sign(params)
  # python3 one way to write
  param = {'root': params}
  xml = (param)
  response = (self._UFDODER_URL, data=('utf-8'), headers={'Content-Type': 'text/xml'})
  # xml 2 dict
  msg = 
  xmlmsg = (msg)
  # 4. Get prepay_id
  if xmlmsg['xml']['return_code'] == 'SUCCESS':
   if xmlmsg['xml']['result_code'] == 'SUCCESS':
    prepay_id = xmlmsg['xml']['prepay_id']
    # Time stamp
    timeStamp = str(int(()))
    # 5. five parameters
    data = {
     "appId": self._APP_ID,
     "nonceStr": nonce_str,
     "package": "prepay_signType": 'MD5',
     "timeStamp": timeStamp,
    }
    # 6. paySign signature
    paySign = self.generate_sign(data)
    data["paySign"] = paySign # Add signature
    # 7. Signed parameters passed to the front end
    return data
  # python2 one way to write
  '''
  request_xml_str = '<xml>'
  for key, value in ():
   if isinstance(value, str):
    request_xml_str = '%s<%s><![CDATA[%s]]></%s>' % (request_xml_str, key, value, key,)
   else:
    request_xml_str = '%s<%s>%s</%s>' % (request_xml_str, key, value, key,)
  request_xml_str = '%s</xml>' % request_xml_str
  # Make a request to WeChat Pay and fetch the return data
  res = (self._UFDODER_URL, data=request_xml_str.encode("utf-8"))
  res_data = (res)
  res_read = res_data.read()
  doc = (res_read)
  return_code = doc['xml']['return_code']
  if return_code == "SUCCESS":
   result_code = doc['xml']['result_code']
   if result_code == "SUCCESS":
    doc = doc['xml']
    data = {
     "appId": self._APP_ID,
     "nonceStr": nonce_str,
     "package": "prepay_prepay_id"],
     "signType": 'MD5',
     "timeStamp": str(int(())),
    }
    # paySign signatures
    paySign = self.generate_sign(data)
    data["paySign"] = paySign # Add signature
    return data
   else:
    err_des = doc['xml']['err_code_des']
    return err_des 
  else:
   fail_des = doc['xml']['return_msg']
   return fail_des
  '''

Of course you may encounter the error has a signature error, the general situation is that your appSecret and merchant number of the API key two get it wrong, of course, if not there may be other problems, solution linkhttps:///article/ 。

Other payment methods to get the user's ip address can be obtained through the (()) method.

4. Payment callback

# Harmonize order callback processing
import xmltodict
from  import HttpResponse
def payback(request):
 msg = ('utf-8')
 xmlmsg = (msg)
 return_code = xmlmsg['xml']['return_code']
 if return_code == 'FAIL':
  # An official error has been issued
  return HttpResponse("""<xml><return_code><![CDATA[FAIL]]></return_code>
       <return_msg><![CDATA[Signature_Error]]></return_msg></xml>""",
       content_type='text/xml', status=200)
 elif return_code == 'SUCCESS':
  # Get the order number for this payment
  out_trade_no = xmlmsg['xml']['out_trade_no']
  # Process business logic as needed
  return HttpResponse("""<xml><return_code><![CDATA[SUCCESS]]></return_code>
       <return_msg><![CDATA[OK]]></return_msg></xml>""",
       content_type='text/xml', status=200)

Of course, there are a lot of parameters for WeChat callbacks that you can refer to in detail./wiki/doc/api/wxa/wxa_api.php?chapter=9_7&index=8

In the callback time may encounter such a problem, after the successful payment did not call the callback function, it is possible that the callback address is https and then changed to http on the line, encountered this pit, the specific reasons do not know. The server does not block https access, https certificate is not a problem, change https to http last.

5. Security issues

In the process of using the merchant system for the content of the payment result notification must be done to verify the signature and check whether the returned order amount is the same as the merchant side of the order amount, to prevent data leakage leading to the emergence of "false notification", resulting in loss of funds.

My solution in the development process is to initiate a request to the WeChat payment terminal, the order number, amount, signature, etc. into the database, and then in the callback function there to verify the judgment. In the case of confirming the same situation with the previous order, before proceeding to a series of subsequent operations.

And finally, a blessing for all of you

#         _oo8oo_
#         o8888888o
#         88" . "88
#         (| -_- |)
#         0\ = /0
#        ___/'==='\___
#        .' \\|  |# '.
#       / \\||| : |||# \
#       / _||||| -:- |||||_ \
#       | | \\\ - #/ | |
#       | \_| ''\---/'' |_/ |
#       \ .-\__ '-' __/-. /
#      ___'. .' /-.-\ '. .'___
#      ."" '< '.___\_<|>_/___.' >' "".
#     | | : `- \`.:`\ _ /`:.`/ -` : | |
#     \ \ `-. \_ __\ /__ _/ .-` / /
#    =====`-.____`.___ \_____/ ___.`____.-`=====
#         `=---=`
#
#
#    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
#       

summarize

The above is a small introduction to the Python implementation of WeChat small program payment function, I hope to help you, if you have any questions please leave me a message, I will reply to you in a timely manner. I would also like to thank you very much for your support of my website!
If you find this article helpful, please feel free to reprint it, and please note the source, thank you!