Appendix

You might also like

Download as doc, pdf, or txt
Download as doc, pdf, or txt
You are on page 1of 100

Appendix: Complete Code Listings

Listing 1
/****** Object: Table [dbo].[Accounts] Script Date: 5/5/99 3:46:19 PM ******/
if exists (select * from sysobjects where id = object_id(N'[dbo].[Accounts]') and OBJECTPROPERTY(id, N'IsUserTable') =
1)
drop table [dbo].[Accounts]
GO

CREATE TABLE [dbo].[Accounts] (


[IDPK] [int] NOT NULL ,
[FirstName] [varchar] (20) NOT NULL ,
[LastName] [varchar] (40) NOT NULL ,
[AddressLine1] [varchar] (20) NOT NULL ,
[AddressLine2] [varchar] (20) NOT NULL ,
[City] [varchar] (20) NOT NULL ,
[State] [varchar] (2) NOT NULL ,
[Zip] [varchar] (5) NOT NULL ,
[Phone] [varchar] (12) NOT NULL ,
[Email] [varchar] (20) NOT NULL ,
[Balance] [money] NOT NULL ,
[Limit] [money] NOT NULL ,
CONSTRAINT [PK_Accounts] PRIMARY KEY NONCLUSTERED
(
[IDPK]
) ON [PRIMARY]
) ON [PRIMARY]
GO

Listing 2
/****** Object: Table [dbo].[Inventory] Script Date: 5/5/99 3:46:20 PM ******/
if exists (select * from sysobjects where id = object_id(N'[dbo].[Inventory]') and OBJECTPROPERTY(id, N'IsUserTable') =
1)
drop table [dbo].[Inventory]
GO

CREATE TABLE [dbo].[Inventory] (


[IDPK] [int] NOT NULL ,
[Description] [varchar] (50) NOT NULL ,
[Price] [money] NOT NULL ,
[QOH] [int] NOT NULL ,
CONSTRAINT [PK_Inventory] PRIMARY KEY NONCLUSTERED
(
[IDPK]
) ON [PRIMARY]
) ON [PRIMARY]
GO

Listing 3
/****** Object: Table [dbo].[PurchaseOrders] Script Date: 5/5/99 3:46:20 PM ******/
if exists (select * from sysobjects where id = object_id(N'[dbo].[PurchaseOrders]') and OBJECTPROPERTY(id,
N'IsUserTable') = 1)
drop table [dbo].[PurchaseOrders]
GO

CREATE TABLE [dbo].[PurchaseOrders] (


[IDPK] [int] NOT NULL ,
[AccountIDFK] [int] NOT NULL ,
[OrderDate] [datetime] NULL CONSTRAINT [DF_PurchaseOrders_OrderDate] DEFAULT (getdate()),
[ShippingHandling] [money] NOT NULL ,
[TaxRate] [real] NOT NULL ,
[Total] [money] NOT NULL ,
[ShipToFirstName] [varchar] (20) NOT NULL ,
[ShipToLastName] [varchar] (40) NOT NULL ,
[ShipToAddressLine1] [varchar] (20) NOT NULL ,
[ShipToAddressLine2] [varchar] (20) NOT NULL ,
[ShipToCity] [varchar] (20) NOT NULL ,
[ShipToState] [varchar] (2) NOT NULL ,
[ShipToZip] [varchar] (5) NOT NULL ,
[ShipToPhone] [varchar] (12) NOT NULL ,
[ShipToEmail] [varchar] (20) NOT NULL ,
CONSTRAINT [PK_PurchaseOrders] PRIMARY KEY NONCLUSTERED
(
[IDPK]
) ON [PRIMARY] ,
CONSTRAINT [FK_PurchaseOrders_Accounts] FOREIGN KEY
(
[AccountIDFK]
) REFERENCES [dbo].[Accounts] (
[IDPK]
)
) ON [PRIMARY]
GO

Listing 4
/****** Object: Table [dbo].[LineItems] Script Date: 5/5/99 3:46:20 PM ******/
if exists (select * from sysobjects where id = object_id(N'[dbo].[LineItems]') and OBJECTPROPERTY(id, N'IsUserTable') =
1)
drop table [dbo].[LineItems]
GO

CREATE TABLE [dbo].[LineItems] (


[IDPK] [int] NOT NULL ,
[PurchaseOrderIDFK] [int] NOT NULL ,
[InventoryIDFK] [int] NOT NULL ,
[Price] [money] NOT NULL ,
[Quantity] [int] NOT NULL ,
CONSTRAINT [PK_LineItems] PRIMARY KEY NONCLUSTERED
(
[IDPK]
) ON [PRIMARY] ,
CONSTRAINT [FK_LineItems_Inventory] FOREIGN KEY
(
[InventoryIDFK]
) REFERENCES [dbo].[Inventory] (
[IDPK]
),
CONSTRAINT [FK_LineItems_PurchaseOrders] FOREIGN KEY
(
[PurchaseOrderIDFK]
) REFERENCES [dbo].[PurchaseOrders] (
[IDPK]
)
) ON [PRIMARY]
GO

Listing 5
/****** Object: Table [dbo].[UniqueIDs] Script Date: 5/5/99 3:46:20 PM ******/
if exists (select * from sysobjects where id = object_id(N'[dbo].[UniqueIDs]') and OBJECTPROPERTY(id, N'IsUserTable')
= 1)
drop table [dbo].[UniqueIDs]
GO

CREATE TABLE [dbo].[UniqueIDs] (


[StartingIDofCurrentBatch] [int] NOT NULL ,
CONSTRAINT [PK_AccountUniqueIDs] PRIMARY KEY NONCLUSTERED
(
[StartingIDofCurrentBatch]
) ON [PRIMARY]
) ON [PRIMARY]
GO

Listing 6
' IAccount
Option Explicit

Public ID As Long
Public FirstName As String
Public LastName As String
Public AddressLine1 As String
Public AddressLine2 As String
Public City As String
Public State As String
Public Zip As String
Public Phone As String
Public Email As String
Public Balance As Currency
Public Limit As Currency

Public Function MarshalToPropertyBag(strKey As String) As Byte()

End Function

Public Property Get Valid() As Boolean

End Property

Listing 7
' IAccountExec
Option Explicit

Public Function CreateRecordset(Optional ByVal strFilter As String = "") As Recordset

End Function

Public Function Create(rIAccount As IAccount, Optional ByVal blnByVal As Boolean = True) As Boolean

End Function

Public Function Destroy(ByVal lngAccountID As Long) As Boolean

End Function

Public Function Modify(rIAccount As IAccount, Optional ByVal blnByVal As Boolean = True) As Boolean

End Function

Public Function IncrementBalance(ByVal lngAccountID As Long, ByVal curAmount As Currency) As Boolean

End Function

Public Function DecrementBalance(ByVal lngAccountID As Long, ByVal curAmount As Currency) As Boolean

End Function

Listing 8
' IInventory
Option Explicit

Public ID As Long
Public Description As String
Public Price As Currency
Public QOH As Long

Public Function MarshalToPropertyBag(strKey As String) As Byte()

End Function

Public Property Get Valid() As Boolean

End Property

Listing 9
' IInventoryExec
Option Explicit

Public Function CreateRecordset(Optional ByVal strFilter As String = "") As Recordset

End Function
Public Function Create(rIInventory As IInventory, Optional ByVal blnByVal As Boolean = True) As Boolean

End Function

Public Function Destroy(ByVal lngInventoryID As Long) As Boolean

End Function

Public Function IncrementQOH(ByVal lngInventoryID As Long, ByVal lngQuantity As Long) As Boolean

End Function

Public Function DecrementQOH(ByVal lngInventoryID As Long, ByVal lngQuantity As Long) As Boolean

End Function

Public Function Modify(rIInventory As IInventory, Optional ByVal blnByVal As Boolean = True) As Boolean

End Function

Listing 10
' ILineItem
Option Explicit

Public ID As Long
Public PurchaseOrderID As Long
Public Item As IInventory
Public Price As Currency
Public Quantity As Long

Public Function MarshalToPropertyBag(strKey As String) As Byte()

End Function

Public Property Get Valid() As Boolean

End Property

Listing 11
' ILineItemExec
Option Explicit

Public Function CreateRecordset(Optional ByVal strFilter As String = "") As Recordset

End Function

Public Function Create(rILineItem As ILineItem, Optional ByVal blnByVal As Boolean = True) As Boolean

End Function

Public Function Destroy(ByVal lngLineItemID As Long) As Boolean

End Function

Public Function DestroyByPurchaseOrder(ByVal lngPurchaseOrderID As Long) As Boolean

End Function

Public Function Modify(rILineItem As ILineItem, Optional ByVal blnByVal As Boolean = True) As Boolean

End Function

Listing 12
' ILineItems
Option Explicit

Public Function Add(rILineItem As ILineItem) As Boolean

End Function
Public Property Get Count() As Long

End Property

Public Function Item(ByVal lngPosKey As Long) As ILineItem

End Function

Public Function Remove(ByVal lngPosKey As Long) As Boolean

End Function

Listing 13
' IPurchaseOrder
Option Explicit

Public ID As Long
Public AccountID As Long
Public OrderDate As Date
Public SubTotal As Currency
Public ShippingHandling As Currency
Public TaxRate As Double
Public Tax As Currency
Public Total As Currency
Public ShipToFirstName As String
Public ShipToLastName As String
Public ShipToAddressLine1 As String
Public ShipToAddressLine2 As String
Public ShipToCity As String
Public ShipToState As String
Public ShipToZip As String
Public ShipToPhone As String
Public ShipToEmail As String

Public Property Get Valid() As Boolean

End Property

Public Function MarshalToPropertyBag(strKey As String) As Byte()

End Function

Public Property Get LineItems() As ILineItems

End Property

Listing 14
' IPurchaseOrderExec
Option Explicit

Public Function CreateRecordset(Optional ByVal strFilter As String = "") As Recordset

End Function

Public Function Create(rIPurchaseOrder As IPurchaseOrder, Optional ByVal blnByVal As Boolean = True) As Boolean

End Function

Public Function Destroy(ByVal lngPurchaseOrderID As Long) As Boolean

End Function

Public Function Modify(rIPurchaseOrder As IPurchaseOrder, Optional ByVal blnByVal As Boolean = True) As Boolean

End Function

Public Function Cancel(ByVal lngPurchaseOrderID As Long) As Boolean

End Function
Listing 15
/****** Object: Stored Procedure dbo.sp_AllocBatchOfUniqueIDs_UniqueIDs Script Date: 5/5/99 3:46:20 PM ******/
if exists (select * from sysobjects where id = object_id(N'[dbo].[sp_AllocBatchOfUniqueIDs_UniqueIDs]') and
OBJECTPROPERTY(id, N'IsProcedure') = 1)
drop procedure [dbo].[sp_AllocBatchOfUniqueIDs_UniqueIDs]
GO

CREATE PROCEDURE [sp_AllocBatchOfUniqueIDs_UniqueIDs]


AS

IF (SELECT COUNT([StartingIDofCurrentBatch]) FROM [DNADesign].[dbo].[UniqueIDs]) = 0


INSERT INTO [DNADesign].[dbo].[UniqueIDs] ([StartingIDofCurrentBatch]) VALUES(0)

UPDATE [DNADesign].[dbo].[UniqueIDs]
SET [StartingIDofCurrentBatch] = [StartingIDofCurrentBatch] + 100
RETURN (SELECT [StartingIDofCurrentBatch] FROM [DNADesign].[dbo].[UniqueIDs])

GO

Listing 16
/****** Object: Stored Procedure dbo.sp_decrementBalance_Accounts Script Date: 5/5/99 3:46:20 PM ******/
if exists (select * from sysobjects where id = object_id(N'[dbo].[sp_decrementBalance_Accounts]') and
OBJECTPROPERTY(id, N'IsProcedure') = 1)
drop procedure [dbo].[sp_decrementBalance_Accounts]
GO

CREATE PROCEDURE [sp_decrementBalance_Accounts]


(@IDPK int,
@Amount money,
@Balance money OUTPUT,
@Limit money OUTPUT)

AS UPDATE [DNADesign].[dbo].[Accounts] SET Balance = Balance - @Amount WHERE ( [IDPK] = @IDPK)


SELECT @Balance = Balance, @Limit = Limit FROM [DNADesign].[dbo].[Accounts] WHERE ( [IDPK] = @IDPK)

GO

Listing 17
/****** Object: Stored Procedure dbo.sp_decrementQOH_Inventory Script Date: 5/5/99 3:46:20 PM ******/
if exists (select * from sysobjects where id = object_id(N'[dbo].[sp_decrementQOH_Inventory]') and
OBJECTPROPERTY(id, N'IsProcedure') = 1)
drop procedure [dbo].[sp_decrementQOH_Inventory]
GO

CREATE PROCEDURE [sp_decrementQOH_Inventory]


(@IDPK int,
@Quantity int)

AS UPDATE [DNADesign].[dbo].[Inventory] SET QOH = QOH - @Quantity WHERE ( [IDPK] = @IDPK)


RETURN (SELECT QOH FROM [DNADesign].[dbo].[Inventory] WHERE ( [IDPK] = @IDPK))

GO

Listing 18
/****** Object: Stored Procedure dbo.sp_delete_Accounts Script Date: 5/5/99 3:46:20 PM ******/
if exists (select * from sysobjects where id = object_id(N'[dbo].[sp_delete_Accounts]') and OBJECTPROPERTY(id,
N'IsProcedure') = 1)
drop procedure [dbo].[sp_delete_Accounts]
GO

CREATE PROCEDURE [sp_delete_Accounts]


(@IDPK int)
AS DELETE [DNADesign].[dbo].[Accounts]

WHERE
( [IDPK] = @IDPK)

GO

Listing 19
/****** Object: Stored Procedure dbo.sp_delete_Inventory Script Date: 5/5/99 3:46:20 PM ******/
if exists (select * from sysobjects where id = object_id(N'[dbo].[sp_delete_Inventory]') and OBJECTPROPERTY(id,
N'IsProcedure') = 1)
drop procedure [dbo].[sp_delete_Inventory]
GO

CREATE PROCEDURE [sp_delete_Inventory]


(@IDPK int)

AS DELETE [DNADesign].[dbo].[Inventory]

WHERE
( [IDPK] = @IDPK)

GO

Listing 20
/****** Object: Stored Procedure dbo.sp_delete_LineItems Script Date: 5/5/99 3:46:21 PM ******/
if exists (select * from sysobjects where id = object_id(N'[dbo].[sp_delete_LineItems]') and OBJECTPROPERTY(id,
N'IsProcedure') = 1)
drop procedure [dbo].[sp_delete_LineItems]
GO

CREATE PROCEDURE [sp_delete_LineItems]


(@IDPK int)

AS DELETE [DNADesign].[dbo].[LineItems]

WHERE
( [IDPK] = @IDPK)

GO

Listing 21
/****** Object: Stored Procedure dbo.sp_deleteByPurchaseOrder_LineItems Script Date: 5/5/99 3:46:21 PM ******/
if exists (select * from sysobjects where id = object_id(N'[dbo].[sp_deleteByPurchaseOrder_LineItems]') and
OBJECTPROPERTY(id, N'IsProcedure') = 1)
drop procedure [dbo].[sp_deleteByPurchaseOrder_LineItems]
GO

CREATE PROCEDURE [sp_deleteByPurchaseOrder_LineItems]


(@PurchaseOrderIDFK int)

AS
DELETE [DNADesign].[dbo].[LineItems] WHERE ([PurchaseOrderIDFK] = @PurchaseOrderIDFK)

GO

Listing 22
/****** Object: Stored Procedure dbo.sp_delete_PurchaseOrders Script Date: 5/5/99 3:46:21 PM ******/
if exists (select * from sysobjects where id = object_id(N'[dbo].[sp_delete_PurchaseOrders]') and OBJECTPROPERTY(id,
N'IsProcedure') = 1)
drop procedure [dbo].[sp_delete_PurchaseOrders]
GO

CREATE PROCEDURE [sp_delete_PurchaseOrders]


(@IDPK int)

AS EXEC sp_deleteByPurchaseOrder_LineItems @IDPK


DELETE [DNADesign].[dbo].[PurchaseOrders] WHERE ( [IDPK] = @IDPK)
GO

Listing 23
/****** Object: Stored Procedure dbo.sp_incrementBalance_Accounts Script Date: 5/5/99 3:46:20 PM ******/
if exists (select * from sysobjects where id = object_id(N'[dbo].[sp_incrementBalance_Accounts]') and
OBJECTPROPERTY(id, N'IsProcedure') = 1)
drop procedure [dbo].[sp_incrementBalance_Accounts]
GO

CREATE PROCEDURE [sp_incrementBalance_Accounts]


(@IDPK int,
@Amount money,
@Balance money OUTPUT,
@Limit money OUTPUT)

AS UPDATE [DNADesign].[dbo].[Accounts] SET Balance = Balance + @Amount WHERE ( [IDPK] = @IDPK)


SELECT @Balance = Balance, @Limit = Limit FROM [DNADesign].[dbo].[Accounts] WHERE ( [IDPK] = @IDPK)

GO

Listing 24
/****** Object: Stored Procedure dbo.sp_incrementQOH_Inventory Script Date: 5/5/99 3:46:20 PM ******/
if exists (select * from sysobjects where id = object_id(N'[dbo].[sp_incrementQOH_Inventory]') and
OBJECTPROPERTY(id, N'IsProcedure') = 1)
drop procedure [dbo].[sp_incrementQOH_Inventory]
GO

CREATE PROCEDURE [sp_incrementQOH_Inventory]


(@IDPK int,
@Quantity int)

AS UPDATE [DNADesign].[dbo].[Inventory] SET QOH = QOH + @Quantity WHERE ( [IDPK] = @IDPK)


RETURN (SELECT QOH FROM [DNADesign].[dbo].[Inventory] WHERE ( [IDPK] = @IDPK))

GO

Listing 25
/****** Object: Stored Procedure dbo.sp_insert_Accounts Script Date: 5/5/99 3:46:20 PM ******/
if exists (select * from sysobjects where id = object_id(N'[dbo].[sp_insert_Accounts]') and OBJECTPROPERTY(id,
N'IsProcedure') = 1)
drop procedure [dbo].[sp_insert_Accounts]
GO

CREATE PROCEDURE [sp_insert_Accounts]


(@IDPK int,
@FirstName varchar(20),
@LastName varchar(40),
@AddressLine1 varchar(20),
@AddressLine2 varchar(20),
@City varchar(20),
@State varchar(2),
@Zip varchar(5),
@Phone varchar(12),
@Email varchar(20),
@Balance money,
@Limit money)

AS INSERT INTO [DNADesign].[dbo].[Accounts]


( [IDPK],
[FirstName],
[LastName],
[AddressLine1],
[AddressLine2],
[City],
[State],
[Zip],
[Phone],
[Email],
[Balance],
[Limit])

VALUES
( @IDPK,
@FirstName,
@LastName,
@AddressLine1,
@AddressLine2,
@City,
@State,
@Zip,
@Phone,
@Email,
@Balance,
@Limit)

GO

Listing 26
/****** Object: Stored Procedure dbo.sp_insert_Inventory Script Date: 5/5/99 3:46:20 PM ******/
if exists (select * from sysobjects where id = object_id(N'[dbo].[sp_insert_Inventory]') and OBJECTPROPERTY(id,
N'IsProcedure') = 1)
drop procedure [dbo].[sp_insert_Inventory]
GO

CREATE PROCEDURE [sp_insert_Inventory]


(@IDPK int,
@Description varchar(50),
@Price money,
@QOH int)

AS INSERT INTO [DNADesign].[dbo].[Inventory]


( [IDPK],
[Description],
[Price],
[QOH])

VALUES
( @IDPK,
@Description,
@Price,
@QOH)

GO

Listing 27
/****** Object: Stored Procedure dbo.sp_insert_LineItems Script Date: 5/5/99 3:46:21 PM ******/
if exists (select * from sysobjects where id = object_id(N'[dbo].[sp_insert_LineItems]') and OBJECTPROPERTY(id,
N'IsProcedure') = 1)
drop procedure [dbo].[sp_insert_LineItems]
GO

CREATE PROCEDURE [sp_insert_LineItems]


(@IDPK int,
@PurchaseOrderIDFK int,
@InventoryIDFK int,
@Price money,
@Quantity int)

AS INSERT INTO [DNADesign].[dbo].[LineItems]


( [IDPK],
[PurchaseOrderIDFK],
[InventoryIDFK],
[Price],
[Quantity])

VALUES
( @IDPK,
@PurchaseOrderIDFK,
@InventoryIDFK,
@Price,
@Quantity)

GO

Listing 28
/****** Object: Stored Procedure dbo.sp_insert_PurchaseOrders Script Date: 5/5/99 3:46:20 PM ******/
if exists (select * from sysobjects where id = object_id(N'[dbo].[sp_insert_PurchaseOrders]') and OBJECTPROPERTY(id,
N'IsProcedure') = 1)
drop procedure [dbo].[sp_insert_PurchaseOrders]
GO

CREATE PROCEDURE [sp_insert_PurchaseOrders]


(@IDPK int,
@AccountIDFK int,
@ShippingHandling money,
@TaxRate real,
@Total money,
@ShipToFirstName varchar(20),
@ShipToLastName varchar(40),
@ShipToAddressLine1 varchar(20),
@ShipToAddressLine2 varchar(20),
@ShipToCity varchar(20),
@ShipToState varchar(2),
@ShipToZip varchar(5),
@ShipToPhone varchar(12),
@ShipToEmail varchar(20))

AS INSERT INTO [DNADesign].[dbo].[PurchaseOrders]


( [IDPK],
[AccountIDFK],
[ShippingHandling],
[TaxRate],
[Total],
[ShipToFirstName],
[ShipToLastName],
[ShipToAddressLine1],
[ShipToAddressLine2],
[ShipToCity],
[ShipToState],
[ShipToZip],
[ShipToPhone],
[ShipToEmail])

VALUES
( @IDPK,
@AccountIDFK,
@ShippingHandling,
@TaxRate,
@Total,
@ShipToFirstName,
@ShipToLastName,
@ShipToAddressLine1,
@ShipToAddressLine2,
@ShipToCity,
@ShipToState,
@ShipToZip,
@ShipToPhone,
@ShipToEmail)
GO

Listing 29
/****** Object: Stored Procedure dbo.sp_update_Accounts Script Date: 5/5/99 3:46:20 PM ******/
if exists (select * from sysobjects where id = object_id(N'[dbo].[sp_update_Accounts]') and OBJECTPROPERTY(id,
N'IsProcedure') = 1)
drop procedure [dbo].[sp_update_Accounts]
GO

CREATE PROCEDURE [sp_update_Accounts]


(@IDPK int,
@FirstName varchar(20),
@LastName varchar(40),
@AddressLine1 varchar(20),
@AddressLine2 varchar(20),
@City varchar(20),
@State varchar(2),
@Zip varchar(5),
@Phone varchar(12),
@Email varchar(20),
@Balance money,
@Limit money)

AS UPDATE [DNADesign].[dbo].[Accounts]

SET [FirstName] = @FirstName,


[LastName] = @LastName,
[AddressLine1] = @AddressLine1,
[AddressLine2] = @AddressLine2,
[City] = @City,
[State] = @State,
[Zip] = @Zip,
[Phone] = @Phone,
[Email] = @Email,
[Balance] = @Balance,
[Limit] = @Limit

WHERE
( [IDPK] = @IDPK)

GO

Listing 30
/****** Object: Stored Procedure dbo.sp_update_Inventory Script Date: 5/5/99 3:46:20 PM ******/
if exists (select * from sysobjects where id = object_id(N'[dbo].[sp_update_Inventory]') and OBJECTPROPERTY(id,
N'IsProcedure') = 1)
drop procedure [dbo].[sp_update_Inventory]
GO

CREATE PROCEDURE [sp_update_Inventory]


(@IDPK int,
@Description varchar(50),
@Price money,
@QOH int)

AS UPDATE [DNADesign].[dbo].[Inventory]

SET [Description] = @Description,


[Price] = @Price,
[QOH] = @QOH

WHERE
( [IDPK] = @IDPK)

GO

Listing 31
/****** Object: Stored Procedure dbo.sp_update_LineItems Script Date: 5/5/99 3:46:21 PM ******/
if exists (select * from sysobjects where id = object_id(N'[dbo].[sp_update_LineItems]') and OBJECTPROPERTY(id,
N'IsProcedure') = 1)
drop procedure [dbo].[sp_update_LineItems]
GO

CREATE PROCEDURE [sp_update_LineItems]


(@IDPK int,
@PurchaseOrderIDFK int,
@InventoryIDFK int,
@Price money,
@Quantity int)

AS UPDATE [DNADesign].[dbo].[LineItems]

SET [PurchaseOrderIDFK] = @PurchaseOrderIDFK,


[InventoryIDFK] = @InventoryIDFK,
[Price] = @Price,
[Quantity] = @Quantity

WHERE
( [IDPK] = @IDPK)

GO

Listing 32
/****** Object: Stored Procedure dbo.sp_update_PurchaseOrders Script Date: 5/5/99 3:46:21 PM ******/
if exists (select * from sysobjects where id = object_id(N'[dbo].[sp_update_PurchaseOrders]') and
OBJECTPROPERTY(id, N'IsProcedure') = 1)
drop procedure [dbo].[sp_update_PurchaseOrders]
GO

CREATE PROCEDURE [sp_update_PurchaseOrders]


(@IDPK int,
@AccountIDFK int,
@ShippingHandling money,
@TaxRate real,
@Total money,
@ShipToFirstName varchar(20),
@ShipToLastName varchar(40),
@ShipToAddressLine1 varchar(20),
@ShipToAddressLine2 varchar(20),
@ShipToCity varchar(20),
@ShipToState varchar(2),
@ShipToZip varchar(5),
@ShipToPhone varchar(12),
@ShipToEmail varchar(20))

AS UPDATE [DNADesign].[dbo].[PurchaseOrders]

SET [AccountIDFK] = @AccountIDFK,


[ShippingHandling] = @ShippingHandling,
[TaxRate] = @TaxRate,
[Total] = @Total,
[ShipToFirstName] = @ShipToFirstName,
[ShipToLastName] = @ShipToLastName,
[ShipToAddressLine1] = @ShipToAddressLine1,
[ShipToAddressLine2] = @ShipToAddressLine2,
[ShipToCity] = @ShipToCity,
[ShipToState] = @ShipToState,
[ShipToZip] = @ShipToZip,
[ShipToPhone] = @ShipToPhone,
[ShipToEmail] = @ShipToEmail

WHERE
( [IDPK] = @IDPK)

GO

Listing 33
' AccountExec
Option Explicit
Implements IAccountExec

' Use field aliases to associate object


' property names with field names from the
' underlying data source
Private Const mstrSQL = "SELECT IDPK AS ID, FirstName, LastName," & _
" AddressLine1, AddressLine2, City, State, Zip," & _
" Phone, Email, Balance, Limit FROM Accounts"

Private Function IAccountExec_Create(rIAccount As POInterfaces.IAccount, Optional ByVal blnByVal As Boolean = True)


As Boolean
Dim objCommand As New Command
Dim objUniqueIDGen As UniqueIDGen
Dim objPropertyBag As New PropertyBag
Dim rIAccountLocal As IAccount
Dim strKey As String
Dim lngRecordsAffected As Long

On Error GoTo ErrorHandler

' Only Administrators can create accounts


If Not GetObjectContext.IsCallerInRole("Administrators") Then GoTo ErrorHandler

If blnByVal Then
' Create a local copy of the object
objPropertyBag.Contents = rIAccount.MarshalToPropertyBag(strKey)
Set rIAccountLocal = objPropertyBag.ReadProperty(strKey, Nothing)
Else
' Use the object ByRef
Set rIAccountLocal = rIAccount
End If
' Make sure that the information is valid
If Not rIAccountLocal.Valid Then GoTo ErrorHandler

' Assign the new Account a unique ID


Set objUniqueIDGen = GetObjectContext.CreateInstance("POExecutants.UniqueIDGen")
rIAccountLocal.ID = objUniqueIDGen.GetNextUniqueID()

