OrdersController.php 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641
  1. <?php
  2. namespace App\Http\Controllers\QuickApp\Order;
  3. use App\Modules\Statistic\Services\AdVisitStatService;
  4. use App\Http\Controllers\QuickApp\BaseController;
  5. use Illuminate\Http\Request;
  6. use App\Modules\Subscribe\Services\BookOrderService;
  7. use App\Modules\Subscribe\Services\ChapterOrderService;
  8. use App\Modules\Subscribe\Services\OrderService;
  9. use App\Http\Controllers\QuickApp\Order\Transformers\BookOrderTransformer;
  10. use App\Http\Controllers\QuickApp\Order\Transformers\ChapterOrderTransformer;
  11. use App\Http\Controllers\QuickApp\Order\Transformers\ChargeListTransformer;
  12. use App\Libs\Pay\PayFactory;
  13. use Hashids;
  14. use App\Modules\Product\Services\ProductService;
  15. use App\Modules\Book\Services\BookConfigService;
  16. use App\Modules\Book\Services\BookService;
  17. use App\Modules\Channel\Services\PayTemplateService;
  18. use App\Modules\Trade\Pay\OrderArousePayFactory;
  19. use App\Modules\Trade\Pay\OrderPaySuccess;
  20. use App\Modules\Trade\Services\PayMerchantService;
  21. use EasyWeChat\Support\XML;
  22. class OrdersController extends BaseController
  23. {
  24. /**
  25. * @apiDefine Order 订单
  26. */
  27. /**
  28. *
  29. */
  30. private $chargeList;
  31. public function exchangeList()
  32. {
  33. foreach ($this->chargeList as &$item) {
  34. if (!$item->switch_to) continue;
  35. $order = Order::where('uid', $this->uid)->where('status', 'PAID')->where('product_id', $item->id)->first();
  36. if ($order) {
  37. $change = ProductService::getProductSingle($item->switch_to);
  38. $item->id = $change->id;
  39. $item->price = $change->price;
  40. $item->given = $change->given;
  41. }
  42. }
  43. }
  44. /**
  45. * @apiVersion 1.0.0
  46. * @apiDescription 充值列表
  47. * @api {get} order/chargeList 充值列表
  48. * @apiHeader {String} [Authorization] token
  49. * @apiGroup Order
  50. * @apiName chargeList
  51. * @apiSuccess {int} code 状态码
  52. * @apiSuccess {String} msg 信息
  53. * @apiSuccess {object} data 结果集
  54. * @apiSuccessExample {json} Success-Response:
  55. * HTTP/1.1 200 OK
  56. * {
  57. * code: 0,
  58. * msg: "",
  59. * data: [
  60. * {
  61. * product_id: 1,
  62. * price: "30.00元",
  63. * vip: 0,
  64. * intro: [
  65. * {
  66. * label: 3000,
  67. * important: false
  68. * },
  69. * {
  70. * label: "书币",
  71. * important: true
  72. * }
  73. * ]
  74. * },
  75. * {
  76. * product_id: 2,
  77. * price: "50.00元",
  78. * vip: 1,
  79. * intro: [
  80. * {
  81. * label: 5000,
  82. * important: false
  83. * },
  84. * {
  85. * label: "1000+",
  86. * important: true
  87. * },
  88. * {
  89. * label: "书币",
  90. * important: false
  91. * }
  92. * ]
  93. * },
  94. * {
  95. * product_id: 5,
  96. * price: "365.00元",
  97. * vip: 0,
  98. * intro: [
  99. * {
  100. * label: "年费VIP会员",
  101. * important: true
  102. * }
  103. * ]
  104. * }
  105. * ]
  106. * }
  107. */
  108. public function chargeList(Request $request)
  109. {
  110. $bid = $request->input('bid', '');
  111. $temp = $bid;
  112. $template_id = PayTemplateService::getPayTemplate($this->distribution_channel_id);
  113. $book_config = null;
  114. if ($bid) {
  115. $bid = Hashids::decode($bid)[0];
  116. $book_config = BookConfigService::getBookById($bid);
  117. }
  118. if ($template_id == 2) { //模板2只有在长篇小说过来的用户才显示
  119. //部分渠道需要2元模板不管哪个入口进来都展示
  120. $exclude_channels = explode(',', env('PRICE_TWO_SHOW_ALL_CHANNEL'));
  121. if (!in_array($this->distribution_channel_id, $exclude_channels)) {
  122. if ($book_config) {
  123. if ($book_config->charge_type == 'BOOK') $template_id = 1;
  124. }
  125. }
  126. }
  127. $res = ProductService::getChargeProduct($template_id);
  128. if (!$res) {
  129. return response()->error('WAP_SYS_ERROR');
  130. }
  131. $this->chargeList = $res;
  132. $this->exchangeList();
  133. //TODO 长篇小数才有模板2
  134. $uid = $this->uid;
  135. $is_first_recharge = OrderService::judgeUserFirstRecharge($uid);
  136. $data = [];
  137. $appad = 0;
  138. foreach ($res as $v) {
  139. if ($template_id == 7 && $book_config && $book_config->charge_type == 'BOOK' && $v->price == 2) {
  140. continue;
  141. }
  142. if ($template_id == 2 && $v->type == 'NEW_USER' && !$bid) {
  143. //2元模版,直接进充值,不出现
  144. continue;
  145. }
  146. if ($v->type == 'NEW_USER' && $is_first_recharge) {
  147. if (
  148. env('NO_NEW_USER_CHARGE') &&
  149. in_array(
  150. $this->distribution_channel_id,
  151. explode(',', env('NO_NEW_USER_CHARGE'))
  152. )
  153. ) {
  154. continue;
  155. }
  156. $temp = [
  157. 'price' => (float) $v->price . '元',
  158. 'is_year_order' => 0,
  159. 'is_month_order' => 0,
  160. 'text' => sprintf('%s+%s书币', $v->price * 100, $v->given),
  161. 'today_special' => $v->is_default,
  162. 'first_charge' => true,
  163. 'save_text' => round($v->given / 100, 1) . '元',
  164. 'product_id' => $v->id,
  165. ];
  166. $data[] = $temp;
  167. } elseif ($v->type == 'YEAR_ORDER') {
  168. if ($v->type == 'NEW_USER') {
  169. continue;
  170. }
  171. $save_text = '年费vip会员';
  172. $text = '每天1元,全年免费看';
  173. $temp = [
  174. 'price' => (int) $v->price . '元',
  175. 'is_year_order' => 1,
  176. 'is_month_order' => 0,
  177. 'text' => $text,
  178. 'today_special' => $v->is_default,
  179. 'first_charge' => false,
  180. 'save_text' => $save_text,
  181. 'product_id' => $v->id,
  182. ];
  183. $data[] = $temp;
  184. } else {
  185. if ($v->type == 'NEW_USER') {
  186. continue;
  187. }
  188. $save_text = '';
  189. if ($v->given) {
  190. $save_text = round($v->given / 100, 1) . '元';
  191. $text = sprintf('%s+%s书币', $v->price * 100, $v->given);
  192. } else {
  193. $text = sprintf('%s书币', $v->price * 100);
  194. }
  195. $temp = [
  196. 'price' => (float) $v->price . '元',
  197. 'is_year_order' => 0,
  198. 'is_month_order' => 0,
  199. 'text' => $text,
  200. 'today_special' => $v->is_default,
  201. 'first_charge' => false,
  202. 'save_text' => $save_text,
  203. 'product_id' => $v->id,
  204. ];
  205. $data[] = $temp;
  206. }
  207. }
  208. return response()->success($data);
  209. }
  210. /**
  211. * @apiVersion 1.0.0
  212. * @apiDescription 单本消费记录
  213. * @api {get} order/bookOrderList 单本消费记录
  214. * @apiHeader {String} [Authorization] token
  215. * @apiGroup Order
  216. * @apiName bookOrderList
  217. * @apiParam {String} [page_size] 分页大小
  218. * @apiParam {String} [page] 页码
  219. * @apiSuccess {int} code 状态码
  220. * @apiSuccess {String} msg 信息
  221. * @apiSuccess {object} data 结果集
  222. * @apiSuccess {Int} uid uid
  223. * @apiSuccess {Int} bid bid
  224. * @apiSuccess {Int} book_name 书名
  225. * @apiSuccess {Int} fee 钱
  226. * @apiSuccess {String} created_at 时间
  227. * @apiSuccessExample {json} Success-Response:
  228. * HTTP/1.1 200 OK
  229. * {
  230. * code: 0,
  231. * msg: "",
  232. * data: list:[
  233. * {
  234. * uid: 4,
  235. * bid: 1,
  236. * book_name: "dfsedfertrwet",
  237. * fee: 100,
  238. * created_at: "2017-12-02 16:24:54"
  239. * }
  240. * ]
  241. * meta: {
  242. * total: 1,
  243. * per_page: 15,
  244. * current_page: 1,
  245. * last_page: 1,
  246. * next_page_url: "",
  247. * prev_page_url: ""
  248. * }
  249. * }
  250. * }
  251. */
  252. public function bookOrderList(Request $request)
  253. {
  254. $page_size = $request->input('page_size', 15);
  255. $book_order = BookOrderService::getRecord($this->uid, $page_size);
  256. return response()->pagination(new BookOrderTransformer(), $book_order);
  257. }
  258. /**
  259. * @apiVersion 1.0.0
  260. * @apiDescription 章节消费记录
  261. * @api {get} order/chapterOrderList 章节消费记录
  262. * @apiHeader {String} [Authorization] token
  263. * @apiGroup Order
  264. * @apiName chapterOrderList
  265. * @apiParam {String} [page_size] 分页大小
  266. * @apiParam {String} [page] 页码
  267. * @apiSuccess {int} code 状态码
  268. * @apiSuccess {String} msg 信息
  269. * @apiSuccess {object} data 结果集
  270. * @apiSuccess {Int} uid uid
  271. * @apiSuccess {Int} bid bid
  272. * @apiSuccess {Int} cid cid
  273. * @apiSuccess {Int} chapter_name 章节名
  274. * @apiSuccess {Int} book_name 书名
  275. * @apiSuccess {Int} fee 钱
  276. * @apiSuccess {String} created_at 时间
  277. * @apiSuccessExample {json} Success-Response:
  278. * HTTP/1.1 200 OK
  279. * {
  280. * code: 0,
  281. * msg: "",
  282. * data: list:[
  283. * {
  284. * uid: 4,
  285. * bid: 1,
  286. * cid: 1,
  287. * chapter_name: "sdfsd",
  288. * book_name: "dfsedfertrwet",
  289. * fee: 100,
  290. * created_at: "2017-12-02 16:24:54"
  291. * }
  292. * ]
  293. * meta: {
  294. * total: 1,
  295. * per_page: 15,
  296. * current_page: 1,
  297. * last_page: 1,
  298. * next_page_url: "",
  299. * prev_page_url: ""
  300. * }
  301. * }
  302. */
  303. public function chapterOrderList(Request $request)
  304. {
  305. $chapter_model = new ChapterOrderService();
  306. $page_size = $request->input('page_size', 15);
  307. $chapter_order = $chapter_model->getByUid($this->uid, $page_size);
  308. foreach ($chapter_order as $item) {
  309. if ($item->fee == 0) {
  310. $result = AdVisitStatService::getInfoV2($this->uid, $item->cid, ['UNLOCK', 'UNLOCK_2']);
  311. $item->fee = '解锁';
  312. }
  313. }
  314. return response()->pagination(new ChapterOrderTransformer(), $chapter_order);
  315. }
  316. /**
  317. * @apiVersion 1.0.0
  318. * @apiDescription 充值记录
  319. * @api {get} order/chargeRecordLists 充值记录
  320. * @apiParam {String} [token] token
  321. * @apiHeader {String} [Authorization] token 两个token任选其一
  322. * @apiGroup Order
  323. * @apiName chargeRecordLists
  324. * @apiParam {String} [page_size] 分页大小
  325. * @apiParam {String} [page] 页码
  326. * @apiSuccess {int} code 状态码
  327. * @apiSuccess {String} msg 信息
  328. * @apiSuccess {object} data 结果集
  329. * @apiSuccess {String} data.price 价格
  330. * @apiSuccess {String} data.status 状态
  331. * @apiSuccess {String} data.trade_no 订单号
  332. * @apiSuccess {String} data.created_at 时间
  333. * @apiSuccessExample {json} Success-Response:
  334. * HTTP/1.1 200 OK
  335. * {
  336. * code: 0,
  337. * msg: "",
  338. * data: {
  339. * list: [
  340. * {
  341. * id: 134,
  342. * price: "1.00",
  343. * status: "PAID",
  344. * trade_no: "201712021915481585670623626232",
  345. * created_at: "2017-12-02 19:15:56"
  346. * }
  347. * ],
  348. * meta: {
  349. * total: 1,
  350. * per_page: 15,
  351. * current_page: 1,
  352. * last_page: 1,
  353. * next_page_url: "",
  354. * prev_page_url: ""
  355. * }
  356. * }
  357. * }
  358. */
  359. public function chargeRecordLists(Request $request)
  360. {
  361. $page_size = $request->input('page_size', 15);
  362. $res = OrderService::getOrderList($this->uid, $page_size);
  363. return response()->pagination(new ChargeListTransformer(), $res);
  364. }
  365. private function getPayParams(Request $request)
  366. {
  367. $uid = $this->uid;
  368. $product_id = $request->get('product_id', 0);
  369. $send_order_id = $this->send_order_id;
  370. if (!$product_id) {
  371. return false;
  372. }
  373. $bid = $request->get('bid', 0);
  374. if ($bid) {
  375. $from_bid = BookService::decodeBidStatic($bid);
  376. }
  377. $trade_no = date("YmdHis") . hexdec(uniqid());
  378. $product_info = ProductService::getProductSingle($product_id);
  379. $distribution_channel_id = $this->distribution_channel_id;
  380. $price = $product_info->price * 100;
  381. if (in_array($uid, explode(',', env('TEST_UID')))) {
  382. $price = 1;
  383. }
  384. $from_type = 'QuickApp';
  385. if ($product_info->type == 'YEAR_ORDER') {
  386. $order_type = 'YEAR';
  387. } elseif ($product_info->type == 'BOOK_ORDER') {
  388. $order_type = 'BOOK';
  389. } elseif ($product_info->type == 'TICKET_RECHARGE') {
  390. $order_type = 'RECHARGE';
  391. } else {
  392. $order_type = '';
  393. }
  394. $create_ip = _getIp();
  395. return compact(
  396. 'distribution_channel_id',
  397. 'uid',
  398. 'product_id',
  399. 'price',
  400. 'trade_no',
  401. 'create_ip',
  402. 'send_order_id',
  403. 'from_bid',
  404. 'from_type',
  405. 'order_type'
  406. );
  407. }
  408. /**
  409. * @apiVersion 1.0.0
  410. * @apiDescription 支付
  411. * @api {get} goToPay 微信APP支付
  412. * @apiGroup pay
  413. * @apiName wxindex
  414. * @apiParam {Int} product_id product_id
  415. * @apiParam {Int} send_order_id send_order_id
  416. * @apiParam {String} bid bid
  417. * @apiHeader {String} [Authorization] token
  418. * @apiSuccess {int} code 状态码
  419. * @apiSuccess {String} msg 信息
  420. * @apiSuccess {Object} data 信息
  421. * @apiSuccess {Object} data.trade_no 订单号
  422. * @apiSuccess {Object} data.appId 唤起支付的appId
  423. * @apiSuccess {Object} data.mch_id 唤起支付的mch_id
  424. * @apiSuccess {Object} data.nonce_str 唤起支付的nonce_str
  425. * @apiSuccess {Object} data.prepay_id 唤起支付的prepay_id
  426. * @apiSuccess {Object} data.sign 唤起支付的sign
  427. * @apiSuccess {Object} data.trade_type 唤起支付trade_type
  428. * @apiSuccessExample {json} Success-Response:
  429. * HTTP/1.1 200 OK
  430. * {
  431. * code: 0,
  432. * msg: "",
  433. * data: {
  434. *
  435. * }
  436. */
  437. function wxIndex(Request $request)
  438. {
  439. if ($params = $this->getPayParams($request)) {
  440. $params['pay_merchant_source'] = 'OFFICIALPAY_QAPP_APP';
  441. } else {
  442. return response()->error('QAPP_PARAM_ERROR');
  443. }
  444. $app = OrderArousePayFactory::wx($this->uid);
  445. // 微信支付参数
  446. $params['trade_type'] = 'APP'; //交易类型
  447. $result = $app->handle($params);
  448. if ($result) {
  449. $result['trade_no'] = $params['trade_no'];
  450. return response()->success($result);
  451. } else {
  452. return response()->error('APP_CREATE_WECHAT_ORDER_FAIL');
  453. }
  454. }
  455. /**
  456. * @apiVersion 1.0.0
  457. * @apiDescription 微信H5支付
  458. * @api {get} goToH5Pay 微信H5支付
  459. * @apiGroup pay
  460. * @apiName wxH5Index
  461. * @apiParam {Int} product_id product_id
  462. * @apiParam {Int} send_order_id send_order_id
  463. * @apiParam {String} bid bid
  464. * @apiHeader {String} [Authorization] token
  465. * @apiSuccess {int} code 状态码
  466. * @apiSuccess {String} msg 信息
  467. * @apiSuccess {Object} data 信息
  468. * @apiSuccess {Object} data.trade_no 订单号
  469. * @apiSuccess {Object} data.appId 唤起支付的appId
  470. * @apiSuccess {Object} data.mch_id 唤起支付的mch_id
  471. * @apiSuccess {Object} data.nonce_str 唤起支付的nonce_str
  472. * @apiSuccess {Object} data.prepay_id 唤起支付的prepay_id
  473. * @apiSuccess {Object} data.sign 唤起支付的sign
  474. * @apiSuccess {Object} data.trade_type 唤起支付trade_type
  475. * @apiSuccess {Object} data.mweb_url 唤起支付mweb_url
  476. * @apiSuccessExample {json} Success-Response:
  477. * HTTP/1.1 200 OK
  478. * {
  479. * code: 0,
  480. * msg: "",
  481. * data: {
  482. *
  483. * }
  484. */
  485. function wxH5Index(Request $request)
  486. {
  487. if ($params = $this->getPayParams($request)) {
  488. $params['pay_merchant_source'] = 'OFFICIALPAY_QAPP_H5';
  489. } else {
  490. return response()->error('QAPP_PARAM_ERROR');
  491. }
  492. $app = OrderArousePayFactory::wx($this->uid);
  493. // 微信支付参数
  494. $params['trade_type'] = 'MWEB'; //交易类型
  495. $result = $app->handle($params);
  496. if ($result) {
  497. $result['trade_no'] = $params['trade_no'];
  498. return response()->success($result);
  499. } else {
  500. return response()->error('APP_CREATE_WECHAT_ORDER_FAIL');
  501. }
  502. }
  503. /**
  504. * @apiVersion 1.0.0
  505. * @apiDescription 支付宝APP支付
  506. * @api {get} goToAliPay 支付宝APP支付
  507. * @apiGroup pay
  508. * @apiName aliIndex
  509. * @apiParam {Int} product_id product_id
  510. * @apiParam {Int} send_order_id send_order_id
  511. * @apiParam {String} bid bid
  512. * @apiHeader {String} [Authorization] token
  513. * @apiSuccess {Object} data.order_info 唤起支付信息str
  514. * @apiSuccess {Object} data.trade_no 订单号
  515. * @apiSuccessExample {json} Success-Response:
  516. * HTTP/1.1 200 OK
  517. * {
  518. * code: 0,
  519. * msg: "",
  520. * data:""
  521. *
  522. */
  523. public function aliIndex(Request $request)
  524. {
  525. if ($params = $this->getPayParams($request)) {
  526. $params['pay_merchant_source'] = 'QuickAppALiPay';
  527. $params['type'] = 'App';
  528. } else {
  529. return response()->error('QAPP_PARAM_ERROR');
  530. }
  531. $app = OrderArousePayFactory::ali($this->uid);
  532. $order_info = $app->handle($params);
  533. return response()->success(['trade_no' => $params['trade_no'], 'order_info' => $order_info]);
  534. }
  535. /**
  536. * @apiVersion 1.0.0
  537. * @apiDescription 订单查询
  538. * @api {get} checkOrder 订单查询
  539. * @apiGroup pay
  540. * @apiName checkOrder
  541. * @apiParam {String} [token] token
  542. * @apiHeader {String} [Authorization] token 两个token任选其一
  543. * @apiParam {String} order order
  544. * @apiSuccess {int} code 状态码
  545. * @apiSuccess {String} msg 信息
  546. * @apiSuccess {Object} data 信息
  547. * @apiSuccessExample {json} Success-Response:
  548. * HTTP/1.1 200 OK
  549. * {
  550. * code: 0,
  551. * msg: "",
  552. * data: {
  553. *
  554. * }
  555. */
  556. public function checkOrder(Request $request)
  557. {
  558. $order = $request->input('order');
  559. $order_info = OrderService::getByTradeNo($order);
  560. if ($order_info && $order_info->status == 'PAID') {
  561. return response()->success();
  562. }
  563. return response()->success($order);
  564. }
  565. /**
  566. * 官方微信回调
  567. */
  568. function wxback(Request $request)
  569. {
  570. $xml = XML::parse(strval($request->getContent()));
  571. myLog('wxpay')->info($xml);
  572. if (isset($xml['attach'])) {
  573. $pay_merchant_name = $xml['attach'];
  574. $config = PayMerchantService::getPayConfigByNameStatic($pay_merchant_name);
  575. $app = PayFactory::official($config);
  576. $response = $app->notify()->handleNotify(function ($notify, $successful) {
  577. if (!$successful) {
  578. return 'fail';
  579. }
  580. if (OrderPaySuccess::handle($notify->out_trade_no, $notify->transaction_id)) {
  581. return true;
  582. } else {
  583. return 'fail';
  584. }
  585. });
  586. return $response;
  587. } else {
  588. return 'fail';
  589. }
  590. }
  591. /**
  592. * 支付宝支付回调
  593. */
  594. function aliback(Request $request)
  595. {
  596. $param = $request->except('_url');
  597. $app = PayFactory::aliPay();
  598. myLog('alipay')->info($param);
  599. if ($app->notify($param)) {
  600. if (OrderPaySuccess::handle($param['out_trade_no'], $param['trade_no'])) {
  601. return response('success');
  602. } else {
  603. return response('fail');
  604. }
  605. } else {
  606. myLog('alipay')->info('sign fail');
  607. return response('fail');
  608. }
  609. }
  610. function wait(Request $request)
  611. {
  612. $param = $request->except('_url');
  613. return view('pay.middleware')->with($param);
  614. }
  615. }