Sistema di transazione via SMS con Scratch Card (PhixionFinancial)

1. Individuazione del problema

PhixionFinancial è una banca commerciale fondata come società per azioni che ha iniziato il suo funzionamento nella metà degli anni ottanta. I dipendenti della PhixionFinancial spendono parecchio tempo per le operazioni di transazione. Al momento non esistono le operazioni di transazioni digitali, così che i dipendenti della PhixionFinancial devono elaborarle a mano. La direzione ha deciso che le transazioni devono essere trattate in modo molto più efficiente e ha deciso di iniziare a lavorare su una soluzione per questo problema.

2. Obiettivi del nuovo sistema

Per risolvere il problema la direzione ha deciso di creare una soluzione per raggiungere i seguenti obiettivi:

3. Soluzione ActiveXperts SMS Messaging Server

La banca manterrà l'elaborazione delle transazioni tramite le consuete forme di transazione ma, inoltre, inizierà ad offrire «operazione scratch-card". Tale carta ha un importo stampato su di essa e viene usato per depositare una quantità di denaro su un conto bancario. Una complessa chiave di sicurezza composta da 15 caratteri, di cui l'ultimo carattere è un '-', è stampato su ogni carta. La chiave non è visibile, finché non viene grattata ad esempio mediante una moneta o unghia. Le chiavi stampate sulla Scratch Card, sono memorizzati in un database su un server all'interno della rete locale della banca. Il cliente deve inviare questa chiave alla banca via SMS,seguito dal numero di conto bancario in cui il denaro deve essere depositato.

Transazione Scratch Card sono offerte nelle seguenti classi:

Per raggiungere questo obiettivo, ActiveXperts SMS Messaging Server viene installato su una macchina dedicata. C'è un database che contiene tutti i dati del conto bancario e che si trova sullo stesso server. Tutte le chiavi delle Scratch Cards sono memorizzate anche loro in questo database. I titolari dei conti non possono aggiornare un conto in banca due volte con la stessa chiave, pertanto, ogni chiave ha una proprietà “Booleana disponibile". Non appena qualcuno usa la sua chiave, questo valore sarà cambiato. La tabella ha i seguenti campi:

Abbiamo creato un nuovo progetto in SMS Messaging Server. Questo progetto contiene uno script che elabora ogni messaggio SMS ricevuto attraverso il numero telefonico associato al server.

Ogni volta che viene ricevuto un SMS, il computer eseguirà la scansione del corpo di esso, per i numeri di conto e la chiave della Scratch Card. Il computer assume i primi 15 caratteri come chiave e gli ultimi 10 caratteri come numero di conto bancario. Ogni chiave si conclude con un "-", perciò un SMS si presenta come "1A3B5C7D9E11F1-1234567890".

In ogni caso il titolare del conto riceve una risposta via SMS.

Il codice


' // ========================================================================
' // C:\Program Files\ActiveXperts\SMS Messaging Server\Projects\The_Bank\Triggers\The_Bank.vbs
' // ------------------------------------------------------------------------
' // 
' // 
' // ========================================================================


Option Explicit

Const STR_DEBUGFILE     = "C:\Program Files\ActiveXperts\SMS Messaging Server\" & _
                          "Projects\The_Bank\LOG\The_Bank_Log.txt"
Const STR_DATABASE      = "C:\Program Files\ActiveXperts\SMS Messaging Server\" & _
                          "Projects\The_Bank\Database\bank.mdb"

' Declaration of global objects
Dim 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: loadDatabase
' // ------------------------------------------------------------------------
' // Loads the bank database, you can migrate to MySql or MSSql if you like..
' // just change the connection string if you do
' // ========================================================================

Function loadDatabase()

  Set loadDatabase = CreateObject("ADODB.Connection")
  loadDatabase.Open "Driver={Microsoft Access Driver (*.mdb)}; DBQ=" & STR_DATABASE & ";"

End Function

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

