Affiliate-新增、查询、佣金计算等

This commit is contained in:
2024-12-09 16:53:29 +08:00
parent 1b15aed6a2
commit 47ca7bde41
21 changed files with 561 additions and 57 deletions

View File

@@ -0,0 +1,22 @@
package com.ai.da.service;
import com.ai.da.mapper.primary.entity.Affiliate;
import com.ai.da.model.dto.AffiliateQueryDTO;
import com.ai.da.model.vo.AffiliateVO;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.IService;
public interface AffiliateService extends IService<Affiliate> {
Boolean registerAsAnAffiliate(String promotionMethod);
IPage<Affiliate> getAffiliateList(AffiliateQueryDTO affiliateQueryDTO);
AffiliateVO personalAffiliateCenter();
Boolean applicationApproval(Long id, Boolean isApproved);
void updateAffiliateInfoWithPayment();
Boolean affiliateLinkViewsIncrease(Long id);
}

View File

@@ -19,6 +19,8 @@ public interface StripeService {
List<String> getSubscriptionIds(String name, String userEmail) throws StripeException;
Map<String, String> getPaymentMethodByInvoiceId(String invoiceId);
void cancelSubscription(String orderNo);
void cancelSubscriptionTemp(String subscriptionId);
@@ -38,4 +40,6 @@ public interface StripeService {
String changeCustomerPayment(String name, String email);
boolean sendRenewalFailEmail(String invoiceId, String subscriptionId, String orderNo);
String getCustomerPaymentMethod(String name, String email);
}

View File

@@ -0,0 +1,189 @@
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.ResultEnum;
import com.ai.da.common.utils.CopyUtil;
import com.ai.da.common.utils.ObjectUtils;
import com.ai.da.common.utils.RedisUtil;
import com.ai.da.common.utils.SendEmailUtil;
import com.ai.da.mapper.primary.AffiliateMapper;
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.AffiliateVO;
import com.ai.da.model.vo.AuthPrincipalVo;
import com.ai.da.service.AccountService;
import com.ai.da.service.AffiliateService;
import com.ai.da.service.OrderInfoService;
import com.ai.da.service.PaymentInfoService;
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 io.netty.util.internal.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
@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 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());
baseMapper.insert(affiliate);
// 邮件通知审批者
// String email = "kimwong@code-create.com.hk";
String email = "xupei3360@163.com";
SendEmailUtil.affiliateEmailReminder(email, new AffiliateEmailParamsDTO(userHolder.getUsername(), promotionMethod), "new");
}else {
throw new BusinessException("You have registered an Affiliate", ResultEnum.PROMPT.getCode());
}
return true;
}
public IPage<Affiliate> getAffiliateList(AffiliateQueryDTO affiliateQueryDTO){
QueryWrapper<Affiliate> qw = new QueryWrapper<>();
qw.eq(affiliateQueryDTO.getStatus() != null, "status", affiliateQueryDTO.getStatus());
qw.gt(affiliateQueryDTO.getStartTime() != null, "create_time", affiliateQueryDTO.getStartTime());
qw.lt(affiliateQueryDTO.getEndTime() != null, "create_time", affiliateQueryDTO.getEndTime());
return baseMapper.selectPage(new Page<>(affiliateQueryDTO.getPage(), affiliateQueryDTO.getSize()), qw);
}
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(accountId));
return affiliateVO;
}
// 审批申请
public Boolean applicationApproval(Long id, Boolean isApproved){
Affiliate affiliate = baseMapper.selectById(id);
// 1、更新db状态
if (isApproved){
// 更新状态
affiliate.setStatus("Active");
affiliate.setApproved(true);
affiliate.setLink(CommonConstant.AFFILIATE_LINK + affiliate.getId());
} else {
affiliate.setStatus("Inactive");
affiliate.setApproved(false);
}
affiliate.setUpdateTime(LocalDateTime.now());
// 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 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());
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())){
// 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"));
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);
}
}
orderInfo.setIsFirstSubscription((byte)1);
orderInfo.setUpdateTime(LocalDateTime.now());
orderInfoService.updateById(orderInfo);
}
});
}
redisUtil.addToString(RedisUtil.PAYMENT_INFO_LAST_SCAN_TIME, currentTime);
}
public Boolean affiliateLinkViewsIncrease(Long id) {
redisUtil.increaseAffiliateLinkViewCount(id);
return Boolean.TRUE;
}
private Long getAffiliateLinkViewCount(Long accountId) {
return redisUtil.getAffiliateLinkViewCount(accountId);
}
// todo 每个月给kim发一封邮件统计本月的affiliate等的收入
public void commissionCalculation(){
}
}

