From e84d800ba01665a7162f83a1000f024c06851b4e Mon Sep 17 00:00:00 2001 From: xupei Date: Wed, 6 Mar 2024 20:56:22 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8A=A0=E5=85=A5=E7=A7=AF=E5=88=86=E7=B3=BB?= =?UTF-8?q?=E7=BB=9F=EF=BC=8C=E5=B0=86=E5=85=85=E5=80=BC=E4=B8=8E=E7=A7=AF?= =?UTF-8?q?=E5=88=86=E5=85=B3=E8=81=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ai/da/common/enums/CreditsEventsEnum.java | 30 ++++++ .../ai/da/controller/AliPayController.java | 6 +- .../ai/da/controller/CreditsController.java | 28 ++++++ .../controller/PayPalCheckoutController.java | 8 +- .../ai/da/mapper/primary/entity/Account.java | 6 ++ .../com/ai/da/service/AccountService.java | 2 + .../java/com/ai/da/service/AliPayService.java | 2 +- .../com/ai/da/service/CreditsService.java | 16 ++++ .../com/ai/da/service/OrderInfoService.java | 2 +- .../ai/da/service/PayPalCheckoutService.java | 2 +- .../da/service/impl/AccountServiceImpl.java | 8 ++ .../ai/da/service/impl/AliPayServiceImpl.java | 29 ++++-- .../da/service/impl/CreditsServiceImpl.java | 91 +++++++++++++++++++ .../da/service/impl/OrderInfoServiceImpl.java | 18 ++-- .../impl/PayPalCheckoutServiceImpl.java | 18 ++-- src/main/resources/application-dev.properties | 2 +- 16 files changed, 234 insertions(+), 34 deletions(-) create mode 100644 src/main/java/com/ai/da/common/enums/CreditsEventsEnum.java create mode 100644 src/main/java/com/ai/da/controller/CreditsController.java create mode 100644 src/main/java/com/ai/da/service/CreditsService.java create mode 100644 src/main/java/com/ai/da/service/impl/CreditsServiceImpl.java diff --git a/src/main/java/com/ai/da/common/enums/CreditsEventsEnum.java b/src/main/java/com/ai/da/common/enums/CreditsEventsEnum.java new file mode 100644 index 00000000..015698db --- /dev/null +++ b/src/main/java/com/ai/da/common/enums/CreditsEventsEnum.java @@ -0,0 +1,30 @@ +package com.ai.da.common.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@AllArgsConstructor +@Getter +public enum CreditsEventsEnum { + + PRICE("price","2"), + + INIT("init", "1000"), + + DAILY_CHECKIN("Daily Check-In", "50"), + + SOCIAL_MEDIA_SHARING("Social Media Sharing","50"), + + BUY_CREDITS("Buy Credits","2000"), + + SUPER_RESOLUTION("Super Resolution","300"), + + OTHER("Other","10"); + + private String name; + + /** + * 对应事件需要消耗or获得的积分 + */ + private String value; +} diff --git a/src/main/java/com/ai/da/controller/AliPayController.java b/src/main/java/com/ai/da/controller/AliPayController.java index 3878628a..468b154b 100644 --- a/src/main/java/com/ai/da/controller/AliPayController.java +++ b/src/main/java/com/ai/da/controller/AliPayController.java @@ -21,12 +21,12 @@ public class AliPayController { private AliPayService aliPayService; @ApiOperation("统一收单下单并支付页面接口的调用") - @PostMapping("/trade/page/pay/{productId}") - public Response tradePagePay(@PathVariable Long productId,@RequestParam String returnUrl){ + @PostMapping("/trade/page/pay/{amount}") + public Response tradePagePay(@PathVariable Integer amount, @RequestParam String returnUrl){ log.info("统一收单下单并支付页面接口的调用"); //支付宝开放平台接受 request 请求对象后 // 会为开发者生成一个html 形式的 form表单,包含自动提交的脚本 - String formStr = aliPayService.tradeCreate(productId, returnUrl); + String formStr = aliPayService.tradeCreate(amount, returnUrl); //我们将form表单字符串返回给前端程序,之后前端将会调用自动提交脚本,进行表单的提交 //此时,表单会自动提交到action属性所指向的支付宝开放平台中,从而为用户展示一个支付页面 return Response.success(formStr); diff --git a/src/main/java/com/ai/da/controller/CreditsController.java b/src/main/java/com/ai/da/controller/CreditsController.java new file mode 100644 index 00000000..fe240ea4 --- /dev/null +++ b/src/main/java/com/ai/da/controller/CreditsController.java @@ -0,0 +1,28 @@ +package com.ai.da.controller; + +import com.ai.da.common.response.Response; +import com.ai.da.service.CreditsService; +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; + +@CrossOrigin +@RestController +@RequestMapping("/api/credits") +@Api(tags = "积分") +@Slf4j +public class CreditsController { + + @Resource + private CreditsService creditsService; + + @ApiOperation("获取积分") + @GetMapping("/getCredits") + public Response getCredits(){ + String credits = creditsService.getCredits(); + return Response.success(credits); + } +} diff --git a/src/main/java/com/ai/da/controller/PayPalCheckoutController.java b/src/main/java/com/ai/da/controller/PayPalCheckoutController.java index 0e141e67..1877f098 100644 --- a/src/main/java/com/ai/da/controller/PayPalCheckoutController.java +++ b/src/main/java/com/ai/da/controller/PayPalCheckoutController.java @@ -30,9 +30,9 @@ public class PayPalCheckoutController { private CallBackService callBackService; @ApiOperation(value = "创建订单") - @PostMapping(value = "/trade/{productId}") - public Response> createOrder(@PathVariable Long productId,@RequestParam String returnUrl) throws SerializeException { - HashMap approvalUrl = payPalCheckoutService.createOrder(productId,returnUrl); + @PostMapping(value = "/trade/{amount}") + public Response> createOrder(@PathVariable Integer amount, @RequestParam String returnUrl) throws SerializeException { + HashMap approvalUrl = payPalCheckoutService.createOrder(amount,returnUrl); return Response.success(approvalUrl); } @@ -41,7 +41,7 @@ public class PayPalCheckoutController { public Response callback(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { Boolean result = callBackService.doGet(request, response); if (result){ - return Response.success(); + return Response.success(200,"success"); }else { return Response.fail(500,"failure"); } 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 bca34dec..ad574fe7 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 @@ -8,6 +8,7 @@ import lombok.EqualsAndHashCode; import lombok.experimental.Accessors; import java.io.Serializable; +import java.math.BigDecimal; import java.util.Date; /** @@ -80,4 +81,9 @@ public class Account implements Serializable { private Integer isBeginner; private String browserIdentifiers; + + /** + * 积分 + */ + private BigDecimal credits; } diff --git a/src/main/java/com/ai/da/service/AccountService.java b/src/main/java/com/ai/da/service/AccountService.java index c00d2a4c..5b00ba5b 100644 --- a/src/main/java/com/ai/da/service/AccountService.java +++ b/src/main/java/com/ai/da/service/AccountService.java @@ -128,4 +128,6 @@ public interface AccountService extends IService { void upgradeNotification(); void moveLibraryDate(); + + void updateCredits(Long accountId, String value); } diff --git a/src/main/java/com/ai/da/service/AliPayService.java b/src/main/java/com/ai/da/service/AliPayService.java index fbfc86df..66dd334d 100644 --- a/src/main/java/com/ai/da/service/AliPayService.java +++ b/src/main/java/com/ai/da/service/AliPayService.java @@ -3,7 +3,7 @@ package com.ai.da.service; import java.util.Map; public interface AliPayService { - String tradeCreate(Long productId,String returnUrl); + String tradeCreate(Integer amount,String returnUrl); String tradeNotify(Map params); diff --git a/src/main/java/com/ai/da/service/CreditsService.java b/src/main/java/com/ai/da/service/CreditsService.java new file mode 100644 index 00000000..64e9f917 --- /dev/null +++ b/src/main/java/com/ai/da/service/CreditsService.java @@ -0,0 +1,16 @@ +package com.ai.da.service; + +public interface CreditsService { + + void initCredits(); + + Boolean buyCredits(Long accountId, Integer quantity); + + void creditsIncrease(Long accountId, String event); + + void creditsDecrease(Long accountId, String event); + + String getCredits(); + + void creditsRefund(Long accountId, Integer quantity); +} diff --git a/src/main/java/com/ai/da/service/OrderInfoService.java b/src/main/java/com/ai/da/service/OrderInfoService.java index 4f4dff38..31e1d99c 100644 --- a/src/main/java/com/ai/da/service/OrderInfoService.java +++ b/src/main/java/com/ai/da/service/OrderInfoService.java @@ -9,7 +9,7 @@ import java.util.List; public interface OrderInfoService extends IService { - OrderInfo createOrderByProductId(Long productId, String paymentType); + OrderInfo createOrderByProductId(Integer productId, String paymentType); 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 8a79b489..8b5d2347 100644 --- a/src/main/java/com/ai/da/service/PayPalCheckoutService.java +++ b/src/main/java/com/ai/da/service/PayPalCheckoutService.java @@ -9,7 +9,7 @@ import java.util.Map; public interface PayPalCheckoutService { - HashMap createOrder(Long productId,String returnUrl) throws SerializeException; + HashMap createOrder(Integer amount,String returnUrl) throws SerializeException; /** * 回调 * @param map 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 38495eab..6baba970 100644 --- a/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/AccountServiceImpl.java @@ -36,6 +36,7 @@ import org.springframework.util.Assert; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; +import java.math.BigDecimal; import java.time.Instant; import java.time.LocalDateTime; import java.time.temporal.ChronoUnit; @@ -885,4 +886,11 @@ public class AccountServiceImpl extends ServiceImpl impl // 未迁移过的进行迁移,注意模特数据迁移打点信息以及转换模特格式 } + + public void updateCredits(Long accountId, String value){ + Account account = new Account(); + account.setId(accountId); + account.setCredits(new BigDecimal(value)); + accountMapper.updateById(account); + } } 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 1b2dc62d..bcc1213f 100644 --- a/src/main/java/com/ai/da/service/impl/AliPayServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/AliPayServiceImpl.java @@ -2,14 +2,12 @@ package com.ai.da.service.impl; import com.ai.da.common.config.exception.BusinessException; 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.mapper.primary.entity.OrderInfo; import com.ai.da.mapper.primary.entity.RefundInfo; -import com.ai.da.service.AliPayService; -import com.ai.da.service.OrderInfoService; -import com.ai.da.service.PaymentInfoService; -import com.ai.da.service.RefundInfoService; +import com.ai.da.service.*; import com.alibaba.fastjson.JSONObject; import com.alipay.api.AlipayApiException; import com.alipay.api.AlipayClient; @@ -49,16 +47,19 @@ public class AliPayServiceImpl implements AliPayService { @Resource private RefundInfoService refundsInfoService; + @Resource + private CreditsService creditsService; + private final ReentrantLock lock = new ReentrantLock(); @Transactional(rollbackFor = Exception.class) @Override - public String tradeCreate(Long productId, String returnUrl) { + public String tradeCreate(Integer amount, String returnUrl) { try { //生成订单 log.info("生成订单"); - OrderInfo orderInfo = orderInfoService.createOrderByProductId(productId, PayTypeEnum.ALIPAY.getType()); + OrderInfo orderInfo = orderInfoService.createOrderByProductId(amount, PayTypeEnum.ALIPAY.getType()); //调用支付宝接口 AlipayTradePagePayRequest request = new AlipayTradePagePayRequest(); @@ -74,7 +75,8 @@ public class AliPayServiceImpl implements AliPayService { bizContent.put("out_trade_no", orderInfo.getOrderNo()); BigDecimal total = new BigDecimal(orderInfo.getTotalFee().toString()); bizContent.put("total_amount", total); - bizContent.put("subject", orderInfo.getTitle()); +// bizContent.put("subject", orderInfo.getTitle()); + bizContent.put("subject", "积分购买"); bizContent.put("product_code", "FAST_INSTANT_TRADE_PAY"); request.setBizContent(bizContent.toString()); @@ -186,6 +188,7 @@ public class AliPayServiceImpl implements AliPayService { //获取订单号 String orderNo = params.get("out_trade_no"); + String totalAmount = params.get("total_amount"); /*在对业务数据进行状态检查和处理之前, 要采用数据锁进行并发控制, @@ -196,7 +199,9 @@ public class AliPayServiceImpl implements AliPayService { try { //处理重复通知 //接口调用的幂等性:无论接口被调用多少次,以下业务执行一次 - String orderStatus = orderInfoService.getOrderStatus(orderNo); +// String orderStatus = orderInfoService.getOrderStatus(orderNo); + OrderInfo orderByOrderNo = orderInfoService.getOrderByOrderNo(orderNo); + String orderStatus = orderByOrderNo.getOrderStatus(); // 当订单状态处于未支付或超时已关闭时,更新订单状态 if (!OrderStatusEnum.NOT_PAY.getType().equals(orderStatus) || !OrderStatusEnum.TIMEOUT_CLOSED.getType().equals(orderStatus)) { return; @@ -205,6 +210,8 @@ public class AliPayServiceImpl implements AliPayService { orderInfoService.updateStatusByOrderNo(orderNo, OrderStatusEnum.SUCCESS); //记录支付日志 paymentInfoService.createPaymentInfoForAliPay(params); + // 更新积分 + creditsService.buyCredits(orderByOrderNo.getAccountId(),Integer.parseInt(totalAmount) / Integer.parseInt(CreditsEventsEnum.PRICE.getValue())); } finally { //要主动释放锁 lock.unlock(); @@ -285,6 +292,7 @@ public class AliPayServiceImpl implements AliPayService { LinkedTreeMap alipayTradeQueryResponse = resultMap.get("alipay_trade_query_response"); String tradeStatus = (String)alipayTradeQueryResponse.get("trade_status"); + OrderInfo orderByOrderNo = orderInfoService.getOrderByOrderNo(orderNo); if(AliPayTradeStateEnum.NOTPAY.getType().equals(tradeStatus)){ log.warn("核实订单未支付 ===> {}", orderNo); //如果订单未支付,则调用关单接口关闭订单 @@ -299,6 +307,8 @@ public class AliPayServiceImpl implements AliPayService { orderInfoService.updateStatusByOrderNo(orderNo, OrderStatusEnum.SUCCESS); //并记录支付日志 paymentInfoService.createPaymentInfoForAliPay(alipayTradeQueryResponse); + // 更新积分 + creditsService.buyCredits(orderByOrderNo.getAccountId(),orderByOrderNo.getTotalFee() / Integer.parseInt(CreditsEventsEnum.PRICE.getValue())); } } @@ -368,6 +378,9 @@ public class AliPayServiceImpl implements AliPayService { refundInfo.getRefundNo(), response.getBody(), AliPayTradeStateEnum.REFUND_SUCCESS.getType()); //退款成功 + // 更新积分状态 + OrderInfo orderByOrderNo = orderInfoService.getOrderByOrderNo(orderNo); + creditsService.creditsRefund(orderByOrderNo.getAccountId(), orderByOrderNo.getTotalFee() / Integer.parseInt(CreditsEventsEnum.PRICE.getValue())); } else { log.info("调用失败,返回码 ===> " + response.getCode() + ", 返回描述 ===> " + response.getMsg()); diff --git a/src/main/java/com/ai/da/service/impl/CreditsServiceImpl.java b/src/main/java/com/ai/da/service/impl/CreditsServiceImpl.java new file mode 100644 index 00000000..9c5ac128 --- /dev/null +++ b/src/main/java/com/ai/da/service/impl/CreditsServiceImpl.java @@ -0,0 +1,91 @@ +package com.ai.da.service.impl; + +import com.ai.da.common.config.exception.BusinessException; +import com.ai.da.common.context.UserContext; +import com.ai.da.common.enums.CreditsEventsEnum; +import com.ai.da.mapper.primary.AccountMapper; +import com.ai.da.mapper.primary.entity.Account; +import com.ai.da.service.AccountService; +import com.ai.da.service.CreditsService; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.math.BigDecimal; + +@Service +public class CreditsServiceImpl implements CreditsService { + + @Resource + private AccountService accountService; + + @Resource + private AccountMapper accountMapper; + + @Override + public void initCredits() { + accountService.updateCredits(UserContext.getUserHolder().getId(), CreditsEventsEnum.INIT.getValue()); + } + + @Override + public Boolean buyCredits(Long accountId, Integer quantity) { + BigDecimal existingCredits = accountMapper.selectById(accountId).getCredits(); + BigDecimal newCredits = new BigDecimal(CreditsEventsEnum.BUY_CREDITS.getValue()).multiply(new BigDecimal(quantity)); + BigDecimal added = existingCredits.add(newCredits); + accountService.updateCredits(accountId, added.toString()); + return Boolean.TRUE; + } + + @Override + public void creditsIncrease(Long accountId, String creditsEvent) { + CreditsEventsEnum event = null; + + switch (creditsEvent){ + case "Daily Check-In": + event = CreditsEventsEnum.DAILY_CHECKIN; + break; + case "Social Media Sharing": + event = CreditsEventsEnum.SOCIAL_MEDIA_SHARING; + break; + case "Other": + event = CreditsEventsEnum.OTHER; + break; + default: + throw new BusinessException("UNKNOWN TYPE"); + } + BigDecimal existingCredits = accountMapper.selectById(UserContext.getUserHolder().getId()).getCredits(); + BigDecimal add = new BigDecimal(event.getValue()).add(existingCredits); + accountService.updateCredits(UserContext.getUserHolder().getId(), add.toString()); + } + + @Override + public void creditsDecrease(Long accountId, String creditsEvent) { + CreditsEventsEnum event = null; + + switch (creditsEvent){ + case "Super Resolution": + event = CreditsEventsEnum.DAILY_CHECKIN; + break; + case "Other": + event = CreditsEventsEnum.OTHER; + break; + default: + throw new BusinessException("UNKNOWN TYPE"); + } + BigDecimal existingCredits = accountMapper.selectById(UserContext.getUserHolder().getId()).getCredits(); + BigDecimal subtract = existingCredits.subtract(new BigDecimal(event.getValue())); + accountService.updateCredits(UserContext.getUserHolder().getId(), subtract.toString()); + } + + @Override + public String getCredits() { + Account account = accountMapper.selectById(UserContext.getUserHolder().getId()); + return account.getCredits().toString(); + } + + public void creditsRefund(Long accountId, Integer quantity){ + BigDecimal existingCredits = accountMapper.selectById(accountId).getCredits(); + BigDecimal newCredits = new BigDecimal(CreditsEventsEnum.BUY_CREDITS.getValue()).multiply(new BigDecimal(quantity)); + BigDecimal subtracted = existingCredits.subtract(newCredits); + accountService.updateCredits(accountId, subtracted.toString()); + } +} 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 43447c30..232b562a 100644 --- a/src/main/java/com/ai/da/service/impl/OrderInfoServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/OrderInfoServiceImpl.java @@ -2,12 +2,12 @@ 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.utils.OrderNoUtils; import com.ai.da.mapper.primary.OrderInfoMapper; import com.ai.da.mapper.primary.ProductMapper; import com.ai.da.mapper.primary.entity.OrderInfo; -import com.ai.da.mapper.primary.entity.Product; import com.ai.da.model.vo.AuthPrincipalVo; import com.ai.da.service.OrderInfoService; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; @@ -28,26 +28,26 @@ public class OrderInfoServiceImpl extends ServiceImpl createOrder(Long productId,String returnUrl) throws SerializeException { + public HashMap createOrder(Integer amount, String returnUrl) throws SerializeException { // 生成订单 log.info("生成订单"); - OrderInfo orderInfo = orderInfoService.createOrderByProductId(productId, PayTypeEnum.PAYPAL.getType()); + OrderInfo orderInfo = orderInfoService.createOrderByProductId(amount, PayTypeEnum.PAYPAL.getType()); OrdersCreateRequest request = new OrdersCreateRequest(); request.header("prefer","return=representation"); @@ -372,6 +372,10 @@ public class PayPalCheckoutServiceImpl implements PayPalCheckoutService { response.result().id(), new Gson().toJson(response.result(), com.paypal.payments.Refund.class), AliPayTradeStateEnum.REFUND_SUCCESS.getType()); //退款成功 + + // 更新积分状态 + OrderInfo orderByOrderNo = orderInfoService.getOrderByOrderNo(orderId); + creditsService.creditsRefund(orderByOrderNo.getAccountId(), orderByOrderNo.getTotalFee() / Integer.parseInt(CreditsEventsEnum.PRICE.getValue())); log.info("退款成功"); result = Boolean.TRUE; }else { @@ -469,6 +473,8 @@ public class PayPalCheckoutServiceImpl implements PayPalCheckoutService { orderInfoService.updateStatusByOrderNo(orderId, OrderStatusEnum.SUCCESS); //记录支付日志 paymentInfoService.createPaymentInfoForPayPal(capturedOrder); + // 更新积分 + creditsService.buyCredits(orderInfo.getAccountId(), orderInfo.getTotalFee() / Integer.parseInt(CreditsEventsEnum.PRICE.getValue())); } } } diff --git a/src/main/resources/application-dev.properties b/src/main/resources/application-dev.properties index 3bb0bef3..ccb406c6 100644 --- a/src/main/resources/application-dev.properties +++ b/src/main/resources/application-dev.properties @@ -21,7 +21,7 @@ spring.security.jwtExpiration=8640000000 #spring security权限设置 认证了token还要认证权限 不然报错Full authentication is required to access this resource 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/product/**,/api/ali-pay/**,/api/order-info/**,/api/paypal/**,/api/credits/** spring.security.authApi=/auth/login