Автоматическая нумерация в карточке

Версии: 3.x, 2.x.

Данная статья описывает, каким образом можно сделать так, чтобы при создании записи в разделе автоматически генерировалось значение в поле «Номер». То есть, чтобы нумерация производилась автоматически.

Создадим поле «Номер» на карточке раздела «Автомобили», который описан в отдельной статье. Для этого добавим на карточку поле «№» (оно не несет смысловой нагрузки, просто оно нужно нам для примера). Чтобы добавить поле на карточку, выполним два действия.

  • Добавим данную колонку в таблицу.

    ALTER TABLE iris_auto
       ADD COLUMN num character varying(15);
  • Изменим structure.xml и на карточку добавим созданное только что поле. Для этого в теге EDITCARD поместим в самое начало тег FIELD, описывающий поле num, а также атрибут layout.

    <EDITCARD name="c_Auto" caption="Автомобиль" width="600" height="120" layout="1, 2, 2, 1, 1, 2, 2">
      <ELEMENTS row_type="fk_column">
        <FIELD elem_type="text" caption="№" db_field="num" mandatory="yes" datatype="string" row_type="common"/>
        ....................
      </ELEMENTS>
    </EDITCARD>

Поле добавлено и теперь карточка выглядит так.

арточка нового раздела Автомобили в IRIS CRM

Теперь приступим к созданию автоматической генерации номера в поле «№». Для этого необходимо создать пользовательскую логику для карточки, которая будет выполнять следующие действия.

  1. При открытии карточки делать поле «№» недоступным для редактирования.
  2. При открытии карточки считывать текущее значение счетчика и помещать его в поле «№».
  3. После сохранения карточки произвести update вставленной записи, чтобы вставить правильное значение номера, а также увеличить счетчик, хранящий значение номера на 1.

Текущее значение счетчика нужно где-то хранить. Воспользуемся системной переменной. Для хранения системных переменных используется таблица iris_SystemVariable. При создании записи будем считывать из нее значение нужного параметра, а после сохранения карточки увеличивать его значение на 1. Создадим новый системный параметр «Тестовый номер». Можно добавить значение в справочник «Системные переменные» или выполнить такой скрипт.

INSERT INTO iris_SystemVariable (id, name, code, variabletypeid, intvalue) VALUES ('123d35fb-546b-485f-9596-bdf8e863c5c1', 'Тестовый номер', 'TestNum', '092a35fb-7e6b-482f-9596-3abde863c5c1', 0)

Теперь создадим два скрипта пользовательской логики в папке config/sections/Auto: клиентской — c_auto.js и серверной — c_auto.php.

Скрипт c_auto.js:

/**********************************************************************
Скрипт карточки раздела "Автомобили"
**********************************************************************/
 
var c_Auto_ScriptFileName = '/config/sections/Auto/c_auto.php';
 
//Инициализация карточки
function c_auto_init(p_wnd_id) {
    // находим форму карточки. p_wnd_id - id на окно карточки. через него ищем само окно, а в нем форму
    var l_form = document.getElementById(p_wnd_id).getElementsByTagName("form")[0];
 
    // Делаем поле № неактивным
    l_form.num.setAttribute('disabled', 'disabled');
 
    // если открыта новая запись, то вставим значение в поле номер
    if (l_form._mode.value == 'insert') {
        // формируем ajax запрос к файлу c_auto.php для получения значения поля №
        var l_auto_init_req = CreatePOSTReqest(c_Auto_ScriptFileName);
        l_auto_init_req.onreadystatechange = function() { c_auto_init_end(l_auto_init_req, l_form); };
        l_auto_init_req.send('_func=GetDefaultValues');
    }
 
}
function c_auto_init_end(p_req, p_form) {
    if (p_req.readyState == 4) {
        // после того, как пришел ответ с сервера присвоим полю полученное значение
        l_response = p_req.responseText.evalJSON(); // ответ приходит в JSON формате - преобразуем его в массив
        p_form.num.value = l_response.Number;
    }
}
 
// обработчик, вызывающийся после сохранения записи
function c_auto_onAfterSave(p_rec_id, p_mode) {
    if (p_mode == 'insert') {
        var req_number = CreatePOSTReqest(c_Auto_ScriptFileName);
        req_number.send('_func=UpdateNumber&_p_id=' + p_rec_id);
    }
}

Скрипт c_auto.php:

