Sfoglia il codice sorgente

Wesmiler 2021-0115第4期分销功能新增

wesmiler 5 anni fa
parent
commit
0895d0af34

+ 2 - 1
.gitignore

@@ -5,4 +5,5 @@
 .env
 
 
-/data/runtime
+/data/runtime
+/public/logs

+ 28 - 0
app/api/controller/TestController.php

@@ -6,6 +6,8 @@
 
 namespace app\api\controller;
 
+use app\weixin\model\UserBalanceLog;
+use app\weixin\service\Award;
 use function AlibabaCloud\Client\value;
 use app\admin\model\CarModel;
 use app\weixin\model\Books;
@@ -32,7 +34,33 @@ class TestController extends HomeBaseController
 
 
 
+    public function marketTest(){
+        $type = input('type', 1);
+        $userId = input('id', 1);
+        $sourceId = input('sid', 0);
+        $money = input('money', 0);
 
+        $result = Award::marketAward($userId, $sourceId, $type, $money);
+        return showJson(1005, $result);
+    }
+
+    public function checkWithdraw(){
+        $orderid = input('id', 0);
+
+        $order = UserBalanceLog::alias('ub')
+            ->leftJoin('user u','u.id=ub.user_id')
+            ->where(['ub.id'=> $orderid])
+            ->field('ub.id,ub.order_sn as orderNo,ub.pay_money as amount,u.openid,ub.description as body,ub.status')
+            ->find();
+        $order = $order? $order->toArray() : [];
+        $order['check_name'] = 'FORCE_CHECK';
+        $order['real_name'] = '张三';
+        var_dump($order);
+        $result = Wechat::transferOrder($order);
+
+        var_dump($result);
+
+    }
 
 }
 

+ 11 - 0
app/weixin/model/Market.php

@@ -0,0 +1,11 @@
+<?php
+
+namespace app\weixin\model;
+
+use think\Model;
+
+class Market extends Model
+{
+    protected $table = 'sg_market';
+
+}

+ 72 - 0
app/weixin/model/Wechat.php

@@ -31,6 +31,8 @@ class Wechat
         'refundOrder' => 'https://api.mch.weixin.qq.com/pay/unifiedorder',
         // 查询订单
         'queryOrder' => 'https://api.mch.weixin.qq.com/pay/orderquery',
+        // 企业付款到零钱
+        'transfers' => 'https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers',
         // 生成二维码
         'makeQrcode' => 'https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=%s',
         // 换取二维码
@@ -653,6 +655,75 @@ class Wechat
         return Wechat::getJsapiPareams($unifiedOrder, $unified);
     }
 
