<?php
/**
 * 易优CMS
 * ============================================================================
 * 版权所有 2016-2028 海口快推科技有限公司，并保留所有权利。
 * 网站地址: http://www.eyoucms.com
 * ----------------------------------------------------------------------------
 * 如果商业用途务必到官方购买正版授权, 以免引起不必要的法律纠纷.
 * ============================================================================
 * Author: 陈风任 <491085389@qq.com>
 * Date: 2020-05-07
 */

namespace app\plugins\model;

use think\Db;
use think\Cache;
use think\Config;

/**
 * 小程序商城 秒杀订单模型
 */
load_trait('controller/Jump');

class SeckillDiyminiproMallUser extends DiyminiproMallUserBase
{
    use \traits\controller\Jump;

    private $miniproInfo = [];

    //初始化
    protected function initialize()
    {
        // 需要调用`Model`的`initialize`方法
        parent::initialize();
        $this->miniproInfo = model('DiyminiproMall')->detail();
    }

    // 判断秒杀商品库存
    public function IsSaledOut($post = [])
    {
        if (!empty($post['product_id'])) {
            if (!empty($post['spec_value_id'])) {
                $SpecWhere = [
                    'aid' => $post['product_id'],
                    'goods_id' => $post['goods_id'],
                    'spec_value_id' => $post['spec_value_id']
                ];

                $spec_stock = Db::name('weapp_seckill_product_spec_value')->where($SpecWhere)->value('seckill_stock');
                $oriSpecWhere = [
                    'aid' => $post['product_id'],
                    'spec_value_id' => $post['spec_value_id']
                ];

                $ori_spec_stock = Db::name('product_spec_value')->where($oriSpecWhere)->value('spec_stock');
                if ($spec_stock > $ori_spec_stock) $spec_stock = $ori_spec_stock;
                if (empty($spec_stock)) {
                    $this->error('商品已售罄！');
                }
                if ($spec_stock < $post['product_num']) {
                    $this->error('商品最大库存：' . $spec_stock);
                }
            } else {
                $secWhere = [
                    'aid' => $post['product_id'],
                    'goods_id' => $post['goods_id'],
                ];
                $stock_count = Db::name('weapp_seckill_archives')->where($secWhere)->value('stock');

                $ArchivesWhere = [
                    'aid'     => $post['product_id'],
                    'lang'    => get_home_lang(),
                    'arcrank' => ['>=', 0]
                ];
                $ori_stock_count   = Db::name('archives')->where($ArchivesWhere)->getField('stock_count');
                if ($stock_count > $ori_stock_count) $stock_count = $ori_stock_count;
                if (empty($stock_count)) {
                    $this->error('商品已售罄！');
                }
                if ($stock_count < $post['product_num']) {
                    $this->error('商品最大库存：' . $stock_count);
                }
            }
        }
    }

    //限购
    public function LimitBuy($post = [],$users = [])
    {
        $act_id = Db::name('weapp_seckill_archives')->where('goods_id',$post['goods_id'])->value('act_id');
        $act = Db::name('weapp_seckill')->where('id',$act_id)->find();
        empty($act) && $this->error('秒杀活动不存在！');

        $where['b.users_id'] = $users['users_id'];
        $where['b.is_seckill_order'] = $act_id;
        $where['b.order_status'] = ['in',[1,2,3]];
        $today_msg = "";
        if (1 == $act['is_limit']){
            $sum = Db::name('shop_order_details')->alias('a')
                ->join('shop_order b','a.order_id = b.order_id')
                ->where($where)
                ->sum('a.num');
        }else if (2 == $act['is_limit']){
            $today = date('Y-m-d');
            $today = strtotime($today);
            $where['b.pay_time'] = ['>=',$today];
            $sum = Db::name('shop_order_details')->alias('a')
                ->join('shop_order b','a.order_id = b.order_id')
                ->where($where)
                ->sum('a.num');
            $today_msg = "每日";
        }

        if (1 == $act['is_limit'] || 2 == $act['is_limit']){
            if ($act['limit'] <= $sum){
                $this->error("商品{$today_msg}限购{$act['limit']}件,您购买已达数量！");
            }
            if($act['limit'] < ($sum + $post['product_num'])){
                $post['product_num'] = $act['limit'] - $sum;
                $this->error("商品{$today_msg}限购{$act['limit']}件,您最多还可购买{$post['product_num']}件！");
            }
        }
    }

    // 立即购买
    public function ShopBuyNow($post = [])
    {
        // 查询条件
        $ArchivesWhere = [
            'aid' => $post['product_id'],
//            'goods_id'      => $post['goods_id'],
            'lang' => get_home_lang(),
            'arcrank' => ['>=', 0]
        ];
        $count = Db::name('archives')->where($ArchivesWhere)->count();

        if (!empty($count)) {
            // 对ID和订单号加密，拼装url路径
            $querydata = [
                'product_id' => $post['product_id'],
                'goods_id' => $post['goods_id'],
                'product_num' => $post['product_num']
            ];

            //存在规格则执行
            if (!empty($post['spec_value_id']) && 'undefined' != $post['spec_value_id']) {
                $querydata['spec_value_id'] = $post['spec_value_id'];
            }

            // 先 json_encode 后 md5 加密信息
            $querystr = md5(json_encode($querydata));

            // 存入缓存，一天有效期
            Cache::set($querystr, $querydata, 86400);

            // 跳转链接
            if (1 == input('param.fenbao/d')) {
                $url = '?querystr=' . $querystr;
            } else {
                $url = '/pages/seckill/product_buy/index?querystr=' . $querystr;
            }
            $this->success('数据正确', $url, ['querystr'=>$querystr, 'url'=>$url]);
        } else {
            $this->error('该商品不存在或已下架！');
        }
    }

    // 获取商品信息进行展示
    public function GetProductData($querystr = null, $users = [])
    {
        if (empty($users['users_id'])) $this->error('请先登录');
        $users_id = $users['users_id'];

        /* 商品信息 */
        $CacheData = Cache::get($querystr);

        // 是否存在购买商品
        $list = $this->GetBuyOrderList($CacheData, $users_id);
        if (empty($list)) $this->error('链接失效，请重新下单');

        // 获取商城配置信息
        $ConfigData = getUsersConfigData('shop');

        /* 商品规格/折扣数据处理 */
        $list = $this->OrderProductProcess($list, $ConfigData);

        if (empty($list)) $this->error('商品库存不足或已过期！');
        /* END */

        /* 全局信息组装 */
        $GlobalInfo = $this->GetGlobalInfo($ConfigData, $CacheData);
        /* END */

        /* 商品数据整合处理 */
        foreach ($list as $key => $value) {
            /* 合计金额、合计数量计算 */
            if ($value['users_price'] >= 0 && !empty($value['product_num'])) {
                // 计算单品小计
                $list[$key]['subtotal'] = sprintf("%.2f", $value['users_price'] * $value['product_num']);
                // 计算合计金额
                $GlobalInfo['TotalAmount'] += $list[$key]['subtotal'];
                $GlobalInfo['TotalAmount'] = sprintf("%.2f", $GlobalInfo['TotalAmount']);
                // 计算合计数量
                $GlobalInfo['TotalNumber'] += $value['product_num'];
                // 判断订单类型，目前逻辑：一个订单中，只要存在一个普通商品(实物商品，需要发货物流)，则为普通订单
                // 0表示为普通订单，1表示为虚拟订单，虚拟订单无需发货物流，无需选择收货地址，无需计算运费
                if (empty($value['prom_type'])) $GlobalInfo['PromType'] = 0;
            }
            /* END */

            /* 规格处理 */
            $list[$key]['product_spec'] = '';
            if (!empty($value['spec_value_id'])) {
                $spec_value_id = explode('_', $value['spec_value_id']);
                if (!empty($spec_value_id)) {
                    $SpecWhere = [
                        'aid' => $value['product_id'],
                        'lang' => get_home_lang(),
                        'spec_value_id' => ['IN', $spec_value_id]
                    ];
                    $ProductSpecData = Db::name("product_spec_data")->where($SpecWhere)->field('spec_name, spec_value')->select();
                    foreach ($ProductSpecData as $spec_value) {
//                        $list[$key]['product_spec'] .= $spec_value['spec_name'] . '：' . $spec_value['spec_value'] . '；';
                        $list[$key]['product_spec'] .= $spec_value['spec_value'] . '；';
                    }
                }
            }
            /* END */

            // 仅到店核销
            if ('2' === $value['logistics_type']) $GlobalInfo['onlyVerify'] = true;
            // 仅物流配送
            if ('1' === $value['logistics_type']) $GlobalInfo['onlyDelivery'] = true;
            // 物流配送 和 到店核销 都支持
            if ('1,2' === $value['logistics_type']) $GlobalInfo['allLogisticsType'] = true;
        }
        /* END */

        /* 默认地址 */
        $address = Db::name('shop_address')->where('users_id', $users_id)->order('is_default desc')->find();
        if (!empty($address)) {
            $address['region']['province'] = $this->GetRegionName($address['province']);
            $address['region']['city'] = $this->GetRegionName($address['city']);
            $address['region']['district'] = $this->GetRegionName($address['district']);
            $address['region']['detail'] = $address['address'];
            $address['address_all'] = $address['region']['province'] . $address['region']['city'] . $address['region']['district'] . $address['region']['detail'];

            $shop_open_shipping = getUsersConfigData('shop.shop_open_shipping');
            if (!empty($shop_open_shipping)) {
                /* 查询运费 */
                $where['province_id'] = $address['province'];
                $template_money = Db::name('shop_shipping_template')->where($where)->getField('template_money');
                if (0 == $template_money) {
                    $where['province_id'] = 100000;
                    $template_money = Db::name('shop_shipping_template')->where($where)->getField('template_money');
                }
                $address['template_money'] = $template_money;
                /* END */
            } else {
                $address['template_money'] = 0;
            }
        } else {
            $address['template_money'] = 0;
        }
        /* END */

        // 最终支付总金额
        if (!empty($post['deliveryShow']) && 1 === intval($post['deliveryShow'])) {
            // 订单总金额 + 运费金额
            $GlobalInfo['PayTotalAmount'] = unifyPriceHandle($GlobalInfo['TotalAmount'] + $address['template_money']);
        } else {
            $GlobalInfo['PayTotalAmount'] = unifyPriceHandle($GlobalInfo['TotalAmount']);
        }

        // 数据返回
        $ResultData = [
            'users' => $users,
            'address' => $address,
            'global_info' => $GlobalInfo,
            'product_data' => $list
        ];
 //     $ResultData['coupon_data'] = $this->getOrderCoupon($list,$users_id);
        $ResultData['conf']['pay_balance_open'] = (int)getUsersConfigData('pay.pay_balance_open');
        // $ResultData['conf']['pay_balance_open'] = 0;


        $this->success('数据正确', null, $ResultData);
    }
    // 获取下单的商品数据
    private function GetBuyOrderList($CacheData = [], $users_id = null)
    {
        $list = [];
        //判断是否还在秒杀时间内
        $seckill_arc = Db::name('weapp_seckill_archives')->where('goods_id',$CacheData['goods_id'])->find();
        if (empty($seckill_arc)) $this->error('秒杀商品不存在!');
        $act_id = $seckill_arc['act_id'];

        $seckill = Db::name('weapp_seckill')->where('id',$act_id)->find();
        if (empty($seckill)) $this->error('秒杀活动不存在!');
        if (empty($seckill['in_progress'])) $this->error('秒杀活动未开启!');
        if (1 !== $seckill['status']) $this->error('秒杀活动未开启!');
        if (getTime() > $seckill['end_time']) $this->error('秒杀活动已结束!');

        // 立即购买下单
        $where['a.aid'] = $CacheData['product_id'];
        if (!empty($CacheData['spec_value_id'])){
            $where['b.goods_id'] = $CacheData['goods_id'];
            //多规格
            $where['b.spec_value_id'] = $CacheData['spec_value_id'];
            $field = 'a.aid, a.typeid, a.title, a.litpic, a.users_price, a.stock_count, a.prom_type, a.attrlist_id, a.logistics_type, b.value_id, b.aid as product_id, b.spec_value_id,b.seckill_price, b.seckill_stock';

            $list = Db::name('archives')->alias('a')->field($field)
                ->join('weapp_seckill_product_spec_value b', 'a.aid = b.aid', 'LEFT')
                ->where($where)
                ->find();
            $spec_stock = Db::name('product_spec_value')->where(['aid'=>$CacheData['product_id'],'spec_value_id'=>$CacheData['spec_value_id']])->value('spec_stock');
            //秒杀库存不能大于商品库存
            if ($list['seckill_stock'] > $spec_stock) $list['seckill_stock'] = $spec_stock;
        }else{
            //单规格
            $list = Db::name('archives')->alias('a')->field('a.aid, a.typeid, a.title, a.litpic, a.users_price, a.stock_count, a.prom_type, a.attrlist_id, a.logistics_type')
                ->where($where)
                ->find();
            $list['product_id'] = $seckill_arc['aid'];
        }

        $list['product_num'] = $CacheData['product_num'];

        //判断该秒杀商品是多规格还是单规格
        if (empty($seckill_arc['is_spec'])) {
            //单规格
            $list['users_price'] = $list['seckill_price'] = $seckill_arc['seckill_price'];
            //秒杀库存不能大于商品库存
            if ($seckill_arc['seckill_stock'] > $list['stock_count']){
                $list['seckill_stock'] = $seckill_arc['seckill_stock'] = $list['stock_count'];
            }else{
                $list['stock_count'] = $list['seckill_stock'] = $seckill_arc['seckill_stock'];
            }
        }

        return $list;
    }

    // 商品规格/折扣数据处理
    private function OrderProductProcess($arc_data = [], $ConfigData = [])
    {
        $list[] = $arc_data;
        foreach ($list as $key => $value) {
            /* 规格处理 */
            $list[$key]['product_spec'] = [];
            if (!empty($value['spec_value_id'])) {
                $spec_value_id = explode('_', $value['spec_value_id']);
                if (!empty($spec_value_id)) {
                    $SpecWhere = [
                        'aid' => $value['aid'],
                        'lang' => get_home_lang(),
                        'spec_value_id' => ['IN', $spec_value_id]
                    ];
                    $ProductSpecData = Db::name("product_spec_data")->where($SpecWhere)->field('spec_name, spec_value')->select();
                    foreach ($ProductSpecData as $spec_value) {
                        $list[$key]['product_spec'][] = $spec_value['spec_value'];
                    }
                }
            }
            /* END */

            /* 未开启多规格则执行 */
            if (!isset($ConfigData['shop_open_spec']) || empty($ConfigData['shop_open_spec'])) {
                $value['spec_value_id'] = $value['seckill_price'] = $value['seckill_stock'] = 0;
                $list[$key]['spec_value_id'] = $list[$key]['seckill_price'] = $list[$key]['seckill_stock'] = 0;
            }
            /* END */

            /* 商品存在规格且价格不为空，则覆盖商品原来的价格 */
            if (!empty($value['spec_value_id']) && 'undefined' != $value['spec_value_id'] && $value['seckill_price'] >= 0) {
                // 规格价格覆盖商品原价
                $list[$key]['users_price'] = $value['users_price'] = $value['seckill_price'];
            }

            // 商品原价
            $list[$key]['old_price'] = sprintf("%.2f", $list[$key]['users_price']);

            /* 商品存在规格且库存不为空，则覆盖商品原来的库存 */
            if (!empty($value['seckill_stock'])) {
                // 规格库存覆盖商品库存
                $list[$key]['stock_count'] = $value['stock_count'] = $value['seckill_stock'];
            }
            if ($value['product_num'] > $value['stock_count']) {
                // 购买数量超过最大库存量则默认购买最大库存量
                $list[$key]['stock_count'] = $list[$key]['product_num'] = $value['stock_count'];
            }
            /* END */

            // 图片处理
            $list[$key]['litpic'] = $this->get_default_pic($value['litpic'], true);

            /* 若库存为空则清除这条数据 */
            if (empty($value['stock_count'])) {
                unset($list[$key]);
                continue;
            }
            /* END */
        }

        return $list;
    }

    // 组装订单流程所需全局信息
    private function GetGlobalInfo($ConfigData = [], $CacheData = [])
    {
        $GlobalInfo = [
            // 温馨提示内容,为空则不展示
            'shop_prompt' => !empty($ConfigData['shop_prompt']) ? $ConfigData['shop_prompt'] : '',
            // 是否开启线下支付(货到付款)
            'shop_open_offline' => !empty($ConfigData['shop_open_offline']) ? $ConfigData['shop_open_offline'] : 0,
            // 是否开启运费设置
            'shop_open_shipping' => !empty($ConfigData['shop_open_shipping']) ? $ConfigData['shop_open_shipping'] : 0,
            // 初始化支付总额
            'TotalAmount' => 0,
            // 初始化支付总额，包含运费
            'PayTotalAmount' => 0,
            // 初始化总数
            'TotalNumber' => 0,
            // 提交来源:0购物车;1直接下单
            'submit_order_type' => !empty($CacheData) ? 1 : 0,
            // 1表示为虚拟订单
            'PromType' => 1,
            // 虚拟订单文案
            'virtual_text1' => '1、该产品为虚拟产品，仅支持在线支付且无需选择收货地址及运费计算。',
            'virtual_text2' => '2、若产品是充值类产品，请将您的手机号或需充值的卡号填入留言中。',
            // 仅到店核销
            'onlyVerify'         => false,
            // 仅物流配送
            'onlyDelivery'       => false,
            // 物流支持
            'allLogisticsType'   => false,
        ];

        return $GlobalInfo;
    }

