优惠券模板

接入 Ping++ 优惠券模板模块接口,仅需要 Ping++ Server SDK 即可。服务器需要做的就是向 Ping++ 请求创建 Coupon Template 对象,具体步骤如下:

  1. 设置 API-Key
  2. SDK 验证签名设置
  3. 从服务端发起创建优惠券模板请求,获取 Coupon Template 对象

第一步:设置 API-Key

Ping++ API 请求时需要设置 API-Key,Server SDK 提供了设置的方法。如果你直接使用 API ,需要在 header 中加入 Authorization,格式是 Authorization: Bearer API-Key。

\Pingpp\Pingpp::setApiKey('sk_test_ibbTe5jLGCi5rzfH4OqPW9KC');
Pingpp.apiKey = "sk_test_ibbTe5jLGCi5rzfH4OqPW9KC";
var pingpp = require('pingpp')('sk_test_ibbTe5jLGCi5rzfH4OqPW9KC');
pingpp.api_key = 'sk_test_ibbTe5jLGCi5rzfH4OqPW9KC'
Pingpp.api_key = "sk_test_ibbTe5jLGCi5rzfH4OqPW9KC"
pingpp.Key = "sk_test_ibbTe5jLGCi5rzfH4OqPW9KC"
Pingpp.Pingpp.SetApiKey("sk_test_ibbTe5jLGCi5rzfH4OqPW9KC");

第二步:SDK 验证签名设置

为了进一步增强交易请求的安全性,Ping++ 交易接口针对所有的 POST 和 PUT 请求已经新增 RSA 加密验签功能。如果使用该签名验证功能,你需要生成密钥,然后将私钥配置到你的代码中,公钥上传至 Ping++ 管理平台并启用验签开关。首先你需要本地生成 RSA 公钥和私钥,生成方法请参考:如何获取 RSA 公钥和私钥?

设置请求签名密钥

你需要在代码中设置请求签名的私钥(rsa_private_key.pem),可以读取配置私钥文件的路径或者直接定义变量。你如果通过 API 接口校验的话,需要生成 RSA 签名(SHA256)并在请求头中添加 Pingplusplus-Signature,如果使用 SDK 的话只需要配置私钥即可。

\Pingpp\Pingpp::setPrivateKeyPath(__DIR__ . '/your_rsa_private_key.pem');
Pingpp.privateKeyPath = "/path/to/your_rsa_private_key.pem";
pingpp.setPrivateKeyPath(__dirname + "/your_rsa_private_key.pem");
pingpp.private_key_path = 'your_rsa_private_key.pem'
Pingpp.private_key_path = File.dirname(__FILE__) + '/your_rsa_private_key.pem'
privateKey, err := ioutil.ReadFile("your_rsa_private_key.pem")
Pingpp.Pingpp.SetPrivateKeyPath(@"../../your_rsa_private_key.pem");

上传公钥至 Ping++ 管理平台

设置完代码中的私钥,你需要将已经生成的公钥(rsa_public_key.pem)填写到 Ping++ 管理平台上。 配置路径: 登录 Ping++ 管理平台->点击右上角公司名称->企业面板->开发参数->商户 RSA 公钥->将你的公钥复制粘贴进去并且保存->先启用 Test 模式进行测试->测试通过后启用 Live 模式

rsa_keys_setting

注意: 一旦上传公钥至 Ping++ 管理平台并启用 Live 模式,则验证签名功能即时生效,Ping++ 会立即验证你的真实线上交易验签请求。如果私钥为空或错误,则会交易失败,所以请确保测试模式正常后再启用 Live 开关。

第三步:从服务端发起优惠券模板请求,获取 Coupon Template 对象

调用 Ping++ Server SDK 发起创建优惠券模板请求,发起请求所需参数具体可参考 API 文档

