Давайте подружим 1С и Android. Часть 2 — авторизуемся в 1С




Принцип обмена данными из 1С с сайтом (на MySQL) и выдачи (публикации) этих данных по запросу.
PHP-Скрипт автоматической загрузки данных из файла данных в формате CSV в базу данных сайта работающего на WordPress.

В продолжение моей темы: 1С:Альфа-Авто Автосалон Автосервис: обмен с сайтом.
С помощью данного скрипта можно загружать в автоматическом режиме, по расписанию, данные сервисных книжек (ремонтов авто) из 1С:Альфа-Авто Автосалон Автосервис.
Также можно загружать данные в ручном режиме: для этого делается скрытая страница, где размещается специальная кнопка.
Комментарии размещенные внутри скрипта разъяснят логику и порядок действия.
Комментарии с "/////    echo" использовались для отладки.
Дополнительно создана таблица для журналирования результатов загрузки данных.
Скрипт включает в себя защиту от SQL инъекций (думаю безопасность соблюдена в полной мере).
В кратце:
1. Пишется скрипт, который запускает этот.
2. Создается регламентное задание в WordPress, по которому запускается скрипт из п.1. 
3. Этот скрипт осуществляет проверку на существование файла обмена в папке.
4. Если данные не новые, загрузка не производится.
5. Если данные новые, очищается таблица сервисных книжек.
6. Загружаются новые данные.

Собственно сам скрипт:

<?php // Полная загрузка сервисных книжек, создан 2024-01-05 12:44:55

global $wpdb2;
global $failure;
global $file_hist;

/////  echo '<H2><b>Старт загрузки</b></H2><br>';

$failure=FALSE;
//подключаемся к базе
$wpdb2 = include_once 'connection.php'; ; // подключаемся к MySQL
// если не удалось подключиться, и нужно оборвать PHP с сообщением об этой ошибке
if (!empty($wpdb2->error))
{
/////   echo '<H2><b>Ошибка подключения к БД, завершение.</b></H2><br>';
$failure=TRUE;
wp_die( $wpdb2->error );
}

$m_size_file=0;
$m_mtime_file=0;
$m_comment='';
/////проверка существования файлов выгрузки из 1С
////файл выгрузки сервисных книжек
$file_hist = ABSPATH.'/_1c_alfa_exchange/AA_hist.csv';
if (!file_exists($file_hist))
{
/////   echo '<H2><b>Файл обмена с сервисными книжками не существует.</b></H2><br>';
$m_comment='Файл обмена с сервисными книжками не существует';
$failure=TRUE;
}

/////инициируем таблицу лога
/////если не существует файла то возврат и ничего не делаем
if ($failure){
///включает защиту от SQL инъекций и данные можно передавать как есть, например: $_GET['foo']
/////   echo '<H2><b>Попытка вставить запись в лог таблицу</b></H2><br>';
$insert_fail_zapros=$wpdb2->insert('vin_logs', array('time_stamp'=>time(),'last_mtime_upload'=>$m_mtime_file,'last_size_upload'=>$m_size_file,'comment'=>$m_comment));
wp_die();
/////    echo '<H2><b>Возврат в начало.</b></H2><br>';
return $failure;
}
/////проверка лога загрузки, что бы не загружать тоже самое
$masiv_data_file=stat($file_hist);   ////передаем в массив свойство файла
$m_size_file=$masiv_data_file[7];    ////получаем размер файла
$m_mtime_file=$masiv_data_file[9];   ////получаем дату модификации файла
////создаем запрос на получение последней удачной загрузки
////выбираем по штампу времени создания (редактирования) файла загрузки AA_hist.csv, $m_mtime_file

/////   echo '<H2><b>Размер файла: '.$m_size_file.'</b></H2><br>';
/////   echo '<H2><b>Штамп времени файла: '.$m_mtime_file.'</b></H2><br>';
/////   echo '<H2><b>Формирование запроса на выборку из лога</b></H2><br>';
////препарируем запрос
$text_zaprosa=$wpdb2->prepare("SELECT * FROM `vin_logs` WHERE `last_mtime_upload` = %s", $m_mtime_file);
$results=$wpdb2->get_results($text_zaprosa);

