Иерархия компаний и поля с автокомпиляцией

Модератор: ykolesnikov

Siyet
OTRS Новобранец
Сообщения: 62
Зарегистрирован: 26 июн 2013, 16:56

Иерархия компаний и поля с автокомпиляцией

Сообщение Siyet » 26 июн 2013, 17:54

Здравствуйте!

Собираюсь реализовать иерархию компаний и поля с автокомпиляцией. Прошерстил форум, погуглил и так ничего не нашел. Так что буду делать сам, а по пути писать как я это делаю. Буду рад если кто поможет, если не по иерархии, то хотя бы по автокомпиляции.

В моей компании работают со всей Россией.

Есть задача:
Реализовать иерархию компаний. Т. е. реализовать возможность указания компании вышестоящей компании (простите за туфтулогию :D ).

И еще одна связанная задача:
Реализовать возможность указания в компании принадлежность к округам и районам России. Реализовать соответствующую отчетность.
OTRS 3.2.8, Ubuntu 12.04, Apache, PostgreSQL

Siyet
OTRS Новобранец
Сообщения: 62
Зарегистрирован: 26 июн 2013, 16:56

Re: Иерархия компаний и поля с автокомпиляцией

Сообщение Siyet » 26 июн 2013, 18:30

По первой задаче:

Чтобы реализовать иерархию нужно компаниям добавить поле "parent_id" (id вышестоящей организации).
У меня OTRS использует БД PostgreSQL.
Добавляем поле parent_id типа аналогичного типу поля customer_id.
Создаем внешний ключ от поля parent_id к полю customer_id. Причем ONDELETE/ONUPDATE я установил CASCADE, если не прав поправьте, я в связях не силен.
Далее будем править конфиг, но об этом завтра :)
OTRS 3.2.8, Ubuntu 12.04, Apache, PostgreSQL

Siyet
OTRS Новобранец
Сообщения: 62
Зарегистрирован: 26 июн 2013, 16:56

Re: Иерархия компаний и поля с автокомпиляцией

Сообщение Siyet » 27 июн 2013, 08:17

Продолжим...

Сначала отступление.
Мы собираемся править код. Для этого разработчики OTRS рекомендуют копировать "родные" файлы в папку otrs/Custom с сохранением вложенностей.
Требуется это для того, чтобы, во-первых, если что сломается и запутается, не нужно переставлять систему, можно будет просто почистить папку otrs/Custom. Во-вторых, все Ваши изменения не пострадают при обновлении системы.

Да, кстати, Perl я не знаю, поэтому, если я что-то не правильно называю, прошу ткнуть меня носом :)

В нашем случае мы править файл не будем, а добавим конфигурацию в файл /otrs/Config.pm. Ищем в файле комментарий:

Код: Выделить всё

    # ---------------------------------------------------- #
    # insert your own config settings "here"               #
    # config settings taken from Kernel/Config/Defaults.pm #
    # ---------------------------------------------------- #
После него вставляем следующее:

Код: Выделить всё

    $Self->{CustomerCompany} = {
        Params => {
            Table => 'customer_company',

            CaseSensitive => 0,
        },

        CustomerCompanyKey => 'customer_id',
        CustomerCompanyValid => 'valid_id',
        CustomerCompanyListFields => [ 'customer_id', 'name' ],
        CustomerCompanySearchFields => ['customer_id', 'name'],
        CustomerCompanySearchPrefix => '',
        CustomerCompanySearchSuffix => '*',
        CustomerCompanySearchListLimit => 250,
        CacheTTL => 60 * 60 * 24, # use 0 to turn off cache

        Map => [
            # var, frontend, storage, shown (1=always,2=lite), required, storage-type, http-link, readonly
            [ 'CustomerID', 'CustomerID', 'customer_id', 0, 1, 'var', '', 0 ],
            [ 'CustomerCompanyName', 'Company', 'name', 1, 1, 'var', '', 0 ],
            [ 'CustomerCompanyStreet', 'Street', 'street', 1, 0, 'var', '', 0 ],
            [ 'CustomerCompanyZIP', 'Zip', 'zip', 1, 0, 'var', '', 0 ],
            [ 'CustomerCompanyCity', 'City', 'city', 1, 0, 'var', '', 0 ],
            [ 'CustomerCompanyCountry', 'Country', 'country', 1, 0, 'var', '', 0 ],
            [ 'CustomerCompanyParent', 'Parent id', 'parent_id', 1, 0, 'var', '', 0 ],
            [ 'CustomerCompanyPhone', 'Phone', 'phone', 1, 0, 'var', '', 0 ],
            [ 'CustomerCompanyURL', 'URL', 'url', 1, 0, 'var', '$Data{"CustomerCompanyURL"}', 0 ],
            [ 'CustomerCompanyComment', 'Comment', 'comments', 1, 0, 'var', '', 0 ],
            [ 'ValidID', 'Valid', 'valid_id', 0, 1, 'int', '', 0 ],
        ],
    };
Комментарии я удалил из кода ибо слишком большое сообщение форумное получается :(
Таким образом, мы переопределили настройку CustomerCompany.
Теперь можем заглянуть в админку /otrs/index.pl?Action=AdminCustomerCompany;Subaction=Add (это URL, вначале добавьте адрес сервера). Видим, что после поля "Страна" добавилось поле "Parent id". Пора русифицировать сию пакость :) .
Для этого скопируем файл otrs/Kernel/Language/xx_Custom.pm в ту же папку, переименовав в ru_Custom.pm.
Внутри файла находим:

Код: Выделить всё

package Kernel::Language::xx_Custom;
Исправляем на:

Код: Выделить всё

package Kernel::Language::ru_Custom;
Удалим (закомментируем) строки:

Код: Выделить всё

$Self->{Translation}->{'Lock'}   = 'Lala';
$Self->{Translation}->{'Unlock'} = 'Lulu';
Вместо них добавим строку:

Код: Выделить всё

$Self->{Translation}->{'Parent id'} = 'Вышестоящая организация';
Вернемся в админку /otrs/index.pl?Action=AdminCustomerCompany;Subaction=Add, а там уже все красиво :) .
Последний раз редактировалось Siyet 27 июн 2013, 14:54, всего редактировалось 1 раз.
OTRS 3.2.8, Ubuntu 12.04, Apache, PostgreSQL

merkushov
OTRS Бывалый
Сообщения: 310
Зарегистрирован: 25 окт 2012, 15:06
Откуда: Воронеж
Поблагодарили: 2 раза

Re: Иерархия компаний и поля с автокомпиляцией

Сообщение merkushov » 27 июн 2013, 09:52

У вас хорошо получается.
Меркушов Виктор, perl программист

Siyet
OTRS Новобранец
Сообщения: 62
Зарегистрирован: 26 июн 2013, 16:56

Re: Иерархия компаний и поля с автокомпиляцией

Сообщение Siyet » 27 июн 2013, 12:17

Спасибо!
Итак, продолжим...

Копируем /otrs/Kernel/Modules/AdminCustomerCompany.pm, в /otrs/Custom/Kernel/Modules/. Теперь работаем со скопированным файлом.
Ищем функцию sub _Edit. У меня 260 строка.
Внутри ищем цикл for my $Entry. У меня 297 строка.
Далее перед строчками:

Код: Выделить всё

            else {
                $Param{Value} = $Param{ $Entry->[0] } || '';
            }
Добавляем еще один elseif:

Код: Выделить всё

            elsif ( $Entry->[0] =~ /^CustomerCompanyParent/i ) {
                my $OptionRequired = '';
                if ( $Entry->[4] ) {
                    $OptionRequired = 'Validate_Required';
                }

                # build Parent string

                $Block = 'Option';
                $Param{Option} = $Self->{LayoutObject}->BuildSelection(
                    Data  => { $Self->{CustomerCompanyObject}->CustomerCompanyList(), },
                    Name  => $Entry->[0],
                    Class => $OptionRequired . ' ' .
                        ( $Param{Errors}->{ $Entry->[0] . 'Invalid' } || '' ),
                    SelectedID => defined( $Param{ $Entry->[0] } ) ? $Param{ $Entry->[0] } : 1,
                );            
            }
Проверяем и радуемся :)
Последний раз редактировалось Siyet 27 июн 2013, 14:57, всего редактировалось 1 раз.
OTRS 3.2.8, Ubuntu 12.04, Apache, PostgreSQL

Siyet
OTRS Новобранец
Сообщения: 62
Зарегистрирован: 26 июн 2013, 16:56

Re: Иерархия компаний и поля с автокомпиляцией

Сообщение Siyet » 27 июн 2013, 12:34

Заметка: если Вы вздумали что-нибудь поправить в компаниях напрямую в базе, Вам нужно удалить содержимое папки /otrs/var/tmp/CacheFileStorable/CustomerCompany_CustomerCompanyList, тогда изменения отобразятся в web-интерфейсе.
OTRS 3.2.8, Ubuntu 12.04, Apache, PostgreSQL

alexus
OTRS Гуру
Сообщения: 5192
Зарегистрирован: 20 сен 2010, 18:17
Откуда: Москва
Благодарил (а): 92 раза
Поблагодарили: 82 раза

Re: Иерархия компаний и поля с автокомпиляцией

Сообщение alexus » 27 июн 2013, 13:28

Siyet писал(а):В нашем случае править будем файл otrs/Kernel/Config/Defaults.pm. Копируем его в otrs/Custom/Kernel/.
Это неправильно!
Надо просто изменения вносить копипастом в файл Config.pm. Сначала читается Defaults.pm, а потом Config.pm, и из него берутся измененные параметры. Config.pm сохранаяется при резервном копировании и не заменяется при обновлении.
Прочитайте документацию не по диагонали, а более внимательно. Вы делаете интересные вещи, и мне просто жаль будет напрасных Ваших трудов. Любой более-менее опытный админ OTRS никогда в жизни не догадается, что измененный Defaults.pm засунули в Custom. Он тупо внесет изменения в Config.pm в части CustomerMap и ваша доработка завалится.
С уважением,
Алексей Юсов

Prod: OTRS CE ITSM 6.0.28 on CentOS 7 Apache 2.4 MariaDB 10.4.13 + Radiant Customer Portal

Radiant System OTRS Intergrator RU
Группа OTRS Community в Teleram
Хотите внедрить OTRS? Спросите меня как!

mukexa
OTRS Новобранец
Сообщения: 148
Зарегистрирован: 30 апр 2013, 19:08
Откуда: Украина, Киев.
Поблагодарили: 1 раз

Re: Иерархия компаний и поля с автокомпиляцией