Function ProcessMessage( numMessageID )
   Dim objMessageIn, objMessageOut

   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, error: [" & _
          g_objMessageDB.LastError & "]"
      Exit Function
   End If


   ' Change Status to from Pending to Success. If you don't do it, the message 
   ' will be processed by subsequent triggers (if defined) because message is 
   ' still pending
   objMessageIn.Status = g_objConstants.MESSAGESTATUS_SUCCESS
   g_objMessageDB.Save objMessageIn  

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

   readmessage( objMessageIn )
 
   ' Close the Message Database
   g_objMessageDB.Close

   g_objDebugger.WriteLine "<< ProcessMessage"

End Function


' // ========================================================================
' // readmessage
' // ------------------------------------------------------------------------
' // Your custom function
' // ========================================================================

Function readmessage( objMessageIn )

   'Declare variables
   Dim objConn
   Dim strMessage, strBankaccount, strSender, strKey
   Dim strQuery, RS, strUpdateQuery

   'Load the database object
   Set objConn = loadDatabase
   
   'Get some info from the sms
   'I've created 8 character keys in the database, so I only
   'need to know the first 8 characters of the sms because I
   'asume that will contain the update key
   strMessage     = objMessageIn.Body
   strSender      = objMessageIn.Sender
   strKey         = Left(strMessage, 15)
   strBankAccount = Mid(strMessage, 16, 10)
   
   'Perhaps the customer sends a question mark because he/she
   'does not know how to use the system. If so, reply with a short howto
   If( Left( strMessage, 1 ) <> "?" ) Then
   
     'Try to fetch the upgrade key from the database
     strQuery   = "SELECT * FROM upgrades WHERE key='" & strKey & "' AND available=true"
     Set RS     = objConn.Execute( strQuery )
   
     'When unable to find the key in the database, notify the sender
     'When able to find the key, upgrade the customers bank account
     If( Not RS.EOF ) Then
       g_objDebugger.WriteLine ">> Start processing message: "
       updateCustomersCredit strKey, strBankAccount, strSender
     Else
       g_objDebugger.WriteLine ">> Invalid upgrade key.. script ended...."
       strMessage =  "Invalid key: Your key was: " & strKey & "."
       reply strSender, strMessage
     End If
   Else
   
     reply strSender, "Please SMS your 8-character upgrade key. The system will " & _
        "upgrade your bank account."
   End If

  g_objDebugger.WriteLine "<< Done processing"

End Function


' // ========================================================================
' // Function: Update
' // ------------------------------------------------------------------------
' // Function to update the database and the customer his credit
' // ========================================================================

Function updateCustomersCredit(strKey, strBankAccount, strSender)

    'Declare variables
    Dim objConn
    Dim strQuery, RSAccount

    'Load the database object
    Set objConn = loadDatabase

    'try to associate the senders phonenumber with his bank account
    strQuery      = "SELECT * FROM accounts WHERE customerAccount=" & strBankAccount
    Set RSAccount = objConn.Execute( strQuery )
    
    'When able to find associate:
    If ( Not RSAccount.EOF ) Then
      
      Dim RSUpgrade
      strQuery      = "SELECT * FROM upgrades WHERE key='" & strKey & "'"
      Set RSUpgrade = objConn.Execute( strQuery )
      
      If ( Not RSUpgrade.EOF ) Then

         g_objDebugger.WriteLine ">> Upgrade valid.."

         'Declare variables
         Dim varCurrentValue, varValue, varNewValue
         Dim errNo, errDescr

         'Calculate the customers new credit
         varCurrentValue = CInt( RSAccount("customerCredit") )
         varValue        = CInt( RSUpgrade("Value") )
         varNewValue     = varCurrentValue + varValue
         
         'Create an update query to update the customers credit
         strQuery = "UPDATE accounts SET customerCredit=" & varNewValue & _
            " WHERE customerAccount=" & strBankAccount

         'Execute the query and try to fetch errors if they occure
         On Error Resume Next
           objConn.Execute( strQuery )
           errNo    = Err.Number
           errDescr = Err.Description
         On Error Goto 0
         
         'if the database was updated properly:
         If ( errNo = 0 ) Then
            
            'Update the database, disable the key. Otherwise the 
            'customer is able to update his credits twice
            'Deleting the record is probably a better idea, but you will not see
            'what exactly happens
            strQuery = "UPDATE upgrades SET available=false WHERE key='" & strKey & "'"
            objConn.Execute( strQuery )
            
            'notify the sender the key was processed succesfully
            reply strSender, "Key processed succesfully, account's credit is upgraded." 
            
            'Update the logfile
            g_objDebugger.WriteLine ">> Key succesfully processed!!"
         Else
            'notify the sender the message wasn't processed properly
            reply strSender, "Sorry.. Error processing message. Please try again or try " & _
                "contacting our servicedesk."
            
            'Update the logfile
             g_objDebugger.WriteLine ">> Error processing message: " & errDescr
         End If 
      End If
    Else
    
       'otherwise, notify the sender
       g_objDebugger.WriteLine ">> Unable to process "
       reply strSender, "Unable to process your message. Could not find account number. " & _
            "Please try again! AccountNo.:" & strBankAccount
    End If
End Function


' // ========================================================================
' // Function: Reply
' // ------------------------------------------------------------------------
' // used to reply to the sender
' // ========================================================================

Function reply(strRecipient, strMessage)

   Dim objMessageOut
   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  ' Any available SMTP channel
      objMessageOut.Body      = strMessage
      g_objMessageDB.Save objMessageOut
      g_objDebugger.WriteLine ">>>> Message succesfully sent"
   Else
      g_objDebugger.WriteLine ">>>> !!! ERROR PROCESSING MESSAGE !!! ERR.NO: " & _
            g_objMessageDB.LastError
   End If

End Function