Правильная ссылка на эту страницу
http://az-design.ru/Projects/AzBook/AZMicro/AZMicroC7.shtml

Форма "Оборотная ведомость"

       В принципе, форма "Оборотная ведомость" мало чем отличается от варианта в AZMicro. Только тем, что она выделена в отдельную форму и в ней добавлено выбор аналитических признаков. Что нужно для этой формы? Набор компонентов Dataset для отображения результата "Оборотной ведомости" (dstTurnSheet), набор компонентов Dataset (dstAccnt) для показа текущего счета и набор компонентов TSQL, для выполнения самой процедуры TurnSheet.
       Из визуальных компонентов нужно:
       — DBGrid, подключенный к dstTurnSheet, для отображения оборотной ведомости;
       — DTText, подключенный к dstAccnt, для отображения текущего счета;
       — ComboBox (cbxTurnType) для выбора типа оборотной ведомости;
       — компоненты для выбора даты начала периода (dtpTurnBeg) и даты конца периода (dtpTurnEnd), который будут переданы как параметры в процедуру TurnSheet.
       И, конечно, кнопка для запуска самой процедуры.
       Как всегда первоначальные настройки Dataset осуществляются в процедуре FormCreate, которая вызывается при создании формы:

procedure TfmTurnsheet.FormCreate(Sender: TObject);
Var
  gr_w,fld_w : integer;
begin
  dstTurnSheet.Close;
  dstTurnSheet.SelectSQL.Clear;
  dstTurnSheet.SelectSQL.Add('Select * from TurnSheetView');
  dstTurnSheet.SelectSQL.Add(' where UsrID='+IntToStr(AZUserID));
  dstTurnSheet.SelectSQL.Add(' order by Accnt');
  dstTurnSheet.Open;

       Выборка результата выполняется из представления TurnSheetView при условии, что это свои данные. Для этого указывается UsrID равным ID текущего пользователя.

  gr_W := grdTurnSheet.Width;
  fld_w := (gr_w - 100-36) div 4;
  grdTurnSheet.Columns.Clear;
  grdTurnSheet.Columns.Add;
  grdTurnSheet.Columns[0].FieldName := 'Accnt';
  grdTurnSheet.Columns[0].Title.caption := 'Счет';
  grdTurnSheet.Columns[0].Title.Alignment := taCenter;
  grdTurnSheet.Columns[0].Width := 100;
  grdTurnSheet.Columns.Add;
  grdTurnSheet.Columns[1].FieldName := 'MSldBeg';
  grdTurnSheet.Columns[1].Title.caption := 'Сальдо начальное';
  grdTurnSheet.Columns[1].Title.Alignment := taCenter;
  grdTurnSheet.Columns[1].Width := fld_w;
  grdTurnSheet.Columns.Add;
  grdTurnSheet.Columns[2].FieldName := 'MTrnCrd';
  grdTurnSheet.Columns[2].Title.caption := 'Оборот по Кредиту';
  grdTurnSheet.Columns[2].Title.Alignment := taCenter;
  grdTurnSheet.Columns[2].Width := fld_w;
  grdTurnSheet.Columns.Add;
  grdTurnSheet.Columns[3].FieldName := 'MTrnDbt';
  grdTurnSheet.Columns[3].Title.caption := 'Оборот по Дебиту';
  grdTurnSheet.Columns[3].Title.Alignment := taCenter;
  grdTurnSheet.Columns[3].Width := fld_w;
  grdTurnSheet.Columns.Add;
  grdTurnSheet.Columns[4].FieldName := 'MSldEnd';
  grdTurnSheet.Columns[4].Title.caption := 'Сальдо конечное';
  grdTurnSheet.Columns[4].Title.Alignment := taCenter;
  grdTurnSheet.Columns[4].Width := fld_w;

       После чего настраиваются колонки в grdTurnSheet — имя поля, название, выравнивание, ширина.

  dstAccnt.Close;
  dstAccnt.SelectSQL.Clear;
  dstAccnt.SelectSQL.Add('Select AccntNum,AccTitle from ChartAcc');
  dstAccnt.SelectSQL.Add(' where AccntNum=:Accnt');
  dstAccnt.Open;

       Дальше настраивается dstAccnt, который выбирает названия счет из плана счетов. При этом номер текущего счета (:Accnt) берется из dstTurnSheet, для чего в dstAccnt свойство DataSource нужно установить в dsrTurnSheet.

  MainForm.dstRO.Close;
  MainForm.dstRO.SelectSQL.Clear;
  MainForm.dstRO.SelectSQL.Add('Select Max(JrnDate) as DtMax, Min(JrnDate) as DtMin');
  MainForm.dstRO.SelectSQL.Add(' from Journal'+AZRls);
  MainForm.dstRO.Open;
  dtpTurnEnd.Date := MainForm.dstRO.FieldValues['DtMax'];
  dtpTurnBeg.Date := MainForm.dstRO.FieldValues['DtMin'];
  MainForm.dstRO.Close;
