stanley-king пре 3 година
родитељ
комит
8bd3dc9220

+ 6 - 1
data/config/dev/refill.ini.php

@@ -1488,4 +1488,9 @@ $config['third_providers'] = $third_providers;
 
 $config['auto_find_channels'] = true;
 $config['cancel_retry_time'] = [10120 => ["9:00",'10:00','11:00']];
-$config['merchant_retry_times'] = [10202 => [ 1 => 1000]];
+$config['merchant_retry_times'] = [
+    10202 => [
+        'qualities' => [1 => ['secs' => 3600, 'times' => 1000], 2 => ['secs' => 300, 'times' => 10]],
+        'lower_ratio' => ['ratio' => 0.9,'period' => 3600]
+    ]    
+];

+ 6 - 1
data/model/predeposit.model.php

@@ -415,7 +415,12 @@ class predepositModel extends Model {
         $mem_info = Model('member')->getMemberInfo(['member_id' => $data['member_id']], '*', true);
         $data_log['lg_available'] = $mem_info['available_predeposit'];
 
-        $update = Model('member')->editMember(['member_id'=>$data['member_id']],$data_pd);
+        if($fRefill) {
+            $update = Model('member')->editMember(['member_id'=>$data['member_id']],$data_pd);
+        }
+        else {
+            $update = Model('member')->editMember(['member_id'=>$data['member_id']],$data_pd);
+        }
 
         if (!$update) {
             throw new Exception('操作失败');

+ 11 - 1
docker/compose/stanley/stat/docker-compose.yml

@@ -41,4 +41,14 @@ services:
       - /Users/stanley-king/work/PHPProject/shoplog:/var/www/html/data/log
       - /Users/stanley-king/work/PHPProject/stdata:/var/www/html/data/stdata
     container_name: "panda-ratio"
-    command: ['python','ratio.py','-h', '192.168.1.220', '-p', '6379']
+    command: ['python','ratio.py','-h', '192.168.1.220', '-p', '6379']
+
+  mratiosrv:
+    image: pycpu:3.7.10
+    volumes:
+      - ../conf/etc/localtime:/etc/localtime:ro
+      - ../../../../:/var/www/html
+      - /Users/stanley-king/work/PHPProject/shoplog:/var/www/html/data/log
+      - /Users/stanley-king/work/PHPProject/stdata:/var/www/html/data/stdata
+    container_name: "panda-mratio"
+    command: ['python','mratio.py','-h', '192.168.1.220', '-p', '6379']

+ 12 - 1
docker/compose/xyz/stat/docker-compose.yml

@@ -44,4 +44,15 @@ services:
       - /mnt/shoplog:/var/www/html/data/log
       - /mnt/stdata:/var/www/html/data/stdata
     container_name: "panda-flask"
-    command: ['python','app.py']
+    command: ['python','app.py']
+
+  mratiosrv:
+    image: pycpu:3.7.10
+    volumes:
+      - ../../../../:/var/www/html
+      - ../conf/etc/localtime:/etc/localtime:ro
+      - /nfs/upload:/var/www/html/data/upload
+      - /mnt/shoplog:/var/www/html/data/log
+      - /mnt/stdata:/var/www/html/data/stdata
+    container_name: "panda-mratio"
+    command: ['python','mratio.py','-h', '172.26.105.125', '-p', '6379']

+ 12 - 1
docker/compose/xyzt/stat/docker-compose.yml

@@ -44,4 +44,15 @@ services:
       - /mnt/testlog:/var/www/html/data/log
       - /mnt/stdata:/var/www/html/data/stdata
     container_name: "panda-flask"
-    command: ['python','app.py']
+    command: ['python','app.py']
+
+  mratiosrv:
+    image: pycpu:3.7.10
+    volumes:
+      - ../../../../:/var/www/html
+      - ../conf/etc/localtime:/etc/localtime:ro
+      - /nfs/upload:/var/www/html/data/upload
+      - /mnt/testlog:/var/www/html/data/log
+      - /mnt/stdata:/var/www/html/data/stdata
+    container_name: "panda-mratio"
+    command: ['python','mratio.py','-h', '172.26.105.125', '-p', '6379']

+ 3 - 3
helper/refill/LZRefillFactory.php

@@ -4,7 +4,7 @@ namespace refill;
 
 require_once(BASE_HELPER_PATH . '/refill/RefillBase.php');
 require_once(BASE_HELPER_PATH . '/refill/ProviderManager.php');
-
+require_once(BASE_HELPER_PATH . '/refill/order.php');
 require_once(BASE_HELPER_PATH . '/refill/policy/IPolicy.php');
 require_once(BASE_HELPER_PATH . '/refill/policy/try_judge.php');
 require_once(BASE_HELPER_PATH . '/refill/policy/lingzh/policy.php');
@@ -14,13 +14,13 @@ require_once(BASE_HELPER_PATH . '/refill/policy/mchctl.php');
 require_once(BASE_HELPER_PATH . '/refill/policy/mchoilctl.php');
 require_once(BASE_HELPER_PATH . '/refill/policy/times_caller.php');
 require_once(BASE_HELPER_PATH . '/refill/policy/quaility.php');
-
 require_once(BASE_HELPER_PATH . '/refill/policy/merchant_price.php');
 require_once(BASE_HELPER_PATH . '/refill/policy/mgroup.php');
 require_once(BASE_HELPER_PATH . '/refill/policy/lingzh/PolicyUtil.php');
 require_once(BASE_HELPER_PATH . '/refill/policy/lingzh/quality_ploy.php');
 require_once(BASE_HELPER_PATH . '/refill/policy/channel_filter.php');
-require_once(BASE_HELPER_PATH . '/refill/order.php');
+require_once(BASE_HELPER_PATH . '/refill/policy/mratio_control.php');
+
 
 
 use Log;

+ 4 - 0
helper/refill/RefillBase.php

@@ -713,4 +713,8 @@ class RefillBase
     {
         $this->mPolicy->update_ratios($ratios);
     }
+    public function UpdatMchRatios($ratios)
+    {
+        $this->mPolicy->update_mchratios($ratios);
+    }
 }

+ 2 - 1
helper/refill/XYZRefillFactory.php

@@ -5,6 +5,7 @@ namespace refill;
 
 require_once(BASE_HELPER_PATH . '/refill/RefillBase.php');
 require_once(BASE_HELPER_PATH . '/refill/ProviderManager.php');
+require_once(BASE_HELPER_PATH . '/refill/order.php');
 require_once(BASE_HELPER_PATH . '/rbridge/RBridgeFactory.php');
 require_once(BASE_HELPER_PATH . '/refill/policy/IPolicy.php');
 require_once(BASE_HELPER_PATH . '/refill/policy/xyz/policy.php');
@@ -22,7 +23,7 @@ require_once(BASE_HELPER_PATH . '/refill/policy/lingzh/PolicyUtil.php');
 require_once(BASE_HELPER_PATH . '/refill/policy/xyz/quality_ploy.php');
 require_once(BASE_HELPER_PATH . '/refill/policy/mgroup.php');
 require_once(BASE_HELPER_PATH . '/refill/policy/channel_filter.php');
-require_once(BASE_HELPER_PATH . '/refill/order.php');
+require_once(BASE_HELPER_PATH . '/refill/policy/mratio_control.php');
 
 
 use Log;

+ 1 - 0
helper/refill/policy/IPolicy.php

@@ -13,4 +13,5 @@ interface IPolicy
     public function notify($order_info, $refill_info): bool;
     public function price($mchid, $spec, $card_type, $quality, $pcode);
     public function update_ratios($ratios);
+    public function update_mchratios($ratios);
 }

