PvService.php 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585
  1. <?php
  2. namespace addons\Happiness\common\service;
  3. use addons\Happiness\common\enums\HappinessEnum;
  4. use addons\Happiness\common\enums\HappinessPvEnum;
  5. use addons\Happiness\common\logic\pv\WalletLogic;
  6. use addons\Happiness\common\models\HappinessPvWallet;
  7. use addons\Happiness\common\models\HappinessPvWalletLog;
  8. use addons\Happiness\common\models\HappinessPvOrder;
  9. use addons\Happiness\common\models\HappinessThirdUser;
  10. use common\enums\StatusEnum;
  11. use common\models\order\Order;
  12. use common\models\order\OrderDetail;
  13. use common\models\order\OrderMarketing;
  14. use common\models\user\User;
  15. use yii\db\Exception;
  16. use yii\helpers\Json;
  17. use yii;
  18. class PvService extends BaseService
  19. {
  20. public function send($order,$is_settle = 0,$store_order=[])
  21. {
  22. try {
  23. $userId = $order['user_id'];
  24. $mallId = $order['mall_id'];
  25. $orderId = $order['id'];
  26. $scale = \Yii::$app->services->setting->addons->get($mallId, HappinessEnum::ADDONS_NAME, 'basic.pv_scale');
  27. $settle_mode = \Yii::$app->services->setting->addons->get($order['mall_id'], HappinessEnum::ADDONS_NAME, 'basic.settlement_method');
  28. $scoreTotal = bcmul($order['pay_money'],bcdiv($scale,100,4),3);
  29. if ($scoreTotal<=0) {
  30. throw new \Exception('赠送积分为0');
  31. }
  32. //创建订单,若不存在
  33. $recordRes = self::recordOrder($order);
  34. if ($recordRes === false) {
  35. throw new \Exception(self::getStaticError());
  36. }
  37. //非结算订单不执行下面的逻辑
  38. if ($is_settle != $settle_mode) {
  39. return true;
  40. }
  41. $t = Yii::$app->db->beginTransaction();
  42. try {
  43. $service=new self;
  44. $syncResult= $service->syncUserPv($userId);
  45. if ($syncResult === false) {
  46. throw new \Exception($service->error);
  47. }
  48. $orderData = [
  49. 'order_id' => $order['id'],
  50. 'order_no' => $order['order_no'],
  51. 'mall_id' => $order['mall_id'],
  52. 'user_id' => $order['user_id'],
  53. 'score' => $scoreTotal,
  54. 'is_settled' => StatusEnum::ENABLED,
  55. 'status' => StatusEnum::ENABLED,
  56. 'goods_price' => $order['pay_money'],
  57. 'settled_time' => time()
  58. ];
  59. // 写入订单明细
  60. $resOrder = HappinessPvOrder::setData($orderData);
  61. if (!$resOrder) {
  62. throw new \Exception('创建订单失败' . HappinessPvOrder::getStaticError());
  63. }
  64. //同步幸福宝
  65. $thirdUser=HappinessThirdUser::find()->where(['user_id'=>$order['user_id'],'type'=>2])->asArray()
  66. ->one();
  67. $res=$this->updatePv($thirdUser['uid'],$scoreTotal,'幸福小店订单消费赠送'.$order['order_no'],$order['order_no']);
  68. if($res===false)
  69. {
  70. throw new \Exception('更新PV失败');
  71. }
  72. //同步信息
  73. $commissionService=new CommissionService;
  74. $res=$commissionService->statsItem( [
  75. 'mall_id' => $order['mall_id'],
  76. 'order_id' => $order['id'],
  77. 'store_id' => $store_order['store_id'],
  78. 'order_no' => $order['order_no'],
  79. 'order_money' => $order['pay_money'],
  80. 'money'=>$scoreTotal,
  81. 'user_id' => $order['user_id'],
  82. ],'pv_money');
  83. if (!$res) throw new Exception($commissionService->getError());
  84. $t->commit();
  85. return true;
  86. } catch (\Exception $e) {
  87. $t->rollBack();
  88. throw $e;
  89. }
  90. }
  91. catch (\Exception $e) {
  92. $this->error = $e->getMessage();
  93. \Yii::error('Happiness OrderPay : ' . $this->error . ' : ' . $e->getLine());
  94. return false;
  95. }
  96. }
  97. //创建订单
  98. public static function recordOrder($order)
  99. {
  100. try {
  101. $powerOrder = HappinessPvOrder::findOne(['mall_id' => $order['mall_id'], 'order_id' => $order['id']]);
  102. if ($powerOrder) {
  103. return true;
  104. }
  105. $mallId = $order['mall_id'];
  106. $scale = \Yii::$app->services->setting->addons->get($mallId, HappinessEnum::ADDONS_NAME, 'basic.pv_scale');
  107. $scoreTotal = bcmul($order['pay_money'],bcdiv($scale,100,4),3);
  108. if($scoreTotal<=0)
  109. {
  110. throw new \Exception('赠送金额为0');
  111. }
  112. $service=new self;
  113. $syncResult= $service->syncUserPv($order['user_id']);
  114. if ($syncResult === false) {
  115. throw new \Exception($service->error);
  116. }
  117. //添加订单记录
  118. $orderData = [
  119. 'order_id' => $order['id'],
  120. 'order_no' => $order['order_no'],
  121. 'mall_id' => $order['mall_id'],
  122. 'user_id' => $order['user_id'],
  123. 'score' => $scoreTotal,
  124. 'is_settled' => StatusEnum::DISABLED,
  125. 'status' => StatusEnum::ENABLED,
  126. 'goods_price' => $order['pay_money'],
  127. ];
  128. $resOrder = HappinessPvOrder::setData($orderData);
  129. if (!$resOrder) {
  130. throw new \Exception('创建订单失败' . HappinessPvOrder::getStaticError());
  131. }
  132. } catch (\Exception $e) {
  133. self::$static_error = $e->getMessage();
  134. \Yii::error('Happiness OrderPay : ' . self::$static_error . ' : ' . $e->getLine());
  135. return false;
  136. }
  137. return true;
  138. }
  139. //退还积分(取消订单)
  140. public static function orderCancel($detail_ids,$order_id)
  141. {
  142. $where = [
  143. 'source_table' => 'order',
  144. 'source_table_id' => $detail_ids,
  145. 'from_type' => HappinessPvEnum::FROM_ORDER_BUY
  146. ];
  147. $log = HappinessPvWalletLog::find()->where($where)->asArray()->all();
  148. if (!empty($log)) {
  149. $wallet_log = [];
  150. foreach ($log as $item) {
  151. $wallet_log[] = [
  152. 'mall_id' => $item['mall_id'],
  153. 'user_id' => $item['user_id'],
  154. 'change_num' => $item['change_num'],
  155. 'desc' => '订单关闭退回,订单号:' . $item['order_no'],
  156. 'source_table' => 'order',
  157. 'source_table_id' => $item['source_table_id'],
  158. 'order_no' => $item['order_no'],
  159. 'from_type' => HappinessPvEnum::FROM_ORDER_CANCEL,
  160. 'wallet_type' => HappinessPvEnum::SCORE_VALUE,
  161. 'status' => 1,
  162. ];
  163. }
  164. $tran = Yii::$app->db->beginTransaction();
  165. try {
  166. $service=new self;
  167. $uid= $service->syncUserPv($log[0]['user_id']);
  168. if ($uid === false) {
  169. throw new \Exception($service->error);
  170. }
  171. $res = WalletLogic::batchHandle($wallet_log);
  172. if ($res === false) {
  173. throw new \Exception(WalletLogic::getStaticError());
  174. }
  175. //同步pv
  176. if(!empty($wallet_log))
  177. {
  178. foreach ($wallet_log as $item)
  179. {
  180. $syncResult= $service->updatePoints($uid,$item['change_num'],$item['order_no']);
  181. if ($syncResult === false) {
  182. throw new \Exception($service->error);
  183. }
  184. }
  185. }
  186. $pvOrder=HappinessPvOrder::find()->where(['order_id'=>$order_id])->one();
  187. if($pvOrder)
  188. {
  189. $pvOrder->status=StatusEnum::DISABLED;
  190. if(!$pvOrder->save())
  191. {
  192. throw new \Exception($pvOrder->getErrorMessage());
  193. }
  194. }
  195. $tran->commit();
  196. return true;
  197. } catch (\Exception $e) {
  198. $tran->rollBack();
  199. self::$static_error = $e->getMessage();
  200. Yii::error($e->getMessage() . __LINE__, __METHOD__);
  201. return false;
  202. }
  203. }
  204. return true;
  205. }
  206. //退还积分(售后)
  207. public static function orderRefund($order_detail_id, $params)
  208. {
  209. $trans = Yii::$app->db->beginTransaction();
  210. try {
  211. $deduct = OrderMarketing::find()->select('deduct_currency')->where(['order_detail_id' => $order_detail_id, 'status' => StatusEnum::ENABLED])->scalar();
  212. if (empty($deduct)) {
  213. throw new Exception('订单不存在PV_SCORE营销');
  214. }
  215. $order_detail = OrderDetail::find()->where(['id' => $order_detail_id])->asArray()->one();
  216. $order = Order::find()->where(['id' => $order_detail['order_id']])->asArray()->one();
  217. $deduct_arr = Json::decode($deduct, true);
  218. $wallet_log = [];
  219. foreach ($deduct_arr as $key => $item) {
  220. if ($key == 'pv_score' && $item['money'] > 0) {
  221. $wallet_log[] = [
  222. 'mall_id' => $params['mall_id'],
  223. 'user_id' => $params['user_id'],
  224. 'change_num' => $item['money'],
  225. 'desc' => '订单售后退回,订单号' . $order['order_no'],
  226. 'source_table' => 'order',
  227. 'order_no' => $order['order_no'],
  228. 'from_type' => HappinessPvEnum::FROM_ORDER_REFUND,
  229. 'wallet_type' => HappinessPvEnum::SCORE_VALUE,
  230. 'status' => 1,
  231. ];
  232. }
  233. }
  234. if (!empty($wallet_log)) {
  235. //同步pv
  236. $service=new self;
  237. $uid= $service->syncUserPv($params['user_id']);
  238. if ($uid === false) {
  239. throw new \Exception($service->error);
  240. }
  241. $res = WalletLogic::batchHandle($wallet_log);
  242. if ($res === false) {
  243. throw new Exception(WalletLogic::getStaticError());
  244. }
  245. foreach ($wallet_log as $item)
  246. {
  247. $syncResult= $service->updatePoints($uid,$item['change_num'],$item['order_no']);
  248. if ($syncResult === false) {
  249. throw new \Exception($service->error);
  250. }
  251. }
  252. }
  253. $trans->commit();
  254. return true;
  255. } catch (\Exception $e) {
  256. $trans->rollBack();
  257. self::setStaticError($e->getMessage());
  258. Yii::error($e->getMessage() . __LINE__, __METHOD__);
  259. return false;
  260. }
  261. }
  262. //同步幸福保积分
  263. private const API_KEY = "HXJT_XFXD_B31_M_3279_Y_250707_01";
  264. private const API_SECRET = '8f^ynijrE9Mc9Q5ez5e8$Tm&$6Xx!ycQ';
  265. private const GATEWAY_URL = "https://testapi.hxxfb.com/gateway";
  266. //获取用户积分
  267. public function getUserInfo($uid)
  268. {
  269. // 请求 URL
  270. $url = self::GATEWAY_URL . "/external/userCenter_service/user/getUserList?uid=".$uid;
  271. return $this->getUrl($url);
  272. }
  273. public function getUserInfoByMobile($mobile)
  274. {
  275. // 请求 URL
  276. $url = self::GATEWAY_URL . "/external/userCenter_service/user/getUserList?account=".$mobile;
  277. return $this->getUrl($url);
  278. }
  279. private function generateSignature($apiKey, $timestamp)
  280. {
  281. $data = $apiKey . "|" . $timestamp . "|" . self::API_SECRET;
  282. return md5($data); // 返回 MD5 签名
  283. }
  284. public function createUser($mobile,$user_name,$mall_id,$avatar_url,$user_id)
  285. {
  286. // 请求 URL
  287. $url = self::GATEWAY_URL . "/external/userCenter_service/user/createUserInfo";
  288. $data = [
  289. "account" => $mobile, //账号
  290. "realName" => $user_name, //真实姓名
  291. "nickname" => $user_name, //用户昵称
  292. "sex" => 1, //性别
  293. "spreadUid" => 1001, //推广员id
  294. "avatar" => $avatar_url, //用户头像
  295. "phone" =>$mobile, //手机号码
  296. "status" => 1, //1为正常,0为禁止
  297. "external" => 4, //用户来源1:储蓄保,2:长寿美,3:聚宝盆1.0,4:幸福小店
  298. "externalId" => $user_id, //外部用户id
  299. "levelId" => 2,
  300. "lastIp" => \Yii::$app->request->getRemoteIP() //获取IP
  301. ];
  302. $res= $this->postUrl($url,$data);
  303. if($res === false && $this->error == '用户已存在')
  304. {
  305. //查询用户
  306. $resGetUserInfo=$this->getUserInfoByMobile($mobile);
  307. if($resGetUserInfo === false)
  308. {
  309. return false;
  310. }
  311. if(empty($resGetUserInfo['list']))
  312. {
  313. $this->error='用户不存在';
  314. return false;
  315. }
  316. $res=$resGetUserInfo['list'][0];
  317. }
  318. if(isset($res) && $res['uid'])
  319. {
  320. //保存第三方信息
  321. $saveData=[
  322. 'uid'=>$res['uid'],
  323. 'mall_id'=>$mall_id,
  324. 'type'=>2,
  325. 'user_id'=>$user_id
  326. ];
  327. $resSave=HappinessThirdUser::setData($saveData);
  328. if($resSave===false)
  329. {
  330. $this->error=HappinessThirdUser::getStaticError();
  331. return false;
  332. }
  333. return $res;
  334. }
  335. return false;
  336. }
  337. public function syncUserPv($user_id)
  338. {
  339. //先检测是否存在用户,没存在先创建
  340. $third_user=HappinessThirdUser::find()->where(['type'=>2,'user_id'=>$user_id])->one();
  341. if(!$third_user)
  342. {
  343. //创建用户
  344. $user=User::find()->where(['id'=>$user_id])->asArray()->one();
  345. $resCreate=$this->createUser($user['mobile'],$user['nickname'],$user['mall_id'],$user['avatar_url'],
  346. $user_id);
  347. if($resCreate===false)
  348. {
  349. return false;
  350. }
  351. $uid=$resCreate['uid'];
  352. }
  353. else
  354. {
  355. $uid=$third_user['uid'];
  356. }
  357. //同步用户积分
  358. $resGetUserInfo=$this->getUserInfo($uid);
  359. if($resGetUserInfo===false)
  360. {
  361. return false;
  362. }
  363. if(empty($resGetUserInfo['list']))
  364. {
  365. $this->error='用户不存在';
  366. return false;
  367. }
  368. $pv=$resGetUserInfo['list'][0]['score'];
  369. //当前pv值
  370. $userWallet=HappinessPvWallet::find()->where(['user_id'=>$user_id])->asArray()->one();
  371. $wallet_log=[];
  372. if($userWallet['score_value']>$pv)
  373. {
  374. //需要减少
  375. $reduce_num=$userWallet['score_value']-$pv;
  376. $wallet_log[] = [
  377. 'mall_id' => $third_user['mall_id'],
  378. 'user_id' => $third_user['user_id'],
  379. 'change_num' =>-$reduce_num,
  380. 'desc' => '系统同步',
  381. 'source_table' => HappinessPvWallet::tableName(),
  382. 'source_table_id' => $third_user['user_id'],
  383. 'order_no' => '',
  384. 'from_type' => HappinessPvEnum::FROM_SYNC,
  385. 'wallet_type' => HappinessPvEnum::SCORE_VALUE,
  386. 'status' => 1,
  387. ];
  388. }
  389. elseif($userWallet['score_value']<$pv)
  390. {
  391. //需要增加
  392. $add_num=$pv-$userWallet['score_value'];
  393. $wallet_log[] = [
  394. 'mall_id' => $third_user['mall_id'],
  395. 'user_id' => $third_user['user_id'],
  396. 'change_num' => $add_num,
  397. 'desc' => '系统同步',
  398. 'source_table' => HappinessPvWallet::tableName(),
  399. 'source_table_id' => $third_user['user_id'],
  400. 'order_no' => '',
  401. 'from_type' => HappinessPvEnum::FROM_SYNC,
  402. 'wallet_type' => HappinessPvEnum::SCORE_VALUE,
  403. 'status' => 1,
  404. ];
  405. }
  406. if(!empty($wallet_log))
  407. {
  408. $res = WalletLogic::batchHandle($wallet_log);
  409. if ($res === false) {
  410. $this->error=WalletLogic::getStaticError();
  411. return false;
  412. }
  413. }
  414. return $uid;
  415. }
  416. //更新用户积分
  417. public function updatePv($uid, $pv,$remark='',$order_id='')
  418. {
  419. // 请求 URL
  420. $url = self::GATEWAY_URL . "/external/userCenter_service/user/modifyPV";
  421. $data = [
  422. "uid" => $uid, //会员id
  423. "pv" => $pv, //pv值
  424. "status" => 1, //pv值状态:1为有效,0为失效,-1为待确认
  425. "mark" => $remark, //pv值获取来源备注
  426. "orderId" => $order_id, //订单id
  427. "orderType" => 1001, //订单类型,关联订单id
  428. "settlementTime" => date('Y-m-d H:i:s')
  429. ];
  430. return $this->postUrl($url,$data);
  431. }
  432. //更新用户积分
  433. public function updatePoints($uid, $pv,$orderId='')
  434. {
  435. // 请求 URL
  436. $url = self::GATEWAY_URL . "/external/userCenter_service/user/modifyUserScore";
  437. $data = [
  438. "uid" => $uid, //会员id
  439. "pm" => $pv>0?1:2, //1为收入积分,2为支出积分
  440. "rewardScore" => abs($pv), //赠送积分数量
  441. "orderId" => $orderId, //订单id
  442. "orderType" => "XFXD" //订单类型,关联订单id
  443. ];
  444. return $this->postUrl($url,$data);
  445. }
  446. private function postUrl($url,$data=[])
  447. {
  448. $timestamp = round(microtime(true) * 1000); // 获取当前时间戳(毫秒)
  449. $signature = $this->generateSignature(self::API_KEY, $timestamp);
  450. // 设置请求头
  451. $headers = [
  452. "X-API-KEY: " . self::API_KEY,
  453. "X-TIMESTAMP: " . $timestamp,
  454. "X-SIGNATURE: " . $signature,
  455. "Content-Type: application/json"
  456. ];
  457. $curl = curl_init();
  458. curl_setopt_array($curl, [
  459. CURLOPT_URL => $url,
  460. CURLOPT_RETURNTRANSFER => true,
  461. CURLOPT_ENCODING => "",
  462. CURLOPT_MAXREDIRS => 10,
  463. CURLOPT_TIMEOUT => 30,
  464. CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  465. CURLOPT_CUSTOMREQUEST => "POST",
  466. CURLOPT_POSTFIELDS => json_encode($data),
  467. CURLOPT_HTTPHEADER => $headers,
  468. ]);
  469. $response = curl_exec($curl);
  470. $err = curl_error($curl);
  471. curl_close($curl);
  472. //记录报文
  473. if ($err) {
  474. throw new \Exception('curl错误:' . $err);
  475. } else {
  476. Yii::error('幸福宝返回信息');
  477. Yii::error('请求参数');
  478. Yii::error('请求地址'.$url);
  479. Yii::error('请求header');
  480. Yii::error(json_encode($headers));
  481. Yii::error($data);
  482. Yii::error('返回报文');
  483. $result = json_decode($response,true);
  484. Yii::error($response);
  485. if (isset($result['code']) && $result['code'] != '200') {
  486. $this->error=$result['message'];
  487. return false;
  488. }
  489. return $result['data'];
  490. }
  491. }
  492. private function getUrl($url, $params = [])
  493. {
  494. // 如果有参数,将其附加到URL上
  495. if (!empty($params)) {
  496. $queryString = http_build_query($params);
  497. $url .= (strpos($url, '?') !== false ? '&' : '?') . $queryString;
  498. }
  499. $timestamp = round(microtime(true) * 1000); // 获取当前时间戳(毫秒)
  500. $signature = $this->generateSignature(self::API_KEY, $timestamp);
  501. // 设置请求头
  502. $headers = [
  503. "X-API-KEY: " . self::API_KEY,
  504. "X-TIMESTAMP: " . $timestamp,
  505. "X-SIGNATURE: " . $signature,
  506. "Content-Type: application/json"
  507. ];
  508. $curl = curl_init();
  509. curl_setopt_array($curl, [
  510. CURLOPT_URL => $url,
  511. CURLOPT_RETURNTRANSFER => true,
  512. CURLOPT_ENCODING => "",
  513. CURLOPT_MAXREDIRS => 10,
  514. CURLOPT_TIMEOUT => 30,
  515. CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  516. CURLOPT_CUSTOMREQUEST => "GET",
  517. CURLOPT_HTTPHEADER => $headers,
  518. ]);
  519. $response = curl_exec($curl);
  520. $err = curl_error($curl);
  521. curl_close($curl);
  522. // 记录报文
  523. if ($err) {
  524. throw new \Exception('curl错误:' . $err);
  525. } else {
  526. Yii::error('幸福宝返回信息(GET)');
  527. Yii::error('请求地址: ' . $url);
  528. Yii::error('请求header');
  529. Yii::error(json_encode($headers));
  530. Yii::error('返回报文');
  531. Yii::error($response);
  532. $result = json_decode($response, true);
  533. if (!isset($result['list'])) {
  534. $this->error = '请求出错';
  535. return false;
  536. }
  537. return $result;
  538. }
  539. }
  540. }