当前位置:网站首页>5. Xuecheng project Alipay payment

5. Xuecheng project Alipay payment

2022-06-11 22:34:00 Python_ twenty-one

1. Alipay API file

* 1.  Official documents 
      Address : https://opendocs.alipay.com/common/02fwvj/

* 2.  Alipay API: Six interfaces   
      Address : https://docs.open.alipay.com/270/105900/

* 3.  Alipay workflow   
      Address : https://docs.open.alipay.com/270/105898/

* 4.  Alipay 8 Secondary asynchronous notification mechanism ( Alipay sends to our server. POST request ,  Ask for  success 7 Characters )
      Address : https://docs.open.alipay.com/270/105902/

2. Test payment in sandbox environment

2.1 testing procedure

 Sandbox environment is a simulation environment to assist developers in interface development and joint commissioning of main functions .
* 1.  Payment by computer website API: https://docs.open.alipay.com/270/105900/

* 2.  Real name authentication in sandbox environment 
	  Address : https://openhome.alipay.com/platform/appDaily.htm?tab=info

* 3.  complete RSA Key generation :https://docs.open.alipay.com/291/105971

* 4.  Set the application public key under the sandbox application of the development center : Fill in the contents of the generated public key file 

* 5. Python Alipay open source third-party framework :https://github.com/fzlee/alipay

* 6. pip install python-alipay-sdk --upgrade

* 7.  The key configuration format of the code 

    alipay_public_key.pem = """-----BEGIN PUBLIC KEY-----
     Alipay public key 
    -----END PUBLIC KEY-----"""

    app_private_key.pem = """-----BEGIN RSA PRIVATE KEY-----
     User private key 
    -----END RSA PRIVATE KEY-----"""

* 8.  Alipay gateway 

     real :https://openapi.alipay.com/gateway.do
     The sandbox :https://openapi.alipaydev.com/gateway.do  #  belt dev

2.2 Sandbox environment configuration

* 1.  authentication 
https://developers.alipay.com/dev/workspace/register?from=http%3A%2F%2Fopenhome.alipay.com%2Fplatform%2FappDaily.html

2022-06-03_00986

image-20220603210906653

image-20220603223019913

* 2.  Configure sandbox application 
     1.  Select web page & Mobile application 
     2.  Select the user-defined key for the interface signing method 
     3.  Public key mode -> Set up and view 

image-20220603221823833

* 3.  download & install   Alipay key generator 
      Download address : https://gw.alipayobjects.com/os/bmw-prod/02b946e1-9faf-4394-8004-d241443c874e.exe

image-20220603221934776

image-20220603222053414

GIF 2022-6-3 22-25-43

* 4.  Generate the key 

2022-06-03_00994

* 5.  Copy public key 

image-20220603223606697

* 6.  Fill the application public key into the sandbox 

image-20220603223527596

* 7.  Generating Alipay public key 

image-20220603223728884

* 8.  Sandbox account 

image-20220603223829186

* 9.  Download the sandbox version of Alipay client 

image-20220603223934032

image-20220604075423063

* 10.  Install the sandbox version of Alipay on the mobile terminal 
	   Buyer account number  aijatb2766@sandbox.com
       The login password  111111
       Payment password  111111

2022-06-03_00999

2.3 Test code

* 1.  install python-alipay-sdk modular 
     pip install python-alipay-sdk
     
      If throw ssl Related errors ,  It's missing pyopenssl modular 
     pip install pyopenssl
* 2.  Test code  ( There should be no extra space when setting the key )
from alipay import AliPay

#  Application private key 
app_private_key_string = """-----BEGIN RSA PRIVATE KEY----- MIIEpAIBAAKCAQEAhe3/9BI+qAaoRprc1f3liRA9v9WYL/n9Xp9Cc+PPcbkfrI/pN7q/GOaaYf521wbCEXmZYW4qQVX4mP4i2S05FwRu2B1/7Ux4oREyM+0vazHrBCNyE7erqGV2+8GsLDJRnyQXApbN79FR40+chrlc5Dt29mGCtv1DKz1l/mnNJKj0srP55joxXfLmDwfeLcNcTEblJsxpgi1TKlnEG0b/0RtkFhGGOsUrClNiLxBK5iZJBUt+QX2P97MDHj8BIqLqKITBe+aSbwHcDzl587S9cq1142y41NVhEjlC20+2iHsESA82HQo8iH7i1A6BzHvRlvk7HoUqeYb8p91ZLI0d7QIDAQABAoIBAAuppQ9RA2nIYqD7XV25JWLhKi9pXz5WS60Qu02yOd9SWqLBSXLT7U4yzqDX8utYqE+zQhsM59sWrHZOMySsXntVpH1nXDuC3EJSaAfDkMyJ5UhP+eAjr2wTod/chqy2mQr9ro9IKJjIppPf2+aTf7ZUQ1DDPwnGVjIOv7H+7qFRf/XBUVyyW1j4uwFlN/ZporDa7B6lwqWgH9+Yvo7w3/Pmjo78z2BKZzPQJa2sq3WxolcphDImflycHzno8jIn+QnB3XmlCu7yxsx4HYXMQMKY8i3gzPejdOdWsjbAuxI3mfyyELN2W8ZCpaZKWfKEhpxR4DA56byZtESWN+s1HmECgYEA7WFD1vhO2gwWyiFBzyu9yHOTpmcH6mBJ30Km7mErPHD3yHOiaCv59Ba4XTD629073m3Q2z6EXpmv7Fwz+uezac12BCBeg7AU9WfBJPiSHBRvwR4qXbZzbU91tElWDFYlwCmjd3Sp5oTGWSpWU/BW3hkxx6KYIwnYUIDIhTChCQUCgYEAkG9j4pp/XisOCUM3cQmTaUzDWZfOILDQUjrWCnLEHfPJPrX5qjtkSkZ8Z6Q4GjGNVg5m4i98VRGkt3rY0wsnsuCDFrws7TzlvDVP9fo0DgTalO4JCQ4gE9fGZypbjRYtbHobTEsGnGmeE3eRrlY5cfNfcwfrr1vKceo7slJzNckCgYAd+8kr4BVlqV0/js/XMTk5lo+x1xXC3wK1tp+LQK7LZaGGqkR7UAK0eCI1czhciSdEwy48YzspD9SO0F6odJfO52revo/xpk4faUmWN+eMsHAlPoAvchpGVmERsqmxyTffe+Lv9cZ4HZFINfbNh3ARgbEt/DWnR1kRYhLx7+CHWQKBgQCNWGTwkm9IsWu4Bs6P0WYwK04VNGklNsN3ZVqnuO5RvYxY0W71d8/KnDYMmvnIMGv3JnrqqLvM6EpAwHjF92mvNOU0b4yr0eelCqsoteURPxDFpDi1YtxjbssblKkpZeWn/csPG3DpyrZGqMGpUXpAGIJ1KPAtmO+CEU7AUM2seQKBgQDmPWXLUXx6FKRVUYLgALEY+PkIc3feRw1gdhSa7Q8/sQw8jugD92YnZ9gdBkZxIlPHqiMpvba+adbFTcTIPx6Myoy8X8mfWFTHU0su+tiwiUXGWkxAvYU/8ebSABs6HRgFGkbJEDU7TqPOvDCLFjAFdTQJ/LKGwbI+E7XfR0f4Sw== -----END RSA PRIVATE KEY-----"""

