Глава 9. СОЗДАЕМ ОКОННЫЙ ИНТЕРФЕЙС ДОКУМЕНТА «ПРОДАЖА»
Реализуем проверку текущего количества товара на складе в документе «Продажа».
При сохранении документа «Продажа», если установлена птичка «
Товар отгружен», нужно проверить наличие товара на складе,
чтобы убедиться, что не отгружается больше единиц товара,
чем это возможно физически. Для этого после первого проведения
документа, непосредственно перед расчетом средней стоимости вставим проверку результирующего
количества товара на складе. И если это количество стало
отрицательным, прервем выполнение команды сохранения, не дойдя до
подтверждения транзакции.
Добавим еще один компонент IBQuery на форму SaleForm.
Придадим в Инспекторе объектов его свойствам значения:
Свойство |
Значение |
Transaction |
traCurrent |
DataSource |
dsrMaster |
Name |
qryTestQuantity |
Дважды щелкнув на свойстве SQL, вызовем редактор SQL-
запросов и впишем в него текст:
select
a.object_id,
o.short_name name,
sum(a.quantity_debit - a.quantity_credit) quantity
from
acc_turn a, object_names o
where
a.acc_id = :stock_acc and
a.op_date <= :entry_date and
a.object_id in (select goods from sale_item where id = :id) and
a.object_id = o.object_id
group by
a.object_id,
o.short_name
having
sum(a.quantity_debit - a.quantity_credit) < 0
Обратим внимание, что запрос параметризованный. Параметры stock_
acc, entry_date и id перед открытием запроса
компонент qryTestQuantity получит из соответствующих полей компонента qryMaster, благодаря
тому, что свойству DataSource компонента qryTestQuantity назначен источник dsrMaster
.
Осталось добавить активизацию этого запроса и проверку результата в обработчик
команды actSave. Добавим объявление новой функции в секцию private
класса формы (показано жирным шрифтом):
private
{ Private declarations }
procedure UpdatePrice(PriceQuery: TDataSet);
function Save: boolean;
public
{ Public declarations }
end;
Добавим реализацию этой функции в раздел implementation модуля:
procedure TSaleForm.Save: boolean;
begin
end;
Вырежем весь текст из обработчика actSave, вставим его в
тело функции и добавим ряд операторов (добавленные операторы выделены
жирным шрифтом):
procedure TSaleForm.Save: boolean;
begin
Result := False;
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
with qryTestQuantity do
begin
Open; //открываем запрос количеств
if not qryTestQuantity.IsEmpty then //если результирующий набор не пуст
begin
{находим позицию в документе}
qryDetail.Locate('GOODS', FieldByName('OBJECT_ID').AsInteger, MkSet());
dbgDetail.SelectedField := qryDetail.FieldByName('QUANTITY');
{выдаем сообщение}
MessageDlg('Недостаточно товара на складе:'#13+
FieldByName('NAME').AsString, mtError, MkSet(mbOK), 0);
Close; //закрываем запрос количеств
exit; //выходим из процедуры сохранения
end
else
Close; //закрываем запрос количеств
end;
{Вызываем перерасчет себестоимости}
qrySetItemCost.ExecSQL;
{повторно проводим документ}
MakeEntries('SALE', qryMaster.FieldByName('ID').AsInteger, traCurrent);
end;
traCurrent.CommitRetaining; //подтвердить транзакцию
Modified := False;
actSave.Enabled := Modified;
RefreshExplorer; //пересветить "Проводник по документам"
RefreshBalance; //пересветить "Баланс"
Result := True;
end;
Обратим внимание, что вначале мы присваиваем результату, который
должна вернуть эта функция, значение False, а в
самом конце – присваиваем True. Поэтому функция вернет True
только в том случае, если функция сохранения довела свою
работу до конца. Если количество какого-то товара
на складе, входящего в данный документ, стало отрицательным
– вызовется команда exit, которая прервет выполнение функции и
та вернет значение False.
В обработчик actSave вместо прежнего текста теперь вставим вызов этой
функции:
procedure TSaleForm.actSaveExecute(Sender: TObject);
begin
Save;
end;
Изменим также обработчик события формы OnCloseQuery: заменим строку
mrYes: actSaveExecute(nil); //вызов обработчика OnExecute команды actSave
на вызов функции Save:
procedure TSaleForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
if Modified then
case MessageDlg(
'Сохранить изменения в документе ?', mtConfirmation,
mkSet(mbYes, mbNo, mbCancel), 0) of
mrYes: CanClose := Save; //вызов функции Save
mrCancel: Canclose := False;
end;
end;
При попытке закрыть окно, если документ редактировался, возникает
предложение сохранить изменения. Если пользователь ответил «Да»,
но при сохранении выяснилось, что товара на складе недостаточно
, то сохранение не произойдет и окно не закроется,
так как переменной CanClose в обработчике OnCloseQuery присвоится значение False
.
Установим в переменных контекста какой-нибудь документ продаж.
Запустим проект и попробуем значительно увеличить количество отгружаемого товара.
При попытке сохранить изменения мы получим сообщение «Недостаточно товара
на складе» и документ не будет сохранен:
Выйдем из режима дизайнера и создадим архивную копию базы (
меню Инструменты/Архивация базы).
Итак, мы полностью закончили интерфейс ввода документа «Продажа
». Нам осталось лишь реализовать печать счетов-фактур и
накладных.
|