ShopController.php 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878
  1. <?php
  2. /**
  3. * Created by PhpStorm.
  4. * User: leo
  5. * Date: 2018/2/24
  6. * Time: 下午12:48
  7. */
  8. namespace frontendApi\modules\v1\controllers;
  9. use common\helpers\Alarm;
  10. use common\helpers\Cache;
  11. use common\helpers\Date;
  12. use common\helpers\DingTalk;
  13. use common\helpers\Form;
  14. use common\helpers\LoggerTool;
  15. use common\helpers\Logistics;
  16. use common\helpers\Tool;
  17. use common\helpers\UPOP\PaySign;
  18. use common\helpers\user\Info;
  19. use common\models\ApproachOrder;
  20. use common\models\ApproachOrderGoods;
  21. use common\models\DecOrder;
  22. use common\models\forms\ApproachOrderForm;
  23. use common\models\forms\DeclarationForm;
  24. use common\models\forms\OrderForm;
  25. use common\models\Order;
  26. use common\models\OrderGoods;
  27. use common\models\ReceiveAddress;
  28. use common\models\Region;
  29. use common\models\ShopGoods;
  30. use common\models\User;
  31. use common\models\UserBonus;
  32. use common\models\UserWallet;
  33. use Exception;
  34. use Yii;
  35. use yii\data\Pagination;
  36. use yii\db\Query;
  37. use yii\web\HttpException;
  38. class ShopController extends BaseController {
  39. public $modelClass = DecOrder::class;
  40. const TRANSACTION_TYPE_PAYMENT = 'payment';
  41. /**
  42. * 商品列表
  43. * @return mixed
  44. * @throws \yii\web\HttpException
  45. */
  46. public function actionIndex() {
  47. $condition = ' AND STATUS=1 AND (FIND_IN_SET(2,GIFT_TYPE)>0';
  48. // $isStudio = User::getEnCodeInfo(\Yii::$app->user->id)['IS_STUDIO'];
  49. // if($isStudio==1){
  50. // $condition.= " OR FIND_IN_SET(4,GIFT_TYPE)>0";
  51. // }
  52. $condition.=")";
  53. $data = ShopGoods::lists($condition, [], [
  54. 'orderBy' => 'SORT ASC,CREATED_AT DESC',
  55. 'from' => ShopGoods::tableName(),
  56. ]);
  57. foreach ($data['list'] as $key => $value) {
  58. $data['list'][$key]['DISCOUNT'] = $value['SELL_DISCOUNT']*100;
  59. $data['list'][$key]['CATE'] = ShopGoods::GOODS_TYPE[$value['CATE_ID']]['name'] ?? '';
  60. }
  61. return static::notice($data);
  62. }
  63. /**
  64. * 获取商品详情
  65. * @return mixed
  66. * @throws \yii\web\HttpException
  67. */
  68. public function actionGoodsDetail(){
  69. $id = \Yii::$app->request->get('id');
  70. $data = null;
  71. if($id){
  72. $data = ShopGoods::findOneAsArray('ID=:ID AND STATUS=1', [':ID'=>$id]);
  73. }
  74. return static::notice($data);
  75. }
  76. /**
  77. * 购物车订单展示
  78. * @throws \yii\web\HttpException
  79. */
  80. public function actionShowCart(){
  81. $userId = \Yii::$app->user->id;
  82. $payList = ShopGoods::payTypes();
  83. $allAddress = ReceiveAddress::findAllAsArray('USER_ID=:USER_ID', [':USER_ID'=>$userId]);
  84. if($allAddress) {
  85. foreach ($allAddress as $key => $row) {
  86. $allAddress[$key]['PROVINCE_NAME'] = Region::getCnName($row['PROVINCE']);
  87. $allAddress[$key]['CITY_NAME'] = Region::getCnName($row['CITY']);
  88. $allAddress[$key]['COUNTY_NAME'] = Region::getCnName($row['COUNTY']);
  89. }
  90. }
  91. $userBalance = [
  92. 'points' => 0,
  93. 'cash' => 0,
  94. 'exchange' => 0
  95. ];
  96. if ($userBonusResult = UserBonus::findOneAsArray(['USER_ID' => $userId])) {
  97. $userBalance['points'] = $userBonusResult['RECONSUME_POINTS'];
  98. $userBalance['exchange'] = $userBonusResult['EXCHANGE_POINTS'];
  99. }
  100. if ($userCashResult = UserWallet::findOneAsArray(['USER_ID' => $userId])) {
  101. $userBalance['cash'] = $userCashResult['CASH'];
  102. }
  103. return static::notice(['payList'=>$payList,'allAddress'=>$allAddress,'userBalance'=>$userBalance]);
  104. }
  105. /**
  106. * 确认订单
  107. */
  108. public function actionSureOrder(){
  109. if (\Yii::$app->request->isPost) {
  110. $formModel = new OrderForm();
  111. $formModel->scenario = 'userOrder';
  112. $formModel->remark = '复销备注';
  113. $post = \Yii::$app->request->post();
  114. $post['type'] = DeclarationForm::TYPE_FX;
  115. if ($formModel->load($post, '') && $formModel->add()) {
  116. return static::notice('购物成功');
  117. } else {
  118. return static::notice(Form::formatErrorsForApi($formModel->getErrors()),400);
  119. }
  120. }
  121. }
  122. /**
  123. * 订单支付成功
  124. * @throws \yii\web\HttpException
  125. */
  126. public function actionPaySuccess(){
  127. $orderSn = \Yii::$app->request->get('orderSn');
  128. $data = null;
  129. if($orderSn){
  130. $data = Order::findOneAsArray('SN=:SN', [':SN'=>$orderSn]);
  131. }
  132. return static::notice($data);
  133. }
  134. /**
  135. * 我的报单
  136. * @return mixed
  137. * @throws \yii\web\HttpException
  138. */
  139. public function actionDecOrderList() {
  140. $condition = ' AND USER_ID=:USER_ID AND IS_DEL=0';
  141. $params[':USER_ID'] = \Yii::$app->user->id;
  142. $data = DecOrder::lists($condition, $params, [
  143. 'select' => 'DO.*,U.USER_NAME USER_NAME,U.REAL_NAME REAL_NAME,RU.USER_NAME REC_USER_NAME,RU.REAL_NAME REC_REAL_NAME,CU.USER_NAME CON_USER_NAME,CU.REAL_NAME CON_REAL_NAME,OG.*',
  144. 'orderBy' => 'DO.CREATED_AT DESC',
  145. 'from' => DecOrder::tableName() . ' AS DO',
  146. 'join' => [
  147. ['LEFT JOIN', User::tableName() . ' AS U', 'DO.TO_USER_ID=U.ID'],
  148. ['LEFT JOIN', User::tableName() . ' AS RU', 'DO.REC_USER_ID=RU.ID'],
  149. ['LEFT JOIN', User::tableName() . ' AS CU', 'DO.CON_USER_ID=CU.ID'],
  150. ['LEFT JOIN', OrderGoods::tableName() . ' AS OG', 'OG.ORDER_SN=DO.ORDER_SN'],
  151. ],
  152. ]);
  153. return static::notice($data);
  154. }
  155. /**
  156. * 我的订单(已支付))
  157. * @return mixed
  158. * @throws \yii\web\HttpException
  159. */
  160. public function actionOrderList() {
  161. $uname = Info::getUserNameByUserId(\Yii::$app->user->id);
  162. $condition = " AND IS_DELETE=0 AND ORDER_TYPE='FX' AND (USER_ID=:USER_ID OR CREATE_USER='$uname')";
  163. $params[':USER_ID'] = \Yii::$app->user->id;
  164. $data = Order::lists($condition, $params, [
  165. 'select' => 'O.*,U.REAL_NAME,OG.*',
  166. 'orderBy' => 'O.CREATED_AT DESC',
  167. 'from' => Order::tableName() . ' AS O',
  168. 'join' => [
  169. ['LEFT JOIN', User::tableName() . ' AS U', 'U.ID=O.USER_ID'],
  170. ['LEFT JOIN', OrderGoods::tableName() . ' AS OG', 'OG.ORDER_SN=O.SN'],
  171. ],
  172. ]);
  173. foreach ($data['list'] as $key => $value) {
  174. $data['list'][$key]['ORDER_TYPE'] = $value['ORDER_TYPE']=='ZC' ? '首单' : '复消';
  175. $data['list'][$key]['PAY_AT'] = Date::convert($value['PAY_AT'],'Y-m-d H:i:s');
  176. $data['list'][$key]['PAY_TYPE'] = ShopGoods::payTypes()[$value['PAY_TYPE']]['name'] ?? '';
  177. $data['list'][$key]['STATUS'] = \Yii::$app->params['orderStatus'][$value['STATUS']]['label'] ?? '';
  178. }
  179. return static::notice($data);
  180. }
  181. // /**
  182. // * 我的订单(未支付)
  183. // * @return mixed
  184. // * @throws \yii\web\HttpException
  185. // */
  186. // public function actionOrderList() {
  187. // $uname = Info::getUserNameByUserId(\Yii::$app->user->id);
  188. // $condition = " O.IS_DELETE = 0 AND O.ORDER_TYPE='FX' AND (O.USER_ID=:USER_ID OR O.CREATE_USER='$uname')";
  189. // $params[':USER_ID'] = \Yii::$app->user->id;
  190. // $orderQuery = Order::find()
  191. // ->alias('O')
  192. // ->where($condition, $params)
  193. // ->select('O.*,U.REAL_NAME,OG.REAL_PRICE,OG.BUY_NUMS,OG.SKU_CODE,OG.GOODS_TITLE,OG.REAL_PV,OG.ORDER_SN,OG.GOODS_ID')
  194. // ->join('LEFT JOIN', User::tableName() . ' AS U', 'U.ID=O.USER_ID')
  195. // ->join('LEFT JOIN', OrderGoods::tableName() . ' AS OG', 'OG.ORDER_SN=O.SN')
  196. // ->orderBy('O.CREATED_AT DESC');
  197. //
  198. // // 订单中间表只查询待支付和支付失败的订单
  199. // $params[':NOT_PAID'] = \Yii::$app->params['orderStatus']['notPaid']['value']; // 待支付
  200. // $params[':FAIL_PAID'] = \Yii::$app->params['orderStatus']['failPaid']['value']; // 支付失败
  201. // $orderStandardQuery = ApproachOrder::find()
  202. // ->alias('O')
  203. // ->where($condition . ' AND (O.STATUS = :NOT_PAID OR O.STATUS = :FAIL_PAID)', $params)
  204. // ->select('O.*,U.REAL_NAME,OG.REAL_PRICE,OG.BUY_NUMS,OG.SKU_CODE,OG.GOODS_TITLE,OG.REAL_PV,OG.ORDER_SN,OG.GOODS_ID')
  205. // ->join('LEFT JOIN', User::tableName() . ' AS U', 'U.ID=O.USER_ID')
  206. // ->join('LEFT JOIN', ApproachOrderGoods::tableName() . ' AS OG', 'OG.ORDER_SN=O.SN')
  207. // ->orderBy('O.CREATED_AT DESC');
  208. //
  209. // $queryAll = $orderQuery->union($orderStandardQuery, true);
  210. // $query = (new Query())->from(['Q' => $queryAll])->select('Q.*')->distinct()->orderBy(['CREATED_AT' => SORT_DESC]);
  211. //
  212. // $totalCount = $query->count();
  213. // $pagination = new Pagination(['totalCount' => $totalCount, 'pageSize' => \Yii::$app->request->get('pageSize')]);
  214. // $lists = $query->offset($pagination->offset)->limit($pagination->limit)->all();
  215. //
  216. // $data = [
  217. // 'list' => $lists,
  218. // 'currentPage'=>$pagination->page,
  219. // 'totalPages'=>$pagination->pageCount,
  220. // 'startNum' => $pagination->page * $pagination->pageSize + 1,
  221. // 'totalCount' => $pagination->totalCount,
  222. // 'pageSize' => $pagination->pageSize,
  223. // ];
  224. //
  225. // foreach ($data['list'] as $key => $value) {
  226. // $data['list'][$key]['ORDER_TYPE'] = $value['ORDER_TYPE'] == 'ZC' ? '首单' : '复消';
  227. // $data['list'][$key]['PAY_AT'] = $value['PAY_AT'] ? Date::convert($value['PAY_AT'],'Y-m-d H:i:s') : '';
  228. // $data['list'][$key]['PAY_TYPE'] = ShopGoods::payTypes()[$value['PAY_TYPE']]['name'] ?? '';
  229. // $data['list'][$key]['STATUS'] = \Yii::$app->params['orderStatus'][$value['STATUS']]['label'] ?? '';
  230. // }
  231. //
  232. // return $data;
  233. // }
  234. /**
  235. * 会员复消
  236. */
  237. public function actionReconsume() {
  238. $isStudio = User::getEnCodeInfo(\Yii::$app->user->id)['IS_STUDIO'];
  239. $condition = " AND STATUS=1";
  240. if($isStudio==1){
  241. $condition .= " AND (FIND_IN_SET(4,GIFT_TYPE)>0)";
  242. }
  243. // $condition.= ")";
  244. $data = ShopGoods::lists($condition, [], [
  245. 'orderBy' => 'SORT ASC,CREATED_AT DESC',
  246. 'from' => ShopGoods::tableName(),
  247. ]);
  248. foreach ($data['list'] as $key => $value) {
  249. $data['list'][$key]['DISCOUNT'] = $value['SELL_DISCOUNT']*100;
  250. }
  251. return static::notice($data);
  252. }
  253. /**
  254. * 帮会员复消购物车
  255. * @throws \yii\web\HttpException
  256. */
  257. public function actionReconsumeCart(){
  258. $userId = \Yii::$app->user->id;
  259. $payList = ['cash'=>['name'=>'消费点数支付'],];
  260. $userBalance = [
  261. 'points' => 0,
  262. 'cash' => 0
  263. ];
  264. if ($userBonusResult = UserBonus::findOneAsArray(['USER_ID' => $userId])) {
  265. $userBalance['points'] = $userBonusResult['RECONSUME_POINTS'];
  266. }
  267. if ($userCashResult = UserWallet::findOneAsArray(['USER_ID' => $userId])) {
  268. $userBalance['cash'] = $userCashResult['CASH'];
  269. }
  270. return static::notice(['payList'=>$payList,'userBalance'=>$userBalance]);
  271. }
  272. /**
  273. * 帮会员复消确认订单
  274. */
  275. public function actionReconsumeSureOrder(){
  276. if (\Yii::$app->request->isPost) {
  277. $formModel = new OrderForm();
  278. $formModel->scenario = 'reconsumeOrder';
  279. $formModel->remark = '帮会员复销';
  280. $post = \Yii::$app->request->post();
  281. $post['type'] = DeclarationForm::TYPE_FX;
  282. if ($formModel->load($post, '') && $formModel->reconsumeAdd()) {
  283. return static::notice('帮会员复消成功');
  284. } else {
  285. return static::notice(Form::formatErrorsForApi($formModel->getErrors()),400);
  286. }
  287. }
  288. return static::notice('无效请求');
  289. }
  290. /**
  291. * 确认订单
  292. */
  293. public function actionSureApproachOrder(){
  294. if (\Yii::$app->request->isPost) {
  295. $formModel = new ApproachOrderForm();
  296. $formModel->scenario = 'userOrder';
  297. $formModel->remark = '复销备注';
  298. $post = \Yii::$app->request->post();
  299. $post['type'] = DeclarationForm::TYPE_FX;
  300. if ($formModel->load($post, '') && $order = $formModel->add()) {
  301. return static::notice($order);
  302. } else {
  303. return static::notice(Form::formatErrorsForApi($formModel->getErrors()),400);
  304. }
  305. }
  306. return static::notice('无效请求');
  307. }
  308. /**
  309. * iPay88支付成功的webhook.
  310. * @throws \Exception
  311. */
  312. public function actionVerifyApproachOrderIpay88() {
  313. // iPay88支付成功的webhook.
  314. $rawPostData = file_get_contents('php://input');
  315. LoggerTool::notice(['actionVerifyApproachOrder', $rawPostData]);
  316. $data = [];
  317. if (strlen($rawPostData) > 0) {
  318. $rawPostArray = explode('&', $rawPostData);
  319. foreach ($rawPostArray as $raw) {
  320. $raw = explode('=', $raw);
  321. if (count($raw) == 2)
  322. $data[$raw[0]] = urldecode($raw[1]);
  323. }
  324. }
  325. // 支付webhook回调日志
  326. //Tool::approachOrderCall($data);
  327. try {
  328. // 订单状态
  329. $orderStatus = ($data['Status'] == '1') ? \Yii::$app->params['orderStatus']['paid']['value'] : \Yii::$app->params['orderStatus']['failPaid']['value'];
  330. $oderSn = $data['RefNo'] ?? '';
  331. $formModel = new ApproachOrderForm();
  332. $formModel->scenario = 'verifyPay';
  333. $load = [
  334. 'sn' => $oderSn,
  335. 'scenario' => 'verifyPay',
  336. 'status' => $orderStatus,
  337. 'note' => [
  338. 'MerchantCode' => $data['MerchantCode'],
  339. 'PaymentId' => $data['PaymentId'],
  340. 'status' => $data['Status'],
  341. 'Signature' => $data['Signature'],
  342. 'Currency' => $data['Currency'],
  343. 'Amount' => $data['Amount'],
  344. 'TransId' => $data['TransId'],
  345. 'TranDate' => $data['TranDate'],
  346. 'BankMID' => $data['BankMID'],
  347. 'CCNo' => $data['CCNo'],
  348. ],
  349. ];
  350. if ($formModel->load($load, '') && $result = $formModel->verifyPayOnline()) {
  351. LoggerTool::info($result);
  352. echo 'RECEIVEOK';
  353. return http_response_code(200);
  354. } else {
  355. echo 'RECEIVEOK';
  356. LoggerTool::error(Form::formatErrorsForApi($formModel->getErrors()));
  357. return http_response_code(200);
  358. }
  359. } catch (\Exception $e) {
  360. echo 'RECEIVEOK';
  361. LoggerTool::error(sprintf('actionVerifyApproachOrderError: File[%s], Line:[%s], Message[%s]', $e->getFile(), $e->getLine(), $e->getMessage()));
  362. return http_response_code(200);
  363. }
  364. }
  365. public function actionReQueryPayment()
  366. {
  367. // 每天巡查一次,查询近24小时的未支付订单. 支付参数记录在NOTE字段中,如没有此数据,则不能进行查询.(待支付、支付方式online、当天订单、未删除)
  368. $orderList = ApproachOrder::find()
  369. ->where('STATUS=:STATUS AND PAY_TYPE=:PAY_TYPE AND CREATED_AT>=:CREATED_AT AND DELETED_AT=0',
  370. [':STATUS' => 0, ':PAY_TYPE' => 'online', ':CREATED_AT' => strtotime(date('Y-m-d', time()))])
  371. ->andWhere(['not', ['NOTE' => null]])
  372. ->asArray()
  373. ->all();
  374. LoggerTool::debug(['actionReQueryPayment', $orderList]);
  375. if (!$orderList) {
  376. return static::notice('no record');
  377. }
  378. foreach ($orderList as $order) {
  379. $message = '';
  380. // 支付参数记录在NOTE字段中,如没有此数据,则不能进行查询
  381. $orderPayment = json_decode($order['NOTE'], true);
  382. $rawPostData = "MerchantCode={$orderPayment['MerchantCode']}&RefNo={$orderPayment['RefNo']}&Amount={$orderPayment['Amount']}";
  383. try {
  384. $ch = curl_init();
  385. $url = 'https://payment.ipay88.com.my/epayment/enquiry.asp' . '?' . $rawPostData;
  386. curl_setopt($ch, CURLOPT_URL, $url);
  387. curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  388. $result = curl_exec($ch);
  389. switch (strtolower($result)) {
  390. case '00': // Successful payment.
  391. ApproachOrder::updateAll(['REMARK' => '00: Successful payment'], 'SN=:SN', [':SN' => $order['SN']]);
  392. $paymentParams = [
  393. 'RefNo' => $orderPayment['RefNo'],
  394. 'Amount' => $orderPayment['Amount'],
  395. 'PaymentId' => '182',
  396. 'ProdDesc' => 'Pay for sales',
  397. 'UserName' => 'MY32',
  398. 'SignatureType' => 'SHA256',
  399. 'UserEmail' => 'ek_dummy25@elken.com',
  400. 'UserContact' => '60172249692',
  401. ];
  402. $paymentFields = \Yii::$app->iPay88->getPaymentFields($paymentParams, self::TRANSACTION_TYPE_PAYMENT);
  403. $formModel = new ApproachOrderForm();
  404. $formModel->scenario = 'verifyPay';
  405. $load = [
  406. 'sn' => $orderPayment['RefNo'],
  407. 'scenario' => 'verifyPay',
  408. 'status' => \Yii::$app->params['orderStatus']['paid']['value'],
  409. 'note' => [
  410. 'MerchantCode' => $orderPayment['MerchantCode'],
  411. 'PaymentId' => $paymentFields['PaymentId'],
  412. 'status' => \Yii::$app->params['orderStatus']['paid']['value'],
  413. 'Signature' => $paymentFields['Signature'],
  414. 'Currency' => $paymentFields['Currency'],
  415. 'Amount' => $paymentFields['Amount'],
  416. 'TransId' => '',
  417. 'TranDate' => '',
  418. 'BankMID' => '',
  419. 'CCNo' => '',
  420. ],
  421. ];
  422. if ($formModel->load($load, '') && $result = $formModel->verifyPayOnline()) {
  423. LoggerTool::info($result);
  424. }
  425. $message = '(ReQueryIPay88Payment). orderSN{%s} 00: Successful payment';
  426. break;
  427. case 'invalid parameters':
  428. ApproachOrder::updateAll(
  429. ['STATUS' => \Yii::$app->params['orderStatus']['failPaid']['value'], 'REMARK' => 'Invalid parameters: Parameters pass in incorrect'],
  430. 'SN=:SN', [':SN' => $order['SN']]
  431. );
  432. $message = '(ReQueryIPay88Payment). orderSN{%s} Invalid parameters: Parameters pass in incorrect';
  433. break;
  434. case 'record not found':
  435. ApproachOrder::updateAll(
  436. ['STATUS' => \Yii::$app->params['orderStatus']['failPaid']['value'], 'REMARK' => 'Record not found: Cannot found the record'],
  437. 'SN=:SN', [':SN' => $order['SN']]
  438. );
  439. $message = '(ReQueryIPay88Payment). orderSN{%s} Record not found: Cannot found the record';
  440. break;
  441. case 'incorrect amount':
  442. $message = '(ReQueryIPay88Payment). orderSN{%s} Incorrect amount: Amount different';
  443. ApproachOrder::updateAll(
  444. ['STATUS' => \Yii::$app->params['orderStatus']['failPaid']['value'], 'REMARK' => 'Incorrect amount: Amount different'],
  445. 'SN=:SN', [':SN' => $order['SN']]
  446. );
  447. break;
  448. case 'payment fail':
  449. ApproachOrder::updateAll(
  450. ['STATUS' => \Yii::$app->params['orderStatus']['failPaid']['value'], 'REMARK' => 'Payment fail: Payment fail'],
  451. 'SN=:SN', [':SN' => $order['SN']]
  452. );
  453. $message = '(ReQueryIPay88Payment). orderSN{%s} Payment fail: Payment fail';
  454. break;
  455. case 'm88admin':
  456. ApproachOrder::updateAll(
  457. ['STATUS' => \Yii::$app->params['orderStatus']['failPaid']['value'], 'REMARK' => 'M88Admin: Payment status updated by iPay88 Admin(Fail)'],
  458. 'SN=:SN', [':SN' => $order['SN']]
  459. );
  460. $message = '(ReQueryIPay88Payment). orderSN{%s} M88Admin: Payment status updated by iPay88 Admin(Fail)';
  461. break;
  462. default:
  463. }
  464. curl_close($ch);
  465. // 推送消息到预警平台
  466. // Alarm::reportAlarm(['brand' => 'MSG', 'message' => sprintf($message, $orderPayment['RefNo'])]);
  467. } catch (exception $e) {
  468. curl_close($ch);
  469. LoggerTool::error('err. ' . $e->getMessage());
  470. // Alarm::reportAlarm(['brand' => 'MSG', 'message' => sprintf('err. (ReQueryIPay88Payment). orderSN{%s}. %s', $orderPayment['RefNo'], $e->getMessage())]);
  471. }
  472. }
  473. return static::notice('');
  474. }
  475. /**
  476. * 删除准订单
  477. */
  478. public function actionDeleteApproachOrder()
  479. {
  480. $orderSn = \Yii::$app->request->post('orderSn');
  481. // 订单中间表更新订单状态为取消
  482. ApproachOrder::updateAll(
  483. [
  484. 'STATUS' => \Yii::$app->params['orderStatus']['cancel']['value'],
  485. 'DELETED_AT' => Date::nowTime(),
  486. 'REMARK' => 'Member cancel order',
  487. ],
  488. 'SN=:SN',
  489. [':SN' => $orderSn]);
  490. return static::notice('');
  491. }
  492. /**
  493. * iPay88支付
  494. * @return mixed
  495. * @throws HttpException
  496. */
  497. public function actionIPay88()
  498. {
  499. // 订单ID
  500. $paymentParams['RefNo'] = \Yii::$app->request->post('RefNo');
  501. // 订单
  502. $order = ApproachOrder::findOne(['SN' => $paymentParams['RefNo']]);
  503. if (is_null($order) || is_null($order->toArray()) || !$order->toArray()) {
  504. return static::notice('订单编号无效');
  505. }
  506. // 转为分
  507. $money = $order['PAY_AMOUNT'];
  508. // 订单金额,元=>分
  509. // $money = \Yii::$app->request->post('Amount');
  510. // 马来币汇率
  511. $exchangeRateMYR = floatval(Cache::getSystemConfig()['exchangeRateMYR']['VALUE'] ?? 0);
  512. // 计算马来币
  513. $amount = number_format(round($money * $exchangeRateMYR), 2, '.', '');
  514. // $amount = number_format($money, 2, '.', '');
  515. // $amount = number_format(1, 2, '.', ''); // TODO: 测试
  516. $paymentParams['Amount'] = str_replace('.', '', $amount);
  517. // (Optional) (int)
  518. $paymentParams['PaymentId'] = '182'; // 2=信用卡 182=银联
  519. // Product description. (length 100)
  520. $paymentParams['ProdDesc'] = 'Pay for sales';
  521. // Customer name. (length 100)
  522. $paymentParams['UserName'] = 'MY32';
  523. $paymentParams['SignatureType'] = 'SHA256';
  524. // Customer email. (length 100)
  525. $paymentParams['UserEmail'] = 'ek_dummy25@elken.com';
  526. // Customer contact. (length 20)
  527. $paymentParams['UserContact'] = '60172249692';
  528. // (Optional) Merchant remarks. (length 100)
  529. //$paymentParams['Remark'] = 'Here is the description';
  530. //merchantkey + merchantcode+ reference Number + amount in cent + currency_code
  531. $paymentFields = \Yii::$app->iPay88->getPaymentFields($paymentParams, self::TRANSACTION_TYPE_PAYMENT);
  532. $transactionUrl = \Yii::$app->iPay88->getTransactionUrl(self::TRANSACTION_TYPE_PAYMENT);
  533. $paymentFields['Amount'] = $amount;
  534. $res = [
  535. 'paymentFields' => $paymentFields,
  536. 'transactionUrl' => $transactionUrl,
  537. ];
  538. // 支付信息写入note
  539. $order->NOTE = json_encode([
  540. 'MerchantCode' => $paymentFields['MerchantCode'],
  541. 'PaymentId' => $paymentFields['PaymentId'],
  542. 'RefNo' => $paymentFields['RefNo'],
  543. 'Amount' => $paymentFields['Amount'],
  544. 'Currency' => $paymentFields['Currency'],
  545. 'Signature' => $paymentFields['Signature'],
  546. ]);
  547. $order->update();
  548. return static::notice($res);
  549. }
  550. /**
  551. * 推送订单到wst仓储系统
  552. * @throws HttpException
  553. * @throws \Exception
  554. */
  555. public function actionLogistics()
  556. {
  557. $orderSn = \Yii::$app->request->get('sn');
  558. $order = Order::find()
  559. ->where('SN=:ORDER_SN', [':ORDER_SN' => $orderSn])
  560. ->asArray()
  561. ->one();
  562. if (!$order) {
  563. return static::notice('订单【' . $orderSn . '】不存在');
  564. }
  565. if ($order['SEND_AT'] > 0) {
  566. return static::notice('订单【' . $orderSn . '】不可重复推送');
  567. }
  568. $logistics = new Logistics();
  569. $response = $logistics->createOrder($order);
  570. LoggerTool::info(['actionLogistics', $response]);
  571. if ($response['success'] == 1) {
  572. // 更新db中订单推送成功状态
  573. if (Order::updateAll(['SEND_AT' => time()], 'SN=:SN', [':SN' => $orderSn])) {
  574. return static::notice($response);
  575. } else {
  576. return static::notice($orderSn . ' 推送wst系统成功, 更新状态失败');
  577. }
  578. }
  579. return static::notice($orderSn . ' 推送wst系统失败');
  580. }
  581. /**
  582. * @throws HttpException
  583. * @throws \Exception
  584. */
  585. public function actionLogisticsAuto()
  586. {
  587. $createdAtEnd = strtotime(date('Y-m-d')) - 1;
  588. // 早0点推送,前一天0-24点的订单
  589. $orderList = Order::find()
  590. ->where(
  591. '(CREATED_AT <= :CREATED_AT_END) AND STATUS=:STATUS AND SEND_AT=:SEND_AT AND PAY_TYPE=:PAY_TYPE AND IS_DELETE = 0',
  592. [
  593. ':CREATED_AT_END' => $createdAtEnd,
  594. ':STATUS' => \Yii::$app->params['orderStatus']['paid']['value'],
  595. ':SEND_AT' => 0,
  596. ':PAY_TYPE' => 'online',
  597. ]
  598. )
  599. ->asArray()
  600. ->all();
  601. if (!$orderList) {
  602. // 发送预警通知
  603. $alarm = [
  604. 'stance' => 2,
  605. 'brand' => 'MSG',
  606. 'message' => '跨境商品推送淘布斯系统终止,原因:无订单',
  607. ];
  608. Alarm::reportAlarm($alarm);
  609. return static::notice('推送wst系统终止,原因:无订单');
  610. }
  611. $orderSnSuccess = [];
  612. $orderSnFailed = [];
  613. $logistics = new Logistics();
  614. foreach ($orderList as $order) {
  615. // 发送wst仓库系统
  616. $response = $logistics->createOrder($order);
  617. LoggerTool::info($response);
  618. if ($response['success'] == 1) {
  619. // 写入mongo
  620. Tool::wstOrderCall($response['data']);
  621. $orderSnSuccess[] = $order['SN'];
  622. } else {
  623. // 记录推送结果
  624. $orderSnFailed[] = $order['SN'];
  625. // 发送预警通知
  626. $alarm = [
  627. 'stance' => 5,
  628. 'brand' => 'MSG',
  629. 'message' => sprintf('跨境商品推送淘布斯系统失败. 订单号[%s], error[%s]', $order['SN'], $response),
  630. ];
  631. Alarm::reportAlarm($alarm);
  632. }
  633. }
  634. $notify = '跨境商品推送淘布斯系统结束. ';
  635. // 更新db中订单推送成功状态
  636. if (count($orderSnSuccess) > 0) {
  637. $orderSnSuccessIds = implode("','", $orderSnSuccess);
  638. Order::updateAll(['SEND_AT' => time()], "SN IN ('" . $orderSnSuccessIds . "')");
  639. $notify .= sprintf('成功订单数{%d}, 订单号[%s];', count($orderSnSuccess), implode(', ', $orderSnSuccess));
  640. }
  641. if (count($orderSnFailed) > 0) {
  642. $notify .= sprintf('失败订单数{%d}, 订单号[%s]', count($orderSnFailed), implode(', ', $orderSnFailed));
  643. }
  644. // 发送预警通知
  645. $alarm = [
  646. 'stance' => 2,
  647. 'brand' => 'MSG',
  648. 'message' => $notify,
  649. ];
  650. Alarm::reportAlarm($alarm);
  651. return static::notice($notify);
  652. }
  653. /*
  654. * 预支付-正扫(4.1).
  655. */
  656. public function actionUpopPrePay()
  657. {
  658. // 订单ID
  659. // $refNo = \Yii::$app->request->post('refNo');
  660. // 银行代码
  661. // $bankCode = \Yii::$app->request->post('bankCode');
  662. // 订单ID
  663. $refNo = 'OS202310198286872118';
  664. // 银行代码
  665. $bankCode = "WECHAT";
  666. // 订单
  667. $order = ApproachOrder::findOneAsArray(['SN' => $refNo]);
  668. if (!$order) {
  669. return static::notice('订单编号无效');
  670. }
  671. $orderProducts = ApproachOrderGoods::findOneAsArray(['ORDER_SN' => $refNo]);
  672. // 支付报文
  673. $payload = [
  674. "version" => "2.0.0", // 版本号.定值2.0.0
  675. "trade_code" => "PAY", // 交易代码
  676. "bank_code" => $bankCode, // 银行代码
  677. "agencyId" => \Yii::$app->params['UPOP']['agencyId'], // 商户号
  678. "child_merchant_no" => \Yii::$app->params['UPOP']['childMerchantId'], // 子商户号
  679. "terminal_no" => \Yii::$app->params['UPOP']['terminalId'], // 商户终端号
  680. "order_no" => $refNo . mt_rand(0, 10000000), // 第三方订单号
  681. // "amount" => number_format($order['PAY_AMOUNT'], 2), // 交易金额(元) 2位小数
  682. "amount" => number_format(0.01, 2), // 交易金额(元) 2位小数
  683. "currency_type" => "HKD", // 交易币种 HKD(港币)
  684. "sett_currency_type" => "HKD", // 清算币种 HKD(港币)
  685. "product_name" => $orderProducts['GOODS_TITLE'], // 产品名称
  686. "return_url" => \Yii::$app->params['UPOP']['returnUrl'], // 同步通知地址
  687. "notify_url" => \Yii::$app->params['UPOP']['notifyUrl'], // 异步通知地址
  688. "client_ip" => $_SERVER['REMOTE_ADDR'] // "18.139.193.5", // 客户端IP(订单⽣成的机器IP,指⽤户浏览器端IP,不是商户服务器IP) $_SERVER['REMOTE_ADDR']
  689. ];
  690. // $result = Tool::httpPost(\Yii::$app->params['unityUat']['url'], http_build_query($payload));
  691. // 预支付
  692. $result = (new PaySign())->sendEncodeData($payload, \Yii::$app->params['UPOP']['backPayUrl']);
  693. return static::notice($result);
  694. }
  695. /*
  696. * 预下单(4.11-4.15). 银联在线支付 - UPOP
  697. */
  698. public function actionUpopOnlinePay()
  699. {
  700. // 订单ID
  701. $refNo = \Yii::$app->request->post('refNo');
  702. // 媒体设备
  703. $device = \Yii::$app->request->post('device', "0");
  704. // 订单
  705. $order = ApproachOrder::findOneAsArray(['SN' => $refNo]);
  706. if (!$order) {
  707. return static::notice('订单编号无效');
  708. }
  709. // 订单商品
  710. $orderProducts = ApproachOrderGoods::findOneAsArray(['ORDER_SN' => $refNo]);
  711. // 预支付报文
  712. $payload = [
  713. "version" => "2.0.0", // 版本号.定值2.0.0
  714. "trade_code" => "PAY", // 交易代码
  715. "agencyId" => \Yii::$app->params['UPOP']['agencyId'], // 商户号
  716. "child_merchant_no" => \Yii::$app->params['UPOP']['childMerchantId'], // 子商户号
  717. "terminal_no" => \Yii::$app->params['UPOP']['terminalId'], // 商户终端号
  718. "order_no" => $refNo . mt_rand(0, 1000), // 第三方订单号
  719. "amount" => number_format($order['PAY_AMOUNT'], 2), // 交易金额(元)
  720. "currency_type" => "HKD", // 交易币种 HKD
  721. "sett_currency_type" => "HKD", // 清算币种
  722. "product_name" => $orderProducts['GOODS_TITLE'], // 产品名称
  723. "user_name" => $order['USER_NAME'], // ⽤户名称
  724. "return_url" => \Yii::$app->params['UPOP']['returnUrl'], // 同步通知地址
  725. "notify_url" => \Yii::$app->params['UPOP']['notifyUrl'], // 异步通知地址
  726. "client_ip" => $_SERVER['REMOTE_ADDR'], // 客户端IP(订单⽣成的机器IP,指⽤户浏览器端IP,不是商户服务器IP)
  727. ];
  728. // 预支付
  729. $response = (new PaySign())->sendEncodeData($payload, \Yii::$app->params['UPOP']['backPayUrl']);
  730. if ($response) {
  731. // 前台支付报文
  732. $request = [
  733. "token_id" => $response['token_id'], // 预下单接⼝返回的token_id
  734. "access_type" => in_array($device, [0, 1]) ?: "0", // 访问端类型: 0:⽹⻚ 1:⼿机
  735. "bank_code" => 'UPOP', // 调起⽀付后的默认⽀付⽅式
  736. ];
  737. $request = \Yii::$app->params['UPOP']['frontPayUrl'] . '?' . http_build_query($request);
  738. return static::notice($request);
  739. }
  740. return static::notice($response);
  741. }
  742. /**
  743. * UPOP支付成功的webhook.
  744. * @throws \Exception
  745. */
  746. public function actionUpopWebhook() {
  747. // 支付成功的webhook.
  748. $rawPostData = file_get_contents('php://input');
  749. LoggerTool::info(['actionUpopWebhook', $rawPostData]);
  750. $data = [];
  751. if (strlen($rawPostData) > 0) {
  752. $rawPostArray = explode('&', $rawPostData);
  753. foreach ($rawPostArray as $raw) {
  754. $raw = explode('=', $raw);
  755. if (count($raw) == 2)
  756. $data[$raw[0]] = urldecode($raw[1]);
  757. }
  758. }
  759. LoggerTool::info(['actionUpopWebhook', $data]);
  760. // 支付webhook回调日志
  761. //Tool::approachOrderCall($data);
  762. // try {
  763. // // 订单状态
  764. // $orderStatus = ($data['Status'] == '1') ? \Yii::$app->params['orderStatus']['paid']['value'] : \Yii::$app->params['orderStatus']['failPaid']['value'];
  765. //
  766. // $oderSn = $data['RefNo'] ?? '';
  767. //
  768. // $formModel = new ApproachOrderForm();
  769. // $formModel->scenario = 'verifyPay';
  770. // $load = [
  771. // 'sn' => $oderSn,
  772. // 'scenario' => 'verifyPay',
  773. // 'status' => $orderStatus,
  774. // 'note' => [
  775. // 'MerchantCode' => $data['MerchantCode'],
  776. // 'PaymentId' => $data['PaymentId'],
  777. // 'status' => $data['Status'],
  778. // 'Signature' => $data['Signature'],
  779. // 'Currency' => $data['Currency'],
  780. // 'Amount' => $data['Amount'],
  781. // 'TransId' => $data['TransId'],
  782. // 'TranDate' => $data['TranDate'],
  783. // 'BankMID' => $data['BankMID'],
  784. // 'CCNo' => $data['CCNo'],
  785. //
  786. // ],
  787. // ];
  788. //
  789. // if ($formModel->load($load, '') && $result = $formModel->verifyPayOnline()) {
  790. // LoggerTool::info($result);
  791. //
  792. // echo 'RECEIVEOK';
  793. // return http_response_code(200);
  794. // } else {
  795. // echo 'RECEIVEOK';
  796. // LoggerTool::error(Form::formatErrorsForApi($formModel->getErrors()));
  797. // return http_response_code(200);
  798. // }
  799. // } catch (\Exception $e) {
  800. // echo 'RECEIVEOK';
  801. // LoggerTool::error(sprintf('actionUpopWebhookError: File[%s], Line:[%s], Message[%s]', $e->getFile(), $e->getLine(), $e->getMessage()));
  802. // return http_response_code(200);
  803. // }
  804. }
  805. }