objCommand.ActiveConnection = gstrCONNECT
objCommand.CommandText = "sp_insert_Accounts"
objCommand.CommandType = adCmdStoredProc
' Create each parameter and supply it's data
objCommand.Parameters.Append _
objCommand.CreateParameter("IDPK", adInteger, _
adParamInput, , rIAccountLocal.ID)
objCommand.Parameters.Append _
objCommand.CreateParameter("FirstName", adVarChar, _
adParamInput, 20, rIAccountLocal.FirstName)
objCommand.Parameters.Append _
objCommand.CreateParameter("LastName", adVarChar, _
adParamInput, 40, rIAccountLocal.LastName)
objCommand.Parameters.Append _
objCommand.CreateParameter("AddressLine1", adVarChar, _
adParamInput, 20, rIAccountLocal.AddressLine1)
objCommand.Parameters.Append _
objCommand.CreateParameter("AddressLine2", adVarChar, _
adParamInput, 20, rIAccountLocal.AddressLine2)
objCommand.Parameters.Append _
objCommand.CreateParameter("City", adVarChar, _
adParamInput, 20, rIAccountLocal.City)
objCommand.Parameters.Append _
objCommand.CreateParameter("State", adVarChar, _
adParamInput, 2, rIAccountLocal.State)
objCommand.Parameters.Append _
objCommand.CreateParameter("Zip", adVarChar, _
adParamInput, 5, rIAccountLocal.Zip)
objCommand.Parameters.Append _
objCommand.CreateParameter("Phone", adVarChar, _
adParamInput, 12, rIAccountLocal.Phone)
objCommand.Parameters.Append _
objCommand.CreateParameter("Email", adVarChar, _
adParamInput, 20, rIAccountLocal.Email)
objCommand.Parameters.Append _
objCommand.CreateParameter("Balance", adCurrency, _
adParamInput, , rIAccountLocal.Balance)
objCommand.Parameters.Append _
objCommand.CreateParameter("Limit", adCurrency, _
adParamInput, , rIAccountLocal.Limit)
' Execute the call
objCommand.Execute lngRecordsAffected

If lngRecordsAffected > 0 Then


GetObjectContext.SetComplete
IAccountExec_Create = True
Else
GoTo ErrorHandler
End If
CleanUp:
Set rIAccountLocal = Nothing
Set objPropertyBag = Nothing
Set objUniqueIDGen = Nothing
Set objCommand = Nothing
Exit Function
ErrorHandler:
GetObjectContext.SetAbort
GoTo CleanUp
End Function

Private Function IAccountExec_CreateRecordset(Optional ByVal strFilter As String = "") As ADODB.Recordset


Dim objConnection As New Connection
Dim objRecordset As New Recordset
Dim strSQL As String

' Preprocess the incoming args


strFilter = Trim$(strFilter)
objConnection.Open "DSN=DNADesign"
objConnection.CursorLocation = adUseClient
If strFilter = "" Then
strSQL = mstrSQL
Else
strSQL = mstrSQL & " WHERE " & strFilter
End If
objRecordset.Open strSQL, objConnection
Set objRecordset.ActiveConnection = Nothing
Set IAccountExec_CreateRecordset = objRecordset

Set objRecordset = Nothing


Set objConnection = Nothing
GetObjectContext.SetComplete
End Function

Private Function IAccountExec_DecrementBalance(ByVal lngAccountID As Long, ByVal curAmount As Currency) As


Boolean
Dim objCommand As New Command
Dim curBalance As Currency
Dim curLimit As Currency
Dim lngRecordsAffected As Long

On Error GoTo ErrorHandler

objCommand.ActiveConnection = gstrCONNECT
objCommand.CommandText = "sp_decrementBalance_Accounts"
objCommand.CommandType = adCmdStoredProc
' Create each parameter and supply it's data
objCommand.Parameters.Append _
objCommand.CreateParameter("IDPK", adInteger, _
adParamInput, , lngAccountID)
objCommand.Parameters.Append _
objCommand.CreateParameter("Amount", adCurrency, _
adParamInput, , curAmount)
objCommand.Parameters.Append _
objCommand.CreateParameter("Balance", adCurrency, _
adParamOutput)
objCommand.Parameters.Append _
objCommand.CreateParameter("Limit", adCurrency, _
adParamOutput)
' Execute the call
objCommand.Execute lngRecordsAffected
' Get the Account Balance
curBalance = objCommand.Parameters(2)
' Get the Account Limit
curLimit = objCommand.Parameters(3)

If lngRecordsAffected > 0 Then


' Balance cannot be negative
If curBalance >= 0 Then
GetObjectContext.SetComplete
IAccountExec_DecrementBalance = True
Else
GoTo ErrorHandler
End If
Else
GoTo ErrorHandler
End If
CleanUp:
Set objCommand = Nothing
Exit Function
ErrorHandler:
GetObjectContext.SetAbort
GoTo CleanUp
End Function

Private Function IAccountExec_Destroy(ByVal lngAccountID As Long) As Boolean


Dim objCommand As New Command
Dim lngRecordsAffected As Long

On Error GoTo ErrorHandler

' Only Administrators can delete accounts


If Not GetObjectContext.IsCallerInRole("Administrators") Then GoTo ErrorHandler

objCommand.ActiveConnection = gstrCONNECT
objCommand.CommandText = "sp_delete_Accounts"
objCommand.CommandType = adCmdStoredProc
' Create each parameter and supply it's data
objCommand.Parameters.Append _
objCommand.CreateParameter("IDPK", adInteger, _
adParamInput, , lngAccountID)
' Execute the call
objCommand.Execute lngRecordsAffected

If lngRecordsAffected > 0 Then


GetObjectContext.SetComplete
IAccountExec_Destroy = True
Else
GoTo ErrorHandler
End If
CleanUp:
Set objCommand = Nothing
Exit Function
ErrorHandler:
GetObjectContext.SetAbort
GoTo CleanUp
End Function

Private Function IAccountExec_IncrementBalance(ByVal lngAccountID As Long, ByVal curAmount As Currency) As


Boolean
Dim objCommand As New Command
Dim curBalance As Currency
Dim curLimit As Currency
Dim lngRecordsAffected As Long

On Error GoTo ErrorHandler

objCommand.ActiveConnection = gstrCONNECT
objCommand.CommandText = "sp_incrementBalance_Accounts"
objCommand.CommandType = adCmdStoredProc
' Create each parameter and supply it's data
objCommand.Parameters.Append _
objCommand.CreateParameter("IDPK", adInteger, _
adParamInput, , lngAccountID)
objCommand.Parameters.Append _
objCommand.CreateParameter("Amount", adCurrency, _
adParamInput, , curAmount)
objCommand.Parameters.Append _
objCommand.CreateParameter("Balance", adCurrency, _
adParamOutput)
objCommand.Parameters.Append _
objCommand.CreateParameter("Limit", adCurrency, _
adParamOutput)
' Execute the call
objCommand.Execute lngRecordsAffected
' Get the Account Balance
curBalance = objCommand.Parameters(2)
' Get the Account Limit
curLimit = objCommand.Parameters(3)

If lngRecordsAffected > 0 Then


' Make sure the new Balance is not
' beyond the Account Limit
If curBalance <= curLimit Then
GetObjectContext.SetComplete
IAccountExec_IncrementBalance = True
Else
GoTo ErrorHandler
End If
Else
GoTo ErrorHandler
End If
CleanUp:
Set objCommand = Nothing
Exit Function
ErrorHandler:
GetObjectContext.SetAbort
GoTo CleanUp
End Function

Private Function IAccountExec_Modify(rIAccount As POInterfaces.IAccount, Optional ByVal blnByVal As Boolean = True)


As Boolean
Dim objCommand As New Command
Dim objUniqueIDGen As UniqueIDGen
Dim objPropertyBag As New PropertyBag
Dim rIAccountLocal As IAccount
Dim strKey As String
Dim lngRecordsAffected As Long

On Error GoTo ErrorHandler

' Only Administrators can modify accounts


If Not GetObjectContext.IsCallerInRole("Administrators") Then GoTo ErrorHandler

If blnByVal Then
' Create a local copy of the object
objPropertyBag.Contents = rIAccount.MarshalToPropertyBag(strKey)
Set rIAccountLocal = objPropertyBag.ReadProperty(strKey, Nothing)
Else
' Use the object ByRef
Set rIAccountLocal = rIAccount
End If
' Make sure that the information is valid
If Not rIAccountLocal.Valid Then GoTo ErrorHandler

objCommand.ActiveConnection = gstrCONNECT
objCommand.CommandText = "sp_update_Accounts"
objCommand.CommandType = adCmdStoredProc
' Create each parameter and supply it's data
objCommand.Parameters.Append _
objCommand.CreateParameter("IDPK", adInteger, _
adParamInput, , rIAccount.ID)
objCommand.Parameters.Append _
objCommand.CreateParameter("FirstName", adVarChar, _
adParamInput, 20, rIAccountLocal.FirstName)
objCommand.Parameters.Append _
objCommand.CreateParameter("LastName", adVarChar, _
adParamInput, 40, rIAccountLocal.LastName)
objCommand.Parameters.Append _
objCommand.CreateParameter("AddressLine1", adVarChar, _
adParamInput, 20, rIAccountLocal.AddressLine1)
objCommand.Parameters.Append _
objCommand.CreateParameter("AddressLine2", adVarChar, _
adParamInput, 20, rIAccountLocal.AddressLine2)
objCommand.Parameters.Append _
objCommand.CreateParameter("City", adVarChar, _
adParamInput, 20, rIAccountLocal.City)
objCommand.Parameters.Append _
objCommand.CreateParameter("State", adVarChar, _
adParamInput, 2, rIAccountLocal.State)
objCommand.Parameters.Append _
objCommand.CreateParameter("Zip", adVarChar, _
adParamInput, 5, rIAccountLocal.Zip)
objCommand.Parameters.Append _
objCommand.CreateParameter("Phone", adVarChar, _
adParamInput, 12, rIAccountLocal.Phone)
objCommand.Parameters.Append _
objCommand.CreateParameter("Email", adVarChar, _
adParamInput, 20, rIAccountLocal.Email)
objCommand.Parameters.Append _
objCommand.CreateParameter("Balance", adCurrency, _
adParamInput, , rIAccountLocal.Balance)
objCommand.Parameters.Append _
objCommand.CreateParameter("Limit", adCurrency, _
adParamInput, , rIAccountLocal.Limit)
' Execute the call
objCommand.Execute lngRecordsAffected

If lngRecordsAffected > 0 Then


GetObjectContext.SetComplete
IAccountExec_Modify = True
Else
GoTo ErrorHandler
End If
CleanUp:
Set rIAccountLocal = Nothing
Set objPropertyBag = Nothing
Set objUniqueIDGen = Nothing
Set objCommand = Nothing
Exit Function
ErrorHandler:
GetObjectContext.SetAbort
GoTo CleanUp
End Function

Listing 34
' InventoryExec
Option Explicit

Implements IInventoryExec

' Use field aliases to associate object


' property names with field names from the
' underlying data source
Private Const mstrSQL = "SELECT IDPK AS ID, Description, Price," & _
" QOH FROM Inventory"

Private Function IInventoryExec_Create(rIInventory As POInterfaces.IInventory, Optional ByVal blnByVal As Boolean =


True) As Boolean
Dim objCommand As New Command
Dim objUniqueIDGen As UniqueIDGen
Dim objPropertyBag As New PropertyBag
Dim rIInventoryLocal As IInventory
Dim strKey As String
Dim lngRecordsAffected As Long

On Error GoTo ErrorHandler

' Only Administrators can create inventory items


If Not GetObjectContext.IsCallerInRole("Administrators") Then GoTo ErrorHandler

If blnByVal Then
' Create a local copy of the object
objPropertyBag.Contents = rIInventory.MarshalToPropertyBag(strKey)
Set rIInventoryLocal = objPropertyBag.ReadProperty(strKey, Nothing)
Else
' Use the object ByRef
Set rIInventoryLocal = rIInventory
End If
' Make sure that the information is valid
If Not rIInventoryLocal.Valid Then GoTo ErrorHandler

' Assign the new Inventory item a unique ID


Set objUniqueIDGen = GetObjectContext.CreateInstance("POExecutants.UniqueIDGen")
rIInventoryLocal.ID = objUniqueIDGen.GetNextUniqueID()

objCommand.ActiveConnection = gstrCONNECT
objCommand.CommandText = "sp_insert_Inventory"
objCommand.CommandType = adCmdStoredProc
' Create each parameter and supply it's data
objCommand.Parameters.Append _
objCommand.CreateParameter("IDPK", adInteger, _
adParamInput, , rIInventoryLocal.ID)
objCommand.Parameters.Append _
objCommand.CreateParameter("Description", adVarChar, _
adParamInput, 50, rIInventoryLocal.Description)
objCommand.Parameters.Append _
objCommand.CreateParameter("Price", adCurrency, _
adParamInput, , rIInventoryLocal.Price)
objCommand.Parameters.Append _
objCommand.CreateParameter("QOH", adInteger, _
adParamInput, , rIInventoryLocal.QOH)
' Execute the call
objCommand.Execute lngRecordsAffected

If lngRecordsAffected > 0 Then


GetObjectContext.SetComplete
IInventoryExec_Create = True
Else
GoTo ErrorHandler
End If
CleanUp:
Set rIInventoryLocal = Nothing
Set objPropertyBag = Nothing
Set objUniqueIDGen = Nothing
Set objCommand = Nothing
Exit Function
ErrorHandler:
GetObjectContext.SetAbort
GoTo CleanUp
End Function
Private Function IInventoryExec_CreateRecordset(Optional ByVal strFilter As String = "") As ADODB.Recordset
Dim objConnection As New Connection
Dim objRecordset As New Recordset
Dim strSQL As String

' Preprocess the incoming args


strFilter = Trim$(strFilter)
objConnection.Open "DSN=DNADesign"
objConnection.CursorLocation = adUseClient
If strFilter = "" Then
strSQL = mstrSQL
Else
strSQL = mstrSQL & " WHERE " & strFilter
End If
objRecordset.Open strSQL, objConnection
Set objRecordset.ActiveConnection = Nothing
Set IInventoryExec_CreateRecordset = objRecordset

Set objRecordset = Nothing


Set objConnection = Nothing
GetObjectContext.SetComplete
End Function

Private Function IInventoryExec_DecrementQOH(ByVal lngInventoryID As Long, ByVal lngQuantity As Long) As Boolean


Dim objCommand As New Command
Dim lngQOH As Long
Dim lngRecordsAffected As Long

On Error GoTo ErrorHandler

objCommand.ActiveConnection = gstrCONNECT
objCommand.CommandText = "sp_decrementQOH_Inventory"
objCommand.CommandType = adCmdStoredProc
' Create each parameter and supply it's data
objCommand.Parameters.Append _
objCommand.CreateParameter("Return", adInteger, _
adParamReturnValue)
objCommand.Parameters.Append _
objCommand.CreateParameter("IDPK", adInteger, _
adParamInput, , lngInventoryID)
objCommand.Parameters.Append _
objCommand.CreateParameter("Quantity", adInteger, _
adParamInput, , lngQuantity)
' Execute the call
objCommand.Execute lngRecordsAffected
' Get the return value
lngQOH = objCommand(0)

If lngRecordsAffected > 0 Then


' Balance in terms of credit cannot be negative
If lngQOH >= 0 Then
GetObjectContext.SetComplete
IInventoryExec_DecrementQOH = True
Else
GoTo ErrorHandler
End If
Else
GoTo ErrorHandler
End If
CleanUp:
Set objCommand = Nothing
Exit Function
ErrorHandler:
GetObjectContext.SetAbort
GoTo CleanUp
End Function

Private Function IInventoryExec_Destroy(ByVal lngInventoryID As Long) As Boolean


Dim objCommand As New Command
Dim lngRecordsAffected As Long
On Error GoTo ErrorHandler

' Only Administrators can destroy inventory items


If Not GetObjectContext.IsCallerInRole("Administrators") Then GoTo ErrorHandler

objCommand.ActiveConnection = gstrCONNECT
objCommand.CommandText = "sp_delete_Inventory"
objCommand.CommandType = adCmdStoredProc
' Create each parameter and supply it's data
objCommand.Parameters.Append _
objCommand.CreateParameter("IDPK", adInteger, _
adParamInput, , lngInventoryID)
' Execute the call
objCommand.Execute lngRecordsAffected

If lngRecordsAffected > 0 Then


GetObjectContext.SetComplete
IInventoryExec_Destroy = True
Else
GoTo ErrorHandler
End If
CleanUp:
Set objCommand = Nothing
Exit Function
ErrorHandler:
GetObjectContext.SetAbort
GoTo CleanUp
End Function

Private Function IInventoryExec_IncrementQOH(ByVal lngInventoryID As Long, ByVal lngQuantity As Long) As Boolean


Dim objCommand As New Command
Dim lngQOH As Long
Dim lngRecordsAffected As Long

On Error GoTo ErrorHandler

objCommand.ActiveConnection = gstrCONNECT
objCommand.CommandText = "sp_incrementQOH_Inventory"
objCommand.CommandType = adCmdStoredProc
' Create each parameter and supply it's data
objCommand.Parameters.Append _
objCommand.CreateParameter("Return", adInteger, _
adParamReturnValue)
objCommand.Parameters.Append _
objCommand.CreateParameter("IDPK", adInteger, _
adParamInput, , lngInventoryID)
objCommand.Parameters.Append _
objCommand.CreateParameter("Quantity", adInteger, _
adParamInput, , lngQuantity)
' Execute the call
objCommand.Execute lngRecordsAffected
' Get the return value
lngQOH = objCommand(0)

If lngRecordsAffected > 0 Then


GetObjectContext.SetComplete
IInventoryExec_IncrementQOH = True
Else
GoTo ErrorHandler
End If
CleanUp:
Set objCommand = Nothing
Exit Function
ErrorHandler:
GetObjectContext.SetAbort
GoTo CleanUp
End Function
Private Function IInventoryExec_Modify(rIInventory As POInterfaces.IInventory, Optional ByVal blnByVal As Boolean =
True) As Boolean
Dim objCommand As New Command
Dim objUniqueIDGen As UniqueIDGen
Dim objPropertyBag As New PropertyBag
Dim rIInventoryLocal As IInventory
Dim strKey As String
Dim lngRecordsAffected As Long

On Error GoTo ErrorHandler

' Only Administrators can modify inventory items


If Not GetObjectContext.IsCallerInRole("Administrators") Then GoTo ErrorHandler

If blnByVal Then
' Create a local copy of the object
objPropertyBag.Contents = rIInventory.MarshalToPropertyBag(strKey)
Set rIInventoryLocal = objPropertyBag.ReadProperty(strKey, Nothing)
Else
' Use the object ByRef
Set rIInventoryLocal = rIInventory
End If
' Make sure that the information is valid
If Not rIInventoryLocal.Valid Then GoTo ErrorHandler

objCommand.ActiveConnection = gstrCONNECT
objCommand.CommandText = "sp_update_Inventory"
objCommand.CommandType = adCmdStoredProc
' Create each parameter and supply it's data
objCommand.Parameters.Append _
objCommand.CreateParameter("IDPK", adInteger, _
adParamInput, , rIInventoryLocal.ID)
objCommand.Parameters.Append _
objCommand.CreateParameter("Description", adVarChar, _
adParamInput, 50, rIInventoryLocal.Description)
objCommand.Parameters.Append _
objCommand.CreateParameter("Price", adCurrency, _
adParamInput, , rIInventoryLocal.Price)
objCommand.Parameters.Append _
objCommand.CreateParameter("QOH", adInteger, _
adParamInput, , rIInventoryLocal.QOH)
' Execute the call
objCommand.Execute lngRecordsAffected

If lngRecordsAffected > 0 Then


GetObjectContext.SetComplete
IInventoryExec_Modify = True
Else
GoTo ErrorHandler
End If
CleanUp:
Set rIInventoryLocal = Nothing
Set objPropertyBag = Nothing
Set objUniqueIDGen = Nothing
Set objCommand = Nothing
Exit Function
ErrorHandler:
GetObjectContext.SetAbort
GoTo CleanUp
End Function

Listing 35
' LineItemExec
Option Explicit

Implements ILineItemExec

' Use field aliases to associate object


' property names with field names from the
' underlying data source
Private Const mstrSQL = "SELECT LineItems.IDPK AS ID," & _
" PurchaseOrderIDFK AS PurchaseOrderID," & _
" LineItems.Price, LineItems.Quantity, " & _
" InventoryIDFK AS 'Inventory.ID'," & _
" Inventory.Description AS 'Inventory.Description'," & _
" Inventory.Price AS 'Inventory.Price'," & _
" Inventory.QOH AS 'Inventory.QOH' FROM LineItems, Inventory" & _
" WHERE InventoryIDFK = Inventory.IDPK"

Private Function ILineItemExec_Create(rILineItem As POInterfaces.ILineItem, Optional ByVal blnByVal As Boolean =


True) As Boolean
Dim objCommand As New Command
Dim objUniqueIDGen As UniqueIDGen
Dim objPropertyBag As New PropertyBag
Dim rILineItemLocal As ILineItem
Dim strKey As String
Dim lngRecordsAffected As Long

On Error GoTo ErrorHandler

If blnByVal Then
' Create a local copy of the object
objPropertyBag.Contents = rILineItem.MarshalToPropertyBag(strKey)
Set rILineItemLocal = objPropertyBag.ReadProperty(strKey, Nothing)
Else
' Use the object ByRef
Set rILineItemLocal = rILineItem
End If
' Make sure that the information is valid
If Not rILineItemLocal.Valid Then GoTo ErrorHandler

' Assign the new LineItem a unique ID


Set objUniqueIDGen = GetObjectContext.CreateInstance("POExecutants.UniqueIDGen")
rILineItemLocal.ID = objUniqueIDGen.GetNextUniqueID()

objCommand.ActiveConnection = gstrCONNECT
objCommand.CommandText = "sp_insert_LineItems"
objCommand.CommandType = adCmdStoredProc
' Create each parameter and supply it's data
objCommand.Parameters.Append _
objCommand.CreateParameter("IDPK", adInteger, _
adParamInput, , rILineItemLocal.ID)
objCommand.Parameters.Append _
objCommand.CreateParameter("PurchaseOrderIDFK", adInteger, _
adParamInput, , rILineItemLocal.PurchaseOrderID)
objCommand.Parameters.Append _
objCommand.CreateParameter("InventoryIDFK", adInteger, _
adParamInput, , rILineItemLocal.Item.ID)
objCommand.Parameters.Append _
objCommand.CreateParameter("Price", adCurrency, _
adParamInput, , rILineItemLocal.Price)
objCommand.Parameters.Append _
objCommand.CreateParameter("Quantity", adInteger, _
adParamInput, , rILineItemLocal.Quantity)
' Execute the call
objCommand.Execute lngRecordsAffected

If lngRecordsAffected > 0 Then


GetObjectContext.SetComplete
ILineItemExec_Create = True
Else
GoTo ErrorHandler
End If
CleanUp:
Set rILineItemLocal = Nothing
Set objPropertyBag = Nothing
Set objUniqueIDGen = Nothing
Set objCommand = Nothing
Exit Function
ErrorHandler:
GetObjectContext.SetAbort
GoTo CleanUp
End Function

Private Function ILineItemExec_CreateRecordset(Optional ByVal strFilter As String = "") As ADODB.Recordset


Dim objConnection As New Connection
Dim objRecordset As New Recordset
Dim strSQL As String

' Preprocess the incoming args


strFilter = Trim$(strFilter)
objConnection.Open "DSN=DNADesign"
objConnection.CursorLocation = adUseClient
If strFilter = "" Then
strSQL = mstrSQL
Else
strSQL = mstrSQL & " AND (" & strFilter & ")"
End If
objRecordset.Open strSQL, objConnection
Set objRecordset.ActiveConnection = Nothing
Set ILineItemExec_CreateRecordset = objRecordset

Set objRecordset = Nothing


Set objConnection = Nothing
GetObjectContext.SetComplete
End Function

Private Function ILineItemExec_Destroy(ByVal lngLineItemID As Long) As Boolean


Dim objCommand As New Command
Dim lngRecordsAffected As Long

On Error GoTo ErrorHandler

objCommand.ActiveConnection = gstrCONNECT
objCommand.CommandText = "sp_delete_LineItems"
objCommand.CommandType = adCmdStoredProc
' Create each parameter and supply it's data
objCommand.Parameters.Append _
objCommand.CreateParameter("IDPK", adInteger, _
adParamInput, , lngLineItemID)
' Execute the call
objCommand.Execute lngRecordsAffected

If lngRecordsAffected > 0 Then


GetObjectContext.SetComplete
ILineItemExec_Destroy = True
Else
GoTo ErrorHandler
End If
CleanUp:
Set objCommand = Nothing
Exit Function
ErrorHandler:
GetObjectContext.SetAbort
GoTo CleanUp
End Function

Private Function ILineItemExec_DestroyByPurchaseOrder(ByVal lngPurchaseOrderID As Long) As Boolean


Dim objCommand As New Command
Dim lngRecordsAffected As Long

On Error GoTo ErrorHandler

objCommand.ActiveConnection = gstrCONNECT
objCommand.CommandText = "sp_deleteByPurchaseOrder_LineItems"
objCommand.CommandType = adCmdStoredProc
' Create each parameter and supply it's data
objCommand.Parameters.Append _
objCommand.CreateParameter("PurchaseOrderIDFK", adInteger, _
adParamInput, , lngPurchaseOrderID)
' Execute the call
objCommand.Execute lngRecordsAffected

If lngRecordsAffected > 0 Then


GetObjectContext.SetComplete
ILineItemExec_DestroyByPurchaseOrder = True
Else
GoTo ErrorHandler
End If
CleanUp:
Set objCommand = Nothing
Exit Function
ErrorHandler:
GetObjectContext.SetAbort
GoTo CleanUp
End Function

Private Function ILineItemExec_Modify(rILineItem As POInterfaces.ILineItem, Optional ByVal blnByVal As Boolean =


True) As Boolean
Dim objCommand As New Command
Dim objUniqueIDGen As UniqueIDGen
Dim objPropertyBag As New PropertyBag
Dim rILineItemLocal As ILineItem
Dim strKey As String
Dim lngRecordsAffected As Long

On Error GoTo ErrorHandler

If blnByVal Then
' Create a local copy of the object
objPropertyBag.Contents = rILineItem.MarshalToPropertyBag(strKey)
Set rILineItemLocal = objPropertyBag.ReadProperty(strKey, Nothing)
Else
' Use the object ByRef
Set rILineItemLocal = rILineItem
End If
' Make sure that the information is valid
If Not rILineItemLocal.Valid Then GoTo ErrorHandler

objCommand.ActiveConnection = gstrCONNECT
objCommand.CommandText = "sp_insert_LineItems"
objCommand.CommandType = adCmdStoredProc
' Create each parameter and supply it's data
objCommand.Parameters.Append _
objCommand.CreateParameter("IDPK", adInteger, _
adParamInput, , rILineItemLocal.ID)
objCommand.Parameters.Append _
objCommand.CreateParameter("PurchaseOrderIDFK", adInteger, _
adParamInput, , rILineItemLocal.PurchaseOrderID)
objCommand.Parameters.Append _
objCommand.CreateParameter("InventoryIDFK", adInteger, _
adParamInput, , rILineItemLocal.Item.ID)
objCommand.Parameters.Append _
objCommand.CreateParameter("Price", adCurrency, _
adParamInput, , rILineItemLocal.Price)
objCommand.Parameters.Append _
objCommand.CreateParameter("Quantity", adInteger, _
adParamInput, , rILineItemLocal.Quantity)
' Execute the call
objCommand.Execute lngRecordsAffected

If lngRecordsAffected > 0 Then


GetObjectContext.SetComplete
ILineItemExec_Modify = True
Else
GoTo ErrorHandler
End If
CleanUp:
Set rILineItemLocal = Nothing
Set objPropertyBag = Nothing
Set objUniqueIDGen = Nothing
Set objCommand = Nothing
Exit Function
ErrorHandler:
GetObjectContext.SetAbort
GoTo CleanUp
End Function

Listing 36
' PurchaseOrderExec
Option Explicit

Implements IPurchaseOrderExec

Private Function IPurchaseOrderExec_Cancel(ByVal lngPurchaseOrderID As Long) As Boolean


Dim objConnection As New Connection
Dim objRecordset As Recordset
Dim rIInventoryExec As IInventoryExec
Dim rIAccountExec As IAccountExec
Dim strSQL As String

On Error GoTo ErrorHandler

Set rIInventoryExec = GetObjectContext.CreateInstance("POExecutants.InventoryExec")


Set rIAccountExec = GetObjectContext.CreateInstance("POExecutants.AccountExec")

' Issue compensating transactions to increment the


