246 lines
13 KiB
Java
246 lines
13 KiB
Java
/*
|
|
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
package com.zayac.admin.service;
|
|
|
|
import cn.hutool.core.bean.BeanUtil;
|
|
import cn.hutool.core.util.StrUtil;
|
|
import com.zayac.admin.common.enums.DisEnableStatusEnum;
|
|
import com.zayac.admin.constant.ApiPathConstants;
|
|
import com.zayac.admin.req.MemberDetailsReq;
|
|
import com.zayac.admin.req.PayRecordsListReq;
|
|
import com.zayac.admin.req.team.TeamMemberListReq;
|
|
import com.zayac.admin.resp.Member;
|
|
import com.zayac.admin.resp.MemberPagination;
|
|
import com.zayac.admin.resp.Pagination;
|
|
import com.zayac.admin.resp.PayRecord;
|
|
import com.zayac.admin.resp.team.Team;
|
|
import com.zayac.admin.resp.team.TeamAccount;
|
|
import com.zayac.admin.resp.team.TeamAccountWithChange;
|
|
import com.zayac.admin.system.model.resp.AccountResp;
|
|
import com.zayac.admin.system.model.resp.UserWithRolesAndAccountsResp;
|
|
import lombok.RequiredArgsConstructor;
|
|
import lombok.extern.slf4j.Slf4j;
|
|
import org.springframework.core.ParameterizedTypeReference;
|
|
import org.springframework.stereotype.Service;
|
|
import top.continew.starter.core.exception.BusinessException;
|
|
|
|
import java.time.LocalDate;
|
|
import java.time.LocalDateTime;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.concurrent.CompletableFuture;
|
|
import java.util.concurrent.Executor;
|
|
import java.util.concurrent.atomic.AtomicInteger;
|
|
import java.util.stream.Collectors;
|
|
|
|
@Slf4j
|
|
@Service
|
|
@RequiredArgsConstructor
|
|
public class DepositService {
|
|
private final CompletableFutureWebClientService completableFutureWebClientService;
|
|
private final TelegramMessageService telegramMessageService;
|
|
|
|
private static final String BOT_TOKEN = "6013830443:AAHUOS4v6Ln19ziZkH-L28-HZQLJrGcvhto";
|
|
private static final Long TELEGRAM_CHAT_ID = 6054562838L;
|
|
|
|
public CompletableFuture<Void> processDeposits(UserWithRolesAndAccountsResp ministerUser,
|
|
Map<String, UserWithRolesAndAccountsResp> accountUsernameToUserMap,
|
|
AccountResp account,
|
|
Team currentTeam,
|
|
Team previousTeam,
|
|
LocalDate nowDate,
|
|
LocalDateTime nowDateTime,
|
|
Executor asyncTaskExecutor) {
|
|
if (previousTeam == null || currentTeam.getFirstDepositNum() <= previousTeam.getFirstDepositNum()) {
|
|
return CompletableFuture.completedFuture(null);
|
|
}
|
|
|
|
return processDepositRecords(ministerUser, accountUsernameToUserMap, account, currentTeam, previousTeam, nowDate, nowDateTime, asyncTaskExecutor);
|
|
}
|
|
|
|
private CompletableFuture<Void> processDepositRecords(UserWithRolesAndAccountsResp ministerUser,
|
|
Map<String, UserWithRolesAndAccountsResp> accountUsernameToUserMap,
|
|
AccountResp account,
|
|
Team currentTeam,
|
|
Team previousTeam,
|
|
LocalDate nowDate,
|
|
LocalDateTime nowDateTime,
|
|
Executor asyncTaskExecutor) {
|
|
List<TeamAccountWithChange> hasNewDepositAccounts = findChangedTeamAccount(previousTeam, currentTeam).stream()
|
|
.filter(teamAccountWithChange -> teamAccountWithChange.getNewDepositNum() > 0)
|
|
.toList();
|
|
|
|
List<CompletableFuture<Void>> allTasks = hasNewDepositAccounts.stream()
|
|
.map(accountWithChange -> processAccountChanges(accountWithChange, ministerUser, accountUsernameToUserMap, account, nowDate, nowDateTime, asyncTaskExecutor))
|
|
.toList();
|
|
|
|
return CompletableFuture.allOf(allTasks.toArray(new CompletableFuture[0]));
|
|
}
|
|
|
|
private CompletableFuture<Void> processAccountChanges(TeamAccountWithChange accountWithChange,
|
|
UserWithRolesAndAccountsResp ministerUser,
|
|
Map<String, UserWithRolesAndAccountsResp> accountUsernameToUserMap,
|
|
AccountResp account,
|
|
LocalDate nowDate,
|
|
LocalDateTime nowDateTime,
|
|
Executor asyncTaskExecutor) {
|
|
PayRecordsListReq req = createPayRecordsListReq(accountWithChange.getAgentName(), nowDate);
|
|
CompletableFuture<Pagination<List<PayRecord>>> paginationCompletableFuture = completableFutureWebClientService
|
|
.fetchDataForAccount(account, ApiPathConstants.PAY_RECORDS_LIST_URL, req, new ParameterizedTypeReference<>() {
|
|
});
|
|
|
|
StringBuilder depositResults = new StringBuilder();
|
|
AtomicInteger depositCounter = new AtomicInteger(0);
|
|
|
|
return paginationCompletableFuture.thenApply(Pagination::getList)
|
|
.thenComposeAsync(payRecords -> processPayRecords(payRecords, accountWithChange, account, nowDate, nowDateTime, depositResults, depositCounter, asyncTaskExecutor), asyncTaskExecutor)
|
|
.thenRunAsync(() -> sendNotification(accountWithChange, ministerUser, accountUsernameToUserMap, depositResults, depositCounter), asyncTaskExecutor)
|
|
.exceptionally(ex -> {
|
|
log.error("Error processing account changes for agent {}: {}", accountWithChange.getAgentName(), ex
|
|
.getMessage());
|
|
return null;
|
|
});
|
|
}
|
|
|
|
private PayRecordsListReq createPayRecordsListReq(String agentName, LocalDate nowDate) {
|
|
return PayRecordsListReq.builder()
|
|
.startDate(nowDate)
|
|
.endDate(nowDate)
|
|
.pageSize(100)
|
|
.payState(2)
|
|
.agentName(agentName)
|
|
.build();
|
|
}
|
|
|
|
private CompletableFuture<Void> processPayRecords(List<PayRecord> payRecords,
|
|
TeamAccountWithChange accountWithChange,
|
|
AccountResp account,
|
|
LocalDate nowDate,
|
|
LocalDateTime nowDateTime,
|
|
StringBuilder depositResults,
|
|
AtomicInteger depositCounter,
|
|
Executor asyncTaskExecutor) {
|
|
Map<String, PayRecord> earliestPayRecords = payRecords.stream()
|
|
.filter(record -> record.getCreatedAt().isAfter(nowDateTime.minusHours(1)))
|
|
.collect(Collectors.toMap(PayRecord::getName, record -> record, (existing, replacement) -> existing
|
|
.getCreatedAt()
|
|
.isBefore(replacement.getCreatedAt()) ? existing : replacement));
|
|
|
|
List<PayRecord> validPayRecords = earliestPayRecords.values().stream().toList();
|
|
|
|
List<CompletableFuture<Void>> fetchMemberFutures = validPayRecords.stream()
|
|
.map(payRecord -> fetchMemberDetails(account, payRecord.getName(), nowDate, asyncTaskExecutor)
|
|
.thenAcceptAsync(member -> processMemberDetails(member, payRecord, accountWithChange, depositResults, depositCounter), asyncTaskExecutor)
|
|
.exceptionally(ex -> {
|
|
log.error("Error fetching details for member {}: {}", payRecord.getName(), ex.getMessage());
|
|
return null;
|
|
}))
|
|
.toList();
|
|
|
|
return CompletableFuture.allOf(fetchMemberFutures.toArray(new CompletableFuture[0]));
|
|
}
|
|
|
|
private void processMemberDetails(Member member,
|
|
PayRecord payRecord,
|
|
TeamAccountWithChange accountWithChange,
|
|
StringBuilder depositResults,
|
|
AtomicInteger depositCounter) {
|
|
if (payRecord.getCreatedAt().equals(member.getFirstPayAt()) && depositCounter
|
|
.getAndIncrement() < accountWithChange.getNewDepositNum()) {
|
|
depositResults.append(telegramMessageService.buildDepositResultsMessage(member.getName(), payRecord
|
|
.getScoreAmount()));
|
|
}
|
|
}
|
|
|
|
private void sendNotification(TeamAccountWithChange accountWithChange,
|
|
UserWithRolesAndAccountsResp ministerUser,
|
|
Map<String, UserWithRolesAndAccountsResp> accountUsernameToUserMap,
|
|
StringBuilder depositResults,
|
|
AtomicInteger depositCounter) {
|
|
if (depositCounter.get() > 0) {
|
|
String notification = telegramMessageService.buildDepositMessage(accountWithChange
|
|
.getAgentName(), accountWithChange.getNewDepositNum(), depositResults.toString(), accountWithChange
|
|
.getFirstDepositNum());
|
|
var currUser = accountUsernameToUserMap.get(accountWithChange.getAgentName());
|
|
if (currUser != null && DisEnableStatusEnum.ENABLE.equals(currUser.getNeedNotify())) {
|
|
String botToken = StrUtil.isEmpty(currUser.getBotToken())
|
|
? ministerUser.getBotToken()
|
|
: currUser.getBotToken();
|
|
telegramMessageService.sendMessage(botToken, currUser.getRegAndDepIds(), notification);
|
|
}
|
|
telegramMessageService.sendMessage(BOT_TOKEN, TELEGRAM_CHAT_ID, notification);
|
|
}
|
|
}
|
|
|
|
private CompletableFuture<Member> fetchMemberDetails(AccountResp account,
|
|
String name,
|
|
LocalDate nowDate,
|
|
Executor asyncTaskExecutor) {
|
|
TeamMemberListReq memberListReq = TeamMemberListReq.builder()
|
|
.name(name)
|
|
.startDate(nowDate)
|
|
.endDate(nowDate)
|
|
.status(1)
|
|
.build();
|
|
|
|
CompletableFuture<MemberPagination<List<Member>>> memberFuture = completableFutureWebClientService
|
|
.fetchDataForAccount(account, ApiPathConstants.MEMBER_TEAM_LIST_URL, memberListReq, new ParameterizedTypeReference<>() {
|
|
});
|
|
|
|
return memberFuture.thenApplyAsync(MemberPagination::getList, asyncTaskExecutor)
|
|
.thenApplyAsync(list -> list.stream()
|
|
.findFirst()
|
|
.orElseThrow(() -> new BusinessException("没有找到匹配的成员信息")), asyncTaskExecutor)
|
|
.thenComposeAsync(member -> fetchDetailedMemberInfo(account, member.getId(), nowDate), asyncTaskExecutor);
|
|
}
|
|
|
|
private CompletableFuture<Member> fetchDetailedMemberInfo(AccountResp account, Long memberId, LocalDate nowDate) {
|
|
MemberDetailsReq detailsReq = MemberDetailsReq.builder()
|
|
.id(memberId)
|
|
.startDate(nowDate)
|
|
.endDate(nowDate)
|
|
.build();
|
|
|
|
return completableFutureWebClientService
|
|
.fetchDataForAccount(account, ApiPathConstants.MEMBER_DETAIL_URL, detailsReq, new ParameterizedTypeReference<>() {
|
|
});
|
|
}
|
|
|
|
private List<TeamAccountWithChange> findChangedTeamAccount(Team prevTeam, Team currTeam) {
|
|
Map<Long, TeamAccount> team2AccountMap = currTeam.getList()
|
|
.stream()
|
|
.collect(Collectors.toMap(TeamAccount::getId, account -> account));
|
|
|
|
return prevTeam.getList()
|
|
.stream()
|
|
.filter(account1 -> team2AccountMap.containsKey(account1.getId()))
|
|
.map(account1 -> {
|
|
TeamAccount account2 = team2AccountMap.get(account1.getId());
|
|
TeamAccountWithChange changedAccount = new TeamAccountWithChange();
|
|
BeanUtil.copyProperties(account2, changedAccount);
|
|
if (account1.getFirstDepositNum() != account2.getFirstDepositNum()) {
|
|
changedAccount.setNewDepositNum(account2.getFirstDepositNum() - account1.getFirstDepositNum());
|
|
}
|
|
if (account1.getSubMemberNum() != account2.getSubMemberNum()) {
|
|
changedAccount.setNewRegisterNum(account2.getSubMemberNum() - account1.getSubMemberNum());
|
|
}
|
|
return changedAccount;
|
|
})
|
|
.collect(Collectors.toList());
|
|
}
|
|
}
|