3.9.4. Doing the Work

Four operations are provided for working with the invoice header: adding, editing, deleting and setting the “paid” attribute. Once an invoice is paid, we prevent any modifications to either the header or the lines. The rule is implemented at stored procedure level. Let’s examine the query strings in the CommandText property for calling the stored procedures.

qryAddInvoice.CommandText

  1. EXECUTE PROCEDURE sp_add_invoice(
  2. NEXT VALUE FOR gen_invoice_id,
  3. :CUSTOMER_ID,
  4. :INVOICE_DATE
  5. )

qryEditInvoice.CommandText

  1. EXECUTE PROCEDURE sp_edit_invoice(
  2. :INVOICE_ID,
  3. :CUSTOMER_ID,
  4. :INVOICE_DATE
  5. )

qryDeleteInvoice.CommandText

  1. EXECUTE PROCEDURE sp_delete_invoice(:INVOICE_ID)

qryPayForInvoice.CommandText

  1. EXECUTE PROCEDURE sp_pay_for_invoice(:invoice_id)

Since our stored procedures are not called from a TFDUpdateSQL object, we need to call qryInvoice.Refresh after they are executed, in order to update the data in the grid.

Stored procedures that do not require input data from the user are called as follows:

  1. procedure TdmInvoice.DeleteInvoice;
  2. begin
  3. // We do everything in a short transaction
  4. trWrite.StartTransaction;
  5. try
  6. qryDeleteInvoice.ParamByName('INVOICE_ID').AsInteger :=
  7. Invoice.INVOICE_ID.Value;
  8. qryDeleteInvoice.Execute;
  9. trWrite.Commit;
  10. qryInvoice.Refresh;
  11. except
  12. on E: Exception do
  13. begin
  14. if trWrite.Active then
  15. trWrite.Rollback;
  16. raise;
  17. end;
  18. end;
  19. end;

Getting User Confirmation

Before performing some operations, such as deleting an invoice, we want to get confirmation from the user:

  1. procedure TInvoiceForm.actDeleteInvoiceExecute(Sender: TObject);
  2. begin
  3. if MessageDlg('Are you sure you want to delete an invoice?',
  4. mtConfirmation,
  5. [mbYes, mbNo], 0) = mrYes then
  6. begin
  7. Invoices.DeleteInvoice;
  8. end;
  9. end;

Adding or Editing Records

As with the primary modules, we will use modal forms to add a new record or edit an existing one. We will not use data-aware visual components in this implementation. As another variation, we will use a TButtonedEdit component to select a customer. It will display the name of the current customer and open a modal form with a grid for selecting a customer on the click of the embedded button. We could use something like TDBLookupCombobox, of course, but it has drawbacks: first, the customer list may be too large for scrolling comfortably through the drop-down list; secondly, the name alone may not be enough to find the customer you want.

fbdevgd30 delphi 008

Figure 9. The Customer input form

As the window for selecting a customer, we will use the same modal form that was created for adding customers. The code for the button click handler for the TButtonedEdit component is as follows:

  1. procedure TEditInvoiceForm.edtCustomerRightButtonClick(Sender: TObject);
  2. var
  3. xSelectForm: TCustomerForm;
  4. begin
  5. xSelectForm := TCustomerForm.Create(Self);
  6. try
  7. xSelectForm.Visible := False;
  8. if xSelectForm.ShowModal = mrOK then
  9. begin
  10. FCustomerId := xSelectForm.Customers.Customer.CUSTOMER_ID.Value;
  11. edtCustomer.Text := xSelectForm.Customers.Customer.NAME.Value;
  12. end;
  13. finally
  14. xSelectForm.Free;
  15. end;
  16. end;

Since we are not using data-aware visual components, we need to initialize the customer code and name for displaying during the call to the edit form:

  1. procedure TInvoiceForm.actEditInvoiceExecute(Sender: TObject);
  2. var
  3. xEditorForm: TEditInvoiceForm;
  4. begin
  5. xEditorForm := TEditInvoiceForm.Create(Self);
  6. try
  7. xEditorForm.OnClose := EditInvoiceEditorClose;
  8. xEditorForm.Caption := 'Edit invoice';
  9. xEditorForm.InvoiceId := Invoices.Invoice.INVOICE_ID.Value;
  10. xEditorForm.SetCustomer(
  11. Invoices.Invoice.CUSTOMER_ID.Value,
  12. Invoices.Invoice.CUSTOMER_NAME.Value);
  13. xEditorForm.InvoiceDate := Invoices.Invoice.INVOICE_DATE.AsDateTime;
  14. xEditorForm.ShowModal;
  15. finally
  16. xEditorForm.Free;
  17. end;
  18. end;
  19. procedure TEditInvoiceForm.SetCustomer(ACustomerId: Integer;
  20. const ACustomerName: string);
  21. begin
  22. FCustomerId := ACustomerId;
  23. edtCustomer.Text := ACustomerName;
  24. end;

Adding a new invoice and editing an existing one will be handled in the Close event of the modal form as it is for the primary modules. However, we will not switch the dataset to CachedUpdates mode for these because the updates carried out by stored procedures and we are not using data-aware visual components to capture input.

  1. procedure TInvoiceForm.actAddInvoiceExecute(Sender: TObject);
  2. var
  3. xEditorForm: TEditInvoiceForm;
  4. begin
  5. xEditorForm := TEditInvoiceForm.Create(Self);
  6. try
  7. xEditorForm.Caption := 'Add invoice';
  8. xEditorForm.OnClose := AddInvoiceEditorClose;
  9. xEditorForm.InvoiceDate := Now;
  10. xEditorForm.ShowModal;
  11. finally
  12. xEditorForm.Free;
  13. end;
  14. end;
  15. procedure TInvoiceForm.AddInvoiceEditorClose(Sender: TObject;
  16. var Action: TCloseAction);
  17. var
  18. xEditorForm: TEditInvoiceForm;
  19. begin
  20. xEditorForm := TEditInvoiceForm(Sender);
  21. if xEditorForm.ModalResult <> mrOK then
  22. begin
  23. Action := caFree;
  24. Exit;
  25. end;
  26. try
  27. Invoices.AddInvoice(xEditorForm.CustomerId, xEditorForm.InvoiceDate);
  28. Action := caFree;
  29. except
  30. on E: Exception do
  31. begin
  32. Application.ShowException(E);
  33. // It does not close the window give the user correct the error
  34. Action := caNone;
  35. end;
  36. end;
  37. end;
  38. procedure TdmInvoice.AddInvoice(ACustomerId: Integer; AInvoiceDate: TDateTime);
  39. begin
  40. // We do everything in a short transaction
  41. trWrite.StartTransaction;
  42. try
  43. qryAddInvoice.ParamByName('CUSTOMER_ID').AsInteger := ACustomerId;
  44. qryAddInvoice.ParamByName('INVOICE_DATE').AsSqlTimeStamp :=
  45. DateTimeToSQLTimeStamp(AInvoiceDate);
  46. qryAddInvoice.Execute();
  47. trWrite.Commit;
  48. qryInvoice.Refresh;
  49. except
  50. on E: Exception do
  51. begin
  52. if trWrite.Active then
  53. trWrite.Rollback;
  54. raise;
  55. end;
  56. end;
  57. end;