' QOH of each Inventory item purchased as part of the order
strSQL = "SELECT InventoryIDFK, Quantity FROM LineItems WHERE PurchaseOrderIDFK = " &
CStr(lngPurchaseOrderID)
objConnection.Open gstrCONNECT
Set objRecordset = objConnection.Execute(strSQL)
Do While Not objRecordset.EOF
If Not rIInventoryExec.IncrementQOH(objRecordset("InventoryIDFK"), objRecordset("Quantity")) Then
GoTo ErrorHandler
End If
objRecordset.MoveNext
Loop
objRecordset.Close
' Issue a compensating transaction to decrement the Account balance
strSQL = "SELECT AccountIDFK, Total FROM PurchaseOrders WHERE IDPK = " & CStr(lngPurchaseOrderID)
Set objRecordset = objConnection.Execute(strSQL)
If Not rIAccountExec.DecrementBalance(objRecordset("AccountIDFK"), objRecordset("Total")) Then
GoTo ErrorHandler
End If
' Delete the PurchaseOrder from the data source
If Not IPurchaseOrderExec_Destroy(lngPurchaseOrderID) Then
GoTo ErrorHandler
End If

GetObjectContext.SetComplete
IPurchaseOrderExec_Cancel = True
CleanUp:
Set rIAccountExec = Nothing
Set rIInventoryExec = Nothing
Set objRecordset = Nothing
Set objConnection = Nothing
Exit Function
ErrorHandler:
GetObjectContext.SetAbort
GoTo CleanUp
End Function

Private Function IPurchaseOrderExec_Create(rIPurchaseOrder As POInterfaces.IPurchaseOrder, Optional ByVal


blnByVal As Boolean = True) As Boolean
Dim objCommand As New Command
Dim objUniqueIDGen As UniqueIDGen
Dim objPropertyBag As New PropertyBag
Dim rIPurchaseOrderLocal As IPurchaseOrder
Dim rILineItemExec As ILineItemExec
Dim rIInventoryExec As IInventoryExec
Dim rIAccountExec As IAccountExec
Dim rILineItem As ILineItem
Dim strKey As String
Dim lngLineItem As Long
Dim lngRecordsAffected As Long

On Error GoTo ErrorHandler

If blnByVal Then
' Create a local copy of the object
objPropertyBag.Contents = rIPurchaseOrder.MarshalToPropertyBag(strKey)
Set rIPurchaseOrderLocal = objPropertyBag.ReadProperty(strKey, Nothing)
Else
' Use the object ByRef
Set rIPurchaseOrderLocal = rIPurchaseOrder
End If
' Make sure that the information is valid
If Not rIPurchaseOrderLocal.Valid Then GoTo ErrorHandler

' Assign the new PurchaseOrder a unique ID


Set objUniqueIDGen = GetObjectContext.CreateInstance("POExecutants.UniqueIDGen")
rIPurchaseOrderLocal.ID = objUniqueIDGen.GetNextUniqueID()

objCommand.ActiveConnection = gstrCONNECT
objCommand.CommandText = "sp_insert_PurchaseOrders"
objCommand.CommandType = adCmdStoredProc
' Create each parameter and supply it's data
objCommand.Parameters.Append _
objCommand.CreateParameter("IDPK", adInteger, _
adParamInput, , rIPurchaseOrderLocal.ID)
objCommand.Parameters.Append _
objCommand.CreateParameter("AccountIDFK", adInteger, _
adParamInput, , rIPurchaseOrderLocal.AccountID)
objCommand.Parameters.Append _
objCommand.CreateParameter("ShippingHandling", adCurrency, _
adParamInput, , rIPurchaseOrderLocal.ShippingHandling)
objCommand.Parameters.Append _
objCommand.CreateParameter("TaxRate", adDouble, _
adParamInput, , rIPurchaseOrderLocal.TaxRate)
objCommand.Parameters.Append _
objCommand.CreateParameter("Total", adCurrency, _
adParamInput, , rIPurchaseOrderLocal.Total)
objCommand.Parameters.Append _
objCommand.CreateParameter("ShipToFirstName", adVarChar, _
adParamInput, 20, rIPurchaseOrderLocal.ShipToFirstName)
objCommand.Parameters.Append _
objCommand.CreateParameter("ShipToLastName", adVarChar, _
adParamInput, 40, rIPurchaseOrderLocal.ShipToLastName)
objCommand.Parameters.Append _
objCommand.CreateParameter("ShipToAddressLine1", adVarChar, _
adParamInput, 20, rIPurchaseOrderLocal.ShipToAddressLine1)
objCommand.Parameters.Append _
objCommand.CreateParameter("ShipToAddressLine2", adVarChar, _
adParamInput, 20, rIPurchaseOrderLocal.ShipToAddressLine2)
objCommand.Parameters.Append _
objCommand.CreateParameter("ShipToCity", adVarChar, _
adParamInput, 20, rIPurchaseOrderLocal.ShipToCity)
objCommand.Parameters.Append _
objCommand.CreateParameter("ShipToState", adVarChar, _
adParamInput, 2, rIPurchaseOrderLocal.ShipToState)
objCommand.Parameters.Append _
objCommand.CreateParameter("ShipToZip", adVarChar, _
adParamInput, 5, rIPurchaseOrderLocal.ShipToZip)
objCommand.Parameters.Append _
objCommand.CreateParameter("ShipToPhone", adVarChar, _
adParamInput, 12, rIPurchaseOrderLocal.ShipToPhone)
objCommand.Parameters.Append _
objCommand.CreateParameter("ShipToEmail", adVarChar, _
adParamInput, 20, rIPurchaseOrderLocal.ShipToEmail)
' Execute the call
objCommand.Execute lngRecordsAffected

If lngRecordsAffected > 0 Then


Set rILineItemExec = GetObjectContext.CreateInstance("POExecutants.LineItemExec")
Set rIInventoryExec = GetObjectContext.CreateInstance("POExecutants.InventoryExec")
Set rIAccountExec = GetObjectContext.CreateInstance("POExecutants.AccountExec")
' Save the related LineItems
For lngLineItem = 1 To rIPurchaseOrderLocal.LineItems.Count
Set rILineItem = rIPurchaseOrderLocal.LineItems.Item(lngLineItem)
If Not rILineItem Is Nothing Then
rILineItem.PurchaseOrderID = rIPurchaseOrderLocal.ID
' Pass each LineItem ByRef since both
' components are in the same package
If rILineItemExec.Create(rILineItem, False) Then
' Decrement the QOH for each Inventory item
If Not rIInventoryExec.DecrementQOH(rILineItem.Item.ID, rILineItem.Quantity) Then
GoTo ErrorHandler
End If
Else
GoTo ErrorHandler
End If
End If
Next lngLineItem
' Increment the Account balance
If Not rIAccountExec.IncrementBalance(rIPurchaseOrderLocal.AccountID, rIPurchaseOrderLocal.Total) Then
GoTo ErrorHandler
End If
GetObjectContext.SetComplete
IPurchaseOrderExec_Create = True
Else
GoTo ErrorHandler
End If
CleanUp:
Set rILineItem = Nothing
Set rIAccountExec = Nothing
Set rIInventoryExec = Nothing
Set rILineItemExec = Nothing
Set rIPurchaseOrderLocal = Nothing
Set objPropertyBag = Nothing
Set objUniqueIDGen = Nothing
Set objCommand = Nothing
Exit Function
ErrorHandler:
GetObjectContext.SetAbort
GoTo CleanUp
End Function

Private Function IPurchaseOrderExec_CreateRecordset(Optional ByVal strFilter As String = "") As ADODB.Recordset


Dim objConnection As New Connection
Dim objRecordset As New Recordset
Dim strParentCommand As String
Dim strChildCommand As String
Dim strSQL As String

' Preprocess the incoming args


strFilter = Trim$(strFilter)
objConnection.Provider = "MSDataShape"
objConnection.Open "DSN=DNADesign"
objConnection.CursorLocation = adUseClient
' Use field aliases to associate object
' property names with field names from the
' underlying data source
If strFilter = "" Then
strParentCommand = "SELECT IDPK AS ID," & _
" AccountIDFK AS 'Account.ID', OrderDate," & _
" ShippingHandling, TaxRate, Total," & _
" ShipToFirstName, ShipToLastName, ShipToAddressLine1," & _
" ShipToAddressLine2, ShipToCity, ShipToState, ShipToZip," & _
" ShipToPhone, ShipToEmail" & _
" FROM PurchaseOrders"
Else
strParentCommand = "SELECT IDPK AS ID," & _
" AccountIDFK AS 'Account.ID', OrderDate," & _
" ShippingHandling, TaxRate, Total," & _
" ShipToFirstName, ShipToLastName, ShipToAddressLine1," & _
" ShipToAddressLine2, ShipToCity, ShipToState, ShipToZip," & _
" ShipToPhone, ShipToEmail" & _
" FROM PurchaseOrders" & _
" WHERE " & strFilter
End If

strChildCommand = "SELECT LineItems.IDPK AS ID," & _


" PurchaseOrderIDFK AS PurchaseOrderID," & _
" LineItems.Price, LineItems.Quantity, " & _
" InventoryIDFK AS 'Inventory.ID'," & _
" Inventory.Description AS 'Inventory.Description'," & _
" Inventory.Price AS 'Inventory.Price'," & _
" Inventory.QOH AS 'Inventory.QOH' FROM LineItems, Inventory" & _
" WHERE InventoryIDFK = Inventory.IDPK"

strSQL = "SHAPE {" & strParentCommand & _


"} APPEND ({" & strChildCommand & _
"} RELATE ID TO PurchaseOrderID) AS chapPurchaseOrderLineItems"
objRecordset.Open strSQL, objConnection
Set objRecordset.ActiveConnection = Nothing
Set IPurchaseOrderExec_CreateRecordset = objRecordset

Set objRecordset = Nothing


Set objConnection = Nothing
GetObjectContext.SetComplete
End Function

Private Function IPurchaseOrderExec_Destroy(ByVal lngPurchaseOrderID As Long) As Boolean


Dim objCommand As New Command
Dim lngRecordsAffected As Long

On Error GoTo ErrorHandler

objCommand.ActiveConnection = gstrCONNECT
objCommand.CommandText = "sp_delete_PurchaseOrders"
objCommand.CommandType = adCmdStoredProc
' Create each parameter and supply it's data
objCommand.Parameters.Append _
objCommand.CreateParameter("IDPK", adInteger, _
adParamInput, , lngPurchaseOrderID)
' Execute the call
objCommand.Execute lngRecordsAffected

If lngRecordsAffected > 0 Then


GetObjectContext.SetComplete
IPurchaseOrderExec_Destroy = True
Else
GoTo ErrorHandler
End If
CleanUp:
Set objCommand = Nothing
Exit Function
ErrorHandler:
GetObjectContext.SetAbort
GoTo CleanUp
End Function

Private Function IPurchaseOrderExec_Modify(rIPurchaseOrder As POInterfaces.IPurchaseOrder, Optional ByVal


blnByVal As Boolean = True) As Boolean
Dim objCommand As New Command
Dim objPropertyBag As New PropertyBag
Dim rIPurchaseOrderLocal As IPurchaseOrder
Dim rILineItemExec As ILineItemExec
Dim rIInventoryExec As IInventoryExec
Dim rIAccountExec As IAccountExec
Dim rILineItem As ILineItem
Dim strKey As String
Dim lngLineItem As Long
Dim lngRecordsAffected As Long

On Error GoTo ErrorHandler

If blnByVal Then
' Create a local copy of the object
objPropertyBag.Contents = rIPurchaseOrder.MarshalToPropertyBag(strKey)
Set rIPurchaseOrderLocal = objPropertyBag.ReadProperty(strKey, Nothing)
Else
' Use the object ByRef
Set rIPurchaseOrderLocal = rIPurchaseOrder
End If
' Make sure that the information is valid
If Not rIPurchaseOrderLocal.Valid Then GoTo ErrorHandler

' Cancel the existing purchase order


If Not IPurchaseOrderExec_Cancel(rIPurchaseOrderLocal.ID) Then GoTo ErrorHandler

objCommand.ActiveConnection = gstrCONNECT
objCommand.CommandText = "sp_insert_PurchaseOrders"
objCommand.CommandType = adCmdStoredProc
' Create each parameter and supply it's data
objCommand.Parameters.Append _
objCommand.CreateParameter("IDPK", adInteger, _
adParamInput, , rIPurchaseOrderLocal.ID)
objCommand.Parameters.Append _
objCommand.CreateParameter("AccountIDFK", adInteger, _
adParamInput, , rIPurchaseOrderLocal.AccountID)
objCommand.Parameters.Append _
objCommand.CreateParameter("ShippingHandling", adCurrency, _
adParamInput, , rIPurchaseOrderLocal.ShippingHandling)
objCommand.Parameters.Append _
objCommand.CreateParameter("TaxRate", adDouble, _
adParamInput, , rIPurchaseOrderLocal.TaxRate)
objCommand.Parameters.Append _
objCommand.CreateParameter("Total", adCurrency, _
adParamInput, , rIPurchaseOrderLocal.Total)
objCommand.Parameters.Append _
objCommand.CreateParameter("ShipToFirstName", adVarChar, _
adParamInput, 20, rIPurchaseOrderLocal.ShipToFirstName)
objCommand.Parameters.Append _
objCommand.CreateParameter("ShipToLastName", adVarChar, _
adParamInput, 40, rIPurchaseOrderLocal.ShipToLastName)
objCommand.Parameters.Append _
objCommand.CreateParameter("ShipToAddressLine1", adVarChar, _
adParamInput, 20, rIPurchaseOrderLocal.ShipToAddressLine1)
objCommand.Parameters.Append _
objCommand.CreateParameter("ShipToAddressLine2", adVarChar, _
adParamInput, 20, rIPurchaseOrderLocal.ShipToAddressLine2)
objCommand.Parameters.Append _
objCommand.CreateParameter("ShipToCity", adVarChar, _
adParamInput, 20, rIPurchaseOrderLocal.ShipToCity)
objCommand.Parameters.Append _
objCommand.CreateParameter("ShipToState", adVarChar, _
adParamInput, 2, rIPurchaseOrderLocal.ShipToState)
objCommand.Parameters.Append _
objCommand.CreateParameter("ShipToZip", adVarChar, _
adParamInput, 5, rIPurchaseOrderLocal.ShipToZip)
objCommand.Parameters.Append _
objCommand.CreateParameter("ShipToPhone", adVarChar, _
adParamInput, 12, rIPurchaseOrderLocal.ShipToPhone)
objCommand.Parameters.Append _
objCommand.CreateParameter("ShipToEmail", adVarChar, _
adParamInput, 20, rIPurchaseOrderLocal.ShipToEmail)
' Execute the call
objCommand.Execute lngRecordsAffected
If lngRecordsAffected > 0 Then
Set rILineItemExec = GetObjectContext.CreateInstance("POExecutants.LineItemExec")
Set rIInventoryExec = GetObjectContext.CreateInstance("POExecutants.InventoryExec")
Set rIAccountExec = GetObjectContext.CreateInstance("POExecutants.AccountExec")
' Save the related LineItems
For lngLineItem = 1 To rIPurchaseOrderLocal.LineItems.Count
Set rILineItem = rIPurchaseOrderLocal.LineItems.Item(lngLineItem)
If Not rILineItem Is Nothing Then
rILineItem.PurchaseOrderID = rIPurchaseOrderLocal.ID
' Pass each LineItem ByRef since both
' components are in the same package
If rILineItemExec.Create(rILineItem, False) Then
' Decrement the QOH for each Inventory item
If Not rIInventoryExec.DecrementQOH(rILineItem.Item.ID, rILineItem.Quantity) Then
GoTo ErrorHandler
End If
Else
GoTo ErrorHandler
End If
End If
Next lngLineItem
' Increment the Account balance
If Not rIAccountExec.IncrementBalance(rIPurchaseOrderLocal.AccountID, rIPurchaseOrderLocal.Total) Then
GoTo ErrorHandler
End If
Else
GoTo ErrorHandler
End If
'
GetObjectContext.SetComplete
IPurchaseOrderExec_Modify = True
CleanUp:
Set rILineItem = Nothing
Set rIAccountExec = Nothing
Set rIInventoryExec = Nothing
Set rILineItemExec = Nothing
Set rIPurchaseOrderLocal = Nothing
Set objPropertyBag = Nothing
Set objCommand = Nothing
Exit Function
ErrorHandler:
GetObjectContext.SetAbort
GoTo CleanUp
End Function

Listing 37
Public Function Create(vntAccount As Variant, Optional ByVal blnByVal As Boolean = True) As Boolean
Dim rIAccount As IAccount

' Cast the generic object reference


' into a specific object type
If VarType(vntAccount) = vbObject Then
Set rIAccount = vntAccount
' Delegate the default interface implementation
' to the appropriate interface implementation
Create = IAccountExec_Create(rIAccount, blnByVal)
End If
Set rIAccount = Nothing
End Function

Public Function CreateRecordset(Optional ByVal strFilter As String = "") As ADODB.Recordset


' Delegate the default interface implementation
' to the appropriate interface implementation
Set CreateRecordset = IAccountExec_CreateRecordset(strFilter)
End Function

Public Function Destroy(ByVal lngAccountID As Long) As Boolean


' Delegate the default interface implementation
' to the appropriate interface implementation
Destroy = IAccountExec_Destroy(lngAccountID)
End Function

Public Function Modify(vntAccount As Variant, Optional ByVal blnByVal As Boolean = True) As Boolean
Dim rIAccount As IAccount

' Cast the generic object reference


' into a specific object type
If VarType(vntAccount) = vbObject Then
Set rIAccount = vntAccount
' Delegate the default interface implementation
' to the appropriate interface implementation
Modify = IAccountExec_Modify(rIAccount, blnByVal)
End If
Set rIAccount = Nothing
End Function

Public Function IncrementBalance(ByVal lngAccountID As Long, ByVal curAmount As Currency) As Boolean


' Delegate the default interface implementation
' to the appropriate interface implementation
IncrementBalance = IAccountExec_IncrementBalance(lngAccountID, curAmount)
End Function

Public Function DecrementBalance(ByVal lngAccountID As Long, ByVal curAmount As Currency) As Boolean


' Delegate the default interface implementation
' to the appropriate interface implementation
DecrementBalance = IAccountExec_DecrementBalance(lngAccountID, curAmount)
End Function

Listing 38
Public Function Create(vntInventory As Variant, Optional ByVal blnByVal As Boolean = True) As Boolean
Dim rIInventory As IInventory

' Cast the generic object reference


' into a specific object type
If VarType(vntInventory) = vbObject Then
Set rIInventory = vntInventory
' Delegate the default interface implementation
' to the appropriate interface implementation
Create = IInventoryExec_Create(rIInventory, blnByVal)
End If
Set rIInventory = Nothing
End Function

Public Function CreateRecordset(Optional ByVal strFilter As String = "") As ADODB.Recordset


' Delegate the default interface implementation
' to the appropriate interface implementation
Set CreateRecordset = IInventoryExec_CreateRecordset(strFilter)
End Function

Public Function Destroy(ByVal lngInventoryID As Long) As Boolean


' Delegate the default interface implementation
' to the appropriate interface implementation
Destroy = IInventoryExec_Destroy(lngInventoryID)
End Function

Public Function IncrementQOH(ByVal lngInventoryID As Long, ByVal lngQuantity As Long) As Boolean


' Delegate the default interface implementation
' to the appropriate interface implementation
IncrementQOH = IInventoryExec_IncrementQOH(lngInventoryID, lngQuantity)
End Function

Public Function DecrementQOH(ByVal lngInventoryID As Long, ByVal lngQuantity As Long) As Boolean


' Delegate the default interface implementation
' to the appropriate interface implementation
DecrementQOH = IInventoryExec_DecrementQOH(lngInventoryID, lngQuantity)
End Function

Public Function Modify(vntInventory As Variant, Optional ByVal blnByVal As Boolean = True) As Boolean
Dim rIInventory As IInventory
' Cast the generic object reference
' into a specific object type
If VarType(vntInventory) = vbObject Then
Set rIInventory = vntInventory
' Delegate the default interface implementation
' to the appropriate interface implementation
Modify = IInventoryExec_Modify(rIInventory, blnByVal)
End If
Set rIInventory = Nothing
End Function

Listing 39
Public Function CreateRecordset(Optional ByVal strFilter As String = "") As ADODB.Recordset
' Delegate the default interface implementation
' to the appropriate interface implementation
Set CreateRecordset = ILineItemExec_CreateRecordset(strFilter)
End Function

Public Function Create(vntLineItem As Variant, Optional ByVal blnByVal As Boolean = True) As Boolean
Dim rILineItem As ILineItem

' Cast the generic object reference


' into a specific object type
If VarType(vntLineItem) = vbObject Then
Set rILineItem = vntLineItem
' Delegate the default interface implementation
' to the appropriate interface implementation
Create = ILineItemExec_Create(rILineItem, blnByVal)
End If
Set rILineItem = Nothing
End Function

Public Function Destroy(ByVal lngLineItemID As Long) As Boolean


' Delegate the default interface implementation
' to the appropriate interface implementation
Destroy = ILineItemExec_Destroy(lngLineItemID)
End Function

Public Function DestroyByPurchaseOrder(ByVal lngLineItemID As Long) As Boolean


' Delegate the default interface implementation
' to the appropriate interface implementation
DestroyByPurchaseOrder = ILineItemExec_DestroyByPurchaseOrder(lngLineItemID)
End Function

Public Function Modify(vntLineItem As Variant, Optional ByVal blnByVal As Boolean = True) As Boolean
Dim rILineItem As ILineItem

' Cast the generic object reference


' into a specific object type
If VarType(vntLineItem) = vbObject Then
Set rILineItem = vntLineItem
' Delegate the default interface implementation
' to the appropriate interface implementation
Modify = ILineItemExec_Modify(rILineItem, blnByVal)
End If
Set rILineItem = Nothing
End Function

Listing 40
Public Function CreateRecordset(Optional ByVal strFilter As String = "") As ADODB.Recordset
' Delegate the default interface implementation
' to the appropriate interface implementation
Set CreateRecordset = IPurchaseOrderExec_CreateRecordset(strFilter)
End Function

Public Function Create(vntPurchaseOrder As Variant, Optional ByVal blnByVal As Boolean = True) As Boolean
Dim rIPurchaseOrder As IPurchaseOrder

' Cast the generic object reference


' into a specific object type
If VarType(vntPurchaseOrder) = vbObject Then
Set rIPurchaseOrder = vntPurchaseOrder
' Delegate the default interface implementation
' to the appropriate interface implementation
Create = IPurchaseOrderExec_Create(rIPurchaseOrder, blnByVal)
End If
Set rIPurchaseOrder = Nothing
End Function

Public Function Destroy(ByVal lngPurchaseOrderID As Long) As Boolean


' Delegate the default interface implementation
' to the appropriate interface implementation
Destroy = IPurchaseOrderExec_Destroy(lngPurchaseOrderID)
End Function

Public Function Modify(vntPurchaseOrder As Variant, Optional ByVal blnByVal As Boolean = True) As Boolean
Dim rIPurchaseOrder As IPurchaseOrder

' Cast the generic object reference


' into a specific object type
If VarType(vntPurchaseOrder) = vbObject Then
Set rIPurchaseOrder = vntPurchaseOrder
' Delegate the default interface implementation
' to the appropriate interface implementation
Modify = IPurchaseOrderExec_Modify(rIPurchaseOrder, blnByVal)
End If
Set rIPurchaseOrder = Nothing
End Function

Public Function Cancel(ByVal lngPurchaseOrderID As Long) As Boolean


' Delegate the default interface implementation
' to the appropriate interface implementation
Cancel = IPurchaseOrderExec_Cancel(lngPurchaseOrderID)
End Function

Listing 41
' UniqueIDAllocBatch
Option Explicit

Public Function AllocBatchOfUniqueIDs() As Long


Dim objCommand As New Command
Dim lngNextReceipt As Long

On Error GoTo ErrorHandler

objCommand.ActiveConnection = gstrCONNECT
objCommand.CommandText = "sp_AllocBatchOfUniqueIDs_UniqueIDs"
objCommand.CommandType = adCmdStoredProc
' Create each parameter and supply it's data
objCommand.Parameters.Append _
objCommand.CreateParameter("Return", adInteger, _
adParamReturnValue)
' Execute the call
objCommand.Execute
' Get the return value
lngNextReceipt = objCommand(0)

GetObjectContext.SetComplete
AllocBatchOfUniqueIDs = lngNextReceipt
CleanUp:
Set objCommand = Nothing

Exit Function
ErrorHandler:
GetObjectContext.SetAbort
AllocBatchOfUniqueIDs = -1

GoTo CleanUp
End Function
Listing 42
' UniqueIDGen
Option Explicit

Public Function GetNextUniqueID() As Long


Dim objSPMMgr As SharedPropertyGroupManager
Dim objSPMGroup As SharedPropertyGroup
Dim objSPMPropNextUniqueID As SharedProperty
Dim objSPMPropMaxIDOfCurrentBatch As SharedProperty
Dim objUniqueIDAllocBatch As UniqueIDAllocBatch
Dim blnResult As Boolean

On Error GoTo ErrorHandler

' If Shared property does not already exist it will be initialized


Set objSPMMgr = GetObjectContext.CreateInstance("MTxSpm.SharedPropertyGroupManager.1")
Set objSPMGroup = objSPMMgr.CreatePropertyGroup("UniqueIDs", LockMethod, Process, blnResult)
Set objSPMPropNextUniqueID = objSPMGroup.CreateProperty("NextID", blnResult)
Set objSPMPropMaxIDOfCurrentBatch = objSPMGroup.CreateProperty("MaxID", blnResult)

' Set the initial value of the Shared Property to


' 0 if the Shared Property didn't already exist.
' This is not entirely necessary but demonstrates how to initialize a value.
If blnResult = False Then
objSPMPropNextUniqueID.Value = 0
End If

If objSPMPropNextUniqueID.Value >= objSPMPropMaxIDOfCurrentBatch.Value Then


Set objUniqueIDAllocBatch = GetObjectContext.CreateInstance("POExecutants.UniqueIDAllocBatch")
objSPMPropNextUniqueID.Value = objUniqueIDAllocBatch.AllocBatchOfUniqueIDs()
Set objUniqueIDAllocBatch = Nothing
objSPMPropMaxIDOfCurrentBatch.Value = objSPMPropNextUniqueID.Value + 100
End If

' Get the next unique number and update property


objSPMPropNextUniqueID.Value = objSPMPropNextUniqueID.Value + 1

GetObjectContext.SetComplete
GetNextUniqueID = objSPMPropNextUniqueID.Value
CleanUp:
Set objSPMMgr = Nothing
Set objSPMGroup = Nothing
Set objSPMPropNextUniqueID = Nothing
Set objSPMPropMaxIDOfCurrentBatch = Nothing
Set objUniqueIDAllocBatch = Nothing

Exit Function
ErrorHandler:
GetObjectContext.SetAbort
GetNextUniqueID = -1

GoTo CleanUp
End Function

Listing 43
' AccountIterator
Option Explicit

' Define ADODB.Field variables to bind to each


' column of the recordset
Private mfldID As Field
Private mfldFirstName As Field
Private mfldLastName As Field
Private mfldAddressLine1 As Field
Private mfldAddressLine2 As Field
Private mfldCity As Field
Private mfldState As Field
Private mfldZip As Field
Private mfldPhone As Field
Private mfldEmail As Field
Private mfldBalance As Field
Private mfldLimit As Field

Private mrs As Recordset

Public Property Let AbsolutePage(ByVal RHS As ADODB.PositionEnum)


' Delegate to the private ADO recordset
mrs.AbsolutePage = RHS
End Property

Public Property Get AbsolutePage() As ADODB.PositionEnum


' Delegate to the private ADO recordset
AbsolutePage = mrs.AbsolutePage
End Property

Public Property Let AbsolutePosition(ByVal RHS As ADODB.PositionEnum)


' Delegate to the private ADO recordset
mrs.AbsolutePosition = RHS
End Property

Public Property Get AbsolutePosition() As ADODB.PositionEnum


' Delegate to the private ADO recordset
AbsolutePosition = mrs.AbsolutePosition
End Property

Public Property Get BOF() As Boolean


' Delegate to the private ADO recordset
BOF = mrs.BOF
End Property

Public Property Let Bookmark(ByVal RHS As Variant)


' Delegate to the private ADO recordset
mrs.Bookmark = RHS
End Property

Public Property Get Bookmark() As Variant


' Delegate to the private ADO recordset
Bookmark = mrs.Bookmark
End Property

Public Property Let CacheSize(ByVal RHS As Long)


' Delegate to the private ADO recordset
mrs.CacheSize = RHS
End Property

Public Property Get CacheSize() As Long


' Delegate to the private ADO recordset
CacheSize = mrs.CacheSize
End Property

Public Function Clone(Optional LockType As ADODB.LockTypeEnum = adLockUnspecified) As ADODB.Recordset


' Delegate to the private ADO recordset
Set Clone = mrs.Clone(LockType)
End Function

Public Property Get EOF() As Boolean


' Delegate to the private ADO recordset
EOF = mrs.EOF
End Property

