rabin 1 week geleden
bovenliggende
commit
b827e14569

+ 201 - 0
src/dai/seller/app/Api/Notify.php

@@ -0,0 +1,201 @@
+<?php namespace Seller\Api;
+use Dever;
+use Connect\Lib\Func\Api;
+class Notify extends Api
+{
+    # 渠道发起回调
+    public function common()
+    {
+        //$param = '{"s":"132dcszvteLAx3r5eKrjarbGyJilBFECGu2F7mCX-H6K2_w","appid":"app483393213726","order_id":"Q202401040798155761553480","merchant_order_id":"yk18f2401040253000002","status":2,"cash":1000,"msg":"充值成功","actual_cash":1004.9999999999999,"time":1704308034101,"nonce":"fa0912fcfeb3ddfec4e821c26","signature":"d58295706e069e61a4a4ef9428ae0d155b36fae6"}';
+        //$input = Dever::json_decode($param);
+        $input = Dever::input();
+        if (!isset($input['s'])) {
+            $this->error('error');
+        }
+        $s = \Dever\Helper\Str::decode($input['s']);
+        if ($s) {
+            list($connect_id, $api_id, $order_id) = explode('|', $s);
+        } elseif (isset($input['order_num'])) {
+            $order_id = Dever::db('seller/order')->find(array('order_num' => $input['order_num']));
+            if (!$order_id) {
+                $this->error('error');
+            }
+            $channel = Dever::db('channel/info')->find($order_id['channel_id']);
+            if (!$channel) {
+                $this->error('order error');
+            }
+            $connect_id = $channel['connect_id'];
+            $api = Dever::db('connect/api')->find(array('connect_id' => $connect_id, 'type' => 1));
+            if (!$api) {
+                $this->error('order error');
+            }
+            $api_id = $api['id'];
+
+        } else {
+            $this->error('error');
+        }
+        $this->connect = Dever::db('connect/info')->find($connect_id);
+        $this->info = Dever::db('connect/api')->find($api_id);
+        
+        unset($input['s']);
+        unset($input['l']);
+        if (!$input) {
+            $input = file_get_contents("php://input");
+            if ($input) {
+                $input = json_decode($input, true);
+                if (is_array($input)) {
+                    if (isset($input['s'])) {
+                        unset($input['s']);
+                    }
+                    if (isset($input['l'])) {
+                        unset($input['l']);
+                    }
+                } else {
+                    $this->error('error');
+                }
+            }
+        }
+        if (!$input) {
+            $this->error('error');
+        }
+        $this->load($input, $connect_id, $api_id, $order_id);
+    }
+
+    private function load($input, $connect_id, $api_id, $order_id)
+    {
+        //Dever::log($input, 'notify');
+        if (is_array($order_id)) {
+            $order = $order_id;
+        } else {
+            $order = Dever::db('seller/order')->find($order_id);
+        }
+        if (!$order || $order['status'] >= 10) {
+            $this->error('order error');
+        }
+        $channel = Dever::db('channel/info')->find($order['channel_id']);
+        if (!$channel) {
+            $this->error('channel error');
+        }
+        $this->connect['appsecret'] = $channel['appsecret'];
+
+        $code = Dever::db('connect/api_notify_code')->select(array('api_id' => $api_id));
+
+        $status = 0;
+        if ($code) {
+            foreach ($code as $k => $v) {
+                if (isset($input[$v['key']]) && $input[$v['key']] == $v['value']) {
+                    $status = $v['type'];
+                }
+            }
+        }
+        $data = $input;
+        $data['status'] = $status;
+        $data = $this->service($data);
+
+        $msg = '';
+        if ($status == 1) {
+            $msg = 'ok';
+        } elseif ($status == 2) {
+            $msg = 'error';
+        }
+        if ($this->info['notify_sign_col']) {
+            $this->info['sign_col'] = $this->info['notify_sign_col'];
+        }
+        if ($sign = Dever::issets($input, $this->connect['sign_name'])) {
+            unset($input[$this->connect['sign_name']]);
+            unset($input['l']);
+            /*
+            $string = '';
+            if ($sign != $this->sign($input, $string)) {
+                $this->error('sign error');
+            }*/
+        }
+        if ($msg) {
+            $update = array();
+            $update['official_msg'] = $data['official_msg'] ?? '';
+            $update['official_order_num'] = $data['official_order_num'] ?? '';
+            $update['channel_callback'] = json_encode($input, JSON_UNESCAPED_UNICODE);
+            $update['channel_callback_date'] = time();
+
+            if ($msg != 'ok') {
+                $channel_num = Dever::db('seller/channel')->count(array('seller_id' => $order['seller_id'], 'goods_id' => $order['goods_id'], 'status' => 1));
+                if ($channel_num > 1) {
+                    # 记录渠道错误信息
+                    $selected = array();
+                    $selected[$order['channel_id']] = true;
+                    $order_error_data = Dever::db('seller/order_channel_error')->select(array('order_id' => $order['id']));
+                    if ($order_error_data) {
+                        foreach ($order_error_data as $k => $v) {
+                            $selected[$v['channel_id']] = true;
+                        }
+                    }
+                    $num = count($selected);
+                    $channel_num = $channel_num - $num;
+                    if ($channel_num > 0) {
+                        $order_error = array();
+                        $order_error['order_id'] = $order['id'];
+                        $order_error['order_channel_id'] = $order['order_channel_id'];
+                        $order_error['channel_id'] = $order['channel_id'];
+                        Dever::db('seller/order_channel_error')->insert($order_error);
+                        Dever::load(\Seller\Lib\Order::class)->handleAct($order, $selected);
+                    } else {
+                        Dever::load(\Seller\Lib\Order::class)->notify($order, $msg, $update);
+                    }
+                } else {
+                    Dever::load(\Seller\Lib\Order::class)->notify($order, $msg, $update);
+                }
+            } else {
+                Dever::load(\Seller\Lib\Order::class)->notify($order, $msg, $update);
+            }
+            echo $this->info['notify_success'];die;
+        }
+        $this->error('error');
+    }
+
+    private function error($msg)
+    {
+        if ($this->info && $this->info['notify_error']) {
+            if ($this->info['notify_error'] == 500) {
+                header("HTTP/1.1 500 Internal Server Error");
+                header("Status: 500 Internal Server Error");
+            } else {
+                echo $this->info['notify_error'];die;
+            }
+        }
+        echo $msg;die;
+    }
+
+    # 生成回调
+    public function callback()
+    {
+        //$param = '{"l":"notify.callback","t":"4-5-user_order","userid":"41438","order_id":"24020213181441438abbf5b39f","account":"15810090811","amount":"100","price":"104.1","state":"failed","user_order":"C2024020251094338265393","sign":"0447CC15F7D0218A1C5C09160A12A19A","voucher":""}';
+        //$input = Dever::json_decode($param);
+        $input = Dever::input();
+        if (!isset($input['t'])) {
+            $this->error('error');
+        }
+        $file = file_get_contents("php://input");
+        if ($file) {
+            $file = json_decode($file, true);
+            if ($file) {
+                $input = array_merge($file, $input);
+            }
+        }
+        $temp = explode('-', $input['t']);
+        $connect_id = $temp[0];
+        $api_id = $temp[1];
+        $order_key = $temp[2];
+        $this->connect = Dever::db('connect/info')->find($connect_id);
+        $this->info = Dever::db('connect/api')->find($api_id);
+        if (!isset($input[$order_key])) {
+            $this->error('error');
+        }
+        $order_id = $input[$order_key];
+        unset($input['t']);
+        $order = Dever::db('seller/order')->find(array('order_num' => $order_id));
+        if (!$order || $order['status'] >= 10) {
+            $this->error('order error');
+        }
+        $this->load($input, $connect_id, $api_id, $order);
+    }
+}

