stanley-king 4 rokov pred
rodič
commit
99e0e2d951

+ 1 - 1
data/config/dev/base.ini.php

@@ -9,8 +9,8 @@ define('LOCAL_DEBUG',false);
 define('BONUS_EXPIRY_DATE',true);
 define('USE_BONUS_RATE',false);
 define('SERVER_TYPE','panda');
-
 define('CROSS_DOAMIN',true);
+define('COMPANY_NAME', 'LZKJ_COMPANY');
 
 $config = [];
 $config['base_site_url']        = SRV_HOST;

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

@@ -66,6 +66,7 @@
 //
 //$config['phone_providers'] = $phone_providers;
 
+define('ZERO_GOODS_ID',6245);
 
 $config['refill_oil_specs'] = [100 , 200 , 500 , 1000 , 2000];
 $config['refill_phone_specs'] = [10 , 20 , 30 , 50 , 100 , 200 , 300 , 500];

+ 2 - 2
data/model/refill_order.model.php

@@ -11,7 +11,7 @@ class refill_orderModel extends Model
 {
 	public function getOrderInfo($condition = [], $fields = '*', $master = false)
     {
-        $order_info = $this->table('refill_order')->field($fields)->where($condition)->master($master)->find();
+        $order_info = $this->table('refill_order')->field($fields)->where($condition)->order('')->master($master)->find();
         if (empty($order_info)) {
             return [];
         }
@@ -24,7 +24,7 @@ class refill_orderModel extends Model
     }
     public function edit($order_id,$data)
     {
-        return$this->table('refill_order')->where(['order_id' => $order_id])->update($data);
+        return $this->table('refill_order')->where(['order_id' => $order_id])->update($data);
     }
     public function getMerchantOrderList($condition, $pagesize = '', $field = '*', $order = 'refill_order.order_id desc', $limit = '')
     {

+ 14 - 1
docker/compose/stanley/docker-compose.yml

@@ -143,7 +143,7 @@ services:
         - "redisrv"
 
   phpcli:
-    image: php-swool:latest
+    image: php-zts-debug:7.3.18
     volumes:
       - ../../conf/etc/localtime:/etc/localtime:ro
       - ../../conf/php/php-debug.ini:/usr/local/etc/php/php.ini
@@ -153,4 +153,17 @@ services:
     depends_on:
       - "redisrv"
       - "websrv"
+      - "searcher"
+
+  phpswool:
+    image: php-swool-redis:latest
+    volumes:
+      - ../../conf/etc/localtime:/etc/localtime:ro
+      - ../../conf/php/php-swoole-debug.ini:/usr/local/etc/php/php.ini
+      - ../../../:/var/www/html
+      - /Volumes/Transcend/upload:/var/www/html/data/upload
+    container_name: "panda-swoole"
+    depends_on:
+      - "redisrv"
+      - "websrv"
       - "searcher"

+ 12 - 0
helper/exceptionex.php

@@ -47,4 +47,16 @@ class UnImplementsException extends Exception
         $code = errcode::ErrUnImplements;
         parent::__construct($method . ":功能未实现", $code, null);
     }
+}
+
+class LzException extends Exception
+{
+    public function __construct()
+    {
+        $code = errcode::ErrSignParamter;
+        $message = errcode::msg($code);
+
+        parent::__construct($message, $code, null);
+    }
+
 }

+ 10 - 0
helper/queue/iqueue.php

@@ -2,6 +2,9 @@
 declare(strict_types=1);
 
 namespace queue;
+
+require_once(BASE_ROOT_PATH . '/helper/performance_helper.php');
+
 use Redis;
 use Exception;
 use Log;
@@ -160,7 +163,14 @@ abstract class ILooper
             {
                 if ($this->_stop) break;
                 $content = $this->mServer->pop($queues,1);
+                perfor_clear();
+                perfor_start();
+
                 $this->handle($content);
+
+                perfor_end('Handle Request');
+                $info = perfor_log();
+                Log::record("{$info} \r\n\r\n",Log::DEBUG);
             }
             catch (Exception $e)
             {

+ 2 - 1
helper/rbridge/wsd/Bridge.php

@@ -42,7 +42,8 @@ class Bridge implements IBridge
         $idcard = '';
         $card_name = '';
 
-        [$code, $msg] = RefillFactory::instance()->add($mchid, $userid, $params['chargeCash'], $params['chargeAcct'], $params['chargeId'], $idcard, $card_name,config::MCH_NOTIFY_URL);
+        [$code, $msg] = RefillFactory::instance()->add($mchid, $userid, $params['chargeCash'], $params['chargeAcct'], $params['chargeId'],
+            $idcard, $card_name,config::MCH_NOTIFY_URL,1,time(),0);
 
         $ret = $this->retbody($code, $msg, $params);
         return json_encode($ret,JSON_UNESCAPED_UNICODE);

+ 22 - 0
helper/refill/CalcMerchantPrice.php

@@ -48,4 +48,26 @@ class CalcMerchantPrice implements ICalc
         Log::record("没有实现该接口" . __FUNCTION__ ,Log::ERR);
         return [];
     }
+}
+
+class ZeroMerchantPrice implements ICalc
+{
+    public function __construct($mchid,$amount,$card_type)
+    {
+    }
+
+    public function calc_vgoods_price($goods_info)
+    {
+        return round(0,2);
+    }
+    public function calc_vorder_amount($order_info)
+    {
+        return round(0,2);
+    }
+
+    public function calc_tips()
+    {
+        Log::record("没有实现该接口" . __FUNCTION__ ,Log::ERR);
+        return [];
+    }
 }

+ 0 - 25
helper/refill/CoRefillFactory.php

@@ -1,25 +0,0 @@
-<?php
-
-
-namespace refill;
-
-require_once(BASE_HELPER_PATH . '/refill/RefillBase.php');
-
-class CoRefillFactory extends RefillBase
-{
-    private static $stInstance = null;
-
-    public static function instance()
-    {
-        if (self::$stInstance == null) {
-            self::$stInstance = new CoRefillFactory();
-        }
-
-        return self::$stInstance;
-    }
-
-    private function __construct()
-    {
-        $this->load();
-    }
-}

+ 52 - 0
helper/refill/LZRefillFactory.php

@@ -0,0 +1,52 @@
+<?php
+
+namespace refill;
+
+require_once(BASE_HELPER_PATH . '/refill/RefillBase.php');
+require_once(BASE_HELPER_PATH . '/refill/ProviderManager.php');
+require_once(BASE_HELPER_PATH . '/refill/policy/IPolicy.php');
+require_once(BASE_HELPER_PATH . '/refill/policy/lingzh/policy.php');
+
+use Log;
+use StatesHelper;
+
+class LZRefillFactory extends RefillBase
+{
+    private static $stInstance = null;
+
+    public static function instance()
+    {
+        if (self::$stInstance == null) {
+            self::$stInstance = new LZRefillFactory();
+        }
+
+        if(defined('SUPPORT_PTHREAD') && SUPPORT_PTHREAD === true)
+        {
+            Log::record("SUPPORT_PTHREAD defined call load",Log::DEBUG);
+            if(StatesHelper::fetch_state('channel')) {
+                Log::record("RefillFactory reload channel config.",Log::DEBUG);
+                self::$stInstance->load();
+            }
+        }
+
+        return self::$stInstance;
+    }
+
+    private function load()
+    {
+        $this->mPolicy->load();
+    }
+
+    private function __construct()
+    {
+        parent::__construct();
+        $this->mPolicy = new policy();
+
+        if (defined('SUPPORT_PTHREAD') && SUPPORT_PTHREAD === true) {
+            Log::record("SUPPORT_PTHREAD defined dont call load",Log::DEBUG);
+        } else {
+            Log::record("SUPPORT_PTHREAD has not defined and call load",Log::DEBUG);
+            $this->load();
+        }
+    }
+}

+ 251 - 0
helper/refill/ProviderManager.php