#  Alipay public key 
alipay_public_key_string = """-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtfLBZtfSKJ3mwThLuRnLO1eEh5jf2fXDlC06VLH/lmFFJrZBfkJqzE9T41k5JoGpluI6r03vo6Vx29UYOP0bf531UUr9Bpg2TLBwmUVQYoY15plsUjKkqTqDYq55m3cYJpn0TBROMyurbGs4i0TcNq35zjC2wbl0DWmxmOhWyg3NhUu9uqWUJGbfxTuowKQxaK/3XDoOLx+mQCytz0JvNevUhBhOu6eZLCh3hNOswu8gMf3a5kCReya24uXOd26SKd5HYlwFHk4ndSSjwIYulQs9hnlSbkJn+zykjc6qdDQLMWuqkSKlb5Snu7TCh5FNUO4KsFqk2bEXgysJy23lhwIDAQAB -----END PUBLIC KEY-----"""
alipay = AliPay(
    #  application id
    appid="2021000120612450",
    #  Default callback 
    app_notify_url=None,
    #  Apply private key string 
    app_private_key_string=app_private_key_string,
    #  Alipay public key string 
    alipay_public_key_string=alipay_public_key_string,
    #  encryption 
    sign_type="RSA2",  # RSA or RSA2
    #  Open the debug ( Online close )
    debug=True
)

#  default gateway ( It needs to be modified after going online )
alipay_url = 'https://openapi.alipaydev.com/gateway.do?'
#  Generating objects ( Transaction page )
order_string = alipay.api_alipay_trade_page_pay(
    #  The order number uniquely identifies 
    out_trade_no="202206041111",
    #  Price 
    total_amount=9.9,
    #  Name of commodity 
    subject='<< Shenbao >> A man should have a good kidney , You should drink kidney treasure . After drinking , Faster than Liu Xiang , Taller than Yao Ming . A bottle of refreshing , Two bottles never tire , Three bottles of immortality . Oh yeah ...',
    #  Successful payment  get Synchronous callback ,  Front desk display page , 
    # return_url="",
    #  Successful payment  post Asynchronous callback ,  Send a request back   Modify order status ( To pay for )
    # notify_url=""
)

#  Generate payment link  ( gateway  +  Transaction page )
print(alipay_url + order_string)

* 3.  Run the program ,  Get a commodity payment address :
https://openapi.alipaydev.com/gateway.do?app_id=2021000120612450&biz_content=%7B%22subject%22%3A%22%5Cu7537%5Cu4eba%5Cu8981%5Cu80be%5Cu597d%5Cuff0c%5Cu5c31%5Cu8981%5Cu559d%5Cu80be%5Cu5b9d%5Cu3002%5Cu559d%5Cu4e86%5Cu4e4b%5Cu540e%5Cuff0c%5Cu6bd4%5Cu5218%5Cu7fd4%5Cu5feb%5Cuff0c%5Cu6bd4%5Cu59da%5Cu660e%5Cu9ad8%5Cu3002%5Cu4e00%5Cu74f6%5Cu63d0%5Cu795e%5Cu9192%5Cu8111%5Cuff0c%5Cu4e24%5Cu74f6%5Cu6c38%5Cu4e0d%5Cu75b2%5Cu52b3%5Cuff0c%5Cu4e09%5Cu74f6%5Cu957f%5Cu751f%5Cu4e0d%5Cu8001%5Cu3002%5Cu5662%5Cu8036...%22%2C%22out_trade_no%22%3A%22%5Cu80be%5Cu5b9d%22%2C%22total_amount%22%3A9.9%2C%22product_code%22%3A%22FAST_INSTANT_TRADE_PAY%22%7D&charset=utf-8&method=alipay.trade.page.pay&notify_url=https%3A%2F%2Fwww.luffycity.com%2Ffree-course&return_url=https%3A%2F%2Fwww.luffycity.com%2Ffree-course&sign_type=RSA2&timestamp=2022-06-03+23%3A26%3A25&version=1.0&sign=BttMCJX7M6PGFNq1ldnaxR0HM1zLcVRbCeC7xmM3NDceOvs2U8tnRHmZb1gKlbozH2T8arQfPHrtJQ4dkjpptQHJMGWD6AU0cQzSi%2F4dI3m5GKEK4Y96w9OC1UNTjp80TXwZ1OlPCTzpHB4SAkjHeRSbxPXGJpvsvt7TjKOhEIbZ02xNAfawLa%2F2ptv6FXtplSb1ckmo1aV2k%2Fa8rQxRUVA52eeM9XNoH7GpoUiDAi47NZalgm1bcsrvrHfDizR83AU39hddA8EkqxFFAlFAOpVCRH6ZWSFgxJfTap4b6KkViYkaee74eELMgvG9qcuV9b04DB3JdFfbctl1VXyqrQ%3D%3D
* 4.  Use the browser to open the address ( If the browser opens too many websites ,  You may be prompted with tips like phishing sites .)