View File

@@ -216,6 +216,8 @@ public class CollectionElementServiceImpl extends ServiceImpl<CollectionElementM
collectionElementMapper.deleteBatchIds(ids);
}
/** 该方法已不再使用 */
@Deprecated
@Override
public GenerateCollectionItemVO generatePrint(CollectionGeneratePrintDTO generatePrintDTO) {
Long userId = UserContext.getUserHolder().getId();
@@ -908,7 +910,7 @@ public class CollectionElementServiceImpl extends ServiceImpl<CollectionElementM
generate.setAccountId(userId);
generate.setLevel1Type(CollectionLevel1TypeEnum.PRINT_BOARD.getRealName());
generate.setGenerateType("synthesis");
generate.setModelName("Image Synthesis Model");
// generate.setModelName("Image Synthesis Model");
generate.setCreateDate(DateUtil.getByTimeZone(timeZone));
return generate;
}

View File

@@ -4,7 +4,7 @@ import com.ai.da.common.enums.PayTypeEnum;
import com.ai.da.mapper.primary.PaymentInfoMapper;
import com.ai.da.mapper.primary.entity.PaymentInfo;
import com.ai.da.model.dto.AlipayHKCallbackDTO;
import com.ai.da.service.PaymentInfoService;
import com.ai.da.service.*;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.gson.Gson;
@@ -19,6 +19,7 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
@@ -30,11 +31,8 @@ import java.util.Objects;
@Slf4j
public class PaymentInfoServiceImpl extends ServiceImpl<PaymentInfoMapper, PaymentInfo> implements PaymentInfoService {
private final StripeServiceImpl stripeServiceImpl;
public PaymentInfoServiceImpl(StripeServiceImpl stripeServiceImpl) {
this.stripeServiceImpl = stripeServiceImpl;
}
@Resource
private StripeService stripeService;
/**
* 记录支付日志:微信支付
@@ -220,7 +218,7 @@ public class PaymentInfoServiceImpl extends ServiceImpl<PaymentInfoMapper, Payme
String type = invoice.getBillingReason().equals("subscription_create") ? "new" :
invoice.getBillingReason().equals("subscription_cycle") ? "renewal" : invoice.getBillingReason();
Map<String, String> paymentMethod = stripeServiceImpl.getPaymentMethodByInvoiceId(invoiceId);
Map<String, String> paymentMethod = stripeService.getPaymentMethodByInvoiceId(invoiceId);
paymentInfo = new PaymentInfo();
paymentInfo.setOrderNo(orderNo);

View File

@@ -553,7 +553,8 @@ public class StripeServiceImpl implements StripeService {
Subscription cancel = subscription.cancel();
cancel.getStatus();
} catch (StripeException e) {
throw new RuntimeException(e);
log.error(e.getMessage());
// throw new RuntimeException(e);
}
}
@@ -988,7 +989,8 @@ public class StripeServiceImpl implements StripeService {
try {
OrderInfo orderInfo = orderInfoService.createOrderByProductId(1, PayTypeEnum.STRIPE.getType(), ProductEnum.DailySubscription);
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);
@@ -997,14 +999,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();
@@ -1064,4 +1066,22 @@ public class StripeServiceImpl implements StripeService {
}
}
public 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();
// todo 方向: 向用户添加了多种付款方式,更改默认的付款方式后,默认付款方式付款失败后是否自动使用其他付款方式付款?
// 如果是的,则需要删除能成功的付款方式,保留唯一失败的付款方式进行续订付款失败测试
} catch (StripeException e) {
throw new RuntimeException(e);
}
return null;
}
}