微信新版商家券开发

1.公共类

<?php

namespace Addons\Pay;
//[1.5.52]
class WxPayV3
{
    protected $authorization = 'WECHATPAY2-SHA256-RSA2048';  //认证类型
    protected $method = "POST";
    protected $url; //链接
    protected $mch_id;        //商户号
    protected $nonce_str;        //随机字符串
    protected $sign;        //签名
    protected $timestamp;   //时间
    protected $serial_no;        //商户Api证书序列号
    protected $apiclient_key;   //私钥地址
    protected $apiclient_cert;   //公钥地址
    protected $token;        //Token
    protected $data;         //发送参数
    protected $stock_id;     //批次号
    protected $response;    //返回信息
    protected $image_type;    //图片类型
    protected $boundary;      //边界符
    protected $suffix;      //图片后缀
    protected $openid;      //发放的openid
    protected $file;         //图片信息


    public function __construct($param)
    {
        $this->mch_id = isset($param['mch_id']) ? $param['mch_id'] : '';
        $this->data = isset($param['data']) ? $param['data'] : '';
        $this->stock_id = isset($param['stock_id']) ? $param['stock_id'] : '';
        $this->serial_no = isset($param['serial_no']) ? $param['serial_no'] : '';
        $this->apiclient_key = isset($param['apiclient_key']) ? $param['apiclient_key'] : '';
        $this->image_type = isset($param['image_type']) ? $param['image_type'] : '';
        $this->boundary = isset($param['boundary']) ? $param['boundary'] : '';
        $this->openid = isset($param['openid']) ? $param['openid'] : '';
        $this->file = isset($param['file']) ? $param['file'] : '';
    }


    /**
     * 上传图片
     * @return bool|string
     */
    public function upload()
    {
        $this->url = 'https://api.mch.weixin.qq.com/v3/marketing/favor/media/image-upload';
        $result = $this->uploadRequestAction();
        return $result;
    }


    /**
     * 图片上传请求
     * @return bool|string
     */
    public function uploadRequestAction()
    {
        if (!in_array('sha256WithRSAEncryption', \openssl_get_md_methods(true))) {
            throw new \RuntimeException("当前PHP环境不支持SHA256withRSA");
        }
        $headerParam = $this->uploadHeaderParam(); //获取头部信息
        $boundarystr = "--{$this->boundary}\r\n";// $out是post的内容
        $str = $boundarystr;
        $str .= 'Content-Disposition: form-data; name="meta"' . "\r\n";
        $str .= 'Content-Type: application/json' . "\r\n";
        $str .= "\r\n";
        $str .= json_encode($this->data['meta']) . "\r\n";
        $str .= $boundarystr;
        $str .= 'Content-Disposition: form-data; name="file"; filename="' . $this->data['meta']['filename'] . '"' . "\r\n";
        $str .= 'Content-Type: ' . $this->image_type . ";\r\n";
        $str .= "\r\n";
        $str .= $this->data['file'] . "\r\n";
        $str .= $boundarystr . "--\r\n";
//        print_r($str);exit;
        $this->response = $this->http_Request($this->url, $headerParam, $str);
        return $this->response;
    }


    /**
     * 图片上传头部参数
     * @return array
     */
    public function uploadHeaderParam()
    {
        $this->getUploadSign();        //生成签名
        $this->getToken();        //生成Token
        $header = [
            "Content-Type: multipart/form-data;name='meta'",
            "Content-Type: application/json",
            "User-Agent:" . $_SERVER['HTTP_USER_AGENT'],
            'Authorization: ' . $this->authorization . ' ' . $this->token,
            "Content-Type: multipart/form-data;boundary=" . $this->boundary
        ];
        return $header;
    }

    /**
     * 图片生成签名
     */
    protected function getUploadSign()
    {
        $url_parts = parse_url($this->url);  //链接
        $canonical_url = ($url_parts['path'] . (!empty($url_parts['query']) ? "?${url_parts['query']}" : ""));
        $this->timestamp = time();
        $this->nonce_str = createKey(); //随机字符串
        $message = $this->method . "\n" .
            $canonical_url . "\n" .
            $this->timestamp . "\n" .
            $this->nonce_str . "\n" .
            json_encode($this->data['meta']) . "\n";
        openssl_sign($message, $raw_sign, openssl_get_privatekey(file_get_contents($this->apiclient_key)), 'sha256WithRSAEncryption');
        $this->sign = base64_encode($raw_sign);
    }

    /**
     * 核销商家券
     * @return bool|string
     */
    public function verificationCoupon()
    {
        $this->url = 'https://api.mch.weixin.qq.com/v3/marketing/busifavor/coupons/use';       //创建代金券请求链接
        $result = $this->requestAction();
        return $result;
    }

    /**
     * 创建商家券
     */
    public function createShopCoupon()
    {
        $this->url = 'https://api.mch.weixin.qq.com/v3/marketing/busifavor/stocks';       //创建代金券请求链接
        $result = $this->requestAction();
        return $result;
    }


    /*  public function searchPayCoupon()
      {
          $this->url = 'https://api.mch.weixin.qq.com/v3/marketing/favor/stocks/15067678';       //创建代金券请求链接
          $this->method = "GET";
          $result = $this->requestAction();
          return $result;
      }*/

    /**
     * 创建代金券
     * @return bool|string
     */
    public function createCoupon()
    {
        $this->url = 'https://api.mch.weixin.qq.com/v3/marketing/favor/coupon-stocks';       //创建代金券请求链接
        $result = $this->requestAction();
        return $result;
    }


    /**
     * 激活代金券
     * @return bool|string
     */
    public function activateCoupon()
    {
        $this->url = "https://api.mch.weixin.qq.com/v3/marketing/favor/stocks/{$this->stock_id}/start";
        $result = $this->requestAction();
        return $result;
    }


    /**
     * 发放代金券
     */
    public function grant()
    {
        $this->url = "https://api.mch.weixin.qq.com/v3/marketing/favor/users/{$this->openid}/coupons";
        $result = $this->requestAction();
        return $result;
    }


    /**
     * 暂停代金券
     */
    public function suspend()
    {
        $this->url = "https://api.mch.weixin.qq.com/v3/marketing/favor/stocks/{$this->stock_id}/pause";
        $result = $this->requestAction();
        return $result;
    }


    /**
     * 重启代金券
     */
    public function restart()
    {
        $this->url = "https://api.mch.weixin.qq.com/v3/marketing/favor/stocks/{$this->stock_id}/restart";
        $result = $this->requestAction();
        return $result;
    }


    /**
     * 发送请求
     * @return bool|string
     */
    protected function requestAction()
    {
        if (!in_array('sha256WithRSAEncryption', \openssl_get_md_methods(true))) {
            throw new \RuntimeException("当前PHP环境不支持SHA256withRSA");
        }
        $headerParam = $this->getHeaderParam(); //获取头部信息
        $this->response = $this->http_Request($this->url, $headerParam, json_encode($this->data));
        return $this->response;
    }


    /**
     * 获取请求头部参数
     * @return array
     */
    protected function getHeaderParam()
    {
        $this->getSign();        //生成签名
        $this->getToken();        //生成Token
        $header = [
            "Content-type: application/json;charset='utf-8'",
            "Accept:application/json",
            "User-Agent:*/*",
            'Authorization: ' . $this->authorization . ' ' . $this->token,
        ];
        return $header;
    }


    /**
     * 生成签名
     */
    protected function getSign()
    {
        $url_parts = parse_url($this->url);  //链接
        $canonical_url = ($url_parts['path'] . (!empty($url_parts['query']) ? "?${url_parts['query']}" : ""));
        $this->timestamp = time();
        $this->nonce_str = createKey(); //随机字符串
        $message = $this->method . "\n" .
            $canonical_url . "\n" .
            $this->timestamp . "\n" .
            $this->nonce_str . "\n" .
            json_encode($this->data) . "\n";
        openssl_sign($message, $raw_sign, openssl_get_privatekey(file_get_contents($this->apiclient_key)), 'sha256WithRSAEncryption');
        $this->sign = base64_encode($raw_sign);
    }


    /**
     * 生成Token
     * @return string
     */
    protected function getToken()
    {
        $this->token = sprintf('mchid="%s",nonce_str="%s",timestamp="%d",serial_no="%s",signature="%s"',
            $this->mch_id, $this->nonce_str, $this->timestamp, $this->serial_no, $this->sign);
    }


    /**
     * 数据请求
     * @param $url
     * @param array $header 获取头部
     * @param string $post_data POST数据,不填写默认以GET方式请求
     * @return bool|string
     */
    public function http_Request($url, $header = array(), $post_data = "")
    {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 2);
        if ($post_data != "") {
            curl_setopt($ch, CURLOPT_POST, TRUE);
            curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data); //设置post提交数据
        }
        //判断当前是不是有post数据的发
        $response = curl_exec($ch);
        if ($response === FALSE) {
            $response = "curl 错误信息: " . curl_error($ch);
        }
        curl_close($ch);
        return $response;
    }
}

2.商家券模块类

<?php

namespace ShopCoupon\Business;

use Addons\Pay\WxPayV3;
use Common\Business\MerchantConfig;
use Common\Business\Store;
use Common\Business\WxUpload;
use Common\Model\RetailMerchantConfigModel;
use Common\Model\RetailPaySetModel;
use ShopCoupon\Model\ShopCouponModel;

/**
 * 商家券类
 * Class ShopCoupon
 * [
 * 微信参数 wxInfo
 * 核销商家券 verificationCoupon
 * 发放状态修改或者删除 suspendOperation
 * 图片上传至微信  wxUpload
 * 创建商家券 createCoupon
 * 创建商家券存表 addCoupon
 * 创建商家券参数转换 createCouponReplace
 * 创建商家券的参数验证 createCouponVerify
 * ]
 * @package ShopCoupon\Business
 */
class ShopCoupon
{
    protected $mch_id;  //商户号
    protected $serial_no;  //证书序列号
    protected $apiclient_key; //私钥地址
    protected $son_mch_id;     //子商户
    protected $appid;        //创建时的appid
    protected $path;        //小程序path
    protected $xcx_appid;        //小程序的ppid
    protected $wx_appid;        //公众号ppid

    /**
     * 微信参数
     * @param $param
     * [
     * merchant_id
     * user_type 1普通支付模式 2服务商支付模式
     * type 1小程序  2公众号
     * ]
     */
    protected function wxInfo($param)
    {
        $merchant_id = $param['merchant_id'];
        $type = $param['type'];
        $user_type = $param['user_type'];
        $paySetModel = new RetailPaySetModel();
        $paySet = $paySetModel->getFindMerchantPaySet($merchant_id);
        $this->xcx_appid = $paySet['config']['xcx_appid'];
        $this->path = '/pages/store/store';
        $this->wx_appid = $paySet['config']['wx_appid'];
        switch ($user_type) {
            case 1:
                //普通支付模式
                switch ($type) {
                    case 1:
                        //小程序
                        $this->mch_id = $paySet['config']['xcx_mer_id'];
                        $this->serial_no = $paySet['config']['wx_xcx_serial_no'];
                        $this->apiclient_key = $paySet['config']['xcx_apiclient_key'];
                        $this->appid = $paySet['config']['xcx_appid'];
                        break;
                    case 2:
                        //公众号
                        $this->mch_id = $paySet['config']['wx_mch_id'];
                        $this->serial_no = $paySet['config']['wx_serial_no'];
                        $this->apiclient_key = $paySet['config']['apiclient_key'];
                        $this->appid = $paySet['config']['wx_appid'];
                        break;
                }
                break;
            case 2:
                //服务商支付模式
                $this->son_mch_id = $paySet['config']['xcx_sub_mchid'];
                $this->mch_id = $paySet['config']['systemConfig']['mch_id'];
                $this->serial_no = $paySet['config']['systemConfig']['wx_serial_no'];
                $this->apiclient_key = $paySet['config']['systemConfig']['wx_apiclient_key'];
                $this->appid = $paySet['config']['systemConfig']['wx_appid'];
                break;
        }
    }


    /**
     * 发放状态修改或者删除
     * @param $param
     * [
     * merchant_id
     * coupon_id  商家券id
     * operation_type    1发放 2暂停 3删除
     * ]
     * @return mixed
     */
    public function suspendOperation($param)
    {
        if (empty($param['merchant_id']) || empty($param['coupon_id']) || empty($param['operation_type'])) {
            return callBack(statusCode()['error'], "参数缺失");
        }
        switch ($param['operation_type']) {
            case 1:
                //开始发放
                $data['suspend_status'] = 1;
                break;
            case 2:
                //暂停发放
                $data['suspend_status'] = 2;
                break;
            case 3:
                //删除
                $data['status'] = 2;
                break;
        }
        $where = [
            'merchant_id' => $param['merchant_id'],
            'id' => $param['coupon_id']
        ];
        $ShopCouponModel = new ShopCouponModel();
        $result = $ShopCouponModel->updateOrder($where, $data);
        if ($result) {
            return callBack(statusCode()['success'], "操作成功");
        } else {
            return callBack(statusCode()['success'], "暂无修改");
        }
    }


    /**
     * 核销商家券
     * @param $param
     * [
     * openid 用户小程序openid
     * service_openid 服务商下的openid
     * ordinary_openid 商户公众号的openid
     * merchant_id
     * user_type 1普通支付模式 2服务商支付模式
     * type 1小程序  2公众号
     * coupon_code 券code
     * app_id 公众账号ID
     * verification_available_type 核销场景 1小程序 2收银机 3公众号
     * verification_store_id 核销的门店
     * operator_id 核销人id  0为小程序用户购买核销
     * ]
     * @return mixed
     */
    public function verificationCoupon($param)
    {
        if (empty($param['merchant_id']) || empty($param['user_type']) || empty($param['type']) || empty($param['coupon_code']) || empty($param['app_id']) || empty($param['verification_available_type']) || empty($param['verification_store_id'])) {
            return callBack(statusCode()['error'], "缺少参数");
        }
        $this->wxInfo($param);
        $time = time();
        $use_time = date("Y-m-d H:i:s", $time) . '+08:00';
        $use_time = str_replace(" ", "T", $use_time);
        $use_request_no = onlyCreateKey();
        $data = [
            'mch_id' => $this->mch_id,
            'serial_no' => $this->serial_no,
            'apiclient_key' => $this->apiclient_key,
            'data' => [
                'coupon_code' => $param['coupon_code'],
                'appid' => $param['app_id'],
                'use_time' => $use_time,
                'use_request_no' => $use_request_no,
            ]
        ];
        switch ($param['user_type']) {
            case 1:
                //普通支付模式
                switch ($param['type']) {
                    case 1:
                        //小程序
                        if (!empty($param['openid'])) {
                            $data['data']['openid'] = $param['openid'];
                        }
                        break;
                    case 2:
                        //公众号
                        if (!empty($param['ordinary_openid'])) {
                            $data['data']['openid'] = $param['ordinary_openid'];
                        }
                        break;
                }
                break;
            case 2:
                //服务商支付模式
                if (!empty($param['service_openid'])) {
                    $data['data']['openid'] = $param['service_openid'];
                }
                break;
        }
        $WxPayV3Class = new WxPayV3($data);
        $result = $WxPayV3Class->verificationCoupon();
        file_put_contents('./shop_coupon_write.txt', $result . PHP_EOL, FILE_APPEND);
//        file_put_contents('./shop_coupon2.txt',json_encode($data));
        $result = json_decode($result, true);
        if (!empty($result['stock_id'])) {
            return callBack(statusCode()['success'], "核销成功", ['use_time' => $time, 'wechatpay_use_time' => $result['wechatpay_use_time'], 'use_request_no' => $use_request_no]);
        } else {
            return callBack(statusCode()['error'], $result['message'], ['use_time' => $time, 'wechatpay_use_time' => $time, 'use_request_no' => $use_request_no]);
        }
    }

    /**
     * 图片上传至微信
     * @param $param
     * [
     * user_type 1普通支付模式 2服务商支付模式
     * merchant_id
     * ]
     * @return array
     */
    public function wxUpload($param)
    {
        if (empty($param['user_type'])) {
            return callBack(statusCode()['error'], "请选择支付模式");
        }
        $this->wxInfo([
            'merchant_id' => $param['merchant_id'],
            'type' => 1,
            'user_type' => $param['user_type']
        ]);
        switch ($param['user_type']) {
            case 1:
                $image = $_FILES['label_img'];
                break;
            case 2:
                $image = $_FILES['label_img_service'];
                break;
        }
        $wxUploadClass = new WxUpload();
        $result = $wxUploadClass->wxUpload([
            'image' => $image,
            'mch_id' => $this->mch_id,
            'serial_no' => $this->serial_no,
            'apiclient_key' => $this->apiclient_key,
            'user_type' => $param['user_type']
        ]);
        if ($result['status'] == 1) {
            $data['merchant_id'] = $param['merchant_id'];
            switch ($param['user_type']) {
                case 1:
                    $data['shop_coupon_simple_image'] = $result['data']['image_path'];
                    $data['shop_coupon_simple_wx_image'] = $result['data']['media_url'];
                    break;
                case 2:
                    $data['shop_coupon_service_image'] = $result['data']['image_path'];
                    $data['shop_coupon_service_wx_image'] = $result['data']['media_url'];
                    break;
            }
            $configClass = new MerchantConfig();
            $configClass->shopCouponImgSet($data);
        }
        return $result;
    }

    /**
     * 创建商家券
     * @param $param
     * [
     * merchant_id
     * operator_id
     * data=>[
     *  store_id_gather 门店集合
     *  user_type 1普通支付模式 2服务商支付模式
     *  type 1小程序  2公众号
     *  stock_name 名称
     *  goods_name 适用商品范围
     *  stock_type 1满减 2折扣 3换购
     *  available_time 有效时间
     *  valid_time_type 生效时间类型
     *  coupon_use_rule=>[
     *    fixed_normal_coupon=>[
     *       discount_amount   优惠金额
     *       transaction_minimum  门槛
     *      ],
     *    coupon_available_time=>[
     *       available_week=>[
     *         week_day=>[],
     *         available_day_time=>[
     *            begin_time
     *            end_time
     *          ],
     *      ]
     *       irregulary_avaliable_time=>[
     *         begin_time
     *         end_time
     *        ]
     *     ]
     *   ],
     *   stock_send_rule=>[
     *       max_amount 批次总预算
     *       max_coupons_per_user  用户最大可领个数
     *    ],
     *    display_pattern_info=>[
     *      merchant_name 商户名称
     *    ]
     *  ]
     * ]
     * @return mixed
     */
    public function createCoupon($param)
    {
        $paySetModel = new RetailPaySetModel();
        $paySet = $paySetModel->getFindMerchantPaySet($param['merchant_id']);
        if (!empty($paySet['config']['xcx_sub_mchid']) && !empty($paySet['config']['systemConfig']['mch_id']) && !empty($paySet['config']['systemConfig']['wx_serial_no']) && !empty($paySet['config']['systemConfig']['wx_apiclient_key']) && !empty($paySet['config']['systemConfig']['wx_appid'])) {
            $param['data']['user_type'] = 2; //服务商模式
        } else if (!empty($paySet['config']['xcx_mer_id']) && !empty($paySet['config']['wx_xcx_serial_no']) && !empty($paySet['config']['xcx_apiclient_key']) && !empty($paySet['config']['xcx_appid'])) {
            $param['data']['user_type'] = 1; //普通模式
        } else {
            return callBack(statusCode()['error'], '请配置小程序支付参数');
        }
        if ($param['data']['user_type'] == 1) {
            if (count($param['data']['available_type']) > 1 || in_array(2, $param['data']['available_type'])) {
                $param['data']['type'] = 2; //公众号创建
            } else if (in_array(1, $param['data']['available_type'])) {
                $param['data']['type'] = 1; //小程序创建
            }
        } else {
            $param['data']['type'] = 2; //公众号创建
        }
        $this->wxInfo([
            'merchant_id' => $param['merchant_id'],
            'user_type' => $param['data']['user_type'],
            'type' => $param['data']['type'], //小程序创建
        ]); //获取微信配置参数
        $verify = $this->createCouponVerify($param); //参数验证
        if ($verify['status'] != 1) {
            return $verify;
        }
        $new_param = $this->createCouponReplace($param);  //去除多余参数
        switch ($param['data']['user_type']) {
            case 1:
                $new_param['belong_merchant'] = $this->mch_id;
                break;
            case 2:
                $new_param['belong_merchant'] = $this->son_mch_id;
                break;
        }
        $data = [
            'mch_id' => $this->mch_id,
            'serial_no' => $this->serial_no,
            'apiclient_key' => $this->apiclient_key,
            'data' => $new_param
        ];
        $WxPayV3Class = new WxPayV3($data);
        $result = $WxPayV3Class->createShopCoupon();
        file_put_contents('./shop_coupon.txt', $result . PHP_EOL, FILE_APPEND);
        $result = json_decode($result, true);
        if (!empty($result['stock_id'])) {
            $param['stock_id'] = $result['stock_id'];
            $param['out_request_no'] = $new_param['out_request_no'];
            $result = $this->addCoupon($param); //存入表
            return $result;
        } else {
            return callBack(statusCode()['error'], $result['message']);
        }
    }


    /**
     * 创建商家券存表
     * @param $param
     * [
     * merchant_id
     * operator_id
     * data=>[
     *  store_id_gather 门店集合
     *  user_type 1普通支付模式 2服务商支付模式
     *  type 1小程序  2公众号
     *  stock_name 名称
     *  goods_name 适用商品范围
     *  stock_type 1满减 2折扣 3换购
     *  available_time 有效时间
     *  valid_time_type 生效时间类型
     *  coupon_use_rule=>[
     *    fixed_normal_coupon=>[
     *       discount_amount   优惠金额
     *       transaction_minimum  门槛
     *      ],
     *    coupon_available_time=>[
     *       available_week=>[
     *         week_day=>[],
     *         available_day_time=>[
     *            begin_time
     *            end_time
     *          ],
     *      ]
     *       irregulary_avaliable_time=>[
     *         begin_time
     *         end_time
     *        ]
     *     ]
     *   ],
     *   stock_send_rule=>[
     *       max_amount 批次总预算
     *       max_coupons_per_user  用户最大可领个数
     *    ],
     *    display_pattern_info=>[
     *      merchant_name 商户名称
     *    ]
     *  ]
     * ]
     * @return mixed
     */
    public function addCoupon($param)
    {
        $data = $param['data'];
        $discount_amount = $data['coupon_use_rule']['fixed_normal_coupon']['discount_amount'];
        $max_amount = $data['stock_send_rule']['max_amount'];
        $coupon_num = intval(floor($max_amount / $discount_amount));
        $data['coupon_use_rule']['coupon_available_time']['available_begin_time'] = $data['available_time'][0];
        $data['coupon_use_rule']['coupon_available_time']['available_end_time'] = $data['available_time'][1];
        $content = [
            'merchant_id' => $param['merchant_id'],
            'app_id' => $this->appid,
            'operator_id' => $param['operator_id'],
            'belong_merchant' => $this->mch_id,
            'stock_id' => $param['stock_id'],
            'user_type' => $data['user_type'],
            'type' => $data['type'],
            'stock_name' => $data['stock_name'],
            'goods_name' => $data['goods_name'],
            'stock_type' => $data['stock_type'],
            'available_begin_time' => strtotime($data['coupon_use_rule']['coupon_available_time']['available_begin_time']),
            'available_end_time' => strtotime($data['coupon_use_rule']['coupon_available_time']['available_end_time']),
            'valid_time_type' => $data['valid_time_type'] ? $data['valid_time_type'] : 0,
            'coupon_use_rule' => json_encode($data['coupon_use_rule']),
            'stock_send_rule' => json_encode($data['stock_send_rule']),
            'display_pattern_info' => json_encode($data['display_pattern_info']),
            'create_time' => time(),
            'out_request_no' => $param['out_request_no'],
            'store_type' => $data['store_type'],
            'goods_type' => $data['goods_type'],
            'available_type' => implode(',', $data['available_type']),
            'coupon_num' => $coupon_num,
            'operation_num' => $coupon_num
        ];
        if (!empty($data['store_id_gather'])) {
            $content['store_id_gather'] = implode(',', $data['store_id_gather']);
        }
        if (!empty($data['goodsList'])) {
            $content['goods_list'] = json_encode($data['goodsList']);
            $content['goods_id_gather'] = implode(',', array_column($data['goodsList'], 'goods_id'));
        }
        if (!empty($data['logo_image'])) {
            $content['logo_image'] = $data['logo_image'];
        }
        $ShopCouponModel = new ShopCouponModel();
        $coupon_id = $ShopCouponModel->addOrder($content);
        if (!empty($coupon_id)) {
            return callBack(statusCode()['success'], "添加成功");
        } else {
            return callBack(statusCode()['error'], "创建成功,记录添加失败");
        }
    }


    /**
     * 创建商家券参数转换
     * @param $param
     * [
     * merchant_id
     * operator_id
     * data=>[
     *  store_id_gather 门店集合
     *  user_type 1普通支付模式 2服务商支付模式
     *  type 1小程序  2公众号
     *  stock_name 名称
     *  goods_name 适用商品范围
     *  stock_type 1满减 2折扣 3换购
     *  available_time 有效时间
     *  valid_time_type 生效时间类型
     *  coupon_use_rule=>[
     *    fixed_normal_coupon=>[
     *       discount_amount   优惠金额
     *       transaction_minimum  门槛
     *      ],
     *    coupon_available_time=>[
     *       available_week=>[
     *         week_day=>[],
     *         available_day_time=>[
     *            begin_time
     *            end_time
     *          ],
     *      ]
     *       irregulary_avaliable_time=>[
     *         begin_time
     *         end_time
     *        ]
     *     ]
     *   ],
     *   stock_send_rule=>[
     *       max_amount 批次总预算
     *       max_coupons_per_user  用户最大可领个数
     *    ],
     *    display_pattern_info=>[
     *      merchant_name 商户名称
     *    ]
     *  ]
     * ]
     * @return mixed
     */
    public function createCouponReplace($param)
    {
        $new_param = $param['data'];
        switch ($new_param['stock_type']) {
            case 1:
                $new_param['stock_type'] = 'NORMAL';
                break;
            case 2:
                $new_param['stock_type'] = 'DISCOUNT';
                break;
            case 3:
                $new_param['stock_type'] = 'EXCHANGE';
                break;
        }
        if (!empty($new_param['coupon_use_rule']['coupon_available_time']['available_day_after_receive'])) {
            $new_param['coupon_use_rule']['coupon_available_time']['available_day_after_receive'] = intval($new_param['coupon_use_rule']['coupon_available_time']['available_day_after_receive']);
        } else {
            unset($new_param['coupon_use_rule']['coupon_available_time']['available_day_after_receive']);
        }
        if (!empty($new_param['valid_time_type'])) {
            switch ($new_param['valid_time_type']) {
                case 1:
                    //无规律时间段
                    $new_param['coupon_use_rule']['coupon_available_time']['irregulary_avaliable_time'][] = ['begin_time' => $new_param['coupon_use_rule']['coupon_available_time']['irregulary_avaliable_time']['irregular_time'][0] . '+08:00', 'end_time' => $new_param['coupon_use_rule']['coupon_available_time']['irregulary_avaliable_time']['irregular_time'][1] . '+08:00'];
                    unset($new_param['coupon_use_rule']['coupon_available_time']['available_week']);
                    unset($new_param['coupon_use_rule']['coupon_available_time']['wait_days_after_receive']);
                    break;
                case 2:
                    //固定周期
                    $time = strtotime(date('Y-m-d', time()));
                    $new_param['coupon_use_rule']['coupon_available_time']['available_week']['available_day_time'][] = ['begin_time' => strtotime($new_param['coupon_use_rule']['coupon_available_time']['available_week']['available_day_time']['begin_time']) - $time, 'end_time' => strtotime($new_param['coupon_use_rule']['coupon_available_time']['available_week']['available_day_time']['end_time']) - $time];
                    if (empty($new_param['coupon_use_rule']['coupon_available_time']['available_week']['week_day'])) {
                        unset($new_param['coupon_use_rule']['coupon_available_time']['available_week']['week_day']);
                    } else {
                        $new_param['coupon_use_rule']['coupon_available_time']['available_week']['week_day'] = array_map('int', $new_param['coupon_use_rule']['coupon_available_time']['available_week']['week_day']);
                    }
                    unset($new_param['coupon_use_rule']['coupon_available_time']['irregulary_avaliable_time']);
                    unset($new_param['coupon_use_rule']['coupon_available_time']['wait_days_after_receive']);
                    unset($new_param['coupon_use_rule']['coupon_available_time']['available_week']['available_day_time']['begin_time']);
                    unset($new_param['coupon_use_rule']['coupon_available_time']['available_week']['available_day_time']['end_time']);
                    break;
                case 3:
                    //领取后N天开始生效
                    $new_param['coupon_use_rule']['coupon_available_time']['wait_days_after_receive'] = intval($new_param['coupon_use_rule']['coupon_available_time']['wait_days_after_receive']);
                    unset($new_param['coupon_use_rule']['coupon_available_time']['irregulary_avaliable_time']);
                    unset($new_param['coupon_use_rule']['coupon_available_time']['available_week']);
                    break;
            }
        } else {
            unset($new_param['coupon_use_rule']['coupon_available_time']);
        }
        $new_param['coupon_use_rule']['fixed_normal_coupon']['discount_amount'] = $new_param['coupon_use_rule']['fixed_normal_coupon']['discount_amount'] * 100;
        $new_param['coupon_use_rule']['fixed_normal_coupon']['transaction_minimum'] = $new_param['coupon_use_rule']['fixed_normal_coupon']['transaction_minimum'] * 100;
        $new_param['stock_send_rule']['max_amount'] = $new_param['stock_send_rule']['max_amount'] * 100;
        $new_param['stock_send_rule']['max_coupons_per_user'] = intval($new_param['stock_send_rule']['max_coupons_per_user']);
        $new_param['coupon_use_rule']['coupon_available_time']['available_begin_time'] = $new_param['available_time'][0] . '+08:00';
        $new_param['coupon_use_rule']['coupon_available_time']['available_end_time'] = $new_param['available_time'][1] . '+08:00';
        if (count($param['data']['available_type']) > 1 || in_array(2, $param['data']['available_type'])) {
            $new_param['coupon_use_rule']['use_method'] = 'PAYMENT_CODE';  //线下实体店
        } else{
            $new_param['coupon_use_rule']['use_method'] = 'MINI_PROGRAMS';
        }
        $new_param['coupon_use_rule']['mini_programs_appid'] = $this->xcx_appid;
        $new_param['coupon_use_rule']['mini_programs_path'] = $this->path;
        $new_param['out_request_no'] = createOrderTradeNo($param['merchant_id']); //随机字符串
        $new_param['coupon_code_mode'] = 'WECHATPAY_MODE';
        $new_param['custom_entrance']['code_display_mode'] = 'BARCODE';
        $new_param['custom_entrance']['mini_programs_info']['mini_programs_appid'] = $this->xcx_appid;
        $new_param['custom_entrance']['mini_programs_info']['mini_programs_path'] = $this->path;
        $new_param['custom_entrance']['mini_programs_info']['entrance_words'] = '欢迎选购';
        $new_param['custom_entrance']['appid'] = $this->wx_appid;
        if (empty($new_param['display_pattern_info']['merchant_name'])) {
            unset($new_param['display_pattern_info']['merchant_name']);
        }
        switch ($new_param['user_type']) {
            case 1:
                //普通
                $image_path = 'shop_coupon_simple_wx_image';
                break;
            case 2:
                //服务商
                $image_path = 'shop_coupon_service_wx_image';
                break;
        }
        $configModel = new RetailMerchantConfigModel();
        $merchant_logo_url = $configModel->getFindField([
            'merchant_id' => $param['merchant_id']
        ], $image_path);
        if (!empty($merchant_logo_url)) {
            $new_param['display_pattern_info']['merchant_logo_url'] = $merchant_logo_url;
        }
        $description = '不能与其他优惠券同时使用, ';  //使用须知
        if ($new_param['stock_type'] == 2) {
            $StoreClass = new Store();
            $storeResult = $StoreClass->storeNameList([
                'store_id_gather' => $new_param['store_id_gather']
            ]);
            if ($storeResult['status'] == 1) {
                $description .= '可使用门店为' . implode(',', $storeResult['data']['list']) . ' ';
            }
        }
        if (count($new_param['available_type']) > 1) {
            $description .= '支持小程序商城与实体店使用 ';
        } else {
            if (in_array(1, $new_param['available_type'])) {
                $description .= '支持小程序商城使用 ';
            }
            if (in_array(2, $new_param['available_type'])) {
                $description .= '支持实体店使用 ';
            }
        }
        if ($new_param['goods_type'] == 1) {
            $description .= '针对全部商品';
        } else if ($new_param['goods_type'] == 2) {
            $goods_name = array_column($new_param['goodsList'], 'goods_name');
            $description .= '针对' . implode(',', $goods_name) . '商品';
        }
        $new_param['display_pattern_info']['description'] = $description;
        unset($new_param['goodsList']);
        unset($new_param['store_id_gather']);
        unset($new_param['store_type']);
        unset($new_param['goods_type']);
        unset($new_param['user_type']);
        unset($new_param['type']);
        unset($new_param['available_time']);
        unset($new_param['valid_time_type']);
        unset($new_param['coupon_use_rule']['coupon_available_time']['irregulary_avaliable_time']['irregular_time']);
        unset($new_param['available_type']);
//                print_r($new_param);exit;
        return $new_param;

    }


    /**
     * 创建商家券的参数验证
     * @param $param
     * [
     * merchant_id
     * operator_id
     * data=>[
     *  store_id_gather 门店集合
     *  user_type 1普通支付模式 2服务商支付模式
     *  type 1小程序  2公众号
     *  stock_name 名称
     *  goods_name 适用商品范围
     *  stock_type 1满减 2折扣 3换购
     *  available_time 有效时间
     *  valid_time_type 生效时间类型
     *  coupon_use_rule=>[
     *    fixed_normal_coupon=>[
     *       discount_amount   优惠金额
     *       transaction_minimum  门槛
     *      ],
     *    coupon_available_time=>[
     *       available_week=>[
     *         week_day=>[],
     *         available_day_time=>[
     *            begin_time
     *            end_time
     *          ],
     *      ]
     *       irregulary_avaliable_time=>[
     *         begin_time
     *         end_time
     *        ]
     *     ]
     *   ],
     *   stock_send_rule=>[
     *       max_amount 批次总预算
     *       max_coupons_per_user  用户最大可领个数
     *    ],
     *    display_pattern_info=>[
     *      merchant_name 商户名称
     *    ]
     *  ]
     * ]
     * @return mixed
     */
    public function createCouponVerify($param)
    {
        $reg = "/^[+]{0,1}(\d+)$|^[+]{0,1}(\d+\.\d{0,2})$/";
        $reg2 = "/^\+?[0-9][0-9]*$/";
        if (empty($param['merchant_id']) || empty($param['operator_id'])) {
            return callBack(statusCode()['error'], "登录超时");
        }
        if (empty($this->mch_id) || empty($this->serial_no) || empty($this->apiclient_key)) {
            return callBack(statusCode()['error'], "请检查支付配置,商户号,Api证书号,私钥证书");
        }
        $data = $param['data'];
        $discount_amount = $data['coupon_use_rule']['fixed_normal_coupon']['discount_amount'];
        $transaction_minimum = $data['coupon_use_rule']['fixed_normal_coupon']['transaction_minimum'];
        $max_amount = $data['stock_send_rule']['max_amount'];
        $max_coupons_per_user = $data['stock_send_rule']['max_coupons_per_user'];
        if (empty($data['available_type'])) return callBack(statusCode()['error'], "请选择可用场景");
        if (empty($data['stock_type'])) return callBack(statusCode()['error'], "请选择商家券类型");
        if (empty($data['stock_name'])) return callBack(statusCode()['error'], "请输入商家券名称");
        if (strlen($data['stock_name']) > 20) return callBack(statusCode()['error'], "商家券名称最多20个字符");
        if (empty($data['goods_name'])) return callBack(statusCode()['error'], "请输入适用商品范围");
        if (strlen($data['goods_name']) > 15) return callBack(statusCode()['error'], "适用商品范围最多15个字符");
        switch ($data['stock_type']) {
            case 1:
                //满减券
                if (empty($discount_amount) || $discount_amount < 0.01 || $discount_amount > 100000 || !preg_match($reg, $discount_amount)) {
                    return callBack(statusCode()['error'], "请输入正确优惠金额");
                }
                if (empty($transaction_minimum) || $transaction_minimum <= $discount_amount || $transaction_minimum > 100000 || !preg_match($reg, $transaction_minimum)) {
                    return callBack(statusCode()['error'], "请输入正确消费门槛");
                }
                if (empty($max_amount) || $max_amount < 0.01 || $max_amount > 1000000000 || !preg_match($reg, $max_amount)) {
                    return callBack(statusCode()['error'], "请输入正确批次总预算");
                }
                if (intval($max_amount / $discount_amount) != ($max_amount / $discount_amount)) {
                    return callBack(statusCode()['error'], "总预算必须能除尽优惠金额");
                }
                break;
        }
        if (empty($max_coupons_per_user) || $max_coupons_per_user < 1 || $max_coupons_per_user > 100 || !preg_match($reg2, $max_coupons_per_user)) {
            return callBack(statusCode()['error'], "请输入正确用户最大可领个数");
        }
        if (empty($data['available_time'])) {
            return callBack(statusCode()['error'], "请选择券可核销时间");
        }
        if (!empty($data['coupon_use_rule']['coupon_available_time']['available_day_after_receive']) && !preg_match($reg2, $data['coupon_use_rule']['coupon_available_time']['available_day_after_receive'])) {
            return callBack(statusCode()['error'], "请输入正确的生效后N天内有效");
        }
        if (!empty($data['valid_time_type'])) {
            switch ($data['valid_time_type']) {
                case 1:
                    if (empty($data['coupon_use_rule']['coupon_available_time']['irregulary_avaliable_time']['irregular_time'])) {
                        return callBack(statusCode()['error'], "请选择无规律有效时间段");
                    }
                    break;
                case 2:
                    if (empty($data['coupon_use_rule']['coupon_available_time']['available_week']['available_day_time']['begin_time']) || empty($data['coupon_use_rule']['coupon_available_time']['available_week']['available_day_time']['end_time'])) {
                        return callBack(statusCode()['error'], "请选择固定周期有效时间段");
                    }
                    break;
                case 3:
                    if (empty($data['coupon_use_rule']['coupon_available_time']['wait_days_after_receive']) || !preg_match($reg2, $data['coupon_use_rule']['coupon_available_time']['wait_days_after_receive'])) {
                        return callBack(statusCode()['error'], "请输入领取后N天开始生效");
                    }
                    if (empty($data['coupon_use_rule']['coupon_available_time']['available_day_after_receive'])) {
                        return callBack(statusCode()['error'], "该类型必须与生效后N天内有效一起使用");
                    }
                    break;
            }
        }
        switch ($data['store_type']) {
            case 1:
                if ($data['goods_type'] != 1) {
                    return callBack(statusCode()['error'], "所有门店必须选择所有商品");
                }
                break;
            case 2:
                if ($data['goods_type'] == 2) {
                    if (count($data['store_id_gather']) != 1) {
                        return callBack(statusCode()['error'], "该类型只能选择一个门店");
                    }
                    if (count($data['goodsList']) == 0) {
                        return callBack(statusCode()['error'], "请选择商品");
                    }
                    if (count($data['goodsList']) > 20) {
                        return callBack(statusCode()['error'], "最多只能选择20种商品");
                    }
                }
                break;
        }
        return callBack(statusCode()['success'], "验证成功");
    }
}

3.商家券公共端类

<?php

namespace Common\Business;
//[1.5.52]
use Common\Model\RetailMerchantConfigModel;
use Common\Model\RetailPaySetModel;
use Common\Model\RetailShoppingModel;
use Common\Model\RetailSkuGoodsModel;
use Common\Model\RetailStoreXcxConfigModel;
use ShopCoupon\Model\ShopCouponModel;
use ShopCoupon\Model\ShopCouponRecordModel;

/**
 * 商家券类
 * Class ShopCoupon
 * [
 * 查询用户券是否使用状态 getUserShopCouponState
 * 未领取的商家券详情  notReceivedCouponRule
 * 已领取商家券规则详情 shopCouponRule
 * 收银机登录会员可用商家券 getVipShopCouponList
 * 收银机下单商家券使用 cashPlaceOrder
 * 将优惠后的商品信息替换原来购买的商品信息 sellDataArrayReplace
 * 获取参与优惠的商品信息 sellDataArray_new
 * 小程序下单商家券使用 xcxPlaceOrder
 * 小程序下单选择可用商家券 xcxGetUserPayShopCoupon
 * 获取小程序普通下单获取商家券所需的商品信息 getShoppingGoods
 * 核销成功用户商家券更新 couponRecordUpdate
 * 核销商家券 verificationCoupon
 * 查询商家券信息 getCouponInfo
 * 商家券条件验证 verificationCouponTermVerify
 * 用户商家券列表 userShopCouponList
 * 领取商家券成功后添加领取记录 receiveCouponCallback
 * 领券签名与商户号 grantCouponSign
 * 领券签名与商户号参数验证 grantCouponSignVerify
 * 商家券列表 couponList
 * ]
 * @package Common\Business
 */
class ShopCoupon
{
    /**
     * 查询用户券是否使用状态
     * @param $param
     * [
     * coupon_id
     * ]
     * @return mixed
     */
    public function getUserShopCouponState($param)
    {
        try {
            $ShopCouponRecordModel = new ShopCouponRecordModel();
            $used_type = $ShopCouponRecordModel->getFindField([
                'id' => $param['coupon_id']
            ], "used_type");
            return callBack(statusCode()['success'], "查询成功", ['used_type' => $used_type]);
        } catch (\Exception $e) {
            return callBack(statusCode()['success'], "查询失败");
        }
    }

    /**
     * 商家小程序立即使用验证
     * @param $param
     * [
     * coupon_id 用户商家券id
     * ]
     * @return mixed
     */
    public function useShopCoupon($param)
    {
        try {
            $fields = 'r.id,r.coupon_code,r.used_type,r.verification_type,r.add_time,s.app_id,s.type,s.user_type,s.available_type,s.stock_type,
        s.available_begin_time,s.available_end_time,s.valid_time_type,s.coupon_use_rule,s.store_type,s.store_id_gather,
        s.goods_type,s.goods_id_gather,s.stock_name';
            $couponRecord = new ShopCouponRecordModel();
            $shop_coupon = $couponRecord->verificationCouponInfo($fields, [
                'r.id' => $param['coupon_id']
            ]);
        } catch (\Exception $e) {
            return callBack(statusCode()['error'], "查询失败");
        }
        $verifyResult = $this->verificationCouponTermVerify([
            'shop_coupon' => $shop_coupon,
            'verification_available_type' => 1, //小程序使用
            'verify_goods_type' => 2, //不需要验证金额
        ]);//条件验证
        return $verifyResult;
    }


    /**
     * 未领取的商家券详情
     * @param $param
     * [
     * id 商家券id
     * merchant_id
     * xcx_id
     * ]
     * @return mixed
     */
    public function notReceivedCouponRule($param)
    {
        try {
            $fields = 'stock_name,stock_id,available_type,available_begin_time,available_end_time,valid_time_type,
        coupon_use_rule,store_type,store_id_gather,goods_type,goods_id_gather,user_type,type,belong_merchant';
            $ShopCouponModel = new ShopCouponModel();
            $shop_coupon = $ShopCouponModel->getFind([
                'id' => $param['id']
            ], $fields);
        } catch (\Exception $e) {
            return callBack(statusCode()['error'], "查询异常");
        }
        if (empty($shop_coupon)) {
            return callBack(statusCode()['error'], "未找到该商家券");
        }
        $available_type = explode(',', $shop_coupon['available_type']);
        if (count($available_type) > 1) {
            $shop_coupon['available_type_name'] = '小程序商城,线下门店通用券';
        } else {
            if (in_array(1, $available_type)) {
                $shop_coupon['available_type_name'] .= '小程序商城';
            } else if (in_array(2, $available_type)) {
                $shop_coupon['available_type_name'] .= '线下门店';
            }
        }
        $coupon_use_rule = json_decode($shop_coupon['coupon_use_rule'], true);
        $shop_coupon['discount_amount'] = $coupon_use_rule['fixed_normal_coupon']['discount_amount']; //优惠金额
        $shop_coupon['transaction_minimum'] = $coupon_use_rule['fixed_normal_coupon']['transaction_minimum']; //消费门槛
        if (!empty($shop_coupon['valid_time_type'])) {
            switch ($shop_coupon['valid_time_type']) {
                case 1:
                    //无规律
                    $irregular_time = $coupon_use_rule['coupon_available_time']['irregulary_avaliable_time']['irregular_time'];
                    $available_begin_time = str_replace("T", " ", $irregular_time[0]);
                    $available_end_time = str_replace("T", " ", $irregular_time[1]);
                    $available_begin_time = str_replace("-", ".", $available_begin_time);
                    $available_end_time = str_replace("-", ".", $available_end_time);
                    $shop_coupon['user_time'] = $available_begin_time . '-' . $available_end_time;
                    break;
                case 2:
                    //固定时间段
                    $available_day_time = $coupon_use_rule['coupon_available_time']['available_week']['available_day_time'];
                    $week_day = $coupon_use_rule['coupon_available_time']['available_week']['week_day'];
                    $available_day_after_receive = $coupon_use_rule['coupon_available_time']['available_day_after_receive']; //多少天内有效
                    $begin_time = str_replace('-', '.', $available_day_time['begin_time']);
                    $end_time = str_replace('-', '.', $available_day_time['end_time']);
                    $shop_coupon['time_slot'] = $begin_time . '-' . $end_time;
                    if (!empty($week_day)) {
                        foreach ($week_day as $week => $weekVal) {
                            switch ($weekVal) {
                                case 1:
                                    $week_day[$week] = "周一";
                                    break;
                                case 2:
                                    $week_day[$week] = "周二";
                                    break;
                                case 3:
                                    $week_day[$week] = "周三";
                                    break;
                                case 4:
                                    $week_day[$week] = "周四";
                                    break;
                                case 5:
                                    $week_day[$week] = "周五";
                                    break;
                                case 6:
                                    $week_day[$week] = "周六";
                                    break;
                                case 0:
                                    $week_day[$week] = "周日";
                                    break;
                            }
                        }
                        $shop_coupon['week_day'] = implode(',', $week_day);
                    }
                    if (!empty($available_day_after_receive) && $available_day_after_receive > 0) {
                        $shop_coupon['available_day_after_receive'] = $available_day_after_receive . "天内有效";
                    }
                    break;
                case 3:
                    //领取后n天后有效
                    $wait_days_after_receive = $coupon_use_rule['coupon_available_time']['wait_days_after_receive'];
                    $shop_coupon['wait_days_after_receive'] = $wait_days_after_receive . "天后生效";
                    $available_day_after_receive = $coupon_use_rule['coupon_available_time']['available_day_after_receive']; //多少天内有效
                    if (!empty($available_day_after_receive) && $available_day_after_receive > 0) {
                        $shop_coupon['available_day_after_receive'] = $available_day_after_receive . "天内有效";
                    }
                    break;
            }
        }
        $available_begin_time = date('Y.m.d H:i:s', $shop_coupon['available_begin_time']); //开始时间
        $available_end_time = date('Y.m.d H:i:s', $shop_coupon['available_end_time']);   //结束时间
        $shop_coupon['time'] = $available_begin_time . '-' . $available_end_time;
        switch ($shop_coupon['store_type']) {
            case 1:
                $shop_coupon['store_type_name'] = '所有门店';
                break;
            case 2:
                $StoreClass = new Store();
                $storeResult = $StoreClass->storeNameList([
                    'store_id_gather' => $shop_coupon['store_id_gather']
                ]);
                if ($storeResult['status'] == 1) {
                    $shop_coupon['store_type_name'] = '可使用门店为' . implode(',', $storeResult['data']['list']);
                }
                break;
        }
        switch ($shop_coupon['goods_type']) {
            case 1:
                $shop_coupon['goods_type_name'] = '所有商品';
                break;
            case 2:
                if (!empty($shop_coupon['goods_id_gather'])) {
                    try {
                        $GoodsClass = new Goods();
                        $goodsResult = $GoodsClass->GoodsNameList([
                            'goods_id_gather' => $shop_coupon['goods_id_gather']
                        ]);
                    } catch (\Exception $e) {
                        return callBack(statusCode()['error'], "未找到该商品");
                    }
                    $shop_coupon['goods_type_name'] = '可使用商品为' . implode(',', $goodsResult['data']['list']);
                }
                break;
        }
        try {
            $paySetModel = new RetailPaySetModel();
            $paySet = $paySetModel->getFindMerchantPaySet($param['merchant_id']);
            if ($paySet['status'] == 0) {
                return callBack(statusCode()['error'], "商户未配置支付");
            }
        } catch (\Exception $e) {
            return callBack(statusCode()['error'], "商户未配置支付");
        }
        $sign = $this->grantCouponSign([
            'merchant_id' => $param['merchant_id'],
            'shop_coupon' => $shop_coupon,
            'paySet' => $paySet
        ]);
        $send_coupon_param = [
            [
                'stock_id' => $shop_coupon['stock_id'],
                'out_request_no' => $sign['data']['out_request_no']
            ]
        ];
        $shop_coupon['send_coupon_param'] = $send_coupon_param;
        $shop_coupon['send_coupon_merchant'] = $shop_coupon['belong_merchant'];
        $shop_coupon['sign'] = $sign['data']['sign'];
        $title = 'http';
        if ($_SERVER['HTTPS'] == 'on') {
            $title .= 's';
        }
        $web_url = $title . '://' . $_SERVER['HTTP_HOST'] . '/index.php/Vip/CouponAuth/couponAuth';
        return callBack(statusCode()['success'], "查询成功", ['info' => $shop_coupon, 'web_url' => $web_url]);
    }