+ 15 - 1
helper/refill/policy/lingzh/policy.php

@@ -181,7 +181,7 @@ class policy extends ProviderManager implements IPolicy
         return count($providers);
     }
 
-    public function find_quality(order $order): array
+    public function find_quality(order $order, bool $skip_pre = false): array
     {
         $mchid = $order->mchid();
         $spec  = $order->spec();
@@ -213,8 +213,17 @@ class policy extends ProviderManager implements IPolicy
             return $result;
         };
 
+        $start = false;
         foreach ($qualities as $quality)
         {
+            if(!$start && $skip_pre)
+            {
+                if($quality == $cur_quality) {
+                    $start = true;
+                }
+                continue;
+            }
+
             $price = $this->mPrices->price($mchid,$card_type,$spec,$quality,$pcode);
             if($price === false) {
                 Log::record("{$mchid} 没有协商 quality = {$quality} 价格",Log::DEBUG);
@@ -304,4 +313,9 @@ class policy extends ProviderManager implements IPolicy
     {
         $this->mChannelControl->update_ratios($ratios);
     }
+
+    public function update_mchratios($ratios)
+    {
+        $this->mQuality->update_mchratios($ratios);
+    }
 }

+ 108 - 0
helper/refill/policy/mratio_control.php

@@ -0,0 +1,108 @@
+<?php
+
+namespace refill;
+use Log;
+
+class mratio_control
+{
+    private $mTimesConfig;
+    private $mCurRatios;
+
+    public function __contruct()
+    {
+        $this->mTimesConfig = [];
+        $this->mCurRatios = [];
+    }
+
+    public function load()
+    {
+        global $config;
+        $this->mTimesConfig = $config['merchant_retry_times'] ?? [];
+    }
+
+    public function total($mchid)
+    {
+        if(array_key_exists($mchid,$this->mTimesConfig))
+        {
+            $items = $this->mTimesConfig[$mchid];
+
+            $times = 0;
+            foreach ($items as $quality => $val) {
+                $times += $val['times'] ?? 1;
+                $secs += $val['secs'] ?? 180;
+            }
+            return [true,$times,$secs];
+        } else {
+            return [false,0,0];
+        }
+    }
+
+    public function times($mchid,$quality)
+    {
+        if(array_key_exists($mchid,$this->mTimesConfig))
+        {
+            $items = $this->mTimesConfig[$mchid];
+            if(array_key_exists($quality,$items)) {
+                return $items['times'];
+            }
+        }
+
+        return false;
+    }
+
+    public function seconds($mchid,$quality)
+    {
+        if(array_key_exists($mchid,$this->mTimesConfig))
+        {
+            $items = $this->mTimesConfig[$mchid];
+            if(array_key_exists($quality,$items)) {
+                return $items['secs'];
+            }
+        }
+
+        return false;
+    }
+
+    public function exist($mchid)
+    {
+        if (array_key_exists($mchid, $this->mTimesConfig)) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    public function update($ratios)
+    {
+        Log::record(__METHOD__,Log::DEBUG);
+        if(!empty($ratios)) {
+            $this->mCurRatios = $ratios;
+        }
+    }
+
+    private function lower_ratio($mchid)
+    {
+        $lower_ratio = $this->mTimesConfig[$mchid];
+        return [$lower_ratio['ratio'],$lower_ratio['period']];
+    }
+
+    private function cur_ratio($mchid,$period)
+    {
+        $mratios = $this->mCurRatios;
+        if(array_key_exists($mchid,$mratios)) {
+            if(array_key_exists($period,$mratios)) {
+                return $mratios[$period];
+            }
+        }
+
+        return 1.0;
+    }
+
+    public function ratio_match($mchid)
+    {
+        [$ratio,$period] = $this->lower_ratio($mchid);
+        $cur_ratio = $this->cur_ratio($mchid,$period);
+
+        return $ratio >= $cur_ratio;
+    }
+}

+ 132 - 10
helper/refill/policy/quaility.php

@@ -43,12 +43,14 @@ class Quality
     protected $mSpeeds;
     protected $mQualities;
     protected $mTryAdjuster;
+    protected $mRatioCtl;
 
     public function __construct()
     {
         $this->mMchPhonectl = new mchctl();
         $this->mMchoilctl = new mchoilctl();
         $this->mTryAdjuster = new try_judge();
+        $this->mRatioCtl = new mratio_control();
     }
 
     public function load()
@@ -56,6 +58,7 @@ class Quality
         $this->mMchPhonectl->load();
         $this->mMchoilctl->load();
         $this->mTryAdjuster->load();
+        $this->mRatioCtl->load();
     }
 
     public function find_quality($mchid, $card_type, $org_quality, $cur_quality, $times, $used_time, $caller): array
@@ -169,22 +172,138 @@ class Quality
         }
 
         $max_times = $this->max_times($mchid,$org_quality);