@@ -0,0 +1,251 @@
+<?php
+
+
+namespace refill;
+
+require_once(BASE_HELPER_PATH . '/mtopcard/mtopcard.php');
+require_once(BASE_HELPER_PATH . '/refill/IRefill.php');
+require_once(BASE_HELPER_PATH . '/refill/IRefillOil.php');
+require_once(BASE_HELPER_PATH . '/refill/IRefillPhone.php');
+require_once(BASE_HELPER_PATH . '/refill/IRefillCallBack.php');
+require_once(BASE_HELPER_PATH . '/refill/CalcMerchantPrice.php');
+require_once(BASE_HELPER_PATH . '/refill/util.php');
+require_once(BASE_HELPER_RAPI_PATH . '/api.php');
+
+use Log;
+use mtopcard;
+use Exception;
+
+class ProviderManager
+{
+    protected $mOilProvider;
+    protected $mPhoneProvider;
+    protected $mProviderNames;
+
+    public function __construct()
+    {
+    }
+
+    public function load()
+    {
+        $this->mOilProvider = [];
+        $this->mPhoneProvider = [];
+        $this->mProviderNames = [];
+
+        global $config;
+        $oil_configs = $config['oil_providers'];
+
+        $cfg_table = $this->read_channel();
+
+        $names = [];
+        foreach ($oil_configs as $item)
+        {
+            $name = $item['name'];
+            $cfg = $item['cfg'];
+
+            if(!array_key_exists($name,$cfg_table)) {
+                continue;
+            }
+
+            try {
+                $class = "refill\\{$name}\\RefillOil";
+                $table = $cfg_table[$name];
+
+                if (class_exists($class, false)) {
+                    $provider = new $class($cfg);
+                    $provider->setOpened($table['opened']);
+                    $provider->setSort($table['sort']);
+
+                    $names[] = $name;
+                    $this->mOilProvider[] = $provider;
+                } else {
+                    $error = "Base Error: class {$class} isn't exists!";
+                    throw new Exception($error);
+                }
+            } catch (Exception $ex) {
+                Log::record($ex->getMessage(), Log::ERR);
+            }
+        }
+
+        $pho_configs = $config['phone_providers'];
+        foreach ($pho_configs as $item)
+        {
+            $name = $item['name'];
+            $cfg = $item['cfg'];
+
+            if(!array_key_exists($name,$cfg_table)) {
+                continue;
+            }
+
+            try {
+                $class = "refill\\{$name}\\RefillPhone";
+                $table = $cfg_table[$name];
+
+                if (class_exists($class, false)) {
+                    $provider = new $class($cfg);
+                    $provider->setOpened($table['opened']);
+                    $provider->setSort($table['sort']);
+                    $names[] = $name;
+
+                    $this->mPhoneProvider[] = $provider;
+                } else {
+                    $error = "Base Error: class {$class} isn't exists!";
+                    throw new Exception($error);
+                }
+            } catch (Exception $ex) {
+                Log::record($ex->getMessage(), Log::ERR);
+            }
+        }
+
+        $this->mProviderNames = array_unique($names);
+    }
+
+    public function read_channel()
+    {
+        $refill_provider = Model('refill_provider');
+        $items = $refill_provider->getProviderList([]);
+
+        $result = [];
+        foreach ($items as $item) {
+            $name = $item['name'];
+            $val = ['type' => intval($item['type']),
+                    'opened' => (intval($item['opened']) == 1) ? true : false,
+                    'sort' => intval($item['sort'])];
+            $result[$name] = $val;
+        }
+
+        return $result;
+    }
+
+    public function find_providers(int $amount, int $card_type,int $quality): array
+    {
+        if ($card_type == mtopcard\SinopecCard || $card_type == mtopcard\PetroChinaCard) {
+            return $this->find_oil($amount, $card_type);
+        } elseif ($card_type == mtopcard\ChinaMobileCard || $card_type == mtopcard\ChinaUnicomCard || $card_type == mtopcard\ChinaTelecomCard) {
+            return $this->find_phone($amount, $card_type);
+        } else {
+            return [];
+        }
+    }
+
+    public function provider(string $chname, int $card_type)
+    {
+        if ($card_type == mtopcard\SinopecCard || $card_type == mtopcard\PetroChinaCard) {
+            $providers = $this->mOilProvider;
+        } elseif ($card_type == mtopcard\ChinaMobileCard || $card_type == mtopcard\ChinaUnicomCard || $card_type == mtopcard\ChinaTelecomCard) {
+            $providers = $this->mPhoneProvider;
+        } else {
+            return null;
+        }
+
+        foreach ($providers as $provider)
+        {
+            if ($provider->name() == $chname) {
+                return $provider;
+            }
+        }
+        return null;
+    }
+
+    private function find_oil(int $amount, int $card_type): array
+    {
+        $providers = [];
+        foreach ($this->mOilProvider as $provider) {
+            $name = $provider->name();
+            [$success, $err] = $provider->check($amount, $card_type);
+            if ($success) {
+                $providers[] = $provider;
+            } else {
+                Log::record("{$name} provider cannot match check,err:{$err}", Log::DEBUG);
+            }
+        }
+
+        return $providers;
+    }
+
+    private function find_phone(int $amount, int $card_type): array
+    {
+        $providers = [];
+        foreach ($this->mPhoneProvider as $provider) {
+            $name = $provider->name();
+            [$success, $err] = $provider->check($amount, $card_type);
+            if ($success) {
+                $providers[] = $provider;
+            } else {
+                Log::record("{$name} provider cannot match check,err:{$err}", Log::DEBUG);
+            }
+        }
+
+        return $providers;
+    }
+
+    public function combine_goods($configs,$type)
+    {
+        $mod_prov = Model('refill_provider');
+        $provider_items = $mod_prov->getProviderList(['type' => $type]);
+        foreach ($provider_items as $item) {
+            $providers[$item['name']] = $item;
+        }
+        $result = [];
+        foreach ($configs as $item)
+        {
+            if($providers[$item['name']]['opened'] != 1) {
+                continue;
+            }
+            $cfg = $item['cfg'];
+
+            $card_types = $cfg['card_type'] ?? [];
+            $amounts = $cfg['amount'] ?? [];
+
+            foreach ($card_types as $type) {
+                if (array_key_exists($type, $result)) {
+                    $item = $result[$type];
+                } else {
+                    $item = [];
+                }
+
+                foreach ($amounts as $amount => $val) {
+                    $item[] = $amount;
+                }
+                $item = array_unique($item);
+                $result[$type] = $item;
+            }
+        }
+
+        return $result;
+    }
+
+    public function goods()
+    {
+        global $config;
+
+        $oil = $this->combine_goods($config['oil_providers'], 1);
+        $phone = $this->combine_goods($config['phone_providers'], 2);
+
+        return array_merge($oil, $phone);
+    }
+    public function providers()
+    {
+        return ['oil' => $this->mOilProvider,'phone' => $this->mPhoneProvider];
+    }
+
+    public function getCaller($chname)
+    {
+        try
+        {
+            $class_name = "refill\\{$chname}\\RefillCallBack";
+            if (class_exists($class_name, false)) {
+                $caller = new $class_name();
+                return $caller;
+            } else {
+                $error = "Base Error: class {$class_name} isn't exists!";
+                Log::record($error, Log::ERR);
+                return false;
+            }
+        }
+        catch (Exception $ex) {
+            Log::record($ex->getMessage(), Log::ERR);
+            return false;
+        }
+    }
+}

+ 124 - 425
helper/refill/RefillBase.php

@@ -1,19 +1,19 @@
 <?php
 
-
 namespace refill;
 
 require_once(BASE_HELPER_PATH . '/queue/rdispatcher.php');
 require_once(BASE_HELPER_PATH . '/mtopcard/mtopcard.php');
 require_once(BASE_HELPER_PATH . '/rbridge/RBridgeFactory.php');
-
-
 require_once(BASE_HELPER_PATH . '/refill/IRefill.php');
 require_once(BASE_HELPER_PATH . '/refill/IRefillOil.php');
 require_once(BASE_HELPER_PATH . '/refill/IRefillPhone.php');
 require_once(BASE_HELPER_PATH . '/refill/IRefillCallBack.php');
+require_once(BASE_HELPER_PATH . '/refill/ProviderManager.php');
 require_once(BASE_HELPER_PATH . '/refill/CalcMerchantPrice.php');
 require_once(BASE_HELPER_PATH . '/refill/util.php');
+require_once(BASE_HELPER_PATH . '/refill/errcode.php');
+
 require_once(BASE_HELPER_RAPI_PATH . '/api.php');
 
 use Log;
@@ -23,269 +23,38 @@ use member_info;
 use Exception;
 use rbridge\RBridgeFactory;
 use trans_wapper;
