stanley-king 4 years atrás
parent
commit
ef700b2154

+ 83 - 55
data/config/dev/refill.ini.php

@@ -1,67 +1,95 @@
 <?php
+//
+////充值额度基本表
+//$config['refill_specs'] = [
+//    'petrochina'    => [100 , 200 , 500 , 1000 , 2000],
+//    'sinopec'       => [100 , 200 , 500 , 1000 , 2000],
+//    'chinamobile'   => [10 , 20 , 30 , 50 , 100 , 200 , 500 , 1000],
+//    'chinaunicom'   => [10 , 20 , 30 , 50 , 100 , 200 , 500 , 1000],
+//    'chinatelecom'  => [10 , 20 , 30 , 50 , 100 , 200 , 500 , 1000]
+//];
+//
+//
+////充值渠道配置表
+//$suhc_oil = ['name' => 'suhc', 'store_id' => 8, 'card_type' => ['sinopec'],
+//    'amount' => [100 => ['goods_id' => 6226, 'price' => 96.8],
+//        200 => ['goods_id' => 6227, 'price' => 193.6],
+//        500 => ['goods_id' => 6228, 'price' => 484],
+//        1000 => ['goods_id' => 6229, 'price' => 968],
+//        2000 => ['goods_id' => 6230, 'price' => 1976]],
+//    'period' => ['start' => '8:30', 'end' => '22:30'], 'refill_type' => 'api'];
+//
+//$suhctm_oil = ['name' => 'suhctm', 'store_id' => 8, 'card_type' => ['sinopec'],
+//    'amount' => [100 => ['goods_id' => 6226, 'price' => 96.8],
+//        200 => ['goods_id' => 6227, 'price' => 193.6],
+//        500 => ['goods_id' => 6228, 'price' => 484],
+//        1000 => ['goods_id' => 6229, 'price' => 968],
+//        2000 => ['goods_id' => 6230, 'price' => 1976]],
+//    'period' => ['start' => '8:30', 'end' => '22:30'], 'refill_type' => 'api'];
+//
+//$lx_oil = ['name' => 'lx', 'store_id' => 10, 'card_type' => ['sinopec'],
+//    'amount' => [100 => ['goods_id' => 6234, 'price' => 95.5],
+//        200 => ['goods_id' => 6235, 'price' => 191],
+//        500 => ['goods_id' => 6236, 'price' => 477.5],
+//        1000 => ['goods_id' => 6237, 'price' => 955],
+//        2000 => ['goods_id' => 6238, 'price' => 1910]],
+//    'period' => ['start' => '8:30', 'end' => '22:30'], 'official_sn' => true];
+//
+//$oil_providers = [
+//    ['name' => 'suhctm', 'cfg' => $suhctm_oil, 'opened' => true, 'sort' => 2],
+//    ['name' => 'lx', 'cfg' => $lx_oil, 'opened' => true, 'sort' => 3]];
+//$config['oil_providers'] = $oil_providers;
+//
+//
+//$beixt_phone = ['name' => 'beixt', 'store_id' => 9, 'card_type' => ['chinamobile', 'chinaunicom', 'chinatelecom'],
+//    'amount' => [50 => ['goods_id' => 6231, 'price' => 48.75],
+//        100 => ['goods_id' => 6232, 'price' => 97.5],
+//        200 => ['goods_id' => 6233, 'price' => 195]],
+//    'refill_type' => 'api'];
+//
+//$bxtwt_phone = ['name' => 'bxtwt', 'store_id' => 10, 'card_type' => ['chinamobile', 'chinaunicom', 'chinatelecom'],
+//    'amount' => [50 => ['goods_id' => 6298, 'price' => 48],
+//        100 => ['goods_id' => 6299, 'price' => 96],
+//        200 => ['goods_id' => 6300, 'price' => 192]],
+//    'refill_type' => 'api'];
+//
+//$jiec_phone = ['name' => 'jiec', 'store_id' => 17, 'card_type' => ['chinaunicom', 'chinatelecom'],
+//    'amount' => [30 => ['goods_id' => 6323, 'price' => 28.74],
+//        50 => ['goods_id' => 6324, 'price' => 47.9],
+//        100 => ['goods_id' => 6325, 'price' => 95.8],
+//        200 => ['goods_id' => 6326, 'price' => 191.6]], 'official_sn' => true, 'refill_type' => 'api'];
+//
+//$phone_providers = [
+//        ['name' => 'beixt', 'cfg' => $beixt_phone, 'opened' => true, 'sort' => 1],
+//        ['name' => 'bxtwt', 'cfg' => $bxtwt_phone, 'opened' => true, 'sort' => 2],
+//        ['name' => 'jiec', 'cfg' => $jiec_phone, 'opened' => true, 'sort' => 1]];
+//
+//$config['phone_providers'] = $phone_providers;
 
+
+$config['refill_oil_specs'] = [100 , 200 , 500 , 1000 , 2000];
+$config['refill_phone_specs'] = [10 , 20 , 30 , 50 , 100 , 200 , 300 , 500];
 //充值额度基本表
 $config['refill_specs'] = [
-    'petrochina'    => [100 , 200 , 500 , 1000 , 2000],
-    'sinopec'       => [100 , 200 , 500 , 1000 , 2000],
-    'chinamobile'   => [10 , 20 , 30 , 50 , 100 , 200 , 500 , 1000],
-    'chinaunicom'   => [10 , 20 , 30 , 50 , 100 , 200 , 500 , 1000],
-    'chinatelecom'  => [10 , 20 , 30 , 50 , 100 , 200 , 500 , 1000]
+    'petrochina'    => $config['refill_oil_specs'],
+    'sinopec'       => $config['refill_oil_specs'],
+    'chinamobile'   => $config['refill_phone_specs'],
+    'chinaunicom'   => $config['refill_phone_specs'],
+    'chinatelecom'  => $config['refill_phone_specs']
 ];
 
 
 //充值渠道配置表
-$suhc_oil = ['name' => 'suhc', 'store_id' => 8, 'card_type' => ['sinopec'],
-    'amount' => [100 => ['goods_id' => 6226, 'price' => 96.8],
-        200 => ['goods_id' => 6227, 'price' => 193.6],
-        500 => ['goods_id' => 6228, 'price' => 484],
-        1000 => ['goods_id' => 6229, 'price' => 968],
-        2000 => ['goods_id' => 6230, 'price' => 1976]],
-    'period' => ['start' => '8:30', 'end' => '22:30'], 'refill_type' => 'api'];
-
-$suhctm_oil = ['name' => 'suhctm', 'store_id' => 8, 'card_type' => ['sinopec'],
-    'amount' => [100 => ['goods_id' => 6226, 'price' => 96.8],
-        200 => ['goods_id' => 6227, 'price' => 193.6],
-        500 => ['goods_id' => 6228, 'price' => 484],
-        1000 => ['goods_id' => 6229, 'price' => 968],
-        2000 => ['goods_id' => 6230, 'price' => 1976]],
-    'period' => ['start' => '8:30', 'end' => '22:30'], 'refill_type' => 'api'];
-
-$lx_oil = ['name' => 'lx', 'store_id' => 10, 'card_type' => ['sinopec'],
-    'amount' => [100 => ['goods_id' => 6234, 'price' => 95.5],
-        200 => ['goods_id' => 6235, 'price' => 191],
-        500 => ['goods_id' => 6236, 'price' => 477.5],
-        1000 => ['goods_id' => 6237, 'price' => 955],
-        2000 => ['goods_id' => 6238, 'price' => 1910]],
-    'period' => ['start' => '8:30', 'end' => '22:30'], 'official_sn' => true];
-
-$oil_providers = [
-    ['name' => 'suhctm', 'cfg' => $suhctm_oil, 'opened' => true, 'sort' => 2],
-    ['name' => 'lx', 'cfg' => $lx_oil, 'opened' => true, 'sort' => 3]];
+$oil_providers = [];
 $config['oil_providers'] = $oil_providers;
 
