Sistema di registrazione dei soldi (Vienna Sanitation)

1. Background

Vienna Sanitation è una società che affitta servizi igienici nelle aree comuni. Per utilizzare una delle loro toilette bisogno una moneta 50 centesimo di essere inserito in un contatore. Ciò aprirà la porta del bagno.

Ogni bagno ha una propria identità e un contatore che conta quante monete sono state inserite nella sala relax. Ogni giorno il valore dei contatori viene registrato in un database e il denaro viene memorizzato in un posto sicuro. Confrontando il valore di oggi con il valore di ieri il dipartimento delle finanze e' in grado di calcolare il rendimento.

Questo caso di studio descrive come Vienna Sanitation ha implementato una soluzione basata su SMS per registrare il denaro raccolto in una posizione centrale, in modo automatico, tramite SMS.

2.Dichiarazione del problema

Attualmente i dipendenti hanno bisogno di leggere lo stato del contatore per tutti i servizi igienici e inviare un modulo al dipartimento delle finanze ogni giorno. Questo modulo contiene il nome del dipendente, l'id bagno e la quantita' del denaro che e' stato depositato. Di solito ci vogliono almeno due giorni in questo modo per arrivare al dipartimento delle finanze. Dopo di che gli impiegati del dipartimento delle finanze compilare i dettagli del modulo in un foglio Excel condiviso.

Vienna Sanitation ha voluto migliorare la velocita' e la qualita' del processo automatizzando il piu' possibile. Per fare questo le informazioni il bagno devono essere inviate al dipartimento delle finanze tramite SMS. In questo modo la direzione finanziaria non deve aspettare due giorni per elaborare il rendimento del giorno. L'invio di informazioni della toilette tramite SMS consente anche a un computer di elaborare automaticamente i dati presentati.

3.Obiettivi del nuovo sistema

Obiettivi del nuovo sistema:

4.Soluzione ActiveXperts SMS Messaging Server

I dipendenti di pulizia di Vienna Sanitation riportano il valore del contatore a Vienna Sanitation inviando un messaggio SMS a un server Vienna Sanitation. Questo server elabora i messaggi e memorizza i valori del contatore presentate nel database. Il mittente del messaggio viene controllato prima che il messaggio stesso sia in elaborazione. Se il messaggio viene ricevuto da un numero telefonico conosciuto, verra' elaborato. Il dipendente deve essere in grado di segnalare diversi risultati in un solo messaggio SMS. I valori inviati verranno inseriti in un database di Access.

La soluzione e' implementata utilizzando il Server ActiveXperts SMS Messaging. C'e' uno script per elaborare i messaggi in arrivo, un database di Access semplice e GSM-modem correttamente configurato con una scheda SIM.

Il database del progetto contiene tre tabelle:

Il valore del contatore deve essere inviato in un formato fisso. I primi numeri dovrebbero indicare l'ID toilette seguito da uno spazio e il valore del contatore. Per esempio il valore del contatore 365 per il numero di toilette 5 devono essere inseriti in questo modo: "5 365". LL'addetto e' in grado di inviare piu' valori del contatore, separandoli con un punto. Per esempio controvalore 365 per la stazione di 5 e controvalore 654 per la stazione di 6 devono essere inseriti in questo modo: "5 356. 6 654".

Formato dei messaggi SMS

Il sistema gestisce SMS come segue:

SMS syntax Sample Explanation
<toilet-number><turnover> 5 356 Turn-over of 356 for toilet 5
<toilet-number 1><turnover 1>.
<toilet-number 2><turnover 2>.
<toilet-number n><turnover n>
5 356.6 611.8 55.9.303 Turn-over of 356 for toilet 5; Turn-over of 611 for toilet 6, etc.
<any other message> Please help Unrecognized command. A Help message is replied

Trigger

Un trigger viene chiamato quando un nuovo messaggio arriva nel sistema. Vienna Sanitation gestisce un solo tipo di messaggi SMS: immatricolazioni turn-over in arrivo. Pertanto, e' necessario solo un innesco:

Enabled Description Condition Script
YES Process incoming commands ANY MESSAGE \Projects\SupportIT\Triggers\SupportIT.vbs

