Пятница, 19.04.2024, 14:08
Приветствую Вас Гость

Не ошибается тот, кто ничего не делает.
Но и ничего не делать - ошибка.

Эмиль Кроткий

Меню сайта
Категории раздела
База данных "Склад" [14]
Статьи, связанные с программированием баз данных
Форма входа

Статистика

Онлайн всего: 4
Гостей: 4
Пользователей: 0


















Тиц
Главная » Статьи » Базы данных » База данных "Склад"

Delphi. Урок 1.13. Программирование баз данных в Delphi (Создаем модуль печати данных о приходе и расходе).
Содержание

Урок 1.1. Пишем программу складского учета.
Будем писать программу учета продуктов на складе по средней цене прихода. А для этого нам нужно научиться работать с базами данных. Начнем работу с создания базы в MS Access 2007.

Урок 1.2. Создаем главную форму программы склад.
На этом уроке мы создадим главную форму для нашего склада. Создадим подключение, к базе, используя компонент TADOConnection. Используемые компоненты ( TADOConnection ).

Урок 1.3. Создаем главную форму программы склад.
На этом уроке мы продолжим создание главной формы для нашего склада. Разместим основные компоненты, создадим меню... Используемые компоненты (TADOTable, TMainMenu).

Урок 1.4. Создаем подчиненные формы для справочников программы склад.
На этом уроке мы создадим форму для справочника "Единицы измерения"  нашего склада. Используемые компоненты (TButton, TDBGrid, TDataSource ).

Урок 1.5. Создаем подчиненные формы для справочников программы склад.
На этом уроке мы создадим форму для справочника «Категории продуктов» и «Поставщики»  нашего склада. Используемые компоненты (TButton, TDBGrid, TDataSource ).

Урок 1.6. Создаем подчиненные формы для справочников программы склад.
На этом уроке мы создадим форму для справочника «Продукты»  нашего склада c использованием поле Lookup  из других таблиц. Используемые компоненты (TButton, TDBGrid, TDataSource ).

Урок 1.7. Создаем формы прихода продуктов на склад.
На этом уроке мы создадим формы прихода продуктов на склад. Приход продуктов будет состоять из трех форм. В первой мы будем хранить данные о приходе. Во второй, данные о продуктах для каждого прихода. Третья – форма для выбора продуктов. Используемые компоненты (TButton, TDBGrid, TADOTable, TADOQuery, DataModule).

Урок 1.8. Создаем формы прихода продуктов на склад.
На этом уроке мы создадим вторую форму,  в которой будут отражаться данные о продуктах для каждого прихода. Используемые компоненты (TButton, TDBGrid, TADOTable, TADOQuery, DataModule, TDateTimePicker, TDBLookupComboBox).

Урок 1.9. Создаем формы прихода продуктов на склад.
На этом уроке мы создадим последнюю форму для прихода продуктов. В  ней  будет происходить   выбор продуктов прихода. Используемые компоненты (TButton, TDataSource, TDateTimePicker, TDBLookupComboBox, TDBEdit).

Урок 1.10. Программирование баз данных в Delphi - создаем формы прихода продуктов на склад.
На этом уроке мы напишем процедуры для обработки событий для наших форм прихода, созданных на уроках 1.7. – 1.9.

Урок 1.13. Программирование баз данных в Delphi (Создаем модуль печати данных о приходе и расходе).
На этом уроке мы реализуем  печать данных прихода, расхода и состояния склада.  Печать будем реализовывать через MS Excel, то есть это будет не совсем печать, а экспорт данных в MS Excel, а там пользователь может сам выбрать, печатать или сохранить отчет. В начале приготовим шаблоны  MS Excel, в которые будем выводить отчеты

Урок 1.14. Программирование баз данных в Delphi (Создаем модуль для сжатия и восстановления базы данных).



Урок 1.13.
Программирование баз данных в Delphi (Создаем модуль печати данных о приходе и расходе).

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

Шаблон ведомость по приходу продуктов питания.

Программирование баз данных в Delphi (Создаем модуль печати данных о приходе и расходе).

    В шаблоне использован стиль ссылок R1C1. Включается Параметры->Формулы-> Стиль ссылок R1C1. Файл сохраняем с типом файла Шаблон Excel 97-2003.

Результат работы программы:

Программирование баз данных в Delphi (Создаем модуль печати данных о приходе и расходе).

Шаблон ведомость по расходу продуктов питания.

Программирование баз данных в Delphi (Создаем модуль печати данных о приходе и расходе).

Шаблон остатки на складе.

Программирование баз данных в Delphi (Создаем модуль печати данных о приходе и расходе).

 Скачать шаблоны можно вместе с исходниками в конце статьи.

Далее в формы прихода и расхода внесем несколько изменений, необходимых для фильтрации документов прихода и расхода по дате.
Добавим на формы прихода и расхода по два компонента TDateTimePicker из вкладки Win32 и компонент  TCheckBox из вкладки Standart.  Кнопку  Button для вызова печати. Размещаем, как показано на рисунке:

Программирование баз данных в Delphi (Создаем модуль печати данных о приходе и расходе).

Аналогично для формы расхода.
В инспекторе объектов для обеих DateTimePicker ов обнуляем свойство Time.

А для  события OnChange прописываем следующий код:

procedure TForm_prihod.DateTimePicker1Change(Sender: TObject);
begin
//Проверка установленных дат
if datetimepicker1.Date>datetimepicker2.Date then
begin
ShowMessage('Внимание. Начальная дата прихода больше конечной');
checkbox1.Checked:=false;
DateTimePicker1.Date:=DateUtils.StartOfTheMonth(now);
DateTimePicker2.Date:=date;
end;
end;

procedure TForm_prihod.DateTimePicker2Change(Sender: TObject);

begin
//Проверка установленных дат
if datetimepicker1.Date>datetimepicker2.Date then
begin
ShowMessage('Внимание. Начальная дата прихода больше конечной');
checkbox1.Checked:=false;
DateTimePicker1.Date:=DateUtils.StartOfTheMonth(now);
DateTimePicker2.Date:=date;
end;
end;


А для события OnClick компонента CheckBox1 пишем:

procedure TForm_prihod. Click(Sender: TObject);
//включение фильтра
begin
dm.table_prihod.Filtered:=checkbox1.Checked;
if checkbox1.Checked=true then  dm.table_prihod.Filter:='(date_prihoda>='+datetostr(datetimepicker1.Date)+') and ('+ 'date_prihoda<='+datetostr(datetimepicker2.Date)+')';
end;

Кроме того для события OnCreate формы пишем:

procedure TForm_prihod.FormCreate(Sender: TObject);
begin
//установка начальных значений дат  DateTimePicker
DateTimePicker1.Date:=DateUtils.StartOfTheMonth(now);
DateTimePicker2.Date:=Date;{DateUtils.EndOfTheMonth(now); }
end;

В модуле Uses добавляем модуль DateUtils.



 Аналогичные операции проделываем с формой расхода.

Далее переходим в DataModule (Unit_dm) и размещаем там компонент  TADOQuery из вкладки dbGo (ADO). В свойстве Name задаем имя  ADOQuery_print, в свойство Connection->Form_general.ADOConnection1. Затем из вкладки Data Access размещаем компонент  TDataSource в свойстве Name задаем имя  print, а в свойство  DataSet->ADOQuery_print.

Сейчас создадим отдельный модуль для печати. Выбираем File->New->Unit – Delphi. Назовем его print.

Подключение интерфейса Excel происходит через модуль comobj.

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

unit print;
interface
Uses Windows, Dialogs, SysUtils, Variants, DB,    Excel_TLB,  comobj, unit_dm;
{Внимание!!!  Перед подключением модуля Excel_TLB, необходимо импортировать библиотеку Excel. Для этого выберите Component->Import Component->Import a Type Library-> находим MS Excel и следуем инструкциям}
function CreateApplication(FileName:string):boolean;
procedure print_prihod(date_start,date_end:TDateTime;check:boolean);
procedure print_rashod(date_start,date_end:TDateTime;check:boolean);
procedure print_ostatki;

var

  exl: OleVariant;
  WorkBook, Sheet: Variant;

implementation


function CreateApplication(FileName:string):boolean;

//создаем приложение excel
begin
try
  //Создаем объект интерфейса для доступа к серверу COM
  exl := CreateOleObject('Excel.Application');
  // Отключаем реакцию Excel на события,
  //чтобы ускорить вывод информации
  exl.Application.EnableEvents := false;
  //Создаем книгу и обращаемся к первому листу
  Workbook := exl.Application.WorkBooks.Add(GetCurrentDir()+FileName);
  Sheet := WorkBook.WorkSheets[1];
  result:=true;
Except
showmessage('Внимание! Произошла ошибка при создании MS Excel приложения');
result:=false;
exl.DisplayAlerts := False; // отключаем предупреждения
exl.Workbooks.Close; // закроем все книги
exl.Application.quit;

//освобождаем интерфейсы
Sheet := Unassigned;
WorkBook := Unassigned;
exl := Unassigned;
end;
end;

//печать прихода

procedure print_prihod(date_start,date_end:TDateTime;check:boolean);
var
  ArrayData,ArrayData1,ArrayData2: Variant;
  x,y,kdx,ndx,ndy,kdy,n,m,i:integer;
  //ndx, ndy -начало диапазона по оси х (вправо) и по оси у (вниз)
  //kdx, kdy -конец диапазона по оси х и по оси у
  // ArrayData -  двухмерный массив для продуктов
  // ArrayData1 - двухмерный массив для единиц измерения
  // ArrayData2 -  массив для дат
begin

if CreateApplication('\Шаблоны\Ведомость прихода продуктов.xlt')=false then exit;

try
//делаем запрос на выбор продуктов и единиц измерения прихода
//и заполняем вариантный массив для продуктов и для единиц измерения
dm.ADOQuery_print.Active:=false;
dm.ADOQuery_print.SQL.Clear;
dm.ADOQuery_print.SQL.Add('SELECT products.product_name, ed_izmer.ed_name FROM prihod LEFT JOIN ((storage LEFT JOIN products ON storage.id_product = products.id) LEFT JOIN ed_izmer'+
' ON storage.id_ed_izmer = ed_izmer.id) ON prihod.id = storage.id_prihod GROUP BY products.product_name, ed_izmer.ed_name;');
dm.ADOQuery_print.Active:=True;
y:=dm.print.DataSet.RecordCount;//количество записей по продуктам в приходе
ArrayData := VarArrayCreate([1, y*2,1,1], varVariant); //двухмерный массив для продуктов
ArrayData1 := VarArrayCreate([1, y*2,1,1], varVariant); //двухмерный массив для единиц измерения
    dm.ADOQuery_print.First;
    for i:=1 to y*2 do  //умножаем на два так как в шаблоне для наименования продукта
                        //используется высота ячейки в две клетки, приходится первую заполнять, а вторую пропускать
     begin
     if (i mod 2)<>0 then begin //шаг - каждый второй
            ArrayData[i,1] :=dm.ADOQuery_print.FieldByName('product_name').AsString; //заполняем продукт
            ArrayData[i+1,1] :=''; // оставляем пустой
            ArrayData1[i,1] :=dm.ADOQuery_print.FieldByName('ed_name').AsString; //заполняем единицу измерения
            ArrayData1[i+1,1] :='';// оставляем пустой
            if dm.ADOQuery_print.eof<>true then dm.ADOQuery_print.next;
           end;
     end;
//выполняем запрос на выбор даты прихода и заполняем вариантный массив2

