实现微信订单监听
This commit is contained in:
parent
82b3bc2cf0
commit
b8577139b7
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,3 +1,5 @@
|
|||||||
antdui-demo/
|
antdui-demo/
|
||||||
|
dujiaoka-master/
|
||||||
|
Vmianqian/
|
||||||
.vs
|
.vs
|
||||||
.idea
|
.idea
|
||||||
@ -14,6 +14,15 @@
|
|||||||
<PackageReference Include="MailKit" Version="4.16.0" />
|
<PackageReference Include="MailKit" Version="4.16.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="UIAutomationClient">
|
||||||
|
<HintPath>C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App\10.0.5\UIAutomationClient.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UIAutomationTypes">
|
||||||
|
<HintPath>C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App\10.0.5\UIAutomationTypes.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Remove="antdui-demo\**\*.cs" />
|
<Compile Remove="antdui-demo\**\*.cs" />
|
||||||
<EmbeddedResource Remove="antdui-demo\**\*" />
|
<EmbeddedResource Remove="antdui-demo\**\*" />
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -6,8 +6,9 @@
|
|||||||
"SmtpPort": 465,
|
"SmtpPort": 465,
|
||||||
"NotifyEmail": "1066960883@qq.com",
|
"NotifyEmail": "1066960883@qq.com",
|
||||||
"EmailAuthCode": "TPPMKSMvCadyzu3m",
|
"EmailAuthCode": "TPPMKSMvCadyzu3m",
|
||||||
"WechatPath": "",
|
"WechatPath": "D:\\Softwares\\Tencent\\Weixin\\Weixin.exe",
|
||||||
"WechatSid": "",
|
"WechatSid": "AAHRxMH-4RkRMiXVf7NSJGhBKBwThd_tfDct27hXjkv0Ag",
|
||||||
|
"WechatApiVersion": "7.10.1",
|
||||||
"AlipayPath": "",
|
"AlipayPath": "",
|
||||||
"AlipayAppId": "",
|
"AlipayAppId": "",
|
||||||
"AlipayUserId": "",
|
"AlipayUserId": "",
|
||||||
@ -15,7 +16,7 @@
|
|||||||
"WechatIntervalSeconds": 5,
|
"WechatIntervalSeconds": 5,
|
||||||
"AlipayIntervalSeconds": 5,
|
"AlipayIntervalSeconds": 5,
|
||||||
"EnableWheelPolling": true,
|
"EnableWheelPolling": true,
|
||||||
"EnableHeartbeat": true,
|
"EnableHeartbeat": false,
|
||||||
"HeartbeatIntervalSeconds": 30,
|
"HeartbeatIntervalSeconds": 30,
|
||||||
"ListenPath": "/notify/"
|
"ListenPath": "/notify/"
|
||||||
}
|
}
|
||||||
1
bin/Debug/net10.0-windows/pending-orders.client.json
Normal file
1
bin/Debug/net10.0-windows/pending-orders.client.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
[]
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,10 +1,9 @@
|
|||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// <auto-generated>
|
// <auto-generated>
|
||||||
// 此代码由工具生成。
|
// This code was generated by a tool.
|
||||||
// 运行时版本:4.0.30319.42000
|
|
||||||
//
|
//
|
||||||
// 对此文件的更改可能会导致不正确的行为,并且如果
|
// Changes to this file may cause incorrect behavior and will be lost if
|
||||||
// 重新生成代码,这些更改将会丢失。
|
// the code is regenerated.
|
||||||
// </auto-generated>
|
// </auto-generated>
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
@ -14,7 +13,7 @@ using System.Reflection;
|
|||||||
[assembly: System.Reflection.AssemblyCompanyAttribute("Vmianqian")]
|
[assembly: System.Reflection.AssemblyCompanyAttribute("Vmianqian")]
|
||||||
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
|
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
|
||||||
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
|
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
|
||||||
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+0de0dc29e29fb873a83396b40d1d356b96fd403f")]
|
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+82b3bc2cf0c49cfa7245d5fdd65ef87ea19892fc")]
|
||||||
[assembly: System.Reflection.AssemblyProductAttribute("Vmianqian")]
|
[assembly: System.Reflection.AssemblyProductAttribute("Vmianqian")]
|
||||||
[assembly: System.Reflection.AssemblyTitleAttribute("Vmianqian")]
|
[assembly: System.Reflection.AssemblyTitleAttribute("Vmianqian")]
|
||||||
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
|
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
2470aa52bf7c9d2f34f885ab74c7c3690d381bd0289dbaafe7d1e260701d7524
|
ebd5591aa83e3ce6dc8b4661368f70755a868c935951ae1bef6bc75ef5c3797f
|
||||||
|
|||||||
Binary file not shown.
@ -1 +1 @@
|
|||||||
1444586d3f97cf78236527678a31115203cb3c8ebe795b8d0d33e2075e906f3f
|
7239ca1570e58a84bff4ce01bdd3920794f5c0a911cc1d186c71d7544994c98a
|
||||||
|
|||||||
@ -32,7 +32,6 @@ E:\Demos\DemoOwns\C\VmianqianC\obj\Debug\net10.0-windows\Vmianqian.csproj.CoreCo
|
|||||||
E:\Demos\DemoOwns\C\VmianqianC\obj\Debug\net10.0-windows\Vmianqian.dll
|
E:\Demos\DemoOwns\C\VmianqianC\obj\Debug\net10.0-windows\Vmianqian.dll
|
||||||
E:\Demos\DemoOwns\C\VmianqianC\obj\Debug\net10.0-windows\refint\Vmianqian.dll
|
E:\Demos\DemoOwns\C\VmianqianC\obj\Debug\net10.0-windows\refint\Vmianqian.dll
|
||||||
E:\Demos\DemoOwns\C\VmianqianC\obj\Debug\net10.0-windows\Vmianqian.pdb
|
E:\Demos\DemoOwns\C\VmianqianC\obj\Debug\net10.0-windows\Vmianqian.pdb
|
||||||
E:\Demos\DemoOwns\C\VmianqianC\bin\Debug\net10.0-windows\Vmianqian.exe
|
|
||||||
E:\Demos\DemoOwns\C\VmianqianC\bin\Debug\net10.0-windows\Vmianqian.deps.json
|
E:\Demos\DemoOwns\C\VmianqianC\bin\Debug\net10.0-windows\Vmianqian.deps.json
|
||||||
E:\Demos\DemoOwns\C\VmianqianC\bin\Debug\net10.0-windows\Vmianqian.runtimeconfig.json
|
E:\Demos\DemoOwns\C\VmianqianC\bin\Debug\net10.0-windows\Vmianqian.runtimeconfig.json
|
||||||
E:\Demos\DemoOwns\C\VmianqianC\bin\Debug\net10.0-windows\Vmianqian.dll
|
E:\Demos\DemoOwns\C\VmianqianC\bin\Debug\net10.0-windows\Vmianqian.dll
|
||||||
@ -53,3 +52,4 @@ E:\Demos\DemoOwns\C\VmianqianC\bin_temp\MimeKit.dll
|
|||||||
E:\Demos\DemoOwns\C\VmianqianC\bin\Debug\net10.0-windows\BouncyCastle.Cryptography.dll
|
E:\Demos\DemoOwns\C\VmianqianC\bin\Debug\net10.0-windows\BouncyCastle.Cryptography.dll
|
||||||
E:\Demos\DemoOwns\C\VmianqianC\bin\Debug\net10.0-windows\MailKit.dll
|
E:\Demos\DemoOwns\C\VmianqianC\bin\Debug\net10.0-windows\MailKit.dll
|
||||||
E:\Demos\DemoOwns\C\VmianqianC\bin\Debug\net10.0-windows\MimeKit.dll
|
E:\Demos\DemoOwns\C\VmianqianC\bin\Debug\net10.0-windows\MimeKit.dll
|
||||||
|
E:\Demos\DemoOwns\C\VmianqianC\bin\Debug\net10.0-windows\Vmianqian.exe
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
735
vmq-customization-pack/Index.php
Normal file
735
vmq-customization-pack/Index.php
Normal file
@ -0,0 +1,735 @@
|
|||||||
|
<?php
|
||||||
|
namespace app\index\controller;
|
||||||
|
|
||||||
|
use think\Db;
|
||||||
|
use think\facade\Session;
|
||||||
|
|
||||||
|
class Index
|
||||||
|
{
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
$url = "http://www.5cctv.net/wp-content/plugins/erphpdown/payment/vmq/notify.php?payId=190717101020112222981¶m=order[7876632]&type=1&price=1&reallyPrice=1&sign=2398a2492db0616381a85c1fedc51a11";
|
||||||
|
return $this->getCurl($url);
|
||||||
|
|
||||||
|
//return 'by:vone';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getReturn($code = 1, $msg = "成功", $data = null)
|
||||||
|
{
|
||||||
|
return array("code" => $code, "msg" => $msg, "data" => $data);
|
||||||
|
}
|
||||||
|
|
||||||
|
//后台用户登录
|
||||||
|
public function login()
|
||||||
|
{
|
||||||
|
$user = input("user");
|
||||||
|
$pass = input("pass");
|
||||||
|
|
||||||
|
$_user = Db::name("setting")->where("vkey", "user")->find();
|
||||||
|
if ($user != $_user["vvalue"]) {
|
||||||
|
return json($this->getReturn(-1, "账号或密码错误"));
|
||||||
|
}
|
||||||
|
|
||||||
|
$_pass = Db::name("setting")->where("vkey", "pass")->find();
|
||||||
|
if ($pass != $_pass["vvalue"]) {
|
||||||
|
return json($this->getReturn(-1, "账号或密码错误"));
|
||||||
|
}
|
||||||
|
|
||||||
|
Session::set("admin", 1);
|
||||||
|
|
||||||
|
return json($this->getReturn());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//后台菜单
|
||||||
|
public function getMenu()
|
||||||
|
{
|
||||||
|
if (!Session::has("admin")) {
|
||||||
|
return json($this->getReturn(-1, "没有登录"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$menu = array(
|
||||||
|
array(
|
||||||
|
"name" => "系统设置",
|
||||||
|
"type" => "url",
|
||||||
|
"url" => "admin/setting.html?t=" . time(),
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
"name" => "监控端设置",
|
||||||
|
"type" => "url",
|
||||||
|
"url" => "admin/jk.html?t=" . time(),
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
"name" => "微信二维码",
|
||||||
|
"type" => "menu",
|
||||||
|
"node" => array(
|
||||||
|
array(
|
||||||
|
"name" => "添加",
|
||||||
|
"type" => "url",
|
||||||
|
"url" => "admin/addwxqrcode.html?t=" . time(),
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
"name" => "管理",
|
||||||
|
"type" => "url",
|
||||||
|
"url" => "admin/wxqrcodelist.html?t=" . time(),
|
||||||
|
)
|
||||||
|
),
|
||||||
|
), array(
|
||||||
|
"name" => "支付宝二维码",
|
||||||
|
"type" => "menu",
|
||||||
|
"node" => array(
|
||||||
|
array(
|
||||||
|
"name" => "添加",
|
||||||
|
"type" => "url",
|
||||||
|
"url" => "admin/addzfbqrcode.html?t=" . time(),
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
"name" => "管理",
|
||||||
|
"type" => "url",
|
||||||
|
"url" => "admin/zfbqrcodelist.html?t=" . time(),
|
||||||
|
)
|
||||||
|
),
|
||||||
|
), array(
|
||||||
|
"name" => "订单列表",
|
||||||
|
"type" => "url",
|
||||||
|
"url" => "admin/orderlist.html?t=" . time(),
|
||||||
|
), array(
|
||||||
|
"name" => "Api说明",
|
||||||
|
"type" => "url",
|
||||||
|
"url" => "api.html?t=" . time(),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return json($menu);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//创建订单
|
||||||
|
public function createOrder()
|
||||||
|
{
|
||||||
|
$this->closeEndOrder();
|
||||||
|
|
||||||
|
$payId = input("payId");
|
||||||
|
if (!$payId || $payId == "") {
|
||||||
|
return json($this->getReturn(-1, "请传入商户订单号"));
|
||||||
|
}
|
||||||
|
$type = input("type");
|
||||||
|
if (!$type || $type == "") {
|
||||||
|
return json($this->getReturn(-1, "请传入支付方式=>1|微信 2|支付宝"));
|
||||||
|
}
|
||||||
|
if ($type != 1 && $type != 2) {
|
||||||
|
return json($this->getReturn(-1, "支付方式错误=>1|微信 2|支付宝"));
|
||||||
|
}
|
||||||
|
|
||||||
|
$price = input("price");
|
||||||
|
if (!$price || $price == "") {
|
||||||
|
return json($this->getReturn(-1, "请传入订单金额"));
|
||||||
|
}
|
||||||
|
if ($price <= 0) {
|
||||||
|
return json($this->getReturn(-1, "订单金额必须大于0"));
|
||||||
|
}
|
||||||
|
|
||||||
|
$sign = input("sign");
|
||||||
|
if (!$sign || $sign == "") {
|
||||||
|
return json($this->getReturn(-1, "请传入签名"));
|
||||||
|
}
|
||||||
|
|
||||||
|
$isHtml = input("isHtml");
|
||||||
|
if (!$isHtml || $isHtml == "") {
|
||||||
|
$isHtml = 0;
|
||||||
|
}
|
||||||
|
$param = input("param");
|
||||||
|
if (!$param) {
|
||||||
|
$param = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
$res = Db::name("setting")->where("vkey", "key")->find();
|
||||||
|
$key = $res['vvalue'];
|
||||||
|
|
||||||
|
if (input("notifyUrl")) {
|
||||||
|
$notify_url = input("notifyUrl");
|
||||||
|
} else {
|
||||||
|
$res = Db::name("setting")->where("vkey", "notifyUrl")->find();
|
||||||
|
$notify_url = $res['vvalue'];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (input("returnUrl")) {
|
||||||
|
$return_url = input("returnUrl");
|
||||||
|
} else {
|
||||||
|
$res = Db::name("setting")->where("vkey", "returnUrl")->find();
|
||||||
|
$return_url = $res['vvalue'];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$_sign = md5($payId . $param . $type . $price . $key);
|
||||||
|
if ($sign != $_sign) {
|
||||||
|
return json($this->getReturn(-1, "签名错误"));
|
||||||
|
}
|
||||||
|
|
||||||
|
$jkstate = Db::name("setting")->where("vkey", "jkstate")->find();
|
||||||
|
$jkstate = $jkstate['vvalue'];
|
||||||
|
if ($jkstate!="1"){
|
||||||
|
return json($this->getReturn(-1, "监控端状态异常,请检查"));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
$reallyPrice = bcmul($price ,100);
|
||||||
|
|
||||||
|
$payQf = Db::name("setting")->where("vkey", "payQf")->find();
|
||||||
|
$payQf = $payQf['vvalue'];
|
||||||
|
|
||||||
|
|
||||||
|
$orderId = date("YmdHms") . rand(1, 9) . rand(1, 9) . rand(1, 9) . rand(1, 9);
|
||||||
|
|
||||||
|
$ok = false;
|
||||||
|
for ($i = 0; $i < 10; $i++) {
|
||||||
|
$tmpPrice = $reallyPrice . "-" . $type;
|
||||||
|
|
||||||
|
$row = Db::execute("INSERT IGNORE INTO tmp_price (price,oid) VALUES ('" . $tmpPrice . "','".$orderId."')");
|
||||||
|
if ($row) {
|
||||||
|
$ok = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if ($payQf == 1) {
|
||||||
|
$reallyPrice++;
|
||||||
|
} else if ($payQf == 2) {
|
||||||
|
$reallyPrice--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$ok) {
|
||||||
|
return json($this->getReturn(-1, "订单超出负荷,请稍后重试"));
|
||||||
|
}
|
||||||
|
//echo $reallyPrice;
|
||||||
|
|
||||||
|
$reallyPrice = bcdiv($reallyPrice, 100,2);
|
||||||
|
|
||||||
|
if ($type == 1) {
|
||||||
|
$payUrl = Db::name("setting")->where("vkey", "wxpay")->find();
|
||||||
|
$payUrl = $payUrl['vvalue'];
|
||||||
|
|
||||||
|
} else if ($type == 2) {
|
||||||
|
$payUrl = Db::name("setting")->where("vkey", "zfbpay")->find();
|
||||||
|
$payUrl = $payUrl['vvalue'];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($payUrl == "") {
|
||||||
|
return json($this->getReturn(-1, "请您先进入后台配置程序"));
|
||||||
|
}
|
||||||
|
$isAuto = 1;
|
||||||
|
$_payUrl = Db::name("pay_qrcode")
|
||||||
|
->where("price", $reallyPrice)
|
||||||
|
->where("type", $type)
|
||||||
|
->find();
|
||||||
|
if ($_payUrl) {
|
||||||
|
$payUrl = $_payUrl['pay_url'];
|
||||||
|
$isAuto = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$res = Db::name("pay_order")->where("pay_id", $payId)->find();
|
||||||
|
if ($res) {
|
||||||
|
return json($this->getReturn(-1, "商户订单号已存在"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
$createDate = time();
|
||||||
|
$data = array(
|
||||||
|
"close_date" => 0,
|
||||||
|
"create_date" => $createDate,
|
||||||
|
"is_auto" => $isAuto,
|
||||||
|
"notify_url" => $notify_url,
|
||||||
|
"order_id" => $orderId,
|
||||||
|
"param" => $param,
|
||||||
|
"pay_date" => 0,
|
||||||
|
"pay_id" => $payId,
|
||||||
|
"pay_url" => $payUrl,
|
||||||
|
"price" => $price,
|
||||||
|
"really_price" => $reallyPrice,
|
||||||
|
"return_url" => $return_url,
|
||||||
|
"state" => 0,
|
||||||
|
"type" => $type
|
||||||
|
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
Db::name("pay_order")->insert($data);
|
||||||
|
|
||||||
|
|
||||||
|
//return "<script>window.location.href = '/payPage/pay.html?orderId=" + c.getOrderId() + "'</script>";
|
||||||
|
|
||||||
|
if ($isHtml == 1) {
|
||||||
|
|
||||||
|
echo "<script>window.location.href = 'payPage/pay.html?orderId=" . $orderId . "'</script>";
|
||||||
|
|
||||||
|
} else {
|
||||||
|
$time = Db::name("setting")->where("vkey", "close")->find();
|
||||||
|
$data = array(
|
||||||
|
"payId" => $payId,
|
||||||
|
"orderId" => $orderId,
|
||||||
|
"payType" => $type,
|
||||||
|
"price" => $price,
|
||||||
|
"reallyPrice" => $reallyPrice,
|
||||||
|
"payUrl" => $payUrl,
|
||||||
|
"isAuto" => $isAuto,
|
||||||
|
"state" => 0,
|
||||||
|
"timeOut" => $time['vvalue'],
|
||||||
|
"date" => $createDate
|
||||||
|
);
|
||||||
|
return json($this->getReturn(1, "成功", $data));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
//获取订单信息
|
||||||
|
public function getOrder()
|
||||||
|
{
|
||||||
|
|
||||||
|
$res = Db::name("pay_order")->where("order_id", input("orderId"))->find();
|
||||||
|
if ($res){
|
||||||
|
$time = Db::name("setting")->where("vkey", "close")->find();
|
||||||
|
|
||||||
|
$data = array(
|
||||||
|
"payId" => $res['pay_id'],
|
||||||
|
"orderId" => $res['order_id'],
|
||||||
|
"payType" => $res['type'],
|
||||||
|
"price" => $res['price'],
|
||||||
|
"reallyPrice" => $res['really_price'],
|
||||||
|
"payUrl" => $res['pay_url'],
|
||||||
|
"isAuto" => $res['is_auto'],
|
||||||
|
"state" => $res['state'],
|
||||||
|
"timeOut" => $time['vvalue'],
|
||||||
|
"date" => $res['create_date']
|
||||||
|
);
|
||||||
|
return json($this->getReturn(1, "成功", $data));
|
||||||
|
}else{
|
||||||
|
return json($this->getReturn(-1, "云端订单编号不存在"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//查询订单状态
|
||||||
|
public function checkOrder()
|
||||||
|
{
|
||||||
|
$res = Db::name("pay_order")->where("order_id", input("orderId"))->find();
|
||||||
|
if ($res){
|
||||||
|
if ($res['state']==0){
|
||||||
|
return json($this->getReturn(-1, "订单未支付"));
|
||||||
|
}
|
||||||
|
if ($res['state']==-1){
|
||||||
|
return json($this->getReturn(-1, "订单已过期"));
|
||||||
|
}
|
||||||
|
|
||||||
|
$res2 = Db::name("setting")->where("vkey","key")->find();
|
||||||
|
$key = $res2['vvalue'];
|
||||||
|
|
||||||
|
$res['price'] = number_format($res['price'],2,".","");
|
||||||
|
$res['really_price'] = number_format($res['really_price'],2,".","");
|
||||||
|
|
||||||
|
|
||||||
|
$p = "payId=".$res['pay_id']."¶m=".$res['param']."&type=".$res['type']."&price=".$res['price']."&reallyPrice=".$res['really_price'];
|
||||||
|
|
||||||
|
$sign = $res['pay_id'].$res['param'].$res['type'].$res['price'].$res['really_price'].$key;
|
||||||
|
$p = $p . "&sign=".md5($sign);
|
||||||
|
|
||||||
|
$url = $res['return_url'];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (strpos($url,"?")===false){
|
||||||
|
$url = $url."?".$p;
|
||||||
|
}else{
|
||||||
|
$url = $url."&".$p;
|
||||||
|
}
|
||||||
|
|
||||||
|
return json($this->getReturn(1, "成功", $url));
|
||||||
|
}else{
|
||||||
|
return json($this->getReturn(-1, "云端订单编号不存在"));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//获取待支付订单列表
|
||||||
|
public function getPendingOrders()
|
||||||
|
{
|
||||||
|
$key = Db::name("setting")->where("vkey", "key")->find();
|
||||||
|
$key = $key ? $key['vvalue'] : "";
|
||||||
|
$t = input("t");
|
||||||
|
$sign = input("sign");
|
||||||
|
$type = input("type");
|
||||||
|
|
||||||
|
if (!$t || !$sign) {
|
||||||
|
return json($this->getReturn(-1, "请传入时间戳和签名"));
|
||||||
|
}
|
||||||
|
|
||||||
|
$_sign = md5($t . $key);
|
||||||
|
if ($_sign != $sign) {
|
||||||
|
return json($this->getReturn(-1, "签名校验不通过"));
|
||||||
|
}
|
||||||
|
|
||||||
|
$query = Db::name("pay_order")
|
||||||
|
->where("state", 0)
|
||||||
|
->order("create_date desc")
|
||||||
|
->limit(50);
|
||||||
|
|
||||||
|
if ($type !== null && $type !== '') {
|
||||||
|
$query->where("type", intval($type));
|
||||||
|
}
|
||||||
|
|
||||||
|
$rows = $query->select();
|
||||||
|
$data = array();
|
||||||
|
foreach ($rows as $row) {
|
||||||
|
$data[] = array(
|
||||||
|
"payId" => $row['pay_id'],
|
||||||
|
"orderId" => $row['order_id'],
|
||||||
|
"param" => $row['param'],
|
||||||
|
"payType" => intval($row['type']),
|
||||||
|
"price" => floatval($row['price']),
|
||||||
|
"reallyPrice" => floatval($row['really_price']),
|
||||||
|
"state" => intval($row['state']),
|
||||||
|
"timeOut" => intval((Db::name("setting")->where("vkey", "close")->find())['vvalue']),
|
||||||
|
"date" => intval($row['create_date'])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return json($this->getReturn(1, "成功", $data));
|
||||||
|
}
|
||||||
|
//关闭订单
|
||||||
|
public function closeOrder(){
|
||||||
|
$res2 = Db::name("setting")->where("vkey","key")->find();
|
||||||
|
$key = $res2['vvalue'];
|
||||||
|
$orderId = input("orderId");
|
||||||
|
|
||||||
|
$_sign = $orderId.$key;
|
||||||
|
|
||||||
|
if (md5($_sign)!=input("sign")){
|
||||||
|
return json($this->getReturn(-1, "签名校验不通过"));
|
||||||
|
}
|
||||||
|
|
||||||
|
$res = Db::name("pay_order")->where("order_id",$orderId)->find();
|
||||||
|
|
||||||
|
if ($res){
|
||||||
|
if ($res['state']!=0){
|
||||||
|
return json($this->getReturn(-1, "订单状态不允许关闭"));
|
||||||
|
}
|
||||||
|
Db::name("pay_order")->where("order_id",$orderId)->update(array("state"=>-1,"close_date"=>time()));
|
||||||
|
Db::name("tmp_price")
|
||||||
|
->where("oid",$res['order_id'])
|
||||||
|
->delete();
|
||||||
|
return json($this->getReturn(1, "成功"));
|
||||||
|
}else{
|
||||||
|
return json($this->getReturn(-1, "云端订单编号不存在"));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
//获取监控端状态
|
||||||
|
public function getState(){
|
||||||
|
$res2 = Db::name("setting")->where("vkey","key")->find();
|
||||||
|
$key = $res2['vvalue'];
|
||||||
|
$t = input("t");
|
||||||
|
|
||||||
|
$_sign = $t.$key;
|
||||||
|
|
||||||
|
if (md5($_sign)!=input("sign")){
|
||||||
|
return json($this->getReturn(-1, "签名校验不通过"));
|
||||||
|
}
|
||||||
|
|
||||||
|
$res = Db::name("setting")->where("vkey","lastheart")->find();
|
||||||
|
$lastheart = $res['vvalue'];
|
||||||
|
$res = Db::name("setting")->where("vkey","lastpay")->find();
|
||||||
|
$lastpay = $res['vvalue'];
|
||||||
|
$res = Db::name("setting")->where("vkey","jkstate")->find();
|
||||||
|
$jkstate = $res['vvalue'];
|
||||||
|
|
||||||
|
return json($this->getReturn(1, "成功",array("lastheart"=>$lastheart,"lastpay"=>$lastpay,"jkstate"=>$jkstate)));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//App心跳接口
|
||||||
|
public function appHeart(){
|
||||||
|
$this->closeEndOrder();
|
||||||
|
|
||||||
|
$res2 = Db::name("setting")->where("vkey","key")->find();
|
||||||
|
$key = $res2['vvalue'];
|
||||||
|
$t = input("t");
|
||||||
|
|
||||||
|
$_sign = $t.$key;
|
||||||
|
|
||||||
|
if (md5($_sign)!=input("sign")){
|
||||||
|
return json($this->getReturn(-1, "签名校验不通过"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// $jg = time()*1000 - $t;
|
||||||
|
// if ($jg>50000 || $jg<-50000){
|
||||||
|
// return json($this->getReturn(-1, "客户端时间错误"));
|
||||||
|
// }
|
||||||
|
|
||||||
|
Db::name("setting")->where("vkey","lastheart")->update(array("vvalue"=>time()));
|
||||||
|
Db::name("setting")->where("vkey","jkstate")->update(array("vvalue"=>1));
|
||||||
|
return json($this->getReturn());
|
||||||
|
}
|
||||||
|
//App推送付款数据接口
|
||||||
|
public function appPush(){
|
||||||
|
$this->closeEndOrder();
|
||||||
|
|
||||||
|
$res2 = Db::name("setting")->where("vkey","key")->find();
|
||||||
|
$key = $res2['vvalue'];
|
||||||
|
$t = input("t");
|
||||||
|
$type = input("type");
|
||||||
|
$price = input("price");
|
||||||
|
|
||||||
|
$_sign = $type.$price.$t.$key;
|
||||||
|
|
||||||
|
if (md5($_sign)!=input("sign")){
|
||||||
|
return json($this->getReturn(-1, "签名校验不通过"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// $jg = time()*1000 - $t;
|
||||||
|
// if ($jg>50000 || $jg<-50000){
|
||||||
|
// return json($this->getReturn(-1, "客户端时间错误"));
|
||||||
|
// }
|
||||||
|
|
||||||
|
Db::name("setting")
|
||||||
|
->where("vkey","lastpay")
|
||||||
|
->update(
|
||||||
|
array(
|
||||||
|
"vvalue"=>time()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$res = Db::name("pay_order")
|
||||||
|
->where("really_price",$price)
|
||||||
|
->where("state",0)
|
||||||
|
->where("type",$type)
|
||||||
|
->find();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if ($res){
|
||||||
|
|
||||||
|
Db::name("tmp_price")
|
||||||
|
->where("oid",$res['order_id'])
|
||||||
|
->delete();
|
||||||
|
|
||||||
|
Db::name("pay_order")->where("id",$res['id'])->update(array("state"=>1,"pay_date"=>time(),"close_date"=>time()));
|
||||||
|
|
||||||
|
$url = $res['notify_url'];
|
||||||
|
|
||||||
|
$res2 = Db::name("setting")->where("vkey","key")->find();
|
||||||
|
$key = $res2['vvalue'];
|
||||||
|
|
||||||
|
$p = "payId=".$res['pay_id']."¶m=".$res['param']."&type=".$res['type']."&price=".$res['price']."&reallyPrice=".$res['really_price'];
|
||||||
|
|
||||||
|
$sign = $res['pay_id'].$res['param'].$res['type'].$res['price'].$res['really_price'].$key;
|
||||||
|
$p = $p . "&sign=".md5($sign);
|
||||||
|
|
||||||
|
if (strpos($url,"?")===false){
|
||||||
|
$url = $url."?".$p;
|
||||||
|
}else{
|
||||||
|
$url = $url."&".$p;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$re = $this->getCurl($url);
|
||||||
|
if ($re=="success"){
|
||||||
|
return json($this->getReturn());
|
||||||
|
}else{
|
||||||
|
Db::name("pay_order")->where("id",$res['id'])->update(array("state"=>2));
|
||||||
|
|
||||||
|
return json($this->getReturn(-1,"异步通知失败"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}else{
|
||||||
|
$data = array(
|
||||||
|
"close_date" => 0,
|
||||||
|
"create_date" => time(),
|
||||||
|
"is_auto" => 0,
|
||||||
|
"notify_url" => "",
|
||||||
|
"order_id" => "无订单转账",
|
||||||
|
"param" => "无订单转账",
|
||||||
|
"pay_date" => 0,
|
||||||
|
"pay_id" => "无订单转账",
|
||||||
|
"pay_url" => "",
|
||||||
|
"price" => $price,
|
||||||
|
"really_price" => $price,
|
||||||
|
"return_url" => "",
|
||||||
|
"state" => 1,
|
||||||
|
"type" => $type
|
||||||
|
|
||||||
|
);
|
||||||
|
|
||||||
|
Db::name("pay_order")->insert($data);
|
||||||
|
return json($this->getReturn());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//App按订单推送付款数据接口
|
||||||
|
public function appPushOrder(){
|
||||||
|
$this->closeEndOrder();
|
||||||
|
|
||||||
|
$res2 = Db::name("setting")->where("vkey","key")->find();
|
||||||
|
$key = $res2['vvalue'];
|
||||||
|
$orderId = input("orderId");
|
||||||
|
$tradeNo = input("tradeNo");
|
||||||
|
$t = input("t");
|
||||||
|
|
||||||
|
if (!$orderId || !$t) {
|
||||||
|
return json($this->getReturn(-1, "参数不完整"));
|
||||||
|
}
|
||||||
|
|
||||||
|
$_sign = $orderId.$tradeNo.$t.$key;
|
||||||
|
if (md5($_sign)!=input("sign")){
|
||||||
|
return json($this->getReturn(-1, "签名校验不通过"));
|
||||||
|
}
|
||||||
|
|
||||||
|
Db::name("setting")
|
||||||
|
->where("vkey","lastpay")
|
||||||
|
->update(array(
|
||||||
|
"vvalue"=>time()
|
||||||
|
));
|
||||||
|
|
||||||
|
$res = Db::name("pay_order")->where("order_id",$orderId)->find();
|
||||||
|
if (!$res){
|
||||||
|
return json($this->getReturn(-1, "云端订单编号不存在"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($res['state']==1){
|
||||||
|
return json($this->getReturn(1, "订单已完成"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($res['state']!=0){
|
||||||
|
return json($this->getReturn(-1, "订单状态不允许推送"));
|
||||||
|
}
|
||||||
|
|
||||||
|
Db::name("tmp_price")
|
||||||
|
->where("oid",$res['order_id'])
|
||||||
|
->delete();
|
||||||
|
|
||||||
|
Db::name("pay_order")->where("id",$res['id'])->update(array("state"=>1,"pay_date"=>time(),"close_date"=>time()));
|
||||||
|
|
||||||
|
$notifyResult = $this->notifyOrder($res);
|
||||||
|
if ($notifyResult === "success"){
|
||||||
|
return json($this->getReturn(1, "成功"));
|
||||||
|
}else{
|
||||||
|
Db::name("pay_order")->where("id",$res['id'])->update(array("state"=>2));
|
||||||
|
return json($this->getReturn(-1,"异步通知失败",$notifyResult));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//关闭过期订单接口(请用定时器至少1分钟调用一次)
|
||||||
|
public function closeEndOrder(){
|
||||||
|
$res = Db::name("setting")->where("vkey","lastheart")->find();
|
||||||
|
$lastheart = $res['vvalue'];
|
||||||
|
if ((time()-$lastheart)>60){
|
||||||
|
Db::name("setting")->where("vkey","jkstate")->update(array("vvalue"=>0));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
$time = Db::name("setting")->where("vkey", "close")->find();
|
||||||
|
|
||||||
|
$closeTime = time()-60*$time['vvalue'];
|
||||||
|
$close_date = time();
|
||||||
|
|
||||||
|
$res = Db::name("pay_order")
|
||||||
|
->where("create_date <=".$closeTime)
|
||||||
|
->where("state",0)
|
||||||
|
->update(array("state"=>-1,"close_date"=>$close_date));
|
||||||
|
|
||||||
|
if ($res){
|
||||||
|
$rows = Db::name("pay_order")->where("close_date",$close_date)->select();
|
||||||
|
foreach ($rows as $row){
|
||||||
|
Db::name("tmp_price")
|
||||||
|
->where("oid",$row['order_id'])
|
||||||
|
->delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
$rows = Db::name("tmp_price")->select();
|
||||||
|
foreach ($rows as $row){
|
||||||
|
$re = Db::name("pay_order")->where("order_id",$row['oid'])->find();
|
||||||
|
if ($re){
|
||||||
|
|
||||||
|
}else{
|
||||||
|
Db::name("tmp_price")
|
||||||
|
->where("oid",$row['oid'])
|
||||||
|
->delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return json($this->getReturn(1,"成功清理".$res."条订单"));
|
||||||
|
}else{
|
||||||
|
return json($this->getReturn(1,"没有等待清理的订单"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//发送Http请求
|
||||||
|
private function getCurl($url, $post = 0, $cookie = 0, $header = 0, $nobaody = 0)
|
||||||
|
{
|
||||||
|
$ch = curl_init();
|
||||||
|
curl_setopt($ch, CURLOPT_URL, $url);
|
||||||
|
curl_setopt($ch, CURLOPT_TIMEOUT, 15);
|
||||||
|
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||||||
|
$klsf[] = 'Accept:*/*';
|
||||||
|
$klsf[] = 'Accept-Language:zh-cn';
|
||||||
|
//$klsf[] = 'Content-Type:application/json';
|
||||||
|
$klsf[] = 'User-Agent:Mozilla/5.0 (iPhone; CPU iPhone OS 11_2_1 like Mac OS X) AppleWebKit/604.4.7 (KHTML, like Gecko) Mobile/15C153 MicroMessenger/6.6.1 NetType/WIFI Language/zh_CN';
|
||||||
|
$klsf[] = 'Referer:'.$url;
|
||||||
|
curl_setopt($ch, CURLOPT_HTTPHEADER, $klsf);
|
||||||
|
if ($post) {
|
||||||
|
curl_setopt($ch, CURLOPT_POST, 1);
|
||||||
|
curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
|
||||||
|
}
|
||||||
|
if ($header) {
|
||||||
|
curl_setopt($ch, CURLOPT_HEADER, true);
|
||||||
|
}
|
||||||
|
if ($cookie) {
|
||||||
|
curl_setopt($ch, CURLOPT_COOKIE, $cookie);
|
||||||
|
}
|
||||||
|
if ($nobaody) {
|
||||||
|
curl_setopt($ch, CURLOPT_NOBODY, 1);
|
||||||
|
}
|
||||||
|
curl_setopt($ch, CURLOPT_TIMEOUT,60);
|
||||||
|
curl_setopt($ch, CURLOPT_ENCODING, 'gzip');
|
||||||
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||||
|
$ret = curl_exec($ch);
|
||||||
|
curl_close($ch);
|
||||||
|
return $ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function notifyOrder($res)
|
||||||
|
{
|
||||||
|
$url = $res['notify_url'];
|
||||||
|
|
||||||
|
$res2 = Db::name("setting")->where("vkey","key")->find();
|
||||||
|
$key = $res2['vvalue'];
|
||||||
|
|
||||||
|
$p = "payId=".$res['pay_id']."¶m=".$res['param']."&type=".$res['type']."&price=".$res['price']."&reallyPrice=".$res['really_price'];
|
||||||
|
|
||||||
|
$sign = $res['pay_id'].$res['param'].$res['type'].$res['price'].$res['really_price'].$key;
|
||||||
|
$p = $p . "&sign=".md5($sign);
|
||||||
|
|
||||||
|
if (strpos($url,"?")===false){
|
||||||
|
$url = $url."?".$p;
|
||||||
|
}else{
|
||||||
|
$url = $url."&".$p;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->getCurl($url);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
178
vmq-customization-pack/README.md
Normal file
178
vmq-customization-pack/README.md
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
# V免签微信协议改造说明
|
||||||
|
|
||||||
|
这个目录用于给其他用户复用本次 V免签 服务端改造。
|
||||||
|
|
||||||
|
## 目录说明
|
||||||
|
|
||||||
|
- `route.php`
|
||||||
|
V免签路由文件改造后的完整版本。
|
||||||
|
- `Index.php`
|
||||||
|
`application/index/controller/Index.php` 改造后的完整版本。
|
||||||
|
|
||||||
|
## 本次改造解决了什么
|
||||||
|
|
||||||
|
原版 V免签 更适合传统监控端通过金额回调 `appPush` 完成订单。
|
||||||
|
这次改造的目标是让一个独立的微信协议监听客户端可以:
|
||||||
|
|
||||||
|
1. 从 V免签 服务端拉取当前未支付订单
|
||||||
|
2. 在本地监听到微信到账后,按 `orderId` 精确回推指定订单
|
||||||
|
3. 继续复用 V免签 原本的异步通知逻辑通知商户站点
|
||||||
|
|
||||||
|
这样就避免了以下问题:
|
||||||
|
|
||||||
|
- 只按金额匹配,多个同金额订单时容易串单
|
||||||
|
- 监听端找不到待支付订单时,错误地把微信交易号直接当作 `payId` 去回调
|
||||||
|
- 服务端根域名被误请求,返回首页 HTML 而不是订单处理结果
|
||||||
|
|
||||||
|
## 服务端新增接口
|
||||||
|
|
||||||
|
### 1. `getPendingOrders`
|
||||||
|
|
||||||
|
用途:
|
||||||
|
给客户端拉取当前待支付订单列表。
|
||||||
|
|
||||||
|
请求方式:
|
||||||
|
`GET` 或 `POST`
|
||||||
|
|
||||||
|
参数:
|
||||||
|
|
||||||
|
- `t`
|
||||||
|
当前时间戳
|
||||||
|
- `sign`
|
||||||
|
签名,算法:`md5(t + 通讯密钥)`
|
||||||
|
- `type`
|
||||||
|
支付类型,微信传 `1`,支付宝传 `2`
|
||||||
|
|
||||||
|
返回:
|
||||||
|
返回 `state=0` 的待支付订单列表,包含:
|
||||||
|
|
||||||
|
- `payId`
|
||||||
|
- `orderId`
|
||||||
|
- `param`
|
||||||
|
- `payType`
|
||||||
|
- `price`
|
||||||
|
- `reallyPrice`
|
||||||
|
- `state`
|
||||||
|
- `timeOut`
|
||||||
|
- `date`
|
||||||
|
|
||||||
|
### 2. `appPushOrder`
|
||||||
|
|
||||||
|
用途:
|
||||||
|
客户端本地匹配到具体订单后,通知 V免签 将指定订单置为已支付。
|
||||||
|
|
||||||
|
请求方式:
|
||||||
|
`GET` 或 `POST`
|
||||||
|
|
||||||
|
参数:
|
||||||
|
|
||||||
|
- `orderId`
|
||||||
|
云端订单号
|
||||||
|
- `tradeNo`
|
||||||
|
微信侧交易号
|
||||||
|
- `t`
|
||||||
|
当前时间戳
|
||||||
|
- `sign`
|
||||||
|
签名,算法:`md5(orderId + tradeNo + t + 通讯密钥)`
|
||||||
|
|
||||||
|
处理流程:
|
||||||
|
|
||||||
|
1. 校验签名
|
||||||
|
2. 查询对应 `orderId`
|
||||||
|
3. 订单状态必须为 `0`
|
||||||
|
4. 更新订单为已支付
|
||||||
|
5. 调用原有商户异步通知
|
||||||
|
6. 成功返回 JSON,失败则把订单状态更新为 `2`
|
||||||
|
|
||||||
|
## 需要修改的原项目文件
|
||||||
|
|
||||||
|
如果你自己的 V免签 项目结构和原版一致,只需要替换:
|
||||||
|
|
||||||
|
- `route/route.php`
|
||||||
|
- `application/index/controller/Index.php`
|
||||||
|
|
||||||
|
建议替换前先备份原文件。
|
||||||
|
|
||||||
|
## 部署步骤
|
||||||
|
|
||||||
|
1. 备份线上原文件
|
||||||
|
2. 用本目录中的 `route.php` 覆盖线上 `route/route.php`
|
||||||
|
3. 用本目录中的 `Index.php` 覆盖线上 `application/index/controller/Index.php`
|
||||||
|
4. 确认线上缓存已刷新
|
||||||
|
5. 重新测试客户端与 V免签 的联动
|
||||||
|
|
||||||
|
## 验证方法
|
||||||
|
|
||||||
|
### 验证 1:拉取待支付订单
|
||||||
|
|
||||||
|
先在 V免签 后台或发卡程序创建一笔新的微信订单,确保订单未过期。
|
||||||
|
|
||||||
|
然后请求:
|
||||||
|
|
||||||
|
```text
|
||||||
|
https://你的域名/getPendingOrders?t=当前时间戳&sign=md5(t+通讯密钥)&type=1
|
||||||
|
```
|
||||||
|
|
||||||
|
如果成功,应该返回 JSON,`data` 中能看到待支付微信订单。
|
||||||
|
|
||||||
|
### 验证 2:按订单推送成功
|
||||||
|
|
||||||
|
当客户端匹配到订单后,应请求:
|
||||||
|
|
||||||
|
```text
|
||||||
|
https://你的域名/appPushOrder?orderId=云端订单号&tradeNo=微信交易号&t=当前时间戳&sign=md5(orderId+tradeNo+t+通讯密钥)
|
||||||
|
```
|
||||||
|
|
||||||
|
成功时应返回类似:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{"code":1,"msg":"成功","data":null}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 与原版的关键差异
|
||||||
|
|
||||||
|
### 原版 `appPush`
|
||||||
|
|
||||||
|
原版只按下面三个条件查单:
|
||||||
|
|
||||||
|
- `really_price`
|
||||||
|
- `state=0`
|
||||||
|
- `type`
|
||||||
|
|
||||||
|
这种方式在同金额并发订单下容易误匹配。
|
||||||
|
|
||||||
|
### 改造后的 `appPushOrder`
|
||||||
|
|
||||||
|
改造后由客户端先拉待支付订单,再在本地完成:
|
||||||
|
|
||||||
|
- 金额匹配
|
||||||
|
- 时间范围过滤
|
||||||
|
- 精确得到 `orderId`
|
||||||
|
|
||||||
|
最后再回推给服务端,服务端按 `orderId` 精确处理,不再依赖“金额即订单”。
|
||||||
|
|
||||||
|
## 适用场景
|
||||||
|
|
||||||
|
适用于以下场景:
|
||||||
|
|
||||||
|
- 自己有独立的微信监听客户端
|
||||||
|
- 不希望直接改发卡系统创建订单逻辑
|
||||||
|
- 想保留 V免签 现有订单表、商户通知和后台逻辑
|
||||||
|
- 想把“支付监听”和“订单完成”拆成两段处理
|
||||||
|
|
||||||
|
## 注意事项
|
||||||
|
|
||||||
|
1. `getPendingOrders` 只会返回未过期且 `state=0` 的订单
|
||||||
|
2. 如果客户端一直拉到 `0` 条订单,先检查订单是否已经过期
|
||||||
|
3. 如果客户端监听到了微信收款,但没匹配到订单,不应该再回调根域名
|
||||||
|
4. 商户异步通知仍然依赖原表中的 `notify_url`
|
||||||
|
5. 如果你在服务端做了二次开发,替换前先比对自定义逻辑
|
||||||
|
|
||||||
|
## 推荐客户端配合逻辑
|
||||||
|
|
||||||
|
为了避免刷历史收款记录,客户端建议再做两件事:
|
||||||
|
|
||||||
|
1. 启动协议监听时忽略历史账单,只处理启动后的新收款
|
||||||
|
2. 正常轮询成功时不要持续打印日志,只在状态变化、检测到收款或异常时打印
|
||||||
|
|
||||||
|
这样用户体验会更好,也更容易排查问题。
|
||||||
37
vmq-customization-pack/route.php
Normal file
37
vmq-customization-pack/route.php
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
// | Author: liu21st <liu21st@gmail.com>
|
||||||
|
// +----------------------------------------------------------------------
|
||||||
|
|
||||||
|
Route::get('think', function () {
|
||||||
|
return 'hello,ThinkPHP5!';
|
||||||
|
});
|
||||||
|
|
||||||
|
Route::any('login','index/index/login');
|
||||||
|
Route::any('getMenu','index/index/getMenu');
|
||||||
|
Route::any('enQrcode','admin/index/enQrcode');
|
||||||
|
Route::any('createOrder','index/index/createOrder');
|
||||||
|
|
||||||
|
|
||||||
|
Route::any('getOrder','index/index/getOrder');
|
||||||
|
Route::any('checkOrder','index/index/checkOrder');
|
||||||
|
Route::any('getPendingOrders','index/index/getPendingOrders');
|
||||||
|
Route::any('getState','index/index/getState');
|
||||||
|
|
||||||
|
Route::any('appHeart','index/index/appHeart');
|
||||||
|
Route::any('appPush','index/index/appPush');
|
||||||
|
Route::any('appPushOrder','index/index/appPushOrder');
|
||||||
|
|
||||||
|
|
||||||
|
Route::any('closeEndOrder','index/index/closeEndOrder');
|
||||||
|
|
||||||
|
|
||||||
|
return [
|
||||||
|
|
||||||
|
];
|
||||||
Loading…
Reference in New Issue
Block a user