Public Property Let Filter(ByVal RHS As String)


' Delegate to the private ADO recordset
mrs.Filter = RHS
End Property

Public Property Get Filter() As String


' Delegate to the private ADO recordset
Filter = mrs.Filter
End Property

Public Function Initialize(Optional ByVal strFilter As String = "") As Boolean


Dim objAccountExec As Object

' To minimize network traffic, only send


' pre-validated requests to the executant

Set objAccountExec = CreateObject("POExecutants.AccountExec")


Set mrs = objAccountExec.CreateRecordset(strFilter)
If Not mrs Is Nothing Then
' Bind to the columns of the recordset
BindToRecordsetFields
Initialize = True
End If

' Clean Up
Set objAccountExec = Nothing
End Function

Public Property Get Item() As Object


Dim objAccount As New Account

' Initialize the return value


Set Item = Nothing
' Configure the object to return
objAccount.ID = mfldID
objAccount.FirstName = mfldFirstName
objAccount.LastName = mfldLastName
objAccount.AddressLine1 = mfldAddressLine1
objAccount.AddressLine2 = mfldAddressLine2
objAccount.City = mfldCity
objAccount.State = mfldState
objAccount.Zip = mfldZip
objAccount.Phone = mfldPhone
objAccount.Email = mfldEmail
objAccount.Balance = mfldBalance
objAccount.Limit = mfldLimit
' Return the object
Set Item = objAccount

' Clean up
Set objAccount = Nothing
End Property

Public Property Let MaxRecords(ByVal RHS As Long)


' Delegate to the private ADO recordset
mrs.MaxRecords = RHS
End Property

Public Property Get MaxRecords() As Long


' Delegate to the private ADO recordset
MaxRecords = mrs.MaxRecords
End Property

Public Sub Move(ByVal NumRecords As Long, Optional Start As Variant = adBookmarkCurrent)


' Delegate to the private ADO recordset
mrs.Move NumRecords, Start
End Sub

Public Sub MoveFirst()


' Delegate to the private ADO recordset
mrs.MoveFirst
End Sub

Public Sub MoveLast()


' Delegate to the private ADO recordset
mrs.MoveLast
End Sub
Public Sub MoveNext()
' Delegate to the private ADO recordset
mrs.MoveNext
End Sub

Public Sub MovePrevious()


' Delegate to the private ADO recordset
mrs.MovePrevious
End Sub

Public Property Get PageCount() As Long


' Delegate to the private ADO recordset
PageCount = mrs.PageCount
End Property

Public Property Let PageSize(ByVal RHS As Long)


' Delegate to the private ADO recordset
mrs.PageSize = RHS
End Property

Public Property Get PageSize() As Long


' Delegate to the private ADO recordset
PageSize = mrs.PageSize
End Property

Public Property Get RecordCount() As Long


' Delegate to the private ADO recordset
RecordCount = mrs.RecordCount
End Property

Public Property Let Sort(ByVal RHS As String)


' Delegate to the private ADO recordset
mrs.Sort = RHS
End Property

Public Property Get Sort() As String


' Delegate to the private ADO recordset
Sort = mrs.Sort
End Property

Public Property Get State() As Long


' Delegate to the private ADO recordset
State = mrs.State
End Property

Private Sub BindToRecordsetFields()


' Bind the module-level ADODB.Field variables
' to the columns of the recordset
If Not mrs Is Nothing Then
Set mfldID = mrs("ID")
Set mfldFirstName = mrs("FirstName")
Set mfldLastName = mrs("LastName")
Set mfldAddressLine1 = mrs("AddressLine1")
Set mfldAddressLine2 = mrs("AddressLine2")
Set mfldCity = mrs("City")
Set mfldState = mrs("State")
Set mfldZip = mrs("Zip")
Set mfldPhone = mrs("Phone")
Set mfldEmail = mrs("Email")
Set mfldBalance = mrs("Balance")
Set mfldLimit = mrs("Limit")
End If
End Sub

Private Sub Class_Terminate()


' Release any module-level ADODB.Field references
Set mfldPhone = Nothing
Set mfldZip = Nothing
Set mfldState = Nothing
Set mfldCity = Nothing
Set mfldAddressLine1 = Nothing
Set mfldAddressLine2 = Nothing
Set mfldLastName = Nothing
Set mfldFirstName = Nothing
Set mfldID = Nothing
' Release any outstanding Recordset references
Set mrs = Nothing
End Sub

Listing 44
' InventoryIterator
Option Explicit

' Define ADODB.Field variables to bind to each


' column of the recordset
Private mfldID As Field
Private mfldDescription As Field
Private mfldPrice As Field
Private mfldQOH As Field

Private mrs As Recordset

Public Function Initialize(Optional ByVal strFilter As String = "") As Boolean


Dim objInventoryExec As Object

' To minimize network traffic, only send


' pre-validated requests to the executant

Set objInventoryExec = CreateObject("POExecutants.InventoryExec")


Set mrs = objInventoryExec.CreateRecordset(strFilter)
If Not mrs Is Nothing Then
' Bind to the columns of the recordset
BindToRecordsetFields
Initialize = True
End If

' Clean Up
Set objInventoryExec = Nothing
End Function

Public Property Get Item() As Object


Dim objInventory As New Inventory

' Initialize the return value


Set Item = Nothing
' Configure the object to return
objInventory.ID = mfldID
objInventory.Description = mfldDescription
objInventory.Price = mfldPrice
objInventory.QOH = mfldQOH
' Return the object
Set Item = objInventory

' Clean up
Set objInventory = Nothing
End Property

Private Sub BindToRecordsetFields()


' Bind the module-level ADODB.Field variables
' to the columns of the recordset
If Not mrs Is Nothing Then
Set mfldID = mrs("ID")
Set mfldDescription = mrs("Description")
Set mfldPrice = mrs("Price")
Set mfldQOH = mrs("QOH")
End If
End Sub

Private Sub Class_Terminate()


' Release any module-level ADODB.Field references
Set mfldQOH = Nothing
Set mfldPrice = Nothing
Set mfldDescription = Nothing
Set mfldID = Nothing
Set mrs = Nothing
' Release any outstanding Recordset references
Set mrs = Nothing
End Sub

Public Property Let AbsolutePage(ByVal RHS As ADODB.PositionEnum)


' Delegate to the private ADO recordset
mrs.AbsolutePage = RHS
End Property

Public Property Get AbsolutePage() As ADODB.PositionEnum


' Delegate to the private ADO recordset
AbsolutePage = mrs.AbsolutePage
End Property

Public Property Let AbsolutePosition(ByVal RHS As ADODB.PositionEnum)


' Delegate to the private ADO recordset
mrs.AbsolutePosition = RHS
End Property

Public Property Get AbsolutePosition() As ADODB.PositionEnum


' Delegate to the private ADO recordset
AbsolutePosition = mrs.AbsolutePosition
End Property

Public Property Get BOF() As Boolean


' Delegate to the private ADO recordset
BOF = mrs.BOF
End Property

Public Property Let Bookmark(ByVal RHS As Variant)


' Delegate to the private ADO recordset
mrs.Bookmark = RHS
End Property

Public Property Get Bookmark() As Variant


' Delegate to the private ADO recordset
Bookmark = mrs.Bookmark
End Property

Public Property Let CacheSize(ByVal RHS As Long)


' Delegate to the private ADO recordset
mrs.CacheSize = RHS
End Property

Public Property Get CacheSize() As Long


' Delegate to the private ADO recordset
CacheSize = mrs.CacheSize
End Property

Public Function Clone(Optional LockType As ADODB.LockTypeEnum = adLockUnspecified) As ADODB.Recordset


' Delegate to the private ADO recordset
Set Clone = mrs.Clone(LockType)
End Function

Public Property Get EOF() As Boolean


' Delegate to the private ADO recordset
EOF = mrs.EOF
End Property

Public Property Let Filter(ByVal RHS As String)


' Delegate to the private ADO recordset
mrs.Filter = RHS
End Property

Public Property Get Filter() As String


' Delegate to the private ADO recordset
Filter = mrs.Filter
End Property

Public Property Let MaxRecords(ByVal RHS As Long)


' Delegate to the private ADO recordset
mrs.MaxRecords = RHS
End Property

Public Property Get MaxRecords() As Long


' Delegate to the private ADO recordset
MaxRecords = mrs.MaxRecords
End Property

Public Sub Move(ByVal NumRecords As Long, Optional Start As Variant = adBookmarkCurrent)


' Delegate to the private ADO recordset
mrs.Move NumRecords, Start
End Sub

Public Sub MoveFirst()


' Delegate to the private ADO recordset
mrs.MoveFirst
End Sub

Public Sub MoveLast()


' Delegate to the private ADO recordset
mrs.MoveLast
End Sub

Public Sub MoveNext()


' Delegate to the private ADO recordset
mrs.MoveNext
End Sub

Public Sub MovePrevious()


' Delegate to the private ADO recordset
mrs.MovePrevious
End Sub

Public Property Get PageCount() As Long


' Delegate to the private ADO recordset
PageCount = mrs.PageCount
End Property

Public Property Let PageSize(ByVal RHS As Long)


' Delegate to the private ADO recordset
mrs.PageSize = RHS
End Property

Public Property Get PageSize() As Long


' Delegate to the private ADO recordset
PageSize = mrs.PageSize
End Property

Public Property Get RecordCount() As Long


' Delegate to the private ADO recordset
RecordCount = mrs.RecordCount
End Property

Public Property Let Sort(ByVal RHS As String)


' Delegate to the private ADO recordset
mrs.Sort = RHS
End Property

Public Property Get Sort() As String


' Delegate to the private ADO recordset
Sort = mrs.Sort
End Property

Public Property Get State() As Long


' Delegate to the private ADO recordset
State = mrs.State
End Property

Listing 45
' LineItemIterator
Option Explicit

' Define ADODB.Field variables to bind to each


' column of the recordset
Private mfldID As Field
Private mfldPurchaseOrderID As Field
Private mfldPrice As Field
Private mfldQuantity As Field
'
Private mfldInventoryID As Field
Private mfldInventoryDescription As Field
Private mfldInventoryPrice As Field
Private mfldInventoryQOH As Field

Private mrs As Recordset

Public Function Initialize(Optional ByVal strFilter As String = "") As Boolean


Dim objLineItemExec As Object

' To minimize network traffic, only send


' pre-validated requests to the executant

Set objLineItemExec = CreateObject("POExecutants.LineItemExec")


Set mrs = objLineItemExec.CreateRecordset(strFilter)
If Not mrs Is Nothing Then
' Bind to the columns of the recordset
BindToRecordsetFields
Initialize = True
End If

' Clean Up
Set objLineItemExec = Nothing
End Function

Public Property Get Item() As Object


Dim objLineItem As New LineItem
Dim objInventory As New Inventory

' Initialize the return value


Set Item = Nothing
' Configure the object to return
objLineItem.ID = mfldID
objLineItem.PurchaseOrderID = mfldPurchaseOrderID
'
objInventory.ID = mfldInventoryID
objInventory.Description = mfldInventoryDescription
objInventory.Price = mfldInventoryPrice
objInventory.QOH = mfldInventoryQOH
'
Set objLineItem.Item = objInventory
objLineItem.Price = mfldPrice
objLineItem.Quantity = mfldQuantity
' Return the object
Set Item = objLineItem

' Clean up
Set objInventory = Nothing
Set objLineItem = Nothing
End Property

Private Sub BindToRecordsetFields()


' Bind the module-level ADODB.Field variables
' to the columns of the recordset
If Not mrs Is Nothing Then
Set mfldID = mrs("ID")
Set mfldPurchaseOrderID = mrs("PurchaseOrderID")
Set mfldPrice = mrs("Price")
Set mfldQuantity = mrs("Quantity")
Set mfldInventoryID = mrs("Inventory.ID")
Set mfldInventoryDescription = mrs("Inventory.Description")
Set mfldInventoryPrice = mrs("Inventory.Price")
Set mfldInventoryQOH = mrs("Inventory.QOH")
End If
End Sub

Private Sub Class_Terminate()


' Release any module-level ADODB.Field references
Set mfldInventoryQOH = Nothing
Set mfldInventoryPrice = Nothing
Set mfldInventoryDescription = Nothing
'
Set mfldQuantity = Nothing
Set mfldPrice = Nothing
Set mfldInventoryID = Nothing
Set mfldPurchaseOrderID = Nothing
Set mfldID = Nothing
' Release any outstanding Recordset references
Set mrs = Nothing
End Sub

Public Property Let AbsolutePage(ByVal RHS As ADODB.PositionEnum)


' Delegate to the private ADO recordset
mrs.AbsolutePage = RHS
End Property

Public Property Get AbsolutePage() As ADODB.PositionEnum


' Delegate to the private ADO recordset
AbsolutePage = mrs.AbsolutePage
End Property

Public Property Let AbsolutePosition(ByVal RHS As ADODB.PositionEnum)


' Delegate to the private ADO recordset
mrs.AbsolutePosition = RHS
End Property

Public Property Get AbsolutePosition() As ADODB.PositionEnum


' Delegate to the private ADO recordset
AbsolutePosition = mrs.AbsolutePosition
End Property

Public Property Get BOF() As Boolean


' Delegate to the private ADO recordset
BOF = mrs.BOF
End Property

Public Property Let Bookmark(ByVal RHS As Variant)


' Delegate to the private ADO recordset
mrs.Bookmark = RHS
End Property

Public Property Get Bookmark() As Variant


' Delegate to the private ADO recordset
Bookmark = mrs.Bookmark
End Property

Public Property Let CacheSize(ByVal RHS As Long)


' Delegate to the private ADO recordset
mrs.CacheSize = RHS
End Property

Public Property Get CacheSize() As Long


' Delegate to the private ADO recordset
CacheSize = mrs.CacheSize
End Property
Public Function Clone(Optional LockType As ADODB.LockTypeEnum = adLockUnspecified) As ADODB.Recordset
' Delegate to the private ADO recordset
Set Clone = mrs.Clone(LockType)
End Function

Public Property Get EOF() As Boolean


' Delegate to the private ADO recordset
EOF = mrs.EOF
End Property

Public Property Let Filter(ByVal RHS As String)


' Delegate to the private ADO recordset
mrs.Filter = RHS
End Property

Public Property Get Filter() As String


' Delegate to the private ADO recordset
Filter = mrs.Filter
End Property

Public Property Let MaxRecords(ByVal RHS As Long)


' Delegate to the private ADO recordset
mrs.MaxRecords = RHS
End Property

Public Property Get MaxRecords() As Long


' Delegate to the private ADO recordset
MaxRecords = mrs.MaxRecords
End Property

Public Sub Move(ByVal NumRecords As Long, Optional Start As Variant = adBookmarkCurrent)


' Delegate to the private ADO recordset
mrs.Move NumRecords, Start
End Sub

Public Sub MoveFirst()


' Delegate to the private ADO recordset
mrs.MoveFirst
End Sub

Public Sub MoveLast()


' Delegate to the private ADO recordset
mrs.MoveLast
End Sub

Public Sub MoveNext()


' Delegate to the private ADO recordset
mrs.MoveNext
End Sub

Public Sub MovePrevious()


' Delegate to the private ADO recordset
mrs.MovePrevious
End Sub

Public Property Get PageCount() As Long


' Delegate to the private ADO recordset
PageCount = mrs.PageCount
End Property

Public Property Let PageSize(ByVal RHS As Long)


' Delegate to the private ADO recordset
mrs.PageSize = RHS
End Property

Public Property Get PageSize() As Long


' Delegate to the private ADO recordset
PageSize = mrs.PageSize
End Property
Public Property Get RecordCount() As Long
' Delegate to the private ADO recordset
RecordCount = mrs.RecordCount
End Property

Public Property Let Sort(ByVal RHS As String)


' Delegate to the private ADO recordset
mrs.Sort = RHS
End Property

Public Property Get Sort() As String


' Delegate to the private ADO recordset
Sort = mrs.Sort
End Property

Public Property Get State() As Long


' Delegate to the private ADO recordset
State = mrs.State
End Property

Listing 46
' PurchaseOrderIterator
Option Explicit

' Define ADODB.Field variables to bind to each


' column of the recordset
Private mfldID As Field
Private mfldAccountID As Field
Private mfldOrderDate As Field
Private mfldShippingHandling As Field
Private mfldTaxRate As Field
Private mfldTotal As Field
Private mfldShipToFirstName As Field
Private mfldShipToLastName As Field
Private mfldShipToAddressLine1 As Field
Private mfldShipToAddressLine2 As Field
Private mfldShipToCity As Field
Private mfldShipToState As Field
Private mfldShipToZip As Field
Private mfldShipToPhone As Field
Private mfldShipToEmail As Field

Private mrs As Recordset

Public Function Initialize(Optional ByVal strFilter As String = "") As Boolean


Dim objPurchaseOrderExec As Object

' To minimize network traffic, only send


' pre-validated requests to the executant

Set objPurchaseOrderExec = CreateObject("POExecutants.PurchaseOrderExec")


Set mrs = objPurchaseOrderExec.CreateRecordset(strFilter)
If Not mrs Is Nothing Then
' Bind to the columns of the recordset
BindToRecordsetFields
Initialize = True
End If

' Clean Up
Set objPurchaseOrderExec = Nothing
End Function

Public Property Get Item() As Object


Dim objPurchaseOrder As New PurchaseOrder
Dim rsLineItems As Recordset
Dim objLineItem As LineItem
Dim objInventory As Inventory

' Initialize the return value


Set Item = Nothing
' Configure the object to return
objPurchaseOrder.ID = mfldID
objPurchaseOrder.AccountID = mfldAccountID
objPurchaseOrder.OrderDate = mfldOrderDate
objPurchaseOrder.ShippingHandling = mfldShippingHandling
objPurchaseOrder.TaxRate = mfldTaxRate
objPurchaseOrder.Total = mfldTotal
objPurchaseOrder.ShipToFirstName = mfldShipToFirstName
objPurchaseOrder.ShipToLastName = mfldShipToLastName
objPurchaseOrder.ShipToAddressLine1 = mfldShipToAddressLine1
objPurchaseOrder.ShipToAddressLine2 = mfldShipToAddressLine2
objPurchaseOrder.ShipToCity = mfldShipToCity
objPurchaseOrder.ShipToState = mfldShipToState
objPurchaseOrder.ShipToZip = mfldShipToZip
objPurchaseOrder.ShipToPhone = mfldShipToPhone
objPurchaseOrder.ShipToEmail = mfldShipToEmail
' Iterate through the child recordset
Set rsLineItems = mrs("chapPurchaseOrderLineItems").Value
' Add each line item to the purchase order
Do While Not rsLineItems.EOF
Set objLineItem = New LineItem
objLineItem.ID = rsLineItems("ID")
objLineItem.PurchaseOrderID = rsLineItems("PurchaseOrderID")
objLineItem.Price = rsLineItems("Price")
objLineItem.Quantity = rsLineItems("Quantity")
'
Set objInventory = New Inventory
objInventory.ID = rsLineItems("Inventory.ID")
objInventory.Description = rsLineItems("Inventory.Description")
objInventory.Price = rsLineItems("Inventory.Price")
objInventory.QOH = rsLineItems("Inventory.QOH")
'
Set objLineItem.Item = objInventory
objPurchaseOrder.LineItems.Add objLineItem
rsLineItems.MoveNext
Loop

' Return the object


Set Item = objPurchaseOrder

' Clean up
Set objInventory = Nothing
Set objLineItem = Nothing
Set rsLineItems = Nothing
Set objPurchaseOrder = Nothing
End Property

Private Sub BindToRecordsetFields()


' Bind the module-level ADODB.Field variables
' to the columns of the recordset
If Not mrs Is Nothing Then
Set mfldID = mrs("ID")
Set mfldAccountID = mrs("Account.ID")
Set mfldOrderDate = mrs("OrderDate")
Set mfldShippingHandling = mrs("ShippingHandling")
Set mfldTaxRate = mrs("TaxRate")
Set mfldTotal = mrs("Total")
Set mfldShipToFirstName = mrs("ShipToFirstName")
Set mfldShipToLastName = mrs("ShipToLastName")
Set mfldShipToAddressLine1 = mrs("ShipToAddressLine1")
Set mfldShipToAddressLine2 = mrs("ShipToAddressLine2")
Set mfldShipToCity = mrs("ShipToCity")
Set mfldShipToState = mrs("ShipToState")
Set mfldShipToZip = mrs("ShipToZip")
Set mfldShipToPhone = mrs("ShipToPhone")
Set mfldShipToEmail = mrs("ShipToEmail")
End If
End Sub
Private Sub Class_Terminate()
' Release any module-level ADODB.Field references
Set mfldShipToEmail = Nothing
Set mfldShipToPhone = Nothing
Set mfldShipToZip = Nothing
Set mfldShipToState = Nothing
Set mfldShipToCity = Nothing
Set mfldShipToAddressLine2 = Nothing
Set mfldShipToAddressLine1 = Nothing
Set mfldShipToLastName = Nothing
Set mfldShipToFirstName = Nothing
Set mfldTotal = Nothing
Set mfldTaxRate = Nothing
Set mfldShippingHandling = Nothing
Set mfldOrderDate = Nothing
Set mfldAccountID = Nothing
Set mfldID = Nothing
' Release any outstanding Recordset references
Set mrs = Nothing
End Sub

Public Property Let AbsolutePage(ByVal RHS As ADODB.PositionEnum)


' Delegate to the private ADO recordset
mrs.AbsolutePage = RHS
End Property

Public Property Get AbsolutePage() As ADODB.PositionEnum


' Delegate to the private ADO recordset
AbsolutePage = mrs.AbsolutePage
End Property

Public Property Let AbsolutePosition(ByVal RHS As ADODB.PositionEnum)


' Delegate to the private ADO recordset
mrs.AbsolutePosition = RHS
End Property

Public Property Get AbsolutePosition() As ADODB.PositionEnum


' Delegate to the private ADO recordset
AbsolutePosition = mrs.AbsolutePosition
End Property

Public Property Get BOF() As Boolean


' Delegate to the private ADO recordset
BOF = mrs.BOF
End Property

Public Property Let Bookmark(ByVal RHS As Variant)


' Delegate to the private ADO recordset
mrs.Bookmark = RHS
End Property

Public Property Get Bookmark() As Variant


' Delegate to the private ADO recordset
Bookmark = mrs.Bookmark
End Property

Public Property Let CacheSize(ByVal RHS As Long)


' Delegate to the private ADO recordset
mrs.CacheSize = RHS
End Property

Public Property Get CacheSize() As Long


' Delegate to the private ADO recordset
CacheSize = mrs.CacheSize
End Property

Public Function Clone(Optional LockType As ADODB.LockTypeEnum = adLockUnspecified) As ADODB.Recordset


' Delegate to the private ADO recordset
Set Clone = mrs.Clone(LockType)
End Function
Public Property Get EOF() As Boolean
' Delegate to the private ADO recordset
EOF = mrs.EOF
End Property

Public Property Let Filter(ByVal RHS As String)


' Delegate to the private ADO recordset
mrs.Filter = RHS
End Property

Public Property Get Filter() As String


' Delegate to the private ADO recordset
Filter = mrs.Filter
End Property

Public Property Let MaxRecords(ByVal RHS As Long)


' Delegate to the private ADO recordset
mrs.MaxRecords = RHS
End Property

Public Property Get MaxRecords() As Long


' Delegate to the private ADO recordset
MaxRecords = mrs.MaxRecords
End Property

Public Sub Move(ByVal NumRecords As Long, Optional Start As Variant = adBookmarkCurrent)


' Delegate to the private ADO recordset
mrs.Move NumRecords, Start
End Sub

Public Sub MoveFirst()


' Delegate to the private ADO recordset
mrs.MoveFirst
End Sub

Public Sub MoveLast()


' Delegate to the private ADO recordset
mrs.MoveLast
End Sub

Public Sub MoveNext()


' Delegate to the private ADO recordset
mrs.MoveNext
End Sub

Public Sub MovePrevious()


' Delegate to the private ADO recordset
mrs.MovePrevious
End Sub

Public Property Get PageCount() As Long


' Delegate to the private ADO recordset
PageCount = mrs.PageCount
End Property

Public Property Let PageSize(ByVal RHS As Long)


' Delegate to the private ADO recordset
mrs.PageSize = RHS
End Property

Public Property Get PageSize() As Long


' Delegate to the private ADO recordset
PageSize = mrs.PageSize
End Property

Public Property Get RecordCount() As Long


' Delegate to the private ADO recordset
RecordCount = mrs.RecordCount
End Property
Public Property Let Sort(ByVal RHS As String)
' Delegate to the private ADO recordset
mrs.Sort = RHS
End Property

Public Property Get Sort() As String


' Delegate to the private ADO recordset
Sort = mrs.Sort
End Property

Public Property Get State() As Long


' Delegate to the private ADO recordset
State = mrs.State
End Property

Listing 47
' InvalidProperties
Option Explicit

Private mcolInvalidProperties As New Collection

Public Property Get Count() As Variant


Count = mcolInvalidProperties.Count
End Property

Public Property Get Item(ByVal lngIndex As Long) As Long


' Return rule # (1 To Count)
Item = mcolInvalidProperties.Item(lngIndex)
End Property

Public Sub Track(ByVal lngRuleNumber As Long, ByVal blnInvalid As Boolean)


On Error GoTo ErrorHandler

If blnInvalid Then
' Add the invalid property to the collection
' if it doesn't already exist
mcolInvalidProperties.Add lngRuleNumber, "Key=" & CStr(lngRuleNumber)
Else
' Remove the invalid property from the
' collection if it exists
mcolInvalidProperties.Remove "Key=" & CStr(lngRuleNumber)
End If
ErrorHandler:
End Sub

Private Sub Class_ReadProperties(PropBag As PropertyBag)


Dim lngCount As Long
Dim lngIndex As Long
Dim lngRuleNumber As String

Set mcolInvalidProperties = New Collection

' Read the total number of items


lngCount = PropBag.ReadProperty("InvalidProperties", 0)
' VB Collections don't support persistence
' so we must read each collection item
' from the property bag manually
For lngIndex = 1 To lngCount
lngRuleNumber = PropBag.ReadProperty("InvalidProp" & CStr(lngIndex), 0)
Track lngRuleNumber, True
Next lngIndex
End Sub

Private Sub Class_Terminate()


Set mcolInvalidProperties = Nothing
End Sub

Private Sub Class_WriteProperties(PropBag As PropertyBag)


Dim lngCount As Long
Dim lngIndex As Long
Dim lngRuleNumber As Long

' Save the total number of items


lngCount = mcolInvalidProperties.Count
' VB Collections don't support persistence
' so we must write each collection item
' to the property bag manually
PropBag.WriteProperty "InvalidProperties", lngCount, 0
For lngIndex = 1 To lngCount
lngRuleNumber = mcolInvalidProperties.Item(lngIndex)
PropBag.WriteProperty "InvalidProp" & CStr(lngIndex), lngRuleNumber, 0
Next lngIndex
End Sub

Listing 48
' Account
Option Explicit

Implements IAccount
Private mobjInvalidProperties As New InvalidProperties

Private mlngID As Long


Private mstrFirstName As String
Private mstrLastName As String
Private mstrAddressLine1 As String
Private mstrAddressLine2 As String
Private mstrCity As String
Private mstrState As String
Private mstrZip As String
Private mstrPhone As String
Private mstrEmail As String
Private mcurBalance As Currency
Private mcurLimit As Currency

Public Function Save() As Boolean


Dim lngRuleNumber As Long
Dim rIAccountExec As IAccountExec
Dim blnInvalid As Boolean

' To minimize network traffic, only send


' pre-validated requests to the executant

' Make sure the object is valid before


' attempting to save it
If mobjInvalidProperties.Count > 0 Then
' The object is invalid & the first
' invalid property is the error
lngRuleNumber = mobjInvalidProperties.Item(1)
Err.Raise vbObjectError + lngRuleNumber, LoadResString(IDS_PROJECTNAME), LoadResString(lngRuleNumber)
Else
Set rIAccountExec = CreateObject("POExecutants.AccountExec")
If mlngID = -1 Then
' Create a new Account
blnInvalid = Not rIAccountExec.Create(Me)
Else
' Modify an existing Account
blnInvalid = Not rIAccountExec.Modify(Me)
End If
If blnInvalid Then
' Notify the client of any error
Err.Raise vbObjectError + IDS_INVALID_ACCOUNT_SAVE, LoadResString(IDS_PROJECTNAME),
LoadResString(IDS_INVALID_ACCOUNT_SAVE)
Else
Save = True
End If
End If

Set rIAccountExec = Nothing


End Function
Public Function Destroy() As Boolean
Dim rIAccountExec As IAccountExec
Dim blnInvalid As Boolean