Сообщение mukexa » 27 июн 2013, 14:21

От себя добавлю.
Поправим /otrs/Kernel/Modules/AdminCustomerCompany.pm, предварительно копируем в /otrs/Custom/Kernel/Modules/AdminCustomerCompany.pm.
Я то уже понимаю, что править нужно именно "Custom/Kernel/Modules/AdminCustomerCompany.pm", но прочитав Вашу строку месяц назад взялся бы править оригинал:
Поправим /otrs/Kernel/Modules/AdminCustomerCompany.pm
OTRS 5s, Ubuntu 12.04

Siyet
OTRS Новобранец
Сообщения: 62
Зарегистрирован: 26 июн 2013, 16:56

Re: Иерархия компаний и поля с автокомпиляцией

Сообщение Siyet » 27 июн 2013, 14:29

За комментарии спасибо сейчас поправлю.

Пообедав, понял, что не хватает пустого поля выбора.

В файле Custom/Kernel/Modules/AdminCustomerCompany.pm ищем место где вносили изменения.
Строку:

Код: Выделить всё

Data  => { $Self->{CustomerCompanyObject}->CustomerCompanyList(), },
Заменяем на:

Код: Выделить всё

                    Data  => { 
                            'NULL' => '-',
                            $Self->{CustomerCompanyObject}->CustomerCompanyList(),
                        },
К сожалению, разработчиками не было предусмотрено запись в БД значения NULL (ну или я не нашел этого). Поэтому поправим файл Custom/Kernel/System/CustomerCompany.pm. Не забудем скопировать оригинал в папку Custom, а потом уже правим.

В функции CustomerCompanyAdd находим цикл for my $Entry. У меня это строка 215.
Внутри находим блок else. Заменяем его на:

Код: Выделить всё

            if ( $Self->{DBObject}->Quote( $Param{ $Entry->[0] } ) =~ /^NULL/i ) {
                $SQL .= " NULL"; 
            }
            else {
                $SQL .= " '" . $Self->{DBObject}->Quote( $Param{ $Entry->[0] } ) . "'";
            }
Теперь нужно перезапустить сервер (в моем случае Apache). Честно говоря, я потратил почти час пока додумался до последнего :(
Последний раз редактировалось Siyet 28 июн 2013, 14:21, всего редактировалось 1 раз.
OTRS 3.2.8, Ubuntu 12.04, Apache, PostgreSQL

merkushov
OTRS Бывалый
Сообщения: 310
Зарегистрирован: 25 окт 2012, 15:06
Откуда: Воронеж
Поблагодарили: 2 раза

Re: Иерархия компаний и поля с автокомпиляцией

Сообщение merkushov » 27 июн 2013, 14:34

У метода BuildSelection() есть параметр PossibleNone. По дефолту он выключен, но если включить то в списке появится возможность выбрать "пустое значение".
Меркушов Виктор, perl программист

Siyet
OTRS Новобранец
Сообщения: 62
Зарегистрирован: 26 июн 2013, 16:56

Re: Иерархия компаний и поля с автокомпиляцией

Сообщение Siyet » 27 июн 2013, 15:06

Спасибо за дельный совет, печально, что я не заметил сразу :( . Сейчас переправлю.

А вот и не поправлю :(
Эффект от PossibleNone => 1 такой же как и от

Код: Выделить всё

                    Data  => { 
                            '' => '-',
                            $Self->{CustomerCompanyObject}->CustomerCompanyList(),
                        },
В этом случае в таблицу вписывается значение '', а для PostgreSQL'я это невозможно для foreign key поля. Нужно передавать именно NULL причем без апострофов и кавычек. Возможно для MySQL подойдет решение, проверить времени, возможности и желания увы нет.

Еще одна заметка:
Если после рестарта Apache OTRS упал, спасет Вас рестарт Cron'a.
OTRS 3.2.8, Ubuntu 12.04, Apache, PostgreSQL

alexus
OTRS Гуру
Сообщения: 5192
Зарегистрирован: 20 сен 2010, 18:17
Откуда: Москва
Благодарил (а): 92 раза
Поблагодарили: 82 раза

Re: Иерархия компаний и поля с автокомпиляцией

Сообщение alexus » 27 июн 2013, 19:27

Siyet писал(а):В файле /Kernel/Modules/AdminCustomerCompany.pm ищем место где вносили изменения.
В этом файле не надо вносить никаких изменений. Только в /otrs/Custom/Kernel/Modules/AdminCustomerCompany.pm
Siyet писал(а):Если после рестарта Apache OTRS упал, спасет Вас рестарт Cron'a.
А при чем тут крон? И что значит "OTRS упал"?
С уважением,
Алексей Юсов

Prod: OTRS CE ITSM 6.0.28 on CentOS 7 Apache 2.4 MariaDB 10.4.13 + Radiant Customer Portal

Radiant System OTRS Intergrator RU
Группа OTRS Community в Teleram
Хотите внедрить OTRS? Спросите меня как!

mukexa
OTRS Новобранец
Сообщения: 148
Зарегистрирован: 30 апр 2013, 19:08
Откуда: Украина, Киев.
Поблагодарили: 1 раз

Re: Иерархия компаний и поля с автокомпиляцией

Сообщение mukexa » 27 июн 2013, 19:55

alexus писал(а):
Siyet писал(а):В файле /Kernel/Modules/AdminCustomerCompany.pm ищем место где вносили изменения.
В этом файле не надо вносить никаких изменений. Только в /otrs/Custom/Kernel/Modules/AdminCustomerCompany.pm
Так он и не говорил об
/otrs/Kernel/Modules/AdminCustomerCompany.pm
может быть и
/Custom/Kernel/Modules/AdminCustomerCompany.pm ;)
тут нужно понимать самому где править. Потому и не старался писать длинных путей, только путает.
OTRS 5s, Ubuntu 12.04

alexus
OTRS Гуру
Сообщения: 5192
Зарегистрирован: 20 сен 2010, 18:17
Откуда: Москва
Благодарил (а): 92 раза
Поблагодарили: 82 раза

Re: Иерархия компаний и поля с автокомпиляцией

Сообщение alexus » 28 июн 2013, 00:31

Я, конечно, согласен, что самому надо понимать. Но автор уже предлагал ранее Defaults.pm перенести в Custom и там его править. А это свидетельствует о неверном понимании автора. Люди без понимания посмотрят и решат, что раз автор пишет так да еще и в разделе Разработка, то уж точно так и надо делать.
Если пишете длинный путь, тогда пишите правильный. Или вообще без пути пишите, чтобы читатель хотя бы "включал голову", что и где надо хранить и править.
С уважением,
Алексей Юсов

Prod: OTRS CE ITSM 6.0.28 on CentOS 7 Apache 2.4 MariaDB 10.4.13 + Radiant Customer Portal

Radiant System OTRS Intergrator RU
Группа OTRS Community в Teleram
Хотите внедрить OTRS? Спросите меня как!

Siyet
OTRS Новобранец
Сообщения: 62
Зарегистрирован: 26 июн 2013, 16:56

Re: Иерархия компаний и поля с автокомпиляцией

Сообщение Siyet » 28 июн 2013, 14:22

Слушайте, забадали уже, все я понимаю, просто забываю каждый раз об этом упоминать. Критику принял, поправил.

OTRS упал - если при переходе по ссылке /otrs/index.pl видим ошибку, прошу прощения за кривой сленг.

Каким образом, помог restart cron'a я не знаю. Перезапустил Apache, увидел ошибку, перезапустил Cron, ошибки нет, все работает. Никаких других телодвижений не совершал, потому сделал такую заметку.
OTRS 3.2.8, Ubuntu 12.04, Apache, PostgreSQL

mukexa
OTRS Новобранец
Сообщения: 148
Зарегистрирован: 30 апр 2013, 19:08
Откуда: Украина, Киев.
Поблагодарили: 1 раз

Re: Иерархия компаний и поля с автокомпиляцией

Сообщение mukexa » 28 июн 2013, 14:46

Siyet писал(а):Слушайте, забадали уже, все я понимаю, просто забываю каждый раз об этом упоминать.
Без обид, просто если бы я реально прочитал это впервые попав на форум... Как работник тех.поддержки всегда ставлю себя на место клиента, Вы уж извините ) Хотя сам порой не прав, но кого то легче обсуждать чем себя )
С удовольствием читаю Ваши посты. Удачи!
OTRS 5s, Ubuntu 12.04

