пятница, 20 августа 2010 г.

1С: Печать Штрих-кода

В прошлой статье, я рассказал как получить доступ к сканеру штрих-кода (ШК), и получить от него данные. Сейчас я постараюсь рассказать как самостоятельно напечатать ШК.
Есть несколько стандартов штрих кодирования (EAN (EAN-8 состоит из 8 цифр, EAN-13 — используются 13 цифр), UPC (UPC-A, UPC-E), Code39, Code128 (UPC/EAN-128), Codabar, «Interleaved 2 of 5». Материал из ru.wikipedia.org).

Для себя я выбрал Code39 (хотя странно, лучше бы взял Code128) Примеры разработки есть в конфигурации Штрих-М (вы же их драйвер поставили?).
Вместе с конфигурацией Штрих-М шел шрифт Barcode.ttf, он должен быть установлен у всех кто будет печатать ШК. Итак приступим:
Функция Код_39_Смв(ввСтр)
    Если ввСтр = "1" Тогда
        Возврат "3113111131";
    ИначеЕсли ввСтр = "2" Тогда
        Возврат "1133111131";
    ИначеЕсли ввСтр = "3" Тогда
        Возврат "3133111111";
    ИначеЕсли ввСтр = "4" Тогда
        Возврат "1113311131";
    ИначеЕсли ввСтр = "5" Тогда
        Возврат "3113311111";
    ИначеЕсли ввСтр = "6" Тогда
        Возврат "1133311111";
    ИначеЕсли ввСтр = "7" Тогда
        Возврат "1113113131";
    ИначеЕсли ввСтр = "8" Тогда
        Возврат "3113113111";
    ИначеЕсли ввСтр = "9" Тогда
        Возврат "1133113111";
    ИначеЕсли ввСтр = "0" Тогда
        Возврат "1113313111";
    ИначеЕсли ввСтр = "A" Тогда
        Возврат "3111131131";
    ИначеЕсли ввСтр = "B" Тогда
        Возврат "1131131131";
    ИначеЕсли ввСтр = "C" Тогда
        Возврат "3131131111";
    ИначеЕсли ввСтр = "D" Тогда
        Возврат "1111331131";
    ИначеЕсли ввСтр = "E" Тогда
        Возврат "3111331111";
    ИначеЕсли ввСтр = "F" Тогда
        Возврат "1131331111";
    ИначеЕсли ввСтр = "G" Тогда
        Возврат "1111133131";
    ИначеЕсли ввСтр = "H" Тогда
        Возврат "3111133111";
    ИначеЕсли ввСтр = "I" Тогда
        Возврат "1131133111";
    ИначеЕсли ввСтр = "J" Тогда
        Возврат "1111333111";
    ИначеЕсли ввСтр = "K" Тогда
        Возврат "3111111331";
    ИначеЕсли ввСтр = "L" Тогда
        Возврат "1131111331";
    ИначеЕсли ввСтр = "M" Тогда
        Возврат "3131111311";
    ИначеЕсли ввСтр = "N" Тогда
        Возврат "1111311331";
    ИначеЕсли ввСтр = "O" Тогда
        Возврат "3111311311";
    ИначеЕсли ввСтр = "P" Тогда
        Возврат "1131311311";
    ИначеЕсли ввСтр = "Q" Тогда
        Возврат "1111113331";
    ИначеЕсли ввСтр = "R" Тогда
        Возврат "3111113311";
    ИначеЕсли ввСтр = "S" Тогда
        Возврат "1131113311";
    ИначеЕсли ввСтр = "T" Тогда
        Возврат "1111313311";
    ИначеЕсли ввСтр = "U" Тогда
        Возврат "3311111131";
    ИначеЕсли ввСтр = "V" Тогда
        Возврат "1331111131";
    ИначеЕсли ввСтр = "W" Тогда
        Возврат "3331111111";
    ИначеЕсли ввСтр = "X" Тогда
        Возврат "1311311131";
    ИначеЕсли ввСтр = "Y" Тогда
        Возврат "3311311111";
    ИначеЕсли ввСтр = "Z" Тогда
        Возврат "1331311111";
    ИначеЕсли ввСтр = "-" Тогда
        Возврат "1311113131";
    ИначеЕсли ввСтр = "." Тогда
        Возврат "3311113111";
    ИначеЕсли ввСтр = " " Тогда
        Возврат "1331113111";
    ИначеЕсли ввСтр = "*" Тогда
        Возврат "1311313111";
    ИначеЕсли ввСтр = "$" Тогда
        Возврат "1313131111";
    ИначеЕсли ввСтр = "/" Тогда
        Возврат "1313111311";
    ИначеЕсли ввСтр = "+" Тогда
        Возврат "1311131311";
    ИначеЕсли ввСтр = "%" Тогда
        Возврат "1113131311";
    КонецЕсли;

    Возврат "";
