|
|
@@ -2,7 +2,6 @@ package com.skyversation.xjcy.counter;
|
|
|
|
|
|
import com.alibaba.fastjson.JSONObject;
|
|
|
import lombok.AllArgsConstructor;
|
|
|
-import lombok.Getter;
|
|
|
|
|
|
import java.math.BigDecimal;
|
|
|
import java.time.Instant;
|
|
|
@@ -15,14 +14,18 @@ import java.util.stream.Collectors;
|
|
|
import java.util.stream.Stream;
|
|
|
|
|
|
public class DataPreCounter {
|
|
|
+
|
|
|
+ public static final Object LOCK = new Object();
|
|
|
+
|
|
|
/**
|
|
|
* 注意输入的数据有副作用
|
|
|
* @param allPark 所有参与的park数据,为避免数据不完整,请提供整个产业园的数据
|
|
|
* @param allLease 所有参与的租赁,提供所有涉及的房间的所有数据即可,如果数据出现房间级的不完整,就会导致结果有误
|
|
|
*/
|
|
|
- public DataPreCounter(List<JSONObject> allPark, List<JSONObject> allLease) {
|
|
|
- this.parkNeedUpload = new HashSet<>();
|
|
|
- this.leaseNeedUpload = new HashSet<>();
|
|
|
+ public DataPreCounter(List<JSONObject> allPark, List<JSONObject> allLease, LocalDate now) {
|
|
|
+ this.now = now;
|
|
|
+ this.parkNeedUploadId = new HashSet<>();
|
|
|
+ this.leaseNeedUploadId = new HashSet<>();
|
|
|
this.allPark = allPark;
|
|
|
this.allLease = allLease;
|
|
|
allLy = new ArrayList<>();
|
|
|
@@ -50,6 +53,19 @@ public class DataPreCounter {
|
|
|
});
|
|
|
}
|
|
|
|
|
|
+ public Set<JSONObject> getRoomsWithCode(Collection<String> roomCodes){
|
|
|
+ return allRoom.stream()
|
|
|
+ .filter(v->roomCodes.contains(v.getString(String.valueOf(ParkKey.c_park_code))))
|
|
|
+ .collect(Collectors.toSet());
|
|
|
+ }
|
|
|
+
|
|
|
+ public List<JSONObject> getParkNeedUpload() {
|
|
|
+ return allPark.stream().filter(v->parkNeedUploadId.contains(v.getString("id"))).collect(Collectors.toList());
|
|
|
+ }
|
|
|
+
|
|
|
+ public List<JSONObject> getLeaseNeedUpload() {
|
|
|
+ return allLease.stream().filter(v->leaseNeedUploadId.contains(v.getString("id"))).collect(Collectors.toList());
|
|
|
+ }
|
|
|
private enum LeaseKey {
|
|
|
c_room_code, c_enterprise_code, c_start_date, c_end_date, c_lease_purpose, c_is_latest_lease, c_lease_status, update_time, c_enterprise_name
|
|
|
}
|
|
|
@@ -102,10 +118,8 @@ public class DataPreCounter {
|
|
|
|
|
|
}
|
|
|
|
|
|
- @Getter
|
|
|
- private final Set<JSONObject> parkNeedUpload;
|
|
|
- @Getter
|
|
|
- private final Set<JSONObject> leaseNeedUpload;
|
|
|
+ private final Set<String> parkNeedUploadId;
|
|
|
+ private final Set<String> leaseNeedUploadId;
|
|
|
private final List<JSONObject> allPark;
|
|
|
private final List<JSONObject> allLy;
|
|
|
private final List<JSONObject> allLd;
|
|
|
@@ -113,29 +127,33 @@ public class DataPreCounter {
|
|
|
private final List<JSONObject> allRoom;
|
|
|
private final List<JSONObject> allLease;
|
|
|
|
|
|
- private final LocalDateTime now = LocalDateTime.now();
|
|
|
+
|
|
|
+
|
|
|
+ private final LocalDate now ;
|
|
|
|
|
|
/**
|
|
|
* 运行预统计,有副作用,注意只能运行提供了租赁数据的房间,你可以从parkNeedUpload和leaseNeedUpload中获取所有更新过的数据
|
|
|
* @param roomRange 统计的范围
|
|
|
*/
|
|
|
public void run(Collection<JSONObject> roomRange){
|
|
|
- if (roomRange==null) {
|
|
|
- roomRange = allRoom;
|
|
|
+ synchronized (LOCK) {
|
|
|
+ if (roomRange==null) {
|
|
|
+ roomRange = allRoom;
|
|
|
+ }
|
|
|
+ //更新并检查所有需更新房间
|
|
|
+ List<JSONObject> updatedRooms = roomRange.stream()
|
|
|
+ .filter(this::countRoom).collect(Collectors.toList());
|
|
|
+ //按层级统计面积
|
|
|
+ //楼层
|
|
|
+ List<JSONObject> fatherLcs = findFathers(updatedRooms,allLc);
|
|
|
+ //楼栋
|
|
|
+ List<JSONObject> fatherLds = findFathers(fatherLcs,allLd);
|
|
|
+ //楼宇/产业园
|
|
|
+ List<JSONObject> fatherLys = findFathers(fatherLds,allLy);
|
|
|
+ fatherLds.forEach(this::countParkByChild);
|
|
|
+ fatherLcs.forEach(this::countParkByChild);
|
|
|
+ fatherLys.forEach(this::countParkByChild);
|
|
|
}
|
|
|
- //更新并检查所有需更新房间
|
|
|
- List<JSONObject> updatedRooms = roomRange.stream()
|
|
|
- .filter(this::countRoom).collect(Collectors.toList());
|
|
|
- //按层级统计面积
|
|
|
- //楼层
|
|
|
- Set<JSONObject> fatherLcs = findFathers(updatedRooms,allLc);
|
|
|
- fatherLcs.forEach(this::countParkByChild);
|
|
|
- //楼栋
|
|
|
- Set<JSONObject> fatherLds = findFathers(fatherLcs,allLd);
|
|
|
- fatherLds.forEach(this::countParkByChild);
|
|
|
- //楼宇/产业园
|
|
|
- Set<JSONObject> fatherLys = findFathers(fatherLds,allLy);
|
|
|
- fatherLys.forEach(this::countParkByChild);
|
|
|
|
|
|
}
|
|
|
/**
|
|
|
@@ -145,13 +163,13 @@ public class DataPreCounter {
|
|
|
run(allRoom);
|
|
|
}
|
|
|
|
|
|
- private Set<JSONObject> findFathers(Collection<JSONObject> children,List<JSONObject> fatherRange) {
|
|
|
+ private List<JSONObject> findFathers(Collection<JSONObject> children,List<JSONObject> fatherRange) {
|
|
|
Set<String> fatherCode= children.stream()
|
|
|
.map(v->v.getString(String.valueOf(ParkKey.c_parent_code)))
|
|
|
.collect(Collectors.toSet());
|
|
|
return fatherRange.stream()
|
|
|
.filter(v->fatherCode.contains(v.getString(String.valueOf(ParkKey.c_park_code))))
|
|
|
- .collect(Collectors.toSet());
|
|
|
+ .collect(Collectors.toList());
|
|
|
}
|
|
|
/**
|
|
|
* 预计算单房间与相关租赁,会修改输入值,会自动统计变动对象
|
|
|
@@ -173,53 +191,56 @@ public class DataPreCounter {
|
|
|
boolean shouldLeaseUpdateFlag = shouldLeaseUpdate(oldWorkingLeases, newWorkingLease);
|
|
|
|
|
|
if (shouldLeaseUpdateFlag) {
|
|
|
-
|
|
|
//更新lease last指示数的状态
|
|
|
updateLeaseLast(newWorkingLease, oldWorkingLeases);
|
|
|
+ }
|
|
|
|
|
|
- //更新房间状态
|
|
|
- updateRoomLease(room, newWorkingLease);
|
|
|
-
|
|
|
+ //评估房间是否需要更新
|
|
|
+ boolean shouldRoomUpdateFlag = shouldRoomUpdate(room,newWorkingLease);
|
|
|
+ if(shouldRoomUpdateFlag){
|
|
|
+ updateRoomLease(room,newWorkingLease);
|
|
|
return true;
|
|
|
}
|
|
|
+
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
+
|
|
|
private void updateRoomLease(JSONObject room, JSONObject lease) {
|
|
|
- if (lease == null) {
|
|
|
+ if (lease == null||!checkLeaseWorking(lease)) {
|
|
|
//绑定企业信息
|
|
|
updateStringValue(room,
|
|
|
String.valueOf(ParkKey.c_zlqymc),
|
|
|
null,
|
|
|
- parkNeedUpload);
|
|
|
+ parkNeedUploadId);
|
|
|
updateStringValue(room,
|
|
|
String.valueOf(ParkKey.c_zlqydm),
|
|
|
null,
|
|
|
- parkNeedUpload);
|
|
|
+ parkNeedUploadId);
|
|
|
//更新房间状态
|
|
|
- updateStringValue(room, String.valueOf(ParkKey.c_room_status), "1", parkNeedUpload);
|
|
|
+ updateStringValue(room, String.valueOf(ParkKey.c_room_status), "1", parkNeedUploadId);
|
|
|
//更新面积数据
|
|
|
String roomSaleType = room.getString(String.valueOf(ParkKey.c_room_sale_type));
|
|
|
boolean isForSale = "3".equals(roomSaleType);
|
|
|
boolean isForRent = "1".equals(roomSaleType);
|
|
|
Double BuildArea = room.getDouble(String.valueOf(ParkKey.c_building_area));
|
|
|
|
|
|
- updateDoubleValue(room, String.valueOf(ParkKey.c_self_used_area), 0d, parkNeedUpload);
|
|
|
- updateDoubleValue(room, String.valueOf(ParkKey.c_sellable_area), isForSale ? BuildArea : 0d, parkNeedUpload);
|
|
|
- updateDoubleValue(room, String.valueOf(ParkKey.c_sold_area), 0d, parkNeedUpload);
|
|
|
- updateDoubleValue(room, String.valueOf(ParkKey.c_rentable_area), isForRent ? BuildArea : 0d, parkNeedUpload);
|
|
|
- updateDoubleValue(room, String.valueOf(ParkKey.c_rented_area), 0d, parkNeedUpload);
|
|
|
- updateDoubleValue(room, String.valueOf(ParkKey.c_vacant_area), isForRent || isForSale ? BuildArea : 0d, parkNeedUpload);
|
|
|
+ updateDoubleValue(room, String.valueOf(ParkKey.c_self_used_area), 0d, parkNeedUploadId);
|
|
|
+ updateDoubleValue(room, String.valueOf(ParkKey.c_sellable_area), isForSale ? BuildArea : 0d, parkNeedUploadId);
|
|
|
+ updateDoubleValue(room, String.valueOf(ParkKey.c_sold_area), 0d, parkNeedUploadId);
|
|
|
+ updateDoubleValue(room, String.valueOf(ParkKey.c_rentable_area), isForRent ? BuildArea : 0d, parkNeedUploadId);
|
|
|
+ updateDoubleValue(room, String.valueOf(ParkKey.c_rented_area), 0d, parkNeedUploadId);
|
|
|
+ updateDoubleValue(room, String.valueOf(ParkKey.c_vacant_area), isForRent || isForSale ? BuildArea : 0d, parkNeedUploadId);
|
|
|
} else {
|
|
|
//绑定企业信息
|
|
|
updateStringValue(room,
|
|
|
String.valueOf(ParkKey.c_zlqydm),
|
|
|
lease.getString(String.valueOf(LeaseKey.c_enterprise_code)),
|
|
|
- parkNeedUpload);
|
|
|
+ parkNeedUploadId);
|
|
|
updateStringValue(room,
|
|
|
String.valueOf(ParkKey.c_zlqymc),
|
|
|
lease.getString(String.valueOf(LeaseKey.c_enterprise_name)),
|
|
|
- parkNeedUpload);
|
|
|
+ parkNeedUploadId);
|
|
|
//更新房间状态
|
|
|
String roomSaleType = room.getString(String.valueOf(ParkKey.c_room_sale_type));
|
|
|
boolean isForSale = "3".equals(roomSaleType);
|
|
|
@@ -236,26 +257,26 @@ public class DataPreCounter {
|
|
|
} else {
|
|
|
state = null; // 如果房间缺失用途数据,则默许缺失蔓延到状态数据
|
|
|
}
|
|
|
- updateStringValue(room, String.valueOf(ParkKey.c_room_status), state, parkNeedUpload);
|
|
|
+ updateStringValue(room, String.valueOf(ParkKey.c_room_status), state, parkNeedUploadId);
|
|
|
|
|
|
//更新面积数据
|
|
|
|
|
|
Double BuildArea = room.getDouble(String.valueOf(ParkKey.c_building_area));
|
|
|
|
|
|
- updateDoubleValue(room, String.valueOf(ParkKey.c_self_used_area), isForSelfUsed ? BuildArea : 0d, parkNeedUpload);
|
|
|
- updateDoubleValue(room, String.valueOf(ParkKey.c_sellable_area), 0d, parkNeedUpload);
|
|
|
- updateDoubleValue(room, String.valueOf(ParkKey.c_sold_area), isForSale ? BuildArea : 0d, parkNeedUpload);
|
|
|
- updateDoubleValue(room, String.valueOf(ParkKey.c_rentable_area), 0d, parkNeedUpload);
|
|
|
- updateDoubleValue(room, String.valueOf(ParkKey.c_rented_area), isForRent ? BuildArea : 0d, parkNeedUpload);
|
|
|
- updateDoubleValue(room, String.valueOf(ParkKey.c_vacant_area), 0d, parkNeedUpload);
|
|
|
+ updateDoubleValue(room, String.valueOf(ParkKey.c_self_used_area), isForSelfUsed ? BuildArea : 0d, parkNeedUploadId);
|
|
|
+ updateDoubleValue(room, String.valueOf(ParkKey.c_sellable_area), 0d, parkNeedUploadId);
|
|
|
+ updateDoubleValue(room, String.valueOf(ParkKey.c_sold_area), isForSale ? BuildArea : 0d, parkNeedUploadId);
|
|
|
+ updateDoubleValue(room, String.valueOf(ParkKey.c_rentable_area), 0d, parkNeedUploadId);
|
|
|
+ updateDoubleValue(room, String.valueOf(ParkKey.c_rented_area), isForRent ? BuildArea : 0d, parkNeedUploadId);
|
|
|
+ updateDoubleValue(room, String.valueOf(ParkKey.c_vacant_area), 0d, parkNeedUploadId);
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
private void updateLeaseLast(JSONObject newWorkingLease, List<JSONObject> oldWorkingLeases) {
|
|
|
oldWorkingLeases.forEach(v -> updateStringValue(v, String.valueOf(LeaseKey.c_is_latest_lease),
|
|
|
- "1", leaseNeedUpload));
|
|
|
- updateStringValue(newWorkingLease, String.valueOf(LeaseKey.c_is_latest_lease), "2", leaseNeedUpload);
|
|
|
+ "1", leaseNeedUploadId));
|
|
|
+ updateStringValue(newWorkingLease, String.valueOf(LeaseKey.c_is_latest_lease), "2", leaseNeedUploadId);
|
|
|
}
|
|
|
|
|
|
private boolean shouldLeaseUpdate(List<JSONObject> allLastWorkingLease, JSONObject workingLease) {
|
|
|
@@ -267,22 +288,30 @@ public class DataPreCounter {
|
|
|
if (!allLastWorkingLease.isEmpty()) {
|
|
|
lastWorkingLease = allLastWorkingLease.get(0);
|
|
|
}
|
|
|
- //新旧执行中lease不相同
|
|
|
+ //新旧执行中lease相同性
|
|
|
return workingLease != lastWorkingLease;
|
|
|
}
|
|
|
}
|
|
|
+ private boolean shouldRoomUpdate(JSONObject room, JSONObject lease) {
|
|
|
+ //检查企业数据
|
|
|
+ boolean isEnterpriseDataEqual = compareRoomAndLeaseByKey(room, lease,ParkKey.c_zlqydm,LeaseKey.c_enterprise_code);
|
|
|
+ isEnterpriseDataEqual = isEnterpriseDataEqual && compareRoomAndLeaseByKey(room, lease,ParkKey.c_zlqymc,LeaseKey.c_enterprise_name);
|
|
|
+
|
|
|
+ //检查房间状态与lease匹配性
|
|
|
+ boolean roomUsing = !"1".equals(room.getString(String.valueOf(ParkKey.c_room_status)));
|
|
|
+ boolean leaseWorking = checkLeaseWorking(lease);
|
|
|
+ boolean isWorkingDataEqual = roomUsing == leaseWorking;
|
|
|
+ return !(isEnterpriseDataEqual && isWorkingDataEqual);
|
|
|
+ }
|
|
|
+
|
|
|
+ private static boolean compareRoomAndLeaseByKey(JSONObject room, JSONObject lease,ParkKey roomKey,LeaseKey leaseKey) {
|
|
|
+ return Objects.equals(room.getString(String.valueOf(roomKey)), lease.getString(String.valueOf(leaseKey)));
|
|
|
+ }
|
|
|
|
|
|
private JSONObject getWorkingLease(Supplier<Stream<JSONObject>> involveLease) {
|
|
|
JSONObject workingLease = involveLease.get()
|
|
|
.sorted(Comparator.comparingLong((JSONObject v) -> v.getLong(String.valueOf(LeaseKey.update_time))).reversed())
|
|
|
- .filter(v -> {
|
|
|
- LocalDate startTime = getLeaseStartTime(v);
|
|
|
- LocalDate endTime = getLeaseEndTime(v);
|
|
|
- if (startTime == null || endTime == null) {
|
|
|
- return false;
|
|
|
- }
|
|
|
- return !startTime.isAfter(now.toLocalDate()) && !endTime.isBefore(now.toLocalDate());
|
|
|
- })
|
|
|
+ .filter(this::checkLeaseWorking)
|
|
|
.findFirst().orElse(null);
|
|
|
if (workingLease == null) {
|
|
|
workingLease = involveLease.get()
|
|
|
@@ -291,7 +320,7 @@ public class DataPreCounter {
|
|
|
if (startTime == null) {
|
|
|
return false;
|
|
|
}
|
|
|
- return startTime.isAfter(now.toLocalDate());
|
|
|
+ return startTime.isAfter(now);
|
|
|
}).min(Comparator.comparingLong(v -> v.getLong(String.valueOf(LeaseKey.c_start_date)))).orElse(null);
|
|
|
}
|
|
|
if (workingLease == null) {
|
|
|
@@ -301,13 +330,22 @@ public class DataPreCounter {
|
|
|
if (endTime == null) {
|
|
|
return false;
|
|
|
}
|
|
|
- return endTime.isBefore(now.toLocalDate());
|
|
|
+ return endTime.isBefore(now);
|
|
|
})
|
|
|
.max(Comparator.comparingLong(v -> v.getLong(String.valueOf(LeaseKey.c_end_date)))).orElse(null);
|
|
|
}
|
|
|
return workingLease;
|
|
|
}
|
|
|
|
|
|
+ private boolean checkLeaseWorking(JSONObject Lease) {
|
|
|
+ LocalDate startTime = getLeaseStartTime(Lease);
|
|
|
+ LocalDate endTime = getLeaseEndTime(Lease);
|
|
|
+ if (startTime == null || endTime == null) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ return !startTime.isAfter(now) && !endTime.isBefore(now);
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 根据父子关系统计面积等等数据,使用时从下到上,一层层处理
|
|
|
*
|
|
|
@@ -341,13 +379,13 @@ public class DataPreCounter {
|
|
|
.map(parkDataCount::new)
|
|
|
.reduce(new parkDataCount(), parkDataCount::add, parkDataCount::add);
|
|
|
|
|
|
- updateDoubleValue(father, String.valueOf(ParkKey.c_building_area), countResult.buildArea.doubleValue(), parkNeedUpload);
|
|
|
- updateDoubleValue(father, String.valueOf(ParkKey.c_sellable_area), countResult.sellableArea.doubleValue(), parkNeedUpload);
|
|
|
- updateDoubleValue(father, String.valueOf(ParkKey.c_sold_area), countResult.soldArea.doubleValue(), parkNeedUpload);
|
|
|
- updateDoubleValue(father, String.valueOf(ParkKey.c_rentable_area), countResult.rentableArea.doubleValue(), parkNeedUpload);
|
|
|
- updateDoubleValue(father, String.valueOf(ParkKey.c_rented_area), countResult.rentedArea.doubleValue(), parkNeedUpload);
|
|
|
- updateDoubleValue(father, String.valueOf(ParkKey.c_self_used_area), countResult.selfUseArea.doubleValue(), parkNeedUpload);
|
|
|
- updateDoubleValue(father, String.valueOf(ParkKey.c_vacant_area), countResult.vacantArea.doubleValue(), parkNeedUpload);
|
|
|
+ updateDoubleValue(father, String.valueOf(ParkKey.c_building_area), countResult.buildArea.doubleValue(), parkNeedUploadId);
|
|
|
+ updateDoubleValue(father, String.valueOf(ParkKey.c_sellable_area), countResult.sellableArea.doubleValue(), parkNeedUploadId);
|
|
|
+ updateDoubleValue(father, String.valueOf(ParkKey.c_sold_area), countResult.soldArea.doubleValue(), parkNeedUploadId);
|
|
|
+ updateDoubleValue(father, String.valueOf(ParkKey.c_rentable_area), countResult.rentableArea.doubleValue(), parkNeedUploadId);
|
|
|
+ updateDoubleValue(father, String.valueOf(ParkKey.c_rented_area), countResult.rentedArea.doubleValue(), parkNeedUploadId);
|
|
|
+ updateDoubleValue(father, String.valueOf(ParkKey.c_self_used_area), countResult.selfUseArea.doubleValue(), parkNeedUploadId);
|
|
|
+ updateDoubleValue(father, String.valueOf(ParkKey.c_vacant_area), countResult.vacantArea.doubleValue(), parkNeedUploadId);
|
|
|
}
|
|
|
|
|
|
private static BigDecimal nullToZero(BigDecimal v) {
|
|
|
@@ -374,19 +412,19 @@ public class DataPreCounter {
|
|
|
return getKeyAndPackToTime(lease, String.valueOf(LeaseKey.c_end_date));
|
|
|
}
|
|
|
|
|
|
- private void updateStringValue(JSONObject obj, String key, String value, Set<JSONObject> uploadSet) {
|
|
|
+ private void updateStringValue(JSONObject obj, String key, String value, Set<String> uploadList) {
|
|
|
String oldValue = obj.getString(key);
|
|
|
if (!oldValue.equals(value)) {
|
|
|
obj.put(key, value);
|
|
|
- uploadSet.add(obj);
|
|
|
+ uploadList.add(obj.getString("id"));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- private void updateDoubleValue(JSONObject obj, String key, Double value, Set<JSONObject> uploadSet) {
|
|
|
+ private void updateDoubleValue(JSONObject obj, String key, Double value, Set<String> uploadList) {
|
|
|
Double oldValue = obj.getDouble(key);
|
|
|
if (!oldValue.equals(value)) {
|
|
|
obj.put(key, value);
|
|
|
- uploadSet.add(obj);
|
|
|
+ uploadList.add(obj.getString("id"));
|
|
|
}
|
|
|
}
|
|
|
}
|