Exemple #1
0
    def post(self, request, *args, **kwargs):

        doc = request.data.xpath('/routesRequest')
        if len(doc) < 1:
            return error_response('Не найден объект routesRequest',
                                  code='routesRequest_not_found')

        doc = doc[0]
        doc_id = doc.get('idDoc', '')
        if not doc_id:
            return error_response('Не указан параметр idDoc',
                                  code='idDoc_not_found')

        try:
            org_id = int(doc.get('idOrg', ''))
        except ValueError:
            org_id = 0

        sess_id = get_wialon_session_key(request.user)
        try:
            routes = get_routes(sess_id)
        except APIProcessError as e:
            return error_response(str(e), code=e.code)
        finally:
            logout_session(request.user, sess_id)

        context = self.get_context_data(**kwargs)
        context.update({
            'doc_id': doc_id,
            'create_date': utcnow(),
            'routes': routes,
            'org_id': org_id
        })

        return XMLResponse('ura/routes.xml', context)
Exemple #2
0
def forwards_func(apps, schema_editor):
    job_model = apps.get_model('ura', 'UraJob')
    user_model = apps.get_model('users', 'User')

    orgs = user_model.objects.filter(is_active=True, supervisor__isnull=False)
    units_cache = {}
    routes_cache = {}

    for org in orgs.iterator():
        print('Organization %s' % org.username)
        sess_id = get_wialon_session_key(org)
        units = get_units(sess_id)
        units_cache[org.pk] = {
            u['id']: '%s (%s) [%s]' % (u['name'], u['number'], u['vin'])
            for u in units
        }

        routes = get_routes(sess_id)
        logout_session(org, sess_id)
        routes_cache[org.pk] = {r['id']: r['name'] for r in routes}

    sess_id = None
    print('Jobs count: %s' % job_model.objects.count())

    i = 0
    for job in job_model.objects.iterator():
        i += 1
        if not job.user_id:
            print('%s: Job %s missed due to lack of user' % (i, job.pk))
            continue

        unit_title = route_title = None

        try:
            unit_id = int(job.unit_id)
            unit_title = units_cache.get(job.user_id, {}).get(unit_id)
            if unit_title:
                job.unit_title = unit_title
        except (ValueError, TypeError, AttributeError):
            pass

        try:
            route_id = int(job.route_id)
            route_title = routes_cache.get(job.user_id, {}).get(route_id)
            if route_title:
                job.route_title = route_title
        except (ValueError, TypeError, AttributeError):
            pass

        if unit_title or route_title:
            job.save()

        print('%s: unit=%s, route=%s (%s)' %
              (i, unit_title, route_title, job.created))
Exemple #3
0
    def get_route(self):
        routes_list = get_routes(self.sess_id, with_points=True)
        routes_dict = {x['id']: x for x in routes_list}

        try:
            self.route = routes_dict[int(self.job.route_id)]
        except (ValueError, KeyError):
            raise APIProcessError(
                'Маршрут id=%s не найден среди известных маршрутов' %
                self.job.route_id)

        self.route_point_names = [x['name'] for x in self.route['points']
                                  ] if self.route else []

        return self.route
Exemple #4
0
    def init_caches(self):
        ura_user = self.user.ura_user if self.user.ura_user_id else self.user
        jobs = Job.objects.filter(user=ura_user,
                                  date_begin__gte=self.utc_dt_from,
                                  date_end__lte=self.utc_dt_to)

        if len(self.units_dict) < 10:
            jobs = jobs.filter(
                unit_id__in=[str(x['id']) for x in self.units_dict.values()])

        self.jobs_cache = {int(j.unit_id): j for j in jobs}
        self.routes_cache = {
            x['id']: x
            for x in get_routes(self.sess_id, with_points=True)
        }
        self.print_time_needed('Init caches')
