Наверное каждому кто пишет свою конфигурацию с нуля, рано или поздно понадобится подключить к ней какое то оборудование, будь то принтер чеков, кассовый аппарат, сканер штрихкодов и т.д. Если делать это с нуля без каких либо заготовок, задача может показаться не такой то и простой, так как потребуется изучить само оборудование, найти драйвера к нему и написать интерфейс обмена его со своей конфигурацией.
Однако не стоит идти путем сопротивление, когда есть достаточно простое и эффективное решение в виде Библиотеки подключаемого оборудования (БПО) от компании 1С. Библиотека предназначена для внедрения в любую конфигурацию и содержит все заготовки для подключения большого количества оборудования. Ее то мы и сегодня рассмотрим. На момент написания данной статьи, текущей версией БПО является 2.1.1.25. Скачать ее надо с сайта ИТС. Ну или если хорошо поискать можно найти на просторах рунета.
Итак скачав и установив БПО, откройте конфигуратор и сделайте операцию Сравнения и объединения и конфигурацией БПО. Сама она находится приблизительно по следующему адресу: C:\Users\nariman\AppData\Roaming\1C\1c8\tmplts\1c\CEL\2_1_1_25\ExtFiles
На вопрос о постановке на поддержку я бы посоветовал ответить Да.
Далее необходимо отметить необходимые вам подсистемы.
1) Для начала снимите галочки с корня конфигурации и диалоге сравнения и объединения, затем выполните действие «Отметить по подсистемам из файла» и отметьте подсистему – ПодключаемоеОборудование. Снимите флажок «Включать объекты подчинённых подсистем». Нажмите «Установить».
2) Ещё раз выполните действие «Отметить по подсистемам из файла». На этот раз отметьте подсистемы необходимого оборудования вложенные в ПодключаемоеОборудование. Нажмите «Установить».
3) Нажмите Выполнить и Продолжить.
Далее согласно инструкциям с ИТС:
В целевую конфигурацию в модуль управляемого приложения в процедуры ПередНачаломРаботыСистемы(), ПриНачалеРаботыСистемы(), ПередЗавершениемРаботыСистемы(), ОбработкаВнешнегоСобытия()перенести код отвечающий за инициализацию и работу библиотеки.
Далее включаем справочники ДрайверыОборудования и ПодключаемоеОборудование в свою подсистему и включаем мх в командный интерфейс управляемого приложения. При попытке запуска настройки рабочего места мы получим ошибку.
Чтож ожидаемо, так как мы не перенесли код в модуль управляемого приложения. Так давайте же сделаем это.
<code>// ПодключаемоеОборудование
Перем глПодключаемоеОборудование Экспорт; // для кэширования на клиенте
// Конец ПодключаемоеОборудование
Процедура ПередНачаломРаботыСистемы(Отказ)
// ПодключаемоеОборудование
МенеджерОборудованияКлиент.ПередНачаломРаботыСистемы();
// Конец ПодключаемоеОборудование
КонецПроцедуры
Процедура ПриНачалеРаботыСистемы()
// ПодключаемоеОборудование
МенеджерОборудованияКлиент.ПриНачалеРаботыСистемы();
// Конец ПодключаемоеОборудование
КонецПроцедуры
Процедура ПередЗавершениемРаботыСистемы(Отказ)
// ПодключаемоеОборудование
МенеджерОборудованияКлиент.ПередЗавершениемРаботыСистемы();
// Конец ПодключаемоеОборудование
КонецПроцедуры
Процедура ОбработкаВнешнегоСобытия(Источник, Событие, Данные)
// ПодключаемоеОборудование
// Подготовить данные
ОписаниеСобытия = Новый Структура();
ОписаниеОшибки = "";
ОписаниеСобытия.Вставить("Источник", Источник);
ОписаниеСобытия.Вставить("Событие", Событие);
ОписаниеСобытия.Вставить("Данные", Данные);
// Передать на обработку данные.
Результат = МенеджерОборудованияКлиент.ОбработатьСобытиеОтУстройства(ОписаниеСобытия, ОписаниеОшибки);
Если Не Результат Тогда
ОбщегоНазначенияКлиентСервер.СообщитьПользователю(НСтр("ru='При обработке внешнего события от устройства произошла ошибка.'")
+ Символы.ПС + ОписаниеОшибки);
КонецЕсли;
// Конец ПодключаемоеОборудование
КонецПроцедуры
</code>
Также нужно установить в параметрах сеанса код, ответственный за установку параметров. Пример кода можно посмотреть в Демо базае БПО, текущего релиза, в моем случае это было:
<code>#Если Сервер Или ТолстыйКлиентОбычноеПриложение Или ВнешнееСоединение Тогда #Область ОбработчикиСобытий Процедура УстановкаПараметровСеанса(ИменаПараметровСеанса) // СтандартныеПодсистемы СтандартныеПодсистемыСервер.УстановкаПараметровСеанса(ИменаПараметровСеанса); // Конец СтандартныеПодсистемы // УниверсальныеМеханизмы Если ИменаПараметровСеанса = Неопределено Тогда // Раздел безусловной установки параметров сеанса. // Конец УниверсальныеМеханизмы // Переопределяемый блок // // Конец переопределяемого блока. // УниверсальныеМеханизмы Иначе // Установка параметров сеанса "по требованию". // Параметры сеанса, инициализация которых требует обращения к одним и тем же данным // следует инициализировать сразу группой. для того, чтобы избежать их повторной инициализации, // имена уже установленных параметров сеанса сохраняются в структуре УстановленныеПараметры. УстановленныеПараметры = Новый Массив(); Для Каждого ИмяПараметра Из ИменаПараметровСеанса Цикл УстановитьЗначениеПараметраСеанса(ИмяПараметра, УстановленныеПараметры); КонецЦикла; КонецЕсли; // Конец УниверсальныеМеханизмы КонецПроцедуры Процедура УстановитьЗначениеПараметраСеанса(Знач ИмяПараметра, УстановленныеПараметры) // Конец УниверсальныеМеханизмы Если УстановленныеПараметры.Найти(ИмяПараметра) <> Неопределено Тогда Возврат; КонецЕсли; // Конец УниверсальныеМеханизмы // Переопределяемый блок // ПодключаемоеОборудование МенеджерОборудованияВызовСервера.УстановитьПараметрыСеансаПодключаемогоОборудования(ИмяПараметра, УстановленныеПараметры); // Конец ПодключаемоеОборудование // Конец переопределяемого блока. КонецПроцедуры #КонецОбласти #КонецЕсли</code>
Итак запускаем базу и видим что ошибок нет. Добавляем драйвера, в конфу, я их выгрузил из справочники Драйверы оборудования и добавил ручками в свою конфу. И создаем экземпляр оборудования.
Ну а дальше дело за малым, читаем документацию соответственно подключаемому оборудованию и реализуем код. В моем случае для печати чека на принтере чеков я реализовал простейшую функцию.
<code>#Область Печать
&НаКлиенте
Процедура ПробитьЧек(Команда)
Если Объект.Услуги.Количество() > 0 И Объект.СуммаДокумента > 0 Тогда
ИдентификаторККТ = мд_ОбщиеПроцедурыСервер.ПолучитьИдентификаторПринтераЧеков();
ВходныеПараметры = ПолучитьДанныеЧека(Неопределено, ИдентификаторККТ);
ВыходныеПараметры = Неопределено;
ПослеОткрытияЧека = Неопределено;
ОписаниеОповещения = Новый ОписаниеОповещения("ФискализацияЧека_Завершение", ЭтотОбъект,);
МенеджерОборудованияКлиент.НачатьФискализациюЧекаНаФискальномУстройстве(ОписаниеОповещения, УникальныйИдентификатор, ВходныеПараметры, ИдентификаторККТ, , ПослеОткрытияЧека);
Иначе
Сообщить("В документе нет оказанных услуг");
КонецЕсли;
КонецПроцедуры
Функция ПолучитьДанныеЧека(ПараметрыОперации = Неопределено, ИдентификаторУстройства = Неопределено);
// Подготовка соответствие секций для табличной части.
ТаблицаТоваровСоответствииСекциям = Новый Соответствие();
//_ДемоПодключаемоеОборудованиеВызовСервера.ЗаполнитьСоответствиеСекцийДляТабличнойЧасти(Объект.РаспределенияВыручки, Объект.Товары, ТаблицаТоваровСоответствииСекциям);
// Общие параметры чека
ОбщиеПараметры = МенеджерОборудованияКлиентСервер.ПараметрыОперацииЧекаКоррекции();
ОбщиеПараметры.ДокументОснование = Объект.Ссылка;
//Если ЗначениеЗаполнено(КорректируемыйДокумент) Тогда
// ОбщиеПараметры.КорректируемыйДокумент = КорректируемыйДокумент
//КонецЕсли;
ФискальнаяОперации = МенеджерОборудованияВызовСервера.ДанныеФискальнойОперации(ОбщиеПараметры.ДокументОснование, XMLСтрока(ОбщиеПараметры.ДокументОснование));
Если ФискальнаяОперации <> Неопределено Тогда
ПараметрыQRКода = МенеджерОборудованияКлиентСервер.ПараметрыQRКодаЧекаККТ();
ПараметрыQRКода.ДатаВремяРасчета = ФискальнаяОперации.Дата;
ПараметрыQRКода.СуммаРасчета = ФискальнаяОперации.Сумма;
ПараметрыQRКода.НомерФискальногоНакопителя = ФискальнаяОперации.ЗаводскойНомерФН;
ПараметрыQRКода.НомерФискальногоДокумента = ФискальнаяОперации.НомерЧекаККМ;
ПараметрыQRКода.ФискальныйПризнак = ФискальнаяОперации.ФискальныйПризнак;
ПараметрыQRКода.ПризнакРасчета = Объект.ТипОперации;
QRКод = МенеджерОборудованияКлиентСервер.СформироватьQRКодЧекаККТ(ПараметрыQRКода);
ОбщиеПараметры.Вставить("QRКод", QRКод);
КонецЕсли;
НомерСтроки = 0;
Для Каждого СтрокаТЧ Из Объект.Услуги Цикл
НомерСтроки = НомерСтроки + 1;
НомерСекции = ТаблицаТоваровСоответствииСекциям.Получить(СтрокаТЧ.НомерСтроки);
СтрокаПозицииЧека = МенеджерОборудованияКлиентСервер.ПараметрыФискальнойСтрокиЧека();
СтрокаПозицииЧека.ПризнакСпособаРасчета = Перечисления.ПризнакиСпособаРасчета.ПредоплатаПолная;
СтрокаПозицииЧека.ПризнакПредметаРасчета = Перечисления.ПризнакиПредметаРасчета.Услуга;
СтрокаПозицииЧека.Наименование = Строка(СтрокаТЧ.Услуга);
СтрокаПозицииЧека.Количество = СтрокаТЧ.Количество;
СтрокаПозицииЧека.Цена = СтрокаТЧ.Цена;
СтрокаПозицииЧека.Сумма = СтрокаТЧ.Сумма;
СтрокаПозицииЧека.НомерСекции = НомерСекции;
СтрокаПозицииЧека.СуммаСкидок = 0;
СтрокаПозицииЧека.СтавкаНДС = 20;
СтрокаПозицииЧека.НомерСтрокиТовара = НомерСтроки;
СтрокаПозицииЧека.СуммаНДС = 0;
СтрокаПозицииЧека.ЕдиницаИзмерения = "Штука";
//СтрокаПозицииЧека.ПризнакАгентаПоПредметуРасчета = СтрокаТЧ.Номенклатура.ПризнакАгента;
//СтрокаПозицииЧека.ДанныеПоставщика.Телефон = СтрокаТЧ.Номенклатура.ДанныеПоставщикаТелефон;
//СтрокаПозицииЧека.ДанныеПоставщика.Наименование = СтрокаТЧ.Номенклатура.ДанныеПоставщикаНаименование;
//СтрокаПозицииЧека.ДанныеПоставщика.ИНН = СтрокаТЧ.Номенклатура.ДанныеПоставщикаИНН;
//СтрокаПозицииЧека.ДанныеАгента.ПлатежныйАгент.Операция = СтрокаТЧ.Номенклатура.ПлатежныйАгентОперация;
//СтрокаПозицииЧека.ДанныеАгента.ПлатежныйАгент.Телефон = СтрокаТЧ.Номенклатура.ПлатежныйАгентТелефон;
//СтрокаПозицииЧека.ДанныеАгента.ОператорПеревода.Телефон = СтрокаТЧ.Номенклатура.ОператорПереводаТелефон;
//СтрокаПозицииЧека.ДанныеАгента.ОператорПеревода.Наименование = СтрокаТЧ.Номенклатура.ОператорПереводаНаименование;
//СтрокаПозицииЧека.ДанныеАгента.ОператорПеревода.Адрес = СтрокаТЧ.Номенклатура.ОператорПереводаАдрес;
//СтрокаПозицииЧека.ДанныеАгента.ОператорПеревода.ИНН = СтрокаТЧ.Номенклатура.ОператорПереводаИНН;
//СтрокаПозицииЧека.ДанныеАгента.ОператорПоПриемуПлатежей.Телефон = СтрокаТЧ.Номенклатура.ОператорПоПриемуПлатежейТелефон;
//СтрокаПозицииЧека.ДанныеКодаТоварнойНоменклатуры.ТипМаркировки = СтрокаТЧ.ТипМаркировки;
//СтрокаПозицииЧека.ДанныеКодаТоварнойНоменклатуры.КонтрольныйИдентификационныйЗнак = СтрокаТЧ.КонтрольныйИдентификационныйЗнак;
//СтрокаПозицииЧека.ДанныеКодаТоварнойНоменклатуры.ГлобальныйИдентификаторТорговойЕдиницы = СтрокаТЧ.ГлобальныйИдентификаторТорговойЕдиницы;
//СтрокаПозицииЧека.ДанныеКодаТоварнойНоменклатуры.СерийныйНомер = СтрокаТЧ.СерийныйНомер;
//СтрокаПозицииЧека.КодСтраныПроисхожденияТовара = СтрокаТЧ.КодСтраныПроисхожденияТовара;
//СтрокаПозицииЧека.НомерТаможеннойДекларации = СтрокаТЧ.НомерТаможеннойДекларации;
//СтрокаПозицииЧека.СуммаАкциза = СтрокаТЧ.СуммаАкциза;
//СтрокаПозицииЧека.ДополнительныйРеквизит = СтрокаТЧ.ДополнительныйРеквизит;
ОбщиеПараметры.ПозицииЧека.Добавить(СтрокаПозицииЧека);
КонецЦикла;
// Подготовка таблицы оплат
СтрокаОплаты = МенеджерОборудованияКлиентСервер.ПараметрыСтрокиОплаты();
СтрокаОплаты.ТипОплаты = Перечисления.ТипыОплатыККТ.Наличные;
СтрокаОплаты.Сумма = Объект.СуммаДокумента;
ОбщиеПараметры.ТаблицаОплат.Добавить(СтрокаОплаты);
ОбщиеПараметры.ПризнакАгента = Ложь;
//ОбщиеПараметры.ДанныеПоставщика.Телефон = Объект.ДанныеПоставщикаТелефон;
//ОбщиеПараметры.ДанныеПоставщика.Наименование = Объект.ДанныеПоставщикаНаименование;
//ОбщиеПараметры.ДанныеПоставщика.ИНН = Объект.ДанныеПоставщикаИНН;
//ОбщиеПараметры.ДанныеАгента.ПлатежныйАгент.Операция = Объект.ПлатежныйАгентОперация;
//ОбщиеПараметры.ДанныеАгента.ПлатежныйАгент.Телефон = Объект.ПлатежныйАгентТелефон;
//ОбщиеПараметры.ДанныеАгента.ОператорПеревода.Телефон = Объект.ОператорПереводаТелефон;
//ОбщиеПараметры.ДанныеАгента.ОператорПеревода.Наименование = Объект.ОператорПереводаНаименование;
//ОбщиеПараметры.ДанныеАгента.ОператорПеревода.Адрес = Объект.ОператорПереводаАдрес;
//ОбщиеПараметры.ДанныеАгента.ОператорПеревода.ИНН = Объект.ОператорПереводаИНН;
//ОбщиеПараметры.ДанныеАгента.ОператорПоПриемуПлатежей.Телефон = Объект.ОператорПоПриемуПлатежейТелефон;
// Общие реквизиты для всех типов оборудования.
ОбщиеПараметры.ТипРасчета = Перечисления.ТипыРасчетаДенежнымиСредствами.ПриходДенежныхСредств;
ОбщиеПараметры.Кассир = СокрЛП("Анна Каренина");
ОбщиеПараметры.КассирИНН = СокрЛП("4205454848484");
ОбщиеПараметры.ОрганизацияНазвание = "ИП Рамазанов Рамазан";
ОбщиеПараметры.ОрганизацияИНН = "123456789012";
ОбщиеПараметры.ОрганизацияКПП = "234523454542";
Если Не ПустаяСтрока(Объект.Пациент) Тогда
ОбщиеПараметры.Получатель = Строка(Объект.Пациент);
ОбщиеПараметры.ПолучательИНН = "";
КонецЕсли;
ОбщиеПараметры.АдресРасчетов = "г.Москва, Дмитровское ш. д.9";
//ОбщиеПараметры.МестоРасчетов = "Северное крыло, комната 9441";
// Параметры необходимые для чека ЕНВД на принтере чеков
ОбщиеПараметры.НомерКассы = "3463345";
ОбщиеПараметры.НомерЧека = Объект.Номер;
ОбщиеПараметры.НомерСмены = 3;
// Новые параметры для ККТ по ФЗ-54
ОбщиеПараметры.ОтправительEmail = "info@1c.ru";
Если ПараметрыОперации <> Неопределено И ПараметрыОперации.Свойство("Печать") Тогда
ОбщиеПараметры.Электронно = НЕ ПараметрыОперации.Печать;
Если ПараметрыОперации.Свойство("ПокупательEmail") И Не ПустаяСтрока(ПараметрыОперации.Свойство("ПокупательEmail")) Тогда
ОбщиеПараметры.ПокупательEmail = ПараметрыОперации.ПокупательEmail;
ОбщиеПараметры.Отправляет1СEmail = ПараметрыОперации.ОтправлятьEmailСредствами1С;
КонецЕсли;
Если ПараметрыОперации.Свойство("ПокупательНомер") И Не ПустаяСтрока(ПараметрыОперации.Свойство("ПокупательНомер")) Тогда
ОбщиеПараметры.ПокупательНомер = ПараметрыОперации.ПокупательНомер;
ОбщиеПараметры.Отправляет1СSMS = ПараметрыОперации.ОтправлятьSMSСредствами1С;
КонецЕсли;
Иначе
ОбщиеПараметры.Электронно = Ложь;
КонецЕсли;
ОбщиеПараметры.СистемаНалогообложения = Перечисления.ТипыСистемНалогообложенияККТ.УСНДоход;
ОбщиеПараметры.ДанныеКоррекции.ТипКоррекции = 0;
ОбщиеПараметры.ДанныеКоррекции.ОписаниеКоррекции = "";
ОбщиеПараметры.ДанныеКоррекции.ДатаКоррекции = ТекущаяДатаСеанса();
ОбщиеПараметры.ДанныеКоррекции.НомерПредписания = 0;
ОбщиеПараметры.НеприменениеККТ = Ложь;
//ОбщиеПараметры.ДополнительныйРеквизит = Объект.ДополнительныйРеквизит;
//ОбщиеПараметры.ДополнительныйРеквизитПользователя.Наименование = Объект.РеквизитПользователяНаименование;
//ОбщиеПараметры.ДополнительныйРеквизитПользователя.Значение = Объект.РеквизитПользователяЗначение;
Если ИдентификаторУстройства <> Неопределено Тогда
РеквизитыОборудования = ФорматноЛогическийКонтрольВызовСервера.СтруктураДанныхФорматноЛогическогоКонтроля(ИдентификаторУстройства);
ОбщиеПараметры.СпособФорматноЛогическогоКонтроля = РеквизитыОборудования.СпособФорматноЛогическогоКонтроля;
ОбщиеПараметры.ДопустимоеРасхождениеФорматноЛогическогоКонтроля = РеквизитыОборудования.ДопустимоеРасхождениеФорматноЛогическогоКонтроля;
Иначе
ОбщиеПараметры.СпособФорматноЛогическогоКонтроля = Перечисления.СпособыФорматноЛогическогоКонтроля.РазделятьСтроки;
КонецЕсли;
ОбщиеПараметры.СформироватьЧекКоррекции = Ложь;
Возврат ОбщиеПараметры;
КонецФункции
&НаКлиенте
Процедура ФискализацияЧека_Завершение(РезультатВыполнения, Параметры) Экспорт
Если РезультатВыполнения.Результат Тогда
Иначе
ТекстСообщения = РезультатВыполнения.ОписаниеОшибки;
ОбщегоНазначенияКлиентСервер.СообщитьПользователю(ТекстСообщения);
КонецЕсли;
Доступность = Истина;
КонецПроцедуры
</code>