<?php
/**********************************************************************
Скрипт карточки раздела "Автомобили"
**********************************************************************/
//Значения по умолчанию
function Auto_GetDefaultValues() {
    $con = GetConnection();
 
    // Номер
    $result['Number'] = GenerateNewNumber('TestNum', null, $con, 1);
    return $result;
}
 
function UpdateAutoNumber($p_id) {
    $con = GetConnection();
    $res = Auto_GetDefaultValues();
    // обновим значение систмной переменной
    SetSystemVariableValue('TestNum', $res['Number'], $con);
 
    //обновим номер
    $update_sql = "update iris_Auto set num='".$res['Number']."' where ID=:p_id";
    $statement = $con->prepare($update_sql);
    $statement->bindParam(':p_id', $p_id);
    $statement->execute();
}
 
 
///////////////////////////////////////////////////////
 
if (!session_id()) {
    @session_start();
    if (!session_id()) {
        echo 'Невозможно создать сессию!';
    }
}
$path = $_SESSION['INDEX_PATH'];
include $path.'/core/engine/applib.php';
include $path.'/config/common/Lib/lib.php';
SendRequestHeaders();
 
if (!isAuthorised()) {
    echo '<b>Не авторизован</b><br>';
    die;
}
 
if (strlen($_POST['_func']) == 0) {
    $response = PrintError('Имя функции не задано');
}
else {
    switch ($_POST['_func']) {
        case 'GetDefaultValues':
            $response = Auto_GetDefaultValues();
            break;
 
        case 'UpdateNumber':
            UpdateAutoNumber(stripslashes($_POST['_p_id']));
            break;
 
        default:
            $response = 'Неверное имя функции: '.$_POST['_func'];
    }
}
 
// посылаем ответ в JSON формате
echo json_encode($response);

Теперь необходимо подключить скрипт c_auto.js к карточке. Добавим в тег EDITCARD атрибуты js_source_file (имя скрипта пользовательской логики), js_function (имя функции, которая должна быть вызвана при открытии карточки), on_after_save (имя функции, которая должна быть вызвана после сохранения карточки).

<EDITCARD name="c_Auto" caption="Автомобиль" width="600" height="120" layout="1, 2, 2, 1, 1, 2, 2" js_source_file="c_auto.js" js_function="c_auto_init" on_after_save="c_auto_onAfterSave">
  <ELEMENTS>
  ..........
  </ELEMENTS>
</EDITCARD>

После того, как скрипт подключен, поле «№» будет получать значение автоматически. Рассмотрим работу скриптов более подробно.

c_auto.js

Функция c_auto_init() делает неактивным поле num формы и если это карточка новой записи, то посылает ajax запрос скрипту c_auto.php, который обращается к БД и возвращает текущее значение для поля «№» (п.1).

Функция c_auto_init_end() вызывается после того, как пришел ответ с сервера (от скрипта c_auto.php). Данная функция просто вставляет значение номера в карточку (п. 2).

Функция c_auto_onAfterSave() вызывается после того, как запись была сохранена. Если это была новая запись, то пошлем ajax запрос скрипту c_auto.php, чтобы он сделал действия из п.3.

c_auto.php

Этот php-скрипт выполняет действия в зависимости от параметра _func. Если _func = GetDefaultValues, то скрипт вернет текущее значение счетчика TestNum. Если _func = UpdateNumber, то скрипт поведет update записи, вствит нужное значение счетчика и увеличит значение счетчика на 1. Сам скрипт имеет около 50 строк, но основную роль выполняют 2 функции.

<?php
GenerateNewNumber('TestNum', null, $con, 1);

GenerateNewNumber() считывает текущее значение счетчика TestNum из таблицы iris_SystemVariable. Можно сделать это вручную, сделав запрос к БД, но эта функция облегчает этот процесс.

<?php
GenerateNewNumber('TestNum', null, $con, 1);

UpdateAutoNumber() выполняет следующие действия.

  • Считывает текущее значение счетчика TestNum.
  • Таблице iris_Auto для только что вставленной записи полю num устанавливает текущее значение счетчика (это необходимо, чтобы исключить ситуацию, когда у двух карточек может быть одинаковый номер, если их создали одновременно).
  • Увеличивает значение счетчика на единицу.

Теперь, при создании новой записи, в поле «№» будет автоматически генерироваться новое значение. Поле при этом будет не редактируемым.