SanJinService.php 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. <?php
  2. namespace App\Services\Payment;
  3. use GuzzleHttp\Client;
  4. use GuzzleHttp\Exception\RequestException;
  5. use GuzzleHttp\Psr7\Response;
  6. use App\Services\BaseService;
  7. use Illuminate\Support\Facades\Lang;
  8. use App\Models\RechargeChannel;
  9. use App\Models\RechargeChannelGroup;
  10. class SanJinService extends BaseService
  11. {
  12. const REQUEST_URL = 'https://jkapi-sanjin.jkcbb.com/';
  13. const PRODUCT_TEST = 'T888'; // 测试支付通道
  14. public static $CHANNEL = [
  15. 'wxsm' => '微信扫码',
  16. 'zfbsm' => '支付宝扫码',
  17. 'zfbge' => '支付宝固额',
  18. 'zfbzk' => '支付宝转卡',
  19. 'ylsm' => '银联扫码',
  20. 'szrmb' => '数字人民币',
  21. 'sdjt' => '手动金条',
  22. ];
  23. /**
  24. * @description: 获取支付频道
  25. * @return {*}
  26. */
  27. public static function getChannel($type = '', ?int $groupId = null)
  28. {
  29. if ($type) {
  30. if ($groupId && RechargeChannel::checkRechargeChannel($type, $groupId) === false) return '';
  31. $name = RechargeChannel::where('data_type', 1)->where('from', 1)
  32. ->where('status', 1)->where('type', $type)->value('name');
  33. return Lang($name);
  34. } else {
  35. $query = RechargeChannel::query()->where('status', 1)->where('data_type', 1)->where('from', 1);
  36. if ($groupId) {
  37. $group = RechargeChannelGroup::query()->find($groupId);
  38. $query->whereIn('type', $group ? (array)$group->recharge_type : []);
  39. }
  40. return $query->orderBy('sort')->get(['type', 'name'])
  41. ->mapWithKeys(fn ($row) => [(string)$row->type => lang($row->name)])->all();
  42. }
  43. }
  44. // public static $PRODUCT = [
  45. // // 'T888' => [
  46. // // 'type' => 'test',
  47. // // 'rate' => 0.02,
  48. // // 'max' => 5000,
  49. // // 'min' => 10
  50. // // ],
  51. // 'WX002' => [
  52. // 'type' => 'wxsm',
  53. // 'rate' => 0.095,
  54. // 'max' => 3000,
  55. // 'min' => 100
  56. // ],
  57. // 'YL001' => [
  58. // 'type' => 'ylsm',
  59. // 'rate' => 0.05,
  60. // 'max' => 500,
  61. // 'min' => 50
  62. // ],
  63. // 'SZ002' => [
  64. // 'type' => 'szrmb',
  65. // 'rate' => 0.05,
  66. // 'max' => 100,
  67. // 'min' => 10
  68. // ],
  69. // 'SZ001' => [
  70. // 'type' => 'szrmb',
  71. // 'rate' => 0.048,
  72. // 'max' => 5000,
  73. // 'min' => 100
  74. // ],
  75. // 'ZFB001' => [
  76. // 'type' => 'zfbsm',
  77. // 'rate' => 0.085,
  78. // 'max' => 200,
  79. // 'min' => 100
  80. // ],
  81. // 'ZFB002' => [
  82. // 'type' => 'zfbsm',
  83. // 'rate' => 0.057,
  84. // 'max' => 1000,
  85. // 'min' => 200
  86. // ],
  87. // 'ZFB003' => [
  88. // 'type' => 'zfbsm',
  89. // 'rate' => 0.052,
  90. // 'max' => 3000,
  91. // 'min' => 1000
  92. // ],
  93. // 'ZFB004' => [
  94. // 'type' => 'zfbsm',
  95. // 'rate' => 0.042,
  96. // 'max' => 20000,
  97. // 'min' => 3000
  98. // ],
  99. // 'ZFB005' => [
  100. // 'type' => 'zfbge',
  101. // 'rate' => 0.027,
  102. // 'fixed' => [945 ,988 ,990]
  103. // ],
  104. // 'ZFBZK001' => [
  105. // 'type' => 'zfbzk',
  106. // 'rate' => 0.05,
  107. // 'max' => 2000,
  108. // 'min' => 200
  109. // ],
  110. // 'JT000' => [
  111. // 'type' => 'sdjt',
  112. // 'rate' => 0.08,
  113. // 'max' => 300,
  114. // 'min' => 100
  115. // ],
  116. // 'JT001' => [
  117. // 'type' => 'sdjt',
  118. // 'rate' => 0.08,
  119. // 'max' => 3000,
  120. // 'min' => 300
  121. // ],
  122. // 'JT002' => [
  123. // 'type' => 'sdjt',
  124. // 'rate' => 0.08,
  125. // 'max' => 5000,
  126. // 'min' => 500
  127. // ],
  128. // ];
  129. public static function product(?int $groupId = null)
  130. {
  131. $product = RechargeChannel::product(1);
  132. if (!$groupId) return $product;
  133. $group = RechargeChannelGroup::query()->find($groupId);
  134. $types = $group ? (array)$group->recharge_type : [];
  135. return array_filter($product, fn ($row) => in_array((string)$row['type'], $types, true));
  136. }
  137. // 获取商户ID
  138. public static function getMerchantId()
  139. {
  140. return config('app.tree_pay_mch_id');
  141. }
  142. // 获取商户秘钥
  143. public static function getSecret()
  144. {
  145. return config('app.tree_pay_key');
  146. }
  147. // 获取异步的通知地址
  148. public static function getNotifyUrl()
  149. {
  150. $host = config('app.url');
  151. return $host.'/api/pay/harvest';
  152. }
  153. /**
  154. * @description: 获取请求客户端
  155. * @return {*}
  156. */
  157. public static function getClient(): Client
  158. {
  159. return new Client([
  160. 'base_uri' => self::REQUEST_URL,
  161. 'timeout' => 5.0,
  162. ]);
  163. }
  164. // 签名
  165. public static function signature($params = [],$must = [])
  166. {
  167. if($must){
  168. foreach($params as $k => $v){
  169. if(!in_array($k,$must)){
  170. unset($params[$k]);
  171. }
  172. }
  173. }
  174. ksort($params, SORT_STRING);
  175. $parts = [];
  176. foreach($params as $k => $v){
  177. array_push($parts,$k.'='.$v);
  178. }
  179. $mch_key = self::getSecret();
  180. $parts[] = "key=".$mch_key;
  181. $sign = md5(implode('&',$parts));
  182. return $sign;
  183. }
  184. /**
  185. * @description: 发起支付订单
  186. * @param {*} $amount 金额单位分
  187. * @param {*} $orderNo 订单号
  188. * @param {*} $type 支付通道
  189. * @return {*}
  190. */
  191. public static function pay($amount,$orderNo,$type = self::PRODUCT_TEST)
  192. {
  193. $must = ['mchId','productId','outTradeNo','amount','reqTime','notifyUrl'];
  194. $mch_id = self::getMerchantId();
  195. $data = [];
  196. $data['mchId'] = $mch_id;
  197. $data['amount'] = $amount;
  198. $data['outTradeNo'] = $orderNo;
  199. $data['notifyUrl'] = self::getNotifyUrl();
  200. $data['reqTime'] = time() * 1000;
  201. $data['productId'] = $type;
  202. $data['sign'] = self::signature($data,$must);
  203. $client = self::getClient();
  204. $response = $client->post('api/v1/pay/unifiedOrder', [
  205. 'json' => $data,
  206. 'headers' => [
  207. 'Content-Type' => 'application/json',
  208. ]
  209. ]);
  210. $body = $response->getBody();
  211. return json_decode($body->getContents(), true);
  212. }
  213. /**
  214. * @description: 查询订单
  215. * @param {*} $orderNo 订单号
  216. * @return {*}
  217. */
  218. public static function queryOrder($orderNo)
  219. {
  220. $must = ['mchId','outTradeNo','reqTime'];
  221. $mch_id = self::getMerchantId();
  222. $data = [];
  223. $data['mchId'] = $mch_id;
  224. $data['outTradeNo'] = $orderNo;
  225. $data['reqTime'] = time() * 1000;
  226. $data['sign'] = self::signature($data,$must);
  227. $client = self::getClient();
  228. $response = $client->post('api/v1/pay/queryOrder', [
  229. 'json' => $data,
  230. 'headers' => [
  231. 'Content-Type' => 'application/json',
  232. ]
  233. ]);
  234. $body = $response->getBody();
  235. return json_decode($body->getContents(), true);
  236. }
  237. public static function getWhere(array $search = []): array
  238. {
  239. return [];
  240. }
  241. }