You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

308 lines
11 KiB

5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
  1. <?php
  2. namespace App\JsonRpc;
  3. use App\Commons\Log;
  4. use App\Constants\v3\ErrorCode;
  5. use App\Constants\v3\LogLabel;
  6. use App\Constants\v3\OrderState;
  7. use App\Exception\ErrorCodeException;
  8. use App\Model\v3\Order;
  9. use App\Model\v3\OrderGoods;
  10. use App\Model\v3\OrderMain;
  11. use App\Service\v3\Interfaces\OrderOnlineServiceInterface;
  12. use App\Service\v3\Interfaces\SeparateAccountsServiceInterface;
  13. use EasyWeChat\Factory;
  14. use EasyWeChat\Kernel\Exceptions\InvalidConfigException;
  15. use Hyperf\DbConnection\Db;
  16. use Hyperf\Guzzle\CoroutineHandler;
  17. use Hyperf\RpcServer\Annotation\RpcService;
  18. use Hyperf\Di\Annotation\Inject;
  19. use function AlibabaCloud\Client\json;
  20. /**
  21. * @RpcService(name="OrderService", protocol="jsonrpc-http", server="jsonrpc-http", publishTo="")
  22. */
  23. class OrderService implements OrderServiceInterface
  24. {
  25. /**
  26. * @Inject
  27. * @var Log
  28. */
  29. protected $log;
  30. /**
  31. * @Inject
  32. * @var OrderOnlineServiceInterface
  33. */
  34. protected $orderOnlineService;
  35. /**
  36. * @Inject
  37. * @var SeparateAccountsServiceInterface
  38. */
  39. protected $separateAccountsService;
  40. /**
  41. * 订单完成
  42. * @param $global_order_id
  43. * @param $user_id
  44. * @return array
  45. */
  46. public function onlineComplete($global_order_id, $user_id)
  47. {
  48. Db::beginTransaction();
  49. try {
  50. $this->orderOnlineService->doComplete($global_order_id, $user_id);
  51. $this->separateAccountsService->orderOnlineCompleted($global_order_id, $user_id);
  52. Db::commit();
  53. return [
  54. "status" => 200,
  55. "code" => 0,
  56. "result" => [],
  57. "message" => '处理成功'
  58. ];
  59. } catch (\Exception $e) {
  60. Db::rollBack();
  61. $this->log->event(LogLabel::ORDER_COMPLETE_LOG, ['jsonrpc_order_service_exception_onlineComplete' => $e->getMessage(), 'params' => json([$global_order_id, $user_id])]);
  62. return [
  63. "status" => 200,
  64. "code" => $e->getCode() ?? ErrorCode::ORDER_COMPLETE_FAIL,
  65. "result" => [],
  66. "message" => $e->getMessage()
  67. ];
  68. }
  69. }
  70. /**
  71. * 线上订单退款,整个订单退,这个是专门用于处理用户的申请退款的同意退款操作
  72. * @param $global_order_id
  73. * @param $user_id
  74. * @return array
  75. */
  76. public function onlineRefund($global_order_id, $user_id)
  77. {
  78. try {
  79. $this->orderOnlineService->doRefund($global_order_id, $user_id);
  80. return [
  81. "status" => 200,
  82. "code" => 0,
  83. "result" => [],
  84. "message" => '处理成功'
  85. ];
  86. } catch (\Exception $e) {
  87. return [
  88. "status" => 200,
  89. "code" => $e->getCode(),
  90. "result" => [],
  91. "message" => $e->getMessage()
  92. ];
  93. }
  94. }
  95. /**
  96. * 线上订单单笔退款,主要用于后台强行操作退单退款
  97. * 支持单商品、单店、整单
  98. * 按比例计算红包进行退款
  99. * 比如:两个子订单和子订单商品,分别是2元,98元,使用了10元优惠券
  100. * 退2元商品时,退款金额为
  101. * 红包 (2/(98+2)*10 = 0.2
  102. * 退款:2-0.2=1.8
  103. * @param $user_id *用户ID
  104. * @param $global_order_id *全局总订单ID
  105. * @param $order_child_id *主订单ID,
  106. * @param $order_goods_id *订单商品ID
  107. * @param $note
  108. * @throws InvalidConfigException
  109. */
  110. public function onlineSingleRefund($user_id, $note, $global_order_id, $order_child_id=null, $order_goods_id=null)
  111. {
  112. Db::beginTransaction();
  113. try {
  114. $params = [
  115. 'user_id' => $user_id,
  116. 'note' => $note,
  117. 'global_order_id' => $global_order_id,
  118. 'order_child_id' => $order_child_id,
  119. 'order_goods_id' => $order_goods_id,
  120. ];
  121. if (!$user_id || !$global_order_id || !$note) {
  122. $this->log->event(LogLabel::ORDER_REFUND_LOG, [
  123. 'jsonrpc_order_service_exception_onlineSingleRefund' => '参数不对',
  124. 'params' => json_encode($params)
  125. ]);
  126. throw new ErrorCodeException(ErrorCode::ORDER_REFUND_FAIL);
  127. }
  128. // 主订单
  129. $orderMain = OrderMain::query()
  130. ->where(['global_order_id' => $global_order_id, 'user_id' => $user_id])
  131. ->whereIn('state', OrderState::CAN_REFUND_DIRECT)
  132. ->first();
  133. if (is_null($orderMain)) {
  134. $this->log->event(LogLabel::ORDER_REFUND_LOG, [
  135. 'jsonrpc_order_service_exception_onlineSingleRefund' => '订单不存在',
  136. 'params' => json_encode($params)
  137. ]);
  138. throw new ErrorCodeException(ErrorCode::ORDER_REFUND_FAIL);
  139. }
  140. // 子订单
  141. $orderChild = null;
  142. if ($order_child_id) {
  143. $orderChild = Order::query()->where(['order_main_id' => $orderMain->global_order_id, 'id' => $order_child_id])->first();
  144. }
  145. // 订单商品
  146. $orderGoods = null;
  147. if ($order_goods_id) {
  148. if (!$order_child_id || is_null($orderChild)) {
  149. $this->log->event(LogLabel::ORDER_REFUND_LOG, [
  150. 'jsonrpc_order_service_exception_onlineSingleRefund' => '子订单参数异常[单品]',
  151. 'params' => json_encode($params)
  152. ]);
  153. throw new ErrorCodeException(ErrorCode::ORDER_REFUND_FAIL);
  154. }
  155. $orderGoods = OrderGoods::query()->where(['order_id' => $orderChild->id, 'id' => $order_goods_id])->first();
  156. if (is_null($orderGoods)) {
  157. $this->log->event(LogLabel::ORDER_REFUND_LOG, [
  158. 'jsonrpc_order_service_exception_onlineSingleRefund' => '订单商品参数异常[单品]',
  159. 'params' => json_encode($params)
  160. ]);
  161. throw new ErrorCodeException(ErrorCode::ORDER_REFUND_FAIL);
  162. }
  163. }
  164. var_dump('ordergoods', $orderGoods);
  165. $totalAmount = $orderMain->total_money; // 订单可退款金额,总订单金额不含配送费和服务费
  166. $preRefundAmount = 0; // 预退款金额
  167. $refundAmount = 0; // 实际退款金额
  168. $refundType = 'main'; // 退款类型, Main整单 Sub子单 Goods单品
  169. if ($orderGoods) { // 1. 如果订单商品存在则说明要退单品
  170. $preRefundAmount = bcmul($orderGoods->price, $orderGoods->number, 2);
  171. $refundType = 'goods';
  172. } elseif ($orderChild) { // 2. 否则如果存在子订单说明退子订单
  173. $preRefundAmount = $orderChild->money;
  174. $refundType = 'sub';
  175. } else { // 3. 再则如果存在主订单说明退主订单
  176. $preRefundAmount = $orderMain->total_money;
  177. $refundType = 'main';
  178. }
  179. // 占订单金额的比例
  180. $rate = bcdiv($preRefundAmount, $totalAmount, 6);
  181. // 计算优惠券所占金额
  182. $couponMoney = bcmul($orderMain->coupon_money, $rate, 6);
  183. // 计算本次退款实际退款金额
  184. $refundAmount = bcsub($preRefundAmount, $couponMoney, 2);
  185. if ($refundAmount <= 0) {
  186. $this->log->event(LogLabel::ORDER_REFUND_LOG, [
  187. 'jsonrpc_order_service_exception_onlineSingleRefund' => '没有可退款金额[实际退款金额]',
  188. 'params' => json_encode($params)
  189. ]);
  190. throw new ErrorCodeException(ErrorCode::ORDER_REFUND_FAIL);
  191. }
  192. var_dump($orderMain->money, $preRefundAmount, $refundAmount);
  193. // 开始退款
  194. $config = config('wxpay');
  195. $app = Factory::payment($config);
  196. $app['guzzle_handler'] = CoroutineHandler::class;
  197. $result = $app->refund->byOutTradeNumber(
  198. $orderMain->global_order_id,
  199. $orderMain->global_order_id,
  200. bcmul($orderMain->money, 100, 0),
  201. bcmul($refundAmount, 100, 0),
  202. [
  203. 'refund_desc' => '订单协商退款[' . $refundType . ']',
  204. 'notify_url' => config('wechat.notify_url.refund_single'),
  205. ]
  206. );
  207. if ($result['return_code'] == 'FAIL') {
  208. $this->log->event(LogLabel::ORDER_REFUND_LOG, [
  209. 'jsonrpc_order_service_exception_onlineSingleRefund' => $result['return_msg'] . '[微信退款失败]',
  210. 'params' => json_encode($result)
  211. ]);
  212. throw new ErrorCodeException(ErrorCode::ORDER_REFUND_FAIL);
  213. }
  214. if ($result['result_code'] == 'FAIL') {
  215. $this->log->event(LogLabel::ORDER_REFUND_LOG, [
  216. 'jsonrpc_order_service_exception_onlineSingleRefund' => $result['err_code_des'] . '[微信退款失败]' . $result['err_code'],
  217. 'params' => json_encode($result)
  218. ]);
  219. throw new ErrorCodeException(ErrorCode::ORDER_REFUND_FAIL);
  220. }
  221. // 退款申请成功,查询退款状态,此处暂时无法传递和记录单品退的信息,所以直接查询退款状态处理,不做回调
  222. $refundResult = $app->refund->queryByRefundId($result['refund_id']);
  223. $this->log->event(LogLabel::ORDER_REFUND_LOG, [
  224. 'jsonrpc_order_service_exception_onlineSingleRefund' => '[微信退款查询]',
  225. 'params' => json_encode($refundResult)
  226. ]);
  227. // 退款成功
  228. if (
  229. !($refundResult['return_code'] == 'SUCCESS'
  230. && isset($refundResult['result_code'])
  231. && $refundResult['result_code'] == 'SUCCESS')
  232. ) {
  233. throw new ErrorCodeException(ErrorCode::ORDER_REFUND_FAIL);
  234. }
  235. $currentTime = time();
  236. // 处理订单状态
  237. $orderMain->state = OrderState::REFUNDED;
  238. $orderMain->total_refund_note = $note;
  239. $orderMain->refund_time = $currentTime;
  240. $orderMain->save();
  241. if ($refundType == 'sub') {
  242. $orderChild->status = 3;
  243. $orderChild->refund_note = $note;
  244. $orderChild->refund_time = $currentTime;
  245. $orderChild->save();
  246. }
  247. if ($refundType == 'goods') {
  248. $orderGoods->status = 3;
  249. $orderGoods->refund_note = $note;
  250. $orderGoods->refund_time = $currentTime;
  251. $orderGoods->save();
  252. }
  253. Db::commit();
  254. return [
  255. "status" => 200,
  256. "code" => 0,
  257. "result" => [],
  258. "message" => '处理成功'
  259. ];
  260. } catch (\Exception $e) {
  261. Db::rollBack();
  262. return [
  263. "status" => 200,
  264. "code" => $e->getCode(),
  265. "result" => [],
  266. "message" => '[退款失败]'.$e->getMessage()
  267. ];
  268. }
  269. }
  270. }