    /**
     * 已领取商家券规则详情
     * @param $param
     * [
     * coupon_id 用户商家券id
     * ]
     * @return mixed
     */
    public function shopCouponRule($param)
    {
        $fields = 's.stock_name,s.available_type,s.available_begin_time,s.available_end_time,s.valid_time_type,
        s.coupon_use_rule,s.store_type,s.store_id_gather,s.goods_type,s.goods_id_gather,r.coupon_code,r.add_time';
        $ShopCouponRecordModel = new ShopCouponRecordModel();
        $shop_coupon = $ShopCouponRecordModel->verificationCouponInfo($fields, [
            'r.id' => $param['coupon_id']
        ]);
        if (empty($shop_coupon)) {
            return callBack(statusCode()['error'], "未找到该商家券");
        }
        $available_type = explode(',', $shop_coupon['available_type']);
        if (count($available_type) > 1) {
            $shop_coupon['available_type_name'] = '线上,门店通用券';
        } else {
            if (in_array(1, $available_type)) {
                $shop_coupon['available_type_name'] .= '线上';
            } else if (in_array(2, $available_type)) {
                $shop_coupon['available_type_name'] .= '门店';
            }
        }
        $coupon_use_rule = json_decode($shop_coupon['coupon_use_rule'], true);
        $shop_coupon['discount_amount'] = $coupon_use_rule['fixed_normal_coupon']['discount_amount']; //优惠金额
        $shop_coupon['transaction_minimum'] = $coupon_use_rule['fixed_normal_coupon']['transaction_minimum']; //消费门槛
        if (!empty($shop_coupon['valid_time_type'])) {
            switch ($shop_coupon['valid_time_type']) {
                case 1:
                    //无规律
                    $irregular_time = $coupon_use_rule['coupon_available_time']['irregulary_avaliable_time']['irregular_time'];
                    $available_begin_time = str_replace("T", " ", $irregular_time[0]);
                    $available_end_time = str_replace("T", " ", $irregular_time[1]);
                    $available_begin_time = str_replace("-", ".", $available_begin_time);
                    $available_end_time = str_replace("-", ".", $available_end_time);
                    $shop_coupon['user_time'] = $available_begin_time . '-' . $available_end_time;
                    break;
                case 2:
                    //固定时间段
                    $available_day_time = $coupon_use_rule['coupon_available_time']['available_week']['available_day_time'];
                    $week_day = $coupon_use_rule['coupon_available_time']['available_week']['week_day'];
                    $available_day_after_receive = $coupon_use_rule['coupon_available_time']['available_day_after_receive']; //多少天内有效
                    $begin_time = str_replace('-', '.', $available_day_time['begin_time']);
                    $end_time = str_replace('-', '.', $available_day_time['end_time']);
                    $shop_coupon['time_slot'] = $begin_time . '-' . $end_time;
                    if (!empty($week_day)) {
                        foreach ($week_day as $week => $weekVal) {
                            switch ($weekVal) {
                                case 1:
                                    $week_day[$week] = "周一";
                                    break;
                                case 2:
                                    $week_day[$week] = "周二";
                                    break;
                                case 3:
                                    $week_day[$week] = "周三";
                                    break;
                                case 4:
                                    $week_day[$week] = "周四";
                                    break;
                                case 5:
                                    $week_day[$week] = "周五";
                                    break;
                                case 6:
                                    $week_day[$week] = "周六";
                                    break;
                                case 0:
                                    $week_day[$week] = "周日";
                                    break;
                            }
                        }
                        $shop_coupon['week_day'] = implode(',', $week_day);
                    }
                    if (!empty($available_day_after_receive) && $available_day_after_receive > 0) {
                        $shop_coupon['available_day_after_receive'] = $available_day_after_receive . "天内有效";
                    }
                    break;
                case 3:
                    //领取后n天后有效
                    $wait_days_after_receive = $coupon_use_rule['coupon_available_time']['wait_days_after_receive'];
                    $shop_coupon['wait_days_after_receive'] = $wait_days_after_receive . "天后生效";
                    $available_day_after_receive = $coupon_use_rule['coupon_available_time']['available_day_after_receive']; //多少天内有效
                    if (!empty($available_day_after_receive) && $available_day_after_receive > 0) {
                        $shop_coupon['available_day_after_receive'] = $available_day_after_receive . "天内有效";
                    }
                    break;
            }
        }
        $available_begin_time = date('Y.m.d H:i:s', $shop_coupon['available_begin_time']); //开始时间
        $available_end_time = date('Y.m.d H:i:s', $shop_coupon['available_end_time']);   //结束时间
        $shop_coupon['time'] = $available_begin_time . '-' . $available_end_time;
        $shop_coupon['add_time'] = date('Y.m.d H:i:s', $shop_coupon['add_time']);
        switch ($shop_coupon['store_type']) {
            case 1:
                $shop_coupon['store_type_name'] = '所有门店';
                break;
            case 2:
                $StoreClass = new Store();
                $storeResult = $StoreClass->storeNameList([
                    'store_id_gather' => $shop_coupon['store_id_gather']
                ]);
                if ($storeResult['status'] == 1) {
                    $shop_coupon['store_type_name'] = '可使用门店为' . implode(',', $storeResult['data']['list']);
                }
                break;
        }
        switch ($shop_coupon['goods_type']) {
            case 1:
                $shop_coupon['goods_type_name'] = '所有商品';
                break;
            case 2:
                if (!empty($shop_coupon['goods_id_gather'])) {
                    $GoodsClass = new Goods();
                    $goodsResult = $GoodsClass->GoodsNameList([
                        'goods_id_gather' => $shop_coupon['goods_id_gather']
                    ]);
                    $shop_coupon['goods_type_name'] = '可使用商品为' . implode(',', $goodsResult['data']['list']);
                }
                break;
        }
        $title = 'http';
        if ($_SERVER['HTTPS'] == 'on') {
            $title .= 's';
        }
        $web_url = $title . '://' . $_SERVER['HTTP_HOST'] . '/index.php/Vip/CouponAuth/couponAuth';
        return callBack(statusCode()['success'], "查询成功", ['shop_coupon' => $shop_coupon, 'web_url' => $web_url]);
    }


    /**
     * 收银机登录会员可用商家券
     * @param $param
     * [
     * merchant_id
     * store_id
     * xcx_id
     * h_coupon_id_redis reids中正在使用的商家券
     * ]
     * @return mixed
     */
    public function getVipShopCouponList($param)
    {
        try {
            $fields = 'r.id,r.coupon_code,r.used_type,r.verification_type,r.add_time,s.app_id,s.type,s.user_type,s.available_type,s.stock_type,
        s.available_begin_time,s.available_end_time,s.valid_time_type,s.coupon_use_rule,s.store_type,s.store_id_gather,
        s.goods_type,s.goods_id_gather,s.stock_name';
            $where = [
                'r.merchant_id' => $param['merchant_id'],
                'r.used_type' => 1,
                'r.verification_type' => 1,
                'r.xcx_id' => $param['xcx_id']
            ];
            if (!empty($param['h_coupon_id_redis'])) {
                $where['r.id'] = ['not in', $param['h_coupon_id_redis']];
            }
            $where['_string'] = "(FIND_IN_SET(2,s.available_type)) AND ((FIND_IN_SET(" . $param['store_id'] . ",s.store_id_gather) and s.store_type=2) OR s.store_type=1)";
            $shopCouponRecordModel = new ShopCouponRecordModel();
            $user_shop_coupon = $shopCouponRecordModel->PlaceOrderCouponList($fields, $where);
        } catch (\Exception $e) {
            return callBack(statusCode()['success'], "查询成功", ['list' => []]);
        }
        $shop_coupon = []; //可用商家券
        foreach ($user_shop_coupon as $key => &$val) {
            $result = $this->verificationCouponTermVerify([
                'shop_coupon' => $val,
                'verification_available_type' => 2, //收银机
                'verification_store_id' => $param['store_id'],
                'verify_goods_type' => 2  //当收银机登录会员获取商家券时不需要验证金额
            ]);
            if ($result['status'] == 1) {
                $val['coupon_choice_type'] = 3; //门店商家券
                $val['coupon_name'] = $val['stock_name'];
                $coupon_use_rule = json_decode($val['coupon_use_rule'], true);
                $val['reduce_money'] = round($coupon_use_rule['fixed_normal_coupon']['discount_amount'], 2); //优惠金额
                $val['need_money'] = round($coupon_use_rule['fixed_normal_coupon']['transaction_minimum'], 2); //消费门槛
                $val['begin_time'] = date('Y-m-d H:i:s', $val['available_begin_time']); //开始时间
                $val['end_time'] = date('Y-m-d H:i:s', $val['available_end_time']);   //结束时间
                $shop_coupon[] = $val;
            }
        }
        return callBack(statusCode()['success'], "查询成功", ['list' => $shop_coupon]);
    }