    // 订单结算
    public function ShopOrderPay($post = [], $usersData = [])
    {
        // 基础判断
        if (empty($post['users_id'])) $this->error('请先登录');
        if (0 == $post['prom_type'] && 1 == $post['deliveryShow']){
            if (empty($post['addr_id']) || $post['addr_id'] == 'undefined') $this->error('请添加收货地址');
        }
        if (empty($post['pay_type'])) $this->error('请选择支付方式');

        // 获取商城配置信息
        $ConfigData = getUsersConfigData('all');

        // 获取下单的商品数据
        $CacheData = Cache::get($post['querystr']);
        $list = $this->GetBuyOrderList($CacheData, $post['users_id']);
        if (empty($list)) $this->error('链接失效，请重新下单');

        // 订单商品数据处理
        $list = $this->OrderProductProcess($list, $ConfigData);
        if (empty($list)) $this->error('商品库存不足或已过期');

        // 组装订单流程所需全局信息
        $GlobalInfo = $this->GetGlobalInfo($ConfigData, $CacheData);

        /* 商品数据整合处理 */
        foreach ($list as $key => $value) {
            /* 合计金额、合计数量计算 */
            if ($value['users_price'] >= 0 && !empty($value['product_num'])) {
                // 计算合计金额
                $GlobalInfo['TotalAmount'] += sprintf("%.2f", $value['users_price'] * $value['product_num']);
                $GlobalInfo['TotalAmount'] = sprintf("%.2f", $GlobalInfo['TotalAmount']);
                // 计算合计数量
                $GlobalInfo['TotalNumber'] += $value['product_num'];
                // 判断订单类型，目前逻辑：一个订单中，只要存在一个普通商品(实物商品，需要发货物流)，则为普通订单
                // 0表示为普通订单，1表示为虚拟订单，虚拟订单无需发货物流，无需选择收货地址，无需计算运费
                if (empty($value['prom_type'])) $GlobalInfo['PromType'] = 0;
            }
            /* END */
        }
        /* END */

        // 获取用户下单时提交的收货地址及运费
        $AddrData = $this->GetUsersAddrData($post, $GlobalInfo['PromType']);
        if (!empty($post['verifyShow'])) $AddrData['shipping_fee'] = 0;

        // 订单总金额 + 运费金额
        $GlobalInfo['PayTotalAmount'] = sprintf("%.2f", $GlobalInfo['TotalAmount'] + $AddrData['shipping_fee']);

        //应付总金额
        $PayAmount = $GlobalInfo['PayTotalAmount'];

        if (2 == $post['pay_type']) {
            $UsersMoney = Db::name('users')->where('users_id', $post['users_id'])->getField('users_money');
            if ($GlobalInfo['PayTotalAmount'] > $UsersMoney) $this->error('您的余额不足，支付失败');
        }

        $act_id = Db::name('weapp_seckill_archives')->where('goods_id',$CacheData['goods_id'])->value('act_id');

        // 添加到订单主表
        $time = getTime();
        $OrderData = [
            'order_code' => date('Ymd') . $time . rand(10, 100),
            'users_id' => $post['users_id'],
            'order_status' => 0, // 订单未付款
            'add_time' => $time,
            'payment_method' => 0,
            'pay_time' => 0,
            'pay_name' => 'wechat',
            'wechat_pay_type' => 'WeChatInternal',
            'order_terminal' => 3,
            'pay_details' => '',
            'order_total_amount' => $GlobalInfo['PayTotalAmount'],
            'order_amount' => $PayAmount,
            'order_total_num' => $GlobalInfo['TotalNumber'],
            'prom_type' => $GlobalInfo['PromType'],
            'order_source' => isset($post['order_source']) ? $post['order_source'] : 10,
            'order_source_id' => isset($post['order_source_id']) ? $post['order_source_id'] : 0,
            'virtual_delivery' => '',
            'admin_note' => '',
            'user_note' => $post['remark'],
            'is_seckill_order' => $act_id, //秒杀插件订单写入活动id
            'logistics_type'     => !empty($post['deliveryShow']) ? 1 : 2,
            'lang' => get_home_lang()
        ];

        // 存在收货地址则追加合并到主表数组
        if (!empty($AddrData)) $OrderData = array_merge($OrderData, $AddrData);

        // 订单提交处理 -- 其他逻辑公共调用方法，部分逻辑改动不适合直接修改原文件时请在此方法做处理和兼容
        $OrderData = model('ShopPublicHandle')->orderSubmitPublicHandle($OrderData, $ConfigData, $this->users_id, $post, $list);

        // 添加订单及后续处理
        $OrderId = Db::name('shop_order')->add($OrderData);
        if (!empty($OrderId)) {
            $OrderData['order_id'] = $OrderId;

            $cart_ids = $UpSpecValue = [];
            $contains_virtual = 1;//是否包含虚拟产品
            foreach ($list as $key => $value) {
                $attr_value = $attr_value_new = $spec_value = '';

                // 旧商品属性处理
                $attr_value = $this->ProductAttrProcessing($value);
                // 新商品属性处理
                $attr_value_new = $this->ProductNewAttrProcessing($value);
                // 商品规格处理
                $spec_value = $this->ProductSpecProcessing($value);

                // 规格及属性
                $ParamData = [
                    // 商品属性
                    'attr_value' => htmlspecialchars($attr_value),
                    // 商品属性
                    'attr_value_new' => htmlspecialchars($attr_value_new),
                    // 商品规格
                    'spec_value' => htmlspecialchars($spec_value),
                    // 商品规格值ID
                    'spec_value_id' => $value['spec_value_id'],
                    // 对应规格值ID的唯一标识ID，数据表主键ID
                    'value_id' => $value['value_id'],
                    'goods_id' => $CacheData['goods_id'],
                ];

                // 订单副表添加数组
                $OrderDetailsData[] = [
                    'order_id' => $OrderId,
                    'users_id' => $post['users_id'],
                    'product_id' => $value['aid'],
                    'product_name' => $value['title'],
                    'num' => $value['product_num'],
                    'data' => serialize($ParamData),
                    'product_price' => $value['users_price'],
                    'prom_type' => $value['prom_type'],
                    'litpic' => $value['litpic'],
                    'add_time' => $time,
                    'lang' => get_home_lang()
                ];

                // 处理购物车ID
                if (empty($GlobalInfo['submit_order_type'])) {
                    array_push($cart_ids, $value['cart_id']);
                }

                // 商品库存处理
                $UpSpecValue[] = [
                    'aid' => $value['aid'],
                    'goods_id' => $CacheData['goods_id'],
                    'value_id' => $value['value_id'],
                    'quantity' => $value['product_num'],
                    'spec_value_id' => $value['spec_value_id'],
                    'order_source' => isset($post['order_source']) ? $post['order_source'] : 10,
                    'order_source_id' => isset($post['order_source_id']) ? $post['order_source_id'] : 0,
                ];

                if (in_array($value['prom_type'], [1, 2, 3])) {
                    $contains_virtual = 2;
                }
            }
            if (2 == $contains_virtual) {
                Db::name('shop_order')->where('order_id', $OrderId)->update(['contains_virtual' => $contains_virtual]);
            }

            $DetailsId = Db::name('shop_order_details')->insertAll($OrderDetailsData);
            if (!empty($OrderId) && !empty($DetailsId)) {
                // 商品库存、销量处理
                $this->ProductStockProcessing($UpSpecValue);

                // 添加订单操作记录
                AddOrderAction($OrderId, $post['users_id']);

                // 微信支付
                if (1 == $post['pay_type']) {
                    $Data = $this->GetWechatAppletsPay($post['openid'], $OrderData['order_code'], $OrderData['order_amount']);
                    $ResultData = [
                        'WeChatPay' => $Data,
                        'OrderData' => [
                            'order_id' => $OrderId,
                            'order_code' => $OrderData['order_code']
                        ]
                    ];
                    // 已开启的微信订阅消息模板
//                    $where = [
//                        'is_open' => 1,
//                        'send_scene' => ['IN', [7]],
//                        'template_code' => ['GT', 0],
//                    ];
//                    $tmplData = Db::name('applets_template')->where($where)->order('send_scene asc')->getAllWithIndex('template_id');
//                    $ResultData['tmplData'] = $tmplData;
                    $ResultData['tmplData'] = [];
                    // 返回提示
                    $this->success('正在支付', null, $ResultData);
                } // 余额支付
                else if (2 == $post['pay_type']) {
                    $pay_details = [
                        'unified_id' => $OrderId,
                        'unified_number' => $OrderData['order_code'],
                        'payment_amount' => $OrderData['order_amount'],
                        'payment_type' => '余额支付'
                    ];
                    $UpOrderData = [
                        'order_status' => 1,
                        'pay_name' => 'balance',
                        'wechat_pay_type' => '',
                        'pay_details' => serialize($pay_details),
                        'pay_time' => getTime(),
                        'update_time' => getTime()
                    ];
                    $ReturnID = Db::name('shop_order')->where('order_id', $OrderId)->update($UpOrderData);
                    if (!empty($ReturnID)) {
                        $UsersData = [
                            'users_money' => $UsersMoney - $OrderData['order_amount'],
                            'update_time' => getTime()
                        ];
                        $users_id = Db::name('users')->where('users_id', $post['users_id'])->update($UsersData);
                        if (!empty($users_id)) {
                            // 添加会员余额记录
                            $getParam = [
                                'users_money' => $UsersMoney,
                                'users_id' => $post['users_id']
                            ];
                            UsersMoneyAction($OrderData['order_code'], $getParam, $OrderData['order_amount'], '订单支付');

                            // 添加订单操作记录
                            AddOrderAction($OrderId, $post['users_id'], 0, 1, 0, 1, '支付成功！', '会员使用余额完成支付！');

                            // 虚拟自动发货
                            $ShopModel = new \app\user\model\Pay();
                            $Where = [
                                'lang' => get_home_lang(),
                                'users_id' => $post['users_id'],
                                'order_id' => $OrderId
                            ];
                            $ShopModel->afterVirtualProductPay($Where);

                            // 统计销售额
                            eyou_statistics_data(2);
                            eyou_statistics_data(3, $OrderData['order_amount']);

                            // 订单支付通知
//                            $params = [
//                                'users_id' => $post['users_id'],
//                                'result_id' => $OrderId,
//                            ];
//                            eyou_send_notice(9, $params);
//
//                            // 已开启的微信订阅消息模板
//                            $where = [
//                                'is_open' => 1,
//                                'send_scene' => ['IN', [7]],
//                                'template_code' => ['GT', 0],
//                            ];
//                            $tmplData = Db::name('applets_template')->where($where)->order('send_scene asc')->getAllWithIndex('template_id');
//                            $result['tmplData'] = $tmplData;
                            $result['tmplData'] = [];

                            // 邮箱发送
                            $result['email'] = GetEamilSendData(tpCache('smtp'), $usersData, $OrderData, 1, 'balance');

                            // 短信发送
                            $result['mobile'] = GetMobileSendData(tpCache('sms'), $usersData, $OrderData, 1, 'balance');

                            // 发送站内信给后台
                            $OrderData['pay_method'] = '余额支付';
                            SendNotifyMessage($OrderData, 5, 1, 0);

                            // 返回数据
                            $result['OrderData'] = $OrderData;
                            $this->success('支付完成', '/pages/order/index', $result);
                        }
                    }
                }
            } else if (!empty($OrderId) && empty($DetailsId)) {
                // 订单详情添加失败则删除已添加的订单主表数据
                Db::name('shop_order')->delete($OrderId);
                $this->error('订单生成失败，商品数据有误！');
            }
        }
        $this->error('订单生成失败，商品数据有误！');
    }


