суббота, 26 мая 2012 г.

Строковые литералы и символьные литералы. Пробел

Хотя ABAP позволяет практически незаметно и безболезненно конвертировать одни типы  данных в другие, а типы  STRING и C вообще считает чуть ли не синонимами, все таки бывают ситуации, когда в их поведении есть отличия. Одним из таких отличий является то, как типы string  и char  воспринимают пробел.

На само деле С (char) - это всего 1 символ, так что правильнее говорить об элементе данных  большей длины, но с внутренним типом C - например CHAR10. Фактически CHAR10 - это "статический" массив из 10 символов типа C, в тоже время STRING - это "динамический" массив ( то есть с переменной длиной) символов типа C.

Рассмотрим следующий код:
DATA lv_char TYPE char10 VALUE '12345'.
DATA lv_str TYPE string VALUE '12345'.

Здесь переменная lv_char хранит значение, равное '12345     '- то есть символы от 1 до 5 и еще 5 пробелов, потому что у нее фиксированная длина 10 символов.  Переменная lv_str хранит только символы '12345'.

А теперь следующий код:
DATA lv_char TYPE char10 VALUE  space.
DATA lv_str TYPE string VALUE space.


space - это заменитель ' '.
Здесь переменная lv_char хранит значение, равное 10 пробелам.  Переменная lv_str хранит '', то есть ничего. Не один пробел, а именно ничего. Длина строки = 0.

Ну с lv_char думаю все понятно. Почему lv_str не хранит пробел?
Потому что мы инициализируем ее символьным литералом (символьной константой) - то есть неким набором символом (в данном случае пробелом), заключенным между одинарных кавычек. Прикол в том, что в символьных литералах граничные  пробелы удаляются. Поскольку у нас ничего кроме пробела нет, то строка в итоге ничего и не хранит.

Рассмотрим пример, в котором проявляются особенности переменных типа CHAR* и сжатия пробелов.
Допустим у нас извне приходит некое значение в переменной lv_char типа CHAR10 - пользователь что-то вводит, IDOC пришел - что угодно. Нам нужно проверить, что это значение содержит только цифры. Если это не так, выдавать ошибку, писать логи - что угодно. Не суть важно.
Как это можно проверить? Например, так:
IF lv_char CO '0123456789'.
  "только цифры.
ELSE.
  "что-то еще
ENDIF.

Теперь допустим  нам приходит в переменной lv_char число 42. Но после проверки мы попадаем в ветку ELSE. Удивительно? На первый взгляд да - ведь в переменной только цифры 4 и 2, проверка должна проходить. Но потом становится понятно, что на самом деле не только 4 и 2, а еще и 8 пробелов. Ладно, меняем условие на такое, что в переменной допускаются цифры и пробелы:
IF lv_char CO '0123456789 '. "После 9 стоит пробел

Но программа  все равно упорно лезет в ветку ELSE. Ну поскольку про сжатие пробелов Вы уже в курсе, то можете догадаться, что наш трюк с добавлением пробела не сработал, потому что компилятор его все равно выкинул и в итоге в скомпилированном коде у нас все также проверка на 1-9. О пробелах ни слова, ни байта.

Ну это все замечательно, но что делать? Вариантов несколько:

  1. Поставить пробел не в конце, а, например, посередине:
    IF lv_char CO '01234 56789'"После 4 стоит пробел. 
    Поможет в данном случае, поскольку пробелы нам фактически не нужны - мы просто обходим особенность CHAR, но могут быть случаи, когда пробел ключевая фигура - ниже я приведу пример.
  2. Помещать lv_char предварительно в переменную типа string. Это также прокатит, если вам фактически пробел не нужен. Но если нужен - то нет. Причем в отличии от п.1 это еще и лишняя переменная, лишнее присвоение, да и лишняя писанина.
  3. Использовать не символьный литерал, а строковый. Строковый в коде задается набором символов ограниченным апострофами (на русской клавиатуре он обычно на кнопке с буквой Ё). Напомню, символьный ограничивается одинарной кавычкой (на кнопке с Э). В строковых литералах пробелы НЕ сжимаются - что ввели, то и будет в коде. То есть, в нашем примере код может быть таким:
    IF lv_char CO  `0123456789 `"После 9 стоит пробел
Теперь обещанный пример, когда пробел ключевая фигура. Задача найти первую позицию с пробелом в строке . Пишем например так:
FIND ' ' IN '12345 Text' MATCH OFFSET lv_offset MATCH LENGTH lv_length.
В результате в lv_offset у нас будет 0, а не ожидаемое 5. Почему? Все потому же - ' ' сжался до пустого места, а пустое место у нас где угодно, а первое пустое место в начале строки. Оба первых пункта из решения выше нам не подойдут здесь, только 3ий:
FIND ` ` IN '12345 Text' MATCH OFFSET lv_offset MATCH LENGTH lv_length. 