-use StatesHelper;
-use queue;
 
 class RefillBase
 {
-    protected $mOilProvider;
-    protected $mPhoneProvider;
-    protected $mProviderNames;
-    protected $mLimits = [];
-
-    public function allow($mchid,$card_type,$amount)
-    {
-        $reader = function () {
-            $cache = rcache("refill_able",'merchant-');
-            if(!empty($cache)) {
-                $result = unserialize($cache['data']);
-            }
-            else {
-                $result = [];
-            }
-            return $result;
-        };
-
-        if(defined('MOBILE_SERVER') && MOBILE_SERVER === true)
-        {
-            if(StatesHelper::fetch_state('merchant')) {
-                $this->mLimits = $reader();
-            }
-        }
-        else {
-            $this->mLimits = $reader();
-        }
-
-        $key = "{$mchid}-{$card_type}-{$amount}";
-        if(empty($this->mLimits)) {
-            return true;
-        }
-        elseif(array_key_exists($key,$this->mLimits)) {
-            return $this->mLimits[$key];
-        }
-        else {
-            return true;
-        }
-    }
-
-    public function goods()
-    {
-        global $config;
-
-        $oil = $this->combine_goods($config['oil_providers'], 1);
-        $phone = $this->combine_goods($config['phone_providers'], 2);
-
-        return array_merge($oil, $phone);
-    }
-
-    public function providers()
-    {
-        return ['oil' => $this->mOilProvider,'phone' => $this->mPhoneProvider];
-    }
-
-    private function combine_goods($configs,$type)
-    {
-        $mod_prov = Model('refill_provider');
-        $provider_items = $mod_prov->getProviderList(['type' => $type]);
-        foreach ($provider_items as $item) {
-            $providers[$item['name']] = $item;
-        }
-        $result = [];
-        foreach ($configs as $item)
-        {
-            if($providers[$item['name']]['opened'] != 1) {
-                continue;
-            }
-            $cfg = $item['cfg'];
-
-            $card_types = $cfg['card_type'] ?? [];
-            $amounts = $cfg['amount'] ?? [];
-
-            foreach ($card_types as $type) {
-                if (array_key_exists($type, $result)) {
-                    $item = $result[$type];
-                } else {
-                    $item = [];
-                }
-
-                foreach ($amounts as $amount => $val) {
-                    $item[] = $amount;
-                }
-                $item = array_unique($item);
-                $result[$type] = $item;
-            }
-        }
-
-        return $result;
-    }
-
-    public function read_channel()
-    {
-        $refill_provider = Model('refill_provider');
-        $items = $refill_provider->getProviderList([]);
-
-        $result = [];
-        foreach ($items as $item) {
-            $name = $item['name'];
-            $val = ['type' => intval($item['type']),
-                'opened' => (intval($item['opened']) == 1) ? true : false,
-                'sort' => intval($item['sort'])];
-            $result[$name] = $val;
-        }
-
-        return $result;
-    }
-
-    protected function load()
-    {
-        $this->mOilProvider = [];
-        $this->mPhoneProvider = [];
-        $this->mProviderNames = [];
-
-        global $config;
-        $oil_configs = $config['oil_providers'];
-
-        $cfg_table = $this->read_channel();
-        $names = [];
-        foreach ($oil_configs as $item)
-        {
-            $name = $item['name'];
-            $cfg = $item['cfg'];
-
-            if(!array_key_exists($name,$cfg_table)) {
-                continue;
-            }
-
-            try {
-                $class = "refill\\{$name}\\RefillOil";
-                $table = $cfg_table[$name];
-
-                if (class_exists($class, false)) {
-                    $provider = new $class($cfg);
-                    $provider->setOpened($table['opened']);
-                    $provider->setSort($table['sort']);
-
-                    $names[] = $name;
-                    $this->mOilProvider[] = $provider;
-                } else {
-                    $error = "Base Error: class {$class} isn't exists!";
-                    throw new Exception($error);
-                }
-            } catch (Exception $ex) {
-                Log::record($ex->getMessage(), Log::ERR);
-            }
-        }
+    protected $mPolicy;
 
-        $pho_configs = $config['phone_providers'];
-        foreach ($pho_configs as $item)
-        {
-            $name = $item['name'];
-            $cfg = $item['cfg'];
-
-            if(!array_key_exists($name,$cfg_table)) {
-                continue;
-            }
-
-            try {
-                $class = "refill\\{$name}\\RefillPhone";
-                $table = $cfg_table[$name];
-
-                if (class_exists($class, false)) {
-                    $provider = new $class($cfg);
-                    $provider->setOpened($table['opened']);
-                    $provider->setSort($table['sort']);
-                    $names[] = $name;
-
-                    $this->mPhoneProvider[] = $provider;
-                } else {
-                    $error = "Base Error: class {$class} isn't exists!";
-                    throw new Exception($error);
-                }
-            } catch (Exception $ex) {
-                Log::record($ex->getMessage(), Log::ERR);
-            }
-        }
-
-        $this->mProviderNames = array_unique($names);
-    }
-
-    public function find_providers(int $amount, int $card_type): array
+    protected $mLimits = [];
+    protected function __construct()
     {
-        if ($card_type == mtopcard\SinopecCard || $card_type == mtopcard\PetroChinaCard) {
-            return $this->find_oil($amount, $card_type);
-        } elseif ($card_type == mtopcard\ChinaMobileCard || $card_type == mtopcard\ChinaUnicomCard || $card_type == mtopcard\ChinaTelecomCard) {
-            return $this->find_phone($amount, $card_type);
-        } else {
-            return [];
-        }
     }
 
-    private function find_oil(int $amount, int $card_type): array
+    public function allow($mchid,$card_type,$amount,$quality)
     {
-        $providers = [];
-        foreach ($this->mOilProvider as $provider) {
-            $name = $provider->name();
-            [$success, $err] = $provider->check($amount, $card_type);
-            if ($success) {
-                $providers[] = $provider;
-            } else {
-                Log::record("{$name} provider cannot match check,err:{$err}", Log::DEBUG);
-            }
-        }
-
-        return $providers;
+        return $this->mPolicy->allow($mchid,$card_type,$amount,$quality);
     }
 
-    public function provider(string $chname, int $card_type)
+    public function goods()
     {
-        if ($card_type == mtopcard\SinopecCard || $card_type == mtopcard\PetroChinaCard) {
-            $providers = $this->mOilProvider;
-        } elseif ($card_type == mtopcard\ChinaMobileCard || $card_type == mtopcard\ChinaUnicomCard || $card_type == mtopcard\ChinaTelecomCard) {
-            $providers = $this->mPhoneProvider;
-        } else {
-            return null;
-        }
-
-        foreach ($providers as $provider) {
-            if ($provider->name() == $chname) {
-                return $provider;
-            }
-        }
-        return null;
+        return $this->mPolicy->goods();
     }
 
-    private function find_phone(int $amount, int $card_type): array
+    public function providers()
     {
-        $providers = [];
-        foreach ($this->mPhoneProvider as $provider) {
-            $name = $provider->name();
-            [$success, $err] = $provider->check($amount, $card_type);
-            if ($success) {
-                $providers[] = $provider;
-            } else {
-                Log::record("{$name} provider cannot match check,err:{$err}", Log::DEBUG);
-            }
-        }
-
-        return $providers;
+        return $this->mPolicy->providers();
     }
 
     public function notify($chname, $input)
     {
-        try {
-            $class_name = "refill\\{$chname}\\RefillCallBack";
-            if (class_exists($class_name, false)) {
-                $caller = new $class_name();
-            } else {
-                $error = "Base Error: class {$class_name} isn't exists!";
-                throw new Exception($error);
-            }
-        } catch (Exception $ex) {
-            Log::record($ex->getMessage(), Log::ERR);
+        $caller = $this->mPolicy->getCaller($chname);
+        if($caller === false) {
             return false;
         }
-
-        if ($caller->verify($input))
+        elseif ($caller->verify($input))
         {
             [$order_id, $success, $can_try, $need_handle] = $caller->notify($input);
             if (!$need_handle) {
@@ -311,7 +80,6 @@ class RefillBase
                     try
                     {
                         $mod_refill = Model('refill_order');
-
                         $trans = new trans_wapper($mod_refill, __METHOD__);
                         $refill_info = $mod_refill->getOrderInfo(['order_id' => $order_id,'inner_status' => 0]);
                         if(!empty($refill_info))
@@ -323,9 +91,7 @@ class RefillBase
                                 return true;
                             }
                         }
-
                         $trans->commit();
-
                     }
                     catch (Exception $ex) {
                         $trans->rollback();
@@ -341,81 +107,105 @@ class RefillBase
                 QueueClient::push("NotifyMerchantComplete", ['order_id' => $order_id,'manual' => false]);
             } else {
                 Log::record("系统无此订单ID:{$order_id}", Log::ERR);
-
             }
-        } else {
+        }
+        else {
             Log::record("{$chname} 签名失败.");
         }
+
         return true;
     }
 
     private function retry(array $refill_info, array $order_info)
     {
-        $checker = function ($refill, $order) {
-            $state = intval($order['order_state']);
-            if ($state !== ORDER_STATE_SEND) {
-                Log::record("retry false:order_state != send", Log::DEBUG);
-                return false;
-            }
-
-            $times = intval($refill['commit_times']);
-            if ($times > 15) {
-                return false;
-            }
+        if($this->mPolicy->can_retry($refill_info,$order_info)) {
+            return false;
+        }
 
-            $period = time() - $refill['order_time'];
-            if ($period >= 15 * 60) {
-                Log::record("retry false:time > 15m", Log::DEBUG);
-                return false;
-            }
+        $params = [ 'mchid' => $refill_info['mchid'],
+            'buyer_id' => $order_info['buyer_id'],
+            'amount' => $refill_info['refill_amount'],
+            'card_no' => $refill_info['card_no'],
+            'quality' => $refill_info['quality'],
+            'mch_order' =>  $refill_info['mch_order'],
+            'notify_url' => $refill_info['notify_url'],
+            'idcard' => $refill_info['idcard'] ?? '',
+            'card_name' => $refill_info['card_name'] ?? '',
+            'order_time' => $refill_info['order_time'],
+            'commit_times' => $refill_info['commit_times'] + 1
+        ];
+
+        return util::push_add($params);
+    }
 
-            return true;
-        };
+    public function zero_order($mchid, $buyer_id, $amount, $card_no,
+                        $mch_order, $idcard, $card_name, $notify_url,$quality,
+                        $order_time = 0, $commit_times = 0,$errmsg='')
+    {
+        $card_type = mtopcard\card_type($card_no);
+        $minfo = new member_info($buyer_id);
 
-        $can_try = $checker($refill_info, $order_info);
-        if (!$can_try) {
-            return false;
-        }
+        $calc = new ZeroMerchantPrice($mchid, $amount, $card_type);
+        $mch_amount = $calc->calc_vgoods_price([]);
 
-        $mchid = $refill_info['mchid'];
-        $buyer_id = $order_info['buyer_id'];
-        $amount = $refill_info['refill_amount'];
-        $card_no = $refill_info['card_no'];
-        $mch_order = $refill_info['mch_order'];
-        $notify_url = $refill_info['notify_url'];
-        $commit_times = $refill_info['commit_times'] + 1;
-        $order_time = $refill_info['order_time'];
+        $input['goods_id'] = ZERO_GOODS_ID;
+        $input['quantity'] = 1; //数量
+        $input['buyer_phone'] = $minfo->mobile();
+        $input['buyer_name']  = $minfo->truename();
+        $input['buyer_msg']   = $_POST['buyer_msg'] ?? '';
+        $input['order_from']  = 1;
+        $input['pd_pay'] = true;
 
-        $idcard = $refill_info['idcard'] ?? '';
-        $card_name = $refill_info['card_name'] ?? '';
+        $logic_buy_virtual = Logic('buy_virtual');
+        $result = $logic_buy_virtual->buyStep3($input, $buyer_id, [$calc, 'calc_vorder_amount'], true);
 
-        [$success, $err] = $this->add($mchid, $buyer_id, $amount, $card_no, $mch_order, $idcard, $card_name, $notify_url, $order_time, $commit_times);
-        Log::record("retry result:{$success} , err: {$err}", Log::DEBUG);
-        return ($success === true);
-    }
+        $mod_refill = Model('refill_order');
+        if ($result['state'] === true)
+        {
+            $order_sn = $result['data']['order_sn'];
+            $order_id = $result['data']['order_id'];
 
-    public function push_add($params)
-    {
-        return queue\DispatcherClient::instance()->push('add',$params);
-    }
+            $logic_vr_order = Logic("vr_order");
+            $order_info = Model('vr_order')->getOrderInfo(['order_id' => $order_id]);
+            $logic_vr_order->changeOrderStateCancel($order_info, '', '无法下单创建0元订单');
 
-    public function push_notify($params)
-    {
-        queue\DispatcherClient::instance()->push('notify',$params);
+            if (empty($mch_order)) {
+                $mch_order = $order_sn;
+            }
+            //虚拟订单表信息扩展
+            $orderext = ['order_id' => $order_id, 'order_sn' => $order_sn, 'mchid' => $mchid,
+                'refill_amount' => $amount, 'mch_order' => $mch_order,
+                'idcard' => $idcard, 'card_name' => $card_name,
+                'notify_url' => $notify_url, 'channel_name' => '',
+                'mch_amount' => $mch_amount, 'channel_amount' => 0,
+                'order_time' => $order_time, 'commit_times' => $commit_times,
+                'card_type' => $card_type, 'card_no' => $card_no,'quality' => $quality,'err_msg' => $errmsg];
+            $mod_refill->add_refill($orderext);
+            return $order_id;
+        }
+        else {
+            return 0;
+        }
     }
 
-    public function push_notify_merchant($params)
+    public function can_nettry($quality,$order_time,$commit_times) : bool
     {
-        queue\DispatcherClient::instance()->push('notify_mechant',$params);
+        return $this->mPolicy->can_nettry($quality,$order_time,$commit_times);
     }
 
-    public function add($mchid, $buyer_id, $amount, $card_no, $mch_order, $idcard, $card_name, $notify_url, $order_time = 0, $commit_times = 0)
+    //$quality,质量
+    //返回值:[ 错误码,错误信息,订单ID,是否是网络错误]
+    //说明:错误码为true 表示成功
+    //     其它情况,则需要判断订单ID
+    public function add($mchid, $buyer_id, $amount, $card_no,
+                        $mch_order, $idcard, $card_name, $notify_url,$quality,
+                        $order_time, $commit_times)
     {
         $card_type = mtopcard\card_type($card_no);
-        $providers = $this->find_providers($amount, $card_type);
+        $providers = $this->mPolicy->find_providers($amount,$card_type,$quality);
 
         if (empty($providers)) {
-            return [202, "找不到合适的充值通道"];
+            return [errcode::CANNOT_MATCH_PROVIDER, "匹配不到合适的充值通道",0,false];
         }
 
         if (empty($notify_url)) {
@@ -425,50 +215,29 @@ class RefillBase
         $minfo = new member_info($buyer_id);
         $calc = new CalcMerchantPrice($mchid, $amount, $card_type);
         $mch_amount = $calc->calc_vgoods_price([]);
+
         $available = $minfo->available_predeposit();
         if ($mch_amount > $available) {
             Log::record("下单时机构余额不足,可用余额为:{$available}", Log::DEBUG);
-            return [203, "余额不足"];
-        }
-
-        if ($order_time === 0) {
-            $order_time = time();
+            return [errcode::MERCHANT_SHORT_MONEY, "余额不足支付订单",0,false];
         }
 
-        $ascending = function ($l, $r) use ($amount) {
-            [$lid, $lprice] = $l->goods($amount);
-            [$rid, $rprice] = $r->goods($amount);
-
-            $lsort = $l->sort();
-            $rsort = $r->sort();
-
-            if($lprice == $rprice) {
-                return $lsort < $rsort ? -1 : 1;
-            }
-            else {
-                return $lprice < $rprice ? -1 : 1;
-            }
-        };
-        usort($providers, $ascending);
-
         $refill_state = false;
+        $order_success = false;
         foreach ($providers as $provider)
         {
-            if(!$provider->opened()) continue;
-
             $channel_name = $provider->name();
-            [$goods_id, $price] = $provider->goods($amount);
 
+            //通道价格大于客户价格,换通道.
+            [$goods_id, $price] = $provider->goods($amount);
             if ($price > $mch_amount) continue;
 
             $input['goods_id'] = $goods_id;
-            $input['quantity'] = 1;
-            $input['price'] = $price;
-
+            $input['quantity'] = 1; //数量
             $input['buyer_phone'] = $minfo->mobile();
-            $input['buyer_name'] = $minfo->truename();
-            $input['buyer_msg'] = $_POST['buyer_msg'] ?? '';
-            $input['order_from'] = 1;
+            $input['buyer_name']  = $minfo->truename();
+            $input['buyer_msg']   = $_POST['buyer_msg'] ?? '';
+            $input['order_from']  = 1;
             $input['pd_pay'] = true;
 
             $logic_buy_virtual = Logic('buy_virtual');
@@ -497,21 +266,21 @@ class RefillBase
                     'notify_url' => $notify_url, 'channel_name' => $channel_name,
                     'mch_amount' => $mch_amount, 'channel_amount' => $price,
                     'order_time' => $order_time, 'commit_times' => $commit_times,
-                    'card_type' => $card_type, 'card_no' => $card_no];
+                    'card_type' => $card_type, 'card_no' => $card_no,'quality' => $quality];
                 $mod_refill->add_refill($orderext);
             } else {
                 continue;
             }
 
+            $order_success = true;
+            util::incr_order($channel_name,$card_type,$amount,$quality);
             $params = ['order_sn' => $order_sn, 'idcard' => $idcard, 'card_name' => $card_name];
-//            [$state, $err] = $provider->add($card_no, $card_type, $amount, $params);
-
-            $px = $this->provider('baidu',$card_type);
-            [$state, $err] = $px->add($card_no, $card_type, $amount, $params);
+            [$state, $errmsg,$neterr] = $provider->add($card_no, $card_type, $amount, $params);
 
             if ($state)
             {
-                $trade_no = $err;
+                //提交成功
+                $trade_no = $errmsg;
                 if ($provider->refill_type() == 'api') {
                     $logic_vr_order = Logic("vr_order");
                     $logic_vr_order->changeOrderStateSend($order_id);
@@ -527,8 +296,10 @@ class RefillBase
                 }
 
                 break;
-            } else {
-                Log::record("channel:{$channel_name} err:{$err}");
+            }
+            else {
+                //提交失败
+                Log::record("channel:{$channel_name} err:{$errmsg}");
                 $logic_vr_order = Logic("vr_order");
                 $order_info = Model('vr_order')->getOrderInfo(['order_id' => $order_id]);
                 $logic_vr_order->changeOrderStateCancel($order_info, '', "调用{$channel_name}接口失败");
@@ -537,9 +308,13 @@ class RefillBase
         }
 
         if ($refill_state) {
-            return [true, $order_sn];
-        } else {
-            return [204, "充值失败."];
+            return [true, '', $order_id,false];
+        }
+        elseif($order_success) {
+            return [errcode::MERCHANT_REFILL_ERROR, "充值失败",$order_id,$neterr];
+        }
+        else {
+            return [errcode::MERCHANT_REFILL_ERROR, "充值失败",0,false];
         }
     }
 