try {
$ct = \Pingpp\CouponTemplate::create(['name' = > '25OFF', // 优惠券模板名称
'type' = > 2, // 优惠券模板的类型 1:现金券;2:折扣券
'percent_off' = > 25, // 折扣百分比, 如 20 表示 8 折, 100 表示免费
'amount_available' = > 10000, // 订单金额大于等于该值时,优惠券有效(适用于满减);0 表示无限制
'max_circulation' = > 1000, // 优惠券最大生成数量,当已生成数量达到最大值时,不能再生成优惠券;默认 null,表示可以无限生成
'metadata' = > [], // metadata
'expiration' = > null // 优惠券模板过期策略
]);
echo $ct; // 输出 Ping++ 返回的 Coupon template 对象
} catch (\Pingpp\Error\Base $e) {
if ($e - > getHttpStatus() != null) {
header('Status: '.$e - > getHttpStatus());
echo $e - > getHttpBody();
} else {
echo $e - > getMessage();
}
}
exit;
@Test
public void testCouponTemplateCreate() throws RateLimitException, APIException, ChannelException, InvalidRequestException, APIConnectionException, AuthenticationException {
Map < String, Object > params = new HashMap < String, Object > ();
params.put("name", "25%OFF"); // 优惠券模板名称, 可选
params.put("type", 2); // 优惠券模板的类型 1:现金券;2:折扣券, 必传
params.put("percent_off", 25); // 折扣百分比, 如 20 表示 8 折, 100 表示免费。当 type 为 2 时,必传。
params.put("amount_available", 1000); // 订单金额大于等于该值时,优惠券有效(适用于满减);0 表示无限制, 可选
params.put("max_circulation", 1000); // 优惠券最大生成数量,当已生成数量达到最大值时,不能再生成优惠券;默认 null,表示可以无限生成, 可选
Map < String, Object > metadata = new HashMap < String, Object > ();
metadata.put("custom_key", "custom_value");
params.put("metadata", metadata);
Map < String, Object > expiration = new HashMap < String, Object > ();
Long duration = new Long(2592000);
expiration.put("duration", duration);
params.put("expiration", expiration); // 优惠券模板过期策略
CouponTemplate obj = CouponTemplate.create(params);
assertEquals("object should be coupon_template", "coupon_template", obj.getObject());
assertEquals("amount_available", params.get("amount_available"), obj.getAmountAvailable());
assertEquals("max_circulation", params.get("max_circulation"), obj.getMaxCirculation());
assertEquals("type", params.get("type"), obj.getType());
assertEquals("name", params.get("name"), obj.getName());
assertEquals("percent_off", params.get("percent_off"), obj.getPercentOff());
assertEquals("expiration duration", expiration.get("duration"), obj.getExpiration().getDuration());
assertEquals("times_circulated", 0, obj.getTimesCirculated().intValue());
assertEquals("times_redeemed", 0, obj.getTimesRedeemed().intValue());
}
pingpp.couponTemplates.create(
APP_ID, // APP ID
{
"name": "25OFF",
// 优惠券模板名称
"type": 1,
// 优惠券模板的类型 1:现金券;2:折扣券
"amount_off": 1,
// 折扣金额
"amount_available": 10000,
// 订单金额大于等于该值时,优惠券有效(适用于满减);0 表示无限制
"max_circulation": 1000,
// 优惠券最大生成数量,当已生成数量达到最大值时,不能再生成优惠券;默认 null,表示可以无限生成
"metadata": {},
"expiration": null
}, function(err, data) {
if (err != null) {
console.log("pingpp.couponTemplates.create fail:", err)
}
// YOUR CODE
});
# api_key获取方式:登录 [Dashboard](https: //dashboard2.pingxx.com)->点击管理平台右上角公司名称->企业面板->开发参数->基础密钥->Test Secret Key 和 Live Secret Key
pingpp.api_key = 'sk_test_ibbTe5jLGCi5rzfH4OqPW9KC'
app_id = 'app_1Gqj58ynP0mHeX1q'
pingpp.private_key_path = os.path.join(
os.path.dirname(os.getcwd()), 'your_rsa_private_key.pem')
# app_id支持全局配置
pingpp.app_id = app_id
try :params = {
"name": "25OFF",
#优惠券模板名称"type": 2,
#优惠券模板的类型1:现金券;2:折扣券,
"percent_off": 25,
#折扣百分比,
20表示8折,
100表示免费。当type为2时,必传。"amount_available": 10000,
#订单金额大于等于该值时,优惠券有效(适用于满减);0表示无限制"max_circulation": 1000,
#优惠券最大生成数量,当已生成数量达到最大值时,不能再生成优惠券;默认null,表示可以无限生成# "amount_off": 10,
#折扣金额。当type为1时,必传。"metadata": {},
"expiration": {
"time_start": 1503658305,
#指定起始时间戳(time_start)、结束时间戳(time_end),如果不指定,表示没有限制。"time_end": 1506250305,
},
"refundable": True #退款时是否恢复优惠券
}
#创建优惠券模板
new_coupon = pingpp.CouponTemplate.create(app = app_id, * * params)
print(new_coupon)
should "execute should return a new coupon_template when passed correct parameters"
do
ctmpl = Pingpp::CouponTemplate.create({
#类型required | integer;优惠券模板的类型1:现金券;2:折扣券: type = > 1,
#折扣金额conditional | integer;当type为1时,必传。: amount_off = > 30,
#折扣百分比conditional | integer;例: 20表示8折,
100表示免费。当type为2时,必传。#: percent_off = > 15,
# optional | integer;订单金额大于等于该值时,优惠券有效(适用于满减);0表示无限制,默认0。: amount_available = > 100,
})
assert ctmpl.kind_of ? (Pingpp::CouponTemplate)
end
func(c * CouponTmplDemo) New()( * pingpp.CouponTmpl, error) {
params: = & pingpp.CouponTmplParams {
Type: couponTemplate.CASH_COUPON,
Amount_off: 10,
}
return couponTemplate.New(c.demoAppID, params)
}
public static void Example(string appId) {
var couTmplParams = new Dictionary < string,
object > {
{
"name", "20-percent-off"
}, {
"type", 2
}, // 1:现金券 2:折扣券
{
"percent_off", 20
}, {
"amount_available", 50000
}, // 满减属性:满 500 可用
{
"max_circulation", 100
}, // 优惠券最大生成数量
{
"expiration", new Dictionary < string, object > {
{
"duration", 604800
}
}
}
};
var couTmpl = CouponTemplate.Create(appId, couTmplParams);
Console.WriteLine("****创建 Coupon Template 对象****");
Console.WriteLine(couTmpl);
Console.WriteLine();
}

