Compare commits
2 Commits
a829be47d5
...
b91923c44f
| Author | SHA1 | Date |
|---|---|---|
|
|
b91923c44f | |
|
|
e043564e96 |
|
|
@ -87,7 +87,7 @@ func closeOrder() {
|
|||
}
|
||||
orderIds = append(orderIds, orderInfo.Id)
|
||||
// 回调通知下游
|
||||
notifyResult := thirdpay_notify.NewOrderNotifyWithHandle(orderInfo.Id, response.Code, common.ORDER_STATUS_CLOSE, 0, "长时间未支付关闭订单")
|
||||
notifyResult := thirdpay_notify.NewOrderNotifyWithHandle(orderInfo.Id, response.Code, common.ORDER_STATUS_CLOSE, 0, 0, "长时间未支付关闭订单")
|
||||
//utils.Log(nil, "主动查询订单支付状态,回调下游", notifyResult)
|
||||
if notifyResult.ErrCode != errorcode.Success {
|
||||
utils.Log(nil, "关闭订单,回调下游失败", fmt.Sprintf("%#v", notifyResult))
|
||||
|
|
@ -305,7 +305,7 @@ func queryRefundOrder() {
|
|||
msg = "退款失败"
|
||||
}
|
||||
// 回调通知下游 todo
|
||||
notifyResult := thirdpay_notify.NewOrderNotifyWithHandle(orderInfo.Id, result.Code, status, int(result.Result.RefundFee), msg)
|
||||
notifyResult := thirdpay_notify.NewOrderNotifyWithHandle(orderInfo.Id, result.Code, status, int(result.Result.RefundFee), int(result.Result.RefundFee), msg)
|
||||
//utils.Log(nil, "主动查询退款订单状态,回调下游", notifyResult)
|
||||
if notifyResult.ErrCode != errorcode.Success {
|
||||
utils.Log(nil, "查询退款订单状态,回调下游失败", notifyResult)
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import (
|
|||
"fmt"
|
||||
"github.com/ahmetb/go-linq/v3"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/qit-team/snow-core/log/logger"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
|
@ -79,6 +80,8 @@ func PayPage(c *gin.Context) {
|
|||
func PayChannelList(c *gin.Context) {
|
||||
req, _ := controllers.GetRequest(c).(*front.PayChannelListRequest)
|
||||
req.UserAgent = c.Request.UserAgent()
|
||||
logger.Info(c, "PayChannelList", fmt.Sprintf("req.OrderId: %s, req.UserAgent: %s", req.OrderId, req.UserAgent))
|
||||
|
||||
data, code := services.PayPageChannelList(*req)
|
||||
|
||||
result := []front.PayChannelListResponse{}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ type Orders struct {
|
|||
OrderType int `xorm:"'order_type' TINYINT"`
|
||||
RefundOrderId int64 `xorm:"'refund_order_id' bigint(20)"`
|
||||
Amount int `xorm:"'amount' int(11)"`
|
||||
ActualAmount int `xorm:"'actual_amount' int(11)"`
|
||||
PayerTotal int `xorm:"'payer_total' int(11)"`
|
||||
ExtJson string `xorm:"'ext_json' varchar(1024)"`
|
||||
Desc string `xorm:"'desc' varchar(100)"`
|
||||
|
|
|
|||
|
|
@ -48,6 +48,13 @@ func PayPageChannelList(reqParam front.PayChannelListRequest) (resultPayChannelL
|
|||
code = errorcode.PayChannelNotFound
|
||||
return
|
||||
}
|
||||
|
||||
// 兜底只有1中支付方式,默认返回该支付方式,不校验支付环境
|
||||
if len(payList) == 1 {
|
||||
resultPayChannelList = payList
|
||||
return
|
||||
}
|
||||
|
||||
merchantPayChannelMap := make(map[int]paychannelmodel.PayChannel, 0)
|
||||
for _, pay := range payList {
|
||||
if !pay.ExpireTime.IsZero() && pay.ExpireTime.Unix() < time.Now().Unix() {
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ func OrderQueryAndNotify(ctx context.Context, orderInfo *ordersmodel.OrdersLeftP
|
|||
msg = "订单关闭"
|
||||
}
|
||||
// 回调通知下游
|
||||
notifyResult := thirdpay_notify.NewOrderNotifyWithHandle(orderInfo.Id, result.Code, status, int(result.Result.PayerTotal), msg)
|
||||
notifyResult := thirdpay_notify.NewOrderNotifyWithHandle(orderInfo.Id, result.Code, status, int(result.Result.AmountTotal), int(result.Result.PayerTotal), msg)
|
||||
//utils.Log(nil, "主动查询订单支付状态,回调下游", notifyResult)
|
||||
if notifyResult.ErrCode != errorcode.Success {
|
||||
utils.Log(nil, "主动查询订单支付状态,回调下游失败", fmt.Sprintf("%+v", notifyResult))
|
||||
|
|
|
|||
|
|
@ -23,7 +23,8 @@ type OrderNotify struct {
|
|||
|
||||
OrderId int64
|
||||
Status int //订单状态
|
||||
ActualAmount int
|
||||
ActualAmount int // 支付上游返回的订单金额,单位为分。该参数的值为支付时传入的
|
||||
PayerTotal int // 用户实际支付金额,单位为分
|
||||
Msg string
|
||||
CompleteTime time.Time
|
||||
}
|
||||
|
|
@ -51,13 +52,16 @@ type OrderNotifySendContent struct {
|
|||
PayerTotal int `json:"payer_total"`
|
||||
}
|
||||
|
||||
func NewOrderNotifyWithHandle(orderId int64, code int, Status int, actualAmount int, msg string) *OrderNotifyResp {
|
||||
// actualAmount 订单支付总金额,支付时传入
|
||||
// payerTotal 用户实际支付金额,(有优惠券的情况下,payerTotal = actualAmount - 优惠金额)
|
||||
func NewOrderNotifyWithHandle(orderId int64, code int, Status int, actualAmount int, payerTotal int, msg string) *OrderNotifyResp {
|
||||
orderNotify := &OrderNotify{
|
||||
OrderId: orderId,
|
||||
Status: Status,
|
||||
ActualAmount: actualAmount,
|
||||
Msg: msg,
|
||||
Code: code,
|
||||
PayerTotal: payerTotal,
|
||||
}
|
||||
return orderNotify.Handle()
|
||||
}
|
||||
|
|
@ -164,7 +168,7 @@ func (o *OrderNotify) setBody() *OrderNotifySendContent {
|
|||
AppId: o.order.AppId,
|
||||
ChannelId: o.order.PayChannelId,
|
||||
//MerchantId: o.order.MerchantId,
|
||||
Amount: o.order.Amount,
|
||||
Amount: o.order.ActualAmount, // 订单支付总金额,支付时传入
|
||||
PayerTotal: o.order.PayerTotal,
|
||||
}
|
||||
}
|
||||
|
|
@ -175,8 +179,13 @@ func (o *OrderNotify) updateOrder() {
|
|||
o.Code = errorcode.OrderStatusErr
|
||||
return
|
||||
}
|
||||
// 支付金额和上游支付金额不一致,记录日志
|
||||
if o.order.Amount != o.ActualAmount {
|
||||
utils.Log(nil, "支付金额和上游支付金额不一致", o.order.Id, o.order.Amount, o.ActualAmount)
|
||||
}
|
||||
o.order.Status = o.Status
|
||||
o.order.PayerTotal = o.ActualAmount
|
||||
o.order.ActualAmount = o.ActualAmount
|
||||
o.order.PayerTotal = o.PayerTotal
|
||||
o.Code = services.OrderUpdate(o.order, "status")
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -155,7 +155,7 @@ func ALiCallBack(notifyReq gopay.BodyMap, aliConfig AliPay) error {
|
|||
|
||||
// 拼装数据触发下游回调,触发下游回调
|
||||
orderId, _ := strconv.Atoi(notifyReq.Get("out_trade_no"))
|
||||
buyerPayAmount := notifyReq.Get("buyer_pay_amount") // 单位为元
|
||||
buyerPayAmount := notifyReq.Get("buyer_pay_amount") // 单位为元 //buyer_pay_amount 用户在交易中支付的金额。
|
||||
// 将字符串转换为浮点数,转为分
|
||||
buyerPayAmountFloat, err := strconv.ParseFloat(buyerPayAmount, 64)
|
||||
if err != nil {
|
||||
|
|
@ -164,6 +164,15 @@ func ALiCallBack(notifyReq gopay.BodyMap, aliConfig AliPay) error {
|
|||
}
|
||||
payerTotal := int(buyerPayAmountFloat * 100)
|
||||
|
||||
totalAmount := notifyReq.Get("total_amount") // 单位为元 //total_amount 本次交易支付的订单金额,单位为人民币(元)
|
||||
// 将字符串转换为浮点数,转为分
|
||||
amountTotalFloat, err := strconv.ParseFloat(totalAmount, 64)
|
||||
if err != nil {
|
||||
logger.Error(context.Background(), "ALiCallBack 发生错误", fmt.Sprintf("回调时,金额转换失败,失败原因:%s", err.Error()))
|
||||
return err
|
||||
}
|
||||
amountTotal := int(amountTotalFloat * 100)
|
||||
|
||||
// 订单状态
|
||||
tradeStatus := notifyReq.Get("trade_status")
|
||||
errCode := 0
|
||||
|
|
@ -187,7 +196,7 @@ func ALiCallBack(notifyReq gopay.BodyMap, aliConfig AliPay) error {
|
|||
return errors.New("订单状态异常,无法进行后续回调")
|
||||
}
|
||||
|
||||
res := thirdpay_notify.NewOrderNotifyWithHandle(int64(orderId), errCode, orderStatus, payerTotal, msg)
|
||||
res := thirdpay_notify.NewOrderNotifyWithHandle(int64(orderId), errCode, orderStatus, amountTotal, payerTotal, msg)
|
||||
merchantCallback, _ := json.Marshal(res)
|
||||
// 记录日志
|
||||
go func() {
|
||||
|
|
@ -249,8 +258,8 @@ func ALiOrderQuery(ctx context.Context, aliConfig AliPay, OrderNo string) (PayOr
|
|||
tradeStateDesc = "未付款交易超时关闭,或支付完成后全额退款"
|
||||
}
|
||||
|
||||
amountTotal, _ := strconv.ParseFloat(aliRsp.Response.TotalAmount, 64)
|
||||
payerTotal, _ := strconv.ParseFloat(aliRsp.Response.BuyerPayAmount, 64)
|
||||
amountTotal, _ := strconv.ParseFloat(aliRsp.Response.TotalAmount, 64) // total_amount 本次交易支付的订单金额,单位为人民币(元)
|
||||
payerTotal, _ := strconv.ParseFloat(aliRsp.Response.BuyerPayAmount, 64) //buyer_pay_amount 用户在交易中支付的金额。
|
||||
// 构建数据
|
||||
outTradeNo, _ := strconv.Atoi(aliRsp.Response.OutTradeNo)
|
||||
return PayOrderQueryInfo{
|
||||
|
|
|
|||
|
|
@ -468,3 +468,87 @@ func TestWechatJSAPIPaymentService(t *testing.T) {
|
|||
//t.Log(closeResutl)
|
||||
|
||||
}
|
||||
|
||||
// 微信 小程序支付
|
||||
func TestWechatMiniPaymentService(t *testing.T) {
|
||||
var err error
|
||||
c := context.Background()
|
||||
//解析启动命令
|
||||
opts := config.GetOptions()
|
||||
if opts.ShowVersion {
|
||||
fmt.Printf("%s\ncommit %s\nbuilt on %s\n", server.Version, server.BuildCommit, server.BuildDate)
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
//加载配置
|
||||
opts.ConfFile = "../../../.env"
|
||||
_, err = config.Load(opts.ConfFile)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
////引导程序
|
||||
//err = bootstrap.Bootstrap(conf)
|
||||
//if err != nil {
|
||||
// return
|
||||
//}
|
||||
|
||||
data := `{"api_v_3_key": "", "mch_id": "" `
|
||||
wechat := backend.WechatPayChannel{}
|
||||
err = json.Unmarshal([]byte(data), &wechat)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
request := PayOrderRequest{
|
||||
PayChannelId: 189140128377123531,
|
||||
OrderId: 345812382113322,
|
||||
ChannelType: payCommon.PAY_CHANNEL_WECHAT_MINI,
|
||||
Description: "测试商品",
|
||||
Amount: 1,
|
||||
PayerClientIp: "192.168.110.235",
|
||||
//Wx: WxPay{
|
||||
// AppId: "wx0a9d03516e77308c",
|
||||
// MchId: "1647084265",
|
||||
// SerialNo: "318457037183AFED5B9A55C129007D9EFE737B18",
|
||||
// ApiV3Key: "lsxdtvR2vOgGBu03u6wA0j9RnX5IP1Yq",
|
||||
// //PrivateKey: "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC7TG44IkSH7c/c\nFJ0+dTvcA9uYPdyIRFGRmtRBVEMP0S9q9MoVAuEeQ0/yxLmTmKb7/kAwShqNbwDU\niIm0y9b1jMpl1NM3lvEG5+LL1xMYKIRh2iOInoZSYpX46l5ME7FQwUq4GyoTg+5o\naIUKHXtzldzUR8/MXnpljYKL1oKb04vA627EMiUNm+Hajt4elhm3UXmOva1ohir7\nb69NEeleM4wjCxG+7ueuFIXlWqeAmXjYKb36C6xOeLbdlQeNg3BSEXmGFI5mDxM4\nlGf+zVWc5KcH9YVsq5D0UIziVHMUC91Za48fUgYjFb3Dho00IEjUqQwKuzCbZtkq\nD9mJ/0FRAgMBAAECggEAc4FO948qdClUZoTP9BSYNbarVdfQiLiZFRJGk4NDWB3J\nAEy10v9TlTYtt6laSIt7byv8qcsJVO9/s5IAWl7a0dNhfishlsafHYMjelHIlL1n\n5nCAOWCJtYTWuArQ3FnIn+SUD7Ww3RgfjoPmh7Zmy4FADim7HG2nTblXKKXBJhbg\nHI6X+7ltmZqMwG6Qb1Phq3WHPm4/Z0z+C3xs/2npikTMb8kY51GX54qJNamBO9G1\nY1pFsxwQ9Ep0V3BwX2Q+YJJFdBHeDVD0UvbO2GekArMgN48+OvkHBqajWFn1xOEB\n6Wp+j8qUue6fMcDFkq7ZY7hfEoBlZ+ZbCJNslYNiAQKBgQDzj/4q8+ChIWkLg5BZ\npaMaMV/goVrCH7HaF3DLxKTYKPWuRBpvW9xgx4tDDERhEZhDGgDoT+xSXdCTtYML\nWMBcvQnSn7JHSHa7CoAu/OwLMtKXSKtU3GO6nQeaifXL+Qi2U3JbIvwN34b7pzW0\n16a95qWVyXKlKM6dh0RKpit2lQKBgQDE3OtPgSiDMauZ+Cn9Sk1+aZ9jfizQZIUH\nkFGifsEgr/txTN2Gt4dIT+up0HSVpwfKLsHPS9wIJs38bivhWblchVEw5J1ZXPFQ\n27cs88B6LySw0dbsMRIceXQOhpm/118hr/QV0h4za99FP/1kGHGPrT4FsSw4FrNg\nBqF3hhUczQKBgBsspZ8FNrrDj4TJWQGniVsSxy+40Pd3sdAzbVJOzlWPvFmFH63t\nAdmKae9BHx/1ZpeV/yPsRuGptevFBKnvbQbr0Hy/dJSfcR/NPCAB+BQHx5c5dGQz\ncq0PeBm16sanMmGlTcz9SkIB/n11Wnii1ue5JCBiKXhj5SmOPgBWKeNBAoGARVZ2\nfwND7KmTAmEZEQCZuNuk6xsm16OAA4D+b9hrV4MEcgybvfZobLzRiXdFiOxS3xCG\n7OeQMULRrIZ1aCL9GaxPQ4RSM4Z77Hnm06tq8N4n8yuFop1J/sN8cB1Si/JkrG3X\n79OZFY16D18Rda7yWKOxQ7n6lCrStRDA0GNmjkUCgYEAnCd1PVJJ+VX7CXJ6gz7H\n0VXLAD+GUQzlnSzv6mgGWzn0acpVz9Q+o1qpxgNL/ehLTz+v3Nr7hexl77pUDVfJ\nS1zBopXaKx330eAJm4d0bKgKndHyfr7VJ6f5H/WezX7Q5jkm32D9/GPhJCfqBp3q\nWA/g+9g+fwkc78QKuQl7M68=\n-----END PRIVATE KEY-----\n",
|
||||
//},
|
||||
Wx: WxPay{
|
||||
AppId: "wx1bb10834390b170e",
|
||||
MchId: wechat.MchId,
|
||||
SerialNo: wechat.SerialNo,
|
||||
ApiV3Key: wechat.ApiV3Key,
|
||||
PrivateKey: wechat.PrivateKey,
|
||||
},
|
||||
OpenId: "oxsH-6wPlbshEOvXo0FvbPqA0l3Y",
|
||||
}
|
||||
// 支付
|
||||
orderResult := PaymentService(c, request)
|
||||
t.Log(orderResult)
|
||||
|
||||
//// 查询订单
|
||||
//qreq := PayOrderQueryRequest{
|
||||
// OrderId: request.OrderId,
|
||||
// PayChannel: 1,
|
||||
// Wx: request.Wx,
|
||||
// //Ali: request.Ali,
|
||||
//}
|
||||
//queryResult := PayOrderQuery(c, qreq)
|
||||
//t.Log(queryResult)
|
||||
|
||||
// 退款
|
||||
|
||||
//refundResult := OrderRefund(c, request)
|
||||
|
||||
//// 关闭订单
|
||||
//closeOrder := OrderCloseRequest{
|
||||
// OrderId: request.OrderId,
|
||||
// PayChannel: 2,
|
||||
// Wx: WxPay{},
|
||||
// Ali: request.Ali,
|
||||
//}
|
||||
//closeResutl := OrderClose(c, closeOrder)
|
||||
//t.Log(closeResutl)
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -180,8 +180,8 @@ func WxPayCallBack(notifyReq *wechat.V3NotifyReq, wxConfig WxPay) error {
|
|||
TradeStateDesc string `json:"trade_state_desc"` // 交易状态描述
|
||||
SuccessTime string `json:"success_time"` // 支付完成时间
|
||||
Amount struct {
|
||||
Total int64 `json:"total"`
|
||||
PayerTotal int64 `json:"payer_total"`
|
||||
Total int64 `json:"total"` // 【总金额】 订单总金额,单位为分,整型。
|
||||
PayerTotal int64 `json:"payer_total"` //用户支付金额】用户实际支付金额,整型,单位为分,用户支付金额=总金额-优惠券金额
|
||||
} `json:"amount"`
|
||||
}
|
||||
// 通用通知解密(推荐此方法)
|
||||
|
|
@ -214,7 +214,7 @@ func WxPayCallBack(notifyReq *wechat.V3NotifyReq, wxConfig WxPay) error {
|
|||
|
||||
// 触发下游回调的格式
|
||||
orderId, _ := strconv.Atoi(CallBackInfo.OutTradeNo)
|
||||
res := thirdpay_notify.NewOrderNotifyWithHandle(int64(orderId), errCode, orderStatus, int(CallBackInfo.Amount.PayerTotal), msg)
|
||||
res := thirdpay_notify.NewOrderNotifyWithHandle(int64(orderId), errCode, orderStatus, int(CallBackInfo.Amount.Total), int(CallBackInfo.Amount.PayerTotal), msg)
|
||||
merchantCallback, _ := json.Marshal(res)
|
||||
// 记录日志
|
||||
go func() {
|
||||
|
|
|
|||
|
|
@ -265,7 +265,7 @@
|
|||
|
||||
<script>
|
||||
// 支付页面模块化实现
|
||||
const API_BASE_URL = 'https://pay.cdlsxd.cn';
|
||||
const API_BASE_URL = '';
|
||||
// ========== 配置模块 ==========
|
||||
const CONFIG = {
|
||||
API: {
|
||||
|
|
@ -499,8 +499,18 @@
|
|||
|
||||
// 处理支付方式数据
|
||||
processPaymentMethods(data, id) {
|
||||
// 处理返回的数据,例如渲染支付方式列表
|
||||
if (data === null || data.data.length === 0) {
|
||||
// 先关闭loading,再展示内容,确保异常/正常都能让用户看到
|
||||
Utils.closeLoading();
|
||||
// 兼容 data.data 可能为 null / [] / {} 等多种情况
|
||||
const isEmpty =
|
||||
data === null ||
|
||||
data.data === null ||
|
||||
data.data === undefined ||
|
||||
(Array.isArray(data.data) && data.data.length === 0) ||
|
||||
(!Array.isArray(data.data) &&
|
||||
typeof data.data === "object" &&
|
||||
Object.keys(data.data).length === 0);
|
||||
if (isEmpty) {
|
||||
const pay = document.getElementById("pay");
|
||||
pay.innerHTML = "<h3>支付环境异常,请检查</h3>";
|
||||
} else if (data.data.length === 1) {
|
||||
|
|
|
|||
|
|
@ -1,23 +1,50 @@
|
|||
{{ define "payTemplateDefault.html"}}
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
{{/* <title>Title</title>*/}}
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<!-- 修复荣耀UA识别关键标签 -->
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, shrink-to-fit=no">
|
||||
<title>支付</title>
|
||||
<style>
|
||||
body { padding: 50px 20px; margin:0; font-family: system-ui; text-align: center; }
|
||||
.desc { font-size:14px; color:#555; margin-bottom:40px; }
|
||||
.wx-pay-btn {
|
||||
width: 90%;
|
||||
padding:14px 0;
|
||||
background:#07C160;
|
||||
color:#fff;
|
||||
border:none;
|
||||
border-radius:8px;
|
||||
font-size:17px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
{{ if eq .code 200}}
|
||||
<div class="desc">正在尝试自动唤起支付<br>若未跳转,请点击下方按钮</div>
|
||||
<button class="wx-pay-btn" id="triggerPay">打开支付</button>
|
||||
|
||||
{{ if eq .code 200}}
|
||||
<script>
|
||||
// 网页默认跳转url
|
||||
window.location.href = "{{.payUrl}}";
|
||||
</script>
|
||||
{{else}}
|
||||
<script>
|
||||
alert("{{.code}}" + "{{.message}}");
|
||||
</script>
|
||||
{{end}}
|
||||
</html>
|
||||
<script>
|
||||
const payLink = "{{.payUrl}}";
|
||||
const btn = document.getElementById('triggerPay');
|
||||
// 荣耀机型必须靠点击事件才能绕过系统拦截
|
||||
btn.onclick = function(){
|
||||
window.location.href = payLink;
|
||||
}
|
||||
// DOM加载完成后延时自动跳转(仅作兜底,荣耀大概率拦截,按钮是核心方案)
|
||||
window.onload = function(){
|
||||
setTimeout(()=>{
|
||||
window.location.href = payLink;
|
||||
}, 500);
|
||||
}
|
||||
</script>
|
||||
{{else}}
|
||||
<script>
|
||||
alert("支付失败:{{.code}} {{.message}}");
|
||||
history.back();
|
||||
</script>
|
||||
{{end}}
|
||||
</body>
|
||||
</html>
|
||||
{{ end }}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue