From fd10d4dbc448f1c53b7721b5b23416f260cc5e21 Mon Sep 17 00:00:00 2001 From: shahaibo <1023316923@qq.com> Date: Wed, 13 Nov 2024 15:44:48 +0800 Subject: [PATCH 01/91] =?UTF-8?q?TASK:=E8=B0=B7=E6=AD=8C=E7=99=BB=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 22 +++ .../ai/da/controller/AccountController.java | 35 ++++ .../da/controller/ThirdPartyController.java | 8 + .../ai/da/mapper/primary/entity/Account.java | 14 ++ .../com/ai/da/model/dto/AccountLoginDTO.java | 2 + .../com/ai/da/model/dto/AddSubAccountDTO.java | 12 ++ .../ai/da/model/dto/SubAccountPageDTO.java | 9 + .../com/ai/da/service/AccountService.java | 16 ++ .../da/service/impl/AccountServiceImpl.java | 187 ++++++++++++++++++ 9 files changed, 305 insertions(+) create mode 100644 src/main/java/com/ai/da/model/dto/AddSubAccountDTO.java create mode 100644 src/main/java/com/ai/da/model/dto/SubAccountPageDTO.java diff --git a/pom.xml b/pom.xml index e20e83e1..ff9df865 100644 --- a/pom.xml +++ b/pom.xml @@ -288,6 +288,28 @@ spring-boot-starter-websocket + + com.google.auth + google-auth-library-oauth2-http + 1.8.0 + + + + com.google.api-client + google-api-client + 1.32.1 + + + com.google.oauth-client + google-oauth-client + 1.32.1 + + + com.google.http-client + google-http-client-jackson2 + 1.41.5 + + diff --git a/src/main/java/com/ai/da/controller/AccountController.java b/src/main/java/com/ai/da/controller/AccountController.java index c73fcdaa..0332154a 100644 --- a/src/main/java/com/ai/da/controller/AccountController.java +++ b/src/main/java/com/ai/da/controller/AccountController.java @@ -3,6 +3,7 @@ package com.ai.da.controller; import com.ai.da.common.config.exception.BusinessException; import com.ai.da.common.response.PageBaseResponse; import com.ai.da.common.response.Response; +import com.ai.da.mapper.primary.entity.Account; import com.ai.da.mapper.primary.entity.TrialOrder; import com.ai.da.model.dto.*; import com.ai.da.model.vo.AccountLoginVO; @@ -261,5 +262,39 @@ public class AccountController { return Response.success(true); } + @PostMapping("enterpriseLogin") + @ApiOperation(value = "企业登录") + public Response enterpriseLogin(@Valid @RequestBody AccountLoginDTO accountDTO) { + return Response.success(accountService.enterpriseLogin(accountDTO)); + } + @PostMapping("schoolLogin") + @ApiOperation(value = "学校登录") + public Response schoolLogin(@Valid @RequestBody AccountLoginDTO accountDTO) { + return Response.success(accountService.schoolLogin(accountDTO)); + } + + @PostMapping("addOrUpdateSubAccount") + @ApiOperation(value = "子账号新增") + public Response addSubAccount(@Valid @RequestBody AddSubAccountDTO addSubAccountDTO) { + return Response.success(accountService.addSubAccount(addSubAccountDTO)); + } + + @PostMapping("deleteSubAccount") + @ApiOperation(value = "子账号删除") + public Response deleteSubAccount(@Valid @RequestBody AddSubAccountDTO addSubAccountDTO) { + return Response.success(accountService.deleteSubAccount(addSubAccountDTO)); + } + + @PostMapping("subAccountList") + @ApiOperation(value = "子账号查询") + public Response> subAccountList(@Valid @RequestBody SubAccountPageDTO subAccountPageDTO) { + return Response.success(accountService.subAccountList(subAccountPageDTO)); + } + + @GetMapping("accountDetail") + @ApiOperation(value = "账号详情") + public Response accountDetail(@RequestParam("id") Long id) { + return Response.success(accountService.accountDetail(id)); + } } diff --git a/src/main/java/com/ai/da/controller/ThirdPartyController.java b/src/main/java/com/ai/da/controller/ThirdPartyController.java index e077fa8c..e0047d62 100644 --- a/src/main/java/com/ai/da/controller/ThirdPartyController.java +++ b/src/main/java/com/ai/da/controller/ThirdPartyController.java @@ -1,6 +1,7 @@ package com.ai.da.controller; import com.ai.da.common.response.Response; +import com.ai.da.mapper.primary.entity.GoogleUser; import com.ai.da.model.dto.*; import com.ai.da.model.vo.AccountLoginVO; import com.ai.da.service.AccountService; @@ -121,4 +122,11 @@ public class ThirdPartyController { public Response googleCallback(@RequestParam("code") String code, HttpSession session) { return Response.success(accountService.googleCallback(code, session)); } + @CrossOrigin + @GetMapping("/parseGoogleCredential") + public Response parseGoogleCredential(@RequestParam("credential") String credential) { + return Response.success(accountService.parseGoogleCredential(credential)); + } + + } diff --git a/src/main/java/com/ai/da/mapper/primary/entity/Account.java b/src/main/java/com/ai/da/mapper/primary/entity/Account.java index 285acd90..3629eedf 100644 --- a/src/main/java/com/ai/da/mapper/primary/entity/Account.java +++ b/src/main/java/com/ai/da/mapper/primary/entity/Account.java @@ -97,6 +97,10 @@ public class Account implements Serializable { * 2 : 月付用户 * 3 : 试用用户 * 4 : 参加活动获取30天有效期和6000个积分的用户 + * 5 : 企业管理员账号 + * 6 : 企业子账号 + * 7 : 学校管理员 + * 8 : 学校子账号 */ private Integer systemUser; @@ -104,4 +108,14 @@ public class Account implements Serializable { * 头像 */ private String avatar; + + private String organizationName; + + private Long parentId; + + private Integer isAdmin; + + private BigDecimal shareCredits; + + private Integer subAccountNum; } diff --git a/src/main/java/com/ai/da/model/dto/AccountLoginDTO.java b/src/main/java/com/ai/da/model/dto/AccountLoginDTO.java index 2c1483c9..2f536ffb 100644 --- a/src/main/java/com/ai/da/model/dto/AccountLoginDTO.java +++ b/src/main/java/com/ai/da/model/dto/AccountLoginDTO.java @@ -32,4 +32,6 @@ public class AccountLoginDTO { @ApiModelProperty("邮箱验证码") private String emailVerifyCode; + private String organizationName; + } diff --git a/src/main/java/com/ai/da/model/dto/AddSubAccountDTO.java b/src/main/java/com/ai/da/model/dto/AddSubAccountDTO.java new file mode 100644 index 00000000..2f894789 --- /dev/null +++ b/src/main/java/com/ai/da/model/dto/AddSubAccountDTO.java @@ -0,0 +1,12 @@ +package com.ai.da.model.dto; + +import com.ai.da.mapper.primary.entity.Account; +import lombok.Data; + +import java.util.List; + +@Data +public class AddSubAccountDTO extends Account { + + private List deleteIdList; +} diff --git a/src/main/java/com/ai/da/model/dto/SubAccountPageDTO.java b/src/main/java/com/ai/da/model/dto/SubAccountPageDTO.java new file mode 100644 index 00000000..f5dcc995 --- /dev/null +++ b/src/main/java/com/ai/da/model/dto/SubAccountPageDTO.java @@ -0,0 +1,9 @@ +package com.ai.da.model.dto; + +import com.ai.da.model.vo.PageQueryBaseVo; +import lombok.Data; + +@Data +public class SubAccountPageDTO extends PageQueryBaseVo { + private String userName; +} diff --git a/src/main/java/com/ai/da/service/AccountService.java b/src/main/java/com/ai/da/service/AccountService.java index bd9c99b4..2d86fdf2 100644 --- a/src/main/java/com/ai/da/service/AccountService.java +++ b/src/main/java/com/ai/da/service/AccountService.java @@ -1,6 +1,8 @@ package com.ai.da.service; +import com.ai.da.common.response.PageBaseResponse; import com.ai.da.mapper.primary.entity.Account; +import com.ai.da.mapper.primary.entity.GoogleUser; import com.ai.da.mapper.primary.entity.TrialOrder; import com.ai.da.model.dto.*; import com.ai.da.model.vo.AccountLoginVO; @@ -186,4 +188,18 @@ public interface AccountService extends IService { String googleCallback(String code, HttpSession session); List getPaidCustomerEmail(); + + AccountLoginVO enterpriseLogin(AccountLoginDTO accountDTO); + + AccountLoginVO schoolLogin(AccountLoginDTO accountDTO); + + Boolean addSubAccount(AddSubAccountDTO addSubAccountDTO); + + Boolean deleteSubAccount(AddSubAccountDTO addSubAccountDTO); + + PageBaseResponse subAccountList(SubAccountPageDTO subAccountPageDTO); + + Account accountDetail(Long id); + + GoogleUser parseGoogleCredential(String credential); } diff --git a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java index bead403e..03145804 100644 --- a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java @@ -7,6 +7,7 @@ import com.ai.da.common.context.UserContext; import com.ai.da.common.enums.AuthenticationOperationTypeEnum; import com.ai.da.common.enums.CreditsEventsEnum; import com.ai.da.common.enums.LoginTypeEnum; +import com.ai.da.common.response.PageBaseResponse; import com.ai.da.common.response.ResultEnum; import com.ai.da.common.security.jwt.JWTTokenHelper; import com.ai.da.common.utils.*; @@ -25,6 +26,13 @@ import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken; +import com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier; +import com.google.api.client.http.javanet.NetHttpTransport; +import com.google.api.client.json.jackson2.JacksonFactory; +import com.google.auth.oauth2.IdToken; +import com.google.auth.oauth2.TokenVerifier; +import com.google.common.base.Function; import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; import io.netty.util.internal.StringUtil; @@ -1945,4 +1953,183 @@ public class AccountServiceImpl extends ServiceImpl impl // return userRepository.save(newUser); // } + + @Override + public AccountLoginVO enterpriseLogin(AccountLoginDTO accountDTO) { + QueryWrapper qw = new QueryWrapper<>(); + qw.lambda().eq(Account::getUserName, accountDTO.getUserName()); + qw.lambda().eq(Account::getOrganizationName, accountDTO.getOrganizationName()); + List accounts = accountMapper.selectList(qw); + if (CollectionUtil.isEmpty(accounts)) { + throw new BusinessException("Username or enterprise name incorrect."); + } + qw.lambda().eq(Account::getUserPassword, accountDTO.getPassword()); + accounts = accountMapper.selectList(qw); + if (CollectionUtil.isEmpty(accounts)) { + throw new BusinessException("Password error."); + } + Account account = accounts.get(0); + AccountLoginVO response = CopyUtil.copyObject(account, AccountLoginVO.class); + response.setEmail(account.getUserEmail()); + String token = LocalCacheUtils.getTokenCache(String.valueOf(account.getId())); + if (StringUtils.isNotBlank(token)) { + //用户已登入 + response.setToken(token); + } else { + response.setToken(createAccountToken(account)); + } + response.setUserId(account.getId()); + response.setSystemUser(account.getSystemUser()); + // 设置头像 + String avatar; + if (StringUtil.isNullOrEmpty(account.getAvatar())){ + avatar = CommonConstant.DEFAULT_AVATAR; + }else { + avatar = account.getAvatar(); + } + response.setAvatar(minioUtil.getPreSignedUrl(avatar, CommonConstant.MINIO_IMAGE_EXPIRE_TIME)); + response.setFolloweeCount(portfolioService.getFolloweeCount(account.getId())); + response.setFollowerCount(portfolioService.getFollowerCount(account.getId())); + //判断是否常用ip 不是则发邮件提示 +// calculateExceptionIp(RequestInfoUtil.getIpAddress(request), account); + return response; + } + + @Override + public AccountLoginVO schoolLogin(AccountLoginDTO accountDTO) { + QueryWrapper qw = new QueryWrapper<>(); + qw.lambda().eq(Account::getUserName, accountDTO.getUserName()); + qw.lambda().eq(Account::getOrganizationName, accountDTO.getOrganizationName()); + List accounts = accountMapper.selectList(qw); + if (CollectionUtil.isEmpty(accounts)) { + throw new BusinessException("Username or school name incorrect."); + } + qw.lambda().eq(Account::getUserPassword, accountDTO.getPassword()); + accounts = accountMapper.selectList(qw); + if (CollectionUtil.isEmpty(accounts)) { + throw new BusinessException("Password error."); + } + Account account = accounts.get(0); + AccountLoginVO response = CopyUtil.copyObject(account, AccountLoginVO.class); + response.setEmail(account.getUserEmail()); + String token = LocalCacheUtils.getTokenCache(String.valueOf(account.getId())); + if (StringUtils.isNotBlank(token)) { + //用户已登入 + response.setToken(token); + } else { + response.setToken(createAccountToken(account)); + } + response.setUserId(account.getId()); + response.setSystemUser(account.getSystemUser()); + // 设置头像 + String avatar; + if (StringUtil.isNullOrEmpty(account.getAvatar())){ + avatar = CommonConstant.DEFAULT_AVATAR; + }else { + avatar = account.getAvatar(); + } + response.setAvatar(minioUtil.getPreSignedUrl(avatar, CommonConstant.MINIO_IMAGE_EXPIRE_TIME)); + response.setFolloweeCount(portfolioService.getFolloweeCount(account.getId())); + response.setFollowerCount(portfolioService.getFollowerCount(account.getId())); + //判断是否常用ip 不是则发邮件提示 +// calculateExceptionIp(RequestInfoUtil.getIpAddress(request), account); + return response; + } + + @Override + public Boolean addSubAccount(AddSubAccountDTO addSubAccountDTO) { + if (null == addSubAccountDTO.getId()) { + AuthPrincipalVo authPrincipalVo = UserContext.getUserHolder(); + Account account = accountMapper.selectById(authPrincipalVo.getId()); + + QueryWrapper qw = new QueryWrapper<>(); + qw.lambda().eq(Account::getOrganizationName, account.getOrganizationName()); + List accounts = accountMapper.selectList(qw); + if (accounts.size() >= account.getSubAccountNum()) { + throw new BusinessException("The maximum number of sub accounts that can be created has been reached."); + } + + qw.lambda().eq(Account::getUserName, addSubAccountDTO.getUserName()); + accounts = accountMapper.selectList(qw); + if (CollectionUtil.isNotEmpty(accounts)) { + throw new BusinessException("The enterprise already has an account with the same username."); + } + + Account subAccount = CopyUtil.copyObject(addSubAccountDTO, Account.class); + subAccount.setSystemUser(6); + subAccount.setValidStartTime(account.getValidStartTime()); + subAccount.setValidEndTime(account.getValidEndTime()); + subAccount.setLanguage(Language.ENGLISH.name()); + subAccount.setCreateDate(new Date()); + subAccount.setIsTrial(0); + subAccount.setIsBeginner(1); + subAccount.setParentId(account.getParentId()); + accountMapper.insert(subAccount); + }else { + Account subAccount = CopyUtil.copyObject(addSubAccountDTO, Account.class); + accountMapper.updateById(subAccount); + } + + + return Boolean.TRUE; + } + + @Override + public Boolean deleteSubAccount(AddSubAccountDTO addSubAccountDTO) { + accountMapper.deleteBatchIds(addSubAccountDTO.getDeleteIdList()); + return Boolean.TRUE; + } + + @Override + public PageBaseResponse subAccountList(SubAccountPageDTO subAccountPageDTO) { + AuthPrincipalVo authPrincipalVo = UserContext.getUserHolder(); + Account account = accountMapper.selectById(authPrincipalVo); + QueryWrapper qw = new QueryWrapper<>(); + qw.lambda().ne(Account::getId, account.getId()); + qw.lambda().eq(Account::getOrganizationName, account.getOrganizationName()); + // 执行分页查询 + IPage page = accountMapper.selectPage(new Page<>(subAccountPageDTO.getPage(), subAccountPageDTO.getSize()), qw); + + return PageBaseResponse.success(page); + } + + @Override + public Account accountDetail(Long id) { + return accountMapper.selectById(id); + } + + @Override + public GoogleUser parseGoogleCredential(String credential) { + try { + // 配置 Google ID Token 验证器 + GoogleIdTokenVerifier verifier = new GoogleIdTokenVerifier.Builder( + new NetHttpTransport(), + JacksonFactory.getDefaultInstance()) + .setAudience(Collections.singletonList(CLIENT_ID)) + .build(); + + // 验证并解析 ID Token + GoogleIdToken idToken = verifier.verify(credential); + + if (idToken != null) { + GoogleIdToken.Payload payload = idToken.getPayload(); + + // 提取用户信息 + String userId = payload.getSubject(); + String email = payload.getEmail(); + String name = (String) payload.get("name"); + log.info(userId); + log.info(email); + log.info(name); + + return new GoogleUser(); + } else { + throw new IllegalArgumentException("Invalid ID token."); + } + + } catch (Exception e) { + e.printStackTrace(); + throw new RuntimeException("Failed to verify ID token: " + e.getMessage()); + } + } } From 9f064609e715a00d3b63f05cf41f1a1658309216 Mon Sep 17 00:00:00 2001 From: shahaibo <1023316923@qq.com> Date: Wed, 13 Nov 2024 15:45:40 +0800 Subject: [PATCH 02/91] =?UTF-8?q?TASK:=E8=B0=B7=E6=AD=8C=E7=99=BB=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/ai/da/common/security/filter/AuthenticationFilter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/ai/da/common/security/filter/AuthenticationFilter.java b/src/main/java/com/ai/da/common/security/filter/AuthenticationFilter.java index a70bc51b..05117ec4 100644 --- a/src/main/java/com/ai/da/common/security/filter/AuthenticationFilter.java +++ b/src/main/java/com/ai/da/common/security/filter/AuthenticationFilter.java @@ -51,7 +51,7 @@ public class AuthenticationFilter extends OncePerRequestFilter { "/api/python/flush","/api/account/healthy","/api/ali-pay/trade/notify","/api/paypal/ipn/back","/api/alipay-hk/trade/notify", "/api/portfolio/page", "/api/portfolio/detail", "/api/portfolio/commentPage", "/api/portfolio/viewsIncrease", "/api/account/designWorksRegister","/api/account/questionnaire","/api/stripe/trade/notify", - "/notification","/api/account/activateNewEmail","/api/third/party/auth/google_callback" + "/notification","/api/account/activateNewEmail","/api/third/party/auth/google_callback","/api/third/party/parseGoogleCredential" ); @Override From 8d27b5b51ebb1172cefd29293fe115675eb1b09a Mon Sep 17 00:00:00 2001 From: xupei Date: Mon, 18 Nov 2024 16:20:25 +0800 Subject: [PATCH 03/91] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=8A=9F=E8=83=BD=20--?= =?UTF-8?q?=20=E4=BA=A7=E5=93=81=E8=AE=A2=E9=98=85=20=E5=B9=B4=E5=BA=A6/?= =?UTF-8?q?=E6=9C=88=E5=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ai/da/common/constant/CommonConstant.java | 4 + .../com/ai/da/common/enums/ProductEnum.java | 25 + .../com/ai/da/common/task/AliPayTask.java | 42 -- .../com/ai/da/common/task/GenerateTask.java | 21 - .../com/ai/da/common/task/PaymentTask.java | 96 +++ .../com/ai/da/common/task/PaypalTask.java | 42 -- .../com/ai/da/common/task/StripeTask.java | 40 -- .../com/ai/da/common/utils/SendEmailUtil.java | 92 +++ .../ai/da/controller/StripeController.java | 32 +- .../primary/SubscriptionInfoMapper.java | 8 + .../da/mapper/primary/entity/PaymentInfo.java | 10 +- .../primary/entity/SubscriptionInfo.java | 43 ++ .../ai/da/model/dto/ProductPurchaseDTO.java | 32 + .../model/dto/SubscriptionEmailParamsDTO.java | 47 ++ .../com/ai/da/service/OrderInfoService.java | 6 + .../com/ai/da/service/PaymentInfoService.java | 7 +- .../java/com/ai/da/service/StripeService.java | 24 +- .../da/service/impl/OrderInfoServiceImpl.java | 74 +- .../service/impl/PaymentInfoServiceImpl.java | 61 +- .../ai/da/service/impl/StripeServiceImpl.java | 633 ++++++++++++++---- src/main/resources/payment.properties | 8 +- 21 files changed, 1029 insertions(+), 318 deletions(-) create mode 100644 src/main/java/com/ai/da/common/enums/ProductEnum.java delete mode 100644 src/main/java/com/ai/da/common/task/AliPayTask.java delete mode 100644 src/main/java/com/ai/da/common/task/GenerateTask.java create mode 100644 src/main/java/com/ai/da/common/task/PaymentTask.java delete mode 100644 src/main/java/com/ai/da/common/task/PaypalTask.java delete mode 100644 src/main/java/com/ai/da/common/task/StripeTask.java create mode 100644 src/main/java/com/ai/da/mapper/primary/SubscriptionInfoMapper.java create mode 100644 src/main/java/com/ai/da/mapper/primary/entity/SubscriptionInfo.java create mode 100644 src/main/java/com/ai/da/model/dto/ProductPurchaseDTO.java create mode 100644 src/main/java/com/ai/da/model/dto/SubscriptionEmailParamsDTO.java diff --git a/src/main/java/com/ai/da/common/constant/CommonConstant.java b/src/main/java/com/ai/da/common/constant/CommonConstant.java index 71f6c86b..e495ee26 100644 --- a/src/main/java/com/ai/da/common/constant/CommonConstant.java +++ b/src/main/java/com/ai/da/common/constant/CommonConstant.java @@ -75,5 +75,9 @@ public class CommonConstant { public static final String PORTFOLIO_DELETED_CN = "作品已删除"; + public static final String TIME_FORMAT_MMM_dd_yyyy_EEEE = "MMM. dd, yyyy, EEEE"; + + public static final String TIME_FORMAT_MMM_dd_yyyy = "MMM. dd, yyyy"; + } diff --git a/src/main/java/com/ai/da/common/enums/ProductEnum.java b/src/main/java/com/ai/da/common/enums/ProductEnum.java new file mode 100644 index 00000000..11237ffe --- /dev/null +++ b/src/main/java/com/ai/da/common/enums/ProductEnum.java @@ -0,0 +1,25 @@ +package com.ai.da.common.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public enum ProductEnum { + // 积分购买 + CreditsProduct("AiDA credits purchase", 6L), + // 年度订阅 + AnnualSubscription("AiDA Annual Subscription", 5000L), + // 月度订阅 + MonthlySubscription("AiDA Monthly Subscription", 500L), + // 测试 + DailySubscription("AiDA Daily Subscription", 5L), + ; + + /** + * 类型 + */ + private final String name; + + private final Long price; +} diff --git a/src/main/java/com/ai/da/common/task/AliPayTask.java b/src/main/java/com/ai/da/common/task/AliPayTask.java deleted file mode 100644 index 670a417c..00000000 --- a/src/main/java/com/ai/da/common/task/AliPayTask.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.ai.da.common.task; - -import com.ai.da.mapper.primary.entity.OrderInfo; -import com.ai.da.common.enums.PayTypeEnum; -import com.ai.da.service.AliPayService; -import com.ai.da.service.OrderInfoService; -import lombok.extern.slf4j.Slf4j; -import org.springframework.scheduling.annotation.Scheduled; -import org.springframework.stereotype.Component; - -import javax.annotation.Resource; -import java.util.List; - -@Slf4j -@Component -public class AliPayTask { - - @Resource - private OrderInfoService orderInfoService; - - @Resource - private AliPayService aliPayService; - - /** - * 从第0秒开始每隔30秒执行1次,查询创建超过5分钟,并且未支付的订单 - */ -// @Scheduled(cron = "0/30 * * * * ?") - public void orderConfirm(){ - -// log.info("Alipay orderConfirm 被执行......"); - - List orderInfoList = orderInfoService.getNoPayOrderByDuration(5, PayTypeEnum.ALIPAY.getType()); - - for (OrderInfo orderInfo : orderInfoList) { - String orderNo = orderInfo.getOrderNo(); - log.warn("超时订单 ===> {}", orderNo); - - //核实订单状态:调用支付宝查单接口 - aliPayService.checkOrderStatus(orderNo); - } - } -} diff --git a/src/main/java/com/ai/da/common/task/GenerateTask.java b/src/main/java/com/ai/da/common/task/GenerateTask.java deleted file mode 100644 index 038976d0..00000000 --- a/src/main/java/com/ai/da/common/task/GenerateTask.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.ai.da.common.task; - -import lombok.extern.slf4j.Slf4j; -import org.springframework.scheduling.annotation.Scheduled; -import org.springframework.stereotype.Component; - -@Component -@Slf4j -public class GenerateTask { - -// @Scheduled(cron = "0 0 */1 * * ?") - public void generateScheduled(){ - log.info("测试定时器:generate"); - - try{ - - }catch(Exception e){ - - } - } -} diff --git a/src/main/java/com/ai/da/common/task/PaymentTask.java b/src/main/java/com/ai/da/common/task/PaymentTask.java new file mode 100644 index 00000000..656e3a23 --- /dev/null +++ b/src/main/java/com/ai/da/common/task/PaymentTask.java @@ -0,0 +1,96 @@ +package com.ai.da.common.task; + +import com.ai.da.common.enums.PayTypeEnum; +import com.ai.da.mapper.primary.entity.OrderInfo; +import com.ai.da.service.AliPayService; +import com.ai.da.service.OrderInfoService; +import com.ai.da.service.PayPalCheckoutService; +import com.ai.da.service.StripeService; +import com.paypal.http.exceptions.SerializeException; +import lombok.extern.slf4j.Slf4j; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.util.List; + +@Slf4j +@Component +public class PaymentTask { + + @Resource + private OrderInfoService orderInfoService; + + @Resource + private StripeService stripeService; + +// @Scheduled(cron = "0/30 * * * * ?") + public void orderConfirmForStripe() throws SerializeException { + + // 查看超过30分钟以上仍未支付的订单 置为超时订单 + List orderInfoList = orderInfoService.getNoPayOrderByDuration(30, PayTypeEnum.STRIPE.getType()); + + for (OrderInfo orderInfo : orderInfoList) { + String orderNo = orderInfo.getOrderNo(); + log.warn("超时订单 ===> {}", orderNo); + + //核实订单状态:调用支付宝查单接口 + stripeService.checkOrderStatus(orderNo); + + } + } + + @Resource + private PayPalCheckoutService payPalCheckoutService; + + // @Scheduled(cron = "0/30 * * * * ?") + public void orderConfirmForPaypal() throws SerializeException { + +// log.info("PayPal orderConfirm 被执行......"); + + List orderInfoList = orderInfoService.getNoPayOrderByDuration(30, PayTypeEnum.PAYPAL.getType()); + + for (OrderInfo orderInfo : orderInfoList) { + String orderNo = orderInfo.getOrderNo(); + log.warn("超时订单 ===> {}", orderNo); + + //核实订单状态:调用支付宝查单接口 + payPalCheckoutService.checkOrderStatus(orderNo); + + } + } + + @Resource + private AliPayService aliPayService; + + /** + * 从第0秒开始每隔30秒执行1次,查询创建超过5分钟,并且未支付的订单 + */ +// @Scheduled(cron = "0/30 * * * * ?") + public void orderConfirmForAlipay(){ +/* + log.info("Alipay orderConfirm 被执行......"); + + List orderInfoList = orderInfoService.getNoPayOrderByDuration(5, PayTypeEnum.ALIPAY.getType()); + + for (OrderInfo orderInfo : orderInfoList) { + String orderNo = orderInfo.getOrderNo(); + log.warn("超时订单 ===> {}", orderNo); + + //核实订单状态:调用支付宝查单接口 + aliPayService.checkOrderStatus(orderNo); + }*/ + } + + // 提前7天向用户发送提醒邮件,每天早上8点执行 + @Scheduled(cron = "0 0 8 * * ?") + public void subscriptionReminder(){ + stripeService.subscriptionReminder(); + } + + // 每天凌晨检查subscription中有哪些已过期,更新状态 + @Scheduled(cron = "0 0 0 * * ?") + public void checkSubscriptionExpiration(){ + stripeService.checkSubscriptionExpiration(); + } +} diff --git a/src/main/java/com/ai/da/common/task/PaypalTask.java b/src/main/java/com/ai/da/common/task/PaypalTask.java deleted file mode 100644 index fa069971..00000000 --- a/src/main/java/com/ai/da/common/task/PaypalTask.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.ai.da.common.task; - -import com.ai.da.common.enums.PayTypeEnum; -import com.ai.da.mapper.primary.entity.OrderInfo; -import com.ai.da.service.OrderInfoService; -import com.ai.da.service.PayPalCheckoutService; -import com.paypal.http.exceptions.SerializeException; -import lombok.extern.slf4j.Slf4j; -import org.springframework.scheduling.annotation.Scheduled; -import org.springframework.stereotype.Component; -import org.springframework.stereotype.Service; - -import javax.annotation.Resource; -import java.util.List; - -@Slf4j -@Component -public class PaypalTask { - - @Resource - private OrderInfoService orderInfoService; - - @Resource - private PayPalCheckoutService payPalCheckoutService; - -// @Scheduled(cron = "0/30 * * * * ?") - public void orderConfirm() throws SerializeException { - -// log.info("PayPal orderConfirm 被执行......"); - - List orderInfoList = orderInfoService.getNoPayOrderByDuration(30, PayTypeEnum.PAYPAL.getType()); - - for (OrderInfo orderInfo : orderInfoList) { - String orderNo = orderInfo.getOrderNo(); - log.warn("超时订单 ===> {}", orderNo); - - //核实订单状态:调用支付宝查单接口 - payPalCheckoutService.checkOrderStatus(orderNo); - - } - } -} diff --git a/src/main/java/com/ai/da/common/task/StripeTask.java b/src/main/java/com/ai/da/common/task/StripeTask.java deleted file mode 100644 index d4a6fbaf..00000000 --- a/src/main/java/com/ai/da/common/task/StripeTask.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.ai.da.common.task; - -import com.ai.da.common.enums.PayTypeEnum; -import com.ai.da.mapper.primary.entity.OrderInfo; -import com.ai.da.service.OrderInfoService; -import com.ai.da.service.StripeService; -import com.paypal.http.exceptions.SerializeException; -import lombok.extern.slf4j.Slf4j; -import org.springframework.scheduling.annotation.Scheduled; -import org.springframework.stereotype.Component; - -import javax.annotation.Resource; -import java.util.List; - -@Slf4j -@Component -public class StripeTask { - - @Resource - private OrderInfoService orderInfoService; - - @Resource - private StripeService stripeService; - -// @Scheduled(cron = "0/30 * * * * ?") - public void orderConfirm() throws SerializeException { - - // 查看超过30分钟以上仍未支付的订单 置为超时订单 - List orderInfoList = orderInfoService.getNoPayOrderByDuration(30, PayTypeEnum.STRIPE.getType()); - - for (OrderInfo orderInfo : orderInfoList) { - String orderNo = orderInfo.getOrderNo(); - log.warn("超时订单 ===> {}", orderNo); - - //核实订单状态:调用支付宝查单接口 - stripeService.checkOrderStatus(orderNo); - - } - } -} diff --git a/src/main/java/com/ai/da/common/utils/SendEmailUtil.java b/src/main/java/com/ai/da/common/utils/SendEmailUtil.java index a89115f8..d1a30ae1 100644 --- a/src/main/java/com/ai/da/common/utils/SendEmailUtil.java +++ b/src/main/java/com/ai/da/common/utils/SendEmailUtil.java @@ -2,8 +2,10 @@ package com.ai.da.common.utils; import com.ai.da.mapper.primary.entity.Account; import com.ai.da.mapper.primary.entity.TrialOrder; +import com.ai.da.model.dto.SubscriptionEmailParamsDTO; import com.alibaba.fastjson.JSONObject; import com.ai.da.common.config.exception.BusinessException; +import com.alibaba.fastjson2.JSON; import com.tencentcloudapi.common.Credential; import com.tencentcloudapi.common.exception.TencentCloudSDKException; import com.tencentcloudapi.common.profile.ClientProfile; @@ -767,4 +769,94 @@ public class SendEmailUtil { throw new BusinessException("failed.to.send.mail"); } } + + private final static Long CANCEL_MERCHANT_EN = 130720L; + 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 RENEWAL_MERCHANT_EN = 130724L; + private final static Long RENEWAL_USER_EN = 130725L; + private final static Long RENEWAL_USER_CN = 130726L; + private final static Long RENEWAL_REMINDER_USER_EN = 130727L; + private final static Long RENEWAL_REMINDER_USER_CN = 130728L; + + public static void subscriptionEmailReminder(String type, SubscriptionEmailParamsDTO subscriptionEmailParamsDTO, String language, String receiverAddress){ + try{ + String kimEmail = "kimwong@code-create.com.hk"; + Credential cred = new Credential(SECRET_ID, SECRET_KEy); + // 实例化一个http选项,可选的,没有特殊需求可以跳过 + HttpProfile httpProfile = new HttpProfile(); + httpProfile.setEndpoint("ses.tencentcloudapi.com"); + // 实例化一个client选项,可选的,没有特殊需求可以跳过 + ClientProfile clientProfile = new ClientProfile(); + clientProfile.setHttpProfile(httpProfile); + // 实例化要请求产品的client对象,clientProfile是可选的 + SesClient client = new SesClient(cred, "ap-hongkong", clientProfile); + // 实例化一个请求对象,每个接口都会对应一个request对象 + SendEmailRequest user = new SendEmailRequest(); + user.setFromEmailAddress(SEND_ADDRESS); + user.setDestination(new String[]{receiverAddress}); + SendEmailRequest merchant = new SendEmailRequest(); + merchant.setFromEmailAddress(SEND_ADDRESS); + merchant.setDestination(new String[]{kimEmail}); + Template templateUser = new Template(); + Template templateMerchant = new Template(); + switch (type) { + case "cancel": + merchant.setSubject("[Code-Create] Subscription Cancelled"); + templateMerchant.setTemplateID(CANCEL_MERCHANT_EN); + break; + case "new": + merchant.setSubject("[Code-Create] New Order(" + subscriptionEmailParamsDTO.getOrderId() + ")"); + templateMerchant.setTemplateID(NEW_MERCHANT_EN); + if (language.equals("ENGLISH")){ + user.setSubject("[Code-Create] You have successfully subscribed to AiDA"); + templateUser.setTemplateID(NEW_USER_EN); + }else { + user.setSubject("[Code-Create] 您已成功订阅AiDA"); + templateUser.setTemplateID(NEW_USER_CN); + } + break; + case "renewal": + merchant.setSubject("[Code-Create] New subscription renewal order (" + subscriptionEmailParamsDTO.getOrderId() + ")"); + templateMerchant.setTemplateID(RENEWAL_MERCHANT_EN); + if (language.equals("ENGLISH")){ + user.setSubject("[Code-Create] AiDA Renewal Successful"); + templateUser.setTemplateID(RENEWAL_USER_EN); + }else { + user.setSubject("[Code-Create] AiDA续订成功"); + templateUser.setTemplateID(RENEWAL_USER_CN); + } + break; + case "reminder": + if (language.equals("ENGLISH")){ + user.setSubject("[Code-Create] AiDA Subscription Renewal Reminder"); + templateUser.setTemplateID(RENEWAL_REMINDER_USER_EN); + }else { + user.setSubject("[Code-Create] AiDA续订提醒"); + templateUser.setTemplateID(RENEWAL_REMINDER_USER_CN); + } + break; + default: + log.error("unknown subscription email type"); +// throw new BusinessException("unknown subscription email type"); + } + + templateUser.setTemplateData(JSON.toJSONString(subscriptionEmailParamsDTO)); + user.setTemplate(templateUser); + + templateMerchant.setTemplateData(JSON.toJSONString(subscriptionEmailParamsDTO)); + merchant.setTemplate(templateMerchant); + + // 返回的resp是一个SendEmailResponse的实例,与请求对象对应 + SendEmailResponse respUser = client.SendEmail(user); + // todo 暂时先不发商家邮件 +// SendEmailResponse respMerchant = client.SendEmail(merchant); + log.info("邮件发送结果toUser###{}", SendEmailResponse.toJsonString(respUser)); +// log.info("邮件发送结果toMerchant###{}", SendEmailResponse.toJsonString(respMerchant)); + } catch (TencentCloudSDKException e) { + log.info("邮件发送失败###{}", e.toString()); + throw new BusinessException("failed.to.send.mail"); + } + } } diff --git a/src/main/java/com/ai/da/controller/StripeController.java b/src/main/java/com/ai/da/controller/StripeController.java index 70430fab..eac49851 100644 --- a/src/main/java/com/ai/da/controller/StripeController.java +++ b/src/main/java/com/ai/da/controller/StripeController.java @@ -1,17 +1,21 @@ package com.ai.da.controller; import com.ai.da.common.response.Response; +import com.ai.da.model.dto.ProductPurchaseDTO; import com.ai.da.service.StripeService; import com.paypal.http.HttpResponse; import com.paypal.payments.Refund; +import com.stripe.exception.StripeException; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import lombok.extern.slf4j.Slf4j; +import org.simpleframework.xml.core.Validate; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; import java.io.IOException; @Api(tags = "Stripe模块") @@ -24,19 +28,19 @@ public class StripeController { private StripeService stripeService; @ApiOperation("创建支付链接") - @PostMapping("/createOrder/{amount}") - public Response pay(@PathVariable Integer amount, @RequestParam String returnUrl) { - return Response.success(stripeService.pay(amount, returnUrl)); + @PostMapping("/createOrder") + public Response pay(@Validate @RequestBody ProductPurchaseDTO productPurchaseDTO) { + return Response.success(stripeService.pay(productPurchaseDTO)); } @ApiOperation("支付通知") @PostMapping("/trade/notify") - public Response callback(HttpServletRequest request) throws ServletException, IOException { + public void callback(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { Boolean result = stripeService.notify(request); if (result){ - return Response.success(200,"success"); + response.setStatus(HttpServletResponse.SC_OK); }else { - return Response.fail(400,"failure"); + response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); } } @@ -51,4 +55,20 @@ public class StripeController { } } + @ApiOperation("获取订阅") + @PostMapping("/getSubscription") + public void getSubscription() { + try { + stripeService.getSubscription("xp", "xupei3360@163.com"); + } catch (StripeException e) { + throw new RuntimeException(e); + } + } + + @ApiOperation("取消订阅") + @PostMapping("/cancelSubscription") + public Response cancelSubscription(@RequestParam String subscriptionId) { + stripeService.cancelSubscription(subscriptionId); + return Response.success("success"); + } } diff --git a/src/main/java/com/ai/da/mapper/primary/SubscriptionInfoMapper.java b/src/main/java/com/ai/da/mapper/primary/SubscriptionInfoMapper.java new file mode 100644 index 00000000..8a45bb7e --- /dev/null +++ b/src/main/java/com/ai/da/mapper/primary/SubscriptionInfoMapper.java @@ -0,0 +1,8 @@ +package com.ai.da.mapper.primary; + +import com.ai.da.mapper.primary.entity.SubscriptionInfo; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +public interface SubscriptionInfoMapper extends BaseMapper { + +} diff --git a/src/main/java/com/ai/da/mapper/primary/entity/PaymentInfo.java b/src/main/java/com/ai/da/mapper/primary/entity/PaymentInfo.java index c3876106..3806d888 100644 --- a/src/main/java/com/ai/da/mapper/primary/entity/PaymentInfo.java +++ b/src/main/java/com/ai/da/mapper/primary/entity/PaymentInfo.java @@ -2,7 +2,9 @@ package com.ai.da.mapper.primary.entity; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; +import lombok.EqualsAndHashCode; +@EqualsAndHashCode(callSuper = true) @Data @TableName("t_payment_info") public class PaymentInfo extends BaseEntity{ @@ -13,11 +15,15 @@ public class PaymentInfo extends BaseEntity{ private String paymentType;//支付类型 - private String tradeType;//交易类型 - private String tradeState;//交易状态 private Float payerTotal;//支付金额(元) private String content;//通知参数 + + // 支付类型 new || renewal + private String type; + + // 当前支付是否已邮件通知 0 || 1 + private Integer notified; } diff --git a/src/main/java/com/ai/da/mapper/primary/entity/SubscriptionInfo.java b/src/main/java/com/ai/da/mapper/primary/entity/SubscriptionInfo.java new file mode 100644 index 00000000..2b61cf48 --- /dev/null +++ b/src/main/java/com/ai/da/mapper/primary/entity/SubscriptionInfo.java @@ -0,0 +1,43 @@ +package com.ai.da.mapper.primary.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@EqualsAndHashCode(callSuper = true) +@Data +@TableName("t_subscription_info") +public class SubscriptionInfo extends BaseEntity{ + + private Long accountId; + + private String orderNo; + + // stripe || paypal 平台生成的id + private String subscriptionId; + + // month || year + private String type; + + // active || expired + private String status = "active"; + + // 是否自动续订 + private byte autoRenewal = (byte)1; + + // 支付方式 + private String paymentMethod; + + // 如果是用卡支付,可以看到银行卡最后四位 + private String last4; + + // 续订的下一个付款日 + private String nextPayDate; + + // 当前订阅订单有效期开始时间 + private Long currentPeriodStart; + + // 当前订阅订单有效期结束时间 + private Long currentPeriodEnd; + +} diff --git a/src/main/java/com/ai/da/model/dto/ProductPurchaseDTO.java b/src/main/java/com/ai/da/model/dto/ProductPurchaseDTO.java new file mode 100644 index 00000000..ce1fb595 --- /dev/null +++ b/src/main/java/com/ai/da/model/dto/ProductPurchaseDTO.java @@ -0,0 +1,32 @@ +package com.ai.da.model.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotBlank; + +@Data +@ApiModel("购买产品DTO") +public class ProductPurchaseDTO { + + @ApiModelProperty("购买数量") + private int quantity; + + // http://example.com + @NotBlank(message = "return url cannot be empty") + @ApiModelProperty("购买完成后返回页面地址") + private String returnUrl; + + @NotBlank(message = "product name cannot be empty") + @ApiModelProperty("产品名 CreditsPurchase || Subscription") + private String productName; + + @ApiModelProperty("Month || Year") + private String subscribeType; + + @ApiModelProperty("是否自动续订 one_time || recurring") + private Boolean autoRenewal; + + private String refId; +} diff --git a/src/main/java/com/ai/da/model/dto/SubscriptionEmailParamsDTO.java b/src/main/java/com/ai/da/model/dto/SubscriptionEmailParamsDTO.java new file mode 100644 index 00000000..0020582f --- /dev/null +++ b/src/main/java/com/ai/da/model/dto/SubscriptionEmailParamsDTO.java @@ -0,0 +1,47 @@ +package com.ai.da.model.dto; + +import lombok.Data; + +@Data +public class SubscriptionEmailParamsDTO { + // 用户名 + private String username; + + // t_payment_info id(每次支付对于用户来说是一笔新订单) + private String orderId; + + // 订单支付创建日期 + private String createDate; + + // 购买数量 + private String quantity; + + // 费用 + private String totalFee; + + // 当前订阅开始时间 + private String lastOrderDate; + + // 当前订阅结束时间 + private String endOfPrepaidTerm; + + // 付款方式 + private String paymentMethod; + + // 订阅Id + private String subscriptionId; + + // 订阅方式 + private String subscriptionType; + + // 订阅开始时间 + private String startDate; + + // 下一个支付日期 + private String nextPayDate; + + // 下次付款时间(reminder) + private String renewalTime; + + +} diff --git a/src/main/java/com/ai/da/service/OrderInfoService.java b/src/main/java/com/ai/da/service/OrderInfoService.java index 35da4881..a420fe70 100644 --- a/src/main/java/com/ai/da/service/OrderInfoService.java +++ b/src/main/java/com/ai/da/service/OrderInfoService.java @@ -2,6 +2,7 @@ package com.ai.da.service; import com.ai.da.common.enums.OrderStatusEnum; +import com.ai.da.common.enums.ProductEnum; import com.ai.da.common.response.PageBaseResponse; import com.ai.da.mapper.primary.entity.OrderInfo; import com.ai.da.model.dto.QueryPageByTimeDTO; @@ -13,6 +14,8 @@ public interface OrderInfoService extends IService { OrderInfo createOrderByProductId(Integer productId, String paymentType); + OrderInfo createOrderByProductId(Integer amount, String paymentType, ProductEnum product); + void saveCodeUrl(String orderNo, String codeUrl); List listOrderByCreateTimeDesc(); @@ -28,4 +31,7 @@ public interface OrderInfoService extends IService { PageBaseResponse getOrderByPage(QueryPageByTimeDTO queryPageByTimeDTO); void updateOrderNoById(Long id, String orderNo); + + void updateTotalFeeByOrderNo(String orderNo); + } diff --git a/src/main/java/com/ai/da/service/PaymentInfoService.java b/src/main/java/com/ai/da/service/PaymentInfoService.java index 74492683..6d3d2d5e 100644 --- a/src/main/java/com/ai/da/service/PaymentInfoService.java +++ b/src/main/java/com/ai/da/service/PaymentInfoService.java @@ -2,12 +2,13 @@ package com.ai.da.service; import com.ai.da.mapper.primary.entity.PaymentInfo; import com.ai.da.model.dto.AlipayHKCallbackDTO; +import com.baomidou.mybatisplus.extension.service.IService; import com.paypal.orders.Order; -import com.stripe.model.checkout.Session; +import com.stripe.model.Invoice; import java.util.Map; -public interface PaymentInfoService { +public interface PaymentInfoService extends IService { void createPaymentInfo(String plainText); @@ -17,7 +18,7 @@ public interface PaymentInfoService { void createPaymentInfoForAliPayHK(AlipayHKCallbackDTO alipayHKCallbackDTO); - void createPaymentInfoForStripe(Session session); + String createPaymentInfoForStripe(Invoice invoice); PaymentInfo getPaymentInfoByOrderId(String orderId); diff --git a/src/main/java/com/ai/da/service/StripeService.java b/src/main/java/com/ai/da/service/StripeService.java index 98709597..b517b325 100644 --- a/src/main/java/com/ai/da/service/StripeService.java +++ b/src/main/java/com/ai/da/service/StripeService.java @@ -1,15 +1,35 @@ package com.ai.da.service; +import com.ai.da.model.dto.ProductPurchaseDTO; +import com.stripe.exception.StripeException; +import com.stripe.model.Subscription; + import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import java.util.List; +import java.util.Map; public interface StripeService { - String pay(Integer quantity, String returnUrl); + String pay(ProductPurchaseDTO productPurchaseDTO); Boolean notify(HttpServletRequest request); String refund(String amount, String orderId, String reason); void checkOrderStatus(String orderNo); + + List getSubscription(String name, String userEmail) throws StripeException; + + void cancelSubscription(String orderNo); + + Map getPaymentMethod(String paymentMethodId); + + /*void updateSubscription(String subscriptionId); + + void resume(String subscriptionId);*/ + + void subscriptionReminder(); + + void checkSubscriptionExpiration(); + } diff --git a/src/main/java/com/ai/da/service/impl/OrderInfoServiceImpl.java b/src/main/java/com/ai/da/service/impl/OrderInfoServiceImpl.java index 416d84d2..ae12e612 100644 --- a/src/main/java/com/ai/da/service/impl/OrderInfoServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/OrderInfoServiceImpl.java @@ -4,15 +4,19 @@ package com.ai.da.service.impl; import com.ai.da.common.context.UserContext; import com.ai.da.common.enums.CreditsEventsEnum; import com.ai.da.common.enums.OrderStatusEnum; +import com.ai.da.common.enums.ProductEnum; import com.ai.da.common.response.PageBaseResponse; import com.ai.da.common.utils.OrderNoUtils; import com.ai.da.mapper.primary.OrderInfoMapper; +import com.ai.da.mapper.primary.PaymentInfoMapper; import com.ai.da.mapper.primary.ProductMapper; import com.ai.da.mapper.primary.entity.OrderInfo; +import com.ai.da.mapper.primary.entity.PaymentInfo; import com.ai.da.model.dto.QueryPageByTimeDTO; import com.ai.da.model.vo.AuthPrincipalVo; import com.ai.da.service.OrderInfoService; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import io.netty.util.internal.StringUtil; @@ -34,9 +38,13 @@ public class OrderInfoServiceImpl extends ServiceImpl queryWrapper = new QueryWrapper<>(); queryWrapper.eq("order_no", orderNo); OrderInfo orderInfo = baseMapper.selectOne(queryWrapper); - if(orderInfo == null){ + if (orderInfo == null) { return null; } return orderInfo.getOrderStatus(); @@ -129,6 +169,7 @@ public class OrderInfoServiceImpl extends ServiceImpl getOrderByPage(QueryPageByTimeDTO queryPageByTimeDTO){ + public PageBaseResponse getOrderByPage(QueryPageByTimeDTO queryPageByTimeDTO) { QueryWrapper qw = new QueryWrapper<>(); - qw.eq("account_id",UserContext.getUserHolder().getId()); + qw.eq("account_id", UserContext.getUserHolder().getId()); String startTime = queryPageByTimeDTO.getStartTime(); String endTime = queryPageByTimeDTO.getEndTime(); - if (StringUtil.isNullOrEmpty(startTime)){ + if (StringUtil.isNullOrEmpty(startTime)) { startTime = "2024-02-01 00:00:00"; } - if (StringUtil.isNullOrEmpty(endTime)){ + if (StringUtil.isNullOrEmpty(endTime)) { LocalDateTime now = LocalDateTime.now(); DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); endTime = now.format(dateTimeFormatter); @@ -206,11 +249,28 @@ public class OrderInfoServiceImpl extends ServiceImpl qw = new QueryWrapper<>(); + qw.eq("order_no", orderNo); + List paymentInfos = paymentInfoMapper.selectList(qw); + Float sum = paymentInfos.stream() + .map(PaymentInfo::getPayerTotal) + .reduce(0f, Float::sum); + + baseMapper.update( + new OrderInfo(), + new UpdateWrapper() + .eq("order_no", orderNo) + .set("total_fee", sum) + ); + } + } diff --git a/src/main/java/com/ai/da/service/impl/PaymentInfoServiceImpl.java b/src/main/java/com/ai/da/service/impl/PaymentInfoServiceImpl.java index 2a80a4f5..035e1135 100644 --- a/src/main/java/com/ai/da/service/impl/PaymentInfoServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/PaymentInfoServiceImpl.java @@ -9,14 +9,20 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.google.gson.Gson; import com.paypal.orders.Order; +import com.stripe.Stripe; +import com.stripe.exception.StripeException; +import com.stripe.model.Invoice; +import com.stripe.model.Subscription; import com.stripe.model.checkout.Session; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import java.math.BigDecimal; import java.math.RoundingMode; import java.util.HashMap; import java.util.Map; +import java.util.Objects; @Service @Slf4j @@ -50,7 +56,6 @@ public class PaymentInfoServiceImpl extends ServiceImpl qw = new QueryWrapper<>(); + qw.eq("transaction_id", invoiceId); + PaymentInfo paymentInfo = baseMapper.selectOne(qw); + // 判断当前支付是否已经被记录,确保同一个支付不会被重复记录 + if (Objects.isNull(paymentInfo)){ + String orderNo; + String subscriptionId = invoice.getSubscription(); + try { + // 从subscription中获取orderNo + orderNo = Subscription.retrieve(subscriptionId).getDescription().replace("AiDA - ", ""); + } catch (StripeException e) { + throw new RuntimeException(e); + } + String status = invoice.getStatus(); + Long amountTotal = invoice.getAmountPaid(); + // stripe 的支付金额单位是分,在我们数据库中金额单位为 元 + Float divide = new BigDecimal(amountTotal).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP).floatValue(); + String type = invoice.getBillingReason().equals("subscription_create") ? "new" : + invoice.getBillingReason().equals("subscription_cycle") ? "renewal" : invoice.getBillingReason(); + + + paymentInfo = new PaymentInfo(); + paymentInfo.setOrderNo(orderNo); + paymentInfo.setPaymentType(PayTypeEnum.STRIPE.getType()); + paymentInfo.setTransactionId(invoiceId); + // 使用invoice的状态 + paymentInfo.setTradeState(status); + paymentInfo.setPayerTotal(divide); + Gson gson = new Gson(); + String json = gson.toJson(invoice); + paymentInfo.setContent(json); + paymentInfo.setType(type); + paymentInfo.setNotified(0); + + baseMapper.insert(paymentInfo); + return orderNo; + } + return null; + } + + @Override public PaymentInfo getPaymentInfoByOrderId(String orderId){ QueryWrapper qw = new QueryWrapper<>(); diff --git a/src/main/java/com/ai/da/service/impl/StripeServiceImpl.java b/src/main/java/com/ai/da/service/impl/StripeServiceImpl.java index 7951adcd..b5e3a68e 100644 --- a/src/main/java/com/ai/da/service/impl/StripeServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/StripeServiceImpl.java @@ -1,16 +1,22 @@ package com.ai.da.service.impl; +import com.ai.da.common.config.exception.BusinessException; +import com.ai.da.common.constant.CommonConstant; import com.ai.da.common.context.UserContext; -import com.ai.da.common.enums.AliPayTradeStateEnum; -import com.ai.da.common.enums.CreditsEventsEnum; -import com.ai.da.common.enums.OrderStatusEnum; -import com.ai.da.common.enums.PayTypeEnum; -import com.ai.da.common.utils.OrderNoUtils; +import com.ai.da.common.enums.*; +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.SubscriptionInfoMapper; import com.ai.da.mapper.primary.entity.OrderInfo; import com.ai.da.mapper.primary.entity.PaymentInfo; import com.ai.da.mapper.primary.entity.RefundInfo; +import com.ai.da.mapper.primary.entity.SubscriptionInfo; +import com.ai.da.model.dto.ProductPurchaseDTO; +import com.ai.da.model.dto.SubscriptionEmailParamsDTO; import com.ai.da.service.*; +import com.alibaba.fastjson.JSON; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.toolkit.StringUtils; import com.google.gson.Gson; import com.stripe.Stripe; @@ -21,6 +27,7 @@ import com.stripe.model.checkout.Session; import com.stripe.net.Webhook; import com.stripe.param.*; import com.stripe.param.checkout.SessionCreateParams; +import io.netty.util.internal.StringUtil; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; @@ -30,10 +37,13 @@ import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import java.math.BigDecimal; import java.math.RoundingMode; -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; +import java.text.SimpleDateFormat; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneOffset; +import java.util.*; +@SuppressWarnings("LoggingSimilarMessage") @Service @Slf4j public class StripeServiceImpl implements StripeService { @@ -51,6 +61,10 @@ public class StripeServiceImpl implements StripeService { @Resource private AccountMapper accountMapper; + @Resource + private SubscriptionInfoMapper subscriptionInfoMapper; + @Resource + private PaymentInfoMapper paymentInfoMapper; @Value("${stripe.private-key}") private String privateKey; @@ -60,53 +74,78 @@ public class StripeServiceImpl implements StripeService { @Override @Transactional(rollbackFor = Exception.class) - public String pay(Integer quantity, String returnUrl) { + public String pay(ProductPurchaseDTO productPurchaseDTO) { Stripe.apiKey = privateKey; - log.info("生成订单"); - OrderInfo orderInfo = orderInfoService.createOrderByProductId(quantity, PayTypeEnum.STRIPE.getType()); - Long id = UserContext.getUserHolder().getId(); - com.ai.da.mapper.primary.entity.Account account = accountMapper.selectById(id); + ProductEnum productEnum; + switch (productPurchaseDTO.getProductName()){ + case "Credits Purchase": + productEnum = ProductEnum.CreditsProduct; + break; + case "Subscription": + switch (productPurchaseDTO.getSubscribeType()){ + case "Month": + productEnum = ProductEnum.MonthlySubscription; + break; + case "Year": + productEnum = ProductEnum.AnnualSubscription; + break; + case "Day": + productEnum = ProductEnum.DailySubscription; + break; + default: + throw new BusinessException("unknown subscription type"); + } + break; + default: + throw new BusinessException("unknown product type"); + } + log.info("生成订单"); + OrderInfo orderInfo = orderInfoService.createOrderByProductId(productPurchaseDTO.getQuantity(), PayTypeEnum.STRIPE.getType(), productEnum); + String payType; + if (productPurchaseDTO.getAutoRenewal()){ + payType = "recurring"; + }else { + payType = "one_time"; + } try { - //创建产品 - Map params = new HashMap<>(); - params.put("name", "AiDA credits purchase"); - Product product = Product.create(params); - String orderId = OrderNoUtils.getOrderNo(); - - BigDecimal actualAmount = new BigDecimal(Long.parseLong(CreditsEventsEnum.PRICE.getValue()) * 100); //stripe的默认单位是分,即传入的amount实际上小数点会被左移两位 - //给price绑定元数据并更新price用于检索 - Map metadata = new HashMap<>(); - metadata.put("orderId", orderId); - //创建价格 - Map priceParams = new HashMap<>(); - priceParams.put("metadata", metadata); //通过订单号关联用于检索price信息(可选) - priceParams.put("unit_amount", actualAmount.intValue()); - priceParams.put("currency", "HKD"); - priceParams.put("product", product.getId()); - Price price = Price.create(priceParams); + Long id = UserContext.getUserHolder().getId(); + com.ai.da.mapper.primary.entity.Account account = accountMapper.selectById(id); + // 获取或创建产品 + String productId = getProduct(productEnum.getName()); + // 获取或创建价格 + String priceId = getPrice(productEnum.getPrice(), productId, payType, productPurchaseDTO.getSubscribeType()); + // 获取或创建customer + String customerId = getCustomer(account.getUserName(), account.getUserEmail()); + // 获取自定义订单号 + String orderId = orderInfo.getOrderNo(); //创建支付信息得到url - SessionCreateParams params3 = SessionCreateParams.builder() - .setMode(SessionCreateParams.Mode.PAYMENT) - .setSuccessUrl(returnUrl)//可自定义成功页面 - .setPaymentIntentData(SessionCreateParams.PaymentIntentData.builder().setDescription("AiDA - " + orderId).build()) - .setLocale(account.getLanguage().equals("CHINESE_SIMPLIFIED") ? SessionCreateParams.Locale.ZH : SessionCreateParams.Locale.EN) - .addLineItem( - SessionCreateParams.LineItem.builder() - .setQuantity(Long.valueOf(quantity)) - .setPrice(price.getId()) - .build()) - .putMetadata("orderId", orderId) //通过订单号关联用于检索支付信息(可选) - .build(); - Session session = Session.create(params3); + // 一次性支付和周期扣款,需要区分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()); + }else { + sessionBuilder.setMode(SessionCreateParams.Mode.PAYMENT); + sessionBuilder.setPaymentIntentData(SessionCreateParams.PaymentIntentData.builder().setDescription("AiDA - " + orderId).build()); + } + sessionBuilder.setCustomer(customerId); + sessionBuilder.setSuccessUrl(productPurchaseDTO.getReturnUrl());//可自定义成功页面 + sessionBuilder.setLocale(account.getLanguage().equals("CHINESE_SIMPLIFIED") ? SessionCreateParams.Locale.ZH : SessionCreateParams.Locale.EN); + sessionBuilder.addLineItem( + SessionCreateParams.LineItem.builder() + .setQuantity((long) productPurchaseDTO.getQuantity()) + .setPrice(priceId) + .build()); + sessionBuilder.putMetadata("orderId", orderId); //通过订单号关联用于检索支付信息(可选) + + Session session = Session.create(sessionBuilder.build()); log.info("sessionId:" + session.getId()); //退款方式1:拿到sessionId入库,退款的时候根据这个id找到PaymentIntent的id然后发起退款 // 更新order信息 orderInfoService.updateOrderNoById(orderInfo.getId(), orderId); - //记录支付日志 - paymentInfoService.createPaymentInfoForStripe(session); return session.getUrl(); } catch (Exception e) { log.error("创建支付会话出现异常:", e); @@ -114,6 +153,69 @@ public class StripeServiceImpl implements StripeService { return ""; } + // 获取产品ID + private String getProduct(String productName) throws StripeException { + Stripe.apiKey = privateKey; + // 1、获取所有的产品 + ProductCollection productCollection = Product.list(ProductListParams.builder().setActive(Boolean.TRUE).build()); + // 2、取一个指定名称的产品 + for (Product product : productCollection.getData()) { + if (product.getName().equals(productName)) { + return product.getId(); + } + } + // 3、在现有产品中没有找到指定产品,新建产品 + Map params = new HashMap<>(); + params.put("name", productName); + Product product = Product.create(params); + return product.getId(); + } + + /** + * 获取价格 + * + * @param priceValue 价格值 + * @param payType recurring || one_time + * @param recurringType monthly || yearly + */ + private String getPrice(Long priceValue, String productId, String payType, String recurringType) throws StripeException { + Stripe.apiKey = privateKey; + PriceCollection priceCollection = Price.list(PriceListParams.builder() + .setActive(Boolean.TRUE) + .setProduct(productId).build()); + for (Price price : priceCollection.getData()) { + // stripe的金额单位为分,所以这里需要 ×100 + if (price.getUnitAmount().equals(priceValue * 100) && price.getType().equals(payType)) { + return price.getId(); + } + } + + Price price = createPrice(priceValue, productId, payType, recurringType); + return price.getId(); + } + + private Price createPrice(Long priceValue, String productId, String payType, String recurringType) throws StripeException { + BigDecimal actualAmount = new BigDecimal(priceValue * 100); //stripe的默认单位是分,即传入的amount实际上小数点会被左移两位 + + PriceCreateParams.Builder priceCreateParams = new PriceCreateParams.Builder(); + priceCreateParams.setBillingScheme(PriceCreateParams.BillingScheme.PER_UNIT); + priceCreateParams.setCurrency("HKD"); + priceCreateParams.setProduct(productId); + priceCreateParams.setUnitAmount(actualAmount.longValue()); + + if (payType.equals("recurring")) { + PriceCreateParams.Recurring.Builder recurring = new PriceCreateParams.Recurring.Builder(); + // One of day, week, month or year. + recurring.setInterval(PriceCreateParams.Recurring.Interval.valueOf(recurringType.toUpperCase())); + // The number of intervals (specified in the interval attribute) between subscription billings. + // For example, interval=month and interval_count=3 bills every 3 months. + recurring.setIntervalCount(1L); + priceCreateParams.setRecurring(recurring.build()); + } + + return Price.create(priceCreateParams.build()); + } + @Override @Transactional(rollbackFor = Exception.class) public Boolean notify(HttpServletRequest request) { @@ -127,19 +229,19 @@ public class StripeServiceImpl implements StripeService { } catch (Exception e) { log.info("stripe 支付回调参数解析异常:errorMsg {}", e.getMessage()); log.info("request sigHeader = {}", sigHeader); - log.info("request body = {}", payload); + log.info("request body = {}", JSON.toJSONString(payload)); e.printStackTrace(); return Boolean.FALSE; } - Event event = null; + Event event; try { assert sigHeader != null; event = Webhook.constructEvent(payload, sigHeader, endpointSecret); } catch (SignatureVerificationException e) { - log.info("stripe 验签,获取事件异常, errorMsg=" + e.getMessage()); + log.info("stripe 验签,获取事件异常, errorMsg={}", e.getMessage()); log.info("request sigHeader = {}", sigHeader); - log.info("request body = {}", payload); + log.info("request body = {}", JSON.toJSONString(payload)); e.printStackTrace(); return Boolean.FALSE; } @@ -148,23 +250,65 @@ public class StripeServiceImpl implements StripeService { // Deserialize the nested object inside the event assert event != null; EventDataObjectDeserializer dataObjectDeserializer = event.getDataObjectDeserializer(); - StripeObject stripeObject = null; + StripeObject stripeObject ; if (dataObjectDeserializer.getObject().isPresent()) { stripeObject = dataObjectDeserializer.getObject().get(); } else { log.info("stripe 验签失败!"); log.info("request sigHeader = {}", sigHeader); - log.info("request body = {}", payload); + log.info("request body = {}", JSON.toJSONString(payload)); return Boolean.FALSE; } log.info("stripe验签成功"); + Boolean response = Boolean.TRUE; - if (event.getType().equals("checkout.session.completed")) { + log.info("回调事件 {}", event.getType()); + if (stripeObject instanceof Session){ Session session = (Session) stripeObject; - processOrder(session); - } + if (event.getType().equals("checkout.session.completed")) { + processOrder(session); + } + } else if (stripeObject instanceof Subscription){ + Subscription subscription = (Subscription) stripeObject; + if (event.getType().equals("customer.subscription.created")){ + // 添加数据到t_subscription_info表 需记录订阅id。需要判断订阅的状态是否active吗 ?? + createSubscription(subscription); + log.info("创建连续订阅"); + } else if (event.getType().equals("customer.subscription.updated")){ + // 更新订阅信息 + response = updateSubscription(subscription); + log.info("订阅更新"); + if (subscription.getStatus().equals("active")){ + response = sendEmail(subscription.getId(), null); + } + } else if (event.getType().equals("customer.subscription.deleted")){ + response = updateSubscription(subscription); + log.info("用户取消连续订阅"); + } else if (event.getType().equals("customer.subscription.paused")){ + updateSubscription(subscription); + } else if (event.getType().equals("customer.subscription.resumed")){ + updateSubscription(subscription); + log.info("用户订阅恢复"); + } + } else if (stripeObject instanceof Invoice) { + Invoice invoice = (Invoice) stripeObject; + if (event.getType().equals("invoice.paid")) { + // 新增支付成功的信息,返回orderNo,表示,该回调第一次被记录 + String orderNo = paymentInfoService.createPaymentInfoForStripe(invoice); - return Boolean.TRUE; + if (!StringUtil.isNullOrEmpty(orderNo)) { + // 更新t_order_info中的total_fee,记录该订单的累计付款金额 + orderInfoService.updateTotalFeeByOrderNo(orderNo); + // 邮件通知商家和用户 + if (invoice.getBillingReason().equals("subscription_create")){ + response = sendEmail(invoice.getSubscription(), "new"); + } else if (invoice.getBillingReason().equals("subscription_cycle")){ + response = sendEmail(invoice.getSubscription(), "renewal"); + } + } + } + } + return response; } public void processOrder(Session session) { @@ -186,31 +330,135 @@ public class StripeServiceImpl implements StripeService { orderInfoService.updateStatusByOrderNo(orderId, OrderStatusEnum.SUCCESS); log.info("Stripe 订单:{} 状态更新成功", orderId); - // 更新支付日志 - paymentInfoService.updatePaymentStatusById( - paymentInfoService.getPaymentInfoByOrderId(orderId).getId(), - session.getStatus(), - new Gson().toJson(session)); - - log.info("Stripe 订单:{} 支付信息状态更新成功", orderId); - float quantity = totalAmount / Float.parseFloat(CreditsEventsEnum.PRICE.getValue()); - // 更新积分 - creditsService.buyCredits(orderByOrderNo.getAccountId(), quantity); - // 添加积分变更记录 - creditsService.insertToCreditsDetail(orderByOrderNo.getAccountId(), - CreditsEventsEnum.BUY_CREDITS.getName() + "--Stripe", - String.valueOf((Long.parseLong(CreditsEventsEnum.BUY_CREDITS.getValue()) * quantity)), - "positive"); - log.info("用户:{} 积分信息更新成功", orderByOrderNo.getAccountId()); - }catch (Exception e){ + if (orderByOrderNo.getTitle().startsWith("积分购买")){ + float quantity = totalAmount / ProductEnum.CreditsProduct.getPrice(); + // 更新积分 + creditsService.buyCredits(orderByOrderNo.getAccountId(), quantity); + // 添加积分变更记录 + creditsService.insertToCreditsDetail(orderByOrderNo.getAccountId(), + CreditsEventsEnum.BUY_CREDITS.getName() + "--Stripe", + String.valueOf((Long.parseLong(CreditsEventsEnum.BUY_CREDITS.getValue()) * quantity)), + "positive"); + log.info("用户:{} 积分信息更新成功", orderByOrderNo.getAccountId()); + } + } catch (Exception e) { log.info(e.getMessage()); } } + @Transactional(rollbackFor = Exception.class) + public SubscriptionInfo createSubscription(Subscription subscription){ + // 确认当前subscription是否已经记录 + QueryWrapper qw = new QueryWrapper<>(); + qw.eq("subscription_id", subscription.getId()); + SubscriptionInfo subscriptionInfo = subscriptionInfoMapper.selectOne(qw); + if (Objects.isNull(subscriptionInfo)){ + String description = subscription.getDescription(); + String orderNo = description.replace("AiDA - ", ""); + OrderInfo orderInfo = orderInfoService.getOrderByOrderNo(orderNo); + + // 从回调信息中获取recurring type + SubscriptionItem subscriptionItem = subscription.getItems().getData().get(0); + String interval = subscriptionItem.getPrice().getRecurring().getInterval(); + Map paymentMethod = getPaymentMethodByInvoiceId(subscription.getLatestInvoice()); + + subscriptionInfo = new SubscriptionInfo(); + subscriptionInfo.setAccountId(orderInfo.getAccountId()); + subscriptionInfo.setOrderNo(orderNo); + subscriptionInfo.setSubscriptionId(subscription.getId()); + subscriptionInfo.setType(interval); + subscriptionInfo.setStatus(subscription.getStatus()); + subscriptionInfo.setPaymentMethod(paymentMethod.get("paymentMethod")); + subscriptionInfo.setLast4(paymentMethod.get("last4")); + subscriptionInfo.setNextPayDate(changeTimeStampFormat(subscription.getCurrentPeriodEnd(), "seconds", CommonConstant.TIME_FORMAT_MMM_dd_yyyy_EEEE)); + subscriptionInfo.setCurrentPeriodStart(subscription.getCurrentPeriodStart()); + subscriptionInfo.setCurrentPeriodEnd(subscription.getCurrentPeriodEnd()); + subscriptionInfo.setCreateTime(LocalDateTime.now()); + subscriptionInfoMapper.insert(subscriptionInfo); + + // 更新账号到期时间 + updateAccountValidity(subscriptionInfo.getAccountId(), subscriptionInfo.getCurrentPeriodEnd()); + } + return subscriptionInfo; + } + + public String changeTimeStampFormat(Long timeStamp, String type, String format){ + // 将秒级时间戳转换为毫秒级 + if (type.equals("seconds")){ + timeStamp = timeStamp * 1000; + } + // 输出格式 + SimpleDateFormat outputFormat = new SimpleDateFormat(format, Locale.ENGLISH); + // 创建Date对象 + Date date = new Date(timeStamp); + // 格式化输出 + return outputFormat.format(date); + } + + @Transactional(rollbackFor = Exception.class) + public Boolean updateSubscription(Subscription subscription){ + // 获取当前是否有已经记录的subscriptionInfo + SubscriptionInfo subscriptionInfo = createSubscription(subscription); + // 用于标志数据有没有变动,避免在没有改动的情况下频繁的更新数据库 + boolean flag = false; + if (!subscriptionInfo.getStatus().equals(subscription.getStatus())){ + subscriptionInfo.setStatus(subscription.getStatus()); + flag = true; + } + if (subscription.getStatus().equals("canceled")){ + subscriptionInfo.setAutoRenewal((byte) 0); + } + if (!subscriptionInfo.getCurrentPeriodStart().equals(subscription.getCurrentPeriodStart())){ + subscriptionInfo.setCurrentPeriodStart(subscription.getCurrentPeriodStart()); + flag = true; + } + if (!subscriptionInfo.getCurrentPeriodEnd().equals(subscription.getCurrentPeriodEnd())){ + subscriptionInfo.setCurrentPeriodEnd(subscription.getCurrentPeriodEnd()); + subscriptionInfo.setNextPayDate(changeTimeStampFormat(subscription.getCurrentPeriodEnd(), "seconds", CommonConstant.TIME_FORMAT_MMM_dd_yyyy_EEEE)); + // 更新账号到期时间 + updateAccountValidity(subscriptionInfo.getAccountId(), subscriptionInfo.getCurrentPeriodEnd()); + log.info("更新 {} 账号到期时间为:{}", subscriptionInfo.getAccountId(), changeTimeStampFormat(subscriptionInfo.getCurrentPeriodEnd(), "seconds", CommonConstant.TIME_FORMAT_MMM_dd_yyyy_EEEE)); + flag = true; + } + if (flag){ + subscriptionInfo.setUpdateTime(LocalDateTime.now()); + // todo 这里需要再检查支付方式吗? + subscriptionInfoMapper.updateById(subscriptionInfo); + } + return true; + } + + private void updateAccountValidity(Long accountId, Long currentPeriodEnd){ + // 不管当前用户的账号是否到期,都根据付款信息重置账号到期时间 + com.ai.da.mapper.primary.entity.Account account = accountMapper.selectById(accountId); + account.setValidEndTime(currentPeriodEnd * 1000); + + accountMapper.updateById(account); + } + + // 取消连续订阅 将订阅从pause状态转为cancel状态(使用定时器,定期检索DB中,过期且不续订的订阅) + public void cancelSubscription(String subscriptionId) { + Stripe.apiKey = privateKey; + Long accountId = UserContext.getUserHolder().getId(); + log.info("用户 {} 申请取消连续订阅 {}", accountId, subscriptionId); + com.ai.da.mapper.primary.entity.Account account = accountMapper.selectById(accountId); + List subscriptions = getSubscription(account.getUserName(), account.getUserEmail()); + // 获取status = active的订阅 + subscriptions.forEach(subscription -> { + if (subscription.getId().equals(subscriptionId)) { + try { + Subscription cancel = subscription.cancel(); + cancel.getStatus(); + } catch (StripeException e) { + log.error("订阅 {} 取消失败, error message : {}", subscription.getId(), e.getMessage()); + } + } + }); + } public String refund(String amount, String orderId, String reason) { - Refund refund ; + Refund refund; RefundInfo refundByOrderNo = refundInfoService.createRefundByOrderNo(orderId, reason); try { @@ -235,7 +483,7 @@ public class StripeServiceImpl implements StripeService { refund = Refund.create(params); log.info("根据会话编号退款成功"); - }else { + } else { log.error("当前订单不存在"); return "退款异常"; } @@ -260,7 +508,7 @@ public class StripeServiceImpl implements StripeService { // 更新积分状态 OrderInfo orderByOrderNo = orderInfoService.getOrderByOrderNo(orderId); - creditsService.creditsRefund(orderByOrderNo.getAccountId(), (int)(orderByOrderNo.getTotalFee() / Float.parseFloat(CreditsEventsEnum.PRICE.getValue()))); + creditsService.creditsRefund(orderByOrderNo.getAccountId(), (int) (orderByOrderNo.getTotalFee() / Float.parseFloat(CreditsEventsEnum.PRICE.getValue()))); } else { //更新订单状态 orderInfoService.updateStatusByOrderNo(orderId, OrderStatusEnum.REFUND_ABNORMAL); @@ -275,17 +523,17 @@ public class StripeServiceImpl implements StripeService { log.info("记录退款订单"); return "退款成功"; } - - public void checkOrderStatus(String orderNo){ + + public void checkOrderStatus(String orderNo) { Stripe.apiKey = privateKey; // 1、通过orderNo 查询sessionId PaymentInfo paymentInfo = paymentInfoService.getPaymentInfoByOrderId(orderNo); try { Session session = Session.retrieve(paymentInfo.getTransactionId()); - if (Objects.isNull(session)){ + if (Objects.isNull(session)) { log.warn("核实订单未创建 ===> {}", orderNo); return; - } else if (session.getStatus().equals("open") || session.getStatus().equals("expired")){ + } else if (session.getStatus().equals("open") || session.getStatus().equals("expired")) { // 订单未支付 || 订单过期 ---> 均设置为超时未支付 log.info("订单超时未支付 ===> {}", orderNo); //更新本地订单状态 @@ -304,96 +552,195 @@ public class StripeServiceImpl implements StripeService { } - // 1、创建customer,获取customerId - // 2、创建客户支付方式 (从前端获取) - // 3、创建支付 paymentIntent - // 4、确认订单 - // 5、捕获金额(执行扣款操作) - public String createCustomer() throws StripeException { + // 获取所有订阅 + public List getSubscription(String username, String userEmail) { + Stripe.apiKey = privateKey; + String customerId = null; + try { + customerId = getCustomer(username, userEmail); + SubscriptionCollection list = Subscription.list(SubscriptionListParams.builder() + .setCustomer(customerId).build()); + return list.getData(); + } catch (StripeException e) { + throw new RuntimeException(e); + } + + } + + private String getCustomer(String username, String userEmail) throws StripeException { + CustomerCollection list = Customer.list(CustomerListParams.builder().setEmail(userEmail).build()); + List data = list.getData(); + if (!data.isEmpty()) { + return data.get(0).getId(); + } + return createCustomer(username, userEmail); + } + + private String createCustomer(String name, String userEmail) throws StripeException { Stripe.apiKey = privateKey; // Customer允许重复使用 CustomerCreateParams params = CustomerCreateParams.builder() - .setName("xp") - .setEmail("xupei3360@163.com") + .setName(name) + .setEmail(userEmail) .build(); - Customer customer = Customer.create(params); return customer.getId(); } - public String createPaymentMethod(String customerId) throws StripeException { - - Stripe.apiKey = privateKey; - - PaymentMethodCreateParams params = - PaymentMethodCreateParams.builder() - .setType(PaymentMethodCreateParams.Type.CARD) - .setCard( - // 测试中,不建议使用卡号,会不安全的异常,必须使用token(https://docs.stripe.com/testing?testing-method=tokens#visa) - PaymentMethodCreateParams.Token.builder().setToken("tok_visa").build() -// PaymentMethodCreateParams.CardDetails.builder() -// .setNumber("4242424242424242") -// .setExpMonth(8L) -// .setExpYear(2026L) -// .setCvc("314") -// .build() - ) - .build(); - - PaymentMethod paymentMethod = PaymentMethod.create(params); - return paymentMethod.getId(); + /** + * 使用连续订阅的订单,回调中没有paymentIntentId,所以通过invoiceId间接获取 + * @param invoiceId 发票Id + */ + public Map getPaymentMethodByInvoiceId(String invoiceId) { + try { + Stripe.apiKey = privateKey; + Invoice invoice = Invoice.retrieve(invoiceId); + PaymentIntent paymentIntent = PaymentIntent.retrieve(invoice.getPaymentIntent()); + PaymentMethod paymentMethod = PaymentMethod.retrieve(paymentIntent.getPaymentMethod()); + return getPaymentMethod(paymentMethod.getId()); + } catch (StripeException e) { + throw new RuntimeException(e); + } } - public String createPaymentIntent(String paymentMethodId, String customerId) throws StripeException { + public Map getPaymentMethod(String paymentMethodId){ Stripe.apiKey = privateKey; + String paymentMethod = null; + String last4 = null; - Long amount = 600L; - PaymentIntentCreateParams params = - PaymentIntentCreateParams.builder() - .setAmount(amount) -// .setPaymentMethod(paymentMethodId) - .setCustomer(customerId) - .setCurrency("hkd") - .setAutomaticPaymentMethods( - PaymentIntentCreateParams.AutomaticPaymentMethods.builder() - .setEnabled(true) - .build() - ) - .build(); - - PaymentIntent paymentIntent = PaymentIntent.create(params); - return paymentIntent.getId(); + try { + PaymentMethod retrieve = PaymentMethod.retrieve(paymentMethodId); + switch (retrieve.getType()){ + case "alipay": + paymentMethod = "Alipay"; + break; + case "bancontact": + paymentMethod = "BanContact"; + break; + case "card": + PaymentMethod.Card card = retrieve.getCard(); + String brand = card.getBrand(); + brand = brand.substring(0, 1).toUpperCase() + brand.substring(1); + paymentMethod = brand + " " + card.getFunding() + "card"; + last4 = card.getLast4(); + break; + case "eps": + PaymentMethod.Eps eps = retrieve.getEps(); + paymentMethod = eps.getBank(); + break; + case "giropay": + paymentMethod = "GiroPay"; + break; + case "ideal": + PaymentMethod.Ideal ideal = retrieve.getIdeal(); + paymentMethod = ideal.getBank(); + break; + case "link": + paymentMethod = "Link"; + break; + } + HashMap resp = new HashMap<>(); + resp.put("paymentMethod", paymentMethod); + resp.put("last4", last4); + return resp; + } catch (StripeException e) { + throw new RuntimeException(e); + } +// return null; } - public String confirmPaymentIntent(String clientSecret) throws StripeException { - Stripe.apiKey = privateKey; + public boolean sendEmail(String subscriptionId, String type){ - PaymentIntent resource = PaymentIntent.retrieve(clientSecret); + SubscriptionEmailParamsDTO emailParamsDTO = new SubscriptionEmailParamsDTO(); + QueryWrapper qwSI = new QueryWrapper<>(); + qwSI.eq("subscription_id", subscriptionId); + SubscriptionInfo subscriptionInfo = subscriptionInfoMapper.selectOne(qwSI); + if (Objects.isNull(subscriptionInfo)) { + return false; + } + QueryWrapper qwPI = new QueryWrapper<>(); + qwPI.eq("order_no", subscriptionInfo.getOrderNo()).orderByDesc("id"); + List paymentInfos = paymentInfoMapper.selectList(qwPI); + if (paymentInfos.isEmpty()) { + return false; + } + PaymentInfo paymentInfo = paymentInfos.get(0); + if (paymentInfo.getNotified() == 1){ + // 已经邮件通知过,直接返回 + return true; + } + if (StringUtil.isNullOrEmpty(type)){ + // 如果没有传入type,则使用paymentInfo中记录的类型 + // (其实这里也可以通过invoiceId查询stripe,但是记录在自己的db中可以不用每次都查,且方便查看) + type = paymentInfo.getType(); + } - PaymentIntentConfirmParams params = - PaymentIntentConfirmParams.builder() - .setPaymentMethod("pm_card_visa") - .setReturnUrl("https://www.example.com") - .build(); + com.ai.da.mapper.primary.entity.Account account = accountMapper.selectById(subscriptionInfo.getAccountId()); + String userName = account.getUserName(); + String language = account.getLanguage(); - PaymentIntent paymentIntent = resource.confirm(params); - return paymentIntent.getId(); + emailParamsDTO.setUsername(userName); + emailParamsDTO.setOrderId(paymentInfo.getId().toString()); + emailParamsDTO.setCreateDate(String.valueOf(paymentInfo.getCreateTime()).replace("T", " ")); + emailParamsDTO.setQuantity(String.valueOf(1)); + emailParamsDTO.setTotalFee(paymentInfo.getPayerTotal().toString()); + emailParamsDTO.setLastOrderDate(changeTimeStampFormat(subscriptionInfo.getCurrentPeriodStart(), "seconds", CommonConstant.TIME_FORMAT_MMM_dd_yyyy)); + emailParamsDTO.setEndOfPrepaidTerm(changeTimeStampFormat(subscriptionInfo.getCurrentPeriodEnd(), "seconds", CommonConstant.TIME_FORMAT_MMM_dd_yyyy)); + emailParamsDTO.setPaymentMethod(subscriptionInfo.getPaymentMethod()); + emailParamsDTO.setSubscriptionId(subscriptionInfo.getId().toString()); + emailParamsDTO.setSubscriptionType(subscriptionInfo.getType()); + emailParamsDTO.setStartDate(changeTimeStampFormat(subscriptionInfo.getCurrentPeriodStart(), "seconds", CommonConstant.TIME_FORMAT_MMM_dd_yyyy)); + emailParamsDTO.setNextPayDate(changeTimeStampFormat(subscriptionInfo.getCurrentPeriodEnd(), "seconds", CommonConstant.TIME_FORMAT_MMM_dd_yyyy)); + emailParamsDTO.setRenewalTime(changeTimeStampFormat(subscriptionInfo.getCurrentPeriodEnd(), "seconds", CommonConstant.TIME_FORMAT_MMM_dd_yyyy)); + + SendEmailUtil.subscriptionEmailReminder(type, emailParamsDTO, language, account.getUserEmail()); + + // 邮件通知成功后,更新标志 + PaymentInfo payment = new PaymentInfo(); + payment.setId(paymentInfo.getId()); + payment.setNotified(1); + payment.setUpdateTime(LocalDateTime.now()); + paymentInfoMapper.updateById(payment); + return true; } - public String capturePaymentIntent(String clientSecret) throws StripeException { + public void subscriptionReminder(){ + // 提前7天的 00:00:00 和 23:59:59 + LocalDateTime startOfDay = LocalDateTime.now().plusDays(7).toLocalDate().atStartOfDay(); + LocalDateTime endOfDay = LocalDateTime.now().plusDays(7).toLocalDate().atTime(23, 59, 59); - Stripe.apiKey = privateKey; + // 转为时间戳 + long startTimestamp = startOfDay.toEpochSecond(ZoneOffset.UTC); + long endTimestamp = endOfDay.toEpochSecond(ZoneOffset.UTC); - PaymentIntent resource = PaymentIntent.retrieve(clientSecret); + QueryWrapper qw = new QueryWrapper<>(); + qw.ge("current_period_end", startTimestamp); + qw.lt("current_period_end", endTimestamp); + qw.eq("status", "active"); - PaymentIntentCaptureParams params = PaymentIntentCaptureParams.builder().build(); - - PaymentIntent paymentIntent = resource.capture(params); - return null; + List subscriptionInfos = subscriptionInfoMapper.selectList(qw); + for (SubscriptionInfo subscriptionInfo : subscriptionInfos) { + boolean b = sendEmail(subscriptionInfo.getSubscriptionId(), null); + if (b) log.info("提前7天向用户 {} 发送续订通知邮件", subscriptionInfo.getAccountId()); + } } + public void checkSubscriptionExpiration(){ + long epochSecond = Instant.now().getEpochSecond(); + QueryWrapper qw = new QueryWrapper<>(); + qw.lt("current_period_end", epochSecond); + qw.eq("status", "active"); + List subscriptionInfos = subscriptionInfoMapper.selectList(qw); + + for (SubscriptionInfo subscriptionInfo : subscriptionInfos) { + subscriptionInfo.setStatus("expired"); + subscriptionInfo.setUpdateTime(LocalDateTime.now()); + subscriptionInfoMapper.updateById(subscriptionInfo); + log.info("用户 {} 的订阅 {} 已过期", subscriptionInfo.getAccountId(), subscriptionInfo.getOrderNo()); + } + } } diff --git a/src/main/resources/payment.properties b/src/main/resources/payment.properties index 56e5a315..43c4e4b7 100644 --- a/src/main/resources/payment.properties +++ b/src/main/resources/payment.properties @@ -27,13 +27,13 @@ paypal.webhook_id=1D107312EX592781K ##### Stripe # developer -#stripe.private-key=sk_test_51P4ZZL02n1TEydyN8qQHjOA9imsFU7Oxs2HMHGy2urHnnQgSHnZuu5vVP6pKhEACwUpsKNyrbZpdcg5TJWJLRHcY008dEO1fn2 -#stripe.webhook-sign-secret=whsec_e0dBiJngx6qqgJj6yPyJ2A9ouh1Cjv5w +stripe.private-key=sk_test_51P4ZZL02n1TEydyN8qQHjOA9imsFU7Oxs2HMHGy2urHnnQgSHnZuu5vVP6pKhEACwUpsKNyrbZpdcg5TJWJLRHcY008dEO1fn2 +stripe.webhook-sign-secret=whsec_e0dBiJngx6qqgJj6yPyJ2A9ouh1Cjv5w # kim - test #stripe.private-key=sk_test_51LwPrxH7nPZ8bkrNj67TFD7sxucaTANs1lf0KGSu1QSJfxYXcnigq2wTaZyZzST7y0fMbhhvaJZ4LjjFhr95M83a00eXrmOTL0 #stripe.webhook-sign-secret=whsec_GoyVEAaBtuGD5Rt55z83JnPnLDAZTN3u # kim - live -stripe.private-key=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 -stripe.webhook-sign-secret=whsec_hhGDgdelQRHSg4LmChtQe41crj41eb11 \ No newline at end of file +#stripe.private-key=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 +#stripe.webhook-sign-secret=whsec_hhGDgdelQRHSg4LmChtQe41crj41eb11 \ No newline at end of file From f6f759110fddc981ad402b433c577912a85b0f24 Mon Sep 17 00:00:00 2001 From: xupei Date: Tue, 19 Nov 2024 16:00:30 +0800 Subject: [PATCH 04/91] =?UTF-8?q?=E6=94=AF=E4=BB=98=E4=BC=98=E5=8C=96--?= =?UTF-8?q?=E4=BF=AE=E6=94=B9=E7=A7=AF=E5=88=86=E8=B4=AD=E4=B9=B0=E7=9B=B8?= =?UTF-8?q?=E5=BA=94=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/ai/da/service/CreditsService.java | 4 +- .../ai/da/service/impl/AliPayServiceImpl.java | 8 ++- .../da/service/impl/AlipayHKServiceImpl.java | 3 +- .../da/service/impl/CreditsServiceImpl.java | 7 +- .../da/service/impl/GenerateServiceImpl.java | 4 +- .../impl/PayPalCheckoutServiceImpl.java | 28 ++++---- .../service/impl/PaymentInfoServiceImpl.java | 11 +++- .../ai/da/service/impl/StripeServiceImpl.java | 64 ++++++++++++------- .../impl/SuperResolutionServiceImpl.java | 2 +- src/main/resources/messages_en.properties | 1 + src/main/resources/messages_zh.properties | 1 + 11 files changed, 81 insertions(+), 52 deletions(-) diff --git a/src/main/java/com/ai/da/service/CreditsService.java b/src/main/java/com/ai/da/service/CreditsService.java index 1d076527..62d9e5e4 100644 --- a/src/main/java/com/ai/da/service/CreditsService.java +++ b/src/main/java/com/ai/da/service/CreditsService.java @@ -17,9 +17,9 @@ public interface CreditsService extends IService { String getCredits(Long accountId); - void creditsRefund(Long accountId, Integer quantity); + void creditsRefund(Long accountId, Integer quantity, String orderNo); - void insertToCreditsDetail(Long accountId, String changeEvent, String credits, String changeType); + void insertToCreditsDetail(Long accountId, String changeEvent, String credits, String changeType, String orderNo); PageBaseResponse queryCreditsDetailsPage(QueryIncomeOrExpenditureDTO queryPageByTimeDTO); diff --git a/src/main/java/com/ai/da/service/impl/AliPayServiceImpl.java b/src/main/java/com/ai/da/service/impl/AliPayServiceImpl.java index ccbd47d2..04fc8993 100644 --- a/src/main/java/com/ai/da/service/impl/AliPayServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/AliPayServiceImpl.java @@ -217,7 +217,8 @@ public class AliPayServiceImpl implements AliPayService { creditsService.insertToCreditsDetail(orderByOrderNo.getAccountId(), CreditsEventsEnum.BUY_CREDITS.getName() + "--Alipay", String.valueOf((Long.parseLong(CreditsEventsEnum.BUY_CREDITS.getValue()) * quantity)), - "positive"); + "positive", + orderByOrderNo.getOrderNo()); } finally { //要主动释放锁 lock.unlock(); @@ -320,7 +321,8 @@ public class AliPayServiceImpl implements AliPayService { creditsService.insertToCreditsDetail(orderByOrderNo.getAccountId(), CreditsEventsEnum.BUY_CREDITS.getName() + "--Alipay", String.valueOf((Long.parseLong(CreditsEventsEnum.BUY_CREDITS.getValue()) * quantity)), - "positive"); + "positive", + orderByOrderNo.getOrderNo()); } } @@ -393,7 +395,7 @@ public class AliPayServiceImpl implements AliPayService { // 更新积分状态 OrderInfo orderByOrderNo = orderInfoService.getOrderByOrderNo(orderNo); // creditsService.creditsRefund(orderByOrderNo.getAccountId(), orderByOrderNo.getTotalFee() / Integer.parseInt(CreditsEventsEnum.PRICE.getValue())); - creditsService.creditsRefund(orderByOrderNo.getAccountId(), (int)(orderByOrderNo.getTotalFee() / Float.parseFloat(CreditsEventsEnum.PRICE.getValue()))); + creditsService.creditsRefund(orderByOrderNo.getAccountId(), (int)(orderByOrderNo.getTotalFee() / Float.parseFloat(CreditsEventsEnum.PRICE.getValue())), orderNo); } else { log.info("调用失败,返回码 ===> " + response.getCode() + ", 返回描述 ===> " + response.getMsg()); diff --git a/src/main/java/com/ai/da/service/impl/AlipayHKServiceImpl.java b/src/main/java/com/ai/da/service/impl/AlipayHKServiceImpl.java index f20d7350..417a03bd 100644 --- a/src/main/java/com/ai/da/service/impl/AlipayHKServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/AlipayHKServiceImpl.java @@ -248,7 +248,8 @@ public class AlipayHKServiceImpl implements AlipayHKService { creditsService.insertToCreditsDetail(orderByOrderNo.getAccountId(), CreditsEventsEnum.BUY_CREDITS.getName() + "--AlipayHK", String.valueOf((Long.parseLong(CreditsEventsEnum.BUY_CREDITS.getValue()) * quantity)), - "positive"); + "positive", + orderByOrderNo.getOrderNo()); log.info("用户:{} 积分信息更新成功",orderByOrderNo.getAccountId()); } finally { //要主动释放锁 diff --git a/src/main/java/com/ai/da/service/impl/CreditsServiceImpl.java b/src/main/java/com/ai/da/service/impl/CreditsServiceImpl.java index 9cc17ce8..5c24211c 100644 --- a/src/main/java/com/ai/da/service/impl/CreditsServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/CreditsServiceImpl.java @@ -100,7 +100,7 @@ public class CreditsServiceImpl extends ServiceImpl增 negative->减 */ @Override - public void insertToCreditsDetail(Long accountId, String changeEvent, String credits, String changeType) { + public void insertToCreditsDetail(Long accountId, String changeEvent, String credits, String changeType, String orderNo) { CreditsDetail creditsDetail = new CreditsDetail(); Account account = accountMapper.selectById(accountId); // BigDecimal finalCredits; @@ -137,6 +137,7 @@ public class CreditsServiceImpl extends ServiceImpl i if (b) creditsService.insertToCreditsDetail(accountId, CreditsEventsEnum.TO_PRODUCT_IMAGE.getName(), CreditsEventsEnum.TO_PRODUCT_IMAGE.getValue(), - "negative"); + "negative", null); } } @@ -736,7 +736,7 @@ public class GenerateServiceImpl extends ServiceImpl i if (b) creditsService.insertToCreditsDetail(accountId, CreditsEventsEnum.RELIGHT.getName(), CreditsEventsEnum.RELIGHT.getValue(), - "negative"); + "negative", null); } } diff --git a/src/main/java/com/ai/da/service/impl/PayPalCheckoutServiceImpl.java b/src/main/java/com/ai/da/service/impl/PayPalCheckoutServiceImpl.java index 22c57621..fb5d5409 100644 --- a/src/main/java/com/ai/da/service/impl/PayPalCheckoutServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/PayPalCheckoutServiceImpl.java @@ -441,11 +441,11 @@ public class PayPalCheckoutServiceImpl implements PayPalCheckoutService { * 申请退款 */ @Transactional(rollbackFor = Exception.class) - public Boolean refundOrder(String orderId, String reason) throws IOException { + public Boolean refundOrder(String orderNo, String reason) throws IOException { - RefundInfo refundByOrderNo = refundsInfoService.createRefundByOrderNo(orderId, reason); + RefundInfo refundByOrderNo = refundsInfoService.createRefundByOrderNo(orderNo, reason); - OrdersGetRequest ordersGetRequest = new OrdersGetRequest(orderId); + OrdersGetRequest ordersGetRequest = new OrdersGetRequest(orderNo); PayPalClient payPalClient = new PayPalClient(); HttpResponse ordersGetResponse = null; ordersGetRequest.authorization("Bearer " + getOAuth()); @@ -461,7 +461,7 @@ public class PayPalCheckoutServiceImpl implements PayPalCheckoutService { request.authorization("Bearer " + getOAuth()); request.prefer("return=representation"); - OrderInfo orderInfo = orderInfoService.getOrderByOrderNo(orderId); + OrderInfo orderInfo = orderInfoService.getOrderByOrderNo(orderNo); request.requestBody(buildRefundRequestBody(String.valueOf(orderInfo.getTotalFee()), reason)); HttpResponse response = null; try { @@ -476,7 +476,7 @@ public class PayPalCheckoutServiceImpl implements PayPalCheckoutService { //进行数据库操作,修改状态为已退款(配合回调和退款查询确定退款成功) //更新订单状态 - orderInfoService.updateStatusByOrderNo(orderId, OrderStatusEnum.REFUND_SUCCESS); + orderInfoService.updateStatusByOrderNo(orderNo, OrderStatusEnum.REFUND_SUCCESS); refundsInfoService.updateRefundForPayPal( refundByOrderNo.getId(), @@ -485,14 +485,14 @@ public class PayPalCheckoutServiceImpl implements PayPalCheckoutService { AliPayTradeStateEnum.REFUND_SUCCESS.getType()); //退款成功 // 更新积分状态 - OrderInfo orderByOrderNo = orderInfoService.getOrderByOrderNo(orderId); + OrderInfo orderByOrderNo = orderInfoService.getOrderByOrderNo(orderNo); // creditsService.creditsRefund(orderByOrderNo.getAccountId(), orderByOrderNo.getTotalFee() / Integer.parseInt(CreditsEventsEnum.PRICE.getValue())); - creditsService.creditsRefund(orderByOrderNo.getAccountId(), (int)(orderByOrderNo.getTotalFee() / Float.parseFloat(CreditsEventsEnum.PRICE.getValue()))); + creditsService.creditsRefund(orderByOrderNo.getAccountId(), (int)(orderByOrderNo.getTotalFee() / Float.parseFloat(CreditsEventsEnum.PRICE.getValue())), orderNo); log.info("退款成功"); result = Boolean.TRUE; } else { //更新订单状态 - orderInfoService.updateStatusByOrderNo(orderId, OrderStatusEnum.REFUND_ABNORMAL); + orderInfoService.updateStatusByOrderNo(orderNo, OrderStatusEnum.REFUND_ABNORMAL); //更新退款单 refundsInfoService.updateRefundForPayPal( @@ -571,19 +571,19 @@ public class PayPalCheckoutServiceImpl implements PayPalCheckoutService { // 处理当前订单 @Transactional(rollbackFor = Exception.class) - public void processOrder(String orderId) { + public void processOrder(String orderNo) { // 1、确定当前订单是否已经被扣款 - OrderInfo orderInfo = orderInfoService.getOrderByOrderNo(orderId); + OrderInfo orderInfo = orderInfoService.getOrderByOrderNo(orderNo); if (orderInfo.getOrderStatus().equals(OrderStatusEnum.SUCCESS.getType())) { // 直接返回 return; } // 发起扣款请求 - Order capturedOrder = captureOrder(orderId); + Order capturedOrder = captureOrder(orderNo); // 业务处理 if (PayPalOrderStatusEnum.COMPLETED.getStatus().equals(capturedOrder.status())) { //更新订单状态 - orderInfoService.updateStatusByOrderNo(orderId, OrderStatusEnum.SUCCESS); + orderInfoService.updateStatusByOrderNo(orderNo, OrderStatusEnum.SUCCESS); //记录支付日志 paymentInfoService.createPaymentInfoForPayPal(capturedOrder); float quantity = orderInfo.getTotalFee() / Float.parseFloat(CreditsEventsEnum.PRICE.getValue()); @@ -593,7 +593,7 @@ public class PayPalCheckoutServiceImpl implements PayPalCheckoutService { creditsService.insertToCreditsDetail(orderInfo.getAccountId(), CreditsEventsEnum.BUY_CREDITS.getName() + "--PayPal", String.valueOf((Long.parseLong(CreditsEventsEnum.BUY_CREDITS.getValue()) * quantity)), - "positive"); + "positive", orderNo); } } @@ -637,7 +637,7 @@ public class PayPalCheckoutServiceImpl implements PayPalCheckoutService { creditsService.insertToCreditsDetail(orderByOrderNo.getAccountId(), CreditsEventsEnum.BUY_CREDITS.getName() + "--Paypal", String.valueOf((Long.parseLong(CreditsEventsEnum.BUY_CREDITS.getValue()) * quantity)), - "positive"); + "positive", orderNo); } } diff --git a/src/main/java/com/ai/da/service/impl/PaymentInfoServiceImpl.java b/src/main/java/com/ai/da/service/impl/PaymentInfoServiceImpl.java index 035e1135..36acae75 100644 --- a/src/main/java/com/ai/da/service/impl/PaymentInfoServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/PaymentInfoServiceImpl.java @@ -187,10 +187,15 @@ public class PaymentInfoServiceImpl extends ServiceImpl resp = new HashMap<>(); + resp.put("paymentMethod", null); + resp.put("last4", null); + return resp; } catch (StripeException e) { throw new RuntimeException(e); } @@ -668,15 +684,15 @@ public class StripeServiceImpl implements StripeService { return false; } PaymentInfo paymentInfo = paymentInfos.get(0); - if (paymentInfo.getNotified() == 1){ - // 已经邮件通知过,直接返回 - return true; - } if (StringUtil.isNullOrEmpty(type)){ // 如果没有传入type,则使用paymentInfo中记录的类型 // (其实这里也可以通过invoiceId查询stripe,但是记录在自己的db中可以不用每次都查,且方便查看) type = paymentInfo.getType(); } + if (!type.equals("reminder") && paymentInfo.getNotified() == 1){ + // 已经邮件通知过,直接返回 + return true; + } com.ai.da.mapper.primary.entity.Account account = accountMapper.selectById(subscriptionInfo.getAccountId()); String userName = account.getUserName(); @@ -692,18 +708,20 @@ public class StripeServiceImpl implements StripeService { emailParamsDTO.setPaymentMethod(subscriptionInfo.getPaymentMethod()); emailParamsDTO.setSubscriptionId(subscriptionInfo.getId().toString()); emailParamsDTO.setSubscriptionType(subscriptionInfo.getType()); - emailParamsDTO.setStartDate(changeTimeStampFormat(subscriptionInfo.getCurrentPeriodStart(), "seconds", CommonConstant.TIME_FORMAT_MMM_dd_yyyy)); + emailParamsDTO.setStartDate(changeTimeStampFormat(subscriptionInfo.getCreateTime())); emailParamsDTO.setNextPayDate(changeTimeStampFormat(subscriptionInfo.getCurrentPeriodEnd(), "seconds", CommonConstant.TIME_FORMAT_MMM_dd_yyyy)); emailParamsDTO.setRenewalTime(changeTimeStampFormat(subscriptionInfo.getCurrentPeriodEnd(), "seconds", CommonConstant.TIME_FORMAT_MMM_dd_yyyy)); SendEmailUtil.subscriptionEmailReminder(type, emailParamsDTO, language, account.getUserEmail()); // 邮件通知成功后,更新标志 - PaymentInfo payment = new PaymentInfo(); - payment.setId(paymentInfo.getId()); - payment.setNotified(1); - payment.setUpdateTime(LocalDateTime.now()); - paymentInfoMapper.updateById(payment); + if (!type.equals("reminder")){ + PaymentInfo payment = new PaymentInfo(); + payment.setId(paymentInfo.getId()); + payment.setNotified(1); + payment.setUpdateTime(LocalDateTime.now()); + paymentInfoMapper.updateById(payment); + } return true; } @@ -723,7 +741,7 @@ public class StripeServiceImpl implements StripeService { List subscriptionInfos = subscriptionInfoMapper.selectList(qw); for (SubscriptionInfo subscriptionInfo : subscriptionInfos) { - boolean b = sendEmail(subscriptionInfo.getSubscriptionId(), null); + boolean b = sendEmail(subscriptionInfo.getSubscriptionId(), "reminder"); if (b) log.info("提前7天向用户 {} 发送续订通知邮件", subscriptionInfo.getAccountId()); } } diff --git a/src/main/java/com/ai/da/service/impl/SuperResolutionServiceImpl.java b/src/main/java/com/ai/da/service/impl/SuperResolutionServiceImpl.java index 03ed3d69..eda65b46 100644 --- a/src/main/java/com/ai/da/service/impl/SuperResolutionServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/SuperResolutionServiceImpl.java @@ -149,7 +149,7 @@ public class SuperResolutionServiceImpl extends ServiceImpl Date: Tue, 19 Nov 2024 17:08:16 +0800 Subject: [PATCH 05/91] =?UTF-8?q?=E6=94=AF=E4=BB=98=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/ai/da/common/utils/SendEmailUtil.java | 20 +++++++++++-------- .../com/ai/da/service/PaymentInfoService.java | 2 +- .../service/impl/PaymentInfoServiceImpl.java | 5 ++--- .../ai/da/service/impl/StripeServiceImpl.java | 14 +++++++------ 4 files changed, 23 insertions(+), 18 deletions(-) diff --git a/src/main/java/com/ai/da/common/utils/SendEmailUtil.java b/src/main/java/com/ai/da/common/utils/SendEmailUtil.java index d1a30ae1..c52d3d8c 100644 --- a/src/main/java/com/ai/da/common/utils/SendEmailUtil.java +++ b/src/main/java/com/ai/da/common/utils/SendEmailUtil.java @@ -782,7 +782,8 @@ public class SendEmailUtil { public static void subscriptionEmailReminder(String type, SubscriptionEmailParamsDTO subscriptionEmailParamsDTO, String language, String receiverAddress){ try{ - String kimEmail = "kimwong@code-create.com.hk"; +// String merchantEmail = "kimwong@code-create.com.hk"; + String merchantEmail = "xupei3360@163.com"; Credential cred = new Credential(SECRET_ID, SECRET_KEy); // 实例化一个http选项,可选的,没有特殊需求可以跳过 HttpProfile httpProfile = new HttpProfile(); @@ -798,7 +799,7 @@ public class SendEmailUtil { user.setDestination(new String[]{receiverAddress}); SendEmailRequest merchant = new SendEmailRequest(); merchant.setFromEmailAddress(SEND_ADDRESS); - merchant.setDestination(new String[]{kimEmail}); + merchant.setDestination(new String[]{merchantEmail}); Template templateUser = new Template(); Template templateMerchant = new Template(); switch (type) { @@ -848,12 +849,15 @@ public class SendEmailUtil { templateMerchant.setTemplateData(JSON.toJSONString(subscriptionEmailParamsDTO)); merchant.setTemplate(templateMerchant); - // 返回的resp是一个SendEmailResponse的实例,与请求对象对应 - SendEmailResponse respUser = client.SendEmail(user); - // todo 暂时先不发商家邮件 -// SendEmailResponse respMerchant = client.SendEmail(merchant); - log.info("邮件发送结果toUser###{}", SendEmailResponse.toJsonString(respUser)); -// log.info("邮件发送结果toMerchant###{}", SendEmailResponse.toJsonString(respMerchant)); + if (!type.equals("cancel")){ + // 返回的resp是一个SendEmailResponse的实例,与请求对象对应 + SendEmailResponse respUser = client.SendEmail(user); + log.info("邮件发送结果toUser###{}", SendEmailResponse.toJsonString(respUser)); + } + if (!type.equals("reminder")){ + SendEmailResponse respMerchant = client.SendEmail(merchant); + log.info("邮件发送结果toMerchant###{}", SendEmailResponse.toJsonString(respMerchant)); + } } catch (TencentCloudSDKException e) { log.info("邮件发送失败###{}", e.toString()); throw new BusinessException("failed.to.send.mail"); diff --git a/src/main/java/com/ai/da/service/PaymentInfoService.java b/src/main/java/com/ai/da/service/PaymentInfoService.java index 6d3d2d5e..fcc69d00 100644 --- a/src/main/java/com/ai/da/service/PaymentInfoService.java +++ b/src/main/java/com/ai/da/service/PaymentInfoService.java @@ -18,7 +18,7 @@ public interface PaymentInfoService extends IService { void createPaymentInfoForAliPayHK(AlipayHKCallbackDTO alipayHKCallbackDTO); - String createPaymentInfoForStripe(Invoice invoice); + PaymentInfo createPaymentInfoForStripe(Invoice invoice); PaymentInfo getPaymentInfoByOrderId(String orderId); diff --git a/src/main/java/com/ai/da/service/impl/PaymentInfoServiceImpl.java b/src/main/java/com/ai/da/service/impl/PaymentInfoServiceImpl.java index 36acae75..e78fd856 100644 --- a/src/main/java/com/ai/da/service/impl/PaymentInfoServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/PaymentInfoServiceImpl.java @@ -176,7 +176,7 @@ public class PaymentInfoServiceImpl extends ServiceImpl resp = new HashMap<>(); - resp.put("paymentMethod", null); - resp.put("last4", null); + resp.put("paymentMethod", "N/A"); + resp.put("last4", "N/A"); return resp; } catch (StripeException e) { throw new RuntimeException(e); @@ -697,6 +698,7 @@ public class StripeServiceImpl implements StripeService { com.ai.da.mapper.primary.entity.Account account = accountMapper.selectById(subscriptionInfo.getAccountId()); String userName = account.getUserName(); String language = account.getLanguage(); + OrderInfo orderByOrderNo = orderInfoService.getOrderByOrderNo(subscriptionInfo.getOrderNo()); emailParamsDTO.setUsername(userName); emailParamsDTO.setOrderId(paymentInfo.getId().toString()); @@ -708,7 +710,7 @@ public class StripeServiceImpl implements StripeService { emailParamsDTO.setPaymentMethod(subscriptionInfo.getPaymentMethod()); emailParamsDTO.setSubscriptionId(subscriptionInfo.getId().toString()); emailParamsDTO.setSubscriptionType(subscriptionInfo.getType()); - emailParamsDTO.setStartDate(changeTimeStampFormat(subscriptionInfo.getCreateTime())); + emailParamsDTO.setStartDate(changeTimeStampFormat(orderByOrderNo.getCreateTime())); emailParamsDTO.setNextPayDate(changeTimeStampFormat(subscriptionInfo.getCurrentPeriodEnd(), "seconds", CommonConstant.TIME_FORMAT_MMM_dd_yyyy)); emailParamsDTO.setRenewalTime(changeTimeStampFormat(subscriptionInfo.getCurrentPeriodEnd(), "seconds", CommonConstant.TIME_FORMAT_MMM_dd_yyyy)); From 5019fbd3fc6156227c97f683e627f89a607be7d7 Mon Sep 17 00:00:00 2001 From: xupei Date: Mon, 25 Nov 2024 10:53:09 +0800 Subject: [PATCH 06/91] =?UTF-8?q?=E6=94=AF=E4=BB=98=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ai/da/common/enums/OrderStatusEnum.java | 5 + .../com/ai/da/common/utils/SendEmailUtil.java | 16 +- .../da/mapper/primary/entity/OrderInfo.java | 2 + .../da/mapper/primary/entity/PaymentInfo.java | 4 + .../primary/entity/SubscriptionInfo.java | 9 +- .../model/dto/SubscriptionEmailParamsDTO.java | 5 + .../com/ai/da/service/PaymentInfoService.java | 5 +- .../service/impl/PaymentInfoServiceImpl.java | 95 ++++++++++- .../ai/da/service/impl/StripeServiceImpl.java | 151 +++++++++++++++--- 9 files changed, 257 insertions(+), 35 deletions(-) diff --git a/src/main/java/com/ai/da/common/enums/OrderStatusEnum.java b/src/main/java/com/ai/da/common/enums/OrderStatusEnum.java index aac9719d..8f8699a6 100644 --- a/src/main/java/com/ai/da/common/enums/OrderStatusEnum.java +++ b/src/main/java/com/ai/da/common/enums/OrderStatusEnum.java @@ -17,6 +17,11 @@ public enum OrderStatusEnum { */ SUCCESS("支付成功"), + /** + * 支付失败 + */ + FAILURE("支付失败"), + /** * 已关闭 */ diff --git a/src/main/java/com/ai/da/common/utils/SendEmailUtil.java b/src/main/java/com/ai/da/common/utils/SendEmailUtil.java index c52d3d8c..c6d61e68 100644 --- a/src/main/java/com/ai/da/common/utils/SendEmailUtil.java +++ b/src/main/java/com/ai/da/common/utils/SendEmailUtil.java @@ -779,6 +779,8 @@ public class SendEmailUtil { private final static Long RENEWAL_USER_CN = 130726L; private final static Long RENEWAL_REMINDER_USER_EN = 130727L; private final static Long RENEWAL_REMINDER_USER_CN = 130728L; + private final static Long PAYMENT_FAILED_NEW_MERCHANT_EN = 131230L; + private final static Long PAYMENT_FAILED_RENEWAL_MERCHANT_EN = 131225L; public static void subscriptionEmailReminder(String type, SubscriptionEmailParamsDTO subscriptionEmailParamsDTO, String language, String receiverAddress){ try{ @@ -807,6 +809,14 @@ public class SendEmailUtil { merchant.setSubject("[Code-Create] Subscription Cancelled"); templateMerchant.setTemplateID(CANCEL_MERCHANT_EN); break; + case "fail_new": + merchant.setSubject("[Code-Create] Payment Failed : New Order (" + subscriptionEmailParamsDTO.getOrderId() + ")"); + templateMerchant.setTemplateID(PAYMENT_FAILED_NEW_MERCHANT_EN); + break; + case "fail_renewal": + merchant.setSubject("[Code-Create] Payment Failed : Renewal Order (" + subscriptionEmailParamsDTO.getOrderId() + ")"); + templateMerchant.setTemplateID(PAYMENT_FAILED_RENEWAL_MERCHANT_EN); + break; case "new": merchant.setSubject("[Code-Create] New Order(" + subscriptionEmailParamsDTO.getOrderId() + ")"); templateMerchant.setTemplateID(NEW_MERCHANT_EN); @@ -849,14 +859,14 @@ public class SendEmailUtil { templateMerchant.setTemplateData(JSON.toJSONString(subscriptionEmailParamsDTO)); merchant.setTemplate(templateMerchant); - if (!type.equals("cancel")){ + if (!type.equals("cancel") && !type.equals("fail_new") && !type.equals("fail_renewal") ){ // 返回的resp是一个SendEmailResponse的实例,与请求对象对应 SendEmailResponse respUser = client.SendEmail(user); - log.info("邮件发送结果toUser###{}", SendEmailResponse.toJsonString(respUser)); + log.info("邮件主题:{},发送结果toUser###{}", user.getSubject(), SendEmailResponse.toJsonString(respUser)); } if (!type.equals("reminder")){ SendEmailResponse respMerchant = client.SendEmail(merchant); - log.info("邮件发送结果toMerchant###{}", SendEmailResponse.toJsonString(respMerchant)); + log.info("邮件主题:{},发送结果toMerchant###{}", merchant.getSubject(), SendEmailResponse.toJsonString(respMerchant)); } } catch (TencentCloudSDKException e) { log.info("邮件发送失败###{}", e.toString()); diff --git a/src/main/java/com/ai/da/mapper/primary/entity/OrderInfo.java b/src/main/java/com/ai/da/mapper/primary/entity/OrderInfo.java index 98a020b9..e5bc0a98 100644 --- a/src/main/java/com/ai/da/mapper/primary/entity/OrderInfo.java +++ b/src/main/java/com/ai/da/mapper/primary/entity/OrderInfo.java @@ -21,5 +21,7 @@ public class OrderInfo extends BaseEntity{ private String orderStatus;//订单状态 + private String note; + private String paymentType;//支付方式 } diff --git a/src/main/java/com/ai/da/mapper/primary/entity/PaymentInfo.java b/src/main/java/com/ai/da/mapper/primary/entity/PaymentInfo.java index 3806d888..8172f4bd 100644 --- a/src/main/java/com/ai/da/mapper/primary/entity/PaymentInfo.java +++ b/src/main/java/com/ai/da/mapper/primary/entity/PaymentInfo.java @@ -26,4 +26,8 @@ public class PaymentInfo extends BaseEntity{ // 当前支付是否已邮件通知 0 || 1 private Integer notified; + + private String paymentMethod; + + private String last4; } diff --git a/src/main/java/com/ai/da/mapper/primary/entity/SubscriptionInfo.java b/src/main/java/com/ai/da/mapper/primary/entity/SubscriptionInfo.java index 2b61cf48..b7895c08 100644 --- a/src/main/java/com/ai/da/mapper/primary/entity/SubscriptionInfo.java +++ b/src/main/java/com/ai/da/mapper/primary/entity/SubscriptionInfo.java @@ -22,14 +22,7 @@ public class SubscriptionInfo extends BaseEntity{ // active || expired private String status = "active"; - // 是否自动续订 - private byte autoRenewal = (byte)1; - - // 支付方式 - private String paymentMethod; - - // 如果是用卡支付,可以看到银行卡最后四位 - private String last4; + private byte cancelNotified = (byte)0; // 续订的下一个付款日 private String nextPayDate; diff --git a/src/main/java/com/ai/da/model/dto/SubscriptionEmailParamsDTO.java b/src/main/java/com/ai/da/model/dto/SubscriptionEmailParamsDTO.java index 0020582f..9ecf0241 100644 --- a/src/main/java/com/ai/da/model/dto/SubscriptionEmailParamsDTO.java +++ b/src/main/java/com/ai/da/model/dto/SubscriptionEmailParamsDTO.java @@ -28,6 +28,8 @@ public class SubscriptionEmailParamsDTO { // 付款方式 private String paymentMethod; + private String last4; + // 订阅Id private String subscriptionId; @@ -43,5 +45,8 @@ public class SubscriptionEmailParamsDTO { // 下次付款时间(reminder) private String renewalTime; + // 付款失败原因 + private String failMessage; + } diff --git a/src/main/java/com/ai/da/service/PaymentInfoService.java b/src/main/java/com/ai/da/service/PaymentInfoService.java index fcc69d00..785fb286 100644 --- a/src/main/java/com/ai/da/service/PaymentInfoService.java +++ b/src/main/java/com/ai/da/service/PaymentInfoService.java @@ -4,6 +4,7 @@ import com.ai.da.mapper.primary.entity.PaymentInfo; import com.ai.da.model.dto.AlipayHKCallbackDTO; import com.baomidou.mybatisplus.extension.service.IService; import com.paypal.orders.Order; +import com.stripe.model.Charge; import com.stripe.model.Invoice; import java.util.Map; @@ -18,7 +19,9 @@ public interface PaymentInfoService extends IService { void createPaymentInfoForAliPayHK(AlipayHKCallbackDTO alipayHKCallbackDTO); - PaymentInfo createPaymentInfoForStripe(Invoice invoice); + PaymentInfo createOrUpdatePaymentInfoForStripe(Invoice invoice); + + PaymentInfo createOrUpdatePaymentInfoForStripe(Charge charge); PaymentInfo getPaymentInfoByOrderId(String orderId); diff --git a/src/main/java/com/ai/da/service/impl/PaymentInfoServiceImpl.java b/src/main/java/com/ai/da/service/impl/PaymentInfoServiceImpl.java index e78fd856..204a9ce4 100644 --- a/src/main/java/com/ai/da/service/impl/PaymentInfoServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/PaymentInfoServiceImpl.java @@ -11,6 +11,7 @@ import com.google.gson.Gson; import com.paypal.orders.Order; import com.stripe.Stripe; import com.stripe.exception.StripeException; +import com.stripe.model.Charge; import com.stripe.model.Invoice; import com.stripe.model.Subscription; import com.stripe.model.checkout.Session; @@ -20,6 +21,7 @@ import org.springframework.stereotype.Service; import java.math.BigDecimal; import java.math.RoundingMode; +import java.time.LocalDateTime; import java.util.HashMap; import java.util.Map; import java.util.Objects; @@ -28,6 +30,12 @@ import java.util.Objects; @Slf4j public class PaymentInfoServiceImpl extends ServiceImpl implements PaymentInfoService { + private final StripeServiceImpl stripeServiceImpl; + + public PaymentInfoServiceImpl(StripeServiceImpl stripeServiceImpl) { + this.stripeServiceImpl = stripeServiceImpl; + } + /** * 记录支付日志:微信支付 * @param plainText @@ -152,7 +160,7 @@ public class PaymentInfoServiceImpl extends ServiceImpl qw = new QueryWrapper<>(); qw.eq("transaction_id", invoiceId); PaymentInfo paymentInfo = baseMapper.selectOne(qw); + String status = invoice.getStatus(); // 判断当前支付是否已经被记录,确保同一个支付不会被重复记录 if (Objects.isNull(paymentInfo)){ String orderNo; @@ -199,13 +208,19 @@ public class PaymentInfoServiceImpl extends ServiceImpl paymentMethod = stripeServiceImpl.getPaymentMethodByInvoiceId(invoiceId); paymentInfo = new PaymentInfo(); paymentInfo.setOrderNo(orderNo); @@ -219,12 +234,84 @@ public class PaymentInfoServiceImpl extends ServiceImpl qw = new QueryWrapper<>(); + qw.eq("transaction_id", charge.getInvoice()); + PaymentInfo paymentInfo = baseMapper.selectOne(qw); + Charge.PaymentMethodDetails paymentMethodDetails = charge.getPaymentMethodDetails(); + String paymentMethod; + String last4 = "N/A"; + switch (paymentMethodDetails.getType()){ + case "alipay": + paymentMethod = "Alipay"; + break; + case "bancontact": + paymentMethod = "BanContact"; + break; + case "card": + Charge.PaymentMethodDetails.Card card = paymentMethodDetails.getCard(); + String brand = card.getBrand(); + brand = brand.substring(0, 1).toUpperCase() + brand.substring(1); + paymentMethod = brand + " " + card.getFunding() + "card"; + last4 = card.getLast4(); + break; + case "eps": + Charge.PaymentMethodDetails.Eps eps = paymentMethodDetails.getEps(); + paymentMethod = eps.getBank(); + break; + case "giropay": + paymentMethod = "GiroPay"; + break; + case "ideal": + Charge.PaymentMethodDetails.Ideal ideal = paymentMethodDetails.getIdeal(); + paymentMethod = ideal.getBank(); + break; + case "link": + paymentMethod = "Link"; + break; + default: + paymentMethod = "N/A"; + } + if (Objects.isNull(paymentInfo)){ + Stripe.apiKey = privateKey; + + Float divide = new BigDecimal(charge.getAmount()).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP).floatValue(); + paymentInfo = new PaymentInfo(); + paymentInfo.setOrderNo(charge.getDescription().replace("AiDA - ", "")); + paymentInfo.setTransactionId(charge.getInvoice()); + paymentInfo.setPaymentType(PayTypeEnum.STRIPE.getType()); + paymentInfo.setTradeState(charge.getStatus()); + paymentInfo.setPayerTotal(divide); + paymentInfo.setNotified(0); + paymentInfo.setPaymentMethod(paymentMethod); + paymentInfo.setLast4(last4); + paymentInfo.setCreateTime(LocalDateTime.now()); + baseMapper.insert(paymentInfo); + }else { + paymentInfo.setTradeState(charge.getStatus()); + paymentInfo.setPaymentMethod(paymentMethod); + paymentInfo.setLast4(last4); + paymentInfo.setUpdateTime(LocalDateTime.now()); + baseMapper.updateById(paymentInfo); + } + + return paymentInfo; + } + @Override public PaymentInfo getPaymentInfoByOrderId(String orderId){ diff --git a/src/main/java/com/ai/da/service/impl/StripeServiceImpl.java b/src/main/java/com/ai/da/service/impl/StripeServiceImpl.java index fe903590..dba20370 100644 --- a/src/main/java/com/ai/da/service/impl/StripeServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/StripeServiceImpl.java @@ -271,6 +271,10 @@ public class StripeServiceImpl implements StripeService { Session session = (Session) stripeObject; if (event.getType().equals("checkout.session.completed")) { processOrder(session); + }else if (event.getType().equals("checkout.session.expired")){ + String orderNo = session.getMetadata().get("orderId"); + // 会话过期 未支付 且之后没有支付成功的订单 + processExpiredOrder(orderNo); } } else if (stripeObject instanceof Subscription){ Subscription subscription = (Subscription) stripeObject; @@ -280,25 +284,30 @@ public class StripeServiceImpl implements StripeService { log.info("创建连续订阅"); } else if (event.getType().equals("customer.subscription.updated")){ // 更新订阅信息 - response = updateSubscription(subscription); + updateSubscription(subscription); log.info("订阅更新"); if (subscription.getStatus().equals("active")){ response = sendEmail(subscription.getId(), null); } } else if (event.getType().equals("customer.subscription.deleted")){ - response = updateSubscription(subscription); + SubscriptionInfo subscriptionInfo = updateSubscription(subscription); log.info("用户取消连续订阅"); - } else if (event.getType().equals("customer.subscription.paused")){ + if (subscriptionInfo.getCancelNotified() == (byte)0){ + response = sendEmail(subscription.getId(), "cancel"); + } + subscriptionInfo.setCancelNotified((byte)1); + subscriptionInfoMapper.updateById(subscriptionInfo); + }/* else if (event.getType().equals("customer.subscription.paused")){ updateSubscription(subscription); } else if (event.getType().equals("customer.subscription.resumed")){ updateSubscription(subscription); log.info("用户订阅恢复"); - } + }*/ } else if (stripeObject instanceof Invoice) { Invoice invoice = (Invoice) stripeObject; if (event.getType().equals("invoice.paid")) { // 新增支付成功的信息,返回orderNo,表示,该回调第一次被记录 - PaymentInfo paymentInfo = paymentInfoService.createPaymentInfoForStripe(invoice); + PaymentInfo paymentInfo = paymentInfoService.createOrUpdatePaymentInfoForStripe(invoice); // 当前支付没有被通知时才需要发送通知邮件 if (paymentInfo.getNotified().equals(0)) { @@ -311,6 +320,43 @@ public class StripeServiceImpl implements StripeService { response = sendEmail(invoice.getSubscription(), "renewal"); } } + } else if (event.getType().equals("invoice.payment_failed")) { + // 更新支付信息 + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("transaction_id", invoice.getId()); + PaymentInfo paymentInfo = paymentInfoService.getBaseMapper().selectOne(queryWrapper); + if (!Objects.isNull(paymentInfo)){ + String type = invoice.getBillingReason().equals("subscription_create") ? "new" : + invoice.getBillingReason().equals("subscription_cycle") ? "renewal" : invoice.getBillingReason(); + Gson gson = new Gson(); + String json = gson.toJson(invoice); + paymentInfo.setContent(json); + paymentInfo.setType(type); + paymentInfoService.updateById(paymentInfo); + } + /*// 支付失败 通知商家的条件 1、会话过期 2、支付失败 3、这个用户在这个支付失败后再无支付成功的订阅 + if (invoice.getBillingReason().equals("subscription_create")){ + response = sendEmail(paymentInfo.getOrderNo()); + } else if (invoice.getBillingReason().equals("subscription_cycle")){ + response = sendEmail(invoice.getSubscription(), "fail_renewal"); + }*/ + } + }else if (stripeObject instanceof Charge) { + Charge charge = (Charge) stripeObject; + String orderNo = charge.getDescription().replace("AiDA - ", ""); + OrderInfo orderInfo = orderInfoService.getOrderByOrderNo(orderNo); + if (event.getType().equals("charge.failed")){ + // 添加支付信息 && 更新支付信息 + // 支付失败时,无法通过invoice_id获取支付方式,所以使用charge.failed回调添加支付信息 + paymentInfoService.createOrUpdatePaymentInfoForStripe(charge); + + orderInfo.setOrderStatus(OrderStatusEnum.FAILURE.getType()); + orderInfo.setNote(charge.getFailureMessage()); + orderInfoService.updateById(orderInfo); + }else if (event.getType().equals("charge.succeeded")){ + orderInfo.setOrderStatus(OrderStatusEnum.SUCCESS.getType()); + orderInfo.setNote(""); + orderInfoService.updateById(orderInfo); } } return response; @@ -351,6 +397,36 @@ public class StripeServiceImpl implements StripeService { } } + private void processExpiredOrder(String orderNo) { + // 支付失败 通知商家的条件 1、会话过期 2、支付失败 3、这个用户在这个支付失败后再无支付成功的订阅 + // 1、获取当前订单的支付状态 +// String orderNo = session.getMetadata().get("orderId"); + OrderInfo orderByOrderNo = orderInfoService.getOrderByOrderNo(orderNo); + // 2、确认订单状态为支付失败 + if (orderByOrderNo.getOrderStatus().equals(OrderStatusEnum.FAILURE.getType())) { + // 3、判断失败订单之后再无成功的订单 + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("account_id", orderByOrderNo.getAccountId()); + queryWrapper.gt("create_time", orderByOrderNo.getCreateTime()); + queryWrapper.eq("order_status", OrderStatusEnum.SUCCESS.getType()); + queryWrapper.likeLeft("title", "Subscription"); + List orderInfos = orderInfoService.getBaseMapper().selectList(queryWrapper); + if (orderInfos.isEmpty()) { + // 4、判断当前订单有没有订阅信息 + QueryWrapper qw = new QueryWrapper<>(); + qw.eq("order_no", orderNo); + SubscriptionInfo subscriptionInfo = subscriptionInfoMapper.selectOne(qw); + // 发送邮件通知商家用户支付失败 + if (Objects.isNull(subscriptionInfo) || subscriptionInfo.getStatus().equals("incomplete")) { + sendEmail(orderNo); + }else { + sendEmail(subscriptionInfo.getSubscriptionId(), "fail_renewal"); + } + } + } + + } + @Transactional(rollbackFor = Exception.class) public SubscriptionInfo createSubscription(Subscription subscription){ // 确认当前subscription是否已经记录 @@ -366,7 +442,6 @@ public class StripeServiceImpl implements StripeService { // 从回调信息中获取recurring type SubscriptionItem subscriptionItem = subscription.getItems().getData().get(0); String interval = subscriptionItem.getPrice().getRecurring().getInterval(); - Map paymentMethod = getPaymentMethodByInvoiceId(subscription.getLatestInvoice()); subscriptionInfo = new SubscriptionInfo(); subscriptionInfo.setAccountId(orderInfo.getAccountId()); @@ -374,8 +449,6 @@ public class StripeServiceImpl implements StripeService { subscriptionInfo.setSubscriptionId(subscription.getId()); subscriptionInfo.setType(interval); subscriptionInfo.setStatus(subscription.getStatus()); - subscriptionInfo.setPaymentMethod(paymentMethod.get("paymentMethod")); - subscriptionInfo.setLast4(paymentMethod.get("last4")); subscriptionInfo.setNextPayDate(changeTimeStampFormat(subscription.getCurrentPeriodEnd(), "seconds", CommonConstant.TIME_FORMAT_MMM_dd_yyyy_EEEE)); subscriptionInfo.setCurrentPeriodStart(subscription.getCurrentPeriodStart()); subscriptionInfo.setCurrentPeriodEnd(subscription.getCurrentPeriodEnd()); @@ -406,7 +479,7 @@ public class StripeServiceImpl implements StripeService { } @Transactional(rollbackFor = Exception.class) - public Boolean updateSubscription(Subscription subscription){ + public SubscriptionInfo updateSubscription(Subscription subscription){ // 获取当前是否有已经记录的subscriptionInfo SubscriptionInfo subscriptionInfo = createSubscription(subscription); // 用于标志数据有没有变动,避免在没有改动的情况下频繁的更新数据库 @@ -415,9 +488,6 @@ public class StripeServiceImpl implements StripeService { subscriptionInfo.setStatus(subscription.getStatus()); flag = true; } - if (subscription.getStatus().equals("canceled")){ - subscriptionInfo.setAutoRenewal((byte) 0); - } if (!subscriptionInfo.getCurrentPeriodStart().equals(subscription.getCurrentPeriodStart())){ subscriptionInfo.setCurrentPeriodStart(subscription.getCurrentPeriodStart()); flag = true; @@ -432,10 +502,9 @@ public class StripeServiceImpl implements StripeService { } if (flag){ subscriptionInfo.setUpdateTime(LocalDateTime.now()); - // todo 这里需要再检查支付方式吗? subscriptionInfoMapper.updateById(subscriptionInfo); } - return true; + return subscriptionInfo; } private void updateAccountValidity(Long accountId, Long currentPeriodEnd){ @@ -633,6 +702,7 @@ public class StripeServiceImpl implements StripeService { switch (retrieve.getType()){ case "alipay": paymentMethod = "Alipay"; + last4 = "N/A"; break; case "bancontact": paymentMethod = "BanContact"; @@ -647,17 +717,24 @@ public class StripeServiceImpl implements StripeService { case "eps": PaymentMethod.Eps eps = retrieve.getEps(); paymentMethod = eps.getBank(); + last4 = "N/A"; break; case "giropay": paymentMethod = "GiroPay"; + last4 = "N/A"; break; case "ideal": PaymentMethod.Ideal ideal = retrieve.getIdeal(); paymentMethod = ideal.getBank(); + last4 = "N/A"; break; case "link": paymentMethod = "Link"; + last4 = "N/A"; break; + default: + paymentMethod = "N/A"; + last4 = "N/A"; } HashMap resp = new HashMap<>(); resp.put("paymentMethod", paymentMethod); @@ -669,7 +746,7 @@ public class StripeServiceImpl implements StripeService { // return null; } - public boolean sendEmail(String subscriptionId, String type){ + public boolean sendEmail(String subscriptionId, String type) { SubscriptionEmailParamsDTO emailParamsDTO = new SubscriptionEmailParamsDTO(); QueryWrapper qwSI = new QueryWrapper<>(); @@ -688,9 +765,9 @@ public class StripeServiceImpl implements StripeService { if (StringUtil.isNullOrEmpty(type)){ // 如果没有传入type,则使用paymentInfo中记录的类型 // (其实这里也可以通过invoiceId查询stripe,但是记录在自己的db中可以不用每次都查,且方便查看) - type = paymentInfo.getType(); + type = StringUtil.isNullOrEmpty(paymentInfo.getType()) ? "new" : paymentInfo.getType(); } - if (!type.equals("reminder") && paymentInfo.getNotified() == 1){ + if (!type.equals("reminder") && !type.equals("cancel") && paymentInfo.getNotified() == 1){ // 已经邮件通知过,直接返回 return true; } @@ -707,8 +784,10 @@ public class StripeServiceImpl implements StripeService { emailParamsDTO.setTotalFee(paymentInfo.getPayerTotal().toString()); emailParamsDTO.setLastOrderDate(changeTimeStampFormat(subscriptionInfo.getCurrentPeriodStart(), "seconds", CommonConstant.TIME_FORMAT_MMM_dd_yyyy)); emailParamsDTO.setEndOfPrepaidTerm(changeTimeStampFormat(subscriptionInfo.getCurrentPeriodEnd(), "seconds", CommonConstant.TIME_FORMAT_MMM_dd_yyyy)); - emailParamsDTO.setPaymentMethod(subscriptionInfo.getPaymentMethod()); + emailParamsDTO.setPaymentMethod(paymentInfo.getPaymentMethod()); + emailParamsDTO.setLast4(paymentInfo.getLast4()); emailParamsDTO.setSubscriptionId(subscriptionInfo.getId().toString()); + emailParamsDTO.setFailMessage(orderByOrderNo.getNote()); emailParamsDTO.setSubscriptionType(subscriptionInfo.getType()); emailParamsDTO.setStartDate(changeTimeStampFormat(orderByOrderNo.getCreateTime())); emailParamsDTO.setNextPayDate(changeTimeStampFormat(subscriptionInfo.getCurrentPeriodEnd(), "seconds", CommonConstant.TIME_FORMAT_MMM_dd_yyyy)); @@ -717,7 +796,7 @@ public class StripeServiceImpl implements StripeService { SendEmailUtil.subscriptionEmailReminder(type, emailParamsDTO, language, account.getUserEmail()); // 邮件通知成功后,更新标志 - if (!type.equals("reminder")){ + if (!type.equals("reminder") && !type.equals("cancel")){ PaymentInfo payment = new PaymentInfo(); payment.setId(paymentInfo.getId()); payment.setNotified(1); @@ -727,6 +806,40 @@ public class StripeServiceImpl implements StripeService { return true; } + public boolean sendEmail(String orderNo){ + SubscriptionEmailParamsDTO emailParamsDTO = new SubscriptionEmailParamsDTO(); + OrderInfo orderInfo = orderInfoService.getOrderByOrderNo(orderNo); + + com.ai.da.mapper.primary.entity.Account account = accountMapper.selectById(orderInfo.getAccountId()); + String userName = account.getUserName(); + String language = account.getLanguage(); + QueryWrapper qwPI = new QueryWrapper<>(); + qwPI.eq("order_no", orderNo); + List paymentInfos = paymentInfoMapper.selectList(qwPI); + if (paymentInfos.isEmpty()) { + return false; + } + PaymentInfo paymentInfo = paymentInfos.get(0); + emailParamsDTO.setUsername(userName); + emailParamsDTO.setOrderId(paymentInfo.getId().toString()); + emailParamsDTO.setCreateDate(String.valueOf(paymentInfo.getCreateTime()).replace("T", " ")); + emailParamsDTO.setQuantity(String.valueOf(1)); + emailParamsDTO.setTotalFee(paymentInfo.getPayerTotal().toString()); + emailParamsDTO.setFailMessage(orderInfo.getNote()); + emailParamsDTO.setPaymentMethod(paymentInfo.getPaymentMethod()); + emailParamsDTO.setLast4(paymentInfo.getLast4()); + + SendEmailUtil.subscriptionEmailReminder("fail_new", emailParamsDTO, language, account.getUserEmail()); + + // 邮件通知成功后,更新标志 + PaymentInfo payment = new PaymentInfo(); + payment.setId(paymentInfo.getId()); + payment.setNotified(1); + payment.setUpdateTime(LocalDateTime.now()); + paymentInfoMapper.updateById(payment); + return true; + } + public void subscriptionReminder(){ // 提前7天的 00:00:00 和 23:59:59 LocalDateTime startOfDay = LocalDateTime.now().plusDays(7).toLocalDate().atStartOfDay(); From 1b15aed6a28801b2a6f8f433f01678d7d19ca35a Mon Sep 17 00:00:00 2001 From: xupei Date: Thu, 28 Nov 2024 10:43:06 +0800 Subject: [PATCH 07/91] =?UTF-8?q?=E6=94=AF=E4=BB=98=E4=BC=98=E5=8C=96-?= =?UTF-8?q?=E7=BB=AD=E8=AE=A2=E5=A4=B1=E8=B4=A5=E9=82=AE=E4=BB=B6=E9=80=9A?= =?UTF-8?q?=E7=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ai/da/common/enums/OrderStatusEnum.java | 9 - .../com/ai/da/common/utils/SendEmailUtil.java | 12 +- .../ai/da/controller/StripeController.java | 42 +++- .../da/mapper/primary/entity/PaymentInfo.java | 3 + .../ai/da/model/dto/ProductPurchaseDTO.java | 2 - .../model/dto/SubscriptionEmailParamsDTO.java | 2 + .../java/com/ai/da/service/StripeService.java | 10 +- .../service/impl/PaymentInfoServiceImpl.java | 1 + .../ai/da/service/impl/StripeServiceImpl.java | 230 ++++++++++++++++-- 9 files changed, 269 insertions(+), 42 deletions(-) diff --git a/src/main/java/com/ai/da/common/enums/OrderStatusEnum.java b/src/main/java/com/ai/da/common/enums/OrderStatusEnum.java index 8f8699a6..02767686 100644 --- a/src/main/java/com/ai/da/common/enums/OrderStatusEnum.java +++ b/src/main/java/com/ai/da/common/enums/OrderStatusEnum.java @@ -10,43 +10,34 @@ public enum OrderStatusEnum { * 未支付 */ NOT_PAY("未支付"), - - /** * 支付成功 */ SUCCESS("支付成功"), - /** * 支付失败 */ FAILURE("支付失败"), - /** * 已关闭 */ TIMEOUT_CLOSED("超时已关闭"), - /** * 已取消 */ CANCEL("用户已取消"), - /** * 退款中 */ REFUND_PROCESSING("退款中"), - /** * 已退款 */ REFUND_SUCCESS("已退款"), - /** * 退款异常 */ REFUND_ABNORMAL("退款异常"), - /** * paypal订单状态为 APPROVED */ diff --git a/src/main/java/com/ai/da/common/utils/SendEmailUtil.java b/src/main/java/com/ai/da/common/utils/SendEmailUtil.java index c6d61e68..b14cd28a 100644 --- a/src/main/java/com/ai/da/common/utils/SendEmailUtil.java +++ b/src/main/java/com/ai/da/common/utils/SendEmailUtil.java @@ -781,6 +781,8 @@ public class SendEmailUtil { private final static Long RENEWAL_REMINDER_USER_CN = 130728L; private final static Long PAYMENT_FAILED_NEW_MERCHANT_EN = 131230L; private final static Long PAYMENT_FAILED_RENEWAL_MERCHANT_EN = 131225L; + private final static Long PAYMENT_FAILED_RENEWAL_USER_EN = 131563L; + private final static Long PAYMENT_FAILED_RENEWAL_USER_CN = 131564L; public static void subscriptionEmailReminder(String type, SubscriptionEmailParamsDTO subscriptionEmailParamsDTO, String language, String receiverAddress){ try{ @@ -816,6 +818,14 @@ public class SendEmailUtil { case "fail_renewal": merchant.setSubject("[Code-Create] Payment Failed : Renewal Order (" + subscriptionEmailParamsDTO.getOrderId() + ")"); templateMerchant.setTemplateID(PAYMENT_FAILED_RENEWAL_MERCHANT_EN); + // todo to user + if (language.equals("ENGLISH")){ + user.setSubject("[Code-Create] Payment Failed : Renewal Order (" + subscriptionEmailParamsDTO.getOrderId() + ")"); + templateUser.setTemplateID(PAYMENT_FAILED_RENEWAL_USER_EN); + }else { + user.setSubject("[Code-Create] 自动续费失败 (" + subscriptionEmailParamsDTO.getOrderId() + ")"); + templateUser.setTemplateID(PAYMENT_FAILED_RENEWAL_USER_CN); + } break; case "new": merchant.setSubject("[Code-Create] New Order(" + subscriptionEmailParamsDTO.getOrderId() + ")"); @@ -859,7 +869,7 @@ public class SendEmailUtil { templateMerchant.setTemplateData(JSON.toJSONString(subscriptionEmailParamsDTO)); merchant.setTemplate(templateMerchant); - if (!type.equals("cancel") && !type.equals("fail_new") && !type.equals("fail_renewal") ){ + if (!type.equals("cancel") && !type.equals("fail_new") ){ // 返回的resp是一个SendEmailResponse的实例,与请求对象对应 SendEmailResponse respUser = client.SendEmail(user); log.info("邮件主题:{},发送结果toUser###{}", user.getSubject(), SendEmailResponse.toJsonString(respUser)); diff --git a/src/main/java/com/ai/da/controller/StripeController.java b/src/main/java/com/ai/da/controller/StripeController.java index eac49851..8becf26b 100644 --- a/src/main/java/com/ai/da/controller/StripeController.java +++ b/src/main/java/com/ai/da/controller/StripeController.java @@ -9,19 +9,22 @@ import com.stripe.exception.StripeException; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import lombok.extern.slf4j.Slf4j; -import org.simpleframework.xml.core.Validate; import org.springframework.web.bind.annotation.*; +import springfox.documentation.annotations.ApiIgnore; import javax.annotation.Resource; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; import java.io.IOException; +import java.util.List; @Api(tags = "Stripe模块") @Slf4j @RestController @RequestMapping("/api/stripe") +@ApiIgnore public class StripeController { @Resource @@ -29,7 +32,7 @@ public class StripeController { @ApiOperation("创建支付链接") @PostMapping("/createOrder") - public Response pay(@Validate @RequestBody ProductPurchaseDTO productPurchaseDTO) { + public Response pay(@Valid @RequestBody ProductPurchaseDTO productPurchaseDTO) { return Response.success(stripeService.pay(productPurchaseDTO)); } @@ -45,7 +48,7 @@ public class StripeController { } @ApiOperation("申请退款") - @PostMapping("/trade/refund/{orderNo}/{reason}") + @GetMapping("/trade/refund/{orderNo}/{reason}") public Response> refund(@PathVariable String orderNo, @PathVariable String reason) throws IOException { String response = stripeService.refund(null,orderNo,reason); if (response.equals("退款成功")){ @@ -56,19 +59,44 @@ public class StripeController { } @ApiOperation("获取订阅") - @PostMapping("/getSubscription") - public void getSubscription() { + @GetMapping("/getSubscription") + public Response> getSubscription(@RequestParam String name, @RequestParam String email) { try { - stripeService.getSubscription("xp", "xupei3360@163.com"); + return Response.success(stripeService.getSubscriptionIds(name, email)); } catch (StripeException e) { throw new RuntimeException(e); } } @ApiOperation("取消订阅") - @PostMapping("/cancelSubscription") + @GetMapping("/cancelSubscription") public Response cancelSubscription(@RequestParam String subscriptionId) { stripeService.cancelSubscription(subscriptionId); return Response.success("success"); } + @ApiOperation("临时 取消订阅") + @GetMapping("/cancelSubscriptionTemp") + public Response cancelSubscriptionTemp(@RequestParam String subscriptionId) { + stripeService.cancelSubscriptionTemp(subscriptionId); + return Response.success("success"); + } + + @ApiOperation("创建订阅 临时") + @GetMapping("/createSubscriptionTemp") + public Response createSubscriptionTemp(@RequestParam String name, @RequestParam String email) { + return Response.success(stripeService.createSubscriptionTemp(name, email)); + } + + @ApiOperation("修改用户默认支付方式 临时") + @GetMapping("/changeCustomerPayment") + public Response changeCustomerPayment(@RequestParam String name, @RequestParam String email) { + return Response.success(stripeService.changeCustomerPayment(name, email)); + } + + @ApiOperation("临时 发送续订失败邮件") + @GetMapping("/sendRenewalFailEmail") + public Response sendRenewalFailEmail(@RequestParam String invoiceId, @RequestParam String subscriptionId, @RequestParam String orderNo) { + return Response.success(stripeService.sendRenewalFailEmail(invoiceId, subscriptionId,orderNo)); + } + } diff --git a/src/main/java/com/ai/da/mapper/primary/entity/PaymentInfo.java b/src/main/java/com/ai/da/mapper/primary/entity/PaymentInfo.java index 8172f4bd..d3533078 100644 --- a/src/main/java/com/ai/da/mapper/primary/entity/PaymentInfo.java +++ b/src/main/java/com/ai/da/mapper/primary/entity/PaymentInfo.java @@ -30,4 +30,7 @@ public class PaymentInfo extends BaseEntity{ private String paymentMethod; private String last4; + + // 发票托管页面 + private String hostedInvoiceUrl; } diff --git a/src/main/java/com/ai/da/model/dto/ProductPurchaseDTO.java b/src/main/java/com/ai/da/model/dto/ProductPurchaseDTO.java index ce1fb595..0e386e8a 100644 --- a/src/main/java/com/ai/da/model/dto/ProductPurchaseDTO.java +++ b/src/main/java/com/ai/da/model/dto/ProductPurchaseDTO.java @@ -27,6 +27,4 @@ public class ProductPurchaseDTO { @ApiModelProperty("是否自动续订 one_time || recurring") private Boolean autoRenewal; - - private String refId; } diff --git a/src/main/java/com/ai/da/model/dto/SubscriptionEmailParamsDTO.java b/src/main/java/com/ai/da/model/dto/SubscriptionEmailParamsDTO.java index 9ecf0241..1f35b705 100644 --- a/src/main/java/com/ai/da/model/dto/SubscriptionEmailParamsDTO.java +++ b/src/main/java/com/ai/da/model/dto/SubscriptionEmailParamsDTO.java @@ -48,5 +48,7 @@ public class SubscriptionEmailParamsDTO { // 付款失败原因 private String failMessage; + private String accountPageRef; + } diff --git a/src/main/java/com/ai/da/service/StripeService.java b/src/main/java/com/ai/da/service/StripeService.java index b517b325..268f08d2 100644 --- a/src/main/java/com/ai/da/service/StripeService.java +++ b/src/main/java/com/ai/da/service/StripeService.java @@ -2,7 +2,6 @@ package com.ai.da.service; import com.ai.da.model.dto.ProductPurchaseDTO; import com.stripe.exception.StripeException; -import com.stripe.model.Subscription; import javax.servlet.http.HttpServletRequest; import java.util.List; @@ -18,10 +17,12 @@ public interface StripeService { void checkOrderStatus(String orderNo); - List getSubscription(String name, String userEmail) throws StripeException; + List getSubscriptionIds(String name, String userEmail) throws StripeException; void cancelSubscription(String orderNo); + void cancelSubscriptionTemp(String subscriptionId); + Map getPaymentMethod(String paymentMethodId); /*void updateSubscription(String subscriptionId); @@ -32,4 +33,9 @@ public interface StripeService { void checkSubscriptionExpiration(); + String createSubscriptionTemp(String name, String email); + + String changeCustomerPayment(String name, String email); + + boolean sendRenewalFailEmail(String invoiceId, String subscriptionId, String orderNo); } diff --git a/src/main/java/com/ai/da/service/impl/PaymentInfoServiceImpl.java b/src/main/java/com/ai/da/service/impl/PaymentInfoServiceImpl.java index 204a9ce4..3459bf93 100644 --- a/src/main/java/com/ai/da/service/impl/PaymentInfoServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/PaymentInfoServiceImpl.java @@ -236,6 +236,7 @@ public class PaymentInfoServiceImpl extends ServiceImpl getSubscription(String username, String userEmail) { Stripe.apiKey = privateKey; String customerId = null; @@ -642,6 +663,25 @@ public class StripeServiceImpl implements StripeService { } catch (StripeException e) { throw new RuntimeException(e); } + } + + // 获取所有订阅 + public List getSubscriptionIds(String username, String userEmail) { + Stripe.apiKey = privateKey; + String customerId = null; + try { + customerId = getCustomer(username, userEmail); + SubscriptionCollection list = Subscription.list(SubscriptionListParams.builder() + .setCustomer(customerId).build()); + List data = list.getData(); + ArrayList subscriptionIds = new ArrayList<>(); + data.forEach(subscription -> { + subscriptionIds.add(subscription.getId()); + }); + return subscriptionIds; + } catch (StripeException e) { + throw new RuntimeException(e); + } } @@ -747,7 +787,6 @@ public class StripeServiceImpl implements StripeService { } public boolean sendEmail(String subscriptionId, String type) { - SubscriptionEmailParamsDTO emailParamsDTO = new SubscriptionEmailParamsDTO(); QueryWrapper qwSI = new QueryWrapper<>(); qwSI.eq("subscription_id", subscriptionId); @@ -784,14 +823,7 @@ public class StripeServiceImpl implements StripeService { emailParamsDTO.setTotalFee(paymentInfo.getPayerTotal().toString()); emailParamsDTO.setLastOrderDate(changeTimeStampFormat(subscriptionInfo.getCurrentPeriodStart(), "seconds", CommonConstant.TIME_FORMAT_MMM_dd_yyyy)); emailParamsDTO.setEndOfPrepaidTerm(changeTimeStampFormat(subscriptionInfo.getCurrentPeriodEnd(), "seconds", CommonConstant.TIME_FORMAT_MMM_dd_yyyy)); - emailParamsDTO.setPaymentMethod(paymentInfo.getPaymentMethod()); - emailParamsDTO.setLast4(paymentInfo.getLast4()); - emailParamsDTO.setSubscriptionId(subscriptionInfo.getId().toString()); - emailParamsDTO.setFailMessage(orderByOrderNo.getNote()); - emailParamsDTO.setSubscriptionType(subscriptionInfo.getType()); - emailParamsDTO.setStartDate(changeTimeStampFormat(orderByOrderNo.getCreateTime())); - emailParamsDTO.setNextPayDate(changeTimeStampFormat(subscriptionInfo.getCurrentPeriodEnd(), "seconds", CommonConstant.TIME_FORMAT_MMM_dd_yyyy)); - emailParamsDTO.setRenewalTime(changeTimeStampFormat(subscriptionInfo.getCurrentPeriodEnd(), "seconds", CommonConstant.TIME_FORMAT_MMM_dd_yyyy)); + setSubscriptionParams(paymentInfo, subscriptionInfo, orderByOrderNo, emailParamsDTO); SendEmailUtil.subscriptionEmailReminder(type, emailParamsDTO, language, account.getUserEmail()); @@ -840,6 +872,79 @@ public class StripeServiceImpl implements StripeService { return true; } + public boolean sendRenewalFailEmail(String invoiceId, String subscriptionId, String orderNo){ + // 1、确认当前订单最后一笔支付为fail + // 更新支付信息 + PaymentInfo paymentInfo; + QueryWrapper queryWrapper = new QueryWrapper<>(); + if (StringUtil.isNullOrEmpty(invoiceId)){ + queryWrapper.eq("order_no", orderNo).orderByDesc("id"); + List paymentInfos = paymentInfoService.getBaseMapper().selectList(queryWrapper); + if (paymentInfos.isEmpty() || !paymentInfos.get(0).getTradeState().equals("failed")){ + return false; + }else { + paymentInfo = paymentInfos.get(0); + } + }else { + queryWrapper.eq("transaction_id", invoiceId); + paymentInfo = paymentInfoService.getBaseMapper().selectOne(queryWrapper); + if (Objects.isNull(paymentInfo) + || !paymentInfo.getTradeState().equals("failed") + || paymentInfo.getNotified().equals(1)){ + return false; + } + } + + // 2、确认当前订阅的状态为past_due + SubscriptionInfo subscriptionInfo; + QueryWrapper qwSI = new QueryWrapper<>(); + if (StringUtil.isNullOrEmpty(subscriptionId)){ + qwSI.eq("order_no", orderNo); + }else { + qwSI.eq("subscription_id", subscriptionId); + } + subscriptionInfo = subscriptionInfoMapper.selectOne(qwSI); + if (Objects.isNull(subscriptionInfo) || !subscriptionInfo.getStatus().equals("past_due")){ + return false; + } + + // 3、组参数 + com.ai.da.mapper.primary.entity.Account account = accountMapper.selectById(subscriptionInfo.getAccountId()); + String userName = account.getUserName(); + String language = account.getLanguage(); + OrderInfo orderByOrderNo = orderInfoService.getOrderByOrderNo(subscriptionInfo.getOrderNo()); + SubscriptionEmailParamsDTO emailParamsDTO = new SubscriptionEmailParamsDTO(); + emailParamsDTO.setUsername(userName); + emailParamsDTO.setOrderId(paymentInfo.getId().toString()); + emailParamsDTO.setCreateDate(String.valueOf(paymentInfo.getCreateTime()).replace("T", " ")); + emailParamsDTO.setQuantity(String.valueOf(1)); + emailParamsDTO.setTotalFee(paymentInfo.getPayerTotal().toString()); + setSubscriptionParams(paymentInfo, subscriptionInfo, orderByOrderNo, emailParamsDTO); + // todo + emailParamsDTO.setAccountPageRef("\"https://www.aida.com.hk/home/homePage\""); + + // 4、发邮件 + SendEmailUtil.subscriptionEmailReminder("fail_renewal", emailParamsDTO, language, account.getUserEmail()); + + PaymentInfo payment = new PaymentInfo(); + payment.setId(paymentInfo.getId()); + payment.setNotified(1); + payment.setUpdateTime(LocalDateTime.now()); + paymentInfoMapper.updateById(payment); + return true; + } + + private void setSubscriptionParams(PaymentInfo paymentInfo, SubscriptionInfo subscriptionInfo, OrderInfo orderByOrderNo, SubscriptionEmailParamsDTO emailParamsDTO) { + emailParamsDTO.setPaymentMethod(paymentInfo.getPaymentMethod()); + emailParamsDTO.setLast4(paymentInfo.getLast4()); + emailParamsDTO.setSubscriptionId(subscriptionInfo.getId().toString()); + emailParamsDTO.setFailMessage(orderByOrderNo.getNote()); + emailParamsDTO.setSubscriptionType(subscriptionInfo.getType()); + emailParamsDTO.setStartDate(changeTimeStampFormat(orderByOrderNo.getCreateTime())); + emailParamsDTO.setNextPayDate(changeTimeStampFormat(subscriptionInfo.getCurrentPeriodEnd(), "seconds", CommonConstant.TIME_FORMAT_MMM_dd_yyyy)); + emailParamsDTO.setRenewalTime(changeTimeStampFormat(subscriptionInfo.getCurrentPeriodEnd(), "seconds", CommonConstant.TIME_FORMAT_MMM_dd_yyyy)); + } + public void subscriptionReminder(){ // 提前7天的 00:00:00 和 23:59:59 LocalDateTime startOfDay = LocalDateTime.now().plusDays(7).toLocalDate().atStartOfDay(); @@ -876,4 +981,87 @@ public class StripeServiceImpl implements StripeService { } } + // todo 新建一个订阅 使用不会成功的付款方式 + + public String createSubscriptionTemp(String name, String email){ + Stripe.apiKey = privateKey; + try { + OrderInfo orderInfo = orderInfoService.createOrderByProductId(1, PayTypeEnum.STRIPE.getType(), ProductEnum.DailySubscription); + + String paymentMethodCode = "pm_card_mastercard"; + PaymentMethod paymentMethod = PaymentMethod.retrieve(paymentMethodCode); + + String customerId = getCustomer(name, email); + log.info("customerId: {}", customerId); + + PaymentMethodAttachParams attachParams = PaymentMethodAttachParams.builder() + .setCustomer(customerId) + .build(); + paymentMethod.attach(attachParams); + + // 设置默认付款方式 + Customer updatedCustomer = Customer.retrieve(customerId); + CustomerUpdateParams params = CustomerUpdateParams.builder() + .setInvoiceSettings( + CustomerUpdateParams.InvoiceSettings.builder() + .setDefaultPaymentMethod(paymentMethod.getId()) + .build() + ) + .build(); + updatedCustomer.update(params); + + // 3. 创建订阅 + SubscriptionCreateParams subscriptionParams = SubscriptionCreateParams.builder() + .setCustomer(customerId) + .addItem( + SubscriptionCreateParams.Item.builder() + .setPrice("price_1QFXkf02n1TEydyNtA4TQ3Yz") // 替换为实际的价格 ID + .build() + ) + .setDescription("AiDA - " + orderInfo.getOrderNo()) + .build(); + Subscription subscription = Subscription.create(subscriptionParams); + + // 打印订阅 ID + System.out.println("Subscription created: " + subscription.getId()); + return subscription.getId(); + } catch (StripeException e) { + throw new RuntimeException(e); + } + } + + public String changeCustomerPayment(String name, String email){ + Stripe.apiKey = privateKey; + String paymentMethodCode = "pm_card_chargeCustomerFail"; + try { + PaymentMethod paymentMethod = PaymentMethod.retrieve(paymentMethodCode); + + String customerId = getCustomer(name, email); + log.info("customerId: {}", customerId); + + // 附加支付方式到客户 + PaymentMethodAttachParams attachParams = PaymentMethodAttachParams.builder() + .setCustomer(customerId) + .build(); + paymentMethod.attach(attachParams); + // 更新客户的默认支付方式 + CustomerUpdateParams params = CustomerUpdateParams.builder() + .setInvoiceSettings( + CustomerUpdateParams.InvoiceSettings.builder() + .setDefaultPaymentMethod(paymentMethod.getId()) + .build() + ) + .build(); + + // 更新客户信息 + Customer customer = Customer.retrieve(customerId); + customer.update(params); + + return paymentMethod.getId(); + + } catch (StripeException e) { + throw new RuntimeException(e); + } + } + } From 1c965224474f95e8a7d3efabd7f5a1f666c79a10 Mon Sep 17 00:00:00 2001 From: shahaibo <1023316923@qq.com> Date: Mon, 9 Dec 2024 13:31:30 +0800 Subject: [PATCH 08/91] TASK:AiDA --- .../security/filter/AuthenticationFilter.java | 2 +- .../ai/da/controller/AccountController.java | 6 + .../ai/da/controller/DesignController.java | 16 +- .../controller/SavedCollectionController.java | 6 + .../da/controller/ThirdPartyController.java | 19 +- .../{entity => }/AccountExtendMapper.java | 3 +- .../primary/ProductImageAttributeMapper.java | 7 + .../ai/da/mapper/primary/entity/Account.java | 2 + .../primary/entity/ProductImageAttribute.java | 35 +++ .../secondary/entity/AttributeRetrieval.java | 2 - .../ai/da/model/dto/DesignCollectionDTO.java | 4 + .../model/dto/ProductImageInitializeDTO.java | 10 + .../da/model/dto/ReDesignCollectionDTO.java | 2 +- .../da/model/vo/DesignCollectionItemVO.java | 2 + .../ai/da/model/vo/DesignCollectionVO.java | 2 + .../com/ai/da/model/vo/ValidateElementVO.java | 4 + .../java/com/ai/da/python/PythonService.java | 133 +++++++++- .../ai/da/python/vo/DesignPythonObject.java | 2 + .../ai/da/python/vo/DesignPythonObjects.java | 2 + .../com/ai/da/service/AccountService.java | 6 +- .../java/com/ai/da/service/DesignService.java | 11 +- .../ai/da/service/UserLikeGroupService.java | 3 + .../da/service/impl/AccountServiceImpl.java | 234 ++++++++++++++++- .../impl/CollectionElementServiceImpl.java | 6 + .../ai/da/service/impl/DesignServiceImpl.java | 246 +++++++++++++++++- .../impl/UserLikeGroupServiceImpl.java | 53 ++++ 26 files changed, 778 insertions(+), 40 deletions(-) rename src/main/java/com/ai/da/mapper/primary/{entity => }/AccountExtendMapper.java (74%) create mode 100644 src/main/java/com/ai/da/mapper/primary/ProductImageAttributeMapper.java create mode 100644 src/main/java/com/ai/da/mapper/primary/entity/ProductImageAttribute.java create mode 100644 src/main/java/com/ai/da/model/dto/ProductImageInitializeDTO.java diff --git a/src/main/java/com/ai/da/common/security/filter/AuthenticationFilter.java b/src/main/java/com/ai/da/common/security/filter/AuthenticationFilter.java index 05117ec4..54dbf3a6 100644 --- a/src/main/java/com/ai/da/common/security/filter/AuthenticationFilter.java +++ b/src/main/java/com/ai/da/common/security/filter/AuthenticationFilter.java @@ -51,7 +51,7 @@ public class AuthenticationFilter extends OncePerRequestFilter { "/api/python/flush","/api/account/healthy","/api/ali-pay/trade/notify","/api/paypal/ipn/back","/api/alipay-hk/trade/notify", "/api/portfolio/page", "/api/portfolio/detail", "/api/portfolio/commentPage", "/api/portfolio/viewsIncrease", "/api/account/designWorksRegister","/api/account/questionnaire","/api/stripe/trade/notify", - "/notification","/api/account/activateNewEmail","/api/third/party/auth/google_callback","/api/third/party/parseGoogleCredential" + "/notification","/api/account/activateNewEmail","/api/third/party/auth/google_callback","/api/third/party/parseGoogleCredential","/api/third/party/receiveDesignResults","/api/third/party/parseWeChatCode" ); @Override diff --git a/src/main/java/com/ai/da/controller/AccountController.java b/src/main/java/com/ai/da/controller/AccountController.java index 0332154a..eaecde79 100644 --- a/src/main/java/com/ai/da/controller/AccountController.java +++ b/src/main/java/com/ai/da/controller/AccountController.java @@ -297,4 +297,10 @@ public class AccountController { public Response accountDetail(@RequestParam("id") Long id) { return Response.success(accountService.accountDetail(id)); } + + @PostMapping("getAccountDetail") + @ApiOperation(value = "获取账户信息") + public Response getAccountDetail() { + return Response.success(accountService.getAccountDetail()); + } } diff --git a/src/main/java/com/ai/da/controller/DesignController.java b/src/main/java/com/ai/da/controller/DesignController.java index 2ea463c1..934bcecb 100644 --- a/src/main/java/com/ai/da/controller/DesignController.java +++ b/src/main/java/com/ai/da/controller/DesignController.java @@ -31,7 +31,7 @@ public class DesignController { @ApiOperation(value = "设计 Conllection") @PostMapping("/designCollection") @CrossOrigin - public Response designCollection(@Valid @RequestBody DesignCollectionDTO designDTO) { + public Response designCollection(@Valid @RequestBody DesignCollectionDTO designDTO) { return Response.success(designService.designCollection(designDTO)); } @@ -43,7 +43,7 @@ public class DesignController { @ApiOperation(value = "重新设计 Collection") @PostMapping("/reDesignCollection") - public Response reDesignCollection(@Valid @RequestBody ReDesignCollectionDTO reDesignDTO) { + public Response reDesignCollection(@Valid @RequestBody ReDesignCollectionDTO reDesignDTO) { return Response.success(designService.reDesignCollection(reDesignDTO)); } @@ -83,4 +83,16 @@ public class DesignController { return Response.success(designService.getModel(designItemIdList)); } + @ApiOperation(value = "获取design结果") + @GetMapping("/getDesignResult") + public Response getDesignResult(@RequestParam("requestId") String requestId, @RequestParam("objectSignList") List objectSignList){ + return Response.success(designService.getDesignResult(requestId, objectSignList)); + } + + @ApiOperation(value = "云生成") + @PostMapping("/designCloud") + @CrossOrigin + public Response designCloud(@Valid @RequestBody DesignCollectionDTO designDTO) { + return Response.success(designService.designCloud(designDTO)); + } } diff --git a/src/main/java/com/ai/da/controller/SavedCollectionController.java b/src/main/java/com/ai/da/controller/SavedCollectionController.java index 29cbabac..1204b2c5 100644 --- a/src/main/java/com/ai/da/controller/SavedCollectionController.java +++ b/src/main/java/com/ai/da/controller/SavedCollectionController.java @@ -245,4 +245,10 @@ public class SavedCollectionController { public Response likeHistoryRelSketch() { return Response.success(userLikeGroupService.likeHistoryRelSketch()); } + + @ApiOperation(value = "productImageInitialize") + @PostMapping("/productImageInitialize") + public Response productImageUpload(@Valid @RequestBody ProductImageInitializeDTO productImageInitializeDTO) { + return Response.success(userLikeGroupService.productImageInitialize(productImageInitializeDTO)); + } } diff --git a/src/main/java/com/ai/da/controller/ThirdPartyController.java b/src/main/java/com/ai/da/controller/ThirdPartyController.java index e0047d62..c0ff893f 100644 --- a/src/main/java/com/ai/da/controller/ThirdPartyController.java +++ b/src/main/java/com/ai/da/controller/ThirdPartyController.java @@ -4,7 +4,10 @@ import com.ai.da.common.response.Response; import com.ai.da.mapper.primary.entity.GoogleUser; import com.ai.da.model.dto.*; import com.ai.da.model.vo.AccountLoginVO; +import com.ai.da.model.vo.DesignCollectionVO; import com.ai.da.service.AccountService; +import com.ai.da.service.DesignService; +import com.alibaba.fastjson.JSONObject; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import lombok.extern.slf4j.Slf4j; @@ -29,6 +32,9 @@ public class ThirdPartyController { @Resource private AccountService accountService; + @Resource + private DesignService designService; + /*@ApiOperation(value = "Add user information") @PostMapping("/addUser") public Response addUser(@Valid @RequestBody AccountAddDTO accountAddDTO) { @@ -124,9 +130,20 @@ public class ThirdPartyController { } @CrossOrigin @GetMapping("/parseGoogleCredential") - public Response parseGoogleCredential(@RequestParam("credential") String credential) { + public Response parseGoogleCredential(@RequestParam("credential") String credential) { return Response.success(accountService.parseGoogleCredential(credential)); } + @CrossOrigin + @GetMapping("/parseWeChatCode") + public Response parseWeChatCode(@RequestParam("code") String code) { + return Response.success(accountService.parseWeChatCode(code)); + } + @ApiOperation(value = "接收Design结果") + @PostMapping("/receiveDesignResults") + @CrossOrigin + public Response receiveDesignResults(@Valid @RequestBody JSONObject responseObject) { + return Response.success(designService.receiveDesignResults(responseObject)); + } } diff --git a/src/main/java/com/ai/da/mapper/primary/entity/AccountExtendMapper.java b/src/main/java/com/ai/da/mapper/primary/AccountExtendMapper.java similarity index 74% rename from src/main/java/com/ai/da/mapper/primary/entity/AccountExtendMapper.java rename to src/main/java/com/ai/da/mapper/primary/AccountExtendMapper.java index 312fa810..687790e3 100644 --- a/src/main/java/com/ai/da/mapper/primary/entity/AccountExtendMapper.java +++ b/src/main/java/com/ai/da/mapper/primary/AccountExtendMapper.java @@ -1,6 +1,7 @@ -package com.ai.da.mapper.primary.entity; +package com.ai.da.mapper.primary; import com.ai.da.common.config.mybatis.plus.CommonMapper; +import com.ai.da.mapper.primary.entity.AccountExtend; import java.util.Date; import java.util.List; diff --git a/src/main/java/com/ai/da/mapper/primary/ProductImageAttributeMapper.java b/src/main/java/com/ai/da/mapper/primary/ProductImageAttributeMapper.java new file mode 100644 index 00000000..65d0551a --- /dev/null +++ b/src/main/java/com/ai/da/mapper/primary/ProductImageAttributeMapper.java @@ -0,0 +1,7 @@ +package com.ai.da.mapper.primary; + +import com.ai.da.common.config.mybatis.plus.CommonMapper; +import com.ai.da.mapper.primary.entity.ProductImageAttribute; + +public interface ProductImageAttributeMapper extends CommonMapper { +} diff --git a/src/main/java/com/ai/da/mapper/primary/entity/Account.java b/src/main/java/com/ai/da/mapper/primary/entity/Account.java index 3629eedf..dc4a93ae 100644 --- a/src/main/java/com/ai/da/mapper/primary/entity/Account.java +++ b/src/main/java/com/ai/da/mapper/primary/entity/Account.java @@ -118,4 +118,6 @@ public class Account implements Serializable { private BigDecimal shareCredits; private Integer subAccountNum; + + private String invitationCode; } diff --git a/src/main/java/com/ai/da/mapper/primary/entity/ProductImageAttribute.java b/src/main/java/com/ai/da/mapper/primary/entity/ProductImageAttribute.java new file mode 100644 index 00000000..129eb32b --- /dev/null +++ b/src/main/java/com/ai/da/mapper/primary/entity/ProductImageAttribute.java @@ -0,0 +1,35 @@ +package com.ai.da.mapper.primary.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +import java.io.Serializable; + +@Data +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("product_image_attribute") +public class ProductImageAttribute implements Serializable { + private static final long serialVersionUID = 1L; + + @TableId(value = "id", type = IdType.AUTO) + private Long id; + private String imgName; + private String length; + private String sleeveLength; + private String sleeveShape; + private String sleeveShoulder; + private String neckline; + private String collar; + private String design; + private String silhouette; + private String type; + private String openingType; + private String subtype; + + private String style; +} diff --git a/src/main/java/com/ai/da/mapper/secondary/entity/AttributeRetrieval.java b/src/main/java/com/ai/da/mapper/secondary/entity/AttributeRetrieval.java index 84cc1b91..12ef2329 100644 --- a/src/main/java/com/ai/da/mapper/secondary/entity/AttributeRetrieval.java +++ b/src/main/java/com/ai/da/mapper/secondary/entity/AttributeRetrieval.java @@ -19,6 +19,4 @@ public class AttributeRetrieval { private String subtype; private String style; - - private Integer deprecated; } diff --git a/src/main/java/com/ai/da/model/dto/DesignCollectionDTO.java b/src/main/java/com/ai/da/model/dto/DesignCollectionDTO.java index 478483c4..91120a0b 100644 --- a/src/main/java/com/ai/da/model/dto/DesignCollectionDTO.java +++ b/src/main/java/com/ai/da/model/dto/DesignCollectionDTO.java @@ -63,4 +63,8 @@ public class DesignCollectionDTO { private String moodboardPostion; + private List requestIdList; + + private Integer designNum; + } diff --git a/src/main/java/com/ai/da/model/dto/ProductImageInitializeDTO.java b/src/main/java/com/ai/da/model/dto/ProductImageInitializeDTO.java new file mode 100644 index 00000000..a3aace06 --- /dev/null +++ b/src/main/java/com/ai/da/model/dto/ProductImageInitializeDTO.java @@ -0,0 +1,10 @@ +package com.ai.da.model.dto; + +import lombok.Data; + +import java.util.List; + +@Data +public class ProductImageInitializeDTO { + private List libraryIds; +} diff --git a/src/main/java/com/ai/da/model/dto/ReDesignCollectionDTO.java b/src/main/java/com/ai/da/model/dto/ReDesignCollectionDTO.java index b72a690a..65a125a9 100644 --- a/src/main/java/com/ai/da/model/dto/ReDesignCollectionDTO.java +++ b/src/main/java/com/ai/da/model/dto/ReDesignCollectionDTO.java @@ -33,7 +33,7 @@ public class ReDesignCollectionDTO { @ApiModelProperty("市场手稿板图片id 数组") private List marketingSketchs; - @NotNull(message = "colorBoards.cannot.be.empty") + @NotNull(message = "systemScale.cannot.be.empty") @ApiModelProperty("系统取图比列") private BigDecimal systemScale; diff --git a/src/main/java/com/ai/da/model/vo/DesignCollectionItemVO.java b/src/main/java/com/ai/da/model/vo/DesignCollectionItemVO.java index dc15cd14..1c98e059 100644 --- a/src/main/java/com/ai/da/model/vo/DesignCollectionItemVO.java +++ b/src/main/java/com/ai/da/model/vo/DesignCollectionItemVO.java @@ -22,6 +22,8 @@ public class DesignCollectionItemVO { @ApiModelProperty("t_design_python_outfit id") private String designOutfitUrl; + private String objectSign; + public DesignCollectionItemVO() { } diff --git a/src/main/java/com/ai/da/model/vo/DesignCollectionVO.java b/src/main/java/com/ai/da/model/vo/DesignCollectionVO.java index 8ad6e7a4..807f364c 100644 --- a/src/main/java/com/ai/da/model/vo/DesignCollectionVO.java +++ b/src/main/java/com/ai/da/model/vo/DesignCollectionVO.java @@ -23,6 +23,8 @@ public class DesignCollectionVO { private String processId; + private List UnfinishedList; + public DesignCollectionVO() { } } diff --git a/src/main/java/com/ai/da/model/vo/ValidateElementVO.java b/src/main/java/com/ai/da/model/vo/ValidateElementVO.java index f2cb87a1..73912616 100644 --- a/src/main/java/com/ai/da/model/vo/ValidateElementVO.java +++ b/src/main/java/com/ai/da/model/vo/ValidateElementVO.java @@ -47,4 +47,8 @@ public class ValidateElementVO { private String modelSex; private String style; + + private List requestIdList; + + private Integer designNum; } diff --git a/src/main/java/com/ai/da/python/PythonService.java b/src/main/java/com/ai/da/python/PythonService.java index 08113d91..3032a498 100644 --- a/src/main/java/com/ai/da/python/PythonService.java +++ b/src/main/java/com/ai/da/python/PythonService.java @@ -230,13 +230,14 @@ public class PythonService { designPythonObjects.setProcess_id(processId); long pinPrintNum = calculateDesignPinPrintNum(elementVO.getPrintBoardElements()); - long noPinPrintNum = calculateDesignNoPinPrintNum(elementVO.getPrintBoardElements()); - long noPrintNum = 8 - pinPrintNum - noPinPrintNum; + long noPinPrintNum = calculateDesignNoPinPrintNum(elementVO.getPrintBoardElements(), elementVO.getDesignNum()); + long noPrintNum = elementVO.getDesignNum() - pinPrintNum - noPinPrintNum; elementVO.setNoPinPrintNum(noPinPrintNum); int[] sketchNumbers = new int[3]; - for (int i = 0; i < 8; i++) { + int designNum = elementVO.getDesignNum(); + for (int i = 0; i < designNum; i++) { CurrentDesignPictureTypeEnum designPictureType = calculateCurrentDesignPictureTypeNew(elementVO, sketchNumbers, systemScale); if (designPictureType == null) break; @@ -261,7 +262,7 @@ public class PythonService { elementVO.setDesignPythonItemPrint(designPythonItemPrint); elementVO.setDesignPrintPictureTypeLayoutList(calculateCurrentDesignPintPictureTypeLayout(elementVO.getModelSex())); - DesignPythonObject pythonObject = createDesignPythonObject(elementVO, designPictureType, systemScale, singleOverall, switchCategory); + DesignPythonObject pythonObject = createDesignPythonObject(elementVO, designPictureType, systemScale, singleOverall, switchCategory, i); objects.add(pythonObject); redisUtil.addProcessId(processId, i + 1); } @@ -296,22 +297,24 @@ public class PythonService { } } - private DesignPythonObject createDesignPythonObject(ValidateElementVO elementVO, CurrentDesignPictureTypeEnum designPictureType, BigDecimal systemScale, String singleOverall, String switchCategory) { + private DesignPythonObject createDesignPythonObject(ValidateElementVO elementVO, CurrentDesignPictureTypeEnum designPictureType, BigDecimal systemScale, String singleOverall, String switchCategory, int i) { DesignPythonObject pythonObject = new DesignPythonObject(); pythonObject.setItems(coverToDesignPythonItemNew(elementVO, designPictureType, systemScale)); pythonObject.setBasic(coverToBasic(pythonObject.getItems().get(0), singleOverall, switchCategory, elementVO.getDesignLibraryModelPoint())); + pythonObject.setObjectSign(elementVO.getRequestIdList().get(i)); return pythonObject; } private CurrentDesignPictureTypeEnum calculateCurrentDesignPictureTypeNew(ValidateElementVO elementVO, int[] sketchNumbers, BigDecimal systemScale) { List pinData = getPinData(elementVO); + Integer designNum = elementVO.getDesignNum(); if (CollectionUtil.isNotEmpty(pinData)) { return CurrentDesignPictureTypeEnum.PIN; } else { if (sketchNumbers[1] == 0 && sketchNumbers[2] == 0) { - sketchNumbers[1] = systemScale.multiply(BigDecimal.valueOf(8 - sketchNumbers[0])).setScale(0, BigDecimal.ROUND_HALF_UP).intValue(); - sketchNumbers[2] = 8 - sketchNumbers[0] - sketchNumbers[1]; + sketchNumbers[1] = systemScale.multiply(BigDecimal.valueOf(designNum - sketchNumbers[0])).setScale(0, BigDecimal.ROUND_HALF_UP).intValue(); + sketchNumbers[2] = designNum - sketchNumbers[0] - sketchNumbers[1]; } if (sketchNumbers[2] > 0 && sketchNumbers[1] > 0) { Long l = RandomsUtil.randomSysFile(0l, 2l); @@ -491,7 +494,7 @@ public class PythonService { } //计算print 非Pin图片剩余张数 - private long calculateDesignNoPinPrintNum(List printBoardElements) { + private long calculateDesignNoPinPrintNum(List printBoardElements, Integer designNum) { if (CollectionUtils.isEmpty(printBoardElements)) { return 0; } @@ -500,10 +503,10 @@ public class PythonService { return 0; } else { long pinNum = printBoardElements.stream().filter(f -> f.getHasPin() == 1).count(); - if (8 - pinNum < 4) { - return RandomsUtil.randomSysFile(0L, 8 - pinNum + 1); + if (designNum - pinNum < designNum/2) { + return RandomsUtil.randomSysFile(0L, designNum - pinNum + 1); } else { - return RandomsUtil.randomSysFile(0L, 4L + 1); + return RandomsUtil.randomSysFile(0L, (long) (designNum/2 + 1)); } } } @@ -553,7 +556,7 @@ public class PythonService { if (elementVO.getSingleOverall().equals(SingleOverallEnum.OVERALL.getRealName())) { List otherSketchCategoryList = getOtherSketchCategoryList(elementVO.getModelSex(), designPythonItem); if (!otherSketchCategoryList.isEmpty()) { - JSONObject attributeRecognition = getAttributeRecognition(designPythonItem, designPythonItem.getType(), elementVO.getModelSex()); + JSONObject attributeRecognition = getAttributeRecognition(designPythonItem.getPath(), designPythonItem.getType(), elementVO.getModelSex()); for (String styleCategory : otherSketchCategoryList) { DesignPythonItem otherSketch = processAttributeRecognition(attributeRecognition, elementVO, designPictureType, styleCategory, systemScale); itemList.add(otherSketch); @@ -790,7 +793,7 @@ public class PythonService { return attributeRetrieval; } - public JSONObject getAttributeRecognition(DesignPythonItem designPythonItem, String styleCategory, String modelSex) { + public JSONObject getAttributeRecognition(String sketchImgUrl, String styleCategory, String modelSex) { OkHttpClient client = new OkHttpClient().newBuilder() .connectTimeout(30, TimeUnit.SECONDS) .readTimeout(60, TimeUnit.SECONDS) @@ -801,7 +804,7 @@ public class PythonService { JSONObject paramJSONObject = new JSONObject(); paramJSONObject.put("category", styleCategory); paramJSONObject.put("colony", modelSex); - paramJSONObject.put("sketch_img_url", designPythonItem.getPath()); + paramJSONObject.put("sketch_img_url", sketchImgUrl); JSONArray paramArray = new JSONArray(); paramArray.add(paramJSONObject); String param = JSON.toJSONString(paramArray, SerializerFeature.DisableCircularReferenceDetect); @@ -3003,6 +3006,58 @@ public class PythonService { throw new BusinessException("design.interface.exception"); } + public JSONObject designStream(DesignPythonObjects designPythonObjects) { + // todo 限流校验 +// AccessLimitUtils.validate("design",5); + OkHttpClient client = new OkHttpClient().newBuilder() + .connectTimeout(30, TimeUnit.SECONDS) + .pingInterval(5, TimeUnit.SECONDS)//websocket轮训间隔(单位:秒) + .readTimeout(60, TimeUnit.SECONDS)//读取超时(单位:秒) + .writeTimeout(60, TimeUnit.SECONDS)//写入超时(单位:秒) + .build(); + MediaType mediaType = MediaType.parse("application/json"); + //关闭FastJson的引用检测 防止出现$ref 现象 + String param = JSON.toJSONString(designPythonObjects, SerializerFeature.DisableCircularReferenceDetect); + log.info("design请求python 参数:####{}", param); + RequestBody body = RequestBody.create(mediaType, param); + Request request = new Request.Builder() + .url(accessPythonIp + ":" + accessPythonPort + "/api/design_v2") +// .url(fastApiPythonAddress + "/api/design") +// .url(accessPythonIp + ":10200/aifda/api/v1.0/generate") + .method("POST", body) + .addHeader("Authorization", "Basic YWlkbGFiOjEyMw==") + .addHeader("Content-Type", "application/json") + .build(); + Response response; + String responseBody; + try { + response = client.newCall(request).execute(); + } catch (IOException ioException) { + AccessLimitUtils.validateOut("design"); + log.error("PythonService##design异常###{}", ExceptionUtil.getThrowableList(ioException)); + throw new BusinessException("design.interface.exception"); + } + //去除限流 +// AccessLimitUtils.validateOut("design"); + if (response.isSuccessful()) { + try { + if (Objects.nonNull(response.body())) { + responseBody = response.body().string(); + JSONObject responseObject = JSON.parseObject(responseBody); + log.info("PythonService##responseObject###{}", responseObject); + return responseObject; + } + throw new BusinessException("design.interface.exception"); + } catch (IOException | JSONException e) { + log.error("PythonService##design异常###{}", e.getMessage()); + throw new BusinessException("design.interface.exception"); + } + } + log.error("PythonService##design异常response###{}", response); + //生成失败 + throw new BusinessException("design.interface.exception"); + } + /** * 暂时未用 */ @@ -3566,4 +3621,54 @@ public class PythonService { //生成失败 throw new BusinessException("bright.interface.exception"); } + + public JSONObject attributeRecognition(List pictureUrls,List ids, List category) { + //限流校验 + AccessLimitUtils.validate("attributeRecognition", 20); + OkHttpClient client = new OkHttpClient().newBuilder() + .connectTimeout(30, TimeUnit.SECONDS) + .pingInterval(5, TimeUnit.SECONDS)//websocket轮训间隔(单位:秒) + .readTimeout(300, TimeUnit.SECONDS)//读取超时(单位:秒) + .writeTimeout(300, TimeUnit.SECONDS)//写入超时(单位:秒) + .build(); + MediaType mediaType = MediaType.parse("application/json"); + Map> content = Maps.newHashMap(); + //识别图片路径数组 + content.put("upload_img_path", pictureUrls); + //识别图片id数组 + content.put("upload_img_id", ids); + content.put("upload_img_category", category); + RequestBody body = RequestBody.create(mediaType, JSON.toJSONString(content)); + Request request = new Request.Builder() + .url(accessPythonIp + ":9993/api/attribute") + .method("POST", body) + .addHeader("Authorization", "Basic YWlkbGFiOjEyMw==") + .addHeader("Content-Type", "application/json") + .build(); + Response response = null; + String bodyStr = null; + try { + log.info("识别python对应的属性标签值请求入参content###{}", JSON.toJSONString(content)); + response = client.newCall(request).execute(); + bodyStr = response.body().string(); + } catch (IOException ioException) { + log.error("PythonService###attributeRecognition异常##{}", ExceptionUtil.getThrowableList(ioException)); + } + log.info("识别python对应的属性标签值结果###{}",bodyStr.trim()); + //去除限流 + AccessLimitUtils.validateOut("attributeRecognition"); + if (Objects.isNull(response)) { + log.error("PythonService##attributeRecognition异常###{}", "response or body is empty!"); + throw new BusinessException("attribute recognition exception!"); + } + JSONObject jsonObject = JSON.parseObject(JSON.toJSONString(response)); + Boolean result = jsonObject.getBoolean("successful"); + if (result) { + JSONObject attributeJSONObject = JSON.parseObject(bodyStr.trim()); + return attributeJSONObject; + } + log.info("识别python对应的属性标签值异常###{}", jsonObject); + //生成失败 + throw new BusinessException("Atribute recognition exception!"); + } } diff --git a/src/main/java/com/ai/da/python/vo/DesignPythonObject.java b/src/main/java/com/ai/da/python/vo/DesignPythonObject.java index aa6a11e2..12946423 100644 --- a/src/main/java/com/ai/da/python/vo/DesignPythonObject.java +++ b/src/main/java/com/ai/da/python/vo/DesignPythonObject.java @@ -15,4 +15,6 @@ public class DesignPythonObject { * basic 选项 */ DesignPythonBasic basic; + + private String objectSign; } diff --git a/src/main/java/com/ai/da/python/vo/DesignPythonObjects.java b/src/main/java/com/ai/da/python/vo/DesignPythonObjects.java index af5fa3be..1f61ee07 100644 --- a/src/main/java/com/ai/da/python/vo/DesignPythonObjects.java +++ b/src/main/java/com/ai/da/python/vo/DesignPythonObjects.java @@ -16,4 +16,6 @@ public class DesignPythonObjects { * design新增的library */ List addLibrary; + + private String requestId; } diff --git a/src/main/java/com/ai/da/service/AccountService.java b/src/main/java/com/ai/da/service/AccountService.java index 2d86fdf2..64bde1da 100644 --- a/src/main/java/com/ai/da/service/AccountService.java +++ b/src/main/java/com/ai/da/service/AccountService.java @@ -201,5 +201,9 @@ public interface AccountService extends IService { Account accountDetail(Long id); - GoogleUser parseGoogleCredential(String credential); + AccountLoginVO parseGoogleCredential(String credential); + + AccountLoginVO parseWeChatCode(String code); + + AccountLoginVO getAccountDetail(); } diff --git a/src/main/java/com/ai/da/service/DesignService.java b/src/main/java/com/ai/da/service/DesignService.java index b346c8bf..d362d27b 100644 --- a/src/main/java/com/ai/da/service/DesignService.java +++ b/src/main/java/com/ai/da/service/DesignService.java @@ -7,6 +7,7 @@ import com.ai.da.model.vo.DesignCollectionVO; import com.ai.da.model.vo.DesignItemDetailVO; import com.ai.da.model.vo.DesignLikeVO; import com.ai.da.python.vo.DesignPythonObjects; +import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.extension.service.IService; import java.math.BigDecimal; @@ -25,7 +26,7 @@ public interface DesignService extends IService { * @param designDTO * @return */ - DesignCollectionVO designCollection(DesignCollectionDTO designDTO); + String designCollection(DesignCollectionDTO designDTO); /** * redesign @@ -33,7 +34,7 @@ public interface DesignService extends IService { * @param reDesignDTO * @return */ - DesignCollectionVO reDesignCollection(ReDesignCollectionDTO reDesignDTO); + String reDesignCollection(ReDesignCollectionDTO reDesignDTO); /** * redesign @@ -99,4 +100,10 @@ public interface DesignService extends IService { List getModel(List designItemIdList); Long getCountByUserAndTime(String startTime, String endTime, List accountIds); + + Boolean receiveDesignResults(JSONObject responseObject); + + DesignCollectionVO getDesignResult(String requestId, List objectSignList); + + String designCloud(DesignCollectionDTO designDTO); } diff --git a/src/main/java/com/ai/da/service/UserLikeGroupService.java b/src/main/java/com/ai/da/service/UserLikeGroupService.java index 71edbc50..fb8feb6a 100644 --- a/src/main/java/com/ai/da/service/UserLikeGroupService.java +++ b/src/main/java/com/ai/da/service/UserLikeGroupService.java @@ -4,6 +4,7 @@ import com.ai.da.mapper.primary.entity.CanvasElementUpload; import com.ai.da.mapper.primary.entity.ToProductImageResult; import com.ai.da.mapper.primary.entity.UserLikeGroup; import com.ai.da.model.dto.ExportSaveDTO; +import com.ai.da.model.dto.ProductImageInitializeDTO; import com.ai.da.model.dto.ProductImageLikeDTO; import com.ai.da.model.dto.ToProductImageDTO; import com.ai.da.model.vo.*; @@ -62,4 +63,6 @@ public interface UserLikeGroupService extends IService { List getRelightResult(List taskIdList); String likeHistoryRelSketch(); + + Boolean productImageInitialize(ProductImageInitializeDTO productImageInitializeDTO); } diff --git a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java index 03145804..13ec162e 100644 --- a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java @@ -11,6 +11,7 @@ import com.ai.da.common.response.PageBaseResponse; import com.ai.da.common.response.ResultEnum; import com.ai.da.common.security.jwt.JWTTokenHelper; import com.ai.da.common.utils.*; +import com.ai.da.mapper.primary.AccountExtendMapper; import com.ai.da.mapper.primary.AccountMapper; import com.ai.da.mapper.primary.QuestionnaireMapper; import com.ai.da.mapper.primary.TrialOrderMapper; @@ -21,6 +22,7 @@ import com.ai.da.model.enums.Language; import com.ai.da.model.vo.*; import com.ai.da.service.*; import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; @@ -30,9 +32,6 @@ import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken; import com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier; import com.google.api.client.http.javanet.NetHttpTransport; import com.google.api.client.json.jackson2.JacksonFactory; -import com.google.auth.oauth2.IdToken; -import com.google.auth.oauth2.TokenVerifier; -import com.google.common.base.Function; import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; import io.netty.util.internal.StringUtil; @@ -1202,9 +1201,10 @@ public class AccountServiceImpl extends ServiceImpl impl if (StringUtils.isBlank(accountDesignWorksRegisterDTO.getLanguage())) { account.setLanguage(Language.ENGLISH.name()); } - account.setIsTrial(0); + account.setIsTrial(1); account.setIsBeginner(1); account.setValidStartTime(Instant.now().toEpochMilli()); + toDayEnd(Instant.now().plus(5, ChronoUnit.DAYS).toEpochMilli()); account.setCreateDate(new Date()); account.setCredits(BigDecimal.valueOf(0)); accountMapper.insert(account); @@ -2099,7 +2099,7 @@ public class AccountServiceImpl extends ServiceImpl impl } @Override - public GoogleUser parseGoogleCredential(String credential) { + public AccountLoginVO parseGoogleCredential(String credential) { try { // 配置 Google ID Token 验证器 GoogleIdTokenVerifier verifier = new GoogleIdTokenVerifier.Builder( @@ -2111,6 +2111,7 @@ public class AccountServiceImpl extends ServiceImpl impl // 验证并解析 ID Token GoogleIdToken idToken = verifier.verify(credential); + if (idToken != null) { GoogleIdToken.Payload payload = idToken.getPayload(); @@ -2122,7 +2123,54 @@ public class AccountServiceImpl extends ServiceImpl impl log.info(email); log.info(name); - return new GoogleUser(); + // 检查数据库中是否已有该用户 + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.lambda().eq(Account::getUserEmail, email); // 根据邮箱查询用户 + List accounts = accountMapper.selectList(queryWrapper); + Account account = new Account(); + if (CollectionUtil.isNotEmpty(accounts)) { + account = accounts.get(0); + } else { + // 用户不存在,创建新用户(自动注册) + Account newUser = new Account(); + newUser.setUserEmail(email); + newUser.setUserName(name); + newUser.setUserPassword("Third-000000"); + newUser.setLanguage(Language.ENGLISH.name()); + newUser.setValidStartTime(System.currentTimeMillis()); + newUser.setValidEndTime(toDayEnd(Instant.now().plus(5, ChronoUnit.DAYS).toEpochMilli())); + newUser.setCreateDate(new Date()); + newUser.setIsTrial(1); + newUser.setIsBeginner(1); + newUser.setCredits(BigDecimal.valueOf(100)); + newUser.setSystemUser(3); + accountMapper.insert(newUser); + + account = newUser; + } + + AccountLoginVO response = CopyUtil.copyObject(account, AccountLoginVO.class); + response.setEmail(account.getUserEmail()); + String token = LocalCacheUtils.getTokenCache(String.valueOf(account.getId())); + if (StringUtils.isNotBlank(token)) { + //用户已登入 + response.setToken(token); + } else { + response.setToken(createAccountToken(account)); + } + response.setUserId(account.getId()); + response.setSystemUser(account.getSystemUser()); + // 设置头像 + String avatar; + if (StringUtil.isNullOrEmpty(account.getAvatar())){ + avatar = CommonConstant.DEFAULT_AVATAR; + }else { + avatar = account.getAvatar(); + } + response.setAvatar(minioUtil.getPreSignedUrl(avatar, CommonConstant.MINIO_IMAGE_EXPIRE_TIME)); + response.setFolloweeCount(portfolioService.getFolloweeCount(account.getId())); + response.setFollowerCount(portfolioService.getFollowerCount(account.getId())); + return response; } else { throw new IllegalArgumentException("Invalid ID token."); } @@ -2132,4 +2180,178 @@ public class AccountServiceImpl extends ServiceImpl impl throw new RuntimeException("Failed to verify ID token: " + e.getMessage()); } } + + private static final String WECHAT_ACCESS_TOKEN_URL = + "https://api.weixin.qq.com/sns/oauth2/access_token"; + + private static final String APP_ID = "wxcfb92eb28d6385f5"; + private static final String APP_SECRET = "e5592c691756455b2d03ebfd21fc3131"; + + @Override + public AccountLoginVO parseWeChatCode(String code) { + // 1. 获取 access_token 和 openid + JSONObject accessTokenResponse = getAccessTokenFromWeChat(code); + String accessToken = accessTokenResponse.getString("access_token"); + String openId = accessTokenResponse.getString("openid"); + + if (StringUtils.isEmpty(accessToken) || StringUtils.isEmpty(openId)) { + throw new RuntimeException("微信接口返回数据缺失: " + accessTokenResponse.toJSONString()); + } + + // 2. 获取用户信息 + JSONObject userInfoResponse = getUserInfoFromWeChat(accessToken, openId); + + // 提取 unionid 和 nickname + String unionId = userInfoResponse.getString("unionid"); + String userName = userInfoResponse.getString("nickname"); + if (unionId == null) { + throw new IllegalArgumentException("无法获取 unionid,请检查微信开发平台配置"); + } + + // 检查数据库中是否已有该unionid + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.lambda().eq(AccountExtend::getAuthType, "WeChat"); + queryWrapper.lambda().eq(AccountExtend::getAuth, unionId); + List accountExtends = accountExtendMapper.selectList(queryWrapper); + Account account = new Account(); + if (CollectionUtil.isEmpty(accountExtends)) { + AccountExtend accountExtendInsert = new AccountExtend(); + accountExtendInsert.setAuth(unionId); + accountExtendInsert.setAuthType("WeChat"); + + // 用户不存在,创建新用户(自动注册) + Account newUser = new Account(); +// newUser.setUserEmail(email); + newUser.setUserName(userName); + newUser.setUserPassword("Third-000000"); + newUser.setLanguage(Language.ENGLISH.name()); + newUser.setValidStartTime(System.currentTimeMillis()); + newUser.setValidEndTime(toDayEnd(Instant.now().plus(5, ChronoUnit.DAYS).toEpochMilli())); + newUser.setCreateDate(new Date()); + newUser.setIsTrial(1); + newUser.setIsBeginner(1); + newUser.setCredits(BigDecimal.valueOf(100)); + newUser.setSystemUser(3); + accountMapper.insert(newUser); + + accountExtendInsert.setAccountId(newUser.getId()); + accountExtendMapper.insert(accountExtendInsert); + + account = newUser; + }else { + AccountExtend accountExtend = accountExtends.get(0); + account = accountMapper.selectById(accountExtend.getAccountId()); + } + + AccountLoginVO response = CopyUtil.copyObject(account, AccountLoginVO.class); + response.setEmail(account.getUserEmail()); + String token = LocalCacheUtils.getTokenCache(String.valueOf(account.getId())); + if (StringUtils.isNotBlank(token)) { + //用户已登入 + response.setToken(token); + } else { + response.setToken(createAccountToken(account)); + } + response.setUserId(account.getId()); + response.setSystemUser(account.getSystemUser()); + // 设置头像 + String avatar; + if (StringUtil.isNullOrEmpty(account.getAvatar())){ + avatar = CommonConstant.DEFAULT_AVATAR; + }else { + avatar = account.getAvatar(); + } + response.setAvatar(minioUtil.getPreSignedUrl(avatar, CommonConstant.MINIO_IMAGE_EXPIRE_TIME)); + response.setFolloweeCount(portfolioService.getFolloweeCount(account.getId())); + response.setFollowerCount(portfolioService.getFollowerCount(account.getId())); + return response; + +// // 2. 根据 unionid 检查用户是否存在 +// User user = userRepository.findByUnionid(unionid); +// if (user == null) { +// // 用户不存在,进行注册 +// user = new User(); +// user.setUnionid(unionid); +// user.setOpenid(weChatResponse.getString("openid")); +// user.setNickname(weChatResponse.getString("nickname")); +// user.setAvatar(weChatResponse.getString("headimgurl")); +// userRepository.save(user); +// } +// +// // 3. 返回 unionid +// return unionid; + } + + private static final String WECHAT_USER_INFO_URL = "https://api.weixin.qq.com/sns/userinfo"; + private JSONObject getUserInfoFromWeChat(String accessToken, String openId) { + // 构造微信用户信息接口的 URL + String url = String.format( + "%s?access_token=%s&openid=%s&lang=zh_CN", + WECHAT_USER_INFO_URL, accessToken, openId + ); + + // 调用微信接口 + RestTemplate restTemplate = new RestTemplate(); + String response = restTemplate.getForObject(url, String.class); + + // 转换为 JSON 对象 + JSONObject jsonResponse = JSONObject.parseObject(response); + if (jsonResponse.containsKey("errcode")) { + throw new RuntimeException("微信用户信息接口调用失败: " + jsonResponse.getString("errmsg")); + } + + return jsonResponse; + } + + private JSONObject getAccessTokenFromWeChat(String code) { + // 构造微信接口请求 URL + String url = String.format( + "%s?appid=%s&secret=%s&code=%s&grant_type=authorization_code", + WECHAT_ACCESS_TOKEN_URL, APP_ID, APP_SECRET, code + ); + + // 调用微信接口 + RestTemplate restTemplate = new RestTemplate(); + String response = restTemplate.getForObject(url, String.class); + + // 转换为 JSON 对象 + JSONObject jsonResponse = JSONObject.parseObject(response); + if (jsonResponse.containsKey("errcode")) { + throw new RuntimeException("微信接口调用失败: " + jsonResponse.getString("errmsg")); + } + + return jsonResponse; + } + + @Override + public AccountLoginVO getAccountDetail() { + AuthPrincipalVo authPrincipalVo = UserContext.getUserHolder(); + Long accountId = authPrincipalVo.getId(); + Account account = accountMapper.selectById(accountId); + + AccountLoginVO response = CopyUtil.copyObject(account, AccountLoginVO.class); + response.setEmail(account.getUserEmail()); + String token = LocalCacheUtils.getTokenCache(String.valueOf(account.getId())); + if (StringUtils.isNotBlank(token)) { + //用户已登入 + response.setToken(token); + } else { + response.setToken(createAccountToken(account)); + } + response.setUserId(account.getId()); + response.setSystemUser(account.getSystemUser()); + // 设置头像 + String avatar; + if (StringUtil.isNullOrEmpty(account.getAvatar())){ + avatar = CommonConstant.DEFAULT_AVATAR; + }else { + avatar = account.getAvatar(); + } + response.setAvatar(minioUtil.getPreSignedUrl(avatar, CommonConstant.MINIO_IMAGE_EXPIRE_TIME)); + response.setFolloweeCount(portfolioService.getFolloweeCount(account.getId())); + response.setFollowerCount(portfolioService.getFollowerCount(account.getId())); + //判断是否常用ip 不是则发邮件提示 +// calculateExceptionIp(RequestInfoUtil.getIpAddress(request), account); + return response; + } } diff --git a/src/main/java/com/ai/da/service/impl/CollectionElementServiceImpl.java b/src/main/java/com/ai/da/service/impl/CollectionElementServiceImpl.java index a6bcedc6..ca26b261 100644 --- a/src/main/java/com/ai/da/service/impl/CollectionElementServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/CollectionElementServiceImpl.java @@ -607,6 +607,12 @@ public class CollectionElementServiceImpl extends ServiceImpl impleme @Resource private RedisUtil redisUtil; + private final ConcurrentHashMap> designContext = new ConcurrentHashMap<>(); + + @Override - public DesignCollectionVO designCollection(DesignCollectionDTO designDTO) { + public String designCollection(DesignCollectionDTO designDTO) { AuthPrincipalVo userInfo = UserContext.getUserHolder(); //校验collection element ValidateElementVO elementVO = collectionElementService.validateElement(designDTO); @@ -283,7 +287,7 @@ public class DesignServiceImpl extends ServiceImpl impleme // return saveDesignItemAndDetail(pythonObjects, designId, collectionId, userInfo, designDTO.getTimeZone()); // } - private DesignCollectionVO designOrRedesignOperateNew(DesignCollectionDTO designDTO, AuthPrincipalVo userInfo, + private String designOrRedesignOperateNew(DesignCollectionDTO designDTO, AuthPrincipalVo userInfo, Long collectionIdParam, ValidateElementVO elementVO) { if (CollectionUtil.isNotEmpty(designDTO.getSketchBoards())) { //编辑sketchBoard @@ -336,7 +340,9 @@ public class DesignServiceImpl extends ServiceImpl impleme log.info("增加image_id关联运行时间:" + totalTimeInSeconds + " 秒"); //design startTime = System.currentTimeMillis(); - JSONObject responseJSONObject = pythonService.designNew(pythonObjects); + String requestId = UUID.randomUUID().toString(); + pythonObjects.setRequestId(requestId); + JSONObject responseJSONObject = pythonService.designStream(pythonObjects); endTime = System.currentTimeMillis(); totalTimeInSeconds = (endTime - startTime) / 1000; log.info("design python端运行时间:" + totalTimeInSeconds + " 秒"); @@ -350,10 +356,26 @@ public class DesignServiceImpl extends ServiceImpl impleme endTime = System.currentTimeMillis(); totalTimeInSeconds = (endTime - startTime) / 1000; log.info("处理关联关系运行时间:" + totalTimeInSeconds + " 秒"); + + + Map context = new HashMap<>(); + context.put("pythonObjects", pythonObjects); // 转换后的 Python 请求参数 + context.put("designId", designId); // 设计 ID + context.put("collectionId", collectionId); // 集合 ID + context.put("userInfo", userInfo); // 用户信息 + context.put("timeZone", designDTO.getTimeZone()); // 时区 + context.put("singleOverall", designDTO.getSingleOverall()); // 其他设计参数 + context.put("requestIdList", elementVO.getRequestIdList()); + + // 将上下文存入全局设计上下文中 + designContext.put(requestId, context); + //保存python返回信息;保存designItem和detail - return savePythonDesignItemAndDetail(pythonObjects, designId, collectionId, userInfo, designDTO.getTimeZone(), responseJSONObject, designDTO.getSingleOverall()); +// return savePythonDesignItemAndDetail(pythonObjects, designId, collectionId, userInfo, designDTO.getTimeZone(), responseJSONObject, designDTO.getSingleOverall()); + return requestId; } + @Override public void relationImageId(DesignPythonObjects pythonObjects) { if (Objects.isNull(pythonObjects)) { @@ -601,6 +623,152 @@ public class DesignServiceImpl extends ServiceImpl impleme @Resource private MinioUtil minioUtil; + private DesignCollectionVO savePythonDesignItemAndDetailSingle(DesignPythonObjects pythonObjects, Long designId, Long collectionId, AuthPrincipalVo userInfo, String timeZone, JSONObject outfit, String singleOverall, Map context) { + Object designCollectionVO = context.get("DesignCollectionVO"); + DesignCollectionVO response; + List designCollectionItems = Lists.newArrayList(); + if (null == designCollectionVO) { + response = new DesignCollectionVO(); + response.setDesignId(designId); + response.setCollectionId(collectionId); + response.setProcessId(pythonObjects.getProcess_id()); + }else { + response = (DesignCollectionVO) designCollectionVO; + designCollectionItems = response.getDesignCollectionItems(); + } + + response.setDesignCollectionItems(designCollectionItems); + + + DesignPythonObject item = new DesignPythonObject(); + String objectSign = outfit.getString("objectSign"); + log.info(objectSign); + for (DesignPythonObject object : pythonObjects.getObjects()) { + if (object.getObjectSign().equals(objectSign)) { + item = object; + continue; + } + } + + + DesignItem designItem = new DesignItem(); + designItem.setAccountId(userInfo.getId()); + designItem.setCollectionId(collectionId); + designItem.setDesignId(designId); + designItem.setCreateDate(DateUtil.getByTimeZone(timeZone)); + //生成的八张图片 + designItem.setDesignUrl(item.getBasic().getSave_name()); + designItem.setHasLike((byte) 0); + //生成designItem + Long designItemId = designItemService.saveOne(designItem); + // python design返回入库及封装 +// JSONObject outfit = data.getJSONObject(i + ""); +// if (null == outfit) { +// continue; +// } + TDesignPythonOutfit designPythonOutfit = new TDesignPythonOutfit(); + designPythonOutfit.setDesignItemId(designItemId); + designPythonOutfit.setUserId(userInfo.getId()); + designPythonOutfit.setDesignId(designId); + designPythonOutfit.setCollectionId(collectionId); + String synthesisUrl = outfit.getString("synthesis_url"); + if (!StringUtils.isEmpty(synthesisUrl)) { + designPythonOutfit.setDesignUrl(synthesisUrl); + } else { + throw new BusinessException("design.interface.exception"); + } + designPythonOutfitService.save(designPythonOutfit); + + JSONArray layers = outfit.getJSONArray("layers"); + List list = new ArrayList<>(); + DesignCollectionItemVO designCollectionItemVO = new DesignCollectionItemVO(); + designCollectionItemVO.setObjectSign(objectSign); + for (int i1 = 0; i1 < layers.size(); i1++) { + JSONObject jsonObject = layers.getJSONObject(i1); + TDesignPythonOutfitDetail designPythonOutfitDetail = new TDesignPythonOutfitDetail(); + designPythonOutfitDetail.setDesignId(designId); + designPythonOutfitDetail.setDesignPythonOutfitId(designPythonOutfit.getId()); + designPythonOutfitDetail.setPosition(jsonObject.getString("position")); + designPythonOutfitDetail.setImageSize(jsonObject.getString("image_size")); + designPythonOutfitDetail.setImageUrl(jsonObject.getString("image_url")); + if (singleOverall.equals(SingleOverallEnum.SINGLE.getRealName())) { + designCollectionItemVO.setDesignItemUrl(designItem.getDesignUrl()); + } + designPythonOutfitDetail.setImageCategory(jsonObject.getString("image_category")); + designPythonOutfitDetail.setMaskUrl(jsonObject.getString("mask_url")); + designPythonOutfitDetail.setUserId(userInfo.getId()); + designPythonOutfitDetail.setPriority(Integer.parseInt(jsonObject.getString("priority"))); + designPythonOutfitDetail.setCreateDate(LocalDateTime.now()); + list.add(designPythonOutfitDetail); + } + designPythonOutfitDetailService.saveBatch(list); + designCollectionItemVO.setDesignItemId(designItemId); + designCollectionItemVO.setDesignItemUrl(designItem.getDesignUrl()); + designCollectionItemVO.setDesignOutfitId(designPythonOutfit.getId()); + String designUrl = designPythonOutfit.getDesignUrl(); + if (!StringUtils.isEmpty(designUrl) && designUrl.contains("/")) { + int firstIndex = designUrl.indexOf("/"); + designCollectionItemVO.setDesignOutfitUrl(minioUtil.getPreSignedUrl(designUrl.substring(0, firstIndex) + "/" + designUrl.substring(firstIndex + 1), 24 * 60)); + } + //response + designCollectionItems.add(designCollectionItemVO); + + List designItemDetails = Lists.newArrayList(); + Map typePriority = list.stream().collect(Collectors.toMap(d -> d.getImageCategory().split("_")[0], + d -> Math.abs(d.getPriority()), + (existing, replacement) -> replacement)); + Map typeAndUndividedLayer = designItemService.setTypeAndUndividedLayer(layers); + for (DesignPythonItem detail : item.getItems()) { + if (null == detail) { + continue; + } + DesignItemDetail designItemDetail = CopyUtil.copyObject(detail, DesignItemDetail.class); + designItemDetail.setAccountId(userInfo.getId()); + designItemDetail.setDesignId(designId); + designItemDetail.setDesignItemId(designItemId); + designItemDetail.setCollectionElementId(detail.getElementId()); + designItemDetail.setCreateDate(DateUtil.getByTimeZone(timeZone)); + designItemDetail.setUndividedLayer(typeAndUndividedLayer.get(designItemDetail.getType().toLowerCase())); + if (SysFileLevel2TypeEnum.BODY.getRealName().equals(detail.getType())) { + designItemDetail.setPath(detail.getBody_path()); + //BODY不关联businessId + designItemDetail.setBusinessId(0L); + } + designItemDetail.setIconPath(detail.getIcon()); + designItemDetail.setPriority(typePriority.get(detail.getType().toLowerCase())); + if (!detail.getType().equals("Body")){ + DesignPythonItemPrint printObject = detail.getPrint().getOverall(); +// designItemDetail.setPrintPath(Objects.isNull(printObject) ? "" : printObject.getPath()); + designItemDetail.setPrintPath(CollectionUtils.isEmpty(printObject.getPrint_path_list()) ? "" : printObject.getPrint_path_list().get(0)); + } + designItemDetailService.save(designItemDetail); + if (!SysFileLevel2TypeEnum.BODY.getRealName().equals(detail.getType()) && !StringUtil.isNullOrEmpty(designItemDetail.getPrintPath())) { + DesignItemDetailPrint print = new DesignItemDetailPrint(); + print.setDesignItemDetailId(designItemDetail.getId()); + print.setPrintType("print"); + print.setPath(designItemDetail.getPrintPath()); + print.setSingleOrOverall("overall"); + print.setPosition("[0.0,0.0]"); +// print.setScale(1d); + // todo mark 将print默认scale置为0.3 + print.setScale(0.3d); + print.setAngle(0.0); + print.setPriority(1); + QueryWrapper getPrintboardLevel2TypeQw = new QueryWrapper<>(); + getPrintboardLevel2TypeQw.lambda().eq(CollectionElement::getUrl, print.getPath()); + getPrintboardLevel2TypeQw.lambda().orderByDesc(CollectionElement::getCreateDate); + getPrintboardLevel2TypeQw.last("limit 1"); + CollectionElement one = collectionElementService.getOne(getPrintboardLevel2TypeQw); + print.setLevel2Type(one.getLevel2Type()); + print.setCreateDate(LocalDateTime.now()); + designItemDetailPrintService.save(print); + } + } + synchronized (context) { + context.put("DesignCollectionVO", response); + } + return response; + } private DesignCollectionVO savePythonDesignItemAndDetail(DesignPythonObjects pythonObjects , Long designId, Long collectionId, AuthPrincipalVo userInfo, String timeZone, JSONObject responseJSONObject, String singleOverall) { DesignCollectionVO response = new DesignCollectionVO(); @@ -612,6 +780,7 @@ public class DesignServiceImpl extends ServiceImpl impleme if (data == null) { throw new BusinessException("design.interface.exception"); } + for (int i = 0; i < pythonObjects.getObjects().size(); i++) { DesignPythonObject item = pythonObjects.getObjects().get(i); DesignItem designItem = new DesignItem(); @@ -641,6 +810,7 @@ public class DesignServiceImpl extends ServiceImpl impleme throw new BusinessException("design.interface.exception"); } designPythonOutfitService.save(designPythonOutfit); + JSONArray layers = outfit.getJSONArray("layers"); List list = new ArrayList<>(); DesignCollectionItemVO designCollectionItemVO = new DesignCollectionItemVO(); @@ -750,7 +920,7 @@ public class DesignServiceImpl extends ServiceImpl impleme //生成designItem Long designItemId = designItemService.saveOne(designItem); //response - designCollectionItems.add(new DesignCollectionItemVO(designItemId, designItem.getDesignUrl(), null, null)); + designCollectionItems.add(new DesignCollectionItemVO(designItemId, designItem.getDesignUrl(), null, null, null)); List designItemDetails = Lists.newArrayList(); item.getItems().forEach(detail -> { @@ -797,7 +967,7 @@ public class DesignServiceImpl extends ServiceImpl impleme } @Override - public DesignCollectionVO reDesignCollection(ReDesignCollectionDTO reDesignDTO) { + public String reDesignCollection(ReDesignCollectionDTO reDesignDTO) { //校验collection Collection collection = collectionService.getById(reDesignDTO.getCollectionId()); if (Objects.isNull(collection)) { @@ -849,15 +1019,15 @@ public class DesignServiceImpl extends ServiceImpl impleme } List designItems = designItemService.getByDesignId(designId); if (CollectionUtils.isEmpty(designItems)) { - return new DesignCollectionVO(designId, design.getCollectionId(), null, null); + return new DesignCollectionVO(designId, design.getCollectionId(), null, null, null); } - return new DesignCollectionVO(designId, design.getCollectionId(), coverDesignItemToVO(designItems), null); + return new DesignCollectionVO(designId, design.getCollectionId(), coverDesignItemToVO(designItems), null, null); } private List coverDesignItemToVO(List designItems) { List response = Lists.newArrayList(); designItems.forEach(designItem -> { - response.add(new DesignCollectionItemVO(designItem.getId(), designItem.getDesignUrl(), null, null)); + response.add(new DesignCollectionItemVO(designItem.getId(), designItem.getDesignUrl(), null, null, null)); }); return response; } @@ -1389,4 +1559,62 @@ public class DesignServiceImpl extends ServiceImpl impleme } } + @Override + @Transactional(rollbackFor = Exception.class) + public Boolean receiveDesignResults(JSONObject responseJSONObject) { + String requestId = "UUID.randomUUID().toString()"; +// String requestId = responseJSONObject.getString("requestId"); + Map context; + synchronized (designContext) { + log.info(designContext.toString()); + context = designContext.get(requestId); + if (context == null) { + log.error("上下文数据缺失,无法完成操作"); + return false; + } + + DesignPythonObjects pythonObjects = (DesignPythonObjects) context.get("pythonObjects"); + Long designId = (Long) context.get("designId"); + Long collectionId = (Long) context.get("collectionId"); + AuthPrincipalVo userInfo = (AuthPrincipalVo) context.get("userInfo"); + String timeZone = (String) context.get("timeZone"); + String singleOverall = (String) context.get("singleOverall"); + + DesignCollectionVO designCollectionVO = savePythonDesignItemAndDetailSingle(pythonObjects, designId, collectionId, userInfo, timeZone, responseJSONObject, singleOverall, context); + + log.info(designContext.toString()); + designContext.put(requestId, context); + } + + return Boolean.TRUE; + } + + @Override + public DesignCollectionVO getDesignResult(String requestId, List objectSignList) { +// Map stringObjectMap = designContext.get("UUID.randomUUID().toString()"); + Map stringObjectMap = designContext.get(requestId); + log.info(stringObjectMap.toString()); + DesignCollectionVO result = (DesignCollectionVO) stringObjectMap.get("DesignCollectionVO"); + if (Objects.isNull(result)) { + DesignCollectionVO noneResult = new DesignCollectionVO(); + noneResult.setUnfinishedList(objectSignList); + return noneResult; + } + for (DesignCollectionItemVO designCollectionItem : result.getDesignCollectionItems()) { + String objectSign = designCollectionItem.getObjectSign(); + objectSignList.remove(objectSign); + } + result.setUnfinishedList(objectSignList); + return result; + } + + @Override + public String designCloud(DesignCollectionDTO designDTO) { + AuthPrincipalVo userInfo = UserContext.getUserHolder(); + //校验collection element + ValidateElementVO elementVO = collectionElementService.validateElement(designDTO); + //design + return designOrRedesignOperateNew(designDTO, userInfo, null, elementVO); + } + } diff --git a/src/main/java/com/ai/da/service/impl/UserLikeGroupServiceImpl.java b/src/main/java/com/ai/da/service/impl/UserLikeGroupServiceImpl.java index 2c51cfa6..8f3e6dbf 100644 --- a/src/main/java/com/ai/da/service/impl/UserLikeGroupServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/UserLikeGroupServiceImpl.java @@ -9,7 +9,9 @@ import com.ai.da.common.utils.*; import com.ai.da.mapper.primary.*; import com.ai.da.mapper.primary.entity.*; import com.ai.da.mapper.secondary.AttributeRetrievalMapper; +import com.ai.da.mapper.secondary.entity.AttributeRecognitionJSON; import com.ai.da.model.dto.PortfolioDTO; +import com.ai.da.model.dto.ProductImageInitializeDTO; import com.ai.da.model.dto.ProductImageLikeDTO; import com.ai.da.model.dto.ToProductImageDTO; import com.ai.da.model.vo.*; @@ -79,6 +81,8 @@ public class UserLikeGroupServiceImpl extends ServiceImpl Date: Mon, 9 Dec 2024 16:53:29 +0800 Subject: [PATCH 09/91] =?UTF-8?q?Affiliate-=E6=96=B0=E5=A2=9E=E3=80=81?= =?UTF-8?q?=E6=9F=A5=E8=AF=A2=E3=80=81=E4=BD=A3=E9=87=91=E8=AE=A1=E7=AE=97?= =?UTF-8?q?=E7=AD=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ai/da/common/constant/CommonConstant.java | 2 + .../com/ai/da/common/utils/RedisUtil.java | 14 ++ .../com/ai/da/common/utils/SendEmailUtil.java | 120 ++++++++--- .../ai/da/controller/AffiliateController.java | 63 ++++++ .../ai/da/controller/ElementController.java | 2 + .../ai/da/controller/StripeController.java | 6 + .../ai/da/mapper/primary/AffiliateMapper.java | 7 + .../ai/da/mapper/primary/entity/Account.java | 3 + .../da/mapper/primary/entity/Affiliate.java | 28 +++ .../da/mapper/primary/entity/OrderInfo.java | 5 + .../da/model/dto/AffiliateEmailParamsDTO.java | 31 +++ .../ai/da/model/dto/AffiliateQueryDTO.java | 13 ++ .../dto/GenerateThroughImageTextDTO.java | 31 +-- .../com/ai/da/model/dto/TimeQueryBaseDTO.java | 19 ++ .../java/com/ai/da/model/vo/AffiliateVO.java | 15 ++ .../com/ai/da/service/AffiliateService.java | 22 ++ .../java/com/ai/da/service/StripeService.java | 4 + .../da/service/impl/AffiliateServiceImpl.java | 189 ++++++++++++++++++ .../impl/CollectionElementServiceImpl.java | 4 +- .../service/impl/PaymentInfoServiceImpl.java | 12 +- .../ai/da/service/impl/StripeServiceImpl.java | 28 ++- 21 files changed, 561 insertions(+), 57 deletions(-) create mode 100644 src/main/java/com/ai/da/controller/AffiliateController.java create mode 100644 src/main/java/com/ai/da/mapper/primary/AffiliateMapper.java create mode 100644 src/main/java/com/ai/da/mapper/primary/entity/Affiliate.java create mode 100644 src/main/java/com/ai/da/model/dto/AffiliateEmailParamsDTO.java create mode 100644 src/main/java/com/ai/da/model/dto/AffiliateQueryDTO.java create mode 100644 src/main/java/com/ai/da/model/dto/TimeQueryBaseDTO.java create mode 100644 src/main/java/com/ai/da/model/vo/AffiliateVO.java create mode 100644 src/main/java/com/ai/da/service/AffiliateService.java create mode 100644 src/main/java/com/ai/da/service/impl/AffiliateServiceImpl.java diff --git a/src/main/java/com/ai/da/common/constant/CommonConstant.java b/src/main/java/com/ai/da/common/constant/CommonConstant.java index e495ee26..cd019602 100644 --- a/src/main/java/com/ai/da/common/constant/CommonConstant.java +++ b/src/main/java/com/ai/da/common/constant/CommonConstant.java @@ -79,5 +79,7 @@ public class CommonConstant { public static final String TIME_FORMAT_MMM_dd_yyyy = "MMM. dd, yyyy"; + public static final String AFFILIATE_LINK = ""; + } diff --git a/src/main/java/com/ai/da/common/utils/RedisUtil.java b/src/main/java/com/ai/da/common/utils/RedisUtil.java index 7d5295dc..d3ba2a93 100644 --- a/src/main/java/com/ai/da/common/utils/RedisUtil.java +++ b/src/main/java/com/ai/da/common/utils/RedisUtil.java @@ -278,4 +278,18 @@ public class RedisUtil { // 设置过期时间为 5 分钟(300 秒) redisTemplate.expire(redisKey, 5, TimeUnit.MINUTES); } + + public final static String PAYMENT_INFO_LAST_SCAN_TIME = "PaymentInfoLastScanTime:"; + + public final static String AFFILIATE_LINK_VIEW_KEY = "AffiliateLink:view:"; + + public void increaseAffiliateLinkViewCount(Long accountId) { + String key = AFFILIATE_LINK_VIEW_KEY + accountId; + redisTemplate.opsForValue().increment(key); + } + + public Long getAffiliateLinkViewCount(Long accountId) { + String key = AFFILIATE_LINK_VIEW_KEY + accountId; + return redisTemplate.opsForValue().increment(key, 0); + } } diff --git a/src/main/java/com/ai/da/common/utils/SendEmailUtil.java b/src/main/java/com/ai/da/common/utils/SendEmailUtil.java index b14cd28a..490b598f 100644 --- a/src/main/java/com/ai/da/common/utils/SendEmailUtil.java +++ b/src/main/java/com/ai/da/common/utils/SendEmailUtil.java @@ -2,6 +2,7 @@ package com.ai.da.common.utils; import com.ai.da.mapper.primary.entity.Account; import com.ai.da.mapper.primary.entity.TrialOrder; +import com.ai.da.model.dto.AffiliateEmailParamsDTO; import com.ai.da.model.dto.SubscriptionEmailParamsDTO; import com.alibaba.fastjson.JSONObject; import com.ai.da.common.config.exception.BusinessException; @@ -177,7 +178,7 @@ public class SendEmailUtil { subject = "Approval Confirmation for AiDA System Trial Access"; if (country.equals("China")) { template.setTemplateID(NOTIFICATION_CHINESE_TEMPLATE_ID); - }else { + } else { template.setTemplateID(NOTIFICATION_TEMPLATE_ID); } template.setTemplateData(buildNotificationData(trialOrder, link)); @@ -227,7 +228,7 @@ public class SendEmailUtil { attachment.setFileName(fileName); // 设置附件文件名 // 设置附件内容 attachment.setContent(Base64.getEncoder().encodeToString(fileContent)); - req.setAttachments(new Attachment[] {attachment}); + req.setAttachments(new Attachment[]{attachment}); // 发送邮件 SendEmailResponse resp = client.SendEmail(req); log.info("短信发送结果res###{}", SendEmailResponse.toJsonString(resp)); @@ -270,7 +271,9 @@ public class SendEmailUtil { throw new BusinessException("failed.to.send.mail"); } } + private final static Long WILLBEEXPIRED_TEMPLATE_ID = 118178L; + public static void sendWillBeExpiredEmail(Account account, String senderAddress) { try { // 实例化一个认证对象 @@ -362,7 +365,7 @@ public class SendEmailUtil { jsonObject.put("email", trialOrder.getEmail()); if (link) { jsonObject.put("days", 14); - }else { + } else { jsonObject.put("days", 5); } return jsonObject.toJSONString(); @@ -372,6 +375,7 @@ public class SendEmailUtil { private final static Long UPGRADE_SUCCESS_NOTIFICATION_ID = 118856L; private final static Long UPGRADE_NOTIFICATION_ID_CHINESE = 122898L; private final static Long UPGRADE_SUCCESS_NOTIFICATION_ID_CHINESE = 122899L; + public static void sendUpgradeNotification(Account account, String senderAddress, Integer type) { try { // 实例化一个认证对象 @@ -394,7 +398,7 @@ public class SendEmailUtil { if (type == 1) { subject = "Upcoming System Upgrade for AiDA 3.0"; template.setTemplateID(UPGRADE_NOTIFICATION_ID); - }else { + } else { subject = "即将到来的AiDA 3.0系统升级"; template.setTemplateID(UPGRADE_NOTIFICATION_ID_CHINESE); } @@ -420,7 +424,8 @@ public class SendEmailUtil { } private final static Long GENERATE_EXCEPTION_WARNING_ID = 122589L; - public static void sendGenerateExceptionWarning(String message){ + + public static void sendGenerateExceptionWarning(String message) { try { // 实例化一个认证对象 Credential cred = new Credential(SECRET_ID, SECRET_KEy); @@ -459,7 +464,8 @@ public class SendEmailUtil { private final static Long QUESTIONNAIRE_FEEDBACK_EN_ID = 124151L; private final static Long QUESTIONNAIRE_FEEDBACK_CN_ID = 124156L; - public static void questionnaireRelatedNotify(String userName, String email, String language){ + + public static void questionnaireRelatedNotify(String userName, String email, String language) { try { // 实例化一个认证对象 Credential cred = new Credential(SECRET_ID, SECRET_KEy); @@ -504,7 +510,7 @@ public class SendEmailUtil { private final static Long RENEWAL_NOTIFICATION_FOR_OLD_USER_EN = 124892L; private final static Long RENEWAL_NOTIFICATION_FOR_OLD_USER_CN = 124891L; - public static void notificationForPaidUser(String receiverAddress, int emailType, String country, String userName, String date){ + public static void notificationForPaidUser(String receiverAddress, int emailType, String country, String userName, String date) { try { // 实例化一个认证对象 Credential cred = new Credential(SECRET_ID, SECRET_KEy); @@ -527,7 +533,7 @@ public class SendEmailUtil { subject = "Welcome to AiDA!"; if (country.equals("China")) { template.setTemplateID(NEW_USER_PAYMENT_NOTIFICATION_CN); - }else { + } else { template.setTemplateID(NEW_USER_PAYMENT_NOTIFICATION_EN); } parameter.put("userName", userName); @@ -538,7 +544,7 @@ public class SendEmailUtil { subject = "Account renewal notification"; if (country.equals("China")) { template.setTemplateID(RENEWAL_NOTIFICATION_FOR_OLD_USER_CN); - }else { + } else { template.setTemplateID(RENEWAL_NOTIFICATION_FOR_OLD_USER_EN); } break; @@ -599,8 +605,8 @@ public class SendEmailUtil { private final static Long NEW_USER_REGISTER_NOTIFICATION_EN = 126919L; - public static void notificationForRegisterUser(String receiverAddress){ - try{ + public static void notificationForRegisterUser(String receiverAddress) { + try { // 实例化一个认证对象,入参需要传入腾讯云账户 SecretId 和 SecretKey,此处还需注意密钥对的保密 // 代码泄露可能会导致 SecretId 和 SecretKey 泄露,并威胁账号下所有资源的安全性。以下代码示例仅供参考,建议采用更安全的方式来使用密钥,请参见:https://cloud.tencent.com/document/product/1278/85305 // 密钥可前往官网控制台 https://console.cloud.tencent.com/cam/capi 进行获取 @@ -636,8 +642,8 @@ public class SendEmailUtil { private final static Long CHANGE_MAILBOX_CONFIRM_CN = 128278L; private final static Long CHANGE_MAILBOX_CONFIRM_EN = 128277L; - public static void changeMailboxConfirm(String receiverAddress, String language, String name, String link){ - try{ + public static void changeMailboxConfirm(String receiverAddress, String language, String name, String link) { + try { // 实例化一个认证对象,入参需要传入腾讯云账户 SecretId 和 SecretKey,此处还需注意密钥对的保密 // 代码泄露可能会导致 SecretId 和 SecretKey 泄露,并威胁账号下所有资源的安全性。以下代码示例仅供参考,建议采用更安全的方式来使用密钥,请参见:https://cloud.tencent.com/document/product/1278/85305 // 密钥可前往官网控制台 https://console.cloud.tencent.com/cam/capi 进行获取 @@ -655,10 +661,10 @@ public class SendEmailUtil { req.setFromEmailAddress(SEND_ADDRESS); req.setDestination(new String[]{receiverAddress}); Template template = new Template(); - if (language.equals("ENGLISH")){ + if (language.equals("ENGLISH")) { req.setSubject("Change the email address bound to the AiDA account"); template.setTemplateID(CHANGE_MAILBOX_CONFIRM_EN); - }else { + } else { req.setSubject("更换AiDA账号绑定的邮箱地址"); template.setTemplateID(CHANGE_MAILBOX_CONFIRM_CN); } @@ -680,12 +686,12 @@ public class SendEmailUtil { private final static Long UPLOAD_TIMEOUT_REMINDER = 128324L; - public static void uploadTimeoutReminder(String userName, String time){ + 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{ + try { // 实例化一个认证对象,入参需要传入腾讯云账户 SecretId 和 SecretKey,此处还需注意密钥对的保密 // 代码泄露可能会导致 SecretId 和 SecretKey 泄露,并威胁账号下所有资源的安全性。以下代码示例仅供参考,建议采用更安全的方式来使用密钥,请参见:https://cloud.tencent.com/document/product/1278/85305 // 密钥可前往官网控制台 https://console.cloud.tencent.com/cam/capi 进行获取 @@ -723,6 +729,7 @@ public class SendEmailUtil { private final static Long HALFPRICEPROMOTION_CN_ID = 128582L; private final static Long HALFPRICEPROMOTION_EN_ID = 128583L; + public static void halfPricePromotion(Account account, String senderAddress, int type) { try { // 实例化一个认证对象 @@ -752,7 +759,7 @@ public class SendEmailUtil { if (type == 1) { subject = "AiDA workshop - Win a trip to Hong Kong!"; template.setTemplateID(HALFPRICEPROMOTION_EN_ID); - }else { + } else { subject = "AiDA workshop - 赢取香港之旅"; template.setTemplateID(HALFPRICEPROMOTION_CN_ID); } @@ -784,8 +791,8 @@ public class SendEmailUtil { private final static Long PAYMENT_FAILED_RENEWAL_USER_EN = 131563L; private final static Long PAYMENT_FAILED_RENEWAL_USER_CN = 131564L; - public static void subscriptionEmailReminder(String type, SubscriptionEmailParamsDTO subscriptionEmailParamsDTO, String language, String receiverAddress){ - try{ + public static void subscriptionEmailReminder(String type, SubscriptionEmailParamsDTO subscriptionEmailParamsDTO, String language, String receiverAddress) { + try { // String merchantEmail = "kimwong@code-create.com.hk"; String merchantEmail = "xupei3360@163.com"; Credential cred = new Credential(SECRET_ID, SECRET_KEy); @@ -819,10 +826,10 @@ public class SendEmailUtil { merchant.setSubject("[Code-Create] Payment Failed : Renewal Order (" + subscriptionEmailParamsDTO.getOrderId() + ")"); templateMerchant.setTemplateID(PAYMENT_FAILED_RENEWAL_MERCHANT_EN); // todo to user - if (language.equals("ENGLISH")){ + if (language.equals("ENGLISH")) { user.setSubject("[Code-Create] Payment Failed : Renewal Order (" + subscriptionEmailParamsDTO.getOrderId() + ")"); templateUser.setTemplateID(PAYMENT_FAILED_RENEWAL_USER_EN); - }else { + } else { user.setSubject("[Code-Create] 自动续费失败 (" + subscriptionEmailParamsDTO.getOrderId() + ")"); templateUser.setTemplateID(PAYMENT_FAILED_RENEWAL_USER_CN); } @@ -830,10 +837,10 @@ public class SendEmailUtil { case "new": merchant.setSubject("[Code-Create] New Order(" + subscriptionEmailParamsDTO.getOrderId() + ")"); templateMerchant.setTemplateID(NEW_MERCHANT_EN); - if (language.equals("ENGLISH")){ + if (language.equals("ENGLISH")) { user.setSubject("[Code-Create] You have successfully subscribed to AiDA"); templateUser.setTemplateID(NEW_USER_EN); - }else { + } else { user.setSubject("[Code-Create] 您已成功订阅AiDA"); templateUser.setTemplateID(NEW_USER_CN); } @@ -841,19 +848,19 @@ public class SendEmailUtil { case "renewal": merchant.setSubject("[Code-Create] New subscription renewal order (" + subscriptionEmailParamsDTO.getOrderId() + ")"); templateMerchant.setTemplateID(RENEWAL_MERCHANT_EN); - if (language.equals("ENGLISH")){ + if (language.equals("ENGLISH")) { user.setSubject("[Code-Create] AiDA Renewal Successful"); templateUser.setTemplateID(RENEWAL_USER_EN); - }else { + } else { user.setSubject("[Code-Create] AiDA续订成功"); templateUser.setTemplateID(RENEWAL_USER_CN); } break; case "reminder": - if (language.equals("ENGLISH")){ + if (language.equals("ENGLISH")) { user.setSubject("[Code-Create] AiDA Subscription Renewal Reminder"); templateUser.setTemplateID(RENEWAL_REMINDER_USER_EN); - }else { + } else { user.setSubject("[Code-Create] AiDA续订提醒"); templateUser.setTemplateID(RENEWAL_REMINDER_USER_CN); } @@ -869,12 +876,12 @@ public class SendEmailUtil { templateMerchant.setTemplateData(JSON.toJSONString(subscriptionEmailParamsDTO)); merchant.setTemplate(templateMerchant); - if (!type.equals("cancel") && !type.equals("fail_new") ){ + if (!type.equals("cancel") && !type.equals("fail_new")) { // 返回的resp是一个SendEmailResponse的实例,与请求对象对应 SendEmailResponse respUser = client.SendEmail(user); log.info("邮件主题:{},发送结果toUser###{}", user.getSubject(), SendEmailResponse.toJsonString(respUser)); } - if (!type.equals("reminder")){ + if (!type.equals("reminder")) { SendEmailResponse respMerchant = client.SendEmail(merchant); log.info("邮件主题:{},发送结果toMerchant###{}", merchant.getSubject(), SendEmailResponse.toJsonString(respMerchant)); } @@ -883,4 +890,57 @@ public class SendEmailUtil { throw new BusinessException("failed.to.send.mail"); } } + + private final static Long NEW_REGISTRATION = 132123L; + private final static Long AFFILIATE_ACCEPTED = 132124L; + private final static Long AFFILIATE_REFUSED = 132125L; + private final static Long AFFILIATE_MONTHLY_SUMMARY = 132126L; + + public static void affiliateEmailReminder(String receiverAddress, AffiliateEmailParamsDTO paramsDTO, String type) { + try { + Credential cred = new Credential(SECRET_ID, SECRET_KEy); + // 实例化一个http选项,可选的,没有特殊需求可以跳过 + HttpProfile httpProfile = new HttpProfile(); + httpProfile.setEndpoint("ses.tencentcloudapi.com"); + // 实例化一个client选项,可选的,没有特殊需求可以跳过 + ClientProfile clientProfile = new ClientProfile(); + clientProfile.setHttpProfile(httpProfile); + // 实例化要请求产品的client对象,clientProfile是可选的 + SesClient client = new SesClient(cred, "ap-hongkong", clientProfile); + // 实例化一个请求对象,每个接口都会对应一个request对象 + SendEmailRequest req = new SendEmailRequest(); + req.setFromEmailAddress(SEND_ADDRESS); + req.setDestination(new String[]{receiverAddress}); + Template template = new Template(); + switch (type) { + case "new": + req.setSubject("New Affiliate Registration"); + template.setTemplateID(NEW_REGISTRATION); + break; + case "accepted": + req.setSubject("Affiliate Application Accepted"); + template.setTemplateID(AFFILIATE_ACCEPTED); + break; + case "refused": + req.setSubject("Affiliate Application Refused"); + template.setTemplateID(AFFILIATE_REFUSED); + break; + case "summary": + req.setSubject("Your Monthly AffiliateWP Summary for AiDA"); + template.setTemplateID(AFFILIATE_MONTHLY_SUMMARY); + break; + } + + template.setTemplateData(JSON.toJSONString(paramsDTO)); + req.setTemplate(template); + + // 返回的resp是一个SendEmailResponse的实例,与请求对象对应 + SendEmailResponse resp = client.SendEmail(req); + log.info("短信发送结果res###{}", SendEmailResponse.toJsonString(resp)); + } catch (TencentCloudSDKException e) { + log.info("邮件发送失败###{}", e.toString()); + throw new BusinessException("failed.to.send.mail"); + } + } + } diff --git a/src/main/java/com/ai/da/controller/AffiliateController.java b/src/main/java/com/ai/da/controller/AffiliateController.java new file mode 100644 index 00000000..4e55ce71 --- /dev/null +++ b/src/main/java/com/ai/da/controller/AffiliateController.java @@ -0,0 +1,63 @@ +package com.ai.da.controller; + + +import com.ai.da.common.response.Response; +import com.ai.da.mapper.primary.entity.Affiliate; +import com.ai.da.model.dto.AffiliateQueryDTO; +import com.ai.da.model.vo.AffiliateVO; +import com.ai.da.service.AffiliateService; +import com.baomidou.mybatisplus.core.metadata.IPage; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; + +@Slf4j +@RestController +@RequestMapping("/api/affiliate") +public class AffiliateController { + + @Resource + private AffiliateService affiliateService; + + @ApiOperation(value = "注册成为affiliate") + @GetMapping("/registration") + public Response completeGuidance(@RequestParam("promotionMethod") String promotionMethod) { + return Response.success(affiliateService.registerAsAnAffiliate(promotionMethod)); + } + + @ApiOperation(value = "获取affiliate列表") + @PostMapping("/list") + public Response> getAffiliateList(@Valid @RequestBody AffiliateQueryDTO affiliateQueryDTO) { + return Response.success(affiliateService.getAffiliateList(affiliateQueryDTO)); + } + + @ApiOperation(value = "获取affiliate个人中心") + @GetMapping("/personalCenter") + public Response personalAffiliateCenter() { + return Response.success(affiliateService.personalAffiliateCenter()); + } + + @ApiOperation(value = "审批affiliate申请") + @GetMapping("/approval") + public Response applicationApproval(@RequestParam("id") Long id, @RequestParam("isApproved")Boolean isApproved) { + return Response.success(affiliateService.applicationApproval(id, isApproved)); + } + + @ApiOperation(value = "审批affiliate申请") + @GetMapping("/testTask") + public Response testTask() { + affiliateService.updateAffiliateInfoWithPayment(); + return Response.success("success "); + } + + @ApiOperation(value = "affiliate链接浏览量增加") + @GetMapping("/viewsIncrease") + public Response viewsGet(@RequestParam("id") Long id) { + return Response.success(affiliateService.affiliateLinkViewsIncrease(id)); + } + + +} diff --git a/src/main/java/com/ai/da/controller/ElementController.java b/src/main/java/com/ai/da/controller/ElementController.java index 40dbcde1..8065c6dc 100644 --- a/src/main/java/com/ai/da/controller/ElementController.java +++ b/src/main/java/com/ai/da/controller/ElementController.java @@ -66,6 +66,8 @@ public class ElementController { return Response.success(); } + /** 该功能已删除 */ + @Deprecated @ApiOperation(value = "生成印花") @PostMapping("/generatePrint") public Response generatePrint(@Valid @RequestBody CollectionGeneratePrintDTO generatePrintDTO) { diff --git a/src/main/java/com/ai/da/controller/StripeController.java b/src/main/java/com/ai/da/controller/StripeController.java index 8becf26b..21c91a86 100644 --- a/src/main/java/com/ai/da/controller/StripeController.java +++ b/src/main/java/com/ai/da/controller/StripeController.java @@ -99,4 +99,10 @@ public class StripeController { return Response.success(stripeService.sendRenewalFailEmail(invoiceId, subscriptionId,orderNo)); } + @ApiOperation("临时 查询指定用户绑定的付款方式") + @GetMapping("/getCustomerPaymentMethod") + public Response getCustomerPaymentMethod(@RequestParam String name, @RequestParam String email) { + return Response.success(stripeService.getCustomerPaymentMethod(name, email)); + } + } diff --git a/src/main/java/com/ai/da/mapper/primary/AffiliateMapper.java b/src/main/java/com/ai/da/mapper/primary/AffiliateMapper.java new file mode 100644 index 00000000..314a0952 --- /dev/null +++ b/src/main/java/com/ai/da/mapper/primary/AffiliateMapper.java @@ -0,0 +1,7 @@ +package com.ai.da.mapper.primary; + +import com.ai.da.mapper.primary.entity.Affiliate; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +public interface AffiliateMapper extends BaseMapper { +} diff --git a/src/main/java/com/ai/da/mapper/primary/entity/Account.java b/src/main/java/com/ai/da/mapper/primary/entity/Account.java index 285acd90..60fcc9f0 100644 --- a/src/main/java/com/ai/da/mapper/primary/entity/Account.java +++ b/src/main/java/com/ai/da/mapper/primary/entity/Account.java @@ -104,4 +104,7 @@ public class Account implements Serializable { * 头像 */ private String avatar; + + private Long invitationCode; + } diff --git a/src/main/java/com/ai/da/mapper/primary/entity/Affiliate.java b/src/main/java/com/ai/da/mapper/primary/entity/Affiliate.java new file mode 100644 index 00000000..56204d75 --- /dev/null +++ b/src/main/java/com/ai/da/mapper/primary/entity/Affiliate.java @@ -0,0 +1,28 @@ +package com.ai.da.mapper.primary.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@EqualsAndHashCode(callSuper = true) +@Data +@TableName("t_affiliate") +public class Affiliate extends BaseEntity{ + + private Long accountId; + + // Active(活跃) || Inactive(过期) || Pending(待审批) || Refused(拒绝) + private String status; + + private Float totalEarnings = 0.00F; + + private Float monthlyEarnings = 0.00F; + + private Float unpaidEarnings = 0.00F; + + private Integer visits = 0; + + private Boolean approved = false; + + private String link; +} diff --git a/src/main/java/com/ai/da/mapper/primary/entity/OrderInfo.java b/src/main/java/com/ai/da/mapper/primary/entity/OrderInfo.java index e5bc0a98..04a9d894 100644 --- a/src/main/java/com/ai/da/mapper/primary/entity/OrderInfo.java +++ b/src/main/java/com/ai/da/mapper/primary/entity/OrderInfo.java @@ -24,4 +24,9 @@ public class OrderInfo extends BaseEntity{ private String note; private String paymentType;//支付方式 + + // 可用于标记用户订单是否首次订阅 + private byte isFirstSubscription = 0; + + private byte isCommissionCalculated = 0; } diff --git a/src/main/java/com/ai/da/model/dto/AffiliateEmailParamsDTO.java b/src/main/java/com/ai/da/model/dto/AffiliateEmailParamsDTO.java new file mode 100644 index 00000000..38c87b72 --- /dev/null +++ b/src/main/java/com/ai/da/model/dto/AffiliateEmailParamsDTO.java @@ -0,0 +1,31 @@ +package com.ai.da.model.dto; + +import lombok.Data; + +@Data +public class AffiliateEmailParamsDTO { + + private String username; + + private String promotionMethod; + + private String totalProgramRevenue; + + private String newApprovedAffiliates; + + private String unpaidEarnings; + + private String paidEarnings; + + public AffiliateEmailParamsDTO() { + } + + public AffiliateEmailParamsDTO(String username) { + this.username = username; + } + + public AffiliateEmailParamsDTO(String username, String promotionMethod) { + this.username = username; + this.promotionMethod = promotionMethod; + } +} diff --git a/src/main/java/com/ai/da/model/dto/AffiliateQueryDTO.java b/src/main/java/com/ai/da/model/dto/AffiliateQueryDTO.java new file mode 100644 index 00000000..5498964b --- /dev/null +++ b/src/main/java/com/ai/da/model/dto/AffiliateQueryDTO.java @@ -0,0 +1,13 @@ +package com.ai.da.model.dto; + +import io.swagger.annotations.ApiModel; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@EqualsAndHashCode(callSuper = true) +@Data +@ApiModel("查询affiliate列表") +public class AffiliateQueryDTO extends TimeQueryBaseDTO{ + + private String status; +} diff --git a/src/main/java/com/ai/da/model/dto/GenerateThroughImageTextDTO.java b/src/main/java/com/ai/da/model/dto/GenerateThroughImageTextDTO.java index 8dbeca50..772cb8cf 100644 --- a/src/main/java/com/ai/da/model/dto/GenerateThroughImageTextDTO.java +++ b/src/main/java/com/ai/da/model/dto/GenerateThroughImageTextDTO.java @@ -12,49 +12,50 @@ import javax.validation.constraints.NotNull; public class GenerateThroughImageTextDTO { @NotNull(message = "userId cannot be empty") @ApiModelProperty("用户id") - Long userId; + private Long userId; @ApiModelProperty("caption | prompt") - String text; + private String text; @ApiModelProperty("图片在t_collection_element表中的id") - Long collectionElementId; + private Long collectionElementId; // todo 后续取消这个字段的传输,由后端自行判断相关参数是否有值 // @NotBlank(message = "you have to choose the generate type") @ApiModelProperty("text image text-image") - String generateType; + private String generateType; @ApiModelProperty("图片来源:update,从library中选择,从toProductImage结果中选择 collection || library || productImage") - String designType; + private String designType; @NotBlank(message = "level1Type cannot be empty!") @ApiModelProperty("Moodboard Printboard Sketchboard MarketingSketch") - String level1Type; + private String level1Type; @ApiModelProperty("Outwear Dress Blouse Skirt Trousers || Logo Slogan Pattern") - String level2Type; + private String level2Type; @ApiModelProperty("性别") - String gender; + private String gender; - @ApiModelProperty("选择的模型名") - String version; + + @ApiModelProperty("选择的模型名 high || fast") + private String version; @NotBlank(message = "timeZone cannot be empty!") @ApiModelProperty("本地时区,比如 'Asia/Tokyo' 东京时间 , 'Asia/Shanghai' 北京时间 由js本地获取") - String timeZone; + private String timeZone; @ApiModelProperty("唯一id,用于保持消息唯一性") - String uniqueId; + private String uniqueId; @NotNull(message = "Please check if the required fields are empty.(isTestUser)") @ApiModelProperty("是否是测试用户") - Boolean isTestUser; + private Boolean isTestUser; @ApiModelProperty("页面上用户设计的slogan所截的图片") - String sloganBase64; + private String sloganBase64; @ApiModelProperty("种子 取值范围 0~500") - String seed; + private String seed; } diff --git a/src/main/java/com/ai/da/model/dto/TimeQueryBaseDTO.java b/src/main/java/com/ai/da/model/dto/TimeQueryBaseDTO.java new file mode 100644 index 00000000..3c10297b --- /dev/null +++ b/src/main/java/com/ai/da/model/dto/TimeQueryBaseDTO.java @@ -0,0 +1,19 @@ +package com.ai.da.model.dto; + +import com.ai.da.model.vo.PageQueryBaseVo; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@EqualsAndHashCode(callSuper = true) +@Data +@ApiModel("按时间查询") +public class TimeQueryBaseDTO extends PageQueryBaseVo { + + @ApiModelProperty("按时间区间查询 区间起点") + private String startTime; + + @ApiModelProperty("按时间区间查询 区间终点") + private String endTime; +} diff --git a/src/main/java/com/ai/da/model/vo/AffiliateVO.java b/src/main/java/com/ai/da/model/vo/AffiliateVO.java new file mode 100644 index 00000000..96177e1a --- /dev/null +++ b/src/main/java/com/ai/da/model/vo/AffiliateVO.java @@ -0,0 +1,15 @@ +package com.ai.da.model.vo; + +import com.ai.da.mapper.primary.entity.Affiliate; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class AffiliateVO extends Affiliate { + + private Long linkViewCount; + +} diff --git a/src/main/java/com/ai/da/service/AffiliateService.java b/src/main/java/com/ai/da/service/AffiliateService.java new file mode 100644 index 00000000..ed340ae4 --- /dev/null +++ b/src/main/java/com/ai/da/service/AffiliateService.java @@ -0,0 +1,22 @@ +package com.ai.da.service; + +import com.ai.da.mapper.primary.entity.Affiliate; +import com.ai.da.model.dto.AffiliateQueryDTO; +import com.ai.da.model.vo.AffiliateVO; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.IService; + +public interface AffiliateService extends IService { + + Boolean registerAsAnAffiliate(String promotionMethod); + + IPage getAffiliateList(AffiliateQueryDTO affiliateQueryDTO); + + AffiliateVO personalAffiliateCenter(); + + Boolean applicationApproval(Long id, Boolean isApproved); + + void updateAffiliateInfoWithPayment(); + + Boolean affiliateLinkViewsIncrease(Long id); +} diff --git a/src/main/java/com/ai/da/service/StripeService.java b/src/main/java/com/ai/da/service/StripeService.java index 268f08d2..f6f60dc3 100644 --- a/src/main/java/com/ai/da/service/StripeService.java +++ b/src/main/java/com/ai/da/service/StripeService.java @@ -19,6 +19,8 @@ public interface StripeService { List getSubscriptionIds(String name, String userEmail) throws StripeException; + Map getPaymentMethodByInvoiceId(String invoiceId); + void cancelSubscription(String orderNo); void cancelSubscriptionTemp(String subscriptionId); @@ -38,4 +40,6 @@ public interface StripeService { String changeCustomerPayment(String name, String email); boolean sendRenewalFailEmail(String invoiceId, String subscriptionId, String orderNo); + + String getCustomerPaymentMethod(String name, String email); } diff --git a/src/main/java/com/ai/da/service/impl/AffiliateServiceImpl.java b/src/main/java/com/ai/da/service/impl/AffiliateServiceImpl.java new file mode 100644 index 00000000..47f2a0b6 --- /dev/null +++ b/src/main/java/com/ai/da/service/impl/AffiliateServiceImpl.java @@ -0,0 +1,189 @@ +package com.ai.da.service.impl; + +import com.ai.da.common.config.exception.BusinessException; +import com.ai.da.common.constant.CommonConstant; +import com.ai.da.common.context.UserContext; +import com.ai.da.common.response.ResultEnum; +import com.ai.da.common.utils.CopyUtil; +import com.ai.da.common.utils.ObjectUtils; +import com.ai.da.common.utils.RedisUtil; +import com.ai.da.common.utils.SendEmailUtil; +import com.ai.da.mapper.primary.AffiliateMapper; +import com.ai.da.mapper.primary.entity.*; +import com.ai.da.model.dto.AffiliateEmailParamsDTO; +import com.ai.da.model.dto.AffiliateQueryDTO; +import com.ai.da.model.vo.AffiliateVO; +import com.ai.da.model.vo.AuthPrincipalVo; +import com.ai.da.service.AccountService; +import com.ai.da.service.AffiliateService; +import com.ai.da.service.OrderInfoService; +import com.ai.da.service.PaymentInfoService; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import io.netty.util.internal.StringUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; +import java.util.Objects; + +@Service +@Slf4j +public class AffiliateServiceImpl extends ServiceImpl implements AffiliateService { + + @Resource + private OrderInfoService orderInfoService; + + @Resource + private AccountService accountService; + + @Resource + private PaymentInfoService paymentInfoService; + + @Resource + private RedisUtil redisUtil; + + // 推广者注册 + public Boolean registerAsAnAffiliate(String promotionMethod){ + AuthPrincipalVo userHolder = UserContext.getUserHolder(); + // 判断该用户是否已注册 + QueryWrapper qw = new QueryWrapper<>(); + qw.eq("account_id", userHolder.getId()); + Affiliate affiliate = baseMapper.selectOne(qw); + if (Objects.isNull(affiliate)){ + affiliate = new Affiliate(); + affiliate.setAccountId(userHolder.getId()); + affiliate.setStatus("Pending"); + affiliate.setCreateTime(LocalDateTime.now()); + baseMapper.insert(affiliate); + // 邮件通知审批者 +// String email = "kimwong@code-create.com.hk"; + String email = "xupei3360@163.com"; + SendEmailUtil.affiliateEmailReminder(email, new AffiliateEmailParamsDTO(userHolder.getUsername(), promotionMethod), "new"); + }else { + throw new BusinessException("You have registered an Affiliate", ResultEnum.PROMPT.getCode()); + } + return true; + } + + public IPage getAffiliateList(AffiliateQueryDTO affiliateQueryDTO){ + QueryWrapper qw = new QueryWrapper<>(); + qw.eq(affiliateQueryDTO.getStatus() != null, "status", affiliateQueryDTO.getStatus()); + qw.gt(affiliateQueryDTO.getStartTime() != null, "create_time", affiliateQueryDTO.getStartTime()); + qw.lt(affiliateQueryDTO.getEndTime() != null, "create_time", affiliateQueryDTO.getEndTime()); + return baseMapper.selectPage(new Page<>(affiliateQueryDTO.getPage(), affiliateQueryDTO.getSize()), qw); + } + + public AffiliateVO personalAffiliateCenter(){ + QueryWrapper qw = new QueryWrapper<>(); + Long accountId = UserContext.getUserHolder().getId(); + qw.eq("account_id", accountId); + Affiliate affiliate = baseMapper.selectOne(qw); + AffiliateVO affiliateVO = CopyUtil.copyObject(affiliate, AffiliateVO.class); + affiliateVO.setLinkViewCount(getAffiliateLinkViewCount(accountId)); + return affiliateVO; + } + + // 审批申请 + public Boolean applicationApproval(Long id, Boolean isApproved){ + Affiliate affiliate = baseMapper.selectById(id); + + // 1、更新db状态 + if (isApproved){ + // 更新状态 + affiliate.setStatus("Active"); + affiliate.setApproved(true); + affiliate.setLink(CommonConstant.AFFILIATE_LINK + affiliate.getId()); + } else { + affiliate.setStatus("Inactive"); + affiliate.setApproved(false); + } + affiliate.setUpdateTime(LocalDateTime.now()); + + // 2、将批准结果邮件通知用户 + Account account = accountService.getById(affiliate.getAccountId()); + String userEmail = account.getUserEmail(); + String userName = account.getUserName(); + if (isApproved){ + SendEmailUtil.affiliateEmailReminder(userEmail, new AffiliateEmailParamsDTO(userName), "accepted"); + }else { + SendEmailUtil.affiliateEmailReminder(userEmail, new AffiliateEmailParamsDTO(userName), "refused"); + } + return true; + } + + // 定时计算佣金 + public void updateAffiliateInfoWithPayment(){ + // id存redis + String lastTime = redisUtil.getFromString(RedisUtil.PAYMENT_INFO_LAST_SCAN_TIME); + String currentTime = LocalDateTime.now().toString(); + // 1、查上次更新之后有无新订单 + QueryWrapper queryWrapper = new QueryWrapper<>(); + if (!StringUtil.isNullOrEmpty(lastTime)){ + queryWrapper.gt("create_time", lastTime); + } + queryWrapper.eq("type","new").eq("trade_state", "paid"); + + List paymentInfos = paymentInfoService.getBaseMapper().selectList(queryWrapper); + if (!paymentInfos.isEmpty()){ + paymentInfos.forEach(paymentInfo -> { + // 2、根据order_no查付款用户id + OrderInfo orderInfo = orderInfoService.getOrderByOrderNo(paymentInfo.getOrderNo()); + Long accountId = orderInfo.getAccountId(); + // 3、查该用户之前是否有初次订阅的订单 + QueryWrapper qwOrderInfo = new QueryWrapper<>(); + qwOrderInfo.eq("account_id", accountId).eq("is_first_subscription", 1); + List orderInfos = orderInfoService.getBaseMapper().selectList(qwOrderInfo); + // 该用户首次订阅(非首次订阅,不分配佣金) + if (orderInfos.isEmpty()){ + // 查询是否绑定affiliateId + Account account = accountService.getById(accountId); + if (!Objects.isNull(account.getInvitationCode())){ + // 3、若有, 直接更新affiliate的所得 + Affiliate affiliate = baseMapper.selectById(account.getInvitationCode()); + Float payerTotal = paymentInfo.getPayerTotal(); + if (payerTotal > 0){ + // 分配新用户首次订阅所付费用的25%作为佣金 + BigDecimal commission = BigDecimal.valueOf(payerTotal).multiply(new BigDecimal("0.25")); + BigDecimal monthlyEarning = BigDecimal.valueOf(affiliate.getMonthlyEarnings()).add(commission); + BigDecimal unpaidEarnings = BigDecimal.valueOf(affiliate.getUnpaidEarnings()).add(commission); + int visits = affiliate.getVisits() + 1; + affiliate.setMonthlyEarnings(monthlyEarning.floatValue()); + affiliate.setUnpaidEarnings(unpaidEarnings.floatValue()); + affiliate.setVisits(visits); + affiliate.setUpdateTime(LocalDateTime.now()); + baseMapper.updateById(affiliate); + + orderInfo.setIsCommissionCalculated((byte)1); + } + } + orderInfo.setIsFirstSubscription((byte)1); + orderInfo.setUpdateTime(LocalDateTime.now()); + orderInfoService.updateById(orderInfo); + } + }); + } + redisUtil.addToString(RedisUtil.PAYMENT_INFO_LAST_SCAN_TIME, currentTime); + } + + public Boolean affiliateLinkViewsIncrease(Long id) { + redisUtil.increaseAffiliateLinkViewCount(id); + return Boolean.TRUE; + } + + private Long getAffiliateLinkViewCount(Long accountId) { + return redisUtil.getAffiliateLinkViewCount(accountId); + } + + // todo 每个月给kim发一封邮件统计本月的affiliate等的收入 + public void commissionCalculation(){ + + } + + +} diff --git a/src/main/java/com/ai/da/service/impl/CollectionElementServiceImpl.java b/src/main/java/com/ai/da/service/impl/CollectionElementServiceImpl.java index a6bcedc6..e0f86569 100644 --- a/src/main/java/com/ai/da/service/impl/CollectionElementServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/CollectionElementServiceImpl.java @@ -216,6 +216,8 @@ public class CollectionElementServiceImpl extends ServiceImpl implements PaymentInfoService { - private final StripeServiceImpl stripeServiceImpl; - - public PaymentInfoServiceImpl(StripeServiceImpl stripeServiceImpl) { - this.stripeServiceImpl = stripeServiceImpl; - } + @Resource + private StripeService stripeService; /** * 记录支付日志:微信支付 @@ -220,7 +218,7 @@ public class PaymentInfoServiceImpl extends ServiceImpl paymentMethod = stripeServiceImpl.getPaymentMethodByInvoiceId(invoiceId); + Map paymentMethod = stripeService.getPaymentMethodByInvoiceId(invoiceId); paymentInfo = new PaymentInfo(); paymentInfo.setOrderNo(orderNo); diff --git a/src/main/java/com/ai/da/service/impl/StripeServiceImpl.java b/src/main/java/com/ai/da/service/impl/StripeServiceImpl.java index 3e8238bc..35b44944 100644 --- a/src/main/java/com/ai/da/service/impl/StripeServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/StripeServiceImpl.java @@ -553,7 +553,8 @@ public class StripeServiceImpl implements StripeService { Subscription cancel = subscription.cancel(); cancel.getStatus(); } catch (StripeException e) { - throw new RuntimeException(e); + log.error(e.getMessage()); +// throw new RuntimeException(e); } } @@ -988,7 +989,8 @@ public class StripeServiceImpl implements StripeService { try { OrderInfo orderInfo = orderInfoService.createOrderByProductId(1, PayTypeEnum.STRIPE.getType(), ProductEnum.DailySubscription); - String paymentMethodCode = "pm_card_mastercard"; + String customerId = getCustomer(name, email); +/* String paymentMethodCode = "pm_card_mastercard"; PaymentMethod paymentMethod = PaymentMethod.retrieve(paymentMethodCode); String customerId = getCustomer(name, email); @@ -997,14 +999,14 @@ public class StripeServiceImpl implements StripeService { PaymentMethodAttachParams attachParams = PaymentMethodAttachParams.builder() .setCustomer(customerId) .build(); - paymentMethod.attach(attachParams); + paymentMethod.attach(attachParams);*/ // 设置默认付款方式 Customer updatedCustomer = Customer.retrieve(customerId); CustomerUpdateParams params = CustomerUpdateParams.builder() .setInvoiceSettings( CustomerUpdateParams.InvoiceSettings.builder() - .setDefaultPaymentMethod(paymentMethod.getId()) +// .setDefaultPaymentMethod(paymentMethod.getId()) .build() ) .build(); @@ -1064,4 +1066,22 @@ public class StripeServiceImpl implements StripeService { } } + public String getCustomerPaymentMethod(String name, String email){ + Stripe.apiKey = privateKey; + try { + String customerId = getCustomer(name, email); + Customer customer = Customer.retrieve(customerId); + PaymentMethodCollection paymentMethodCollection = customer.listPaymentMethods(); + List data = paymentMethodCollection.getData(); + + // todo 方向: 向用户添加了多种付款方式,更改默认的付款方式后,默认付款方式付款失败后是否自动使用其他付款方式付款? + // 如果是的,则需要删除能成功的付款方式,保留唯一失败的付款方式进行续订付款失败测试 + } catch (StripeException e) { + throw new RuntimeException(e); + } + return null; + } + + + } From 5dd1e10b613cb7d071812d730aac012823fb0abb Mon Sep 17 00:00:00 2001 From: xupei Date: Tue, 10 Dec 2024 10:09:21 +0800 Subject: [PATCH 10/91] to dev --- .../java/com/ai/da/common/config/MyTaskScheduler.java | 4 ++-- src/main/java/com/ai/da/common/task/AccountTask.java | 10 +++++----- src/main/java/com/ai/da/common/task/PaypalTask.java | 2 +- src/main/java/com/ai/da/common/task/StripeTask.java | 2 +- src/main/resources/application.properties | 4 ++-- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/ai/da/common/config/MyTaskScheduler.java b/src/main/java/com/ai/da/common/config/MyTaskScheduler.java index 95c55e9a..61e964ea 100644 --- a/src/main/java/com/ai/da/common/config/MyTaskScheduler.java +++ b/src/main/java/com/ai/da/common/config/MyTaskScheduler.java @@ -51,7 +51,7 @@ public class MyTaskScheduler { // 定时任务,每十五天执行一次 // @Scheduled(cron = "0 0 0 ? * MON") - @Scheduled(cron = "0 0 0 */15 * ?") +// @Scheduled(cron = "0 0 0 */15 * ?") public void checkExpiry() { // 检测正式用户是否快要过期 QueryWrapper qw = new QueryWrapper<>(); @@ -85,7 +85,7 @@ public class MyTaskScheduler { } } } - @Scheduled(cron = "0 0 9 * * ?") +// @Scheduled(cron = "0 0 9 * * ?") public void sendTrialOrderExcelToManagements() { // 获取前一天日期 LocalDate yesterday = LocalDate.now().minusDays(1); diff --git a/src/main/java/com/ai/da/common/task/AccountTask.java b/src/main/java/com/ai/da/common/task/AccountTask.java index 6950878d..cfc65fd4 100644 --- a/src/main/java/com/ai/da/common/task/AccountTask.java +++ b/src/main/java/com/ai/da/common/task/AccountTask.java @@ -19,21 +19,21 @@ public class AccountTask { /** * 每周日晚上刷新 年付用户、月付用户的积分 */ - @Scheduled(cron = "59 59 23 ? * SUN") +// @Scheduled(cron = "59 59 23 ? * SUN") // @Scheduled(cron = "59 59 23 * * ?") public void refreshCreditsMonthly() { log.info("每周日晚11:59:59刷新付费用户积分为 6000"); accountService.refreshCreditsWeekly(); } - @Scheduled(cron = "0 */5 * * * *") // Run every 5 minutes +// @Scheduled(cron = "0 */5 * * * *") // Run every 5 minutes public void getPaidUser() { // 获取code-create 表中 指定日期之后 订单状态为wc-processing的订单 accountService.extendValidityForCC(); } // 每天凌晨0点执行一次 - @Scheduled(cron = "0 0 0 * * ?") +// @Scheduled(cron = "0 0 0 * * ?") public void cancelActivityBenefits() { // 1、查询当前所有参与了活动且过期的用户 List accountList = accountService.getExpiredUserBySystemUser(4); @@ -46,7 +46,7 @@ public class AccountTask { } // 每天检测正式用户到期情况,每天凌晨0点执行 - @Scheduled(cron = "0 0 0 * * ?") +// @Scheduled(cron = "0 0 0 * * ?") public void paidUserToVisitor() { // 1、查询当前已过期正式用户或试用用户 List accountList = accountService.getExpiredUserBySystemUser(1); @@ -63,7 +63,7 @@ public class AccountTask { /** * 将Code-Create上注册的用户添加为AiDA的游客 */ - @Scheduled(cron = "0 */5 * * * *") // Run every 5 minutes +// @Scheduled(cron = "0 */5 * * * *") // Run every 5 minutes public void registerUserToVisitor() { accountService.registerUserToVisitor(); } diff --git a/src/main/java/com/ai/da/common/task/PaypalTask.java b/src/main/java/com/ai/da/common/task/PaypalTask.java index 865eaaa4..fa069971 100644 --- a/src/main/java/com/ai/da/common/task/PaypalTask.java +++ b/src/main/java/com/ai/da/common/task/PaypalTask.java @@ -23,7 +23,7 @@ public class PaypalTask { @Resource private PayPalCheckoutService payPalCheckoutService; - @Scheduled(cron = "0/30 * * * * ?") +// @Scheduled(cron = "0/30 * * * * ?") public void orderConfirm() throws SerializeException { // log.info("PayPal orderConfirm 被执行......"); diff --git a/src/main/java/com/ai/da/common/task/StripeTask.java b/src/main/java/com/ai/da/common/task/StripeTask.java index 45d98997..d4a6fbaf 100644 --- a/src/main/java/com/ai/da/common/task/StripeTask.java +++ b/src/main/java/com/ai/da/common/task/StripeTask.java @@ -22,7 +22,7 @@ public class StripeTask { @Resource private StripeService stripeService; - @Scheduled(cron = "0/30 * * * * ?") +// @Scheduled(cron = "0/30 * * * * ?") public void orderConfirm() throws SerializeException { // 查看超过30分钟以上仍未支付的订单 置为超时订单 diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 8550475d..974fee23 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -2,7 +2,7 @@ #spring.profiles.active=test #����application-prod�ļ�(��������) -spring.profiles.active=prod +#spring.profiles.active=prod #����application-dev�ļ�(��������) -#spring.profiles.active=dev +spring.profiles.active=dev From 2ac54a50ecb91c846cf6d6b3fe575778fe82b960 Mon Sep 17 00:00:00 2001 From: shahaibo <1023316923@qq.com> Date: Wed, 11 Dec 2024 14:21:29 +0800 Subject: [PATCH 11/91] TASK:AiDA --- .../ai/da/controller/AccountController.java | 14 +++++++++++ .../da/model/dto/ReDesignCollectionDTO.java | 4 ++++ .../com/ai/da/service/AccountService.java | 4 ++++ .../da/service/impl/AccountServiceImpl.java | 23 +++++++++++++++++++ .../ai/da/service/impl/DesignServiceImpl.java | 4 ++-- 5 files changed, 47 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/ai/da/controller/AccountController.java b/src/main/java/com/ai/da/controller/AccountController.java index 1a8485d7..219d890f 100644 --- a/src/main/java/com/ai/da/controller/AccountController.java +++ b/src/main/java/com/ai/da/controller/AccountController.java @@ -310,4 +310,18 @@ public class AccountController { public Response getAccountDetail() { return Response.success(accountService.getAccountDetail()); } + + @CrossOrigin + @GetMapping("/bindGoogle") + @ApiOperation(value = "绑定谷歌") + public Response bindGoogle(@RequestParam("credential") String credential) { + return Response.success(accountService.bindGoogle(credential)); + } + + @CrossOrigin + @GetMapping("/bindWeChat") + @ApiOperation(value = "绑定微信") + public Response bindWeChat(@RequestParam("code") String code) { + return Response.success(accountService.bindWeChat(code)); + } } diff --git a/src/main/java/com/ai/da/model/dto/ReDesignCollectionDTO.java b/src/main/java/com/ai/da/model/dto/ReDesignCollectionDTO.java index 65a125a9..8c8bbe48 100644 --- a/src/main/java/com/ai/da/model/dto/ReDesignCollectionDTO.java +++ b/src/main/java/com/ai/da/model/dto/ReDesignCollectionDTO.java @@ -67,4 +67,8 @@ public class ReDesignCollectionDTO { private String moodboardPosition; private String moodTemplateId; + + private List requestIdList; + + private Integer designNum; } diff --git a/src/main/java/com/ai/da/service/AccountService.java b/src/main/java/com/ai/da/service/AccountService.java index 262f3b91..6a5fd436 100644 --- a/src/main/java/com/ai/da/service/AccountService.java +++ b/src/main/java/com/ai/da/service/AccountService.java @@ -208,4 +208,8 @@ public interface AccountService extends IService { AccountLoginVO parseWeChatCode(String code); AccountLoginVO getAccountDetail(); + + AccountLoginVO bindGoogle(String credential); + + AccountLoginVO bindWeChat(String code); } diff --git a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java index 74483e51..20fff9b4 100644 --- a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java @@ -1503,6 +1503,16 @@ public class AccountServiceImpl extends ServiceImpl impl } } + public static void main(String[] args) { + List a = new ArrayList<>(); + a.add("1023316923@qq.com"); + a.add("Malinyuquan@gmail.com"); + + if (a.contains("malinyuquan@gmail.com")) { + log.info("aaaaaaaaaaaaaaaaaaaaa"); + } + } + private static final String QUERY_PAID_CUSTOMER_EMAIL = "SELECT distinct c.email " + "FROM `pmr_wc_order_stats` o " + "inner join `pmr_wc_customer_lookup` c " + @@ -2400,8 +2410,21 @@ public class AccountServiceImpl extends ServiceImpl impl response.setAvatar(minioUtil.getPreSignedUrl(avatar, CommonConstant.MINIO_IMAGE_EXPIRE_TIME)); response.setFolloweeCount(portfolioService.getFolloweeCount(account.getId())); response.setFollowerCount(portfolioService.getFollowerCount(account.getId())); + response.setSystemUser(1); //判断是否常用ip 不是则发邮件提示 // calculateExceptionIp(RequestInfoUtil.getIpAddress(request), account); + + return response; } + + @Override + public AccountLoginVO bindGoogle(String credential) { + return null; + } + + @Override + public AccountLoginVO bindWeChat(String code) { + return null; + } } diff --git a/src/main/java/com/ai/da/service/impl/DesignServiceImpl.java b/src/main/java/com/ai/da/service/impl/DesignServiceImpl.java index 3abb7e36..e26071a3 100644 --- a/src/main/java/com/ai/da/service/impl/DesignServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/DesignServiceImpl.java @@ -1562,8 +1562,8 @@ public class DesignServiceImpl extends ServiceImpl impleme @Override @Transactional(rollbackFor = Exception.class) public Boolean receiveDesignResults(JSONObject responseJSONObject) { - String requestId = "UUID.randomUUID().toString()"; -// String requestId = responseJSONObject.getString("requestId"); +// String requestId = "UUID.randomUUID().toString()"; + String requestId = responseJSONObject.getString("requestId"); Map context; synchronized (designContext) { log.info(designContext.toString()); From 82f75716124abf2d7cb9bd8178b992b4767ea0f5 Mon Sep 17 00:00:00 2001 From: shahaibo <1023316923@qq.com> Date: Wed, 11 Dec 2024 16:21:18 +0800 Subject: [PATCH 12/91] TASK:AiDA --- .../ai/da/controller/AccountController.java | 4 +- .../mapper/primary/entity/AccountExtend.java | 5 + .../com/ai/da/model/vo/AccountLoginVO.java | 4 + .../com/ai/da/service/AccountService.java | 4 +- .../da/service/impl/AccountServiceImpl.java | 116 ++++++++++++++---- 5 files changed, 107 insertions(+), 26 deletions(-) diff --git a/src/main/java/com/ai/da/controller/AccountController.java b/src/main/java/com/ai/da/controller/AccountController.java index 219d890f..5ec9754a 100644 --- a/src/main/java/com/ai/da/controller/AccountController.java +++ b/src/main/java/com/ai/da/controller/AccountController.java @@ -314,14 +314,14 @@ public class AccountController { @CrossOrigin @GetMapping("/bindGoogle") @ApiOperation(value = "绑定谷歌") - public Response bindGoogle(@RequestParam("credential") String credential) { + public Response bindGoogle(@RequestParam("credential") String credential) { return Response.success(accountService.bindGoogle(credential)); } @CrossOrigin @GetMapping("/bindWeChat") @ApiOperation(value = "绑定微信") - public Response bindWeChat(@RequestParam("code") String code) { + public Response bindWeChat(@RequestParam("code") String code) { return Response.success(accountService.bindWeChat(code)); } } diff --git a/src/main/java/com/ai/da/mapper/primary/entity/AccountExtend.java b/src/main/java/com/ai/da/mapper/primary/entity/AccountExtend.java index 5742f0ec..c5b612b1 100644 --- a/src/main/java/com/ai/da/mapper/primary/entity/AccountExtend.java +++ b/src/main/java/com/ai/da/mapper/primary/entity/AccountExtend.java @@ -1,5 +1,6 @@ package com.ai.da.mapper.primary.entity; +import com.ai.da.common.response.PageResponse; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; @@ -26,5 +27,9 @@ public class AccountExtend implements Serializable { private String authType; + private String headImgUrl; + + private String name; + private String auth; } diff --git a/src/main/java/com/ai/da/model/vo/AccountLoginVO.java b/src/main/java/com/ai/da/model/vo/AccountLoginVO.java index ab23b872..9a1f9b85 100644 --- a/src/main/java/com/ai/da/model/vo/AccountLoginVO.java +++ b/src/main/java/com/ai/da/model/vo/AccountLoginVO.java @@ -1,5 +1,6 @@ package com.ai.da.model.vo; +import com.ai.da.mapper.primary.entity.AccountExtend; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import io.swagger.models.auth.In; @@ -8,6 +9,7 @@ import lombok.Data; import lombok.NoArgsConstructor; import javax.validation.constraints.NotBlank; +import java.util.List; @AllArgsConstructor @NoArgsConstructor @@ -40,4 +42,6 @@ public class AccountLoginVO { private Long followerCount; + private List accountExtendList; + } diff --git a/src/main/java/com/ai/da/service/AccountService.java b/src/main/java/com/ai/da/service/AccountService.java index 6a5fd436..2f2f6ff3 100644 --- a/src/main/java/com/ai/da/service/AccountService.java +++ b/src/main/java/com/ai/da/service/AccountService.java @@ -209,7 +209,7 @@ public interface AccountService extends IService { AccountLoginVO getAccountDetail(); - AccountLoginVO bindGoogle(String credential); + Boolean bindGoogle(String credential); - AccountLoginVO bindWeChat(String code); + Boolean bindWeChat(String code); } diff --git a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java index 20fff9b4..7fff9732 100644 --- a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java @@ -2179,6 +2179,7 @@ public class AccountServiceImpl extends ServiceImpl impl String userId = payload.getSubject(); String email = payload.getEmail(); String name = (String) payload.get("name"); + String pictureUrl = (String) payload.get("picture"); log.info(userId); log.info(email); log.info(name); @@ -2191,6 +2192,13 @@ public class AccountServiceImpl extends ServiceImpl impl if (CollectionUtil.isNotEmpty(accounts)) { account = accounts.get(0); } else { + + AccountExtend accountExtendInsert = new AccountExtend(); + accountExtendInsert.setAuth(userId); + accountExtendInsert.setAuthType("Google"); + accountExtendInsert.setHeadImgUrl(pictureUrl); + accountExtendInsert.setName(name); + // 用户不存在,创建新用户(自动注册) Account newUser = new Account(); newUser.setUserEmail(email); @@ -2206,6 +2214,9 @@ public class AccountServiceImpl extends ServiceImpl impl newUser.setSystemUser(3); accountMapper.insert(newUser); + accountExtendInsert.setAccountId(newUser.getId()); + accountExtendMapper.insert(accountExtendInsert); + account = newUser; } @@ -2264,6 +2275,7 @@ public class AccountServiceImpl extends ServiceImpl impl // 提取 unionid 和 nickname String unionId = userInfoResponse.getString("unionid"); String userName = userInfoResponse.getString("nickname"); + String headimgurl = userInfoResponse.getString("headimgurl"); if (unionId == null) { throw new IllegalArgumentException("无法获取 unionid,请检查微信开发平台配置"); } @@ -2278,6 +2290,8 @@ public class AccountServiceImpl extends ServiceImpl impl AccountExtend accountExtendInsert = new AccountExtend(); accountExtendInsert.setAuth(unionId); accountExtendInsert.setAuthType("WeChat"); + accountExtendInsert.setHeadImgUrl(headimgurl); + accountExtendInsert.setName(userName); // 用户不存在,创建新用户(自动注册) Account newUser = new Account(); @@ -2325,21 +2339,6 @@ public class AccountServiceImpl extends ServiceImpl impl response.setFolloweeCount(portfolioService.getFolloweeCount(account.getId())); response.setFollowerCount(portfolioService.getFollowerCount(account.getId())); return response; - -// // 2. 根据 unionid 检查用户是否存在 -// User user = userRepository.findByUnionid(unionid); -// if (user == null) { -// // 用户不存在,进行注册 -// user = new User(); -// user.setUnionid(unionid); -// user.setOpenid(weChatResponse.getString("openid")); -// user.setNickname(weChatResponse.getString("nickname")); -// user.setAvatar(weChatResponse.getString("headimgurl")); -// userRepository.save(user); -// } -// -// // 3. 返回 unionid -// return unionid; } private static final String WECHAT_USER_INFO_URL = "https://api.weixin.qq.com/sns/userinfo"; @@ -2410,21 +2409,94 @@ public class AccountServiceImpl extends ServiceImpl impl response.setAvatar(minioUtil.getPreSignedUrl(avatar, CommonConstant.MINIO_IMAGE_EXPIRE_TIME)); response.setFolloweeCount(portfolioService.getFolloweeCount(account.getId())); response.setFollowerCount(portfolioService.getFollowerCount(account.getId())); - response.setSystemUser(1); - //判断是否常用ip 不是则发邮件提示 -// calculateExceptionIp(RequestInfoUtil.getIpAddress(request), account); + QueryWrapper qw = new QueryWrapper<>(); + qw.lambda().eq(AccountExtend::getAccountId, response.getUserId()); + List accountExtends = accountExtendMapper.selectList(qw); + if (CollectionUtil.isNotEmpty(accountExtends)) { + response.setAccountExtendList(accountExtends); + } return response; } @Override - public AccountLoginVO bindGoogle(String credential) { - return null; + public Boolean bindGoogle(String credential) { + try { + // 配置 Google ID Token 验证器 + GoogleIdTokenVerifier verifier = new GoogleIdTokenVerifier.Builder( + new NetHttpTransport(), + JacksonFactory.getDefaultInstance()) + .setAudience(Collections.singletonList(CLIENT_ID)) + .build(); + + // 验证并解析 ID Token + GoogleIdToken idToken = verifier.verify(credential); + + + if (idToken != null) { + GoogleIdToken.Payload payload = idToken.getPayload(); + + // 提取用户信息 + String userId = payload.getSubject(); + String email = payload.getEmail(); + String name = (String) payload.get("name"); + String pictureUrl = (String) payload.get("picture"); + + + AccountExtend accountExtendInsert = new AccountExtend(); + accountExtendInsert.setAuth(userId); + accountExtendInsert.setAuthType("Google"); + accountExtendInsert.setHeadImgUrl(pictureUrl); + accountExtendInsert.setName(name); + + + AuthPrincipalVo authPrincipalVo = UserContext.getUserHolder(); + accountExtendInsert.setAccountId(authPrincipalVo.getId()); + accountExtendMapper.insert(accountExtendInsert); + + return Boolean.TRUE; + } else { + throw new IllegalArgumentException("Invalid ID token."); + } + + } catch (Exception e) { + e.printStackTrace(); + throw new RuntimeException("Failed to verify ID token: " + e.getMessage()); + } } @Override - public AccountLoginVO bindWeChat(String code) { - return null; + public Boolean bindWeChat(String code) { + // 1. 获取 access_token 和 openid + JSONObject accessTokenResponse = getAccessTokenFromWeChat(code); + String accessToken = accessTokenResponse.getString("access_token"); + String openId = accessTokenResponse.getString("openid"); + + if (StringUtils.isEmpty(accessToken) || StringUtils.isEmpty(openId)) { + throw new RuntimeException("微信接口返回数据缺失: " + accessTokenResponse.toJSONString()); + } + + // 2. 获取用户信息 + JSONObject userInfoResponse = getUserInfoFromWeChat(accessToken, openId); + + // 提取 unionid 和 nickname + String unionId = userInfoResponse.getString("unionid"); + String userName = userInfoResponse.getString("nickname"); + String headimgurl = userInfoResponse.getString("headimgurl"); + if (unionId == null) { + throw new IllegalArgumentException("无法获取 unionid,请检查微信开发平台配置"); + } + AccountExtend accountExtendInsert = new AccountExtend(); + accountExtendInsert.setAuth(unionId); + accountExtendInsert.setAuthType("WeChat"); + accountExtendInsert.setHeadImgUrl(headimgurl); + accountExtendInsert.setName(userName); + + AuthPrincipalVo authPrincipalVo = UserContext.getUserHolder(); + accountExtendInsert.setAccountId(authPrincipalVo.getId()); + accountExtendMapper.insert(accountExtendInsert); + + return Boolean.TRUE; } } From cdf29d2b0d2381bcf7bfd897f790db93bf093082 Mon Sep 17 00:00:00 2001 From: shahaibo <1023316923@qq.com> Date: Fri, 13 Dec 2024 16:07:21 +0800 Subject: [PATCH 13/91] TASK:AiDA --- .../ai/da/controller/AccountController.java | 14 ++- .../com/ai/da/model/vo/AccountLoginVO.java | 2 + .../java/com/ai/da/python/PythonService.java | 54 ++++++++++ .../com/ai/da/service/AccountService.java | 4 + .../da/service/impl/AccountServiceImpl.java | 33 ++++-- .../ai/da/service/impl/DesignServiceImpl.java | 100 ++++++++++++++++-- 6 files changed, 188 insertions(+), 19 deletions(-) diff --git a/src/main/java/com/ai/da/controller/AccountController.java b/src/main/java/com/ai/da/controller/AccountController.java index 5ec9754a..12de1981 100644 --- a/src/main/java/com/ai/da/controller/AccountController.java +++ b/src/main/java/com/ai/da/controller/AccountController.java @@ -311,17 +311,27 @@ public class AccountController { return Response.success(accountService.getAccountDetail()); } - @CrossOrigin @GetMapping("/bindGoogle") @ApiOperation(value = "绑定谷歌") public Response bindGoogle(@RequestParam("credential") String credential) { return Response.success(accountService.bindGoogle(credential)); } - @CrossOrigin @GetMapping("/bindWeChat") @ApiOperation(value = "绑定微信") public Response bindWeChat(@RequestParam("code") String code) { return Response.success(accountService.bindWeChat(code)); } + + @GetMapping("/unbindWeChat") + @ApiOperation(value = "解除绑定微信") + public Response unbindWeChat() { + return Response.success(accountService.unbindWeChat()); + } + + @GetMapping("/unbindGoogle") + @ApiOperation(value = "解除绑定谷歌") + public Response unbindGoogle() { + return Response.success(accountService.unbindGoogle()); + } } diff --git a/src/main/java/com/ai/da/model/vo/AccountLoginVO.java b/src/main/java/com/ai/da/model/vo/AccountLoginVO.java index 9a1f9b85..e3d02b58 100644 --- a/src/main/java/com/ai/da/model/vo/AccountLoginVO.java +++ b/src/main/java/com/ai/da/model/vo/AccountLoginVO.java @@ -44,4 +44,6 @@ public class AccountLoginVO { private List accountExtendList; + private String Language; + } diff --git a/src/main/java/com/ai/da/python/PythonService.java b/src/main/java/com/ai/da/python/PythonService.java index 3032a498..5cb17cee 100644 --- a/src/main/java/com/ai/da/python/PythonService.java +++ b/src/main/java/com/ai/da/python/PythonService.java @@ -3671,4 +3671,58 @@ public class PythonService { //生成失败 throw new BusinessException("Atribute recognition exception!"); } + + public JSONObject designBatch(DesignPythonObjects designPythonObjects) { + // todo 限流校验 +// AccessLimitUtils.validate("design",5); + OkHttpClient client = new OkHttpClient().newBuilder() + .connectTimeout(30, TimeUnit.SECONDS) + .pingInterval(5, TimeUnit.SECONDS)//websocket轮训间隔(单位:秒) + .readTimeout(60, TimeUnit.SECONDS)//读取超时(单位:秒) + .writeTimeout(60, TimeUnit.SECONDS)//写入超时(单位:秒) + .build(); + MediaType mediaType = MediaType.parse("application/json"); + //关闭FastJson的引用检测 防止出现$ref 现象 + + String param = JSON.toJSONString(designPythonObjects, SerializerFeature.DisableCircularReferenceDetect); + log.info("design请求python 参数:####{}", param); + RequestBody body = RequestBody.create(mediaType, param); + Request request = new Request.Builder() + .url(accessPythonIp + ":" + accessPythonPort + "/api/design_batch_generate") +// .url(fastApiPythonAddress + "/api/design") +// .url(accessPythonIp + ":10200/aifda/api/v1.0/generate") + .method("POST", body) + .addHeader("Authorization", "Basic YWlkbGFiOjEyMw==") + .addHeader("Content-Type", "application/json") + .build(); + Response response; + String responseBody; + try { + response = client.newCall(request).execute(); + } catch (IOException ioException) { + AccessLimitUtils.validateOut("design"); + log.error("PythonService##design异常###{}", ExceptionUtil.getThrowableList(ioException)); + throw new BusinessException("design.interface.exception"); + } + + //去除限流 +// AccessLimitUtils.validateOut("design"); + if (response.isSuccessful()) { + try { + if (Objects.nonNull(response.body())) { + responseBody = response.body().string(); + JSONObject responseObject = JSON.parseObject(responseBody); + log.info("PythonService##responseObject###{}", responseObject); + return responseObject; + } + throw new BusinessException("design.interface.exception"); + } catch (IOException | JSONException e) { + log.error("PythonService##design异常###{}", e.getMessage()); + throw new BusinessException("design.interface.exception"); + } + } + log.error("PythonService##design异常response###{}", response); + //生成失败 + throw new BusinessException("design.interface.exception"); + } } diff --git a/src/main/java/com/ai/da/service/AccountService.java b/src/main/java/com/ai/da/service/AccountService.java index 2f2f6ff3..a792bd74 100644 --- a/src/main/java/com/ai/da/service/AccountService.java +++ b/src/main/java/com/ai/da/service/AccountService.java @@ -212,4 +212,8 @@ public interface AccountService extends IService { Boolean bindGoogle(String credential); Boolean bindWeChat(String code); + + Boolean unbindWeChat(); + + Boolean unbindGoogle(); } diff --git a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java index 7fff9732..fc3022a1 100644 --- a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java @@ -2185,12 +2185,13 @@ public class AccountServiceImpl extends ServiceImpl impl log.info(name); // 检查数据库中是否已有该用户 - QueryWrapper queryWrapper = new QueryWrapper<>(); - queryWrapper.lambda().eq(Account::getUserEmail, email); // 根据邮箱查询用户 - List accounts = accountMapper.selectList(queryWrapper); + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.lambda().eq(AccountExtend::getAuth, userId); // 根据邮箱查询用户 + List accountExtends = accountExtendMapper.selectList(queryWrapper); Account account = new Account(); - if (CollectionUtil.isNotEmpty(accounts)) { - account = accounts.get(0); + if (CollectionUtil.isNotEmpty(accountExtends)) { + Long accountId = accountExtends.get(0).getAccountId(); + account = accountMapper.selectById(accountId); } else { AccountExtend accountExtendInsert = new AccountExtend(); @@ -2416,7 +2417,7 @@ public class AccountServiceImpl extends ServiceImpl impl if (CollectionUtil.isNotEmpty(accountExtends)) { response.setAccountExtendList(accountExtends); } - + response.setLanguage(Language.valueOf(account.getLanguage()).name()); return response; } @@ -2499,4 +2500,24 @@ public class AccountServiceImpl extends ServiceImpl impl return Boolean.TRUE; } + + @Override + public Boolean unbindWeChat() { + AuthPrincipalVo authPrincipalVo = UserContext.getUserHolder(); + QueryWrapper qw = new QueryWrapper<>(); + qw.lambda().eq(AccountExtend::getAccountId, authPrincipalVo.getId()); + qw.lambda().eq(AccountExtend::getAuthType, "WeChat"); + accountExtendMapper.delete(qw); + return Boolean.TRUE; + } + + @Override + public Boolean unbindGoogle() { + AuthPrincipalVo authPrincipalVo = UserContext.getUserHolder(); + QueryWrapper qw = new QueryWrapper<>(); + qw.lambda().eq(AccountExtend::getAccountId, authPrincipalVo.getId()); + qw.lambda().eq(AccountExtend::getAuthType, "Google"); + accountExtendMapper.delete(qw); + return Boolean.TRUE; + } } diff --git a/src/main/java/com/ai/da/service/impl/DesignServiceImpl.java b/src/main/java/com/ai/da/service/impl/DesignServiceImpl.java index e26071a3..5f70f836 100644 --- a/src/main/java/com/ai/da/service/impl/DesignServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/DesignServiceImpl.java @@ -288,7 +288,7 @@ public class DesignServiceImpl extends ServiceImpl impleme // } private String designOrRedesignOperateNew(DesignCollectionDTO designDTO, AuthPrincipalVo userInfo, - Long collectionIdParam, ValidateElementVO elementVO) { + Long collectionIdParam, ValidateElementVO elementVO) { if (CollectionUtil.isNotEmpty(designDTO.getSketchBoards())) { //编辑sketchBoard collectionElementService.editSketchBoardsElement(elementVO, designDTO.getSketchBoards()); @@ -303,14 +303,6 @@ public class DesignServiceImpl extends ServiceImpl impleme collectionId = collectionService.saveCollection(userInfo.getId(), designDTO.getTimeZone(), designDTO.getMoodTemplateId(), designDTO.getMoodboardPostion()); }else { collectionId = collectionIdParam; -// Collection byId = collectionService.getById(collectionIdParam); -// if (!designDTO.getMoodboardPostion().equals(byId.getMoodboardPosition())) { -// byId.setMoodboardPosition(designDTO.getMoodboardPostion()); -// } -// if (!designDTO.getMoodTemplateId().equals(byId.getMoodTemplateId())) { -// byId.setMoodTemplateId(designDTO.getMoodTemplateId()); -// } -// collectionService.updateById(byId); } List elementIds = getElementId(elementVO); //批量关联element 到 collection @@ -1566,7 +1558,6 @@ public class DesignServiceImpl extends ServiceImpl impleme String requestId = responseJSONObject.getString("requestId"); Map context; synchronized (designContext) { - log.info(designContext.toString()); context = designContext.get(requestId); if (context == null) { log.error("上下文数据缺失,无法完成操作"); @@ -1614,7 +1605,94 @@ public class DesignServiceImpl extends ServiceImpl impleme //校验collection element ValidateElementVO elementVO = collectionElementService.validateElement(designDTO); //design - return designOrRedesignOperateNew(designDTO, userInfo, null, elementVO); + return designBatch(designDTO, userInfo, null, elementVO); + } + + private String designBatch(DesignCollectionDTO designDTO, AuthPrincipalVo userInfo, Long collectionIdParam, ValidateElementVO elementVO) { + if (CollectionUtil.isNotEmpty(designDTO.getSketchBoards())) { + //编辑sketchBoard + collectionElementService.editSketchBoardsElement(elementVO, designDTO.getSketchBoards()); + } + if (CollectionUtil.isNotEmpty(designDTO.getPrintBoards())) { + //编辑printBoard + collectionElementService.editPrintBoardsElement(elementVO, designDTO.getPrintBoards()); + } + //保存collection + Long collectionId; + if (null == collectionIdParam) { + collectionId = collectionService.saveCollection(userInfo.getId(), designDTO.getTimeZone(), designDTO.getMoodTemplateId(), designDTO.getMoodboardPostion()); + }else { + collectionId = collectionIdParam; +// Collection byId = collectionService.getById(collectionIdParam); +// if (!designDTO.getMoodboardPostion().equals(byId.getMoodboardPosition())) { +// byId.setMoodboardPosition(designDTO.getMoodboardPostion()); +// } +// if (!designDTO.getMoodTemplateId().equals(byId.getMoodTemplateId())) { +// byId.setMoodTemplateId(designDTO.getMoodTemplateId()); +// } +// collectionService.updateById(byId); + } + List elementIds = getElementId(elementVO); + //批量关联element 到 collection + collectionElementService.relationCollection(elementIds, collectionId); + //library转化为collection(生成) + saveCollectionElemntsByLibrarys(elementVO, collectionId); + //generate转化为collection(生成) + saveCollectionElemntsByGenerates(elementVO, collectionId); + //保存颜色版 + collectionElementService.saveColorBoard(designDTO.getColorBoards(), collectionId, designDTO.getTimeZone()); + //保存design + Long designId = saveOne(designDTO, collectionId, userInfo.getId()); + //计算library +// calculateLibraryAndSysFile(designDTO, elementVO, userInfo); + //组装design入参 + long startTime = System.currentTimeMillis(); + DesignPythonObjects pythonObjects = pythonService.covertDesignParam(designDTO.getSystemScale(), + designDTO.getSingleOverall(), designDTO.getSwitchCategory(), elementVO, designDTO.getProcessId()); + long endTime = System.currentTimeMillis(); + long totalTimeInSeconds = (endTime - startTime) / 1000; + log.info("组装入参运行时间:" + totalTimeInSeconds + " 秒"); + // pythonObjects增加image_id关联 + startTime = System.currentTimeMillis(); + List imageIds = relationImageIds(pythonObjects); + endTime = System.currentTimeMillis(); + totalTimeInSeconds = (endTime - startTime) / 1000; + log.info("增加image_id关联运行时间:" + totalTimeInSeconds + " 秒"); + //design + startTime = System.currentTimeMillis(); + String requestId = UUID.randomUUID().toString(); + pythonObjects.setRequestId(requestId); + JSONObject responseJSONObject = pythonService.designBatch(pythonObjects); + endTime = System.currentTimeMillis(); + totalTimeInSeconds = (endTime - startTime) / 1000; + log.info("design python端运行时间:" + totalTimeInSeconds + " 秒"); + //生成library + startTime = System.currentTimeMillis(); + generateLibrary(elementVO, designDTO.getTimeZone()); + //处理关联关系,修复element覆盖得情况 + List relationElements = collectionElementService.getByOnlyCollectionId(collectionId); + List relationElementIds = relationElements.stream().map(CollectionElement::getId).collect(Collectors.toList()); + handleCollectionElementRelation(collectionId, null != collectionIdParam, relationElementIds); + endTime = System.currentTimeMillis(); + totalTimeInSeconds = (endTime - startTime) / 1000; + log.info("处理关联关系运行时间:" + totalTimeInSeconds + " 秒"); + + + Map context = new HashMap<>(); + context.put("pythonObjects", pythonObjects); // 转换后的 Python 请求参数 + context.put("designId", designId); // 设计 ID + context.put("collectionId", collectionId); // 集合 ID + context.put("userInfo", userInfo); // 用户信息 + context.put("timeZone", designDTO.getTimeZone()); // 时区 + context.put("singleOverall", designDTO.getSingleOverall()); // 其他设计参数 + context.put("requestIdList", elementVO.getRequestIdList()); + + // 将上下文存入全局设计上下文中 + designContext.put(requestId, context); + + //保存python返回信息;保存designItem和detail +// return savePythonDesignItemAndDetail(pythonObjects, designId, collectionId, userInfo, designDTO.getTimeZone(), responseJSONObject, designDTO.getSingleOverall()); + return requestId; } } From bf8af41f3f95b8cd29c7c170dc664cfe79e925f7 Mon Sep 17 00:00:00 2001 From: xupei Date: Mon, 16 Dec 2024 10:26:02 +0800 Subject: [PATCH 14/91] =?UTF-8?q?=E6=B7=BB=E5=8A=A0Affiliate=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ai/da/common/constant/CommonConstant.java | 4 +- .../java/com/ai/da/common/utils/DateUtil.java | 19 ++++- .../ai/da/controller/AffiliateController.java | 12 ++- .../ai/da/controller/OrderInfoController.java | 10 ++- .../ai/da/controller/StripeController.java | 4 +- .../da/mapper/primary/PaymentInfoMapper.java | 7 ++ .../da/mapper/primary/entity/Affiliate.java | 2 + .../primary/entity/SubscriptionInfo.java | 3 + .../com/ai/da/model/vo/AccountLoginVO.java | 15 ++++ .../vo/AffiliateInvitationDetailsVO.java | 25 ++++++ .../java/com/ai/da/model/vo/OrderListVO.java | 29 +++++++ .../com/ai/da/service/AffiliateService.java | 5 ++ .../com/ai/da/service/PaymentInfoService.java | 8 +- .../java/com/ai/da/service/StripeService.java | 5 +- .../da/service/impl/AccountServiceImpl.java | 11 +++ .../da/service/impl/AffiliateServiceImpl.java | 70 ++++++++++++++-- .../service/impl/PaymentInfoServiceImpl.java | 48 ++++++++++- .../ai/da/service/impl/StripeServiceImpl.java | 83 ++++++++++++------- src/main/resources/application-dev.properties | 2 +- .../mapper/primary/PaymentInfoMapper.xml | 42 ++++++++++ 20 files changed, 349 insertions(+), 55 deletions(-) create mode 100644 src/main/java/com/ai/da/model/vo/AffiliateInvitationDetailsVO.java create mode 100644 src/main/java/com/ai/da/model/vo/OrderListVO.java create mode 100644 src/main/resources/mapper/primary/PaymentInfoMapper.xml diff --git a/src/main/java/com/ai/da/common/constant/CommonConstant.java b/src/main/java/com/ai/da/common/constant/CommonConstant.java index cd019602..35ff4504 100644 --- a/src/main/java/com/ai/da/common/constant/CommonConstant.java +++ b/src/main/java/com/ai/da/common/constant/CommonConstant.java @@ -79,7 +79,5 @@ public class CommonConstant { public static final String TIME_FORMAT_MMM_dd_yyyy = "MMM. dd, yyyy"; - public static final String AFFILIATE_LINK = ""; - - + public static final String AFFILIATE_LINK = "https://www.aida.com.hk?ref="; } diff --git a/src/main/java/com/ai/da/common/utils/DateUtil.java b/src/main/java/com/ai/da/common/utils/DateUtil.java index 94269826..e1b1d755 100644 --- a/src/main/java/com/ai/da/common/utils/DateUtil.java +++ b/src/main/java/com/ai/da/common/utils/DateUtil.java @@ -9,8 +9,8 @@ import java.time.LocalDate; import java.time.LocalDateTime; import java.time.ZoneId; import java.time.format.DateTimeFormatter; -import java.util.Calendar; import java.util.Date; +import java.util.Locale; import java.util.TimeZone; @Slf4j @@ -81,4 +81,21 @@ public class DateUtil { return String.valueOf(epochSecond).substring(0, 10); } + public static String changeTimeStampFormat(Long timeStamp, String type, String format){ + // 将秒级时间戳转换为毫秒级 + if (type.equals("seconds")){ + timeStamp = timeStamp * 1000; + } + // 输出格式 + SimpleDateFormat outputFormat = new SimpleDateFormat(format, Locale.ENGLISH); + // 创建Date对象 + Date date = new Date(timeStamp); + // 格式化输出 + return outputFormat.format(date); + } + + public static String changeTimeStampFormat(LocalDateTime localDate){ + return localDate.format(DateTimeFormatter.ofPattern("MMM. dd, yyyy, EEEE", Locale.US)); + } + } diff --git a/src/main/java/com/ai/da/controller/AffiliateController.java b/src/main/java/com/ai/da/controller/AffiliateController.java index 4e55ce71..f980dd10 100644 --- a/src/main/java/com/ai/da/controller/AffiliateController.java +++ b/src/main/java/com/ai/da/controller/AffiliateController.java @@ -4,19 +4,23 @@ package com.ai.da.controller; import com.ai.da.common.response.Response; import com.ai.da.mapper.primary.entity.Affiliate; 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.service.AffiliateService; import com.baomidou.mybatisplus.core.metadata.IPage; +import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import javax.validation.Valid; +import java.util.List; @Slf4j @RestController @RequestMapping("/api/affiliate") +@Api(tags = "Affiliate模块") public class AffiliateController { @Resource @@ -46,7 +50,7 @@ public class AffiliateController { return Response.success(affiliateService.applicationApproval(id, isApproved)); } - @ApiOperation(value = "审批affiliate申请") + @ApiOperation(value = "定时计算佣金") @GetMapping("/testTask") public Response testTask() { affiliateService.updateAffiliateInfoWithPayment(); @@ -59,5 +63,11 @@ public class AffiliateController { return Response.success(affiliateService.affiliateLinkViewsIncrease(id)); } + @ApiOperation(value = "获取每个affiliate产生的收入") + @GetMapping("/getEachAffiliateGeneratedRevenue") + public Response> getEachAffiliateGeneratedRevenue(@RequestParam("id") Long id, @RequestParam(required = false) String startTime, @RequestParam(required = false) String endTime) { + return Response.success(affiliateService.getEachAffiliateGeneratedRevenue(id, startTime, endTime)); + } + } diff --git a/src/main/java/com/ai/da/controller/OrderInfoController.java b/src/main/java/com/ai/da/controller/OrderInfoController.java index 3a9ce1d5..56e60a48 100644 --- a/src/main/java/com/ai/da/controller/OrderInfoController.java +++ b/src/main/java/com/ai/da/controller/OrderInfoController.java @@ -3,9 +3,10 @@ package com.ai.da.controller; import com.ai.da.common.enums.OrderStatusEnum; import com.ai.da.common.response.PageBaseResponse; import com.ai.da.common.response.Response; -import com.ai.da.mapper.primary.entity.OrderInfo; import com.ai.da.model.dto.QueryPageByTimeDTO; +import com.ai.da.model.vo.OrderListVO; import com.ai.da.service.OrderInfoService; +import com.ai.da.service.PaymentInfoService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.web.bind.annotation.*; @@ -22,10 +23,13 @@ public class OrderInfoController { @Resource private OrderInfoService orderInfoService; + @Resource + private PaymentInfoService paymentInfoService; + @ApiOperation("订单列表") @PostMapping("/list") - public Response> list(@Valid @RequestBody QueryPageByTimeDTO queryPageByTimeDTO){ - PageBaseResponse orderByAccountId = orderInfoService.getOrderByPage(queryPageByTimeDTO); + public Response> list(@Valid @RequestBody QueryPageByTimeDTO queryPageByTimeDTO){ + PageBaseResponse orderByAccountId = paymentInfoService.getPaymentInfo(queryPageByTimeDTO); // List list = orderInfoService.listOrderByCreateTimeDesc(); return Response.success(orderByAccountId); } diff --git a/src/main/java/com/ai/da/controller/StripeController.java b/src/main/java/com/ai/da/controller/StripeController.java index 21c91a86..ede043d6 100644 --- a/src/main/java/com/ai/da/controller/StripeController.java +++ b/src/main/java/com/ai/da/controller/StripeController.java @@ -70,8 +70,8 @@ public class StripeController { @ApiOperation("取消订阅") @GetMapping("/cancelSubscription") - public Response cancelSubscription(@RequestParam String subscriptionId) { - stripeService.cancelSubscription(subscriptionId); + public Response cancelSubscription(@RequestParam String subscriptionId, @RequestParam String reason) { + stripeService.cancelSubscription(subscriptionId, reason); return Response.success("success"); } @ApiOperation("临时 取消订阅") diff --git a/src/main/java/com/ai/da/mapper/primary/PaymentInfoMapper.java b/src/main/java/com/ai/da/mapper/primary/PaymentInfoMapper.java index 27b147a4..ea23d39d 100644 --- a/src/main/java/com/ai/da/mapper/primary/PaymentInfoMapper.java +++ b/src/main/java/com/ai/da/mapper/primary/PaymentInfoMapper.java @@ -1,7 +1,14 @@ package com.ai.da.mapper.primary; import com.ai.da.mapper.primary.entity.PaymentInfo; +import com.ai.da.model.vo.OrderListVO; import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import java.util.List; + public interface PaymentInfoMapper extends BaseMapper { + + List selectPageOrderList(Long accountId, String startTime, String endTime, int offset, int pageSize); + + int queryOrderListTotalCount(Long accountId, String startTime, String endTime); } diff --git a/src/main/java/com/ai/da/mapper/primary/entity/Affiliate.java b/src/main/java/com/ai/da/mapper/primary/entity/Affiliate.java index 56204d75..beb52662 100644 --- a/src/main/java/com/ai/da/mapper/primary/entity/Affiliate.java +++ b/src/main/java/com/ai/da/mapper/primary/entity/Affiliate.java @@ -25,4 +25,6 @@ public class Affiliate extends BaseEntity{ private Boolean approved = false; private String link; + + private String promotionMethod; } diff --git a/src/main/java/com/ai/da/mapper/primary/entity/SubscriptionInfo.java b/src/main/java/com/ai/da/mapper/primary/entity/SubscriptionInfo.java index b7895c08..7ee32ab0 100644 --- a/src/main/java/com/ai/da/mapper/primary/entity/SubscriptionInfo.java +++ b/src/main/java/com/ai/da/mapper/primary/entity/SubscriptionInfo.java @@ -33,4 +33,7 @@ public class SubscriptionInfo extends BaseEntity{ // 当前订阅订单有效期结束时间 private Long currentPeriodEnd; + // 取消订阅原因 + private String cancelReason; + } diff --git a/src/main/java/com/ai/da/model/vo/AccountLoginVO.java b/src/main/java/com/ai/da/model/vo/AccountLoginVO.java index 9a1f9b85..8033057b 100644 --- a/src/main/java/com/ai/da/model/vo/AccountLoginVO.java +++ b/src/main/java/com/ai/da/model/vo/AccountLoginVO.java @@ -44,4 +44,19 @@ public class AccountLoginVO { private List accountExtendList; + // 订阅id(stripe提供) + private String subscriptionId; + + // 订阅状态 + private String status; + + // 订阅过期时间 + private String expireTime; + + // 订阅类型 month || year + private String subscriptionType; + + // 是否自动续订 + private boolean isAutoRenewal; + } diff --git a/src/main/java/com/ai/da/model/vo/AffiliateInvitationDetailsVO.java b/src/main/java/com/ai/da/model/vo/AffiliateInvitationDetailsVO.java new file mode 100644 index 00000000..4a9cdf54 --- /dev/null +++ b/src/main/java/com/ai/da/model/vo/AffiliateInvitationDetailsVO.java @@ -0,0 +1,25 @@ +package com.ai.da.model.vo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.LocalDateTime; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class AffiliateInvitationDetailsVO { + + private Long accountId; + + private String username; + + private Float firstSubscriptionPaymentAmount; + + private Float commission; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8") + private LocalDateTime time; +} diff --git a/src/main/java/com/ai/da/model/vo/OrderListVO.java b/src/main/java/com/ai/da/model/vo/OrderListVO.java new file mode 100644 index 00000000..44e42bff --- /dev/null +++ b/src/main/java/com/ai/da/model/vo/OrderListVO.java @@ -0,0 +1,29 @@ +package com.ai.da.model.vo; + + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * 用于订单列表展示(展示的是所有支付信息) + */ +@Data +public class OrderListVO { + + private Long id; + + private Float amount; + + private String paymentMethod; + + private String state; + + private String orderType; + + private String invoiceLink; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8") + private LocalDateTime createTime; +} diff --git a/src/main/java/com/ai/da/service/AffiliateService.java b/src/main/java/com/ai/da/service/AffiliateService.java index ed340ae4..768bb214 100644 --- a/src/main/java/com/ai/da/service/AffiliateService.java +++ b/src/main/java/com/ai/da/service/AffiliateService.java @@ -2,10 +2,13 @@ package com.ai.da.service; import com.ai.da.mapper.primary.entity.Affiliate; import com.ai.da.model.dto.AffiliateQueryDTO; +import com.ai.da.model.vo.AffiliateInvitationDetailsVO; import com.ai.da.model.vo.AffiliateVO; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.service.IService; +import java.util.List; + public interface AffiliateService extends IService { Boolean registerAsAnAffiliate(String promotionMethod); @@ -19,4 +22,6 @@ public interface AffiliateService extends IService { void updateAffiliateInfoWithPayment(); Boolean affiliateLinkViewsIncrease(Long id); + + List getEachAffiliateGeneratedRevenue(Long affiliateId, String startTime, String endTime); } diff --git a/src/main/java/com/ai/da/service/PaymentInfoService.java b/src/main/java/com/ai/da/service/PaymentInfoService.java index 785fb286..761c0d8b 100644 --- a/src/main/java/com/ai/da/service/PaymentInfoService.java +++ b/src/main/java/com/ai/da/service/PaymentInfoService.java @@ -1,12 +1,16 @@ package com.ai.da.service; +import com.ai.da.common.response.PageBaseResponse; import com.ai.da.mapper.primary.entity.PaymentInfo; import com.ai.da.model.dto.AlipayHKCallbackDTO; +import com.ai.da.model.dto.QueryPageByTimeDTO; +import com.ai.da.model.vo.OrderListVO; import com.baomidou.mybatisplus.extension.service.IService; import com.paypal.orders.Order; import com.stripe.model.Charge; import com.stripe.model.Invoice; +import java.util.List; import java.util.Map; public interface PaymentInfoService extends IService { @@ -23,7 +27,9 @@ public interface PaymentInfoService extends IService { PaymentInfo createOrUpdatePaymentInfoForStripe(Charge charge); - PaymentInfo getPaymentInfoByOrderId(String orderId); + List getPaymentInfoByOrderNo(String orderId, String order); void updatePaymentStatusById(Long id, String status, String content); + + PageBaseResponse getPaymentInfo(QueryPageByTimeDTO queryPageByTimeDTO); } diff --git a/src/main/java/com/ai/da/service/StripeService.java b/src/main/java/com/ai/da/service/StripeService.java index f6f60dc3..f0a95a7c 100644 --- a/src/main/java/com/ai/da/service/StripeService.java +++ b/src/main/java/com/ai/da/service/StripeService.java @@ -1,5 +1,6 @@ package com.ai.da.service; +import com.ai.da.mapper.primary.entity.SubscriptionInfo; import com.ai.da.model.dto.ProductPurchaseDTO; import com.stripe.exception.StripeException; @@ -13,6 +14,8 @@ public interface StripeService { Boolean notify(HttpServletRequest request); + SubscriptionInfo getLatestSubscriptionInfoByAccountId(Long accountId); + String refund(String amount, String orderId, String reason); void checkOrderStatus(String orderNo); @@ -21,7 +24,7 @@ public interface StripeService { Map getPaymentMethodByInvoiceId(String invoiceId); - void cancelSubscription(String orderNo); + void cancelSubscription(String orderNo, String cancelReason); void cancelSubscriptionTemp(String subscriptionId); diff --git a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java index 7fff9732..74ccd3f2 100644 --- a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java @@ -104,6 +104,9 @@ public class AccountServiceImpl extends ServiceImpl impl @Resource private RedisUtil redisUtil; + @Resource + private StripeService stripeService; + @Override @Transactional(rollbackFor = Exception.class) public AccountPreLoginVO preLogin(AccountPreLoginDTO accountDTO) { @@ -2416,6 +2419,14 @@ public class AccountServiceImpl extends ServiceImpl impl if (CollectionUtil.isNotEmpty(accountExtends)) { response.setAccountExtendList(accountExtends); } + SubscriptionInfo subscriptionInfo = stripeService.getLatestSubscriptionInfoByAccountId(accountId); + if (!Objects.isNull(subscriptionInfo)) { + response.setSubscriptionId(subscriptionInfo.getSubscriptionId()); + response.setSubscriptionType(subscriptionInfo.getType()); + response.setStatus(subscriptionInfo.getStatus()); + response.setExpireTime(String.valueOf(subscriptionInfo.getCurrentPeriodEnd())); + response.setAutoRenewal(subscriptionInfo.getStatus().equals("active")); + } return response; } diff --git a/src/main/java/com/ai/da/service/impl/AffiliateServiceImpl.java b/src/main/java/com/ai/da/service/impl/AffiliateServiceImpl.java index 47f2a0b6..a249b08d 100644 --- a/src/main/java/com/ai/da/service/impl/AffiliateServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/AffiliateServiceImpl.java @@ -5,13 +5,14 @@ import com.ai.da.common.constant.CommonConstant; import com.ai.da.common.context.UserContext; import com.ai.da.common.response.ResultEnum; import com.ai.da.common.utils.CopyUtil; -import com.ai.da.common.utils.ObjectUtils; import com.ai.da.common.utils.RedisUtil; import com.ai.da.common.utils.SendEmailUtil; import com.ai.da.mapper.primary.AffiliateMapper; +import com.ai.da.mapper.primary.SubscriptionInfoMapper; import com.ai.da.mapper.primary.entity.*; import com.ai.da.model.dto.AffiliateEmailParamsDTO; import com.ai.da.model.dto.AffiliateQueryDTO; +import com.ai.da.model.vo.AffiliateInvitationDetailsVO; import com.ai.da.model.vo.AffiliateVO; import com.ai.da.model.vo.AuthPrincipalVo; import com.ai.da.service.AccountService; @@ -22,6 +23,7 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.mysql.cj.util.StringUtils; import io.netty.util.internal.StringUtil; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -29,6 +31,7 @@ import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.math.BigDecimal; import java.time.LocalDateTime; +import java.util.ArrayList; import java.util.List; import java.util.Objects; @@ -45,6 +48,9 @@ public class AffiliateServiceImpl extends ServiceImpl getAffiliateList(AffiliateQueryDTO affiliateQueryDTO){ QueryWrapper qw = new QueryWrapper<>(); - qw.eq(affiliateQueryDTO.getStatus() != null, "status", affiliateQueryDTO.getStatus()); - qw.gt(affiliateQueryDTO.getStartTime() != null, "create_time", affiliateQueryDTO.getStartTime()); - qw.lt(affiliateQueryDTO.getEndTime() != null, "create_time", affiliateQueryDTO.getEndTime()); + qw.eq(!StringUtils.isNullOrEmpty(affiliateQueryDTO.getStatus()), "status", affiliateQueryDTO.getStatus()); + qw.gt(!StringUtils.isNullOrEmpty(affiliateQueryDTO.getStartTime()), "create_time", affiliateQueryDTO.getStartTime()); + qw.lt(!StringUtils.isNullOrEmpty(affiliateQueryDTO.getEndTime()), "create_time", affiliateQueryDTO.getEndTime()); return baseMapper.selectPage(new Page<>(affiliateQueryDTO.getPage(), affiliateQueryDTO.getSize()), qw); } @@ -85,7 +92,7 @@ public class AffiliateServiceImpl extends ServiceImpl getEachAffiliateGeneratedRevenue(Long affiliateId, String startTime, String endTime) { + List resp = new ArrayList<>() ; + // 1、从account表中找到所有关联了指定affiliateId的accountId + QueryWrapper qw = new QueryWrapper<>(); + qw.eq("invitation_code", affiliateId); + + List accountList = accountService.getBaseMapper().selectList(qw); + if (accountList.isEmpty()){ + return null; + } else { + accountList.forEach(account -> { + // 2、分别找到各个accountId产生的第一笔订阅 + Long accountId = account.getId(); + QueryWrapper subscriptionInfoQueryWrapper = new QueryWrapper<>(); + subscriptionInfoQueryWrapper.eq("account_id", accountId) + .and(s -> s.eq("status", "active").or().eq("status", "canceled")) + .gt(!StringUtils.isNullOrEmpty(startTime) ,"create_time", startTime) + .lt(!StringUtils.isNullOrEmpty(endTime) ,"create_time", endTime).last("limit 1"); + + SubscriptionInfo subscriptionInfo = subscriptionInfoMapper.selectOne(subscriptionInfoQueryWrapper); + // 2、分别第一笔订阅的付款信息 + if (!Objects.isNull(subscriptionInfo)){ + PaymentInfo paymentInfo = paymentInfoService.getPaymentInfoByOrderNo(subscriptionInfo.getOrderNo(), "ASC").get(0); + AffiliateInvitationDetailsVO affiliateInvitationDetailsVO = new AffiliateInvitationDetailsVO(); + affiliateInvitationDetailsVO.setAccountId(accountId); + affiliateInvitationDetailsVO.setUsername(account.getUserName()); + affiliateInvitationDetailsVO.setFirstSubscriptionPaymentAmount(paymentInfo.getPayerTotal()); + affiliateInvitationDetailsVO.setCommission(BigDecimal.valueOf(paymentInfo.getPayerTotal()).multiply(new BigDecimal("0.25")).floatValue()); + affiliateInvitationDetailsVO.setTime(subscriptionInfo.getCreateTime()); + resp.add(affiliateInvitationDetailsVO); + } + }); + } + return resp; } // todo 每个月给kim发一封邮件统计本月的affiliate等的收入 public void commissionCalculation(){ + // 1、总收入(近一个月通过affiliate产生的收入) + + // 2、未支付的金额 affiliate表中unpaid的总和 + + // 3、邀请的新人 查询account表中,本月新增并有invitation_id的数量 + } diff --git a/src/main/java/com/ai/da/service/impl/PaymentInfoServiceImpl.java b/src/main/java/com/ai/da/service/impl/PaymentInfoServiceImpl.java index e5b35ed0..538886aa 100644 --- a/src/main/java/com/ai/da/service/impl/PaymentInfoServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/PaymentInfoServiceImpl.java @@ -1,11 +1,17 @@ package com.ai.da.service.impl; +import com.ai.da.common.context.UserContext; import com.ai.da.common.enums.PayTypeEnum; +import com.ai.da.common.response.PageBaseResponse; import com.ai.da.mapper.primary.PaymentInfoMapper; import com.ai.da.mapper.primary.entity.PaymentInfo; import com.ai.da.model.dto.AlipayHKCallbackDTO; +import com.ai.da.model.dto.QueryPageByTimeDTO; +import com.ai.da.model.vo.OrderListVO; import com.ai.da.service.*; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.google.gson.Gson; import com.paypal.orders.Order; @@ -15,15 +21,19 @@ import com.stripe.model.Charge; import com.stripe.model.Invoice; import com.stripe.model.Subscription; import com.stripe.model.checkout.Session; +import io.netty.util.internal.StringUtil; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; import javax.annotation.Resource; import java.math.BigDecimal; import java.math.RoundingMode; import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Objects; @@ -313,11 +323,11 @@ public class PaymentInfoServiceImpl extends ServiceImpl getPaymentInfoByOrderNo(String orderId, String order){ QueryWrapper qw = new QueryWrapper<>(); - qw.eq("order_no", orderId); + qw.eq("order_no", orderId).orderByDesc(order.equals("DESC"),"id"); - return baseMapper.selectOne(qw); + return baseMapper.selectList(qw); } @Override @@ -329,4 +339,36 @@ public class PaymentInfoServiceImpl extends ServiceImpl getPaymentInfo(QueryPageByTimeDTO queryPageByTimeDTO){ + Long accountId = UserContext.getUserHolder().getId(); + + String startTime = queryPageByTimeDTO.getStartTime(); + String endTime = queryPageByTimeDTO.getEndTime(); + if (StringUtil.isNullOrEmpty(startTime)) { + startTime = "2024-02-01 00:00:00"; + } + if (StringUtil.isNullOrEmpty(endTime)) { + LocalDateTime now = LocalDateTime.now(); + DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + endTime = now.format(dateTimeFormatter); + } + + int offset = (queryPageByTimeDTO.getPage() - 1) * queryPageByTimeDTO.getSize(); + List orderListVOS = baseMapper.selectPageOrderList(accountId, startTime, endTime, offset, queryPageByTimeDTO.getSize()); + + if (CollectionUtils.isEmpty(orderListVOS)) { + return PageBaseResponse.success(new Page<>()); + }else { + int totalCount = baseMapper.queryOrderListTotalCount(accountId, startTime, endTime); + IPage orderListVOIPage = new Page<>(); + Integer size = queryPageByTimeDTO.getSize(); + orderListVOIPage.setSize(size); + orderListVOIPage.setRecords(orderListVOS); + orderListVOIPage.setCurrent(queryPageByTimeDTO.getPage()); + orderListVOIPage.setPages((long)Math.ceil((double) totalCount / size)); + orderListVOIPage.setTotal(totalCount); + return PageBaseResponse.success(orderListVOIPage); + } + } } diff --git a/src/main/java/com/ai/da/service/impl/StripeServiceImpl.java b/src/main/java/com/ai/da/service/impl/StripeServiceImpl.java index 35b44944..3d776186 100644 --- a/src/main/java/com/ai/da/service/impl/StripeServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/StripeServiceImpl.java @@ -4,6 +4,7 @@ import com.ai.da.common.config.exception.BusinessException; import com.ai.da.common.constant.CommonConstant; import com.ai.da.common.context.UserContext; import com.ai.da.common.enums.*; +import com.ai.da.common.utils.DateUtil; import com.ai.da.common.utils.SendEmailUtil; import com.ai.da.mapper.primary.AccountMapper; import com.ai.da.mapper.primary.PaymentInfoMapper; @@ -37,11 +38,9 @@ import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import java.math.BigDecimal; import java.math.RoundingMode; -import java.text.SimpleDateFormat; import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneOffset; -import java.time.format.DateTimeFormatter; import java.util.*; @SuppressWarnings("LoggingSimilarMessage") @@ -440,11 +439,9 @@ public class StripeServiceImpl implements StripeService { @Transactional(rollbackFor = Exception.class) public SubscriptionInfo createSubscription(Subscription subscription){ // 确认当前subscription是否已经记录 - QueryWrapper qw = new QueryWrapper<>(); - qw.eq("subscription_id", subscription.getId()); - - SubscriptionInfo subscriptionInfo = subscriptionInfoMapper.selectOne(qw); - if (Objects.isNull(subscriptionInfo)){ + SubscriptionInfo subscriptionInfo = getSubscriptionInfoBySubId(subscription.getId()); +// SubscriptionInfo subscriptionInfo = subscriptionInfoMapper.selectOne(qw); + if (Objects.isNull(subscriptionInfo)) { String description = subscription.getDescription(); String orderNo = description.replace("AiDA - ", ""); OrderInfo orderInfo = orderInfoService.getOrderByOrderNo(orderNo); @@ -459,7 +456,7 @@ public class StripeServiceImpl implements StripeService { subscriptionInfo.setSubscriptionId(subscription.getId()); subscriptionInfo.setType(interval); subscriptionInfo.setStatus(subscription.getStatus()); - subscriptionInfo.setNextPayDate(changeTimeStampFormat(subscription.getCurrentPeriodEnd(), "seconds", CommonConstant.TIME_FORMAT_MMM_dd_yyyy_EEEE)); + subscriptionInfo.setNextPayDate(DateUtil.changeTimeStampFormat(subscription.getCurrentPeriodEnd(), "seconds", CommonConstant.TIME_FORMAT_MMM_dd_yyyy_EEEE)); subscriptionInfo.setCurrentPeriodStart(subscription.getCurrentPeriodStart()); subscriptionInfo.setCurrentPeriodEnd(subscription.getCurrentPeriodEnd()); subscriptionInfo.setCreateTime(LocalDateTime.now()); @@ -471,21 +468,34 @@ public class StripeServiceImpl implements StripeService { return subscriptionInfo; } - public String changeTimeStampFormat(Long timeStamp, String type, String format){ - // 将秒级时间戳转换为毫秒级 - if (type.equals("seconds")){ - timeStamp = timeStamp * 1000; + public SubscriptionInfo getSubscriptionInfoBySubId(String subId){ + QueryWrapper qw = new QueryWrapper<>(); + qw.eq("subscription_id", subId); + + List subscriptionInfos = subscriptionInfoMapper.selectList(qw); + if (subscriptionInfos.size() == 1){ + return subscriptionInfos.get(0); + }else if (subscriptionInfos.size() > 1) { + // 如果新建了多个订阅,则筛选出状态为active的订单 + Optional activeSubscriptionInfo = subscriptionInfos.stream() + .filter(sub -> sub.getStatus().equals("active")) + .findFirst(); + + return activeSubscriptionInfo.orElseGet(() -> subscriptionInfos.get(0)); + }else { + return null; } - // 输出格式 - SimpleDateFormat outputFormat = new SimpleDateFormat(format, Locale.ENGLISH); - // 创建Date对象 - Date date = new Date(timeStamp); - // 格式化输出 - return outputFormat.format(date); } - public String changeTimeStampFormat(LocalDateTime localDate){ - return localDate.format(DateTimeFormatter.ofPattern("MMM. dd, yyyy, EEEE", Locale.US)); + public SubscriptionInfo getLatestSubscriptionInfoByAccountId(Long accountId){ + QueryWrapper qw = new QueryWrapper<>(); + qw.eq("account_id", accountId); + List subscriptionInfos = subscriptionInfoMapper.selectList(qw); + if (subscriptionInfos.isEmpty()){ + return null; + }else { + return subscriptionInfos.get(0); + } } @Transactional(rollbackFor = Exception.class) @@ -504,10 +514,10 @@ public class StripeServiceImpl implements StripeService { } if (!subscriptionInfo.getCurrentPeriodEnd().equals(subscription.getCurrentPeriodEnd())){ subscriptionInfo.setCurrentPeriodEnd(subscription.getCurrentPeriodEnd()); - subscriptionInfo.setNextPayDate(changeTimeStampFormat(subscription.getCurrentPeriodEnd(), "seconds", CommonConstant.TIME_FORMAT_MMM_dd_yyyy_EEEE)); + subscriptionInfo.setNextPayDate(DateUtil.changeTimeStampFormat(subscription.getCurrentPeriodEnd(), "seconds", CommonConstant.TIME_FORMAT_MMM_dd_yyyy_EEEE)); // 更新账号到期时间 updateAccountValidity(subscriptionInfo.getAccountId(), subscriptionInfo.getCurrentPeriodEnd()); - log.info("更新 {} 账号到期时间为:{}", subscriptionInfo.getAccountId(), changeTimeStampFormat(subscriptionInfo.getCurrentPeriodEnd(), "seconds", CommonConstant.TIME_FORMAT_MMM_dd_yyyy_EEEE)); + log.info("更新 {} 账号到期时间为:{}", subscriptionInfo.getAccountId(), DateUtil.changeTimeStampFormat(subscriptionInfo.getCurrentPeriodEnd(), "seconds", CommonConstant.TIME_FORMAT_MMM_dd_yyyy_EEEE)); flag = true; } if (flag){ @@ -526,7 +536,7 @@ public class StripeServiceImpl implements StripeService { } // 取消连续订阅 将订阅从pause状态转为cancel状态(使用定时器,定期检索DB中,过期且不续订的订阅) - public void cancelSubscription(String subscriptionId) { + public void cancelSubscription(String subscriptionId, String cancelReason) { Stripe.apiKey = privateKey; Long accountId = UserContext.getUserHolder().getId(); log.info("用户 {} 申请取消连续订阅 {}", accountId, subscriptionId); @@ -538,6 +548,9 @@ public class StripeServiceImpl implements StripeService { try { Subscription cancel = subscription.cancel(); cancel.getStatus(); + + // 更新数据库 + updateCancelReason(subscriptionId, cancelReason); } catch (StripeException e) { log.error("订阅 {} 取消失败, error message : {}", subscription.getId(), e.getMessage()); } @@ -564,8 +577,9 @@ public class StripeServiceImpl implements StripeService { try { Stripe.apiKey = privateKey; + // todo transactionId不再是sessionId而是invoiceId,所以这里需要更新 // 根据orderId找到对应的sessionId - String sessionId = paymentInfoService.getPaymentInfoByOrderId(orderNo).getTransactionId(); + String sessionId = paymentInfoService.getPaymentInfoByOrderNo(orderNo, "DESC").get(0).getTransactionId(); if (StringUtils.isNotEmpty(sessionId)) { //根据会话编号退款 Session session = Session.retrieve(sessionId); @@ -628,7 +642,8 @@ public class StripeServiceImpl implements StripeService { public void checkOrderStatus(String orderNo) { Stripe.apiKey = privateKey; // 1、通过orderNo 查询sessionId - PaymentInfo paymentInfo = paymentInfoService.getPaymentInfoByOrderId(orderNo); + // todo transactionId不再是sessionId而是invoiceId,所以这里需要更新 + PaymentInfo paymentInfo = paymentInfoService.getPaymentInfoByOrderNo(orderNo, "DESC").get(0); try { Session session = Session.retrieve(paymentInfo.getTransactionId()); if (Objects.isNull(session)) { @@ -822,8 +837,8 @@ public class StripeServiceImpl implements StripeService { emailParamsDTO.setCreateDate(String.valueOf(paymentInfo.getCreateTime()).replace("T", " ")); emailParamsDTO.setQuantity(String.valueOf(1)); emailParamsDTO.setTotalFee(paymentInfo.getPayerTotal().toString()); - emailParamsDTO.setLastOrderDate(changeTimeStampFormat(subscriptionInfo.getCurrentPeriodStart(), "seconds", CommonConstant.TIME_FORMAT_MMM_dd_yyyy)); - emailParamsDTO.setEndOfPrepaidTerm(changeTimeStampFormat(subscriptionInfo.getCurrentPeriodEnd(), "seconds", CommonConstant.TIME_FORMAT_MMM_dd_yyyy)); + emailParamsDTO.setLastOrderDate(DateUtil.changeTimeStampFormat(subscriptionInfo.getCurrentPeriodStart(), "seconds", CommonConstant.TIME_FORMAT_MMM_dd_yyyy)); + emailParamsDTO.setEndOfPrepaidTerm(DateUtil.changeTimeStampFormat(subscriptionInfo.getCurrentPeriodEnd(), "seconds", CommonConstant.TIME_FORMAT_MMM_dd_yyyy)); setSubscriptionParams(paymentInfo, subscriptionInfo, orderByOrderNo, emailParamsDTO); SendEmailUtil.subscriptionEmailReminder(type, emailParamsDTO, language, account.getUserEmail()); @@ -941,9 +956,9 @@ public class StripeServiceImpl implements StripeService { emailParamsDTO.setSubscriptionId(subscriptionInfo.getId().toString()); emailParamsDTO.setFailMessage(orderByOrderNo.getNote()); emailParamsDTO.setSubscriptionType(subscriptionInfo.getType()); - emailParamsDTO.setStartDate(changeTimeStampFormat(orderByOrderNo.getCreateTime())); - emailParamsDTO.setNextPayDate(changeTimeStampFormat(subscriptionInfo.getCurrentPeriodEnd(), "seconds", CommonConstant.TIME_FORMAT_MMM_dd_yyyy)); - emailParamsDTO.setRenewalTime(changeTimeStampFormat(subscriptionInfo.getCurrentPeriodEnd(), "seconds", CommonConstant.TIME_FORMAT_MMM_dd_yyyy)); + emailParamsDTO.setStartDate(DateUtil.changeTimeStampFormat(orderByOrderNo.getCreateTime())); + emailParamsDTO.setNextPayDate(DateUtil.changeTimeStampFormat(subscriptionInfo.getCurrentPeriodEnd(), "seconds", CommonConstant.TIME_FORMAT_MMM_dd_yyyy)); + emailParamsDTO.setRenewalTime(DateUtil.changeTimeStampFormat(subscriptionInfo.getCurrentPeriodEnd(), "seconds", CommonConstant.TIME_FORMAT_MMM_dd_yyyy)); } public void subscriptionReminder(){ @@ -1082,6 +1097,14 @@ public class StripeServiceImpl implements StripeService { return null; } + public void updateCancelReason(String subscriptionId, String reason){ + QueryWrapper qw = new QueryWrapper<>(); + qw.eq("subscription_id", subscriptionId); + SubscriptionInfo subscriptionInfo = subscriptionInfoMapper.selectOne(qw); + + subscriptionInfo.setCancelReason(reason); + subscriptionInfoMapper.updateById(subscriptionInfo); + } } diff --git a/src/main/resources/application-dev.properties b/src/main/resources/application-dev.properties index 992396c3..2afd01c3 100644 --- a/src/main/resources/application-dev.properties +++ b/src/main/resources/application-dev.properties @@ -20,7 +20,7 @@ spring.security.jwtExpiration=8640000000 spring.security.ignorePaths=/,/favicon.ico,/doc.html,/webjars/**,/swagger-resources,/v2/api-docs,\ /api/account/**,/api/element/**,/api/python/**,/api/design/**,/api/history/**,/api/library/**,/api/third/party/**,/api/generate/**,/api/workspace/**,/api/classification/**,\ /api/product/**,/api/ali-pay/**,/api/order-info/**,/api/paypal/**,/api/credits/**,/api/inquiry/**,/api/tasks/**,/api/python/prepareForSR,/api/alipay-hk/**,/api/portfolio/**,\ - /api/stripe/**,/api/message/**,/notification/** + /api/stripe/**,/api/message/**,/notification/**,/api/affiliate/** spring.security.authApi=/auth/login diff --git a/src/main/resources/mapper/primary/PaymentInfoMapper.xml b/src/main/resources/mapper/primary/PaymentInfoMapper.xml new file mode 100644 index 00000000..8bab6ca5 --- /dev/null +++ b/src/main/resources/mapper/primary/PaymentInfoMapper.xml @@ -0,0 +1,42 @@ + + + + + + + + + From 7d8f047087f2ecceb38bce959e955242c7c4d5c9 Mon Sep 17 00:00:00 2001 From: xupei Date: Wed, 18 Dec 2024 11:53:41 +0800 Subject: [PATCH 15/91] =?UTF-8?q?Affiliate=E5=8A=9F=E8=83=BD-=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E5=BA=93=E8=A1=A8=E8=AE=BE=E8=AE=A1=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/ai/da/common/task/PaymentTask.java | 39 ++++- .../com/ai/da/common/utils/RedisUtil.java | 2 +- .../ai/da/controller/AffiliateController.java | 25 +++- .../ai/da/controller/StripeController.java | 11 +- .../mapper/primary/AffiliateIncomeMapper.java | 14 ++ .../ai/da/mapper/primary/AffiliateMapper.java | 4 + .../primary/entity/AffiliateIncome.java | 26 ++++ .../ai/da/model/dto/AffiliateQueryDTO.java | 20 ++- .../com/ai/da/model/vo/AccountLoginVO.java | 3 + .../com/ai/da/service/AffiliateService.java | 10 +- .../java/com/ai/da/service/StripeService.java | 4 +- .../da/service/impl/AccountServiceImpl.java | 7 + .../da/service/impl/AffiliateServiceImpl.java | 140 ++++++++++++------ .../ai/da/service/impl/StripeServiceImpl.java | 53 ++++++- .../mapper/primary/AffiliateIncomeMapper.xml | 36 +++++ .../mapper/primary/AffiliateMapper.xml | 16 ++ 16 files changed, 338 insertions(+), 72 deletions(-) create mode 100644 src/main/java/com/ai/da/mapper/primary/AffiliateIncomeMapper.java create mode 100644 src/main/java/com/ai/da/mapper/primary/entity/AffiliateIncome.java create mode 100644 src/main/resources/mapper/primary/AffiliateIncomeMapper.xml create mode 100644 src/main/resources/mapper/primary/AffiliateMapper.xml diff --git a/src/main/java/com/ai/da/common/task/PaymentTask.java b/src/main/java/com/ai/da/common/task/PaymentTask.java index 656e3a23..40450055 100644 --- a/src/main/java/com/ai/da/common/task/PaymentTask.java +++ b/src/main/java/com/ai/da/common/task/PaymentTask.java @@ -2,16 +2,14 @@ package com.ai.da.common.task; import com.ai.da.common.enums.PayTypeEnum; import com.ai.da.mapper.primary.entity.OrderInfo; -import com.ai.da.service.AliPayService; -import com.ai.da.service.OrderInfoService; -import com.ai.da.service.PayPalCheckoutService; -import com.ai.da.service.StripeService; +import com.ai.da.service.*; import com.paypal.http.exceptions.SerializeException; import lombok.extern.slf4j.Slf4j; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import javax.annotation.Resource; +import java.time.LocalDate; import java.util.List; @Slf4j @@ -24,6 +22,10 @@ public class PaymentTask { @Resource private StripeService stripeService; + @Resource + private AffiliateService affiliateService; + + // 考虑删除该定时任务(原因:之后的订单列允许用户查看发票,发票未过期时仍可以支付,所以不需要手动使订单过期) // @Scheduled(cron = "0/30 * * * * ?") public void orderConfirmForStripe() throws SerializeException { @@ -89,8 +91,31 @@ public class PaymentTask { } // 每天凌晨检查subscription中有哪些已过期,更新状态 - @Scheduled(cron = "0 0 0 * * ?") - public void checkSubscriptionExpiration(){ - stripeService.checkSubscriptionExpiration(); +// @Scheduled(cron = "0 0 0 * * ?") +// public void checkSubscriptionExpiration(){ +// stripeService.checkSubscriptionExpiration(); +// } + + // 如果有订阅已创建,但是没有发邮件通知的,需要主动获取回调信息并向用户发送邮件 + public void checkSubscriptionPayment(){ + // + } + + @Scheduled(cron = "0 */5 * * * *") // Run every 5 minutes + public void updateAffiliateInfoWithPayment(){ + affiliateService.updateAffiliateInfoWithPayment(); + } + + @Scheduled(cron = "0 0 8 28-31 * ?") + public void commissionSummaryReminder(){ + // 每个月末的最后一天的早上八点执行 + LocalDate today = LocalDate.now(); + // 判断是否为月底 + if (today.plusDays(1).getDayOfMonth() == 1) { + log.info("今天是月底,执行佣金结算提醒任务!"); + affiliateService.commissionCalculation(null, null); + } + } + } diff --git a/src/main/java/com/ai/da/common/utils/RedisUtil.java b/src/main/java/com/ai/da/common/utils/RedisUtil.java index d3ba2a93..7e0d9578 100644 --- a/src/main/java/com/ai/da/common/utils/RedisUtil.java +++ b/src/main/java/com/ai/da/common/utils/RedisUtil.java @@ -279,7 +279,7 @@ public class RedisUtil { redisTemplate.expire(redisKey, 5, TimeUnit.MINUTES); } - public final static String PAYMENT_INFO_LAST_SCAN_TIME = "PaymentInfoLastScanTime:"; + public final static String PAYMENT_INFO_LAST_SCAN_TIME = "PaymentInfoLastScanTime"; public final static String AFFILIATE_LINK_VIEW_KEY = "AffiliateLink:view:"; diff --git a/src/main/java/com/ai/da/controller/AffiliateController.java b/src/main/java/com/ai/da/controller/AffiliateController.java index f980dd10..1be751ac 100644 --- a/src/main/java/com/ai/da/controller/AffiliateController.java +++ b/src/main/java/com/ai/da/controller/AffiliateController.java @@ -28,7 +28,7 @@ public class AffiliateController { @ApiOperation(value = "注册成为affiliate") @GetMapping("/registration") - public Response completeGuidance(@RequestParam("promotionMethod") String promotionMethod) { + public Response completeGuidance(@RequestParam(value = "promotionMethod", required = false) String promotionMethod) { return Response.success(affiliateService.registerAsAnAffiliate(promotionMethod)); } @@ -44,18 +44,31 @@ public class AffiliateController { return Response.success(affiliateService.personalAffiliateCenter()); } + @ApiOperation(value = "获取个人佣金图表数据") + @GetMapping("/getPersonalMonthlyIncome") + public Response getPersonalMonthlyIncome(@RequestParam("year")int year) { + return Response.success(affiliateService.getPersonalMonthlyIncome(year)); + } + @ApiOperation(value = "审批affiliate申请") @GetMapping("/approval") public Response applicationApproval(@RequestParam("id") Long id, @RequestParam("isApproved")Boolean isApproved) { return Response.success(affiliateService.applicationApproval(id, isApproved)); } - @ApiOperation(value = "定时计算佣金") + /*@ApiOperation(value = "定时计算佣金") @GetMapping("/testTask") public Response testTask() { affiliateService.updateAffiliateInfoWithPayment(); return Response.success("success "); - } + }*/ + + /*@ApiOperation(value = "每月发送结算邮件") + @GetMapping("/commissionCalculation") + public Response commissionCalculation() { + affiliateService.commissionCalculation(null, null); + return Response.success("success "); + }*/ @ApiOperation(value = "affiliate链接浏览量增加") @GetMapping("/viewsIncrease") @@ -64,9 +77,9 @@ public class AffiliateController { } @ApiOperation(value = "获取每个affiliate产生的收入") - @GetMapping("/getEachAffiliateGeneratedRevenue") - public Response> getEachAffiliateGeneratedRevenue(@RequestParam("id") Long id, @RequestParam(required = false) String startTime, @RequestParam(required = false) String endTime) { - return Response.success(affiliateService.getEachAffiliateGeneratedRevenue(id, startTime, endTime)); + @PostMapping("/getEachAffiliateGeneratedRevenue") + public Response> getEachAffiliateGeneratedRevenue(@RequestBody AffiliateQueryDTO affiliateQueryDTO) { + return Response.success(affiliateService.getEachAffiliateGeneratedRevenue(affiliateQueryDTO)); } diff --git a/src/main/java/com/ai/da/controller/StripeController.java b/src/main/java/com/ai/da/controller/StripeController.java index ede043d6..82c5e1cc 100644 --- a/src/main/java/com/ai/da/controller/StripeController.java +++ b/src/main/java/com/ai/da/controller/StripeController.java @@ -19,6 +19,7 @@ import javax.servlet.http.HttpServletResponse; import javax.validation.Valid; import java.io.IOException; import java.util.List; +import java.util.Map; @Api(tags = "Stripe模块") @Slf4j @@ -70,7 +71,7 @@ public class StripeController { @ApiOperation("取消订阅") @GetMapping("/cancelSubscription") - public Response cancelSubscription(@RequestParam String subscriptionId, @RequestParam String reason) { + public Response cancelSubscription(@RequestParam String subscriptionId, @RequestParam(required = false) String reason) { stripeService.cancelSubscription(subscriptionId, reason); return Response.success("success"); } @@ -101,8 +102,14 @@ public class StripeController { @ApiOperation("临时 查询指定用户绑定的付款方式") @GetMapping("/getCustomerPaymentMethod") - public Response getCustomerPaymentMethod(@RequestParam String name, @RequestParam String email) { + public Response>> getCustomerPaymentMethod(@RequestParam String name, @RequestParam String email) { return Response.success(stripeService.getCustomerPaymentMethod(name, email)); } + @ApiOperation("临时 解绑指定用户绑定的所有付款方式") + @GetMapping("/detachCustomerAllPaymentMethod") + public Response detachCustomerAllPaymentMethod(@RequestParam String name, @RequestParam String email) { + return Response.success(stripeService.detachCustomerAllPaymentMethod(name, email)); + } + } diff --git a/src/main/java/com/ai/da/mapper/primary/AffiliateIncomeMapper.java b/src/main/java/com/ai/da/mapper/primary/AffiliateIncomeMapper.java new file mode 100644 index 00000000..d0a7d6ce --- /dev/null +++ b/src/main/java/com/ai/da/mapper/primary/AffiliateIncomeMapper.java @@ -0,0 +1,14 @@ +package com.ai.da.mapper.primary; + +import com.ai.da.mapper.primary.entity.AffiliateIncome; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +import java.util.List; +import java.util.Map; + +public interface AffiliateIncomeMapper extends BaseMapper { + + List> getPersonalMonthlyIncome(Long affiliateAccountId, int year); + + List> getMonthlyAffiliateIncome(int year, int month); +} diff --git a/src/main/java/com/ai/da/mapper/primary/AffiliateMapper.java b/src/main/java/com/ai/da/mapper/primary/AffiliateMapper.java index 314a0952..3974b904 100644 --- a/src/main/java/com/ai/da/mapper/primary/AffiliateMapper.java +++ b/src/main/java/com/ai/da/mapper/primary/AffiliateMapper.java @@ -3,5 +3,9 @@ package com.ai.da.mapper.primary; import com.ai.da.mapper.primary.entity.Affiliate; import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import java.util.Map; + public interface AffiliateMapper extends BaseMapper { + + Map getMonthlyApprovedAffiliate(int year, int month); } diff --git a/src/main/java/com/ai/da/mapper/primary/entity/AffiliateIncome.java b/src/main/java/com/ai/da/mapper/primary/entity/AffiliateIncome.java new file mode 100644 index 00000000..eb8ce12c --- /dev/null +++ b/src/main/java/com/ai/da/mapper/primary/entity/AffiliateIncome.java @@ -0,0 +1,26 @@ +package com.ai.da.mapper.primary.entity; + +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.time.LocalDateTime; + +@EqualsAndHashCode(callSuper = true) +@Data +@TableName("t_affiliate_income") +public class AffiliateIncome extends BaseEntity { + + private Long affiliateId; + + private Long affiliateAccountId; + + private Long inviteeAccountId; + + private Float amount; + + private LocalDateTime paymentTime; + + private Float commission; + +} diff --git a/src/main/java/com/ai/da/model/dto/AffiliateQueryDTO.java b/src/main/java/com/ai/da/model/dto/AffiliateQueryDTO.java index 5498964b..79fac3e7 100644 --- a/src/main/java/com/ai/da/model/dto/AffiliateQueryDTO.java +++ b/src/main/java/com/ai/da/model/dto/AffiliateQueryDTO.java @@ -1,6 +1,7 @@ package com.ai.da.model.dto; import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; import lombok.Data; import lombok.EqualsAndHashCode; @@ -8,6 +9,23 @@ import lombok.EqualsAndHashCode; @Data @ApiModel("查询affiliate列表") public class AffiliateQueryDTO extends TimeQueryBaseDTO{ - + @ApiModelProperty("Active(活跃) || Inactive(过期) || Pending(待审批) || Refused(拒绝)") private String status; + + @ApiModelProperty("推广者id") + private Long affiliateId; + + @ApiModelProperty("按时间 DESC 降序 || ASC 升序") + private String order = "ASC"; + + @Override + public String toString() { + return "AffiliateQueryDTO{" + + "status='" + status + '\'' + ' ' + + "startTime='" + super.getStartTime() + '\'' + ' ' + + "endTime='" + super.getEndTime() + '\'' + ' ' + + "page='" + super.getPage() + '\'' + ' ' + + "size='" + super.getSize() + '\'' + ' ' + + '}'; + } } diff --git a/src/main/java/com/ai/da/model/vo/AccountLoginVO.java b/src/main/java/com/ai/da/model/vo/AccountLoginVO.java index 8033057b..d514dc8d 100644 --- a/src/main/java/com/ai/da/model/vo/AccountLoginVO.java +++ b/src/main/java/com/ai/da/model/vo/AccountLoginVO.java @@ -59,4 +59,7 @@ public class AccountLoginVO { // 是否自动续订 private boolean isAutoRenewal; + // 是否是affiliate + private boolean isAffiliate = false; + } diff --git a/src/main/java/com/ai/da/service/AffiliateService.java b/src/main/java/com/ai/da/service/AffiliateService.java index 768bb214..9ceb1cb1 100644 --- a/src/main/java/com/ai/da/service/AffiliateService.java +++ b/src/main/java/com/ai/da/service/AffiliateService.java @@ -7,8 +7,6 @@ import com.ai.da.model.vo.AffiliateVO; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.service.IService; -import java.util.List; - public interface AffiliateService extends IService { Boolean registerAsAnAffiliate(String promotionMethod); @@ -17,11 +15,17 @@ public interface AffiliateService extends IService { AffiliateVO personalAffiliateCenter(); + double[] getPersonalMonthlyIncome(int year); + Boolean applicationApproval(Long id, Boolean isApproved); void updateAffiliateInfoWithPayment(); Boolean affiliateLinkViewsIncrease(Long id); - List getEachAffiliateGeneratedRevenue(Long affiliateId, String startTime, String endTime); + IPage getEachAffiliateGeneratedRevenue(AffiliateQueryDTO affiliateQueryDTO); + + Affiliate getByAccountId(Long accountId); + + void commissionCalculation(Integer year, Integer month); } diff --git a/src/main/java/com/ai/da/service/StripeService.java b/src/main/java/com/ai/da/service/StripeService.java index f0a95a7c..978b7c41 100644 --- a/src/main/java/com/ai/da/service/StripeService.java +++ b/src/main/java/com/ai/da/service/StripeService.java @@ -44,5 +44,7 @@ public interface StripeService { boolean sendRenewalFailEmail(String invoiceId, String subscriptionId, String orderNo); - String getCustomerPaymentMethod(String name, String email); + List> getCustomerPaymentMethod(String name, String email); + + String detachCustomerAllPaymentMethod(String name, String email); } diff --git a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java index 74ccd3f2..5840852e 100644 --- a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java @@ -107,6 +107,9 @@ public class AccountServiceImpl extends ServiceImpl impl @Resource private StripeService stripeService; + @Resource + private AffiliateService affiliateService; + @Override @Transactional(rollbackFor = Exception.class) public AccountPreLoginVO preLogin(AccountPreLoginDTO accountDTO) { @@ -2428,6 +2431,10 @@ public class AccountServiceImpl extends ServiceImpl impl response.setAutoRenewal(subscriptionInfo.getStatus().equals("active")); } + Affiliate affiliate = affiliateService.getByAccountId(accountId); + if (!Objects.isNull(affiliate) && affiliate.getStatus().equals("Active")) { + response.setAffiliate(true); + } return response; } diff --git a/src/main/java/com/ai/da/service/impl/AffiliateServiceImpl.java b/src/main/java/com/ai/da/service/impl/AffiliateServiceImpl.java index a249b08d..220aefe6 100644 --- a/src/main/java/com/ai/da/service/impl/AffiliateServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/AffiliateServiceImpl.java @@ -7,6 +7,8 @@ import com.ai.da.common.response.ResultEnum; import com.ai.da.common.utils.CopyUtil; import com.ai.da.common.utils.RedisUtil; import com.ai.da.common.utils.SendEmailUtil; +import com.ai.da.mapper.primary.AccountMapper; +import com.ai.da.mapper.primary.AffiliateIncomeMapper; import com.ai.da.mapper.primary.AffiliateMapper; import com.ai.da.mapper.primary.SubscriptionInfoMapper; import com.ai.da.mapper.primary.entity.*; @@ -31,9 +33,10 @@ import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.math.BigDecimal; import java.time.LocalDateTime; -import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.Objects; +import java.util.function.Function; @Service @Slf4j @@ -51,6 +54,9 @@ public class AffiliateServiceImpl extends ServiceImpl getAffiliateList(AffiliateQueryDTO affiliateQueryDTO){ + log.info("parameter => {}", affiliateQueryDTO.toString()); QueryWrapper qw = new QueryWrapper<>(); - qw.eq(!StringUtils.isNullOrEmpty(affiliateQueryDTO.getStatus()), "status", affiliateQueryDTO.getStatus()); - qw.gt(!StringUtils.isNullOrEmpty(affiliateQueryDTO.getStartTime()), "create_time", affiliateQueryDTO.getStartTime()); - qw.lt(!StringUtils.isNullOrEmpty(affiliateQueryDTO.getEndTime()), "create_time", affiliateQueryDTO.getEndTime()); + qw.eq(!StringUtils.isNullOrEmpty(affiliateQueryDTO.getStatus()), "status", affiliateQueryDTO.getStatus()) + .gt(!StringUtils.isNullOrEmpty(affiliateQueryDTO.getStartTime()), "create_time", affiliateQueryDTO.getStartTime()) + .lt(!StringUtils.isNullOrEmpty(affiliateQueryDTO.getEndTime()), "create_time", affiliateQueryDTO.getEndTime()) + .eq(!Objects.isNull(affiliateQueryDTO.getAffiliateId()), "id", affiliateQueryDTO.getAffiliateId()) + .orderByDesc(affiliateQueryDTO.getOrder().equals("DESC"), "create_time"); return baseMapper.selectPage(new Page<>(affiliateQueryDTO.getPage(), affiliateQueryDTO.getSize()), qw); } @@ -96,6 +105,18 @@ public class AffiliateServiceImpl extends ServiceImpl> personalMonthlyIncome = affiliateIncomeMapper.getPersonalMonthlyIncome(accountId, year); + double[] commissions = new double[12]; + personalMonthlyIncome.forEach(income -> { + int month = Integer.parseInt(income.get("yearMonth").toString()); + commissions[month-1] = (double)income.get("totalCommission"); + }); + + return commissions; + } + // 审批申请 public Boolean applicationApproval(Long id, Boolean isApproved){ Affiliate affiliate = baseMapper.selectById(id); @@ -107,7 +128,7 @@ public class AffiliateServiceImpl extends ServiceImpl { // 2、根据order_no查付款用户id OrderInfo orderInfo = orderInfoService.getOrderByOrderNo(paymentInfo.getOrderNo()); + if (Objects.isNull(orderInfo)){ + return; + } Long accountId = orderInfo.getAccountId(); // 3、查该用户之前是否有初次订阅的订单 QueryWrapper qwOrderInfo = new QueryWrapper<>(); @@ -155,6 +179,7 @@ public class AffiliateServiceImpl extends ServiceImpl 0){ // 分配新用户首次订阅所付费用的25%作为佣金 BigDecimal commission = BigDecimal.valueOf(payerTotal).multiply(new BigDecimal("0.25")); @@ -168,6 +193,17 @@ public class AffiliateServiceImpl extends ServiceImpl getEachAffiliateGeneratedRevenue(Long affiliateId, String startTime, String endTime) { - List resp = new ArrayList<>() ; - // 1、从account表中找到所有关联了指定affiliateId的accountId - QueryWrapper qw = new QueryWrapper<>(); - qw.eq("invitation_code", affiliateId); - - List accountList = accountService.getBaseMapper().selectList(qw); - if (accountList.isEmpty()){ - return null; - } else { - accountList.forEach(account -> { - // 2、分别找到各个accountId产生的第一笔订阅 - Long accountId = account.getId(); - QueryWrapper subscriptionInfoQueryWrapper = new QueryWrapper<>(); - subscriptionInfoQueryWrapper.eq("account_id", accountId) - .and(s -> s.eq("status", "active").or().eq("status", "canceled")) - .gt(!StringUtils.isNullOrEmpty(startTime) ,"create_time", startTime) - .lt(!StringUtils.isNullOrEmpty(endTime) ,"create_time", endTime).last("limit 1"); - - SubscriptionInfo subscriptionInfo = subscriptionInfoMapper.selectOne(subscriptionInfoQueryWrapper); - // 2、分别第一笔订阅的付款信息 - if (!Objects.isNull(subscriptionInfo)){ - PaymentInfo paymentInfo = paymentInfoService.getPaymentInfoByOrderNo(subscriptionInfo.getOrderNo(), "ASC").get(0); - AffiliateInvitationDetailsVO affiliateInvitationDetailsVO = new AffiliateInvitationDetailsVO(); - affiliateInvitationDetailsVO.setAccountId(accountId); - affiliateInvitationDetailsVO.setUsername(account.getUserName()); - affiliateInvitationDetailsVO.setFirstSubscriptionPaymentAmount(paymentInfo.getPayerTotal()); - affiliateInvitationDetailsVO.setCommission(BigDecimal.valueOf(paymentInfo.getPayerTotal()).multiply(new BigDecimal("0.25")).floatValue()); - affiliateInvitationDetailsVO.setTime(subscriptionInfo.getCreateTime()); - resp.add(affiliateInvitationDetailsVO); - } - }); + public IPage getEachAffiliateGeneratedRevenue(AffiliateQueryDTO affiliateQueryDTO) { + if (Objects.isNull(affiliateQueryDTO.getAffiliateId())){ + throw new BusinessException("Please specify the affiliate ID.", ResultEnum.PROMPT.getCode()); } - return resp; + + QueryWrapper affiliateIncomeQueryWrapper = new QueryWrapper<>(); + affiliateIncomeQueryWrapper + .gt(!StringUtils.isNullOrEmpty(affiliateQueryDTO.getStartTime()), "create_time", affiliateQueryDTO.getStartTime()) + .lt(!StringUtils.isNullOrEmpty(affiliateQueryDTO.getEndTime()), "create_time", affiliateQueryDTO.getEndTime()) + .eq(!Objects.isNull(affiliateQueryDTO.getAffiliateId()), "affiliate_id", affiliateQueryDTO.getAffiliateId()) + .orderByDesc(affiliateQueryDTO.getOrder().equals("DESC"), "create_time"); + IPage affiliateIncomePage = affiliateIncomeMapper.selectPage(new Page<>(affiliateQueryDTO.getPage(), affiliateQueryDTO.getSize()), affiliateIncomeQueryWrapper); + return affiliateIncomePage.convert((Function) affiliateIncome -> { + AffiliateInvitationDetailsVO affiliateInvitationDetailsVO = CopyUtil.copyObject(affiliateIncome, AffiliateInvitationDetailsVO.class); + affiliateInvitationDetailsVO.setAccountId(affiliateIncome.getInviteeAccountId()); + affiliateInvitationDetailsVO.setUsername(accountService.getBaseMapper().selectById(affiliateIncome.getInviteeAccountId()).getUserName()); + affiliateInvitationDetailsVO.setFirstSubscriptionPaymentAmount(affiliateIncome.getAmount()); + affiliateInvitationDetailsVO.setCommission(affiliateIncome.getCommission()); + affiliateInvitationDetailsVO.setTime(affiliateIncome.getPaymentTime()); + return affiliateInvitationDetailsVO; + }); } - // todo 每个月给kim发一封邮件统计本月的affiliate等的收入 - public void commissionCalculation(){ - // 1、总收入(近一个月通过affiliate产生的收入) + public void commissionCalculation(Integer year, Integer month) { + if (Objects.isNull(year)) { + year = LocalDateTime.now().getYear(); + } + if (Objects.isNull(month)) { + month = LocalDateTime.now().getMonthValue(); + } - // 2、未支付的金额 affiliate表中unpaid的总和 + List> monthlyAffiliateIncome = affiliateIncomeMapper.getMonthlyAffiliateIncome(year, month); + // 1、总收入(近一个月通过affiliate产生的收入),未支付的金额 affiliate表中unpaid的总和 + Double totalAmount = 0.0; + Double totalCommission = 0.0; + if (!monthlyAffiliateIncome.isEmpty()){ + Map monthlyIncome = monthlyAffiliateIncome.get(0); + totalAmount = (Double) monthlyIncome.get("totalAmount"); + totalCommission = (Double) monthlyIncome.get("totalCommission"); + } - // 3、邀请的新人 查询account表中,本月新增并有invitation_id的数量 + // 2、本月新注册的Affiliate + Map monthlyApprovedAffiliate = baseMapper.getMonthlyApprovedAffiliate(year, month); + Long count = monthlyApprovedAffiliate.get("count"); + AffiliateEmailParamsDTO affiliateEmailParamsDTO = new AffiliateEmailParamsDTO(); + affiliateEmailParamsDTO.setTotalProgramRevenue(totalAmount.toString()); + affiliateEmailParamsDTO.setNewApprovedAffiliates(count.toString()); + affiliateEmailParamsDTO.setUnpaidEarnings(totalCommission.toString()); + affiliateEmailParamsDTO.setPaidEarnings("0"); + String receiverEmail = "xupei3360@163.com"; +// String receiverEmail = "kimwong@code-create.com.hk"; + // 邮件通知 + SendEmailUtil.affiliateEmailReminder(receiverEmail, affiliateEmailParamsDTO, "summary"); + } + + @Override + public Affiliate getByAccountId(Long accountId) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("account_id", accountId).orderByDesc("id").last("limit 1"); + + return baseMapper.selectOne(queryWrapper); } diff --git a/src/main/java/com/ai/da/service/impl/StripeServiceImpl.java b/src/main/java/com/ai/da/service/impl/StripeServiceImpl.java index 3d776186..f16bbb85 100644 --- a/src/main/java/com/ai/da/service/impl/StripeServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/StripeServiceImpl.java @@ -1004,8 +1004,8 @@ public class StripeServiceImpl implements StripeService { try { OrderInfo orderInfo = orderInfoService.createOrderByProductId(1, PayTypeEnum.STRIPE.getType(), ProductEnum.DailySubscription); - String customerId = getCustomer(name, email); -/* String paymentMethodCode = "pm_card_mastercard"; +// String customerId = getCustomer(name, email); + String paymentMethodCode = "pm_card_mastercard"; PaymentMethod paymentMethod = PaymentMethod.retrieve(paymentMethodCode); String customerId = getCustomer(name, email); @@ -1014,14 +1014,14 @@ public class StripeServiceImpl implements StripeService { PaymentMethodAttachParams attachParams = PaymentMethodAttachParams.builder() .setCustomer(customerId) .build(); - paymentMethod.attach(attachParams);*/ + paymentMethod.attach(attachParams); // 设置默认付款方式 Customer updatedCustomer = Customer.retrieve(customerId); CustomerUpdateParams params = CustomerUpdateParams.builder() .setInvoiceSettings( CustomerUpdateParams.InvoiceSettings.builder() -// .setDefaultPaymentMethod(paymentMethod.getId()) + .setDefaultPaymentMethod(paymentMethod.getId()) .build() ) .build(); @@ -1081,19 +1081,54 @@ public class StripeServiceImpl implements StripeService { } } - public String getCustomerPaymentMethod(String name, String email){ + public List> getCustomerPaymentMethod(String name, String email){ Stripe.apiKey = privateKey; try { String customerId = getCustomer(name, email); Customer customer = Customer.retrieve(customerId); PaymentMethodCollection paymentMethodCollection = customer.listPaymentMethods(); List data = paymentMethodCollection.getData(); + ArrayList> resp = new ArrayList<>(); + data.forEach(paymentMethod -> { + Map map = new HashMap<>(); + if (paymentMethod.getType().equals("card")){ + map.put(paymentMethod.getId(),paymentMethod.getCard().getLast4()); + }else { + map.put(paymentMethod.getId(),null); + } + resp.add(map); + }); - // todo 方向: 向用户添加了多种付款方式,更改默认的付款方式后,默认付款方式付款失败后是否自动使用其他付款方式付款? + return resp; + // 方向: 向用户添加了多种付款方式,更改默认的付款方式后,默认付款方式付款失败后是否自动使用其他付款方式付款? // 如果是的,则需要删除能成功的付款方式,保留唯一失败的付款方式进行续订付款失败测试 } catch (StripeException e) { throw new RuntimeException(e); } + + } + + public String detachCustomerAllPaymentMethod(String name, String email){ + Stripe.apiKey = privateKey; + // 方向: 向用户添加了多种付款方式,更改默认的付款方式后,默认付款方式付款失败后是否自动使用其他付款方式付款? + // 如果是的,则需要删除能成功的付款方式,保留唯一失败的付款方式进行续订付款失败测试 + try { + String customerId = getCustomer(name, email); + Customer customer = Customer.retrieve(customerId); + PaymentMethodCollection paymentMethodCollection = customer.listPaymentMethods(); + List data = paymentMethodCollection.getData(); + data.forEach(paymentMethod -> { + try { + PaymentMethod retrieve = PaymentMethod.retrieve(paymentMethod.getId()); + PaymentMethodDetachParams params = PaymentMethodDetachParams.builder().build(); + retrieve.detach(params); + } catch (StripeException e) { + throw new RuntimeException(e); + } + }); + } catch (StripeException e) { + throw new RuntimeException(e); + } return null; } @@ -1102,8 +1137,10 @@ public class StripeServiceImpl implements StripeService { qw.eq("subscription_id", subscriptionId); SubscriptionInfo subscriptionInfo = subscriptionInfoMapper.selectOne(qw); - subscriptionInfo.setCancelReason(reason); - subscriptionInfoMapper.updateById(subscriptionInfo); + if (!Objects.isNull(subscriptionInfo)) { + subscriptionInfo.setCancelReason(reason); + subscriptionInfoMapper.updateById(subscriptionInfo); + } } diff --git a/src/main/resources/mapper/primary/AffiliateIncomeMapper.xml b/src/main/resources/mapper/primary/AffiliateIncomeMapper.xml new file mode 100644 index 00000000..bac4a547 --- /dev/null +++ b/src/main/resources/mapper/primary/AffiliateIncomeMapper.xml @@ -0,0 +1,36 @@ + + + + + + + + + diff --git a/src/main/resources/mapper/primary/AffiliateMapper.xml b/src/main/resources/mapper/primary/AffiliateMapper.xml new file mode 100644 index 00000000..8dbe92da --- /dev/null +++ b/src/main/resources/mapper/primary/AffiliateMapper.xml @@ -0,0 +1,16 @@ + + + + + + + From 1a19604163bdbd9aea23cd4f1e4fd6e64d10b052 Mon Sep 17 00:00:00 2001 From: shahaibo <1023316923@qq.com> Date: Thu, 19 Dec 2024 10:51:38 +0800 Subject: [PATCH 16/91] TASK:AiDA --- .../ai/da/controller/AccountController.java | 6 + .../da/mapper/primary/DesignBatchMapper.java | 16 ++ .../da/mapper/primary/entity/DesignBatch.java | 44 ++++ .../dto/AccountDesignWorksRegisterDTO.java | 2 + .../java/com/ai/da/python/PythonService.java | 76 +++++-- .../com/ai/da/service/AccountService.java | 1 + .../java/com/ai/da/service/DesignService.java | 4 + .../da/service/impl/AccountServiceImpl.java | 23 +- .../ai/da/service/impl/DesignServiceImpl.java | 205 ++++++++++++++++-- 9 files changed, 329 insertions(+), 48 deletions(-) create mode 100644 src/main/java/com/ai/da/mapper/primary/DesignBatchMapper.java create mode 100644 src/main/java/com/ai/da/mapper/primary/entity/DesignBatch.java diff --git a/src/main/java/com/ai/da/controller/AccountController.java b/src/main/java/com/ai/da/controller/AccountController.java index 12de1981..a16337ce 100644 --- a/src/main/java/com/ai/da/controller/AccountController.java +++ b/src/main/java/com/ai/da/controller/AccountController.java @@ -323,6 +323,12 @@ public class AccountController { return Response.success(accountService.bindWeChat(code)); } + @GetMapping("/bindEmail") + @ApiOperation(value = "绑定邮箱") + public Response bindEmail(@RequestParam("email") String email) { + return Response.success(accountService.bindEmail(email)); + } + @GetMapping("/unbindWeChat") @ApiOperation(value = "解除绑定微信") public Response unbindWeChat() { diff --git a/src/main/java/com/ai/da/mapper/primary/DesignBatchMapper.java b/src/main/java/com/ai/da/mapper/primary/DesignBatchMapper.java new file mode 100644 index 00000000..1c8f2b65 --- /dev/null +++ b/src/main/java/com/ai/da/mapper/primary/DesignBatchMapper.java @@ -0,0 +1,16 @@ +package com.ai.da.mapper.primary; + +import com.ai.da.common.config.mybatis.plus.CommonMapper; +import com.ai.da.mapper.primary.entity.AccountExtend; +import com.ai.da.mapper.primary.entity.DesignBatch; + +/** + * Mapper 接口 + * + * @author easy-generator + * @since 2022-06-13 + */ +public interface DesignBatchMapper extends CommonMapper { + + +} diff --git a/src/main/java/com/ai/da/mapper/primary/entity/DesignBatch.java b/src/main/java/com/ai/da/mapper/primary/entity/DesignBatch.java new file mode 100644 index 00000000..3ad4dbb5 --- /dev/null +++ b/src/main/java/com/ai/da/mapper/primary/entity/DesignBatch.java @@ -0,0 +1,44 @@ +package com.ai.da.mapper.primary.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.models.auth.In; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +import java.io.Serializable; +import java.time.LocalDateTime; + +@Data +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("design_batch") +public class DesignBatch implements Serializable { + private static final long serialVersionUID = 1L; + + /** + * ID + */ + @TableId(value = "id", type = IdType.AUTO) + private Long id; + + private Long accountId; // account_id + + private Long designId; // design_id + + private Long collectionId; // collection_id + + private Integer status; // status + + private LocalDateTime createTime; // create_time + + private LocalDateTime updateTime; // update_time + + private String taskId; // task_id + + private Integer totalNum; // total_num + + private Integer completedNum; // completed_num +} diff --git a/src/main/java/com/ai/da/model/dto/AccountDesignWorksRegisterDTO.java b/src/main/java/com/ai/da/model/dto/AccountDesignWorksRegisterDTO.java index db2dac3b..27320588 100644 --- a/src/main/java/com/ai/da/model/dto/AccountDesignWorksRegisterDTO.java +++ b/src/main/java/com/ai/da/model/dto/AccountDesignWorksRegisterDTO.java @@ -6,4 +6,6 @@ import lombok.Data; @Data public class AccountDesignWorksRegisterDTO extends Account { private String emailVerifyCode; + +// private String invitationCode; } diff --git a/src/main/java/com/ai/da/python/PythonService.java b/src/main/java/com/ai/da/python/PythonService.java index 5cb17cee..f7f47631 100644 --- a/src/main/java/com/ai/da/python/PythonService.java +++ b/src/main/java/com/ai/da/python/PythonService.java @@ -41,6 +41,7 @@ import org.springframework.web.multipart.MultipartFile; import javax.annotation.Resource; import java.io.File; +import java.io.FileWriter; import java.io.IOException; import java.math.BigDecimal; import java.math.RoundingMode; @@ -237,6 +238,9 @@ public class PythonService { int[] sketchNumbers = new int[3]; int designNum = elementVO.getDesignNum(); + Set assembledObjects = new HashSet<>(); // 用于存储已组装的 DesignPythonObject + DesignPythonObject lastAssembledObject = null; // 上一次组装的对象 + for (int i = 0; i < designNum; i++) { CurrentDesignPictureTypeEnum designPictureType = calculateCurrentDesignPictureTypeNew(elementVO, sketchNumbers, systemScale); if (designPictureType == null) break; @@ -256,13 +260,28 @@ public class PythonService { noPrintNum--; break; } -// updatePrintNumbers(designPrintPictureType, pinPrintNum, noPinPrintNum, noPrintNum); DesignPythonItemPrint designPythonItemPrint = getRandomPrint(elementVO, designPrintPictureType); elementVO.setDesignPythonItemPrint(designPythonItemPrint); elementVO.setDesignPrintPictureTypeLayoutList(calculateCurrentDesignPintPictureTypeLayout(elementVO.getModelSex())); DesignPythonObject pythonObject = createDesignPythonObject(elementVO, designPictureType, systemScale, singleOverall, switchCategory, i); + + // 如果当前对象与已组装的对象重复,则跳过当前组装 + if (assembledObjects.contains(pythonObject)) { + if (lastAssembledObject != null && assembledObjects.contains(lastAssembledObject)) { + // 如果当前组装与前一个组装的对象重复,且前一个组装也重复,结束组装 + System.out.println("当前组装的对象与前两个组装的对象重复,结束组装。"); + break; + } + // 否则,跳过当前组装 + continue; + } + + // 将当前对象添加到已组装的集合中,并记录 + assembledObjects.add(pythonObject); + lastAssembledObject = pythonObject; // 更新上一次组装的对象 + objects.add(pythonObject); redisUtil.addProcessId(processId, i + 1); } @@ -3672,29 +3691,44 @@ public class PythonService { throw new BusinessException("Atribute recognition exception!"); } - public JSONObject designBatch(DesignPythonObjects designPythonObjects) { + public String designBatch(DesignPythonObjects designPythonObjects, Long accountId, int designNum, String taskId) { // todo 限流校验 -// AccessLimitUtils.validate("design",5); + // AccessLimitUtils.validate("design",5); + + // 将 designPythonObjects 写入文件 + File file = new File("design_batch_test.txt"); + try (FileWriter writer = new FileWriter(file)) { + String param = JSON.toJSONString(designPythonObjects, SerializerFeature.DisableCircularReferenceDetect); + writer.write(param); + log.info("设计请求参数已写入文件:####{}", file.getAbsolutePath()); + } catch (IOException e) { + log.error("写入文件异常:{}", e.getMessage()); + throw new BusinessException("file.write.exception"); + } + OkHttpClient client = new OkHttpClient().newBuilder() .connectTimeout(30, TimeUnit.SECONDS) - .pingInterval(5, TimeUnit.SECONDS)//websocket轮训间隔(单位:秒) - .readTimeout(60, TimeUnit.SECONDS)//读取超时(单位:秒) - .writeTimeout(60, TimeUnit.SECONDS)//写入超时(单位:秒) + .pingInterval(5, TimeUnit.SECONDS) + .readTimeout(60, TimeUnit.SECONDS) + .writeTimeout(60, TimeUnit.SECONDS) .build(); - MediaType mediaType = MediaType.parse("application/json"); - //关闭FastJson的引用检测 防止出现$ref 现象 - String param = JSON.toJSONString(designPythonObjects, SerializerFeature.DisableCircularReferenceDetect); - log.info("design请求python 参数:####{}", param); - RequestBody body = RequestBody.create(mediaType, param); - Request request = new Request.Builder() - .url(accessPythonIp + ":" + accessPythonPort + "/api/design_batch_generate") -// .url(fastApiPythonAddress + "/api/design") -// .url(accessPythonIp + ":10200/aifda/api/v1.0/generate") - .method("POST", body) - .addHeader("Authorization", "Basic YWlkbGFiOjEyMw==") - .addHeader("Content-Type", "application/json") + // 构建 multipart 表单 + RequestBody body = new MultipartBody.Builder().setType(MultipartBody.FORM) + .addFormDataPart("file", "design_batch_test.txt", + RequestBody.create(MediaType.parse("text/plain"), file)) + .addFormDataPart("tasks_id", taskId) + .addFormDataPart("user_id", String.valueOf(accountId)) + .addFormDataPart("file_name", "design_batch_test" + taskId + ".json") + .addFormDataPart("total", String.valueOf(designNum)) .build(); + + Request request = new Request.Builder() + .url("http://18.167.251.121:9994/api/design_batch_generate") + .method("POST", body) + .addHeader("Content-Type", "multipart/form-data") + .build(); + Response response; String responseBody; try { @@ -3705,15 +3739,13 @@ public class PythonService { throw new BusinessException("design.interface.exception"); } - //去除限流 -// AccessLimitUtils.validateOut("design"); if (response.isSuccessful()) { try { if (Objects.nonNull(response.body())) { responseBody = response.body().string(); JSONObject responseObject = JSON.parseObject(responseBody); log.info("PythonService##responseObject###{}", responseObject); - return responseObject; + return taskId; } throw new BusinessException("design.interface.exception"); } catch (IOException | JSONException e) { @@ -3722,7 +3754,7 @@ public class PythonService { } } log.error("PythonService##design异常response###{}", response); - //生成失败 throw new BusinessException("design.interface.exception"); } + } diff --git a/src/main/java/com/ai/da/service/AccountService.java b/src/main/java/com/ai/da/service/AccountService.java index a792bd74..6ecb4f0a 100644 --- a/src/main/java/com/ai/da/service/AccountService.java +++ b/src/main/java/com/ai/da/service/AccountService.java @@ -48,6 +48,7 @@ public interface AccountService extends IService { * @return */ Boolean bindEmail(AccountBindEmailDTO accountBindEmailDTO); + Boolean bindEmail(String email); /** * 忘记密码 diff --git a/src/main/java/com/ai/da/service/DesignService.java b/src/main/java/com/ai/da/service/DesignService.java index d362d27b..80d13f47 100644 --- a/src/main/java/com/ai/da/service/DesignService.java +++ b/src/main/java/com/ai/da/service/DesignService.java @@ -12,6 +12,8 @@ import com.baomidou.mybatisplus.extension.service.IService; import java.math.BigDecimal; import java.util.List; +import java.util.Map; +import java.util.Objects; /** * 服务类 @@ -106,4 +108,6 @@ public interface DesignService extends IService { DesignCollectionVO getDesignResult(String requestId, List objectSignList); String designCloud(DesignCollectionDTO designDTO); + + void processDesignBatch(Map designBatchResult); } diff --git a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java index ca71c47d..211fe4a8 100644 --- a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java @@ -1217,6 +1217,7 @@ public class AccountServiceImpl extends ServiceImpl impl account.setValidStartTime(Instant.now().toEpochMilli()); account.setCreateDate(new Date()); account.setCredits(BigDecimal.valueOf(0)); + account.setInvitationCode(accountDesignWorksRegisterDTO.getInvitationCode()); accountMapper.insert(account); AccountLoginVO response = CopyUtil.copyObject(account, AccountLoginVO.class); response.setEmail(account.getUserEmail()); @@ -2424,19 +2425,6 @@ public class AccountServiceImpl extends ServiceImpl impl response.setAccountExtendList(accountExtends); } response.setLanguage(Language.valueOf(account.getLanguage()).name()); - SubscriptionInfo subscriptionInfo = stripeService.getLatestSubscriptionInfoByAccountId(accountId); - if (!Objects.isNull(subscriptionInfo)) { - response.setSubscriptionId(subscriptionInfo.getSubscriptionId()); - response.setSubscriptionType(subscriptionInfo.getType()); - response.setStatus(subscriptionInfo.getStatus()); - response.setExpireTime(String.valueOf(subscriptionInfo.getCurrentPeriodEnd())); - response.setAutoRenewal(subscriptionInfo.getStatus().equals("active")); - } - - Affiliate affiliate = affiliateService.getByAccountId(accountId); - if (!Objects.isNull(affiliate) && affiliate.getStatus().equals("Active")) { - response.setAffiliate(true); - } return response; } @@ -2539,4 +2527,13 @@ public class AccountServiceImpl extends ServiceImpl impl accountExtendMapper.delete(qw); return Boolean.TRUE; } + + @Override + public Boolean bindEmail(String email) { + AuthPrincipalVo userHolder = UserContext.getUserHolder(); + Account account = accountMapper.selectById(userHolder.getId()); + account.setUserEmail(email); + accountMapper.updateById(account); + return Boolean.TRUE; + } } diff --git a/src/main/java/com/ai/da/service/impl/DesignServiceImpl.java b/src/main/java/com/ai/da/service/impl/DesignServiceImpl.java index 5f70f836..05275007 100644 --- a/src/main/java/com/ai/da/service/impl/DesignServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/DesignServiceImpl.java @@ -8,6 +8,7 @@ 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.*; +import com.ai.da.mapper.primary.DesignBatchMapper; import com.ai.da.mapper.primary.DesignMapper; import com.ai.da.mapper.primary.GenerateDetailMapper; import com.ai.da.mapper.primary.TDesignPythonOutfitMapper; @@ -110,6 +111,9 @@ public class DesignServiceImpl extends ServiceImpl impleme @Resource private RedisUtil redisUtil; + @Resource + private DesignBatchMapper designBatchMapper; + private final ConcurrentHashMap> designContext = new ConcurrentHashMap<>(); @@ -1623,14 +1627,6 @@ public class DesignServiceImpl extends ServiceImpl impleme collectionId = collectionService.saveCollection(userInfo.getId(), designDTO.getTimeZone(), designDTO.getMoodTemplateId(), designDTO.getMoodboardPostion()); }else { collectionId = collectionIdParam; -// Collection byId = collectionService.getById(collectionIdParam); -// if (!designDTO.getMoodboardPostion().equals(byId.getMoodboardPosition())) { -// byId.setMoodboardPosition(designDTO.getMoodboardPostion()); -// } -// if (!designDTO.getMoodTemplateId().equals(byId.getMoodTemplateId())) { -// byId.setMoodTemplateId(designDTO.getMoodTemplateId()); -// } -// collectionService.updateById(byId); } List elementIds = getElementId(elementVO); //批量关联element 到 collection @@ -1662,7 +1658,20 @@ public class DesignServiceImpl extends ServiceImpl impleme startTime = System.currentTimeMillis(); String requestId = UUID.randomUUID().toString(); pythonObjects.setRequestId(requestId); - JSONObject responseJSONObject = pythonService.designBatch(pythonObjects); + AuthPrincipalVo userHolder = UserContext.getUserHolder(); + String taskId = pythonService.designBatch(pythonObjects, userHolder.getId(), elementVO.getDesignNum(), requestId); + + DesignBatch designBatch = new DesignBatch(); + + designBatch.setAccountId(userInfo.getId()); + designBatch.setDesignId(designId); + designBatch.setCollectionId(collectionId); + designBatch.setTaskId(taskId); + designBatch.setCreateTime(LocalDateTime.now()); + designBatch.setStatus(0); + designBatch.setTotalNum(elementVO.getDesignNum()); + designBatchMapper.insert(designBatch); + endTime = System.currentTimeMillis(); totalTimeInSeconds = (endTime - startTime) / 1000; log.info("design python端运行时间:" + totalTimeInSeconds + " 秒"); @@ -1688,11 +1697,181 @@ public class DesignServiceImpl extends ServiceImpl impleme context.put("requestIdList", elementVO.getRequestIdList()); // 将上下文存入全局设计上下文中 - designContext.put(requestId, context); + designContext.put(taskId, context); + return taskId; + } + + @Override + public void processDesignBatch(Map designBatchResult) { + Object progress = designBatchResult.get("progress"); + if (progress instanceof String) { + if (progress.equals("0/100")) { + return; + } + if (progress.equals("ok")) { + String taskId = (String) designBatchResult.get("task_id"); + QueryWrapper qw = new QueryWrapper<>(); + qw.lambda().eq(DesignBatch::getTaskId, taskId); + List designBatches = designBatchMapper.selectList(qw); + if (CollectionUtil.isNotEmpty(designBatches)) { + DesignBatch designBatch = designBatches.get(0); + designBatch.setStatus(1); + designBatchMapper.updateById(designBatch); + } + } + }else { + String taskId = (String) designBatchResult.get("task_id"); + QueryWrapper qw = new QueryWrapper<>(); + qw.lambda().eq(DesignBatch::getTaskId, taskId); + List designBatches = designBatchMapper.selectList(qw); + if (CollectionUtil.isNotEmpty(designBatches)) { + DesignBatch designBatch = designBatches.get(0); + if (designBatch.getCompletedNum() == null) { + designBatch.setCompletedNum(1); + }else { + designBatch.setCompletedNum(designBatch.getCompletedNum() + 1); + } + designBatchMapper.updateById(designBatch); + } + + Integer i = (Integer) progress; + Map context; + synchronized (designContext) { + context = designContext.get(taskId); + if (context == null) { + log.error("上下文数据缺失,无法完成操作"); + return; + } + + DesignPythonObjects pythonObjects = (DesignPythonObjects) context.get("pythonObjects"); + Long designId = (Long) context.get("designId"); + Long collectionId = (Long) context.get("collectionId"); + AuthPrincipalVo userInfo = (AuthPrincipalVo) context.get("userInfo"); + String timeZone = (String) context.get("timeZone"); + String singleOverall = (String) context.get("singleOverall"); + + DesignPythonObject item = pythonObjects.getObjects().get(i); + DesignItem designItem = new DesignItem(); + designItem.setAccountId(userInfo.getId()); + designItem.setCollectionId(collectionId); + designItem.setDesignId(designId); + designItem.setCreateDate(DateUtil.getByTimeZone(timeZone)); + //生成的八张图片 + designItem.setDesignUrl(item.getBasic().getSave_name()); + designItem.setHasLike((byte) 0); + //生成designItem + Long designItemId = designItemService.saveOne(designItem); + // python design返回入库及封装 + JSONObject outfit = (JSONObject) designBatchResult.get("result"); + if (null == outfit) { + return; + } + TDesignPythonOutfit designPythonOutfit = new TDesignPythonOutfit(); + designPythonOutfit.setDesignItemId(designItemId); + designPythonOutfit.setUserId(userInfo.getId()); + designPythonOutfit.setDesignId(designId); + designPythonOutfit.setCollectionId(collectionId); + String synthesisUrl = outfit.getString("synthesis_url"); + if (!StringUtils.isEmpty(synthesisUrl)) { + designPythonOutfit.setDesignUrl(synthesisUrl); + } else { + throw new BusinessException("design.interface.exception"); + } + designPythonOutfitService.save(designPythonOutfit); + + JSONArray layers = outfit.getJSONArray("layers"); + List list = new ArrayList<>(); + DesignCollectionItemVO designCollectionItemVO = new DesignCollectionItemVO(); + for (int i1 = 0; i1 < layers.size(); i1++) { + JSONObject jsonObject = layers.getJSONObject(i1); + TDesignPythonOutfitDetail designPythonOutfitDetail = new TDesignPythonOutfitDetail(); + designPythonOutfitDetail.setDesignId(designId); + designPythonOutfitDetail.setDesignPythonOutfitId(designPythonOutfit.getId()); + designPythonOutfitDetail.setPosition(jsonObject.getString("position")); + designPythonOutfitDetail.setImageSize(jsonObject.getString("image_size")); + designPythonOutfitDetail.setImageUrl(jsonObject.getString("image_url")); + if (singleOverall.equals(SingleOverallEnum.SINGLE.getRealName())) { + designCollectionItemVO.setDesignItemUrl(designItem.getDesignUrl()); + } + designPythonOutfitDetail.setImageCategory(jsonObject.getString("image_category")); + designPythonOutfitDetail.setMaskUrl(jsonObject.getString("mask_url")); + designPythonOutfitDetail.setUserId(userInfo.getId()); + designPythonOutfitDetail.setPriority(Integer.parseInt(jsonObject.getString("priority"))); + designPythonOutfitDetail.setCreateDate(LocalDateTime.now()); + list.add(designPythonOutfitDetail); + } + designPythonOutfitDetailService.saveBatch(list); + designCollectionItemVO.setDesignItemId(designItemId); + designCollectionItemVO.setDesignItemUrl(designItem.getDesignUrl()); + designCollectionItemVO.setDesignOutfitId(designPythonOutfit.getId()); + String designUrl = designPythonOutfit.getDesignUrl(); + if (!StringUtils.isEmpty(designUrl) && designUrl.contains("/")) { + int firstIndex = designUrl.indexOf("/"); + designCollectionItemVO.setDesignOutfitUrl(minioUtil.getPreSignedUrl(designUrl.substring(0, firstIndex) + "/" + designUrl.substring(firstIndex + 1), 24 * 60)); + } + //response +// designCollectionItems.add(designCollectionItemVO); + + List designItemDetails = Lists.newArrayList(); + Map typePriority = list.stream().collect(Collectors.toMap(d -> d.getImageCategory().split("_")[0], + d -> Math.abs(d.getPriority()), + (existing, replacement) -> replacement)); + Map typeAndUndividedLayer = designItemService.setTypeAndUndividedLayer(layers); + for (DesignPythonItem detail : item.getItems()) { + if (null == detail) { + continue; + } + DesignItemDetail designItemDetail = CopyUtil.copyObject(detail, DesignItemDetail.class); + designItemDetail.setAccountId(userInfo.getId()); + designItemDetail.setDesignId(designId); + designItemDetail.setDesignItemId(designItemId); + designItemDetail.setCollectionElementId(detail.getElementId()); + designItemDetail.setCreateDate(DateUtil.getByTimeZone(timeZone)); + designItemDetail.setUndividedLayer(typeAndUndividedLayer.get(designItemDetail.getType().toLowerCase())); + if (SysFileLevel2TypeEnum.BODY.getRealName().equals(detail.getType())) { + designItemDetail.setPath(detail.getBody_path()); + //BODY不关联businessId + designItemDetail.setBusinessId(0L); + } + designItemDetail.setIconPath(detail.getIcon()); + designItemDetail.setPriority(typePriority.get(detail.getType().toLowerCase())); + if (!detail.getType().equals("Body")){ + DesignPythonItemPrint printObject = detail.getPrint().getOverall(); +// designItemDetail.setPrintPath(Objects.isNull(printObject) ? "" : printObject.getPath()); + designItemDetail.setPrintPath(CollectionUtils.isEmpty(printObject.getPrint_path_list()) ? "" : printObject.getPrint_path_list().get(0)); + } + designItemDetailService.save(designItemDetail); + if (!SysFileLevel2TypeEnum.BODY.getRealName().equals(detail.getType()) && !StringUtil.isNullOrEmpty(designItemDetail.getPrintPath())) { + DesignItemDetailPrint print = new DesignItemDetailPrint(); + print.setDesignItemDetailId(designItemDetail.getId()); + print.setPrintType("print"); + print.setPath(designItemDetail.getPrintPath()); + print.setSingleOrOverall("overall"); + print.setPosition("[0.0,0.0]"); +// print.setScale(1d); + // todo mark 将print默认scale置为0.3 + print.setScale(0.3d); + print.setAngle(0.0); + print.setPriority(1); + QueryWrapper getPrintboardLevel2TypeQw = new QueryWrapper<>(); + getPrintboardLevel2TypeQw.lambda().eq(CollectionElement::getUrl, print.getPath()); + getPrintboardLevel2TypeQw.lambda().orderByDesc(CollectionElement::getCreateDate); + getPrintboardLevel2TypeQw.last("limit 1"); + CollectionElement one = collectionElementService.getOne(getPrintboardLevel2TypeQw); + print.setLevel2Type(one.getLevel2Type()); + print.setCreateDate(LocalDateTime.now()); + designItemDetailPrintService.save(print); + } + } + } + +// for (int i = 0; i < pythonObjects.getObjects().size(); i++) { +// +// } +// response.setProcessId(pythonObjects.getProcess_id()); + return; + } - //保存python返回信息;保存designItem和detail -// return savePythonDesignItemAndDetail(pythonObjects, designId, collectionId, userInfo, designDTO.getTimeZone(), responseJSONObject, designDTO.getSingleOverall()); - return requestId; } } From 3dc432131c1667afd401547f8bbfeca47e42ad5c Mon Sep 17 00:00:00 2001 From: shahaibo <1023316923@qq.com> Date: Thu, 19 Dec 2024 11:13:30 +0800 Subject: [PATCH 17/91] TASK:AiDA --- .../com/ai/da/model/dto/AccountBindEmailDTO.java | 6 +++--- .../com/ai/da/service/impl/AccountServiceImpl.java | 13 ++++++++----- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/ai/da/model/dto/AccountBindEmailDTO.java b/src/main/java/com/ai/da/model/dto/AccountBindEmailDTO.java index 8671e051..d0b67792 100644 --- a/src/main/java/com/ai/da/model/dto/AccountBindEmailDTO.java +++ b/src/main/java/com/ai/da/model/dto/AccountBindEmailDTO.java @@ -11,9 +11,9 @@ import javax.validation.constraints.NotNull; @ApiModel("绑定邮箱") public class AccountBindEmailDTO { - @NotNull(message = "userId.cannot.be.empty") - @ApiModelProperty("用户id") - private Long userId; +// @NotNull(message = "userId.cannot.be.empty") +// @ApiModelProperty("用户id") +// private Long userId; @NotBlank(message = "email.cannot.be.empty") @ApiModelProperty("邮箱") diff --git a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java index 211fe4a8..e92d0149 100644 --- a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java @@ -281,13 +281,15 @@ public class AccountServiceImpl extends ServiceImpl impl @Override public Boolean bindEmail(AccountBindEmailDTO accountBindEmailDTO) { - Account account = baseMapper.selectById(accountBindEmailDTO.getUserId()); +// Account account = baseMapper.selectById(accountBindEmailDTO.getUserId()); + AuthPrincipalVo userHolder = UserContext.getUserHolder(); + Account account = accountMapper.selectById(userHolder.getId()); if (Objects.isNull(account)) { throw new BusinessException("userName.does.not.exist", ResultEnum.PROMPT.getCode()); } - if (StringUtils.isNotBlank(account.getUserEmail())) { - throw new BusinessException("user.has.bound.mailbox"); - } +// if (StringUtils.isNotBlank(account.getUserEmail())) { +// throw new BusinessException("user.has.bound.mailbox"); +// } //校验邮箱验证码 String verifyCode = LocalCacheUtils.getVerifyCodeCache(AuthenticationOperationTypeEnum.BIND_MAILBOX.name() + "_" + accountBindEmailDTO.getUserEmail()); if (StringUtils.isBlank(verifyCode)) { @@ -297,7 +299,8 @@ public class AccountServiceImpl extends ServiceImpl impl throw new BusinessException("verification.code.error", ResultEnum.PROMPT.getCode()); } //绑定 - updatePwdByUserId(accountBindEmailDTO.getUserEmail(), accountBindEmailDTO.getUserId()); + account.setUserEmail(accountBindEmailDTO.getUserEmail()); +// updatePwdByUserId(accountBindEmailDTO.getUserEmail(), accountBindEmailDTO.getUserId()); return Boolean.TRUE; } From ec094d74716f19050a5ac57e817589fcb3144d24 Mon Sep 17 00:00:00 2001 From: shahaibo <1023316923@qq.com> Date: Thu, 19 Dec 2024 13:31:01 +0800 Subject: [PATCH 18/91] TASK:AiDA --- src/main/java/com/ai/da/common/utils/SendEmailUtil.java | 3 ++- src/main/java/com/ai/da/controller/AccountController.java | 5 +++-- src/main/java/com/ai/da/service/AccountService.java | 5 +++-- .../java/com/ai/da/service/impl/AccountServiceImpl.java | 8 ++++---- 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/ai/da/common/utils/SendEmailUtil.java b/src/main/java/com/ai/da/common/utils/SendEmailUtil.java index 9dd76934..048f65af 100644 --- a/src/main/java/com/ai/da/common/utils/SendEmailUtil.java +++ b/src/main/java/com/ai/da/common/utils/SendEmailUtil.java @@ -73,7 +73,8 @@ public class SendEmailUtil { /** * 绑定邮箱模板id */ - public static Long BIND_MAILBOX_TEMPLATE_ID = 45619L; +// public static Long BIND_MAILBOX_TEMPLATE_ID = 45619L; + public static Long BIND_MAILBOX_TEMPLATE_ID = 132754L; public static Long CHANGE_MAILBOX_TEMPLATE_ID = 128210L; diff --git a/src/main/java/com/ai/da/controller/AccountController.java b/src/main/java/com/ai/da/controller/AccountController.java index a16337ce..9d2b0f4d 100644 --- a/src/main/java/com/ai/da/controller/AccountController.java +++ b/src/main/java/com/ai/da/controller/AccountController.java @@ -4,6 +4,7 @@ import com.ai.da.common.config.exception.BusinessException; import com.ai.da.common.response.PageBaseResponse; import com.ai.da.common.response.Response; import com.ai.da.mapper.primary.entity.Account; +import com.ai.da.mapper.primary.entity.AccountExtend; import com.ai.da.mapper.primary.entity.TrialOrder; import com.ai.da.model.dto.*; import com.ai.da.model.vo.AccountLoginVO; @@ -313,13 +314,13 @@ public class AccountController { @GetMapping("/bindGoogle") @ApiOperation(value = "绑定谷歌") - public Response bindGoogle(@RequestParam("credential") String credential) { + public Response bindGoogle(@RequestParam("credential") String credential) { return Response.success(accountService.bindGoogle(credential)); } @GetMapping("/bindWeChat") @ApiOperation(value = "绑定微信") - public Response bindWeChat(@RequestParam("code") String code) { + public Response bindWeChat(@RequestParam("code") String code) { return Response.success(accountService.bindWeChat(code)); } diff --git a/src/main/java/com/ai/da/service/AccountService.java b/src/main/java/com/ai/da/service/AccountService.java index 6ecb4f0a..07944fcd 100644 --- a/src/main/java/com/ai/da/service/AccountService.java +++ b/src/main/java/com/ai/da/service/AccountService.java @@ -2,6 +2,7 @@ package com.ai.da.service; import com.ai.da.common.response.PageBaseResponse; import com.ai.da.mapper.primary.entity.Account; +import com.ai.da.mapper.primary.entity.AccountExtend; import com.ai.da.mapper.primary.entity.GoogleUser; import com.ai.da.mapper.primary.entity.TrialOrder; import com.ai.da.model.dto.*; @@ -210,9 +211,9 @@ public interface AccountService extends IService { AccountLoginVO getAccountDetail(); - Boolean bindGoogle(String credential); + AccountExtend bindGoogle(String credential); - Boolean bindWeChat(String code); + AccountExtend bindWeChat(String code); Boolean unbindWeChat(); diff --git a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java index e92d0149..054ab718 100644 --- a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java @@ -2432,7 +2432,7 @@ public class AccountServiceImpl extends ServiceImpl impl } @Override - public Boolean bindGoogle(String credential) { + public AccountExtend bindGoogle(String credential) { try { // 配置 Google ID Token 验证器 GoogleIdTokenVerifier verifier = new GoogleIdTokenVerifier.Builder( @@ -2466,7 +2466,7 @@ public class AccountServiceImpl extends ServiceImpl impl accountExtendInsert.setAccountId(authPrincipalVo.getId()); accountExtendMapper.insert(accountExtendInsert); - return Boolean.TRUE; + return accountExtendInsert; } else { throw new IllegalArgumentException("Invalid ID token."); } @@ -2478,7 +2478,7 @@ public class AccountServiceImpl extends ServiceImpl impl } @Override - public Boolean bindWeChat(String code) { + public AccountExtend bindWeChat(String code) { // 1. 获取 access_token 和 openid JSONObject accessTokenResponse = getAccessTokenFromWeChat(code); String accessToken = accessTokenResponse.getString("access_token"); @@ -2508,7 +2508,7 @@ public class AccountServiceImpl extends ServiceImpl impl accountExtendInsert.setAccountId(authPrincipalVo.getId()); accountExtendMapper.insert(accountExtendInsert); - return Boolean.TRUE; + return accountExtendInsert; } @Override From b15cc542e1eab33a966093d8175a2836fa456e4f Mon Sep 17 00:00:00 2001 From: xupei Date: Thu, 19 Dec 2024 13:56:17 +0800 Subject: [PATCH 19/91] =?UTF-8?q?=E6=8C=89id=E6=9F=A5=E8=AF=A2=E8=AE=A2?= =?UTF-8?q?=E5=8D=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/ai/da/mapper/primary/PaymentInfoMapper.java | 4 ++-- src/main/java/com/ai/da/model/dto/QueryPageByTimeDTO.java | 3 +++ .../com/ai/da/model/dto/SubscriptionEmailParamsDTO.java | 5 +++-- .../java/com/ai/da/service/impl/PaymentInfoServiceImpl.java | 5 +++-- src/main/java/com/ai/da/service/impl/StripeServiceImpl.java | 6 ++++-- src/main/resources/application-dev.properties | 4 +++- src/main/resources/application-prod.properties | 4 +++- src/main/resources/mapper/primary/PaymentInfoMapper.xml | 6 ++++++ 8 files changed, 27 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/ai/da/mapper/primary/PaymentInfoMapper.java b/src/main/java/com/ai/da/mapper/primary/PaymentInfoMapper.java index ea23d39d..797c5baf 100644 --- a/src/main/java/com/ai/da/mapper/primary/PaymentInfoMapper.java +++ b/src/main/java/com/ai/da/mapper/primary/PaymentInfoMapper.java @@ -8,7 +8,7 @@ import java.util.List; public interface PaymentInfoMapper extends BaseMapper { - List selectPageOrderList(Long accountId, String startTime, String endTime, int offset, int pageSize); + List selectPageOrderList(Long accountId, String startTime, String endTime, int offset, int pageSize, Long id); - int queryOrderListTotalCount(Long accountId, String startTime, String endTime); + int queryOrderListTotalCount(Long accountId, String startTime, String endTime, Long id); } diff --git a/src/main/java/com/ai/da/model/dto/QueryPageByTimeDTO.java b/src/main/java/com/ai/da/model/dto/QueryPageByTimeDTO.java index c0c37a98..669493eb 100644 --- a/src/main/java/com/ai/da/model/dto/QueryPageByTimeDTO.java +++ b/src/main/java/com/ai/da/model/dto/QueryPageByTimeDTO.java @@ -16,4 +16,7 @@ public class QueryPageByTimeDTO extends PageQueryBaseVo { @ApiModelProperty("结束时间 yyyy-mm-dd hh:mm:ss 可以不要时分秒") private String endTime; + + @ApiModelProperty("指定id") + private Long id; } diff --git a/src/main/java/com/ai/da/model/dto/SubscriptionEmailParamsDTO.java b/src/main/java/com/ai/da/model/dto/SubscriptionEmailParamsDTO.java index 1f35b705..1d6f6fd7 100644 --- a/src/main/java/com/ai/da/model/dto/SubscriptionEmailParamsDTO.java +++ b/src/main/java/com/ai/da/model/dto/SubscriptionEmailParamsDTO.java @@ -10,6 +10,9 @@ public class SubscriptionEmailParamsDTO { // t_payment_info id(每次支付对于用户来说是一笔新订单) private String orderId; + // 链接到订单列表的某个订单 + private String orderRef; + // 订单支付创建日期 private String createDate; @@ -48,7 +51,5 @@ public class SubscriptionEmailParamsDTO { // 付款失败原因 private String failMessage; - private String accountPageRef; - } diff --git a/src/main/java/com/ai/da/service/impl/PaymentInfoServiceImpl.java b/src/main/java/com/ai/da/service/impl/PaymentInfoServiceImpl.java index 538886aa..4e4d11b2 100644 --- a/src/main/java/com/ai/da/service/impl/PaymentInfoServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/PaymentInfoServiceImpl.java @@ -355,12 +355,13 @@ public class PaymentInfoServiceImpl extends ServiceImpl orderListVOS = baseMapper.selectPageOrderList(accountId, startTime, endTime, offset, queryPageByTimeDTO.getSize()); + List orderListVOS = baseMapper.selectPageOrderList(accountId, startTime, endTime, offset, + queryPageByTimeDTO.getSize(), queryPageByTimeDTO.getId()); if (CollectionUtils.isEmpty(orderListVOS)) { return PageBaseResponse.success(new Page<>()); }else { - int totalCount = baseMapper.queryOrderListTotalCount(accountId, startTime, endTime); + int totalCount = baseMapper.queryOrderListTotalCount(accountId, startTime, endTime, queryPageByTimeDTO.getId()); IPage orderListVOIPage = new Page<>(); Integer size = queryPageByTimeDTO.getSize(); orderListVOIPage.setSize(size); diff --git a/src/main/java/com/ai/da/service/impl/StripeServiceImpl.java b/src/main/java/com/ai/da/service/impl/StripeServiceImpl.java index f16bbb85..d3b2df08 100644 --- a/src/main/java/com/ai/da/service/impl/StripeServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/StripeServiceImpl.java @@ -72,6 +72,9 @@ public class StripeServiceImpl implements StripeService { @Value("${stripe.webhook-sign-secret}") private String signSecret; + @Value("${orderList.link}") + private String orderListLink; + @Override @Transactional(rollbackFor = Exception.class) public String pay(ProductPurchaseDTO productPurchaseDTO) { @@ -834,6 +837,7 @@ public class StripeServiceImpl implements StripeService { emailParamsDTO.setUsername(userName); emailParamsDTO.setOrderId(paymentInfo.getId().toString()); + emailParamsDTO.setOrderRef("\"" + orderListLink + paymentInfo.getId().toString() + "\""); emailParamsDTO.setCreateDate(String.valueOf(paymentInfo.getCreateTime()).replace("T", " ")); emailParamsDTO.setQuantity(String.valueOf(1)); emailParamsDTO.setTotalFee(paymentInfo.getPayerTotal().toString()); @@ -936,8 +940,6 @@ public class StripeServiceImpl implements StripeService { emailParamsDTO.setQuantity(String.valueOf(1)); emailParamsDTO.setTotalFee(paymentInfo.getPayerTotal().toString()); setSubscriptionParams(paymentInfo, subscriptionInfo, orderByOrderNo, emailParamsDTO); - // todo - emailParamsDTO.setAccountPageRef("\"https://www.aida.com.hk/home/homePage\""); // 4、发邮件 SendEmailUtil.subscriptionEmailReminder("fail_renewal", emailParamsDTO, language, account.getUserEmail()); diff --git a/src/main/resources/application-dev.properties b/src/main/resources/application-dev.properties index 2afd01c3..19854ce9 100644 --- a/src/main/resources/application-dev.properties +++ b/src/main/resources/application-dev.properties @@ -104,4 +104,6 @@ rabbitmq.queues.srResult=SuperResolution-dev rabbitmq.queues.generateResult=GenerateImage-dev rabbitmq.queues.toProductImageResult=ToProductImage-dev rabbitmq.queues.relightResult=Relight-dev -rabbitmq.exchange.generate=generate-exchange \ No newline at end of file +rabbitmq.exchange.generate=generate-exchange + +orderList.link=https://develop.aida.com.hk/home/homePage?order= \ No newline at end of file diff --git a/src/main/resources/application-prod.properties b/src/main/resources/application-prod.properties index 5e9bffe9..e17972c6 100644 --- a/src/main/resources/application-prod.properties +++ b/src/main/resources/application-prod.properties @@ -105,4 +105,6 @@ rabbitmq.queues.srResult=SuperResolution-prod rabbitmq.queues.generateResult=GenerateImage-prod rabbitmq.queues.toProductImageResult=ToProductImage-prod rabbitmq.queues.relightResult=Relight-prod -rabbitmq.exchange.generate=generate-exchange \ No newline at end of file +rabbitmq.exchange.generate=generate-exchange + +orderList.link=https://aida.com.hk/home/homePage?order= \ No newline at end of file diff --git a/src/main/resources/mapper/primary/PaymentInfoMapper.xml b/src/main/resources/mapper/primary/PaymentInfoMapper.xml index 8bab6ca5..f6e823e8 100644 --- a/src/main/resources/mapper/primary/PaymentInfoMapper.xml +++ b/src/main/resources/mapper/primary/PaymentInfoMapper.xml @@ -18,6 +18,9 @@ p.order_no = o.order_no WHERE o.account_id = #{accountId} + + AND p.id = #{id} + AND p.create_time BETWEEN #{startTime} AND #{endTime} ORDER BY p.id DESC @@ -35,6 +38,9 @@ p.order_no = o.order_no WHERE o.account_id = #{accountId} + + AND p.id = #{id} + AND p.create_time BETWEEN #{startTime} AND #{endTime}; From 5b653272eea28faddd3c03f085f0c86ec58c548c Mon Sep 17 00:00:00 2001 From: xupei Date: Thu, 19 Dec 2024 17:15:55 +0800 Subject: [PATCH 20/91] =?UTF-8?q?=E8=A6=86=E7=9B=96=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E6=81=A2=E5=A4=8D-=E8=8E=B7=E5=8F=96=E4=B8=AA=E4=BA=BA?= =?UTF-8?q?=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/ai/da/service/impl/AccountServiceImpl.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java index 054ab718..b1fae881 100644 --- a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java @@ -2428,6 +2428,19 @@ public class AccountServiceImpl extends ServiceImpl impl response.setAccountExtendList(accountExtends); } response.setLanguage(Language.valueOf(account.getLanguage()).name()); + SubscriptionInfo subscriptionInfo = stripeService.getLatestSubscriptionInfoByAccountId(accountId); + if (!Objects.isNull(subscriptionInfo)) { + response.setSubscriptionId(subscriptionInfo.getSubscriptionId()); + response.setSubscriptionType(subscriptionInfo.getType()); + response.setStatus(subscriptionInfo.getStatus()); + response.setExpireTime(String.valueOf(subscriptionInfo.getCurrentPeriodEnd())); + response.setAutoRenewal(subscriptionInfo.getStatus().equals("active")); + } + + Affiliate affiliate = affiliateService.getByAccountId(accountId); + if (!Objects.isNull(affiliate) && affiliate.getStatus().equals("Active")) { + response.setAffiliate(true); + } return response; } From 0574180e4b40b97855cf8aa140e040dbb7ccd97e Mon Sep 17 00:00:00 2001 From: xupei Date: Thu, 19 Dec 2024 17:26:16 +0800 Subject: [PATCH 21/91] =?UTF-8?q?generate=E5=8E=BB=E9=99=A4=E9=A2=9D?= =?UTF-8?q?=E5=A4=96prompt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/ai/da/service/impl/GenerateServiceImpl.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/ai/da/service/impl/GenerateServiceImpl.java b/src/main/java/com/ai/da/service/impl/GenerateServiceImpl.java index ec647e44..92adba26 100644 --- a/src/main/java/com/ai/da/service/impl/GenerateServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/GenerateServiceImpl.java @@ -328,7 +328,8 @@ public class GenerateServiceImpl extends ServiceImpl i // generate.setText(text); break; case "Printboard": - if (prefix.contains("Painting Style")) { + text = translated; + /*if (prefix.contains("Painting Style")) { text = "Picasso,increased color saturation,increased glossiness," + translated + ", fabric print, high quality"; } else if (prefix.contains("Illustration Style")) { text = "Flat coating,romantic,soft,pencil strokes,accentuating and widening the depth of pencil strokes,paper patterns,block colors,crayons,reducing image contrast,and hand drawn painting marks," + translated + ", fabric print, high quality"; @@ -336,7 +337,7 @@ public class GenerateServiceImpl extends ServiceImpl i text = "Hyper realism,3d,deepened projection,increased permutation value,increased concavity and convexity value," + translated + ", fabric print, high quality"; } else { text = translated; - } + }*/ // text = userInput + ", fabric print, high quality"; // generate.setText(text); break; From 7fb74bc7d85501f49f7e0b8938e3e611112ef84d Mon Sep 17 00:00:00 2001 From: shahaibo <1023316923@qq.com> Date: Thu, 19 Dec 2024 17:52:14 +0800 Subject: [PATCH 22/91] TASK:AiDA --- src/main/java/com/ai/da/service/impl/AccountServiceImpl.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java index b1fae881..0fc61c15 100644 --- a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java @@ -300,6 +300,7 @@ public class AccountServiceImpl extends ServiceImpl impl } //绑定 account.setUserEmail(accountBindEmailDTO.getUserEmail()); + accountMapper.updateById(account); // updatePwdByUserId(accountBindEmailDTO.getUserEmail(), accountBindEmailDTO.getUserId()); return Boolean.TRUE; } From 15cde37af7544f71f140ee64f5a618a92b1721ed Mon Sep 17 00:00:00 2001 From: shahaibo <1023316923@qq.com> Date: Fri, 20 Dec 2024 11:44:21 +0800 Subject: [PATCH 23/91] TASK:AiDA --- .../da/service/impl/AccountServiceImpl.java | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java index 0fc61c15..d91ce874 100644 --- a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java @@ -384,7 +384,7 @@ public class AccountServiceImpl extends ServiceImpl impl if (Objects.isNull(authenticationOperationTypeEnum)) { throw new BusinessException("unknown.authentication.operation.type"); } - Account emailAccount = getOneByEmail(emailSendDTO.getEmail()); +// Account emailAccount = getOneByEmail(emailSendDTO.getEmail()); String randomVerifyCode = RandomsUtil.generateVerifyCode(100000L, 999999L); LocalCacheUtils.setVerifyCodeCache( emailSendDTO.getOperationType() + "_" + emailSendDTO.getEmail(), randomVerifyCode); @@ -403,6 +403,12 @@ public class AccountServiceImpl extends ServiceImpl impl SendEmailUtil.EXCEPTION_ID_TEMPLATE_ID, randomVerifyCode); break; case BIND_MAILBOX: + QueryWrapper qw = new QueryWrapper<>(); + qw.lambda().eq(Account::getUserEmail, emailSendDTO.getEmail()); + List accounts = accountMapper.selectList(qw); + if (CollectionUtil.isNotEmpty(accounts)) { + throw new BusinessException("This email has been bound"); + } result = SendEmailUtil.send(emailSendDTO.getEmail(), null, SendEmailUtil.BIND_MAILBOX_TEMPLATE_ID, randomVerifyCode); break; @@ -2468,6 +2474,14 @@ public class AccountServiceImpl extends ServiceImpl impl String name = (String) payload.get("name"); String pictureUrl = (String) payload.get("picture"); + QueryWrapper qw = new QueryWrapper<>(); + qw.lambda().eq(AccountExtend::getAuth, userId); + qw.lambda().eq(AccountExtend::getAuthType, "Google"); + List accountExtends = accountExtendMapper.selectList(qw); + + if (CollectionUtil.isNotEmpty(accountExtends)) { + throw new BusinessException("The Google has been bound."); + } AccountExtend accountExtendInsert = new AccountExtend(); accountExtendInsert.setAuth(userId); @@ -2512,6 +2526,15 @@ public class AccountServiceImpl extends ServiceImpl impl if (unionId == null) { throw new IllegalArgumentException("无法获取 unionid,请检查微信开发平台配置"); } + QueryWrapper qw = new QueryWrapper<>(); + qw.lambda().eq(AccountExtend::getAuth, unionId); + qw.lambda().eq(AccountExtend::getAuthType, "WeChat"); + List accountExtends = accountExtendMapper.selectList(qw); + + if (CollectionUtil.isNotEmpty(accountExtends)) { + throw new BusinessException("The WeChat has been bound."); + } + AccountExtend accountExtendInsert = new AccountExtend(); accountExtendInsert.setAuth(unionId); accountExtendInsert.setAuthType("WeChat"); From e033671ffbb3850b60d890c80bb41da36e04c15b Mon Sep 17 00:00:00 2001 From: shahaibo <1023316923@qq.com> Date: Fri, 20 Dec 2024 16:11:52 +0800 Subject: [PATCH 24/91] TASK:AiDA --- src/main/java/com/ai/da/model/vo/AccountLoginVO.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/com/ai/da/model/vo/AccountLoginVO.java b/src/main/java/com/ai/da/model/vo/AccountLoginVO.java index 5496c82f..7fe88a93 100644 --- a/src/main/java/com/ai/da/model/vo/AccountLoginVO.java +++ b/src/main/java/com/ai/da/model/vo/AccountLoginVO.java @@ -44,6 +44,10 @@ public class AccountLoginVO { private List accountExtendList; + private Long validStartTime; + + private Long validEndTime; + private String Language; // 订阅id(stripe提供) From 69743d4ef063c11db2caa2b35d26c7dd25f7e20b Mon Sep 17 00:00:00 2001 From: shahaibo <1023316923@qq.com> Date: Mon, 23 Dec 2024 10:27:01 +0800 Subject: [PATCH 25/91] =?UTF-8?q?BUGFIX:=E8=B0=B7=E6=AD=8C=E5=BF=AB?= =?UTF-8?q?=E6=8D=B7=E7=99=BB=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../da/service/impl/AccountServiceImpl.java | 32 ++++++++++++------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java index d91ce874..c30813a7 100644 --- a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java @@ -2217,20 +2217,28 @@ public class AccountServiceImpl extends ServiceImpl impl accountExtendInsert.setHeadImgUrl(pictureUrl); accountExtendInsert.setName(name); + QueryWrapper accountQueryWrapper = new QueryWrapper<>(); + accountQueryWrapper.lambda().eq(Account::getUserEmail, email); // 根据邮箱查询用户 + List accounts = accountMapper.selectList(accountQueryWrapper); + // 用户不存在,创建新用户(自动注册) Account newUser = new Account(); - newUser.setUserEmail(email); - newUser.setUserName(name); - newUser.setUserPassword("Third-000000"); - newUser.setLanguage(Language.ENGLISH.name()); - newUser.setValidStartTime(System.currentTimeMillis()); - newUser.setValidEndTime(toDayEnd(Instant.now().plus(5, ChronoUnit.DAYS).toEpochMilli())); - newUser.setCreateDate(new Date()); - newUser.setIsTrial(1); - newUser.setIsBeginner(1); - newUser.setCredits(BigDecimal.valueOf(100)); - newUser.setSystemUser(3); - accountMapper.insert(newUser); + if (CollectionUtil.isNotEmpty(accounts)) { + newUser = CopyUtil.copyObject(accounts.get(0), Account.class); + }else { + newUser.setUserEmail(email); + newUser.setUserName(name); + newUser.setUserPassword("Third-000000"); + newUser.setLanguage(Language.ENGLISH.name()); + newUser.setValidStartTime(System.currentTimeMillis()); + newUser.setValidEndTime(toDayEnd(Instant.now().plus(5, ChronoUnit.DAYS).toEpochMilli())); + newUser.setCreateDate(new Date()); + newUser.setIsTrial(1); + newUser.setIsBeginner(1); + newUser.setCredits(BigDecimal.valueOf(100)); + newUser.setSystemUser(3); + accountMapper.insert(newUser); + } accountExtendInsert.setAccountId(newUser.getId()); accountExtendMapper.insert(accountExtendInsert); From 7283ace072ce99211486784bf630bb755d9d2127 Mon Sep 17 00:00:00 2001 From: xupei Date: Mon, 23 Dec 2024 14:31:48 +0800 Subject: [PATCH 26/91] =?UTF-8?q?getAffiliateList=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E8=BF=94=E5=9B=9E=E7=94=A8=E6=88=B7=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ai/da/controller/AffiliateController.java | 5 +- .../ai/da/mapper/primary/AffiliateMapper.java | 8 +++ .../java/com/ai/da/model/vo/AffiliateVO.java | 2 + .../com/ai/da/service/AffiliateService.java | 3 +- .../da/service/impl/AffiliateServiceImpl.java | 41 +++++++++++-- .../mapper/primary/AffiliateMapper.xml | 59 +++++++++++++++++++ 6 files changed, 110 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/ai/da/controller/AffiliateController.java b/src/main/java/com/ai/da/controller/AffiliateController.java index 1be751ac..c0c03a3d 100644 --- a/src/main/java/com/ai/da/controller/AffiliateController.java +++ b/src/main/java/com/ai/da/controller/AffiliateController.java @@ -1,8 +1,8 @@ package com.ai.da.controller; +import com.ai.da.common.response.PageBaseResponse; import com.ai.da.common.response.Response; -import com.ai.da.mapper.primary.entity.Affiliate; import com.ai.da.model.dto.AffiliateQueryDTO; import com.ai.da.model.vo.AffiliateInvitationDetailsVO; import com.ai.da.model.vo.AffiliateVO; @@ -15,7 +15,6 @@ import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import javax.validation.Valid; -import java.util.List; @Slf4j @RestController @@ -34,7 +33,7 @@ public class AffiliateController { @ApiOperation(value = "获取affiliate列表") @PostMapping("/list") - public Response> getAffiliateList(@Valid @RequestBody AffiliateQueryDTO affiliateQueryDTO) { + public Response> getAffiliateList(@Valid @RequestBody AffiliateQueryDTO affiliateQueryDTO) { return Response.success(affiliateService.getAffiliateList(affiliateQueryDTO)); } diff --git a/src/main/java/com/ai/da/mapper/primary/AffiliateMapper.java b/src/main/java/com/ai/da/mapper/primary/AffiliateMapper.java index 3974b904..1a53ca9f 100644 --- a/src/main/java/com/ai/da/mapper/primary/AffiliateMapper.java +++ b/src/main/java/com/ai/da/mapper/primary/AffiliateMapper.java @@ -1,11 +1,19 @@ package com.ai.da.mapper.primary; import com.ai.da.mapper.primary.entity.Affiliate; +import com.ai.da.model.vo.AffiliateVO; import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import java.util.List; import java.util.Map; public interface AffiliateMapper extends BaseMapper { Map getMonthlyApprovedAffiliate(int year, int month); + + List getAffiliateList(String status, String startTime, String endTime, + String order, Long affiliateId, int size, int offset); + + int queryAffiliateTotalCount(String status, String startTime, String endTime, Long affiliateId); + } diff --git a/src/main/java/com/ai/da/model/vo/AffiliateVO.java b/src/main/java/com/ai/da/model/vo/AffiliateVO.java index 96177e1a..eedf5481 100644 --- a/src/main/java/com/ai/da/model/vo/AffiliateVO.java +++ b/src/main/java/com/ai/da/model/vo/AffiliateVO.java @@ -12,4 +12,6 @@ public class AffiliateVO extends Affiliate { private Long linkViewCount; + private String username; + } diff --git a/src/main/java/com/ai/da/service/AffiliateService.java b/src/main/java/com/ai/da/service/AffiliateService.java index 9ceb1cb1..fa03936f 100644 --- a/src/main/java/com/ai/da/service/AffiliateService.java +++ b/src/main/java/com/ai/da/service/AffiliateService.java @@ -1,5 +1,6 @@ package com.ai.da.service; +import com.ai.da.common.response.PageBaseResponse; import com.ai.da.mapper.primary.entity.Affiliate; import com.ai.da.model.dto.AffiliateQueryDTO; import com.ai.da.model.vo.AffiliateInvitationDetailsVO; @@ -11,7 +12,7 @@ public interface AffiliateService extends IService { Boolean registerAsAnAffiliate(String promotionMethod); - IPage getAffiliateList(AffiliateQueryDTO affiliateQueryDTO); + PageBaseResponse getAffiliateList(AffiliateQueryDTO affiliateQueryDTO); AffiliateVO personalAffiliateCenter(); diff --git a/src/main/java/com/ai/da/service/impl/AffiliateServiceImpl.java b/src/main/java/com/ai/da/service/impl/AffiliateServiceImpl.java index 220aefe6..97b464a7 100644 --- a/src/main/java/com/ai/da/service/impl/AffiliateServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/AffiliateServiceImpl.java @@ -3,11 +3,11 @@ package com.ai.da.service.impl; import com.ai.da.common.config.exception.BusinessException; import com.ai.da.common.constant.CommonConstant; import com.ai.da.common.context.UserContext; +import com.ai.da.common.response.PageBaseResponse; import com.ai.da.common.response.ResultEnum; import com.ai.da.common.utils.CopyUtil; import com.ai.da.common.utils.RedisUtil; import com.ai.da.common.utils.SendEmailUtil; -import com.ai.da.mapper.primary.AccountMapper; import com.ai.da.mapper.primary.AffiliateIncomeMapper; import com.ai.da.mapper.primary.AffiliateMapper; import com.ai.da.mapper.primary.SubscriptionInfoMapper; @@ -29,6 +29,7 @@ import com.mysql.cj.util.StringUtils; import io.netty.util.internal.StringUtil; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; import javax.annotation.Resource; import java.math.BigDecimal; @@ -84,15 +85,47 @@ public class AffiliateServiceImpl extends ServiceImpl getAffiliateList(AffiliateQueryDTO affiliateQueryDTO){ + public PageBaseResponse getAffiliateList(AffiliateQueryDTO affiliateQueryDTO){ log.info("parameter => {}", affiliateQueryDTO.toString()); - QueryWrapper qw = new QueryWrapper<>(); + + int offset = (affiliateQueryDTO.getPage() - 1) * affiliateQueryDTO.getSize(); + List affiliateList = baseMapper.getAffiliateList(affiliateQueryDTO.getStatus(), + affiliateQueryDTO.getStartTime(), + affiliateQueryDTO.getEndTime(), + affiliateQueryDTO.getOrder(), + affiliateQueryDTO.getAffiliateId(), + affiliateQueryDTO.getSize(), + offset + ); + if (CollectionUtils.isEmpty(affiliateList)) { + return PageBaseResponse.success(new Page<>()); + }else { + int totalCount = baseMapper.queryAffiliateTotalCount(affiliateQueryDTO.getStatus(), + affiliateQueryDTO.getStartTime(), + affiliateQueryDTO.getEndTime(), + affiliateQueryDTO.getAffiliateId() + ); + IPage orderListVOIPage = new Page<>(); + Integer size = affiliateQueryDTO.getSize(); + orderListVOIPage.setSize(size); + orderListVOIPage.setRecords(affiliateList); + orderListVOIPage.setCurrent(affiliateQueryDTO.getPage()); + orderListVOIPage.setPages((long)Math.ceil((double) totalCount / size)); + orderListVOIPage.setTotal(totalCount); + return PageBaseResponse.success(orderListVOIPage); + } + /*QueryWrapper qw = new QueryWrapper<>(); qw.eq(!StringUtils.isNullOrEmpty(affiliateQueryDTO.getStatus()), "status", affiliateQueryDTO.getStatus()) .gt(!StringUtils.isNullOrEmpty(affiliateQueryDTO.getStartTime()), "create_time", affiliateQueryDTO.getStartTime()) .lt(!StringUtils.isNullOrEmpty(affiliateQueryDTO.getEndTime()), "create_time", affiliateQueryDTO.getEndTime()) .eq(!Objects.isNull(affiliateQueryDTO.getAffiliateId()), "id", affiliateQueryDTO.getAffiliateId()) .orderByDesc(affiliateQueryDTO.getOrder().equals("DESC"), "create_time"); - return baseMapper.selectPage(new Page<>(affiliateQueryDTO.getPage(), affiliateQueryDTO.getSize()), qw); + Page affiliatePage = baseMapper.selectPage(new Page<>(affiliateQueryDTO.getPage(), affiliateQueryDTO.getSize()), qw); + affiliatePage.convert((Function) affiliate-> { + AffiliateVO affiliateVO = CopyUtil.copyObject(affiliate, AffiliateVO.class); + affiliateVO.setUsername(); + }); + return affiliatePage;*/ } public AffiliateVO personalAffiliateCenter(){ diff --git a/src/main/resources/mapper/primary/AffiliateMapper.xml b/src/main/resources/mapper/primary/AffiliateMapper.xml index 8dbe92da..e2637ec0 100644 --- a/src/main/resources/mapper/primary/AffiliateMapper.xml +++ b/src/main/resources/mapper/primary/AffiliateMapper.xml @@ -13,4 +13,63 @@ AND status = 'Active' + + + From fa94667c0f500ccbcc9371f7d409cd4f930bf97a Mon Sep 17 00:00:00 2001 From: xupei Date: Mon, 23 Dec 2024 16:07:05 +0800 Subject: [PATCH 27/91] =?UTF-8?q?=E6=B8=B8=E5=AE=A2=E5=88=B0=E6=9C=9F?= =?UTF-8?q?=E6=97=B6=E9=97=B4=E4=B8=8D=E7=BD=AE=E7=A9=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/ai/da/service/impl/AccountServiceImpl.java | 4 +++- src/main/resources/mapper/primary/AccountMapper.xml | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java index 5840852e..204cd2d5 100644 --- a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java @@ -1488,12 +1488,14 @@ public class AccountServiceImpl extends ServiceImpl impl // 将新增用户添加到AiDA,身份为游客 if (!newUsersInfo.isEmpty()){ newUsersInfo.forEach(userInfo -> { + long epochMilli = Instant.now().toEpochMilli(); Account account = new Account(); account.setUserEmail(userInfo.get("email")); account.setUserName(userInfo.get("username")); account.setUserPassword("Third-000000"); account.setLanguage(Language.ENGLISH.name()); - account.setValidStartTime(Instant.now().toEpochMilli()); + account.setValidStartTime(epochMilli); + account.setValidEndTime(epochMilli); account.setCreateDate(new Date()); account.setIsTrial(0); account.setIsBeginner(1); diff --git a/src/main/resources/mapper/primary/AccountMapper.xml b/src/main/resources/mapper/primary/AccountMapper.xml index 643624d5..b9c76324 100644 --- a/src/main/resources/mapper/primary/AccountMapper.xml +++ b/src/main/resources/mapper/primary/AccountMapper.xml @@ -25,7 +25,7 @@ update t_account - set valid_end_time = null, is_trial = 0, credits = 0, system_user = 0, update_date = #{date} + set is_trial = 0, credits = 0, system_user = 0, update_date = #{date} where id = #{id} From 468ad385d7b9985843accde64c64bc7cb0a87811 Mon Sep 17 00:00:00 2001 From: xupei Date: Mon, 23 Dec 2024 17:29:48 +0800 Subject: [PATCH 28/91] =?UTF-8?q?=E7=94=A8=E6=88=B7=E7=99=BB=E5=BD=95?= =?UTF-8?q?=E6=97=B6=EF=BC=8C=E4=B8=8D=E6=A0=A1=E9=AA=8C=E6=B8=B8=E5=AE=A2?= =?UTF-8?q?=E8=B4=A6=E5=8F=B7=E6=9C=89=E6=95=88=E6=9C=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/ai/da/service/impl/AccountServiceImpl.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java index 204cd2d5..95645efd 100644 --- a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java @@ -236,6 +236,9 @@ public class AccountServiceImpl extends ServiceImpl impl private void validateUserValidaExpire(Account account) { Long currentTime = new Date().getTime(); + if (account.getSystemUser().equals(0)){ + return; + } if (Objects.nonNull(account.getValidStartTime())) { if (currentTime < account.getValidStartTime()) { throw new BusinessException("user.expired"); @@ -243,7 +246,9 @@ public class AccountServiceImpl extends ServiceImpl impl } if (Objects.nonNull(account.getValidEndTime())) { if (currentTime > account.getValidEndTime()) { - throw new BusinessException("user.expired"); + toVisitor(account); + return; +// throw new BusinessException("user.expired"); } } } From bfa1d67b5c0bddd831ef96e5f862ab8ab98565c9 Mon Sep 17 00:00:00 2001 From: shahaibo <1023316923@qq.com> Date: Tue, 24 Dec 2024 14:00:44 +0800 Subject: [PATCH 29/91] BUGFIX:Collection not found --- src/main/java/com/ai/da/service/impl/DesignServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/ai/da/service/impl/DesignServiceImpl.java b/src/main/java/com/ai/da/service/impl/DesignServiceImpl.java index 05275007..46ff2d8c 100644 --- a/src/main/java/com/ai/da/service/impl/DesignServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/DesignServiceImpl.java @@ -985,7 +985,7 @@ public class DesignServiceImpl extends ServiceImpl impleme Design oldDesign = selectByCollectionId(reDesignDTO.getCollectionId()); //删除老的关联的design deleteByCollectionId(reDesignDTO.getCollectionId()); - designItemService.deleteByCollectionId(reDesignDTO.getCollectionId()); +// designItemService.deleteByCollectionId(reDesignDTO.getCollectionId()); designItemDetailService.deleteByDesignId(oldDesign.getId()); //redesign return designOrRedesignOperateNew(CopyUtil.copyObject( From b01ee9129b02545bf122110564b19399e3a33cab Mon Sep 17 00:00:00 2001 From: xupei Date: Fri, 27 Dec 2024 10:31:27 +0800 Subject: [PATCH 30/91] =?UTF-8?q?develop=20=E7=8E=AF=E5=A2=83webhook=5Fsec?= =?UTF-8?q?ret=E5=8F=98=E6=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/payment.properties | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/resources/payment.properties b/src/main/resources/payment.properties index 43c4e4b7..b4fad5ad 100644 --- a/src/main/resources/payment.properties +++ b/src/main/resources/payment.properties @@ -28,7 +28,8 @@ paypal.webhook_id=1D107312EX592781K # developer stripe.private-key=sk_test_51P4ZZL02n1TEydyN8qQHjOA9imsFU7Oxs2HMHGy2urHnnQgSHnZuu5vVP6pKhEACwUpsKNyrbZpdcg5TJWJLRHcY008dEO1fn2 -stripe.webhook-sign-secret=whsec_e0dBiJngx6qqgJj6yPyJ2A9ouh1Cjv5w +#stripe.webhook-sign-secret=whsec_e0dBiJngx6qqgJj6yPyJ2A9ouh1Cjv5w +stripe.webhook-sign-secret=whsec_TJcMSnAkh4uktrNY1M6Iy8XaVze4Rzqm # kim - test #stripe.private-key=sk_test_51LwPrxH7nPZ8bkrNj67TFD7sxucaTANs1lf0KGSu1QSJfxYXcnigq2wTaZyZzST7y0fMbhhvaJZ4LjjFhr95M83a00eXrmOTL0 From f45bd7acc404bf700b7331c95c89bd4fcdd4439d Mon Sep 17 00:00:00 2001 From: xupei Date: Fri, 27 Dec 2024 10:46:52 +0800 Subject: [PATCH 31/91] =?UTF-8?q?develop=20=E7=8E=AF=E5=A2=83webhook=5Fsec?= =?UTF-8?q?ret=E5=8F=98=E6=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/payment.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/resources/payment.properties b/src/main/resources/payment.properties index b4fad5ad..2415fd97 100644 --- a/src/main/resources/payment.properties +++ b/src/main/resources/payment.properties @@ -28,8 +28,8 @@ paypal.webhook_id=1D107312EX592781K # developer stripe.private-key=sk_test_51P4ZZL02n1TEydyN8qQHjOA9imsFU7Oxs2HMHGy2urHnnQgSHnZuu5vVP6pKhEACwUpsKNyrbZpdcg5TJWJLRHcY008dEO1fn2 -#stripe.webhook-sign-secret=whsec_e0dBiJngx6qqgJj6yPyJ2A9ouh1Cjv5w -stripe.webhook-sign-secret=whsec_TJcMSnAkh4uktrNY1M6Iy8XaVze4Rzqm +stripe.webhook-sign-secret=whsec_e0dBiJngx6qqgJj6yPyJ2A9ouh1Cjv5w +#stripe.webhook-sign-secret=whsec_TJcMSnAkh4uktrNY1M6Iy8XaVze4Rzqm # kim - test #stripe.private-key=sk_test_51LwPrxH7nPZ8bkrNj67TFD7sxucaTANs1lf0KGSu1QSJfxYXcnigq2wTaZyZzST7y0fMbhhvaJZ4LjjFhr95M83a00eXrmOTL0 From ca4d75c63fc1a02c2bb49d62a6aa2385b9d04f5e Mon Sep 17 00:00:00 2001 From: xupei Date: Fri, 27 Dec 2024 14:29:07 +0800 Subject: [PATCH 32/91] =?UTF-8?q?BUGFIX:=E7=94=A8=E6=88=B7=E8=AE=A2?= =?UTF-8?q?=E9=98=85=E5=90=8E=E6=9B=B4=E6=96=B0=E7=94=A8=E6=88=B7=E8=BA=AB?= =?UTF-8?q?=E4=BB=BD=E5=92=8C=E7=A7=AF=E5=88=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/ai/da/service/AccountService.java | 4 +++ .../da/service/impl/AccountServiceImpl.java | 28 +++++++++++++++++++ .../ai/da/service/impl/StripeServiceImpl.java | 20 ++++++------- 3 files changed, 42 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/ai/da/service/AccountService.java b/src/main/java/com/ai/da/service/AccountService.java index 07944fcd..bff69738 100644 --- a/src/main/java/com/ai/da/service/AccountService.java +++ b/src/main/java/com/ai/da/service/AccountService.java @@ -218,4 +218,8 @@ public interface AccountService extends IService { Boolean unbindWeChat(); Boolean unbindGoogle(); + + void updateAccountValidity(Long accountId, Long currentPeriodEnd); + + void updateUserRoleAndCredits(Long accountId, String type); } diff --git a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java index 96d66d72..83b82a8e 100644 --- a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java @@ -2591,4 +2591,32 @@ public class AccountServiceImpl extends ServiceImpl impl accountMapper.updateById(account); return Boolean.TRUE; } + + public void updateAccountValidity(Long accountId, Long currentPeriodEnd){ + // 不管当前用户的账号是否到期,都根据付款信息重置账号到期时间 + Account account = accountMapper.selectById(accountId); + account.setValidEndTime(currentPeriodEnd * 1000); + + accountMapper.updateById(account); + } + + public void updateUserRoleAndCredits(Long accountId, String type){ + Account account = accountMapper.selectById(accountId); + switch (type) { + case "month": + account.setSystemUser(2); + account.setCredits(BigDecimal.valueOf(Long.parseLong(CreditsEventsEnum.INIT_MONTHLY.getValue()))); + break; + case "year": + account.setSystemUser(1); + account.setCredits(BigDecimal.valueOf(Long.parseLong(CreditsEventsEnum.INIT_YEARLY.getValue()))); + break; + case "day": + account.setSystemUser(3); + account.setCredits(BigDecimal.valueOf(Long.parseLong(CreditsEventsEnum.INIT_WEEKLY.getValue()))); + break; + } + + accountMapper.updateById(account); + } } diff --git a/src/main/java/com/ai/da/service/impl/StripeServiceImpl.java b/src/main/java/com/ai/da/service/impl/StripeServiceImpl.java index d3b2df08..0fc00b32 100644 --- a/src/main/java/com/ai/da/service/impl/StripeServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/StripeServiceImpl.java @@ -58,6 +58,8 @@ public class StripeServiceImpl implements StripeService { private CreditsService creditsService; @Resource private RefundInfoService refundInfoService; + @Resource + private AccountService accountService; @Resource private AccountMapper accountMapper; @@ -368,6 +370,7 @@ public class StripeServiceImpl implements StripeService { orderInfoService.updateById(orderInfo); } } + log.info("回调事件 {} 处理完成", event.getType()); return response; } @@ -466,7 +469,10 @@ public class StripeServiceImpl implements StripeService { subscriptionInfoMapper.insert(subscriptionInfo); // 更新账号到期时间 - updateAccountValidity(subscriptionInfo.getAccountId(), subscriptionInfo.getCurrentPeriodEnd()); + accountService.updateAccountValidity(subscriptionInfo.getAccountId(), subscriptionInfo.getCurrentPeriodEnd()); + + // 更新账号身份和积分 + accountService.updateUserRoleAndCredits(subscriptionInfo.getAccountId(), interval); } return subscriptionInfo; } @@ -519,7 +525,9 @@ public class StripeServiceImpl implements StripeService { subscriptionInfo.setCurrentPeriodEnd(subscription.getCurrentPeriodEnd()); subscriptionInfo.setNextPayDate(DateUtil.changeTimeStampFormat(subscription.getCurrentPeriodEnd(), "seconds", CommonConstant.TIME_FORMAT_MMM_dd_yyyy_EEEE)); // 更新账号到期时间 - updateAccountValidity(subscriptionInfo.getAccountId(), subscriptionInfo.getCurrentPeriodEnd()); + accountService.updateAccountValidity(subscriptionInfo.getAccountId(), subscriptionInfo.getCurrentPeriodEnd()); + // 更新账号身份和积分 + accountService.updateUserRoleAndCredits(subscriptionInfo.getAccountId(), subscriptionInfo.getType()); log.info("更新 {} 账号到期时间为:{}", subscriptionInfo.getAccountId(), DateUtil.changeTimeStampFormat(subscriptionInfo.getCurrentPeriodEnd(), "seconds", CommonConstant.TIME_FORMAT_MMM_dd_yyyy_EEEE)); flag = true; } @@ -530,14 +538,6 @@ public class StripeServiceImpl implements StripeService { return subscriptionInfo; } - private void updateAccountValidity(Long accountId, Long currentPeriodEnd){ - // 不管当前用户的账号是否到期,都根据付款信息重置账号到期时间 - com.ai.da.mapper.primary.entity.Account account = accountMapper.selectById(accountId); - account.setValidEndTime(currentPeriodEnd * 1000); - - accountMapper.updateById(account); - } - // 取消连续订阅 将订阅从pause状态转为cancel状态(使用定时器,定期检索DB中,过期且不续订的订阅) public void cancelSubscription(String subscriptionId, String cancelReason) { Stripe.apiKey = privateKey; From 1157b41730f229cac5c79a25bb3430f050754fc5 Mon Sep 17 00:00:00 2001 From: xupei Date: Tue, 31 Dec 2024 11:38:12 +0800 Subject: [PATCH 33/91] =?UTF-8?q?=E7=A7=AF=E5=88=86=E8=B4=AD=E4=B9=B0=20?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E9=82=AE=E4=BB=B6=E9=80=9A=E7=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/ai/da/common/utils/SendEmailUtil.java | 40 +++++++++++++++++++ .../da/service/impl/AlipayHKServiceImpl.java | 7 ++++ 2 files changed, 47 insertions(+) diff --git a/src/main/java/com/ai/da/common/utils/SendEmailUtil.java b/src/main/java/com/ai/da/common/utils/SendEmailUtil.java index 048f65af..712cffc8 100644 --- a/src/main/java/com/ai/da/common/utils/SendEmailUtil.java +++ b/src/main/java/com/ai/da/common/utils/SendEmailUtil.java @@ -985,4 +985,44 @@ public class SendEmailUtil { } } + private final static Long CREDITS_PURCHASE_MERCHANT = 133275L; + + public static void creditsPurchaseReminder(String username, String quantity, String amount) { + try { + Credential cred = new Credential(SECRET_ID, SECRET_KEy); + // 实例化一个http选项,可选的,没有特殊需求可以跳过 + HttpProfile httpProfile = new HttpProfile(); + httpProfile.setEndpoint("ses.tencentcloudapi.com"); + // 实例化一个client选项,可选的,没有特殊需求可以跳过 + ClientProfile clientProfile = new ClientProfile(); + clientProfile.setHttpProfile(httpProfile); + // 实例化要请求产品的client对象,clientProfile是可选的 + SesClient client = new SesClient(cred, "ap-hongkong", clientProfile); + // 实例化一个请求对象,每个接口都会对应一个request对象 + SendEmailRequest req = new SendEmailRequest(); + req.setFromEmailAddress(SEND_ADDRESS); + String merchantEmail = "kimwong@code-create.com.hk"; + String developerEmail = "xupei@code-create.com.hk"; + req.setDestination(new String[]{merchantEmail, developerEmail}); + Template template = new Template(); + req.setSubject("New Credit Purchase Order"); + template.setTemplateID(CREDITS_PURCHASE_MERCHANT); + JSONObject jsonObject = new JSONObject(); + // 设置试用订单相关数据 + jsonObject.put("userName", username); + jsonObject.put("quantity", quantity); + jsonObject.put("totalFee", amount); + + template.setTemplateData(JSON.toJSONString(jsonObject)); + req.setTemplate(template); + + // 返回的resp是一个SendEmailResponse的实例,与请求对象对应 + SendEmailResponse resp = client.SendEmail(req); + log.info("短信发送结果res###{}", SendEmailResponse.toJsonString(resp)); + } catch (TencentCloudSDKException e) { + log.info("邮件发送失败###{}", e.toString()); + throw new BusinessException("failed.to.send.mail"); + } + } + } diff --git a/src/main/java/com/ai/da/service/impl/AlipayHKServiceImpl.java b/src/main/java/com/ai/da/service/impl/AlipayHKServiceImpl.java index 417a03bd..910129ef 100644 --- a/src/main/java/com/ai/da/service/impl/AlipayHKServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/AlipayHKServiceImpl.java @@ -6,6 +6,8 @@ import com.ai.da.common.enums.OrderStatusEnum; import com.ai.da.common.enums.PayTypeEnum; import com.ai.da.common.utils.AlipayHKEncryptionUtil; import com.ai.da.common.utils.AlipayHKRequestUtil; +import com.ai.da.common.utils.SendEmailUtil; +import com.ai.da.mapper.primary.AccountMapper; import com.ai.da.mapper.primary.entity.OrderInfo; import com.ai.da.model.dto.AlipayHKCallbackDTO; import com.ai.da.model.dto.AlipayHKRequestDTO; @@ -54,6 +56,8 @@ public class AlipayHKServiceImpl implements AlipayHKService { private AlipayHKEncryptionUtil alipayHKEncryptionUtil; @Resource private AlipayHKRequestUtil alipayHKRequestUtil; + @Resource + private AccountMapper accountMapper; /** @@ -251,6 +255,9 @@ public class AlipayHKServiceImpl implements AlipayHKService { "positive", orderByOrderNo.getOrderNo()); log.info("用户:{} 积分信息更新成功",orderByOrderNo.getAccountId()); + // 邮件通知Kim + String username = accountMapper.selectById(orderByOrderNo.getAccountId()).getUserName(); + SendEmailUtil.creditsPurchaseReminder(username, String.valueOf(quantity), totalAmount); } finally { //要主动释放锁 lock.unlock(); From ee1e2f8556b80764ab3f969da89f5346c749a221 Mon Sep 17 00:00:00 2001 From: xupei Date: Thu, 2 Jan 2025 17:32:49 +0800 Subject: [PATCH 34/91] =?UTF-8?q?=E8=8E=B7=E5=8F=96=E6=89=80=E6=9C=89?= =?UTF-8?q?=E6=A0=87=E7=AD=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/ai/da/controller/AccountController.java | 4 ++-- src/main/java/com/ai/da/controller/TagsController.java | 2 +- src/main/java/com/ai/da/mapper/primary/entity/Tags.java | 3 +++ src/main/java/com/ai/da/service/AccountService.java | 4 ++-- .../java/com/ai/da/service/impl/AccountServiceImpl.java | 5 ++--- src/main/java/com/ai/da/service/impl/TagsServiceImpl.java | 6 +++++- src/main/resources/application-dev.properties | 2 +- 7 files changed, 16 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/ai/da/controller/AccountController.java b/src/main/java/com/ai/da/controller/AccountController.java index 9d2b0f4d..1afac49d 100644 --- a/src/main/java/com/ai/da/controller/AccountController.java +++ b/src/main/java/com/ai/da/controller/AccountController.java @@ -235,7 +235,7 @@ public class AccountController { return Response.success("success"); } - @ApiOperation(value = "verifyUserEmail") + /*@ApiOperation(value = "verifyUserEmail") @GetMapping("/verifyUserEmail") public Response verifyUserEmail(@RequestParam("verifyCode") String verifyCode){ accountService.verifyUserEmail(verifyCode); @@ -254,7 +254,7 @@ public class AccountController { public Response activateNewEmail(@RequestParam("token") String token){ accountService.activateNewEmail(token); return Response.success("success"); - } + }*/ @PostMapping("halfPricePromotion") @ApiOperation(value = "十月半价活动") diff --git a/src/main/java/com/ai/da/controller/TagsController.java b/src/main/java/com/ai/da/controller/TagsController.java index 8a2b3209..a248cfcd 100644 --- a/src/main/java/com/ai/da/controller/TagsController.java +++ b/src/main/java/com/ai/da/controller/TagsController.java @@ -25,7 +25,7 @@ public class TagsController { @ApiOperation("获取标签") @GetMapping("/getTags") - public Response> getTags(@RequestParam("userInput") String userInput) { + public Response> getTags(@RequestParam(value = "userInput", required = false) String userInput) { return Response.success(tagsService.getTags(userInput)); } } diff --git a/src/main/java/com/ai/da/mapper/primary/entity/Tags.java b/src/main/java/com/ai/da/mapper/primary/entity/Tags.java index fc7dfd90..7ffe7a62 100644 --- a/src/main/java/com/ai/da/mapper/primary/entity/Tags.java +++ b/src/main/java/com/ai/da/mapper/primary/entity/Tags.java @@ -10,4 +10,7 @@ import lombok.EqualsAndHashCode; public class Tags extends BaseEntity{ private String tagName; + + // 表示标签是否正在活动中 0->不在活动中 1->在活动中 + private byte active = (byte)0; } diff --git a/src/main/java/com/ai/da/service/AccountService.java b/src/main/java/com/ai/da/service/AccountService.java index bff69738..e37d4b09 100644 --- a/src/main/java/com/ai/da/service/AccountService.java +++ b/src/main/java/com/ai/da/service/AccountService.java @@ -177,11 +177,11 @@ public interface AccountService extends IService { void editUserName(String newUserName); - void verifyUserEmail(String verifyCode); + /*void verifyUserEmail(String verifyCode); void changeUserEmail(String newMailbox); - void activateNewEmail(String token); + void activateNewEmail(String token);*/ String updateNoLoginRequiredNew(NoLoginRequiredDTO noLoginRequiredDTO, HttpServletRequest request); diff --git a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java index 83b82a8e..964be51d 100644 --- a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java @@ -1863,7 +1863,7 @@ public class AccountServiceImpl extends ServiceImpl impl } } - // 验证是否是本人进行邮箱绑定更改 + /*// 验证是否是本人进行邮箱绑定更改 public void verifyUserEmail(String verifyCode){ // 向旧邮箱发送验证码,以保证是当前邮箱拥有者在进行更改 String userEmail = baseMapper.selectById(UserContext.getUserHolder().getId()).getUserEmail(); @@ -1896,7 +1896,6 @@ public class AccountServiceImpl extends ServiceImpl impl // 验证激活链接 public void activateNewEmail(String token){ // 获取链接地址信息,更新指定用户邮箱 - String emailAndId = jwtTokenHelper.parseToEmailAndId(token); String newMailbox = emailAndId.substring(0, emailAndId.lastIndexOf("_")); String accountId = emailAndId.substring(emailAndId.lastIndexOf("_") + 1); @@ -1918,7 +1917,7 @@ public class AccountServiceImpl extends ServiceImpl impl account.setId(Long.parseLong(accountId)); baseMapper.updateById(account); log.info("邮箱绑定更改完成,用户id:{},新邮箱:{}", accountId, newMailbox); - } + }*/ @Override public String googleCallback(String code, HttpSession session) { diff --git a/src/main/java/com/ai/da/service/impl/TagsServiceImpl.java b/src/main/java/com/ai/da/service/impl/TagsServiceImpl.java index c0a1182c..f3321499 100644 --- a/src/main/java/com/ai/da/service/impl/TagsServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/TagsServiceImpl.java @@ -5,6 +5,7 @@ import com.ai.da.mapper.primary.entity.Tags; import com.ai.da.service.TagsService; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import io.netty.util.internal.StringUtil; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -19,7 +20,10 @@ public class TagsServiceImpl extends ServiceImpl implements Ta public List getTags(String tagPrefix){ // 1、根据tag前缀,查询 QueryWrapper queryWrapper = new QueryWrapper<>(); - queryWrapper.likeRight("tag_name", tagPrefix); + if (!StringUtil.isNullOrEmpty(tagPrefix)) { + queryWrapper.like("tag_name", tagPrefix); + } + queryWrapper.orderByDesc("id").last("limit 10"); // 需返回标签内容和id return baseMapper.selectList(queryWrapper); diff --git a/src/main/resources/application-dev.properties b/src/main/resources/application-dev.properties index 19854ce9..5daaa774 100644 --- a/src/main/resources/application-dev.properties +++ b/src/main/resources/application-dev.properties @@ -20,7 +20,7 @@ spring.security.jwtExpiration=8640000000 spring.security.ignorePaths=/,/favicon.ico,/doc.html,/webjars/**,/swagger-resources,/v2/api-docs,\ /api/account/**,/api/element/**,/api/python/**,/api/design/**,/api/history/**,/api/library/**,/api/third/party/**,/api/generate/**,/api/workspace/**,/api/classification/**,\ /api/product/**,/api/ali-pay/**,/api/order-info/**,/api/paypal/**,/api/credits/**,/api/inquiry/**,/api/tasks/**,/api/python/prepareForSR,/api/alipay-hk/**,/api/portfolio/**,\ - /api/stripe/**,/api/message/**,/notification/**,/api/affiliate/** + /api/stripe/**,/api/message/**,/api/tags/**,/notification/**,/api/affiliate/** spring.security.authApi=/auth/login From 5ea8e851d780daf72e7d1eefe2937ef5b026993f Mon Sep 17 00:00:00 2001 From: shahaibo <1023316923@qq.com> Date: Mon, 6 Jan 2025 10:46:51 +0800 Subject: [PATCH 35/91] TASK:AiDA design like sort --- pom.xml | 8 ++- .../ai/da/controller/DesignController.java | 6 ++ .../da/mapper/primary/UserLikeSortMapper.java | 7 ++ .../mapper/primary/entity/UserLikeSort.java | 24 +++++++ .../com/ai/da/model/dto/UserLikeSortDTO.java | 13 ++++ .../java/com/ai/da/model/vo/DesignLikeVO.java | 2 + .../java/com/ai/da/model/vo/UserLikeVO.java | 2 + .../java/com/ai/da/python/PythonService.java | 31 +++++++-- .../java/com/ai/da/service/DesignService.java | 2 + .../ai/da/service/impl/DesignServiceImpl.java | 66 +++++++++++++++++-- .../impl/UserLikeGroupServiceImpl.java | 9 +++ 11 files changed, 159 insertions(+), 11 deletions(-) create mode 100644 src/main/java/com/ai/da/mapper/primary/UserLikeSortMapper.java create mode 100644 src/main/java/com/ai/da/mapper/primary/entity/UserLikeSort.java create mode 100644 src/main/java/com/ai/da/model/dto/UserLikeSortDTO.java diff --git a/pom.xml b/pom.xml index ff9df865..db7bdb0b 100644 --- a/pom.xml +++ b/pom.xml @@ -151,9 +151,15 @@ 3.0.3 + + + + + + com.tencentcloudapi - tencentcloud-sdk-java-ses + tencentcloud-sdk-java 3.1.572 diff --git a/src/main/java/com/ai/da/controller/DesignController.java b/src/main/java/com/ai/da/controller/DesignController.java index 934bcecb..6046ed32 100644 --- a/src/main/java/com/ai/da/controller/DesignController.java +++ b/src/main/java/com/ai/da/controller/DesignController.java @@ -71,6 +71,12 @@ public class DesignController { return Response.success(designService.dislike(disDesignLikeDTO)); } + @ApiOperation(value = "Design sort") + @PostMapping("/sort") + public Response sort(@Valid @RequestBody UserLikeSortDTO userLikeSortDTO) { + return Response.success(designService.sort(userLikeSortDTO)); + } + @ApiOperation(value = "sketchBoard upload generate design前裁剪") @PostMapping("/sketchBoardsBoundingBox") public Response> sketchesBoundingBox(@Valid @RequestBody ReDesignCollectionDTO reDesignCollectionDTO) { diff --git a/src/main/java/com/ai/da/mapper/primary/UserLikeSortMapper.java b/src/main/java/com/ai/da/mapper/primary/UserLikeSortMapper.java new file mode 100644 index 00000000..c6966249 --- /dev/null +++ b/src/main/java/com/ai/da/mapper/primary/UserLikeSortMapper.java @@ -0,0 +1,7 @@ +package com.ai.da.mapper.primary; + +import com.ai.da.common.config.mybatis.plus.CommonMapper; +import com.ai.da.mapper.primary.entity.UserLikeSort; + +public interface UserLikeSortMapper extends CommonMapper { +} diff --git a/src/main/java/com/ai/da/mapper/primary/entity/UserLikeSort.java b/src/main/java/com/ai/da/mapper/primary/entity/UserLikeSort.java new file mode 100644 index 00000000..3e733d3c --- /dev/null +++ b/src/main/java/com/ai/da/mapper/primary/entity/UserLikeSort.java @@ -0,0 +1,24 @@ +package com.ai.da.mapper.primary.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +import java.io.Serializable; +import java.util.Date; +@Data +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("user_like_sort") +public class UserLikeSort implements Serializable { + private static final long serialVersionUID = 1L; + + @TableId(value = "id", type = IdType.AUTO) + private Long id; + private Long userLikeGroupId; + private Long userLikeId; + private Integer sort; +} \ No newline at end of file diff --git a/src/main/java/com/ai/da/model/dto/UserLikeSortDTO.java b/src/main/java/com/ai/da/model/dto/UserLikeSortDTO.java new file mode 100644 index 00000000..9cf6dd8c --- /dev/null +++ b/src/main/java/com/ai/da/model/dto/UserLikeSortDTO.java @@ -0,0 +1,13 @@ +package com.ai.da.model.dto; + +import com.ai.da.mapper.primary.entity.UserLikeSort; +import lombok.Data; + +import java.util.List; + +@Data +public class UserLikeSortDTO{ + private Long userLikeGroupId; + + List userLikeSortList; +} diff --git a/src/main/java/com/ai/da/model/vo/DesignLikeVO.java b/src/main/java/com/ai/da/model/vo/DesignLikeVO.java index 2a38f8bd..a54bc2ec 100644 --- a/src/main/java/com/ai/da/model/vo/DesignLikeVO.java +++ b/src/main/java/com/ai/da/model/vo/DesignLikeVO.java @@ -19,6 +19,8 @@ public class DesignLikeVO { private String pictureName; + private Long userLikeId; + public DesignLikeVO() { } } diff --git a/src/main/java/com/ai/da/model/vo/UserLikeVO.java b/src/main/java/com/ai/da/model/vo/UserLikeVO.java index 589e8fc6..a1344f80 100644 --- a/src/main/java/com/ai/da/model/vo/UserLikeVO.java +++ b/src/main/java/com/ai/da/model/vo/UserLikeVO.java @@ -23,4 +23,6 @@ public class UserLikeVO { @ApiModelProperty("图片路径") private String designOutfitUrl; private String pictureName; + + private Integer sort; } diff --git a/src/main/java/com/ai/da/python/PythonService.java b/src/main/java/com/ai/da/python/PythonService.java index f7f47631..9cfb9fa4 100644 --- a/src/main/java/com/ai/da/python/PythonService.java +++ b/src/main/java/com/ai/da/python/PythonService.java @@ -268,7 +268,8 @@ public class PythonService { DesignPythonObject pythonObject = createDesignPythonObject(elementVO, designPictureType, systemScale, singleOverall, switchCategory, i); // 如果当前对象与已组装的对象重复,则跳过当前组装 - if (assembledObjects.contains(pythonObject)) { + DesignPythonObject designPythonObjectCopy = getCopy(pythonObject); + if (assembledObjects.contains(designPythonObjectCopy)) { if (lastAssembledObject != null && assembledObjects.contains(lastAssembledObject)) { // 如果当前组装与前一个组装的对象重复,且前一个组装也重复,结束组装 System.out.println("当前组装的对象与前两个组装的对象重复,结束组装。"); @@ -279,8 +280,8 @@ public class PythonService { } // 将当前对象添加到已组装的集合中,并记录 - assembledObjects.add(pythonObject); - lastAssembledObject = pythonObject; // 更新上一次组装的对象 + assembledObjects.add(designPythonObjectCopy); + lastAssembledObject = designPythonObjectCopy; // 更新上一次组装的对象 objects.add(pythonObject); redisUtil.addProcessId(processId, i + 1); @@ -288,6 +289,26 @@ public class PythonService { return designPythonObjects; } + private DesignPythonObject getCopy(DesignPythonObject pythonObject) { + DesignPythonObject designPythonObjectCopy = CopyUtil.copyObject(pythonObject, DesignPythonObject.class); + designPythonObjectCopy.setObjectSign(null); + DesignPythonBasic basic = designPythonObjectCopy.getBasic(); + basic.setSave_name(null); + designPythonObjectCopy.setBasic(basic); + List items = designPythonObjectCopy.getItems(); + List itemsCopy = new ArrayList<>(); + for (DesignPythonItem item : items) { + item.setElementId(null); + item.setIcon(null); + item.setBusinessId(null); + item.setImage_id(null); + item.setImageId(null); + itemsCopy.add(item); + } + designPythonObjectCopy.setItems(itemsCopy); + return designPythonObjectCopy; + } + private void updateSketchNumbers(CurrentDesignPictureTypeEnum designPictureType, int[] sketchNumbers) { switch (designPictureType) { case PIN: @@ -320,7 +341,9 @@ public class PythonService { DesignPythonObject pythonObject = new DesignPythonObject(); pythonObject.setItems(coverToDesignPythonItemNew(elementVO, designPictureType, systemScale)); pythonObject.setBasic(coverToBasic(pythonObject.getItems().get(0), singleOverall, switchCategory, elementVO.getDesignLibraryModelPoint())); - pythonObject.setObjectSign(elementVO.getRequestIdList().get(i)); + if (CollectionUtil.isNotEmpty(elementVO.getRequestIdList())) { + pythonObject.setObjectSign(elementVO.getRequestIdList().get(i)); + } return pythonObject; } diff --git a/src/main/java/com/ai/da/service/DesignService.java b/src/main/java/com/ai/da/service/DesignService.java index 80d13f47..9dc7591d 100644 --- a/src/main/java/com/ai/da/service/DesignService.java +++ b/src/main/java/com/ai/da/service/DesignService.java @@ -110,4 +110,6 @@ public interface DesignService extends IService { String designCloud(DesignCollectionDTO designDTO); void processDesignBatch(Map designBatchResult); + + Boolean sort(UserLikeSortDTO userLikeSortDTO); } diff --git a/src/main/java/com/ai/da/service/impl/DesignServiceImpl.java b/src/main/java/com/ai/da/service/impl/DesignServiceImpl.java index 46ff2d8c..c24ce8a6 100644 --- a/src/main/java/com/ai/da/service/impl/DesignServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/DesignServiceImpl.java @@ -8,10 +8,7 @@ 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.*; -import com.ai.da.mapper.primary.DesignBatchMapper; -import com.ai.da.mapper.primary.DesignMapper; -import com.ai.da.mapper.primary.GenerateDetailMapper; -import com.ai.da.mapper.primary.TDesignPythonOutfitMapper; +import com.ai.da.mapper.primary.*; import com.ai.da.mapper.primary.entity.*; import com.ai.da.mapper.primary.entity.Collection; import com.ai.da.model.dto.*; @@ -114,6 +111,9 @@ public class DesignServiceImpl extends ServiceImpl impleme @Resource private DesignBatchMapper designBatchMapper; + @Resource + private UserLikeSortMapper userLikeSortMapper; + private final ConcurrentHashMap> designContext = new ConcurrentHashMap<>(); @@ -1040,7 +1040,9 @@ public class DesignServiceImpl extends ServiceImpl impleme } String pictureName = null; UserLike userLike; + Boolean isFirst = true; if (Objects.nonNull(userGroupId)) { + isFirst = false; UserLikeGroup userLikeGroup = userLikeGroupService.getById(userGroupId); if (Objects.isNull(userLikeGroup)) { throw new BusinessException("userLikeGroup.not.found"); @@ -1086,6 +1088,24 @@ public class DesignServiceImpl extends ServiceImpl impleme designItem.getDesignId(), designLikeDTO.getDesignItemId(), designLikeDTO.getDesignPythonOutfitId(), tDesignPythonOutfits.get(0).getDesignUrl(), designLikeDTO.getTimeZone()); } userLikeService.save(userLike); + if (isFirst) { + UserLikeSort userLikeSort = new UserLikeSort(); + userLikeSort.setUserLikeGroupId(userGroupId); + userLikeSort.setUserLikeId(userLike.getId()); + userLikeSort.setSort(1); + userLikeSortMapper.insert(userLikeSort); + }else { + QueryWrapper qw = new QueryWrapper<>(); + qw.lambda().eq(UserLikeSort::getUserLikeGroupId, userGroupId); + qw.lambda().orderByDesc(UserLikeSort::getSort); + List userLikeSorts = userLikeSortMapper.selectList(qw); + Integer sort = userLikeSorts.get(0).getSort(); + UserLikeSort userLikeSort = new UserLikeSort(); + userLikeSort.setUserLikeGroupId(userGroupId); + userLikeSort.setUserLikeId(userLike.getId()); + userLikeSort.setSort(sort + 1); + userLikeSortMapper.insert(userLikeSort); + } groupDetailId = userLike.getId(); String designUrl = designPythonOutfitMapper.selectById(userLike.getDesignOutfitId()).getDesignUrl(); if (designUrl.contains("/")) { @@ -1094,7 +1114,7 @@ public class DesignServiceImpl extends ServiceImpl impleme } //修改designItem为like状态 designItemService.updateLikeStatus(designLikeDTO.getDesignItemId(), (byte) 1); - return new DesignLikeVO(userGroupId, groupDetailId, pictureName); + return new DesignLikeVO(userGroupId, groupDetailId, pictureName, userLike.getId()); } private List validateMergeElement(List oldElements, List designItemDetails) { @@ -1176,9 +1196,32 @@ public class DesignServiceImpl extends ServiceImpl impleme //group 下面没有元素时候 直接删除 // userLikeGroupService.removeById(userLike.getUserLikeGroupId()); } + + QueryWrapper qw = new QueryWrapper<>(); + qw.lambda().eq(UserLikeSort::getUserLikeGroupId, userLike.getUserLikeGroupId()); + qw.lambda().orderByDesc(UserLikeSort::getSort); + List userLikeSorts = userLikeSortMapper.selectList(qw); + UserLikeSort userLikeSort = getUserLikeSortByUserLikeId(userLike.getId()); + Long userLikeSortId = userLikeSort.getId(); + for (UserLikeSort likeSort : userLikeSorts) { + if (Objects.equals(likeSort.getId(), userLikeSortId)) { + userLikeSortMapper.deleteById(likeSort); + break; + }else { + likeSort.setSort(likeSort.getSort() - 1); + userLikeSortMapper.updateById(likeSort); + } + } return Boolean.TRUE; } + private UserLikeSort getUserLikeSortByUserLikeId(Long userLikeId) { + QueryWrapper qw = new QueryWrapper<>(); + qw.lambda().eq(UserLikeSort::getUserLikeId, userLikeId); + UserLikeSort userLikeSort = userLikeSortMapper.selectOne(qw); + return userLikeSort; + } + @Override public String generateHighDesign(GenerateHighDesignDTO generateHighDesignDTO) { DesignItem designItem = designItemService.getById(generateHighDesignDTO.getDesignItemId()); @@ -1874,4 +1917,15 @@ public class DesignServiceImpl extends ServiceImpl impleme } -} + @Override + public Boolean sort(UserLikeSortDTO userLikeSortDTO) { +// QueryWrapper qw = new QueryWrapper<>(); +// qw.lambda().eq(UserLikeSort::getUserLikeGroupId, userLikeSortDTO.getUserLikeGroupId()); +// userLikeSortMapper.delete(qw); + for (UserLikeSort userLikeSort : userLikeSortDTO.getUserLikeSortList()) { + userLikeSortMapper.updateById(userLikeSort); + } + return Boolean.TRUE; + } + +} \ No newline at end of file diff --git a/src/main/java/com/ai/da/service/impl/UserLikeGroupServiceImpl.java b/src/main/java/com/ai/da/service/impl/UserLikeGroupServiceImpl.java index 0aff560f..4e8a730f 100644 --- a/src/main/java/com/ai/da/service/impl/UserLikeGroupServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/UserLikeGroupServiceImpl.java @@ -86,6 +86,8 @@ public class UserLikeGroupServiceImpl extends ServiceImpl userLikeSortQueryWrapper = new QueryWrapper<>(); + userLikeSortQueryWrapper.lambda().eq(UserLikeSort::getUserLikeId, o.getId()); + List userLikeSorts = userLikeSortMapper.selectList(userLikeSortQueryWrapper); + if (CollectionUtil.isNotEmpty(userLikeSorts)) { + o.setSort(userLikeSorts.get(0).getSort()); + } }); UserLikeCollectionVO userLikeCollection = collectionService.chooseCollection(group.getCollectionId()); Integer beenPublished = 0; From da9b3a04b4241be139e5f2acf1a5eef37aa1d8aa Mon Sep 17 00:00:00 2001 From: shahaibo <1023316923@qq.com> Date: Mon, 6 Jan 2025 11:35:54 +0800 Subject: [PATCH 36/91] TASK:AiDA design like sort --- .../service/impl/UserLikeGroupServiceImpl.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/main/java/com/ai/da/service/impl/UserLikeGroupServiceImpl.java b/src/main/java/com/ai/da/service/impl/UserLikeGroupServiceImpl.java index 4e8a730f..697ea056 100644 --- a/src/main/java/com/ai/da/service/impl/UserLikeGroupServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/UserLikeGroupServiceImpl.java @@ -153,6 +153,22 @@ public class UserLikeGroupServiceImpl extends ServiceImpl userLikeVOS = userLikeService.getGroupDetail(userGroupId); String sex = null; + + QueryWrapper userLikeSortQw = new QueryWrapper<>(); + userLikeSortQw.lambda().eq(UserLikeSort::getUserLikeGroupId, userGroupId); + List userLikeSortList = userLikeSortMapper.selectList(userLikeSortQw); + if (CollectionUtil.isEmpty(userLikeSortList)) { + Integer sort = 1; + for (UserLikeVO userLikeVO : userLikeVOS) { + UserLikeSort userLikeSort = new UserLikeSort(); + userLikeSort.setUserLikeId(userLikeVO.getId()); + userLikeSort.setUserLikeGroupId(userGroupId); + userLikeSort.setSort(sort); + userLikeSortMapper.insert(userLikeSort); + sort ++; + } + } + userLikeVOS.forEach(o -> { TDesignPythonOutfit tDesignPythonOutfit1 = designPythonOutfitMapper.selectById(o.getDesignOutfitId()); o.setUrl(tDesignPythonOutfit1.getDesignUrl()); From c04b102a81d5b7a25bf14da7a7247c2355762109 Mon Sep 17 00:00:00 2001 From: shahaibo <1023316923@qq.com> Date: Mon, 6 Jan 2025 11:49:47 +0800 Subject: [PATCH 37/91] TASK:AiDA design like sort --- src/main/java/com/ai/da/model/vo/DesignLikeVO.java | 2 ++ src/main/java/com/ai/da/service/impl/DesignServiceImpl.java | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/ai/da/model/vo/DesignLikeVO.java b/src/main/java/com/ai/da/model/vo/DesignLikeVO.java index a54bc2ec..afbac27c 100644 --- a/src/main/java/com/ai/da/model/vo/DesignLikeVO.java +++ b/src/main/java/com/ai/da/model/vo/DesignLikeVO.java @@ -21,6 +21,8 @@ public class DesignLikeVO { private Long userLikeId; + private Integer sort; + public DesignLikeVO() { } } diff --git a/src/main/java/com/ai/da/service/impl/DesignServiceImpl.java b/src/main/java/com/ai/da/service/impl/DesignServiceImpl.java index c24ce8a6..6885040c 100644 --- a/src/main/java/com/ai/da/service/impl/DesignServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/DesignServiceImpl.java @@ -1088,6 +1088,7 @@ public class DesignServiceImpl extends ServiceImpl impleme designItem.getDesignId(), designLikeDTO.getDesignItemId(), designLikeDTO.getDesignPythonOutfitId(), tDesignPythonOutfits.get(0).getDesignUrl(), designLikeDTO.getTimeZone()); } userLikeService.save(userLike); + Integer sortParam = 1; if (isFirst) { UserLikeSort userLikeSort = new UserLikeSort(); userLikeSort.setUserLikeGroupId(userGroupId); @@ -1105,6 +1106,7 @@ public class DesignServiceImpl extends ServiceImpl impleme userLikeSort.setUserLikeId(userLike.getId()); userLikeSort.setSort(sort + 1); userLikeSortMapper.insert(userLikeSort); + sortParam = userLikeSort.getSort(); } groupDetailId = userLike.getId(); String designUrl = designPythonOutfitMapper.selectById(userLike.getDesignOutfitId()).getDesignUrl(); @@ -1114,7 +1116,7 @@ public class DesignServiceImpl extends ServiceImpl impleme } //修改designItem为like状态 designItemService.updateLikeStatus(designLikeDTO.getDesignItemId(), (byte) 1); - return new DesignLikeVO(userGroupId, groupDetailId, pictureName, userLike.getId()); + return new DesignLikeVO(userGroupId, groupDetailId, pictureName, userLike.getId(), sortParam); } private List validateMergeElement(List oldElements, List designItemDetails) { From e4a8bf80e91c11666b493b0afa35eee3577f2436 Mon Sep 17 00:00:00 2001 From: xupei Date: Mon, 6 Jan 2025 14:42:08 +0800 Subject: [PATCH 38/91] =?UTF-8?q?1=E3=80=81=E7=94=A8=E6=88=B7=E8=AF=A6?= =?UTF-8?q?=E7=BB=86=E4=BF=A1=E6=81=AF=E6=B7=BB=E5=8A=A0=E5=9B=BD=E5=AE=B6?= =?UTF-8?q?=E3=80=81=E8=81=8C=E4=B8=9A=E3=80=81=E7=94=A8=E6=88=B7=E5=90=8D?= =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=89=A9=E4=BD=99=E6=AC=A1=E6=95=B0=202?= =?UTF-8?q?=E3=80=81=E7=A7=AF=E5=88=86=E4=B8=8D=E5=A4=9F=20=E8=BF=94?= =?UTF-8?q?=E5=9B=9E=E5=BC=82=E5=B8=B8=E6=8F=90=E7=A4=BA=E7=B1=BB=E5=9E=8B?= =?UTF-8?q?=E6=9B=B4=E6=94=B9=203=E3=80=81=E6=B7=BB=E5=8A=A0=E6=A0=B9?= =?UTF-8?q?=E6=8D=AEip=E8=A7=A3=E6=9E=90=E5=9C=B0=E7=90=86=E4=BD=8D?= =?UTF-8?q?=E7=BD=AE=E6=B5=8B=E8=AF=95=E6=8E=A5=E5=8F=A3=204=E3=80=81?= =?UTF-8?q?=E6=9B=B4=E6=96=B0=E7=A7=AF=E5=88=86=E5=88=B7=E6=96=B0=E6=9C=BA?= =?UTF-8?q?=E5=88=B6=EF=BC=88=E6=AF=8F=E6=9C=881=E5=8F=B70=E7=82=B9?= =?UTF-8?q?=E5=88=B7=E6=96=B0=E5=B9=B4=E8=B4=B9=E7=94=A8=E6=88=B7=E7=A7=AF?= =?UTF-8?q?=E5=88=86=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/ai/da/common/task/AccountTask.java | 4 +- .../ai/da/controller/StripeController.java | 6 ++ .../ai/da/mapper/primary/entity/Account.java | 5 + .../com/ai/da/model/vo/AccountLoginVO.java | 9 +- .../java/com/ai/da/service/StripeService.java | 2 + .../da/service/impl/AccountServiceImpl.java | 6 +- .../da/service/impl/GenerateServiceImpl.java | 2 +- .../ai/da/service/impl/StripeServiceImpl.java | 97 +++++++++++++++++++ 8 files changed, 125 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/ai/da/common/task/AccountTask.java b/src/main/java/com/ai/da/common/task/AccountTask.java index cfc65fd4..62d901b0 100644 --- a/src/main/java/com/ai/da/common/task/AccountTask.java +++ b/src/main/java/com/ai/da/common/task/AccountTask.java @@ -18,9 +18,11 @@ public class AccountTask { /** * 每周日晚上刷新 年付用户、月付用户的积分 + * 替换为 + * 每个月月初只刷新年付用户的积分 */ -// @Scheduled(cron = "59 59 23 ? * SUN") // @Scheduled(cron = "59 59 23 * * ?") + @Scheduled(cron = "0 0 0 1 * ?") public void refreshCreditsMonthly() { log.info("每周日晚11:59:59刷新付费用户积分为 6000"); accountService.refreshCreditsWeekly(); diff --git a/src/main/java/com/ai/da/controller/StripeController.java b/src/main/java/com/ai/da/controller/StripeController.java index 82c5e1cc..42ff382c 100644 --- a/src/main/java/com/ai/da/controller/StripeController.java +++ b/src/main/java/com/ai/da/controller/StripeController.java @@ -112,4 +112,10 @@ public class StripeController { return Response.success(stripeService.detachCustomerAllPaymentMethod(name, email)); } + @ApiOperation("临时 获取ip") + @GetMapping("/getIp2") + public Response getIp2(HttpServletRequest request) { + return Response.success(stripeService.getIp2(request)); + } + } diff --git a/src/main/java/com/ai/da/mapper/primary/entity/Account.java b/src/main/java/com/ai/da/mapper/primary/entity/Account.java index dc4a93ae..1dbebd7f 100644 --- a/src/main/java/com/ai/da/mapper/primary/entity/Account.java +++ b/src/main/java/com/ai/da/mapper/primary/entity/Account.java @@ -57,6 +57,11 @@ public class Account implements Serializable { */ private String country; + /** + * 职业 + */ + private String occupation; + /** * 账户有效期开始时间 */ diff --git a/src/main/java/com/ai/da/model/vo/AccountLoginVO.java b/src/main/java/com/ai/da/model/vo/AccountLoginVO.java index 7fe88a93..04c783ac 100644 --- a/src/main/java/com/ai/da/model/vo/AccountLoginVO.java +++ b/src/main/java/com/ai/da/model/vo/AccountLoginVO.java @@ -3,13 +3,12 @@ package com.ai.da.model.vo; import com.ai.da.mapper.primary.entity.AccountExtend; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; -import io.swagger.models.auth.In; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; -import javax.validation.constraints.NotBlank; import java.util.List; +import java.util.Map; @AllArgsConstructor @NoArgsConstructor @@ -68,4 +67,10 @@ public class AccountLoginVO { // 是否是affiliate private boolean isAffiliate = false; + private String country; + + private String occupation; + + private Map usernameModify; + } diff --git a/src/main/java/com/ai/da/service/StripeService.java b/src/main/java/com/ai/da/service/StripeService.java index 978b7c41..4a2e78e1 100644 --- a/src/main/java/com/ai/da/service/StripeService.java +++ b/src/main/java/com/ai/da/service/StripeService.java @@ -47,4 +47,6 @@ public interface StripeService { List> getCustomerPaymentMethod(String name, String email); String detachCustomerAllPaymentMethod(String name, String email); + + String getIp2(HttpServletRequest request); } diff --git a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java index 964be51d..3dd13d77 100644 --- a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java @@ -1622,7 +1622,8 @@ public class AccountServiceImpl extends ServiceImpl impl // 刷新账号有效期截止之前的年付用户的积分 long epochMilli = Instant.now().toEpochMilli(); accountUpdateWrapper.lambda().set(Account::getCredits, CreditsEventsEnum.INIT_WEEKLY.getValue()) - .eq(Account::getSystemUser,1).or().eq(Account::getSystemUser,2) + .eq(Account::getSystemUser,1) +// .or().eq(Account::getSystemUser,2) .gt(Account::getValidEndTime, epochMilli); baseMapper.update(null,accountUpdateWrapper); } @@ -2462,6 +2463,8 @@ public class AccountServiceImpl extends ServiceImpl impl if (!Objects.isNull(affiliate) && affiliate.getStatus().equals("Active")) { response.setAffiliate(true); } + + response.setUsernameModify(getNicknameModifyTimes()); return response; } @@ -2503,7 +2506,6 @@ public class AccountServiceImpl extends ServiceImpl impl accountExtendInsert.setHeadImgUrl(pictureUrl); accountExtendInsert.setName(name); - AuthPrincipalVo authPrincipalVo = UserContext.getUserHolder(); accountExtendInsert.setAccountId(authPrincipalVo.getId()); accountExtendMapper.insert(accountExtendInsert); diff --git a/src/main/java/com/ai/da/service/impl/GenerateServiceImpl.java b/src/main/java/com/ai/da/service/impl/GenerateServiceImpl.java index 92adba26..7df98322 100644 --- a/src/main/java/com/ai/da/service/impl/GenerateServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/GenerateServiceImpl.java @@ -592,7 +592,7 @@ public class GenerateServiceImpl extends ServiceImpl i // 2、判断用户当前积分是否够本次生成消耗 Boolean preDeduction = creditsService.creditsPreDeduction(creditsEventsEnum, 1); if (!preDeduction) { - throw new BusinessException("remaining.credits.insufficient"); + throw new BusinessException("remaining.credits.insufficient", ResultEnum.WARNING.getCode()); } // 3、生成唯一id 使用uuid,由于uuid重复的几率很小,故取消对uuid重复性的校验 diff --git a/src/main/java/com/ai/da/service/impl/StripeServiceImpl.java b/src/main/java/com/ai/da/service/impl/StripeServiceImpl.java index 0fc00b32..a1c15a47 100644 --- a/src/main/java/com/ai/da/service/impl/StripeServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/StripeServiceImpl.java @@ -5,6 +5,7 @@ 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.RequestInfoUtil; import com.ai.da.common.utils.SendEmailUtil; import com.ai.da.mapper.primary.AccountMapper; import com.ai.da.mapper.primary.PaymentInfoMapper; @@ -17,6 +18,7 @@ import com.ai.da.model.dto.ProductPurchaseDTO; import com.ai.da.model.dto.SubscriptionEmailParamsDTO; import com.ai.da.service.*; import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.toolkit.StringUtils; import com.google.gson.Gson; @@ -36,8 +38,12 @@ import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; +import java.io.BufferedReader; +import java.io.InputStreamReader; import java.math.BigDecimal; import java.math.RoundingMode; +import java.net.HttpURLConnection; +import java.net.URL; import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneOffset; @@ -1145,5 +1151,96 @@ public class StripeServiceImpl implements StripeService { } } + public String getIp2(HttpServletRequest request) { + /*String ip = request.getHeader("X-Forwarded-For"); + String ipAddress = ""; + if(StringUtils.isNotEmpty(ip) && !"unKnown".equalsIgnoreCase(ip)){ + //多次反向代理后会有多个ip值,第一个ip才是真实ip + int index = ip.indexOf(","); + if(index != -1){ + ipAddress = ip.substring(0,index); + }else{ + ipAddress = ip; + } + } + ip = request.getHeader("X-Real-IP"); + if(StringUtils.isNotEmpty(ip) && !"unKnown".equalsIgnoreCase(ip)){ + ipAddress = ip; + } + if (!StringUtil.isNullOrEmpty(ipAddress)) { + getIPLocation(ipAddress); + }*/ + String ipAddress = RequestInfoUtil.getIpAddress(request); + if (!StringUtil.isNullOrEmpty(ipAddress)) { + return getIPLocation(ipAddress); + } + return request.getRemoteAddr(); + } + + /* 免费 API 服务可能有请求频率限制,如果你需要处理大量 IP 地址,可能需要考虑使用付费服务或购买 IP 地理位置数据库。此外,始终要遵守 API 提供商的使用条款和隐私政策。*/ + + public String getIPLocation(String ip) { +// String ip = "117.143.125.1"; // 替换为你想查询的 IP 地址 +// String ip = "194.5.48.180"; // 替换为你想查询的 IP 地址 + String apiURL = "http://ip-api.com/json/" + ip; + + try { + URL url = new URL(apiURL); + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setRequestMethod("GET"); + conn.setRequestProperty("Accept", "application/json"); + + if (conn.getResponseCode() != 200) { + throw new RuntimeException("Failed : HTTP error code : " + conn.getResponseCode()); + } + + BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream())); + String output; + StringBuilder outputBuilder = new StringBuilder(); + System.out.println("Output from Server .... \n"); + while ((output = br.readLine()) != null) { + outputBuilder.append(output); + System.out.println(output); + } + conn.disconnect(); + Map map = JSONObject.parseObject(outputBuilder.toString(), Map.class); + log.info("map: {}", map); + return JSON.toJSONString(map); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + public static void main(String[] args) { + String ip = "117.143.125.1"; // 替换为你想查询的 IP 地址 +// String ip = "194.5.48.180"; // 替换为你想查询的 IP 地址 + String apiURL = "http://ip-api.com/json/" + ip; + + try { + URL url = new URL(apiURL); + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setRequestMethod("GET"); + conn.setRequestProperty("Accept", "application/json"); + + if (conn.getResponseCode() != 200) { + throw new RuntimeException("Failed : HTTP error code : " + conn.getResponseCode()); + } + + BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream())); + String output; + System.out.println("Output from Server .... \n"); + StringBuilder outputBuilder = new StringBuilder(); + while ((output = br.readLine()) != null) { + outputBuilder.append(output); + System.out.println(output); + } + conn.disconnect(); + Map map = JSONObject.parseObject(outputBuilder.toString(), Map.class); + log.info("map: {}", map); + } catch (Exception e) { + e.printStackTrace(); + } + } } From b0fa185d3659729df61540f5295b6e78deb78b2f Mon Sep 17 00:00:00 2001 From: xupei Date: Mon, 6 Jan 2025 14:58:46 +0800 Subject: [PATCH 39/91] =?UTF-8?q?=E6=9B=B4=E6=94=B9=E7=A7=AF=E5=88=86?= =?UTF-8?q?=E5=88=B7=E6=96=B0task?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/ai/da/common/enums/CreditsEventsEnum.java | 1 + src/main/java/com/ai/da/common/task/AccountTask.java | 2 +- src/main/java/com/ai/da/service/impl/AccountServiceImpl.java | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/ai/da/common/enums/CreditsEventsEnum.java b/src/main/java/com/ai/da/common/enums/CreditsEventsEnum.java index 532934b0..ed9f73b6 100644 --- a/src/main/java/com/ai/da/common/enums/CreditsEventsEnum.java +++ b/src/main/java/com/ai/da/common/enums/CreditsEventsEnum.java @@ -20,6 +20,7 @@ public enum CreditsEventsEnum { INIT_MONTHLY("init_monthly", "5000"), INIT_TRIAL("init_trial", "100"), INIT_WEEKLY("init_weekly","6000"), + RESET_YEAR_CREDITS("reset_year_credits","6000"), // SUPER_RESOLUTION("Super Resolution","30"), SUPER_RESOLUTION("Super Resolution","10"), diff --git a/src/main/java/com/ai/da/common/task/AccountTask.java b/src/main/java/com/ai/da/common/task/AccountTask.java index 62d901b0..9c66563c 100644 --- a/src/main/java/com/ai/da/common/task/AccountTask.java +++ b/src/main/java/com/ai/da/common/task/AccountTask.java @@ -24,7 +24,7 @@ public class AccountTask { // @Scheduled(cron = "59 59 23 * * ?") @Scheduled(cron = "0 0 0 1 * ?") public void refreshCreditsMonthly() { - log.info("每周日晚11:59:59刷新付费用户积分为 6000"); + log.info("每月1号0点 将年费用户积分重置为 6000"); accountService.refreshCreditsWeekly(); } diff --git a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java index 3dd13d77..fea340e5 100644 --- a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java @@ -1621,7 +1621,7 @@ public class AccountServiceImpl extends ServiceImpl impl UpdateWrapper accountUpdateWrapper = new UpdateWrapper<>(); // 刷新账号有效期截止之前的年付用户的积分 long epochMilli = Instant.now().toEpochMilli(); - accountUpdateWrapper.lambda().set(Account::getCredits, CreditsEventsEnum.INIT_WEEKLY.getValue()) + accountUpdateWrapper.lambda().set(Account::getCredits, CreditsEventsEnum.RESET_YEAR_CREDITS.getValue()) .eq(Account::getSystemUser,1) // .or().eq(Account::getSystemUser,2) .gt(Account::getValidEndTime, epochMilli); From 6a861305d648716c77ac3ddadf0b867d3324e97f Mon Sep 17 00:00:00 2001 From: xupei Date: Tue, 7 Jan 2025 11:07:49 +0800 Subject: [PATCH 40/91] =?UTF-8?q?=E8=A7=A3=E6=9E=90=E6=89=80=E6=9C=89?= =?UTF-8?q?=E5=8F=91=E8=B5=B7=E8=B4=AD=E4=B9=B0=E7=9A=84=E5=AE=A2=E6=88=B7?= =?UTF-8?q?=E7=AB=AFip=E5=9C=B0=E5=9D=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ai/da/common/enums/CreditsEventsEnum.java | 6 +- .../ai/da/common/utils/RequestInfoUtil.java | 65 ++++++++++++++++++- .../ai/da/controller/AliPayController.java | 5 +- .../ai/da/controller/AlipayHKController.java | 5 +- .../controller/PayPalCheckoutController.java | 4 +- .../ai/da/controller/StripeController.java | 13 ++-- .../da/mapper/primary/entity/OrderInfo.java | 6 ++ .../da/mapper/primary/entity/PaymentInfo.java | 6 ++ .../java/com/ai/da/service/AliPayService.java | 3 +- .../com/ai/da/service/AlipayHKService.java | 4 +- .../com/ai/da/service/OrderInfoService.java | 5 +- .../ai/da/service/PayPalCheckoutService.java | 2 +- .../java/com/ai/da/service/StripeService.java | 4 +- .../ai/da/service/impl/AliPayServiceImpl.java | 17 ++--- .../da/service/impl/AlipayHKServiceImpl.java | 5 +- .../da/service/impl/OrderInfoServiceImpl.java | 32 ++++++--- .../impl/PayPalCheckoutServiceImpl.java | 12 ++-- .../service/impl/PaymentInfoServiceImpl.java | 56 ++++++++++++++-- src/main/resources/payment.properties | 20 +++--- 19 files changed, 204 insertions(+), 66 deletions(-) diff --git a/src/main/java/com/ai/da/common/enums/CreditsEventsEnum.java b/src/main/java/com/ai/da/common/enums/CreditsEventsEnum.java index 532934b0..2141aff7 100644 --- a/src/main/java/com/ai/da/common/enums/CreditsEventsEnum.java +++ b/src/main/java/com/ai/da/common/enums/CreditsEventsEnum.java @@ -7,10 +7,12 @@ import lombok.Getter; @Getter public enum CreditsEventsEnum { - PRICE("price","6"), +// PRICE("price","6"), + PRICE("price","1"),// for test // PRICE("price","0.1"), - BUY_CREDITS("Buy Credits","60"), +// BUY_CREDITS("Buy Credits","60"), + BUY_CREDITS("Buy Credits","10"),// for test REFUND("Refund","60"), // BUY_CREDITS("Buy Credits","10"), diff --git a/src/main/java/com/ai/da/common/utils/RequestInfoUtil.java b/src/main/java/com/ai/da/common/utils/RequestInfoUtil.java index 5f87110e..afa6497a 100644 --- a/src/main/java/com/ai/da/common/utils/RequestInfoUtil.java +++ b/src/main/java/com/ai/da/common/utils/RequestInfoUtil.java @@ -1,7 +1,16 @@ package com.ai.da.common.utils; -import javax.servlet.http.HttpServletRequest; +import com.alibaba.fastjson.JSONObject; +import lombok.extern.slf4j.Slf4j; +import javax.servlet.http.HttpServletRequest; +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.Map; + +@Slf4j public class RequestInfoUtil { /** @@ -45,4 +54,58 @@ public class RequestInfoUtil { return ip; } + /** + * 免费 API 服务可能有请求频率限制,如果你需要处理大量 IP 地址,可能需要考虑使用付费服务或购买 IP 地理位置数据库。此外,始终要遵守 API 提供商的使用条款和隐私政策 + * @param ip + * @return + * { + * "query": "24.48.0.1", + * "status": "success", + * "country": "Canada", + * "countryCode": "CA", + * "region": "QC", + * "regionName": "Quebec", + * "city": "Montreal", + * "zip": "H1L", + * "lat": 45.6026, + * "lon": -73.5167, + * "timezone": "America/Toronto", + * "isp": "Le Groupe Videotron Ltee", + * "org": "Videotron Ltee", + * "as": "AS5769 Videotron Ltee" + * } + */ + public static Map getIPLocation(String ip) { +// String ip = "117.143.125.1"; // 替换为你想查询的 IP 地址 +// String ip = "194.5.48.180"; // 替换为你想查询的 IP 地址 + String apiURL = "http://ip-api.com/json/" + ip; + + try { + URL url = new URL(apiURL); + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setRequestMethod("GET"); + conn.setRequestProperty("Accept", "application/json"); + + if (conn.getResponseCode() != 200) { + throw new RuntimeException("Failed : HTTP error code : " + conn.getResponseCode()); + } + + BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream())); + String output; + StringBuilder outputBuilder = new StringBuilder(); + System.out.println("Output from Server .... \n"); + while ((output = br.readLine()) != null) { + outputBuilder.append(output); + System.out.println(output); + } + conn.disconnect(); + Map map = JSONObject.parseObject(outputBuilder.toString(), Map.class); + log.info("map: {}", map); + return map; + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + } diff --git a/src/main/java/com/ai/da/controller/AliPayController.java b/src/main/java/com/ai/da/controller/AliPayController.java index b3a9c65b..90452b37 100644 --- a/src/main/java/com/ai/da/controller/AliPayController.java +++ b/src/main/java/com/ai/da/controller/AliPayController.java @@ -8,6 +8,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; import java.util.Map; @CrossOrigin @@ -22,11 +23,11 @@ public class AliPayController { @ApiOperation("统一收单下单并支付页面接口的调用") @PostMapping("/trade/page/pay/{amount}") - public Response tradePagePay(@PathVariable Integer amount, @RequestParam String returnUrl){ + public Response tradePagePay(@PathVariable Integer amount, @RequestParam String returnUrl, HttpServletRequest request){ log.info("统一收单下单并支付页面接口的调用"); //支付宝开放平台接受 request 请求对象后 // 会为开发者生成一个html 形式的 form表单,包含自动提交的脚本 - String formStr = aliPayService.tradeCreate(amount, returnUrl); + String formStr = aliPayService.tradeCreate(amount, returnUrl, request); //我们将form表单字符串返回给前端程序,之后前端将会调用自动提交脚本,进行表单的提交 //此时,表单会自动提交到action属性所指向的支付宝开放平台中,从而为用户展示一个支付页面 return Response.success(formStr); diff --git a/src/main/java/com/ai/da/controller/AlipayHKController.java b/src/main/java/com/ai/da/controller/AlipayHKController.java index 006c00b9..734a9d62 100644 --- a/src/main/java/com/ai/da/controller/AlipayHKController.java +++ b/src/main/java/com/ai/da/controller/AlipayHKController.java @@ -8,6 +8,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; @CrossOrigin @RestController @@ -21,8 +22,8 @@ public class AlipayHKController { @ApiOperation(value = "创建订单") @PostMapping(value = "/createOrder/{wallet}/{amount}") - public Response createOrder(@PathVariable Integer amount, @PathVariable String wallet) { - String order = alipayHKService.createOrder(amount, wallet); + public Response createOrder(@PathVariable Integer amount, @PathVariable String wallet, HttpServletRequest request) { + String order = alipayHKService.createOrder(amount, wallet, request); return Response.success(order); } diff --git a/src/main/java/com/ai/da/controller/PayPalCheckoutController.java b/src/main/java/com/ai/da/controller/PayPalCheckoutController.java index 203da0e7..87648940 100644 --- a/src/main/java/com/ai/da/controller/PayPalCheckoutController.java +++ b/src/main/java/com/ai/da/controller/PayPalCheckoutController.java @@ -27,8 +27,8 @@ public class PayPalCheckoutController { @ApiOperation(value = "创建订单") @PostMapping(value = "/trade/{amount}") - public Response> createOrder(@PathVariable Integer amount, @RequestParam String returnUrl) throws SerializeException { - HashMap approvalUrl = payPalCheckoutService.createOrder(amount,returnUrl); + public Response> createOrder(@PathVariable Integer amount, @RequestParam String returnUrl, HttpServletRequest request) throws SerializeException { + HashMap approvalUrl = payPalCheckoutService.createOrder(amount, returnUrl, request); return Response.success(approvalUrl); } diff --git a/src/main/java/com/ai/da/controller/StripeController.java b/src/main/java/com/ai/da/controller/StripeController.java index 42ff382c..2cbbbf1f 100644 --- a/src/main/java/com/ai/da/controller/StripeController.java +++ b/src/main/java/com/ai/da/controller/StripeController.java @@ -33,8 +33,8 @@ public class StripeController { @ApiOperation("创建支付链接") @PostMapping("/createOrder") - public Response pay(@Valid @RequestBody ProductPurchaseDTO productPurchaseDTO) { - return Response.success(stripeService.pay(productPurchaseDTO)); + public Response pay(@Valid @RequestBody ProductPurchaseDTO productPurchaseDTO, HttpServletRequest request) { + return Response.success(stripeService.pay(productPurchaseDTO, request)); } @ApiOperation("支付通知") @@ -75,7 +75,7 @@ public class StripeController { stripeService.cancelSubscription(subscriptionId, reason); return Response.success("success"); } - @ApiOperation("临时 取消订阅") + /*@ApiOperation("临时 取消订阅") @GetMapping("/cancelSubscriptionTemp") public Response cancelSubscriptionTemp(@RequestParam String subscriptionId) { stripeService.cancelSubscriptionTemp(subscriptionId); @@ -110,12 +110,7 @@ public class StripeController { @GetMapping("/detachCustomerAllPaymentMethod") public Response detachCustomerAllPaymentMethod(@RequestParam String name, @RequestParam String email) { return Response.success(stripeService.detachCustomerAllPaymentMethod(name, email)); - } + }*/ - @ApiOperation("临时 获取ip") - @GetMapping("/getIp2") - public Response getIp2(HttpServletRequest request) { - return Response.success(stripeService.getIp2(request)); - } } diff --git a/src/main/java/com/ai/da/mapper/primary/entity/OrderInfo.java b/src/main/java/com/ai/da/mapper/primary/entity/OrderInfo.java index 04a9d894..15ae0cee 100644 --- a/src/main/java/com/ai/da/mapper/primary/entity/OrderInfo.java +++ b/src/main/java/com/ai/da/mapper/primary/entity/OrderInfo.java @@ -29,4 +29,10 @@ public class OrderInfo extends BaseEntity{ private byte isFirstSubscription = 0; private byte isCommissionCalculated = 0; + + private String ipAddress; + + private String country; + + private String city; } diff --git a/src/main/java/com/ai/da/mapper/primary/entity/PaymentInfo.java b/src/main/java/com/ai/da/mapper/primary/entity/PaymentInfo.java index d3533078..0c273d87 100644 --- a/src/main/java/com/ai/da/mapper/primary/entity/PaymentInfo.java +++ b/src/main/java/com/ai/da/mapper/primary/entity/PaymentInfo.java @@ -33,4 +33,10 @@ public class PaymentInfo extends BaseEntity{ // 发票托管页面 private String hostedInvoiceUrl; + + private String ipAddress; + + private String country; + + private String city; } diff --git a/src/main/java/com/ai/da/service/AliPayService.java b/src/main/java/com/ai/da/service/AliPayService.java index 66dd334d..300505bc 100644 --- a/src/main/java/com/ai/da/service/AliPayService.java +++ b/src/main/java/com/ai/da/service/AliPayService.java @@ -1,9 +1,10 @@ package com.ai.da.service; +import javax.servlet.http.HttpServletRequest; import java.util.Map; public interface AliPayService { - String tradeCreate(Integer amount,String returnUrl); + String tradeCreate(Integer amount,String returnUrl, HttpServletRequest request); String tradeNotify(Map params); diff --git a/src/main/java/com/ai/da/service/AlipayHKService.java b/src/main/java/com/ai/da/service/AlipayHKService.java index 13495fe2..51272bb1 100644 --- a/src/main/java/com/ai/da/service/AlipayHKService.java +++ b/src/main/java/com/ai/da/service/AlipayHKService.java @@ -2,9 +2,11 @@ package com.ai.da.service; import com.ai.da.model.dto.AlipayHKCallbackDTO; +import javax.servlet.http.HttpServletRequest; + public interface AlipayHKService { - String createOrder(Integer amount, String wallet); + String createOrder(Integer amount, String wallet, HttpServletRequest request); String callback(String paramString); diff --git a/src/main/java/com/ai/da/service/OrderInfoService.java b/src/main/java/com/ai/da/service/OrderInfoService.java index a420fe70..19264239 100644 --- a/src/main/java/com/ai/da/service/OrderInfoService.java +++ b/src/main/java/com/ai/da/service/OrderInfoService.java @@ -8,13 +8,14 @@ import com.ai.da.mapper.primary.entity.OrderInfo; import com.ai.da.model.dto.QueryPageByTimeDTO; import com.baomidou.mybatisplus.extension.service.IService; +import javax.servlet.http.HttpServletRequest; import java.util.List; public interface OrderInfoService extends IService { - OrderInfo createOrderByProductId(Integer productId, String paymentType); + OrderInfo createOrderByProductId(Integer productId, String paymentType, HttpServletRequest request); - OrderInfo createOrderByProductId(Integer amount, String paymentType, ProductEnum product); + OrderInfo createOrderByProductId(Integer amount, String paymentType, ProductEnum product, HttpServletRequest request); void saveCodeUrl(String orderNo, String codeUrl); diff --git a/src/main/java/com/ai/da/service/PayPalCheckoutService.java b/src/main/java/com/ai/da/service/PayPalCheckoutService.java index d9da17e4..ccf60e92 100644 --- a/src/main/java/com/ai/da/service/PayPalCheckoutService.java +++ b/src/main/java/com/ai/da/service/PayPalCheckoutService.java @@ -12,7 +12,7 @@ import java.util.Map; public interface PayPalCheckoutService { - HashMap createOrder(Integer amount,String returnUrl) throws SerializeException; + HashMap createOrder(Integer amount,String returnUrl, HttpServletRequest request) throws SerializeException; // String callback(@SuppressWarnings("rawtypes") Map map); diff --git a/src/main/java/com/ai/da/service/StripeService.java b/src/main/java/com/ai/da/service/StripeService.java index 4a2e78e1..008b615c 100644 --- a/src/main/java/com/ai/da/service/StripeService.java +++ b/src/main/java/com/ai/da/service/StripeService.java @@ -10,7 +10,7 @@ import java.util.Map; public interface StripeService { - String pay(ProductPurchaseDTO productPurchaseDTO); + String pay(ProductPurchaseDTO productPurchaseDTO, HttpServletRequest request); Boolean notify(HttpServletRequest request); @@ -48,5 +48,5 @@ public interface StripeService { String detachCustomerAllPaymentMethod(String name, String email); - String getIp2(HttpServletRequest request); +// Map getIp(HttpServletRequest request); } diff --git a/src/main/java/com/ai/da/service/impl/AliPayServiceImpl.java b/src/main/java/com/ai/da/service/impl/AliPayServiceImpl.java index 04fc8993..a8bdf410 100644 --- a/src/main/java/com/ai/da/service/impl/AliPayServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/AliPayServiceImpl.java @@ -23,6 +23,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; import java.math.BigDecimal; import java.util.HashMap; import java.util.Map; @@ -54,21 +55,21 @@ public class AliPayServiceImpl implements AliPayService { @Transactional(rollbackFor = Exception.class) @Override - public String tradeCreate(Integer amount, String returnUrl) { + public String tradeCreate(Integer amount, String returnUrl, HttpServletRequest request) { try { //生成订单 log.info("生成订单"); - OrderInfo orderInfo = orderInfoService.createOrderByProductId(amount, PayTypeEnum.ALIPAY.getType()); + OrderInfo orderInfo = orderInfoService.createOrderByProductId(amount, PayTypeEnum.ALIPAY.getType(), request); //调用支付宝接口 - AlipayTradePagePayRequest request = new AlipayTradePagePayRequest(); + AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest(); //配置需要的公共请求参数 //支付完成后,支付宝发起异步通知的地址 - request.setNotifyUrl(config.getProperty("alipay.notify-url")); + alipayRequest.setNotifyUrl(config.getProperty("alipay.notify-url")); //支付完成后,我们想让页面跳转回aida的页面,配置returnUrl -// request.setReturnUrl(config.getProperty("alipay.return-url")); - request.setReturnUrl(returnUrl); +// alipayRequest.setReturnUrl(config.getProperty("alipay.return-url")); + alipayRequest.setReturnUrl(returnUrl); //组装当前业务方法的请求参数 JSONObject bizContent = new JSONObject(); @@ -79,10 +80,10 @@ public class AliPayServiceImpl implements AliPayService { bizContent.put("subject", "积分购买"); bizContent.put("product_code", "FAST_INSTANT_TRADE_PAY"); - request.setBizContent(bizContent.toString()); + alipayRequest.setBizContent(bizContent.toString()); //执行请求,调用支付宝接口 - AlipayTradePagePayResponse response = alipayClient.pageExecute(request); + AlipayTradePagePayResponse response = alipayClient.pageExecute(alipayRequest); if(response.isSuccess()){ log.info("调用成功,返回结果 ===> " + response.getBody()); diff --git a/src/main/java/com/ai/da/service/impl/AlipayHKServiceImpl.java b/src/main/java/com/ai/da/service/impl/AlipayHKServiceImpl.java index 910129ef..fd01eae3 100644 --- a/src/main/java/com/ai/da/service/impl/AlipayHKServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/AlipayHKServiceImpl.java @@ -20,6 +20,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.HashMap; @@ -64,7 +65,7 @@ public class AlipayHKServiceImpl implements AlipayHKService { * 创建订单 */ @Override - public String createOrder(Integer amount, String wallet){ + public String createOrder(Integer amount, String wallet , HttpServletRequest request){ try{ HashMap param = new HashMap<>(); @@ -80,7 +81,7 @@ public class AlipayHKServiceImpl implements AlipayHKService { log.info("alipay-hk 创建订单,参数信息: {}", param); // 生成订单 log.info("创建订单"); - OrderInfo orderInfo = orderInfoService.createOrderByProductId(amount, PayTypeEnum.ALIPAY_HK.getType()); + OrderInfo orderInfo = orderInfoService.createOrderByProductId(amount, PayTypeEnum.ALIPAY_HK.getType(), request); /*// 加密 AlipayHKRequestDTO alipayHKRequestDTO = alipayHKEncryptionUtil.AESCBCWithRSA(param, AlipayHKConstant.CREATE_ORDER); // 请求Alipay服务端 diff --git a/src/main/java/com/ai/da/service/impl/OrderInfoServiceImpl.java b/src/main/java/com/ai/da/service/impl/OrderInfoServiceImpl.java index ae12e612..6c63b002 100644 --- a/src/main/java/com/ai/da/service/impl/OrderInfoServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/OrderInfoServiceImpl.java @@ -7,6 +7,7 @@ import com.ai.da.common.enums.OrderStatusEnum; import com.ai.da.common.enums.ProductEnum; import com.ai.da.common.response.PageBaseResponse; import com.ai.da.common.utils.OrderNoUtils; +import com.ai.da.common.utils.RequestInfoUtil; import com.ai.da.mapper.primary.OrderInfoMapper; import com.ai.da.mapper.primary.PaymentInfoMapper; import com.ai.da.mapper.primary.ProductMapper; @@ -25,11 +26,14 @@ import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; import java.time.Duration; import java.time.Instant; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.List; +import java.util.Map; +import java.util.Objects; @Service @Slf4j @@ -42,7 +46,7 @@ public class OrderInfoServiceImpl extends ServiceImpl createOrder(Integer amount, String returnUrl) throws SerializeException { + public HashMap createOrder(Integer amount, String returnUrl, HttpServletRequest request) throws SerializeException { // 生成订单 log.info("生成订单"); - OrderInfo orderInfo = orderInfoService.createOrderByProductId(amount, PayTypeEnum.PAYPAL.getType()); + OrderInfo orderInfo = orderInfoService.createOrderByProductId(amount, PayTypeEnum.PAYPAL.getType(), request); - OrdersCreateRequest request = new OrdersCreateRequest(); - request.header("prefer", "return=representation"); - request.requestBody(buildRequestBody(String.valueOf(orderInfo.getTotalFee()), returnUrl)); + OrdersCreateRequest paypalRequest = new OrdersCreateRequest(); + paypalRequest.header("prefer", "return=representation"); + paypalRequest.requestBody(buildRequestBody(String.valueOf(orderInfo.getTotalFee()), returnUrl)); HttpResponse response = null; try { - response = payPalClient.client(mode, clientId, clientSecret).execute(request); + response = payPalClient.client(mode, clientId, clientSecret).execute(paypalRequest); } catch (Exception e) { log.error("调用paypal订单创建失败,失败原因 ===> {}", e.getMessage()); throw new BusinessException("Order creation failed"); diff --git a/src/main/java/com/ai/da/service/impl/PaymentInfoServiceImpl.java b/src/main/java/com/ai/da/service/impl/PaymentInfoServiceImpl.java index 4e4d11b2..2d0f3e5c 100644 --- a/src/main/java/com/ai/da/service/impl/PaymentInfoServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/PaymentInfoServiceImpl.java @@ -4,6 +4,7 @@ import com.ai.da.common.context.UserContext; import com.ai.da.common.enums.PayTypeEnum; 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.model.dto.AlipayHKCallbackDTO; import com.ai.da.model.dto.QueryPageByTimeDTO; @@ -44,6 +45,9 @@ public class PaymentInfoServiceImpl extends ServiceImpl paymentMethod = stripeService.getPaymentMethodByInvoiceId(invoiceId); + // 获取订单信息 + OrderInfo orderByOrderNo = orderInfoService.getOrderByOrderNo(orderNo); paymentInfo = new PaymentInfo(); paymentInfo.setOrderNo(orderNo); @@ -246,7 +277,11 @@ public class PaymentInfoServiceImpl extends ServiceImpl Date: Tue, 7 Jan 2025 11:09:22 +0800 Subject: [PATCH 41/91] =?UTF-8?q?=E8=A7=A3=E6=9E=90=E6=89=80=E6=9C=89?= =?UTF-8?q?=E5=8F=91=E8=B5=B7=E8=B4=AD=E4=B9=B0=E7=9A=84=E5=AE=A2=E6=88=B7?= =?UTF-8?q?=E7=AB=AFip=E5=9C=B0=E5=9D=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ai/da/service/impl/StripeServiceImpl.java | 127 +++--------------- 1 file changed, 17 insertions(+), 110 deletions(-) diff --git a/src/main/java/com/ai/da/service/impl/StripeServiceImpl.java b/src/main/java/com/ai/da/service/impl/StripeServiceImpl.java index a1c15a47..f4699890 100644 --- a/src/main/java/com/ai/da/service/impl/StripeServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/StripeServiceImpl.java @@ -5,7 +5,6 @@ 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.RequestInfoUtil; import com.ai.da.common.utils.SendEmailUtil; import com.ai.da.mapper.primary.AccountMapper; import com.ai.da.mapper.primary.PaymentInfoMapper; @@ -18,7 +17,6 @@ import com.ai.da.model.dto.ProductPurchaseDTO; import com.ai.da.model.dto.SubscriptionEmailParamsDTO; import com.ai.da.service.*; import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.toolkit.StringUtils; import com.google.gson.Gson; @@ -38,12 +36,8 @@ import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; -import java.io.BufferedReader; -import java.io.InputStreamReader; import java.math.BigDecimal; import java.math.RoundingMode; -import java.net.HttpURLConnection; -import java.net.URL; import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneOffset; @@ -85,7 +79,7 @@ public class StripeServiceImpl implements StripeService { @Override @Transactional(rollbackFor = Exception.class) - public String pay(ProductPurchaseDTO productPurchaseDTO) { + public String pay(ProductPurchaseDTO productPurchaseDTO, HttpServletRequest request) { Stripe.apiKey = privateKey; ProductEnum productEnum; @@ -102,9 +96,9 @@ public class StripeServiceImpl implements StripeService { case "Year": productEnum = ProductEnum.AnnualSubscription; break; - case "Day": + /*case "Day": productEnum = ProductEnum.DailySubscription; - break; + break;*/ default: throw new BusinessException("unknown subscription type"); } @@ -113,7 +107,8 @@ public class StripeServiceImpl implements StripeService { throw new BusinessException("unknown product type"); } log.info("生成订单"); - OrderInfo orderInfo = orderInfoService.createOrderByProductId(productPurchaseDTO.getQuantity(), PayTypeEnum.STRIPE.getType(), productEnum); + OrderInfo orderInfo = orderInfoService.createOrderByProductId(productPurchaseDTO.getQuantity(), + PayTypeEnum.STRIPE.getType(), productEnum, request); String payType; if (productPurchaseDTO.getAutoRenewal()){ payType = "recurring"; @@ -356,7 +351,6 @@ public class StripeServiceImpl implements StripeService { // 发送续订失败邮件 response = sendRenewalFailEmail(invoice.getId(), null, paymentInfo.getOrderNo()); } - } }else if (stripeObject instanceof Charge) { Charge charge = (Charge) stripeObject; @@ -1005,12 +999,11 @@ public class StripeServiceImpl implements StripeService { } } - // todo 新建一个订阅 使用不会成功的付款方式 - + // 新建一个订阅 使用不会成功的付款方式(仅供测试使用) public String createSubscriptionTemp(String name, String email){ Stripe.apiKey = privateKey; try { - OrderInfo orderInfo = orderInfoService.createOrderByProductId(1, PayTypeEnum.STRIPE.getType(), ProductEnum.DailySubscription); + OrderInfo orderInfo = orderInfoService.createOrderByProductId(1, PayTypeEnum.STRIPE.getType(), ProductEnum.DailySubscription, null); // String customerId = getCustomer(name, email); String paymentMethodCode = "pm_card_mastercard"; @@ -1030,8 +1023,7 @@ public class StripeServiceImpl implements StripeService { .setInvoiceSettings( CustomerUpdateParams.InvoiceSettings.builder() .setDefaultPaymentMethod(paymentMethod.getId()) - .build() - ) + .build()) .build(); updatedCustomer.update(params); @@ -1041,8 +1033,7 @@ public class StripeServiceImpl implements StripeService { .addItem( SubscriptionCreateParams.Item.builder() .setPrice("price_1QFXkf02n1TEydyNtA4TQ3Yz") // 替换为实际的价格 ID - .build() - ) + .build()) .setDescription("AiDA - " + orderInfo.getOrderNo()) .build(); Subscription subscription = Subscription.create(subscriptionParams); @@ -1151,96 +1142,12 @@ public class StripeServiceImpl implements StripeService { } } - public String getIp2(HttpServletRequest request) { - /*String ip = request.getHeader("X-Forwarded-For"); - String ipAddress = ""; - if(StringUtils.isNotEmpty(ip) && !"unKnown".equalsIgnoreCase(ip)){ - //多次反向代理后会有多个ip值,第一个ip才是真实ip - int index = ip.indexOf(","); - if(index != -1){ - ipAddress = ip.substring(0,index); - }else{ - ipAddress = ip; - } - } - ip = request.getHeader("X-Real-IP"); - if(StringUtils.isNotEmpty(ip) && !"unKnown".equalsIgnoreCase(ip)){ - ipAddress = ip; - } - if (!StringUtil.isNullOrEmpty(ipAddress)) { - getIPLocation(ipAddress); - }*/ - String ipAddress = RequestInfoUtil.getIpAddress(request); - if (!StringUtil.isNullOrEmpty(ipAddress)) { - return getIPLocation(ipAddress); - } - - return request.getRemoteAddr(); - } - - /* 免费 API 服务可能有请求频率限制,如果你需要处理大量 IP 地址,可能需要考虑使用付费服务或购买 IP 地理位置数据库。此外,始终要遵守 API 提供商的使用条款和隐私政策。*/ - - public String getIPLocation(String ip) { -// String ip = "117.143.125.1"; // 替换为你想查询的 IP 地址 -// String ip = "194.5.48.180"; // 替换为你想查询的 IP 地址 - String apiURL = "http://ip-api.com/json/" + ip; - - try { - URL url = new URL(apiURL); - HttpURLConnection conn = (HttpURLConnection) url.openConnection(); - conn.setRequestMethod("GET"); - conn.setRequestProperty("Accept", "application/json"); - - if (conn.getResponseCode() != 200) { - throw new RuntimeException("Failed : HTTP error code : " + conn.getResponseCode()); - } - - BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream())); - String output; - StringBuilder outputBuilder = new StringBuilder(); - System.out.println("Output from Server .... \n"); - while ((output = br.readLine()) != null) { - outputBuilder.append(output); - System.out.println(output); - } - conn.disconnect(); - Map map = JSONObject.parseObject(outputBuilder.toString(), Map.class); - log.info("map: {}", map); - return JSON.toJSONString(map); - } catch (Exception e) { - e.printStackTrace(); - } - return null; - } - - public static void main(String[] args) { - String ip = "117.143.125.1"; // 替换为你想查询的 IP 地址 -// String ip = "194.5.48.180"; // 替换为你想查询的 IP 地址 - String apiURL = "http://ip-api.com/json/" + ip; - - try { - URL url = new URL(apiURL); - HttpURLConnection conn = (HttpURLConnection) url.openConnection(); - conn.setRequestMethod("GET"); - conn.setRequestProperty("Accept", "application/json"); - - if (conn.getResponseCode() != 200) { - throw new RuntimeException("Failed : HTTP error code : " + conn.getResponseCode()); - } - - BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream())); - String output; - System.out.println("Output from Server .... \n"); - StringBuilder outputBuilder = new StringBuilder(); - while ((output = br.readLine()) != null) { - outputBuilder.append(output); - System.out.println(output); - } - conn.disconnect(); - Map map = JSONObject.parseObject(outputBuilder.toString(), Map.class); - log.info("map: {}", map); - } catch (Exception e) { - e.printStackTrace(); - } - } +// public String getIp(HttpServletRequest request) { +// String ipAddress = RequestInfoUtil.getIpAddress(request); +// if (!StringUtil.isNullOrEmpty(ipAddress)) { +// return getIPLocation(ipAddress); +// } +// +// return request.getRemoteAddr(); +// } } From c8e4d624b78bc299c5fdae61fce1a77462f74750 Mon Sep 17 00:00:00 2001 From: shahaibo <1023316923@qq.com> Date: Tue, 7 Jan 2025 11:15:25 +0800 Subject: [PATCH 42/91] TASK:AiDA design like sort --- src/main/java/com/ai/da/model/vo/DesignLikeVO.java | 2 ++ src/main/java/com/ai/da/service/impl/DesignServiceImpl.java | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/ai/da/model/vo/DesignLikeVO.java b/src/main/java/com/ai/da/model/vo/DesignLikeVO.java index afbac27c..118b5fe5 100644 --- a/src/main/java/com/ai/da/model/vo/DesignLikeVO.java +++ b/src/main/java/com/ai/da/model/vo/DesignLikeVO.java @@ -12,6 +12,8 @@ import java.util.List; @ApiModel("design like-响应") public class DesignLikeVO { + private Long id; + @ApiModelProperty("分组id") private Long userGroupId; @ApiModelProperty("分组详情id") diff --git a/src/main/java/com/ai/da/service/impl/DesignServiceImpl.java b/src/main/java/com/ai/da/service/impl/DesignServiceImpl.java index 6885040c..984ab558 100644 --- a/src/main/java/com/ai/da/service/impl/DesignServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/DesignServiceImpl.java @@ -1089,12 +1089,14 @@ public class DesignServiceImpl extends ServiceImpl impleme } userLikeService.save(userLike); Integer sortParam = 1; + Long userLikeSortId; if (isFirst) { UserLikeSort userLikeSort = new UserLikeSort(); userLikeSort.setUserLikeGroupId(userGroupId); userLikeSort.setUserLikeId(userLike.getId()); userLikeSort.setSort(1); userLikeSortMapper.insert(userLikeSort); + userLikeSortId = userLikeSort.getId(); }else { QueryWrapper qw = new QueryWrapper<>(); qw.lambda().eq(UserLikeSort::getUserLikeGroupId, userGroupId); @@ -1107,6 +1109,7 @@ public class DesignServiceImpl extends ServiceImpl impleme userLikeSort.setSort(sort + 1); userLikeSortMapper.insert(userLikeSort); sortParam = userLikeSort.getSort(); + userLikeSortId = userLikeSort.getId(); } groupDetailId = userLike.getId(); String designUrl = designPythonOutfitMapper.selectById(userLike.getDesignOutfitId()).getDesignUrl(); @@ -1116,7 +1119,7 @@ public class DesignServiceImpl extends ServiceImpl impleme } //修改designItem为like状态 designItemService.updateLikeStatus(designLikeDTO.getDesignItemId(), (byte) 1); - return new DesignLikeVO(userGroupId, groupDetailId, pictureName, userLike.getId(), sortParam); + return new DesignLikeVO(userLikeSortId, userGroupId, groupDetailId, pictureName, userLike.getId(), sortParam); } private List validateMergeElement(List oldElements, List designItemDetails) { From 710abf2323775f874e2dd3c8d7fae60c5b460ffc Mon Sep 17 00:00:00 2001 From: xupei Date: Tue, 7 Jan 2025 11:47:33 +0800 Subject: [PATCH 43/91] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E7=A7=AF=E5=88=86?= =?UTF-8?q?=E4=BB=B7=E6=A0=BC=EF=BC=8Cfor=20test?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/ai/da/common/enums/ProductEnum.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/ai/da/common/enums/ProductEnum.java b/src/main/java/com/ai/da/common/enums/ProductEnum.java index 11237ffe..4a859b9c 100644 --- a/src/main/java/com/ai/da/common/enums/ProductEnum.java +++ b/src/main/java/com/ai/da/common/enums/ProductEnum.java @@ -7,7 +7,7 @@ import lombok.Getter; @AllArgsConstructor public enum ProductEnum { // 积分购买 - CreditsProduct("AiDA credits purchase", 6L), + CreditsProduct("AiDA credits purchase", 1L), // 年度订阅 AnnualSubscription("AiDA Annual Subscription", 5000L), // 月度订阅 From ee676614f852c682ae8e5dd0fc240bc5776ce380 Mon Sep 17 00:00:00 2001 From: xupei Date: Tue, 7 Jan 2025 14:31:43 +0800 Subject: [PATCH 44/91] =?UTF-8?q?=E7=BB=9F=E4=B8=80=E5=A4=9A=E7=A7=8D?= =?UTF-8?q?=E6=94=AF=E4=BB=98=E6=96=B9=E5=BC=8F=E5=88=9B=E5=BB=BA=E8=AE=A2?= =?UTF-8?q?=E5=8D=95=E7=9A=84=E5=85=A5=E5=8F=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/ai/da/common/enums/ProductEnum.java | 2 +- .../java/com/ai/da/controller/AliPayController.java | 8 +++++--- .../java/com/ai/da/controller/AlipayHKController.java | 8 +++++--- .../ai/da/controller/ConvenientInquiryController.java | 10 ++++++++-- .../com/ai/da/controller/PayPalCheckoutController.java | 8 +++++--- .../java/com/ai/da/model/dto/ProductPurchaseDTO.java | 3 +++ src/main/java/com/ai/da/service/AliPayService.java | 4 +++- src/main/java/com/ai/da/service/AlipayHKService.java | 3 ++- .../java/com/ai/da/service/PayPalCheckoutService.java | 4 ++-- .../java/com/ai/da/service/impl/AliPayServiceImpl.java | 7 ++++--- .../com/ai/da/service/impl/AlipayHKServiceImpl.java | 9 +++++---- .../ai/da/service/impl/PayPalCheckoutServiceImpl.java | 7 ++++--- 12 files changed, 47 insertions(+), 26 deletions(-) diff --git a/src/main/java/com/ai/da/common/enums/ProductEnum.java b/src/main/java/com/ai/da/common/enums/ProductEnum.java index 11237ffe..4a859b9c 100644 --- a/src/main/java/com/ai/da/common/enums/ProductEnum.java +++ b/src/main/java/com/ai/da/common/enums/ProductEnum.java @@ -7,7 +7,7 @@ import lombok.Getter; @AllArgsConstructor public enum ProductEnum { // 积分购买 - CreditsProduct("AiDA credits purchase", 6L), + CreditsProduct("AiDA credits purchase", 1L), // 年度订阅 AnnualSubscription("AiDA Annual Subscription", 5000L), // 月度订阅 diff --git a/src/main/java/com/ai/da/controller/AliPayController.java b/src/main/java/com/ai/da/controller/AliPayController.java index 90452b37..abde0710 100644 --- a/src/main/java/com/ai/da/controller/AliPayController.java +++ b/src/main/java/com/ai/da/controller/AliPayController.java @@ -1,6 +1,7 @@ package com.ai.da.controller; import com.ai.da.common.response.Response; +import com.ai.da.model.dto.ProductPurchaseDTO; import com.ai.da.service.AliPayService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; @@ -9,6 +10,7 @@ import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; +import javax.validation.Valid; import java.util.Map; @CrossOrigin @@ -22,12 +24,12 @@ public class AliPayController { private AliPayService aliPayService; @ApiOperation("统一收单下单并支付页面接口的调用") - @PostMapping("/trade/page/pay/{amount}") - public Response tradePagePay(@PathVariable Integer amount, @RequestParam String returnUrl, HttpServletRequest request){ + @PostMapping("/trade/page/pay") + public Response tradePagePay(@Valid @RequestBody ProductPurchaseDTO productPurchaseDTO, HttpServletRequest request){ log.info("统一收单下单并支付页面接口的调用"); //支付宝开放平台接受 request 请求对象后 // 会为开发者生成一个html 形式的 form表单,包含自动提交的脚本 - String formStr = aliPayService.tradeCreate(amount, returnUrl, request); + String formStr = aliPayService.tradeCreate(productPurchaseDTO, request); //我们将form表单字符串返回给前端程序,之后前端将会调用自动提交脚本,进行表单的提交 //此时,表单会自动提交到action属性所指向的支付宝开放平台中,从而为用户展示一个支付页面 return Response.success(formStr); diff --git a/src/main/java/com/ai/da/controller/AlipayHKController.java b/src/main/java/com/ai/da/controller/AlipayHKController.java index 734a9d62..1cfdcf06 100644 --- a/src/main/java/com/ai/da/controller/AlipayHKController.java +++ b/src/main/java/com/ai/da/controller/AlipayHKController.java @@ -1,6 +1,7 @@ package com.ai.da.controller; import com.ai.da.common.response.Response; +import com.ai.da.model.dto.ProductPurchaseDTO; import com.ai.da.service.AlipayHKService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; @@ -9,6 +10,7 @@ import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; +import javax.validation.Valid; @CrossOrigin @RestController @@ -21,9 +23,9 @@ public class AlipayHKController { private AlipayHKService alipayHKService; @ApiOperation(value = "创建订单") - @PostMapping(value = "/createOrder/{wallet}/{amount}") - public Response createOrder(@PathVariable Integer amount, @PathVariable String wallet, HttpServletRequest request) { - String order = alipayHKService.createOrder(amount, wallet, request); + @PostMapping(value = "/createOrder") + public Response createOrder(@Valid @RequestBody ProductPurchaseDTO productPurchaseDTO, HttpServletRequest request) { + String order = alipayHKService.createOrder(productPurchaseDTO, request); return Response.success(order); } diff --git a/src/main/java/com/ai/da/controller/ConvenientInquiryController.java b/src/main/java/com/ai/da/controller/ConvenientInquiryController.java index ecc8fdd1..564819fa 100644 --- a/src/main/java/com/ai/da/controller/ConvenientInquiryController.java +++ b/src/main/java/com/ai/da/controller/ConvenientInquiryController.java @@ -11,9 +11,9 @@ import com.ai.da.model.dto.UserDesignStatisticDTO; import com.ai.da.model.vo.QuestionnaireFeedbackVO; import com.ai.da.model.vo.QuestionnaireVO; import com.ai.da.model.vo.QueryUserConditionsVO; +import com.ai.da.service.AccountService; import com.ai.da.service.ConvenientInquiryService; import com.baomidou.mybatisplus.core.metadata.IPage; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import io.netty.util.internal.StringUtil; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; @@ -36,13 +36,19 @@ public class ConvenientInquiryController { private DesignMapper designMapper; @Resource private ConvenientInquiryService convenientInquiryService; + @Resource + private AccountService accountService; @ApiOperation("获取当前所有试用用户") @PostMapping("/getTrial") public Response> getTrial(@Valid @RequestBody QueryUserConditionsVO queryUserConditionsVO) { Long accountId = UserContext.getUserHolder().getId(); - if (accountId.equals(31L) || accountId.equals(87L) || accountId.equals(83L) || accountId.equals(6L) || accountId.equals(4L) || accountId.equals(73L)) { + 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") + ) { return Response.success(convenientInquiryService.getTrial(queryUserConditionsVO)); } else { return Response.fail("Sorry, you don't have permission"); diff --git a/src/main/java/com/ai/da/controller/PayPalCheckoutController.java b/src/main/java/com/ai/da/controller/PayPalCheckoutController.java index 87648940..8e3eda9a 100644 --- a/src/main/java/com/ai/da/controller/PayPalCheckoutController.java +++ b/src/main/java/com/ai/da/controller/PayPalCheckoutController.java @@ -1,6 +1,7 @@ package com.ai.da.controller; import com.ai.da.common.response.Response; +import com.ai.da.model.dto.ProductPurchaseDTO; import com.ai.da.service.PayPalCheckoutService; import com.paypal.http.HttpResponse; import com.paypal.http.exceptions.SerializeException; @@ -14,6 +15,7 @@ import javax.annotation.Resource; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; import java.io.IOException; import java.util.HashMap; @@ -26,9 +28,9 @@ public class PayPalCheckoutController { private PayPalCheckoutService payPalCheckoutService; @ApiOperation(value = "创建订单") - @PostMapping(value = "/trade/{amount}") - public Response> createOrder(@PathVariable Integer amount, @RequestParam String returnUrl, HttpServletRequest request) throws SerializeException { - HashMap approvalUrl = payPalCheckoutService.createOrder(amount, returnUrl, request); + @PostMapping(value = "/trade") + public Response> createOrder(@Valid @RequestBody ProductPurchaseDTO productPurchaseDTO, HttpServletRequest request) throws SerializeException { + HashMap approvalUrl = payPalCheckoutService.createOrder(productPurchaseDTO, request); return Response.success(approvalUrl); } diff --git a/src/main/java/com/ai/da/model/dto/ProductPurchaseDTO.java b/src/main/java/com/ai/da/model/dto/ProductPurchaseDTO.java index 0e386e8a..371439f9 100644 --- a/src/main/java/com/ai/da/model/dto/ProductPurchaseDTO.java +++ b/src/main/java/com/ai/da/model/dto/ProductPurchaseDTO.java @@ -27,4 +27,7 @@ public class ProductPurchaseDTO { @ApiModelProperty("是否自动续订 one_time || recurring") private Boolean autoRenewal; + + @ApiModelProperty("使用Alipay-HK时需要选择 ALIPAYHK || ALIPAYCN") + private String wallet; } diff --git a/src/main/java/com/ai/da/service/AliPayService.java b/src/main/java/com/ai/da/service/AliPayService.java index 300505bc..450a14bb 100644 --- a/src/main/java/com/ai/da/service/AliPayService.java +++ b/src/main/java/com/ai/da/service/AliPayService.java @@ -1,10 +1,12 @@ package com.ai.da.service; +import com.ai.da.model.dto.ProductPurchaseDTO; + import javax.servlet.http.HttpServletRequest; import java.util.Map; public interface AliPayService { - String tradeCreate(Integer amount,String returnUrl, HttpServletRequest request); + String tradeCreate(ProductPurchaseDTO productPurchaseDTO, HttpServletRequest request); String tradeNotify(Map params); diff --git a/src/main/java/com/ai/da/service/AlipayHKService.java b/src/main/java/com/ai/da/service/AlipayHKService.java index 51272bb1..a8492c0b 100644 --- a/src/main/java/com/ai/da/service/AlipayHKService.java +++ b/src/main/java/com/ai/da/service/AlipayHKService.java @@ -1,12 +1,13 @@ package com.ai.da.service; import com.ai.da.model.dto.AlipayHKCallbackDTO; +import com.ai.da.model.dto.ProductPurchaseDTO; import javax.servlet.http.HttpServletRequest; public interface AlipayHKService { - String createOrder(Integer amount, String wallet, HttpServletRequest request); + String createOrder(ProductPurchaseDTO productPurchaseDTO, HttpServletRequest request); String callback(String paramString); diff --git a/src/main/java/com/ai/da/service/PayPalCheckoutService.java b/src/main/java/com/ai/da/service/PayPalCheckoutService.java index ccf60e92..e6256827 100644 --- a/src/main/java/com/ai/da/service/PayPalCheckoutService.java +++ b/src/main/java/com/ai/da/service/PayPalCheckoutService.java @@ -1,5 +1,6 @@ package com.ai.da.service; +import com.ai.da.model.dto.ProductPurchaseDTO; import com.paypal.http.exceptions.SerializeException; import com.paypal.orders.Order; @@ -8,11 +9,10 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.HashMap; -import java.util.Map; public interface PayPalCheckoutService { - HashMap createOrder(Integer amount,String returnUrl, HttpServletRequest request) throws SerializeException; + HashMap createOrder(ProductPurchaseDTO productPurchaseDTO, HttpServletRequest request) throws SerializeException; // String callback(@SuppressWarnings("rawtypes") Map map); diff --git a/src/main/java/com/ai/da/service/impl/AliPayServiceImpl.java b/src/main/java/com/ai/da/service/impl/AliPayServiceImpl.java index a8bdf410..2d14a37b 100644 --- a/src/main/java/com/ai/da/service/impl/AliPayServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/AliPayServiceImpl.java @@ -7,6 +7,7 @@ import com.ai.da.common.enums.OrderStatusEnum; import com.ai.da.common.enums.PayTypeEnum; import com.ai.da.mapper.primary.entity.OrderInfo; import com.ai.da.mapper.primary.entity.RefundInfo; +import com.ai.da.model.dto.ProductPurchaseDTO; import com.ai.da.service.*; import com.alibaba.fastjson.JSONObject; import com.alipay.api.AlipayApiException; @@ -55,12 +56,12 @@ public class AliPayServiceImpl implements AliPayService { @Transactional(rollbackFor = Exception.class) @Override - public String tradeCreate(Integer amount, String returnUrl, HttpServletRequest request) { + public String tradeCreate(ProductPurchaseDTO productPurchaseDTO, HttpServletRequest request) { try { //生成订单 log.info("生成订单"); - OrderInfo orderInfo = orderInfoService.createOrderByProductId(amount, PayTypeEnum.ALIPAY.getType(), request); + OrderInfo orderInfo = orderInfoService.createOrderByProductId(productPurchaseDTO.getQuantity(), PayTypeEnum.ALIPAY.getType(), request); //调用支付宝接口 AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest(); @@ -69,7 +70,7 @@ public class AliPayServiceImpl implements AliPayService { alipayRequest.setNotifyUrl(config.getProperty("alipay.notify-url")); //支付完成后,我们想让页面跳转回aida的页面,配置returnUrl // alipayRequest.setReturnUrl(config.getProperty("alipay.return-url")); - alipayRequest.setReturnUrl(returnUrl); + alipayRequest.setReturnUrl(productPurchaseDTO.getReturnUrl()); //组装当前业务方法的请求参数 JSONObject bizContent = new JSONObject(); diff --git a/src/main/java/com/ai/da/service/impl/AlipayHKServiceImpl.java b/src/main/java/com/ai/da/service/impl/AlipayHKServiceImpl.java index fd01eae3..a8230e8c 100644 --- a/src/main/java/com/ai/da/service/impl/AlipayHKServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/AlipayHKServiceImpl.java @@ -11,6 +11,7 @@ import com.ai.da.mapper.primary.AccountMapper; import com.ai.da.mapper.primary.entity.OrderInfo; import com.ai.da.model.dto.AlipayHKCallbackDTO; import com.ai.da.model.dto.AlipayHKRequestDTO; +import com.ai.da.model.dto.ProductPurchaseDTO; import com.ai.da.service.*; import com.alibaba.fastjson.JSONObject; @@ -65,23 +66,23 @@ public class AlipayHKServiceImpl implements AlipayHKService { * 创建订单 */ @Override - public String createOrder(Integer amount, String wallet , HttpServletRequest request){ + public String createOrder(ProductPurchaseDTO productPurchaseDTO, HttpServletRequest request){ try{ HashMap param = new HashMap<>(); String orderRef = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")); param.put("order_ref", orderRef); - param.put("amount", Float.parseFloat(CreditsEventsEnum.PRICE.getValue()) * amount); + param.put("amount", Float.parseFloat(CreditsEventsEnum.PRICE.getValue()) * productPurchaseDTO.getQuantity()); param.put("subject", "AiDA Credits Purchase"); // ALIPAYHK 或者 ALIPAYCN - param.put("wallet", wallet); + param.put("wallet", productPurchaseDTO.getWallet()); param.put("segment_id", segmentId); // param.put("payment_solution", "WAP"); param.put("payment_solution", "PC2MOBILE"); log.info("alipay-hk 创建订单,参数信息: {}", param); // 生成订单 log.info("创建订单"); - OrderInfo orderInfo = orderInfoService.createOrderByProductId(amount, PayTypeEnum.ALIPAY_HK.getType(), request); + OrderInfo orderInfo = orderInfoService.createOrderByProductId(productPurchaseDTO.getQuantity(), PayTypeEnum.ALIPAY_HK.getType(), request); /*// 加密 AlipayHKRequestDTO alipayHKRequestDTO = alipayHKEncryptionUtil.AESCBCWithRSA(param, AlipayHKConstant.CREATE_ORDER); // 请求Alipay服务端 diff --git a/src/main/java/com/ai/da/service/impl/PayPalCheckoutServiceImpl.java b/src/main/java/com/ai/da/service/impl/PayPalCheckoutServiceImpl.java index 63d47097..22d4cd47 100644 --- a/src/main/java/com/ai/da/service/impl/PayPalCheckoutServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/PayPalCheckoutServiceImpl.java @@ -9,6 +9,7 @@ import com.ai.da.common.utils.paypalRequest.AuthenticationRequest; import com.ai.da.common.utils.paypalRequest.WebhookVerifyRequest; import com.ai.da.mapper.primary.entity.OrderInfo; import com.ai.da.mapper.primary.entity.RefundInfo; +import com.ai.da.model.dto.ProductPurchaseDTO; import com.ai.da.service.*; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.gson.Gson; @@ -84,14 +85,14 @@ public class PayPalCheckoutServiceImpl implements PayPalCheckoutService { */ @Override @Transactional(rollbackFor = Exception.class) - public HashMap createOrder(Integer amount, String returnUrl, HttpServletRequest request) throws SerializeException { + public HashMap createOrder(ProductPurchaseDTO productPurchaseDTO, HttpServletRequest request) throws SerializeException { // 生成订单 log.info("生成订单"); - OrderInfo orderInfo = orderInfoService.createOrderByProductId(amount, PayTypeEnum.PAYPAL.getType(), request); + OrderInfo orderInfo = orderInfoService.createOrderByProductId(productPurchaseDTO.getQuantity(), PayTypeEnum.PAYPAL.getType(), request); OrdersCreateRequest paypalRequest = new OrdersCreateRequest(); paypalRequest.header("prefer", "return=representation"); - paypalRequest.requestBody(buildRequestBody(String.valueOf(orderInfo.getTotalFee()), returnUrl)); + paypalRequest.requestBody(buildRequestBody(String.valueOf(orderInfo.getTotalFee()), productPurchaseDTO.getReturnUrl())); HttpResponse response = null; try { response = payPalClient.client(mode, clientId, clientSecret).execute(paypalRequest); From b49f098a5e7b0ba2957de8f2fc139eec8e15c074 Mon Sep 17 00:00:00 2001 From: shahaibo <1023316923@qq.com> Date: Tue, 7 Jan 2025 15:29:46 +0800 Subject: [PATCH 45/91] =?UTF-8?q?TASK:AiDA=20design=20like=20sort=E3=80=81?= =?UTF-8?q?moodboardPosition?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../primary/MoodboardPositionMapper.java | 7 ++ .../primary/entity/MoodboardPosition.java | 29 +++++++ .../ai/da/model/dto/DesignCollectionDTO.java | 2 +- .../java/com/ai/da/model/vo/UserLikeVO.java | 1 + .../service/impl/CollectionServiceImpl.java | 58 +++++++++++++- .../ai/da/service/impl/DesignServiceImpl.java | 79 ++++++++++++++++++- .../impl/UserLikeGroupServiceImpl.java | 4 +- 7 files changed, 174 insertions(+), 6 deletions(-) create mode 100644 src/main/java/com/ai/da/mapper/primary/MoodboardPositionMapper.java create mode 100644 src/main/java/com/ai/da/mapper/primary/entity/MoodboardPosition.java diff --git a/src/main/java/com/ai/da/mapper/primary/MoodboardPositionMapper.java b/src/main/java/com/ai/da/mapper/primary/MoodboardPositionMapper.java new file mode 100644 index 00000000..1ea6f067 --- /dev/null +++ b/src/main/java/com/ai/da/mapper/primary/MoodboardPositionMapper.java @@ -0,0 +1,7 @@ +package com.ai.da.mapper.primary; + +import com.ai.da.common.config.mybatis.plus.CommonMapper; +import com.ai.da.mapper.primary.entity.MoodboardPosition; + +public interface MoodboardPositionMapper extends CommonMapper { +} diff --git a/src/main/java/com/ai/da/mapper/primary/entity/MoodboardPosition.java b/src/main/java/com/ai/da/mapper/primary/entity/MoodboardPosition.java new file mode 100644 index 00000000..db58f7d3 --- /dev/null +++ b/src/main/java/com/ai/da/mapper/primary/entity/MoodboardPosition.java @@ -0,0 +1,29 @@ +package com.ai.da.mapper.primary.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +import java.io.Serializable; +import java.time.LocalDateTime; + +@Data +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +@TableName("moodboard_position") +public class MoodboardPosition implements Serializable { + private static final long serialVersionUID = 1L; + @TableId(value = "id", type = IdType.AUTO) + private Long id; + private Long moodboardId; + private Long collectionId; + private String type; + private String styleData; + private Integer sequence; + private LocalDateTime createTime; + private LocalDateTime updateTime; + +} diff --git a/src/main/java/com/ai/da/model/dto/DesignCollectionDTO.java b/src/main/java/com/ai/da/model/dto/DesignCollectionDTO.java index 91120a0b..54314307 100644 --- a/src/main/java/com/ai/da/model/dto/DesignCollectionDTO.java +++ b/src/main/java/com/ai/da/model/dto/DesignCollectionDTO.java @@ -61,7 +61,7 @@ public class DesignCollectionDTO { @ApiModelProperty("python端design进程ID") private String processId; - private String moodboardPostion; + private String moodboardPosition; private List requestIdList; diff --git a/src/main/java/com/ai/da/model/vo/UserLikeVO.java b/src/main/java/com/ai/da/model/vo/UserLikeVO.java index a1344f80..db4d4638 100644 --- a/src/main/java/com/ai/da/model/vo/UserLikeVO.java +++ b/src/main/java/com/ai/da/model/vo/UserLikeVO.java @@ -25,4 +25,5 @@ public class UserLikeVO { private String pictureName; private Integer sort; + private Long userLikeSortId; } diff --git a/src/main/java/com/ai/da/service/impl/CollectionServiceImpl.java b/src/main/java/com/ai/da/service/impl/CollectionServiceImpl.java index 218c9814..90e299e2 100644 --- a/src/main/java/com/ai/da/service/impl/CollectionServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/CollectionServiceImpl.java @@ -9,13 +9,19 @@ import com.ai.da.common.utils.DateUtil; import com.ai.da.common.utils.MinioUtil; import com.ai.da.common.utils.RedisUtil; import com.ai.da.mapper.primary.CollectionMapper; +import com.ai.da.mapper.primary.MoodboardPositionMapper; import com.ai.da.mapper.primary.entity.Collection; import com.ai.da.mapper.primary.entity.CollectionElement; +import com.ai.da.mapper.primary.entity.MoodboardPosition; import com.ai.da.model.vo.CollectionColorVO; import com.ai.da.model.vo.CollectionElementVO; import com.ai.da.model.vo.UserLikeCollectionVO; import com.ai.da.service.CollectionElementService; import com.ai.da.service.CollectionService; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.toolkit.StringUtils; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import io.netty.util.internal.StringUtil; @@ -25,6 +31,7 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.util.CollectionUtils; import javax.annotation.Resource; +import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Objects; @@ -45,6 +52,8 @@ public class CollectionServiceImpl extends ServiceImpl qw = new QueryWrapper<>(); + qw.lambda().eq(MoodboardPosition::getCollectionId, id); + List moodboardPositions = moodboardPositionMapper.selectList(qw); + if (moodboardPositions != null && !moodboardPositions.isEmpty()) { + // 将查询结果转换为 JSON 字符串 + JSONObject resultJson = new JSONObject(); + + // 遍历 MoodboardPosition 列表,根据实际情况填充到 resultJson 中 + for (MoodboardPosition position : moodboardPositions) { + String type = position.getType(); + String styleData = position.getStyleData(); + int sequence = position.getSequence(); // 获取 sequence 值 + + // 如果 type 字段还没有对应的 JSONArray,则初始化它 + if (!resultJson.containsKey(type)) { + resultJson.put(type, new ArrayList<>()); + } + + // 获取对应类型的列表 + List styleList = (List) resultJson.get(type); + + // 确保列表长度足够,可以容纳 `sequence` 索引 + while (styleList.size() <= sequence) { + styleList.add(new JSONObject()); // 添加空的 JSONObject,直到长度大于 `sequence` + } + + // 将解析的样式数据存入正确的索引位置 + JSONObject styleObject = JSON.parseObject(styleData); + styleList.set(sequence, styleObject); // 根据 sequence 设置数据 + + // 更新回 resultJson + resultJson.put(type, styleList); + } + + // 将最终结果转换为字符串 + return resultJson.toJSONString(); + } else { + return null; // 返回空的 JSON 对象 + } + } + private List resolveColorBoard(List collectionElements) { return CopyUtil.copyList(collectionElements, CollectionColorVO.class, (o, d) -> { String name = o.getName(); diff --git a/src/main/java/com/ai/da/service/impl/DesignServiceImpl.java b/src/main/java/com/ai/da/service/impl/DesignServiceImpl.java index 984ab558..0d27ef2f 100644 --- a/src/main/java/com/ai/da/service/impl/DesignServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/DesignServiceImpl.java @@ -94,6 +94,9 @@ public class DesignServiceImpl extends ServiceImpl impleme @Resource private TDesignPythonOutfitMapper designPythonOutfitMapper; + @Resource + private MoodboardPositionMapper moodboardPositionMapper; + @Value("${minio.endpoint}") private String endpoint; @Value("${minio.bucketName.results}") @@ -304,7 +307,9 @@ public class DesignServiceImpl extends ServiceImpl impleme //保存collection Long collectionId; if (null == collectionIdParam) { - collectionId = collectionService.saveCollection(userInfo.getId(), designDTO.getTimeZone(), designDTO.getMoodTemplateId(), designDTO.getMoodboardPostion()); + collectionId = collectionService.saveCollection(userInfo.getId(), designDTO.getTimeZone(), designDTO.getMoodTemplateId(), designDTO.getMoodboardPosition()); + String moodboardPosition = designDTO.getMoodboardPosition(); + parseMoodboardPosition(moodboardPosition, collectionId); }else { collectionId = collectionIdParam; } @@ -371,6 +376,74 @@ public class DesignServiceImpl extends ServiceImpl impleme return requestId; } + private void parseMoodboardPosition(String moodboardPosition, Long collectionIdParam) { + if (!StringUtils.isEmpty(moodboardPosition)) { + // 将 JSON 字符串解析为 JSONObject + JSONObject moodboardPositionJson = JSONObject.parseObject(moodboardPosition); + + // 准备保存的 MoodboardPosition 列表 + List moodboardPositions = new ArrayList<>(); + + // 遍历 JSON 对象的 key(即样式类型) + for (String key : moodboardPositionJson.keySet()) { + // 特殊处理 "class" 字段 + if ("class".equals(key)) { + // 获取 "class" 字段的值并将其转为 List + JSONArray classArray = moodboardPositionJson.getJSONArray(key); + if (classArray != null) { + + for (int j = 0; j < classArray.size(); j++) { + // 将 classList 存入 MoodboardPosition(或者其他结构) + + MoodboardPosition position = new MoodboardPosition() + .setCollectionId(collectionIdParam) // 关联 Collection ID + .setType(key) // 样式类型 + .setStyleData(classArray.getString(j)) // 设置 class 字段 + .setSequence(j) // 根据索引值设置顺序 + .setCreateTime(LocalDateTime.now()) // 创建时间 + .setUpdateTime(LocalDateTime.now()); // 更新时间 + + // 添加到列表中 + moodboardPositions.add(position); + } + } + continue; // 跳过 "class" 字段的常规处理 + } + + JSONArray styleArray = moodboardPositionJson.getJSONArray(key); + if (styleArray != null) { + for (int i = 0; i < styleArray.size(); i++) { + // 获取当前样式数据 + JSONObject styleData = styleArray.getJSONObject(i); + + // 构建 MoodboardPosition 实例 + MoodboardPosition position = new MoodboardPosition() + .setCollectionId(collectionIdParam) // 关联 Collection ID + .setType(key) // 样式类型 + .setStyleData(styleData.toJSONString()) // 样式数据存为 JSON 字符串 + .setSequence(i) // 根据索引值设置顺序 + .setCreateTime(LocalDateTime.now()) // 创建时间 + .setUpdateTime(LocalDateTime.now()); // 更新时间 + + // 添加到列表中 + moodboardPositions.add(position); + } + } + } + // 如果解析结果非空,保存到数据库 + if (!moodboardPositions.isEmpty()) { + for (MoodboardPosition position : moodboardPositions) { + moodboardPositionMapper.insert(position); + } + log.info("成功解析并保存 {} 条 MoodboardPosition 数据", moodboardPositions.size()); + } else { + log.warn("未找到可保存的 MoodboardPosition 数据"); + } + } else { + log.warn("传入的 moodboardPosition 字段为空"); + } + } + @Override public void relationImageId(DesignPythonObjects pythonObjects) { @@ -417,7 +490,7 @@ public class DesignServiceImpl extends ServiceImpl impleme if (!reDesignDTO.getMoodboardPosition().equals(collection.getMoodboardPosition())) { collection.setMoodboardPosition(reDesignDTO.getMoodboardPosition()); } - if (null != reDesignDTO.getMoodTemplateId() && reDesignDTO.getMoodTemplateId().equals(collection.getMoodTemplateId())) { + if (null != reDesignDTO.getMoodTemplateId() && !reDesignDTO.getMoodTemplateId().equals(collection.getMoodTemplateId())) { collection.setMoodTemplateId(reDesignDTO.getMoodTemplateId()); } collectionService.updateById(collection); @@ -1672,7 +1745,7 @@ public class DesignServiceImpl extends ServiceImpl impleme //保存collection Long collectionId; if (null == collectionIdParam) { - collectionId = collectionService.saveCollection(userInfo.getId(), designDTO.getTimeZone(), designDTO.getMoodTemplateId(), designDTO.getMoodboardPostion()); + collectionId = collectionService.saveCollection(userInfo.getId(), designDTO.getTimeZone(), designDTO.getMoodTemplateId(), designDTO.getMoodboardPosition()); }else { collectionId = collectionIdParam; } diff --git a/src/main/java/com/ai/da/service/impl/UserLikeGroupServiceImpl.java b/src/main/java/com/ai/da/service/impl/UserLikeGroupServiceImpl.java index 697ea056..87ced60b 100644 --- a/src/main/java/com/ai/da/service/impl/UserLikeGroupServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/UserLikeGroupServiceImpl.java @@ -189,7 +189,9 @@ public class UserLikeGroupServiceImpl extends ServiceImpl userLikeSorts = userLikeSortMapper.selectList(userLikeSortQueryWrapper); if (CollectionUtil.isNotEmpty(userLikeSorts)) { - o.setSort(userLikeSorts.get(0).getSort()); + UserLikeSort userLikeSort = userLikeSorts.get(0); + o.setSort(userLikeSort.getSort()); + o.setUserLikeSortId(userLikeSort.getId()); } }); UserLikeCollectionVO userLikeCollection = collectionService.chooseCollection(group.getCollectionId()); From 50d90af3a57591d5ce7905910e4c31d8e13b1288 Mon Sep 17 00:00:00 2001 From: xupei Date: Tue, 7 Jan 2025 17:15:22 +0800 Subject: [PATCH 46/91] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E7=AE=A1=E7=90=86?= =?UTF-8?q?=E5=91=98=E8=AE=BF=E9=97=AE=E8=80=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/ai/da/controller/ConvenientInquiryController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/ai/da/controller/ConvenientInquiryController.java b/src/main/java/com/ai/da/controller/ConvenientInquiryController.java index 564819fa..b18525b9 100644 --- a/src/main/java/com/ai/da/controller/ConvenientInquiryController.java +++ b/src/main/java/com/ai/da/controller/ConvenientInquiryController.java @@ -47,7 +47,7 @@ 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("joho8228@hotmail.com") || userEmail.equals("wanninghua160@gmail.com") ) { return Response.success(convenientInquiryService.getTrial(queryUserConditionsVO)); } else { From 0b245f62afecbb67366202ea94b52ea552f7bdb3 Mon Sep 17 00:00:00 2001 From: shahaibo <1023316923@qq.com> Date: Tue, 7 Jan 2025 17:16:45 +0800 Subject: [PATCH 47/91] =?UTF-8?q?TASK:AiDA=20design=20like=20sort=E3=80=81?= =?UTF-8?q?moodboardPosition?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/impl/CollectionServiceImpl.java | 56 +++++++++++++------ 1 file changed, 38 insertions(+), 18 deletions(-) diff --git a/src/main/java/com/ai/da/service/impl/CollectionServiceImpl.java b/src/main/java/com/ai/da/service/impl/CollectionServiceImpl.java index 90e299e2..9c6fdf93 100644 --- a/src/main/java/com/ai/da/service/impl/CollectionServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/CollectionServiceImpl.java @@ -175,25 +175,45 @@ public class CollectionServiceImpl extends ServiceImpl()); + // 如果 type 字段为 "class",直接将其作为字符串处理 + if ("class".equals(type)) { + // 如果 type 字段还没有对应的 JSONArray,则初始化它 + if (!resultJson.containsKey(type)) { + resultJson.put(type, new ArrayList<>()); + } + + // 获取对应类型的列表 + List classList = (List) resultJson.get(type); + + // 确保列表长度足够,可以容纳 `sequence` 索引 + while (classList.size() <= sequence) { + classList.add(""); // 添加空字符串,直到长度大于 `sequence` + } + + // 将 class 字段直接存入列表 + classList.set(sequence, styleData); // 根据 sequence 设置数据 + + resultJson.put(type, classList); + } else { + // 如果 type 字段为其他类型,按照正常方式处理 + if (!resultJson.containsKey(type)) { + resultJson.put(type, new ArrayList<>()); + } + + // 获取对应类型的列表 + List styleList = (List) resultJson.get(type); + + // 确保列表长度足够,可以容纳 `sequence` 索引 + while (styleList.size() <= sequence) { + styleList.add(new JSONObject()); // 添加空的 JSONObject,直到长度大于 `sequence` + } + + // 将解析的样式数据存入正确的索引位置 + JSONObject styleObject = JSON.parseObject(styleData); + styleList.set(sequence, styleObject); // 根据 sequence 设置数据 + + resultJson.put(type, styleList); } - - // 获取对应类型的列表 - List styleList = (List) resultJson.get(type); - - // 确保列表长度足够,可以容纳 `sequence` 索引 - while (styleList.size() <= sequence) { - styleList.add(new JSONObject()); // 添加空的 JSONObject,直到长度大于 `sequence` - } - - // 将解析的样式数据存入正确的索引位置 - JSONObject styleObject = JSON.parseObject(styleData); - styleList.set(sequence, styleObject); // 根据 sequence 设置数据 - - // 更新回 resultJson - resultJson.put(type, styleList); } // 将最终结果转换为字符串 From e4936a23bc619134ebce0b4fe9b2ce8a732d38c7 Mon Sep 17 00:00:00 2001 From: xupei Date: Wed, 8 Jan 2025 14:20:12 +0800 Subject: [PATCH 48/91] =?UTF-8?q?=E7=BC=96=E8=BE=91=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E5=90=8D=EF=BC=8C=E6=94=B9=E4=B8=BA=E5=BD=93=E5=89=8D=E6=9C=88?= =?UTF-8?q?=E5=85=81=E8=AE=B8=E4=BF=AE=E6=94=B95=E6=AC=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/ai/da/common/task/AccountTask.java | 10 +++++ .../com/ai/da/common/task/PaymentTask.java | 2 +- .../com/ai/da/common/utils/RedisUtil.java | 8 ++++ .../ai/da/controller/AccountController.java | 2 +- .../com/ai/da/model/vo/AccountLoginVO.java | 2 +- .../com/ai/da/service/AccountService.java | 2 +- .../da/service/impl/AccountServiceImpl.java | 38 +++++++++---------- 7 files changed, 41 insertions(+), 23 deletions(-) diff --git a/src/main/java/com/ai/da/common/task/AccountTask.java b/src/main/java/com/ai/da/common/task/AccountTask.java index 9c66563c..b4aacac8 100644 --- a/src/main/java/com/ai/da/common/task/AccountTask.java +++ b/src/main/java/com/ai/da/common/task/AccountTask.java @@ -1,5 +1,6 @@ package com.ai.da.common.task; +import com.ai.da.common.utils.RedisUtil; import com.ai.da.mapper.primary.entity.Account; import com.ai.da.service.AccountService; import lombok.extern.slf4j.Slf4j; @@ -15,6 +16,8 @@ public class AccountTask { @Resource private AccountService accountService; + @Resource + private RedisUtil redisUtil; /** * 每周日晚上刷新 年付用户、月付用户的积分 @@ -69,4 +72,11 @@ public class AccountTask { public void registerUserToVisitor() { accountService.registerUserToVisitor(); } + + @Scheduled(cron = "0 0 0 1 * ?") + // 每月初刷新所有用户用户名剩余修改次数 + public void resetUsernameModifyTimes(){ + log.info("重置所有用户的用户名修改次数"); + redisUtil.batchDeleteKeysWithSamePrefix(RedisUtil.NICKNAME_MODIFY_TIMES); + } } diff --git a/src/main/java/com/ai/da/common/task/PaymentTask.java b/src/main/java/com/ai/da/common/task/PaymentTask.java index 40450055..a7fe8ffb 100644 --- a/src/main/java/com/ai/da/common/task/PaymentTask.java +++ b/src/main/java/com/ai/da/common/task/PaymentTask.java @@ -102,7 +102,7 @@ public class PaymentTask { } - @Scheduled(cron = "0 */5 * * * *") // Run every 5 minutes +// @Scheduled(cron = "0 */5 * * * *") // Run every 5 minutes public void updateAffiliateInfoWithPayment(){ affiliateService.updateAffiliateInfoWithPayment(); } diff --git a/src/main/java/com/ai/da/common/utils/RedisUtil.java b/src/main/java/com/ai/da/common/utils/RedisUtil.java index 7e0d9578..a0d42840 100644 --- a/src/main/java/com/ai/da/common/utils/RedisUtil.java +++ b/src/main/java/com/ai/da/common/utils/RedisUtil.java @@ -292,4 +292,12 @@ public class RedisUtil { String key = AFFILIATE_LINK_VIEW_KEY + accountId; return redisTemplate.opsForValue().increment(key, 0); } + + public void batchDeleteKeysWithSamePrefix(String prefix){ + Set keys = redisTemplate.keys(prefix + "*"); + assert keys != null; + if (!keys.isEmpty()){ + redisTemplate.delete(keys); + } + } } diff --git a/src/main/java/com/ai/da/controller/AccountController.java b/src/main/java/com/ai/da/controller/AccountController.java index 1afac49d..56b2f2f4 100644 --- a/src/main/java/com/ai/da/controller/AccountController.java +++ b/src/main/java/com/ai/da/controller/AccountController.java @@ -224,7 +224,7 @@ public class AccountController { @ApiOperation(value = "getUsernameModifyTimes") @GetMapping("/getNicknameModifyTimes") - public Response> getNicknameModifyTimes(){ + public Response getNicknameModifyTimes(){ return Response.success(accountService.getNicknameModifyTimes()); } diff --git a/src/main/java/com/ai/da/model/vo/AccountLoginVO.java b/src/main/java/com/ai/da/model/vo/AccountLoginVO.java index 04c783ac..02b2c73d 100644 --- a/src/main/java/com/ai/da/model/vo/AccountLoginVO.java +++ b/src/main/java/com/ai/da/model/vo/AccountLoginVO.java @@ -71,6 +71,6 @@ public class AccountLoginVO { private String occupation; - private Map usernameModify; + private Long usernameModify; } diff --git a/src/main/java/com/ai/da/service/AccountService.java b/src/main/java/com/ai/da/service/AccountService.java index e37d4b09..2374234e 100644 --- a/src/main/java/com/ai/da/service/AccountService.java +++ b/src/main/java/com/ai/da/service/AccountService.java @@ -173,7 +173,7 @@ public interface AccountService extends IService { void registerUserToVisitor(); - Map getNicknameModifyTimes(); + Long getNicknameModifyTimes(); void editUserName(String newUserName); diff --git a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java index fac4f83f..0577e514 100644 --- a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java @@ -1830,36 +1830,36 @@ public class AccountServiceImpl extends ServiceImpl impl return redisUtil.getPersonalHomepageViewCount(accountId); } - // 获取当前用户30天内 剩余昵称修改次数 - public Map getNicknameModifyTimes(){ + // 获取当前用户本月内 剩余昵称修改次数 + public Long getNicknameModifyTimes(){ Long accountId = UserContext.getUserHolder().getId(); String key = RedisUtil.NICKNAME_MODIFY_TIMES + accountId; Long times = redisUtil.getIncrementCount(key); - HashMap resp = new HashMap<>(); - resp.put("remainingTimes", 5L - times); - resp.put("remainingDays", redisUtil.getExpire(key) == -1 ? 30L : (long) Math.ceil((double) redisUtil.getExpire(key) / (24 * 60 * 60))); - return resp; +// HashMap resp = new HashMap<>(); +// resp.put("remainingTimes", 5L - times); +// resp.put("remainingDays", redisUtil.getExpire(key) == -1 ? 30L : (long) Math.ceil((double) redisUtil.getExpire(key) / (24 * 60 * 60))); + return 5L - times; } - // 修改用户名 允许用户30天内修改5次 + // 修改用户名 允许用户当前月内修改5次 @Transactional(rollbackFor = Exception.class) public void editUserName(String newUserName){ Long accountId = UserContext.getUserHolder().getId(); // 判断当前用户是否还有修改昵称的次数 - Map remainTimes = getNicknameModifyTimes(); - Long remainingModifyTimes = remainTimes.get("remainingTimes"); +// Map remainTimes = getNicknameModifyTimes(); + Long remainingModifyTimes = getNicknameModifyTimes(); if (remainingModifyTimes > 0){ - Account account = new Account().setUserName(newUserName); - account.setId(accountId); - baseMapper.updateById(account); - - String key = RedisUtil.NICKNAME_MODIFY_TIMES + accountId; - // 先判断有没有这个key,若没有这个key, 需要为key添加有效期 - if (remainingModifyTimes == 5){ - redisUtil.setKeyExpire(key, 30L); + Account account = baseMapper.selectById(accountId); + // 当新昵称与旧昵称不同时,修改 + if (!account.getUserName().equals(newUserName)){ + account.setUserName(newUserName); + account.setId(accountId); + baseMapper.updateById(account); + // 每个月初清除RedisUtil.NICKNAME_MODIFY_TIMES下的所有记录 + String key = RedisUtil.NICKNAME_MODIFY_TIMES + accountId; + // 增加修改次数 + redisUtil.increaseCount(key); } - // 增加修改次数 - redisUtil.increaseCount(key); }else { throw new BusinessException("remaining.modifications", 1); } From 57a8260f03dabc0566a1c1fd7bf13dd19d95365d Mon Sep 17 00:00:00 2001 From: shahaibo <1023316923@qq.com> Date: Wed, 8 Jan 2025 15:38:29 +0800 Subject: [PATCH 49/91] TASK:AiDA design like sort --- src/main/java/com/ai/da/model/vo/DesignLikeVO.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/ai/da/model/vo/DesignLikeVO.java b/src/main/java/com/ai/da/model/vo/DesignLikeVO.java index 118b5fe5..a8d0c5d8 100644 --- a/src/main/java/com/ai/da/model/vo/DesignLikeVO.java +++ b/src/main/java/com/ai/da/model/vo/DesignLikeVO.java @@ -12,7 +12,7 @@ import java.util.List; @ApiModel("design like-响应") public class DesignLikeVO { - private Long id; + private Long userLikeSortId; @ApiModelProperty("分组id") private Long userGroupId; From 4fe5f658677588d00f919add6a7b8a8f70370112 Mon Sep 17 00:00:00 2001 From: shahaibo <1023316923@qq.com> Date: Wed, 8 Jan 2025 16:56:02 +0800 Subject: [PATCH 50/91] TASK:AiDA design like sort --- .../com/ai/da/service/impl/DesignServiceImpl.java | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/ai/da/service/impl/DesignServiceImpl.java b/src/main/java/com/ai/da/service/impl/DesignServiceImpl.java index 0d27ef2f..10a5d576 100644 --- a/src/main/java/com/ai/da/service/impl/DesignServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/DesignServiceImpl.java @@ -1175,11 +1175,17 @@ public class DesignServiceImpl extends ServiceImpl impleme qw.lambda().eq(UserLikeSort::getUserLikeGroupId, userGroupId); qw.lambda().orderByDesc(UserLikeSort::getSort); List userLikeSorts = userLikeSortMapper.selectList(qw); - Integer sort = userLikeSorts.get(0).getSort(); UserLikeSort userLikeSort = new UserLikeSort(); - userLikeSort.setUserLikeGroupId(userGroupId); - userLikeSort.setUserLikeId(userLike.getId()); - userLikeSort.setSort(sort + 1); + if (CollectionUtils.isEmpty(userLikeSorts)) { + userLikeSort.setUserLikeGroupId(userGroupId); + userLikeSort.setUserLikeId(userLike.getId()); + userLikeSort.setSort(1); + }else { + Integer sort = userLikeSorts.get(0).getSort(); + userLikeSort.setUserLikeGroupId(userGroupId); + userLikeSort.setUserLikeId(userLike.getId()); + userLikeSort.setSort(sort + 1); + } userLikeSortMapper.insert(userLikeSort); sortParam = userLikeSort.getSort(); userLikeSortId = userLikeSort.getId(); From 698fca878753c12fdccbee6a4107f993e87f157d Mon Sep 17 00:00:00 2001 From: xupei Date: Fri, 10 Jan 2025 13:27:27 +0800 Subject: [PATCH 51/91] =?UTF-8?q?=E6=9F=A5=E8=AF=A2=E5=90=84=E5=B9=B3?= =?UTF-8?q?=E5=8F=B0=E4=BA=A4=E6=98=93=E8=AE=B0=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ConvenientInquiryController.java | 11 ++- .../da/mapper/primary/PaymentInfoMapper.java | 10 +++ .../da/mapper/primary/entity/PaymentInfo.java | 10 ++- .../ai/da/model/dto/QueryPaymentInfoDTO.java | 27 ++++++ .../com/ai/da/model/vo/PaymentInfoVO.java | 32 +++++++ .../da/service/ConvenientInquiryService.java | 5 ++ .../com/ai/da/service/PaymentInfoService.java | 6 +- .../da/service/impl/AccountServiceImpl.java | 2 +- .../ai/da/service/impl/AliPayServiceImpl.java | 4 +- .../da/service/impl/AlipayHKServiceImpl.java | 2 +- .../impl/ConvenientInquiryServiceImpl.java | 71 ++++++++++----- .../impl/PayPalCheckoutServiceImpl.java | 4 +- .../service/impl/PaymentInfoServiceImpl.java | 9 +- .../mapper/primary/PaymentInfoMapper.xml | 86 +++++++++++++++++++ 14 files changed, 240 insertions(+), 39 deletions(-) create mode 100644 src/main/java/com/ai/da/model/dto/QueryPaymentInfoDTO.java create mode 100644 src/main/java/com/ai/da/model/vo/PaymentInfoVO.java diff --git a/src/main/java/com/ai/da/controller/ConvenientInquiryController.java b/src/main/java/com/ai/da/controller/ConvenientInquiryController.java index 9795ca1a..42f87ad2 100644 --- a/src/main/java/com/ai/da/controller/ConvenientInquiryController.java +++ b/src/main/java/com/ai/da/controller/ConvenientInquiryController.java @@ -2,20 +2,21 @@ package com.ai.da.controller; import com.ai.da.common.context.UserContext; +import com.ai.da.common.response.PageBaseResponse; import com.ai.da.common.response.Response; import com.ai.da.mapper.primary.DesignMapper; import com.ai.da.mapper.primary.entity.Account; import com.ai.da.mapper.primary.entity.TrialOrder; import com.ai.da.model.dto.AccountAddDTO; +import com.ai.da.model.dto.QueryPaymentInfoDTO; import com.ai.da.model.dto.UserDesignStatisticDTO; +import com.ai.da.model.vo.PaymentInfoVO; import com.ai.da.model.vo.QuestionnaireFeedbackVO; import com.ai.da.model.vo.QuestionnaireVO; import com.ai.da.model.vo.QueryUserConditionsVO; import com.ai.da.service.AccountService; import com.ai.da.service.ConvenientInquiryService; import com.baomidou.mybatisplus.core.metadata.IPage; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import com.itextpdf.text.pdf.PRIndirectReference; import io.netty.util.internal.StringUtil; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; @@ -196,5 +197,9 @@ public class ConvenientInquiryController { return Response.success(convenientInquiryService.getAllUserIdList()); } - + @ApiOperation("获取所有交易信息") + @PostMapping("/queryTransaction") + public Response> queryTransactionRecords(@Valid @RequestBody QueryPaymentInfoDTO queryPaymentInfoDTO){ + return Response.success(convenientInquiryService.queryTransactionRecords(queryPaymentInfoDTO)); + } } diff --git a/src/main/java/com/ai/da/mapper/primary/PaymentInfoMapper.java b/src/main/java/com/ai/da/mapper/primary/PaymentInfoMapper.java index 797c5baf..b0a82f21 100644 --- a/src/main/java/com/ai/da/mapper/primary/PaymentInfoMapper.java +++ b/src/main/java/com/ai/da/mapper/primary/PaymentInfoMapper.java @@ -2,6 +2,7 @@ package com.ai.da.mapper.primary; import com.ai.da.mapper.primary.entity.PaymentInfo; import com.ai.da.model.vo.OrderListVO; +import com.ai.da.model.vo.PaymentInfoVO; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import java.util.List; @@ -11,4 +12,13 @@ public interface PaymentInfoMapper extends BaseMapper { List selectPageOrderList(Long accountId, String startTime, String endTime, int offset, int pageSize, Long id); int queryOrderListTotalCount(Long accountId, String startTime, String endTime, Long id); + + List queryPaymentInfo(String paymentType,String payerTotal, String type, String status, + String country, String city, String startTime, String endTime, + int limit, int offset + ); + + Long queryPaymentInfoCount(String paymentType,String payerTotal, String type, String status, + String country, String city, String startTime, String endTime + ); } diff --git a/src/main/java/com/ai/da/mapper/primary/entity/PaymentInfo.java b/src/main/java/com/ai/da/mapper/primary/entity/PaymentInfo.java index 0c273d87..12470d20 100644 --- a/src/main/java/com/ai/da/mapper/primary/entity/PaymentInfo.java +++ b/src/main/java/com/ai/da/mapper/primary/entity/PaymentInfo.java @@ -15,13 +15,21 @@ public class PaymentInfo extends BaseEntity{ private String paymentType;//支付类型 + /** + * PayPal 订单状态:CREATED/SAVED/APPROVED/VOIDED/COMPLETED/PAYER_ACTION_REQUIRED + * Stripe 订单状态: 原 session 状态:open/completed/expired ; 现 invoice 状态:draft/open/paid/uncollectible/void + * Alipay-HK 订单状态:wait, paid, expired, liquidated + * paid and liquidated means the refund request has been executed. + * expired means the request has been rejected. + * wait means the request is still under processing. + */ private String tradeState;//交易状态 private Float payerTotal;//支付金额(元) private String content;//通知参数 - // 支付类型 new || renewal + // 支付类型 new || renewal || credits private String type; // 当前支付是否已邮件通知 0 || 1 diff --git a/src/main/java/com/ai/da/model/dto/QueryPaymentInfoDTO.java b/src/main/java/com/ai/da/model/dto/QueryPaymentInfoDTO.java new file mode 100644 index 00000000..28f7ac06 --- /dev/null +++ b/src/main/java/com/ai/da/model/dto/QueryPaymentInfoDTO.java @@ -0,0 +1,27 @@ +package com.ai.da.model.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +@EqualsAndHashCode(callSuper = true) +@NoArgsConstructor +@Data +@ApiModel("交易记录详情") +public class QueryPaymentInfoDTO extends QueryPageByTimeDTO { + @ApiModelProperty("选择的支付平台 PayPal || Stripe || Alipay-HK") + private String platform; + @ApiModelProperty("支付的金额 单位:HKD") + private String payerTotal; + @ApiModelProperty("商品种类 new || renewal || credits") + private String type; + @ApiModelProperty("交易状态 Success || Fail || Pending") + private String status; + @ApiModelProperty("付款人所在国家") + private String country; + @ApiModelProperty("付款人所在城市") + private String city; + +} diff --git a/src/main/java/com/ai/da/model/vo/PaymentInfoVO.java b/src/main/java/com/ai/da/model/vo/PaymentInfoVO.java new file mode 100644 index 00000000..34ddbf79 --- /dev/null +++ b/src/main/java/com/ai/da/model/vo/PaymentInfoVO.java @@ -0,0 +1,32 @@ +package com.ai.da.model.vo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.NoArgsConstructor; + +@NoArgsConstructor +@Data +@ApiModel("交易记录详情") +public class PaymentInfoVO { + private Long id; + @ApiModelProperty("选择的支付平台 PayPal || Stripe || Alipay-HK") + private String platform; + @ApiModelProperty("支付的金额 单位:HKD") + private String payerTotal; + @ApiModelProperty("商品种类 new || renewal || credits") + private String type; + @ApiModelProperty("交易状态 Success || Fail || Pending") + private String status; + @ApiModelProperty("付款人所在国家") + private String country; + @ApiModelProperty("付款人所在城市") + private String city; + @ApiModelProperty("使用Stripe具体的支付方式") + private String paymentMethod; + @ApiModelProperty("信用卡支付的卡号后四位") + private String last4; + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8") + private String createTime; +} diff --git a/src/main/java/com/ai/da/service/ConvenientInquiryService.java b/src/main/java/com/ai/da/service/ConvenientInquiryService.java index fa4210f4..3e71d645 100644 --- a/src/main/java/com/ai/da/service/ConvenientInquiryService.java +++ b/src/main/java/com/ai/da/service/ConvenientInquiryService.java @@ -1,9 +1,12 @@ package com.ai.da.service; +import com.ai.da.common.response.PageBaseResponse; import com.ai.da.mapper.primary.entity.Account; import com.ai.da.mapper.primary.entity.Questionnaire; import com.ai.da.mapper.primary.entity.TrialOrder; import com.ai.da.model.dto.AccountAddDTO; +import com.ai.da.model.dto.QueryPaymentInfoDTO; +import com.ai.da.model.vo.PaymentInfoVO; import com.ai.da.model.vo.QuestionnaireFeedbackVO; import com.ai.da.model.vo.QuestionnaireVO; import com.ai.da.model.vo.QueryUserConditionsVO; @@ -43,4 +46,6 @@ public interface ConvenientInquiryService extends IService { IPage getUserInfo(QueryUserConditionsVO queryUserConditionsVO); List> getAllUserIdList(); + + PageBaseResponse queryTransactionRecords(QueryPaymentInfoDTO queryPaymentInfoDTO); } diff --git a/src/main/java/com/ai/da/service/PaymentInfoService.java b/src/main/java/com/ai/da/service/PaymentInfoService.java index 761c0d8b..03db46a4 100644 --- a/src/main/java/com/ai/da/service/PaymentInfoService.java +++ b/src/main/java/com/ai/da/service/PaymentInfoService.java @@ -17,11 +17,11 @@ public interface PaymentInfoService extends IService { void createPaymentInfo(String plainText); - void createPaymentInfoForAliPay(Map params); + void createPaymentInfoForAliPay(Map params, String type); - void createPaymentInfoForPayPal(Order order); + void createPaymentInfoForPayPal(Order order, String type); - void createPaymentInfoForAliPayHK(AlipayHKCallbackDTO alipayHKCallbackDTO); + void createPaymentInfoForAliPayHK(AlipayHKCallbackDTO alipayHKCallbackDTO, String type); PaymentInfo createOrUpdatePaymentInfoForStripe(Invoice invoice); diff --git a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java index 0577e514..3679acfa 100644 --- a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java @@ -1256,7 +1256,7 @@ public class AccountServiceImpl extends ServiceImpl impl private static final String QUERY_CUSTOMER_EMAIL = "SELECT username, email, country FROM pmr_wc_customer_lookup " + "WHERE customer_id = ? "; private static final String UPDATE_ORDER_STATUS = "UPDATE pmr_wc_order_stats " + - "SET status = 'wc-complete' , date_completed = ? " + + "SET status = 'wc-completed' , date_completed = ? " + "WHERE order_id = ?"; private static final DataSource dataSource; diff --git a/src/main/java/com/ai/da/service/impl/AliPayServiceImpl.java b/src/main/java/com/ai/da/service/impl/AliPayServiceImpl.java index 2d14a37b..2d3e6ed4 100644 --- a/src/main/java/com/ai/da/service/impl/AliPayServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/AliPayServiceImpl.java @@ -211,7 +211,7 @@ public class AliPayServiceImpl implements AliPayService { //更新订单状态 orderInfoService.updateStatusByOrderNo(orderNo, OrderStatusEnum.SUCCESS); //记录支付日志 - paymentInfoService.createPaymentInfoForAliPay(params); + paymentInfoService.createPaymentInfoForAliPay(params,"credits"); float quantity = Float.parseFloat(totalAmount) / Float.parseFloat(CreditsEventsEnum.PRICE.getValue()); // 更新积分 creditsService.buyCredits(orderByOrderNo.getAccountId(), quantity); @@ -315,7 +315,7 @@ public class AliPayServiceImpl implements AliPayService { //如果订单已支付,则更新商户端订单状态 orderInfoService.updateStatusByOrderNo(orderNo, OrderStatusEnum.SUCCESS); //并记录支付日志 - paymentInfoService.createPaymentInfoForAliPay(alipayTradeQueryResponse); + paymentInfoService.createPaymentInfoForAliPay(alipayTradeQueryResponse, "credits"); float quantity = orderByOrderNo.getTotalFee() / Float.parseFloat(CreditsEventsEnum.PRICE.getValue()); // 更新积分 creditsService.buyCredits(orderByOrderNo.getAccountId(), quantity); diff --git a/src/main/java/com/ai/da/service/impl/AlipayHKServiceImpl.java b/src/main/java/com/ai/da/service/impl/AlipayHKServiceImpl.java index a8230e8c..6b74b072 100644 --- a/src/main/java/com/ai/da/service/impl/AlipayHKServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/AlipayHKServiceImpl.java @@ -245,7 +245,7 @@ public class AlipayHKServiceImpl implements AlipayHKService { orderInfoService.updateStatusByOrderNo(orderNo, OrderStatusEnum.SUCCESS); log.info("Alipay-HK 订单:{} 状态更新成功",orderNo); //记录支付日志 - paymentInfoService.createPaymentInfoForAliPayHK(alipayHKCallbackDTO); + paymentInfoService.createPaymentInfoForAliPayHK(alipayHKCallbackDTO, "credits"); log.info("Alipay-HK 订单:{} 支付信息状态更新成功",orderNo); float quantity = Float.parseFloat(totalAmount) / Float.parseFloat(CreditsEventsEnum.PRICE.getValue()); // 更新积分 diff --git a/src/main/java/com/ai/da/service/impl/ConvenientInquiryServiceImpl.java b/src/main/java/com/ai/da/service/impl/ConvenientInquiryServiceImpl.java index 69167b80..0bd9a40c 100644 --- a/src/main/java/com/ai/da/service/impl/ConvenientInquiryServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/ConvenientInquiryServiceImpl.java @@ -4,19 +4,16 @@ import com.ai.da.common.config.exception.BusinessException; import com.ai.da.common.constant.CommonConstant; import com.ai.da.common.context.UserContext; import com.ai.da.common.enums.CreditsEventsEnum; +import com.ai.da.common.response.PageBaseResponse; import com.ai.da.common.utils.CopyUtil; -import com.ai.da.mapper.primary.AccountMapper; -import com.ai.da.mapper.primary.QuestionnaireMapper; -import com.ai.da.mapper.primary.ToProductImageResultMapper; -import com.ai.da.mapper.primary.TrialOrderMapper; +import com.ai.da.mapper.primary.*; import com.ai.da.mapper.primary.entity.Account; import com.ai.da.mapper.primary.entity.Questionnaire; import com.ai.da.mapper.primary.entity.TrialOrder; import com.ai.da.model.dto.AccountAddDTO; +import com.ai.da.model.dto.QueryPaymentInfoDTO; import com.ai.da.model.enums.Language; -import com.ai.da.model.vo.QuestionnaireFeedbackVO; -import com.ai.da.model.vo.QuestionnaireVO; -import com.ai.da.model.vo.QueryUserConditionsVO; +import com.ai.da.model.vo.*; import com.ai.da.service.*; import com.alibaba.fastjson.JSON; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; @@ -43,9 +40,22 @@ public class ConvenientInquiryServiceImpl extends ServiceImpl getTrial(QueryUserConditionsVO queryUserConditionsVO) { log.info("getTrial parameter : {},page:{}, size:{}", queryUserConditionsVO, queryUserConditionsVO.getPage(), queryUserConditionsVO.getSize()); @@ -323,17 +333,6 @@ public class ConvenientInquiryServiceImpl extends ServiceImpl> getActiveUserFunc(String startTime, String endTime, List ids) { log.info("getActiveUserFunc ==> startTime:{}, endTime:{}, accountList:{}", startTime, endTime, ids); @@ -388,9 +387,6 @@ public class ConvenientInquiryServiceImpl extends ServiceImpl conversionRate(String startTime, String endTime) { @@ -457,7 +453,6 @@ public class ConvenientInquiryServiceImpl extends ServiceImpl (Long)map.get("id")).collect(Collectors.toList()); } + /** + * 查询交易记录 + * 允许按日期,支付方式,支付金额,商品种类,交易状态,付款人的国家或城市查询,需要分页查询 + */ + public PageBaseResponse queryTransactionRecords(QueryPaymentInfoDTO queryPaymentInfoDTO) { + Integer size = queryPaymentInfoDTO.getSize(); + int offset = (queryPaymentInfoDTO.getPage() - 1) * size; + List paymentInfoVOS = paymentInfoMapper.queryPaymentInfo(queryPaymentInfoDTO.getPlatform(), queryPaymentInfoDTO.getPayerTotal(), + queryPaymentInfoDTO.getType(), queryPaymentInfoDTO.getStatus(), + queryPaymentInfoDTO.getCountry(), queryPaymentInfoDTO.getCity(), + queryPaymentInfoDTO.getStartTime(), queryPaymentInfoDTO.getEndTime(), + size, offset); + // 查询数据总量 + Long total = paymentInfoMapper.queryPaymentInfoCount(queryPaymentInfoDTO.getPlatform(), queryPaymentInfoDTO.getPayerTotal(), + queryPaymentInfoDTO.getType(), queryPaymentInfoDTO.getStatus(), + queryPaymentInfoDTO.getCountry(), queryPaymentInfoDTO.getCity(), + queryPaymentInfoDTO.getStartTime(), queryPaymentInfoDTO.getEndTime()); + + // 总页数 + double totalPage = Math.ceil((double) total / size); + // 组装返回参数 + PageBaseResponse response = new PageBaseResponse<>(); + response.setContent(paymentInfoVOS); + response.setPage(queryPaymentInfoDTO.getPage()); + response.setSize(size); + response.setTotal(total); + response.setPages((long) totalPage); + return response; + } + } diff --git a/src/main/java/com/ai/da/service/impl/PayPalCheckoutServiceImpl.java b/src/main/java/com/ai/da/service/impl/PayPalCheckoutServiceImpl.java index 22d4cd47..98595177 100644 --- a/src/main/java/com/ai/da/service/impl/PayPalCheckoutServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/PayPalCheckoutServiceImpl.java @@ -586,7 +586,7 @@ public class PayPalCheckoutServiceImpl implements PayPalCheckoutService { //更新订单状态 orderInfoService.updateStatusByOrderNo(orderNo, OrderStatusEnum.SUCCESS); //记录支付日志 - paymentInfoService.createPaymentInfoForPayPal(capturedOrder); + paymentInfoService.createPaymentInfoForPayPal(capturedOrder, "credits"); float quantity = orderInfo.getTotalFee() / Float.parseFloat(CreditsEventsEnum.PRICE.getValue()); // 更新积分 creditsService.buyCredits(orderInfo.getAccountId(), quantity); @@ -629,7 +629,7 @@ public class PayPalCheckoutServiceImpl implements PayPalCheckoutService { //如果订单已支付,则更新商户端订单状态 orderInfoService.updateStatusByOrderNo(orderNo, OrderStatusEnum.SUCCESS); //并记录支付日志 - paymentInfoService.createPaymentInfoForPayPal(result); + paymentInfoService.createPaymentInfoForPayPal(result, "credits"); float quantity = orderByOrderNo.getTotalFee() / Float.parseFloat(CreditsEventsEnum.PRICE.getValue()); // 更新积分 // creditsService.buyCredits(orderByOrderNo.getAccountId(),orderByOrderNo.getTotalFee() / Integer.parseInt(CreditsEventsEnum.PRICE.getValue())); diff --git a/src/main/java/com/ai/da/service/impl/PaymentInfoServiceImpl.java b/src/main/java/com/ai/da/service/impl/PaymentInfoServiceImpl.java index 2d0f3e5c..f5db3e24 100644 --- a/src/main/java/com/ai/da/service/impl/PaymentInfoServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/PaymentInfoServiceImpl.java @@ -89,7 +89,7 @@ public class PaymentInfoServiceImpl extends ServiceImpl params) { + public void createPaymentInfoForAliPay(Map params, String type) { log.info("记录支付日志"); @@ -111,6 +111,7 @@ public class PaymentInfoServiceImpl extends ServiceImpl + + + + From ef705981802711bf3760d6c6c3096ded711c796f Mon Sep 17 00:00:00 2001 From: xupei Date: Fri, 10 Jan 2025 16:13:45 +0800 Subject: [PATCH 52/91] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=9F=A5=E8=AF=A2?= =?UTF-8?q?=E4=BA=A4=E6=98=93=E8=AE=B0=E5=BD=95=E6=8E=A5=E5=8F=A3=201?= =?UTF-8?q?=E3=80=81=E6=B7=BB=E5=8A=A0=E6=8C=89id=E6=8E=92=E5=BA=8F=202?= =?UTF-8?q?=E3=80=81=E6=B7=BB=E5=8A=A0=E6=9F=A5=E8=AF=A2=E6=89=80=E6=9C=89?= =?UTF-8?q?=E5=9B=BD=E5=AE=B6=203=E3=80=81=E6=B7=BB=E5=8A=A0=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=EF=BC=8C=E6=9B=B4=E6=96=B0=E7=94=A8=E6=88=B7=E5=9B=BD?= =?UTF-8?q?=E5=AE=B6=E3=80=81=E8=81=8C=E4=B8=9A=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ai/da/controller/AccountController.java | 7 +++++++ .../ConvenientInquiryController.java | 6 ++++++ .../da/mapper/primary/PaymentInfoMapper.java | 7 ++++++- .../ai/da/model/dto/QueryPaymentInfoDTO.java | 3 ++- .../com/ai/da/service/AccountService.java | 2 ++ .../da/service/ConvenientInquiryService.java | 2 ++ .../impl/ConvenientInquiryServiceImpl.java | 21 ++++++++++++++++++- .../mapper/primary/PaymentInfoMapper.xml | 15 ++++++++++++- 8 files changed, 59 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/ai/da/controller/AccountController.java b/src/main/java/com/ai/da/controller/AccountController.java index 56b2f2f4..7a4f4d84 100644 --- a/src/main/java/com/ai/da/controller/AccountController.java +++ b/src/main/java/com/ai/da/controller/AccountController.java @@ -341,4 +341,11 @@ public class AccountController { public Response unbindGoogle() { return Response.success(accountService.unbindGoogle()); } + + @GetMapping("/updateUserInfo") + @ApiOperation(value = "更新用户国家、职业信息") + public Response updateUserInfo(@RequestParam(value = "country", required = false) String country, @RequestParam(value = "occupation", required = false) String occupation) { + accountService.updateUserInfo(country, occupation); + return Response.success(); + } } diff --git a/src/main/java/com/ai/da/controller/ConvenientInquiryController.java b/src/main/java/com/ai/da/controller/ConvenientInquiryController.java index 42f87ad2..0f8547d5 100644 --- a/src/main/java/com/ai/da/controller/ConvenientInquiryController.java +++ b/src/main/java/com/ai/da/controller/ConvenientInquiryController.java @@ -202,4 +202,10 @@ public class ConvenientInquiryController { public Response> queryTransactionRecords(@Valid @RequestBody QueryPaymentInfoDTO queryPaymentInfoDTO){ return Response.success(convenientInquiryService.queryTransactionRecords(queryPaymentInfoDTO)); } + + @ApiOperation("获取所有国家、城市") + @GetMapping("/getCities") + public Response>> getCities(){ + return Response.success(convenientInquiryService.getCities()); + } } diff --git a/src/main/java/com/ai/da/mapper/primary/PaymentInfoMapper.java b/src/main/java/com/ai/da/mapper/primary/PaymentInfoMapper.java index b0a82f21..1d2cf84d 100644 --- a/src/main/java/com/ai/da/mapper/primary/PaymentInfoMapper.java +++ b/src/main/java/com/ai/da/mapper/primary/PaymentInfoMapper.java @@ -6,6 +6,7 @@ import com.ai.da.model.vo.PaymentInfoVO; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import java.util.List; +import java.util.Map; public interface PaymentInfoMapper extends BaseMapper { @@ -15,10 +16,14 @@ public interface PaymentInfoMapper extends BaseMapper { List queryPaymentInfo(String paymentType,String payerTotal, String type, String status, String country, String city, String startTime, String endTime, - int limit, int offset + int limit, int offset, String order ); Long queryPaymentInfoCount(String paymentType,String payerTotal, String type, String status, String country, String city, String startTime, String endTime ); + + List> getCities(); + + List> getCountries(); } diff --git a/src/main/java/com/ai/da/model/dto/QueryPaymentInfoDTO.java b/src/main/java/com/ai/da/model/dto/QueryPaymentInfoDTO.java index 28f7ac06..fa61e724 100644 --- a/src/main/java/com/ai/da/model/dto/QueryPaymentInfoDTO.java +++ b/src/main/java/com/ai/da/model/dto/QueryPaymentInfoDTO.java @@ -23,5 +23,6 @@ public class QueryPaymentInfoDTO extends QueryPageByTimeDTO { private String country; @ApiModelProperty("付款人所在城市") private String city; - + @ApiModelProperty("按id排序 DESC || ASC") + private String order = "DESC"; } diff --git a/src/main/java/com/ai/da/service/AccountService.java b/src/main/java/com/ai/da/service/AccountService.java index 2374234e..770143f0 100644 --- a/src/main/java/com/ai/da/service/AccountService.java +++ b/src/main/java/com/ai/da/service/AccountService.java @@ -222,4 +222,6 @@ public interface AccountService extends IService { void updateAccountValidity(Long accountId, Long currentPeriodEnd); void updateUserRoleAndCredits(Long accountId, String type); + + void updateUserInfo(String country, String occupation); } diff --git a/src/main/java/com/ai/da/service/ConvenientInquiryService.java b/src/main/java/com/ai/da/service/ConvenientInquiryService.java index 3e71d645..bb44b6b7 100644 --- a/src/main/java/com/ai/da/service/ConvenientInquiryService.java +++ b/src/main/java/com/ai/da/service/ConvenientInquiryService.java @@ -48,4 +48,6 @@ public interface ConvenientInquiryService extends IService { List> getAllUserIdList(); PageBaseResponse queryTransactionRecords(QueryPaymentInfoDTO queryPaymentInfoDTO); + + Map> getCities(); } diff --git a/src/main/java/com/ai/da/service/impl/ConvenientInquiryServiceImpl.java b/src/main/java/com/ai/da/service/impl/ConvenientInquiryServiceImpl.java index 0bd9a40c..20b97125 100644 --- a/src/main/java/com/ai/da/service/impl/ConvenientInquiryServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/ConvenientInquiryServiceImpl.java @@ -620,11 +620,15 @@ public class ConvenientInquiryServiceImpl extends ServiceImpl queryTransactionRecords(QueryPaymentInfoDTO queryPaymentInfoDTO) { Integer size = queryPaymentInfoDTO.getSize(); int offset = (queryPaymentInfoDTO.getPage() - 1) * size; + String order = "DESC"; + if (!StringUtil.isNullOrEmpty(queryPaymentInfoDTO.getOrder()) && queryPaymentInfoDTO.getOrder().equals("ASC")) { + order = "ASC"; + } List paymentInfoVOS = paymentInfoMapper.queryPaymentInfo(queryPaymentInfoDTO.getPlatform(), queryPaymentInfoDTO.getPayerTotal(), queryPaymentInfoDTO.getType(), queryPaymentInfoDTO.getStatus(), queryPaymentInfoDTO.getCountry(), queryPaymentInfoDTO.getCity(), queryPaymentInfoDTO.getStartTime(), queryPaymentInfoDTO.getEndTime(), - size, offset); + size, offset, order); // 查询数据总量 Long total = paymentInfoMapper.queryPaymentInfoCount(queryPaymentInfoDTO.getPlatform(), queryPaymentInfoDTO.getPayerTotal(), queryPaymentInfoDTO.getType(), queryPaymentInfoDTO.getStatus(), @@ -643,5 +647,20 @@ public class ConvenientInquiryServiceImpl extends ServiceImpl> getCities(){ + List> cities = paymentInfoMapper.getCities(); + List> countries = paymentInfoMapper.getCountries(); + List cityCollect = cities.stream() + .map(cityEntry -> cityEntry.get("city")) + .collect(Collectors.toList()); + List countryCollect = countries.stream() + .map(cityEntry -> cityEntry.get("country")) + .collect(Collectors.toList()); + + return new HashMap>() {{ + put("city", cityCollect); + put("country", countryCollect); + }}; + } } diff --git a/src/main/resources/mapper/primary/PaymentInfoMapper.xml b/src/main/resources/mapper/primary/PaymentInfoMapper.xml index 1d798ac7..0343fd2a 100644 --- a/src/main/resources/mapper/primary/PaymentInfoMapper.xml +++ b/src/main/resources/mapper/primary/PaymentInfoMapper.xml @@ -91,7 +91,7 @@ AND create_time BETWEEN #{startTime} AND #{endTime} ORDER BY - id DESC + id ${order} LIMIT ${limit} OFFSET ${offset} @@ -130,5 +130,18 @@ + + + From e7aa951e89cae323d7f6ad4d9d570984118fbb24 Mon Sep 17 00:00:00 2001 From: xupei Date: Fri, 10 Jan 2025 16:19:53 +0800 Subject: [PATCH 53/91] =?UTF-8?q?=E6=BC=8F=E4=BC=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ai/da/service/impl/AccountServiceImpl.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java index 3679acfa..9197b95e 100644 --- a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java @@ -2621,4 +2621,19 @@ public class AccountServiceImpl extends ServiceImpl impl accountMapper.updateById(account); } + + public void updateUserInfo(String country, String occupation){ + Long accountId = UserContext.getUserHolder().getId(); + Account account = accountMapper.selectById(accountId); + boolean flag = false; + if (!StringUtil.isNullOrEmpty(country) && !country.equals(account.getCountry())) { + account.setCountry(country.trim()); + flag = true; + } + if (!StringUtil.isNullOrEmpty(occupation) && !occupation.equals(account.getOccupation())) { + account.setOccupation(occupation.trim()); + flag = true; + } + if(flag) accountMapper.updateById(account); + } } From cb7099264ea5c2f94af8f4901f7df91c014f1fac Mon Sep 17 00:00:00 2001 From: xupei Date: Fri, 10 Jan 2025 16:54:44 +0800 Subject: [PATCH 54/91] =?UTF-8?q?=E7=BB=91=E5=AE=9A=E9=82=AE=E7=AE=B1?= =?UTF-8?q?=E6=97=B6=E9=9C=80=E8=A6=81=E5=A1=AB=E5=86=99=E5=9B=BD=E5=AE=B6?= =?UTF-8?q?=E5=92=8C=E8=81=8C=E4=B8=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/ai/da/common/task/PaymentTask.java | 2 +- .../com/ai/da/common/utils/RequestInfoUtil.java | 2 +- .../com/ai/da/controller/AccountController.java | 4 ++-- .../java/com/ai/da/service/AccountService.java | 4 ++-- .../ai/da/service/impl/AccountServiceImpl.java | 16 +++++++++------- 5 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/ai/da/common/task/PaymentTask.java b/src/main/java/com/ai/da/common/task/PaymentTask.java index a7fe8ffb..40450055 100644 --- a/src/main/java/com/ai/da/common/task/PaymentTask.java +++ b/src/main/java/com/ai/da/common/task/PaymentTask.java @@ -102,7 +102,7 @@ public class PaymentTask { } -// @Scheduled(cron = "0 */5 * * * *") // Run every 5 minutes + @Scheduled(cron = "0 */5 * * * *") // Run every 5 minutes public void updateAffiliateInfoWithPayment(){ affiliateService.updateAffiliateInfoWithPayment(); } diff --git a/src/main/java/com/ai/da/common/utils/RequestInfoUtil.java b/src/main/java/com/ai/da/common/utils/RequestInfoUtil.java index afa6497a..d041362f 100644 --- a/src/main/java/com/ai/da/common/utils/RequestInfoUtil.java +++ b/src/main/java/com/ai/da/common/utils/RequestInfoUtil.java @@ -56,7 +56,7 @@ public class RequestInfoUtil { /** * 免费 API 服务可能有请求频率限制,如果你需要处理大量 IP 地址,可能需要考虑使用付费服务或购买 IP 地理位置数据库。此外,始终要遵守 API 提供商的使用条款和隐私政策 - * @param ip + * @param ip https://ip-api.com/docs/api:json 使用的接口api * @return * { * "query": "24.48.0.1", diff --git a/src/main/java/com/ai/da/controller/AccountController.java b/src/main/java/com/ai/da/controller/AccountController.java index 7a4f4d84..51b1c3f6 100644 --- a/src/main/java/com/ai/da/controller/AccountController.java +++ b/src/main/java/com/ai/da/controller/AccountController.java @@ -326,8 +326,8 @@ public class AccountController { @GetMapping("/bindEmail") @ApiOperation(value = "绑定邮箱") - public Response bindEmail(@RequestParam("email") String email) { - return Response.success(accountService.bindEmail(email)); + public Response bindEmail(@RequestParam("email") String email, @RequestParam("country") String country, @RequestParam("occupation") String occupation) { + return Response.success(accountService.bindEmail(email, country, occupation)); } @GetMapping("/unbindWeChat") diff --git a/src/main/java/com/ai/da/service/AccountService.java b/src/main/java/com/ai/da/service/AccountService.java index 770143f0..2e579451 100644 --- a/src/main/java/com/ai/da/service/AccountService.java +++ b/src/main/java/com/ai/da/service/AccountService.java @@ -3,7 +3,6 @@ package com.ai.da.service; import com.ai.da.common.response.PageBaseResponse; import com.ai.da.mapper.primary.entity.Account; import com.ai.da.mapper.primary.entity.AccountExtend; -import com.ai.da.mapper.primary.entity.GoogleUser; import com.ai.da.mapper.primary.entity.TrialOrder; import com.ai.da.model.dto.*; import com.ai.da.model.vo.AccountLoginVO; @@ -49,7 +48,8 @@ public interface AccountService extends IService { * @return */ Boolean bindEmail(AccountBindEmailDTO accountBindEmailDTO); - Boolean bindEmail(String email); + + Boolean bindEmail(String email, String country, String occupation); /** * 忘记密码 diff --git a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java index 9197b95e..118edb37 100644 --- a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java @@ -1263,12 +1263,12 @@ public class AccountServiceImpl extends ServiceImpl impl static { HikariConfig config = new HikariConfig(); - config.setJdbcUrl("jdbc:mysql://code-create.com.hk:3306/db1nfvsgmjp3b8"); - config.setUsername("uafqtz4gsvfrw"); - config.setPassword("aida123456."); -// config.setJdbcUrl("jdbc:mysql://localhost:3306/code-create-local?serverTimezone=UTC"); -// config.setUsername("root"); -// config.setPassword("root"); +// config.setJdbcUrl("jdbc:mysql://code-create.com.hk:3306/db1nfvsgmjp3b8"); +// config.setUsername("uafqtz4gsvfrw"); +// config.setPassword("aida123456."); + config.setJdbcUrl("jdbc:mysql://localhost:3306/code-create-local?serverTimezone=UTC"); + config.setUsername("root"); + config.setPassword("root"); config.addDataSourceProperty("cachePrepStmts", "true"); config.addDataSourceProperty("prepStmtCacheSize", "250"); config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048"); @@ -2586,10 +2586,12 @@ public class AccountServiceImpl extends ServiceImpl impl } @Override - public Boolean bindEmail(String email) { + public Boolean bindEmail(String email, String country, String occupation) { AuthPrincipalVo userHolder = UserContext.getUserHolder(); Account account = accountMapper.selectById(userHolder.getId()); account.setUserEmail(email); + account.setCountry(country); + account.setOccupation(occupation); accountMapper.updateById(account); return Boolean.TRUE; } From 931a4cf807884b668c2b304c2b98b182cfec77fd Mon Sep 17 00:00:00 2001 From: xupei Date: Fri, 10 Jan 2025 17:01:59 +0800 Subject: [PATCH 55/91] to dev --- .../com/ai/da/service/impl/AccountServiceImpl.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java index 118edb37..e4c31f14 100644 --- a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java @@ -1263,12 +1263,12 @@ public class AccountServiceImpl extends ServiceImpl impl static { HikariConfig config = new HikariConfig(); -// config.setJdbcUrl("jdbc:mysql://code-create.com.hk:3306/db1nfvsgmjp3b8"); -// config.setUsername("uafqtz4gsvfrw"); -// config.setPassword("aida123456."); - config.setJdbcUrl("jdbc:mysql://localhost:3306/code-create-local?serverTimezone=UTC"); - config.setUsername("root"); - config.setPassword("root"); + config.setJdbcUrl("jdbc:mysql://code-create.com.hk:3306/db1nfvsgmjp3b8"); + config.setUsername("uafqtz4gsvfrw"); + config.setPassword("aida123456."); +// config.setJdbcUrl("jdbc:mysql://localhost:3306/code-create-local?serverTimezone=UTC"); +// config.setUsername("root"); +// config.setPassword("root"); config.addDataSourceProperty("cachePrepStmts", "true"); config.addDataSourceProperty("prepStmtCacheSize", "250"); config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048"); From ac2454fd0efd81a29897d810b40e5a02ca3f054b Mon Sep 17 00:00:00 2001 From: xupei Date: Fri, 10 Jan 2025 17:16:08 +0800 Subject: [PATCH 56/91] =?UTF-8?q?=E7=BB=91=E5=AE=9A=E9=82=AE=E7=AE=B1?= =?UTF-8?q?=E6=97=B6=E6=B7=BB=E5=8A=A0=E5=9B=BD=E5=AE=B6=E3=80=81=E8=81=8C?= =?UTF-8?q?=E4=B8=9A=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/ai/da/controller/AccountController.java | 4 ++-- .../java/com/ai/da/model/dto/AccountBindEmailDTO.java | 9 ++++++++- src/main/java/com/ai/da/service/AccountService.java | 2 +- .../java/com/ai/da/service/impl/AccountServiceImpl.java | 6 +++--- 4 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/ai/da/controller/AccountController.java b/src/main/java/com/ai/da/controller/AccountController.java index 51b1c3f6..7a4f4d84 100644 --- a/src/main/java/com/ai/da/controller/AccountController.java +++ b/src/main/java/com/ai/da/controller/AccountController.java @@ -326,8 +326,8 @@ public class AccountController { @GetMapping("/bindEmail") @ApiOperation(value = "绑定邮箱") - public Response bindEmail(@RequestParam("email") String email, @RequestParam("country") String country, @RequestParam("occupation") String occupation) { - return Response.success(accountService.bindEmail(email, country, occupation)); + public Response bindEmail(@RequestParam("email") String email) { + return Response.success(accountService.bindEmail(email)); } @GetMapping("/unbindWeChat") diff --git a/src/main/java/com/ai/da/model/dto/AccountBindEmailDTO.java b/src/main/java/com/ai/da/model/dto/AccountBindEmailDTO.java index d0b67792..67394ebf 100644 --- a/src/main/java/com/ai/da/model/dto/AccountBindEmailDTO.java +++ b/src/main/java/com/ai/da/model/dto/AccountBindEmailDTO.java @@ -5,7 +5,6 @@ import io.swagger.annotations.ApiModelProperty; import lombok.Data; import javax.validation.constraints.NotBlank; -import javax.validation.constraints.NotNull; @Data @ApiModel("绑定邮箱") @@ -22,4 +21,12 @@ public class AccountBindEmailDTO { @NotBlank(message = "emailVerifyCode.cannot.be.empty") @ApiModelProperty("邮箱验证码") private String emailVerifyCode; + + @NotBlank(message = "country cannot be empty" ) + @ApiModelProperty("国家") + private String country; + + @NotBlank(message = "occupation cannot be empty") + @ApiModelProperty("职业") + private String occupation; } diff --git a/src/main/java/com/ai/da/service/AccountService.java b/src/main/java/com/ai/da/service/AccountService.java index 2e579451..972458a4 100644 --- a/src/main/java/com/ai/da/service/AccountService.java +++ b/src/main/java/com/ai/da/service/AccountService.java @@ -49,7 +49,7 @@ public interface AccountService extends IService { */ Boolean bindEmail(AccountBindEmailDTO accountBindEmailDTO); - Boolean bindEmail(String email, String country, String occupation); + Boolean bindEmail(String email); /** * 忘记密码 diff --git a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java index e4c31f14..58c1a93a 100644 --- a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java @@ -305,6 +305,8 @@ public class AccountServiceImpl extends ServiceImpl impl } //绑定 account.setUserEmail(accountBindEmailDTO.getUserEmail()); + account.setCountry(accountBindEmailDTO.getCountry()); + account.setOccupation(accountBindEmailDTO.getOccupation()); accountMapper.updateById(account); // updatePwdByUserId(accountBindEmailDTO.getUserEmail(), accountBindEmailDTO.getUserId()); return Boolean.TRUE; @@ -2586,12 +2588,10 @@ public class AccountServiceImpl extends ServiceImpl impl } @Override - public Boolean bindEmail(String email, String country, String occupation) { + public Boolean bindEmail(String email) { AuthPrincipalVo userHolder = UserContext.getUserHolder(); Account account = accountMapper.selectById(userHolder.getId()); account.setUserEmail(email); - account.setCountry(country); - account.setOccupation(occupation); accountMapper.updateById(account); return Boolean.TRUE; } From 501cee0057654bd9d9849179413617ed27fd3356 Mon Sep 17 00:00:00 2001 From: shahaibo <1023316923@qq.com> Date: Mon, 13 Jan 2025 10:05:38 +0800 Subject: [PATCH 57/91] =?UTF-8?q?TASK:=E5=8E=BB=E6=97=A5=E5=BF=97;?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/ai/da/service/impl/DesignServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/ai/da/service/impl/DesignServiceImpl.java b/src/main/java/com/ai/da/service/impl/DesignServiceImpl.java index 10a5d576..592df997 100644 --- a/src/main/java/com/ai/da/service/impl/DesignServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/DesignServiceImpl.java @@ -1704,7 +1704,7 @@ public class DesignServiceImpl extends ServiceImpl impleme DesignCollectionVO designCollectionVO = savePythonDesignItemAndDetailSingle(pythonObjects, designId, collectionId, userInfo, timeZone, responseJSONObject, singleOverall, context); - log.info(designContext.toString()); +// log.info(designContext.toString()); designContext.put(requestId, context); } From d2069a3e7fa7bf108f19d82c1c2ce8cf8586a8c1 Mon Sep 17 00:00:00 2001 From: shahaibo <1023316923@qq.com> Date: Mon, 13 Jan 2025 10:12:04 +0800 Subject: [PATCH 58/91] =?UTF-8?q?TASK:=E5=8E=BB=E6=97=A5=E5=BF=97;?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/ai/da/service/impl/DesignServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/ai/da/service/impl/DesignServiceImpl.java b/src/main/java/com/ai/da/service/impl/DesignServiceImpl.java index 592df997..47d19d1c 100644 --- a/src/main/java/com/ai/da/service/impl/DesignServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/DesignServiceImpl.java @@ -711,7 +711,7 @@ public class DesignServiceImpl extends ServiceImpl impleme DesignPythonObject item = new DesignPythonObject(); String objectSign = outfit.getString("objectSign"); - log.info(objectSign); +// log.info(objectSign); for (DesignPythonObject object : pythonObjects.getObjects()) { if (object.getObjectSign().equals(objectSign)) { item = object; From 07004a741503593334bbbef5bc20fcb9a4a4ebcc Mon Sep 17 00:00:00 2001 From: shahaibo <1023316923@qq.com> Date: Mon, 13 Jan 2025 10:20:14 +0800 Subject: [PATCH 59/91] =?UTF-8?q?TASK:=E5=8E=BB=E6=97=A5=E5=BF=97;?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/ai/da/service/impl/DesignServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/ai/da/service/impl/DesignServiceImpl.java b/src/main/java/com/ai/da/service/impl/DesignServiceImpl.java index 47d19d1c..c325fbb8 100644 --- a/src/main/java/com/ai/da/service/impl/DesignServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/DesignServiceImpl.java @@ -1715,7 +1715,7 @@ public class DesignServiceImpl extends ServiceImpl impleme public DesignCollectionVO getDesignResult(String requestId, List objectSignList) { // Map stringObjectMap = designContext.get("UUID.randomUUID().toString()"); Map stringObjectMap = designContext.get(requestId); - log.info(stringObjectMap.toString()); +// log.info(stringObjectMap.toString()); DesignCollectionVO result = (DesignCollectionVO) stringObjectMap.get("DesignCollectionVO"); if (Objects.isNull(result)) { DesignCollectionVO noneResult = new DesignCollectionVO(); From ab303cfeef7aa82bff941a353b0fec1ac62edacb Mon Sep 17 00:00:00 2001 From: xupei Date: Mon, 13 Jan 2025 10:55:08 +0800 Subject: [PATCH 60/91] =?UTF-8?q?=E7=BB=91=E5=AE=9A=E9=82=AE=E7=AE=B1?= =?UTF-8?q?=E6=97=B6=E6=B7=BB=E5=8A=A0=E5=9B=BD=E5=AE=B6=E3=80=81=E8=81=8C?= =?UTF-8?q?=E4=B8=9A=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/ai/da/model/dto/AccountBindEmailDTO.java | 8 -------- src/main/java/com/ai/da/model/dto/EmailSendDTO.java | 6 ++++++ .../java/com/ai/da/service/impl/AccountServiceImpl.java | 9 +++++++++ 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/ai/da/model/dto/AccountBindEmailDTO.java b/src/main/java/com/ai/da/model/dto/AccountBindEmailDTO.java index 67394ebf..b5559769 100644 --- a/src/main/java/com/ai/da/model/dto/AccountBindEmailDTO.java +++ b/src/main/java/com/ai/da/model/dto/AccountBindEmailDTO.java @@ -21,12 +21,4 @@ public class AccountBindEmailDTO { @NotBlank(message = "emailVerifyCode.cannot.be.empty") @ApiModelProperty("邮箱验证码") private String emailVerifyCode; - - @NotBlank(message = "country cannot be empty" ) - @ApiModelProperty("国家") - private String country; - - @NotBlank(message = "occupation cannot be empty") - @ApiModelProperty("职业") - private String occupation; } diff --git a/src/main/java/com/ai/da/model/dto/EmailSendDTO.java b/src/main/java/com/ai/da/model/dto/EmailSendDTO.java index eed614bb..9a111e87 100644 --- a/src/main/java/com/ai/da/model/dto/EmailSendDTO.java +++ b/src/main/java/com/ai/da/model/dto/EmailSendDTO.java @@ -21,4 +21,10 @@ public class EmailSendDTO { @ApiModelProperty("异常ip") private String ip; + @ApiModelProperty("国家") + private String country; + + @ApiModelProperty("职业") + private String occupation; + } diff --git a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java index 58c1a93a..4dc03dbf 100644 --- a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java @@ -418,6 +418,15 @@ public class AccountServiceImpl extends ServiceImpl impl } result = SendEmailUtil.send(emailSendDTO.getEmail(), null, SendEmailUtil.BIND_MAILBOX_TEMPLATE_ID, randomVerifyCode); + + if (!StringUtil.isNullOrEmpty(emailSendDTO.getCountry()) || !StringUtil.isNullOrEmpty(emailSendDTO.getOccupation())){ + Long accountId = UserContext.getUserHolder().getId(); + Account account = baseMapper.selectById(accountId); + account.setCountry(emailSendDTO.getCountry()); + account.setOccupation(emailSendDTO.getOccupation()); + baseMapper.updateById(account); + } + break; case CHANGE_MAILBOX: result = SendEmailUtil.send(emailSendDTO.getEmail(), null, From cd89a77189608f1eb590486ad07b0cb0fcff6f50 Mon Sep 17 00:00:00 2001 From: xupei Date: Mon, 13 Jan 2025 10:56:06 +0800 Subject: [PATCH 61/91] =?UTF-8?q?=E6=BC=8F=E4=BC=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/ai/da/service/impl/AccountServiceImpl.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java index 4dc03dbf..682ba6d2 100644 --- a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java @@ -305,8 +305,6 @@ public class AccountServiceImpl extends ServiceImpl impl } //绑定 account.setUserEmail(accountBindEmailDTO.getUserEmail()); - account.setCountry(accountBindEmailDTO.getCountry()); - account.setOccupation(accountBindEmailDTO.getOccupation()); accountMapper.updateById(account); // updatePwdByUserId(accountBindEmailDTO.getUserEmail(), accountBindEmailDTO.getUserId()); return Boolean.TRUE; From 51e2c9af0237851b75e7e10de95c9c599c552111 Mon Sep 17 00:00:00 2001 From: xupei Date: Mon, 13 Jan 2025 11:11:01 +0800 Subject: [PATCH 62/91] =?UTF-8?q?=E5=8F=AA=E5=A1=AB=E5=86=99=E5=9B=BD?= =?UTF-8?q?=E5=AE=B6=E5=92=8C=E8=81=8C=E4=B8=9A=EF=BC=88=E4=B8=8D=E5=8F=91?= =?UTF-8?q?=E9=80=81=E9=AA=8C=E8=AF=81=E7=A0=81=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/enums/AuthenticationOperationTypeEnum.java | 6 +++++- .../com/ai/da/service/impl/AccountServiceImpl.java | 11 ++++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/ai/da/common/enums/AuthenticationOperationTypeEnum.java b/src/main/java/com/ai/da/common/enums/AuthenticationOperationTypeEnum.java index a8300691..784edb63 100644 --- a/src/main/java/com/ai/da/common/enums/AuthenticationOperationTypeEnum.java +++ b/src/main/java/com/ai/da/common/enums/AuthenticationOperationTypeEnum.java @@ -27,7 +27,11 @@ public enum AuthenticationOperationTypeEnum { /** * 更改邮箱 */ - CHANGE_MAILBOX; + CHANGE_MAILBOX, + /** + * 填写用户国家和职业 + */ + UPDATE_USERINFO; public static AuthenticationOperationTypeEnum of(String name) { return Stream.of(AuthenticationOperationTypeEnum.values()).filter(v -> v.name().equals(name)).findFirst().orElse(null); diff --git a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java index 682ba6d2..1bf8ec30 100644 --- a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java @@ -424,12 +424,21 @@ public class AccountServiceImpl extends ServiceImpl impl account.setOccupation(emailSendDTO.getOccupation()); baseMapper.updateById(account); } - break; case CHANGE_MAILBOX: result = SendEmailUtil.send(emailSendDTO.getEmail(), null, SendEmailUtil.CHANGE_MAILBOX_TEMPLATE_ID, randomVerifyCode); break; + case UPDATE_USERINFO: + if (!StringUtil.isNullOrEmpty(emailSendDTO.getCountry()) || !StringUtil.isNullOrEmpty(emailSendDTO.getOccupation())){ + Long accountId = UserContext.getUserHolder().getId(); + Account account = baseMapper.selectById(accountId); + account.setCountry(emailSendDTO.getCountry()); + account.setOccupation(emailSendDTO.getOccupation()); + baseMapper.updateById(account); + result = true; + } + break; default: } if (!result) { From 74f89c8b2dc460415e5388c78f3fa38380b84f86 Mon Sep 17 00:00:00 2001 From: xupei Date: Mon, 13 Jan 2025 11:15:31 +0800 Subject: [PATCH 63/91] =?UTF-8?q?=E5=8F=AA=E5=A1=AB=E5=86=99=E5=9B=BD?= =?UTF-8?q?=E5=AE=B6=E5=92=8C=E8=81=8C=E4=B8=9A=EF=BC=88=E4=B8=8D=E5=8F=91?= =?UTF-8?q?=E9=80=81=E9=AA=8C=E8=AF=81=E7=A0=81=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/ai/da/model/dto/EmailSendDTO.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/ai/da/model/dto/EmailSendDTO.java b/src/main/java/com/ai/da/model/dto/EmailSendDTO.java index 9a111e87..946946bd 100644 --- a/src/main/java/com/ai/da/model/dto/EmailSendDTO.java +++ b/src/main/java/com/ai/da/model/dto/EmailSendDTO.java @@ -15,7 +15,8 @@ public class EmailSendDTO { private String email; @NotBlank(message = "operationType.cannot.be.empty") - @ApiModelProperty("操作类型 LOGIN 注册 FORGET_PWD 忘记密码 BIND_MAILBOX 绑定邮箱 CHANGE_MAILBOX 更改邮箱") + @ApiModelProperty("操作类型 LOGIN 注册 FORGET_PWD 忘记密码 BIND_MAILBOX 绑定邮箱 " + + "CHANGE_MAILBOX 更改邮箱 UPDATE_USERINFO 仅填写国家、职业(不发送邮件)") private String operationType; @ApiModelProperty("异常ip") From 845a553097290cd2c77e021804de9f572c14bf9d Mon Sep 17 00:00:00 2001 From: shahaibo <1023316923@qq.com> Date: Mon, 13 Jan 2025 14:11:03 +0800 Subject: [PATCH 64/91] =?UTF-8?q?BUGFIX:=E5=BE=AE=E4=BF=A1=E5=90=8D?= =?UTF-8?q?=E8=A7=A3=E6=9E=90=E3=80=81toproductimage=20=E6=89=93=E5=85=89?= =?UTF-8?q?=E7=A7=AF=E5=88=86=E4=B8=8D=E8=B6=B3code=E7=A0=81=E4=BF=AE?= =?UTF-8?q?=E6=94=B9;?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../da/service/impl/AccountServiceImpl.java | 21 +++++++++++++++++++ .../impl/UserLikeGroupServiceImpl.java | 5 +++-- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java index 1bf8ec30..889d969f 100644 --- a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java @@ -49,6 +49,7 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import javax.sql.DataSource; import java.math.BigDecimal; +import java.nio.charset.StandardCharsets; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; @@ -2405,6 +2406,15 @@ public class AccountServiceImpl extends ServiceImpl impl RestTemplate restTemplate = new RestTemplate(); String response = restTemplate.getForObject(url, String.class); + // 强制校正编码为 UTF-8(如果返回的是 ISO-8859-1 编码) + if (!isUTF8(response)) { // 检查编码方法,下面会提供 + byte[] bytes = response.getBytes(StandardCharsets.ISO_8859_1); + response = new String(bytes, StandardCharsets.UTF_8); + } + + // 打印调试信息 + log.info("WeChat user info response: {}", response); + // 转换为 JSON 对象 JSONObject jsonResponse = JSONObject.parseObject(response); if (jsonResponse.containsKey("errcode")) { @@ -2414,6 +2424,17 @@ public class AccountServiceImpl extends ServiceImpl impl return jsonResponse; } + private boolean isUTF8(String text) { + try { + byte[] bytes = text.getBytes(StandardCharsets.ISO_8859_1); + String decoded = new String(bytes, StandardCharsets.UTF_8); + return decoded.equals(text); + } catch (Exception e) { + return false; + } + } + + private JSONObject getAccessTokenFromWeChat(String code) { // 构造微信接口请求 URL String url = String.format( diff --git a/src/main/java/com/ai/da/service/impl/UserLikeGroupServiceImpl.java b/src/main/java/com/ai/da/service/impl/UserLikeGroupServiceImpl.java index 87ced60b..ee988979 100644 --- a/src/main/java/com/ai/da/service/impl/UserLikeGroupServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/UserLikeGroupServiceImpl.java @@ -5,6 +5,7 @@ import com.ai.da.common.config.exception.BusinessException; import com.ai.da.common.constant.CommonConstant; import com.ai.da.common.context.UserContext; import com.ai.da.common.enums.CreditsEventsEnum; +import com.ai.da.common.response.ResultEnum; import com.ai.da.common.utils.*; import com.ai.da.mapper.primary.*; import com.ai.da.mapper.primary.entity.*; @@ -274,7 +275,7 @@ public class UserLikeGroupServiceImpl extends ServiceImpl Date: Mon, 13 Jan 2025 15:12:54 +0800 Subject: [PATCH 65/91] =?UTF-8?q?BUGFIX:toproductimage=20=E6=89=93?= =?UTF-8?q?=E5=85=89=E7=A7=AF=E5=88=86=E4=B8=8D=E8=B6=B3=E6=8F=90=E7=A4=BA?= =?UTF-8?q?=E4=BF=AE=E6=94=B9;?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/ai/da/service/impl/UserLikeGroupServiceImpl.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/ai/da/service/impl/UserLikeGroupServiceImpl.java b/src/main/java/com/ai/da/service/impl/UserLikeGroupServiceImpl.java index ee988979..1b7698eb 100644 --- a/src/main/java/com/ai/da/service/impl/UserLikeGroupServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/UserLikeGroupServiceImpl.java @@ -275,7 +275,7 @@ public class UserLikeGroupServiceImpl extends ServiceImpl Date: Wed, 15 Jan 2025 10:45:51 +0800 Subject: [PATCH 66/91] =?UTF-8?q?=E6=9F=A5=E8=AF=A2=E4=BA=A4=E6=98=93?= =?UTF-8?q?=E8=AE=B0=E5=BD=95=20=E6=B7=BB=E5=8A=A0=E4=BB=98=E6=AC=BE?= =?UTF-8?q?=E4=BA=BA=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../da/controller/DesignDetailController.java | 3 - .../da/mapper/primary/PaymentInfoMapper.java | 4 +- .../ai/da/model/dto/QueryPaymentInfoDTO.java | 2 + .../com/ai/da/model/vo/PaymentInfoVO.java | 2 + .../impl/ConvenientInquiryServiceImpl.java | 4 +- .../mapper/primary/PaymentInfoMapper.xml | 79 +++++++++++-------- 6 files changed, 56 insertions(+), 38 deletions(-) diff --git a/src/main/java/com/ai/da/controller/DesignDetailController.java b/src/main/java/com/ai/da/controller/DesignDetailController.java index 994b0b2c..a02e0835 100644 --- a/src/main/java/com/ai/da/controller/DesignDetailController.java +++ b/src/main/java/com/ai/da/controller/DesignDetailController.java @@ -5,7 +5,6 @@ import com.ai.da.model.dto.*; import com.ai.da.model.vo.*; import com.ai.da.service.DesignItemService; import com.ai.da.service.DesignService; -import com.ai.da.service.UserLikeService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; @@ -15,8 +14,6 @@ import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import javax.validation.Valid; import java.io.IOException; -import java.util.List; -import java.util.Map; @Api(tags = "design Detail模块") diff --git a/src/main/java/com/ai/da/mapper/primary/PaymentInfoMapper.java b/src/main/java/com/ai/da/mapper/primary/PaymentInfoMapper.java index 1d2cf84d..c6721dd1 100644 --- a/src/main/java/com/ai/da/mapper/primary/PaymentInfoMapper.java +++ b/src/main/java/com/ai/da/mapper/primary/PaymentInfoMapper.java @@ -16,11 +16,11 @@ public interface PaymentInfoMapper extends BaseMapper { List queryPaymentInfo(String paymentType,String payerTotal, String type, String status, String country, String city, String startTime, String endTime, - int limit, int offset, String order + int limit, int offset, String order, String payer ); Long queryPaymentInfoCount(String paymentType,String payerTotal, String type, String status, - String country, String city, String startTime, String endTime + String country, String city, String startTime, String endTime, String payer ); List> getCities(); diff --git a/src/main/java/com/ai/da/model/dto/QueryPaymentInfoDTO.java b/src/main/java/com/ai/da/model/dto/QueryPaymentInfoDTO.java index fa61e724..6aa95e9a 100644 --- a/src/main/java/com/ai/da/model/dto/QueryPaymentInfoDTO.java +++ b/src/main/java/com/ai/da/model/dto/QueryPaymentInfoDTO.java @@ -25,4 +25,6 @@ public class QueryPaymentInfoDTO extends QueryPageByTimeDTO { private String city; @ApiModelProperty("按id排序 DESC || ASC") private String order = "DESC"; + @ApiModelProperty("付款用户名") + private String payer; } diff --git a/src/main/java/com/ai/da/model/vo/PaymentInfoVO.java b/src/main/java/com/ai/da/model/vo/PaymentInfoVO.java index 34ddbf79..caa1955c 100644 --- a/src/main/java/com/ai/da/model/vo/PaymentInfoVO.java +++ b/src/main/java/com/ai/da/model/vo/PaymentInfoVO.java @@ -11,6 +11,8 @@ import lombok.NoArgsConstructor; @ApiModel("交易记录详情") public class PaymentInfoVO { private Long id; + @ApiModelProperty("付款用户名") + private String payer; @ApiModelProperty("选择的支付平台 PayPal || Stripe || Alipay-HK") private String platform; @ApiModelProperty("支付的金额 单位:HKD") diff --git a/src/main/java/com/ai/da/service/impl/ConvenientInquiryServiceImpl.java b/src/main/java/com/ai/da/service/impl/ConvenientInquiryServiceImpl.java index 20b97125..e0d6d978 100644 --- a/src/main/java/com/ai/da/service/impl/ConvenientInquiryServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/ConvenientInquiryServiceImpl.java @@ -628,12 +628,12 @@ public class ConvenientInquiryServiceImpl extends ServiceImpl SELECT - id, - payment_type platform, - payer_total, - type, - payment_method, - last4, - country, - city, - create_time, + p.id, + a.user_name payer, + p.payment_type platform, + p.payer_total, + p.type, + p.payment_method, + p.last4, + p.country, + p.city, + p.create_time, CASE - WHEN trade_state IN ('paid', 'COMPLETED', 'complete', 'liquidated') THEN 'Success' - WHEN trade_state IN ('failed', 'expired', 'VOIDED', 'void', 'uncollectible') THEN 'Fail' - ELSE 'Pending' + + 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 AS status FROM - t_payment_info + 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 - AND payment_type = #{paymentType} + AND p.payment_type = #{paymentType} - AND payer_total = #{payerTotal} + AND p.payer_total = #{payerTotal} - AND type = #{type} + AND p.type = #{type} AND CASE - WHEN trade_state IN ('paid', 'COMPLETED', 'complete', 'liquidated') THEN 'Success' - WHEN trade_state IN ('failed', 'expired', 'VOIDED', 'void', 'uncollectible') THEN 'Fail' + 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} - AND country = #{country} + AND p.country = #{country} - AND city = #{city} + AND p.city = #{city} - AND create_time BETWEEN #{startTime} AND #{endTime} + AND p.create_time BETWEEN #{startTime} AND #{endTime} + + + AND a.user_name = #{payer} ORDER BY - id ${order} + p.id ${order} LIMIT ${limit} OFFSET ${offset} @@ -99,34 +109,41 @@ SELECT COUNT(*) FROM - t_payment_info + 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 - AND payment_type = #{paymentType} + AND p.payment_type = #{paymentType} - AND payer_total = #{payerTotal} + AND p.payer_total = #{payerTotal} - AND type = #{type} + AND p.type = #{type} AND CASE - WHEN trade_state IN ('paid', 'COMPLETED', 'complete', 'liquidated') THEN 'Success' - WHEN trade_state IN ('failed', 'expired', 'VOIDED', 'void', 'uncollectible') THEN 'Fail' + 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} - AND country = #{country} + AND p.country = #{country} - AND city = #{city} + AND p.city = #{city} - AND create_time BETWEEN #{startTime} AND #{endTime} + AND p.create_time BETWEEN #{startTime} AND #{endTime} + + + AND a.user_name = #{payer} From bb7c98c0941fc95c81c12dbc247c8f2ede809639 Mon Sep 17 00:00:00 2001 From: xupei Date: Wed, 22 Jan 2025 15:32:09 +0800 Subject: [PATCH 67/91] =?UTF-8?q?affiliate=20=E4=BD=A3=E9=87=91=E8=AE=A1?= =?UTF-8?q?=E7=AE=97=E7=BB=9F=E8=AE=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/ai/da/common/task/PaymentTask.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/ai/da/common/task/PaymentTask.java b/src/main/java/com/ai/da/common/task/PaymentTask.java index 40450055..e01213f5 100644 --- a/src/main/java/com/ai/da/common/task/PaymentTask.java +++ b/src/main/java/com/ai/da/common/task/PaymentTask.java @@ -104,6 +104,7 @@ public class PaymentTask { @Scheduled(cron = "0 */5 * * * *") // Run every 5 minutes public void updateAffiliateInfoWithPayment(){ + log.info("佣金计算定时器"); affiliateService.updateAffiliateInfoWithPayment(); } From c4c04aecb6669ab695ce266edcd4b66afc2b9140 Mon Sep 17 00:00:00 2001 From: xupei Date: Wed, 22 Jan 2025 16:37:40 +0800 Subject: [PATCH 68/91] =?UTF-8?q?affiliateIncome=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E5=AD=97=E6=AE=B5paymentInfoId?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/ai/da/mapper/primary/entity/AffiliateIncome.java | 2 ++ src/main/java/com/ai/da/service/impl/AffiliateServiceImpl.java | 1 + 2 files changed, 3 insertions(+) diff --git a/src/main/java/com/ai/da/mapper/primary/entity/AffiliateIncome.java b/src/main/java/com/ai/da/mapper/primary/entity/AffiliateIncome.java index eb8ce12c..d2d276c4 100644 --- a/src/main/java/com/ai/da/mapper/primary/entity/AffiliateIncome.java +++ b/src/main/java/com/ai/da/mapper/primary/entity/AffiliateIncome.java @@ -19,6 +19,8 @@ public class AffiliateIncome extends BaseEntity { private Float amount; + private Long paymentInfoId; + private LocalDateTime paymentTime; private Float commission; diff --git a/src/main/java/com/ai/da/service/impl/AffiliateServiceImpl.java b/src/main/java/com/ai/da/service/impl/AffiliateServiceImpl.java index 97b464a7..9ae4d6ad 100644 --- a/src/main/java/com/ai/da/service/impl/AffiliateServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/AffiliateServiceImpl.java @@ -233,6 +233,7 @@ public class AffiliateServiceImpl extends ServiceImpl Date: Wed, 22 Jan 2025 16:41:40 +0800 Subject: [PATCH 69/91] =?UTF-8?q?=E4=BD=A3=E9=87=91=E8=AE=A1=E7=AE=97=20?= =?UTF-8?q?=E6=89=93=E5=8D=B0=E6=97=A5=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/ai/da/common/task/PaymentTask.java | 2 +- src/main/java/com/ai/da/service/impl/AffiliateServiceImpl.java | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/ai/da/common/task/PaymentTask.java b/src/main/java/com/ai/da/common/task/PaymentTask.java index e01213f5..f926e6f3 100644 --- a/src/main/java/com/ai/da/common/task/PaymentTask.java +++ b/src/main/java/com/ai/da/common/task/PaymentTask.java @@ -104,7 +104,7 @@ public class PaymentTask { @Scheduled(cron = "0 */5 * * * *") // Run every 5 minutes public void updateAffiliateInfoWithPayment(){ - log.info("佣金计算定时器"); +// log.info("佣金计算定时器"); affiliateService.updateAffiliateInfoWithPayment(); } diff --git a/src/main/java/com/ai/da/service/impl/AffiliateServiceImpl.java b/src/main/java/com/ai/da/service/impl/AffiliateServiceImpl.java index 9ae4d6ad..f8533c6a 100644 --- a/src/main/java/com/ai/da/service/impl/AffiliateServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/AffiliateServiceImpl.java @@ -209,6 +209,7 @@ public class AffiliateServiceImpl extends ServiceImpl Date: Thu, 23 Jan 2025 13:55:48 +0800 Subject: [PATCH 70/91] =?UTF-8?q?=E4=BC=98=E5=8C=96=E8=AF=B7=E6=B1=82?= =?UTF-8?q?=E6=9C=AA=E6=90=BA=E5=B8=A6token=E6=97=B6=E7=9A=84=E6=97=A5?= =?UTF-8?q?=E5=BF=97=E6=89=93=E5=8D=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/ai/da/common/enums/CreditsEventsEnum.java | 8 ++++---- src/main/java/com/ai/da/common/enums/ProductEnum.java | 2 +- .../da/common/security/filter/AuthenticationFilter.java | 4 +++- src/main/resources/mapper/primary/PaymentInfoMapper.xml | 2 ++ 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/ai/da/common/enums/CreditsEventsEnum.java b/src/main/java/com/ai/da/common/enums/CreditsEventsEnum.java index 3d4c50fa..e8565984 100644 --- a/src/main/java/com/ai/da/common/enums/CreditsEventsEnum.java +++ b/src/main/java/com/ai/da/common/enums/CreditsEventsEnum.java @@ -7,12 +7,12 @@ import lombok.Getter; @Getter public enum CreditsEventsEnum { -// PRICE("price","6"), - PRICE("price","1"),// for test + PRICE("price","6"), +// PRICE("price","1"),// for test // PRICE("price","0.1"), -// BUY_CREDITS("Buy Credits","60"), - BUY_CREDITS("Buy Credits","10"),// for test + BUY_CREDITS("Buy Credits","60"), +// BUY_CREDITS("Buy Credits","10"),// for test REFUND("Refund","60"), // BUY_CREDITS("Buy Credits","10"), diff --git a/src/main/java/com/ai/da/common/enums/ProductEnum.java b/src/main/java/com/ai/da/common/enums/ProductEnum.java index 4a859b9c..11237ffe 100644 --- a/src/main/java/com/ai/da/common/enums/ProductEnum.java +++ b/src/main/java/com/ai/da/common/enums/ProductEnum.java @@ -7,7 +7,7 @@ import lombok.Getter; @AllArgsConstructor public enum ProductEnum { // 积分购买 - CreditsProduct("AiDA credits purchase", 1L), + CreditsProduct("AiDA credits purchase", 6L), // 年度订阅 AnnualSubscription("AiDA Annual Subscription", 5000L), // 月度订阅 diff --git a/src/main/java/com/ai/da/common/security/filter/AuthenticationFilter.java b/src/main/java/com/ai/da/common/security/filter/AuthenticationFilter.java index 54dbf3a6..e26b267f 100644 --- a/src/main/java/com/ai/da/common/security/filter/AuthenticationFilter.java +++ b/src/main/java/com/ai/da/common/security/filter/AuthenticationFilter.java @@ -1,6 +1,7 @@ package com.ai.da.common.security.filter; import cn.hutool.core.util.StrUtil; +import com.ai.da.common.config.exception.MissingTokenException; import com.ai.da.common.context.UserContext; import com.ai.da.common.security.config.SecurityProperties; import com.ai.da.common.security.jwt.JWTTokenHelper; @@ -101,7 +102,8 @@ public class AuthenticationFilter extends OncePerRequestFilter { if (StrUtil.isBlank(jwtToken)) { String ipAddress = RequestInfoUtil.getIpAddress(request); log.info("本次请求的ip为 : " + ipAddress); - throw new RuntimeException("请传入token!"); +// throw new RuntimeException("请传入token!"); + throw new MissingTokenException("请传入token!"); } if(jwtToken.equals("Bearer-eyJhbGciOiJIUzUxMiJ9.eyJqdGkiOiIyIiwic3ViIjoie1wiaWRcIjoyLFwidXNlcm5hbWVcIjpcImxpcnNcIn0iLCJpYXQiOjE2NjU3NDEwODcsImlzcyI6IkRXSiIsImF1dGhvcml0aWVzIjoiW10iLCJleHAiOjE2NzQzODEwODd9.ShM9R_NNFD7oo1OvxrEgg7PFeWinOuAKkuInUCMQupp66s64Hhv8tN0Wwr83nIN4rHPqtn95wmd4msWcvaFYJA")){ //写死 暂时放行 diff --git a/src/main/resources/mapper/primary/PaymentInfoMapper.xml b/src/main/resources/mapper/primary/PaymentInfoMapper.xml index b5868c94..29a82d72 100644 --- a/src/main/resources/mapper/primary/PaymentInfoMapper.xml +++ b/src/main/resources/mapper/primary/PaymentInfoMapper.xml @@ -100,6 +100,7 @@ AND a.user_name = #{payer} + AND p.transaction_id NOT LIKE 'cs_test%' ORDER BY p.id ${order} LIMIT ${limit} OFFSET ${offset} @@ -145,6 +146,7 @@ AND a.user_name = #{payer} + AND p.transaction_id NOT LIKE 'cs_test%' update t_account - set is_trial = 0, credits = 0, system_user = 0, update_date = #{date} + set is_trial = 0, credits = 0, system_user = 0 where id = #{id} From cf76235123d78c14ee3fc7c2dca7eb424bf99a1f Mon Sep 17 00:00:00 2001 From: shahaibo <1023316923@qq.com> Date: Wed, 5 Feb 2025 12:04:53 +0800 Subject: [PATCH 88/91] =?UTF-8?q?TASK:=E8=B0=B7=E6=AD=8C=E5=BE=AE=E4=BF=A1?= =?UTF-8?q?=E5=BF=AB=E6=8D=B7=E5=8C=BA=E5=88=86=E7=99=BB=E5=BD=95=E6=B3=A8?= =?UTF-8?q?=E5=86=8C;?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../da/controller/ThirdPartyController.java | 8 +- .../com/ai/da/service/AccountService.java | 4 +- .../da/service/impl/AccountServiceImpl.java | 180 ++++++++++-------- 3 files changed, 110 insertions(+), 82 deletions(-) diff --git a/src/main/java/com/ai/da/controller/ThirdPartyController.java b/src/main/java/com/ai/da/controller/ThirdPartyController.java index c0ff893f..72454016 100644 --- a/src/main/java/com/ai/da/controller/ThirdPartyController.java +++ b/src/main/java/com/ai/da/controller/ThirdPartyController.java @@ -130,14 +130,14 @@ public class ThirdPartyController { } @CrossOrigin @GetMapping("/parseGoogleCredential") - public Response parseGoogleCredential(@RequestParam("credential") String credential) { - return Response.success(accountService.parseGoogleCredential(credential)); + public Response parseGoogleCredential(@RequestParam("credential") String credential, @RequestParam("type") Integer type) { + return Response.success(accountService.parseGoogleCredential(credential, type)); } @CrossOrigin @GetMapping("/parseWeChatCode") - public Response parseWeChatCode(@RequestParam("code") String code) { - return Response.success(accountService.parseWeChatCode(code)); + public Response parseWeChatCode(@RequestParam("code") String code, @RequestParam("type") Integer type) { + return Response.success(accountService.parseWeChatCode(code, type)); } @ApiOperation(value = "接收Design结果") diff --git a/src/main/java/com/ai/da/service/AccountService.java b/src/main/java/com/ai/da/service/AccountService.java index e8a2324b..270d2d66 100644 --- a/src/main/java/com/ai/da/service/AccountService.java +++ b/src/main/java/com/ai/da/service/AccountService.java @@ -206,9 +206,9 @@ public interface AccountService extends IService { Account accountDetail(Long id); - AccountLoginVO parseGoogleCredential(String credential); + AccountLoginVO parseGoogleCredential(String credential, Integer type); - AccountLoginVO parseWeChatCode(String code); + AccountLoginVO parseWeChatCode(String code, Integer type); AccountLoginVO getAccountDetail(); diff --git a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java index b3fc9c35..3917722c 100644 --- a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java @@ -2235,7 +2235,7 @@ public class AccountServiceImpl extends ServiceImpl impl } @Override - public AccountLoginVO parseGoogleCredential(String credential) { + public AccountLoginVO parseGoogleCredential(String credential, Integer type) { try { // 配置 Google ID Token 验证器 GoogleIdTokenVerifier verifier = new GoogleIdTokenVerifier.Builder( @@ -2259,52 +2259,67 @@ public class AccountServiceImpl extends ServiceImpl impl log.info(userId); log.info(email); log.info(name); - - // 检查数据库中是否已有该用户 - QueryWrapper queryWrapper = new QueryWrapper<>(); - queryWrapper.lambda().eq(AccountExtend::getAuth, userId); // 根据邮箱查询用户 - List accountExtends = accountExtendMapper.selectList(queryWrapper); Account account = new Account(); - if (CollectionUtil.isNotEmpty(accountExtends)) { - Long accountId = accountExtends.get(0).getAccountId(); - account = accountMapper.selectById(accountId); - } else { - - AccountExtend accountExtendInsert = new AccountExtend(); - accountExtendInsert.setAuth(userId); - accountExtendInsert.setAuthType("Google"); - accountExtendInsert.setHeadImgUrl(pictureUrl); - accountExtendInsert.setName(name); - - QueryWrapper accountQueryWrapper = new QueryWrapper<>(); - accountQueryWrapper.lambda().eq(Account::getUserEmail, email); // 根据邮箱查询用户 - List accounts = accountMapper.selectList(accountQueryWrapper); - - // 用户不存在,创建新用户(自动注册) - Account newUser = new Account(); - if (CollectionUtil.isNotEmpty(accounts)) { - newUser = CopyUtil.copyObject(accounts.get(0), Account.class); + if (type == 1) { + // 注册 + QueryWrapper accountExtendQW = new QueryWrapper<>(); + accountExtendQW.lambda().eq(AccountExtend::getAuthType, "Google"); + accountExtendQW.lambda().eq(AccountExtend::getAuth, userId); + List accountExtends = accountExtendMapper.selectList(accountExtendQW); + if (CollectionUtil.isNotEmpty(accountExtends)) { + throw new BusinessException("This Google account has been registered for AiDA, please use Google Quick Login directly."); }else { - newUser.setUserEmail(email); - newUser.setUserName(name); - newUser.setUserPassword("Third-000000"); - newUser.setLanguage(Language.ENGLISH.name()); - newUser.setValidStartTime(System.currentTimeMillis()); - newUser.setValidEndTime(toDayEnd(Instant.now().plus(5, ChronoUnit.DAYS).toEpochMilli())); - newUser.setCreateDate(new Date()); - newUser.setIsTrial(1); - newUser.setIsBeginner(1); - newUser.setCredits(BigDecimal.valueOf(100)); - newUser.setSystemUser(3); - accountMapper.insert(newUser); + QueryWrapper accountQueryWrapper = new QueryWrapper<>(); + accountQueryWrapper.lambda().eq(Account::getUserEmail, email); // 根据邮箱查询用户 + List accounts = accountMapper.selectList(accountQueryWrapper); + if (CollectionUtil.isNotEmpty(accounts)) { + account = accounts.get(0); + AccountExtend accountExtendInsert = new AccountExtend(); + accountExtendInsert.setAuth(userId); + accountExtendInsert.setAuthType("Google"); + accountExtendInsert.setHeadImgUrl(pictureUrl); + accountExtendInsert.setName(name); + accountExtendInsert.setAccountId(account.getId()); + accountExtendMapper.insert(accountExtendInsert); + }else { + Account newUser = new Account(); + newUser.setUserEmail(email); + newUser.setUserName(name); + newUser.setUserPassword("Third-000000"); + newUser.setLanguage(Language.ENGLISH.name()); + newUser.setValidStartTime(System.currentTimeMillis()); + newUser.setValidEndTime(toDayEnd(Instant.now().plus(5, ChronoUnit.DAYS).toEpochMilli())); + newUser.setCreateDate(new Date()); + newUser.setIsTrial(1); + newUser.setIsBeginner(1); + newUser.setCredits(BigDecimal.valueOf(100)); + newUser.setSystemUser(3); + accountMapper.insert(newUser); + + account = newUser; + + AccountExtend accountExtendInsert = new AccountExtend(); + accountExtendInsert.setAuth(userId); + accountExtendInsert.setAuthType("Google"); + accountExtendInsert.setHeadImgUrl(pictureUrl); + accountExtendInsert.setName(name); + accountExtendInsert.setAccountId(newUser.getId()); + accountExtendMapper.insert(accountExtendInsert); + } + } + }else { + // 登录 + QueryWrapper accountExtendQW = new QueryWrapper<>(); + accountExtendQW.lambda().eq(AccountExtend::getAuthType, "Google"); + accountExtendQW.lambda().eq(AccountExtend::getAuth, userId); + List accountExtends = accountExtendMapper.selectList(accountExtendQW); + if (CollectionUtil.isNotEmpty(accountExtends)) { + AccountExtend accountExtend = accountExtends.get(0); + account = accountMapper.selectById(accountExtend.getAccountId()); + }else { + throw new BusinessException("This Google account has not been bound to an AiDA account yet. Please register an AiDA account and bind it to a Google account, or bind the Google account to an existing AiDA account."); } - - accountExtendInsert.setAccountId(newUser.getId()); - accountExtendMapper.insert(accountExtendInsert); - - account = newUser; } - AccountLoginVO response = CopyUtil.copyObject(account, AccountLoginVO.class); response.setEmail(account.getUserEmail()); String token = LocalCacheUtils.getTokenCache(String.valueOf(account.getId())); @@ -2344,7 +2359,7 @@ public class AccountServiceImpl extends ServiceImpl impl private static final String APP_SECRET = "e5592c691756455b2d03ebfd21fc3131"; @Override - public AccountLoginVO parseWeChatCode(String code) { + public AccountLoginVO parseWeChatCode(String code, Integer type) { // 1. 获取 access_token 和 openid JSONObject accessTokenResponse = getAccessTokenFromWeChat(code); String accessToken = accessTokenResponse.getString("access_token"); @@ -2361,45 +2376,58 @@ public class AccountServiceImpl extends ServiceImpl impl String unionId = userInfoResponse.getString("unionid"); String userName = userInfoResponse.getString("nickname"); String headimgurl = userInfoResponse.getString("headimgurl"); + if (unionId == null) { throw new IllegalArgumentException("无法获取 unionid,请检查微信开发平台配置"); } - - // 检查数据库中是否已有该unionid - QueryWrapper queryWrapper = new QueryWrapper<>(); - queryWrapper.lambda().eq(AccountExtend::getAuthType, "WeChat"); - queryWrapper.lambda().eq(AccountExtend::getAuth, unionId); - List accountExtends = accountExtendMapper.selectList(queryWrapper); Account account = new Account(); - if (CollectionUtil.isEmpty(accountExtends)) { - AccountExtend accountExtendInsert = new AccountExtend(); - accountExtendInsert.setAuth(unionId); - accountExtendInsert.setAuthType("WeChat"); - accountExtendInsert.setHeadImgUrl(headimgurl); - accountExtendInsert.setName(userName); + if (type == 1) { + // 注册 + // 检查数据库中是否已有该unionid + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.lambda().eq(AccountExtend::getAuthType, "WeChat"); + queryWrapper.lambda().eq(AccountExtend::getAuth, unionId); + List accountExtends = accountExtendMapper.selectList(queryWrapper); + if (CollectionUtil.isNotEmpty(accountExtends)) { + throw new BusinessException("This Wechat account has been registered for AiDA, please use Wechat Quick Login directly."); + }else { + // 创建新用户(自动注册) + Account newUser = new Account(); + newUser.setUserName(userName); + newUser.setUserPassword("Third-000000"); + newUser.setLanguage(Language.ENGLISH.name()); + newUser.setValidStartTime(System.currentTimeMillis()); + newUser.setValidEndTime(toDayEnd(Instant.now().plus(5, ChronoUnit.DAYS).toEpochMilli())); + newUser.setCreateDate(new Date()); + newUser.setIsTrial(1); + newUser.setIsBeginner(1); + newUser.setCredits(BigDecimal.valueOf(100)); + newUser.setSystemUser(3); + accountMapper.insert(newUser); - // 用户不存在,创建新用户(自动注册) - Account newUser = new Account(); -// newUser.setUserEmail(email); - newUser.setUserName(userName); - newUser.setUserPassword("Third-000000"); - newUser.setLanguage(Language.ENGLISH.name()); - newUser.setValidStartTime(System.currentTimeMillis()); - newUser.setValidEndTime(toDayEnd(Instant.now().plus(5, ChronoUnit.DAYS).toEpochMilli())); - newUser.setCreateDate(new Date()); - newUser.setIsTrial(1); - newUser.setIsBeginner(1); - newUser.setCredits(BigDecimal.valueOf(100)); - newUser.setSystemUser(3); - accountMapper.insert(newUser); + AccountExtend accountExtendInsert = new AccountExtend(); + accountExtendInsert.setAuth(unionId); + accountExtendInsert.setAuthType("WeChat"); + accountExtendInsert.setHeadImgUrl(headimgurl); + accountExtendInsert.setName(userName); + accountExtendInsert.setAccountId(newUser.getId()); + accountExtendMapper.insert(accountExtendInsert); - accountExtendInsert.setAccountId(newUser.getId()); - accountExtendMapper.insert(accountExtendInsert); - - account = newUser; + account = newUser; + } }else { - AccountExtend accountExtend = accountExtends.get(0); - account = accountMapper.selectById(accountExtend.getAccountId()); + // 登录 + // 检查数据库中是否已有该unionid + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.lambda().eq(AccountExtend::getAuthType, "WeChat"); + queryWrapper.lambda().eq(AccountExtend::getAuth, unionId); + List accountExtends = accountExtendMapper.selectList(queryWrapper); + if (CollectionUtil.isNotEmpty(accountExtends)) { + AccountExtend accountExtend = accountExtends.get(0); + account = accountMapper.selectById(accountExtend.getAccountId()); + }else { + throw new BusinessException("This WeChat account has not been bound to an AiDA account yet. Please register an AiDA account and bind it to the WeChat account, or bind the WeChat account to an existing AiDA account."); + } } AccountLoginVO response = CopyUtil.copyObject(account, AccountLoginVO.class); From 627f264ef312ae70df5d9d8d5545479e7dcbc0dc Mon Sep 17 00:00:00 2001 From: shahaibo <1023316923@qq.com> Date: Wed, 5 Feb 2025 13:02:26 +0800 Subject: [PATCH 89/91] =?UTF-8?q?BUGFIX:=E7=BB=91=E5=AE=9A=E8=B0=B7?= =?UTF-8?q?=E6=AD=8C;?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../da/service/impl/AccountServiceImpl.java | 83 ++++++++++--------- 1 file changed, 43 insertions(+), 40 deletions(-) diff --git a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java index 0130bf11..986fe901 100644 --- a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java @@ -48,8 +48,10 @@ import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import javax.sql.DataSource; +import java.io.IOException; import java.math.BigDecimal; import java.nio.charset.StandardCharsets; +import java.security.GeneralSecurityException; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; @@ -2572,54 +2574,55 @@ public class AccountServiceImpl extends ServiceImpl impl @Override public AccountExtend bindGoogle(String credential) { + // 配置 Google ID Token 验证器 + GoogleIdTokenVerifier verifier = new GoogleIdTokenVerifier.Builder( + new NetHttpTransport(), + JacksonFactory.getDefaultInstance()) + .setAudience(Collections.singletonList(CLIENT_ID)) + .build(); + + // 验证并解析 ID Token + GoogleIdToken idToken = null; try { - // 配置 Google ID Token 验证器 - GoogleIdTokenVerifier verifier = new GoogleIdTokenVerifier.Builder( - new NetHttpTransport(), - JacksonFactory.getDefaultInstance()) - .setAudience(Collections.singletonList(CLIENT_ID)) - .build(); - - // 验证并解析 ID Token - GoogleIdToken idToken = verifier.verify(credential); + idToken = verifier.verify(credential); + } catch (GeneralSecurityException e) { + throw new RuntimeException(e); + } catch (IOException e) { + throw new RuntimeException(e); + } - if (idToken != null) { - GoogleIdToken.Payload payload = idToken.getPayload(); + if (idToken != null) { + GoogleIdToken.Payload payload = idToken.getPayload(); - // 提取用户信息 - String userId = payload.getSubject(); - String email = payload.getEmail(); - String name = (String) payload.get("name"); - String pictureUrl = (String) payload.get("picture"); + // 提取用户信息 + String userId = payload.getSubject(); + String email = payload.getEmail(); + String name = (String) payload.get("name"); + String pictureUrl = (String) payload.get("picture"); - QueryWrapper qw = new QueryWrapper<>(); - qw.lambda().eq(AccountExtend::getAuth, userId); - qw.lambda().eq(AccountExtend::getAuthType, "Google"); - List accountExtends = accountExtendMapper.selectList(qw); + QueryWrapper qw = new QueryWrapper<>(); + qw.lambda().eq(AccountExtend::getAuth, userId); + qw.lambda().eq(AccountExtend::getAuthType, "Google"); + List accountExtends = accountExtendMapper.selectList(qw); - if (CollectionUtil.isNotEmpty(accountExtends)) { - throw new BusinessException("The Google has been bound."); - } - - AccountExtend accountExtendInsert = new AccountExtend(); - accountExtendInsert.setAuth(userId); - accountExtendInsert.setAuthType("Google"); - accountExtendInsert.setHeadImgUrl(pictureUrl); - accountExtendInsert.setName(name); - - AuthPrincipalVo authPrincipalVo = UserContext.getUserHolder(); - accountExtendInsert.setAccountId(authPrincipalVo.getId()); - accountExtendMapper.insert(accountExtendInsert); - - return accountExtendInsert; - } else { - throw new IllegalArgumentException("Invalid ID token."); + if (CollectionUtil.isNotEmpty(accountExtends)) { + throw new BusinessException("The Google has been bound."); } - } catch (Exception e) { - e.printStackTrace(); - throw new RuntimeException("Failed to verify ID token: " + e.getMessage()); + AccountExtend accountExtendInsert = new AccountExtend(); + accountExtendInsert.setAuth(userId); + accountExtendInsert.setAuthType("Google"); + accountExtendInsert.setHeadImgUrl(pictureUrl); + accountExtendInsert.setName(name); + + AuthPrincipalVo authPrincipalVo = UserContext.getUserHolder(); + accountExtendInsert.setAccountId(authPrincipalVo.getId()); + accountExtendMapper.insert(accountExtendInsert); + + return accountExtendInsert; + } else { + throw new IllegalArgumentException("Invalid ID token."); } } From 9e5d2f47e2bad08fa8f3413f33db9edb2aefeb11 Mon Sep 17 00:00:00 2001 From: shahaibo <1023316923@qq.com> Date: Wed, 5 Feb 2025 13:38:10 +0800 Subject: [PATCH 90/91] =?UTF-8?q?BUGFIX:=E7=BB=91=E5=AE=9A=E8=B0=B7?= =?UTF-8?q?=E6=AD=8C;?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../da/service/impl/AccountServiceImpl.java | 205 +++++++++--------- 1 file changed, 103 insertions(+), 102 deletions(-) diff --git a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java index 986fe901..c20ad942 100644 --- a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java @@ -2240,119 +2240,120 @@ public class AccountServiceImpl extends ServiceImpl impl @Override public AccountLoginVO parseGoogleCredential(String credential, Integer type) { + // 配置 Google ID Token 验证器 + GoogleIdTokenVerifier verifier = new GoogleIdTokenVerifier.Builder( + new NetHttpTransport(), + JacksonFactory.getDefaultInstance()) + .setAudience(Collections.singletonList(CLIENT_ID)) + .build(); + + // 验证并解析 ID Token + GoogleIdToken idToken = null; try { - // 配置 Google ID Token 验证器 - GoogleIdTokenVerifier verifier = new GoogleIdTokenVerifier.Builder( - new NetHttpTransport(), - JacksonFactory.getDefaultInstance()) - .setAudience(Collections.singletonList(CLIENT_ID)) - .build(); - - // 验证并解析 ID Token - GoogleIdToken idToken = verifier.verify(credential); + idToken = verifier.verify(credential); + } catch (GeneralSecurityException e) { + throw new RuntimeException(e); + } catch (IOException e) { + throw new RuntimeException(e); + } - if (idToken != null) { - GoogleIdToken.Payload payload = idToken.getPayload(); + if (idToken != null) { + GoogleIdToken.Payload payload = idToken.getPayload(); - // 提取用户信息 - String userId = payload.getSubject(); - String email = payload.getEmail(); - String name = (String) payload.get("name"); - String pictureUrl = (String) payload.get("picture"); - log.info(userId); - log.info(email); - log.info(name); - Account account = new Account(); - if (type == 1) { - // 注册 - QueryWrapper accountExtendQW = new QueryWrapper<>(); - accountExtendQW.lambda().eq(AccountExtend::getAuthType, "Google"); - accountExtendQW.lambda().eq(AccountExtend::getAuth, userId); - List accountExtends = accountExtendMapper.selectList(accountExtendQW); - if (CollectionUtil.isNotEmpty(accountExtends)) { - throw new BusinessException("This Google account has been registered for AiDA, please use Google Quick Login directly."); - }else { - QueryWrapper accountQueryWrapper = new QueryWrapper<>(); - accountQueryWrapper.lambda().eq(Account::getUserEmail, email); // 根据邮箱查询用户 - List accounts = accountMapper.selectList(accountQueryWrapper); - if (CollectionUtil.isNotEmpty(accounts)) { - account = accounts.get(0); - AccountExtend accountExtendInsert = new AccountExtend(); - accountExtendInsert.setAuth(userId); - accountExtendInsert.setAuthType("Google"); - accountExtendInsert.setHeadImgUrl(pictureUrl); - accountExtendInsert.setName(name); - accountExtendInsert.setAccountId(account.getId()); - accountExtendMapper.insert(accountExtendInsert); - }else { - Account newUser = new Account(); - newUser.setUserEmail(email); - newUser.setUserName(name); - newUser.setUserPassword("Third-000000"); - newUser.setLanguage(Language.ENGLISH.name()); - newUser.setValidStartTime(System.currentTimeMillis()); - newUser.setValidEndTime(toDayEnd(Instant.now().plus(5, ChronoUnit.DAYS).toEpochMilli())); - newUser.setCreateDate(new Date()); - newUser.setIsTrial(1); - newUser.setIsBeginner(1); - newUser.setCredits(BigDecimal.valueOf(100)); - newUser.setSystemUser(3); - accountMapper.insert(newUser); - - account = newUser; - - AccountExtend accountExtendInsert = new AccountExtend(); - accountExtendInsert.setAuth(userId); - accountExtendInsert.setAuthType("Google"); - accountExtendInsert.setHeadImgUrl(pictureUrl); - accountExtendInsert.setName(name); - accountExtendInsert.setAccountId(newUser.getId()); - accountExtendMapper.insert(accountExtendInsert); - } - } + // 提取用户信息 + String userId = payload.getSubject(); + String email = payload.getEmail(); + String name = (String) payload.get("name"); + String pictureUrl = (String) payload.get("picture"); + log.info(userId); + log.info(email); + log.info(name); + Account account = new Account(); + if (type == 1) { + // 注册 + QueryWrapper accountExtendQW = new QueryWrapper<>(); + accountExtendQW.lambda().eq(AccountExtend::getAuthType, "Google"); + accountExtendQW.lambda().eq(AccountExtend::getAuth, userId); + List accountExtends = accountExtendMapper.selectList(accountExtendQW); + if (CollectionUtil.isNotEmpty(accountExtends)) { + throw new BusinessException("This Google account has been registered for AiDA, please use Google Quick Login directly."); }else { - // 登录 - QueryWrapper accountExtendQW = new QueryWrapper<>(); - accountExtendQW.lambda().eq(AccountExtend::getAuthType, "Google"); - accountExtendQW.lambda().eq(AccountExtend::getAuth, userId); - List accountExtends = accountExtendMapper.selectList(accountExtendQW); - if (CollectionUtil.isNotEmpty(accountExtends)) { - AccountExtend accountExtend = accountExtends.get(0); - account = accountMapper.selectById(accountExtend.getAccountId()); + QueryWrapper accountQueryWrapper = new QueryWrapper<>(); + accountQueryWrapper.lambda().eq(Account::getUserEmail, email); // 根据邮箱查询用户 + List accounts = accountMapper.selectList(accountQueryWrapper); + if (CollectionUtil.isNotEmpty(accounts)) { + account = accounts.get(0); + AccountExtend accountExtendInsert = new AccountExtend(); + accountExtendInsert.setAuth(userId); + accountExtendInsert.setAuthType("Google"); + accountExtendInsert.setHeadImgUrl(pictureUrl); + accountExtendInsert.setName(name); + accountExtendInsert.setAccountId(account.getId()); + accountExtendMapper.insert(accountExtendInsert); }else { - throw new BusinessException("This Google account has not been bound to an AiDA account yet. Please register an AiDA account and bind it to a Google account, or bind the Google account to an existing AiDA account."); + Account newUser = new Account(); + newUser.setUserEmail(email); + newUser.setUserName(name); + newUser.setUserPassword("Third-000000"); + newUser.setLanguage(Language.ENGLISH.name()); + newUser.setValidStartTime(System.currentTimeMillis()); + newUser.setValidEndTime(toDayEnd(Instant.now().plus(5, ChronoUnit.DAYS).toEpochMilli())); + newUser.setCreateDate(new Date()); + newUser.setIsTrial(1); + newUser.setIsBeginner(1); + newUser.setCredits(BigDecimal.valueOf(100)); + newUser.setSystemUser(3); + accountMapper.insert(newUser); + + account = newUser; + + AccountExtend accountExtendInsert = new AccountExtend(); + accountExtendInsert.setAuth(userId); + accountExtendInsert.setAuthType("Google"); + accountExtendInsert.setHeadImgUrl(pictureUrl); + accountExtendInsert.setName(name); + accountExtendInsert.setAccountId(newUser.getId()); + accountExtendMapper.insert(accountExtendInsert); } } - AccountLoginVO response = CopyUtil.copyObject(account, AccountLoginVO.class); - response.setEmail(account.getUserEmail()); - String token = LocalCacheUtils.getTokenCache(String.valueOf(account.getId())); - if (StringUtils.isNotBlank(token)) { - //用户已登入 - response.setToken(token); - } else { - response.setToken(createAccountToken(account)); - } - response.setUserId(account.getId()); - response.setSystemUser(account.getSystemUser()); - // 设置头像 - String avatar; - if (StringUtil.isNullOrEmpty(account.getAvatar())){ - avatar = CommonConstant.DEFAULT_AVATAR; + }else { + // 登录 + QueryWrapper accountExtendQW = new QueryWrapper<>(); + accountExtendQW.lambda().eq(AccountExtend::getAuthType, "Google"); + accountExtendQW.lambda().eq(AccountExtend::getAuth, userId); + List accountExtends = accountExtendMapper.selectList(accountExtendQW); + if (CollectionUtil.isNotEmpty(accountExtends)) { + AccountExtend accountExtend = accountExtends.get(0); + account = accountMapper.selectById(accountExtend.getAccountId()); }else { - avatar = account.getAvatar(); + throw new BusinessException("This Google account has not been bound to an AiDA account yet. Please register an AiDA account and bind it to a Google account, or bind the Google account to an existing AiDA account."); } - response.setAvatar(minioUtil.getPreSignedUrl(avatar, CommonConstant.MINIO_IMAGE_EXPIRE_TIME)); - response.setFolloweeCount(portfolioService.getFolloweeCount(account.getId())); - response.setFollowerCount(portfolioService.getFollowerCount(account.getId())); - return response; - } else { - throw new IllegalArgumentException("Invalid ID token."); } - - } catch (Exception e) { - e.printStackTrace(); - throw new RuntimeException("Failed to verify ID token: " + e.getMessage()); + AccountLoginVO response = CopyUtil.copyObject(account, AccountLoginVO.class); + response.setEmail(account.getUserEmail()); + String token = LocalCacheUtils.getTokenCache(String.valueOf(account.getId())); + if (StringUtils.isNotBlank(token)) { + //用户已登入 + response.setToken(token); + } else { + response.setToken(createAccountToken(account)); + } + response.setUserId(account.getId()); + response.setSystemUser(account.getSystemUser()); + // 设置头像 + String avatar; + if (StringUtil.isNullOrEmpty(account.getAvatar())){ + avatar = CommonConstant.DEFAULT_AVATAR; + }else { + avatar = account.getAvatar(); + } + response.setAvatar(minioUtil.getPreSignedUrl(avatar, CommonConstant.MINIO_IMAGE_EXPIRE_TIME)); + response.setFolloweeCount(portfolioService.getFolloweeCount(account.getId())); + response.setFollowerCount(portfolioService.getFollowerCount(account.getId())); + return response; + } else { + throw new IllegalArgumentException("Invalid ID token."); } } From 6f52c956ecf9b5dcb702547afa9e70541ee9ab74 Mon Sep 17 00:00:00 2001 From: shahaibo <1023316923@qq.com> Date: Wed, 5 Feb 2025 14:20:22 +0800 Subject: [PATCH 91/91] =?UTF-8?q?TASK:=E6=96=B0=E7=9A=84=E8=AF=95=E7=94=A8?= =?UTF-8?q?=E8=AE=A2=E5=8D=95=E7=94=9F=E6=88=90;?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/ai/da/controller/AccountController.java | 4 ++-- src/main/java/com/ai/da/service/AccountService.java | 2 +- .../com/ai/da/service/impl/AccountServiceImpl.java | 11 ++++++++++- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/ai/da/controller/AccountController.java b/src/main/java/com/ai/da/controller/AccountController.java index a4431794..de8dc770 100644 --- a/src/main/java/com/ai/da/controller/AccountController.java +++ b/src/main/java/com/ai/da/controller/AccountController.java @@ -51,8 +51,8 @@ public class AccountController { @ApiOperation(value = "绑定邮箱") @PostMapping("/bindEmail") - public Response bindEmail(@Valid @RequestBody AccountBindEmailDTO accountBindEmailDTO) { - return Response.success(accountService.bindEmail(accountBindEmailDTO)); + public Response bindEmail(@Valid @RequestBody AccountBindEmailDTO accountBindEmailDTO, HttpServletRequest request) { + return Response.success(accountService.bindEmail(accountBindEmailDTO, request)); } @ApiOperation(value = "忘记密码") diff --git a/src/main/java/com/ai/da/service/AccountService.java b/src/main/java/com/ai/da/service/AccountService.java index 270d2d66..531c3fc7 100644 --- a/src/main/java/com/ai/da/service/AccountService.java +++ b/src/main/java/com/ai/da/service/AccountService.java @@ -48,7 +48,7 @@ public interface AccountService extends IService { * @param accountBindEmailDTO * @return */ - BindEmailVO bindEmail(AccountBindEmailDTO accountBindEmailDTO); + BindEmailVO bindEmail(AccountBindEmailDTO accountBindEmailDTO, HttpServletRequest request); BindEmailVO bindEmail(String email); diff --git a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java index c20ad942..3bbb1785 100644 --- a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java @@ -288,7 +288,7 @@ public class AccountServiceImpl extends ServiceImpl impl } @Override - public BindEmailVO bindEmail(AccountBindEmailDTO accountBindEmailDTO) { + public BindEmailVO bindEmail(AccountBindEmailDTO accountBindEmailDTO, HttpServletRequest request) { AuthPrincipalVo userHolder = UserContext.getUserHolder(); Account account = accountMapper.selectById(userHolder.getId()); @@ -335,6 +335,15 @@ public class AccountServiceImpl extends ServiceImpl impl Account accountNew = accountMapper.selectById(userHolder.getId()); accountNew.setUserEmail(accountBindEmailDTO.getUserEmail()); accountMapper.updateById(accountNew); + + TrialOrder trialOrder = CopyUtil.copyObject(accountNew, TrialOrder.class); + trialOrder.setCreateTime(LocalDateTime.now()); + trialOrder.setStatus(1); + // 获取用户申请试用IP + String ipAddress = RequestInfoUtil.getIpAddress(request); + trialOrder.setIp(ipAddress); + trialOrderMapper.insert(trialOrder); + return result; }