计费规则:默认计算

This commit is contained in:
attiya 2025-05-08 16:31:21 +08:00
parent 55684426b1
commit 8f44c10610
3 changed files with 53 additions and 110 deletions

View File

@ -69,4 +69,13 @@ public class EbikeOrderDetails implements Serializable {
@Column(onInsertValue = "now()")
private LocalDateTime createdAt;
public EbikeOrderDetails(Long orderId, Integer itemType, String itemName, BigDecimal itemAmount, String calculationRule, String couponId, LocalDateTime createdAt) {
this.orderId = orderId;
this.itemType = itemType;
this.itemName = itemName;
this.itemAmount = itemAmount;
this.calculationRule = calculationRule;
this.couponId = couponId;
this.createdAt = createdAt;
}
}

View File

@ -162,6 +162,7 @@ public class UserOrdersServiceImpl extends ServiceImpl<UserOrdersMapper, EbikeUs
FeignEbikeRegionDto regionDto = regionResult.getData();
ResFeignEbikeSysRcostsetDto feignEbikeSysRcostsetDto = operateJsonResult.getData();
//费用计算
costCalculation(feignEbikeSysRcostsetDto, resGpsDto, regionDto, userOrders);
userOrdersMapper.update(userOrders);
//关锁,并且等待结果
@ -346,7 +347,8 @@ public class UserOrdersServiceImpl extends ServiceImpl<UserOrdersMapper, EbikeUs
boolean pointInParking = redisUtil.isPointInParking(resGpsDto.getLongitude(), resGpsDto.getLatitude(), regionDto.getOrgId());
long minutes = TimeUtils.betweenMinutes(userOrders.getStartTime(), userOrders.getEndTime());
//是否取消订单
if (pointInOperation && pointInParking && minutes < feignEbikeSysRcostsetDto.getFreeDuration()) {
Integer freeDuration = feignEbikeSysRcostsetDto.getFreeDuration();
if (pointInOperation && pointInParking && minutes < freeDuration) {
userOrders.setStatus(OrderStatus.CANCELLED);
return;
}
@ -374,7 +376,7 @@ public class UserOrdersServiceImpl extends ServiceImpl<UserOrdersMapper, EbikeUs
list.add(orderDetails);
totalAmount = totalAmount.add(operationAreaSchedulingFee);
}
//时长费用计算
//时长费用计算(已知超出免费时长
Character timeDivisionCharging = feignEbikeSysRcostsetDto.getTimeDivisionCharging();
BigDecimal decimal = switch (timeDivisionCharging) {
case TIME_SLOT -> timeSlotCostCalculation(list, userOrders, feignEbikeSysRcostsetDto);
@ -384,7 +386,7 @@ public class UserOrdersServiceImpl extends ServiceImpl<UserOrdersMapper, EbikeUs
totalAmount = totalAmount.add(decimal);
BigDecimal cappedAmount = feignEbikeSysRcostsetDto.getCappedAmount();
int result = cappedAmount.compareTo(totalAmount);
if (result == 1){
if (result > 0){
totalAmount = cappedAmount;
}
userOrders.setStatus(OrderStatus.PENDING_PAYMENT);
@ -401,7 +403,7 @@ public class UserOrdersServiceImpl extends ServiceImpl<UserOrdersMapper, EbikeUs
* @return 计费后总金额
*/
BigDecimal timeSlotCostCalculation(List<EbikeOrderDetails> list, EbikeUserOrders userOrders, ResFeignEbikeSysRcostsetDto feignEbikeSysRcostsetDto) {
BigDecimal decimal = new BigDecimal(0);
BigDecimal decimal = BigDecimal.ZERO;
//TODO计算起步费用后时间后移
List<TimeSegment> timeSegments = TimeUtils.splitByDays(userOrders.getStartTime(), userOrders.getEndTime());
//TODO:时间划分不同自然时间段每一段才判断在高峰时间段内有多长时间收费多少非高峰期多长时间收费多少
@ -477,7 +479,7 @@ public class UserOrdersServiceImpl extends ServiceImpl<UserOrdersMapper, EbikeUs
* @return 计费后总金额
*/
BigDecimal weekCostCalculation(List<EbikeOrderDetails> list, EbikeUserOrders userOrders, ResFeignEbikeSysRcostsetDto feignEbikeSysRcostsetDto) {
BigDecimal decimal = new BigDecimal(0);
BigDecimal decimal = BigDecimal.ZERO;
LocalDateTime startTime = userOrders.getStartTime();
LocalDateTime endTime = userOrders.getEndTime();
Long orderId = userOrders.getOrderId();
@ -487,113 +489,12 @@ public class UserOrdersServiceImpl extends ServiceImpl<UserOrdersMapper, EbikeUs
for (int i = 0; i < timeSegments.size(); i++) {
TimeSegment timeSegment = timeSegments.get(i);
boolean checked = checkWeek(timeSegment, feignEbikeSysRcostsetDto);
BigDecimal dailiedFee = dailyFee(timeSegment, feignEbikeSysRcostsetDto, i < 1, checked, list, orderId);
BigDecimal dailiedFee = BigDecimal.ZERO;
decimal = decimal.add(dailiedFee);
}
return decimal;
}
/**
* 根据自然时间段计算高峰出行日费用
*
* @param timeSegment 时间段
* @param feignEbikeSysRcostsetDto 计算规则
* @return 金额
*/
BigDecimal dailyFee(TimeSegment timeSegment, ResFeignEbikeSysRcostsetDto feignEbikeSysRcostsetDto, boolean isStart, boolean isWeek, List<EbikeOrderDetails> list, long orderId) {
BigDecimal decimal = new BigDecimal(0);
List<ResFeignEbikeSysRcostsetWeekDto> weekDtos = feignEbikeSysRcostsetDto.getEbikeSysRcostsetWeekDtos();
LocalDateTime startTime = timeSegment.getStart();
String weekNumber = TimeUtils.getDayOfWeekNumber(startTime);
LocalDateTime endTime = timeSegment.getEnd();
long minutes = TimeUtils.betweenMinutes(startTime, endTime);
BigDecimal minutesNew = BigDecimal.valueOf(minutes);
if (isWeek) {
//高峰日出现计算
for (ResFeignEbikeSysRcostsetWeekDto weekCostCalculation : weekDtos) {
//根据符合要求的规则计算费用
if (weekCostCalculation.getWeek().contains(weekNumber)) {
if (isStart) {
EbikeOrderDetails orderDetails = new EbikeOrderDetails();
orderDetails.setOrderId(orderId);
orderDetails.setItemAmount(weekCostCalculation.getStartupCost());
orderDetails.setItemType(OrderDetailsType.TRAVEL_EXPENSES_ON_PEAK_DAYS);
orderDetails.setItemName("高峰日出行费用-起步费用");
orderDetails.setCalculationRule(JSONObject.toJSONString(feignEbikeSysRcostsetDto));
list.add(orderDetails);
Integer startupDuration = weekCostCalculation.getStartupDuration();
if (minutes > startupDuration) {
BigDecimal startupDurationNew = BigDecimal.valueOf(startupDuration);
//超出时长总时长减去起步时长
minutesNew = minutesNew.subtract(startupDurationNew);
}
}
//时长计费
BigDecimal durationCost = weekCostCalculation.getDurationCost();
//时长多久计费一次
Integer duration = weekCostCalculation.getDuration();
//总计费几次向上取整
int ceil = NumberUtils.divideAndCeil(duration, minutesNew.intValue());
BigDecimal ceilCost = BigDecimal.valueOf(ceil);
//最终值
BigDecimal multiply = durationCost.multiply(ceilCost);
EbikeOrderDetails durationCostOrderDetails = new EbikeOrderDetails();
durationCostOrderDetails.setOrderId(orderId);
durationCostOrderDetails.setItemAmount(multiply);
durationCostOrderDetails.setItemType(OrderDetailsType.TRAVEL_EXPENSES_ON_PEAK_DAYS);
durationCostOrderDetails.setItemName("高峰日出行费用-时长计费");
durationCostOrderDetails.setCalculationRule(JSONObject.toJSONString(feignEbikeSysRcostsetDto));
list.add(durationCostOrderDetails);
decimal = decimal.add(multiply);
break;
}
}
} else {
//非高峰出行日计费
if (isStart) {
//起始计费
Integer startupDuration = feignEbikeSysRcostsetDto.getStartupDuration();
BigDecimal startupCost = feignEbikeSysRcostsetDto.getStartupCost();
EbikeOrderDetails orderDetails = new EbikeOrderDetails();
orderDetails.setOrderId(orderId);
orderDetails.setItemAmount(startupCost);
orderDetails.setItemType(OrderDetailsType.STARTING_FEE);
orderDetails.setItemName("起步费用");
orderDetails.setCalculationRule(JSONObject.toJSONString(feignEbikeSysRcostsetDto));
list.add(orderDetails);
decimal = decimal.add(startupCost);
//超出起步时长计费
if (minutes > startupDuration) {
BigDecimal startupDurationNew = BigDecimal.valueOf(startupDuration);
//超出时长
minutesNew = minutesNew.subtract(startupDurationNew);
}
}
//时长计费
BigDecimal durationCost = feignEbikeSysRcostsetDto.getDurationCost();
//时长多久计费一次
Integer duration = feignEbikeSysRcostsetDto.getDuration();
//总计费几次向上取整
int ceil = NumberUtils.divideAndCeil(duration, minutesNew.intValue());
BigDecimal ceilCost = BigDecimal.valueOf(ceil);
//最终值
BigDecimal multiply = durationCost.multiply(ceilCost);
EbikeOrderDetails durationCostOrderDetails = new EbikeOrderDetails();
durationCostOrderDetails.setOrderId(orderId);
durationCostOrderDetails.setItemAmount(multiply);
durationCostOrderDetails.setItemType(OrderDetailsType.CYCLING_DURATION_FEE);
durationCostOrderDetails.setItemName("时长计费");
durationCostOrderDetails.setCalculationRule(JSONObject.toJSONString(feignEbikeSysRcostsetDto));
list.add(durationCostOrderDetails);
decimal = decimal.add(multiply);
}
return decimal;
}
/**
* 检查是否高峰期
@ -622,10 +523,31 @@ public class UserOrdersServiceImpl extends ServiceImpl<UserOrdersMapper, EbikeUs
* @return 计费后总金额
*/
BigDecimal defaultCostCalculation(List<EbikeOrderDetails> list, EbikeUserOrders userOrders, ResFeignEbikeSysRcostsetDto feignEbikeSysRcostsetDto, long orderId) {
BigDecimal decimal = BigDecimal.ZERO;
LocalDateTime startTime = userOrders.getStartTime();
LocalDateTime endTime = userOrders.getEndTime();
//TODO计算起步费用后时间后移
TimeSegment timeSegment = new TimeSegment(startTime, endTime);
return dailyFee(timeSegment, feignEbikeSysRcostsetDto, true, false, list, orderId);
long minutes = TimeUtils.betweenMinutes(startTime, endTime);
BigDecimal startupCost = feignEbikeSysRcostsetDto.getStartupCost();
EbikeOrderDetails startupDetails = new EbikeOrderDetails(orderId,OrderDetailsType.STARTING_FEE,"默认起步费用",startupCost,JSONObject.toJSONString(feignEbikeSysRcostsetDto),null,LocalDateTime.now());
list.add(startupDetails);
decimal = decimal.add(startupCost);
Integer startupDuration = feignEbikeSysRcostsetDto.getStartupDuration();
//判断是否超出起步时长
if (minutes>startupDuration) {
startTime = startTime.plusMinutes(startupDuration);
long newMinutes = TimeUtils.betweenMinutes(startTime, endTime);
Integer duration = feignEbikeSysRcostsetDto.getDuration();
//时长费用
BigDecimal durationCost = feignEbikeSysRcostsetDto.getDurationCost();
int newMinutesInt = NumberUtils.longConvertInt(newMinutes);
int ceil = NumberUtils.divideAndCeil(newMinutesInt, duration);
BigDecimal bigDecimalCeil = BigDecimal.valueOf(ceil);
//总时长费用
BigDecimal multiply = bigDecimalCeil.multiply(durationCost);
EbikeOrderDetails timeDetails = new EbikeOrderDetails(orderId,OrderDetailsType.CYCLING_DURATION_FEE,"默认时长费用",multiply,JSONObject.toJSONString(feignEbikeSysRcostsetDto),null,LocalDateTime.now());
list.add(timeDetails);
decimal = decimal.add(multiply);
}
return decimal;
}
}

View File

@ -23,6 +23,18 @@ public final class NumberUtils {
return (int) Math.ceil((double) dividend / divisor);
}
/**
* 安全的将long转换为int
* @param value long值
* @return int值
*/
public static int longConvertInt(long value) {
if (value < Integer.MIN_VALUE || value > Integer.MAX_VALUE) {
throw new ArithmeticException("大小超出安全值");
}
return (int) value;
}
/**
* 安全转换字符串为整数
* @param str 要转换的字符串