-
-$beixt_phone = ['name' => 'beixt', 'store_id' => 9, 'card_type' => ['chinamobile', 'chinaunicom', 'chinatelecom'],
-    'amount' => [50 => ['goods_id' => 6231, 'price' => 48.75],
-        100 => ['goods_id' => 6232, 'price' => 97.5],
-        200 => ['goods_id' => 6233, 'price' => 195]],
-    'refill_type' => 'api'];
-
-$bxtwt_phone = ['name' => 'bxtwt', 'store_id' => 10, 'card_type' => ['chinamobile', 'chinaunicom', 'chinatelecom'],
-    'amount' => [50 => ['goods_id' => 6298, 'price' => 48],
-        100 => ['goods_id' => 6299, 'price' => 96],
-        200 => ['goods_id' => 6300, 'price' => 192]],
-    'refill_type' => 'api'];
-
-$jiec_phone = ['name' => 'jiec', 'store_id' => 17, 'card_type' => ['chinaunicom', 'chinatelecom'],
-    'amount' => [30 => ['goods_id' => 6323, 'price' => 28.74],
-        50 => ['goods_id' => 6324, 'price' => 47.9],
-        100 => ['goods_id' => 6325, 'price' => 95.8],
-        200 => ['goods_id' => 6326, 'price' => 191.6]], 'official_sn' => true, 'refill_type' => 'api'];
-
+$baidu_phone = ['name' => 'baidu', 'store_id' => 8, 'card_type' => ['chinamobile', 'chinaunicom', 'chinatelecom'],
+    'amount' => [10 => ['goods_id' => 6245, 'price' => 9.51],
+        20 => ['goods_id' => 6247, 'price' => 19.02],
+        30 => ['goods_id' => 6249, 'price' => 28.53],
+        50 => ['goods_id' => 6250, 'price' => 47.55],
+        100 => ['goods_id' => 6251, 'price' => 95.1]],
+    'official_sn' => true, 'refill_type' => 'api'];
 $phone_providers = [
-        ['name' => 'beixt', 'cfg' => $beixt_phone, 'opened' => true, 'sort' => 1],
-        ['name' => 'bxtwt', 'cfg' => $bxtwt_phone, 'opened' => true, 'sort' => 2],
-        ['name' => 'jiec', 'cfg' => $jiec_phone, 'opened' => true, 'sort' => 1]];
-
+    ['name' => 'baidu', 'cfg' => $baidu_phone, 'opened' => true, 'sort' => 1]];
 $config['phone_providers'] = $phone_providers;

+ 25 - 0
helper/refill/CoRefillFactory.php

@@ -0,0 +1,25 @@
+<?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();
+    }
+}

+ 730 - 0
helper/refill/RefillBase.php

@@ -0,0 +1,730 @@
+<?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/CalcMerchantPrice.php');
+require_once(BASE_HELPER_PATH . '/refill/util.php');
+require_once(BASE_HELPER_RAPI_PATH . '/api.php');
+
+use Log;
+use mtopcard;
+use QueueClient;
+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);
+            }
+        }
+
+        $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
+    {
+        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
+    {
+        $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;
+    }
+
+    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_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 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);
+            return false;
+        }
+
+        if ($caller->verify($input))
+        {
+            [$order_id, $success, $can_try, $need_handle] = $caller->notify($input);
+            if (!$need_handle) {
+                return true;
+            }
+
+            if ($order_id !== false)
+            {
+                $mod_order = Model('vr_order');
+                $order_info = $mod_order->getOrderInfo(['order_id' => $order_id]);
+                $order_state = intval($order_info['order_state']);
+
+                if ($order_state != ORDER_STATE_SEND) {
+                    return false;
+                }
+
+                $logic_vr_order = Logic("vr_order");
+                if ($success) {
+                    $logic_vr_order->changeOrderStateSuccess($order_id);
+                }
+                elseif ($can_try)
+                {
+                    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))
+                        {
+                            $logic_vr_order->changeOrderStateCancel($order_info, '', "{$chname}接口回调通知失败,正在重试");
+                            if ($this->retry($refill_info, $order_info)) {
+                                $mod_refill->edit($order_id, ['inner_status' => 1, 'notify_time' => time(), 'notify_state' => 1]);
+                                $trans->commit();
+                                return true;
+                            }
+                        }
+
+                        $trans->commit();
+
+                    }
+                    catch (Exception $ex) {
+                        $trans->rollback();
+                        Log::record("Error:" . $ex->getMessage(),Log::ERR);
+                    }
+                }
+                else {
+                    $logic_vr_order->changeOrderStateCancel($order_info, '', "{$chname}接口回调通知失败,不可重试.");
+                }
+
+                $mod_refill = Model('refill_order');
+                $mod_refill->edit($order_id, ['notify_time' => time(), 'notify_state' => 1]);
+                QueueClient::push("NotifyMerchantComplete", ['order_id' => $order_id,'manual' => false]);
+            } else {
+                Log::record("系统无此订单ID:{$order_id}", Log::ERR);
+
+            }
+        } 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;
+            }
+
+            $period = time() - $refill['order_time'];
+            if ($period >= 15 * 60) {
+                Log::record("retry false:time > 15m", Log::DEBUG);
+                return false;
+            }
+
+            return true;
+        };
+
+        $can_try = $checker($refill_info, $order_info);
+        if (!$can_try) {
+            return false;
+        }
+
+        $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'];
+
+        $idcard = $refill_info['idcard'] ?? '';
+        $card_name = $refill_info['card_name'] ?? '';
+
+        [$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);
+    }
+
+    public function push_add($params)
+    {
+        return queue\DispatcherClient::instance()->push('add',$params);
+    }
+
+    public function push_notify($params)
+    {
+        queue\DispatcherClient::instance()->push('notify',$params);
+    }
+
+    public function push_notify_merchant($params)
+    {
+        queue\DispatcherClient::instance()->push('notify_mechant',$params);
+    }
+
+    public function add($mchid, $buyer_id, $amount, $card_no, $mch_order, $idcard, $card_name, $notify_url, $order_time = 0, $commit_times = 0)
+    {
+        $card_type = mtopcard\card_type($card_no);
+        $providers = $this->find_providers($amount, $card_type);
+
+        if (empty($providers)) {
+            return [202, "找不到合适的充值通道"];
+        }
+
+        if (empty($notify_url)) {
+            $notify_url = "";
+        }
+
+        $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();
+        }
+
+        $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;
+        foreach ($providers as $provider)
+        {
+            if(!$provider->opened()) continue;
+
+            $channel_name = $provider->name();
+            [$goods_id, $price] = $provider->goods($amount);
+
+            if ($price > $mch_amount) continue;
+
+            $input['goods_id'] = $goods_id;
+            $input['quantity'] = 1;
+            $input['price'] = $price;
+
+            $input['buyer_phone'] = $minfo->mobile();
+            $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');
+            $result = $logic_buy_virtual->buyStep3($input, $buyer_id, [$calc, 'calc_vorder_amount'], true);
+
+            $mod_refill = Model('refill_order');
+            if ($result['state'] === true)
+            {
+                $order_sn = $result['data']['order_sn'];
+                $order_id = $result['data']['order_id'];
+
+                if(!$this->pay_completed($order_sn)) {
+                    $logic_vr_order = Logic("vr_order");
+                    $order_info = Model('vr_order')->getOrderInfo(['order_id' => $order_id]);
+                    $logic_vr_order->changeOrderStateCancel($order_info, '', "预存款不足以支付该订单");
+                    continue;
+                }
+
+                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' => $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];
+                $mod_refill->add_refill($orderext);
+            } else {
+                continue;
+            }
+
+            $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);
+
+            if ($state)
+            {
+                $trade_no = $err;
+                if ($provider->refill_type() == 'api') {
+                    $logic_vr_order = Logic("vr_order");
+                    $logic_vr_order->changeOrderStateSend($order_id);
+                }
+
+                $data = ['commit_time' => time(), 'ch_trade_no' => $trade_no];
+                $mod_refill->edit($order_id, $data);
+                $refill_state = true;
+
+                //如果对方没有回调能力,则启动主动查询.
+                if($provider->callback() === false) {
+                    QueueClient::async_push("QueryRefillState",['order_id' => $order_id],180);
+                }
+
+                break;
+            } else {
+                Log::record("channel:{$channel_name} err:{$err}");
+                $logic_vr_order = Logic("vr_order");
+                $order_info = Model('vr_order')->getOrderInfo(['order_id' => $order_id]);
+                $logic_vr_order->changeOrderStateCancel($order_info, '', "调用{$channel_name}接口失败");
+                $mod_refill->edit($order_id, ['commit_time' => time(), 'inner_status' => 1]);
+            }
+        }
+
+        if ($refill_state) {
+            return [true, $order_sn];
+        } else {
+            return [204, "充值失败."];
+        }
+    }
+
+    private function pay_completed($order_sn)
+    {
+        $logic_payment = Logic('payment');
+        $order = $logic_payment->getVrOrderInfo($order_sn);
+        $api_pay_amount = $order['data']['api_pay_amount'];
+
+        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) {
+            return [false, "订单ID小于0"];
+        }
+
+        $vr_order = Model('vr_order');
+        $refill_order = Model('refill_order');
+
+        $order_info = $vr_order->getOrderInfo(['order_id' => $order_id]);
+        $refill_info = $refill_order->getOrderInfo(['order_id' => $order_id]);
+
+        if (empty($order_info) || empty($refill_info)) {
+            return [false, "无此订单"];
+        }
+
+        //手动通知,之所以不做尝试,是担心客户方状态处理不当
+        if (!$manual && $refill_info['mch_notify_state'] != 0) {
+            return [false, "已经通知客户方"];
+        }
+
+        $notify_url = $refill_info['notify_url'];
+        if (empty($notify_url)) {
+            $refill_order->edit($order_id, ['mch_notify_state' => 1, 'mch_notify_times' => 0]);
+            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 {
+            return [false, "错误的订单状态,不能通知."];
+        }
+
+        $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") {
+            $refill_order->edit($order_id, ['mch_notify_state' => 1, 'mch_notify_times' => ['exp', 'mch_notify_times+1']]);
+            return [true, ""];
+        } else {
+            $refill_order->edit($order_id, ['mch_notify_times' => ['exp', 'mch_notify_times+1']]);
+            $times = $refill_info['mch_notify_times'] + 1;
+
+            if ($times > 80) {
+                $refill_order->edit($order_id, ['mch_notify_state' => 2]);
+            } else {
+                $N = intval($times / 5);
+                $period = intval(pow(2, $N));
+                QueueClient::async_push("NotifyMerchantComplete", ['order_id' => $order_id,'manual' => false], $period);
+            }
+            return [false, "通知{$times}次,失败."];
+        }
+    }
+
+    public function query($order_id)
+    {
+        $mod_refill = Model('refill_order');
+        $refill_info = $mod_refill->getOrderInfo(['order_id' => $order_id,'inner_status' => 0]);
+
+        $chname = $refill_info['channel_name'];
+        $card_type = intval($refill_info['card_type']);
+
+        $provider = $this->provider($chname, $card_type);
+        [$state, $order_state] = $provider->query($refill_info);
+
+        if ($state === true)
+        {
+            $notify_state = $refill_info['notify_state'];
+            if($notify_state == 0)
+            {
+                $modify_able = true;
+                if(!$provider->callback())
+                {
+                    $logic_vr_order = Logic("vr_order");
+                    if ($order_state == ORDER_STATE_SUCCESS) {
+                        $logic_vr_order->changeOrderStateSuccess($order_id);
+                    } elseif ($order_state == ORDER_STATE_CANCEL) {
+                        $mod_order = Model('vr_order');
+                        $order_info = $mod_order->getOrderInfo(['order_id' => $order_id]);
+                        $logic_vr_order->changeOrderStateCancel($order_info, '', "{$chname}接口查询失败,不再重试.");
+                    } else {
+                        $modify_able = false;
+                        QueueClient::async_push("QueryRefillState",['order_id' => $order_id],180);
+                    }
+                }
+
+                if($modify_able) {
+                    $mod_refill->edit($order_id, ['notify_time' => time(), 'notify_state' => 1]);
+                    QueueClient::push("NotifyMerchantComplete", ['order_id' => $order_id,'manual' => false]);
+                }
+            }
+
+            return true;
+        }
+        else {
+            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;
+    }
+}