' To minimize network traffic, only send


' pre-validated requests to the executant

Set rIAccountExec = CreateObject("POExecutants.AccountExec")


blnInvalid = Not rIAccountExec.Destroy(mlngID)
If blnInvalid Then
' Notify the client of any error
Err.Raise vbObjectError + IDS_INVALID_ACCOUNT_DESTROY, LoadResString(IDS_PROJECTNAME),
LoadResString(IDS_INVALID_ACCOUNT_DESTROY)
Else
Destroy = True
End If
' Clean Up
Set rIAccountExec = Nothing
End Function

Private Sub Class_Initialize()


' Initialize private members
mlngID = -1
' Track properties that are initially invalid but
' must become valid before the entire object can be
' deemed "Valid".
mobjInvalidProperties.Track IDS_INVALID_ACCOUNT_FIRSTNAME, True
mobjInvalidProperties.Track IDS_INVALID_ACCOUNT_LASTNAME, True
mobjInvalidProperties.Track IDS_INVALID_ACCOUNT_ADDRESS, True
mobjInvalidProperties.Track IDS_INVALID_ACCOUNT_CITY, True
mobjInvalidProperties.Track IDS_INVALID_ACCOUNT_STATE, True
mobjInvalidProperties.Track IDS_INVALID_ACCOUNT_ZIP, True
End Sub

Private Sub Class_ReadProperties(PropBag As PropertyBag)


' Load the saved state for the object
mlngID = PropBag.ReadProperty("ID", -1)
mstrFirstName = PropBag.ReadProperty("FirstName", "")
mstrLastName = PropBag.ReadProperty("LastName", "")
mstrAddressLine1 = PropBag.ReadProperty("AddressLine1", "")
mstrAddressLine2 = PropBag.ReadProperty("AddressLine2", "")
mstrCity = PropBag.ReadProperty("City", "")
mstrState = PropBag.ReadProperty("State", "")
mstrZip = PropBag.ReadProperty("Zip", "")
mstrPhone = PropBag.ReadProperty("Phone", "")
mstrEmail = PropBag.ReadProperty("Email", "")
mcurBalance = PropBag.ReadProperty("Balance", 0)
mcurLimit = PropBag.ReadProperty("Limit", 0)
' Load the invalid property information
Set mobjInvalidProperties = PropBag.ReadProperty("InvalidProperties", Nothing)
End Sub

Private Sub Class_Terminate()


' Clean up
Set mobjInvalidProperties = Nothing
End Sub

Private Sub Class_WriteProperties(PropBag As PropertyBag)


' Save the current state of the object
PropBag.WriteProperty "ID", mlngID, -1
PropBag.WriteProperty "FirstName", mstrFirstName, ""
PropBag.WriteProperty "LastName", mstrLastName, ""
PropBag.WriteProperty "AddressLine1", mstrAddressLine1, ""
PropBag.WriteProperty "AddressLine2", mstrAddressLine2, ""
PropBag.WriteProperty "City", mstrCity, ""
PropBag.WriteProperty "State", mstrState, ""
PropBag.WriteProperty "Zip", mstrZip, ""
PropBag.WriteProperty "Phone", mstrPhone, ""
PropBag.WriteProperty "Email", mstrEmail, ""
PropBag.WriteProperty "Balance", mcurBalance, 0
PropBag.WriteProperty "Limit", mcurLimit, 0
' Save the invalid property information
PropBag.WriteProperty "InvalidProperties", mobjInvalidProperties, Nothing
End Sub

Private Property Let IAccount_AddressLine1(ByVal RHS As String)


Dim blnInvalid As Boolean

' Perform any data validation that does not require


' access to the data services

' Limit AddressLine1 to 20 characters


RHS = Trim$(Left$(RHS, 20))
' Address cannot be blank
If RHS = "" And mstrAddressLine2 = "" Then
blnInvalid = True
Else
blnInvalid = False
mstrAddressLine1 = RHS
End If
' Track whether or not the property is invalid
mobjInvalidProperties.Track IDS_INVALID_ACCOUNT_ADDRESS, blnInvalid
' Notify the client of any error
If blnInvalid Then
Err.Raise vbObjectError + IDS_INVALID_ACCOUNT_ADDRESS, LoadResString(IDS_PROJECTNAME),
LoadResString(IDS_INVALID_ACCOUNT_ADDRESS)
End If
End Property

Private Property Get IAccount_AddressLine1() As String


IAccount_AddressLine1 = mstrAddressLine1
End Property

Private Property Let IAccount_AddressLine2(ByVal RHS As String)


Dim blnInvalid As Boolean

' Perform any data validation that does not require


' access to the data services

' Limit AddressLine2 to 20 characters


RHS = Trim$(Left$(RHS, 20))
' Address cannot be blank
If RHS = "" And mstrAddressLine1 = "" Then
blnInvalid = True
Else
blnInvalid = False
mstrAddressLine2 = RHS
End If
' Track whether or not the property is invalid
mobjInvalidProperties.Track IDS_INVALID_ACCOUNT_ADDRESS, blnInvalid
' Notify the client of any error
If blnInvalid Then
Err.Raise vbObjectError + IDS_INVALID_ACCOUNT_ADDRESS, LoadResString(IDS_PROJECTNAME),
LoadResString(IDS_INVALID_ACCOUNT_ADDRESS)
End If
End Property

Private Property Get IAccount_AddressLine2() As String


IAccount_AddressLine2 = mstrAddressLine2
End Property

Private Property Let IAccount_Balance(ByVal RHS As Currency)


' Perform any data validation that does not require
' access to the data services

mcurBalance = RHS
End Property

Private Property Get IAccount_Balance() As Currency


IAccount_Balance = mcurBalance
End Property

Private Property Let IAccount_City(ByVal RHS As String)


Dim blnInvalid As Boolean

' Perform any data validation that does not require


' access to the data services

' Limit City to 20 characters


RHS = Trim$(Left$(RHS, 20))
' City cannot be blank
If RHS = "" Then
blnInvalid = True
Else
blnInvalid = False
mstrCity = RHS
End If
' Track whether or not the property is invalid
mobjInvalidProperties.Track IDS_INVALID_ACCOUNT_CITY, blnInvalid
' Notify the client of any error
If blnInvalid Then
Err.Raise vbObjectError + IDS_INVALID_ACCOUNT_CITY, LoadResString(IDS_PROJECTNAME),
LoadResString(IDS_INVALID_ACCOUNT_CITY)
End If
End Property

Private Property Get IAccount_City() As String


IAccount_City = mstrCity
End Property

Public Function IncrementBalance(ByVal curAmount As Currency) As Boolean


Dim rIAccountExec As IAccountExec

' To minimize network traffic, only send


' pre-validated requests to the executant

Set rIAccountExec = CreateObject("POExecutants.AccountExec")


IncrementBalance = rIAccountExec.IncrementBalance(mlngID, curAmount)

' Clean Up
Set rIAccountExec = Nothing
End Function

Public Function DecrementBalance(ByVal curAmount As Currency) As Boolean


Dim rIAccountExec As IAccountExec

' To minimize network traffic, only send


' pre-validated requests to the executant

Set rIAccountExec = CreateObject("POExecutants.AccountExec")


DecrementBalance = rIAccountExec.DecrementBalance(mlngID, curAmount)

' Clean Up
Set rIAccountExec = Nothing
End Function

Private Property Let IAccount_Email(ByVal RHS As String)


' Perform any data validation that does not require
' access to the data services

' Limit Email to 20 characters


mstrEmail = Trim$(Left$(RHS, 20))
End Property

Private Property Get IAccount_Email() As String


IAccount_Email = mstrEmail
End Property

Private Property Let IAccount_FirstName(ByVal RHS As String)


Dim blnInvalid As Boolean

' Perform any data validation that does not require


' access to the data services

' Limit FirstName to 20 characters


RHS = Trim$(Left$(RHS, 20))
' FirstName cannot be blank
If RHS = "" Then
blnInvalid = True
Else
blnInvalid = False
mstrFirstName = RHS
End If
' Track whether or not the property is invalid
mobjInvalidProperties.Track IDS_INVALID_ACCOUNT_FIRSTNAME, blnInvalid
' Notify the client of any error
If blnInvalid Then
Err.Raise vbObjectError + IDS_INVALID_ACCOUNT_FIRSTNAME, LoadResString(IDS_PROJECTNAME),
LoadResString(IDS_INVALID_ACCOUNT_FIRSTNAME)
End If
End Property

Private Property Get IAccount_FirstName() As String


IAccount_FirstName = mstrFirstName
End Property

Private Property Let IAccount_ID(ByVal RHS As Long)


' Perform any data validation that does not require
' access to the data services
mlngID = RHS
End Property

Private Property Get IAccount_ID() As Long


IAccount_ID = mlngID
End Property

Private Property Let IAccount_LastName(ByVal RHS As String)


Dim blnInvalid As Boolean

' Perform any data validation that does not require


' access to the data services

' Limit LastName to 40 characters


RHS = Trim$(Left$(RHS, 40))
' LastName cannot be blank
If RHS = "" Then
blnInvalid = True
Else
blnInvalid = False
mstrLastName = RHS
End If
' Track whether or not the property is invalid
mobjInvalidProperties.Track IDS_INVALID_ACCOUNT_LASTNAME, blnInvalid
' Notify the client of any error
If blnInvalid Then
Err.Raise vbObjectError + IDS_INVALID_ACCOUNT_LASTNAME, LoadResString(IDS_PROJECTNAME),
LoadResString(IDS_INVALID_ACCOUNT_LASTNAME)
End If
End Property

Private Property Get IAccount_LastName() As String


IAccount_LastName = mstrLastName
End Property

Private Property Let IAccount_Limit(ByVal RHS As Currency)


' Perform any data validation that does not require
' access to the data services

mcurLimit = RHS
End Property

Private Property Get IAccount_Limit() As Currency


IAccount_Limit = mcurLimit
End Property

Private Function IAccount_MarshalToPropertyBag(strKey As String) As Byte()


Dim objPropertyBag As New PropertyBag

' Return the key that identifies the


' object state information ByRef
strKey = "AccountState"
' Marshal this object instance to the property bag
objPropertyBag.WriteProperty strKey, Me, Nothing
' Return the contents of the property bag
' which can be assigned to another property bag
' and accessed via 'strKey' to recreate the object
IAccount_MarshalToPropertyBag = objPropertyBag.Contents

Set objPropertyBag = Nothing


End Function

Private Property Let IAccount_Phone(ByVal RHS As String)


' Perform any data validation that does not require
' access to the data services

' Limit Phone to 12 characters


mstrPhone = Trim$(Left$(RHS, 12))
End Property

Private Property Get IAccount_Phone() As String


IAccount_Phone = mstrPhone
End Property

Private Property Let IAccount_State(ByVal RHS As String)


Dim intCharacterCode As Integer
Dim intPos As Integer
Dim blnInvalid As Boolean

' Perform any data validation that does not require


' access to the data services

' State must be 2 alpha characters


If Len(RHS) = 2 Then
blnInvalid = False
For intPos = 1 To 2
intCharacterCode = Asc(Mid$(RHS, intPos, 1))
If intCharacterCode < 65 Or intCharacterCode > 122 Then
blnInvalid = True
Exit For
End If
Next intPos
' If the new value is valid then save it
If Not blnInvalid Then
mstrState = RHS
End If
Else
blnInvalid = True
End If
' Track whether or not the property is invalid
mobjInvalidProperties.Track IDS_INVALID_ACCOUNT_STATE, blnInvalid
' Notify the client of any error
If blnInvalid Then
Err.Raise vbObjectError + IDS_INVALID_ACCOUNT_STATE, LoadResString(IDS_PROJECTNAME),
LoadResString(IDS_INVALID_ACCOUNT_STATE)
End If
End Property

Private Property Get IAccount_State() As String


IAccount_State = mstrState
End Property

Private Property Get IAccount_Valid() As Boolean


' The entire object cannot be valid unless
' all of its properties are valid
IAccount_Valid = (mobjInvalidProperties.Count = 0)
End Property

Private Property Let IAccount_Zip(ByVal RHS As String)


Dim intCharacterCode As Integer
Dim intPos As Integer
Dim blnInvalid As Boolean

' Perform any data validation that does not require


' access to the data services

' Zip must be 5 numeric characters


If Len(RHS) = 5 Then
blnInvalid = False
For intPos = 1 To 5
intCharacterCode = Asc(Mid$(RHS, intPos, 1))
If intCharacterCode < 48 Or intCharacterCode > 57 Then
blnInvalid = True
Exit For
End If
Next intPos
' If the new value is valid then save it
If Not blnInvalid Then
mstrZip = RHS
End If
Else
blnInvalid = True
End If
' Track whether or not the property is invalid
mobjInvalidProperties.Track IDS_INVALID_ACCOUNT_ZIP, blnInvalid
' Notify the client of any error
If blnInvalid Then
Err.Raise vbObjectError + IDS_INVALID_ACCOUNT_ZIP, LoadResString(IDS_PROJECTNAME),
LoadResString(IDS_INVALID_ACCOUNT_ZIP)
End If
End Property

Private Property Get IAccount_Zip() As String


IAccount_Zip = mstrZip
End Property

Public Property Get AddressLine1() As String


' Delegate the default interface implementation
' to the appropriate interface implementation
AddressLine1 = IAccount_AddressLine1
End Property

Public Property Let AddressLine1(ByVal strNewValue As String)


' Delegate the default interface implementation
' to the appropriate interface implementation
IAccount_AddressLine1 = strNewValue
End Property

Public Property Get AddressLine2() As String


' Delegate the default interface implementation
' to the appropriate interface implementation
AddressLine2 = IAccount_AddressLine2
End Property

Public Property Let AddressLine2(ByVal strNewValue As String)


' Delegate the default interface implementation
' to the appropriate interface implementation
IAccount_AddressLine2 = strNewValue
End Property
Public Property Get Balance() As Currency
' Delegate the default interface implementation
' to the appropriate interface implementation
Balance = IAccount_Balance
End Property

Public Property Let Balance(ByVal curNewValue As Currency)


' Delegate the default interface implementation
' to the appropriate interface implementation
IAccount_Balance = curNewValue
End Property

Public Property Get City() As String


' Delegate the default interface implementation
' to the appropriate interface implementation
City = IAccount_City
End Property

Public Property Let City(ByVal strNewValue As String)


' Delegate the default interface implementation
' to the appropriate interface implementation
IAccount_City = strNewValue
End Property

Public Property Get State() As String


' Delegate the default interface implementation
' to the appropriate interface implementation
State = IAccount_State
End Property

Public Property Let State(ByVal strNewValue As String)


' Delegate the default interface implementation
' to the appropriate interface implementation
IAccount_State = strNewValue
End Property

Public Property Get Zip() As String


' Delegate the default interface implementation
' to the appropriate interface implementation
Zip = IAccount_Zip
End Property

Public Property Let Zip(ByVal strNewValue As String)


' Delegate the default interface implementation
' to the appropriate interface implementation
IAccount_Zip = strNewValue
End Property

Public Property Get Email() As String


' Delegate the default interface implementation
' to the appropriate interface implementation
Email = IAccount_Email
End Property

Public Property Let Email(ByVal strNewValue As String)


' Delegate the default interface implementation
' to the appropriate interface implementation
IAccount_Email = strNewValue
End Property

Public Property Get Phone() As String


' Delegate the default interface implementation
' to the appropriate interface implementation
Phone = IAccount_Phone
End Property

Public Property Let Phone(ByVal strNewValue As String)


' Delegate the default interface implementation
' to the appropriate interface implementation
IAccount_Phone = strNewValue
End Property

Public Property Get FirstName() As String


' Delegate the default interface implementation
' to the appropriate interface implementation
FirstName = IAccount_FirstName
End Property

Public Property Let FirstName(ByVal strNewValue As String)


' Delegate the default interface implementation
' to the appropriate interface implementation
IAccount_FirstName = strNewValue
End Property

Public Property Get LastName() As String


' Delegate the default interface implementation
' to the appropriate interface implementation
LastName = IAccount_LastName
End Property

Public Property Let LastName(ByVal strNewValue As String)


' Delegate the default interface implementation
' to the appropriate interface implementation
IAccount_LastName = strNewValue
End Property

Public Property Get ID() As Long


' Delegate the default interface implementation
' to the appropriate interface implementation
ID = IAccount_ID
End Property

Public Property Let ID(ByVal lngNewValue As Long)


' Delegate the default interface implementation
' to the appropriate interface implementation
IAccount_ID = lngNewValue
End Property

Public Property Get Limit() As Currency


' Delegate the default interface implementation
' to the appropriate interface implementation
Limit = IAccount_Limit
End Property

Public Property Let Limit(ByVal curNewValue As Currency)


' Delegate the default interface implementation
' to the appropriate interface implementation
IAccount_Limit = curNewValue
End Property

Public Function MarshalToPropertyBag(strKey As String) As Byte()


' Delegate the default interface implementation
' to the appropriate interface implementation
MarshalToPropertyBag = IAccount_MarshalToPropertyBag(strKey)
End Function

Public Property Get Valid() As Boolean


' Delegate the default interface implementation
' to the appropriate interface implementation
Valid = IAccount_Valid
End Property

Listing 49
' Inventory
Option Explicit

Implements IInventory
Private mobjInvalidProperties As New InvalidProperties

Private mlngID As Long


Private mstrDescription As String
Private mcurPrice As Currency
Private mlngQOH As Long

Private Function IncrementQOH(ByVal lngQuantity As Long) As Boolean


Dim rIInventoryExec As IInventoryExec

' To minimize network traffic, only send


' pre-validated requests to the executant

Set rIInventoryExec = CreateObject("POExecutants.InventoryExec")


IncrementQOH = rIInventoryExec.IncrementQOH(mlngID, lngQuantity)

' Clean Up
Set rIInventoryExec = Nothing
End Function

Private Function DecrementQOH(ByVal lngQuantity As Long) As Boolean


Dim rIInventoryExec As IInventoryExec

' To minimize network traffic, only send


' pre-validated requests to the executant

Set rIInventoryExec = CreateObject("POExecutants.InventoryExec")


DecrementQOH = rIInventoryExec.DecrementQOH(mlngID, lngQuantity)

' Clean Up
Set rIInventoryExec = Nothing
End Function

Public Function Save() As Boolean


Dim lngRuleNumber As Long
Dim rIInventoryExec As IInventoryExec
Dim blnInvalid As Boolean

' To minimize network traffic, only send


' pre-validated requests to the executant

' Make sure the object is valid before


' attempting to save it
If mobjInvalidProperties.Count > 0 Then
' The object is invalid & the first
' invalid property is the error
lngRuleNumber = mobjInvalidProperties.Item(1)
Err.Raise vbObjectError + lngRuleNumber, LoadResString(IDS_PROJECTNAME), LoadResString(lngRuleNumber)
Else
Set rIInventoryExec = CreateObject("POExecutants.InventoryExec")
If mlngID = -1 Then
' Create a new Inventory item
blnInvalid = Not rIInventoryExec.Create(Me)
Else
' Modify an existing Inventory item
blnInvalid = Not rIInventoryExec.Modify(Me)
End If
If blnInvalid Then
' Notify the client of any error
Err.Raise vbObjectError + IDS_INVALID_INVENTORY_SAVE, LoadResString(IDS_PROJECTNAME),
LoadResString(IDS_INVALID_INVENTORY_SAVE)
Else
Save = True
End If
End If

Set rIInventoryExec = Nothing


End Function

Public Function Destroy() As Boolean


Dim rIInventoryExec As IInventoryExec
Dim blnInvalid As Boolean
' To minimize network traffic, only send
' pre-validated requests to the executant

Set rIInventoryExec = CreateObject("POExecutants.InventoryExec")


blnInvalid = Not rIInventoryExec.Destroy(mlngID)
If blnInvalid Then
' Notify the client of any error
Err.Raise vbObjectError + IDS_INVALID_INVENTORY_DESTROY, LoadResString(IDS_PROJECTNAME),
LoadResString(IDS_INVALID_INVENTORY_DESTROY)
Else
Destroy = True
End If

' Clean Up
Set rIInventoryExec = Nothing
End Function

Private Sub Class_Initialize()


' Initialize private members
mlngID = -1
' Track properties that are initially invalid but
' must become valid before the entire object can be
' deemed "Valid".
mobjInvalidProperties.Track IDS_INVALID_INVENTORY_DESCRIPTION, True
End Sub

Private Sub Class_ReadProperties(PropBag As PropertyBag)


' Load the saved state for the object
mlngID = PropBag.ReadProperty("ID", -1)
mstrDescription = PropBag.ReadProperty("Description", "")
mcurPrice = PropBag.ReadProperty("Price", 0)
mlngQOH = PropBag.ReadProperty("QOH", 0)
' Load the invalid property information
Set mobjInvalidProperties = PropBag.ReadProperty("InvalidProperties", Nothing)
End Sub

Private Sub Class_Terminate()


' Clean up
Set mobjInvalidProperties = Nothing
End Sub

Private Sub Class_WriteProperties(PropBag As PropertyBag)


' Save the current state of the object
PropBag.WriteProperty "ID", mlngID, -1
PropBag.WriteProperty "Description", mstrDescription, ""
PropBag.WriteProperty "Price", mcurPrice, 0
PropBag.WriteProperty "QOH", mlngQOH, 0
' Save the invalid property information
PropBag.WriteProperty "InvalidProperties", mobjInvalidProperties, Nothing
End Sub

Private Property Let IInventory_Description(ByVal RHS As String)


Dim blnInvalid As Boolean

' Perform any data validation that does not require


' access to the data services

' Limit Description to 50 characters


RHS = Trim$(Left$(RHS, 50))
' Description cannot be blank
If RHS = "" Then
blnInvalid = True
Else
blnInvalid = False
mstrDescription = RHS
End If
' Track whether or not the property is invalid
mobjInvalidProperties.Track IDS_INVALID_INVENTORY_DESCRIPTION, blnInvalid
' Notify the client of any error
If blnInvalid Then
Err.Raise vbObjectError + IDS_INVALID_INVENTORY_DESCRIPTION, LoadResString(IDS_PROJECTNAME),
LoadResString(IDS_INVALID_INVENTORY_DESCRIPTION)
End If
End Property

Private Property Get IInventory_Description() As String


IInventory_Description = mstrDescription
End Property

Private Property Let IInventory_ID(ByVal RHS As Long)


' Perform any data validation that does not require
' access to the data services
mlngID = RHS
End Property

Private Property Get IInventory_ID() As Long


IInventory_ID = mlngID
End Property

Private Function IInventory_MarshalToPropertyBag(strKey As String) As Byte()


Dim objPropertyBag As New PropertyBag

' Return the key that identifies the


' object state information ByRef
strKey = "InventoryState"
' Marshal this object instance to the property bag
objPropertyBag.WriteProperty strKey, Me, Nothing
' Return the contents of the property bag
' which can be assigned to another property bag
' and accessed via 'strKey' to recreate the object
IInventory_MarshalToPropertyBag = objPropertyBag.Contents

Set objPropertyBag = Nothing


End Function

Public Function MarshalToPropertyBag(strKey As String) As Byte()


' Delegate the default interface implementation
' to the appropriate interface implementation
MarshalToPropertyBag = IInventory_MarshalToPropertyBag(strKey)
End Function

Private Property Let IInventory_Price(ByVal RHS As Currency)


Dim blnInvalid As Boolean

' Perform any data validation that does not require


' access to the data services

' Price cannot have a negative value


If RHS < 0 Then
blnInvalid = True
Else
blnInvalid = False
mcurPrice = RHS
End If
' Track whether or not the property is invalid
mobjInvalidProperties.Track IDS_INVALID_INVENTORY_PRICE, blnInvalid
' Notify the client of any error
If blnInvalid Then
Err.Raise vbObjectError + IDS_INVALID_INVENTORY_PRICE, LoadResString(IDS_PROJECTNAME),
LoadResString(IDS_INVALID_INVENTORY_PRICE)
End If
End Property

Private Property Get IInventory_Price() As Currency


IInventory_Price = mcurPrice
End Property

Private Property Let IInventory_QOH(ByVal RHS As Long)


Dim blnInvalid As Boolean
' Perform any data validation that does not require
' access to the data services

' Quantity On Hand cannot have a negative value


If RHS < 0 Then
blnInvalid = True
Else
blnInvalid = False
mlngQOH = RHS
End If
' Track whether or not the property is invalid
mobjInvalidProperties.Track IDS_INVALID_INVENTORY_QOH, blnInvalid
' Notify the client of any error
If blnInvalid Then
Err.Raise vbObjectError + IDS_INVALID_INVENTORY_QOH, LoadResString(IDS_PROJECTNAME),
LoadResString(IDS_INVALID_INVENTORY_QOH)
End If
End Property

Private Property Get IInventory_QOH() As Long


IInventory_QOH = mlngQOH
End Property

Public Property Get ID() As Long


' Delegate the default interface implementation
' to the appropriate interface implementation
ID = IInventory_ID
End Property

Public Property Let ID(ByVal lngNewValue As Long)


' Delegate the default interface implementation
' to the appropriate interface implementation
IInventory_ID = lngNewValue
End Property

Public Property Get Description() As String


' Delegate the default interface implementation
' to the appropriate interface implementation
Description = IInventory_Description
End Property

Public Property Let Description(ByVal strNewValue As String)


' Delegate the default interface implementation
' to the appropriate interface implementation
IInventory_Description = strNewValue
End Property

Public Property Get Price() As Currency


' Delegate the default interface implementation
' to the appropriate interface implementation
Price = IInventory_Price
End Property

Public Property Let Price(ByVal curNewValue As Currency)


' Delegate the default interface implementation
' to the appropriate interface implementation
IInventory_Price = curNewValue
End Property

Public Property Get QOH() As Long


' Delegate the default interface implementation
' to the appropriate interface implementation
QOH = IInventory_QOH
End Property

Public Property Get Valid() As Boolean


' Delegate the default interface implementation
' to the appropriate interface implementation
Valid = IInventory_Valid
End Property

Public Property Let QOH(ByVal lngNewValue As Long)


' Delegate the default interface implementation
' to the appropriate interface implementation
IInventory_QOH = lngNewValue
End Property

Private Property Get IInventory_Valid() As Boolean


' The entire object cannot be valid unless
' all of its properties are valid
IInventory_Valid = (mobjInvalidProperties.Count = 0)
End Property

Listing 50
' LineItem
Option Explicit

Implements ILineItem
Private mobjInvalidProperties As New InvalidProperties

Private mlngID As Long


Private mlngPurchaseOrderID As Long
Private mrIInventory As IInventory
Private mcurPrice As Currency
Private mlngQuantity As Long

Public Function Save() As Boolean


Dim lngRuleNumber As Long
Dim rILineItemExec As ILineItemExec
Dim blnInvalid As Boolean

' To minimize network traffic, only send


' pre-validated requests to the executant

' Make sure the object is valid before


' attempting to save it
If mobjInvalidProperties.Count > 0 Then
' The object is invalid & the first
' invalid property is the error
lngRuleNumber = mobjInvalidProperties.Item(1)
Err.Raise vbObjectError + lngRuleNumber, LoadResString(IDS_PROJECTNAME), LoadResString(lngRuleNumber)
Else
Set rILineItemExec = CreateObject("POExecutants.LineItemExec")
If mlngID = -1 Then
' Create a new LineItem
blnInvalid = Not rILineItemExec.Create(Me)
Else
' Modify an existing LineItem
blnInvalid = Not rILineItemExec.Modify(Me)
End If
If blnInvalid Then
' Notify the client of any error
Err.Raise vbObjectError + IDS_INVALID_LINEITEM_SAVE, LoadResString(IDS_PROJECTNAME),
LoadResString(IDS_INVALID_LINEITEM_SAVE)
Else
Save = True
End If
End If

Set rILineItemExec = Nothing


End Function

Public Function Destroy() As Boolean


Dim rILineItemExec As ILineItemExec
Dim blnInvalid As Boolean

' To minimize network traffic, only send


' pre-validated requests to the executant
Set rILineItemExec = CreateObject("POExecutants.LineItemExec")
blnInvalid = Not rILineItemExec.Destroy(mlngID)
If blnInvalid Then
' Notify the client of any error
Err.Raise vbObjectError + IDS_INVALID_LINEITEM_DESTROY, LoadResString(IDS_PROJECTNAME),
LoadResString(IDS_INVALID_LINEITEM_DESTROY)
Else
Destroy = True
End If

' Clean Up
Set rILineItemExec = Nothing
End Function

Public Property Get ID() As Long


' Delegate the default interface implementation
' to the appropriate interface implementation
ID = ILineItem_ID
End Property

Public Property Let ID(ByVal lngNewValue As Long)


