import com.haulmont.cuba.core.entity.Entity
import com.haulmont.cuba.core.global.*
import com.groupstp.rtneo.entity.*
import com.groupstp.rtneo.service.*
import com.groupstp.rtneo.core.bean.*
import com.haulmont.cuba.core.*
import java.util.stream.Collectors
import com.haulmont.cuba.core.global.ViewRepository;
import com.haulmont.cuba.core.global.View;
import java.util.function.*;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.stream.Collectors
df = new SimpleDateFormat("dd.MM.yyyy");
vRep = AppBeans.get(ViewRepository.NAME)
messages = AppBeans.get(Messages.NAME)
//start = df.parse('01.01.2019')
//end = df.parse('31.12.2020')
//params = ["municipality":dataManager.load(Municipality.class).id(UUID.fromString("db4d3ab9-8043-616e-996f-128b86d35cab")).view("_local").optional().orElse(null), reportFrom:df.parse('01.01.2019'), reportTo:df.parse('31.12.2019')]
start = params.reportFrom
end = params.reportTo
result = new ArrayList<LinkedHashMap<String, Object>>();
def list = getCreList().stream()
.filter{e-> !(e.realEstate.name.equals('Земельный участок') && (e.createdBy.contains('dataminer') || e.createdBy.equals('admin')))}
.collect(Collectors.groupingBy({p->p.getRealEstate()}))
String periodCaption = "Суммы норматив январь 19|Суммы норматив февраль 19|Суммы норматив март 19|Суммы норматив апрель 19|Суммы норматив май 19|Суммы норматив июнь 19|Суммы норматив июль 19|Суммы норматив август 19|Суммы норматив сентябрь 19|Суммы норматив октябрь 19|Суммы норматив ноябрь 19|Суммы норматив декабрь 19|Суммы норматив январь 20|Суммы норматив февраль 20|Суммы норматив март 20|Суммы норматив апрель 20|Суммы норматив май 20|Суммы норматив июнь 20|Суммы норматив июль 20|Суммы норматив август 20|Суммы норматив сентябрь 20|Суммы норматив октябрь 20|Суммы норматив ноябрь 20|Суммы норматив декабрь 20|Суммы факт январь 19|Суммы факт февраль 19|Суммы факт март 19|Суммы факт апрель 19|Суммы факт май 19|Суммы факт июнь 19|Суммы факт июль 19|Суммы факт август 19|Суммы факт сентябрь 19|Суммы факт октябрь 19|Суммы факт ноябрь 19|Суммы факт декабрь 19|Суммы факт январь 20|Суммы факт февраль 20|Суммы факт март 20|Суммы факт апрель 20|Суммы факт май 20|Суммы факт июнь 20|Суммы факт июль 20|Суммы факт август 20|Суммы факт сентябрь 20|Суммы факт октябрь 20|Суммы факт ноябрь 20|Суммы факт декабрь 20"
_("|Кадастровый|МО|Адрес|Владение|ЛС|Категория|Площадь|р/е|Категория контрагента|Доля|${periodCaption}|Общая по контрагенту|Статус")
for(def item : list.entrySet()){
List<LinkedHashMap<String, Object>> pre = prePrint(item)
//После тестов вынести в обработчик. Может в prePrint??
// _("|----------${item.getValue().size()}-----------")
//Разделяем арендаторов и собственников
def prePart = pre.stream()
.collect(Collectors.partitioningBy{e -> e.ownType.equals("Собственность")})
.toSorted{o1, o2 -> -1*o1.getKey().compareTo(o2.getKey())}
for(def own : prePart.entrySet()){
def renterCre;
def ownerCre;
boolean isFact = false
if(own.getKey()){
ownerCre = own.getValue()
if(ownerCre.isEmpty())continue
//Проверяем, если у всех объектов не указаны доли, нужно вывести один объект с минимальными начислениями??
boolean isNoAllShare = ownerCre.stream().allMatch{e -> e.share.equals(-1)}
isFact = ownerCre.stream().anyMatch{e -> e.sumFactJoiner != null}
boolean isNoAnyShare = ownerCre.stream().anyMatch{e -> e.share.equals(-1)}
if(isNoAnyShare){
//Если есть объект с незаполненной долей, выводим его
def noShare = ownerCre.stream().filter{e -> e.share.equals(-1)}.collect(Collectors.toList())
if(!noShare.isEmpty())ownerCre = noShare
//Сортируем по сумме начислений
Collections.sort(ownerCre, new Comparator<HashMap<String, Object>>() {
public int compare(HashMap<String, Object> o1, HashMap<String, Object> o2) {
//По возрастанию
//Проверить решение??
if(o1.totalSum.equals(-1))return -1
if(o2.totalSum.equals(-1))return -1
return o1.totalSum.compareTo(o2.totalSum);
}
});
//Выводим первый объект из сортированного списка
// _("|isNoAllShare")
printFromCollection(ownerCre.get(0))
continue
}
//Если есть объекты с заполненной долей
//Отсортировать по доле
Collections.sort(ownerCre, new Comparator<HashMap<String, Object>>() {
public int compare(HashMap<String, Object> o1, HashMap<String, Object> o2) {
return -1*o1.share.compareTo(o2.share);
}
});
def totalShare = BigDecimal.ZERO
for(def owner : ownerCre){
//Если пошли без доли, дальше суммировать долю смысла нет, выводим последнюю запись и прерываем цикл
if(owner.share.equals(-1)){
printFromCollection(owner)
break
}
//Суммируем доли пока не будет 1 целое
totalShare += owner.share
//Возможно нужно учесть погрешность??0
if(totalShare <= BigDecimal.ONE){
printFromCollection(owner)
}else{
break
}
}
}else{
renterCre = own.getValue()
if(renterCre.isEmpty() || isFact)continue
for(def renter : renterCre){
printFromCollection(renter)
}
}
}
}
def accrualsForPeriods(List<Accrual> accruals, boolean isFact = false){
HashMap<Date, Object> sumForPeriod = new HashMap<>()
Calendar calStart = Calendar.getInstance()
Calendar calEnd = Calendar.getInstance()
calStart.setTime(params.reportFrom)
calEnd.setTime(params.reportTo)
while(!calStart.after(calEnd)){
def sum = accruals.stream()
.filter{e-> e.getPeriod() == calStart.getTime()}
.filter{e -> isFact ? e.comment != null && e.comment.contains(" факту") : e.comment == null || !e.comment.contains(" факту")}
.map{e-> e.getTotalSumBase() != null ? e.getTotalSumBase() : BigDecimal.ZERO}
.reduce{a1, a2 -> a1.add(a2)}
.orElse(null)
sumForPeriod.put(calStart.getTime(), sum)
calStart.add(Calendar.MONTH, 1)
}
// String printSumForPeriod = sumForPeriod.entrySet().stream()
// .sorted{k1, k2-> k1.getKey().compareTo(k2.getKey())}
// .map{e-> e.getValue() as String}
// .collect(Collectors.toMap({Map.Entry::getKey}, {Map.Entry::getValue, (key, val) -> key, LinkedHashMap::new}))
//// .collect(Collectors.joining("|"))
def printSumForPeriod = sumForPeriod.entrySet().stream()
.sorted{k1, k2-> k1.getKey().compareTo(k2.getKey())}
.collect(Collectors.toMap(
{o1 -> (isFact?'факт ':'норматив ')+df.format(o1.getKey())},
{o2 -> o2.getValue()==null?"null":o2.getValue()},
{oldValue, newValue -> oldValue},
{new LinkedHashMap<>()}))
return printSumForPeriod
}
List<ContragentRealEstate> getCreList(){
//Тулун - 9690c445-31bf-4fce-4234-b9af0ad7151f
//Город Усолье-Сибирское - b9ecbdaa-0a2c-aa2f-8256-a85f639a50a2
//Усольский район - 7e07702d-2282-6d14-820e-f4fc981bc32a
//Тулунский район - d2189341-f55d-3953-9776-0bebb7029576
//Город Зима - 90ee42aa-9d9e-0365-c8d1-e0b3400240ac
//Зиминский район - eedc8946-5d7b-d109-5180-9d25dada7070
//Город Саянск - 779e475d-4b7a-4e25-b461-66be0949c00a
//Город Свирск - fbd2bc0e-4539-9c08-0ff1-cafa4af4bc4d
//Город Черемхово - 583ecc11-0c6b-77c5-f4ec-f4057489facd
//Черемховский район - 6111a085-22a8-cefb-ab40-2bb6b1c4dced
//Балаганский район - 411cfee3-ed88-9934-33a7-0c3ba9d3fbe8
//город Бодайбо и район - f6f8462f-df56-a7fd-ae26-7e7f2532eed5
//Жигаловский район -
//Заларинский район -
return dataManager.load(ContragentRealEstate.class)
// .query('select c from rtneo$ContragentRealEstate c where c.id =\'66e7162e-90ea-79f2-fc80-d06a3462e9b8\'')
// .query('select c from rtneo$ContragentRealEstate c where (lower(c.realEstate.address) like lower(\'%%г. Иркутск%%\') or lower(c.realEstate.address) like lower(\'%%г.Иркутск%%\')) and (c.type.id = \'a1122505-7e60-19f0-be56-5ec549ab80c8\' or c.type.id = \'a633833e-83bc-52b1-0aef-9898739f434f\')')
// .query('select c from rtneo$ContragentRealEstate c where (lower(c.realEstate.address) like lower(\'%%Иркутск %%\') or lower(c.realEstate.address) like lower(\'%%Иркутск,%%\') or lower(c.realEstate.address) like lower(\'%%Иркутск.%%\')) and (c.type.id = \'a1122505-7e60-19f0-be56-5ec549ab80c8\' or c.type.id = \'a633833e-83bc-52b1-0aef-9898739f434f\')')
.query('select c from rtneo$ContragentRealEstate c where (c.contragent.hasWasteGenerationProject is null or c.contragent.hasWasteGenerationProject = false) and (c.type.isLiving is null or c.category.isLiving = false) and (c.type.isLiving is null or c.category.isLiving = false) and (c.excludeFromAccounting is null or c.excludeFromAccounting = false) and not c.type.id = \'b468fb60-2363-b06b-6e80-0f0e77ff383c\' and c.contragent.type <> 4 and c.category is not null and not c.realEstate.name = \'Земельный участок\' and (c.validityTo is null or c.validityTo > \'2019-01-01\') and c.realEstate.municipality.id = :municipality order by c.realEstate.municipality.id, c.id')
// .query('select c from rtneo$ContragentRealEstate c where (c.type.isLiving is null or c.type.isLiving = false) and (c.excludeFromAccounting is null or c.excludeFromAccounting = false) and not c.type.id = \'b468fb60-2363-b06b-6e80-0f0e77ff383c\' and c.contragent.type <> 4 and c.category is not null and not c.realEstate.name = \'Земельный участок\' and c.realEstate.cadastralNumber = \'38:35:010103:253\'')//df5c1720-3268-0ca0-bb8d-25601b59c461 // and c.realEstate.cadastralNumber = \'38:35:010229:1493\'
.parameter("municipality", params.municipality.id)
.view(getCreView())
.list()
}
//Подготовка коллекции для вывода //Подумать как эффективнее обрабатывать большие объемы
List<LinkedHashMap<String, Object>> prePrint(Map.Entry<RealEstate, ContragentRealEstate> creList){
List<LinkedHashMap<String, Object>> collectPrint = new ArrayList<>()
BigDecimal totalSum = BigDecimal.ZERO
for(def cre : creList.getValue()){
if(cre.getContragent() == null){
_("|>>>>>>>>>>>>>>>Contragent is NULL ${cre}")
continue
}
List<Accrual> accrualsCre = getContragentBillsCRE2(cre.getContragent().getId(), cre.getId()).stream().filter{e -> e.getPeriod().compareTo(end) <=0}.collect(Collectors.toList())
def sum = accrualsCre.stream().map{e -> e.getTotalSumBase() != null ? e.getTotalSumBase() : BigDecimal.ZERO}.reduce{a1, a2 -> a1.add(a2)}.orElse(-1)
def sumFactJoiner = accrualsForPeriods(accrualsCre, true)
def sumNormJoiner = accrualsForPeriods(accrualsCre)
if(cre?.getOwnType() == null)continue
def area = (cre?.getOwnType().getId() == 2 || cre?.getOwnType().getId() == 3) ? cre.getRealEstate()?.getArea() : cre.getAreaInRent()
LinkedHashMap<String, Object> item = ["cadastral" : creList.getKey().getCadastralNumber(),
"mo" : cre.getRealEstate().getMunicipality()?.getName(),
"address" : creList.getKey().getAddress(),
"ownType" : messages.getMessage(cre.getOwnType()),//TypeOwnership.MANAGEMENT
"personalAccount" : cre.getContragent().getPersonalAccount(),
// "name" : cre.getContragent().getName(),
// "isDouble" : "null",
"category" : cre.getCategory()?.getName(),
"area" : area,
"calculationAmount" : getCalculationAmount(cre),
"contragentCategory" : cre.getContragent().getCategory()?.getName(),
"share" : cre.getShare() != null ? cre.getShare() : -1,
// "sumNormJoiner" : sumNormJoiner,
// "sumFactJoiner" : sumFactJoiner,
"totalSum" : sum,
"status" : checkStat(cre)]
item.putAll(sumNormJoiner)
item.putAll(sumFactJoiner)
collectPrint.add(item)
totalSum += sum
}
//Если нужно выводить общую сумму начислений за объект по всем контрагентам
// collectPrint.stream().map{e -> e.put("totalSum", totalSum)}
return collectPrint
}
String checkStat(ContragentRealEstate cre){
StringJoiner status = new StringJoiner(", ")
if(Boolean.TRUE.equals(cre.getExcludeFromAccounting()))status.add('Исключен')
// dataManager.loadValue('select count(s) from rtneo$EntityesTemporarySet s where (s.setName = \'garages\' or s.setName = \'gardens\') and s.entityId = :realEstate_id', Integer.class)
// .parameter("realEstate_id", cre.getRealEstate().getId())
// .optional().ifPresent{e -> if(e > 0)status.add('ГК')}
dataManager.loadValues('select s.setName from rtneo$EntityesTemporarySet s where (s.setName = \'garages\' or s.setName = \'gardens\') and s.entityId = :realEstate_id')
.property("status")
.parameter("realEstate_id", cre.getRealEstate().getId())
.list().stream().map{e -> e.getValue("status")}.forEach{e ->
if(e.equals("garages"))status.add('ГК')
if(e.equals("gardens"))status.add('СНТ')
}
return status.toString()
}
void printFromCollection(LinkedHashMap<String, Object> item){
result.addAll(item)
}
View getCreView(){
View creView = vRep.getView(ContragentRealEstate.class, "_minimal")
.addProperty("realEstate", vRep.getView(RealEstate.class, "_minimal")
.addProperty("municipality", vRep.getView(Municipality.class, "_minimal")
.addProperty("name")
)
.addProperty("cadastralNumber")
.addProperty("area")
)
.addProperty("category", vRep.getView(RealEstateCategory.class, "_minimal")
.addProperty("unit", vRep.getView(Unit.class, "_minimal")
.addProperty("isArea")
)
.addProperty("parentCategory", vRep.getView(RealEstateCategory.class, "_minimal")
.addProperty("ratio")
)
.addProperty("name")
.addProperty("ratio")
)
.addProperty("contragent", vRep.getView(Contragent.class, "_minimal")
.addProperty("category", vRep.getView(ContragentCategory.class, "_minimal")
.addProperty("name")
)
.addProperty("name")
.addProperty("inn")
.addProperty("personalAccount")
)
.addProperty("ownType")
.addProperty("introducedWithTechPassport")
.addProperty("createdBy")
.addProperty("validityFrom")
.addProperty("validityTo")
.addProperty("share")
.addProperty("particularArea")
.addProperty("excludeFromAccounting")
.addProperty("areaInRent")
}
//List<Accrual> getContragentBillsCRE(UUID contragentID,UUID creId, Boolean noAccept){
// long st = System.currentTimeMillis();
//
// Persistence persistence= AppBeans.get(Persistence.NAME)
// ViewRepository vRep = AppBeans.get(ViewRepository.NAME)
// DataManager dataManager = AppBeans.get(DataManager.NAME)
//
// View viewAccrual = vRep.getView(Accrual.class, "_local")
// .addProperty("category", vRep.getView(RealEstateCategory.class, "_local")
// .addProperty("unit", vRep.getView(Unit.class, "_local"))
// )
// .addProperty("realEstate", vRep.getView(RealEstate.class, "_local")
//
// )
//
// Transaction tr = persistence.createTransaction()
// List accruals
// try{
// EntityManager em = persistence.getEntityManager();
//
// String str = "with accruals as(\n" +
// "select\n" +
// "a.id as id, c.number_, a.document_number, a.\"period\", a.create_ts, row_number() over (partition by a.\"period\" order by c.create_ts desc) as num\n" +
// "from\n" +
// "rtneo_accrual a\n" +
// "join rtneo_contract_position cp on\n" +
// "a.contract_position_id = cp.id\n" +
// "join rtneo_contragent_real_estate cre on\n" +
// "cp.contragent_real_estate_id = cre.id\n" +
// "join rtneo_contract c on cp.contract_id = c.id\n" +
// "where\n" +
// "a.delete_ts is null\n" +
// "and cp.delete_ts is null\n" +
// "and cre.delete_ts is null\n" +
// "and c.delete_ts is null\n" +
// "and cre.id = #cre\n" +
// "and c.accepted = true\n" +
// "order by a.\"period\"\n" +
// ")\n" +
// "select accs.id from accruals accs where accs.num = 1"
//
// String q2 = "select a.id from rtneo_accrual a offset 0 limit 10"
// Query query = em.createNativeQuery(str);
// //query.setViewName("_local")
// query.setParameter("cre", creId);
// accruals = query.getResultList();
// tr.commit()
// tr.close()
//}catch(Exception e){
// tr.commit()
// tr.close()
//}finally{
// tr.commit()
// tr.close()
//}
//// List<Accrual> accs = accruals.stream().map{e -> dataManager.load(Accrual.class).id(e).view(viewAccrual).one()}.collect(Collectors.toList())
// List<Accrual> accs = dataManager.load(Accrual.class)
// .query('select a from rtneo$Accrual a where a.id in :ids')
// .parameter("ids", accruals)
// .view(viewAccrual)
// .list()
//// accs.each{log.debug(it)}
//long end = System.currentTimeMillis();
////log.debug("Time: ${end-st}");
////_(accs, "json")
//accs.each{_(it, "json")}
// return accs
//}
List<Accrual> getContragentBillsCRE2(UUID contragentID,UUID creId){
ViewRepository vRep = AppBeans.get(ViewRepository.NAME)
DataManager dataManager = AppBeans.get(DataManager.NAME)
View viewAccrual = vRep.getView(Accrual.class, "_local")
.addProperty("category", vRep.getView(RealEstateCategory.class, "_local")
.addProperty("unit", vRep.getView(Unit.class, "_local"))
)
.addProperty("realEstate", vRep.getView(RealEstate.class, "_local")
)
String sqlQuery = 'select e from rtneo$Accrual e where 1=0';
List<Accrual> accruals = new ArrayList<Accrual>();
List<Contract> contracts = dataManager.load(Contract.class)
.query('select e from rtneo$Contract e join e.positions p where e.contragent.id = :contragent and p.contragentRealEstate.id = :creId order by e.createTs desc')
.parameter("contragent", contragentID)
.parameter("creId", creId)
.view("_local")
.list();
if(contracts.stream().anyMatch{e -> Objects.nonNull(e.getTemplate()) && e.getTemplate().equals('MSG310820')}){
contracts = contracts.stream().filter{e -> Boolean.TRUE.equals(e.getAccepted())}.collect(Collectors.toList())
}
if (contracts.size() > 0) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Contract lastContract = null;
for (Contract contract : contracts) {
if (lastContract == null) {
lastContract = contract;
sqlQuery = "cast(a.contractPosition.contract.id text)='" + contract.getId().toString() + "' ";
} else {
if (contract.getFrom().before(lastContract.getFrom())) {
sqlQuery = sqlQuery + " or (cast(a.contractPosition.contract.id text)='" + contract.getId().toString() + "' and a.period < '" + sdf.format(lastContract.getFrom()) + "' )";
lastContract = contract;
}
}
}
sqlQuery = 'select a from rtneo$Accrual a where a.contractPosition.contragentRealEstate.id=:creId and a.contragent.id = :contragentID and (' + sqlQuery + ') order by a.period';
accruals = dataManager.load(Accrual.class)
.query(sqlQuery)
.parameter("contragentID", contragentID)
.parameter("creId", creId)
.view(viewAccrual)
.list();
}
// if(accruals.isEmpty()){
// _(contragentID)
// _(creId)
// accruals = getContragentBillsCRE(contragentID, creId, true)
// }
return accruals;
}
List<Accrual> getContragentBillsCRE2(UUID contragentID,UUID creId, Boolean noAccept){
long st = System.currentTimeMillis();
ViewRepository vRep = AppBeans.get(ViewRepository.NAME)
DataManager dataManager = AppBeans.get(DataManager.NAME)
View viewAccrual = vRep.getView(Accrual.class, "_local")
.addProperty("category", vRep.getView(RealEstateCategory.class, "_local")
.addProperty("unit", vRep.getView(Unit.class, "_local"))
)
.addProperty("realEstate", vRep.getView(RealEstate.class, "_local")
)
String sqlQuery = 'select e from rtneo$Accrual e where 1=0';
List<Accrual> accruals = new ArrayList<Accrual>();
List<Contract> contracts = dataManager.load(Contract.class)
.query('select e from rtneo$Contract e join e.positions p where e.contragent.id = :contragent and p.contragentRealEstate.id = :creId order by e.createTs desc')
.parameter("contragent", contragentID)
.parameter("creId", creId)
.view("_base")
.list();
_(contracts)
if (contracts.size() > 0) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Contract lastContract = null;
for (Contract contract : contracts) {
if (lastContract == null) {
lastContract = contract;
sqlQuery = "cast(a.contractPosition.contract.id text)='" + contract.getId().toString() + "' ";
} else {
if (contract.getFrom().before(lastContract.getFrom())) {
sqlQuery = sqlQuery + " or (cast(a.contractPosition.contract.id text)='" + contract.getId().toString() + "' and a.period < '" + sdf.format(lastContract.getFrom()) + "' )";
lastContract = contract;
}
}
}
sqlQuery = 'select a from rtneo$Accrual a where a.contractPosition.contragentRealEstate.id=:creId and a.contragent.id = :contragentID and (' + sqlQuery + ') order by a.period';
accruals = dataManager.load(Accrual.class)
.query(sqlQuery)
.parameter("contragentID", contragentID)
.parameter("creId", creId)
.view(viewAccrual)
.list();
}
long end = System.currentTimeMillis();
//log.debug("Time: ${end-st}");
return accruals;
}
private BigDecimal getCalculationAmount(ContragentRealEstate cre) {
BigDecimal ratio = null;
RealEstateCategory category = cre.getCategory();
while (ratio == null && category != null) {
ratio = category.getRatio();
if (ratio == null) {
category = category.getParentCategory();
}
}
ratio = ratio == null ? BigDecimal.ONE : ratio;
BigDecimal area = Boolean.TRUE.equals(cre.getIntroducedWithTechPassport()) ?
cre.getParticularArea() : cre.getRealEstate() == null ? null : cre.getRealEstate().getArea();
//Если объект арендован
area = (cre.getOwnType().getId() == 1 || cre.getOwnType().getId() == 4) ? cre.areaInRent : area
area = area == null ? BigDecimal.ZERO : area;
def isArea = Boolean.TRUE.equals(cre.getCategory()?.getUnit()?.getIsArea())
def calculationAmount = ratio.multiply(area)
return isArea ? calculationAmount.setScale(2, BigDecimal.ROUND_UP) : calculationAmount.setScale(0, BigDecimal.ROUND_HALF_DOWN)
}
private _(Object obj, String... options){
}
//return [[:]]
return result as List<LinkedHashMap<String, Object>>;