/** * @brief 获取关联的交易记录 * * @return public function * @retval * @see * @note * @author 吕宝贵 * @date 2015/12/17 20:31:11 **/ public function getTrans() { return $this->hasOne(Trans::className(), ['id' => 'trans_id']); }
/** * @brief 充值成功处理,第三方的只有充值成功通知,在支持成功之后的业务逻辑处理,支付宝和微信的所有回告都应该是充值接口 * * @param string $callback 回调函数,仅仅对需要对订单进行逻辑处理的操作有效,需要添加订单id为参数 * @return Trans object 返回充值支付的交易记录 * @see * @note * @author 吕宝贵 * @date 2015/12/06 21:14:32 **/ public function processChargePaySuccess($receivable) { $receivable->status = Receivable::PAY_STATUS_FINISHED; if (!$receivable->save()) { return false; } //获取交易记录 $trans = Trans::findOne($receivable->trans_id); if (!$trans) { return false; } //充值型trans,直接成功,设置交易信息 $trans->status = Trans::PAY_STATUS_FINISHED; if (!$trans->save()) { return false; } //为用户账户充值,充值成功即为一个事物,后续的购买判断在controller里面完成 $userAccount = $this->getUserAccount($trans->to_uid); if (!$userAccount->plus($trans->total_money, $trans->id, $trans->trans_type_id, '充值', '账户充值')) { return false; } return $trans; }
/** * @brief 用户帐户变动的核心函数,所有的变动都需要通过此函数来记录 * * @return public function * @retval * @see * @note * @author 吕宝贵 * @date 2015/12/30 14:39:00 **/ protected function balance($uid, $balanceType, $money, $transId, $description, $currency) { $freezeCat = false; $freeze = null; $trans = null; Yii::warning('进入balance页面', __METHOD__); Yii::warning('uid and balanceType:' . $uid . '---' . $balanceType, __METHOD__); if (in_array($balanceType, [UserAccount::BALANCE_TYPE_FREEZE, UserAccount::BALANCE_TYPE_UNFREEZE, UserAccount::BALANCE_TYPE_FINISH_FREEZE])) { $freezeCat = true; $freeze = Freeze::findOne($transId); if (!$freeze) { $this->addError('trans', '不存在该交易订单'); return false; } } else { //根据交易号查找对应的交易 $trans = Trans::findOne($transId); if (!$trans) { $this->addError('trans', '不存在该交易订单'); return false; } } Yii::warning('获取用户帐户', __METHOD__); $userAccount = $this->getUserAccount($uid); Yii::warning('判断账户变更类型', __METHOD__); switch ($balanceType) { case UserAccount::BALANCE_TYPE_PLUS: $userAccount->plus($money); break; case UserAccount::BALANCE_TYPE_MINUS: $userAccount->minus($money); break; case UserAccount::BALANCE_TYPE_FREEZE: Yii::warning('进入帐号金额冻结'); $userAccount->freeze($money); break; case UserAccount::BALANCE_TYPE_UNFREEZE: $userAccount->unFreeze($money); break; case UserAccount::BALANCE_TYPE_FINISH_FREEZE: $userAccount->finishFreeze($money); break; default: $this->addError(__METHOD__, '不支持提交的账户操作类型'); return false; } if ($userAccount->save()) { //记录账单 Yii::warning('产生用户账单', __METHOD__); $bill = new Bill(); $bill->uid = $userAccount->uid; if (!$freezeCat) { $bill->trans_id = $trans->id; $bill->trans_type_id = $trans->trans_type_id; $bill->trans_type_name = $trans->transType->name; } else { $bill->trans_id = $freeze->id; } $bill->money = $money; $bill->balance_type = $balanceType; $bill->currency = $currency; $bill->description = $description; if (!$bill->save()) { $this->addErrors($bill->getErrors()); return false; } Yii::warning('产生账户快照', __METHOD__); //账户快照产生 $accountLog = new UserAccountLog(); $accountLog->uid = $userAccount->uid; $accountLog->account_type = $userAccount->type; $accountLog->currency = $currency; if (!$freezeCat) { $accountLog->trans_id = $trans->id; } else { $accountLog->trans_id = $freeze->id; } $accountLog->balance = $userAccount->balance; $accountLog->deposit = $userAccount->deposit; $accountLog->frozen_money = $userAccount->frozen_money; $accountLog->balance_type = $balanceType; $accountLog->trans_money = $money; $accountLog->trans_desc = $description; Yii::warning('保存账户信息', __METHOD__); if (!$accountLog->save()) { //$this->addErrors($accountLog->getErrors()); Yii::warning('保存账户快照失败', __METHOD__); Yii::warning($accountLog->getErrors(), __METHOD__); return false; } else { Yii::warning('保存账户快照成功', __METHOD__); return true; } } else { return false; } }
/** * @brief 充值成功处理,第三方的只有充值成功通知,在支持成功之后的业务逻辑处理,支付宝和微信的所有回告都应该是充值接口 * * @param string $callback 回调函数,仅仅对需要对订单进行逻辑处理的操作有效,需要添加订单id为参数 * @return Trans object 返回充值支付的交易记录 * @see * @note * @author 吕宝贵 * @date 2015/12/06 21:14:32 **/ public function processChargePaySuccess($transId) { //获取交易记录 $trans = Trans::findOne($transId); if (!$trans) { $this->addError(__METHOD__, '对应的交易记录不存在'); return false; } //充值型trans,直接成功,设置交易信息 $trans->status = Trans::PAY_STATUS_FINISHED; if (!$trans->save()) { return false; } //为用户账户充值,充值成功即为一个事物,后续的购买判断在controller里面完成 $userAccount = $this->getUserAccount($trans->from_uid); if (!$this->plus($userAccount->uid, $trans->total_money, $trans->id, '用户账户充值')) { $this->addError(__METHOD__, '为账户充值时发生错误'); return false; } return $trans; }
/** * based on the pay form ,generate Trans, this method can be rewrite by the child class * * @return Trans 返回trans实例 */ public function getTrans() { $this->booking = Booking::findOne(['bid' => $this->booking_id, 'q_uid' => Yii::$app->user->identity['uid']]); if (empty($this->booking)) { $this->addError('booking_id', '指定的订单不存在'); return false; } //如果预定已经成功支付,则不允许用户进行第二次支付 if ($this->booking->status > BookingStatus::PAYSUCCESS) { $this->addError('booking_id', '订单已支付!'); return false; } if (empty($this->booking->trans_id)) { $this->trans = $this->generateTrans(); } else { $this->trans = Trans::findOne($this->booking->trans_id); } return $this->trans; }
/** * @brief 处理充值消息通知的action,对于notify来讲,不需要做页面跳转,只需要针对不同的支付方式返回对应的状态 * * @return public function * @retval * @see * @note * @author 吕宝贵 * @date 2015/12/09 23:30:24 **/ protected function processPayNotify($payChannelId) { $channels = PayChannel::find()->select(['id', 'name', 'alias'])->indexBy('id')->all(); //回调的时候,appId根据返回的参数来确定 $payment = new Payment($channels[$payChannelId]['alias']); //判断订单是否支付成功, 如果成功则进入成功处理逻辑 if ($payment->checkPayStatus() === false) { Yii::error('支付结果检查失败!'); $payment->replyFailureToServer(); exit; } $receivable = $payment->getReceivable(); if (!$receivable) { Yii::error('找不到对应的收款单!'); $payment->replyFailureToServer(); exit; } else { //如果收款单的付款成功事件已被处理,则直接返回服务器成功 if ($receivable->hasPaySucceeded()) { Yii::info('收款单已处理!'); $payment->replySuccessToServer(); exit; } } //如果checkPayStatus返回成功,代表支付成功,此时进行实际的业务处理 $transaction = Yii::$app->db->beginTransaction(); //设置支付的成功和失败回调函数,此处处理的主要是账户体系的逻辑 $handlers = ['paySuccessHandler' => [Yii::$app->account, 'processChargePaySuccess'], 'payFailHandler' => [Yii::$app->account, 'processPayFailure']]; $trans = null; //业务逻辑处理,此处应当判断订单是否成功 if ($transId = $payment->processNotify($handlers)) { //充值交易完成,在commit之后,需要回告给服务器 $transaction->commit(); $trans = Trans::findOne($transId); Yii::info('交易id为:' . $transId, 'account-pay-notify'); Yii::info('成功处理用户充值逻辑', 'account-pay-notify'); //如果交易存在关联的交易,则查询关联交易的信息,并尝试支付相应的关联订单,需要提供订单的回调函数 if ($trans->trans_id_ext) { //如果存在关联订单,需要开启新事务处理相关订单 Yii::info('存在关联交易,处理关联交易逻辑', 'account-pay-notify'); $transaction = Yii::$app->db->beginTransaction(); $transOrder = Trans::findOne($trans->trans_id_ext); if (!$transOrder) { $transaction->rollback(); Yii::warning('关联交易查询失败,并不存在该关联交易订单, 退出购买逻辑', 'account-pay-notify'); exit; } if (Yii::$app->account->pay($transOrder)) { //如果关联交易为产品购买 if ($transOrder->trans_type_id == Trans::TRANS_TYPE_TRADE) { $booking = Booking::findOne(['bid' => $transOrder->trans_id_ext]); if (!$booking) { $transaction->rollback(); Yii::warning('查询关联预订失败', 'account-pay-notify'); throw new LBUserException('查询关联订单信息失败', 2); exit; } Yii::info('关联预订信息获取成功', 'account-pay-notify'); $callbackData = ['bid' => $booking->bid, 'trans_id' => $booking->trans_id]; //此处的回调为业务上的订单处理回调 if (!Booking::processPaySuccess($callbackData)) { $transaction->rollback(); Yii::warning('关联预订处理操作失败', 'account-pay-notify'); throw new LBUserException('订单支付成功回调处理失败', 3); exit; } Yii::info('关联预订相关回调处理成功', 'account-pay-notify'); } $transaction->commit(); Yii::info('提交事务...', 'account-pay-notify'); //页面跳转逻辑 } else { $transaction->rollback(); Yii::error('用户付款失败', 'account-pay-notify'); exit; } } else { Yii::info('交易没有关联订单:', 'account-pay-notify'); Yii::info($trans); } } else { $transaction->rollback(); Yii::warning('处理支付成功失败...', 'account-pay-notify'); $payment->replyFailureToServer(); exit; } Yii::info('交易成功处理...', 'account-pay-notify'); $payment->replySuccessToServer(); exit; }