    /**
     * 收银机下单商家券使用
     * @param $param
     * [
     * coupon_id 用户商家券id
     * allMoney 订单金额
     * store_id 门店id
     * sellDataArray 购买的商品信息
     * ]
     * @return mixed
     * [
     * status
     * message
     * shop_coupon
     * goods 使用商家券的商品信息
     * goods_money 参与优惠的商品总金额
     * ]
     */
    public function cashPlaceOrder($param)
    {
        if (empty($param['coupon_id']) || empty($param['allMoney']) || empty($param['store_id']) || empty($param['sellDataArray'])) {
            return callBack(statusCode()['error'], "未找到该商家券");
        }
        $fields = 'r.coupon_code,r.used_type,r.verification_type,r.add_time,s.app_id,s.type,s.user_type,s.available_type,s.stock_type,
        s.available_begin_time,s.available_end_time,s.valid_time_type,s.coupon_use_rule,s.store_type,s.store_id_gather,
        s.goods_type,s.goods_id_gather';
        $ShopCouponRecordModel = new ShopCouponRecordModel();
        $shop_coupon = $ShopCouponRecordModel->verificationCouponInfo($fields, [
            'r.id' => $param['coupon_id']
        ]);
        if (empty($shop_coupon)) {
            return callBack(statusCode()['error'], "未找到该商家券");
        }
        $result = $this->verificationCouponTermVerify([
            'shop_coupon' => $shop_coupon,
            'verification_available_type' => 2,//核销场景收银机
            'verification_store_id' => $param['store_id'],//核销门店
            'order_money' => $param['allMoney'], //订单金额
            'goods_id_gather' => $param['sellDataArray']    //购买的商品信息
        ]);
        return $result;
    }


    /**
     * 将优惠后的商品信息替换原来购买的商品信息
     * @param $param
     * [
     * sellDataArray 实际购买的商品信息
     * sellDataArray_new 参与优惠的商品信息处理优惠后的商品信息
     * ]
     * @return mixed
     */
    public function sellDataArrayReplace($param)
    {
        $sellDataArray = $param['sellDataArray'];
        $sellDataArray_new = $param['sellDataArray_new'];
        foreach ($sellDataArray as $key => $val) {
            foreach ($sellDataArray_new as $c_key => $c_val) {
                if ($key == $c_key) {
                    $sellDataArray[$key] = $c_val;
                }
            }
        }
        return $sellDataArray;
    }


    /**
     * 获取参与优惠的商品信息
     * @param $param
     * [
     * sellDataArray 实际购买的商品信息
     * shop_coupon_goods 参与优惠的商品信息
     * ]
     * @return mixed
     */
    public function sellDataArray_new($param)
    {
        $sellDataArray = $param['sellDataArray'];
        $shop_coupon_goods = $param['shop_coupon_goods'];
        $sellDataArray_new = [];
        foreach ($sellDataArray as $key => $val) {
            foreach ($shop_coupon_goods as $c_key => $c_val) {
                if ($val['goods_id'] == $c_val) {
                    $sellDataArray_new[$key] = $val;
                }
            }
        }
        $sellDataArray_new = ascSortByFields($sellDataArray_new, 'price');
        return $sellDataArray_new;
    }


    /**
     * 小程序下单商家券使用
     * @param $param
     * [
     * coupon_id 用户商家券id
     * allMoney 订单金额
     * store_id 门店id
     * sellDataArray 购买的商品信息
     * ]
     * @return mixed
     * [
     * status
     * message
     * shop_coupon
     * goods 使用商家券的商品信息
     * goods_money 参与优惠的商品总金额
     * ]
     */
    public function xcxPlaceOrder($param)
    {
        if (empty($param['coupon_id']) || empty($param['allMoney']) || empty($param['store_id']) || empty($param['sellDataArray'])) {
            return callBack(statusCode()['error'], "未找到该商家券");
        }
        $fields = 'r.coupon_code,r.used_type,r.verification_type,r.add_time,s.app_id,s.type,s.user_type,s.available_type,s.stock_type,
        s.available_begin_time,s.available_end_time,s.valid_time_type,s.coupon_use_rule,s.store_type,s.store_id_gather,
        s.goods_type,s.goods_id_gather';
        $ShopCouponRecordModel = new ShopCouponRecordModel();
        $shop_coupon = $ShopCouponRecordModel->verificationCouponInfo($fields, [
            'r.id' => $param['coupon_id']
        ]);
        if (empty($shop_coupon)) {
            return callBack(statusCode()['error'], "未找到改商家券");
        }
        $result = $this->verificationCouponTermVerify([
            'shop_coupon' => $shop_coupon,
            'verification_available_type' => 1,//核销场景小程序
            'verification_store_id' => $param['store_id'],//核销门店
            'order_money' => $param['allMoney'], //订单金额
            'goods_id_gather' => $param['sellDataArray']    //购买的商品信息
        ]);
        return $result;
    }


    /**
     * 小程序普通下单选择可用商家券
     * @param $param
     * [
     * scene_type  1普通下单场景  2预售下单场景
     * merchant_id
     * store_id 门店id
     * shopping_ids 购物车id集合 普通订单使用
     * goods_id  预售订单使用
     * xcx_id 小程序用户id
     * vip_info 会员信息
     * is_integral_cash 是否启用积分抵现1启用  0不启用
     * h_coupon_id_redis redis中正在使用的商家券信息
     * order_money 订单金额
     * ]
     * @return mixed
     */
    public function xcxGetUserPayShopCoupon($param)
    {
        switch ($param['scene_type']) {
            case 1:
                //普通下单
                $result = $this->getShoppingGoods($param);
                $goods = $result['data']['sellDataArray']; //购买的商品信息
                break;
            case 2:
                $goods[] = array(
                    'goods_id' => $param['goods_id'],
                    'all_money' => $param['order_money'],
                );
                break;
        }
        try {
            $fields = 'r.id,r.coupon_code,r.used_type,r.verification_type,r.add_time,s.app_id,s.type,s.user_type,s.available_type,s.stock_type,
        s.available_begin_time,s.available_end_time,s.valid_time_type,s.coupon_use_rule,s.store_type,s.store_id_gather,
        s.goods_type,s.goods_id_gather,s.stock_name';
            $where = [
                'r.merchant_id' => $param['merchant_id'],
                'r.used_type' => 1,
                'r.verification_type' => 1,
                'r.xcx_id' => $param['xcx_id']
            ];
            if (!empty($param['h_coupon_id_redis'])) {
                $where['r.id'] = ['not in', $param['h_coupon_id_redis']];
            }
            $where['_string'] = "(FIND_IN_SET(1,s.available_type))";
            $shopCouponRecordModel = new ShopCouponRecordModel();
            $user_shop_coupon = $shopCouponRecordModel->PlaceOrderCouponList($fields, $where);
        } catch (\Exception $e) {
            return callBack(statusCode()['success'], "查询成功", ['shop_coupon' => []]);
        }
        $shop_coupon = []; //可用商家券
        if (!empty($user_shop_coupon)) {
            foreach ($user_shop_coupon as $key => &$val) {
                $result = $this->verificationCouponTermVerify([
                    'shop_coupon' => $val,
                    'verification_available_type' => 1, //小程序
                    'verification_store_id' => $param['store_id'],
                    'order_money' => $param['order_money'],
                    'goods_id_gather' => $goods
                ]);
                if ($result['status'] == 1) {
                    $val['coupon_choice_type'] = 3; //门店商家券
                    $val['coupon_name'] = $val['stock_name'];
                    $coupon_use_rule = json_decode($val['coupon_use_rule'], true);
                    $val['reduce_money'] = round($coupon_use_rule['fixed_normal_coupon']['discount_amount'], 2); //优惠金额
                    $val['need_money'] = round($coupon_use_rule['fixed_normal_coupon']['transaction_minimum'], 2); //消费门槛
                    $val['begin_time'] = date('Y.m.d', $val['available_begin_time']); //开始时间
                    $val['end_time'] = date('Y.m.d', $val['available_end_time']);   //结束时间
                    $shop_coupon[] = $val;
                }
            }
        }
        return callBack(statusCode()['success'], "查询成功", ['shop_coupon' => $shop_coupon]);
    }


    /**
     * 获取小程序普通下单获取商家券所需的商品信息
     * @param $param
     * [
     * merchant_id
     * store_id 门店id
     * shopping_ids 购物车id集合
     * xcx_id 小程序用户id
     * vip_info 会员信息
     * is_integral_cash 是否启用积分抵现1启用  0不启用
     * ]
     * @return mixed
     */
    public function getShoppingGoods($param)
    {
        try {
            $fields = array(
                's.num',
                's.sku_id',
                's.goods_id',
                'g.online_price',
                'g.shop_mem_status',
                'g.shop_mem_price',
                'g.vip_online_state',
                'g.pricing_method',
                'g.plus_mem_status',
                'g.plus_price',
                'g.attribute_state',
                'h.status as promotion_status',
                'h.act_price',
            );
            $ShoppingModel = new RetailShoppingModel();
            $goods = $ShoppingModel->getShoppingGoods($param['xcx_id'], $param['store_id'], $fields, $param['shopping_ids'], '1,2'); //获取要购买的商品详情
            $vipInfo = $param['vip_info']; //会员信息
            $MerchantConfigModel = new RetailMerchantConfigModel(); //商户设置
            $Config = $MerchantConfigModel->getConfig($param['merchant_id']); //积分设置
            $XcxConfigModel = new RetailStoreXcxConfigModel();
            $promotion_status = $XcxConfigModel->getFindField(array('storeid' => $param['store_id']), 'promotion_status'); //门店促销设置
            $is_integral_cash = $param['is_integral_cash']; //积分抵现
            $SkuGoodsModel = new RetailSkuGoodsModel();
            $sku_map = [
                'state' => 0
            ]; //规格查询公共条件
            $sellDataArray = []; //商品信息
            foreach ($goods as $key => &$value) {
                if (!empty($value['sku_id'])) {
                    $sku_map['id'] = $value['sku_id'];
                    $sku = $SkuGoodsModel->getFind($sku_map);
                    $value['shop_mem_price'] = $sku['shop_mem_price'] > 0 ? $sku['shop_mem_price'] : 0;
                    $value['plus_price'] = $sku['plus_price'] > 0 ? $sku['plus_price'] : 0;
                    $value['online_price'] = $sku['online_price'] > 0 ? $sku['online_price'] : $value['online_price'];
                    $value['shop_mem_integral'] = $sku['shop_mem_integral'] > 0 ? $sku['shop_mem_integral'] : 0;
                    $value['plus_mem_integral'] = $sku['plus_mem_integral'] > 0 ? $sku['plus_mem_integral'] : 0;
                } else {
                    $value['shop_mem_integral'] = $value['shop_mem_integral'] > 0 ? $value['shop_mem_integral'] : 0;
                    $value['plus_mem_integral'] = $value['plus_mem_integral'] > 0 ? $value['plus_mem_integral'] : 0;
                }
                if ($promotion_status != 1) {
                    $value['promotion_status'] = 0;
                } else if ($value['promotion_status'] == 1) {
                    $value['online_price'] = $value['act_price'];
                }
                if ($value['promotion_status'] == 1) {
                    $value['shop_mem_status'] = 2;
                    $value['plus_mem_status'] = 2;
                    $value['vip_online_state'] = 0; // 参加了促销商品 不打折 不优惠
                }
                $price = $value['online_price']; //购买时的角色价格
                $discount = $vipInfo['discount'] && $vipInfo['user_type'] != 1 && $value['vip_online_state'] == 1 && !$value['promotion_status'] ? $vipInfo['discount'] : 1; //会员打折折扣值
                if ($vipInfo && $vipInfo['user_type'] != 1) {
                    //会员
                    if ($vipInfo['user_type'] == 2 && $value['plus_mem_status'] == 1) {
                        //plus会员
                        if ($Config['integral_arrive_cash'] == 1 && $is_integral_cash != 1 && $value['plus_mem_integral'] > 0 && $Config['marketing_methods'] == 2) {
                            $price = $value['online_price']; //商城原价
                        } else {
                            $price = $value['plus_price'];
                        }
                        $discount = 1;
                    } else if ($value['shop_mem_status'] == 1) {
                        //常规会员
                        if ($Config['integral_arrive_cash'] == 1 && $is_integral_cash != 1 && $value['shop_mem_integral'] > 0 && $Config['marketing_methods'] == 2) {
                            $price = $value['online_price']; //商城原价
                        } else {
                            $price = $value['shop_mem_price'];
                        }
                    }
                }
                $money = round($price * $discount * $value['num'], 2);
                $money = $money > 0.01 ? $money : 0.01;
                $sellDataArray[] = array(
                    'goods_id' => $value['goods_id'],
                    'all_money' => $money,
                );
            }
            return callBack(statusCode()['success'], "查询成功", ['sellDataArray' => $sellDataArray]);
        } catch (\Exception $e) {
            return callBack(statusCode()['success'], "查询成功", ['sellDataArray' => []]);
        }
    }


