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

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

Реализуем расчет средней себестоимости в документе «Продажа».

Мы с вами уже рассчитывали среднюю себестоимость, когда занимались генерацией продаж. Тогда мы создали в базе данных хранимую процедуру SALE_ITEM_UPDATE_COST, которая вычисляла среднюю стоимость каждого проданного товара и записывала ее в позиции всех документов «Продажа». Вычисление средней стоимости делалось на основе данных в таблице бухгалтерских проводок ACC_TURN .

Мы создадим новую хранимую процедуру SALE_ITEM_SET _COST на основе имеющейся процедуры, ограничив ее действие позициями одного документа.

Вызовем окно интерактивного SQL и введем такой текст (жирным шрифтом выделены отличия от процедуры SALE_ITEM_UPDATE _COST):

create procedure sale_item_set_cost(id integer)
as
  /*переменные для хранения полей*/
  declare variable acc_id integer;
  declare variable op_date date;
  declare variable layer_id integer;
  declare variable object_id integer;
  declare variable template_id integer;
  declare variable doc_id integer;
  declare variable debit decimal(18,2);
  declare variable credit decimal(18,2);
  declare variable quantity_debit decimal(18,3);
  declare variable quantity_credit decimal(18,3);
  /*переменные для хранения текущей суммы и количества в партии товара*/
  declare variable amount decimal(18,2);
  declare variable quantity decimal(18,3);
  declare variable avg_cost double precision;
  /*переменная для храниения текущего id товара*/
  declare variable goods integer;
begin
  goods = -1;
  select stock_acc from sale where id = :id
  into :acc_id;
  for select
    op_date, layer_id, object_id, template_id, doc_id,
    debit, credit, quantity_debit, quantity_credit
  from
    acc_turn
  where
    acc_id = :acc_id and layer_id = 2  and
    object_id in (select goods from sale_item where id = :id)
  order by
    object_id, op_date, template_id
  into
    :op_date, :layer_id, :object_id, :template_id, :doc_id,
    :debit, :credit, :quantity_debit, :quantity_credit
  do
  begin
    if (goods <> object_id) then /*начинаем очередной товар*/
    begin
      amount = 0;
      quantity = 0;
      goods = object_id;
    end
    if ((template_id = 103) and (doc_id = id)) then /*103 - Продажа*/
    begin
      if (quantity <> 0) then
        avg_cost = amount / quantity;
      else
        avg_cost = 0;
      credit = quantity_credit * avg_cost;
      /*изменяем стоимость в позициях документа "Продажи"*/
      update sale_item set cost_s = quantity * :avg_cost
      where id = :doc_id and goods = :object_id
                  and cost_s <> (quantity * :avg_cost);
    end
    amount = amount + debit - credit;
    quantity = quantity + quantity_debit - quantity_credit;
  end
end

Выполним команду в окне ISQL, нажав Ctrl+Enter .

Обратите внимание, что мы используем вложенный запрос в условии WHERE основного запроса:

object_id in (select goods from sale_item where id = :id)

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

Кроме этого мы добавили условие в команду UPDATE:

and cost_s <> (quantity * :avg_cost)

Это защитит от обновления те позиции документа, себестоимость в которых уже рассчитана и рассчитана правильно. Дело в том , что мы будем вызывать созданную нами хранимую процедуру при сохранении документа «Продажа». А так как пользователь может несколько раз редактировать и сохранять документ, то не хотелось бы, чтобы это приводило к многократной перезаписи одних и тех же позиций в базе. Многоверсионный механизм транзакций сервера InterBase при каждой модификации записи в таблице создает ее копию и лишние модификации могут приводить к «замусориванию» базы данных такими копиями и неоправданному увеличению размера файла базы.

Нам осталось добавить вызов хранимой процедуры SALE_ITEM_ SET_COST в проект оконного интерфейса «Продажа». Закроем окно ISQL и войдем в режим «Дизайнер».

Откроем проект sale_project.ipr.

Добавим на форму SaleForm компонент IBQuery с палитры InterBase.

Придадим в Инспекторе объектов его свойствам значения:


Свойство Значение
Transaction TraCurrent
DataSource DsrMaster
SQL execute procedure sale_item_set_cost(: id)
Name QrySetItemCost

В обработчик команды actSave добавим текст, выделенный жирным шрифтом :

procedure TSaleForm.actSaveExecute(Sender: TObject);
begin
  qryTotals.Open;
  qryMaster.Edit;
  qryMaster.FieldByName('TOTAL_L').AsCurrency := qryTotals.Fields[0].AsCurrency;
  qryMaster.FieldByName('TOTAL_R').AsCurrency := qryTotals.Fields[1].AsCurrency;
  qryMaster.FieldByName('TOTAL_S').AsCurrency := qryTotals.Fields[2].AsCurrency;
  qryMaster.Post;
  qryTotals.Close;
  MakeEntries('SALE', qryMaster.FieldByName('ID').AsInteger, traCurrent);
  if qryMaster.FieldByName('HAS_ENTRY').AsInteger = 1 then
  begin
    {Вызываем перерасчет себестоимости}
    qrySetItemCost.ExecSQL;
    {повторно проводим документ}
    MakeEntries('SALE', qryMaster.FieldByName('ID').AsInteger, traCurrent);
  end;
  traCurrent.CommitRetaining; //подтвердить транзакцию
  Modified := False;
  actSave.Enabled := Modified;
  RefreshExplorer; //пересветить "Проводник по документам"
  RefreshBalance;  //пересветить "Баланс"
end;


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