+ 139 - 0
src/dai/seller/app/Api/Order.php

@@ -0,0 +1,139 @@
+<?php namespace Seller\Api;
+use Dever;
+class Order
+{
+    private $info;
+    public function signature()
+    {
+        $token = $this->token();
+        $request = Dever::input();
+        unset($request['l']);
+        $result = \Dever\Helper\Secure::get($request, $token);
+        $string = '';
+        foreach ($result as $k => $v) {
+            $string .= $k . '=' . $v . '&';
+        }
+        $string = rtrim($string, '&');
+        return array('param' => $result, 'string' => $string);
+    }
+
+    # 检测加密是否正确
+    public function check_secure(){}
+    public function check_token(){return $this->token();}
+    public function check()
+    {
+        return 'ok';
+    }
+
+    # 队列提交订单 不做任何数据库操作 先不实现
+    //public function submit_commit(){}
+    //public function submit_secure(){}
+    //public function submit_token(){return $this->token();}
+    public function submit()
+    {
+        # 余额保存在redis中
+        # 商户信息和折扣也保存在redis中
+        # 扣款
+        # 收单
+        # 按照一个商户一个进程去跑,保证单商户单应用
+        return $this->act();
+    }
+
+    # 查询订单
+    public function info_secure(){}
+    public function info_token(){return $this->token();}
+    public function info()
+    {
+        $order_num = Dever::input('order_num');
+        if (!$order_num) {
+            Dever::error('请传入订单号');
+        }
+        $info = Dever::db('seller/order')->find(array('seller_order_num' => $order_num));
+        if (!$info) {
+            Dever::error('订单不存在');
+        }
+        $result['system_order_num'] = $info['order_num'];
+        $result['order_num'] = $info['seller_order_num'];
+        $result['order_status'] = $info['status'];
+        $result['cash'] = $info['cash'];
+        $result['num'] = $info['num'];
+        $result['price'] = $info['price'];
+        $result['cdate'] = date('Y-m-d H:i:s', $info['cdate']);
+        return $result;
+    }
+
+    # 查询账户
+    public function account_secure(){}
+    public function account_token(){return $this->token();}
+    public function account()
+    {
+        $result['name'] = $this->info['name'];
+        $result['yue'] = $this->info['cash'] + $this->info['credit'];
+        $result['cash'] = $this->info['cash'];
+        $result['credit'] = $this->info['credit'];
+        $result['payCash'] = $this->info['p_cash'];
+        return $result;
+    }
+
+    # 直接提交订单
+    private function act()
+    {
+        if (!$this->info) {
+            $this->token();
+        }
+        $code = Dever::input('code');
+        if (!$code) {
+            Dever::error('请传入商品编码');
+        }
+        $account = Dever::input('account');
+        if (!$account) {
+            Dever::error('请传入账号');
+        }
+        $order = Dever::input('order');
+        if (!$order) {
+            Dever::error('请传入订单号');
+        }
+
+        $sku = Dever::db('goods/info_sku')->find(array('code' => $code));
+        if (!$sku) {
+            Dever::error('商品编码不存在');
+        }
+        if ($sku['key'] == -1) {
+            $cash = Dever::input('cash');
+            if (!$cash) {
+                Dever::error('请传入面值');
+            }
+            $sku['value'] = $cash;
+        }
+        $goods = Dever::db('goods/info')->find($sku['info_id']);
+        if (!$goods) {
+            Dever::error('商品不存在');
+        }
+        if ($goods['status'] == 2) {
+            Dever::error('商品已下架');
+        }
+        $num = 1;
+        Dever::load(\Seller\Lib\Order::class)->add($this->info, $goods, $sku, $account, $order, $num);
+        return array
+        (
+            'order_status' => 1,
+        );
+    }
+
+    # 获取token
+    private function token()
+    {
+        $appkey = Dever::input('appkey');
+        if (!$appkey) {
+            Dever::error('appkey错误');
+        }
+        $this->info = Dever::db('seller/info')->find(array('appkey' => $appkey));
+        if (!$this->info) {
+            Dever::error('商户不存在');
+        }
+        if ($this->info && $this->info['status'] == 2) {
+            Dever::error('商户已封禁');
+        }
+        return $this->info['appsecret'];
+    }
+}