image-20220604074308312

* 5.  Use the sandbox version of Alipay to pay 

image-20220603234055655

* 6.  Check the balance in the sandbox account 

image-20220603233804278

3. Secondary packaging Alipay

 In the project lib Reseal Alipay under the directory 
 The configuration can be written in iPay Under the settings.py Of a document or project dev.py In profile .
lib
    ├── iPay  						  # aliapy Secondary package 
       ├── __init__.py 			   #  Package file 
       ├── pem						  #  Public and private key folder 
          ├── alipay_public_key.pem	#  Alipay public key file 
          ├── app_private_key.pem		#  Apply private key file 
       ├── pay.py					   #  Payment documents 
    └── └── settings.py | dev.py         #  Application configuration 
* 1.  In the project lib New under the directory iPay Catalog ,  Then create other files and directories according to the directory structure .
* 2.  stay app_private_key.pem Write Alipay public key in 
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAhe3/9BI+qAaoRprc1f3liRA9v9WYL/n9Xp9Cc+PPcbkfrI/pN7q/GOaaYf521wbCEXmZYW4qQVX4mP4i2S05FwRu2B1/7Ux4oREyM+0vazHrBCNyE7erqGV2+8GsLDJRnyQXApbN79FR40+chrlc5Dt29mGCtv1DKz1l/mnNJKj0srP55joxXfLmDwfeLcNcTEblJsxpgi1TKlnEG0b/0RtkFhGGOsUrClNiLxBK5iZJBUt+QX2P97MDHj8BIqLqKITBe+aSbwHcDzl587S9cq1142y41NVhEjlC20+2iHsESA82HQo8iH7i1A6BzHvRlvk7HoUqeYb8p91ZLI0d7QIDAQABAoIBAAuppQ9RA2nIYqD7XV25JWLhKi9pXz5WS60Qu02yOd9SWqLBSXLT7U4yzqDX8utYqE+zQhsM59sWrHZOMySsXntVpH1nXDuC3EJSaAfDkMyJ5UhP+eAjr2wTod/chqy2mQr9ro9IKJjIppPf2+aTf7ZUQ1DDPwnGVjIOv7H+7qFRf/XBUVyyW1j4uwFlN/ZporDa7B6lwqWgH9+Yvo7w3/Pmjo78z2BKZzPQJa2sq3WxolcphDImflycHzno8jIn+QnB3XmlCu7yxsx4HYXMQMKY8i3gzPejdOdWsjbAuxI3mfyyELN2W8ZCpaZKWfKEhpxR4DA56byZtESWN+s1HmECgYEA7WFD1vhO2gwWyiFBzyu9yHOTpmcH6mBJ30Km7mErPHD3yHOiaCv59Ba4XTD629073m3Q2z6EXpmv7Fwz+uezac12BCBeg7AU9WfBJPiSHBRvwR4qXbZzbU91tElWDFYlwCmjd3Sp5oTGWSpWU/BW3hkxx6KYIwnYUIDIhTChCQUCgYEAkG9j4pp/XisOCUM3cQmTaUzDWZfOILDQUjrWCnLEHfPJPrX5qjtkSkZ8Z6Q4GjGNVg5m4i98VRGkt3rY0wsnsuCDFrws7TzlvDVP9fo0DgTalO4JCQ4gE9fGZypbjRYtbHobTEsGnGmeE3eRrlY5cfNfcwfrr1vKceo7slJzNckCgYAd+8kr4BVlqV0/js/XMTk5lo+x1xXC3wK1tp+LQK7LZaGGqkR7UAK0eCI1czhciSdEwy48YzspD9SO0F6odJfO52revo/xpk4faUmWN+eMsHAlPoAvchpGVmERsqmxyTffe+Lv9cZ4HZFINfbNh3ARgbEt/DWnR1kRYhLx7+CHWQKBgQCNWGTwkm9IsWu4Bs6P0WYwK04VNGklNsN3ZVqnuO5RvYxY0W71d8/KnDYMmvnIMGv3JnrqqLvM6EpAwHjF92mvNOU0b4yr0eelCqsoteURPxDFpDi1YtxjbssblKkpZeWn/csPG3DpyrZGqMGpUXpAGIJ1KPAtmO+CEU7AUM2seQKBgQDmPWXLUXx6FKRVUYLgALEY+PkIc3feRw1gdhSa7Q8/sQw8jugD92YnZ9gdBkZxIlPHqiMpvba+adbFTcTIPx6Myoy8X8mfWFTHU0su+tiwiUXGWkxAvYU/8ebSABs6HRgFGkbJEDU7TqPOvDCLFjAFdTQJ/LKGwbI+E7XfR0f4Sw==
-----END RSA PRIVATE KEY-----
* 3.  stay alipay_public_key.pem Write the application private key to the file 
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtfLBZtfSKJ3mwThLuRnLO1eEh5jf2fXDlC06VLH/lmFFJrZBfkJqzE9T41k5JoGpluI6r03vo6Vx29UYOP0bf531UUr9Bpg2TLBwmUVQYoY15plsUjKkqTqDYq55m3cYJpn0TBROMyurbGs4i0TcNq35zjC2wbl0DWmxmOhWyg3NhUu9uqWUJGbfxTuowKQxaK/3XDoOLx+mQCytz0JvNevUhBhOu6eZLCh3hNOswu8gMf3a5kCReya24uXOd26SKd5HYlwFHk4ndSSjwIYulQs9hnlSbkJn+zykjc6qdDQLMWuqkSKlb5Snu7TCh5FNUO4KsFqk2bEXgysJy23lhwIDAQAB
-----END PUBLIC KEY-----
* 4. settings.py  Fill in the parameters in the configuration file 
import os