@@ -552,16 +327,6 @@ class RefillBase
         return ($api_pay_amount == ncPriceFormat(0.00));
     }
 
-    private function is_url($url)
-    {
-        $checker = function ($haystack, $needle) {
-            $length = strlen($needle);
-            return (substr($haystack, 0, $length) === $needle);
-        };
-
-        return $checker($url, "http://") || $checker($url, "https://");
-    }
-
     public function notify_merchant($order_id,$manual)
     {
         if ($order_id <= 0) {
@@ -589,32 +354,19 @@ class RefillBase
             return [false, "回调地址为空"];
         }
 
+        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
         $order_state = $order_info['order_state'];
-        if ($order_state == ORDER_STATE_CANCEL) {
-            $state = "CANCEL";
-        } elseif ($order_state == ORDER_STATE_SUCCESS) {
-            $state = "SUCCESS";
-        } else {
+        if ($order_state !== ORDER_STATE_CANCEL && $order_state !== ORDER_STATE_SUCCESS) {
             return [false, "错误的订单状态,不能通知."];
         }
+        $resp = $this->mPolicy->notify($order_info,$refill_info);
 
-        $mchid = $refill_info['mchid'];
-        $mch_info = Model('merchant')->getMerchantInfo(['mchid' => $mchid]);
-
-        [$params, $sign] = $this->body($state, $refill_info, $mch_info);
-        $params['sign'] = $sign;
-
-        //如果http请求内部,又发出回调自己的请求,在处理进程非动态扩容的情况下,容易造成阻塞.
-        if ($this->is_url($notify_url)) {
-            $resp = http_request($notify_url, $params, 'POST');
-        } else {
-            $resp = RBridgeFactory::instance()->notify($notify_url, $params);
-        }
-
-        if ($resp == "SUCCESS") {
+        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+        if ($resp) {
             $refill_order->edit($order_id, ['mch_notify_state' => 1, 'mch_notify_times' => ['exp', 'mch_notify_times+1']]);
             return [true, ""];
-        } else {
+        }
+        else {
             $refill_order->edit($order_id, ['mch_notify_times' => ['exp', 'mch_notify_times+1']]);
             $times = $refill_info['mch_notify_times'] + 1;
 
@@ -625,6 +377,7 @@ class RefillBase
                 $period = intval(pow(2, $N));
                 QueueClient::async_push("NotifyMerchantComplete", ['order_id' => $order_id,'manual' => false], $period);
             }
+
             return [false, "通知{$times}次,失败."];
         }
     }
@@ -637,7 +390,7 @@ class RefillBase
         $chname = $refill_info['channel_name'];
         $card_type = intval($refill_info['card_type']);
 
-        $provider = $this->provider($chname, $card_type);
+        $provider = $this->mPolicy->provider($chname, $card_type);
         [$state, $order_state] = $provider->query($refill_info);
 
         if ($state === true)
@@ -673,58 +426,4 @@ class RefillBase
             return false;
         }
     }