+ 5 - 722
helper/refill/RefillFactory.php

@@ -3,30 +3,13 @@
 
 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/CalcMerchantPrice.php');
-require_once(BASE_HELPER_PATH . '/refill/util.php');
-require_once(BASE_HELPER_RAPI_PATH . '/api.php');
+require_once(BASE_HELPER_PATH . '/refill/RefillBase.php');
 
 use Log;
-use mtopcard;
-use QueueClient;
-use member_info;
-use Exception;
-use rbridge\RBridgeFactory;
-use trans_wapper;
 use StatesHelper;
-use queue;
 
-class RefillFactory
+class RefillFactory extends RefillBase
 {
     private static $stInstance = null;
 
@@ -48,713 +31,13 @@ class RefillFactory
         return self::$stInstance;
     }
 
-    private $mOilProvider;
-    private $mPhoneProvider;
-    private $mProviderNames;
-    private $mLimits = [];
-
     private function __construct()
     {
-        if (defined('MOBILE_SERVER') && MOBILE_SERVER === false) {
-            Log::record("MOBILE_SERVER defined dont call load",Log::DEBUG);
+        if (defined('SUPPORT_PTHREAD') && SUPPORT_PTHREAD === false) {
+            Log::record("SUPPORT_PTHREAD defined dont call load",Log::DEBUG);
         } else {
-            Log::record("MOBILE_SERVER has not defined and call load",Log::DEBUG);
+            Log::record("SUPPORT_PTHREAD has not defined and call load",Log::DEBUG);
             $this->load();
         }
     }
-
-    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;
-    }
-
-    private 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 find_providers(int $amount, int $card_type): 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 [];
-        }
-    }
-
-    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;
-    }
-
-    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_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 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);
-            return false;
-        }
-
-        if ($caller->verify($input))
-        {
-            [$order_id, $success, $can_try, $need_handle] = $caller->notify($input);
-            if (!$need_handle) {
-                return true;
-            }
-
-            if ($order_id !== false)
-            {
-                $mod_order = Model('vr_order');
-                $order_info = $mod_order->getOrderInfo(['order_id' => $order_id]);
-                $order_state = intval($order_info['order_state']);
-
-                if ($order_state != ORDER_STATE_SEND) {
-                    return false;
-                }
-
-                $logic_vr_order = Logic("vr_order");
-                if ($success) {
-                    $logic_vr_order->changeOrderStateSuccess($order_id);
-                }
-                elseif ($can_try)
-                {
-                    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))
-                        {
-                            $logic_vr_order->changeOrderStateCancel($order_info, '', "{$chname}接口回调通知失败,正在重试");
-                            if ($this->retry($refill_info, $order_info)) {
-                                $mod_refill->edit($order_id, ['inner_status' => 1, 'notify_time' => time(), 'notify_state' => 1]);
-                                $trans->commit();
-                                return true;
-                            }
-                        }
-
-                        $trans->commit();
-
-                    }
-                    catch (Exception $ex) {
-                        $trans->rollback();
-                        Log::record("Error:" . $ex->getMessage(),Log::ERR);
-                    }
-                }
-                else {
-                    $logic_vr_order->changeOrderStateCancel($order_info, '', "{$chname}接口回调通知失败,不可重试.");
-                }
-
-                $mod_refill = Model('refill_order');
-                $mod_refill->edit($order_id, ['notify_time' => time(), 'notify_state' => 1]);
-                QueueClient::push("NotifyMerchantComplete", ['order_id' => $order_id,'manual' => false]);
-            } else {
-                Log::record("系统无此订单ID:{$order_id}", Log::ERR);
-
-            }
-        } 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;
-            }
-
-            $period = time() - $refill['order_time'];
-            if ($period >= 15 * 60) {
-                Log::record("retry false:time > 15m", Log::DEBUG);
-                return false;
-            }
-
-            return true;
-        };
-
-        $can_try = $checker($refill_info, $order_info);
-        if (!$can_try) {
-            return false;
-        }
-
-        $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'];
-
-        $idcard = $refill_info['idcard'] ?? '';
-        $card_name = $refill_info['card_name'] ?? '';
-
-        [$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);
-    }
-
-    public function push_add($params)
-    {
-        return queue\DispatcherClient::instance()->push('add',$params);
-    }
-
-    public function push_notify($params)
-    {
-        queue\DispatcherClient::instance()->push('notify',$params);
-    }
-
-    public function push_notify_merchant($params)
-    {
-        queue\DispatcherClient::instance()->push('notify_mechant',$params);
-    }
-
-    public function add($mchid, $buyer_id, $amount, $card_no, $mch_order, $idcard, $card_name, $notify_url, $order_time = 0, $commit_times = 0)
-    {
-        $card_type = mtopcard\card_type($card_no);
-        $providers = $this->find_providers($amount, $card_type);
-
-        if (empty($providers)) {
-            return [202, "找不到合适的充值通道"];
-        }
-
-        if (empty($notify_url)) {
-            $notify_url = "";
-        }
-
-        $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();
-        }
-
-        $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;
-        foreach ($providers as $provider)
-        {
-            if(!$provider->opened()) continue;
-
-            $channel_name = $provider->name();
-            [$goods_id, $price] = $provider->goods($amount);
-
-            if ($price > $mch_amount) continue;
-
-            $input['goods_id'] = $goods_id;
-            $input['quantity'] = 1;
-            $input['price'] = $price;
-
-            $input['buyer_phone'] = $minfo->mobile();
-            $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');
-            $result = $logic_buy_virtual->buyStep3($input, $buyer_id, [$calc, 'calc_vorder_amount'], true);
-
-            $mod_refill = Model('refill_order');
-            if ($result['state'] === true)
-            {
-                $order_sn = $result['data']['order_sn'];
-                $order_id = $result['data']['order_id'];
-
-                if(!$this->pay_completed($order_sn)) {
-                    $logic_vr_order = Logic("vr_order");
-                    $order_info = Model('vr_order')->getOrderInfo(['order_id' => $order_id]);
-                    $logic_vr_order->changeOrderStateCancel($order_info, '', "预存款不足以支付该订单");
-                    continue;
-                }
-
-                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' => $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];
-                $mod_refill->add_refill($orderext);
-            } else {
-                continue;
-            }
-
-            $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);
-
-            if ($state)
-            {
-                $trade_no = $err;
-                if ($provider->refill_type() == 'api') {
-                    $logic_vr_order = Logic("vr_order");
-                    $logic_vr_order->changeOrderStateSend($order_id);
-                }
-
-                $data = ['commit_time' => time(), 'ch_trade_no' => $trade_no];
-                $mod_refill->edit($order_id, $data);
-                $refill_state = true;
-
-                //如果对方没有回调能力,则启动主动查询.
-                if($provider->callback() === false) {
-                    QueueClient::async_push("QueryRefillState",['order_id' => $order_id],180);
-                }
-
-                break;
-            } else {
-                Log::record("channel:{$channel_name} err:{$err}");
-                $logic_vr_order = Logic("vr_order");
-                $order_info = Model('vr_order')->getOrderInfo(['order_id' => $order_id]);
-                $logic_vr_order->changeOrderStateCancel($order_info, '', "调用{$channel_name}接口失败");
-                $mod_refill->edit($order_id, ['commit_time' => time(), 'inner_status' => 1]);
-            }
-        }
-
-        if ($refill_state) {
-            return [true, $order_sn];
-        } else {
-            return [204, "充值失败."];
-        }
-    }
-
-    private function pay_completed($order_sn)
-    {
-        $logic_payment = Logic('payment');
-        $order = $logic_payment->getVrOrderInfo($order_sn);
-        $api_pay_amount = $order['data']['api_pay_amount'];
-
-        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) {
-            return [false, "订单ID小于0"];
-        }
-
-        $vr_order = Model('vr_order');
-        $refill_order = Model('refill_order');
-
-        $order_info = $vr_order->getOrderInfo(['order_id' => $order_id]);
-        $refill_info = $refill_order->getOrderInfo(['order_id' => $order_id]);
-
-        if (empty($order_info) || empty($refill_info)) {
-            return [false, "无此订单"];
-        }
-
-        //手动通知,之所以不做尝试,是担心客户方状态处理不当
-        if (!$manual && $refill_info['mch_notify_state'] != 0) {
-            return [false, "已经通知客户方"];
-        }
-
-        $notify_url = $refill_info['notify_url'];
-        if (empty($notify_url)) {
-            $refill_order->edit($order_id, ['mch_notify_state' => 1, 'mch_notify_times' => 0]);
-            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 {
-            return [false, "错误的订单状态,不能通知."];
-        }
-
-        $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") {
-            $refill_order->edit($order_id, ['mch_notify_state' => 1, 'mch_notify_times' => ['exp', 'mch_notify_times+1']]);
-            return [true, ""];
-        } else {
-            $refill_order->edit($order_id, ['mch_notify_times' => ['exp', 'mch_notify_times+1']]);
-            $times = $refill_info['mch_notify_times'] + 1;
-
-            if ($times > 80) {
-                $refill_order->edit($order_id, ['mch_notify_state' => 2]);
-            } else {
-                $N = intval($times / 5);
-                $period = intval(pow(2, $N));
-                QueueClient::async_push("NotifyMerchantComplete", ['order_id' => $order_id,'manual' => false], $period);
-            }
-            return [false, "通知{$times}次,失败."];
-        }
-    }
-
-    public function query($order_id)
-    {
-        $mod_refill = Model('refill_order');
-        $refill_info = $mod_refill->getOrderInfo(['order_id' => $order_id,'inner_status' => 0]);
-
-        $chname = $refill_info['channel_name'];
-        $card_type = intval($refill_info['card_type']);
-
-        $provider = $this->provider($chname, $card_type);
-        [$state, $order_state] = $provider->query($refill_info);
-
-        if ($state === true)
-        {
-            $notify_state = $refill_info['notify_state'];
-            if($notify_state == 0)
-            {
-                $modify_able = true;
-                if(!$provider->callback())
-                {
-                    $logic_vr_order = Logic("vr_order");
-                    if ($order_state == ORDER_STATE_SUCCESS) {
-                        $logic_vr_order->changeOrderStateSuccess($order_id);
-                    } elseif ($order_state == ORDER_STATE_CANCEL) {
-                        $mod_order = Model('vr_order');
-                        $order_info = $mod_order->getOrderInfo(['order_id' => $order_id]);
-                        $logic_vr_order->changeOrderStateCancel($order_info, '', "{$chname}接口查询失败,不再重试.");
-                    } else {
-                        $modify_able = false;
-                        QueueClient::async_push("QueryRefillState",['order_id' => $order_id],180);
-                    }
-                }
-
-                if($modify_able) {
-                    $mod_refill->edit($order_id, ['notify_time' => time(), 'notify_state' => 1]);
-                    QueueClient::push("NotifyMerchantComplete", ['order_id' => $order_id,'manual' => false]);
-                }
-            }
-
-            return true;
-        }
-        else {
-            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;
-    }
 }

