|
@@ -1,14 +1,19 @@
|
|
|
package com.qmrb.parking.fee;
|
|
|
|
|
|
+import cn.hutool.core.date.DateUtil;
|
|
|
+import com.qmrb.system.pojo.entity.ContractPlaceNumberRel;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
import org.apache.commons.lang3.StringUtils;
|
|
|
|
|
|
-import java.math.BigDecimal;
|
|
|
import java.time.Duration;
|
|
|
import java.time.LocalDateTime;
|
|
|
import java.time.LocalTime;
|
|
|
+import java.time.ZoneId;
|
|
|
import java.util.ArrayList;
|
|
|
+import java.util.HashMap;
|
|
|
import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
+
|
|
|
@Slf4j
|
|
|
public class ParkingFeeCalculator {
|
|
|
|
|
@@ -43,6 +48,8 @@ public class ParkingFeeCalculator {
|
|
|
|
|
|
public CouponRecord couponRecord = new CouponRecord();
|
|
|
|
|
|
+ public String contractType;
|
|
|
+
|
|
|
}
|
|
|
|
|
|
|
|
@@ -67,6 +74,7 @@ public class ParkingFeeCalculator {
|
|
|
|
|
|
Duration billingDuration = Duration.between(billingStartTime, billingEndTime);
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
|
for (PaymentRecord payment : parkingRecord.paymentRecords) {
|
|
@@ -139,12 +147,13 @@ public class ParkingFeeCalculator {
|
|
|
if(totalFee<0){
|
|
|
return 0.0;
|
|
|
}
|
|
|
- } else if (StringUtils.equals(couponRecord.couponType,"2")) {
|
|
|
+ }
|
|
|
+
|
|
|
|
|
|
double dicFee = calculateRemainingFeeDue(Duration.ofMinutes(new BigDecimal(couponRecord.denomination).intValue()), feeRule);
|
|
|
log.info("优惠金额: "+dicFee+"元");
|
|
|
return totalFee - dicFee;
|
|
|
- }
|
|
|
+ }*/
|
|
|
return totalFee;
|
|
|
}
|
|
|
|
|
@@ -210,6 +219,40 @@ public class ParkingFeeCalculator {
|
|
|
}
|
|
|
|
|
|
|
|
|
+ * 包租协议测试
|
|
|
+ */
|
|
|
+ public static void e3(){
|
|
|
+
|
|
|
+ FeeRule feeRule = new FeeRule();
|
|
|
+ feeRule.freeDurationMinutes = 0;
|
|
|
+ feeRule.firstCycleFee = 20.0;
|
|
|
+ feeRule.firstCycleDurationMinutes = 60;
|
|
|
+ feeRule.cycleDurationMinutes = 30;
|
|
|
+ feeRule.cycleFee = 2;
|
|
|
+ feeRule.dailyCapFee = 30;
|
|
|
+ feeRule.gracePeriodMinutes = 15;
|
|
|
+
|
|
|
+
|
|
|
+ ParkingRecord parkingRecord = new ParkingRecord();
|
|
|
+ parkingRecord.entryTime = LocalDateTime.of(2025, 3, 28, 14, 0);
|
|
|
+ parkingRecord.exitTime = LocalDateTime.of(2025, 3, 29, 15, 50);
|
|
|
+ parkingRecord.monthlyCardExpiryTime = null;
|
|
|
+
|
|
|
+ parkingRecord.paymentRecords=new ArrayList<>();*/
|
|
|
+
|
|
|
+ paymentRecord.paymentTime = LocalDateTime.of(2025, 3, 14, 10, 0);
|
|
|
+ parkingRecord.paymentRecords.add(paymentRecord);*/
|
|
|
+ List<ContractPlaceNumberRel> registrations = new ArrayList<>();
|
|
|
+ ContractPlaceNumberRel placeNumberRel = new ContractPlaceNumberRel();
|
|
|
+ placeNumberRel.setStartTime(DateUtil.parse("2025-03-28 12:00:00"));
|
|
|
+ placeNumberRel.setEndTime(DateUtil.parse(" 2025-03-29 14:00:00"));
|
|
|
+ registrations.add(placeNumberRel);
|
|
|
+
|
|
|
+ Map<String, Object> result = calculateParkingFee(parkingRecord, feeRule, registrations);
|
|
|
+ System.out.println("停车费用: " + result.toString());
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
* 设【免费时长】=0;【24小时收费金额】=30元;【首周期计费时长】=60分钟;【首周期计费金额】=20元;【计费周期】=30分钟;【每周期计费金额】=2元
|
|
|
*/
|
|
|
public static void e1(){
|
|
@@ -234,11 +277,84 @@ public class ParkingFeeCalculator {
|
|
|
double fee = calculateParkingFee(parkingRecord, feeRule, false);
|
|
|
log.info("停车费用: " + fee + " 元");
|
|
|
}
|
|
|
+
|
|
|
+
|
|
|
+ * 包租协议计算停车费用
|
|
|
+ * @param registrations 车牌登记记录列表(已按车牌筛选)
|
|
|
+ * @return 包含停车时长和费用的Map
|
|
|
+ */
|
|
|
+ public static Map<String, Object> calculateParkingFee(ParkingRecord parkingRecord,FeeRule feeRule,
|
|
|
+ List<ContractPlaceNumberRel> registrations) {
|
|
|
+ LocalDateTime entryTime = parkingRecord.entryTime;
|
|
|
+ LocalDateTime currentTime = LocalDateTime.now();
|
|
|
+ Map<String, Object> result = new HashMap<>();
|
|
|
+
|
|
|
+
|
|
|
+ long totalMinutes = Duration.between(entryTime, currentTime).toMinutes();
|
|
|
+
|
|
|
+
|
|
|
+ long coveredMinutes = calculateCoveredMinutes(entryTime, currentTime, registrations);
|
|
|
+
|
|
|
+
|
|
|
+ long chargedMinutes = Math.max(0, totalMinutes - coveredMinutes);
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ result.put("totalMinutes", totalMinutes);
|
|
|
+ result.put("coveredMinutes", coveredMinutes);
|
|
|
+ result.put("chargedMinutes", chargedMinutes);
|
|
|
+
|
|
|
+ parkingRecord.exitTime = parkingRecord.entryTime.plusMinutes(chargedMinutes);
|
|
|
+ result.put("fee", calculateParkingFee(parkingRecord, feeRule, false));
|
|
|
+ log.info("包租协议收费:"+result.toString());
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ * 计算所有登记记录覆盖的有效时长
|
|
|
+ */
|
|
|
+ private static long calculateCoveredMinutes(LocalDateTime entryTime,
|
|
|
+ LocalDateTime currentTime,
|
|
|
+ List<ContractPlaceNumberRel> registrations) {
|
|
|
+ return registrations.stream()
|
|
|
+ .mapToLong(reg -> calculateSingleRegistrationMinutes(entryTime, currentTime, reg))
|
|
|
+ .sum();
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ * 计算单条登记记录的有效时长
|
|
|
+ */
|
|
|
+ private static long calculateSingleRegistrationMinutes(LocalDateTime entryTime,
|
|
|
+ LocalDateTime currentTime,
|
|
|
+ ContractPlaceNumberRel registration) {
|
|
|
+ LocalDateTime regStartTime = registration.getStartTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
|
|
|
+ LocalDateTime regEndTime = registration.getEndTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
|
|
|
+
|
|
|
+
|
|
|
+ LocalDateTime effectiveStart = regStartTime.isAfter(entryTime)
|
|
|
+ ? regStartTime
|
|
|
+ : entryTime;
|
|
|
+
|
|
|
+
|
|
|
+ LocalDateTime effectiveEnd = regEndTime.isBefore(currentTime)
|
|
|
+ ? regEndTime
|
|
|
+ : currentTime;
|
|
|
+
|
|
|
+
|
|
|
+ if (effectiveStart.isBefore(effectiveEnd)) {
|
|
|
+ return Duration.between(effectiveStart, effectiveEnd).toMinutes();
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
|
|
|
* @param args
|
|
|
*/
|
|
|
public static void main(String[] args) {
|
|
|
|
|
|
- e2();
|
|
|
+
|
|
|
+ e3();
|
|
|
}
|
|
|
}
|