+
+    /**
+     * 提现打款
+     * @param $order
+     * @param string $scene
+     * @return array|string[]
+     */
+    public static function transferOrder($order, $scene='withdraw'){
+        $appId = Wechat::getConfigs('appid');
+        $mchId = Wechat::getConfigs('mch_id');
+        $openid = isset($order['openid']) ? trim($order['openid']) : '';
+        $orderNo = isset($order['orderNo']) ? trim($order['orderNo']) : '';
+        $totalFee = isset($order['amount']) ? moneyFormat($order['amount']) : 0.00;
+
+        // 测试支付金额
+        $payDebug = config('weixin.payDebug');
+        if ($payDebug) {
+            $totalFee = 0.01;
+        }
+        if (empty($openid) || empty($orderNo) || empty($totalFee)) {
+            return ['code' => 'error', 'message' => '参数错误'];
+        }
+        $unified = array(
+            'mch_appid' => $appId,
+            'mchid' => trim($mchId),
+            'nonce_str' => Wechat::createNonceStr(),
+            'partner_trade_no' => $orderNo,
+            'openid' => $openid,
+            'check_name' => isset($order['check_name']) && $order['check_name']? trim($order['check_name']) : 'NO_CHECK', // 是否校验真实姓名
+            'amount' => intval($totalFee * 100),       //单位 转为分
+            'desc' => isset($order['body']) ? trim($order['body']) : '余额提现',
+            'spbill_create_ip' => get_client_ip(),
+        );
+
+        // 是否校验真实姓名
+        if($unified['check_name'] == 'FORCE_CHECK'){
+            $unified['re_user_name'] = isset($order['real_name']) ? trim($order['real_name']) : '';
+        }
+var_dump($unified);
+        PRedis::set('orders:'.$scene.':'.$openid.':unified', $unified, 600);
+        $unified['sign'] = Wechat::getPaySign($unified);
+        var_dump($unified);
+        PRedis::set('orders:'.$scene.':'.$openid.':unifiedSign', $unified, 600);
+        $url = !empty(self::$apiUrl['unifiedorder']) ? trim(self::$apiUrl['unifiedorder']) : 'https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers';
+        $data = Wechat::arrayToXml($unified);
+        var_dump($data);
+        PRedis::set('orders:'.$scene.':'.$openid.':unifiedXml', ['data'=> $unified,'result'=> $data], 600);
+        $responseXml = Wechat::curlPost($url, trim($data));
+        //禁止引用外部xml实体
+        libxml_disable_entity_loader(true);
+        $result = simplexml_load_string($responseXml, 'SimpleXMLElement', LIBXML_NOCDATA);
+        $result = (array)$result;
+        PRedis::set('orders:'.$scene.':'.$openid.':unifiedResult', ['data'=> $result,'result'=> $data], 600);
+        if ($result === false) {
+            return ['code' => 'exception', 'message' => 'parase xml error'];
+        }
+        if ($result['return_code'] != 'SUCCESS') {
+            return ['code' => 'error', 'message' => $result['return_msg'],'type'=>'return_code'];
+        }
+        if ($result['result_code'] != 'SUCCESS') {
+            return ['code' => 'error', 'message' => $result['err_code'],'type'=>'result_code'];
+        }
+
+        return $result;
+    }
+
+    /**
+     * 退款订单
+     */
     public static function refundOrder(){
 
     }
@@ -795,6 +866,7 @@ class Wechat
     public static function curlPost($url = '', $postData = '', $options = array())
     {
         if (is_array($postData)) {
+            echo 666;
             $postData = http_build_query($postData);
         }
         $ch = curl_init();

+ 246 - 4
app/weixin/service/Award.php

@@ -6,8 +6,12 @@
 
 namespace app\weixin\service;
 
+use app\weixin\model\AccountLog;
+use app\weixin\model\Market;
 use app\weixin\model\Member;
+use app\weixin\model\UserBalanceLog;
 use app\weixin\model\Wechat;
+use think\Db;
 
 class Award
 {
@@ -16,7 +20,7 @@ class Award
         $userInfo = Member::where(['id' => $userId, 'user_status' => 1])
             ->field('id,user_login,user_nickname,openid,redheart')
             ->find();
-        PRedis::set('test:userInfo', ['data'=> $userInfo,'userId'=> $userId], 600);
+        PRedis::set('test:userInfo', ['data' => $userInfo, 'userId' => $userId], 600);
         $inviteOpenid = isset($userInfo['openid']) ? $userInfo['openid'] : '';
         $inviteNickname = isset($userInfo['user_nickname']) ? $userInfo['user_nickname'] : '';
         $redheart = isset($userInfo['redheart']) ? floatval($userInfo['redheart']) : 0;
@@ -57,16 +61,254 @@ class Award
                 $match = ['{nickname}', '{inviteNickname}', '{awardNum}', '{datetime}', '{date}'];
                 $data = [$regNickname, $inviteNickname, $awardNum, $dateTime, date('Y.m.d')];
                 $inviteMsg = $inviteMsg ? str_replace($match, $data, $inviteMsg) : "尊敬的【{$inviteNickname}】,您在{$dateTime}成功邀请了用户{$regNickname}关注{$siteName},获得奖励{$awardNum}颗爱心!!!";
-                $message = ['content'=> $inviteMsg];
+                $message = ['content' => $inviteMsg];
             }
 
-            return ['openid'=> $inviteOpenid, 'message'=> $message];
+            return ['openid' => $inviteOpenid, 'message' => $message];
         }
 
         return false;
     }
 
