Преглед на файлове

Merge branch 'develop/v1.0' into master-test

tangxiangan преди 1 седмица
родител
ревизия
2c1990c8e5
променени са 12 файла, в които са добавени 81 реда и са изтрити 36 реда
  1. 2 2
      pdf-office-payment/src/main/java/cn/kdan/cloud/pdf/office/payment/client/AppStoreClient.java
  2. 12 8
      pdf-office-payment/src/main/java/cn/kdan/cloud/pdf/office/payment/service/impl/AppStoreServiceImpl.java
  3. 1 7
      pdf-office-payment/src/main/java/cn/kdan/cloud/pdf/office/payment/service/impl/AppStoreWebhookServiceImpl.java
  4. 16 9
      pdf-office-payment/src/main/java/cn/kdan/cloud/pdf/office/payment/service/impl/GooglePayServiceImpl.java
  5. 6 4
      pdf-office-payment/src/main/java/cn/kdan/cloud/pdf/office/payment/service/impl/OrderServiceImpl.java
  6. 9 3
      pdf-office-payment/src/main/java/cn/kdan/cloud/pdf/office/payment/service/impl/PayCenterWebhookServiceImpl.java
  7. 2 1
      pdf-office-payment/src/main/java/cn/kdan/cloud/pdf/office/payment/service/impl/WebhookServiceImpl.java
  8. 1 0
      pdf-office-payment/src/main/java/cn/kdan/cloud/pdf/office/payment/webhook/AppStoreWebhookMonitor.java
  9. 2 0
      pdf-office-payment/src/main/java/cn/kdan/cloud/pdf/office/payment/webhook/appstore/notification/JWSTransactionDecodedPayload.java
  10. 10 0
      pdf-office-pdf-website/src/main/java/cn/kdan/cloud/pdf/office/website/controller/TranslateController.java
  11. 2 2
      pdf-office-pdf-website/src/main/java/cn/kdan/cloud/pdf/office/website/service/impl/OrderServiceImpl.java
  12. 18 0
      pdf-office-sso/src/main/java/cn/kdan/cloud/pdf/office/sso/controller/UserCenterController.java

+ 2 - 2
pdf-office-payment/src/main/java/cn/kdan/cloud/pdf/office/payment/client/AppStoreClient.java