Exemple #5
0
def route_overstatement_notification(job,
                                     sess_id,
                                     routes_cache=None,
                                     job_template=None):
    """7. Превышение времени нахождения на маршруте"""
    if not job_template:
        raise NotificationError(
            'Не найден норматив шаблона задания. ID ПЛ=%s' % job.pk)

    if not routes_cache:
        routes = get_routes(sess_id, with_points=True)
        routes_cache = {r['id']: r for r in routes}

    dt_from = int(time.mktime(job.date_begin.timetuple()))
    dt_to = int(time.mktime(job.date_end.timetuple()))

    route = routes_cache.get(int(job.route_id), {})
    # ищем только маршруты
    geozones = list(
        filter(lambda x: 'маршрут' in x['name'].lower(),
               route.get('points', [])))

    if not route or not geozones:
        raise NotificationError(
            'Маршрут неизвестен или отсутствуют геозоны. ID ПЛ=%s' % job.pk)

    for geozone in geozones:
        standard = StandardPoint.objects.filter(
            wialon_id=geozone['id'].strip()).first()
        if not standard or not standard.total_time_standard:
            print(
                'Не найдена геозона или отсутствует норматив нахождения для нее. '
                'ID ПЛ=%s, ID геозоны=%s' % (job.pk, geozone['id']))
            continue

        data = {
            'itemId':
            get_wialon_report_resource_id(job.user, sess_id),
            'id':
            0,
            'callMode':
            'create',
            'n':
            'Превысил время нахождения на маршруте %s' % geozone['name'],
            'txt':
            '%UNIT% %CURR_TIME% превысил время нахождения (' +
            str(standard.total_time_standard) + ' мин.) на маршруте ' +
            geozone['name'],
            # время активации (UNIX формат)
            'ta':
            dt_from,
            # время деактивации (UNIX формат)
            'td':
            dt_to,
            # максимальное количество срабатываний (0 - не ограничено)
            'ma':
            0,
            # таймаут срабатывания(секунд)
            'cdt':
            10,
            # максимальный временной интервал между сообщениями (секунд)
            'mmtd':
            60 * 60,
            # минимальная продолжительность тревожного состояния (секунд)
            'mast':
            int(standard.total_time_standard * 60),
            # минимальная продолжительность предыдущего состояния (секунд)
            'mpst':
            10,
            # период контроля относительно текущего времени (секунд)
            'cp':
            24 * 60 * 60,
            # флаги
            'fl':
            0,
            # часовой пояс
            'tz':
            get_wialon_timezone_integer(job.user.timezone
                                        or get_current_timezone()),
            # язык пользователя (двухбуквенный код)
            'la':
            'ru',
            # массив ID объектов/групп объектов
            'un': [int(job.unit_id)],
            'sch': {
                'f1': 0,
                'f2': 0,
                't1': 0,
                't2': 0,
                'm': 0,
                'y': 0,
                'w': 0
            },
            'ctrl_sch': {
                'f1': 0,
                'f2': 0,
                't1': 0,
                't2': 0,
                'm': 0,
                'y': 0,
                'w': 0
            },
            'trg': {
                't': 'geozone',
                'p': {
                    'sensor_type': '',
                    'sensor_name_mask': '',
                    'lower_bound': 0,
                    'upper_bound': 0,
                    'merge': 0,
                    'geozone_ids': str(geozone['id'].split('-')[1]),
                    'reversed': 0,
                    'type': 0,
                    'min_speed': 0,
                    'max_speed': 0,
                    'lo': 'AND'
                }
            },
            'act': [{
                't': 'message',
                'p': {
                    'name':
                    'Превысил время нахождения на маршруте %s' %
                    geozone['name'],
                    'url':
                    '',
                    'color':
                    '',
                    'blink':
                    0
                }
            }, {
                't': 'event',
                'p': {
                    'flags': 1
                }
            }]
        }

        result = update_notification(data, sess_id)
        yield result[0], result[1], data
Exemple #6
0
def space_notification(job, sess_id, routes_cache=None, job_template=None):
    """6. Нахождение объекта вне планового маршрута"""
    if not job_template or not job_template.space_overstatements_standard:
        raise NotificationError(
            'Не найден норматив перенахождения вне маршрута. ID ПЛ=%s' %
            job.pk)

    if not routes_cache:
        routes = get_routes(sess_id, with_points=True)
        routes_cache = {r['id']: r for r in routes}

    dt_from = int(time.mktime(job.date_begin.timetuple()))
    dt_to = int(time.mktime(job.date_end.timetuple()))

    route = routes_cache.get(int(job.route_id), {})
    route_title = route.get('name')
    geozones = route.get('points', [])
    geozones_ids = list(map(lambda x: x['id'].split('-')[1], geozones))

    if not route or not geozones:
        raise NotificationError(
            'Маршрут неизвестен или отсутствуют геозоны. ID ПЛ=%s' % job.pk)

    data = {
        'itemId':
        get_wialon_report_resource_id(job.user, sess_id),
        'id':
        0,
        'callMode':
        'create',
        'n':
        'Нахождение вне планового маршрута %s' % route_title,
        'txt':
        '%UNIT% находился вне планового маршрута ' + route_title,
        # время активации (UNIX формат)
        'ta':
        dt_from,
        # время деактивации (UNIX формат)
        'td':
        dt_to,
        # максимальное количество срабатываний (0 - не ограничено)
        'ma':
        0,
        # таймаут срабатывания(секунд)
        'cdt':
        10,
        # максимальный временной интервал между сообщениями (секунд)
        'mmtd':
        60 * 60,
        # минимальная продолжительность тревожного состояния (секунд)
        'mast':
        int(job_template.space_overstatements_standard * 60.0),
        # минимальная продолжительность предыдущего состояния (секунд)
        'mpst':
        10,
        # период контроля относительно текущего времени (секунд)
        'cp':
        24 * 60 * 60,
        # флаги
        'fl':
        0,
        # часовой пояс
        'tz':
        get_wialon_timezone_integer(job.user.timezone
                                    or get_current_timezone()),
        # язык пользователя (двухбуквенный код)
        'la':
        'ru',
        # массив ID объектов/групп объектов
        'un': [int(job.unit_id)],
        'sch': {
            'f1': 0,
            'f2': 0,
            't1': 0,
            't2': 0,
            'm': 0,
            'y': 0,
            'w': 0
        },
        'ctrl_sch': {
            'f1': 0,
            'f2': 0,
            't1': 0,
            't2': 0,
            'm': 0,
            'y': 0,
            'w': 0
        },
        'trg': {
            't': 'geozone',
            'p': {
                'sensor_type': '',
                'sensor_name_mask': '',
                'lower_bound': 0,
                'upper_bound': 0,
                'merge': 0,
                'geozone_ids': ','.join(geozones_ids),
                'reversed': 0,
                'type': 1,
                'min_speed': 0,
                'max_speed': 0,
                'lo': 'AND'
            }
        },
        'act': [{
            't': 'message',
            'p': {
                'name': 'Нахождение вне планового маршрута %s' % route_title,
                'url': '',
                'color': '',
                'blink': 0
            }
        }, {
            't': 'event',
            'p': {
                'flags': 1
            }
        }]
    }

    result = update_notification(data, sess_id)
    yield result[0], result[1], data