-
-    private function body($state, $refill_info, $mch_info)
-    {
-        $params = [
-            "mchid" => $refill_info['mchid'],
-            "order_sn" => $refill_info['mch_order'],
-            "amount" => $refill_info['refill_amount'],//intval($refill_info['refill_amount'] + 0.05),
-            "cardno" => $refill_info['card_no'],
-            "trade_no" => $refill_info['order_sn'],
-            "idcard" => $refill_info['idcard'] ?? "",
-            "card_name" => $refill_info['card_name'] ?? "",
-            'official_sn' => $refill_info['official_sn'] ?? "",
-            'message' => $refill_info['err_msg'] ?? "",
-            "state" => $state];
-
-        $secure_key = $mch_info['secure_key'];
-        $sign = $this->sign($params, $secure_key);
-
-        return [$params, $sign];
-    }
-
-    private function sign($params, $key)
-    {
-        ksort($params);
-
-        $body = "";
-        $i = 0;
-        foreach ($params as $k => $v) {
-            if (false === $this->check_empty($v) && "@" != substr($v, 0, 1)) {
-                if ($i == 0) {
-                    $body .= "{$k}" . "=" . urlencode($v);
-                } else {
-                    $body .= "&" . "{$k}" . "=" . urlencode($v);
-                }
-                $i++;
-            }
-        }
-        $body .= "&key={$key}";
-        Log::record("notify body={$body}",Log::DEBUG);
-
-        return md5($body);
-    }
-
-    private function check_empty($value)
-    {
-        if (!isset($value))
-            return true;
-        if ($value === null)
-            return true;
-        if (trim($value) === "")
-            return true;
-
-        return false;
-    }
 }

+ 7 - 33
helper/refill/RefillFactory.php

@@ -1,44 +1,18 @@
 <?php
 
-
 namespace refill;
 