Siyet
OTRS Новобранец
Сообщения: 62
Зарегистрирован: 26 июн 2013, 16:56

Re: Иерархия компаний и поля с автокомпиляцией

Сообщение Siyet » 28 июн 2013, 15:01

С автокомпиляцией пока повременим. Займемся областями, и городами компаний.

Создаем в базе в таблице customer_company, следующие таблицы:

1. city
- id (integer)
- name (character varying)
- region_id (integer)

2. region
- id (integer)
- name (character varying)

Добавляем внешний ключ для таблицы city поля region_id, ONDELETE CASCADE, ONUPDATE CASCADE.
Теперь нужно настроить автоматическое заполнение поля id (автоинкремент), чтобы при создании новой записи ей присваивался id +1 к последнему значению.
Подробно описывать процесс создания таблиц смысла не вижу, у всех разные БД, а у меня PostgreSQL, которая не так уж и распространена.
Далее импортируем данные из файлов во вложении.

Теперь правим файл Config.pm:
Ищем строку:

Код: Выделить всё

[ 'CustomerCompanyCity',    'City',       'city',        1, 0, 'var', '', 0 ],
Заменяем на:

Код: Выделить всё

            [ 'CustomerCompanyCity',    'City',       'city_id',     1, 1, 'int', '', 0 ],
            [ 'CustomerCompanyRegion',  'Region',     'region_id',   1, 1, 'int', '', 0 ],
Теперь русифицируем "область". Правим, созданный ранее, файл otrs/Kernel/Language/ru_Custom.pm
Ищем комментарий:

Код: Выделить всё

    # own translations
После него добавляем:

Код: Выделить всё

    $Self->{Translation}->{'Region'} = 'Область';
Города и области еще можно из CLADR'a взять, по-моему, так называется. Это классификатор адресов, который можно взять на сайте одного из министерств России (давно было не помню уже какое именно).
Вложения
Data.7z
(18.29 КБ) 602 скачивания
Последний раз редактировалось Siyet 05 июл 2013, 10:59, всего редактировалось 2 раза.
OTRS 3.2.8, Ubuntu 12.04, Apache, PostgreSQL

Siyet
OTRS Новобранец
Сообщения: 62
Зарегистрирован: 26 июн 2013, 16:56

