Merge branch 'dev/dev_xp' into dev/dev
This commit is contained in:
@@ -113,4 +113,10 @@ public class PaymentTask {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @Scheduled(cron = "0 */5 * * * *") // Run every 5 minutes
|
||||||
|
public void calcCouponsCommission(){
|
||||||
|
log.info("优惠券佣金计算定时器");
|
||||||
|
affiliateService.calcCouponsCommission();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,8 +4,13 @@ import com.ai.da.common.response.Response;
|
|||||||
import com.ai.da.common.utils.DateUtil;
|
import com.ai.da.common.utils.DateUtil;
|
||||||
import com.ai.da.common.utils.RedisUtil;
|
import com.ai.da.common.utils.RedisUtil;
|
||||||
import com.ai.da.common.utils.SendEmailUtil;
|
import com.ai.da.common.utils.SendEmailUtil;
|
||||||
|
import com.ai.da.mapper.primary.entity.ProductCoupons;
|
||||||
|
import com.ai.da.model.dto.CreateCouponDTO;
|
||||||
import com.ai.da.model.dto.ProductPurchaseDTO;
|
import com.ai.da.model.dto.ProductPurchaseDTO;
|
||||||
|
import com.ai.da.model.dto.QueryCouponsPageDTO;
|
||||||
|
import com.ai.da.model.vo.CheckCouponsVO;
|
||||||
import com.ai.da.service.StripeService;
|
import com.ai.da.service.StripeService;
|
||||||
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
import com.paypal.http.HttpResponse;
|
import com.paypal.http.HttpResponse;
|
||||||
import com.paypal.payments.Refund;
|
import com.paypal.payments.Refund;
|
||||||
import com.stripe.exception.StripeException;
|
import com.stripe.exception.StripeException;
|
||||||
@@ -99,6 +104,36 @@ public class StripeController {
|
|||||||
stripeService.cancelSubscription(subscriptionId, reason);
|
stripeService.cancelSubscription(subscriptionId, reason);
|
||||||
return Response.success("success");
|
return Response.success("success");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ApiOperation("创建推广码")
|
||||||
|
@PostMapping("/createCoupon")
|
||||||
|
public Response<String> createCoupon(@Valid @RequestBody CreateCouponDTO createCouponDTO){
|
||||||
|
return Response.success(stripeService.createCoupon(createCouponDTO));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("检查推广码")
|
||||||
|
@GetMapping("/checkCoupon")
|
||||||
|
public Response<CheckCouponsVO> checkCoupon(@RequestParam String promotionCode, @RequestParam Long price){
|
||||||
|
return Response.success(stripeService.checkProductCoupon(promotionCode, price));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("获取所有推广码")
|
||||||
|
@PostMapping("/getAllCoupons")
|
||||||
|
public Response<IPage<ProductCoupons>> getAllCoupons(@RequestBody QueryCouponsPageDTO queryCouponsPageDTO){
|
||||||
|
return Response.success(stripeService.getAllCoupons(queryCouponsPageDTO));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("检索优惠券")
|
||||||
|
@GetMapping("/retrieveCoupon")
|
||||||
|
public Response<String> retrieveCoupon(@RequestParam String couponId){
|
||||||
|
return Response.success(stripeService.retrieveCoupon(couponId));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("检索推广码")
|
||||||
|
@GetMapping("/retrievePromotionCode")
|
||||||
|
public Response<String> retrievePromotionCode(@RequestParam String retrievePromotionCode){
|
||||||
|
return Response.success(stripeService.retrievePromotionCode(retrievePromotionCode));
|
||||||
|
}
|
||||||
/*@ApiOperation("临时 取消订阅")
|
/*@ApiOperation("临时 取消订阅")
|
||||||
@GetMapping("/cancelSubscriptionTemp")
|
@GetMapping("/cancelSubscriptionTemp")
|
||||||
public Response<String> cancelSubscriptionTemp(@RequestParam String subscriptionId) {
|
public Response<String> cancelSubscriptionTemp(@RequestParam String subscriptionId) {
|
||||||
|
|||||||
@@ -29,4 +29,6 @@ public interface PaymentInfoMapper extends BaseMapper<PaymentInfo> {
|
|||||||
List<Map<String, String>> getCountries();
|
List<Map<String, String>> getCountries();
|
||||||
|
|
||||||
int insertIgnore(@Param("paymentInfo")PaymentInfo paymentInfo);
|
int insertIgnore(@Param("paymentInfo")PaymentInfo paymentInfo);
|
||||||
|
|
||||||
|
List<PaymentInfo> selectPaidPaymentsByAccountAndPromotion(Long accountId, String promotionCode);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,4 +47,6 @@ public class PaymentInfo extends BaseEntity{
|
|||||||
private String country;
|
private String country;
|
||||||
|
|
||||||
private String city;
|
private String city;
|
||||||
|
|
||||||
|
private String promotionCode;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ public class ProductCoupons extends BaseEntity{
|
|||||||
// 对应的推广码
|
// 对应的推广码
|
||||||
private String promotionCode;
|
private String promotionCode;
|
||||||
// 最大兑换次数
|
// 最大兑换次数
|
||||||
private Integer maxRedemptions;
|
private Long maxRedemptions;
|
||||||
// 优惠券的折扣
|
// 优惠券的折扣
|
||||||
private float percentOff;
|
private float percentOff;
|
||||||
// 佣金比例
|
// 佣金比例
|
||||||
@@ -38,11 +38,12 @@ public class ProductCoupons extends BaseEntity{
|
|||||||
public ProductCoupons() {
|
public ProductCoupons() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public ProductCoupons(String couponId, Long redeemBy, String promotionCodeId, String promotionCode, float percentOff, float commissionRate) {
|
public ProductCoupons(String couponId, Long redeemBy, String promotionCodeId, String promotionCode, Long maxRedemptions, float percentOff, float commissionRate) {
|
||||||
this.couponId = couponId;
|
this.couponId = couponId;
|
||||||
this.redeemBy = redeemBy;
|
this.redeemBy = redeemBy;
|
||||||
this.promotionCodeId = promotionCodeId;
|
this.promotionCodeId = promotionCodeId;
|
||||||
this.promotionCode = promotionCode;
|
this.promotionCode = promotionCode;
|
||||||
|
this.maxRedemptions = maxRedemptions;
|
||||||
this.percentOff = percentOff;
|
this.percentOff = percentOff;
|
||||||
this.commissionRate = commissionRate;
|
this.commissionRate = commissionRate;
|
||||||
}
|
}
|
||||||
|
|||||||
20
src/main/java/com/ai/da/model/dto/CreateCouponDTO.java
Normal file
20
src/main/java/com/ai/da/model/dto/CreateCouponDTO.java
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
package com.ai.da.model.dto;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class CreateCouponDTO {
|
||||||
|
@ApiModelProperty("折扣率")
|
||||||
|
@NotNull(message = "Please set the percentOff")
|
||||||
|
private Float percentOff;
|
||||||
|
@ApiModelProperty("佣金比例")
|
||||||
|
@NotNull(message = "Please set the commissionRate.")
|
||||||
|
private Float commissionRate;
|
||||||
|
@ApiModelProperty("推广码到期时间 秒级时间戳")
|
||||||
|
private Long timestamp;
|
||||||
|
@ApiModelProperty("推广码最大使用次数")
|
||||||
|
private Long maxRedemptions;
|
||||||
|
}
|
||||||
@@ -30,4 +30,7 @@ public class ProductPurchaseDTO {
|
|||||||
|
|
||||||
@ApiModelProperty("使用Alipay-HK时需要选择 ALIPAYHK || ALIPAYCN")
|
@ApiModelProperty("使用Alipay-HK时需要选择 ALIPAYHK || ALIPAYCN")
|
||||||
private String wallet;
|
private String wallet;
|
||||||
|
|
||||||
|
@ApiModelProperty("优惠码")
|
||||||
|
private String promotionCode;
|
||||||
}
|
}
|
||||||
|
|||||||
18
src/main/java/com/ai/da/model/vo/CheckCouponsVO.java
Normal file
18
src/main/java/com/ai/da/model/vo/CheckCouponsVO.java
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
package com.ai.da.model.vo;
|
||||||
|
|
||||||
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class CheckCouponsVO {
|
||||||
|
|
||||||
|
@ApiModelProperty("expired || invalid || valid")
|
||||||
|
private String status;
|
||||||
|
|
||||||
|
private String message;
|
||||||
|
|
||||||
|
private Float discountedPrice;
|
||||||
|
}
|
||||||
@@ -29,4 +29,6 @@ public interface AffiliateService extends IService<Affiliate> {
|
|||||||
Affiliate getByAccountId(Long accountId);
|
Affiliate getByAccountId(Long accountId);
|
||||||
|
|
||||||
void commissionCalculation(Integer year, Integer month);
|
void commissionCalculation(Integer year, Integer month);
|
||||||
|
|
||||||
|
void calcCouponsCommission();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,4 +32,6 @@ public interface PaymentInfoService extends IService<PaymentInfo> {
|
|||||||
void updatePaymentStatusById(Long id, String status, String content);
|
void updatePaymentStatusById(Long id, String status, String content);
|
||||||
|
|
||||||
PageBaseResponse<OrderListVO> getPaymentInfo(QueryPageByTimeDTO queryPageByTimeDTO);
|
PageBaseResponse<OrderListVO> getPaymentInfo(QueryPageByTimeDTO queryPageByTimeDTO);
|
||||||
|
|
||||||
|
List<PaymentInfo> getPaymentInfoByPromCode(Long accountId, String promCode);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,12 @@
|
|||||||
package com.ai.da.service;
|
package com.ai.da.service;
|
||||||
|
|
||||||
|
import com.ai.da.mapper.primary.entity.ProductCoupons;
|
||||||
import com.ai.da.mapper.primary.entity.SubscriptionInfo;
|
import com.ai.da.mapper.primary.entity.SubscriptionInfo;
|
||||||
|
import com.ai.da.model.dto.CreateCouponDTO;
|
||||||
import com.ai.da.model.dto.ProductPurchaseDTO;
|
import com.ai.da.model.dto.ProductPurchaseDTO;
|
||||||
|
import com.ai.da.model.dto.QueryCouponsPageDTO;
|
||||||
|
import com.ai.da.model.vo.CheckCouponsVO;
|
||||||
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
import com.stripe.exception.StripeException;
|
import com.stripe.exception.StripeException;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
@@ -51,4 +56,16 @@ public interface StripeService {
|
|||||||
// Map getIp(HttpServletRequest request);
|
// Map getIp(HttpServletRequest request);
|
||||||
|
|
||||||
String getStackTrace(Exception e, int maxLines);
|
String getStackTrace(Exception e, int maxLines);
|
||||||
|
|
||||||
|
String createCoupon(CreateCouponDTO createCouponDTO);
|
||||||
|
|
||||||
|
CheckCouponsVO checkProductCoupon(String promotionCode, Long price);
|
||||||
|
|
||||||
|
ProductCoupons getProductCoupon(String promotionCode, String promotionCodeId);
|
||||||
|
|
||||||
|
String retrieveCoupon(String couponId);
|
||||||
|
|
||||||
|
String retrievePromotionCode(String promotionCode);
|
||||||
|
|
||||||
|
IPage<ProductCoupons> getAllCoupons(QueryCouponsPageDTO queryCouponsPageDTO);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import com.ai.da.common.utils.RedisUtil;
|
|||||||
import com.ai.da.common.utils.SendEmailUtil;
|
import com.ai.da.common.utils.SendEmailUtil;
|
||||||
import com.ai.da.mapper.primary.AffiliateIncomeMapper;
|
import com.ai.da.mapper.primary.AffiliateIncomeMapper;
|
||||||
import com.ai.da.mapper.primary.AffiliateMapper;
|
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.SubscriptionInfoMapper;
|
||||||
import com.ai.da.mapper.primary.entity.*;
|
import com.ai.da.mapper.primary.entity.*;
|
||||||
import com.ai.da.model.dto.AffiliateEmailParamsDTO;
|
import com.ai.da.model.dto.AffiliateEmailParamsDTO;
|
||||||
@@ -17,10 +18,7 @@ import com.ai.da.model.dto.AffiliateQueryDTO;
|
|||||||
import com.ai.da.model.vo.AffiliateInvitationDetailsVO;
|
import com.ai.da.model.vo.AffiliateInvitationDetailsVO;
|
||||||
import com.ai.da.model.vo.AffiliateVO;
|
import com.ai.da.model.vo.AffiliateVO;
|
||||||
import com.ai.da.model.vo.AuthPrincipalVo;
|
import com.ai.da.model.vo.AuthPrincipalVo;
|
||||||
import com.ai.da.service.AccountService;
|
import com.ai.da.service.*;
|
||||||
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.conditions.query.QueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
@@ -34,9 +32,7 @@ import org.springframework.util.CollectionUtils;
|
|||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.List;
|
import java.util.*;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@@ -45,19 +41,18 @@ public class AffiliateServiceImpl extends ServiceImpl<AffiliateMapper, Affiliate
|
|||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private OrderInfoService orderInfoService;
|
private OrderInfoService orderInfoService;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private AccountService accountService;
|
private AccountService accountService;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private PaymentInfoService paymentInfoService;
|
private PaymentInfoService paymentInfoService;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private SubscriptionInfoMapper subscriptionInfoMapper;
|
private SubscriptionInfoMapper subscriptionInfoMapper;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private AffiliateIncomeMapper affiliateIncomeMapper;
|
private AffiliateIncomeMapper affiliateIncomeMapper;
|
||||||
|
@Resource
|
||||||
|
private StripeService stripeService;
|
||||||
|
@Resource
|
||||||
|
private ProductCouponsMapper productCouponsMapper;
|
||||||
@Resource
|
@Resource
|
||||||
private RedisUtil redisUtil;
|
private RedisUtil redisUtil;
|
||||||
|
|
||||||
@@ -328,5 +323,47 @@ public class AffiliateServiceImpl extends ServiceImpl<AffiliateMapper, Affiliate
|
|||||||
return baseMapper.selectOne(queryWrapper);
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import com.ai.da.common.response.PageBaseResponse;
|
|||||||
import com.ai.da.mapper.primary.PaymentInfoMapper;
|
import com.ai.da.mapper.primary.PaymentInfoMapper;
|
||||||
import com.ai.da.mapper.primary.entity.OrderInfo;
|
import com.ai.da.mapper.primary.entity.OrderInfo;
|
||||||
import com.ai.da.mapper.primary.entity.PaymentInfo;
|
import com.ai.da.mapper.primary.entity.PaymentInfo;
|
||||||
|
import com.ai.da.mapper.primary.entity.ProductCoupons;
|
||||||
import com.ai.da.model.dto.AlipayHKCallbackDTO;
|
import com.ai.da.model.dto.AlipayHKCallbackDTO;
|
||||||
import com.ai.da.model.dto.QueryPageByTimeDTO;
|
import com.ai.da.model.dto.QueryPageByTimeDTO;
|
||||||
import com.ai.da.model.vo.OrderListVO;
|
import com.ai.da.model.vo.OrderListVO;
|
||||||
@@ -232,20 +233,27 @@ public class PaymentInfoServiceImpl extends ServiceImpl<PaymentInfoMapper, Payme
|
|||||||
qw.eq("transaction_id", invoiceId);
|
qw.eq("transaction_id", invoiceId);
|
||||||
PaymentInfo paymentInfo = baseMapper.selectOne(qw);
|
PaymentInfo paymentInfo = baseMapper.selectOne(qw);
|
||||||
String status = invoice.getStatus();
|
String status = invoice.getStatus();
|
||||||
|
// 判断是否有优惠码
|
||||||
|
String promotionCode = null;
|
||||||
|
if (Objects.nonNull(invoice.getDiscount()) && !StringUtil.isNullOrEmpty(invoice.getDiscount().getPromotionCode())){
|
||||||
|
ProductCoupons productCoupon = stripeService.getProductCoupon(null, invoice.getDiscount().getPromotionCode());
|
||||||
|
promotionCode = productCoupon.getPromotionCode();
|
||||||
|
}
|
||||||
// 判断当前支付是否已经被记录,确保同一个支付不会被重复记录
|
// 判断当前支付是否已经被记录,确保同一个支付不会被重复记录
|
||||||
if (Objects.isNull(paymentInfo)){
|
if (Objects.isNull(paymentInfo)){
|
||||||
String orderNo;
|
String orderNo;
|
||||||
try {
|
try {
|
||||||
String chargeId = invoice.getCharge();
|
if (invoice.getBillingReason().equals("manual")){
|
||||||
orderNo = Charge.retrieve(chargeId).getDescription().replace("AiDA - ", "");
|
// 手动创建的发票,针对one-time支付
|
||||||
// if (invoice.getBillingReason().equals("manual")){
|
// orderNo = invoice.getLines().getData().get(0).getPrice().getMetadata().get("orderId");
|
||||||
// // 手动创建的发票,针对one-time支付
|
// 当支付失败时,chargeId为空
|
||||||
//// orderNo = invoice.getLines().getData().get(0).getPrice().getMetadata().get("orderId");
|
String chargeId = invoice.getCharge();
|
||||||
// }else {
|
orderNo = Charge.retrieve(chargeId).getDescription().replace("AiDA - ", "");
|
||||||
// String subscriptionId = invoice.getSubscription();
|
}else {
|
||||||
// // 从subscription中获取orderNo
|
String subscriptionId = invoice.getSubscription();
|
||||||
// orderNo = Subscription.retrieve(subscriptionId).getDescription().replace("AiDA - ", "");
|
// 从subscription中获取orderNo
|
||||||
// }
|
orderNo = Subscription.retrieve(subscriptionId).getDescription().replace("AiDA - ", "");
|
||||||
|
}
|
||||||
} catch (StripeException e) {
|
} catch (StripeException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
@@ -281,6 +289,7 @@ public class PaymentInfoServiceImpl extends ServiceImpl<PaymentInfoMapper, Payme
|
|||||||
paymentInfo.setPaymentMethod(paymentMethod.get("paymentMethod"));
|
paymentInfo.setPaymentMethod(paymentMethod.get("paymentMethod"));
|
||||||
paymentInfo.setLast4(paymentMethod.get("last4"));
|
paymentInfo.setLast4(paymentMethod.get("last4"));
|
||||||
paymentInfo.setHostedInvoiceUrl(invoice.getHostedInvoiceUrl());
|
paymentInfo.setHostedInvoiceUrl(invoice.getHostedInvoiceUrl());
|
||||||
|
paymentInfo.setPromotionCode(promotionCode);
|
||||||
paymentInfo.setCreateTime(LocalDateTime.now());
|
paymentInfo.setCreateTime(LocalDateTime.now());
|
||||||
if (!Objects.isNull(orderByOrderNo)){
|
if (!Objects.isNull(orderByOrderNo)){
|
||||||
paymentInfo.setCountry(orderByOrderNo.getCountry());
|
paymentInfo.setCountry(orderByOrderNo.getCountry());
|
||||||
@@ -291,6 +300,7 @@ public class PaymentInfoServiceImpl extends ServiceImpl<PaymentInfoMapper, Payme
|
|||||||
log.info("Payment Info insert affect rows:{}", row);
|
log.info("Payment Info insert affect rows:{}", row);
|
||||||
}else {
|
}else {
|
||||||
paymentInfo.setTradeState(status);
|
paymentInfo.setTradeState(status);
|
||||||
|
paymentInfo.setPromotionCode(promotionCode);
|
||||||
paymentInfo.setUpdateTime(LocalDateTime.now());
|
paymentInfo.setUpdateTime(LocalDateTime.now());
|
||||||
baseMapper.updateById(paymentInfo);
|
baseMapper.updateById(paymentInfo);
|
||||||
}
|
}
|
||||||
@@ -421,4 +431,8 @@ public class PaymentInfoServiceImpl extends ServiceImpl<PaymentInfoMapper, Payme
|
|||||||
return PageBaseResponse.success(orderListVOIPage);
|
return PageBaseResponse.success(orderListVOIPage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<PaymentInfo> getPaymentInfoByPromCode(Long accountId, String promCode){
|
||||||
|
return baseMapper.selectPaidPaymentsByAccountAndPromotion(accountId, promCode);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,14 +8,20 @@ import com.ai.da.common.utils.DateUtil;
|
|||||||
import com.ai.da.common.utils.SendEmailUtil;
|
import com.ai.da.common.utils.SendEmailUtil;
|
||||||
import com.ai.da.mapper.primary.AccountMapper;
|
import com.ai.da.mapper.primary.AccountMapper;
|
||||||
import com.ai.da.mapper.primary.PaymentInfoMapper;
|
import com.ai.da.mapper.primary.PaymentInfoMapper;
|
||||||
|
import com.ai.da.mapper.primary.ProductCouponsMapper;
|
||||||
import com.ai.da.mapper.primary.SubscriptionInfoMapper;
|
import com.ai.da.mapper.primary.SubscriptionInfoMapper;
|
||||||
import com.ai.da.mapper.primary.entity.*;
|
import com.ai.da.mapper.primary.entity.*;
|
||||||
|
import com.ai.da.model.dto.CreateCouponDTO;
|
||||||
import com.ai.da.model.dto.ProductPurchaseDTO;
|
import com.ai.da.model.dto.ProductPurchaseDTO;
|
||||||
|
import com.ai.da.model.dto.QueryCouponsPageDTO;
|
||||||
import com.ai.da.model.dto.SubscriptionEmailParamsDTO;
|
import com.ai.da.model.dto.SubscriptionEmailParamsDTO;
|
||||||
|
import com.ai.da.model.vo.CheckCouponsVO;
|
||||||
import com.ai.da.service.*;
|
import com.ai.da.service.*;
|
||||||
import com.alibaba.fastjson.JSON;
|
import com.alibaba.fastjson.JSON;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
|
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.stripe.Stripe;
|
import com.stripe.Stripe;
|
||||||
import com.stripe.exception.SignatureVerificationException;
|
import com.stripe.exception.SignatureVerificationException;
|
||||||
@@ -67,6 +73,8 @@ public class StripeServiceImpl implements StripeService {
|
|||||||
private SubscriptionInfoMapper subscriptionInfoMapper;
|
private SubscriptionInfoMapper subscriptionInfoMapper;
|
||||||
@Resource
|
@Resource
|
||||||
private PaymentInfoMapper paymentInfoMapper;
|
private PaymentInfoMapper paymentInfoMapper;
|
||||||
|
@Resource
|
||||||
|
private ProductCouponsMapper productCouponsMapper;
|
||||||
|
|
||||||
@Value("${stripe.private-key}")
|
@Value("${stripe.private-key}")
|
||||||
private String privateKey;
|
private String privateKey;
|
||||||
@@ -85,6 +93,9 @@ public class StripeServiceImpl implements StripeService {
|
|||||||
public String pay(ProductPurchaseDTO productPurchaseDTO, HttpServletRequest request) {
|
public String pay(ProductPurchaseDTO productPurchaseDTO, HttpServletRequest request) {
|
||||||
Stripe.apiKey = privateKey;
|
Stripe.apiKey = privateKey;
|
||||||
|
|
||||||
|
//创建支付信息得到url
|
||||||
|
// 一次性支付和周期扣款,需要区分mode: payment || subscription || setup
|
||||||
|
SessionCreateParams.Builder sessionBuilder = new SessionCreateParams.Builder();
|
||||||
ProductEnum productEnum;
|
ProductEnum productEnum;
|
||||||
switch (productPurchaseDTO.getProductName()){
|
switch (productPurchaseDTO.getProductName()){
|
||||||
case "CreditsPurchase":
|
case "CreditsPurchase":
|
||||||
@@ -105,6 +116,8 @@ public class StripeServiceImpl implements StripeService {
|
|||||||
default:
|
default:
|
||||||
throw new BusinessException("unknown subscription type");
|
throw new BusinessException("unknown subscription type");
|
||||||
}
|
}
|
||||||
|
// 只有订阅时才允许使用推广码优惠
|
||||||
|
// sessionBuilder.setAllowPromotionCodes(true);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new BusinessException("unknown product type");
|
throw new BusinessException("unknown product type");
|
||||||
@@ -131,12 +144,11 @@ public class StripeServiceImpl implements StripeService {
|
|||||||
String priceId = getPrice(productEnum.getPrice(), productId, payType, productPurchaseDTO.getSubscribeType());
|
String priceId = getPrice(productEnum.getPrice(), productId, payType, productPurchaseDTO.getSubscribeType());
|
||||||
// 获取或创建customer
|
// 获取或创建customer
|
||||||
String customerId = getCustomer(account.getUserName(), account.getUserEmail());
|
String customerId = getCustomer(account.getUserName(), account.getUserEmail());
|
||||||
|
log.info("customerId:{}", customerId);
|
||||||
// 获取自定义订单号
|
// 获取自定义订单号
|
||||||
String orderId = orderInfo.getOrderNo();
|
String orderId = orderInfo.getOrderNo();
|
||||||
|
|
||||||
//创建支付信息得到url
|
|
||||||
// 一次性支付和周期扣款,需要区分mode: payment || subscription || setup
|
|
||||||
SessionCreateParams.Builder sessionBuilder = new SessionCreateParams.Builder();
|
|
||||||
if (payType.equals("recurring")){
|
if (payType.equals("recurring")){
|
||||||
sessionBuilder.setMode(SessionCreateParams.Mode.SUBSCRIPTION);
|
sessionBuilder.setMode(SessionCreateParams.Mode.SUBSCRIPTION);
|
||||||
sessionBuilder.setSubscriptionData(SessionCreateParams.SubscriptionData.builder().setDescription("AiDA - " + orderId).build());
|
sessionBuilder.setSubscriptionData(SessionCreateParams.SubscriptionData.builder().setDescription("AiDA - " + orderId).build());
|
||||||
@@ -148,8 +160,6 @@ public class StripeServiceImpl implements StripeService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sessionBuilder.setPaymentMethodConfiguration(paymentMethodConfigurationId);
|
sessionBuilder.setPaymentMethodConfiguration(paymentMethodConfigurationId);
|
||||||
// sessionBuilder.addPaymentMethodType(SessionCreateParams.PaymentMethodType.ALIPAY);
|
|
||||||
// sessionBuilder.addPaymentMethodType(SessionCreateParams.PaymentMethodType.CARD);
|
|
||||||
sessionBuilder.setCustomer(customerId);
|
sessionBuilder.setCustomer(customerId);
|
||||||
sessionBuilder.setSuccessUrl(productPurchaseDTO.getReturnUrl());//可自定义成功页面
|
sessionBuilder.setSuccessUrl(productPurchaseDTO.getReturnUrl());//可自定义成功页面
|
||||||
sessionBuilder.setLocale(account.getLanguage().equals("CHINESE_SIMPLIFIED") ? SessionCreateParams.Locale.ZH : SessionCreateParams.Locale.EN);
|
sessionBuilder.setLocale(account.getLanguage().equals("CHINESE_SIMPLIFIED") ? SessionCreateParams.Locale.ZH : SessionCreateParams.Locale.EN);
|
||||||
@@ -160,6 +170,16 @@ public class StripeServiceImpl implements StripeService {
|
|||||||
.build());
|
.build());
|
||||||
sessionBuilder.putMetadata("orderId", orderId); //通过订单号关联用于检索支付信息(可选)
|
sessionBuilder.putMetadata("orderId", orderId); //通过订单号关联用于检索支付信息(可选)
|
||||||
|
|
||||||
|
// 添加优惠券
|
||||||
|
String promotionCode = productPurchaseDTO.getPromotionCode();
|
||||||
|
if (!StringUtil.isNullOrEmpty(promotionCode)){
|
||||||
|
ProductCoupons productCoupon = checkProductCoupon(promotionCode);;
|
||||||
|
if (productCoupon != null){
|
||||||
|
sessionBuilder.addDiscount(SessionCreateParams.Discount.builder()
|
||||||
|
.setPromotionCode(productCoupon.getPromotionCodeId()).build());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Session session = Session.create(sessionBuilder.build());
|
Session session = Session.create(sessionBuilder.build());
|
||||||
List<String> paymentMethodTypes = session.getPaymentMethodTypes();
|
List<String> paymentMethodTypes = session.getPaymentMethodTypes();
|
||||||
log.info("paymentMethodTypes: {}", paymentMethodTypes);
|
log.info("paymentMethodTypes: {}", paymentMethodTypes);
|
||||||
@@ -171,6 +191,8 @@ public class StripeServiceImpl implements StripeService {
|
|||||||
// 更新order信息
|
// 更新order信息
|
||||||
orderInfoService.updateOrderNoById(orderInfo.getId(), orderId);
|
orderInfoService.updateOrderNoById(orderInfo.getId(), orderId);
|
||||||
return session.getUrl();
|
return session.getUrl();
|
||||||
|
} catch (BusinessException e) {
|
||||||
|
throw e;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("创建支付会话出现异常:", e);
|
log.error("创建支付会话出现异常:", e);
|
||||||
}
|
}
|
||||||
@@ -1346,4 +1368,192 @@ public class StripeServiceImpl implements StripeService {
|
|||||||
}
|
}
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 优惠券实施:
|
||||||
|
* 1、由管理员创建优惠券,手动设置该优惠券对应的折扣
|
||||||
|
* 2、用户在订阅时,手动输入优惠码
|
||||||
|
* 3、使用stripe的字段 redeem_by 管理优惠券的有效期
|
||||||
|
* 4、promotion code与 coupons需要绑定
|
||||||
|
* 5、用户只能使用一次优惠券
|
||||||
|
*
|
||||||
|
* 问题:对于一次付款和订阅,优惠码是否可以混用
|
||||||
|
*/
|
||||||
|
public String createCoupon(CreateCouponDTO createCouponDTO){
|
||||||
|
Stripe.apiKey = privateKey;
|
||||||
|
CouponCreateParams.Builder couponParams = CouponCreateParams.builder()
|
||||||
|
// 任何客户只能用一次这个优惠券
|
||||||
|
.setDuration(CouponCreateParams.Duration.ONCE)
|
||||||
|
.setPercentOff(BigDecimal.valueOf(createCouponDTO.getPercentOff()));
|
||||||
|
if (Objects.nonNull(createCouponDTO.getTimestamp())){
|
||||||
|
couponParams.setRedeemBy(createCouponDTO.getTimestamp());
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
// 1、创建优惠券
|
||||||
|
Coupon coupon = Coupon.create(couponParams.build());
|
||||||
|
// 2、创建一个推广码
|
||||||
|
PromotionCode promotionCode = createPromotionCode(coupon.getId(), createCouponDTO.getMaxRedemptions());
|
||||||
|
// 3、落库
|
||||||
|
ProductCoupons productCoupons = new ProductCoupons(coupon.getId(), createCouponDTO.getTimestamp(), promotionCode.getId(),
|
||||||
|
promotionCode.getCode(), createCouponDTO.getMaxRedemptions(), createCouponDTO.getPercentOff(), createCouponDTO.getCommissionRate());
|
||||||
|
productCoupons.setCreateTime(LocalDateTime.now());
|
||||||
|
productCouponsMapper.insert(productCoupons);
|
||||||
|
|
||||||
|
return promotionCode.getCode();
|
||||||
|
} catch (StripeException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public PromotionCode createPromotionCode(String couponId, Long maxRedemption){
|
||||||
|
Stripe.apiKey = privateKey;
|
||||||
|
PromotionCodeCreateParams.Builder promotionCodeParams = PromotionCodeCreateParams.builder()
|
||||||
|
.setCoupon(couponId)
|
||||||
|
.setRestrictions(PromotionCodeCreateParams.Restrictions.builder().build());
|
||||||
|
if (Objects.nonNull(maxRedemption)){
|
||||||
|
promotionCodeParams.setMaxRedemptions(maxRedemption);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return PromotionCode.create(promotionCodeParams.build());
|
||||||
|
} catch (StripeException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProductCoupons checkProductCoupon(String promotionCode){
|
||||||
|
Stripe.apiKey = privateKey;
|
||||||
|
Long accountId = UserContext.getUserHolder().getId();
|
||||||
|
// 1、从数据库查找promotionCode对应的promotionCodeId
|
||||||
|
ProductCoupons productCoupons = productCouponsMapper.selectOne(new QueryWrapper<ProductCoupons>().eq("promotion_code", promotionCode));
|
||||||
|
if (Objects.nonNull(productCoupons)){
|
||||||
|
// 2、查绑定的Coupons是否存在以及是否过期
|
||||||
|
long epochSecondNow = Instant.now().getEpochSecond();
|
||||||
|
Long redeemBy = productCoupons.getRedeemBy();
|
||||||
|
if (redeemBy < epochSecondNow){
|
||||||
|
throw new BusinessException("this.promotion.code.has.expired");
|
||||||
|
} else {
|
||||||
|
// 判断该用户是否有成功使用过这个推广码
|
||||||
|
List<PaymentInfo> paymentInfoByPromCode = paymentInfoService.getPaymentInfoByPromCode(accountId, promotionCode);
|
||||||
|
if (!paymentInfoByPromCode.isEmpty()) {
|
||||||
|
// 已使用过推广码,状态无效
|
||||||
|
if (paymentInfoByPromCode.size() > 1) {
|
||||||
|
log.error("用户[{}]多次成功使用优惠码[{}]", accountId, promotionCode);
|
||||||
|
}
|
||||||
|
log.info("用户[{}]已成功使用过优惠码[{}]", accountId, promotionCode);
|
||||||
|
throw new BusinessException("one.time.limit.per.customer");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}else {
|
||||||
|
throw new BusinessException("this.promotion.code.is.invalid");
|
||||||
|
}
|
||||||
|
return productCoupons;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CheckCouponsVO checkProductCoupon(String promotionCode, Long price){
|
||||||
|
Stripe.apiKey = privateKey;
|
||||||
|
Long accountId = UserContext.getUserHolder().getId();
|
||||||
|
CheckCouponsVO checkCouponsVO = new CheckCouponsVO();
|
||||||
|
// 1、从数据库查找promotionCode对应的promotionCodeId
|
||||||
|
ProductCoupons productCoupons = productCouponsMapper.selectOne(new QueryWrapper<ProductCoupons>().eq("promotion_code", promotionCode));
|
||||||
|
if (Objects.nonNull(productCoupons)){
|
||||||
|
// 2、查绑定的Coupons是否存在以及是否过期
|
||||||
|
long epochSecondNow = Instant.now().getEpochSecond();
|
||||||
|
Long redeemBy = productCoupons.getRedeemBy();
|
||||||
|
if (redeemBy < epochSecondNow){
|
||||||
|
String msg = BusinessException.getMessageFromResource("this.promotion.code.has.expired");
|
||||||
|
checkCouponsVO.setMessage(msg);
|
||||||
|
checkCouponsVO.setStatus("expired");
|
||||||
|
}else {
|
||||||
|
// 判断该用户是否有成功使用过这个推广码
|
||||||
|
List<PaymentInfo> paymentInfoByPromCode = paymentInfoService.getPaymentInfoByPromCode(accountId, promotionCode);
|
||||||
|
if (paymentInfoByPromCode.isEmpty()) {
|
||||||
|
// 未使用过推广码,状态有效
|
||||||
|
checkCouponsVO.setStatus("valid");
|
||||||
|
checkCouponsVO.setDiscountedPrice(price * (1 - productCoupons.getPercentOff() / 100));
|
||||||
|
} else {
|
||||||
|
// 已使用过推广码,状态无效
|
||||||
|
if (paymentInfoByPromCode.size() > 1) {
|
||||||
|
log.error("用户[{}]多次成功使用优惠码[{}]", accountId, promotionCode);
|
||||||
|
}
|
||||||
|
log.info("用户[{}]已成功使用过优惠码[{}]", accountId, promotionCode);
|
||||||
|
String msg = BusinessException.getMessageFromResource("one.time.limit.per.customer");
|
||||||
|
checkCouponsVO.setMessage(msg);
|
||||||
|
checkCouponsVO.setStatus("invalid");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}else {
|
||||||
|
String msg = BusinessException.getMessageFromResource("this.promotion.code.is.invalid");
|
||||||
|
checkCouponsVO.setMessage(msg);
|
||||||
|
checkCouponsVO.setStatus("invalid");
|
||||||
|
}
|
||||||
|
return checkCouponsVO;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProductCoupons getProductCoupon(String promotionCode, String promotionCodeId){
|
||||||
|
Stripe.apiKey = privateKey;
|
||||||
|
QueryWrapper<ProductCoupons> qw = new QueryWrapper<>();
|
||||||
|
// 1、从数据库查找promotionCode对应的promotionCodeId
|
||||||
|
if (!StringUtil.isNullOrEmpty(promotionCode)){
|
||||||
|
qw.eq("promotion_code", promotionCode);
|
||||||
|
}
|
||||||
|
if (!StringUtil.isNullOrEmpty(promotionCodeId)){
|
||||||
|
qw.eq("promotion_code_id", promotionCodeId);
|
||||||
|
}
|
||||||
|
return productCouponsMapper.selectOne(qw);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String retrieveCoupon(String couponId){
|
||||||
|
Stripe.apiKey = privateKey;
|
||||||
|
try {
|
||||||
|
Coupon coupon = Coupon.retrieve(couponId);
|
||||||
|
log.info("retrieve的coupon: {}", coupon);
|
||||||
|
return JSON.toJSONString(coupon);
|
||||||
|
} catch (StripeException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String retrievePromotionCode(String promotionCode){
|
||||||
|
Stripe.apiKey = privateKey;
|
||||||
|
try {
|
||||||
|
ProductCoupons productCoupon = getProductCoupon(promotionCode, null);
|
||||||
|
PromotionCode retrieve = PromotionCode.retrieve(productCoupon.getPromotionCodeId());
|
||||||
|
log.info("retrieve的promotionCode: {}", retrieve);
|
||||||
|
return JSON.toJSONString(retrieve);
|
||||||
|
} catch (StripeException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public IPage<ProductCoupons> getAllCoupons(QueryCouponsPageDTO queryCouponsPageDTO){
|
||||||
|
// 分页 + 按条件查询
|
||||||
|
QueryWrapper<ProductCoupons> queryWrapper = new QueryWrapper<>();
|
||||||
|
if (!StringUtil.isNullOrEmpty(queryCouponsPageDTO.getOrderById()) && queryCouponsPageDTO.getOrderById().equals("DESC")){
|
||||||
|
queryWrapper.orderByDesc("id");
|
||||||
|
}
|
||||||
|
if (!StringUtil.isNullOrEmpty(queryCouponsPageDTO.getPromotionCode())){
|
||||||
|
queryWrapper.like("promotion_code", queryCouponsPageDTO.getPromotionCode());
|
||||||
|
}
|
||||||
|
if (Objects.nonNull(queryCouponsPageDTO.getIsExpired())){
|
||||||
|
long epochSecond = Instant.now().getEpochSecond();
|
||||||
|
if (queryCouponsPageDTO.getIsExpired()){
|
||||||
|
queryWrapper.lt("redeem_by", epochSecond);
|
||||||
|
}else {
|
||||||
|
queryWrapper.gt("redeem_by", epochSecond);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!StringUtil.isNullOrEmpty(queryCouponsPageDTO.getCooperator())){
|
||||||
|
queryWrapper.like("cooperator", queryCouponsPageDTO.getCooperator());
|
||||||
|
}
|
||||||
|
if (!StringUtil.isNullOrEmpty(queryCouponsPageDTO.getStartTime())){
|
||||||
|
queryWrapper.gt("create_time", queryCouponsPageDTO.getStartTime());
|
||||||
|
}
|
||||||
|
if (!StringUtil.isNullOrEmpty(queryCouponsPageDTO.getEndTime())){
|
||||||
|
queryWrapper.lt("create_time", queryCouponsPageDTO.getEndTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
return productCouponsMapper.selectPage(new Page<>(queryCouponsPageDTO.getPage(), queryCouponsPageDTO.getSize()), queryWrapper);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -167,11 +167,21 @@
|
|||||||
INSERT IGNORE INTO
|
INSERT IGNORE INTO
|
||||||
t_payment_info (order_no, transaction_id, payment_type, trade_state, payer_total,
|
t_payment_info (order_no, transaction_id, payment_type, trade_state, payer_total,
|
||||||
type, content, notified, payment_method, last4, hosted_invoice_url,
|
type, content, notified, payment_method, last4, hosted_invoice_url,
|
||||||
country, city, ip_address, create_time)
|
country, city, ip_address, promotion_code, create_time)
|
||||||
VALUES (#{paymentInfo.orderNo}, #{paymentInfo.transactionId}, #{paymentInfo.paymentType},
|
VALUES (#{paymentInfo.orderNo}, #{paymentInfo.transactionId}, #{paymentInfo.paymentType},
|
||||||
#{paymentInfo.tradeState}, #{paymentInfo.payerTotal},#{paymentInfo.type}, #{paymentInfo.content},
|
#{paymentInfo.tradeState}, #{paymentInfo.payerTotal},#{paymentInfo.type}, #{paymentInfo.content},
|
||||||
#{paymentInfo.notified},#{paymentInfo.paymentMethod}, #{paymentInfo.last4},#{paymentInfo.hostedInvoiceUrl},
|
#{paymentInfo.notified},#{paymentInfo.paymentMethod}, #{paymentInfo.last4},#{paymentInfo.hostedInvoiceUrl},
|
||||||
#{paymentInfo.country},#{paymentInfo.city},#{paymentInfo.ipAddress},#{paymentInfo.createTime});
|
#{paymentInfo.country},#{paymentInfo.city},#{paymentInfo.ipAddress},#{paymentInfo.promotionCode},#{paymentInfo.createTime});
|
||||||
</insert>
|
</insert>
|
||||||
|
|
||||||
|
<select id="selectPaidPaymentsByAccountAndPromotion" resultType="com.ai.da.mapper.primary.entity.PaymentInfo">
|
||||||
|
SELECT pi.*
|
||||||
|
FROM t_order_info oi
|
||||||
|
LEFT JOIN t_payment_info pi ON oi.order_no = pi.order_no
|
||||||
|
WHERE oi.account_id = #{accountId}
|
||||||
|
AND pi.promotion_code = #{promotionCode}
|
||||||
|
AND pi.trade_state = 'paid'
|
||||||
|
</select>
|
||||||
|
|
||||||
|
|
||||||
</mapper>
|
</mapper>
|
||||||
|
|||||||
@@ -153,6 +153,9 @@ generate.result.below.standard=The quality of the generated images currently fal
|
|||||||
partial.design.failed=Partial design failed, Please try again later.
|
partial.design.failed=Partial design failed, Please try again later.
|
||||||
email.count.limit=Rate limit reached. Retry in 1 hour.
|
email.count.limit=Rate limit reached. Retry in 1 hour.
|
||||||
model.path.cannot.be.empty=Model path cannot be empty.
|
model.path.cannot.be.empty=Model path cannot be empty.
|
||||||
|
this.promotion.code.has.expired=This promotion code has expired.
|
||||||
|
this.promotion.code.is.invalid=This promotion code is invalid.
|
||||||
|
one.time.limit.per.customer=This code has already been redeemed. Promo codes are limited to one-time use per customer.
|
||||||
|
|
||||||
# 可能会报异常
|
# 可能会报异常
|
||||||
# Informative:
|
# Informative:
|
||||||
|
|||||||
@@ -149,6 +149,9 @@ generate.result.below.standard=当前生成的图像质量低于标准。请考
|
|||||||
partial.design.failed=局部设计失败。请稍后重试。
|
partial.design.failed=局部设计失败。请稍后重试。
|
||||||
email.count.limit=您的账号触发邮件发送频率限制,请一小时后重试。
|
email.count.limit=您的账号触发邮件发送频率限制,请一小时后重试。
|
||||||
model.path.cannot.be.empty=模特路径不能为空
|
model.path.cannot.be.empty=模特路径不能为空
|
||||||
|
this.promotion.code.has.expired=该促销码已过期。
|
||||||
|
this.promotion.code.is.invalid=该促销码无效。
|
||||||
|
one.time.limit.per.customer=该码已兑换。每个促销码每位用户仅限使用一次。
|
||||||
|
|
||||||
# 可能会报异常
|
# 可能会报异常
|
||||||
# Informative:
|
# Informative:
|
||||||
|
|||||||
Reference in New Issue
Block a user