' Delegate the default interface implementation
' to the appropriate interface implementation
ILineItem_ID = lngNewValue
End Property

Public Property Get Valid() As Boolean


' Delegate the default interface implementation
' to the appropriate interface implementation
Valid = ILineItem_Valid
End Property

Public Property Get Price() As Currency


' Delegate the default interface implementation
' to the appropriate interface implementation
Price = ILineItem_Price
End Property

Public Property Let Price(ByVal curNewValue As Currency)


' Delegate the default interface implementation
' to the appropriate interface implementation
ILineItem_Price = curNewValue
End Property

Private Sub Class_Initialize()


' Initialize private members
mlngID = -1
mlngPurchaseOrderID = -1
' Track properties that are initially invalid but
' must become valid before the entire object can be
' deemed "Valid".
mobjInvalidProperties.Track IDS_INVALID_LINEITEM_ITEM, True
End Sub

Private Sub Class_ReadProperties(PropBag As PropertyBag)


' Load the saved state for the object
mlngID = PropBag.ReadProperty("ID", -1)
mlngPurchaseOrderID = PropBag.ReadProperty("PurchaseOrderID", 0)
Set mrIInventory = PropBag.ReadProperty("InventoryItem", Nothing)
mcurPrice = PropBag.ReadProperty("Price", 0)
mlngQuantity = PropBag.ReadProperty("Quantity", 0)
' Load the invalid property information
Set mobjInvalidProperties = PropBag.ReadProperty("InvalidProperties", Nothing)
End Sub

Public Function MarshalToPropertyBag(strKey As String) As Byte()


' Delegate the default interface implementation
' to the appropriate interface implementation
MarshalToPropertyBag = ILineItem_MarshalToPropertyBag(strKey)
End Function
Private Sub Class_Terminate()
' Clean up
Set mrIInventory = Nothing
Set mobjInvalidProperties = Nothing
End Sub

Private Sub Class_WriteProperties(PropBag As PropertyBag)


' Save the current state of the object
PropBag.WriteProperty "ID", mlngID, -1
PropBag.WriteProperty "PurchaseOrderID", mlngPurchaseOrderID, 0
PropBag.WriteProperty "InventoryItem", mrIInventory, Nothing
PropBag.WriteProperty "Price", mcurPrice, 0
PropBag.WriteProperty "Quantity", mlngQuantity, 0
' Save the invalid property information
PropBag.WriteProperty "InvalidProperties", mobjInvalidProperties, Nothing
End Sub

Private Property Let ILineItem_ID(ByVal RHS As Long)


' Perform any data validation that does not require
' access to the data services

' Update the property with the new value


mlngID = RHS
End Property

Private Property Get ILineItem_ID() As Long


ILineItem_ID = mlngID
End Property

Private Property Get ILineItem_Item() As POInterfaces.IInventory


Set ILineItem_Item = mrIInventory
End Property

Private Property Set ILineItem_Item(ByVal RHS As POInterfaces.IInventory)


Dim blnInvalid As Boolean

' Perform any data validation that does not require


' access to the data services

' Item must be a valid reference


If RHS Is Nothing Then
blnInvalid = True
Else
blnInvalid = False
' Update the property with the new value
Set mrIInventory = RHS
End If
' Track whether or not the property is invalid
mobjInvalidProperties.Track IDS_INVALID_LINEITEM_ITEM, blnInvalid
' Notify the client of any error
If blnInvalid Then
Err.Raise vbObjectError + IDS_INVALID_LINEITEM_ITEM, LoadResString(IDS_PROJECTNAME),
LoadResString(IDS_INVALID_LINEITEM_ITEM)
End If
End Property

Private Function ILineItem_MarshalToPropertyBag(strKey As String) As Byte()


Dim objPropertyBag As New PropertyBag

' Return the key that identifies the


' object state information ByRef
strKey = "LineItemState"
' Marshal this object instance to the property bag
objPropertyBag.WriteProperty strKey, Me, Nothing
' Return the contents of the property bag
' which can be assigned to another property bag
' and accessed via 'strKey' to recreate the object
ILineItem_MarshalToPropertyBag = objPropertyBag.Contents

Set objPropertyBag = Nothing


End Function

Private Property Let ILineItem_Price(ByVal RHS As Currency)


Dim blnInvalid As Boolean

' Perform any data validation that does not require


' access to the data services

' Price cannot have a negative value


If RHS < 0 Then
blnInvalid = True
Else
blnInvalid = False
' Update the property with the new value
mcurPrice = RHS
End If
' Track whether or not the property is invalid
mobjInvalidProperties.Track IDS_INVALID_LINEITEM_PRICE, blnInvalid
' Notify the client of any error
If blnInvalid Then
Err.Raise vbObjectError + IDS_INVALID_LINEITEM_PRICE, LoadResString(IDS_PROJECTNAME),
LoadResString(IDS_INVALID_LINEITEM_PRICE)
End If
End Property

Private Property Get ILineItem_Price() As Currency


ILineItem_Price = mcurPrice
End Property

Private Property Get ILineItem_PurchaseOrderID() As Long


ILineItem_PurchaseOrderID = mlngPurchaseOrderID
End Property

Private Property Let ILineItem_PurchaseOrderID(ByVal RHS As Long)


' Perform any data validation that does not require
' access to the data services

' Update the property with the new value


mlngPurchaseOrderID = RHS
End Property

Private Property Let ILineItem_Quantity(ByVal RHS As Long)


Dim blnInvalid As Boolean

' Perform any data validation that does not require


' access to the data services

' Quantity cannot have a negative value


If RHS < 0 Then
blnInvalid = True
Else
blnInvalid = False
' Update the property with the new value
mlngQuantity = RHS
End If
' Track whether or not the property is invalid
mobjInvalidProperties.Track IDS_INVALID_LINEITEM_QUANTITY, blnInvalid
' Notify the client of any error
If blnInvalid Then
Err.Raise vbObjectError + IDS_INVALID_LINEITEM_QUANTITY, LoadResString(IDS_PROJECTNAME),
LoadResString(IDS_INVALID_LINEITEM_QUANTITY)
End If
End Property

Private Property Get ILineItem_Quantity() As Long


ILineItem_Quantity = mlngQuantity
End Property
Public Property Get Quantity() As Long
' Delegate the default interface implementation
' to the appropriate interface implementation
Quantity = ILineItem_Quantity
End Property

Public Property Let Quantity(ByVal lngNewValue As Long)


' Delegate the default interface implementation
' to the appropriate interface implementation
ILineItem_Quantity = lngNewValue
End Property

Public Property Get PurchaseOrderID() As Long


' Delegate the default interface implementation
' to the appropriate interface implementation
PurchaseOrderID = ILineItem_PurchaseOrderID
End Property

Public Property Let PurchaseOrderID(ByVal lngNewValue As Long)


' Delegate the default interface implementation
' to the appropriate interface implementation
ILineItem_PurchaseOrderID = lngNewValue
End Property

Public Property Get Item() As Inventory


' Delegate the default interface implementation
' to the appropriate interface implementation
Set Item = ILineItem_Item
End Property

Public Property Set Item(robjInventory As Inventory)


' Delegate the default interface implementation
' to the appropriate interface implementation
Set ILineItem_Item = robjInventory
End Property

Private Property Get ILineItem_Valid() As Boolean


' The entire object cannot be valid unless
' all of its properties are valid
ILineItem_Valid = (mobjInvalidProperties.Count = 0)
End Property

Listing 51
' LineItems
Option Explicit

Implements ILineItems

Private mcolLineItems As New Collection

Public Property Get Count() As Long


' Delegate the default interface implementation
' to the appropriate interface implementation
Count = ILineItems_Count
End Property

Private Sub Class_ReadProperties(PropBag As PropertyBag)


Dim lngCount As Long
Dim lngNextItem As Long
Dim rILineItem As ILineItem

' Get the property values


' out of the property bag
lngCount = PropBag.ReadProperty("Count", 0)
' Load each LineItem object
For lngNextItem = 1 To lngCount
Set rILineItem = PropBag.ReadProperty("LineItem" & CStr(lngNextItem), Nothing)
' Add the object to the internal collection
' using the interface implementation
ILineItems_Add rILineItem
Next lngNextItem
Set rILineItem = Nothing
End Sub

Private Sub Class_Terminate()


Dim lngLineItem As Long

If Not mcolLineItems Is Nothing Then


' Delete any remaining line items
For lngLineItem = 1 To mcolLineItems.Count
mcolLineItems.Remove 1
Next lngLineItem
End If
Set mcolLineItems = Nothing
End Sub

Private Sub Class_WriteProperties(PropBag As PropertyBag)


Dim lngCount As Long
Dim lngNextItem As Long
Dim rILineItem As ILineItem

' Put the property values


' into the property bag
lngCount = ILineItems_Count
' Save each LineItem object
For lngNextItem = 1 To lngCount
Set rILineItem = ILineItems_Item(lngNextItem)
PropBag.WriteProperty "LineItem" & CStr(lngNextItem), rILineItem, Nothing
Next lngNextItem
PropBag.WriteProperty "Count", lngCount, 0
Set rILineItem = Nothing
End Sub

Private Function ILineItems_Add(rILineItem As POInterfaces.ILineItem) As Boolean


' Perform non-dabatase data validation
' Implement non-database specific business logic
If Not rILineItem Is Nothing Then
mcolLineItems.Add rILineItem
ILineItems_Add = True
End If
End Function

Public Function Add(vntILineItem As Variant) As Boolean


Dim rILineItem As ILineItem

' Cast the generic object reference


' into a specific object type
If VarType(vntILineItem) = vbObject Then
Set rILineItem = vntILineItem
' Delegate the default interface implementation
' to the appropriate interface implementation
Add = ILineItems_Add(rILineItem)
End If
Set rILineItem = Nothing
End Function

Public Function Item(ByVal lngPosKey As Long) As LineItem


' Delegate the default interface implementation
' to the appropriate interface implementation
Set Item = ILineItems_Item(lngPosKey)
End Function

Public Function Remove(ByVal lngPosKey As Long) As Boolean


' Delegate the default interface implementation
' to the appropriate interface implementation
Remove = ILineItems_Remove(lngPosKey)
End Function

Private Property Get ILineItems_Count() As Long


' Perform non-dabatase data validation
' Implement non-database specific business logic
ILineItems_Count = mcolLineItems.Count
End Property

Private Function ILineItems_Item(ByVal lngPosKey As Long) As POInterfaces.ILineItem


' Perform non-dabatase data validation
' Implement non-database specific business logic
If lngPosKey < 1 Or lngPosKey > mcolLineItems.Count Then
Set ILineItems_Item = Nothing
Else
Set ILineItems_Item = mcolLineItems.Item(lngPosKey)
End If
End Function

Private Function ILineItems_Remove(ByVal lngPosKey As Long) As Boolean


' Perform non-dabatase data validation
' Implement non-database specific business logic
If lngPosKey >= 1 And lngPosKey <= mcolLineItems.Count Then
mcolLineItems.Remove lngPosKey
ILineItems_Remove = True
End If
End Function

Listing 52
' PurchaseOrder
Option Explicit

Implements IPurchaseOrder
Private mobjInvalidProperties As New InvalidProperties

Private mlngID As Long


Private mlngAccountID As Long
Private mobjLineItems As New LineItems
Private mdatOrderDate As Date
Private mcurShippingHandling As Currency
Private mdblTaxRate As Double
Private mcurTotal As Currency
Private mstrShipToFirstName As String
Private mstrShipToLastName As String
Private mstrShipToAddressLine1 As String
Private mstrShipToAddressLine2 As String
Private mstrShipToCity As String
Private mstrShipToState As String
Private mstrShipToZip As String
Private mstrShipToPhone As String
Private mstrShipToEmail As String

Public Function Cancel() As Boolean


Dim rIPurchaseOrderExec As IPurchaseOrderExec
Dim blnInvalid As Boolean

' To minimize network traffic, only send


' pre-validated requests to the executant

Set rIPurchaseOrderExec = CreateObject("POExecutants.PurchaseOrderExec")


blnInvalid = Not rIPurchaseOrderExec.Cancel(mlngID)
If blnInvalid Then
' Notify the client of any error
Err.Raise vbObjectError + IDS_INVALID_PURCHASEORDER_CANCEL, LoadResString(IDS_PROJECTNAME),
LoadResString(IDS_INVALID_PURCHASEORDER_CANCEL)
Else
Cancel = True
End If

' Clean Up
Set rIPurchaseOrderExec = Nothing
End Function

Public Function Destroy() As Boolean


Dim rIPurchaseOrderExec As IPurchaseOrderExec
Dim blnInvalid As Boolean

' To minimize network traffic, only send


' pre-validated requests to the executant

Set rIPurchaseOrderExec = CreateObject("POExecutants.PurchaseOrderExec")


blnInvalid = Not rIPurchaseOrderExec.Destroy(mlngID)
If blnInvalid Then
' Notify the client of any error
Err.Raise vbObjectError + IDS_INVALID_PURCHASEORDER_DESTROY, LoadResString(IDS_PROJECTNAME),
LoadResString(IDS_INVALID_PURCHASEORDER_DESTROY)
Else
Destroy = True
End If

' Clean Up
Set rIPurchaseOrderExec = Nothing
End Function

Public Function Save() As Boolean


Dim lngRuleNumber As Long
Dim rIPurchaseOrderExec As IPurchaseOrderExec
Dim blnInvalid As Boolean

' To minimize network traffic, only send


' pre-validated requests to the executant

' Make sure the object is valid before


' attempting to save it
If mobjInvalidProperties.Count > 0 Then
' The object is invalid & the first
' invalid property is the error
lngRuleNumber = mobjInvalidProperties.Item(1)
Err.Raise vbObjectError + lngRuleNumber, LoadResString(IDS_PROJECTNAME), LoadResString(lngRuleNumber)
Else
Set rIPurchaseOrderExec = CreateObject("POExecutants.PurchaseOrderExec")
If mlngID = -1 Then
' Create a new PurchaseOrder
blnInvalid = Not rIPurchaseOrderExec.Create(Me)
Else
' Modify an existing PurchaseOrder
blnInvalid = Not rIPurchaseOrderExec.Modify(Me)
End If
If blnInvalid Then
' Notify the client of any error
Err.Raise vbObjectError + IDS_INVALID_PURCHASEORDER_SAVE, LoadResString(IDS_PROJECTNAME),
LoadResString(IDS_INVALID_PURCHASEORDER_SAVE)
Else
Save = True
End If
End If

Set rIPurchaseOrderExec = Nothing


End Function

Public Property Get Tax() As Currency


' Delegate the default interface implementation
' to the appropriate interface implementation
Tax = IPurchaseOrder_Tax
End Property

Public Property Let Tax(ByVal curTax As Currency)


' Delegate the default interface implementation
' to the appropriate interface implementation
IPurchaseOrder_Tax = curTax
End Property

Public Property Get Valid() As Boolean


' Delegate the default interface implementation
' to the appropriate interface implementation
Valid = IPurchaseOrder_Valid
End Property

Private Sub Class_Initialize()


' Initialize private members
mlngID = -1
mlngAccountID = -1
mdatOrderDate = Date
' Shipping and Handling is fixed at $20.00
mcurShippingHandling = 20#
' The tax rate is 8.6%
mdblTaxRate = 0.086
' Track properties that are initially invalid but
' must become valid before the entire object can be
' deemed "Valid".
mobjInvalidProperties.Track IDS_INVALID_PURCHASEORDER_ACCOUNTID, True
mobjInvalidProperties.Track IDS_INVALID_PURCHASEORDER_SHIPTOFIRSTNAME, True
mobjInvalidProperties.Track IDS_INVALID_PURCHASEORDER_SHIPTOLASTNAME, True
mobjInvalidProperties.Track IDS_INVALID_PURCHASEORDER_SHIPTOADDRESS, True
mobjInvalidProperties.Track IDS_INVALID_PURCHASEORDER_SHIPTOCITY, True
mobjInvalidProperties.Track IDS_INVALID_PURCHASEORDER_SHIPTOSTATE, True
mobjInvalidProperties.Track IDS_INVALID_PURCHASEORDER_SHIPTOZIP, True
End Sub

Private Sub Class_ReadProperties(PropBag As PropertyBag)


' Load the saved state of the object
mlngID = PropBag.ReadProperty("ID", -1)
mlngAccountID = PropBag.ReadProperty("AccountID", -1)
mdatOrderDate = PropBag.ReadProperty("OrderDate", Date)
mcurShippingHandling = PropBag.ReadProperty("ShippingHandling", 0)
mdblTaxRate = PropBag.ReadProperty("TaxRate", 0)
mcurTotal = PropBag.ReadProperty("Total", 0)
mstrShipToFirstName = PropBag.ReadProperty("ShipToFirstName", "")
mstrShipToLastName = PropBag.ReadProperty("ShipToLastName", "")
mstrShipToAddressLine1 = PropBag.ReadProperty("ShipToAddressLine1", "")
mstrShipToAddressLine2 = PropBag.ReadProperty("ShipToAddressLine2", "")
mstrShipToCity = PropBag.ReadProperty("ShipToCity", "")
mstrShipToState = PropBag.ReadProperty("ShipToState", "")
mstrShipToZip = PropBag.ReadProperty("ShipToZip", "")
mstrShipToPhone = PropBag.ReadProperty("ShipToPhone", "")
mstrShipToEmail = PropBag.ReadProperty("ShipToEmail", "")
Set mobjLineItems = PropBag.ReadProperty("LineItems", Nothing)
' Load the invalid property information
Set mobjInvalidProperties = PropBag.ReadProperty("InvalidProperties", Nothing)
End Sub

Private Sub Class_Terminate()


' Clean up
Set mobjLineItems = Nothing
Set mobjInvalidProperties = Nothing
End Sub

Private Sub Class_WriteProperties(PropBag As PropertyBag)


' Save the current state of the object
PropBag.WriteProperty "ID", mlngID, -1
PropBag.WriteProperty "AccountID", mlngAccountID, -1
PropBag.WriteProperty "OrderDate", mdatOrderDate, Date
PropBag.WriteProperty "ShippingHandling", mcurShippingHandling, 0
PropBag.WriteProperty "TaxRate", mdblTaxRate, 0
PropBag.WriteProperty "Total", mcurTotal, 0
PropBag.WriteProperty "ShipToFirstName", mstrShipToFirstName, ""
PropBag.WriteProperty "ShipToLastName", mstrShipToLastName, ""
PropBag.WriteProperty "ShipToAddressLine1", mstrShipToAddressLine1, ""
PropBag.WriteProperty "ShipToAddressLine2", mstrShipToAddressLine2, ""
PropBag.WriteProperty "ShipToCity", mstrShipToCity, ""
PropBag.WriteProperty "ShipToState", mstrShipToState, ""
PropBag.WriteProperty "ShipToZip", mstrShipToZip, ""
PropBag.WriteProperty "ShipToPhone", mstrShipToPhone, ""
PropBag.WriteProperty "ShipToEmail", mstrShipToEmail, ""
PropBag.WriteProperty "LineItems", mobjLineItems, Nothing
' Save the invalid property information
PropBag.WriteProperty "InvalidProperties", mobjInvalidProperties, Nothing
End Sub

Private Property Let IPurchaseOrder_AccountID(ByVal RHS As Long)


Dim blnInvalid As Boolean

' Perform any data validation that does not require


' access to the data services

' AccountID must be greater than 0


If RHS < 1 Then
blnInvalid = True
Else
blnInvalid = False
mlngAccountID = RHS
End If
' Track whether or not the property is invalid
mobjInvalidProperties.Track IDS_INVALID_PURCHASEORDER_ACCOUNTID, blnInvalid
' Notify the client of any error
If blnInvalid Then
Err.Raise vbObjectError + IDS_INVALID_PURCHASEORDER_ACCOUNTID,
LoadResString(IDS_PROJECTNAME), LoadResString(IDS_INVALID_PURCHASEORDER_ACCOUNTID)
End If
End Property

Private Property Get IPurchaseOrder_AccountID() As Long


IPurchaseOrder_AccountID = mlngAccountID
End Property

Private Property Let IPurchaseOrder_ID(ByVal RHS As Long)


' Perform any data validation that does not require
' access to the data services
mlngID = RHS
End Property

Private Property Get IPurchaseOrder_ID() As Long


IPurchaseOrder_ID = mlngID
End Property

Private Property Get IPurchaseOrder_LineItems() As POInterfaces.ILineItems


Set IPurchaseOrder_LineItems = mobjLineItems
End Property

Private Function IPurchaseOrder_MarshalToPropertyBag(strKey As String) As Byte()


Dim objPropertyBag As New PropertyBag

' Return the key that identifies the


' object state information ByRef
strKey = "PurchaseOrderState"
' Marshal this object instance to the property bag
objPropertyBag.WriteProperty strKey, Me, Nothing
' Return the contents of the property bag
' which can be assigned to another property bag
' and accessed via 'strKey' to recreate the object
IPurchaseOrder_MarshalToPropertyBag = objPropertyBag.Contents

Set objPropertyBag = Nothing


End Function

Public Function MarshalToPropertyBag(strKey As String) As Byte()


' Delegate the default interface implementation
' to the appropriate interface implementation
MarshalToPropertyBag = IPurchaseOrder_MarshalToPropertyBag(strKey)
End Function

Private Property Let IPurchaseOrder_OrderDate(ByVal RHS As Date)


' Perform any data validation that does not require
' access to the data services
mdatOrderDate = RHS
End Property

Private Property Get IPurchaseOrder_OrderDate() As Date


IPurchaseOrder_OrderDate = mdatOrderDate
End Property

Private Property Let IPurchaseOrder_ShippingHandling(ByVal RHS As Currency)


Dim blnInvalid As Boolean

' Perform any data validation that does not require


' access to the data services

' ShippingHandling cannot have a negative value


If RHS < 0 Then
blnInvalid = True
Else
blnInvalid = False
mcurShippingHandling = RHS
End If
' Track whether or not the property is invalid
mobjInvalidProperties.Track IDS_INVALID_PURCHASEORDER_SHIPPINGHANDLING, blnInvalid
' Notify the client of any error
If blnInvalid Then
Err.Raise vbObjectError + IDS_INVALID_PURCHASEORDER_SHIPPINGHANDLING,
LoadResString(IDS_PROJECTNAME), LoadResString(IDS_INVALID_PURCHASEORDER_SHIPPINGHANDLING)
End If
End Property

Private Property Get IPurchaseOrder_ShippingHandling() As Currency


IPurchaseOrder_ShippingHandling = mcurShippingHandling
End Property

Private Property Let IPurchaseOrder_ShipToAddressLine1(ByVal RHS As String)


Dim blnInvalid As Boolean

' Perform any data validation that does not require


' access to the data services

' Limit ShipToAddressLine1 to 20 characters


RHS = Trim$(Left$(RHS, 20))
' Address cannot be blank
If RHS = "" And mstrShipToAddressLine2 = "" Then
blnInvalid = True
Else
blnInvalid = False
mstrShipToAddressLine1 = RHS
End If
' Track whether or not the property is invalid
mobjInvalidProperties.Track IDS_INVALID_PURCHASEORDER_SHIPTOADDRESS, blnInvalid
' Notify the client of any error
If blnInvalid Then
Err.Raise vbObjectError + IDS_INVALID_PURCHASEORDER_SHIPTOADDRESS,
LoadResString(IDS_PROJECTNAME), LoadResString(IDS_INVALID_PURCHASEORDER_SHIPTOADDRESS)
End If
End Property

Private Property Get IPurchaseOrder_ShipToAddressLine1() As String


IPurchaseOrder_ShipToAddressLine1 = mstrShipToAddressLine1
End Property

Private Property Get IPurchaseOrder_ShipToAddressLine2() As String


IPurchaseOrder_ShipToAddressLine2 = mstrShipToAddressLine2
End Property

Private Property Let IPurchaseOrder_ShipToAddressLine2(ByVal RHS As String)


Dim blnInvalid As Boolean

' Perform any data validation that does not require


' access to the data services

' Limit ShipToAddressLine2 to 20 characters


RHS = Trim$(Left$(RHS, 20))
' Address cannot be blank
If RHS = "" And mstrShipToAddressLine1 = "" Then
blnInvalid = True
Else
blnInvalid = False
mstrShipToAddressLine2 = RHS
End If
' Track whether or not the property is invalid
mobjInvalidProperties.Track IDS_INVALID_PURCHASEORDER_SHIPTOADDRESS, blnInvalid
' Notify the client of any error
If blnInvalid Then
Err.Raise vbObjectError + IDS_INVALID_PURCHASEORDER_SHIPTOADDRESS,
LoadResString(IDS_PROJECTNAME), LoadResString(IDS_INVALID_PURCHASEORDER_SHIPTOADDRESS)
End If
End Property

Private Property Get IPurchaseOrder_ShipToCity() As String


IPurchaseOrder_ShipToCity = mstrShipToCity
End Property

Private Property Let IPurchaseOrder_ShipToCity(ByVal RHS As String)


Dim blnInvalid As Boolean

' Perform any data validation that does not require


' access to the data services

' Limit ShipToCity to 20 characters


RHS = Trim$(Left$(RHS, 20))
' Address cannot be blank
If RHS = "" Then
blnInvalid = True
Else
blnInvalid = False
mstrShipToCity = RHS
End If
' Track whether or not the property is invalid
mobjInvalidProperties.Track IDS_INVALID_PURCHASEORDER_SHIPTOCITY, blnInvalid
' Notify the client of any error
If blnInvalid Then
Err.Raise vbObjectError + IDS_INVALID_PURCHASEORDER_SHIPTOCITY,
LoadResString(IDS_PROJECTNAME), LoadResString(IDS_INVALID_PURCHASEORDER_SHIPTOCITY)
End If
End Property

Private Property Get IPurchaseOrder_ShipToEmail() As String


IPurchaseOrder_ShipToEmail = mstrShipToEmail
End Property

Private Property Let IPurchaseOrder_ShipToEmail(ByVal RHS As String)


' Perform any data validation that does not require
' access to the data services

' Limit ShipToEmail to 20 characters


mstrShipToEmail = Trim$(Left$(RHS, 20))
End Property

Private Property Get IPurchaseOrder_ShipToFirstName() As String


IPurchaseOrder_ShipToFirstName = mstrShipToFirstName
End Property

Private Property Let IPurchaseOrder_ShipToFirstName(ByVal RHS As String)


Dim blnInvalid As Boolean

' Perform any data validation that does not require


' access to the data services
' Limit ShipToFirstName to 20 characters
RHS = Trim$(Left$(RHS, 20))
' Address cannot be blank
If RHS = "" Then
blnInvalid = True
Else
blnInvalid = False
mstrShipToFirstName = RHS
End If
' Track whether or not the property is invalid
mobjInvalidProperties.Track IDS_INVALID_PURCHASEORDER_SHIPTOFIRSTNAME, blnInvalid
' Notify the client of any error
If blnInvalid Then
Err.Raise vbObjectError + IDS_INVALID_PURCHASEORDER_SHIPTOFIRSTNAME,
LoadResString(IDS_PROJECTNAME), LoadResString(IDS_INVALID_PURCHASEORDER_SHIPTOFIRSTNAME)
End If
End Property

Private Property Get IPurchaseOrder_ShipToLastName() As String


IPurchaseOrder_ShipToLastName = mstrShipToLastName
End Property

Private Property Let IPurchaseOrder_ShipToLastName(ByVal RHS As String)


Dim blnInvalid As Boolean

' Perform any data validation that does not require


' access to the data services

' Limit ShipToLastName to 40 characters


RHS = Trim$(Left$(RHS, 40))
' ShipToLastName cannot be blank
If RHS = "" Then
blnInvalid = True
Else
blnInvalid = False
mstrShipToLastName = RHS
End If
' Track whether or not the property is invalid
mobjInvalidProperties.Track IDS_INVALID_PURCHASEORDER_SHIPTOLASTNAME, blnInvalid
' Notify the client of any error
If blnInvalid Then
Err.Raise vbObjectError + IDS_INVALID_PURCHASEORDER_SHIPTOLASTNAME,
LoadResString(IDS_PROJECTNAME), LoadResString(IDS_INVALID_PURCHASEORDER_SHIPTOLASTNAME)
End If
End Property

Private Property Get IPurchaseOrder_ShipToPhone() As String


IPurchaseOrder_ShipToPhone = mstrShipToPhone
End Property

Private Property Let IPurchaseOrder_ShipToPhone(ByVal RHS As String)


' Perform any data validation that does not require
' access to the data services

' Limit ShipToPhone to 12 characters


mstrShipToPhone = Trim$(Left$(RHS, 12))
End Property

Private Property Get IPurchaseOrder_ShipToState() As String