#  Get iPay The path of 
BASE_DIR = os.path.dirname(__file__)
print(BASE_DIR)
#  obtain iPay Under the pem Directory path 
PEM_DIR = os.path.join(BASE_DIR, 'pem')
#  Application private key address 
APP_PRIVATE_KEY_URL = os.path.join(PEM_DIR, 'app_private_key.pem')
#  Alipay public key address 
ALIPAY_PUBLIC_KEY_URL = os.path.join(PEM_DIR, 'alipay_public_key.pem')

#  application id
APPID = '2021000120612450'

#  Default callback 
APP_NOTIFY_URL = None

#  Apply private key string 
with open(APP_PRIVATE_KEY_URL, mode='r', encoding='utf8') as rf1:
    APP_PRIVATE_KEY_STRING = rf1.read()

#  Alipay public key string 
with open(ALIPAY_PUBLIC_KEY_URL, mode='r', encoding='utf8') as rf2:
    ALIPAY_PUBLIC_KEY_STRING = rf2.read()

#  encryption 
SIGN_TYPE = "RSA2"

# BUG Pattern 
DEBUG = True

#  Sandbox gateway  ( DEBUG = True )
dev = 'https://openapi.alipaydev.com/gateway.do?'

#  Real gateway  ( DEBUG = False )
master = 'https://openapi.alipay.com/gateway.do?'

#  gateway 
ALIPAY_URL = dev if DEBUG else master

* 5.  stay pay.py Generate alipay Payment object 
#  Import configuration parameters 
from .settings import *

#  Import AliPay modular 
from alipay import AliPay

#  Generate alipay object 
alipay = AliPay(
    #  application id
    appid=APPID,
    #  Default callback 
    app_notify_url=APP_NOTIFY_URL,
    #  Apply private key string 
    app_private_key_string=APP_PRIVATE_KEY_STRING,
    #  Alipay public key string 
    alipay_public_key_string=ALIPAY_PUBLIC_KEY_STRING,
    #  encryption 
    sign_type=SIGN_TYPE,
    #  Commissioning switch ( Online settings False)
    debug=False,

)

* 6. __init__.py  Import alipay object   And   gateway 
      In the import iPay Will automatically trigger __init__.py, Then import alipay object   And   gateway 
#  Import alipay object   And   gateway 
from .pay import alipay
from .settings import ALIPAY_URL

"""  In the import iPay Import when alipay object   And   gateway  from luffy/lib import iPay iPay.alipay ... iPay.ALIPAY_URL ... """

4. Order interface

4.1 establish app

* 1.  New order app
cd luffy/apps/
python ../../manage.py startapp order
* 2.  register app
INSTALLED_APPS = [
    ...
    'order'
* 3.  Total routing configuration 
path('order/', include('order.urls')),
* 4.  Sub route  
      First in order New under the directory urls.py
from django.urls import re_path, include

from . import views
#  Import SimpleRouter
from rest_framework.routers import SimpleRouter

#  Generating objects 
router = SimpleRouter()
#  Registered routing 
router.register('pay', views.PayView, 'pay')

#  The routing list 
urlpatterns = [
    re_path('', include(router.urls)),
]

4.2 Table settings

1.  The order sheet 
2.  The third table of the order form and the curriculum 
from django.db import models

#  Import user table 
from user.models import User
#  Import the curriculum 
from course.models import Course


#  The order sheet 
class Order(models.Model):
    """  User table ( One )  Yes  ( many ) The order sheet   A user can have multiple orders ,  An order can only have one user .  One-to-many relation ,  The associated field is written on the more side . """
    #  Payment status 
    status_choices = (
        (0, ' Did not pay '),
        (1, ' Paid '),
        (2, ' With timeout '),
        (3, ' Time out cancellation ')
    )

    #  Payment status 
    pay_choices = (
        (0, ' Alipay '),
        (1, ' WeChat ')
    )

    #  Order label 
    subject = models.CharField(max_length=150, verbose_name=' Order title ')
    #  The order price 
    total_amount = models.DecimalField(max_digits=10, decimal_places=2, verbose_name=' The order price ', default=0)
    #  The order number   only 
    out_trade_no = models.CharField(max_length=64, verbose_name=' The order number ', unique=True)
    #  The order status 
    order_status = models.SmallIntegerField(choices=status_choices, default=0, verbose_name=' The order status ')
    #  Method of payment 
    pay_type = models.SmallIntegerField(choices=pay_choices, default=0, verbose_name=' Method of payment ')
    #  Time of payment 
    pay_time = models.DateTimeField(null=True, verbose_name=' Time of payment ')
    #  Foreign keys 
    user = models.ForeignKey(to=User, related_name='order_user', on_delete=models.DO_NOTHING, db_constraint=False,
                             verbose_name=' Order user ')
    #  Creation time 
    created_time = models.DateTimeField(auto_now_add=True, verbose_name=' Creation time ')
    #  Last update time 
    updated_time = models.DateTimeField(auto_now=True, verbose_name=' Last update time ')

    #  Define metaclass 
    class Meta:
        #  Table name 
        db_table = 'luffy_order'
        #  Define a variable 
        verbose_name = ' Order records '
        #  Table name displayed in the background 
        verbose_name_plural = verbose_name

    #  Display the name and price of the product when printing the object 
    def __str__(self):
        return f'{
      self.subject} - ¥:{
      self.total_amount}'