SupportIT.vbs (full code)


 Option Explicit

 CONST STR_DEBUGFILE     = "Sys\Tmp\Vienna Sanitation.txt"
 CONST STR_DATABASEFILE	 = "Projects\Vienna Sanitation\Database\Vienna Sanitation.mdb"

 Const SEPERATOR         = "."

 ' Declaration of global objects
 im g_objMessageDB, g_objDebugger, g_objConstants

 ' Creation of global objects
 Set g_objConstants      = CreateObject( "Axsms-messaging-server.Constants" )
 Set g_objMessageDB      = CreateObject( "Axsms-messaging-server.MessageDB" ) 
 Set g_objDebugger       = CreateObject( "ActiveXperts.VbDebugger" )

 ' Set Debug file - for troubleshooting purposes
 g_objDebugger.DebugFile = STR_DEBUGFILE
 g_objDebugger.Enabled   = True


 ' // ========================================================================
 ' // Function: ProcessMessage
 ' // ------------------------------------------------------------------------
 ' // ProcessMessage trigger function to process incoming messages
 ' // ========================================================================

 Function ProcessMessage( numMessageID )
   Dim objMessageIn, objMessageOut
   Dim numEmployeeID, numStationID, numTellerStand 
   Dim strEmployeeName, strErrorMessage 
   Dim bResult
   Dim strMessageOutBody
   Dim arrMessage, i
   Dim strInvoerMethode

   g_objDebugger.WriteLine ">> ProcessMessage"

   ' Open the Message Database
   g_objMessageDB.Open
   If( g_objMessageDB.LastError <> 0 ) Then
      g_objDebugger.WriteLine "<< ProcessMessage,  unable to open database"
      Exit Function
   End If

   ' Retrieve the message that has just been received. If it fails then exit script 
   Set objMessageIn   = g_objMessageDB.FindFirstMessage ( "ID = " & numMessageID ) 
   If g_objMessageDB.LastError <> 0 Then
      g_objMessageDB.Close
      g_objDebugger.WriteLine "<< ProcessMessage,  FindFirstMessage failed: [" & _
          g_objMessageDB.LastError & "]"
      Exit Function
   End If

   ' Change Status to from Pending to Success. 
   objMessageIn.Status = g_objConstants.MESSAGESTATUS_SUCCESS
   g_objMessageDB.Save objMessageIn   

   g_objDebugger.WriteLine "Incoming message saved, result: [" & g_objMessageDB.LastError & "]"

   ' Retrieve Member's name
   bResult = CheckEmployee( objMessageIn.From, numEmployeeID, strEmployeeName, strErrorMessage )
   
   ' Convert the message to an array
   arrMessage = MessageToArray( objMessageIn.Body )
   
   ' Check whether the user input is valid or not
   If( objMessageIn.Body <> "" ) Then
     If( IsValidMessage( arrMessage ) ) Then
   
       ' Loop throught the results and process them
       For i = 0 To UBound( arrMessage )
         If( bResult ) Then
           bResult = InsertCollected( numEmployeeID, arrMessage(i,0), arrMessage(i,1), _
              strErrorMessage )  
         Else
           Exit For
         End If
       Next
     
       ' Reply to the customer
       If( bResult = False ) Then
        strMessageOutBody = strErrorMessage
       Else
        strMessageOutBody = "Dear " & strEmployeeName & ", we received your counter info " & _
                            PrintResults( arrMessage ) & " successfully."
       End If
     
     Else
       strMessageOutBody  = "Invalid message. Provide toilet-id, followed by a blank, " & _
                            "followed by the counter info"
     End If
   End If
      
   If( strMessageOutBody <> "" ) Then
     ReplyMessage objMessageIn.From, strMessageOutBody
   End If
 
   ' Close the Message Database
   g_objMessageDB.Close

   g_objDebugger.WriteLine "<< ProcessMessage"

 End Function



 ' // ========================================================================

 Function ReplyMessage( strRecipient, strBody )

   Dim objMessageOut

   g_objDebugger.WriteLine ">> ReplyMessage"
      
   ' Create the reply message
   Set objMessageOut = g_objMessageDB.Create
   
   If( g_objMessageDB.LastError = 0 ) Then
     objMessageOut.Direction = g_objConstants.MESSAGEDIRECTION_OUT
     objMessageOut.Type      = g_objConstants.MESSAGETYPE_SMS 
     objMessageOut.Status    = g_objConstants.MESSAGESTATUS_PENDING
     objMessageOut.To        = strRecipient
     objMessageOut.ChannelID = 0
     objMessageOut.Body      = strBody

     g_objMessageDB.Save objMessageOut
   End If

   g_objDebugger.WriteLine "<< ReplyMessage"

 End Function


 ' // ========================================================================
 ' // CheckEmployee
 ' // ------------------------------------------------------------------------
 ' // Check if a mobile number is in the Members database to confirm that the
 ' // person is a member
 ' // ========================================================================

 Function CheckEmployee( strInputNumber, ByRef numEmployeeID, ByRef strEmployeeName, _
      ByRef strErrorMessage )
   Dim objConn, RS, strQuery

   g_objDebugger.WriteLine( ">> CheckEmployee" )

   CheckEmployee = False
   numEmployeeID = 0
   strEmployeeName = ""

   Set objConn = GetDatabase()

   Set RS = objConn.Execute( "SELECT * FROM tblEmployees WHERE Cell='" & strInputNumber & "'"  )
   If RS.EOF Then
      CheckEmployee   = False
      numEmployeeID   = 0
      strEmployeeName = ""
      strErrorMessage = "Error: Unknown user!"
   Else
      CheckEmployee   = True
      numEmployeeID   = RS( "ID" )
      strEmployeeName = RS( "Name" )
      strErrorMessage = ""
   End If

   objConn.Close
   Set objConn = Nothing

   g_objDebugger.WriteLine( "<< CheckEmployee" )

 End Function


 ' // ========================================================================
 ' // Query InsertOpgave
 ' // ------------------------------------------------------------------------
 ' // Lookup the current price of the selected stock ( use ticker symbol )
 ' // ========================================================================

 Function InsertCollected( numEmployeeID, numStationID, numCounter, ByRef strErrorMessage  )

   g_objDebugger.WriteLine( ">> InsertCollected" )

   Dim objConn, RS
   Dim strQuery

   InsertCollected    = False
   strErrorMessage = ""

   Set objConn = GetDatabase()

   strQuery = "INSERT INTO tblCounter( EmployeeID, StationID, CoinsCounter ) VALUES( " & _
              numEmployeeID & ", " & numStationID & ", " & numCounter & ")" 
   g_objDebugger.WriteLine( ">> Inserting into database: " & strQuery )
   objConn.Execute ( strQuery )
   
   ' Close database
   objConn.Close
   Set objConn = Nothing

   InsertCollected = True

   g_objDebugger.WriteLine( "<< InsertCollected" )

 End Function


 ' // ========================================================================
 ' // MessageToArray
 ' // ------------------------------------------------------------------------
 ' // Change the current message in a 2 dimentional array
 ' // ========================================================================

 Function MessageToArray( strMessageBody )

   ' Declare array to store results in
   Dim arrResult()
   Dim arrValues, arrMessage, i


   ' In case 2 or more counter results are submitted a 2 dimentional
   ' array needs to be reserved
      
   ' Split the messages into seperate results
   arrMessage = Split( strMessageBody, SEPERATOR )
          
   ' Count how many results are returned and redeclare an array
   ReDim arrResult( UBound(arrMessage), 1 )
          
   ' Read the message and store it into an array
   For i = 0 To UBound( arrMessage )
      If( InStr( arrMessage( i ), " " ) ) Then
         arrValues = Split( Trim(arrMessage( i )), " " )

         On Error Resume Next
           arrResult(i,0) = arrValues(0)
           arrResult(i,1) = arrValues(1)
         On Error Goto 0
      End If 
   Next

   ' Return this array
   MessageToArray = arrResult
 End Function


 ' // ========================================================================
 ' // PrintResultaten
 ' // ------------------------------------------------------------------------
 ' // Show the results
 ' // ========================================================================

 Function PrintResults( arrResult )
  Dim strResults, i
  For i = 0 To UBound( arrResult )
    strResults = strResults & arrResult(i,1) & " for station " & arrResult(i,0)
    If( i <= ( UBound( arrResult ) -1 ) ) Then
       strResults = strResults & " and "
    End If
  Next
  PrintResults = strResults
 End Function



 ' // ========================================================================
 ' // IsValidMessage
 ' // ------------------------------------------------------------------------
 ' // Check whether the user input is correct or not
 ' // ========================================================================

 Function IsValidMessage( arrResultaten )
   
   Dim bResult, objConn, RS, i
   
   bResult = True
   
   ' Op the database
   Set objConn = GetDatabase()
   
   For i = 0 To UBound( arrResultaten )
     
     ' Check wheter the station exists or not
     If( Not IsNumeric(arrResultaten(i,0) ) ) Then
       bResult = False
       Exit For
     End If

     Set RS = objConn.Execute( "SELECT Count(*) FROM tblStations WHERE ID=" & arrResultaten(i,0) )
     If( RS(0) < 1 ) Then
       bResult = False
       Exit For
     End If
     
     ' Check whether the counter value is correctly    
     If( Not IsNumeric( arrResultaten(i,1) ) ) Then
       bResult = False
       Exit For
     End If
     
     If( Trim(arrResultaten(i,1)) = "" ) Then
       bResult = False
       Exit For
     End If
     
     If( arrResultaten(i,1) < 0 ) Then
       bResult = False
       Exit For
     End If
     
   Next
   
   ' Database closen
       objConn.Close
   Set objConn = Nothing
   
   ' Return the results
   IsValidMessage = bResult
 End Function



 ' // ========================================================================
 ' // GetDatabase
 ' // ------------------------------------------------------------------------
 ' // Try to connect to the project database
 ' // ========================================================================

 Function GetDatabase()

   g_objDebugger.WriteLine( ">> GetDatabase" )

   'Declare variables
   Dim numErrNo
   Dim objDB
   
   'Set the FileSystemObject and the databaseobject
   Set objDB  = CreateObject("ADODB.Connection")
   
   'Try to open the database
   On Error Resume Next
     objDB.Open "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & STR_DATABASEFILE & ";"
     numErrNo = Err.Number   
   On Error Goto 0
   
   'If unable to succesfully do so, quit the script!
   If( numErrNo <> 0 ) Then
      g_objDebugger.WriteLine( ">> GetDatabase: Cannot find database.." )
      WScript.Quit
      
   'Otherwise, return the databaseobject
   Else
      Set GetDatabase = objDB
   End If
   
   g_objDebugger.WriteLine( "<< GetDatabase" )

 End Function