IPurchaseOrder_ShipToState = mstrShipToState
End Property

Private Property Let IPurchaseOrder_ShipToState(ByVal RHS As String)


Dim intCharacterCode As Integer
Dim intPos As Integer
Dim blnInvalid As Boolean

' Perform any data validation that does not require


' access to the data services
' ShipToState must be 2 alpha characters
If Len(RHS) = 2 Then
blnInvalid = False
For intPos = 1 To 2
intCharacterCode = Asc(Mid$(RHS, intPos, 1))
If intCharacterCode < 65 Or intCharacterCode > 122 Then
blnInvalid = True
Exit For
End If
Next intPos
' If the new value is valid then save it
If Not blnInvalid Then
mstrShipToState = RHS
End If
Else
blnInvalid = True
End If
' Track whether or not the property is invalid
mobjInvalidProperties.Track IDS_INVALID_PURCHASEORDER_SHIPTOSTATE, blnInvalid
' Notify the client of any error
If blnInvalid Then
Err.Raise vbObjectError + IDS_INVALID_PURCHASEORDER_SHIPTOSTATE,
LoadResString(IDS_PROJECTNAME), LoadResString(IDS_INVALID_PURCHASEORDER_SHIPTOSTATE)
End If
End Property

Private Property Get IPurchaseOrder_ShipToZip() As String


IPurchaseOrder_ShipToZip = mstrShipToZip
End Property

Private Property Let IPurchaseOrder_ShipToZip(ByVal RHS As String)


Dim intCharacterCode As Integer
Dim intPos As Integer
Dim blnInvalid As Boolean

' Perform any data validation that does not require


' access to the data services

' ShipToZip must be 5 numeric characters


If Len(RHS) = 5 Then
blnInvalid = False
For intPos = 1 To 5
intCharacterCode = Asc(Mid$(RHS, intPos, 1))
If intCharacterCode < 48 Or intCharacterCode > 57 Then
blnInvalid = True
Exit For
End If
Next intPos
' If the new value is valid then save it
If Not blnInvalid Then
mstrShipToZip = RHS
End If
Else
blnInvalid = True
End If
' Track whether or not the property is invalid
mobjInvalidProperties.Track IDS_INVALID_PURCHASEORDER_SHIPTOZIP, blnInvalid
' Notify the client of any error
If blnInvalid Then
Err.Raise vbObjectError + IDS_INVALID_PURCHASEORDER_SHIPTOZIP, LoadResString(IDS_PROJECTNAME),
LoadResString(IDS_INVALID_PURCHASEORDER_SHIPTOZIP)
End If
End Property

Private Property Get IPurchaseOrder_SubTotal() As Currency


Dim rILineItem As ILineItem
Dim lngItem As Long
Dim curSubTotal As Currency
For lngItem = 1 To mobjLineItems.Count
Set rILineItem = mobjLineItems.Item(lngItem)
curSubTotal = curSubTotal + (rILineItem.Price * rILineItem.Quantity)
Next lngItem
IPurchaseOrder_SubTotal = curSubTotal
Set rILineItem = Nothing
End Property

Private Property Let IPurchaseOrder_SubTotal(ByVal RHS As Currency)


' Perform any data validation that does not require
' access to the data services

' Property is R/O


Err.Raise 383
End Property

Private Property Get IPurchaseOrder_Tax() As Currency


' Don't charge tax unless there are
' items actually being purchased
If mobjLineItems.Count > 0 Then
IPurchaseOrder_Tax = (IPurchaseOrder_SubTotal + IPurchaseOrder_ShippingHandling) * mdblTaxRate
Else
IPurchaseOrder_Tax = 0
End If
End Property

Private Property Let IPurchaseOrder_Tax(ByVal RHS As Currency)


' Perform any data validation that does not require
' access to the data services

' Property is R/O


Err.Raise 383
End Property

Private Property Get IPurchaseOrder_TaxRate() As Double


IPurchaseOrder_TaxRate = mdblTaxRate
End Property

Private Property Let IPurchaseOrder_TaxRate(ByVal RHS As Double)


Dim blnInvalid As Boolean

' Perform any data validation that does not require


' access to the data services

' TaxRate cannot have a negative value


If RHS < 0 Then
blnInvalid = True
Else
blnInvalid = False
mdblTaxRate = RHS
End If
' Track whether or not the property is invalid
mobjInvalidProperties.Track IDS_INVALID_PURCHASEORDER_TAXRATE, blnInvalid
' Notify the client of any error
If blnInvalid Then
Err.Raise vbObjectError + IDS_INVALID_PURCHASEORDER_TAXRATE, LoadResString(IDS_PROJECTNAME),
LoadResString(IDS_INVALID_PURCHASEORDER_TAXRATE)
End If
End Property

Private Property Get IPurchaseOrder_Total() As Currency


' Don't charge for shipping unless there are
' items actually being purchased
If mobjLineItems.Count > 0 Then
IPurchaseOrder_Total = IPurchaseOrder_SubTotal + IPurchaseOrder_ShippingHandling + IPurchaseOrder_Tax
Else
IPurchaseOrder_Total = 0
End If
End Property
Private Property Let IPurchaseOrder_Total(ByVal RHS As Currency)
Dim blnInvalid As Boolean

' Perform any data validation that does not require


' access to the data services

' Total cannot have a negative value


If RHS < 0 Then
blnInvalid = True
Else
blnInvalid = False
mcurTotal = RHS
End If
' Track whether or not the property is invalid
mobjInvalidProperties.Track IDS_INVALID_PURCHASEORDER_TOTAL, blnInvalid
' Notify the client of any error
If blnInvalid Then
Err.Raise vbObjectError + IDS_INVALID_PURCHASEORDER_TOTAL, LoadResString(IDS_PROJECTNAME),
LoadResString(IDS_INVALID_PURCHASEORDER_TOTAL)
End If
End Property

Public Property Get ID() As Long


' Delegate the default interface implementation
' to the appropriate interface implementation
ID = IPurchaseOrder_ID
End Property

Public Property Let ID(ByVal lngNewValue As Long)


' Delegate the default interface implementation
' to the appropriate interface implementation
IPurchaseOrder_ID = lngNewValue
End Property

Public Property Get AccountID() As Long


' Delegate the default interface implementation
' to the appropriate interface implementation
AccountID = IPurchaseOrder_AccountID
End Property

Public Property Let AccountID(ByVal lngNewValue As Long)


' Delegate the default interface implementation
' to the appropriate interface implementation
IPurchaseOrder_AccountID = lngNewValue
End Property

Public Property Get OrderDate() As Date


' Delegate the default interface implementation
' to the appropriate interface implementation
OrderDate = IPurchaseOrder_OrderDate
End Property

Public Property Let OrderDate(ByVal datNewValue As Date)


' Delegate the default interface implementation
' to the appropriate interface implementation
IPurchaseOrder_OrderDate = datNewValue
End Property

Public Property Get SubTotal() As Currency


' Delegate the default interface implementation
' to the appropriate interface implementation
SubTotal = IPurchaseOrder_SubTotal
End Property

Public Property Let SubTotal(ByVal curNewValue As Currency)


' Delegate the default interface implementation
' to the appropriate interface implementation
IPurchaseOrder_SubTotal = curNewValue
End Property
Public Property Get ShippingHandling() As Currency
' Delegate the default interface implementation
' to the appropriate interface implementation
ShippingHandling = IPurchaseOrder_ShippingHandling
End Property

Public Property Let ShippingHandling(ByVal curNewValue As Currency)


' Delegate the default interface implementation
' to the appropriate interface implementation
IPurchaseOrder_ShippingHandling = curNewValue
End Property

Public Property Get TaxRate() As Double


' Delegate the default interface implementation
' to the appropriate interface implementation
TaxRate = IPurchaseOrder_TaxRate
End Property

Public Property Let TaxRate(ByVal dblNewValue As Double)


' Delegate the default interface implementation
' to the appropriate interface implementation
IPurchaseOrder_TaxRate = dblNewValue
End Property

Public Property Get Total() As Currency


' Delegate the default interface implementation
' to the appropriate interface implementation
Total = IPurchaseOrder_Total
End Property

Public Property Let Total(ByVal curNewValue As Currency)


' Delegate the default interface implementation
' to the appropriate interface implementation
IPurchaseOrder_Total = curNewValue
End Property

Public Property Get ShipToFirstName() As String


' Delegate the default interface implementation
' to the appropriate interface implementation
ShipToFirstName = IPurchaseOrder_ShipToFirstName
End Property

Public Property Let ShipToFirstName(ByVal strNewValue As String)


' Delegate the default interface implementation
' to the appropriate interface implementation
IPurchaseOrder_ShipToFirstName = strNewValue
End Property

Public Property Get ShipToLastName() As String


' Delegate the default interface implementation
' to the appropriate interface implementation
ShipToLastName = IPurchaseOrder_ShipToLastName
End Property

Public Property Let ShipToLastName(ByVal strNewValue As String)


' Delegate the default interface implementation
' to the appropriate interface implementation
IPurchaseOrder_ShipToLastName = strNewValue
End Property

Public Property Get ShipToAddressLine1() As String


' Delegate the default interface implementation
' to the appropriate interface implementation
ShipToAddressLine1 = IPurchaseOrder_ShipToAddressLine1
End Property

Public Property Let ShipToAddressLine1(ByVal strNewValue As String)


' Delegate the default interface implementation
' to the appropriate interface implementation
IPurchaseOrder_ShipToAddressLine1 = strNewValue
End Property

Public Property Get ShipToAddressLine2() As String


' Delegate the default interface implementation
' to the appropriate interface implementation
ShipToAddressLine2 = IPurchaseOrder_ShipToAddressLine2
End Property

Public Property Let ShipToAddressLine2(ByVal strNewValue As String)


' Delegate the default interface implementation
' to the appropriate interface implementation
IPurchaseOrder_ShipToAddressLine2 = strNewValue
End Property

Public Property Get ShipToCity() As String


' Delegate the default interface implementation
' to the appropriate interface implementation
ShipToCity = IPurchaseOrder_ShipToCity
End Property

Public Property Let ShipToCity(ByVal strNewValue As String)


' Delegate the default interface implementation
' to the appropriate interface implementation
IPurchaseOrder_ShipToCity = strNewValue
End Property

Public Property Get ShipToState() As String


' Delegate the default interface implementation
' to the appropriate interface implementation
ShipToState = IPurchaseOrder_ShipToState
End Property

Public Property Let ShipToState(ByVal strNewValue As String)


' Delegate the default interface implementation
' to the appropriate interface implementation
IPurchaseOrder_ShipToState = strNewValue
End Property

Public Property Get ShipToZip() As String


' Delegate the default interface implementation
' to the appropriate interface implementation
ShipToZip = IPurchaseOrder_ShipToZip
End Property

Public Property Let ShipToZip(ByVal strNewValue As String)


' Delegate the default interface implementation
' to the appropriate interface implementation
IPurchaseOrder_ShipToZip = strNewValue
End Property

Public Property Get ShipToPhone() As String


' Delegate the default interface implementation
' to the appropriate interface implementation
ShipToPhone = IPurchaseOrder_ShipToPhone
End Property

Public Property Let ShipToPhone(ByVal strNewValue As String)


' Delegate the default interface implementation
' to the appropriate interface implementation
IPurchaseOrder_ShipToPhone = strNewValue
End Property

Public Property Get ShipToEmail() As String


' Delegate the default interface implementation
' to the appropriate interface implementation
ShipToEmail = IPurchaseOrder_ShipToEmail
End Property

Public Property Let ShipToEmail(ByVal strNewValue As String)


' Delegate the default interface implementation
' to the appropriate interface implementation
IPurchaseOrder_ShipToEmail = strNewValue
End Property

Public Property Get LineItems() As LineItems


Set LineItems = mobjLineItems
End Property

Private Property Get IPurchaseOrder_Valid() As Boolean


' The entire object cannot be valid unless
' all of its properties are valid
IPurchaseOrder_Valid = (mobjInvalidProperties.Count = 0)
End Property

Listing 53
' Constants
Option Explicit

Public Enum PurchaseOrderEmissaryConstants


' Project Name
IDS_PROJECTNAME = 101
' Account Emissary Errors
IDS_INVALID_ACCOUNT_FIRSTNAME
IDS_INVALID_ACCOUNT_LASTNAME
IDS_INVALID_ACCOUNT_ADDRESS
IDS_INVALID_ACCOUNT_CITY
IDS_INVALID_ACCOUNT_STATE
IDS_INVALID_ACCOUNT_ZIP
IDS_INVALID_ACCOUNT_DESTROY
IDS_INVALID_ACCOUNT_SAVE
' Inventory Emissary Errors
IDS_INVALID_INVENTORY_DESCRIPTION
IDS_INVALID_INVENTORY_PRICE
IDS_INVALID_INVENTORY_QOH
IDS_INVALID_INVENTORY_DESTROY
IDS_INVALID_INVENTORY_SAVE
' LineItem Emissary Errors
IDS_INVALID_LINEITEM_ITEM
IDS_INVALID_LINEITEM_PRICE
IDS_INVALID_LINEITEM_QUANTITY
IDS_INVALID_LINEITEM_DESTROY
IDS_INVALID_LINEITEM_SAVE
' PurchaseOrder Emissary Errors
IDS_INVALID_PURCHASEORDER_ACCOUNTID
IDS_INVALID_PURCHASEORDER_SHIPPINGHANDLING
IDS_INVALID_PURCHASEORDER_SHIPTOFIRSTNAME
IDS_INVALID_PURCHASEORDER_SHIPTOLASTNAME
IDS_INVALID_PURCHASEORDER_SHIPTOADDRESS
IDS_INVALID_PURCHASEORDER_SHIPTOCITY
IDS_INVALID_PURCHASEORDER_SHIPTOSTATE
IDS_INVALID_PURCHASEORDER_SHIPTOZIP
IDS_INVALID_PURCHASEORDER_TAXRATE
IDS_INVALID_PURCHASEORDER_TOTAL
IDS_INVALID_PURCHASEORDER_CANCEL
IDS_INVALID_PURCHASEORDER_DESTROY
IDS_INVALID_PURCHASEORDER_SAVE
End Enum

Listing 54
' Global
Option Explicit

Public Sub HighlightContents(robjTextbox As TextBox)


robjTextbox.SelStart = 0
robjTextbox.SelLength = Len(robjTextbox.Text)
End Sub

Listing 55
'frmPurchaseOrderManagement
Option Explicit
Private mobjPurchaseOrderIterator As PurchaseOrderIterator

Private Sub DisplayPurchaseOrders()


Dim objPurchaseOrder As PurchaseOrder
Dim objListViewItemAdded As ListItem

' Clear any existing contents


lvPurchaseOrders.ListItems.Clear
Set mobjPurchaseOrderIterator = New PurchaseOrderIterator
mobjPurchaseOrderIterator.Initialize
' Display the PurchaseOrders
Do While Not mobjPurchaseOrderIterator.EOF
Set objPurchaseOrder = mobjPurchaseOrderIterator.Item
Set objListViewItemAdded = lvPurchaseOrders.ListItems.Add(, "Key=" & CStr(objPurchaseOrder.ID),
CStr(objPurchaseOrder.ID))
' AccountID
objListViewItemAdded.SubItems(1) = CStr(objPurchaseOrder.AccountID)
' OrderDate
objListViewItemAdded.SubItems(2) = CStr(objPurchaseOrder.OrderDate)
mobjPurchaseOrderIterator.MoveNext
Loop
' Enable the Modify, Destroy, and CancelOrder buttons if necessary
cmdModify.Enabled = Not (lvPurchaseOrders.SelectedItem Is Nothing)
cmdDestroy.Enabled = cmdModify.Enabled
cmdCancelOrder.Enabled = cmdModify.Enabled

' Clean Up
Set objListViewItemAdded = Nothing
Set objPurchaseOrder = Nothing
End Sub

Private Sub cmdCancelOrder_Click()


Dim objListViewItemSelected As ListItem
Dim objPurchaseOrder As PurchaseOrder

' Get the selected item


Set objListViewItemSelected = lvPurchaseOrders.SelectedItem
mobjPurchaseOrderIterator.Filter = "ID = " & Mid$(objListViewItemSelected.Key, 5)
Set objPurchaseOrder = mobjPurchaseOrderIterator.Item
If vbYes = MsgBox("Are you sure you want to cancel PurchaseOrder # " & objPurchaseOrder.ID & " ?", vbYesNo) Then
On Error GoTo ErrorHandler
If objPurchaseOrder.Cancel() Then DisplayPurchaseOrders
End If

CleanUp:
Set objPurchaseOrder = Nothing
Set objListViewItemSelected = Nothing
Exit Sub
ErrorHandler:
' Inform the user of the invalid operation
MsgBox Err.Description, vbExclamation
GoTo CleanUp
End Sub

Private Sub cmdCreate_Click()


If frmPurchaseOrderDetailed.CreatePurchaseOrder() Then DisplayPurchaseOrders
End Sub

Private Sub cmdDestroy_Click()


Dim objListViewItemSelected As ListItem
Dim objPurchaseOrder As PurchaseOrder

' Get the selected item


Set objListViewItemSelected = lvPurchaseOrders.SelectedItem
mobjPurchaseOrderIterator.Filter = "ID = " & Mid$(objListViewItemSelected.Key, 5)
Set objPurchaseOrder = mobjPurchaseOrderIterator.Item
If vbYes = MsgBox("Are you sure you want to delete PurchaseOrder # " & objPurchaseOrder.ID & " ?", vbYesNo) Then
On Error GoTo ErrorHandler
If objPurchaseOrder.Destroy() Then DisplayPurchaseOrders
End If

CleanUp:
Set objPurchaseOrder = Nothing
Set objListViewItemSelected = Nothing
Exit Sub
ErrorHandler:
' Inform the user of the invalid operation
MsgBox Err.Description, vbExclamation
GoTo CleanUp
End Sub

Private Sub cmdModify_Click()


Dim objListViewItemSelected As ListItem
Dim objPurchaseOrder As PurchaseOrder

' Get the selected item


Set objListViewItemSelected = lvPurchaseOrders.SelectedItem
mobjPurchaseOrderIterator.Filter = "ID = " & Mid$(objListViewItemSelected.Key, 5)
Set objPurchaseOrder = mobjPurchaseOrderIterator.Item
If frmPurchaseOrderDetailed.ModifyPurchaseOrder(objPurchaseOrder) Then DisplayPurchaseOrders

Set objPurchaseOrder = Nothing


Set objListViewItemSelected = Nothing
End Sub

Private Sub Form_Load()


mnuViewRefresh_Click
End Sub

Private Sub Form_Unload(Cancel As Integer)


Set mobjPurchaseOrderIterator = Nothing
Set frmPurchaseOrderManagement = Nothing
End Sub

Private Sub lvPurchaseOrders_DblClick()


If cmdModify.Enabled Then cmdModify_Click
End Sub

Private Sub mnuFileExit_Click()


Unload Me
End Sub

Private Sub mnuManageAccounts_Click()


Load frmAccountManagement
frmAccountManagement.Show 1
Unload frmAccountManagement
End Sub

Private Sub mnuManageInventory_Click()


Load frmInventoryManagement
frmInventoryManagement.Show 1
Unload frmInventoryManagement
End Sub

Private Sub mnuViewRefresh_Click()


DisplayPurchaseOrders
End Sub

Listing 56
' frmPurchaseOrderDetailed
Option Explicit

Private mobjPurchaseOrder As PurchaseOrder


Private mblnCanceled As Boolean
Private mblnUpdatingUI As Boolean

Public Function CreatePurchaseOrder() As Boolean


' Create a new blank 'current' PurchaseOrder
Set mobjPurchaseOrder = New PurchaseOrder
Load Me
Label1.Caption = "Create a New Purchase Order"
DisplayCurrentPurchaseOrder
' Enable the Remove button if necessary
cmdRemove.Enabled = Not (lvLineItems.SelectedItem Is Nothing)
' Enable the Done button if necessary
EnableDoneButton
Me.Show 1
CreatePurchaseOrder = Not mblnCanceled
Unload Me
End Function

Private Sub DisplayCurrentPurchaseOrder()


' Signal that we are updating the UI
mblnUpdatingUI = True
' Display the PurchaseOrder information
DisplayLineItems
' Display the Shipping information
txtFirstName.Text = mobjPurchaseOrder.ShipToFirstName
txtLastName.Text = mobjPurchaseOrder.ShipToLastName
txtAddressLine1.Text = mobjPurchaseOrder.ShipToAddressLine1
txtAddressLine2.Text = mobjPurchaseOrder.ShipToAddressLine2
txtCity.Text = mobjPurchaseOrder.ShipToCity
txtState.Text = mobjPurchaseOrder.ShipToState
txtZip.Text = mobjPurchaseOrder.ShipToZip
txtPhone.Text = mobjPurchaseOrder.ShipToPhone
txtEmail.Text = mobjPurchaseOrder.ShipToEmail
' Done updating the UI
mblnUpdatingUI = False
End Sub

Private Sub DisplayLineItems()


Dim lngItem As Long
Dim objLineItem As LineItem
Dim objListViewItemAdded As ListItem

' Clear any existing contents


lvLineItems.ListItems.Clear
' Iterate and display each line item
For lngItem = 1 To mobjPurchaseOrder.LineItems.Count
Set objLineItem = mobjPurchaseOrder.LineItems.Item(lngItem)
If Not objLineItem Is Nothing Then
' Quantity
Set objListViewItemAdded = lvLineItems.ListItems.Add(, "Key=" & CStr(lngItem), CStr(objLineItem.Quantity))
' Title
objListViewItemAdded.SubItems(1) = objLineItem.Item.Description
' Price
objListViewItemAdded.SubItems(2) = Format$(objLineItem.Price, "Currency")
End If
Next lngItem
' Display the Payment information
txtAccountID.Text = CStr(mobjPurchaseOrder.AccountID)
lblSubTotal.Caption = Format$(mobjPurchaseOrder.SubTotal, "Currency")
lblShipping.Caption = Format$(mobjPurchaseOrder.ShippingHandling, "Currency")
lblTaxRate.Caption = Format$(mobjPurchaseOrder.TaxRate, "Tax #0.000%")
lblTax.Caption = Format$(mobjPurchaseOrder.Tax, "Currency")
lblTotal.Caption = Format$(mobjPurchaseOrder.Total, "Currency")
Set objLineItem = Nothing
Set objListViewItemAdded = Nothing
End Sub

Public Function ModifyPurchaseOrder(robjPurchaseOrder As PurchaseOrder) As Boolean


' Make the incoming PurchaseOrder the 'current' PurchaseOrder
Set mobjPurchaseOrder = robjPurchaseOrder
Load Me
Label1.Caption = "Purchase Order - " & CStr(mobjPurchaseOrder.ID)
DisplayCurrentPurchaseOrder
' Enable the Remove button if necessary
cmdRemove.Enabled = Not (lvLineItems.SelectedItem Is Nothing)
' Enable the Done button if necessary
EnableDoneButton
Me.Show 1
ModifyPurchaseOrder = Not mblnCanceled
Unload Me
End Function

Private Sub EnableDoneButton()


' Only enable the Done button if the
' entire object is valid
cmdDone.Enabled = mobjPurchaseOrder.Valid
End Sub

Private Sub cmdAdd_Click()


Dim objInventory As Inventory
Dim objLineItem As New LineItem

Set objInventory = frmInventorySelection.SelectItem()


If Not objInventory Is Nothing Then
' Add the item to the PO
objLineItem.PurchaseOrderID = mobjPurchaseOrder.ID
Set objLineItem.Item = objInventory
objLineItem.Price = objInventory.Price
objLineItem.Quantity = 1
mobjPurchaseOrder.LineItems.Add objLineItem
' Update the display
DisplayLineItems
' Enable the Remove button if necessary
cmdRemove.Enabled = Not (lvLineItems.SelectedItem Is Nothing)
' Enable the Done button if necessary
EnableDoneButton
End If
Set objLineItem = Nothing
Set objInventory = Nothing
End Sub

Private Sub cmdCancel_Click()


Me.Hide
End Sub

Private Sub cmdDone_Click()


On Error GoTo ErrorHandler

If mobjPurchaseOrder.Save() Then
mblnCanceled = False
Me.Hide
End If
Exit Sub
ErrorHandler:
' Inform the user of the invalid operation
MsgBox Err.Description, vbExclamation
End Sub

Private Sub cmdRemove_Click()


' Remove the currently selected
' line item from the PO
mobjPurchaseOrder.LineItems.Remove lvLineItems.SelectedItem.Index
' Update the display
DisplayLineItems
' Enable the Remove button if necessary
cmdRemove.Enabled = Not (lvLineItems.SelectedItem Is Nothing)
' Enable the Done button if necessary
EnableDoneButton
End Sub

Private Sub Form_Load()


mblnCanceled = True
End Sub

Private Sub Form_Unload(Cancel As Integer)


Set mobjPurchaseOrder = Nothing
Set frmPurchaseOrderDetailed = Nothing
End Sub

Private Sub lvLineItems_AfterLabelEdit(Cancel As Integer, NewString As String)


Dim objLineItem As LineItem
Dim objListViewItemSelected As ListItem

' Update the Quantity to purchase


Set objListViewItemSelected = lvLineItems.SelectedItem
If Not objListViewItemSelected Is Nothing Then
Set objLineItem = mobjPurchaseOrder.LineItems.Item(objListViewItemSelected.Index)
If Not objLineItem Is Nothing Then
objLineItem.Quantity = CLng(NewString)
' Update the display
DisplayLineItems
End If
End If
Set objListViewItemSelected = Nothing
Set objLineItem = Nothing
End Sub

Private Sub txtAccountID_Change()


If mblnUpdatingUI Then Exit Sub
' It's best to trap errors in the
' Validate or LostFocus event so as not to disturb
' the user while they are entering data
On Error Resume Next
If Trim$(txtAccountID.Text) = "" Then
mobjPurchaseOrder.AccountID = 0
Else
mobjPurchaseOrder.AccountID = CLng(txtAccountID.Text)
End If
' Enable the Done button if necessary
EnableDoneButton
End Sub

Private Sub txtAccountID_Validate(Cancel As Boolean)


On Error GoTo ErrorHandler
' Reassign the property value to check for
' invalid data
mobjPurchaseOrder.AccountID = CLng(txtAccountID.Text)
Exit Sub
ErrorHandler:
' Inform the user of the invalid entry
MsgBox Err.Description, vbExclamation
HighlightContents txtAccountID
' Keep the focus and allow the user to
' enter valid data
Cancel = True
End Sub

Private Sub txtAddressLine1_Change()


If mblnUpdatingUI Then Exit Sub
' It's best to trap errors in the
' Validate or LostFocus event so as not to disturb
' the user while they are entering data
On Error Resume Next
mobjPurchaseOrder.ShipToAddressLine1 = txtAddressLine1.Text
' Enable the Done button if necessary
EnableDoneButton
End Sub

Private Sub txtAddressLine1_Validate(Cancel As Boolean)


On Error GoTo ErrorHandler
' Reassign the property value to check for
' invalid data
mobjPurchaseOrder.ShipToAddressLine1 = txtAddressLine1.Text
Exit Sub
ErrorHandler:
' Inform the user of the invalid entry
MsgBox Err.Description, vbExclamation
HighlightContents txtAddressLine1
' Keep the focus and allow the user to
' enter valid data
Cancel = True
End Sub

Private Sub txtAddressLine2_Change()


If mblnUpdatingUI Then Exit Sub
' It's best to trap errors in the
' Validate or LostFocus event so as not to disturb
' the user while they are entering data
On Error Resume Next
mobjPurchaseOrder.ShipToAddressLine2 = txtAddressLine2.Text
' Enable the Done button if necessary
EnableDoneButton
End Sub

Private Sub txtAddressLine2_Validate(Cancel As Boolean)


On Error GoTo ErrorHandler
' Reassign the property value to check for
' invalid data
mobjPurchaseOrder.ShipToAddressLine2 = txtAddressLine2.Text
Exit Sub
ErrorHandler:
' Inform the user of the invalid entry
MsgBox Err.Description, vbExclamation
HighlightContents txtAddressLine2
' Keep the focus and allow the user to
' enter valid data
Cancel = True
End Sub

Private Sub txtCity_Change()


If mblnUpdatingUI Then Exit Sub
' It's best to trap errors in the
' Validate or LostFocus event so as not to disturb
' the user while they are entering data
On Error Resume Next
mobjPurchaseOrder.ShipToCity = txtCity.Text
' Enable the Done button if necessary
EnableDoneButton
End Sub

Private Sub txtCity_Validate(Cancel As Boolean)