    // 微信小程序支付后续处理
    public function WechatAppletsPayDealWith($PostData = [], $notify = false)
    {
        $OpenID = !empty($PostData['openid']) ? $PostData['openid'] : '';
        $UsersID = !empty($PostData['users_id']) ? $PostData['users_id'] : '';
        $OrderID = $PostData['order_id'];
        $OrderCode = $PostData['order_code'];

        if (!empty($OrderID) && !empty($OrderCode)) {
            /* 查询本站订单状态 */
            $where = [
                'users_id' => $UsersID,
                'order_id' => $OrderID,
                'order_code' => $OrderCode,
            ];
            $order = Db::name('shop_order')->where($where)->find();

            if (empty($order)) {
                $this->error('无效订单！');
            } else if (0 < $order['order_status']) {
                // 订单已支付
                if ($notify === true) { // 异步
                    return [
                        'code' => 1,
                        'msg' => 'ok',
                    ];
                } else { // 同步
                    $usersData = Db::name('users')->where('users_id', $UsersID)->find();
                    // 邮箱发送
                    $resultData['email'] = GetEamilSendData(tpCache('smtp'), $usersData, $order, 1, 'wechat');
                    // 短信发送
                    $resultData['mobile'] = GetMobileSendData(tpCache('sms'), $usersData, $order, 1, 'wechat');
                    $this->success('支付完成', '/pages/order/index', $resultData);
                }
            }

            // 当前时间戳
            $time = getTime();

            // 当前时间戳 + OpenID 经 MD5加密
            $nonceStr = md5($time . $OpenID);

            // 调用支付接口参数
            $params = [
                'appid' => $this->miniproInfo['appid'],
                'mch_id' => $this->miniproInfo['mchid'],
                'nonce_str' => $nonceStr,
                'out_trade_no' => $OrderCode
            ];

            // 生成参数签名
            $params['sign'] = $this->ParamsSign($params, $this->miniproInfo['apikey']);

            // 生成参数XML格式
            $ParamsXml = $this->ParamsXml($params);

            // 调用接口返回数据
            $url = 'https://api.mch.weixin.qq.com/pay/orderquery';
            $result = $this->HttpsPost($url, $ParamsXml);

            // 解析XML格式
            $ResultData = $this->ResultXml($result);

            // 订单是否存在
            if (!empty($ResultData) && 'SUCCESS' == $ResultData['return_code'] && 'OK' == $ResultData['return_msg']) {
                // if ('NOTPAY' == $ResultData['trade_state'] && !empty($ResultData['trade_state_desc'])) {
                //     // 订单未支付
                //     $this->error($ResultData['trade_state_desc']);
                // }
                if ('SUCCESS' == $ResultData['trade_state']) {
                    // 订单已支付，处理订单流程
                    $OrderWhere = [
                        'order_id' => $OrderID,
                        'users_id' => $order['users_id']
                    ];
                    $OrderData = [
                        'order_status' => 1,
                        'pay_details' => serialize($ResultData),
                        'pay_time' => getTime(),
                        'update_time' => getTime()
                    ];
                    $ResultID = Db::name('shop_order')->where($OrderWhere)->update($OrderData);
                    if (!empty($ResultID)) {
                        // 添加订单操作记录
                        AddOrderAction($OrderID, $order['users_id'], 0, 1, 0, 1, '支付成功！', '会员使用微信小程序完成支付！');

                        $payConfig = [
                            'appid' => $this->miniproInfo['appid'],
                            'appsecret' => $this->miniproInfo['appsecret'],
                            'mchid' => $this->miniproInfo['mchid'],
                            'plugins' => 'DiyminiproMall'
                        ];

                        // 虚拟自动发货
                        $ShopModel = new \app\user\model\Pay();
                        $Where = [
                            'lang' => get_home_lang(),
                            'users_id' => $UsersID,
                            'order_id' => $OrderID
                        ];
                        $ShopModel->afterVirtualProductPay($Where);

                        // 订单支付通知
                        $params = [
                            'users_id' => $UsersID,
                            'result_id' => $OrderID,
                        ];
                        eyou_send_notice(9, $params);

                        // 站内信通知
                        $order['pay_method'] = '微信支付';
                        SendNotifyMessage($order, 5, 1, 0);

                        // 小程序支付后发送短信提醒
                        $this->PaySendSms($OrderCode);
                        // 小程序支付后发送邮件提醒
                        $this->PaySendEmail($OrderCode);

                        if (1 !== intval($order['prom_type']) && 'wechat' === trim($order['pay_name'])){
                            $payConfig = [
                                'appid' => $this->miniproInfo['appid'],
                                'appsecret' => $this->miniproInfo['appsecret'],
                                'mchid' => $this->miniproInfo['mchid'],
                                'plugins' => 'DiyminiproMall'
                            ];
                            // 保存微信发货推送表记录(需要物流发货订单)
                            if (1 === intval($order['logistics_type'])) {
                                model('ShopPublicHandle')->saveWxShippingInfo($order['users_id'], $order['order_code'], 2, $payConfig);
                            } // 推送微信发货推送表记录(核销订单)
                            else if (2 === intval($order['logistics_type'])) {
                                model('ShopPublicHandle')->pushWxShippingInfo($order['users_id'], $order['order_code'], 2, '', $payConfig);
                            }
                        }

                        // 订单支付完成
                        if ($notify === true) { // 异步
                            return [
                                'code' => 1,
                                'msg' => 'ok',
                            ];
                        } else {// 同步
                            // 统计销售额
                            eyou_statistics_data(2);
                            eyou_statistics_data(3, $order['order_amount']);
                            $this->success('支付完成', '/pages/order/index', $resultData);
                        }
                    }
                }
            }
        }
    }

