From b0c138f7042946a9a7b76eeb43ff5e49b26689fa Mon Sep 17 00:00:00 2001 From: Guoqs <123456@jsowell.com> Date: Fri, 3 Jul 2026 16:08:17 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AF=B9=E6=8E=A5=E7=A7=91=E6=8B=93=E5=81=9C?= =?UTF-8?q?=E8=BD=A6=E4=BC=98=E6=83=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/科拓停车充电桩抵扣配置指南.md | 150 ++++++++++++++++++ .../parkplatform/ParkingPlatformEnum.java | 1 + .../pile/domain/ThirdpartyParkingConfig.java | 2 +- .../thirdparty/common/CommonService.java | 91 +++++++++++ .../bean/KetuoChargePileDeductionDTO.java | 68 ++++++++ .../parking/service/KetuoService.java | 11 ++ .../service/impl/KetuoServiceImpl.java | 139 ++++++++++++++++ 7 files changed, 461 insertions(+), 1 deletion(-) create mode 100644 docs/科拓停车充电桩抵扣配置指南.md create mode 100644 jsowell-thirdparty/src/main/java/com/jsowell/thirdparty/parking/common/bean/KetuoChargePileDeductionDTO.java create mode 100644 jsowell-thirdparty/src/main/java/com/jsowell/thirdparty/parking/service/KetuoService.java create mode 100644 jsowell-thirdparty/src/main/java/com/jsowell/thirdparty/parking/service/impl/KetuoServiceImpl.java diff --git a/docs/科拓停车充电桩抵扣配置指南.md b/docs/科拓停车充电桩抵扣配置指南.md new file mode 100644 index 000000000..6a38f5132 --- /dev/null +++ b/docs/科拓停车充电桩抵扣配置指南.md @@ -0,0 +1,150 @@ +# 科拓停车充电桩抵扣配置指南 + +本文用于配置科拓停车系统 2.5.4 充电桩抵扣接口。配置完成后,订单满足站点停车优惠条件时,系统会向科拓下发 `syncChargePilePay` 抵扣请求。 + +## 一、停车场平台配置 + +数据表:`thirdparty_parking_config` + +| 字段 | 是否必填 | 科拓配置说明 | +| --- | --- | --- | +| `parking_name` | 建议填 | 停车场/商户名称,便于后台识别。 | +| `platform_type` | 是 | 科拓固定填 `4`。 | +| `app_id` | 是 | 科拓分配的 `appId`。 | +| `secret_key` | 是 | 科拓分配的 `appSercert`,用于生成请求体 `key`。 | +| `park_id` | 是 | 科拓分配的车场 ID。 | +| `api_url` | 是 | 科拓接口地址。可填接口基址,如 `https://IP:端口`;也可填完整地址 `https://IP:端口/api/wec/SyncChargePilePay`。 | +| `org_id` | 否 | qcyun 使用,科拓不用。 | +| `del_flag` | 是 | 正常数据填 `0`。 | + +示例: + +```sql +insert into thirdparty_parking_config ( + parking_name, + platform_type, + app_id, + secret_key, + park_id, + api_url, + create_time, + create_by, + del_flag +) values ( + '示例科拓停车场', + '4', + '10038', + 'KETUO_APP_SECRET', + '592011253', + 'https://IP:端口', + now(), + 'admin', + '0' +); +``` + +## 二、站点绑定停车场配置 + +数据表:`pile_station_info` + +```sql +update pile_station_info +set parking_id = 'thirdparty_parking_config.id' +where id = '站点ID'; +``` + +后台接口同样可用: + +```http +POST /pile/station/bindParkingPlatform +``` + +请求体: + +```json +{ + "stationId": "站点ID", + "parkingId": "thirdparty_parking_config.id" +} +``` + +## 三、站点停车优惠规则 + +数据表:`charge_parking_discount` + +| 字段 | 是否必填 | 说明 | +| --- | --- | --- | +| `station_id` | 是 | 站点 ID。 | +| `parking_platform_id` | 是 | 科拓固定填 `4`。 | +| `condition_type` | 是 | 发券门槛类型:`1` 固定电量;`2` 固定时长。 | +| `condition_value` | 是 | 门槛值。电量单位度,时长单位分钟。 | +| `discount_type` | 是 | 优惠类型:`1` 减时间;`2` 减金额。 | +| `discount_value` | 是 | 优惠值。减时间单位分钟,系统下发科拓时会转成秒;减金额单位元,系统下发科拓时会转成分。 | +| `start_time` | 是 | 优惠生效开始时间。 | +| `end_time` | 是 | 优惠生效结束时间。 | +| `del_flag` | 是 | 正常数据填 `0`。 | + +示例:充电满 10 度,抵扣 120 分钟停车时长。 + +```sql +insert into charge_parking_discount ( + station_id, + parking_platform_id, + condition_type, + condition_value, + discount_type, + discount_value, + start_time, + end_time, + create_time, + create_by, + del_flag +) values ( + '站点ID', + 4, + '1', + '10', + '1', + '120', + '00:00:00', + '23:59:00', + now(), + 'admin', + '0' +); +``` + +## 四、下发给科拓的数据来源 + +| 科拓字段 | 当前系统取值 | +| --- | --- | +| `orderNo` | `order_basic_info.order_code` | +| `plateNo` | `order_basic_info.plate_number` | +| `startTime` | `order_basic_info.charge_start_time`,为空时用订单创建时间 | +| `endTime` | `order_basic_info.charge_end_time`,为空时用当前时间 | +| `stationId` | `order_basic_info.station_id` | +| `stationName` | `pile_station_info.station_name` | +| `deviceId` | `order_basic_info.pile_sn` | +| `deviceName` | `pile_basic_info.name`,为空时用桩 SN | +| `spaceNo` | `pile_connector_info.park_no`,为空时用 `0` | +| `power` | 实时数据 `chargingDegree`,保留 2 位小数 | +| `totalMoney` | 实时数据 `chargingAmount`,元转分 | +| `elecMoney` | 当前填 `0` | +| `seviceMoney` | 当前填 `totalMoney` | +| `freeType` | 固定填 `0`,按 `freeMoney/freeTime` 减免 | +| `freeMoney` | 金额优惠时取优惠金额并元转分;时长优惠时为 `0` | +| `freeTime` | 时长优惠时取优惠分钟并转秒;金额优惠时为 `0` | + +## 五、生效条件 + +沿用现有充电停车优惠链路: + +1. 订单有车牌号。 +2. 站点存在 `charge_parking_discount` 有效配置。 +3. 订单创建时间在优惠时间段内。 +4. 订单实时充电电量或充电时长满足门槛。 +5. 同一订单未在 `car_coupon_record` 写入过发券记录。 +6. 优惠规则 `parking_platform_id = 4`。 +7. 站点绑定的 `thirdparty_parking_config.platform_type = '4'`。 +8. 科拓配置 `app_id`、`secret_key`、`park_id`、`api_url` 不为空。 + diff --git a/jsowell-common/src/main/java/com/jsowell/common/enums/parkplatform/ParkingPlatformEnum.java b/jsowell-common/src/main/java/com/jsowell/common/enums/parkplatform/ParkingPlatformEnum.java index 8665a2a81..734414c04 100644 --- a/jsowell-common/src/main/java/com/jsowell/common/enums/parkplatform/ParkingPlatformEnum.java +++ b/jsowell-common/src/main/java/com/jsowell/common/enums/parkplatform/ParkingPlatformEnum.java @@ -10,6 +10,7 @@ public enum ParkingPlatformEnum { LU_TONG_YUN_TING_PLATFORM("1", "路通云停停车平台"), RUAN_JIE_PLATFORM("2", "软杰停车平台"), SHEN_ZHEN_PLATFORM("3", "深圳停车道闸平台"), + KE_TUO_PLATFORM("4", "科拓停车平台"), ; private String code; diff --git a/jsowell-pile/src/main/java/com/jsowell/pile/domain/ThirdpartyParkingConfig.java b/jsowell-pile/src/main/java/com/jsowell/pile/domain/ThirdpartyParkingConfig.java index 345d658e7..e87bf8bf2 100644 --- a/jsowell-pile/src/main/java/com/jsowell/pile/domain/ThirdpartyParkingConfig.java +++ b/jsowell-pile/src/main/java/com/jsowell/pile/domain/ThirdpartyParkingConfig.java @@ -27,7 +27,7 @@ public class ThirdpartyParkingConfig { private String parkingName; /** - * 停车平台类型(1-路通云停;2-软杰;3-qcyun) + * 停车平台类型(1-路通云停;2-软杰;3-qcyun;4-科拓) */ private String platformType; diff --git a/jsowell-thirdparty/src/main/java/com/jsowell/thirdparty/common/CommonService.java b/jsowell-thirdparty/src/main/java/com/jsowell/thirdparty/common/CommonService.java index c3f4a96b2..aef51f4e6 100644 --- a/jsowell-thirdparty/src/main/java/com/jsowell/thirdparty/common/CommonService.java +++ b/jsowell-thirdparty/src/main/java/com/jsowell/thirdparty/common/CommonService.java @@ -17,6 +17,8 @@ import com.jsowell.common.util.StringUtils; import com.jsowell.pile.domain.CarCouponRecord; import com.jsowell.pile.domain.OrderBasicInfo; import com.jsowell.pile.domain.PileBasicInfo; +import com.jsowell.pile.domain.PileConnectorInfo; +import com.jsowell.pile.domain.PileStationInfo; import com.jsowell.pile.domain.ThirdPartyStationRelation; import com.jsowell.pile.dto.PushRealTimeInfoDTO; import com.jsowell.pile.dto.PushStationInfoDTO; @@ -34,6 +36,8 @@ import com.jsowell.thirdparty.huawei.HuaweiServiceV2; import com.jsowell.thirdparty.lianlian.service.LianLianService; import com.jsowell.thirdparty.nanrui.service.NRService; import com.jsowell.thirdparty.parking.common.bean.QcyunParkCouponDTO; +import com.jsowell.thirdparty.parking.common.bean.KetuoChargePileDeductionDTO; +import com.jsowell.thirdparty.parking.service.KetuoService; import com.jsowell.thirdparty.parking.service.LTYTService; import com.jsowell.thirdparty.parking.service.QcyunsService; import com.jsowell.thirdparty.parking.service.RJService; @@ -54,6 +58,7 @@ import org.springframework.stereotype.Service; import java.io.UnsupportedEncodingException; import java.math.BigDecimal; +import java.math.RoundingMode; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.security.spec.InvalidKeySpecException; @@ -112,6 +117,12 @@ public class CommonService { @Autowired private QcyunsService qcyunsService; + @Autowired + private KetuoService ketuoService; + + @Autowired + private PileConnectorInfoService pileConnectorInfoService; + @Autowired private HuaweiServiceV2 huaweiServiceV2; @@ -827,6 +838,11 @@ public class CommonService { .discountValue(chargeParkingDiscount.getDiscountValue()) .build(); discountFlag = qcyunsService.issuanceOfParkingTickets(dto); + } else if (StringUtils.equals(ParkingPlatformEnum.KE_TUO_PLATFORM.getCode(), parkingPlatformId)) { + // 科拓--充电桩抵扣 + KetuoChargePileDeductionDTO dto = buildKetuoChargePileDeductionDTO( + realTimeMonitorData, orderBasicInfo, chargeParkingDiscount); + discountFlag = ketuoService.syncChargePilePay(dto); } if (discountFlag) { @@ -842,6 +858,81 @@ public class CommonService { } } + private KetuoChargePileDeductionDTO buildKetuoChargePileDeductionDTO(RealTimeMonitorData realTimeMonitorData, + OrderBasicInfo orderBasicInfo, + ChargeParkingDiscountVO chargeParkingDiscount) { + PileStationInfo stationInfo = pileStationInfoService.selectPileStationInfoById(Long.parseLong(orderBasicInfo.getStationId())); + PileBasicInfo pileBasicInfo = pileBasicInfoService.selectPileBasicInfoBySN(orderBasicInfo.getPileSn()); + PileConnectorInfo connectorInfo = getPileConnectorInfo(orderBasicInfo); + + Integer totalMoney = yuanToFen(realTimeMonitorData.getChargingAmount()); + Integer freeMoney = Constants.TWO.equals(String.valueOf(chargeParkingDiscount.getDiscountType())) + ? yuanToFen(chargeParkingDiscount.getDiscountValue()) + : 0; + Integer freeTime = Constants.ONE.equals(String.valueOf(chargeParkingDiscount.getDiscountType())) + ? minutesToSeconds(chargeParkingDiscount.getDiscountValue()) + : 0; + + return KetuoChargePileDeductionDTO.builder() + .stationId(orderBasicInfo.getStationId()) + .orderNo(orderBasicInfo.getOrderCode()) + .plateNo(orderBasicInfo.getPlateNumber()) + .startTime(formatDateTime(orderBasicInfo.getChargeStartTime(), orderBasicInfo.getCreateTime())) + .endTime(formatDateTime(orderBasicInfo.getChargeEndTime(), new java.util.Date())) + .stationName(stationInfo == null ? orderBasicInfo.getStationId() : stationInfo.getStationName()) + .deviceId(orderBasicInfo.getPileSn()) + .deviceName(pileBasicInfo == null || StringUtils.isBlank(pileBasicInfo.getName()) + ? orderBasicInfo.getPileSn() : pileBasicInfo.getName()) + .spaceNo(connectorInfo == null || StringUtils.isBlank(connectorInfo.getParkNo()) + ? "0" : connectorInfo.getParkNo()) + .power(formatPower(realTimeMonitorData.getChargingDegree())) + .elecMoney(0) + .seviceMoney(totalMoney) + .totalMoney(totalMoney) + .freeType(0) + .freeMoney(freeMoney) + .freeTime(freeTime) + .build(); + } + + private PileConnectorInfo getPileConnectorInfo(OrderBasicInfo orderBasicInfo) { + if (StringUtils.isBlank(orderBasicInfo.getPileConnectorCode())) { + return null; + } + PileConnectorInfo query = new PileConnectorInfo(); + query.setPileConnectorCode(orderBasicInfo.getPileConnectorCode()); + List connectorInfoList = pileConnectorInfoService.selectPileConnectorInfoList(query); + if (CollectionUtils.isNotEmpty(connectorInfoList)) { + return connectorInfoList.get(0); + } + return null; + } + + private String formatDateTime(java.util.Date date, java.util.Date defaultDate) { + return DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, date == null ? defaultDate : date); + } + + private String formatPower(String power) { + if (StringUtils.isBlank(power)) { + return "0.00"; + } + return new BigDecimal(power).setScale(2, RoundingMode.HALF_UP).toPlainString(); + } + + private Integer yuanToFen(String amount) { + if (StringUtils.isBlank(amount)) { + return 0; + } + return new BigDecimal(amount).multiply(new BigDecimal("100")).setScale(0, RoundingMode.HALF_UP).intValue(); + } + + private Integer minutesToSeconds(String minutes) { + if (StringUtils.isBlank(minutes)) { + return 0; + } + return new BigDecimal(minutes).multiply(new BigDecimal("60")).setScale(0, RoundingMode.HALF_UP).intValue(); + } + /** * 统一请求启动充电,目前给华为平台用 * @param dto diff --git a/jsowell-thirdparty/src/main/java/com/jsowell/thirdparty/parking/common/bean/KetuoChargePileDeductionDTO.java b/jsowell-thirdparty/src/main/java/com/jsowell/thirdparty/parking/common/bean/KetuoChargePileDeductionDTO.java new file mode 100644 index 000000000..f1866731d --- /dev/null +++ b/jsowell-thirdparty/src/main/java/com/jsowell/thirdparty/parking/common/bean/KetuoChargePileDeductionDTO.java @@ -0,0 +1,68 @@ +package com.jsowell.thirdparty.parking.common.bean; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 科拓充电桩抵扣 DTO. + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class KetuoChargePileDeductionDTO { + private String stationId; + + private String orderNo; + + private String plateNo; + + private String startTime; + + private String endTime; + + private String stationName; + + private String deviceId; + + private String deviceName; + + private String spaceNo; + + /** + * 充电量,单位度,小数点后 2 位。 + */ + private String power; + + /** + * 电费,单位分。 + */ + private Integer elecMoney; + + /** + * 服务费/附加费,单位分。科拓接口字段名为 seviceMoney。 + */ + private Integer seviceMoney; + + /** + * 总费用,单位分。 + */ + private Integer totalMoney; + + /** + * 0: 根据 freeMoney/freeTime 减免; 1: 本地车场配置减免规则。 + */ + private Integer freeType; + + /** + * 减免停车金额,单位分。 + */ + private Integer freeMoney; + + /** + * 减免停车时长,单位秒。 + */ + private Integer freeTime; +} diff --git a/jsowell-thirdparty/src/main/java/com/jsowell/thirdparty/parking/service/KetuoService.java b/jsowell-thirdparty/src/main/java/com/jsowell/thirdparty/parking/service/KetuoService.java new file mode 100644 index 000000000..ae95b0c11 --- /dev/null +++ b/jsowell-thirdparty/src/main/java/com/jsowell/thirdparty/parking/service/KetuoService.java @@ -0,0 +1,11 @@ +package com.jsowell.thirdparty.parking.service; + +import com.jsowell.thirdparty.parking.common.bean.KetuoChargePileDeductionDTO; + +public interface KetuoService { + + /** + * 科拓--充电桩抵扣。 + */ + boolean syncChargePilePay(KetuoChargePileDeductionDTO dto); +} diff --git a/jsowell-thirdparty/src/main/java/com/jsowell/thirdparty/parking/service/impl/KetuoServiceImpl.java b/jsowell-thirdparty/src/main/java/com/jsowell/thirdparty/parking/service/impl/KetuoServiceImpl.java new file mode 100644 index 000000000..d1d48d615 --- /dev/null +++ b/jsowell-thirdparty/src/main/java/com/jsowell/thirdparty/parking/service/impl/KetuoServiceImpl.java @@ -0,0 +1,139 @@ +package com.jsowell.thirdparty.parking.service.impl; + +import cn.hutool.http.HttpUtil; +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONObject; +import com.jsowell.common.enums.parkplatform.ParkingPlatformEnum; +import com.jsowell.common.util.StringUtils; +import com.jsowell.common.util.id.UUID; +import com.jsowell.common.util.sign.MD5Util; +import com.jsowell.pile.domain.ThirdpartyParkingConfig; +import com.jsowell.pile.service.ThirdPartyParkingConfigService; +import com.jsowell.thirdparty.parking.common.bean.KetuoChargePileDeductionDTO; +import com.jsowell.thirdparty.parking.service.KetuoService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.Map; +import java.util.TreeMap; + +@Slf4j +@Service +public class KetuoServiceImpl implements KetuoService { + + private static final String SERVICE_CODE_SYNC_CHARGE_PILE_PAY = "syncChargePilePay"; + + private static final String API_PATH_SYNC_CHARGE_PILE_PAY = "/api/wec/SyncChargePilePay"; + + @Autowired + private ThirdPartyParkingConfigService thirdPartyParkingConfigService; + + @Override + public boolean syncChargePilePay(KetuoChargePileDeductionDTO dto) { + ThirdpartyParkingConfig parkingConfig = resolveParkingConfig(dto); + if (parkingConfig == null) { + return false; + } + JSONObject requestBody = buildRequestBody(dto, parkingConfig); + requestBody.put("key", generateKey(requestBody, parkingConfig.getSecretKey())); + + String requestUrl = getRequestUrl(parkingConfig); + log.info("科拓充电桩抵扣 requestUrl:{}, requestBody:{}", requestUrl, requestBody.toJSONString()); + String result = HttpUtil.post(requestUrl, requestBody.toJSONString()); + if (StringUtils.isBlank(result)) { + log.warn("科拓充电桩抵扣返回为空, requestBody:{}", requestBody.toJSONString()); + return false; + } + JSONObject response = JSON.parseObject(result); + log.info("科拓充电桩抵扣 response:{}", JSON.toJSONString(response)); + return StringUtils.equals("0", response.getString("resCode")); + } + + private ThirdpartyParkingConfig resolveParkingConfig(KetuoChargePileDeductionDTO dto) { + if (dto == null || StringUtils.isBlank(dto.getStationId())) { + log.warn("科拓充电桩抵扣失败, stationId为空, dto:{}", JSON.toJSONString(dto)); + return null; + } + ThirdpartyParkingConfig parkingConfig = thirdPartyParkingConfigService.selectByStationId(dto.getStationId()); + if (parkingConfig == null) { + log.warn("科拓充电桩抵扣失败, 站点未绑定停车场配置, stationId:{}", dto.getStationId()); + return null; + } + if (!StringUtils.equals(ParkingPlatformEnum.KE_TUO_PLATFORM.getCode(), parkingConfig.getPlatformType())) { + log.warn("科拓充电桩抵扣失败, 站点绑定的停车平台类型不是科拓, stationId:{}, parkingConfigId:{}, platformType:{}", + dto.getStationId(), parkingConfig.getId(), parkingConfig.getPlatformType()); + return null; + } + if (StringUtils.isBlank(parkingConfig.getAppId()) + || StringUtils.isBlank(parkingConfig.getSecretKey()) + || StringUtils.isBlank(parkingConfig.getParkId())) { + log.warn("科拓充电桩抵扣失败, 停车场配置缺少appId/secretKey/parkId, stationId:{}, parkingConfigId:{}", + dto.getStationId(), parkingConfig.getId()); + return null; + } + if (StringUtils.isBlank(parkingConfig.getApiUrl())) { + log.warn("科拓充电桩抵扣失败, 停车场配置缺少apiUrl, stationId:{}, parkingConfigId:{}", + dto.getStationId(), parkingConfig.getId()); + return null; + } + return parkingConfig; + } + + private JSONObject buildRequestBody(KetuoChargePileDeductionDTO dto, ThirdpartyParkingConfig parkingConfig) { + JSONObject requestBody = new JSONObject(); + requestBody.put("appId", parkingConfig.getAppId()); + requestBody.put("parkId", parkingConfig.getParkId()); + requestBody.put("serviceCode", SERVICE_CODE_SYNC_CHARGE_PILE_PAY); + requestBody.put("ts", System.currentTimeMillis()); + requestBody.put("reqId", UUID.randomUUID().toString().replace("-", "")); + requestBody.put("orderNo", dto.getOrderNo()); + requestBody.put("plateNo", dto.getPlateNo()); + requestBody.put("startTime", dto.getStartTime()); + requestBody.put("endTime", dto.getEndTime()); + requestBody.put("stationId", dto.getStationId()); + requestBody.put("stationName", dto.getStationName()); + requestBody.put("deviceId", dto.getDeviceId()); + requestBody.put("deviceName", dto.getDeviceName()); + requestBody.put("spaceNo", dto.getSpaceNo()); + requestBody.put("power", dto.getPower()); + requestBody.put("elecMoney", dto.getElecMoney()); + requestBody.put("seviceMoney", dto.getSeviceMoney()); + requestBody.put("totalMoney", dto.getTotalMoney()); + requestBody.put("freeType", dto.getFreeType()); + requestBody.put("freeMoney", dto.getFreeMoney()); + requestBody.put("freeTime", dto.getFreeTime()); + return requestBody; + } + + private String generateKey(JSONObject requestBody, String appSecret) { + TreeMap params = new TreeMap<>(); + requestBody.entrySet().stream() + .filter(entry -> !"key".equals(entry.getKey()) && !"appId".equals(entry.getKey())) + .filter(entry -> entry.getValue() != null) + .filter(entry -> !(entry.getValue() instanceof Map) && !(entry.getValue() instanceof Iterable)) + .filter(entry -> !StringUtils.equals("", entry.getValue().toString())) + .forEach(entry -> params.put(entry.getKey(), entry.getValue().toString())); + + StringBuilder signContent = new StringBuilder(); + for (Map.Entry entry : params.entrySet()) { + if (signContent.length() > 0) { + signContent.append("&"); + } + signContent.append(entry.getKey()).append("=").append(entry.getValue()); + } + signContent.append("&").append(appSecret); + return MD5Util.MD5Encode(signContent.toString()).toUpperCase(); + } + + private String getRequestUrl(ThirdpartyParkingConfig parkingConfig) { + String apiUrl = parkingConfig.getApiUrl(); + if (apiUrl.endsWith(API_PATH_SYNC_CHARGE_PILE_PAY)) { + return apiUrl; + } + while (apiUrl.endsWith("/")) { + apiUrl = apiUrl.substring(0, apiUrl.length() - 1); + } + return apiUrl + API_PATH_SYNC_CHARGE_PILE_PAY; + } +}