On Error GoTo ErrorHandler
' Reassign the property value to check for
' invalid data
mobjPurchaseOrder.ShipToCity = txtCity.Text
Exit Sub
ErrorHandler:
' Inform the user of the invalid entry
MsgBox Err.Description, vbExclamation
HighlightContents txtCity
' Keep the focus and allow the user to
' enter valid data
Cancel = True
End Sub

Private Sub txtEmail_Change()


If mblnUpdatingUI Then Exit Sub
' It's best to trap errors in the
' Validate or LostFocus event so as not to disturb
' the user while they are entering data
On Error Resume Next
mobjPurchaseOrder.ShipToEmail = txtEmail.Text
' Enable the Done button if necessary
EnableDoneButton
End Sub
Private Sub txtEmail_Validate(Cancel As Boolean)
On Error GoTo ErrorHandler
' Reassign the property value to check for
' invalid data
mobjPurchaseOrder.ShipToEmail = txtEmail.Text
Exit Sub
ErrorHandler:
' Inform the user of the invalid entry
MsgBox Err.Description, vbExclamation
HighlightContents txtEmail
' Keep the focus and allow the user to
' enter valid data
Cancel = True
End Sub

Private Sub txtFirstName_Change()


If mblnUpdatingUI Then Exit Sub
' It's best to trap errors in the
' Validate or LostFocus event so as not to disturb
' the user while they are entering data
On Error Resume Next
mobjPurchaseOrder.ShipToFirstName = txtFirstName.Text
' Enable the Done button if necessary
EnableDoneButton
End Sub

Private Sub txtFirstName_Validate(Cancel As Boolean)


On Error GoTo ErrorHandler
' Reassign the property value to check for
' invalid data
mobjPurchaseOrder.ShipToFirstName = txtFirstName.Text
Exit Sub
ErrorHandler:
' Inform the user of the invalid entry
MsgBox Err.Description, vbExclamation
HighlightContents txtFirstName
' Keep the focus and allow the user to
' enter valid data
Cancel = True
End Sub

Private Sub txtLastName_Change()


If mblnUpdatingUI Then Exit Sub
' It's best to trap errors in the
' Validate or LostFocus event so as not to disturb
' the user while they are entering data
On Error Resume Next
mobjPurchaseOrder.ShipToLastName = txtLastName.Text
' Enable the Done button if necessary
EnableDoneButton
End Sub

Private Sub txtLastName_Validate(Cancel As Boolean)


On Error GoTo ErrorHandler
' Reassign the property value to check for
' invalid data
mobjPurchaseOrder.ShipToLastName = txtLastName.Text
Exit Sub
ErrorHandler:
' Inform the user of the invalid entry
MsgBox Err.Description, vbExclamation
HighlightContents txtLastName
' Keep the focus and allow the user to
' enter valid data
Cancel = True
End Sub

Private Sub txtPhone_Change()


If mblnUpdatingUI Then Exit Sub
' It's best to trap errors in the
' Validate or LostFocus event so as not to disturb
' the user while they are entering data
On Error Resume Next
mobjPurchaseOrder.ShipToPhone = txtPhone.Text
' Enable the Done button if necessary
EnableDoneButton
End Sub

Private Sub txtPhone_Validate(Cancel As Boolean)


On Error GoTo ErrorHandler
' Reassign the property value to check for
' invalid data
mobjPurchaseOrder.ShipToPhone = txtPhone.Text
Exit Sub
ErrorHandler:
' Inform the user of the invalid entry
MsgBox Err.Description, vbExclamation
HighlightContents txtPhone
' Keep the focus and allow the user to
' enter valid data
Cancel = True
End Sub

Private Sub txtState_Change()


If mblnUpdatingUI Then Exit Sub
' It's best to trap errors in the
' Validate or LostFocus event so as not to disturb
' the user while they are entering data
On Error Resume Next
mobjPurchaseOrder.ShipToState = txtState.Text
' Enable the Done button if necessary
EnableDoneButton
End Sub

Private Sub txtState_Validate(Cancel As Boolean)


On Error GoTo ErrorHandler
' Reassign the property value to check for
' invalid data
mobjPurchaseOrder.ShipToState = txtState.Text
Exit Sub
ErrorHandler:
' Inform the user of the invalid entry
MsgBox Err.Description, vbExclamation
HighlightContents txtState
' Keep the focus and allow the user to
' enter valid data
Cancel = True
End Sub

Private Sub txtZip_Change()


If mblnUpdatingUI Then Exit Sub
' It's best to trap errors in the
' Validate or LostFocus event so as not to disturb
' the user while they are entering data
On Error Resume Next
mobjPurchaseOrder.ShipToZip = txtZip.Text
' Enable the Done button if necessary
EnableDoneButton
End Sub

Private Sub txtZip_Validate(Cancel As Boolean)


On Error GoTo ErrorHandler
' Reassign the property value to check for
' invalid data
mobjPurchaseOrder.ShipToZip = txtZip.Text
Exit Sub
ErrorHandler:
' Inform the user of the invalid entry
MsgBox Err.Description, vbExclamation
HighlightContents txtZip
' Keep the focus and allow the user to
' enter valid data
Cancel = True
End Sub

Listing 57
' frmInventorySelection
Option Explicit

Private mobjInventoryIterator As InventoryIterator


Private mblnCanceled As Boolean

Private Sub DisplayInventory()


Dim objInventory As Inventory
Dim objListViewItemAdded As ListItem

' Clear any existing contents


lvInventory.ListItems.Clear
Set mobjInventoryIterator = New InventoryIterator
mobjInventoryIterator.Initialize
' Sort the items
mobjInventoryIterator.Sort = "Description ASC"
' Display the Inventory Items
Do While Not mobjInventoryIterator.EOF
Set objInventory = mobjInventoryIterator.Item
Set objListViewItemAdded = lvInventory.ListItems.Add(, "Key=" & CStr(objInventory.ID), CStr(objInventory.ID))
' Description
objListViewItemAdded.SubItems(1) = objInventory.Description
' Price
objListViewItemAdded.SubItems(2) = Format$(objInventory.Price, "Currency")
' Quantity On Hand
objListViewItemAdded.SubItems(3) = CStr(objInventory.QOH)
mobjInventoryIterator.MoveNext
Loop
' Enable the Done button if necessary
cmdDone.Enabled = Not (lvInventory.SelectedItem Is Nothing)

' Clean Up
Set objListViewItemAdded = Nothing
Set objInventory = Nothing
End Sub

Public Function SelectItem() As Inventory


Dim objListViewItemSelected As ListItem

Load Me
' Display the Inventory information
DisplayInventory
' Enable the Done button if necessary
cmdDone.Enabled = (lvInventory.ListItems.Count > 0)
Me.Show 1
If Not mblnCanceled Then
' Get the selected item
Set objListViewItemSelected = lvInventory.SelectedItem
mobjInventoryIterator.Filter = "ID = " & Mid$(objListViewItemSelected.Key, 5)
Set SelectItem = mobjInventoryIterator.Item
End If
Unload Me
Set objListViewItemSelected = Nothing
End Function

Private Sub cmdCancel_Click()


Me.Hide
End Sub

Private Sub cmdDone_Click()


mblnCanceled = False
Me.Hide
End Sub
Private Sub Form_Load()
mblnCanceled = True
End Sub

Private Sub Form_Unload(Cancel As Integer)


Set frmInventorySelection = Nothing
End Sub

Private Sub lvInventory_DblClick()


If cmdDone.Enabled Then cmdDone_Click
End Sub

Listing 58
' frmInventoryManagement
Option Explicit

Private mobjInventoryIterator As InventoryIterator

Private Sub DisplayInventory()


Dim objInventory As Inventory
Dim objListViewItemAdded As ListItem

' Clear any existing contents


lvInventory.ListItems.Clear
Set mobjInventoryIterator = New InventoryIterator
mobjInventoryIterator.Initialize
' Sort the items
mobjInventoryIterator.Sort = "Description ASC"
' Display the Inventory Items
Do While Not mobjInventoryIterator.EOF
Set objInventory = mobjInventoryIterator.Item
Set objListViewItemAdded = lvInventory.ListItems.Add(, "Key=" & CStr(objInventory.ID), CStr(objInventory.ID))
' Description
objListViewItemAdded.SubItems(1) = objInventory.Description
' Price
objListViewItemAdded.SubItems(2) = Format$(objInventory.Price, "Currency")
' Quantity On Hand
objListViewItemAdded.SubItems(3) = CStr(objInventory.QOH)
mobjInventoryIterator.MoveNext
Loop
' Enable the Modify and Destroy buttons if necessary
cmdModify.Enabled = Not (lvInventory.SelectedItem Is Nothing)
cmdDestroy.Enabled = cmdModify.Enabled

' Clean Up
Set objListViewItemAdded = Nothing
Set objInventory = Nothing
End Sub

Private Sub cmdClose_Click()


Unload Me
End Sub

Private Sub cmdCreate_Click()


If frmInventoryDetailed.CreateInventory() Then DisplayInventory
End Sub

Private Sub cmdDestroy_Click()


Dim objListViewItemSelected As ListItem
Dim objInventory As Inventory

' Get the selected item


Set objListViewItemSelected = lvInventory.SelectedItem
mobjInventoryIterator.Filter = "ID = " & Mid$(objListViewItemSelected.Key, 5)
Set objInventory = mobjInventoryIterator.Item
If vbYes = MsgBox("Are you sure you want to delete Inventory item # " & objInventory.ID & " ?", vbYesNo) Then
On Error GoTo ErrorHandler
If objInventory.Destroy() Then DisplayInventory
End If
CleanUp:
Set objInventory = Nothing
Set objListViewItemSelected = Nothing
Exit Sub
ErrorHandler:
' Inform the user of the invalid operation
MsgBox Err.Description, vbExclamation
GoTo CleanUp
End Sub

Private Sub cmdModify_Click()


Dim objListViewItemSelected As ListItem
Dim objInventory As Inventory

' Get the selected item


Set objListViewItemSelected = lvInventory.SelectedItem
mobjInventoryIterator.Filter = "ID = " & Mid$(objListViewItemSelected.Key, 5)
Set objInventory = mobjInventoryIterator.Item
If frmInventoryDetailed.ModifyInventory(objInventory) Then DisplayInventory

Set objInventory = Nothing


Set objListViewItemSelected = Nothing
End Sub

Private Sub Form_Load()


DisplayInventory
End Sub

Private Sub Form_Unload(Cancel As Integer)


Set mobjInventoryIterator = Nothing
Set frmInventoryManagement = Nothing
End Sub

Private Sub lvInventory_DblClick()


If cmdModify.Enabled Then cmdModify_Click
End Sub

Listing 59
' frmInventoryDetailed
Option Explicit

Private mobjInventory As Inventory


Private mblnCanceled As Boolean
Private mblnUpdatingUI As Boolean

Public Function CreateInventory() As Boolean


' Create a new blank 'current' Inventory item
Set mobjInventory = New Inventory
Load Me
Label1.Caption = "Create a New Inventory Item"
DisplayCurrentInventory
' Enable the Done button if necessary
EnableDoneButton
Me.Show 1
CreateInventory = Not mblnCanceled
Unload Me
End Function

Private Sub DisplayCurrentInventory()


' Signal that we are updating the UI
mblnUpdatingUI = True
' Display the Inventory information
txtDescription.Text = mobjInventory.Description
txtPrice.Text = Format$(mobjInventory.Price, "Currency")
txtQOH.Text = CStr(mobjInventory.QOH)
' Done updating the UI
mblnUpdatingUI = False
End Sub

Public Function ModifyInventory(robjInventory As Inventory) As Boolean


' Make the incoming Inventory item the 'current' Inventory item
Set mobjInventory = robjInventory
Load Me
Label1.Caption = "Inventory Item - " & CStr(mobjInventory.ID)
DisplayCurrentInventory
' Enable the Done button if necessary
EnableDoneButton
Me.Show 1
ModifyInventory = Not mblnCanceled
Unload Me
End Function

Private Sub EnableDoneButton()


' Only enable the Done button if the
' entire object is valid
cmdDone.Enabled = mobjInventory.Valid
End Sub

Private Sub cmdCancel_Click()


Me.Hide
End Sub

Private Sub cmdDone_Click()


On Error GoTo ErrorHandler

If mobjInventory.Save() Then
mblnCanceled = False
Me.Hide
End If
Exit Sub
ErrorHandler:
' Inform the user of the invalid operation
MsgBox Err.Description, vbExclamation
End Sub

Private Sub Form_Load()


mblnCanceled = True
End Sub

Private Sub Form_Unload(Cancel As Integer)


Set mobjInventory = Nothing
Set frmInventoryDetailed = Nothing
End Sub

Private Sub txtDescription_Change()


If mblnUpdatingUI Then Exit Sub
' It's best to trap errors in the
' Validate or LostFocus event so as not to disturb
' the user while they are entering data
On Error Resume Next
mobjInventory.Description = txtDescription.Text
' Enable the Done button if necessary
EnableDoneButton
End Sub

Private Sub txtDescription_Validate(Cancel As Boolean)


On Error GoTo ErrorHandler
' Reassign the property value to check for
' invalid data
mobjInventory.Description = txtDescription.Text
Exit Sub
ErrorHandler:
' Inform the user of the invalid entry
MsgBox Err.Description, vbExclamation
HighlightContents txtDescription
' Keep the focus and allow the user to
' enter valid data
Cancel = True
End Sub
Private Sub txtPrice_Change()
If mblnUpdatingUI Then Exit Sub
' It's best to trap errors in the
' Validate or LostFocus event so as not to disturb
' the user while they are entering data
On Error Resume Next
mobjInventory.Price = CCur(txtPrice.Text)
' Enable the Done button if necessary
EnableDoneButton
End Sub

Private Sub txtPrice_Validate(Cancel As Boolean)


On Error GoTo ErrorHandler
' Reassign the property value to check for
' invalid data
mobjInventory.Price = CCur(txtPrice.Text)
Exit Sub
ErrorHandler:
' Inform the user of the invalid entry
MsgBox Err.Description, vbExclamation
HighlightContents txtPrice
' Keep the focus and allow the user to
' enter valid data
Cancel = True
End Sub

Private Sub txtQOH_Change()


If mblnUpdatingUI Then Exit Sub
' It's best to trap errors in the
' Validate or LostFocus event so as not to disturb
' the user while they are entering data
On Error Resume Next
mobjInventory.QOH = CLng(txtQOH.Text)
' Enable the Done button if necessary
EnableDoneButton
End Sub

Private Sub txtQOH_Validate(Cancel As Boolean)


On Error GoTo ErrorHandler
' Reassign the property value to check for
' invalid data
mobjInventory.QOH = CLng(txtQOH.Text)
Exit Sub
ErrorHandler:
' Inform the user of the invalid entry
MsgBox Err.Description, vbExclamation
HighlightContents txtQOH
' Keep the focus and allow the user to
' enter valid data
Cancel = True
End Sub

Listing 60
' frmAccountManagement
Option Explicit

Private mobjAccountIterator As AccountIterator

Private Sub DisplayAccounts()


Dim objAccount As Account
Dim objListViewItemAdded As ListItem

' Clear any existing contents


lvAccounts.ListItems.Clear
Set mobjAccountIterator = New AccountIterator
mobjAccountIterator.Initialize
' Sort the items
mobjAccountIterator.Sort = "LastName ASC, FirstName ASC"
' Display the Accounts
Do While Not mobjAccountIterator.EOF
Set objAccount = mobjAccountIterator.Item
Set objListViewItemAdded = lvAccounts.ListItems.Add(, "Key=" & CStr(objAccount.ID), CStr(objAccount.ID))
' Owner
objListViewItemAdded.SubItems(1) = objAccount.LastName & ", " & objAccount.FirstName
' Current Balance
objListViewItemAdded.SubItems(2) = Format$(objAccount.Balance, "Currency")
' Available Credit
objListViewItemAdded.SubItems(3) = Format$(objAccount.Limit - objAccount.Balance, "Currency")
' Credit Limit
objListViewItemAdded.SubItems(4) = Format$(objAccount.Limit, "Currency")
mobjAccountIterator.MoveNext
Loop
' Enable the Modify and Destroy buttons if necessary
cmdModify.Enabled = Not (lvAccounts.SelectedItem Is Nothing)
cmdDestroy.Enabled = cmdModify.Enabled

' Clean Up
Set objListViewItemAdded = Nothing
Set objAccount = Nothing
End Sub

Private Sub cmdClose_Click()


Unload Me
End Sub

Private Sub cmdCreate_Click()


If frmAccountDetailed.CreateAccount() Then DisplayAccounts
End Sub

Private Sub cmdDestroy_Click()


Dim objListViewItemSelected As ListItem
Dim objAccount As Account

' Get the selected item


Set objListViewItemSelected = lvAccounts.SelectedItem
mobjAccountIterator.Filter = "ID = " & Mid$(objListViewItemSelected.Key, 5)
Set objAccount = mobjAccountIterator.Item
If vbYes = MsgBox("Are you sure you want to delete Account # " & objAccount.ID & " ?", vbYesNo) Then
On Error GoTo ErrorHandler
If objAccount.Destroy() Then DisplayAccounts
End If

CleanUp:
Set objAccount = Nothing
Set objListViewItemSelected = Nothing
Exit Sub
ErrorHandler:
' Inform the user of the invalid operation
MsgBox Err.Description, vbExclamation
GoTo CleanUp
End Sub

Private Sub cmdModify_Click()


Dim objListViewItemSelected As ListItem
Dim objAccount As Account

' Get the selected item


Set objListViewItemSelected = lvAccounts.SelectedItem
mobjAccountIterator.Filter = "ID = " & Mid$(objListViewItemSelected.Key, 5)
Set objAccount = mobjAccountIterator.Item
If frmAccountDetailed.ModifyAccount(objAccount) Then DisplayAccounts

Set objAccount = Nothing


Set objListViewItemSelected = Nothing
End Sub

Private Sub Form_Load()


DisplayAccounts
End Sub
Private Sub Form_Unload(Cancel As Integer)
Set mobjAccountIterator = Nothing
Set frmAccountManagement = Nothing
End Sub

Private Sub lvAccounts_DblClick()


If cmdModify.Enabled Then cmdModify_Click
End Sub

Listing 61
' frmAccountDetailed
Option Explicit

Private mobjAccount As Account


Private mblnCanceled As Boolean
Private mblnUpdatingUI As Boolean

Private Sub DisplayCurrentAccount()


' Signal that we are updating the UI
mblnUpdatingUI = True
' Display the Account information
txtFirstName.Text = mobjAccount.FirstName
txtLastName.Text = mobjAccount.LastName
txtAddressLine1.Text = mobjAccount.AddressLine1
txtAddressLine2.Text = mobjAccount.AddressLine2
txtCity.Text = mobjAccount.City
txtState.Text = mobjAccount.State
txtZip.Text = mobjAccount.Zip
txtPhone.Text = mobjAccount.Phone
txtEmail.Text = mobjAccount.Email
txtBalance.Text = Format$(mobjAccount.Balance, "Currency")
txtLimit.Text = Format$(mobjAccount.Limit, "Currency")
' Done updating the UI
mblnUpdatingUI = False
End Sub

Public Function ModifyAccount(robjAccount As Account) As Boolean


' Make the incoming Account the 'current' Account
Set mobjAccount = robjAccount
Load Me
Label1.Caption = "Account - " & CStr(mobjAccount.ID)
DisplayCurrentAccount
' Enable the Done button if necessary
EnableDoneButton
Me.Show 1
ModifyAccount = Not mblnCanceled
Unload Me
End Function

Public Function CreateAccount() As Boolean


' Create a new blank 'current' Account
Set mobjAccount = New Account
Load Me
Label1.Caption = "Create a New Account"
DisplayCurrentAccount
' Enable the Done button if necessary
EnableDoneButton
Me.Show 1
CreateAccount = Not mblnCanceled
Unload Me
End Function

Private Sub cmdCancel_Click()


Me.Hide
End Sub

Private Sub cmdDone_Click()


On Error GoTo ErrorHandler

If mobjAccount.Save() Then
mblnCanceled = False
Me.Hide
End If
Exit Sub
ErrorHandler:
' Inform the user of the invalid operation
MsgBox Err.Description, vbExclamation
End Sub

Private Sub Form_Load()


mblnCanceled = True
End Sub

Private Sub Form_Unload(Cancel As Integer)


Set mobjAccount = Nothing
Set frmAccountDetailed = Nothing
End Sub

Private Sub txtAddressLine1_Change()


If mblnUpdatingUI Then Exit Sub
' It's best to trap errors in the
' Validate or LostFocus event so as not to disturb
' the user while they are entering data
On Error Resume Next
mobjAccount.AddressLine1 = txtAddressLine1.Text
' Enable the Done button if necessary
EnableDoneButton
End Sub

Private Sub EnableDoneButton()


' Only enable the Done button if the
' entire object is valid
cmdDone.Enabled = mobjAccount.Valid
End Sub

Private Sub txtAddressLine1_Validate(Cancel As Boolean)


On Error GoTo ErrorHandler
' Reassign the property value to check for
' invalid data
mobjAccount.AddressLine1 = txtAddressLine1.Text
Exit Sub
ErrorHandler:
' Inform the user of the invalid entry
MsgBox Err.Description, vbExclamation
HighlightContents txtAddressLine1
' Keep the focus and allow the user to
' enter valid data
Cancel = True
End Sub

Private Sub txtAddressLine2_Change()


If mblnUpdatingUI Then Exit Sub
' It's best to trap errors in the
' Validate or LostFocus event so as not to disturb
' the user while they are entering data
On Error Resume Next
mobjAccount.AddressLine2 = txtAddressLine2.Text
' Enable the Done button if necessary
EnableDoneButton
End Sub

Private Sub txtAddressLine2_Validate(Cancel As Boolean)


On Error GoTo ErrorHandler
' Reassign the property value to check for
' invalid data
mobjAccount.AddressLine2 = txtAddressLine2.Text
Exit Sub
ErrorHandler:
' Inform the user of the invalid entry
MsgBox Err.Description, vbExclamation
HighlightContents txtAddressLine2
' Keep the focus and allow the user to
' enter valid data
Cancel = True
End Sub

Private Sub txtBalance_Change()


If mblnUpdatingUI Then Exit Sub
' It's best to trap errors in the
' Validate or LostFocus event so as not to disturb
' the user while they are entering data
On Error Resume Next
mobjAccount.Balance = CCur(txtBalance.Text)
' Enable the Done button if necessary
EnableDoneButton
End Sub

Private Sub txtBalance_Validate(Cancel As Boolean)


On Error GoTo ErrorHandler
' Reassign the property value to check for
' invalid data
mobjAccount.Balance = txtBalance.Text
Exit Sub
ErrorHandler:
' Inform the user of the invalid entry
MsgBox Err.Description, vbExclamation
HighlightContents txtBalance
' Keep the focus and allow the user to
' enter valid data
Cancel = True
End Sub

Private Sub txtCity_Change()


If mblnUpdatingUI Then Exit Sub
' It's best to trap errors in the
' Validate or LostFocus event so as not to disturb
' the user while they are entering data
On Error Resume Next
mobjAccount.City = txtCity.Text
' Enable the Done button if necessary
EnableDoneButton
End Sub

Private Sub txtCity_Validate(Cancel As Boolean)


On Error GoTo ErrorHandler
' Reassign the property value to check for
' invalid data
mobjAccount.City = txtCity.Text
Exit Sub
ErrorHandler:
' Inform the user of the invalid entry
MsgBox Err.Description, vbExclamation
HighlightContents txtCity
' Keep the focus and allow the user to
' enter valid data
Cancel = True
End Sub

Private Sub txtEmail_Change()


If mblnUpdatingUI Then Exit Sub
' It's best to trap errors in the
' Validate or LostFocus event so as not to disturb
' the user while they are entering data
On Error Resume Next
mobjAccount.Email = txtEmail.Text
' Enable the Done button if necessary
EnableDoneButton
End Sub

Private Sub txtEmail_Validate(Cancel As Boolean)


On Error GoTo ErrorHandler
' Reassign the property value to check for
' invalid data
mobjAccount.Email = txtEmail.Text
Exit Sub
ErrorHandler:
' Inform the user of the invalid entry
MsgBox Err.Description, vbExclamation
HighlightContents txtEmail
' Keep the focus and allow the user to
' enter valid data
Cancel = True
End Sub

Private Sub txtFirstName_Change()


If mblnUpdatingUI Then Exit Sub
' It's best to trap errors in the
' Validate or LostFocus event so as not to disturb
' the user while they are entering data
On Error Resume Next
mobjAccount.FirstName = txtFirstName.Text
' Enable the Done button if necessary
EnableDoneButton
End Sub

Private Sub txtFirstName_Validate(Cancel As Boolean)


On Error GoTo ErrorHandler
' Reassign the property value to check for
' invalid data
mobjAccount.FirstName = txtFirstName.Text
Exit Sub
ErrorHandler:
' Inform the user of the invalid entry
MsgBox Err.Description, vbExclamation
HighlightContents txtFirstName
' Keep the focus and allow the user to
' enter valid data
Cancel = True
End Sub

Private Sub txtLastName_Change()


If mblnUpdatingUI Then Exit Sub
' It's best to trap errors in the
' Validate or LostFocus event so as not to disturb
' the user while they are entering data
On Error Resume Next
mobjAccount.LastName = txtLastName.Text
' Enable the Done button if necessary
EnableDoneButton
End Sub

Private Sub txtLastName_Validate(Cancel As Boolean)


On Error GoTo ErrorHandler
' Reassign the property value to check for
' invalid data
mobjAccount.LastName = txtLastName.Text
Exit Sub
ErrorHandler:
' Inform the user of the invalid entry
MsgBox Err.Description, vbExclamation
HighlightContents txtLastName
' Keep the focus and allow the user to
' enter valid data
Cancel = True
End Sub

Private Sub txtLimit_Change()


If mblnUpdatingUI Then Exit Sub
' It's best to trap errors in the
' Validate or LostFocus event so as not to disturb
' the user while they are entering data
On Error Resume Next
mobjAccount.Limit = CCur(txtLimit.Text)
' Enable the Done button if necessary
EnableDoneButton
End Sub

Private Sub txtLimit_Validate(Cancel As Boolean)


On Error GoTo ErrorHandler
' Reassign the property value to check for
' invalid data
mobjAccount.Limit = txtLimit.Text
Exit Sub
ErrorHandler:
' Inform the user of the invalid entry
MsgBox Err.Description, vbExclamation
HighlightContents txtLimit
' Keep the focus and allow the user to
' enter valid data
Cancel = True
End Sub

Private Sub txtPhone_Change()


If mblnUpdatingUI Then Exit Sub
' It's best to trap errors in the
' Validate or LostFocus event so as not to disturb
' the user while they are entering data
On Error Resume Next
mobjAccount.Phone = txtPhone.Text
' Enable the Done button if necessary
EnableDoneButton
End Sub

Private Sub txtPhone_Validate(Cancel As Boolean)


On Error GoTo ErrorHandler
' Reassign the property value to check for
' invalid data
mobjAccount.Phone = txtPhone.Text
Exit Sub
ErrorHandler:
' Inform the user of the invalid entry
MsgBox Err.Description, vbExclamation
HighlightContents txtPhone
' Keep the focus and allow the user to
' enter valid data
Cancel = True
End Sub

Private Sub txtState_Change()


If mblnUpdatingUI Then Exit Sub
' It's best to trap errors in the
' Validate or LostFocus event so as not to disturb
' the user while they are entering data
On Error Resume Next
mobjAccount.State = txtState.Text
' Enable the Done button if necessary
EnableDoneButton
End Sub

Private Sub txtState_Validate(Cancel As Boolean)


On Error GoTo ErrorHandler
' Reassign the property value to check for
' invalid data
mobjAccount.State = txtState.Text
Exit Sub
ErrorHandler:
' Inform the user of the invalid entry
MsgBox Err.Description, vbExclamation
HighlightContents txtState
' Keep the focus and allow the user to
' enter valid data
Cancel = True
End Sub

Private Sub txtZip_Change()


If mblnUpdatingUI Then Exit Sub
' It's best to trap errors in the
' Validate or LostFocus event so as not to disturb
' the user while they are entering data
On Error Resume Next
mobjAccount.Zip = txtZip.Text
' Enable the Done button if necessary
EnableDoneButton
End Sub

Private Sub txtZip_Validate(Cancel As Boolean)


On Error GoTo ErrorHandler
' Reassign the property value to check for
' invalid data
mobjAccount.Zip = txtZip.Text
Exit Sub
ErrorHandler:
' Inform the user of the invalid entry
MsgBox Err.Description, vbExclamation
HighlightContents txtZip
' Keep the focus and allow the user to
' enter valid data
Cancel = True
End Sub

© 1999 Microsoft Corporation. All rights reserved. Terms of Use.

You might also like