#  Order details 
class OrderDetail(models.Model):
    """  The order sheet ( many )  Yes  ( many ) The curriculum   One order can have multiple courses ,  A course can be in pairs of orders   The third table is the foreign key associated order table ,  Associated curriculum ,  Create additional fields  """
    #  Foreign keys   Associated order table 
    order = models.ForeignKey(to=Order, related_name='order_courses', on_delete=models.CASCADE, db_constraint=False,
                              verbose_name=' Order foreign key ')
    #  Foreign keys   Associate associate curriculum 
    course = models.ForeignKey(to=Course, related_name='course_orders', on_delete=models.CASCADE, db_constraint=False,
                               verbose_name=' Course foreign key ')
    #  The original price 
    price = models.DecimalField(max_digits=6, decimal_places=2, verbose_name=' Course the original price ')
    #  Firm price 
    real_price = models.DecimalField(max_digits=6, decimal_places=2, verbose_name=' The course is real ')

    #  Define metaclass 
    class Meta:
        #  Table name 
        db_table = 'luffy_order_detail'
        #  Define a variable 
        verbose_name = ' Order details '
        #  Orientation details 
        verbose_name_plural = verbose_name

    #  Show when printing objects   Course name : Price of course 
    def __str__(self):
        try:
            return f'{
      self.course.name} The order of : {
      self.order.out_trade_no}'
        #  No error will be reported if no data is recorded 
        except:
            return super().__str__()

 Database migration :
python manage.py makemigrations
python manage.py migrate
#  modify order In the catalog admin.py  File to register the table in the background 
import xadmin

from . import models
#  Transfer the conditions on the order table and order details table to the background management 
xadmin.site.register(models.Order)
xadmin.site.register(models.OrderDetail)

#  The Chinese menu is displayed in the background 
#  modify order Under the __init__.py
default_app_config = "order.apps.OrderConfig"

#  modify order Under the apps.py
from django.apps import AppConfig


class OrderConfig(AppConfig):
    name = 'order'
    verbose_name = ' Order '

4.3 Interface

 Payment interface analysis 
1.  Payment interface 
    Generate order ,  Generate payment connection ,  Return to the payment link 
   
2.  When payment is successful :  Asynchronous callback of Alipay post Interface 
    Verify the signature ,  Modify order status 

3.  When payment is successful :  Alipay sync get Callback  ( Page displayed after successful payment )
   vue When creating a page   The life cycle hook function sends a request to the backend to query the order status ( not essential )
   
1.  Order total price verification 
    Get the corresponding course object from the database ,  The course price is taken out and accumulated ,  Then compare with the value passed by the front end to see if it is equal .
2.  Generate order number 
    Use one uuid Generate a random string 
3.  Payment link generation 
    Use your own encapsulated Alipay module to generate payment connections ,  Store the payment link in the... Of the serialized object context Properties of the .
4. request.user  Get user object in 
    View class create Method ,  by context The parameter setting value is request,  Get the user object from the serialization 
5.  Put in storage ( Two tables ) Information preparation for 
    Save user objects to attrs In the dictionary 
6.  Override serialized create Method 
    Change the course from validated_data In the dictionary pop come out ...
    First create the data of the payment table ,  After traversing the data that creates the payment details table 
* 1.  Model serializer 
#  Import model serialization 
from rest_framework import serializers

#  Import model layer 
from . import models

#  Import exception module 
from rest_framework.exceptions import ValidationError