dm.ADOQuery_print.Active:=false;
dm.ADOQuery_print.SQL.Clear;
//проверяем включен ли фильтр и формируем соответствующий запрос по дате или без
if check=false then dm.ADOQuery_print.SQL.Add('SELECT prihod.date_prihoda FROM prihod GROUP BY prihod.date_prihoda ORDER BY prihod.date_prihoda;')
   else
     begin
       dm.ADOQuery_print.Parameters.AddParameter.Name:='date1';
       dm.ADOQuery_print.Parameters.ParamByName('date1').DataType:=ftDateTime;
       dm.ADOQuery_print.Parameters.AddParameter.Name:='date2';
       dm.ADOQuery_print.Parameters.ParamByName('date2').DataType:=ftDateTime;
       dm.ADOQuery_print.SQL.Add('SELECT prihod.date_prihoda FROM prihod GROUP BY prihod.date_prihoda HAVING (((prihod.date_prihoda)>=:date1 and (prihod.date_prihoda)<=:date2)) ORDER BY prihod.date_prihoda; ');
       dm.ADOQuery_print.Parameters.ParamByName('date1').Value:=date_start;
       dm.ADOQuery_print.Parameters.ParamByName('date2').Value:=date_end;
     end;
dm.ADOQuery_print.Active:=True;
x:=dm.print.DataSet.RecordCount;//количество записей дат
ArrayData2 := VarArrayCreate([1, x,1,1], varVariant);//массив для дат
dm.ADOQuery_print.First;
for i:=1 to x do
  begin
     //заполняем массив датами
    ArrayData2[i,1] :=dm.ADOQuery_print.FieldByName('date_prihoda').AsString;
    if dm.ADOQuery_print.eof<>true then dm.ADOQuery_print.next;
  end;
     // рисуем поле данных
         ndy:=24;  ndx:=18;
         kdx:=18+x*4-1; kdy:=25;
     //выделение диапазона ячеек
         sheet.Range[sheet.cells[24,18],sheet.cells[25,21]].Select;
     //объеденение ячеек
         sheet.Range[sheet.cells[24,18],sheet.cells[25,21]].Merge;

     //рисуем поле с цифрами
         ndy:=23;  ndx:=18;
         kdx:=18+x*4-1; kdy:=23;
         sheet.Range[sheet.cells[23,18],sheet.cells[23,21]].Select;
         sheet.Range[sheet.cells[23,18],sheet.cells[23,21]].Merge;
         Exl.Selection.HorizontalAlignment:=xlCenter;
         sheet.cells[23,18].value:=3;

      //рисуем поле с датами
         ndy:=17;  ndx:=18;
         kdx:=18+x*4-1; kdy:=22;
         sheet.Range[sheet.cells[17,18],sheet.cells[22,21]].Select;
         sheet.Range[sheet.cells[17,18],sheet.cells[22,21]].Merge;
         exl.Selection.Orientation := 90;
         Exl.Selection.HorizontalAlignment:=xlCenter;
         Exl.Selection.VerticalAlignment:=xlCenter;

        //общее выделение и размножение вправо
    if x>1 then begin
          ndy:=17;  ndx:=18;
          kdx:=18+x*4-1; kdy:=25;
          sheet.Range[sheet.cells[17,18],sheet.cells[25,21]].Select;
          //автозаполнение выделенного диапазона
          exl.selection.autofill(sheet.Range[sheet.cells[ndy,ndx], sheet.cells[kdy,kdx]], xlFillDefault);
          end;

       //рисуем шапку над датой
          ndy:=15;  ndx:=18;
          kdx:=18+x*4-1; kdy:=16;
          sheet.Range[sheet.cells[15,18],sheet.cells[16,kdx]].Select;
          sheet.Range[sheet.cells[15,18],sheet.cells[16,kdx]].Merge;

        // рисуем поле итоги
          sheet.Range[sheet.cells[15,kdx+1],sheet.cells[22,kdx+5]].Select;
          sheet.Range[sheet.cells[15,kdx+1],sheet.cells[22,kdx+5]].Merge;
          sheet.cells[15,kdx+1].value:='Итого';
          Exl.Selection.HorizontalAlignment:=xlCenter;
          sheet.Range[sheet.cells[23,kdx+1],sheet.cells[23,kdx+5]].Select;
          sheet.Range[sheet.cells[23,kdx+1],sheet.cells[23,kdx+5]].Merge;
          sheet.cells[23,kdx+1].value:=3+x;
          Exl.Selection.HorizontalAlignment:=xlCenter;
          sheet.Range[sheet.cells[24,kdx+1],sheet.cells[25,kdx+5]].Select;
          sheet.Range[sheet.cells[24,kdx+1],sheet.cells[25,kdx+5]].Merge;
          //вводим формулу суммы
           sheet.cells[24,kdx+1].value:='=SUM(RC[-'+inttostr(x*4)+']:R[1]C[-1])';

          //выделяем и рисуем границы шапки таблицы
           sheet.Range[sheet.cells[15,18],sheet.cells[23,kdx+5]].Select;
           exl.Selection.Borders[xlEdgeLeft].LineStyle := xlContinuous;
           exl.Selection.Borders[xlEdgeLeft].Weight := xlMedium;
           exl.Selection.Borders[xlEdgeTop].LineStyle := xlContinuous;
           exl.Selection.Borders[xlEdgeTop].Weight := xlMedium;
           exl.Selection.Borders[xlEdgeBottom].LineStyle := xlContinuous;
           exl.Selection.Borders[xlEdgeBottom].Weight := xlMedium;
           exl.Selection.Borders[xlEdgeRight].LineStyle := xlContinuous;
           exl.Selection.Borders[xlEdgeRight].Weight := xlMedium;
           exl.Selection.Borders[xlInsideVertical].LineStyle := xlContinuous;
           exl.Selection.Borders[xlInsideVertical].Weight := xlMedium;
           exl.Selection.Borders[xlInsideHorizontal].LineStyle := xlContinuous;
           exl.Selection.Borders[xlInsideHorizontal].Weight := xlMedium;

   ndy:=24;  ndx:=2;
   kdx:=18+x*4-1; kdy:=24+y*2-1;
   //общее выделение и размножение вниз
   if y>1 then begin
          sheet.Range[sheet.cells[ndy,ndx],sheet.cells[ndy+1,kdx+5]].Select;
          exl.selection.autofill(sheet.Range[sheet.cells[ndy,ndx], sheet.cells[kdy,kdx+5]],xlfillcopy);
          end;

      //выделяем и рисуем границы  данныx
          sheet.Range[sheet.cells[24,18],sheet.cells[kdy,kdx+5]].Select;
          exl.Selection.NumberFormat:='0,000';
          exl.Selection.Borders[xlEdgeTop].LineStyle := xlContinuous;
          exl.Selection.Borders[xlEdgeTop].Weight := xlMedium;
          exl.Selection.Borders[xlEdgeBottom].LineStyle := xlContinuous;
          exl.Selection.Borders[xlEdgeBottom].Weight := xlMedium;
          exl.Selection.Borders[xlEdgeRight].LineStyle := xlContinuous;
          exl.Selection.Borders[xlEdgeRight].Weight := xlMedium;
          exl.Selection.Borders[xlInsideVertical].LineStyle := xlContinuous;
          exl.Selection.Borders[xlInsideVertical].Weight := xlThin;
          exl.Selection.Borders[xlInsideHorizontal].LineStyle := xlContinuous;
          exl.Selection.Borders[xlInsideHorizontal].Weight := xlThin;

  //заполняем продуктами и еденицами измерения
        sheet.Range[sheet.cells[24,2],sheet.cells[kdy,14]].value:= ArrayData;
        sheet.Range[sheet.cells[24,15],sheet.cells[kdy,17]].value:= ArrayData1;