    /**
     * 核销成功用户商家券更新
     * @param $param
     * [
     * coupon_code 用户商家券券码
     * verification_type 核销状态1未核销  2已核销
     * verification_available_type 核销场景 1小程序 2收银机 3公众号
     * verification_store_id 核销的门店
     * operator_id 核销人id  0为小程序用户购买核销
     * use_request_no 核销请求单据号
     * use_time 请求核销时间
     * wechatpay_use_time 核销时间
     *
     * ]
     * @return mixed
     */
    public function couponRecordUpdate($param)
    {
        $where = [
            'coupon_code' => $param['coupon_code']
        ];
        $data = [
            'used_type' => 2,
            'verification_type' => $param['verification_type'],
            'verification_available_type' => $param['verification_available_type'],
            'verification_store_id' => $param['verification_store_id'],
            'operator_id' => $param['operator_id'] ? $param['operator_id'] : 0,
            'use_request_no' => $param['use_request_no'],
            'wechatpay_use_time' => time(),
            'use_time' => $param['use_time'],
            'bill_id' => $param['bill_id'] ? $param['bill_id'] : 0
        ];
        $ShopCouponRecordModel = new ShopCouponRecordModel();
        $result = $ShopCouponRecordModel->updateOrder($where, $data);
        if ($result) {
            return callBack(statusCode()['success'], "商家券核销成功");
        } else {
            return callBack(statusCode()['success'], "商家券核销成功,记录更新失败");
        }
    }


    /**
     * 核销商家券
     * @param $param
     * [
     * openid  用户小程序openid
     * service_openid 服务商openid
     * ordinary_openid 商户公众号的openid
     * coupon_code 用户商家券券码 收银机核销
     * coupon_id 用户商家券id 小程序核销
     * merchant_id
     * verification_available_type 核销场景 1小程序 2收银机 3公众号
     * verification_store_id 核销的门店
     * operator_id 核销人id  0为小程序用户购买核销
     * bill_id 订单id
     * ]
     * @return mixed
     */
    public function verificationCoupon($param)
    {
        $result = $this->getCouponInfo($param);
        if ($result['status'] != 1) {
            return $result;
        }
        $shop_coupon = $result['data']['shop_coupon']; //商家券信息
        $ShopCouponClass = new \ShopCoupon\Business\ShopCoupon();
        $result = $ShopCouponClass->verificationCoupon([
            'merchant_id' => $param['merchant_id'],
            'user_type' => $shop_coupon['user_type'],
            'type' => $shop_coupon['type'],
            'coupon_code' => $shop_coupon['coupon_code'],
            'app_id' => $shop_coupon['app_id'],
            'verification_available_type' => $param['verification_available_type'],
            'verification_store_id' => $param['verification_store_id'],
            'operator_id' => $param['operator_id'] ? $param['operator_id'] : 0,
            'openid' => $param['openid'],
            'service_openid' => $param['service_openid'],
            'ordinary_openid' => $param['ordinary_openid'],
        ]);
        if ($result['status'] == 1) {
            $param['verification_type'] = 2;
        } else {
            $param['verification_type'] = 1;
        }
        $param['use_request_no'] = $result['data']['use_request_no'];
        $param['use_time'] = $result['data']['use_time'];
        $param['coupon_code'] = $shop_coupon['coupon_code'];
        $result = $this->couponRecordUpdate($param); //用户券更新
        return $result;
    }


    /**
     *询商家券信息
     * @param $param
     * [
     * 用户商家券券码 coupon_code 线下
     * 用户商家券 coupon_id 线上
     * merchant_id
     * verification_available_type 核销场景 1小程序 2收银机 3公众号
     * verification_store_id 核销的门店
     * ]
     * @return mixed
     */
    public function getCouponInfo($param)
    {
        $fields = 'r.id,r.coupon_code,r.used_type,r.verification_type,r.add_time,s.app_id,s.type,s.user_type,s.available_type,s.stock_type,
        s.available_begin_time,s.available_end_time,s.valid_time_type,s.coupon_use_rule,s.store_type,s.store_id_gather,
        s.goods_type,s.goods_id_gather';
        $where = [
            'r.merchant_id' => $param['merchant_id'],
            'r.used_type' => 1,
            'r.verification_type' => 1
        ];
        switch ($param['verification_available_type']) {
            case 1:
                //小程序
                $where['r.id'] = $param['coupon_id'];
                break;
            case 2:
                //线下
                if (!empty($param['coupon_id'])) {
                    $where['r.id'] = $param['coupon_id'];
                } else {
                    $where['r.coupon_code'] = $param['coupon_code'];
                }
                break;
        }
        $ShopCouponRecordModel = new ShopCouponRecordModel();
        $shop_coupon = $ShopCouponRecordModel->verificationCouponInfo($fields, $where);
        if (empty($shop_coupon)) {
            return callBack(statusCode()['error'], "未找到可用商家去");
        } else {
            return callBack(statusCode()['success'], "查询成功", ['shop_coupon' => $shop_coupon]);
        }
    }


    /**
     * 商家券条件验证
     * @param $param
     * [
     * shop_coupon 商家券
     * verification_available_type 核销场景 1小程序 2收银机 3公众号
     * verification_store_id 核销的门店
     * order_money 订单的金额
     * goods_id_gather 商品信息集合['goods_id'=>1,'all_money'=>1]
     * verify_goods_type  2 当收银机登录会员或者点击立即使用时获取商家券时不需要验证金额
     * ]
     * @return mixed
     */
    public function verificationCouponTermVerify($param)
    {
        $time = time();
        $shop_coupon = $param['shop_coupon'];
        $available_type = explode(',', $shop_coupon['available_type']);
        $verification_available_type = $param['verification_available_type'];
        if ($param['verification_available_type'] == 3) {
            $verification_available_type = 2; //线下
        }
        if (!in_array($verification_available_type, $available_type)) {
            return callBack(statusCode()['error'], "该券不支持该场景使用");
        }
        if ($shop_coupon['available_begin_time'] > $time || $shop_coupon['available_end_time'] < $time) {
            return callBack(statusCode()['error'], "未在有效时间内");
        }
        if ($shop_coupon['store_type'] == 2) {
            $store_id_gather = explode(',', $shop_coupon['store_id_gather']);
            if (!in_array($param['verification_store_id'], $store_id_gather)) {
                return callBack(statusCode()['error'], "该门店不支持此商家券");
            }
        }
        $coupon_use_rule = json_decode($shop_coupon['coupon_use_rule'], true);
        $transaction_minimum = $coupon_use_rule['fixed_normal_coupon']['transaction_minimum']; //消费门槛
        if (empty($param['verify_goods_type']) || $param['verify_goods_type'] != 2) {
            switch ($shop_coupon['goods_type']) {
                case 1:
                    //所有商品
                    switch ($shop_coupon['stock_type']) {
                        case 1:
                            //满减券
                            if ($param['order_money'] < $transaction_minimum) {
                                return callBack(statusCode()['error'], "未达到消费门槛");
                            }
                            break;
                    }
                    break;
                case 2:
                    //指定商品
                    $names = array();
                    $names = array_reduce($param['goods_id_gather'], create_function('$v,$w', '$v[$w["all_money"]]=$w["goods_id"];return $v;'));
                    $intersection = array_intersect($names, explode(',', $shop_coupon['goods_id_gather'])); //交集
                    $goods = array_flip($intersection);
                    $goods_money = floatval(array_sum($goods)); //商品总金额
                    if ($goods_money < $transaction_minimum) {
                        return callBack(statusCode()['error'], "未达到消费门槛");
                    }
                    break;
            }
        }
        if (!empty($shop_coupon['valid_time_type'])) {
            switch ($shop_coupon['valid_time_type']) {
                case 1:
                    //无规律时间段
                    $irregular_time = $coupon_use_rule['coupon_available_time']['irregulary_avaliable_time']['irregular_time']; //无规律时间段
                    if (!empty($irregular_time)) {
                        $begin_time = strtotime($irregular_time[0]);
                        $end_time = strtotime($irregular_time[1]);
                        if ($begin_time > $time || $end_time < $time) {
                            return callBack(statusCode()['error'], "未在有效时间内");
                        }
                    }
                    break;
                case 2:
                    //固定周期
                    $available_day_time = $coupon_use_rule['coupon_available_time']['available_week']['available_day_time']; //时间段
                    $week_day = $coupon_use_rule['coupon_available_time']['available_week']['week_day'];  //星期
                    if (!empty($week_day)) {
                        $week = date("w", time());
                        if (!in_array($week, $week_day)) {
                            return callBack(statusCode()['error'], "未在有效时间内");
                        }
                    }
                    $begin_time = $available_day_time['begin_time'];
                    $end_time = $available_day_time['end_time'];
                    if (!empty($begin_time) && !empty($end_time)) {
                        $begin_time = strtotime($begin_time);
                        $end_time = strtotime($end_time);
                        if ($begin_time > $time || $end_time < $time) {
                            return callBack(statusCode()['error'], "未在有效时间内");
                        }
                    }
                    $available_day_after_receive = $coupon_use_rule['coupon_available_time']['available_day_after_receive']; //生效内n天有效
                    if (!empty($available_day_after_receive) && $available_day_after_receive > 0) {
                        $receive_time = ($time - $shop_coupon['add_time']) / 86400;
                        if ($receive_time > $available_day_after_receive) {
                            return callBack(statusCode()['error'], "未在有效时间内,领取后" . $available_day_after_receive . "天内有效");
                        }
                    }
                    break;
                case 3:
                    //领取后N天开始生效
                    $wait_days_after_receive = $coupon_use_rule['coupon_available_time']['wait_days_after_receive'];  //领取n天后开始生效
                    $available_day_after_receive = $coupon_use_rule['coupon_available_time']['available_day_after_receive']; //生效内n天有效
                    if (!empty($wait_days_after_receive) && $wait_days_after_receive > 0) {
                        $wait_time = ($time - $shop_coupon['add_time']) / 86400;
                        if ($wait_time < $wait_days_after_receive) {
                            return callBack(statusCode()['error'], "未到有效时间,领取后" . $wait_days_after_receive . "天开始生效");
                        }
                        if (!empty($available_day_after_receive) && $available_day_after_receive > 0) {
                            $receive_time = ($time - ($shop_coupon['add_time'] + 86400 * $wait_days_after_receive)) / 86400;
                            if ($receive_time > $available_day_after_receive) {
                                return callBack(statusCode()['error'], "未在有效时间内,生效后" . $available_day_after_receive . "天内有效");
                            }
                        }
                    }
                    break;
            }
        }
        return callBack(statusCode()['success'], "验证成功", ['shop_coupon' => $shop_coupon, 'goods' => $intersection ? $intersection : [], 'goods_money' => $goods_money ? $goods_money : 0, 'discount_amount' => $coupon_use_rule['fixed_normal_coupon']['discount_amount'], 'transaction_minimum' => $coupon_use_rule['fixed_normal_coupon']['transaction_minimum'], 'id' => $shop_coupon['id'], 'reduce_money' => $coupon_use_rule['fixed_normal_coupon']['discount_amount'], 'need_money' => $coupon_use_rule['fixed_normal_coupon']['transaction_minimum']]);//收银机专用参数
    }


