Pull to refresh
0
True Engineering
Лаборатория технологических инноваций

Мобильное приложение против мошенников и бумажной волокиты в автостраховании

Reading time 10 min
Views 8.5K
Сегодня хотим поделиться нашим опытом в разборе автомобилей. Нет, мы не планируем устраивать выпуск Top Gear. У нас для вас другая тема – как с помощью мобильного приложения перевести в цифровой формат бумажную волокиту вокруг добровольного автострахования – всем известного КАСКО.

Тема будет интересна в первую очередь тем, кто занимается разработкой мобильных бизнес-приложений и автоматизацией бизнес-процессов. Интересные технические моменты будем рассказывать на примере разработки под iOS.



Итак, к проблематике. КАСКО – вторая по значимости услуга страховых компаний для физических лиц. Самая популярная, естественно, ОСАГО, а далее сразу КАСКО. Вот только оформить ОСАГО можно буквально на каждом шагу, а за КАСКО вам придется еще попотеть: не только выбрать страховую, но и дождаться агента, заполнить кипу бумажек, провести с агентом осмотр машины, дождаться, когда он отвезет все бумажки и фото в офис, андеррайтер все проверит, даст добро, после этого вы подписываете документы, у вас готовы принять деньги, и ваша машина, наконец, защищена. Аллилуйя!



Но страховые, конечно, понимают, что забюрократизированная система, бумажная волокита, низкое качество работы специалистов реально мешают им развивать услугу и привлекать новых клиентов. И что делать?

Мы ответили на этот вызов системой из мобильного приложения для страховых агентов под iOS и Android, серверной частью и рабочего места андеррайтера. Через приложение представители компании получают заказы и в нем же могут проводить полную процедуру осмотра и фотофиксирования с моментальной отправкой данных в страховую компанию, где их проверяет андеррайтер и выносит вердикт.



Одно-единственное приложение решает целый ряд задач страховой компании:
  1. Обеспечивает более легкий «вход в профессию». Вместо очного обучения агентов, обеспечения их фотоаппаратами, теперь достаточно дать агенту ссылку на скачивание приложения.
  2. При этом повышается качество работы агентов. За счет зашитых в приложение множественных «защит от дурака» процедура предполагает неукоснительное соблюдение технологии.
  3. И одновременно такая технология эффективно защищает от всевозможных махинаций и мошенничества за счет предусмотренных в приложении мер контроля и ограничений.

В итоге страховая компания одновременно получила возможность снизить затраты на заключение договора КАСКО, повысить качество работы агентов и защититься от мошенничества.

А теперь к реализации


Как водится, многое было достаточно стандартным. Но были и интересные технические задачки, реализацией которых мы и хотим поделиться с вами.

1. Планирование осмотра


После регистрации в приложении (а в дальнейшем – после логина) пользователь (страховой агент) видит список заявок на осмотр. По заявке он может запланировать осмотр на будущее или сразу его начать.

Чтобы запланировать осмотр, пользователь указывает дату и время осмотра, и дополнительно может указать адрес. Для осмотра автоматически создается событие в календаре смартфона, и устанавливается напоминание за час до осмотра. Если пользователь меняет запланированное время – событие в календаре также обновляется.



Чтобы реализовать такую синхронизацию, мы использовали стандартную библиотеку для работы с календарем EventKit:
Синхронизация со стандартным календарем
- (void)syncEventForSurvey:(Survey *)survey
                completion:(void (^)(NSError *))completion
{
    if (!survey.dateScheduled)
        return;
    [self.eventStore requestAccessToEntityType:EKEntityTypeEvent
                                    completion:^(BOOL granted, NSError *error)
    {
        dispatch_async(dispatch_get_main_queue(), ^{
            if (!granted || error) {
                if (completion)
                    completion(error);
                return;
            }
            
            NSTimeInterval oneHour = 60*60;
            EKEvent *event = nil;
            if (survey.eventIdentifier) {
                event = [self.eventStore eventWithIdentifier:survey.eventIdentifier];
            }
            if (!event) {
                event = [EKEvent eventWithEventStore:self.eventStore];
                event.calendar = [self surveysCalendar];
                
                event.title = survey.title;
                
                NSTimeInterval alarmOffset = -oneHour;
                EKAlarm *alarm = [EKAlarm alarmWithRelativeOffset:alarmOffset];
                event.alarms = @[alarm];
            }
            
            event.startDate = survey.dateScheduled;
            NSTimeInterval surveyDuration = oneHour;
            event.endDate = [event.startDate dateByAddingTimeInterval:surveyDuration];
            
            NSError *saveError = nil;
            [self.eventStore saveEvent:event
                                  span:EKSpanThisEvent
                                commit:YES
                                 error:&saveError];
            if (!saveError) {
                survey.eventIdentifier = event.eventIdentifier;
            }
            if (completion)
                completion(saveError);
        });
    }];
}



eventStore — это просто [[EKEventStore alloc] init];
surveysCalendar — немного сложнее:

surveysCalendar
- (EKCalendar *)surveysCalendar
{
    NSString *calendarTitle = @"Осмотры ТС";
    
    EKCalendar *calendar = nil;
    if (self.surveysCalendarIdentifier) {
        calendar = [self.eventStore calendarWithIdentifier:self.surveysCalendarIdentifier];
    }
    if (!calendar) {
        NSArray *allCalendars = [self.eventStore calendarsForEntityType:EKEntityTypeEvent];
        calendar = [allCalendars etr_filter:^BOOL(EKCalendar *obj) {
            return [obj.title isEqualToString:calendarTitle];
        }].firstObject;
    }
    if (!calendar) {
        calendar = [EKCalendar calendarForEntityType:EKEntityTypeEvent
                                          eventStore:self.eventStore];
        calendar.source = self.eventStore.defaultCalendarForNewEvents.source;
        calendar.title = calendarTitle;
        [self.eventStore saveCalendar:calendar
                               commit:YES
                                error:nil];
        self.surveysCalendarIdentifier = calendar.calendarIdentifier;
    }
    return calendar;
}


Когда у осмотра выставляется dateScheduled, вызывается синхронизация с календарем. В нашем приложении это происходит при сохранении запланированного осмотра.

2. Проведение осмотра


Для проведения осмотра пользователь выбирает объект из списка запланированных или недавно загруженных заявок на осмотр и нажимает на кнопку «Осмотреть». Сам осмотр состоит из двух частей – осмотр транспортного средства и добавление документов.



Блок «Документы» – это просто список документов, которые при необходимости можно сфотографировать и отправить на сервер. Эта часть не является обязательной, и ограничений на нее тоже нет.

В осмотре же автомобиля всё гораздо интереснее. Он состоит из нескольких блоков:
  • обязательный к заполнению блок фотографий транспортного средства,
  • необязательные блоки для указания дополнительного оборудования и повреждений.


Для предотвращения «подделки» фото в приложении реализовано несколько ограничений:
  • ограничение времени осмотра – 30 минут,
  • фиксирование геолокации каждого фото,
  • нет возможности добавлять фотографии из библиотеки смартфона.


2.1. Таймер, или успеть за 30 минут


Как только пользователь нажимает кнопку «Начать осмотр», запускается отсчет времени. И на всех экранах приложения в режиме проведения осмотра отображается таймер. В случае, если осмотр транспортного средства (ТС) не был проведен за 30 минут, все фотографии, сделанные для этого осмотра, удаляются, и осмотр нужно начинать заново. Такое ограничение позволяет предотвратить обманное фотографирование разных автомобилей для одного осмотра.

2.2 Ограничение по геолокации


Также для предотвращения фальсификаций вначале мы хотели сделать прерывание осмотра, если пользователь удалился от точки начала осмотра более чем на 500 метров. Мы даже это реализовали вот так:

При старте осмотра приложение сохраняет текущую геопозицию как стартовую и подписывается на уведомления об изменении геолокации на следующие 30 минут. При получении новых координат, сравнивается, не превысило ли расстояние до стартовой точки 500 метров. В случае удаления от точки начала осмотра более чем на 500 метров, осмотр заканчивается и его нужно начинать заново.