-    public static function marketInviteUser($userId, $money, $sourceUid=0){
+    /**
+     * 分销收益奖励结算
+     * @param $userId 当前奖励用户ID
+     * @param $sourceUid 当前收益直接来源用户ID
+     * @param $type 收益类型:对应market表ID
+     * @param int $money 结算金额:比例分成必传金额
+     * @return bool
+     * @throws \think\Exception
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public static function marketAward($userId, $sourceUid, $type, $money=0)
+    {
+        if (empty($type) || $userId <= 0) {
+            return false;
+        }
+
+        // 分销参数配置
+        $cacheKey = "market:award:u_{$userId}_{$sourceUid}_{$type}";
+        $logData = ['money' => $money, 'sourceUid' => $sourceUid, 'userId'=> $userId];
+        $marketConfig = Market::where(['id' => $type, 'status' => 1])->find();
+        $marketType = isset($marketConfig['type']) ? $marketConfig['type'] : 2;
+        $logData['config'] = $marketConfig;
+        if (empty($marketConfig)) {
+            PRedis::set("{$cacheKey}:error_config", $logData, 7200);
+            return false;
+        }
+
+        // 验证上级用户是否符合奖励条件
+
+        $where = ['id' => $userId, 'agent_type' => 1, 'agent_status' => 1];
+        $field = 'id,openid,user_nickname,parent_id,user_login,balance';
+        $userInfo = Member::getInfo($where, $field);
+        $nickname = isset($userInfo['nickname']) ? trim($userInfo['nickname']) : '';
+        $userLogin = isset($userInfo['user_login']) ? trim($userInfo['user_login']) : '';
+        $balance = isset($userInfo['balance']) ? floatval($userInfo['balance']) : 0;
+        $nickname = $nickname? $nickname : $userLogin;
+        $logData['userInfo'] = $userInfo;
+        if (empty($userInfo)) {
+            PRedis::set("{$cacheKey}:error_user", $logData, 7200);
+            return false;
+        }
+
+        // 收益原始来源用户
+        $sWhere = ['id' => $sourceUid, 'user_type' => 2];
+        $sourceInfo = Member::getInfo($sWhere, $field);
+        $sourceNickname = isset($sourceInfo['user_nickname']) ? $sourceInfo['user_nickname'] : '';
+        $userLogin = isset($sourceInfo['user_login']) ? trim($sourceInfo['user_login']) : '';
+        $sourceNickname = $sourceNickname? $sourceNickname : $userLogin;
+
+        // 一级分销收益结算
+        $logData['level'] = 1;
+        $level1Award = isset($marketConfig['level_1']) ? floatval($marketConfig['level_1']) : 0;
+        $awardMoney = $marketType==1? moneyFormat($level1Award) : moneyFormat($money * ($level1Award / 100));
+        $logData['levelAward'] = $level1Award;
+        if ($level1Award > 0 && $level1Award <= 100 && $awardMoney > 0) {
+            // 账户变动
+            Db::startTrans();
+            if (Member::where($where)->setInc('balance', $awardMoney)) {
+                // 写入奖励日志
+                $levelName = "您邀请的[{$sourceNickname}]用户";
+                $marketName = isset($marketConfig['name']) ? $marketConfig['name'] : '分销收益';
+                $logTitle = "{$levelName}支付{$money}元,获得{$marketName}{$awardMoney}元";
+                $log = [
+                    'change' => $awardMoney,
+                    'type' => $type,
+                    'level' => 1,
+                    'change_type' => 1,
+                    'pay_money' => $awardMoney,
+                    'user_id' => $userId,
+                    'source_uid' => $sourceUid,
+                    'balance' => moneyFormat($balance + $awardMoney),
+                    'description' => $logTitle,
+                    'create_time' => time(),
+                    'status' => 1,
+                ];
+                $logData['log'] = $log;
+                PRedis::set("{$cacheKey}:log", $logData, 7200);
+                if(UserBalanceLog::insertGetId($log)){
+                    // 账户明细
+                    $accountData = [
+                        'type' => 4,
+                        'account_type' => 2,
+                        'change_type' => 1,
+                        'user_id' => $userId,
+                        'money' => $awardMoney,
+                        'balance' => $balance,
+                        'created_at' => date('Y-m-d H:i:s'),
+                        'remark' => $logTitle,
+                    ];
+                    if(AccountLog::insertGetId($accountData)){
+                        // 发送模板消息
+                        $openid = isset($userInfo['openid'])? $userInfo['openid'] : '';
+                        if($openid){
+                            $checkTime = date('Y.m.d H:i');
+                            $remark = "感谢您对拾光的信任,我们一起解救单身青年!点击查看收益明细";
+                            $msgParams = [
+                                'title' => "您邀请的用户[$sourceNickname]消费所得的收益已到账!\n\n类型:\t{$marketName}",
+                                'remark' => $remark,
+                                'type' => 'income',
+                                'keywords' => [
+                                    'keyword1' => [
+                                        'value' => "{$awardMoney}",
+                                        'color' => '#173177',
+                                    ],
+                                    'keyword2' => [
+                                        'value' => $checkTime,
+                                        'color' => '#173177',
+                                    ],
+                                ],
+                                'url' => url('/weixin/market/income', '', '', true),
+                            ];
+                            PRedis::set("{$cacheKey}:message", ['result' => $userInfo, 'params' => $msgParams], 600);
+                            Wechat::sendTplMsg($openid, $msgParams);
+                        }
+
+                        Db::commit();;
+                    }else{
+                        PRedis::set("{$cacheKey}:account_log", $logData, 7200);
+                        Db::rollback();
+                    }
+                }else{
+                    PRedis::set("{$cacheKey}:balance_log", $logData, 7200);
+                    Db::rollback();
+                }
+
+            } else {
+                PRedis::set("{$cacheKey}:update_balance", $logData, 7200);
+                Db::rollback();
+            }
+        } else {
+            PRedis::set("{$cacheKey}:error_awardMoney", $logData, 7200);
+        }
+
+        // 二级分销收益结算
+        $logData['level'] = 2;
+        $userTwoId = isset($userInfo['parent_id'])? intval($userInfo['parent_id']) : 0;
+        $cacheKey = "market:award:u_{$userTwoId}_{$sourceUid}_{$type}";
+        if($userTwoId<=0){
+            PRedis::set("{$cacheKey}:market2", $logData, 7200);
+            return false;
+        }
+
+        $whereTwo = ['id' => $userTwoId, 'agent_type' => 1, 'agent_status' => 1];
+        $userInfoTwo = Member::getInfo($whereTwo, $field);
+        $balanceTwo = isset($userInfoTwo['balance']) ? floatval($userInfoTwo['balance']) : 0;
+        $logData['userInfo'] = $userInfoTwo;
+        if(empty($userInfoTwo)){
+            PRedis::set("{$cacheKey}:error_userTwo", $logData, 7200);
+            return false;
+        }
+
+        $level2Award = isset($marketConfig['level_2']) ? floatval($marketConfig['level_2']) : 0;
+        $awardMoneyTwo = $marketType==1? moneyFormat($level2Award) : moneyFormat($money * ($level2Award / 100));
+        $logData['levelAward'] = $level2Award;
+        if ($level2Award > 0 && $level2Award <= 100 && $awardMoneyTwo > 0) {
+            // 账户变动
+            Db::startTrans();
+            if (Member::where($whereTwo)->setInc('balance', $awardMoneyTwo)) {
+                // 写入奖励日志
+                $levelName = "您的下级[{$nickname}]邀请的[{$sourceNickname}]用户";
+                $marketName = isset($marketConfig['name']) ? $marketConfig['name'] : '分销收益';
+                $logTitle = "{$levelName}消费{$money}元,获得{$marketName}{$awardMoneyTwo}元";
+                $log = [
+                    'change' => $awardMoneyTwo,
+                    'type' => $type,
+                    'level' => 2,
+                    'change_type' => 1,
+                    'pay_money' => $awardMoneyTwo,
+                    'user_id' => $userTwoId,
+                    'source_uid' => $userId,
+                    'balance' => moneyFormat($balanceTwo + $awardMoneyTwo),
+                    'description' => $logTitle,
+                    'create_time' => time(),
+                    'status' => 1,
+                ];
+                $logData['log'] = $log;
+                PRedis::set("{$cacheKey}:log", $logData, 7200);
+                if(UserBalanceLog::insertGetId($log)){
+                    // 账户明细
+                    $accountData = [
+                        'type' => 4,
+                        'account_type' => 2,
+                        'change_type' => 1,
+                        'user_id' => $userTwoId,
+                        'money' => $awardMoneyTwo,
+                        'balance' => $balanceTwo,
+                        'created_at' => date('Y-m-d H:i:s'),
+                        'remark' => $logTitle,
+                    ];
+                    if(AccountLog::insertGetId($accountData)){
+                        // 发送模板消息
+                        $openid = isset($userInfoTwo['openid'])? $userInfoTwo['openid'] : '';
+                        if($openid){
+                            $checkTime = date('Y.m.d H:i');
+                            $remark = "感谢您对拾光的信任,我们一起解救单身青年!点击查看收益明细";
+                            $msgParams = [
+                                'title' => "您的下级[$nickname]邀请的用户[{$sourceNickname}]消费所得的收益已到账!\n\n类型:\t{$marketName}",
+                                'remark' => $remark,
+                                'type' => 'income',
+                                'keywords' => [
+                                    'keyword1' => [
+                                        'value' => "{$awardMoneyTwo}",
+                                        'color' => '#173177',
+                                    ],
+                                    'keyword2' => [
+                                        'value' => $checkTime,
+                                        'color' => '#173177',
+                                    ],
+                                ],
+                                'url' => url('/weixin/market/income', '', '', true),
+                            ];
+                            PRedis::set("{$cacheKey}:message", ['result' => $userInfoTwo, 'params' => $msgParams], 600);
+                            Wechat::sendTplMsg($openid, $msgParams);
+                        }
+
+                        Db::commit();
+                    }else{
+                        PRedis::set("{$cacheKey}:account_log", $logData, 7200);
+                        Db::rollback();
+                        return false;
+                    }
+                }else{
+                    PRedis::set("{$cacheKey}:balance_log", $logData, 7200);
+                    Db::rollback();
+                    return false;
+                }
+
+            } else {
+                PRedis::set("{$cacheKey}:update_balance", $logData, 7200);
+                Db::rollback();
+                return false;
+            }
+        } else {
+            PRedis::set("{$cacheKey}:error_awardMoney", $logData, 7200);
+            return false;
+        }
 
+        return true;
     }
 }

+ 2 - 0
app/weixin/service/Member.php

@@ -169,4 +169,6 @@ class Member
             return 1015;
         }
     }
+
+
 }

+ 2 - 1
data/config/weixin.php

@@ -50,11 +50,12 @@ return [
     'incomeTypes'=> [
         2=> '会员开通VIP分成',
         3=> '人工牵线付费分成',
-        4=> '会员注册分成',
+        4=> '会员完善资料分成',
         5=> '会员实名认证分成',
         6=> '会员学历认证分成',
         7=> '会员工作认证分成',
         8=> '会员爱心充值分成',
+        9=> '会员活动报名分成',
     ],
     // 用户操作记录清除
     'userLogDel' => true,

+ 9 - 0
public/themes/admin_simpleboot3/admin/setting/site.html

@@ -568,6 +568,15 @@
                             </div>
                         </div>
                         <div class="form-group">
+                            <label for="input-income_template" class="col-sm-3 control-label">收益结算消息模板ID</label>
+                            <div class="col-md-6 col-sm-10">
+                                <input type="text" class="form-control" id="input-income_template"
+                                       name="templates[income_template]" value="{$templates.income_template|default=''}">
+                                <span class="help-block">收益结算消息模板ID,复制公众号模板消息ID</span>
+                            </div>
+                        </div>
+
+                        <div class="form-group">
                             <label for="input-auth_template" class="col-sm-3 control-label">认证审核通过消息模板ID</label>
                             <div class="col-md-6 col-sm-10">
                                 <input type="text" class="form-control" id="input-auth_template"