-
-require_once(BASE_HELPER_PATH . '/refill/RefillBase.php');
-
-
-use Log;
-use StatesHelper;
-
-class RefillFactory extends RefillBase
+class RefillFactory
 {
-    private static $stInstance = null;
-
     public static function instance()
     {
-        if (self::$stInstance == null) {
-            self::$stInstance = new RefillFactory();
+        if(defined('COMPANY_NAME') && COMPANY_NAME === 'LZKJ_COMPANY') {
+            require_once(BASE_HELPER_PATH . '/refill/LZRefillFactory.php');
+            return LZRefillFactory::instance();
         }
-
-        if(defined('SUPPORT_PTHREAD') && SUPPORT_PTHREAD === true)
-        {
-            Log::record("MOBILE_SERVER defined call load",Log::DEBUG);
-            if(StatesHelper::fetch_state('channel')) {
-                Log::record("RefillFactory reload channel config.",Log::DEBUG);
-                self::$stInstance->load();
-            }
-        }
-
-        return self::$stInstance;
-    }
-
-    private function __construct()
-    {
-        if (defined('SUPPORT_PTHREAD') && SUPPORT_PTHREAD === false) {
-            Log::record("SUPPORT_PTHREAD defined dont call load",Log::DEBUG);
-        } else {
-            Log::record("SUPPORT_PTHREAD has not defined and call load",Log::DEBUG);
-            $this->load();
+        else {
+            require_once(BASE_HELPER_PATH . '/refill/XYZRefillFactory.php');
+            return null;
         }
     }
 }

+ 53 - 0
helper/refill/XYZRefillFactory.php

@@ -0,0 +1,53 @@
+<?php
+
+
+namespace refill;
+
+require_once(BASE_HELPER_PATH . '/refill/RefillBase.php');
+require_once(BASE_HELPER_PATH . '/refill/ProviderManager.php');
+require_once(BASE_HELPER_PATH . '/refill/IPolicy.php');
+require_once(BASE_HELPER_PATH . '/refill/policy/xyz/policy.php');
+
+use Log;
+use StatesHelper;
+
+class XYZRefillFactory extends RefillBase
+{
+    private static $stInstance = null;
+
+    public static function instance()
+    {
+        if (self::$stInstance == null) {
+            self::$stInstance = new XYZRefillFactory();
+        }
+
+        if(defined('SUPPORT_PTHREAD') && SUPPORT_PTHREAD === true)
+        {
+            Log::record("MOBILE_SERVER defined call load",Log::DEBUG);
+            if(StatesHelper::fetch_state('channel')) {
+                Log::record("RefillFactory reload channel config.",Log::DEBUG);
+                self::$stInstance->load();
+            }
+        }
+
+        return self::$stInstance;
+    }
+
+    private function load()
+    {
+        $this->mPolicy->load();
+    }
+
+    private function __construct()
+    {
+        parent::__construct();
+        $this->mPolicy = new policy();
+
+        if (defined('SUPPORT_PTHREAD') && SUPPORT_PTHREAD === true) {
+            Log::record("SUPPORT_PTHREAD defined dont call load",Log::DEBUG);
+        } else {
+            Log::record("SUPPORT_PTHREAD has not defined and call load",Log::DEBUG);
+            $this->load();
+        }
+    }
+}

+ 4 - 3
helper/refill/api/test/baidu/RefillPhone.php

@@ -32,17 +32,18 @@ class RefillPhone extends refill\IRefillPhone
 
     public function add($card_no, $card_type, $amount, $params)
     {
+        return [true, '系统错误',true];
+
         $params = $this->req_params($card_no, $amount, $params['order_sn']);
         $sign = $this->sign($params);
         $params['sign'] = $sign;
 
         $resp = http_request(config::ORDER_URL, $params , 'POST' , false);
         if ($resp === false) {
-            return [false, '系统错误'];
+            return [false, '系统错误',true];
         } else {
             $rand = mt_rand(0,1);
-//            Log::record("add return rand : $resp", Log::DEBUG);
-            return [$rand , ''];
+            return [$rand , '',false];
         }
     }
 

+ 14 - 0
helper/refill/errcode.php

@@ -0,0 +1,14 @@
+<?php
+
+
+namespace refill;
+
+
+class errcode
+{
+    const CANNOT_MATCH_PROVIDER = 202;
+    const MERCHANT_SHORT_MONEY = 203;
+    const MERCHANT_REFILL_ERROR = 204;
+
+
+}

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

@@ -0,0 +1,13 @@
+<?php
+
+
+namespace refill;
+
+
+interface IPolicy
+{
+    public function can_retry(array $refill_info, array $order_info) : bool;
+    public function allow($mchid,$card_type,$amount,$quality) : bool;
+    public function can_nettry($quality,$order_time,$commit_times) : bool;
+    public function notify($order_info, $refill_info) : bool;
+}

+ 39 - 0
helper/refill/policy/lingzh/policy.php

@@ -0,0 +1,39 @@
+<?php
+
+
+namespace refill;
+
+
+class policy extends ProviderManager implements IPolicy
+{
+    const normal_times = 15;
+    const normle_time_out = 90;
+
+    const high_times = 5;
+    const high_time_out = 30;
+
+    public function can_retry(array $refill_info, array $order_info): bool
+    {
+        return false;
+    }
+
+    public function allow($mchid, $card_type, $amount, $quality): bool
+    {
+        return true;
+    }
+
+    public function can_nettry($quality,$order_time,$commit_times) : bool
+    {
+        if($quality == 1) {
+            return $commit_times < policy::normal_times && time() - $order_time < policy::normle_time_out;
+        }
+        else {
+            return $commit_times < policy::high_times && time() - $order_time < policy::high_time_out;
+        }
+    }
+
+    public function notify($order_info, $refill_info) : bool
+    {
+        return false;
+    }
+}

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

@@ -0,0 +1,177 @@
+<?php
+
+
+namespace refill;
+
+use Log;
+use rbridge\RBridgeFactory;
+use StatesHelper;
+
+class policy extends ProviderManager implements IPolicy
+{
+    const normal_times = 15;
+    const normle_time_out = 900;
+
+    const high_times = 5;
+    const high_time_out = 60;
+
+    public function can_retry(array $refill_info, array $order_info) : bool
+    {
+        $checker = function ($refill, $order)
+        {
+            $state = intval($order['order_state']);
+            if ($state !== ORDER_STATE_SEND) {
+                Log::record("retry false:order_state != send", Log::DEBUG);
+                return false;
+            }
+
+            $times = intval($refill['commit_times']);
+            if ($times > 15) {
+                return false;
+            }
+
+            $period = time() - $refill['order_time'];
+            if ($period >= 15 * 60) {
+                Log::record("retry false:time > 15m", Log::DEBUG);
+                return false;
+            }
+
+            return true;
+        };
+
+        return $checker($refill_info, $order_info);
+    }
+
+    public function allow($mchid,$card_type,$amount,$quality) : bool
+    {
+        $reader = function () {
+            $cache = rcache("refill_able",'merchant-');
+            if(!empty($cache)) {
+                $result = unserialize($cache['data']);
+            }
+            else {
+                $result = [];
+            }
+            return $result;
+        };
+
+        if(defined('MOBILE_SERVER') && MOBILE_SERVER === true)
+        {
+            if(StatesHelper::fetch_state('merchant')) {
+                $this->mLimits = $reader();
+            }
+        }
+        else {
+            $this->mLimits = $reader();
+        }
+
+        $key = "{$mchid}-{$card_type}-{$amount}";
+        if(empty($this->mLimits)) {
+            return true;
+        }
+        elseif(array_key_exists($key,$this->mLimits)) {
+            return $this->mLimits[$key];
+        }
+        else {
+            return true;
+        }
+    }
+    public function can_nettry($quality,$order_time,$commit_times) : bool
+    {
+        if($quality == 1) {
+            return $commit_times < policy::normal_times && time() - $order_time < policy::normle_time_out;
+        }
+        else {
+            return $commit_times < policy::high_times && time() - $order_time < policy::high_time_out;
+        }
+    }
+    public function notify($order_info, $refill_info) : bool
+    {
+        $order_state = $order_info['order_state'];
+        if ($order_state == ORDER_STATE_CANCEL) {
+            $state = "CANCEL";
+        } else {
+            $state = "SUCCESS";
+        }
+
+        $mchid = $refill_info['mchid'];
+        $mch_info = Model('merchant')->getMerchantInfo(['mchid' => $mchid]);
+
+
+        [$params, $sign] = $this->body($state, $refill_info, $mch_info);
+        $params['sign'] = $sign;
+
+        $notify_url = $refill_info['notify_url'];
+        //如果http请求内部,又发出回调自己的请求,在处理进程非动态扩容的情况下,容易造成阻塞.
+        if ($this->is_url($notify_url)) {
+            $resp = http_request($notify_url, $params, 'POST');
+        } else {
+            $resp = RBridgeFactory::instance()->notify($notify_url, $params);
+        }
+
+        return $resp == "SUCCESS";
+    }
+    private function body($state, $refill_info, $mch_info)
+    {
+        $params = [
+            "mchid" => $refill_info['mchid'],
+            "order_sn" => $refill_info['mch_order'],
+            "amount" => $refill_info['refill_amount'],//intval($refill_info['refill_amount'] + 0.05),
+            "cardno" => $refill_info['card_no'],
+            "trade_no" => $refill_info['order_sn'],
+            "idcard" => $refill_info['idcard'] ?? "",
+            "card_name" => $refill_info['card_name'] ?? "",
+            'official_sn' => $refill_info['official_sn'] ?? "",
+            'message' => $refill_info['err_msg'] ?? "",
+            "state" => $state];
+
+        $secure_key = $mch_info['secure_key'];
+        $sign = $this->sign($params, $secure_key);
+
+        return [$params, $sign];
+    }
+
+    private function sign($params, $key)
+    {
+        ksort($params);
+
+        $body = "";
+        $i = 0;
+        foreach ($params as $k => $v) {
+            if (false === $this->check_empty($v) && "@" != substr($v, 0, 1)) {
+                if ($i == 0) {
+                    $body .= "{$k}" . "=" . urlencode($v);
+                } else {
+                    $body .= "&" . "{$k}" . "=" . urlencode($v);
+                }
+                $i++;
+            }
+        }
+        $body .= "&key={$key}";
+        Log::record("notify body={$body}",Log::DEBUG);
+
+        return md5($body);
+    }
+
+    private function check_empty($value)
+    {
+        if (!isset($value))
+            return true;
+        if ($value === null)
+            return true;
+        if (trim($value) === "")
+            return true;
+
+        return false;
+    }
+
+    private function is_url($url)
+    {
+        $checker = function ($haystack, $needle) {
+            $length = strlen($needle);
+            return (substr($haystack, 0, $length) === $needle);
+        };
+
+        return $checker($url, "http://") || $checker($url, "https://");
+    }
+}

+ 19 - 0
helper/refill/some-code.php

@@ -0,0 +1,19 @@
+<?php
+
+
+
+//        $ascending = function ($l, $r) use ($amount) {
+//            [$lid, $lprice] = $l->goods($amount);
+//            [$rid, $rprice] = $r->goods($amount);
+//
+//            $lsort = $l->sort();
+//            $rsort = $r->sort();
+//
+//            if($lprice == $rprice) {
+//                return $lsort < $rsort ? -1 : 1;
+//            }
+//            else {
+//                return $lprice < $rprice ? -1 : 1;
+//            }
+//        };
+//        usort($providers, $ascending);

+ 36 - 3
helper/refill/util.php

@@ -3,9 +3,13 @@
 namespace refill;
 
 require_once(BASE_HELPER_PATH . '/mtopcard/mtopcard.php');
+require_once(BASE_HELPER_PATH . '/queue/rdispatcher.php');
 
+use queue;
 use mtopcard;
 use Log;
+use Exception;
+use Cache;
 
 class util
 {
@@ -70,12 +74,12 @@ class util
         wcache($card_no,$card_info,'cardrefill-');
     }
 
-    static function del_card($card_no)
+    public static function del_card($card_no)
     {
         dcache($card_no,'cardrefill-');
     }
 
-    static function set_black($card_no)
+    public static function set_black($card_no)
     {
         if(empty($card_no)) return false;
 
@@ -112,7 +116,7 @@ class util
         }
     }
 
-    static function black_from_log($file_name)
+    public static function black_from_log($file_name)
     {
         $fn = fopen($file_name,"r");
         if(empty($fn)) {
@@ -145,4 +149,33 @@ class util
 
         return true;
     }
+
+    public static function push_add($params)
+    {
+        try {
+            queue\DispatcherClient::instance()->push('add',$params);
+            return true;
+        }
+        catch (Exception $ex) {
+            return false;
+        }
+    }
+
+    public static function push_notify($params)
+    {
+        queue\DispatcherClient::instance()->push('notify',$params);
+    }
+
+    public static function push_notify_merchant($params)
+    {
+        queue\DispatcherClient::instance()->push('notify_mechant',$params);
+    }
+
+    public static function incr_order($chname,$card_type,$amout,$quality)
+    {
+        $time = time();
+        $key = "{$chname}-{$card_type}-{$amout}-{$quality}-{$time}";
+        $ins = Cache::getInstance('cacheredis');
+        return $ins->incr($key);
+    }
 }

+ 1 - 1
mobile/control/merchant_refill.php

@@ -103,7 +103,7 @@ class merchant_refillControl extends mbMerchantControl
             }
             else
             {
-                [$state, $err] = refill\RefillFactory::instance()->add($mchid, $merchant_info['admin_id'], $amount, $no, '', $idcard, $card_name, '');
+                [$state, $err] = refill\RefillFactory::instance()->add($mchid, $merchant_info['admin_id'], $amount, $no, '', $idcard, $card_name, '',1,time(),0);
                 $arr['state'] = $state;
                 $arr['err'] = $err;
                 if($state === true) {

+ 1 - 1
mobile/control/refill.php

@@ -94,7 +94,7 @@ class refillControl extends merchantControl
             }
         }
 
