Example Product Rule - Balance Calibrations Recorded to an SPC File

Scenario: A job CALIB1 is set up with one scheme BALCAL which has three analytes CURRWT, PREVWT, WTDIFF. Typically, every day, a new sample would be created for the job, with the format CALIBnnnnnn, where nnnnnn is an incremental integer with a step size of 1, starting at 000001. For example, if CALIB000008 was being analysed and CURRWT was read as 3.7, PREVWT is taken to be the CURRWT of the previous sample CALIB0000007, and the WTDIFF is calculated using a defined tolerance. If the WTDIFF for the current sample is out of tolerance, an email message is issued to a defined destination. The SPC file for the balance is updated with the lastest results.

Sub Main()
  'Daily Dry Balance Calibration Check Procedure
  'CURRWT = Todays weight
  'PREVWT = Yesterdays weight
  'DIFFWT = Weight Difference
  Dim iNoElems
  Dim dPrevWt, dCurrWt, dWtDiff, dTol
  Dim sPrevIdent
  Dim sSPCRecord
  Dim oSupport, oFileSystem, oTextFile
  Const ForAppending = 8
  'Set up some defaults for testing purposes
  'Current.Pro_Job ="CALIB1"
  'Current.Cuid = "0000033737"
  'Current.Sampleident = "CALIB000003"
  'Current.Sampletype ="UNK"
  'Current.Sch_Code ="BALCAL"
  'Current.AnalyteCode = "CURRWT"
  'Current.ProductCode ="DAILYBALCHK"
  Set oSupport = CreateObject("CCSUPP01.clsSupport")
  'Ensure CURRWT is stored
  clsBDProfjob.PopulateByCuid Current.Cuid, Current.Sch_Code, "CURRWT"
  'Note, when you populate using a particular Cuid, Scheme and Analyte, all schemes and
  'all analytes for that Cuid are loaded into the record sets. If you then re-populate
  'using the same Cuid, but change the Scheme and/or Analyte, only those affected records
  'are updated. If you re-populate using a different Cuid, all record sets are updated.
  If ProfjobCuidSchemeAnalyte.Analytestatus = "CPL" Then
    dCurrWt = oSupport.cnvdouble(ProfjobCuidSchemeAnalyte.Finalvalue)
    clsBDProfjob.PopulateByCuid Current.Cuid, Current.Sch_Code, "PREVWT"
    If ProfjobCuidSchemeAnalyte.Analytestatus = "CPL" Then
      'Presume that results have already been passed to SPC
      MsgBox "Results have already been passed to SPC", vbOKCancel, "BALCAL"
    Else
      If ProfjobCuid.Sampleident = "CALIB000001" Then
        MsgBox "First sample - no previous weight available for comparison", vbOKCancel, "BALCAL"
      Else
        'If the Sample ident for this current Cuid is >CALIB000001, get the record sets for the
        'previous Sample Ident, if it exists. Copy the CURRWT for that previous Sample
        'ident, and copy it into PREVWT for the current Cuid.
        sPrevIdent = "CALIB" & Right ("000000" & cStr (cDbl (Right (ProfjobCuid.Sampleident, 6)) - 1) ,6)
        clsBDProfjob.PopulateByIdent Current.Pro_Job, Current.Sch_Code, "CURRWT", "UNK", sPrevIdent
          If clsBDProfjob.FoundProfjobSchemeAnalyte Then
            'Get the current weight from this previous record and use it as the previous weight
            dPrevWt = oSupport.cnvdouble(ProfjobCuidSchemeAnalyte.Finalvalue)
            'Populate the record set for the current Cuid again, ensuring that BatchUpdate = True
            'so that records are not overwritten as you move through the analytes of a cuid+scheme
            clsBDProfjob.BatchUpdate = True
            'Update the previous weight for the current Cuid
            clsBDProfjob.PopulateByCuid Current.Cuid, Current.Sch_Code, "PREVWT"
            ProfjobCuidSchemeAnalyte.Analytestatus = "CPL"
            ProfjobCuidSchemeAnalyte.Numericvalue = dPrevWt
            ProfjobCuidSchemeAnalyte.Finalvalue = cStr (dPrevWt)
            'Save the record set, using BatchUpdate = True,
            'indicating there is more to save for this Cuid
            clsBDProfjob.IsProfjobCuidSchemeAnalyteDirty = True
            clsBDProfjob.SaveProfjobCuidSchemeAnalyte True
            dWtDiff = dCurrWt - dPrevWt
            'Update the weight difference for the current Cuid
            clsBDProfjob.PopulateByCuid Current.Cuid, Current.Sch_Code, "WTDIFF"
            ProfjobCuidSchemeAnalyte.Analytestatus = "CPL"
            ProfjobCuidSchemeAnalyte.Numericvalue = dWtDiff
            ProfjobCuidSchemeAnalyte.Finalvalue = cStr (dWtDiff)
            'Save the record set, using BatchUpdate = False,
            'indicating there is no more to save for this Cuid
            clsBDProfjob.BatchUpdate = False 
            clsBDProfjob.IsProfjobCuidSchemeAnalyteDirty = True
            clsBDProfjob.SaveProfjobCuidSchemeAnalyte True
            'Validate that the results are within limits +/- Tolerance
            dTol = 0.0003
            Msgbox "PREVWT = " & cStr(dPrevWt) & vbCrLf & "CURRWT = " & cStr(dCurrWt) & vbCrLf & _
            "EXPECTED = " & cStr(dPrevWt - dTol) & " to " & cStr(dPrevWt + dTol), _
            vbOKOnly, "BALCAL"
            If (dCurrWt < dPrevWt - dTol) or (dCurrWt > dPrevWt + dTol) Then
              'Something is not right. Send a message!
              SendEmail "Lab Manager", "Instrument Calibration", _
              "Balance" & vbTab & ProfjobCuidScheme.Instcode & vbCrLf & _
              "Cuid" & vbTab & Current.Cuid & vbCrLf & _
              "Job" & vbTab & Current.Pro_Job & vbCrLf & _
              "Sample" & vbTab & Current.Sampleident & vbCrLf & _
              "Expected = " & cStr (dPrevWt - dTol) & " to " & cStr (dPrevWt + dTol) & _
              "Reading = " & cStr (dCurrWt), _
              "labmgr@company.com.", ""
            End If
            'Pass all results to SPC
            Set oFileSystem = CreateObject( "Scripting.FileSystemObject" )
            Set oTextFile = oFileSystem.OpenTextFile( "I:\CCLASELSQL\SPC\BalCal_Daily.SPC", ForAppending, True )
            'SPF file format:
              'SCHEME 1-20
              'IDENT 21-40
              'JOB 41-60
              'DD/MM/YY 61-68
              'HH:MM:SS 69-76
              '#EL=nnn 77-83
              'ELEMn 84-93
              'FLAG 94
              'VALUE 95-106
            'Determine the list of analytes for this scheme
            iNoElems = 0
            sSPCRecord = ""
            clsBDProfjob.SkipProfjobCuidSchemeAnalyte 0
            do while not clsBDProfjob.EOFProfjobCuidSchemeAnalyte
              iNoElems = iNoElems + 1
              sSPCRecord = sSPCRecord & _
              Left( ProfjobCuidSchemeAnalyte.AnalyteCode & Space(20), 20 ) & _
              Left( ProfjobCuidSchemeAnalyte.Analytestatus & Space(3), 3 ) & _
              Left( ProfjobCuidSchemeAnalyte.Finalvalue & Space(20), 20 )
              clsBDProfjob.SkipProfjobCuidSchemeAnalyte 1
            loop
            oTextFile.WriteLine Left( Current.Sch_Code & Space(20), 20 ) & _
            Left( Current.Sampleident & Space(20), 20 ) & _
            Left ( Current.Pro_Job & Space(20), 20 ) & _
            CCLASDateFormat(Now) & "#ANA=" & Right( "00" & cStr(iNoElems), 3 ) & _
            sSPCRecord
            oTextFile.Close
            MsgBox "SPC file updated", vbOKOnly, "SPC"
          Else
            'If the record is not found, copy CURRWT for the current Cuid into PREVWT,
            'don't calculate the DIFFWT and don't worry about SPC
            MsgBox "Previous sample not found - no previous weight for comparison", vbOKOnly, "BALCAL"
          End If
        End If
      End If
    Else
      MsgBox "Sample " & Current.Cuid & " " & Current.Sampleident & " is incomplete", vbOKCancel, "BALCAL"
    End if 