Так было задумано. Но от этой идеи пришлось отказаться, потому что точность получения координат сильно зависит от источника сигнала. В некоторых ситуациях, когда мобильное устройство определяет геопозицию по Wi-Fi точкам, при переподключении между ними приложение может получить информацию об изменении расстояния более чем на 500 метров, хотя пользователь не прошел и трех. Из-за таких скачков осмотр прерывался. Место проведения осмотра, как и источники информации о геопозиции, мы ограничить не можем, поэтому от этого ограничения пришлось отказаться.

Тем не менее, безопасность сохраняется. Ко всем фотографиям, сделанным в процессе осмотра, добавляются геоданные, которые передаются на сервер. А без определения геолокации возможность проведения осмотра заблокирована.

2.3. Корректная фотофиксация


Фотографии, которые используются в приложении, создаются и хранятся только в приложении. Нет возможности сохранить фотографии в библиотеку или передать их куда-либо, кроме сервера страховой компании. Это значит, что агент не сможет подделать фото, а фото ТС – не попадут в чужие руки.

В процессе проведения осмотра агент производит фотофиксацию всех элементов автомобиля, следуя процедуре, по которой его ведет приложение. Каждый элемент осмотра, для которого нужно сделать фото, имеет название: «Лобовое стекло», «ТС с правой стороны», «Диагональ ТС с правого угла заднего бампера». Для того чтобы было проще выбрать правильный ракурс съемки, в приложении реализованы маски и подсказки. На маске, которая отображается в режиме фотографирования, отмечены рамкой положения колес автомобиля. Из режима фотографирования также доступна подсказка, которая содержит пример готовой фотографии в соответствующем ракурсе.



2.4. Фотографии повреждений


И, наконец, в приложении агент указывает и отдельно фотографирует все выявленные повреждения авто. Деталь, на которой есть повреждение, нужно отметить на схеме. После того как деталь выбрана, пользователь может указать конкретную часть детали и тип повреждения и сделать две фотографии: детальное фото повреждения и фото дефекта на общем плане детали авто.



В приложении на макете авто агент выбирает деталь ТС, на которой есть повреждения, она выделяется цветом, и далее приложение переходит к этапу фотографирования повреждения.

Чтобы реализовать выделение на схеме криволинейных элементов (а детали авто все такие), мы использовали кривые Безье, полученные из формата SVG (Scalable Vector Graphics).

Кривые Безье позволяют задать уравнение сложных кривых, а в нашем случае – контуров деталей автомобиля, а SVG – формат двумерных векторных изображений, основанный на XML. Любопытно, что кривые Безье были разработаны именно для проектирования кузовных деталей автомобилей.
Подробнее о кривых и формате SVG можно прочитать тут:
ru.wikipedia.org/wiki/Кривая_Безье
en.wikipedia.org/wiki/Scalable_Vector_Graphics

А наш рецепт выбора детали на схеме выглядит так:
Сначала дизайнеры нарисовали схему машины в трех проекциях в SVG. Изображение из SVG формата мы сконвертировали в набор отдельных файлов деталей в виде кривых Безье (для этого можно использовать PocketSVG — github.com/arielelkin/PocketSVG ).

Все файлы .bezier добавили в проект и использовали на экране со схемой: используется фоновая картинка с автомобилем, а сверху добавляются детали из UIBezierPath:
Работа с кривыми Безье
- (void)awakeFromNib {
   [super awakeFromNib];
    NSArray *carParts = [SurveyStructure sharedStructure].carParts;
    NSMutableArray *newLayers = [NSMutableArray array];
    for (SurveyStructureCarPart* part in carParts) {
        @autoreleasepool {
            NSString *filepath = [[NSBundle mainBundle] pathForResource:part.identifier ofType:@"bezier"];
            UIBezierPath *bezier = [NSKeyedUnarchiver unarchiveObjectWithFile:filepath];
            CarPartLayer* layer = [[CarPartLayer alloc] initWithCarPart:part];
            layer.anchorPoint = CGPointZero;
            layer.path = bezier.CGPath;
            layer.actions = @{@"fillColor": [NSNull null], @"opacity": [NSNull null]};
            [newLayers addObject:layer];
            [self.layersContainer.layer insertSublayer:layer atIndex:0];
        }
    }
    self.carPartLayers = newLayers;
}  

