Order.php 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | 商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2017~2021 https://www.thinkphp.com All rights reserved.
  6. // +----------------------------------------------------------------------
  7. // | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
  8. // +----------------------------------------------------------------------
  9. // | Author: thinkphp <admin@yiovo.com>
  10. // +----------------------------------------------------------------------
  11. declare (strict_types=1);
  12. namespace app\api\model\book;
  13. use app\api\model\School;
  14. use app\api\model\SchoolSpeciality;
  15. use app\api\model\Setting as SettingModel;
  16. use app\api\model\SpecialityBook;
  17. use app\api\model\User;
  18. use app\api\service\User as UserService;
  19. use app\common\library\helper;
  20. use app\common\library\wechat\WxPay;
  21. use app\common\model\book\Order as OrderModel;
  22. use app\common\model\wxapp\Setting as WxappSettingModel;
  23. use app\common\service\Order as OrderService;
  24. use app\api\service\book\PaySuccess as OrderPaySuccesService;
  25. use app\api\service\Order\source\Factory as OrderSourceFactory;
  26. use app\common\enum\book\order\PayStatus as PayStatusEnum;
  27. use app\common\enum\book\order\PayType as OrderPayTypeEnum;
  28. use app\common\exception\BaseException;
  29. /**
  30. * 用户报名订单模型
  31. * Class Order
  32. * @package app\api\model\book
  33. */
  34. class Order extends OrderModel
  35. {
  36. protected $globalScope = [''];
  37. /**
  38. * 隐藏字段
  39. * @var array
  40. */
  41. protected $hidden = [
  42. 'transaction_id',
  43. 'create_time',
  44. 'update_time',
  45. ];
  46. /**
  47. * 获取订单列表
  48. * @return \think\Paginator
  49. * @throws BaseException
  50. * @throws \think\db\exception\DbException
  51. */
  52. public function getList()
  53. {
  54. // 当前用户ID
  55. $userId = UserService::getCurrentLoginUserId();
  56. // 获取列表数据
  57. return $this->where('user_id', '=', $userId)
  58. ->where('status', '>=', PayStatusEnum::PENDING)
  59. ->order(['create_time' => 'desc'])
  60. ->paginate(15);
  61. }
  62. /**
  63. * 获取订单详情(待付款状态)
  64. * @param $orderNo
  65. * @return array|null|static
  66. */
  67. public static function getPayDetail(string $orderNo)
  68. {
  69. return self::detail(['order_no' => $orderNo, 'status' => PayStatusEnum::PENDING]);
  70. }
  71. /**
  72. * 获取用户报名订单详情(含关联数据)
  73. * @param int $orderId 订单ID
  74. * @return Order|array|null
  75. * @throws BaseException
  76. * @throws \think\db\exception\DataNotFoundException
  77. * @throws \think\db\exception\DbException
  78. * @throws \think\db\exception\ModelNotFoundException
  79. */
  80. public static function getUserOrderDetail(int $orderId)
  81. {
  82. // 查询订单记录
  83. $order = static::getDetail($orderId);
  84. // 该订单是否允许申请售后
  85. $order['isAllowRefund'] = 1;
  86. return $order;
  87. }
  88. /**
  89. * 获取用户报名订单详情(仅订单记录)
  90. * @param int $orderId
  91. * @param array $with
  92. * @return Order|array|null
  93. * @throws BaseException
  94. */
  95. public static function getDetail(int $orderId, array $with = [])
  96. {
  97. // 查询订单记录
  98. $order = static::detail($orderId, $with);
  99. empty($order) && throwError('订单不存在');
  100. return $order;
  101. }
  102. /**
  103. * 创建报名订单
  104. * @param array|null $params
  105. * @return bool|int
  106. * @throws BaseException
  107. * @throws \think\db\exception\DataNotFoundException
  108. * @throws \think\db\exception\DbException
  109. * @throws \think\db\exception\ModelNotFoundException
  110. */
  111. public function createOrder(array $params)
  112. {
  113. $teacherUserId = isset($params['user_id'])? intval($params['user_id']) : 0;
  114. $teacher = User::detail($teacherUserId,['info']);
  115. $teacherInfo = isset($teacher['info'])? $teacher['info'] : [];
  116. if(empty($teacherUserId) || empty($teacher)){
  117. $this->error = '报名咨询老师参数错误';
  118. return false;
  119. }
  120. $schoolId = isset($params['school_id'])? intval($params['school_id']) : 0;
  121. $specialityId = isset($params['speciality_id'])? intval($params['speciality_id']) : 0;
  122. if($schoolId<=0 || $specialityId <= 0){
  123. $this->error = '报名学校或报名专业参数错误';
  124. return false;
  125. }
  126. $school = School::detail($schoolId);
  127. if(empty($school)){
  128. $this->error = '报名学校不存在';
  129. return false;
  130. }
  131. // 表单参数验证
  132. $realName = isset($params['real_name'])? $params['real_name'] : '';
  133. if(empty($realName)){
  134. $this->error = '请填写报名用户真实姓名';
  135. return false;
  136. }
  137. $gender = isset($params['gender'])? intval($params['gender']) : 0;
  138. if($gender<=0){
  139. $this->error = '请选择报名用户性别';
  140. return false;
  141. }
  142. $schoolName = isset($params['school_name'])? $params['school_name'] : '';
  143. if(empty($schoolName)){
  144. $this->error = '请填写报名用户现读学校';
  145. return false;
  146. }
  147. $realName = isset($params['real_name'])? $params['real_name'] : '';
  148. if(empty($realName)){
  149. $this->error = '请填写报名用户真实姓名';
  150. return false;
  151. }
  152. $receiptName = isset($params['receipt_name'])? $params['receipt_name'] : '';
  153. if(empty($receiptName)){
  154. $this->error = '请填写收货人姓名';
  155. return false;
  156. }
  157. $receiptMobile = isset($params['receipt_mobile'])? $params['receipt_mobile'] : '';
  158. if(empty($receiptMobile)){
  159. $this->error = '请填写收货人联系电话';
  160. return false;
  161. }
  162. $receiptAddress = isset($params['receipt_address'])? $params['receipt_address'] : '';
  163. if(empty($receiptAddress)){
  164. $this->error = '请填写收货人地址';
  165. return false;
  166. }
  167. $trade = \app\store\model\Setting::getItem('trade');
  168. $price = isset($trade['books']['book_cost'])? floatval($trade['books']['book_cost']) : 0;
  169. if($price<=0){
  170. $this->error = '请先后台设置报名费用';
  171. return false;
  172. }
  173. // 专业参数验证
  174. $speciality = SchoolSpeciality::detail($specialityId);
  175. if(empty($speciality)){
  176. $this->error = '报名专业不存在';
  177. return false;
  178. }
  179. if($speciality['school_id'] != $schoolId){
  180. $this->error = '报名专业和学校不匹配';
  181. return false;
  182. }
  183. // 报名人数验证
  184. $bookNum = SpecialityBook::getBooks($specialityId);
  185. $remainBookNum = max(0, $speciality['recruit_num'] - $bookNum);
  186. if($remainBookNum <= 0){
  187. $this->error = '该专业报名人数已满';
  188. return false;
  189. }
  190. // 订单数据
  191. $fields = isset($params['fields'])? $params['fields'] : [];
  192. $fields = $fields && is_array($fields)? json_encode($fields) : '';
  193. $order = [
  194. 'book_user_id' => UserService::getCurrentLoginUserId(),
  195. 'user_id' => $teacherUserId,
  196. 'agent_id' => isset($teacherInfo['agent_id'])? $teacherInfo['agent_id'] : 0,
  197. 'order_no' => 'BK' . OrderService::createOrderNo(),
  198. 'real_name' => $realName,
  199. 'gender' => $gender,
  200. 'age' => isset($params['age'])? $params['age'] : 0,
  201. 'school_name' => $schoolName,
  202. 'school_id' => $schoolId,
  203. 'speciality_id' => $specialityId,
  204. 'price' => floatval($price),
  205. 'total_price' => floatval($price),
  206. 'receipt_name' => $receiptName,
  207. 'receipt_mobile' => $receiptMobile,
  208. 'receipt_address' => $receiptAddress,
  209. 'fields' => $fields,
  210. 'create_time' => time(),
  211. 'update_time' => time(),
  212. 'status' => 1,
  213. ];
  214. return $this->save($order);
  215. }
  216. /**
  217. * 验证支付订单
  218. * @param $order
  219. * @return bool
  220. * @throws \think\db\exception\DataNotFoundException
  221. * @throws \think\db\exception\DbException
  222. * @throws \think\db\exception\ModelNotFoundException
  223. */
  224. public function checkPay($order)
  225. {
  226. $orderId = isset($order['order_id'])? $order['order_id'] : 0;
  227. if($orderId<=0){
  228. return false;
  229. }
  230. $orderStatus = isset($order['status'])? $order['status'] : 0;
  231. if($orderStatus == 3){
  232. $this->error = '订单已支付';
  233. return false;
  234. }
  235. if($orderStatus != 2){
  236. $this->error = '订单未确认或状态不可支付';
  237. return false;
  238. }
  239. $specialityId = isset($order['speciality_id'])? intval($order['speciality_id']) : 0;
  240. // 专业参数验证
  241. $speciality = SchoolSpeciality::detail($specialityId);
  242. if(empty($speciality)){
  243. $this->error = '报名专业不存在';
  244. return false;
  245. }
  246. // 报名人数验证
  247. $bookNum = SpecialityBook::getBooks($specialityId);
  248. $remainBookNum = max(0, $speciality['recruit_num'] - $bookNum);
  249. if($remainBookNum <= 0){
  250. $this->error = '该专业报名人数已满';
  251. return false;
  252. }
  253. // 已经报名次数
  254. $trade = \app\store\model\Setting::getItem('books');
  255. $bookLimit = isset($trade['books']['book_limit'])? intval($trade['books']['book_limit']) : 0;
  256. $bookLimit = $bookLimit? $bookLimit : 3;
  257. if(SpecialityBook::getUserBooks($orderId) >= $bookLimit){
  258. $this->error = "您已经报名了{$bookLimit}次,不能再报名";
  259. return false;
  260. }
  261. return true;
  262. }
  263. /**
  264. * 确认报名订单
  265. * @param $orderId
  266. * @param $noticeImg
  267. * @return bool
  268. * @throws BaseException
  269. * @throws \think\db\exception\DataNotFoundException
  270. * @throws \think\db\exception\DbException
  271. * @throws \think\db\exception\ModelNotFoundException
  272. */
  273. public function confirmOrder($orderId, $noticeImg)
  274. {
  275. if(empty($orderId)){
  276. $this->error = '订单参数错误';
  277. return false;
  278. }
  279. if(empty($noticeImg)){
  280. $this->error = '请上传录取通知书';
  281. return false;
  282. }
  283. $model = new Order();
  284. $model = $model::getUserOrderDetail($orderId);
  285. if(!$model){
  286. $this->error = '报名订单不存在';
  287. return false;
  288. }
  289. // 订单所属老师才何以设置
  290. $userInfo = UserService::getCurrentLoginUser(true);
  291. if($userInfo['user_id'] != $model['user_id']){
  292. $this->error = '订单无权操作';
  293. return false;
  294. }
  295. if($model['status'] != 1){
  296. $this->error = '订单已确认或状态不可操作';
  297. return false;
  298. }
  299. return $model->save(['status'=> 2,'notice_img'=> $noticeImg]);
  300. }
  301. /**
  302. * 订单发货设置
  303. * @param int $orderId 订单ID
  304. * @param $params 发货参数:快递公司ID、快递公司名称、快递单号
  305. * @return bool
  306. * @throws BaseException
  307. * @throws \think\db\exception\DataNotFoundException
  308. * @throws \think\db\exception\DbException
  309. * @throws \think\db\exception\ModelNotFoundException
  310. */
  311. public function setDelivery(int $orderId, $params)
  312. {
  313. $data['express_id'] = isset($params['express_id'])? $params['express_id'] : '';
  314. $data['express_company'] = isset($params['express_company'])? $params['express_company'] : '';
  315. $data['express_no'] = isset($params['express_no'])? $params['express_no'] : '';
  316. if(empty($orderId)){
  317. $this->error = '订单参数错误';
  318. return false;
  319. }
  320. if(empty($data['express_id'])){
  321. $this->error = '请选择快递公司';
  322. return false;
  323. }
  324. if(empty($data['express_company'])){
  325. $this->error = '请选择快递公司';
  326. return false;
  327. }
  328. if(empty($data['express_no'])){
  329. $this->error = '请填写快递单号';
  330. return false;
  331. }
  332. $model = new Order();
  333. $model = $model::getUserOrderDetail($orderId);
  334. if(!$model){
  335. $this->error = '报名订单不存在';
  336. return false;
  337. }
  338. // 订单所属老师才何以设置对应发货信息
  339. $userInfo = UserService::getCurrentLoginUser(true);
  340. if($userInfo['user_id'] != $model['user_id']){
  341. $this->error = '订单无权操作';
  342. return false;
  343. }
  344. if($model['status'] != 3){
  345. $this->error = '订单已发货或状态不可操作';
  346. return false;
  347. }
  348. $data['status'] = 4;
  349. $data['delivery_time'] = time();
  350. return $model->save($data);
  351. }
  352. /**
  353. * 订单确认收货
  354. * @param $orderId
  355. * @return false
  356. * @throws BaseException
  357. * @throws \cores\exception\BaseException
  358. * @throws \think\db\exception\DataNotFoundException
  359. * @throws \think\db\exception\DbException
  360. * @throws \think\db\exception\ModelNotFoundException
  361. */
  362. public function receiptOrder($orderId)
  363. {
  364. if(empty($orderId)){
  365. $this->error = '订单参数错误';
  366. return false;
  367. }
  368. $model = new Order();
  369. $model = $model::getUserOrderDetail($orderId);
  370. if(!$model){
  371. $this->error = '报名订单不存在';
  372. return false;
  373. }
  374. $userInfo = UserService::getCurrentLoginUser(true);
  375. if($userInfo['user_id'] != $model['book_user_id']){
  376. $this->error = '订单无权操作';
  377. return false;
  378. }
  379. if($model['refund_status'] != 4){
  380. $this->error = '订单已收货或状态不可操作';
  381. return false;
  382. }
  383. // 直接收货完成
  384. $data['status'] = 6;
  385. $data['receipt_time'] = time();
  386. return $model->save($data);
  387. }
  388. /**
  389. * 设置订单为可退款
  390. * @param int $orderId
  391. * @return bool
  392. * @throws BaseException
  393. * @throws \think\db\exception\DataNotFoundException
  394. * @throws \think\db\exception\DbException
  395. * @throws \think\db\exception\ModelNotFoundException
  396. */
  397. public function setRefund(int $orderId)
  398. {
  399. if(empty($orderId)){
  400. $this->error = '订单参数错误';
  401. return false;
  402. }
  403. $model = new Order();
  404. $model = $model::getUserOrderDetail($orderId);
  405. if(!$model){
  406. $this->error = '报名订单不存在';
  407. return false;
  408. }
  409. // 订单所属老师才可以操作
  410. $userInfo = UserService::getCurrentLoginUser(true);
  411. if($userInfo['user_id'] != $model['user_id']){
  412. $this->error = '订单无权操作';
  413. return false;
  414. }
  415. if($model['refund_status'] != 1 || $model['status'] <=1){
  416. $this->error = '订单设置为可退款或状态不可操作';
  417. return false;
  418. }
  419. return $model->save(['refund_status'=> 2]);
  420. }
  421. /**
  422. * 订单申请退款
  423. * @param $orderId
  424. * @param $refundResult 退款原因
  425. * @return bool
  426. * @throws BaseException
  427. * @throws \think\db\exception\DataNotFoundException
  428. * @throws \think\db\exception\DbException
  429. * @throws \think\db\exception\ModelNotFoundException
  430. */
  431. public function refundOrder($orderId, $refundResult)
  432. {
  433. if(empty($orderId)){
  434. $this->error = '订单参数错误';
  435. return false;
  436. }
  437. if(empty($refundResult)){
  438. $this->error = '请填写退款原因';
  439. return false;
  440. }
  441. $model = new Order();
  442. $model = $model::getUserOrderDetail($orderId);
  443. if(!$model){
  444. $this->error = '报名订单不存在';
  445. return false;
  446. }
  447. // 订单所属用户才可以操作
  448. $userInfo = UserService::getCurrentLoginUser(true);
  449. if($userInfo['user_id'] != $model['book_user_id']){
  450. $this->error = '订单无权操作';
  451. return false;
  452. }
  453. if($model['refund_status'] != 2 || $model['status'] <=1){
  454. $this->error = '订单已申请退款或状态不可操作';
  455. return false;
  456. }
  457. return $model->save(['refund_status'=> 3,'refund_result'=> $refundResult]);
  458. }
  459. /**
  460. * 订单退款确认
  461. * @param $orderId
  462. * @param $refundResult 退款凭证
  463. * @return bool
  464. * @throws BaseException
  465. * @throws \think\db\exception\DataNotFoundException
  466. * @throws \think\db\exception\DbException
  467. * @throws \think\db\exception\ModelNotFoundException
  468. */
  469. public function refundConfirm($orderId, $refundImg)
  470. {
  471. if(empty($orderId)){
  472. $this->error = '订单参数错误';
  473. return false;
  474. }
  475. if(empty($refundResult)){
  476. $this->error = '请填写退款原因';
  477. return false;
  478. }
  479. $model = new Order();
  480. $model = $model::getUserOrderDetail($orderId);
  481. if(!$model){
  482. $this->error = '报名订单不存在';
  483. return false;
  484. }
  485. // 订单所属老师才可以处理
  486. $userInfo = UserService::getCurrentLoginUser(true);
  487. if($userInfo['user_id'] != $model['user_id']){
  488. $this->error = '订单无权操作';
  489. return false;
  490. }
  491. if($model['refund_status'] != 3 || $model['status'] <= 0){
  492. $this->error = '订单已退款或状态不可操作';
  493. return false;
  494. }
  495. // 调起退款
  496. if(!$this->refund($model)){
  497. $this->error = '退款处理失败';
  498. return false;
  499. }
  500. return $model->save(['refund_status'=> 4,'refund_img'=> $refundImg,'status'=> -2]);
  501. }
  502. public function cancel()
  503. {
  504. }
  505. /**
  506. * 退款调起
  507. * @param $order
  508. * @param int $money
  509. * @return bool
  510. * @throws BaseException
  511. * @throws \cores\exception\BaseException
  512. * @throws \think\db\exception\DataNotFoundException
  513. * @throws \think\db\exception\DbException
  514. * @throws \think\db\exception\ModelNotFoundException
  515. */
  516. private function refund($order, $money=0)
  517. {
  518. $wxConfig = WxappSettingModel::getWxappConfig(getStoreId());
  519. $WxPay = new WxPay($wxConfig, getStoreId());
  520. $money = $money? $money : $order['pay_price'];
  521. return $WxPay->refund($order['transaction_id'], $order['pay_price'], $money);
  522. }
  523. }