Менеджер отчётов

© 2008 Савельев Андрей

Общий смысл написания этой статьи состоит в том, чтобы показать, как можно легко управлять большим количеством отчётов в своей программе для определённой категории. Сама идея такой реализации использовании отчётов родилась давно, но реализовать её пришлось только недавно на своём проекте АРМ: Торговля и склад. Сам проект, конечно, предоставлять не буду, так он коммерческий, а во-вторых "увесистый". Но суть самого проекта, да и идеи создания менеджера отчётов распишу вкратце. Суть самого проекта заключается в реализации программного обеспечения для работы как на складе, так и на кассе (в торговом зале). Раз есть модуль склад, то он в себе подразумевает группу документов: приходные документы, расходные документы, списание товара, возврат товара, продажи по кассе и т.д. И к каждой группе документов соответствуют свои отчёты. Например, к приходным и расходным документам относятся такие отчёты как "Приходная и расходная накладная", "Печать ценников на оприходованный товар", к списанию товара или передачи в другой отдел соответствуют такие отчёты как "Акт на списание", "Накладная на списание"; к документам Продажи по кассе соответствуют "Список чеков на дату", "Справка отчёт кассира – операциониста" и т.д. Как видно из перечисляемых отчётов, их просто большое количество, а как для определённого документа выполнить тот или иной отчёт? Для этого и сделан менеджер отчётов.

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

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

- ID_RPT // нумерация позиций отчётов
- NAME_RPT //название отчёта
- COMMENT_RPT // комментарий для отчёта
- VALUE_RPT // значение, которому будет соответствовать тип операции
- NAME_RPT_SHOT // физическое название отчёта

DDL таблицы

CREATE TABLE RPT_LIST (
   ID_RPT INTEGER NOT NULL,
   NAME_RPT VARCHAR(50) NOT NULL,
   COMMENT_RPT VARCHAR(255) NOT NULL,
   VALUE_RPT INTEGER NOT NULL,
   NAME_RPT_SHORT VARCHAR(50) NOT NULL
);

Так со структурой разобрались, теперь перейдём к части проектирования проекта.

Создадим новый проект, на форму бросим Panel, на панели разместим три кнопки и назовём их btnPreview, btnPrint, btnExit. Также на форме разместим DBGrid и DBMemo. Выставим нужные Align у компонентов так, как это показано на рисунке 1.


рис. 1

Создадим DataMoule и бросим туда IBDataBase, IBTransaction, IBQuery, DataSources. Свяжем их, как обычно (подробно, смотрите в примере). Теперь дело осталось за малым: написать код и разобраться с алгоритмом действий.

Алгоритм действий очень прост: при открытии формы, в DBGrid’е формируется список отчётов в зависимости от выбранного типа операции. В нашем случае за тип операций отвечают RatioButton’s и по умолчанию выбран тип "Приход". При выборе в гриде необходимого отчёта, в DBMemo отображается краткое описание для выбранного отчёта. Выбранный отчёт можно как просмотреть в предварительном просмотре, так и сразу вывести на печать.

С алгоритмом действий разобрались. Идём дальше...

В написании кода вообще ничего военного нет, всё очень просто.

Полный код проекта предоставлен ниже:

Код модуля DataModule (назван в примере dm)

procedure Tdm.DataModuleCreate(Sender: TObject);
begin
  // вызываем процедуру подключения БД
  frmMain.OpenBD;
  // Открываем DataSet для первичного формирования группы отчётов
  // для определённого типа операции
  IRep.Open;
end;

Код главной формы frmMain

//процедура, которая отвечает за динамическое подключение БД
procedure TfrmMain.OpenBD;
begin
   //путь до БД
   dm.IBDatabase.DatabaseName := ExtractFilePath(Application.ExeName)+'\base.fdb';

   with dm do
     begin
       try
         IBDatabase.Connected := True;
         IBTransaction.Active := True;
       except
         on E:Exception do
           begin
             Application.MessageBox(PChar('Не удалось подключиться к серверу!' +
             #10#13+#10#13 + e.Message),'Пример',MB_OK + MB_ICONERROR);
             Close;
       end;
     end;
   end;
end;

procedure TfrmMain.RadioButton1Click(Sender: TObject);
begin
   with dm.IRep do
     begin
       close;
       sql.Clear;
       sql.Text := 'select * from rpt_list where value_rpt = ' + QuotedStr(IntToStr((Sender as TRadioButton).Tag));
       Open;
     end;
end;

//кнопка просмотра
procedure TfrmMain.btnPreviewClick(Sender: TObject);
begin
   //Создаём объект
   Rep := TfrxReport.Create(self);
   //загружаем отчёт
   Rep.LoadFromFile(ExtractFilePath(Application.ExeName)+dm.IRep.FieldByName('name_rpt_short').AsString);
   //просмотр отчёта
   if rep.PrepareReport then
     rep.ShowPreparedReport;
   //освобождаем память
   rep.Free;
end;

procedure TfrmMain.btnExitClick(Sender: TObject);
begin
   Close;
end;

// кнопка печати
procedure TfrmMain.btnPrintClick(Sender: TObject);
begin
   //Создаём объект
   Rep := TfrxReport.Create(self);
   //загружаем отчёт
   Rep.LoadFromFile(ExtractFilePath(Application.ExeName)+dm.IRep.FieldByName('name_rpt_short').AsString);
   //печать отчёта
   if Rep.PrepareReport then
   Rep.Print;
   //освобождаем память
   Rep.Free;
end;

Ну, вот в принципе и вся задумка по этому делу.

Полный вид написанного выше выглядит как на рисунке 2


рис. 2

Все описанные в статье примеры можно посмотреть в архиве example.zip (841K).

База данных создавалась на СУБД FireBird 1.5.4. Для работы примера, необходимо чтобы СУБД была установлена!!!

Copyright© 2008 Савельев Андрей  Специально для Delphi Plus