Compare commits
72 Commits
zhangli-te
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 4fb1d9b00c | |||
| af71c55529 | |||
| d47caef111 | |||
| 09412ff8fe | |||
| d9be23b4cf | |||
| c730010937 | |||
| 540ecb522c | |||
| 1b7682729c | |||
| c8e1268e87 | |||
| 44508651b6 | |||
| fc29003411 | |||
| 362866113a | |||
| 18b9318b0d | |||
| 97444a1520 | |||
| b5c4e4226a | |||
| 3a0d707a5a | |||
| b3ba5ef5b1 | |||
| 53f98d9174 | |||
| a97513c33f | |||
| dab12a4b98 | |||
| d2ce1120b0 | |||
| 63bb831152 | |||
| f64bb390dc | |||
| 151898fdac | |||
| d627e9ed42 | |||
| 6aa0cb4834 | |||
| 79b0012d4e | |||
| 46fa58a78a | |||
| 1e95a147e6 | |||
| d9fe7405eb | |||
| 19a5bde9b0 | |||
| e2958b47ca | |||
| 9b85e3a39f | |||
| dd5603c450 | |||
| 7751595742 | |||
| 60defa3bb4 | |||
| 1f06e34d99 | |||
| 70a6b578ef | |||
| 5f56194f0c | |||
| b811e01da6 | |||
| 164434b3da | |||
| 875ac87316 | |||
| 9162888023 | |||
| 872d1d1b7b | |||
| eaaf9d4902 | |||
| 39b793adbb | |||
| 3937c32c6b | |||
| e998dc6651 | |||
| 652573f9ef | |||
| 90559cff06 | |||
| b07726c866 | |||
| 6f0bf4d57c | |||
| 0338f3c675 | |||
| af974e7368 | |||
| c55b433bcc | |||
| 9c4113cb43 | |||
| a2f8d90eea | |||
| 1330b8cb68 | |||
| 879678cb56 | |||
| cefafddf5a | |||
| 1814c5c199 | |||
| edd2d6e728 | |||
| c3e64ce40f | |||
| 17dddc27a2 | |||
| 5136b0f940 | |||
| b4a37065c5 | |||
| acf125b02a | |||
| 1d678f2f98 | |||
| 729ae0e19c | |||
| b51e0e1cd9 | |||
| c08f92cf4f | |||
| 2b250068cf |
59
pom.xml
59
pom.xml
@ -46,6 +46,11 @@
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
<version>2.13.2</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
@ -185,6 +190,12 @@
|
||||
<version>2.11.1</version> <!-- 可根据需要选择版本 -->
|
||||
</dependency>
|
||||
|
||||
<!-- Apache Commons Codec -->
|
||||
<dependency>
|
||||
<groupId>commons-codec</groupId>
|
||||
<artifactId>commons-codec</artifactId>
|
||||
<version>1.15</version>
|
||||
</dependency>
|
||||
<!-- swagger2 -->
|
||||
<dependency>
|
||||
<groupId>io.springfox</groupId>
|
||||
@ -243,8 +254,38 @@
|
||||
<artifactId>shedlock-provider-redis-spring</artifactId>
|
||||
<version>4.44.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.douyin.openapi</groupId>
|
||||
<artifactId>sdk</artifactId>
|
||||
<version>1.0.6</version>
|
||||
<scope>system</scope>
|
||||
<systemPath>${project.basedir}/src/main/resources/lib/sdk-1.0.6.jar</systemPath>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.meituan.sdk</groupId>
|
||||
<artifactId>sdk</artifactId>
|
||||
<version>1.0</version>
|
||||
<scope>system</scope>
|
||||
<systemPath>${project.basedir}/src/main/resources/lib/MtOpJavaSDK-1.0-SNAPSHOT.jar</systemPath>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
<version>2.13.2</version> <!-- 或更高稳定版本 -->
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- Build Configuration -->
|
||||
<build>
|
||||
<finalName>sczx_order</finalName>
|
||||
@ -262,6 +303,19 @@
|
||||
<exclude>*.yml</exclude>
|
||||
</excludes>
|
||||
</resource>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
<includes>
|
||||
<include>lib/*.jar</include>
|
||||
</includes>
|
||||
<targetPath>${project.build.directory}/lib</targetPath>
|
||||
</resource>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
<excludes>
|
||||
<exclude>lib/**</exclude>
|
||||
</excludes>
|
||||
</resource>
|
||||
</resources>
|
||||
<plugins>
|
||||
<!-- Compiler Plugin -->
|
||||
@ -278,6 +332,10 @@
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<!-- 确保包含系统作用域的依赖 -->
|
||||
<includeSystemScope>true</includeSystemScope>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
@ -297,6 +355,7 @@
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
|
||||
@ -7,4 +7,6 @@ public interface RedisKeyConstants {
|
||||
|
||||
String BIND_CAR_KEY = SERVICE_PREFIX + "bindCar:";
|
||||
|
||||
String E_Fence_KEY = SERVICE_PREFIX + "eFence:";
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,20 @@
|
||||
package com.sczx.order.common.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* @Author: 张黎
|
||||
* @Date: 2024/03/08/17:42
|
||||
* @Description: 支付方式枚举
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public enum CouponTypeEnum {
|
||||
MT("MT", "美团"),
|
||||
DY("DY", "抖音"),
|
||||
;
|
||||
private final String code;
|
||||
|
||||
private final String msg;
|
||||
}
|
||||
@ -11,12 +11,15 @@ import lombok.Getter;
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public enum PayStatusEnum {
|
||||
INIT("INIT", "初始化"),
|
||||
USERPAYING("USERPAYING", "用户支付中"),
|
||||
SUCCESS("SUCCESS", "支付成功"),
|
||||
UNFREEZE_SUCCESS("UNFREEZE_SUCCESS", "解除免押成功"),
|
||||
PAYERROR("PAYERROR", "支付失败"),
|
||||
REFUNDING("REFUNDING", "退款中"),
|
||||
REFUND_SUCCESS("REFUND_SUCCESS", "退款成功"),
|
||||
REFUND_ERROR("REFUND_ERROR", "退款失败"),
|
||||
CLOSE("CLOSE", "订单关闭"),
|
||||
;
|
||||
private final String code;
|
||||
|
||||
|
||||
@ -11,6 +11,7 @@ import lombok.Getter;
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public enum SubOrderTypeEnum {
|
||||
NO_DEPOSIT("NO_DEPOSIT", "免押冻结订单"),
|
||||
DEPOSIT("DEPOSIT", "押金订单"),
|
||||
RENTCAR("RENTCAR", "租车订单"),
|
||||
RENTBATTEY("RENTBATTEY", "租电订单"),
|
||||
|
||||
103
src/main/java/com/sczx/order/config/DouyinTokenManager.java
Normal file
103
src/main/java/com/sczx/order/config/DouyinTokenManager.java
Normal file
@ -0,0 +1,103 @@
|
||||
package com.sczx.order.config;
|
||||
|
||||
import com.aliyun.tea.TeaException;
|
||||
import com.douyin.openapi.client.Client;
|
||||
import com.douyin.openapi.client.models.OauthClientTokenRequest;
|
||||
import com.douyin.openapi.client.models.OauthClientTokenResponse;
|
||||
import com.douyin.openapi.credential.models.Config;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
/**
|
||||
* 抖音 client_token 管理器
|
||||
* 负责定时获取和缓存 client_token
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class DouyinTokenManager {
|
||||
|
||||
// 应用凭证信息
|
||||
@Value("${coupon.douyin.client_key}")
|
||||
private String CLIENT_KEY;
|
||||
|
||||
@Value("${coupon.douyin.client_secret}")
|
||||
private String CLIENT_SECRET;
|
||||
|
||||
// Token 缓存
|
||||
private final AtomicReference<OauthClientTokenResponse> tokenCache =
|
||||
new AtomicReference<>();
|
||||
|
||||
// 定时任务执行器
|
||||
private final ScheduledThreadPoolExecutor scheduler =
|
||||
new ScheduledThreadPoolExecutor(1, r -> {
|
||||
Thread t = new Thread(r, "DouyinTokenRefreshThread");
|
||||
t.setDaemon(false);
|
||||
return t;
|
||||
});
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
// 初始化时立即获取一次 token
|
||||
refreshClientToken();
|
||||
|
||||
// 每小时更新一次 token (3600秒)
|
||||
scheduler.scheduleAtFixedRate(
|
||||
this::refreshClientToken,
|
||||
3600,
|
||||
3600,
|
||||
TimeUnit.SECONDS
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前有效的 client_token
|
||||
*
|
||||
* @return 当前有效的 access_token
|
||||
*/
|
||||
public String getCurrentToken() {
|
||||
OauthClientTokenResponse response = tokenCache.get();
|
||||
if (response != null && response.getData() != null) {
|
||||
return response.getData().getAccessToken();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新 client_token
|
||||
*/
|
||||
private void refreshClientToken() {
|
||||
try {
|
||||
Config config = new Config()
|
||||
.setClientKey(CLIENT_KEY)
|
||||
.setClientSecret(CLIENT_SECRET);
|
||||
|
||||
Client client = new Client(config);
|
||||
|
||||
OauthClientTokenRequest sdkRequest = new OauthClientTokenRequest();
|
||||
sdkRequest.setClientKey(CLIENT_KEY);
|
||||
sdkRequest.setClientSecret(CLIENT_SECRET);
|
||||
sdkRequest.setGrantType("client_credential");
|
||||
|
||||
OauthClientTokenResponse sdkResponse = client.OauthClientToken(sdkRequest);
|
||||
|
||||
// 更新缓存
|
||||
tokenCache.set(sdkResponse);
|
||||
|
||||
if (sdkResponse.getData() != null) {
|
||||
log.info("抖音 client_token 更新成功: {},有效期至: {}", sdkResponse.getData().getAccessToken(),
|
||||
(System.currentTimeMillis() + sdkResponse.getData().getExpiresIn() * 1000));
|
||||
}
|
||||
} catch (TeaException e) {
|
||||
log.error("获取抖音 client_token 失败 (TeaException): " + e.getMessage());
|
||||
} catch (Exception e) {
|
||||
log.error("获取抖音 client_token 失败 (Exception): " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -3,6 +3,7 @@ package com.sczx.order.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import springfox.documentation.builders.ApiInfoBuilder;
|
||||
import springfox.documentation.builders.ParameterBuilder;
|
||||
import springfox.documentation.builders.PathSelectors;
|
||||
@ -17,6 +18,7 @@ import java.util.Arrays;
|
||||
|
||||
@Configuration
|
||||
@EnableSwagger2
|
||||
@Profile("!prod") // 除了prod环境外都启用
|
||||
public class SwaggerConfig {
|
||||
@Bean
|
||||
public Docket createRestApi() {
|
||||
|
||||
@ -53,6 +53,24 @@ public class ClientOrderController {
|
||||
return Result.ok(orderService.submitRentCarOrder(rentCarOrderReq));
|
||||
}
|
||||
|
||||
@ApiOperation(value = "免押生成租车订单")
|
||||
@PostMapping("/depositFreeSubmitRentCarOrder")
|
||||
public Result<RentCarOrderResultDTO> depositFreeSubmitRentCarOrder(@Valid @RequestBody RentCarOrderReq rentCarOrderReq){
|
||||
return Result.ok(orderService.depositFreeSubmitRentCarOrder(rentCarOrderReq));
|
||||
}
|
||||
|
||||
@ApiOperation(value = "免押支付")
|
||||
@PostMapping("/depositFreePayRentCarOrder")
|
||||
public Result<RentCarOrderResultDTO> depositFreePayRentCarOrder(@Valid @RequestBody RentCarOrderReq rentCarOrderReq){
|
||||
return Result.ok(orderService.depositFreePayRentCarOrder(rentCarOrderReq));
|
||||
}
|
||||
|
||||
@ApiOperation(value = "第三方订单")
|
||||
@PostMapping("/thirdPlatformRentCarOrder")
|
||||
public Result<RentCarOrderResultDTO> thirdPlatformRentCarOrder(@Valid @RequestBody RentCarThirdPlatformOrderReq rentCarOrderReq){
|
||||
return Result.ok(orderService.thirdPlatformRentCarOrder(rentCarOrderReq));
|
||||
}
|
||||
|
||||
@ApiOperation(value = "续租车")
|
||||
@PostMapping("/reRentalCarOrder")
|
||||
public Result<RentCarOrderResultDTO> reRentalCarOrder(@Valid @RequestBody ReRentCarReq rentCarOrderReq){
|
||||
@ -62,7 +80,7 @@ public class ClientOrderController {
|
||||
@ApiOperation(value = "取消订单")
|
||||
@PostMapping("/cancelOrder")
|
||||
public Result<Boolean> cancelOrder(@Valid @RequestBody PayOrderReq payOrderReq){
|
||||
orderService.cancelOrder(payOrderReq);
|
||||
orderService.cancelOrder(payOrderReq,null);
|
||||
return Result.ok(true);
|
||||
}
|
||||
|
||||
|
||||
@ -2,6 +2,7 @@ package com.sczx.order.controller;
|
||||
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.sczx.order.common.Result;
|
||||
import com.sczx.order.dto.VerifyGroupBuyCouponsReq;
|
||||
import com.sczx.order.dto.OrderDetailDTO;
|
||||
import com.sczx.order.dto.OrderDistribDTO;
|
||||
import com.sczx.order.dto.OrderDistribQueryReq;
|
||||
@ -12,6 +13,8 @@ import io.swagger.annotations.ApiOperation;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.validation.Valid;
|
||||
|
||||
/**
|
||||
* @Author: 张黎
|
||||
* @Date: 2025/07/25/16:42
|
||||
@ -49,4 +52,10 @@ public class PubOrderController {
|
||||
orderDistribService.saveOrderDistrib(orderNo);
|
||||
return Result.ok(true);
|
||||
}
|
||||
|
||||
@ApiOperation(value = "团购券核销")
|
||||
@PostMapping("/verifyGroupBuyCoupons")
|
||||
public Result<OrderDetailDTO> verifyGroupBuyCoupons(@Valid @RequestBody VerifyGroupBuyCouponsReq req){
|
||||
return Result.ok(orderService.verifyGroupBuyCoupons( req));
|
||||
}
|
||||
}
|
||||
|
||||
@ -60,4 +60,10 @@ public class StoreOrderController {
|
||||
public Result<OrderDTO> confirmReturnCar(@RequestBody ReturnCarReq returnCarReq){
|
||||
return Result.ok(orderService.confirmReturnCar(returnCarReq));
|
||||
}
|
||||
|
||||
@ApiOperation(value = "抖音团购核销")
|
||||
@PostMapping("/verifyCar")
|
||||
public Result<OrderDTO> verifyCar(@RequestBody ReturnCarReq returnCarReq){
|
||||
return Result.ok(orderService.confirmReturnCar(returnCarReq));
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,35 @@
|
||||
package com.sczx.order.controller;
|
||||
|
||||
import com.sczx.order.common.Result;
|
||||
import com.sczx.order.service.DouyinService;
|
||||
import com.sczx.order.service.MeiTuanService;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/verify")
|
||||
public class VerifyController {
|
||||
|
||||
@Autowired
|
||||
private MeiTuanService meituanService;
|
||||
|
||||
@ApiOperation(value = "接收美团Token数据接口")
|
||||
@GetMapping("/authorization")
|
||||
public Result<String> authorization(@RequestParam("code") String code, @RequestParam("sign") String sign, @RequestParam("developerId") Long developerId, @RequestParam("businessId") int businessId,
|
||||
@RequestParam("state") String state){
|
||||
|
||||
log.info("接收美团授权数据 - code: {}, sign: {}, developerId: {}, businessId: {}, state: {}",
|
||||
code, sign, developerId, businessId, state);
|
||||
|
||||
return Result.ok(meituanService.getAccessToken(code,state));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -1,9 +1,6 @@
|
||||
package com.sczx.order.convert;
|
||||
|
||||
import com.sczx.order.dto.OrderDTO;
|
||||
import com.sczx.order.dto.OrderDetailDTO;
|
||||
import com.sczx.order.dto.RentCarOrderReq;
|
||||
import com.sczx.order.dto.SimpleUserInfoDTO;
|
||||
import com.sczx.order.dto.*;
|
||||
import com.sczx.order.po.OrderMainPO;
|
||||
import com.sczx.order.po.OrderSubPO;
|
||||
import com.sczx.order.thirdpart.dto.*;
|
||||
@ -31,7 +28,6 @@ public interface OrderConvert {
|
||||
@Mapping(source = "rentCarOrderReq.carModelId", target = "carModelId"),
|
||||
@Mapping(source = "rentCarOrderReq.rentCarRuleId", target = "rentCarRuleId"),
|
||||
@Mapping(source = "rentCarOrderReq.rentBatteyRuleId", target = "rentBatteyRuleId"),
|
||||
@Mapping(source = "rentCarOrderReq.isAutoDeduct", target = "isAutoDeduct"),
|
||||
@Mapping(source = "rentCarOrderReq.isDepositFree", target = "isDepositFree"),
|
||||
@Mapping(source = "rentCarOrderReq.batteryType", target = "batteryType"),
|
||||
@Mapping(source = "userInfoDTO.userId", target = "customerId"),
|
||||
@ -47,6 +43,31 @@ public interface OrderConvert {
|
||||
})
|
||||
OrderMainPO subOrderToPo(RentCarOrderReq rentCarOrderReq, SimpleUserInfoDTO userInfoDTO, RentCarRuleDTO rentCarRuleDTO);
|
||||
|
||||
@Mappings({
|
||||
@Mapping(target = "orderId", ignore = true),
|
||||
@Mapping(target = "createTime", ignore = true),
|
||||
@Mapping(target = "updateTime", ignore = true),
|
||||
@Mapping(target = "delFlag", ignore = true),
|
||||
@Mapping(source = "rentCarOrderReq.storeId", target = "storeId"),
|
||||
@Mapping(source = "rentCarOrderReq.operatorId", target = "operatorId"),
|
||||
@Mapping(source = "rentCarOrderReq.carModelId", target = "carModelId"),
|
||||
@Mapping(source = "rentCarOrderReq.rentCarRuleId", target = "rentCarRuleId"),
|
||||
@Mapping(source = "rentCarOrderReq.rentBatteyRuleId", target = "rentBatteyRuleId"),
|
||||
@Mapping(source = "rentCarOrderReq.isDepositFree", target = "isDepositFree"),
|
||||
@Mapping(source = "rentCarOrderReq.batteryType", target = "batteryType"),
|
||||
@Mapping(source = "userInfoDTO.userId", target = "customerId"),
|
||||
@Mapping(source = "userInfoDTO.userName", target = "customerName"),
|
||||
@Mapping(source = "userInfoDTO.phoneNumber", target = "customerPhone"),
|
||||
@Mapping(source = "rentCarRuleDTO.rentalType", target = "rentalType"),
|
||||
@Mapping(source = "rentCarRuleDTO.rentalDays", target = "rentalDays"),
|
||||
@Mapping(source = "rentCarRuleDTO.rentalPrice", target = "rentalPrice"),
|
||||
@Mapping(source = "rentCarRuleDTO.depositPrice", target = "depositPrice"),
|
||||
@Mapping(source = "rentCarRuleDTO.overdueFee", target = "overdueFee"),
|
||||
@Mapping(source = "rentCarRuleDTO.overdueType", target = "overdueType")
|
||||
|
||||
})
|
||||
OrderMainPO subOrderToPo(RentCarThirdPlatformOrderReq rentCarOrderReq, SimpleUserInfoDTO userInfoDTO, RentCarRuleDTO rentCarRuleDTO);
|
||||
|
||||
@Mappings({
|
||||
|
||||
@Mapping(source = "orderMainPO.orderId", target = "orderId"),
|
||||
@ -87,6 +108,7 @@ public interface OrderConvert {
|
||||
@Mapping(source = "rentBatteyRuleDTO.categoryName", target = "categoryName"),
|
||||
@Mapping(source = "rentBatteyRuleDTO.title", target = "rentBatteyTitle"),
|
||||
@Mapping(source = "rentBatteyRuleDTO.durationType", target = "durationType"),
|
||||
@Mapping(source = "rentBatteyRuleDTO.rentPrice", target = "rentBatteyPrice"),
|
||||
@Mapping(source = "rentBatteyOrder.vinBatteryNo", target = "batteyNo"),
|
||||
})
|
||||
OrderDetailDTO mainOrderToDetailDTO(OrderMainPO orderMainPO, CompanyStoreDTO companyStoreDTO, RentBatteyRuleDTO rentBatteyRuleDTO, CarDTO carDTO, CarModelSimpleDTO carModelSimpleDTO,OrderSubPO rentBatteyOrder);
|
||||
|
||||
38
src/main/java/com/sczx/order/dto/GroupBuyOrderInfoDto.java
Normal file
38
src/main/java/com/sczx/order/dto/GroupBuyOrderInfoDto.java
Normal file
@ -0,0 +1,38 @@
|
||||
package com.sczx.order.dto;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* 团购订单必须信息
|
||||
* @Author: 张黎
|
||||
* @Date: 2025/10/27/20:42
|
||||
* @Description:
|
||||
*/
|
||||
@Data
|
||||
public class GroupBuyOrderInfoDto {
|
||||
|
||||
@ApiModelProperty(value = "门店id")
|
||||
@NotNull(message = "门店id不能为空")
|
||||
private Long storeId;
|
||||
|
||||
@ApiModelProperty(value = "客户id")
|
||||
private Long customerId;
|
||||
|
||||
@ApiModelProperty("车型ID")
|
||||
@NotNull(message = "车型ID不能为空")
|
||||
private Long carModelId;
|
||||
|
||||
@ApiModelProperty(value = "租车套餐id")
|
||||
@NotNull(message = "租车套餐id不能为空")
|
||||
private Long rentCarRuleId;
|
||||
|
||||
|
||||
@ApiModelProperty(value = "租电套餐id")
|
||||
private Long rentBatteyRuleId;
|
||||
|
||||
@ApiModelProperty(value = "团购券类型")
|
||||
private String couponType;
|
||||
}
|
||||
@ -119,6 +119,9 @@ public class OrderDetailDTO {
|
||||
@ApiModelProperty("电池编码")
|
||||
private String batteyNo;
|
||||
|
||||
@ApiModelProperty("租电租金")
|
||||
private BigDecimal rentBatteyPrice;
|
||||
|
||||
@ApiModelProperty("计时方式")
|
||||
private Integer durationType;
|
||||
|
||||
@ -176,4 +179,7 @@ public class OrderDetailDTO {
|
||||
|
||||
@ApiModelProperty("支付订单信息")
|
||||
private List<PayOrderDTO> payOrderDTOList;
|
||||
|
||||
@ApiModelProperty("待支付金额")
|
||||
private BigDecimal waitPayAmount;
|
||||
}
|
||||
|
||||
@ -23,6 +23,4 @@ public class ReRentCarReq {
|
||||
@ApiModelProperty(value = "客户id")
|
||||
private Long customerId;
|
||||
|
||||
@ApiModelProperty("是否开通代扣")
|
||||
private Boolean isAutoDeduct = false;
|
||||
}
|
||||
|
||||
@ -5,7 +5,6 @@ import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
@ -40,17 +39,12 @@ public class RentCarOrderReq {
|
||||
|
||||
|
||||
@ApiModelProperty(value = "租电套餐id")
|
||||
@NotNull(message = "租电套餐id不能为空")
|
||||
private Long rentBatteyRuleId;
|
||||
|
||||
@ApiModelProperty("选择的电池类型")
|
||||
@NotBlank(message = "租电套餐id不能为空")
|
||||
private String batteryType;
|
||||
|
||||
|
||||
@ApiModelProperty("是否开通免押")
|
||||
private Boolean isDepositFree = false;
|
||||
|
||||
@ApiModelProperty("是否开通代扣")
|
||||
private Boolean isAutoDeduct = false;
|
||||
}
|
||||
|
||||
@ -0,0 +1,62 @@
|
||||
package com.sczx.order.dto;
|
||||
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* @Author: 张黎
|
||||
* @Date: 2025/07/25/16:58
|
||||
* @Description:
|
||||
*/
|
||||
@Data
|
||||
@ApiModel(value = "租车订单请求参数")
|
||||
public class RentCarThirdPlatformOrderReq {
|
||||
|
||||
@ApiModelProperty(value = "订单编号,租车不需要传,续租和逾期处理需要传")
|
||||
private String orderNo;
|
||||
|
||||
@ApiModelProperty(value = "运营商id")
|
||||
private Long operatorId;
|
||||
|
||||
@ApiModelProperty(value = "门店id")
|
||||
@NotNull(message = "门店id不能为空")
|
||||
private Long storeId;
|
||||
|
||||
@ApiModelProperty(value = "客户id")
|
||||
private Long customerId;
|
||||
|
||||
@ApiModelProperty(value = "客户姓名")
|
||||
private String customerName;
|
||||
|
||||
@ApiModelProperty(value = "客户电话")
|
||||
private String customerPhone;
|
||||
|
||||
@ApiModelProperty(value = "第三方订单号")
|
||||
private String thirdOrderNo;
|
||||
|
||||
@ApiModelProperty(value = "订单来源")
|
||||
private String orderSource;
|
||||
|
||||
@ApiModelProperty("车型ID")
|
||||
@NotNull(message = "车型ID不能为空")
|
||||
private Long carModelId;
|
||||
|
||||
@ApiModelProperty(value = "租车套餐id")
|
||||
@NotNull(message = "租车套餐id不能为空")
|
||||
private Long rentCarRuleId;
|
||||
|
||||
|
||||
@ApiModelProperty(value = "租电套餐id")
|
||||
private Long rentBatteyRuleId;
|
||||
|
||||
@ApiModelProperty("选择的电池类型")
|
||||
private String batteryType;
|
||||
|
||||
|
||||
@ApiModelProperty("是否开通免押")
|
||||
private Boolean isDepositFree = false;
|
||||
}
|
||||
@ -0,0 +1,34 @@
|
||||
package com.sczx.order.dto;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* @Author: 张黎
|
||||
* @Date: 2025/10/27/19:13
|
||||
* @Description:
|
||||
*/
|
||||
@ApiModel(value = "团购券核销请求参数")
|
||||
@Data
|
||||
public class VerifyGroupBuyCouponsReq {
|
||||
|
||||
@NotEmpty(message = "券码类型不能为空")
|
||||
@ApiModelProperty(value = "券码类型:美团MT,抖音DY")
|
||||
private String couponType;
|
||||
|
||||
@NotEmpty(message = "券码不能为空")
|
||||
@ApiModelProperty(value = "券码")
|
||||
private String couponCode;
|
||||
|
||||
@NotNull(message = "门店id不能为空")
|
||||
@ApiModelProperty(value = "门店id")
|
||||
private Long storeId;
|
||||
|
||||
@NotEmpty(message = "用户手机号不能为空")
|
||||
@ApiModelProperty(value = "用户完整手机号")
|
||||
private String mobile;
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
package com.sczx.order.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.sczx.order.po.ElectronicFenceRulePO;
|
||||
import com.sczx.order.po.OrderCarChangePO;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 订单车辆变更表 Mapper 接口
|
||||
* </p>
|
||||
*
|
||||
* @author zhangli
|
||||
* @since 2025-09-03 23:12:55
|
||||
*/
|
||||
public interface ElectronicFenceRuleMapper extends BaseMapper<ElectronicFenceRulePO> {
|
||||
|
||||
}
|
||||
16
src/main/java/com/sczx/order/mapper/OrderProcessMapper.java
Normal file
16
src/main/java/com/sczx/order/mapper/OrderProcessMapper.java
Normal file
@ -0,0 +1,16 @@
|
||||
package com.sczx.order.mapper;
|
||||
|
||||
import com.sczx.order.po.OrderProcessPO;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 订单异常处理表 Mapper 接口
|
||||
* </p>
|
||||
*
|
||||
* @author zhangli
|
||||
* @since 2025-09-27 22:05:11
|
||||
*/
|
||||
public interface OrderProcessMapper extends BaseMapper<OrderProcessPO> {
|
||||
|
||||
}
|
||||
66
src/main/java/com/sczx/order/po/ElectronicFenceRulePO.java
Normal file
66
src/main/java/com/sczx/order/po/ElectronicFenceRulePO.java
Normal file
@ -0,0 +1,66 @@
|
||||
package com.sczx.order.po;
|
||||
|
||||
import com.alibaba.fastjson.annotation.JSONField;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 套餐规则与电子围栏关联表
|
||||
* </p>
|
||||
*
|
||||
* @author lingma
|
||||
* @since 2025-07-25 17:17:28
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@TableName("zc_electronic_fence_rule")
|
||||
@ApiModel(value = "ElectronicFenceRulePO对象", description = "套餐规则与电子围栏关联表")
|
||||
public class ElectronicFenceRulePO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ApiModelProperty("规则ID")
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
@ApiModelProperty("车辆规则ID")
|
||||
private Long carRuleId;
|
||||
|
||||
@ApiModelProperty("电子围栏ID")
|
||||
private Long electronicFenceId;
|
||||
|
||||
@ApiModelProperty("排序")
|
||||
private Integer sortOrder;
|
||||
|
||||
@ApiModelProperty("删除标志(0代表存在 2代表删除)")
|
||||
private String delFlag;
|
||||
|
||||
@ApiModelProperty("创建者")
|
||||
private String createBy;
|
||||
|
||||
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||
@ApiModelProperty("创建时间")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
@ApiModelProperty("更新者")
|
||||
private String updateBy;
|
||||
|
||||
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||
@ApiModelProperty("更新时间")
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
@ApiModelProperty("备注")
|
||||
private String remark;
|
||||
}
|
||||
@ -105,11 +105,12 @@ public class OrderMainPO implements Serializable {
|
||||
@ApiModelProperty("申请还车时间")
|
||||
private LocalDateTime reqEndRentTime;
|
||||
|
||||
|
||||
|
||||
@ApiModelProperty("实际还车时间")
|
||||
private LocalDateTime actEndRentTime;
|
||||
|
||||
@ApiModelProperty("租赁时长")
|
||||
private Integer rentalDuration;
|
||||
|
||||
@ApiModelProperty("逾期天数")
|
||||
private Integer overdueDays;
|
||||
|
||||
|
||||
56
src/main/java/com/sczx/order/po/OrderProcessPO.java
Normal file
56
src/main/java/com/sczx/order/po/OrderProcessPO.java
Normal file
@ -0,0 +1,56 @@
|
||||
package com.sczx.order.po;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 订单异常处理表
|
||||
* </p>
|
||||
*
|
||||
* @author zhangli
|
||||
* @since 2025-09-27 22:05:11
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@TableName("zc_order_process")
|
||||
@ApiModel(value = "OrderProcessPO对象", description = "订单异常处理表")
|
||||
public class OrderProcessPO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ApiModelProperty("订单ID(主键)")
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
@ApiModelProperty("订单id")
|
||||
private Long orderId;
|
||||
|
||||
@ApiModelProperty("订单编号")
|
||||
private String orderNo;
|
||||
|
||||
@ApiModelProperty("处理类型,NO_PAY未支付, RE_FUND退款")
|
||||
private String processType;
|
||||
|
||||
@ApiModelProperty("处理次数")
|
||||
private Integer retryNum;
|
||||
|
||||
@ApiModelProperty("删除标志(0代表存在 2代表删除)")
|
||||
private String delFlag;
|
||||
|
||||
@ApiModelProperty("创建时间")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
@ApiModelProperty("更新时间")
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
|
||||
}
|
||||
@ -74,6 +74,9 @@ public class OrderSubPO implements Serializable {
|
||||
@ApiModelProperty("备注")
|
||||
private String remark;
|
||||
|
||||
@ApiModelProperty("平台流水号")
|
||||
private String transactionId;
|
||||
|
||||
@ApiModelProperty("删除标志(0代表存在 2代表删除)")
|
||||
private String delFlag;
|
||||
|
||||
|
||||
@ -0,0 +1,16 @@
|
||||
package com.sczx.order.repository;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.sczx.order.po.ElectronicFenceRulePO;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 套餐规则与电子围栏关联表 服务类
|
||||
* </p>
|
||||
*
|
||||
* @author lingma
|
||||
* @since 2025-07-25 17:17:28
|
||||
*/
|
||||
public interface ElectronicFenceRuleRepo extends IService<ElectronicFenceRulePO> {
|
||||
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
package com.sczx.order.repository;
|
||||
|
||||
import com.sczx.order.po.OrderProcessPO;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 订单异常处理表 服务类
|
||||
* </p>
|
||||
*
|
||||
* @author zhangli
|
||||
* @since 2025-09-27 22:05:11
|
||||
*/
|
||||
public interface OrderProcessRepo extends IService<OrderProcessPO> {
|
||||
|
||||
}
|
||||
@ -0,0 +1,21 @@
|
||||
package com.sczx.order.repository.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.sczx.order.po.ElectronicFenceRulePO;
|
||||
import com.sczx.order.repository.ElectronicFenceRuleRepo;
|
||||
import com.sczx.order.mapper.ElectronicFenceRuleMapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 套餐规则与电子围栏关联表 服务实现类
|
||||
* </p>
|
||||
*
|
||||
* @author lingma
|
||||
* @since 2025-07-25 17:17:28
|
||||
*/
|
||||
@Service
|
||||
public class ElectronicFenceRuleRepoImpl extends ServiceImpl<ElectronicFenceRuleMapper, ElectronicFenceRulePO> implements ElectronicFenceRuleRepo {
|
||||
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
package com.sczx.order.repository.impl;
|
||||
|
||||
import com.sczx.order.po.OrderProcessPO;
|
||||
import com.sczx.order.mapper.OrderProcessMapper;
|
||||
import com.sczx.order.repository.OrderProcessRepo;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 订单异常处理表 服务实现类
|
||||
* </p>
|
||||
*
|
||||
* @author zhangli
|
||||
* @since 2025-09-27 22:05:11
|
||||
*/
|
||||
@Service
|
||||
public class OrderProcessRepoImpl extends ServiceImpl<OrderProcessMapper, OrderProcessPO> implements OrderProcessRepo {
|
||||
|
||||
}
|
||||
17
src/main/java/com/sczx/order/service/DouyinService.java
Normal file
17
src/main/java/com/sczx/order/service/DouyinService.java
Normal file
@ -0,0 +1,17 @@
|
||||
package com.sczx.order.service;
|
||||
|
||||
import com.douyin.openapi.client.models.*;
|
||||
|
||||
|
||||
public interface DouyinService {
|
||||
|
||||
CertificatePrepareResponse prepare(CertificatePrepareRequest req);
|
||||
|
||||
CertificateVerifyResponse verify(CertificateVerifyRequest req);
|
||||
|
||||
CertificateCancelResponse cancel(CertificateCancelRequest req);
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,27 @@
|
||||
package com.sczx.order.service;
|
||||
|
||||
import com.sczx.order.dto.GroupBuyOrderInfoDto;
|
||||
|
||||
/** 团购券服务
|
||||
* @Author: 张黎
|
||||
* @Date: 2025/10/27/20:30
|
||||
* @Description:
|
||||
*/
|
||||
public interface GroupBuyCouponService {
|
||||
/**
|
||||
* 获取团购券下单信息
|
||||
* @param couponCode 团购券码
|
||||
* @param couponType 团购券类型
|
||||
* @param mobile 手机号
|
||||
* @return
|
||||
*/
|
||||
GroupBuyOrderInfoDto getGroupBuyOrderInfoDto(String couponCode, String couponType, String mobile);
|
||||
|
||||
/**
|
||||
* 校验团购券码
|
||||
* @param couponCode 团购券码
|
||||
* @param couponType 团购券类型
|
||||
* @return
|
||||
*/
|
||||
boolean checkCouponCode(String couponCode, String couponType);
|
||||
}
|
||||
17
src/main/java/com/sczx/order/service/MeiTuanService.java
Normal file
17
src/main/java/com/sczx/order/service/MeiTuanService.java
Normal file
@ -0,0 +1,17 @@
|
||||
package com.sczx.order.service;
|
||||
|
||||
import com.meituan.sdk.MeituanResponse;
|
||||
import com.meituan.sdk.auth.MeituanTokenResponse;
|
||||
import com.meituan.sdk.model.ddzh.tuangou.tuangouReceiptConsume.TuangouReceiptConsumeResponse;
|
||||
|
||||
public interface MeiTuanService {
|
||||
|
||||
MeituanTokenResponse getAccessToken(String code , String state);
|
||||
|
||||
MeituanTokenResponse prepare(String code);
|
||||
|
||||
MeituanResponse<TuangouReceiptConsumeResponse> consume(String code);
|
||||
|
||||
MeituanTokenResponse refreshAccessToken(String refreshToken);
|
||||
|
||||
}
|
||||
@ -15,6 +15,13 @@ public interface OrderService {
|
||||
*/
|
||||
OrderMainPO queryOrderMainPoByOrderNo(String orderNo, String delFlag);
|
||||
|
||||
/**
|
||||
* 团购券核销
|
||||
* @param req
|
||||
* @return
|
||||
*/
|
||||
OrderDetailDTO verifyGroupBuyCoupons(VerifyGroupBuyCouponsReq req) ;
|
||||
|
||||
/**
|
||||
* 提交租车订单
|
||||
* @param rentCarOrderReq
|
||||
@ -22,6 +29,28 @@ public interface OrderService {
|
||||
*/
|
||||
RentCarOrderResultDTO submitRentCarOrder(RentCarOrderReq rentCarOrderReq);
|
||||
|
||||
/**
|
||||
* 免押下单
|
||||
* @param rentCarOrderReq
|
||||
* @return
|
||||
*/
|
||||
RentCarOrderResultDTO depositFreeSubmitRentCarOrder(RentCarOrderReq rentCarOrderReq);
|
||||
|
||||
/**
|
||||
* 免押支付
|
||||
* @param rentCarOrderReq
|
||||
* @return
|
||||
*/
|
||||
RentCarOrderResultDTO depositFreePayRentCarOrder(RentCarOrderReq rentCarOrderReq);
|
||||
|
||||
|
||||
/**
|
||||
* 第三方订单
|
||||
* @param rentCarOrderReq
|
||||
* @return
|
||||
*/
|
||||
RentCarOrderResultDTO thirdPlatformRentCarOrder(RentCarThirdPlatformOrderReq rentCarOrderReq);
|
||||
|
||||
/**
|
||||
* 续租车
|
||||
* @param rentCarOrderReq
|
||||
@ -40,7 +69,19 @@ public interface OrderService {
|
||||
* 取消订单
|
||||
* @param payOrderReq
|
||||
*/
|
||||
void cancelOrder(PayOrderReq payOrderReq);
|
||||
void cancelOrder(PayOrderReq payOrderReq,OrderMainPO orderMainPO);
|
||||
|
||||
/**
|
||||
* 取消续租订单
|
||||
* @param orderMainPO
|
||||
*/
|
||||
void cancelRerentOrOverDueOrder(OrderMainPO orderMainPO);
|
||||
|
||||
/**
|
||||
* 强制删除租车订单
|
||||
* @param orderMainPO
|
||||
*/
|
||||
void forceRemoveRentOrder(OrderMainPO orderMainPO);
|
||||
|
||||
/**
|
||||
* 逾期处理
|
||||
|
||||
@ -7,6 +7,8 @@ import java.math.BigDecimal;
|
||||
|
||||
public interface PayService {
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 预支付下单
|
||||
* @param payType
|
||||
@ -28,4 +30,44 @@ public interface PayService {
|
||||
* @param refundFee
|
||||
*/
|
||||
String refundOrder(String payType,Long companyId,String outTradeNo, BigDecimal totalFee, BigDecimal refundFee);
|
||||
|
||||
|
||||
/**
|
||||
* 支付宝免押扣款
|
||||
* @param body
|
||||
* @param companyId
|
||||
* @param outTradeNo
|
||||
* @param authNo
|
||||
* @param aliPayOpenId
|
||||
* @param totalFee
|
||||
* @return
|
||||
*/
|
||||
UnifiedPaymentInfoDTO zhimaPayOrder(String body, Long companyId, String outTradeNo, String authNo, String aliPayOpenId,BigDecimal totalFee);
|
||||
|
||||
|
||||
/**
|
||||
* 冻结
|
||||
* @param companyId
|
||||
* @param outOrderNo
|
||||
* @param freezeFee
|
||||
* @return
|
||||
*/
|
||||
UnifiedPaymentInfoDTO freezeOrder(Long companyId,String outOrderNo, BigDecimal freezeFee);
|
||||
|
||||
/**
|
||||
* 解冻
|
||||
* @param companyId
|
||||
* @param outOrderNo
|
||||
* @param authCode
|
||||
* @return
|
||||
*/
|
||||
boolean finishFreezeOrder(Long companyId,String outOrderNo, String authCode, BigDecimal freezeFee);
|
||||
|
||||
/**
|
||||
* 取消冻结
|
||||
* @param companyId
|
||||
* @param outOrderNo
|
||||
* @return
|
||||
*/
|
||||
boolean cancelFreezeOrder(Long companyId,String outOrderNo);
|
||||
}
|
||||
|
||||
191
src/main/java/com/sczx/order/service/impl/DouyinServiceImpl.java
Normal file
191
src/main/java/com/sczx/order/service/impl/DouyinServiceImpl.java
Normal file
@ -0,0 +1,191 @@
|
||||
package com.sczx.order.service.impl;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.aliyun.tea.TeaException;
|
||||
import com.douyin.openapi.client.Client;
|
||||
import com.douyin.openapi.client.models.*;
|
||||
import com.douyin.openapi.credential.models.Config;
|
||||
|
||||
|
||||
import com.meituan.sdk.DefaultMeituanClient;
|
||||
import com.meituan.sdk.MeituanClient;
|
||||
import com.meituan.sdk.MeituanResponse;
|
||||
import com.meituan.sdk.auth.MeituanTokenResponse;
|
||||
import com.meituan.sdk.internal.utils.SignerUtil;
|
||||
import com.meituan.sdk.model.ddzh.tuangou.tuangouReceiptPrepare.TuangouReceiptPrepareRequest;
|
||||
import com.meituan.sdk.model.ddzh.tuangou.tuangouReceiptPrepare.TuangouReceiptPrepareResponse;
|
||||
import com.sczx.order.common.Result;
|
||||
import com.sczx.order.config.DouyinTokenManager;
|
||||
import com.sczx.order.dto.VerifyGroupBuyCouponsReq;
|
||||
import com.sczx.order.exception.InnerException;
|
||||
import com.sczx.order.service.DouyinService;
|
||||
import com.sczx.order.thirdpart.dto.CompanyStoreDTO;
|
||||
import com.sczx.order.thirdpart.integration.StoreInteg;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
public class DouyinServiceImpl implements DouyinService {
|
||||
|
||||
@Value("${coupon.douyin.client_key}")
|
||||
private String CLIENT_KEY;
|
||||
|
||||
@Value("${coupon.douyin.client_secret}")
|
||||
private String CLIENT_SECRET;
|
||||
|
||||
@Value("${coupon.douyin.account_id}")
|
||||
private String ACCOUNT_ID;
|
||||
|
||||
@Value("${coupon.douyin.poi_id}")
|
||||
private String POI_ID;
|
||||
|
||||
@Autowired
|
||||
private DouyinTokenManager douyinTokenManager;
|
||||
|
||||
|
||||
public String resolveShortUrlToGetObjectId(String shortUrl) {
|
||||
try {
|
||||
URL url = new URL(shortUrl);
|
||||
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
||||
connection.setInstanceFollowRedirects(false); // 禁止自动重定向
|
||||
connection.connect();
|
||||
|
||||
String longUrl = connection.getHeaderField("Location");
|
||||
connection.disconnect();
|
||||
|
||||
if (longUrl == null || longUrl.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 使用正则表达式匹配object_id参数
|
||||
java.util.regex.Pattern pattern = java.util.regex.Pattern.compile("object_id=([^&]*)");
|
||||
java.util.regex.Matcher matcher = pattern.matcher(longUrl);
|
||||
|
||||
if (matcher.find()) {
|
||||
return matcher.group(1);
|
||||
}
|
||||
|
||||
return null;
|
||||
} catch (Exception e) {
|
||||
log.error("二维码不正确");
|
||||
throw new InnerException("扫码核销失败,二维码不正确");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 抖音验券准备返回抖音验券对象
|
||||
*/
|
||||
@Override
|
||||
public CertificatePrepareResponse prepare(CertificatePrepareRequest req) {
|
||||
// 获取当前有效的access_token
|
||||
String accessToken = douyinTokenManager.getCurrentToken();
|
||||
|
||||
if (accessToken == null || accessToken.isEmpty()) {
|
||||
throw new RuntimeException("无法获取有效的access_token");
|
||||
}
|
||||
|
||||
//抖音验券请求
|
||||
try {
|
||||
Config config = new Config().setClientKey(CLIENT_KEY).setClientSecret(CLIENT_SECRET);
|
||||
Client client = new Client(config);
|
||||
|
||||
CertificatePrepareRequest sdkRequest = new CertificatePrepareRequest();
|
||||
sdkRequest.setAccessToken(accessToken);
|
||||
sdkRequest.setAccountId(ACCOUNT_ID);
|
||||
|
||||
String encryptedData = resolveShortUrlToGetObjectId(req.getEncryptedData());
|
||||
sdkRequest.setEncryptedData(encryptedData);
|
||||
|
||||
sdkRequest.setPoiId(req.getPoiId());
|
||||
CertificatePrepareResponse sdkResponse = client.CertificatePrepare(sdkRequest);
|
||||
System.out.println(JSONObject.toJSONString(sdkResponse));
|
||||
|
||||
if (sdkResponse.getExtra().getErrorCode() != 0){
|
||||
throw new RuntimeException("券验证失败:" + sdkResponse.getExtra().getDescription());
|
||||
}
|
||||
|
||||
return sdkResponse;
|
||||
|
||||
} catch (TeaException e) {
|
||||
throw new RuntimeException("券验证失败");
|
||||
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("券验证失败");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CertificateVerifyResponse verify(CertificateVerifyRequest req) {
|
||||
// 获取当前有效的access_token
|
||||
String accessToken = douyinTokenManager.getCurrentToken();
|
||||
|
||||
if (accessToken == null || accessToken.isEmpty()) {
|
||||
throw new RuntimeException("无法获取有效的access_token");
|
||||
}
|
||||
|
||||
try{
|
||||
Config config = new Config().setClientKey(CLIENT_KEY).setClientSecret(CLIENT_SECRET);
|
||||
Client client = new Client(config);
|
||||
|
||||
CertificateVerifyRequest sdkRequest = new CertificateVerifyRequest();
|
||||
sdkRequest.setAccessToken(accessToken);
|
||||
sdkRequest.setAccountId(ACCOUNT_ID);
|
||||
sdkRequest.setPoiId(req.getPoiId());
|
||||
sdkRequest.setVerifyToken(req.getVerifyToken());
|
||||
|
||||
CertificateVerifyResponse sdkResponse = client.CertificateVerify(sdkRequest);
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CertificateCancelResponse cancel(CertificateCancelRequest req) {
|
||||
// 获取当前有效的access_token
|
||||
String accessToken = douyinTokenManager.getCurrentToken();
|
||||
|
||||
if (accessToken == null || accessToken.isEmpty()) {
|
||||
throw new RuntimeException("无法获取有效的access_token");
|
||||
}
|
||||
|
||||
try{
|
||||
|
||||
Config config = new Config().setClientKey(CLIENT_KEY).setClientSecret(CLIENT_SECRET);
|
||||
Client client = new Client(config);
|
||||
|
||||
CertificateCancelRequest sdkRequest = new CertificateCancelRequest();
|
||||
sdkRequest.setAccessToken(accessToken);
|
||||
sdkRequest.setVerifyId(req.getVerifyId());
|
||||
sdkRequest.setCertificateId(req.getCertificateId());
|
||||
|
||||
CertificateCancelResponse sdkResponse = client.CertificateCancel(sdkRequest);
|
||||
System.out.println(JSONObject.toJSONString(sdkResponse));
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,49 @@
|
||||
package com.sczx.order.service.impl;
|
||||
|
||||
import com.sczx.order.common.enums.CouponTypeEnum;
|
||||
import com.sczx.order.dto.GroupBuyOrderInfoDto;
|
||||
import com.sczx.order.dto.SimpleUserInfoDTO;
|
||||
import com.sczx.order.exception.BizException;
|
||||
import com.sczx.order.service.GroupBuyCouponService;
|
||||
import com.sczx.order.service.MeiTuanService;
|
||||
import com.sczx.order.thirdpart.integration.UserInteg;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* @Author: 张黎
|
||||
* @Date: 2025/10/27/20:48
|
||||
* @Description:
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class GroupBuyCouponServiceImpl implements GroupBuyCouponService {
|
||||
|
||||
|
||||
@Autowired
|
||||
private UserInteg userInteg;
|
||||
|
||||
@Autowired
|
||||
private MeiTuanService meiTuanService;
|
||||
|
||||
@Override
|
||||
public GroupBuyOrderInfoDto getGroupBuyOrderInfoDto(String couponCode, String couponType, String mobile) {
|
||||
SimpleUserInfoDTO userInfoDTO = userInteg.getUInfoByMobile(mobile);
|
||||
if(userInfoDTO==null){
|
||||
throw new BizException("用户不存在");
|
||||
}
|
||||
if(userInfoDTO.getAuthed()==0){
|
||||
throw new BizException("用户未实名认证");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkCouponCode(String couponCode, String couponType) {
|
||||
if(CouponTypeEnum.MT.getCode().equals(couponType)){
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,133 @@
|
||||
package com.sczx.order.service.impl;
|
||||
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.meituan.sdk.DefaultMeituanClient;
|
||||
import com.meituan.sdk.MeituanClient;
|
||||
import com.meituan.sdk.MeituanResponse;
|
||||
import com.meituan.sdk.auth.MeituanTokenResponse;
|
||||
import com.meituan.sdk.internal.exceptions.MtSdkException;
|
||||
import com.meituan.sdk.model.ddzh.tuangou.tuangouReceiptConsume.TuangouReceiptConsumeRequest;
|
||||
import com.meituan.sdk.model.ddzh.tuangou.tuangouReceiptConsume.TuangouReceiptConsumeResponse;
|
||||
import com.meituan.sdk.model.ddzh.tuangou.tuangouReceiptPrepare.TuangouReceiptPrepareRequest;
|
||||
import com.meituan.sdk.model.ddzh.tuangou.tuangouReceiptPrepare.TuangouReceiptPrepareResponse;
|
||||
import com.sczx.order.exception.BizException;
|
||||
import com.sczx.order.service.MeiTuanService;
|
||||
import com.sczx.order.thirdpart.integration.StoreInteg;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
public class MeiTuanServiceImpl implements MeiTuanService {
|
||||
|
||||
|
||||
private Long DeveloperId = 116997L;
|
||||
|
||||
private String Signkey = "n8xlhtshk7t1luvi";
|
||||
|
||||
//private String accessToken = "V2-26b8d231854d3fdf6a5c06273377a65e441e4c9f1c8cea4959c510bf0dd19ed7657e34bebe4b74aa455b80d3c757cd8a66e3ece9148e6d6838778db5f9600cf383dbf89c0cc27f07f777c98649bd94fe";
|
||||
|
||||
private String accessToken = "V2-549da132ffebe5ce5731a17ae166cb899e13c579900d6cbc4163b60e4d40440ccbe8e56d25c3341cd1003c5529c407085c06af2eb41d2d091353b4d2be6f887582d9d4bf247cf9a511581ad46ade47e8";
|
||||
|
||||
@Autowired
|
||||
private StoreInteg storeInteg;
|
||||
|
||||
@Override
|
||||
public MeituanTokenResponse getAccessToken(String code, String state) {
|
||||
try {
|
||||
// 使用美团SDK构建客户端
|
||||
MeituanClient client = DefaultMeituanClient.builder(DeveloperId, Signkey).build();
|
||||
|
||||
|
||||
// 使用美团SDK的getOAuthToken方法获取token
|
||||
MeituanTokenResponse response = client.getOAuthToken(58, code);
|
||||
|
||||
|
||||
log.info("获取access_token响应结果: {}", JSONObject.toJSONString(response));
|
||||
String token = response.getData().getAccessToken();
|
||||
|
||||
storeInteg.recordToken(state, token);
|
||||
|
||||
return null;
|
||||
|
||||
|
||||
} catch (Exception e) {
|
||||
throw new BizException("获取access_token失败");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public MeituanTokenResponse prepare(String code) {
|
||||
try {
|
||||
MeituanClient meituanClient = DefaultMeituanClient.builder(DeveloperId, Signkey).build();
|
||||
|
||||
TuangouReceiptPrepareRequest tuangouReceiptPrepareRequest = new TuangouReceiptPrepareRequest();
|
||||
|
||||
tuangouReceiptPrepareRequest.setReceiptCode("0106972239359");
|
||||
|
||||
String appAuthToken = accessToken;
|
||||
MeituanResponse<TuangouReceiptPrepareResponse> response = meituanClient.invokeApi(tuangouReceiptPrepareRequest, appAuthToken);
|
||||
|
||||
log.info("获取access_token响应结果: {}", JSONObject.toJSONString(response));
|
||||
|
||||
if (response.isSuccess()) {
|
||||
TuangouReceiptPrepareResponse resp = response.getData();
|
||||
System.out.println(resp);
|
||||
} else {
|
||||
System.out.println("调用失败");
|
||||
}
|
||||
return null;
|
||||
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("获取access_token异常", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public MeituanTokenResponse refreshAccessToken(String refreshToken) {
|
||||
try {
|
||||
MeituanClient meituanClient = DefaultMeituanClient.builder(DeveloperId, Signkey).build();
|
||||
|
||||
MeituanTokenResponse response = meituanClient.refreshToken(58, refreshToken);
|
||||
|
||||
return response;
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("获取access_token异常", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public MeituanResponse<TuangouReceiptConsumeResponse> consume (String code) {
|
||||
try {
|
||||
MeituanClient meituanClient = DefaultMeituanClient.builder(DeveloperId, Signkey).build();
|
||||
|
||||
TuangouReceiptConsumeRequest tuangouReceiptConsumeRequest = new TuangouReceiptConsumeRequest();
|
||||
|
||||
tuangouReceiptConsumeRequest.setReceiptCode("0106972239359");
|
||||
tuangouReceiptConsumeRequest.setCount(1);
|
||||
tuangouReceiptConsumeRequest.setRequestId("fdae143414");
|
||||
tuangouReceiptConsumeRequest.setAppShopAccountName("customer");
|
||||
tuangouReceiptConsumeRequest.setAppShopAccount("customer");
|
||||
|
||||
|
||||
String appAuthToken = accessToken;
|
||||
MeituanResponse<TuangouReceiptConsumeResponse> response = meituanClient.invokeApi(tuangouReceiptConsumeRequest, appAuthToken);
|
||||
|
||||
log.info("获取access_token响应结果: {}", JSONObject.toJSONString(response));
|
||||
return response;
|
||||
} catch (MtSdkException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -5,16 +5,18 @@ import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.sczx.order.common.enums.DistribTypeEnum;
|
||||
import com.sczx.order.common.enums.WalletChangeTypeEnum;
|
||||
import com.sczx.order.dto.OrderDistribDTO;
|
||||
import com.sczx.order.dto.OrderDistribQueryReq;
|
||||
import com.sczx.order.exception.BizException;
|
||||
import com.sczx.order.po.*;
|
||||
import com.sczx.order.po.BaseUserReferralPO;
|
||||
import com.sczx.order.po.OrderDistribPO;
|
||||
import com.sczx.order.po.OrderMainPO;
|
||||
import com.sczx.order.repository.*;
|
||||
import com.sczx.order.service.OrderDistribService;
|
||||
import com.sczx.order.thirdpart.dto.CompanyDTO;
|
||||
import com.sczx.order.thirdpart.dto.CompanyStoreDTO;
|
||||
import com.sczx.order.thirdpart.dto.SysConfigDTO;
|
||||
import com.sczx.order.thirdpart.dto.req.DistibIncomeReq;
|
||||
import com.sczx.order.thirdpart.integration.StoreInteg;
|
||||
import com.sczx.order.thirdpart.integration.UserInteg;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@ -24,7 +26,6 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
@ -99,11 +100,11 @@ public class OrderDistribServiceImpl implements OrderDistribService {
|
||||
//判断奖励是否过期
|
||||
if(awardDeadline.isAfter(LocalDate.now())){
|
||||
String invitationRate = String.valueOf(configList.stream().filter(config -> "sczx.invitation.rate".equals(config.getConfigKey())).findFirst().orElse(null));
|
||||
referralDistribPO = getOrderDistribPO(orderMainPO.getOrderId(),orderMainPO.getOrderNo(),DistribTypeEnum.REFERRAL.getCode(),invitationRate,orderMainPO.getOrderAmount(),null,null,baseUserReferralPO.getReferralUserId());
|
||||
referralDistribPO = getOrderDistribPO(orderMainPO.getOrderId(),orderMainPO.getOrderNo(),DistribTypeEnum.REFERRAL.getCode(),invitationRate,orderMainPO.getOrderAmount(),Integer.valueOf(orderMainPO.getOperatorId().toString()),Integer.valueOf(orderMainPO.getStoreId().toString()),baseUserReferralPO.getReferralUserId());
|
||||
addOrderDistribPOList.add(referralDistribPO);
|
||||
}
|
||||
}
|
||||
BigDecimal alreadyShareRate = addOrderDistribPOList.stream().map(OrderDistribPO::getDistribRate).reduce(BigDecimal::add).orElse(BigDecimal.ZERO);
|
||||
BigDecimal alreadyShareRate = addOrderDistribPOList.stream().map(OrderDistribPO::getDistribRate).reduce(BigDecimal.ZERO,BigDecimal::add);
|
||||
//运营商分润
|
||||
String companyRate = String.valueOf(BigDecimal.ONE.subtract(alreadyShareRate).multiply(BigDecimal.valueOf(100)));
|
||||
OrderDistribPO companyDistribPO = getOrderDistribPO(orderMainPO.getOrderId(),orderMainPO.getOrderNo(),DistribTypeEnum.COMPANY.getCode(),companyRate,orderMainPO.getOrderAmount(),Integer.valueOf(orderMainPO.getOperatorId().toString()),Integer.valueOf(orderMainPO.getStoreId().toString()),null);
|
||||
@ -115,30 +116,39 @@ public class OrderDistribServiceImpl implements OrderDistribService {
|
||||
.set(OrderMainPO::getDistribed, 1);
|
||||
orderMainRepo.update(updateMainWrapper);
|
||||
|
||||
//更新推荐信息,防止重复分润
|
||||
LambdaUpdateWrapper<BaseUserReferralPO> updateWrapper = new LambdaUpdateWrapper<>();
|
||||
updateWrapper.eq(BaseUserReferralPO::getUserId, orderMainPO.getCustomerId())
|
||||
.set(BaseUserReferralPO::getReferralOrderNo, storeDistribPO.getOrderNo());
|
||||
baseUserReferralRepo.update(updateWrapper);
|
||||
|
||||
//门店钱包入账
|
||||
LambdaQueryWrapper<BaseWalletPO> queryWalletWrapper = new LambdaQueryWrapper<>();
|
||||
queryWalletWrapper.eq(BaseWalletPO::getUserId, orderMainPO.getOperatorId()).last(" limit 1");
|
||||
BaseWalletPO baseWalletPO = baseWalletRepo.getOne(queryWalletWrapper);
|
||||
if(baseWalletPO != null){
|
||||
LambdaUpdateWrapper<BaseWalletPO> updateWalletWrapper = new LambdaUpdateWrapper<>();
|
||||
updateWalletWrapper.eq(BaseWalletPO::getUserId, orderMainPO.getOperatorId())
|
||||
.set(BaseWalletPO::getBalance, baseWalletPO.getBalance().add(storeDistribPO.getDistribAmount()));
|
||||
baseWalletRepo.update(updateWalletWrapper);
|
||||
DistibIncomeReq distibIncomeReq = new DistibIncomeReq();
|
||||
distibIncomeReq.setStoreId(orderMainPO.getStoreId());
|
||||
distibIncomeReq.setAmount(storeDistribPO.getDistribAmount());
|
||||
storeInteg.distibIncome(distibIncomeReq);
|
||||
|
||||
BaseWalletChangePO baseWalletChangePO = new BaseWalletChangePO();
|
||||
baseWalletChangePO.setUserId(orderMainPO.getOperatorId());
|
||||
baseWalletChangePO.setChangeType(WalletChangeTypeEnum.REFERRAL.getCode());
|
||||
baseWalletChangePO.setChangeTime(LocalDateTime.now());
|
||||
baseWalletChangePO.setChangeAmount(storeDistribPO.getDistribAmount());
|
||||
baseWalletChangePO.setReferralOrderNo(orderMainPO.getOrderNo());
|
||||
baseWalletChangeRepo.save(baseWalletChangePO);
|
||||
// LambdaQueryWrapper<BaseWalletPO> queryWalletWrapper = new LambdaQueryWrapper<>();
|
||||
// queryWalletWrapper.eq(BaseWalletPO::getUserId, orderMainPO.getStoreId()).last(" limit 1");
|
||||
// BaseWalletPO baseWalletPO = baseWalletRepo.getOne(queryWalletWrapper);
|
||||
// if(baseWalletPO != null){
|
||||
// LambdaUpdateWrapper<BaseWalletPO> updateWalletWrapper = new LambdaUpdateWrapper<>();
|
||||
// updateWalletWrapper.eq(BaseWalletPO::getUserId, orderMainPO.getOperatorId())
|
||||
// .set(BaseWalletPO::getBalance, baseWalletPO.getBalance().add(storeDistribPO.getDistribAmount()));
|
||||
// baseWalletRepo.update(updateWalletWrapper);
|
||||
// }else {
|
||||
// baseWalletPO = new BaseWalletPO();
|
||||
// baseWalletPO.setUserId(Long.valueOf(companyStoreDTO.getId()));
|
||||
// baseWalletPO.setUserName(companyStoreDTO.getName());
|
||||
// }
|
||||
// BaseWalletChangePO baseWalletChangePO = new BaseWalletChangePO();
|
||||
// baseWalletChangePO.setUserId(orderMainPO.getOperatorId());
|
||||
// baseWalletChangePO.setChangeType(WalletChangeTypeEnum.REFERRAL.getCode());
|
||||
// baseWalletChangePO.setChangeTime(LocalDateTime.now());
|
||||
// baseWalletChangePO.setChangeAmount(storeDistribPO.getDistribAmount());
|
||||
// baseWalletChangePO.setReferralOrderNo(orderMainPO.getOrderNo());
|
||||
// baseWalletChangeRepo.save(baseWalletChangePO);
|
||||
|
||||
//更新推荐信息,防止重复分润
|
||||
LambdaUpdateWrapper<BaseUserReferralPO> updateWrapper = new LambdaUpdateWrapper<>();
|
||||
updateWrapper.eq(BaseUserReferralPO::getUserId, orderMainPO.getCustomerId())
|
||||
.set(BaseUserReferralPO::getReferralOrderNo, storeDistribPO.getOrderNo());
|
||||
baseUserReferralRepo.update(updateWrapper);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -160,14 +170,11 @@ public class OrderDistribServiceImpl implements OrderDistribService {
|
||||
private static OrderDistribPO getOrderDistribPO(Long orderId,String orderNo,String distribType,String invitationRate, BigDecimal orderAmount,Integer companyId,Integer storeId,Long referralUserId) {
|
||||
BigDecimal referralRate = new BigDecimal(invitationRate).multiply(new BigDecimal("0.01"));
|
||||
OrderDistribPO referralDistribPO = new OrderDistribPO();
|
||||
if(DistribTypeEnum.COMPANY.getCode().equalsIgnoreCase(distribType)){
|
||||
referralDistribPO.setCompanyId(companyId);
|
||||
} else if(DistribTypeEnum.STORE.getCode().equalsIgnoreCase(distribType)){
|
||||
referralDistribPO.setStoreId(storeId);
|
||||
} else if(DistribTypeEnum.REFERRAL.getCode().equalsIgnoreCase(distribType)){
|
||||
referralDistribPO.setCompanyId(companyId);
|
||||
referralDistribPO.setStoreId(storeId);
|
||||
if(DistribTypeEnum.REFERRAL.getCode().equalsIgnoreCase(distribType)){
|
||||
referralDistribPO.setReferralUserId(referralUserId);
|
||||
}
|
||||
referralDistribPO.setReferralUserId(referralUserId);
|
||||
referralDistribPO.setOrderId(orderId);
|
||||
referralDistribPO.setOrderNo(orderNo);
|
||||
referralDistribPO.setDistribType(distribType);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -3,11 +3,10 @@ package com.sczx.order.service.impl;
|
||||
import com.sczx.order.common.enums.PaymentTypeEnum;
|
||||
import com.sczx.order.dto.SimpleUserInfoDTO;
|
||||
import com.sczx.order.service.PayService;
|
||||
import com.sczx.order.thirdpart.dto.AlipayFundFreezeResponse;
|
||||
import com.sczx.order.thirdpart.dto.AlipayResponse;
|
||||
import com.sczx.order.thirdpart.dto.UnifiedPaymentInfoDTO;
|
||||
import com.sczx.order.thirdpart.dto.req.AlipayCreateRequest;
|
||||
import com.sczx.order.thirdpart.dto.req.AlipayRefundRequest;
|
||||
import com.sczx.order.thirdpart.dto.req.PaymentRequest;
|
||||
import com.sczx.order.thirdpart.dto.req.RefundRequest;
|
||||
import com.sczx.order.thirdpart.dto.req.*;
|
||||
import com.sczx.order.thirdpart.integration.PayInteg;
|
||||
import com.sczx.order.utils.OrderUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@ -89,4 +88,52 @@ public class PayServiceImpl implements PayService {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnifiedPaymentInfoDTO zhimaPayOrder(String body, Long companyId, String outTradeNo, String authNo, String aliPayOpenId,BigDecimal totalFee) {
|
||||
AlipayCreateRequest alipayCreateRequest = new AlipayCreateRequest();
|
||||
alipayCreateRequest.setCompanyId(companyId);
|
||||
alipayCreateRequest.setSubject(body);
|
||||
alipayCreateRequest.setBody(body);
|
||||
alipayCreateRequest.setOutTradeNo(outTradeNo);
|
||||
alipayCreateRequest.setAuthNo(authNo);
|
||||
alipayCreateRequest.setOpenId(aliPayOpenId);
|
||||
alipayCreateRequest.setTotalAmount(totalFee.toString());
|
||||
return payInteg.zhiMaOrder(alipayCreateRequest);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnifiedPaymentInfoDTO freezeOrder(Long companyId, String outOrderNo, BigDecimal freezeFee) {
|
||||
AlipayFundFreezeRequest request = new AlipayFundFreezeRequest();
|
||||
request.setCompanyId(companyId.toString());
|
||||
request.setOutOrderNo(outOrderNo);
|
||||
request.setTitle("租车免押");
|
||||
request.setAmount(freezeFee.toString());
|
||||
AlipayFundFreezeResponse result = payInteg.fundFreeze(request);
|
||||
UnifiedPaymentInfoDTO unifiedPaymentInfoDTO = new UnifiedPaymentInfoDTO();
|
||||
unifiedPaymentInfoDTO.setOrderStr(result.getOrderStr());
|
||||
return unifiedPaymentInfoDTO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean finishFreezeOrder(Long companyId, String outOrderNo, String authCode, BigDecimal freezeFee) {
|
||||
log.info("开始完结支付宝押金冻结支付单");
|
||||
AlipayFinishFreezeRequest finishFreezeRequest = new AlipayFinishFreezeRequest();
|
||||
finishFreezeRequest.setCompanyId(companyId.toString());
|
||||
finishFreezeRequest.setAuthNo(authCode);
|
||||
finishFreezeRequest.setOutRequestNo(OrderUtil.generateSubOrderNo(OrderUtil.FFZ_PREFIX));
|
||||
finishFreezeRequest.setAmount(freezeFee.toString());
|
||||
AlipayResponse alipayResponse = payInteg.finishFreeze(finishFreezeRequest);
|
||||
return alipayResponse.isSuccess();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean cancelFreezeOrder(Long companyId, String outOrderNo) {
|
||||
log.info("开始取消支付宝押金冻结支付单");
|
||||
AlipayFundFreezeRequest request = new AlipayFundFreezeRequest();
|
||||
request.setCompanyId(companyId.toString());
|
||||
request.setOutOrderNo(outOrderNo);
|
||||
return payInteg.cancelFundFreeze(request);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,17 +3,16 @@ package com.sczx.order.task;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.sczx.order.common.enums.OrderStatusEnum;
|
||||
import com.sczx.order.common.enums.PayStatusEnum;
|
||||
import com.sczx.order.common.enums.PaymentTypeEnum;
|
||||
import com.sczx.order.dto.PayOrderReq;
|
||||
import com.sczx.order.po.OrderMainPO;
|
||||
import com.sczx.order.po.OrderSubPO;
|
||||
import com.sczx.order.po.OrderProcessPO;
|
||||
import com.sczx.order.repository.OrderMainRepo;
|
||||
import com.sczx.order.repository.OrderProcessRepo;
|
||||
import com.sczx.order.repository.OrderSubRepo;
|
||||
import com.sczx.order.thirdpart.dto.req.AlipayCloseRequest;
|
||||
import com.sczx.order.service.OrderService;
|
||||
import com.sczx.order.thirdpart.integration.PayInteg;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.javacrumbs.shedlock.spring.annotation.SchedulerLock;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
@ -22,6 +21,7 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
@ -35,8 +35,14 @@ public class NoPayOrderProcessTask {
|
||||
@Autowired
|
||||
private PayInteg payInteg;
|
||||
|
||||
@Autowired
|
||||
private OrderService orderService;
|
||||
|
||||
@Autowired
|
||||
private OrderProcessRepo orderProcessRepo;
|
||||
|
||||
/**
|
||||
* 每30分钟检查一次逾期订单
|
||||
* 每6分钟检查一次逾期订单
|
||||
* 使用ShedLock确保在分布式环境下只有一个实例执行
|
||||
* 分布式锁机制:ShedLock使用Redis作为锁存储,确保同一时间只有一个服务实例执行定时任务
|
||||
* 任务名称:@SchedulerLock 注解中的 name 属性标识任务名称,相同名称的任务在分布式环境下互斥执行
|
||||
@ -45,7 +51,7 @@ public class NoPayOrderProcessTask {
|
||||
* lockAtLeastFor:锁最少持有时间,防止任务执行过快导致频繁执行
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Scheduled(cron = "0 */15 * * * ?")
|
||||
@Scheduled(cron = "0 */6 * * * ?")
|
||||
@SchedulerLock(name = "checkNoPayOrders", lockAtMostFor = "9m", lockAtLeastFor = "1m")
|
||||
public void checkNoPayOrders() {
|
||||
log.info("开始执行未支付订单检查任务");
|
||||
@ -66,7 +72,7 @@ public class NoPayOrderProcessTask {
|
||||
LambdaQueryWrapper<OrderMainPO> queryWrapper = new LambdaQueryWrapper<>();
|
||||
queryWrapper.eq(OrderMainPO::getDelFlag, "0").in(OrderMainPO::getOrderStatus,
|
||||
Arrays.asList(OrderStatusEnum.WAIT_PAY.getCode(), OrderStatusEnum.RERENT_WAIT_PAY.getCode()))
|
||||
.lt(OrderMainPO::getUpdateTime, LocalDateTime.now().minusHours(1));
|
||||
.lt(OrderMainPO::getUpdateTime, LocalDateTime.now().minusMinutes(5));
|
||||
|
||||
List<OrderMainPO> orders = orderMainRepo.list(queryWrapper);
|
||||
|
||||
@ -100,52 +106,41 @@ public class NoPayOrderProcessTask {
|
||||
* @param orderMainPO
|
||||
*/
|
||||
private void processWayPay(OrderMainPO orderMainPO) {
|
||||
LambdaQueryWrapper<OrderSubPO> orderSubQueryWrapper = new LambdaQueryWrapper<>();
|
||||
orderSubQueryWrapper.eq(OrderSubPO::getOrderId, orderMainPO.getOrderId());
|
||||
orderSubQueryWrapper.eq(OrderSubPO::getPayStatus, PayStatusEnum.USERPAYING.getCode());
|
||||
orderSubQueryWrapper.orderByDesc(OrderSubPO::getCreatedAt).last(" limit 1");
|
||||
OrderSubPO orderSubPO = orderSubRepo.getOne(orderSubQueryWrapper);
|
||||
boolean closePayOrder = false;
|
||||
|
||||
//关闭支付单
|
||||
if (StringUtils.equalsIgnoreCase(orderSubPO.getPaymentMethod(), PaymentTypeEnum.WX_PAY.getCode())) {
|
||||
log.info("开始关闭支付单");
|
||||
closePayOrder = payInteg.closeOrder(orderMainPO.getOperatorId(), orderSubPO.getPaymentId());
|
||||
} else if (StringUtils.equalsIgnoreCase(orderSubPO.getPaymentMethod(), PaymentTypeEnum.ZFB_PAY.getCode())) {
|
||||
log.info("开始关闭支付宝支付单");
|
||||
AlipayCloseRequest alipayCloseRequest = new AlipayCloseRequest();
|
||||
alipayCloseRequest.setCompanyId(orderMainPO.getOperatorId());
|
||||
alipayCloseRequest.setOutTradeNo(orderSubPO.getPaymentId());
|
||||
closePayOrder = payInteg.alipayCloseOrder(alipayCloseRequest);
|
||||
OrderProcessPO orderProcessPO = orderProcessRepo.getOne(new LambdaQueryWrapper<OrderProcessPO>()
|
||||
.eq(OrderProcessPO::getOrderId, orderMainPO.getOrderId())
|
||||
.eq(OrderProcessPO::getProcessType, "NO_PAY"));
|
||||
if(Objects.isNull(orderProcessPO)){
|
||||
orderProcessPO = new OrderProcessPO();
|
||||
orderProcessPO.setOrderId(orderMainPO.getOrderId());
|
||||
orderProcessPO.setProcessType("NO_PAY");
|
||||
orderProcessPO.setOrderNo(orderMainPO.getOrderNo());
|
||||
orderProcessPO.setRetryNum(1);
|
||||
orderProcessRepo.save(orderProcessPO);
|
||||
}else {
|
||||
orderProcessPO.setRetryNum(orderProcessPO.getRetryNum()+1);
|
||||
LambdaUpdateWrapper<OrderProcessPO> updateWrapper = new LambdaUpdateWrapper<>();
|
||||
updateWrapper.eq(OrderProcessPO::getId, orderProcessPO.getId())
|
||||
.set(OrderProcessPO::getRetryNum, orderProcessPO.getRetryNum());
|
||||
orderProcessRepo.update(updateWrapper);
|
||||
}
|
||||
|
||||
if (closePayOrder) {
|
||||
|
||||
LambdaUpdateWrapper<OrderSubPO> updateSubWrapper = new LambdaUpdateWrapper<>();
|
||||
updateSubWrapper.set(OrderSubPO::getDelFlag, "2");
|
||||
updateSubWrapper.eq(OrderSubPO::getOrderId, orderMainPO.getOrderId());
|
||||
orderSubRepo.update(updateSubWrapper);
|
||||
|
||||
if (StringUtils.equalsIgnoreCase(orderMainPO.getOrderStatus(), OrderStatusEnum.WAIT_PAY.getCode())) {
|
||||
log.info("开始逻辑删除订单");
|
||||
//逻辑删除订单
|
||||
LambdaUpdateWrapper<OrderMainPO> updateWrapper = new LambdaUpdateWrapper<>();
|
||||
updateWrapper.set(OrderMainPO::getDelFlag, "2");
|
||||
updateWrapper.eq(OrderMainPO::getOrderId, orderMainPO.getOrderId());
|
||||
orderMainRepo.update(updateWrapper);
|
||||
} else if (StringUtils.equalsIgnoreCase(orderMainPO.getOrderStatus(), OrderStatusEnum.RERENT_WAIT_PAY.getCode())) {
|
||||
log.info("开始恢复续租订单状态");
|
||||
//更新订单状态及信息
|
||||
LambdaUpdateWrapper<OrderMainPO> updateWrapper = new LambdaUpdateWrapper<>();
|
||||
updateWrapper.set(OrderMainPO::getOrderStatus, OrderStatusEnum.RENT_ING.getCode());
|
||||
if(orderMainPO.getOverdueDays()>0){
|
||||
updateWrapper.set(OrderMainPO::getOrderStatus, OrderStatusEnum.RENT_OVERDUE.getCode());
|
||||
}else {
|
||||
updateWrapper.set(OrderMainPO::getOrderStatus, OrderStatusEnum.RENT_ING.getCode());
|
||||
}
|
||||
updateWrapper.eq(OrderMainPO::getOrderId, orderMainPO.getOrderId());
|
||||
orderMainRepo.update(updateWrapper);
|
||||
if(orderProcessPO.getRetryNum()>5){
|
||||
log.info("订单{}已超过最大重试次数,强行删除订单", orderMainPO.getOrderNo());
|
||||
orderService.forceRemoveRentOrder(orderMainPO);
|
||||
} else {
|
||||
if(orderMainPO.getOrderStatus().equals(OrderStatusEnum.WAIT_PAY.getCode())){
|
||||
PayOrderReq payOrderReq = new PayOrderReq();
|
||||
payOrderReq.setOrderNo(orderMainPO.getOrderNo());
|
||||
orderService.cancelOrder(payOrderReq,orderMainPO);
|
||||
} else if(orderMainPO.getOrderStatus().equals(OrderStatusEnum.RERENT_WAIT_PAY.getCode())){
|
||||
PayOrderReq payOrderReq = new PayOrderReq();
|
||||
payOrderReq.setOrderNo(orderMainPO.getOrderNo());
|
||||
orderService.cancelRerentOrOverDueOrder(orderMainPO);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -81,7 +81,7 @@ public class OrderOverdueTask {
|
||||
.set(OrderMainPO::getOverdueDays, overdueDaysOrHours)
|
||||
.eq(OrderMainPO::getOrderId, order.getOrderId())
|
||||
// 确保状态未被其他节点修改
|
||||
.eq(OrderMainPO::getOrderStatus, OrderStatusEnum.RENT_ING.getCode());
|
||||
.in(OrderMainPO::getOrderStatus, Arrays.asList(OrderStatusEnum.RENT_ING.getCode(), OrderStatusEnum.RENT_OVERDUE.getCode()));
|
||||
|
||||
boolean updated = orderMainRepo.update(updateWrapper);
|
||||
|
||||
|
||||
@ -6,8 +6,10 @@ import com.sczx.order.common.enums.PayStatusEnum;
|
||||
import com.sczx.order.common.enums.PaymentTypeEnum;
|
||||
import com.sczx.order.common.enums.SubOrderTypeEnum;
|
||||
import com.sczx.order.po.OrderMainPO;
|
||||
import com.sczx.order.po.OrderProcessPO;
|
||||
import com.sczx.order.po.OrderSubPO;
|
||||
import com.sczx.order.repository.OrderMainRepo;
|
||||
import com.sczx.order.repository.OrderProcessRepo;
|
||||
import com.sczx.order.repository.OrderSubRepo;
|
||||
import com.sczx.order.thirdpart.dto.AlipayResponse;
|
||||
import com.sczx.order.thirdpart.dto.req.AlipayRefundRequest;
|
||||
@ -23,11 +25,15 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class RefundSubOrderProcessTask {
|
||||
|
||||
@Autowired
|
||||
private OrderProcessRepo orderProcessRepo;
|
||||
|
||||
@Autowired
|
||||
private OrderMainRepo orderMainRepo;
|
||||
|
||||
@ -101,27 +107,54 @@ public class RefundSubOrderProcessTask {
|
||||
* @param subPO
|
||||
*/
|
||||
private void processRefund(OrderSubPO subPO) {
|
||||
OrderMainPO orderMainPO = orderMainRepo.getById(subPO.getOrderId());
|
||||
boolean fundResult = false;
|
||||
if(PaymentTypeEnum.WX_PAY.getCode().equalsIgnoreCase(subPO.getPaymentMethod())){
|
||||
Map<String, String> wxPayResult = payInteg.refundQuery(orderMainPO.getOperatorId(), subPO.getPaymentId());
|
||||
String returnCode = wxPayResult.get("return_code");
|
||||
if(StringUtils.isNotBlank(returnCode)){
|
||||
fundResult = "SUCCESS".equals(returnCode);
|
||||
}
|
||||
} else {
|
||||
AlipayRefundRequest request = new AlipayRefundRequest();
|
||||
request.setOutTradeNo(subPO.getPaymentId());
|
||||
request.setCompanyId(orderMainPO.getOperatorId());
|
||||
AlipayResponse alipayResponse = payInteg.alipayRefundQuery(request);
|
||||
fundResult = "SUCCESS".equals(alipayResponse.getCode());
|
||||
OrderProcessPO orderProcessPO = orderProcessRepo.getOne(new LambdaQueryWrapper<OrderProcessPO>()
|
||||
.eq(OrderProcessPO::getOrderNo, subPO.getSuborderNo())
|
||||
.eq(OrderProcessPO::getProcessType, "RE_FUND"));
|
||||
if(Objects.isNull(orderProcessPO)){
|
||||
orderProcessPO = new OrderProcessPO();
|
||||
orderProcessPO.setOrderId(subPO.getOrderId());
|
||||
orderProcessPO.setProcessType("RE_FUND");
|
||||
orderProcessPO.setOrderNo(subPO.getSuborderNo());
|
||||
orderProcessPO.setRetryNum(1);
|
||||
orderProcessRepo.save(orderProcessPO);
|
||||
}else {
|
||||
orderProcessPO.setRetryNum(orderProcessPO.getRetryNum()+1);
|
||||
LambdaUpdateWrapper<OrderProcessPO> updateWrapper = new LambdaUpdateWrapper<>();
|
||||
updateWrapper.eq(OrderProcessPO::getId, orderProcessPO.getId())
|
||||
.set(OrderProcessPO::getRetryNum, orderProcessPO.getRetryNum());
|
||||
orderProcessRepo.update(updateWrapper);
|
||||
}
|
||||
|
||||
if (fundResult) {
|
||||
if(orderProcessPO.getRetryNum()>5){
|
||||
log.info("支付单单{}已超过最大重试次数,强行关闭支付单", subPO.getSuborderNo());
|
||||
LambdaUpdateWrapper<OrderSubPO> updateSubWrapper = new LambdaUpdateWrapper<>();
|
||||
updateSubWrapper.set(OrderSubPO::getPayStatus, PayStatusEnum.REFUND_SUCCESS.getCode());
|
||||
updateSubWrapper.set(OrderSubPO::getPayStatus, PayStatusEnum.CLOSE.getCode());
|
||||
updateSubWrapper.eq(OrderSubPO::getSuborderId, subPO.getSuborderId());
|
||||
orderSubRepo.update(updateSubWrapper);
|
||||
} else {
|
||||
OrderMainPO orderMainPO = orderMainRepo.getById(subPO.getOrderId());
|
||||
boolean fundResult = false;
|
||||
if(PaymentTypeEnum.WX_PAY.getCode().equalsIgnoreCase(subPO.getPaymentMethod())){
|
||||
Map<String, String> wxPayResult = payInteg.refundQuery(orderMainPO.getOperatorId(), subPO.getPaymentId());
|
||||
String returnCode = wxPayResult.get("return_code");
|
||||
if(StringUtils.isNotBlank(returnCode)){
|
||||
fundResult = "SUCCESS".equals(returnCode);
|
||||
}
|
||||
} else {
|
||||
AlipayRefundRequest request = new AlipayRefundRequest();
|
||||
request.setOutTradeNo(subPO.getPaymentId());
|
||||
request.setCompanyId(orderMainPO.getOperatorId());
|
||||
request.setOutRequestNo(subPO.getRefundId());
|
||||
AlipayResponse alipayResponse = payInteg.alipayRefundQuery(request);
|
||||
fundResult = "SUCCESS".equals(alipayResponse.getCode());
|
||||
}
|
||||
|
||||
if (fundResult) {
|
||||
LambdaUpdateWrapper<OrderSubPO> updateSubWrapper = new LambdaUpdateWrapper<>();
|
||||
updateSubWrapper.set(OrderSubPO::getPayStatus, PayStatusEnum.REFUND_SUCCESS.getCode());
|
||||
updateSubWrapper.eq(OrderSubPO::getSuborderId, subPO.getSuborderId());
|
||||
orderSubRepo.update(updateSubWrapper);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,14 @@
|
||||
package com.sczx.order.thirdpart.dto;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import lombok.Data;
|
||||
|
||||
@ApiModel("支付宝资金冻结响应参数")
|
||||
@Data
|
||||
public class AlipayFundFreezeResponse {
|
||||
private boolean success;
|
||||
private String message;
|
||||
private String outTradeNo; // 商户订单号
|
||||
private String orderStr; // 支付串(用于前端调起支付)
|
||||
private String code; // 状态码
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
package com.sczx.order.thirdpart.dto;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import lombok.Data;
|
||||
|
||||
@ApiModel("支付宝资金冻结响应参数")
|
||||
@Data
|
||||
public class AlipayQueryFreezeResponse {
|
||||
private boolean success;
|
||||
private String message;
|
||||
private String outTradeNo; // 商户订单号
|
||||
private String authNo; // 支付串(用于前端调起支付)
|
||||
private String code; // 状态码
|
||||
}
|
||||
@ -65,4 +65,10 @@ public class CompanyStoreDTO {
|
||||
|
||||
@ApiModelProperty("以租代售分成比例")
|
||||
private BigDecimal daishouRatio;
|
||||
|
||||
@ApiModelProperty("美团token")
|
||||
private String mtToken;
|
||||
|
||||
@ApiModelProperty("抖音门店id")
|
||||
private String dyStoreId;
|
||||
}
|
||||
|
||||
@ -62,4 +62,7 @@ public class UnifiedPaymentInfoDTO {
|
||||
|
||||
@ApiModelProperty(value = "支付宝交易号")
|
||||
private String tradeNo; // 支付宝交易号
|
||||
|
||||
@ApiModelProperty(value = "支付宝芝麻信用免押支付串(用于前端调起支付)")
|
||||
private String orderStr;
|
||||
}
|
||||
|
||||
@ -11,4 +11,5 @@ public class AlipayCreateRequest {
|
||||
private String totalAmount; // 订单总金额
|
||||
private String body; // 订单描述
|
||||
private String openId; // 用户ID
|
||||
private String authNo; //支付宝资金授权操作处理号
|
||||
}
|
||||
|
||||
@ -0,0 +1,19 @@
|
||||
package com.sczx.order.thirdpart.dto.req;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
@ApiModel("支付宝资金冻结请求参数")
|
||||
@Data
|
||||
public class AlipayFinishFreezeRequest {
|
||||
private String companyId;
|
||||
@ApiModelProperty(value = "支付宝资金授权订单号")
|
||||
private String authNo;
|
||||
|
||||
@ApiModelProperty(value = "解冻请求流水号")
|
||||
private String outRequestNo;
|
||||
|
||||
@ApiModelProperty(value = "解冻金额")
|
||||
private String amount;
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
package com.sczx.order.thirdpart.dto.req;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import lombok.Data;
|
||||
|
||||
@ApiModel("支付宝资金冻结请求参数")
|
||||
@Data
|
||||
public class AlipayFundFreezeRequest {
|
||||
private String companyId;
|
||||
private String outOrderNo;
|
||||
private String title;
|
||||
private String amount;
|
||||
}
|
||||
@ -0,0 +1,12 @@
|
||||
package com.sczx.order.thirdpart.dto.req;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import lombok.Data;
|
||||
|
||||
@ApiModel("支付宝资金冻结请求参数")
|
||||
@Data
|
||||
public class AlipayQueryFreezeRequest {
|
||||
private String companyId;
|
||||
private String outOrderNo;
|
||||
private String operationType;
|
||||
}
|
||||
@ -0,0 +1,18 @@
|
||||
package com.sczx.order.thirdpart.dto.req;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@ApiModel(value = "分润收入查询参数")
|
||||
@Data
|
||||
public class DistibIncomeReq {
|
||||
|
||||
@ApiModelProperty("门店id")
|
||||
private Long storeId;
|
||||
|
||||
@ApiModelProperty("金额")
|
||||
private BigDecimal amount ;
|
||||
}
|
||||
@ -1,9 +1,6 @@
|
||||
package com.sczx.order.thirdpart.facade;
|
||||
|
||||
import com.sczx.order.thirdpart.dto.AlipayCreateResponse;
|
||||
import com.sczx.order.thirdpart.dto.AlipayQueryResponse;
|
||||
import com.sczx.order.thirdpart.dto.AlipayResponse;
|
||||
import com.sczx.order.thirdpart.dto.PaymentResponse;
|
||||
import com.sczx.order.thirdpart.dto.*;
|
||||
import com.sczx.order.thirdpart.dto.req.*;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
@ -63,6 +60,12 @@ public interface PayFacade {
|
||||
@PostMapping("/api/alipay/unifiedOrder")
|
||||
AlipayCreateResponse alipayUnifiedOrder(@RequestBody AlipayCreateRequest request);
|
||||
|
||||
/**
|
||||
* 支付宝统一下单接口
|
||||
*/
|
||||
@PostMapping("/api/alipay/zhiMaOrder")
|
||||
AlipayCreateResponse zhiMaOrder(@RequestBody AlipayCreateRequest request);
|
||||
|
||||
/**
|
||||
* 查询订单接口
|
||||
*/
|
||||
@ -86,4 +89,32 @@ public interface PayFacade {
|
||||
*/
|
||||
@PostMapping("/api/alipay/refundQuery")
|
||||
AlipayResponse alipayRefundQuery(@RequestBody AlipayRefundRequest request);
|
||||
|
||||
/**
|
||||
* 冻结接口
|
||||
*/
|
||||
@PostMapping("/api/authAlipay/fundFreeze")
|
||||
AlipayFundFreezeResponse fundFreeze(@RequestBody AlipayFundFreezeRequest request);
|
||||
|
||||
/**
|
||||
* 取消冻结
|
||||
*/
|
||||
@PostMapping("/api/authAlipay/cancelFundFreeze")
|
||||
AlipayFundFreezeResponse cancelFundFreeze(@RequestBody AlipayFundFreezeRequest request);
|
||||
|
||||
/**
|
||||
* 查询冻结
|
||||
* @param alipayQueryFreezeRequest
|
||||
* @return
|
||||
*/
|
||||
@PostMapping("/api/authAlipay/queryFundFreeze")
|
||||
AlipayQueryFreezeResponse queryFundFreeze(@RequestBody AlipayQueryFreezeRequest alipayQueryFreezeRequest);
|
||||
|
||||
/**
|
||||
* 完结冻结
|
||||
* @param alipayFinishFreezeRequest
|
||||
* @return
|
||||
*/
|
||||
@PostMapping("/api/authAlipay/finishFreeze")
|
||||
AlipayResponse finishFreeze(@RequestBody AlipayFinishFreezeRequest alipayFinishFreezeRequest);
|
||||
}
|
||||
|
||||
@ -5,6 +5,7 @@ import com.sczx.order.thirdpart.dto.CompanyDTO;
|
||||
import com.sczx.order.thirdpart.dto.CompanyStoreDTO;
|
||||
import com.sczx.order.thirdpart.dto.SysConfigDTO;
|
||||
import com.sczx.order.thirdpart.dto.SysDictDataDTO;
|
||||
import com.sczx.order.thirdpart.dto.req.DistibIncomeReq;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
@ -32,4 +33,10 @@ public interface StoreFacade {
|
||||
|
||||
@GetMapping("/sys/getConfigByConfigKey")
|
||||
Result<SysConfigDTO> getConfigByConfigKey(@RequestParam(name = "configKey") String configKey);
|
||||
|
||||
@PostMapping("/wallet/distibIncome")
|
||||
Result<Boolean> distibIncome(@RequestBody DistibIncomeReq distibIncomeReq);
|
||||
|
||||
@PostMapping("/store/recordToken")
|
||||
Result<Boolean> recordToken(@RequestParam(name = "storeNumber") String storeNumber, @RequestParam(name = "token") String token);
|
||||
}
|
||||
|
||||
@ -12,4 +12,7 @@ public interface SyncFacade {
|
||||
@GetMapping("/send/subOrder/{subOrderId}")
|
||||
Map<String, String> sendSubOrderId(@PathVariable Long subOrderId);
|
||||
|
||||
@GetMapping("/send/OrderMeal/{subOrderId}")
|
||||
Map<String, String> sendUserMeal(@PathVariable Long subOrderId);
|
||||
|
||||
}
|
||||
@ -1,6 +1,7 @@
|
||||
package com.sczx.order.thirdpart.facade;
|
||||
|
||||
import com.sczx.order.common.Result;
|
||||
import com.sczx.order.dto.SimpleUserInfoDTO;
|
||||
import com.sczx.order.thirdpart.dto.BaseUserReferralDTO;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
@ -11,4 +12,7 @@ public interface UserFacade {
|
||||
|
||||
@GetMapping("/referral/getUserReferralByUserId")
|
||||
Result<BaseUserReferralDTO> getUserReferralByUserId(@RequestParam("userId") Long userId);
|
||||
|
||||
@GetMapping("/auth/getUInfoByMobile")
|
||||
Result<SimpleUserInfoDTO> getUInfoByMobile(@RequestParam("mobile") String mobile);
|
||||
}
|
||||
|
||||
@ -122,7 +122,7 @@ public class PayInteg {
|
||||
if(StringUtils.isNotBlank(returnCode)&&StringUtils.equalsIgnoreCase(returnCode, "SUCCESS")){
|
||||
return true;
|
||||
} else {
|
||||
throw new InnerException("关闭订单失败");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -152,6 +152,26 @@ public class PayInteg {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 支付宝免押扣款接口
|
||||
*/
|
||||
public UnifiedPaymentInfoDTO zhiMaOrder(AlipayCreateRequest request){
|
||||
try {
|
||||
AlipayCreateResponse result = payFacade.zhiMaOrder(request);
|
||||
if(StringUtils.isNotBlank(result.getCode()) && "SUCCESS".equals(result.getCode())){
|
||||
UnifiedPaymentInfoDTO unifiedPaymentInfo = new UnifiedPaymentInfoDTO();
|
||||
unifiedPaymentInfo.setOutTradeNo(result.getOutTradeNo());
|
||||
unifiedPaymentInfo.setTradeNo(result.getTradeNo());
|
||||
return unifiedPaymentInfo;
|
||||
}else {
|
||||
throw new InnerException("支付宝免押扣款失败");
|
||||
}
|
||||
} catch (Exception e){
|
||||
log.error("支付宝免押扣款失败",e);
|
||||
throw new InnerException("支付宝免押扣款失败");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询订单接口
|
||||
*/
|
||||
@ -220,4 +240,69 @@ public class PayInteg {
|
||||
throw new InnerException("支付宝查询退款失败");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 免押冻结
|
||||
*/
|
||||
public AlipayFundFreezeResponse fundFreeze(AlipayFundFreezeRequest request) {
|
||||
try {
|
||||
AlipayFundFreezeResponse result = payFacade.fundFreeze( request);
|
||||
if(StringUtils.isNotBlank(result.getCode()) && "SUCCESS".equals(result.getCode())){
|
||||
return result;
|
||||
} else {
|
||||
throw new InnerException("免押冻结失败");
|
||||
}
|
||||
} catch (Exception e){
|
||||
log.error("免押冻结失败",e);
|
||||
throw new InnerException("免押冻结失败");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消冻结
|
||||
*/
|
||||
|
||||
public boolean cancelFundFreeze(AlipayFundFreezeRequest request) {
|
||||
try {
|
||||
AlipayFundFreezeResponse result = payFacade.cancelFundFreeze( request);
|
||||
if(StringUtils.isNotBlank(result.getCode()) && "SUCCESS".equals(result.getCode())){
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} catch (Exception e){
|
||||
log.error("取消免押冻结失败",e);
|
||||
throw new InnerException("取消免押冻结失败");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public AlipayQueryFreezeResponse queryFundFreeze(AlipayQueryFreezeRequest alipayQueryFreezeRequest) {
|
||||
try {
|
||||
AlipayQueryFreezeResponse result = payFacade.queryFundFreeze( alipayQueryFreezeRequest);
|
||||
if(StringUtils.isNotBlank(result.getCode()) && "SUCCESS".equals(result.getCode())){
|
||||
return result;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} catch (Exception e){
|
||||
log.error("查询免押押冻结失败",e);
|
||||
throw new InnerException("查询免押冻结失败");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public AlipayResponse finishFreeze(AlipayFinishFreezeRequest alipayFinishFreezeRequest) {
|
||||
try {
|
||||
AlipayResponse result = payFacade.finishFreeze(alipayFinishFreezeRequest);
|
||||
if(StringUtils.isNotBlank(result.getCode()) && "SUCCESS".equals(result.getCode())){
|
||||
return result;
|
||||
} else {
|
||||
throw new InnerException("完成免押冻结失败");
|
||||
}
|
||||
} catch (Exception e){
|
||||
log.error("完成免押押冻结失败",e);
|
||||
throw new InnerException("完成免押冻结失败");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,6 +6,7 @@ import com.sczx.order.thirdpart.dto.CompanyDTO;
|
||||
import com.sczx.order.thirdpart.dto.CompanyStoreDTO;
|
||||
import com.sczx.order.thirdpart.dto.SysConfigDTO;
|
||||
import com.sczx.order.thirdpart.dto.SysDictDataDTO;
|
||||
import com.sczx.order.thirdpart.dto.req.DistibIncomeReq;
|
||||
import com.sczx.order.thirdpart.facade.StoreFacade;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@ -86,4 +87,36 @@ public class StoreInteg {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 分润收入
|
||||
* @param distibIncomeReq
|
||||
* @return
|
||||
*/
|
||||
public boolean distibIncome(DistibIncomeReq distibIncomeReq){
|
||||
|
||||
try{
|
||||
Result<Boolean> result = storeFacade.distibIncome(distibIncomeReq);
|
||||
if(result.isSuccess()){
|
||||
return result.getData();
|
||||
}
|
||||
} catch (Exception e){
|
||||
log.error("分润收入失败",e);
|
||||
throw new InnerException("分润收入失败");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean recordToken(String storeNumber, String token){
|
||||
try{
|
||||
Result<Boolean> result = storeFacade.recordToken(storeNumber, token);
|
||||
if(result.isSuccess()){
|
||||
return result.getData();
|
||||
}
|
||||
} catch (Exception e){
|
||||
log.error("记录门店token失败",e);
|
||||
throw new InnerException("记录门店token失败");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -18,16 +18,29 @@ public class SyncInteg {
|
||||
public Map<String, String> sendSubOrderId(Long subOrderId){
|
||||
try{
|
||||
Map<String, String> result = syncFacade.sendSubOrderId(subOrderId);
|
||||
if(result.get("code") == "200"){
|
||||
if( "200".equals(result.get("code"))){
|
||||
return result;
|
||||
}else{
|
||||
return result;
|
||||
}
|
||||
} catch (Exception e){
|
||||
log.error("发送租电订单同步失败",e);
|
||||
throw new InnerException("发送租电订单同步失败");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public Map<String, String> sendUserMeal(Long subOrderId){
|
||||
try{
|
||||
Map<String, String> result = syncFacade.sendUserMeal(subOrderId);
|
||||
if( "200".equals(result.get("code"))){
|
||||
return result;
|
||||
}else{
|
||||
return result;
|
||||
}
|
||||
} catch (Exception e){
|
||||
log.error("发送租电订单查询失败",e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,12 +1,14 @@
|
||||
package com.sczx.order.thirdpart.integration;
|
||||
|
||||
import com.sczx.order.common.Result;
|
||||
import com.sczx.order.dto.SimpleUserInfoDTO;
|
||||
import com.sczx.order.exception.InnerException;
|
||||
import com.sczx.order.thirdpart.dto.BaseUserReferralDTO;
|
||||
import com.sczx.order.thirdpart.facade.UserFacade;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
@ -27,4 +29,17 @@ public class UserInteg {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public SimpleUserInfoDTO getUInfoByMobile(String mobile){
|
||||
try{
|
||||
Result<SimpleUserInfoDTO> result = userFacade.getUInfoByMobile(mobile);
|
||||
if(result.isSuccess()){
|
||||
return result.getData();
|
||||
}
|
||||
} catch (Exception e){
|
||||
log.error("获取用户信息失败",e);
|
||||
throw new InnerException("获取用户信息失败");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
107
src/main/java/com/sczx/order/utils/DouyinTokenManager.java
Normal file
107
src/main/java/com/sczx/order/utils/DouyinTokenManager.java
Normal file
@ -0,0 +1,107 @@
|
||||
package com.sczx.order.utils;
|
||||
|
||||
import com.aliyun.tea.TeaException;
|
||||
import com.douyin.openapi.client.Client;
|
||||
import com.douyin.openapi.client.models.OauthClientTokenRequest;
|
||||
import com.douyin.openapi.client.models.OauthClientTokenResponse;
|
||||
import com.douyin.openapi.credential.models.Config;
|
||||
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
/**
|
||||
* 抖音 client_token 管理器
|
||||
* 负责定时获取和缓存 client_token
|
||||
*/
|
||||
public class DouyinTokenManager {
|
||||
|
||||
// 应用凭证信息
|
||||
private static final String CLIENT_KEY = "awomt6nnjlfc491m";
|
||||
private static final String CLIENT_SECRET = "c678c411c7a68c6f97969f2dbd8ef8fc";
|
||||
|
||||
// Token 缓存
|
||||
private static final AtomicReference<OauthClientTokenResponse> tokenCache =
|
||||
new AtomicReference<>();
|
||||
|
||||
// 定时任务执行器
|
||||
private static final ScheduledThreadPoolExecutor scheduler =
|
||||
new ScheduledThreadPoolExecutor(1, r -> {
|
||||
Thread t = new Thread(r, "DouyinTokenRefreshThread");
|
||||
t.setDaemon(false);
|
||||
return t;
|
||||
});
|
||||
|
||||
static {
|
||||
// 初始化时立即获取一次 token
|
||||
refreshClientToken();
|
||||
|
||||
// 每小时更新一次 token (3600秒)
|
||||
scheduler.scheduleAtFixedRate(
|
||||
DouyinTokenManager::refreshClientToken,
|
||||
3600,
|
||||
3600,
|
||||
TimeUnit.SECONDS
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前有效的 client_token
|
||||
*
|
||||
* @return 当前有效的 access_token
|
||||
*/
|
||||
public static String getCurrentToken() {
|
||||
OauthClientTokenResponse response = tokenCache.get();
|
||||
if (response != null && response.getData() != null) {
|
||||
return response.getData().getAccessToken();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新 client_token
|
||||
*/
|
||||
private static void refreshClientToken() {
|
||||
try {
|
||||
Config config = new Config()
|
||||
.setClientKey(CLIENT_KEY)
|
||||
.setClientSecret(CLIENT_SECRET);
|
||||
|
||||
Client client = new Client(config);
|
||||
|
||||
OauthClientTokenRequest sdkRequest = new OauthClientTokenRequest();
|
||||
sdkRequest.setClientKey(CLIENT_KEY);
|
||||
sdkRequest.setClientSecret(CLIENT_SECRET);
|
||||
sdkRequest.setGrantType("client_credential");
|
||||
|
||||
OauthClientTokenResponse sdkResponse = client.OauthClientToken(sdkRequest);
|
||||
|
||||
// 更新缓存
|
||||
tokenCache.set(sdkResponse);
|
||||
|
||||
if (sdkResponse.getData() != null) {
|
||||
System.out.println("抖音 client_token 更新成功,有效期至: " +
|
||||
(System.currentTimeMillis() + sdkResponse.getData().getExpiresIn() * 1000));
|
||||
}
|
||||
} catch (TeaException e) {
|
||||
System.err.println("获取抖音 client_token 失败 (TeaException): " + e.getMessage());
|
||||
} catch (Exception e) {
|
||||
System.err.println("获取抖音 client_token 失败 (Exception): " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭定时任务
|
||||
*/
|
||||
public static void shutdown() {
|
||||
scheduler.shutdown();
|
||||
|
||||
// 获取当前有效的 client_token
|
||||
String token = DouyinTokenManager.getCurrentToken();
|
||||
|
||||
// 使用 token 调用抖音 API
|
||||
if (token != null) {
|
||||
// 调用订单查询等接口
|
||||
}
|
||||
}
|
||||
}
|
||||
86
src/main/java/com/sczx/order/utils/MeiTuanSignUtils.java
Normal file
86
src/main/java/com/sczx/order/utils/MeiTuanSignUtils.java
Normal file
@ -0,0 +1,86 @@
|
||||
package com.sczx.order.utils;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.security.MessageDigest;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
@Slf4j
|
||||
public class MeiTuanSignUtils {
|
||||
private MeiTuanSignUtils() {}
|
||||
|
||||
public static String getSign(String signKey, Map<String, String> params) {
|
||||
try {
|
||||
String sortedStr = getSortedParamStr(params);
|
||||
String paraStr = signKey + sortedStr;
|
||||
|
||||
return createSign(paraStr);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
log.warn("getSign UnsupportedEncodingException ", e);
|
||||
}
|
||||
|
||||
return StringUtils.EMPTY;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造自然排序请求参数
|
||||
*
|
||||
* @param params 请求
|
||||
* @return 字符串
|
||||
*/
|
||||
private static String getSortedParamStr(Map<String, String> params) throws UnsupportedEncodingException {
|
||||
Set<String> sortedParams = new TreeSet<>(params.keySet());
|
||||
|
||||
StringBuilder strB = new StringBuilder();
|
||||
// 排除sign和空值参数
|
||||
for (String key : sortedParams) {
|
||||
if ("sign".equalsIgnoreCase(key)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String value = params.get(key);
|
||||
|
||||
if (StringUtils.isNotEmpty(value)) {
|
||||
strB.append(key).append(value);
|
||||
}
|
||||
}
|
||||
return strB.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成新sign
|
||||
*
|
||||
* @param str 字符串
|
||||
* @return String
|
||||
*/
|
||||
private static String createSign(String str) {
|
||||
if (str == null || str.length() == 0) {
|
||||
return null;
|
||||
}
|
||||
char[] hexDigits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
|
||||
try {
|
||||
MessageDigest mdTemp = MessageDigest.getInstance("SHA1");
|
||||
mdTemp.update(str.getBytes("UTF-8"));
|
||||
|
||||
byte[] md = mdTemp.digest();
|
||||
int j = md.length;
|
||||
char[] buf = new char[j * 2];
|
||||
int k = 0;
|
||||
int i = 0;
|
||||
while (i < j) {
|
||||
byte byte0 = md[i];
|
||||
buf[k++] = hexDigits[byte0 >>> 4 & 0xf];
|
||||
buf[k++] = hexDigits[byte0 & 0xf];
|
||||
i++;
|
||||
}
|
||||
return new String(buf);
|
||||
} catch (Exception e) {
|
||||
log.warn("create sign was failed", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,7 @@
|
||||
package com.sczx.order.utils;
|
||||
|
||||
import com.sczx.order.common.enums.RentCarTypeEnum;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
@ -9,10 +10,12 @@ import java.time.format.DateTimeFormatter;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.UUID;
|
||||
|
||||
@Slf4j
|
||||
public class OrderUtil {
|
||||
|
||||
public static final String ORDER_PREFIX = "OC";
|
||||
|
||||
public static final String MY_PREFIX = "MY";
|
||||
public static final String YJ_PREFIX = "YJ";
|
||||
|
||||
public static final String ZD_PREFIX = "ZD";
|
||||
@ -25,6 +28,10 @@ public class OrderUtil {
|
||||
|
||||
public static final String FD_PREFIX = "FD";
|
||||
|
||||
public static final String FZ_PREFIX = "FZ";
|
||||
|
||||
public static final String FFZ_PREFIX = "FFZ";
|
||||
|
||||
/**
|
||||
* 生成订单号的方法
|
||||
* @return 唯一订单号字符串
|
||||
@ -55,8 +62,10 @@ public class OrderUtil {
|
||||
public static Integer getOrderOverdueHours(LocalDateTime endRentTime) {
|
||||
if(endRentTime!=null){
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
log.info("计算间隔小时数,预计还车时间:{}, 当前时间 : {}", endRentTime, now);
|
||||
if(now.isAfter(endRentTime)){
|
||||
return (int) ChronoUnit.HOURS.between(endRentTime, now);
|
||||
int hours = (int) ChronoUnit.HOURS.between(endRentTime, now);
|
||||
return hours +1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
@ -70,8 +79,14 @@ public class OrderUtil {
|
||||
public static Integer getOrderOverdueDays(LocalDateTime endRentTime) {
|
||||
if(endRentTime!=null){
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
log.info("计算间隔天数,预计还车时间:{}, 当前时间 : {}", endRentTime, now);
|
||||
if(now.isAfter(endRentTime)){
|
||||
return (int) ChronoUnit.DAYS.between(endRentTime, now);
|
||||
long days = ChronoUnit.DAYS.between(endRentTime, now);
|
||||
// 检查是否有不足一天的余数
|
||||
if (!now.truncatedTo(ChronoUnit.DAYS).equals(endRentTime.plusDays(days).truncatedTo(ChronoUnit.DAYS))) {
|
||||
return (int) days + 1;
|
||||
}
|
||||
return (int) days;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
@ -93,6 +108,31 @@ public class OrderUtil {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算间隔时间
|
||||
* @param startTime
|
||||
* @param endTime
|
||||
* @param rentalType
|
||||
* @return
|
||||
*/
|
||||
public static Integer getDuration(LocalDateTime startTime,LocalDateTime endTime,String rentalType) {
|
||||
if(startTime!=null&&endTime!=null){
|
||||
if(startTime.isBefore(endTime)){
|
||||
if(StringUtils.equalsIgnoreCase(rentalType, RentCarTypeEnum.HOUR_RENTAL.getCode())){
|
||||
return (int) ChronoUnit.HOURS.between(startTime, endTime) +1;
|
||||
} else {
|
||||
long days = ChronoUnit.DAYS.between(startTime, endTime) +1;
|
||||
// 检查是否有不足一天的余数
|
||||
if (!endTime.truncatedTo(ChronoUnit.DAYS).equals(endTime.plusDays(days).truncatedTo(ChronoUnit.DAYS))) {
|
||||
return (int) days + 1;
|
||||
}
|
||||
return (int) days;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 计算订单逾期金额
|
||||
@ -114,19 +154,64 @@ public class OrderUtil {
|
||||
* @param rentalType 租期类型
|
||||
* @return 预计还车时间
|
||||
*/
|
||||
public static LocalDateTime getEndRentTime(LocalDateTime origTime,Integer rentalDays, String rentalType) {
|
||||
public static LocalDateTime getEndRentTime(LocalDateTime origTime,Integer rerentInterval,Integer rentalDays, String rentalType) {
|
||||
LocalDateTime endRentTime = null;
|
||||
//设置预计还车时间
|
||||
if(StringUtils.equalsIgnoreCase(RentCarTypeEnum.HOUR_RENTAL.getCode(), rentalType)){
|
||||
endRentTime = origTime.plusHours(1);
|
||||
endRentTime = origTime.plusHours(rerentInterval);
|
||||
}else if(StringUtils.equalsIgnoreCase(RentCarTypeEnum.DAILY_RENTAL.getCode(), rentalType)){
|
||||
endRentTime = origTime.plusDays(1);
|
||||
endRentTime = origTime.plusDays(rerentInterval);
|
||||
} else if(StringUtils.equalsIgnoreCase(RentCarTypeEnum.DAYS_RENTAL.getCode(), rentalType)){
|
||||
endRentTime = origTime.plusDays(rentalDays);
|
||||
endRentTime = origTime.plusDays((long) rerentInterval * rentalDays);
|
||||
} else if(StringUtils.equalsIgnoreCase(RentCarTypeEnum.RENT_INSTEAD_SELL.getCode(), rentalType)){
|
||||
//以租代售默认期限为30天
|
||||
endRentTime = origTime.plusDays(30);
|
||||
endRentTime = origTime.plusDays(rerentInterval*30);
|
||||
}
|
||||
log.info("query endRentTime : {}", endRentTime);
|
||||
return endRentTime;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取租车订单金额
|
||||
* @param rentalType
|
||||
* @param rentalPrice
|
||||
* @param rentalDays
|
||||
* @return
|
||||
*/
|
||||
public static BigDecimal getRentCarAmount(String rentalType, BigDecimal rentalPrice, Integer rentalDays) {
|
||||
// BigDecimal rentCarOrderAmount = new BigDecimal(0);
|
||||
// if(RentCarTypeEnum.HOUR_RENTAL.getCode().equalsIgnoreCase(rentalType)||RentCarTypeEnum.DAILY_RENTAL.getCode().equalsIgnoreCase(rentalType)){
|
||||
// rentCarOrderAmount = rentCarOrderAmount.add(rentalPrice);
|
||||
// } else if(RentCarTypeEnum.DAYS_RENTAL.getCode().equalsIgnoreCase(rentalType)){
|
||||
// rentCarOrderAmount = rentalPrice.multiply(new BigDecimal(rentalDays));
|
||||
// } else {
|
||||
// rentCarOrderAmount = rentalPrice.multiply(new BigDecimal(30));
|
||||
// }
|
||||
return rentalPrice;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取续租订单金额
|
||||
* @param rerentInterval 续租周期
|
||||
* @param rentalPrice
|
||||
* @return
|
||||
*/
|
||||
public static BigDecimal getReRentCarAmount(int rerentInterval,BigDecimal rentalPrice) {
|
||||
//计算续租金额
|
||||
return rentalPrice.multiply(new BigDecimal(rerentInterval));
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算续租轮数以覆盖逾期天数
|
||||
* @param overdueDays 逾期天数
|
||||
* @param rentalDays 每轮续租天数
|
||||
* @return 需要的续租轮数
|
||||
*/
|
||||
public static int calculateRerentRoundsToCoverOverdue(Integer overdueDays, Integer rentalDays) {
|
||||
overdueDays = overdueDays == null|| overdueDays == 0 ? 1 : overdueDays;
|
||||
rentalDays = rentalDays == null|| rentalDays == 0 ? 1 : overdueDays;
|
||||
// 使用向上取整计算需要的续租轮数
|
||||
return (int) Math.ceil((double) overdueDays / rentalDays);
|
||||
}
|
||||
}
|
||||
|
||||
@ -24,6 +24,10 @@ public class RedisUtil {
|
||||
redisTemplate.opsForValue().set(key, value, timeout, unit);
|
||||
}
|
||||
|
||||
public void set(String key, String value) {
|
||||
redisTemplate.opsForValue().set(key, value);
|
||||
}
|
||||
|
||||
public String get(String key) {
|
||||
return redisTemplate.opsForValue().get(key);
|
||||
}
|
||||
|
||||
BIN
src/main/resources/lib/MtOpJavaSDK-1.0-SNAPSHOT.jar
Normal file
BIN
src/main/resources/lib/MtOpJavaSDK-1.0-SNAPSHOT.jar
Normal file
Binary file not shown.
BIN
src/main/resources/lib/sdk-1.0.6.jar
Normal file
BIN
src/main/resources/lib/sdk-1.0.6.jar
Normal file
Binary file not shown.
@ -22,16 +22,16 @@
|
||||
<pattern>${PATTERN}</pattern>
|
||||
</layout>
|
||||
</encoder>
|
||||
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||
<level>WARN</level>
|
||||
<onMatch>DENY</onMatch>
|
||||
<onMismatch>NEUTRAL</onMismatch>
|
||||
</filter>
|
||||
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||
<level>ERROR</level>
|
||||
<onMatch>DENY</onMatch>
|
||||
<onMismatch>NEUTRAL</onMismatch>
|
||||
</filter>
|
||||
<!-- <filter class="ch.qos.logback.classic.filter.LevelFilter">-->
|
||||
<!-- <level>WARN</level>-->
|
||||
<!-- <onMatch>DENY</onMatch>-->
|
||||
<!-- <onMismatch>NEUTRAL</onMismatch>-->
|
||||
<!-- </filter>-->
|
||||
<!-- <filter class="ch.qos.logback.classic.filter.LevelFilter">-->
|
||||
<!-- <level>ERROR</level>-->
|
||||
<!-- <onMatch>DENY</onMatch>-->
|
||||
<!-- <onMismatch>NEUTRAL</onMismatch>-->
|
||||
<!-- </filter>-->
|
||||
</appender>
|
||||
|
||||
<appender name="WARN_FILE_APPENDER" class="ch.qos.logback.core.FileAppender">
|
||||
@ -45,6 +45,18 @@
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<!-- 针对 MyBatis SQL 日志 -->
|
||||
<logger name="org.apache.ibatis" level="DEBUG" additivity="false">
|
||||
<appender-ref ref="INFO_FILE_APPENDER"/>
|
||||
<appender-ref ref="STDOUT"/>
|
||||
</logger>
|
||||
|
||||
<!-- 针对 JDBC SQL 日志 -->
|
||||
<logger name="java.sql" level="DEBUG" additivity="false">
|
||||
<appender-ref ref="INFO_FILE_APPENDER"/>
|
||||
<appender-ref ref="STDOUT"/>
|
||||
</logger>
|
||||
|
||||
<root level="info">
|
||||
<appender-ref ref="INFO_FILE_APPENDER"/>
|
||||
<appender-ref ref="WARN_FILE_APPENDER"/>
|
||||
|
||||
5
src/main/resources/mapper/ElectronicFenceRuleMapper.xml
Normal file
5
src/main/resources/mapper/ElectronicFenceRuleMapper.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.sczx.order.mapper.ElectronicFenceRuleMapper">
|
||||
|
||||
</mapper>
|
||||
@ -6,8 +6,8 @@
|
||||
SELECT
|
||||
store_id,
|
||||
COUNT(*) as total_orders,
|
||||
SUM(CASE WHEN (order_status = 'AUTO_END' OR order_status = 'MANUAL_END') AND DATE_FORMAT(end_order_time, '%Y-%m') = DATE_FORMAT(NOW(), '%Y-%m') THEN 1 ELSE 0 END) as monthly_completed_orders,
|
||||
SUM(CASE WHEN (order_status = 'AUTO_END' OR order_status = 'MANUAL_END') AND DATE_FORMAT(end_order_time, '%Y-%m') = DATE_FORMAT(NOW(), '%Y-%m') THEN order_amount ELSE 0 END) as monthly_order_amount,
|
||||
SUM(CASE WHEN (order_status = 'AUTO_END' OR order_status = 'MANUAL_END') AND DATE_FORMAT(ifnull(end_order_time,act_end_rent_time), '%Y-%m') = DATE_FORMAT(NOW(), '%Y-%m') THEN 1 ELSE 0 END) as monthly_completed_orders,
|
||||
SUM(CASE WHEN (order_status = 'AUTO_END' OR order_status = 'MANUAL_END') AND DATE_FORMAT(ifnull(end_order_time,act_end_rent_time), '%Y-%m') = DATE_FORMAT(NOW(), '%Y-%m') THEN order_amount ELSE 0 END) as monthly_order_amount,
|
||||
COUNT(CASE WHEN order_status = 'WAIT_PICK' THEN 1 END) as pending_pickup_count,
|
||||
COUNT(CASE WHEN order_status = 'WAIT_RETURN' THEN 1 END) as pending_return_count,
|
||||
COUNT(CASE WHEN order_status = 'RENT_OVERDUE' THEN 1 END) as overdue_count
|
||||
@ -82,6 +82,7 @@
|
||||
|
||||
<where>
|
||||
zos.del_flag = '0'
|
||||
and zos.suborder_type = 'RENTBATTEY'
|
||||
and zom.del_flag = '0'
|
||||
<if test="customerId != null">
|
||||
and zom.customer_id = #{customerId}
|
||||
|
||||
5
src/main/resources/mapper/OrderProcessMapper.xml
Normal file
5
src/main/resources/mapper/OrderProcessMapper.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.sczx.order.mapper.OrderProcessMapper">
|
||||
|
||||
</mapper>
|
||||
Reference in New Issue
Block a user