На главную   На главную   Форумы Новости Документация Скачать Купить  
Регистрация  
Система Allegro
Oб Allegro Характеристики Пример конфигурации Документация База ошибок Развитие
Версия для печати К списку книг Вернуться к оглавлению Предыдущий параграф Следующий параграф
Поиск по книге

Глава 5. СОЗДАЕМ ОКОННЫЙ ИНТЕРФЕЙС «ПОСТУПЛЕНИЯ НА СКЛАД»

Создаем SQL-запросы Update и Insert для «шапки» документа.

Включим режим «Дизайнер» и откроем проект stock_ in_project.ipr.

Выберем на главной форме проекта компонент qryMaster и щелкнем на нем правой кнопкой мыши. Появится контекстное меню компонента. Используем пункт меню DataSet Editor. Перед нами появится редактор SQL-запросов вставки, модификации и удаления.



Этот редактор весьма полезен при создании SQL-запросов, так как помогает нам на основе запроса, записанного в свойстве SelectSQL, сформировать все остальные запросы автоматически. Редактор имеет две закладки: Options и SQL. На первой закладке требуется выделить в списке Key Fields ключевые поля, а в правом списке Upadate Fields – поля, которые необходимо модифицировать. Нажмем кнопку Get Table Fields, чтобы выбрать все поля таблицы STOCK_IN, а затем кнопку Select Primary Keys , чтобы выбрать поле ID в качестве ключевого. Теперь нажмем кнопку Generate SQL:



Редактор сам сформирует все тексты запросов и покажет их на закладке «SQL»:



Переключая радиокнопки Statement Type, мы можем посмотреть тексты всех запросов. Обратим внимание, что запросы Insert, Update Delete работают только с одной таблицей, хотя в запросе Select мы использовали объединение нескольких таблиц. Но это правильно , так как нам нужно изменять данные только в таблице документа, а остальные таблицы мы используем лишь в целях получения дополнительной информации при отображении данных. К сожалению, запрос Refresh, сформированный редактором, тоже запрашивает поля одной таблицы, поэтому мы не сможем использовать его в таком виде. Очистим текст запроса Refresh. Очистим также текст запроса Delete, так как удаление документа мы не будем использовать. Нажмем OK.

Дважды щелкнем на свойстве SelectSQL компонента qryMaster в Инспекторе объектов , выделим весь текст запроса и скопируем (Ctrl+ C) его в буфер обмена Windows. Закроем диалог редактора свойства SelectSQL и дважды щелкнем на свойстве RefreshSQL. В появившемся редакторе вставим (Ctrl+V) текст запроса из буфера обмена. Таким образом, в запросах SelectSQL и RefreshSQL для «шапки» документа мы будем использовать один и тот же текст. Запрос RefreshSQL используется после вставки или изменения данных для того, чтобы освежить текущую строку набора.

Теперь набор данных в компоненте qryMaster, стал редактируемым.

Взглянем на переменные контекста, вызвав соответствующее окно через меню Запуск/Переменные контекста. Нужно убедиться, что в переменных контекста сейчас указан конкретный документ. Если это не так, установим тип документа и текущий документ (первые две строки). Выйдем из окна «Переменные контекста».

Запустим проект (F9).

Вызовем окно шапки и убедимся, что управляющие элементы теперь работают. Однако внесенные изменения пока не сохраняются.

Остановим проект и внесем некоторые команды в тексты модулей.

Добавим объявление переменной после implementation:

var
  Modified: boolean;

В этой переменной мы будем хранить признак того, что документ редактировался.

В обработчик OnCreate формы StockInForm, перед другими командами, добавим команды:

traCurrent.StartTransaction; //стартовать транзакцию
Modified := False;

Старт транзакции должен выполняться при запуске проекта, до того , как будут открыты SQL-запросы. Нам необходимо явно стартовать транзакцию, чтобы потом мы могли подтвердить ее или откатить. Все сделанные нами изменения в базе данных после подтверждения транзакции запомнятся окончательно, а в случае отката транзакции, наоборот, все изменения в базе данных, сделанные после старта транзакции, будут отменены.

Дважды щелкнем на компоненте ActionList1, выберем в редакторе списка команду «Сохранить» и создадим к ней обработчик события OnExecute.

Впишем в обработчик следующий тест:

traCurrent.CommitRetaining; //подтвердить транзакцию
Modified := False;

Мы вызвали метод подтверждения транзакции. У компонента класса TIBTransaction существует еще один метод подтверждения транзакции, который называется просто Commit. Разница между ними в том, что метод CommitRetaining оставляет транзакцию активной, и SQL-запросы остаются открытыми. Так как нам в данном случае хочется иметь возможность делать иногда сохранения в процессе редактирование документа, мы выбираем этот метод. Иначе нам пришлось бы каждый раз после сохранения документа переоткрывать все запросы.

В свойстве DefaultAction компонента транзакции traCurrent мы указали TARollback. Это означает, что при закрытии окна транзакция откатится автоматически . Разумеется, мы должны выдать предупреждение пользователю, если он попытается закрыть окно, что изменения могут быть утеряны . Лучше всего предложить ему сделать выбор: сохранить изменения , не сохранять их или отказаться от закрытия окна и продолжить редактирование.

Для того чтобы это реализовать, создадим для формы StockInForm обработчик события OnCloseQuery. Этот обработчик вызывается всякий раз, когда пользователь пытается закрыть форму. Обработчик имеет параметр CanClose , который можно изменить на False внутрь процедуры обработки и тогда форма не закроется. Поэтому впишем в обработчик такой текст:

if Modified then
  case MessageDlg('Сохранить изменения в документе?', mtConfirmation,
                  MkSet(mbYes, mbNo, mbCancel), 0) of
  mrYes: miSave.Click; //вызов обработчика OnClick пункта меню miSave
  mrCancel: Canclose := False;
  end;

Создадим у компонента qryMaster обработчик события AfterPost и впишем в него:

Modified := True;

Мы должны еще позаботиться о том, чтобы вызвать метод Post компонента qryMaster, так как только при вызове этого метода SQL-запросы вставки (insert) и модификации данных (update) посылаются на сервер. Перейдем к форме шапки. Создадим обработчик нажатия кнопки btnOK, дважды щелкнув на этой кнопке. Впишем в него такой текст :

with StockInForm.qryMaster do
if InSet(State, MkSet(dsEdit, dsInsert)) then
begin
   Post;
   RunContext.Documents[0].doc_id := FieldByName('ID').AsInteger;
end;
self.ModalResult := mrOK;

Прежде чем применять метод Post, нужно убедиться, что компонент находится в режиме редактирования или вставки. Поэтому мы предварительно проверяем, входит ли его состояние State во множество состояний [dsEdit, dsInsert]. Если метод Post отработал без ошибок, то свойству ModalResult формы будет присвоено значение mrOK, что автоматически приведет к закрытию формы.

Если данные в каких-то полях были изменены, но мы не хотим посылать эти изменения на сервер, нужно вызвать у метод Cancel компонента qryMaster. Сделаем так , чтобы независимо от того, каким способом пользователь закрывает окно редактирования шапки, если компонент находился при этом в состоянии редактирования или вставки, то будет вызван метод Cancel . Для этого создадим у формы StockInHeaderForm обработчик формы OnClose и впишем в него такой текст:

with StockInForm.qryMaster do
if InSet(State, MkSet(dsEdit, dsInsert)) then
    Cancel;

Запустим проект и вызовем окно шапки документа с помощью контекстного меню. Изменим данные в полях шапки, например, поменяем «Склад». Нажмем OK. А теперь попытаемся закрыть окно документа. Мы должны увидеть предложение сохранить документ :



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

Прежде, чем добавлять позиции в новый документ «Поступление на склад», пользователь всегда заполняет его шапку. Документы в Allegro создаются, как правило, из «Проводника по документам», который просто вызывает наш проект оконного интерфейса . Проект должен проверить значение переменной контекста RunContext.Documents [0].doc_id и если оно не положительно, сразу принять решение о том, что это новый документ и вызвать форму для редактирования «шапки» с помощью метода ShowModal. Нам нужно сделать так, чтобы пользователь мог отменить создание документа на этом этапе, нажав кнопку «Отмена» в окне редактирования «шапки ». Вызовем окно «шапки» в событии OnCreate ( при создании) главной формы проекта. Если пользователь откажется от создания нового документа, нажав «Отмена», то метод ShowModal вернет значение, отличное от mrOK. Это и будет сигналом к ому, чтобы завершить работу проекта . Для того чтобы завершить работу проекта нужно закрыть его главную форму StockInForm. Так как в обработчике события OnCreate формы закрыть эту форму нельзя, используем компонент таймера. Запустим таймер в обработчике OnCreate формы, если требуется ее закрыть. Когда произойдет событие таймера, то обработчик этого события закроет главную форму.

