mirror of
https://github.com/crmeb/CRMEB.git
synced 2025-12-31 08:10:19 +00:00
390 lines
9.1 KiB
PHP
390 lines
9.1 KiB
PHP
<?php
|
|
|
|
/*
|
|
* This file is part of the overtrue/wechat.
|
|
*
|
|
* (c) overtrue <i@overtrue.me>
|
|
*
|
|
* This source file is subject to the MIT license that is bundled
|
|
* with this source code in the file LICENSE.
|
|
*/
|
|
|
|
/**
|
|
* Payment.php.
|
|
*
|
|
* @author overtrue <i@overtrue.me>
|
|
* @copyright 2015 overtrue <i@overtrue.me>
|
|
*
|
|
* @see https://github.com/overtrue
|
|
* @see http://overtrue.me
|
|
*/
|
|
|
|
namespace EasyWeChat\Payment;
|
|
|
|
use Doctrine\Common\Cache\Cache;
|
|
use EasyWeChat\Core\Exceptions\FaultException;
|
|
use EasyWeChat\Support\Url as UrlHelper;
|
|
use EasyWeChat\Support\XML;
|
|
use Overtrue\Socialite\AccessTokenInterface;
|
|
use Symfony\Component\HttpFoundation\Response;
|
|
|
|
/**
|
|
* Class Payment.
|
|
*
|
|
* @mixin API
|
|
*/
|
|
class Payment
|
|
{
|
|
/**
|
|
* Scheme base path.
|
|
*/
|
|
const SCHEME_PATH = 'weixin://wxpay/bizpayurl';
|
|
|
|
/**
|
|
* @var API
|
|
*/
|
|
protected $api;
|
|
|
|
/**
|
|
* Merchant instance.
|
|
*
|
|
* @var \EasyWeChat\Payment\Merchant
|
|
*/
|
|
protected $merchant;
|
|
|
|
/**
|
|
* Cache.
|
|
*
|
|
* @var \Doctrine\Common\Cache\Cache
|
|
*/
|
|
protected $cache;
|
|
|
|
/**
|
|
* Constructor.
|
|
*
|
|
* @param \EasyWeChat\Payment\Merchant $merchant
|
|
* @param \Doctrine\Common\Cache\Cache|null $cache
|
|
*/
|
|
public function __construct(Merchant $merchant, Cache $cache = null)
|
|
{
|
|
$this->merchant = $merchant;
|
|
$this->cache = $cache;
|
|
}
|
|
|
|
/**
|
|
* Build payment scheme for product.
|
|
*
|
|
* @param string $productId
|
|
*
|
|
* @return string
|
|
*/
|
|
public function scheme($productId)
|
|
{
|
|
$params = [
|
|
'appid' => $this->merchant->app_id,
|
|
'mch_id' => $this->merchant->merchant_id,
|
|
'time_stamp' => time(),
|
|
'nonce_str' => uniqid(),
|
|
'product_id' => $productId,
|
|
];
|
|
|
|
$params['sign'] = generate_sign($params, $this->merchant->key, 'md5');
|
|
|
|
return self::SCHEME_PATH.'?'.http_build_query($params);
|
|
}
|
|
|
|
/**
|
|
* Handle payment notify.
|
|
*
|
|
* @param callable $callback
|
|
*
|
|
* @return Response
|
|
*/
|
|
public function handleNotify(callable $callback)
|
|
{
|
|
$notify = $this->getNotify();
|
|
|
|
if (!$notify->isValid()) {
|
|
throw new FaultException('Invalid request payloads.', 400);
|
|
}
|
|
|
|
$notify = $notify->getNotify();
|
|
$successful = 'SUCCESS' === $notify->get('result_code');
|
|
|
|
$handleResult = call_user_func_array($callback, [$notify, $successful]);
|
|
|
|
if (is_bool($handleResult) && $handleResult) {
|
|
$response = [
|
|
'return_code' => 'SUCCESS',
|
|
'return_msg' => 'OK',
|
|
];
|
|
} else {
|
|
$response = [
|
|
'return_code' => 'FAIL',
|
|
'return_msg' => $handleResult,
|
|
];
|
|
}
|
|
|
|
return new Response(XML::build($response));
|
|
}
|
|
|
|
/**
|
|
* Handle refund notify.
|
|
*
|
|
* @param callable $callback
|
|
*
|
|
* @return Response
|
|
*/
|
|
public function handleRefundNotify(callable $callback)
|
|
{
|
|
$notify = $this->getRefundNotify()->getNotify();
|
|
$successful = 'SUCCESS' === $notify->get('return_code');
|
|
|
|
$handleResult = call_user_func_array($callback, [$notify, $successful]);
|
|
|
|
if (is_bool($handleResult) && $handleResult) {
|
|
$response = [
|
|
'return_code' => 'SUCCESS',
|
|
'return_msg' => 'OK',
|
|
];
|
|
} else {
|
|
$response = [
|
|
'return_code' => 'FAIL',
|
|
'return_msg' => $handleResult,
|
|
];
|
|
}
|
|
|
|
return new Response(XML::build($response));
|
|
}
|
|
|
|
/**
|
|
* Handle native scan notify.
|
|
* https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_4
|
|
* The callback shall return string of prepay_id or throw an exception.
|
|
*
|
|
* @param callable $callback
|
|
*
|
|
* @return Response
|
|
*/
|
|
public function handleScanNotify(callable $callback)
|
|
{
|
|
$notify = $this->getNotify();
|
|
|
|
if (!$notify->isValid()) {
|
|
throw new FaultException('Invalid request payloads.', 400);
|
|
}
|
|
|
|
$notify = $notify->getNotify();
|
|
|
|
try {
|
|
$prepayId = call_user_func_array($callback, [$notify->get('product_id'), $notify->get('openid'), $notify]);
|
|
$response = [
|
|
'return_code' => 'SUCCESS',
|
|
'appid' => $this->merchant->app_id,
|
|
'mch_id' => $this->merchant->merchant_id,
|
|
'nonce_str' => uniqid(),
|
|
'prepay_id' => strval($prepayId),
|
|
'result_code' => 'SUCCESS',
|
|
];
|
|
$response['sign'] = generate_sign($response, $this->merchant->key);
|
|
} catch (\Exception $e) {
|
|
$response = [
|
|
'return_code' => 'SUCCESS',
|
|
'return_msg' => $e->getCode(),
|
|
'result_code' => 'FAIL',
|
|
'err_code_des' => $e->getMessage(),
|
|
];
|
|
}
|
|
|
|
return new Response(XML::build($response));
|
|
}
|
|
|
|
/**
|
|
* [WeixinJSBridge] Generate js config for payment.
|
|
*
|
|
* <pre>
|
|
* WeixinJSBridge.invoke(
|
|
* 'getBrandWCPayRequest',
|
|
* ...
|
|
* );
|
|
* </pre>
|
|
*
|
|
* @param string $prepayId
|
|
* @param bool $json
|
|
*
|
|
* @return string|array
|
|
*/
|
|
public function configForPayment($prepayId, $json = true)
|
|
{
|
|
$params = [
|
|
'appId' => $this->merchant->app_id,
|
|
'timeStamp' => strval(time()),
|
|
'nonceStr' => uniqid(),
|
|
'package' => "prepay_id=$prepayId",
|
|
'signType' => 'MD5',
|
|
];
|
|
|
|
$params['paySign'] = generate_sign($params, $this->merchant->key, 'md5');
|
|
|
|
return $json ? json_encode($params) : $params;
|
|
}
|
|
|
|
/**
|
|
* [JSSDK] Generate js config for payment.
|
|
*
|
|
* <pre>
|
|
* wx.chooseWXPay({...});
|
|
* </pre>
|
|
*
|
|
* @param string $prepayId
|
|
*
|
|
* @return array|string
|
|
*/
|
|
public function configForJSSDKPayment($prepayId)
|
|
{
|
|
$config = $this->configForPayment($prepayId, false);
|
|
|
|
$config['timestamp'] = $config['timeStamp'];
|
|
unset($config['timeStamp']);
|
|
|
|
return $config;
|
|
}
|
|
|
|
/**
|
|
* Generate app payment parameters.
|
|
*
|
|
* @param string $prepayId
|
|
*
|
|
* @return array
|
|
*/
|
|
public function configForAppPayment($prepayId)
|
|
{
|
|
$params = [
|
|
'appid' => $this->merchant->app_id,
|
|
'partnerid' => $this->merchant->merchant_id,
|
|
'prepayid' => $prepayId,
|
|
'noncestr' => uniqid(),
|
|
'timestamp' => time(),
|
|
'package' => 'Sign=WXPay',
|
|
];
|
|
|
|
$params['sign'] = generate_sign($params, $this->merchant->key);
|
|
|
|
return $params;
|
|
}
|
|
|
|
/**
|
|
* Generate js config for share user address.
|
|
*
|
|
* @param string|\Overtrue\Socialite\AccessTokenInterface $accessToken
|
|
* @param bool $json
|
|
*
|
|
* @return string|array
|
|
*/
|
|
public function configForShareAddress($accessToken, $json = true)
|
|
{
|
|
if ($accessToken instanceof AccessTokenInterface) {
|
|
$accessToken = $accessToken->getToken();
|
|
}
|
|
|
|
$params = [
|
|
'appId' => $this->merchant->app_id,
|
|
'scope' => 'jsapi_address',
|
|
'timeStamp' => strval(time()),
|
|
'nonceStr' => uniqid(),
|
|
'signType' => 'SHA1',
|
|
];
|
|
|
|
$signParams = [
|
|
'appid' => $params['appId'],
|
|
'url' => UrlHelper::current(),
|
|
'timestamp' => $params['timeStamp'],
|
|
'noncestr' => $params['nonceStr'],
|
|
'accesstoken' => strval($accessToken),
|
|
];
|
|
|
|
ksort($signParams);
|
|
|
|
$params['addrSign'] = sha1(urldecode(http_build_query($signParams)));
|
|
|
|
return $json ? json_encode($params) : $params;
|
|
}
|
|
|
|
/**
|
|
* Merchant setter.
|
|
*
|
|
* @param Merchant $merchant
|
|
*/
|
|
public function setMerchant(Merchant $merchant)
|
|
{
|
|
$this->merchant = $merchant;
|
|
}
|
|
|
|
/**
|
|
* Merchant getter.
|
|
*
|
|
* @return Merchant
|
|
*/
|
|
public function getMerchant()
|
|
{
|
|
return $this->merchant;
|
|
}
|
|
|
|
/**
|
|
* Return Notify instance.
|
|
*
|
|
* @return \EasyWeChat\Payment\Notify
|
|
*/
|
|
public function getNotify()
|
|
{
|
|
return new Notify($this->merchant);
|
|
}
|
|
|
|
/**
|
|
* Return RefundNotify instance.
|
|
*
|
|
* @return \EasyWeChat\Payment\RefundNotify
|
|
*/
|
|
public function getRefundNotify()
|
|
{
|
|
return new RefundNotify($this->merchant);
|
|
}
|
|
|
|
/**
|
|
* API setter.
|
|
*
|
|
* @param API $api
|
|
*/
|
|
public function setAPI(API $api)
|
|
{
|
|
$this->api = $api;
|
|
}
|
|
|
|
/**
|
|
* Return API instance.
|
|
*
|
|
* @return API
|
|
*/
|
|
public function getAPI()
|
|
{
|
|
return $this->api ?: $this->api = new API($this->getMerchant(), $this->cache);
|
|
}
|
|
|
|
/**
|
|
* Magic call.
|
|
*
|
|
* @param string $method
|
|
* @param array $args
|
|
*
|
|
* @return mixed
|
|
*
|
|
* @codeCoverageIgnore
|
|
*/
|
|
public function __call($method, $args)
|
|
{
|
|
if (is_callable([$this->getAPI(), $method])) {
|
|
return call_user_func_array([$this->api, $method], $args);
|
|
}
|
|
}
|
|
}
|