По нажатию отслеживаем и обозначаем деталь:
- (void)hightlightPartAtPoint:(CGPoint)point {
    for (CarPartLayer *layer in self.carPartLayers) {
        if (CGPathContainsPoint(layer.path, NULL, point, false)) {
            if (self.highlightedLayer != layer) {
                self.highlightedLayer = layer;
            }
            return;
        }
    }

    if (self.highlightedLayer != nil) {
        self.highlightedLayer = nil;
    }
}



Для удобства выбора детали на схеме используется «увеличительное стекло» (например, cocoapods.org/pods/iOS-MagnifyingGlass ).

3. Передача данных


После того как все необходимые фотографии сделаны, приложение предлагает пользователю завершить осмотр и отправить данные на сервер. Пользователь жмет магическую кнопку, и осмотр переводится в очередь на отправку.

3.1. Отправка в бэкграунде


Отправка осмотров производится в фоне. И когда приложение запущено, и когда приложение в бэкграунде. В синглтоне UploadManager используется FetchResultsController, выбирающий из списка осмотров объекты в статусе «На отправку». При переводе какого-то осмотра на отправку, фетчер сообщает менеджеру, что необходимо загрузить. Менеджер загружает данные по осмотру на сервер, и меняет статус объекта. После этого выполняется проверка о наличии других осмотров на отправку. Если других договоров в этот момент нет, менеджер загрузки будет ждать следующей нотификации от фетчера.



Чтобы приложение отправляло данные по осмотрам в бэкграунде, мы добавили backgroud task:
Синхронизация в бэкграунде
- (void)applicationDidEnterBackground:(UIApplication *)application
{
    if ([[UploadSurveysManager sharedManager] isNeedUpload]) {
        self.bgTask = [application beginBackgroundTaskWithExpirationHandler:^{
            [application endBackgroundTask:self.bgTask];
            self.bgTask = UIBackgroundTaskInvalid;
        }];

        [[UploadSurveysManager sharedManager] uploadIfNeeded];
    }
}


В Info.plist проекта необходимо указать Required background modes: “App downloads content from the network”
С более подробным описанием запуска процессов в бэкграунде можно ознакомиться тут:

developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/BackgroundExecution/BackgroundExecution.html#//apple_ref/doc/uid/TP40007072-CH5-SW6

Важно помнить, что задачи в бэкгрунде имеют ограничение по времени выполнения. Для того чтобы эффективно использовать загрузку в бэкграунде, ее необходимо выполнять небольшими порциями и сохранять текущее состояние, чтобы восстановить отправку при следующем запуске background task. Для удовлетворения этих ограничений мы обрабатываем отправку осмотров по очереди. Сначала по отдельности отправляются фотографии, относящиеся к осмотру, а потом – специальный запрос со списком идентификаторов фотографий, связывающих их с осмотром по соответствующему заданию. Только после этого осмотр считается отправленным.

3.2. Оптимизация мобильного трафика


Для экономии мобильного трафика в приложении реализована проверка типа интернет-соединения. В настройках приложения можно включить опцию «Не передавать данные по сотовой связи в автоматическом режиме». Когда эта настройка включена, информация по проведенным осмотрам будет отправляться на сервер только при подключении смартфона к сети Wi-Fi. Кроме того, можно включить отправку по сотовой связи для отдельного договора.

Для случаев, когда осмотр необходимо отправить срочно, а Wi-Fi недоступен, можно включить настройку для одного договора: если доступен Wi-Fi, отправляется любой осмотр, а если мобильная связь, то только договоры со включенной настройкой отправки по сотовой связи.

Заключение


Вот так благодаря нам, автовладельцы получили возможность оформить КАСКО максимально легко.

Для страховой компании мы сделали удобный инструмент, который решает комплекс задач:
  1. повышение эффективности работы,
  2. стандартизация процесса осмотра,
  3. защита от мошенничества.


А мы решили несколько интересных задач и надеемся, что вам тоже было интересно узнать о том, как:
  • реализовать выбор элемента на схеме, построенной на основе векторного изображения,
  • настроить синхронизацию с системным календарем,
  • и реализовать загрузку данных в бэкграунде.


До новых встреч!
Tags:
Hubs:
+9
Comments 5
Comments Comments 5

Articles

Information

Website
www.trueengineering.ru
Registered
Founded
Employees
101–200 employees
Location
Россия