~~~ <?php /** * Created by PhpStorm. * User: Mikkle * QQ:776329498 * Date: 2018/4/3 * Time: 17:25 */ namespace app\base\service; use app\base\base\RedisInfoBase; use app\base\options\Fields; use mikkle\tp_wxpay\Wxpay; use think\Exception; use think\facade\Build; use think\facade\Config; use think\facade\Env; use think\facade\Log; class ChannelCenter extends RedisInfoBase { protected $table="mk_payment_channel"; //数据表的 protected $pk = "channel_id"; //数据表的主键 protected $debugHost = "http://pm.******"; protected $releaseHost = "http://pm.*********"; protected $wxpay; protected $wxpayUnifiedOrder; protected $wxpayJsapi; protected $wxpayNotifyUrl ="/weixin/api.callback/callbackWxPay"; protected $wxpayError; protected $isDebug=true; public function _initialize() { $this->initLoadTableData(); } public function initLoadTableData(){ //判断数据存在 并设置检查周期10分钟 if (!$this->checkLock("dataExists") && !$this->checkTableDataExists()){ throw new Exception("相关渠道数据不存在"); }else{ //设置检查锁10分钟 $this->setLock("dataExists",600); } //如果数据不存在 初始化读取数据 if (!$this->checkExists()){ $this->initTableData(); } } public function getWxpayOptions($refresh=false){ $refresh && $this->initTableData(); $options = $this->getInfoList([ "wxpay_app_id" ,"wxpay_secret","wxpay_mch_id","wxpay_key","ca_path","wxpay_cert_path","wxpay_cert_key_path","wxpay_callback_url" ]); return !empty( $options["wxpay_app_id"] ) ?[ "appid"=>$options["wxpay_app_id"], 'secret' => $options["wxpay_secret"], 'mch_id'=>$options["wxpay_mch_id"], 'key'=>$options["wxpay_key"], 'ca_path'=>$options["ca_path"] ? Env::get('root_path').$options["ca_path"] : "", 'cert_path'=>$options["wxpay_cert_path"] ? Env::get('root_path').$options["wxpay_cert_path"] : "", 'key_path'=>$options["wxpay_cert_key_path"] ? Env::get('root_path').$options["wxpay_cert_key_path"] : "", "callback_url"=>$options["wxpay_callback_url"], ] : [ ] ; } protected function getWechatOptions(){ $options = $this->getInfoList([ "wxpay_app_id" ,"wxpay_secret" ]); return [ 'appid'=>$options["wxpay_app_id"], 'appsecret'=>$options["wxpay_secret"], ]; } /** * title * description wxpay * User: Mikkle * QQ:776329498 * @return Wxpay */ public function wxpay(){ if (isset($this->wxpay )){ return $this->wxpay; } $this->wxpay = Wxpay::instance($this->getWxpayOptions()); return $this->wxpay ; } public function wxpayUnifiedOrder(){ if (isset($this->wxpayUnifiedOrder)){ return $this->wxpayUnifiedOrder; } $this->wxpayUnifiedOrder =$this->wxpay()->unifiedOrder(); return $this->wxpayUnifiedOrder; } public function wxpayJsapi(){ if (isset($this->wxpayJsapi)){ return $this->wxpayJsapi; } $this->wxpayJsapi =$this->wxpay()->jsApi(); return $this->wxpayJsapi; } protected function getWxpayNotifyUrl(){ $url = (Config::get("app_status")=="debug" ? $this->debugHost :$this->releaseHost) . $this->wxpayNotifyUrl; return $url ."/".Fields::$channelId."/".$this->infoId; } public function getWxpayPrepayId($param){ $param["body"]=" "; $param["notify_url"] = $this->getWxpayNotifyUrl(); $this->isDebug && Log::notice($param); $prepayId = $this->wxpayUnifiedOrder()->setParam($param )->getPrepayId(); if ($prepayId == false){ $this->isDebug && Log::notice($this->wxpayUnifiedOrder()->getResponse()); $this->wxpayError = $this->wxpayUnifiedOrder()->getResponseMsg() ; } return $prepayId; } public function getWxpayPayUrl($param,$type="MWEB"){ if ($type =="NATIVE"){ $param["trade_type"] ="NATIVE"; }else{ $param["trade_type"] ="MWEB"; } $param["body"]=" "; $param["notify_url"] = $this->getWxpayNotifyUrl(); $this->isDebug && Log::notice($param); $result = $this->wxpayUnifiedOrder()->setParam($param )->getPayUrl(); if ($result == false){ $this->isDebug && Log::notice($this->wxpayUnifiedOrder()->getResponse()); $this->wxpayError = $this->wxpayUnifiedOrder()->getResponseMsg() ; } return $result; } public function getWxpayGetJsapiPayParams($param){ $param["trade_type"]="JSAPI" ; /**交易类型 NATIVE MWEB JSAPI*/ $prepayId = $this->getWxpayPrepayId( $param ); if ( $prepayId ==false ){ return false ; } $payParams = $this->wxpayJsapi()->getJsPayParamsByPrepayId($prepayId) ; if ($payParams == false){ $this->wxpayError = $this->wxpayUnifiedOrder()->getResponseMsg() ; } return $payParams; } public function getWxpayError(){ return $this->wxpayError; } public function getRsaPublicCert(){ return $this->getInfoFieldValue("wxpay_ras_public_key"); } protected function refreshWxpayRsaPublicCert(){ $cert = $this->wxpay()->RsaPublicKey()->getRsaPublicKey(); if ($cert){ $this->setInfoFieldValue("wxpay_ras_public_key_",$cert); $this->updateTableData(["wxpay_ras_public_key_pkcs#1"]); } return $this->getInfoFieldValue( "wxpay_ras_public_key_pkcs#1" ); } } ~~~ ~~~ <?php /** * Created by PhpStorm. * User: Mikkle * QQ:776329498 * Date: 2018/5/25 * Time: 9:07 */ namespace app\base\service; use app\base\options\Fields; use app\base\options\Functions; use app\base\options\Rands; use app\base\options\Tables; use think\Db; use think\Exception; use think\facade\Hook; use think\facade\Log; class BalanceCenter { static protected $instance; protected $vendorId; protected $vendorCenter; protected $error; public static function instance($info_id) { $sn = md5(json_encode($info_id)); if (self::$instance[$sn]){ return self::$instance[$sn]; } return new static($info_id); } public function __construct($vendorId = "") { if (!empty($vendorId)) { $this->setVendorId($vendorId); } } public function setVendorId($vendorId="") { if (!empty($vendorId) && is_numeric( $vendorId ) && $this->checkVendorId( $vendorId ) ) { $this->vendorId = $vendorId ; } return $this; } protected function checkVendorId($infoId) { return AuthCenter::authVendorId($infoId); } public function wxPayToUser($data){ if ( ! $this->vendorId ){ $this->error = "未设置商户ID或设置信息错误" ; return false; } if ( !isset( $data[Fields::$vendorId]) || ! $this->checkVendorId($data[Fields::$vendorId]) ){ $this->error = "未设置转入商户ID或设置信息错误" ; return false; } if ( !isset( $data[Fields::$systemId]) || !AuthCenter::authVendorIdAttachSystem ($data[Fields::$vendorId] , $data[Fields::$systemId]) ){ $this->error = "SystemId 不存在" ; return false; } if ( !isset( $data[Fields::$amount]) || empty($data[Fields::$amount]) ){ $this->error = "余额 不存在" ; return false; } if ( !isset( $data[Fields::$openid]) || empty($data[Fields::$vendorId]) ){ $this->error = "OPENID 不存在" ; return false; } $channelId = DataCenter::getWxpayChannelIdBySystemId( $data[Fields::$systemId] ); $withdrawNum = Rands::createWithdrawSerialNumber(); $vendorInfo = DataCenter::getVendorInfoByVendorId($data[Fields::$vendorId]); if ($data[Fields::$amount] >$vendorInfo[Fields::$vendorAmount] ){ $this->error = "商户的余款不足" ; return false; } if ($data[Fields::$amount] >1000 ){ $this->error = "Debug测试提现金额不能大于 10元" ; return false; } $time = time(); $withdrawData =[ Fields::$withdrawNum => $withdrawNum, Fields::$withdrawType => 1, Fields::$systemId =>$data[Fields::$systemId], Fields::$vendorId =>$data[Fields::$vendorId], "wx_".Fields::$openid =>$data[Fields::$openid], Fields::$amount =>$data[Fields::$amount], Fields::$withdrawTime =>Rands::getTimeString($time), Fields::$status=>0, Fields::$createTime => $time, ]; $channelCenter = ChannelCenter::instance($channelId); $payCenter = $channelCenter->wxpay()->Transfers(); $result = $payCenter->setParam([ "partner_trade_no"=>$withdrawData[Fields::$withdrawNum], "openid"=>$withdrawData["wx_".Fields::$openid], "check_name"=>"NO_CHECK", "amount"=>$withdrawData[Fields::$amount], "desc"=>"测试" ])->payToUser(); if (! $result || !is_array($result ) || ! isset( $result["result_code"]) || $result["result_code"] != "SUCCESS" ){ Db::table(Tables::$paymentSystemVendorWithdraw ) ->insert( $withdrawData); $this->error = "提交提现记录失败" ; return false; } if (! isset( $result["payment_no"]) || ! isset( $result["payment_time"] )){ Log::notice($result); Db::table(Tables::$paymentSystemVendorWithdraw ) ->insert( $withdrawData); $this->error = "提交提现记录解析返回数据出错" ; return false; } $withdrawData["payment_no"] =$result["payment_no"]; $withdrawData["payment_time"] =$result["payment_time"]; $withdrawData[Fields::$status] =1; if (! Db::table(Tables::$paymentSystemVendorWithdraw ) ->insert( $withdrawData)){ Log::notice($withdrawData); $this->error = "存储提现信息失败" ; Hook::listen("payment_error",$withdrawData); return false; } if ($this->completeWxPayToUser( $withdrawData )){ return true; }else{ $this->error = "存储提现信息失败" ; Hook::listen("payment_error",$withdrawData); return false; } } public function completeWxPayToUser($data){ //获取当前的收费员的帐号余额和版本号 $vendorAmount = Db::table(Tables::$paymentSystemVendor) ->where([Fields::$vendorId =>$data[Fields::$vendorId],Fields::$status=>1]) ->field([Fields::$vendorId,Fields::$vendorAmount,Fields::$vendorAmountVersion])->find(); if (!is_numeric($vendorAmount[Fields::$vendorAmount]) || !is_numeric($vendorAmount[Fields::$vendorAmountVersion]) ){ throw new Exception("商户的余款数据不正确"); } $amount = (int)$vendorAmount[Fields::$vendorAmount]; $newAmount = $amount - (int)$data[Fields::$amount]; $version = (int)$vendorAmount[Fields::$vendorAmountVersion]; //收费员账户流水表信息 $vendorIncomeDate = [ Fields::$incomeNum=>Rands::createIncomeSerialNumber(), Fields::$systemId=>$data[Fields::$systemId], Fields::$vendorId=>$data[Fields::$vendorId], Fields::$incomeType=>2, //流水类型 1 清算 2 提现 3 转入 4转出 5 冲正 Fields::$incomeMode=>2 , //流水模式 1 进账 2 出账 Fields::$money =>$data[Fields::$amount] , Fields::$vendorAmount =>$newAmount, Fields::$originalVendorAmount =>$amount, Fields::$vendorAmountVersion => $version+1, Fields::$withdrawNum=>$data[Fields::$withdrawNum], Fields::$desc=>"提现清算:{$data[Fields::$withdrawNum]} 转入", Fields::$status=>1, Fields::$incomeTime=>$data[Fields::$withdrawTime], Fields::$createTime=>$data[Fields::$createTime], ]; try{ //多表处理 开启事务 Db::startTrans(); //升级收费员余额 加入了乐观锁判断 if (!Db::table(Tables::$paymentSystemVendor) ->where([Fields::$vendorId=>$data[Fields::$vendorId],Fields::$vendorAmountVersion =>$version ]) ->update([Fields::$vendorAmount=>$newAmount,Fields::$vendorAmountVersion=>$version+1]) ){ throw new Exception("商户的余额信息已经变动,请重试"); } //插入商户金额流水信息 if (!Db::table(Tables::$paymentSystemIncome)->insert($vendorIncomeDate)){ throw new Exception("插入商户金额流水信息失败"); } Db::commit(); return true; }catch (Exception $e){ $this->error = $e->getMessage(); Log::error($e->getMessage()); Db::rollback(); return false; } } public function vendorTransfer($inVendorId,$mount){ if ( ! $this->vendorId ){ $this->error = "未设置商户ID或设置信息错误" ; return false; } if ( ! $this->checkVendorId($inVendorId) ){ $this->error = "未设置转入商户ID或设置信息错误" ; return false; } $transferData =[ "out_vendor"=>$this->vendorId, "in_vendor"=>$inVendorId, "amount"=>$mount ]; if ($this->completeTransfer( $transferData )){ return true; }else{ return false; } } protected function completeTransfer($data){ //获取当前的收费员的帐号余额和版本号 $vendorOut = Db::table(Tables::$paymentSystemVendor) ->where([Fields::$vendorId =>$data["out_vendor"],Fields::$status=>1]) ->field([Fields::$systemId,Fields::$vendorId,Fields::$vendorName,Fields::$vendorAmount,Fields::$vendorAmountVersion])->find(); if (!is_numeric($vendorOut[Fields::$vendorAmount]) || !is_numeric($vendorOut[Fields::$vendorAmountVersion]) ){ throw new Exception("商户的余款数据不正确"); } if ($data["amount"] >$vendorOut[Fields::$vendorAmount] ){ throw new Exception("商户的余款不足"); } $vendorIn = Db::table(Tables::$paymentSystemVendor) ->where([Fields::$vendorId =>$data["in_vendor"],Fields::$status=>1]) ->field([Fields::$systemId,Fields::$vendorId,Fields::$vendorName,Fields::$vendorAmount,Fields::$vendorAmountVersion])->find(); if ($vendorOut[Fields::$systemId] !=$vendorIn[Fields::$systemId] ){ throw new Exception("不容许跨平台间的商户转账"); } $amountOut = (int)$vendorOut[Fields::$vendorAmount]; $newAmountOut =$amountOut - (int)$data["amount"] ; $versionOut = (int)$vendorOut[Fields::$vendorAmountVersion]; $amountIn= (int)$vendorIn[Fields::$vendorAmount]; $newAmountIn =$amountIn + (int)$data["amount"] ; $versionIn= (int)$vendorIn[Fields::$vendorAmountVersion]; $time =time(); $transferNum = Rands::createTransferSerialNumber(); $transferData = [ "transfer_num" => $transferNum, "system_id"=>$vendorOut[Fields::$systemId], "out_vendor_id"=>$data["out_vendor"], "out_vendor_name"=>$vendorOut[Fields::$vendorName], "in_vendor_id"=>$data["in_vendor"], "in_vendor_name"=>$vendorIn[Fields::$vendorName], "amount"=>$data["amount"], "transfer_time"=>Rands::getDateString( $time ), "status"=>1, "create_time"=>$time, ]; //商户出账流水表信息 $vendorIncomeDateOut = [ Fields::$incomeNum=>Rands::createIncomeSerialNumber(), Fields::$systemId=>$vendorOut[Fields::$systemId], Fields::$vendorId=>$vendorOut[Fields::$vendorId], Fields::$incomeType=>4, //流水类型 1 清算 2 提现 3 转入 4转出 5 冲正 Fields::$incomeMode=>2 , //流水模式 1 进账 2 出账 Fields::$money =>$data["amount"], Fields::$vendorAmount =>$newAmountOut, Fields::$originalVendorAmount =>$amountOut, Fields::$vendorAmountVersion => $versionOut+1, Fields::$transferNum=>$transferNum, Fields::$desc=>"商户内转账:{$data[Fields::$balanceNum]} 的转出付款", Fields::$status=>1, Fields::$incomeTime=>Rands::getDateString( $time ), Fields::$createTime=>$time, ]; //商户入账账户流水表信息 $vendorIncomeDateIn = [ Fields::$incomeNum=>Rands::createIncomeSerialNumber(), Fields::$systemId=>$vendorIn[Fields::$systemId], Fields::$vendorId=>$vendorIn[Fields::$vendorId], Fields::$incomeType=>3, //流水类型 1 清算 2 提现 3 转入 4转出 5 冲正 Fields::$incomeMode=>1 , //流水模式 1 进账 2 出账 Fields::$money =>$data["amount"], Fields::$vendorAmount =>$newAmountIn, Fields::$originalVendorAmount =>$amountIn, Fields::$vendorAmountVersion => $versionIn+1, Fields::$transferNum=>$transferNum, Fields::$desc=>"商户内转账:{$data[Fields::$balanceNum]} 的转入付款", Fields::$status=>1, Fields::$incomeTime=>Rands::getDateString( $time ), Fields::$createTime=>$time, ]; try{ //多表处理 开启事务 Db::startTrans(); //升级商户余额 加入了乐观锁判断 出账 if (!Db::table(Tables::$paymentSystemVendor) ->where([Fields::$vendorId=>$vendorOut[Fields::$vendorId],Fields::$vendorAmountVersion =>$versionOut ]) ->update([Fields::$vendorAmount=>$newAmountOut,Fields::$vendorAmountVersion=>$versionOut+1]) ){ throw new Exception("出账商户的余额信息已经变动,请重试"); } //升级商户余额 加入了乐观锁判断 入账 if (!Db::table(Tables::$paymentSystemVendor) ->where([Fields::$vendorId=>$vendorIn[Fields::$vendorId],Fields::$vendorAmountVersion =>$versionIn ]) ->update([Fields::$vendorAmount=>$newAmountIn,Fields::$vendorAmountVersion=>$versionIn+1]) ){ throw new Exception("入账商户的余额信息已经变动,请重试"); } //插入结算流水信息 if (!Db::table(Tables::$paymentSystemVendorTransfer)->insert($transferData)){ throw new Exception("插入结算流水信息失败"); } //插入商户金额流水信息 if (!Db::table(Tables::$paymentSystemIncome)->insert($vendorIncomeDateOut)){ throw new Exception("插入商户出账金额流水信息失败"); } //插入商户金额流水信息 if (!Db::table(Tables::$paymentSystemIncome)->insert($vendorIncomeDateIn)){ throw new Exception("插入商户入账金额流水信息失败"); } Db::commit(); return true; }catch (Exception $e){ $this->error = $e->getMessage(); Log::error($e->getMessage()); Db::rollback(); return false; } } public function balancePay($payNum){ if ( ! $this->vendorId ){ $this->error = "未设置商户ID或设置信息错误" ; return false; } $payInfo = DataCenter::getPayInfoByPayNum($payNum); if ( empty( $payInfo ) || $payInfo[Fields::$status]>1){ $this->error = "付款信息不存在或者已经结算" ; return false; } $this->vendorCenter =VendorCenter::instance( $this->vendorId ); $balanceRate = $this->vendorCenter->getInfoFieldValue("balance_rate"); if ( !Functions::checkBalanceRate( $balanceRate )){ $this->error = "结算手续费不合法" ; return false; } $balanceNum = Rands::createBalanceSerialNumber(); //手续费 四舍五入 取整分 $balanceCharge = round ($payInfo[Fields::$payMoney] * $balanceRate ); $time =time() ; $balanceData = [ Fields::$balanceNum => $balanceNum, Fields::$systemId => $payInfo[Fields::$systemId], Fields::$vendorId => $payInfo[Fields::$vendorId], Fields::$channelId => $payInfo[Fields::$channelId], Fields::$wxBillNum => $payInfo[Fields::$wxBillNum], Fields::$billNum => $payInfo[Fields::$billNum], Fields::$payNum => $payInfo[Fields::$payNum], Fields::$payMoney => $payInfo[Fields::$payMoney], Fields::$balanceRate =>$balanceRate, Fields::$balanceCharge => $balanceCharge, Fields::$balanceMoney=> $payInfo[Fields::$payMoney] - $balanceCharge, Fields::$status=>1, Fields::$balanceTime => Rands::getTimeString( $time), Fields::$createTime => $time, ]; if ($this->completeBalance( $balanceData )){ return true; }else{ return false; } } protected function completeBalance($data){ //获取当前的收费员的帐号余额和版本号 $vendorAmount = Db::table(Tables::$paymentSystemVendor) ->where([Fields::$vendorId =>$data[Fields::$vendorId],Fields::$status=>1]) ->field([Fields::$vendorId,Fields::$vendorAmount,Fields::$vendorAmountVersion])->find(); if (!is_numeric($vendorAmount[Fields::$vendorAmount]) || !is_numeric($vendorAmount[Fields::$vendorAmountVersion]) ){ throw new Exception("商户的余款数据不正确"); } $amount = (int)$vendorAmount[Fields::$vendorAmount]; $newAmount = $amount + (int)$data[Fields::$balanceMoney]; $version = (int)$vendorAmount[Fields::$vendorAmountVersion]; //收费员账户流水表信息 $vendorIncomeDate = [ Fields::$incomeNum=>Rands::createIncomeSerialNumber(), Fields::$systemId=>$data[Fields::$systemId], Fields::$vendorId=>$data[Fields::$vendorId], Fields::$incomeType=>1, //流水类型 1 清算 2 提现 3 转入 4转出 5 冲正 Fields::$incomeMode=>1 , //流水模式 1 进账 2 出账 Fields::$money =>$data[Fields::$balanceMoney] , Fields::$vendorAmount =>$newAmount, Fields::$originalVendorAmount =>$amount, Fields::$vendorAmountVersion => $version+1, Fields::$balanceNum=>$data[Fields::$balanceNum], Fields::$desc=>"付款清算:{$data[Fields::$balanceNum]} 转入", Fields::$status=>1, Fields::$incomeTime=>$data[Fields::$balanceTime], Fields::$createTime=>$data[Fields::$createTime], ]; try{ //多表处理 开启事务 Db::startTrans(); //升级收费员余额 加入了乐观锁判断 if (!Db::table(Tables::$paymentSystemVendor) ->where([Fields::$vendorId=>$data[Fields::$vendorId],Fields::$vendorAmountVersion =>$version ]) ->update([Fields::$vendorAmount=>$newAmount,Fields::$vendorAmountVersion=>$version+1]) ){ throw new Exception("商户的余额信息已经变动,请重试"); } //升级付款表为已经结算状态 if (!Db::table(Tables::$paymentPay)->where([ Fields::$payNum=>$data[Fields::$payNum],Fields::$status=>1, ])->update([Fields::$status=>2,Fields::$balanceTime=>$data[Fields::$createTime]])){ throw new Exception("升级付款表失败"); } //插入结算流水信息 if (!Db::table(Tables::$paymentPayBalance)->insert($data)){ throw new Exception("插入结算流水信息失败"); } //插入商户金额流水信息 if (!Db::table(Tables::$paymentSystemIncome)->insert($vendorIncomeDate)){ throw new Exception("插入商户金额流水信息失败"); } Db::commit(); return true; }catch (Exception $e){ $this->error = $e->getMessage(); Log::error($e->getMessage()); Db::rollback(); return false; } } public function getError(){ return $this->error; } } ~~~ ~~~ <?php /** * Created by PhpStorm. * User: Mikkle * QQ:776329498 * Date: 2018/5/18 * Time: 9:49 */ namespace app\base\service; use app\base\base\RedisInfoBase; use app\base\options\Fields; use app\base\options\Rands; use app\base\options\Tables; use app\worker\push\PushPayMessageHandle; use think\Db; use think\Exception; use think\facade\Hook; use think\facade\Log; class BillCenter extends RedisInfoBase { protected $table="mk_payment_bill"; //数据表的 protected $pk = "out_trade_no"; //数据表的主键 public function completeBillByWxPayCallback($data){ if (Db::table(Tables::$paymentPay)->where([Fields::$wxBillNum=>$this->infoId])->count()>0){ $this->addError("已经处理过本条付款信息"); return false ; } $payNum= Rands::createPaySerialNumber(); $billInfo =$this->getInfoList( [ Fields::$systemId,Fields::$channelId,Fields::$channelType,Fields::$billNum,Fields::$notifyUrl,Fields::$vendorId ]); $time = time(); $payData =[ Fields::$payNum =>$payNum, Fields::$systemId => $billInfo[Fields::$systemId], Fields::$vendorId=>$billInfo[Fields::$vendorId], Fields::$wxBillNum=>$this->infoId, Fields::$billNum=>$billInfo[Fields::$billNum], Fields::$channelId => $billInfo[Fields::$channelId], Fields::$channelType => $billInfo[Fields::$channelType], Fields::$tradeType=>$data[Fields::$tradeType], Fields::$payMoney => $data[Fields::$payMoney], Fields::$payTime=>$data["time_end"], Fields::$status=>1, Fields::$createTime => $time, ]; $billData =[ Fields::$status=>2, Fields::$payMoney => $data[Fields::$payMoney], Fields::$payTime=>$data["time_end"], Fields::$payStatus=>2, Fields::$status=>2, Fields::$completeTime => $time, ]; if ($this->saveCompleteBillData($payData,$billData)){ //更新流水信息 $this->setInfoArray($billData); $this->setExpire(3600*24*7); $this->pushPayMessage($billInfo[Fields::$notifyUrl],$payData); $hookData = [Fields::$payNum =>$payNum,Fields::$vendorId=>$billInfo[Fields::$vendorId]]; Hook::listen(Fields::$hookCompletePay, $hookData); //更新帐号余额 return true; }else{ return false; } } protected function saveCompleteBillData($payData,$billData){ try{ //多表处理 开启事务 Db::startTrans(); //插入付款流水信息 if (!Db::table(Tables::$paymentPay)->insert($payData)){ throw new Exception("插入付款流水信息失败"); } $map = [ [Fields::$wxBillNum, "=", $this->infoId], [Fields::$status, "<>", 2] ]; if (!Db::table(Tables::$paymentBill)->where($map)->update($billData)){ Log::notice($map); Log::notice($billData); throw new Exception("完成账单信息失败"); } Db::commit(); return true; }catch (Exception $e){ Db::rollback(); Log::error($e->getMessage()); return false; } } public function pushPayMessage($url,$pushData){ unset($pushData[Fields::$createTime]); unset($pushData[Fields::$status]); unset($pushData[Fields::$wxBillNum]); $data =[ "url"=>$url, "result"=>$pushData, ]; return PushPayMessageHandle::add( $data ); } } ~~~ ~~~ <?php /** * Created by PhpStorm. * User: Mikkle * QQ:776329498 * Date: 2018/5/25 * Time: 9:07 */ namespace app\base\service; use app\base\options\Fields; use app\base\options\Functions; use app\base\options\Rands; use app\base\options\Tables; use think\Db; use think\Exception; use think\facade\Hook; use think\facade\Log; class BalanceCenter { static protected $instance; protected $vendorId; protected $vendorCenter; protected $error; public static function instance($info_id) { $sn = md5(json_encode($info_id)); if (self::$instance[$sn]){ return self::$instance[$sn]; } return new static($info_id); } public function __construct($vendorId = "") { if (!empty($vendorId)) { $this->setVendorId($vendorId); } } public function setVendorId($vendorId="") { if (!empty($vendorId) && is_numeric( $vendorId ) && $this->checkVendorId( $vendorId ) ) { $this->vendorId = $vendorId ; } return $this; } protected function checkVendorId($infoId) { return AuthCenter::authVendorId($infoId); } public function wxPayToUser($data){ if ( ! $this->vendorId ){ $this->error = "未设置商户ID或设置信息错误" ; return false; } if ( !isset( $data[Fields::$vendorId]) || ! $this->checkVendorId($data[Fields::$vendorId]) ){ $this->error = "未设置转入商户ID或设置信息错误" ; return false; } if ( !isset( $data[Fields::$systemId]) || !AuthCenter::authVendorIdAttachSystem ($data[Fields::$vendorId] , $data[Fields::$systemId]) ){ $this->error = "SystemId 不存在" ; return false; } if ( !isset( $data[Fields::$amount]) || empty($data[Fields::$amount]) ){ $this->error = "余额 不存在" ; return false; } if ( !isset( $data[Fields::$openid]) || empty($data[Fields::$vendorId]) ){ $this->error = "OPENID 不存在" ; return false; } $channelId = DataCenter::getWxpayChannelIdBySystemId( $data[Fields::$systemId] ); $withdrawNum = Rands::createWithdrawSerialNumber(); $vendorInfo = DataCenter::getVendorInfoByVendorId($data[Fields::$vendorId]); if ($data[Fields::$amount] >$vendorInfo[Fields::$vendorAmount] ){ $this->error = "商户的余款不足" ; return false; } if ($data[Fields::$amount] >1000 ){ $this->error = "Debug测试提现金额不能大于 10元" ; return false; } $time = time(); $withdrawData =[ Fields::$withdrawNum => $withdrawNum, Fields::$withdrawType => 1, Fields::$systemId =>$data[Fields::$systemId], Fields::$vendorId =>$data[Fields::$vendorId], "wx_".Fields::$openid =>$data[Fields::$openid], Fields::$amount =>$data[Fields::$amount], Fields::$withdrawTime =>Rands::getTimeString($time), Fields::$status=>0, Fields::$createTime => $time, ]; $channelCenter = ChannelCenter::instance($channelId); $payCenter = $channelCenter->wxpay()->Transfers(); $result = $payCenter->setParam([ "partner_trade_no"=>$withdrawData[Fields::$withdrawNum], "openid"=>$withdrawData["wx_".Fields::$openid], "check_name"=>"NO_CHECK", "amount"=>$withdrawData[Fields::$amount], "desc"=>"测试" ])->payToUser(); if (! $result || !is_array($result ) || ! isset( $result["result_code"]) || $result["result_code"] != "SUCCESS" ){ Db::table(Tables::$paymentSystemVendorWithdraw ) ->insert( $withdrawData); $this->error = "提交提现记录失败" ; return false; } if (! isset( $result["payment_no"]) || ! isset( $result["payment_time"] )){ Log::notice($result); Db::table(Tables::$paymentSystemVendorWithdraw ) ->insert( $withdrawData); $this->error = "提交提现记录解析返回数据出错" ; return false; } $withdrawData["payment_no"] =$result["payment_no"]; $withdrawData["payment_time"] =$result["payment_time"]; $withdrawData[Fields::$status] =1; if (! Db::table(Tables::$paymentSystemVendorWithdraw ) ->insert( $withdrawData)){ Log::notice($withdrawData); $this->error = "存储提现信息失败" ; Hook::listen("payment_error",$withdrawData); return false; } if ($this->completeWxPayToUser( $withdrawData )){ return true; }else{ $this->error = "存储提现信息失败" ; Hook::listen("payment_error",$withdrawData); return false; } } public function completeWxPayToUser($data){ //获取当前的收费员的帐号余额和版本号 $vendorAmount = Db::table(Tables::$paymentSystemVendor) ->where([Fields::$vendorId =>$data[Fields::$vendorId],Fields::$status=>1]) ->field([Fields::$vendorId,Fields::$vendorAmount,Fields::$vendorAmountVersion])->find(); if (!is_numeric($vendorAmount[Fields::$vendorAmount]) || !is_numeric($vendorAmount[Fields::$vendorAmountVersion]) ){ throw new Exception("商户的余款数据不正确"); } $amount = (int)$vendorAmount[Fields::$vendorAmount]; $newAmount = $amount - (int)$data[Fields::$amount]; $version = (int)$vendorAmount[Fields::$vendorAmountVersion]; //收费员账户流水表信息 $vendorIncomeDate = [ Fields::$incomeNum=>Rands::createIncomeSerialNumber(), Fields::$systemId=>$data[Fields::$systemId], Fields::$vendorId=>$data[Fields::$vendorId], Fields::$incomeType=>2, //流水类型 1 清算 2 提现 3 转入 4转出 5 冲正 Fields::$incomeMode=>2 , //流水模式 1 进账 2 出账 Fields::$money =>$data[Fields::$amount] , Fields::$vendorAmount =>$newAmount, Fields::$originalVendorAmount =>$amount, Fields::$vendorAmountVersion => $version+1, Fields::$withdrawNum=>$data[Fields::$withdrawNum], Fields::$desc=>"提现清算:{$data[Fields::$withdrawNum]} 转入", Fields::$status=>1, Fields::$incomeTime=>$data[Fields::$withdrawTime], Fields::$createTime=>$data[Fields::$createTime], ]; try{ //多表处理 开启事务 Db::startTrans(); //升级收费员余额 加入了乐观锁判断 if (!Db::table(Tables::$paymentSystemVendor) ->where([Fields::$vendorId=>$data[Fields::$vendorId],Fields::$vendorAmountVersion =>$version ]) ->update([Fields::$vendorAmount=>$newAmount,Fields::$vendorAmountVersion=>$version+1]) ){ throw new Exception("商户的余额信息已经变动,请重试"); } //插入商户金额流水信息 if (!Db::table(Tables::$paymentSystemIncome)->insert($vendorIncomeDate)){ throw new Exception("插入商户金额流水信息失败"); } Db::commit(); return true; }catch (Exception $e){ $this->error = $e->getMessage(); Log::error($e->getMessage()); Db::rollback(); return false; } } public function vendorTransfer($inVendorId,$mount){ if ( ! $this->vendorId ){ $this->error = "未设置商户ID或设置信息错误" ; return false; } if ( ! $this->checkVendorId($inVendorId) ){ $this->error = "未设置转入商户ID或设置信息错误" ; return false; } $transferData =[ "out_vendor"=>$this->vendorId, "in_vendor"=>$inVendorId, "amount"=>$mount ]; if ($this->completeTransfer( $transferData )){ return true; }else{ return false; } } protected function completeTransfer($data){ //获取当前的收费员的帐号余额和版本号 $vendorOut = Db::table(Tables::$paymentSystemVendor) ->where([Fields::$vendorId =>$data["out_vendor"],Fields::$status=>1]) ->field([Fields::$systemId,Fields::$vendorId,Fields::$vendorName,Fields::$vendorAmount,Fields::$vendorAmountVersion])->find(); if (!is_numeric($vendorOut[Fields::$vendorAmount]) || !is_numeric($vendorOut[Fields::$vendorAmountVersion]) ){ throw new Exception("商户的余款数据不正确"); } if ($data["amount"] >$vendorOut[Fields::$vendorAmount] ){ throw new Exception("商户的余款不足"); } $vendorIn = Db::table(Tables::$paymentSystemVendor) ->where([Fields::$vendorId =>$data["in_vendor"],Fields::$status=>1]) ->field([Fields::$systemId,Fields::$vendorId,Fields::$vendorName,Fields::$vendorAmount,Fields::$vendorAmountVersion])->find(); if ($vendorOut[Fields::$systemId] !=$vendorIn[Fields::$systemId] ){ throw new Exception("不容许跨平台间的商户转账"); } $amountOut = (int)$vendorOut[Fields::$vendorAmount]; $newAmountOut =$amountOut - (int)$data["amount"] ; $versionOut = (int)$vendorOut[Fields::$vendorAmountVersion]; $amountIn= (int)$vendorIn[Fields::$vendorAmount]; $newAmountIn =$amountIn + (int)$data["amount"] ; $versionIn= (int)$vendorIn[Fields::$vendorAmountVersion]; $time =time(); $transferNum = Rands::createTransferSerialNumber(); $transferData = [ "transfer_num" => $transferNum, "system_id"=>$vendorOut[Fields::$systemId], "out_vendor_id"=>$data["out_vendor"], "out_vendor_name"=>$vendorOut[Fields::$vendorName], "in_vendor_id"=>$data["in_vendor"], "in_vendor_name"=>$vendorIn[Fields::$vendorName], "amount"=>$data["amount"], "transfer_time"=>Rands::getDateString( $time ), "status"=>1, "create_time"=>$time, ]; //商户出账流水表信息 $vendorIncomeDateOut = [ Fields::$incomeNum=>Rands::createIncomeSerialNumber(), Fields::$systemId=>$vendorOut[Fields::$systemId], Fields::$vendorId=>$vendorOut[Fields::$vendorId], Fields::$incomeType=>4, //流水类型 1 清算 2 提现 3 转入 4转出 5 冲正 Fields::$incomeMode=>2 , //流水模式 1 进账 2 出账 Fields::$money =>$data["amount"], Fields::$vendorAmount =>$newAmountOut, Fields::$originalVendorAmount =>$amountOut, Fields::$vendorAmountVersion => $versionOut+1, Fields::$transferNum=>$transferNum, Fields::$desc=>"商户内转账:{$data[Fields::$balanceNum]} 的转出付款", Fields::$status=>1, Fields::$incomeTime=>Rands::getDateString( $time ), Fields::$createTime=>$time, ]; //商户入账账户流水表信息 $vendorIncomeDateIn = [ Fields::$incomeNum=>Rands::createIncomeSerialNumber(), Fields::$systemId=>$vendorIn[Fields::$systemId], Fields::$vendorId=>$vendorIn[Fields::$vendorId], Fields::$incomeType=>3, //流水类型 1 清算 2 提现 3 转入 4转出 5 冲正 Fields::$incomeMode=>1 , //流水模式 1 进账 2 出账 Fields::$money =>$data["amount"], Fields::$vendorAmount =>$newAmountIn, Fields::$originalVendorAmount =>$amountIn, Fields::$vendorAmountVersion => $versionIn+1, Fields::$transferNum=>$transferNum, Fields::$desc=>"商户内转账:{$data[Fields::$balanceNum]} 的转入付款", Fields::$status=>1, Fields::$incomeTime=>Rands::getDateString( $time ), Fields::$createTime=>$time, ]; try{ //多表处理 开启事务 Db::startTrans(); //升级商户余额 加入了乐观锁判断 出账 if (!Db::table(Tables::$paymentSystemVendor) ->where([Fields::$vendorId=>$vendorOut[Fields::$vendorId],Fields::$vendorAmountVersion =>$versionOut ]) ->update([Fields::$vendorAmount=>$newAmountOut,Fields::$vendorAmountVersion=>$versionOut+1]) ){ throw new Exception("出账商户的余额信息已经变动,请重试"); } //升级商户余额 加入了乐观锁判断 入账 if (!Db::table(Tables::$paymentSystemVendor) ->where([Fields::$vendorId=>$vendorIn[Fields::$vendorId],Fields::$vendorAmountVersion =>$versionIn ]) ->update([Fields::$vendorAmount=>$newAmountIn,Fields::$vendorAmountVersion=>$versionIn+1]) ){ throw new Exception("入账商户的余额信息已经变动,请重试"); } //插入结算流水信息 if (!Db::table(Tables::$paymentSystemVendorTransfer)->insert($transferData)){ throw new Exception("插入结算流水信息失败"); } //插入商户金额流水信息 if (!Db::table(Tables::$paymentSystemIncome)->insert($vendorIncomeDateOut)){ throw new Exception("插入商户出账金额流水信息失败"); } //插入商户金额流水信息 if (!Db::table(Tables::$paymentSystemIncome)->insert($vendorIncomeDateIn)){ throw new Exception("插入商户入账金额流水信息失败"); } Db::commit(); return true; }catch (Exception $e){ $this->error = $e->getMessage(); Log::error($e->getMessage()); Db::rollback(); return false; } } public function balancePay($payNum){ if ( ! $this->vendorId ){ $this->error = "未设置商户ID或设置信息错误" ; return false; } $payInfo = DataCenter::getPayInfoByPayNum($payNum); if ( empty( $payInfo ) || $payInfo[Fields::$status]>1){ $this->error = "付款信息不存在或者已经结算" ; return false; } $this->vendorCenter =VendorCenter::instance( $this->vendorId ); $balanceRate = $this->vendorCenter->getInfoFieldValue("balance_rate"); if ( !Functions::checkBalanceRate( $balanceRate )){ $this->error = "结算手续费不合法" ; return false; } $balanceNum = Rands::createBalanceSerialNumber(); //手续费 四舍五入 取整分 $balanceCharge = round ($payInfo[Fields::$payMoney] * $balanceRate ); $time =time() ; $balanceData = [ Fields::$balanceNum => $balanceNum, Fields::$systemId => $payInfo[Fields::$systemId], Fields::$vendorId => $payInfo[Fields::$vendorId], Fields::$channelId => $payInfo[Fields::$channelId], Fields::$wxBillNum => $payInfo[Fields::$wxBillNum], Fields::$billNum => $payInfo[Fields::$billNum], Fields::$payNum => $payInfo[Fields::$payNum], Fields::$payMoney => $payInfo[Fields::$payMoney], Fields::$balanceRate =>$balanceRate, Fields::$balanceCharge => $balanceCharge, Fields::$balanceMoney=> $payInfo[Fields::$payMoney] - $balanceCharge, Fields::$status=>1, Fields::$balanceTime => Rands::getTimeString( $time), Fields::$createTime => $time, ]; if ($this->completeBalance( $balanceData )){ return true; }else{ return false; } } protected function completeBalance($data){ //获取当前的收费员的帐号余额和版本号 $vendorAmount = Db::table(Tables::$paymentSystemVendor) ->where([Fields::$vendorId =>$data[Fields::$vendorId],Fields::$status=>1]) ->field([Fields::$vendorId,Fields::$vendorAmount,Fields::$vendorAmountVersion])->find(); if (!is_numeric($vendorAmount[Fields::$vendorAmount]) || !is_numeric($vendorAmount[Fields::$vendorAmountVersion]) ){ throw new Exception("商户的余款数据不正确"); } $amount = (int)$vendorAmount[Fields::$vendorAmount]; $newAmount = $amount + (int)$data[Fields::$balanceMoney]; $version = (int)$vendorAmount[Fields::$vendorAmountVersion]; //收费员账户流水表信息 $vendorIncomeDate = [ Fields::$incomeNum=>Rands::createIncomeSerialNumber(), Fields::$systemId=>$data[Fields::$systemId], Fields::$vendorId=>$data[Fields::$vendorId], Fields::$incomeType=>1, //流水类型 1 清算 2 提现 3 转入 4转出 5 冲正 Fields::$incomeMode=>1 , //流水模式 1 进账 2 出账 Fields::$money =>$data[Fields::$balanceMoney] , Fields::$vendorAmount =>$newAmount, Fields::$originalVendorAmount =>$amount, Fields::$vendorAmountVersion => $version+1, Fields::$balanceNum=>$data[Fields::$balanceNum], Fields::$desc=>"付款清算:{$data[Fields::$balanceNum]} 转入", Fields::$status=>1, Fields::$incomeTime=>$data[Fields::$balanceTime], Fields::$createTime=>$data[Fields::$createTime], ]; try{ //多表处理 开启事务 Db::startTrans(); //升级收费员余额 加入了乐观锁判断 if (!Db::table(Tables::$paymentSystemVendor) ->where([Fields::$vendorId=>$data[Fields::$vendorId],Fields::$vendorAmountVersion =>$version ]) ->update([Fields::$vendorAmount=>$newAmount,Fields::$vendorAmountVersion=>$version+1]) ){ throw new Exception("商户的余额信息已经变动,请重试"); } //升级付款表为已经结算状态 if (!Db::table(Tables::$paymentPay)->where([ Fields::$payNum=>$data[Fields::$payNum],Fields::$status=>1, ])->update([Fields::$status=>2,Fields::$balanceTime=>$data[Fields::$createTime]])){ throw new Exception("升级付款表失败"); } //插入结算流水信息 if (!Db::table(Tables::$paymentPayBalance)->insert($data)){ throw new Exception("插入结算流水信息失败"); } //插入商户金额流水信息 if (!Db::table(Tables::$paymentSystemIncome)->insert($vendorIncomeDate)){ throw new Exception("插入商户金额流水信息失败"); } Db::commit(); return true; }catch (Exception $e){ $this->error = $e->getMessage(); Log::error($e->getMessage()); Db::rollback(); return false; } } public function getError(){ return $this->error; } } ~~~