home *** CD-ROM | disk | FTP | other *** search
/ PC Format Collection 48 / SENT14D.ISO / tech / delphi / disk15 / mastapp.pak / EDORDERS.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1995-08-24  |  24.0 KB  |  773 lines

  1. { See the comments in MAIN.PAS for information about this project }
  2. unit Edorders;
  3.  
  4. interface
  5.  
  6. uses
  7.   SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
  8.   Dialogs, Forms, StdCtrls, DBGrids, DBCtrls, DBTables, DB, Buttons, Mask, Grids,
  9.   DBLookup, ExtCtrls;
  10.  
  11. type
  12.   TOrderForm = class(TForm)
  13.     Orders: TTable;
  14.     Cust: TTable;
  15.     Items: TTable;
  16.     Parts: TTable;
  17.     OrdersSource: TDataSource;
  18.     CustSource: TDataSource;
  19.     ItemsSource: TDataSource;
  20.     PartsPartNo: TFloatField;
  21.     PartsVendorNo: TFloatField;
  22.     PartsOnHand: TFloatField;
  23.     PartsOnOrder: TFloatField;
  24.     PartsCost: TCurrencyField;
  25.     PartsListPrice: TCurrencyField;
  26.     OrdersTaxTotal: TCurrencyField;
  27.     NextOrd: TTable;
  28.     NextOrdNewKey: TFloatField;
  29.     HeaderPanel: TPanel;
  30.     CustNameEdit: TDBEdit;
  31.     ShipToAdd1Edit: TDBEdit;
  32.     ShipToAdd2Edit: TDBEdit;
  33.     CustAdd1Edit: TDBEdit;
  34.     CustAdd2Edit: TDBEdit;
  35.     ShipToCompanyEdit: TDBEdit;
  36.     CustCityEdit: TDBEdit;
  37.     CustStateEdit: TDBEdit;
  38.     CustZipEdit: TDBEdit;
  39.     ShipToCityEdit: TDBEdit;
  40.     ShipToStateEdit: TDBEdit;
  41.     ShipToZipEdit: TDBEdit;
  42.     ModeIndicator: TLabel;
  43.     POEdit: TDBEdit;
  44.     TermsCombo: TDBComboBox;
  45.     PaymentCombo: TDBComboBox;
  46.     ShipViaCombo: TDBComboBox;
  47.     Speedbar: TPanel;
  48.     DBNavBtns: TDBNavigator;
  49.     SaleDateEdit: TDBEdit;
  50.     OrderNoEdit: TDBEdit;
  51.     InvisiblePanel: TPanel;
  52.     DBEditBtns: TDBNavigator;
  53.     OrdersOrderNo: TFloatField;
  54.     OrdersCustNo: TFloatField;
  55.     OrdersShipToContact: TStringField;
  56.     OrdersShipToAddr1: TStringField;
  57.     OrdersShipToAddr2: TStringField;
  58.     OrdersShipToCity: TStringField;
  59.     OrdersShipToState: TStringField;
  60.     OrdersShipToZip: TStringField;
  61.     OrdersShipToCountry: TStringField;
  62.     OrdersShipToPhone: TStringField;
  63.     OrdersShipVIA: TStringField;
  64.     OrdersPO: TStringField;
  65.     OrdersTerms: TStringField;
  66.     OrdersPaymentMethod: TStringField;
  67.     OrdersItemsTotal: TCurrencyField;
  68.     OrdersTaxRate: TFloatField;
  69.     OrdersFreight: TCurrencyField;
  70.     OrdersAmountPaid: TCurrencyField;
  71.     CustCustNo: TFloatField;
  72.     CustCompany: TStringField;
  73.     CustAddr1: TStringField;
  74.     CustAddr2: TStringField;
  75.     CustCity: TStringField;
  76.     CustState: TStringField;
  77.     CustZip: TStringField;
  78.     CustCountry: TStringField;
  79.     CustPhone: TStringField;
  80.     CustTaxRate: TFloatField;
  81.     CustContact: TStringField;
  82.     ItemsItemNo: TFloatField;
  83.     ItemsOrderNo: TFloatField;
  84.     ItemsPartNo: TFloatField;
  85.     ItemsQty: TIntegerField;
  86.     ItemsSellPrice: TCurrencyField;
  87.     ItemsDiscount: TFloatField;
  88.     PartsDescription: TStringField;
  89.     ActiveSource: TDataSource;
  90.     CustUpdate: TTable;
  91.     CustUpdateCustNo: TFloatField;
  92.     ItemsExtPrice: TCurrencyField;
  93.     OrdersAmountDue: TCurrencyField;
  94.     CustNoEdit: TDBEdit;
  95.     OrdersSaleDate: TDateTimeField;
  96.     OrdersShipDate: TDateTimeField;
  97.     OrdersEmpNo: TIntegerField;
  98.     CustLastInvoiceDate: TDateTimeField;
  99.     CustFAX: TStringField;
  100.     ItemsDescription: TStringField;
  101.     SoldByEdit: TDBLookupCombo;
  102.     Emps: TTable;
  103.     EmpsSource: TDataSource;
  104.     EmpsEmpNo: TIntegerField;
  105.     EmpsLastName: TStringField;
  106.     EmpsFirstName: TStringField;
  107.     EmpsPhoneExt: TStringField;
  108.     EmpsHireDate: TDateTimeField;
  109.     EmpsSalary: TFloatField;
  110.     EmpsFullName: TStringField;
  111.     CustUpdateLastInvoiceDate: TDateTimeField;
  112.     ItemsGrid: TDBGrid;
  113.     AmountPaidEdit: TDBEdit;
  114.     TotalEdit: TDBEdit;
  115.     TaxTotalEdit: TDBEdit;
  116.     FreightEdit: TDBEdit;
  117.     AmountDueEdit: TDBEdit;
  118.     TaxRateEdit: TDBEdit;
  119.     CloseBtn: TButton;
  120.     CancelBtn: TButton;
  121.     PostBtn: TButton;
  122.     BrowsePartsBtn: TSpeedButton;
  123.     SearchCustBtn: TSpeedButton;
  124.     PopupCalBtn: TSpeedButton;
  125.     Image1: TImage;
  126.     PrintBtn: TSpeedButton;
  127.     LastItemQuery: TQuery;
  128.     Label7: TLabel;
  129.     procedure FormCreate(Sender: TObject);
  130.     procedure OrdersCalcFields(DataSet: TDataSet);
  131.     procedure OrdersAfterPost(DataSet: TDataSet);
  132.     procedure ItemsCalcFields(DataSet: TDataSet);
  133.     procedure ItemsBeforeEdit(DataSet: TDataSet);
  134.     procedure ItemsBeforeInsert(DataSet: TDataset);
  135.     procedure ItemsAfterPost(DataSet: TDataSet);
  136.     procedure OrdersNewRecord(DataSet: TDataSet);
  137.     procedure ItemsNewRecord(DataSet: TDataSet);
  138.     procedure ItemsAfterDelete(DataSet: TDataSet);
  139.     procedure ItemsBeforePost(DataSet: TDataSet);
  140.     procedure ItemsAfterInsert(DataSet: TDataset);
  141.     procedure PickPartNo(Sender: TObject);
  142.     procedure OrdersAfterCancel(DataSet: TDataSet);
  143.     procedure OrdersBeforeDelete(DataSet: TDataSet);
  144.     procedure OrdersCustNoChange(Sender: TField);
  145.     procedure ItemsGridEnter(Sender: TObject);
  146.     procedure ActiveSourceStateChange(Sender: TObject);
  147.     procedure ItemsSourceStateChange(Sender: TObject);
  148.     procedure PickCustNo(Sender: TObject);
  149.     procedure ItemsGridExit(Sender: TObject);
  150.     procedure OrdersBeforeCancel(DataSet: TDataset);
  151.     procedure EmpsCalcFields(DataSet: TDataset);
  152.     procedure CancelBtnClick(Sender: TObject);
  153.     procedure OrdersSourceStateChange(Sender: TObject);
  154.     procedure PostBtnClick(Sender: TObject);
  155.     procedure CloseBtnClick(Sender: TObject);
  156.     procedure OrdersBeforeOpen(DataSet: TDataset);
  157.     procedure ItemsBeforeOpen(DataSet: TDataset);
  158.     procedure OrdersSaleDateValidate(Sender: TField);
  159.     procedure CustNoEditKeyPress(Sender: TObject; var Key: Char);
  160.     procedure OrdersCustNoValidate(Sender: TField);
  161.     procedure OrdersFreightValidate(Sender: TField);
  162.     procedure ItemsPartNoValidate(Sender: TField);
  163.     procedure ItemsQtyValidate(Sender: TField);
  164.     procedure ItemsBeforeClose(DataSet: TDataset);
  165.     procedure OrdersBeforeInsert(DataSet: TDataset);
  166.     procedure OrdersBeforeClose(DataSet: TDataset);
  167.     procedure OrdersAfterDelete(DataSet: TDataset);
  168.     procedure BrowsePartsBtnClick(Sender: TObject);
  169.     procedure ItemsGridKeyPress(Sender: TObject; var Key: Char);
  170.     procedure PickDate(Sender: TObject);
  171.     procedure FormClose(Sender: TObject; var Action: TCloseAction);
  172.     procedure PrintBtnClick(Sender: TObject);
  173.     procedure SaleDateEditKeyPress(Sender: TObject; var Key: Char);
  174.     procedure ItemsBeforeDelete(DataSet: TDataset);
  175.   private
  176.   { Used to update Parts.OnOrder after an edited Item has been posted }
  177.     PrevPartNo: Double;            { remembers Item's previous part# }
  178.     PrevQty: Longint;            { remembers Item's previous qty }
  179.     DeletingItems: Boolean;        { suppress totals calc. if deleting items }
  180.     AddedItems: Boolean;        { flag: only prompt Orders.Cancel if items were added }
  181.     NoCommit: Boolean;                  { flag: don't commit wwhen posting on order insertion }
  182.     procedure UpdateTotals;
  183.     procedure DeleteItems;
  184.   public
  185.     procedure Enter;
  186.     procedure Edit(OrderNo: Double);
  187.   end;
  188.  
  189. var
  190.   OrderForm: TOrderForm;
  191.  
  192. implementation
  193.  
  194. uses Main, BrModal, CustOrd,  Pickdate, edCust;
  195.  
  196. {$R *.DFM}
  197.  
  198. const
  199.   DatasetStates: array[TDataSetState] of string[11] =
  200.     ('Not active', 'Browsing', 'Editing', 'Inserting',
  201.     'Setting key', 'Calculating');
  202.   HelpTopicEdit = 2;
  203.   HelpTopicBrowse = 3;
  204.  
  205.  
  206. procedure TOrderForm.FormCreate(Sender: TObject);
  207. begin
  208.   Orders.Open;
  209. end;
  210.  
  211. procedure TOrderForm.FormClose(Sender: TObject; var Action: TCloseAction);
  212. begin
  213.   if Orders.State in [dsEdit, dsInsert] then
  214.   begin
  215.     MessageDlg('Cancel edits or post this order before closing',
  216.       mtInformation, [mbOK], 0);
  217.     Action := caNone;
  218.     Exit;
  219.   end;
  220.   Orders.Close;
  221.   if MainForm.Database.IsSQLbased then MainForm.Database.Commit;
  222. end;
  223.  
  224.  
  225. {+++++++++++++  PUBLIC methods  ++++++++++++++++}
  226.  
  227. { On SQL databases, always start a transaction before any tables are open and
  228.   ensure that there is always an active transaction by starting one here and
  229.   restarting one after a commit or rollback. }
  230. procedure TOrderForm.Enter;
  231. begin
  232.   if MainForm.Database.IsSQLbased then Mainform.Database.StartTransaction;
  233.   Orders.Open;
  234.   Orders.Insert;
  235.   ShowModal;
  236. end;
  237.  
  238. { On SQL databases, always start a transaction before any tables are open and
  239.   ensure that there is always an active transaction by starting one here and
  240.   restarting one after a commit or rollback. }
  241. procedure TOrderForm.Edit(OrderNo: Double);
  242. begin
  243.   if MainForm.Database.IsSQLbased then Mainform.Database.StartTransaction;
  244.   Orders.Open;
  245.   Orders.FindKey([OrderNo]);
  246.   ShowModal;
  247. end;
  248.  
  249. {+++++++++++++  field calculation routines  ++++++++++++++++}
  250.  
  251. { Calculate the order's tax totals and amount due }
  252. procedure TOrderForm.OrdersCalcFields(DataSet: TDataSet);
  253. begin
  254.   OrdersTaxTotal.Value := OrdersItemsTotal.Value * (OrdersTaxRate.Value / 100);
  255.   OrdersAmountDue.Value := OrdersItemsTotal.Value + OrdersTaxTotal.Value +
  256.     OrdersFreight.Value - OrdersAmountPaid.Value;
  257. end;
  258.  
  259. { Concatenate last name + first name for the order's SoldBy DBLookupCombo }
  260. procedure TOrderForm.EmpsCalcFields(DataSet: TDataset);
  261. begin
  262.   EmpsFullName.Value := Format('%s, %s', [EmpsLastName.Value, EmpsFirstName.Value]);
  263. end;
  264.  
  265. { Lookup PartNo info for the item; calculate its extended price }
  266. procedure TOrderForm.ItemsCalcFields(DataSet: TDataSet);
  267. begin
  268.   if Parts.FindKey([ItemsPartNo]) then
  269.   begin
  270.     ItemsDescription.Value := PartsDescription.Value;
  271.     ItemsSellPrice.Value := PartsListPrice.Value;
  272.   end;
  273.   ItemsExtPrice.Value := ItemsQty.Value *
  274.     ItemsSellPrice.Value * (100 - ItemsDiscount.Value) / 100;
  275. end;
  276.  
  277. { Steps through Items and gathers sum of ExtPrice. After OrdersItemsTotal
  278.   is calculated, OrdersCalcFields is automatically called (which
  279.   updates other calculated fields. }
  280. procedure TOrderForm.UpdateTotals;
  281. var
  282.   TempTotal: Extended;
  283.   PrevRecord: TBookmark;
  284. begin
  285.   if DeletingItems then Exit;        { don't calculate if deleting all items }
  286.   PrevRecord := Items.GetBookmark;    { returns nil if table is empty }
  287.   try
  288.     Items.DisableControls;
  289.     Items.First;
  290.     TempTotal := 0;            { use temp for efficiency }
  291.     while not Items.EOF do
  292.     begin
  293.       TempTotal := TempTotal + ItemsExtPrice.Value;
  294.       Items.Next;
  295.     end;
  296.     OrdersItemsTotal.Value := TempTotal;
  297.   finally
  298.      Items.EnableControls;
  299.      if PrevRecord <> nil then
  300.      begin
  301.        Items.GoToBookmark(PrevRecord);
  302.        Items.FreeBookmark(PrevRecord);
  303.      end;
  304.   end;
  305. end;
  306.  
  307. {+++++++++++++  orders routines  ++++++++++++++++}
  308.  
  309. { Inititializes the record values as a result of an Orders.Insert.
  310.   Gets a unique OrderNo. On SQL databases, a transaction is active. Commit
  311.   the post of the NextOrd table and then start another transaction. }
  312. procedure TOrderForm.OrdersNewRecord(DataSet: TDataSet);
  313. begin
  314.   { get next OrderNo }
  315.   NextOrd.Open;                                { open = exclusive }
  316.   NextOrd.Edit;
  317.   try
  318.     OrdersOrderNo.Value := NextOrdNewKey.Value;
  319.     NextOrdNewKey.Value := NextOrdNewKey.Value + 1;
  320.     NextOrd.Post;                              { release lock }
  321.     if MainForm.Database.IsSQLbased then
  322.     begin
  323.       MainForm.Database.Commit;
  324.       MainForm.Database.StartTransaction;
  325.     end;
  326.   finally
  327.     NextOrd.Cancel;
  328.     NextOrd.Close;
  329.   end;
  330.   OrdersSaleDate.Value := Date;
  331.   OrdersShipVia.Value := 'UPS';
  332.   OrdersTerms.Value := 'net 30';
  333.   OrdersPaymentMethod.Value := 'Check';
  334.   OrdersItemsTotal.Value := 0;
  335.   OrdersTaxRate.Value := 0;
  336.   OrdersFreight.Value := 0;
  337.   OrdersAmountPaid.Value := 0;
  338.   AddedItems := False;        { clear flag }
  339. end;
  340.  
  341. { Post new LastInvoiceDate to CUST table. On SQL databases, commit the
  342.   transaction and start another one. }
  343. procedure TOrderForm.OrdersAfterPost(DataSet: TDataSet);
  344. begin
  345.   if (CustUpdate.FindKey([OrdersCustNo])) and
  346.     (CustUpdateLastInvoiceDate.Value < OrdersShipDate.Value) then
  347.   begin
  348.     CustUpdate.Edit;
  349.     CustUpdateLastInvoiceDate.Value := OrdersShipDate.Value;
  350.     CustUpdate.Post;
  351.   end;
  352.   if MainForm.Database.IsSQLbased and (not NoCommit) then
  353.   begin
  354.     MainForm.Database.Commit;
  355.     MainForm.Database.StartTransaction;
  356.   end;
  357. end;
  358.  
  359. { On SQL databases, whether inserting or editing, use transaction
  360.   processing to cancel all changes. On desktop databases, delete all the
  361.   items (for new orders only). Note when an existing order on desktop
  362.   databases, all changes to the items table (insert, delete, edit)
  363.   are permanent. }
  364. procedure TOrderForm.OrdersAfterCancel(DataSet: TDataSet);
  365. begin
  366.   if MainForm.Database.IsSQLbased then
  367.   begin
  368.     MainForm.Database.Rollback;
  369.     Orders.Refresh;
  370.     Items.Refresh;
  371.     MainForm.Database.StartTransaction;
  372.   end
  373.   else if Orders.State = dsInsert then DeleteItems; { new orders only }
  374. end;
  375.  
  376. procedure TOrderForm.OrdersBeforeDelete(DataSet: TDataSet);
  377. begin
  378.   if MessageDlg('Delete order and line items?',
  379.     mtConfirmation, [mbYes,MbNo], 0) <> mrYes then Abort;
  380.   DeleteItems;
  381. end;
  382.  
  383. { New customer: clear SHIP TO fields, get TaxRate }
  384. procedure TOrderForm.OrdersCustNoChange(Sender: TField);
  385. begin
  386.   OrdersShipToContact.Value := '';
  387.   OrdersShipToPhone.Value := '';
  388.   OrdersShipToAddr1.Value := '';
  389.   OrdersShipToAddr2.Value := '';
  390.   OrdersShipToCity.Value := '';
  391.   OrdersShipToState.Value := '';
  392.   OrdersShipToZip.Value := '';
  393.   OrdersShipToCountry.Value := '';
  394.   OrdersTaxRate.Value := CustTaxRate.Value;
  395. end;
  396.  
  397. procedure TOrderForm.OrdersBeforeInsert(DataSet: TDataset);
  398. begin
  399.   if Orders.State in [dsInsert, dsEdit] then
  400.   begin
  401.     if MessageDlg('An order is being processed. Post changes before inserting new order?',
  402.       mtInformation, mbOKCancel, 0) = mrOK then Orders.Post
  403.     else Abort;
  404.   end;
  405. end;
  406.  
  407. procedure TOrderForm.OrdersBeforeClose(DataSet: TDataset);
  408. begin
  409.   Items.Close;
  410.   Emps.Close;
  411.   CustUpdate.Close;
  412.   Cust.Close;
  413. end;
  414.  
  415. { On SQL databases, commit the delete and start another transaction. }
  416. procedure TOrderForm.OrdersAfterDelete(DataSet: TDataset);
  417. begin
  418.   if MainForm.Database.IsSQLbased then
  419.   begin
  420.     MainForm.Database.Commit;
  421.     MainForm.Database.StartTransaction;
  422.   end;
  423. end;
  424.  
  425. procedure TOrderForm.OrdersBeforeCancel(DataSet: TDataset);
  426. begin
  427.   if (Orders.State = dsInsert) and not (Items.BOF and Items.EOF) then
  428.     if MessageDlg('Cancel order being inserted and delete all line items?',
  429.     mtConfirmation, mbOKCancel, 0) <> mrOk then Abort;
  430. end;
  431.  
  432. {+++++++++++++  items routines  ++++++++++++++++}
  433.  
  434. procedure TOrderForm.ItemsAfterDelete(DataSet: TDataSet);
  435. begin
  436.   UpdateTotals;
  437. end;
  438.  
  439. { New item. Zero the "prev" buckets, initialize the key }
  440. procedure TOrderForm.ItemsNewRecord(DataSet: TDataSet);
  441. begin
  442.   PrevPartNo := 0;
  443.   PrevQty := 0;
  444.   ItemsOrderNo.Value := OrdersOrderNo.Value;
  445.   ItemsQty.Value := 1;
  446.   ItemsDiscount.Value := 0;
  447. end;
  448.  
  449. {  When a change to the detail table affects a field in the master, always make
  450.   sure the master table is in edit or insert mode before allowing the
  451.   detail table to be modified. }
  452. procedure TOrderForm.ItemsBeforeDelete(DataSet: TDataset);
  453. begin
  454.   Orders.Edit;
  455. end;
  456.  
  457. { Remember previous PartNo and Qty for updating Parts.OnOrder after post.
  458.   When a change to the detail table affects a field in the master, always make
  459.   sure the master table is in edit or insert mode before allowing the
  460.   detail table to be modified. }
  461. procedure TOrderForm.ItemsBeforeEdit(DataSet: TDataSet);
  462. begin
  463.   Orders.Edit;
  464.   PrevPartNo := ItemsPartNo.Value;
  465.   PrevQty := ItemsQty.Value;
  466. end;
  467.  
  468. { For data integrity purposes:
  469.  
  470.     o On SQL databases: the order must exist before an item may be posted;
  471.       if the user selects CANCEL, rollback will be used to back out all changes.
  472.     o On the desktop, force a valid customer number before allowing a new item;
  473.       if the user selects CANCEL, all items will be deleted.
  474.  
  475.   When a change to the detail table affects a field in the master, always make
  476.   sure the master table is in edit or insert mode before allowing the
  477.   detail table to be modified.
  478. }
  479. procedure TOrderForm.ItemsBeforeInsert(DataSet: TDataset);
  480. begin
  481.   if Orders.State = dsInsert then
  482.   begin
  483.     { Don't commit until the whole order is ready, but for SQL and non-SQL,
  484.       referential integrity requires the master posted before a detail. }
  485.     NoCommit := True;
  486.     Orders.Post;
  487.     Orders.Edit;
  488.     NoCommit := False;
  489.   end else Orders.Edit;
  490. end;
  491.  
  492. { Update the order totals and the Parts table }
  493. procedure TOrderForm.ItemsAfterPost(DataSet: TDataSet);
  494.  
  495. { Reduce/increase Parts table's OnOrder field }
  496. procedure UpdateParts(PartNo: Double; Qty : Longint);
  497. var DisplayVerb: string[10];
  498. begin
  499.   if Qty < 0 then DisplayVerb := 'reducing'
  500.   else DisplayVerb := 'increasing';
  501.   try
  502.     if not Parts.FindKey([ItemsPartNo]) then
  503.       raise Exception.CreateFmt('Cannot find PartNo %G', [ItemsPartNo.Value]);
  504.     Parts.Edit;
  505.     PartsOnOrder.Value := PartsOnOrder.Value + ItemsQty.Value;
  506.     Parts.Post;
  507.   except
  508.     on E: Exception do
  509.       ShowMessage(
  510.         Format('The following error occurred while %S PartNo %G''s OnOrder field by %D units: %S',
  511.           [DisplayVerb, PartNo, Qty, E.Message]));
  512.   end;
  513. end;
  514.  
  515. begin
  516.   UpdateTotals;
  517.   { Reduce previous Part#'s OnOrder field by previous Qty }
  518.   UpdateParts(PrevPartNo, PrevQty);
  519.   { Increase Part#'s OnOrder by new Qty }
  520.   UpdateParts(ItemsPartNo.Value, ItemsQty.Value);
  521. end;
  522.  
  523. { Complete the item's key by initializing its NextItemNo field }
  524. procedure TOrderForm.ItemsBeforePost(DataSet: TDataSet);
  525. begin
  526.   if Items.State = dsInsert then              { fetch new ItemNo for the key }
  527.   begin
  528.     LastItemQuery.Close;
  529.     LastItemQuery.Open;
  530.     { SQL servers return Null for some aggregates if no items are present }
  531.     with LastItemQuery.Fields[0] do
  532.       if IsNull then ItemsItemNo.Value := 1
  533.       else ItemsItemNo.Value := AsFloat + 1;
  534.   end;
  535. end;
  536.  
  537. procedure TOrderForm.DeleteItems;
  538. begin
  539.   DeletingItems := True;    { suppress recalc of totals during delete }
  540.   Items.DisableControls;        { for faster table traversal }
  541.   try
  542.     Items.First;
  543.     while not Items.EOF do Items.Delete;
  544.   finally
  545.     DeletingItems := False;
  546.     Items.EnableControls;       { always re-enable controls after disabling }
  547.   end;
  548. end;
  549.  
  550. { This two methods enable the navigators to service both the Orders
  551.   and Items tables by switching the ActiveSource between them. }
  552. procedure TOrderForm.ItemsGridEnter(Sender: TObject);
  553. begin
  554.   ActiveSource.Dataset := Items;
  555.   BrowsePartsBtn.Enabled := True;
  556. end;
  557.  
  558. procedure TOrderForm.ItemsGridExit(Sender: TObject);
  559. begin
  560.   ActiveSource.Dataset := Orders;
  561.   BrowsePartsBtn.Enabled := False;
  562. end;
  563.  
  564. {+++++++++++++  state change routines  ++++++++++++++++}
  565.  
  566. procedure TOrderForm.ActiveSourceStateChange(Sender: TObject);
  567. begin
  568.   with ActiveSource do
  569.   begin
  570.     if Dataset <> nil then ModeIndicator.Caption :=
  571.       Format('[%S: %S]', [Dataset.Name, DatasetStates[State]]);
  572.     if State in [dsEdit, dsInsert] then
  573.     begin
  574.       HelpContext := HelpTopicEdit;
  575.       ModeIndicator.Font.Color := clRed;
  576.     end
  577.     else
  578.     begin
  579.       HelpContext := HelpTopicBrowse;
  580.       ModeIndicator.Font.Color := clBlue;
  581.     end;
  582.   end;
  583. end;
  584.  
  585. { Tab exits grid when browsing, goes to next column when editing/inserting }
  586. procedure TOrderForm.ItemsSourceStateChange(Sender: TObject);
  587. begin
  588.   if Items.State = dsBrowse then ItemsGrid.Options := ItemsGrid.Options - [dgTabs]
  589.   else ItemsGrid.Options := ItemsGrid.Options + [dgTabs];
  590. end;
  591.  
  592. { Manage the enabling and disabling of the order form's buttons }
  593. procedure TOrderForm.OrdersSourceStateChange(Sender: TObject);
  594. begin
  595.   PostBtn.Enabled := Orders.State in [dsEdit, dsInsert];
  596.   CancelBtn.Enabled := PostBtn.Enabled;
  597.   CloseBtn.Enabled := Orders.State = dsBrowse;
  598. end;
  599.  
  600. {+++++++++++++  table open/close routines  ++++++++++++++++}
  601.  
  602. { These open and close routines "cascade" (opening Orders opens Items first,
  603.   which first opens Parts, etc.) }
  604. procedure TOrderForm.OrdersBeforeOpen(DataSet: TDataset);
  605. begin
  606.   Cust.Open;
  607.   CustUpdate.Open;
  608.   Emps.Open;
  609.   Items.Open;
  610. end;
  611.  
  612. procedure TOrderForm.ItemsBeforeOpen(DataSet: TDataset);
  613. begin
  614.   Parts.Open;
  615. end;
  616.  
  617. procedure TOrderForm.ItemsBeforeClose(DataSet: TDataset);
  618. begin
  619.   Parts.Close;
  620. end;
  621.  
  622. { Set flag used for deletion }
  623. procedure TOrderForm.ItemsAfterInsert(DataSet: TDataset);
  624. begin
  625.   AddedItems := True;
  626. end;
  627.  
  628. {+++++++++++++  validation routines  ++++++++++++++++}
  629.  
  630. { Alternatively, could set the Qty field's Min and Max values in code
  631.   or in the Object Inspector. }
  632. procedure TOrderForm.ItemsQtyValidate(Sender: TField);
  633. begin
  634.   if ItemsQty.Value < 1 then raise Exception.Create('Must specify quantity');
  635. end;
  636.  
  637. procedure TOrderForm.OrdersCustNoValidate(Sender: TField);
  638. begin
  639.   if not CustUpdate.FindKey([OrdersCustNo]) then
  640.   begin
  641.     CustNoEdit.SetFocus;
  642.     raise Exception.Create('You must specify a valid CustNo.'#10 +
  643.       'Click the search button to pick from a list');
  644.   end;
  645. end;
  646.  
  647. { Alternatively, could set the Freight field's Min and Max values in code
  648.   or in the Object Inspector. }
  649. procedure TOrderForm.OrdersFreightValidate(Sender: TField);
  650. begin
  651.   if OrdersFreight.Value < 0 then
  652.     raise Exception.Create('Freight cannot be less than zero');
  653. end;
  654.  
  655. procedure TOrderForm.ItemsPartNoValidate(Sender: TField);
  656. begin
  657.   if not Parts.FindKey([ItemsPartNo]) then
  658.     raise Exception.Create('You must specify a valid PartNo');
  659. end;
  660.  
  661. procedure TOrderForm.OrdersSaleDateValidate(Sender: TField);
  662. begin
  663.   if OrdersSaleDate.Value > Now then
  664.     raise Exception.Create('Cannot enter a future date');
  665. end;
  666.  
  667. {+++++++++++++  Click events  ++++++++++++++++}
  668.  
  669. { Browse a calendar to pick an invoice date }
  670. procedure TOrderForm.PickDate(Sender: TObject);
  671. begin
  672.   BrDateForm.Date := OrdersSaleDate.Value;     { start with current date }
  673.   if BrDateForm.ShowModal = mrOk then
  674.   begin
  675.     Orders.Edit;
  676.     OrdersSaleDate.Value := BrDateForm.Date;
  677.     SaleDateEdit.SelectAll;
  678.   end;
  679. end;
  680.  
  681. { Browse Cust table, fetch CustNo }
  682. procedure TOrderForm.PickCustNo(Sender: TObject);
  683. begin
  684.   if OrdersCustNo.Value <> 0 then
  685.     PickDlg.CustNo := OrdersCustNo.Value;    { start with current CustNo }
  686.   if PickDlg.ShowModalCust = mrOk then
  687.   begin
  688.     Orders.Edit;
  689.     OrdersCustNo.Value := PickDlg.CustNo;
  690.     CustNoEdit.SelectAll;
  691.   end;
  692. end;
  693.  
  694. { Browse Parts table, fetch PartNo }
  695. procedure TOrderForm.PickPartNo(Sender: TObject);
  696. begin
  697.   if ItemsGrid.SelectedField = ItemsPartNo then    { PartNo column only }
  698.   begin
  699.     if ItemsPartNo.Value <> 0 then
  700.       PickDlg.PartNo := ItemsPartNo.Value;    { start with current PartNo }
  701.     if PickDlg.ShowModalParts = mrOk then
  702.     begin
  703.       Items.Edit;
  704.       ItemsPartNo.Value := PickDlg.PartNo;
  705.     end;
  706.   end;
  707. end;
  708.  
  709. { Ctrl+Enter in the SaleDate edit control brings up PickDate dialog }
  710. procedure TOrderForm.SaleDateEditKeyPress(Sender: TObject; var Key: Char);
  711. begin
  712.   if Key = ^J then
  713.   begin
  714.     PickDate(Sender);
  715.     Key := #0;
  716.   end;
  717. end;
  718.  
  719. { Ctrl+Enter in the CustNo edit control brings up PickCustNo dialog }
  720. procedure TOrderForm.CustNoEditKeyPress(Sender: TObject; var Key: Char);
  721. begin
  722.   if Key = ^J then
  723.   begin
  724.     PickCustNo(Sender);
  725.     Key := #0;
  726.   end;
  727. end;
  728.  
  729. { Ctrl+Enter in the PartNo column of the items grid brings up PickPartNo dialog }
  730. procedure TOrderForm.ItemsGridKeyPress(Sender: TObject; var Key: Char);
  731. begin
  732.   if (ItemsGrid.SelectedField = ItemsPartNo) and (Key = ^J) then
  733.   begin
  734.     PickPartNo(Sender);
  735.     Key := #0;
  736.   end;
  737. end;
  738.  
  739. { Clicking on the PARTS button brings up PickPartNo dialog }
  740. procedure TOrderForm.BrowsePartsBtnClick(Sender: TObject);
  741. begin
  742.   ItemsGrid.SelectedField := ItemsPartNo;
  743.   PickPartNo(nil);
  744. end;
  745.  
  746. { Begins a series of cascading Before and After post events }
  747. procedure TOrderForm.PostBtnClick(Sender: TObject);
  748. begin
  749.   Orders.Post;
  750. end;
  751.  
  752. { Closes the form window. Only enabled if the order is in browse mode }
  753. procedure TOrderForm.CloseBtnClick(Sender: TObject);
  754. begin
  755.   Close;
  756. end;
  757.  
  758. { Cancels insert or edit on the Orders table }
  759. procedure TOrderForm.CancelBtnClick(Sender: TObject);
  760. begin
  761.   Orders.Cancel;
  762. end;
  763.  
  764. { Prints snapshot of the form. An invoice report is available via the Main window }
  765. procedure TOrderForm.PrintBtnClick(Sender: TObject);
  766. begin
  767.   if MessageDlg('Print image of this form window?', mtConfirmation,
  768.     [mbYes, mbNo], 0) = mrYes then Print;
  769. end;
  770.  
  771.  
  772. end.
  773.