分润模板

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

  1. 设置 API-Key
  2. SDK 验证签名设置
  3. 从服务端发起创建分润模板请求,获取 Royalty 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 开关。

第三步:从服务端发起创建分润模板请求,获取 Royalty Template 对象

调用 Ping++ Server SDK 发起创建分润模板请求。

try {
$royalty_template = \Pingpp\RoyaltyTemplate::create(['app' = > \Pingpp\Pingpp::getAppId(), //应用 ID
'name' = > 'royalty_template_name', // 分润模板名称,允许中英文等常用字符
'rule' = > ['royalty_mode' = > 'rate', //分润模式。分为按订单金额(包含优惠券金额)的比例 rate 和固定金额 fixed
'refund_mode' = > 'no_refund', //退分润模式。分为退款时不退分润 no_refund、按比例退分润 proportional 和一旦退款分润全退 full_refund
'allocation_mode' = > 'receipt_reserved', //分配模式。指当订单确定的层级如果少于模板配置层级时,模板中多余的分润金额是归属于收款方 receipt_reserved 还是服务方 service_reserved。
'data' = > [
['level' = > 1, //子商户层级值,0 表示平台, 1 表示一级子商户,取值范围 >=0
'value' = > 30 //分润数值。rate 下取值为 0 - 10000,单位为 0.01 %,fixed 下取值为 0 - 1000000,单位为分
],
['level' = > 2, 'value' = > 20],
['level' = > 3, 'value' = > 10], ], ], 'description' = > 'Your description', ]);
echo $royalty_template;
} catch (\Pingpp\Error\Base $e) {
// 捕获报错信息
if ($e - > getHttpStatus() != NULL) {
echo $e - > getHttpStatus().PHP_EOL;
echo $e - > getHttpBody().PHP_EOL;
} else {
echo $e - > getMessage().PHP_EOL;
}
}
@Test
public void testRoyaltyTemplateCreate() throws RateLimitException, APIException, ChannelException, InvalidRequestException, APIConnectionException, AuthenticationException {
Map < String, Object > params = new HashMap < > ();
params.put("app", PingppAccountTestData.getAppID()); // App ID, 必传
params.put("name", "royalty_templates name"); // 模板名称,允许中英文等常用字符, 可选
Map < String, Object > rule = new HashMap < > ();
rule.put("royalty_mode", "rate"); // 分润模式。分为按订单金额(包含优惠券金额)的比例 rate 和固定金额 fixed, 必传
rule.put("refund_mode", "no_refund"); // 退分润模式。分为退款时不退分润 no_refund、按比例退分润 proportional 和一旦退款分润全退 full_refund, 必传
// 分配模式。指当订单确定的层级如果少于模板配置层级时,模板中多余的分润金额是归属于收款方 receipt_reserved 还是服务方 service_reserved。
// 必传
rule.put("allocation_mode", "receipt_reserved");
List < Map > data = new ArrayList < > (); // 分润数据列表, 必传
Map < String, Object > data1 = new HashMap < > ();
data1.put("level", 0); // 子商户层级值,0 表示平台, 1 表示一级子商户,取值范围 >=0
data1.put("value", 11); // 分润数值。rate 下取值为 0 - 10000,单位为 0.01 %,fixed 下取值为 0 - 1000000,单位为分
Map < String, Object > data2 = new HashMap < > ();
data2.put("level", 1);
data2.put("value", 12);
data.add(data1);
data.add(data2);
rule.put("data", data);
params.put("rule", rule);
// 创建 royalty_template 方法
// 参数: params
RoyaltyTemplate obj = RoyaltyTemplate.create(params);
assertEquals("object should be royalty_template", "royalty_template", obj.getObject());
assertEquals("name", params.get("name"), obj.getName());
}
pingpp.royaltyTemplates.create({
'app': APP_ID,
// App ID, 必传
'name': 'royalty_templates name',
// 模板名称,允许中英文等常用字符, 可选
'rule': {
'royalty_mode': 'rate',
// 分润模式。分为按订单金额(包含优惠券金额)的比例 rate 和固定金额 fixed, 必传
'refund_mode': 'no_refund',
// 退分润模式。分为退款时不退分润 no_refund、按比例退分润 proportional 和一旦退款分润全退 full_refund, 必传
'allocation_mode': 'receipt_reserved',
// 分配模式。指当订单确定的层级如果少于模板配置层级时,模板中多余的分润金额是归属于收款方 receipt_reserved 还是服务方 service_reserved。必传
'data': [ // 分润数据列表, 必传
{
'level': 0,
// 子商户层级值,0 表示平台, 1 表示一级子商户,取值范围 >=0
'value': 11 // 分润数值。rate 下取值为 0 - 10000,单位为 0.01 %,fixed 下取值为 0 - 1000000,单位为分
}, {
'level': 1,
'value': 12
}]
}
}, function(err, royaltyTemplate) {
if (err != null) {
console.log(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'
#设置API Key
pingpp.api_key = api_key # app_id支持全局配置
pingpp.app_id = app_id
pingpp.private_key_path = os.path.join(
os.path.dirname(os.getcwd()), 'your_rsa_private_key.pem')
try :#创建分润结算对象
params = {
"app": pingpp.app_id,
"name": "Your RoyaltyTemplate Name",
#模板名称,允许中英文等常用字符"rule": {
"royalty_mode": "rate",
#分润模式。分为按订单金额(包含优惠券金额)的比例rate和固定金额fixed "refund_mode": "no_refund",
#退分润模式。分为退款时不退分润no_refund、按比例退分润proportional和一旦退款分润全退full_refund "allocation_mode": "receipt_reserved",
#分配模式。指当订单确定的层级如果少于模板配置层级时,#模板中多余的分润金额是归属于收款方receipt_reserved还是服务方service_reserved。"data": [{
"level": 1,
#子商户层级值,0表示平台,1表示一级子商户,取值范围 >= 0 "value": 20 #分润数值。rate下取值为0 - 10000,单位为0.01 % ,fixed下取值为0 - 1000000,单位为分
}, {
"level": 2,
"value": 10
}]
}
}
royalty_template = pingpp.RoyaltyTemplate.create( * * params)
print('create royalty_template', royalty_template)
except Exception as e: print(e.http_body)
should "return a royalty_template object when passed correct parameters"
do
params = {
# App ID required | string: app = > get_app_id,
#描述信息optional | string: description = > "TEMPLATE DESCRIPTION",
#模版名称optional | string #: name = > "TEMPLATE_NAME",
#分润规则required | hash: rule = > {
#分润模式required | string;
rate: 按订单金额(包含优惠券金额)的比例,
fixed: 固定金额: royalty_mode = > "rate",
#分配模式required | string;指当订单确定的层级如果少于模板配置层级时,#模板中多余的分润金额是归属于收款方`receipt_reserved`还是服务方`service_reserved`。: allocation_mode = > "receipt_reserved",
#退分润模式required | string;
no_refund: 退款时不退分润,
proportional: 按比例退分润,
full_refund: 一旦退款分润全退: refund_mode = > "no_refund",
#分润数据列表required | array: data = > [{: level = > 0,
: value = > 10
}, {: level = > 1,
: value = > 20
}],
},
}
o = Pingpp::RoyaltyTemplate.create(params)
assert o.kind_of ? (Pingpp::RoyaltyTemplate)
end
func(c * RoyaltyTmplDemo) New()( * pingpp.RoyaltyTmpl, error) {
params: = & pingpp.RoyaltyTmplParams {
App: c.demoAppID,
Name: "royalty_template_name",
Rule: pingpp.Rule {
Royalty_mode: "rate",
Refund_mode: "no_refund",
Allocation_mode: "receipt_reserved",
Data: [] pingpp.RuleData {
pingpp.RuleData {
Level: 1,
Value: 30,
}, pingpp.RuleData {
Level: 2,
Value: 20,
}, pingpp.RuleData {
Level: 3,
Value: 10,
},
},
},
Description: "Your description",
}
return royaltyTemplate.New(params)
}
public static void Example(string appId) {
var createParams = new Dictionary < string,
object > {
{
"app", appId
}, {
"name", "Your Royalty Template Name"
}, //模板名称,允许中英文等常用字符
{
"rule", new Dictionary < string, object > {
{
"royalty_mode", "rate"
}, //分润模式。分为按订单金额(包含优惠券金额)的比例 rate 和固定金额 fixed
{
"refund_mode", "full_refund"
}, //退分润模式。分为退款时不退分润 no_refund、按比例退分润 proportional 和一旦退款分润全退 full_refund
{
"allocation_mode", "receipt_reserved"
}, //分配模式。指当订单确定的层级如果少于模板配置层级时,模板中多余的分润金额是归属于收款方 receipt_reserved 还是服务方 service_reserved。
{
"data", new List < Dictionary < string, object >> {
new Dictionary < string, object > {
{
"level", 1
}, //子商户层级值,0 表示平台, 1 表示一级子商户,取值范围 >=0
{
"value", 20
} //分润数值。rate 下取值为 0 - 10000,单位为 0.01 %,fixed 下取值为 0 - 1000000,单位为分
}, new Dictionary < string, object > {
{
"level", 2
}, {
"value", 10
}
}
}
}
}
}
};
}

