Compare commits
35 Commits
c649907222
...
release/3.
| Author | SHA1 | Date | |
|---|---|---|---|
| 3c2b4ffc48 | |||
| b90df7468e | |||
| 370d9402f2 | |||
| 4d518d05b9 | |||
| 13514b277b | |||
| d6c5d0e95d | |||
| 301a62a563 | |||
| 22e5a97143 | |||
| 765d404845 | |||
| d5cf4e9d3f | |||
| 4b7fd649a3 | |||
| 6249d53b7b | |||
| b445f1f11e | |||
| 5c66ece467 | |||
| 3b6b0c7e2c | |||
| 9a81fb7ee4 | |||
| 31bb29f2fd | |||
| c7b46229b5 | |||
| 1482bb6ab2 | |||
| eae4087b3e | |||
| faf98607c4 | |||
| c19e9094d1 | |||
| db55c5597f | |||
| 0c79739867 | |||
| e484f22788 | |||
| 6a694cee18 | |||
| 1a077edf0c | |||
|
|
68926757dc | ||
|
|
eea57435e5 | ||
| 1f0e8f9cf2 | |||
|
|
63ee41e3b8 | ||
|
|
08072001a7 | ||
| 6b4d82a67d | |||
| 5612b5b1d4 | |||
| 1d46a3b6d4 |
@@ -141,25 +141,27 @@ public class MyTaskScheduler {
|
||||
String fileName = "trialOrder-" + yesterday.format(DateTimeFormatter.ofPattern("yyyyMMdd")) + ".xlsx";
|
||||
try (FileOutputStream fileOut = new FileOutputStream(fileName)) {
|
||||
workbook.write(fileOut);
|
||||
SendEmailUtil.sendExcelEmail("1023316923@qq.com", null, Files.readAllBytes(Paths.get(fileName)), fileName);
|
||||
// SendEmailUtil.sendExcelEmail("1023316923@qq.com", null, Files.readAllBytes(Paths.get(fileName)), fileName);
|
||||
SendEmailUtil.sendExcelEmail("calvinwong@aidlab.hk", null, Files.readAllBytes(Paths.get(fileName)), fileName);
|
||||
SendEmailUtil.sendExcelEmail("kaicpang.pang@connect.polyu.hk", null, Files.readAllBytes(Paths.get(fileName)), fileName);
|
||||
SendEmailUtil.sendExcelEmail("kimwong@code-create.com.hk", null, Files.readAllBytes(Paths.get(fileName)), fileName);
|
||||
SendEmailUtil.sendExcelEmail("ningning@code-create.com.hk", null, Files.readAllBytes(Paths.get(fileName)), fileName);
|
||||
// SendEmailUtil.sendExcelEmail("ningning@code-create.com.hk", null, Files.readAllBytes(Paths.get(fileName)), fileName);
|
||||
SendEmailUtil.sendExcelEmail("johnnyho@code-create.com.hk", null, Files.readAllBytes(Paths.get(fileName)), fileName);
|
||||
SendEmailUtil.sendExcelEmail("ringolau@code-create.com.hk", null, Files.readAllBytes(Paths.get(fileName)), fileName);
|
||||
SendEmailUtil.sendExcelEmail("chelseayu@code-create.com.hk", null, Files.readAllBytes(Paths.get(fileName)), fileName);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}else {
|
||||
SendEmailUtil.sendNoExcelEmail("1023316923@qq.com", null);
|
||||
// SendEmailUtil.sendNoExcelEmail("1023316923@qq.com", null);
|
||||
SendEmailUtil.sendNoExcelEmail("calvinwong@aidlab.hk", null);
|
||||
SendEmailUtil.sendNoExcelEmail("kaicpang.pang@connect.polyu.hk", null);
|
||||
SendEmailUtil.sendNoExcelEmail("kimwong@code-create.com.hk", null);
|
||||
SendEmailUtil.sendNoExcelEmail("ningning@code-create.com.hk", null);
|
||||
// SendEmailUtil.sendNoExcelEmail("ningning@code-create.com.hk", null);
|
||||
SendEmailUtil.sendNoExcelEmail("johnnyho@code-create.com.hk", null);
|
||||
SendEmailUtil.sendNoExcelEmail("ringolau@code-create.com.hk", null);
|
||||
SendEmailUtil.sendNoExcelEmail("chelseayu@code-create.com.hk", null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,8 @@ public class CommonConstant {
|
||||
public static final Integer MINIO_IMAGE_EXPIRE_TIME = 24 * 60;
|
||||
// 单位 秒 一天过期 in redis
|
||||
public static final Long GENERATE_RESULT_EXPIRE_TIME = 24 * 60 * 60L;
|
||||
// 单位 秒 7天过期
|
||||
public static final Long REDIS_SET_EXPIRE_TIME = 24 * 60 * 60 * 7L;
|
||||
|
||||
public static class Numbers{
|
||||
public static final Integer NUMBER_10 = 10;
|
||||
@@ -79,5 +81,7 @@ public class CommonConstant {
|
||||
|
||||
public static final String TIME_FORMAT_MMM_dd_yyyy = "MMM. dd, yyyy";
|
||||
|
||||
public static final String TIME_FORMAT_yyyy_MM_dd_HH_mm_ss = "yyyy-MM-dd HH:mm:ss";
|
||||
|
||||
public static final String AFFILIATE_LINK = "https://www.aida.com.hk?ref=";
|
||||
}
|
||||
|
||||
@@ -31,7 +31,9 @@ public enum AuthenticationOperationTypeEnum {
|
||||
/**
|
||||
* 填写用户国家和职业
|
||||
*/
|
||||
UPDATE_USERINFO;
|
||||
UPDATE_USERINFO,
|
||||
|
||||
REGISTER;
|
||||
|
||||
public static AuthenticationOperationTypeEnum of(String name) {
|
||||
return Stream.of(AuthenticationOperationTypeEnum.values()).filter(v -> v.name().equals(name)).findFirst().orElse(null);
|
||||
|
||||
@@ -13,7 +13,7 @@ public enum ProductEnum {
|
||||
// 月度订阅
|
||||
MonthlySubscription("AiDA Monthly Subscription", 500L),
|
||||
// 测试
|
||||
DailySubscription("AiDA Daily Subscription", 5L),
|
||||
DailySubscription("AiDA Daily Subscription", 10L),
|
||||
;
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.ai.da.common.response;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@ApiModel("交易记录分页响应结果")
|
||||
public class TransactionPageResponse<T> extends PageBaseResponse<T> {
|
||||
|
||||
private BigDecimal totalAmount;
|
||||
}
|
||||
@@ -84,8 +84,9 @@ public class PaymentTask {
|
||||
}*/
|
||||
}
|
||||
|
||||
// !!关闭此定时器,改为提前三天站内信提醒!!
|
||||
// 提前7天向用户发送提醒邮件,每天早上8点执行
|
||||
@Scheduled(cron = "0 0 8 * * ?")
|
||||
// @Scheduled(cron = "0 0 8 * * ?")
|
||||
public void subscriptionReminder(){
|
||||
stripeService.subscriptionReminder();
|
||||
}
|
||||
@@ -113,4 +114,10 @@ public class PaymentTask {
|
||||
}
|
||||
}
|
||||
|
||||
@Scheduled(cron = "0 */5 * * * *") // Run every 5 minutes
|
||||
public void calcCouponsCommission(){
|
||||
// log.info("优惠券佣金计算定时器");
|
||||
affiliateService.calcCouponsCommission();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
package com.ai.da.common.utils;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class ComprehensivePunctuationConverter {
|
||||
private static final Map<Character, Character> FULL_TO_HALF_MAP = new HashMap<>();
|
||||
|
||||
static {
|
||||
// 中文标点到英文标点的映射(扩展版)
|
||||
FULL_TO_HALF_MAP.put(',', ',');
|
||||
FULL_TO_HALF_MAP.put('。', '.');
|
||||
FULL_TO_HALF_MAP.put(';', ';');
|
||||
FULL_TO_HALF_MAP.put(':', ':');
|
||||
FULL_TO_HALF_MAP.put('?', '?');
|
||||
FULL_TO_HALF_MAP.put('!', '!');
|
||||
FULL_TO_HALF_MAP.put('(', '(');
|
||||
FULL_TO_HALF_MAP.put(')', ')');
|
||||
FULL_TO_HALF_MAP.put('【', '[');
|
||||
FULL_TO_HALF_MAP.put('】', ']');
|
||||
FULL_TO_HALF_MAP.put('「', '\'');
|
||||
FULL_TO_HALF_MAP.put('」', '\'');
|
||||
FULL_TO_HALF_MAP.put('『', '"');
|
||||
FULL_TO_HALF_MAP.put('』', '"');
|
||||
FULL_TO_HALF_MAP.put('、', '\\');
|
||||
FULL_TO_HALF_MAP.put('~', '~');
|
||||
FULL_TO_HALF_MAP.put('—', '-');
|
||||
FULL_TO_HALF_MAP.put('.', '.');
|
||||
FULL_TO_HALF_MAP.put('〈', '<');
|
||||
FULL_TO_HALF_MAP.put('〉', '>');
|
||||
FULL_TO_HALF_MAP.put('《', '«');
|
||||
FULL_TO_HALF_MAP.put('》', '»');
|
||||
FULL_TO_HALF_MAP.put('〝', '"');
|
||||
FULL_TO_HALF_MAP.put('〞', '"');
|
||||
FULL_TO_HALF_MAP.put('﹁', '"');
|
||||
FULL_TO_HALF_MAP.put('﹂', '"');
|
||||
FULL_TO_HALF_MAP.put('…', '.');
|
||||
FULL_TO_HALF_MAP.put('﹏', '_');
|
||||
|
||||
// 全角字母和数字
|
||||
for (char c = 'A'; c <= 'Z'; c++) {
|
||||
FULL_TO_HALF_MAP.put(c, (char)(c - 'A' + 'A'));
|
||||
}
|
||||
for (char c = 'a'; c <= 'z'; c++) {
|
||||
FULL_TO_HALF_MAP.put(c, (char)(c - 'a' + 'a'));
|
||||
}
|
||||
for (char c = '0'; c <= '9'; c++) {
|
||||
FULL_TO_HALF_MAP.put(c, (char)(c - '0' + '0'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将字符串中的全角字符(包括标点、字母、数字)转换为半角字符
|
||||
*/
|
||||
public static String convertToHalfWidth(String input) {
|
||||
if (input == null || input.isEmpty()) {
|
||||
return input;
|
||||
}
|
||||
|
||||
StringBuilder result = new StringBuilder();
|
||||
for (int i = 0; i < input.length(); i++) {
|
||||
char c = input.charAt(i);
|
||||
|
||||
// 检查映射表
|
||||
if (FULL_TO_HALF_MAP.containsKey(c)) {
|
||||
result.append(FULL_TO_HALF_MAP.get(c));
|
||||
}
|
||||
// 处理全角空格(Unicode 12288)
|
||||
else if (c == ' ') {
|
||||
result.append(' ');
|
||||
}
|
||||
// 其他字符保持不变
|
||||
else {
|
||||
result.append(c);
|
||||
}
|
||||
}
|
||||
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
// String text = "这是一个全角示例,包含:中文标点、全角字母(ABC)、全角数字(123) 还有全角空格!";
|
||||
String text = "birds,yellow";
|
||||
String converted = convertToHalfWidth(text);
|
||||
System.out.println("原始文本: " + text);
|
||||
System.out.println("转换后: " + converted);
|
||||
}
|
||||
}
|
||||
@@ -28,7 +28,7 @@ public final class LocalCacheUtils {
|
||||
private static LoadingCache<String, String> loadTokenCache() {
|
||||
LoadingCache<String, String> tokenCache = CacheBuilder.newBuilder()
|
||||
.concurrencyLevel(10)
|
||||
.expireAfterWrite(24 * 100, TimeUnit.HOURS)
|
||||
.expireAfterWrite(24 * (7 - 1), TimeUnit.HOURS)
|
||||
.initialCapacity(100)
|
||||
.maximumSize(10000)
|
||||
.recordStats()
|
||||
|
||||
@@ -84,8 +84,10 @@ public class RedisUtil {
|
||||
/**
|
||||
* 将数据放入set缓存
|
||||
*/
|
||||
public void addToSet(String key, String value) {
|
||||
public void addToSet(String key, String value, Long expiresIn) {
|
||||
redisTemplate.opsForSet().add(key, value);
|
||||
// 设置过期时间
|
||||
redisTemplate.expire(key, expiresIn, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -302,4 +304,5 @@ public class RedisUtil {
|
||||
}
|
||||
|
||||
public final static String STRIPE_EXCEPTION_LOG = "StripeException:";
|
||||
public final static String SUBSCRIPTION_SENT_EMAIL_TYPE = "SubscriptionEmailSentType:";
|
||||
}
|
||||
|
||||
@@ -693,7 +693,6 @@ public class SendEmailUtil {
|
||||
|
||||
public static void uploadTimeoutReminder(String userName, String time) {
|
||||
String xp = "xupei3360@163.com";
|
||||
String shb = "shahaibodd99@gmail.com";
|
||||
String wxd = "X1627315083@163.com";
|
||||
String pkc = "kaicpang.pang@connect.polyu.hk";
|
||||
try {
|
||||
@@ -712,7 +711,7 @@ public class SendEmailUtil {
|
||||
// 实例化一个请求对象,每个接口都会对应一个request对象
|
||||
SendEmailRequest req = new SendEmailRequest();
|
||||
req.setFromEmailAddress(SEND_ADDRESS);
|
||||
req.setDestination(new String[]{shb, xp, wxd, pkc});
|
||||
req.setDestination(new String[]{xp, wxd, pkc});
|
||||
Template template = new Template();
|
||||
req.setSubject("上传图片超时提醒");
|
||||
template.setTemplateID(UPLOAD_TIMEOUT_REMINDER);
|
||||
@@ -827,9 +826,12 @@ public class SendEmailUtil {
|
||||
// private final static Long NEW_MERCHANT_EN = 130721L;
|
||||
// private final static Long NEW_USER_EN = 130722L;
|
||||
// private final static Long NEW_USER_CN = 130723L;
|
||||
private final static Long NEW_MERCHANT_EN = 135190L;
|
||||
private final static Long NEW_USER_EN = 135189L;
|
||||
private final static Long NEW_USER_CN = 135186L;
|
||||
private final static Long NEW_MERCHANT_EN = 140335L;
|
||||
// private final static Long NEW_MERCHANT_EN = 135190L;
|
||||
// private final static Long NEW_USER_EN = 135189L;
|
||||
// private final static Long NEW_USER_CN = 135186L;
|
||||
private final static Long NEW_USER_EN = 140316L;
|
||||
private final static Long NEW_USER_CN = 140317L;
|
||||
private final static Long RENEWAL_MERCHANT_EN = 130724L;
|
||||
private final static Long RENEWAL_USER_EN = 130725L;
|
||||
private final static Long RENEWAL_USER_CN = 130726L;
|
||||
|
||||
@@ -51,8 +51,17 @@ public class AffiliateController {
|
||||
|
||||
@ApiOperation(value = "审批affiliate申请")
|
||||
@GetMapping("/approval")
|
||||
public Response<Boolean> applicationApproval(@RequestParam("id") Long id, @RequestParam("isApproved")Boolean isApproved) {
|
||||
return Response.success(affiliateService.applicationApproval(id, isApproved));
|
||||
public Response<Boolean> applicationApproval(@RequestParam("id") Long id,
|
||||
@RequestParam("isApproved")Boolean isApproved,
|
||||
@RequestParam("commission") Float commission) {
|
||||
return Response.success(affiliateService.applicationApproval(id, isApproved, commission));
|
||||
}
|
||||
|
||||
@ApiOperation(value = "更新佣金比例")
|
||||
@GetMapping("/updateCommission")
|
||||
public Response<String> updateCommissionPercentage(@RequestParam("id") Long id, @RequestParam("commission") Float commission) {
|
||||
affiliateService.updateCommissionPercentage(id, commission);
|
||||
return Response.success("success");
|
||||
}
|
||||
|
||||
/*@ApiOperation(value = "定时计算佣金")
|
||||
|
||||
@@ -51,7 +51,9 @@ public class ConvenientInquiryController {
|
||||
String userEmail = accountService.getById(accountId).getUserEmail();
|
||||
if (accountId.equals(31L) || accountId.equals(87L) || accountId.equals(83L)
|
||||
|| accountId.equals(6L) || accountId.equals(4L) || accountId.equals(73L)
|
||||
|| userEmail.equals("joho8228@hotmail.com") || userEmail.equals("wanninghua160@gmail.com")
|
||||
|| userEmail.equals("joho8228@hotmail.com")
|
||||
|| userEmail.equals("chelseayu@code-create.com.hk")
|
||||
|| userEmail.equals("cheungzt007@gmail.com")
|
||||
) {
|
||||
return Response.success(convenientInquiryService.getTrial(queryUserConditionsVO));
|
||||
} else {
|
||||
@@ -67,7 +69,9 @@ public class ConvenientInquiryController {
|
||||
String userEmail = accountService.getById(accountId).getUserEmail();
|
||||
if (accountId.equals(31L) || accountId.equals(87L) || accountId.equals(83L)
|
||||
|| accountId.equals(6L) || accountId.equals(4L) || accountId.equals(73L)
|
||||
|| userEmail.equals("joho8228@hotmail.com") || userEmail.equals("wanninghua160@gmail.com")
|
||||
|| userEmail.equals("joho8228@hotmail.com")
|
||||
|| userEmail.equals("chelseayu@code-create.com.hk")
|
||||
|| userEmail.equals("cheungzt007@gmail.com")
|
||||
) {
|
||||
if (StringUtil.isNullOrEmpty(startTime)) startTime = "2024-02-01 00:00:00";
|
||||
if (StringUtil.isNullOrEmpty(endTime)) {
|
||||
@@ -184,7 +188,9 @@ public class ConvenientInquiryController {
|
||||
String userEmail = accountService.getById(accountId).getUserEmail();
|
||||
if (accountId.equals(31L) || accountId.equals(87L) || accountId.equals(83L)
|
||||
|| accountId.equals(6L) || accountId.equals(4L) || accountId.equals(73L)
|
||||
|| userEmail.equals("joho8228@hotmail.com") || userEmail.equals("wanninghua160@gmail.com")
|
||||
|| userEmail.equals("joho8228@hotmail.com")
|
||||
|| userEmail.equals("chelseayu@code-create.com.hk")
|
||||
|| userEmail.equals("cheungzt007@gmail.com")
|
||||
) {
|
||||
return Response.success(convenientInquiryService.getUserInfo(queryUserConditionsVO));
|
||||
} else {
|
||||
|
||||
@@ -4,8 +4,13 @@ import com.ai.da.common.response.Response;
|
||||
import com.ai.da.common.utils.DateUtil;
|
||||
import com.ai.da.common.utils.RedisUtil;
|
||||
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.QueryCouponsPageDTO;
|
||||
import com.ai.da.model.vo.CheckCouponsVO;
|
||||
import com.ai.da.service.StripeService;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.paypal.http.HttpResponse;
|
||||
import com.paypal.payments.Refund;
|
||||
import com.stripe.exception.StripeException;
|
||||
@@ -99,6 +104,53 @@ public class StripeController {
|
||||
stripeService.cancelSubscription(subscriptionId, reason);
|
||||
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("更新推广码信息")
|
||||
@GetMapping("/updatePromCodeInfo")
|
||||
public Response<ProductCoupons> updateCouponsInfo(@RequestParam Long id, @RequestParam(required = false) String paidCommission,
|
||||
@RequestParam(required = false) String cooperator,
|
||||
@RequestParam(required = false) String remark,
|
||||
@RequestParam(required = false) Long startTime){
|
||||
return Response.success(stripeService.updateCouponsInfo(id, paidCommission, cooperator, remark, startTime));
|
||||
}
|
||||
|
||||
@ApiOperation("删除推广码")
|
||||
@GetMapping("/deletePromCode")
|
||||
public Response<String> deleteCoupon(@RequestParam Long id){
|
||||
stripeService.deleteCoupon(id);
|
||||
return Response.success("success");
|
||||
}
|
||||
|
||||
/*@ApiOperation("临时 取消订阅")
|
||||
@GetMapping("/cancelSubscriptionTemp")
|
||||
public Response<String> cancelSubscriptionTemp(@RequestParam String subscriptionId) {
|
||||
|
||||
@@ -6,6 +6,7 @@ import com.ai.da.model.vo.PaymentInfoVO;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -24,9 +25,15 @@ public interface PaymentInfoMapper extends BaseMapper<PaymentInfo> {
|
||||
String country, String city, String startTime, String endTime, String payer
|
||||
);
|
||||
|
||||
BigDecimal queryTotalPaymentAmount(String paymentType,String payerTotal, String type, String status,
|
||||
String country, String city, String startTime, String endTime, String payer
|
||||
);
|
||||
|
||||
List<Map<String, String>> getCities();
|
||||
|
||||
List<Map<String, String>> getCountries();
|
||||
|
||||
int insertIgnore(@Param("paymentInfo")PaymentInfo paymentInfo);
|
||||
|
||||
List<PaymentInfo> selectPaidPaymentsByAccountAndPromotion(Long accountId, String promotionCode);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.ai.da.mapper.primary;
|
||||
|
||||
import com.ai.da.common.config.mybatis.plus.CommonMapper;
|
||||
import com.ai.da.mapper.primary.entity.ProductCoupons;
|
||||
|
||||
public interface ProductCouponsMapper extends CommonMapper<ProductCoupons> {
|
||||
|
||||
}
|
||||
@@ -14,6 +14,8 @@ public class Affiliate extends BaseEntity{
|
||||
// Active(活跃) || Inactive(过期) || Pending(待审批) || Refused(拒绝)
|
||||
private String status;
|
||||
|
||||
private Float commissionPercent;
|
||||
|
||||
private Float totalEarnings = 0.00F;
|
||||
|
||||
private Float monthlyEarnings = 0.00F;
|
||||
|
||||
@@ -80,4 +80,18 @@ public class Library implements Serializable {
|
||||
private Date updateDate;
|
||||
|
||||
// private Integer isCopy;
|
||||
|
||||
|
||||
public Library() {
|
||||
}
|
||||
|
||||
public Library(Long accountId, String level1Type, String level2Type, String level3Type, String url, String md5, Date createDate) {
|
||||
this.accountId = accountId;
|
||||
this.level1Type = level1Type;
|
||||
this.level2Type = level2Type;
|
||||
this.level3Type = level3Type;
|
||||
this.url = url;
|
||||
this.md5 = md5;
|
||||
this.createDate = createDate;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,4 +47,6 @@ public class PaymentInfo extends BaseEntity{
|
||||
private String country;
|
||||
|
||||
private String city;
|
||||
|
||||
private String promotionCode;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
package com.ai.da.mapper.primary.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableLogic;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
@TableName("t_product_coupons")
|
||||
@NoArgsConstructor
|
||||
public class ProductCoupons extends BaseEntity{
|
||||
// 优惠券id
|
||||
private String couponId;
|
||||
// 优惠券有效期的截止日期
|
||||
private Long redeemBy;
|
||||
// 绑定的推广码id
|
||||
private String promotionCodeId;
|
||||
// 对应的推广码
|
||||
private String promotionCode;
|
||||
// 优惠券有效期开始时间
|
||||
private Long startTime;
|
||||
// 最大兑换次数
|
||||
private Long maxRedemptions;
|
||||
// 优惠券的折扣
|
||||
private float percentOff;
|
||||
// 佣金比例
|
||||
private float commissionRate;
|
||||
// 合作者
|
||||
private String cooperator;
|
||||
// 使用了该优惠券支付的总金额
|
||||
private BigDecimal totalEarnings = BigDecimal.ZERO;
|
||||
// 佣金
|
||||
private BigDecimal commission = BigDecimal.ZERO;
|
||||
// 已付佣金
|
||||
private BigDecimal paidCommission = BigDecimal.ZERO;
|
||||
// 未付佣金
|
||||
private BigDecimal unpaidCommission = BigDecimal.ZERO;
|
||||
// 备注
|
||||
private String remark;
|
||||
|
||||
@TableLogic
|
||||
private Integer isDeleted;
|
||||
|
||||
public ProductCoupons(String couponId, Long redeemBy, String promotionCodeId, String promotionCode, Long maxRedemptions, float percentOff, float commissionRate, String cooperator, String remark) {
|
||||
this.couponId = couponId;
|
||||
this.redeemBy = redeemBy;
|
||||
this.promotionCodeId = promotionCodeId;
|
||||
this.promotionCode = promotionCode;
|
||||
this.maxRedemptions = maxRedemptions;
|
||||
this.percentOff = percentOff;
|
||||
this.cooperator = cooperator;
|
||||
this.remark = remark;
|
||||
this.commissionRate = commissionRate;
|
||||
}
|
||||
}
|
||||
26
src/main/java/com/ai/da/model/dto/CreateCouponDTO.java
Normal file
26
src/main/java/com/ai/da/model/dto/CreateCouponDTO.java
Normal file
@@ -0,0 +1,26 @@
|
||||
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 endTime;
|
||||
@ApiModelProperty("推广码开始时间 秒级时间戳")
|
||||
private Long startTime;
|
||||
@ApiModelProperty("推广码最大使用次数")
|
||||
private Long maxRedemptions;
|
||||
@ApiModelProperty("合作者/机构名")
|
||||
private String cooperator;
|
||||
@ApiModelProperty("备注")
|
||||
private String remark;
|
||||
}
|
||||
@@ -32,7 +32,6 @@ public class DesignSingleItemDTO implements Serializable {
|
||||
@ApiModelProperty("对应的图片的minIO路径")
|
||||
private String path;
|
||||
|
||||
@NotBlank(message = "color.cannot.be.empty")
|
||||
@ApiModelProperty("颜色 存 RGB值 中间空格分隔 比如 \"58 58 169\"")
|
||||
private String color;
|
||||
|
||||
|
||||
@@ -15,8 +15,8 @@ public class EmailSendDTO {
|
||||
private String email;
|
||||
|
||||
@NotBlank(message = "operationType.cannot.be.empty")
|
||||
@ApiModelProperty("操作类型 LOGIN 注册 FORGET_PWD 忘记密码 BIND_MAILBOX 绑定邮箱 " +
|
||||
"CHANGE_MAILBOX 更改邮箱 UPDATE_USERINFO 仅填写国家、职业(不发送邮件)")
|
||||
@ApiModelProperty("操作类型 LOGIN 登录 FORGET_PWD 忘记密码 BIND_MAILBOX 绑定邮箱 " +
|
||||
"CHANGE_MAILBOX 更改邮箱 UPDATE_USERINFO 仅填写国家、职业(不发送邮件) REGISTER 注册")
|
||||
private String operationType;
|
||||
|
||||
@ApiModelProperty("异常ip")
|
||||
|
||||
@@ -21,9 +21,12 @@ public class GenerateModifyDTO {
|
||||
@ApiModelProperty(value = "sketch所属分类", required = true)
|
||||
private String category;
|
||||
|
||||
@ApiModelProperty(value = "originalId的来源 Library || Generate(默认为空)", required = true)
|
||||
private String originalIdSource;
|
||||
|
||||
@NotNull(message = "id cannot be empty")
|
||||
@ApiModelProperty(value = "原图id", required = true)
|
||||
private String originalId;
|
||||
private Long originalId;
|
||||
|
||||
@ApiModelProperty("是否覆盖原图")
|
||||
private Boolean isOverride;
|
||||
|
||||
@@ -30,4 +30,7 @@ public class ProductPurchaseDTO {
|
||||
|
||||
@ApiModelProperty("使用Alipay-HK时需要选择 ALIPAYHK || ALIPAYCN")
|
||||
private String wallet;
|
||||
|
||||
@ApiModelProperty("优惠码")
|
||||
private String promotionCode;
|
||||
}
|
||||
|
||||
22
src/main/java/com/ai/da/model/dto/QueryCouponsPageDTO.java
Normal file
22
src/main/java/com/ai/da/model/dto/QueryCouponsPageDTO.java
Normal file
@@ -0,0 +1,22 @@
|
||||
package com.ai.da.model.dto;
|
||||
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
@ApiModel
|
||||
public class QueryCouponsPageDTO extends QueryPageByTimeDTO {
|
||||
@ApiModelProperty("DESC(按id降序) || ASC(按id升序)")
|
||||
private String orderById;
|
||||
@ApiModelProperty("推广码")
|
||||
private String promotionCode;
|
||||
@ApiModelProperty("查询过期 || 未过期的优惠券")
|
||||
private Boolean isExpired;
|
||||
@ApiModelProperty("按合作者名字查询")
|
||||
private String cooperator;
|
||||
|
||||
}
|
||||
@@ -22,6 +22,8 @@ public class SubscriptionEmailParamsDTO {
|
||||
// 费用
|
||||
private String totalFee;
|
||||
|
||||
private String renewalFee;
|
||||
|
||||
// 当前订阅开始时间
|
||||
private String lastOrderDate;
|
||||
|
||||
|
||||
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 有效 || pending 尚未生效")
|
||||
private String status;
|
||||
|
||||
private String message;
|
||||
|
||||
private Float discountedPrice;
|
||||
}
|
||||
@@ -13,6 +13,8 @@ public class PaymentInfoVO {
|
||||
private Long id;
|
||||
@ApiModelProperty("付款用户名")
|
||||
private String payer;
|
||||
@ApiModelProperty("付款者邮箱")
|
||||
private String email;
|
||||
@ApiModelProperty("选择的支付平台 PayPal || Stripe || Alipay-HK")
|
||||
private String platform;
|
||||
@ApiModelProperty("支付的金额 单位:HKD")
|
||||
|
||||
@@ -18,7 +18,9 @@ public interface AffiliateService extends IService<Affiliate> {
|
||||
|
||||
double[] getPersonalMonthlyIncome(int year);
|
||||
|
||||
Boolean applicationApproval(Long id, Boolean isApproved);
|
||||
Boolean applicationApproval(Long id, Boolean isApproved, Float commission);
|
||||
|
||||
void updateCommissionPercentage(Long id, Float commission);
|
||||
|
||||
void updateAffiliateInfoWithPayment();
|
||||
|
||||
@@ -29,4 +31,6 @@ public interface AffiliateService extends IService<Affiliate> {
|
||||
Affiliate getByAccountId(Long accountId);
|
||||
|
||||
void commissionCalculation(Integer year, Integer month);
|
||||
|
||||
void calcCouponsCommission();
|
||||
}
|
||||
|
||||
@@ -53,6 +53,8 @@ public interface DesignItemService extends IService<DesignItem> {
|
||||
|
||||
DesignSingleVO designSingleIncludeLayers(DesignSingleIncludeLayersDTO designSingleIncludeLayersDTO);
|
||||
|
||||
Map<String, String> setPriorityAndUndividedLayer(JSONArray layers);
|
||||
|
||||
Map<String, String> setTypeAndUndividedLayer(JSONArray layers);
|
||||
|
||||
ComposeLayersVO editLayersPositionAndScale(EditLayersPositionAndScaleVO positionAndScaleVO) throws IOException;
|
||||
|
||||
@@ -32,4 +32,6 @@ public interface PaymentInfoService extends IService<PaymentInfo> {
|
||||
void updatePaymentStatusById(Long id, String status, String content);
|
||||
|
||||
PageBaseResponse<OrderListVO> getPaymentInfo(QueryPageByTimeDTO queryPageByTimeDTO);
|
||||
|
||||
List<PaymentInfo> getPaymentInfoByPromCode(Long accountId, String promCode);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
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.model.dto.CreateCouponDTO;
|
||||
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 javax.servlet.http.HttpServletRequest;
|
||||
@@ -51,4 +56,20 @@ public interface StripeService {
|
||||
// Map getIp(HttpServletRequest request);
|
||||
|
||||
String getStackTrace(Exception e, int maxLines);
|
||||
|
||||
String createCoupon(CreateCouponDTO createCouponDTO);
|
||||
|
||||
CheckCouponsVO checkProductCoupon(String promotionCode, Long price);
|
||||
|
||||
ProductCoupons updateCouponsInfo(Long id, String paidCommission, String cooperator, String remark, Long startTime);
|
||||
|
||||
ProductCoupons getProductCoupon(String promotionCode, String promotionCodeId);
|
||||
|
||||
String retrieveCoupon(String couponId);
|
||||
|
||||
String retrievePromotionCode(String promotionCode);
|
||||
|
||||
IPage<ProductCoupons> getAllCoupons(QueryCouponsPageDTO queryCouponsPageDTO);
|
||||
|
||||
void deleteCoupon(Long id);
|
||||
}
|
||||
|
||||
@@ -517,11 +517,15 @@ public class AccountServiceImpl extends ServiceImpl<AccountMapper, Account> impl
|
||||
result = true;
|
||||
}
|
||||
break;
|
||||
case REGISTER:
|
||||
result = SendEmailUtil.designWorksRegister(emailSendDTO.getEmail(), randomVerifyCode);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
if (!result) {
|
||||
throw new BusinessException("failed.to.send.mail");
|
||||
}
|
||||
log.info("向邮箱 {} 发送验证码为:{}, 邮件类型:{}", emailSendDTO.getEmail(), randomVerifyCode, authenticationOperationTypeEnum);
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
|
||||
@@ -1287,27 +1291,30 @@ public class AccountServiceImpl extends ServiceImpl<AccountMapper, Account> impl
|
||||
|
||||
@Override
|
||||
public Boolean designWorksRegister(AccountDesignWorksRegisterDTO accountDesignWorksRegisterDTO) {
|
||||
String userEmail = accountDesignWorksRegisterDTO.getUserEmail();
|
||||
log.info("账号注册,邮箱为:{}", userEmail);
|
||||
QueryWrapper<Account> qw = new QueryWrapper<>();
|
||||
qw.eq("BINARY user_email", accountDesignWorksRegisterDTO.getUserEmail());
|
||||
qw.eq("BINARY user_email", userEmail);
|
||||
List<Account> accountList = accountMapper.selectList(qw);
|
||||
if (CollectionUtil.isNotEmpty(accountList)) {
|
||||
throw new BusinessException("The email has already been registered");
|
||||
}
|
||||
|
||||
String randomVerifyCode = RandomsUtil.generateVerifyCode(100000L, 999999L);
|
||||
LocalCacheUtils.setVerifyCodeCache("DesignWorksRegister" + "_" + accountDesignWorksRegisterDTO.getUserEmail(), randomVerifyCode);
|
||||
LocalCacheUtils.setVerifyCodeCache("REGISTER" + "_" + userEmail, randomVerifyCode);
|
||||
|
||||
Boolean b = SendEmailUtil.designWorksRegister(accountDesignWorksRegisterDTO.getUserEmail(), randomVerifyCode);
|
||||
Boolean b = SendEmailUtil.designWorksRegister(userEmail, randomVerifyCode);
|
||||
if (!b) {
|
||||
throw new BusinessException("failed.to.send.mail");
|
||||
}
|
||||
log.info("向邮箱 {} 发送验证码:{}, 邮件类型:REGISTER", userEmail, randomVerifyCode);
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AccountLoginVO designWorksRegisterCode(AccountDesignWorksRegisterDTO accountDesignWorksRegisterDTO) {
|
||||
|
||||
String verifyCode = LocalCacheUtils.getVerifyCodeCache("DesignWorksRegister" + "_" + accountDesignWorksRegisterDTO.getUserEmail());
|
||||
String verifyCode = LocalCacheUtils.getVerifyCodeCache("REGISTER" + "_" + accountDesignWorksRegisterDTO.getUserEmail());
|
||||
if (StringUtils.isBlank(verifyCode)) {
|
||||
throw new BusinessException("the.verification.code.has.expired", ResultEnum.PROMPT.getCode());
|
||||
}
|
||||
@@ -1633,7 +1640,7 @@ public class AccountServiceImpl extends ServiceImpl<AccountMapper, Account> impl
|
||||
|
||||
public static void main(String[] args) {
|
||||
List<String> a = new ArrayList<>();
|
||||
a.add("1023316923@qq.com");
|
||||
// a.add("1023316923@qq.com");
|
||||
a.add("Malinyuquan@gmail.com");
|
||||
|
||||
if (a.contains("malinyuquan@gmail.com")) {
|
||||
|
||||
@@ -10,6 +10,7 @@ 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;
|
||||
@@ -17,10 +18,7 @@ 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.AccountService;
|
||||
import com.ai.da.service.AffiliateService;
|
||||
import com.ai.da.service.OrderInfoService;
|
||||
import com.ai.da.service.PaymentInfoService;
|
||||
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;
|
||||
@@ -33,11 +31,12 @@ import org.springframework.util.CollectionUtils;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
@@ -45,19 +44,18 @@ public class AffiliateServiceImpl extends ServiceImpl<AffiliateMapper, Affiliate
|
||||
|
||||
@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;
|
||||
|
||||
@@ -152,7 +150,7 @@ public class AffiliateServiceImpl extends ServiceImpl<AffiliateMapper, Affiliate
|
||||
}
|
||||
|
||||
// 审批申请
|
||||
public Boolean applicationApproval(Long id, Boolean isApproved){
|
||||
public Boolean applicationApproval(Long id, Boolean isApproved, Float commission){
|
||||
Affiliate affiliate = baseMapper.selectById(id);
|
||||
|
||||
// 1、更新db状态
|
||||
@@ -161,6 +159,12 @@ public class AffiliateServiceImpl extends ServiceImpl<AffiliateMapper, Affiliate
|
||||
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);
|
||||
@@ -180,6 +184,19 @@ public class AffiliateServiceImpl extends ServiceImpl<AffiliateMapper, Affiliate
|
||||
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
|
||||
@@ -216,8 +233,8 @@ public class AffiliateServiceImpl extends ServiceImpl<AffiliateMapper, Affiliate
|
||||
Float payerTotal = paymentInfo.getPayerTotal();
|
||||
|
||||
if (payerTotal > 0){
|
||||
// 分配新用户首次订阅所付费用的25%作为佣金
|
||||
BigDecimal commission = BigDecimal.valueOf(payerTotal).multiply(new BigDecimal("0.25"));
|
||||
// 分配新用户首次订阅所付费用 预设的佣金比例 作为佣金
|
||||
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;
|
||||
@@ -328,5 +345,108 @@ public class AffiliateServiceImpl extends ServiceImpl<AffiliateMapper, Affiliate
|
||||
return baseMapper.selectOne(queryWrapper);
|
||||
}
|
||||
|
||||
/*public void calcCouponsCommission() {
|
||||
String lastTime = redisUtil.getFromString(RedisUtil.PAYMENT_INFO_LAST_SCAN_TIME);
|
||||
log.info("优惠券佣金计算,上次执行时间:{}", lastTime);
|
||||
String currentTime = LocalDateTime.now().toString();
|
||||
|
||||
// 1. 查询新增的优惠券订单
|
||||
QueryWrapper<PaymentInfo> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.eq("trade_state", "paid")
|
||||
.lt("create_time", currentTime)
|
||||
.isNotNull("promotion_code");
|
||||
Optional.ofNullable(lastTime)
|
||||
.filter(time -> !time.isEmpty())
|
||||
.ifPresent(time -> queryWrapper.gt("create_time", time));
|
||||
|
||||
List<PaymentInfo> paymentInfos = paymentInfoService.list(queryWrapper);
|
||||
log.info("目前,新增使用优惠券的订单数:{}", paymentInfos.size());
|
||||
|
||||
// 2. 按推广码汇总支付金额
|
||||
Map<String, BigDecimal> codeAmount = paymentInfos.stream()
|
||||
.collect(Collectors.toMap(
|
||||
PaymentInfo::getPromotionCode,
|
||||
payment -> new BigDecimal(payment.getPayerTotal()),
|
||||
BigDecimal::add
|
||||
));
|
||||
|
||||
// 3. 更新佣金数据
|
||||
codeAmount.forEach((promotionCode, amount) -> {
|
||||
ProductCoupons coupon = stripeService.getProductCoupon(promotionCode, null);
|
||||
if (coupon != null) {
|
||||
updateCouponCommission(coupon, amount);
|
||||
productCouponsMapper.updateById(coupon);
|
||||
}
|
||||
});
|
||||
|
||||
// 4. 更新最后执行时间
|
||||
redisUtil.addToString(RedisUtil.PAYMENT_INFO_LAST_SCAN_TIME, currentTime);
|
||||
}*/
|
||||
|
||||
public void calcCouponsCommission() {
|
||||
// 1. 获取并格式化时间
|
||||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||
String lastTime = redisUtil.getFromString(RedisUtil.PAYMENT_INFO_LAST_SCAN_TIME);
|
||||
log.info("优惠券佣金计算,上次执行时间:{}", lastTime);
|
||||
|
||||
// 2. 查询新增订单(使用>=和<)
|
||||
QueryWrapper<PaymentInfo> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.eq("trade_state", "paid")
|
||||
.isNotNull("promotion_code");
|
||||
|
||||
if (!StringUtils.isNullOrEmpty(lastTime)) {
|
||||
queryWrapper.ge("create_time", lastTime); // 关键修复:>=代替>
|
||||
}
|
||||
queryWrapper.lt("create_time", LocalDateTime.now().format(formatter));
|
||||
|
||||
List<PaymentInfo> paymentInfos = paymentInfoService.list(queryWrapper);
|
||||
log.info("扫描时间范围: {} - {}, 新增订单数: {}",
|
||||
lastTime, LocalDateTime.now().format(formatter), paymentInfos.size());
|
||||
|
||||
// 3. 按推广码汇总支付金额
|
||||
Map<String, BigDecimal> codeAmount = paymentInfos.stream()
|
||||
.collect(Collectors.toMap(
|
||||
PaymentInfo::getPromotionCode,
|
||||
payment -> new BigDecimal(payment.getPayerTotal()),
|
||||
BigDecimal::add
|
||||
));
|
||||
|
||||
// 4. 更新佣金数据
|
||||
codeAmount.forEach((promotionCode, amount) -> {
|
||||
ProductCoupons coupon = stripeService.getProductCoupon(promotionCode, null);
|
||||
if (coupon != null) {
|
||||
updateCouponCommission(coupon, amount);
|
||||
productCouponsMapper.updateById(coupon);
|
||||
}
|
||||
});
|
||||
|
||||
// 5. 结束时更新Redis时间
|
||||
String newLastTime = LocalDateTime.now().format(formatter);
|
||||
redisUtil.addToString(RedisUtil.PAYMENT_INFO_LAST_SCAN_TIME, newLastTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新优惠券的佣金数据
|
||||
*/
|
||||
private void updateCouponCommission(ProductCoupons coupon, BigDecimal newAmount) {
|
||||
// 总收益 = 原收益(默认0) + 新增金额
|
||||
BigDecimal totalEarnings = Optional.ofNullable(coupon.getTotalEarnings())
|
||||
.orElse(BigDecimal.ZERO)
|
||||
.add(newAmount);
|
||||
coupon.setTotalEarnings(totalEarnings);
|
||||
|
||||
// 佣金 = 总收益 × 佣金比例(需除以100)
|
||||
BigDecimal commission = totalEarnings.multiply(
|
||||
BigDecimal.valueOf(coupon.getCommissionRate())
|
||||
.divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP));
|
||||
coupon.setCommission(commission);
|
||||
|
||||
// 未支付佣金 = 总佣金 - 已支付佣金(默认0)
|
||||
BigDecimal unpaidCommission = commission.subtract(
|
||||
Optional.ofNullable(coupon.getPaidCommission())
|
||||
.orElse(BigDecimal.ZERO));
|
||||
coupon.setUnpaidCommission(unpaidCommission);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -5,6 +5,7 @@ import com.ai.da.common.constant.CommonConstant;
|
||||
import com.ai.da.common.context.UserContext;
|
||||
import com.ai.da.common.enums.CreditsEventsEnum;
|
||||
import com.ai.da.common.response.PageBaseResponse;
|
||||
import com.ai.da.common.response.TransactionPageResponse;
|
||||
import com.ai.da.common.utils.CopyUtil;
|
||||
import com.ai.da.common.utils.DateUtil;
|
||||
import com.ai.da.mapper.primary.*;
|
||||
@@ -610,16 +611,21 @@ public class ConvenientInquiryServiceImpl extends ServiceImpl<QuestionnaireMappe
|
||||
queryPaymentInfoDTO.getType(), queryPaymentInfoDTO.getStatus(),
|
||||
queryPaymentInfoDTO.getCountry(), queryPaymentInfoDTO.getCity(),
|
||||
queryPaymentInfoDTO.getStartTime(), queryPaymentInfoDTO.getEndTime(), queryPaymentInfoDTO.getPayer());
|
||||
|
||||
// 查询符合查询条件的总金额
|
||||
BigDecimal payerTotal = paymentInfoMapper.queryTotalPaymentAmount(queryPaymentInfoDTO.getPlatform(), queryPaymentInfoDTO.getPayerTotal(),
|
||||
queryPaymentInfoDTO.getType(), queryPaymentInfoDTO.getStatus(),
|
||||
queryPaymentInfoDTO.getCountry(), queryPaymentInfoDTO.getCity(),
|
||||
queryPaymentInfoDTO.getStartTime(), queryPaymentInfoDTO.getEndTime(), queryPaymentInfoDTO.getPayer());
|
||||
// 总页数
|
||||
double totalPage = Math.ceil((double) total / size);
|
||||
// 组装返回参数
|
||||
PageBaseResponse<PaymentInfoVO> response = new PageBaseResponse<>();
|
||||
TransactionPageResponse<PaymentInfoVO> response = new TransactionPageResponse<>();
|
||||
response.setContent(paymentInfoVOS);
|
||||
response.setPage(queryPaymentInfoDTO.getPage());
|
||||
response.setSize(size);
|
||||
response.setTotal(total);
|
||||
response.setPages((long) totalPage);
|
||||
response.setTotalAmount(Objects.isNull(payerTotal) ? BigDecimal.ZERO : payerTotal);
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,6 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.mysql.cj.util.StringUtils;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.SerializationUtils;
|
||||
@@ -326,7 +325,7 @@ public class DesignItemServiceImpl extends ServiceImpl<DesignItemMapper, DesignI
|
||||
private List<TDesignPythonOutfitDetail> saveDesignSingleItemDetailAndLayers(DesignPythonObjects pythonObjects
|
||||
, Long designId, Long designItemId, Long userId
|
||||
, JSONObject outfit, String timeZone, List<DesignSingleItemDTO> designSingleItemDTOList
|
||||
, Map<String, String> categoryAndUndividedLayer) {
|
||||
, Map<String, String> priorityAndUndividedLayer) {
|
||||
|
||||
DesignItem designItem = new DesignItem();
|
||||
// String url = pythonObjects.getObjects().get(0).getBasic().getSave_name();
|
||||
@@ -357,7 +356,8 @@ public class DesignItemServiceImpl extends ServiceImpl<DesignItemMapper, DesignI
|
||||
designItemDetail.setPriority(0);
|
||||
}
|
||||
designItemDetail.setIconPath(detail.getIcon());
|
||||
designItemDetail.setUndividedLayer(categoryAndUndividedLayer.get(detail.getType().toLowerCase()));
|
||||
// designItemDetail.setUndividedLayer(priorityAndUndividedLayer.get(detail.getType().toLowerCase()));
|
||||
if (!detail.getType().equals("Body")) designItemDetail.setUndividedLayer(priorityAndUndividedLayer.get(detail.getPriority().toString()));
|
||||
// 印花存储在design_item_detail_print表中 这里还要存吗?
|
||||
// DesignPythonItemPrint printObject = detail.getPrintToPython();
|
||||
// designItemDetail.setPrintPath(Objects.isNull(printObject) ? "" : printObject.getPath());
|
||||
@@ -542,13 +542,13 @@ public class DesignItemServiceImpl extends ServiceImpl<DesignItemMapper, DesignI
|
||||
}
|
||||
|
||||
JSONArray layers = outfit.getJSONArray("layers");
|
||||
Map<String, String> categoryAndUndividedLayer = setTypeAndUndividedLayer(layers);
|
||||
Map<String, String> priorityAndUndividedLayer = setPriorityAndUndividedLayer(layers);
|
||||
if (!designSingleIncludeLayersDTO.getIsPreview()) {
|
||||
// 更新及保存图层信息
|
||||
tDesignPythonOutfitDetails = saveDesignSingleItemDetailAndLayers(objects, design.getId(), designSingleIncludeLayersDTO.getDesignItemId()
|
||||
, userId, outfit, designSingleIncludeLayersDTO.getTimeZone()
|
||||
, designSingleIncludeLayersDTO.getDesignSingleItemDTOList()
|
||||
, categoryAndUndividedLayer);
|
||||
, priorityAndUndividedLayer);
|
||||
|
||||
saveCollectionElement(designSingleIncludeLayersDTO);
|
||||
} else {
|
||||
@@ -576,7 +576,7 @@ public class DesignItemServiceImpl extends ServiceImpl<DesignItemMapper, DesignI
|
||||
designSingleIncludeLayersDTO.getDesignSingleItemDTOList(),
|
||||
detailsVO,
|
||||
design.getSingleOverall(),
|
||||
categoryAndUndividedLayer);
|
||||
priorityAndUndividedLayer);
|
||||
}
|
||||
|
||||
private void sketchBase64ToPath(DesignSingleIncludeLayersDTO designSingleIncludeLayersDTO){
|
||||
@@ -624,15 +624,28 @@ public class DesignItemServiceImpl extends ServiceImpl<DesignItemMapper, DesignI
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> setPriorityAndUndividedLayer(JSONArray layers){
|
||||
HashMap<String, String> priorityAndLayer = new HashMap<>();
|
||||
for (int i = 0; i < layers.size(); i++) {
|
||||
JSONObject jsonObject = layers.getJSONObject(i);
|
||||
String priority = jsonObject.getString("priority");
|
||||
String category = jsonObject.getString("image_category").split("_")[0];
|
||||
if (!category.equals("body") && !priorityAndLayer.containsKey(priority)) priorityAndLayer.put(priority, jsonObject.getString("pattern_image_url"));
|
||||
}
|
||||
return priorityAndLayer;
|
||||
}
|
||||
|
||||
// 由于在design过程中没有priority 优先级的概念,并且在design时,不会出现上下两件使用相同服装类型的情况,所以这里依然保留这个方法。
|
||||
@Override
|
||||
public Map<String, String> setTypeAndUndividedLayer(JSONArray layers){
|
||||
HashMap<String, String> categoryAndLayer = new HashMap<>();
|
||||
HashMap<String, String> typeAndLayer = new HashMap<>();
|
||||
for (int i = 0; i < layers.size(); i++) {
|
||||
JSONObject jsonObject = layers.getJSONObject(i);
|
||||
String category = jsonObject.getString("image_category").split("_")[0];
|
||||
if (!category.equals("body") && !categoryAndLayer.containsKey(category)) categoryAndLayer.put(category, jsonObject.getString("pattern_image_url"));
|
||||
if (!category.equals("body") && !typeAndLayer.containsKey(category)) typeAndLayer.put(category, jsonObject.getString("pattern_image_url"));
|
||||
}
|
||||
return categoryAndLayer;
|
||||
return typeAndLayer;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -726,7 +739,7 @@ public class DesignItemServiceImpl extends ServiceImpl<DesignItemMapper, DesignI
|
||||
List<DesignSingleItemDTO> designSingleItemDTOList,
|
||||
List<DesignPythonOutfitVO> layersObject,
|
||||
String singleOrOverall,
|
||||
Map<String, String> categoryAndUndividedLayer) {
|
||||
Map<String, String> priorityAndUndividedLayer) {
|
||||
|
||||
DesignSingleVO designSingleVO = new DesignSingleVO();
|
||||
ArrayList<DesignItemClothesDetailVO> clothes = new ArrayList<>();
|
||||
@@ -753,7 +766,7 @@ public class DesignItemServiceImpl extends ServiceImpl<DesignItemMapper, DesignI
|
||||
// 重置sketch的minio临时访问凭证
|
||||
designItemClothesDetailVO.setPath(minioUtil.getPreSignedUrl(singleItem.getPath(), 24 * 60, true));
|
||||
designItemClothesDetailVO.setMinIOPath(singleItem.getPath());
|
||||
designItemClothesDetailVO.setColor(panToneService.getPantoneByRgb(singleItem.getColor()));
|
||||
if (!StringUtil.isNullOrEmpty(singleItem.getColor())) designItemClothesDetailVO.setColor(panToneService.getPantoneByRgb(singleItem.getColor()));
|
||||
designItemClothesDetailVO.setPrintObject(singleItem.getPrintObject());
|
||||
designItemClothesDetailVO.setTrims(singleItem.getTrims());
|
||||
designItemClothesDetailVO.setLayersObject(layersObject.stream().filter(
|
||||
@@ -761,7 +774,7 @@ public class DesignItemServiceImpl extends ServiceImpl<DesignItemMapper, DesignI
|
||||
&& (flag ? Boolean.TRUE : singleItem.getPriority().equals(layers.getPriority())))
|
||||
).collect(Collectors.toList()));
|
||||
designItemClothesDetailVO.setGradient(singleItem.getGradient());
|
||||
if (categoryAndUndividedLayer.containsKey(singleItem.getType().toLowerCase())) designItemClothesDetailVO.setUndividedLayer(minioUtil.getPreSignedUrl(categoryAndUndividedLayer.get(singleItem.getType().toLowerCase()), CommonConstant.MINIO_IMAGE_EXPIRE_TIME, true));
|
||||
if (priorityAndUndividedLayer.containsKey(singleItem.getPriority().toString())) designItemClothesDetailVO.setUndividedLayer(minioUtil.getPreSignedUrl(priorityAndUndividedLayer.get(singleItem.getPriority().toString()), CommonConstant.MINIO_IMAGE_EXPIRE_TIME, true));
|
||||
body.setLayersObject(layersObject.stream().filter(layers -> layers.getImageCategory().equals("body")).collect(Collectors.toList()));
|
||||
|
||||
clothes.add(designItemClothesDetailVO);
|
||||
|
||||
@@ -787,6 +787,7 @@ public class DesignServiceImpl extends ServiceImpl<DesignMapper, Design> impleme
|
||||
d -> Math.abs(d.getPriority()),
|
||||
(existing, replacement) -> replacement));
|
||||
Map<String, String> typeAndUndividedLayer = designItemService.setTypeAndUndividedLayer(layers);
|
||||
log.info("all typeLayers Map:{}", typeAndUndividedLayer);
|
||||
for (DesignPythonItem detail : item.getItems()) {
|
||||
if (null == detail) {
|
||||
continue;
|
||||
@@ -797,7 +798,11 @@ public class DesignServiceImpl extends ServiceImpl<DesignMapper, Design> impleme
|
||||
designItemDetail.setDesignItemId(designItemId);
|
||||
designItemDetail.setCollectionElementId(detail.getElementId());
|
||||
designItemDetail.setCreateDate(DateUtil.getByTimeZone(timeZone));
|
||||
designItemDetail.setUndividedLayer(typeAndUndividedLayer.get(designItemDetail.getType().toLowerCase()));
|
||||
log.info("detail.getType():{}", detail.getType());
|
||||
if (!detail.getType().equals("Body")){
|
||||
log.info("layer : {}", typeAndUndividedLayer.get(designItemDetail.getType()));
|
||||
designItemDetail.setUndividedLayer(typeAndUndividedLayer.get(designItemDetail.getType()));
|
||||
}
|
||||
if (SysFileLevel2TypeEnum.BODY.getRealName().equals(detail.getType())) {
|
||||
designItemDetail.setPath(detail.getBody_path());
|
||||
//BODY不关联businessId
|
||||
@@ -928,7 +933,10 @@ public class DesignServiceImpl extends ServiceImpl<DesignMapper, Design> impleme
|
||||
designItemDetail.setDesignItemId(designItemId);
|
||||
designItemDetail.setCollectionElementId(detail.getElementId());
|
||||
designItemDetail.setCreateDate(DateUtil.getByTimeZone(timeZone));
|
||||
designItemDetail.setUndividedLayer(typeAndUndividedLayer.get(designItemDetail.getType().toLowerCase()));
|
||||
if (!detail.getType().equals("Body")){
|
||||
designItemDetail.setUndividedLayer(typeAndUndividedLayer.get(designItemDetail.getType()));
|
||||
}
|
||||
|
||||
if (SysFileLevel2TypeEnum.BODY.getRealName().equals(detail.getType())) {
|
||||
designItemDetail.setPath(detail.getBody_path());
|
||||
//BODY不关联businessId
|
||||
@@ -1265,10 +1273,10 @@ public class DesignServiceImpl extends ServiceImpl<DesignMapper, Design> impleme
|
||||
if (Objects.isNull(design)) {
|
||||
throw new BusinessException("design.detail.not.found");
|
||||
}
|
||||
if (!userLike.getDesignId().equals(disDesignLikeDTO.getDesignId())) {
|
||||
//不是相同的design不会合并
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
// if (!userLike.getDesignId().equals(disDesignLikeDTO.getDesignId())) {
|
||||
// //不是相同的design不会合并
|
||||
// return Boolean.TRUE;
|
||||
// }
|
||||
//修改designItem为dislike状态
|
||||
designItemService.updateLikeStatus(userLike.getDesignItemId(), (byte) 0);
|
||||
//删除关联的collection,先不做
|
||||
@@ -1988,7 +1996,9 @@ public class DesignServiceImpl extends ServiceImpl<DesignMapper, Design> impleme
|
||||
designItemDetail.setDesignItemId(designItemId);
|
||||
designItemDetail.setCollectionElementId(detail.getElementId());
|
||||
designItemDetail.setCreateDate(DateUtil.getByTimeZone(timeZone));
|
||||
designItemDetail.setUndividedLayer(typeAndUndividedLayer.get(designItemDetail.getType().toLowerCase()));
|
||||
if (!detail.getType().equals("Body")){
|
||||
designItemDetail.setUndividedLayer(typeAndUndividedLayer.get(designItemDetail.getType()));
|
||||
}
|
||||
if (SysFileLevel2TypeEnum.BODY.getRealName().equals(detail.getType())) {
|
||||
designItemDetail.setPath(detail.getBody_path());
|
||||
//BODY不关联businessId
|
||||
|
||||
@@ -111,8 +111,9 @@ public class GenerateServiceImpl extends ServiceImpl<GenerateMapper, Generate> i
|
||||
public void generateThroughImageText(GenerateThroughImageTextDTO generateThroughImageTextDTO) {
|
||||
// 1、获取用户信息
|
||||
Long accountId = generateThroughImageTextDTO.getUserId();
|
||||
String generateType = generateThroughImageTextDTO.getGenerateType();
|
||||
|
||||
GenerateModeEnum modeEnum = getMode(generateThroughImageTextDTO);
|
||||
String generateType = modeEnum.getValue();
|
||||
// 2、判断必须入参是否为非空(在prepare阶段已校验)
|
||||
Generate generate = new Generate();
|
||||
generate.setAccountId(accountId);
|
||||
@@ -141,9 +142,7 @@ public class GenerateServiceImpl extends ServiceImpl<GenerateMapper, Generate> i
|
||||
CollectionElement collectionElement = collectionElementService.editLevel2Type(elementId, generateThroughImageTextDTO.getLevel2Type(), generateThroughImageTextDTO.getDesignType());
|
||||
|
||||
// 3、向模型发起请求
|
||||
String mode = GenerateModeEnum.TEXT.getValue().equals(generateType) ?
|
||||
GenerateModeEnum.TEXT.getType() :
|
||||
GenerateModeEnum.TEXT_IMAGE.getType();
|
||||
String mode = modeEnum.getType();
|
||||
String category = generateThroughImageTextDTO.getLevel1Type().equals(SKETCH_BOARD.getRealName()) ? "sketch" :
|
||||
generateThroughImageTextDTO.getLevel1Type().equals(PRINT_BOARD.getRealName()) ? "print" : "moodboard";
|
||||
String path = CommonConstant.GENERATE_PATH;
|
||||
@@ -188,7 +187,6 @@ public class GenerateServiceImpl extends ServiceImpl<GenerateMapper, Generate> i
|
||||
jsonString = JSON.toJSONString(generateToPythonDTO, SerializerFeature.WriteMapNullValue);
|
||||
}
|
||||
|
||||
|
||||
Boolean requestResult = pythonService.generateSketchOrPrint(jsonString, port, path);
|
||||
|
||||
// 4、将请求信息落库,将本次generate的请求信息添加到t_generate表中
|
||||
@@ -207,6 +205,21 @@ public class GenerateServiceImpl extends ServiceImpl<GenerateMapper, Generate> i
|
||||
|
||||
}
|
||||
|
||||
public GenerateModeEnum getMode(GenerateThroughImageTextDTO generateThroughImageTextDTO){
|
||||
if (!StringUtil.isNullOrEmpty(generateThroughImageTextDTO.getText())){
|
||||
if (Objects.nonNull(generateThroughImageTextDTO.getCollectionElementId())){
|
||||
return GenerateModeEnum.TEXT_IMAGE;
|
||||
}else {
|
||||
return GenerateModeEnum.TEXT;
|
||||
}
|
||||
}else {
|
||||
if (Objects.nonNull(generateThroughImageTextDTO.getCollectionElementId())){
|
||||
return GenerateModeEnum.IMAGE;
|
||||
}
|
||||
}
|
||||
return GenerateModeEnum.TEXT;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void processGenerateResult(String taskId, String url, String category) {
|
||||
@@ -321,6 +334,10 @@ public class GenerateServiceImpl extends ServiceImpl<GenerateMapper, Generate> i
|
||||
prefix = userInput.substring(0, userInput.indexOf(",")) + ", ";
|
||||
userInput = userInput.substring(userInput.indexOf(",") + 1);
|
||||
}
|
||||
// 替换用户输入中的中文字符
|
||||
log.info("用户输入,处理前:{}", userInput);
|
||||
userInput = ComprehensivePunctuationConverter.convertToHalfWidth(userInput);
|
||||
log.info("用户输入,处理后:{}", userInput);
|
||||
String translated = prefix + pythonService.promptTranslate(userInput);
|
||||
switch (level1Type) {
|
||||
case "Moodboard":
|
||||
@@ -688,7 +705,7 @@ public class GenerateServiceImpl extends ServiceImpl<GenerateMapper, Generate> i
|
||||
// todo 取消待优化
|
||||
uniqueIdList.forEach(uniqueId -> {
|
||||
// 1、将需要取消的唯一id加入redis,以便及时取消生成
|
||||
redisUtil.addToSet(cancelSetKey, uniqueId);
|
||||
redisUtil.addToSet(cancelSetKey, uniqueId, CommonConstant.REDIS_SET_EXPIRE_TIME);
|
||||
|
||||
/*// 1、确认当前消息是否还在排队中
|
||||
Boolean exists = redisUtil.isElementExistsInZSet(consumptionOrderKey, uniqueId);
|
||||
@@ -881,43 +898,96 @@ public class GenerateServiceImpl extends ServiceImpl<GenerateMapper, Generate> i
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public GenerateResultVO modifySketch(GenerateModifyDTO generateModifyDTO) {
|
||||
log.info("修改提取出的sketch,并加入到library");
|
||||
|
||||
// 提取常用参数
|
||||
Long accountId = UserContext.getUserHolder().getId();
|
||||
String base64 = generateModifyDTO.getBase64();
|
||||
String gender = generateModifyDTO.getGender();
|
||||
String gender = generateModifyDTO.getGender().toLowerCase();
|
||||
String category = generateModifyDTO.getCategory();
|
||||
Long originalId = generateModifyDTO.getOriginalId();
|
||||
boolean isOverride = generateModifyDTO.getIsOverride();
|
||||
boolean isFromLibrary = !StringUtil.isNullOrEmpty(generateModifyDTO.getOriginalIdSource())
|
||||
&& generateModifyDTO.getOriginalIdSource().equals("Library");
|
||||
|
||||
// 将base64上传到minio
|
||||
String path;
|
||||
GenerateDetail originalDetail = generateDetailMapper.selectById(generateModifyDTO.getOriginalId());
|
||||
Long generateDetailId = originalDetail.getId();
|
||||
if (generateModifyDTO.getIsOverride()){
|
||||
path = originalDetail.getUrl().replaceFirst("^[^/]+/", "").replaceFirst("\\.[^.]+$", "");
|
||||
}else {
|
||||
path = accountId + "/sketchboard/" + gender.toLowerCase() + "/" + category + "/" + UUID.randomUUID();
|
||||
// 获取原始路径和可能的generateId
|
||||
PathInfo pathInfo = getOriginalPathAndGenerateId(isFromLibrary, originalId);
|
||||
|
||||
// 确定存储路径
|
||||
String storagePath = isOverride
|
||||
? pathInfo.originalPath.replaceFirst("^[^/]+/", "").replaceFirst("\\.[^.]+$", "")
|
||||
: accountId + "/sketchboard/" + gender + "/" + category + "/" + UUID.randomUUID();
|
||||
|
||||
// 上传到MinIO
|
||||
String minioPath = minioUtil.base64UploadToPath(base64, userBucket, storagePath);
|
||||
log.info("修改后的图片:{}", minioPath);
|
||||
|
||||
// 保存到数据库并返回结果
|
||||
return isFromLibrary
|
||||
? handleLibrarySave(accountId, originalId, minioPath, category, gender, isOverride)
|
||||
: handleGenerateSave(originalId, pathInfo.generateId, minioPath, category, isOverride);
|
||||
}
|
||||
|
||||
private static class PathInfo {
|
||||
String originalPath;
|
||||
Long generateId;
|
||||
|
||||
PathInfo(String originalPath, Long generateId) {
|
||||
this.originalPath = originalPath;
|
||||
this.generateId = generateId;
|
||||
}
|
||||
}
|
||||
|
||||
String minioPath = minioUtil.base64UploadToPath(base64, userBucket, path);
|
||||
private PathInfo getOriginalPathAndGenerateId(boolean isFromLibrary, Long originalId) {
|
||||
if (isFromLibrary) {
|
||||
return new PathInfo(libraryService.getById(originalId).getUrl(), null);
|
||||
} else {
|
||||
GenerateDetail detail = generateDetailMapper.selectById(originalId);
|
||||
return new PathInfo(detail.getUrl(), detail.getGenerateId());
|
||||
}
|
||||
}
|
||||
|
||||
log.info("修改后的图片 : {}", minioPath);
|
||||
private GenerateResultVO handleLibrarySave(Long accountId, Long libraryId, String minioPath,
|
||||
String category, String gender, boolean isOverride) {
|
||||
Library library;
|
||||
if (isOverride) {
|
||||
library = new Library();
|
||||
library.setId(libraryId);
|
||||
library.setUrl(minioPath);
|
||||
library.setUpdateDate(new Date());
|
||||
libraryService.updateById(library);
|
||||
} else {
|
||||
library = new Library(accountId, "Sketchboard", category, gender, minioPath,
|
||||
MD5Utils.encryptFile(minioUtil.getPreSignedUrl(minioPath, CommonConstant.MINIO_IMAGE_EXPIRE_TIME), false),
|
||||
new Date());
|
||||
libraryService.save(library);
|
||||
libraryId = library.getId();
|
||||
}
|
||||
return buildResultVO(libraryId, minioPath, category);
|
||||
}
|
||||
|
||||
// 存入db 保存到t_generate_detail
|
||||
if (!generateModifyDTO.getIsOverride()){
|
||||
GenerateDetail generateDetail = new GenerateDetail();
|
||||
generateDetail.setGenerateId(originalDetail.getGenerateId());
|
||||
private GenerateResultVO handleGenerateSave(Long originalId, Long generateId, String minioPath,
|
||||
String category, boolean isOverride) {
|
||||
GenerateDetail generateDetail = new GenerateDetail();
|
||||
if (isOverride) {
|
||||
generateDetail.setId(originalId);
|
||||
generateDetail.setUrl(minioPath);
|
||||
generateDetail.setUpdateDate(new Date());
|
||||
generateDetailMapper.updateById(generateDetail);
|
||||
} else {
|
||||
generateDetail.setGenerateId(generateId);
|
||||
generateDetail.setUrl(minioPath);
|
||||
generateDetail.setIsLike((byte)0);
|
||||
generateDetail.setMd5(MD5Utils.encryptFile(minioUtil.getPreSignedUrl(minioPath, CommonConstant.MINIO_IMAGE_EXPIRE_TIME, true), Boolean.FALSE));
|
||||
generateDetail.setMd5(MD5Utils.encryptFile(minioUtil.getPreSignedUrl(minioPath,
|
||||
CommonConstant.MINIO_IMAGE_EXPIRE_TIME, true), Boolean.FALSE));
|
||||
generateDetail.setCreateDate(LocalDateTime.now());
|
||||
generateDetailMapper.insert(generateDetail);
|
||||
|
||||
generateDetailId = generateDetail.getId();
|
||||
}else {
|
||||
GenerateDetail generateDetail = new GenerateDetail();
|
||||
generateDetail.setUrl(minioPath);
|
||||
generateDetail.setId(generateDetailId);
|
||||
generateDetailMapper.updateById(generateDetail);
|
||||
originalId = generateDetail.getId();
|
||||
}
|
||||
return buildResultVO(originalId, minioPath, category);
|
||||
}
|
||||
|
||||
return new GenerateResultVO(generateDetailId, minioUtil.getPreSignedUrl(minioPath, CommonConstant.MINIO_IMAGE_EXPIRE_TIME, true), "Success", category);
|
||||
private GenerateResultVO buildResultVO(Long id, String minioPath, String category) {
|
||||
String url = minioUtil.getPreSignedUrl(minioPath, CommonConstant.MINIO_IMAGE_EXPIRE_TIME, true);
|
||||
return new GenerateResultVO(id, url, "Success", category);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import com.ai.da.common.response.PageBaseResponse;
|
||||
import com.ai.da.mapper.primary.PaymentInfoMapper;
|
||||
import com.ai.da.mapper.primary.entity.OrderInfo;
|
||||
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.QueryPageByTimeDTO;
|
||||
import com.ai.da.model.vo.OrderListVO;
|
||||
@@ -232,20 +233,27 @@ public class PaymentInfoServiceImpl extends ServiceImpl<PaymentInfoMapper, Payme
|
||||
qw.eq("transaction_id", invoiceId);
|
||||
PaymentInfo paymentInfo = baseMapper.selectOne(qw);
|
||||
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)){
|
||||
String orderNo;
|
||||
try {
|
||||
String chargeId = invoice.getCharge();
|
||||
orderNo = Charge.retrieve(chargeId).getDescription().replace("AiDA - ", "");
|
||||
// if (invoice.getBillingReason().equals("manual")){
|
||||
// // 手动创建的发票,针对one-time支付
|
||||
//// orderNo = invoice.getLines().getData().get(0).getPrice().getMetadata().get("orderId");
|
||||
// }else {
|
||||
// String subscriptionId = invoice.getSubscription();
|
||||
// // 从subscription中获取orderNo
|
||||
// orderNo = Subscription.retrieve(subscriptionId).getDescription().replace("AiDA - ", "");
|
||||
// }
|
||||
if (invoice.getBillingReason().equals("manual")){
|
||||
// 手动创建的发票,针对one-time支付
|
||||
// orderNo = invoice.getLines().getData().get(0).getPrice().getMetadata().get("orderId");
|
||||
// 当支付失败时,chargeId为空
|
||||
String chargeId = invoice.getCharge();
|
||||
orderNo = Charge.retrieve(chargeId).getDescription().replace("AiDA - ", "");
|
||||
}else {
|
||||
String subscriptionId = invoice.getSubscription();
|
||||
// 从subscription中获取orderNo
|
||||
orderNo = Subscription.retrieve(subscriptionId).getDescription().replace("AiDA - ", "");
|
||||
}
|
||||
} catch (StripeException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
@@ -281,6 +289,7 @@ public class PaymentInfoServiceImpl extends ServiceImpl<PaymentInfoMapper, Payme
|
||||
paymentInfo.setPaymentMethod(paymentMethod.get("paymentMethod"));
|
||||
paymentInfo.setLast4(paymentMethod.get("last4"));
|
||||
paymentInfo.setHostedInvoiceUrl(invoice.getHostedInvoiceUrl());
|
||||
paymentInfo.setPromotionCode(promotionCode);
|
||||
paymentInfo.setCreateTime(LocalDateTime.now());
|
||||
if (!Objects.isNull(orderByOrderNo)){
|
||||
paymentInfo.setCountry(orderByOrderNo.getCountry());
|
||||
@@ -291,6 +300,7 @@ public class PaymentInfoServiceImpl extends ServiceImpl<PaymentInfoMapper, Payme
|
||||
log.info("Payment Info insert affect rows:{}", row);
|
||||
}else {
|
||||
paymentInfo.setTradeState(status);
|
||||
paymentInfo.setPromotionCode(promotionCode);
|
||||
paymentInfo.setUpdateTime(LocalDateTime.now());
|
||||
baseMapper.updateById(paymentInfo);
|
||||
}
|
||||
@@ -300,6 +310,7 @@ public class PaymentInfoServiceImpl extends ServiceImpl<PaymentInfoMapper, Payme
|
||||
public PaymentInfo createOrUpdatePaymentInfoForStripe(Charge charge){
|
||||
Stripe.apiKey = privateKey;
|
||||
QueryWrapper<PaymentInfo> qw = new QueryWrapper<>();
|
||||
// todo 首次支付失败,没有invoiceId,所以如果这个order之后成功支付后,会有多条paymentInfo 是否需要优化??
|
||||
qw.eq("transaction_id", charge.getInvoice());
|
||||
PaymentInfo paymentInfo = baseMapper.selectOne(qw);
|
||||
Charge.PaymentMethodDetails paymentMethodDetails = charge.getPaymentMethodDetails();
|
||||
@@ -421,4 +432,8 @@ public class PaymentInfoServiceImpl extends ServiceImpl<PaymentInfoMapper, Payme
|
||||
return PageBaseResponse.success(orderListVOIPage);
|
||||
}
|
||||
}
|
||||
|
||||
public List<PaymentInfo> getPaymentInfoByPromCode(Long accountId, String promCode){
|
||||
return baseMapper.selectPaidPaymentsByAccountAndPromotion(accountId, promCode);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,19 +5,27 @@ import com.ai.da.common.constant.CommonConstant;
|
||||
import com.ai.da.common.context.UserContext;
|
||||
import com.ai.da.common.enums.*;
|
||||
import com.ai.da.common.utils.DateUtil;
|
||||
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.PaymentInfoMapper;
|
||||
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.CreateCouponDTO;
|
||||
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.vo.CheckCouponsVO;
|
||||
import com.ai.da.service.*;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
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.extension.plugins.pagination.Page;
|
||||
import com.google.gson.Gson;
|
||||
import com.stripe.Stripe;
|
||||
import com.stripe.exception.InvalidRequestException;
|
||||
import com.stripe.exception.SignatureVerificationException;
|
||||
import com.stripe.exception.StripeException;
|
||||
import com.stripe.model.*;
|
||||
@@ -60,13 +68,16 @@ public class StripeServiceImpl implements StripeService {
|
||||
private RefundInfoService refundInfoService;
|
||||
@Resource
|
||||
private AccountService accountService;
|
||||
|
||||
@Resource
|
||||
private AccountMapper accountMapper;
|
||||
@Resource
|
||||
private SubscriptionInfoMapper subscriptionInfoMapper;
|
||||
@Resource
|
||||
private PaymentInfoMapper paymentInfoMapper;
|
||||
@Resource
|
||||
private ProductCouponsMapper productCouponsMapper;
|
||||
@Resource
|
||||
private RedisUtil redisUtil;
|
||||
|
||||
@Value("${stripe.private-key}")
|
||||
private String privateKey;
|
||||
@@ -85,6 +96,9 @@ public class StripeServiceImpl implements StripeService {
|
||||
public String pay(ProductPurchaseDTO productPurchaseDTO, HttpServletRequest request) {
|
||||
Stripe.apiKey = privateKey;
|
||||
|
||||
//创建支付信息得到url
|
||||
// 一次性支付和周期扣款,需要区分mode: payment || subscription || setup
|
||||
SessionCreateParams.Builder sessionBuilder = new SessionCreateParams.Builder();
|
||||
ProductEnum productEnum;
|
||||
switch (productPurchaseDTO.getProductName()){
|
||||
case "CreditsPurchase":
|
||||
@@ -105,6 +119,18 @@ public class StripeServiceImpl implements StripeService {
|
||||
default:
|
||||
throw new BusinessException("unknown subscription type");
|
||||
}
|
||||
|
||||
// 添加优惠券(只允许在订阅时使用优惠券)
|
||||
String promotionCode = productPurchaseDTO.getPromotionCode();
|
||||
if (!StringUtil.isNullOrEmpty(promotionCode)){
|
||||
ProductCoupons productCoupon = checkProductCoupon(promotionCode);;
|
||||
if (productCoupon != null){
|
||||
sessionBuilder.addDiscount(SessionCreateParams.Discount.builder()
|
||||
.setPromotionCode(productCoupon.getPromotionCodeId()).build());
|
||||
}
|
||||
}
|
||||
// 只有订阅时才允许使用推广码优惠
|
||||
// sessionBuilder.setAllowPromotionCodes(true);
|
||||
break;
|
||||
default:
|
||||
throw new BusinessException("unknown product type");
|
||||
@@ -131,12 +157,11 @@ public class StripeServiceImpl implements StripeService {
|
||||
String priceId = getPrice(productEnum.getPrice(), productId, payType, productPurchaseDTO.getSubscribeType());
|
||||
// 获取或创建customer
|
||||
String customerId = getCustomer(account.getUserName(), account.getUserEmail());
|
||||
log.info("customerId:{}", customerId);
|
||||
// 获取自定义订单号
|
||||
String orderId = orderInfo.getOrderNo();
|
||||
|
||||
//创建支付信息得到url
|
||||
// 一次性支付和周期扣款,需要区分mode: payment || subscription || setup
|
||||
SessionCreateParams.Builder sessionBuilder = new SessionCreateParams.Builder();
|
||||
|
||||
if (payType.equals("recurring")){
|
||||
sessionBuilder.setMode(SessionCreateParams.Mode.SUBSCRIPTION);
|
||||
sessionBuilder.setSubscriptionData(SessionCreateParams.SubscriptionData.builder().setDescription("AiDA - " + orderId).build());
|
||||
@@ -148,8 +173,6 @@ public class StripeServiceImpl implements StripeService {
|
||||
}
|
||||
|
||||
sessionBuilder.setPaymentMethodConfiguration(paymentMethodConfigurationId);
|
||||
// sessionBuilder.addPaymentMethodType(SessionCreateParams.PaymentMethodType.ALIPAY);
|
||||
// sessionBuilder.addPaymentMethodType(SessionCreateParams.PaymentMethodType.CARD);
|
||||
sessionBuilder.setCustomer(customerId);
|
||||
sessionBuilder.setSuccessUrl(productPurchaseDTO.getReturnUrl());//可自定义成功页面
|
||||
sessionBuilder.setLocale(account.getLanguage().equals("CHINESE_SIMPLIFIED") ? SessionCreateParams.Locale.ZH : SessionCreateParams.Locale.EN);
|
||||
@@ -171,6 +194,11 @@ public class StripeServiceImpl implements StripeService {
|
||||
// 更新order信息
|
||||
orderInfoService.updateOrderNoById(orderInfo.getId(), orderId);
|
||||
return session.getUrl();
|
||||
} catch (BusinessException e) {
|
||||
throw e;
|
||||
} catch (InvalidRequestException e) {
|
||||
log.info("创建会话出现异常:", e);
|
||||
throw new BusinessException(e.getMessage().substring(0, e.getMessage().indexOf(";")));
|
||||
} catch (Exception e) {
|
||||
log.error("创建支付会话出现异常:", e);
|
||||
}
|
||||
@@ -342,28 +370,31 @@ public class StripeServiceImpl implements StripeService {
|
||||
// 新增支付成功的信息,返回orderNo,表示,该回调第一次被记录
|
||||
PaymentInfo paymentInfo = paymentInfoService.createOrUpdatePaymentInfoForStripe(invoice);
|
||||
|
||||
/* 在sendEmail方法中有做判断,这里的判断取消
|
||||
// 当前支付没有被通知时才需要发送通知邮件
|
||||
if (paymentInfo.getNotified().equals(0)) {
|
||||
// 更新t_order_info中的total_fee,记录该订单的累计付款金额
|
||||
orderInfoService.updateTotalFeeByOrderNo(paymentInfo.getOrderNo());
|
||||
// 邮件通知商家和用户
|
||||
String billingReason = invoice.getBillingReason();
|
||||
switch (billingReason) {
|
||||
case "subscription_create":
|
||||
response = sendEmail(invoice.getSubscription(), "new", null);
|
||||
break;
|
||||
case "subscription_cycle":
|
||||
response = sendEmail(invoice.getSubscription(), "renewal", null);
|
||||
break;
|
||||
case "manual":
|
||||
boolean b = invoice.getLines().getData().get(0).getDescription().endsWith("Subscription");
|
||||
if (b) {
|
||||
// 非自动续订式订阅,Stripe不会创建Subscription,所以invoice中不会有subscriptionId
|
||||
response = sendEmail(null, "new", paymentInfo.getOrderNo());
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}*/
|
||||
// 更新t_order_info中的total_fee,记录该订单的累计付款金额
|
||||
orderInfoService.updateTotalFeeByOrderNo(paymentInfo.getOrderNo());
|
||||
// 邮件通知商家和用户
|
||||
String billingReason = invoice.getBillingReason();
|
||||
switch (billingReason) {
|
||||
case "subscription_create":
|
||||
response = sendEmail(invoice.getSubscription(), "new", null);
|
||||
break;
|
||||
case "subscription_cycle":
|
||||
response = sendEmail(invoice.getSubscription(), "renewal", null);
|
||||
break;
|
||||
case "manual":
|
||||
boolean b = invoice.getLines().getData().get(0).getDescription().endsWith("Subscription");
|
||||
if (b) {
|
||||
// 非自动续订式订阅,Stripe不会创建Subscription,所以invoice中不会有subscriptionId
|
||||
response = sendEmail(null, "new", paymentInfo.getOrderNo());
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
} else if (event.getType().equals("invoice.payment_failed")) {
|
||||
// 更新支付信息
|
||||
QueryWrapper<PaymentInfo> queryWrapper = new QueryWrapper<>();
|
||||
@@ -985,7 +1016,12 @@ public class StripeServiceImpl implements StripeService {
|
||||
// (其实这里也可以通过invoiceId查询stripe,但是记录在自己的db中可以不用每次都查,且方便查看)
|
||||
type = StringUtil.isNullOrEmpty(paymentInfo.getType()) ? "new" : paymentInfo.getType();
|
||||
}
|
||||
if (!type.equals("reminder") && !type.equals("cancel") && paymentInfo.getNotified() == 1){
|
||||
|
||||
// todo 之后这种改成通过email-log来判断
|
||||
String key = RedisUtil.SUBSCRIPTION_SENT_EMAIL_TYPE + subscriptionInfo.getId();
|
||||
// 先判断当前订单 这个类型的邮件是否已发送过
|
||||
Boolean elementExistsInSet = redisUtil.isElementExistsInSet(key, type);
|
||||
if (!type.equals("reminder") && !type.equals("cancel") && paymentInfo.getNotified() == 1 && elementExistsInSet){
|
||||
// 已经邮件通知过,直接返回
|
||||
log.info("不发送邮件,原因:【type为:{},order_no为:{},已经进行邮件通知】", type, orderNo);
|
||||
return true;
|
||||
@@ -1018,6 +1054,9 @@ public class StripeServiceImpl implements StripeService {
|
||||
payment.setUpdateTime(LocalDateTime.now());
|
||||
paymentInfoMapper.updateById(payment);
|
||||
}
|
||||
|
||||
// 将发成功的邮件类型存入redis 避免同一个订阅重复发送相同类型的邮件 subId:type
|
||||
redisUtil.addToSet(key, type, CommonConstant.REDIS_SET_EXPIRE_TIME);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1126,6 +1165,15 @@ public class StripeServiceImpl implements StripeService {
|
||||
emailParamsDTO.setFailMessage(orderByOrderNo.getNote());
|
||||
emailParamsDTO.setSubscriptionType(subscriptionInfo.getType());
|
||||
emailParamsDTO.setStartDate(DateUtil.changeTimeStampFormat(orderByOrderNo.getCreateTime()));
|
||||
if (subscriptionInfo.getType().equals("month")){
|
||||
emailParamsDTO.setRenewalFee(String.valueOf(ProductEnum.MonthlySubscription.getPrice()));
|
||||
} else if (subscriptionInfo.getType().equals("year")){
|
||||
emailParamsDTO.setRenewalFee(String.valueOf(ProductEnum.AnnualSubscription.getPrice()));
|
||||
} else if (subscriptionInfo.getType().equals("day")){
|
||||
emailParamsDTO.setRenewalFee(String.valueOf(ProductEnum.DailySubscription.getPrice()));
|
||||
} else {
|
||||
emailParamsDTO.setRenewalFee("?");
|
||||
}
|
||||
if (subscriptionInfo.getStatus().equals("active")){
|
||||
if (language.equals("ENGLISH")){
|
||||
emailParamsDTO.setEndDate("When cancelled");
|
||||
@@ -1346,4 +1394,266 @@ public class StripeServiceImpl implements StripeService {
|
||||
}
|
||||
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)
|
||||
// percent_off 与 amount_off 不能同时设置
|
||||
.setPercentOff(BigDecimal.valueOf(createCouponDTO.getPercentOff()));
|
||||
if (Objects.nonNull(createCouponDTO.getEndTime())){
|
||||
couponParams.setRedeemBy(createCouponDTO.getEndTime());
|
||||
}
|
||||
try {
|
||||
// 1、创建优惠券
|
||||
Coupon coupon = Coupon.create(couponParams.build());
|
||||
// 2、创建一个推广码
|
||||
PromotionCode promotionCode = createPromotionCode(coupon.getId(), createCouponDTO.getMaxRedemptions());
|
||||
// 3、落库
|
||||
ProductCoupons productCoupons = new ProductCoupons(coupon.getId(), createCouponDTO.getEndTime(), promotionCode.getId(),
|
||||
promotionCode.getCode(), createCouponDTO.getMaxRedemptions(), createCouponDTO.getPercentOff(),
|
||||
createCouponDTO.getCommissionRate(), createCouponDTO.getCooperator(), createCouponDTO.getRemark());
|
||||
productCoupons.setStartTime(createCouponDTO.getStartTime());
|
||||
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 updateCouponsInfo(Long id, String paidCommission, String cooperator, String remark, Long startTime){
|
||||
ProductCoupons productCoupons = productCouponsMapper.selectById(id);
|
||||
if (Objects.isNull(productCoupons)){
|
||||
throw new BusinessException("Unknown Promotion Code");
|
||||
}
|
||||
boolean flag = false;
|
||||
if (!StringUtil.isNullOrEmpty(cooperator)){
|
||||
productCoupons.setCooperator(cooperator);
|
||||
flag = true;
|
||||
}
|
||||
if (!StringUtil.isNullOrEmpty(remark)){
|
||||
productCoupons.setRemark(remark);
|
||||
flag = true;
|
||||
}
|
||||
if (Objects.nonNull(paidCommission)){
|
||||
// 将 paidCommission 从 String 转换为 BigDecimal
|
||||
if (!paidCommission.matches("-?\\d+(\\.\\d+)?")) {
|
||||
throw new BusinessException("Invalid paidCommission value: " + paidCommission);
|
||||
}
|
||||
BigDecimal paidCommissionBigDecimal = new BigDecimal(paidCommission);
|
||||
// 设置已支付佣金
|
||||
productCoupons.setPaidCommission(paidCommissionBigDecimal);
|
||||
BigDecimal commission = Objects.isNull(productCoupons.getCommission()) ? new BigDecimal(0) : productCoupons.getCommission();
|
||||
// 计算未支付佣金
|
||||
BigDecimal unpaidCommission = commission.subtract(paidCommissionBigDecimal);
|
||||
// 设置未支付佣金,确保其不为负数
|
||||
productCoupons.setUnpaidCommission(unpaidCommission.compareTo(BigDecimal.ZERO) > 0 ? unpaidCommission : BigDecimal.ZERO);
|
||||
flag = true;
|
||||
}
|
||||
if (Objects.nonNull(startTime)){
|
||||
productCoupons.setStartTime(startTime);
|
||||
flag = true;
|
||||
}
|
||||
if (flag){
|
||||
productCoupons.setUpdateTime(LocalDateTime.now());
|
||||
productCouponsMapper.updateById(productCoupons);
|
||||
}
|
||||
return productCoupons;
|
||||
}
|
||||
|
||||
public ProductCoupons checkProductCoupon(String promotionCode){
|
||||
Stripe.apiKey = privateKey;
|
||||
Long accountId = UserContext.getUserHolder().getId();
|
||||
String language = UserContext.getUserHolder().getLanguage();
|
||||
// 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 if (Objects.nonNull(productCoupons.getStartTime()) && productCoupons.getStartTime() > epochSecondNow) {
|
||||
String startTime = DateUtil.changeTimeStampFormat(productCoupons.getStartTime(), "seconds", CommonConstant.TIME_FORMAT_yyyy_MM_dd_HH_mm_ss);
|
||||
String en = "This coupon will become active on " + startTime + ". Please try again then!";
|
||||
String cn = "该优惠券尚未到生效时间,请在 " + startTime + " 后使用。";
|
||||
throw new BusinessException(language.equals("ENGLISH") ? en : cn);
|
||||
} 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();
|
||||
String language = UserContext.getUserHolder().getLanguage();
|
||||
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 if (Objects.nonNull(productCoupons.getStartTime()) && productCoupons.getStartTime() > epochSecondNow) {
|
||||
String startTime = DateUtil.changeTimeStampFormat(productCoupons.getStartTime(), "seconds", CommonConstant.TIME_FORMAT_yyyy_MM_dd_HH_mm_ss);
|
||||
String en = "This coupon will become active on " + startTime + ". Please try again then!";
|
||||
String cn = "该优惠券尚未到生效时间,请在 " + startTime + " 后使用。";
|
||||
checkCouponsVO.setMessage(language.equals("ENGLISH") ? en : cn);
|
||||
checkCouponsVO.setStatus("pending");
|
||||
} 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);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void deleteCoupon(Long id){
|
||||
Stripe.apiKey = privateKey;
|
||||
ProductCoupons productCoupons = productCouponsMapper.selectById(id);
|
||||
if (Objects.isNull(productCoupons)){
|
||||
throw new BusinessException("unknown promotion code");
|
||||
}
|
||||
try {
|
||||
Coupon coupon = Coupon.retrieve(productCoupons.getCouponId());
|
||||
coupon.delete();
|
||||
log.info("coupon {} 删除成功", productCoupons.getCouponId());
|
||||
productCouponsMapper.deleteById(id);
|
||||
} catch (StripeException e) {
|
||||
log.error("未知coupons,无法通过couponId: {} 获得Coupons", productCoupons.getCouponId());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -535,6 +535,7 @@ public class UserLikeGroupServiceImpl extends ServiceImpl<UserLikeGroupMapper, U
|
||||
if (type.equals("image")) {
|
||||
String minioUrl = jsonObject1.getString("minioUrl");
|
||||
jsonObject1.put("src", minioUtil.getPreSignedUrl(minioUrl, 24 * 60));
|
||||
jsonObject1.put("crossOrigin", "anonymous");
|
||||
}
|
||||
objects.set(i, jsonObject1);
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ access.python.port=9990
|
||||
access.python.generate_sr_port=9990
|
||||
access.python.address=http://18.167.251.121:9990
|
||||
|
||||
minio.endpoint=https://www.minio.aida.com.hk:12024
|
||||
minio.endpoint=https://www.minio-api.aida.com.hk
|
||||
minio.accessKey=admin
|
||||
minio.secretKey=Aidlab123123!
|
||||
minio.bucketName.clothing=aida-clothing
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
SELECT
|
||||
p.id,
|
||||
a.user_name payer,
|
||||
a.user_email email,
|
||||
p.payment_type platform,
|
||||
p.payer_total,
|
||||
p.type,
|
||||
@@ -149,6 +150,44 @@
|
||||
AND p.transaction_id NOT LIKE 'cs_test%'
|
||||
</select>
|
||||
|
||||
<select id="queryTotalPaymentAmount" resultType="java.math.BigDecimal">
|
||||
SELECT SUM(p.payer_total)
|
||||
FROM t_payment_info p
|
||||
LEFT JOIN t_order_info o ON p.order_no = o.order_no
|
||||
LEFT JOIN t_account a ON a.id = o.account_id
|
||||
WHERE 1 = 1
|
||||
<if test="paymentType != null and paymentType != ''">
|
||||
AND p.payment_type = #{paymentType}
|
||||
</if>
|
||||
<if test="payerTotal != null and payerTotal != ''">
|
||||
AND p.payer_total = #{payerTotal}
|
||||
</if>
|
||||
<if test="type != null and type != ''">
|
||||
AND p.type = #{type}
|
||||
</if>
|
||||
<if test="status != null and status != ''">
|
||||
AND
|
||||
CASE
|
||||
WHEN p.trade_state IN ('paid', 'COMPLETED', 'complete', 'liquidated') THEN 'Success'
|
||||
WHEN p.trade_state IN ('failed', 'expired', 'VOIDED', 'void', 'uncollectible') THEN 'Fail'
|
||||
ELSE 'Pending'
|
||||
END = #{status}
|
||||
</if>
|
||||
<if test="country != null and country != ''">
|
||||
AND p.country = #{country}
|
||||
</if>
|
||||
<if test="city != null and city != ''">
|
||||
AND p.city = #{city}
|
||||
</if>
|
||||
<if test="startTime != null and startTime != '' and endTime != null and endTime != ''">
|
||||
AND p.create_time BETWEEN #{startTime} AND #{endTime}
|
||||
</if>
|
||||
<if test="payer != null and payer != ''">
|
||||
AND a.user_name = #{payer}
|
||||
</if>
|
||||
AND p.transaction_id NOT LIKE 'cs_test%'
|
||||
</select>
|
||||
|
||||
<select id="getCities" resultType="java.util.Map">
|
||||
SELECT DISTINCT city
|
||||
FROM t_payment_info
|
||||
@@ -167,11 +206,21 @@
|
||||
INSERT IGNORE INTO
|
||||
t_payment_info (order_no, transaction_id, payment_type, trade_state, payer_total,
|
||||
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},
|
||||
#{paymentInfo.tradeState}, #{paymentInfo.payerTotal},#{paymentInfo.type}, #{paymentInfo.content},
|
||||
#{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>
|
||||
|
||||
<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>
|
||||
|
||||
@@ -150,6 +150,12 @@ only.original.works.can.participate.in.the.event=Sorry, only original works can
|
||||
remaining.credits.insufficient=Your remaining credits are insufficient for this generation. Please recharge.
|
||||
you.haven't.subscribed.to.any.products.yet=You haven't subscribed to any products yet
|
||||
generate.result.below.standard=The quality of the generated images currently falls below standard. Please consider adjusting your prompt and trying again.
|
||||
partial.design.failed=Partial design failed, Please try again later.
|
||||
email.count.limit=Rate limit reached. Retry in 1 hour.
|
||||
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:
|
||||
|
||||
@@ -130,6 +130,7 @@ the.workspace.lastIndex.not.found=未找到工作区的lastIndex。
|
||||
gender.cannot.be.empty=性别不能为空。
|
||||
image.synthesis.failed=图像合成失败。
|
||||
priority.cannot.be.repeated=优先级不能重复。
|
||||
image.modify.failed=图片修改失败,请稍后重试。
|
||||
slogan.style.cannot.be.empty=标语风格文本不能为空。
|
||||
slogan.image.cannot.be.empty=标语图片不能为空。
|
||||
questionnaire.filled.out=您已填写过当前问卷。
|
||||
@@ -145,6 +146,12 @@ only.original.works.can.participate.in.the.event=抱歉,只有原创作品能
|
||||
remaining.credits.insufficient=您的剩余积分不够本次生成消耗,请充值
|
||||
you.haven't.subscribed.to.any.products.yet=您还未订阅任何产品
|
||||
generate.result.below.standard=当前生成的图像质量低于标准。请考虑调整您的提示词并再次尝试
|
||||
partial.design.failed=局部设计失败。请稍后重试。
|
||||
email.count.limit=您的账号触发邮件发送频率限制,请一小时后重试。
|
||||
model.path.cannot.be.empty=模特路径不能为空
|
||||
this.promotion.code.has.expired=该促销码已过期。
|
||||
this.promotion.code.is.invalid=该促销码无效。
|
||||
one.time.limit.per.customer=该码已兑换。每个促销码每位用户仅限使用一次。
|
||||
|
||||
# 可能会报异常
|
||||
# Informative:
|
||||
|
||||
Reference in New Issue
Block a user