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'] = ['in', ['退款', '会员退款']]; if (!empty($where['order_return_addtimes'])) { $where['order_return_addtimes'][0] = strtotime($where['order_return_addtimes'][0]); $where['order_return_addtimes'][1] = strtotime($where['order_return_addtimes'][1]); } 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'])) { $orderSheet = OrderSheet::with([ 'goods' => function ($query) { $query->select('goods_id', 'goods_name'); } ])->select('join_sheet_order_id', 'join_sheet_goods_id') ->where('join_sheet_order_id', $item['order']->order_id) ->get() ->toArray(); $goodsName = !empty($orderSheet) ? $orderSheet[0]['goods']['goods_name'] : ''; if (count($orderSheet) > 1) { $goodsName .= ' 等'; } $item['goods_name'] = $goodsName; } 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'] ?? ''; } if (!empty($item['order_return_refund_json']) && is_json($item['order_return_refund_json'])) { $returnRefundJson = json_decode($item['order_return_refund_json'], true); if (!empty($returnRefundJson['user_id'])) { $item['userName'] = SysUser::where('user_id', $returnRefundJson['user_id'])->value('user_name'); } } } return $items; } /** * @Desc 退款管理顶部统计 * @Author Gorden * @Date 2024/10/31 11:37 * * @param Request $request * @return Response */ public function statistics(Request $request) { $status = $request->get('order_return_status'); $memberId = $request->get('join_return_member_id'); $orderId = $request->get('orderId'); $orderReturnAddtimes = $request->get('order_return_addtimes'); if (!empty($orderReturnAddtimes)) { $orderReturnAddtimes[0] = strtotime($orderReturnAddtimes[0]); $orderReturnAddtimes[1] = strtotime($orderReturnAddtimes[1]); } $returnModel = OrderReturn::when(!empty($status), function ($query) use ($status) { $query->where('order_return_status', $status); })->when(!empty($memberId), function ($query) use ($memberId) { $query->where('join_return_member_id', $memberId); })->when(!empty($orderId), function ($query) use ($orderId) { $query->where('join_return_order_id', 'like', '%' . $orderId . '%'); })->when(!empty($orderReturnAddtimes), function ($query) use ($orderReturnAddtimes) { $query->whereBetween('order_return_addtimes', $orderReturnAddtimes); }); $totalModel = clone $returnModel; $total = $totalModel->selectRaw("SUM(JSON_UNQUOTE(JSON_EXTRACT(order_return_apply_json,'$.amount'))) as amount,count(orders_return_id) as total") ->first() ->toArray(); $total['amount'] = sprintf('%.2f', round($total['amount'], 2)); $pendingTotalModel = clone $returnModel; $pendingTotal = $pendingTotalModel->where('order_return_status', 'PENDING') ->selectRaw("SUM(JSON_UNQUOTE(JSON_EXTRACT(order_return_apply_json,'$.amount'))) as amount,count(orders_return_id) as total") ->first() ->toArray(); $pendingTotal['amount'] = sprintf('%.2f', round($pendingTotal['amount'], 2)); $doingTotalModel = clone $returnModel; $doingTotal = $doingTotalModel->where('order_return_status', 'DOING') ->selectRaw("SUM(JSON_UNQUOTE(JSON_EXTRACT(order_return_apply_json,'$.amount'))) as amount,count(orders_return_id) as total") ->first() ->toArray(); $doingTotal['amount'] = sprintf('%.2f', round($doingTotal['amount'], 2)); $disagreeTotalModel = clone $returnModel; $disagreeTotal = $disagreeTotalModel->where('order_return_status', 'DISAGREE') ->selectRaw("SUM(JSON_UNQUOTE(JSON_EXTRACT(order_return_apply_json,'$.amount'))) as amount,count(orders_return_id) as total") ->first() ->toArray(); $disagreeTotal['amount'] = sprintf('%.2f', round($disagreeTotal['amount'], 2)); $doneTotalModel = clone $returnModel; $doneTotal = $doneTotalModel->where('order_return_status', 'DONE') ->selectRaw("SUM(JSON_UNQUOTE(JSON_EXTRACT(order_return_apply_json,'$.amount'))) as amount,count(orders_return_id) as total") ->first() ->toArray(); $doneTotal['amount'] = sprintf('%.2f', round($doneTotal['amount'], 2)); return json_success('success', [ 'total' => $total, 'pendingTotal' => $pendingTotal, 'doingTotal' => $doingTotal, 'disagreeTotal' => $disagreeTotal, 'doneTotal' => $doneTotal ]); } 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', 'join_member_role_id', 'member_is_owner', 'member_is_vip', 'member_is_partner', 'member_is_referrer', 'member_is_franchisee'); }, 'goods' => function ($query) { $query->select('goods_id', 'goods_name', 'goods_cover', 'goods_market_price', 'goods_sales_price', 'goods_classify'); }, 'sku' => function ($query) { $query->select('goods_sku_id', 'join_sku_goods_id', 'goods_sku_specs_json', 'goods_sku_sales_price'); }, 'memberInfo', 'cert', 'refund' ])->where('join_sheet_order_id', $orderId) ->get() ->toArray(); $member = []; $cert = []; $memberInfo = []; $sheets = []; foreach ($orderSheet as &$item) { if (isset($item['member']) && empty($member)) { $member = $item['member']; $member['level'] = MemberService::getRoleName($member['join_member_role_id'] ?? ''); } if (isset($item['cert']) && empty($cert)) { $cert = $item['cert']; } if (isset($item['member_info']) && empty($memberInfo)) { $memberInfo = $item['member_info']; $memberInfo['member_info_nickname'] = $memberInfo['member_info_nickname'] ?? MemberService::getMemberNickname($member['member_mobile'] ?? ''); $memberInfo['member_info_headimg'] = MemberService::getAvatarUrl($memberInfo['member_info_headimg'] ?? ''); } $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') ->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['sku'])) { if (!empty($item['sku']['goods_sku_specs_json'])) { $specsJson = json_decode($item['sku']['goods_sku_specs_json'], true); $skuName = ''; foreach ($specsJson as $specsKey => $skuSpecs) { if (is_array($skuSpecs)) { $skuName = $skuName . ' ' . implode(' ', $skuSpecs) . ';'; } else { $skuName = $skuName . ' ' . $skuSpecs . ';'; } } $item['sku']['goods_sku_title'] = rtrim($skuName, ';'); } } 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(); $return = OrderReturn::where('join_return_order_id', $orderId)->first(); if (!empty($return->order_return_refund_json)) { $returnRefundJson = json_decode($return->order_return_refund_json, true); if (!empty($returnRefundJson['user_id'])) { $return->userName = SysUser::where('user_id', $returnRefundJson['user_id'])->value('user_name'); } } if (!empty($return->order_return_apply_json)) { $returnApplyJson = json_decode($return->order_return_apply_json, true); if (!empty($returnApplyJson['order_id'])) { $sheets = OrderSheet::with([ 'goods' => function ($query) { $query->select('goods_id', 'goods_name', 'goods_cover', 'goods_market_price', 'goods_sales_price', 'goods_classify'); }, 'sku' => function ($query) { $query->select('goods_sku_id', 'join_sku_goods_id', 'goods_sku_specs_json', 'goods_sku_sales_price'); }, ])->whereIn('join_sheet_order_id', $returnApplyJson['order_id']) ->select('order_sheet_id', 'join_sheet_goods_id', 'join_sheet_goods_sku_id', 'order_sheet_num', 'order_sheet_price', 'order_sheet_amount') ->get() ->toArray(); foreach ($sheets as $key => $sheetsItem) { if (empty($sheetsItem['goods'])) { unset($sheets[$key]); continue; } $sheets[$key]['goods']['goods_cover'] = getenv('STORAGE_DOMAIN') . $sheetsItem['goods']['goods_cover']; if (!empty($sheetsItem['sku'])) { if (!empty($item['sku']['goods_sku_specs_json'])) { $specsJson = json_decode($item['sku']['goods_sku_specs_json'], true); $skuName = ''; foreach ($specsJson as $specsKey => $skuSpecs) { if (is_array($skuSpecs)) { $skuName = $skuName . ' ' . implode(' ', $skuSpecs) . ';'; } else { $skuName = $skuName . ' ' . $skuSpecs . ';'; } } $sheets[$key]['sku']['goods_sku_title'] = rtrim($skuName, ';'); } } } $sheets = array_values($sheets); } } $express = OrderExpress::where('join_express_order_id', $orderId)->first(); $payDetails = PayDetail::where('join_pay_order_id', $order->order_groupby) ->whereJsonContains('join_pay_object_json->order_id', $orderId) ->where('pay_status', 'SUCCESS') ->where('pay_category', '<>', 'REFUND') ->get() ->toArray(); if (count($payDetails) > 1) { $order->pay_category = 'CONSTITUTE'; } $payDetail = !empty($payDetails) && count($payDetails) > 0 ? $payDetails[0] : []; if (!empty($payDetail) && !empty($payDetail['pay_prepayid'])) { $categoryArray = explode('-', $payDetail['pay_prepayid']); if (isset($categoryArray[1])) { $payDetail['pay_category'] = $categoryArray[1]; } else if (in_array($categoryArray[0], ['WXPAY', 'ALIPAY', 'OFFLINE', 'OFFLINE_ALIPAY', 'OFFLINE_WXPAY', 'MONEY'])) { $payDetail['pay_category'] = $categoryArray[0]; } } $data = [ 'member' => $member, 'cert' => $cert, 'member_info' => $memberInfo, 'order' => $order, 'refund' => $return, 'sheet' => $orderSheet, 'sheets' => $sheets, 'express' => $express, 'payDetail' => json_decode(json_encode($payDetail)), 'payDetails' => json_decode(json_encode($payDetails)) ]; return json_success('', $data); } /** * @Desc 会员退款详情 * @Author Gorden * @Date 2024/10/25 9:21 * * @param Request $request * @return Response */ public function rechargeSheet(Request $request) { $returnId = $request->get('return_id'); if (!$returnId) { return json_fail("参数异常"); } $return = OrderReturn::with([ 'member' => function ($query) { $query->select('member_id', 'member_mobile', 'join_member_role_id', 'member_is_owner', 'member_is_vip', 'member_is_partner', 'member_is_referrer'); }, 'info' => function ($query) { $query->select('join_info_member_id', 'member_info_nickname', 'member_info_headimg'); }, 'cert' => function ($query) { $query->select('join_cert_member_id', 'member_cert_name'); }, ])->where('orders_return_id', $returnId) ->first(); if (!$return) { return json_fail('数据异常'); } $return = $return->toArray(); $return['role_name'] = MemberService::getRoleName(!empty($return['member']) ? $return['member']['join_member_role_id'] : ''); $return['info']['member_info_nickname'] = MemberService::getNickname(!empty($return['info']) ? $return['info']['member_info_nickname'] : '', !empty($return['member']) ? $return['member']['member_mobile'] : ''); $return['info']['member_info_headimg'] = MemberService::getAvatarUrl(!empty($return['info']) ? $return['info']['member_info_headimg'] : ''); if (!empty($return['order_return_apply_json']) && is_json($return['order_return_apply_json'])) { $json = json_decode($return['order_return_apply_json'], true); $return['reason'] = $json['reason'] ?? ''; $return['order_return_apply_json'] = $json; } if (!empty($return['order_return_recharge_json']) && is_json($return['order_return_recharge_json'])) { $json = json_decode($return['order_return_recharge_json'], true); $return['change'] = $json['change'] ?? ''; } if (!empty($return['join_order_return_user_id'])) { $return['disposeUserName'] = SysUser::where('user_id', $return['join_order_return_user_id'])->value('user_name'); } if (!empty($return['order_return_refund_json'])) { $returnRefundJson = json_decode($return['order_return_refund_json'], true); if (!empty($returnRefundJson['user_id'])) { $return['userName'] = SysUser::where('user_id', $returnRefundJson['user_id'])->value('user_name'); } } $data = [ 'refund' => $return, ]; 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) ->whereJsonContains('join_pay_object_json->order_id', $orderId) ->where('pay_status', 'SUCCESS') ->where('pay_prepayid', '<>', '') ->whereIn('pay_category', ['GOODS', 'SERVICE', 'CHNMED', 'CHNNCD', 'MEALS', 'DISHES', 'VIP', 'PACKAGE']) ->get() ->toArray(); if (empty($payDetail)) { return json_fail("支付状态异常"); } $refundPayIds = array_column($payDetail, 'pay_id'); $response = []; Db::beginTransaction(); try { // 全额退款,检查优惠券,恢复可使用 if (sprintf("%.2f", $amount) == sprintf("%.2f", $order->order_amount_pay)) { if (!empty($order->order_discount_json)) { $discountJson = json_decode($order->order_discount_json, true); foreach ($discountJson as $item) { if (empty($item['coupon_id'])) { continue; } // 是否有其他订单一起使用优惠券 if (!Order::where('order_groupby', $order->order_groupby)->where('order_id', '<>', $order->order_id)->where('order_is_complete', '<>', 'R')->exists()) { foreach ($item['coupon_detail_id'] as $detailId) { CouponDetail::where('coupon_detail_id', $detailId)->update([ 'coupon_detail_status' => 'ACTIVED', 'coupon_detail_used_datetime' => '' ]); } } } } } // 主订单,退款作为优惠入库 $this->updateMainOrderByRefund($order, $amount, $remark); // return 表记录 $return = OrderReturn::where('join_return_order_id', $orderId)->first(); if (empty($return)) { $returnId = $this->createReturnRecord($order, $amount, $remark); } else { $returnId = $return->orders_return_id; //['amount' => $amount, 'user_id' => JwtToken::getCurrentId(), 'datetime' => date('Y-m-d H:i:s'), 'remark' => $remark ?? ''] OrderReturn::where('join_return_order_id', $orderId)->update([ 'order_return_status' => 'DONE', 'order_return_refund_json' => json_encode([ 'amount' => $amount, 'user_id' => JwtToken::getCurrentId(), 'datetime' => date('Y-m-d H:i:s'), 'remark' => $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 = 'ALIPAY'; $payDetail0['order_id'] = $order->order_id; $response = $this->refundToAlipay($payDetail0, $amount); } elseif ($payWay[0] == 'MONEY') { $prepayid = 'MONEY'; // $response = $this->refundToCash($order->join_order_member_id, $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] == 'WELFARE') { $prepayid = $order->join_order_member_id . '-WELFARE'; $this->refundToWelfare($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] == 'VIP') { $prepayid = $order->join_order_member_id . '-VIP'; $this->refundToVIP($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 . '-CARD'; $this->refundToCard($order->join_order_member_id, $amount); $response = ['order_id' => $order->order_id, 'member_id' => $order->join_order_member_id]; } elseif ($payWay[0] == 'OFFLINE') { $prepayid = 'OFFLINE'; $response = []; } elseif ($payWay[0] == 'OFFLINE_ALIPAY') { $prepayid = 'OFFLINE_ALIPAY'; $response = []; } elseif ($payWay[0] == 'OFFLINE_WXPAY') { $prepayid = 'OFFLINE_WXPAY'; $response = []; } } // payDetail 表记录 $this->createReturnPayDetail($order, $refundPayIds, $prepayid, $amount, $response); Db::commit(); // 退款入收支 $params['orderId'] = $orderId; $params['type'] = 'refund'; Event::dispatch('statistics.inout.out', $params); return json_success('success'); } catch (BusinessException $e) { Db::rollBack(); Log::info("退款失败", ['msg' => $e->getMessage()]); return json_fail($e->getMessage()); } catch (\Exception $e) { Db::rollBack(); Log::info("退款失败", ['msg' => $e->getMessage()]); 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->member_account_expend = $account->member_account_expend - $amount; $account->member_account_update_user_id = JwtToken::getCurrentId(); $account->member_account_updatetimes = time(); $account->save(); } /** * @Desc 退款到福利账户 * @Author Gorden * @Date 2024/9/20 17:09 * * @param $memberId * @param $amount * @return void * @throws BusinessException */ private function refundToWelfare($memberId, $amount) { $account = MemberAccount::where('join_account_member_id', $memberId)->where('member_account_classify', 'WELFARE')->first(); if (!$account) { throw new BusinessException("余额账户异常"); } $account->member_account_surplus = $account->member_account_surplus + $amount; $account->member_account_expend = $account->member_account_expend - $amount; $account->member_account_update_user_id = JwtToken::getCurrentId(); $account->member_account_updatetimes = time(); $account->save(); } /** * @Desc 退款到VIP账户 * @Author Gorden * @Date 2024/9/20 17:12 * * @param $memberId * @param $amount * @return void * @throws BusinessException */ private function refundToVIP($memberId, $amount) { $account = MemberAccount::where('join_account_member_id', $memberId)->where('member_account_classify', 'VIP')->first(); if (!$account) { throw new BusinessException("余额账户异常"); } $account->member_account_surplus = $account->member_account_surplus + $amount; $account->member_account_expend = $account->member_account_expend - $amount; $account->member_account_update_user_id = JwtToken::getCurrentId(); $account->member_account_updatetimes = time(); $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->member_account_expend = $account->member_account_expend - $amount; $account->member_account_update_user_id = JwtToken::getCurrentId(); $account->member_account_updatetimes = time(); $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("退款失败"); } Log::info("退款响应", $resArray); return $resArray; } catch (\Exception $e) { Log::error("微信退款失败", ['msg' => $e->getMessage()]); 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, 'out_request_no' => $params['order_id'] ]; Log::error("支付宝退款参数", $data); 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) { Log::error("支付宝退款失败", ['msg' => $e->getMessage()]); 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('Y-m-d 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_is_complete = 'R'; $order->order_category = 'RETURN'; // $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' => '后台自定义退款', 'amount' => $amount]), '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, $refundPayIds, $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, 'join_pay_object_json' => json_encode(['order_id' => $order->order_id, 'refund_pay_ids' => $refundPayIds]), 'pay_json_request' => json_encode(['order_id' => $order->order_id]), 'pay_json_response' => json_encode($response), 'pay_addtimes' => time() ]); } catch (\Exception $e) { } } /** * @Desc 充值退款详情 * @Author Gorden * @Date 2024/10/16 11:40 * * @param Request $request * @return Response */ // public function rechargeSheet(Request $request) // { // $refundId = $request->get('return_id'); // if (!$refundId) { // return json_fail("参数异常"); // } // // $refund = OrderReturn::where('orders_return_id', $refundId) // ->first(); // if (!empty($refund->order_return_apply_json)) { // $refund->order_return_apply_json = json_decode($refund->order_return_apply_json); // } // // // return json_success('', $refund); // } /** * @Desc 充值退款 * @Author Gorden * @Date 2024/10/16 11:42 * * @param Request $request * @return Response */ public function rechargeRefund(Request $request) { $memberId = $request->post('member_id'); $refundId = $request->post('return_id'); $password = $request->post('refund_password', ''); if (!$memberId) { return json_fail('参数异常'); } if ($password != '123456') { return json_fail('支付密码错误'); } $returnOrder = OrderReturn::where('orders_return_id', $refundId) ->where('join_return_member_id', $memberId) ->where('order_return_status', 'DOING') ->where('order_return_category', '会员退款') ->first(); if (!$returnOrder) { return json_fail("退款数据异常"); } $memberAccount = MemberAccount::where('join_account_member_id', $memberId) ->where('member_account_classify', 'CASH') ->where('member_account_status', 'ACTIVED') ->first(); if (!$memberAccount) { return json_fail('会员账户异常'); } try { Db::beginTransaction(); $refundApplyJson = json_decode($returnOrder->order_return_apply_json, true); // 应减金额等于 扣除金额 + 银行打款金额 $amount = $refundApplyJson['surplus'] + $refundApplyJson['amount']; $addedAmount = $refundApplyJson['added']; $refundApplyJson['added_amount'] = $addedAmount; $refundApplyJson['user_id'] = JwtToken::getCurrentId(); $refundApplyJson['datetime'] = date('Y-m-d H:i:s'); $refundApplyJson['remark'] = $request->post('refund_remark', ''); $returnOrder->order_return_refund_json = json_encode($refundApplyJson); $returnOrder->order_return_status = 'DONE'; $returnOrder->order_return_remark = $request->post('refund_remark', ''); $returnOrder->save(); // 账户剩余 if ($memberAccount->member_account_surplus < $amount) { throw new BusinessException("账户本金余额不足"); } if ($memberAccount->member_account_added < $addedAmount) { throw new BusinessException("账户增值余额不足"); } // 本金 $memberAccount->member_account_surplus = $memberAccount->member_account_surplus - $amount; // 增值 $memberAccount->member_account_added = $memberAccount->member_account_added - $addedAmount; $memberAccount->member_account_update_user_id = JwtToken::getCurrentId(); $memberAccount->member_account_updatetimes = time(); $memberAccount->save(); // 删除会员身份 Member::where('member_id', $memberId) ->update([ 'join_member_role_id' => '', 'member_role_begintime' => '', 'member_role_config_json' => '[]' ]); // 没用的优惠券失效 CouponDetail::where('join_coupon_detail_member_id', $memberId) ->where('coupon_detail_status', '<>', 'USED') ->whereJsonContains('coupon_detail_extend_json->gettype', 'ROLE') ->update([ 'coupon_detail_status' => 'DISABLED' ]); // 产生两条退款记录 (pay_detail) $payDetailInsertData = [ 'join_pay_member_id' => $memberId, 'join_pay_order_id' => 'ROLE_REFUND', 'join_pay_object_json' => '[]', 'pay_status' => 'SUCCESS', 'pay_category' => 'ROLE_REFUND', 'pay_amount' => $refundApplyJson['amount'], 'pay_paytimes' => date('Y-m-d H:i:s'), 'pay_prepayid' => $memberId . '-CASH', 'pay_addtimes' => time() ]; // 退款记录 PayDetail::insert($payDetailInsertData); // 扣除记录 $payDetailInsertData['join_pay_order_id'] = 'ROLE_DEDUCT'; $payDetailInsertData['pay_category'] = 'ROLE_DEDUCT'; $payDetailInsertData['pay_amount'] = $refundApplyJson['surplus'] + $addedAmount; PayDetail::insert($payDetailInsertData); Db::commit(); return json_success('success'); } catch (BusinessException $e) { Db::rollBack(); return json_fail($e->getMessage()); } catch (\Exception $e) { Db::rollBack(); return json_fail('退款失败'); } } }