Ping++ 收到创建分润模板请求后返回给你的服务器一个 Royalty Template 对象,下面是 Royalty Template 的一个示例:

{
"id": "450170814144600001",
"object": "royalty_template",
"livemode": false,
"app": "app_1Gqj58ynP0mHeX1q",
"name": "royalty_templates name",
"created": 1502693202,
"description": null,
"rule": {
"royalty_mode": "rate",
"refund_mode": "no_refund",
"allocation_mode": "receipt_reserved",
"data": [{
"level": 0,
"value": 11
}, {
"level": 1,
"value": 12
}]
}
}

分润模板查询

Ping++ 提供分润模板查询接口可以查询单个分润模板以及分润模板列表。

单个分润模板查询

try {
$royalty_tpl_info = \Pingpp\RoyaltyTemplate::retrieve('451170807182300001');
echo $royalty_tpl_info;
} catch (\Pingpp\Error\Base $e) {
// 捕获报错信息
if ($e - > getHttpStatus() != NULL) {
echo $e - > getHttpStatus().PHP_EOL;
echo $e - > getHttpBody().PHP_EOL;
} else {
echo $e - > getMessage().PHP_EOL;
}
}
@Test public void testRoyaltyTemplateRetrieve() throws RateLimitException, APIException, ChannelException, InvalidRequestException, APIConnectionException, AuthenticationException {
String id = "450170822152200001";
// 查询单个 royalty_template 方法
// 参数: royalty_template id
RoyaltyTemplate obj = RoyaltyTemplate.retrieve(id);
assertEquals("object should be royalty_template", "royalty_template", obj.getObject());
assertEquals("id", id, obj.getId());
}
pingpp.royaltyTemplates.retrieve('450170830143400001', // RoyaltyTemplates ID
function(err, royaltyTemplate) {
if (err != null) {
console.log(err);
}
// YOUR CODE
});
print('retrieve royalty_template', pingpp.RoyaltyTemplate.retrieve(royalty_template.id))
should "return an existed royalty_template object when passed a correct id"
do
o = Pingpp::RoyaltyTemplate.retrieve(existed_royalty_template_id)
assert o.kind_of ? (Pingpp::RoyaltyTemplate)
end
func(c * RoyaltyTmplDemo) Get()( * pingpp.RoyaltyTmpl, error) {
return royaltyTemplate.Get(c.demoroyaltyTmplId)
}
Console.WriteLine("**** 查询分润模板 ****");
Console.WriteLine(RoyaltyTemplate.Retrieve("451170814105500001"));