//в зависимости от фильтра по дате заполняем шапку датами начала периода и конца периода

if check=false then sheet.cells[8,27].value:=ArrayData2[1,1]+' - '+ArrayData2[x,1]
               else sheet.cells[8,27].value:=DateToStr(date_start)+' - '+DateToStr(date_end);
// заполняем таблицу датами
dm.ADOQuery_print.First;
for i:=1 to x do
     begin
       sheet.cells[17,14+i*4].value:= dm.ADOQuery_print.fieldbyname('date_prihoda').AsString;
       if dm.ADOQuery_print.eof<>true then dm.ADOQuery_print.next;
     end;
//запрос на выбор продукта, единицы измерения, даты прихода и суммы
//формируем запрос и заполняем таблицу данными
dm.ADOQuery_print.Active:=false;
dm.ADOQuery_print.SQL.Clear;
dm.ADOQuery_print.SQL.Add('SELECT products.product_name, ed_izmer.ed_name, prihod.date_prihoda, Sum(storage.quantity) AS [Sum-quantity]'+
' FROM prihod LEFT JOIN ((storage LEFT JOIN products ON storage.id_product = products.id) LEFT JOIN ed_izmer ON storage.id_ed_izmer = ed_izmer.id) ON prihod.id = storage.id_prihod'+
' GROUP BY products.product_name, ed_izmer.ed_name, prihod.date_prihoda ORDER BY prihod.date_prihoda; ');

dm.ADOQuery_print.Active:=True;

dm.ADOQuery_print.First;
for m:=1 to y*2 do
   for n:=1 to x do
       if (m mod 2)<>0 then
           begin
           //выбираем продукт и единицу измерения и ищем совпадение по дате прихода
              if (dm.ADOQuery_print.Locate('product_name;ed_name;date_prihoda', VarArrayOf([ArrayData[m,1], ArrayData1[m,1],ArrayData2[n,1]]),[loCaseInsensitive, loPartialKey])) then  begin sheet.cells[23+m,14+n*4].value:= dm.ADOQuery_print.fieldbyname('Sum-quantity').Value; end;
           end;

//показываем excel

exl.visible:=true;
//освобождаем память и интерфейс excel
ArrayData := Unassigned;
ArrayData1 := Unassigned;
ArrayData2 := Unassigned;
Sheet := Unassigned;
WorkBook := Unassigned;
exl := Unassigned;
Except
//в случае ошибки освобождаем ресурсы
showmessage('Внимание! Произошла ошибка при создании отчета');
exl.DisplayAlerts := False; // отключаем предупреждения
exl.Workbooks.Close; // закроем все книги
exl.Application.quit;
ArrayData := Unassigned;
ArrayData1 := Unassigned;
ArrayData2 := Unassigned;
Sheet := Unassigned;
WorkBook := Unassigned;
exl := Unassigned;
end;
end;

//печать расхода

procedure print_rashod(date_start,date_end:TDateTime;check:boolean);
var
  ArrayData,ArrayData1,ArrayData2: Variant;
  x,y,kdx,ndx,ndy,kdy,n,m,i:integer;
  //ndx, ndy -начало диапазона по оси х (вправо) и по оси у (вниз)
  //kdx, kdy -конец диапазона по оси х и по оси у
  // ArrayData -  двухмерный массив для продуктов
  // ArrayData1 - двухмерный массив для единиц измерения
  // ArrayData2 -  массив для дат
begin

if CreateApplication('\Шаблоны\Ведомость расхода продуктов.xlt')=false then exit;

