精华内容
下载资源
问答
  • 微信商家券开发

    2020-09-17 18:00:27
    微信新版商家券开发 1.公共类 <?php namespace Addons\Pay; //[1.5.52] class WxPayV3 { protected $authorization = 'WECHATPAY2-SHA256-RSA2048'; //认证类型 protected $method = "POST"; protected $url;...

    微信新版商家券开发

    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]);
        }
    }
    
    展开全文
  • 微信商家券支持商户平台使用小结

    千次阅读 2020-11-29 22:53:57
    商家券介绍可以在上述网址中看到,利用微信商家券,可以得到更好的用户触达能力,同时可以更好的提醒用户商家券的到期事件等。应用于广泛的发券场景之中,商家小程序、公众号、H5网页、APP、推文等,也可以在微信...

    基本信息介绍:

    微信支付商家券官方文档地址:https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/marketing/busifavor/chapter1_1.shtml

    商家券介绍可以在上述网址中看到,利用微信商家券,可以得到更好的用户触达能力,同时可以更好的提醒用户商家券的到期事件等。应用于广泛的发券场景之中,商家小程序、公众号、H5网页、APP、推文等,也可以在微信独特的自营渠道(附近发券、支付有礼、朋友圈、商家券推广小程序)中进行投放。利用微信自带的安全防刷风险管控机制,提供广泛的商家内部系统互联机制。

    插入到用户卡包中的商家券详情如下:

    img

    商家券类型: 满减券、换购券、折扣券 - 我理解这三种类型的券实际上和最终的支付行为并无关联,因为有这样一段话

    **说明:**用户是否满足优惠使用门槛条件,以及对应优惠金额或商品均由商家系统自行判断。如满足对应要求后,商家系统再请求微信支付系统核销商家券。

    **发放方式:**自有渠道通过发券插件发放或者通过微信支付平台流量入口进行发放

    **核销方式:**线上小程序核销或者线下扫码枪扫码核销

    集成方式与系统设计:

    微信官方提供的开发指引业务流程时序图如下:

    img

    u1s1我当时看的时候真的是一脸懵逼,而且这张时序图其实是存在一些明显的错误的,基于此我整理出了一个通用的系统架构图,交互时许也用序号标注了出来:

    在这里插入图片描述

    可以看出来我对系统具体的组件划分进行了初步的抽象,将优惠券和用户绑定关系管理作为独立的服务,优惠券是否可以使用通过促销系统进行管控,而商户B端控制页面与C端用户的小程序和移动端接入进行了区分。同时,对于敏感信息的证书密钥商户id小程序id等信息的统一管理配置和第三方集成交互也使用了专门的微服务。

    领券事件:

    在实际的使用过程中,如何在用户通过小程序领券后尽快响应,让用户能尽快看到已经到的优惠券,有两种处理方式。

    1.小程序领券插件与微信官方服务交互之后会得到返回结果中的coupon_id与stock_id,证明该用户在该批次下领券成功,领取优惠券的唯一id就是coupon_id,小程序可以在获得这个信息之后主动向优惠券管理系统告知某个union_id的用户领取了某个stock_id的优惠券,这张券的id是coupon_id;

    2.微信在用户领取商家券之后会通知商户领券事件,需要在优惠券批次配置过程中设置通知的app id,同时需要商户的后台系统暴露接口监听微信的领券事件回调。需要注意的是在我的使用过程中,领券事件回调会存在几百毫秒到2秒钟的延迟,这种情况下如果用户领取优惠券之后立即跳转到自己的商户卡包,是没办法看到新领取的优惠券对应的商户券(如果商户不维护自己的卡券系统,和微信公用一套卡券包的话,就不存在这个问题)

    展开全文
  • 微信小程序:微信商家券的领取

    千次阅读 2020-12-20 10:40:26
    微信小程序:微信商家券的领取 微信在去年推出了商家券,我前不久才接触,在制作领取程序的时候由于网上相关的资料很少,所以 走了不少弯路。 主要问题 这里可以注意到,微信券的领取需要传递三个参数,坑爹的是,...

    微信小程序:微信商家券的领取

    微信在去年推出了商家券,我前不久才接触,在制作领取程序的时候由于网上相关的资料很少,所以 走了不少弯路。

    主要问题

    在这里插入图片描述
    这里可以注意到,微信券的领取需要传递三个参数,坑爹的是,当我们点击领取之后他在最开始就会把参数传递过去,并不会给我们时间去组织参数。这对于有选择性领券的小程序(类似于礼券商城)是相当不友好的,因为我们只有在确定领取的是哪张券之后才能开始组织参数并计算签名,而这就意味着我们在点击领取按钮之前必须先进行选择按钮的点击,这就大大影响了小程序的用户体验,我一开始碰到这个问题的时候也是觉得不可思议的,在网上查了很多资料,最后实在没办法了询问了公司的微信技术助手,得到的明确回复是,小程序l领券插件是不支持在发送请求之前组织参数,那就没办法了。
    我的补救措施是:

    增加一个领取界面,在选择界面选择完所需的商家券之后在领取界面领取,这样就在点击领取按钮之前就已经组织好了参数,虽然还是需要点击两次按钮,但是逻辑上就说得过去了。

    具体的案例可以参考微信小程序:CoCo都可限时优惠+

    在这里插入图片描述
    签名的计算是不能在小程序里面进行的,这一点在文档里面说的很清楚,曾经的粗心让我尝试过在小程序里面获取签名,结果自然是报错:签名错误。
    微信签名检验工具

    https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=20_1

    选择自定义参数检验

    查看发券结果

    发券步骤完成后,通过查看回调函数参数detail,可以查看发券结果:
    在这里插入图片描述

    小程序发券插件API开发文档:

    https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/marketing/miniprogram/chapter3_1.shtml

    展开全文
  • 用于微信V3版商家券小程序发券插件签名的生成。 https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter9_3_1.shtml 二.注意事项 1.虽然是V3版本的微信支付,但是发券的插件签名用的还是V2的接口规则。 接口...

    一.使用范围

    用于微信V3版商家券小程序发券插件签名的生成。

    https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter9_3_1.shtml

    二.注意事项

    1.虽然是V3版本的微信支付,但是发券的插件签名用的还是V2的接口规则。

    接口规则: 本接口使用V2版本接口规则。详见https://pay.weixin.qq.com/wiki/doc/api/wxpay_v2/jiekouguize/chapter1_1.shtml

    2.注意,生成sgin必须全部参数都参与才行,不然签名就是错误的,如果是指定CODE,注意时间字段customize_send_time也要参与签名,带上0

    3.重中之重

    1)这个商户号,一定是商户号,不是子商户号

    发券商户号send_coupon_merchantstring[8,15]发券商户号
    示例值:10016226

    2)key一定是V2版本的key,不要用V3的

    V2key位置:

    V3key位置:

    3)签名方式一定要用 HMAC-SHA256

    4)签名源串请按照示例参数格式进行拼接,参数顺序按照字典序排列

    5)参数名严格区分大小写

    4.签名校验工具

    https://pay.weixin.qq.com/wiki/doc/api/wxpay_v2/jiekouguize/tool.shtml

    三.代码

    1.主方法

    /**
     * 微信商户号(注意是商户号,不是子商户号)
     */
    
    public static String WECHAT_MCHID;
    
    /**
     * 微信api密钥V2
     */
    public static String WECHAT_APIV2KEY;
    
    public static String getSginForWeixinCoupon(List<SendCouponParam> sendCouponParams) throws Exception {
        Map<String, String> params = new HashMap<String, String>();
        for (int i = 0; i < sendCouponParams.size(); i++) {
            SendCouponParam sendCouponParam =  sendCouponParams.get(i);
            params.put("coupon_code"+i,sendCouponParam.getCoupon_code());
            params.put("out_request_no"+i,sendCouponParam.getOut_request_no());
            params.put("stock_id"+i,sendCouponParam.getStock_id());
            params.put("customize_send_time"+i,sendCouponParam.getCustomize_send_time());
        }
        params.put("send_coupon_merchant",WECHAT_MCHID);
    
        String key = WECHAT_APIV2KEY; //这里是微信V2api密钥
        String string = createSign(params);
        String stringSignTemp = string + "key=" + key;
        Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
        SecretKeySpec secret_key = new SecretKeySpec(key.getBytes(), "HmacSHA256");
        sha256_HMAC.init(secret_key);
        //  utf-8 : 解决中文加密不一致问题,必须指定编码格式
        String sgin = byteArrayToHexString(sha256_HMAC.doFinal(stringSignTemp.getBytes("utf-8"))).toUpperCase();
        System.out.println("sing:"+s);
        // 返回签名
        return sgin;
    }

    2.对参数排序,并拼接成字符串

        public static String createSign(Map<String, String> params){
            List<Map.Entry<String, String>> infoIds = new ArrayList<Map.Entry<String, String>>(params.entrySet());
            // 对所有传入参数按照字段名的 ASCII 码从小到大排序(字典序)
            Collections.sort(infoIds, new Comparator<Map.Entry<String, String>>() {
    
                @Override
                public int compare(Map.Entry<String, String> o1, Map.Entry<String, String> o2) {
                    return (o1.getKey()).toString().compareTo(o2.getKey());
                }
            });
            // 构造签名键值对的格式
            StringBuilder sb = new StringBuilder();
            for (Map.Entry<String, String> item : infoIds) {
                if (item.getKey() != null || item.getKey() != "") {
                    String key = item.getKey();
                    String val = item.getValue();
                    if (!(val == "" || val == null)) {
                        sb.append(key + "=" + val + "&");
                    }
                }
            }
            return sb.toString();
        }

    3.将加密后的字节数组转换成字符串

        private static String byteArrayToHexString(byte[] b) {
            StringBuilder hs = new StringBuilder();
            String stmp;
            for (int n = 0; b!=null && n < b.length; n++) {
                stmp = Integer.toHexString(b[n] & 0XFF);
                if (stmp.length() == 1) {
                    hs.append('0');
                }
                hs.append(stmp);
            }
            return hs.toString().toLowerCase();
        }

    4.小程序领取卡券微信小程序发券插件参数模板

    @Data
    public class SendCouponParams {
    
        @ApiModelProperty("微信卡券id即商家券批次号stock_id")
        private String stock_id;
    
        @ApiModelProperty("微信商家券发券凭证")
        private String 	out_request_no;
    
        @ApiModelProperty("卡券核销码即券code coupon_code")
        private String coupon_code;
    
        @ApiModelProperty("自定义领取时间即customize_send_time")
        private String customize_send_time;
    
    }

     

    展开全文
  • 微信商家券回调参数样式 1.微信回调的参数分两部分,这里两部分参数都要用的! A.Body { "id":"8b33f79f-8869-5ae5-b41b-3c0b59f957d0", "create_time":"2019-12-12T16:54:38+08:00", "resource_type":...
  • 拼多多平台的优惠是可以帮商家有效提高店铺的转化率和客单价的,所以商家也可以通过设置优惠劵来获取流量,那么这个优惠劵要如何设置,能不能叠加,叠加之后的价格是怎么算的。商家可以了解一下的哦。 一、活动...
  • @Slf4j public class WxStocksInterfaceInvoker { /** * 创建商家券 */ public static StockCreateResponse createStocks(StockCreateRequest stockCreateRequest) { String responseStr = null; try { **...
  • API结构 1.0.4.RELEASE更新日志 微信支付 feat: 增加微信支付商家券相关接口WechatMarketingBusiFavorApi,商家券请阅读相关产品文档。 feat: 代金券功能增加发放消费卡接口。 refactor: 现在app支付、小程序支付...
  • 熟客优惠券商家

    2015-10-18 15:27:19
    熟客优惠APP是关注于老客户服务领域、基于LBS服务的本地生活服务类O2O移动互联网产品,商家版主要包含优惠收发、优惠统计及我的商铺功能。 应用价值: 1、 优惠管理:替代纸质优惠实时查询优惠使用情况,...
  • 微信小程序 同城商家联盟优惠小程序 2.0.5 更新安装一体包
  • 62769同城社区 6.6.69+商家优惠+分销
  • 米花同城社区 7.5.8 商家优惠 分销
  • 62769 米花同城社区V7.5.2+商家优惠+分销 原版.rar62769 米花同城社区V7.5.2+商家优惠+分销 原版.rar
  • 腾讯直播优惠能力商家接入文档.rar
  • 腾讯直播优惠能力商家接入文档.pdf
  • 同城商家联盟优惠小程序 V2.0.5 全开源解密版.rar
  • 互联网时代优惠商家们的福音还是噩耗.docx
  • 米花同城社区7.0.0
  • 24团购网给商家的信、分析报告与协议合同书.docx
  • 5月18日消息,为助力五月全国消费促进月,各商家品牌纷纷在线上线下展开促销活动。据支付宝方面发布的消息,今起上千万商家在支付宝开启新一轮“云促销”,覆盖餐饮、商超、快消及休闲娱乐等线下服务...
  • 乐得同城优惠券系统 更新日志:V1.9.0 201904更新[增加]拼团券(商家后台设定成团人数,第一拼团人为团长可邀请会员为其助力,达到成团人数即可以优惠价格或免费获取商家券。拼团成功后团长会收到
  • 仅供学习交流使用,不提供技术支持
  • [增加]拼团券(商家后台设定成团人数,第一拼团人为团长可邀请会员为其助力,达到成团人数即可以优惠价格或免费获取商家券。拼团成功后团长会收到站内信息提示,然后领券。拼团券在后台券类型中添加); [增加]后台...
  • 一、关于领淘宝优惠还能拿返利 以前我也加了很多优惠群,再里面也领过很多淘宝优惠,还逛过"什么值得买" 逛丢”等这样购物资讯网站,也为自己家里增添了很多实用的小宝贝,让我确实便宜了很多钱,...
  • 淘宝天猫优惠

    2019-03-24 20:35:10
    淘宝天猫优惠免费领取工具,根据淘宝商家推广信息,免费获取优惠
  • 为了吸引顾客消费,配合营销活动的开展,很多商家都会制作诸如打折、满减、代金等优惠,发送给门店会员以及潜在顾客。收到优惠的顾客朋友,因为有更优惠的消费渠道,自然也乐意到门店来购买或者体验产品...
  • 本拓展主要让用户在淘宝天猫或者拼多多的购物中能挖掘出商家的优惠。能够在显显眼的地方提醒提示用户下单前先领取优惠。让用户可以少掏钱,商家销量也会更多,双赢。具体功能如下: 1、可以跳转到搜索优惠页面...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 10,913
精华内容 4,365
关键字:

商家券