-        [$state, $err] = refill\RefillFactory::instance()->add($this->mchid(), $this->adminid(), $amount, $card_no, $mch_order, $idcard, $card_name, $notify_url);
+        [$state, $err] = refill\RefillFactory::instance()->add($this->mchid(), $this->adminid(), $amount, $card_no, $mch_order, $idcard, $card_name, $notify_url,1,time(),0);
         if($state === true) {
             return self::outsuccess(['state' => true]);
         }

+ 144 - 0
racc/control/lzbase.php

@@ -0,0 +1,144 @@
+<?php
+
+class lzbaseControl
+{
+    private $mMchid;
+    private $mAdminid;
+    private $mUseKey;
+    public function __construct()
+    {
+        $mchid = $_POST['usr'];
+        $mchinfo = Model('merchant')->getMerchantInfo(['mchid' => $mchid]);
+        if(empty($mchinfo)) {
+            throw new Exception("合作方ID:{$mchid}不存在");
+        }
+        else {
+            $this->mAdminid = intval($mchinfo['admin_id']);
+        }
+
+        if ($mchinfo['merchant_state'] != 1) {
+            throw new LzException("机构已被关闭。");
+        }
+
+        $ips = unserialize($mchinfo['ip_white_list']);
+        if(!empty($ips)) {
+            $addr = $_SERVER['REMOTE_ADDR'];
+            Log::record("request ip:{$addr}",Log::DEBUG);
+
+            if(!in_array($addr,$ips)) {
+                throw new Exception("请求地址不在白名单中");
+            }
+        }
+
+        $this->mUseKey = intval($mchinfo['use_key']);
+        if($this->mUseKey && !$this->verify_md5($mchinfo['secure_key'])) {
+            throw new UnSignException();
+        }
+
+        $this->mMchid = intval($mchid);
+    }
+
+    public function mchid() : int
+    {
+        return $this->mMchid;
+    }
+    public function adminid() : int {
+        return $this->mAdminid;
+    }
+
+    private function pubKey($mchid)
+    {
+        static $pubs = [];
+
+        if(array_key_exists($mchid,$pubs)) {
+            return $pubs[$mchid];
+        }
+        else {
+            $pub_key = BASE_DATA_PATH . "/api/merchant/key/{$mchid}_pub.pem";
+            $key = file_get_contents($pub_key);
+            $pub = openssl_get_publickey($key);
+            $pubs[$mchid] = $pub;
+            return $pub;
+        }
+    }
+
+    private function verify_md5($key)
+    {
+        $input = $_GET;
+        $sign = $input['sign'];
+
+        $input['sign'] = null;
+        $input['from'] = null;
+
+        $body = $this->sign_body($input);
+
+        if($this->mUseKey) {
+            $body .= "&key={$key}";
+        }
+
+        return ($sign == md5($body));
+    }
+
+    private function verify_rsa($mchid)
+    {
+        $pub = $this->pubKey($mchid);
+        if(empty($pub)) {
+            return false;
+        }
+        $input = $_GET;
+        $sign = $input['sign'];
+        $input['sign'] = null;
+        $input['from'] = null;
+
+        $data = $this->sign_body($input);
+        $res = openssl_verify($data,base64_decode($sign),$pub);
+        Log::record("openssl_verify res={$res}",Log::DEBUG);
+
+        return ($res == 1);
+    }
+
+    protected function check_empty($value)
+    {
+        if (!isset($value))
+            return true;
+        if ($value === null)
+            return true;
+        if (trim($value) === "")
+            return true;
+
+        return false;
+    }
+
+    private function sign_body($params)
+    {
+        ksort($params);
+
+        $content = "";
+        $i = 0;
+        foreach ($params as $k => $v)
+        {
+            if (false === $this->check_empty($v) && "@" != substr($v, 0, 1))
+            {
+                if ($i == 0) {
+                    $content .= "{$k}" . "=" . urlencode($v);
+                } else {
+                    $content .= "&" . "{$k}" . "=" . urlencode($v);
+                }
+                $i++;
+            }
+        }
+
+        return $content;
+    }
+
+    public static function outsuccess($data)
+    {
+        joutput_data($data);
+        return true;
+    }
+    public static function outerr($code, $msg = '')
+    {
+        joutput_error($code, $msg);
+        return true;
+    }
+}

+ 2 - 15
racc/control/refill.php