try
//делаем запрос на выбор продуктов и единиц измерения прихода
//и заполняем вариантный массив для продуктов и для единиц измерения
dm.ADOQuery_print.Active:=false;
dm.ADOQuery_print.SQL.Clear;
dm.ADOQuery_print.SQL.Add('SELECT products.product_name, ed_izmer.ed_name FROM rashod_doc LEFT JOIN ((rashod LEFT JOIN products ON rashod.id_product = products.id) LEFT JOIN ed_izmer'+
' ON rashod.id_ed_izmer = ed_izmer.id) ON rashod_doc.id = rashod.id_rashod_doc GROUP BY products.product_name, ed_izmer.ed_name;');
dm.ADOQuery_print.Active:=True;
y:=dm.print.DataSet.RecordCount;//количество записей по продуктам в приходе
ArrayData := VarArrayCreate([1, y*2,1,1], varVariant); //двухмерный массив для продуктов
ArrayData1 := VarArrayCreate([1, y*2,1,1], varVariant); //двухмерный массив для единиц измерения
    dm.ADOQuery_print.First;
    for i:=1 to y*2 do  //умножаем на два так как в шаблоне для наименования продукта
                        //используется высота ячейки в две клетки, приходится первую заполнять, а вторую пропускать
     begin
     if (i mod 2)<>0 then begin //шаг - каждый второй
             ArrayData[i,1] := dm.ADOQuery_print.FieldByName('product_name').AsString; //заполняем продукт
             ArrayData[i+1,1] :=''; // оставляем пустой
             ArrayData1[i,1] := dm.ADOQuery_print.FieldByName('ed_name').AsString; //заполняем единицу измерения
             ArrayData1[i+1,1] :='';// оставляем пустой
             if dm.ADOQuery_print.eof<>true then dm.ADOQuery_print.next;
            end;
     end;

//выполняем запрос на выбор даты прихода и заполняем вариантный массив2

dm.ADOQuery_print.Active:=false;
dm.ADOQuery_print.SQL.Clear;
//проверяем включен ли фильтр и формируем соответствующий запрос по дате или без
if check=false then dm.ADOQuery_print.SQL.Add('SELECT rashod_doc.date_rashoda FROM rashod_doc GROUP BY rashod_doc.date_rashoda ORDER BY rashod_doc.date_rashoda;')
    else
        begin
            dm.ADOQuery_print.Parameters.AddParameter.Name:='date1';
            dm.ADOQuery_print.Parameters.ParamByName('date1').DataType:=ftDateTime;
            dm.ADOQuery_print.Parameters.AddParameter.Name:='date2';
            dm.ADOQuery_print.Parameters.ParamByName('date2').DataType:=ftDateTime;
            dm.ADOQuery_print.SQL.Add('SELECT rashod_doc.date_rashoda FROM rashod_doc GROUP BY rashod_doc.date_rashoda HAVING (((rashod_doc.date_rashoda)>=:date1 and (rashod_doc.date_rashoda)<=:date2)) ORDER BY rashod_doc.date_rashoda; ');
            dm.ADOQuery_print.Parameters.ParamByName('date1').Value:=date_start;
            dm.ADOQuery_print.Parameters.ParamByName('date2').Value:=date_end;
         end;
dm.ADOQuery_print.Active:=True;
x:=dm.print.DataSet.RecordCount;//количество записей дат
ArrayData2 := VarArrayCreate([1, x,1,1], varVariant);//массив для дат
dm.ADOQuery_print.First;
for i:=1 to x do
  begin
     //заполняем массив датами
     ArrayData2[i,1] :=dm.ADOQuery_print.FieldByName('date_rashoda').AsString;
     if dm.ADOQuery_print.eof<>true then dm.ADOQuery_print.next;
  end;
     // рисуем поле данных
        ndy:=24;  ndx:=18;
        kdx:=18+x*4-1; kdy:=25;
     //выделение диапазона ячеек
        sheet.Range[sheet.cells[24,18],sheet.cells[25,21]].Select;
     //объеденение ячеек
         sheet.Range[sheet.cells[24,18],sheet.cells[25,21]].Merge;

      //рисуем поле с цифрами
         ndy:=23;  ndx:=18;
         kdx:=18+x*4-1; kdy:=23;
         sheet.Range[sheet.cells[23,18],sheet.cells[23,21]].Select;
         sheet.Range[sheet.cells[23,18],sheet.cells[23,21]].Merge;
         Exl.Selection.HorizontalAlignment:=xlCenter;
         sheet.cells[23,18].value:=3;

       //рисуем поле с датами
         ndy:=17;  ndx:=18;
         kdx:=18+x*4-1; kdy:=22;
         sheet.Range[sheet.cells[17,18],sheet.cells[22,21]].Select;
         sheet.Range[sheet.cells[17,18],sheet.cells[22,21]].Merge;
         exl.Selection.Orientation := 90;
         Exl.Selection.HorizontalAlignment:=xlCenter;
         Exl.Selection.VerticalAlignment:=xlCenter;

                  //общее выделение и размножение вправо
    if x>1 then begin
                  ndy:=17;  ndx:=18;
                  kdx:=18+x*4-1; kdy:=25;
                  sheet.Range[sheet.cells[17,18],sheet.cells[25,21]].Select;
                  //автозаполнение выделенного диапазона
                  exl.selection.autofill(sheet.Range[sheet.cells[ndy,ndx], sheet.cells[kdy,kdx]], xlFillDefault);
                end;

                  //рисуем шапку над датой
                  ndy:=15;  ndx:=18;
                  kdx:=18+x*4-1; kdy:=16;
                  sheet.Range[sheet.cells[15,18],sheet.cells[16,kdx]].Select;
                  sheet.Range[sheet.cells[15,18],sheet.cells[16,kdx]].Merge;

                  // рисуем поле итоги
                  sheet.Range[sheet.cells[15,kdx+1],sheet.cells[22,kdx+5]].Select;
                  sheet.Range[sheet.cells[15,kdx+1],sheet.cells[22,kdx+5]].Merge;
                  sheet.cells[15,kdx+1].value:='Итого';
                  Exl.Selection.HorizontalAlignment:=xlCenter;
                  sheet.Range[sheet.cells[23,kdx+1],sheet.cells[23,kdx+5]].Select;
                  sheet.Range[sheet.cells[23,kdx+1],sheet.cells[23,kdx+5]].Merge;
                  sheet.cells[23,kdx+1].value:=3+x;
                  Exl.Selection.HorizontalAlignment:=xlCenter;
                  sheet.Range[sheet.cells[24,kdx+1],sheet.cells[25,kdx+5]].Select;
                  sheet.Range[sheet.cells[24,kdx+1],sheet.cells[25,kdx+5]].Merge;
                  //вводим формулу суммы
                  sheet.cells[24,kdx+1].value:='=SUM(RC[-'+inttostr(x*4)+']:R[1]C[-1])';

                  //выделяем и рисуем границы шапки таблицы
                  sheet.Range[sheet.cells[15,18],sheet.cells[23,kdx+5]].Select;
                  exl.Selection.Borders[xlEdgeLeft].LineStyle := xlContinuous;
                  exl.Selection.Borders[xlEdgeLeft].Weight := xlMedium;
                  exl.Selection.Borders[xlEdgeTop].LineStyle := xlContinuous;
                  exl.Selection.Borders[xlEdgeTop].Weight := xlMedium;
                  exl.Selection.Borders[xlEdgeBottom].LineStyle := xlContinuous;
                  exl.Selection.Borders[xlEdgeBottom].Weight := xlMedium;
                  exl.Selection.Borders[xlEdgeRight].LineStyle := xlContinuous;
                  exl.Selection.Borders[xlEdgeRight].Weight := xlMedium;
                  exl.Selection.Borders[xlInsideVertical].LineStyle := xlContinuous;
                  exl.Selection.Borders[xlInsideVertical].Weight := xlMedium;
                  exl.Selection.Borders[xlInsideHorizontal].LineStyle := xlContinuous;
                  exl.Selection.Borders[xlInsideHorizontal].Weight := xlMedium;

   ndy:=24;  ndx:=2;
   kdx:=18+x*4-1; kdy:=24+y*2-1;
   //общее выделение и размножение вниз
   if y>1 then begin
                  sheet.Range[sheet.cells[ndy,ndx], sheet.cells[ndy+1,kdx+5]].Select;
                  exl.selection.autofill(sheet.Range[sheet.cells[ndy,ndx], sheet.cells[kdy,kdx+5]], xlfillcopy);
                end;

                  //выделяем и рисуем границы  данныx
                  sheet.Range[sheet.cells[24,18],sheet.cells[kdy,kdx+5]].Select;
                  exl.Selection.NumberFormat:='0,000';
                  exl.Selection.Borders[xlEdgeTop].LineStyle := xlContinuous;
                  exl.Selection.Borders[xlEdgeTop].Weight := xlMedium;
                  exl.Selection.Borders[xlEdgeBottom].LineStyle := xlContinuous;
                  exl.Selection.Borders[xlEdgeBottom].Weight := xlMedium;
                  exl.Selection.Borders[xlEdgeRight].LineStyle := xlContinuous;
                  exl.Selection.Borders[xlEdgeRight].Weight := xlMedium;
                  exl.Selection.Borders[xlInsideVertical].LineStyle := xlContinuous;
                  exl.Selection.Borders[xlInsideVertical].Weight := xlThin;
                  exl.Selection.Borders[xlInsideHorizontal].LineStyle := xlContinuous;
                  exl.Selection.Borders[xlInsideHorizontal].Weight := xlThin;

     //заполняем продуктами и еденицами измерения
        sheet.Range[sheet.cells[24,2],sheet.cells[kdy,14]].value:= ArrayData;
        sheet.Range[sheet.cells[24,15],sheet.cells[kdy,17]].value:= ArrayData1;

//в зависимости от фильтра по дате заполняем шапку датами начала периода и конца периода

if check=false then sheet.cells[8,27].value:= ArrayData2[1,1]+' - '+ ArrayData2[x,1]
               else sheet.cells[8,27].value:= DateToStr(date_start) + ' - ' + DateToStr(date_end);

// заполняем таблицу датами

dm.ADOQuery_print.First;
for i:=1 to x do
     begin
       sheet.cells[17,14+i*4].value:= dm.ADOQuery_print.fieldbyname('date_rashoda').AsString;
       if dm.ADOQuery_print.eof<>true then dm.ADOQuery_print.next;
     end;
//запрос на выбор продукта, единицы измерения, даты расхода и суммы
//формируем запрос и заполняем таблицу данными
dm.ADOQuery_print.Active:=false;
dm.ADOQuery_print.SQL.Clear;
dm.ADOQuery_print.SQL.Add('SELECT products.product_name, ed_izmer.ed_name, rashod_doc.date_rashoda, Sum(rashod.quantity) AS [Sum-quantity]'+
' FROM rashod_doc LEFT JOIN ((rashod LEFT JOIN products ON rashod.id_product = products.id) LEFT JOIN ed_izmer ON rashod.id_ed_izmer = ed_izmer.id) ON rashod_doc.id = rashod.id_rashod_doc'+
' GROUP BY products.product_name, ed_izmer.ed_name, rashod_doc.date_rashoda ORDER BY rashod_doc.date_rashoda; ');

dm.ADOQuery_print.Active:=True;

dm.ADOQuery_print.First;
for m:=1 to y*2 do
   for n:=1 to x do
       if (m mod 2)<>0 then
           begin
           //выбираем продукт и единицу измерения и ищем совпадение по дате расхода
              if (dm.ADOQuery_print.Locate('product_name;ed_name;date_rashoda', VarArrayOf([ArrayData[m,1], ArrayData1[m,1], ArrayData2[n,1]]), [loCaseInsensitive, loPartialKey])) then  begin sheet.cells[23+m,14+n*4].value:=dm.ADOQuery_print.fieldbyname('Sum-quantity').Value; end;
           end;

//показываем excel

exl.visible:=true;
//освобождаем память и интерфейс excel
ArrayData := Unassigned;
ArrayData1 := Unassigned;
ArrayData2 := Unassigned;
Sheet := Unassigned;
WorkBook := Unassigned;
exl := Unassigned;
Except
//в случае ошибки освобождаем ресурсы
showmessage('Внимание! Произошла ошибка при создании отчета');
exl.DisplayAlerts := False; // отключаем предупреждения
exl.Workbooks.Close; // закроем все книги
exl.Application.quit;
ArrayData := Unassigned;
ArrayData1 := Unassigned;
ArrayData2 := Unassigned;
Sheet := Unassigned;
WorkBook := Unassigned;
exl := Unassigned;
end;
end;

//Печать остатков на складе

procedure print_ostatki;
var
  ArrayData: Variant;
  i:integer;
begin
//если остатков нет выходим
if dm.ostatki.DataSet.RecordCount=0 then begin
  showmessage('На складе нет остатков');
  exit;
end;
//создаем интерфейс Excel
if CreateApplication('\Шаблоны\Остатки на складе.xlt')=false then exit;
try
begin
//объявляем вариантный массив
 ArrayData := VarArrayCreate([1, dm.ostatki.DataSet.RecordCount,1,6], varVariant);
 dm.ADOQuery_ostatki.First;
 for i:= 1 to dm.ostatki.DataSet.RecordCount do
  begin
  //Заполняем вариантный массив данными из запроса остатки
  ArrayData[i,1] :=i;
  ArrayData[i,2] :=dm.ADOQuery_ostatki.FieldByName('product_name').Value;
  ArrayData[i,3] :=dm.ADOQuery_ostatki.FieldByName('ed_name').Value;
  ArrayData[i,4] :=dm.ADOQuery_ostatki.FieldByName('ostatok').Value;
  ArrayData[i,5] :=dm.ADOQuery_ostatki.FieldByName('summa').Value;
  ArrayData[i,6] :=dm.ADOQuery_ostatki.FieldByName('sred_price').Value;
  dm.ADOQuery_ostatki.Next;
  end;
end;

//выделяем и рисуем границы  данныx

                  sheet.Range['a4','f'+IntToStr(dm.ostatki.DataSet.RecordCount+3)].Select;
                  exl.Selection.Borders[xlEdgeTop].LineStyle := xlContinuous;
                  exl.Selection.Borders[xlEdgeTop].Weight := xlMedium;
                  exl.Selection.Borders[xlEdgeBottom].LineStyle := xlContinuous;
                  exl.Selection.Borders[xlEdgeBottom].Weight := xlMedium;
                  exl.Selection.Borders[xlEdgeRight].LineStyle := xlContinuous;
                  exl.Selection.Borders[xlEdgeRight].Weight := xlMedium;
                  exl.Selection.Borders[xlEdgeLeft].LineStyle := xlContinuous;
                  exl.Selection.Borders[xlEdgeLeft].Weight := xlMedium;
                  exl.Selection.Borders[xlInsideVertical].LineStyle := xlContinuous;
                  exl.Selection.Borders[xlInsideVertical].Weight := xlThin;
                  exl.Selection.Borders[xlInsideHorizontal].LineStyle := xlContinuous;
                  exl.Selection.Borders[xlInsideHorizontal].Weight := xlThin;

//заполняем ячейки таблицы Excel из массива

sheet.Range['a4','f'+IntToStr(dm.ostatki.DataSet.RecordCount+3)].value:= ArrayData;
//показываем excel
exl.visible:=true;
//освобождаем память и интерфейс excel
ArrayData := Unassigned;
Sheet := Unassigned;
WorkBook := Unassigned;
exl := Unassigned;
Except
//в случае ошибки освобождаем ресурсы
showmessage('Внимание! Произошла ошибка при создании отчета');
exl.DisplayAlerts := False; // отключаем предупреждения
exl.Workbooks.Close; // закроем все книги
exl.Application.quit;
ArrayData := Unassigned;
Sheet := Unassigned;
WorkBook := Unassigned;
exl := Unassigned;
end;

end;
end.

Как работать с Excel из Delphi, можно прочитать здесь, или найти в Интернете.
На форме приход дважды нажимаем на кнопку печат ь и пишем следующий код  для события OnClick:

procedure TForm_prihod.Button4Click(Sender: TObject);
var date_start:TDate;
    date_end:TDate;
    check:boolean;
begin
//вызов процедуры печати
if CheckBox1.Checked=True then check:=true else check:=false ;
date_start:=(datetimepicker1.Date);
date_end:=(datetimepicker2.Date);
print_prihod(date_start,date_end,check);
end;

Не забываем прописать модуль print в uses для формы прихода.
uses general, unit_dm, prihod_prod, print;

Аналогично делаем и для формы расхода.
Для печати остатков на складе, размещаем на форме кнопку называем ее Печать и по событию OnClick вызываем процедуру печати print_ostatki;
Печать справочников вы можете организовать самостоятельно по аналогии с печатью остатков на складе.

Примеры запросов к базе, созданные в конструкторе MS Access,  для выбора информации для отчета по приходу я оставил в базе для образца их можно удалить. Запросы называются :
ADOQuery_print1
- выбор продуктов и единиц измерения;
ADOQuery_print2 – запрос на выбор дат прихода
ADOQuery_print3 – запрос на выбор продукта, единицы измерения, даты прихода и суммы.
Как работать с конструктором MS Access, можно посмотреть в моей статье в блоге.

Скачать исходники к уроку можно здесь.

С вопросами по программе склад обращайтесь на форум.

Желаю всем удачи.


Категория: База данных "Склад" | Добавил: xaramamburu (13.09.2011)
Просмотров: 22881 | Комментарии: 42 | Рейтинг: 5.0/1
Всего комментариев: 421 2 »
41 Starscream  
0
и вообще событие  OnChange в DateTimePicker генерируется 2 раза...так что уход в цикл это верно.

42 xaramamburu  
0
Такая проблема действительно есть и не только у вас.  В интернете я честно сказать не нашел ни одного адекватного решения, если найдете то выкладывайте, думаю все будут благодарны. Эта ошибка исчезает если переключить режим DateTimePicker свойство DateMode в dmUpDown, но тогда им пользоваться не совсем удобно, но это лучше чем ничего.))))

40 Starscream  
0
Программа уходит в цикл только у меня при проверке установленных дат если при открытии формы в DateTimePicker2 сразу месяц пролистать назад? Думал может сам накосячил чего, скачал "исходник", ан нет опять в цикл...может в DateUtils проблема?  tongue

39 xaramamburu  
0
Под Delphi XE2 при вызове печати возникают ошибки типа:



Проблема связана с константами модуля Excel_TLB (это xlMedium и xlCenter, возможно есть и другие, но пока прблемы только с этими), почему то Delphi XE2  их не очень  хочет понимать. Пока для исправления могу предложить следующее: 

В модуле Print перед разделом Var добавьте раздел констант

const
xlMedium = Integer($FFFFEFD6);
xlCenter = Integer($FFFFEFF4);

Или в строках по всему коду модуля Print

Exl.Selection.HorizontalAlignment:=xlCenter;
Exl.Selection.VerticalAlignment:=xlCenter;

замените xlCenter на Integer(xlCenter) так:

Exl.Selection.HorizontalAlignment:=Integer(xlCenter);
Exl.Selection.VerticalAlignment:=Integer(xlCenter);

а в строках  exl.Selection.Borders[------------].Weight := xlMedium; на
exl.Selection.Borders[------------].Weight := Integer(xlMedium);

Можно также заменить  xlMedium на xlThin,
но тогда надо будет корректировать толщину линий в шаблоне иначе будет не красиво. Они отвечают за расположение текста в ячейке и за толщину линий.

Должно работать.))))

38 afetta  
0
вывести в эксель именно ту запись, которая мне нужна(например 26 числа приход товара был от иванова, петрова и сидорова), как вывести одного из них? (вот например двойным кликом по необходимой строке) можно так сделать

36 afetta  
0
а такая ситуация, в один день большой приход товара от разных поставщиков как мне вывести одного только указав при этом название поставщика, вид упаковки, продукт ед.измерения количество, цена и сумма как тогда

37 xaramamburu  
0
Вывести откуда и куда? А в общем все это делается с помощью запросов.))))

35 afetta  
0
спасибо большое Вам получилось, только теперь надо привести все в нормальный вид

31 afetta  
0
здравствуйте, подскажите, почему все запускается, но идет то, что ошибка при создании эксель приложения что нужно исправить подскажите пожалуйста

34 xaramamburu  
0
Ну так сказать сразу сказать достаточно сложно. Посмотрите вот на эту строчку:
Workbook := exl.Application.WorkBooks.Add(GetCurrentDir()+FileName);
здесь GetCurrentDir() - получение пути к директории с ваши приложением,
FileName - имя файла шаблона с указанием пути от директории с приложением  до файла.
Вот пример вызова - CreateApplication('\Шаблоны\Ведомость прихода продуктов.xlt').
Проверьте, правильно ли указан у вас путь и имя файла.
Можно попробовать путь указать сразу в этой строке:
Workbook := exl.Application.WorkBooks.Add(GetCurrentDir()+FileName);
например так:
Workbook := exl.Application.WorkBooks.Add('c:\\sklad\Шаблоны\Ведомость прихода продуктов.xlt');
Только укажите ваш полный путь и без ошибок.))))
А вообще желательно найти строку которая приводит к ошибке.)))

30 afetta  
0
и почему -то ошибка в приходе и расходе, когда запись новую добавишь, сохраняешь и возникает ошибка невозможно найти строку для обновления.некоторые значения изменены со времени последнего ее чтения
из-за чего это может быть?

32 xaramamburu  
0
Обычно такое бывает когда запрос делается по нескольким таблица и не указана главная из них. Когда я смотрел ваш проект, таких ошибок не возникало.(((

29 afetta  
0
Здравствуйте, спасибо что помогаете, у меня возникает ошибка что произошла ошибка при создании эксель объекта, можно подробнее расписать функцию create application что куда зачем
заранее большое спасибо

33 xaramamburu  
0
Там вроде и так все строчки с комментариями.(((
Смотрите в блоге, там есть статья по работе с Excel. http://basicsprog.ucoz.ru/blog/2011-09-30-8 . Попробуйте создать что нибудь подобное.)))

25 kissesgirl5551  
0
при нажатии на печать выдает ошибку

First chance exception at $759BC6E3. Exception class EAccessViolation with message 'Access violation at address 00551ADB in module 'storage.exe'. Read of address 00000000'. Process storage.exe (5272)

помогите )

26 xaramamburu  
0
Ошибка доступа к памяти. Она может быть из-за чего угодно. Нужно искать строку кода, которая ее вызывает, а уже дальше думать как ее решать. Можно ее попытаться отловить при пошаговом выполнении программы или путем за комментирования фрагментов кода.)))))

27 kissesgirl5551  
0
указывает на 

y:=dm.print.DataSet.RecordCount;

))я новичок..  wacko

28 xaramamburu  
0
Скорее всего ошибка связана с тем, что dm.print.DataSet.RecordCount; не имеет значения т.е. равно null. Это происходит в нескольких случаях:
1. Неправильно выполняется предыдущий запрос;
2. Нет данных о приходе т.е. DBGrid с приходом пустой. Соответственно для исправления ошибки нужно сделать проверку вида:
if dm.print.DataSet.RecordCount<>0 then
begin
//что то выполняем
end
else
begin
//выводим сообщение об ошибке и освобождаем интерфейсы
end;

3. Обращаетесь к закрытому или пустому DataSet .
4. И т.д.
К сожалению в рамках статей уроков разбирается лишь учебный вариант и всех возможных проверок не предусмотрено.)))

1-10 11-15
Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]
Поиск
Наш опрос
Оцените мой сайт
Всего ответов: 585
Уголок общения



Copyright MyCorp © 2024Конструктор сайтов - uCoz