среда, 25 апреля 2012 г.

Ручное изменение таблиц

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

Для этой цели существует несколько недокументированных возможностей.

  1. Транзакция SE16N. После запуска до выбора данных в окне команд нужно ввести "&sap_edit" (без кавычек), нажать Enter, после чего запустить выборку. При этом таблица откроется и в строке команд будут доступны команды создания/удаления строк и поля будут доступны на изменения. Но в последних версиях эту возможность пропатчили и она не работает. 
  2. Если п.1, не работает, то можно попробовать вместо SE16N запускать транзакцию UASE16N и выполнять ту же последовательность действий. Но эта транзакция может быть объявлена как устаревшая, о чем будет соответствующее сообщение при запуске, и использовать ее не получится.
  3. Если вышеперечисленные способы не работают, можно попробовать в транзакции SE37 запустить ФМ SE16N_INTERFACE, указав ему в параметре I_TAB имя таблицы, а в параметре I_EDIT значение 'X'. Остальное можно оставить по умолчанию. В результате получим тоже окно для редактирования, что и в SE16N с &SAP_EDIT.

понедельник, 23 апреля 2012 г.

Связь бонусных соглашений и условий

Заголовки условий хранятся в таблице KONH. Уникальный номер условия KONH-KNUMH.
Соглашения хранятся в таблице KONA. Уникальный номер соглашения KONA-KNUMA.

Получить номер соглашения по номеру условия просто - он хранится в одном из полей  KONH-KNUMA_* (например KNUMA_BO).

Получить все номера условий для заданного соглашения, конечно, можно, выполнив SELECT по  KONH-KNUMA_*, но это очень медленно, потому что индекса по этим полям в KONH нет.
В принципе для этого существует  индекcная таблица KONAIND, но судя по тому стандартному коду, который находится поиском, она используется только в случае, если тип соглашения (KONA-ABTYP) равен "C" (Мероприятие по стимулированию продаж).

Для бонусных соглашений правильным способом получения всех условий  является использование ФМ SD_BONUS_READ. Если же "копнуть" глубже, то поиск условий в этом ФМ производится по таблицам KOTE*,  в которых есть поля KNUMA и KNUMH и, как правило, есть индекс по KNUMA.

Особенности вывода PDF в Web Dynpro

При использовании Web Dynpro компонента INTERACTIVE_FORM для вывода PDF прямо в HTML страницу могут возникнуть некоторые проблемы.

Например, если на представлении помимо компонента INTERACTIVE_FORM присутствуют другие элементы, которые должны реагировать на действия пользователя - типичный вариант, кнопка Назад - то реагировать они не будут. Происходит это похоже потому, что используемый для вывода Adobe Reader перехватывает эти события и до обработчиков они не доходят. Возможно, это сделано для работы с интерактивными PDF-формами. Не знаю, пока с ними не сталкивался.
Но если у Вас обычная форма, которую нужно просто показать пользователю, то решением будет просто снятие флага Enabled у компонента INTERACTIVE_FORM.

Вторая тонкость заключается в способе формирования PDF. Компонент позволяет 2 варианта. В первом случае вы задаете в свойстве templateSource имя шаблона,  а в свойство dataSource "байндите" данные. Очень похоже на то, как  PDF выводится через свой сгенерированный ФМ при работе через SAP GUI. Но при выводе этим способом уже неоднократно сталкивались с тем, что при этом формируемый  на сайте PDF либо вообще не содержит текста, либо кракозябры вместо него. Возможно проблема в отсутствии каких-то шрифтов или прописанных путей до них. Пока не нашли в чем дело. Да и не искали особо. Потому что есть более надежный и простой способ - сгенерировать PDF как обычно через ФМ, но не выводить его, а получить сформированный файл в виде XSTRING и присвоить свойству pdfSource компонента INTERACTIVE_FORM. Для получения файла в виде XSTRING необходимо при вызове ФМ FP_JOB_OPEN передать в параметре ie_outputparams установленные поля nodialog и getpdf. При этом вызов сгенерированного ФМ для формирования выходного документа в параметре /1bcdwb/formoutput вернет в поле pdf созданный файл.

SAP GUI 7.2 Patch 11 for Windows

SAP выпустил очередное обновление своего GUI 7.2 для Windows. Значимой вещью 11го патча является исправление проблемы с Adobe LiveCycle Designer - после установки толи 9, толи 10  патча в дизайнере PDF пропадало главное меню. Судя по ноте, это проявлялось только при наличии Microsoft Office 2010. Это исправлено. Скачать можно с официального сайта или  отсюда .

понедельник, 9 апреля 2012 г.

О чем это?

Когда будет свободное время и мне будет не лень, то здесь будут появляться записи о тонкостях программирования на ABAP. Скорее даже обо всем, с чем приходится сталкиваться абаперу в процессе свой профессиональной жизнедеятельности - в том числе PDF, MS Office, Web, SQL etc.