|
@@ -67,16 +67,12 @@ public class TencentClient {
|
|
|
* @param bid 匹配到的竞价记录(含 callback URL)
|
|
* @param bid 匹配到的竞价记录(含 callback URL)
|
|
|
* @param payment 百度转化支付信息
|
|
* @param payment 百度转化支付信息
|
|
|
* @param platform 平台标识("android" 或 "ios")
|
|
* @param platform 平台标识("android" 或 "ios")
|
|
|
- * @param actionTypeOverride 广告位维度的回传方式;非空时优先作为 action_type,
|
|
|
|
|
- * 为空时回退到 act-map 映射
|
|
|
|
|
|
|
+ * @param actionType 已解析出的腾讯回传行为
|
|
|
* @return MediaCallbackRecord 记录回传结果(含请求体、响应、状态)
|
|
* @return MediaCallbackRecord 记录回传结果(含请求体、响应、状态)
|
|
|
*/
|
|
*/
|
|
|
public MediaCallbackRecord sendConversionEvent(BidRecord bid, PaymentInfo payment, String platform,
|
|
public MediaCallbackRecord sendConversionEvent(BidRecord bid, PaymentInfo payment, String platform,
|
|
|
- String actionTypeOverride) {
|
|
|
|
|
|
|
+ String actionType) {
|
|
|
long eventTimeMs = Instant.now().toEpochMilli();
|
|
long eventTimeMs = Instant.now().toEpochMilli();
|
|
|
- String actionType = (actionTypeOverride != null && !actionTypeOverride.isBlank())
|
|
|
|
|
- ? actionTypeOverride
|
|
|
|
|
- : conversionActionType(payment.getAct());
|
|
|
|
|
|
|
|
|
|
MediaCallbackRecord record = new MediaCallbackRecord();
|
|
MediaCallbackRecord record = new MediaCallbackRecord();
|
|
|
record.setMedia("tencent");
|
|
record.setMedia("tencent");
|
|
@@ -231,7 +227,7 @@ public class TencentClient {
|
|
|
UserAction action = new UserAction();
|
|
UserAction action = new UserAction();
|
|
|
action.setActionTime(eventTimeMs / 1000); // 秒级时间戳
|
|
action.setActionTime(eventTimeMs / 1000); // 秒级时间戳
|
|
|
action.setActionType(actionType);
|
|
action.setActionType(actionType);
|
|
|
- action.setOuterActionId(payment.getQk() + "_" + payment.getAct() + "_" + eventTimeMs);
|
|
|
|
|
|
|
+ action.setOuterActionId(buildOuterActionId(bid, payment, actionType));
|
|
|
|
|
|
|
|
// 设备标识
|
|
// 设备标识
|
|
|
UserId userId = buildUserId(bid);
|
|
UserId userId = buildUserId(bid);
|
|
@@ -248,7 +244,8 @@ public class TencentClient {
|
|
|
// action_param
|
|
// action_param
|
|
|
if ("PURCHASE".equals(actionType) || "COMPLETE_ORDER".equals(actionType)) {
|
|
if ("PURCHASE".equals(actionType) || "COMPLETE_ORDER".equals(actionType)) {
|
|
|
UserAction.ActionParam param = new UserAction.ActionParam();
|
|
UserAction.ActionParam param = new UserAction.ActionParam();
|
|
|
- param.setValue((int) (payment.getPayment() * 100)); // 分
|
|
|
|
|
|
|
+ double amount = payment.getGmv() > 0 ? payment.getGmv() : payment.getPayment();
|
|
|
|
|
+ param.setValue((int) (amount * 100)); // 分
|
|
|
action.setActionParam(param);
|
|
action.setActionParam(param);
|
|
|
} else if ("START_APP".equals(actionType)) {
|
|
} else if ("START_APP".equals(actionType)) {
|
|
|
// 留存行为必须带 length_of_stay(文档要求)
|
|
// 留存行为必须带 length_of_stay(文档要求)
|
|
@@ -273,6 +270,21 @@ public class TencentClient {
|
|
|
return action;
|
|
return action;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ private String buildOuterActionId(BidRecord bid, PaymentInfo payment, String actionType) {
|
|
|
|
|
+ String source = String.join("|",
|
|
|
|
|
+ safe(payment.getQk()),
|
|
|
|
|
+ safe(payment.getDate()),
|
|
|
|
|
+ safe(payment.getDeviceId()),
|
|
|
|
|
+ safe(bid.getTagId()),
|
|
|
|
|
+ String.valueOf(payment.getAct()),
|
|
|
|
|
+ safe(actionType));
|
|
|
|
|
+ return md5Hex(source);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private String safe(String value) {
|
|
|
|
|
+ return value == null ? "" : value;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
/**
|
|
/**
|
|
|
* 从 BidRecord 的 mediaParams 中提取设备标识构造 UserId。
|
|
* 从 BidRecord 的 mediaParams 中提取设备标识构造 UserId。
|
|
|
*/
|
|
*/
|
|
@@ -327,6 +339,17 @@ public class TencentClient {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ private static String md5Hex(String value) {
|
|
|
|
|
+ if (value == null) return null;
|
|
|
|
|
+ try {
|
|
|
|
|
+ MessageDigest md = MessageDigest.getInstance("MD5");
|
|
|
|
|
+ byte[] hash = md.digest(value.getBytes(StandardCharsets.UTF_8));
|
|
|
|
|
+ return HexFormat.of().formatHex(hash);
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ return value;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
private static String firstNotBlank(String... values) {
|
|
private static String firstNotBlank(String... values) {
|
|
|
for (String v : values) {
|
|
for (String v : values) {
|
|
|
if (v != null && !v.isBlank()) return v;
|
|
if (v != null && !v.isBlank()) return v;
|