优惠券发放
接入 Ping++ 优惠券模块接口,仅需要 Ping++ Server SDK 即可。服务器需要做的就是向 Ping++ 请求创建 Coupon 对象,具体步骤如下:
- 设置 API-Key
- SDK 验证签名设置
- 从服务端发起创建优惠券请求,获取 Coupon 对象
第一步:设置 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 模式
注意: 一旦上传公钥至 Ping++ 管理平台并启用 Live 模式,则验证签名功能即时生效,Ping++ 会立即验证你的真实线上交易验签请求。如果私钥为空或错误,则会交易失败,所以请确保测试模式正常后再启用 Live 开关。
第三步:从服务端发起创建优惠券请求,获取 Coupon 对象
调用 Ping++ Server SDK 发起创建优惠券请求,发起请求所需参数具体可参考 API 文档。
$user_id = 'uid582d1756b1650'; // 用户 ID$params = ['coupon_template' = > '300216111619300600019101', // 优惠券模版 ID];try { $cp = \Pingpp\Coupon::create($user_id, $params); echo $cp;} catch (\Pingpp\Error\Base $e) { if ($e - > getHttpStatus() != null) { header('Status: '.$e - > getHttpStatus()); echo $e - > getHttpBody(); } else { echo $e - > getMessage(); }}exit;
public void testCouponCreate() throws RateLimitException, APIException, ChannelException, InvalidRequestException, APIConnectionException, AuthenticationException { String userId = "test_user_001"; // 用户 ID, 必传 Map < String, Object > params = new HashMap < > (); params.put("coupon_template", "300117082315262900016402"); // 优惠券模板 id, 必传 // 创建优惠券 Coupon 方法 // 参数一: userId // 参数二: params Coupon obj = Coupon.create(userId, params); assertEquals("object should be coupon", "coupon", obj.getObject());}
pingpp.coupons.create(APP_ID, // App ID"123", // 用户 ID,{ "coupon_template": "300117083118533800023602", "metadata": {},}, function(err, data) { if (err != null) { console.log("pingpp.coupons.create fail:", err) } console.log(data); // YOUR CODE});
# api_key获取方式:登录 [Dashboard](https: //dashboard2.pingxx.com)->点击管理平台右上角公司名称->企业面板->开发参数->基础密钥->Test Secret Key 和 Live Secret Keypingpp.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 params = { "coupon_template": "300117082817355900186301", "metadata": { "key": "value" }} try :#创建优惠券new_coupon = pingpp.Coupon.create(user = "user_test_001", * * params)print(new_coupon)
should "return a new coupon for user when passed correct parameters"dobegino = Pingpp::Coupon.create({: coupon_template = > existed_coupon_template_id}, {: user = > get_user_id}) assert o.kind_of ? (Pingpp::Coupon)rescue = > eassert e.kind_of ? (Pingpp::InvalidRequestError) || e.kind_of ? (Pingpp::ChannelError)assert e.message.include ? ("已领取") || e.message.include ? ("received")endend
func(c * CouponDemo) New()( * pingpp.Coupon, error) { params: = & pingpp.CouponParams { Coupon_tmpl_id: c.demoCouponTmplID, } return coupon.New(c.demoAppID, "uid582d1756b1650", 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 对象,下面是 Coupon 的一个示例:
{ "id": "COUPON_ID", "object": "coupon", "app": "APP_ID", "actual_amount": null, "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, "metadata": { }, "name": "25 OFF", "percent_off": null, "refundable": true, "times_circulated": 0, "times_redeemed": 0, "type": 1 }, "created": 1470969003, "livemode": false, "metadata": { }, "order": null, "user_times_circulated":1, "redeemed": false, "time_end": 1472265014, "time_start": 1470969010, "user": "USER_ID", "valid": true}
优惠券查询
Ping++ 提供优惠券查询接口可以查询单个优惠券、用户优惠券列表以及优惠券列表。具体可参考优惠券查询接口。
单个优惠券查询
$user_id = 'uid582d1756b1650'; // 用户 ID$coupon_id = '300416111711463500023901'; // 优惠券 IDtry { $cp = \Pingpp\Coupon::retrieve($user_id, $coupon_id); echo $cp;} catch (\Pingpp\Error\Base $e) { if ($e - > getHttpStatus() != null) { header('Status: '.$e - > getHttpStatus()); echo $e - > getHttpBody(); } else { echo $e - > getMessage(); }}exit;
@Test public void testCouponRetrieve() throws RateLimitException, APIException, ChannelException, InvalidRequestException, APIConnectionException, AuthenticationException { String userId = "test_user_001"; String couponId = "300317082315265100025202"; // 查询单个优惠券 Coupon // 参数一: userId // 参数二: couponId (优惠券 id) Coupon obj = Coupon.retrieve(userId, couponId); assertEquals("object should be coupon", "coupon", obj.getObject());}
pingpp.coupons.retrieve(APP_ID, // App ID"123", // 用户 ID"300317083118552300072201", function(err, data) { if (err != null) { console.log("pingpp.coupons.retrieve fail:", err) } // YOUR CODE});
retr_coupon = pingpp.Coupon.retrieve(new_coupon.id, user = "user_test_001")print(retr_coupon)
should "execute should return a coupon object when passed correct parameters"docoupon_id, user_id = coupon_id_and_usercoupon = Pingpp::Coupon.retrieve(coupon_id, {: user = > user_id}) assert coupon.kind_of ? (Pingpp::Coupon)end
func(c * CouponDemo) Get()( * pingpp.Coupon, error) { return coupon.Get(c.demoAppID, c.demoUser, c.demoCouponTmplID)}
Console.WriteLine("****查询 Coupon 对象****");Console.WriteLine(Coupon.Retrieve(appId, uid, cou.Id));Console.WriteLine();
用户优惠券列表查询
$user_id = 'uid582d1756b1650'; // 用户 ID$search_params = [ //搜索条件,此数组可以为空'page' = > 1, //页码,取值范围:1~1000000000;默认值为"1"'per_page' = > 2 //每页数量,取值范围:1~100;默认值为"20"];try { $cp_all = \Pingpp\Coupon::all($user_id, $search_params); echo $cp_all;} catch (\Pingpp\Error\Base $e) { if ($e - > getHttpStatus() != null) { header('Status: '.$e - > getHttpStatus()); echo $e - > getHttpBody(); } else { echo $e - > getMessage(); }}exit;
@Test public void testUserCouponList() throws RateLimitException, APIException, ChannelException, InvalidRequestException, APIConnectionException, AuthenticationException { String userId = "test_user_001"; Map < String, Object > params = new HashMap < > (); params.put("page", 1); params.put("per_page", 3); // 查询用户优惠券 Coupon 列表方法 // 参数一: userId // 参数二: params CouponCollection objs = Coupon.list(userId, params); assertEquals("object should be list", "list", objs.getObject());}
pingpp.coupons.list(APP_ID, // App ID"123", // 用户 ID{ page: 1}, function(err, datas) { if (err != null) { console.log("pingpp.coupons.list fail:", err) } // YOUR CODE});
coupon_list = pingpp.Coupon.list(user = "user_test_001")print(coupon_list)
should "execute should return a coupon when passed correct parameters" do coupons = Pingpp::Coupon.list({: per_page = > 3 }, {: user = > get_user_id }) assert coupons.kind_of ? (Pingpp::ListObject) assert coupons.data.count <= 3 assert coupons.data[0].kind_of ? (Pingpp::Coupon) end
func(c * CouponDemo) List()( * pingpp.CouponList, error) { params: = & pingpp.PagingParams {} params.Filters.AddFilter("page", "", "1") //页码,取值范围:1~1000000000;默认值为"1" params.Filters.AddFilter("per_page", "", "2") //每页数量,取值范围:1~100;默认值为"20" // params.Filters.AddFilter("redeemed", "", "false") //查询用户未核销优惠券 return coupon.UserList(c.demoAppID, c.demoUser, params)}
Console.WriteLine("****查询用户的 Coupon 对象列表****");Console.WriteLine(Coupon.List(appId, uid));Console.WriteLine();
优惠券列表查询
$coupon_tmpl_id = '300216111711085500022401'; // ping++返回的优惠券模板 IDtry { $cp = \Pingpp\CouponTemplate::couponsList($coupon_tmpl_id); echo $cp;} catch (\Pingpp\Error\Base $e) { if ($e->getHttpStatus() != null) { header('Status: ' . $e->getHttpStatus()); echo $e->getHttpBody(); } else { echo $e->getMessage(); }}exit;
@Test public void testCouponList() throws RateLimitException, APIException, ChannelException, InvalidRequestException, APIConnectionException, AuthenticationException { String couponId = "300117082315262900016402"; Map < String, Object > params = new HashMap < > (); params.put("page", 1); params.put("per_page", 3); // 查询优惠券模板下的优惠券列表 // 参数一: userId // 参数二: params CouponCollection objs = CouponTemplate.listCoupons(couponId, params); assertEquals("object should be list", "list", objs.getObject());}
pingpp.couponTemplates.listCoupons(APP_ID, // APP ID"300117083118482700048701", // 优惠券模板 ID{ page: 1}, function(err, datas) { if (err != null) { console.log("pingpp.couponTemplates.listCoupons fail:", err) } // YOUR CODE}); // YOUR CODE });
tmpl_coupon_list = pingpp.CouponTemplate.retrieve_coupons(coupon_tmpl = new_coupon.id)print(tmpl_coupon_list)
should "execute should return a coupon list made from coupon_template when passed correct coupon_template_id"docoupons = Pingpp::CouponTemplate.list_coupons(get_coupon_template_id, {: per_page = > 3}) assert coupons.kind_of ? (Pingpp::ListObject)assert coupons.object == 'list'assert coupons.data.count <= 3end
func(c * CouponTmplDemo) CouponList()( * pingpp.CouponList, error) { params: = & pingpp.PagingParams {} params.Filters.AddFilter("page", "", "1") params.Filters.AddFilter("per_page", "", "2") params.Filters.AddFilter("redeemed", "", "false") //查询用户未核销优惠券 return couponTemplate.CouponList("app_1Gqj58ynP0mHeX1q", "300216101014204500032301", params)}
Console.WriteLine("****查询模板下的 Coupon 对象列表****");Console.WriteLine(Coupon.ListInTemplate(appId, cou.Id));Console.WriteLine();
注意事项
- 订单创建时会检查优惠券 ID 是否属于订单消费用户,以及优惠券是否过期。
- 优惠券会在订单取消时自动退还。
- 订单全额退款时是否退还优惠券可以在优惠券模板中配置。
下一步多级商户系统