    // 微信小程序支付
    public function GetWechatAppletsPay($OpenID = null, $out_trade_no = null, $total_fee = null)
    {
        // 小程序配置
        $diyminiproMallSettingModel = new \weapp\DiyminiproMall\model\DiyminiproMallSettingModel;
        $Setting                    = $diyminiproMallSettingModel->getSettingValue('setting');

        // 当前时间戳
        $time = time();

        // 当前时间戳 + OpenID 经 MD5加密
        $nonceStr = md5($time . $OpenID);

        // 调用支付接口参数
        $params = [
            'appid'            => $Setting['appId'],
            'attach'           => "微信小程序支付",
            'body'             => "商品支付",
            'mch_id'           => $this->miniproInfo['mchid'],
            'nonce_str'        => $nonceStr,
            'notify_url'       => url('plugins/DiyminiproMall/wxpay_notify', [], true, true, 1, 2),
            'openid'           => $OpenID,
            'out_trade_no'     => $out_trade_no,
            'spbill_create_ip' => $this->GetClientIP(),
            'total_fee'        => strval($total_fee * 100),
            'trade_type'       => 'JSAPI'
        ];

        // 生成参数签名
        $params['sign'] = $this->ParamsSign($params, $this->miniproInfo['apikey']);

        // 生成参数XML格式
        $ParamsXml = $this->ParamsXml($params);

        // 调用接口返回数据
        $url    = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
        $result = $this->HttpsPost($url, $ParamsXml);

        // 解析XML格式
        $ResultData = $this->ResultXml($result);

        // 数据返回
        if ($ResultData['return_code'] == 'SUCCESS' && $ResultData['return_msg'] == 'OK') {
            // 返回支付所需参数
            $ReturnData = [
                'prepay_id' => $ResultData['prepay_id'],
                'nonceStr'  => $nonceStr,
                'timeStamp' => strval($time)
            ];
            // 生成支付所需的签名
            $ReturnData['paySign'] = $this->PaySign($Setting['appId'], $params['nonce_str'], $ResultData['prepay_id'], $time);
            return $ReturnData;
        } else if ($ResultData['return_code'] == 'FAIL') {
            if ($ResultData['return_msg'] == '签名错误') {
                $ResultData['return_msg'] = '小程序支付配置不正确！';
            }
            return $ResultData;
        } else {
            return $ResultData;
        }
    }

    private function ParamsSign($values, $apikey)
    {
        //签名步骤一：按字典序排序参数
        ksort($values);
        $string = $this->ParamsUrl($values);
        //签名步骤二：在string后加入KEY
        $string = $string . '&key=' . $apikey;
        //签名步骤三：MD5加密
        $string = md5($string);
        //签名步骤四：所有字符转为大写
        $result = strtoupper($string);
        return $result;
    }

    private function ParamsUrl($values)
    {
        $Url = '';
        foreach ($values as $k => $v) {
            if ($k != 'sign' && $v != '' && !is_array($v)) {
                $Url .= $k . '=' . $v . '&';
            }
        }
        return trim($Url, '&');
    }

    private function ParamsXml($values)
    {
        if (!is_array($values)
            || count($values) <= 0
        ) {
            return false;
        }

        $xml = "<xml>";
        foreach ($values as $key => $val) {
            if (is_numeric($val)) {
                $xml .= "<" . $key . ">" . $val . "</" . $key . ">";
            } else {
                $xml .= "<" . $key . "><![CDATA[" . $val . "]]></" . $key . ">";
            }
        }
        $xml .= "</xml>";
        return $xml;
    }

    private function ResultXml($xml)
    {
        // 禁止引用外部xml实体
        @libxml_disable_entity_loader(true);
        return json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
    }

