понедельник, 14 мая 2012 г.

Урок 45. Отчет по группам затрат. Детализация

Как ты думаешь, дорогой читатель, для чего я так много времени посвятил каким-то абстрактным группам затрат?

Ответ прост: чтобы получить еще пару удобных отчетов.


Добавьте в проект новую форму, назвав ее AnalizGroupFrm, как уже описывалось ранее, не забыв прописать имя модуля в Uses главной формы и исключив ее из автоматически загружаемых в установках проекта.



На второй вкладке расположена сетка с итогами в футере:


В разделе implementation модуля формы (я назвал его AnalizGroup) имеются уже привычные процедуры, которые я здесь приведу (для порядку), но особого интереса они уже для нас не представляют, как привычные:

implementation

{$R *.dfm}

Uses Main
    , AnalizGroupDetails
    ;

procedure TAnalizGroupFrm.FormCreate(Sender: TObject);
begin

  // Создание формы

  // Задание начальных значений для контролов - дат
  Date_N.Value:=Now()-365;
  Date_K.Value:=Now()+1;

  // Назначение подключения запросу
  ADOQuery1.Connection:=MainFrm.ADOConnection1;

end;

procedure TAnalizGroupFrm.FormClose(Sender: TObject; var Action: TCloseAction);
begin

  // Освобождение памяти
  Action:= caFree;

end;

procedure TAnalizGroupFrm.FormKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  case Key of            // Start Case   Обработка нажатий клавиш

    VK_ESCAPE:
      begin
        MyClose;
      end;

    else

  End;                   // End case
end;

procedure TAnalizGroupFrm.MyClose();
Begin
  Close;
end;

procedure TAnalizGroupFrm.ButtonClickExecuteExecute(Sender: TObject);
begin

  // Акшн, обрабатывающий события нажатия кнопок (ОК и Cancel) при наличии
  if (ModalResult=1) OR (ModalResult=2)
  then
  Begin
    MyClose;
  end;

end;


Еще одна знакомая вещь - использование ранее разработанной функции экспорта в Excel:


procedure TAnalizGroupFrm.N_ExportClick(Sender: TObject);
begin
  Try
  MainFrm.ExportTo(PCHAR('Лист 1'), DBGridEh1, MainFrm.XLApp, PCHAR('Затраты по группам'), PCHAR('Период: '+FormatDateTime('dd/mm/yy',Date_N.Value)+' - '+FormatDateTime('dd/mm/yy',Date_K.Value)));
  Finally
  end;
end;

А теперь - собственно алгоритм получения результатов:


procedure TAnalizGroupFrm.Button1Click(Sender: TObject);
Var MyStr: String;
    j: Integer;
begin


  // Наполнение грида


  // Подготовка запроса
  ADOQuery1.Active:=False;
  ADOQuery1.SQL.Clear;


  // Формирование строки запроса
  MyStr:='SELECT ExpenseGroup.ID, ExpenseGroup.Name, Sum(Main.Summa) AS [MySum] ';
  MyStr:=MyStr + 'FROM (Accounts INNER JOIN (ExpenseGroup INNER JOIN ExpenseAcc ON ExpenseGroup.ID = ExpenseAcc.IDGroup) ON Accounts.ID = ExpenseAcc.IDAcc) INNER JOIN Main ON Accounts.ID = Main.D ';
  MyStr:=MyStr + 'WHERE (((Accounts.Val)='+IntToStr(MySelect.MySel_IDVal)+') ';
  MyStr:=MyStr + 'AND ((Main.MyDate)>=#'+FormatDateTime('mm/dd/yyyy',Date_N.Value)+'# And (Main.MyDate)<#'+FormatDateTime('mm/dd/yyyy',Date_K.Value)+'#)) ';
  MyStr:=MyStr + 'GROUP BY ExpenseGroup.ID, ExpenseGroup.Name ';
  MyStr:=MyStr + 'ORDER BY Sum(Main.Summa) DESC';
  ADOQuery1.SQL.Add(MyStr);
  ADOQuery1.Active:=True;


  // Сопоставление полученных в запросе данных сериям на графике
  j:=1;
  With Series1 do
  begin
   Clear;
    while (Not ADOQuery1.Eof) do
    Begin
      if j>16
      then
        j:=1
      else
        j:=j+1;
      Add(ADOQuery1.FieldByName('MySum').Value, ADOQuery1.FieldByName('Name').Text, MyColor[j]);
      ADOQuery1.Next;
    end;
    Active:=True;
  end;


end;

Пару слов о строке, формирующей запрос.
Составить необходимый запрос проще в среде MS ACCESS:


В результат запроса должны быть отобраны записи, счета Дебета в таблице Main, которых присутствуют в корреляционной таблице ExpenseAcc.
Запрос содержит два условия:
  • Выбираются записи по одной из валют (поле Val)
  • Выбираются записи в интервале дат
Условия отбора я указал не через переменные и параметры, на напрямую.
Еще раз обращаю Ваше внимание, что даты в Access положено заключать в символы "#".
Этот запрос - запрос с группировкой (интересует общая сумма по той или иной группе с учетом условий).

Теперь не сложно взять текст SQL из конструктора запросов Access и перенести его в среду разработки:

SELECT ExpenseGroup.ID, ExpenseGroup.Name, Sum(Main.Summa) AS MySum
FROM ExpenseGroup INNER JOIN ((Accounts INNER JOIN ExpenseAcc ON Accounts.ID = ExpenseAcc.IDAcc) INNER JOIN Main ON Accounts.ID = Main.D) ON ExpenseGroup.ID = ExpenseAcc.IDGroup
WHERE (((Accounts.Val)=1) AND ((Main.MyDate)>=#1/1/2011# And (Main.MyDate)<#1/1/2012#))
GROUP BY ExpenseGroup.ID, ExpenseGroup.Name
ORDER BY Sum(Main.Summa) DESC;

Обратите внимание, что постфикс "DESC" указывает на обратный порядок сортировки по полю сумм.

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



Точно такую же табличку нужно получить в Grid на форме.
Остается только подставить текст запроса в переменную MyStr, указав вместо кода валюты и даты начала и конца периода обработанные (преобразованные) значения соответствующих переменных и контролов:

IntToStr(MySelect.MySel_IDVal) - код валюты преобразуется в строковое значение,
FormatDateTime('mm/dd/yyyy',Date_N.Value) - значение даты из контрола Date_N преобразуется в строковое значение приемлемого формата.

В итоге, должна получиться вот такая картинка:


Но, любого бухгалтера (или вторую половинку:-)) такая диаграмма устроит мало. Вот, чтобы она не огорошила Вас вопросом: "А чего это такой большой зеленый столбик? Откуда эта огромная сумма? Куда делись деньги? А?" Чтобы Вам не пришлось краснеть у руководства и мямлить: "Так, ведь, это ж за целый год...",  предлагаю подумать, как использовать кнопку "Детализация", которую я предусмотрел на форме.

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


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




Комментариев нет:

Отправить комментарий