-        $fMixed = PolicyUtil::mixed_quality($org_quality);
+        if($this->mRatioCtl->exist($mchid))
+        {
+            $qualities = $this->ratio_phone_quality($qualities,$cur_quality,$times,$used_time,$mchid);
+            return [$org_quality,$qualities];
+        }
+        else {
+            $fMixed = PolicyUtil::mixed_quality($org_quality);
+            $qualities = $this->calc_phone_quality($qualities,$fMixed,$cur_quality,$times,$used_time,$time_out,$max_times,$mchid);
+            return [$org_quality,$qualities];
+        }
+    }
+
+    private function ratio_phone_quality($qualities,$cur_quality,$times,$used_time,$mchid)
+    {
+        [$succ,$max_times,$time_out] = $this->mRatioCtl->total($mchid);
+
+        $left_time = $time_out - $used_time;
+        if ($left_time <= 0 || $max_times <= $times) {
+            return [];
+        }
+
+        $match_ratio = $this->mRatioCtl->ratio_match($mchid);
+
+        Log::record("ratio_phone_quality begin qualities= " . implode(',',$qualities),Log::DEBUG);
+        $times_checker = function($qualities, $times) use($match_ratio,$max_times,$mchid)
+        {
+            $result = [];
+            $pre_times = 0;
+            foreach ($qualities as $quality)
+            {
+                if ($match_ratio) {
+                    $result[] = $quality;
+                }
+                else
+                {
+                    $qtimes = $this->mRatioCtl->times($mchid, $quality);
+                    if($qtimes == false) continue;
+
+                    $pre_times += $qtimes;
+                    if ($times < $pre_times) {
+                        $result[] = $quality;
+                    }
+                }
+            }
 
-        $qualities = $this->calc_phone_quality($qualities,$fMixed,$cur_quality,$times,$used_time,$time_out,$max_times,$mchid);
+            return $result;
+        };
+
+        $timeout_checker = function ($qualities, $left_time) use($cur_quality,$match_ratio,$mchid)
+        {
+            if($match_ratio)
+            {
+                $result = [];
+                foreach ($qualities as $quality)
+                {
+                    $per_secs = $this->mSpeeds[$quality]['per_secs'];
+                    $left_time -= $per_secs;
+                    if($left_time > 0) {
+                        $result[] = $quality;
+                    } else {
+                        break;
+                    }
+                }
+
+                return $result;
+            }
+            else
+            {
+                $result = [];
+
+                $qualities = array_reverse($qualities);
+                foreach ($qualities as $quality)
+                {
+                    $per_secs = $this->mSpeeds[$quality]['per_secs'];
+                    $qsecs = $this->mRatioCtl->seconds($mchid, $quality);
+                    if($qsecs == false) continue;
+
+                    if($left_time - $qsecs > 0) {
+                        $left_time -= $qsecs;
+                        $result[] = $quality;
+                    }
+                    elseif($left_time - $per_secs > 0) {
+                        $left_time -= $per_secs;
+                        $result[] = $quality;
+                    }
+                    else {
+                        break;
+                    }
+                }
+                $result = array_reverse($result);
+
+                return $result;
+            }
+        };
+
+        $pTryAdjuster = $this->mTryAdjuster;
+        $timeing_checker = function ($qualities) use($pTryAdjuster,$mchid)
+        {
+            foreach ($qualities as $quality)
+            {
+                $ret = $pTryAdjuster->can_try($mchid,$quality);
+                if($ret == false) {
+                    return false;
+                }
+            }
+
+            return true;
+        };
+
+        if($times > 0)
+        {
+            $qualities = $times_checker($qualities,$times);
+            Log::record("calc_quality times_checker result = " . implode(',', $qualities), Log::DEBUG);
+            $qualities = $timeout_checker($qualities,$left_time);
+            Log::record("calc_quality timeout_checker result = " . implode(',', $qualities), Log::DEBUG);
+
+            if(!$timeing_checker($qualities)) {
+                $qualities = [];
+                Log::record("calc_quality timeing_checker result is empty", Log::DEBUG);
+            }
+        }
+
+        return $qualities;
 
-        return [$org_quality,$qualities];
     }
 
     private function max_times($mchid,$quality)
     {
-        global $config;
-        $mtimes = $config['merchant_retry_times'] ?? [];
-
-        if(array_key_exists($mchid,$mtimes) && array_key_exists($quality,$mtimes[$mchid])) {
-            return $mtimes[$mchid][$quality];
-        }
-        else {
+        [$succ, $times,$secs] = $this->mRatioCtl->total($mchid);
+        if ($succ) {
+            return $times;
+        } else {
             return $this->mSpeeds[$quality]['retry_times'];
         }
     }
@@ -273,4 +392,7 @@ class Quality
 
         return $qualities;
     }
