model = new OrderReturn(); $this->validate = true; $this->validateClass = new ReturnValidate(); } public function select(Request $request): Response { [$where, $format, $limit, $field, $order] = $this->selectInput($request); $order = $request->get('order', 'desc'); $type = $request->get('type', ''); $field = $field ?? 'order_return_addtimes'; $where['order_return_category'] = '退款'; if ($type == 'today') { $where['order_return_addtimes'] = [ strtotime(date('Y-m-d') . ' 00:00:00'), strtotime(date('Y-m-d') . ' 23:59:59') ]; } $query = $this->doSelect($where, $field, $order); return $this->doFormat($query, $format, $limit); } protected function doSelect(array $where, string $field = null, string $order = 'desc') { $model = $this->model->with([ 'member' => function ($query) { $query->select('member_id', 'member_mobile'); }, 'cert' => function ($query) { $query->select('join_cert_member_id', 'member_cert_name'); }, 'order' => function ($query) { $query->select('order_id', 'order_name'); } ]); foreach ($where as $column => $value) { if (is_array($value)) { if ($value[0] === 'like' || $value[0] === 'not like') { $model = $model->where($column, $value[0], "%$value[1]%"); } elseif (in_array($value[0], ['>', '=', '<', '<>'])) { $model = $model->where($column, $value[0], $value[1]); } elseif ($value[0] == 'in' && !empty($value[1])) { $valArr = $value[1]; if (is_string($value[1])) { $valArr = explode(",", trim($value[1])); } $model = $model->whereIn($column, $valArr); } elseif ($value[0] == 'not in' && !empty($value[1])) { $valArr = $value[1]; if (is_string($value[1])) { $valArr = explode(",", trim($value[1])); } $model = $model->whereNotIn($column, $valArr); } elseif ($value[0] == 'null') { $model = $model->whereNull($column); } elseif ($value[0] == 'not null') { $model = $model->whereNotNull($column); } elseif ($value[0] !== '' || $value[1] !== '') { $model = $model->whereBetween($column, $value); } } else { $model = $model->where($column, $value); } } if ($field) { $model = $model->orderBy($field, $order); } return $model; } public function afterQuery($items) { foreach ($items as &$item) { if (!empty($item['order_return_apply_json']) && is_json($item['order_return_apply_json'])) { $json = json_decode($item['order_return_apply_json'], true); $item['order_return_apply_json'] = $json['apply'] ?? ''; } if (!empty($item['order_return_recharge_json']) && is_json($item['order_return_recharge_json'])) { $json = json_decode($item['order_return_recharge_json'], true); $item['order_return_recharge_json'] = $json['change'] ?? ''; } } return $items; } protected function updateInput(Request $request): array { $primary_key = $this->model->getKeyName(); $id = $request->post($primary_key); $data = $this->inputFilter($request->post()); $model = $this->model->find($id); if (!$model) { throw new BusinessException('记录不存在', 2); } if (empty($model->order_return_accept_datetimes) && $model->order_return_status == 'PENDING' && $data['order_return_status'] == 'DOING') { $data['order_return_accept_datetimes'] = date('Y-m-d H:i:s'); } if (!empty($data['order_return_apply_json'])) { $data['order_return_apply_json'] = json_encode(['apply' => $data['order_return_apply_json']]); } if (!empty($data['order_return_recharge_json'])) { $data['order_return_recharge_json'] = json_encode(['change' => $data['order_return_recharge_json']]); } unset($data[$primary_key]); return [$id, $data]; } /** * @Desc 订单商品详情 * @Author Gorden * @Date 2024/3/29 8:50 * * @param Request $request * @return Response */ public function sheet(Request $request) { $orderId = $request->get('order_id'); $orderSheet = OrderSheet::with([ 'member' => function ($query) { $query->select('member_id', 'member_mobile'); }, 'goods' => function ($query) { $query->select('goods_id', 'goods_name', 'goods_cover', 'goods_market_price', 'goods_sales_price', 'goods_classify'); }, 'memberInfo', 'cert', 'refund' ])->where('join_sheet_order_id', $orderId) ->get() ->toArray(); foreach ($orderSheet as &$item) { $item['goods']['goods_cover'] = getenv('STORAGE_DOMAIN') . $item['goods']['goods_cover']; if (!empty($item['goods']) && $item['goods']['goods_classify'] == 'PACKAGE') { $components = GoodsComponent::with('goods') ->where('join_component_master_goods_id', $item['goods']['goods_id']) ->select('join_component_master_goods_id', 'join_component_goods_id', 'goods_component_price', 'goods_component_price', 'goods_component_config_json') ->get() ->toArray(); $goodsArr = []; foreach ($components as $component) { $configJson = !empty($component['goods_component_config_json']) ? json_decode($component['goods_component_config_json'], true) : []; if (!empty($component['goods'])) { $goodsArr[] = [ 'goods_name' => $component['goods']['goods_name'], 'goods_cover' => getenv('STORAGE_DOMAIN') . $component['goods']['goods_cover'], 'nbr' => $configJson['nbr'] ?? 0, ]; } } $item['goods']['components'] = $goodsArr; } if (!empty($item['refund'])) { if (!empty($item['refund']['order_return_apply_json']) && is_json($item['refund']['order_return_apply_json'])) { $json = json_decode($item['refund']['order_return_apply_json'], true); $item['refund']['order_return_apply_json'] = $json['reason'] ?? ''; } if (!empty($item['refund']['order_return_recharge_json']) && is_json($item['refund']['order_return_recharge_json'])) { $json = json_decode($item['refund']['order_return_recharge_json'], true); $item['refund']['order_return_recharge_json'] = $json['change'] ?? ''; } } } $order = Order::where('order_id', $orderId)->first(); $express = OrderExpress::where('join_express_order_id', $orderId)->first(); $data = [ 'order' => $order, 'sheet' => $orderSheet, 'express' => $express ]; return json_success('', $data); } public function customRefund(Request $request) { $orderId = $request->post('order_id', ''); $amount = $request->post('refund_amount', 0); $password = $request->post('refund_password', ''); $remark = $request->post('refund_remark', ''); if (!$orderId || !$amount || !$password) { return json_fail('参数异常'); } if ($password != '123456') { return json_fail('支付密码错误'); } $order = Order::where('order_id', $orderId)->where('order_status_payment', 'SUCCESS')->first(); if (!$order) { return json_fail("订单异常"); } if ($amount > $order->order_amount_pay) { return json_fail("退款金额不能超过支付金额"); } $payDetail = PayDetail::where('join_pay_order_id', $order->order_groupby) ->where('pay_status', 'SUCCESS') ->whereIn('pay_category', ['GOODS', 'SERVICE', 'CHNMED', 'CHNNCD', 'MEALS', 'DISHES', 'VIP', 'PACKAGE']) ->get() ->toArray(); if (empty($payDetail)) { return json_fail("支付状态异常"); } $response = []; Db::beginTransaction(); try { // 主订单,退款作为优惠入库 $this->updateMainOrderByRefund($order, $amount, $remark); // return 表记录 $returnId = $this->createReturnRecord($order, $amount,$remark); // 组合支付,退到余额账户 $prepayid = ''; if (count($payDetail) > 1) { $prepayid = $order->join_order_member_id . '-CASH'; $this->refundToCash($order->join_order_member_id, $amount); $response = ['order_id' => $order->order_id, 'member_id' => $order->join_order_member_id]; } else if (count($payDetail) == 1) { $payDetail0 = $payDetail[0]; $payWay = explode('-', $payDetail0['pay_prepayid']); if ($payWay[0] == 'WXPAY') { $prepayid = 'WXPAY'; $response = $this->refundToWx($payDetail0, $returnId, $amount); } elseif ($payWay[0] == 'ALIPAY') { $prepayid = 'WXPAY'; $response = $this->refundToAlipay($payDetail0, $amount); } elseif (isset($payWay[1]) && $payWay[1] == 'CASH') { $prepayid = $order->join_order_member_id . '-CASH'; $this->refundToCash($order->join_order_member_id, $amount); $response = ['order_id' => $order->order_id, 'member_id' => $order->join_order_member_id]; } elseif (isset($payWay['1']) && $payWay[1] == 'CARD') { $prepayid = $order->join_order_member_id . '-CASH'; $this->refundToCard($order->join_order_member_id, $amount); $response = ['order_id' => $order->order_id, 'member_id' => $order->join_order_member_id]; } } // payDetail 表记录 $this->createReturnPayDetail($order, $prepayid, $amount, $response); Db::commit(); return json_success('success'); } catch (BusinessException $e) { Db::rollBack(); return json_fail($e->getMessage()); } catch (\Exception $e) { Db::rollBack(); return json_fail("退款失败"); } } /** * @Desc 退款到余额 * @Author Gorden * @Date 2024/8/20 11:54 * * @param $memberId * @param $amount * @return void * @throws BusinessException */ private function refundToCash($memberId, $amount) { $account = MemberAccount::where('join_account_member_id', $memberId)->where('member_account_classify', 'CASH')->first(); if (!$account) { throw new BusinessException("余额账户异常"); } $account->member_account_surplus = $account->member_account_surplus + $amount; $account->save(); } /** * @Desc 退款到储蓄卡 * @Author Gorden * @Date 2024/8/20 14:47 * * @param $memberId * @param $amount * @return void * @throws BusinessException */ private function refundToCard($cardNbr, $amount) { $account = MemberAccount::where('member_account_nbr', $cardNbr)->where('member_account_classify', 'CARD')->first(); if (!$account) { throw new BusinessException("储值卡账户异常"); } $account->member_account_surplus = $account->member_account_surplus + $amount; $account->save(); } /** * @Desc * @Author Gorden * @Date 2024/8/20 14:17 * * @param $params * @param $returnId * @param $amount * @return mixed * @throws BusinessException * @throws \Yansongda\Pay\Exceptions\GatewayException * @throws \Yansongda\Pay\Exceptions\InvalidArgumentException * @throws \Yansongda\Pay\Exceptions\InvalidSignException */ private function refundToWx($params, $returnId, $amount) { try { $data = [ 'type' => 'app', 'out_trade_no' => $params['join_pay_order_id'], 'out_refund_no' => $returnId, 'total_fee' => $params['pay_amount'] * 100, 'refund_fee' => $amount * 100, 'refund_desc' => '退款', ]; $res = Pay::wechat(config('payment.wxpay'))->refund($data); $resArray = json_decode($res, true); if (!$resArray['result_code'] == 'SUCCESS' || !$resArray['return_code'] == 'SUCCESS') { Log::channel('pay')->error('WXPAY_REFUND_FAIL', $resArray); throw new BusinessException("退款失败"); } return $resArray; } catch (\Exception $e) { throw new BusinessException("退款失败"); } } /** * @Desc 支付宝退款 * @Author Gorden * @Date 2024/8/20 14:40 * * @param $params * @param $amount * @return mixed * @throws BusinessException */ private function refundToAlipay($params, $amount) { $data = [ 'out_trade_no' => $params['join_pay_order_id'], 'refund_amount' => $amount, ]; try { $res = Pay::alipay(config('payment.alipay'))->refund($data); $resArray = json_decode($res, true); if ($resArray['fund_change'] != 'Y' || $resArray['msg'] != 'Success') { Log::channel('pay')->error('ALIPAY_REFUND_FAIL', $resArray); throw new BusinessException("退款失败"); } return $resArray; } catch (\Exception $e) { throw new BusinessException("退款失败"); } } /** * @Desc 更新主订单 * @Author Gorden * @Date 2024/8/20 14:56 * * @param $order * @param $amount * @param $remark * @return void * @throws BusinessException */ private function updateMainOrderByRefund($order, $amount, $remark) { $orderDiscountJson = []; if (!empty($order->order_discount_json)) { $orderDiscountJson = json_decode($order->order_discount_json, true); } try { $orderDiscountJson[date('YH:i:s H:i:s')] = [ 'coupon_id' => null, 'coupon_value' => $amount, 'coupon_classify' => '退款', 'coupon_detail_id' => $remark ]; $order->order_discount_json = json_encode($orderDiscountJson, JSON_UNESCAPED_UNICODE); $order->order_amount_pay = $order->order_amount_pay - $amount; $order->save(); } catch (\Exception $e) { throw new BusinessException("退款失败"); } } /** * @Desc * @Author Gorden * @Date 2024/8/20 13:51 * * @param $order * @return int * @throws BusinessException */ private function createReturnRecord($order, $amount,$remark) { try { return OrderReturn::insertGetId([ 'join_order_return_user_id' => JwtToken::getCurrentId(), 'join_return_member_id' => $order->join_order_member_id, 'join_return_order_id' => $order->order_id, 'order_return_status' => 'DONE', 'order_return_category' => '退款', 'order_return_apply_datetime' => date('Y-m-d H:i:s'), 'order_return_apply_json' => json_encode(['reason' => '后台自定义退款']), 'order_return_accept_datetime' => date('Y-m-d H:i:s'), 'order_return_refund_json' => json_encode(['amount' => $amount, 'user_id' => JwtToken::getCurrentId(), 'datetime' => date('Y-m-d H:i:s'),'remark'=>$remark ?? '']), 'order_return_addtimes' => time() ]); } catch (\Exception $e) { throw new BusinessException("创建退款信息失败"); } } private function createReturnPayDetail($order, $prepayid, $amount, $response = []) { try { return PayDetail::insert([ 'join_pay_member_id' => $order->join_order_member_id, 'join_pay_order_id' => $order->order_groupby, 'pay_status' => 'SUCCESS', 'pay_category' => 'REFUND', 'pay_amount' => $amount, 'pay_paytimes' => date('Y-m-d H:i:s'), 'pay_prepayid' => $prepayid, 'pay_json_request' => json_encode(['order_id' => $order->order_id]), 'pay_json_response' => json_encode($response), 'pay_addtimes' => time() ]); } catch (\Exception $e) { } } }