TASK: 发送邮件功能及发送失败后的重试机制
This commit is contained in:
@@ -1,138 +1,145 @@
|
||||
package com.ai.da.service;
|
||||
|
||||
import com.ai.da.mapper.primary.entity.Account;
|
||||
import com.ai.da.mapper.primary.entity.TrialOrder;
|
||||
import com.ai.da.model.dto.AffiliateEmailParamsDTO;
|
||||
import com.ai.da.model.dto.BasicEmailParamDTO;
|
||||
import com.ai.da.model.dto.SubscriptionEmailParamsDTO;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import org.springframework.core.io.InputStreamSource;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface EmailService {
|
||||
|
||||
|
||||
void loadSingleEmailTemplate(String templatePath);
|
||||
|
||||
void loadTemplatesFromResources(String resourcesPath);
|
||||
|
||||
/**
|
||||
* 发邮件
|
||||
*
|
||||
* @param mailTo 收件人邮箱
|
||||
* @param jsonObject 动态邮件模板参数
|
||||
* @param templateName 邮件模板名(只有文件名且需要带文件后缀)
|
||||
* @param title 邮件标题
|
||||
* @param fileName 附件文件名。没有附件置为null
|
||||
* @param inputStreamSource 附件文件数据。没有附件置为null
|
||||
*/
|
||||
|
||||
void sendEmail(List<String> mailTo, JSONObject jsonObject, String templateName, String title, String fileName, InputStreamSource inputStreamSource);
|
||||
|
||||
/**
|
||||
* 适用于 : 需要自定义发件人信息
|
||||
*
|
||||
* @param jsonObject 模板参数
|
||||
* @param basicEmailParamDTO 包含发件人信息、邮件标题、收件人信息
|
||||
* @param templateName 使用的模板文件名
|
||||
* @param fileName 附件文件名
|
||||
* @param inputStreamSource 附件文件信息
|
||||
*/
|
||||
|
||||
void sendEmail(JSONObject jsonObject, BasicEmailParamDTO basicEmailParamDTO, String templateName, String fileName, InputStreamSource inputStreamSource);
|
||||
|
||||
// 登入模板id
|
||||
String LOGIN_TEMPLATE_ID = "58020_login_aida_en.html";
|
||||
// 修改密码模板id
|
||||
String UPDATE_PWD_TEMPLATE_ID = "58022_update_password.html";
|
||||
// 异常ip模板id
|
||||
String EXCEPTION_ID_TEMPLATE_ID = "58021_exception_ip.html";
|
||||
// 绑定邮箱模板id
|
||||
String BIND_MAILBOX_TEMPLATE_ID = "132754_绑定邮箱.html";
|
||||
// 更换绑定邮箱
|
||||
String CHANGE_MAILBOX_TEMPLATE_ID = "128210_change_mailbox_en.html";
|
||||
|
||||
/**
|
||||
* 发送登录相关的邮件
|
||||
*
|
||||
* @param receiverAddress 收件地址
|
||||
* @param ip 请求ip
|
||||
* @param templateId 模板ID名
|
||||
* @param verifyCode 验证码
|
||||
*/
|
||||
Boolean send(String receiverAddress, String ip, String templateId, String verifyCode);
|
||||
|
||||
/**
|
||||
* 发送试用订单相关的邮件
|
||||
*
|
||||
* @param receiverAddress 收件人邮箱地址
|
||||
* @param trialOrder 试用订单相关参数
|
||||
* @param emailType 邮件类型:1 - 提交试用请求,2 - 审批通过,3 - 试用请求通过通知
|
||||
* @param country 通过城市判断邮件模板的语言
|
||||
* @param link ?
|
||||
*/
|
||||
void sendCustomEmail(String receiverAddress, TrialOrder trialOrder, int emailType, String country, Boolean link);
|
||||
|
||||
/**
|
||||
* 发送昨日的试用订单用户数据
|
||||
*
|
||||
* @param receiverAddress 收件人地址
|
||||
* @param fileName 附件文件名
|
||||
* @param inputStreamSource 附件文件数据
|
||||
*/
|
||||
void sendExcelEmail(List<String> receiverAddress, String fileName, InputStreamSource inputStreamSource);
|
||||
|
||||
/**
|
||||
* 发送昨日的试用订单用户数据--无试用订单情况
|
||||
*
|
||||
* @param receiverAddress 收件人地址
|
||||
*/
|
||||
void sendNoExcelEmail(List<String> receiverAddress);
|
||||
|
||||
/**
|
||||
* 向账号快要到期的用户发送提醒邮件
|
||||
*
|
||||
* @param account 账号信息
|
||||
*/
|
||||
void sendWillBeExpiredEmail(Account account);
|
||||
|
||||
/**
|
||||
* 发送系统升级通知邮件
|
||||
*
|
||||
* @param account 用户信息
|
||||
* @param senderAddress 发件人邮件
|
||||
* @param type 邮件类型
|
||||
*/
|
||||
void sendUpgradeNotification(Account account, String senderAddress, Integer type);
|
||||
|
||||
/**
|
||||
* 通知在Code_Create上付费的用户,AiDA账号的更新
|
||||
*
|
||||
* @param receiverAddress 收件人地址
|
||||
* @param emailType 邮件类型
|
||||
* @param country 国家(确定发送邮件的语言)
|
||||
* @param userName 用户名
|
||||
* @param date 账号到期时间
|
||||
*/
|
||||
void notificationForPaidUser(String receiverAddress, int emailType, String country, String userName, String date);
|
||||
|
||||
/**
|
||||
* 广场用户注册通知邮件
|
||||
*
|
||||
* @param userEmail
|
||||
* @param randomVerifyCode
|
||||
* @return
|
||||
*/
|
||||
Boolean designWorksRegister(String userEmail, String randomVerifyCode);
|
||||
|
||||
void uploadTimeoutReminder(String userName, String time);
|
||||
|
||||
boolean subscriptionEmailReminder(String type, SubscriptionEmailParamsDTO subscriptionEmailParamsDTO, String language, String receiverAddress);
|
||||
|
||||
void affiliateEmailReminder(List<String> receiverAddress, AffiliateEmailParamsDTO paramsDTO, String type);
|
||||
|
||||
void creditsPurchaseReminder(String username, String quantity, String amount);
|
||||
|
||||
void commonExceptionReminder(String functionName, List<String> destination);
|
||||
}
|
||||
package com.ai.da.service;
|
||||
|
||||
import com.ai.da.mapper.primary.entity.Account;
|
||||
import com.ai.da.mapper.primary.entity.TrialOrder;
|
||||
import com.ai.da.model.dto.AffiliateEmailParamsDTO;
|
||||
import com.ai.da.model.dto.BasicEmailParamDTO;
|
||||
import com.ai.da.model.dto.SubscriptionEmailParamsDTO;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import org.springframework.core.io.InputStreamSource;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface EmailService {
|
||||
|
||||
String FAILED = "failed";
|
||||
String DELIVERED = "delivered";
|
||||
String RETRYING = "retrying";
|
||||
|
||||
void loadSingleEmailTemplate(String templatePath);
|
||||
|
||||
void loadTemplatesFromResources(String resourcesPath);
|
||||
|
||||
/**
|
||||
* 发邮件
|
||||
*
|
||||
* @param mailTo 收件人邮箱
|
||||
* @param jsonObject 动态邮件模板参数
|
||||
* @param templateName 邮件模板名(只有文件名且需要带文件后缀)
|
||||
* @param title 邮件标题
|
||||
* @param fileName 附件文件名。没有附件置为null
|
||||
* @param inputStreamSource 附件文件数据。没有附件置为null
|
||||
*/
|
||||
|
||||
void sendEmail(List<String> mailTo, JSONObject jsonObject, String templateName, String title, String fileName, InputStreamSource inputStreamSource);
|
||||
|
||||
void updateRetryCount(Long logId, int retryCount);
|
||||
|
||||
void updateStatus(Long logId, String status);
|
||||
|
||||
/**
|
||||
* 适用于 : 需要自定义发件人信息
|
||||
*
|
||||
* @param jsonObject 模板参数
|
||||
* @param basicEmailParamDTO 包含发件人信息、邮件标题、收件人信息
|
||||
* @param templateName 使用的模板文件名
|
||||
* @param fileName 附件文件名
|
||||
* @param inputStreamSource 附件文件信息
|
||||
*/
|
||||
|
||||
void sendEmail(JSONObject jsonObject, BasicEmailParamDTO basicEmailParamDTO, String templateName, String fileName, InputStreamSource inputStreamSource);
|
||||
|
||||
// 登入模板id
|
||||
String LOGIN_TEMPLATE_ID = "58020_login_aida_en.html";
|
||||
// 修改密码模板id
|
||||
String UPDATE_PWD_TEMPLATE_ID = "58022_update_password.html";
|
||||
// 异常ip模板id
|
||||
String EXCEPTION_ID_TEMPLATE_ID = "58021_exception_ip.html";
|
||||
// 绑定邮箱模板id
|
||||
String BIND_MAILBOX_TEMPLATE_ID = "132754_绑定邮箱.html";
|
||||
// 更换绑定邮箱
|
||||
String CHANGE_MAILBOX_TEMPLATE_ID = "128210_change_mailbox_en.html";
|
||||
|
||||
/**
|
||||
* 发送登录相关的邮件
|
||||
*
|
||||
* @param receiverAddress 收件地址
|
||||
* @param ip 请求ip
|
||||
* @param templateId 模板ID名
|
||||
* @param verifyCode 验证码
|
||||
*/
|
||||
Boolean send(String receiverAddress, String ip, String templateId, String verifyCode);
|
||||
|
||||
/**
|
||||
* 发送试用订单相关的邮件
|
||||
*
|
||||
* @param receiverAddress 收件人邮箱地址
|
||||
* @param trialOrder 试用订单相关参数
|
||||
* @param emailType 邮件类型:1 - 提交试用请求,2 - 审批通过,3 - 试用请求通过通知
|
||||
* @param country 通过城市判断邮件模板的语言
|
||||
* @param link ?
|
||||
*/
|
||||
void sendCustomEmail(String receiverAddress, TrialOrder trialOrder, int emailType, String country, Boolean link);
|
||||
|
||||
/**
|
||||
* 发送昨日的试用订单用户数据
|
||||
*
|
||||
* @param receiverAddress 收件人地址
|
||||
* @param fileName 附件文件名
|
||||
* @param inputStreamSource 附件文件数据
|
||||
*/
|
||||
void sendExcelEmail(List<String> receiverAddress, String fileName, InputStreamSource inputStreamSource);
|
||||
|
||||
/**
|
||||
* 发送昨日的试用订单用户数据--无试用订单情况
|
||||
*
|
||||
* @param receiverAddress 收件人地址
|
||||
*/
|
||||
void sendNoExcelEmail(List<String> receiverAddress);
|
||||
|
||||
/**
|
||||
* 向账号快要到期的用户发送提醒邮件
|
||||
*
|
||||
* @param account 账号信息
|
||||
*/
|
||||
void sendWillBeExpiredEmail(Account account);
|
||||
|
||||
/**
|
||||
* 发送系统升级通知邮件
|
||||
*
|
||||
* @param account 用户信息
|
||||
* @param senderAddress 发件人邮件
|
||||
* @param type 邮件类型
|
||||
*/
|
||||
void sendUpgradeNotification(Account account, String senderAddress, Integer type);
|
||||
|
||||
/**
|
||||
* 通知在Code_Create上付费的用户,AiDA账号的更新
|
||||
*
|
||||
* @param receiverAddress 收件人地址
|
||||
* @param emailType 邮件类型
|
||||
* @param country 国家(确定发送邮件的语言)
|
||||
* @param userName 用户名
|
||||
* @param date 账号到期时间
|
||||
*/
|
||||
void notificationForPaidUser(String receiverAddress, int emailType, String country, String userName, String date);
|
||||
|
||||
/**
|
||||
* 广场用户注册通知邮件
|
||||
*
|
||||
* @param userEmail
|
||||
* @param randomVerifyCode
|
||||
* @return
|
||||
*/
|
||||
Boolean designWorksRegister(String userEmail, String randomVerifyCode);
|
||||
|
||||
void uploadTimeoutReminder(String userName, String time);
|
||||
|
||||
boolean subscriptionEmailReminder(String type, SubscriptionEmailParamsDTO subscriptionEmailParamsDTO, String language, String receiverAddress);
|
||||
|
||||
void affiliateEmailReminder(List<String> receiverAddress, AffiliateEmailParamsDTO paramsDTO, String type);
|
||||
|
||||
void creditsPurchaseReminder(String username, String quantity, String amount);
|
||||
|
||||
void commonExceptionReminder(String functionName, List<String> destination);
|
||||
}
|
||||
|
||||
@@ -1,388 +1,394 @@
|
||||
package com.ai.da.service.impl;
|
||||
|
||||
import com.ai.da.common.config.exception.BusinessException;
|
||||
import com.ai.da.common.constant.CommonConstant;
|
||||
import com.ai.da.common.context.UserContext;
|
||||
import com.ai.da.common.response.PageBaseResponse;
|
||||
import com.ai.da.common.response.ResultEnum;
|
||||
import com.ai.da.common.utils.CopyUtil;
|
||||
import com.ai.da.common.utils.RedisUtil;
|
||||
import com.ai.da.common.utils.SendEmailUtil;
|
||||
import com.ai.da.mapper.primary.AffiliateIncomeMapper;
|
||||
import com.ai.da.mapper.primary.AffiliateMapper;
|
||||
import com.ai.da.mapper.primary.ProductCouponsMapper;
|
||||
import com.ai.da.mapper.primary.SubscriptionInfoMapper;
|
||||
import com.ai.da.mapper.primary.entity.*;
|
||||
import com.ai.da.model.dto.AffiliateEmailParamsDTO;
|
||||
import com.ai.da.model.dto.AffiliateQueryDTO;
|
||||
import com.ai.da.model.vo.AffiliateInvitationDetailsVO;
|
||||
import com.ai.da.model.vo.AffiliateVO;
|
||||
import com.ai.da.model.vo.AuthPrincipalVo;
|
||||
import com.ai.da.service.*;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.mysql.cj.util.StringUtils;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
public class AffiliateServiceImpl extends ServiceImpl<AffiliateMapper, Affiliate> implements AffiliateService {
|
||||
|
||||
@Resource
|
||||
private OrderInfoService orderInfoService;
|
||||
@Resource
|
||||
private AccountService accountService;
|
||||
@Resource
|
||||
private PaymentInfoService paymentInfoService;
|
||||
@Resource
|
||||
private SubscriptionInfoMapper subscriptionInfoMapper;
|
||||
@Resource
|
||||
private AffiliateIncomeMapper affiliateIncomeMapper;
|
||||
@Resource
|
||||
private StripeService stripeService;
|
||||
@Resource
|
||||
private ProductCouponsMapper productCouponsMapper;
|
||||
@Resource
|
||||
private RedisUtil redisUtil;
|
||||
|
||||
// 推广者注册
|
||||
public Boolean registerAsAnAffiliate(String promotionMethod){
|
||||
AuthPrincipalVo userHolder = UserContext.getUserHolder();
|
||||
// 判断该用户是否已注册
|
||||
QueryWrapper<Affiliate> qw = new QueryWrapper<>();
|
||||
qw.eq("account_id", userHolder.getId());
|
||||
Affiliate affiliate = baseMapper.selectOne(qw);
|
||||
if (Objects.isNull(affiliate)){
|
||||
affiliate = new Affiliate();
|
||||
affiliate.setAccountId(userHolder.getId());
|
||||
affiliate.setStatus("Pending");
|
||||
affiliate.setCreateTime(LocalDateTime.now());
|
||||
affiliate.setPromotionMethod(promotionMethod);
|
||||
baseMapper.insert(affiliate);
|
||||
// 邮件通知审批者
|
||||
String merchantEmail = "kimwong@code-create.com.hk";
|
||||
String developer = "xupei3360@163.com";
|
||||
String[] receiverEmail = {merchantEmail, developer};
|
||||
SendEmailUtil.affiliateEmailReminder(receiverEmail, new AffiliateEmailParamsDTO(userHolder.getUsername(), promotionMethod), "new");
|
||||
}else {
|
||||
throw new BusinessException("You have registered an Affiliate", ResultEnum.PROMPT.getCode());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public PageBaseResponse<AffiliateVO> getAffiliateList(AffiliateQueryDTO affiliateQueryDTO){
|
||||
log.info("parameter => {}", affiliateQueryDTO.toString());
|
||||
|
||||
int offset = (affiliateQueryDTO.getPage() - 1) * affiliateQueryDTO.getSize();
|
||||
List<AffiliateVO> affiliateList = baseMapper.getAffiliateList(affiliateQueryDTO.getStatus(),
|
||||
affiliateQueryDTO.getStartTime(),
|
||||
affiliateQueryDTO.getEndTime(),
|
||||
affiliateQueryDTO.getOrder(),
|
||||
affiliateQueryDTO.getAffiliateId(),
|
||||
affiliateQueryDTO.getSize(),
|
||||
offset
|
||||
);
|
||||
if (CollectionUtils.isEmpty(affiliateList)) {
|
||||
return PageBaseResponse.success(new Page<>());
|
||||
}else {
|
||||
int totalCount = baseMapper.queryAffiliateTotalCount(affiliateQueryDTO.getStatus(),
|
||||
affiliateQueryDTO.getStartTime(),
|
||||
affiliateQueryDTO.getEndTime(),
|
||||
affiliateQueryDTO.getAffiliateId()
|
||||
);
|
||||
IPage<AffiliateVO> orderListVOIPage = new Page<>();
|
||||
Integer size = affiliateQueryDTO.getSize();
|
||||
orderListVOIPage.setSize(size);
|
||||
orderListVOIPage.setRecords(affiliateList);
|
||||
orderListVOIPage.setCurrent(affiliateQueryDTO.getPage());
|
||||
orderListVOIPage.setPages((long)Math.ceil((double) totalCount / size));
|
||||
orderListVOIPage.setTotal(totalCount);
|
||||
return PageBaseResponse.success(orderListVOIPage);
|
||||
}
|
||||
/*QueryWrapper<Affiliate> qw = new QueryWrapper<>();
|
||||
qw.eq(!StringUtils.isNullOrEmpty(affiliateQueryDTO.getStatus()), "status", affiliateQueryDTO.getStatus())
|
||||
.gt(!StringUtils.isNullOrEmpty(affiliateQueryDTO.getStartTime()), "create_time", affiliateQueryDTO.getStartTime())
|
||||
.lt(!StringUtils.isNullOrEmpty(affiliateQueryDTO.getEndTime()), "create_time", affiliateQueryDTO.getEndTime())
|
||||
.eq(!Objects.isNull(affiliateQueryDTO.getAffiliateId()), "id", affiliateQueryDTO.getAffiliateId())
|
||||
.orderByDesc(affiliateQueryDTO.getOrder().equals("DESC"), "create_time");
|
||||
Page<Affiliate> affiliatePage = baseMapper.selectPage(new Page<>(affiliateQueryDTO.getPage(), affiliateQueryDTO.getSize()), qw);
|
||||
affiliatePage.convert((Function<Affiliate, AffiliateVO>) affiliate-> {
|
||||
AffiliateVO affiliateVO = CopyUtil.copyObject(affiliate, AffiliateVO.class);
|
||||
affiliateVO.setUsername();
|
||||
});
|
||||
return affiliatePage;*/
|
||||
}
|
||||
|
||||
public AffiliateVO personalAffiliateCenter(){
|
||||
QueryWrapper<Affiliate> qw = new QueryWrapper<>();
|
||||
Long accountId = UserContext.getUserHolder().getId();
|
||||
qw.eq("account_id", accountId);
|
||||
Affiliate affiliate = baseMapper.selectOne(qw);
|
||||
AffiliateVO affiliateVO = CopyUtil.copyObject(affiliate, AffiliateVO.class);
|
||||
affiliateVO.setLinkViewCount(getAffiliateLinkViewCount(affiliate.getId()));
|
||||
return affiliateVO;
|
||||
}
|
||||
|
||||
public double[] getPersonalMonthlyIncome(int year){
|
||||
Long accountId = UserContext.getUserHolder().getId();
|
||||
List<Map<String, Object>> personalMonthlyIncome = affiliateIncomeMapper.getPersonalMonthlyIncome(accountId, year);
|
||||
double[] commissions = new double[12];
|
||||
personalMonthlyIncome.forEach(income -> {
|
||||
int month = Integer.parseInt(income.get("yearMonth").toString());
|
||||
commissions[month-1] = (double)income.get("totalCommission");
|
||||
});
|
||||
|
||||
return commissions;
|
||||
}
|
||||
|
||||
// 审批申请
|
||||
public Boolean applicationApproval(Long id, Boolean isApproved, Float commission){
|
||||
Affiliate affiliate = baseMapper.selectById(id);
|
||||
|
||||
// 1、更新db状态
|
||||
if (isApproved){
|
||||
// 更新状态
|
||||
affiliate.setStatus("Active");
|
||||
affiliate.setApproved(true);
|
||||
affiliate.setLink(CommonConstant.AFFILIATE_LINK + affiliate.getId());
|
||||
if (Objects.isNull(commission)) {
|
||||
// 未设置佣金比例的情况下,默认25%
|
||||
affiliate.setCommissionPercent(25f);
|
||||
} else {
|
||||
affiliate.setCommissionPercent(commission);
|
||||
}
|
||||
} else {
|
||||
affiliate.setStatus("Refused");
|
||||
affiliate.setApproved(false);
|
||||
}
|
||||
affiliate.setUpdateTime(LocalDateTime.now());
|
||||
baseMapper.updateById(affiliate);
|
||||
|
||||
// 2、将批准结果邮件通知用户
|
||||
Account account = accountService.getById(affiliate.getAccountId());
|
||||
String[] userEmail = {account.getUserEmail()};
|
||||
String userName = account.getUserName();
|
||||
if (isApproved){
|
||||
SendEmailUtil.affiliateEmailReminder(userEmail, new AffiliateEmailParamsDTO(userName), "accepted");
|
||||
}else {
|
||||
SendEmailUtil.affiliateEmailReminder(userEmail, new AffiliateEmailParamsDTO(userName), "refused");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void updateCommissionPercentage(Long id, Float commission){
|
||||
Affiliate affiliate = baseMapper.selectById(id);
|
||||
if (Objects.isNull(affiliate)){
|
||||
log.info("未知affiliate id :{}", id);
|
||||
throw new BusinessException("unknown affiliate");
|
||||
}
|
||||
if (!Objects.equals(affiliate.getCommissionPercent(), commission)){
|
||||
affiliate.setCommissionPercent(commission);
|
||||
affiliate.setUpdateTime(LocalDateTime.now());
|
||||
baseMapper.updateById(affiliate);
|
||||
}
|
||||
}
|
||||
|
||||
// 定时计算佣金
|
||||
public void updateAffiliateInfoWithPayment(){
|
||||
// id存redis
|
||||
String lastTime = redisUtil.getFromString(RedisUtil.PAYMENT_INFO_LAST_SCAN_TIME);
|
||||
String currentTime = LocalDateTime.now().toString();
|
||||
// 1、查上次更新之后有无新订单
|
||||
QueryWrapper<PaymentInfo> queryWrapper = new QueryWrapper<>();
|
||||
if (!StringUtil.isNullOrEmpty(lastTime)){
|
||||
queryWrapper.gt("create_time", lastTime);
|
||||
}
|
||||
queryWrapper.eq("type","new").eq("trade_state", "paid");
|
||||
|
||||
List<PaymentInfo> paymentInfos = paymentInfoService.getBaseMapper().selectList(queryWrapper);
|
||||
if (!paymentInfos.isEmpty()){
|
||||
paymentInfos.forEach(paymentInfo -> {
|
||||
// 2、根据order_no查付款用户id
|
||||
OrderInfo orderInfo = orderInfoService.getOrderByOrderNo(paymentInfo.getOrderNo());
|
||||
if (Objects.isNull(orderInfo)){
|
||||
return;
|
||||
}
|
||||
Long accountId = orderInfo.getAccountId();
|
||||
// 3、查该用户之前是否有初次订阅的订单
|
||||
QueryWrapper<OrderInfo> qwOrderInfo = new QueryWrapper<>();
|
||||
qwOrderInfo.eq("account_id", accountId).eq("is_first_subscription", 1);
|
||||
List<OrderInfo> orderInfos = orderInfoService.getBaseMapper().selectList(qwOrderInfo);
|
||||
// 该用户首次订阅(非首次订阅,不分配佣金)
|
||||
if (orderInfos.isEmpty()){
|
||||
// 查询是否绑定affiliateId
|
||||
Account account = accountService.getById(accountId);
|
||||
if (!Objects.isNull(account.getInvitationCode())){
|
||||
log.info("结算订单id为{}的佣金", orderInfo.getId());
|
||||
// 3、若有, 直接更新affiliate的所得
|
||||
Affiliate affiliate = baseMapper.selectById(account.getInvitationCode());
|
||||
Float payerTotal = paymentInfo.getPayerTotal();
|
||||
|
||||
if (payerTotal > 0){
|
||||
// 分配新用户首次订阅所付费用 预设的佣金比例 作为佣金
|
||||
BigDecimal commission = BigDecimal.valueOf(payerTotal).multiply(BigDecimal.valueOf(affiliate.getCommissionPercent() / 100));
|
||||
BigDecimal monthlyEarning = BigDecimal.valueOf(affiliate.getMonthlyEarnings()).add(commission);
|
||||
BigDecimal unpaidEarnings = BigDecimal.valueOf(affiliate.getUnpaidEarnings()).add(commission);
|
||||
int visits = affiliate.getVisits() + 1;
|
||||
affiliate.setMonthlyEarnings(monthlyEarning.floatValue());
|
||||
affiliate.setUnpaidEarnings(unpaidEarnings.floatValue());
|
||||
affiliate.setVisits(visits);
|
||||
affiliate.setUpdateTime(LocalDateTime.now());
|
||||
baseMapper.updateById(affiliate);
|
||||
|
||||
orderInfo.setIsCommissionCalculated((byte)1);
|
||||
|
||||
// 4、添加到t_affiliate_income
|
||||
AffiliateIncome affiliateIncome = new AffiliateIncome();
|
||||
affiliateIncome.setAffiliateId(affiliate.getId());
|
||||
affiliateIncome.setAffiliateAccountId(affiliate.getAccountId());
|
||||
affiliateIncome.setInviteeAccountId(accountId);
|
||||
affiliateIncome.setAmount(payerTotal);
|
||||
affiliateIncome.setPaymentInfoId(paymentInfo.getId());
|
||||
affiliateIncome.setPaymentTime(paymentInfo.getCreateTime());
|
||||
affiliateIncome.setCommission(commission.floatValue());
|
||||
affiliateIncome.setCreateTime(LocalDateTime.now());
|
||||
affiliateIncomeMapper.insert(affiliateIncome);
|
||||
}
|
||||
}
|
||||
orderInfo.setIsFirstSubscription((byte)1);
|
||||
orderInfo.setUpdateTime(LocalDateTime.now());
|
||||
orderInfoService.updateById(orderInfo);
|
||||
}
|
||||
});
|
||||
}
|
||||
redisUtil.addToString(RedisUtil.PAYMENT_INFO_LAST_SCAN_TIME, currentTime);
|
||||
}
|
||||
|
||||
public Boolean affiliateLinkViewsIncrease(Long affiliateId) {
|
||||
redisUtil.increaseAffiliateLinkViewCount(affiliateId);
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
|
||||
private Long getAffiliateLinkViewCount(Long affiliateId) {
|
||||
return redisUtil.getAffiliateLinkViewCount(affiliateId);
|
||||
}
|
||||
|
||||
// 查看每个affiliate带来收入的详情
|
||||
@Override
|
||||
public IPage<AffiliateInvitationDetailsVO> getEachAffiliateGeneratedRevenue(AffiliateQueryDTO affiliateQueryDTO) {
|
||||
if (Objects.isNull(affiliateQueryDTO.getAffiliateId())){
|
||||
throw new BusinessException("Please specify the affiliate ID.", ResultEnum.PROMPT.getCode());
|
||||
}
|
||||
|
||||
QueryWrapper<AffiliateIncome> affiliateIncomeQueryWrapper = new QueryWrapper<>();
|
||||
affiliateIncomeQueryWrapper
|
||||
.gt(!StringUtils.isNullOrEmpty(affiliateQueryDTO.getStartTime()), "create_time", affiliateQueryDTO.getStartTime())
|
||||
.lt(!StringUtils.isNullOrEmpty(affiliateQueryDTO.getEndTime()), "create_time", affiliateQueryDTO.getEndTime())
|
||||
.eq(!Objects.isNull(affiliateQueryDTO.getAffiliateId()), "affiliate_id", affiliateQueryDTO.getAffiliateId())
|
||||
.orderByDesc(affiliateQueryDTO.getOrder().equals("DESC"), "create_time");
|
||||
IPage<AffiliateIncome> affiliateIncomePage = affiliateIncomeMapper.selectPage(new Page<>(affiliateQueryDTO.getPage(), affiliateQueryDTO.getSize()), affiliateIncomeQueryWrapper);
|
||||
return affiliateIncomePage.convert((Function<AffiliateIncome, AffiliateInvitationDetailsVO>) affiliateIncome -> {
|
||||
AffiliateInvitationDetailsVO affiliateInvitationDetailsVO = CopyUtil.copyObject(affiliateIncome, AffiliateInvitationDetailsVO.class);
|
||||
affiliateInvitationDetailsVO.setAccountId(affiliateIncome.getInviteeAccountId());
|
||||
affiliateInvitationDetailsVO.setUsername(accountService.getBaseMapper().selectById(affiliateIncome.getInviteeAccountId()).getUserName());
|
||||
affiliateInvitationDetailsVO.setFirstSubscriptionPaymentAmount(affiliateIncome.getAmount());
|
||||
affiliateInvitationDetailsVO.setCommission(affiliateIncome.getCommission());
|
||||
affiliateInvitationDetailsVO.setTime(affiliateIncome.getPaymentTime());
|
||||
return affiliateInvitationDetailsVO;
|
||||
});
|
||||
}
|
||||
|
||||
public void commissionCalculation(Integer year, Integer month) {
|
||||
if (Objects.isNull(year)) {
|
||||
year = LocalDateTime.now().getYear();
|
||||
}
|
||||
if (Objects.isNull(month)) {
|
||||
month = LocalDateTime.now().getMonthValue();
|
||||
}
|
||||
|
||||
List<Map<String, Object>> monthlyAffiliateIncome = affiliateIncomeMapper.getMonthlyAffiliateIncome(year, month);
|
||||
// 1、总收入(近一个月通过affiliate产生的收入),未支付的金额 affiliate表中unpaid的总和
|
||||
Double totalAmount = 0.0;
|
||||
Double totalCommission = 0.0;
|
||||
if (!monthlyAffiliateIncome.isEmpty()){
|
||||
Map<String, Object> monthlyIncome = monthlyAffiliateIncome.get(0);
|
||||
totalAmount = (Double) monthlyIncome.get("totalAmount");
|
||||
totalCommission = (Double) monthlyIncome.get("totalCommission");
|
||||
}
|
||||
|
||||
// 2、本月新注册的Affiliate
|
||||
Map<String, Long> monthlyApprovedAffiliate = baseMapper.getMonthlyApprovedAffiliate(year, month);
|
||||
Long count = monthlyApprovedAffiliate.get("count");
|
||||
|
||||
AffiliateEmailParamsDTO affiliateEmailParamsDTO = new AffiliateEmailParamsDTO();
|
||||
affiliateEmailParamsDTO.setTotalProgramRevenue(totalAmount.toString());
|
||||
affiliateEmailParamsDTO.setNewApprovedAffiliates(count.toString());
|
||||
affiliateEmailParamsDTO.setUnpaidEarnings(totalCommission.toString());
|
||||
affiliateEmailParamsDTO.setPaidEarnings("0");
|
||||
|
||||
String merchantEmail = "kimwong@code-create.com.hk";
|
||||
String developer = "xupei3360@163.com";
|
||||
String[] receiverEmail = {merchantEmail, developer};
|
||||
// 邮件通知
|
||||
SendEmailUtil.affiliateEmailReminder(receiverEmail, affiliateEmailParamsDTO, "summary");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Affiliate getByAccountId(Long accountId) {
|
||||
QueryWrapper<Affiliate> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.eq("account_id", accountId).orderByDesc("id").last("limit 1");
|
||||
|
||||
return baseMapper.selectOne(queryWrapper);
|
||||
}
|
||||
|
||||
public void calcCouponsCommission(){
|
||||
// id存redis
|
||||
String lastTime = redisUtil.getFromString(RedisUtil.PAYMENT_INFO_LAST_SCAN_TIME);
|
||||
String currentTime = LocalDateTime.now().toString();
|
||||
// 1、查上次更新之后有无使用了优惠券的新订单
|
||||
QueryWrapper<PaymentInfo> queryWrapper = new QueryWrapper<>();
|
||||
if (!StringUtil.isNullOrEmpty(lastTime)){
|
||||
queryWrapper.gt("create_time", lastTime)
|
||||
.lt("create_time", currentTime)
|
||||
.isNotNull("promotion_code");
|
||||
}
|
||||
List<PaymentInfo> paymentInfos = paymentInfoService.getBaseMapper().selectList(queryWrapper);
|
||||
|
||||
// key:推广码, value:用户支付的金额
|
||||
HashMap<String, Float> codeAmount = new HashMap<>();
|
||||
if (!paymentInfos.isEmpty()){
|
||||
for (PaymentInfo paymentInfo : paymentInfos){
|
||||
String promotionCode = paymentInfo.getPromotionCode();
|
||||
Float sum = codeAmount.get(promotionCode);
|
||||
if (sum == null || sum == 0.0f){
|
||||
codeAmount.put(promotionCode, paymentInfo.getPayerTotal());
|
||||
}else {
|
||||
codeAmount.put(promotionCode, sum + paymentInfo.getPayerTotal());
|
||||
}
|
||||
}
|
||||
for (Map.Entry<String, Float> entry : codeAmount.entrySet()){
|
||||
String promotionCode = entry.getKey();
|
||||
ProductCoupons productCoupons = stripeService.getProductCoupon(promotionCode, null);
|
||||
if (!Objects.isNull(productCoupons)){
|
||||
// 2、计算支付金额的总和,更新totalEarnings,commission,unpaidCommission
|
||||
float sum = productCoupons.getTotalEarnings() + entry.getValue();
|
||||
productCoupons.setTotalEarnings(sum);
|
||||
float commission = sum * productCoupons.getCommissionRate() / 100;
|
||||
productCoupons.setCommission(commission);
|
||||
productCoupons.setUnpaidCommission(commission - productCoupons.getPaidCommission());
|
||||
productCouponsMapper.updateById(productCoupons);
|
||||
}
|
||||
}
|
||||
}
|
||||
redisUtil.addToString(RedisUtil.PAYMENT_INFO_LAST_SCAN_TIME, currentTime);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
package com.ai.da.service.impl;
|
||||
|
||||
import com.ai.da.common.config.exception.BusinessException;
|
||||
import com.ai.da.common.constant.CommonConstant;
|
||||
import com.ai.da.common.context.UserContext;
|
||||
import com.ai.da.common.response.PageBaseResponse;
|
||||
import com.ai.da.common.response.ResultEnum;
|
||||
import com.ai.da.common.utils.CopyUtil;
|
||||
import com.ai.da.common.utils.RedisUtil;
|
||||
import com.ai.da.common.utils.SendEmailUtil;
|
||||
import com.ai.da.mapper.primary.AffiliateIncomeMapper;
|
||||
import com.ai.da.mapper.primary.AffiliateMapper;
|
||||
import com.ai.da.mapper.primary.ProductCouponsMapper;
|
||||
import com.ai.da.mapper.primary.SubscriptionInfoMapper;
|
||||
import com.ai.da.mapper.primary.entity.*;
|
||||
import com.ai.da.model.dto.AffiliateEmailParamsDTO;
|
||||
import com.ai.da.model.dto.AffiliateQueryDTO;
|
||||
import com.ai.da.model.vo.AffiliateInvitationDetailsVO;
|
||||
import com.ai.da.model.vo.AffiliateVO;
|
||||
import com.ai.da.model.vo.AuthPrincipalVo;
|
||||
import com.ai.da.service.*;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.mysql.cj.util.StringUtils;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
public class AffiliateServiceImpl extends ServiceImpl<AffiliateMapper, Affiliate> implements AffiliateService {
|
||||
|
||||
@Resource
|
||||
private OrderInfoService orderInfoService;
|
||||
@Resource
|
||||
private AccountService accountService;
|
||||
@Resource
|
||||
private PaymentInfoService paymentInfoService;
|
||||
@Resource
|
||||
private SubscriptionInfoMapper subscriptionInfoMapper;
|
||||
@Resource
|
||||
private AffiliateIncomeMapper affiliateIncomeMapper;
|
||||
@Resource
|
||||
private StripeService stripeService;
|
||||
@Resource
|
||||
private ProductCouponsMapper productCouponsMapper;
|
||||
@Resource
|
||||
private RedisUtil redisUtil;
|
||||
@Resource
|
||||
private EmailService emailService;
|
||||
|
||||
// 推广者注册
|
||||
public Boolean registerAsAnAffiliate(String promotionMethod){
|
||||
AuthPrincipalVo userHolder = UserContext.getUserHolder();
|
||||
// 判断该用户是否已注册
|
||||
QueryWrapper<Affiliate> qw = new QueryWrapper<>();
|
||||
qw.eq("account_id", userHolder.getId());
|
||||
Affiliate affiliate = baseMapper.selectOne(qw);
|
||||
if (Objects.isNull(affiliate)){
|
||||
affiliate = new Affiliate();
|
||||
affiliate.setAccountId(userHolder.getId());
|
||||
affiliate.setStatus("Pending");
|
||||
affiliate.setCreateTime(LocalDateTime.now());
|
||||
affiliate.setPromotionMethod(promotionMethod);
|
||||
baseMapper.insert(affiliate);
|
||||
// 邮件通知审批者
|
||||
String merchantEmail = "kimwong@code-create.com.hk";
|
||||
String developer = "xupei3360@163.com";
|
||||
String[] receiverEmail = {merchantEmail, developer};
|
||||
SendEmailUtil.affiliateEmailReminder(receiverEmail, new AffiliateEmailParamsDTO(userHolder.getUsername(), promotionMethod), "new");
|
||||
// emailService.affiliateEmailReminder(Arrays.asList(/*merchantEmail,*/ developer), new AffiliateEmailParamsDTO(userHolder.getUsername(), promotionMethod), "new");
|
||||
}else {
|
||||
throw new BusinessException("You have registered an Affiliate", ResultEnum.PROMPT.getCode());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public PageBaseResponse<AffiliateVO> getAffiliateList(AffiliateQueryDTO affiliateQueryDTO){
|
||||
log.info("parameter => {}", affiliateQueryDTO.toString());
|
||||
|
||||
int offset = (affiliateQueryDTO.getPage() - 1) * affiliateQueryDTO.getSize();
|
||||
List<AffiliateVO> affiliateList = baseMapper.getAffiliateList(affiliateQueryDTO.getStatus(),
|
||||
affiliateQueryDTO.getStartTime(),
|
||||
affiliateQueryDTO.getEndTime(),
|
||||
affiliateQueryDTO.getOrder(),
|
||||
affiliateQueryDTO.getAffiliateId(),
|
||||
affiliateQueryDTO.getSize(),
|
||||
offset
|
||||
);
|
||||
if (CollectionUtils.isEmpty(affiliateList)) {
|
||||
return PageBaseResponse.success(new Page<>());
|
||||
}else {
|
||||
int totalCount = baseMapper.queryAffiliateTotalCount(affiliateQueryDTO.getStatus(),
|
||||
affiliateQueryDTO.getStartTime(),
|
||||
affiliateQueryDTO.getEndTime(),
|
||||
affiliateQueryDTO.getAffiliateId()
|
||||
);
|
||||
IPage<AffiliateVO> orderListVOIPage = new Page<>();
|
||||
Integer size = affiliateQueryDTO.getSize();
|
||||
orderListVOIPage.setSize(size);
|
||||
orderListVOIPage.setRecords(affiliateList);
|
||||
orderListVOIPage.setCurrent(affiliateQueryDTO.getPage());
|
||||
orderListVOIPage.setPages((long)Math.ceil((double) totalCount / size));
|
||||
orderListVOIPage.setTotal(totalCount);
|
||||
return PageBaseResponse.success(orderListVOIPage);
|
||||
}
|
||||
/*QueryWrapper<Affiliate> qw = new QueryWrapper<>();
|
||||
qw.eq(!StringUtils.isNullOrEmpty(affiliateQueryDTO.getStatus()), "status", affiliateQueryDTO.getStatus())
|
||||
.gt(!StringUtils.isNullOrEmpty(affiliateQueryDTO.getStartTime()), "create_time", affiliateQueryDTO.getStartTime())
|
||||
.lt(!StringUtils.isNullOrEmpty(affiliateQueryDTO.getEndTime()), "create_time", affiliateQueryDTO.getEndTime())
|
||||
.eq(!Objects.isNull(affiliateQueryDTO.getAffiliateId()), "id", affiliateQueryDTO.getAffiliateId())
|
||||
.orderByDesc(affiliateQueryDTO.getOrder().equals("DESC"), "create_time");
|
||||
Page<Affiliate> affiliatePage = baseMapper.selectPage(new Page<>(affiliateQueryDTO.getPage(), affiliateQueryDTO.getSize()), qw);
|
||||
affiliatePage.convert((Function<Affiliate, AffiliateVO>) affiliate-> {
|
||||
AffiliateVO affiliateVO = CopyUtil.copyObject(affiliate, AffiliateVO.class);
|
||||
affiliateVO.setUsername();
|
||||
});
|
||||
return affiliatePage;*/
|
||||
}
|
||||
|
||||
public AffiliateVO personalAffiliateCenter(){
|
||||
QueryWrapper<Affiliate> qw = new QueryWrapper<>();
|
||||
Long accountId = UserContext.getUserHolder().getId();
|
||||
qw.eq("account_id", accountId);
|
||||
Affiliate affiliate = baseMapper.selectOne(qw);
|
||||
AffiliateVO affiliateVO = CopyUtil.copyObject(affiliate, AffiliateVO.class);
|
||||
affiliateVO.setLinkViewCount(getAffiliateLinkViewCount(affiliate.getId()));
|
||||
return affiliateVO;
|
||||
}
|
||||
|
||||
public double[] getPersonalMonthlyIncome(int year){
|
||||
Long accountId = UserContext.getUserHolder().getId();
|
||||
List<Map<String, Object>> personalMonthlyIncome = affiliateIncomeMapper.getPersonalMonthlyIncome(accountId, year);
|
||||
double[] commissions = new double[12];
|
||||
personalMonthlyIncome.forEach(income -> {
|
||||
int month = Integer.parseInt(income.get("yearMonth").toString());
|
||||
commissions[month-1] = (double)income.get("totalCommission");
|
||||
});
|
||||
|
||||
return commissions;
|
||||
}
|
||||
|
||||
// 审批申请
|
||||
public Boolean applicationApproval(Long id, Boolean isApproved, Float commission){
|
||||
Affiliate affiliate = baseMapper.selectById(id);
|
||||
|
||||
// 1、更新db状态
|
||||
if (isApproved){
|
||||
// 更新状态
|
||||
affiliate.setStatus("Active");
|
||||
affiliate.setApproved(true);
|
||||
affiliate.setLink(CommonConstant.AFFILIATE_LINK + affiliate.getId());
|
||||
if (Objects.isNull(commission)) {
|
||||
// 未设置佣金比例的情况下,默认25%
|
||||
affiliate.setCommissionPercent(25f);
|
||||
} else {
|
||||
affiliate.setCommissionPercent(commission);
|
||||
}
|
||||
} else {
|
||||
affiliate.setStatus("Refused");
|
||||
affiliate.setApproved(false);
|
||||
}
|
||||
affiliate.setUpdateTime(LocalDateTime.now());
|
||||
baseMapper.updateById(affiliate);
|
||||
|
||||
// 2、将批准结果邮件通知用户
|
||||
Account account = accountService.getById(affiliate.getAccountId());
|
||||
String[] userEmail = {account.getUserEmail()};
|
||||
String userName = account.getUserName();
|
||||
if (isApproved){
|
||||
SendEmailUtil.affiliateEmailReminder(userEmail, new AffiliateEmailParamsDTO(userName), "accepted");
|
||||
// emailService.affiliateEmailReminder(Collections.singletonList(account.getUserEmail()), new AffiliateEmailParamsDTO(userName), "accepted");
|
||||
}else {
|
||||
SendEmailUtil.affiliateEmailReminder(userEmail, new AffiliateEmailParamsDTO(userName), "refused");
|
||||
// emailService.affiliateEmailReminder(Collections.singletonList(account.getUserEmail()), new AffiliateEmailParamsDTO(userName), "refused");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void updateCommissionPercentage(Long id, Float commission){
|
||||
Affiliate affiliate = baseMapper.selectById(id);
|
||||
if (Objects.isNull(affiliate)){
|
||||
log.info("未知affiliate id :{}", id);
|
||||
throw new BusinessException("unknown affiliate");
|
||||
}
|
||||
if (!Objects.equals(affiliate.getCommissionPercent(), commission)){
|
||||
affiliate.setCommissionPercent(commission);
|
||||
affiliate.setUpdateTime(LocalDateTime.now());
|
||||
baseMapper.updateById(affiliate);
|
||||
}
|
||||
}
|
||||
|
||||
// 定时计算佣金
|
||||
public void updateAffiliateInfoWithPayment(){
|
||||
// id存redis
|
||||
String lastTime = redisUtil.getFromString(RedisUtil.PAYMENT_INFO_LAST_SCAN_TIME);
|
||||
String currentTime = LocalDateTime.now().toString();
|
||||
// 1、查上次更新之后有无新订单
|
||||
QueryWrapper<PaymentInfo> queryWrapper = new QueryWrapper<>();
|
||||
if (!StringUtil.isNullOrEmpty(lastTime)){
|
||||
queryWrapper.gt("create_time", lastTime);
|
||||
}
|
||||
queryWrapper.eq("type","new").eq("trade_state", "paid");
|
||||
|
||||
List<PaymentInfo> paymentInfos = paymentInfoService.getBaseMapper().selectList(queryWrapper);
|
||||
if (!paymentInfos.isEmpty()){
|
||||
paymentInfos.forEach(paymentInfo -> {
|
||||
// 2、根据order_no查付款用户id
|
||||
OrderInfo orderInfo = orderInfoService.getOrderByOrderNo(paymentInfo.getOrderNo());
|
||||
if (Objects.isNull(orderInfo)){
|
||||
return;
|
||||
}
|
||||
Long accountId = orderInfo.getAccountId();
|
||||
// 3、查该用户之前是否有初次订阅的订单
|
||||
QueryWrapper<OrderInfo> qwOrderInfo = new QueryWrapper<>();
|
||||
qwOrderInfo.eq("account_id", accountId).eq("is_first_subscription", 1);
|
||||
List<OrderInfo> orderInfos = orderInfoService.getBaseMapper().selectList(qwOrderInfo);
|
||||
// 该用户首次订阅(非首次订阅,不分配佣金)
|
||||
if (orderInfos.isEmpty()){
|
||||
// 查询是否绑定affiliateId
|
||||
Account account = accountService.getById(accountId);
|
||||
if (!Objects.isNull(account.getInvitationCode())){
|
||||
log.info("结算订单id为{}的佣金", orderInfo.getId());
|
||||
// 3、若有, 直接更新affiliate的所得
|
||||
Affiliate affiliate = baseMapper.selectById(account.getInvitationCode());
|
||||
Float payerTotal = paymentInfo.getPayerTotal();
|
||||
|
||||
if (payerTotal > 0){
|
||||
// 分配新用户首次订阅所付费用 预设的佣金比例 作为佣金
|
||||
BigDecimal commission = BigDecimal.valueOf(payerTotal).multiply(BigDecimal.valueOf(affiliate.getCommissionPercent() / 100));
|
||||
BigDecimal monthlyEarning = BigDecimal.valueOf(affiliate.getMonthlyEarnings()).add(commission);
|
||||
BigDecimal unpaidEarnings = BigDecimal.valueOf(affiliate.getUnpaidEarnings()).add(commission);
|
||||
int visits = affiliate.getVisits() + 1;
|
||||
affiliate.setMonthlyEarnings(monthlyEarning.floatValue());
|
||||
affiliate.setUnpaidEarnings(unpaidEarnings.floatValue());
|
||||
affiliate.setVisits(visits);
|
||||
affiliate.setUpdateTime(LocalDateTime.now());
|
||||
baseMapper.updateById(affiliate);
|
||||
|
||||
orderInfo.setIsCommissionCalculated((byte)1);
|
||||
|
||||
// 4、添加到t_affiliate_income
|
||||
AffiliateIncome affiliateIncome = new AffiliateIncome();
|
||||
affiliateIncome.setAffiliateId(affiliate.getId());
|
||||
affiliateIncome.setAffiliateAccountId(affiliate.getAccountId());
|
||||
affiliateIncome.setInviteeAccountId(accountId);
|
||||
affiliateIncome.setAmount(payerTotal);
|
||||
affiliateIncome.setPaymentInfoId(paymentInfo.getId());
|
||||
affiliateIncome.setPaymentTime(paymentInfo.getCreateTime());
|
||||
affiliateIncome.setCommission(commission.floatValue());
|
||||
affiliateIncome.setCreateTime(LocalDateTime.now());
|
||||
affiliateIncomeMapper.insert(affiliateIncome);
|
||||
}
|
||||
}
|
||||
orderInfo.setIsFirstSubscription((byte)1);
|
||||
orderInfo.setUpdateTime(LocalDateTime.now());
|
||||
orderInfoService.updateById(orderInfo);
|
||||
}
|
||||
});
|
||||
}
|
||||
redisUtil.addToString(RedisUtil.PAYMENT_INFO_LAST_SCAN_TIME, currentTime);
|
||||
}
|
||||
|
||||
public Boolean affiliateLinkViewsIncrease(Long affiliateId) {
|
||||
redisUtil.increaseAffiliateLinkViewCount(affiliateId);
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
|
||||
private Long getAffiliateLinkViewCount(Long affiliateId) {
|
||||
return redisUtil.getAffiliateLinkViewCount(affiliateId);
|
||||
}
|
||||
|
||||
// 查看每个affiliate带来收入的详情
|
||||
@Override
|
||||
public IPage<AffiliateInvitationDetailsVO> getEachAffiliateGeneratedRevenue(AffiliateQueryDTO affiliateQueryDTO) {
|
||||
if (Objects.isNull(affiliateQueryDTO.getAffiliateId())){
|
||||
throw new BusinessException("Please specify the affiliate ID.", ResultEnum.PROMPT.getCode());
|
||||
}
|
||||
|
||||
QueryWrapper<AffiliateIncome> affiliateIncomeQueryWrapper = new QueryWrapper<>();
|
||||
affiliateIncomeQueryWrapper
|
||||
.gt(!StringUtils.isNullOrEmpty(affiliateQueryDTO.getStartTime()), "create_time", affiliateQueryDTO.getStartTime())
|
||||
.lt(!StringUtils.isNullOrEmpty(affiliateQueryDTO.getEndTime()), "create_time", affiliateQueryDTO.getEndTime())
|
||||
.eq(!Objects.isNull(affiliateQueryDTO.getAffiliateId()), "affiliate_id", affiliateQueryDTO.getAffiliateId())
|
||||
.orderByDesc(affiliateQueryDTO.getOrder().equals("DESC"), "create_time");
|
||||
IPage<AffiliateIncome> affiliateIncomePage = affiliateIncomeMapper.selectPage(new Page<>(affiliateQueryDTO.getPage(), affiliateQueryDTO.getSize()), affiliateIncomeQueryWrapper);
|
||||
return affiliateIncomePage.convert((Function<AffiliateIncome, AffiliateInvitationDetailsVO>) affiliateIncome -> {
|
||||
AffiliateInvitationDetailsVO affiliateInvitationDetailsVO = CopyUtil.copyObject(affiliateIncome, AffiliateInvitationDetailsVO.class);
|
||||
affiliateInvitationDetailsVO.setAccountId(affiliateIncome.getInviteeAccountId());
|
||||
affiliateInvitationDetailsVO.setUsername(accountService.getBaseMapper().selectById(affiliateIncome.getInviteeAccountId()).getUserName());
|
||||
affiliateInvitationDetailsVO.setFirstSubscriptionPaymentAmount(affiliateIncome.getAmount());
|
||||
affiliateInvitationDetailsVO.setCommission(affiliateIncome.getCommission());
|
||||
affiliateInvitationDetailsVO.setTime(affiliateIncome.getPaymentTime());
|
||||
return affiliateInvitationDetailsVO;
|
||||
});
|
||||
}
|
||||
|
||||
public void commissionCalculation(Integer year, Integer month) {
|
||||
if (Objects.isNull(year)) {
|
||||
year = LocalDateTime.now().getYear();
|
||||
}
|
||||
if (Objects.isNull(month)) {
|
||||
month = LocalDateTime.now().getMonthValue();
|
||||
}
|
||||
|
||||
List<Map<String, Object>> monthlyAffiliateIncome = affiliateIncomeMapper.getMonthlyAffiliateIncome(year, month);
|
||||
// 1、总收入(近一个月通过affiliate产生的收入),未支付的金额 affiliate表中unpaid的总和
|
||||
Double totalAmount = 0.0;
|
||||
Double totalCommission = 0.0;
|
||||
if (!monthlyAffiliateIncome.isEmpty()){
|
||||
Map<String, Object> monthlyIncome = monthlyAffiliateIncome.get(0);
|
||||
totalAmount = (Double) monthlyIncome.get("totalAmount");
|
||||
totalCommission = (Double) monthlyIncome.get("totalCommission");
|
||||
}
|
||||
|
||||
// 2、本月新注册的Affiliate
|
||||
Map<String, Long> monthlyApprovedAffiliate = baseMapper.getMonthlyApprovedAffiliate(year, month);
|
||||
Long count = monthlyApprovedAffiliate.get("count");
|
||||
|
||||
AffiliateEmailParamsDTO affiliateEmailParamsDTO = new AffiliateEmailParamsDTO();
|
||||
affiliateEmailParamsDTO.setTotalProgramRevenue(totalAmount.toString());
|
||||
affiliateEmailParamsDTO.setNewApprovedAffiliates(count.toString());
|
||||
affiliateEmailParamsDTO.setUnpaidEarnings(totalCommission.toString());
|
||||
affiliateEmailParamsDTO.setPaidEarnings("0");
|
||||
|
||||
String merchantEmail = "kimwong@code-create.com.hk";
|
||||
String developer = "xupei3360@163.com";
|
||||
String[] receiverEmail = {merchantEmail, developer};
|
||||
// 邮件通知
|
||||
SendEmailUtil.affiliateEmailReminder(receiverEmail, affiliateEmailParamsDTO, "summary");
|
||||
// emailService.affiliateEmailReminder(Arrays.asList(/*merchantEmail,*/ developer), affiliateEmailParamsDTO, "summary");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Affiliate getByAccountId(Long accountId) {
|
||||
QueryWrapper<Affiliate> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.eq("account_id", accountId).orderByDesc("id").last("limit 1");
|
||||
|
||||
return baseMapper.selectOne(queryWrapper);
|
||||
}
|
||||
|
||||
public void calcCouponsCommission(){
|
||||
// id存redis
|
||||
String lastTime = redisUtil.getFromString(RedisUtil.PAYMENT_INFO_LAST_SCAN_TIME);
|
||||
String currentTime = LocalDateTime.now().toString();
|
||||
// 1、查上次更新之后有无使用了优惠券的新订单
|
||||
QueryWrapper<PaymentInfo> queryWrapper = new QueryWrapper<>();
|
||||
if (!StringUtil.isNullOrEmpty(lastTime)){
|
||||
queryWrapper.gt("create_time", lastTime)
|
||||
.lt("create_time", currentTime)
|
||||
.isNotNull("promotion_code");
|
||||
}
|
||||
List<PaymentInfo> paymentInfos = paymentInfoService.getBaseMapper().selectList(queryWrapper);
|
||||
|
||||
// key:推广码, value:用户支付的金额
|
||||
HashMap<String, Float> codeAmount = new HashMap<>();
|
||||
if (!paymentInfos.isEmpty()){
|
||||
for (PaymentInfo paymentInfo : paymentInfos){
|
||||
String promotionCode = paymentInfo.getPromotionCode();
|
||||
Float sum = codeAmount.get(promotionCode);
|
||||
if (sum == null || sum == 0.0f){
|
||||
codeAmount.put(promotionCode, paymentInfo.getPayerTotal());
|
||||
}else {
|
||||
codeAmount.put(promotionCode, sum + paymentInfo.getPayerTotal());
|
||||
}
|
||||
}
|
||||
for (Map.Entry<String, Float> entry : codeAmount.entrySet()){
|
||||
String promotionCode = entry.getKey();
|
||||
ProductCoupons productCoupons = stripeService.getProductCoupon(promotionCode, null);
|
||||
if (!Objects.isNull(productCoupons)){
|
||||
// 2、计算支付金额的总和,更新totalEarnings,commission,unpaidCommission
|
||||
float sum = productCoupons.getTotalEarnings() + entry.getValue();
|
||||
productCoupons.setTotalEarnings(sum);
|
||||
float commission = sum * productCoupons.getCommissionRate() / 100;
|
||||
productCoupons.setCommission(commission);
|
||||
productCoupons.setUnpaidCommission(commission - productCoupons.getPaidCommission());
|
||||
productCouponsMapper.updateById(productCoupons);
|
||||
}
|
||||
}
|
||||
}
|
||||
redisUtil.addToString(RedisUtil.PAYMENT_INFO_LAST_SCAN_TIME, currentTime);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user