OrderRevoke.php 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486
  1. <?php
  2. /**
  3. * 重庆赤晓店信息科技有限公司
  4. * https://www.chixiaodian.com
  5. * Copyright (c) 2023 赤店商城 All rights reserved.
  6. */
  7. namespace app\utils;
  8. use app\models\AccountLog;
  9. use app\models\Goods;
  10. use app\models\Order;
  11. use app\models\OrderDetail;
  12. use app\models\OrderGoodsCancel;
  13. use app\models\OrderUnion;
  14. use app\models\SaaSLeaguePriceLog;
  15. use app\models\SaasUser;
  16. use app\models\SeckillActivityGoods;
  17. use app\models\SeckillActivityOrderLog;
  18. use app\models\User;
  19. use app\models\UserCoupon;
  20. use app\models\SaasCoupon;
  21. use app\models\VerifyCardSale;
  22. use Yii;
  23. use app\models\UserPayMonth;
  24. use app\models\OrderTransit;
  25. use app\models\StoreCloud;
  26. use app\constants\OptionSetting;
  27. class OrderRevoke
  28. {
  29. public $order;
  30. /**
  31. * 订单类型 0 普通订单
  32. */
  33. public $type = 0;
  34. /**
  35. * 同意订单取消操作
  36. */
  37. public static function orderRevoke($order)
  38. {
  39. $t = Yii::$app->db->beginTransaction();
  40. $order->trade_status = Order::ORDER_FLOW_CANCEL;
  41. // $order->is_delete = Order::IS_DELETE_TRUE;
  42. if ($order->save()) {
  43. //查看是否存在转单数据
  44. $orderTransitInfo = OrderTransit::find()->where(['order_id'=>$order->attributes['id'],"is_delete"=>0])->all();
  45. if($orderTransitInfo){
  46. $cloudInfo = StoreCloud::find()->where(['store_id'=>$order->store_id,"is_delete"=>0])->one();
  47. if($cloudInfo) {
  48. foreach ($orderTransitInfo as $value) {
  49. $mch_order_cancel_url = "/cloud/mch/mchOrderCancel";
  50. $mch_order_cancel_data = [];
  51. $mch_order_cancel_data['access_token'] = $cloudInfo->attributes['access_token'];
  52. $mch_order_cancel_data['order_id'] = $value->attributes['cloud_order_id'];
  53. $domain = (new OptionSetting)->getCloudDomainName();
  54. cloud_post($domain . $mch_order_cancel_url, $mch_order_cancel_data);
  55. $value->status = -1;
  56. $value->save();
  57. }
  58. }
  59. }
  60. $orderRevoke = new OrderRevoke();
  61. $orderRevoke->order = $order;
  62. $orderRevoke->type = 0;
  63. // 恢复商品库存
  64. $numRes = $orderRevoke->backGoodsNum();
  65. // 返回优惠券
  66. if ($order->is_pay == 0) {
  67. $couponRes = $orderRevoke->backUserCoupon();
  68. }else{
  69. //积分兑换订单不使用优惠券
  70. if($order->order_type ==7){
  71. $couponRes = true;
  72. }
  73. }
  74. // 订单退款
  75. if ($order->is_pay == 1) {
  76. //新积分商品返还积分
  77. $new_integralRes = $orderRevoke->backNewUserIntegral();
  78. // 返还积分
  79. $integralRes = $orderRevoke->backUserIntegral();
  80. if ($order->pay_type == 3) {
  81. if (!$orderRevoke->OrderRefund()) {
  82. $t->rollBack();
  83. return [
  84. 'code' => 0,
  85. 'msg' => '退款失败,取消失败'
  86. ];
  87. }
  88. }
  89. if ($order->pay_type == 1) {
  90. $refundFee = $order->pay_price;
  91. $res = $orderRevoke->orderWxRefund($refundFee);
  92. if ($res !== true) {
  93. $t->rollBack();
  94. return $res;
  95. }
  96. }
  97. if ($order->pay_type == Order::PAY_TYPE_MONTH) {
  98. $refundFee = $order->pay_price;
  99. $res = UserPayMonth::refund($order->user_id, $order, $refundFee);
  100. if ($res !== true) {
  101. $t->rollBack();
  102. return $res;
  103. }
  104. }
  105. // 预约商品增加库存
  106. BookOrderNum::bookNumAdd($order);
  107. // 取消下单时送的核销卡
  108. VerifyCardSale::cancelCard($order);
  109. } else {
  110. $t->commit();
  111. return [
  112. 'code' => 0,
  113. 'msg' => '订单已取消'
  114. ];
  115. }
  116. if (!$numRes || !$couponRes || !$integralRes || !$new_integralRes) {
  117. $t->rollBack();
  118. return [
  119. 'code' => 1,
  120. 'msg' => '订单取消失败'
  121. ];
  122. }
  123. // 订单打印
  124. if ((int)$order->md_id === -1 || (int)$order->md_id === 0 || !isset($order->md_id)) {
  125. $order->md_id = 0;
  126. }
  127. $printer_order = new PrintOrder($order->store_id, $order->id, 'pay', 0, $order->md_id, 0, $order['mch_id']);
  128. $printer_order->is_refund = true;
  129. $printer_order->print_order();
  130. $t->commit();
  131. $check = SaaSLeaguePriceLog::findOne(['order_id' => $order->id,'type' => 4]);
  132. if($order->take_price > 0 && $check){
  133. $user = User::findOne($order->user_id);
  134. $saas_user = SaasUser::findOne(['mobile' => $user->binding]);
  135. if($saas_user){
  136. $take_price = $order->take_price;
  137. $before = $saas_user->league_price;
  138. $saas_user->updateCounters(['league_price' => floatval($take_price)]);
  139. \app\models\SaaSLeaguePriceLog::setLeaguePriceLog(
  140. $order->store_id,
  141. $saas_user->id,
  142. $take_price,
  143. $before,
  144. \app\models\SaaSLeaguePriceLog::TYPE_CANCEL,
  145. \app\models\SaaSLeaguePriceLog::SEND_TYPE,
  146. \app\models\SaaSLeaguePriceLog::ROLE_USER,
  147. $order->id
  148. );
  149. }
  150. }
  151. return [
  152. 'code' => 0,
  153. 'msg' => '订单已取消'
  154. ];
  155. } else {
  156. $t->commit();
  157. return [
  158. 'code' => 1,
  159. 'msg' => '订单取消失败' . array_shift($order->getFirstErrors()),
  160. ];
  161. }
  162. }
  163. /**
  164. * 同意订单取消操作
  165. */
  166. public static function allianceOrderRevoke($order)
  167. {
  168. $t = Yii::$app->db->beginTransaction();
  169. $order->trade_status = Order::ORDER_FLOW_CANCEL;
  170. // $order->is_delete = Order::IS_DELETE_TRUE;
  171. if ($order->save()) {
  172. $orderRevoke = new OrderRevoke();
  173. $orderRevoke->order = $order;
  174. $orderRevoke->type = 0;
  175. // 恢复商品库存
  176. $numRes = $orderRevoke->backGoodsNum();
  177. $couponRes = true;
  178. // 返回优惠券
  179. if ($order->is_pay == 0) {
  180. $couponRes = $orderRevoke->backSaasCoupon();
  181. }
  182. // // 返还积分
  183. //$integralRes = $orderRevoke->backUserIntegral();
  184. // 订单退款
  185. if ($order->is_pay == 1) {
  186. if ($order->pay_type == 3) {
  187. if (!$orderRevoke->OrderRefund()) {
  188. $t->rollBack();
  189. return [
  190. 'code' => 0,
  191. 'msg' => '退款失败,取消失败'
  192. ];
  193. }
  194. }
  195. if ($order->pay_type == 1) {
  196. $refundFee = $order->pay_price;
  197. $refund_res = Refund::refund($order, $order->order_union_id ? OrderNo::ORDER_UNION : '',$order->order_no, $order->pay_price);
  198. // $res = $orderRevoke->orderWxRefund($refundFee);
  199. if ($refund_res !== true) {
  200. $t->rollBack();
  201. return $refund_res;
  202. }
  203. }
  204. // 预约商品增加库存
  205. BookOrderNum::bookNumAdd($order);
  206. }
  207. if (!$numRes || !$couponRes) {
  208. $t->rollBack();
  209. return [
  210. 'code' => 1,
  211. 'msg' => '订单取消失败'
  212. ];
  213. }
  214. // 订单打印
  215. if ((int)$order->md_id === -1 || (int)$order->md_id === 0 || !isset($order->md_id)) {
  216. $order->md_id = 0;
  217. }
  218. $printer_order = new PrintOrder($order->store_id, $order->id, 'pay', 0, $order->md_id, 0, $order['mch_id']);
  219. $printer_order->print_order();
  220. $t->commit();
  221. return [
  222. 'code' => 0,
  223. 'msg' => '订单已取消'
  224. ];
  225. } else {
  226. $t->commit();
  227. return [
  228. 'code' => 1,
  229. 'msg' => '订单取消失败'
  230. ];
  231. }
  232. }
  233. /**
  234. * 恢复商品库存
  235. */
  236. public function backGoodsNum($order_goods_cancel_id = 0)
  237. {
  238. $order = $this->order;
  239. $orderGoodsCancel = null;
  240. $order_detail_list = [];
  241. if ($order_goods_cancel_id) {
  242. $orderGoodsCancel = OrderGoodsCancel::findOne($order_goods_cancel_id);
  243. }
  244. if ($this->type == 0) {
  245. $query = OrderDetail::find()->where(['order_id' => $order->id, 'is_delete' => 0]);
  246. if ($orderGoodsCancel) {
  247. $query->andWhere(['id' => $orderGoodsCancel->order_detail_id]);
  248. }
  249. $order_detail_list = $query->all();
  250. }
  251. //库存恢复
  252. foreach ($order_detail_list as $order_detail) {
  253. if ($orderGoodsCancel) {
  254. $order_detail->num = $orderGoodsCancel->num;
  255. }
  256. if($this->type == 0) {
  257. $goods = Goods::findOne($order_detail->goods_id);
  258. }
  259. $attr_id_list = [];
  260. foreach (json_decode($order_detail->attr) as $item) {
  261. array_push($attr_id_list, $item->attr_id);
  262. }
  263. $goods->numAdd($attr_id_list, $order_detail->num);
  264. }
  265. // 这里判断是不是秒杀订单 如果是秒杀订单的话要退秒杀商品的库存
  266. if($order->seckill_order_id > 0){
  267. $seckillActivityOrderLog = SeckillActivityOrderLog::find()->where(['id' => $order->seckill_order_id])->one();
  268. $seckillActivityGoods = SeckillActivityGoods::find()->where(['id' =>$seckillActivityOrderLog->activity_goods_id ,'goods_id' => $seckillActivityOrderLog->goods_id,'store_id' => $order->store_id,'is_delete' => 0])->one();
  269. // 这里循环的还是订单商品信息表
  270. foreach($order_detail_list as $order_detail){
  271. $attr_id_list = [];
  272. foreach (json_decode($order_detail->attr) as $item) {
  273. array_push($attr_id_list, $item->attr_id);
  274. }
  275. // 这里执行退库存的是秒杀商品的库存
  276. $seckillActivityGoods->numAdd($attr_id_list,$order_detail->num);
  277. }
  278. // 减去销量
  279. $seckillActivityGoods->sale_num -= array_sum(array_column($order_detail_list,'num'));
  280. $seckillActivityGoods->save();
  281. // 恢复库存之后 将秒杀订单修改未删除状态
  282. $seckillActivityOrderLog->is_delete = 1;
  283. $seckillActivityOrderLog->save();
  284. }
  285. return true;
  286. }
  287. /**
  288. * 返还优惠券
  289. */
  290. public function backUserCoupon()
  291. {
  292. UserCoupon::updateAll(['is_use' => 0], ['id' => $this->order->user_coupon_id]);
  293. return true;
  294. }
  295. /**
  296. * 返还优惠券
  297. */
  298. public function backSaasCoupon()
  299. {
  300. SaasCoupon::updateAll(['is_use' => 0], ['id' => $this->order->user_coupon_id]);
  301. return true;
  302. }
  303. /**
  304. * 返还积分
  305. */
  306. public function backUserIntegral()
  307. {
  308. $order = $this->order;
  309. $integral = json_decode($order->integral)->forehead_integral;
  310. if ($integral <= 0) {
  311. return true;
  312. }
  313. $tt = Yii::$app->db->beginTransaction();
  314. $log = AccountLog::saveLog($order->user_id, $integral, AccountLog::TYPE_INTEGRAL, AccountLog::LOG_TYPE_INCOME, AccountLog::TYPE_PLATFORM_REFUND_ORDER, $order->id, "商城订单退积分,订单号:{$order->order_no}");
  315. if ($log) {
  316. $tt->commit();
  317. return true;
  318. } else {
  319. $tt->rollBack();
  320. return false;
  321. }
  322. }
  323. /**
  324. * 购买积分商品返还积分
  325. */
  326. public function backNewUserIntegral()
  327. {
  328. $order = $this->order;
  329. $integral = $order->integral_price;
  330. if ($integral <= 0) {
  331. return true;
  332. }
  333. $tt = Yii::$app->db->beginTransaction();
  334. $log = AccountLog::saveLog($order->user_id, $integral, AccountLog::TYPE_INTEGRAL, AccountLog::LOG_TYPE_INCOME, AccountLog::TYPE_PLATFORM_REFUND_ORDER, $order->id, "商城订单退积分,订单号:{$order->order_no}");
  335. if ($log) {
  336. $tt->commit();
  337. return true;
  338. } else {
  339. $tt->rollBack();
  340. return false;
  341. }
  342. }
  343. /**
  344. * 订单退款余额
  345. */
  346. public function OrderRefund($refundFee = 0)
  347. {
  348. $order = $this->order;
  349. $refundFee = $refundFee > 0 ? $refundFee : $order->pay_price;
  350. if ($order->is_pay == 1 && $order->pay_type == 3) {
  351. $tt = Yii::$app->db->beginTransaction();
  352. $log = AccountLog::saveLog($order->user_id, $refundFee, AccountLog::TYPE_BALANCE, AccountLog::LOG_TYPE_INCOME, AccountLog::TYPE_PLATFORM_REFUND_ORDER, $order->id, "商城订单退款,订单号:{$order->order_no}");
  353. if ($log) {
  354. $tt->commit();
  355. return true;
  356. }else {
  357. $tt->rollBack();
  358. return false;
  359. }
  360. }else {
  361. return true;
  362. }
  363. }
  364. /**
  365. * @param $refundFee integer 退款金额
  366. * @return array|bool
  367. */
  368. public function orderWxRefund($refundFee, $refund_account = null)
  369. {
  370. $order = $this->order;
  371. if (isset($order->pay_price)) {
  372. $payPrice = $order->pay_price;
  373. } else {
  374. // 联合订单支付的总额
  375. $payPrice = $order->price;
  376. }
  377. $data = [
  378. 'out_trade_no' => $order->order_no,
  379. 'out_refund_no' => $order->order_no,
  380. 'total_fee' => $payPrice * 100,
  381. 'refund_fee' => $refundFee * 100,
  382. ];
  383. if (isset($order->order_union_id) && $order->order_union_id != 0) {
  384. // 多商户合并订单退款
  385. $orderUnion = OrderUnion::findOne($order->order_union_id);
  386. if (!$orderUnion) {
  387. return [
  388. 'code' => 1,
  389. 'msg' => '订单操作失败,合并支付订单不存在。',
  390. ];
  391. }
  392. $data['out_trade_no'] = $orderUnion->order_no;
  393. $data['total_fee'] = $orderUnion->price * 100;
  394. }
  395. $config = [];
  396. if ($refund_account) {
  397. $config['refund_account'] = $refund_account;
  398. }
  399. $wechatPay = \Yii::$app->controller->wechatPay;
  400. $jssdk = $wechatPay->refund;
  401. $res = $jssdk
  402. ->byOutTradeNumber($data['out_trade_no'], $data['out_refund_no'], $data['total_fee'], $data['refund_fee'],$config);
  403. if (!$res) {
  404. return [
  405. 'code' => 1,
  406. 'msg' => '订单取消失败,退款失败,服务端配置出错',
  407. ];
  408. }
  409. if ($res['return_code'] != 'SUCCESS') {
  410. return [
  411. 'code' => 1,
  412. 'msg' => '订单取消失败,退款失败,' . $res['return_msg'],
  413. 'res' => $res,
  414. ];
  415. }
  416. if (isset($res['err_code']) && $res['err_code'] == 'NOTENOUGH' && !$refund_account) {
  417. // 交易未结算资金不足,请使用可用余额退款
  418. return $this->orderWxRefund($refundFee, 'REFUND_SOURCE_RECHARGE_FUNDS');
  419. }
  420. if ($res['result_code'] != 'SUCCESS') {
  421. /**
  422. * 检测退款失败原因
  423. */
  424. $refundQuery = $jssdk->queryByOutTradeNumber($order->order_no);
  425. if ($refundQuery['return_code'] != 'SUCCESS') {
  426. return [
  427. 'code' => 1,
  428. 'msg' => '订单取消失败,退款失败,' . $refundQuery['return_msg'],
  429. 'res' => $refundQuery,
  430. ];
  431. }
  432. if ($refundQuery['result_code'] == 'FAIL') {
  433. return [
  434. 'code' => 1,
  435. 'msg' => '订单取消失败,退款失败,' . $res['err_code_des'],
  436. 'res' => $res,
  437. ];
  438. }
  439. if ($refundQuery['result_code'] != 'SUCCESS') {
  440. return [
  441. 'code' => 1,
  442. 'msg' => '订单取消失败,退款失败,' . $refundQuery['err_code_des'],
  443. 'res' => $refundQuery,
  444. ];
  445. }
  446. if ($refundQuery['refund_status_0'] != 'SUCCESS') {
  447. return [
  448. 'code' => 1,
  449. 'msg' => '订单取消失败,退款失败,' . $refundQuery['err_code_des'],
  450. 'res' => $refundQuery,
  451. ];
  452. }
  453. }
  454. return true;
  455. }
  456. /**
  457. * 返还佣金
  458. */
  459. public function backUserShare()
  460. {
  461. }
  462. }