class OrderModelSerializer(serializers.ModelSerializer):
    course_obj = models.Course.objects.all()
    """ PrimaryKeyRelatedField  take  {'course': [ Course id1,  Course id2, ...]}  To  {'course': [ Course 1_obj,  Course 2_obj, ...]} queryset Parameter for conversion table queryset object ,  The submitted value is a list ,  Set up many=True,  Write only mode  Course Table and  Order Yes, it doesn't matter , Just set queryset The parameter value of is the data of a table   adopt id Get the data object corresponding to the table  """
    course = serializers.PrimaryKeyRelatedField(queryset=course_obj, many=True, write_only=True)

    class Meta:
        model = models.Order

        #  Converted fields   Order label   Price   Method of payment   Purchased courses 
        fields = ['subject', 'total_amount', 'pay_type', 'course']
        # ( Set the default value ,  The price will not be indicated   The payment method field is required ,  Use require Prompt field must be filled in )
        extra_kwargs = {
    
            'total_amount': {
    'required': True},
            'pay_type': {
    'required': True},
        }

    #  Global verification 
    def validate(self, attrs):
        # 1.  Check the price ,  If the verification fails, an exception will be thrown directly ,  Price returned after successful verification 
        total_amount = self._check_price(attrs)
        # 2.  Generate order number 
        out_trade_no = self._gen_out_trade_no()
        # 3.  Generate a payment link and save it to context Parameters in 
        self._gen_pay_url(attrs, out_trade_no, total_amount)
        # 4.  Get user object   Override... In the view class create Method ,  When the model serialization object is generated request adopt context Parameter passing 
        user_obj = self._get_user()
        # 5.  Prepare before writing to the database 
        self._before_create(attrs, user_obj, out_trade_no)

        return attrs

    #  Price check 
    @staticmethod
    def _check_price(attrs):
        #  Get the price submitted 
        total_amount = attrs.get('total_amount')
        #  Get the course object 
        course_list = attrs.get('course')
        #  Calculate the price in the database 
        total_price = 0
        for course_obj in course_list:
            total_price += course_obj.price
        #  The judgment values are all equal 
        if total_amount != total_price:
            #  The prices are not the same ,  Throw an exception directly 
            raise ValidationError(' The price is illegal ')
        return total_amount

    #  Generate order number 
    @staticmethod
    def _gen_out_trade_no():
        #  The order number is a unique string ,  Use uuid that will do 
        from uuid import uuid4
        # uuid The format of the type value of  bce5eed9-8985-42ab-b37a-51bf8909c1c5  The type is  <class 'uuid.UUID'>
        #  Change the class type to str type ,  then - Remove  bce5eed9898542abb37a51bf8909c1c5
        return str(uuid4()).replace('-', '')

    #  Generate payment link 
    def _gen_pay_url(self, attrs, out_trade_no, total_amount):
        #  Import payment module 
        from luffy.lib import iPay
        #  Get the product name ( Front end incoming )
        subject = attrs.get('subject')
        #  Import callback address 
        from django.conf import settings
        #  default gateway 
        alipay_url = iPay.ALIPAY_URL

        # total_amount yes Decimal type ,  Alipay cannot recognize ,  To float The type is enough 
        print(total_amount, type(total_amount))  # 138.00 <class 'decimal.Decimal'>
        total_amount = float(total_amount)
        #  Generating objects 
        order_string = iPay.alipay.api_alipay_trade_page_pay(
            #  The order number uniquely identifies 
            out_trade_no=out_trade_no,
            #  Price 
            total_amount=total_amount,
            #  Name of commodity 
            subject=subject,
            #  Successful payment  get Synchronous callback ,  Front desk display page ,
            return_url=settings.NOTIFY_URL,
            #  Successful payment  post Asynchronous callback ,  Send a request back   Modify order status ( To pay for )
            notify_url=settings.RETURN_URL
        )
        #  Generate payment address 
        pay_url = alipay_url + order_string
        #  Save the payment link to context in 
        self.context['pay_url'] = pay_url

    #  Get users 
    def _get_user(self):
        #  from context In order to get request object 
        request = self.context.get('request')
        #  Put back user object ( After successful login request.user There will be user data objects )
        return request.user

    #  Prepare before writing data 
    @staticmethod
    def _before_create(attrs, user_obj, out_trade_no):
        #  Write the user object to the serialization Dictionary 
        attrs['user'] = user_obj
        #  Write the order number to the serialization Dictionary 
        attrs['out_trade_no'] = out_trade_no

    def create(self, validated_data):
        #  Make the course list a virtual field pop fall 
        course_list = validated_data.pop('course')

        #  Payment table data writing ( Data required , 'subject', 'total_amount', 'course', 'user')
        order_obj = models.Order.objects.create(**validated_data)

        #  Write in the payment details table ,  Data required (order, course, price, real_price)
        for course_obj in course_list:
            models.OrderDetail.objects.create(order=order_obj, course=course_obj, price=course_obj.price,
                                              real_price=course_obj.price)

        #  Return the payment object to ,  It doesn't need to be returned 
        return order_obj

#  Alipay callback address 
#  backstage URL
BASE_URL = 'http://127.0.0.1:8000'
#  The front desk URL
LUFFY_URL = 'http://127.0.0.1:8080'

#  Background asynchronous callback address 
RETURN_URL = BASE_URL + '/order/success/'
#  Foreground synchronous callback address ( No, / ending )
NOTIFY_URL = LUFFY_URL + '/pay/success'

* 2.  View class 
     Use alone rest_framework_jwt.authentication.JSONWebTokenAuthentication All tourists can visit , 
    request.user  yes AnonymousUser  Anonymous users ,  Use rest_framework Built in permission class ,  Verify the logged in user , 
     Anonymous users are forbidden to access !
from rest_framework.viewsets import GenericViewSet
from rest_framework.mixins import CreateModelMixin
from . import models
from .serializer import OrderModelSerializer
from rest_framework.response import Response
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
from rest_framework.permissions import IsAuthenticated


#  Generate payment order 
class PayView(GenericViewSet, CreateModelMixin):
    #  Login authentication class  +  Restricted class   It is now restricted to only logged in users 
    authentication_classes = [JSONWebTokenAuthentication]  #  No user login returned 
    permission_classes = [IsAuthenticated]
    #  Table data used 
    queryset = models.Order.objects.all()
    #  Model serialization class used 
    serializer_class = OrderModelSerializer

    #  Override the view class  create Method  ( Copy CreateModelMixin Of create Method to modify )
    def create(self, request, *args, **kwargs):
        #  When generating serializer ,  take request Object is created to the model serializer   adopt context Parameters 
        serializer = self.get_serializer(data=request.data, context=request)
        #  Check the data 
        serializer.is_valid(raise_exception=True)
        #  Save the data 
        self.perform_create(serializer)
        headers = self.get_success_headers(serializer.data)
        return Response(serializer.context.get('pay_url'))

4.4 The interface test

* 1.  Address of the interface : http://127.0.0.1:8000/order/pay/

image-20220608211000598

* 2.  You need to log in first (post request )
      Login address : http://127.0.0.1:8000/user/login/?username=root&password=zxc123456

image-20220608211435407

* 3.  carry token Access the payment interface 
key: Authorization 
value: jwt eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VybmFtZSI6InJvb3QiLCJleHAiOjE2NTUyOTg4NTYsImVtYWlsIjoiMTM2QHFxLmNvbSJ9.7vHsFCMCM-8_Uc5-bOvEFMvUf4d5fBtCGayQG53mb2c
* token Carry in front  jwt Space 

image-20220608212010864

* 4.  Illegal price test 
	  All three courses are now ,  price is 138,  Now fill in a wrong price 

image-20220608212348631

* 5.  Price normal test ,  Return the payment address 

image-20220608220622293

