Появилась задача детализировать доставки по населенным пунктам.
Сам адрес чаще всего представлен строкой в произвольном формате. И выдернуть из него город или село проблематично. Иногда его вообще нет, но зато есть координаты места(широта и долгота). Как из 1с получить точный адрес и выдернуть из него населенный пункт? Будем использовать API Google Maps.Для работы с ним нам нужен API key.
Получаем API Key для Google Maps
Для этого нужен аккаунт в Google, если его нет регистрируем.
Переходим на Google Cloud Platform и регистрируем новый проект
Включите нужные API. Для задачи достаточно Geolocation API – Геолокация. Я также добавил построение маршрутов Directions API и Maps Javascript API для размещения Google карт на сайте.
Создаем ключ API . Выбираем API и сервисы -Учетные данные -создать учетные данные ключ API
Ключ создан и чтобы запросы к Api работали нужно к запросу добавить параметр &key=Ваш ключ
Для того чтобы получить информацию о месте на карте по координатам отправляем запрос
https://maps.googleapis.com/maps/api/geocode/json?latlng=широта,долгота&language=ru&key=ВашКлюч
для получения данных в формате json и
https://maps.googleapis.com/maps/api/geocode/xml?latlng=широта,долгота&language=ru&key=ВашКлюч
для получения данных в формате xml.
Параметры:
latlng – координаты(широта, долгота);
language – язык на котором будет ответ;
key- ключ Api google maps
Ответ сервера будет приблизительно такой (json) :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 | { "plus_code" : { "compound_code" : "FHG5+2X Маслов-Орешин, Саратовская область, Россия", "global_code" : "9H3FFHG5+2X" }, "results" : [ { "address_components" : [ { "long_name" : "413604", "short_name" : "413604", "types" : [ "postal_code" ] }, { "long_name" : "Озинский район", "short_name" : "Озинский р-н", "types" : [ "administrative_area_level_2", "political" ] }, { "long_name" : "Саратовская область", "short_name" : "Саратовская обл.", "types" : [ "administrative_area_level_1", "political" ] }, { "long_name" : "Россия", "short_name" : "RU", "types" : [ "country", "political" ] } ], "formatted_address" : "Саратовская обл., Россия, 413604", "geometry" : { "bounds" : { "northeast" : { "lat" : 51.55775999999999, "lng" : 49.6273399 }, "southwest" : { "lat" : 51.2403609, "lng" : 49.29563599999999 } }, "location" : { "lat" : 51.4244713, "lng" : 49.4481422 }, "location_type" : "APPROXIMATE", "viewport" : { "northeast" : { "lat" : 51.55775999999999, "lng" : 49.6273399 }, "southwest" : { "lat" : 51.2403609, "lng" : 49.29563599999999 } } }, "place_id" : "ChIJ2SYTKWnCbUER6ztjTJ74wZ8", "types" : [ "postal_code" ] }, { "address_components" : [ { "long_name" : "Озинский район", "short_name" : "Озинский р-н", "types" : [ "administrative_area_level_2", "political" ] }, { "long_name" : "Саратовская область", "short_name" : "Саратовская обл.", "types" : [ "administrative_area_level_1", "political" ] }, { "long_name" : "Россия", "short_name" : "RU", "types" : [ "country", "political" ] } ], "formatted_address" : "Озинский р-н, Саратовская обл., Россия", "geometry" : { "bounds" : { "northeast" : { "lat" : 51.70881199999999, "lng" : 50.5569231 }, "southwest" : { "lat" : 50.98724800000001, "lng" : 49.2263019 } }, "location" : { "lat" : 51.19856979999999, "lng" : 49.7267069 }, "location_type" : "APPROXIMATE", "viewport" : { "northeast" : { "lat" : 51.70881199999999, "lng" : 50.5569231 }, "southwest" : { "lat" : 50.98724800000001, "lng" : 49.2263019 } } }, "place_id" : "ChIJkd7Wdq38bUERYE9ivk_co1E", "types" : [ "administrative_area_level_2", "political" ] }, { "address_components" : [ { "long_name" : "Саратовская область", "short_name" : "Саратовская обл.", "types" : [ "administrative_area_level_1", "political" ] }, { "long_name" : "Россия", "short_name" : "RU", "types" : [ "country", "political" ] } ], "formatted_address" : "Саратовская обл., Россия", "geometry" : { "bounds" : { "northeast" : { "lat" : 52.8175969, "lng" : 50.8330918 }, "southwest" : { "lat" : 49.800981, "lng" : 42.5132981 } }, "location" : { "lat" : 51.83692629999999, "lng" : 46.7539397 }, "location_type" : "APPROXIMATE", "viewport" : { "northeast" : { "lat" : 52.8175969, "lng" : 50.8330918 }, "southwest" : { "lat" : 49.800981, "lng" : 42.5132981 } } }, "place_id" : "ChIJpYvAqJVWE0ERLadaTEr-qus", "types" : [ "administrative_area_level_1", "political" ] }, { "address_components" : [ { "long_name" : "Россия", "short_name" : "RU", "types" : [ "country", "political" ] } ], "formatted_address" : "Россия", "geometry" : { "bounds" : { "northeast" : { "lat" : 82.1673907, "lng" : -168.97788 }, "southwest" : { "lat" : 41.185353, "lng" : 19.6160999 } }, "location" : { "lat" : 61.52401, "lng" : 105.318756 }, "location_type" : "APPROXIMATE", "viewport" : { "northeast" : { "lat" : 82.1673907, "lng" : -168.97788 }, "southwest" : { "lat" : 41.185353, "lng" : 19.6160999 } } }, "place_id" : "ChIJ-yRniZpWPEURE_YRZvj9CRQ", "types" : [ "country", "political" ] } ], "status" : "OK" } |
Для получения координат по адресу используется запрос
https://maps.googleapis.com/maps/api/geocode/json?address=Адрес&language=ru&key=ВашКлюч
Теперь реализуем это в 1с. Будем использовать HTTPСоединение, учитывая что запрос идет по протоколу https
1 | HTTPСоединение = Новый HTTPСоединение(СтруктураURI.Хост, СтруктураURI.Порт,,,,,Новый ЗащищенноеСоединениеOpenSSL()); |
и HttpЗапрос , передавая в него обращение к API Google maps
1 2 3 4 5 6 7 | HTTPЗапрос = Новый HTTPЗапрос(СтруктураURI.ПутьНаСервере); Попытка Результат = HTTPСоединение.Получить(HTTPЗапрос); Исключение // исключение здесь говорит о том, что запрос не дошел до HTTP-Сервера Сообщить("Произошла сетевая ошибка!"); КонецПопытки; |
Далее получаем ответ от сервера и непосредственно результат(ПолучитьТелоКакСтроку()) в виде json.
1 2 | Ответ=ВыполнитьHTTPЗапрос("https://maps.googleapis.com/maps/api/geocode/json?latlng="+стрКоординаты+"&language=ru&key=ключAPI"); Результат = Ответ.ПолучитьТелоКакСтроку(); |
Преобразуем json в структуру и вытаскиваем нужные данные
Полный код для обычного приложения 1с:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 | Функция JSON_ПреобразоватьВСтруктуру(_Строка, _Представление="") Экспорт ИмяВременногоФайла = ПолучитьИмяВременногоФайла(); Если ТипЗнч(_Строка) = Тип("Строка") Тогда Запись = Новый ЗаписьТекста(ИмяВременногоФайла); Запись.Записать(_Строка); Запись.Закрыть(); Иначе _Строка.Записать(ИмяВременногоФайла); КонецЕсли; ЧтениеJSON = Новый ЧтениеJSON(); ЧтениеJSON.ОткрытьФайл(ИмяВременногоФайла); СериалОБъектJSON = Неопределено; ТекущийСериалОбъектJSON = Неопределено; СимволКавычки=""""; ИмяСвойства=""; спОткрытыеОбъекты = Новый СписокЗначений; Попытка Пока ЧтениеJSON.Прочитать() Цикл Если ЧтениеJSON.ТипТекущегоЗначения = ТипЗначенияJSON.НачалоОбъекта или ЧтениеJSON.ТипТекущегоЗначения = ТипЗначенияJSON.НачалоМассива Тогда ТипОбъекта = ?(ЧтениеJSON.ТипТекущегоЗначения = ТипЗначенияJSON.НачалоОбъекта, "Структура", "Массив"); Если СериалОБъектJSON = Неопределено Тогда СериалОБъектJSON = Вычислить("Новый "+ТипОбъекта); ТекущийСериалОбъектJSON = СериалОБъектJSON; Иначе Если ТипЗнч(ТекущийСериалОбъектJSON) = Тип("Массив") Тогда Выполнить("ТекущийСериалОбъектJSON.Добавить(Новый "+ТипОбъекта+")"); //добавляем новую структуру / массив ТекущийСериалОбъектJSON = Вычислить("ТекущийСериалОбъектJSON.Получить(ТекущийСериалОбъектJSON.Количество()-1)"); Иначе Выполнить("ТекущийСериалОбъектJSON.Вставить("+СимволКавычки+ИмяСвойства+СимволКавычки+", Новый "+ТипОбъекта+")"); //добавляем новую структуру / массив ТекущийСериалОбъектJSON = Вычислить("ТекущийСериалОбъектJSON."+ИмяСвойства); КонецЕсли; КонецЕсли; спОткрытыеОбъекты.Добавить(Новый Структура("ТекущийСериалОбъектJSON", ТекущийСериалОбъектJSON)); ИначеЕсли ЧтениеJSON.ТипТекущегоЗначения = ТипЗначенияJSON.КонецОбъекта или ЧтениеJSON.ТипТекущегоЗначения = ТипЗначенияJSON.КонецМассива Тогда спОткрытыеОбъекты.Удалить(спОткрытыеОбъекты.Получить(спОткрытыеОбъекты.Количество()-1)); Попытка ТекущийСериалОбъектJSON = спОткрытыеОбъекты.Получить(спОткрытыеОбъекты.Количество()-1).Значение.ТекущийСериалОбъектJSON; Исключение //дошли до конца КонецПопытки; ИначеЕсли ЧтениеJSON.ТипТекущегоЗначения = ТипЗначенияJSON.ИмяСвойства Тогда ИмяСвойства = ЧтениеJSON.ТекущееЗначение; ИначеЕсли ЧтениеJSON.ТипТекущегоЗначения = ТипЗначенияJSON.Null или ЧтениеJSON.ТипТекущегоЗначения = ТипЗначенияJSON.Булево ИЛИ ЧтениеJSON.ТипТекущегоЗначения = ТипЗначенияJSON.Строка или ЧтениеJSON.ТипТекущегоЗначения = ТипЗначенияJSON.Число Тогда ТекущееЗначение = ЧтениеJSON.ТекущееЗначение; Если Найти(нрег(ИмяСвойства), "date")>0 Тогда Если ЧтениеJSON.ТекущееЗначение="" Тогда ТекущееЗначение = Дата(1,1,1); Иначе Попытка ТекущееЗначение = Дата(Лев(ТекущееЗначение,4), Сред(ТекущееЗначение,6,2), Сред(ТекущееЗначение,9,2), Сред(ТекущееЗначение,12,2),Сред(ТекущееЗначение,15,2),0); Исключение //прописать преобразования в дату в ненайденном формате КонецПопытки; КонецЕсли; КонецЕсли; Если ТипЗнч(ТекущийСериалОбъектJSON) = Тип("Массив") Тогда ТекущийСериалОбъектJSON.добавить(ТекущееЗначение); ИначеЕсли ИмяСвойства<>"" Тогда ТекущийСериалОбъектJSON.Вставить(ИмяСвойства, ТекущееЗначение); КонецЕсли; Иначе ИмяТекущегоЗначения = ""; КонецЕсли; КонецЦикла; Исключение Сообщить(""+ОписаниеОшибки()+Символы.пс+"Строка json не преобразована: "+_Представление); Возврат Новый Массив(); КонецПопытки; Возврат СериалОБъектJSON КонецФункции Функция СтруктураURI(Знач СтрокаURI) Экспорт СтрокаURI = СокрЛП(СтрокаURI); // схема Схема = ""; Позиция = Найти(СтрокаURI, "://"); Если Позиция > 0 Тогда Схема = НРег(Лев(СтрокаURI, Позиция - 1)); СтрокаURI = Сред(СтрокаURI, Позиция + 3); КонецЕсли; // строка соединения и путь на сервере СтрокаСоединения = СтрокаURI; ПутьНаСервере = ""; Позиция = Найти(СтрокаСоединения, "/"); Если Позиция > 0 Тогда ПутьНаСервере = Сред(СтрокаСоединения, Позиция + 1); СтрокаСоединения = Лев(СтрокаСоединения, Позиция - 1); КонецЕсли; // информация пользователя и имя сервера СтрокаАвторизации = ""; ИмяСервера = СтрокаСоединения; Позиция = Найти(СтрокаСоединения, "@"); Если Позиция > 0 Тогда СтрокаАвторизации = Лев(СтрокаСоединения, Позиция - 1); ИмяСервера = Сред(СтрокаСоединения, Позиция + 1); КонецЕсли; // логин и пароль Логин = СтрокаАвторизации; Пароль = ""; Позиция = Найти(СтрокаАвторизации, ":"); Если Позиция > 0 Тогда Логин = Лев(СтрокаАвторизации, Позиция - 1); Пароль = Сред(СтрокаАвторизации, Позиция + 1); КонецЕсли; // хост и порт Хост = ИмяСервера; Порт = ""; Позиция = Найти(ИмяСервера, ":"); Если Позиция > 0 Тогда Хост = Лев(ИмяСервера, Позиция - 1); Порт = Сред(ИмяСервера, Позиция + 1); КонецЕсли; Результат = Новый Структура; Результат.Вставить("Схема", Схема); Результат.Вставить("Логин", Логин); Результат.Вставить("Пароль", Пароль); Результат.Вставить("ИмяСервера", ИмяСервера); Результат.Вставить("Хост", Хост); Результат.Вставить("Порт", ?(Порт <> "", Число(Порт), Неопределено)); Результат.Вставить("ПутьНаСервере", ПутьНаСервере); Возврат Результат; КонецФункции Функция ВыполнитьHTTPЗапрос(ПолныйАдресРесурса) Экспорт СтруктураURI = СтруктураURI(ПолныйАдресРесурса); HTTPСоединение = Новый HTTPСоединение(СтруктураURI.Хост, СтруктураURI.Порт,,,,,Новый ЗащищенноеСоединениеOpenSSL()); HTTPЗапрос = Новый HTTPЗапрос(СтруктураURI.ПутьНаСервере); Попытка Результат = HTTPСоединение.Получить(HTTPЗапрос); Исключение // исключение здесь говорит о том, что запрос не дошел до HTTP-Сервера Сообщить("Произошла сетевая ошибка!"); ВызватьИсключение; КонецПопытки; Если Результат.КодСостояния >= 400 и Результат.КодСостояния < 500 Тогда Сообщить("Код статуса больше 4XX, ошибка запроса. Код статуса: " + Результат.КодСостояния); КонецЕсли; Если Результат.КодСостояния >= 500 и Результат.КодСостояния < 600 Тогда Сообщить("Код статуса больше 5XX, ошибка сервера. Код статуса: " + Результат.КодСостояния); КонецЕсли; Если Результат.КодСостояния >= 300 и Результат.КодСостояния < 400 Тогда Сообщить("Код статуса больше 3XX, Перенаправление. Код статуса: " + Результат.КодСостояния); Если Результат.КодСостояния = 302 Тогда Сообщить("Код статуса 302, Постоянное перенаправление."); АдресРесурса = Результат.Заголовки.Получить("Location"); Если АдресРесурса <> Неопределено Тогда Сообщить("Выполняю запрос по новому адресу " + АдресРесурса); ВыполнитьHTTPЗапрос(АдресРесурса); Иначе Сообщить("Сервер не сообщил адрес ресурса!"); КонецЕсли; КонецЕсли; КонецЕсли; // Статусы 1XX и 2XX считаем хорошими Если Результат.КодСостояния < 300 Тогда // Сообщить("Ок"); // Сообщить("Код статуса: " + Результат.КодСостояния); КонецЕсли; возврат(Результат); КонецФункции Процедура КнопкаВыполнитьНажатие(Кнопка) Запрос = Новый Запрос("ВЫБРАТЬ | РасчетПродукция.Ссылка.стрНомер, | РасчетПродукция.Номенклатура, | РасчетПродукция.Цена, | РасчетПродукция.Количество, | РасчетПродукция.Сумма, | РасчетПродукция.Ссылка.АдресДоставки, | РасчетПродукция.Ссылка.ЗначенияПолейАдреса, | РасчетПродукция.Ссылка.Менеджер, | РасчетПродукция.Ссылка.Координаты |ИЗ | Документ.Расчет.Продукция КАК РасчетПродукция |ГДЕ | РасчетПродукция.Ссылка.Дата МЕЖДУ &НачалоПериода И &КонецПериода | И РасчетПродукция.Номенклатура В(&Номенклатура) | И РасчетПродукция.Ссылка.Проведен = ИСТИНА"); Запрос.УстановитьПараметр("Номенклатура", Доставки); Запрос.УстановитьПараметр("НачалоПериода", НачалоПериода); Запрос.УстановитьПараметр("КонецПериода", КонецПериода); Рез=Запрос.Выполнить().Выгрузить(); рез.Колонки.Добавить("Город"); Если рез.Количество()>0 тогда Для каждого стр из рез Цикл Попытка стрКоординаты = СтрЗаменить(СтрЗаменить(СтрЗаменить(стр.координаты, "(", ""), ")", ""), " ", ""); Ответ=ВыполнитьHTTPЗапрос("https://maps.googleapis.com/maps/api/geocode/json?latlng="+стрКоординаты+"&language=ru&key=ключAPI"); Результат = Ответ.ПолучитьТелоКакСтроку(); тДанные=JSON_ПреобразоватьВСтруктуру(результат); т1=лев(тДанные.plus_code.compound_code,СтрНайти(тДанные.plus_code.compound_code,",")-1); стр.Город=прав(т1,СтрДлина(т1)-СтрНайти(т1," ")); Исключение //в случае ошибки пишем весь адрес без парсинга стр.Город=стр.АдресДоставки; КонецПопытки; КонецЦикла; КонецЕсли; КонецПроцедуры |