end;

       И, в завершение, нужно определить даты начала и конца периода, доступные в журнале операций, и записать их в свойства Date соответствующих dtpTurnBeg и dtpTurnEnd, чтобы пользователь знал границы, в которых он может работать.
       Для того, чтобы при любом изменении размеров формы grdTurnSheet правильно отображал колонки, используется процедура FormResize:

procedure TfmTurnsheet.FormResize(Sender: TObject);
Var
  gr_w,fld_w : integer;
begin
   gr_W := grdTurnSheet.Width;
   fld_w := (gr_w - 100-36) div 4;
   grdTurnSheet.Columns[0].Width := 100;
   grdTurnSheet.Columns[1].Width := fld_w;
   grdTurnSheet.Columns[2].Width := fld_w;
   grdTurnSheet.Columns[3].Width := fld_w;
   grdTurnSheet.Columns[4].Width := fld_w;
end;

       Так как, оборотная ведомость показывается как в деньгах, так и в количестве, то необходимо предоставить пользователю механизм выбора, что делается с помощью cbxTypeView, который запускает процедуру cbxTypeViewChange:

procedure TfmTurnsheet.cbxTypeViewChange(Sender: TObject);
begin
  if cbxTypeView.ItemIndex=0 then begin
     grdTurnSheet.Columns[1].FieldName := 'MSldBeg';
     grdTurnSheet.Columns[2].FieldName := 'MTrnCrd';
     grdTurnSheet.Columns[3].FieldName := 'MTrnDbt';
     grdTurnSheet.Columns[4].FieldName := 'MSldEnd';
  end;
  if cbxTypeView.ItemIndex=1 then begin
     grdTurnSheet.Columns[1].FieldName := 'NSldBeg';
     grdTurnSheet.Columns[2].FieldName := 'NTrnCrd';
     grdTurnSheet.Columns[3].FieldName := 'NTrnDbt';
     grdTurnSheet.Columns[4].FieldName := 'NSldEnd';
  end;
  grdTurnSheet.Refresh;
end;

       Суть ее проста. В одном случае для колонок в свойстве FieldName записываются имена полей, которые начинаются с символа M (Money), а в другом — которые начинаются с символа N (Number).
       Осталось только получить соответствующий аналитический признак. Ведь было же заявлено, что можно получить Оборотную ведомость по отдельному договору. Для этого используется cbxTurnType и процедура, которая вызывается при его изменении:

procedure TfmTurnsheet.cbxTurnTypeChange(Sender: TObject);
Var
  gr_w : integer;
  sFld : string;
begin
  if cbxTurnType.ItemIndex=0 then begin
     iDoc := 0;     iPrt := 0;     iGds := 0;     iPrs := 0;
  end;

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

  if cbxTurnType.ItemIndex=1 then begin
     Application.CreateForm(TfmSelOptions,fmSelOptions);
     ScreenPoint := cbxTurnType.ClientToScreen(cbxTurnType.ClientRect.TopLeft);
     fmSelOptions.Left := ScreenPoint.X+5;  fmSelOptions.Top := ScreenPoint.Y+25;
     fmSelOptions.Width := cbxTurnType.Width+120;
     fmSelOptions.Tag := 0;

       При выборе, например, Оборотной ведомости по Документу, создается форма для выбора Документа. Опять используется форма fmSelOptions, которая после создания устанавливается в левый верхний угол cbxTurnType.

     fmSelOptions.dstRO.Close;
     fmSelOptions.dstRO.SelectSQL.Clear;
     fmSelOptions.dstRO.SelectSQL.Add('Select d.DocID as ID,d.DCode,d.DTitle from Documents d');
     fmSelOptions.dstRO.SelectSQL.Add(' where exists (select j.DocID from Journal j');
     fmSelOptions.dstRO.SelectSQL.Add('                where j.DocID=d.DocID)');
     fmSelOptions.dstRO.SelectSQL.Add('   and d.DocID<>0');
     fmSelOptions.dstRO.SelectSQL.Add('   and ((d.DCode like :DFltr) or (d.DTitle like :DFltr))');
     fmSelOptions.dstRO.SelectSQL.Add(' order by d.DCode');
     fmSelOptions.dstRO.Prepare;
     fmSelOptions.dstRO.ParamByName('DFltr').AsString := '%';

       Потом в dstRO формы записывается запрос для поиска Документа. При этом выбираются только те Документы, которые присутствуют в Журнале операций, потому что в противном случае бессмыслено получать Оборотную ведомость. Для этого используется подзапрос из таблицы Journal и специальный оператор exists.

     gr_W := fmSelOptions.grdRO.Width;
     fmSelOptions.grdRO.Columns.Clear;
     fmSelOptions.grdRO.Columns.Add;
     fmSelOptions.grdRO.Columns[0].FieldName := 'DCode';
     fmSelOptions.grdRO.Columns[0].Title.caption := 'Код';
     fmSelOptions.grdRO.Columns[0].Title.Alignment := taCenter;
     fmSelOptions.grdRO.Columns[0].Width := 120;
     fmSelOptions.grdRO.Columns.Add;
     fmSelOptions.grdRO.Columns[1].FieldName := 'DTitle';
     fmSelOptions.grdRO.Columns[1].Title.caption := 'Название документа';
     fmSelOptions.grdRO.Columns[1].Title.Alignment := taCenter;
     fmSelOptions.grdRO.Columns[1].Width := gr_W - 120 - 35;
     fmSelOptions.dstRO.Open;

       Далее настраивается отображение колонок.

     if fmSelOptions.ShowModal=mrOK then begin
        iDoc := fmSelOptions.Tag;
        sFld := fmSelOptions.dstRO.FieldValues['DCode'];
        sFld := sFld + '{' +fmSelOptions.dstRO.FieldValues['DTitle']+'}';
        self.Caption := 'Оборот.Ведом. по '+sFld;
     end;
  end;

       И, наконец, все это показывается показывается пользователю и ожидает его выбора. После того как пользователь нажал кнопку "OK" аналитический признак записывается в переменную iDoc, а название выбранного документа записывается в заголовок формы.
       Для остальных аналитических признаков все выполняется таким же образом.
       И, наконец, нужно получить саму оборотную ведомость. Для этого кнопка btnStart вызывает процедуру btnStartClick:

