Merge branch 'main' of https://gitea.fhgr.ch/stoffelmauro/ConsultancyProject_2_ETL
This commit is contained in:
		
						commit
						4487932f1b
					
				@ -23,7 +23,7 @@ class Api
 | 
			
		||||
            return Cache::get($request);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $get = Http::timeout(800)->get($request);
 | 
			
		||||
        $get = Http::timeout(1600)->get($request);
 | 
			
		||||
 | 
			
		||||
        if($get->successful()){
 | 
			
		||||
            $result = $get->json();
 | 
			
		||||
@ -94,6 +94,11 @@ class Api
 | 
			
		||||
        return self::get("/region/{$id}/capacities");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static function regionMovingAverage(int $id, string $date): mixed
 | 
			
		||||
    {
 | 
			
		||||
        return self::get("/region/{$id}/movingAverage/{$date}");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -178,10 +178,10 @@ body.property main{
 | 
			
		||||
  grid-template-columns: repeat(4, minmax(10%, 50%));
 | 
			
		||||
    grid-template-rows: repeat(3, 1fr) 4em;
 | 
			
		||||
    grid-template-areas:
 | 
			
		||||
      "chart2 chart2 chart5 chart5"
 | 
			
		||||
      "chart1 chart1 chart3 chart4"
 | 
			
		||||
      "chart1 chart1 chart3 chart4"
 | 
			
		||||
      "timeline timeline timeline timeline";
 | 
			
		||||
      "chart2 chart2 chart1 chart1"
 | 
			
		||||
      "chart5 chart5 chart1 chart1"
 | 
			
		||||
      "chart5 chart5 chart3 chart4"
 | 
			
		||||
      "chart5 chart5 timeline timeline";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
body.region main{
 | 
			
		||||
@ -190,8 +190,8 @@ body.region main{
 | 
			
		||||
    grid-template-areas:
 | 
			
		||||
      "chart1 chart1 chart2 chart2"
 | 
			
		||||
      "chart1 chart1 chart3 chart4"
 | 
			
		||||
      "chart1 chart1 chart3 chart4"
 | 
			
		||||
      "chart1 chart1 timeline timeline";
 | 
			
		||||
      "chart6 chart6 chart3 chart4"
 | 
			
		||||
      "chart6 chart6 timeline timeline";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
article{
 | 
			
		||||
@ -204,7 +204,15 @@ article{
 | 
			
		||||
 | 
			
		||||
article.header{
 | 
			
		||||
    grid-template-columns: 100%;
 | 
			
		||||
    grid-template-rows: minmax(1%, 10%) 1fr;
 | 
			
		||||
    grid-template-rows: minmax(1%, 2.5em) 1fr;
 | 
			
		||||
    padding: .5em 1em 1em .5em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
article.map{
 | 
			
		||||
    padding: 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
article.map>header{
 | 
			
		||||
  padding: .5em 1em 1em .5em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -231,3 +239,33 @@ article>header>h2{
 | 
			
		||||
    grid-template-rows: repeat(4, minmax(20em, 25em));
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.leaflet-marker-icon span{
 | 
			
		||||
  background: blue;
 | 
			
		||||
  width: 2rem;
 | 
			
		||||
  height: 2rem;
 | 
			
		||||
  display: block;
 | 
			
		||||
  left: -1rem;
 | 
			
		||||
  top: -1rem;
 | 
			
		||||
  position: relative;
 | 
			
		||||
  border-radius: 50% 50% 0;
 | 
			
		||||
  transform: rotate(45deg);
 | 
			
		||||
  border: 2px solid #fff
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*['#9ecae1','#6baed6','#4292c6','#2171b5','#084594'*/
 | 
			
		||||
.leaflet-marker-icon.region1 span{
 | 
			
		||||
  background: #9ecae1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.leaflet-marker-icon.region2 span{
 | 
			
		||||
  background: #6baed6;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.leaflet-marker-icon.region3 span{
 | 
			
		||||
  background: #4292c6;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.leaflet-marker-icon.region4 span{
 | 
			
		||||
  background: #2171b5;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -49,7 +49,7 @@
 | 
			
		||||
 | 
			
		||||
const sharedOptions = {
 | 
			
		||||
  basic: {
 | 
			
		||||
    color: ['#f1eef6','#bdc9e1','#74a9cf','#2b8cbe','#045a8d'],
 | 
			
		||||
    color: ['#9ecae1','#6baed6','#4292c6','#2171b5','#08519c','#08306b'],
 | 
			
		||||
    grid: {
 | 
			
		||||
      top: 20,
 | 
			
		||||
      left: 60,
 | 
			
		||||
@ -156,6 +156,7 @@ const chartPropsPerRegion = document.getElementById('chart-props-per-region');
 | 
			
		||||
const cPropsPerRegion = echarts.init(chartPropsPerRegion);
 | 
			
		||||
const cPropsPerRegionOptions = {
 | 
			
		||||
  grid: sharedOptions.basic.grid,
 | 
			
		||||
  color: sharedOptions.basic.color,
 | 
			
		||||
  xAxis: {
 | 
			
		||||
    name: 'Region',
 | 
			
		||||
    nameLocation: 'center',
 | 
			
		||||
@ -178,8 +179,13 @@ const cPropsPerRegionOptions = {
 | 
			
		||||
  series: [
 | 
			
		||||
    {
 | 
			
		||||
      data: {!! $propsPerRegion[1] !!},
 | 
			
		||||
      type: 'bar'
 | 
			
		||||
      type: 'bar',
 | 
			
		||||
      itemStyle: {
 | 
			
		||||
        color: (e) => {
 | 
			
		||||
          return sharedOptions.basic.color[e.dataIndex];
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
  ]
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -193,13 +199,13 @@ const filters = {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const cExtractionsOptions = {
 | 
			
		||||
  color: sharedOptions.basic.color,
 | 
			
		||||
  tooltip: {
 | 
			
		||||
    trigger: 'axis'
 | 
			
		||||
  },
 | 
			
		||||
  legend: {
 | 
			
		||||
    data: filters.regions
 | 
			
		||||
  },
 | 
			
		||||
  color: sharedOptions.basic.color,
 | 
			
		||||
  grid: sharedOptions.basic.grid,
 | 
			
		||||
  xAxis: {
 | 
			
		||||
    name: 'Zeitpunkt Scraping',
 | 
			
		||||
@ -226,30 +232,26 @@ const cExtractionsOptions = {
 | 
			
		||||
      name: 'Alle',
 | 
			
		||||
      type: 'line',
 | 
			
		||||
      stack: 'Total',
 | 
			
		||||
      data: {!! json_encode($growth['total_all']) !!}
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      name: 'Heidiland',
 | 
			
		||||
      type: 'line',
 | 
			
		||||
      stack: 'Heidiland',
 | 
			
		||||
      data: {!! json_encode($growth['total_heidiland']) !!}
 | 
			
		||||
      data: {!! json_encode($growth['total_all']) !!},
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      name: 'Davos',
 | 
			
		||||
      type: 'line',
 | 
			
		||||
      stack: 'Davos',
 | 
			
		||||
      data: {!! json_encode($growth['total_davos']) !!}
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      name: 'Engadin',
 | 
			
		||||
      type: 'line',
 | 
			
		||||
      stack: 'Engadin',
 | 
			
		||||
      data: {!! json_encode($growth['total_engadin']) !!}
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      name: 'Heidiland',
 | 
			
		||||
      type: 'line',
 | 
			
		||||
      data: {!! json_encode($growth['total_heidiland']) !!}
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      name: 'St. Moritz',
 | 
			
		||||
      type: 'line',
 | 
			
		||||
      stack: 'St. Moritz',
 | 
			
		||||
      data: {!! json_encode($growth['total_stmoritz']) !!}
 | 
			
		||||
    },
 | 
			
		||||
  ]
 | 
			
		||||
@ -257,18 +259,37 @@ const cExtractionsOptions = {
 | 
			
		||||
 | 
			
		||||
cExtractions.setOption(cExtractionsOptions);
 | 
			
		||||
 | 
			
		||||
const map = L.map('leaflet').setView([46.862962, 9.535296], 9);
 | 
			
		||||
const map = L.map('leaflet');
 | 
			
		||||
 | 
			
		||||
L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
 | 
			
		||||
    maxZoom: 19,
 | 
			
		||||
    attribution: '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
 | 
			
		||||
}).addTo(map);
 | 
			
		||||
 | 
			
		||||
const properties = {!! json_encode($geo) !!}
 | 
			
		||||
properties.forEach( prop => {
 | 
			
		||||
    let coords = prop.coordinates.split(',');
 | 
			
		||||
    L.marker(coords).addTo(map).bindPopup('<a href="/prop/'+prop.id+'">'+prop.coordinates+'</a>');
 | 
			
		||||
function icon(id){
 | 
			
		||||
  return L.divIcon({
 | 
			
		||||
    className: "region"+id,
 | 
			
		||||
    html: '<span></span>'
 | 
			
		||||
  })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const markers = L.featureGroup([
 | 
			
		||||
    @foreach($geo as $g)
 | 
			
		||||
    L.marker([{{ $g['latlng'] }}], {icon: icon({{ $g['region_id'] }})}).bindPopup('<a href="/property/{{ $g['property_id'] }}">{{ $g['latlng'] }}</a>'),
 | 
			
		||||
    @endforeach
 | 
			
		||||
]).addTo(map);
 | 
			
		||||
 | 
			
		||||
map.fitBounds(markers.getBounds(), {padding: [20,20]})
 | 
			
		||||
 | 
			
		||||
cHeatmap.on('click', 'series', (e) => {
 | 
			
		||||
  window.open(`/property/${e.value[1]}?date=${e.value[0]}`, '_self');
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
cPropsPerRegion.on('click', 'series', (e) => {
 | 
			
		||||
  console.log(e.dataIndex);
 | 
			
		||||
  //window.open(`/property/${e.value[1]}?date=${e.value[0]}`, '_self');
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
@ -32,6 +32,14 @@
 | 
			
		||||
    </header>
 | 
			
		||||
    <div id="chart-calendar"></div>
 | 
			
		||||
</article>
 | 
			
		||||
<article class="header map" style="grid-area: chart5;">
 | 
			
		||||
    <header>
 | 
			
		||||
        <h2 id="belegung-title">
 | 
			
		||||
            Kurzzeitmietobjekte in der Nähe
 | 
			
		||||
        </h2>
 | 
			
		||||
    </header>
 | 
			
		||||
    <div id="chart-map"></div>
 | 
			
		||||
</article>
 | 
			
		||||
<article class="header" style="grid-area: chart3;">
 | 
			
		||||
    <header>
 | 
			
		||||
        <h2>
 | 
			
		||||
@ -80,7 +88,7 @@ const cTimelineOptions = {
 | 
			
		||||
        label: {
 | 
			
		||||
            show: false
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
cTimeline.setOption(cTimelineOptions);
 | 
			
		||||
@ -168,6 +176,7 @@ const chartCapacity = document.getElementById('chart-capacity');
 | 
			
		||||
const cCapacity = echarts.init(chartCapacity);
 | 
			
		||||
 | 
			
		||||
const cCapacityOptions = {
 | 
			
		||||
    color: ['#9ecae1','#6baed6','#4292c6','#2171b5','#084594'],
 | 
			
		||||
    legend: {
 | 
			
		||||
        data: ['Auslastung Property', 'Auslastung {{ $base['region_name'] }}', 'Auslastung alle Regionen']
 | 
			
		||||
    },
 | 
			
		||||
@ -176,7 +185,7 @@ const cCapacityOptions = {
 | 
			
		||||
    valueFormatter: (value) => value.toFixed(2)+' %'
 | 
			
		||||
  },
 | 
			
		||||
  grid: {
 | 
			
		||||
    top: 20,
 | 
			
		||||
    top: 40,
 | 
			
		||||
    left: 25,
 | 
			
		||||
    right: 10,
 | 
			
		||||
    bottom: 20,
 | 
			
		||||
@ -348,6 +357,29 @@ cTimeline.on('timelinechanged', (e) => {
 | 
			
		||||
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
/* Map w/ neighbours*/
 | 
			
		||||
const map = L.map('chart-map');
 | 
			
		||||
 | 
			
		||||
L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
 | 
			
		||||
    maxZoom: 19,
 | 
			
		||||
    attribution: '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
 | 
			
		||||
}).addTo(map);
 | 
			
		||||
 | 
			
		||||
function icon(id = 0){
 | 
			
		||||
  return L.divIcon({
 | 
			
		||||
    className: "region"+id,
 | 
			
		||||
    html: '<span></span>'
 | 
			
		||||
  })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const markers = L.featureGroup([
 | 
			
		||||
    @foreach($neighbours as $n)
 | 
			
		||||
    L.marker([{{ $n['lat'] }}, {{ $n['lon'] }}], {icon: icon()}).bindPopup('<a href="/property/{{ $n['id'] }}">{{ $n['lat'] }}, {{ $n['lon'] }}</a>'),
 | 
			
		||||
    @endforeach
 | 
			
		||||
]).addTo(map);
 | 
			
		||||
 | 
			
		||||
map.fitBounds(markers.getBounds(), {padding: [20,20]})
 | 
			
		||||
 | 
			
		||||
cCapacity.on('click', 'series', (e) => {
 | 
			
		||||
 | 
			
		||||
    // Switch to correct calendar in the timeline
 | 
			
		||||
@ -356,7 +388,6 @@ cCapacity.on('click', 'series', (e) => {
 | 
			
		||||
        currentIndex: e.dataIndex
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -17,9 +17,15 @@
 | 
			
		||||
<article style="grid-area: timeline;">
 | 
			
		||||
    <div id="timeline"></div>
 | 
			
		||||
</article>
 | 
			
		||||
<article class="header" style="grid-area: chart6;">
 | 
			
		||||
    <header>
 | 
			
		||||
        <h2 id="prediction-title">Auslastung Vorhersage</h2>
 | 
			
		||||
    </header>
 | 
			
		||||
    <div id="chart-prediction"></div>
 | 
			
		||||
</article>
 | 
			
		||||
<article class="header" style="grid-area: chart1;">
 | 
			
		||||
    <header>
 | 
			
		||||
        <h2 id="belegung-title"></h2>
 | 
			
		||||
        <h2 id="belegung-title">Gesamtauslastung</h2>
 | 
			
		||||
    </header>
 | 
			
		||||
    <div id="chart-heatmap"></div>
 | 
			
		||||
</article>
 | 
			
		||||
@ -58,7 +64,7 @@
 | 
			
		||||
 | 
			
		||||
const sharedOptions = {
 | 
			
		||||
  basic: {
 | 
			
		||||
    color: ['#f1eef6','#bdc9e1','#74a9cf','#2b8cbe','#045a8d'],
 | 
			
		||||
    color: ['#9ecae1','#6baed6','#4292c6','#2171b5','#084594'],
 | 
			
		||||
    grid: {
 | 
			
		||||
      top: 20,
 | 
			
		||||
      left: 60,
 | 
			
		||||
@ -134,22 +140,90 @@ const cCapacityOptions = {
 | 
			
		||||
 | 
			
		||||
cCapacity.setOption(cCapacityOptions);
 | 
			
		||||
 | 
			
		||||
const chartPrediction = document.getElementById('chart-prediction');
 | 
			
		||||
const cPrediction = echarts.init(chartPrediction);
 | 
			
		||||
 | 
			
		||||
const cPredictionOptions = {
 | 
			
		||||
  legend: {
 | 
			
		||||
      data: ['Moving Average', 'Earlier', 'Later']
 | 
			
		||||
  },
 | 
			
		||||
  tooltip: {
 | 
			
		||||
    trigger: 'axis',
 | 
			
		||||
    valueFormatter: (value) => value.toFixed(2)+' %'
 | 
			
		||||
  },
 | 
			
		||||
  grid: {
 | 
			
		||||
    top: 20,
 | 
			
		||||
    left: 25,
 | 
			
		||||
    right: 10,
 | 
			
		||||
    bottom: 20,
 | 
			
		||||
    containLabel: true
 | 
			
		||||
  },
 | 
			
		||||
  xAxis: {
 | 
			
		||||
    type: 'category',
 | 
			
		||||
    boundaryGap: false,
 | 
			
		||||
    data: {!! json_encode($prediction['dates']) !!},
 | 
			
		||||
    name: 'Zeitpunkt Scraping',
 | 
			
		||||
    nameLocation: 'center',
 | 
			
		||||
    nameGap: 24,
 | 
			
		||||
    nameTextStyle: {
 | 
			
		||||
      fontWeight: 'bold',
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  yAxis: {
 | 
			
		||||
    type: 'value',
 | 
			
		||||
    min: 0,
 | 
			
		||||
    max: 1,
 | 
			
		||||
    name: 'Auslastung in Prozent',
 | 
			
		||||
    nameLocation: 'center',
 | 
			
		||||
    nameGap: 38,
 | 
			
		||||
    nameTextStyle: {
 | 
			
		||||
      fontWeight: 'bold',
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  series: [{
 | 
			
		||||
      name: 'Moving Average',
 | 
			
		||||
      type: 'line',
 | 
			
		||||
      symbolSize: 7,
 | 
			
		||||
      data: {!! json_encode($prediction['movAvg']) !!}
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        name: 'Earlier',
 | 
			
		||||
        type: 'line',
 | 
			
		||||
        symbolSize: 7,
 | 
			
		||||
        data: {!! json_encode($prediction['cap_earlierTimeframe']) !!}
 | 
			
		||||
    },
 | 
			
		||||
  {
 | 
			
		||||
        name: 'Later',
 | 
			
		||||
        type: 'line',
 | 
			
		||||
        symbolSize: 7,
 | 
			
		||||
        data: {!! json_encode($prediction['cap_laterTimeframe']) !!}
 | 
			
		||||
    }]
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
cPrediction.setOption(cPredictionOptions);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
const chartHeatmap = document.getElementById('chart-heatmap');
 | 
			
		||||
const cHeatmap = echarts.init(chartHeatmap);
 | 
			
		||||
const cHeatmapOptions = {
 | 
			
		||||
  animation: false,
 | 
			
		||||
  tooltip: {
 | 
			
		||||
    position: 'top'
 | 
			
		||||
  },
 | 
			
		||||
  grid: {
 | 
			
		||||
    top: 30,
 | 
			
		||||
    right: 0,
 | 
			
		||||
    bottom: 0,
 | 
			
		||||
    left: 0
 | 
			
		||||
    right: 45,
 | 
			
		||||
    bottom: 50,
 | 
			
		||||
    left: 5
 | 
			
		||||
  },
 | 
			
		||||
  dataZoom: [{
 | 
			
		||||
    type: 'inside'
 | 
			
		||||
  }
 | 
			
		||||
  ],
 | 
			
		||||
      type: 'slider'
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      type: 'slider',
 | 
			
		||||
      show: true,
 | 
			
		||||
      yAxisIndex: 0,
 | 
			
		||||
  }],
 | 
			
		||||
  xAxis: {
 | 
			
		||||
    show: false,
 | 
			
		||||
    name: 'Kurzzeitmietobjekt',
 | 
			
		||||
@ -196,8 +270,7 @@ const cHeatmapOptions = {
 | 
			
		||||
      },
 | 
			
		||||
      tooltip: {
 | 
			
		||||
        formatter: (data) => {
 | 
			
		||||
          let v = data.value
 | 
			
		||||
          return `Kurzzeitmietobjekte-ID: ${data.name}<br />Datum Scraping: ${extractionDates[v[1]]}<br/>Auslastung: ${v[2]} %`
 | 
			
		||||
          return `Kurzzeitmietobjekte-ID: ${data.data[1]}<br />Datum Scraping: ${data.data[0]}<br/>Auslastung: ${data.data[2].toFixed(2)} %`
 | 
			
		||||
        },
 | 
			
		||||
      },
 | 
			
		||||
      emphasis: {
 | 
			
		||||
 | 
			
		||||
@ -12,18 +12,20 @@ Route::get('/', function () {
 | 
			
		||||
    $propsPerRegion = Api::propertiesPerRegion();
 | 
			
		||||
    $propsPerRegionName = [];
 | 
			
		||||
    $propsPerRegionCounts = [];
 | 
			
		||||
    $propsPerRegionId = [];
 | 
			
		||||
 | 
			
		||||
    foreach ($propsPerRegion as $el) {
 | 
			
		||||
        $propsPerRegionName[] = $el['name'];
 | 
			
		||||
        $propsPerRegionId[] = $el['id'];
 | 
			
		||||
        $propsPerRegionCounts[] = $el['count_properties'];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $propertiesGeo = Api::propertiesGeo();
 | 
			
		||||
 | 
			
		||||
    return view('overview', ["regions" => $regionBase, "regionPropertiesCapacities" => $regionPropertyCapacities, "geo" => $propertiesGeo, "growth" => $propertiesGrowth, "propsPerRegion" => [json_encode($propsPerRegionName), json_encode($propsPerRegionCounts)]]);
 | 
			
		||||
    return view('overview', ["regions" => $regionBase, "regionPropertiesCapacities" => $regionPropertyCapacities, "geo" => $propertiesGeo, "growth" => $propertiesGrowth, "propsPerRegion" => [json_encode($propsPerRegionId), json_encode($propsPerRegionName), json_encode($propsPerRegionCounts)]]);
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
Route::get('/prop/{id}', function (int $id) {
 | 
			
		||||
Route::get('/property/{id}', function (int $id) {
 | 
			
		||||
 | 
			
		||||
    $propertyBase = Api::propertyBase($id);
 | 
			
		||||
    $calendars = Api::propertyExtractions($id);
 | 
			
		||||
@ -90,13 +92,14 @@ Route::get('/region/{id}', function (int $id) {
 | 
			
		||||
    $regionBaseAll = Api::regionBase(-1);
 | 
			
		||||
    $regionBaseAll[] = ['region_name' => 'Alle Regionen', 'region_id' => -1];
 | 
			
		||||
    $regionBaseRegion = $id >= 0 ? Api::regionBase($id) : [['region_name' => 'Alle Regionen']];
 | 
			
		||||
    $regionMovingAverage = Api::regionMovingAverage($id, '2024-04-25');
 | 
			
		||||
 | 
			
		||||
    $regionPropertiesCapacities = Api::regionPropertiesCapacities($id);
 | 
			
		||||
    $regionCapacitiesRegion = Api::regionCapacities($id);
 | 
			
		||||
    $regionCapacitiesAll = Api::regionCapacities(-1);
 | 
			
		||||
    $regionCapacities = [$regionCapacitiesAll, $regionCapacitiesRegion];
 | 
			
		||||
 | 
			
		||||
    return view('region', ['regions' => $regionBaseAll, 'region' => $regionBaseRegion, 'region_id' => $id, 'regionCapacities' => $regionCapacities, 'regionPropertiesCapacities' => $regionPropertiesCapacities]);
 | 
			
		||||
    return view('region', ['regions' => $regionBaseAll, 'region' => $regionBaseRegion, 'region_id' => $id, 'regionCapacities' => $regionCapacities, 'regionPropertiesCapacities' => $regionPropertiesCapacities, 'prediction' => $regionMovingAverage]);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
@ -1,30 +1,92 @@
 | 
			
		||||
<mxfile host="app.diagrams.net" agent="Mozilla/5.0 (X11; Linux x86_64; rv:133.0) Gecko/20100101 Firefox/133.0" version="25.0.3">
 | 
			
		||||
  <diagram name="Seite-1" id="5abS_fUiar5VuBZXZINZ">
 | 
			
		||||
    <mxGraphModel dx="1195" dy="1534" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
 | 
			
		||||
<mxfile host="app.diagrams.net" agent="Mozilla/5.0 (X11; Linux x86_64; rv:134.0) Gecko/20100101 Firefox/134.0" version="26.0.5">
 | 
			
		||||
  <diagram name="Seite-1" id="chpUGVRRn7alPJZ1I-il">
 | 
			
		||||
    <mxGraphModel dx="819" dy="1052" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
 | 
			
		||||
      <root>
 | 
			
		||||
        <mxCell id="0" />
 | 
			
		||||
        <mxCell id="1" parent="0" />
 | 
			
		||||
        <object placeholders="1" c4Name="REST-API" c4Type="Python (FastAPI)" c4Description="REST Schnittstelle" label="<font style="font-size: 16px"><b>%c4Name%</b></font><div>[%c4Type%]</div><br><div><font style="font-size: 11px"><font color="#cccccc">%c4Description%</font></div>" id="DRD_0cKAZXVdgcTgqyKr-1">
 | 
			
		||||
          <mxCell style="rounded=1;whiteSpace=wrap;html=1;labelBackgroundColor=none;fillColor=#1061B0;fontColor=#ffffff;align=center;arcSize=10;strokeColor=#0D5091;metaEdit=1;resizable=0;points=[[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.75,1,0],[0.5,1,0],[0.25,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];" vertex="1" parent="1">
 | 
			
		||||
            <mxGeometry x="360" y="40" width="240" height="120" as="geometry" />
 | 
			
		||||
          </mxCell>
 | 
			
		||||
        </object>
 | 
			
		||||
        <mxCell id="DRD_0cKAZXVdgcTgqyKr-5" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" edge="1" parent="1" source="DRD_0cKAZXVdgcTgqyKr-2" target="DRD_0cKAZXVdgcTgqyKr-1">
 | 
			
		||||
          <mxGeometry relative="1" as="geometry" />
 | 
			
		||||
        </mxCell>
 | 
			
		||||
        <object placeholders="1" c4Name="Data" c4Type="Python (Polars)" c4Description="Eigenes Python Package. Enthält Programmcode für das ETL" label="<font style="font-size: 16px"><b>%c4Name%</b></font><div>[%c4Type%]</div><br><div><font style="font-size: 11px"><font color="#cccccc">%c4Description%</font></div>" id="DRD_0cKAZXVdgcTgqyKr-2">
 | 
			
		||||
          <mxCell style="rounded=1;whiteSpace=wrap;html=1;labelBackgroundColor=none;fillColor=#1061B0;fontColor=#ffffff;align=center;arcSize=10;strokeColor=#0D5091;metaEdit=1;resizable=0;points=[[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.75,1,0],[0.5,1,0],[0.25,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];" vertex="1" parent="1">
 | 
			
		||||
            <mxGeometry x="40" y="40" width="240" height="120" as="geometry" />
 | 
			
		||||
          </mxCell>
 | 
			
		||||
        </object>
 | 
			
		||||
        <object placeholders="1" c4Name="Datenbank" c4Type="Container" c4Technology="DuckDB" c4Description="Datenbank, welches die aggregierten Daten enthält." label="<font style="font-size: 16px"><b>%c4Name%</b></font><div>[%c4Type%:&nbsp;%c4Technology%]</div><br><div><font style="font-size: 11px"><font color="#E6E6E6">%c4Description%</font></div>" id="DRD_0cKAZXVdgcTgqyKr-3">
 | 
			
		||||
        <object placeholders="1" c4Name="RDBMS" c4Type="Container" c4Technology="DuckDB" c4Description="Aggregierte Daten." label="<font style="font-size: 16px"><b>%c4Name%</b></font><div>[%c4Type%:&nbsp;%c4Technology%]</div><br><div><font style="font-size: 11px"><font color="#E6E6E6">%c4Description%</font></div>" id="_wAeSdXpbb6KPP4DEc36-2">
 | 
			
		||||
          <mxCell style="shape=cylinder3;size=15;whiteSpace=wrap;html=1;boundedLbl=1;rounded=0;labelBackgroundColor=none;fillColor=#23A2D9;fontSize=12;fontColor=#ffffff;align=center;strokeColor=#0E7DAD;metaEdit=1;points=[[0.5,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.5,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];resizable=0;" vertex="1" parent="1">
 | 
			
		||||
            <mxGeometry x="40" y="240" width="240" height="120" as="geometry" />
 | 
			
		||||
            <mxGeometry x="50" y="60" width="240" height="120" as="geometry" />
 | 
			
		||||
          </mxCell>
 | 
			
		||||
        </object>
 | 
			
		||||
        <mxCell id="DRD_0cKAZXVdgcTgqyKr-4" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;entryPerimeter=0;" edge="1" parent="1" source="DRD_0cKAZXVdgcTgqyKr-2" target="DRD_0cKAZXVdgcTgqyKr-3">
 | 
			
		||||
        <object placeholders="1" c4Name="ETL" c4Type="SQL, Python (Polars)" c4Description="Bereitet Daten mittels algorithmischer<br> Verfahren auf." label="<font style="font-size: 16px"><b>%c4Name%</b></font><div>[%c4Type%]</div><br><div><font style="font-size: 11px"><font color="#cccccc">%c4Description%</font></div>" id="_wAeSdXpbb6KPP4DEc36-3">
 | 
			
		||||
          <mxCell style="rounded=1;whiteSpace=wrap;html=1;labelBackgroundColor=none;fillColor=#1061B0;fontColor=#ffffff;align=center;arcSize=10;strokeColor=#0D5091;metaEdit=1;resizable=0;points=[[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.75,1,0],[0.5,1,0],[0.25,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];" vertex="1" parent="1">
 | 
			
		||||
            <mxGeometry x="480" y="60" width="240" height="120" as="geometry" />
 | 
			
		||||
          </mxCell>
 | 
			
		||||
        </object>
 | 
			
		||||
        <mxCell id="_wAeSdXpbb6KPP4DEc36-4" style="rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;exitPerimeter=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0;entryPerimeter=0;dashed=1;dashPattern=8 8;" edge="1" parent="1" source="_wAeSdXpbb6KPP4DEc36-3" target="_wAeSdXpbb6KPP4DEc36-2">
 | 
			
		||||
          <mxGeometry relative="1" as="geometry" />
 | 
			
		||||
        </mxCell>
 | 
			
		||||
        <mxCell id="_wAeSdXpbb6KPP4DEc36-5" value="Liest Datenbank" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="_wAeSdXpbb6KPP4DEc36-4">
 | 
			
		||||
          <mxGeometry x="0.0412" y="1" relative="1" as="geometry">
 | 
			
		||||
            <mxPoint x="-1" y="-1" as="offset" />
 | 
			
		||||
          </mxGeometry>
 | 
			
		||||
        </mxCell>
 | 
			
		||||
        <mxCell id="_wAeSdXpbb6KPP4DEc36-15" style="rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;exitPerimeter=0;dashed=1;dashPattern=8 8;entryX=0;entryY=0.5;entryDx=0;entryDy=0;entryPerimeter=0;" edge="1" parent="1" source="_wAeSdXpbb6KPP4DEc36-6" target="_wAeSdXpbb6KPP4DEc36-13">
 | 
			
		||||
          <mxGeometry relative="1" as="geometry" />
 | 
			
		||||
        </mxCell>
 | 
			
		||||
        <mxCell id="_wAeSdXpbb6KPP4DEc36-21" value="<div>Führt Abfragen aus</div><div>[JSON/HTTPS]<br></div>" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="_wAeSdXpbb6KPP4DEc36-15">
 | 
			
		||||
          <mxGeometry x="-0.0541" y="-1" relative="1" as="geometry">
 | 
			
		||||
            <mxPoint as="offset" />
 | 
			
		||||
          </mxGeometry>
 | 
			
		||||
        </mxCell>
 | 
			
		||||
        <object placeholders="1" c4Name="Webapplikation" c4Type="PHP (Laravel)" c4Description="Verarbeitet Anfragen von Benutzer:innen" label="<font style="font-size: 16px"><b>%c4Name%</b></font><div>[%c4Type%]</div><br><div><font style="font-size: 11px"><font color="#cccccc">%c4Description%</font></div>" id="_wAeSdXpbb6KPP4DEc36-6">
 | 
			
		||||
          <mxCell style="rounded=1;whiteSpace=wrap;html=1;labelBackgroundColor=none;fillColor=#1061B0;fontColor=#ffffff;align=center;arcSize=10;strokeColor=#0D5091;metaEdit=1;resizable=0;points=[[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.75,1,0],[0.5,1,0],[0.25,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];" vertex="1" parent="1">
 | 
			
		||||
            <mxGeometry x="50" y="230" width="240" height="120" as="geometry" />
 | 
			
		||||
          </mxCell>
 | 
			
		||||
        </object>
 | 
			
		||||
        <object placeholders="1" c4Name="Dashboard" c4Type="Container" c4Technology="Apache Echarts" c4Description="Stellt Benutzer:innen Auswertungs-<br>möglichkeiten zur Verfügbarkeit von Kurzzeitmietobjekten." label="<font style="font-size: 16px"><b>%c4Name%</b></font><div>[%c4Type%:&nbsp;%c4Technology%]</div><br><div><font style="font-size: 11px"><font color="#E6E6E6">%c4Description%</font></div>" id="_wAeSdXpbb6KPP4DEc36-8">
 | 
			
		||||
          <mxCell style="shape=mxgraph.c4.webBrowserContainer2;whiteSpace=wrap;html=1;boundedLbl=1;rounded=0;labelBackgroundColor=none;strokeColor=#118ACD;fillColor=#23A2D9;strokeColor=#118ACD;strokeColor2=#0E7DAD;fontSize=12;fontColor=#ffffff;align=center;metaEdit=1;points=[[0.5,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.5,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];resizable=0;" vertex="1" parent="1">
 | 
			
		||||
            <mxGeometry x="480" y="370" width="240" height="160" as="geometry" />
 | 
			
		||||
          </mxCell>
 | 
			
		||||
        </object>
 | 
			
		||||
        <mxCell id="_wAeSdXpbb6KPP4DEc36-10" style="rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;exitPerimeter=0;dashed=1;dashPattern=8 8;" edge="1" parent="1" source="_wAeSdXpbb6KPP4DEc36-9" target="_wAeSdXpbb6KPP4DEc36-6">
 | 
			
		||||
          <mxGeometry relative="1" as="geometry" />
 | 
			
		||||
        </mxCell>
 | 
			
		||||
        <mxCell id="_wAeSdXpbb6KPP4DEc36-16" value="<div>Besucht Webapplikation</div><div>[HTTPS]<br></div>" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="_wAeSdXpbb6KPP4DEc36-10">
 | 
			
		||||
          <mxGeometry x="0.1247" y="-2" relative="1" as="geometry">
 | 
			
		||||
            <mxPoint as="offset" />
 | 
			
		||||
          </mxGeometry>
 | 
			
		||||
        </mxCell>
 | 
			
		||||
        <mxCell id="_wAeSdXpbb6KPP4DEc36-11" style="rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;exitPerimeter=0;dashed=1;dashPattern=8 8;" edge="1" parent="1" source="_wAeSdXpbb6KPP4DEc36-9" target="_wAeSdXpbb6KPP4DEc36-8">
 | 
			
		||||
          <mxGeometry relative="1" as="geometry" />
 | 
			
		||||
        </mxCell>
 | 
			
		||||
        <mxCell id="_wAeSdXpbb6KPP4DEc36-17" value="Betrachtet Auswertungen" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="_wAeSdXpbb6KPP4DEc36-11">
 | 
			
		||||
          <mxGeometry x="0.2151" y="-1" relative="1" as="geometry">
 | 
			
		||||
            <mxPoint x="2" as="offset" />
 | 
			
		||||
          </mxGeometry>
 | 
			
		||||
        </mxCell>
 | 
			
		||||
        <object placeholders="1" c4Name="Benutzer:in" c4Type="Person" c4Description="Person welche Auswertungen zur Verfügbarkeit von Kurzzeitmietobjekten in Ferienregionen durchführt." label="<font style="font-size: 16px"><b>%c4Name%</b></font><div>[%c4Type%]</div><br><div><font style="font-size: 11px"><font color="#cccccc">%c4Description%</font></div>" id="_wAeSdXpbb6KPP4DEc36-9">
 | 
			
		||||
          <mxCell style="html=1;fontSize=11;dashed=0;whiteSpace=wrap;fillColor=#083F75;strokeColor=#06315C;fontColor=#ffffff;shape=mxgraph.c4.person2;align=center;metaEdit=1;points=[[0.5,0,0],[1,0.5,0],[1,0.75,0],[0.75,1,0],[0.5,1,0],[0.25,1,0],[0,0.75,0],[0,0.5,0]];resizable=0;" vertex="1" parent="1">
 | 
			
		||||
            <mxGeometry x="314" y="600" width="200" height="180" as="geometry" />
 | 
			
		||||
          </mxCell>
 | 
			
		||||
        </object>
 | 
			
		||||
        <mxCell id="_wAeSdXpbb6KPP4DEc36-14" style="rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;entryPerimeter=0;dashed=1;dashPattern=8 8;" edge="1" parent="1" source="_wAeSdXpbb6KPP4DEc36-13" target="_wAeSdXpbb6KPP4DEc36-3">
 | 
			
		||||
          <mxGeometry relative="1" as="geometry" />
 | 
			
		||||
        </mxCell>
 | 
			
		||||
        <mxCell id="_wAeSdXpbb6KPP4DEc36-20" value="Ruft ETL Verfahren auf" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="_wAeSdXpbb6KPP4DEc36-14">
 | 
			
		||||
          <mxGeometry x="-0.0667" y="-1" relative="1" as="geometry">
 | 
			
		||||
            <mxPoint as="offset" />
 | 
			
		||||
          </mxGeometry>
 | 
			
		||||
        </mxCell>
 | 
			
		||||
        <object placeholders="1" c4Name="FastAPI" c4Type="Python (FastAPI)" c4Description="Stellt aufbereitete Daten via <br>JSON/HTTPS API zur Verfügung." label="<font style="font-size: 16px"><b>%c4Name%</b></font><div>[%c4Type%]</div><br><div><font style="font-size: 11px"><font color="#cccccc">%c4Description%</font></div>" id="_wAeSdXpbb6KPP4DEc36-13">
 | 
			
		||||
          <mxCell style="rounded=1;whiteSpace=wrap;html=1;labelBackgroundColor=none;fillColor=#1061B0;fontColor=#ffffff;align=center;arcSize=10;strokeColor=#0D5091;metaEdit=1;resizable=0;points=[[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.75,1,0],[0.5,1,0],[0.25,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];" vertex="1" parent="1">
 | 
			
		||||
            <mxGeometry x="480" y="230" width="240" height="120" as="geometry" />
 | 
			
		||||
          </mxCell>
 | 
			
		||||
        </object>
 | 
			
		||||
        <mxCell id="_wAeSdXpbb6KPP4DEc36-18" style="rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;entryPerimeter=0;dashed=1;dashPattern=8 8;" edge="1" parent="1" source="_wAeSdXpbb6KPP4DEc36-6" target="_wAeSdXpbb6KPP4DEc36-8">
 | 
			
		||||
          <mxGeometry relative="1" as="geometry" />
 | 
			
		||||
        </mxCell>
 | 
			
		||||
        <mxCell id="_wAeSdXpbb6KPP4DEc36-19" value="<div>Liefert Inhalte zum Webbrowser&nbsp;</div><div>von Benutzer:innen</div>" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="_wAeSdXpbb6KPP4DEc36-18">
 | 
			
		||||
          <mxGeometry x="-0.0888" y="-2" relative="1" as="geometry">
 | 
			
		||||
            <mxPoint x="5" y="7" as="offset" />
 | 
			
		||||
          </mxGeometry>
 | 
			
		||||
        </mxCell>
 | 
			
		||||
        <object placeholders="1" c4Name="Visual Analytics Tool" c4Type="SystemScopeBoundary" c4Application="Software System" label="<font style="font-size: 16px"><b><div style="text-align: left">%c4Name%</div></b></font><div style="text-align: left">[%c4Application%]</div>" id="_wAeSdXpbb6KPP4DEc36-23">
 | 
			
		||||
          <mxCell style="rounded=1;fontSize=11;whiteSpace=wrap;html=1;dashed=1;arcSize=20;fillColor=none;strokeColor=#666666;fontColor=#333333;labelBackgroundColor=none;align=left;verticalAlign=bottom;labelBorderColor=none;spacingTop=0;spacing=10;dashPattern=8 4;metaEdit=1;rotatable=0;perimeter=rectanglePerimeter;noLabel=0;labelPadding=0;allowArrows=0;connectable=0;expand=0;recursiveResize=0;editable=1;pointerEvents=0;absoluteArcSize=1;points=[[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0.25,0],[1,0.5,0],[1,0.75,0],[0.75,1,0],[0.5,1,0],[0.25,1,0],[0,0.75,0],[0,0.5,0],[0,0.25,0]];" vertex="1" parent="1">
 | 
			
		||||
            <mxGeometry x="30" y="40" width="710" height="540" as="geometry" />
 | 
			
		||||
          </mxCell>
 | 
			
		||||
        </object>
 | 
			
		||||
      </root>
 | 
			
		||||
    </mxGraphModel>
 | 
			
		||||
  </diagram>
 | 
			
		||||
 | 
			
		||||
@ -9,6 +9,7 @@ from data import etl_region_capacities_weekdays as etl_rcw
 | 
			
		||||
from data import etl_region_movAverage as etl_rmA
 | 
			
		||||
from data import etl_region_properties_capacities as etl_rpc
 | 
			
		||||
from data import etl_region_capacities_comparison as etl_rcc
 | 
			
		||||
from data import etl_region_movAverage as etl_rmA
 | 
			
		||||
from data import etl_region_properties_capacities as etl_rpc
 | 
			
		||||
from fastapi import FastAPI, Response
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -137,6 +137,7 @@ class Database:
 | 
			
		||||
		return self.connection.sql("""
 | 
			
		||||
			SELECT 
 | 
			
		||||
				regions.name, 
 | 
			
		||||
				regions.id,
 | 
			
		||||
				COUNT(*) AS count_properties 
 | 
			
		||||
			FROM 
 | 
			
		||||
				consultancy_d.properties 
 | 
			
		||||
@ -146,7 +147,8 @@ class Database:
 | 
			
		||||
				consultancy_d.regions ON regions.id = seeds.region_id 
 | 
			
		||||
			GROUP BY 
 | 
			
		||||
				properties.seed_id, 
 | 
			
		||||
				regions.name
 | 
			
		||||
				regions.name,
 | 
			
		||||
				regions.id
 | 
			
		||||
			ORDER BY
 | 
			
		||||
				count_properties ASC
 | 
			
		||||
			""")
 | 
			
		||||
@ -427,10 +429,15 @@ class Database:
 | 
			
		||||
	def properties_geo(self):
 | 
			
		||||
		return self.connection.sql("""
 | 
			
		||||
			SELECT
 | 
			
		||||
				p.id,
 | 
			
		||||
				p.check_data as coordinates
 | 
			
		||||
				p.id as property_id,
 | 
			
		||||
				p.check_data as latlng,
 | 
			
		||||
				r.id as region_id
 | 
			
		||||
			FROM
 | 
			
		||||
				consultancy_d.properties p
 | 
			
		||||
			LEFT JOIN 
 | 
			
		||||
				consultancy_d.seeds s ON s.id = p.seed_id
 | 
			
		||||
			LEFT JOIN 
 | 
			
		||||
				consultancy_d.regions r ON r.id = s.region_id
 | 
			
		||||
		""")
 | 
			
		||||
 | 
			
		||||
	def properties_geo_seeds(self):
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user