Exemple #7
0
    def get_context_data(self, **kwargs):
        sess_id = self.request.session.get('sid')
        if not sess_id:
            raise ReportException(WIALON_NOT_LOGINED)

        try:
            units_list = get_units(sess_id, extra_fields=True)
        except WialonException as e:
            raise ReportException(str(e))

        self.default_unit = units_list[0]['id']
        kwargs = super(VchmTaxiingView, self).get_context_data(**kwargs)
        form = kwargs['form']
        kwargs['units'] = units_list

        if not self.request.POST:
            return kwargs

        if form.is_valid():
            report_data = []
            stats = {
                'dt_from_min': None,
                'dt_to_max': None,
                'total_time': .0,
                'moving_time': .0,
                'parking_time': .0,
                'idle_time': .0,
                'idle_off_time': .0,
                'angle_sensor_time': .0,
                'over_3min_parkings_count': 0,
                'odometer': .0,
                'fuel_level_delta': .0,
                'refills_delta': .0,
                'discharge_delta': .0,
                'overstatement_mileage': .0,
                'overstatement_time': .0
            }
            kwargs.update(report_data=report_data, stats=stats)

            self.user = User.objects.filter(is_active=True) \
                .filter(wialon_username=self.request.session.get('user')).first()
            if not self.user:
                raise ReportException(WIALON_USER_NOT_FOUND)

            local_dt_from = datetime.datetime.combine(form.cleaned_data['dt'],
                                                      datetime.time(0, 0, 0))
            local_dt_to = datetime.datetime.combine(form.cleaned_data['dt'],
                                                    datetime.time(23, 59, 59))

            unit_id = form.cleaned_data.get('unit')
            self.units_dict = OrderedDict([(x['name'], x) for x in units_list
                                           if x['id'] == unit_id])
            unit = list(self.units_dict.values())[0]

            routes = {
                x['id']: x
                for x in get_routes(sess_id, with_points=True)
            }
            standard_job_templates = StandardJobTemplate.objects \
                .filter(wialon_id__in=[str(x) for x in routes.keys()]) \
                .prefetch_related(
                    Prefetch(
                        'points',
                        StandardPoint.objects.filter(
                            Q(total_time_standard__isnull=False) |
                            Q(parking_time_standard__isnull=False)
                        ),
                        'points_cache'
                    )
                )

            standards = {
                int(x.wialon_id): {
                    'space_overstatements_standard':
                    x.space_overstatements_standard
                    if x.space_overstatements_standard is not None else None,
                    'points': {
                        p.title: {
                            'total_time_standard':
                            p.total_time_standard
                            if p.total_time_standard is not None else None,
                            'parking_time_standard':
                            p.parking_time_standard
                            if p.parking_time_standard is not None else None
                        }
                        for p in x.points_cache
                    }
                }
                for x in standard_job_templates if
                x.space_overstatements_standard is not None or x.points_cache
            }

            service = MovingService(self.user,
                                    local_dt_from,
                                    local_dt_to,
                                    sess_id,
                                    object_id=unit_id,
                                    units_dict=self.units_dict,
                                    last_visit_allowance=60 * 10,
                                    devide_last_parking_by_motohours=True)
            service.exec_report()
            service.analyze()

            ura_user = self.user.ura_user if self.user.ura_user_id else self.user
            jobs = Job.objects.filter(
                user=ura_user,
                date_begin__gte=local_to_utc_time(local_dt_from,
                                                  ura_user.timezone),
                date_end__lte=local_to_utc_time(local_dt_to,
                                                ura_user.timezone))
            jobs_cache = {int(j.unit_id): j for j in jobs}

            normal_ratio = 1 + (form.cleaned_data.get(
                'overstatement_param', DEFAULT_OVERSTATEMENT_NORMAL_PERCENTAGE)
                                / 100.0)

            unit_report_data = service.report_data.get(unit['name'])
            if not unit_report_data:
                return kwargs

            kwargs.update(heading_data=OrderedDict((
                ('Марка, модель', self.get_car_model(unit['name'])),
                ('Гос.номер', self.get_car_number(unit['name'])),
                ('VIN', self.get_car_vin(unit['name'])),
                ('Тип ТС', self.get_car_type(unit['name'])),
                ('Дата', date_format(form.cleaned_data['dt'], 'd.m.Y')))))

            job = jobs_cache.get(unit['id'])
            standard = None
            if job:
                standard = standards.get(int(job.route_id))

            for i, visit in enumerate(unit_report_data.geozones.target):
                try:
                    next_visit = unit_report_data.geozones.target[i + 1]
                except IndexError:
                    next_visit = None

                point_standard = None
                if standard:
                    point_standard = standard.get('points', {}).get(
                        visit.geozone_full, {})
                    if not point_standard:
                        point_standard = standard.get('points', {}).get(
                            visit.geozone, {})

                total_standart = parking_standard = None
                if point_standard:
                    total_standart = point_standard['total_time_standard'] * 60
                    parking_standard = point_standard[
                        'parking_time_standard'] * 60

                total_delta = (visit.dt_to - visit.dt_from).total_seconds()
                moving_delta = getattr(visit, 'trips_delta', .0)
                # переделал пока под расчет разницы между периодом нахождения и временем в
                # движении, так как в расчет стоянок иногда не принимаются концевые участки
                # длиной несколько минут
                # parking_delta = getattr(visit, 'parkings_delta', .0)
                parking_delta = max(.0, total_delta - moving_delta)

                motohours_delta = getattr(visit, 'motohours_delta', .0)
                idle_delta = getattr(visit, 'idle_delta', .0)
                off_delta = max(.0, total_delta - motohours_delta)
                angle_sensor_delta = getattr(visit, 'angle_sensor_delta', .0)
                refillings_volume = getattr(visit, 'refillings_volume', .0)
                discharges_volume = getattr(visit, 'discharges_volume', .0)

                overstatement_time = .0
                if total_standart is not None \
                        and total_delta / total_standart > normal_ratio:
                    overstatement_time += total_delta - total_standart

                elif parking_standard is not None \
                        and parking_delta / parking_standard > normal_ratio:
                    overstatement_time += parking_delta - parking_standard

                point_name = self.get_point_name(visit.geozone)
                if not point_name:
                    # если первая строка, и зона неизвестна, то это зона, где машина
                    # находилась до включения блока (допущение, предложенное заказчиком)
                    if i == 0 and next_visit:
                        point_name = self.get_point_name(next_visit.geozone)
                    else:
                        point_name = 'Неизвестная'

                over_3min_parkings_count = 0
                if point_name == 'Неизвестная':
                    over_3min_parkings_count = len([
                        True for x in getattr(visit, 'parkings', [])
                        if (x.dt_to - x.dt_from).total_seconds() > 3 * 60
                    ])

                report_row = {
                    'car_number': self.get_car_number(unit['name']),
                    'driver_fio': job.driver_fio
                    if job and job.driver_fio else 'Неизвестный',
                    'route_name': job.route_title
                    if job and job.route_title else 'Неизвестный маршрут',
                    'point_name': point_name,
                    'dt_from': visit.dt_from,
                    'dt_to': visit.dt_to,
                    'total_time': total_delta,
                    'moving_time': moving_delta,
                    'parking_time': parking_delta,
                    'idle_time': idle_delta,
                    'idle_off_time': off_delta,
                    'angle_sensor_time': angle_sensor_delta,
                    'over_3min_parkings_count': over_3min_parkings_count,
                    'odometer': self.get_odometer(unit, visit),
                    'fuel_level_delta': self.get_fuel_delta(unit, visit),
                    'refills_delta': refillings_volume,
                    'discharge_delta': discharges_volume,
                    'overstatement_mileage': .0,
                    'overstatement_time': overstatement_time,
                    'faults': self.render_faults(visit, i, unit_report_data)
                }
                report_data.append(report_row)

                if stats['dt_from_min'] is None:
                    stats['dt_from_min'] = visit.dt_from
                else:
                    stats['dt_from_min'] = min(stats['dt_from_min'],
                                               visit.dt_from)

                if stats['dt_to_max'] is None:
                    stats['dt_to_max'] = visit.dt_to
                else:
                    stats['dt_to_max'] = max(stats['dt_to_max'], visit.dt_to)

                stats['total_time'] += total_delta
                stats['moving_time'] += moving_delta
                stats['parking_time'] += parking_delta
                stats['idle_time'] += idle_delta
                stats['idle_off_time'] += off_delta
                stats['angle_sensor_time'] += angle_sensor_delta
                stats['over_3min_parkings_count'] += over_3min_parkings_count
                stats['odometer'] += self.get_odometer(unit, visit)
                stats['fuel_level_delta'] += self.get_fuel_delta(unit, visit)
                stats['refills_delta'] += refillings_volume
                stats['discharge_delta'] += discharges_volume
                stats['overstatement_mileage'] += .0
                stats['overstatement_time'] += overstatement_time

        return kwargs