procedure TfmTurnsheet.btnStartClick(Sender: TObject);
Var
  dtBeg,dtEnd : String;
begin
  dtBeg := ''''+FormatDateTime('yyyy"-"mm"-"dd',dtpTurnBeg.DateTime)+'''';
  dtEnd := ''''+FormatDateTime('yyyy"-"mm"-"dd',dtpTurnEnd.DateTime)+'''';
  sqlProc.Close;
  sqlProc.SQL.Clear;
  if cbxTurnType.ItemIndex=0 then begin
     sqlProc.SQL.Add('Execute procedure TurnSheetCore'+AZRls+'('+dtBeg+','+dtEnd+');');
  end;
  if cbxTurnType.ItemIndex=1 then begin
     if iDoc<>0 then sqlProc.SQL.Add('Execute procedure TurnSheetDocuments'+AZRls
                                  +'('+dtBeg+','+dtEnd+','+IntToStr(iDoc)+');')
                else sqlProc.SQL.Add('Execute procedure TurnSheetCore'+AZRls
                                  +'('+dtBeg+','+dtEnd+');');
  end;

       Если тип Оборотной ведомости указан, например, "по Документу", то проверяется ID документа, которых хранится в перемонной iDoc, и если он не равен 0, то на сервере выполняется процедура TurnSheetDocuments с добавлением роли текущего пользователя, в противном случае выполняется стандартная процедура TurnSheetCore без аналитики.

  if cbxTurnType.ItemIndex=2 then begin
     if iPrt<>0 then sqlProc.SQL.Add('Execute procedure TurnSheetPartners'+AZRls
                                  +'('+dtBeg+','+dtEnd+','+IntToStr(iPrt)+');')
                else sqlProc.SQL.Add('Execute procedure TurnSheetCore'+AZRls
                                  +'('+dtBeg+','+dtEnd+');');
  end;
  if cbxTurnType.ItemIndex=3 then begin
     if iGds<>0 then sqlProc.SQL.Add('Execute procedure TurnSheetGoods'+AZRls
                                  +'('+dtBeg+','+dtEnd+','+IntToStr(iGds)+');')
                else sqlProc.SQL.Add('Execute procedure TurnSheetCore'+AZRls
                                  +'('+dtBeg+','+dtEnd+');');
  end;
  if cbxTurnType.ItemIndex=4 then begin
     if iPrs<>0 then sqlProc.SQL.Add('Execute procedure TurnSheetPersons'+AZRls
                                  +'('+dtBeg+','+dtEnd+','+IntToStr(iPrs)+');')
                else sqlProc.SQL.Add('Execute procedure TurnSheetCore'+AZRls
                                 +'('+dtBeg+','+dtEnd+');');
  end;
  trProc.StartTransaction;
  sqlProc.ExecQuery; // выполнение указанной процедуры
  trProc.Commit;
  dstTurnSheet.Close;
  dstTurnSheet.Open;
end;

       После выполнения выбранной процедуры датасет dstTurnSheet закрывается и открывается, чтобы обновить его содержимое.
       Результаты трудов можно посмотреть ниже:


Рис.AZMicro2_06 - выбор Документа для оборотной ведомости


Рис.AZMicro2_07 - результат Оборотной ведомости по выбранному документу

Архангельский Андрей




<<< Пред. Оглавление
Начало раздела
След. >>>

Дата последнего изменения:
Thursday, 21-Aug-2014 09:10:56 MSK


Постоянный адрес статьи:
http://az-design.ru/Projects/AzBook/AZMicro/AZMicroC7.shtml