Ping++ 收到优惠券模板请求后返回给你的服务器一个 Coupon Template 对象,下面是 Coupon Template 的一个示例:

{
"id": "300116082415452100000700",
"object": "coupon_template",
"app": "APP_ID",
"amount_available": 10000,
"amount_off": 25,
"created": 1470904889,
"expiration": null,
"livemode": false,
"max_circulation": 1000,
"max_user_circulation":1,
"metadata": {
},
"name": "25OFF",
"percent_off": null,
"refundable": true,
"times_circulated": 0,
"times_redeemed": 0,
"type": 1
}

优惠券模板查询

Ping++ 提供优惠券模板查询接口可以查询单个优惠券模板以及优惠券模板列表。具体可参考:优惠券模板查询接口

单个优惠券模板查询

$coupon_tmpl_id = '300216111711073000022301'; // ping++返回的优惠券模板 ID
try {
$ct = \Pingpp\CouponTemplate::retrieve($coupon_tmpl_id);
echo $ct;
} catch (\Pingpp\Error\Base $e) {
if ($e - > getHttpStatus() != null) {
header('Status: '.$e - > getHttpStatus());
echo $e - > getHttpBody();
} else {
echo $e - > getMessage();
}
}
exit;
@Test public void testCouponTemplateRetrieve() throws RateLimitException, APIException, ChannelException, InvalidRequestException, APIConnectionException, AuthenticationException {
String couponTemplateId = "300117082315262900016402";
// 查询优惠券模板方法
// 参数: couponTemplateId (优惠券模板 id)
CouponTemplate obj = CouponTemplate.retrieve(couponTemplateId);
assertEquals("object should be coupon_template", "coupon_template", obj.getObject());
}
pingpp.couponTemplates.retrieve(
APP_ID, // APP ID
"300117083118440300048601", // 优惠券模板 ID
function(err, data) {
if (err != null) {
console.log("pingpp.couponTemplates.retrieve fail:", err)
}
// YOUR CODE
});
retr_coupon_templ = pingpp.CouponTemplate.retrieve(new_coupon.id)
print(retr_coupon_templ)
should "execute should return an exist coupon_template when passed correct id"
do
ctmpl = Pingpp::CouponTemplate.retrieve(get_coupon_template_id)
assert ctmpl.kind_of ? (Pingpp::CouponTemplate)
assert ctmpl.object == 'coupon_template'
assert ctmpl.id == get_coupon_template_id
end
func(c * CouponTmplDemo) Get()( * pingpp.CouponTmpl, error) {
return couponTemplate.Get(c.demoAppID, c.demoCouponTmplID)
}
Console.WriteLine("****查询 Coupon Template 对象****");
Console.WriteLine(CouponTemplate.Retrieve(appId, couTmpl.Id));
Console.WriteLine();