+    public function update_mchratios($ratios) {
+        $this->mRatioCtl->update($ratios);
+    }
 }

+ 5 - 0
helper/refill/policy/xyz/policy.php

@@ -418,4 +418,9 @@ class policy extends ProviderManager implements IPolicy
     {
         $this->mChannelControl->update_ratios($ratios);
     }
+
+    public function update_mchratios($ratios)
+    {
+        $this->mQuality->update_mchratios($ratios);
+    }
 }

+ 95 - 0
plot/MchDataCenter.py

@@ -10,6 +10,7 @@ from matplotlib.figure import Figure
 from matplotlib import ticker
 from io import BytesIO
 import logging
+import time as time
 
 
 class MchDataCenter(object):
@@ -368,6 +369,100 @@ class MchDataCenter(object):
             if path == '' or path is None:
                 path = 'average'
             return f"{path}:{count}/{all} = {ratio}%"
+        pass
+
+    #统计机构当前时间之前序列时间成功率
+    def _merge_mobile_path(self,paths):
+        result = {}
+        for path in paths:
+            items = re.split(r'/', path)
+            if len(items) != 6:
+                continue
+            (_, _sday, _mchid, _quality, _card_type, _amount) = items
+
+            _card_type = int(_card_type)
+            if _card_type not in [4, 5, 6]:
+                continue
+
+            _mchid = int(_mchid)
+            if _mchid not in result:
+                result[_mchid] = []
+            result[_mchid].append(path)
+        return result
+
+    def _merge_data(self, hfive, paths):
+        predata = np.zeros((2, 86400))
+        for path in paths:
+            predata += hfive[path]
+        return predata
+
+    def _calc_mratio(self,data,startes,end):
+        all = data[0]
+        ySucc = data[1]
+        x = np.arange(0, 86400, 1)
 