4.5 Click the purchase event at the front desk

 Bind events for click to buy ,  Free course page ,  Page details ,  Search page ,  Three places .
 Only when there are users can they buy :
 After successful login  this.$cookies.set('token', response.data.token)  take token Saved to scookies in 
 First from cokkies In order to get token,  If there is a value, you can send a request ,  If there is no value, the user will be prompted to log in .

 Get the payment address and jump to the payment page ( New page )
window.open(url)  Abbreviation  open(url) 
 Open the URL on the current page 
open(url, '_self')
<span class="buy-now" @click="buy_now(course)"> Buy now </span>
//  Purchase course 
buy_now(course) {
    
    //  from cookies In order to get token
    let token = this.$cookies.get('token')
    //  Determine whether it is in login status 
    if (!token) {
    
        //  Prompt the user to log in 
        this.$message({
    
            message: ' Please log in first !'
        })
        return false
    }
    //  The user has logged in and sent a request to the background 
    this.$axios({
    
        method: 'post', url: this.$settings.base_url + '/order/pay/',
            headers: {
    Authorization: 'jwt ' + token}, data: {
    
                //  The name of the course serves as the title of the product 
                "subject": course.name,
                //  The price of the course 
                "total_amount": course.price,
                //  Method of payment 
                "pay_type": 1,
                //  Curriculum id
                "course": [
                course.id
                ]
        }
    }).then(response => {
    
        //  Visit successfully to get the payment link   Directly from response.data Get data in ( The back end directly returns the link ,  Not return request.data)
        //  An error is reported in the view serializer   Need from response.data.dat Get error information in 
        // console.log(response.data)
        //  Jump to the payment address 
        if (response.data.data) {
    
            this.$message({
    
                message: response.data.data  //  Very new   for example  { "total_amount": [ " This field is required ." ] }
            })
            return false
        }
        //  If the error message is not returned, it is the payment link 
        let pay_url = response.data

        // console.log(pay_url)
        //  Jump to payment link 
        open(pay_url, '_self')

    }).catch(error => {
    
        this.$message({
    
            message: ' Unknown error ,  Please contact the Administrator !'
        })
    })
}

GIF 2022-6-9 11-31-26

4.6 Synchronous callback page

 Two parts :
1.  Analyze the Alipay callback parameters to display the payment status of the order 
2.  To the back end get request ,  Query whether the backend modifies the order status 
* 1.  Create a new page for successful payment presentation  PayCourse.vue
<template>
  <div class="pay-success">
    <!-- If it is a separate page , There's no need to show the navigation bar ( User with login )-->
    <Header/>
    <div class="main">
      <div class="title">
        <div class="success-tips">
          <p class="tips"> You have successfully purchased  1  Courses !</p>
        </div>
      </div>
      <div class="order-info">
        <p class="info"><b> The order number :</b><span>{
   { result.out_trade_no }}</span></p>
        <p class="info"><b> Transaction No :</b><span>{
   { result.trade_no }}</span></p>
        <p class="info"><b> Time of payment :</b><span><span>{
   { result.timestamp }}</span></span></p>
      </div>
      <div class="study">
        <span> Learn now </span>
      </div>
    </div>
  </div>
</template>

<script> import Header from "@/components/Head" export default {
       name: "PayCourse", data() {
       return {
       result: {
      }, }; }, created() {
       // location.search  obtain  url Parameters of rear splicing :? And all subsequent parameters  => ?a=1&b=2 // console.log(location.search); //  Analysis of Alipay callbacks url Parameters  let params = location.search.substring(1); //  Remove ?  Retain  a=1&b=2 //  Press & Shard to get a tuple ,  There must be an empty tuple  let items = params.length ? params.split('&') : []; // console.log(items) /* 0: "charset=utf-8" 1: "out_trade_no=1c6bd7ee950842249a7cb0b6956224d2" ... */ //  Add each item to... One by one args In the object  for (let i = 0; i < items.length; i++) {
       //  First cycle a=1, The second time b=2 //  Press = Cut to get  k = v let k_v = items[i].split('='); // ['a', '1'] //  List elements are less than 2 Direct to ignore ,  There are key missing values  if (k_v.length >= 2) {
       // url Coded inverse solution   Decoding operation , Because the query string is encoded  //  decode k let k = decodeURIComponent(k_v[0]); //  decode value  And save to result In the object  this.result[k] = decodeURIComponent(k_v[1]); } } //  Results after analysis  // console.log(this.result); /* app_id: "2021000120612450" auth_app_id: "2021000120612450" charset: "utf-8" */ //  Put the payment result on the address bar , Again get Forward request to backend  this.$axios({
       method: 'get', //  Access the backend with parameters of synchronous callback  url: this.$settings.base_url + '/order/success/' + location.search, }).then(response => {
       console.log(response.data) if (response.data) {
       this.$message({
       message: ' Payment results synchronized successfully ' }) } else {
       this.$message({
       message: ' Payment result synchronization failed ' }) } }).catch(() => {
       this.$message({
       message: ' Failed to query order payment status ' }) }) }, components: {
       Header, } } </script>