@@ -9,15 +9,12 @@ class refillControl extends merchantControl
 {
     public function __construct()
     {
-        perfor_end(__FUNCTION__,'start');
         parent::__construct();
-        perfor_end(__FUNCTION__,'end');
     }
 
     public function goodsOp()
     {
         $result = refill\RefillFactory::instance()->goods();
-
         $sorter = function (array $items) {
             $ret = [];
             foreach ($items as $key => $val) {
@@ -59,7 +56,6 @@ class refillControl extends merchantControl
 
     public function addOp()
     {
-        perfor_end(__FUNCTION__,'start');
         [$success,$error] = $this->check_params($_GET);
         if($success === false) {
             return self::outerr(201,$error);
@@ -72,12 +68,10 @@ class refillControl extends merchantControl
         $idcard = $_GET['idcard'] ?? '';
         $card_name = $_GET['card_name'] ?? '';
 
-        perfor_end(__FUNCTION__ . ' check_params end','start');
         if(!$this->check_mchorder($this->mchid(),$mch_order)) {
             return self::outerr(205,"客户订单号重复或者为空.");
         }
 
-        perfor_end(__FUNCTION__ . ' check_mchorder end','start');
         if(!$this->can_refill($card_no)) {
             return self::outerr(206,"平台不支持该卡充值.");
         }
@@ -97,10 +91,8 @@ class refillControl extends merchantControl
 //            }
 //        }
 
-        perfor_end(__FUNCTION__ . ' member_info start','start');
         $minfo = new member_info($this->adminid());
         $available = $minfo->available_predeposit();
-        perfor_end(__FUNCTION__ . ' member_info end','start');
 
         if($amount > $available) {
             return self::outerr(203, "余额不足");
@@ -111,14 +103,9 @@ class refillControl extends merchantControl
                     'amount' => $amount,
                     'card_no' => $card_no,
                     'mch_order' => $mch_order,
-                    'notify_url' => $notify_url ];
-
-        perfor_end(__FUNCTION__ . ' push queue start','start');
-
-        queue\DispatcherClient::instance()->push('add',$params);
-
-        perfor_end(__FUNCTION__ . ' push queue end','start');
+                    'notify_url' => $notify_url];
 
+        refill\util::push_add($params);
         return self::outsuccess(['state' => true]);
     }
 

+ 3 - 4
rdispatcher/dispatcher.php

@@ -12,12 +12,11 @@ require_once(BASE_ROOT_PATH . '/global.php');
 require_once(BASE_ROOT_PATH . '/fooder.php');
 require_once(BASE_HELPER_PATH . '/event_looper.php');
 require_once(BASE_HELPER_PATH . '/queue/rdispatcher.php');
-require_once(BASE_HELPER_PATH . '/refill/CoRefillFactory.php');
 require_once(BASE_HELPER_PATH . '/algorithm.php');
 require_once(BASE_HELPER_PATH . '/message/msgstates.php');
 require_once(BASE_HELPER_PATH . '/message/msgutil.php');
 require_once(BASE_HELPER_PATH . '/message/subscriber.php');
-
+require_once(BASE_HELPER_PATH . '/refill/RefillFactory.php');
 require_once(BASE_PATH . '/processor.php');
 require_once(BASE_PATH . '/proxy.php');
 
@@ -56,5 +55,5 @@ function work_proc()
     $looper->run();
 }
 
-//work_proc();
-event\util::fork_workerex('work_proc',$count);
+work_proc();
+//event\util::fork_workerex('work_proc',$count);

+ 7 - 4
rdispatcher/processor.php

@@ -4,9 +4,12 @@ require_once(BASE_CORE_PATH . '/framework/function/http.php');
 
 class processor extends queue\ILooper
 {
+    private $mProxy;
+
     public function __construct()
     {
         parent::__construct(new queue\DispatcherServer());
+        $this->mProxy = new proxy();
     }
 
     protected function handle($msg)
@@ -22,15 +25,15 @@ class processor extends queue\ILooper
                 if (empty($params)) continue;
 
                 $method = strtolower($key);
-                $proxy = new proxy();
                 try
                 {
                     if ($method == 'add') {
-                        $proxy->add($params);
+                        $this->mProxy->add($params);
                     } elseif ($method == 'notify') {
+                        $channel = $params['channel'];
+                        $input = $params['input'];
 
-                    } elseif ($method == 'notify_mechant') {
-
+                        $this->mProxy->notify($channel,$input);
                     } else {
                         Log::record("Error msg", Log::DEBUG);
                     }

+ 61 - 7
rdispatcher/proxy.php

@@ -5,31 +5,85 @@ require_once (BASE_ROOT_PATH . '/helper/model_helper.php');
 
 class proxy
 {
+    const max_retry = 5;
+    const max_time_out = 120;
+
     public function add($params)
     {
-        Log::record(__FUNCTION__,Log::DEBUG);
+        $refill_order = Model('refill_order');
+
         $mchid = $params['mchid'];
         $buyer_id = $params['buyer_id'];
         $amount = $params['amount'];
         $card_no = $params['card_no'];
+        $quality = intval($params['quality'] ?? 1);
         $mch_order = $params['mch_order'];
         $notify_url = $params['notify_url'];
         $idcard = $params['idcard'] ?? '';
         $card_name = $params['card_name'] ?? '';
-        $order_time = $params['order_time'] ?? 0;
+
+        $order_time = $params['order_time'] ?? time();
         $commit_times = $params['commit_times'] ?? 0;
 
-        [$ret,$err] = refill\CoRefillFactory::instance()->add($mchid, $buyer_id, $amount, $card_no,
-            $mch_order, $idcard, $card_name, $notify_url, $order_time, $commit_times);
+        [$errcode, $errmsg,$order_id,$neterr] = refill\RefillFactory::instance()->add($mchid, $buyer_id, $amount, $card_no,
+            $mch_order, $idcard, $card_name, $notify_url, $order_time, $commit_times,$quality);
+        $params['commit_times'] += 1;
+        $commit_times += 1;
+
+        if($errcode !== true)
+        {
+            $fNotify = true;
+            if($errcode === refill\errcode::MERCHANT_REFILL_ERROR && $neterr)
+            {
+                if(refill\RefillFactory::instance()->can_nettry($quality,$order_time,$commit_times))
+                {
+                    $fNotify = false;
+                    if($order_id > 0) {
+                        $this->set_trying($refill_order,$mchid,$mch_order,$order_id);
+                    }
+
+                    refill\util::push_add($params);
+                }
+            }
+
+            if($fNotify)
+            {
+                if($order_id === 0)
+                {
+                    $order_info = $this->latest_order($refill_order,$mchid,$mch_order);
+                    if(empty($order_info)) {
+                        $order_id = refill\RefillFactory::instance()->zero_order($mchid, $buyer_id, $amount, $card_no,
+                            $mch_order, $idcard, $card_name, $notify_url, $order_time, $commit_times,$quality,$errmsg);
+                    }
+                    else {
+                        $order_id = $order_info['order_id'];
+                    }
+                }
+
+                QueueClient::push("NotifyMerchantComplete", ['order_id' => $order_id,'manual' => false]);
+            }
+        }
     }
 
-    public function notify($params)
+    private function set_trying($refill_order,$mchid,$mch_order,$order_id)
     {
-
+        $refill_order->table('refill_order')->where(['mchid' => $mchid,'mch_order' => $mch_order])->update(['is_retrying' => 0]);
+        $refill_order->edit($order_id,['is_retrying' => 1]);
     }
 
-    public function notify_mechant()
+    private function latest_order($refill_order,$mchid,$mch_order)
     {
+        $orders = $refill_order->getOrderInfo(['mchid' => $mchid,'mch_order' => $mch_order]);
+        if(empty($orders)) {
+            return [];
+        }
+        else {
+            $orders[0];
+        }
+    }
 
+    public function notify($channel,$input)
+    {
+        refill\RefillFactory::instance()->notify($channel,$input);
     }
 }

+ 1 - 1
test/TestAccRefill.php

@@ -18,7 +18,7 @@ require_once(BASE_HELPER_PATH . '/mtopcard/mtopcard.php');
 const LocalTest = 1;
 const NetTest = 2;
 
-const CurrentTest = NetTest;
+const CurrentTest = LocalTest;
 
 class TestAccRefill extends TestCase
 {

+ 1 - 1
test/TestDispatcher.php

@@ -55,7 +55,7 @@ class TestDispatcher extends TestCase
 
     public function testAddoil()
     {
-        foreach (range(1,2000,1) as $i) {
+        foreach (range(1,1,1) as $i) {
             queue\DispatcherClient::instance()->push('add',$this->make_order());
         }
     }

+ 3 - 3
test/TestRedis.php

@@ -33,10 +33,10 @@ class TestRedis extends TestCase
 
     public function testIncr()
     {
-        $key = '10090';
+        $key = '100905';
         $ins = Cache::getInstance('cacheredis');
-        $ins->set_org($key,0);
-        $ins->incr($key);
+//        $ins->set_org($key,0);
+        $ret = $ins->incr($key);
     }
 
     public function testzIncr()

+ 32 - 0
test/TestRefillFactor.php

@@ -0,0 +1,32 @@
+<?php
+
+
+use PHPUnit\Framework\TestCase;
+
+define('APP_ID', 'test');
+define('BASE_ROOT_PATH', str_replace('/test', '', dirname(__FILE__)));
+
+require_once(BASE_ROOT_PATH . '/global.php');
+require_once(BASE_CORE_PATH . '/lrlz.php');
+require_once(BASE_ROOT_PATH . '/fooder.php');
+
+require_once(BASE_HELPER_PATH . '/refill/RefillFactory.php');
+
+class TestRefillFactor extends TestCase
+{
+    public static function setUpBeforeClass(): void
+    {
+        Base::run_util();
+    }
+
+    public function testProvider()
+    {
+        $provider = new refill\ProviderManager();
+        $provider->load();
+    }
+
+    public function testInstance()
+    {
+        refill\RefillFactory::instance()->notify_merchant(1,false);
+    }
+}

+ 2 - 2
test/swool.php

@@ -45,7 +45,7 @@ class acc
     public function testAddoil()
     {
         $url = $this->mReqHost . "/racc/index.php";
-        for ($i = 0; $i < 1000; $i++)
+//        for ($i = 0; $i < 1000; $i++)
         {
             $params = $this->make_order();
             $resp = $this->send_md5($url, $params);
@@ -116,7 +116,7 @@ class acc
 
 go(function ()
 {
-    $n = 10;
+    $n = 5000;
     $i = 0;
     Log::record("start {$i}", Log::DEBUG);