Affiliate功能-数据库表设计更新
This commit is contained in:
@@ -7,8 +7,6 @@ import com.ai.da.model.vo.AffiliateVO;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface AffiliateService extends IService<Affiliate> {
|
||||
|
||||
Boolean registerAsAnAffiliate(String promotionMethod);
|
||||
@@ -17,11 +15,17 @@ public interface AffiliateService extends IService<Affiliate> {
|
||||
|
||||
AffiliateVO personalAffiliateCenter();
|
||||
|
||||
double[] getPersonalMonthlyIncome(int year);
|
||||
|
||||
Boolean applicationApproval(Long id, Boolean isApproved);
|
||||
|
||||
void updateAffiliateInfoWithPayment();
|
||||
|
||||
Boolean affiliateLinkViewsIncrease(Long id);
|
||||
|
||||
List<AffiliateInvitationDetailsVO> getEachAffiliateGeneratedRevenue(Long affiliateId, String startTime, String endTime);
|
||||
IPage<AffiliateInvitationDetailsVO> getEachAffiliateGeneratedRevenue(AffiliateQueryDTO affiliateQueryDTO);
|
||||
|
||||
Affiliate getByAccountId(Long accountId);
|
||||
|
||||
void commissionCalculation(Integer year, Integer month);
|
||||
}
|
||||
|
||||
@@ -44,5 +44,7 @@ public interface StripeService {
|
||||
|
||||
boolean sendRenewalFailEmail(String invoiceId, String subscriptionId, String orderNo);
|
||||
|
||||
String getCustomerPaymentMethod(String name, String email);
|
||||
List<Map<String,String>> getCustomerPaymentMethod(String name, String email);
|
||||
|
||||
String detachCustomerAllPaymentMethod(String name, String email);
|
||||
}
|
||||
|
||||
@@ -107,6 +107,9 @@ public class AccountServiceImpl extends ServiceImpl<AccountMapper, Account> impl
|
||||
@Resource
|
||||
private StripeService stripeService;
|
||||
|
||||
@Resource
|
||||
private AffiliateService affiliateService;
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public AccountPreLoginVO preLogin(AccountPreLoginDTO accountDTO) {
|
||||
@@ -2428,6 +2431,10 @@ public class AccountServiceImpl extends ServiceImpl<AccountMapper, Account> impl
|
||||
response.setAutoRenewal(subscriptionInfo.getStatus().equals("active"));
|
||||
}
|
||||
|
||||
Affiliate affiliate = affiliateService.getByAccountId(accountId);
|
||||
if (!Objects.isNull(affiliate) && affiliate.getStatus().equals("Active")) {
|
||||
response.setAffiliate(true);
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,8 @@ 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.AccountMapper;
|
||||
import com.ai.da.mapper.primary.AffiliateIncomeMapper;
|
||||
import com.ai.da.mapper.primary.AffiliateMapper;
|
||||
import com.ai.da.mapper.primary.SubscriptionInfoMapper;
|
||||
import com.ai.da.mapper.primary.entity.*;
|
||||
@@ -31,9 +33,10 @@ import org.springframework.stereotype.Service;
|
||||
import javax.annotation.Resource;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Function;
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
@@ -51,6 +54,9 @@ public class AffiliateServiceImpl extends ServiceImpl<AffiliateMapper, Affiliate
|
||||
@Resource
|
||||
private SubscriptionInfoMapper subscriptionInfoMapper;
|
||||
|
||||
@Resource
|
||||
private AffiliateIncomeMapper affiliateIncomeMapper;
|
||||
|
||||
@Resource
|
||||
private RedisUtil redisUtil;
|
||||
|
||||
@@ -79,10 +85,13 @@ public class AffiliateServiceImpl extends ServiceImpl<AffiliateMapper, Affiliate
|
||||
}
|
||||
|
||||
public IPage<Affiliate> getAffiliateList(AffiliateQueryDTO affiliateQueryDTO){
|
||||
log.info("parameter => {}", affiliateQueryDTO.toString());
|
||||
QueryWrapper<Affiliate> qw = new QueryWrapper<>();
|
||||
qw.eq(!StringUtils.isNullOrEmpty(affiliateQueryDTO.getStatus()), "status", affiliateQueryDTO.getStatus());
|
||||
qw.gt(!StringUtils.isNullOrEmpty(affiliateQueryDTO.getStartTime()), "create_time", affiliateQueryDTO.getStartTime());
|
||||
qw.lt(!StringUtils.isNullOrEmpty(affiliateQueryDTO.getEndTime()), "create_time", affiliateQueryDTO.getEndTime());
|
||||
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");
|
||||
return baseMapper.selectPage(new Page<>(affiliateQueryDTO.getPage(), affiliateQueryDTO.getSize()), qw);
|
||||
}
|
||||
|
||||
@@ -96,6 +105,18 @@ public class AffiliateServiceImpl extends ServiceImpl<AffiliateMapper, Affiliate
|
||||
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){
|
||||
Affiliate affiliate = baseMapper.selectById(id);
|
||||
@@ -107,7 +128,7 @@ public class AffiliateServiceImpl extends ServiceImpl<AffiliateMapper, Affiliate
|
||||
affiliate.setApproved(true);
|
||||
affiliate.setLink(CommonConstant.AFFILIATE_LINK + affiliate.getId());
|
||||
} else {
|
||||
affiliate.setStatus("Inactive");
|
||||
affiliate.setStatus("Refused");
|
||||
affiliate.setApproved(false);
|
||||
}
|
||||
affiliate.setUpdateTime(LocalDateTime.now());
|
||||
@@ -142,6 +163,9 @@ public class AffiliateServiceImpl extends ServiceImpl<AffiliateMapper, Affiliate
|
||||
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<>();
|
||||
@@ -155,6 +179,7 @@ public class AffiliateServiceImpl extends ServiceImpl<AffiliateMapper, Affiliate
|
||||
// 3、若有, 直接更新affiliate的所得
|
||||
Affiliate affiliate = baseMapper.selectById(account.getInvitationCode());
|
||||
Float payerTotal = paymentInfo.getPayerTotal();
|
||||
|
||||
if (payerTotal > 0){
|
||||
// 分配新用户首次订阅所付费用的25%作为佣金
|
||||
BigDecimal commission = BigDecimal.valueOf(payerTotal).multiply(new BigDecimal("0.25"));
|
||||
@@ -168,6 +193,17 @@ public class AffiliateServiceImpl extends ServiceImpl<AffiliateMapper, Affiliate
|
||||
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.setPaymentTime(paymentInfo.getCreateTime());
|
||||
affiliateIncome.setCommission(commission.floatValue());
|
||||
affiliateIncome.setCreateTime(LocalDateTime.now());
|
||||
affiliateIncomeMapper.insert(affiliateIncome);
|
||||
}
|
||||
}
|
||||
orderInfo.setIsFirstSubscription((byte)1);
|
||||
@@ -190,51 +226,69 @@ public class AffiliateServiceImpl extends ServiceImpl<AffiliateMapper, Affiliate
|
||||
|
||||
// 查看每个affiliate带来收入的详情
|
||||
@Override
|
||||
public List<AffiliateInvitationDetailsVO> getEachAffiliateGeneratedRevenue(Long affiliateId, String startTime, String endTime) {
|
||||
List<AffiliateInvitationDetailsVO> resp = new ArrayList<>() ;
|
||||
// 1、从account表中找到所有关联了指定affiliateId的accountId
|
||||
QueryWrapper<Account> qw = new QueryWrapper<>();
|
||||
qw.eq("invitation_code", affiliateId);
|
||||
|
||||
List<Account> accountList = accountService.getBaseMapper().selectList(qw);
|
||||
if (accountList.isEmpty()){
|
||||
return null;
|
||||
} else {
|
||||
accountList.forEach(account -> {
|
||||
// 2、分别找到各个accountId产生的第一笔订阅
|
||||
Long accountId = account.getId();
|
||||
QueryWrapper<SubscriptionInfo> subscriptionInfoQueryWrapper = new QueryWrapper<>();
|
||||
subscriptionInfoQueryWrapper.eq("account_id", accountId)
|
||||
.and(s -> s.eq("status", "active").or().eq("status", "canceled"))
|
||||
.gt(!StringUtils.isNullOrEmpty(startTime) ,"create_time", startTime)
|
||||
.lt(!StringUtils.isNullOrEmpty(endTime) ,"create_time", endTime).last("limit 1");
|
||||
|
||||
SubscriptionInfo subscriptionInfo = subscriptionInfoMapper.selectOne(subscriptionInfoQueryWrapper);
|
||||
// 2、分别第一笔订阅的付款信息
|
||||
if (!Objects.isNull(subscriptionInfo)){
|
||||
PaymentInfo paymentInfo = paymentInfoService.getPaymentInfoByOrderNo(subscriptionInfo.getOrderNo(), "ASC").get(0);
|
||||
AffiliateInvitationDetailsVO affiliateInvitationDetailsVO = new AffiliateInvitationDetailsVO();
|
||||
affiliateInvitationDetailsVO.setAccountId(accountId);
|
||||
affiliateInvitationDetailsVO.setUsername(account.getUserName());
|
||||
affiliateInvitationDetailsVO.setFirstSubscriptionPaymentAmount(paymentInfo.getPayerTotal());
|
||||
affiliateInvitationDetailsVO.setCommission(BigDecimal.valueOf(paymentInfo.getPayerTotal()).multiply(new BigDecimal("0.25")).floatValue());
|
||||
affiliateInvitationDetailsVO.setTime(subscriptionInfo.getCreateTime());
|
||||
resp.add(affiliateInvitationDetailsVO);
|
||||
}
|
||||
});
|
||||
public IPage<AffiliateInvitationDetailsVO> getEachAffiliateGeneratedRevenue(AffiliateQueryDTO affiliateQueryDTO) {
|
||||
if (Objects.isNull(affiliateQueryDTO.getAffiliateId())){
|
||||
throw new BusinessException("Please specify the affiliate ID.", ResultEnum.PROMPT.getCode());
|
||||
}
|
||||
return resp;
|
||||
|
||||
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;
|
||||
});
|
||||
}
|
||||
|
||||
// todo 每个月给kim发一封邮件统计本月的affiliate等的收入
|
||||
public void commissionCalculation(){
|
||||
// 1、总收入(近一个月通过affiliate产生的收入)
|
||||
public void commissionCalculation(Integer year, Integer month) {
|
||||
if (Objects.isNull(year)) {
|
||||
year = LocalDateTime.now().getYear();
|
||||
}
|
||||
if (Objects.isNull(month)) {
|
||||
month = LocalDateTime.now().getMonthValue();
|
||||
}
|
||||
|
||||
// 2、未支付的金额 affiliate表中unpaid的总和
|
||||
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");
|
||||
}
|
||||
|
||||
// 3、邀请的新人 查询account表中,本月新增并有invitation_id的数量
|
||||
// 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 receiverEmail = "xupei3360@163.com";
|
||||
// String receiverEmail = "kimwong@code-create.com.hk";
|
||||
// 邮件通知
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1004,8 +1004,8 @@ public class StripeServiceImpl implements StripeService {
|
||||
try {
|
||||
OrderInfo orderInfo = orderInfoService.createOrderByProductId(1, PayTypeEnum.STRIPE.getType(), ProductEnum.DailySubscription);
|
||||
|
||||
String customerId = getCustomer(name, email);
|
||||
/* String paymentMethodCode = "pm_card_mastercard";
|
||||
// String customerId = getCustomer(name, email);
|
||||
String paymentMethodCode = "pm_card_mastercard";
|
||||
PaymentMethod paymentMethod = PaymentMethod.retrieve(paymentMethodCode);
|
||||
|
||||
String customerId = getCustomer(name, email);
|
||||
@@ -1014,14 +1014,14 @@ public class StripeServiceImpl implements StripeService {
|
||||
PaymentMethodAttachParams attachParams = PaymentMethodAttachParams.builder()
|
||||
.setCustomer(customerId)
|
||||
.build();
|
||||
paymentMethod.attach(attachParams);*/
|
||||
paymentMethod.attach(attachParams);
|
||||
|
||||
// 设置默认付款方式
|
||||
Customer updatedCustomer = Customer.retrieve(customerId);
|
||||
CustomerUpdateParams params = CustomerUpdateParams.builder()
|
||||
.setInvoiceSettings(
|
||||
CustomerUpdateParams.InvoiceSettings.builder()
|
||||
// .setDefaultPaymentMethod(paymentMethod.getId())
|
||||
.setDefaultPaymentMethod(paymentMethod.getId())
|
||||
.build()
|
||||
)
|
||||
.build();
|
||||
@@ -1081,19 +1081,54 @@ public class StripeServiceImpl implements StripeService {
|
||||
}
|
||||
}
|
||||
|
||||
public String getCustomerPaymentMethod(String name, String email){
|
||||
public List<Map<String,String>> getCustomerPaymentMethod(String name, String email){
|
||||
Stripe.apiKey = privateKey;
|
||||
try {
|
||||
String customerId = getCustomer(name, email);
|
||||
Customer customer = Customer.retrieve(customerId);
|
||||
PaymentMethodCollection paymentMethodCollection = customer.listPaymentMethods();
|
||||
List<PaymentMethod> data = paymentMethodCollection.getData();
|
||||
ArrayList<Map<String,String>> resp = new ArrayList<>();
|
||||
data.forEach(paymentMethod -> {
|
||||
Map<String,String> map = new HashMap<>();
|
||||
if (paymentMethod.getType().equals("card")){
|
||||
map.put(paymentMethod.getId(),paymentMethod.getCard().getLast4());
|
||||
}else {
|
||||
map.put(paymentMethod.getId(),null);
|
||||
}
|
||||
resp.add(map);
|
||||
});
|
||||
|
||||
// todo 方向: 向用户添加了多种付款方式,更改默认的付款方式后,默认付款方式付款失败后是否自动使用其他付款方式付款?
|
||||
return resp;
|
||||
// 方向: 向用户添加了多种付款方式,更改默认的付款方式后,默认付款方式付款失败后是否自动使用其他付款方式付款?
|
||||
// 如果是的,则需要删除能成功的付款方式,保留唯一失败的付款方式进行续订付款失败测试
|
||||
} catch (StripeException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public String detachCustomerAllPaymentMethod(String name, String email){
|
||||
Stripe.apiKey = privateKey;
|
||||
// 方向: 向用户添加了多种付款方式,更改默认的付款方式后,默认付款方式付款失败后是否自动使用其他付款方式付款?
|
||||
// 如果是的,则需要删除能成功的付款方式,保留唯一失败的付款方式进行续订付款失败测试
|
||||
try {
|
||||
String customerId = getCustomer(name, email);
|
||||
Customer customer = Customer.retrieve(customerId);
|
||||
PaymentMethodCollection paymentMethodCollection = customer.listPaymentMethods();
|
||||
List<PaymentMethod> data = paymentMethodCollection.getData();
|
||||
data.forEach(paymentMethod -> {
|
||||
try {
|
||||
PaymentMethod retrieve = PaymentMethod.retrieve(paymentMethod.getId());
|
||||
PaymentMethodDetachParams params = PaymentMethodDetachParams.builder().build();
|
||||
retrieve.detach(params);
|
||||
} catch (StripeException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
} catch (StripeException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -1102,8 +1137,10 @@ public class StripeServiceImpl implements StripeService {
|
||||
qw.eq("subscription_id", subscriptionId);
|
||||
SubscriptionInfo subscriptionInfo = subscriptionInfoMapper.selectOne(qw);
|
||||
|
||||
subscriptionInfo.setCancelReason(reason);
|
||||
subscriptionInfoMapper.updateById(subscriptionInfo);
|
||||
if (!Objects.isNull(subscriptionInfo)) {
|
||||
subscriptionInfo.setCancelReason(reason);
|
||||
subscriptionInfoMapper.updateById(subscriptionInfo);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user