Exemple #8
0
def cache_geozones():
    print('Caching geozones...')

    with transaction.atomic():
        i = 1
        users = User.objects.filter(supervisor__isnull=False,
                                    wialon_username__isnull=False,
                                    wialon_password__isnull=False).exclude(
                                        wialon_username='', wialon_password='')

        print('%s users found' % len(users))

        for user in users:
            sess_id = get_wialon_session_key(user)
            print('%s) User %s processing' % (i, user))

            routes = get_routes(sess_id, with_points=True)
            logout_session(user, sess_id)
            del sess_id

            print('%s routes found' % len(routes))

            for route in routes:
                print('Route %s' % route['name'])

                name = route['name'].strip()
                job_template, created = StandardJobTemplate.objects.get_or_create(
                    wialon_id=str(route['id']),
                    defaults={
                        'title': name,
                        'user': user
                    })

                existing_points = set()
                if not created:
                    if job_template.title != name:
                        job_template.title = name
                    job_template.user = user
                    job_template.save()

                    existing_points = {p for p in job_template.points.all()}

                # убираем дубли (когда одна и та же геозона дублируется в маршруте)
                route['points'] = {r['id']: r
                                   for r in route['points']}.values()

                print('%s points found, already exist: %s' %
                      (len(route['points']), len(existing_points)))

                for point in route['points']:
                    name = point['name'].strip()
                    standard_point, created = StandardPoint.objects.get_or_create(
                        job_template=job_template,
                        wialon_id=str(point['id']),
                        defaults={'title': name})

                    if not created:
                        existing_points.discard(standard_point)

                        if standard_point.title != name:
                            standard_point.title = name
                            standard_point.save()

                if existing_points:
                    print('Points to remove: %s' %
                          ', '.join([str(x) for x in existing_points]))
                    for existing_point in existing_points:
                        existing_point.delete()

            sleep(.3)
            i += 1
    def get_context_data(self, **kwargs):
        kwargs = super(InvalidJobStartEndView, self).get_context_data(**kwargs)
        report_data = None
        form = kwargs['form']
        stats = {}
        kwargs['today'] = datetime.date.today()

        if self.request.POST:
            if form.is_valid():
                report_data = OrderedDict()
                sess_id = self.request.session.get('sid')
                if not sess_id:
                    raise ReportException(WIALON_NOT_LOGINED)

                user = User.objects.filter(is_active=True) \
                    .filter(wialon_username=self.request.session.get('user')).first()
                if not user:
                    raise ReportException(WIALON_USER_NOT_FOUND)

                dt_from = local_to_utc_time(form.cleaned_data['dt_from'],
                                            user.timezone)
                dt_to = local_to_utc_time(
                    form.cleaned_data['dt_to'].replace(second=59),
                    user.timezone)

                routes_dict = {
                    x['id']: x
                    for x in get_routes(sess_id, with_points=True)
                }
                units_dict = {x['id']: x for x in get_units(sess_id)}

                ura_user = user.ura_user if user.ura_user_id else user
                jobs = Job.objects.filter(
                    user=ura_user,
                    date_begin__gte=dt_from,
                    date_end__lte=dt_to,
                    route_id__in=list(
                        routes_dict.keys())).prefetch_related('points')

                if jobs:
                    report_data = dict(start=[], end=[])

                def get_car_number(unit_id, _units_dict):
                    return _units_dict.get(int(unit_id), {}).get('number', '')

                for job in jobs:
                    route = routes_dict.get(int(job.route_id))

                    if not route:
                        print('No route found! job_id=%s' % job.pk)
                        continue

                    elif not form.cleaned_data.get('include_fixed', False) \
                            and is_fixed_route(route['name']):
                        print('Fixed route was skipped. job_id=%s, route=%s' %
                              (job.pk, route['name']))
                        continue

                    route_points = route['points']
                    has_base = len(
                        list(
                            filter(lambda x: 'база' in x['name'].lower(),
                                   route_points))) > 0

                    points = list(job.points.order_by('id'))

                    if not points:
                        # кэша нет, пропускаем
                        print('No job moving cache! job_id=%s' % job.pk)
                        continue

                    start_point = points[0]
                    start_point_name = start_point.title.lower().strip()

                    if (has_base and 'база' not in start_point_name)\
                            or (
                                not has_base
                                and 'погрузк' not in start_point_name
                                and 'база' not in start_point_name
                            ):
                        row = self.get_new_start_grouping()

                        row['car_number'] = get_car_number(
                            job.unit_id, units_dict)
                        row['driver_fio'] = job.driver_fio.strip()
                        row['job_date_start'] = utc_to_local_time(
                            job.date_begin.replace(tzinfo=None), user.timezone)
                        row['point_type'] = get_point_type(start_point.title)
                        row['route_id'] = str(job.route_id)
                        row['route_title'] = routes_dict.get(
                            int(job.route_id), {}).get('name', '')
                        row['route_fact_start'] = start_point.title

                        if start_point_name == 'space':
                            row['fact_start'] = '%s, %s' % (start_point.lat,
                                                            start_point.lng)

                        report_data['start'].append(row)

                    if len(points) <= 1:
                        continue

                    end_point = points[-1]
                    if not end_point.enter_date_time:
                        continue

                    delta = (job.date_end -
                             end_point.enter_date_time).total_seconds() / 60.0
                    if delta < form.cleaned_data.get('job_end_timeout', 30.0):
                        continue

                    row = self.get_new_end_grouping()
                    row['car_number'] = get_car_number(job.unit_id, units_dict)
                    row['driver_fio'] = job.driver_fio.strip()
                    row['job_date_end'] = utc_to_local_time(
                        job.date_end.replace(tzinfo=None), user.timezone)
                    row['point_type'] = get_point_type(end_point.title)
                    row['point_title'] = end_point.title
                    row['route_id'] = str(job.route_id)
                    row['route_title'] = routes_dict.get(
                        int(job.route_id), {}).get('name', '')
                    row['fact_end'] = utc_to_local_time(
                        end_point.enter_date_time.replace(tzinfo=None),
                        user.timezone)
                    row['delta'] = round(delta / 60.0, 2)

                    report_data['end'].append(row)

        kwargs.update(stats=stats, report_data=report_data)

        return kwargs