@@ -221,7 +221,7 @@ public class AppStoreClient {
     private static void testID() {
         String issuerId = "69a6de93-a322-47e3-e053-5b8c7c11a4d1";
         String keyId = "7ZM85LHZYB";
-        String bundleId = "com.brother.pdfreaderprofree.mac";
+        String bundleId = " com.brother.pdfreaderpro.mac";
         String content = new IOUtils().getAppStoreKey();
         BearerTokenAuthenticator authenticator = new BearerTokenAuthenticator(content, keyId, issuerId, bundleId);
         String bearerToken = authenticator.generateToken();
@@ -249,7 +249,7 @@ public class AppStoreClient {
                 HttpMethod.GET, // Change to GET
                 new HttpEntity<>(null, httpHeaders), // No body for GET, just headers
                 HistoryResponse.class,
-                "2000000775930767" // Make sure to replace with the actual transactionId
+                "2000000779042198" // Make sure to replace with the actual transactionId
         ).getBody();
         List<AppTransaction> signedTransactions = new ArrayList<>();
         a.getSignedTransactions().stream().forEach(item->{

+ 12 - 8
pdf-office-payment/src/main/java/cn/kdan/cloud/pdf/office/payment/service/impl/AppStoreServiceImpl.java

@@ -122,8 +122,8 @@ public class AppStoreServiceImpl implements AppStoreService {
             createSubscription.setPrice(price);
             createSubscription.setPayTime(0);
             subscriptionsService.createSubscription(createSubscription);
-            String readeNo = MyDateUtils.getTimeStamp() + "-" + product.getId() + "-" + (int) ((Math.random() * 9 + 1) * 1000);
-            // 更新订单
+            String readeNo = cn.kdan.cloud.pdf.office.payment.utils.CommonUtils.generateRightsId((long) ((Math.random() * 9999 + 1) * 10000));
+           // 更新订单
             CreateOrderManualDTO orderManualDTO = CreateOrderManualDTO.builder()
                     .thirdTradeNo(originalTransactionId)
                     .thirdOrderNo(transactionId)
@@ -177,12 +177,13 @@ public class AppStoreServiceImpl implements AppStoreService {
                 price = ObjectUtils.isNotEmpty(product.getCnyDisplayPrice())? product.getCnyDisplayPrice().toString() : product.getCnyPrice().toString();
                 renewPrice = product.getCnyPrice();
             }
-            contentMap.put("@payPrice@", price);
-            contentMap.put("@renewPrice@", renewPrice.toString());
+            contentMap.put("@payPrice@", orderManualDTO.getCurrency()+price);
+            contentMap.put("@renewPrice@",orderManualDTO.getCurrency()+price);
+
             bo.setSendTitleContent(titleMap);
             //设置内容
             bo.setSendContent(contentMap);
-            String file = sendInvoice(userVO.getEmail(),formattedDate,orderManualDTO.getTradeNo(),orderManualDTO.getInvoiceNo(),renewPrice,orderManualDTO.getPrice());
+            String file = sendInvoice(userVO.getEmail(),formattedDate,orderManualDTO.getTradeNo(),orderManualDTO.getInvoiceNo(),renewPrice,orderManualDTO.getPrice(),orderManualDTO.getCurrency());
             bo.setFileUrl(file);
             bo.setFileName("invoice.pdf");
             emailApi.sendEmail(bo);
@@ -211,11 +212,11 @@ public class AppStoreServiceImpl implements AppStoreService {
                 price = ObjectUtils.isNotEmpty(product.getCnyDisplayPrice())? product.getCnyDisplayPrice().toString() : product.getCnyPrice().toString();
                 renewPrice = product.getCnyPrice();
             }
-            contentMap.put("@payPrice@", price);
+            contentMap.put("@payPrice@", orderManualDTO.getCurrency()+price);
             bo.setSendTitleContent(titleMap);
             //设置内容
             bo.setSendContent(contentMap);
-            String file = sendInvoice(userVO.getEmail(),formattedDate,orderManualDTO.getTradeNo(),orderManualDTO.getInvoiceNo(),renewPrice,orderManualDTO.getPrice());
+            String file = sendInvoice(userVO.getEmail(),formattedDate,orderManualDTO.getTradeNo(),orderManualDTO.getInvoiceNo(),renewPrice,orderManualDTO.getPrice(),orderManualDTO.getCurrency());
             bo.setFileUrl(file);
             bo.setFileName("invoice.pdf");
             emailApi.sendEmail(bo);
@@ -223,7 +224,7 @@ public class AppStoreServiceImpl implements AppStoreService {
     }
 
     //生成发票
-    private String sendInvoice(String email, String purchasedDate,String tradeNo,String invoiceNumber,BigDecimal unitPrice,BigDecimal amount) {
+    private String sendInvoice(String email, String purchasedDate,String tradeNo,String invoiceNumber,BigDecimal unitPrice,BigDecimal amount,String currency) {
         String invoiceHtml = null;
         try {
             invoiceHtml = new String(StreamUtils.copyToByteArray(this.getClass().getClassLoader().getResourceAsStream("templates/invoice_member.html")), StandardCharsets.UTF_8);
@@ -246,6 +247,9 @@ public class AppStoreServiceImpl implements AppStoreService {
         log.info("发票html内容填充map:{}", map);
         // 生成替换内容后的发票
         String htmlStr = TemplatesUtil.replaceStringUsingFreeMarker(invoiceHtml, map);
+        if (!currency.equals("USD")) {
+            htmlStr = htmlStr.replace("USD", currency);
+        }
         HttpHeaders headers = new HttpHeaders();
         headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
         // 封装表单数据

+ 1 - 7
pdf-office-payment/src/main/java/cn/kdan/cloud/pdf/office/payment/service/impl/AppStoreWebhookServiceImpl.java

@@ -41,13 +41,7 @@ public class AppStoreWebhookServiceImpl implements AppStoreWebhookService {
             return;
         }
         OrdersVO ordersVONew = ordersVOS.get(0);
-        ProductVO productVO = ordersService.getProduct(ordersVONew.getProductId());
-        BigDecimal price;
-        if(StringUtils.isNotEmpty(ordersVONew.getCurrency())&&ordersVONew.getCurrency().equals("USD")){
-            price = productVO.getPrice();
-        }else{
-            price = productVO.getCnyPrice();
-        }
+        BigDecimal price = BigDecimal.valueOf(jwsTransactionDecodedPayload.getPrice()/1000);
         webhookService.handleSubsequentAutomaticDeduction(price, thirdTradeNo, thirdOrderId,ordersVONew,payTime, jwsTransactionDecodedPayload.toString());
     }
 

+ 16 - 9
pdf-office-payment/src/main/java/cn/kdan/cloud/pdf/office/payment/service/impl/GooglePayServiceImpl.java

@@ -135,7 +135,7 @@ public class GooglePayServiceImpl implements GooglePayService {
         createSubscription.setPrice(price);
         createSubscription.setPayTime(0);
         subscriptionsService.createSubscription(createSubscription);
-        String readeNo = MyDateUtils.getTimeStamp() + "-" + product.getId() + "-" + (int) ((Math.random() * 9 + 1) * 1000);
+        String readeNo = cn.kdan.cloud.pdf.office.payment.utils.CommonUtils.generateRightsId((long) ((Math.random() * 9999 + 1) * 10000));
         CreateOrderManualDTO orderManualDTO = CreateOrderManualDTO.builder()
                 .thirdTradeNo(subscriptionPurchaseV2.getExternalAccountIdentifiers().getObfuscatedExternalAccountId())
                 .thirdOrderNo(subscriptionPurchaseV2.getLatestOrderId())
@@ -190,12 +190,13 @@ public class GooglePayServiceImpl implements GooglePayService {
                 price = ObjectUtils.isNotEmpty(product.getCnyDisplayPrice())? product.getCnyDisplayPrice().toString() : product.getCnyPrice().toString();
                 renewPrice = product.getCnyPrice();
             }
-            contentMap.put("@payPrice@", price);
-            contentMap.put("@renewPrice@", renewPrice.toString());
+            contentMap.put("@payPrice@", orderManualDTO.getCurrency()+price);
+            contentMap.put("@renewPrice@",orderManualDTO.getCurrency()+price);
+
             bo.setSendTitleContent(titleMap);
             //设置内容
             bo.setSendContent(contentMap);
-            String file = sendInvoice(userVO.getEmail(),formattedDate,orderManualDTO.getTradeNo(),orderManualDTO.getInvoiceNo(),renewPrice,orderManualDTO.getPrice());
+            String file = sendInvoice(userVO.getEmail(),formattedDate,orderManualDTO.getTradeNo(),orderManualDTO.getInvoiceNo(),renewPrice,orderManualDTO.getPrice(),orderManualDTO.getCurrency());
             bo.setFileUrl(file);
             bo.setFileName("invoice.pdf");
             emailApi.sendEmail(bo);
@@ -224,11 +225,11 @@ public class GooglePayServiceImpl implements GooglePayService {
                 price = ObjectUtils.isNotEmpty(product.getCnyDisplayPrice())? product.getCnyDisplayPrice().toString() : product.getCnyPrice().toString();
                 renewPrice = product.getCnyPrice();
             }
-            contentMap.put("@payPrice@", price);
+            contentMap.put("@payPrice@", orderManualDTO.getCurrency()+price);
             bo.setSendTitleContent(titleMap);
             //设置内容
             bo.setSendContent(contentMap);
-            String file = sendInvoice(userVO.getEmail(),formattedDate,orderManualDTO.getTradeNo(),orderManualDTO.getInvoiceNo(),renewPrice,orderManualDTO.getPrice());
+            String file = sendInvoice(userVO.getEmail(),formattedDate,orderManualDTO.getTradeNo(),orderManualDTO.getInvoiceNo(),renewPrice,orderManualDTO.getPrice(),orderManualDTO.getCurrency());
             bo.setFileUrl(file);
             bo.setFileName("invoice.pdf");
             emailApi.sendEmail(bo);
@@ -236,7 +237,7 @@ public class GooglePayServiceImpl implements GooglePayService {
     }
 
     //生成发票
-    private String sendInvoice(String email, String purchasedDate,String tradeNo,String invoiceNumber,BigDecimal unitPrice,BigDecimal amount) {
+    private String sendInvoice(String email, String purchasedDate,String tradeNo,String invoiceNumber,BigDecimal unitPrice,BigDecimal amount,String currency) {
         String invoiceHtml = null;
         try {
             invoiceHtml = new String(StreamUtils.copyToByteArray(this.getClass().getClassLoader().getResourceAsStream("templates/invoice_member.html")), StandardCharsets.UTF_8);
@@ -259,6 +260,9 @@ public class GooglePayServiceImpl implements GooglePayService {
         log.info("发票html内容填充map:{}", map);
         // 生成替换内容后的发票
         String htmlStr = TemplatesUtil.replaceStringUsingFreeMarker(invoiceHtml, map);
+        if (!currency.equals("USD")) {
+            htmlStr = htmlStr.replace("USD", currency);
+        }
         HttpHeaders headers = new HttpHeaders();
         headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
         // 封装表单数据
@@ -298,8 +302,11 @@ public class GooglePayServiceImpl implements GooglePayService {
         }
         OrdersVO ordersVONew = orderByTradeNo.get(0);
         ProductVO productVO = orderService.getProduct(ordersVONew.getProductId());
-
-        webhookService.handleSubsequentAutomaticDeduction(productVO.getPrice(), thirdTradeNo, thirdOrderId,ordersVONew, 1, subscriptionGoogleOrderV2.toString());
+        BigDecimal price = productVO.getPrice();
+        if(orderByTradeNo.size()==1&&productVO.getCode().equals("advanced-annual-subscription-blackFive-trail")){
+            price = productVO.getDisplayPrice();
+        }
+        webhookService.handleSubsequentAutomaticDeduction(price, thirdTradeNo, thirdOrderId,ordersVONew, 1, subscriptionGoogleOrderV2.toString());
     }
 
     @Override

+ 6 - 4
pdf-office-payment/src/main/java/cn/kdan/cloud/pdf/office/payment/service/impl/OrderServiceImpl.java

@@ -201,7 +201,8 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements
             key = "T(String).valueOf(#createUserOrderDTO.userId)" +
                     ".concat('-').concat(#createUserOrderDTO.productId)" +
                     ".concat('-').concat(#createUserOrderDTO.paymentMethod)" +
-                    ".concat('-').concat(#createUserOrderDTO.num)",
+                    ".concat('-').concat(#createUserOrderDTO.num)" +
+                    ".concat('-').concat(#createUserOrderDTO.discountFlag)",
             cacheManager = "myRedisCacheManager", unless = "#result == null")
     public Map<String, String> createUserOrder(CreateUserOrderDTO createUserOrderDTO) {
         UserVO userVO = userApi.getById(createUserOrderDTO.getUserId()).getResult();
@@ -341,7 +342,8 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements
             key = "T(String).valueOf(#createUserOrderDTO.userId)" +
                     ".concat('-').concat(#createUserOrderDTO.productId)" +
                     ".concat('-').concat(#createUserOrderDTO.paymentMethod)" +
-                    ".concat('-').concat(#createUserOrderDTO.num)",
+                    ".concat('-').concat(#createUserOrderDTO.num)" +
+                    ".concat('-').concat(#createUserOrderDTO.discountFlag)",
             cacheManager = "myRedisCacheManager", unless = "#result == null")
     public Map<String, String> createUserSubscription(CreateUserOrderDTO createUserOrderDTO) {
         UserVO userVO = userApi.getById(createUserOrderDTO.getUserId()).getResult();
@@ -546,7 +548,7 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements
         //删除缓存中的订单
         deleteTheCacheInTheCacheManager(orders.getEmail() + "-" + orders.getProductId() + "-" + orders.getPayment());
         // 会员订单,通过userId
-        deleteTheCacheInTheCacheManager(orders.getUserId() + "-" + orders.getProductId() + "-" + orders.getPayment() + "-" + orders.getPayNumber());
+        deleteTheCacheInTheCacheManager(orders.getUserId() + "-" + orders.getProductId() + "-" + orders.getPayment() + "-" + orders.getPayNumber() + "-" + orders.getDiscountType());
         // 检查订单优惠券
         productApi.refundCouponByOrderId(orderId);
     }
@@ -567,7 +569,7 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements
                 this.baseMapper.updateById(order);
             }
             //删除缓存中的订单
-            deleteTheCacheInTheCacheManager(orders.getUserId() + "-" + orders.getProductId() + "-" + orders.getPayment() + "-" + orders.getPayNumber());
+            deleteTheCacheInTheCacheManager(orders.getUserId() + "-" + orders.getProductId() + "-" + orders.getPayment() + "-" + orders.getPayNumber() + "-" + orders.getDiscountType());
             // 检查订单优惠券
             productApi.refundCouponByOrderId(orders.getId());
         }

+ 9 - 3
pdf-office-payment/src/main/java/cn/kdan/cloud/pdf/office/payment/service/impl/PayCenterWebhookServiceImpl.java

@@ -323,7 +323,7 @@ public class PayCenterWebhookServiceImpl implements PayCenterWebhookService {
                         }
                     }
                     //删除缓存中的订单
-                    ordersService.deleteTheCacheInTheCacheManager(ordersVO.getUserId() + "-" + ordersVO.getProductId() + "-" + ordersVO.getPayment() + "-" + ordersVO.getPayNumber());
+                    ordersService.deleteTheCacheInTheCacheManager(ordersVO.getUserId() + "-" + ordersVO.getProductId() + "-" + ordersVO.getPayment() + "-" + ordersVO.getPayNumber() + "-" + ordersVO.getDiscountType());
                     // 关闭用户同类型订单
                     ordersService.closeOrderByUser(ordersVO.getUserId(), productVO.getPlatform());
                     if (emailFlag) {
@@ -349,8 +349,14 @@ public class PayCenterWebhookServiceImpl implements PayCenterWebhookService {
                         String formattedDate = sdf.format(date);
                         contentMap.put("@date@",formattedDate);
                         String price = ObjectUtils.isNotEmpty(ordersVO.getReducedPrice())? ordersVO.getReducedPrice().toEngineeringString() : ordersVO.getPrice().toEngineeringString();
-                        contentMap.put("@payPrice@", price);
-                        contentMap.put("@renewPrice@", productVO.getPrice().toEngineeringString());
+                        String currencySign;
+                        if (ordersVO.getPayment() == 1 || ordersVO.getPayment() == 2) {
+                            currencySign = "¥";
+                        } else {
+                            currencySign = "$";
+                        }
+                        contentMap.put("@payPrice@", currencySign + price);
+                        contentMap.put("@renewPrice@", currencySign + price);
                         bo.setSendContent(contentMap);
                         log.info("获取发票");
                         String invoiceHtml = null;

+ 2 - 1
pdf-office-payment/src/main/java/cn/kdan/cloud/pdf/office/payment/service/impl/WebhookServiceImpl.java

@@ -109,6 +109,7 @@ public class WebhookServiceImpl implements WebhookService {
         createOrderManual.setPaymentMethod(PaymentMethodEnum.fromValue(orderByTradeNo.getPayment()));
         // 设置实际扣费价格
         createOrderManual.setPrice(price);
+        createOrderManual.setReducedPrice(price);
         if(!StringUtils.isEmpty(orderByTradeNo.getCurrency())){
             createOrderManual.setCurrency(orderByTradeNo.getCurrency());
         }
@@ -121,7 +122,7 @@ public class WebhookServiceImpl implements WebhookService {
         createOrderManual.setThirdOrderNo(thirdOrderId);
         createOrderManual.setSubscriptionId(subId);
         createOrderManual.setEmail(orderByTradeNo.getEmail());
-        String readeNo = MyDateUtils.getTimeStamp() + "-" + orderByTradeNo.getProductId() + "-" + (int) ((Math.random() * 9 + 1) * 1000);
+        String readeNo = cn.kdan.cloud.pdf.office.payment.utils.CommonUtils.generateRightsId((long) ((Math.random() * 9999 + 1) * 10000));
         createOrderManual.setTradeNo(readeNo);
         createOrderManual.setInvoiceNo(MyDateUtils.getTimeStamp() + (int) ((Math.random() * 9 + 1) * 1000));
         createOrderManual.setId(orderId);

+ 1 - 0
pdf-office-payment/src/main/java/cn/kdan/cloud/pdf/office/payment/webhook/AppStoreWebhookMonitor.java

@@ -106,6 +106,7 @@ public class AppStoreWebhookMonitor {
 //                            throw new BackendRuntimeException(ErrorMessage.PAYMENT_APPSTORE_WEBHOOK_EVENT_NO_HANDLE.concat(decodedPayload.getNotificationType().toString()));
                     }
                 }
+                return ResponseEntity.ok().build();
             } catch (InterruptedException e) {
                 log.info("上锁失败");
                 log.error("上锁失败".concat(e.getMessage()),e);

+ 2 - 0
pdf-office-payment/src/main/java/cn/kdan/cloud/pdf/office/payment/webhook/appstore/notification/JWSTransactionDecodedPayload.java

@@ -37,4 +37,6 @@ public class JWSTransactionDecodedPayload {
 
   private String webOrderLineItemId;
   private String environment;
+  private String currency;
+  private Integer price;
 }

+ 10 - 0
pdf-office-pdf-website/src/main/java/cn/kdan/cloud/pdf/office/website/controller/TranslateController.java

@@ -73,6 +73,16 @@ public class TranslateController {
             } else {
                 cost = (int) Math.ceil(vo.getCharCount() / 10000.0 )*2;
             }
+            UserSubscriptionInfoVO userSubscriptionInfoVO = getAiSubscriptionInfo(principal);
+            if(!checkPoint(userSubscriptionInfoVO, cost)){
+                TranslateResult<Map<String,Integer>> result1 = new TranslateResult<Map<String,Integer>>();
+                result1.setCode("500");
+                result1.setMessage("run out");
+                Map<String,Integer> map1 = new HashMap<>();
+                map1.put("credit",cost);
+                result1.setData(map1);
+                return result1;
+            }
             vo.setCredit(cost);
             result.setData(vo);
             return result;

+ 2 - 2
pdf-office-pdf-website/src/main/java/cn/kdan/cloud/pdf/office/website/service/impl/OrderServiceImpl.java

@@ -134,7 +134,7 @@ public class OrderServiceImpl implements OrderService {
 //                log.error("升级购买价格校验失败,商品id:{},用户id:{},升级价格:{},用户传入价格:{}", createOrderDTO.getProductId(), createOrderDTO.getUserId(), productPriceForBuy.getUpgradePrice(), createOrderDTO.getPrice());
 //                throw new BackendRuntimeException(ExceptionEnum.EXCEPTION_PRICE_ERROR);
 //            }
-            } else if (createOrderDTO.getDiscountFlag() == 1) {
+            } else if (createOrderDTO.getDiscountFlag() == 1 || createOrderDTO.getDiscountFlag() == 11) {
                 if (createOrderDTO.getCouponCode() == null) {
                     log.error("优惠券校验失败,优惠券为空,{}", createOrderDTO);
                     throw new BackendRuntimeException(ExceptionEnum.EXCEPTION_COUPON_NOT_EXISTS);
@@ -252,7 +252,7 @@ public class OrderServiceImpl implements OrderService {
         }
         // 优惠券
         boolean couponFlag = false;
-        if (createOrderDTO.getDiscountFlag() == 1) {
+        if (createOrderDTO.getDiscountFlag() == 1 || createOrderDTO.getDiscountFlag() == 11) {
             if (createOrderDTO.getCouponCode() == null) {
                 log.error("优惠券校验失败,优惠券为空,{}", createOrderDTO);
                 throw new BackendRuntimeException(ExceptionEnum.EXCEPTION_COUPON_NOT_EXISTS);

+ 18 - 0
pdf-office-sso/src/main/java/cn/kdan/cloud/pdf/office/sso/controller/UserCenterController.java

@@ -26,6 +26,7 @@ import org.springframework.security.oauth2.provider.OAuth2Authentication;
 import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationDetails;
 import org.springframework.web.bind.annotation.*;
 
+import java.math.BigDecimal;
 import java.security.Principal;
 import java.time.*;
 import java.time.format.DateTimeFormatter;
@@ -135,9 +136,26 @@ public class UserCenterController {
         List<PrizeVO> filteredList = list.stream()
                 .filter(prize -> {
                     Date endDate = prize.getEndDate();
+
                     LocalDate endLocalDate = endDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
                     return endLocalDate.isAfter(today);
                 })
+                .sorted((prize1, prize2) -> {
+                    BigDecimal price1 = prize1.getUsdPrice();
+                    BigDecimal price2 = prize2.getUsdPrice();
+
+                    // 处理 null 值,null 排在最后,按价格降序排序
+                    if (price1 == null && price2 == null) {
+                        return 0;
+                    } else if (price1 == null) {
+                        return 1; // 如果 price1 是 null,则排在后面
+                    } else if (price2 == null) {
+                        return -1; // 如果 price2 是 null,则排在后面
+                    } else {
+                        // 正常情况下比较 BigDecimal,降序排序
+                        return price2.compareTo(price1);
+                    }
+                })
                 .collect(Collectors.toList());
 
         result.setGiftList(filteredList);