+ 4 - 2
rdispatcher/dispatcher.php

@@ -12,7 +12,7 @@ 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/RefillFactory.php');
+require_once(BASE_HELPER_PATH . '/refill/CoRefillFactory.php');
 require_once(BASE_HELPER_PATH . '/algorithm.php');
 
 require_once(BASE_PATH . '/processor.php');
@@ -74,4 +74,6 @@ function corun()
     });
 }
 
-event\util::fork_workerex('corun',$count);
+work_proc();
+
+//event\util::fork_workerex('corun',$count);

+ 16 - 8
rdispatcher/processor.php

@@ -24,14 +24,22 @@ class processor extends queue\ILooper
                 $proxy = new proxy();
                 if($method == 'add')
                 {
-                    go(function () use ($proxy,$params) {
-                        try {
-                            $proxy->add($params);
-                        }
-                        catch (Exception $x) {
-                            Log::record($x->getMessage(),Log::ERR);
-                        }
-                    });
+                    try {
+                        $proxy->add($params);
+                    }
+                    catch (Exception $x) {
+                        Log::record($x->getMessage(),Log::ERR);
+                    }
+
+//                    go(function () use ($proxy,$params)
+//                    {
+//                        try {
+//                            $proxy->add($params);
+//                        }
+//                        catch (Exception $x) {
+//                            Log::record($x->getMessage(),Log::ERR);
+//                        }
+//                    });
                 }
                 elseif($method == 'notify') {
 

+ 1 - 3
rdispatcher/proxy.php

@@ -3,8 +3,6 @@
 
 require_once (BASE_ROOT_PATH . '/helper/model_helper.php');
 
-use refill;
-
 class proxy
 {
     public function add($params)
@@ -22,7 +20,7 @@ class proxy
         $order_time = $params['order_time'] ?? 0;
         $commit_times = $params['commit_times'] ?? 0;
 
-        [$ret,$err] = refill\RefillFactory::instance()->add($mchid, $buyer_id, $amount, $card_no,
+        [$ret,$err] = refill\CoRefillFactory::instance()->add($mchid, $buyer_id, $amount, $card_no,
             $mch_order, $idcard, $card_name, $notify_url, $order_time, $commit_times);
     }
 

+ 6 - 897
test/TestAccRefill.php

@@ -46,241 +46,6 @@ class TestAccRefill extends TestCase
         Base::run_util();
     }
 
-    public function testFactory()
-    {
-        $providers = refill\RefillFactory::instance();
-    }
-
-    private function make_sn()
-    {
-        return mt_rand(1000, 9999)
-            . sprintf('%010d', time())
-            . sprintf('%06d', (float)microtime() * 1000000);
-    }
-
-    public function testRandomMobile()
-    {
-        $no = "1" . mt_rand(1, 9999999999);
-        Log::record("phone no={$no}",Log::DEBUG);
-    }
-
-    public function testBJBAddPhone()
-    {
-        $providers = new refill\bjb\RefillPhone([]);
-        for ($i = 3; $i > 0; --$i) {
-            $resp = $providers->add(13911129867, 4, 10, ['order_sn' => $this->make_sn()]);
-            $resp = $providers->add(18500608333, 4, 10, ['order_sn' => $this->make_sn()]);
-            $resp = $providers->add(18510683168, 4, 10, ['order_sn' => $this->make_sn()]);
-            $resp = $providers->add(18513846008, 4, 10, ['order_sn' => $this->make_sn()]);
-            $resp = $providers->add(18518237398, 4, 10, ['order_sn' => $this->make_sn()]);
-        }
-    }
-
-    public function testOilticket()
-    {
-        $providers = new refill\bjb\RefillPhone([]);
-    }
-
-    public function testBjbRet()
-    {
-        $resp = '0|提交成功|14936.8600';
-        $resp = explode('|' , $resp);
-    }
-
-    public function testIpWhiteList()
-    {
-        $x = serialize(['47.99.57.105']);
-        $ips = unserialize('a:1:{i:0;s:12:"47.99.57.105";}');
-        if (!empty($ips)) {
-            $addr = '47.99.57.105';
-            Log::record("request ip:{$addr}", Log::DEBUG);
-            if (!in_array($addr, $ips)) {
-                throw new Exception("请求地址不在白名单中");
-            }
-        }
-    }
-
-    public function testXcPhone()
-    {
-        $providers = new refill\xc\RefillPhone([]);
-        $resp = $providers->add(18500608333, 5, 100, ['order_sn' => $this->make_sn()]);
-    }
-
-    public function testAfandPhone()
-    {
-        $providers = new refill\afand\RefillPhone([]);
-        for ($i = 3; $i > 0; --$i) {
-            $resp = $providers->add(18518267398, 4, 30, ['order_sn' => $this->make_sn()]);
-        }
-    }
-
-    public function testYifaPhone()
-    {
-        $providers = new refill\yifa\RefillPhone([]);
-        $resp = $providers->add(15120035568, 5, 50, ['order_sn' => $this->make_sn()]);
-    }
-
-    public function testTianjtOil()
-    {
-        $cardno = 1000111100021211884;
-        $providers = new refill\tianjt\RefillOil([]);
-        $resp = $providers->add($cardno, 2, 500, ['order_sn' => $this->make_sn()]);
-    }
-
-    public function testTianxPhone()
-    {
-        $cardno = 13699279618;
-        $providers = new refill\tianx\RefillPhone([]);
-        $resp = $providers->add($cardno, 4, 50, ['order_sn' => $this->make_sn()]);
-    }
-
-    public function testWeitPhone()
-    {
-        $providers = new refill\weit\RefillPhone([]);
-        for ($i = 0;$i<=10;$i++){
-            $resp = $providers->add(18500608333, 5, 10, ['order_sn' => $this->make_sn()]);
-        }
-    }
-
-    public function testWeitCB()
-    {
-        $params['sign'] = 'af820c33472f4b571fa0c48483dfb975';
-        $params['status'] = 0;
-        $params['price'] = 30;
-        $params['op_order_id'] = '';
-        $params['mch_order_id'] = '900664281823957221';
-        $params['pt_order_id'] = '2021011802434412825405218901';
-        $params['pay_type'] = '';
-        $params['tel'] = 18500608333;
-        $params['mchid'] = 10014;
-        $resp = http_request($this->mReqHost . "/mobile/refill_weit.php", $params , 'POST');
-    }
-
-    public function testYifaCB()
-    {
-        $body = '{"app_id":"e4a61b2acf1119c72c1ed9b61781494e","nonce_str":"OQMEBRQWJGPKOWYUXDVPTNMLEQJHXFWG","timestamp":1610275083,"order_sn":"161027325773032634","coder_order_sn":"60641610273255214687","isp_order_sn":null,"phone":"15120035568","amount":"94.000","discount":"0.9400","create_time":"2021-01-10 18:07:42","recharge_time":"","status":"fail","channel_id":3,"sign":"47278AD74EFA7F5FC8DE3A6D362C409B"}';
-        $input = json_decode($body,true);
-        refill\RefillFactory::instance()->notify('yifa',$input);
-    }
-
-    public function testBjbQuery()
-    {
-        $providers = new refill\bjb\RefillPhone([]);
-        $refill_info = ['order_sn' => 110667993758599771, 'ch_trade_no' => 499, 'card_no' => 1000111200005252927];
-        $resp = $providers->query($refill_info);
-    }
-
-    public function testXcQuery()
-    {
-        $providers = new refill\xc\RefillPhone([]);
-        $refill_info = ['order_sn' => 950663423236726632, 'ch_trade_no' => 499, 'card_no' => 1000111200005252927];
-        $resp = $providers->query($refill_info);
-    }
-
-    public function testTianjtQuery()
-    {
-        $providers = new refill\tianjt\RefillOil([]);
-        $refill_info = ['order_sn' => 680665862267622221, 'ch_trade_no' => 499, 'card_no' => 1000111200005252927];
-        $resp = $providers->query($refill_info);
-    }
-
-    public function testSaihuOil()
-    {
-        $providers = new refill\saihu\RefillOil([]);
-        $resp = $providers->add(1000111100021211884, 2, 100, ['order_sn' => $this->make_sn()]);
-    }
-
-    public function testBdtOil()
-    {
-        $providers = new refill\bdt\RefillOil([]);
-        $resp = $providers->add(1000111100021211884, 2, 100, ['order_sn' => '200229600556618886']);
-    }
-
-    public function testGFTDOil()
-    {
-        $providers = new refill\gftd\RefillOil([]);
-        $resp = $providers->add(1000111100020445281, mtopcard\SinopecCard, 100, ['order_sn' => $this->make_sn()]);
-    }
-
-    public function testGFTDCB()
-    {
-        $data = '{"channelOrderNumber":"79091610959059372019","orderNumber":"GYFL1610959060397001","message":"充值成功","signature":"881036222bd8f067ff47d248c75f4c8d","voucher":"","status":101}';
-        $url = "http://192.168.1.220/mobile/refill_gftd.php?" . $data;
-        $resp = http_post_data($url, $data, ['Content-Type: application/json;charset=UTF-8;','Accept:application/json;charset=UTF-8;']);
-    }
-
-    public function testJiecPhone()
-    {
-        $providers = new refill\jiec\RefillPhone([]);
-        $resp = $providers->add('18500608333', 5, 30, ['order_sn' => $this->make_sn()]);
-    }
-
-    public function testBxtwtCB()
-    {
-        $data = '{"order_number":18219726,"shipping_status":4,"shipping_status_desc":"发货失败","shipping_status_message":"","sign":"863b4d972f2a4d39a9af7396879116c4","voucher":"","vouchertype":"","voucherurl":"","tradeNo":"100662475851197741"}';
-    }
-
-    public function testTianjtJDVerify()
-    {
-        $data = 'onlystr=920661883198026632&sign=533151e3f0dff5f507786aabc37b18f7&amt=100&notifyurl=https%3A%2F%2Fwww.xyzshops.cn%2Fmobile%2Frefill_tianjt.php&jdno&cardtype=Sinoepc&batchid=26106&cardno=1000111100020654226&orgid=1590993600&status=3';
-        $url = "http://192.168.1.220/mobile/refill_tianjt.php?" . $data;
-        $resp = http_request($url);
-    }
-
-    public function testSuhcPDD()
-    {
-        $data = 'onlystr=820663525320005221&pddno&sign=4b1e8645f7541ced34855779448d9d52&amt=100&notifyurl=https%3A%2F%2Fwww.xyzshops.cn%2Fmobile%2Frefill_suhcpdd.php&cardtype=Sinoepc&batchid=3&cardno=1000111100020445281&orgid=1590993600&status=2';
-
-        $url = "https://www.xyzshops.cn/mobile/refill_suhcpdd.php?" . $data;
-        $resp = http_request($url);
-    }
-
-    public function testSuhcTMVerify()
-    {
-        $data = 'onlystr=180662473867058221&sign=5ff5f95d54a89e78dbb49923f6b20c08&amt=100&notifyurl=https%3A%2F%2Fwww.xyzshops.cn%2Fmobile%2Frefill_suhctm.php&cardtype=Sinoepc&batchid=3&cardno=1000111100020445281&orgid=1590993600&status=3';
-        $url = "https://www.xyzshops.cn/mobile/refill_suhctm.php?" . $data;
-        $resp = http_request($url);
-    }
-
-    public function testBeixtVerify()
-    {
-        $data = '{"order_number":18219726,"shipping_status":4,"shipping_status_desc":"发货失败","shipping_status_message":"","sign":"863b4d972f2a4d39a9af7396879116c4","voucher":"","vouchertype":"","voucherurl":"","tradeNo":"100662475851197741"}';
-        $url = "https://www.xyzshops.cn/mobile/refill_bxtwt.php";
-
-        $headers = ['Content-Type: application/json'];
-        $resp = http_post_data($url, $data, $headers);
-    }
-
-    public function testInput()
-    {
-        $input = fopen("php://input", "rw");
-        file_put_contents($input, 'xxxx');
-        $content = file_get_contents('php://input');
-    }
-
-
-    public function testUrl()
-    {
-        $data = 'onlystr=190661874318128632&sign=9eb60765c356341fd41c9bec6526f46a&amt=1000&notifyurl=https%3A%2F%2Fwww.xyzshops.cn%2Fmobile%2Frefill_suhc.php&jdno&cardtype=Sinoepc&batchid=25940&cardno=1000111100012304048&orgid=1590993600&status=2';
-
-        $params = preg_split('/&/', $data);
-        foreach ($params as $pair) {
-            $kv = explode('=', $pair);
-            $count = count($kv);
-            if ($count === 1) {
-                $key = $kv[0];
-                $val = "";
-            } elseif ($count === 2) {
-                $key = $kv[0];
-                $val = $kv[1];
-            } else {
-                continue;
-            }
-
-            Log::record("{$key}:{$val}", Log::DEBUG);
-        }
-    }
-
     public function testAddoil()
     {
         $url = $this->mReqHost . "/racc/index.php";
@@ -304,674 +69,18 @@ class TestAccRefill extends TestCase
             'notifyurl' => $notifyurl];
 
         return $params;
-
-
-    }
-
-    public function testBalance()
-    {
-        $url = $this->mReqHost . "/mobile/index.php";
-        $params = ['mchid' => 1092,
-            "act" => "refill",
-            "op" => "balance"];
-        $resp = $this->send_md5($url, $params);
-        Log::record($resp, Log::DEBUG);
-    }
-
-
-    public function testAddPhoe()
-    {
-        $phones = [//13911129867,
-            18500608333,
-            18510683168,
-            18513846008,
-            18518237398];
-        $amount = 10;
-
-        for ($i = 0; $i < 3; $i++) {
-            foreach ($phones as $phone) {
-                $url = $this->mReqHost . "/mobile/index.php";
-                $params = ['mchid' => 1092,
-                    'cardno' => $phone,
-                    'amount' => $amount,
-                    "act" => "refill",
-                    "op" => "add",
-                    'order_sn' => $this->make_sn(),
-                    'notifyurl' => $this->mReqHost . "/mobile/refill_xyz.php"];
-
-                $resp = $this->send_md5($url, $params);
-                Log::record($resp, Log::DEBUG);
-            }
-        }
-    }
-
-    public function testProxyHelper()
-    {
-        $phone = '13911129867';
-        $amount = 100;
-        $url = $this->mReqHost . "/mobile/index.php";
-        $params = ['mchid' => 1090,
-            'cardno' => $phone,
-            'amount' => $amount,
-            "act" => "refill",
-            "op" => "add",
-            'order_sn' => $this->make_sn(),
-            'notifyurl' => "https://xxx"];
-        $proxy = new refill_proxy("xxx");
-        $resp = $proxy->send($url, $params);
-    }
-
-    public function testGoods()
-    {
-        $req_url = $this->mReqHost . '/mobile/index.php';
-        $params = ['mchid' => $this->mMchid,
-            "act" => "refill",
-            "op" => "goods"];
-
-        $resp = $this->send_md5($req_url, $params);
-    }
-
-    public function testQueryFactory()
-    {
-        refill\RefillFactory::instance()->query(295);
-    }
-
-    public function testQuery()
-    {
-        //$req_url = 'https://www.xyzshops.cn/mobile/index.php';
-//        $notifyurl = 'https://www.xyzshops.cn/mobile/signature.php';
-
-        $req_url = BASE_SITE_URL . '/mobile/index.php';
-        $notifyurl = 'https://www.xyzshops.cn/mobile/signature.php';
-
-        $params = ['mchid' => 1,
-            "act" => "refill",
-            "op" => "query",
-            'order_sn' => "13281476"];
-
-        $resp = $this->send_md5($req_url, $params);
-    }
-
-    public function testRemoveSession()
-    {
-        $resp = http_request(BASE_SITE_URL . "/mobile/signature.php", [], 'POST');
-    }
-
-
-    public function testTianjtCB()
-    {
-//        $notifyurl = BASE_SITE_URL . "/mobile/refill_tianjt.php";
-        $notifyurl = "https://www.xyzshops.cn/mobile/refill_tianjt.php";
-//        $notifyurl = "https%3A%2F%2Fwww.xyzshops.cn%2Fmobile%2Frefill_tianjt.php";
-
-        $params = ['onlystr' => '690665858589475818',
-            'amt' => 1000,
-            'jdno' => '',
-            'notifyurl' => $notifyurl,
-            'cardtype' => 'Sinoepc',
-            'batchid' => 30589,
-            'cardno' => '1000113300007993287',
-            'orgid' => '1590993600',
-            'status' => 3];
-
-        $sign = $this->md5_sign($params);
-        $params['sign'] = $sign;
-
-        $resp = http_request($notifyurl, $params, 'POST');
-        Log::record($resp, Log::DEBUG);
-    }
-
-
-    public function testBJBCB()
-    {
-        $params = [
-            'usr' => '13699279618',
-            'ord' => '710662733975412771',
-            'state' => '2',
-            'bz' => '',
-            'sgn' => 'AC9AFD254DE682D8440A97CA68B992DA'
-        ];
-
-        $resp = http_request("https://www.xyzshops.cn/mobile/refill_bjb.php", $params, 'POST');
-    }
-
-    public function testJiecCB()
-    {
-        $params['result'] = 'fail';
-        $params['msg'] = '0';
-        $params['order'] = 'null';
-        $params['phone_no'] = '18500608333';
-        $params['amount'] = '30.00';
-        $params['op_no'] = '800663597981819221';
-        $params['sign'] = '2510046895e8e12322c8a32547905ee9';
-
-        $resp = http_request($this->mReqHost . "/mobile/refill_jiec.php", $params, 'POST');
-    }
-
-
-    public function testZFKJ()
-    {
-        //带签名参数:mchid=1090&act=refill&op=add&cardno=100112121212212133
-        //&amount=10&order_sn=PH2012261356569433&
-        //notifyurl=https%3A%2F%2Fqzcz.edusahoo.com.cn%2Findex%2Findex%2Fcallback
-        //&sign=4a3ac5f9706e64aa70c6cab0fc5839d3
-
-        $params = ['mchid' => 1090,
-            'cardno' => '100112121212212133',
-            'amount' => '10',
-            "act" => "refill",
-            "op" => "add",
-            'order_sn' => 'PH2012261356569433',
-            'notifyurl' => 'https://qzcz.edusahoo.com.cn/index/index/callback'];
-
-        $resp = $this->send_md5(BASE_SITE_URL . '/mobile/index.php', $params);
-    }
-
-
-    protected function check_empty($value)
-    {
-        if (!isset($value))
-            return true;
-        if ($value === null)
-            return true;
-        if (trim($value) === "")
-            return true;
-
-        return false;
-    }
-
-    private function md5_sign($params)
-    {
-        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}" . "=" . urldecode($v);
-                } else {
-                    $body .= "&" . "{$k}" . "=" . urldecode($v);
-                }
-                $i++;
-            }
-        }
-
-        $body .= "&key=7yDCLS6S2KzSAJQOUc3vsa";
-
-        return md5($body);
-    }
-
-    public function testCallMech()
-    {
-        $logic = Logic('queue');
-        $logic->NotifyMerchantComplete(['order_id' => 18171,'manual' => true]);
-    }
-
-    //docker-compose run phpcli php /var/www/html/phpunit-9.2.5.phar --filter "/(TestRefill::testCallMech)( .*)?$/" --test-suffix TestRefill.php /var/www/html/test
-
-
-    private function send($url, $params)
-    {
-        $mchid = $params['mchid'];
-        $pri_key = BASE_DATA_PATH . "/api/merchant/key/{$mchid}_pri.pem";
-
-        $key = file_get_contents($pri_key);
-        $pri = openssl_get_privatekey($key);
-
-        $body = $this->body($params);
-
-        openssl_sign($body, $signed, $pri);
-        $sign = base64_encode($signed);
-        $params['sign'] = $sign;
-
-        $resp = http_request($url, $params, 'POST');
-        Log::record("resp:{$resp}", Log::DEBUG);
-    }
-
-    private function send_md5($url, $params)
-    {
-        $body = $this->body($params);
-        $body .= "&key={$this->mKey}";
-        $params['sign'] = md5($body);
-
-        $resp = http_request($url, $params, 'POST');
-        Log::record("resp:{$resp}", Log::DEBUG);
-
-        return $resp;
-    }
-
-    public function testCardType()
-    {
-        $cardno = '1000111100021211884';
-        $ret = preg_match('/^1[0-9]{18}$/', $cardno, $matches);
-    }
-
-    public function testMtrand()
-    {
-    }
-
-    public function testHttpRefill()
-    {
-        $mchid = '000001';
-        $pri_key = BASE_DATA_PATH . "/api/merchant/key/{$mchid}_pri.pem";
-
-        $key = file_get_contents($pri_key);
-        $pri = openssl_get_privatekey($key);
-
-        $params = ['MCHID' => $mchid, 'cardno' => '1000111100021211884', 'amt' => "100", "act" => "refill", "op" => "addoil"];
-        $body = $this->body($params);
-
-        openssl_sign($body, $signed, $pri);
-        $sign = base64_encode($signed);
-        $params['sign'] = $sign;
-
-        $resp = http_request(BASE_SITE_URL . "/mobile/index.php", $params, 'POST');
-    }
-
-    private function body($params)
-    {
-        ksort($params);
-        $body = "";
-        $i = 0;
-        foreach ($params as $k => $v) {
-            if (false === $this->checkEmpty($v) && "@" != substr($v, 0, 1)) {
-                if ($i == 0) {
-                    $body .= "{$k}" . "=" . urlencode($v);
-                } else {
-                    $body .= "&" . "{$k}" . "=" . urlencode($v);
-                }
-                $i++;
-            }
-        }
-        return $body;
-    }
-
-    private function checkEmpty($value)
-    {
-        if (!isset($value))
-            return true;
-        if ($value === null)
-            return true;
-        if (trim($value) === "")
-            return true;
-
-        return false;
-    }
-
-    public function testKsort()
-    {
-        $age = ["Peter" => "35", "Ben" => "37", "Joe" => "43"];
-        ksort($age);
-
-        foreach ($age as $x => $x_value) {
-            echo "Key=" . $x . ", Value=" . $x_value;
-            echo "<br>";
-        }
-    }
-
-    public function testip()
-    {
-        $model_merchant = Model('merchant');
-        $merchant_info = $model_merchant->getMerchantInfo(['mchid' => 1]);
-        $ipwhitelist = unserialize($merchant_info['ip_white_list']);
-        $res = json_encode($ipwhitelist);
-    }
-
-    //测试向内部店提交订单,可先屏蔽其它充值通道
-    public function testAddoilToInnerStore()
-    {
-        $url = $this->mReqHost . "/mobile/index.php";
-        $notifyurl = BASE_SITE_URL . '/mobile/signature.php';
-        $params = ['mchid' => 1,
-            'cardno' => '1000111100020445281',
-            'amount' => "1000",
-            "act" => "refill",
-            "op" => "add",
-            'card_name' => '江海苗',
-            'order_sn' => $this->make_sn(),
-            'notifyurl' => $notifyurl];
-
-        $resp = $this->send_md5($url, $params);
-        Log::record($resp, Log::DEBUG);
-    }
-
-    public function testRefillInnerCB()
-    {
-        $params = ['state_type' => 'order_cancel', 'order_id' => 311, 'channel_name' => 'lx'];
-        $resp = http_request(BASE_SITE_URL . '/mobile/refill_inner.php', $params, 'POST');
-    }
-
-    public function testArgs()
-    {
-        Log::record($_SERVER['argv'], Log::DEBUG);
-    }
-
-    public function testCall()
-    {
-        $order_id = 14974;
-        QueueClient::async_push("NotifyMerchantComplete", ['order_id' => $order_id,'manual' => true], 10);
-    }
-
-    public function testSyncconfig()
-    {
-        $name_val_cfg = function ($items) {
-            $result = [];
-            foreach ($items as $item) {
-                $name = $item->name();
-                $result[$name] = $item;
-            }
-            return $result;
-        };
-
-        $name_val_row = function ($items) {
-            $result = [];
-            foreach ($items as $item) {
-                $name = $item['name'];
-                $result[$name] = $item;
-            }
-            return $result;
-        };
-
-        $match = function ($all,$cur)
-        {
-            $insert = [];
-            foreach ($all as $key => $value)
-            {
-                if(!array_key_exists($key,$cur)) {
-                    $insert[] = $key;
-                }
-            }
-            return $insert;
-        };
-
-        $inserter = function ($mod,$type,$names)
-        {
-            foreach ($names as $name) {
-                $data = ['name' => $name,'type' => $type];
-                $mod->insert($data);
-            }
-        };
-
-        $providers = refill\RefillFactory::instance()->providers();
-        $oils = $name_val_cfg($providers['oil']);
-        $phones = $name_val_cfg($providers['phone']);
-
-        $mod_prov = Model('refill_provider');
-
-        $oil_items = $mod_prov->getProviderList(['type' => 1]);
-        $oil_items = $name_val_row($oil_items);
-        $oil_inserts = $match($oils,$oil_items);
-
-        $phone_items = $mod_prov->getProviderList(['type' => 2]);
-        $phone_items = $name_val_row($phone_items);
-        $phone_inserts = $match($phones,$phone_items);
-
-        $inserter($mod_prov,1,$oil_inserts);
-        $inserter($mod_prov,2,$phone_inserts);
-    }
-
-    public function testStat()
-    {
-        $model_refill_order = Model('refill_order');
-        $stat = Model('')->table('refill_order,vr_order')->join('inner')
-            ->on('refill_order.order_id=vr_order.order_id')
-            ->field('sum(refill_amount) as refill_amounts , sum(channel_amount) as channel_amounts , sum(mch_amount) as mch_amounts')
-            ->where([])->select();
-    }
-    public function testRefillGoods()
-    {
-        $goods = refill\RefillFactory::instance()->goods();
-    }
-
-    private function make_mobile()
-    {
-        $no = "1" . mt_rand(3000000000, 3999999999);
-        return $no;
-    }
-
-    private function refill_info($card_no, $card_type)
-    {
-        $data = rcache($card_no, 'cardrefill-');
-        if(empty($data))
-        {
-            $mod_topcard = Model('topcard');
-            $ret = $mod_topcard->get_card($card_no);
-            if(empty($ret)) {
-                $bind_phone = $this->make_mobile();
-                $mod_topcard->add($card_no,$card_type,time(),$bind_phone);
-                $data['bind_phone'] = $bind_phone;
-                $data['refill_time'] = time();
-                $data['times'] = 0;
-
-                wcache($card_no,$data,'cardrefill-');
-            }
-            else {
-                $val = $ret[0];
-
-                $data['bind_phone'] = $val['bind_phone'];
-                $data['refill_time'] = time();
-                $data['times'] = 0;
-            }
-        }
-
-        return $data;
-    }
-
-    public function testGetMobile()
-    {
-        $card_no = '1000119000001679247';
-        $card_type = 1;
-
-        $info = $this->refill_info($card_no,$card_type);
-
-    }
-
-    private function check_mchorder($mchid,$mch_order)
-    {
-        if(empty($mch_order)) {
-            return true;
-        }
-        else {
-            $refill_order = Model('refill_order');
-            $ret = $refill_order->getOrderInfo(['mchid' => $mchid,'mch_order' => $mch_order]);
-
-            return empty($ret);
-        }
-    }
-
-    public function testCheckMchorder()
-    {
-        $ret = $this->check_mchorder(1,'13281475');
-    }
-
-    public function testMakemobile()
-    {
-        $mobile = refill\util::make_mobile();
-        $ret = refill\util::set_black('1000111100020445281');
-    }
-
-    public function testLoadBlack()
-    {
-        $path = BASE_DATA_PATH . "/log";
-        $names = ['20210119-mobile.log',
-            '20210120-mobile.log','20210121-mobile.log','20210122-mobile.log','20210123-mobile.log',
-            '20210124-mobile.log','20210125-mobile.log'];
-
-        foreach ($names as $name)
-        {
-            $file_name = $path . "/" . $name;
-            refill\util::black_from_log($file_name);
-        }
-    }
-
-
-
-    public function testStats()
-    {
-        $date = date('Y-m-d',time());
-        $today = strtotime("{$date}");
-
-        $times_begin = function ($start) {
-            $times = [];
-            $begin = $start;
-            for($i = 0; $i < 7; $i++) {
-                $times[] = $begin;
-                $begin -= 86400;
-            }
-            return $times;
-        };
-
-        $reader = function ($mchid,$time) {
-            $cond['mchid'] = $mchid;
-            $cond['inner_status'] = 0;
-            $cond['refill_order.order_time'] = ['between', [$time, $time + 86400 -1]];
-
-            $items = Model('')->table('refill_order,vr_order')->join('inner')
-                ->on('refill_order.order_id=vr_order.order_id')
-                ->field('count(*) as order_count, vr_order.order_state, sum(mch_amount) as mch_amounts')
-                ->group('vr_order.order_state')
-                ->where($cond)->select();
-
-            return $items;
-        };
-
-        $begins = $times_begin($today);
-
-        $mchid = 10096;
-//        $states = rcache($this->mchid() , 'refillstat-');
-        $states = unserialize($states ?? "");
-        if(empty($states)) $states = [];
-
-        $result = [];
-        $cache = [];
-        foreach ($begins as $begin)
-        {
-            if(array_key_exists($begin,$states)) {
-                $item = $states[$begin];
-            }
-            else {
-                $item = $reader($mchid,$begin);
-            }
-            $result[$begin] = $item;
-
-            //判断item 中充值中的状态是否为0,为0的情况下放进cache
-            $cache = $item;
-
-        }
-
-        wcache($this->mchid() ,$cache, 'refillstat-');
-
-        return $result;
-    }
-
-    public function testNotify()
-    {
-        $mch_cache = rcache("merchant-notify" , 'refill-');
-        $caches = empty($mch_cache['data']) ? [] : unserialize($mch_cache['data']);
-
-        $new_caches = [];
-        $merchants = Model('merchant')->getMerchantList([],'','','merchant.*,member.available_predeposit' ,"0,1000");
-        foreach ($merchants as $merchant)
-        {
-            $mchid = $merchant['mchid'];
-            $phone = $merchant['contact_phone'] ?? "";
-            $available_pd = intval($merchant['available_predeposit']);
-            $alarm_pd = intval($merchant['alarm_amount']) < 10000 ? 10000 : intval($merchant['alarm_amount']);
-
-            if(array_key_exists($mchid,$caches)) {
-                $mch_cache = $caches[$mchid];
-            }
-            else {
-                $mch_cache = ['last_time' => 0, 'send_count' => 0];
-            }
-
-            if(!empty($phone) && ($available_pd < $alarm_pd))
-            {
-                $counts =  $mch_cache['send_count'];
-                if(($mch_cache['last_time'] + 300 < time()) && $counts < 5) {
-                    $mch_cache = ['last_time' => time(), 'send_count' => $counts + 1];
-                    QueueClient::push('sendSMS', ['mobile'=>$merchant['contact_phone'],
-                        'type'=>'balance_warning','datas' => [date("m月d日H时") , $merchant['available_predeposit']]]);
-
-                }
-            }
-            else {
-                $mch_cache = ['last_time' => 0, 'send_count' => 0];
-            }
-            $new_caches[$mchid] = $mch_cache;
-        }
-
-        wcache("merchant-notify", ['data' => serialize($new_caches)], 'refill-');
-    }
-
-    public function testReadChannel()
-    {
-        refill\RefillFactory::instance()->read_channel();
-    }
-
-    public function testAllow()
-    {
-        $allow = refill\RefillFactory::instance()->allow(10096,1,100);
-
-    }
-
-    public function testCheckData(){
-        $str = '2|110667993758599771-充值失败|';
-        $str = '0|提交成功|-36557.7400';
-//        if(preg_match( '/^-*[0-9]{1,3}\|[\x{4e00}-\x{9fa5}]+\|-*[0-9]+\.*[0-9]+$/u',$str,$matches)) {
-//            return true;
-//        }
-        if(preg_match('/^[0-3]\|[0-9]+-*[\x{4e00}-\x{9fa5}]+\|[0-9]*$/u',$str,$matches)){
-            return true;
-        }
-        return false;
     }
 