+        result = {}
+        for start in startes:
+            if end - start < 0:
+                start_pos = 0
+            else:
+                start_pos = end - start
+
+            pos = np.where(x >= start_pos)
+            t = x[pos]
+            _all = all[pos]
+            _succ = ySucc[pos]
+
+            pos = np.where(t < end)
+            _all = _all[pos]
+            _succ = _succ[pos]
+
+            succ_count = np.sum(_succ)
+            all_count  = np.sum(_all) + 0.00001
+
+            ratio = round(succ_count / all_count, 2)
+            if ratio > 1.0:
+                ratio = 1.0
+            result[start] = ratio
+        return result
+
+    def mratios(self, time_stamp,presecs):
+        paths = self.paths(time_stamp)
+        mchid_paths = self._merge_mobile_path(paths)
+        day_stamp = self.day_stamp(time_stamp)
+
+        mratios = {}
+        hfive = h5py.File(self._file_name, 'a')
+        for mchid, paths in mchid_paths.items():
+            mdata = self._merge_data(hfive,paths)
+            result = self._calc_mratio(mdata,presecs,time_stamp - day_stamp)
+            mratios[mchid] = result
+        hfive.close()
+        return mratios
+
+    def calc_ratio(self):
+        import json
+
+        r = None
+        try:
+            pool = redis.ConnectionPool(host=self._mRHost, port=self._mRPort, db=0)
+            r = redis.Redis(connection_pool=pool)
+        except Exception as ex:
+            print(ex)
+
+        while True:
+            try:
+                time_sec = int(time.time() - 86400 * 2)
+                presecs = [900, 1800, 3600, 7200, 86400]
+                mratios = self.mratios(time_sec, presecs)
+
+                if len(mratios) != 0:
+                    r.set(f"nc_merchant_ratios", json.dumps(mratios))
+                    r.publish('refill',json.dumps({'type':'mch_ratio','value':0}))
+                    print('push msg=',mratios)
+            except Exception as ex:
+                print(ex)
+            finally:
+                stime.sleep(120)
 
 mchDataCenter = MchDataCenter()