КонецФункции                        

Функция Код_Символа(ввСтр)
    Стр = "";
    Если ввСтр = "211412" Тогда
        Стр = "A";
    ИначеЕсли ввСтр = "211214" Тогда
        Стр = "B";
    ИначеЕсли ввСтр = "211232" Тогда
        Стр = "C";
    ИначеЕсли ввСтр = "2331112" Тогда
        Стр = "@";
    Иначе
        Стр = "";

        Для ц = 0 по СтрДлина(ввСтр)/2-1 Цикл
            ст = Сред(ввСтр,2*ц+1,2);
            Если ст = "11" Тогда
                Стр = Стр + "0";
            ИначеЕсли ст = "21" Тогда
                Стр = Стр + "1";
            ИначеЕсли ст = "31" Тогда
                Стр = Стр + "2";
            ИначеЕсли ст = "41" Тогда
                Стр = Стр + "3";
            ИначеЕсли ст = "12" Тогда
                Стр = Стр + "4";
            ИначеЕсли ст = "22" Тогда
                Стр = Стр + "5";
            ИначеЕсли ст = "32" Тогда
                Стр = Стр + "6";
            ИначеЕсли ст = "42" Тогда
                Стр = Стр + "7";
            ИначеЕсли ст = "13" Тогда
                Стр = Стр + "8";
            ИначеЕсли ст = "23" Тогда
                Стр = Стр + "9";
            ИначеЕсли ст = "33" Тогда
                Стр = Стр + ":";
            ИначеЕсли ст = "43" Тогда
                Стр = Стр + ";";
            ИначеЕсли ст = "14" Тогда
                Стр = Стр + "<";    
            ИначеЕсли ст = "24" Тогда
                Стр = Стр + "=";
            ИначеЕсли ст = "34" Тогда
                Стр = Стр + ">";
            ИначеЕсли ст = "44" Тогда
                Стр = Стр + "?";
            КонецЕсли;
        КонецЦикла;
    КОнецЕсли;
    Возврат Стр;
КонецФункции

Функция Код_39(ввСтр)
    стр = "";
    Для ц = 1 по СтрДлина(ввСтр) Цикл
        Стр = Стр + Код_Символа(Код_39_Смв(Сред(ввСтр,ц,1)));
    КонецЦикла;
    Возврат Код_Символа(Код_39_Смв("*")) + Стр + Код_Символа(Код_39_Смв("*"));
КонецФункции
Это я взял из конфы. Можно так и переносить. Как видим Код39 предоставляет нам 39 символа, их кодирование достаточно понятно (учитывая понимание специфики кодирования штрих кодов, в строке цифрой указывается ширина полосы), для Code128 так же есть готовое решение (все в том же Штрих-М).
Теперь в любом месте, где нужно напечатать ШК, создаем ячейку с шрифтом Barcode и выражением Код_39(Строка(<требуемая строка>)).
В штрих код я заношу следующее: Сумма-ИДД-Дата. Выходит порядка 16-20 символов.
Казалось бы все хорошо можем передавать строку и получать ШК. Как оказалось на практике, ловить сканером строку длиннее 13 символов сложно, и не удобно. Можно было бы использовать Code128. Но я решил пойти другим путем: Сжать передаваемое значение до минимума. В нашем распоряжении 36 символов (A-Z,0-9). На вход получаем строку состоящую только из чисел. Приводим число к основанию 36, и отправляем на печать.
Моя реализация:
Функция Симв36(Стр)
    // выдает символ по коду
    Возврат ?((Стр >= 0) и (Стр <= 9),Симв(стр + 48),симв(стр + 55));