Function CCLASDateFormat ( DateIn )
  Dim dDateIn
  CCLASDateFormat = Right("0"&cStr(Day(DateIn)),2) & ":" & Right("0"&cStr(Month(DateIn)),2) & ":" & _
  Right("O"&cStr(Year(DateIn)),2) & "0" & Right("0"&cStr(Hour(DateIn)),2) & ":" & _
  Right("0"&cStr(Minute(DateIn)),2) & ":" & Right("0" & cStr(Second(DateIn)),2)
End Function
Sub SendEmail ( sProfile, sSubject, sMessage, sRecipient, sAttach )
  Dim oEmail
  Set oEmail = New clsEmail
  With oEmail
    .Session = sProfile
    .Subject = sSubject
    .Text = sMessage
    .Recipient = sRecipient
    .Attach = sAttach
    If Msgbox ("OK to send to " & .Recipient, 4 + 48, "Email" ) = vbYes Then
      .Send
    End If
  End With
  Set oEmail = Nothing
End Sub
Class clsEmail
  'Simple Email Class
  Private msSession, msSubject, msText, msRecipient, msAttach
  Property Let Session (sSession)
    msSession = sSession
  End Property
  Property Let Subject (sSubject)
    msSubject = sSubject
  End Property
  Property Let Text (sText)
    msText = sText
  End Property
  Property Let Recipient (sRecipient)
    msRecipient = sRecipient
  End Property
  Property Let Attach (sAttach)
    msAttach = sAttach
  End Property
  Property Get Session ()
    Session = msSession
  End Property
  Property Get Subject ()
    Subject = msSubject
  End Property
  Property Get Text ()
    Text = msText
  End Property
  Property Get Recipient ()
    Recipient = msRecipient
  End Property
  Property Get Attach ()
    Attach = msAttach
  End Property
  Sub Send ()
    'Send the email
    Dim oSession, oMessage, oRecipient, oAttach
    Set oSession = CreateObject ("MAPI.Session")
    oSession.Logon msSession
    Set oMessage = oSession.Outbox.Messages.Add
    oMessage.Subject = msSubject
    oMessage.Text = msText
    If msAttach <> "" Then
      Set oAttach = oMessage.Attachments.Add
      oAttach.Source = msAttach
    End If
    Set oRecipient = oMessage.Recipients.Add
    oRecipient.Name = msRecipient
    oRecipient.Resolve
    oMessage.Update
    oMessage.Send
    oSession.Logoff
    set oAttach = Nothing
    set oMessage = Nothing
    set oRecipient = Nothing
    set oSession = Nothing
    End Sub
End Class