Exemple #10
0
    def post(self, request, *args, **kwargs):
        jobs = []
        jobs_els = request.data.xpath('/setJobs/job')
        sess_id = get_wialon_session_key(request.user)

        if jobs_els:

            for j in jobs_els:
                data = parse_xml_input_data(request, self.model_mapping, j)

                name = data.get('name')
                if not name:
                    logout_session(request.user, sess_id)
                    return error_response('Не указан параметр jobName',
                                          code='jobName_not_found')

                routes = get_routes(sess_id, with_points=True)
                units = get_units(sess_id)

                routes_ids = [x['id'] for x in routes]
                if data['route_id'] not in routes_ids:
                    return error_response(
                        'Шаблон задания idRoute неверный или не принадлежит текущей организации',
                        code='route_permission')

                units_cache = {
                    u['id']:
                    '%s (%s) [%s]' % (u['name'], u['number'], u['vin'])
                    for u in units
                }

                try:
                    data['unit_title'] = units_cache.get(int(data['unit_id']))
                except (ValueError, TypeError, AttributeError):
                    pass

                if not data['unit_title']:
                    return error_response(
                        'Объект ID=%s не найден в текущем ресурсе организации'
                        % data['unit_id'],
                        code='unit_not_found_permission')

                routes_cache = {r['id']: r for r in routes}
                try:
                    data['route_title'] = routes_cache.get(
                        int(data['route_id']), {}).get('name')
                except (ValueError, TypeError, AttributeError):
                    pass

                data['user'] = request.user
                self.job = self.model.objects.create(**data)
                register_job_notifications(self.job,
                                           sess_id,
                                           routes_cache=routes_cache)
                logout_session(request.user, sess_id)
                jobs.append(self.job)

        context = self.get_context_data(**kwargs)
        context.update({'now': utcnow(), 'acceptedJobs': jobs})

        return XMLResponse('ura/ackjobs.xml', context)
