AdapayV2.php 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490
  1. <?php
  2. /**
  3. * 重庆赤晓店信息科技有限公司
  4. * https://www.chixiaodian.com
  5. * Copyright (c) 2023 赤店商城 All rights reserved.
  6. */
  7. namespace app\utils\Adapay;
  8. use app\models\Option;
  9. use app\constants\OptionSetting;
  10. use app\models\LevelOrder;
  11. use app\models\Order;
  12. use app\models\OrderUnion;
  13. use app\models\ReOrder;
  14. use app\models\SaasUser;
  15. use app\models\Store;
  16. use app\models\WechatConfig;
  17. use app\modules\client\models\v1\OpenidForm;
  18. use app\utils\DataTransform;
  19. use app\utils\OrderNo;
  20. use EasyWeChat\Kernel\Exceptions\Exception;
  21. use GuzzleHttp\Exception\GuzzleException;
  22. use yii\base\BaseObject;
  23. use function GuzzleHttp\Psr7\str;
  24. use app\models\DeliveryInfo;
  25. use app\models\AccountLog;
  26. use app\modules\admin\models\SaasForm;
  27. use app\models\SaasDistribution;
  28. use BsPaySdk\core\BsPayTools;
  29. use BsPaySdk\core\BsPay;
  30. use BsPaySdk\core\BsPayClient;
  31. //use BsPaySdk\request\V2TradeOnlinepaymentQuickpayFrontpayRequest;
  32. define('BsPaySdk_Path', \Yii::$app->basePath . "/utils/Adapay/bspay-php-sdk/BsPaySdk");
  33. include_once BsPaySdk_Path . "/init.php";
  34. class AdapayV2 extends Adapay
  35. {
  36. public static $notify_url = 'adapay/notify';
  37. public static $h5_url = 'adapay/h5';
  38. public static $confs = [];
  39. public static function verifySign($store_id, $resp_sign, $resp_data) {
  40. $conf = self::conf($store_id);
  41. # 对返回数据验签失败的逻辑分支
  42. if (!BsPayTools::verifySign($resp_sign, $resp_data, $conf['v2']['rsa_huifu_public_key'])) {
  43. debug_log([__METHOD__, __LINE__, $resp_sign, $resp_data], __CLASS__ . '.log');
  44. return [
  45. 'code' => 1,
  46. 'msg' => '接口结果返回签名验证失败',
  47. ];
  48. }
  49. return [
  50. 'code' => 0,
  51. 'msg' => 'ok',
  52. ];
  53. }
  54. public static function initRequest($class) {
  55. include_once BsPaySdk_Path . "/request/" . $class . ".php";
  56. $className = 'BsPaySdk\\request\\' . $class;
  57. $obj = new $className();
  58. return $obj;
  59. }
  60. public static function initStoreAdapay($store_id) {
  61. $conf = self::conf($store_id);
  62. BsPay::init($conf['v2'], true);
  63. }
  64. public static function create($pay_type, $order, $type, $goods_names = null, $total_pay_price = 0, $is_app = false, $balance_price = 0, $is_h5 = false, $is_official = false) {
  65. $store_id = $order->store_id;
  66. self::initStoreAdapay($store_id);
  67. $param = self::paymentParams($pay_type, $order, $type, $goods_names, $total_pay_price, $is_app, $balance_price, $is_h5, $is_official);
  68. # 创建请求Client对象,调用接口
  69. $client = new BsPayClient();
  70. $result = $client->postRequest($param);
  71. $httpStateCode = $result->getHttpStateCode();
  72. if($httpStateCode != 200){
  73. // debug_log([__METHOD__, __LINE__, $result->getErrorInfo()], __CLASS__ . '.log');
  74. return [
  75. 'code' => $httpStateCode,
  76. 'msg' => '操作失败,HTTP_STATE_CODE-' . $httpStateCode . '。参考:https://paas.huifu.com/partners/api/#/csfl/api_csfl_ywm?id=网关返回码',
  77. ];
  78. }
  79. $data = $result->getRspDatas();
  80. // var_dump($result);die;
  81. if (!$result || $result->isError()) { //失败处理
  82. debug_log([__METHOD__, __LINE__, $result->getErrorInfo()], __CLASS__ . '.log');
  83. return [
  84. 'code' => 1,
  85. 'msg' => '操作失败,' . $result -> getErrorInfo()['msg'],
  86. 'res' => $data,
  87. ];
  88. }
  89. if($data['data']['resp_code'] > 100){
  90. debug_log([__METHOD__, __LINE__, $data], __CLASS__ . '.log');
  91. return [
  92. 'code' => 1,
  93. 'msg' => '操作失败,' . $data['data']['resp_code'] . ',' . $data['data']['resp_desc'],
  94. 'res' => $data,
  95. ];
  96. }
  97. if($data['data']['trans_stat'] === 'F'){
  98. return [
  99. 'code' => 1,
  100. 'msg' => '操作失败,adapay交易失败',
  101. 'res' => $data,
  102. ];
  103. }
  104. $return = [
  105. 'code' => 0,
  106. 'msg' => '操作成功',
  107. 'data' => $data,
  108. 'res' => $data,
  109. 'body' => $goods_names,
  110. '$param' => $param,
  111. ];
  112. if(!empty($data['data']['pay_info'])){
  113. $return['data'] = json_decode($data['data']['pay_info'], true);
  114. }
  115. if ($type == OrderNo::ORDER_UNION) {
  116. foreach ($order as $value) {
  117. $value->order_union_id = $value->id;
  118. $value->adapay_payment_id = $data['data']['hf_seq_id'];
  119. $value->save();
  120. }
  121. $return['order_no'] = $data['data']['req_seq_id'];
  122. $return['body'] = $data['data']['goods_desc'];
  123. }else{
  124. $order->adapay_payment_id = $data['data']['hf_seq_id'];
  125. $order->save();
  126. }
  127. debug_log([$data, $return, $order->getFirstErrors()], __CLASS__ . '.log');
  128. if ($is_h5) {
  129. $return['res']['mweb_url'] = $return['res']['mweb_url'] . '&redirect_url=' . \Yii::$app->request->hostInfo . '/h5/#/order/order/order';
  130. }
  131. return $return;
  132. }
  133. public static function params_notify_url($data) {
  134. $data['params']['notify_url'] = pay_notify_url(self::$notify_url);
  135. return $data;
  136. }
  137. public static function params_huifu_id($data, $store_id) {
  138. $conf = self::conf($store_id)['v2'];
  139. $data['params']['huifu_id'] = $conf['huifu_id'];
  140. return $data;
  141. }
  142. public static function params_risk_check_data($data) {
  143. $ip_addr = \Yii::$app->request->remoteIP;
  144. $data['params']['risk_check_data'] = self::json_encode([
  145. 'ip_addr' => $ip_addr,
  146. ]);
  147. return $data;
  148. }
  149. public static function params_terminal_device_data($data) {
  150. $ip_addr = \Yii::$app->request->remoteIP;
  151. $data['params']['terminal_device_data'] = self::json_encode([
  152. 'device_type' => 1,
  153. 'device_ip' => $ip_addr,
  154. ]);
  155. return $data;
  156. }
  157. public static function json_encode($param) {
  158. return json_encode($param,JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);
  159. }
  160. public static function req_seq_id2order_no($req_seq_id){
  161. if(strstr($req_seq_id, '_')){
  162. return explode('_', $req_seq_id)[0];
  163. }
  164. return $req_seq_id;
  165. }
  166. public static function order_no2req_seq_id($order_no){
  167. return $order_no . '_' . time();
  168. }
  169. public static function paymentParams($pay_type, $order, $type, $goods_names, $total_pay_price, $is_app, $balance_price, $is_h5, $is_official) {
  170. $param = [];
  171. $ip_addr = \Yii::$app->request->remoteIP;
  172. $store_id = $order->store_id;
  173. $user_id = $order->user_id;
  174. $user = \app\models\User::findOne($user_id);
  175. if ($type == OrderNo::ORDER_UNION) {
  176. $goods_title = count($order) . '笔订单合并支付';
  177. $out_trade_no = OrderNo::getOrderNo(OrderNo::ORDER_UNION);
  178. $total_fee = $balance_price > 0 ? floatval($total_pay_price - $balance_price) * 100 : $total_pay_price * 100;
  179. $order_union = new OrderUnion();
  180. $order_union->store_id = $store_id;
  181. $order_union->user_id = $user_id;
  182. $order_union->order_no = $out_trade_no;
  183. $order_union->price = $total_pay_price;
  184. $order_union->is_pay = 0;
  185. $order_union->created_at = time();
  186. $order_union->is_delete = 0;
  187. $order_id_list = [];
  188. foreach ($order as $value) {
  189. $order_id_list[] = $value->id;
  190. }
  191. $order_union->order_id_list = json_encode($order_id_list);
  192. if (!$order_union->save()) {
  193. foreach ($order_union->errors as $error) {
  194. return [
  195. 'code' => 1,
  196. 'msg' => $error
  197. ];
  198. }
  199. }
  200. } else {
  201. $pay_price = $order->pay_price;
  202. // if ($type != OrderNo::ORDER_RECHARGE) {
  203. // if (isset($order->is_delivery) && $order->is_delivery == 1) {
  204. // $deliveryInfo = DeliveryInfo::find()->where(['order_no' => $order->order_no])->one();
  205. // if ($deliveryInfo) {
  206. // $pay_price += $deliveryInfo->fee;
  207. // }
  208. // }
  209. // }
  210. $goods_title = mb_substr($goods_names, 0, 20);
  211. $out_trade_no = $order->order_no;
  212. $total_fee = $balance_price > 0 ? floatval($pay_price - $balance_price) * 100 : $pay_price * 100;
  213. }
  214. if($pay_type == Order::PAY_TYPE_ADAPAY_QUICKPAY_FRONTPAY){
  215. // new \BsPaySdk\request\V2TradeOnlinepaymentQuickpayFrontpayRequest;
  216. $request = self::initRequest('V2TradeOnlinepaymentQuickpayFrontpayRequest');
  217. $param = array(
  218. "funcCode" => $request->getFunctionCode(),
  219. "params" => array(
  220. "req_seq_id" => self::order_no2req_seq_id($out_trade_no),
  221. "req_date" => date("Ymd"),
  222. "goods_desc" => $goods_title,
  223. // "huifu_id" => $conf['huifu_id'],
  224. "user_huifu_id" => $user->adapay_user_huifu_id,
  225. "trans_amt" => sprintf("%.2f", $total_fee/100),
  226. 'request_type' => 'M',
  227. // 'notify_url' => pay_notify_url(self::$notify_url),
  228. 'front_url' => pay_notify_url(self::$h5_url),
  229. 'extend_pay_data' => self::json_encode([
  230. 'goods_short_name' => '1',
  231. 'biz_tp' => '100099',
  232. 'gw_chnnl_tp' => '02',
  233. ]),
  234. ),
  235. );
  236. $param = self::params_huifu_id($param, $store_id);
  237. $param = self::params_risk_check_data($param);
  238. $param = self::params_terminal_device_data($param);
  239. $param = self::params_notify_url($param);
  240. }
  241. if($pay_type == Order::PAY_TYPE_HUIFU_V2_JSPAY_WX){
  242. if ($is_app) {
  243. $open_id = get_user()->wechat_app_open_id;
  244. } else if ($is_official) {
  245. $open_id = get_user()->wechat_platform_open_id;
  246. } else {
  247. $open_id = get_user()->wechat_open_id;
  248. }
  249. $from_type = WechatConfig::TYPE_CONFIG_MINI;
  250. $store_wechat = WechatConfig::findOne(['store_id' => get_store_id(), 'type' => $from_type]);
  251. $sub_appid = $store_wechat->app_id;
  252. // new \BsPaySdk\request\V2TradePaymentJspayRequest();
  253. $request = self::initRequest('V2TradePaymentJspayRequest');
  254. $param = array(
  255. "funcCode" => $request->getFunctionCode(),
  256. "params" => array(
  257. "req_seq_id" => self::order_no2req_seq_id($out_trade_no),
  258. "req_date" => date("Ymd"),
  259. "goods_desc" => $goods_title,
  260. 'trade_type' => 'T_JSAPI',
  261. // "huifu_id" => $conf['huifu_id'],
  262. "trans_amt" => sprintf("%.2f", $total_fee/100),
  263. // 'notify_url' => pay_notify_url(self::$notify_url),
  264. 'wx_data' => [
  265. 'sub_appid' => $sub_appid,
  266. 'sub_openid' => $open_id,
  267. ],
  268. ),
  269. );
  270. $param = self::params_huifu_id($param, $store_id);
  271. $param = self::params_risk_check_data($param);
  272. $param = self::params_terminal_device_data($param);
  273. $param = self::params_notify_url($param);
  274. }
  275. return $param;
  276. }
  277. /**
  278. * 退款
  279. * @param Object $order
  280. * @param string $orderRefundNo
  281. * @param string $type
  282. * @param integer $refundFee
  283. * @param $refund_account
  284. * @return array
  285. */
  286. public static function orderRefund($order, $type, $refundFee, $orderRefundNo, $refund_account = null, $profit_share = 1) {
  287. $store_id = $order->store_id;
  288. self::initStoreAdapay($store_id);
  289. // new \BsPaySdk\request\V2TradeOnlinepaymentRefundRequest;
  290. $request = self::initRequest('V2TradeOnlinepaymentRefundRequest');
  291. $param = array(
  292. "funcCode" => $request->getFunctionCode(),
  293. "params" => array(
  294. "req_seq_id" => self::order_no2req_seq_id($order->order_no) . '_refund',
  295. "req_date" => date("Ymd") -1,
  296. "ord_amt" => sprintf("%.2f", $order->pay_price),
  297. 'org_hf_seq_id' => $order->adapay_payment_id,
  298. // 'org_req_seq_id' => $order->order_no,
  299. // 'org_req_date' => date("Ymd") -1,
  300. ),
  301. );
  302. if($order->pay_type == Order::PAY_TYPE_HUIFU_V2_JSPAY_WX){
  303. // new \BsPaySdk\request\V2TradePaymentScanpayRefundRequest;
  304. $request = self::initRequest('V2TradePaymentScanpayRefundRequest');
  305. $param = array(
  306. "funcCode" => $request->getFunctionCode(),
  307. "params" => array(
  308. "req_seq_id" => self::order_no2req_seq_id($order->order_no) . '_refund',
  309. "req_date" => date("Ymd"),
  310. "ord_amt" => sprintf("%.2f", $order->pay_price),
  311. 'org_hf_seq_id' => $order->adapay_payment_id,
  312. // 'org_req_seq_id' => $order->order_no,
  313. 'org_req_date' => date("Ymd", $order->pay_time),
  314. ),
  315. );
  316. }
  317. $param = self::params_huifu_id($param, $store_id);
  318. $param = self::params_risk_check_data($param);
  319. $param = self::params_terminal_device_data($param);
  320. $param = self::params_notify_url($param);
  321. # 创建请求Client对象,调用接口
  322. $client = new BsPayClient();
  323. $result = $client->postRequest($param);
  324. $httpStateCode = $result->getHttpStateCode();
  325. if($httpStateCode != 200){
  326. // debug_log([__METHOD__, __LINE__, $result->getErrorInfo()], __CLASS__ . '.log');
  327. return [
  328. 'code' => $httpStateCode,
  329. 'msg' => '操作失败,HTTP_STATE_CODE-' . $httpStateCode . '。参考:https://paas.huifu.com/partners/api/#/csfl/api_csfl_ywm?id=网关返回码',
  330. ];
  331. }
  332. $data = $result->getRspDatas();
  333. // var_dump($result);die;
  334. if (!$result || $result->isError()) { //失败处理
  335. debug_log([__METHOD__, __LINE__, $result->getErrorInfo()], __CLASS__ . '.log');
  336. return [
  337. 'code' => 1,
  338. 'msg' => '退款失败1,' . $result -> getErrorInfo()['msg'],
  339. 'res' => $data,
  340. ];
  341. }
  342. if($data['data']['resp_code'] > 100){
  343. debug_log([__METHOD__, __LINE__, $data], __CLASS__ . '.log');
  344. return [
  345. 'code' => 1,
  346. 'msg' => '退款失败2,错误码:' . $data['data']['resp_code'] . ',' . $data['data']['resp_desc'],
  347. 'res' => $data,
  348. ];
  349. }
  350. if($data['data']['trans_stat'] == 'F'){
  351. return [
  352. 'code' => 1,
  353. 'msg' => '操作失败,adapay交易失败',
  354. 'res' => $data,
  355. ];
  356. }
  357. $return = [
  358. 'code' => 0,
  359. 'msg' => '操作成功',
  360. 'data' => $data,
  361. ];
  362. if($data['data']['trans_stat'] == 'P'){
  363. $return = [
  364. 'code' => 0,
  365. 'msg' => '处理中,银行受理结果:' . $data['data']['bank_code'] . $data['data']['bank_message'] . '。',
  366. 'res' => $data,
  367. ];
  368. }
  369. // 联合支付,退余额
  370. if ($order->is_combine_pay == 1 && $order->combine_money > 0) {
  371. AccountLog::saveLog($order->user_id, $order->combine_money, AccountLog::TYPE_BALANCE, AccountLog::LOG_TYPE_INCOME, AccountLog::TYPE_PLATFORM_REFUND_ORDER, $order->id, "商城订单退款,订单号:{$order->order_no}");
  372. }
  373. return $return;
  374. }
  375. public static function merchant_busi_config_query($store_id) {
  376. self::initStoreAdapay($store_id);
  377. // new \BsPaySdk\request\V2MerchantBusiConfigQueryRequest();
  378. $request = self::initRequest('V2MerchantBusiConfigQueryRequest');
  379. $param = array(
  380. "funcCode" => $request->getFunctionCode(),
  381. "params" => array(
  382. "req_seq_id" => time() . '_merchant',
  383. "req_date" => date("Ymd"),
  384. ),
  385. );
  386. $param = self::params_huifu_id($param, $store_id);
  387. # 创建请求Client对象,调用接口
  388. $client = new BsPayClient();
  389. $result = $client->postRequest($param);
  390. $httpStateCode = $result->getHttpStateCode();
  391. if($httpStateCode != 200){
  392. // debug_log([__METHOD__, __LINE__, $result->getErrorInfo()], __CLASS__ . '.log');
  393. return [
  394. 'code' => $httpStateCode,
  395. 'msg' => '操作失败,HTTP_STATE_CODE-' . $httpStateCode . '。参考:https://paas.huifu.com/partners/api/#/csfl/api_csfl_ywm?id=网关返回码',
  396. ];
  397. }
  398. $data = $result->getRspDatas();
  399. // var_dump($result);die;
  400. if (!$result || $result->isError()) { //失败处理
  401. debug_log([__METHOD__, __LINE__, $result->getErrorInfo()], __CLASS__ . '.log');
  402. return [
  403. 'code' => 1,
  404. 'msg' => '失败1,' . $result -> getErrorInfo()['msg'],
  405. 'res' => $data,
  406. ];
  407. }
  408. $return = [
  409. 'code' => 0,
  410. 'msg' => '操作成功',
  411. 'data' => $data,
  412. 'url_fee_type' => 'https://paas.huifu.com/open/doc/api/#/api_ggcsbm?id=%e5%be%ae%e4%bf%a1%e4%b8%9a%e5%8a%a1%e5%bc%80%e9%80%9a%e7%b1%bb%e5%9e%8b',
  413. 'url_config' => 'https://paas.huifu.com/open/doc/api/#/shgl/shjj/api_shjj_wxshpz',
  414. ];
  415. return $return;
  416. }
  417. public static function merchant_busi_config($store_id, $conf) {
  418. self::initStoreAdapay($store_id);
  419. // new \BsPaySdk\request\V2MerchantBusiConfigRequest();
  420. $request = self::initRequest('V2MerchantBusiConfigRequest');
  421. $param = array(
  422. "funcCode" => $request->getFunctionCode(),
  423. "params" => array(
  424. "req_seq_id" => time() . '_merchantConf',
  425. "req_date" => date("Ymd"),
  426. // 'fee_type' => '02',
  427. // 'wx_applet_app_id' => 'wxac56e7dc6301d517',
  428. ),
  429. );
  430. $param['params'] = array_merge($param['params'], $conf);
  431. $param = self::params_huifu_id($param, $store_id);
  432. # 创建请求Client对象,调用接口
  433. $client = new BsPayClient();
  434. $result = $client->postRequest($param);
  435. $httpStateCode = $result->getHttpStateCode();
  436. if($httpStateCode != 200){
  437. // debug_log([__METHOD__, __LINE__, $result->getErrorInfo()], __CLASS__ . '.log');
  438. return [
  439. 'code' => $httpStateCode,
  440. 'msg' => '操作失败,HTTP_STATE_CODE-' . $httpStateCode . '。参考:https://paas.huifu.com/partners/api/#/csfl/api_csfl_ywm?id=网关返回码',
  441. ];
  442. }
  443. $data = $result->getRspDatas();
  444. // var_dump($result);die;
  445. if (!$result || $result->isError()) { //失败处理
  446. debug_log([__METHOD__, __LINE__, $result->getErrorInfo()], __CLASS__ . '.log');
  447. return [
  448. 'code' => 1,
  449. 'msg' => '失败1,' . $result -> getErrorInfo()['msg'],
  450. 'res' => $data,
  451. ];
  452. }
  453. $return = [
  454. 'code' => 0,
  455. 'msg' => '操作成功',
  456. 'data' => $data,
  457. ];
  458. return $return;
  459. }
  460. }