if ($results)
{   foreach ( $results as $r)
{
////если штамп времени и размер файла совпадают, возврат
if (($r->last_mtime_upload==$m_mtime_file) && ($r->last_size_upload==$m_size_file))
{////echo '<H2><b>Возврат в начало, т.к. найдена запись в логе.</b></H2><br>';
$insert_fail_zapros=$wpdb2->insert('vin_logs', array('time_stamp'=>time(),'last_mtime_upload'=>$m_mtime_file,'last_size_upload'=>$m_size_file,'comment'=>'Загрузка отменена, новых данных нет, т.к. найдена запись в логе.'));
wp_die();
return $failure;
}
}
}
////если данные новые, пишем в лог запись о начале загрузки
/////echo '<H2><b>Попытка вставить запись о начале загрузки в лог таблицу</b></H2><br>';
$insert_fail_zapros=$wpdb2->insert('vin_logs', array('time_stamp'=>time(),'last_mtime_upload'=>0, 'last_size_upload'=>$m_size_file, 'comment'=>'Начало загрузки'));

////очищаем таблицу
$clear_tbl_zap=$wpdb2->prepare("TRUNCATE TABLE %s", 'vin_history');
$clear_tbl_zap_repl=str_replace("'","`",$clear_tbl_zap);
$results=$wpdb2->query($clear_tbl_zap_repl);
/////   echo '<H2><b>Очистка таблицы сервисных книжек</b></H2><br>';
if (empty($results))
{
/////   echo '<H2><b>Ошибка очистки таблицы книжек, завершение.</b></H2><br>';
//// если очистка не удалась, возврат
$failure=TRUE;
wp_die();
return $failure;
}

////загружаем данные
$table='vin_history';         // Имя таблицы для импорта
//$file_hist Имя CSV файла, откуда берется информация     // (путь от корня web-сервера)
$delim=';';          // Разделитель полей в CSV файле
$enclosed='"';      // Кавычки для содержимого полей
$escaped='\