Exemple #11
0
    def get_context_data(self, **kwargs):
        kwargs = super(VchmIdleTimesView, self).get_context_data(**kwargs)
        report_data = None
        form = kwargs['form']

        sess_id = self.request.session.get('sid')
        if not sess_id:
            raise ReportException(WIALON_NOT_LOGINED)

        try:
            units_list = get_units(sess_id, extra_fields=True)
        except WialonException as e:
            raise ReportException(str(e))

        kwargs['units'] = units_list

        if self.request.POST:

            if form.is_valid():
                report_data = []

                user = User.objects.filter(is_active=True) \
                    .filter(wialon_username=self.request.session.get('user')).first()
                if not user:
                    raise ReportException(WIALON_USER_NOT_FOUND)

                local_dt_from = datetime.datetime.combine(
                    form.cleaned_data['dt_from'],
                    datetime.time(0, 0, 0)
                )
                local_dt_to = datetime.datetime.combine(
                    form.cleaned_data['dt_to'],
                    datetime.time(23, 59, 59)
                )

                selected_unit = form.cleaned_data.get('unit')
                self.units_dict = OrderedDict(
                    (x['name'], x) for x in units_list
                    if not selected_unit or (selected_unit and x['id'] == selected_unit)
                )

                routes = {
                    x['id']: x for x in get_routes(sess_id, with_points=True)
                }
                standard_job_templates = StandardJobTemplate.objects \
                    .filter(wialon_id__in=[str(x) for x in routes.keys()]) \
                    .prefetch_related(
                        Prefetch(
                            'points',
                            StandardPoint.objects.filter(
                                Q(total_time_standard__isnull=False) |
                                Q(parking_time_standard__isnull=False)
                            ),
                            'points_cache'
                        )
                    )

                standards = {
                    int(x.wialon_id): {
                        'space_overstatements_standard': x.space_overstatements_standard
                        if x.space_overstatements_standard is not None else None,
                        'points': {
                            p.title: {
                                'total_time_standard': p.total_time_standard
                                if p.total_time_standard is not None else None,
                                'parking_time_standard': p.parking_time_standard
                                if p.parking_time_standard is not None else None
                            } for p in x.points_cache
                        }
                    } for x in standard_job_templates
                    if x.space_overstatements_standard is not None or x.points_cache
                }

                ura_user = user.ura_user if user.ura_user_id else user
                jobs = Job.objects.filter(
                    user=ura_user,
                    date_begin__gte=local_to_utc_time(local_dt_from, ura_user.timezone),
                    date_end__lte=local_to_utc_time(local_dt_to, ura_user.timezone)
                )
                jobs_cache = {int(j.unit_id): j for j in jobs}

                mobile_vehicle_types = set()
                vehtypes = user.wialon_mobile_vehicle_types or ura_user.wialon_mobile_vehicle_types
                if vehtypes:
                    mobile_vehicle_types = set(x.strip() for x in vehtypes.lower().split(','))

                service = MovingService(
                    user,
                    local_dt_from,
                    local_dt_to,
                    sess_id,
                    object_id=selected_unit if selected_unit else None,
                    units_dict=self.units_dict,
                    calc_odometer=False
                )
                service.exec_report()
                service.analyze()

                normal_ratio = 1 + (
                    form.cleaned_data.get(
                        'overstatement_param',
                        DEFAULT_OVERSTATEMENT_NORMAL_PERCENTAGE
                    ) / 100.0
                )
                total_count = len(self.units_dict)
                i = 0
                for unit in self.units_dict.values():
                    i += 1
                    print('%s/%s: %s' % (i, total_count, unit['name']))

                    vehicle_type = unit['vehicle_type'].lower()
                    if mobile_vehicle_types and vehicle_type \
                            and vehicle_type not in mobile_vehicle_types:
                        print('%s) Skip vehicle type "%s" of item %s' % (
                            i, vehicle_type, unit['name']
                        ))
                        continue

                    job = jobs_cache.get(unit['id'])
                    standard = None
                    fixed_route = False
                    if job:
                        fixed_route = is_fixed_route(job.route_title)
                        standard = standards.get(int(job.route_id))

                    unit_report_data = service.report_data.get(unit['name'], {})

                    for visit in unit_report_data.geozones.target:
                        total_standart = parking_standard = space_standard = None
                        point_standard = {}
                        if standard:
                            point_standard = standard.get('points', {}).get(visit.geozone_full, {})
                            if not point_standard:
                                point_standard = standard.get('points', {}).get(visit.geozone, {})

                        if fixed_route:
                            point_standard['space_time_standard'] = form.cleaned_data.get(
                                'default_space_time_standard',
                                DEFAULT_SPACE_TOTAL_TIME_STANDARD_MINUTES
                            )

                        if point_standard.get('total_time_standard'):
                            total_standart = point_standard['total_time_standard'] * 60
                        if point_standard.get('parking_time_standard'):
                            parking_standard = point_standard['parking_time_standard'] * 60
                        if point_standard.get('space_time_standard'):
                            space_standard = point_standard['space_time_standard'] * 60

                        overstatement = .0
                        total_time = (visit.dt_to - visit.dt_from).total_seconds()
                        parking_time = getattr(visit, 'parkings_delta', .0)

                        if visit.geozone.lower() == 'space':
                            if space_standard is not None \
                                    and total_time / space_standard > normal_ratio:
                                overstatement += total_time - space_standard

                        elif total_standart is not None \
                                and total_time / total_standart > normal_ratio:
                            overstatement += total_time - total_standart

                        if parking_standard is not None \
                                and parking_time / parking_standard > normal_ratio:
                            overstatement += parking_time - parking_standard

                        if overstatement > .0 and total_time < 86395:  # суточный простой исключаем
                            row = dict()
                            row['driver_fio'] = job.driver_fio \
                                if job and job.driver_fio else 'Неизвестный'
                            row['car_number'] = self.get_car_number(unit['name'])
                            row['car_vin'] = self.get_car_vin(unit['name'])
                            row['car_type'] = self.get_car_type(unit['name'])
                            row['route_name'] = job.route_title \
                                if job and job.route_title else 'Неизвестный маршрут'
                            row['point_name'] = self.get_point_name(visit.geozone)

                            row['total_time'] = total_time
                            row['parking_time'] = parking_time
                            row['off_motor_time'] = max(total_time - getattr(
                                visit, 'motohours_delta', .0
                            ), .0)
                            row['idle_time'] = sum([
                                (x.dt_to - x.dt_from).total_seconds() for x in
                                getattr(visit, 'idle_times', [])
                            ])
                            row['gpm_time'] = getattr(
                                visit, 'angle_sensor_delta', .0
                            )
                            row['parkings'] = getattr(visit, 'parkings', [])

                            row['overstatement'] = round(overstatement)
                            report_data.append(row)

            kwargs.update(
                report_data=report_data
            )

        return kwargs