Добавим на форму StockInForm компонент Timer (палитра System) и установим его свойства:

Enabled = False

Interval = 100

А в обработчике OnCreate формы, после выражения

qryMaster.Open;

добавим такой текст:

  if RunContext.Documents[0].doc_id <=0 then
  begin
    qryMaster.Insert;
    {присваиваем начальные значения полям}
    qryMaster.FieldByName('DIR_ID').AsInteger := RunContext.dir_id;
    qryMaster.FieldByName('DOC_KIND').AsInteger := 0;
    qryMaster.FieldByName('CALC_MODE').AsInteger := 1;
    qryMaster.FieldByName('DOC_DATE').AsDateTime := Date;
    qryMaster.FieldByName('HAS_ENTRY').AsInteger := 1;
    qryMaster.FieldByName('ENTRY_DATE').AsDateTime := Date;
    qryMaster.FieldByName('VAT_RATE').AsCurrency := 20;
    qryMaster.FieldByName('TOTAL_L').AsCurrency := 0;
    qryMaster.FieldByName('TOTAL_S').AsCurrency := 0;
    qryMaster.FieldByName('TOTAL_R').AsCurrency := 0;
    qryMaster.FieldByName('CONTRAGENT').AsInteger := 0;
    qryMaster.FieldByName('STOCK_ACC').AsInteger := 1007; //Главный склад
    qryMaster.FieldByName('ACC_ID').AsInteger := 1012; //Поставщики
    if StockInHeaderForm.ShowModal <> mrOK then
      Timer1.Enabled := True;
  end;
  if Timer1.Enabled then
    exit;

Выберем компонент Timer, создадим обработчик его события OnTimer и впишем в него:

Timer1.Enabled := False;
Modified := False;
Self.Close;

Метод Self.Close закроет главную форму, когда произойдет событие таймера. А оно произойдет только в том случае , если пользователь отказался от создания нового документа, нажав кнопку Отмена в окне редактирования шапки.

При создании любой новый документ должен получить новое уникальное значение для поля ID с помощью специального генератора DOC_ID _GEN, существующего в базе данных. Займемся подключением генератора DOC_ID_GEN к компоненту qryMaster. Для этого выберем компонент qryMaster в Инспекторе объектов и дважды щелкнем на его свойстве GeneratorField. Появится редактор свойства:



Установим свойства:

Generator = DOC_ID_GEN

Field = ID

Increment By = 1

Apply Event = On Post

Эти установки означают, что для получения новых значений поля ID, если оно еще пустое, будет использоваться генератор DOC_ID_GEN, каждый раз увеличивая свое значение на единицу. Запуск генератора будет производиться в момент вызова метода Post компонента qryMaster.

Нам нужно еще разобраться с обязательными и необязательными полями. Дважды щелкнем на компоненте qryMaster и в Инспекторе объектов установим свойство Required для следующих полей:


Поле Свойство Required
STOCK_ACC_NAME False
LAYER_NAME False
CREDIT_ACC_NAME False
CONTRAGENT_NAME False
   
DOC_DATE True
DOC_NO True
VAT_RATE True
EXCH_RATE_S True
EXCH_RATE_L True
ENTRY_DATE True

Сохраним проект. Растянем Главное окно Allegro, вызовем « Проводник по документам» и попытаемся создать из него с помощью через контекстное меню новое «Поступление на склад». Попробуем отменить, нажав Отмена. Попробуем создание еще раз , заполним все поля шапки и нажмем OK. Закроем окно документа, на вопрос о сохранении ответим Да. Документ создан, хоть он пока и не виден в «Проводнике». Для того чтобы его увидеть, нужно освежить проводник (Ctrl+F5).

Для того чтобы после каждого сохранения документа проводник освежался автоматически , добавим в конец текста обработчика OnExecute команды меню actSave вызов следующей процедуры:

RefreshExplorer; //пересветить «Проводник по документам»


Пример создания склада в Allegro Наверх