Modelling a warranty claim as an object, not four arrays.
Ride Me Cycles tracked open warranty claims as four parallel arrays, frame numbers, purchase dates, fault descriptions and statuses, kept in step by array index alone. A class module gives each claim its own identity instead, one that can't quietly fall out of step.
BlackTor Group LtdDartmoor, UK
A note on this page
A reference, not a client write-up.
Illustrative, per the note on the main VBA page: not real client work. It sits alongside the Frame-Number Check and Resilient Export pages as a deeper dive on one routine that comes up often enough to be worth its own write-up.
The issue
Four arrays, kept in step by index alone, don't stay in step.
With a claim's fields spread across four separate arrays, the only thing tying a frame number at index 12 to its fault description is that it's also at index 12 in a different array. Sort one array to review claims by date and the other three are now describing entirely different claims unless every one of them is sorted identically, by hand, every time.
It also has no room for behaviour: working out how many days a claim has left under warranty means writing that calculation out again everywhere it's needed, rather than asking the claim itself.
Class module
clsWarrantyClaim: one object per claim, with its own behaviour
' ===== Class Module: clsWarrantyClaim =====
Option Explicit
Private mstrFrameNumber As String
Private mdatPurchaseDate As Date
Private mstrFaultDetail As String
Private mblnIsResolved As Boolean
Public Property Get FrameNumber() As String
FrameNumber = mstrFrameNumber
End Property
Public Property Let FrameNumber(ByVal strValue As String)
mstrFrameNumber = strValue
End Property
Public Property Get PurchaseDate() As Date
PurchaseDate = mdatPurchaseDate
End Property
Public Property Let PurchaseDate(ByVal datValue As Date)
mdatPurchaseDate = datValue
End Property
Public Property Get FaultDetail() As String
FaultDetail = mstrFaultDetail
End Property
Public Property Let FaultDetail(ByVal strValue As String)
mstrFaultDetail = strValue
End Property
Public Property Get IsResolved() As Boolean
IsResolved = mblnIsResolved
End Property
Public Sub MarkResolved()
mblnIsResolved = True
End Sub
' DaysRemainingUnderWarranty
' --------------------------
' Ride Me Cycles' standard warranty is 24 months from purchase. Returns
' the number of whole days left before it lapses, or 0 once it already
' has -- never a negative number, so a caller can test "> 0" directly
' instead of also having to check the sign.
Public Function DaysRemainingUnderWarranty() As Long
Const WARRANTY_MONTHS As Integer = 24
Dim datExpiryDate As Date
datExpiryDate = DateAdd("m", WARRANTY_MONTHS, mdatPurchaseDate)
DaysRemainingUnderWarranty = _
Application.WorksheetFunction.Max(0, DateDiff("d", Date, datExpiryDate))
End Function
' ===== Standard Module =====
Option Explicit
' BuildOpenClaimsCollection
' -------------------------
' Reads the Warranty Claims sheet into a Collection of
' clsWarrantyClaim objects, keyed by frame number, so a claim can be
' retrieved directly by colOpenClaims(strFrameNumber) instead of a
' linear search through parallel arrays.
Public Function BuildOpenClaimsCollection() As Collection
Dim colOpenClaims As New Collection
Dim wksClaims As Worksheet
Dim varClaimsData As Variant
Dim lngRowIndex As Long
Dim objClaim As clsWarrantyClaim
Set wksClaims = ThisWorkbook.Worksheets("Warranty Claims")
varClaimsData = wksClaims.Range("A2:D" & _
wksClaims.Cells(wksClaims.Rows.Count, "A").End(xlUp).Row).Value
For lngRowIndex = 1 To UBound(varClaimsData, 1)
Set objClaim = New clsWarrantyClaim
With objClaim
.FrameNumber = varClaimsData(lngRowIndex, 1)
.PurchaseDate = varClaimsData(lngRowIndex, 2)
.FaultDetail = varClaimsData(lngRowIndex, 3)
End With
' Collection keys must be unique -- On Error traps the rare case
' of two claims logged against the same frame number, rather
' than letting the whole build fail on one bad row.
On Error Resume Next
colOpenClaims.Add objClaim, Key:=objClaim.FrameNumber
On Error GoTo 0
Next lngRowIndex
Set BuildOpenClaimsCollection = colOpenClaims
End Function
Every field a claim has lives inside one object now, so sorting, filtering or passing a claim around always carries its frame number, purchase date and fault detail together. There's no longer a second or third array that has to be kept in step by hand.
DaysRemainingUnderWarranty is what a class module adds that four arrays never could: real behaviour attached to the data. Any code holding a claim object can ask it directly, rather than that calculation being copied out at every place it's needed and risking drifting out of sync with itself.
Keying the Collection by frame number means a specific claim is retrieved directly with colOpenClaims(strFrameNumber), rather than looping through every claim to find the one that matches.
Result
A claim can be sorted, filtered or passed around without falling apart.
Claims now behave as single, self-contained records. A sort or a filter on the Collection can never leave a frame number pointing at the wrong fault description.