Re: Иерархия компаний и поля с автокомпиляцией

Сообщение Siyet » 28 июн 2013, 15:11

Без обид, просто если бы я реально прочитал это впервые попав на форум... Как работник тех.поддержки всегда ставлю себя на место клиента, Вы уж извините ) Хотя сам порой не прав, но кого то легче обсуждать чем себя )
Я не Вам.
OTRS 3.2.8, Ubuntu 12.04, Apache, PostgreSQL

Siyet
OTRS Новобранец
Сообщения: 62
Зарегистрирован: 26 июн 2013, 16:56

Re: Иерархия компаний и поля с автокомпиляцией

Сообщение Siyet » 28 июн 2013, 17:05

Далее...
В создании/редактировании компании нам нужно сделать поля "Город" и "Область" ниспадающими списками, в которые подгружать данные из созданных нами соответствующих таблиц.
Подумав, покавырявшись, предлагаю сделать сие следующим образом:

Копируем файл otrs/Kernel/Service/ReferenceData.pm в otrs/Custom/Kernel/Service/. Правим скопированный файл:
Ищем строку

Код: Выделить всё

sub new {
Внутри ищем цикл:

Код: Выделить всё

    for my $Object (qw(ConfigObject LogObject EncodeObject MainObject)) {
Заменяем на строку:

Код: Выделить всё

    for my $Object (qw(DBObject ConfigObject LogObject EncodeObject MainObject)) {
Далее ищем строку с короткой записью: Перед ней вставляем код выдергивания из базы данных городов и областей и создания соответствующих List'ов:

Код: Выделить всё

sub CityList {
    my ( $Self, %Param ) = @_;

    # get list from database
    return if !$Self->{DBObject}->Prepare( SQL => 'SELECT id, name FROM city' );

    # fetch the result
    my %Data;
    while ( my @Row = $Self->{DBObject}->FetchrowArray() ) {
        $Data{ $Row[0] } = $Row[1];
    }

    return %Data;
}

sub RegionList {
    my ( $Self, %Param ) = @_;

    # get list from database
    return if !$Self->{DBObject}->Prepare( SQL => 'SELECT id, name FROM region' );

    # fetch the result
    my %Data;
    while ( my @Row = $Self->{DBObject}->FetchrowArray() ) {
        $Data{ $Row[0] } = $Row[1];
    }

    return %Data;
}
Теперь поправим ранее созданный файл otrs/Custom/Kernel/Modules/AdminCustomerCompany.pm
Ищем добавленный нами ранее код, обрабатывающий случай с полем "Вышестоящая организация":

Код: Выделить всё

            elsif ( $Entry->[0] =~ /^CustomerCompanyParent/i ) {

            ... (весь код не влез из-за ограничений по количеству символов сообщения)

            }
После него вставляем:

Код: Выделить всё

            elsif ( $Entry->[0] =~ /^CustomerCompanyCity/i ) {
                my $OptionRequired = '';
                if ( $Entry->[4] ) {
                    $OptionRequired = 'Validate_Required';
                }

                # build City string
                $Block = 'Option';
                $Param{Option} = $Self->{LayoutObject}->BuildSelection(
                    Data  => { $Self->{ReferenceDataObject}->CityList(), },
                    Name  => $Entry->[0],
                    Class => $OptionRequired . ' ' .
                        ( $Param{Errors}->{ $Entry->[0] . 'Invalid' } || '' ),
                    SelectedID => defined( $Param{ $Entry->[0] } ) ? $Param{ $Entry->[0] } : 1,
                );            
            }
            elsif ( $Entry->[0] =~ /^CustomerCompanyRegion/i ) {
                my $OptionRequired = '';
                if ( $Entry->[4] ) {
                    $OptionRequired = 'Validate_Required';
                }

                # build City string
                $Block = 'Option';
                $Param{Option} = $Self->{LayoutObject}->BuildSelection(
                    Data  => { $Self->{ReferenceDataObject}->RegionList(), },
                    Name  => $Entry->[0],
                    Class => $OptionRequired . ' ' .
                        ( $Param{Errors}->{ $Entry->[0] . 'Invalid' } || '' ),
                    SelectedID => defined( $Param{ $Entry->[0] } ) ? $Param{ $Entry->[0] } : 1,
                );            
            }
Готово!

Буду рад, если знающие люди подскажут как ПРАВИЛЬНО и КРАСИВО объединить четыре схожих elsif (ValidID, CustomCompanyParent, CustomerCompanyCity и CustomCompanyRegion), а то много повторяющегося кода.
Последний раз редактировалось Siyet 30 июн 2013, 13:35, всего редактировалось 1 раз.
OTRS 3.2.8, Ubuntu 12.04, Apache, PostgreSQL

alexus
OTRS Гуру
Сообщения: 5192
Зарегистрирован: 20 сен 2010, 18:17
Откуда: Москва
Благодарил (а): 92 раза
Поблагодарили: 82 раза

Re: Иерархия компаний и поля с автокомпиляцией

Сообщение alexus » 28 июн 2013, 18:56

Siyet писал(а):Слушайте, забадали уже, все я понимаю,
Если Вы так будете реагировать на советы, то желания у людей Вам отвечать это не прибавит.
С уважением,
Алексей Юсов

Prod: OTRS CE ITSM 6.0.28 on CentOS 7 Apache 2.4 MariaDB 10.4.13 + Radiant Customer Portal

Radiant System OTRS Intergrator RU
Группа OTRS Community в Teleram
Хотите внедрить OTRS? Спросите меня как!

Siyet
OTRS Новобранец
Сообщения: 62
Зарегистрирован: 26 июн 2013, 16:56

Re: Иерархия компаний и поля с автокомпиляцией

Сообщение Siyet » 30 июн 2013, 13:33

Siyet писал(а):... Критику принял...
OTRS 3.2.8, Ubuntu 12.04, Apache, PostgreSQL

Siyet
OTRS Новобранец
Сообщения: 62
Зарегистрирован: 26 июн 2013, 16:56

Re: Иерархия компаний и поля с автокомпиляцией

Сообщение Siyet » 30 июн 2013, 14:24

Как я уже говорил, в файле otrs/Custom/Kernel/Modules/AdminCustomerCompany.pm, у нас получилось много однообразного кода. Поправим это.
Следующие действия необязательны и требуются, наверное, лишь для "духовного равновесия" :D .
В файле otrs/Custom/Kernel/Modules/AdminCustomerCompany.pm ищем следующий код:

Код: Выделить всё

elsif ( $Entry->[0] =~ /^ValidID/i ) {
   my $OptionRequired = '';
   if ( $Entry->[4] ) {
      $OptionRequired = 'Validate_Required';
   }

   $Block = 'Option';
   $Param{Option} = $Self->{LayoutObject}->BuildSelection(
         Data  => { $Self->{ValidObject}->ValidList(), },
         Name  => $Entry->[0],
         Class => $OptionRequired . ' ' .
            ( $Param{Errors}->{ $Entry->[0] . 'Invalid' } || '' ),
         SelectedID => defined( $Param{ $Entry->[0] } ) ? $Param{ $Entry->[0] } : 1,
      );
}
elsif ( $Entry->[0] =~ /^CustomerCompanyParent/i ) {
   my $OptionRequired = '';
   if ( $Entry->[4] ) {
      $OptionRequired = 'Validate_Required';
   }
   $Block = 'Option';
   $Param{Option} = $Self->{LayoutObject}->BuildSelection(
         Data  => { 
               'NULL' => '-',
               $Self->{CustomerCompanyObject}->CustomerCompanyList(),
            },
         Name  => $Entry->[0],
         Class => $OptionRequired . ' ' .
            ( $Param{Errors}->{ $Entry->[0] . 'Invalid' } || '' ),
         SelectedID => defined( $Param{ $Entry->[0] } ) ? $Param{ $Entry->[0] } : 1,
      );
}
elsif ( $Entry->[0] =~ /^CustomerCompanyCity/i ) {
   my $OptionRequired = '';
   if ( $Entry->[4] ) {
      $OptionRequired = 'Validate_Required';
   }
   $Block = 'Option';
   $Param{Option} = $Self->{LayoutObject}->BuildSelection(
         Data  => { $Self->{ReferenceDataObject}->CityList(), },
         Name  => $Entry->[0],
         Class => $OptionRequired . ' ' .
            ( $Param{Errors}->{ $Entry->[0] . 'Invalid' } || '' ),
         SelectedID => defined( $Param{ $Entry->[0] } ) ? $Param{ $Entry->[0] } : 1,
      );            
}
elsif ( $Entry->[0] =~ /^CustomerCompanyRegion/i ) {
   my $OptionRequired = '';
   if ( $Entry->[4] ) {
      $OptionRequired = 'Validate_Required';
   }
   $Block = 'Option';
   $Param{Option} = $Self->{LayoutObject}->BuildSelection(
         Data  => { $Self->{ReferenceDataObject}->RegionList(), },
         Name  => $Entry->[0],
         Class => $OptionRequired . ' ' .
            ( $Param{Errors}->{ $Entry->[0] . 'Invalid' } || '' ),
         SelectedID => defined( $Param{ $Entry->[0] } ) ? $Param{ $Entry->[0] } : 1,
      );
}
Заменяем на:

Код: Выделить всё

elsif ( $Entry->[0] =~ /^ValidID/i || $Entry->[0] =~ /^CustomerCompanyParent/i || $Entry->[0] =~ /^CustomerCompanyCity/i 
      || $Entry->[0] =~ /^CustomerCompanyRegion/i ) {

   my $OptionRequired = '';
   my $ParamData = undef;
   if ( $Entry->[4] ) {
      $OptionRequired = 'Validate_Required';
   }
   if ( $Entry->[0] =~ /^ValidID/i ) { $ParamData = { $Self->{ValidObject}->ValidList(), } }
   elsif ( $Entry->[0] =~ /^CustomerCompanyParent/i ) { $ParamData = { 
         'NULL' => '-',
         $Self->{CustomerCompanyObject}->CustomerCompanyList(),
   } }
   elsif ( $Entry->[0] =~ /^CustomerCompanyCity/i ) { $ParamData = { $Self->{ReferenceDataObject}->CityList(), } }
   elsif ( $Entry->[0] =~ /^CustomerCompanyRegion/i ) { $ParamData = { $Self->{ReferenceDataObject}->RegionList(), } };

   $Block = 'Option';
   $Param{Option} = $Self->{LayoutObject}->BuildSelection(
         Data  => $ParamData,
         Name  => $Entry->[0],
         Class => $OptionRequired . ' ' .
            ( $Param{Errors}->{ $Entry->[0] . 'Invalid' } || '' ),
         SelectedID => defined( $Param{ $Entry->[0] } ) ? $Param{ $Entry->[0] } : 1,
      );
}
OTRS 3.2.8, Ubuntu 12.04, Apache, PostgreSQL

Siyet
OTRS Новобранец
Сообщения: 62
Зарегистрирован: 26 июн 2013, 16:56

Re: Иерархия компаний и поля с автокомпиляцией

Сообщение Siyet » 01 июл 2013, 16:08

Продолжим! :)
Мы добавили возможность указывать из ниспадающего списка город и область организации. Города и областя подгружали из файлов. Теперь сотворим интерфейс редактирования списков городов и областей из панели администратора.
Я почти уверен, что в предлагаемом мною коде есть недочеты, прошу поправить меня если заметите таковые.

Итак приступим:
Берем файл AdminCity.dtl из архива на скрепке. Кладем его в otrs/Custom/Kernel/Output/HTML/Standard/.
Это template с версткой интерфейса (view'шка);

Берем файл AdminCity.pm из того же архива на скрепке. Кладем его в otrs/Custom/Kernel/Modules/.
Это controller с логикой;

В файле otrs/Custom/Kernel/System/ReferenceData.pm:
После

Код: Выделить всё

sub CityList {
   ...
}
Добавляем это:

Код: Выделить всё

sub CityGet {
    my ( $Self, %Param ) = @_;

    # check needed stuff
    if ( !$Param{ID} ) {
        $Self->{LogObject}->Log( Priority => 'error', Message => 'Need ID!' );
        return;
    }

    # sql
    return if !$Self->{DBObject}->Prepare(
        SQL  => 'SELECT name, region_id FROM city WHERE id = ?',
        Bind => [ \$Param{ID} ],
    );
    my %City;
    while ( my @Data = $Self->{DBObject}->FetchrowArray() ) {
        %City = (
            ID         => $Param{ID},
            Name       => $Data[0],
            RegionID   => $Data[1],
        );
    }
    return %City;
}

sub CityUpdate {
    my ( $Self, %Param ) = @_;

    # check needed stuff
    for (qw(ID Name RegionID)) {
        if ( !$Param{$_} ) {
            $Self->{LogObject}->Log( Priority => 'error', Message => "Need $_!" );
            return;
        }
    }

    # sql
    return if !$Self->{DBObject}->Do(
        SQL => 'UPDATE city SET name = ?, region_id = ? WHERE id = ?',
        Bind => [
            \$Param{Name}, \$Param{RegionID}, \$Param{ID}
        ],
    );

    return 1;
}

sub CityAdd {
    my ( $Self, %Param ) = @_;

    # check needed stuff
    for (qw(Name RegionID)) {
        if ( !$Param{$_} ) {
            $Self->{LogObject}->Log( Priority => 'error', Message => "Need $_!" );
            return;
        }
    }

    # insert new city
    return if !$Self->{DBObject}->Do(
        SQL => 'INSERT INTO city (name, region_id)'
            . ' VALUES (?, ?)',
        Bind => [
            \$Param{Name}, \$Param{RegionID},
        ],
    );

    # get new city id
    return if !$Self->{DBObject}->Prepare(
        SQL  => 'SELECT id FROM city WHERE name = ?',
        Bind => [ \$Param{Name} ],
    );
    my $CityID;
    while ( my @Row = $Self->{DBObject}->FetchrowArray() ) {
        $CityID = $Row[0];
    }

    # log notice
    $Self->{LogObject}->Log(
        Priority => 'notice',
        Message  => "City: '$Param{Name}' ID: '$CityID' created successfully!",
    );

    return $CityID;
}
Это модель.

Теперь добавим новый пункт меню в админке. Для этого правим файл otrs/Kernel/Config.pm
После:

Код: Выделить всё

    # ---------------------------------------------------- #
    # insert your own config settings "here"               #
    # config settings taken from Kernel/Config/Defaults.pm #
    # ---------------------------------------------------- #
Вставляем:

Код: Выделить всё

    $Self->{'Frontend::Module'}->{AdminCity} = {
        Group        => ['admin'],
        Description  => 'Admin',
        Title        => 'City management',
        NavBarName   => 'Admin',
        NavBarModule => {
            Module => 'Kernel::Output::HTML::NavBarModuleAdmin',
            Name   => 'City management',
            Block  => 'System',
            Prio   => 1200,
        },
    };
Вложения
Files.7z
(2.91 КБ) 558 скачиваний
Последний раз редактировалось Siyet 01 июл 2013, 17:01, всего редактировалось 1 раз.
OTRS 3.2.8, Ubuntu 12.04, Apache, PostgreSQL

Siyet
OTRS Новобранец
Сообщения: 62
Зарегистрирован: 26 июн 2013, 16:56

Re: Иерархия компаний и поля с автокомпиляцией

Сообщение Siyet » 01 июл 2013, 16:31

Теперь русифицируем:
В файле otrs/Kernel/Language/re_Custom.pm после

Код: Выделить всё

    # own translations
добавляем

Код: Выделить всё

    $Self->{Translation}->{'City updated!'} = 'Сведения о городе обновлены!';
    $Self->{Translation}->{'City added!'} = 'Город добавлен!';
    $Self->{Translation}->{'City management'} = 'Управление списком городов';
    $Self->{Translation}->{'Add city'} = 'Добавить город';
    $Self->{Translation}->{'Add City'} = 'Добавление города';
    $Self->{Translation}->{'Edit City'} = 'Редактирование сведений о городе';
    $Self->{Translation}->{'NoCityDefined'} = 'Не добавлено ни одного города';
    $Self->{Translation}->{'Region updated!'} = 'Сведения об области обновлены!';
    $Self->{Translation}->{'Region added!'} = 'Область добавлена!';
    $Self->{Translation}->{'Region management'} = 'Управление списком областей';
    $Self->{Translation}->{'Add region'} = 'Добавить область';
    $Self->{Translation}->{'Add Region'} = 'Добавление области';
    $Self->{Translation}->{'Edit Region'} = 'Редактирование сведений об области';    
    $Self->{Translation}->{'NoRegionDefined'} = 'Не добавлено ни одной области';
Если я забыл что-то русифицировать, укажите что именно.
Стоит отметить, что я не сделал кэширование списка городов, что не совсем красиво, так что как-нибудь доделаю.
Последний раз редактировалось Siyet 01 июл 2013, 17:39, всего редактировалось 1 раз.
OTRS 3.2.8, Ubuntu 12.04, Apache, PostgreSQL

Siyet
OTRS Новобранец
Сообщения: 62
Зарегистрирован: 26 июн 2013, 16:56

Re: Иерархия компаний и поля с автокомпиляцией

Сообщение Siyet » 01 июл 2013, 17:14

Теперь по аналогии сделаем области:
Берем из архива на скрепке файл AdminRegion.dtl кладем в otrs/Custom/Kernel/Output/HTML/Standard/
Файл AdminRegion.pm из этого же архива кладем в otrs/Custom/Kernel/Modules/
Правим файл otrs/Custom/Kernel/System/ReferenceData.pm:
после

Код: Выделить всё

sub RegionList {
   ...   
}
добавляем

Код: Выделить всё

sub RegionGet {
    my ( $Self, %Param ) = @_;

    # check needed stuff
    if ( !$Param{ID} ) {
        $Self->{LogObject}->Log( Priority => 'error', Message => 'Need ID!' );
        return;
    }

    # sql
    return if !$Self->{DBObject}->Prepare(
        SQL  => 'SELECT name FROM region WHERE id = ?',
        Bind => [ \$Param{ID} ],
    );
    my %Region;
    while ( my @Data = $Self->{DBObject}->FetchrowArray() ) {
        %Region = (
            ID         => $Param{ID},
            Name       => $Data[0],
        );
    }
    return %Region;
}

sub RegionUpdate {
    my ( $Self, %Param ) = @_;

    # check needed stuff
    for (qw(ID Name)) {
        if ( !$Param{$_} ) {
            $Self->{LogObject}->Log( Priority => 'error', Message => "Need $_!" );
            return;
        }
    }

    # sql
    return if !$Self->{DBObject}->Do(
        SQL => 'UPDATE region SET name = ? WHERE id = ?',
        Bind => [
            \$Param{Name}, \$Param{ID}
        ],
    );

    return 1;
}

sub RegionAdd {
    my ( $Self, %Param ) = @_;

    # check needed stuff
    for (qw(Name)) {
        if ( !$Param{$_} ) {
            $Self->{LogObject}->Log( Priority => 'error', Message => "Need $_!" );
            return;
        }
    }

    # insert new region
    return if !$Self->{DBObject}->Do(
        SQL => 'INSERT INTO region (name)'
            . ' VALUES (?)',
        Bind => [
            \$Param{Name},
        ],
    );

    # get new region id
    return if !$Self->{DBObject}->Prepare(
        SQL  => 'SELECT id FROM region WHERE name = ?',
        Bind => [ \$Param{Name} ],
    );
    my $RegionID;
    while ( my @Row = $Self->{DBObject}->FetchrowArray() ) {
        $RegionID = $Row[0];
    }

    # log notice
    $Self->{LogObject}->Log(
        Priority => 'notice',
        Message  => "Region: '$Param{Name}' ID: '$RegionID' created successfully!",
    );

    return $RegionID;
}
Правим файл otrs/Kernel/Config.pm:
после

Код: Выделить всё

    # ---------------------------------------------------- #
    # insert your own config settings "here"               #
    # config settings taken from Kernel/Config/Defaults.pm #
    # ---------------------------------------------------- #
добавляем

Код: Выделить всё

    $Self->{'Frontend::Module'}->{AdminRegion} = {
        Group        => ['admin'],
        Description  => 'Admin',
        Title        => 'Region management',
        NavBarName   => 'Admin',
        NavBarModule => {
            Module => 'Kernel::Output::HTML::NavBarModuleAdmin',
            Name   => 'Region management',
            Block  => 'System',
            Prio   => 1400,
        },
    };
Готово! Теперь из админки можно редактировать списки городов и областей :)

P. S. некоторое время у меня уйдет на добавление еще 4 сущностей наподобии городов и областей, но они специфичны для деятельности моей компании, поэтому здесь я их описывать не буду, но какое-то время я писать ничего нового не смогу, не теряйте меня, постараюсь поскорее продолжить повествование. ;)
Вложения
Files1.7z
(2.75 КБ) 510 скачиваний
OTRS 3.2.8, Ubuntu 12.04, Apache, PostgreSQL

Ответить