request->post(); $validateService = Yii::$app->services->validate; $rules = [ [['order_id', 'order_type'], 'required'], ['order_type', 'in', 'range' => ['goods'], 'message' => '订单类型不合法'], ]; $labels = [ 'order_id' => '订单ID', 'order_type' => '订单类型' ]; $valid = $validateService->validate($post, $rules, $labels); if (!$valid) { return $this->error($validateService->getFirstErrorSummary()); } $orders = []; $orderList = Order::find()->where(['id' => $post['order_id'], 'pay_status' => 0, 'order_status' => OrderStatusEnum::NOT_PAY])->all(); foreach ($orderList as $info) { $orders[] = [ 'order_no' => $info['order_no'], 'amount' => $info['pay_money'], 'title' => Order::getOrderTitle($info), 'order_type' => $post['order_type'] ]; } $res = Yii::$app->services->pay->createTrade($this->mall_id, $this->user_id, $orders); return $this->success('操作成功', $res); } /* * 支付接口 * @return mixed|void */ public function actionPay() { $key = sprintf('PaymentPay:%s', $this->user_id); try { if (LockHelper::fLock($key, 5)) throw new Exception('请勿频繁请求'); $post = Yii::$app->request->post(); $validateService = Yii::$app->services->validate; $rules = [ [['trade_no', 'pay_type'], 'required'], [['period'], 'integer'], [['action', 'sms_code'], 'string'], [['transaction_password','source','is_pay_group','pay_group_list', 'order_ids', 'main_order_id', 'is_store_pay', 'pay_type', 'trade_type'], 'safe'], [['balance_desc_type'], 'integer'] ]; $valid = $validateService->validate($post, $rules); if (!$valid) { return $this->error($validateService->getFirstErrorSummary()); } $trade_no = $post['trade_no']; //交易流水号 //获取交易流水信息 $trade = Yii::$app->services->pay->getByTradeNo($trade_no); if (!$trade || $trade->user_id != $this->user_id) { throw new Exception('交易不存在'); } // 已支付 if ($trade->is_pay) { throw new Exception('订单已支付'); } if ($trade->isBindPayType()) { throw new Exception('支付方式已变更,请刷新页面重新支付'); } $pay_type = $post['pay_type']; //支付方式 : 1,2,3 $trade_type = $post['trade_type']; //交易类型 $params['sms_code'] = $post['sms_code'] ?? ''; //汇聚快捷支付:短信验证码 $params['period'] = $post['period'] ?? 0; // 花呗分期期数 $params['is_store_pay'] = $post['is_store_pay'] ?? 0; // 是否门店支付 $source = $post['source'] ?? 1; // 判断是否开启超级支付 $is_tactics_pay = false; if (MallAddons::isInstall($this->mall_id, AddonsEnum::ADDONS_NAME_TACTICS_PAY)) { $tactics_setting = Yii::$app->services->setting->addons->get($this->mall_id, AddonsEnum::ADDONS_NAME_TACTICS_PAY, 'basic'); !empty($tactics_setting['is_enable']) && $is_tactics_pay = true; } $enable_pay_type = Yii::$app->services->pay->getEnablePayment($this->mall_id, $this->platform,$source,['pay_money' => $trade->pay_fee ?? 0, 'user_id' => $this->user_id]); $enable_pay_type_arr = array_column($enable_pay_type, null, 'pay_type'); // 判断是否支持该支付方式 if (array_diff(is_array($pay_type) ? $pay_type : [$pay_type] , array_column($enable_pay_type, 'pay_type')) && !$is_tactics_pay) { throw new Exception('不支持该支付方式'); } // 余额支付,判断是否允许余额支付 if ($pay_type == PayTypeEnum::BALANCE && (new PaymentService(['mall_id' => $this->mall_id]))->isExcludeBalance($trade_no, $source)) { throw new Exception('不支持该支付方式'); } // 判断是否组合支付 // if (is_array($pay_type)) { // $paymentOrderObj = PaymentTradeGroupOrder::class; // } else { $paymentOrderObj = PaymentTradeOrder::class; // } // $payment_order_list = $paymentOrderObj::findAll(['trade_id' => $trade->id]); $payment_order_list = $paymentOrderObj::findAll(['trade_id' => $trade->id]); $order_type = reset($payment_order_list)->order_type; $order_no_arr = array_column($payment_order_list, 'order_no'); switch ($order_type) { case PaymentTradeOrderEnum::MAIN_ORDER: $counts = Order::find()->where(['order_no'=>$order_no_arr,'pay_status'=>0])->count(); if($counts!=count($payment_order_list)) throw new Exception('主订单不一致'); $counts = Order::find()->where(['order_no'=>$order_no_arr,'pay_status'=>0,'order_status'=>OrderStatusEnum::NOT_PAY])->count(); if(!$counts){ throw new Exception('待支付订单不存在'); } break; case PaymentTradeOrderEnum::OPERATING_NOTE_ORDER: $counts = AddonsOperatingNoteBuy::find()->where(['order_no'=>$order_no_arr,'is_pay'=>0])->count(); if($counts!=count($payment_order_list)) throw new Exception('主订单不一致'); break; case PaymentTradeOrderEnum::QIAN_XI_SUPPLY_CHAIN: $counts = QianxiSupplyChainOrder::find()->where(['order_no'=>$order_no_arr,'order_status'=>0])->count(); if($counts!=count($payment_order_list)) throw new Exception('主订单不一致'); break; case PaymentTradeOrderEnum::COURSE_ORDER: $counts = AddonsCourseOrders::find()->where(['order_no'=>$order_no_arr,'order_status'=>0])->count(); if($counts!=count($payment_order_list)) throw new Exception('主订单不一致'); break; case PaymentTradeOrderEnum::LAO_DA_FU_MEDICAL_RECORD: $counts = LaoDaFuStoreMedicalRecord::find()->where(['order_no'=>$order_no_arr,'pay_at'=>0])->count(); if($counts!=count($payment_order_list)) throw new Exception('主订单不一致'); break; default: $params['order_type'] = $order_type; $params['order_no_arr'] = $order_no_arr; $params['payment_order_list'] = $payment_order_list; Yii::$app->services->globalFunction->orderCheck('orderCheck',$params); } //查询用户open_id $user_info = UserInfo::findOne(['user_id' => $this->user_id, 'status' => 1, 'platform' => $this->platform]); $params['openid'] = !empty($user_info) ? $user_info->openid : ''; // 支付参数 $params['transaction_password'] = $post['transaction_password']??''; $params['balance_desc_type'] = $post['balance_desc_type']??StatusEnum::DISABLED; $params['source'] = $source; // 组合支付先进行钱包支付 if (is_array($all_pay_type = $pay_type)) { $service = new \services\common\MixedPayService(['mall_id' => $this->mall_id]); // 设置为组合支付 $service->setIsPayGroup($trade); // 创建支付子订单 $service->createTradeItem($trade, $all_pay_type, $trade_type); // 积分或余额以外的支付方式 $pay_type = $service->getOnlinePayType($all_pay_type); // 先进行钱包支付 $wallet_pay_type = $service->getWalletPayType($all_pay_type); $pay_type_action = $enable_pay_type_arr[$wallet_pay_type]['action']; $this->isPostOrderDetail($service->getTradeType($trade_type, $wallet_pay_type), $pay_type_action, $order_no_arr, $params); $res = Yii::$app->services->pay->$pay_type_action($trade, $trade_type, $params); // 添加调用记录 PaymentTradeLog::addLog([ 'trade_id' => $trade->id, 'pay_type' => $pay_type, 'trade_type' => $service->getTradeType($trade_type, $wallet_pay_type), 'api_result' => json_encode($res) ], $trade); // 剩余的交易类型 $trade_type = $service->getTradeType($trade_type, $pay_type); } if (!$enable_pay_type_arr[$pay_type]['action'] && !$is_tactics_pay) { throw new Exception('支付方式不存在'); } $pay_type_action = $enable_pay_type_arr[$pay_type]['action'] ?? ''; //TODO: 改写成功公共调用 $mall_pay_types = array_keys(PayTypeEnum::mallPayType()); // 判断是否开启超级支付 if ($is_tactics_pay && !in_array($pay_type, [PayTypeEnum::BALANCE, PayTypeEnum::SCORE])) { $params['trade'] = $trade; $params['trade_type'] = $trade_type; $params['mall_id'] = $this->mall_id; $params['user_id'] = $this->user_id; $params['app_platform'] = $this->platform; $params['pay_type'] = $pay_type; $res = Payment::pay($params); }else if (in_array($pay_type, $mall_pay_types)) { // 主商城本身支持的支付方式,直接调用 service // 支付宝且为js的支付方式,需要带上商品 if($order_type == PaymentTradeOrderEnum::MAIN_ORDER) $this->isPostOrderDetail($trade_type, $pay_type_action, $order_no_arr, $params); $res = Yii::$app->services->pay->$pay_type_action($trade, $trade_type, $params); } else { // 不是主商城支持(通过插件或者其他方式扩展)的支付方式,走公共调用 // $invoke_id = (\Yii::$app->params)['common_function']['payment'][$pay_type]; // // dd($pay_type, $invoke_id); // $params['trade'] = $trade; // $params['trade_type'] = $trade_type; // $res = GlobalInvoke::exec($invoke_id, $this->mall_id, $params); $params['action'] = $post['action'] ?? $pay_type_action; $params['trade'] = $trade; $params['trade_type'] = $trade_type; $params['mall_id'] = $this->mall_id; $params['user_id'] = $this->user_id; $params['app_platform'] = $this->platform; $params['pay_type'] = $pay_type; $res = GlobalInvoke::exec(GlobalInvoke::INVOKE_PAYMENT,$this->mall_id,$params); } if (!in_array($pay_type, [PayTypeEnum::BALANCE, PayTypeEnum::SCORE])) { //添加调用记录 PaymentTradeLog::addLog([ 'trade_id' => $trade->id, 'pay_type' => $pay_type, 'trade_type' => $trade_type, 'api_result' => json_encode($res) ], $trade); } else { LockHelper::unFLock($key); // 余额支付,返回值是否特殊处理 return $this->success('支付成功', [ 'pay_fee' => $trade['pay_fee'], 'order_ids' => $post['order_ids'] ?? '', 'main_order_id' => $post['main_order_id'] ?? '', ]); } if (!empty($res['return_code']) && $res['return_code'] == 'FAIL') return $this->error($res['return_msg'], $res); if (!empty($res['result_code']) && $res['result_code'] == 'FAIL') return $this->error($res['err_code_des'], $res); $res['pay_fee'] = $trade['pay_fee']; $res['order_ids'] = $post['order_ids'] ?? ''; $res['main_order_id'] = $post['main_order_id'] ?? ''; LockHelper::unFLock($key); return $this->success('操作成功', $res, ApiStatusEnum::CODE_SUCCESS, JSON_BIGINT_AS_STRING); } catch (Exception $e) { LockHelper::unFLock($key); if($e->getMessage()=='您未设置支付密码'){ return $this->error($e->getMessage(),[],ApiStatusEnum::CODE_ERROR_SETTING_PAY_PASSWORD); } if($e->getMessage()=='请输入交易密码'){ return $this->error($e->getMessage(),[],ApiStatusEnum::CODE_ERROR_PAY_PASSWORD); } return $this->error($e->getMessage()); } } /** * 获取支付类型 * * @return void */ public function actionGetPayType() { $wallet = UserWallet::getOne( [['user_id' => $this->user_id]], true, [], false, 'balance,score as total_score' ); $source = $this->request->get('source', 1, 1); $trade_no = $this->request->get('trade_no', ''); //判断是否有卡券插件 if (MallAddons::isInstall($this->mall_id, AddonsEnum::ADDONS_NAME_CARD_COUPONS)) { $allMoney = CardCouponsScoreGive::find() ->where(['mall_id' => $this->mall_id, 'receive_user_id' => $this->user_id, 'status' => StatusEnum::ENABLED,'is_active'=>CardCouponsScoreGive::ACTIVATED,'is_open'=>CardCouponsScoreGive::OPEN]) ->andWhere(['<=', 'start_at', time()]) ->andWhere(['>=', 'end_at', time()]) ->sum('can_use_money'); $wallet['balance'] = bcadd($wallet['balance'],$allMoney,2); } $trade = PaymentTrade::findOne(['out_trade_no'=>$trade_no]); if(!empty($trade_no)){ if(!empty($trade)){ if($trade->pay_fee<=0){ $pay_type_list = Yii::$app->services->pay->getEnablePayMentByZero($this->mall_id); return $this->success('操作成功', ['list' => $pay_type_list, 'wallet' => $wallet]); } $payment_trade_order = PaymentTradeOrder::getOne([ ['trade_id' => $trade['id']], ['order_type'=>['order','cashier_order']] ]); //判断订单类型,判断是否为门店订单/门店收银台订单 if(!empty($payment_trade_order)){ switch ($payment_trade_order['order_type']){ case 'order': $pre = $payment_trade_order['order_no'][0].$payment_trade_order['order_no'][1]; if($pre=='st'){ $source = 6; } break; case 'cashier_order': $source = 6; break; } } } } $pay_type_list = Yii::$app->services->pay->getEnablePayment($this->mall_id, $this->platform, $source, ['pay_money' => $trade->pay_fee ?? 0, 'user_id' => $this->user_id]); //支付限制 if (isset($trade->limit_payment)&&!empty($trade->limit_payment)) { //排除系统的主要支付方式 $pay_type_list_filter = array_filter($pay_type_list, function ($item) { return !in_array($item['pay_type'], [PayTypeEnum::BALANCE, PayTypeEnum::SCORE, PayTypeEnum::WECHAT, PayTypeEnum::ALI, PayTypeEnum::MIXED]); }); $limit_payment = json_decode($trade->limit_payment, true); foreach ($pay_type_list as $key => $pay) { foreach ($limit_payment as $key_l => $lpay) { if ($lpay==$pay['pay_type'] && $lpay!=0){ $pay_type_list_filter[]=$pay_type_list[$key]; } } } $pay_type_list=$pay_type_list_filter; } //如果存在消费卡支付方式,则将消费卡金额写入wallet内 foreach ($pay_type_list as $key => $value) { if ($value['pay_type'] == PayTypeEnum::CONSUMER_CARD) $wallet['consumer_card'] = $value['consumer_card']; } // 获取支付方式是否支持组合支付 $service = new \services\common\MixedPayService(['mall_id' => $this->mall_id]); $pay_type_list = $service->getPayTypeList($trade, $pay_type_list, $wallet, $source); // 排除支付方式 //监听插件修改支付方式是否可用 $event = new PaymentTypeEvent($this->mall_id, $pay_type_list, $this->user_id); Yii::$app->services->events->dispatch($event); $pay_type_list = $event->getResultForm(); $paymentService = new PaymentService(['mall_id' => $this->mall_id]); $paymentService->excludePayType((string)$trade_no, (int)$source, $pay_type_list); return $this->success('操作成功', ['list' => $pay_type_list, 'wallet' => $wallet]); } /** * 是否需要响应订单中的商品数据 * @param $trade_type * @param $pay_type_action * @param $order_no_arr * @param $params * @return mixed */ private function isPostOrderDetail($trade_type, $pay_type_action, $order_no_arr, &$params) { if ($trade_type == AliPayPayTypeEnum::JS && $pay_type_action == "alipay") { $order = Order::find()->where(['order_no'=>$order_no_arr,'pay_status'=>0]) ->with(['detail' => function($query) { $query->select('order_id, goods_id, goods_name, price, num as quantity')->where(['order_status' => StatusEnum::DISABLED]); }])->asArray()->all(); $params['goods_detail'] = []; foreach ($order as $item) { foreach ($item['detail'] as $value) { $params['goods_detail'][] = $value; } } } return $params; } /** * 生成组合订单支付流水 * @return mixed|void */ public function actionGroupCreate() { $post = Yii::$app->request->post(); $validateService = Yii::$app->services->validate; $rules = [ [['trade_id','pay_group_list'], 'required'], [['pay_type','order_type'], 'safe'], [['order_id'],'safe'] ]; $valid = $validateService->validate($post, $rules); if (!$valid) { return $this->error($validateService->getFirstErrorSummary()); } if(empty($post['pay_group_list'])){ return $this->error('支付类型错误'); } $parent_trade_exist = PaymentTrade::find()->where(['parent_trade_id' => $post['trade_id']])->one(); if(!empty($parent_trade_exist)){ //已经存在组合支付 return $this->error('已存在待支付订单'); } $trade = PaymentTrade::find()->where(['id' => $post['trade_id'],'is_pay' => 0])->one(); if(empty($trade)){ return $this->error('支付订单不存在'); } $order_type = $post['order_type']; if(empty($order_type)){ $trade_order = PaymentTradeOrder::find()->where(['trade_id' => $trade['id'],'is_pay' => 0])->asArray()->one(); if(empty($trade_order)) return $this->error('待支付订单不存在'); $order_type = $trade_order['order_type']; if($order_type == Order::DEFAULT){ $order_ids = explode(",", $post['order_id']); $group_order = []; foreach ($order_ids as $order_id) { /** * @var Order $order */ $order = Order::find()->where(['id' => $order_id, 'pay_status' => 0, 'order_status' => OrderStatusEnum::NOT_PAY])->one(); if(empty($order)){ return $this->error('待支付订单不存在!'); } $order_no = $order['order_no']; $title = Order::getOrderTitle($order); $group_order[] = [ 'order_no' => $order_no, 'title' => $title, 'id' => $order->id ]; } }else{ $title = $trade['title']; $order_no = $trade_order['order_no']; } }elseif($order_type == AddonsEnum::ADDONS_NAME_CAKE){ $order = CakeOrder::find()->where(['id' => $post['order_id'], 'pay_status' => 0, 'order_status' => OrderStatusEnum::NOT_PAY])->one(); if(empty($order)){ return $this->error('待支付订单不存在'); } $order_no = $order['order_no']; $title = CakeOrder::getOrderTitle($order); }elseif($order_type == AddonsEnum::ADDONS_NAME_BAI_MI_MOVIE){ $order = MovieOrder::find()->where(['id' => $post['order_id'], 'is_pay' => 0])->one(); if(empty($order)){ return $this->error('待支付订单不存在'); } $order_no = $order['channel_order_no']; $title = mb_strlen($order->order_title) > 32 ? mb_substr($order->order_title, 0, 32) : $order->order_title; }else{ return $this->error('未知订单类型'); } $pay_type = !empty($post['pay_type']) ? $post['pay_type'] : 0; $result = []; $pay_money_list = array_column($post['pay_group_list'],'pay_money'); $pay_fee = bcadd($trade['pay_fee'],$trade['rand_fee'],2); if(bccomp(array_sum($pay_money_list), $pay_fee,2) !== 0){ return $this->error('支付金额错误'); } foreach ($post['pay_group_list'] as $pay_group) { $orders = []; if (!empty($group_order)) { foreach ($group_order as $item) { $orders[] = [ 'order_id' => $item['id'], 'order_no' => $item['order_no'], 'amount' => $pay_group['pay_money'], 'title' => $item['title'], 'order_type' => $order_type, //'notify_class' => 'common\logic\notify\Notify', ]; } } else { $orders[] = [ 'order_id' => $order['id'] ?? 0, 'order_no' => $order_no, 'amount' => $pay_group['pay_money'], 'title' => $title, 'order_type' => $order_type, //'notify_class' => 'common\logic\notify\Notify', ]; } try{ $res = Yii::$app->services->pay->createGroupTrade($this->mall_id, $this->user_id, array_values($orders),$post['trade_id'],$pay_type); $result[$pay_group['trade_type']] = $res; }catch(\Exception $e){ return $this->error($e->getMessage()); } } return $this->success('操作成功', $result); } /** * 获取组合支付类型 * * @return void */ public function actionGetPayTypeByGroup() { $params = \Yii::$app->request->get(); $res = \Yii::$app->services->validate->validate($params, [ [['pay_type','source'], 'required'], ]); if ($res === false) return $this->error(\Yii::$app->services->validate->getErrorMessage()); $pay_type_list = Yii::$app->services->pay->getEnablePayment($this->mall_id, $this->platform, $params['source']); $new_list = []; foreach($pay_type_list as $key => $pay_type){ if($pay_type['pay_type'] != $params['pay_type'] && $pay_type['pay_type'] != PayTypeEnum::MIXED){ $new_list[] = $pay_type; } } return $this->success('操作成功', ['list' => $new_list]); } /** * 组合支付-获取支付方式 * * @return void */ public function actionGetPayTypeByMixed() { $params = \Yii::$app->request->get(); $res = \Yii::$app->services->validate->validate($params, [ [['source'], 'required'], ]); if ($res === false) return $this->error(\Yii::$app->services->validate->getErrorMessage()); $pay_type_list = Yii::$app->services->pay->getEnablePayment($this->mall_id, $this->platform, $params['source']); $new_list = []; $mall_list = PayTypeEnum::mallParty(); $new_list['mall_pay_types'] = []; $new_list['third_pay_types'] = []; foreach($pay_type_list as $key => $pay_type){ if($pay_type['pay_type'] == PayTypeEnum::MIXED){ continue; } if($pay_type['pay_type'] == PayTypeEnum::HUIFUPAY){ //临时暂停汇付参与组合支付 continue; } if(isset($mall_list[$pay_type['pay_type']])){ $new_list['mall_pay_types'][] = $pay_type; }else{ $new_list['third_pay_types'][] = $pay_type; } } $wallet = UserWallet::getOne( [['user_id' => $this->user_id]], true, [], false, 'balance,score as total_score' ); return $this->success('操作成功', ['list' => $new_list,'wallet' => $wallet]); } /** * 支付订单号支付验证 * @return void */ public function actionPayVerify() { // 支付流水单号 $trade_id = Yii::$app->request->post('trade_id', 0); if (empty($trade_id)) return $this->error('参数错误'); $res = Yii::$app->services->pay->getPayVerify($trade_id); if (!$res) { return $this->error('订单支付失败'); } return $this->success('订单支付成功'); } }