+ 232 - 0
src/dai/seller/app/Api/Task.php

@@ -0,0 +1,232 @@
+<?php namespace Seller\Api;
+use Dever;
+use Dever\Helper\Date;
+ini_set("memory_limit", -1);
+class Task
+{
+    # 每日整理订单数据
+    public function order()
+    {
+        # 获取昨天的时间
+        $time = \Dever\Helper\Date::day();
+        $where['status'] = array('>=', 10);
+        $where['cdate'] = array('<', $time[0]);
+        $order = Dever::db('seller/order')->load($where);
+        $cash = [];
+        foreach ($order as $v) {
+            if ($v['finish_date'] > 0) {
+                $id = $v['id'];
+                unset($v['id']);
+                $info = Dever::db('seller/order_record')->find(array('order_num' => $v['order_num']));
+                if (!$info) {
+                    $info = Dever::db('seller/order_record')->insert($v);
+                    if ($info) {
+                        Dever::db('seller/order')->delete($id);
+                        if (empty($cash[$v['seller_id']])) {
+                            $cash[$v['seller_id']] = 0;
+                        }
+                        if ($v['status'] == 10) {
+                            $cash[$v['seller_id']] -= $v['price'];
+                        }
+                    }
+                }
+            }
+        }
+
+        if ($cash) {
+            $day = date('Ymd', $time[0]);
+            foreach ($cash as $k => $v) {
+                Dever::load(\Seller\Lib\Info::class)->log($k, $v, 3, $day);
+            }
+        }
+        $this->yue();
+    }
+
+    # 每小时统计一次正确的商户余额
+    public function yue()
+    {
+        $seller = Dever::db('seller/info')->select(['status' => 1]);
+        if ($seller) {
+            foreach ($seller as $v) {
+                $price = Dever::db('seller/order')->sum(['status' => ['!=', 11]], 'num`*`price');
+                $cash = Dever::db('seller/log')->sum(array('seller_id' => $v['id']), 'cash');
+                $up['cash'] = $cash - $price;
+                Dever::db('seller/info')->update($v['id'], $up);
+            }
+        }
+    }
+
+    # 统计
+    public function stat()
+    {
+        $day = Dever::input('day');
+        if ($day) {
+            $time = \Dever\Helper\Date::day($day);
+        } else {
+            # 获取昨天的时间
+            $time = \Dever\Helper\Date::day(1);
+        }
+        
+        $where['cdate'] = array('>=', $time[0]);
+        $where['cdate#'] = array('<=', $time[1]);
+        $order = Dever::db('seller/order_record')->load($where);
+        $data = array();
+        $default = array
+        (
+            'total_num' => 0,
+            'success_num' => 0,
+            'error_num' => 0,
+            'total_cash' => 0,
+            'success_cash' => 0,
+            'error_cash' => 0,
+            'seller_actual_cash' => 0,
+            'channel_actual_cash' => 0,
+            'profit_cash' => 0,
+            'data' => array(),
+        );
+        foreach ($order as $k => $v) {
+            # 整理这一天成功的和失败的
+            $day = \Dever\Helper\Date::mktime(date('Y-m-d 00:00:00', $v['cdate']));
+            $this->statItem($data, $day, '_1', $default, $v);
+            $this->statItem($data, $day, 'seller_' . $v['seller_id'], $default, $v, $v['channel_id']);
+            if ($v['channel_id']) {
+                $this->statItem($data, $day, 'channel_' . $v['channel_id'], $default, $v, $v['seller_id']);
+            }
+        }
+
+        if ($data) {
+            foreach ($data as $k => $v) {
+                foreach ($v as $k1 => $v1) {
+                    $v1['data'] = Dever::json_encode($v1['data']);
+                    $k1 = explode('_', $k1);
+                    $w = array();
+                    $w['day'] = $k;
+                    $table = 'order_stat';
+                    if ($k1[0]) {
+                        $w[$k1[0] . '_id'] = $k1[1];
+                        $table .= '_' . $k1[0];
+                    }
+                    $info = Dever::db('seller/' . $table)->find($w);
+                    if ($info) {
+                        Dever::db('seller/' . $table)->update($info['id'], $v1);
+                    } else {
+                        $v1 = array_merge($v1, $w);
+                        Dever::db('seller/' . $table)->insert($v1);
+                    }
+                }
+            }
+        }
+    }
+
+    public function statItem(&$data, $day, $mid, $default, $v, $rid = false)
+    {
+        if (!isset($data[$day][$mid])) {
+            $data[$day][$mid] = $default;
+        }
+        if ($rid) {
+            if (!isset($data[$day][$mid]['data'][$rid])) {
+                $data[$day][$mid]['data'][$rid] = $default;
+            }
+        }
+        
+        $data[$day][$mid]['total_num'] += $v['num'];
+        $data[$day][$mid]['total_cash'] += $v['cash'];
+        if ($rid) {
+            $data[$day][$mid]['data'][$rid]['total_num'] += $v['num'];
+            $data[$day][$mid]['data'][$rid]['total_cash'] += $v['cash'];
+        }
+        if ($v['status'] == 10) {
+            $data[$day][$mid]['success_num'] += $v['num'];
+            $data[$day][$mid]['success_cash'] += $v['cash'];
+            $data[$day][$mid]['seller_actual_cash'] += $v['price'];
+            $data[$day][$mid]['channel_actual_cash'] += $v['buy_price'];
+            $data[$day][$mid]['profit_cash'] += ($v['price']-$v['buy_price']);
+            if ($rid) {
+                $data[$day][$mid]['data'][$rid]['success_num'] += $v['num'];
+                $data[$day][$mid]['data'][$rid]['success_cash'] += $v['cash'];
+                $data[$day][$mid]['data'][$rid]['seller_actual_cash'] += $v['price'];
+                $data[$day][$mid]['data'][$rid]['channel_actual_cash'] += $v['buy_price'];
+                $data[$day][$mid]['data'][$rid]['profit_cash'] += ($v['price']-$v['buy_price']);
+            }
+
+        } elseif ($v['status'] == 11) {
+            $data[$day][$mid]['error_num'] += $v['num'];
+            $data[$day][$mid]['error_cash'] += $v['cash'];
+            if ($rid) {
+                $data[$day][$mid]['data'][$rid]['error_num'] += $v['num'];
+                $data[$day][$mid]['data'][$rid]['error_cash'] += $v['cash'];
+            }
+        }
+    }
+
+    # 每5分钟跑一次回调
+    public function callback()
+    {
+        $where['seller_callback'] = 2;
+        $order = Dever::db('seller/order')->load($where);
+        foreach ($order as $v) {
+            $msg = '';
+            if ($v['status'] == 10) {
+                $msg = 'ok';
+            } elseif ($v['status'] == 11) {
+                $msg = 'error';
+            }
+            if ($msg) {
+                Dever::load(\Seller\Lib\Order::class)->notify($v, $msg);
+            }
+        }
+    }
+
+    # 将历史订单迁移到备份中
+    public function bak()
+    {
+        # 迁移2个月前的数据
+        list($start, $end) = Date::month(2);
+        $where['cdate'] = array('<=', $end);
+        $where['status'] = 11;
+        $order = Dever::db('seller/order_history')->load($where);
+        $test = Dever::input('test');
+        if ($order) {
+            foreach ($order as $k => $v) {
+                if ($test == 1) {
+                    $v['cdate_string'] = date('Y-m-d', $v['cdate']);
+                    print_r($v);die;
+                }
+                $id = $v['id'];
+                unset($v['id']);
+                $info = Dever::db('seller/order_bak')->find(array('order_num' => $v['order_num']));
+                //$info = false;
+                if (!$info) {
+                    $info = Dever::db('seller/order_bak')->insert($v);
+                }
+                if ($info) {
+                    Dever::db('seller/order_history')->delete($id);
+                }
+            }
+        }
+    }
+
+    # 定时查询渠道的余额
+    public function channel_yue()
+    {
+        $channel = Dever::db('channel/info')->select(array('type' => 1, 'status' => 1));
+        if ($channel) {
+            foreach ($channel as $k => $v) {
+                if ($v['connect_id'] && $v['host'] && $v['appkey'] && $v['appsecret']) {
+                    $connect = Dever::db('connect/info')->find($v['connect_id']);
+                    if ($connect) {
+                        $api = Dever::db('connect/api')->find(array('type' => 3, 'connect_id' => $connect['id']));
+                        if ($api) {
+                            # 获取余额
+                            $result = Dever::load(\Connect\Lib\Func\Api::class)->run(3, false, $v);
+                            if ($result['status'] == 1 && isset($result['data']['yue'])) {
+                                Dever::db('channel/info')->update($v['id'], array('cash' => $result['data']['yue']));
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        return 'ok';
+    }
+}

+ 48 - 0
src/dai/seller/app/Api/Test.php

@@ -0,0 +1,48 @@
+<?php namespace Seller\Api;
+use Dever;
+use Dever\Helper\Str;
+class Test
+{
+    # 测试商户回调
+    public function callback()
+    {
+        $input = Dever::input();
+        Dever::log($input, 'callback');
+        return 'ok';
+    }
+
+    public function run()
+    {
+        $order = Dever::input('order');
+        $info = Dever::db('seller/order')->find($order);
+        Dever::load(\Seller\Lib\Order::class)->handle($info);
+    }
+
+    # 压力测试
+    public function test()
+    {
+        $code = 'lt10';
+        $info = Dever::db('seller/info')->find(1);
+        $sku = Dever::db('goods/info_sku')->find(array('code' => $code));
+        $goods = Dever::db('goods/info')->find($sku['info_id']);
+        $account = '1' . Str::rand(10, 0);
+        $order = Str::order('T');
+        $num = 1;
+        return Dever::load(\Seller\Lib\Order::class)->add($info, $goods, $sku, $account, $order, $num);
+    }
+
+    # 将当前订单置为失败
+    public function test_no()
+    {
+        while(1) {
+            $order = Dever::db('seller/order')->find(array('seller_id' => 1, 'status' => 2));
+            if ($order) {
+                $msg = 'error';
+                $update = array();
+                $update['official_msg'] = '';
+                $update['official_order_num'] = '';
+                Dever::load(\Seller\Lib\Order::class)->notify($order, $msg, $update);
+            }
+        };
+    }
+}

+ 28 - 0
src/dai/seller/app/Lib/Cron.php

@@ -0,0 +1,28 @@
+<?php namespace Seller\Lib;
+use Dever;
+use Dever\Helper\Redis;
+ini_set("memory_limit", -1);
+class Cron
+{
+    public function run()
+    {
+        while (true) {
+            try {
+                $order = Redis::pop('submit_' . DEVER_PROJECT);
+                if (!$order) {
+                    continue;
+                }
+
+                Dever::request(function () use ($order) {
+                    $info = Dever::db('seller/order')->find($order);
+                    if ($info) {
+                        Dever::load(\Seller\Lib\Order::class)->handle($info);
+                    }
+                });
+            } catch (\Throwable $e) {
+                Dever::log('seller_cron_error', $e->getMessage());
+                usleep(200000);
+            }
+        }
+    }
+}

+ 43 - 0
src/dai/seller/app/Lib/Info.php

@@ -0,0 +1,43 @@
+<?php namespace Seller\Lib;
+use Dever;
+class Info
+{
+    # 余额扣款
+    public function dec_commit(){}
+    public function dec($id, $cash, $version = 0)
+    {
+        $state = Dever::db('seller/info')->update($id, array('cash' => array('-', $cash)), $version);
+        return $state;
+    }
+
+    # 余额加款
+    public function inc_commit(){}
+    public function inc($id, $cash, $version = 0)
+    {
+        $state = Dever::db('seller/info')->update($id, array('cash' => array('+', $cash)), $version);
+        return $state;
+    }
+
+    # 增加日志
+    public function log($seller_id, $cash, $type = 3, $day = false)
+    {
+        $data['seller_id'] = $seller_id;
+        $data['type'] = $type;
+        if ($day) {
+            $data['day'] = $day;
+            $info = Dever::db('seller/log')->find($data);
+            if ($info) {
+                return Dever::db('seller/log')->update($info['id'], ['cash' => $cash]);
+            }
+        }
+        $data['cash'] = $cash;
+        $data['day'] = $day ?: date('Ymd');
+        return Dever::db('seller/log')->insert($data);
+    }
+
+    # 获取余额
+    public function yue($seller_id)
+    {
+
+    }
+}

+ 467 - 0
src/dai/seller/app/Lib/Order.php

@@ -0,0 +1,467 @@
+<?php namespace Seller\Lib;
+use Dever;
+use Dever\Helper\Str;
+use Dever\Helper\Redis;
+class Order
+{
+    # 新增订单 收单
+    public function add($info, $goods, $sku, $account, $order, $num = 1)
+    {
+        $data = $this->addAct($info, $goods, $sku, $account, $order, $num);
+        if ($data) {
+            \Dever\Helper\Redis::push('submit_' . DEVER_PROJECT, $data['id']);
+        }
+        return $data;
+    }
+    public function addAct($info, $goods, $sku, $account, $order, $num = 1)
+    {
+        # 验证规则
+        /*
+        $cate = Dever::db('cate', 'goods')->find($goods['cate_id']);
+        if ($cate && $cate['rule'] && !preg_match($cate['rule'], $account)) {
+            Dever::error($account . '不符合规则');
+        }*/
+        # 验证订单号
+        /*
+        $check = Dever::db('order', 'seller')->find(array('seller_id' => $info['id'], 'seller_order_num' => $order));
+        if ($check) {
+            Dever::error('订单重复');
+        }*/
+
+        $cash = $this->cash($info['id'], $sku['info_id'], $sku['id'], $sku['value'], $num);
+
+        # 开始下单
+        $data = array();
+        $data['status'] = 1;
+        $data['finish'] = 2;
+        $data['account'] = $account;
+        $data['cate_id'] = $goods['cate_id'];
+        $data['goods_id'] = $sku['info_id'];
+        $data['sku_id'] = $sku['id'];
+        $data['num'] = $num;
+        $data['cash'] = $sku['value'];
+        $data['price'] = $cash;
+        $data['seller_id'] = $info['id'];
+        $data['seller_order_num'] = $order;
+        $data['seller_notify'] = Dever::input('notify');
+        $data['id'] = Dever::db('seller/order')->insert($data);
+        if (!$data['id']) {
+            Dever::error('下单失败');
+        }
+
+        $seller['order_id'] = $data['id'];
+        $seller['request'] = json_encode(Dever::input(), JSON_UNESCAPED_UNICODE);
+        Dever::db('seller/order_seller')->insert($seller);
+        return $data;
+    }
+
+    # 扣费
+    public function cash($seller_id, $goods_id, $sku_id, $value, $num = 1)
+    {
+        if (!$value || $value <= 0) {
+            Dever::error('面值无效');
+        }
+        
+        # 查询折扣 扣费
+        $seller_goods = Dever::db('seller/goods')->find(array('seller_id' => $seller_id, 'goods_id' => $goods_id, 'sku_id' => $sku_id));
+        if (!$seller_goods) {
+            $seller_goods = Dever::db('seller/goods')->find(array('seller_id' => $seller_id, 'goods_id' => $goods_id, 'sku_id' => -1));
+        }
+
+        $info = Dever::db('seller/info')->find($seller_id);
+        if ($seller_goods && $seller_goods['discount']) {
+            $info['discount'] = $seller_goods['discount'];
+        }
+        if (!$info['discount']) {
+            $info['discount'] = 1;
+        }
+        $cash = round($value * $info['discount'], 2) * $num;
+
+        # 查询余额是否充足
+        $info['yue'] = $info['credit'] + $info['cash'];
+        if ($info['yue'] < $cash) {
+            Dever::error('余额不足');
+        }
+        $state = Dever::load(Info::class)->dec($info['id'], $cash, $info['version']);
+        if (!$state) {
+            Dever::error('余额不足');
+        }
+        return $cash;
+    }
+
+    # 向渠道发起请求
+    public function handle($info, $selected = array())
+    {
+        $data = $this->handleAct($info, $selected);
+        return $data;
+    }
+
+    public function handleAct($info, $selected = array())
+    {
+        $lockKey = 'seller_order_lock_' . $info['id'];
+        $lockToken = uniqid('order_', true);
+        if (!Redis::lock($lockKey, $lockToken, 5)) {
+            return;
+        }
+        try {
+            $test = Dever::input('test');
+            if ($test == 1) {
+
+            } elseif ($info['status'] >= 10) {
+                return;
+            }
+            $update['status'] = 2;
+            if (!$info['order_num']) {
+                $info['order_num'] = $update['order_num'] = $this->createOrder();
+            }
+            if ($info['seller_callback'] == 1) {
+                $info['seller_callback'] = 2;
+                $update['seller_callback'] = 2;
+            }
+            Dever::db('seller/order')->update($info['id'], $update);
+
+            $channel_num = 0;
+            $channel = $this->channel($info['seller_id'], $info['goods_id'], $info['sku_id'], $channel_num, $selected);
+            if (!$channel) {
+                return $this->notify($info, '通道未开启', $update);
+            }
+            $result = array();
+            if ($channel['type'] == 1) {
+                # 通信
+                # 向渠道发起请求 下单
+                $param['order_id'] = $info['id'];
+                $param['order_num'] = $info['order_num'];
+                $param['account'] = $info['account'];
+                $param['cash'] = $info['cash'];
+                $param['num'] = $info['num'];
+                $param['goods_id'] = $info['goods_id'];
+                if ($info['other']) {
+                    $info['other'] = Dever::json_decode($info['other']);
+                    $param = array_merge($info['other'], $param);
+                }
+                if (isset($channel['goods']['discount']) && $channel['goods']['discount']) {
+                    $param['scash'] = $channel['goods']['discount']*$param['cash'];
+                }
+                if (isset($channel['goods']['code']) && $channel['goods']['code']) {
+                    $param['code'] = $channel['goods']['code'];
+                } else {
+                    $sku = Dever::db('goods/info_sku')->find($info['sku_id']);
+                    $param['code'] = $sku['code'];
+                }
+                $result = Dever::load(\Connect\Lib\Func\Api::class)->run(1, $info['cate_id'], $channel, $param);
+                if ($channel_num > 1 && $result && $result['status'] != 1) {
+                    # 记录渠道错误信息
+                    $selected[$channel['id']] = true;
+                    $order_error_data = Dever::db('seller/order_channel_error')->select(array('order_id' => $info['id']));
+                    if ($order_error_data) {
+                        foreach ($order_error_data as $k => $v) {
+                            $selected[$v['channel_id']] = true;
+                        }
+                    }
+                    $num = count($selected);
+                    $channel_num = $channel_num - $num;
+                    if ($channel_num > 0) {
+                        $order_error = $this->channel_record($info, $channel, $result);
+                        $order_error['order_id'] = $info['id'];
+                        Dever::db('seller/order_channel_error')->insert($order_error);
+                        return $this->handleAct($info, $selected);
+                    }
+                }
+            } elseif ($channel['type'] == 2) {
+            # 需要审核
+            # 获取卡密并占用
+            $param['seller_id'] = array('in', '-1,' . $info['seller_id']);
+            $param['channel_id'] = $channel['id'];
+            $param['goods_id'] = $info['goods_id'];
+            $param['sku_id'] = $info['sku_id'];
+            $param['status'] = 1;
+            $param['use_status'] = 1;
+            $card = Dever::db('channel/card')->select($param, array('order' => 'seller_id desc','limit' => '0, ' . $info['num']), true);
+            $total = count($card);
+            if ($total < $info['num']) {
+                return $this->notify($info, '卡密剩余数量不足', $update);
+            }
+            foreach ($card as $k => $v) {
+                Dever::db('channel/card')->update($v['id'], array('use_status' => 3, 'order_id' => $info['id']));
+            }
+            $result['status'] = 1;
+        } elseif ($channel['type'] == 11) {
+            $result['status'] = 1;
+        }
+        $update = $this->channel_record($info, $channel, $result);
+        if ($result['status'] == 1) {
+            # 下单成功
+            Dever::db('seller/order')->update($info['id'], $update);
+            return 'ok';
+        } else {
+            # 下单失败
+            return $this->notify($info, '下单失败', $update);
+        }
+        } finally {
+            Redis::unlock($lockKey, $lockToken);
+        }
+    }
+
+    # 记录渠道信息
+    public function channel_record($info, $channel, $result)
+    {
+        $update = array();
+        $update['channel_id'] = $channel['id'];
+        $update['order_date'] = time();
+        if (isset($result['request'])) {
+            $update['request'] = json_encode($result['request'], JSON_UNESCAPED_UNICODE);
+        }
+        if (isset($result['response'])) {
+            $update['response'] = json_encode($result['response'], JSON_UNESCAPED_UNICODE);
+        }
+        if (isset($channel['goods']['id'])) {
+            $update['goods_id'] = $channel['goods']['id'];
+        }
+        $update['goods_discount'] = $channel['discount'];
+        if (isset($channel['goods']['discount']) && $channel['goods']['discount']) {
+            $update['goods_discount'] = $channel['goods']['discount'];
+        }
+        if (!$update['goods_discount']) {
+            $update['goods_discount'] = 1;
+        }
+        $update['buy_price'] = round($info['cash'] * $update['goods_discount'], 2) * $info['num'];
+        $update['order_channel_id'] = Dever::db('seller/order_channel')->insert($update);
+        return $update;
+    }
+
+    # 向商户发起回调
+    public function notify($info, $msg, $update = array(), $total = 5, $oper = 1, $table = 'order')
+    {
+        $seller = Dever::db('seller/info')->find($info['seller_id']);
+        $status = 11;
+        if ($msg == 'ok') {
+            $status = 10;
+        }
+        # 获取商户回调地址,向商户发起回调
+        if (isset($info['seller_notify']) && $info['seller_notify']) {
+            $notify = $info['seller_notify'];
+        } else {
+            $notify = $seller['notify'];
+        }
+        $seller_log = [];
+        if ($notify) {
+            if ($info['seller_callback'] == 2 && $info['seller_callback_num'] <= $total) {
+                $param = array();
+                $param['appkey'] = $seller['appkey'];
+                $param['order_num'] = $info['seller_order_num'];
+                $param['system_order_num'] = $info['order_num'];
+                $param['order_status'] = $status;
+                $param['order_cash'] = $info['cash'];
+                $param['official_order_num'] = $param['official_msg'] = '';
+                if (isset($info['official_order_num'])) {
+                    $param['official_order_num'] = $info['official_order_num'];
+                }
+                if (isset($info['official_msg'])) {
+                    $param['official_msg'] = $info['official_msg'];
+                }
+                if (isset($update['official_order_num'])) {
+                    $param['official_order_num'] = $update['official_order_num'];
+                }
+                if (isset($update['official_msg'])) {
+                    $param['official_msg'] = $update['official_msg'];
+                }
+
+                # 反正所有榆钱和沧渤的资源进到系统  流水号只要出我们的系统自动就是89   联通就是10010   电信就是10000(不变的)
+                # 89+8位随机数字+8位订单日期(比如今天就是20240325)+10位随机
+                /*
+                $channel_id = array(5,6,8);
+                if ($status == 10 && in_array($info['channel_id'], $channel_id)) {
+                    $official_order_num = '';
+                    if ($info['goods_id'] == 1) {
+                        # 移动
+                        //$str = '8913807663202404289794416983';
+                        //$str = '8923656675202405029019879800';
+                        $official_order_num = '89' . rand(10000000, 99999999) . date('Ymd') . rand(1000000000, 9999999999);
+                    } elseif ($info['goods_id'] == 2) {
+                        # 联通
+                        $official_order_num = preg_replace('/^11010/i', '10010', $param['official_order_num']);
+                    }
+                    if ($official_order_num) {
+                        $param['official_order_num'] = $update['official_order_num'] = $official_order_num;
+                    }
+                }*/
+                
+
+                $param = \Dever\Helper\Secure::get($param, $seller['appsecret']);
+                $notify = urldecode($notify);
+                $response = Dever::curl($notify, $param, 'post')->result();
+                # ok是成功
+                $seller_log['callback'] = $response;
+                $seller_log['callback_date'] = time();
+                if ($response == 'ok') {
+                    $update['seller_callback'] = 3;
+                } else {
+                    $update['seller_callback'] = 2;
+                }
+                $update['seller_callback_num'] = $info['seller_callback_num'] + 1;
+            }
+        } else {
+            $seller_log['callback'] = 'ok';
+            $seller_log['callback_date'] = time();
+            $update['seller_callback'] = 3;
+            $update['seller_callback_num'] = $info['seller_callback_num'] + 1;
+        }
+        $id = $info['id'];
+        if ($info['status'] < 10 && $status >= 10) {
+            # 订单完成
+            $info['status'] = $update['status'] = $status;
+            $update['finish'] = 1;
+            $update['finish_date'] = time();
+            $info = array_merge($info, $update);
+            $this->finish($info, $oper, $table);
+        }
+        if (!$info['order_num']) {
+            $update['order_num'] = $this->createOrder();
+        }
+        if ($update) {
+            Dever::db('seller/' . $table)->update($id, $update);
+        }
+        if ($seller_log) {
+            Dever::db('seller/order_seller')->update(['order_id' => $id], $seller_log);
+        }
+
+        if (isset($update['channel_callback']) && $update['channel_callback']) {
+            Dever::db('seller/order_channel')->update(['id' => $update['order_channel_id']], ['callback' => $update['channel_callback'], 'callback_date' => $update['channel_callback_date']]);
+        }
+        
+        return $msg;
+    }
+
+    public function finish($info, $oper = 1, $table = 'order')
+    {
+        if ($info['status'] == 10) {
+            if ($info['channel_id']) {
+                $channel = Dever::db('channel/info')->find($info['channel_id']);
+                if (!$channel) {
+                    Dever::error('未分配渠道');
+                }
+                if ($channel['type'] == 2) {
+                    # 审核通过
+                    $param['order_id'] = $info['id'];
+                    //$param['status'] = 1;
+                    $param['use_status'] = 3;
+                    Dever::db('channel/card')->update($param, array('use_status' => 2));
+                }
+            }
+        }
+        if ($info['status'] == 11) {
+            if ($info['channel_id']) {
+                $channel = Dever::db('channel/info')->find($info['channel_id']);
+                if (!$channel) {
+                    Dever::error('未分配渠道');
+                }
+                if ($channel['type'] == 2) {
+                    # 审核失败
+                    $param['order_id'] = $info['id'];
+                    //$param['status'] = 1;
+                    $param['use_status'] = 3;
+                    Dever::db('channel/card')->update($param, array('use_status' => 1));
+                }
+            }
+
+            if ($oper == 2) {
+                $channel_num = Dever::db('seller/channel')->count(array('seller_id' => $info['seller_id'], 'goods_id' => $info['goods_id'], 'status' => 1));
+                if ($channel_num > 1 && $info['channel_id']) {
+                    $info['status'] = 2;
+                    Dever::db('seller/' . $table)->update($info['id'], array('status' => 2, 'finish' => 2, 'finish_date' => '0'));
+                    # 记录渠道错误信息
+                    $selected = array();
+                    $selected[$info['channel_id']] = true;
+                    $order_error_data = Dever::db('seller/order_channel_error')->select(array('order_id' => $info['id']));
+                    if ($order_error_data) {
+                        foreach ($order_error_data as $k => $v) {
+                            $selected[$v['channel_id']] = true;
+                        }
+                    }
+                    $num = count($selected);
+                    $channel_num = $channel_num - $num;
+                    if ($channel_num > 0) {
+                        $order_error = array();
+                        $order_error['order_id'] = $info['id'];
+                        $order_error['order_channel_id'] = $info['order_channel_id'];
+                        $order_error['channel_id'] = $info['channel_id'];
+                        Dever::db('seller/order_channel_error')->insert($order_error);
+                        return $this->handleAct($info, $selected);
+                    }
+                }
+            }
+            
+            # 失败,余额加回来
+            Dever::load(Info::class)->inc($info['seller_id'], $info['price'], 1);
+        }
+    }
+
+    # 获取渠道
+    public function channel($seller_id, $goods_id, $sku_id, &$channel_num, $selected = array())
+    {
+        # 查找渠道
+        $channel_list = Dever::db('seller/channel')->select(array('seller_id' => $seller_id, 'goods_id' => $goods_id, 'status' => 1));
+        if (!$channel_list) {
+            return false;
+        }
+        $channel_num = count($channel_list);
+        $max = 1;
+        $channel = $goods = array();
+        foreach ($channel_list as $k => $v) {
+            if ($selected && isset($selected[$v['channel_id']])) {
+                continue;
+            }
+            if (!$v['sku_id']) {
+                $goods = Dever::db('channel/goods')->find(array('channel_id' => $v['channel_id'], 'goods_id' => $goods_id, 'sku_id' => $sku_id));
+                if ($goods) {
+                    $channel = $v['channel_id'];
+                    $max = $v['max'];
+                    break;
+                } else {
+                    $goods = Dever::db('channel/goods')->find(array('channel_id' => $v['channel_id'], 'goods_id' => $goods_id, 'sku_id' => -1));
+                    if ($goods) {
+                        $channel = $v['channel_id'];
+                        $max = $v['max'];
+                        break;
+                    }
+                }
+            } else {
+                $all_sku_id = explode(',', $v['sku_id']);
+                if (in_array($sku_id, $all_sku_id)) {
+                    $channel = $v['channel_id'];
+                    $max = $v['max'];
+                    $goods = Dever::db('channel/goods')->find(array('channel_id' => $v['channel_id'], 'goods_id' => $goods_id, 'sku_id' => $sku_id));
+                    if (!$goods) {
+                        $goods = Dever::db('channel/goods')->find(array('channel_id' => $v['channel_id'], 'goods_id' => $goods_id, 'sku_id' => -1));
+                    }
+                    break;
+                }
+            }
+        }
+        if (!$channel) {
+            return false;
+        }
+
+        $channel = Dever::db('channel/info')->find($channel);
+        if (!$channel) {
+            return false;
+        }
+        if ($channel['status'] == 2) {
+            return false;
+        }
+        $channel['goods'] = $goods;
+        $channel['max'] = $max;
+        return $channel;
+    }
+
+    public function createOrder()
+    {
+        $where['order_num'] = Str::order('C');
+        $state = Dever::db('seller/order')->find($where);
+        if (!$state) {
+            return $where['order_num'];
+        } else {
+            return $this->createOrder();
+        }
+    }
+}