48 Comments

  1. infosoft-v

    Отличная статья. Спасибо.

    Reply
  2. Ann.prog1C

    Полезно. Спасибо.

    Reply
  3. flyer

    продолжайте слежу за темой

    Reply
  4. gudun_ku

    Отличная статья. Код под Андроид хорош, оценил, что легко переложить на net cf, чем я и займусь как-нибудь. Жду продолжения, про сканирование.

    Reply
  5. Ibrogim

    Вот теперь ставлю плюс.

    Вы кстати вдохновили меня тоже статью написать)

    Reply
  6. WKBAPKA

    о, отличная статья. спасибо

    Reply
  7. Yashazz

    Вообще не очень понимаю, нафига это всё… Мобильное приложение — кривоватое побочное дитя попытки 1С угнаться за модой, которое однажды канет в прошлое, как веб-расширения и тому подобная мутота… Охота вам силы тратить.

    Reply
  8. solarisman

    (7) Yashazz, Не понял, при чем тут мобильное приложение 1С? Приложение нативное, написанное на Java. По поводу

    канет в прошлое

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

    Reply
  9. dj_serega

    Почему не на http?

    Reply
  10. solarisman

    (9) dj_serega, Вообще не понял, о чем речь здесь? HTTP — протокол передачи данных, SOAP — протокол доступа к объектам, который использует HTTP.

    Reply
  11. solarisman

    Коллеги, давайте по существу, хочется конструктивной критики.

    Reply
  12. Nenaviju1C

    Нечто подобное тоже себе организовал:

    База (если так можно сказать) 1с — самописная конфиг-я для формирования ежемесячных отчетов по счетчикам гор/хол воды для ЖКХ с рассылкой определенную дату по регламенту от своего имени (*@mail.ru) на почту ЖКХ.

    Мобильное приложение написано на java (Android Studio). Транспорт использую тот же — WS (soap).

    Писал ЭТО для себя от нечего делать 🙂 … да и надоело счета собирать в папке на компе вручную ))

    По потоку:

    Из базы передается список XDTO состоящий из GUID «документа-отчета» и даты отчета.

    Каждая строка содержит список XDTO (номер счетчика + замеры до и после)

    На приложении:

    Всего 3 layout:настройки, список документов, детализация по документу (она же регистрация).

    Можно было и динамически клепать их, но лениво все описывать было да и отлавливать баги потом 🙂

    При открытии layouta документа (в т.ч. и нового) уже установлены номера счетчиков — только надо внести показания и все.

    Как то так …

    Мобильное приложение — кривоватое побочное дитя попытки 1С угнаться за модой, которое однажды канет в прошлое, как веб-расширения и тому подобная мутота…

    Что за консерватизм?? Мобильные устройства в бизнесе используются все больше и больше.

    «Мутота» — это для тех кто не знает КАК.

    Reply
  13. solarisman

    (13) DitriX, А на что обижаться, все правильно написано.

    Конечно, мне до ваших статей далеко, но и на фурор я не рассчитывал.

    Reply
  14. Yashazz

    (13) DitriX, а ещё от таких статей на ровном месте растёт «рейтинг»))) И потом начинаются распальцовки)

    Reply
  15. Yashazz

    (12) Nenaviju1C,

    Что за консерватизм?? Мобильные устройства в бизнесе используются все больше и больше.

    «Мутота» — это для тех кто не знает КАК.

    Ясно. Внимательно читать не умеете. Я же не про мобильные устройства «вообще» написал. Я про мобильное приложение 1С. И кое-что о перспективах оного знаю.

    Reply
  16. solarisman

    (15) Yashazz, Ладно, ладно, еще одну статью напишу в завершение и все, честно-честно. А то ишь, покусился на святой рейтинг топ-авторов.

    Вот честно, как дети. Напишите то же самое приложение с использованием

    (http реквесты, odata, json)

    покажите что оно лучше во всем и тогда я скажу что я опозорился и статьи удалю вообще

    Reply
  17. solarisman

    (16) Yashazz,

    И кое-что о перспективах оного знаю.

    Поделитесь секретом-то. А то я понять не могу, почему у нас региональный пищевой холдинг автоматизируется на мобильной платформе.

    Reply
  18. CheBurator

    (18) как заавтоматизируется и выйдет в плановую работу — отпишитесь. порадуемся или поплачем вместе…

    Reply
  19. WKBAPKA

    (13) DitriX, я поддержу автора. Для меня, как человека, который изучает Андроид, эта статья очень полезна. Меня больше интересует не подача текста, а примеры, которые автор очень любезно выложил.

    Reply
  20. mkostya

    Все отлично, заработало. Жду следующей статьи.

    Там будет и критика и предложения))

    Reply
  21. solarisman

    (22) Значит буду делать работу над ошибками 🙂

    Постараюсь написать статью 2-3 числа, был в командировке и все не разберусь с текущими задачами

    Reply
  22. agent00mouse

    2-3 Апреля? Долго, ну да ладно, ждём. Пилю приложение на базе 1С мобильного приложения, Да, функционал/идею протестировать годно, что серьёзнее и удобнее — нативный Java ведра нужен. т.ч. жду следующей статьи. Спасибо за разработку.

    И вопрос, soap конечно удобна, сам через неё работаю, но быстрее и главное проще же дёргать 1С за URL через HTTPСервисы, и как решается вопрос безопасного подключения(ssl)?

    Кому интересно, HTTPСервисы (I5-2500 (3,3GHz), 8Gb RAM, Пустая процедура ответа ~ 20000 подключений одновременно, с живой процедурой думаю цифра просядет)

    Reply
  23. user706108_prog

    Если в 1С не создавать пакет XDTO, то из мобильного приложения нельзя будет подсоединиться к веб-сервису 1С? В чем суть пакета XDTO?

    Тимур, а Вы в своем мобильном приложении какие библиотеки используете?

    ksoap2 используете или нет?

    Reply
  24. Serg O.

    главная идея вообще — БОМБА!

    1) мобильная платформа 1С — не нужна вообще!

    2) вместо этого — делаем красивое и простое приложение…

    в среде разработки — Android Studio

    3) с 1С — «общаемся» через web-сервисы 1С (или другие запросы кому как нравится)

    со стороны 1С — всё понятно, делаем web-сервисы и публикуем на «где-нибудь»

    мы тоже до этого «дошли» не так давно… один чел. у нас на Android Studio пишет

    другой — web-сервисы для него клепает…

    для программистов 1С — конечно трудновато «вспониминать» универ — создавать классы, методы, java язык с кучей скобок,

    вспоминать основы ООП…

    но визуальная среда — Android Studio — достаточно легка и интуитивно-понятна и многие вещи делаются по щелчку мыши

    в youtube — есть циклы обучения по Android Studio — я пару вечеров посидел… и вроде «вкурил» тему…

    Более того, Android Studio имеет автоматическую синхронизацию проекта в github

    Предлагаю проект выложить в Github — и далее там развивать эту тему…

    для «живого» проекта — наверное все-таки лучше приглашать отдельного java-программиста

    Reply
  25. WKBAPKA

    (26) круто конечно пишешь, но не все там просто в этом Андроид 😉

    все же Андроид будет покруче и посложнее 1С в изучении 🙂

    и поверь, сам язык Java фигня, а вот API изучить, приемы работы….

    за пару дней вьехать, это ты конечно немножечко преувеличил

    Reply
  26. WKBAPKA

    (26) а что там в студио по щелчку мыши можно сделать?

    layout-файл создать?

    😉

    Reply
  27. WKBAPKA

    (26) мобильная платформа знаешь где нужна, когда тебе надо сделать приложение со всеми этими иерархическими справочниками и т.п.

    поверь, на андроид ты таких готовых view не найдешь … в этом сила мобильного приложения.

    а если тебе надо написать приложени чисто под андроид и специфичное, то согласен, мобильная платформа тут не нужна

    Reply
  28. silberRus

    Поставил плюс.

    Пожелание:

    — сделать на http сервисе, через rest+json. SOAP + XML все таки громоздкий, как по отношению к данным так и по отношению к реализации.

    — добавить юнит тесты

    Reply
  29. ECartman

    Настроил сервер 1с по инструкции. Скачал проект для Android. Теперь если я захожу браузером по ссылке, то получаю xml файл — т.е. вроде со стороны 1с все работает. Но вот если запускаю apk на андроиде то получаю сообщение «невозможно соединиться с сервером». Подскажите куда копать?

    Reply
  30. ECartman

    (31) В классе MainActivity

    в параметрах подключения проставляю

    public void saveSettings(View v){
    
    soapParam_server    = etSoapServer.getText().toString();
    soapParam_database  = etSoapDatabase.getText().toString();
    soapParam_user      = etSoapUser.getText().toString();
    soapParam_pass      = etSoapPass.getText().toString();
    soapParam_timeout   = Integer.parseInt(etSoapTimeout.getText().toString());
    soapParam_URL       = «http://» + soapParam_server + «/» + soapParam_database + «/ws/AcceptingOrders.1cws?wsdl»;
    
    SharedPreferences.Editor editor = preferences.edit();
    editor.putString(«server», soapParam_server);
    editor.putString(«database», soapParam_database);
    editor.putString(«user», soapParam_user);
    editor.putString(«pass», soapParam_pass);
    editor.putString(«URL»,        soapParam_URL);
    editor.putInt(«timeout», soapParam_timeout);
    editor.apply();
    
    setContentView(R.layout.activity_main);
    startExchange(ACTION_GetLoginList);
    
    }
    
    protected void initiateConnectionSettings(){
    
    soapParam_server    = preferences.getString(«server», «192.168.0.25»);
    soapParam_database  = preferences.getString(«database», «AcceptingOrders»);
    soapParam_user      = preferences.getString(«user», «WSUser»);
    soapParam_pass      = preferences.getString(«pass», «1234»);
    soapParam_URL       = preferences.getString(«URL», «http://192.168.0.25/AcceptingOrders/ws/AcceptingOrders.1cws?wsdl»);
    soapParam_timeout   = preferences.getInt(«timeout», 10);
    
    }

    Показать

    Reply
  31. ECartman
    Reply
  32. WKBAPKA
    @Override
    protected String doInBackground(Void… voids) {
    try {
    
    DataXML.append(«Подключение к серверу …»);
    sendMessage(MainActivity.STATUS_MESSAGE);
    
    SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME);
    request.addProperty(«IDLogin»,mlogin);
    SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
    envelope.setOutputSoapObject(request);
    //envelope.dotNet = true;
    //envelope.implicitTypes = true;
    HttpTransportSE androidHttpTransport = new HttpTransportBasicAuthSE(URL, «pass», «pass»);
    androidHttpTransport.debug = true;
    try {
    DataXML.append(«Получение данных …»);
    sendMessage(MainActivity.STATUS_MESSAGE);
    
    androidHttpTransport.call(SOAP_ACTION, envelope);
    SoapObject resultRequestSOAP = (SoapObject) envelope.bodyIn;
    //Log.d(LOG_TAG, resultRequestSOAP.toString());
    return envelope.getResponse().toString();
    //return resultRequestSOAP.toString();
    }catch (Exception e){
    DataXML.append(«Ошибка при получении данных <» + e.toString() + «>»);
    sendMessage(MainActivity.STATUS_ERR);
    //                e.printStackTrace();
    }
    
    
    }catch (Exception e) {
    DataXML.append(«Ошибка при подключении к серверу <«+ e.toString() + «>»);
    sendMessage(MainActivity.STATUS_ERR);
    //            Log.d(LOG_TAG,e.toString());
    //            e.printStackTrace();
    }
    return «»;
    };
    
    

    Показать

    рабочий код из моего проекта

    Reply
  33. ECartman

    (34)

    рабочий код из моего проекта

    Прошу прощения, это модификация этого проекта или это кусок кода из Вашего проекта? Просто не понимаю, как это может быть для меня полезно? В какой класс это нужно вставить и откуда нужно вызывать функцию «doInBackground»? Просто у меня проблема с подключением. Андроид просто не может обратиться к серверу. Библиотеку ksoap2 я качал jar и подключал через меню file->project structure->dependies.

    Reply
  34. WKBAPKA

    Вы можете убрать лишнее и использовать в своем проекте. Я скопировал код реализации получения данных с помощью класса AsynkTask . За основу брал пример из этой статьи.

    Reply
  35. WKBAPKA

    Проект мой, рабочий. Ещё обратите внимание на релиз платформы 1С. Проверять работу веб сервиса советую другими средствами.

    Reply
  36. WKBAPKA

    я использовал SoapUI 5.3.0

    Reply
  37. WKBAPKA

    Еще обратите внимание, что на 1С:Предприятие 8.3 (8.3.9.1850) работать не будет, нужно ставить свежее платформу

    Reply
  38. zoytsa

    Коллеги, запутался с создагнием XDTO-пакета.

    Как LoginList создать, состоящий из Login?

    Вот так пробую (и еще много как):

    <xs:schema xmlns:tns=»AcceptingOrdersService» xmlns:xs=»http://www.w3.org/2001/XMLSchema» targetNamespace=»AcceptingOrdersService» attributeFormDefault=»unqualified» elementFormDefault=»qualified»>
    <xs:complexType name=»Login»>
    <xs:sequence>
    <xs:element name=»ID»/>
    <xs:element name=»Description»/>
    </xs:sequence>
    </xs:complexType>
    <xs:complexType name=»LoginList»>
    <xs:sequence>
    <xs:element name=»Login» type=»tns:Login»/>
    </xs:sequence>
    </xs:complexType>
    <xs:complexType name=»LoginResult»>
    <xs:sequence>
    <xs:element name=»Result»/>
    <xs:element name=»Name»/>
    </xs:sequence>
    </xs:complexType>
    </xs:schema>

    Показать

    Reply
  39. user966277

    (0)Здравствуйте помогите вывести qr-код в табличный документ

    &НаКлиенте
    Процедура печатькода(Команда)
    ТабДок1=внешнийQR();
    Если ТабДок1<>Ложь Тогда
    ТабДок1.Показать();
    КонецЕсли;
    
    КонецПроцедуры
    
    
    
    
    &Наклиенте
    Функция внешнийQR()
    
    
    
    
    #Если МобильноеПриложениеКлиент  Тогда
    
    
    НовВз = Новый ЗапускПриложенияМобильногоУстройства();
    НовВз.Действие=»com.google.zxing.client.android.ENCODE»;
    НовВз.ДополнительныеДанные.Добавить(«ENCODE_DATA»,»123″,»String»);
    НовВз.ДополнительныеДанные.Добавить(«ENCODE_TYPE»,»Text»,»String»);
    НовВз.ДополнительныеДанные.Добавить(«ENCODE_FORMAT»,»UPC_A»,»String»);
    НовВз.Запустить(Истина);
    
    //Для Каждого Стр Из НовВз.ДополнительныеДанные Цикл
    //Сообщить(Стр.Ключ+» — «+Стр.Значение);
    // КонецЦикла;
    
    
    Для Каждого Стр Из НовВз.ДополнительныеДанные Цикл
    
    Сообщить(Стр.Ключ+» — «+Стр.Значение);
    
    КонецЦикла;
    
    
    #КонецЕсли
    
    
    
    
    
    КонецФункции // внешнийQR()

    Показать

    (0)

    Reply
  40. WKBAPKA

    в последних проектах я использовал библиотеку Retrofit. В 1С HTTP сервис.

    Reply
  41. Denzip

    (11)отличная статья. Какая тут критика?

    Я давно искал способ написать интернет магазин со связью 1с. По ходу нашёл точку опоры!

    Огромное Вам спасибо за труды. Это многого стоит

    Reply
  42. fimbulwinter

    Спасибо, полезная статья.

    Reply
  43. fimbulwinter

    может кто нибудь выложить проект на гитхаб?

    Reply
  44. WKBAPKA

    (45) проще подключить Retrofit

    Reply
  45. WKBAPKA

    (46) зачем? )

    Reply
  46. WKBAPKA

    (30) Retrofit

    Reply
  47. WKBAPKA

    статья устаревшая. Лучше попробуйте Retrofit.

    Проще отлаживать, проще подключать, можно работать с GSon

    вот пример интерфейса:

    public interface ApiService {
    @GET(«{secondURL}/{id}/products»)
    Call<List<RetrofitProduct>> getListProducts(@Path(value =  «secondURL», encoded = true) String secondURL, @Path(«id») String id_client);
    
    }

    вот вызов

       response = mApiService.getReport(
    App.getDefaultSecondURL(),
    App.CONSTANT_ID_PARTNER,
    «reports»,
    retrofitDataReport).execute();
    
    if (response.isSuccessful()) {
    updateInfoReportData(idReport, response.body());
    }else {
    String errorMessage = response.raw().toString() + »
    »
    + response.errorBody().string();
    updateInfoReportData(idReport, response.raw().toString());
    MyLog.d(errorMessage);
    res.putString(KEY_EVENT_TEXT_ERROR, errorMessage);
    
    }

    Показать

    Reply
  48. WKBAPKA

    пример приведен синхронного вызова, т.к. работает с помощью WorkManager

    Reply

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *