You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
133 lines
6.3 KiB
133 lines
6.3 KiB
import datetime
|
|
from io import BytesIO
|
|
|
|
import pandas as pd
|
|
from django.contrib.gis.measure import Distance
|
|
from django.db.models import F
|
|
|
|
from postamates.settings import DEFAULT_PLACEMENT_POINT_UPDATE_RADIUS
|
|
from service import models
|
|
from service.enums import PointStatus
|
|
from service.tasks import raschet
|
|
from service.utils import create_columns_dist
|
|
|
|
|
|
class LayerService:
|
|
@staticmethod
|
|
def get_post_and_pvz_categroies():
|
|
return models.Post_and_pvzCategory.objects.all(), models.Post_and_pvzGroup.objects.all()
|
|
|
|
|
|
class PointService:
|
|
|
|
def update_fact(self, postamat_id: str, fact: int):
|
|
qs = self.get_point_by_postamat_id(postamat_id)
|
|
qs.update(**{'fact': fact})
|
|
|
|
def update_postamat_id(self, point_id: int, postamat_id: str):
|
|
qs = self.get_point_by_id(point_id)
|
|
qs.update(**{'postamat_id': postamat_id})
|
|
|
|
@staticmethod
|
|
def get_min_distances_to_group(postamat_id: str):
|
|
return {d['pvz_postamates_group']: d['dist'] for d in list(
|
|
models.PlacementPointPVZDistance.objects.filter(placement_point=postamat_id).values(
|
|
'pvz_postamates_group', 'dist'))}
|
|
|
|
@staticmethod
|
|
def update_points_in_radius(qs: models.PlacementPoint, new_status: str):
|
|
triggers = False
|
|
for point in qs:
|
|
if new_status == PointStatus.Installation.name:
|
|
if point.status == PointStatus.Pending.name:
|
|
pnts = models.PlacementPoint.objects.filter(
|
|
geometry__distance_lt=(point.geometry, Distance(m=DEFAULT_PLACEMENT_POINT_UPDATE_RADIUS)),
|
|
)
|
|
pnts.update(prediction_first=F('prediction_current'), target_post_cnt=F('target_post_cnt') + 1)
|
|
triggers = True
|
|
elif new_status == PointStatus.Cancelled.name or new_status == PointStatus.Pending.name:
|
|
if point.status == PointStatus.Installation.name:
|
|
pnts = models.PlacementPoint.objects.filter(
|
|
geometry__distance_lt=(point.geometry, Distance(m=DEFAULT_PLACEMENT_POINT_UPDATE_RADIUS)),
|
|
)
|
|
pnts.update(target_post_cnt=F('target_post_cnt') - 1 if F('target_post_cnt') != 0 else 0)
|
|
triggers = True
|
|
elif new_status == PointStatus.Working.name and point.status == PointStatus.Pending.name:
|
|
triggers = True
|
|
if triggers:
|
|
raschet.delay()
|
|
|
|
@staticmethod
|
|
def update_status(qs: models.PlacementPoint, new_status: str) -> models.PlacementPoint:
|
|
for q in qs:
|
|
if q.status == PointStatus.Installation.name and new_status == PointStatus.Working.name:
|
|
qs.update(**{'age_day': 0, 'start_date': datetime.datetime.now(), 'status': new_status})
|
|
else:
|
|
qs.update(**{'status': new_status})
|
|
|
|
@staticmethod
|
|
def get_point_by_id(point_id: int):
|
|
return models.PlacementPoint.objects.filter(pk=point_id)
|
|
|
|
@staticmethod
|
|
def get_point_by_postamat_id(postamat_id: str):
|
|
return models.PlacementPoint.objects.filter(postamat_id=postamat_id)
|
|
|
|
@staticmethod
|
|
def to_excel(serializer):
|
|
data = pd.DataFrame(serializer.data)
|
|
if not data.empty:
|
|
if data['start_date'].any():
|
|
data['start_date'] = data.get('start_date').dt.tz_localize(None)
|
|
data['sample_trn'] = data['sample_trn'].astype(int)
|
|
data.rename(columns={'district_id': 'district', 'area_id': 'area'}, inplace=True)
|
|
data['min_distance_to_group'] = data['min_distance_to_group'].apply(lambda x: list(x.items()))
|
|
new_columns = data.apply(create_columns_dist, axis=1)
|
|
for ind in new_columns.columns:
|
|
expanded = new_columns[ind].apply(pd.Series)
|
|
group = models.Post_and_pvzGroup.objects.get(id=int(expanded.loc[0, 0]))
|
|
expanded[[f"group_{ind + 1}_name", f"group_{ind + 1}_category"]] = group.name, group.category.name
|
|
expanded = expanded.rename(columns={1: f"dist_to_group_{ind + 1}"})
|
|
expanded = expanded.drop(0, axis=1)
|
|
new_columns = pd.concat([new_columns, expanded], axis=1)
|
|
new_columns = new_columns.drop(ind, axis=1)
|
|
data.drop('min_distance_to_group', axis=1, inplace=True)
|
|
data = pd.concat([data, new_columns], axis=1)
|
|
with BytesIO() as b:
|
|
with pd.ExcelWriter(b) as writer:
|
|
data.to_excel(
|
|
writer, sheet_name='Placement Points',
|
|
index=False,
|
|
)
|
|
return b.getvalue()
|
|
|
|
@staticmethod
|
|
def to_json(serializer):
|
|
data = pd.DataFrame(serializer.data)
|
|
data['start_date'] = pd.to_datetime(data['start_date'], errors='coerce')
|
|
data['start_date'] = data['start_date'].dt.tz_localize(None)
|
|
data['sample_trn'] = data['sample_trn'].astype(int)
|
|
data['geometry'] = data['geometry'].apply(lambda x: {'latitude': x[1], 'longtitude': x[0]})
|
|
data.rename(columns={'district_id': 'district', 'area_id': 'area'}, inplace=True)
|
|
data['min_distance_to_group'] = data['min_distance_to_group'].apply(lambda x: list(x.items()))
|
|
new_columns = data.apply(create_columns_dist, axis=1)
|
|
for ind in new_columns.columns:
|
|
expanded = new_columns[ind].apply(pd.Series)
|
|
group = models.Post_and_pvzGroup.objects.get(id=int(expanded.loc[0, 0]))
|
|
expanded[[f"group_{ind + 1}_name", f"group_{ind + 1}_category"]] = group.name, group.category.name
|
|
expanded = expanded.rename(columns={1: f"dist_to_group_{ind + 1}"})
|
|
expanded = expanded.drop(0, axis=1)
|
|
new_columns = pd.concat([new_columns, expanded], axis=1)
|
|
new_columns = new_columns.drop(ind, axis=1)
|
|
data.drop('min_distance_to_group', axis=1, inplace=True)
|
|
data = pd.concat([data, new_columns], axis=1)
|
|
return data.to_json(orient='records')
|
|
|
|
@staticmethod
|
|
def get_first_10_k():
|
|
if models.PlacementPoint.objects.count() > 10000:
|
|
qs = models.PlacementPoint.objects.order_by('-prediction_current').all()[10000]
|
|
return qs.prediction_current
|
|
else:
|
|
return models.PlacementPoint.objects.order_by('prediction_current').first().prediction_current
|