<style scoped> .main {
       padding: 60px 0; margin: 0 auto; width: 1200px; background: #fff; } .main .title {
       display: flex; -ms-flex-align: center; align-items: center; padding: 25px 40px; border-bottom: 1px solid #f2f2f2; } .main .title .success-tips {
       box-sizing: border-box; } .title img {
       vertical-align: middle; width: 60px; height: 60px; margin-right: 40px; } .title .success-tips {
       box-sizing: border-box; } .title .tips {
       font-size: 26px; color: #000; } .info span {
       color: #ec6730; } .order-info {
       padding: 25px 48px; padding-bottom: 15px; border-bottom: 1px solid #f2f2f2; } .order-info p {
       display: -ms-flexbox; display: flex; margin-bottom: 10px; font-size: 16px; } .order-info p b {
       font-weight: 400; color: #9d9d9d; white-space: nowrap; } .study {
       padding: 25px 40px; } .study span {
       display: block; width: 140px; height: 42px; text-align: center; line-height: 42px; cursor: pointer; background: #ffc210; border-radius: 6px; font-size: 16px; color: #fff; } </style>
* 2.  Set up PayCourse The routing 
//  Import payment success prompt page  import PayCourse from "@/views/PayCourse" //  Payment success prompt page  ( It is consistent with the configuration in the background )
{
    
    path: '/pay/success',
    name: 'PayCourse',
    component: PayCourse
},
#  Foreground synchronous callback address ( No, / ending )
RETURN_URL = LUFFY_URL + '/pay/success'
* 3. vue in url Extra in the address /#/
      If it is not deleted, the callback address route matching will not succeed 
     http://127.0.0.1:8080/pay/success  Route matching failed 
//  Set in the route  mode: "history",  Delete url The superfluous /#/
const router = new VueRouter({
    
    mode: "history",
    routes
})

* 4.  Buy course tests ,  After successful purchase 
      The callback address carries parameters 

 token url + Parameters 
http://127.0.0.1:8080/pay/success?
//  Coding format 
charset=utf8
//  The order number 
&out_trade_no=ffb82dd39bf043808c311b4ae983d9ec&method=alipay.trade.page.pay.return
//  Price 
&total_amount=39.00
//  Signature 
&sign=KFPDpjwAGuUa73qsBctb0m9Nj0514PoQnxcMyH%2Fzw1rPmzY%2F1%2BTwH2v4BB1hSyc5%2BRV6TIc%2Bvz1SrchxtND20HU%2BOjLuT%2BxSlGK034OFUDpxtiy4ofkYWWqcvxz84sQ8BUifdGKWDFoH1cgagbJVGl3DO1Lce5HbsvNZY2GeYQTC%2BTIWCUMKCcWYP375%2FQFCFoMUWj6LNcIQk3rrKMNJm9B%2F%2BwryrcRMJT1cNZnuLhKiYTzcIFRWnDyVu4aVfKa3xJtIEbTKAqIVHK9LuV%2BkrkBqD1GAwOy1gwIlrkB4VJ%2BvwPuyRpmVzGK7zVq6JIVzZNVawjFBhduwuoG0eUH7oA%3D%3D
//  Alipay serial number 
&trade_no=2022060922001441860503213387
//  Authorized merchant App id
&auth_app_id=2021000120612450
//  edition 
&version=1.0
//  application id
&app_id=2021000120612450
//  Signature type 
&sign_type=RSA2
//  seller id
&seller_id=2088621959339670
//  Time stamp 
&timestamp=2022-06-09+11%3A50%3A44#/
location.search  obtain  url Parameters of rear splicing 
 Remove first ?  Press & Partition to get tuples ,  Elements of tuples 'k=v',
 In traversing elements ,  Press = Shard to get a tuple  ['k', 'v']
 Yes k, v To decode and save the characters in an object 

image-20220609125826707

4.7 Order status interface

1.  Query order status interface  get request   
2.  Modify the order status interface  post request  
* 1.  route order.py Of urls.py
#  Order status interface 
re_path('success', views.SuccessView.as_view())
#  Payment status 
class SuccessView(APIView):
    @staticmethod
    def get(request):
        #  Get the order number from the parameter and query the order status in the database 
        out_trade_no = request.query_params.get('out_trade_no')
        order_obj = models.Order.objects.filter(out_trade_no=out_trade_no).first()
        #  The order status 
        order_status = order_obj.order_status
        #  Judge the order status 
        if order_status != 1:  # 1  Payment success status 
            return Response(False)
        return Response(True)

    #  Alipay asynchronous callback ( Can only be accessed after online ,  Alipay can't access the local address of my computer )
    @staticmethod
    def post(request):
        #  Import payment class 
        from lib.iPay import alipay
        from utils.logger import log

        #  Get the order number 
        out_trade_no = request.data.get('out_trade_no')
        #  Get payment time 
        pay_time = request.data.get('gmt_payment')

        #  Verify the signature   Returned by Alipay urlencode The format is changed to queryset_dict
        data = request.data.dict()  #  Set as normal field 
        sign = data.pop('sign')
        success = alipay.verify(data, sign)
        #  Verify success ,  also  data in trade_status The value of must be TRADE_SUCCESS or TRADE_FINISHED
        if success and data['trade_status'] in ('TRADE_SUCCESS', 'TRADE_FINISHED'):
            #  Update order status and payment time 
            models.Order.objects.filter(out_trade_no=out_trade_no).update(order_status=1, pay_time=pay_time)

            #  Log 
            log.info(f'{
      out_trade_no} Successful payment ')

            return Response('success')  #  If the verification is successful, you must return success

        log.info(f'{
      out_trade_no} Failure to pay ')
        return Response('error')  #  Validation failed 

5. Upload to remote warehouse

 stay Terminai Input in git command 
5.1 front end
#  Add to the staging area 
PS D:\vue\luffy_vue> git add .
#  Commit to the repository 
PS D:\vue\luffy_vue> git commit -m ' Complete the payment page '
#  The drop-down 
PS F:\synchro\Project\luffy> git pull origin dev                        
#  Upload to remote warehouse 
PS F:\synchro\Project\luffy> git push origin dev
5.2 Back end
#  Add to the staging area 
PS F:\synchro\Project\luffy> git add .    
#  Commit to the repository 
PS F:\synchro\Project\luffy> git commit -m ' Complete the payment function '
#  The drop-down 
PS F:\synchro\Project\luffy> git pull origin dev                        
#  Upload to remote warehouse 
PS F:\synchro\Project\luffy> git push origin dev
原网站

版权声明
本文为[Python_ twenty-one]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/162/202206112144319852.html