КонецФункции

Функция ВСтр36(ТекЧ) Экспорт
    // собственно приведение с помощью рекурсии
    Если ТекЧ = 0 Тогда
        Возврат ""
    КонецЕсли;
    Возврат ВСтр36((ТекЧ - (ТекЧ % 36)) / 36) + Симв36(ТекЧ % 36);
КонецФункции


Функция Обратить(Стр)
    // реверс
    Если Стр = "" тогда
        Возврат Стр
    КонецЕсли;
    Возврат Обратить(Прав(Стр,СтрДлина(Стр)-1)) + Лев(стр,1);
КонецФункции

Функция Из36вСтр(ТекС)
    // Обратная операция, так же рекурсия
    Если ТекС = "" Тогда
        Возврат 0
    КонецЕсли;

    Сим = Лев(ТекС,1);
    ТекС = Прав(ТекС,СтрДлина(ТекС) - 1);
 
    Возврат ?((Сим >= "0") и (Сим <= "9"),Из36ВСтр(Текс)*36 + 
              (КодСимв(Сим) - 48),Из36ВСтр(Текс)*36 + (КодСимв(Сим) - 55));
КонецФункции

функция Из36ВСтроку(Текс) Экспорт
    Возврат Из36вСтр(Обратить(Текс));
КонецФункции
Хочется затронуть еще один момент, я долго размышлял как мне универсально найти документ, изначально в ШК был зашит номер документа и его дата, но был найден более элегантный способ, использовать функции ЗначениеВСтрокуВнутр, ЗначениеИзСтрокиВнутр. Получить ИДД и Объект по ИДД например так:
// Функция получает уникальный идентификатор объекта.
// Передаваемые значения:
// объект метаданных (элемент справочника, документ и т.д.).
// вид метаданных (число, строка или вид документа или справочника). 
// тип метаданных документ, справочник и т.д..
Функция мбИДД(Объект,Тип,Вид) Экспорт
    Если (СокрЛП(ТипЗначенияСтр(Объект)) = "Строка") или
        (СокрЛП(ТипЗначенияСтр(Объект)) = "Число") Тогда
        ПустойОбъект = "";
        Если Тип <> "Перечисление" Тогда
            ПустойОбъект = СоздатьОбъект(Тип + "." + Вид);
        Иначе
            ПустойОбъект = Перечисление.ТипыРасхЦен.Прайсовая;
        КонецЕсли;

        ПустойОбъект = ЗначениеВСтрокуВнутр(ПустойОбъект);       
        П1 = Найти(ПустойОбъект,"}");
        П2 = Сред(ПустойОбъект,1,29);
        П3 = ЗначениеИзСтрокиВнутр(П2 + Строка(Объект) + " ""} ");
        Возврат П3;
    Иначе 
        СтрокаОбъекта = Сред(ЗначениеВСтрокуВнутр(Объект),30,Найти(ЗначениеВСтрокуВнутр(Объект),"}")-31);
        Возврат СтрокаОбъекта;
    КонецЕсли;
КонецФункции // мбИДД(Объект,Тип,Вид).
Позаимствовано из конфигурации CDC (ОПТИМУМ, мобильные продажи). Ну и кратенько пример как я собираю строку для ШК.
ДляШК = ВСтр36(Число(Строка(Формат(Итог("Сумма"),"Ч(0)8.0") + Строка(Формат(Число(мбИДД(ТекущийДокумент(),"Документ","РасходнаяКредит")),"Ч(0)8.0")) + Строка(Формат(ДатаМесяц(ДатаДок),"Ч(0)2.0")) + Строка(Формат(ДатаЧисло(ДатаДок),"Ч(0)2.0"))));
По невыясненным причинам иногда Формат по отдельности выдает строки, а при конкатенации преобразует к числу и складывает их между собой.
В итоге у меня в худшем случае получается 20 символов, после преобразования 16. Но таких случаев очень мало, с начала года есть только один документ на 2кк. А среднее не превышает 10к. Документ с суммой в 300к занимает 12знаков.

Комментариев нет:

Отправить комментарий