优惠券模板列表查询

$search_params = [ //搜索条件,此数组可以为空
'page' = > 1, //页码,取值范围:1~1000000000;默认值为"1"
'per_page' = > 2 //每页数量,取值范围:1~100;默认值为"20"
];
try {
$ct_all = \Pingpp\CouponTemplate::all($search_params);
echo $ct_all; // 输出 Ping++ 返回的 Coupon template 对象列表
} catch (\Pingpp\Error\Base $e) {
if ($e - > getHttpStatus() != null) {
header('Status: '.$e - > getHttpStatus());
echo $e - > getHttpBody();
} else {
echo $e - > getMessage();
}
}
@Test public void testCouponTemplateList() throws RateLimitException, APIException, ChannelException, InvalidRequestException, APIConnectionException, AuthenticationException {
Map < String, Object > params = new HashMap < > ();
params.put("page", 1);
params.put("per_page", 3);
// 查询优惠券模板列表
// 参数: params
CouponTemplateCollection objs = CouponTemplate.list(params);
assertEquals("object should be list", "list", objs.getObject());
}
pingpp.couponTemplates.list(
APP_ID, // APP ID
{
page: 1
}, function(err, datas) {
if (err != null) {
console.log("pingpp.couponTemplates.list fail:", err)
}
// YOUR CODE
});
coupon_templ_list = pingpp.CouponTemplate.list()
print(coupon_templ_list)
should "execute should return a coupon_template list when passed correct parameters"
do
ctmpl = Pingpp::CouponTemplate.list({: per_page = > 3
})
assert ctmpl.kind_of ? (Pingpp::ListObject)
assert ctmpl.data.count <= 3
assert ctmpl.data[0].kind_of ? (Pingpp::CouponTemplate)
end
func(c * CouponTmplDemo) List()( * pingpp.CouponTmplList, error) {
params: = & pingpp.PagingParams {}
params.Filters.AddFilter("page", "", "1") //页码,取值范围:1~1000000000;默认值为"1"
params.Filters.AddFilter("per_page", "", "2") //每页数量,取值范围:1~100;默认值为"20"
return couponTemplate.List(c.demoAppID, params)
}
Console.WriteLine("****查询 Coupon Template 对象列表****");
Console.WriteLine(CouponTemplate.List(appId));
Console.WriteLine();

注意事项

  1. 优惠券模板可以在自定义字段(metadata)中传入商品品类限制信息等,在客户端使用时检查该字段,控制该优惠券是否可用。(由商户自行实现这部分逻辑)
  2. 优惠券模板需要在向用户发放优惠券之前创建。

下一步优惠券发放