    /**
     * 用户商家券列表
     * @param $param
     * [
     * merchant_id
     * xcx_id
     * type 1可用 2已使用 3已过期
     * page 页码
     * ]
     * @return mixed
     */
    public function userShopCouponList($param)
    {
        $where = [
            's.merchant_id' => $param['merchant_id'],
            's.xcx_id' => $param['xcx_id'],
        ];
        switch ($param['type']) {
            case 1:
                //可使用
                $where['s.used_type'] = 1;
                $where['c.available_end_time'] = ['gt', time()];
                break;
            case 2:
                //已使用
                $where['s.used_type'] = 2;
                break;
            case 3:
                //已过期
                $where['s.used_type'] = 1;
                $where['c.available_end_time'] = ['lt', time()];
                break;
        }
        $fields = 's.id,c.stock_name,c.coupon_use_rule,c.goods_type,c.store_type,c.available_begin_time,c.available_end_time,c.goods_id_gather,c.available_type,c.store_id_gather';
        $page = $param['page'];
        try {
            $ShopCouponModel = new ShopCouponRecordModel();
            $list = $ShopCouponModel->userCouponList($fields, $where, $page, 10);
        } catch (\Exception $e) {
            return callBack(statusCode()['success'], "查询成功", ['list' => []]);
        }
        if ($list) {
            foreach ($list as &$val) {
                switch ($val['goods_type']) {
                    case 1:
                        $val['goods_type_name'] = '所有商品';
                        break;
                    case 2:
                        $val['goods_type_name'] = '部分商品';
                        break;
                }
                $available_type = explode(',', $val['available_type']);
                if (count($available_type) > 1) {
                    $val['available_type_name'] = '线上,门店通用';
                } else {
                    if (in_array(1, $available_type)) {
                        $val['available_type_name'] .= '线上';
                    } else if (in_array(2, $available_type)) {
                        $val['available_type_name'] .= '门店';
                    }
                }
                $coupon_use_rule = json_decode($val['coupon_use_rule'], true);
                $val['discount_amount'] = $coupon_use_rule['fixed_normal_coupon']['discount_amount']; //优惠金额
                $val['transaction_minimum'] = $coupon_use_rule['fixed_normal_coupon']['transaction_minimum']; //消费门槛
                $available_begin_time = date('Y.m.d', $val['available_begin_time']); //开始时间
                $available_end_time = date('Y.m.d', $val['available_end_time']);   //结束时间
                $val['time'] = $available_begin_time . '-' . $available_end_time;
            }
        }
        return callBack(statusCode()['success'], "查询成功", ['list' => $list]);
    }


    /**
     * 领取商家券成功后添加领取记录
     * @param $param
     * [
     * merchant_id
     * store_id
     * coupon_id 商家券主键id
     * xcx_id 小程序用户id
     * stock_id  商家券发券id
     * coupon_code  商家券券码
     * openid  用户openid
     * ]
     * @return mixed
     */
    public function receiveCouponCallback($param)
    {
        $ShopCouponRecordModel = new ShopCouponRecordModel();
        $shop_coupon = $ShopCouponRecordModel->getFind([
            'coupon_code' => $param['coupon_code'],
            'merchant_id' => $param['merchant_id'],
            'xcx_id' => $param['xcx_id']
        ]);
        if (!empty($shop_coupon)) {
            return callBack(statusCode()['error'], "已领取");
        }
        try {
            $content = [
                'merchant_id' => $param['merchant_id'],
                'coupon_id' => $param['coupon_id'],
                'xcx_id' => $param['xcx_id'],
                'openid' => $param['openid'],
                'stock_id' => $param['stock_id'],
                'coupon_code' => $param['coupon_code'],
                'add_time' => time(),
                'store_id' => $param['store_id']
            ];
            $result = $ShopCouponRecordModel->addOrder($content);
            if (!empty($result)) {
                $where = [
                    'id' => $param['coupon_id']
                ];
                $ShopCouponModel = new ShopCouponModel();
                $ShopCouponModel->toSetDec($where, "operation_num", 1);
                return callBack(statusCode()['success'], "领取成功,已存放至卡包");
            } else {
                return callBack(statusCode()['error'], "已存至卡包,领取记录添加失败");
            }
        } catch (\Exception $e) {
            return callBack(statusCode()['error'], "已存至卡包,领取记录添加失败");
        }
    }


    /**
     * 发券签名与商户号
     * @param $param
     * [
     * merchant_id
     * shop_coupon 商家券信息
     * paySet 商户配置
     * ]
     * @return mixed
     */
    public function grantCouponSign($param)
    {
        $paySet = $param['paySet'];
        $shop_coupon = $param['shop_coupon'];
        $out_request_no = onlyCreateKey(); //随机字符串
        switch ($shop_coupon['user_type']) {
            case 1:
                //普通模式
                switch ($shop_coupon['type']) {
                    case 1:
                        //小程序
                        $key = $paySet['config']['xcx_secret_key'];
                        break;
                    case 2:
                        //公众号
                        $key = $paySet['config']['wx_secret_key'];
                        break;
                }
                break;
            case 2:
                //服务商模式
                $key = $paySet['config']['systemConfig']['wx_key'];
                break;
            default:
                return callBack(statusCode()['error'], "暂无法领取该商家券,请联系商家");
                break;
        }
        $SignClass = new Sign();
        $sign = $SignClass->wxHmacSign([
            'stock_id0' => $shop_coupon['stock_id'],
            'send_coupon_merchant' => $shop_coupon['belong_merchant'],
            'out_request_no0' => $out_request_no
        ], $key);
        return callBack(statusCode()['success'], "生成成功", ['stock_id' => $shop_coupon['stock_id'], 'send_coupon_merchant' => $shop_coupon['belong_merchant'], 'out_request_no' => $out_request_no, 'sign' => $sign]);
    }


    /**
     * 领取商家券前判断(2020-8-20已作废)
     * @param $param
     * [
     * merchant_id
     * id 商家券主键id
     * xcx_id 小程序用户id
     * ]
     * @return mixed
     */
    public function grantCouponSignVerify($param)
    {
        if (empty($param['merchant_id']) || empty($param['id']) || empty($param['xcx_id'])) {
            return callBack(statusCode()['error'], "登录超时,请删除小程序重新登录");
        }
        $where = [
            'merchant_id' => $param['merchant_id'],
            'id' => $param['id'],
            'status' => 1,
            'suspend_status' => 1
        ];
        $fields = 'available_end_time,available_type,belong_merchant,stock_id,user_type,type,operation_num';
        $ShopCouponModel = new ShopCouponModel();
        $shop_coupon = $ShopCouponModel->getFind($where, $fields);
        if (empty($shop_coupon)) {
            return callBack(statusCode()['error'], "该商家券已下架,已刷新重试");
        }
        if ($shop_coupon['available_end_time'] < time()) {
            return callBack(statusCode()['error'], "该商家券已过期,请刷新重试");
        }
        if ($shop_coupon['operation_num'] <= 0) {
            return callBack(statusCode()['error'], "该商家券已抢完");
        }
        return callBack(statusCode()['success'], "验证成功", ['shop_coupon' => $shop_coupon]);
    }


    /**
     * 商家券列表
     * @param $param
     * [
     * merchant_id
     * xcx_id 小程序用户id
     * store_id 展示的门店id
     * goods_id 商品详情的商品id
     * couponType 2商家券
     * page
     * limit
     * ]
     * @return mixed
     */
    public function couponList($param)
    {
        try {
            $where = [
                'merchant_id' => $param['merchant_id'],
                'xcx_id' => $param['xcx_id'],
            ];
            $ShopCouponRecord = new ShopCouponRecordModel();
            $user_coupon_id = $ShopCouponRecord->getFindField($where, 'coupon_id', true);
            $where = [
                'merchant_id' => $param['merchant_id'],
                'status' => 1,
                'suspend_status' => 1,
                'available_end_time' => ['egt', time()],
                'operation_num' => ['gt', 0],
            ];
            if (!empty($user_coupon_id)) {
                $where['id'] = ['not in', $user_coupon_id];
            }
            $sql_str = '';
            if (!empty($param['store_id'])) {
                $sql_str .= "((FIND_IN_SET(" . $param['store_id'] . ",store_id_gather) and store_type=2) OR store_type=1)";
            }
            if (!empty($param['goods_id'])) {
                if (!empty($sql_str)) {
                    $sql_str .= ' AND ';
                }
                $sql_str .= "((FIND_IN_SET(" . $param['goods_id'] . ",goods_id_gather) and goods_type=2) OR goods_type=1)";
                $limit = 3;
            } else {
                $limit = $param['limit'] ? $param['limit'] : 10;
            }
            if (!empty($sql_str)) {
                $where['_string'] = $sql_str;
            }
            $page = $param['page'];
            $ShopCouponModel = new ShopCouponModel();
            $list = $ShopCouponModel->getSelect($where, 'id,stock_name,coupon_use_rule,goods_type,store_type,available_begin_time,available_end_time,goods_id_gather,stock_id,user_type,type,belong_merchant,available_type', 'id desc', $page . ',' . $limit);
        } catch (\Exception $e) {
            return callBack(statusCode()['success'], "查询成功", ['list' => []]);
        }
        if ($list) {
            $paySetModel = new RetailPaySetModel();
            $paySet = $paySetModel->getFindMerchantPaySet($param['merchant_id']);
            foreach ($list as &$val) {
                switch ($val['goods_type']) {
                    case 1:
                        $val['goods_type_name'] = '所有商品';
                        break;
                    case 2:
                        $val['goods_type_name'] = '部分商品';
                        break;
                }
                $val['available_type_name'] = '';
                $available_type = explode(',', $val['available_type']);
                if (count($available_type) > 1) {
                    $val['available_type_name'] = '商家券';
                } else {
                    if (in_array(1, $available_type)) {
                        $val['available_type_name'] .= '商家券线上';
                    } else if (in_array(2, $available_type)) {
                        $val['available_type_name'] .= '商家券线下';
                    }
                }
                $coupon_use_rule = json_decode($val['coupon_use_rule'], true);
                $val['discount_amount'] = $coupon_use_rule['fixed_normal_coupon']['discount_amount']; //优惠金额
                $val['transaction_minimum'] = $coupon_use_rule['fixed_normal_coupon']['transaction_minimum']; //消费门槛
                $val['available_begin_time'] = date('Y.m.d', $val['available_begin_time']); //开始时间
                $val['available_end_time'] = date('Y.m.d', $val['available_end_time']);   //结束时间
                //diy辉哥规定的字段设置转换
                if ($param['couponType'] == 2) {
                    $val['begin_time'] = $val['available_begin_time'];
                    $val['end_time'] = $val['available_end_time'];
                    $val['coupon_name'] = $val['stock_name'];
                    $val['need_money'] = $val['transaction_minimum'];
                    $val['reduce_money'] = $val['discount_amount'];
                    $val['use'] = false;
                }
                $sign = $this->grantCouponSign([
                    'merchant_id' => $param['merchant_id'],
                    'xcx_id' => $param['xcx_id'],
                    'shop_coupon' => $val,
                    'paySet' => $paySet
                ]);
                $send_coupon_param = [
                    [
                        'stock_id' => $val['stock_id'],
                        'out_request_no' => $sign['data']['out_request_no']
                    ]
                ];
                $val['send_coupon_param'] = $send_coupon_param;
                $val['send_coupon_merchant'] = $val['belong_merchant'];
                $val['sign'] = $sign['data']['sign'];
            }
        }
        return callBack(statusCode()['success'], "查询成功", ['list' => $list]);
    }
}