    private function GetClientIP()
    {
        if (getenv('HTTP_CLIENT_IP') && strcasecmp(getenv('HTTP_CLIENT_IP'), 'unknown')) {
            $ip = getenv('HTTP_CLIENT_IP');
        } elseif (getenv('HTTP_X_FORWARDED_FOR') && strcasecmp(getenv('HTTP_X_FORWARDED_FOR'), 'unknown')) {
            $ip = getenv('HTTP_X_FORWARDED_FOR');
        } elseif (getenv('REMOTE_ADDR') && strcasecmp(getenv('REMOTE_ADDR'), 'unknown')) {
            $ip = getenv('REMOTE_ADDR');
        } elseif (isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] && strcasecmp($_SERVER['REMOTE_ADDR'], 'unknown')) {
            $ip = $_SERVER['REMOTE_ADDR'];
        }
        return preg_match('/[\d\.]{7,15}/', $ip, $matches) ? $matches [0] : '';
    }

    private function HttpsPost($url, $data)
    {
        $result = httpRequest($url, 'POST', $data);
        return $result;

        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
        // curl_setopt ( $ch, CURLOPT_FOLLOWLOCATION, 1 );
        curl_setopt($ch, CURLOPT_AUTOREFERER, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        $result = curl_exec($ch);
        if (curl_errno($ch)) {
            return 'Errno: ' . curl_error($ch);
        }
        curl_close($ch);
        return $result;
    }

    private function PaySign($appid, $nonceStr, $prepay_id, $timeStamp)
    {
        $data = [
            'appId' => $appid,
            'nonceStr' => $nonceStr,
            'package' => 'prepay_id=' . $prepay_id,
            'signType' => 'MD5',
            'timeStamp' => $timeStamp,
        ];
        // 签名步骤一：按字典序排序参数
        ksort($data);
        $string = $this->ParamsUrl($data);
        // 签名步骤二：在string后加入KEY
        $string = $string . '&key=' . $this->miniproInfo['apikey'];
        // 签名步骤三：MD5加密
        $string = md5($string);
        // 签名步骤四：所有字符转为大写
        $result = strtoupper($string);
        return $result;
    }

    // 扣除商品库存 既要扣秒杀的也要扣原商品的,库存同步
    private function ProductStockProcessing($SpecValue = [])
    {
        if (!empty($SpecValue)) {
            foreach ($SpecValue as $key => $value) {
                if (!empty($value['value_id'])) {
                    //秒杀订单
                    $SpecUpData = [
                        'seckill_stock' => Db::raw('seckill_stock-' . ($value['quantity'])),
                        'seckill_sales_num' => Db::raw('seckill_sales_num+' . ($value['quantity'])),
                        'update_time' => getTime(),
                    ];
                    Db::name('weapp_seckill_product_spec_value')->where('value_id', $value['value_id'])->update($SpecUpData);
                    $ArcUpData = [
                        'buy_count' => Db::raw('buy_count+' . ($value['quantity'])),
                        'update_time' => getTime(),
                    ];
                    Db::name('weapp_seckill_archives')->where('goods_id', $value['goods_id'])->update($ArcUpData);

                    $oriSpecUpData = [
                        'spec_stock'     => Db::raw('spec_stock-' . ($value['quantity'])),
                        'spec_sales_num' => Db::raw('spec_sales_num+' . ($value['quantity'])),
                        'update_time' => getTime(),
                    ];
                    Db::name('product_spec_value')->where(['aid'=> $value['aid'],'spec_value_id'=> $value['spec_value_id']])->update($oriSpecUpData);

                    $oriArcUpData = [
                        'stock_count' => Db::raw('stock_count-' . ($value['quantity'])),
                        'sales_num'   => Db::raw('sales_num+' . ($value['quantity'])),
                        'sales_all'   => Db::raw('sales_all+' . ($value['quantity'])),
                        'update_time' => getTime(),
                    ];

                } else {
                    $ArcUpData = [
                        'stock' => Db::raw('stock-' . ($value['quantity'])),
                        'buy_count' => Db::raw('buy_count+' . ($value['quantity'])),
                        'update_time' => getTime(),
                    ];
                    $oriArcUpData = [
                        'stock_count' => Db::raw('stock_count-' . ($value['quantity'])),
                        'sales_num'   => Db::raw('sales_num+' . ($value['quantity'])),
                        'sales_all'   => Db::raw('sales_all+' . ($value['quantity'])),
                        'update_time' => getTime(),
                    ];
                }
                Db::name('weapp_seckill_archives')->where('goods_id', $value['goods_id'])->update($ArcUpData);
                Db::name('archives')->where('aid', $value['aid'])->update($oriArcUpData);
            }
        }
    }

    // 获取用户下单时提交的收货地址及运费
    private function GetUsersAddrData($post = [], $PromType = 0)
    {
        $AddrData = [];
        if (0 == $PromType) {
            // 查询收货地址
            $AddrWhere   = [
                'addr_id'  => $post['addr_id'],
                'users_id' => $post['users_id'],
                'lang'     => get_home_lang()
            ];
            $AddressData = Db::name('shop_address')->where($AddrWhere)->find();
            if (empty($AddressData)) $this->error('收货地址不存在！');

            $shop_open_shipping = getUsersConfigData('shop.shop_open_shipping');
            $template_money     = '0.00';
            if (!empty($shop_open_shipping)) {
                // 通过省份获取运费模板中的运费价格
                $where['province_id'] = $AddressData['province'];
                $template_money       = Db::name('shop_shipping_template')->where($where)->getField('template_money');
                if (0 == $template_money) {
                    // 省份运费价格为0时，使用统一的运费价格，固定ID为100000
                    $where['province_id'] = 100000;
                    $template_money       = Db::name('shop_shipping_template')->where($where)->getField('template_money');
                }
            }
        }

        // 拼装数组
        $AddrData = [
            'consignee'    => !empty($AddressData['consignee']) ? $AddressData['consignee'] : '',
            'country'      => !empty($AddressData['country']) ? $AddressData['country'] : '',
            'province'     => !empty($AddressData['province']) ? $AddressData['province'] : '',
            'city'         => !empty($AddressData['city']) ? $AddressData['city'] : '',
            'district'     => !empty($AddressData['district']) ? $AddressData['district'] : '',
            'address'      => !empty($AddressData['address']) ? $AddressData['address'] : '',
            'mobile'       => !empty($AddressData['mobile']) ? $AddressData['mobile'] : '',
            'shipping_fee' => !empty($template_money) ? $template_money : 0,
        ];

        return $AddrData;
    }

    // 旧产品属性处理
    private function ProductAttrProcessing($value = array())
    {
        $attr_value = '';
        $AttrWhere = [
            'a.aid' => $value['aid'],
            'b.lang' => get_home_lang()
        ];
        $attrData = Db::name('product_attr')
            ->alias('a')
            ->field('a.attr_value as value, b.attr_name as name')
            ->join('__PRODUCT_ATTRIBUTE__ b', 'a.attr_id = b.attr_id', 'LEFT')
            ->where($AttrWhere)
            ->order('b.sort_order asc, a.attr_id asc')
            ->select();
        foreach ($attrData as $val) {
            $attr_value .= $val['name'] . '：' . $val['value'] . '<br/>';
        }
        return $attr_value;
    }

    // 新商品属性处理
    private function ProductNewAttrProcessing($value = array())
    {
        $attr_value = '';
        $where = [
            'a.list_id' => $value['attrlist_id'],
            'a.status' => 1,
            'b.aid' => $value['aid']
        ];
        $attrData = Db::name('shop_product_attribute')
            ->alias('a')
            ->field('a.attr_name as name, b.attr_value as value')
            ->join('__SHOP_PRODUCT_ATTR__ b', 'a.attr_id = b.attr_id', 'LEFT')
            ->where($where)
            ->order('a.sort_order asc, a.attr_id asc')
            ->select();
        foreach ($attrData as $val) {
            $attr_value .= $val['name'] . '：' . $val['value'] . '<br/>';
        }
        return $attr_value;
    }

    // 商品规格处理
    private function ProductSpecProcessing($value = array())
    {
        $spec_value_s = '';
        if (!empty($value['spec_value_id'])) {
            $spec_value_id = explode('_', $value['spec_value_id']);
            if (!empty($spec_value_id)) {
                $SpecWhere = [
                    'aid' => $value['aid'],
                    'lang' => get_home_lang(),
                    'spec_value_id' => ['IN', $spec_value_id],
                ];
                $ProductSpecData = Db::name("product_spec_data")->where($SpecWhere)->field('spec_name,spec_value')->select();
                foreach ($ProductSpecData as $spec_value) {
                    $spec_value_s .= $spec_value['spec_name'] . '：' . $spec_value['spec_value'] . '<br/>';
                }
            }
        }
        return $spec_value_s;
    }
    /*商城购物流程--END*/

    /**
     * 构建支付请求的参数
     * @param $users
     * @param $order
     * @param $payType
     * @return array
     * @throws BaseException
     * @throws \think\exception\DbException
     */
    public function onOrderPayment($users, $order, $payType = 20)
    {
        if ($payType == 20) { // 微信支付
            return $this->onPaymentByWechat($users, $order);
        }
        return [];
    }

    /**
     * 构建微信支付请求
     * @param $users
     * @param $order
     * @return array
     * @throws BaseException
     * @throws \think\exception\DbException
     */
    protected function onPaymentByWechat($users, $order)
    {
        // 统一下单API
        if (empty($this->miniproInfo['mchid']) || empty($this->miniproInfo['apikey'])) {
            return [
                'code' => 0,
                'msg' => '很抱歉，请在网站小程序后台，完善微信支付配置！',
            ];
        }
        $openid = Db::name('weapp_diyminipro_mall_users')->where(['users_id' => $users['users_id']])->getField('openid');
        $payment = $this->unifiedorder($order['order_code'], $openid, $order['order_amount']);

        return $payment;
    }

    /**
     * 统一下单API
     * @param $order_code
     * @param $openid
     * @param $totalFee
     * @return array
     * @throws BaseException
     */
    public function unifiedorder($order_code, $openid, $totalFee)
    {
        // 当前时间
        $time = getTime();
        // 生成随机字符串
        $nonceStr = md5($time . $openid);

        // API参数
        $params = [
            'appid' => $this->miniproInfo['appid'],
            'attach' => '微信小程序支付',
            'body' => $order_code,
            'mch_id' => $this->miniproInfo['mchid'],
            'nonce_str' => $nonceStr,
            'notify_url' => url('api/v1/Api/wxpay_notify', [], true, true, 1, 1),  // 异步通知地址
            'openid' => $openid,
            'out_trade_no' => $order_code,
            'spbill_create_ip' => clientIP(),
            'total_fee' => $totalFee * 100, // 价格:单位分
            'trade_type' => 'JSAPI',
        ];
        // 生成签名
        $params['sign'] = model('v1.User')->makeSign($params, $this->miniproInfo['apikey']);
        // 请求API
        $url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
        $result = httpRequest($url, 'POST', model('v1.User')->toXml($params));
        $prepay = model('v1.User')->fromXml($result);
        // 请求失败
        if ($prepay['return_code'] === 'FAIL') {
            return [
                'code' => 0,
                'msg' => "微信支付api：{$prepay['return_msg']}",
            ];
        }
        if ($prepay['result_code'] === 'FAIL') {
            return [
                'code' => 0,
                'msg' => "微信支付api：{$prepay['err_code_des']}",
            ];
        }
        // 生成 nonce_str 供前端使用
        $paySign = $this->makePaySign($this->miniproInfo['appid'], $params['nonce_str'], $prepay['prepay_id'], $time);
        return [
            'prepay_id' => $prepay['prepay_id'],
            'nonceStr' => $nonceStr,
            'timeStamp' => (string)$time,
            'paySign' => $paySign
        ];
    }

    /**
     * 生成paySign
     * @param $nonceStr
     * @param $prepay_id
     * @param $timeStamp
     * @return string
     */
    private function makePaySign($appid, $nonceStr, $prepay_id, $timeStamp)
    {
        $data = [
            'appId' => $appid,
            'nonceStr' => $nonceStr,
            'package' => 'prepay_id=' . $prepay_id,
            'signType' => 'MD5',
            'timeStamp' => $timeStamp,
        ];
        // 签名步骤一：按字典序排序参数
        ksort($data);
        $string = model('v1.User')->toUrlParams($data);
        // 签名步骤二：在string后加入KEY
        $string = $string . '&key=' . $this->miniproInfo['apikey'];
        // 签名步骤三：MD5加密
        $string = md5($string);
        // 签名步骤四：所有字符转为大写
        $result = strtoupper($string);
        return $result;
    }

    // 地址ID 换取地址名称
    private function GetRegionName($id = 1)
    {
        $name = Db::name('region')->where('id', $id)->getField('name');
        return $name;
    }

    // 小程序支付后发送短信提醒
    private function PaySendSms($OrderCode = 0)
    {
        // 查询短信配置
        $SmsData = tpCache('sms');
        // 查询短信模板是否配置完成
        $where = [
            'is_open' => 1,
            'send_scene' => 5,
            'lang' => get_home_lang(),
            'sms_type' => $SmsData['sms_type']
        ];
        $SmsTemplate = Db::name('sms_template')->where($where)->find();
        // 发送短信逻辑
        if (!empty($SmsTemplate) && !empty($SmsTemplate['sms_tpl_code']) && !empty($SmsTemplate['tpl_content'])) {
            // 是否已经发送过，没有发送过则进行发送
            $where = [
                'source' => 5,
                'status' => 1,
                'code' => $OrderCode,
                'sms_type' => $SmsData['sms_type'],
                'mobile' => $SmsData['sms_test_mobile'],
            ];
            $SmsLog = Db::name('sms_log')->where($where)->count();
            // 手机短信提醒发送
            if (empty($SmsLog)) sendSms(5, $SmsData['sms_test_mobile'], array('content'=>$OrderCode));
        }
    }
    // 小程序支付后发送邮件提醒
    private function PaySendEmail($OrderCode = 0)
    {
        $smtp_config = tpCache('smtp');
        $where = [
            'send_scene' => 5,
            'is_open' => 1,
            'lang' => get_home_lang()
        ];
        $smtp_tpl = Db::name('smtp_tpl')->where($where)->find();
        if (!empty($smtp_tpl)){
            send_email($smtp_config['smtp_from_eamil'], $smtp_tpl['tpl_name'], $smtp_tpl['tpl_title'], 0, $smtp_config);
        }
    }
}