Compare commits
No commits in common. "main" and "release/redis-memory-fix-20260521" have entirely different histories.
main
...
release/re
2
.gitignore
vendored
2
.gitignore
vendored
@ -97,5 +97,3 @@ devops-monitor-id_rsa.key
|
|||||||
/claude/
|
/claude/
|
||||||
|
|
||||||
.local-run/
|
.local-run/
|
||||||
|
|
||||||
.env
|
|
||||||
@ -175,7 +175,6 @@ gateway:
|
|||||||
- /product/apple/config
|
- /product/apple/config
|
||||||
- /game/sud/**
|
- /game/sud/**
|
||||||
- /web/pay/**
|
- /web/pay/**
|
||||||
- /order/web/pay/**
|
|
||||||
- /external/oss/upload
|
- /external/oss/upload
|
||||||
- /telegram/webhook
|
- /telegram/webhook
|
||||||
- /account/create/getRegion
|
- /account/create/getRegion
|
||||||
@ -198,12 +197,6 @@ gateway:
|
|||||||
- /go/resident-activity/specified-gift-weekly-rank/**
|
- /go/resident-activity/specified-gift-weekly-rank/**
|
||||||
- /resident-activity/specified-gift-weekly-rank/**
|
- /resident-activity/specified-gift-weekly-rank/**
|
||||||
- /go/resident-activity/week-star/**
|
- /go/resident-activity/week-star/**
|
||||||
- /getUserInfo
|
|
||||||
- /go/getUserInfo
|
|
||||||
- /updateBalance
|
|
||||||
- /go/updateBalance
|
|
||||||
- /game/hotgame/**
|
|
||||||
- /go/game/hotgame/**
|
|
||||||
- /resident-activity/week-star/**
|
- /resident-activity/week-star/**
|
||||||
- /resident-activity/sign-in-reward/**
|
- /resident-activity/sign-in-reward/**
|
||||||
- /resident-activity/vip/**
|
- /resident-activity/vip/**
|
||||||
@ -213,7 +206,6 @@ gateway:
|
|||||||
- /resident-activity/voice-room-rocket/**
|
- /resident-activity/voice-room-rocket/**
|
||||||
- /resident-activity/wheel/**
|
- /resident-activity/wheel/**
|
||||||
- /resident-activity/smash-golden-egg/**
|
- /resident-activity/smash-golden-egg/**
|
||||||
- /operate/hotgame-game/**
|
|
||||||
- /operate/baishun-game/**
|
- /operate/baishun-game/**
|
||||||
- /operate/lingxian-game/**
|
- /operate/lingxian-game/**
|
||||||
- /app-system/home-popups/**
|
- /app-system/home-popups/**
|
||||||
|
|||||||
@ -128,13 +128,6 @@ task:
|
|||||||
topic: ${TASK_CENTER_EVENT_MQ_TOPIC:RC_DEFAULT_APP_ORDINARY}
|
topic: ${TASK_CENTER_EVENT_MQ_TOPIC:RC_DEFAULT_APP_ORDINARY}
|
||||||
tag: ${TASK_CENTER_EVENT_MQ_TAG:task_center_event}
|
tag: ${TASK_CENTER_EVENT_MQ_TAG:task_center_event}
|
||||||
|
|
||||||
cp:
|
|
||||||
relation-broadcast:
|
|
||||||
mq:
|
|
||||||
enabled: ${CP_RELATION_BROADCAST_MQ_ENABLED:true}
|
|
||||||
topic: ${CP_RELATION_BROADCAST_MQ_TOPIC:RC_DEFAULT_APP_ORDINARY}
|
|
||||||
tag: ${CP_RELATION_BROADCAST_MQ_TAG:cp_relation_broadcast}
|
|
||||||
|
|
||||||
voice-room:
|
voice-room:
|
||||||
region-broadcast:
|
region-broadcast:
|
||||||
go:
|
go:
|
||||||
|
|||||||
@ -39,11 +39,10 @@ public class LoginAccessValidationService {
|
|||||||
"香港", "澳门", "澳門", "台湾", "台灣", "Hong Kong", "Macau", "Macao", "Taiwan"
|
"香港", "澳门", "澳門", "台湾", "台灣", "Hong Kong", "Macau", "Macao", "Taiwan"
|
||||||
);
|
);
|
||||||
private static final List<String> BLOCKED_COUNTRY_CODES = List.of(
|
private static final List<String> BLOCKED_COUNTRY_CODES = List.of(
|
||||||
"HK", "MO", "TW", "SG"
|
"MO"
|
||||||
);
|
);
|
||||||
private static final List<String> BLOCKED_COUNTRY_NAMES = List.of(
|
private static final List<String> BLOCKED_COUNTRY_NAMES = List.of(
|
||||||
"香港", "澳门", "澳門", "台湾", "台灣", "新加坡",
|
"澳门", "澳門", "Macau", "Macao"
|
||||||
"Hong Kong", "Macau", "Macao", "Taiwan", "Singapore"
|
|
||||||
);
|
);
|
||||||
private static final List<IpGeoProvider> IP_GEO_PROVIDERS = List.of(
|
private static final List<IpGeoProvider> IP_GEO_PROVIDERS = List.of(
|
||||||
new IpGeoProvider("ip.sb", "https://api.ip.sb/geoip/%s"),
|
new IpGeoProvider("ip.sb", "https://api.ip.sb/geoip/%s"),
|
||||||
|
|||||||
@ -70,22 +70,22 @@ public class LoginAccessValidationServiceTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void blockHongKongRegion() {
|
public void allowHongKongRegion() {
|
||||||
JSONObject data = JSON.parseObject("""
|
JSONObject data = JSON.parseObject("""
|
||||||
{"country_id":"CN","country":"中国","region":"香港"}
|
{"country_id":"CN","country":"中国","region":"香港"}
|
||||||
""");
|
""");
|
||||||
|
|
||||||
assertFalse(LoginAccessValidationService.isMainlandChina(data));
|
assertFalse(LoginAccessValidationService.isMainlandChina(data));
|
||||||
assertTrue(LoginAccessValidationService.isBlockedIpRegion(data));
|
assertFalse(LoginAccessValidationService.isBlockedIpRegion(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void blockHongKongCountryCode() {
|
public void allowHongKongCountryCode() {
|
||||||
JSONObject data = JSON.parseObject("""
|
JSONObject data = JSON.parseObject("""
|
||||||
{"country_id":"HK","country":"Hong Kong","region":"Kwai Tsing District"}
|
{"country_id":"HK","country":"Hong Kong","region":"Kwai Tsing District"}
|
||||||
""");
|
""");
|
||||||
|
|
||||||
assertTrue(LoginAccessValidationService.isBlockedIpRegion(data));
|
assertFalse(LoginAccessValidationService.isBlockedIpRegion(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -98,30 +98,30 @@ public class LoginAccessValidationServiceTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void blockSingaporeCountryCode() {
|
public void allowSingaporeCountryCode() {
|
||||||
JSONObject data = JSON.parseObject("""
|
JSONObject data = JSON.parseObject("""
|
||||||
{"country_id":"SG","country":"Singapore","region":""}
|
{"country_id":"SG","country":"Singapore","region":""}
|
||||||
""");
|
""");
|
||||||
|
|
||||||
assertTrue(LoginAccessValidationService.isBlockedIpRegion(data));
|
assertFalse(LoginAccessValidationService.isBlockedIpRegion(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void blockTaiwanRegion() {
|
public void allowTaiwanRegion() {
|
||||||
JSONObject data = JSON.parseObject("""
|
JSONObject data = JSON.parseObject("""
|
||||||
{"country_id":"CN","country":"中国","region":"台湾"}
|
{"country_id":"CN","country":"中国","region":"台湾"}
|
||||||
""");
|
""");
|
||||||
|
|
||||||
assertFalse(LoginAccessValidationService.isMainlandChina(data));
|
assertFalse(LoginAccessValidationService.isMainlandChina(data));
|
||||||
assertTrue(LoginAccessValidationService.isBlockedIpRegion(data));
|
assertFalse(LoginAccessValidationService.isBlockedIpRegion(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void blockTaiwanCountryCode() {
|
public void allowTaiwanCountryCode() {
|
||||||
JSONObject data = JSON.parseObject("""
|
JSONObject data = JSON.parseObject("""
|
||||||
{"country_id":"TW","country":"Taiwan","region":""}
|
{"country_id":"TW","country":"Taiwan","region":""}
|
||||||
""");
|
""");
|
||||||
|
|
||||||
assertTrue(LoginAccessValidationService.isBlockedIpRegion(data));
|
assertFalse(LoginAccessValidationService.isBlockedIpRegion(data));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -39,7 +39,7 @@ public enum ConsoleAccountStatusEnum {
|
|||||||
/**
|
/**
|
||||||
* 账号解封.
|
* 账号解封.
|
||||||
*/
|
*/
|
||||||
UNTIE_ACOOUNT("UNTIE_ACOOUNT", "账号解封"),
|
UNTIE_ACOOUNT("UNTIE_DEVICE", "账号解封"),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设备+账户解封.
|
* 设备+账户解封.
|
||||||
|
|||||||
@ -51,9 +51,4 @@ public class GiveGiftConfig implements Serializable {
|
|||||||
*/
|
*/
|
||||||
private String giftTab;
|
private String giftTab;
|
||||||
|
|
||||||
/**
|
|
||||||
* CP礼物关系类型:CP/BROTHER/SISTERS.
|
|
||||||
*/
|
|
||||||
private String cpRelationType;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -56,10 +56,6 @@ public class BuySuccessEvent implements Serializable {
|
|||||||
*/
|
*/
|
||||||
String payPlatform;
|
String payPlatform;
|
||||||
|
|
||||||
/**
|
|
||||||
* 本次充值请求的App版本.
|
|
||||||
*/
|
|
||||||
String appVersion;
|
|
||||||
/**
|
/**
|
||||||
* 来源.
|
* 来源.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -1,39 +0,0 @@
|
|||||||
package com.red.circle.mq.business.model.event.pay;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
|
||||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.util.Map;
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.experimental.Accessors;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 通用充值成功事件。
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@Accessors(chain = true)
|
|
||||||
public class RechargeSuccessEvent implements Serializable {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
private String eventId;
|
|
||||||
private String sysOrigin;
|
|
||||||
|
|
||||||
@JsonSerialize(using = ToStringSerializer.class)
|
|
||||||
private Long userId;
|
|
||||||
|
|
||||||
@JsonSerialize(using = ToStringSerializer.class)
|
|
||||||
private Long amountCents;
|
|
||||||
|
|
||||||
private String amountUsd;
|
|
||||||
private String currency;
|
|
||||||
private String payPlatform;
|
|
||||||
private String paymentMethod;
|
|
||||||
private String googleProductId;
|
|
||||||
private String productId;
|
|
||||||
private String appVersion;
|
|
||||||
private String sourceOrderId;
|
|
||||||
private String orderId;
|
|
||||||
private String occurredAt;
|
|
||||||
private Map<String, Object> payload;
|
|
||||||
}
|
|
||||||
@ -22,11 +22,6 @@ public interface QueueNameConstant {
|
|||||||
*/
|
*/
|
||||||
String BUY_SUCCESS = "BUY_SUCCESS";
|
String BUY_SUCCESS = "BUY_SUCCESS";
|
||||||
|
|
||||||
/**
|
|
||||||
* 通用充值成功。
|
|
||||||
*/
|
|
||||||
String RECHARGE_SUCCESS = "RECHARGE_SUCCESS";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 视频语音房间会话
|
* 视频语音房间会话
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -1,12 +0,0 @@
|
|||||||
package com.red.circle.mq.rocket.business.streams;
|
|
||||||
|
|
||||||
import com.red.circle.mq.rocket.business.constant.QueueNameConstant;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 通用充值成功事件。
|
|
||||||
*/
|
|
||||||
public interface RechargeSuccessSink {
|
|
||||||
|
|
||||||
String INPUT = QueueNameConstant.RECHARGE_SUCCESS;
|
|
||||||
String TAG = "recharge_success_v1";
|
|
||||||
}
|
|
||||||
@ -1,11 +1,7 @@
|
|||||||
package com.red.circle.external.inner.endpoint.message.api;
|
package com.red.circle.external.inner.endpoint.message.api;
|
||||||
|
|
||||||
import com.red.circle.framework.dto.ResultResponse;
|
import com.red.circle.framework.dto.ResultResponse;
|
||||||
import com.red.circle.external.inner.model.cmd.message.CustomC2cMsgBodyCmd;
|
|
||||||
import jakarta.validation.Valid;
|
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RequestBody;
|
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -33,10 +29,4 @@ public interface ImMessageClientApi {
|
|||||||
@RequestParam("toAccount") Long toAccount,
|
@RequestParam("toAccount") Long toAccount,
|
||||||
@RequestParam("text") String text);
|
@RequestParam("text") String text);
|
||||||
|
|
||||||
/**
|
|
||||||
* 发送 C2C 自定义消息.
|
|
||||||
*/
|
|
||||||
@PostMapping("/sendCustomMessage")
|
|
||||||
ResultResponse<Void> sendCustomMessage(@RequestBody @Valid CustomC2cMsgBodyCmd cmd);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,91 +0,0 @@
|
|||||||
package com.red.circle.external.inner.model.cmd.message;
|
|
||||||
|
|
||||||
import com.red.circle.framework.dto.Command;
|
|
||||||
import jakarta.validation.constraints.NotBlank;
|
|
||||||
import jakarta.validation.constraints.NotNull;
|
|
||||||
import java.io.Serial;
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.EqualsAndHashCode;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* C2C custom IM message.
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@EqualsAndHashCode(callSuper = true)
|
|
||||||
public class CustomC2cMsgBodyCmd extends Command {
|
|
||||||
|
|
||||||
@Serial
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
@NotBlank(message = "fromAccount required.")
|
|
||||||
private String fromAccount;
|
|
||||||
|
|
||||||
@NotBlank(message = "toAccount required.")
|
|
||||||
private String toAccount;
|
|
||||||
|
|
||||||
@NotBlank(message = "desc required.")
|
|
||||||
private String desc;
|
|
||||||
|
|
||||||
@NotNull(message = "data required.")
|
|
||||||
private Object data;
|
|
||||||
|
|
||||||
private Integer syncOtherMachine;
|
|
||||||
|
|
||||||
public static CustomC2cMsgBodyBuilder builder() {
|
|
||||||
return new CustomC2cMsgBodyBuilder();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class CustomC2cMsgBodyBuilder {
|
|
||||||
|
|
||||||
private String fromAccount;
|
|
||||||
private String toAccount;
|
|
||||||
private String desc;
|
|
||||||
private Object data;
|
|
||||||
private Integer syncOtherMachine;
|
|
||||||
|
|
||||||
public CustomC2cMsgBodyBuilder fromAccount(String fromAccount) {
|
|
||||||
this.fromAccount = fromAccount;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CustomC2cMsgBodyBuilder fromAccount(Long fromAccount) {
|
|
||||||
this.fromAccount = String.valueOf(fromAccount);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CustomC2cMsgBodyBuilder toAccount(String toAccount) {
|
|
||||||
this.toAccount = toAccount;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CustomC2cMsgBodyBuilder toAccount(Long toAccount) {
|
|
||||||
this.toAccount = String.valueOf(toAccount);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CustomC2cMsgBodyBuilder desc(String desc) {
|
|
||||||
this.desc = desc;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CustomC2cMsgBodyBuilder data(Object data) {
|
|
||||||
this.data = data;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CustomC2cMsgBodyBuilder syncOtherMachine(Integer syncOtherMachine) {
|
|
||||||
this.syncOtherMachine = syncOtherMachine;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CustomC2cMsgBodyCmd build() {
|
|
||||||
CustomC2cMsgBodyCmd cmd = new CustomC2cMsgBodyCmd();
|
|
||||||
cmd.setFromAccount(this.fromAccount);
|
|
||||||
cmd.setToAccount(this.toAccount);
|
|
||||||
cmd.setDesc(this.desc);
|
|
||||||
cmd.setData(this.data);
|
|
||||||
cmd.setSyncOtherMachine(this.syncOtherMachine);
|
|
||||||
return cmd;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -6,9 +6,7 @@ import com.red.circle.framework.dto.ResultResponse;
|
|||||||
import com.red.circle.order.inner.model.cmd.SysPayCountryAddCmd;
|
import com.red.circle.order.inner.model.cmd.SysPayCountryAddCmd;
|
||||||
import com.red.circle.order.inner.model.cmd.SysPayCountryChannelCmd;
|
import com.red.circle.order.inner.model.cmd.SysPayCountryChannelCmd;
|
||||||
import com.red.circle.order.inner.model.cmd.SysPayCountryChannelDetailsCmd;
|
import com.red.circle.order.inner.model.cmd.SysPayCountryChannelDetailsCmd;
|
||||||
import com.red.circle.order.inner.model.cmd.SysPayCountryCurrencyRateSyncCmd;
|
|
||||||
import com.red.circle.order.inner.model.cmd.SysPayCountryQryCmd;
|
import com.red.circle.order.inner.model.cmd.SysPayCountryQryCmd;
|
||||||
import com.red.circle.order.inner.model.dto.PayCountryCurrencyRateSyncDTO;
|
|
||||||
import com.red.circle.order.inner.model.dto.PayCountryDTO;
|
import com.red.circle.order.inner.model.dto.PayCountryDTO;
|
||||||
import com.red.circle.order.inner.model.dto.SysPayCountryChannelDTO;
|
import com.red.circle.order.inner.model.dto.SysPayCountryChannelDTO;
|
||||||
import com.red.circle.order.inner.model.dto.SysPayCountryChannelDetailsDTO;
|
import com.red.circle.order.inner.model.dto.SysPayCountryChannelDetailsDTO;
|
||||||
@ -90,10 +88,6 @@ public interface PayCountryClientApi {
|
|||||||
@GetMapping("/shelf")
|
@GetMapping("/shelf")
|
||||||
ResultResponse<Void> shelf(@RequestParam("id") Long id, @RequestParam("shelf") Boolean shelf);
|
ResultResponse<Void> shelf(@RequestParam("id") Long id, @RequestParam("shelf") Boolean shelf);
|
||||||
|
|
||||||
@PostMapping("/syncCurrencyRates")
|
|
||||||
ResultResponse<PayCountryCurrencyRateSyncDTO> syncCurrencyRates(
|
|
||||||
@RequestBody SysPayCountryCurrencyRateSyncCmd cmd);
|
|
||||||
|
|
||||||
@GetMapping("/listPayCountryByRegionId")
|
@GetMapping("/listPayCountryByRegionId")
|
||||||
ResultResponse<List<PayCountryDTO>> listPayCountryByRegionId(
|
ResultResponse<List<PayCountryDTO>> listPayCountryByRegionId(
|
||||||
@RequestParam("regionId") String regionId);
|
@RequestParam("regionId") String regionId);
|
||||||
|
|||||||
@ -7,7 +7,6 @@ import jakarta.validation.constraints.NotBlank;
|
|||||||
import jakarta.validation.constraints.NotNull;
|
import jakarta.validation.constraints.NotNull;
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.util.List;
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.experimental.Accessors;
|
import lombok.experimental.Accessors;
|
||||||
@ -47,12 +46,6 @@ public class SysPayApplicationCommodityCmd extends CommonCommand {
|
|||||||
@JsonSerialize(using = ToStringSerializer.class)
|
@JsonSerialize(using = ToStringSerializer.class)
|
||||||
private Long payCountryId;
|
private Long payCountryId;
|
||||||
|
|
||||||
/**
|
|
||||||
* 批量创建时的国家列表;表结构仍是一条商品对应一个国家,所以只在新增时拆成多条记录.
|
|
||||||
*/
|
|
||||||
@JsonSerialize(contentUsing = ToStringSerializer.class)
|
|
||||||
private List<Long> payCountryIds;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 区域ID.
|
* 区域ID.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -1,33 +0,0 @@
|
|||||||
package com.red.circle.order.inner.model.cmd;
|
|
||||||
|
|
||||||
import com.red.circle.framework.core.dto.CommonCommand;
|
|
||||||
import jakarta.validation.constraints.DecimalMax;
|
|
||||||
import jakarta.validation.constraints.DecimalMin;
|
|
||||||
import jakarta.validation.constraints.Digits;
|
|
||||||
import jakarta.validation.constraints.NotNull;
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.EqualsAndHashCode;
|
|
||||||
import lombok.experimental.Accessors;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 支付国家货币汇率同步命令.
|
|
||||||
*
|
|
||||||
* @author system
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@EqualsAndHashCode(callSuper = true)
|
|
||||||
@Accessors(chain = true)
|
|
||||||
public class SysPayCountryCurrencyRateSyncCmd extends CommonCommand {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 上浮比例,5 表示在实时汇率基础上增加 5%.
|
|
||||||
*/
|
|
||||||
@NotNull
|
|
||||||
@DecimalMin("0")
|
|
||||||
@DecimalMax("100")
|
|
||||||
@Digits(integer = 3, fraction = 4)
|
|
||||||
private BigDecimal markupPercent;
|
|
||||||
}
|
|
||||||
@ -102,9 +102,4 @@ public class InAppPurchaseDetailsQryCmd extends Command {
|
|||||||
* 条数.
|
* 条数.
|
||||||
*/
|
*/
|
||||||
private Integer limit;
|
private Integer limit;
|
||||||
|
|
||||||
/**
|
|
||||||
* 是否导出全部筛选结果;导出时不使用 lastId 和 limit 分页.
|
|
||||||
*/
|
|
||||||
private Boolean exportAll;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,47 +0,0 @@
|
|||||||
package com.red.circle.order.inner.model.dto;
|
|
||||||
|
|
||||||
import com.red.circle.framework.dto.DTO;
|
|
||||||
import java.io.Serial;
|
|
||||||
import java.util.List;
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.EqualsAndHashCode;
|
|
||||||
import lombok.experimental.Accessors;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 支付国家货币汇率同步结果.
|
|
||||||
*
|
|
||||||
* @author system
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@EqualsAndHashCode(callSuper = true)
|
|
||||||
@Accessors(chain = true)
|
|
||||||
public class PayCountryCurrencyRateSyncDTO extends DTO {
|
|
||||||
|
|
||||||
@Serial
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 参与同步的支付国家数量.
|
|
||||||
*/
|
|
||||||
private Integer totalCount;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 已更新的支付国家数量.
|
|
||||||
*/
|
|
||||||
private Integer updatedCount;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 跳过的支付国家数量.
|
|
||||||
*/
|
|
||||||
private Integer skippedCount;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 汇率来源.
|
|
||||||
*/
|
|
||||||
private String sourceName;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 被跳过的国家说明.
|
|
||||||
*/
|
|
||||||
private List<String> skippedCountries;
|
|
||||||
}
|
|
||||||
@ -11,15 +11,11 @@ import com.red.circle.other.inner.model.cmd.team.TeamApplicationProcessChangeCmd
|
|||||||
import com.red.circle.other.inner.model.cmd.team.TeamApplicationProcessQryCmd;
|
import com.red.circle.other.inner.model.cmd.team.TeamApplicationProcessQryCmd;
|
||||||
import com.red.circle.other.inner.model.cmd.team.TeamChangeOwnerCmd;
|
import com.red.circle.other.inner.model.cmd.team.TeamChangeOwnerCmd;
|
||||||
import com.red.circle.other.inner.model.cmd.team.TeamCreateCmd;
|
import com.red.circle.other.inner.model.cmd.team.TeamCreateCmd;
|
||||||
import com.red.circle.other.inner.model.cmd.team.TeamManualSalaryPaymentCmd;
|
|
||||||
import com.red.circle.other.inner.model.cmd.team.TeamManualSalaryPaymentQryCmd;
|
|
||||||
import com.red.circle.other.inner.model.cmd.team.TeamSalaryBackQryCmd;
|
import com.red.circle.other.inner.model.cmd.team.TeamSalaryBackQryCmd;
|
||||||
import com.red.circle.other.inner.model.cmd.team.TeamTableQryCmd;
|
import com.red.circle.other.inner.model.cmd.team.TeamTableQryCmd;
|
||||||
import com.red.circle.other.inner.model.cmd.team.TeamUpdateCmd;
|
import com.red.circle.other.inner.model.cmd.team.TeamUpdateCmd;
|
||||||
import com.red.circle.other.inner.model.dto.agency.agency.TeamApplicationProcessApprovalDTO;
|
import com.red.circle.other.inner.model.dto.agency.agency.TeamApplicationProcessApprovalDTO;
|
||||||
import com.red.circle.other.inner.model.dto.agency.agency.TeamApplicationProcessDTO;
|
import com.red.circle.other.inner.model.dto.agency.agency.TeamApplicationProcessDTO;
|
||||||
import com.red.circle.other.inner.model.dto.agency.agency.TeamManualSalaryPaymentDTO;
|
|
||||||
import com.red.circle.other.inner.model.dto.agency.agency.TeamManualSalaryPaymentResultDTO;
|
|
||||||
import com.red.circle.other.inner.model.dto.agency.agency.TeamMemberDTO;
|
import com.red.circle.other.inner.model.dto.agency.agency.TeamMemberDTO;
|
||||||
import com.red.circle.other.inner.model.dto.agency.agency.TeamProfileDTO;
|
import com.red.circle.other.inner.model.dto.agency.agency.TeamProfileDTO;
|
||||||
import com.red.circle.other.inner.model.dto.agency.agency.TeamSalaryPaymentDTO;
|
import com.red.circle.other.inner.model.dto.agency.agency.TeamSalaryPaymentDTO;
|
||||||
@ -154,20 +150,6 @@ public interface TeamProfileClientApi {
|
|||||||
ResultResponse<PageResult<TeamSalaryPaymentDTO>> listByCondition(
|
ResultResponse<PageResult<TeamSalaryPaymentDTO>> listByCondition(
|
||||||
@RequestBody TeamSalaryBackQryCmd cmd);
|
@RequestBody TeamSalaryBackQryCmd cmd);
|
||||||
|
|
||||||
/**
|
|
||||||
* 后台手动发放主播工资预览.
|
|
||||||
*/
|
|
||||||
@PostMapping("/manualSalary/page")
|
|
||||||
ResultResponse<PageResult<TeamManualSalaryPaymentDTO>> manualSalaryPage(
|
|
||||||
@RequestBody TeamManualSalaryPaymentQryCmd cmd);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 后台手动发放主播工资.
|
|
||||||
*/
|
|
||||||
@PostMapping("/manualSalary/pay")
|
|
||||||
ResultResponse<List<TeamManualSalaryPaymentResultDTO>> manualSalaryPay(
|
|
||||||
@RequestBody TeamManualSalaryPaymentCmd cmd);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获得区域下的所有团队ID.
|
* 获得区域下的所有团队ID.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -222,21 +222,6 @@ public enum EnumConfigKey {
|
|||||||
*/
|
*/
|
||||||
CP_PRICE,
|
CP_PRICE,
|
||||||
|
|
||||||
/**
|
|
||||||
* CP 关系解绑金币.
|
|
||||||
*/
|
|
||||||
CP_DISMISS_CONSUME_GOLD,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Brother 关系解绑金币.
|
|
||||||
*/
|
|
||||||
BROTHER_DISMISS_CONSUME_GOLD,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sisters 关系解绑金币.
|
|
||||||
*/
|
|
||||||
SISTERS_DISMISS_CONSUME_GOLD,
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Aswat 超级管理员ID.
|
* Aswat 超级管理员ID.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -1,45 +0,0 @@
|
|||||||
package com.red.circle.other.inner.model.cmd.team;
|
|
||||||
|
|
||||||
import com.red.circle.framework.dto.Command;
|
|
||||||
import java.io.Serial;
|
|
||||||
import java.util.List;
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.EqualsAndHashCode;
|
|
||||||
import lombok.experimental.Accessors;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 后台手动发放主播工资.
|
|
||||||
*/
|
|
||||||
@EqualsAndHashCode(callSuper = true)
|
|
||||||
@Data
|
|
||||||
@Accessors(chain = true)
|
|
||||||
public class TeamManualSalaryPaymentCmd extends Command {
|
|
||||||
|
|
||||||
@Serial
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 归属系统.
|
|
||||||
*/
|
|
||||||
private String sysOrigin;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 国家 code.
|
|
||||||
*/
|
|
||||||
private String countryCode;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 工资账期,为空时使用当前整月账期.
|
|
||||||
*/
|
|
||||||
private Integer billBelong;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 指定发放用户,为空时按国家全量发放.
|
|
||||||
*/
|
|
||||||
private List<Long> userIds;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 后台操作人.
|
|
||||||
*/
|
|
||||||
private Long operationUserId;
|
|
||||||
}
|
|
||||||
@ -1,49 +0,0 @@
|
|||||||
package com.red.circle.other.inner.model.cmd.team;
|
|
||||||
|
|
||||||
import com.red.circle.framework.core.dto.PageCommand;
|
|
||||||
import java.io.Serial;
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.EqualsAndHashCode;
|
|
||||||
import lombok.experimental.Accessors;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 后台手动发放主播工资预览.
|
|
||||||
*/
|
|
||||||
@EqualsAndHashCode(callSuper = true)
|
|
||||||
@Data
|
|
||||||
@Accessors(chain = true)
|
|
||||||
public class TeamManualSalaryPaymentQryCmd extends PageCommand {
|
|
||||||
|
|
||||||
@Serial
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 归属系统.
|
|
||||||
*/
|
|
||||||
private String sysOrigin;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 国家 code.
|
|
||||||
*/
|
|
||||||
private String countryCode;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 工资账期,为空时使用当前整月账期.
|
|
||||||
*/
|
|
||||||
private Integer billBelong;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 用户 id.
|
|
||||||
*/
|
|
||||||
private Long userId;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 排序字段.
|
|
||||||
*/
|
|
||||||
private String sortField;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 排序方向.
|
|
||||||
*/
|
|
||||||
private String sortOrder;
|
|
||||||
}
|
|
||||||
@ -29,16 +29,6 @@ public class TeamManagerAddCmd extends Command {
|
|||||||
@NotBlank(message = "regionId required.")
|
@NotBlank(message = "regionId required.")
|
||||||
private String regionId;
|
private String regionId;
|
||||||
|
|
||||||
private Boolean canAddBdLeader;
|
|
||||||
|
|
||||||
private Boolean canGiftProps;
|
|
||||||
|
|
||||||
private Boolean canBanUser;
|
|
||||||
|
|
||||||
private Boolean canUnbanUser;
|
|
||||||
|
|
||||||
private Boolean canChangeCountry;
|
|
||||||
|
|
||||||
@NotNull(message = "createUser required.")
|
@NotNull(message = "createUser required.")
|
||||||
private Long createUser;
|
private Long createUser;
|
||||||
|
|
||||||
|
|||||||
@ -1,158 +0,0 @@
|
|||||||
package com.red.circle.other.inner.model.dto.agency.agency;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
|
||||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
|
||||||
import java.io.Serial;
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.experimental.Accessors;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 后台手动发放主播工资预览.
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@Accessors(chain = true)
|
|
||||||
public class TeamManualSalaryPaymentDTO implements Serializable {
|
|
||||||
|
|
||||||
@Serial
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 成员目标记录 id.
|
|
||||||
*/
|
|
||||||
private String id;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 归属系统.
|
|
||||||
*/
|
|
||||||
private String sysOrigin;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 国家 code.
|
|
||||||
*/
|
|
||||||
private String countryCode;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 区域 id.
|
|
||||||
*/
|
|
||||||
private String region;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 团队 id.
|
|
||||||
*/
|
|
||||||
@JsonSerialize(using = ToStringSerializer.class)
|
|
||||||
private Long teamId;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 团队拥有者用户 id.
|
|
||||||
*/
|
|
||||||
@JsonSerialize(using = ToStringSerializer.class)
|
|
||||||
private Long teamOwnId;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 主播用户 id.
|
|
||||||
*/
|
|
||||||
@JsonSerialize(using = ToStringSerializer.class)
|
|
||||||
private Long userId;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 当前账期.
|
|
||||||
*/
|
|
||||||
private Integer billBelong;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 上次结算的积分.
|
|
||||||
*/
|
|
||||||
private Long lastSettlementTarget;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 本次积分.
|
|
||||||
*/
|
|
||||||
private Long currentTarget;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 本次积分档位.
|
|
||||||
*/
|
|
||||||
private Integer policyLevel;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 是否满足任意档位.
|
|
||||||
*/
|
|
||||||
private Boolean satisfyLevel;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 当前用户是否为代理.
|
|
||||||
*/
|
|
||||||
private Boolean agentMember;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 当前账期按积分档位计算出的工资.
|
|
||||||
*/
|
|
||||||
private BigDecimal expectedSalary;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 当前账期主播应发工资.
|
|
||||||
*/
|
|
||||||
private BigDecimal expectedMemberSalary;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 当前账期代理应发工资.
|
|
||||||
*/
|
|
||||||
private BigDecimal expectedAgentSalary;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 待结算工资 = 当前账期应发工资 - 当前账期实收工资.
|
|
||||||
*/
|
|
||||||
private BigDecimal payableSalary;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 主播待结算工资 = 主播应发工资 - 主播实收工资.
|
|
||||||
*/
|
|
||||||
private BigDecimal payableMemberSalary;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 代理待结算工资 = 代理应发工资 - 代理实收工资.
|
|
||||||
*/
|
|
||||||
private BigDecimal payableAgentSalary;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 当前账期总发放工资.
|
|
||||||
*/
|
|
||||||
private BigDecimal totalIssuedSalary;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 当前账期主播实收工资.
|
|
||||||
*/
|
|
||||||
private BigDecimal memberIssuedSalary;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 当前账期代理实收工资.
|
|
||||||
*/
|
|
||||||
private BigDecimal agentIssuedSalary;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 当前账期多发工资.
|
|
||||||
*/
|
|
||||||
private BigDecimal overIssuedSalary;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 当前账期主播多发工资.
|
|
||||||
*/
|
|
||||||
private BigDecimal memberOverIssuedSalary;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 当前账期代理多发工资.
|
|
||||||
*/
|
|
||||||
private BigDecimal agentOverIssuedSalary;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 当前工资余额.
|
|
||||||
*/
|
|
||||||
private BigDecimal currentSalaryBalance;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 当前档位是否已发放.
|
|
||||||
*/
|
|
||||||
private Boolean paid;
|
|
||||||
}
|
|
||||||
@ -1,88 +0,0 @@
|
|||||||
package com.red.circle.other.inner.model.dto.agency.agency;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
|
||||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
|
||||||
import java.io.Serial;
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.experimental.Accessors;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 后台手动发放主播工资结果.
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@Accessors(chain = true)
|
|
||||||
public class TeamManualSalaryPaymentResultDTO implements Serializable {
|
|
||||||
|
|
||||||
@Serial
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 工资发放明细 id.
|
|
||||||
*/
|
|
||||||
private String id;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 归属系统.
|
|
||||||
*/
|
|
||||||
private String sysOrigin;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 国家 code.
|
|
||||||
*/
|
|
||||||
private String countryCode;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 区域 id.
|
|
||||||
*/
|
|
||||||
private String region;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 团队 id.
|
|
||||||
*/
|
|
||||||
@JsonSerialize(using = ToStringSerializer.class)
|
|
||||||
private Long teamId;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 团队拥有者用户 id.
|
|
||||||
*/
|
|
||||||
@JsonSerialize(using = ToStringSerializer.class)
|
|
||||||
private Long teamOwnId;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 主播用户 id.
|
|
||||||
*/
|
|
||||||
@JsonSerialize(using = ToStringSerializer.class)
|
|
||||||
private Long userId;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 当前账期.
|
|
||||||
*/
|
|
||||||
private Integer billBelong;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 发放前工资余额.
|
|
||||||
*/
|
|
||||||
private BigDecimal beforeSalaryBalance;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 发放后工资余额.
|
|
||||||
*/
|
|
||||||
private BigDecimal afterSalaryBalance;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 本次发放工资.
|
|
||||||
*/
|
|
||||||
private BigDecimal issuedSalary;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 本次积分.
|
|
||||||
*/
|
|
||||||
private Long currentTarget;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 发放档位.
|
|
||||||
*/
|
|
||||||
private Integer policyLevel;
|
|
||||||
}
|
|
||||||
@ -32,16 +32,6 @@ public class TeamManagerDTO extends DTO {
|
|||||||
|
|
||||||
private String regionId;
|
private String regionId;
|
||||||
|
|
||||||
private Boolean canAddBdLeader;
|
|
||||||
|
|
||||||
private Boolean canGiftProps;
|
|
||||||
|
|
||||||
private Boolean canBanUser;
|
|
||||||
|
|
||||||
private Boolean canUnbanUser;
|
|
||||||
|
|
||||||
private Boolean canChangeCountry;
|
|
||||||
|
|
||||||
private Timestamp createTime;
|
private Timestamp createTime;
|
||||||
|
|
||||||
private Timestamp updateTime;
|
private Timestamp updateTime;
|
||||||
|
|||||||
@ -96,11 +96,6 @@ public class GiftConfigDTO implements Serializable {
|
|||||||
*/
|
*/
|
||||||
private String giftTab;
|
private String giftTab;
|
||||||
|
|
||||||
/**
|
|
||||||
* CP礼物关系类型:CP/BROTHER/SISTERS.
|
|
||||||
*/
|
|
||||||
private String cpRelationType;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 0.未删除 1.已删除.
|
* 0.未删除 1.已删除.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
package com.red.circle.wallet.inner.model.cmd;
|
package com.red.circle.wallet.inner.model.cmd;
|
||||||
|
|
||||||
import com.red.circle.common.business.dto.cmd.HistoryRangeTimeQryPageCmd;
|
import com.red.circle.framework.core.dto.CommonCommand;
|
||||||
import jakarta.validation.constraints.NotBlank;
|
import jakarta.validation.constraints.NotBlank;
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
@ -13,7 +13,7 @@ import lombok.experimental.Accessors;
|
|||||||
@Data
|
@Data
|
||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
@Accessors(chain = true)
|
@Accessors(chain = true)
|
||||||
public class UserFreightBalanceRunningWaterExportQryCmd extends HistoryRangeTimeQryPageCmd {
|
public class UserFreightBalanceRunningWaterExportQryCmd extends CommonCommand {
|
||||||
|
|
||||||
@Serial
|
@Serial
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
@ -27,31 +27,7 @@ public class UserFreightBalanceRunningWaterExportQryCmd extends HistoryRangeTime
|
|||||||
/**
|
/**
|
||||||
* 日期yyyyMM.
|
* 日期yyyyMM.
|
||||||
*/
|
*/
|
||||||
|
@NotBlank
|
||||||
private String monthDate;
|
private String monthDate;
|
||||||
|
|
||||||
/**
|
|
||||||
* 发送人用户id.
|
|
||||||
*/
|
|
||||||
private Long userId;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 接收人用户id.
|
|
||||||
*/
|
|
||||||
private Long acceptUserId;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 来源.
|
|
||||||
*/
|
|
||||||
private String origin;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 查询后台操作流水.
|
|
||||||
*/
|
|
||||||
private Boolean queryBackOperationUser;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 操作用户ID,多个用逗号分隔.
|
|
||||||
*/
|
|
||||||
private String createUsers;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -42,9 +42,5 @@ public class UserFreightBalanceRunningWaterPageQryCmd extends HistoryRangeTimeQr
|
|||||||
*/
|
*/
|
||||||
private Boolean queryBackOperationUser;
|
private Boolean queryBackOperationUser;
|
||||||
|
|
||||||
/**
|
|
||||||
* 操作用户ID,多个用逗号分隔.
|
|
||||||
*/
|
|
||||||
private String createUsers;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -50,11 +50,6 @@ public class UserGoldRunningWaterBackQryCmd extends Command {
|
|||||||
@JsonSerialize(using = ToStringSerializer.class)
|
@JsonSerialize(using = ToStringSerializer.class)
|
||||||
private Long backOperationUser;
|
private Long backOperationUser;
|
||||||
|
|
||||||
/**
|
|
||||||
* 后台操作用户ID,多个用逗号分隔.
|
|
||||||
*/
|
|
||||||
private String backOperationUsers;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 跟踪id.
|
* 跟踪id.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -755,11 +755,6 @@ public enum GoldOrigin {
|
|||||||
*/
|
*/
|
||||||
CP_LOVE_LETTER("CP love letter"),
|
CP_LOVE_LETTER("CP love letter"),
|
||||||
|
|
||||||
/**
|
|
||||||
* 解除 CP/Brother/Sisters 关系.
|
|
||||||
*/
|
|
||||||
CP_DISMISS("CP dismiss"),
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* cp榜单(周榜和季度榜)
|
* cp榜单(周榜和季度榜)
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -1,36 +0,0 @@
|
|||||||
package com.red.circle.console.adapter.app.activity;
|
|
||||||
|
|
||||||
import com.red.circle.console.app.dto.clienobject.app.activity.cp.ResidentCpConfigCO;
|
|
||||||
import com.red.circle.console.app.dto.cmd.app.activity.cp.ResidentCpConfigSaveCmd;
|
|
||||||
import com.red.circle.console.app.service.app.activity.ResidentCpActivityService;
|
|
||||||
import com.red.circle.console.infra.annotations.OpsOperationReqLog;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import org.springframework.validation.annotation.Validated;
|
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RequestBody;
|
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 常驻 CP 后台接口.
|
|
||||||
*/
|
|
||||||
@Validated
|
|
||||||
@RestController
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
@RequestMapping("/resident-activity/cp")
|
|
||||||
public class ResidentCpActivityRestController {
|
|
||||||
|
|
||||||
private final ResidentCpActivityService residentCpActivityService;
|
|
||||||
|
|
||||||
@GetMapping("/config")
|
|
||||||
public ResidentCpConfigCO getConfig(String sysOrigin) {
|
|
||||||
return residentCpActivityService.getConfig(sysOrigin);
|
|
||||||
}
|
|
||||||
|
|
||||||
@OpsOperationReqLog(value = "保存 CP 等级积分配置")
|
|
||||||
@PostMapping("/config/save")
|
|
||||||
public void saveConfig(@RequestBody @Validated ResidentCpConfigSaveCmd cmd) {
|
|
||||||
residentCpActivityService.saveConfig(cmd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -2,11 +2,8 @@ package com.red.circle.console.adapter.app.order;
|
|||||||
|
|
||||||
import com.red.circle.console.app.dto.clienobject.order.InAppPurchaseDetailsCO;
|
import com.red.circle.console.app.dto.clienobject.order.InAppPurchaseDetailsCO;
|
||||||
import com.red.circle.console.app.service.app.order.InAppPurchaseBackService;
|
import com.red.circle.console.app.service.app.order.InAppPurchaseBackService;
|
||||||
import com.red.circle.console.infra.annotations.OpsOperationReqLog;
|
|
||||||
import com.red.circle.framework.web.controller.BaseController;
|
import com.red.circle.framework.web.controller.BaseController;
|
||||||
import com.red.circle.order.inner.model.cmd.inapp.InAppPurchaseDetailsQryCmd;
|
import com.red.circle.order.inner.model.cmd.inapp.InAppPurchaseDetailsQryCmd;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
@ -53,14 +50,4 @@ public class InAppPurchaseRestController extends BaseController {
|
|||||||
return inAppPurchaseBackService.statistics(query);
|
return inAppPurchaseBackService.statistics(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 订单详情导出.
|
|
||||||
*/
|
|
||||||
@OpsOperationReqLog(value = "导出-订单详情", ignoreRequestParam = true)
|
|
||||||
@GetMapping("/details/export")
|
|
||||||
public void exportDetails(HttpServletResponse response, InAppPurchaseDetailsQryCmd query)
|
|
||||||
throws IOException {
|
|
||||||
inAppPurchaseBackService.exportDetails(response, query);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,9 +6,7 @@ import com.red.circle.console.infra.annotations.OpsOperationReqLog;
|
|||||||
import com.red.circle.framework.dto.PageResult;
|
import com.red.circle.framework.dto.PageResult;
|
||||||
import com.red.circle.framework.web.controller.BaseController;
|
import com.red.circle.framework.web.controller.BaseController;
|
||||||
import com.red.circle.order.inner.model.cmd.SysPayCountryAddCmd;
|
import com.red.circle.order.inner.model.cmd.SysPayCountryAddCmd;
|
||||||
import com.red.circle.order.inner.model.cmd.SysPayCountryCurrencyRateSyncCmd;
|
|
||||||
import com.red.circle.order.inner.model.cmd.SysPayCountryQryCmd;
|
import com.red.circle.order.inner.model.cmd.SysPayCountryQryCmd;
|
||||||
import com.red.circle.order.inner.model.dto.PayCountryCurrencyRateSyncDTO;
|
|
||||||
import com.red.circle.order.inner.model.dto.PayCountryDTO;
|
import com.red.circle.order.inner.model.dto.PayCountryDTO;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
@ -118,14 +116,5 @@ public class SysPayOpenCountryController extends BaseController {
|
|||||||
sysPayCountryService.shelf(id, shelf);
|
sysPayCountryService.shelf(id, shelf);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 同步全球支付国家货币和实时汇率.
|
|
||||||
*/
|
|
||||||
@OpsOperationReqLog("同步全球支付国家货币汇率")
|
|
||||||
@PostMapping("/sync-currency-rates")
|
|
||||||
public PayCountryCurrencyRateSyncDTO syncCurrencyRates(
|
|
||||||
@RequestBody @Validated SysPayCountryCurrencyRateSyncCmd cmd) {
|
|
||||||
return sysPayCountryService.syncCurrencyRates(cmd);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,19 +1,12 @@
|
|||||||
package com.red.circle.console.adapter.app.team;
|
package com.red.circle.console.adapter.app.team;
|
||||||
|
|
||||||
import com.red.circle.console.app.dto.clienobject.team.TeamManualSalaryCO;
|
|
||||||
import com.red.circle.console.app.dto.clienobject.team.TeamManualSalaryResultCO;
|
|
||||||
import com.red.circle.console.app.dto.clienobject.team.TeamSalaryCO;
|
import com.red.circle.console.app.dto.clienobject.team.TeamSalaryCO;
|
||||||
import com.red.circle.console.app.service.app.team.TeamSalaryBackService;
|
import com.red.circle.console.app.service.app.team.TeamSalaryBackService;
|
||||||
import com.red.circle.framework.dto.PageResult;
|
import com.red.circle.framework.dto.PageResult;
|
||||||
import com.red.circle.framework.web.controller.BaseController;
|
import com.red.circle.framework.web.controller.BaseController;
|
||||||
import com.red.circle.other.inner.model.cmd.team.TeamManualSalaryPaymentCmd;
|
|
||||||
import com.red.circle.other.inner.model.cmd.team.TeamManualSalaryPaymentQryCmd;
|
|
||||||
import com.red.circle.other.inner.model.cmd.team.TeamSalaryBackQryCmd;
|
import com.red.circle.other.inner.model.cmd.team.TeamSalaryBackQryCmd;
|
||||||
import java.util.List;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RequestBody;
|
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
@ -37,22 +30,4 @@ public class TeamSalaryRestController extends BaseController {
|
|||||||
return teamSalaryBackService.listByCondition(query);
|
return teamSalaryBackService.listByCondition(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 手动工资发放预览.
|
|
||||||
*/
|
|
||||||
@GetMapping("/manual/page")
|
|
||||||
public PageResult<TeamManualSalaryCO> manualSalaryPage(TeamManualSalaryPaymentQryCmd query) {
|
|
||||||
return teamSalaryBackService.manualSalaryPage(query);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 确认手动发放工资.
|
|
||||||
*/
|
|
||||||
@PostMapping("/manual/pay")
|
|
||||||
public List<TeamManualSalaryResultCO> manualSalaryPay(
|
|
||||||
@RequestBody TeamManualSalaryPaymentCmd cmd) {
|
|
||||||
cmd.setOperationUserId(getReqUserId());
|
|
||||||
return teamSalaryBackService.manualSalaryPay(cmd);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,7 +7,6 @@ import com.red.circle.console.app.dto.cmd.datav.CountryDashboardGameMetricQryCmd
|
|||||||
import com.red.circle.console.app.dto.cmd.datav.CountryDashboardQryCmd;
|
import com.red.circle.console.app.dto.cmd.datav.CountryDashboardQryCmd;
|
||||||
import com.red.circle.console.app.dto.cmd.datav.CountryDashboardRechargeDetailQryCmd;
|
import com.red.circle.console.app.dto.cmd.datav.CountryDashboardRechargeDetailQryCmd;
|
||||||
import com.red.circle.console.app.service.app.datav.CountryDashboardDailyMetricService;
|
import com.red.circle.console.app.service.app.datav.CountryDashboardDailyMetricService;
|
||||||
import com.red.circle.console.app.service.app.datav.CountryDashboardBackfillLockService;
|
|
||||||
import com.red.circle.console.app.service.app.datav.CountryDashboardGameMetricService;
|
import com.red.circle.console.app.service.app.datav.CountryDashboardGameMetricService;
|
||||||
import com.red.circle.console.app.service.app.datav.CountryDashboardService;
|
import com.red.circle.console.app.service.app.datav.CountryDashboardService;
|
||||||
import com.red.circle.console.app.service.app.user.DatavService;
|
import com.red.circle.console.app.service.app.user.DatavService;
|
||||||
@ -42,7 +41,6 @@ public class DatavRestController extends BaseController {
|
|||||||
private final DatavService userExpandService;
|
private final DatavService userExpandService;
|
||||||
private final CountryDashboardService countryDashboardService;
|
private final CountryDashboardService countryDashboardService;
|
||||||
private final CountryDashboardDailyMetricService countryDashboardDailyMetricService;
|
private final CountryDashboardDailyMetricService countryDashboardDailyMetricService;
|
||||||
private final CountryDashboardBackfillLockService countryDashboardBackfillLockService;
|
|
||||||
private final CountryDashboardGameMetricService countryDashboardGameMetricService;
|
private final CountryDashboardGameMetricService countryDashboardGameMetricService;
|
||||||
|
|
||||||
@Value("${red-circle.country-dashboard.query-enabled:true}")
|
@Value("${red-circle.country-dashboard.query-enabled:true}")
|
||||||
@ -118,21 +116,14 @@ public class DatavRestController extends BaseController {
|
|||||||
}
|
}
|
||||||
LocalDate parsedStartDate = LocalDate.parse(startDate);
|
LocalDate parsedStartDate = LocalDate.parse(startDate);
|
||||||
LocalDate parsedEndDate = LocalDate.parse(endDate);
|
LocalDate parsedEndDate = LocalDate.parse(endDate);
|
||||||
Map<String, Object> refreshed = countryDashboardBackfillLockService.call(() -> {
|
List<String> refreshedTimezones = countryDashboardDailyMetricService.refreshRange(
|
||||||
List<String> countryTimezones = countryDashboardDailyMetricService.refreshRange(
|
parsedStartDate, parsedEndDate, sysOrigin, statTimezones);
|
||||||
parsedStartDate, parsedEndDate, sysOrigin, statTimezones);
|
|
||||||
List<String> gameTimezones = countryDashboardGameMetricService.refreshRange(
|
|
||||||
parsedStartDate, parsedEndDate, sysOrigin, statTimezones);
|
|
||||||
return Map.of(
|
|
||||||
"countryStatTimezones", countryTimezones,
|
|
||||||
"gameStatTimezones", gameTimezones);
|
|
||||||
});
|
|
||||||
return Map.of(
|
return Map.of(
|
||||||
"status", "success",
|
"status", "success",
|
||||||
"startDate", parsedStartDate.toString(),
|
"startDate", parsedStartDate.toString(),
|
||||||
"endDate", parsedEndDate.toString(),
|
"endDate", parsedEndDate.toString(),
|
||||||
"sysOrigin", sysOrigin,
|
"sysOrigin", sysOrigin,
|
||||||
"statTimezones", refreshed);
|
"statTimezones", refreshedTimezones);
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/country-dashboard/game-metrics/backfill")
|
@PostMapping("/country-dashboard/game-metrics/backfill")
|
||||||
@ -146,21 +137,14 @@ public class DatavRestController extends BaseController {
|
|||||||
}
|
}
|
||||||
LocalDate parsedStartDate = LocalDate.parse(startDate);
|
LocalDate parsedStartDate = LocalDate.parse(startDate);
|
||||||
LocalDate parsedEndDate = LocalDate.parse(endDate);
|
LocalDate parsedEndDate = LocalDate.parse(endDate);
|
||||||
Map<String, Object> refreshed = countryDashboardBackfillLockService.call(() -> {
|
List<String> refreshedTimezones = countryDashboardGameMetricService.refreshRange(
|
||||||
List<String> countryTimezones = countryDashboardDailyMetricService.refreshRange(
|
parsedStartDate, parsedEndDate, sysOrigin, statTimezones);
|
||||||
parsedStartDate, parsedEndDate, sysOrigin, statTimezones);
|
|
||||||
List<String> gameTimezones = countryDashboardGameMetricService.refreshRange(
|
|
||||||
parsedStartDate, parsedEndDate, sysOrigin, statTimezones);
|
|
||||||
return Map.of(
|
|
||||||
"countryStatTimezones", countryTimezones,
|
|
||||||
"gameStatTimezones", gameTimezones);
|
|
||||||
});
|
|
||||||
return Map.of(
|
return Map.of(
|
||||||
"status", "success",
|
"status", "success",
|
||||||
"startDate", parsedStartDate.toString(),
|
"startDate", parsedStartDate.toString(),
|
||||||
"endDate", parsedEndDate.toString(),
|
"endDate", parsedEndDate.toString(),
|
||||||
"sysOrigin", sysOrigin,
|
"sysOrigin", sysOrigin,
|
||||||
"statTimezones", refreshed);
|
"statTimezones", refreshedTimezones);
|
||||||
}
|
}
|
||||||
|
|
||||||
private CountryDashboardCO emptyCountryDashboard(CountryDashboardQryCmd cmd) {
|
private CountryDashboardCO emptyCountryDashboard(CountryDashboardQryCmd cmd) {
|
||||||
|
|||||||
@ -141,22 +141,15 @@ public class UserFreightRestController extends BaseController {
|
|||||||
|
|
||||||
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
|
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
|
||||||
response.setCharacterEncoding("utf-8");
|
response.setCharacterEncoding("utf-8");
|
||||||
String fileName = URLEncoder.encode("Export Freight RunningWater " + getExportNameSuffix(query),
|
String fileName = URLEncoder.encode("Export Freight RunningWater " + query.getMonthDate(),
|
||||||
|
StandardCharsets.UTF_8)
|
||||||
|
.replaceAll("\\+", "%20");
|
||||||
|
String sheetName = URLEncoder.encode("Export Freight RunningWater " + query.getMonthDate(),
|
||||||
StandardCharsets.UTF_8)
|
StandardCharsets.UTF_8)
|
||||||
.replaceAll("\\+", "%20");
|
.replaceAll("\\+", "%20");
|
||||||
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
|
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
|
||||||
EasyExcel.write(response.getOutputStream(), UserFreightBalanceRunningWaterExportModel.class)
|
EasyExcel.write(response.getOutputStream(), UserFreightBalanceRunningWaterExportModel.class)
|
||||||
.sheet("FreightRunningWater").doWrite(userFreightService.listExport(query));
|
.sheet(sheetName).doWrite(userFreightService.listExport(query));
|
||||||
}
|
|
||||||
|
|
||||||
private String getExportNameSuffix(UserFreightBalanceRunningWaterExportQryCmd query) {
|
|
||||||
if (query.getMonthDate() != null && !query.getMonthDate().isBlank()) {
|
|
||||||
return query.getMonthDate();
|
|
||||||
}
|
|
||||||
if (query.getStartTime() != null || query.getEndTime() != null) {
|
|
||||||
return query.getStartTime() + "-" + query.getEndTime();
|
|
||||||
}
|
|
||||||
return "Filtered";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -11,8 +11,6 @@ import com.red.circle.wallet.inner.model.cmd.DeductGoldCmd;
|
|||||||
import com.red.circle.wallet.inner.model.cmd.DiamondCmd;
|
import com.red.circle.wallet.inner.model.cmd.DiamondCmd;
|
||||||
import com.red.circle.wallet.inner.model.cmd.SendGoldCmd;
|
import com.red.circle.wallet.inner.model.cmd.SendGoldCmd;
|
||||||
import com.red.circle.wallet.inner.model.cmd.UserGoldRunningWaterBackQryCmd;
|
import com.red.circle.wallet.inner.model.cmd.UserGoldRunningWaterBackQryCmd;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
@ -54,16 +52,6 @@ public class UserWalletRestController extends BaseController {
|
|||||||
return userWalletService.getGoldRunningWaterCls(query);
|
return userWalletService.getGoldRunningWaterCls(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 流水导出.
|
|
||||||
*/
|
|
||||||
@GetMapping("/gold/running-water/cls/export")
|
|
||||||
public void exportGoldRunningWaterCls(
|
|
||||||
HttpServletResponse response,
|
|
||||||
@Validated UserGoldRunningWaterBackQryCmd query) throws IOException {
|
|
||||||
userWalletService.exportGoldRunningWater(response, query);
|
|
||||||
}
|
|
||||||
|
|
||||||
@OpsOperationReqLog("发送金币")
|
@OpsOperationReqLog("发送金币")
|
||||||
@PostMapping("/send-gold")
|
@PostMapping("/send-gold")
|
||||||
public void sendGold(@RequestBody @Validated SendGoldCmd param) {
|
public void sendGold(@RequestBody @Validated SendGoldCmd param) {
|
||||||
|
|||||||
@ -29,12 +29,6 @@
|
|||||||
<version>${easyexcel.version}</version>
|
<version>${easyexcel.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-test</artifactId>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<parent>
|
<parent>
|
||||||
|
|||||||
@ -94,12 +94,6 @@ public class UserFreightBalanceRunningWaterExportModel implements Serializable {
|
|||||||
@ExcelProperty(value = "Origin Name")
|
@ExcelProperty(value = "Origin Name")
|
||||||
private String originName;
|
private String originName;
|
||||||
|
|
||||||
/**
|
|
||||||
* 操作人.
|
|
||||||
*/
|
|
||||||
@ExcelProperty(value = "Operator")
|
|
||||||
private String operationUserNickname;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 备注
|
* 备注
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -1,88 +0,0 @@
|
|||||||
package com.red.circle.console.app.excel.model.order;
|
|
||||||
|
|
||||||
import com.alibaba.excel.annotation.ExcelProperty;
|
|
||||||
import java.io.Serial;
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.experimental.Accessors;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 内购订单详情导出模型.
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@Accessors(chain = true)
|
|
||||||
public class InAppPurchaseDetailsExportModel implements Serializable {
|
|
||||||
|
|
||||||
@Serial
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
@ExcelProperty(value = "Env")
|
|
||||||
private String env;
|
|
||||||
|
|
||||||
@ExcelProperty(value = "Sys Origin")
|
|
||||||
private String sysOrigin;
|
|
||||||
|
|
||||||
@ExcelProperty(value = "Platform")
|
|
||||||
private String platform;
|
|
||||||
|
|
||||||
@ExcelProperty(value = "Factory")
|
|
||||||
private String factoryCode;
|
|
||||||
|
|
||||||
@ExcelProperty(value = "Channel")
|
|
||||||
private String channel;
|
|
||||||
|
|
||||||
@ExcelProperty(value = "Buyer User ID")
|
|
||||||
private String buyerUserId;
|
|
||||||
|
|
||||||
@ExcelProperty(value = "Buyer Account")
|
|
||||||
private String buyerAccount;
|
|
||||||
|
|
||||||
@ExcelProperty(value = "Buyer Nickname")
|
|
||||||
private String buyerNickname;
|
|
||||||
|
|
||||||
@ExcelProperty(value = "Accept User ID")
|
|
||||||
private String acceptUserId;
|
|
||||||
|
|
||||||
@ExcelProperty(value = "Accept Account")
|
|
||||||
private String acceptAccount;
|
|
||||||
|
|
||||||
@ExcelProperty(value = "Accept Nickname")
|
|
||||||
private String acceptNickname;
|
|
||||||
|
|
||||||
@ExcelProperty(value = "Amount(USD)")
|
|
||||||
private BigDecimal amountUsd;
|
|
||||||
|
|
||||||
@ExcelProperty(value = "Amount")
|
|
||||||
private BigDecimal amount;
|
|
||||||
|
|
||||||
@ExcelProperty(value = "Currency")
|
|
||||||
private String currency;
|
|
||||||
|
|
||||||
@ExcelProperty(value = "Description")
|
|
||||||
private String productDescriptor;
|
|
||||||
|
|
||||||
@ExcelProperty(value = "Status")
|
|
||||||
private String status;
|
|
||||||
|
|
||||||
@ExcelProperty(value = "Receipt Type")
|
|
||||||
private String receiptType;
|
|
||||||
|
|
||||||
@ExcelProperty(value = "Third Party Order ID")
|
|
||||||
private String orderId;
|
|
||||||
|
|
||||||
@ExcelProperty(value = "App Order ID")
|
|
||||||
private String appOrderId;
|
|
||||||
|
|
||||||
@ExcelProperty(value = "Track ID")
|
|
||||||
private String trackId;
|
|
||||||
|
|
||||||
@ExcelProperty(value = "Country Code")
|
|
||||||
private String countryCode;
|
|
||||||
|
|
||||||
@ExcelProperty(value = "Create Time")
|
|
||||||
private String createTime;
|
|
||||||
|
|
||||||
@ExcelProperty(value = "Update Time")
|
|
||||||
private String updateTime;
|
|
||||||
}
|
|
||||||
@ -1,91 +0,0 @@
|
|||||||
package com.red.circle.console.app.excel.model.wallet;
|
|
||||||
|
|
||||||
import com.alibaba.excel.annotation.ExcelProperty;
|
|
||||||
import java.io.Serial;
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.experimental.Accessors;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 后台金币流水导出.
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@Accessors(chain = true)
|
|
||||||
public class UserGoldRunningWaterExportModel implements Serializable {
|
|
||||||
|
|
||||||
@Serial
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 流水ID.
|
|
||||||
*/
|
|
||||||
@ExcelProperty(value = "Record ID")
|
|
||||||
private String recordId;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 系统来源.
|
|
||||||
*/
|
|
||||||
@ExcelProperty(value = "Sys Origin")
|
|
||||||
private String sysOrigin;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 用户ID.
|
|
||||||
*/
|
|
||||||
@ExcelProperty(value = "User ID")
|
|
||||||
private String userId;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 用户账号.
|
|
||||||
*/
|
|
||||||
@ExcelProperty(value = "User Account")
|
|
||||||
private String userAccount;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 用户昵称.
|
|
||||||
*/
|
|
||||||
@ExcelProperty(value = "User Nickname")
|
|
||||||
private String userNickname;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 类型.
|
|
||||||
*/
|
|
||||||
@ExcelProperty(value = "Type")
|
|
||||||
private String type;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 金币金额.
|
|
||||||
*/
|
|
||||||
@ExcelProperty(value = "Amount")
|
|
||||||
private BigDecimal quantity;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 操作后余额.
|
|
||||||
*/
|
|
||||||
@ExcelProperty(value = "Balance")
|
|
||||||
private BigDecimal balance;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 原因.
|
|
||||||
*/
|
|
||||||
@ExcelProperty(value = "Reason")
|
|
||||||
private String originName;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 备注.
|
|
||||||
*/
|
|
||||||
@ExcelProperty(value = "Remark")
|
|
||||||
private String remark;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 操作人.
|
|
||||||
*/
|
|
||||||
@ExcelProperty(value = "Operator")
|
|
||||||
private String backOperationName;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 操作时间.
|
|
||||||
*/
|
|
||||||
@ExcelProperty(value = "Create Time")
|
|
||||||
private String createTime;
|
|
||||||
}
|
|
||||||
@ -1,38 +0,0 @@
|
|||||||
package com.red.circle.console.app.scheduler;
|
|
||||||
|
|
||||||
import com.red.circle.component.redis.annotation.TaskCacheLock;
|
|
||||||
import com.red.circle.console.app.service.app.datav.CountryDashboardDailyMetricService;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
|
||||||
import org.springframework.scheduling.annotation.Scheduled;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 国家数据大屏活跃和留存增量聚合任务.
|
|
||||||
*/
|
|
||||||
@Slf4j
|
|
||||||
@Component
|
|
||||||
@ConditionalOnProperty(
|
|
||||||
name = "red-circle.country-dashboard.active-retention-refresh-enabled",
|
|
||||||
havingValue = "true",
|
|
||||||
matchIfMissing = true)
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class CountryDashboardActiveRetentionMetricTask {
|
|
||||||
|
|
||||||
private final CountryDashboardDailyMetricService countryDashboardDailyMetricService;
|
|
||||||
|
|
||||||
@Value("${red-circle.country-dashboard.active-retention-refresh-days:32}")
|
|
||||||
private int refreshDays;
|
|
||||||
|
|
||||||
@Scheduled(cron = "${red-circle.country-dashboard.active-retention-refresh-cron:0 */10 * * * ?}",
|
|
||||||
zone = "Asia/Shanghai")
|
|
||||||
@TaskCacheLock(key = "COUNTRY_DASHBOARD_ACTIVE_RETENTION_REFRESH", expireSecond = 60 * 8)
|
|
||||||
public void refreshActiveRetention() {
|
|
||||||
long start = System.currentTimeMillis();
|
|
||||||
countryDashboardDailyMetricService.refreshActiveRetentionRecentDays(refreshDays);
|
|
||||||
log.info("country dashboard active retention refresh task finished, days={}, costMs={}",
|
|
||||||
refreshDays, System.currentTimeMillis() - start);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -6,7 +6,6 @@ import com.red.circle.console.app.service.app.datav.CountryDashboardGameMetricSe
|
|||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
|
||||||
import org.springframework.scheduling.annotation.Scheduled;
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
@ -15,7 +14,6 @@ import org.springframework.stereotype.Component;
|
|||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Component
|
@Component
|
||||||
@ConditionalOnProperty(name = "red-circle.country-dashboard.refresh-enabled", havingValue = "true")
|
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class CountryDashboardDailyMetricTask {
|
public class CountryDashboardDailyMetricTask {
|
||||||
|
|
||||||
|
|||||||
@ -1,286 +0,0 @@
|
|||||||
package com.red.circle.console.app.service.app.activity;
|
|
||||||
|
|
||||||
import com.red.circle.console.app.dto.clienobject.app.activity.cp.ResidentCpConfigCO;
|
|
||||||
import com.red.circle.console.app.dto.clienobject.app.activity.cp.ResidentCpLevelConfigCO;
|
|
||||||
import com.red.circle.console.app.dto.cmd.app.activity.cp.ResidentCpConfigSaveCmd;
|
|
||||||
import com.red.circle.console.app.dto.cmd.app.activity.cp.ResidentCpLevelConfigSaveCmd;
|
|
||||||
import com.red.circle.console.app.service.app.sys.CpCabinConfigService;
|
|
||||||
import com.red.circle.console.app.service.app.sys.SysEnumConfigService;
|
|
||||||
import com.red.circle.framework.core.asserts.ResponseAssert;
|
|
||||||
import com.red.circle.framework.core.response.ResponseErrorCode;
|
|
||||||
import com.red.circle.framework.dto.PageQuery;
|
|
||||||
import com.red.circle.framework.dto.PageResult;
|
|
||||||
import com.red.circle.other.inner.enums.config.EnumConfigKey;
|
|
||||||
import com.red.circle.other.inner.model.cmd.sys.SysCpCabinConfigQryCmd;
|
|
||||||
import com.red.circle.other.inner.model.dto.sys.EnumConfigDTO;
|
|
||||||
import com.red.circle.other.inner.model.dto.sys.SysCpCabinConfigDTO;
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.function.Function;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 常驻 CP 配置服务实现.
|
|
||||||
*/
|
|
||||||
@Service
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class ResidentCpActivityServiceImpl implements ResidentCpActivityService {
|
|
||||||
|
|
||||||
private static final int CP_LEVEL_COUNT = 6;
|
|
||||||
private static final int CP_MIN_LEVEL = 0;
|
|
||||||
private static final int QUERY_LIMIT = 50;
|
|
||||||
private static final String CONFIG_GROUP_NAME = "CP";
|
|
||||||
private static final String CONFIG_DATA_TYPE = "int";
|
|
||||||
private static final String RELATION_TYPE_CP = "CP";
|
|
||||||
private static final String RELATION_TYPE_BROTHER = "BROTHER";
|
|
||||||
private static final String RELATION_TYPE_SISTERS = "SISTERS";
|
|
||||||
|
|
||||||
private final CpCabinConfigService cpCabinConfigService;
|
|
||||||
private final SysEnumConfigService sysEnumConfigService;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ResidentCpConfigCO getConfig(String sysOrigin) {
|
|
||||||
String normalizedSysOrigin = normalizeSysOrigin(sysOrigin);
|
|
||||||
List<SysCpCabinConfigDTO> configs = listCpCabinConfigs(normalizedSysOrigin);
|
|
||||||
List<ResidentCpLevelConfigCO> levels = new ArrayList<>(CP_LEVEL_COUNT);
|
|
||||||
for (int level = CP_MIN_LEVEL; level < CP_LEVEL_COUNT; level++) {
|
|
||||||
SysCpCabinConfigDTO config = level < configs.size() ? configs.get(level) : null;
|
|
||||||
levels.add(toLevelCO(level, config));
|
|
||||||
}
|
|
||||||
return new ResidentCpConfigCO()
|
|
||||||
.setConfigured(!configs.isEmpty())
|
|
||||||
.setSysOrigin(normalizedSysOrigin)
|
|
||||||
.setDismissConsumeGolds(getDismissConsumeGolds(normalizedSysOrigin))
|
|
||||||
.setLevels(levels);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void saveConfig(ResidentCpConfigSaveCmd cmd) {
|
|
||||||
validateConfig(cmd);
|
|
||||||
String normalizedSysOrigin = normalizeSysOrigin(cmd.getSysOrigin());
|
|
||||||
List<SysCpCabinConfigDTO> configs = listCpCabinConfigs(normalizedSysOrigin);
|
|
||||||
Map<Long, SysCpCabinConfigDTO> configById = configs.stream()
|
|
||||||
.filter(item -> Objects.nonNull(item.getId()))
|
|
||||||
.collect(Collectors.toMap(SysCpCabinConfigDTO::getId, Function.identity(), (left, right) -> left));
|
|
||||||
|
|
||||||
for (ResidentCpLevelConfigSaveCmd levelCmd : sortedLevels(cmd.getLevels())) {
|
|
||||||
SysCpCabinConfigDTO config = Optional.ofNullable(levelCmd.getCabinConfigId())
|
|
||||||
.map(configById::get)
|
|
||||||
.orElseGet(() -> levelCmd.getLevel() < configs.size()
|
|
||||||
? configs.get(levelCmd.getLevel())
|
|
||||||
: null);
|
|
||||||
boolean exists = Objects.nonNull(config) && Objects.nonNull(config.getId());
|
|
||||||
if (!exists) {
|
|
||||||
config = new SysCpCabinConfigDTO();
|
|
||||||
}
|
|
||||||
config.setSysOrigin(normalizedSysOrigin)
|
|
||||||
.setName(defaultLevelName(levelCmd.getLevel(), levelCmd.getLevelName()))
|
|
||||||
.setCabinUnlockValue(defaultRequiredValue(levelCmd.getRequiredIntimacyValue()))
|
|
||||||
.setSort(levelCmd.getLevel().longValue());
|
|
||||||
|
|
||||||
if (exists) {
|
|
||||||
cpCabinConfigService.updateCpCabin(config);
|
|
||||||
} else {
|
|
||||||
cpCabinConfigService.addCpCabin(config);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
saveDismissConsumeGolds(normalizedSysOrigin, cmd.getDismissConsumeGolds());
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<SysCpCabinConfigDTO> listCpCabinConfigs(String sysOrigin) {
|
|
||||||
SysCpCabinConfigQryCmd query = new SysCpCabinConfigQryCmd().setSysOrigin(sysOrigin);
|
|
||||||
PageQuery pageQuery = new PageQuery();
|
|
||||||
pageQuery.setCursor(1);
|
|
||||||
pageQuery.setLimit(QUERY_LIMIT);
|
|
||||||
pageQuery.setSearchCount(false);
|
|
||||||
query.setPageQuery(pageQuery);
|
|
||||||
PageResult<SysCpCabinConfigDTO> result = cpCabinConfigService.getCpCabin(query);
|
|
||||||
return Optional.ofNullable(result.getRecords())
|
|
||||||
.stream()
|
|
||||||
.flatMap(java.util.Collection::stream)
|
|
||||||
.sorted(Comparator
|
|
||||||
.comparing((SysCpCabinConfigDTO item) -> Optional.ofNullable(item.getSort())
|
|
||||||
.orElse(Long.MAX_VALUE))
|
|
||||||
.thenComparing(item -> Optional.ofNullable(item.getCabinUnlockValue())
|
|
||||||
.orElse(Long.MAX_VALUE))
|
|
||||||
.thenComparing(item -> Optional.ofNullable(item.getId()).orElse(Long.MAX_VALUE)))
|
|
||||||
.toList();
|
|
||||||
}
|
|
||||||
|
|
||||||
private ResidentCpLevelConfigCO toLevelCO(int level, SysCpCabinConfigDTO config) {
|
|
||||||
return new ResidentCpLevelConfigCO()
|
|
||||||
.setLevel(level)
|
|
||||||
.setLevelName(Objects.isNull(config)
|
|
||||||
? defaultLevelName(level, null)
|
|
||||||
: defaultLevelName(level, config.getName()))
|
|
||||||
.setRequiredIntimacyValue(Objects.isNull(config)
|
|
||||||
? 0L
|
|
||||||
: defaultRequiredValue(config.getCabinUnlockValue()))
|
|
||||||
.setCabinConfigId(Objects.isNull(config) ? null : config.getId());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void validateConfig(ResidentCpConfigSaveCmd cmd) {
|
|
||||||
ResponseAssert.notBlank(ResponseErrorCode.REQUEST_PARAMETER_ERROR, cmd.getSysOrigin());
|
|
||||||
List<ResidentCpLevelConfigSaveCmd> levels = sortedLevels(cmd.getLevels());
|
|
||||||
Set<Integer> levelSet = new HashSet<>();
|
|
||||||
long previousRequiredValue = -1L;
|
|
||||||
for (ResidentCpLevelConfigSaveCmd level : levels) {
|
|
||||||
ResponseAssert.isTrue(ResponseErrorCode.REQUEST_PARAMETER_ERROR,
|
|
||||||
"CP level must be between 0 and 5.",
|
|
||||||
Objects.nonNull(level.getLevel()) && level.getLevel() >= CP_MIN_LEVEL
|
|
||||||
&& level.getLevel() < CP_LEVEL_COUNT && levelSet.add(level.getLevel()));
|
|
||||||
long requiredValue = defaultRequiredValue(level.getRequiredIntimacyValue());
|
|
||||||
ResponseAssert.isTrue(ResponseErrorCode.REQUEST_PARAMETER_ERROR,
|
|
||||||
"requiredIntimacyValue must be greater than or equal to zero.", requiredValue >= 0);
|
|
||||||
ResponseAssert.isTrue(ResponseErrorCode.REQUEST_PARAMETER_ERROR,
|
|
||||||
"requiredIntimacyValue must be ascending by level.",
|
|
||||||
requiredValue >= previousRequiredValue);
|
|
||||||
previousRequiredValue = requiredValue;
|
|
||||||
}
|
|
||||||
validateDismissConsumeGolds(cmd.getDismissConsumeGolds());
|
|
||||||
}
|
|
||||||
|
|
||||||
private Map<String, Long> getDismissConsumeGolds(String sysOrigin) {
|
|
||||||
Map<String, Long> result = defaultDismissConsumeGolds();
|
|
||||||
dismissConsumeGoldKeys().forEach((relationType, key) -> result.put(relationType,
|
|
||||||
enumConfigGoldValue(sysEnumConfigService.getByCode(key.name(), sysOrigin))));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void saveDismissConsumeGolds(String sysOrigin, Map<String, Long> dismissConsumeGolds) {
|
|
||||||
if (Objects.isNull(dismissConsumeGolds)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
dismissConsumeGoldKeys().forEach((relationType, key) -> {
|
|
||||||
if (dismissConsumeGolds.containsKey(relationType)) {
|
|
||||||
saveDismissConsumeGold(sysOrigin, key, dismissConsumeGolds.get(relationType));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void saveDismissConsumeGold(String sysOrigin, EnumConfigKey key, Long value) {
|
|
||||||
Long normalizedValue = defaultGold(value);
|
|
||||||
EnumConfigDTO enumConfig = sysEnumConfigService.getByCode(key.name(), sysOrigin);
|
|
||||||
boolean exists = Objects.nonNull(enumConfig) && Objects.nonNull(enumConfig.getId());
|
|
||||||
if (!exists) {
|
|
||||||
enumConfig = new EnumConfigDTO();
|
|
||||||
}
|
|
||||||
enumConfig.setSysOrigin(sysOrigin)
|
|
||||||
.setName(key.name())
|
|
||||||
.setTitle(dismissConsumeGoldTitle(key))
|
|
||||||
.setVal(String.valueOf(normalizedValue))
|
|
||||||
.setDescription(dismissConsumeGoldTitle(key))
|
|
||||||
.setDataType(CONFIG_DATA_TYPE)
|
|
||||||
.setReturnApp(Boolean.FALSE)
|
|
||||||
.setGroupName(CONFIG_GROUP_NAME);
|
|
||||||
if (exists) {
|
|
||||||
sysEnumConfigService.updateSysEnumConfig(enumConfig);
|
|
||||||
} else {
|
|
||||||
sysEnumConfigService.saveSysEnumConfig(enumConfig);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void validateDismissConsumeGolds(Map<String, Long> dismissConsumeGolds) {
|
|
||||||
if (Objects.isNull(dismissConsumeGolds)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
dismissConsumeGolds.forEach((relationType, gold) -> {
|
|
||||||
ResponseAssert.isTrue(ResponseErrorCode.REQUEST_PARAMETER_ERROR,
|
|
||||||
"relationType is not supported.",
|
|
||||||
dismissConsumeGoldKeys().containsKey(normalizeRelationType(relationType)));
|
|
||||||
ResponseAssert.isTrue(ResponseErrorCode.REQUEST_PARAMETER_ERROR,
|
|
||||||
"dismissConsumeGold must be greater than or equal to zero.",
|
|
||||||
defaultGold(gold) >= 0);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private Long enumConfigGoldValue(EnumConfigDTO enumConfig) {
|
|
||||||
if (Objects.isNull(enumConfig) || StringUtils.isBlank(enumConfig.getVal())) {
|
|
||||||
return 0L;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
return new BigDecimal(enumConfig.getVal()).longValue();
|
|
||||||
} catch (NumberFormatException ex) {
|
|
||||||
return 0L;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Map<String, Long> defaultDismissConsumeGolds() {
|
|
||||||
Map<String, Long> result = new LinkedHashMap<>();
|
|
||||||
dismissConsumeGoldKeys().keySet().forEach(relationType -> result.put(relationType, 0L));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Map<String, EnumConfigKey> dismissConsumeGoldKeys() {
|
|
||||||
Map<String, EnumConfigKey> result = new LinkedHashMap<>();
|
|
||||||
result.put(RELATION_TYPE_CP, EnumConfigKey.CP_DISMISS_CONSUME_GOLD);
|
|
||||||
result.put(RELATION_TYPE_BROTHER, EnumConfigKey.BROTHER_DISMISS_CONSUME_GOLD);
|
|
||||||
result.put(RELATION_TYPE_SISTERS, EnumConfigKey.SISTERS_DISMISS_CONSUME_GOLD);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String dismissConsumeGoldTitle(EnumConfigKey key) {
|
|
||||||
return switch (key) {
|
|
||||||
case CP_DISMISS_CONSUME_GOLD -> "CP 解绑金币";
|
|
||||||
case BROTHER_DISMISS_CONSUME_GOLD -> "Brother 解绑金币";
|
|
||||||
case SISTERS_DISMISS_CONSUME_GOLD -> "Sisters 解绑金币";
|
|
||||||
default -> "关系解绑金币";
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<ResidentCpLevelConfigSaveCmd> sortedLevels(
|
|
||||||
List<ResidentCpLevelConfigSaveCmd> levels) {
|
|
||||||
if (Objects.isNull(levels)) {
|
|
||||||
return List.of();
|
|
||||||
}
|
|
||||||
return levels.stream()
|
|
||||||
.filter(Objects::nonNull)
|
|
||||||
.sorted(Comparator.comparing(ResidentCpLevelConfigSaveCmd::getLevel,
|
|
||||||
Comparator.nullsLast(Integer::compareTo)))
|
|
||||||
.toList();
|
|
||||||
}
|
|
||||||
|
|
||||||
private String normalizeSysOrigin(String sysOrigin) {
|
|
||||||
return Objects.toString(sysOrigin, "").trim().toUpperCase();
|
|
||||||
}
|
|
||||||
|
|
||||||
private Long defaultRequiredValue(Long requiredValue) {
|
|
||||||
return requiredValue == null ? 0L : requiredValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Long defaultGold(Long gold) {
|
|
||||||
return gold == null ? 0L : gold;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String normalizeRelationType(String relationType) {
|
|
||||||
if (StringUtils.isBlank(relationType)) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
String normalized = relationType.trim().toUpperCase();
|
|
||||||
if (Objects.equals(normalized, "BROTHERS")) {
|
|
||||||
return RELATION_TYPE_BROTHER;
|
|
||||||
}
|
|
||||||
if (Objects.equals(normalized, "SISTER")) {
|
|
||||||
return RELATION_TYPE_SISTERS;
|
|
||||||
}
|
|
||||||
return normalized;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String defaultLevelName(Integer level, String levelName) {
|
|
||||||
if (StringUtils.isNotBlank(levelName)) {
|
|
||||||
return levelName.trim();
|
|
||||||
}
|
|
||||||
return "CP " + level + "级";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,42 +0,0 @@
|
|||||||
package com.red.circle.console.app.service.app.datav;
|
|
||||||
|
|
||||||
import com.red.circle.console.infra.database.rds.dao.datav.CountryDashboardDAO;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.function.Supplier;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Coordinates dashboard backfill and CDC worker writes through a MySQL named lock.
|
|
||||||
*/
|
|
||||||
@Slf4j
|
|
||||||
@Service
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class CountryDashboardBackfillLockService {
|
|
||||||
|
|
||||||
private static final String LOCK_NAME = "country_dashboard_backfill_lock";
|
|
||||||
|
|
||||||
private final CountryDashboardDAO countryDashboardDAO;
|
|
||||||
|
|
||||||
@Value("${red-circle.country-dashboard.backfill-lock-timeout-seconds:10}")
|
|
||||||
private Integer lockTimeoutSeconds;
|
|
||||||
|
|
||||||
public <T> T call(Supplier<T> supplier) {
|
|
||||||
Integer acquired = countryDashboardDAO.getDashboardBackfillLock(
|
|
||||||
LOCK_NAME, Math.max(Objects.requireNonNullElse(lockTimeoutSeconds, 10), 0));
|
|
||||||
if (!Objects.equals(acquired, 1)) {
|
|
||||||
throw new IllegalStateException("country dashboard backfill lock is held by CDC worker");
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
return supplier.get();
|
|
||||||
} finally {
|
|
||||||
try {
|
|
||||||
countryDashboardDAO.releaseDashboardBackfillLock(LOCK_NAME);
|
|
||||||
} catch (Exception ex) {
|
|
||||||
log.warn("release country dashboard backfill lock failed", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -5,10 +5,7 @@ import com.red.circle.console.infra.database.rds.dao.datav.CountryDashboardDAO;
|
|||||||
import com.red.circle.console.infra.database.rds.dto.datav.CountryDashboardDailyMetricDTO;
|
import com.red.circle.console.infra.database.rds.dto.datav.CountryDashboardDailyMetricDTO;
|
||||||
import com.red.circle.console.infra.database.rds.dto.datav.CountryDashboardMetricDTO;
|
import com.red.circle.console.infra.database.rds.dto.datav.CountryDashboardMetricDTO;
|
||||||
import com.red.circle.console.infra.database.rds.dto.datav.CountryDashboardPeriodMetricDTO;
|
import com.red.circle.console.infra.database.rds.dto.datav.CountryDashboardPeriodMetricDTO;
|
||||||
import com.red.circle.console.infra.database.rds.dto.datav.CountryDashboardRetentionUserDTO;
|
|
||||||
import com.red.circle.console.infra.database.rds.dto.datav.CountryDashboardUserCountryDTO;
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.sql.Timestamp;
|
|
||||||
import java.time.DayOfWeek;
|
import java.time.DayOfWeek;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
@ -20,7 +17,6 @@ import java.time.temporal.ChronoUnit;
|
|||||||
import java.time.temporal.WeekFields;
|
import java.time.temporal.WeekFields;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -28,17 +24,9 @@ import java.util.Locale;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.function.BiConsumer;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.bson.Document;
|
|
||||||
import org.bson.types.Decimal128;
|
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.data.mongodb.core.MongoTemplate;
|
|
||||||
import org.springframework.data.mongodb.core.aggregation.Aggregation;
|
|
||||||
import org.springframework.data.mongodb.core.aggregation.AggregationOperation;
|
|
||||||
import org.springframework.data.mongodb.core.query.Criteria;
|
|
||||||
import org.springframework.data.mongodb.core.query.Query;
|
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.support.TransactionTemplate;
|
import org.springframework.transaction.support.TransactionTemplate;
|
||||||
|
|
||||||
@ -61,18 +49,14 @@ public class CountryDashboardDailyMetricService {
|
|||||||
private static final ZoneId STORAGE_ZONE_ID = ZoneId.of("Asia/Riyadh");
|
private static final ZoneId STORAGE_ZONE_ID = ZoneId.of("Asia/Riyadh");
|
||||||
private static final String STORAGE_TIMEZONE = "Asia/Riyadh";
|
private static final String STORAGE_TIMEZONE = "Asia/Riyadh";
|
||||||
private static final String STORAGE_TIMEZONE_OFFSET = "+03:00";
|
private static final String STORAGE_TIMEZONE_OFFSET = "+03:00";
|
||||||
private static final String COLLECTION_USER_DAILY_ACTIVE_LOG = "user_daily_active_log";
|
|
||||||
private static final String COLLECTION_GIFT_GIVE_RUNNING_WATER = "gift_give_running_water";
|
|
||||||
private static final int USER_BATCH_SIZE = 1000;
|
|
||||||
|
|
||||||
private final CountryDashboardDAO countryDashboardDAO;
|
private final CountryDashboardDAO countryDashboardDAO;
|
||||||
private final TransactionTemplate transactionTemplate;
|
private final TransactionTemplate transactionTemplate;
|
||||||
private final MongoTemplate mongoTemplate;
|
|
||||||
|
|
||||||
@Value("${red-circle.country-dashboard.refresh-sys-origins:LIKEI}")
|
@Value("${red-circle.country-dashboard.refresh-sys-origins:LIKEI}")
|
||||||
private String refreshSysOrigins;
|
private String refreshSysOrigins;
|
||||||
|
|
||||||
@Value("${red-circle.country-dashboard.refresh-timezones:Asia/Riyadh}")
|
@Value("${red-circle.country-dashboard.refresh-timezones:Asia/Riyadh,UTC,Asia/Shanghai}")
|
||||||
private String refreshTimezones;
|
private String refreshTimezones;
|
||||||
|
|
||||||
private volatile boolean metricSchemaEnsured;
|
private volatile boolean metricSchemaEnsured;
|
||||||
@ -114,39 +98,6 @@ public class CountryDashboardDailyMetricService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void refreshActiveRetentionRecentDays(int days) {
|
|
||||||
ensureMetricSchema();
|
|
||||||
int safeDays = Math.max(days, 1);
|
|
||||||
List<String> sysOrigins = resolveSysOrigins();
|
|
||||||
List<StatTimezone> statTimezones = resolveStatTimezones(null);
|
|
||||||
for (String sysOrigin : sysOrigins) {
|
|
||||||
for (StatTimezone statTimezone : statTimezones) {
|
|
||||||
List<LocalDate> statDates = recentDates(safeDays, statTimezone.zoneId());
|
|
||||||
for (LocalDate statDate : statDates) {
|
|
||||||
try {
|
|
||||||
refreshActiveRetentionPeriod(toDayWindow(statDate), sysOrigin, statTimezone);
|
|
||||||
} catch (Exception ex) {
|
|
||||||
log.error("refresh country dashboard active retention day failed, statDate={}, sysOrigin={}, statTimezone={}",
|
|
||||||
statDate, sysOrigin, statTimezone.id(), ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Set<PeriodWindow> windows = new LinkedHashSet<>();
|
|
||||||
for (LocalDate statDate : statDates) {
|
|
||||||
windows.add(toWeekWindow(statDate, statTimezone.zoneId()));
|
|
||||||
windows.add(toMonthWindow(statDate, statTimezone.zoneId()));
|
|
||||||
}
|
|
||||||
for (PeriodWindow window : windows) {
|
|
||||||
try {
|
|
||||||
refreshActiveRetentionPeriod(window, sysOrigin, statTimezone);
|
|
||||||
} catch (Exception ex) {
|
|
||||||
log.error("refresh country dashboard active retention period failed, periodType={}, periodKey={}, sysOrigin={}, statTimezone={}",
|
|
||||||
window.periodType(), window.periodKey(), sysOrigin, statTimezone.id(), ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void refreshRange(LocalDate startDate, LocalDate endDate, String sysOrigin) {
|
public void refreshRange(LocalDate startDate, LocalDate endDate, String sysOrigin) {
|
||||||
refreshRange(startDate, endDate, sysOrigin, null);
|
refreshRange(startDate, endDate, sysOrigin, null);
|
||||||
}
|
}
|
||||||
@ -208,8 +159,6 @@ public class CountryDashboardDailyMetricService {
|
|||||||
countryDashboardDAO.createPeriodMetricTable();
|
countryDashboardDAO.createPeriodMetricTable();
|
||||||
countryDashboardDAO.createPeriodUserMetricTable();
|
countryDashboardDAO.createPeriodUserMetricTable();
|
||||||
countryDashboardDAO.ensurePeriodMetricTimezoneSchema();
|
countryDashboardDAO.ensurePeriodMetricTimezoneSchema();
|
||||||
countryDashboardDAO.ensurePeriodMetricUserColumnsSchema();
|
|
||||||
countryDashboardDAO.ensureMetricValueColumnsSchema();
|
|
||||||
metricSchemaEnsured = true;
|
metricSchemaEnsured = true;
|
||||||
log.info("country dashboard metric tables ensured");
|
log.info("country dashboard metric tables ensured");
|
||||||
}
|
}
|
||||||
@ -266,14 +215,6 @@ public class CountryDashboardDailyMetricService {
|
|||||||
PERIOD_DAY, startTime, endTime, startTimeMillis, endTimeMillis, null, sysOrigin,
|
PERIOD_DAY, startTime, endTime, startTimeMillis, endTimeMillis, null, sysOrigin,
|
||||||
STORAGE_TIMEZONE_OFFSET, STORAGE_TIMEZONE_OFFSET),
|
STORAGE_TIMEZONE_OFFSET, STORAGE_TIMEZONE_OFFSET),
|
||||||
statDate, sysOrigin);
|
statDate, sysOrigin);
|
||||||
TimeWindow timeWindow = new TimeWindow(startTime, endTime, startTimeMillis, endTimeMillis,
|
|
||||||
statDate.atStartOfDay(STORAGE_ZONE_ID).toInstant(),
|
|
||||||
statDate.plusDays(1).atStartOfDay(STORAGE_ZONE_ID).toInstant());
|
|
||||||
mergeDailyMongo(rows, listGiftConsume(timeWindow, sysOrigin, STORAGE_TIMEZONE),
|
|
||||||
(row, amount) -> row.setGiftConsume(add(row.getGiftConsume(), amount)), statDate, sysOrigin);
|
|
||||||
mergeDailyMongo(rows, listLuckyGiftAnchorShare(timeWindow, sysOrigin, STORAGE_TIMEZONE),
|
|
||||||
(row, amount) -> row.setLuckyGiftAnchorShare(add(row.getLuckyGiftAnchorShare(), amount)),
|
|
||||||
statDate, sysOrigin);
|
|
||||||
|
|
||||||
List<CountryDashboardDailyMetricDTO> metrics = new ArrayList<>(rows.values());
|
List<CountryDashboardDailyMetricDTO> metrics = new ArrayList<>(rows.values());
|
||||||
RefreshWriteResult writeResult = transactionTemplate.execute(status -> {
|
RefreshWriteResult writeResult = transactionTemplate.execute(status -> {
|
||||||
@ -343,15 +284,6 @@ public class CountryDashboardDailyMetricService {
|
|||||||
mergePeriodAmounts(rows, countryDashboardDAO.listLuckyBoxGame(
|
mergePeriodAmounts(rows, countryDashboardDAO.listLuckyBoxGame(
|
||||||
window.periodType(), startTime, endTime, null, sysOrigin,
|
window.periodType(), startTime, endTime, null, sysOrigin,
|
||||||
STORAGE_TIMEZONE_OFFSET, statTimezone.offset()), window, sysOrigin, statTimezone);
|
STORAGE_TIMEZONE_OFFSET, statTimezone.offset()), window, sysOrigin, statTimezone);
|
||||||
mergePeriodMongo(rows, listGiftConsume(timeWindow, sysOrigin, statTimezone.id()),
|
|
||||||
(row, amount) -> row.setGiftConsume(add(row.getGiftConsume(), amount)),
|
|
||||||
window, sysOrigin, statTimezone);
|
|
||||||
mergePeriodMongo(rows, listLuckyGiftAnchorShare(timeWindow, sysOrigin, statTimezone.id()),
|
|
||||||
(row, amount) -> row.setLuckyGiftAnchorShare(add(row.getLuckyGiftAnchorShare(), amount)),
|
|
||||||
window, sysOrigin, statTimezone);
|
|
||||||
mergePeriodDailyActive(rows, listDailyActive(window, sysOrigin), window, sysOrigin,
|
|
||||||
statTimezone);
|
|
||||||
mergePeriodRetention(rows, window, sysOrigin, statTimezone, startTime, endTime);
|
|
||||||
|
|
||||||
RefreshWriteResult writeResult = transactionTemplate.execute(status -> {
|
RefreshWriteResult writeResult = transactionTemplate.execute(status -> {
|
||||||
countryDashboardDAO.deletePeriodUserMetrics(window.periodType(), window.periodKey(),
|
countryDashboardDAO.deletePeriodUserMetrics(window.periodType(), window.periodKey(),
|
||||||
@ -385,24 +317,6 @@ public class CountryDashboardDailyMetricService {
|
|||||||
System.currentTimeMillis() - start);
|
System.currentTimeMillis() - start);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void refreshActiveRetentionPeriod(PeriodWindow window, String sysOrigin,
|
|
||||||
StatTimezone statTimezone) {
|
|
||||||
long start = System.currentTimeMillis();
|
|
||||||
TimeWindow timeWindow = toStorageTimeWindow(window, statTimezone);
|
|
||||||
Map<String, CountryDashboardPeriodMetricDTO> rows = new LinkedHashMap<>();
|
|
||||||
mergePeriodDailyActive(rows, listDailyActive(window, sysOrigin), window, sysOrigin,
|
|
||||||
statTimezone);
|
|
||||||
mergePeriodRetention(rows, window, sysOrigin, statTimezone, timeWindow.startTime(),
|
|
||||||
timeWindow.endTime());
|
|
||||||
List<CountryDashboardPeriodMetricDTO> metrics = new ArrayList<>(rows.values());
|
|
||||||
int upserted = metrics.isEmpty() ? 0
|
|
||||||
: transactionTemplate.execute(status ->
|
|
||||||
countryDashboardDAO.upsertPeriodActiveRetentionMetrics(metrics));
|
|
||||||
log.info("refresh country dashboard active retention success, periodType={}, periodKey={}, sysOrigin={}, statTimezone={}, countries={}, upserted={}, costMs={}",
|
|
||||||
window.periodType(), window.periodKey(), sysOrigin, statTimezone.id(), metrics.size(),
|
|
||||||
upserted, System.currentTimeMillis() - start);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void refreshAll(String sysOrigin, StatTimezone statTimezone) {
|
private void refreshAll(String sysOrigin, StatTimezone statTimezone) {
|
||||||
long start = System.currentTimeMillis();
|
long start = System.currentTimeMillis();
|
||||||
PeriodWindow window = new PeriodWindow(PERIOD_ALL, PERIOD_ALL, "全部", null, null);
|
PeriodWindow window = new PeriodWindow(PERIOD_ALL, PERIOD_ALL, "全部", null, null);
|
||||||
@ -438,20 +352,15 @@ public class CountryDashboardDailyMetricService {
|
|||||||
for (CountryDashboardMetricDTO metric : metrics) {
|
for (CountryDashboardMetricDTO metric : metrics) {
|
||||||
CountryDashboardDailyMetricDTO row = getRow(rows, metric, statDate, sysOrigin);
|
CountryDashboardDailyMetricDTO row = getRow(rows, metric, statDate, sysOrigin);
|
||||||
row.setCountryNewUser(safeLong(row.getCountryNewUser()) + safeLong(metric.getCountryNewUser()));
|
row.setCountryNewUser(safeLong(row.getCountryNewUser()) + safeLong(metric.getCountryNewUser()));
|
||||||
row.setDailyRechargeUser(safeLong(row.getDailyRechargeUser()) + safeLong(metric.getDailyRechargeUser()));
|
|
||||||
row.setNewUserRecharge(add(row.getNewUserRecharge(), metric.getNewUserRecharge()));
|
row.setNewUserRecharge(add(row.getNewUserRecharge(), metric.getNewUserRecharge()));
|
||||||
row.setOfficialRecharge(add(row.getOfficialRecharge(), metric.getOfficialRecharge()));
|
row.setOfficialRecharge(add(row.getOfficialRecharge(), metric.getOfficialRecharge()));
|
||||||
row.setMifapayRecharge(add(row.getMifapayRecharge(), metric.getMifapayRecharge()));
|
row.setMifapayRecharge(add(row.getMifapayRecharge(), metric.getMifapayRecharge()));
|
||||||
row.setGoogleRecharge(add(row.getGoogleRecharge(), metric.getGoogleRecharge()));
|
row.setGoogleRecharge(add(row.getGoogleRecharge(), metric.getGoogleRecharge()));
|
||||||
row.setDealerRecharge(add(row.getDealerRecharge(), metric.getDealerRecharge()));
|
row.setDealerRecharge(add(row.getDealerRecharge(), metric.getDealerRecharge()));
|
||||||
row.setUserRecharge(add(row.getUserRecharge(), metric.getUserRecharge()));
|
|
||||||
row.setNewDealerUserRecharge(add(row.getNewDealerUserRecharge(), metric.getNewDealerUserRecharge()));
|
|
||||||
row.setSalaryExchange(add(row.getSalaryExchange(), metric.getSalaryExchange()));
|
row.setSalaryExchange(add(row.getSalaryExchange(), metric.getSalaryExchange()));
|
||||||
row.setGiftConsume(add(row.getGiftConsume(), metric.getGiftConsume()));
|
|
||||||
row.setLuckyGiftTotalFlow(add(row.getLuckyGiftTotalFlow(), metric.getLuckyGiftTotalFlow()));
|
row.setLuckyGiftTotalFlow(add(row.getLuckyGiftTotalFlow(), metric.getLuckyGiftTotalFlow()));
|
||||||
row.setLuckyGiftUser(safeLong(row.getLuckyGiftUser()) + safeLong(metric.getLuckyGiftUser()));
|
row.setLuckyGiftUser(safeLong(row.getLuckyGiftUser()) + safeLong(metric.getLuckyGiftUser()));
|
||||||
row.setLuckyGiftPayout(add(row.getLuckyGiftPayout(), metric.getLuckyGiftPayout()));
|
row.setLuckyGiftPayout(add(row.getLuckyGiftPayout(), metric.getLuckyGiftPayout()));
|
||||||
row.setLuckyGiftAnchorShare(add(row.getLuckyGiftAnchorShare(), metric.getLuckyGiftAnchorShare()));
|
|
||||||
row.setGameTotalFlow(add(row.getGameTotalFlow(), metric.getGameTotalFlow()));
|
row.setGameTotalFlow(add(row.getGameTotalFlow(), metric.getGameTotalFlow()));
|
||||||
row.setGameUser(safeLong(row.getGameUser()) + safeLong(metric.getGameUser()));
|
row.setGameUser(safeLong(row.getGameUser()) + safeLong(metric.getGameUser()));
|
||||||
row.setGamePayout(add(row.getGamePayout(), metric.getGamePayout()));
|
row.setGamePayout(add(row.getGamePayout(), metric.getGamePayout()));
|
||||||
@ -472,13 +381,9 @@ public class CountryDashboardDailyMetricService {
|
|||||||
row.setMifapayRecharge(add(row.getMifapayRecharge(), metric.getMifapayRecharge()));
|
row.setMifapayRecharge(add(row.getMifapayRecharge(), metric.getMifapayRecharge()));
|
||||||
row.setGoogleRecharge(add(row.getGoogleRecharge(), metric.getGoogleRecharge()));
|
row.setGoogleRecharge(add(row.getGoogleRecharge(), metric.getGoogleRecharge()));
|
||||||
row.setDealerRecharge(add(row.getDealerRecharge(), metric.getDealerRecharge()));
|
row.setDealerRecharge(add(row.getDealerRecharge(), metric.getDealerRecharge()));
|
||||||
row.setUserRecharge(add(row.getUserRecharge(), metric.getUserRecharge()));
|
|
||||||
row.setNewDealerUserRecharge(add(row.getNewDealerUserRecharge(), metric.getNewDealerUserRecharge()));
|
|
||||||
row.setSalaryExchange(add(row.getSalaryExchange(), metric.getSalaryExchange()));
|
row.setSalaryExchange(add(row.getSalaryExchange(), metric.getSalaryExchange()));
|
||||||
row.setGiftConsume(add(row.getGiftConsume(), metric.getGiftConsume()));
|
|
||||||
row.setLuckyGiftTotalFlow(add(row.getLuckyGiftTotalFlow(), metric.getLuckyGiftTotalFlow()));
|
row.setLuckyGiftTotalFlow(add(row.getLuckyGiftTotalFlow(), metric.getLuckyGiftTotalFlow()));
|
||||||
row.setLuckyGiftPayout(add(row.getLuckyGiftPayout(), metric.getLuckyGiftPayout()));
|
row.setLuckyGiftPayout(add(row.getLuckyGiftPayout(), metric.getLuckyGiftPayout()));
|
||||||
row.setLuckyGiftAnchorShare(add(row.getLuckyGiftAnchorShare(), metric.getLuckyGiftAnchorShare()));
|
|
||||||
row.setGameTotalFlow(add(row.getGameTotalFlow(), metric.getGameTotalFlow()));
|
row.setGameTotalFlow(add(row.getGameTotalFlow(), metric.getGameTotalFlow()));
|
||||||
row.setGamePayout(add(row.getGamePayout(), metric.getGamePayout()));
|
row.setGamePayout(add(row.getGamePayout(), metric.getGamePayout()));
|
||||||
}
|
}
|
||||||
@ -494,302 +399,11 @@ public class CountryDashboardDailyMetricService {
|
|||||||
CountryDashboardPeriodMetricDTO row = getPeriodRow(rows, metric, window, sysOrigin,
|
CountryDashboardPeriodMetricDTO row = getPeriodRow(rows, metric, window, sysOrigin,
|
||||||
statTimezone);
|
statTimezone);
|
||||||
row.setCountryNewUser(safeLong(metric.getCountryNewUser()));
|
row.setCountryNewUser(safeLong(metric.getCountryNewUser()));
|
||||||
row.setDailyRechargeUser(safeLong(metric.getDailyRechargeUser()));
|
|
||||||
row.setLuckyGiftUser(safeLong(metric.getLuckyGiftUser()));
|
row.setLuckyGiftUser(safeLong(metric.getLuckyGiftUser()));
|
||||||
row.setGameUser(safeLong(metric.getGameUser()));
|
row.setGameUser(safeLong(metric.getGameUser()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void mergePeriodDailyActive(Map<String, CountryDashboardPeriodMetricDTO> rows,
|
|
||||||
List<CountryDashboardMetricDTO> metrics, PeriodWindow window, String sysOrigin,
|
|
||||||
StatTimezone statTimezone) {
|
|
||||||
if (metrics == null || metrics.isEmpty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (CountryDashboardMetricDTO metric : metrics) {
|
|
||||||
CountryDashboardPeriodMetricDTO row = getPeriodRow(rows, metric, window, sysOrigin,
|
|
||||||
statTimezone);
|
|
||||||
row.setDailyActiveUser(safeLong(row.getDailyActiveUser()) + safeLong(metric.getDailyActiveUser()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void mergeDailyMongo(Map<String, CountryDashboardDailyMetricDTO> rows,
|
|
||||||
List<MongoMetric> metrics, BiConsumer<CountryDashboardDailyMetricDTO, BigDecimal> merger,
|
|
||||||
LocalDate statDate, String sysOrigin) {
|
|
||||||
if (metrics == null || metrics.isEmpty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Map<Long, CountryDashboardUserCountryDTO> countryMap = mapUserCountries(
|
|
||||||
metrics.stream().map(MongoMetric::userId).filter(Objects::nonNull).distinct().toList());
|
|
||||||
for (MongoMetric metric : metrics) {
|
|
||||||
CountryDashboardUserCountryDTO country = countryMap.get(metric.userId());
|
|
||||||
if (country == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
CountryDashboardMetricDTO rowKey = new CountryDashboardMetricDTO()
|
|
||||||
.setCountryCode(country.getCountryCode())
|
|
||||||
.setCountryName(country.getCountryName());
|
|
||||||
merger.accept(getRow(rows, rowKey, statDate, sysOrigin), metric.amount());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void mergePeriodMongo(Map<String, CountryDashboardPeriodMetricDTO> rows,
|
|
||||||
List<MongoMetric> metrics, BiConsumer<CountryDashboardPeriodMetricDTO, BigDecimal> merger,
|
|
||||||
PeriodWindow window, String sysOrigin, StatTimezone statTimezone) {
|
|
||||||
if (metrics == null || metrics.isEmpty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Map<Long, CountryDashboardUserCountryDTO> countryMap = mapUserCountries(
|
|
||||||
metrics.stream().map(MongoMetric::userId).filter(Objects::nonNull).distinct().toList());
|
|
||||||
for (MongoMetric metric : metrics) {
|
|
||||||
CountryDashboardUserCountryDTO country = countryMap.get(metric.userId());
|
|
||||||
if (country == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
CountryDashboardMetricDTO rowKey = new CountryDashboardMetricDTO()
|
|
||||||
.setCountryCode(country.getCountryCode())
|
|
||||||
.setCountryName(country.getCountryName());
|
|
||||||
merger.accept(getPeriodRow(rows, rowKey, window, sysOrigin, statTimezone), metric.amount());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void mergePeriodRetention(Map<String, CountryDashboardPeriodMetricDTO> rows,
|
|
||||||
PeriodWindow window, String sysOrigin, StatTimezone statTimezone, LocalDateTime startTime,
|
|
||||||
LocalDateTime endTime) {
|
|
||||||
mergePeriodRetentionDays(rows, window, sysOrigin, statTimezone, startTime.minusDays(1),
|
|
||||||
endTime.minusDays(1), 1);
|
|
||||||
mergePeriodRetentionDays(rows, window, sysOrigin, statTimezone, startTime.minusDays(7),
|
|
||||||
endTime.minusDays(7), 7);
|
|
||||||
mergePeriodRetentionDays(rows, window, sysOrigin, statTimezone, startTime.minusDays(30),
|
|
||||||
endTime.minusDays(30), 30);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void mergePeriodRetentionDays(Map<String, CountryDashboardPeriodMetricDTO> rows,
|
|
||||||
PeriodWindow window, String sysOrigin, StatTimezone statTimezone, LocalDateTime cohortStartTime,
|
|
||||||
LocalDateTime cohortEndTime, int retentionDays) {
|
|
||||||
List<CountryDashboardRetentionUserDTO> cohorts = countryDashboardDAO.listNewUserCohorts(
|
|
||||||
window.periodType(), cohortStartTime, cohortEndTime, null, sysOrigin,
|
|
||||||
STORAGE_TIMEZONE_OFFSET, statTimezone.offset());
|
|
||||||
if (cohorts == null || cohorts.isEmpty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
LocalDate today = LocalDate.now(statTimezone.zoneId());
|
|
||||||
Set<Long> userIds = new HashSet<>();
|
|
||||||
Set<String> activeDates = new HashSet<>();
|
|
||||||
for (CountryDashboardRetentionUserDTO cohort : cohorts) {
|
|
||||||
if (cohort.getUserId() == null || !hasText(cohort.getRegisterDate())) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
userIds.add(cohort.getUserId());
|
|
||||||
collectRetentionActiveDate(activeDates, cohort.getRegisterDate(), retentionDays, today);
|
|
||||||
}
|
|
||||||
|
|
||||||
Set<String> activeUserDates = listActiveUserDateSet(userIds, activeDates, sysOrigin);
|
|
||||||
for (CountryDashboardRetentionUserDTO cohort : cohorts) {
|
|
||||||
if (cohort.getUserId() == null || !hasText(cohort.getRegisterDate())) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
CountryDashboardMetricDTO metric = new CountryDashboardMetricDTO()
|
|
||||||
.setCountryCode(cohort.getCountryCode())
|
|
||||||
.setCountryName(cohort.getCountryName());
|
|
||||||
CountryDashboardPeriodMetricDTO row = getPeriodRow(rows, metric, window, sysOrigin,
|
|
||||||
statTimezone);
|
|
||||||
mergeRetentionDay(row, cohort.getUserId(), cohort.getRegisterDate(), retentionDays, today,
|
|
||||||
activeUserDates);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<CountryDashboardMetricDTO> listDailyActive(PeriodWindow window, String sysOrigin) {
|
|
||||||
if (window.periodStartDate() == null || window.periodEndDate() == null) {
|
|
||||||
return List.of();
|
|
||||||
}
|
|
||||||
List<Criteria> criteria = new ArrayList<>();
|
|
||||||
criteria.add(Criteria.where("activeDate")
|
|
||||||
.gte(window.periodStartDate().format(DATE_FORMATTER))
|
|
||||||
.lt(window.periodEndDate().format(DATE_FORMATTER)));
|
|
||||||
if (hasText(sysOrigin)) {
|
|
||||||
criteria.add(Criteria.where("sysOrigin").is(sysOrigin));
|
|
||||||
}
|
|
||||||
|
|
||||||
List<AggregationOperation> operations = new ArrayList<>();
|
|
||||||
operations.add(Aggregation.match(new Criteria().andOperator(criteria.toArray(new Criteria[0]))));
|
|
||||||
operations.add(Aggregation.group("registerCountryCode", "userId"));
|
|
||||||
operations.add(Aggregation.group("_id.registerCountryCode").count().as("dailyActiveUser"));
|
|
||||||
|
|
||||||
return mongoTemplate.aggregate(Aggregation.newAggregation(operations),
|
|
||||||
COLLECTION_USER_DAILY_ACTIVE_LOG, Document.class)
|
|
||||||
.getMappedResults()
|
|
||||||
.stream()
|
|
||||||
.map(this::toDailyActiveMetric)
|
|
||||||
.filter(Objects::nonNull)
|
|
||||||
.toList();
|
|
||||||
}
|
|
||||||
|
|
||||||
private CountryDashboardMetricDTO toDailyActiveMetric(Document document) {
|
|
||||||
String countryCode = normalizeCountryCode(document.get("_id"));
|
|
||||||
Long dailyActiveUser = toLong(document.get("dailyActiveUser"));
|
|
||||||
if (dailyActiveUser == null || dailyActiveUser <= 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return new CountryDashboardMetricDTO()
|
|
||||||
.setCountryCode(countryCode)
|
|
||||||
.setCountryName(countryCode)
|
|
||||||
.setDailyActiveUser(dailyActiveUser);
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<MongoMetric> listGiftConsume(TimeWindow timeWindow, String sysOrigin,
|
|
||||||
String statTimezone) {
|
|
||||||
List<Criteria> criteria = baseGiftCriteria(timeWindow, sysOrigin);
|
|
||||||
criteria.add(Criteria.where("luckyGift").ne(Boolean.TRUE));
|
|
||||||
criteria.add(Criteria.where("originId").regex("^\\d+$"));
|
|
||||||
criteria.add(new Criteria().orOperator(
|
|
||||||
Criteria.where("dynamicContentId").exists(false),
|
|
||||||
Criteria.where("dynamicContentId").is(null),
|
|
||||||
Criteria.where("dynamicContentId").is("")
|
|
||||||
));
|
|
||||||
return aggregateGiftAmount(criteria, "$giftValue.actualAmount", false, statTimezone);
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<MongoMetric> listLuckyGiftAnchorShare(TimeWindow timeWindow, String sysOrigin,
|
|
||||||
String statTimezone) {
|
|
||||||
List<Criteria> criteria = baseGiftCriteria(timeWindow, sysOrigin);
|
|
||||||
criteria.add(Criteria.where("luckyGift").is(Boolean.TRUE));
|
|
||||||
return aggregateGiftAmount(criteria, "$acceptUsers.targetAmount", true, statTimezone);
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<Criteria> baseGiftCriteria(TimeWindow timeWindow, String sysOrigin) {
|
|
||||||
List<Criteria> criteria = new ArrayList<>();
|
|
||||||
criteria.add(Criteria.where("refunded").ne(Boolean.TRUE));
|
|
||||||
criteria.add(Criteria.where("userId").ne(null));
|
|
||||||
criteria.add(Criteria.where("createTime").gte(Timestamp.from(timeWindow.startInstant())));
|
|
||||||
criteria.add(Criteria.where("createTime").lt(Timestamp.from(timeWindow.endInstant())));
|
|
||||||
if (hasText(sysOrigin)) {
|
|
||||||
criteria.add(Criteria.where("sysOrigin").is(sysOrigin));
|
|
||||||
}
|
|
||||||
return criteria;
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<MongoMetric> aggregateGiftAmount(List<Criteria> criteria, String amountPath,
|
|
||||||
boolean unwindAcceptUsers, String statTimezone) {
|
|
||||||
List<AggregationOperation> operations = new ArrayList<>();
|
|
||||||
operations.add(Aggregation.match(new Criteria().andOperator(criteria.toArray(new Criteria[0]))));
|
|
||||||
if (unwindAcceptUsers) {
|
|
||||||
operations.add(Aggregation.unwind("acceptUsers"));
|
|
||||||
}
|
|
||||||
operations.add(context -> new Document("$project",
|
|
||||||
new Document("userId", "$userId")
|
|
||||||
.append("amount", amountPath)
|
|
||||||
.append("day", new Document("$dateToString",
|
|
||||||
new Document("format", "%Y-%m-%d")
|
|
||||||
.append("date", "$createTime")
|
|
||||||
.append("timezone", statTimezone)))));
|
|
||||||
operations.add(Aggregation.group("userId", "day").sum("amount").as("amount"));
|
|
||||||
|
|
||||||
return mongoTemplate.aggregate(Aggregation.newAggregation(operations),
|
|
||||||
COLLECTION_GIFT_GIVE_RUNNING_WATER, Document.class)
|
|
||||||
.getMappedResults()
|
|
||||||
.stream()
|
|
||||||
.map(this::toMongoMetric)
|
|
||||||
.filter(Objects::nonNull)
|
|
||||||
.toList();
|
|
||||||
}
|
|
||||||
|
|
||||||
private MongoMetric toMongoMetric(Document document) {
|
|
||||||
Object id = document.get("_id");
|
|
||||||
if (!(id instanceof Document idDoc)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
Long userId = toLong(idDoc.get("userId"));
|
|
||||||
String day = Objects.toString(idDoc.get("day"), null);
|
|
||||||
BigDecimal amount = toBigDecimal(document.get("amount"));
|
|
||||||
if (userId == null || !hasText(day) || amount == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return new MongoMetric(userId, day, amount);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void collectRetentionActiveDate(Set<String> activeDates, String registerDate,
|
|
||||||
int retentionDays, LocalDate today) {
|
|
||||||
LocalDate targetDate = LocalDate.parse(registerDate, DATE_FORMATTER).plusDays(retentionDays);
|
|
||||||
if (!targetDate.isAfter(today)) {
|
|
||||||
activeDates.add(targetDate.format(DATE_FORMATTER));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void mergeRetentionDay(CountryDashboardPeriodMetricDTO row, Long userId,
|
|
||||||
String registerDate, int retentionDays, LocalDate today, Set<String> activeUserDates) {
|
|
||||||
LocalDate targetDate = LocalDate.parse(registerDate, DATE_FORMATTER).plusDays(retentionDays);
|
|
||||||
if (targetDate.isAfter(today)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
String activeKey = userId + "|" + targetDate.format(DATE_FORMATTER);
|
|
||||||
boolean retained = activeUserDates.contains(activeKey);
|
|
||||||
if (retentionDays == 1) {
|
|
||||||
row.setD1RetentionBaseUser(safeLong(row.getD1RetentionBaseUser()) + 1);
|
|
||||||
row.setD1RetentionUser(safeLong(row.getD1RetentionUser()) + (retained ? 1 : 0));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (retentionDays == 7) {
|
|
||||||
row.setD7RetentionBaseUser(safeLong(row.getD7RetentionBaseUser()) + 1);
|
|
||||||
row.setD7RetentionUser(safeLong(row.getD7RetentionUser()) + (retained ? 1 : 0));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
row.setD30RetentionBaseUser(safeLong(row.getD30RetentionBaseUser()) + 1);
|
|
||||||
row.setD30RetentionUser(safeLong(row.getD30RetentionUser()) + (retained ? 1 : 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
private Set<String> listActiveUserDateSet(Set<Long> userIds, Set<String> activeDates,
|
|
||||||
String sysOrigin) {
|
|
||||||
Set<String> result = new HashSet<>();
|
|
||||||
if (userIds == null || userIds.isEmpty() || activeDates == null || activeDates.isEmpty()) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
List<Long> ids = new ArrayList<>(userIds);
|
|
||||||
for (int start = 0; start < ids.size(); start += USER_BATCH_SIZE) {
|
|
||||||
int end = Math.min(start + USER_BATCH_SIZE, ids.size());
|
|
||||||
List<Criteria> criteria = new ArrayList<>();
|
|
||||||
criteria.add(Criteria.where("userId").in(ids.subList(start, end)));
|
|
||||||
criteria.add(Criteria.where("activeDate").in(activeDates));
|
|
||||||
if (hasText(sysOrigin)) {
|
|
||||||
criteria.add(Criteria.where("sysOrigin").is(sysOrigin));
|
|
||||||
}
|
|
||||||
Query query = Query.query(new Criteria().andOperator(criteria.toArray(new Criteria[0])));
|
|
||||||
query.fields().include("userId").include("activeDate");
|
|
||||||
List<Document> documents = mongoTemplate.find(query, Document.class,
|
|
||||||
COLLECTION_USER_DAILY_ACTIVE_LOG);
|
|
||||||
for (Document document : documents) {
|
|
||||||
Long userId = toLong(document.get("userId"));
|
|
||||||
String activeDate = Objects.toString(document.get("activeDate"), null);
|
|
||||||
if (userId != null && hasText(activeDate)) {
|
|
||||||
result.add(userId + "|" + activeDate);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Map<Long, CountryDashboardUserCountryDTO> mapUserCountries(List<Long> userIds) {
|
|
||||||
Map<Long, CountryDashboardUserCountryDTO> result = new LinkedHashMap<>();
|
|
||||||
if (userIds == null || userIds.isEmpty()) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
for (int start = 0; start < userIds.size(); start += USER_BATCH_SIZE) {
|
|
||||||
int end = Math.min(start + USER_BATCH_SIZE, userIds.size());
|
|
||||||
List<CountryDashboardUserCountryDTO> batch = countryDashboardDAO.listUserCountryByIds(
|
|
||||||
userIds.subList(start, end));
|
|
||||||
if (batch == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
for (CountryDashboardUserCountryDTO item : batch) {
|
|
||||||
if (item.getUserId() != null) {
|
|
||||||
result.put(item.getUserId(), item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private CountryDashboardDailyMetricDTO getRow(Map<String, CountryDashboardDailyMetricDTO> rows,
|
private CountryDashboardDailyMetricDTO getRow(Map<String, CountryDashboardDailyMetricDTO> rows,
|
||||||
CountryDashboardMetricDTO metric, LocalDate statDate, String sysOrigin) {
|
CountryDashboardMetricDTO metric, LocalDate statDate, String sysOrigin) {
|
||||||
String countryCode = hasText(metric.getCountryCode()) ? metric.getCountryCode() : "UNKNOWN";
|
String countryCode = hasText(metric.getCountryCode()) ? metric.getCountryCode() : "UNKNOWN";
|
||||||
@ -863,9 +477,7 @@ public class CountryDashboardDailyMetricService {
|
|||||||
LocalDateTime.ofInstant(startInstant, STORAGE_ZONE_ID),
|
LocalDateTime.ofInstant(startInstant, STORAGE_ZONE_ID),
|
||||||
LocalDateTime.ofInstant(endInstant, STORAGE_ZONE_ID),
|
LocalDateTime.ofInstant(endInstant, STORAGE_ZONE_ID),
|
||||||
startInstant.toEpochMilli(),
|
startInstant.toEpochMilli(),
|
||||||
endInstant.toEpochMilli(),
|
endInstant.toEpochMilli());
|
||||||
startInstant,
|
|
||||||
endInstant);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<StatTimezone> resolveStatTimezones(String statTimezonesValue) {
|
private List<StatTimezone> resolveStatTimezones(String statTimezonesValue) {
|
||||||
@ -874,7 +486,7 @@ public class CountryDashboardDailyMetricService {
|
|||||||
config = trimToNull(refreshTimezones);
|
config = trimToNull(refreshTimezones);
|
||||||
}
|
}
|
||||||
if (config == null) {
|
if (config == null) {
|
||||||
config = "Asia/Riyadh";
|
config = "Asia/Riyadh,UTC,Asia/Shanghai";
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, StatTimezone> zones = new LinkedHashMap<>();
|
Map<String, StatTimezone> zones = new LinkedHashMap<>();
|
||||||
@ -947,37 +559,6 @@ public class CountryDashboardDailyMetricService {
|
|||||||
return value == null ? 0L : value;
|
return value == null ? 0L : value;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Long toLong(Object value) {
|
|
||||||
if (value instanceof Number number) {
|
|
||||||
return number.longValue();
|
|
||||||
}
|
|
||||||
if (value == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return Long.valueOf(Objects.toString(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static BigDecimal toBigDecimal(Object value) {
|
|
||||||
if (value == null) {
|
|
||||||
return BigDecimal.ZERO;
|
|
||||||
}
|
|
||||||
if (value instanceof BigDecimal bigDecimal) {
|
|
||||||
return bigDecimal;
|
|
||||||
}
|
|
||||||
if (value instanceof Decimal128 decimal128) {
|
|
||||||
return decimal128.bigDecimalValue();
|
|
||||||
}
|
|
||||||
if (value instanceof Number number) {
|
|
||||||
return new BigDecimal(number.toString());
|
|
||||||
}
|
|
||||||
return new BigDecimal(Objects.toString(value, "0"));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String normalizeCountryCode(Object value) {
|
|
||||||
String countryCode = Objects.toString(value, "").trim();
|
|
||||||
return countryCode.isEmpty() ? "UNKNOWN" : countryCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean hasText(String value) {
|
private static boolean hasText(String value) {
|
||||||
return value != null && !value.trim().isEmpty();
|
return value != null && !value.trim().isEmpty();
|
||||||
}
|
}
|
||||||
@ -998,12 +579,9 @@ public class CountryDashboardDailyMetricService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private record TimeWindow(LocalDateTime startTime, LocalDateTime endTime,
|
private record TimeWindow(LocalDateTime startTime, LocalDateTime endTime,
|
||||||
Long startTimeMillis, Long endTimeMillis, Instant startInstant, Instant endInstant) {
|
Long startTimeMillis, Long endTimeMillis) {
|
||||||
}
|
}
|
||||||
|
|
||||||
private record RefreshWriteResult(int deleted, int inserted, int userRows) {
|
private record RefreshWriteResult(int deleted, int inserted, int userRows) {
|
||||||
}
|
}
|
||||||
|
|
||||||
private record MongoMetric(Long userId, String day, BigDecimal amount) {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -56,7 +56,7 @@ public class CountryDashboardGameMetricServiceImpl implements CountryDashboardGa
|
|||||||
@Value("${red-circle.country-dashboard.refresh-sys-origins:LIKEI}")
|
@Value("${red-circle.country-dashboard.refresh-sys-origins:LIKEI}")
|
||||||
private String refreshSysOrigins;
|
private String refreshSysOrigins;
|
||||||
|
|
||||||
@Value("${red-circle.country-dashboard.refresh-timezones:Asia/Riyadh}")
|
@Value("${red-circle.country-dashboard.refresh-timezones:Asia/Riyadh,UTC,Asia/Shanghai}")
|
||||||
private String refreshTimezones;
|
private String refreshTimezones;
|
||||||
|
|
||||||
private volatile boolean metricSchemaEnsured;
|
private volatile boolean metricSchemaEnsured;
|
||||||
@ -478,7 +478,7 @@ public class CountryDashboardGameMetricServiceImpl implements CountryDashboardGa
|
|||||||
config = trimToNull(refreshTimezones);
|
config = trimToNull(refreshTimezones);
|
||||||
}
|
}
|
||||||
if (config == null) {
|
if (config == null) {
|
||||||
config = "Asia/Riyadh";
|
config = "Asia/Riyadh,UTC,Asia/Shanghai";
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, StatTimezone> zones = new LinkedHashMap<>();
|
Map<String, StatTimezone> zones = new LinkedHashMap<>();
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
package com.red.circle.console.app.service.app.datav;
|
package com.red.circle.console.app.service.app.datav;
|
||||||
|
|
||||||
import com.red.circle.console.app.dto.clientobject.datav.CountryDashboardCO;
|
import com.red.circle.console.app.dto.clientobject.datav.CountryDashboardCO;
|
||||||
import com.red.circle.console.app.dto.clientobject.datav.CountryDashboardArpuSummaryCO;
|
|
||||||
import com.red.circle.console.app.dto.clientobject.datav.CountryDashboardMetricCO;
|
import com.red.circle.console.app.dto.clientobject.datav.CountryDashboardMetricCO;
|
||||||
import com.red.circle.console.app.dto.clientobject.datav.CountryDashboardRechargeDetailCO;
|
import com.red.circle.console.app.dto.clientobject.datav.CountryDashboardRechargeDetailCO;
|
||||||
import com.red.circle.console.app.dto.cmd.datav.CountryDashboardQryCmd;
|
import com.red.circle.console.app.dto.cmd.datav.CountryDashboardQryCmd;
|
||||||
@ -73,24 +72,33 @@ public class CountryDashboardServiceImpl implements CountryDashboardService {
|
|||||||
|
|
||||||
private final CountryDashboardDAO countryDashboardDAO;
|
private final CountryDashboardDAO countryDashboardDAO;
|
||||||
private final MongoTemplate mongoTemplate;
|
private final MongoTemplate mongoTemplate;
|
||||||
private volatile boolean rechargeDetailSchemaEnsured;
|
|
||||||
private volatile boolean periodMetricSchemaEnsured;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CountryDashboardCO query(CountryDashboardQryCmd cmd) {
|
public CountryDashboardCO query(CountryDashboardQryCmd cmd) {
|
||||||
ensurePeriodMetricSchema();
|
|
||||||
QueryCondition condition = QueryCondition.of(cmd);
|
QueryCondition condition = QueryCondition.of(cmd);
|
||||||
CountryDashboardCO dashboard = queryPrecomputed(condition);
|
|
||||||
dashboard.setArpuSummary(buildArpuSummary(condition));
|
|
||||||
return dashboard;
|
|
||||||
}
|
|
||||||
|
|
||||||
private CountryDashboardCO queryPrecomputed(QueryCondition condition) {
|
|
||||||
Map<String, CountryDashboardMetricCO> rows = new LinkedHashMap<>();
|
Map<String, CountryDashboardMetricCO> rows = new LinkedHashMap<>();
|
||||||
|
|
||||||
mergeSql(rows, countryDashboardDAO.listPrecomputedPeriodMetrics(
|
boolean usePrecomputedMetrics = shouldUsePrecomputedMetrics(condition);
|
||||||
condition.periodType, condition.startTime, condition.endTime,
|
if (usePrecomputedMetrics) {
|
||||||
condition.countryKeyword, condition.statTimezone, condition.sysOrigin));
|
mergeSql(rows, countryDashboardDAO.listPrecomputedPeriodMetrics(
|
||||||
|
condition.periodType, condition.startTime, condition.endTime,
|
||||||
|
condition.countryKeyword, condition.statTimezone, condition.sysOrigin));
|
||||||
|
} else {
|
||||||
|
mergeLiveSql(rows, condition);
|
||||||
|
mergeBankSalaryExchange(rows, condition);
|
||||||
|
}
|
||||||
|
if (usePrecomputedMetrics && condition.shouldOverlayLiveSalaryExchange()) {
|
||||||
|
overlayLiveSalaryExchange(rows, condition);
|
||||||
|
}
|
||||||
|
|
||||||
|
mergeMongo(rows, condition, listGiftConsume(condition),
|
||||||
|
(row, amount) -> row.setGiftConsume(add(row.getGiftConsume(), amount)));
|
||||||
|
mergeMongo(rows, condition, listLuckyGiftAnchorShare(condition),
|
||||||
|
(row, amount) -> row.setLuckyGiftAnchorShare(add(row.getLuckyGiftAnchorShare(), amount)));
|
||||||
|
mergeMongo(rows, condition, listBankSalaryTransfer(condition),
|
||||||
|
(row, amount) -> row.setSalaryTransfer(add(row.getSalaryTransfer(), amount)));
|
||||||
|
mergeDailyActive(rows, condition, listDailyActive(condition));
|
||||||
|
mergeRetention(rows, condition);
|
||||||
|
|
||||||
List<CountryDashboardMetricCO> records = rows.values().stream()
|
List<CountryDashboardMetricCO> records = rows.values().stream()
|
||||||
.peek(this::calculateFormulaFields)
|
.peek(this::calculateFormulaFields)
|
||||||
@ -112,13 +120,6 @@ public class CountryDashboardServiceImpl implements CountryDashboardService {
|
|||||||
.setRecords(records);
|
.setRecords(records);
|
||||||
}
|
}
|
||||||
|
|
||||||
private CountryDashboardArpuSummaryCO buildArpuSummary(QueryCondition condition) {
|
|
||||||
return new CountryDashboardArpuSummaryCO()
|
|
||||||
.setDay(queryPrecomputed(condition.recentDays(1)))
|
|
||||||
.setThreeDay(queryPrecomputed(condition.recentDays(3)))
|
|
||||||
.setWeek(queryPrecomputed(condition.recentDays(7)));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void mergeLiveSql(Map<String, CountryDashboardMetricCO> rows, QueryCondition condition) {
|
private void mergeLiveSql(Map<String, CountryDashboardMetricCO> rows, QueryCondition condition) {
|
||||||
mergeSql(rows, countryDashboardDAO.listNewUsers(
|
mergeSql(rows, countryDashboardDAO.listNewUsers(
|
||||||
condition.periodType, condition.startTime, condition.endTime,
|
condition.periodType, condition.startTime, condition.endTime,
|
||||||
@ -302,60 +303,32 @@ public class CountryDashboardServiceImpl implements CountryDashboardService {
|
|||||||
@Override
|
@Override
|
||||||
public PageResult<CountryDashboardRechargeDetailCO> pageRechargeDetails(
|
public PageResult<CountryDashboardRechargeDetailCO> pageRechargeDetails(
|
||||||
CountryDashboardRechargeDetailQryCmd cmd) {
|
CountryDashboardRechargeDetailQryCmd cmd) {
|
||||||
ensureRechargeDetailSchema();
|
QueryCondition condition = QueryCondition.of(cmd);
|
||||||
int cursor = Math.max(1, cmd == null || cmd.getCursor() == null ? 1 : cmd.getCursor());
|
int cursor = Math.max(1, cmd == null || cmd.getCursor() == null ? 1 : cmd.getCursor());
|
||||||
int limit = Math.max(1, cmd == null || cmd.getLimit() == null ? 100 : cmd.getLimit());
|
int limit = Math.max(1, cmd == null || cmd.getLimit() == null ? 100 : cmd.getLimit());
|
||||||
limit = Math.min(100, limit);
|
limit = Math.min(100, limit);
|
||||||
|
int offset = (cursor - 1) * limit;
|
||||||
|
String countryCodes = normalizeCountryCodes(cmd == null ? null : cmd.getCountryCodes());
|
||||||
|
|
||||||
QueryCondition condition = QueryCondition.of(cmd);
|
Long total = countryDashboardDAO.countRechargeDetails(
|
||||||
String countryCodes = QueryCondition.trimToNull(cmd == null ? null : cmd.getCountryCodes());
|
|
||||||
long total = safeLong(countryDashboardDAO.countRechargeDetails(
|
|
||||||
condition.startTime, condition.endTime, condition.countryKeyword, countryCodes,
|
condition.startTime, condition.endTime, condition.countryKeyword, countryCodes,
|
||||||
condition.sysOrigin, condition.storageTimezoneOffset, condition.statTimezoneOffset));
|
condition.sysOrigin, condition.storageTimezoneOffset, condition.statTimezoneOffset);
|
||||||
List<CountryDashboardRechargeDetailCO> records = total <= 0 ? List.of()
|
List<CountryDashboardRechargeDetailCO> records = countryDashboardDAO.listRechargeDetails(
|
||||||
: countryDashboardDAO.listRechargeDetails(
|
condition.startTime, condition.endTime, condition.countryKeyword, countryCodes,
|
||||||
condition.startTime, condition.endTime, condition.countryKeyword, countryCodes,
|
condition.sysOrigin, condition.storageTimezoneOffset, condition.statTimezoneOffset,
|
||||||
condition.sysOrigin, condition.storageTimezoneOffset, condition.statTimezoneOffset,
|
offset, limit)
|
||||||
(cursor - 1) * limit, limit)
|
.stream()
|
||||||
.stream()
|
.map(this::toRechargeDetailCO)
|
||||||
.map(this::toRechargeDetailCO)
|
.toList();
|
||||||
.toList();
|
|
||||||
PageResult<CountryDashboardRechargeDetailCO> result = new PageResult<>();
|
PageResult<CountryDashboardRechargeDetailCO> result = new PageResult<>();
|
||||||
result.setCurrent(cursor);
|
result.setCurrent(cursor);
|
||||||
result.setSize(limit);
|
result.setSize(limit);
|
||||||
result.setTotal(total);
|
result.setTotal(total == null ? 0L : total);
|
||||||
result.setRecords(records);
|
result.setRecords(records);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ensureRechargeDetailSchema() {
|
|
||||||
if (rechargeDetailSchemaEnsured) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
synchronized (this) {
|
|
||||||
if (rechargeDetailSchemaEnsured) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
countryDashboardDAO.createRechargeDetailTable();
|
|
||||||
rechargeDetailSchemaEnsured = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ensurePeriodMetricSchema() {
|
|
||||||
if (periodMetricSchemaEnsured) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
synchronized (this) {
|
|
||||||
if (periodMetricSchemaEnsured) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
countryDashboardDAO.createPeriodMetricTable();
|
|
||||||
countryDashboardDAO.ensurePeriodMetricUserColumnsSchema();
|
|
||||||
countryDashboardDAO.ensureMetricValueColumnsSchema();
|
|
||||||
periodMetricSchemaEnsured = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private CountryDashboardRechargeDetailCO toRechargeDetailCO(
|
private CountryDashboardRechargeDetailCO toRechargeDetailCO(
|
||||||
CountryDashboardRechargeDetailDTO dto) {
|
CountryDashboardRechargeDetailDTO dto) {
|
||||||
return new CountryDashboardRechargeDetailCO()
|
return new CountryDashboardRechargeDetailCO()
|
||||||
@ -382,31 +355,18 @@ public class CountryDashboardServiceImpl implements CountryDashboardService {
|
|||||||
CountryDashboardMetricCO row = getRow(rows, metric.getCountryCode(), metric.getCountryName(),
|
CountryDashboardMetricCO row = getRow(rows, metric.getCountryCode(), metric.getCountryName(),
|
||||||
metric.getPeriodKey(), metric.getPeriodName());
|
metric.getPeriodKey(), metric.getPeriodName());
|
||||||
row.setCountryNewUser(row.getCountryNewUser() + safeLong(metric.getCountryNewUser()));
|
row.setCountryNewUser(row.getCountryNewUser() + safeLong(metric.getCountryNewUser()));
|
||||||
row.setDailyActiveUser(row.getDailyActiveUser() + safeLong(metric.getDailyActiveUser()));
|
|
||||||
row.setDailyRechargeUser(row.getDailyRechargeUser() + safeLong(metric.getDailyRechargeUser()));
|
|
||||||
row.setNewUserRecharge(add(row.getNewUserRecharge(), metric.getNewUserRecharge()));
|
row.setNewUserRecharge(add(row.getNewUserRecharge(), metric.getNewUserRecharge()));
|
||||||
row.setOfficialRecharge(add(row.getOfficialRecharge(), metric.getOfficialRecharge()));
|
row.setOfficialRecharge(add(row.getOfficialRecharge(), metric.getOfficialRecharge()));
|
||||||
row.setMifapayRecharge(add(row.getMifapayRecharge(), metric.getMifapayRecharge()));
|
row.setMifapayRecharge(add(row.getMifapayRecharge(), metric.getMifapayRecharge()));
|
||||||
row.setGoogleRecharge(add(row.getGoogleRecharge(), metric.getGoogleRecharge()));
|
row.setGoogleRecharge(add(row.getGoogleRecharge(), metric.getGoogleRecharge()));
|
||||||
row.setDealerRecharge(add(row.getDealerRecharge(), metric.getDealerRecharge()));
|
row.setDealerRecharge(add(row.getDealerRecharge(), metric.getDealerRecharge()));
|
||||||
row.setUserRecharge(add(row.getUserRecharge(), metric.getUserRecharge()));
|
|
||||||
row.setNewDealerUserRecharge(add(row.getNewDealerUserRecharge(), metric.getNewDealerUserRecharge()));
|
|
||||||
row.setSalaryExchange(add(row.getSalaryExchange(), metric.getSalaryExchange()));
|
row.setSalaryExchange(add(row.getSalaryExchange(), metric.getSalaryExchange()));
|
||||||
row.setSalaryTransfer(add(row.getSalaryTransfer(), metric.getSalaryTransfer()));
|
|
||||||
row.setGiftConsume(add(row.getGiftConsume(), metric.getGiftConsume()));
|
|
||||||
row.setLuckyGiftTotalFlow(add(row.getLuckyGiftTotalFlow(), metric.getLuckyGiftTotalFlow()));
|
row.setLuckyGiftTotalFlow(add(row.getLuckyGiftTotalFlow(), metric.getLuckyGiftTotalFlow()));
|
||||||
row.setLuckyGiftUser(row.getLuckyGiftUser() + safeLong(metric.getLuckyGiftUser()));
|
row.setLuckyGiftUser(row.getLuckyGiftUser() + safeLong(metric.getLuckyGiftUser()));
|
||||||
row.setLuckyGiftPayout(add(row.getLuckyGiftPayout(), metric.getLuckyGiftPayout()));
|
row.setLuckyGiftPayout(add(row.getLuckyGiftPayout(), metric.getLuckyGiftPayout()));
|
||||||
row.setLuckyGiftAnchorShare(add(row.getLuckyGiftAnchorShare(), metric.getLuckyGiftAnchorShare()));
|
|
||||||
row.setGameTotalFlow(add(row.getGameTotalFlow(), metric.getGameTotalFlow()));
|
row.setGameTotalFlow(add(row.getGameTotalFlow(), metric.getGameTotalFlow()));
|
||||||
row.setGameUser(row.getGameUser() + safeLong(metric.getGameUser()));
|
row.setGameUser(row.getGameUser() + safeLong(metric.getGameUser()));
|
||||||
row.setGamePayout(add(row.getGamePayout(), metric.getGamePayout()));
|
row.setGamePayout(add(row.getGamePayout(), metric.getGamePayout()));
|
||||||
row.setD1RetentionUser(row.getD1RetentionUser() + safeLong(metric.getD1RetentionUser()));
|
|
||||||
row.setD1RetentionBaseUser(row.getD1RetentionBaseUser() + safeLong(metric.getD1RetentionBaseUser()));
|
|
||||||
row.setD7RetentionUser(row.getD7RetentionUser() + safeLong(metric.getD7RetentionUser()));
|
|
||||||
row.setD7RetentionBaseUser(row.getD7RetentionBaseUser() + safeLong(metric.getD7RetentionBaseUser()));
|
|
||||||
row.setD30RetentionUser(row.getD30RetentionUser() + safeLong(metric.getD30RetentionUser()));
|
|
||||||
row.setD30RetentionBaseUser(row.getD30RetentionBaseUser() + safeLong(metric.getD30RetentionBaseUser()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -787,14 +747,11 @@ public class CountryDashboardServiceImpl implements CountryDashboardService {
|
|||||||
for (CountryDashboardMetricCO row : records) {
|
for (CountryDashboardMetricCO row : records) {
|
||||||
total.setCountryNewUser(total.getCountryNewUser() + safeLong(row.getCountryNewUser()));
|
total.setCountryNewUser(total.getCountryNewUser() + safeLong(row.getCountryNewUser()));
|
||||||
total.setDailyActiveUser(total.getDailyActiveUser() + safeLong(row.getDailyActiveUser()));
|
total.setDailyActiveUser(total.getDailyActiveUser() + safeLong(row.getDailyActiveUser()));
|
||||||
total.setDailyRechargeUser(total.getDailyRechargeUser() + safeLong(row.getDailyRechargeUser()));
|
|
||||||
total.setNewUserRecharge(add(total.getNewUserRecharge(), row.getNewUserRecharge()));
|
total.setNewUserRecharge(add(total.getNewUserRecharge(), row.getNewUserRecharge()));
|
||||||
total.setOfficialRecharge(add(total.getOfficialRecharge(), row.getOfficialRecharge()));
|
total.setOfficialRecharge(add(total.getOfficialRecharge(), row.getOfficialRecharge()));
|
||||||
total.setMifapayRecharge(add(total.getMifapayRecharge(), row.getMifapayRecharge()));
|
total.setMifapayRecharge(add(total.getMifapayRecharge(), row.getMifapayRecharge()));
|
||||||
total.setGoogleRecharge(add(total.getGoogleRecharge(), row.getGoogleRecharge()));
|
total.setGoogleRecharge(add(total.getGoogleRecharge(), row.getGoogleRecharge()));
|
||||||
total.setDealerRecharge(add(total.getDealerRecharge(), row.getDealerRecharge()));
|
total.setDealerRecharge(add(total.getDealerRecharge(), row.getDealerRecharge()));
|
||||||
total.setUserRecharge(add(total.getUserRecharge(), row.getUserRecharge()));
|
|
||||||
total.setNewDealerUserRecharge(add(total.getNewDealerUserRecharge(), row.getNewDealerUserRecharge()));
|
|
||||||
total.setSalaryExchange(add(total.getSalaryExchange(), row.getSalaryExchange()));
|
total.setSalaryExchange(add(total.getSalaryExchange(), row.getSalaryExchange()));
|
||||||
total.setSalaryTransfer(add(total.getSalaryTransfer(), row.getSalaryTransfer()));
|
total.setSalaryTransfer(add(total.getSalaryTransfer(), row.getSalaryTransfer()));
|
||||||
total.setGiftConsume(add(total.getGiftConsume(), row.getGiftConsume()));
|
total.setGiftConsume(add(total.getGiftConsume(), row.getGiftConsume()));
|
||||||
@ -993,34 +950,6 @@ public class CountryDashboardServiceImpl implements CountryDashboardService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private QueryCondition recentDays(int dayCount) {
|
|
||||||
LocalDate end = LocalDate.now(statZoneId);
|
|
||||||
LocalDate start = end.minusDays(Math.max(1, dayCount) - 1L);
|
|
||||||
Instant recentStartInstant = start.atStartOfDay(statZoneId).toInstant();
|
|
||||||
Instant recentEndInstant = end.plusDays(1).atStartOfDay(statZoneId).toInstant();
|
|
||||||
LocalDateTime recentStorageStartTime =
|
|
||||||
LocalDateTime.ofInstant(recentStartInstant, STORAGE_ZONE_ID);
|
|
||||||
LocalDateTime recentStorageEndTime =
|
|
||||||
LocalDateTime.ofInstant(recentEndInstant, STORAGE_ZONE_ID);
|
|
||||||
return new QueryCondition(
|
|
||||||
"DAY",
|
|
||||||
DATE_FORMATTER.format(start),
|
|
||||||
DATE_FORMATTER.format(end),
|
|
||||||
statTimezone,
|
|
||||||
statZoneId,
|
|
||||||
storageTimezoneOffset,
|
|
||||||
statTimezoneOffset,
|
|
||||||
start,
|
|
||||||
end,
|
|
||||||
recentStorageStartTime,
|
|
||||||
recentStorageEndTime,
|
|
||||||
recentStartInstant,
|
|
||||||
recentEndInstant,
|
|
||||||
null,
|
|
||||||
sysOrigin
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private PeriodBucket toPeriodBucket(String day) {
|
private PeriodBucket toPeriodBucket(String day) {
|
||||||
if (PERIOD_ALL.equals(periodType)) {
|
if (PERIOD_ALL.equals(periodType)) {
|
||||||
return new PeriodBucket(PERIOD_ALL, "全部");
|
return new PeriodBucket(PERIOD_ALL, "全部");
|
||||||
|
|||||||
@ -1,25 +1,16 @@
|
|||||||
package com.red.circle.console.app.service.app.order;
|
package com.red.circle.console.app.service.app.order;
|
||||||
|
|
||||||
import com.alibaba.excel.EasyExcel;
|
|
||||||
import com.red.circle.console.app.dto.clienobject.order.InAppPurchaseDetailsCO;
|
import com.red.circle.console.app.dto.clienobject.order.InAppPurchaseDetailsCO;
|
||||||
import com.red.circle.console.app.excel.EasyExcelUtils;
|
|
||||||
import com.red.circle.console.app.excel.model.order.InAppPurchaseDetailsExportModel;
|
|
||||||
import com.red.circle.console.infra.database.rds.entity.admin.User;
|
import com.red.circle.console.infra.database.rds.entity.admin.User;
|
||||||
import com.red.circle.console.infra.database.rds.service.admin.UserService;
|
import com.red.circle.console.infra.database.rds.service.admin.UserService;
|
||||||
import com.red.circle.framework.core.asserts.ResponseAssert;
|
import com.red.circle.framework.core.asserts.ResponseAssert;
|
||||||
import com.red.circle.order.inner.asserts.OrderErrorCode;
|
import com.red.circle.order.inner.asserts.OrderErrorCode;
|
||||||
import com.red.circle.order.inner.endpoint.InAppPurchaseDetailsClient;
|
import com.red.circle.order.inner.endpoint.InAppPurchaseDetailsClient;
|
||||||
import com.red.circle.order.inner.model.cmd.inapp.InAppPurchaseDetailsQryCmd;
|
import com.red.circle.order.inner.model.cmd.inapp.InAppPurchaseDetailsQryCmd;
|
||||||
import com.red.circle.order.inner.model.dto.inapp.InAppPurchaseFactoryDTO;
|
|
||||||
import com.red.circle.order.inner.model.dto.inapp.InAppPurchaseDetailsDTO;
|
import com.red.circle.order.inner.model.dto.inapp.InAppPurchaseDetailsDTO;
|
||||||
import com.red.circle.tool.core.collection.CollectionUtils;
|
import com.red.circle.tool.core.collection.CollectionUtils;
|
||||||
import com.red.circle.tool.core.text.StringUtils;
|
|
||||||
import com.red.circle.other.inner.model.dto.user.UserProfileDTO;
|
import com.red.circle.other.inner.model.dto.user.UserProfileDTO;
|
||||||
import com.red.circle.other.inner.endpoint.user.user.UserProfileClient;
|
import com.red.circle.other.inner.endpoint.user.user.UserProfileClient;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.URLEncoder;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -142,85 +133,4 @@ public class InAppPurchaseBackServiceImpl implements InAppPurchaseBackService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void exportDetails(HttpServletResponse response, InAppPurchaseDetailsQryCmd query)
|
|
||||||
throws IOException {
|
|
||||||
query.setLastId(null);
|
|
||||||
query.setLimit(null);
|
|
||||||
query.setExportAll(Boolean.TRUE);
|
|
||||||
|
|
||||||
List<InAppPurchaseDetailsExportModel> exportRows = listDetails(query).stream()
|
|
||||||
.map(this::toExportModel)
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
|
|
||||||
response.setCharacterEncoding(StandardCharsets.UTF_8.name());
|
|
||||||
String fileName = URLEncoder.encode("InAppPurchaseOrders", StandardCharsets.UTF_8)
|
|
||||||
.replaceAll("\\+", "%20");
|
|
||||||
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
|
|
||||||
EasyExcel.write(response.getOutputStream(), InAppPurchaseDetailsExportModel.class)
|
|
||||||
.registerWriteHandler(EasyExcelUtils.getStyleStrategy())
|
|
||||||
.sheet("Orders")
|
|
||||||
.doWrite(exportRows);
|
|
||||||
}
|
|
||||||
|
|
||||||
private InAppPurchaseDetailsExportModel toExportModel(InAppPurchaseDetailsCO co) {
|
|
||||||
InAppPurchaseDetailsDTO details = co.getDetails();
|
|
||||||
InAppPurchaseFactoryDTO factory = Objects.isNull(details) ? null : details.getFactory();
|
|
||||||
UserProfileDTO buyer = pickBuyerProfile(co, details);
|
|
||||||
UserProfileDTO accept = co.getAcceptUserProfile();
|
|
||||||
|
|
||||||
return new InAppPurchaseDetailsExportModel()
|
|
||||||
.setEnv(text(Objects.isNull(details) ? null : details.getEnv()))
|
|
||||||
.setSysOrigin(text(Objects.isNull(details) ? null : details.getSysOrigin()))
|
|
||||||
.setPlatform(text(Objects.isNull(factory) ? null : factory.getPlatform()))
|
|
||||||
.setFactoryCode(text(Objects.isNull(factory) ? null : factory.getFactoryCode()))
|
|
||||||
.setChannel(text(Objects.isNull(factory) ? null : factory.getFactoryChannelCode()))
|
|
||||||
.setBuyerUserId(userId(buyer, Objects.isNull(details) ? null : details.getCreateUser()))
|
|
||||||
.setBuyerAccount(text(Objects.isNull(buyer) ? null : buyer.getAccount()))
|
|
||||||
.setBuyerNickname(buyerNickname(co, buyer))
|
|
||||||
.setAcceptUserId(userId(accept, Objects.isNull(details) ? null : details.getAcceptUserId()))
|
|
||||||
.setAcceptAccount(text(Objects.isNull(accept) ? null : accept.getAccount()))
|
|
||||||
.setAcceptNickname(text(Objects.isNull(accept) ? null : accept.getUserNickname()))
|
|
||||||
.setAmountUsd(Objects.isNull(details) ? null : details.getAmountUsd())
|
|
||||||
.setAmount(Objects.isNull(details) ? null : details.getAmount())
|
|
||||||
.setCurrency(text(Objects.isNull(details) ? null : details.getCurrency()))
|
|
||||||
.setProductDescriptor(text(Objects.isNull(details) ? null : details.getProductDescriptor()))
|
|
||||||
.setStatus(text(Objects.isNull(details) ? null : details.getStatus()))
|
|
||||||
.setReceiptType(text(Objects.isNull(details) ? null : details.getReceiptType()))
|
|
||||||
.setOrderId(text(Objects.isNull(details) ? null : details.getOrderId()))
|
|
||||||
.setAppOrderId(text(Objects.isNull(details) ? null : details.getId()))
|
|
||||||
.setTrackId(text(Objects.isNull(details) ? null : details.getTrackId()))
|
|
||||||
.setCountryCode(text(Objects.isNull(details) ? null : details.getCountryCode()))
|
|
||||||
.setCreateTime(text(Objects.isNull(details) ? null : details.getCreateTime()))
|
|
||||||
.setUpdateTime(text(Objects.isNull(details) ? null : details.getUpdateTime()));
|
|
||||||
}
|
|
||||||
|
|
||||||
private UserProfileDTO pickBuyerProfile(InAppPurchaseDetailsCO co, InAppPurchaseDetailsDTO details) {
|
|
||||||
if (Objects.nonNull(co.getCreateUserProfile())) {
|
|
||||||
return co.getCreateUserProfile();
|
|
||||||
}
|
|
||||||
if (Objects.nonNull(details) && Objects.equals(details.getCreateUser(), details.getAcceptUserId())) {
|
|
||||||
return co.getAcceptUserProfile();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String buyerNickname(InAppPurchaseDetailsCO co, UserProfileDTO buyer) {
|
|
||||||
if (StringUtils.isNotBlank(co.getCreateNickname())) {
|
|
||||||
return co.getCreateNickname();
|
|
||||||
}
|
|
||||||
return text(Objects.isNull(buyer) ? null : buyer.getUserNickname());
|
|
||||||
}
|
|
||||||
|
|
||||||
private String userId(UserProfileDTO profile, Long fallback) {
|
|
||||||
if (Objects.nonNull(profile) && Objects.nonNull(profile.getId())) {
|
|
||||||
return Objects.toString(profile.getId());
|
|
||||||
}
|
|
||||||
return text(fallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String text(Object value) {
|
|
||||||
return Objects.isNull(value) ? "" : Objects.toString(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -37,11 +37,6 @@ public class SysEnumConfigServiceImpl implements SysEnumConfigService {
|
|||||||
return ResponseAssert.requiredSuccess(enumConfigClient.getViolationAvatar(violationPicture));
|
return ResponseAssert.requiredSuccess(enumConfigClient.getViolationAvatar(violationPicture));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public EnumConfigDTO getByCode(String name, String sysOrigin) {
|
|
||||||
return ResponseAssert.requiredSuccess(enumConfigClient.getByCode(name, sysOrigin));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void saveSysEnumConfig(EnumConfigDTO sysEnumConfig) {
|
public void saveSysEnumConfig(EnumConfigDTO sysEnumConfig) {
|
||||||
ResponseAssert.requiredSuccess(enumConfigClient.saveSysEnumConfig(sysEnumConfig));
|
ResponseAssert.requiredSuccess(enumConfigClient.saveSysEnumConfig(sysEnumConfig));
|
||||||
|
|||||||
@ -4,9 +4,7 @@ import com.red.circle.framework.core.asserts.ResponseAssert;
|
|||||||
import com.red.circle.framework.dto.PageResult;
|
import com.red.circle.framework.dto.PageResult;
|
||||||
import com.red.circle.order.inner.endpoint.PayCountryClient;
|
import com.red.circle.order.inner.endpoint.PayCountryClient;
|
||||||
import com.red.circle.order.inner.model.cmd.SysPayCountryAddCmd;
|
import com.red.circle.order.inner.model.cmd.SysPayCountryAddCmd;
|
||||||
import com.red.circle.order.inner.model.cmd.SysPayCountryCurrencyRateSyncCmd;
|
|
||||||
import com.red.circle.order.inner.model.cmd.SysPayCountryQryCmd;
|
import com.red.circle.order.inner.model.cmd.SysPayCountryQryCmd;
|
||||||
import com.red.circle.order.inner.model.dto.PayCountryCurrencyRateSyncDTO;
|
|
||||||
import com.red.circle.order.inner.model.dto.PayCountryDTO;
|
import com.red.circle.order.inner.model.dto.PayCountryDTO;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -70,11 +68,6 @@ public class SysPayCountryServiceImpl implements SysPayCountryService {
|
|||||||
ResponseAssert.requiredSuccess(payCountryClient.shelf(id, shelf));
|
ResponseAssert.requiredSuccess(payCountryClient.shelf(id, shelf));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public PayCountryCurrencyRateSyncDTO syncCurrencyRates(SysPayCountryCurrencyRateSyncCmd cmd) {
|
|
||||||
return ResponseAssert.requiredSuccess(payCountryClient.syncCurrencyRates(cmd));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<Long, PayCountryDTO> mapCountryByIds(Set<Long> ids) {
|
public Map<Long, PayCountryDTO> mapCountryByIds(Set<Long> ids) {
|
||||||
return ResponseAssert.requiredSuccess(payCountryClient.mapCountryByIds(ids));
|
return ResponseAssert.requiredSuccess(payCountryClient.mapCountryByIds(ids));
|
||||||
|
|||||||
@ -2,19 +2,13 @@ package com.red.circle.console.app.service.app.team;
|
|||||||
|
|
||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
import com.red.circle.console.app.dto.clienobject.team.TeamManualSalaryCO;
|
|
||||||
import com.red.circle.console.app.dto.clienobject.team.TeamManualSalaryResultCO;
|
|
||||||
import com.red.circle.console.app.convertor.team.TeamAppConvertor;
|
import com.red.circle.console.app.convertor.team.TeamAppConvertor;
|
||||||
import com.red.circle.console.app.dto.clienobject.team.TeamSalaryCO;
|
import com.red.circle.console.app.dto.clienobject.team.TeamSalaryCO;
|
||||||
import com.red.circle.console.app.dto.clienobject.team.TeamSalaryDetailsCO;
|
import com.red.circle.console.app.dto.clienobject.team.TeamSalaryDetailsCO;
|
||||||
import com.red.circle.framework.core.asserts.ResponseAssert;
|
import com.red.circle.framework.core.asserts.ResponseAssert;
|
||||||
import com.red.circle.framework.dto.PageResult;
|
import com.red.circle.framework.dto.PageResult;
|
||||||
import com.red.circle.other.inner.endpoint.team.target.TeamProfileClient;
|
import com.red.circle.other.inner.endpoint.team.target.TeamProfileClient;
|
||||||
import com.red.circle.other.inner.model.cmd.team.TeamManualSalaryPaymentCmd;
|
|
||||||
import com.red.circle.other.inner.model.cmd.team.TeamManualSalaryPaymentQryCmd;
|
|
||||||
import com.red.circle.other.inner.model.cmd.team.TeamSalaryBackQryCmd;
|
import com.red.circle.other.inner.model.cmd.team.TeamSalaryBackQryCmd;
|
||||||
import com.red.circle.other.inner.model.dto.agency.agency.TeamManualSalaryPaymentDTO;
|
|
||||||
import com.red.circle.other.inner.model.dto.agency.agency.TeamManualSalaryPaymentResultDTO;
|
|
||||||
import com.red.circle.other.inner.model.dto.agency.agency.TeamSalaryPaymentDTO;
|
import com.red.circle.other.inner.model.dto.agency.agency.TeamSalaryPaymentDTO;
|
||||||
import com.red.circle.other.inner.model.dto.agency.agency.TeamSalaryPaymentDetailsDTO;
|
import com.red.circle.other.inner.model.dto.agency.agency.TeamSalaryPaymentDetailsDTO;
|
||||||
import com.red.circle.tool.core.collection.CollectionUtils;
|
import com.red.circle.tool.core.collection.CollectionUtils;
|
||||||
@ -22,9 +16,7 @@ import com.red.circle.tool.core.text.StringUtils;
|
|||||||
import com.red.circle.other.inner.model.dto.user.UserProfileDTO;
|
import com.red.circle.other.inner.model.dto.user.UserProfileDTO;
|
||||||
import com.red.circle.other.inner.endpoint.user.region.RegionConfigClient;
|
import com.red.circle.other.inner.endpoint.user.region.RegionConfigClient;
|
||||||
import com.red.circle.other.inner.endpoint.user.user.UserProfileClient;
|
import com.red.circle.other.inner.endpoint.user.user.UserProfileClient;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@ -121,39 +113,6 @@ public class TeamSalaryBackServiceImpl implements TeamSalaryBackService {
|
|||||||
return page;
|
return page;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public PageResult<TeamManualSalaryCO> manualSalaryPage(TeamManualSalaryPaymentQryCmd query) {
|
|
||||||
PageResult<TeamManualSalaryPaymentDTO> pageResult = ResponseAssert.requiredSuccess(
|
|
||||||
teamProfileClient.manualSalaryPage(query));
|
|
||||||
PageResult<TeamManualSalaryCO> page = pageResult.convert(this::toManualSalaryCO);
|
|
||||||
if (page.checkRecordsEmpty()) {
|
|
||||||
return page;
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<Long, UserProfileDTO> userProfileMap = getUserProfileMap(page.getRecords().stream()
|
|
||||||
.map(TeamManualSalaryCO::getUserId)
|
|
||||||
.collect(Collectors.toSet()));
|
|
||||||
page.getRecords().forEach(record -> record.setUserProfile(userProfileMap.get(record.getUserId())));
|
|
||||||
return page;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<TeamManualSalaryResultCO> manualSalaryPay(TeamManualSalaryPaymentCmd cmd) {
|
|
||||||
List<TeamManualSalaryPaymentResultDTO> results = ResponseAssert.requiredSuccess(
|
|
||||||
teamProfileClient.manualSalaryPay(cmd));
|
|
||||||
if (CollectionUtils.isEmpty(results)) {
|
|
||||||
return List.of();
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<Long, UserProfileDTO> userProfileMap = getUserProfileMap(results.stream()
|
|
||||||
.map(TeamManualSalaryPaymentResultDTO::getUserId)
|
|
||||||
.collect(Collectors.toSet()));
|
|
||||||
return results.stream()
|
|
||||||
.map(result -> toManualSalaryResultCO(result)
|
|
||||||
.setUserProfile(userProfileMap.get(result.getUserId())))
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
}
|
|
||||||
|
|
||||||
private Map<String, String> getMapRegionName(TeamSalaryBackQryCmd query) {
|
private Map<String, String> getMapRegionName(TeamSalaryBackQryCmd query) {
|
||||||
return ResponseAssert.requiredSuccess(
|
return ResponseAssert.requiredSuccess(
|
||||||
regionConfigClient.mapRegionNameBySysOrigin(query.getSysOrigin()));
|
regionConfigClient.mapRegionNameBySysOrigin(query.getSysOrigin()));
|
||||||
@ -188,67 +147,4 @@ public class TeamSalaryBackServiceImpl implements TeamSalaryBackService {
|
|||||||
return ResponseAssert.requiredSuccess(userProfileClient.mapByUserIds(userIds));
|
return ResponseAssert.requiredSuccess(userProfileClient.mapByUserIds(userIds));
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<Long, UserProfileDTO> getUserProfileMap(Collection<Long> userIds) {
|
|
||||||
if (CollectionUtils.isEmpty(userIds)) {
|
|
||||||
return Maps.newHashMap();
|
|
||||||
}
|
|
||||||
Set<Long> userIdSet = userIds.stream()
|
|
||||||
.filter(Objects::nonNull)
|
|
||||||
.collect(Collectors.toSet());
|
|
||||||
if (CollectionUtils.isEmpty(userIdSet)) {
|
|
||||||
return Maps.newHashMap();
|
|
||||||
}
|
|
||||||
return ResponseAssert.requiredSuccess(userProfileClient.mapByUserIds(userIdSet));
|
|
||||||
}
|
|
||||||
|
|
||||||
private TeamManualSalaryCO toManualSalaryCO(TeamManualSalaryPaymentDTO dto) {
|
|
||||||
return new TeamManualSalaryCO()
|
|
||||||
.setId(dto.getId())
|
|
||||||
.setSysOrigin(dto.getSysOrigin())
|
|
||||||
.setCountryCode(dto.getCountryCode())
|
|
||||||
.setRegion(dto.getRegion())
|
|
||||||
.setTeamId(dto.getTeamId())
|
|
||||||
.setTeamOwnId(dto.getTeamOwnId())
|
|
||||||
.setUserId(dto.getUserId())
|
|
||||||
.setBillBelong(dto.getBillBelong())
|
|
||||||
.setLastSettlementTarget(dto.getLastSettlementTarget())
|
|
||||||
.setCurrentTarget(dto.getCurrentTarget())
|
|
||||||
.setPolicyLevel(dto.getPolicyLevel())
|
|
||||||
.setSatisfyLevel(dto.getSatisfyLevel())
|
|
||||||
.setAgentMember(dto.getAgentMember())
|
|
||||||
.setExpectedSalary(dto.getExpectedSalary())
|
|
||||||
.setExpectedMemberSalary(dto.getExpectedMemberSalary())
|
|
||||||
.setExpectedAgentSalary(dto.getExpectedAgentSalary())
|
|
||||||
.setPayableSalary(dto.getPayableSalary())
|
|
||||||
.setPayableMemberSalary(dto.getPayableMemberSalary())
|
|
||||||
.setPayableAgentSalary(dto.getPayableAgentSalary())
|
|
||||||
.setTotalIssuedSalary(dto.getTotalIssuedSalary())
|
|
||||||
.setMemberIssuedSalary(dto.getMemberIssuedSalary())
|
|
||||||
.setAgentIssuedSalary(dto.getAgentIssuedSalary())
|
|
||||||
.setOverIssuedSalary(dto.getOverIssuedSalary())
|
|
||||||
.setMemberOverIssuedSalary(dto.getMemberOverIssuedSalary())
|
|
||||||
.setAgentOverIssuedSalary(dto.getAgentOverIssuedSalary())
|
|
||||||
.setCurrentSalaryBalance(dto.getCurrentSalaryBalance())
|
|
||||||
.setAgentMember(dto.getAgentMember())
|
|
||||||
.setPaid(dto.getPaid());
|
|
||||||
}
|
|
||||||
|
|
||||||
private TeamManualSalaryResultCO toManualSalaryResultCO(
|
|
||||||
TeamManualSalaryPaymentResultDTO dto) {
|
|
||||||
return new TeamManualSalaryResultCO()
|
|
||||||
.setId(dto.getId())
|
|
||||||
.setSysOrigin(dto.getSysOrigin())
|
|
||||||
.setCountryCode(dto.getCountryCode())
|
|
||||||
.setRegion(dto.getRegion())
|
|
||||||
.setTeamId(dto.getTeamId())
|
|
||||||
.setTeamOwnId(dto.getTeamOwnId())
|
|
||||||
.setUserId(dto.getUserId())
|
|
||||||
.setBillBelong(dto.getBillBelong())
|
|
||||||
.setBeforeSalaryBalance(dto.getBeforeSalaryBalance())
|
|
||||||
.setAfterSalaryBalance(dto.getAfterSalaryBalance())
|
|
||||||
.setIssuedSalary(dto.getIssuedSalary())
|
|
||||||
.setCurrentTarget(dto.getCurrentTarget())
|
|
||||||
.setPolicyLevel(dto.getPolicyLevel());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -92,11 +92,6 @@ public class TeamManagerServiceImpl implements TeamManagerService {
|
|||||||
.orElse(""))
|
.orElse(""))
|
||||||
.setRegionId(info.getRegionId())
|
.setRegionId(info.getRegionId())
|
||||||
.setRegionName(regionNameMap.get(info.getRegionId()))
|
.setRegionName(regionNameMap.get(info.getRegionId()))
|
||||||
.setCanAddBdLeader(defaultEnabled(info.getCanAddBdLeader()))
|
|
||||||
.setCanGiftProps(defaultEnabled(info.getCanGiftProps()))
|
|
||||||
.setCanBanUser(defaultEnabled(info.getCanBanUser()))
|
|
||||||
.setCanUnbanUser(defaultEnabled(info.getCanUnbanUser()))
|
|
||||||
.setCanChangeCountry(defaultEnabled(info.getCanChangeCountry()))
|
|
||||||
.setCreateTime(info.getCreateTime())
|
.setCreateTime(info.getCreateTime())
|
||||||
.setUpdateTime(info.getUpdateTime()));
|
.setUpdateTime(info.getUpdateTime()));
|
||||||
}
|
}
|
||||||
@ -117,11 +112,6 @@ public class TeamManagerServiceImpl implements TeamManagerService {
|
|||||||
.setSysOrigin(cmd.getSysOrigin())
|
.setSysOrigin(cmd.getSysOrigin())
|
||||||
.setContact(cmd.getContact())
|
.setContact(cmd.getContact())
|
||||||
.setRegionId(cmd.getRegionId())
|
.setRegionId(cmd.getRegionId())
|
||||||
.setCanAddBdLeader(defaultEnabled(cmd.getCanAddBdLeader()))
|
|
||||||
.setCanGiftProps(defaultEnabled(cmd.getCanGiftProps()))
|
|
||||||
.setCanBanUser(defaultEnabled(cmd.getCanBanUser()))
|
|
||||||
.setCanUnbanUser(defaultEnabled(cmd.getCanUnbanUser()))
|
|
||||||
.setCanChangeCountry(defaultEnabled(cmd.getCanChangeCountry()))
|
|
||||||
.setCreateUser(cmd.getCreateUser());
|
.setCreateUser(cmd.getCreateUser());
|
||||||
|
|
||||||
ResponseAssert.requiredSuccess(teamManagerClient.add(addCmd));
|
ResponseAssert.requiredSuccess(teamManagerClient.add(addCmd));
|
||||||
@ -134,11 +124,6 @@ public class TeamManagerServiceImpl implements TeamManagerService {
|
|||||||
.setId(cmd.getId())
|
.setId(cmd.getId())
|
||||||
.setContact(cmd.getContact())
|
.setContact(cmd.getContact())
|
||||||
.setRegionId(cmd.getRegionId())
|
.setRegionId(cmd.getRegionId())
|
||||||
.setCanAddBdLeader(cmd.getCanAddBdLeader())
|
|
||||||
.setCanGiftProps(cmd.getCanGiftProps())
|
|
||||||
.setCanBanUser(cmd.getCanBanUser())
|
|
||||||
.setCanUnbanUser(cmd.getCanUnbanUser())
|
|
||||||
.setCanChangeCountry(cmd.getCanChangeCountry())
|
|
||||||
.setUpdateUser(cmd.getUpdateUser())));
|
.setUpdateUser(cmd.getUpdateUser())));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -159,8 +144,4 @@ public class TeamManagerServiceImpl implements TeamManagerService {
|
|||||||
ResponseAssert.requiredSuccess(administratorClient.deleteSysAdministrator(administrator.getId()));
|
ResponseAssert.requiredSuccess(administratorClient.deleteSysAdministrator(administrator.getId()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private Boolean defaultEnabled(Boolean value) {
|
|
||||||
return !Boolean.FALSE.equals(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -456,11 +456,6 @@ public class UserFreightBalanceServiceImpl implements
|
|||||||
Map<Long, RegionConfigDTO> regionConfigMap = ResponseAssert.requiredSuccess(
|
Map<Long, RegionConfigDTO> regionConfigMap = ResponseAssert.requiredSuccess(
|
||||||
userRegionClient.mapUserRegionConfig(
|
userRegionClient.mapUserRegionConfig(
|
||||||
new UserRegionConfigMapCmd().setUserIds(userIds)));
|
new UserRegionConfigMapCmd().setUserIds(userIds)));
|
||||||
Map<Long, String> opsUserNicknameMap = userService.mapBackUserNickname(
|
|
||||||
waters.stream()
|
|
||||||
.map(UserFreightBalanceRunningWaterDTO::getCreateUser)
|
|
||||||
.filter(Objects::nonNull)
|
|
||||||
.collect(Collectors.toSet()));
|
|
||||||
|
|
||||||
return waters.stream().map(water -> {
|
return waters.stream().map(water -> {
|
||||||
|
|
||||||
@ -477,9 +472,6 @@ public class UserFreightBalanceServiceImpl implements
|
|||||||
.map(RegionConfigDTO::getRegionCode)
|
.map(RegionConfigDTO::getRegionCode)
|
||||||
.orElse("未知"));
|
.orElse("未知"));
|
||||||
exportModel.setOriginName(FreightBalanceOrigin.getDesc(water.getOrigin()));
|
exportModel.setOriginName(FreightBalanceOrigin.getDesc(water.getOrigin()));
|
||||||
exportModel.setOperationUserNickname(Optional.ofNullable(water.getCreateUser())
|
|
||||||
.map(opsUserNicknameMap::get)
|
|
||||||
.orElse(""));
|
|
||||||
exportModel.setAccount(getAccountDescribe(sendUser));
|
exportModel.setAccount(getAccountDescribe(sendUser));
|
||||||
exportModel.setNickname(Optional.ofNullable(sendUser)
|
exportModel.setNickname(Optional.ofNullable(sendUser)
|
||||||
.map(UserProfileDTO::getUserNickname).orElse("?"));
|
.map(UserProfileDTO::getUserNickname).orElse("?"));
|
||||||
|
|||||||
@ -1,8 +1,5 @@
|
|||||||
package com.red.circle.console.app.service.app.user;
|
package com.red.circle.console.app.service.app.user;
|
||||||
|
|
||||||
import com.alibaba.excel.EasyExcel;
|
|
||||||
import com.alibaba.excel.ExcelWriter;
|
|
||||||
import com.alibaba.excel.write.metadata.WriteSheet;
|
|
||||||
import com.alibaba.nacos.shaded.com.google.common.collect.Lists;
|
import com.alibaba.nacos.shaded.com.google.common.collect.Lists;
|
||||||
import com.red.circle.common.business.core.enums.ReceiptType;
|
import com.red.circle.common.business.core.enums.ReceiptType;
|
||||||
import com.red.circle.common.business.core.enums.SysOriginPlatformEnum;
|
import com.red.circle.common.business.core.enums.SysOriginPlatformEnum;
|
||||||
@ -11,8 +8,6 @@ import com.red.circle.console.app.convertor.WalletAppConvertor;
|
|||||||
import com.red.circle.console.app.dto.clienobject.user.UserGoldBalanceCO;
|
import com.red.circle.console.app.dto.clienobject.user.UserGoldBalanceCO;
|
||||||
import com.red.circle.console.app.dto.clienobject.user.UserGoldRunningWaterCO;
|
import com.red.circle.console.app.dto.clienobject.user.UserGoldRunningWaterCO;
|
||||||
import com.red.circle.console.app.dto.clienobject.user.UserGoldRunningWaterClsTmpCO;
|
import com.red.circle.console.app.dto.clienobject.user.UserGoldRunningWaterClsTmpCO;
|
||||||
import com.red.circle.console.app.excel.EasyExcelUtils;
|
|
||||||
import com.red.circle.console.app.excel.model.wallet.UserGoldRunningWaterExportModel;
|
|
||||||
import com.red.circle.console.infra.database.rds.service.admin.UserService;
|
import com.red.circle.console.infra.database.rds.service.admin.UserService;
|
||||||
import com.red.circle.console.inner.error.ConsoleErrorCode;
|
import com.red.circle.console.inner.error.ConsoleErrorCode;
|
||||||
import com.red.circle.framework.core.asserts.ResponseAssert;
|
import com.red.circle.framework.core.asserts.ResponseAssert;
|
||||||
@ -42,17 +37,9 @@ import com.red.circle.wallet.inner.model.cmd.GoldReceiptCmd;
|
|||||||
import com.red.circle.wallet.inner.model.cmd.SendGoldCmd;
|
import com.red.circle.wallet.inner.model.cmd.SendGoldCmd;
|
||||||
import com.red.circle.wallet.inner.model.cmd.UserGoldRunningWaterBackQryCmd;
|
import com.red.circle.wallet.inner.model.cmd.UserGoldRunningWaterBackQryCmd;
|
||||||
import com.red.circle.wallet.inner.model.dto.UserGoldRunningWaterClsHistoryDTO;
|
import com.red.circle.wallet.inner.model.dto.UserGoldRunningWaterClsHistoryDTO;
|
||||||
import com.red.circle.wallet.inner.model.dto.UserGoldRunningWaterDTO;
|
|
||||||
import com.red.circle.wallet.inner.model.dto.UserGoldRunningWaterHistoryDTO;
|
import com.red.circle.wallet.inner.model.dto.UserGoldRunningWaterHistoryDTO;
|
||||||
import com.red.circle.wallet.inner.model.enums.GoldOrigin;
|
import com.red.circle.wallet.inner.model.enums.GoldOrigin;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.net.URLEncoder;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.time.Instant;
|
|
||||||
import java.time.ZoneId;
|
|
||||||
import java.time.format.DateTimeFormatter;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
@ -70,10 +57,6 @@ import org.springframework.stereotype.Service;
|
|||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class UserWalletServiceImpl implements UserWalletService {
|
public class UserWalletServiceImpl implements UserWalletService {
|
||||||
|
|
||||||
private static final int EXPORT_BATCH_SIZE = 1000;
|
|
||||||
private static final DateTimeFormatter EXPORT_TIME_FORMATTER =
|
|
||||||
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
|
||||||
|
|
||||||
private final UserService userService;
|
private final UserService userService;
|
||||||
private final UserSvipClient userSvipClient;
|
private final UserSvipClient userSvipClient;
|
||||||
private final WalletGoldClient walletGoldClient;
|
private final WalletGoldClient walletGoldClient;
|
||||||
@ -195,133 +178,6 @@ public class UserWalletServiceImpl implements UserWalletService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void exportGoldRunningWater(HttpServletResponse response, UserGoldRunningWaterBackQryCmd query)
|
|
||||||
throws IOException {
|
|
||||||
UserGoldRunningWaterBackQryCmd exportQuery = copyGoldRunningWaterQuery(query)
|
|
||||||
.setContext(null)
|
|
||||||
.setLastId(null)
|
|
||||||
.setLimit(EXPORT_BATCH_SIZE);
|
|
||||||
|
|
||||||
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
|
|
||||||
response.setCharacterEncoding(StandardCharsets.UTF_8.name());
|
|
||||||
String fileName = URLEncoder.encode("GmGoldRunningWater", StandardCharsets.UTF_8)
|
|
||||||
.replaceAll("\\+", "%20");
|
|
||||||
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
|
|
||||||
|
|
||||||
ExcelWriter excelWriter = null;
|
|
||||||
try {
|
|
||||||
excelWriter = EasyExcel.write(response.getOutputStream(), UserGoldRunningWaterExportModel.class)
|
|
||||||
.registerWriteHandler(EasyExcelUtils.getStyleStrategy())
|
|
||||||
.build();
|
|
||||||
WriteSheet sheet = EasyExcel.writerSheet("GmGoldRunningWater").build();
|
|
||||||
boolean wroteAnyData = false;
|
|
||||||
while (true) {
|
|
||||||
List<UserGoldRunningWaterCO> waters = listGoldRunningWater(exportQuery);
|
|
||||||
if (CollectionUtils.isEmpty(waters)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
excelWriter.write(toGoldRunningWaterExportModels(waters), sheet);
|
|
||||||
wroteAnyData = true;
|
|
||||||
Long nextLastId = getLastRunningWaterId(waters);
|
|
||||||
if (Objects.isNull(nextLastId) || Objects.equals(nextLastId, exportQuery.getLastId())) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
exportQuery.setLastId(nextLastId);
|
|
||||||
}
|
|
||||||
if (!wroteAnyData) {
|
|
||||||
excelWriter.write(Lists.newArrayList(), sheet);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
if (Objects.nonNull(excelWriter)) {
|
|
||||||
excelWriter.finish();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private UserGoldRunningWaterBackQryCmd copyGoldRunningWaterQuery(
|
|
||||||
UserGoldRunningWaterBackQryCmd source) {
|
|
||||||
if (Objects.isNull(source)) {
|
|
||||||
return new UserGoldRunningWaterBackQryCmd();
|
|
||||||
}
|
|
||||||
return new UserGoldRunningWaterBackQryCmd()
|
|
||||||
.setId(source.getId())
|
|
||||||
.setSysOrigin(source.getSysOrigin())
|
|
||||||
.setUserId(source.getUserId())
|
|
||||||
.setQueryBackOperationUser(source.getQueryBackOperationUser())
|
|
||||||
.setBackOperationUser(source.getBackOperationUser())
|
|
||||||
.setBackOperationUsers(source.getBackOperationUsers())
|
|
||||||
.setTrackId(source.getTrackId())
|
|
||||||
.setType(source.getType())
|
|
||||||
.setOrigin(source.getOrigin())
|
|
||||||
.setStartTime(source.getStartTime())
|
|
||||||
.setEndTime(source.getEndTime());
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<UserGoldRunningWaterExportModel> toGoldRunningWaterExportModels(
|
|
||||||
List<UserGoldRunningWaterCO> waters) {
|
|
||||||
return waters.stream()
|
|
||||||
.map(water -> {
|
|
||||||
UserGoldRunningWaterDTO runningWater = water.getRunningWater();
|
|
||||||
UserProfileDTO userProfile = water.getUserProfile();
|
|
||||||
return new UserGoldRunningWaterExportModel()
|
|
||||||
.setRecordId(Objects.toString(runningWater.getId(), ""))
|
|
||||||
.setSysOrigin(runningWater.getSysOrigin())
|
|
||||||
.setUserId(Objects.toString(runningWater.getUserId(), ""))
|
|
||||||
.setUserAccount(getAccountDescribe(userProfile))
|
|
||||||
.setUserNickname(Optional.ofNullable(userProfile)
|
|
||||||
.map(UserProfileDTO::getUserNickname).orElse(""))
|
|
||||||
.setType(getGoldRunningWaterTypeName(runningWater.getType()))
|
|
||||||
.setQuantity(runningWater.getQuantity())
|
|
||||||
.setBalance(runningWater.getBalance())
|
|
||||||
.setOriginName(runningWater.getOriginName())
|
|
||||||
.setRemark(runningWater.getRemark())
|
|
||||||
.setBackOperationName(StringUtils.isBlank(water.getBackOperationName())
|
|
||||||
? "-" : water.getBackOperationName())
|
|
||||||
.setCreateTime(formatExportTime(runningWater.getCreateTime()));
|
|
||||||
})
|
|
||||||
.toList();
|
|
||||||
}
|
|
||||||
|
|
||||||
private Long getLastRunningWaterId(List<UserGoldRunningWaterCO> waters) {
|
|
||||||
if (CollectionUtils.isEmpty(waters)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return Optional.ofNullable(waters.get(waters.size() - 1))
|
|
||||||
.map(UserGoldRunningWaterCO::getRunningWater)
|
|
||||||
.map(UserGoldRunningWaterDTO::getId)
|
|
||||||
.orElse(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getGoldRunningWaterTypeName(Integer type) {
|
|
||||||
if (Objects.equals(type, 0)) {
|
|
||||||
return "增加";
|
|
||||||
}
|
|
||||||
if (Objects.equals(type, 1)) {
|
|
||||||
return "减少";
|
|
||||||
}
|
|
||||||
return Objects.toString(type, "");
|
|
||||||
}
|
|
||||||
|
|
||||||
private String formatExportTime(Long time) {
|
|
||||||
if (Objects.isNull(time)) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
return EXPORT_TIME_FORMATTER.format(
|
|
||||||
Instant.ofEpochMilli(time).atZone(ZoneId.systemDefault()));
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getAccountDescribe(UserProfileDTO userProfile) {
|
|
||||||
if (Objects.isNull(userProfile)) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
if (Objects.nonNull(userProfile.getOwnSpecialId())) {
|
|
||||||
return userProfile.getOwnSpecialId().getAccount() + "(" + userProfile.getAccount() + ")";
|
|
||||||
}
|
|
||||||
return userProfile.getAccount();
|
|
||||||
}
|
|
||||||
|
|
||||||
private UserGoldRunningWaterClsTmpCO getGoldRunningWaterDbFallback(
|
private UserGoldRunningWaterClsTmpCO getGoldRunningWaterDbFallback(
|
||||||
UserGoldRunningWaterBackQryCmd query) {
|
UserGoldRunningWaterBackQryCmd query) {
|
||||||
if (StringUtils.isNotBlank(query.getContext()) && Objects.isNull(query.getLastId())) {
|
if (StringUtils.isNotBlank(query.getContext()) && Objects.isNull(query.getLastId())) {
|
||||||
|
|||||||
@ -30,7 +30,6 @@ import com.red.circle.tool.core.sequence.IdWorkerUtils;
|
|||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.sql.Timestamp;
|
import java.sql.Timestamp;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -97,10 +96,7 @@ public class GmVipGiftServiceImpl implements GmVipGiftService {
|
|||||||
expireAt, now);
|
expireAt, now);
|
||||||
vipOrderRecordService.save(order);
|
vipOrderRecordService.save(order);
|
||||||
|
|
||||||
Set<Long> previousResourceIds = vipResourceIds(currentState);
|
|
||||||
upsertUserVipState(currentState, userProfile, config, startAt, expireAt, now);
|
upsertUserVipState(currentState, userProfile, config, startAt, expireAt, now);
|
||||||
expireSupersededVipResources(userProfile.getOriginSys(), userProfile.getId(), config,
|
|
||||||
previousResourceIds, now);
|
|
||||||
giftVipResources(userProfile.getId(), config, now, cmd.getReqUserId());
|
giftVipResources(userProfile.getId(), config, now, cmd.getReqUserId());
|
||||||
|
|
||||||
GmVipGiftRecord record = buildGiftRecord(cmd, applicant, userProfile, fromLevel, config,
|
GmVipGiftRecord record = buildGiftRecord(cmd, applicant, userProfile, fromLevel, config,
|
||||||
@ -276,63 +272,6 @@ public class GmVipGiftServiceImpl implements GmVipGiftService {
|
|||||||
now, opUser);
|
now, opUser);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void expireSupersededVipResources(String sysOrigin, Long userId,
|
|
||||||
VipLevelConfig targetConfig, Set<Long> previousResourceIds, Timestamp now) {
|
|
||||||
Set<Long> targetResourceIds = vipResourceIds(targetConfig);
|
|
||||||
Set<Long> allVipResourceIds = new HashSet<>();
|
|
||||||
vipLevelConfigService.query()
|
|
||||||
.eq(VipLevelConfig::getSysOrigin, sysOrigin)
|
|
||||||
.list()
|
|
||||||
.forEach(config -> allVipResourceIds.addAll(vipResourceIds(config)));
|
|
||||||
allVipResourceIds.addAll(previousResourceIds);
|
|
||||||
allVipResourceIds.removeAll(targetResourceIds);
|
|
||||||
if (CollectionUtils.isEmpty(allVipResourceIds)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
userPropsBackpackService.update()
|
|
||||||
.set(UserPropsBackpack::getExpireTime, now)
|
|
||||||
.set(UserPropsBackpack::getUseProps, Boolean.FALSE)
|
|
||||||
.set(UserPropsBackpack::getAllowGive, Boolean.FALSE)
|
|
||||||
.set(UserPropsBackpack::getUpdateTime, now)
|
|
||||||
.eq(UserPropsBackpack::getUserId, userId)
|
|
||||||
.in(UserPropsBackpack::getPropsId, allVipResourceIds)
|
|
||||||
.gt(UserPropsBackpack::getExpireTime, now)
|
|
||||||
.execute();
|
|
||||||
}
|
|
||||||
|
|
||||||
private Set<Long> vipResourceIds(VipLevelConfig config) {
|
|
||||||
Set<Long> ids = new HashSet<>();
|
|
||||||
if (Objects.isNull(config)) {
|
|
||||||
return ids;
|
|
||||||
}
|
|
||||||
addPositive(ids, config.getBadgeResourceId());
|
|
||||||
addPositive(ids, config.getAvatarFrameResourceId());
|
|
||||||
addPositive(ids, config.getEntryEffectResourceId());
|
|
||||||
addPositive(ids, config.getChatBubbleResourceId());
|
|
||||||
addPositive(ids, config.getFloatPictureResourceId());
|
|
||||||
return ids;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Set<Long> vipResourceIds(UserVipState state) {
|
|
||||||
Set<Long> ids = new HashSet<>();
|
|
||||||
if (Objects.isNull(state)) {
|
|
||||||
return ids;
|
|
||||||
}
|
|
||||||
addPositive(ids, state.getBadgeResourceId());
|
|
||||||
addPositive(ids, state.getAvatarFrameResourceId());
|
|
||||||
addPositive(ids, state.getEntryEffectResourceId());
|
|
||||||
addPositive(ids, state.getChatBubbleResourceId());
|
|
||||||
addPositive(ids, state.getFloatPictureResourceId());
|
|
||||||
return ids;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addPositive(Set<Long> ids, Long id) {
|
|
||||||
if (Objects.nonNull(id) && id > 0) {
|
|
||||||
ids.add(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void giveProp(Long userId, Long propsId, String type, Integer days, Timestamp now,
|
private void giveProp(Long userId, Long propsId, String type, Integer days, Timestamp now,
|
||||||
Long opUser) {
|
Long opUser) {
|
||||||
if (Objects.isNull(propsId) || propsId <= 0 || Objects.isNull(days) || days <= 0) {
|
if (Objects.isNull(propsId) || propsId <= 0 || Objects.isNull(days) || days <= 0) {
|
||||||
|
|||||||
@ -1,86 +0,0 @@
|
|||||||
package com.red.circle.console.app.service.app.activity;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
|
||||||
import static org.mockito.Mockito.mock;
|
|
||||||
import static org.mockito.Mockito.times;
|
|
||||||
import static org.mockito.Mockito.verify;
|
|
||||||
import static org.mockito.Mockito.when;
|
|
||||||
|
|
||||||
import com.red.circle.console.app.dto.clienobject.app.activity.cp.ResidentCpConfigCO;
|
|
||||||
import com.red.circle.console.app.dto.clienobject.app.activity.cp.ResidentCpLevelConfigCO;
|
|
||||||
import com.red.circle.console.app.dto.cmd.app.activity.cp.ResidentCpConfigSaveCmd;
|
|
||||||
import com.red.circle.console.app.dto.cmd.app.activity.cp.ResidentCpLevelConfigSaveCmd;
|
|
||||||
import com.red.circle.console.app.service.app.sys.CpCabinConfigService;
|
|
||||||
import com.red.circle.framework.dto.PageResult;
|
|
||||||
import com.red.circle.other.inner.model.cmd.sys.SysCpCabinConfigQryCmd;
|
|
||||||
import com.red.circle.other.inner.model.dto.sys.SysCpCabinConfigDTO;
|
|
||||||
import java.util.List;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
class ResidentCpActivityServiceImplTest {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void getConfigShouldReturnCpLevelsFromZeroToFive() {
|
|
||||||
CpCabinConfigService cpCabinConfigService = mock(CpCabinConfigService.class);
|
|
||||||
ResidentCpActivityServiceImpl service = new ResidentCpActivityServiceImpl(
|
|
||||||
cpCabinConfigService);
|
|
||||||
PageResult<SysCpCabinConfigDTO> page = new PageResult<>();
|
|
||||||
page.setRecords(List.of(
|
|
||||||
config(100L, 1L, 100L),
|
|
||||||
config(101L, 2L, 200L),
|
|
||||||
config(102L, 3L, 300L),
|
|
||||||
config(103L, 4L, 400L),
|
|
||||||
config(104L, 5L, 500L)
|
|
||||||
));
|
|
||||||
when(cpCabinConfigService.getCpCabin(any(SysCpCabinConfigQryCmd.class))).thenReturn(page);
|
|
||||||
|
|
||||||
ResidentCpConfigCO result = service.getConfig("likei");
|
|
||||||
|
|
||||||
assertEquals("LIKEI", result.getSysOrigin());
|
|
||||||
assertEquals(List.of(0, 1, 2, 3, 4, 5),
|
|
||||||
result.getLevels().stream().map(ResidentCpLevelConfigCO::getLevel).toList());
|
|
||||||
assertEquals(100L, result.getLevels().get(0).getRequiredIntimacyValue());
|
|
||||||
assertEquals(100L, result.getLevels().get(0).getCabinConfigId());
|
|
||||||
assertEquals(0L, result.getLevels().get(5).getRequiredIntimacyValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void saveConfigShouldNotRequireExactLevelCount() {
|
|
||||||
CpCabinConfigService cpCabinConfigService = mock(CpCabinConfigService.class);
|
|
||||||
ResidentCpActivityServiceImpl service = new ResidentCpActivityServiceImpl(
|
|
||||||
cpCabinConfigService);
|
|
||||||
PageResult<SysCpCabinConfigDTO> page = new PageResult<>();
|
|
||||||
page.setRecords(List.of());
|
|
||||||
when(cpCabinConfigService.getCpCabin(any(SysCpCabinConfigQryCmd.class))).thenReturn(page);
|
|
||||||
|
|
||||||
ResidentCpConfigSaveCmd cmd = new ResidentCpConfigSaveCmd()
|
|
||||||
.setSysOrigin("likei")
|
|
||||||
.setLevels(List.of(
|
|
||||||
level(0, 0L),
|
|
||||||
level(1, 100L),
|
|
||||||
level(2, 200L),
|
|
||||||
level(3, 300L),
|
|
||||||
level(4, 400L)
|
|
||||||
));
|
|
||||||
|
|
||||||
assertDoesNotThrow(() -> service.saveConfig(cmd));
|
|
||||||
verify(cpCabinConfigService, times(5)).addCpCabin(any(SysCpCabinConfigDTO.class));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static SysCpCabinConfigDTO config(Long id, Long sort, Long unlockValue) {
|
|
||||||
return new SysCpCabinConfigDTO()
|
|
||||||
.setId(id)
|
|
||||||
.setName("CP " + sort + "级")
|
|
||||||
.setCabinUnlockValue(unlockValue)
|
|
||||||
.setSort(sort);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ResidentCpLevelConfigSaveCmd level(Integer level, Long requiredValue) {
|
|
||||||
return new ResidentCpLevelConfigSaveCmd()
|
|
||||||
.setLevel(level)
|
|
||||||
.setLevelName("CP " + level + "级")
|
|
||||||
.setRequiredIntimacyValue(requiredValue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,34 +0,0 @@
|
|||||||
package com.red.circle.console.app.dto.clienobject.app.activity.cp;
|
|
||||||
|
|
||||||
import com.red.circle.framework.dto.ClientObject;
|
|
||||||
import java.io.Serial;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.EqualsAndHashCode;
|
|
||||||
import lombok.experimental.Accessors;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 常驻 CP 配置.
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@Accessors(chain = true)
|
|
||||||
@EqualsAndHashCode(callSuper = true)
|
|
||||||
public class ResidentCpConfigCO extends ClientObject {
|
|
||||||
|
|
||||||
@Serial
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
private Boolean configured = Boolean.FALSE;
|
|
||||||
|
|
||||||
private String sysOrigin;
|
|
||||||
|
|
||||||
private List<ResidentCpLevelConfigCO> levels = new ArrayList<>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Relation dismiss gold config. Key: CP/BROTHER/SISTERS.
|
|
||||||
*/
|
|
||||||
private Map<String, Long> dismissConsumeGolds = new LinkedHashMap<>();
|
|
||||||
}
|
|
||||||
@ -1,31 +0,0 @@
|
|||||||
package com.red.circle.console.app.dto.clienobject.app.activity.cp;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
|
||||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
|
||||||
import com.red.circle.framework.dto.ClientObject;
|
|
||||||
import java.io.Serial;
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.EqualsAndHashCode;
|
|
||||||
import lombok.experimental.Accessors;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 常驻 CP 等级配置.
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@Accessors(chain = true)
|
|
||||||
@EqualsAndHashCode(callSuper = true)
|
|
||||||
public class ResidentCpLevelConfigCO extends ClientObject {
|
|
||||||
|
|
||||||
@Serial
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
private Integer level;
|
|
||||||
|
|
||||||
private String levelName;
|
|
||||||
|
|
||||||
@JsonSerialize(using = ToStringSerializer.class)
|
|
||||||
private Long requiredIntimacyValue;
|
|
||||||
|
|
||||||
@JsonSerialize(using = ToStringSerializer.class)
|
|
||||||
private Long cabinConfigId;
|
|
||||||
}
|
|
||||||
@ -91,11 +91,6 @@ public class SysGiftConfigCO implements Serializable {
|
|||||||
*/
|
*/
|
||||||
private String giftTab;
|
private String giftTab;
|
||||||
|
|
||||||
/**
|
|
||||||
* CP礼物关系类型:CP/BROTHER/SISTERS.
|
|
||||||
*/
|
|
||||||
private String cpRelationType;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 0.未删除 1.已删除.
|
* 0.未删除 1.已删除.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -1,57 +0,0 @@
|
|||||||
package com.red.circle.console.app.dto.clienobject.team;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
|
||||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
|
||||||
import com.red.circle.other.inner.model.dto.user.UserProfileDTO;
|
|
||||||
import java.io.Serial;
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.experimental.Accessors;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 后台手动发放主播工资预览.
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@Accessors(chain = true)
|
|
||||||
public class TeamManualSalaryCO implements Serializable {
|
|
||||||
|
|
||||||
@Serial
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
private String id;
|
|
||||||
private String sysOrigin;
|
|
||||||
private String countryCode;
|
|
||||||
private String region;
|
|
||||||
|
|
||||||
@JsonSerialize(using = ToStringSerializer.class)
|
|
||||||
private Long teamId;
|
|
||||||
|
|
||||||
@JsonSerialize(using = ToStringSerializer.class)
|
|
||||||
private Long teamOwnId;
|
|
||||||
|
|
||||||
@JsonSerialize(using = ToStringSerializer.class)
|
|
||||||
private Long userId;
|
|
||||||
|
|
||||||
private UserProfileDTO userProfile;
|
|
||||||
private Integer billBelong;
|
|
||||||
private Long lastSettlementTarget;
|
|
||||||
private Long currentTarget;
|
|
||||||
private Integer policyLevel;
|
|
||||||
private Boolean satisfyLevel;
|
|
||||||
private Boolean agentMember;
|
|
||||||
private BigDecimal expectedSalary;
|
|
||||||
private BigDecimal expectedMemberSalary;
|
|
||||||
private BigDecimal expectedAgentSalary;
|
|
||||||
private BigDecimal payableSalary;
|
|
||||||
private BigDecimal payableMemberSalary;
|
|
||||||
private BigDecimal payableAgentSalary;
|
|
||||||
private BigDecimal totalIssuedSalary;
|
|
||||||
private BigDecimal memberIssuedSalary;
|
|
||||||
private BigDecimal agentIssuedSalary;
|
|
||||||
private BigDecimal overIssuedSalary;
|
|
||||||
private BigDecimal memberOverIssuedSalary;
|
|
||||||
private BigDecimal agentOverIssuedSalary;
|
|
||||||
private BigDecimal currentSalaryBalance;
|
|
||||||
private Boolean paid;
|
|
||||||
}
|
|
||||||
@ -1,43 +0,0 @@
|
|||||||
package com.red.circle.console.app.dto.clienobject.team;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
|
||||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
|
||||||
import com.red.circle.other.inner.model.dto.user.UserProfileDTO;
|
|
||||||
import java.io.Serial;
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.experimental.Accessors;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 后台手动发放主播工资结果.
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@Accessors(chain = true)
|
|
||||||
public class TeamManualSalaryResultCO implements Serializable {
|
|
||||||
|
|
||||||
@Serial
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
private String id;
|
|
||||||
private String sysOrigin;
|
|
||||||
private String countryCode;
|
|
||||||
private String region;
|
|
||||||
|
|
||||||
@JsonSerialize(using = ToStringSerializer.class)
|
|
||||||
private Long teamId;
|
|
||||||
|
|
||||||
@JsonSerialize(using = ToStringSerializer.class)
|
|
||||||
private Long teamOwnId;
|
|
||||||
|
|
||||||
@JsonSerialize(using = ToStringSerializer.class)
|
|
||||||
private Long userId;
|
|
||||||
|
|
||||||
private UserProfileDTO userProfile;
|
|
||||||
private Integer billBelong;
|
|
||||||
private BigDecimal beforeSalaryBalance;
|
|
||||||
private BigDecimal afterSalaryBalance;
|
|
||||||
private BigDecimal issuedSalary;
|
|
||||||
private Long currentTarget;
|
|
||||||
private Integer policyLevel;
|
|
||||||
}
|
|
||||||
@ -38,16 +38,6 @@ public class TeamManagerCO extends ClientObject {
|
|||||||
|
|
||||||
private String regionName;
|
private String regionName;
|
||||||
|
|
||||||
private Boolean canAddBdLeader;
|
|
||||||
|
|
||||||
private Boolean canGiftProps;
|
|
||||||
|
|
||||||
private Boolean canBanUser;
|
|
||||||
|
|
||||||
private Boolean canUnbanUser;
|
|
||||||
|
|
||||||
private Boolean canChangeCountry;
|
|
||||||
|
|
||||||
private Timestamp createTime;
|
private Timestamp createTime;
|
||||||
|
|
||||||
private Timestamp updateTime;
|
private Timestamp updateTime;
|
||||||
|
|||||||
@ -1,23 +0,0 @@
|
|||||||
package com.red.circle.console.app.dto.clientobject.datav;
|
|
||||||
|
|
||||||
import java.io.Serial;
|
|
||||||
import java.io.Serializable;
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.experimental.Accessors;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 国家数据大屏 ARPU 汇总.
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@Accessors(chain = true)
|
|
||||||
public class CountryDashboardArpuSummaryCO implements Serializable {
|
|
||||||
|
|
||||||
@Serial
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
private CountryDashboardCO day;
|
|
||||||
|
|
||||||
private CountryDashboardCO threeDay;
|
|
||||||
|
|
||||||
private CountryDashboardCO week;
|
|
||||||
}
|
|
||||||
@ -29,6 +29,4 @@ public class CountryDashboardCO implements Serializable {
|
|||||||
private CountryDashboardMetricCO total;
|
private CountryDashboardMetricCO total;
|
||||||
|
|
||||||
private List<CountryDashboardMetricCO> records;
|
private List<CountryDashboardMetricCO> records;
|
||||||
|
|
||||||
private CountryDashboardArpuSummaryCO arpuSummary;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -28,16 +28,10 @@ public class CountryDashboardMetricCO implements Serializable {
|
|||||||
|
|
||||||
private Long dailyActiveUser = 0L;
|
private Long dailyActiveUser = 0L;
|
||||||
|
|
||||||
private Long dailyRechargeUser = 0L;
|
|
||||||
|
|
||||||
private BigDecimal newUserRecharge = BigDecimal.ZERO;
|
private BigDecimal newUserRecharge = BigDecimal.ZERO;
|
||||||
|
|
||||||
private BigDecimal dealerRecharge = BigDecimal.ZERO;
|
private BigDecimal dealerRecharge = BigDecimal.ZERO;
|
||||||
|
|
||||||
private BigDecimal userRecharge = BigDecimal.ZERO;
|
|
||||||
|
|
||||||
private BigDecimal newDealerUserRecharge = BigDecimal.ZERO;
|
|
||||||
|
|
||||||
private BigDecimal mifapayRecharge = BigDecimal.ZERO;
|
private BigDecimal mifapayRecharge = BigDecimal.ZERO;
|
||||||
|
|
||||||
private BigDecimal googleRecharge = BigDecimal.ZERO;
|
private BigDecimal googleRecharge = BigDecimal.ZERO;
|
||||||
|
|||||||
@ -1,34 +0,0 @@
|
|||||||
package com.red.circle.console.app.dto.cmd.app.activity.cp;
|
|
||||||
|
|
||||||
import jakarta.validation.Valid;
|
|
||||||
import jakarta.validation.constraints.NotBlank;
|
|
||||||
import jakarta.validation.constraints.NotEmpty;
|
|
||||||
import java.io.Serial;
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.experimental.Accessors;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 常驻 CP 配置保存命令.
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@Accessors(chain = true)
|
|
||||||
public class ResidentCpConfigSaveCmd implements Serializable {
|
|
||||||
|
|
||||||
@Serial
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
@NotBlank(message = "sysOrigin required.")
|
|
||||||
private String sysOrigin;
|
|
||||||
|
|
||||||
@Valid
|
|
||||||
@NotEmpty(message = "levels required.")
|
|
||||||
private List<ResidentCpLevelConfigSaveCmd> levels;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Relation dismiss gold config. Key: CP/BROTHER/SISTERS.
|
|
||||||
*/
|
|
||||||
private Map<String, Long> dismissConsumeGolds;
|
|
||||||
}
|
|
||||||
@ -1,32 +0,0 @@
|
|||||||
package com.red.circle.console.app.dto.cmd.app.activity.cp;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
|
||||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
|
||||||
import jakarta.validation.constraints.NotNull;
|
|
||||||
import java.io.Serial;
|
|
||||||
import java.io.Serializable;
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.experimental.Accessors;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 常驻 CP 等级配置保存命令.
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@Accessors(chain = true)
|
|
||||||
public class ResidentCpLevelConfigSaveCmd implements Serializable {
|
|
||||||
|
|
||||||
@Serial
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
@NotNull(message = "level required.")
|
|
||||||
private Integer level;
|
|
||||||
|
|
||||||
private String levelName;
|
|
||||||
|
|
||||||
@NotNull(message = "requiredIntimacyValue required.")
|
|
||||||
@JsonSerialize(using = ToStringSerializer.class)
|
|
||||||
private Long requiredIntimacyValue;
|
|
||||||
|
|
||||||
@JsonSerialize(using = ToStringSerializer.class)
|
|
||||||
private Long cabinConfigId;
|
|
||||||
}
|
|
||||||
@ -31,14 +31,4 @@ public class TeamManagerAddCmd extends Command {
|
|||||||
@NotBlank(message = "regionId required.")
|
@NotBlank(message = "regionId required.")
|
||||||
private String regionId;
|
private String regionId;
|
||||||
|
|
||||||
private Boolean canAddBdLeader;
|
|
||||||
|
|
||||||
private Boolean canGiftProps;
|
|
||||||
|
|
||||||
private Boolean canBanUser;
|
|
||||||
|
|
||||||
private Boolean canUnbanUser;
|
|
||||||
|
|
||||||
private Boolean canChangeCountry;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -29,14 +29,4 @@ public class TeamManagerUpdateCmd extends Command {
|
|||||||
@NotBlank(message = "regionId required.")
|
@NotBlank(message = "regionId required.")
|
||||||
private String regionId;
|
private String regionId;
|
||||||
|
|
||||||
private Boolean canAddBdLeader;
|
|
||||||
|
|
||||||
private Boolean canGiftProps;
|
|
||||||
|
|
||||||
private Boolean canBanUser;
|
|
||||||
|
|
||||||
private Boolean canUnbanUser;
|
|
||||||
|
|
||||||
private Boolean canChangeCountry;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,14 +0,0 @@
|
|||||||
package com.red.circle.console.app.service.app.activity;
|
|
||||||
|
|
||||||
import com.red.circle.console.app.dto.clienobject.app.activity.cp.ResidentCpConfigCO;
|
|
||||||
import com.red.circle.console.app.dto.cmd.app.activity.cp.ResidentCpConfigSaveCmd;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 常驻 CP 配置管理.
|
|
||||||
*/
|
|
||||||
public interface ResidentCpActivityService {
|
|
||||||
|
|
||||||
ResidentCpConfigCO getConfig(String sysOrigin);
|
|
||||||
|
|
||||||
void saveConfig(ResidentCpConfigSaveCmd cmd);
|
|
||||||
}
|
|
||||||
@ -2,8 +2,6 @@ package com.red.circle.console.app.service.app.order;
|
|||||||
|
|
||||||
import com.red.circle.console.app.dto.clienobject.order.InAppPurchaseDetailsCO;
|
import com.red.circle.console.app.dto.clienobject.order.InAppPurchaseDetailsCO;
|
||||||
import com.red.circle.order.inner.model.cmd.inapp.InAppPurchaseDetailsQryCmd;
|
import com.red.circle.order.inner.model.cmd.inapp.InAppPurchaseDetailsQryCmd;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@ -29,10 +27,4 @@ public interface InAppPurchaseBackService extends IOrderService {
|
|||||||
*/
|
*/
|
||||||
Map<String, Object> statistics(InAppPurchaseDetailsQryCmd query);
|
Map<String, Object> statistics(InAppPurchaseDetailsQryCmd query);
|
||||||
|
|
||||||
/**
|
|
||||||
* 按筛选条件导出订单详情,不使用分页条件.
|
|
||||||
*/
|
|
||||||
void exportDetails(HttpServletResponse response, InAppPurchaseDetailsQryCmd query)
|
|
||||||
throws IOException;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,8 +20,6 @@ public interface SysEnumConfigService {
|
|||||||
|
|
||||||
String getViolationAvatar(EnumConfigKey violationPicture);
|
String getViolationAvatar(EnumConfigKey violationPicture);
|
||||||
|
|
||||||
EnumConfigDTO getByCode(String name, String sysOrigin);
|
|
||||||
|
|
||||||
void saveSysEnumConfig(EnumConfigDTO sysEnumConfig);
|
void saveSysEnumConfig(EnumConfigDTO sysEnumConfig);
|
||||||
|
|
||||||
void updateSysEnumConfig(EnumConfigDTO sysEnumConfig);
|
void updateSysEnumConfig(EnumConfigDTO sysEnumConfig);
|
||||||
|
|||||||
@ -2,9 +2,7 @@ package com.red.circle.console.app.service.app.sys.pay;
|
|||||||
|
|
||||||
import com.red.circle.framework.dto.PageResult;
|
import com.red.circle.framework.dto.PageResult;
|
||||||
import com.red.circle.order.inner.model.cmd.SysPayCountryAddCmd;
|
import com.red.circle.order.inner.model.cmd.SysPayCountryAddCmd;
|
||||||
import com.red.circle.order.inner.model.cmd.SysPayCountryCurrencyRateSyncCmd;
|
|
||||||
import com.red.circle.order.inner.model.cmd.SysPayCountryQryCmd;
|
import com.red.circle.order.inner.model.cmd.SysPayCountryQryCmd;
|
||||||
import com.red.circle.order.inner.model.dto.PayCountryCurrencyRateSyncDTO;
|
|
||||||
import com.red.circle.order.inner.model.dto.PayCountryDTO;
|
import com.red.circle.order.inner.model.dto.PayCountryDTO;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -61,11 +59,6 @@ public interface SysPayCountryService {
|
|||||||
*/
|
*/
|
||||||
void shelf(Long id, Boolean shelf);
|
void shelf(Long id, Boolean shelf);
|
||||||
|
|
||||||
/**
|
|
||||||
* 同步支付国家默认货币和实时美元汇率.
|
|
||||||
*/
|
|
||||||
PayCountryCurrencyRateSyncDTO syncCurrencyRates(SysPayCountryCurrencyRateSyncCmd cmd);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据id集合获得.
|
* 根据id集合获得.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -2,13 +2,8 @@ package com.red.circle.console.app.service.app.team;
|
|||||||
|
|
||||||
|
|
||||||
import com.red.circle.console.app.dto.clienobject.team.TeamSalaryCO;
|
import com.red.circle.console.app.dto.clienobject.team.TeamSalaryCO;
|
||||||
import com.red.circle.console.app.dto.clienobject.team.TeamManualSalaryCO;
|
|
||||||
import com.red.circle.console.app.dto.clienobject.team.TeamManualSalaryResultCO;
|
|
||||||
import com.red.circle.framework.dto.PageResult;
|
import com.red.circle.framework.dto.PageResult;
|
||||||
import com.red.circle.other.inner.model.cmd.team.TeamManualSalaryPaymentCmd;
|
|
||||||
import com.red.circle.other.inner.model.cmd.team.TeamManualSalaryPaymentQryCmd;
|
|
||||||
import com.red.circle.other.inner.model.cmd.team.TeamSalaryBackQryCmd;
|
import com.red.circle.other.inner.model.cmd.team.TeamSalaryBackQryCmd;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 团队自动发送工资凭证.
|
* 团队自动发送工资凭证.
|
||||||
@ -22,14 +17,4 @@ public interface TeamSalaryBackService {
|
|||||||
*/
|
*/
|
||||||
PageResult<TeamSalaryCO> listByCondition(TeamSalaryBackQryCmd query);
|
PageResult<TeamSalaryCO> listByCondition(TeamSalaryBackQryCmd query);
|
||||||
|
|
||||||
/**
|
|
||||||
* 手动工资发放预览.
|
|
||||||
*/
|
|
||||||
PageResult<TeamManualSalaryCO> manualSalaryPage(TeamManualSalaryPaymentQryCmd query);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 确认手动发放工资.
|
|
||||||
*/
|
|
||||||
List<TeamManualSalaryResultCO> manualSalaryPay(TeamManualSalaryPaymentCmd cmd);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,8 +7,6 @@ import com.red.circle.wallet.inner.model.cmd.DeductGoldCmd;
|
|||||||
import com.red.circle.wallet.inner.model.cmd.DiamondCmd;
|
import com.red.circle.wallet.inner.model.cmd.DiamondCmd;
|
||||||
import com.red.circle.wallet.inner.model.cmd.SendGoldCmd;
|
import com.red.circle.wallet.inner.model.cmd.SendGoldCmd;
|
||||||
import com.red.circle.wallet.inner.model.cmd.UserGoldRunningWaterBackQryCmd;
|
import com.red.circle.wallet.inner.model.cmd.UserGoldRunningWaterBackQryCmd;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ -36,12 +34,6 @@ public interface UserWalletService {
|
|||||||
*/
|
*/
|
||||||
UserGoldRunningWaterClsTmpCO getGoldRunningWaterCls(UserGoldRunningWaterBackQryCmd query);
|
UserGoldRunningWaterClsTmpCO getGoldRunningWaterCls(UserGoldRunningWaterBackQryCmd query);
|
||||||
|
|
||||||
/**
|
|
||||||
* 导出用户金币流水.
|
|
||||||
*/
|
|
||||||
void exportGoldRunningWater(HttpServletResponse response, UserGoldRunningWaterBackQryCmd query)
|
|
||||||
throws IOException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 发送金币.
|
* 发送金币.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -30,20 +30,8 @@ public interface CountryDashboardDAO extends BaseDAO<IUserBaseInfo> {
|
|||||||
|
|
||||||
int createGamePeriodUserMetricTable();
|
int createGamePeriodUserMetricTable();
|
||||||
|
|
||||||
int createRechargeDetailTable();
|
|
||||||
|
|
||||||
int ensurePeriodMetricTimezoneSchema();
|
int ensurePeriodMetricTimezoneSchema();
|
||||||
|
|
||||||
int ensurePeriodMetricUserColumnsSchema();
|
|
||||||
|
|
||||||
int ensureMetricValueColumnsSchema();
|
|
||||||
|
|
||||||
Integer getDashboardBackfillLock(
|
|
||||||
@Param("lockName") String lockName,
|
|
||||||
@Param("timeoutSeconds") Integer timeoutSeconds);
|
|
||||||
|
|
||||||
Integer releaseDashboardBackfillLock(@Param("lockName") String lockName);
|
|
||||||
|
|
||||||
List<CountryDashboardMetricDTO> listNewUsers(
|
List<CountryDashboardMetricDTO> listNewUsers(
|
||||||
@Param("periodType") String periodType,
|
@Param("periodType") String periodType,
|
||||||
@Param("startTime") LocalDateTime startTime,
|
@Param("startTime") LocalDateTime startTime,
|
||||||
@ -191,9 +179,6 @@ public interface CountryDashboardDAO extends BaseDAO<IUserBaseInfo> {
|
|||||||
|
|
||||||
int upsertPeriodMetrics(@Param("metrics") List<CountryDashboardPeriodMetricDTO> metrics);
|
int upsertPeriodMetrics(@Param("metrics") List<CountryDashboardPeriodMetricDTO> metrics);
|
||||||
|
|
||||||
int upsertPeriodActiveRetentionMetrics(
|
|
||||||
@Param("metrics") List<CountryDashboardPeriodMetricDTO> metrics);
|
|
||||||
|
|
||||||
int deletePeriodUserMetrics(
|
int deletePeriodUserMetrics(
|
||||||
@Param("periodType") String periodType,
|
@Param("periodType") String periodType,
|
||||||
@Param("periodKey") String periodKey,
|
@Param("periodKey") String periodKey,
|
||||||
|
|||||||
@ -24,8 +24,6 @@ public class CountryDashboardDailyMetricDTO {
|
|||||||
|
|
||||||
private Long countryNewUser;
|
private Long countryNewUser;
|
||||||
|
|
||||||
private Long dailyRechargeUser;
|
|
||||||
|
|
||||||
private BigDecimal newUserRecharge;
|
private BigDecimal newUserRecharge;
|
||||||
|
|
||||||
private BigDecimal officialRecharge;
|
private BigDecimal officialRecharge;
|
||||||
@ -36,24 +34,14 @@ public class CountryDashboardDailyMetricDTO {
|
|||||||
|
|
||||||
private BigDecimal dealerRecharge;
|
private BigDecimal dealerRecharge;
|
||||||
|
|
||||||
private BigDecimal userRecharge;
|
|
||||||
|
|
||||||
private BigDecimal newDealerUserRecharge;
|
|
||||||
|
|
||||||
private BigDecimal salaryExchange;
|
private BigDecimal salaryExchange;
|
||||||
|
|
||||||
private BigDecimal salaryTransfer;
|
|
||||||
|
|
||||||
private BigDecimal giftConsume;
|
|
||||||
|
|
||||||
private BigDecimal luckyGiftTotalFlow;
|
private BigDecimal luckyGiftTotalFlow;
|
||||||
|
|
||||||
private Long luckyGiftUser;
|
private Long luckyGiftUser;
|
||||||
|
|
||||||
private BigDecimal luckyGiftPayout;
|
private BigDecimal luckyGiftPayout;
|
||||||
|
|
||||||
private BigDecimal luckyGiftAnchorShare;
|
|
||||||
|
|
||||||
private BigDecimal gameTotalFlow;
|
private BigDecimal gameTotalFlow;
|
||||||
|
|
||||||
private Long gameUser;
|
private Long gameUser;
|
||||||
|
|||||||
@ -21,10 +21,6 @@ public class CountryDashboardMetricDTO {
|
|||||||
|
|
||||||
private Long countryNewUser;
|
private Long countryNewUser;
|
||||||
|
|
||||||
private Long dailyActiveUser;
|
|
||||||
|
|
||||||
private Long dailyRechargeUser;
|
|
||||||
|
|
||||||
private BigDecimal newUserRecharge;
|
private BigDecimal newUserRecharge;
|
||||||
|
|
||||||
private BigDecimal officialRecharge;
|
private BigDecimal officialRecharge;
|
||||||
@ -35,39 +31,17 @@ public class CountryDashboardMetricDTO {
|
|||||||
|
|
||||||
private BigDecimal dealerRecharge;
|
private BigDecimal dealerRecharge;
|
||||||
|
|
||||||
private BigDecimal userRecharge;
|
|
||||||
|
|
||||||
private BigDecimal newDealerUserRecharge;
|
|
||||||
|
|
||||||
private BigDecimal salaryExchange;
|
private BigDecimal salaryExchange;
|
||||||
|
|
||||||
private BigDecimal salaryTransfer;
|
|
||||||
|
|
||||||
private BigDecimal giftConsume;
|
|
||||||
|
|
||||||
private BigDecimal luckyGiftTotalFlow;
|
private BigDecimal luckyGiftTotalFlow;
|
||||||
|
|
||||||
private Long luckyGiftUser;
|
private Long luckyGiftUser;
|
||||||
|
|
||||||
private BigDecimal luckyGiftPayout;
|
private BigDecimal luckyGiftPayout;
|
||||||
|
|
||||||
private BigDecimal luckyGiftAnchorShare;
|
|
||||||
|
|
||||||
private BigDecimal gameTotalFlow;
|
private BigDecimal gameTotalFlow;
|
||||||
|
|
||||||
private Long gameUser;
|
private Long gameUser;
|
||||||
|
|
||||||
private BigDecimal gamePayout;
|
private BigDecimal gamePayout;
|
||||||
|
|
||||||
private Long d1RetentionUser;
|
|
||||||
|
|
||||||
private Long d1RetentionBaseUser;
|
|
||||||
|
|
||||||
private Long d7RetentionUser;
|
|
||||||
|
|
||||||
private Long d7RetentionBaseUser;
|
|
||||||
|
|
||||||
private Long d30RetentionUser;
|
|
||||||
|
|
||||||
private Long d30RetentionBaseUser;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -32,10 +32,6 @@ public class CountryDashboardPeriodMetricDTO {
|
|||||||
|
|
||||||
private Long countryNewUser;
|
private Long countryNewUser;
|
||||||
|
|
||||||
private Long dailyActiveUser;
|
|
||||||
|
|
||||||
private Long dailyRechargeUser;
|
|
||||||
|
|
||||||
private BigDecimal newUserRecharge;
|
private BigDecimal newUserRecharge;
|
||||||
|
|
||||||
private BigDecimal officialRecharge;
|
private BigDecimal officialRecharge;
|
||||||
@ -46,39 +42,17 @@ public class CountryDashboardPeriodMetricDTO {
|
|||||||
|
|
||||||
private BigDecimal dealerRecharge;
|
private BigDecimal dealerRecharge;
|
||||||
|
|
||||||
private BigDecimal userRecharge;
|
|
||||||
|
|
||||||
private BigDecimal newDealerUserRecharge;
|
|
||||||
|
|
||||||
private BigDecimal salaryExchange;
|
private BigDecimal salaryExchange;
|
||||||
|
|
||||||
private BigDecimal salaryTransfer;
|
|
||||||
|
|
||||||
private BigDecimal giftConsume;
|
|
||||||
|
|
||||||
private BigDecimal luckyGiftTotalFlow;
|
private BigDecimal luckyGiftTotalFlow;
|
||||||
|
|
||||||
private Long luckyGiftUser;
|
private Long luckyGiftUser;
|
||||||
|
|
||||||
private BigDecimal luckyGiftPayout;
|
private BigDecimal luckyGiftPayout;
|
||||||
|
|
||||||
private BigDecimal luckyGiftAnchorShare;
|
|
||||||
|
|
||||||
private BigDecimal gameTotalFlow;
|
private BigDecimal gameTotalFlow;
|
||||||
|
|
||||||
private Long gameUser;
|
private Long gameUser;
|
||||||
|
|
||||||
private BigDecimal gamePayout;
|
private BigDecimal gamePayout;
|
||||||
|
|
||||||
private Long d1RetentionUser;
|
|
||||||
|
|
||||||
private Long d1RetentionBaseUser;
|
|
||||||
|
|
||||||
private Long d7RetentionUser;
|
|
||||||
|
|
||||||
private Long d7RetentionBaseUser;
|
|
||||||
|
|
||||||
private Long d30RetentionUser;
|
|
||||||
|
|
||||||
private Long d30RetentionBaseUser;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,14 +3,6 @@
|
|||||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||||
<mapper namespace="com.red.circle.console.infra.database.rds.dao.datav.CountryDashboardDAO">
|
<mapper namespace="com.red.circle.console.infra.database.rds.dao.datav.CountryDashboardDAO">
|
||||||
|
|
||||||
<select id="getDashboardBackfillLock" resultType="java.lang.Integer">
|
|
||||||
SELECT GET_LOCK(#{lockName}, #{timeoutSeconds})
|
|
||||||
</select>
|
|
||||||
|
|
||||||
<select id="releaseDashboardBackfillLock" resultType="java.lang.Integer">
|
|
||||||
SELECT RELEASE_LOCK(#{lockName})
|
|
||||||
</select>
|
|
||||||
|
|
||||||
<update id="createDailyMetricTable">
|
<update id="createDailyMetricTable">
|
||||||
CREATE TABLE IF NOT EXISTS `country_dashboard_daily_metric` (
|
CREATE TABLE IF NOT EXISTS `country_dashboard_daily_metric` (
|
||||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
|
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||||||
@ -20,21 +12,15 @@
|
|||||||
`country_code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'UNKNOWN' COMMENT '国家码',
|
`country_code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'UNKNOWN' COMMENT '国家码',
|
||||||
`country_name` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'UNKNOWN' COMMENT '国家名称',
|
`country_name` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'UNKNOWN' COMMENT '国家名称',
|
||||||
`country_new_user` bigint NOT NULL DEFAULT 0 COMMENT '新增用户数',
|
`country_new_user` bigint NOT NULL DEFAULT 0 COMMENT '新增用户数',
|
||||||
`daily_recharge_user` bigint NOT NULL DEFAULT 0 COMMENT '当日充值用户数',
|
|
||||||
`new_user_recharge` decimal(20,2) NOT NULL DEFAULT 0.00 COMMENT '新增用户充值',
|
`new_user_recharge` decimal(20,2) NOT NULL DEFAULT 0.00 COMMENT '新增用户充值',
|
||||||
`official_recharge` decimal(20,2) NOT NULL DEFAULT 0.00 COMMENT '官方充值',
|
`official_recharge` decimal(20,2) NOT NULL DEFAULT 0.00 COMMENT '官方充值',
|
||||||
`mifapay_recharge` decimal(20,2) NOT NULL DEFAULT 0.00 COMMENT 'MifaPay充值',
|
`mifapay_recharge` decimal(20,2) NOT NULL DEFAULT 0.00 COMMENT 'MifaPay充值',
|
||||||
`google_recharge` decimal(20,2) NOT NULL DEFAULT 0.00 COMMENT 'Google充值',
|
`google_recharge` decimal(20,2) NOT NULL DEFAULT 0.00 COMMENT 'Google充值',
|
||||||
`dealer_recharge` decimal(20,2) NOT NULL DEFAULT 0.00 COMMENT '代理充值',
|
`dealer_recharge` decimal(20,2) NOT NULL DEFAULT 0.00 COMMENT '代理充值',
|
||||||
`user_recharge` decimal(20,2) NOT NULL DEFAULT 0.00 COMMENT '用户充值',
|
|
||||||
`new_dealer_user_recharge` decimal(20,2) NOT NULL DEFAULT 0.00 COMMENT '新增币商用户充值',
|
|
||||||
`salary_exchange` decimal(20,2) NOT NULL DEFAULT 0.00 COMMENT '工资兑换',
|
`salary_exchange` decimal(20,2) NOT NULL DEFAULT 0.00 COMMENT '工资兑换',
|
||||||
`salary_transfer` decimal(20,2) NOT NULL DEFAULT 0.00 COMMENT '工资转移',
|
|
||||||
`gift_consume` decimal(20,2) NOT NULL DEFAULT 0.00 COMMENT '礼物消耗',
|
|
||||||
`lucky_gift_total_flow` decimal(20,2) NOT NULL DEFAULT 0.00 COMMENT '幸运礼物流水',
|
`lucky_gift_total_flow` decimal(20,2) NOT NULL DEFAULT 0.00 COMMENT '幸运礼物流水',
|
||||||
`lucky_gift_user` bigint NOT NULL DEFAULT 0 COMMENT '幸运礼物用户数',
|
`lucky_gift_user` bigint NOT NULL DEFAULT 0 COMMENT '幸运礼物用户数',
|
||||||
`lucky_gift_payout` decimal(20,2) NOT NULL DEFAULT 0.00 COMMENT '幸运礼物返奖',
|
`lucky_gift_payout` decimal(20,2) NOT NULL DEFAULT 0.00 COMMENT '幸运礼物返奖',
|
||||||
`lucky_gift_anchor_share` decimal(20,2) NOT NULL DEFAULT 0.00 COMMENT '幸运礼物主播分成',
|
|
||||||
`game_total_flow` decimal(20,2) NOT NULL DEFAULT 0.00 COMMENT '游戏流水',
|
`game_total_flow` decimal(20,2) NOT NULL DEFAULT 0.00 COMMENT '游戏流水',
|
||||||
`game_user` bigint NOT NULL DEFAULT 0 COMMENT '游戏用户数',
|
`game_user` bigint NOT NULL DEFAULT 0 COMMENT '游戏用户数',
|
||||||
`game_payout` decimal(20,2) NOT NULL DEFAULT 0.00 COMMENT '游戏返奖',
|
`game_payout` decimal(20,2) NOT NULL DEFAULT 0.00 COMMENT '游戏返奖',
|
||||||
@ -61,31 +47,18 @@
|
|||||||
`country_code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'UNKNOWN' COMMENT '国家码',
|
`country_code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'UNKNOWN' COMMENT '国家码',
|
||||||
`country_name` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'UNKNOWN' COMMENT '国家名称',
|
`country_name` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'UNKNOWN' COMMENT '国家名称',
|
||||||
`country_new_user` bigint NOT NULL DEFAULT 0 COMMENT '新增用户数',
|
`country_new_user` bigint NOT NULL DEFAULT 0 COMMENT '新增用户数',
|
||||||
`daily_active_user` bigint NOT NULL DEFAULT 0 COMMENT '当日活跃用户数',
|
|
||||||
`daily_recharge_user` bigint NOT NULL DEFAULT 0 COMMENT '当日充值用户数',
|
|
||||||
`new_user_recharge` decimal(20,2) NOT NULL DEFAULT 0.00 COMMENT '新增用户充值',
|
`new_user_recharge` decimal(20,2) NOT NULL DEFAULT 0.00 COMMENT '新增用户充值',
|
||||||
`official_recharge` decimal(20,2) NOT NULL DEFAULT 0.00 COMMENT '官方充值',
|
`official_recharge` decimal(20,2) NOT NULL DEFAULT 0.00 COMMENT '官方充值',
|
||||||
`mifapay_recharge` decimal(20,2) NOT NULL DEFAULT 0.00 COMMENT 'MifaPay充值',
|
`mifapay_recharge` decimal(20,2) NOT NULL DEFAULT 0.00 COMMENT 'MifaPay充值',
|
||||||
`google_recharge` decimal(20,2) NOT NULL DEFAULT 0.00 COMMENT 'Google充值',
|
`google_recharge` decimal(20,2) NOT NULL DEFAULT 0.00 COMMENT 'Google充值',
|
||||||
`dealer_recharge` decimal(20,2) NOT NULL DEFAULT 0.00 COMMENT '代理充值',
|
`dealer_recharge` decimal(20,2) NOT NULL DEFAULT 0.00 COMMENT '代理充值',
|
||||||
`user_recharge` decimal(20,2) NOT NULL DEFAULT 0.00 COMMENT '用户充值',
|
|
||||||
`new_dealer_user_recharge` decimal(20,2) NOT NULL DEFAULT 0.00 COMMENT '新增币商用户充值',
|
|
||||||
`salary_exchange` decimal(20,2) NOT NULL DEFAULT 0.00 COMMENT '工资兑换',
|
`salary_exchange` decimal(20,2) NOT NULL DEFAULT 0.00 COMMENT '工资兑换',
|
||||||
`salary_transfer` decimal(20,2) NOT NULL DEFAULT 0.00 COMMENT '工资转移',
|
|
||||||
`gift_consume` decimal(20,2) NOT NULL DEFAULT 0.00 COMMENT '礼物消耗',
|
|
||||||
`lucky_gift_total_flow` decimal(20,2) NOT NULL DEFAULT 0.00 COMMENT '幸运礼物流水',
|
`lucky_gift_total_flow` decimal(20,2) NOT NULL DEFAULT 0.00 COMMENT '幸运礼物流水',
|
||||||
`lucky_gift_user` bigint NOT NULL DEFAULT 0 COMMENT '幸运礼物用户数',
|
`lucky_gift_user` bigint NOT NULL DEFAULT 0 COMMENT '幸运礼物用户数',
|
||||||
`lucky_gift_payout` decimal(20,2) NOT NULL DEFAULT 0.00 COMMENT '幸运礼物返奖',
|
`lucky_gift_payout` decimal(20,2) NOT NULL DEFAULT 0.00 COMMENT '幸运礼物返奖',
|
||||||
`lucky_gift_anchor_share` decimal(20,2) NOT NULL DEFAULT 0.00 COMMENT '幸运礼物主播分成',
|
|
||||||
`game_total_flow` decimal(20,2) NOT NULL DEFAULT 0.00 COMMENT '游戏流水',
|
`game_total_flow` decimal(20,2) NOT NULL DEFAULT 0.00 COMMENT '游戏流水',
|
||||||
`game_user` bigint NOT NULL DEFAULT 0 COMMENT '游戏用户数',
|
`game_user` bigint NOT NULL DEFAULT 0 COMMENT '游戏用户数',
|
||||||
`game_payout` decimal(20,2) NOT NULL DEFAULT 0.00 COMMENT '游戏返奖',
|
`game_payout` decimal(20,2) NOT NULL DEFAULT 0.00 COMMENT '游戏返奖',
|
||||||
`d1_retention_user` bigint NOT NULL DEFAULT 0 COMMENT '次日留存用户数',
|
|
||||||
`d1_retention_base_user` bigint NOT NULL DEFAULT 0 COMMENT '次日留存基数',
|
|
||||||
`d7_retention_user` bigint NOT NULL DEFAULT 0 COMMENT '7日留存用户数',
|
|
||||||
`d7_retention_base_user` bigint NOT NULL DEFAULT 0 COMMENT '7日留存基数',
|
|
||||||
`d30_retention_user` bigint NOT NULL DEFAULT 0 COMMENT '30日留存用户数',
|
|
||||||
`d30_retention_base_user` bigint NOT NULL DEFAULT 0 COMMENT '30日留存基数',
|
|
||||||
`refreshed_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '最近刷新时间',
|
`refreshed_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '最近刷新时间',
|
||||||
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||||
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||||
@ -208,28 +181,6 @@
|
|||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='国家数据大屏游戏维度周期用户去重明细'
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='国家数据大屏游戏维度周期用户去重明细'
|
||||||
</update>
|
</update>
|
||||||
|
|
||||||
<update id="createRechargeDetailTable">
|
|
||||||
CREATE TABLE IF NOT EXISTS `country_dashboard_recharge_detail` (
|
|
||||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
|
|
||||||
`source_type` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '充值来源',
|
|
||||||
`record_id` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '来源记录ID',
|
|
||||||
`source_channel` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '来源渠道',
|
|
||||||
`sys_origin` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '系统来源',
|
|
||||||
`user_id` bigint NOT NULL COMMENT '用户ID',
|
|
||||||
`country_code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'UNKNOWN' COMMENT '国家码',
|
|
||||||
`country_name` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'UNKNOWN' COMMENT '国家名称',
|
|
||||||
`amount` decimal(20,2) NOT NULL DEFAULT 0.00 COMMENT 'USD金额',
|
|
||||||
`coin_quantity` decimal(20,2) DEFAULT NULL COMMENT '金币数量',
|
|
||||||
`remark` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '备注',
|
|
||||||
`create_time` datetime NOT NULL COMMENT '业务创建时间',
|
|
||||||
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
|
||||||
PRIMARY KEY (`id`),
|
|
||||||
UNIQUE KEY `uk_recharge_source_record` (`source_type`, `record_id`),
|
|
||||||
KEY `idx_recharge_query` (`sys_origin`, `create_time`, `country_code`),
|
|
||||||
KEY `idx_recharge_user` (`user_id`, `create_time`)
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='国家数据大屏充值明细预聚合'
|
|
||||||
</update>
|
|
||||||
|
|
||||||
<update id="ensurePeriodMetricTimezoneSchema">
|
<update id="ensurePeriodMetricTimezoneSchema">
|
||||||
SET @country_dashboard_schema_lock = GET_LOCK('country_dashboard_period_timezone_schema', 60);
|
SET @country_dashboard_schema_lock = GET_LOCK('country_dashboard_period_timezone_schema', 60);
|
||||||
SET @current_schema = DATABASE();
|
SET @current_schema = DATABASE();
|
||||||
@ -473,305 +424,6 @@
|
|||||||
DO IF(@country_dashboard_schema_lock = 1, RELEASE_LOCK('country_dashboard_period_timezone_schema'), 0);
|
DO IF(@country_dashboard_schema_lock = 1, RELEASE_LOCK('country_dashboard_period_timezone_schema'), 0);
|
||||||
</update>
|
</update>
|
||||||
|
|
||||||
<update id="ensurePeriodMetricUserColumnsSchema">
|
|
||||||
SET @country_dashboard_user_columns_schema_lock = GET_LOCK('country_dashboard_period_user_columns_schema', 60);
|
|
||||||
SET @current_schema = DATABASE();
|
|
||||||
|
|
||||||
SET @ddl = IF(
|
|
||||||
@country_dashboard_user_columns_schema_lock = 1
|
|
||||||
AND NOT EXISTS (
|
|
||||||
SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS
|
|
||||||
WHERE TABLE_SCHEMA = @current_schema
|
|
||||||
AND TABLE_NAME = 'country_dashboard_period_metric'
|
|
||||||
AND COLUMN_NAME = 'daily_active_user'
|
|
||||||
),
|
|
||||||
'ALTER TABLE `country_dashboard_period_metric` ADD COLUMN `daily_active_user` bigint NOT NULL DEFAULT 0 COMMENT ''当日活跃用户数'' AFTER `country_new_user`',
|
|
||||||
'SELECT 1'
|
|
||||||
);
|
|
||||||
PREPARE stmt FROM @ddl;
|
|
||||||
EXECUTE stmt;
|
|
||||||
DEALLOCATE PREPARE stmt;
|
|
||||||
|
|
||||||
SET @ddl = IF(
|
|
||||||
@country_dashboard_user_columns_schema_lock = 1
|
|
||||||
AND NOT EXISTS (
|
|
||||||
SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS
|
|
||||||
WHERE TABLE_SCHEMA = @current_schema
|
|
||||||
AND TABLE_NAME = 'country_dashboard_period_metric'
|
|
||||||
AND COLUMN_NAME = 'daily_recharge_user'
|
|
||||||
),
|
|
||||||
'ALTER TABLE `country_dashboard_period_metric` ADD COLUMN `daily_recharge_user` bigint NOT NULL DEFAULT 0 COMMENT ''当日充值用户数'' AFTER `daily_active_user`',
|
|
||||||
'SELECT 1'
|
|
||||||
);
|
|
||||||
PREPARE stmt FROM @ddl;
|
|
||||||
EXECUTE stmt;
|
|
||||||
DEALLOCATE PREPARE stmt;
|
|
||||||
|
|
||||||
SET @ddl = IF(
|
|
||||||
@country_dashboard_user_columns_schema_lock = 1
|
|
||||||
AND NOT EXISTS (
|
|
||||||
SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS
|
|
||||||
WHERE TABLE_SCHEMA = @current_schema
|
|
||||||
AND TABLE_NAME = 'country_dashboard_period_metric'
|
|
||||||
AND COLUMN_NAME = 'd1_retention_user'
|
|
||||||
),
|
|
||||||
'ALTER TABLE `country_dashboard_period_metric` ADD COLUMN `d1_retention_user` bigint NOT NULL DEFAULT 0 COMMENT ''次日留存用户数'' AFTER `game_payout`',
|
|
||||||
'SELECT 1'
|
|
||||||
);
|
|
||||||
PREPARE stmt FROM @ddl;
|
|
||||||
EXECUTE stmt;
|
|
||||||
DEALLOCATE PREPARE stmt;
|
|
||||||
|
|
||||||
SET @ddl = IF(
|
|
||||||
@country_dashboard_user_columns_schema_lock = 1
|
|
||||||
AND NOT EXISTS (
|
|
||||||
SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS
|
|
||||||
WHERE TABLE_SCHEMA = @current_schema
|
|
||||||
AND TABLE_NAME = 'country_dashboard_period_metric'
|
|
||||||
AND COLUMN_NAME = 'd1_retention_base_user'
|
|
||||||
),
|
|
||||||
'ALTER TABLE `country_dashboard_period_metric` ADD COLUMN `d1_retention_base_user` bigint NOT NULL DEFAULT 0 COMMENT ''次日留存基数'' AFTER `d1_retention_user`',
|
|
||||||
'SELECT 1'
|
|
||||||
);
|
|
||||||
PREPARE stmt FROM @ddl;
|
|
||||||
EXECUTE stmt;
|
|
||||||
DEALLOCATE PREPARE stmt;
|
|
||||||
|
|
||||||
SET @ddl = IF(
|
|
||||||
@country_dashboard_user_columns_schema_lock = 1
|
|
||||||
AND NOT EXISTS (
|
|
||||||
SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS
|
|
||||||
WHERE TABLE_SCHEMA = @current_schema
|
|
||||||
AND TABLE_NAME = 'country_dashboard_period_metric'
|
|
||||||
AND COLUMN_NAME = 'd7_retention_user'
|
|
||||||
),
|
|
||||||
'ALTER TABLE `country_dashboard_period_metric` ADD COLUMN `d7_retention_user` bigint NOT NULL DEFAULT 0 COMMENT ''7日留存用户数'' AFTER `d1_retention_base_user`',
|
|
||||||
'SELECT 1'
|
|
||||||
);
|
|
||||||
PREPARE stmt FROM @ddl;
|
|
||||||
EXECUTE stmt;
|
|
||||||
DEALLOCATE PREPARE stmt;
|
|
||||||
|
|
||||||
SET @ddl = IF(
|
|
||||||
@country_dashboard_user_columns_schema_lock = 1
|
|
||||||
AND NOT EXISTS (
|
|
||||||
SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS
|
|
||||||
WHERE TABLE_SCHEMA = @current_schema
|
|
||||||
AND TABLE_NAME = 'country_dashboard_period_metric'
|
|
||||||
AND COLUMN_NAME = 'd7_retention_base_user'
|
|
||||||
),
|
|
||||||
'ALTER TABLE `country_dashboard_period_metric` ADD COLUMN `d7_retention_base_user` bigint NOT NULL DEFAULT 0 COMMENT ''7日留存基数'' AFTER `d7_retention_user`',
|
|
||||||
'SELECT 1'
|
|
||||||
);
|
|
||||||
PREPARE stmt FROM @ddl;
|
|
||||||
EXECUTE stmt;
|
|
||||||
DEALLOCATE PREPARE stmt;
|
|
||||||
|
|
||||||
SET @ddl = IF(
|
|
||||||
@country_dashboard_user_columns_schema_lock = 1
|
|
||||||
AND NOT EXISTS (
|
|
||||||
SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS
|
|
||||||
WHERE TABLE_SCHEMA = @current_schema
|
|
||||||
AND TABLE_NAME = 'country_dashboard_period_metric'
|
|
||||||
AND COLUMN_NAME = 'd30_retention_user'
|
|
||||||
),
|
|
||||||
'ALTER TABLE `country_dashboard_period_metric` ADD COLUMN `d30_retention_user` bigint NOT NULL DEFAULT 0 COMMENT ''30日留存用户数'' AFTER `d7_retention_base_user`',
|
|
||||||
'SELECT 1'
|
|
||||||
);
|
|
||||||
PREPARE stmt FROM @ddl;
|
|
||||||
EXECUTE stmt;
|
|
||||||
DEALLOCATE PREPARE stmt;
|
|
||||||
|
|
||||||
SET @ddl = IF(
|
|
||||||
@country_dashboard_user_columns_schema_lock = 1
|
|
||||||
AND NOT EXISTS (
|
|
||||||
SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS
|
|
||||||
WHERE TABLE_SCHEMA = @current_schema
|
|
||||||
AND TABLE_NAME = 'country_dashboard_period_metric'
|
|
||||||
AND COLUMN_NAME = 'd30_retention_base_user'
|
|
||||||
),
|
|
||||||
'ALTER TABLE `country_dashboard_period_metric` ADD COLUMN `d30_retention_base_user` bigint NOT NULL DEFAULT 0 COMMENT ''30日留存基数'' AFTER `d30_retention_user`',
|
|
||||||
'SELECT 1'
|
|
||||||
);
|
|
||||||
PREPARE stmt FROM @ddl;
|
|
||||||
EXECUTE stmt;
|
|
||||||
DEALLOCATE PREPARE stmt;
|
|
||||||
|
|
||||||
DO IF(@country_dashboard_user_columns_schema_lock = 1, RELEASE_LOCK('country_dashboard_period_user_columns_schema'), 0);
|
|
||||||
</update>
|
|
||||||
|
|
||||||
<update id="ensureMetricValueColumnsSchema">
|
|
||||||
SET @country_dashboard_value_columns_schema_lock = GET_LOCK('country_dashboard_value_columns_schema', 60);
|
|
||||||
SET @current_schema = DATABASE();
|
|
||||||
|
|
||||||
SET @ddl = IF(
|
|
||||||
@country_dashboard_value_columns_schema_lock = 1
|
|
||||||
AND NOT EXISTS (
|
|
||||||
SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS
|
|
||||||
WHERE TABLE_SCHEMA = @current_schema
|
|
||||||
AND TABLE_NAME = 'country_dashboard_daily_metric'
|
|
||||||
AND COLUMN_NAME = 'salary_transfer'
|
|
||||||
),
|
|
||||||
'ALTER TABLE `country_dashboard_daily_metric` ADD COLUMN `salary_transfer` decimal(20,2) NOT NULL DEFAULT 0.00 COMMENT ''工资转移'' AFTER `salary_exchange`',
|
|
||||||
'SELECT 1'
|
|
||||||
);
|
|
||||||
PREPARE stmt FROM @ddl;
|
|
||||||
EXECUTE stmt;
|
|
||||||
DEALLOCATE PREPARE stmt;
|
|
||||||
|
|
||||||
SET @ddl = IF(
|
|
||||||
@country_dashboard_value_columns_schema_lock = 1
|
|
||||||
AND NOT EXISTS (
|
|
||||||
SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS
|
|
||||||
WHERE TABLE_SCHEMA = @current_schema
|
|
||||||
AND TABLE_NAME = 'country_dashboard_daily_metric'
|
|
||||||
AND COLUMN_NAME = 'daily_recharge_user'
|
|
||||||
),
|
|
||||||
'ALTER TABLE `country_dashboard_daily_metric` ADD COLUMN `daily_recharge_user` bigint NOT NULL DEFAULT 0 COMMENT ''当日充值用户数'' AFTER `country_new_user`',
|
|
||||||
'SELECT 1'
|
|
||||||
);
|
|
||||||
PREPARE stmt FROM @ddl;
|
|
||||||
EXECUTE stmt;
|
|
||||||
DEALLOCATE PREPARE stmt;
|
|
||||||
|
|
||||||
SET @ddl = IF(
|
|
||||||
@country_dashboard_value_columns_schema_lock = 1
|
|
||||||
AND NOT EXISTS (
|
|
||||||
SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS
|
|
||||||
WHERE TABLE_SCHEMA = @current_schema
|
|
||||||
AND TABLE_NAME = 'country_dashboard_daily_metric'
|
|
||||||
AND COLUMN_NAME = 'user_recharge'
|
|
||||||
),
|
|
||||||
'ALTER TABLE `country_dashboard_daily_metric` ADD COLUMN `user_recharge` decimal(20,2) NOT NULL DEFAULT 0.00 COMMENT ''用户充值'' AFTER `dealer_recharge`',
|
|
||||||
'SELECT 1'
|
|
||||||
);
|
|
||||||
PREPARE stmt FROM @ddl;
|
|
||||||
EXECUTE stmt;
|
|
||||||
DEALLOCATE PREPARE stmt;
|
|
||||||
|
|
||||||
SET @ddl = IF(
|
|
||||||
@country_dashboard_value_columns_schema_lock = 1
|
|
||||||
AND NOT EXISTS (
|
|
||||||
SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS
|
|
||||||
WHERE TABLE_SCHEMA = @current_schema
|
|
||||||
AND TABLE_NAME = 'country_dashboard_period_metric'
|
|
||||||
AND COLUMN_NAME = 'user_recharge'
|
|
||||||
),
|
|
||||||
'ALTER TABLE `country_dashboard_period_metric` ADD COLUMN `user_recharge` decimal(20,2) NOT NULL DEFAULT 0.00 COMMENT ''用户充值'' AFTER `dealer_recharge`',
|
|
||||||
'SELECT 1'
|
|
||||||
);
|
|
||||||
PREPARE stmt FROM @ddl;
|
|
||||||
EXECUTE stmt;
|
|
||||||
DEALLOCATE PREPARE stmt;
|
|
||||||
|
|
||||||
SET @ddl = IF(
|
|
||||||
@country_dashboard_value_columns_schema_lock = 1
|
|
||||||
AND NOT EXISTS (
|
|
||||||
SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS
|
|
||||||
WHERE TABLE_SCHEMA = @current_schema
|
|
||||||
AND TABLE_NAME = 'country_dashboard_daily_metric'
|
|
||||||
AND COLUMN_NAME = 'new_dealer_user_recharge'
|
|
||||||
),
|
|
||||||
'ALTER TABLE `country_dashboard_daily_metric` ADD COLUMN `new_dealer_user_recharge` decimal(20,2) NOT NULL DEFAULT 0.00 COMMENT ''新增币商用户充值'' AFTER `user_recharge`',
|
|
||||||
'SELECT 1'
|
|
||||||
);
|
|
||||||
PREPARE stmt FROM @ddl;
|
|
||||||
EXECUTE stmt;
|
|
||||||
DEALLOCATE PREPARE stmt;
|
|
||||||
|
|
||||||
SET @ddl = IF(
|
|
||||||
@country_dashboard_value_columns_schema_lock = 1
|
|
||||||
AND NOT EXISTS (
|
|
||||||
SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS
|
|
||||||
WHERE TABLE_SCHEMA = @current_schema
|
|
||||||
AND TABLE_NAME = 'country_dashboard_period_metric'
|
|
||||||
AND COLUMN_NAME = 'new_dealer_user_recharge'
|
|
||||||
),
|
|
||||||
'ALTER TABLE `country_dashboard_period_metric` ADD COLUMN `new_dealer_user_recharge` decimal(20,2) NOT NULL DEFAULT 0.00 COMMENT ''新增币商用户充值'' AFTER `user_recharge`',
|
|
||||||
'SELECT 1'
|
|
||||||
);
|
|
||||||
PREPARE stmt FROM @ddl;
|
|
||||||
EXECUTE stmt;
|
|
||||||
DEALLOCATE PREPARE stmt;
|
|
||||||
|
|
||||||
SET @ddl = IF(
|
|
||||||
@country_dashboard_value_columns_schema_lock = 1
|
|
||||||
AND NOT EXISTS (
|
|
||||||
SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS
|
|
||||||
WHERE TABLE_SCHEMA = @current_schema
|
|
||||||
AND TABLE_NAME = 'country_dashboard_daily_metric'
|
|
||||||
AND COLUMN_NAME = 'gift_consume'
|
|
||||||
),
|
|
||||||
'ALTER TABLE `country_dashboard_daily_metric` ADD COLUMN `gift_consume` decimal(20,2) NOT NULL DEFAULT 0.00 COMMENT ''礼物消耗'' AFTER `salary_exchange`',
|
|
||||||
'SELECT 1'
|
|
||||||
);
|
|
||||||
PREPARE stmt FROM @ddl;
|
|
||||||
EXECUTE stmt;
|
|
||||||
DEALLOCATE PREPARE stmt;
|
|
||||||
|
|
||||||
SET @ddl = IF(
|
|
||||||
@country_dashboard_value_columns_schema_lock = 1
|
|
||||||
AND NOT EXISTS (
|
|
||||||
SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS
|
|
||||||
WHERE TABLE_SCHEMA = @current_schema
|
|
||||||
AND TABLE_NAME = 'country_dashboard_period_metric'
|
|
||||||
AND COLUMN_NAME = 'salary_transfer'
|
|
||||||
),
|
|
||||||
'ALTER TABLE `country_dashboard_period_metric` ADD COLUMN `salary_transfer` decimal(20,2) NOT NULL DEFAULT 0.00 COMMENT ''工资转移'' AFTER `salary_exchange`',
|
|
||||||
'SELECT 1'
|
|
||||||
);
|
|
||||||
PREPARE stmt FROM @ddl;
|
|
||||||
EXECUTE stmt;
|
|
||||||
DEALLOCATE PREPARE stmt;
|
|
||||||
|
|
||||||
SET @ddl = IF(
|
|
||||||
@country_dashboard_value_columns_schema_lock = 1
|
|
||||||
AND NOT EXISTS (
|
|
||||||
SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS
|
|
||||||
WHERE TABLE_SCHEMA = @current_schema
|
|
||||||
AND TABLE_NAME = 'country_dashboard_daily_metric'
|
|
||||||
AND COLUMN_NAME = 'lucky_gift_anchor_share'
|
|
||||||
),
|
|
||||||
'ALTER TABLE `country_dashboard_daily_metric` ADD COLUMN `lucky_gift_anchor_share` decimal(20,2) NOT NULL DEFAULT 0.00 COMMENT ''幸运礼物主播分成'' AFTER `lucky_gift_payout`',
|
|
||||||
'SELECT 1'
|
|
||||||
);
|
|
||||||
PREPARE stmt FROM @ddl;
|
|
||||||
EXECUTE stmt;
|
|
||||||
DEALLOCATE PREPARE stmt;
|
|
||||||
|
|
||||||
SET @ddl = IF(
|
|
||||||
@country_dashboard_value_columns_schema_lock = 1
|
|
||||||
AND NOT EXISTS (
|
|
||||||
SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS
|
|
||||||
WHERE TABLE_SCHEMA = @current_schema
|
|
||||||
AND TABLE_NAME = 'country_dashboard_period_metric'
|
|
||||||
AND COLUMN_NAME = 'gift_consume'
|
|
||||||
),
|
|
||||||
'ALTER TABLE `country_dashboard_period_metric` ADD COLUMN `gift_consume` decimal(20,2) NOT NULL DEFAULT 0.00 COMMENT ''礼物消耗'' AFTER `salary_exchange`',
|
|
||||||
'SELECT 1'
|
|
||||||
);
|
|
||||||
PREPARE stmt FROM @ddl;
|
|
||||||
EXECUTE stmt;
|
|
||||||
DEALLOCATE PREPARE stmt;
|
|
||||||
|
|
||||||
SET @ddl = IF(
|
|
||||||
@country_dashboard_value_columns_schema_lock = 1
|
|
||||||
AND NOT EXISTS (
|
|
||||||
SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS
|
|
||||||
WHERE TABLE_SCHEMA = @current_schema
|
|
||||||
AND TABLE_NAME = 'country_dashboard_period_metric'
|
|
||||||
AND COLUMN_NAME = 'lucky_gift_anchor_share'
|
|
||||||
),
|
|
||||||
'ALTER TABLE `country_dashboard_period_metric` ADD COLUMN `lucky_gift_anchor_share` decimal(20,2) NOT NULL DEFAULT 0.00 COMMENT ''幸运礼物主播分成'' AFTER `lucky_gift_payout`',
|
|
||||||
'SELECT 1'
|
|
||||||
);
|
|
||||||
PREPARE stmt FROM @ddl;
|
|
||||||
EXECUTE stmt;
|
|
||||||
DEALLOCATE PREPARE stmt;
|
|
||||||
|
|
||||||
DO IF(@country_dashboard_value_columns_schema_lock = 1, RELEASE_LOCK('country_dashboard_value_columns_schema'), 0);
|
|
||||||
</update>
|
|
||||||
|
|
||||||
<sql id="CountryColumns">
|
<sql id="CountryColumns">
|
||||||
NULLIF(u.country_code, '') AS countryCode,
|
NULLIF(u.country_code, '') AS countryCode,
|
||||||
NULLIF(u.country_name, '') AS countryName
|
NULLIF(u.country_name, '') AS countryName
|
||||||
@ -1180,21 +832,15 @@
|
|||||||
MAX(t.country_name) AS countryName,
|
MAX(t.country_name) AS countryName,
|
||||||
<include refid="PrecomputedPeriodColumns"/>,
|
<include refid="PrecomputedPeriodColumns"/>,
|
||||||
IFNULL(SUM(t.country_new_user), 0) AS countryNewUser,
|
IFNULL(SUM(t.country_new_user), 0) AS countryNewUser,
|
||||||
IFNULL(SUM(t.daily_recharge_user), 0) AS dailyRechargeUser,
|
|
||||||
IFNULL(SUM(t.new_user_recharge), 0) AS newUserRecharge,
|
IFNULL(SUM(t.new_user_recharge), 0) AS newUserRecharge,
|
||||||
IFNULL(SUM(t.official_recharge), 0) AS officialRecharge,
|
IFNULL(SUM(t.official_recharge), 0) AS officialRecharge,
|
||||||
IFNULL(SUM(t.mifapay_recharge), 0) AS mifapayRecharge,
|
IFNULL(SUM(t.mifapay_recharge), 0) AS mifapayRecharge,
|
||||||
IFNULL(SUM(t.google_recharge), 0) AS googleRecharge,
|
IFNULL(SUM(t.google_recharge), 0) AS googleRecharge,
|
||||||
IFNULL(SUM(t.dealer_recharge), 0) AS dealerRecharge,
|
IFNULL(SUM(t.dealer_recharge), 0) AS dealerRecharge,
|
||||||
IFNULL(SUM(t.user_recharge), 0) AS userRecharge,
|
|
||||||
IFNULL(SUM(t.new_dealer_user_recharge), 0) AS newDealerUserRecharge,
|
|
||||||
IFNULL(SUM(t.salary_exchange), 0) AS salaryExchange,
|
IFNULL(SUM(t.salary_exchange), 0) AS salaryExchange,
|
||||||
IFNULL(SUM(t.salary_transfer), 0) AS salaryTransfer,
|
|
||||||
IFNULL(SUM(t.gift_consume), 0) AS giftConsume,
|
|
||||||
IFNULL(SUM(t.lucky_gift_total_flow), 0) AS luckyGiftTotalFlow,
|
IFNULL(SUM(t.lucky_gift_total_flow), 0) AS luckyGiftTotalFlow,
|
||||||
IFNULL(SUM(t.lucky_gift_user), 0) AS luckyGiftUser,
|
IFNULL(SUM(t.lucky_gift_user), 0) AS luckyGiftUser,
|
||||||
IFNULL(SUM(t.lucky_gift_payout), 0) AS luckyGiftPayout,
|
IFNULL(SUM(t.lucky_gift_payout), 0) AS luckyGiftPayout,
|
||||||
IFNULL(SUM(t.lucky_gift_anchor_share), 0) AS luckyGiftAnchorShare,
|
|
||||||
IFNULL(SUM(t.game_total_flow), 0) AS gameTotalFlow,
|
IFNULL(SUM(t.game_total_flow), 0) AS gameTotalFlow,
|
||||||
IFNULL(SUM(t.game_user), 0) AS gameUser,
|
IFNULL(SUM(t.game_user), 0) AS gameUser,
|
||||||
IFNULL(SUM(t.game_payout), 0) AS gamePayout
|
IFNULL(SUM(t.game_payout), 0) AS gamePayout
|
||||||
@ -1241,31 +887,18 @@
|
|||||||
t.period_key AS periodKey,
|
t.period_key AS periodKey,
|
||||||
MAX(t.period_name) AS periodName,
|
MAX(t.period_name) AS periodName,
|
||||||
IFNULL(SUM(t.country_new_user), 0) AS countryNewUser,
|
IFNULL(SUM(t.country_new_user), 0) AS countryNewUser,
|
||||||
IFNULL(SUM(t.daily_active_user), 0) AS dailyActiveUser,
|
|
||||||
IFNULL(SUM(t.daily_recharge_user), 0) AS dailyRechargeUser,
|
|
||||||
IFNULL(SUM(t.new_user_recharge), 0) AS newUserRecharge,
|
IFNULL(SUM(t.new_user_recharge), 0) AS newUserRecharge,
|
||||||
IFNULL(SUM(t.official_recharge), 0) AS officialRecharge,
|
IFNULL(SUM(t.official_recharge), 0) AS officialRecharge,
|
||||||
IFNULL(SUM(t.mifapay_recharge), 0) AS mifapayRecharge,
|
IFNULL(SUM(t.mifapay_recharge), 0) AS mifapayRecharge,
|
||||||
IFNULL(SUM(t.google_recharge), 0) AS googleRecharge,
|
IFNULL(SUM(t.google_recharge), 0) AS googleRecharge,
|
||||||
IFNULL(SUM(t.dealer_recharge), 0) AS dealerRecharge,
|
IFNULL(SUM(t.dealer_recharge), 0) AS dealerRecharge,
|
||||||
IFNULL(SUM(t.user_recharge), 0) AS userRecharge,
|
|
||||||
IFNULL(SUM(t.new_dealer_user_recharge), 0) AS newDealerUserRecharge,
|
|
||||||
IFNULL(SUM(t.salary_exchange), 0) AS salaryExchange,
|
IFNULL(SUM(t.salary_exchange), 0) AS salaryExchange,
|
||||||
IFNULL(SUM(t.salary_transfer), 0) AS salaryTransfer,
|
|
||||||
IFNULL(SUM(t.gift_consume), 0) AS giftConsume,
|
|
||||||
IFNULL(SUM(t.lucky_gift_total_flow), 0) AS luckyGiftTotalFlow,
|
IFNULL(SUM(t.lucky_gift_total_flow), 0) AS luckyGiftTotalFlow,
|
||||||
IFNULL(SUM(t.lucky_gift_user), 0) AS luckyGiftUser,
|
IFNULL(SUM(t.lucky_gift_user), 0) AS luckyGiftUser,
|
||||||
IFNULL(SUM(t.lucky_gift_payout), 0) AS luckyGiftPayout,
|
IFNULL(SUM(t.lucky_gift_payout), 0) AS luckyGiftPayout,
|
||||||
IFNULL(SUM(t.lucky_gift_anchor_share), 0) AS luckyGiftAnchorShare,
|
|
||||||
IFNULL(SUM(t.game_total_flow), 0) AS gameTotalFlow,
|
IFNULL(SUM(t.game_total_flow), 0) AS gameTotalFlow,
|
||||||
IFNULL(SUM(t.game_user), 0) AS gameUser,
|
IFNULL(SUM(t.game_user), 0) AS gameUser,
|
||||||
IFNULL(SUM(t.game_payout), 0) AS gamePayout,
|
IFNULL(SUM(t.game_payout), 0) AS gamePayout
|
||||||
IFNULL(SUM(t.d1_retention_user), 0) AS d1RetentionUser,
|
|
||||||
IFNULL(SUM(t.d1_retention_base_user), 0) AS d1RetentionBaseUser,
|
|
||||||
IFNULL(SUM(t.d7_retention_user), 0) AS d7RetentionUser,
|
|
||||||
IFNULL(SUM(t.d7_retention_base_user), 0) AS d7RetentionBaseUser,
|
|
||||||
IFNULL(SUM(t.d30_retention_user), 0) AS d30RetentionUser,
|
|
||||||
IFNULL(SUM(t.d30_retention_base_user), 0) AS d30RetentionBaseUser
|
|
||||||
FROM country_dashboard_period_metric t
|
FROM country_dashboard_period_metric t
|
||||||
WHERE t.period_type = #{periodType}
|
WHERE t.period_type = #{periodType}
|
||||||
AND t.stat_timezone = #{statTimezone}
|
AND t.stat_timezone = #{statTimezone}
|
||||||
@ -1330,21 +963,15 @@
|
|||||||
country_code,
|
country_code,
|
||||||
country_name,
|
country_name,
|
||||||
country_new_user,
|
country_new_user,
|
||||||
daily_recharge_user,
|
|
||||||
new_user_recharge,
|
new_user_recharge,
|
||||||
official_recharge,
|
official_recharge,
|
||||||
mifapay_recharge,
|
mifapay_recharge,
|
||||||
google_recharge,
|
google_recharge,
|
||||||
dealer_recharge,
|
dealer_recharge,
|
||||||
user_recharge,
|
|
||||||
new_dealer_user_recharge,
|
|
||||||
salary_exchange,
|
salary_exchange,
|
||||||
salary_transfer,
|
|
||||||
gift_consume,
|
|
||||||
lucky_gift_total_flow,
|
lucky_gift_total_flow,
|
||||||
lucky_gift_user,
|
lucky_gift_user,
|
||||||
lucky_gift_payout,
|
lucky_gift_payout,
|
||||||
lucky_gift_anchor_share,
|
|
||||||
game_total_flow,
|
game_total_flow,
|
||||||
game_user,
|
game_user,
|
||||||
game_payout,
|
game_payout,
|
||||||
@ -1359,21 +986,15 @@
|
|||||||
#{item.countryCode},
|
#{item.countryCode},
|
||||||
#{item.countryName},
|
#{item.countryName},
|
||||||
IFNULL(#{item.countryNewUser}, 0),
|
IFNULL(#{item.countryNewUser}, 0),
|
||||||
IFNULL(#{item.dailyRechargeUser}, 0),
|
|
||||||
IFNULL(#{item.newUserRecharge}, 0),
|
IFNULL(#{item.newUserRecharge}, 0),
|
||||||
IFNULL(#{item.officialRecharge}, 0),
|
IFNULL(#{item.officialRecharge}, 0),
|
||||||
IFNULL(#{item.mifapayRecharge}, 0),
|
IFNULL(#{item.mifapayRecharge}, 0),
|
||||||
IFNULL(#{item.googleRecharge}, 0),
|
IFNULL(#{item.googleRecharge}, 0),
|
||||||
IFNULL(#{item.dealerRecharge}, 0),
|
IFNULL(#{item.dealerRecharge}, 0),
|
||||||
IFNULL(#{item.userRecharge}, 0),
|
|
||||||
IFNULL(#{item.newDealerUserRecharge}, 0),
|
|
||||||
IFNULL(#{item.salaryExchange}, 0),
|
IFNULL(#{item.salaryExchange}, 0),
|
||||||
IFNULL(#{item.salaryTransfer}, 0),
|
|
||||||
IFNULL(#{item.giftConsume}, 0),
|
|
||||||
IFNULL(#{item.luckyGiftTotalFlow}, 0),
|
IFNULL(#{item.luckyGiftTotalFlow}, 0),
|
||||||
IFNULL(#{item.luckyGiftUser}, 0),
|
IFNULL(#{item.luckyGiftUser}, 0),
|
||||||
IFNULL(#{item.luckyGiftPayout}, 0),
|
IFNULL(#{item.luckyGiftPayout}, 0),
|
||||||
IFNULL(#{item.luckyGiftAnchorShare}, 0),
|
|
||||||
IFNULL(#{item.gameTotalFlow}, 0),
|
IFNULL(#{item.gameTotalFlow}, 0),
|
||||||
IFNULL(#{item.gameUser}, 0),
|
IFNULL(#{item.gameUser}, 0),
|
||||||
IFNULL(#{item.gamePayout}, 0),
|
IFNULL(#{item.gamePayout}, 0),
|
||||||
@ -1383,21 +1004,15 @@
|
|||||||
ON DUPLICATE KEY UPDATE
|
ON DUPLICATE KEY UPDATE
|
||||||
country_name = VALUES(country_name),
|
country_name = VALUES(country_name),
|
||||||
country_new_user = VALUES(country_new_user),
|
country_new_user = VALUES(country_new_user),
|
||||||
daily_recharge_user = VALUES(daily_recharge_user),
|
|
||||||
new_user_recharge = VALUES(new_user_recharge),
|
new_user_recharge = VALUES(new_user_recharge),
|
||||||
official_recharge = VALUES(official_recharge),
|
official_recharge = VALUES(official_recharge),
|
||||||
mifapay_recharge = VALUES(mifapay_recharge),
|
mifapay_recharge = VALUES(mifapay_recharge),
|
||||||
google_recharge = VALUES(google_recharge),
|
google_recharge = VALUES(google_recharge),
|
||||||
dealer_recharge = VALUES(dealer_recharge),
|
dealer_recharge = VALUES(dealer_recharge),
|
||||||
user_recharge = VALUES(user_recharge),
|
|
||||||
new_dealer_user_recharge = VALUES(new_dealer_user_recharge),
|
|
||||||
salary_exchange = VALUES(salary_exchange),
|
salary_exchange = VALUES(salary_exchange),
|
||||||
salary_transfer = VALUES(salary_transfer),
|
|
||||||
gift_consume = VALUES(gift_consume),
|
|
||||||
lucky_gift_total_flow = VALUES(lucky_gift_total_flow),
|
lucky_gift_total_flow = VALUES(lucky_gift_total_flow),
|
||||||
lucky_gift_user = VALUES(lucky_gift_user),
|
lucky_gift_user = VALUES(lucky_gift_user),
|
||||||
lucky_gift_payout = VALUES(lucky_gift_payout),
|
lucky_gift_payout = VALUES(lucky_gift_payout),
|
||||||
lucky_gift_anchor_share = VALUES(lucky_gift_anchor_share),
|
|
||||||
game_total_flow = VALUES(game_total_flow),
|
game_total_flow = VALUES(game_total_flow),
|
||||||
game_user = VALUES(game_user),
|
game_user = VALUES(game_user),
|
||||||
game_payout = VALUES(game_payout),
|
game_payout = VALUES(game_payout),
|
||||||
@ -1426,31 +1041,18 @@
|
|||||||
country_code,
|
country_code,
|
||||||
country_name,
|
country_name,
|
||||||
country_new_user,
|
country_new_user,
|
||||||
daily_active_user,
|
|
||||||
daily_recharge_user,
|
|
||||||
new_user_recharge,
|
new_user_recharge,
|
||||||
official_recharge,
|
official_recharge,
|
||||||
mifapay_recharge,
|
mifapay_recharge,
|
||||||
google_recharge,
|
google_recharge,
|
||||||
dealer_recharge,
|
dealer_recharge,
|
||||||
user_recharge,
|
|
||||||
new_dealer_user_recharge,
|
|
||||||
salary_exchange,
|
salary_exchange,
|
||||||
salary_transfer,
|
|
||||||
gift_consume,
|
|
||||||
lucky_gift_total_flow,
|
lucky_gift_total_flow,
|
||||||
lucky_gift_user,
|
lucky_gift_user,
|
||||||
lucky_gift_payout,
|
lucky_gift_payout,
|
||||||
lucky_gift_anchor_share,
|
|
||||||
game_total_flow,
|
game_total_flow,
|
||||||
game_user,
|
game_user,
|
||||||
game_payout,
|
game_payout,
|
||||||
d1_retention_user,
|
|
||||||
d1_retention_base_user,
|
|
||||||
d7_retention_user,
|
|
||||||
d7_retention_base_user,
|
|
||||||
d30_retention_user,
|
|
||||||
d30_retention_base_user,
|
|
||||||
refreshed_at
|
refreshed_at
|
||||||
)
|
)
|
||||||
VALUES
|
VALUES
|
||||||
@ -1466,31 +1068,18 @@
|
|||||||
#{item.countryCode},
|
#{item.countryCode},
|
||||||
#{item.countryName},
|
#{item.countryName},
|
||||||
IFNULL(#{item.countryNewUser}, 0),
|
IFNULL(#{item.countryNewUser}, 0),
|
||||||
IFNULL(#{item.dailyActiveUser}, 0),
|
|
||||||
IFNULL(#{item.dailyRechargeUser}, 0),
|
|
||||||
IFNULL(#{item.newUserRecharge}, 0),
|
IFNULL(#{item.newUserRecharge}, 0),
|
||||||
IFNULL(#{item.officialRecharge}, 0),
|
IFNULL(#{item.officialRecharge}, 0),
|
||||||
IFNULL(#{item.mifapayRecharge}, 0),
|
IFNULL(#{item.mifapayRecharge}, 0),
|
||||||
IFNULL(#{item.googleRecharge}, 0),
|
IFNULL(#{item.googleRecharge}, 0),
|
||||||
IFNULL(#{item.dealerRecharge}, 0),
|
IFNULL(#{item.dealerRecharge}, 0),
|
||||||
IFNULL(#{item.userRecharge}, 0),
|
|
||||||
IFNULL(#{item.newDealerUserRecharge}, 0),
|
|
||||||
IFNULL(#{item.salaryExchange}, 0),
|
IFNULL(#{item.salaryExchange}, 0),
|
||||||
IFNULL(#{item.salaryTransfer}, 0),
|
|
||||||
IFNULL(#{item.giftConsume}, 0),
|
|
||||||
IFNULL(#{item.luckyGiftTotalFlow}, 0),
|
IFNULL(#{item.luckyGiftTotalFlow}, 0),
|
||||||
IFNULL(#{item.luckyGiftUser}, 0),
|
IFNULL(#{item.luckyGiftUser}, 0),
|
||||||
IFNULL(#{item.luckyGiftPayout}, 0),
|
IFNULL(#{item.luckyGiftPayout}, 0),
|
||||||
IFNULL(#{item.luckyGiftAnchorShare}, 0),
|
|
||||||
IFNULL(#{item.gameTotalFlow}, 0),
|
IFNULL(#{item.gameTotalFlow}, 0),
|
||||||
IFNULL(#{item.gameUser}, 0),
|
IFNULL(#{item.gameUser}, 0),
|
||||||
IFNULL(#{item.gamePayout}, 0),
|
IFNULL(#{item.gamePayout}, 0),
|
||||||
IFNULL(#{item.d1RetentionUser}, 0),
|
|
||||||
IFNULL(#{item.d1RetentionBaseUser}, 0),
|
|
||||||
IFNULL(#{item.d7RetentionUser}, 0),
|
|
||||||
IFNULL(#{item.d7RetentionBaseUser}, 0),
|
|
||||||
IFNULL(#{item.d30RetentionUser}, 0),
|
|
||||||
IFNULL(#{item.d30RetentionBaseUser}, 0),
|
|
||||||
NOW()
|
NOW()
|
||||||
)
|
)
|
||||||
</foreach>
|
</foreach>
|
||||||
@ -1500,31 +1089,18 @@
|
|||||||
period_end_date = VALUES(period_end_date),
|
period_end_date = VALUES(period_end_date),
|
||||||
country_name = VALUES(country_name),
|
country_name = VALUES(country_name),
|
||||||
country_new_user = VALUES(country_new_user),
|
country_new_user = VALUES(country_new_user),
|
||||||
daily_active_user = VALUES(daily_active_user),
|
|
||||||
daily_recharge_user = VALUES(daily_recharge_user),
|
|
||||||
new_user_recharge = VALUES(new_user_recharge),
|
new_user_recharge = VALUES(new_user_recharge),
|
||||||
official_recharge = VALUES(official_recharge),
|
official_recharge = VALUES(official_recharge),
|
||||||
mifapay_recharge = VALUES(mifapay_recharge),
|
mifapay_recharge = VALUES(mifapay_recharge),
|
||||||
google_recharge = VALUES(google_recharge),
|
google_recharge = VALUES(google_recharge),
|
||||||
dealer_recharge = VALUES(dealer_recharge),
|
dealer_recharge = VALUES(dealer_recharge),
|
||||||
user_recharge = VALUES(user_recharge),
|
|
||||||
new_dealer_user_recharge = VALUES(new_dealer_user_recharge),
|
|
||||||
salary_exchange = VALUES(salary_exchange),
|
salary_exchange = VALUES(salary_exchange),
|
||||||
salary_transfer = VALUES(salary_transfer),
|
|
||||||
gift_consume = VALUES(gift_consume),
|
|
||||||
lucky_gift_total_flow = VALUES(lucky_gift_total_flow),
|
lucky_gift_total_flow = VALUES(lucky_gift_total_flow),
|
||||||
lucky_gift_user = VALUES(lucky_gift_user),
|
lucky_gift_user = VALUES(lucky_gift_user),
|
||||||
lucky_gift_payout = VALUES(lucky_gift_payout),
|
lucky_gift_payout = VALUES(lucky_gift_payout),
|
||||||
lucky_gift_anchor_share = VALUES(lucky_gift_anchor_share),
|
|
||||||
game_total_flow = VALUES(game_total_flow),
|
game_total_flow = VALUES(game_total_flow),
|
||||||
game_user = VALUES(game_user),
|
game_user = VALUES(game_user),
|
||||||
game_payout = VALUES(game_payout),
|
game_payout = VALUES(game_payout),
|
||||||
d1_retention_user = VALUES(d1_retention_user),
|
|
||||||
d1_retention_base_user = VALUES(d1_retention_base_user),
|
|
||||||
d7_retention_user = VALUES(d7_retention_user),
|
|
||||||
d7_retention_base_user = VALUES(d7_retention_base_user),
|
|
||||||
d30_retention_user = VALUES(d30_retention_user),
|
|
||||||
d30_retention_base_user = VALUES(d30_retention_base_user),
|
|
||||||
refreshed_at = NOW()
|
refreshed_at = NOW()
|
||||||
</insert>
|
</insert>
|
||||||
|
|
||||||
@ -1538,63 +1114,6 @@
|
|||||||
</if>
|
</if>
|
||||||
</delete>
|
</delete>
|
||||||
|
|
||||||
<insert id="upsertPeriodActiveRetentionMetrics">
|
|
||||||
INSERT INTO country_dashboard_period_metric (
|
|
||||||
period_type,
|
|
||||||
period_key,
|
|
||||||
stat_timezone,
|
|
||||||
period_name,
|
|
||||||
period_start_date,
|
|
||||||
period_end_date,
|
|
||||||
sys_origin,
|
|
||||||
country_code,
|
|
||||||
country_name,
|
|
||||||
daily_active_user,
|
|
||||||
d1_retention_user,
|
|
||||||
d1_retention_base_user,
|
|
||||||
d7_retention_user,
|
|
||||||
d7_retention_base_user,
|
|
||||||
d30_retention_user,
|
|
||||||
d30_retention_base_user,
|
|
||||||
refreshed_at
|
|
||||||
)
|
|
||||||
VALUES
|
|
||||||
<foreach collection="metrics" item="item" separator=",">
|
|
||||||
(
|
|
||||||
#{item.periodType},
|
|
||||||
#{item.periodKey},
|
|
||||||
#{item.statTimezone},
|
|
||||||
#{item.periodName},
|
|
||||||
#{item.periodStartDate},
|
|
||||||
#{item.periodEndDate},
|
|
||||||
#{item.sysOrigin},
|
|
||||||
#{item.countryCode},
|
|
||||||
#{item.countryName},
|
|
||||||
IFNULL(#{item.dailyActiveUser}, 0),
|
|
||||||
IFNULL(#{item.d1RetentionUser}, 0),
|
|
||||||
IFNULL(#{item.d1RetentionBaseUser}, 0),
|
|
||||||
IFNULL(#{item.d7RetentionUser}, 0),
|
|
||||||
IFNULL(#{item.d7RetentionBaseUser}, 0),
|
|
||||||
IFNULL(#{item.d30RetentionUser}, 0),
|
|
||||||
IFNULL(#{item.d30RetentionBaseUser}, 0),
|
|
||||||
NOW()
|
|
||||||
)
|
|
||||||
</foreach>
|
|
||||||
ON DUPLICATE KEY UPDATE
|
|
||||||
period_name = VALUES(period_name),
|
|
||||||
period_start_date = VALUES(period_start_date),
|
|
||||||
period_end_date = VALUES(period_end_date),
|
|
||||||
country_name = VALUES(country_name),
|
|
||||||
daily_active_user = VALUES(daily_active_user),
|
|
||||||
d1_retention_user = VALUES(d1_retention_user),
|
|
||||||
d1_retention_base_user = VALUES(d1_retention_base_user),
|
|
||||||
d7_retention_user = VALUES(d7_retention_user),
|
|
||||||
d7_retention_base_user = VALUES(d7_retention_base_user),
|
|
||||||
d30_retention_user = VALUES(d30_retention_user),
|
|
||||||
d30_retention_base_user = VALUES(d30_retention_base_user),
|
|
||||||
refreshed_at = NOW()
|
|
||||||
</insert>
|
|
||||||
|
|
||||||
<insert id="insertPeriodNewUserMetrics">
|
<insert id="insertPeriodNewUserMetrics">
|
||||||
INSERT IGNORE INTO country_dashboard_period_user_metric (
|
INSERT IGNORE INTO country_dashboard_period_user_metric (
|
||||||
period_type,
|
period_type,
|
||||||
@ -1756,7 +1275,6 @@
|
|||||||
t.period_key AS periodKey,
|
t.period_key AS periodKey,
|
||||||
MAX(t.period_name) AS periodName,
|
MAX(t.period_name) AS periodName,
|
||||||
SUM(CASE WHEN t.metric_type = 'COUNTRY_NEW_USER' THEN 1 ELSE 0 END) AS countryNewUser,
|
SUM(CASE WHEN t.metric_type = 'COUNTRY_NEW_USER' THEN 1 ELSE 0 END) AS countryNewUser,
|
||||||
SUM(CASE WHEN t.metric_type = 'RECHARGE_USER' THEN 1 ELSE 0 END) AS dailyRechargeUser,
|
|
||||||
SUM(CASE WHEN t.metric_type = 'LUCKY_GIFT_USER' THEN 1 ELSE 0 END) AS luckyGiftUser,
|
SUM(CASE WHEN t.metric_type = 'LUCKY_GIFT_USER' THEN 1 ELSE 0 END) AS luckyGiftUser,
|
||||||
SUM(CASE WHEN t.metric_type = 'GAME_USER' THEN 1 ELSE 0 END) AS gameUser
|
SUM(CASE WHEN t.metric_type = 'GAME_USER' THEN 1 ELSE 0 END) AS gameUser
|
||||||
FROM country_dashboard_period_user_metric t
|
FROM country_dashboard_period_user_metric t
|
||||||
@ -1776,30 +1294,16 @@
|
|||||||
MAX(t.country_name) AS countryName,
|
MAX(t.country_name) AS countryName,
|
||||||
'ALL' AS periodKey,
|
'ALL' AS periodKey,
|
||||||
'全部' AS periodName,
|
'全部' AS periodName,
|
||||||
IFNULL(SUM(t.country_new_user), 0) AS countryNewUser,
|
|
||||||
IFNULL(SUM(t.daily_active_user), 0) AS dailyActiveUser,
|
|
||||||
IFNULL(SUM(t.daily_recharge_user), 0) AS dailyRechargeUser,
|
|
||||||
IFNULL(SUM(t.new_user_recharge), 0) AS newUserRecharge,
|
IFNULL(SUM(t.new_user_recharge), 0) AS newUserRecharge,
|
||||||
IFNULL(SUM(t.official_recharge), 0) AS officialRecharge,
|
IFNULL(SUM(t.official_recharge), 0) AS officialRecharge,
|
||||||
IFNULL(SUM(t.mifapay_recharge), 0) AS mifapayRecharge,
|
IFNULL(SUM(t.mifapay_recharge), 0) AS mifapayRecharge,
|
||||||
IFNULL(SUM(t.google_recharge), 0) AS googleRecharge,
|
IFNULL(SUM(t.google_recharge), 0) AS googleRecharge,
|
||||||
IFNULL(SUM(t.dealer_recharge), 0) AS dealerRecharge,
|
IFNULL(SUM(t.dealer_recharge), 0) AS dealerRecharge,
|
||||||
IFNULL(SUM(t.user_recharge), 0) AS userRecharge,
|
|
||||||
IFNULL(SUM(t.new_dealer_user_recharge), 0) AS newDealerUserRecharge,
|
|
||||||
IFNULL(SUM(t.salary_exchange), 0) AS salaryExchange,
|
IFNULL(SUM(t.salary_exchange), 0) AS salaryExchange,
|
||||||
IFNULL(SUM(t.salary_transfer), 0) AS salaryTransfer,
|
|
||||||
IFNULL(SUM(t.gift_consume), 0) AS giftConsume,
|
|
||||||
IFNULL(SUM(t.lucky_gift_total_flow), 0) AS luckyGiftTotalFlow,
|
IFNULL(SUM(t.lucky_gift_total_flow), 0) AS luckyGiftTotalFlow,
|
||||||
IFNULL(SUM(t.lucky_gift_payout), 0) AS luckyGiftPayout,
|
IFNULL(SUM(t.lucky_gift_payout), 0) AS luckyGiftPayout,
|
||||||
IFNULL(SUM(t.lucky_gift_anchor_share), 0) AS luckyGiftAnchorShare,
|
|
||||||
IFNULL(SUM(t.game_total_flow), 0) AS gameTotalFlow,
|
IFNULL(SUM(t.game_total_flow), 0) AS gameTotalFlow,
|
||||||
IFNULL(SUM(t.game_payout), 0) AS gamePayout,
|
IFNULL(SUM(t.game_payout), 0) AS gamePayout
|
||||||
IFNULL(SUM(t.d1_retention_user), 0) AS d1RetentionUser,
|
|
||||||
IFNULL(SUM(t.d1_retention_base_user), 0) AS d1RetentionBaseUser,
|
|
||||||
IFNULL(SUM(t.d7_retention_user), 0) AS d7RetentionUser,
|
|
||||||
IFNULL(SUM(t.d7_retention_base_user), 0) AS d7RetentionBaseUser,
|
|
||||||
IFNULL(SUM(t.d30_retention_user), 0) AS d30RetentionUser,
|
|
||||||
IFNULL(SUM(t.d30_retention_base_user), 0) AS d30RetentionBaseUser
|
|
||||||
FROM country_dashboard_period_metric t
|
FROM country_dashboard_period_metric t
|
||||||
WHERE t.period_type = 'DAY'
|
WHERE t.period_type = 'DAY'
|
||||||
AND t.stat_timezone = #{statTimezone}
|
AND t.stat_timezone = #{statTimezone}
|
||||||
@ -1919,68 +1423,41 @@
|
|||||||
|
|
||||||
<select id="countRechargeDetails" resultType="java.lang.Long">
|
<select id="countRechargeDetails" resultType="java.lang.Long">
|
||||||
SELECT COUNT(1)
|
SELECT COUNT(1)
|
||||||
FROM country_dashboard_recharge_detail t
|
FROM (
|
||||||
|
<include refid="RechargeDetailSource"/>
|
||||||
|
) t
|
||||||
|
INNER JOIN user_base_info u ON u.id = t.userId
|
||||||
WHERE 1 = 1
|
WHERE 1 = 1
|
||||||
<if test="startTime != null">
|
<include refid="UserWhere"/>
|
||||||
AND t.create_time >= #{startTime}
|
<include refid="CountryCodesWhere"/>
|
||||||
</if>
|
|
||||||
<if test="endTime != null">
|
|
||||||
AND t.create_time < #{endTime}
|
|
||||||
</if>
|
|
||||||
<if test="countryKeyword != null and countryKeyword != ''">
|
|
||||||
AND (
|
|
||||||
t.country_code = #{countryKeyword}
|
|
||||||
OR t.country_name LIKE CONCAT('%', #{countryKeyword}, '%')
|
|
||||||
)
|
|
||||||
</if>
|
|
||||||
<if test="countryCodes != null and countryCodes != ''">
|
|
||||||
AND FIND_IN_SET(t.country_code, #{countryCodes})
|
|
||||||
</if>
|
|
||||||
<if test="sysOrigin != null and sysOrigin != ''">
|
|
||||||
AND t.sys_origin = #{sysOrigin}
|
|
||||||
</if>
|
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<select id="listRechargeDetails"
|
<select id="listRechargeDetails"
|
||||||
resultType="com.red.circle.console.infra.database.rds.dto.datav.CountryDashboardRechargeDetailDTO">
|
resultType="com.red.circle.console.infra.database.rds.dto.datav.CountryDashboardRechargeDetailDTO">
|
||||||
SELECT
|
SELECT
|
||||||
t.record_id AS recordId,
|
t.recordId,
|
||||||
t.source_type AS sourceType,
|
t.sourceType,
|
||||||
t.source_channel AS sourceChannel,
|
t.sourceChannel,
|
||||||
t.user_id AS userId,
|
t.userId,
|
||||||
u.account AS userAccount,
|
u.account AS userAccount,
|
||||||
u.user_nickname AS userNickname,
|
u.user_nickname AS userNickname,
|
||||||
t.country_code AS countryCode,
|
NULLIF(u.country_code, '') AS countryCode,
|
||||||
t.country_name AS countryName,
|
NULLIF(u.country_name, '') AS countryName,
|
||||||
t.amount,
|
t.amount,
|
||||||
t.coin_quantity AS coinQuantity,
|
t.coinQuantity,
|
||||||
t.remark,
|
t.remark,
|
||||||
DATE_FORMAT(
|
DATE_FORMAT(
|
||||||
CONVERT_TZ(t.create_time, #{storageTimezoneOffset}, #{statTimezoneOffset}),
|
CONVERT_TZ(t.createTime, #{storageTimezoneOffset}, #{statTimezoneOffset}),
|
||||||
'%Y-%m-%d %H:%i:%s'
|
'%Y-%m-%d %H:%i:%s'
|
||||||
) AS createTime
|
) AS createTime
|
||||||
FROM country_dashboard_recharge_detail t
|
FROM (
|
||||||
LEFT JOIN user_base_info u ON u.id = t.user_id
|
<include refid="RechargeDetailSource"/>
|
||||||
|
) t
|
||||||
|
INNER JOIN user_base_info u ON u.id = t.userId
|
||||||
WHERE 1 = 1
|
WHERE 1 = 1
|
||||||
<if test="startTime != null">
|
<include refid="UserWhere"/>
|
||||||
AND t.create_time >= #{startTime}
|
<include refid="CountryCodesWhere"/>
|
||||||
</if>
|
ORDER BY t.createTime DESC, t.recordId DESC
|
||||||
<if test="endTime != null">
|
|
||||||
AND t.create_time < #{endTime}
|
|
||||||
</if>
|
|
||||||
<if test="countryKeyword != null and countryKeyword != ''">
|
|
||||||
AND (
|
|
||||||
t.country_code = #{countryKeyword}
|
|
||||||
OR t.country_name LIKE CONCAT('%', #{countryKeyword}, '%')
|
|
||||||
)
|
|
||||||
</if>
|
|
||||||
<if test="countryCodes != null and countryCodes != ''">
|
|
||||||
AND FIND_IN_SET(t.country_code, #{countryCodes})
|
|
||||||
</if>
|
|
||||||
<if test="sysOrigin != null and sysOrigin != ''">
|
|
||||||
AND t.sys_origin = #{sysOrigin}
|
|
||||||
</if>
|
|
||||||
ORDER BY t.create_time DESC, t.record_id DESC
|
|
||||||
LIMIT #{limit} OFFSET #{offset}
|
LIMIT #{limit} OFFSET #{offset}
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
|||||||
@ -1,93 +0,0 @@
|
|||||||
# 国家数据大屏口径对账与修复计划
|
|
||||||
|
|
||||||
## 基准说明
|
|
||||||
|
|
||||||
- 对账日期:`2026-05-27`
|
|
||||||
- 统计时区:`Asia/Riyadh`
|
|
||||||
- 统计窗口:`2026-05-27 00:00:00` 到 `2026-05-28 00:00:00`
|
|
||||||
- 系统来源:`LIKEI`
|
|
||||||
- 对账方式:旧 Java 源表口径结果 vs 当前 `country_dashboard_*` 预聚合结果。
|
|
||||||
- 注意:日内数据会继续增长,金额和人数会随时间变化。本文中的“之前数据”来自本轮对账快照;后续修复验证必须重新跑同一窗口源表对账。
|
|
||||||
|
|
||||||
## 总体结论
|
|
||||||
|
|
||||||
当前大屏切到预聚合后,差异主要来自三类问题:
|
|
||||||
|
|
||||||
1. 旧 Java 是直接按 Mongo/SQL 源表字段聚合,CDC worker 有些字段改成了用户国家表、wallet 事件或部分表事件,口径没有完全复刻。
|
|
||||||
2. 部分 Mongo 源表没有进入 CDC:日活、礼物流水、幸运礼物、工资转移等需要单独的 reconcile/增量任务。
|
|
||||||
3. 留存基数与留存命中当前使用 worker 自己的用户国家表和活跃集合,和旧 Java 的注册 cohort + active log 口径不一致。
|
|
||||||
|
|
||||||
## 字段对账表
|
|
||||||
|
|
||||||
| 字段 | 旧 Java 口径 | 旧口径源表结果 | 当前预聚合结果 | 差异 | 差异原因 | 修复方案 | 状态 |
|
|
||||||
| --- | --- | ---: | ---: | ---: | --- | --- | --- |
|
|
||||||
| 新增 | 按 admin 用户列表展示口径统计 `user_base_info` 创建时间,展示日等于 `create_time + 8h` 后的日期;按用户国家归组。 | 之前用户列表显示约 57,部署期间增长到 60 | 修复前明显少算 | 修复前不稳定 | worker 原先按数据库原始时间截日,和 admin 用户列表展示日不一致。 | 已改 worker 的新用户统计窗口为 `create_time + 8h` 展示日;回填目标日期并重建 `DAY/ALL`。 | 已修 |
|
|
||||||
| 日活 | Mongo `user_daily_active_log`,按 `activeDate + sysOrigin` 过滤;先按 `registerCountryCode,userId` 去重,再按 `registerCountryCode` 计数。 | 984 | 844 | -140 | worker 原先读取 active log 后,又强依赖 `dashboard_cdc_user_country` 做国家归类,用户国家缺失或删除标记会把活跃用户过滤掉;旧 Java 不查用户国家表。 | 已改 worker:日活直接使用 active log 的 `sysOrigin/registerCountryCode`;只有 active log 国家为空才 fallback 用户国家表。 | 已修 |
|
|
||||||
| 新增充值 | 旧 Java 订单口径中,新注册用户在窗口内产生的充值。 | 2 | 2 | 0 | 当前已对齐。 | 保持现状;后续只做回归验证。 | 正常 |
|
|
||||||
| Google 充值 | Google 订单成功支付金额,按订单完成时间落入统计窗口。 | 63 | 63 | 0 | 当前已对齐。 | 保持现状;后续只做回归验证。 | 正常 |
|
|
||||||
| MifaPay 充值 | MifaPay 订单成功支付金额,按订单完成时间落入统计窗口。 | 0 | 0 | 0 | 当前已对齐。 | 保持现状;后续只做回归验证。 | 正常 |
|
|
||||||
| 币商充值 | 币商/代理充值流水,旧 Java 从币商充值相关 SQL 表聚合。 | 0 | 0 | 0 | 当前已对齐。 | 保持现状;后续只做回归验证。 | 正常 |
|
|
||||||
| 总充值 | Google + MifaPay + 币商等充值汇总。 | 63 | 63 | 0 | 当前已对齐。 | 保持现状;后续只做回归验证。 | 正常 |
|
|
||||||
| 工资兑换 | 旧 Java 包含 SQL 工资账户流水和 Mongo bank 流水中的工资兑换口径。 | 6.75 | 0 | -6.75 | worker 当前没有完整接入工资兑换相关 SQL/Mongo 流水。 | 增加工资兑换 reconcile:读取旧 Java 使用的 SQL 表和 Mongo `user_bank_running_water` 条件,按用户国家归组写 `salary_exchange`;补回填。 | 待修 |
|
|
||||||
| 工资转移 | 旧 Java 来自 Mongo `user_bank_running_water` 的工资转移口径。 | 38 | 0 | -38 | worker 当前未接入 Mongo bank 转移流水。 | 增加 Mongo bank reconcile:复刻旧 Java 的转移类型、状态、时间字段、金额单位,写 `salary_transfer`;补回填。 | 待修 |
|
|
||||||
| 礼物消耗 | Mongo `gift_give_running_water`;旧 Java 条件包含 `refunded != true`、`userId != null`、窗口内 `createTime`、指定 `sysOrigin`、`luckyGift != true`、`originId` 为数字、`dynamicContentId` 为空或不存在;金额取 `giftValue.actualAmount`。 | 7,276,368 | 3,327,288 | -3,949,080 | worker 当前没有完整复刻 Mongo `gift_give_running_water` 条件,可能只覆盖部分礼物事件或国家映射。 | 新增/修正 gift reconcile,直接按旧 Java Mongo 条件聚合普通礼物消耗,写 `gift_consume`;不要从 wallet `LUCKY_GIFT` 反推普通礼物。 | 待修 |
|
|
||||||
| 幸运礼物流水 | 旧 Java 从 `game_lucky_gift_count` 聚合幸运礼物总流水。 | 2,279,050 | 0 | -2,279,050 | `game_lucky_gift_count` 有源数据,但 worker/预聚合没有写入 `lucky_gift_total_flow`。 | 新增 lucky gift reconcile:按旧 Java 查询条件读取 `game_lucky_gift_count`,写 `lucky_gift_total_flow`,同时写用户去重表 `LUCKY_GIFT_USER`。 | 待修 |
|
|
||||||
| 幸运礼物人数 | 旧 Java 从 `game_lucky_gift_count` 按用户去重统计参与人数。 | 101 | 0 | -101 | 同幸运礼物流水,用户去重表未写。 | lucky gift reconcile 写 `country_dashboard_period_user_metric.metric_type='LUCKY_GIFT_USER'`,再重建汇总人数。 | 待修 |
|
|
||||||
| 幸运礼物返奖 | 旧 Java 从 `game_lucky_gift_count` 聚合返奖金额。 | 1,892,900 | 0 | -1,892,900 | 同幸运礼物流水,返奖字段未写。 | lucky gift reconcile 写 `lucky_gift_payout`。 | 待修 |
|
|
||||||
| 幸运礼物利润 | `幸运礼物流水 - 幸运礼物返奖`。 | 386,150 | 0 | -386,150 | 流水和返奖都缺失导致利润为 0。 | 修复幸运礼物流水和返奖后自动恢复;利润不应单独写源数据。 | 待修 |
|
|
||||||
| 游戏流水 | 旧 Java 从 `wallet_gold_asset_record_*` 和游戏统计表按游戏下注/消耗事件聚合。 | 109,688,935 | 74,509,547 | -35,179,388 | worker 当前游戏聚合少覆盖部分 `event_type` 或表来源,且用户去重也随之少算。 | 按旧 Java 的 game event_type 列表逐项核对,补齐 consume 事件映射;对每类事件做源表 vs 预聚合差异拆分。 | 待修 |
|
|
||||||
| 游戏人数 | 旧 Java 按游戏流水参与用户去重。 | 176 | 113 | -63 | 游戏流水事件少覆盖,导致用户去重同步少算。 | 游戏流水修复时同步写 `GAME_USER` 去重表;重建 `DAY/ALL`。 | 待修 |
|
|
||||||
| 游戏返奖 | 旧 Java 从游戏返奖/中奖事件聚合。 | 107,776,247 | 72,064,472 | -35,711,775 | worker 当前 payout 事件覆盖不完整,返奖少算幅度大于流水少算。 | 按旧 Java payout event_type 和 `game_lucky_box_count` 等来源补齐映射;验证 consume/payout 各自差值。 | 待修 |
|
|
||||||
| 游戏利润 | `游戏流水 - 游戏返奖`。 | 1,912,688 | 2,445,075 | +532,387 | 流水和返奖都少算,但返奖少算更多,所以利润虚高。 | 修复游戏流水和游戏返奖后重算;利润不单独写源数据。 | 待修 |
|
|
||||||
| 次日留存 | 旧 Java:注册 cohort 来自用户注册表;命中来自 Mongo `user_daily_active_log` 的目标活跃日期。 | 0 / 0 | 84 / 127 | +84 / +127 | 当前留存基数和命中口径与旧 Java 不一致,使用了 worker 用户国家表和当前 active 集合。 | 重写 retention reconcile:注册 cohort 复刻旧 Java `listNewUserCohorts`,活跃命中直接查 active log;按国家分别写 base/user。 | 待修 |
|
|
||||||
| 七日留存 | 同上,目标日期为注册日 + 7。 | 0 / 0 | 25 / 60 | +25 / +60 | 同次日留存。 | 同 retention reconcile,支持 D7。 | 待修 |
|
|
||||||
| 30 日留存 | 同上,目标日期为注册日 + 30。 | 0 / 0 | 5 / 7 | +5 / +7 | 同次日留存。 | 同 retention reconcile,支持 D30。 | 待修 |
|
|
||||||
|
|
||||||
## 已完成修复记录
|
|
||||||
|
|
||||||
### 新增
|
|
||||||
|
|
||||||
- 修改点:`dashboard-cdc-worker` 新增用户统计使用 admin 用户列表展示日,即 `create_time + 8h` 后的日期。
|
|
||||||
- 验证结果:`2026-05-27` 修复后源数据和预聚合从 57 增长到 60,增长来自部署期间新增的 3 个用户。
|
|
||||||
- 结论:新增已与用户列表显示口径对齐。
|
|
||||||
|
|
||||||
### 日活
|
|
||||||
|
|
||||||
- 修改点:`dashboard-cdc-worker/internal/storage/active_reconcile.go`
|
|
||||||
- 提交:`0b5e687 Align daily active metric with active log`
|
|
||||||
- 部署镜像:`dashboard-cdc-worker:daily-active-log-country-20260527-0b5e687`
|
|
||||||
- 验证结果:`2026-05-27`
|
|
||||||
- Mongo 旧 Java 口径:`1054`
|
|
||||||
- `country_dashboard_period_metric` 预聚合:`1054`
|
|
||||||
- 差值:`0`
|
|
||||||
- 结论:日活已与旧 Java active log 口径对齐。
|
|
||||||
|
|
||||||
## 后续修复顺序建议
|
|
||||||
|
|
||||||
1. 工资兑换、工资转移:影响字段少,数据源明确,先补 Mongo/SQL reconcile。
|
|
||||||
2. 礼物消耗:复刻 `gift_give_running_water` 条件,避免继续从 wallet 侧错误推导。
|
|
||||||
3. 幸运礼物:直接接 `game_lucky_gift_count`,同时写金额和人数去重。
|
|
||||||
4. 游戏流水、游戏返奖、游戏人数:按 event_type 拆分差异后逐类补齐。
|
|
||||||
5. 留存:最后统一重写,因为它依赖新增口径和日活口径都稳定。
|
|
||||||
|
|
||||||
## 每项修复后的验证模板
|
|
||||||
|
|
||||||
每修一个字段,都必须跑同一套对账:
|
|
||||||
|
|
||||||
```sql
|
|
||||||
-- 预聚合结果
|
|
||||||
SELECT
|
|
||||||
SUM(<metric_column>) AS precomputed_value
|
|
||||||
FROM country_dashboard_period_metric
|
|
||||||
WHERE period_type = 'DAY'
|
|
||||||
AND period_key = '2026-05-27'
|
|
||||||
AND stat_timezone = 'Asia/Riyadh'
|
|
||||||
AND sys_origin = 'LIKEI';
|
|
||||||
```
|
|
||||||
|
|
||||||
源表侧按旧 Java 条件单独查一遍,并输出:
|
|
||||||
|
|
||||||
| 字段 | 旧 Java 源表结果 | 预聚合结果 | 差值 | 是否通过 |
|
|
||||||
| --- | ---: | ---: | ---: | --- |
|
|
||||||
| 待验证字段 | 0 | 0 | 0 | 是/否 |
|
|
||||||
|
|
||||||
@ -1,7 +1,6 @@
|
|||||||
package com.red.circle.external.inner.endpoint.message;
|
package com.red.circle.external.inner.endpoint.message;
|
||||||
|
|
||||||
import com.red.circle.external.inner.endpoint.message.api.ImMessageClientApi;
|
import com.red.circle.external.inner.endpoint.message.api.ImMessageClientApi;
|
||||||
import com.red.circle.external.inner.model.cmd.message.CustomC2cMsgBodyCmd;
|
|
||||||
import com.red.circle.external.inner.service.message.ImMessageClientService;
|
import com.red.circle.external.inner.service.message.ImMessageClientService;
|
||||||
import com.red.circle.framework.dto.ResultResponse;
|
import com.red.circle.framework.dto.ResultResponse;
|
||||||
import com.red.circle.tool.core.parse.DataTypeUtils;
|
import com.red.circle.tool.core.parse.DataTypeUtils;
|
||||||
@ -37,10 +36,4 @@ public class ImMessageClientEndpoint implements ImMessageClientApi {
|
|||||||
return ResultResponse.success();
|
return ResultResponse.success();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public ResultResponse<Void> sendCustomMessage(CustomC2cMsgBodyCmd cmd) {
|
|
||||||
imMessageClientService.sendCustomMessage(cmd);
|
|
||||||
return ResultResponse.success();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,5 @@
|
|||||||
package com.red.circle.external.inner.service.message;
|
package com.red.circle.external.inner.service.message;
|
||||||
|
|
||||||
import com.red.circle.external.inner.model.cmd.message.CustomC2cMsgBodyCmd;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* im 消息服务.
|
* im 消息服务.
|
||||||
*
|
*
|
||||||
@ -14,9 +12,4 @@ public interface ImMessageClientService {
|
|||||||
*/
|
*/
|
||||||
void sendMessageText(String fromAccount, String toAccount, String text);
|
void sendMessageText(String fromAccount, String toAccount, String text);
|
||||||
|
|
||||||
/**
|
|
||||||
* 发送 C2C 自定义消息.
|
|
||||||
*/
|
|
||||||
void sendCustomMessage(CustomC2cMsgBodyCmd cmd);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,13 +1,7 @@
|
|||||||
package com.red.circle.external.inner.service.message.impl;
|
package com.red.circle.external.inner.service.message.impl;
|
||||||
|
|
||||||
import com.red.circle.component.instant.msg.tencet.service.endpoint.api.im.account.ImMessageManagerService;
|
import com.red.circle.component.instant.msg.tencet.service.endpoint.api.im.account.ImMessageManagerService;
|
||||||
import com.red.circle.component.instant.msg.tencet.service.param.ImMessageParam;
|
|
||||||
import com.red.circle.component.instant.msg.tencet.service.param.MessageBody;
|
|
||||||
import com.red.circle.component.instant.msg.tencet.service.param.OfflinePushInfo;
|
|
||||||
import com.red.circle.external.inner.model.cmd.message.CustomC2cMsgBodyCmd;
|
|
||||||
import com.red.circle.external.inner.service.message.ImMessageClientService;
|
import com.red.circle.external.inner.service.message.ImMessageClientService;
|
||||||
import com.red.circle.tool.core.num.NumUtils;
|
|
||||||
import com.red.circle.tool.core.parse.DataTypeUtils;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.log4j.Log4j2;
|
import lombok.extern.log4j.Log4j2;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
@ -29,21 +23,4 @@ public class ImMessageClientServiceImpl implements ImMessageClientService {
|
|||||||
imMessageManagerService.sendMessageText(fromAccount, toAccount, text).subscribe();
|
imMessageManagerService.sendMessageText(fromAccount, toAccount, text).subscribe();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void sendCustomMessage(CustomC2cMsgBodyCmd cmd) {
|
|
||||||
ImMessageParam param = ImMessageParam.builder()
|
|
||||||
.syncOtherMachine(cmd.getSyncOtherMachine())
|
|
||||||
.fromAccount(cmd.getFromAccount())
|
|
||||||
.toAccount(cmd.getToAccount())
|
|
||||||
.offlinePushInfo(OfflinePushInfo.builder()
|
|
||||||
.pushFlag(0)
|
|
||||||
.build())
|
|
||||||
.msgRandom(DataTypeUtils.toInteger(NumUtils.getRandomNumberString(9)))
|
|
||||||
.build()
|
|
||||||
.addMsgBody(MessageBody.customBody(cmd.getDesc(), cmd.getData()));
|
|
||||||
imMessageManagerService.sendMessage(param)
|
|
||||||
.subscribe(res -> log.warn("sendCustomMessage response result:{}", res),
|
|
||||||
res -> log.error("sendCustomMessage error cmd={}, result={}", cmd, res));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -109,7 +109,6 @@ public class AppInAppPurchaseCmdExe {
|
|||||||
.setSysOrigin(history.getSysOrigin())
|
.setSysOrigin(history.getSysOrigin())
|
||||||
.setPlatform(history.getPlatform())
|
.setPlatform(history.getPlatform())
|
||||||
.setPayPlatform(history.getPayPlatform())
|
.setPayPlatform(history.getPayPlatform())
|
||||||
.setAppVersion(reqAppVersion(cmd))
|
|
||||||
.setOrigin(appCommodity.getProductConfigProductId())
|
.setOrigin(appCommodity.getProductConfigProductId())
|
||||||
.setOriginName(appCommodity.getOriginDescription())
|
.setOriginName(appCommodity.getOriginDescription())
|
||||||
.setExpireDateMs(history.getExpiresDateMs())
|
.setExpireDateMs(history.getExpiresDateMs())
|
||||||
@ -169,11 +168,6 @@ public class AppInAppPurchaseCmdExe {
|
|||||||
return MonthlyRechargeType.UNDEFINED;
|
return MonthlyRechargeType.UNDEFINED;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String reqAppVersion(AbstractPurchaseCmd cmd) {
|
|
||||||
return Objects.nonNull(cmd.getReqAppIntel())
|
|
||||||
? Objects.toString(cmd.getReqAppIntel().getVersion(), "")
|
|
||||||
: "";
|
|
||||||
}
|
|
||||||
private void saveFriendshipRecord(AppCommodity appCommodity) {
|
private void saveFriendshipRecord(AppCommodity appCommodity) {
|
||||||
PurchaseHistory purchaseHistory = appCommodity.getPurchaseHistory();
|
PurchaseHistory purchaseHistory = appCommodity.getPurchaseHistory();
|
||||||
orderPurchaseFriendshipRecordService.save(
|
orderPurchaseFriendshipRecordService.save(
|
||||||
|
|||||||
@ -49,14 +49,6 @@ public class PayCountryAliasResolver {
|
|||||||
return getMappedUsablePayCountryByCountryId(countryId);
|
return getMappedUsablePayCountryByCountryId(countryId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public PayCountry resolvePayCountryByCountryId(Long countryId) {
|
|
||||||
PayCountry usablePayCountry = resolveUsablePayCountryByCountryId(countryId);
|
|
||||||
if (Objects.nonNull(usablePayCountry)) {
|
|
||||||
return usablePayCountry;
|
|
||||||
}
|
|
||||||
return getShelfPayCountryByCountryId(countryId);
|
|
||||||
}
|
|
||||||
|
|
||||||
private PayCountry getMappedUsablePayCountryByCountryId(Long countryId) {
|
private PayCountry getMappedUsablePayCountryByCountryId(Long countryId) {
|
||||||
SysCountryCodeDTO countryCode = getCountryCodeById(countryId);
|
SysCountryCodeDTO countryCode = getCountryCodeById(countryId);
|
||||||
if (Objects.isNull(countryCode)) {
|
if (Objects.isNull(countryCode)) {
|
||||||
@ -122,21 +114,6 @@ public class PayCountryAliasResolver {
|
|||||||
.orElse(null);
|
.orElse(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private PayCountry getShelfPayCountryByCountryId(Long countryId) {
|
|
||||||
if (Objects.isNull(countryId)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return payCountryService.query()
|
|
||||||
.eq(PayCountry::getShelf, Boolean.TRUE)
|
|
||||||
.eq(PayCountry::getCountryId, countryId)
|
|
||||||
.orderByDesc(PayCountry::getSort)
|
|
||||||
.list()
|
|
||||||
.stream()
|
|
||||||
.findFirst()
|
|
||||||
.orElse(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isUsablePayCountry(PayCountry payCountry) {
|
private boolean isUsablePayCountry(PayCountry payCountry) {
|
||||||
return Objects.nonNull(payCountry)
|
return Objects.nonNull(payCountry)
|
||||||
&& StringUtils.isNotBlank(payCountry.getCurrency())
|
&& StringUtils.isNotBlank(payCountry.getCurrency())
|
||||||
|
|||||||
@ -5,7 +5,6 @@ import com.google.api.client.util.Maps;
|
|||||||
import com.google.api.client.util.Sets;
|
import com.google.api.client.util.Sets;
|
||||||
import com.red.circle.common.business.core.amount.PayAmountArithmeticUtils;
|
import com.red.circle.common.business.core.amount.PayAmountArithmeticUtils;
|
||||||
import com.red.circle.common.business.core.enums.SysOriginPlatformEnum;
|
import com.red.circle.common.business.core.enums.SysOriginPlatformEnum;
|
||||||
import com.red.circle.common.business.core.util.CountryCodeAliasUtils;
|
|
||||||
import com.red.circle.framework.core.asserts.ResponseAssert;
|
import com.red.circle.framework.core.asserts.ResponseAssert;
|
||||||
import com.red.circle.framework.core.response.CommonErrorCode;
|
import com.red.circle.framework.core.response.CommonErrorCode;
|
||||||
import com.red.circle.order.app.convertor.PayAppConvertor;
|
import com.red.circle.order.app.convertor.PayAppConvertor;
|
||||||
@ -24,8 +23,6 @@ import com.red.circle.order.infra.database.rds.service.pay.PayApplicationCommodi
|
|||||||
import com.red.circle.order.infra.database.rds.service.pay.PayApplicationService;
|
import com.red.circle.order.infra.database.rds.service.pay.PayApplicationService;
|
||||||
import com.red.circle.order.infra.database.rds.service.pay.PayChannelService;
|
import com.red.circle.order.infra.database.rds.service.pay.PayChannelService;
|
||||||
import com.red.circle.order.infra.database.rds.service.pay.PayCountryChannelDetailsService;
|
import com.red.circle.order.infra.database.rds.service.pay.PayCountryChannelDetailsService;
|
||||||
import com.red.circle.other.inner.endpoint.sys.SysCountryCodeClient;
|
|
||||||
import com.red.circle.other.inner.model.dto.sys.SysCountryCodeDTO;
|
|
||||||
import com.red.circle.tool.core.collection.CollectionUtils;
|
import com.red.circle.tool.core.collection.CollectionUtils;
|
||||||
import com.red.circle.tool.core.num.ArithmeticUtils;
|
import com.red.circle.tool.core.num.ArithmeticUtils;
|
||||||
import com.red.circle.tool.core.text.StringUtils;
|
import com.red.circle.tool.core.text.StringUtils;
|
||||||
@ -57,7 +54,6 @@ public class PayWebApplicationCommodityV2QueryExe {
|
|||||||
private final PayCountryAliasResolver payCountryAliasResolver;
|
private final PayCountryAliasResolver payCountryAliasResolver;
|
||||||
private final PayApplicationCommodityService payApplicationCommodityService;
|
private final PayApplicationCommodityService payApplicationCommodityService;
|
||||||
private final PayCountryChannelDetailsService payCountryChannelDetailsService;
|
private final PayCountryChannelDetailsService payCountryChannelDetailsService;
|
||||||
private final SysCountryCodeClient sysCountryCodeClient;
|
|
||||||
|
|
||||||
public ApplicationCommodityCardV2CO execute(PayWebApplicationCommodityCmd cmd) {
|
public ApplicationCommodityCardV2CO execute(PayWebApplicationCommodityCmd cmd) {
|
||||||
|
|
||||||
@ -76,20 +72,6 @@ public class PayWebApplicationCommodityV2QueryExe {
|
|||||||
.setApplication(application);
|
.setApplication(application);
|
||||||
}
|
}
|
||||||
|
|
||||||
// LIKEI/Yumi 的 H5 支付方式由本地 JSON 控制,商品接口只负责按后台商品配置返回商品。
|
|
||||||
// 如果这里继续依赖支付国家渠道详情,JSON 已配置但后端渠道未上架时会把商品误过滤为空。
|
|
||||||
List<PayApplicationCommodityCO> commodity = toCommodityCO(payCountry,
|
|
||||||
payApplicationCommodities);
|
|
||||||
if (CollectionUtils.isEmpty(commodity)) {
|
|
||||||
return new ApplicationCommodityCardV2CO()
|
|
||||||
.setApplication(application);
|
|
||||||
}
|
|
||||||
if (isJsonControlledPayment(cmd)) {
|
|
||||||
return new ApplicationCommodityCardV2CO()
|
|
||||||
.setApplication(application)
|
|
||||||
.setCommodity(commodity);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 所有支持的渠道
|
// 所有支持的渠道
|
||||||
List<PayCountryChannelDetails> countryChannelDetails = payCountryChannelDetailsService
|
List<PayCountryChannelDetails> countryChannelDetails = payCountryChannelDetailsService
|
||||||
.listChannelCode(cmd.getPayCountryId());
|
.listChannelCode(cmd.getPayCountryId());
|
||||||
@ -99,6 +81,15 @@ public class PayWebApplicationCommodityV2QueryExe {
|
|||||||
.setApplication(application);
|
.setApplication(application);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 商品
|
||||||
|
List<PayApplicationCommodityCO> commodity = toCommodityCO(payCountry,
|
||||||
|
payApplicationCommodities);
|
||||||
|
|
||||||
|
if (CollectionUtils.isEmpty(commodity)) {
|
||||||
|
return new ApplicationCommodityCardV2CO()
|
||||||
|
.setApplication(application);
|
||||||
|
}
|
||||||
|
|
||||||
// 过滤渠道限额范围
|
// 过滤渠道限额范围
|
||||||
countryChannelDetails = filterCountryChannelLimit(countryChannelDetails, commodity);
|
countryChannelDetails = filterCountryChannelLimit(countryChannelDetails, commodity);
|
||||||
|
|
||||||
@ -125,10 +116,8 @@ public class PayWebApplicationCommodityV2QueryExe {
|
|||||||
private List<PayApplicationCommodity> getPayApplicationCommodities(
|
private List<PayApplicationCommodity> getPayApplicationCommodities(
|
||||||
PayWebApplicationCommodityCmd cmd) {
|
PayWebApplicationCommodityCmd cmd) {
|
||||||
|
|
||||||
// Yumi/LIKEI H5 已经先按用户资料拿到国家,商品应按国家查;regionId 只保留给旧的区域商品链路.
|
|
||||||
if (Objects.equals(cmd.requireReqSysOriginChildEnum(), SysOriginPlatformEnum.YOLO)
|
if (Objects.equals(cmd.requireReqSysOriginChildEnum(), SysOriginPlatformEnum.YOLO)
|
||||||
|| (StringUtils.isNotBlank(cmd.getRegionId())
|
|| StringUtils.isNotBlank(cmd.getRegionId())) {
|
||||||
&& StringUtils.isBlank(cmd.getCountryCode()))) {
|
|
||||||
|
|
||||||
ResponseAssert
|
ResponseAssert
|
||||||
.isTrue(CommonErrorCode.NOT_SUPPORTED_REGION, StringUtils.isNotBlank(cmd.getRegionId()));
|
.isTrue(CommonErrorCode.NOT_SUPPORTED_REGION, StringUtils.isNotBlank(cmd.getRegionId()));
|
||||||
@ -143,10 +132,6 @@ public class PayWebApplicationCommodityV2QueryExe {
|
|||||||
cmd.getType(), null);
|
cmd.getType(), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isJsonControlledPayment(PayWebApplicationCommodityCmd cmd) {
|
|
||||||
return Objects.equals(cmd.requireReqSysOriginChildEnum(), SysOriginPlatformEnum.LIKEI);
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<PayCountryChannelDetails> filterCountryChannelLimit(
|
private List<PayCountryChannelDetails> filterCountryChannelLimit(
|
||||||
List<PayCountryChannelDetails> countryChannelDetails,
|
List<PayCountryChannelDetails> countryChannelDetails,
|
||||||
List<PayApplicationCommodityCO> commodity) {
|
List<PayApplicationCommodityCO> commodity) {
|
||||||
@ -180,17 +165,7 @@ public class PayWebApplicationCommodityV2QueryExe {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private PayCountry getPayCountry(PayWebApplicationCommodityCmd cmd) {
|
private PayCountry getPayCountry(PayWebApplicationCommodityCmd cmd) {
|
||||||
if (Objects.nonNull(cmd.getPayCountryId()) || StringUtils.isBlank(cmd.getCountryCode())) {
|
return payCountryAliasResolver.resolveUsablePayCountry(cmd.getPayCountryId());
|
||||||
return payCountryAliasResolver.resolveUsablePayCountry(cmd.getPayCountryId());
|
|
||||||
}
|
|
||||||
|
|
||||||
String normalizedCountryCode = CountryCodeAliasUtils.normalizePaymentCountryCode(
|
|
||||||
cmd.getCountryCode());
|
|
||||||
SysCountryCodeDTO countryCode = ResponseAssert.requiredSuccess(
|
|
||||||
sysCountryCodeClient.getByCode(normalizedCountryCode));
|
|
||||||
ResponseAssert.notNull(CommonErrorCode.NOT_SUPPORTED_REGION, countryCode);
|
|
||||||
// H5 只传用户国家码;这里仅把真实国家转成商品表使用的支付国家ID,是否开放支付国家由 H5 JSON 控制.
|
|
||||||
return payCountryAliasResolver.resolvePayCountryByCountryId(countryCode.getId());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<PayChannelDetailsCO> getPayChannels(List<PayChannel> payChannels,
|
private List<PayChannelDetailsCO> getPayChannels(List<PayChannel> payChannels,
|
||||||
|
|||||||
@ -26,10 +26,8 @@ public class PayWebOrderStatusQueryExe {
|
|||||||
public PayOrderStatusCO execute(PayOrderStatusCmd cmd) {
|
public PayOrderStatusCO execute(PayOrderStatusCmd cmd) {
|
||||||
OrderUserPurchasePay mysqlOrder = getMysqlOrder(cmd.getOrderId());
|
OrderUserPurchasePay mysqlOrder = getMysqlOrder(cmd.getOrderId());
|
||||||
ResponseAssert.notNull(OrderErrorCode.NO_PURCHASE_RECORD_FOUND, mysqlOrder);
|
ResponseAssert.notNull(OrderErrorCode.NO_PURCHASE_RECORD_FOUND, mysqlOrder);
|
||||||
Long expectedUserId = Objects.nonNull(cmd.getReqUserId()) ? cmd.getReqUserId() : cmd.getUserId();
|
|
||||||
// 登录态请求继续使用网关注入的 reqUserId;公开 H5 轮询没有登录态,只允许用下单用户ID校验同一笔订单.
|
|
||||||
ResponseAssert.isTrue(OrderErrorCode.NO_PURCHASE_RECORD_FOUND,
|
ResponseAssert.isTrue(OrderErrorCode.NO_PURCHASE_RECORD_FOUND,
|
||||||
Objects.nonNull(expectedUserId) && Objects.equals(mysqlOrder.getUserId(), expectedUserId));
|
Objects.equals(mysqlOrder.getUserId(), cmd.getReqUserId()));
|
||||||
InAppPurchaseStatus status = MiFaPayMysqlOrderSupport
|
InAppPurchaseStatus status = MiFaPayMysqlOrderSupport
|
||||||
.toInAppPurchaseStatus(mysqlOrder.getPayStatus());
|
.toInAppPurchaseStatus(mysqlOrder.getPayStatus());
|
||||||
return new PayOrderStatusCO()
|
return new PayOrderStatusCO()
|
||||||
|
|||||||
@ -121,7 +121,6 @@ public class PayWebPlaceAnOrderCmdExe {
|
|||||||
+ "&appType=" + commodity.getType());
|
+ "&appType=" + commodity.getType());
|
||||||
details.setCancelRedirectUrl(details.getRechargeUrl());
|
details.setCancelRedirectUrl(details.getRechargeUrl());
|
||||||
details.setNewVersion(cmd.getNewVersion());
|
details.setNewVersion(cmd.getNewVersion());
|
||||||
details.setAppVersion(cmd.getAppVersion());
|
|
||||||
details.setRequestIp(IpUtils.getIpAddr());
|
details.setRequestIp(IpUtils.getIpAddr());
|
||||||
|
|
||||||
// 记录充值金额
|
// 记录充值金额
|
||||||
|
|||||||
@ -18,11 +18,13 @@ import com.red.circle.tool.core.regex.RegexConstant;
|
|||||||
import com.red.circle.tool.core.text.StringUtils;
|
import com.red.circle.tool.core.text.StringUtils;
|
||||||
import com.red.circle.other.inner.asserts.user.UserErrorCode;
|
import com.red.circle.other.inner.asserts.user.UserErrorCode;
|
||||||
import com.red.circle.other.inner.model.dto.user.UserProfileDTO;
|
import com.red.circle.other.inner.model.dto.user.UserProfileDTO;
|
||||||
|
import com.red.circle.other.inner.model.dto.user.reigon.RegionRelationDTO;
|
||||||
|
import com.red.circle.other.inner.enums.user.RegionRelationGroupEnum;
|
||||||
|
import com.red.circle.other.inner.endpoint.user.region.RegionRelationClient;
|
||||||
import com.red.circle.other.inner.endpoint.user.region.UserRegionClient;
|
import com.red.circle.other.inner.endpoint.user.region.UserRegionClient;
|
||||||
import com.red.circle.other.inner.endpoint.user.user.UserProfileClient;
|
import com.red.circle.other.inner.endpoint.user.user.UserProfileClient;
|
||||||
import com.red.circle.wallet.inner.endpoint.freight.FreightGoldClient;
|
import com.red.circle.wallet.inner.endpoint.freight.FreightGoldClient;
|
||||||
import java.util.AbstractMap;
|
import java.util.AbstractMap;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
@ -45,6 +47,7 @@ public class UserProfileAndCountryQueryExe {
|
|||||||
private final PayCountryAliasResolver payCountryAliasResolver;
|
private final PayCountryAliasResolver payCountryAliasResolver;
|
||||||
private final UserProfileClient userProfileClient;
|
private final UserProfileClient userProfileClient;
|
||||||
private final SysCountryCodeClient sysCountryCodeClient;
|
private final SysCountryCodeClient sysCountryCodeClient;
|
||||||
|
private final RegionRelationClient regionRelationClient;
|
||||||
|
|
||||||
public UserProfileAndCountryCO execute(PayWebUserCmd cmd) {
|
public UserProfileAndCountryCO execute(PayWebUserCmd cmd) {
|
||||||
|
|
||||||
@ -61,15 +64,25 @@ public class UserProfileAndCountryQueryExe {
|
|||||||
.toWebSiteUseProfileCO(userProfile);
|
.toWebSiteUseProfileCO(userProfile);
|
||||||
webSiteUseProfile.setAccount(userProfile.actualAccount());
|
webSiteUseProfile.setAccount(userProfile.actualAccount());
|
||||||
|
|
||||||
|
List<PayCountry> payCountryList;
|
||||||
|
|
||||||
String regionId = ResponseAssert.requiredSuccess(
|
String regionId = ResponseAssert.requiredSuccess(
|
||||||
userRegionClient.getRegionId(userProfile.getId())
|
userRegionClient.getRegionId(userProfile.getId())
|
||||||
);
|
);
|
||||||
|
|
||||||
if (Objects.equals(cmd.getSysOrigin(), SysOriginPlatformEnum.LIKEI.name())) {
|
if (Objects.equals(cmd.getSysOrigin(), SysOriginPlatformEnum.LIKEI.name())) {
|
||||||
return toLikeiUserCountryResult(userProfile, webSiteUseProfile, regionId);
|
ResponseAssert.isTrue(CommonErrorCode.NOT_SUPPORTED_REGION, StringUtils.isNotBlank(regionId));
|
||||||
|
|
||||||
|
List<RegionRelationDTO> regionRelationList = getRegionRelationList(userProfile, regionId);
|
||||||
|
ResponseAssert.notEmpty(CommonErrorCode.NOT_SUPPORTED_REGION, regionRelationList);
|
||||||
|
|
||||||
|
payCountryList = getPayCountryList(regionRelationList);
|
||||||
|
ResponseAssert.notEmpty(CommonErrorCode.NOT_SUPPORTED_REGION, payCountryList);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
payCountryList = payCountryService.listAllShelf();
|
||||||
}
|
}
|
||||||
|
|
||||||
List<PayCountry> payCountryList = payCountryService.listAllShelf();
|
|
||||||
Map<Long, SysCountryCodeDTO> mapCountryCode = getMapCountryCode(payCountryList);
|
Map<Long, SysCountryCodeDTO> mapCountryCode = getMapCountryCode(payCountryList);
|
||||||
ResponseAssert.notEmpty(CommonErrorCode.NOT_SUPPORTED_REGION, mapCountryCode);
|
ResponseAssert.notEmpty(CommonErrorCode.NOT_SUPPORTED_REGION, mapCountryCode);
|
||||||
Map<Long, PayCountry> compatiblePayCountryMap = getCompatiblePayCountryMap(payCountryList);
|
Map<Long, PayCountry> compatiblePayCountryMap = getCompatiblePayCountryMap(payCountryList);
|
||||||
@ -96,57 +109,6 @@ public class UserProfileAndCountryQueryExe {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private UserProfileAndCountryCO toLikeiUserCountryResult(UserProfileDTO userProfile,
|
|
||||||
WebSiteUseProfileCO webSiteUseProfile, String regionId) {
|
|
||||||
|
|
||||||
SysCountryCodeDTO countryCode = getUserCountryCode(userProfile);
|
|
||||||
ResponseAssert.notNull(CommonErrorCode.NOT_SUPPORTED_REGION, countryCode);
|
|
||||||
|
|
||||||
PayCountry compatiblePayCountry = payCountryAliasResolver
|
|
||||||
.resolvePayCountryByCountryId(countryCode.getId());
|
|
||||||
boolean freightUser = existsFreightBalance(userProfile.getId());
|
|
||||||
webSiteUseProfile
|
|
||||||
.setFreightUser(freightUser)
|
|
||||||
// Yumi H5 先确认用户身份,再用这里返回的商品类型查询后台商品,避免币商误买普通金币商品后入普通金币账户.
|
|
||||||
.setCommodityType(freightUser ? PayApplicationCommodityType.FREIGHT_GOLD.name()
|
|
||||||
: PayApplicationCommodityType.GOLD.name());
|
|
||||||
|
|
||||||
// LIKEI/Yumi 的支付国家开放由 H5 JSON 控制;这里仅返回用户真实国家,商品接口再按国家码查该国商品.
|
|
||||||
PayCountryCO payCountryCO = new PayCountryCO()
|
|
||||||
.setId(Objects.nonNull(compatiblePayCountry) ? compatiblePayCountry.getId() : null)
|
|
||||||
.setPayCountryId(Objects.nonNull(compatiblePayCountry) ? compatiblePayCountry.getId() : null)
|
|
||||||
.setCountryId(countryCode.getId())
|
|
||||||
.setCurrency(Objects.nonNull(compatiblePayCountry) ? compatiblePayCountry.getCurrency() : null)
|
|
||||||
.setCountry(countryCode);
|
|
||||||
|
|
||||||
return new UserProfileAndCountryCO()
|
|
||||||
.setCountryList(Collections.singletonList(payCountryCO))
|
|
||||||
.setUserProfile(webSiteUseProfile)
|
|
||||||
.setRegionId(regionId);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean existsFreightBalance(Long userId) {
|
|
||||||
return Boolean.TRUE.equals(ResponseAssert.requiredSuccess(
|
|
||||||
freightGoldClient.existsBalance(userId)
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
private SysCountryCodeDTO getUserCountryCode(UserProfileDTO userProfile) {
|
|
||||||
if (Objects.nonNull(userProfile.getCountryId())) {
|
|
||||||
return ResponseAssert.requiredSuccess(
|
|
||||||
sysCountryCodeClient.getById(userProfile.getCountryId())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (StringUtils.isNotBlank(userProfile.getCountryCode())) {
|
|
||||||
return ResponseAssert.requiredSuccess(
|
|
||||||
sysCountryCodeClient.getByCode(userProfile.getCountryCode())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private UserProfileDTO getUserProfile(PayWebUserCmd cmd) {
|
private UserProfileDTO getUserProfile(PayWebUserCmd cmd) {
|
||||||
if (StringUtils.isNotBlank(cmd.getAccount()) && StringUtils.isNotBlank(cmd.getSysOrigin())) {
|
if (StringUtils.isNotBlank(cmd.getAccount()) && StringUtils.isNotBlank(cmd.getSysOrigin())) {
|
||||||
return ResponseAssert.requiredSuccess(
|
return ResponseAssert.requiredSuccess(
|
||||||
@ -184,4 +146,18 @@ public class UserProfileAndCountryQueryExe {
|
|||||||
(left, right) -> left));
|
(left, right) -> left));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<RegionRelationDTO> getRegionRelationList(UserProfileDTO userProfile,
|
||||||
|
String regionId) {
|
||||||
|
return ResponseAssert.requiredSuccess(
|
||||||
|
regionRelationClient
|
||||||
|
.listByRegionId(regionId, userProfile.getOriginSys(),
|
||||||
|
RegionRelationGroupEnum.OPEN_PAY_COUNTRY)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<PayCountry> getPayCountryList(List<RegionRelationDTO> regionRelationList) {
|
||||||
|
return payCountryService
|
||||||
|
.listByIds(regionRelationList.stream().map(RegionRelationDTO::getRelationId).collect(
|
||||||
|
Collectors.toSet()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -115,10 +115,6 @@ public class PayPlaceAnOrderDetailsV2 implements Serializable {
|
|||||||
*/
|
*/
|
||||||
private Boolean newVersion;
|
private Boolean newVersion;
|
||||||
|
|
||||||
/**
|
|
||||||
* 本次充值请求的App版本.
|
|
||||||
*/
|
|
||||||
private String appVersion;
|
|
||||||
/**
|
/**
|
||||||
* 请求ip信息.
|
* 请求ip信息.
|
||||||
*/
|
*/
|
||||||
@ -160,7 +156,6 @@ public class PayPlaceAnOrderDetailsV2 implements Serializable {
|
|||||||
.put("countryCode", this.getCountryCode())
|
.put("countryCode", this.getCountryCode())
|
||||||
.put("amount", this.getAmount().toString())
|
.put("amount", this.getAmount().toString())
|
||||||
.put("currency", this.getCurrency())
|
.put("currency", this.getCurrency())
|
||||||
.put("appVersion", Objects.toString(this.getAppVersion(), ""))
|
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
package com.red.circle.order.app.command.pay.web.strategy;
|
package com.red.circle.order.app.command.pay.web.strategy;
|
||||||
|
|
||||||
|
import com.google.api.client.util.Maps;
|
||||||
import com.red.circle.component.pay.paymax.PayMaxUtils;
|
import com.red.circle.component.pay.paymax.PayMaxUtils;
|
||||||
import com.red.circle.framework.core.request.RequestClientEnum;
|
import com.red.circle.framework.core.request.RequestClientEnum;
|
||||||
import com.red.circle.framework.web.props.EnvProperties;
|
import com.red.circle.framework.web.props.EnvProperties;
|
||||||
@ -20,13 +21,8 @@ import com.red.circle.tool.core.date.TimestampUtils;
|
|||||||
import com.red.circle.tool.core.http.RcHttpClient;
|
import com.red.circle.tool.core.http.RcHttpClient;
|
||||||
import com.red.circle.tool.core.json.JacksonUtils;
|
import com.red.circle.tool.core.json.JacksonUtils;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Optional;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
@ -108,7 +104,7 @@ public class PayPlaceAnOrderService {
|
|||||||
.setNoticeData(response.extra())
|
.setNoticeData(response.extra())
|
||||||
.setCreateTime(TimestampUtils.now())
|
.setCreateTime(TimestampUtils.now())
|
||||||
))
|
))
|
||||||
.setMetadata(param.createMetadata())
|
.setMetadata(Maps.newHashMap())
|
||||||
.setVersion(0)
|
.setVersion(0)
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -126,27 +122,6 @@ public class PayPlaceAnOrderService {
|
|||||||
* @return 汇率值
|
* @return 汇率值
|
||||||
*/
|
*/
|
||||||
public BigDecimal getRealTimeExchangeRate(String baseCurrency, String targetCurrency) {
|
public BigDecimal getRealTimeExchangeRate(String baseCurrency, String targetCurrency) {
|
||||||
return getRealTimeExchangeRates(baseCurrency, List.of(targetCurrency)).get(targetCurrency);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<String, BigDecimal> getRealTimeExchangeRates(String baseCurrency,
|
|
||||||
Collection<String> targetCurrencies) {
|
|
||||||
Map<String, BigDecimal> result = new HashMap<>();
|
|
||||||
Optional.ofNullable(targetCurrencies).orElseGet(List::of).stream()
|
|
||||||
.filter(Objects::nonNull)
|
|
||||||
.map(String::trim)
|
|
||||||
.filter(currency -> !currency.isEmpty())
|
|
||||||
.distinct()
|
|
||||||
.forEach(targetCurrency -> {
|
|
||||||
BigDecimal rate = queryRealTimeExchangeRate(baseCurrency, targetCurrency);
|
|
||||||
if (Objects.nonNull(rate)) {
|
|
||||||
result.put(targetCurrency, rate);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private BigDecimal queryRealTimeExchangeRate(String baseCurrency, String targetCurrency) {
|
|
||||||
try {
|
try {
|
||||||
QuoteQueryParam param = new QuoteQueryParam();
|
QuoteQueryParam param = new QuoteQueryParam();
|
||||||
QuoteQueryParam.QuoteQueryData data = new QuoteQueryParam.QuoteQueryData();
|
QuoteQueryParam.QuoteQueryData data = new QuoteQueryParam.QuoteQueryData();
|
||||||
|
|||||||
@ -9,7 +9,6 @@ import com.red.circle.framework.core.response.CommonErrorCode;
|
|||||||
import com.red.circle.framework.dto.ResultResponse;
|
import com.red.circle.framework.dto.ResultResponse;
|
||||||
import com.red.circle.framework.web.props.EnvProperties;
|
import com.red.circle.framework.web.props.EnvProperties;
|
||||||
import com.red.circle.mq.business.model.event.pay.BuySuccessEvent;
|
import com.red.circle.mq.business.model.event.pay.BuySuccessEvent;
|
||||||
import com.red.circle.order.app.common.task.RechargeSuccessEventPublisher;
|
|
||||||
import com.red.circle.order.app.command.pay.web.strategy.PayEnv;
|
import com.red.circle.order.app.command.pay.web.strategy.PayEnv;
|
||||||
import com.red.circle.order.domain.gateway.UserRechargeCountGateway;
|
import com.red.circle.order.domain.gateway.UserRechargeCountGateway;
|
||||||
import com.red.circle.order.infra.database.mongo.order.InAppPurchaseCollectionReceiptService;
|
import com.red.circle.order.infra.database.mongo.order.InAppPurchaseCollectionReceiptService;
|
||||||
@ -80,7 +79,6 @@ public class InAppPurchaseCommon {
|
|||||||
private final PropsActivityClient propsActivityClient;
|
private final PropsActivityClient propsActivityClient;
|
||||||
private final UserOneTimeTaskClient userOneTimeTaskClient;
|
private final UserOneTimeTaskClient userOneTimeTaskClient;
|
||||||
private final UserProfileClient userProfileClient;
|
private final UserProfileClient userProfileClient;
|
||||||
private final RechargeSuccessEventPublisher rechargeSuccessEventPublisher;
|
|
||||||
|
|
||||||
public void inAppPurchaseReceipt(InAppPurchaseDetails order) {
|
public void inAppPurchaseReceipt(InAppPurchaseDetails order) {
|
||||||
inAppPurchaseReceipt(order,
|
inAppPurchaseReceipt(order,
|
||||||
@ -198,8 +196,6 @@ public class InAppPurchaseCommon {
|
|||||||
inviteUserClient.processRechargeCommission(amount,
|
inviteUserClient.processRechargeCommission(amount,
|
||||||
order.getSysOrigin(), order.getAcceptUserId());
|
order.getSysOrigin(), order.getAcceptUserId());
|
||||||
|
|
||||||
rechargeSuccessEventPublisher.reportPaymentRecharge(order);
|
|
||||||
|
|
||||||
// 发送首充奖励
|
// 发送首充奖励
|
||||||
completedFirstCharge(order.getAcceptUserId(), order.getSysOrigin());
|
completedFirstCharge(order.getAcceptUserId(), order.getSysOrigin());
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,9 +15,7 @@ import java.math.BigDecimal;
|
|||||||
import java.math.RoundingMode;
|
import java.math.RoundingMode;
|
||||||
import java.sql.Timestamp;
|
import java.sql.Timestamp;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -63,7 +61,6 @@ public final class MiFaPayMysqlOrderSupport {
|
|||||||
.setFactoryCode(param.getFactoryCode())
|
.setFactoryCode(param.getFactoryCode())
|
||||||
.setFactoryOrderId(Objects.toString(response.getTradeNo(), ""))
|
.setFactoryOrderId(Objects.toString(response.getTradeNo(), ""))
|
||||||
.setReferenceId(Objects.toString(param.getApplicationId(), ""))
|
.setReferenceId(Objects.toString(param.getApplicationId(), ""))
|
||||||
.setAppVersion(Objects.toString(param.getAppVersion(), ""))
|
|
||||||
.setReceiptType(Objects.toString(param.getReceiptType(),
|
.setReceiptType(Objects.toString(param.getReceiptType(),
|
||||||
InAppPurchaseReceiptType.PAYMENT.name()))
|
InAppPurchaseReceiptType.PAYMENT.name()))
|
||||||
.setPaymentChannel(Objects.toString(param.getChannelCode(), ""))
|
.setPaymentChannel(Objects.toString(param.getChannelCode(), ""))
|
||||||
@ -124,8 +121,7 @@ public final class MiFaPayMysqlOrderSupport {
|
|||||||
.setReason(order.getReason())
|
.setReason(order.getReason())
|
||||||
.setCreateTime(order.getCreateTime())
|
.setCreateTime(order.getCreateTime())
|
||||||
.setUpdateTime(order.getUpdateTime())
|
.setUpdateTime(order.getUpdateTime())
|
||||||
.setCreateUser(order.getCreateUser())
|
.setCreateUser(order.getCreateUser());
|
||||||
.setMetadata(metadata(order));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static InAppPurchaseStatus toInAppPurchaseStatus(String payStatus) {
|
public static InAppPurchaseStatus toInAppPurchaseStatus(String payStatus) {
|
||||||
@ -166,14 +162,6 @@ public final class MiFaPayMysqlOrderSupport {
|
|||||||
return InAppPurchaseReceiptType.PAYMENT;
|
return InAppPurchaseReceiptType.PAYMENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Map<String, String> metadata(OrderUserPurchasePay order) {
|
|
||||||
Map<String, String> metadata = new HashMap<>();
|
|
||||||
if (StringUtils.isNotBlank(order.getAppVersion())) {
|
|
||||||
metadata.put("appVersion", order.getAppVersion());
|
|
||||||
}
|
|
||||||
return metadata;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static BigDecimal defaultDecimal(BigDecimal value) {
|
private static BigDecimal defaultDecimal(BigDecimal value) {
|
||||||
return value != null ? value : BigDecimal.ZERO;
|
return value != null ? value : BigDecimal.ZERO;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,242 +0,0 @@
|
|||||||
package com.red.circle.order.app.common.task;
|
|
||||||
|
|
||||||
import com.red.circle.component.mq.MessageEvent;
|
|
||||||
import com.red.circle.mq.business.model.event.pay.BuySuccessEvent;
|
|
||||||
import com.red.circle.mq.business.model.event.pay.RechargeSuccessEvent;
|
|
||||||
import com.red.circle.mq.rocket.business.service.MessageSenderService;
|
|
||||||
import com.red.circle.mq.rocket.business.streams.RechargeSuccessSink;
|
|
||||||
import com.red.circle.order.infra.database.mongo.order.entity.InAppPurchaseDetails;
|
|
||||||
import com.red.circle.order.infra.database.mongo.order.entity.assist.InAppPurchaseProduct;
|
|
||||||
import com.red.circle.order.inner.model.enums.PayApplicationCommodityType;
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.math.RoundingMode;
|
|
||||||
import java.sql.Timestamp;
|
|
||||||
import java.time.Instant;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Objects;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.beans.factory.ObjectProvider;
|
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
@Component
|
|
||||||
public class RechargeSuccessEventPublisher {
|
|
||||||
|
|
||||||
private static final String GOOGLE = "GOOGLE";
|
|
||||||
private static final String APPLE = "APPLE";
|
|
||||||
private static final String THIRD_PARTY = "THIRD_PARTY";
|
|
||||||
private static final String UNKNOWN = "UNKNOWN";
|
|
||||||
|
|
||||||
private final ObjectProvider<MessageSenderService> messageSenderServiceProvider;
|
|
||||||
|
|
||||||
@Value("${recharge.success.mq.enabled:true}")
|
|
||||||
private boolean mqEnabled;
|
|
||||||
|
|
||||||
@Value("${recharge.success.mq.topic:RC_DEFAULT_APP_ORDINARY}")
|
|
||||||
private String mqTopic;
|
|
||||||
|
|
||||||
@Value("${recharge.success.mq.tag:" + RechargeSuccessSink.TAG + "}")
|
|
||||||
private String mqTag;
|
|
||||||
|
|
||||||
public RechargeSuccessEventPublisher(ObjectProvider<MessageSenderService> messageSenderServiceProvider) {
|
|
||||||
this.messageSenderServiceProvider = messageSenderServiceProvider;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void reportAppPurchaseRecharge(BuySuccessEvent event) {
|
|
||||||
if (Objects.isNull(event)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Long userId = event.getAcceptUserId();
|
|
||||||
Long purchaseHistoryId = event.getPurchaseHistoryId();
|
|
||||||
BigDecimal amountUsd = Objects.nonNull(event.getProductConfig())
|
|
||||||
? event.getProductConfig().getUnitPrice()
|
|
||||||
: null;
|
|
||||||
Long amountCents = toCents(amountUsd);
|
|
||||||
if (Objects.isNull(userId) || Objects.isNull(purchaseHistoryId) || !positive(amountCents)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
String sourceOrderId = String.valueOf(purchaseHistoryId);
|
|
||||||
String payPlatform = normalizePayPlatform(defaultIfBlank(event.getPayPlatform(), event.getPlatform()));
|
|
||||||
String paymentMethod = classifyPaymentMethod(payPlatform);
|
|
||||||
String appVersion = defaultIfBlank(event.getAppVersion(), "");
|
|
||||||
String productId = Objects.nonNull(event.getProductConfig())
|
|
||||||
? defaultIfBlank(event.getProductConfig().getProductId(), event.getOrigin())
|
|
||||||
: defaultIfBlank(event.getOrigin(), "");
|
|
||||||
String googleProductId = Objects.equals(GOOGLE, payPlatform) ? productId : "";
|
|
||||||
|
|
||||||
Map<String, Object> payload = new HashMap<>();
|
|
||||||
payload.put("payerUserId", event.getUserId());
|
|
||||||
payload.put("acceptUserId", userId);
|
|
||||||
payload.put("purchaseHistoryId", purchaseHistoryId);
|
|
||||||
payload.put("candyQuantity", event.getCandyQuantity());
|
|
||||||
payload.put("platform", event.getPlatform());
|
|
||||||
payload.put("payPlatform", event.getPayPlatform());
|
|
||||||
payload.put("appVersion", event.getAppVersion());
|
|
||||||
payload.put("productId", productId);
|
|
||||||
payload.put("googleProductId", googleProductId);
|
|
||||||
|
|
||||||
publish(new RechargeSuccessEvent()
|
|
||||||
.setEventId("RECHARGE_SUCCESS:" + paymentMethod + ":" + sourceOrderId)
|
|
||||||
.setSysOrigin(event.getSysOrigin())
|
|
||||||
.setUserId(userId)
|
|
||||||
.setAmountCents(amountCents)
|
|
||||||
.setAmountUsd(formatAmount(amountUsd))
|
|
||||||
.setCurrency("USD")
|
|
||||||
.setPayPlatform(payPlatform)
|
|
||||||
.setPaymentMethod(paymentMethod)
|
|
||||||
.setProductId(productId)
|
|
||||||
.setGoogleProductId(googleProductId)
|
|
||||||
.setAppVersion(appVersion)
|
|
||||||
.setSourceOrderId(sourceOrderId)
|
|
||||||
.setOrderId(sourceOrderId)
|
|
||||||
.setOccurredAt(toInstantString(event.getBuyDateTime()))
|
|
||||||
.setPayload(payload));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void reportPaymentRecharge(InAppPurchaseDetails order) {
|
|
||||||
if (Objects.isNull(order) || !order.receiptTypeEqPayment()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
InAppPurchaseProduct product = order.firstProduct();
|
|
||||||
if (Objects.isNull(product) || !PayApplicationCommodityType.GOLD.eq(product.getCode())) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
String payPlatform = normalizePayPlatform(Objects.nonNull(order.getFactory()) ? order.getFactory().getFactoryCode() : "");
|
|
||||||
String paymentMethod = classifyPaymentMethod(payPlatform);
|
|
||||||
|
|
||||||
BigDecimal amountUsd = firstPositive(order.getAmountUsd(), product.getAmountUsd());
|
|
||||||
Long amountCents = toCents(amountUsd);
|
|
||||||
if (Objects.isNull(order.getAcceptUserId()) || isBlank(order.getId()) || !positive(amountCents)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<String, Object> payload = new HashMap<>();
|
|
||||||
payload.put("trackId", order.getTrackId());
|
|
||||||
payload.put("sourceOrderId", order.getId());
|
|
||||||
payload.put("orderId", order.getOrderId());
|
|
||||||
payload.put("factoryCode", payPlatform);
|
|
||||||
payload.put("factoryChannelCode", Objects.nonNull(order.getFactory()) ? order.getFactory().getFactoryChannelCode() : null);
|
|
||||||
payload.put("platform", Objects.nonNull(order.getFactory()) ? order.getFactory().getPlatform() : null);
|
|
||||||
payload.put("productCode", product.getCode());
|
|
||||||
payload.put("productContent", product.getContent());
|
|
||||||
String appVersion = appVersionFromMetadata(order);
|
|
||||||
payload.put("appVersion", appVersion);
|
|
||||||
String productId = defaultIfBlank(order.getTrackId(), "");
|
|
||||||
String googleProductId = Objects.equals(GOOGLE, payPlatform) ? productId : "";
|
|
||||||
payload.put("productId", productId);
|
|
||||||
payload.put("googleProductId", googleProductId);
|
|
||||||
|
|
||||||
publish(new RechargeSuccessEvent()
|
|
||||||
.setEventId("RECHARGE_SUCCESS:" + paymentMethod + ":" + payPlatform + ":" + order.getId())
|
|
||||||
.setSysOrigin(order.getSysOrigin())
|
|
||||||
.setUserId(order.getAcceptUserId())
|
|
||||||
.setAmountCents(amountCents)
|
|
||||||
.setAmountUsd(formatAmount(amountUsd))
|
|
||||||
.setCurrency(defaultIfBlank(order.getCurrency(), "USD"))
|
|
||||||
.setPayPlatform(payPlatform)
|
|
||||||
.setPaymentMethod(paymentMethod)
|
|
||||||
.setProductId(productId)
|
|
||||||
.setGoogleProductId(googleProductId)
|
|
||||||
.setAppVersion(appVersion)
|
|
||||||
.setSourceOrderId(order.getId())
|
|
||||||
.setOrderId(defaultIfBlank(order.getOrderId(), order.getId()))
|
|
||||||
.setOccurredAt(firstTime(order.getPurchaseDateMs(), order.getUpdateTime(), order.getCreateTime()))
|
|
||||||
.setPayload(payload));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void publish(RechargeSuccessEvent event) {
|
|
||||||
if (!mqEnabled) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
MessageSenderService senderService = messageSenderServiceProvider.getIfAvailable();
|
|
||||||
if (Objects.isNull(senderService)) {
|
|
||||||
log.warn("Recharge success mq sender missing, skip event report. eventId={}", event.getEventId());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
senderService.sendEventMessage(MessageEvent.builder()
|
|
||||||
.consumeId(event.getEventId())
|
|
||||||
.topicString(defaultIfBlank(mqTopic, "RC_DEFAULT_APP_ORDINARY"))
|
|
||||||
.tag(defaultIfBlank(mqTag, RechargeSuccessSink.TAG))
|
|
||||||
.body(event)
|
|
||||||
.build());
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.warn("Recharge success mq report error. eventId={}", event.getEventId(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private String normalizePayPlatform(String value) {
|
|
||||||
String normalized = Objects.toString(value, "").trim().toUpperCase();
|
|
||||||
return normalized.isEmpty() ? UNKNOWN : normalized;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String classifyPaymentMethod(String payPlatform) {
|
|
||||||
if (Objects.equals(GOOGLE, payPlatform)) {
|
|
||||||
return GOOGLE;
|
|
||||||
}
|
|
||||||
if (Objects.equals(APPLE, payPlatform)) {
|
|
||||||
return APPLE;
|
|
||||||
}
|
|
||||||
if (Objects.equals(UNKNOWN, payPlatform)) {
|
|
||||||
return UNKNOWN;
|
|
||||||
}
|
|
||||||
return THIRD_PARTY;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String appVersionFromMetadata(InAppPurchaseDetails order) {
|
|
||||||
if (Objects.isNull(order) || Objects.isNull(order.getMetadata())) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
return defaultIfBlank(order.getMetadata().get("appVersion"), "");
|
|
||||||
}
|
|
||||||
|
|
||||||
private Long toCents(BigDecimal amount) {
|
|
||||||
if (Objects.isNull(amount) || amount.compareTo(BigDecimal.ZERO) <= 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return amount.multiply(BigDecimal.valueOf(100)).setScale(0, RoundingMode.HALF_UP).longValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
private BigDecimal firstPositive(BigDecimal first, BigDecimal second) {
|
|
||||||
if (Objects.nonNull(first) && first.compareTo(BigDecimal.ZERO) > 0) {
|
|
||||||
return first;
|
|
||||||
}
|
|
||||||
return second;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean positive(Long value) {
|
|
||||||
return Objects.nonNull(value) && value > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String toInstantString(Timestamp timestamp) {
|
|
||||||
return Objects.nonNull(timestamp) ? timestamp.toInstant().toString() : Instant.now().toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
private String firstTime(Timestamp first, Timestamp second, Timestamp third) {
|
|
||||||
if (Objects.nonNull(first)) {
|
|
||||||
return first.toInstant().toString();
|
|
||||||
}
|
|
||||||
if (Objects.nonNull(second)) {
|
|
||||||
return second.toInstant().toString();
|
|
||||||
}
|
|
||||||
if (Objects.nonNull(third)) {
|
|
||||||
return third.toInstant().toString();
|
|
||||||
}
|
|
||||||
return Instant.now().toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
private String formatAmount(BigDecimal amount) {
|
|
||||||
return Objects.isNull(amount) ? null : amount.stripTrailingZeros().toPlainString();
|
|
||||||
}
|
|
||||||
|
|
||||||
private String defaultIfBlank(String value, String fallback) {
|
|
||||||
return isBlank(value) ? fallback : value.trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isBlank(String value) {
|
|
||||||
return Objects.toString(value, "").trim().isEmpty();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -17,7 +17,6 @@ import com.red.circle.framework.dto.ResultResponse;
|
|||||||
import com.red.circle.mq.business.model.event.pay.BuySuccessEvent;
|
import com.red.circle.mq.business.model.event.pay.BuySuccessEvent;
|
||||||
import com.red.circle.mq.business.model.event.pay.PurchaseProductEvent;
|
import com.red.circle.mq.business.model.event.pay.PurchaseProductEvent;
|
||||||
import com.red.circle.mq.rocket.business.streams.BuySuccessSink;
|
import com.red.circle.mq.rocket.business.streams.BuySuccessSink;
|
||||||
import com.red.circle.order.app.common.task.RechargeSuccessEventPublisher;
|
|
||||||
import com.red.circle.order.app.common.task.TaskCenterGoClient;
|
import com.red.circle.order.app.common.task.TaskCenterGoClient;
|
||||||
import com.red.circle.other.inner.endpoint.activity.CumulativeRechargeClient;
|
import com.red.circle.other.inner.endpoint.activity.CumulativeRechargeClient;
|
||||||
import com.red.circle.other.inner.endpoint.activity.PropsActivityClient;
|
import com.red.circle.other.inner.endpoint.activity.PropsActivityClient;
|
||||||
@ -72,7 +71,6 @@ public class BuySuccessListener implements MessageListener {
|
|||||||
private final CumulativeRechargeClient cumulativeRechargeClient;
|
private final CumulativeRechargeClient cumulativeRechargeClient;
|
||||||
private final RedisService redisService;
|
private final RedisService redisService;
|
||||||
private final TaskCenterGoClient taskCenterGoClient;
|
private final TaskCenterGoClient taskCenterGoClient;
|
||||||
private final RechargeSuccessEventPublisher rechargeSuccessEventPublisher;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Action consume(ConsumerMessage message) {
|
public Action consume(ConsumerMessage message) {
|
||||||
@ -135,7 +133,6 @@ public class BuySuccessListener implements MessageListener {
|
|||||||
eventBody.getPlatform(),
|
eventBody.getPlatform(),
|
||||||
eventBody.getPayPlatform(),
|
eventBody.getPayPlatform(),
|
||||||
Objects.nonNull(eventBody.getBuyDateTime()) ? eventBody.getBuyDateTime().toInstant() : null);
|
Objects.nonNull(eventBody.getBuyDateTime()) ? eventBody.getBuyDateTime().toInstant() : null);
|
||||||
rechargeSuccessEventPublisher.reportAppPurchaseRecharge(eventBody);
|
|
||||||
|
|
||||||
userExpandClient.updatePurchasingToTrue(eventBody.getUserId());
|
userExpandClient.updatePurchasingToTrue(eventBody.getUserId());
|
||||||
|
|
||||||
|
|||||||
@ -49,16 +49,6 @@ public class WebSiteUseProfileCO extends ClientObject {
|
|||||||
*/
|
*/
|
||||||
private String sysOrigin;
|
private String sysOrigin;
|
||||||
|
|
||||||
/**
|
|
||||||
* 是否存在货运金币账户;Yumi H5 用这个身份决定展示普通金币还是货运金币商品.
|
|
||||||
*/
|
|
||||||
private Boolean freightUser;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 本次 H5 充值应该请求的商品类型,普通用户是 GOLD,货运/币商用户是 FREIGHT_GOLD.
|
|
||||||
*/
|
|
||||||
private String commodityType;
|
|
||||||
|
|
||||||
public static WebSiteUseProfileCO toWebSiteUseProfileCO(UserProfileDTO userProfile) {
|
public static WebSiteUseProfileCO toWebSiteUseProfileCO(UserProfileDTO userProfile) {
|
||||||
if (userProfile == null) {
|
if (userProfile == null) {
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@ -23,9 +23,4 @@ public class PayOrderStatusCmd extends AppExtCommand {
|
|||||||
*/
|
*/
|
||||||
@NotBlank(message = "orderId required.")
|
@NotBlank(message = "orderId required.")
|
||||||
private String orderId;
|
private String orderId;
|
||||||
|
|
||||||
/**
|
|
||||||
* H5公开支付页没有登录态,轮询状态时必须用下单用户ID继续做订单归属校验.
|
|
||||||
*/
|
|
||||||
private Long userId;
|
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user