Страница 1 из 2

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

Добавлено: 26 июн 2013, 17:54
Siyet
Здравствуйте!

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

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

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

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

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

Добавлено: 26 июн 2013, 18:30
Siyet
По первой задаче:

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

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

Добавлено: 27 июн 2013, 08:17
Siyet
Продолжим...

Сначала отступление.
Мы собираемся править код. Для этого разработчики 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, а там уже все красиво :) .

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

Добавлено: 27 июн 2013, 09:52
merkushov
У вас хорошо получается.

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

Добавлено: 27 июн 2013, 12:17
Siyet
Спасибо!
Итак, продолжим...

Копируем /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,
                );            
            }
Проверяем и радуемся :)

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

Добавлено: 27 июн 2013, 12:34
Siyet
Заметка: если Вы вздумали что-нибудь поправить в компаниях напрямую в базе, Вам нужно удалить содержимое папки /otrs/var/tmp/CacheFileStorable/CustomerCompany_CustomerCompanyList, тогда изменения отобразятся в web-интерфейсе.

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

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

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

Добавлено: 27 июн 2013, 14:21
mukexa
От себя добавлю.
Поправим /otrs/Kernel/Modules/AdminCustomerCompany.pm, предварительно копируем в /otrs/Custom/Kernel/Modules/AdminCustomerCompany.pm.
Я то уже понимаю, что править нужно именно "Custom/Kernel/Modules/AdminCustomerCompany.pm", но прочитав Вашу строку месяц назад взялся бы править оригинал:
Поправим /otrs/Kernel/Modules/AdminCustomerCompany.pm

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

Добавлено: 27 июн 2013, 14:29
Siyet
За комментарии спасибо сейчас поправлю.

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

В файле 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). Честно говоря, я потратил почти час пока додумался до последнего :(

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

Добавлено: 27 июн 2013, 14:34
merkushov
У метода BuildSelection() есть параметр PossibleNone. По дефолту он выключен, но если включить то в списке появится возможность выбрать "пустое значение".

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

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

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

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

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

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

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

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

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

Добавлено: 27 июн 2013, 19:55
mukexa
alexus писал(а):
Siyet писал(а):В файле /Kernel/Modules/AdminCustomerCompany.pm ищем место где вносили изменения.
В этом файле не надо вносить никаких изменений. Только в /otrs/Custom/Kernel/Modules/AdminCustomerCompany.pm
Так он и не говорил об
/otrs/Kernel/Modules/AdminCustomerCompany.pm
может быть и
/Custom/Kernel/Modules/AdminCustomerCompany.pm ;)
тут нужно понимать самому где править. Потому и не старался писать длинных путей, только путает.

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

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

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

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

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

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

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

Добавлено: 28 июн 2013, 14:46
mukexa
Siyet писал(а):Слушайте, забадали уже, все я понимаю, просто забываю каждый раз об этом упоминать.
Без обид, просто если бы я реально прочитал это впервые попав на форум... Как работник тех.поддержки всегда ставлю себя на место клиента, Вы уж извините ) Хотя сам порой не прав, но кого то легче обсуждать чем себя )
С удовольствием читаю Ваши посты. Удачи!

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

Добавлено: 28 июн 2013, 15:01
Siyet
С автокомпиляцией пока повременим. Займемся областями, и городами компаний.

Создаем в базе в таблице 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 взять, по-моему, так называется. Это классификатор адресов, который можно взять на сайте одного из министерств России (давно было не помню уже какое именно).

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

Добавлено: 28 июн 2013, 15:11
Siyet
Без обид, просто если бы я реально прочитал это впервые попав на форум... Как работник тех.поддержки всегда ставлю себя на место клиента, Вы уж извините ) Хотя сам порой не прав, но кого то легче обсуждать чем себя )
Я не Вам.

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

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

Копируем файл 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), а то много повторяющегося кода.

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

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

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

Добавлено: 30 июн 2013, 13:33
Siyet
Siyet писал(а):... Критику принял...

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

Добавлено: 30 июн 2013, 14:24
Siyet
Как я уже говорил, в файле 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,
      );
}

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

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

Итак приступим:
Берем файл 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,
        },
    };

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

Добавлено: 01 июл 2013, 16:31
Siyet
Теперь русифицируем:
В файле 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'} = 'Не добавлено ни одной области';
Если я забыл что-то русифицировать, укажите что именно.
Стоит отметить, что я не сделал кэширование списка городов, что не совсем красиво, так что как-нибудь доделаю.

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

Добавлено: 01 июл 2013, 17:14
Siyet
Теперь по аналогии сделаем области:
Берем из архива на скрепке файл 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 сущностей наподобии городов и областей, но они специфичны для деятельности моей компании, поэтому здесь я их описывать не буду, но какое-то время я писать ничего нового не смогу, не теряйте меня, постараюсь поскорее продолжить повествование. ;)