1120 lines
58 KiB
PHP
1120 lines
58 KiB
PHP
<?php
|
||
/**
|
||
* SaaSMall商城系统 - 团队十年电商经验汇集巨献!
|
||
* =========================================================
|
||
* Copy right 2019-2029 成都SAAS云科技有限公司, 保留所有权利。
|
||
* ----------------------------------------------
|
||
* 官方网址: https://www.gobuysaas.com
|
||
* =========================================================
|
||
*/
|
||
|
||
namespace addon\coupon\model;
|
||
|
||
use addon\wechatpay\model\Config;
|
||
use addon\weapp\model\Config as weAppConfig;
|
||
use addon\wechatpay\model\V3;
|
||
use app\model\BaseModel;
|
||
use think\Exception;
|
||
|
||
|
||
/**
|
||
* Common: 卡卷 - 微信端操作【小程序&公众号】
|
||
* 代金券开发文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter9_1_1.shtml
|
||
*
|
||
* Author: wu-hui
|
||
* Time: 2023/06/13 10:27
|
||
* Class CouponWeChat
|
||
* @package addon\coupon\model
|
||
*/
|
||
class CouponWeChat extends BaseModel{
|
||
|
||
private $app;
|
||
private $siteId;
|
||
private $mchId;
|
||
private $subMchId;
|
||
private $payConfig;
|
||
// 偏移时间;单位(秒);由于卡卷开始使用时间不能低于当前时间,所以在开始时间计算后需要添加偏移时间,保证开始时间参数正确
|
||
private $offsetTime = 5;
|
||
// 微信卡卷相关消息通知地址
|
||
private $notifyUrl;
|
||
// 商户模式:true=服务商模式;false=普通模式
|
||
private $stortMode = false;
|
||
|
||
|
||
/**
|
||
* Common: 基本配置初始化
|
||
* Author: wu-hui
|
||
* Time: 2023/06/13 10:43
|
||
* CouponWeChat constructor.
|
||
* @param int|string $siteId 平台id
|
||
* @param string $source 渠道:mini=小程序,wechat=公众号
|
||
* @throws Exception
|
||
*/
|
||
public function __construct($siteId){
|
||
// 域名相关信息处理
|
||
$domainName = request()->domain();
|
||
$this->notifyUrl = $domainName . '/pay/notify/weChatCoupon';
|
||
// 平台id获取
|
||
$this->siteId = (int)$siteId;
|
||
if($this->siteId <= 0) throw new Exception('缺少必要字段site_id!');
|
||
// 实例化请求数据
|
||
$this->app = $this->api();
|
||
}
|
||
/**
|
||
* Common: 请求配置
|
||
* Author: wu-hui
|
||
* Time: 2023/06/28 14:20
|
||
* @return V3
|
||
* @throws \app\exception\ApiException
|
||
*/
|
||
private function api(){
|
||
// 普通模式
|
||
$payConfig = (new Config())->getPayConfig($this->siteId)['data']['value'];
|
||
if($this->stortMode){
|
||
// 服务商模式
|
||
$subConfig = $payConfig;
|
||
$payConfig = config('wechat.ispPay');
|
||
$payConfig['v3_pay_signkey'] = $payConfig['v3_signkey'] ?? '';
|
||
$payConfig['sub_mch_id'] = $subConfig['mch_id'] ?? '';
|
||
$payConfig['sub_pay_signkey'] = $subConfig['pay_signkey'] ?? '';
|
||
$payConfig['sub_v3_pay_signkey'] = $subConfig['v3_pay_signkey'] ?? '';
|
||
}
|
||
$this->payConfig = $payConfig;
|
||
if($payConfig) {
|
||
$payConfig['site_id'] = $this->siteId;
|
||
$this->subMchId = $payConfig['mch_id'] ?? '';
|
||
return (new V3($payConfig));
|
||
}
|
||
}
|
||
/**
|
||
* Common: 发起请求
|
||
* Author: wu-hui
|
||
* Time: 2023/06/28 14:40
|
||
* @param String $api
|
||
* @param array $params
|
||
* @param String $type
|
||
* @return mixed
|
||
* @throws Exception
|
||
*/
|
||
private function requestApi(String $api,array $params,String $type = 'post'){
|
||
$result = $this->app->requestApi($api,$params,$type);
|
||
|
||
if($result['code'] == 0) return $result['data'];
|
||
else throw new Exception($result['message']);
|
||
}
|
||
|
||
|
||
/**
|
||
* Common: 商家券 —— 创建
|
||
* Author: wu-hui
|
||
* Time: 2023/06/29 15:59
|
||
* @param $data
|
||
* @return mixed
|
||
* @throws Exception
|
||
*/
|
||
public function storeAdd($data){
|
||
// 发布参数获取
|
||
$params = $this->storeAddParams($data);
|
||
// 发起请求
|
||
return $this->requestApi('v3/marketing/busifavor/stocks',$params);
|
||
}
|
||
/**
|
||
* Common: 商家券 —— 创建参数获取
|
||
* Author: wu-hui
|
||
* Time: 2023/06/29 15:57
|
||
* @param $data
|
||
* @return array
|
||
* @throws Exception
|
||
*/
|
||
private function storeAddParams($data){
|
||
$maxMoney = 10000000;// 金额限制 1千万(满减券-优惠金额、消费门槛;折扣券-消费门槛)
|
||
// 商品可用描述 1=全部商品参与;2=指定商品参与
|
||
$goodsName = $data['goods_type'] == 1 ? '全部商品参与' : '指定商品参与';
|
||
// 批次类型 reward=满减;discount=折扣
|
||
$stockType = $data['type'] == 'reward' ? 'NORMAL' : 'DISCOUNT';
|
||
// 有效期时间信息获取 商家券有效期最长为1年
|
||
[$startTime,$endTime] = $this->storeAddParamsTime($data);
|
||
$startTimeText = date("c",$startTime);
|
||
$endTimeText = date("c",$endTime);
|
||
// 获取配置信息
|
||
$weAppConfig = (new weAppConfig())->getWeappConfig($this->siteId)['data']['value'];
|
||
$appid = $weAppConfig['appid'];
|
||
$path = '/pages_market/goods/list';
|
||
// 判断:发放数量 & 领取数量
|
||
if((int)$data['count'] > 10000000 || (int)$data['count'] < 1) throw new Exception('发放数量应在1~1千万之间!');
|
||
if((int)$data['max_fetch'] > 100) throw new Exception('每个用户可领取数量应在1~100之间!');
|
||
// 凭据号
|
||
$outRequestNo = 'S'.date('YmdHi') . (string)rand(10000, 99999);
|
||
// 配置请求参数
|
||
$params = [
|
||
'stock_name' => $data['coupon_name'],// 批次名称,字数上限为21个,一个中文汉字/英文字母/数字均占用一个字数。
|
||
'belong_merchant' => $this->subMchId,// 批次归属商户号。
|
||
'goods_name' => $goodsName,// 用来描述批次在哪些商品可用,会显示在微信卡包中。字数上限为15个
|
||
'stock_type' => $stockType,// 批次类型:NORMAL=固定面额满减券;DISCOUNT=折扣券;EXCHANGE=换购券
|
||
// 核销规则
|
||
'coupon_use_rule' => [
|
||
// 券可核销时间
|
||
'coupon_available_time' => [
|
||
'available_begin_time' => $startTimeText,// 开始时间;商家券有效期最长为1年 例如:2015-03-20T13:29:35+08:00
|
||
'available_end_time' => $endTimeText,// 结束时间;商家券有效期最长为1年 例如:2015-05-20T13:29:35+08:00
|
||
],
|
||
// 核销方式:OFF_LINE=线下滴码核销;MINI_PROGRAMS=线上小程序核销;PAYMENT_CODE=微信支付付款码核销;SELF_CONSUME=用户自助核销(暂不支持)
|
||
'use_method' => 'MINI_PROGRAMS',
|
||
'mini_programs_appid' => $appid,// 小程序appid;use_method=MINI_PROGRAMS 必填
|
||
'mini_programs_path' => $path,// 小程序path;use_method=MINI_PROGRAMS 必填
|
||
],
|
||
// 发放规则
|
||
'stock_send_rule' => [
|
||
'max_coupons' => (int)$data['count'],// 批次最大可发放个数限制;特殊规则:取值范围 1 ≤ value ≤ 1000000000
|
||
'max_coupons_per_user' => (int)$data['max_fetch'],// 用户最大可领个数;用户可领个数,每个用户最多100张券
|
||
'natural_person_limit' => TRUE,// 【否】是否开启自然人限制;true=是,false=否(默认)
|
||
'prevent_api_abuse' => TRUE,// 【否】可疑账号拦截;true=是,false=否(默认)
|
||
],
|
||
'out_request_no' => $outRequestNo,// 商户创建批次凭据号(格式:商户id+日期+流水号),商户侧需保持唯一性
|
||
// 【否】自定义入口 卡详情页面,可选择多种入口引导用户。
|
||
'custom_entrance' => [
|
||
// 【否】小程序入口
|
||
'mini_programs_info' => [
|
||
'mini_programs_appid' => $appid,// 商家小程序appid
|
||
'mini_programs_path' => $path,// 商家小程序path
|
||
'entrance_words' => '查看详情',// 入口文案;字数上限为5个,一个中文汉字/英文字母/数字均占用一个字数。
|
||
],
|
||
'code_display_mode' => 'QRCODE',//【否】code展示模式:NOT_SHOW=不展示code;BARCODE=一维码;QRCODE=二维码
|
||
],
|
||
// 券code模式:WECHATPAY_MODE=系统分配,MERCHANT_API=商户发放时接口指定券code,MERCHANT_UPLOAD=商户上传自定义code,发券时系统随机选取上传的券code。
|
||
'coupon_code_mode' => 'WECHATPAY_MODE',
|
||
// 【否】事件通知配置 事件回调通知商户的配置
|
||
'notify_config' => [
|
||
'notify_appid' => $appid,// 【否】事件通知appid;小程序or公众号的APPID;不填则回调通知中涉及到用户身份信息的openid与unionid都将为空
|
||
],
|
||
];
|
||
// 根据 【批次类型】 配置使用规则
|
||
$atLeast = (int)((float)$data['at_least'] * 100);// 消费门槛(单位分)
|
||
if($atLeast > $maxMoney || $atLeast < 1) throw new Exception("消费门槛应在1元~1千万元之间");
|
||
if($stockType == 'NORMAL'){
|
||
// 固定面额满减券
|
||
$money = (int)((float)$data['money'] * 100);// 优惠金额(单位分)
|
||
if($money > $maxMoney || $money < 1) throw new Exception("优惠金额应在1元~1千万元之间");
|
||
$params['coupon_use_rule']['fixed_normal_coupon'] = [
|
||
'discount_amount' => $money,// 优惠金额,单位:分。取值范围 1 ≤ value ≤ 10000000
|
||
'transaction_minimum' => $atLeast,// 消费门槛,单位:分。特殊规则:取值范围 1 ≤ value ≤ 10000000
|
||
];
|
||
}else{
|
||
// 折扣券
|
||
$discount = (float)((float)$data['discount'] * 10);
|
||
if($discount <= 0 || $discount > 100) throw new Exception("折扣无效,折扣应在0.1~9.9之间!");
|
||
$params['coupon_use_rule']['discount_coupon'] = [
|
||
'discount_percent' => $discount,// 折扣百分比,例如:86为八六折。
|
||
'transaction_minimum' => $atLeast,// 消费门槛,单位:分。特殊规则:取值范围 1 ≤ value ≤ 10000000
|
||
];
|
||
}
|
||
|
||
|
||
return $params;
|
||
// ---- 全部参数
|
||
/*$params = [
|
||
'stock_name' => '',// 批次名称,字数上限为21个,一个中文汉字/英文字母/数字均占用一个字数。
|
||
'belong_merchant' => '',// 批次归属于哪个商户。
|
||
'comment' => '',// 【否】仅配置商户可见,用于自定义信息。字数上限为20个,
|
||
'goods_name' => '',// 用来描述批次在哪些商品可用,会显示在微信卡包中。字数上限为15个
|
||
'stock_type' => '',// 批次类型:NORMAL=固定面额满减券;DISCOUNT=折扣券;EXCHANGE=换购券
|
||
// 核销规则
|
||
'coupon_use_rule' => [
|
||
// 券可核销时间
|
||
'coupon_available_time' => [
|
||
'available_begin_time' => '',// 开始时间,格式为yyyy-MM-DDTHH:mm:ss+TIMEZONE 商家券有效期最长为1年 例如:2015-03-20T13:29:35+08:00
|
||
'available_end_time' => '',// 结束时间,格式为yyyy-MM-DDTHH:mm:ss+TIMEZONE 商家券有效期最长为1年 例如:2015-05-20T13:29:35+08:00
|
||
'available_day_after_receive' => '',// 【否】生效后N天内有效,1=当天,2=明天;以此类推。
|
||
'wait_days_after_receive' => '',// 领取后N天开始生效;领取后立即生效则不填写,第二天则填1,以此类推;最大不能超过30天
|
||
// 【否】固定周期时间段
|
||
'available_week' => [
|
||
'week_day' => '',//0代表周日,1代表周一,以此类推;当填写available_day_time时,week_day必填
|
||
// 当天可用时间段 可以填写多个时间段,最多不超过2个。
|
||
'available_day_time' => [
|
||
[
|
||
'begin_time' => '',// 当天可用开始时间 当天可用开始时间,单位:秒,1代表当天0点0分1秒。
|
||
'end_time' => '',// 当天可用结束时间 当天可用结束时间,单位:秒,86399代表当天23点59分59秒。
|
||
]
|
||
],
|
||
],
|
||
// 【否】无规律的有效时间段 多个无规律时间段,用户自定义字段。
|
||
'irregulary_avaliable_time' => [
|
||
[
|
||
'begin_time' => '',// 开始时间:格式为yyyy-MM-DDTHH:mm:ss+TIMEZONE 例:2015-05-20T13:29:35+08:00
|
||
'end_time' => '',// 结束时间:格式为yyyy-MM-DDTHH:mm:ss+TIMEZONE 例:2015-05-20T13:29:35+08:00
|
||
]
|
||
],
|
||
],
|
||
// 【否】固定面额满减券使用规则 stock_type为NORMAL时必填。
|
||
'fixed_normal_coupon' => [
|
||
'discount_amount' => '',// 优惠金额,单位:分。取值范围 1 ≤ value ≤ 10000000
|
||
'transaction_minimum' => '',// 消费门槛,单位:分。特殊规则:取值范围 1 ≤ value ≤ 10000000
|
||
],
|
||
// 【否】折扣券使用规则 stock_type为DISCOUNT时必填。
|
||
'discount_coupon' => [
|
||
'discount_percent' => '',// 折扣百分比,例如:86为八六折。
|
||
'transaction_minimum'=> '',// 消费门槛,单位:分。特殊规则:取值范围 1 ≤ value ≤ 10000000
|
||
],
|
||
// 【否】换购券使用规则 stock_type为EXCHANGE时必填
|
||
'exchange_coupon' => [
|
||
'exchange_price' => '',//单品换购价,单位:分。特殊规则:取值范围 0 ≤ value ≤ 10000000
|
||
'transaction_minimum' => '',// 消费门槛,单位:分。特殊规则:取值范围 0 ≤ value ≤ 10000000
|
||
],
|
||
// 核销方式:OFF_LINE=线下滴码核销;MINI_PROGRAMS=线上小程序核销;PAYMENT_CODE=微信支付付款码核销;SELF_CONSUME=用户自助核销(暂不支持)
|
||
'use_method' => 'MINI_PROGRAMS',
|
||
'mini_programs_appid' => '',// 小程序appid;use_method=MINI_PROGRAMS 必填
|
||
'mini_programs_path' => '',// 小程序path;use_method=MINI_PROGRAMS 必填
|
||
],
|
||
// 发放规则
|
||
'stock_send_rule' => [
|
||
'max_coupons' => '',// 批次最大可发放个数限制;特殊规则:取值范围 1 ≤ value ≤ 1000000000
|
||
'max_coupons_per_user' => '',// 用户最大可领个数;用户可领个数,每个用户最多100张券
|
||
'max_coupons_by_day' => '',// 【否】单天发放上限个数;stock_type=DISCOUNT或者stock_type=EXCHANGE;取值范围 1 ≤ value ≤ 1000000000
|
||
'natural_person_limit' => '',// 【否】是否开启自然人限制;true=是,false=否(默认)
|
||
'prevent_api_abuse' => '',// 【否】可疑账号拦截;true=是,false=否(默认)
|
||
'transferable' => '',// 【否、未开放】是否允许转赠;true=是,false=否(默认)
|
||
'shareable' => '',// 【否、未开放】是否允许分享链接;true=是,false=否(默认)
|
||
],
|
||
'out_request_no' => '',// 商户创建批次凭据号(格式:商户id+日期+流水号),商户侧需保持唯一性
|
||
// 【否】自定义入口 卡详情页面,可选择多种入口引导用户。
|
||
'custom_entrance' => [
|
||
// 【否】小程序入口
|
||
'mini_programs_info' => [
|
||
'mini_programs_appid' => '',// 商家小程序appid
|
||
'mini_programs_path' => '',// 商家小程序path
|
||
'entrance_words' => '',// 入口文案;字数上限为5个,一个中文汉字/英文字母/数字均占用一个字数。
|
||
'guiding_words' => '',// 【否】引导文案;字数上限为6个,一个中文汉字/英文字母/数字均占用一个字数。
|
||
],
|
||
'appid' => '',// 【否】商户公众号appid;可配置商户公众号,从券详情可跳转至公众号,用户自定义字段。
|
||
'hall_id' => '',// 【否】营销馆id;
|
||
'store_id' => '',// 【否】可用门店id
|
||
'code_display_mode' => 'QRCODE',//【否】code展示模式:NOT_SHOW=不展示code;BARCODE=一维码;QRCODE=二维码
|
||
],
|
||
// 【否】样式信息 创建批次时的样式信息
|
||
'display_pattern_info' => [
|
||
'description' => '',// 【否】使用须知;用于说明详细的活动规则,会展示在代金券详情页。
|
||
'merchant_logo_url' => '',// 【否,建议上传】商户logo;大小需为120像素*120像素;支持JPG/JPEG/PNG格式,且图片小于1M
|
||
'merchant_name' => '',//【否】商户名称;展示上限12个字符。不支持商户自定义
|
||
'background_color' => '',//【否】背景颜色;使用微信指定颜色值,不能自定义
|
||
'coupon_image_url' => '',//【否】券详情图片;1074像素(宽)*603像素(高),图片大小不超过2M,支持JPG/PNG格式
|
||
],
|
||
// 【否】视频号相关信息
|
||
'finder_info' => [
|
||
'finder_id' => '',// 视频号ID
|
||
'finder_video_id' => '',// 视频号视频ID
|
||
'finder_video_cover_image_url' => '',// 视频号封面图;图片尺寸:1074像素(宽)*603像素(高),图片大小不超过2M,支持JPG/PNG格式。
|
||
],
|
||
'coupon_code_mode' => '',// 券code模式:WECHATPAY_MODE=系统分配,MERCHANT_API=商户发放时接口指定券code,MERCHANT_UPLOAD=商户上传自定义code,发券时系统随机选取上传的券code。
|
||
// 【否】事件通知配置 事件回调通知商户的配置
|
||
'notify_config' => [
|
||
'notify_appid' => '',// 【否】事件通知appid;小程序or公众号的APPID;不填则回调通知中涉及到用户身份信息的openid与unionid都将为空
|
||
],
|
||
'subsidy' => '',// 【否】是否允许营销补贴;true=允许,false=否(默认)
|
||
];*/
|
||
}
|
||
/**
|
||
* Common: 商家券 —— 创建参数 - 有效期时间参数获取
|
||
* Author: wu-hui
|
||
* Time: 2023/06/29 15:06
|
||
* @param $data
|
||
* @return array
|
||
*/
|
||
private function storeAddParamsTime($data):array{
|
||
// 0=固定时间,1=领取之日起,2=长期有效 商家券有效期最长为1年
|
||
$startTime = (int)(time() + $this->offsetTime);
|
||
switch((int)$data['validity_type']){
|
||
case 0:
|
||
// 固定时间
|
||
$maxEndTime = strtotime(date('Y-m-d H:i:s', $startTime)." +1 year");
|
||
$endTime = (int)$data['end_time'] > $maxEndTime ? $maxEndTime : (int)$data['end_time'];
|
||
break;
|
||
default:
|
||
$endTime = strtotime(date('Y-m-d H:i:s', $startTime)." +1 year");
|
||
}
|
||
|
||
return [$startTime,$endTime];
|
||
}
|
||
/**
|
||
* Common: 商家券 —— 查看详情
|
||
* Author: wu-hui
|
||
* Time: 2023/06/29 16:15
|
||
* @param $stockId
|
||
* @return mixed
|
||
* @throws Exception
|
||
*/
|
||
public function storeDetail($stockId){
|
||
// 请求参数配置
|
||
$params = [];
|
||
// 发起请求
|
||
return $this->requestApi("v3/marketing/busifavor/stocks/$stockId",$params,'get');
|
||
}
|
||
/**
|
||
* Common: 商家券 —— 核销用户券
|
||
* Author: wu-hui
|
||
* Time: 2023/07/10 16:50
|
||
* @param $stockId
|
||
* @param $couponCode
|
||
* @param $useRequestNo
|
||
* @param string $openId
|
||
* @return mixed
|
||
* @throws Exception
|
||
*/
|
||
public function storeMemberUse($stockId,$couponCode,$useRequestNo,$openId = ''){
|
||
// 获取配置信息
|
||
$weAppConfig = (new weAppConfig())->getWeappConfig($this->siteId)['data']['value'];
|
||
// 发起请求
|
||
$params = [
|
||
'coupon_code' => $couponCode,// 券的唯一标识。
|
||
'stock_id' => $stockId,//微信为每个商家券批次分配的唯一ID
|
||
'appid' => $weAppConfig['appid'],// 支持小程序appid与公众号appid
|
||
'use_time' => date("c",time()),// 商户请求核销用户券的时间;例如:2015-05-20T13:29:35+08:00
|
||
'use_request_no' => $useRequestNo,// 每次核销请求的唯一标识,商户需保证唯一。
|
||
'openid' => $openId,// 【否】用户的唯一标识,做安全校验使用
|
||
];
|
||
|
||
return $this->requestApi("v3/marketing/busifavor/coupons/use",$params);
|
||
}
|
||
/**
|
||
* Common: 商家券 —— 根据过滤条件查询用户券
|
||
* Author: wu-hui
|
||
* Time: 2023/07/10 14:47
|
||
* @param $openid
|
||
* @param int $offset
|
||
* @param string $status
|
||
* @param int $stockId
|
||
* @return mixed
|
||
* @throws Exception
|
||
*/
|
||
public function storeMemberSelect($openid,int $offset = 0,string $status = '',int $stockId = 0){
|
||
// 获取配置信息
|
||
$weAppConfig = (new weAppConfig())->getWeappConfig($this->siteId)['data']['value'];
|
||
// 请求参数配置
|
||
$params = [
|
||
'appid' => $weAppConfig['appid'],// 支持小程序appid与公众号appid
|
||
// 'stock_id' => $stockId,// 【否】微信为每个商家券批次分配的唯一ID,是否指定批次号查询
|
||
// 'coupon_state' => '',// 【否】券状态:SENDED=可用,USED=已核销,EXPIRED=已过期
|
||
'creator_merchant' => $this->subMchId,// 【否】批次创建方商户号,当调用方商户号(即请求头中的商户号)为创建批次方商户号时,该参数必传
|
||
// 'belong_merchant' => '',// 【否】批次归属商户号,当调用方商户号(即请求头中的商户号)为批次归属商户号时,该参数必传
|
||
// 'sender_merchant' => '',// 【否】批次发放商户号,当调用方商户号(即请求头中的商户号)为批次发放商户号时,该参数必传;委托营销关系下,请填写委托发券的商户号
|
||
'offset' => $offset,// 分页页码
|
||
'limit' => 20,// 分页大小
|
||
];
|
||
if($stockId > 0) $params['stock_id'] = $stockId;
|
||
if(!empty($status)) $params['coupon_state'] = $status;
|
||
// 发起请求
|
||
return $this->requestApi("v3/marketing/busifavor/users/$openid/coupons",$params,'get');
|
||
}
|
||
/**
|
||
* Common: 商家券 —— 查询用户单张券详情
|
||
* Author: wu-hui
|
||
* Time: 2023/07/10 15:05
|
||
* @param $openid
|
||
* @param string $couponCode
|
||
* @return mixed
|
||
* @throws Exception
|
||
*/
|
||
public function storeMemberSingleDetail($openid,string $couponCode){
|
||
// 获取配置信息
|
||
$weAppConfig = (new weAppConfig())->getWeappConfig($this->siteId)['data']['value'];
|
||
$appid = $weAppConfig['appid'];// 支持小程序appid与公众号appid
|
||
// 发起请求
|
||
$params = [];
|
||
return $this->requestApi("v3/marketing/busifavor/users/$openid/coupons/$couponCode/appids/$appid",$params,'get');
|
||
}
|
||
/**
|
||
* Common: 商家券 —— 设置商家券事件通知地址
|
||
* Author: wu-hui
|
||
* Time: 2023/07/10 15:08
|
||
* @return mixed
|
||
* @throws Exception
|
||
*/
|
||
public function storeNotifySet(){
|
||
// 请求参数配置
|
||
$params = [
|
||
'mchid' => $this->subMchId,// 微信支付商户的商户号,由微信支付生成并下发,不填默认查询调用方商户的通知URL。
|
||
'notify_url' => $this->notifyUrl,// 商户提供的用于接收商家券事件通知的url地址,必须支持https。
|
||
];
|
||
// 发起请求
|
||
return $this->requestApi("v3/marketing/busifavor/callbacks",$params);
|
||
}
|
||
/**
|
||
* Common: 商家券 —— 查询商家券事件通知地址
|
||
* Author: wu-hui
|
||
* Time: 2023/07/10 15:30
|
||
* @return mixed
|
||
* @throws Exception
|
||
*/
|
||
public function storeNotifySee(){
|
||
// 请求参数配置
|
||
$params = [
|
||
'mchid' => $this->subMchId,// 微信支付商户的商户号,由微信支付生成并下发,不填默认查询调用方商户的通知URL
|
||
];
|
||
// 发起请求
|
||
return $this->requestApi("v3/marketing/busifavor/callbacks",$params,'get');
|
||
}
|
||
/**
|
||
* Common: 商家券 —— 关联订单信息
|
||
* Author: wu-hui
|
||
* Time: 2023/07/10 15:43
|
||
* @param $stockId
|
||
* @param $couponCode
|
||
* @param $outTradeNo
|
||
* @return mixed
|
||
* @throws Exception
|
||
*/
|
||
public function storeOrderJoin($stockId,$couponCode,$outTradeNo){
|
||
$outRequestNo = 'COJ'.date('YmdHi') . (string)rand(10000, 99999);
|
||
// 请求参数配置
|
||
$params = [
|
||
'stock_id' => $stockId,// 微信为每个商家券批次分配的唯一ID,对于商户自定义code的批次,关联请求必须填写批次号
|
||
'coupon_code' => $couponCode,// 券的唯一标识
|
||
'out_trade_no' => $outTradeNo,// 微信支付下单时的商户订单号,欲与该商家券关联的微信支付
|
||
'out_request_no' => $outRequestNo,// 商户创建批次凭据号(格式:商户id+日期+流水号),商户侧需保持唯一性,可包含英文字母,数字,|,_,*,-等内容,不允许出现其他不合法符号。
|
||
];
|
||
// 发起请求
|
||
$result = $this->requestApi("v3/marketing/busifavor/coupons/associate",$params);
|
||
$result['out_request_no'] = $outRequestNo;
|
||
|
||
return $result;
|
||
}
|
||
/**
|
||
* Common: 商家券 —— 取消关联订单信息
|
||
* Author: wu-hui
|
||
* Time: 2023/07/10 16:05
|
||
* @param $stockId
|
||
* @param $couponCode
|
||
* @param $outTradeNo
|
||
* @param $outRequestNo
|
||
* @return mixed
|
||
* @throws Exception
|
||
*/
|
||
public function storeOrderJoinCancel($stockId,$couponCode,$outTradeNo,$outRequestNo){
|
||
// 请求参数配置
|
||
$params = [
|
||
'stock_id' => $stockId,// 微信为每个商家券批次分配的唯一ID,对于商户自定义code的批次,关联请求必须填写批次号
|
||
'coupon_code' => $couponCode,// 券的唯一标识
|
||
'out_trade_no' => $outTradeNo,// 微信支付下单时的商户订单号,欲与该商家券关联的微信支付
|
||
'out_request_no' => $outRequestNo,// 商户创建批次凭据号(格式:商户id+日期+流水号),商户侧需保持唯一性,可包含英文字母,数字,|,_,*,-等内容,不允许出现其他不合法符号。
|
||
];
|
||
// 发起请求
|
||
return $this->requestApi("v3/marketing/busifavor/coupons/disassociate",$params);
|
||
}
|
||
/**
|
||
* Common: 商家券 —— 修改批次预算
|
||
* Author: wu-hui
|
||
* Time: 2023/07/10 17:29
|
||
* @param $stockId
|
||
* @param $num
|
||
* @param $oldNum
|
||
* @param string $type
|
||
* @return mixed
|
||
* @throws Exception
|
||
*/
|
||
public function storeUpdateBudget($stockId,$num,$oldNum,$type = 'max'){
|
||
$modifyBudgetRequestNo = 'UB'.date('YmdHi') . (string)rand(10000, 99999);
|
||
// 请求参数配置
|
||
$params = [
|
||
'modify_budget_request_no' => $modifyBudgetRequestNo,// 修改预算请求单据号
|
||
];
|
||
// 根据修改类型进行处理 type:max=修改批次最大发放个数,day=修改单天发放上限个数
|
||
if($type == 'max'){
|
||
$params['target_max_coupons'] = $num;// 批次最大发放个数 二选一
|
||
$params['current_max_coupons'] = $oldNum;// 当前批次最大发放个数,当传入target_max_coupons大于0时,current_max_coupons必传
|
||
}
|
||
else{
|
||
$params['target_max_coupons_by_day'] = $num;// 单天发放上限个数 二选一
|
||
$params['current_max_coupons_by_day'] = $oldNum;// 当前单天发放上限个数 ,当传入target_max_coupons_by_day大于0时,current_max_coupons_by_day必填
|
||
}
|
||
|
||
// 发起请求
|
||
return $this->requestApi("v3/marketing/busifavor/stocks/$stockId/budget",$params,'patch');
|
||
}
|
||
/**
|
||
* Common: 商家券 —— 修改商家券基本信息(TODO:未对接 - 目前商家券没有需要修改的内容所以暂不对接修改接口)
|
||
* Author: wu-hui
|
||
* Time: 2023/07/11 9:57
|
||
* @param $data
|
||
* @param $id
|
||
* @return mixed
|
||
* @throws Exception
|
||
*/
|
||
public function storeUpdateBaseInfo($data,$id){
|
||
$stockId = model('promotion_coupon_type')->getValue([
|
||
['coupon_type_id','=',$id]
|
||
],'weapp_stock_id');
|
||
// 发布参数获取
|
||
$params = $this->storeUpdateParams($data);
|
||
|
||
// 发起请求
|
||
return $this->requestApi("v3/marketing/busifavor/stocks/$stockId",$params,'patch');
|
||
}
|
||
/**
|
||
* Common: 商家券 —— 编辑参数获取(TODO:未对接 - 目前商家券没有需要修改的内容所以暂不对接修改接口)
|
||
* Author: wu-hui
|
||
* Time: 2023/07/11 9:57
|
||
* @param $data
|
||
* @return array
|
||
*/
|
||
public function storeUpdateParams($data){
|
||
return [
|
||
// 【否】自定义入口 卡详情页面,可选择多种入口引导用户。
|
||
'custom_entrance' => [
|
||
// 【否】小程序入口
|
||
'mini_programs_info' => [
|
||
'mini_programs_appid' => '',// 商家小程序appid
|
||
'mini_programs_path' => '',// 商家小程序path
|
||
'entrance_words' => '查看详情',// 入口文案;字数上限为5个,一个中文汉字/英文字母/数字均占用一个字数。
|
||
'guiding_words' => '', // 小程序入口引导文案,字数上限为6个,一个中文汉字/英文字母/数字均占用一个字数。
|
||
],
|
||
'appid' => '',// 【否】可配置商户公众号,从券详情可跳转至公众号
|
||
'hall_id' => '',// 【否】填写微信支付营销馆的馆id,用户自定义字段。 营销馆需在商户平台 创建
|
||
'code_display_mode' => 'QRCODE',//【否】code展示模式:NOT_SHOW=不展示code;BARCODE=一维码;QRCODE=二维码
|
||
],
|
||
'comment' => '',// 【否】批次备注,仅配置商户可见,用于自定义信息。字数上限为20个
|
||
'goods_name' => '',// 【否】用来描述批次在哪些商品可用,会显示在微信卡包中。字数上限为15个,一个中文汉字/英文字母/数字均占用一个字数。
|
||
'out_request_no' => '',// 商户修改批次凭据号(格式:商户id+日期+流水号),商户侧需保持唯一性。
|
||
// 【否】样式信息 创建批次时的样式信息
|
||
'display_pattern_info' => [
|
||
'description' => '',// 【否】使用须知;用于说明详细的活动规则,会展示在代金券详情页。
|
||
'background_color' => '',//【否】背景颜色;使用微信指定颜色值,不能自定义
|
||
'coupon_image_url' => '',//【否】券详情图片;1074像素(宽)*603像素(高),图片大小不超过2M,支持JPG/PNG格式
|
||
// 【否】视频号相关信息
|
||
'finder_info' => [
|
||
'finder_id' => '',// 视频号ID
|
||
'finder_video_id' => '',// 视频号视频ID
|
||
'finder_video_cover_image_url' => '',// 视频号封面图;图片尺寸:1074像素(宽)*603像素(高),图片大小不超过2M,支持JPG/PNG格式。
|
||
],
|
||
],
|
||
// 【否】核销规则
|
||
'coupon_use_rule' => [
|
||
// 核销方式:OFF_LINE=线下滴码核销;MINI_PROGRAMS=线上小程序核销;PAYMENT_CODE=微信支付付款码核销;SELF_CONSUME=用户自助核销(暂不支持)
|
||
'use_method' => 'MINI_PROGRAMS',
|
||
'mini_programs_appid' => '',// 小程序appid;use_method=MINI_PROGRAMS 必填
|
||
'mini_programs_path' => '',// 小程序path;use_method=MINI_PROGRAMS 必填
|
||
],
|
||
// 【否】发放规则
|
||
'stock_send_rule' => [
|
||
'prevent_api_abuse' => '',// 【否】可疑账号拦截;true=是,false=否(默认)
|
||
],
|
||
// 【否】事件通知配置 事件回调通知商户的配置
|
||
'notify_config' => [
|
||
'notify_appid' => '',// 【否】事件通知appid;小程序or公众号的APPID;不填则回调通知中涉及到用户身份信息的openid与unionid都将为空
|
||
],
|
||
];
|
||
}
|
||
/**
|
||
* Common: 商家券 —— 申请退券
|
||
* Author: wu-hui
|
||
* Time: 2023/07/11 9:14
|
||
* @param $couponCode
|
||
* @param $stockId
|
||
* @return mixed
|
||
* @throws Exception
|
||
*/
|
||
public function storeRefund($couponCode,$stockId){
|
||
$returnRequestNo = 'CR'.date('YmdHi') . (string)rand(10000, 99999);
|
||
// 请求参数配置
|
||
$params = [
|
||
'coupon_code' => $couponCode,// 券的唯一标识
|
||
'stock_id' => $stockId,// 券的所属批次号
|
||
'return_request_no' => $returnRequestNo,// 每次退券请求的唯一标识,商户需保证唯一
|
||
];
|
||
// 发起请求
|
||
$result = $this->requestApi("v3/marketing/busifavor/coupons/return",$params);
|
||
$result['return_request_no'] = $returnRequestNo;
|
||
|
||
return $result;
|
||
}
|
||
/**
|
||
* Common: 商家券 —— 使券失效
|
||
* Author: wu-hui
|
||
* Time: 2023/07/11 9:23
|
||
* @param $couponCode
|
||
* @param $stockId
|
||
* @param string $reason
|
||
* @return mixed
|
||
* @throws Exception
|
||
*/
|
||
public function storeDeactivate($couponCode,$stockId,$reason = ''){
|
||
$returnRequestNo = 'CD'.date('YmdHi') . (string)rand(10000, 99999);
|
||
// 请求参数配置
|
||
$params = [
|
||
'coupon_code' => $couponCode,// 券的唯一标识
|
||
'stock_id' => $stockId,// 券的所属批次号
|
||
'deactivate_request_no' => $returnRequestNo,// 每次失效请求的唯一标识,商户需保证唯一
|
||
];
|
||
if(trim($reason)) $params['deactivate_reason'] = $reason;//失效的原因
|
||
// 发起请求
|
||
$result = $this->requestApi("v3/marketing/busifavor/coupons/deactivate",$params);
|
||
$result['deactivate_request_no'] = $returnRequestNo;
|
||
|
||
return $result;
|
||
}
|
||
|
||
|
||
/**
|
||
* Common: 代金券 —— 发布
|
||
* Author: wu-hui
|
||
* Time: 2023/06/28 14:32
|
||
* @param $data
|
||
* @return mixed
|
||
* @throws Exception
|
||
* @throws \app\exception\ApiException
|
||
*/
|
||
public function voucherAdd($data){
|
||
// 发布参数获取
|
||
$params = $this->voucherParams($data);
|
||
|
||
// 发起请求
|
||
return $this->requestApi('v3/marketing/favor/coupon-stocks',$params);
|
||
}
|
||
/**
|
||
* Common: 代金券 —— 发布 - 请求参数获取
|
||
* Author: wu-hui
|
||
* Time: 2023/06/27 14:01
|
||
* @param $data
|
||
* @return array
|
||
* @throws Exception
|
||
*/
|
||
private function voucherParams($data):array{
|
||
// 时间信息获取
|
||
[$startTime,$endTime] = $this->voucherParamsTime($data);
|
||
$startTimeText = date("c",$startTime);
|
||
$endTimeText = date("c",$endTime);
|
||
// 优惠劵发放数量
|
||
$count = (int)$data['count'];// 设置发放优惠劵数量
|
||
$maxCount = 10000000;
|
||
if($count < 5 || $count > $maxCount) throw new Exception('优惠劵发放数量必须大于5且小于等于1000万!');
|
||
// 优惠劵面额和最高预算(单位:分) 面额-必须为整数、必须大于1元且小于等于500元
|
||
if((float)$data['money'] < 1 || (float)$data['money'] > 500) throw new Exception("优惠劵面额必须大于1元且小于等于500元!");
|
||
$money = (int)((float)$data['money'] * 100);// 金额(单位分)
|
||
$maxMoney = (int)$money * $count;// 最高预算金额(单位分)
|
||
// 最大领取数量
|
||
$maxFetch = (int)$data['max_fetch'];
|
||
if($maxFetch < 1 || $maxFetch > 60 || $maxFetch > $count) throw new Exception('最大领取数量必须大于1且小于等于60且不能超过发放数量!');
|
||
// 使用条件
|
||
$atLeast = (float)($data['at_least'] * 100);
|
||
if($atLeast <= $money) throw new Exception('使用条件金额必须大于优惠劵面额!');
|
||
// 凭据号
|
||
$outRequestNo = 'V'.date('YmdHi') . (string)rand(10000, 99999);
|
||
|
||
// 信息配置
|
||
$paramsConfig = [
|
||
'stock_name' => $data['coupon_name'],// * 批次名称,批次名称最多9个中文汉字、最多20个字母、不能包含不当内容和特殊字符 _ , ; |
|
||
'belong_merchant' => $this->subMchId,// * 归属商户号
|
||
'available_begin_time' => $startTimeText,// * 批次开始时间;开始时间不可早于当前时间、不能创建365天后开始的批次、批次可用时间范围最长为90天 例如:2015-05-20T13:29:35+08:00
|
||
'available_end_time' => $endTimeText,// * 批次结束时间;结束时间需晚于开始时间、可用时间最长为90天、有效时间间隔最短为1s 例如:2015-05-20T13:29:35+08:00
|
||
// 批次使用规则
|
||
'stock_use_rule' => [
|
||
'max_coupons' => $count,// * 最大发券数;发放总个数最少5个、发放总个数最多1000万个
|
||
'max_amount' => $maxMoney,// * 最大发券预算;批次总预算最多1000万元 单位:分 max_amount需要等于coupon_amount(面额) * max_coupons(发放总上限)
|
||
'max_coupons_per_user' => $maxFetch,// * 活动期间每个用户可领个数;不能大于发放总个数、最少为1个,最多为60个
|
||
'natural_person_limit' => true,// * 是否开启自然人限制;多个微信号同属于一个身份证时,视为同一用户,枚举值:true 是、false 否
|
||
'prevent_api_abuse' => true,// * 是否开启防刷拦截;当用户命中恶意、小号、机器、羊毛党、黑产等风险行为时,无法成功发放代金券 是=true、否=false
|
||
],
|
||
// 代金券详情页
|
||
'pattern_info' => [
|
||
'description' => '微信支付营销代金券',// * 使用说明;最多1000个UTF8字符
|
||
],
|
||
// 核销规则
|
||
'coupon_use_rule' => [
|
||
// 固定面额满减券使用规则 stock_type为NORMAL时必填。
|
||
'fixed_normal_coupon' => [
|
||
'coupon_amount' => $money,// 面额,单位:分;必须为整数、必须大于1元且小于等于500元
|
||
'transaction_minimum' => $atLeast,// 使用券金额门槛,单位:分;使用门槛必须大于优惠金额
|
||
],
|
||
'available_merchants' => [$this->subMchId],// 可用商户的交易才可核销/使用代金券
|
||
],
|
||
'no_cash' => true,// 营销经费。枚举值:true:免充值、false:预充值
|
||
'stock_type' => 'NORMAL',// 批次类型,仅支持:NORMAL:固定面额满减券批次
|
||
'out_request_no' => $outRequestNo,// 商户创建批次凭据号
|
||
];
|
||
if($data['goods_ids']) $paramsConfig['coupon_use_rule']['available_items'] = explode(',',$data['goods_ids']);
|
||
|
||
return $paramsConfig;
|
||
|
||
// ---- 全部参数
|
||
// $params = [
|
||
// 'stock_name' => '',// * 批次名称,批次名称最多9个中文汉字、最多20个字母、不能包含不当内容和特殊字符 _ , ; |
|
||
// // 'comment' => '',// 批次备注,批次备注最多60个UTF8字符数
|
||
// 'belong_merchant' => '',// * 归属商户号
|
||
// 'available_begin_time' => '',// * 批次开始时间;开始时间不可早于当前时间、不能创建365天后开始的批次、批次可用时间范围最长为90天
|
||
// 'available_end_time' => '',// * 批次结束时间;结束时间需晚于开始时间、可用时间最长为90天、有效时间间隔最短为1s
|
||
// // 批次使用规则
|
||
// 'stock_use_rule' => [
|
||
// 'max_coupons' => 0, // * 最大发券数;发放总个数最少5个、发放总个数最多1000万个
|
||
// 'max_amount' => '', // * 最大发券预算;批次总预算最多1000万元 单位:分 max_amount需要等于coupon_amount(面额) * max_coupons(发放总上限)
|
||
// // 'max_amount_by_day' => 0, // 单天最大发券预算;不能大于总预算、max_amount_by_day不可以为0
|
||
// 'max_coupons_per_user' => '',// * 活动期间每个用户可领个数;不能大于发放总个数、最少为1个,最多为60个
|
||
// 'natural_person_limit' => true,// *是否开启自然人限制;多个微信号同属于一个身份证时,视为同一用户,枚举值:true 是、false 否
|
||
// 'prevent_api_abuse' => true,// *是否开启防刷拦截;当用户命中恶意、小号、机器、羊毛党、黑产等风险行为时,无法成功发放代金券 是=true、否=false
|
||
// ],
|
||
// // 代金券详情页
|
||
// 'pattern_info' => [
|
||
// 'description' => '',// * 使用说明;最多1000个UTF8字符
|
||
// // 'merchant_logo' => '',// 商户logo;商户logo ,仅支持通过《图片上传API》接口获取的图片URL地址、商户logo大小需为120像素*120像素、支持JPG/JPEG/PNG格式,且图片小于1M、最多128个UTF8字符
|
||
// // 'merchant_name' => '',// 品牌名称;最多12个中文汉字、最多36个英文字符
|
||
// // 'background_color' => '',// 背景颜色;色值需要参考卡券背景颜色图中的颜色值标识、不能直接使用RGB或者16位颜色值
|
||
// // 'coupon_image' => '',// 券详情图片;850像素*350像素,且图片大小不超过2M,支持JPG/PNG格式,仅支持通过《图片上传API》接口获取的图片URL地址。
|
||
// ],
|
||
// // 核销规则
|
||
// 'coupon_use_rule' => [
|
||
// // 允许指定券的特殊生效时间规则 - 该字段暂未开放
|
||
// /*'coupon_available_time' => [
|
||
// // 固定时间段可用
|
||
// 'fix_available_time' => [
|
||
// 'available_week_day' => '',// 允许指定每周固定星期数生效,0代表周日生效,1代表周一生效,以此类推;不填则代表在可用时间内周一至周日都生效。
|
||
// 'begin_time'=> '',// 当天开始时间
|
||
// 'end_time' => '',// 当天结束时间
|
||
// ],
|
||
// 'second_day_available' => '',// 领取后N天有效;领取后,券的开始时间为领券后第二天,如7月1日领券,那么在7月2日00:00:00开始;true=是,false=否
|
||
// 'available_time_after_receive' => '',// 领取后,券的结束时间为领取N天后;单位:分钟
|
||
// ],*/
|
||
// // 固定面额满减券使用规则 stock_type为NORMAL时必填。
|
||
// 'fixed_normal_coupon' => [
|
||
// 'coupon_amount' => '',// 面额,单位:分;必须为整数、必须大于1元且小于等于500元
|
||
// 'transaction_minimum' => '',// 使用券金额门槛,单位:分;使用门槛必须大于优惠金额
|
||
// ],
|
||
// // 'goods_tag' => '',// 订单优惠标记,按json格式;最多允许录入50个、每个订单优惠标记支持字母/数字/下划线,不超过128个UTF8字符
|
||
// // 'limit_pay' => '',// 指定付款方式;可指定零钱付款、指定银行卡付款,需填入支付方式编码、例如:[CFT,ICBC_CREDIT]
|
||
// // 指定银行卡bin付款的交易可核销/使用代金券,当批次限定了指定银行卡时方可生效
|
||
// /*'limit_card' => [
|
||
// 'name' => '',// 银行卡名称
|
||
// 'bin' => '',// 指定卡BIN;使用指定卡BIN的银行卡支付方可享受优惠,按json格式 例如:['62123456','62123457']
|
||
// ],*/
|
||
// // 'trade_type' => [],// 允许指定支付方式的交易才可核销/使用,不填则默认不限:MICROAPP:小程序支付、APPPAY:APP支付、PPAY:免密支付、CARD:刷卡支付、FACE:人脸支付、OTHER:其他支付
|
||
// // 'combine_use' => '',// 允许指定本优惠是否可以和本商户号创建的其他券同时使用,不填则默认允许同时使用。枚举值:true=是、false=否
|
||
// // 'available_items'=> '',// 可核销商品编码;单个商品编码的字符长度为【1,128】、条目个数限制为【1,50】
|
||
// // 'unavailable_items' => '',// 不可核销的商品编码或条目编码;单个商品编码的字符长度为【1,128】、条目个数限制为【1,50】
|
||
// 'available_merchants'=> '',// 可用商户的交易才可核销/使用代金券
|
||
// ],
|
||
// 'no_cash' => '',// 营销经费。枚举值:true:免充值、false:预充值
|
||
// 'stock_type' => 'NORMAL',// 批次类型,仅支持:NORMAL:固定面额满减券批次
|
||
// 'out_request_no' => '',// 商户创建批次凭据号
|
||
// // '商户创建批次凭据号' => [],// 扩展属性字段,按json格式,如无需要则不填写。
|
||
// ];
|
||
}
|
||
/**
|
||
* Common: 代金券 —— 发布 - 请求参数获取(时间参数处理)
|
||
* Author: wu-hui
|
||
* Time: 2023/06/27 11:16
|
||
* @param $data
|
||
* @return array
|
||
* @throws Exception
|
||
*/
|
||
private function voucherParamsTime($data):array{
|
||
switch((int)$data['validity_type']){
|
||
case 0:
|
||
// 固定时间
|
||
$startTime = (int)(time() + $this->offsetTime);
|
||
$maxEndTime = strtotime(date('Y-m-d H:i:s', $startTime)." +90 day");
|
||
$endTime = (int)$data['end_time'];
|
||
// 判断:过期时间不能超出90天
|
||
if($endTime > $maxEndTime) throw new Exception('有效期错误,微信代金券过期时间不能超过90天!');
|
||
break;
|
||
case 1:
|
||
// 领取之日起
|
||
throw new Exception('有效期类型错误,微信代金券禁止使用该类型!');
|
||
break;
|
||
case 2:
|
||
// 长期有效
|
||
throw new Exception('有效期类型错误,微信代金券禁止使用该类型!');
|
||
break;
|
||
default:
|
||
throw new Exception('有效期类型错误,微信代金券禁止使用该类型!');
|
||
}
|
||
|
||
return [$startTime,$endTime];
|
||
}
|
||
/**
|
||
* Common: 代金券 —— 激活代金券批次
|
||
* Author: wu-hui
|
||
* Time: 2023/06/28 14:49
|
||
* @param $stockId
|
||
* @return mixed
|
||
* @throws Exception
|
||
*/
|
||
public function voucherActivation($stockId){
|
||
// 参数获取
|
||
$params = [
|
||
'stock_creator_mchid' => $this->subMchId,// 批次创建方商户号
|
||
];
|
||
// 发起请求
|
||
return $this->requestApi("v3/marketing/favor/stocks/$stockId/start",$params);
|
||
}
|
||
/**
|
||
* Common: 代金券 —— 发放代金券批次
|
||
* Author: wu-hui
|
||
* Time: 2023/06/29 10:21
|
||
* @param $stockId
|
||
* @param $openid
|
||
* @return mixed
|
||
* @throws Exception
|
||
*/
|
||
public function voucherGrant($stockId,$openid){
|
||
// 生成凭据号
|
||
$outRequestNo = $this->subMchId.'NO'. (string)rand(10000, 99999);
|
||
// 获取配置信息
|
||
$weAppConfig = (new weAppConfig())->getWeappConfig($this->siteId)['data']['value'];
|
||
// 参数获取
|
||
$params = [
|
||
'stock_id' => json_encode($stockId),// 批次id
|
||
'out_request_no' => $outRequestNo,// 商户此次发放凭据号
|
||
'appid' => $weAppConfig['appid'],// 小程序appid || 公众号appid || APP的appid
|
||
'stock_creator_mchid' => $this->subMchId,// 批次创建方商户号
|
||
];
|
||
|
||
// 发起请求
|
||
return $this->requestApi("v3/marketing/favor/users/$openid/coupons",$params);
|
||
}
|
||
/**
|
||
* Common: 代金券 —— 暂停代金券批次
|
||
* Author: wu-hui
|
||
* Time: 2023/06/29 9:05
|
||
* @param $stockId
|
||
* @return mixed
|
||
* @throws Exception
|
||
*/
|
||
public function voucherSuspend($stockId){
|
||
// 参数获取
|
||
$params = [
|
||
'stock_creator_mchid' => $this->subMchId,// 批次创建方商户号
|
||
];
|
||
|
||
// 发起请求
|
||
return $this->requestApi("v3/marketing/favor/stocks/$stockId/pause",$params);
|
||
}
|
||
/**
|
||
* Common: 代金券 —— 重启代金券批次
|
||
* Author: wu-hui
|
||
* Time: 2023/06/29 9:06
|
||
* @param $stockId
|
||
* @return mixed
|
||
* @throws Exception
|
||
*/
|
||
public function voucherRestart($stockId){
|
||
// 参数获取
|
||
$params = [
|
||
'stock_creator_mchid' => $this->subMchId,// 批次创建方商户号
|
||
];
|
||
|
||
// 发起请求
|
||
return $this->requestApi("v3/marketing/favor/stocks/$stockId/restart",$params);
|
||
}
|
||
/**
|
||
* Common: 代金券 —— 条件查询批次列表
|
||
* Author: wu-hui
|
||
* Time: 2023/06/28 16:14
|
||
* @param int $offset
|
||
* @return mixed
|
||
* @throws Exception
|
||
*/
|
||
public function voucherBatchList(int $offset = 0){
|
||
// 参数获取
|
||
$params = [
|
||
'offset' => $offset,// 页码从0开始,默认第0页
|
||
'limit' => 10,// 分页大小,最大10
|
||
'stock_creator_mchid' => $this->subMchId,// 创建批次的商户号
|
||
// 'create_start_time' => '',// 起始创建时间 格式:yyyy-MM-DDTHH:mm:ss+TIMEZONE 请求协议url编码
|
||
// 'create_end_time' => '',// 终止创建时间 格式:yyyy-MM-DDTHH:mm:ss+TIMEZONE 请求协议url编码
|
||
// 'status' => '',// 批次状态:unactivated=未激活;audit=审核中;running=运行中;stoped=已停止;paused:暂停发放
|
||
];
|
||
// 发起请求
|
||
return $this->requestApi("v3/marketing/favor/stocks",$params,'get');
|
||
}
|
||
/**
|
||
* Common: 代金券 —— 查询批次详情
|
||
* Author: wu-hui
|
||
* Time: 2023/06/29 9:10
|
||
* @param $stockId
|
||
* @return mixed
|
||
* @throws Exception
|
||
*/
|
||
public function voucherBatchDetail($stockId){
|
||
// 参数获取
|
||
$params = [
|
||
'stock_creator_mchid' => $this->subMchId,// 批次创建方商户号
|
||
];
|
||
|
||
// 发起请求
|
||
return $this->requestApi("v3/marketing/favor/stocks/$stockId",$params,'get');
|
||
}
|
||
/**
|
||
* Common: 代金券 —— 查询代金券详情
|
||
* Author: wu-hui
|
||
* Time: 2023/06/29 10:37
|
||
* @param $openid
|
||
* @param $couponId
|
||
* @return mixed
|
||
* @throws Exception
|
||
*/
|
||
public function voucherDetail($openid,$couponId){
|
||
// 获取配置信息
|
||
$weAppConfig = (new weAppConfig())->getWeappConfig($this->siteId)['data']['value'];
|
||
// 参数获取
|
||
$params = [
|
||
'appid' => $weAppConfig['appid'],// 小程序appid || 公众号appid || APP的appid
|
||
];
|
||
// 发起请求
|
||
return $this->requestApi("v3/marketing/favor/users/$openid/coupons/$couponId",$params,'get');
|
||
}
|
||
/**
|
||
* Common: 代金券 —— 查询代金券可用商户
|
||
* Author: wu-hui
|
||
* Time: 2023/06/29 9:15
|
||
* @param $offset
|
||
* @param $stockId
|
||
* @return mixed
|
||
* @throws Exception
|
||
*/
|
||
public function voucherAvailableMerchants($offset,$stockId){
|
||
// 参数获取
|
||
$params = [
|
||
'offset' => $offset,// 页码从0开始,默认第0页
|
||
'limit' => 10,// 分页大小,最大10
|
||
'stock_creator_mchid' => $this->subMchId,// 创建批次的商户号
|
||
];
|
||
|
||
// 发起请求
|
||
return $this->requestApi("v3/marketing/favor/stocks/$stockId/merchants",$params,'get');
|
||
}
|
||
/**
|
||
* Common: 代金券 —— 查询代金券可用单品
|
||
* Author: wu-hui
|
||
* Time: 2023/06/29 9:17
|
||
* @param $offset
|
||
* @param $stockId
|
||
* @return mixed
|
||
* @throws Exception
|
||
*/
|
||
public function voucherAvailableGoods($offset,$stockId){
|
||
// 参数获取
|
||
$params = [
|
||
'offset' => $offset,// 页码从0开始,默认第0页
|
||
'limit' => 10,// 分页大小,最大10
|
||
'stock_creator_mchid' => $this->subMchId,// 创建批次的商户号
|
||
];
|
||
|
||
// 发起请求
|
||
return $this->requestApi("v3/marketing/favor/stocks/$stockId/items ",$params,'get');
|
||
}
|
||
/**
|
||
* Common: 代金券 —— 根据商户号查用户的券
|
||
* Author: wu-hui
|
||
* Time: 2023/06/29 10:33
|
||
* @param $offset
|
||
* @param $stockId
|
||
* @param $openid
|
||
* @return mixed
|
||
* @throws Exception
|
||
*/
|
||
public function voucherMemberCoupon($offset,$stockId,$openid){
|
||
// 获取配置信息
|
||
$weAppConfig = (new weAppConfig())->getWeappConfig($this->siteId)['data']['value'];
|
||
// 参数获取
|
||
$params = [
|
||
'appid' => $weAppConfig['appid'],// 公众账号ID
|
||
'stock_id' => $stockId,// 批次id
|
||
// 'status' => 'SENDED',//SENDED=返回可用,USED=返回可用+已实扣
|
||
'creator_mchid' => $this->subMchId,// 批次创建方商户号
|
||
'offset' => $offset,// 页码从0开始,默认第0页
|
||
// 'limit' => 10,// 分页大小,默认20
|
||
];
|
||
|
||
// 发起请求
|
||
return $this->requestApi("v3/marketing/favor/users/$openid/coupons",$params,'get');
|
||
}
|
||
/**
|
||
* Common: 代金券 —— 下载批次核销明细
|
||
* Author: wu-hui
|
||
* Time: 2023/06/29 10:42
|
||
* @param $stockId
|
||
* @return mixed
|
||
* @throws Exception
|
||
*/
|
||
public function voucherDownloadBatchUseDetails($stockId){
|
||
// 参数获取
|
||
$params = [];
|
||
|
||
// 发起请求
|
||
return $this->requestApi("v3/marketing/favor/stocks/$stockId/use-flow",$params,'get');
|
||
}
|
||
/**
|
||
* Common: 代金券 —— 下载批次退款明细
|
||
* Author: wu-hui
|
||
* Time: 2023/06/29 10:48
|
||
* @param $stockId
|
||
* @return mixed
|
||
* @throws Exception
|
||
*/
|
||
public function voucherDownloadBatchRefundDetails($stockId){
|
||
// 参数获取
|
||
$params = [];
|
||
|
||
// 发起请求
|
||
return $this->requestApi("v3/marketing/favor/stocks/$stockId/refund-flow",$params,'get');
|
||
}
|
||
/**
|
||
* Common: 代金券 —— 设置消息通知地址;可接收营销相关的事件通知:核销通知
|
||
* Author: wu-hui
|
||
* Time: 2023/06/29 11:23
|
||
* @return mixed
|
||
* @throws Exception
|
||
*/
|
||
public function voucherSetNotify(){
|
||
// 参数获取
|
||
$params = [
|
||
'mchid' => $this->subMchId,
|
||
'notify_url' => $this->notifyUrl,
|
||
// 'switch' => true,// true=开启推送;false=停止推送。 false暂不支持使用,如果想关闭通知请在商户平台关闭券的回调通知
|
||
];
|
||
// 发起请求
|
||
return $this->requestApi("v3/marketing/favor/callbacks",$params);
|
||
}
|
||
|
||
|
||
/**
|
||
* Common: 获取微信优惠券领取信息
|
||
* Author: wu-hui
|
||
* Time: 2023/07/07 15:17
|
||
* @param $info
|
||
* @return array
|
||
*/
|
||
public function getWeAppConfig($info){
|
||
// 判断:如果没有配置信息 则返回空数组
|
||
if(!$this->payConfig) return [];
|
||
// 优惠券信息 每条信息代表领取一张卡券 一次最多可以领取10张
|
||
$outRequestNo = 'WEAPP'.date('YmdHi') . (string)rand(10000, 99999);
|
||
$sendCouponParams = [
|
||
[
|
||
'stock_id' => $info['weapp_stock_id'] ?? 0,//微信支付券批次id
|
||
'out_request_no' => $outRequestNo,//发券凭证,可包含英文字母,数字,|,_,*,-等内容,不允许出现其他不合法符号,需在单个批次单个用户下确保唯一性
|
||
// 'create_coupon_merchant' => $this->subMchId,//创建支付券的商户号;如果是支付券,则是必填项;商家券无需填写
|
||
'customize_send_time' => date("c",time()),// 商家券在商户业务系统里的实际领取时间,目前只支持商家券、支付券暂不支持。示例值:2015-05-20T13:29:35+08:00
|
||
]
|
||
];
|
||
$key = $this->payConfig['pay_signkey'];
|
||
// 生成签名
|
||
$signArr = [];
|
||
foreach($sendCouponParams as $index => &$sendCouponParamsItem){
|
||
// 判断:如果是代金券 需要添加【create_coupon_merchant】字段内容;如果是商家券则不需要该字段
|
||
if($info['weapp_channel'] == 'voucher') $sendCouponParamsItem['create_coupon_merchant'] = $this->subMchId;
|
||
// 循环处理 获取加密数组
|
||
foreach($sendCouponParamsItem as $sendCouponParamsKey => $subSendCouponParamsItem){
|
||
$signArr[$sendCouponParamsKey.$index] = $subSendCouponParamsItem;
|
||
}
|
||
}
|
||
$signArr['send_coupon_merchant'] = $this->subMchId;
|
||
ksort($signArr);
|
||
$signStr = urldecode(http_build_query($signArr))."&key=".$key;
|
||
$sign = strtoupper(hash_hmac("sha256", $signStr, $key));
|
||
|
||
return [
|
||
'send_coupon_params' => $sendCouponParams,
|
||
'sign' => $sign,//签名计算值 签名方式:HMAC-SHA256。
|
||
'send_coupon_merchant' => $this->subMchId,//发券商户号
|
||
];
|
||
}
|
||
|
||
|
||
} |