+ 23 - 0
plot/mratio.py

@@ -0,0 +1,23 @@
+from MchDataCenter import mchDataCenter
+import signal as sig
+import sys,getopt
+
+if __name__ == '__main__':
+    try:
+        opts, args = getopt.getopt(sys.argv[1:],"h:p:",["host=",'port='])
+    except Exception as ex:
+        print(ex)
+        sys.exit(2)
+
+    rhost = ''
+    rport=6379
+    for o, val in opts:
+        if o in ("-h", "--host"):
+            rhost = val
+        elif o in ('-p', "--port"):
+            rport = int(val)
+        else:
+            print("Err argv")
+    mchDataCenter.set_redis(rhost,rport)
+    sig.signal(sig.SIGINT, lambda: mchDataCenter.stop())
+    mchDataCenter.calc_ratio()

+ 10 - 1
plot/thdf5.py

@@ -112,7 +112,7 @@ class DataTest(unittest.TestCase):
         dates = dates[0:30]
 
     def test_mchpaths(self):
-        time_stamp = int(time.time())
+        time_stamp = int(time.time() - 86400)
         paths = mchDataCenter.paths(time_stamp)
         print(paths)
 
@@ -131,6 +131,15 @@ class DataTest(unittest.TestCase):
         dataCenter.set_redis('192.168.1.220','6379')
         dataCenter.calc_ratio()
 
+    def test_mchpath(self):
+        time_stamp = int(time.time() - 86400)
+        mchDataCenter.set_redis('192.168.1.220','6379')
+        mchDataCenter.mratios(time_stamp)
+
+    def test_mratio(self):
+        mchDataCenter.set_redis('192.168.1.220','6379')
+        mchDataCenter.calc_ratio()
+
     def test_pubRatio(self):
         dataCenter.set_redis('192.168.1.220','6379')
         dataCenter.pub_ratio()

+ 12 - 0
rdispatcher/codispatcher.php

@@ -91,6 +91,18 @@ function subscribe_message(&$quit, &$redis, $channels)
 
                         refill\RefillFactory::instance()->UpdateRatio($ratios);
                     }
+                    elseif($type == 'mch_ratio') {
+                        $ins = Cache::getInstance('cacheredis');
+                        $val = $ins->get_org('merchant_ratios');
+
+                        Log::record("mch_ratio meessage",Log::DEBUG);
+
+                        if(empty($val)) continue;
+                        $mch_ratios = json_decode($val,true);
+                        if(empty($mch_ratios)) continue;
+
+                        refill\RefillFactory::instance()->UpdatMchRatios($mch_ratios);
+                    }
                     else {
                         Log::record("subscribe_message dont not handle mgs:{$sub_type}-{$channel}-{$type}",Log::DEBUG);
                     }

Разлика између датотеке није приказан због своје велике величине
+ 6 - 0
test/TestBigData.php