Exemple #12
0
    def get_context_data(self, **kwargs):
        kwargs = super(OverstatementsView, self).get_context_data(**kwargs)
        report_data = None
        form = kwargs['form']
        kwargs['today'] = datetime.date.today()
        stats = {
            'total': 0
        }

        if self.request.POST:
            report_data = []

            if form.is_valid():
                sess_id = self.request.session.get('sid')
                if not sess_id:
                    raise ReportException(WIALON_NOT_LOGINED)

                user = User.objects.filter(is_active=True) \
                    .filter(wialon_username=self.request.session.get('user')).first()
                if not user:
                    raise ReportException(WIALON_USER_NOT_FOUND)

                dt_from = local_to_utc_time(form.cleaned_data['dt_from'], user.timezone)
                dt_to = local_to_utc_time(
                    form.cleaned_data['dt_to'].replace(second=59), user.timezone
                )

                routes = {
                    x['id']: x for x in get_routes(sess_id, with_points=True)
                }
                units_dict = {x['id']: x for x in get_units(sess_id)}

                standard_job_templates = StandardJobTemplate.objects\
                    .filter(wialon_id__in=[str(x) for x in routes.keys()])\
                    .prefetch_related(
                        Prefetch(
                            'points',
                            StandardPoint.objects.filter(
                                Q(total_time_standard__isnull=False) |
                                Q(parking_time_standard__isnull=False)
                            ),
                            'points_cache'
                        )
                    )

                standards = {
                    int(x.wialon_id): {
                        'space_overstatements_standard': x.space_overstatements_standard
                        if x.space_overstatements_standard is not None else None,
                        'points': {
                            p.title: {
                                'total_time_standard': p.total_time_standard
                                if p.total_time_standard is not None else None,
                                'parking_time_standard': p.parking_time_standard
                                if p.parking_time_standard is not None else None
                            } for p in x.points_cache
                        }
                    } for x in standard_job_templates
                    if x.space_overstatements_standard is not None or x.points_cache
                }

                ura_user = user.ura_user if user.ura_user_id else user
                jobs = Job.objects \
                    .filter(
                        user=ura_user,
                        date_begin__gte=dt_from,
                        date_end__lte=dt_to,
                        route_id__in=list(routes.keys())
                    )\
                    .prefetch_related(
                        Prefetch(
                            'points', JobPoint.objects.order_by('id'), to_attr='cached_points'
                        )
                    )\
                    .order_by('date_begin', 'date_end')

                def get_car_number(unit_id, _units_dict):
                    return _units_dict.get(int(unit_id), {}).get('number', '')

                normal_ratio = 1 + (form.cleaned_data['overstatement_param'] / 100.0)

                for job in jobs:
                    spaces_total_time = .0
                    spaces = []
                    standard = standards.get(int(job.route_id))
                    if not standard:
                        print('No standards (job id=%s)' % job.pk)
                        continue

                    for point in job.cached_points:

                        if point.title.lower() == 'space':
                            spaces.append(point)
                            spaces_total_time += point.total_time

                        else:
                            point_standard = standard['points'].get(point.title)
                            if not point_standard:
                                continue

                            overstatement = .0
                            total_time = point.total_time / 60.0
                            if point_standard['total_time_standard'] is not None\
                                    and total_time / point_standard['total_time_standard'] \
                                    > normal_ratio:
                                overstatement += total_time - point_standard['total_time_standard']

                            parking_time = point.parking_time / 60.0
                            if point_standard['parking_time_standard'] is not None\
                                    and parking_time / point_standard['parking_time_standard'] \
                                    > normal_ratio:
                                overstatement += parking_time \
                                    - point_standard['parking_time_standard']

                            if overstatement > .0:
                                stats['total'] += overstatement / 60.0
                                row = self.get_new_grouping()
                                row['fact_period'] = '%s - %s' % (
                                    date(utc_to_local_time(
                                        point.enter_date_time.replace(tzinfo=None),
                                        user.timezone
                                    ), 'd.m.Y H:i:s'),
                                    date(utc_to_local_time(
                                        point.leave_date_time.replace(tzinfo=None),
                                        user.timezone
                                    ), 'd.m.Y H:i:s')
                                )

                                row['plan_period'] = '%s - %s' % (
                                    date(utc_to_local_time(
                                        job.date_begin.replace(tzinfo=None),
                                        user.timezone
                                    ), 'd.m.Y H:i:s'),
                                    date(utc_to_local_time(
                                        job.date_end.replace(tzinfo=None),
                                        user.timezone
                                    ), 'd.m.Y H:i:s')
                                )
                                row['route_id'] = job.route_id
                                row['point_name'] = point.title
                                row['point_type'] = get_point_type(point.title)
                                row['car_number'] = get_car_number(job.unit_id, units_dict)
                                row['driver_fio'] = job.driver_fio if job.driver_fio else ''
                                overstatement = round(overstatement / 60.0, 2) \
                                    if overstatement > 1.0 else round(overstatement / 60.0, 4)
                                row['overstatement'] = overstatement

                                report_data.append(row)

                    spaces_total_time /= 60.0
                    if spaces \
                            and standard['space_overstatements_standard'] is not None \
                            and spaces_total_time / standard['space_overstatements_standard'] \
                            > normal_ratio:
                        row = self.get_new_grouping()
                        # период пока не указываем, так как это по всему маршруту
                        row['fact_period'] = '%s - %s' % (
                            date(utc_to_local_time(
                                spaces[0].enter_date_time.replace(tzinfo=None),
                                user.timezone
                            ), 'd.m.Y H:i:s'),
                            date(utc_to_local_time(
                                spaces[-1].leave_date_time.replace(tzinfo=None),
                                user.timezone
                            ), 'd.m.Y H:i:s')
                        )
                        row['plan_period'] = '%s - %s' % (
                            date(utc_to_local_time(
                                job.date_begin.replace(tzinfo=None),
                                user.timezone
                            ), 'd.m.Y H:i:s'),
                            date(utc_to_local_time(
                                job.date_end.replace(tzinfo=None),
                                user.timezone
                            ), 'd.m.Y H:i:s')
                        )
                        row['route_id'] = job.route_id
                        row['point_name'] = 'SPACE'
                        row['point_type'] = '0'
                        row['car_number'] = get_car_number(job.unit_id, units_dict)
                        row['driver_fio'] = job.driver_fio if job.driver_fio else ''
                        row['overstatement'] = round((
                            spaces_total_time - standard['space_overstatements_standard']
                        ) / 60.0, 2)

                        report_data.append(row)
                        stats['total'] += row['overstatement']

            report_data = sorted(report_data, key=lambda k: k['fact_period'])

        if stats['total']:
            stats['total'] = round(stats['total'], 2)

        kwargs.update(
            stats=stats,
            report_data=report_data
        )

        return kwargs
