'wx7a48de22423333c3', // 'secret' => '5306eb0f85490248e2f39e51dbbd6de3', 'app_id' => 'wx088555482d9bae2b', 'secret' => 'b8a3a0da52df81472af4ec1fbc4b571c', // 'response_type' => 'array', 'log' => [ 'level' => 'debug', 'file' => __DIR__ . '/wechat_debug.log', ], ]; private $tpl1 = [ 'template_id' => 'bhkIzzwYpjjXJJ9lPdfXIsUYRrfSz52aJel1n74AA7A', // 所需下发的订阅模板id 'touser' => 'o11PJ5QDWJnIa1kPKsvvStXj243U', 'data' => [ ] ]; private $tpl2 = [ 'template_id' => '_3OK4582YpA9s5y_6D_dwewqxqEdsd9JNrhvBFQqcrI', // 所需下发的订阅模板id 'touser' => 'o11PJ5QDWJnIa1kPKsvvStXj243U', // 接收者(用户)的 openid 'page' => '/pages/index/index', // 点击模板卡片后的跳转页面,仅限本小程序内的页面。支持带参数,(示例index?foo=bar)。该字段不填则模板无跳转。 'data' => [ // 模板内容,格式形如 { "key1": { "value": any }, "key2": { "value": any } } 'thing1' => [ 'value' => '拼团返现奖励金', ], 'thing2' => [ 'value' => "快打开小程序,立即抢红包!", ] ] ]; private $tpl3 = [ 'template_id' => 'v2nNL6LKvYr0pyGsTBw5r9Zaa7lS63Hm5AjvJq-tKWc', // 所需下发的订阅模板id 'touser' => 'o11PJ5QDWJnIa1kPKsvvStXj243U', 'data' => [ ] ]; protected $wechat; /** * * @author 许祖兴 < zuxing.xu@lettered.cn> * @date 2020/7/1 14:46 */ public function initialize() { // 加载配置 $wechat = sys_config('', 'wechat'); //var_dump($wechat); $this->wechat = Factory::miniProgram([ 'app_id' => $wechat['mini_appid'], 'secret' => $wechat['mni_secret_key'], 'response_type' => 'array', 'log' => [ 'level' => 'debug', 'file' => app()->getRuntimePath() . 'log/' . date('Ym') . '/wechat_debug.log', ], ]); } /** * 获取微信session * * @return \think\response\Json * @author 许祖兴 < zuxing.xu@lettered.cn> * @date 2020/7/6 16:27 * */ public function getSession() { // 接收数据 $param = $this->request->param(); // 内置验证 $valid = $this->validate($param, [ 'code' => 'require' ]); // 错误 if (true !== $valid) { return $this->ApiJson(-1, $valid); } $session = $this->wechat->auth->session($param['code']); if (isset($session['errcode'])) { return $this->ApiJson(-1, '获取不到用户OpenId!'); } // 这里存在问题,建议修改 20210525,cache存在唯一,多个用户登录会有问题 // 写入缓存 Cache::set('wx_session', $session); return $this->ApiJson(0, 'OK!', $session); } /** * 前置验证 * * @return array|\think\response\Json * @author 许祖兴 < zuxing.xu@lettered.cn> * @date 2020/7/8 10:55 * */ private function preValidData() { // 接收数据 $param = $this->request->param(); // 内置验证 $valid = $this->validate($param, [ 'encryptedData' => 'require', 'iv' => 'require', ]); // 错误 if (true !== $valid) { return $this->ApiJson(-1, $valid); } return $param; } /** * 登录解密用户数据 * * @return \think\response\Json * @author 许祖兴 < zuxing.xu@lettered.cn> * @date 2020/7/6 16:27 * */ public function login() { // 验证 $param = $this->preValidData(); // 读取用户session $session = Cache::get('wx_session'); // app()->log(enjson([$param,$session,$parent]),'debug'); // die; try { // 解密用户信息 $decryptedData = $this->wechat->encryptor->decryptData($session['session_key'], $param['iv'], $param['encryptedData']); app()->log('decryptedData:' . enjson($decryptedData)); // 查用户 $model = model("common/Users"); if (!$user = $model->where(['open_id' => $session['openid']])->find()) { // 创建新用户 $model::create([ 'card_id' => make_mcard_id(), 'open_id' => $session['openid'], 'avatar_url' => $decryptedData['avatarUrl'], 'nickname' => $decryptedData['nickName'], 'gender' => $decryptedData['gender'] ], true); // 再查完整记录 $user = $model->where(['open_id' => $session['openid']])->find(); // 存在邀请码 if ($param['inviteCode'] !== "" && $param['inviteCode'] !== "undefined") { // 查找上级 $parent = model('common/UsersInvite')->getBy(['code' => $param['inviteCode']]); if ($parent) { // 写入关系 model('common/UsersInviteRelation')->storeBy([ 'form_id' => $parent['user_id'], 'invite_id' => $user['id'] ]); // 推荐奖励 $user_spread_property_reward = sys_config('user_spread_property_reward', 'user'); model('common/Users')->changeProperty( $parent['user_id'], $user_spread_property_reward, "推荐奖励,资产【" . round($user_spread_property_reward, 3) . '】', true ); // 更新上级字段 $user->updateBy($user['id'], [ 'parent_id' => $parent['user_id'] ]); } } } // 用户状态 if ($user['status'] == 0) { return $this->ApiJson(-1, '账号冻结,请联系客服'); } // 登录 $token = $this->auth->guard('user')->attempt($user); return $this->ApiJson(0, 'OK!', ['token' => 'Bearer ' . $token]); } catch (\Exception $e) { return $this->ApiJson(-1, $e->getMessage()); } } /** * 解密手机号 * * @return \think\response\Json * @author 许祖兴 < zuxing.xu@lettered.cn> * @date 2020/7/6 16:28 * */ public function mobile() { // 验证 $param = $this->preValidData(); // 读取用户session $session = Cache::get('wx_session'); try { // 解密用户信息 $decryptedData = $this->wechat->encryptor->decryptData($session['session_key'], $param['iv'], $param['encryptedData']); // 更新用户数据 model("common/Users")->update(['mobile' => $decryptedData['phoneNumber']], ['open_id' => $session['openid']]); return $this->ApiJson(0, 'OK!', $decryptedData); } catch (\Exception $e) { return $this->ApiJson(-1, $e->getMessage()); } } /** * 统一支付 * * @return \think\response\Json * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException * @throws \GuzzleHttp\Exception\GuzzleException * @throws \Lettered\Support\Exceptions\FailedException * @author 许祖兴 < zuxing.xu@lettered.cn> * @date 2020/7/7 10:27 * */ public function payment() { // 查 $param = $this->request->param(); $param['payType'] = input('payType', 'wechat'); // 数据校验 $valid = $this->validate($param, [ 'trade_no|支付单号' => 'require', 'payType|支付方式' => 'require' ]); // 错误 if (true !== $valid) { return $this->ApiJson(-1, $valid); } // 数据检查 $paylog = model('common/OrderPaylog')->getBy(['out_trade_no' => $param['trade_no']]); if (!$paylog) { return $this->ApiJson(-1, '本次交易不存在'); } if ($paylog['is_pay'] == 1) { return $this->ApiJson(-1, '本次交易已处理,请勿重复操作'); } // 选中支付方式 switch ($param['payType']) { case 'alipay': case 'wechat': return $this->thirdPayment($param['payType'], $paylog); break; case 'property': default: // 默认余额支付 // 1. 支付订单 // 2. 扣减余额 return $this->buyOnUserSelf($param['payType'], $paylog); break; } } /*** * * @return \think\response\Json * @throws \Lettered\Support\Exceptions\FailedException * @author 许祖兴 < zuxing.xu@lettered.cn> * @date 2020/7/15 11:00 * */ public function repay() { $param = $this->request->param(); // 数据校验 $valid = $this->validate($param, [ 'order_id|订单号' => 'require', ]); // 错误 if (true !== $valid) { return $this->ApiJson(-1, $valid); } // 订单信息 $order = model('common/GoodsOrder') ->getBy(['id' => $param['order_id'], 'user_id' => $this->auth->user()['id']]); // 数据检查 $paylog = model('common/OrderPaylog')->getBy(['order_idx' => $param['order_id'], 'ascription' => 'goods']); if (!$paylog) { return $this->ApiJson(-1, '本次交易不存在'); } if ($paylog['is_pay'] == 1) { return $this->ApiJson(-1, '本次交易已处理,请勿重复操作'); } // 是否有过记录 if (!$paylog) { // 二次创建子支付 $trade_no = get_order_no(); model('common/OrderPaylog')->storeBy([ 'order_idx' => $param['order_id'], 'out_trade_no' => $trade_no, 'total_price' => $order['total_price'], 'ascription' => 'goods' // 归属订单 ]); return $this->ApiJson(0, '获取支付信息成功', $trade_no); } // 再次支付 return $this->ApiJson(0, '获取支付信息成功', $paylog['out_trade_no']); } public function refund() { // 查 $param = $this->request->param(); $param['payType'] = input('payType', 'wechat'); // 数据校验 $valid = $this->validate($param, [ 'trade_no|支付单号' => 'require', 'payType|支付方式' => 'require' ]); // 错误 if (true !== $valid) { return $this->ApiJson(-1, $valid); } // 数据检查 $paylog = model('common/OrderPaylog')->getBy(['out_trade_no' => $param['trade_no']]); if (!$paylog) { return $this->ApiJson(-1, '本次交易不存在'); } if ($paylog['is_pay'] != 1) { return $this->ApiJson(-1, '本次交易未支付'); } return $this->thirdRefund('wechat', $paylog); } /** * 支付通知 * * @throws \EasyWeChat\Kernel\Exceptions\Exception * @author 许祖兴 < zuxing.xu@lettered.cn> * @date 2020/7/7 9:56 * */ public function paymentNotify() { // 加载配置 $wechat = sys_config('', 'wechat'); // 发起支付 $config = [ 'app_id' => $wechat['mini_appid'], 'mch_id' => $wechat['pay_mch_id'], 'key' => $wechat['pay_secret_key'], ]; app()->log("微信异步:" . enjson($config), 'debug'); // 创建应用实例 $payment = Factory::payment($config); Db::startTrans(); try { // 响应处理 $response = $payment->handlePaidNotify(function ($message, $fail) { app()->log("微信异步:" . enjson($message), 'debug'); // 获取支付订单 $order = model('common/OrderPaylog')->where(['out_trade_no' => $message['out_trade_no']])->lock(true)->find(); // 订单状态 if (!$order || $order->is_pay == 1) { return true; // 告诉微信,我已经处理完了,订单没找到,别再通知我了 } if ($message['return_code'] === 'SUCCESS' && $message['result_code'] === 'SUCCESS') { // return_code 表示通信状态,不代表支付状态 Log::debug(enjson($message)); // 支付成功 $pay_price = sprintf("%.2f", round($message['total_fee'] / 100, 2)); // 1. 支付订单状态is_pay =1 model('common/OrderPaylog')->updateBy($order['id'], [ 'pay_price' => $pay_price, 'is_pay' => 1, ]); // TODO 下面的写法我自己都看累,应该提出对应方法好处理写 =_= $thing5 = '感谢您的支持,我们将致力于更好的服务!'; // 2. 对归属订单状态处理 foreach (str2arr($order['order_idx']) as $orderId) { // 所属订单 //TODO 等待优化 $goodsOrder = []; // 模板消息标题 $tplTitle = ""; switch ($order['ascription']) { // 田地订单 case "farmland": $tplTitle = "人人接 - 田地服务"; $goodsOrder = model('common/FarmlandOrder')->getBy(['id' => $orderId]); model('common/FarmlandOrder')->updateBy($orderId, ['status' => 2, 'pay_type' => 'wechat']); // todo 停止本次招标 model('common/FarmlandBlock')->updateBy($goodsOrder['block_id'], [ 'status' => 2 // 1 可用 2 服务中 ]); push_socket_data('farmland', [ 'id' => $orderId, 'msg' => '有新的农田订单等待处理,点击前往!' ]); break; // 摩的订单 case "motor": $tplTitle = "人人接 - 摩的服务"; $goodsOrder = model('common/TaxiOrder')->getBy(['id' => $orderId]); model('common/TaxiOrder')->updateBy($orderId, ['status' => 2]); push_socket_data('motor', [ 'id' => $orderId, 'msg' => '有新的摩的订单等待处理,点击前往!' ]); // 订阅消息 $thing5 = '电话请保持通畅,师傅正在赶往路上,请稍候'; // 订单结算给摩的代理 //model('\app\api\model\taxi\Award')->send($goodsOrder); break; // 技能订单 case "skill": $tplTitle = "人人接 - 技能服务"; $goodsOrder = model('common/SkillOrder')->getBy(['id' => $orderId]); model('common/SkillOrder')->updateBy($orderId, ['status' => 2]); push_socket_data('skill', [ 'id' => $orderId, 'msg' => '有新的技能订单等待处理,点击前往!' ]); break; // 配送订单 case "mission": $tplTitle = "人人接 - 配送服务"; $goodsOrder = model('common/MissionOrder')->getBy(['id' => $orderId]); model('common/MissionOrder')->updateBy($orderId, ['status' => 2]); push_socket_data('mission', [ 'id' => $orderId, 'msg' => '有新的配送订单等待处理,点击前往!' ]); break; // 救援订单 case "rescue": $tplTitle = "人人接 - 救援服务"; $goodsOrder = model('common/RescueOrder')->getBy(['id' => $orderId]); model('common/RescueOrder')->updateBy($orderId, ['status' => 2]); push_socket_data('rescue', [ 'id' => $orderId, 'msg' => '有新的救援订单等待处理,点击前往!' ]); break; // 商品订单 case "goods": $tplTitle = "人人接 - 商品购买"; // 产品订单 $goodsOrder = model('common/GoodsOrder')->where(['id' => $orderId])->lock(true)->find(); // 已经支付过了 if ($goodsOrder['status'] !== 1) { return $fail('已经支付过了'); } // 获取当前支付订单是否为拼团 // todo if ($goodsOrder && $goodsOrder['is_pin']) { $this->dealWithPinOrder($pay_price, $goodsOrder); } else { // 0: 已关闭 1:待支付, 2:待发货,3:待收货 , 4: 已完成 , 5: 待开团 , 6: 未中团 // 数据更新 model('common/GoodsOrder')->updateBy($orderId, [ 'pay_price' => $pay_price, 'paid_at' => time(), 'status' => 2 ]); } $thing5 = '顾客您好您的订单已出库小哥预计十分钟送达'; push_socket_data('goods', [ 'id' => $orderId, 'msg' => '有新的商品订单等待处理,点击前往!' ]); break; // 司机升级订单 case "level": $tplTitle = "人人接 - 司机付费升级"; // 订单 $goodsOrder = UserPaymentOrder::where(['id' => $orderId])->find(); if (empty($goodsOrder)) { return $fail('订单不存在'); } // 已经支付过了 if ($goodsOrder['status'] !== 1) { return $fail('已经支付过了'); } $levelData = TaxiUsersLevel::where(['id' => $goodsOrder['source_id']])->find(); if (empty($levelData)) { return $fail('升级参数错误'); } // 数据更新 if (!UserPaymentOrder::where(['id' => $orderId])->update([ 'pay_at' => time(), 'status' => 2 ])) { return $fail('升级订单处理失败'); } if (!TaxiUser::where(['user_id' => $goodsOrder['user_id']])->update(['level' => $levelData['level']])) { return $fail('司机等级更新失败'); } $user = model('common/Users')->getBy(['id' => $goodsOrder['user_id']]); if (!Users::where(['id'=>$goodsOrder['user_id']])->update(['taxi_property'=> $goodsOrder['price']+$user['taxi_property']])) { return $fail('司机资产更新失败'); } $thing5 = '尊敬的用户您好,您的升级订单已经支付成功!'; break; case "motor_agent": $UserPaymentOrder = new UserPaymentOrder(); $goodsOrder = $UserPaymentOrder->with('agent,user') ->field('id,user_id,order_no,status') ->find($orderId); // 更新订单信息 $goodsOrder->status = 2; $goodsOrder->save(); // 更新摩的代理 $goodsOrder->agent->status = 40; $goodsOrder->agent->save(); // 更新用户信息 $goodsOrder->user->is_motor_agent = 2; $goodsOrder->user->save(); break; case "motor_driver": $UserPaymentOrder = new UserPaymentOrder(); $goodsOrder = $UserPaymentOrder->with('driver') ->field('id,user_id,order_no,status') ->find($orderId); // 更新订单信息 $goodsOrder->status = 2; $goodsOrder->save(); // 更新摩的代理 $goodsOrder->driver->status = 1; $goodsOrder->driver->save(); } // 获取用户 $user = model('common/Users')->getBy(['id' => $goodsOrder['user_id']]); // 用户消费金额处理 // 写入本次消费后总金额 $user_consume_total = $user['consume'] + $pay_price; model('common/Users')->updateBy($goodsOrder['user_id'], [ 'consume' => sprintf('%.2f', $user_consume_total) ]); // 3.查找用户消费获得资产奖励 if ($order['ascription'] == 'goods') { // 消费总额包含 商品、接单、技能、摩的 // 获取资产设置 $user_property_reward = sys_config('user_property_reward', 'user'); if ($user_property_reward != '') { foreach (str2arr($user_property_reward, ',') as $key => $reward) { list($select, $amount) = str2arr($reward, ":"); if ($amount == 0) continue; // 当前总消费达到奖励 if ($user_consume_total >= $select && $key == $user['property_count']) { //TODO 达到消费 -- 反奖励 model('common/Users')->changeProperty( $goodsOrder['user_id'], sprintf("%.2f", round($amount, 2)), "消费满 {$select},平台奖励资产【" . sprintf("%.2f", round($amount, 2)) . '】', true ); // 增加领取次数 model('common/Users')->where(['id' => $goodsOrder['user_id']]) ->setInc('property_count'); } } } } // 模板消息 $this->tpl1['touser'] = $user['open_id']; $this->tpl1['data'] = [ 'character_string1' => [ 'value' => $goodsOrder['order_no'], ], 'thing3' => [ 'value' => $tplTitle, ], 'amount4' => [ 'value' => $pay_price, ], 'date2' => [ 'value' => date("Y/m/d H:i:s"), ], 'thing7' => [ 'value' => $thing5, ] ]; $this->wechat->subscribe_message->send($this->tpl1); } return true; } else { return $fail('支付失败,请稍后再通知我'); } }); Db::commit(); return $response->send(); // Laravel 里请使用:return $response; } catch (Exception $e) { app()->log('支付错误:' . $e->getMessage(),'pay'); Db::rollback(); return $this->ApiJson(-1, "支付返回时错误!" . $e->getMessage()); } } /** * 获取小程序分享码 * * @return \think\response\Json * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException * @throws \EasyWeChat\Kernel\Exceptions\RuntimeException * @throws \Lettered\Support\Exceptions\FailedException * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\ModelNotFoundException * @throws \think\exception\DbException * @author 许祖兴 < zuxing.xu@lettered.cn> * @date 2020/6/26 18:11 * */ public function getShareSpread() { // 获取用户信息 $user = $this->auth->user(); // 获取邀请信息 $spread = model('common/UsersInvite') ->where(['user_id' => $user['id']])->find(); // 存在性判断 if (!$spread) { // 邀请码就选择用户ID $response = $this->wechat->app_code->getUnlimit('spd=' . $user['card_id'], [ // 'scene' => [ // 'spd' => $user['card_id'] // ], 'page' => 'pages/index/index', 'width' => 600, 'line_color' => [ 'r' => 236, 'g' => 108, 'b' => 68, ] ]); // 检查 if (is_array($response) && $response['errcode'] == '41030') { return $this->ApiJson(-1, '当前体验版无法生成二维码,请上线后重试~'); } // 保存二维码 if ($response instanceof \EasyWeChat\Kernel\Http\StreamResponse) { $filename = $response->saveAs($this->app->getRootPath() . 'public/uploads/spread', md5(time()) . '.png'); $qrImg = get_annex_url('/spread/' . $filename); //TODO 二维码写入数据库 model('common/UsersInvite')->storeBy([ 'user_id' => $user['id'], 'code' => $user['card_id'], 'qr_img' => $qrImg ]); return $this->ApiJson(0, 'OK!', [ 'inviteCode' => $user['card_id'], 'qrcodeImg' => $qrImg ]); } return $this->ApiJson(-1, '生成邀请失败,请稍后重试~'); } return $this->ApiJson(0, 'OK!', [ 'inviteCode' => $spread['code'], 'qrcodeImg' => $spread['qr_img'] ]); } private function thirdPayment($channel, $paylog) { // 目前就微信支付 // 加载配置 $wechat = sys_config('', $channel); // 发起支付 $config = [ // 前面的appid什么的也得保留哦 'app_id' => $wechat['mini_appid'], 'mch_id' => $wechat['pay_mch_id'], 'key' => $wechat['pay_secret_key'], // 'notify_url' => 'https://api.gxrrj.cn/api/v1/wechat/notify', 'notify_url' => site_url() . '/api/v1/wechat/notify', // 'notify_url' => 'http://ncnjmz.natappfree.cc/api/v1/wechat/notify', // 'sandbox' => true ]; app()->log(json_encode($config, 256),'wechat'); // 创建应用实例 $payment = Factory::payment($config); $jssdk = $payment->jssdk; // 服务名称 $serve = ""; switch ($paylog['ascription']) { case 'farmland': $serve = "田地服务"; break; case 'motor': $serve = "摩的服务"; break; case 'skill': $serve = "技能服务"; break; case 'mission': $serve = "配送服务"; break; case 'goods': $serve = "商品购买"; break; case 'level': $serve = "司机付费升级"; break; } // 统一下单 $result = $payment->order->unify([ 'attach' => $paylog['ascription'], // 附加数据,区分订单所属 'body' => '人人接 - ' . $serve, 'out_trade_no' => $paylog['out_trade_no'], 'total_fee' => round($paylog['total_price'] * 100), 'trade_type' => 'JSAPI', 'openid' => $this->auth->user()['open_id'] ]); app()->log('提交支付' . enjson($result), 'debug'); if ($result['return_code'] == 'SUCCESS' && $result['result_code'] == 'SUCCESS') { return $this->ApiJson(0, '', $jssdk->sdkConfig($result['prepay_id'])); } return $this->ApiJson(-1, isset($result['return_msg']) ? $result['return_msg'] : '支付异常,请稍后重试...'); } private function thirdRefund($channel, $paylog) { // 1.查找对应是否有退款订单 // 2.创建退款单记录 // 3.请求微信退款 // 参数分别为:微信订单号、商户退款单号、订单金额、退款金额、其他参数 //$app->refund->byTransactionId(string $transactionId, string $refundNumber, int $totalFee, int $refundFee, array $config = []); // Example: $result = $app->refund->byTransactionId($paylog['out_trade_no'], 'refund-no-xxx', 10000, 10000, [ // 可在此处传入其他参数,详细参数见微信支付文档 'refund_desc' => '商品已售完', ]); } /** * 余额支付 * * @param $payType * @param $paylog * @return \think\response\Json * @throws \Lettered\Support\Exceptions\FailedException * @throws \think\Exception * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\ModelNotFoundException * @throws \think\exception\DbException * @throws \think\exception\PDOException * @author 许祖兴 < zuxing.xu@lettered.cn> * @date 2020/8/6 16:39 * */ private function buyOnUserSelf($payType = 'balance', $paylog) { // 检查用户余额 $user = $this->auth->user(); if ($user[$payType] < $paylog['total_price']) { return $this->ApiJson(-1, '支付失败,账户余额不足!'); } // 支付金额 $pay_price = sprintf("%.2f", round($paylog['total_price'], 2)); Db::startTrans(); try { // 支付成功 支付订单状态is_pay =1 model('common/OrderPaylog')->updateBy($paylog['id'], [ 'pay_price' => $pay_price, 'pay_type' => $payType, // 默认支付方式 'is_pay' => 1, ]); $orderId = $paylog['order_idx']; // 模板消息标题 $tplTitle = ""; $thing7 = '感谢您的支持,我们将致力于更好的服务!'; $goodsOrder = 1; switch ($paylog['ascription']) { // 田地订单 case "farmland": $goodsOrder = model('common/FarmlandOrder')->getBy(['id' => $orderId]); $tplTitle = "人人接 - 田地服务"; model('common/FarmlandOrder')->updateBy($orderId, ['status' => 2, 'pay_type' => $payType]); // todo 停止本次招标 model('common/FarmlandBlock')->updateBy($goodsOrder['block_id'], [ 'status' => 2 // 1 可用 2 服务中 ]); push_socket_data('farmland', [ 'id' => $orderId, 'msg' => '有新的农田订单等待处理,点击前往!' ]); break; // 摩的订单 case "motor": $goodsOrder = model('common/TaxiOrder')->getBy(['id' => $orderId]); $tplTitle = "人人接 - 摩的服务"; model('common/TaxiOrder')->updateBy($orderId, ['status' => 2]); push_socket_data('motor', [ 'id' => $orderId, 'msg' => '有新的摩的订单等待处理,点击前往!' ]); // 订阅消息 // $thing7 = '电话请保持通畅,师傅正在赶往路上,请稍候'; // 订单结算给摩的代理 //model('\app\api\model\taxi\Award')->send($goodsOrder); break; // 技能订单 case "skill": $tplTitle = "人人接 - 技能服务"; $goodsOrder = model('common/SkillOrder')->getBy(['id' => $orderId]); model('common/SkillOrder')->updateBy($orderId, ['status' => 2]); push_socket_data('skill', [ 'id' => $orderId, 'msg' => '有新的技能订单等待处理,点击前往!' ]); break; // 配送订单 case "mission": $tplTitle = "人人接 - 配送服务"; $goodsOrder = model('common/MissionOrder')->getBy(['id' => $orderId]); model('common/MissionOrder')->updateBy($orderId, ['status' => 2]); push_socket_data('mission', [ 'id' => $orderId, 'msg' => '有新的配送订单等待处理,点击前往!' ]); break; // 救援订单 case "rescue": $tplTitle = "人人接 - 救援服务"; $goodsOrder = model('common/RescueOrder')->getBy(['id' => $orderId]); model('common/RescueOrder')->updateBy($orderId, ['status' => 2]); push_socket_data('rescue', [ 'id' => $orderId, 'msg' => '有新的救援订单等待处理,点击前往!' ]); break; // 商品订单 case "goods": // 获取订单产品 $goods = model('common/GoodsOrderDetail')->where(['order_id' => $paylog['order_idx']])->find(); $tplTitle = $goods['title']; // 产品订单 $goodsOrder = model('common/GoodsOrder')->where(['id' => $paylog['order_idx']])->lock(true)->find(); // 获取当前支付订单是否为拼团 if ($goodsOrder && $goodsOrder['is_pin']) { $this->dealWithPinOrder($pay_price, $goodsOrder); } else { // 0: 已关闭 1:待支付, 2:待发货,3:待收货 , 4: 已完成 , 5: 待开团 , 6: 未中团 // 数据更新 model('common/GoodsOrder')->updateBy($goodsOrder['id'], [ 'pay_price' => $pay_price, 'paid_at' => time(), 'status' => 2 ]); } push_socket_data('goods', [ 'id' => $goodsOrder['id'], 'msg' => '有新的商品订单等待处理,点击前往!' ]); break; } //$user = model('common/Users')->getBy(['id' => $goodsOrder['user_id']]); // 扣减账户余额 if ($payType == 'balance') { model('common/Users')->changeBalance( $user['id'], $pay_price, "支付成功,支付金额【" . $pay_price . "】" ); } else if ($payType == 'property') { model('common/Users')->changeProperty( $user['id'], $pay_price, "消费成功,消费资产【{$pay_price}】" ); } // 查找用户消费获得资产奖励 - 资产消费无法获得资产 if ($paylog['ascription'] == 'goods' && $payType != 'property') { // 用户消费金额处理 // 写入本次消费后总金额 $user_consume_total = $user['consume'] + $pay_price; model('common/Users')->updateBy($user['id'], [ 'consume' => sprintf('%.2f', $user_consume_total) ]); // 消费总额包含 商品、接单、技能、摩的 // 获取资产设置 $user_property_reward = sys_config('user_property_reward', 'user'); if ($user_property_reward != '') { foreach (str2arr($user_property_reward, ',') as $key => $reward) { list($select, $amount) = str2arr($reward, ":"); if ($amount == 0) continue; // 当前总消费达到奖励 if ($user_consume_total >= $select && $key == $user['property_count']) { //TODO 达到消费 -- 反奖励 model('common/Users')->changeProperty( $goodsOrder['user_id'], sprintf("%.2f", round($amount, 2)), "消费满 {$select},平台奖励资产【" . sprintf("%.2f", round($amount, 2)) . '】', true ); // 增加领取次数 model('common/Users')->where(['id' => $goodsOrder['user_id']]) ->setInc('property_count'); } } } } // 模板消息 $this->tpl1['touser'] = $user['open_id']; $this->tpl1['data'] = [ 'character_string1' => [ 'value' => $goodsOrder['order_no'], ], 'thing3' => [ 'value' => $tplTitle, ], 'amount4' => [ 'value' => $pay_price, ], 'date2' => [ 'value' => date("Y/m/d H:i:s"), ], 'thing7' => [ 'value' => $thing7, ] ]; // $this->wechat->subscribe_message->send($this->tpl1); Db::commit(); return $this->ApiJson(0, '支付成功'); } catch (\Exception $e) { Log::error('支付错误:' . $e->getMessage() . $e->getTraceAsString()); Db::rollback(); return $this->ApiJson(-1, $e->getMessage()); } } private function dealWithPinOrder($pay_price, $goodsOrder) { // 拼单详情 $gorder_detail = model('common/GoodsOrderDetail')->getBy(['order_id' => $goodsOrder['id']]); // 查拼单产品 $goods = model('common/Goods')->where(['id' => $gorder_detail['goods_id']])->lock(true)->find(); // 支付成功 -- 0 为创建拼团 if ($goodsOrder['group_id'] == 0) { $joinId = model('common/GoodsOrderGroup')->storeBy([ 'user_id' => $goodsOrder['user_id'], 'goods_id' => $goods['id'], 'pin_sum' => $goods['pin_sum'], 'pin_number' => $goods['pin_number'], // 超时时间 'expired_at' => time() + (sys_config('pin_expired_at', 'store') * 3600) // 24 * 3600 ]); // 数据更新 model('common/GoodsOrder')->updateBy($goodsOrder['id'], [ 'group_id' => $joinId, //创建的时候追加拼团id 'pay_price' => $pay_price, 'paid_at' => time(), 'status' => 5 ]); } else { // 参加拼团 -- 增加人数 $groupOrder = model('common/GoodsOrderGroup')->where(['id' => $goodsOrder['group_id']])->lock(true)->find(); // 1. 是否已经拼满了,或者已经拼单成功了 -- 拼单满了就直接拼单失败,直接返回金额到余额,关闭订单开启限时红白奖励 if (($groupOrder['pin_sum'] == $groupOrder['now_number']) || $groupOrder['status'] == 1) { // 关闭我的订单 -- 这里应该直接关闭订单直接返款,没有红包 // 先返款 model('common/Users')->changeBalance( $goodsOrder['user_id'], $pay_price, "参团失败,退还支付金额【" . $pay_price . '】', true ); // 单产品SKU库存回增 model('common/GoodsSku') ->where(['param' => enjson(str2arr($gorder_detail['spec']))]) ->setInc('stock', $gorder_detail['count']); // 产品总库存更新 model('common/Goods') ->where(['id' => $gorder_detail['goods_id']]) ->setInc('stock', $gorder_detail['count']); // 销量减 model('common/Goods') ->where(['id' => $gorder_detail['goods_id']]) ->setDec('sell_count', $gorder_detail['count']); // 再更新 -- 关闭订单 model('common/GoodsOrder')->updateBy($goodsOrder['id'], [ 'pay_price' => $pay_price, 'paid_at' => time(), 'status' => 0 ]); } else { // pin_sum 拼团人数 // pin_number 获得人数 // now_number 当前人数 // 2. 加入拼单成功,检查我是不是最后一个,最后一个直接开团,获得者从随机获得 $gog = model('common/GoodsOrderGroup')->where(['id' => $goodsOrder['group_id']]); $gog->setInc('now_number', $gorder_detail['count']); // 当前人数检查 -- 达到拼团人数--开团 if ($groupOrder['pin_sum'] == $gog->value("now_number")) { // 当前拼单成团 - 进行逻辑发放 // 查找当前拼团下的所有订单 $cgo = model('common/GoodsOrder') ->where(['group_id' => $groupOrder['id']]) ->select(); // 利润 count * ( total_price - instock ) // 总利润 $cgo_total = 0; // 子单 foreach ($cgo as $item) { // 子单明细 $its = model('common/GoodsOrderDetail')->where(['order_id' => $item['id']])->select(); foreach ($its as $itsv) { // 产品 $goin = model('common/GoodsSku')->where(['goods_id' => $itsv['goods_id'], 'param' => enjson(str2arr($itsv['spec'], ','))])->value('instock_price'); $cgo_total += sprintf("%.2f", round($itsv['total_price'] - $goin, 2)); } } // todo 返现生成如果是按百分比和整数混合 $pin_rebate_amount = sys_config('pin_rebate_amount', 'store'); $pin_rebate_expired_at = sys_config('pin_rebate_expired_at', 'store'); // 20200730 客户说按利润比得数据 // 利润 * 比例 = 要发放的钱 $rebate = sprintf("%.2f", round($cgo_total * (float)$pin_rebate_amount / 100, 2)); $num = count($cgo);// 分成10个红包,支持10人随机领取 $min = 0.01 * $rebate;//每个人最少能收到0.01元 $rArr = []; for ($i = 1; $i < $num; $i++) { $safe_total = ($rebate - ($num - $i) * $min) / ($num - $i);//随机安全上限 $money = mt_rand($min * 100, $safe_total * 100) / 100; $rebate -= $money; $rArr[$i] = $money; } $rArr[$num] = $rebate; //TODO 暂时脑子瓦特,想不到什么好办法 // 0: 已关闭 1:待支付, 2:待发货,3:待收货 , 4: 已完成 , 5: 待开团 , 6: 未中团 $in_num = array_rand($cgo->toArray(), $groupOrder['pin_number']); foreach ($cgo->toArray() as $key => $val) { if (in_array($key, (array)$in_num)) { // 这里是拼中的 -- 修改订单状态 (拼团成功,等待发货) model('common/GoodsOrder')->updateBy($val['id'], [ 'status' => 2 ]); } else { // 这里是拼不中-- 修改订单状态 (未中团,返款加限时红包,等待红包过期才关闭订单) // 先返款 model('common/Users')->changeBalance( $val['user_id'], $pay_price, "参团失败,退还支付金额【" . $pay_price . '】', true ); // 获取用户信息 $user = model('common/Users')->findBy($val['user_id']); // 订阅消息 $this->tpl2['touser'] = $user['open_id']; $this->wechat->subscribe_message->send($this->tpl2); // 获取订单产品 $order_detail = model('common/GoodsOrderDetail')->getAll(['order_id' => $val['id']]); // 单产品SKU库存回增 foreach ($order_detail as $goods) { // 单产品SKU库存回增 model('common/GoodsSku') ->where(['param' => enjson(str2arr($goods['spec']))]) ->setInc('stock', $goods['count']); // 产品总库存更新 model('common/Goods') ->where(['id' => $goods['goods_id']]) ->setInc('stock', $goods['count']); } // 再更新 model('common/GoodsOrder')->updateBy($val['id'], [ 'pin_rebate' => $rArr[$key + 1], //返现生成 -- 读取数据库配置 'pin_rebate_expired' => time() + ($pin_rebate_expired_at * 3600), // x 3600 数据库配置 'status' => 6 ]); } } // 数据更新 model('common/GoodsOrder')->updateBy($goodsOrder['id'], [ 'pay_price' => $pay_price, 'paid_at' => time() ]); // 拼团完成 model('common/GoodsOrderGroup')->updateBy(['id' => $goodsOrder['group_id']], [ 'success_at' => time(), // 拼单成功时间 'status' => 1 // 拼单状态完成 ]); } else { // 数据更新 model('common/GoodsOrder')->updateBy($goodsOrder['id'], [ 'pay_price' => $pay_price, 'paid_at' => time(), 'status' => 5 ]); } } } } }