-    public function testErrre()
+    public function testFactory()
     {
-        $line = '[13 2021-01-24 16:07:03] DEBUG: type = application/json;charset=utf-8, content={"channelOrderNumber":"610664819621371793","orderNumber":"GYFL1611475621525437","message":"充值失败","signature":"6c28c15b9ce2b2243742ecebbd929ac5","status":109}';
-        $ret = preg_match('/[\w\W]+"channelOrderNumber":"(?P<order_sn>[^"]+)"[\w\W]+"message":"(?P<message>[\x{4e00}-\x{9fa5}]+)"[\w\W]+"status":109/u',$line,$matches);
+        $providers = refill\RefillFactory::instance();
     }
 
-    public function testLog()
+    private function make_sn()
     {
-//        $line = './LOG/20210203-mobile.log:[15 2021-02-03 10:41:17] SQL: UPDATE `lrlz_member` SET available_predeposit=available_predeposit+975 WHERE ( member_id = \'65818\' ) [ RunTime:0.000297s ]';
-        $fn = fopen(BASE_ROOT_PATH . "/10096.log","r");
-        $mod = Model();
-        $mod->table('tfloat')->where(['member_id' => 65818])->update( ['pdamount'=>0]);
-
-
-        $total_amount = ncPriceFormat(0.00);
-
-        $i = 0;
-        while(! feof($fn))  {
-
-            $i++;
-            $line = trim(fgets($fn));
-            $ret = preg_match('/[\w\W]+UPDATE[\w\W]+available_predeposit=available_predeposit(?P<oper>[-+]+)(?P<amount>[.\d]+)/i',$line,$matches);
-            if($ret) {
-                $oper = $matches['oper'];
-                $amount = $matches['amount'];
-                if($oper == '-') {
-                    $total_amount = ncPriceFormat($total_amount) - ncPriceFormat($amount);
-//                    $mod->table('tfloat')->where(['member_id' => 65818])->update( ['pdamount'=>['exp','pdamount-'.$amount]]);
-
-                }
-                else {
-                    $total_amount = ncPriceFormat($total_amount) + ncPriceFormat($amount);
-//                    $mod->table('tfloat')->where(['member_id' => 65818])->update( ['pdamount'=>['exp','pdamount+'.$amount]]);
-
-                }
-
-                Log::record("index = {$i} {$total_amount} = {$total_amount} {$oper} {$amount}",Log::DEBUG);
-            }
-        }
-
-        Log::record("total_amount:{$total_amount}",Log::DEBUG);
-        fclose($fn);
-
-
+        return mt_rand(1000, 9999)
+            . sprintf('%010d', time())
+            . sprintf('%06d', (float)microtime() * 1000000);
     }
 }