分润模板列表查询

try {
$params = ['page' = > 1, 'per_page' = > 10, ];
$royalty_tpl_info = \Pingpp\RoyaltyTemplate::all($params);
echo $royalty_tpl_info;
} catch (\Pingpp\Error\Base $e) {
// 捕获报错信息
if ($e - > getHttpStatus() != NULL) {
echo $e - > getHttpStatus().PHP_EOL;
echo $e - > getHttpBody().PHP_EOL;
} else {
echo $e - > getMessage().PHP_EOL;
}
}
@Test public void testRoyaltyTemplateList() throws RateLimitException, APIException, ChannelException, InvalidRequestException, APIConnectionException, AuthenticationException {
Map < String, Object > params = new HashMap < > ();
params.put("per_page", 3);
params.put("page", 1);
// 查询 royalty_template list 列表方法
// 参数: params
RoyaltyTemplateCollection objs = RoyaltyTemplate.list(params);
assertEquals("object should be list", "list", objs.getObject());
}
pingpp.royaltyTemplates.list({
page: 1,
per_page: 3
}, function(err, data) {
if (err != null) {
console.log(err);
}
// YOUR CODE
});
print("retrieve royalty_template list", pingpp.RoyaltyTemplate.all())
should "return a list object of royalty_template"
do
o = Pingpp::RoyaltyTemplate.list({: per_page = > 3,
: page = > 1
})
assert o.kind_of ? (Pingpp::ListObject)
assert o.data[0].kind_of ? (Pingpp::RoyaltyTemplate)
end
func(c * RoyaltyTmplDemo) List()( * pingpp.RoyaltyTmplList, error) {
params: = & pingpp.PagingParams {}
params.Filters.AddFilter("page", "", "1")
params.Filters.AddFilter("per_page", "", "10")
return royaltyTemplate.List(params)
}
Console.WriteLine("**** 查询分润模板列表 ****");
Console.WriteLine(RoyaltyTemplate.List(new Dictionary < string, object > {
{
"page", 1
}, {
"per_page", 10
}
}));

注意事项

  1. 分润模板和子商户的创建顺序没有限制,但需要保证在订单创建前创建完成。
  2. 分润模板支持修改和删除。但如果在修改或删除之前将模板传入订单,这些订单不受影响。
  3. 分润模板只能由平台创建、管理,子商户不能查看或管理分润模板。
  4. 平台拥有多个分润规则业务时,可以创建多个模板,在订单创建时指定对应规则的分润模板 ID 即可。
  5. 在订单创建时使用了分润模板后,在退款时分润模板会自动生效,此时如果填写了退分润用户列表,则分润模板不生效,以传入的为准。

下一步分润结算