diff --git a/app/data/controller/Payment.php b/app/data/controller/Payment.php index 9d3eb5aad..e13b46967 100644 --- a/app/data/controller/Payment.php +++ b/app/data/controller/Payment.php @@ -74,15 +74,20 @@ class Payment extends Controller protected function _form_filter(array &$data) { if ($this->request->isGet()) { - foreach ($this->types as &$vo) { - $binds = []; + $this->payments = []; + foreach ($this->types as $k => $vo) { + [$allow, $group] = [[], ucfirst(strstr($k, '_', true))]; foreach ($vo['bind'] as $api) if (isset(UserService::TYPES[$api])) { - $binds[$api] = UserService::TYPES[$api]['name']; + $allow[$api] = UserService::TYPES[$api]['name']; } - $vo['allow'] = join('、', $binds); + $vo['allow'] = join('、', $allow); + $this->payments[$group][$k] = $vo; } $data['content'] = json_decode($data['content'] ?? '[]', true) ?: []; } else { + if (empty($data['type'])) { + $this->error('请选择支付通道并配置支付参数!'); + } $data['content'] = json_encode($this->request->post() ?: [], JSON_UNESCAPED_UNICODE); } } diff --git a/app/data/controller/api/Login.php b/app/data/controller/api/Login.php index 1322a8720..2e404371f 100644 --- a/app/data/controller/api/Login.php +++ b/app/data/controller/api/Login.php @@ -17,7 +17,7 @@ class Login extends Controller * 接口认证类型 * @var string */ - private $type = UserService::APITYPE_WAP; + private $type; /** * 绑定数据表 @@ -25,6 +25,17 @@ class Login extends Controller */ protected $table = 'DataUser'; + /** + * 控制器初始化 + */ + protected function initialize() + { + $this->type = input('api', UserService::APITYPE_WAP); + if (empty(UserService::TYPES[$this->type])) { + $this->error("接口通道[{$this->type}]未定义规则!"); + } + } + /** * 用户登录接口 * @throws \think\Exception diff --git a/app/data/controller/api/Notify.php b/app/data/controller/api/Notify.php index 7c040c66f..4db9f8c58 100644 --- a/app/data/controller/api/Notify.php +++ b/app/data/controller/api/Notify.php @@ -2,6 +2,7 @@ namespace app\data\controller\api; +use app\data\service\payment\AliPaymentService; use app\data\service\payment\JoinPaymentService; use app\data\service\payment\WechatPaymentService; use think\admin\Controller; @@ -32,6 +33,21 @@ class Notify extends Controller } } + /** + * 支付宝支付通知 + * @param string $scene 支付场景 + * @param string $param 支付通道 + * @return string + */ + public function alipay(string $scene = 'order', string $param = ''): string + { + if (strtolower($scene) === 'order') { + return AliPaymentService::instance()->notify($param); + } else { + return 'success'; + } + } + /** * 汇聚支付通知 * @param string $scene 支付场景 diff --git a/app/data/service/PaymentService.php b/app/data/service/PaymentService.php index faf08395f..e52a0b412 100644 --- a/app/data/service/PaymentService.php +++ b/app/data/service/PaymentService.php @@ -19,35 +19,61 @@ abstract class PaymentService extends Service const PAYMENT_JOINPAY_XCX = 'joinpay_xcx'; // 微信支付通道 + const PAYMENT_WECHAT_APP = 'wechat_app'; const PAYMENT_WECHAT_MWEB = 'wechat_mweb'; const PAYMENT_WECHAT_JSAPI = 'wechat_jsapi'; const PAYMENT_WECHAT_NATIVE = 'wechat_native'; + // 支付宝支付通道 + const PAYMENT_ALIAPY_APP = 'alipay_app'; + const PAYMENT_ALIPAY_WAP = 'alipay_wap'; + const PAYMENT_ALIPAY_WEB = 'alipay_web'; + // 支付通道配置 const TYPES = [ + PaymentService::PAYMENT_WECHAT_APP => [ + 'type' => 'APP', + 'name' => '微信商户 APP 支付', + 'bind' => [UserService::APITYPE_IOSAPP, UserService::APITYPE_ANDROID], + ], PaymentService::PAYMENT_WECHAT_MWEB => [ 'type' => 'MWEB', - 'name' => '微信商户H5支付', + 'name' => '微信商户 H5 支付', 'bind' => [UserService::APITYPE_WAP], ], PaymentService::PAYMENT_WECHAT_NATIVE => [ 'type' => 'NATIVE', - 'name' => '微信商户NATIVE支付', + 'name' => '微信商户 NATIVE 支付', 'bind' => [UserService::APITYPE_WEB], ], PaymentService::PAYMENT_WECHAT_JSAPI => [ 'type' => 'JSAPI', - 'name' => '微信商户JSAPI支付', + 'name' => '微信商户 JSAPI 支付', 'bind' => [UserService::APITYPE_WXAPP, UserService::APITYPE_WECHAT], ], + PaymentService::PAYMENT_ALIAPY_APP => [ + 'type' => '', + 'name' => '支付宝 APP 支付', + 'bind' => [UserService::APITYPE_ANDROID, UserService::APITYPE_IOSAPP], + ], + PaymentService::PAYMENT_ALIPAY_WAP => [ + 'type' => '', + 'name' => '支付宝 WAP 支付', + 'bind' => [UserService::APITYPE_WAP], + ], + PaymentService::PAYMENT_ALIPAY_WEB => [ + 'type' => '', + 'name' => '支付宝 WEB 支付', + 'bind' => [UserService::APITYPE_WEB], + ], PaymentService::PAYMENT_JOINPAY_XCX => [ 'type' => 'WEIXIN_XCX', - 'name' => '汇聚小程序JSAPI支付', + 'name' => '汇聚小程序 JSAPI 支付', 'bind' => [UserService::APITYPE_WXAPP], ], PaymentService::PAYMENT_JOINPAY_GZH => [ 'type' => 'WEIXIN_GZH', - 'name' => '汇聚服务号JSAPI支付', + 'name' => '汇聚服务号 JSAPI 支付', 'bind' => [UserService::APITYPE_WECHAT], ], ]; diff --git a/app/data/service/UserService.php b/app/data/service/UserService.php index e880f07d0..a24c64097 100644 --- a/app/data/service/UserService.php +++ b/app/data/service/UserService.php @@ -15,24 +15,34 @@ class UserService extends Service const APITYPE_WEB = 'web'; const APITYPE_WXAPP = 'wxapp'; const APITYPE_WECHAT = 'wechat'; + const APITYPE_IOSAPP = 'ios'; + const APITYPE_ANDROID = 'android'; const TYPES = [ - UserService::APITYPE_WAP => [ - 'name' => '手机浏览器终端', + UserService::APITYPE_WAP => [ + 'name' => '手机浏览器', 'auth' => '', ], - UserService::APITYPE_WEB => [ - 'name' => '电脑浏览器终端', + UserService::APITYPE_WEB => [ + 'name' => '电脑浏览器', 'auth' => '', ], - UserService::APITYPE_WXAPP => [ - 'name' => '微信小程序终端', + UserService::APITYPE_WXAPP => [ + 'name' => '微信小程序', 'auth' => 'openid1', ], - UserService::APITYPE_WECHAT => [ - 'name' => '微信服务号终端', + UserService::APITYPE_WECHAT => [ + 'name' => '微信服务号', 'auth' => 'openid2', ], + UserService::APITYPE_ANDROID => [ + 'name' => '安卓应用', + 'auth' => '', + ], + UserService::APITYPE_IOSAPP => [ + 'name' => '苹果应用', + 'auth' => '', + ], ]; /** diff --git a/app/data/service/payment/AliPaymentService.php b/app/data/service/payment/AliPaymentService.php new file mode 100644 index 000000000..651c634cf --- /dev/null +++ b/app/data/service/payment/AliPaymentService.php @@ -0,0 +1,141 @@ +params = [ + // 沙箱模式 + 'debug' => false, + // 签名类型(RSA|RSA2) + 'sign_type' => "RSA2", + // 应用ID + 'appid' => static::$config['alipay_appid'], + // 支付宝公钥 (1行填写,特别注意,这里是支付宝公钥,不是应用公钥,最好从开发者中心的网页上去复制) + 'public_key' => static::$config['alipay_public_key'], + // 支付宝私钥 (1行填写) + 'private_key' => static::$config['alipay_private_key'], + // 应用公钥证书(新版资金类接口转 app_cert_sn) + 'app_cert' => '', + // 支付宝根证书(新版资金类接口转 alipay_root_cert_sn) + 'root_cert' => '', + // 支付成功通知地址 + 'notify_url' => '', + // 网页支付回跳地址 + 'return_url' => '', + ]; + return $this; + } + + /** + * 支付结果处理 + * @param string $type 支付通道 + * @return string + * @throws \WeChat\Exceptions\InvalidResponseException + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\DbException + * @throws \think\db\exception\ModelNotFoundException + */ + public function notify(string $type = ''): string + { + if (is_numeric(stripos($type, '-'))) { + [$payType, $payId] = explode('-', $type); + } else { + [$payType, $payId] = [$type ?: static::$type, static::$id]; + } + $notify = \AliPay\App::instance($this->params)->notify(); + if (in_array($notify['trade_status'], ['TRADE_SUCCESS', 'TRADE_FINISHED'])) { + // 更新支付记录 + data_save('DataPaymentItem', [ + 'order_no' => $notify['out_trade_no'], + 'payment_id' => $payId, + 'payment_type' => $payType, + 'payment_code' => $notify['trade_no'], + 'payment_amount' => $notify['total_amount'], + 'payment_status' => 1, + 'payment_datatime' => date('Y-m-d H:i:s'), + ], 'order_no', ['payment_type' => $payType, 'payment_status' => 0]); + // 更新记录状态 + if ($this->updateOrder($notify['out_trade_no'], $notify['trade_no'], $notify['total_amount'], $payType)) { + return 'success'; + } + } else { + return 'error'; + } + } + + /** + * 查询订单数据 + * @param string $orderNo + * @return array + * @throws \WeChat\Exceptions\InvalidResponseException + * @throws \WeChat\Exceptions\LocalCacheException + */ + public function query(string $orderNo): array + { + return \AliPay\App::instance($this->params)->query($orderNo); + } + + /** + * 创建订单支付参数 + * @param string $openid 会员OPENID + * @param string $orderNo 交易订单单号 + * @param string $payAmount 交易订单金额(元) + * @param string $payTitle 交易订单名称 + * @param string $payRemark 订单订单描述 + * @return array + * @throws \think\Exception + */ + public function create(string $openid, string $orderNo, string $payAmount, string $payTitle, string $payRemark): array + { + try { + if (isset(static::TYPES[static::$type])) { + $tradeType = static::TYPES[static::$type]['type']; + $tradeParam = static::$type . '-' . static::$id; + } else { + throw new \think\Exception('支付类型[' . static::$type . ']未配置定义!'); + } + $this->params['notify_url'] = sysuri("@data/api.notify/alipay/scene/order/param/{$tradeParam}", [], false, true); + if ($tradeType === static::PAYMENT_WECHAT_APP) { + $payment = \AliPay\App::instance($this->params); + } elseif ($tradeType === static::PAYMENT_ALIPAY_WAP) { + $payment = \AliPay\Wap::instance($this->params); + } elseif ($tradeType === static::PAYMENT_ALIPAY_WEB) { + $payment = \AliPay\Web::instance($this->params); + } else { + throw new \think\Exception("支付类型[{$tradeType}]暂时不支持!"); + } + $result = $payment->apply(['out_trade_no' => $orderNo, 'total_amount' => $payAmount, 'subject' => $payTitle, 'body' => $payRemark]); + // 创建支付记录 + $this->app->db->name('DataPaymentItem')->insert([ + 'order_no' => $orderNo, 'order_name' => $payTitle, 'order_amount' => $payAmount, + 'payment_id' => static::$id, 'payment_type' => static::$type, + ]); + return ['result' => $result]; + } catch (\think\Exception $exception) { + throw $exception; + } catch (\Exception $exception) { + throw new \think\Exception($exception->getMessage(), $exception->getCode()); + } + } +} \ No newline at end of file diff --git a/app/data/service/payment/JoinPaymentService.php b/app/data/service/payment/JoinPaymentService.php index 1dfc0ff94..e6c712ba2 100644 --- a/app/data/service/payment/JoinPaymentService.php +++ b/app/data/service/payment/JoinPaymentService.php @@ -70,7 +70,7 @@ class JoinPaymentService extends PaymentService try { if (isset(static::TYPES[static::$type])) { $tradeType = static::TYPES[static::$type]['type']; - $tradeParam = static::$type . '_' . static::$id; + $tradeParam = static::$type . '-' . static::$id; } else { throw new \think\Exception('支付类型[' . static::$type . ']未配置定义!'); } @@ -132,8 +132,8 @@ class JoinPaymentService extends PaymentService */ public function notify(string $type = ''): string { - if (is_numeric(stripos($type, '_'))) { - [$payType, $payId] = explode('_', $type); + if (is_numeric(stripos($type, '-'))) { + [$payType, $payId] = explode('-', $type); } else { [$payType, $payId] = [$type ?: static::$type, static::$id]; } diff --git a/app/data/service/payment/WechatPaymentService.php b/app/data/service/payment/WechatPaymentService.php index a9d4f2177..28e6212b3 100644 --- a/app/data/service/payment/WechatPaymentService.php +++ b/app/data/service/payment/WechatPaymentService.php @@ -60,7 +60,7 @@ class WechatPaymentService extends PaymentService try { if (isset(static::TYPES[static::$type])) { $tradeType = static::TYPES[static::$type]['type']; - $tradeParam = static::$type . '_' . static::$id; + $tradeParam = static::$type . '-' . static::$id; } else { throw new \think\Exception('支付类型[' . static::$type . ']未配置定义!'); } @@ -108,8 +108,8 @@ class WechatPaymentService extends PaymentService */ public function notify(string $type = ''): string { - if (is_numeric(stripos($type, '_'))) { - [$payType, $payId] = explode('_', $type); + if (is_numeric(stripos($type, '-'))) { + [$payType, $payId] = explode('-', $type); } else { [$payType, $payId] = [$type ?: static::$type, static::$id]; } diff --git a/app/data/view/payment/form.html b/app/data/view/payment/form.html index 35961bfbc..58fb4ef8c 100644 --- a/app/data/view/payment/form.html +++ b/app/data/view/payment/form.html @@ -14,22 +14,25 @@