Exemple #13
0
    def get_context_data(self, **kwargs):
        kwargs = super(FinishedJobsView, self).get_context_data(**kwargs)
        report_data = None
        form = kwargs['form']
        kwargs['today'] = datetime.date.today()
        stats = {'total': 0, 'non_actual': 0}

        if self.request.POST:
            report_data = OrderedDict()

            if form.is_valid():
                sess_id = self.request.session.get('sid')
                if not sess_id:
                    raise ReportException(WIALON_NOT_LOGINED)

                user = User.objects.filter(is_active=True) \
                    .filter(wialon_username=self.request.session.get('user')).first()

                if not user:
                    raise ReportException(WIALON_USER_NOT_FOUND)

                dt_from = local_to_utc_time(form.cleaned_data['dt_from'],
                                            user.timezone)
                dt_to = local_to_utc_time(
                    form.cleaned_data['dt_to'].replace(second=59),
                    user.timezone)

                routes_list = get_routes(sess_id, with_points=True)
                routes_dict = {
                    x['id']: x
                    for x in routes_list if not is_fixed_route(x['name'])
                }
                all_routes_dict = {x['id']: x for x in routes_list}
                used_routes = set()

                stats['total'] = len(routes_dict)

                ura_user = user.ura_user if user.ura_user_id else user
                jobs = Job.objects\
                    .filter(
                        user=ura_user,
                        date_begin__gte=dt_from,
                        date_end__lte=dt_to,
                        route_id__in=list(routes_dict.keys())
                    )\
                    .prefetch_related('points').order_by('date_begin', 'date_end')

                for job in jobs:
                    route = routes_dict.get(int(job.route_id))
                    if not route:
                        possible_route_name = all_routes_dict.get(int(job.route_id), {})\
                            .get('name', '')
                        if not is_fixed_route(possible_route_name):
                            print(
                                'Route not found (job_id: %s, route name: %s)'
                                % (job.pk, possible_route_name))
                        continue

                    key = int(job.route_id)
                    used_routes.add(key)
                    if key not in report_data:
                        report_data[key] = self.get_new_grouping()
                        report_data[key]['key'] = key
                        report_data[key]['name'] = all_routes_dict.get(
                            key, {}).get('name', '')

                    report_data[key]['plan'] += 1

                    route_points = {p['name'] for p in route['points']}
                    points = list(
                        map(
                            lambda x: x.title,
                            filter(lambda x: x.title != 'SPACE',
                                   job.points.all())))
                    remaining_route_points = [
                        x for x in route_points if x not in points
                    ]

                    if remaining_route_points:
                        stats['non_actual'] += 1
                    else:
                        report_data[key]['finished'] += 1

                for v in report_data.values():
                    v['ratio'] = round((v['finished'] / v['plan']) * 100, 2)

                # убираем полностью завершенные
                report_data = OrderedDict(
                    (x[0], x[1]) for x in report_data.items()
                    if x[1]['ratio'] < 100 -
                    form.cleaned_data['non_actual_param'])

                # добавим те, которые вообще не использовались:
                unused_routes = [
                    x for x in routes_dict.values()
                    if x['id'] not in used_routes
                ]
                for unused_route in unused_routes:
                    key = unused_route['id']
                    report_data[key] = self.get_new_grouping(key)
                    report_data[key]['name'] = all_routes_dict.get(
                        key, {}).get('name', '')

        kwargs.update(stats=stats, report_data=report_data)

        return kwargs