first commit
This commit is contained in:
commit
eda8d5ae0d
3
conf/alipay/private.txt
Normal file
3
conf/alipay/private.txt
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCNEFKfj8jib0cWXyEml7I7cTKyUMAMJmcIfoNNeFcNvp7pNH8cB9QpHvQIOrPTwuyxw591iGWkLCzfKRJc1K594hl558OVrJrB7sM716jyCT1SOqlFcMvuk1Eq3ayMCTR2gyMqdnzaxbSedpPDFQXCXeT5AWDq+IPI1un32Qi35jl0sZu8Ve8KKzaFogig/MkDONShMb593B89p1qRie5HfeHMilcMy4Q1jJ7eo83Q2PfsE0NIuDj6gm38+GcFr3n0h24KeGUANkjU4DhBN2hKwqcpyPFmFio+JWIB8u8dH+8nKS81p8PgqeiKaeJEMWMes1VCeBtICoiyTVgYCpY9AgMBAAECggEALigdIOCnVpAarpNKAZq5UwHjGL2bWV5ncDwVMpAhy/mHfb8TqFRXc20RZG/wz2WElVXxI0ASIfniZNLHk2B0B/SnaWAQezUTHknF0BrsyOWFDxbqtDIISHQjpucJwnhwliaqpwZGLD9srj0WdEq4q7SVa3SsBbZzSJAp1lNJqwJJf7GZUL+5riuSSBBqv+ZExBEwFRlJL8mjOqlISgQQanU5N6ROr5h5vQ3kn2KsXNZdkroEVSA9aeCHn1nDZLE3qCRLhSyOCSmx4YqTO3neFYN50Zo7QoE40LLzSK5SACctp/AWzq12GN9f5iGya6mf+t4pKF/SjZ6ogFZo9QOCcQKBgQDB50aVaBSDsRLXcSFveFPUrOtIzOBmNtuaq96ibqHj+3fGmji6XKIoWN2Yd0Iet6CK7Ph0hKQgljtiaRWSi0cmkqZU4NvZerNWKWxBhnVBkZRqPdyHjEG47qJCaz7wv72S2kQTh3yBap8o/Mtt1M+2QDG0TkHfbjF2mI1q6dnzCwKBgQC6PRwHyArbcqCy48NGTgmxUBJhHIz1zKB/7xX+uPzUyMfvx4bHwwih8bL362zQMlpxwjm28qFQ8/Dh1/baavnrEztaqUChnD6sb2xENP26PNCmxoho71AInVnp0vKEYDw7jYfc5pvl46nlvK8ErbKeohL8gzfew7lit+sUP6lo1wKBgFr9zs+Z0daip7bV7dzDWIN6ycaV7c/JenAwqv8Kb4nunZxjDq/VfHr2iLZdcHe9r+bBoS38eJCaLy/VJDxqg28Ebm1yP3jk7XdHZPeywx+L01uvv+cT2FuSEC6e6SBMugdJyZxoffK1OA8h4cyeiwJ5SVnVR3Az455FpEdBifdVAoGABf5DcaipWMiGjVsxBIksXK1j+gYOLzbHj3ZlMc5ILJzNelTkbHdFRtjdVocX+Fc2e+SxMMb8E/vVq57kjcDVjBARX+iEcO7zQV9Qj51Y8O5WFJfc+euBmtVdeF3WehYSuiPi1GQDblF2PTNmOnNQhTRYAhJC8QNBawDaKsulqv8CgYA1fxxqgYqV3BKh4stzDnczt9bPMrCmWmwo2RkVykJMZv/jtXzefPOE27Q+COp5dxLxRnYnGc55B4COVov0p8y05KABOTvN1IJR5BwJLST+gofZW2X3Zd2swAVO758hbpDukKP1A3BeHFoe40S2udGqgntVsMHQhnWUlnDAH++C5A==
|
||||||
|
-----END RSA PRIVATE KEY-----
|
||||||
3
conf/alipay/public.txt
Normal file
3
conf/alipay/public.txt
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
-----BEGIN PUBLIC KEY-----
|
||||||
|
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAgD4YlfnWKd4vEHsim6vxLwustbnBBh9IUJwF5rGJ3b7wjYyzMnQZ36Cgf81A685IQ+Ni9GogNDaUWZx9V+qGxZRwaLbktSLnUNwPMudKlUoPyQtqyygU+Bmwg1B+UBzZsz8eG72qOuvu9xNbT72QZqFxzLlo0vzWldijnaPcqukUhTaeIYe1AObI9v3ySAa72GkGCHaSkQqvBLydCJt2mu3zJYhPMKre1oNmQkGYUxLKCwonbABaugOEl7t1vL8mAMlwFg2ihJbYiogGfr2Imt/Y1jy8rftiW41opX1UQ30rgfRYeuEsKvVwuoyqffGHeBSjs53xZkYStYKj0m+8AQIDAQAB
|
||||||
|
-----END PUBLIC KEY-----
|
||||||
16
conf/config.json
Normal file
16
conf/config.json
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"pay":{
|
||||||
|
"alipay":{
|
||||||
|
"public_key_file":"$[workdir]$/alipay/public.txt",
|
||||||
|
"private_key_file":"$[workdir]$/alipay/private.txt",
|
||||||
|
"appid":"2021005111636494",
|
||||||
|
"callback":"/api/callback/alipay"
|
||||||
|
},
|
||||||
|
"paypal":{
|
||||||
|
"mode":"sandbox",
|
||||||
|
"client_id":"myid",
|
||||||
|
"client_secret":"mysecret",
|
||||||
|
"return_url":"ret_url",
|
||||||
|
"cancel_url":"cancel_url"
|
||||||
|
}
|
||||||
|
}
|
||||||
1
pf_pay/__init__.py
Normal file
1
pf_pay/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
from .version import __version__
|
||||||
66
pf_pay/ali_pay.py
Normal file
66
pf_pay/ali_pay.py
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
from appPublic.jsonConfig import getConfig
|
||||||
|
from appPublic.worker import awaitify
|
||||||
|
from appPublic.log import debug, info, exception, error
|
||||||
|
from alipay import AliPay
|
||||||
|
|
||||||
|
class Zhifubao_Pay:
|
||||||
|
"""
|
||||||
|
config:{
|
||||||
|
"pay":{
|
||||||
|
"alipay":{
|
||||||
|
"public_key_file":,
|
||||||
|
"private_key_file":,
|
||||||
|
"appid":
|
||||||
|
"callback":
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
def __init__(self):
|
||||||
|
config = getConfig()
|
||||||
|
pubfile = config.pay.alipay.public_key_file
|
||||||
|
prifile = config.pay.alipay.private_key_file
|
||||||
|
appid = config.pay.alipay.appid
|
||||||
|
self.callback = config.pay.alipay.callback
|
||||||
|
"""
|
||||||
|
支付宝支付
|
||||||
|
传递参数:
|
||||||
|
out_trade_no : 订单
|
||||||
|
total_amount : 金额
|
||||||
|
subject : 产品
|
||||||
|
"""
|
||||||
|
with open(pubfile, 'r') as f:
|
||||||
|
alipay_public_key_string = f.read()
|
||||||
|
with open(prifile, 'r') as f:
|
||||||
|
app_private_key_string = f.read()
|
||||||
|
#alipay_appid = '2021005111636494'
|
||||||
|
self.alipay = AliPay(
|
||||||
|
appid=appid,
|
||||||
|
app_notify_url=self.callback, # 默认回调url
|
||||||
|
app_private_key_string=app_private_key_string,
|
||||||
|
# 支付宝的公钥,验证支付宝回传消息使用,不是自己的公钥,
|
||||||
|
alipay_public_key_string=alipay_public_key_string,
|
||||||
|
sign_type="RSA2", # RSA 或者 RSA2
|
||||||
|
debug=False, # 默认False
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def alipay_payment(self, out_trade_no, total_amount, subject):
|
||||||
|
order_string = self.alipay.api_alipay_trade_page_pay(
|
||||||
|
# 订单号
|
||||||
|
out_trade_no=out_trade_no,
|
||||||
|
# 金额
|
||||||
|
total_amount=total_amount,
|
||||||
|
# 产品
|
||||||
|
subject=subject,
|
||||||
|
# 回调地址和默认配置一样即可
|
||||||
|
return_url=self.callback,
|
||||||
|
notify_url=self.callback # 可选, 不填则使用默认notify url
|
||||||
|
)
|
||||||
|
url = f"https://openapi.alipay.com/gateway.do?{order_string}"
|
||||||
|
return url
|
||||||
|
|
||||||
|
async def alipay_callback_verify(self, data, sign):
|
||||||
|
f = awaitify(self.alipay.verify)
|
||||||
|
r = await f(data, sign)
|
||||||
|
return r
|
||||||
9
pf_pay/init.py
Normal file
9
pf_pay/init.py
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
from ahserver.serverenv import ServerEnv
|
||||||
|
from pf_pay.ali_pay import Zhifubao_Pay
|
||||||
|
|
||||||
|
def load_pf_pay():
|
||||||
|
g = ServerEnv()
|
||||||
|
zfb = Zhifubao_Pay()
|
||||||
|
g.alipay_payment = zfb.alipay_payment
|
||||||
|
g.alipay_callback_verify = zfb.alipay_callback_verify
|
||||||
|
|
||||||
47
pf_pay/paypal_pay.py
Normal file
47
pf_pay/paypal_pay.py
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
import os
|
||||||
|
import paypalrestsdk
|
||||||
|
from paypalrestsdk import Payment
|
||||||
|
|
||||||
|
paypalrestsdk.config({
|
||||||
|
"mode":"sandbox",
|
||||||
|
"client_id":"your id",
|
||||||
|
"client_secret":"your secret"
|
||||||
|
})
|
||||||
|
|
||||||
|
class TransItem:
|
||||||
|
class __init__(self, itemid, name, price, currency, quantity):
|
||||||
|
self.id = itemid
|
||||||
|
self.name = name
|
||||||
|
self.price = price
|
||||||
|
self.currency = currency
|
||||||
|
self.quantity = quantity
|
||||||
|
|
||||||
|
def dic(self):
|
||||||
|
return {
|
||||||
|
"name":self.name,
|
||||||
|
"sku":self.id,
|
||||||
|
"price":self.price,
|
||||||
|
"currency":self.currency,
|
||||||
|
"quantity":self.quantity
|
||||||
|
}
|
||||||
|
|
||||||
|
class OrderGoods:
|
||||||
|
|
||||||
|
class Paypal_Pay:
|
||||||
|
def __init__(self):
|
||||||
|
config = getConfig()
|
||||||
|
self.client_id = config.paypal.client_id
|
||||||
|
self.client_secret = config.paypal.client_secret
|
||||||
|
self.client_mode = "SANDBOX"
|
||||||
|
|
||||||
|
def get_products(self):
|
||||||
|
credentials = {
|
||||||
|
'client_id' : self.client_id,
|
||||||
|
'client_secret':self.client_secret,
|
||||||
|
'client_mode':self.client_mode
|
||||||
|
}
|
||||||
|
result = Products(credentials=credentials).list_product()
|
||||||
|
payload = result.payload()
|
||||||
|
return payload
|
||||||
|
|
||||||
|
|
||||||
1
pf_pay/version.py
Normal file
1
pf_pay/version.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
__version__ = '0.0.1'
|
||||||
108
pf_pay/weixin_pay.py
Normal file
108
pf_pay/weixin_pay.py
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
import time
|
||||||
|
import json
|
||||||
|
import random
|
||||||
|
import string
|
||||||
|
import io
|
||||||
|
|
||||||
|
import requests
|
||||||
|
|
||||||
|
from base64 import b64encode
|
||||||
|
from urllib.parse import urlparse
|
||||||
|
from Cryptodome.PublicKey import RSA
|
||||||
|
from Cryptodome.Signature import pkcs1_15
|
||||||
|
from Cryptodome.Hash import SHA256
|
||||||
|
import qrcode
|
||||||
|
from appPublic.jsonConfig import getConfig
|
||||||
|
from ahserver.globalEnv import save_file
|
||||||
|
from appPublic.uniqueID import getID
|
||||||
|
|
||||||
|
class WXPay:
|
||||||
|
""" 微信 Native支付
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.appid = "wx892972c8fb1005b4" # APPID
|
||||||
|
self.mchid = "1682646155" # 商户号
|
||||||
|
self.payment_url = 'https://api.mch.weixin.qq.com/v3/pay/transactions/native' # Native支付下单接口
|
||||||
|
self.refund_url = 'https://api.mch.weixin.qq.com/v3/refund/domestic/refunds' # 退款接口
|
||||||
|
self.notify_url = "https://www.kaiyuancloud.cn/dev/customer/get_weixpay.dspy" # 通知url
|
||||||
|
self.serial_no = '7B8C3F6F573F249EDD3ED6AA95EC632691BCB503' # 商户证书序列号
|
||||||
|
|
||||||
|
# 生成签名
|
||||||
|
def get_sign(self, sign_str):
|
||||||
|
config = getConfig()
|
||||||
|
# 线上证书路径
|
||||||
|
apiclient_key = config.weixinpay.private
|
||||||
|
rsa_key = RSA.importKey(open(apiclient_key).read())
|
||||||
|
signer = pkcs1_15.new(rsa_key)
|
||||||
|
digest = SHA256.new(sign_str.encode('utf8'))
|
||||||
|
sign = b64encode(signer.sign(digest)).decode('utf-8')
|
||||||
|
return sign
|
||||||
|
|
||||||
|
def request(self, url: str, method: str, data: dict = None):
|
||||||
|
data = json.dumps(data) if data else ''
|
||||||
|
random_str = ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(32))
|
||||||
|
timestamp = str(int(time.time()))
|
||||||
|
sign_str = '\n'.join([
|
||||||
|
method.upper(), # HTTP请求方法
|
||||||
|
url.split(urlparse(url).netloc)[-1], # path+args
|
||||||
|
timestamp, # 时间戳
|
||||||
|
random_str, # 请求随机串
|
||||||
|
data, '' # 请求报文主体
|
||||||
|
]) # 结尾空窜仅用于让后面多一个\n
|
||||||
|
sign = self.get_sign(sign_str)
|
||||||
|
|
||||||
|
headers = {
|
||||||
|
'Content-Type': 'application/json; charset=UTF-8',
|
||||||
|
'Authorization': f'WECHATPAY2-SHA256-RSA2048 mchid="{self.mchid}",nonce_str="{random_str}",signature="{sign}",timestamp="{timestamp}",serial_no="{self.serial_no}"'
|
||||||
|
}
|
||||||
|
response = requests.request(url=url, method=method, data=data, headers=headers)
|
||||||
|
return response
|
||||||
|
|
||||||
|
# # 支付
|
||||||
|
async def payment(self, order_no, total, description):
|
||||||
|
data = {
|
||||||
|
"mchid": self.mchid,
|
||||||
|
"out_trade_no": order_no, # 订单号
|
||||||
|
"appid": self.appid,
|
||||||
|
"description": description, # 商品描述
|
||||||
|
"notify_url": self.notify_url,
|
||||||
|
"amount": {
|
||||||
|
"total": total, # 总金额(分)
|
||||||
|
"currency": "CNY"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
num = self.request(self.payment_url, 'POST', data)
|
||||||
|
# 生成二维码
|
||||||
|
img = qrcode.make(num.json()['code_url'])
|
||||||
|
buf = io.BytesIO()
|
||||||
|
img.save(buf, format='PNG')
|
||||||
|
buf.seek(0, 0)
|
||||||
|
byt = buf.read()
|
||||||
|
imgurl = await save_file(byt, getID()+'.png')
|
||||||
|
return imgurl
|
||||||
|
|
||||||
|
# 退款
|
||||||
|
def refund(self, transaction_id, out_refund_no, refund, reason):
|
||||||
|
data = {
|
||||||
|
"transaction_id": transaction_id, # 微信支付订单号(交易单号)
|
||||||
|
"out_refund_no": out_refund_no, # 商户退款单号(商户单号)
|
||||||
|
"reason": reason, # 退款原因
|
||||||
|
"notify_url": self.notify_url, # 通知Url
|
||||||
|
"amount": {
|
||||||
|
"total": refund, # 订单金额
|
||||||
|
"refund": refund, # 退款金额(分)
|
||||||
|
"currency": "CNY"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return self.request(self.refund_url, 'POST', data)
|
||||||
|
|
||||||
|
def application_bill(self):
|
||||||
|
url = 'https://api.mch.weixin.qq.com/v3/bill/tradebill?bill_date=2022-02-28&bill_type=ALL'
|
||||||
|
return self.request(url, 'GET')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
async def pay_wx(order_no, total, description):
|
||||||
|
result = await WXPay().payment(order_no, total, description)
|
||||||
|
return result
|
||||||
4
requirements.txt
Normal file
4
requirements.txt
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
# python-paypal-api
|
||||||
|
paypalrestsdk
|
||||||
|
python-alipay-sdk
|
||||||
|
|
||||||
52
setup.py
Executable file
52
setup.py
Executable file
@ -0,0 +1,52 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from pf_pay.version import __version__
|
||||||
|
try:
|
||||||
|
from setuptools import setup
|
||||||
|
except ImportError:
|
||||||
|
from distutils.core import setup
|
||||||
|
required = []
|
||||||
|
with open('requirements.txt', 'r') as f:
|
||||||
|
ls = f.read()
|
||||||
|
required = ls.split('\n')
|
||||||
|
|
||||||
|
with open('pf_pay/version.py', 'r') as f:
|
||||||
|
x = f.read()
|
||||||
|
y = x[x.index("'")+1:]
|
||||||
|
z = y[:y.index("'")]
|
||||||
|
version = z
|
||||||
|
with open("README.md", "r") as fh:
|
||||||
|
long_description = fh.read()
|
||||||
|
|
||||||
|
name = "pf_pay"
|
||||||
|
description = "pf_pay"
|
||||||
|
author = "yumoqing"
|
||||||
|
email = "yumoqing@gmail.com"
|
||||||
|
|
||||||
|
package_data = {}
|
||||||
|
|
||||||
|
setup(
|
||||||
|
name="pf_pay",
|
||||||
|
version=version,
|
||||||
|
|
||||||
|
# uncomment the following lines if you fill them out in release.py
|
||||||
|
description=description,
|
||||||
|
author=author,
|
||||||
|
author_email=email,
|
||||||
|
platforms='any',
|
||||||
|
install_requires=required ,
|
||||||
|
packages=[
|
||||||
|
"pf_pay"
|
||||||
|
],
|
||||||
|
package_data=package_data,
|
||||||
|
keywords = [
|
||||||
|
],
|
||||||
|
url="https://github.com/yumoqing/pf_pay",
|
||||||
|
long_description=long_description,
|
||||||
|
long_description_content_type="text/markdown",
|
||||||
|
classifiers = [
|
||||||
|
'Operating System :: OS Independent',
|
||||||
|
'Programming Language :: Python :: 3',
|
||||||
|
'License :: OSI Approved :: MIT License',
|
||||||
|
],
|
||||||
|
)
|
||||||
Loading…
x
Reference in New Issue
Block a user