Continuando con las series de programación, Kal es un software multivendor para kioskos y de ATMs mediante este software permite la centralización de la gestión desde un mismo punto y de forma multivendor de varias marcas de hardware de ATMs, mediante su plataforma kalignite.
Esta plataforma permite mediante múltiples interfaces el acceso a los perimetrales mediante la implementación de los Kxcontrolers también llamadas DLLs de funciones y esto permite darle funcionalidades lógicas a los perimetrales para operar en entornos financieros.
En este caso queremos mostrar como hacer una interacción con una aplicación hecha a mano , aunque existe el KXdesingner o Active X Control, dentro de la suite que facilita extremadamente este tipo de desarrollos la idea es explicar a mano como interacción desde HTML hacia un perimetral.
Para empezar pueden usar cualquier IDE, o notepad que permita escribir y guardar en formato HTML vamos a hacer una pequeña aplicación de dispensador.
Para el caso de KAL tiene una interfaz que se puede programar con Vbscripts y HTML la cual pues usaremos para tal demostración., aunque para los bancos con el KXFormsDesigner ayuda y ya resuelve mucho trabajo de programación como si fuera un dreamweaver no la usaremos para este ejemplo
vamos a reproducir un accionador de capacidades y estatus de dispensador como esto:
estas funciones dependen de KXCashDispenser, Claro que en el siguiente código para evitar incidentes evitamos ciertas cositas de los formatos html, pero para el programador entrenado se pueden ver a simple vista si intentamos montar una aplicación HTML, que está faltando agregar a mano ;)
<SCRIPT language=vbscript src=Common.vbs></SCRIPT>
<script LANGUAGE="VBScript">
<!--
sub buttonEnableCashUnitEvents_OnClick()
call KXCashDispenser1.EnableCashUnitEvents()
end sub
sub buttonDisableCashUnitEvents_OnClick()
DisplayValue LabelCashUnitInfoChangedEvent, ""
call KXCashDispenser1.DisableCashUnitEvents()
end sub
-->
</script>
<script LANGUAGE="VBScript">
<!--
' Global Declarations
Dim gNotesInStacker
Dim gNotesAtOutput
Dim CUNum
Dim initialisation
Dim ErrorTargetLabel
Dim CashPresentTargetLabel
Dim Control
dim CashUnitConfigurationInitiated
dim LabelNotSupported
' Initialisation
Sub window_onload()
Set Control = KXCashDispenser1
Set ErrorTargetLabel = lblErrorStatus
gNotesInStacker = False
gNotesAtOutput = False
txtMixDenomination.innerText = "0, 1"
initialisation = False
CashUnitConfigurationInitiated = False
Set LabelNotSupported = LabelCalibrateComplete
' Warning: Don't call any methods or properties on the control on startup
' otherwise the service name and instance name cannot be set.
end sub
Sub KXCashDispenser1_DeviceError()
frameLastEvent.UpdateLastEvent "DeviceError"
lblErrorStatus.innerText = "DeviceError"
ErrorTargetLabel.innerText = "DeviceError"
UpdateAllStatusDisplays
end sub
Sub KXCashDispenser1_FatalError(hResult)
frameLastEvent.UpdateLastEvent "FatalError"
lblErrorStatus.innerText = "FatalError " & hResult
end sub
Sub KXCashDispenser1_Timeout()
frameLastEvent.UpdateLastEvent "Timeout"
lblPresentReturn.innerText = "Timeout"
call UpdateAllStatusDisplays
end sub
Sub KXCashDispenser1_StatusChanged(PropertyName,OldValue,NewValue)
frameLastEvent.UpdateLastEvent "StatusChanged"
frameStatusChanged.StatusChanged PropertyName, OldValue, NewValue
end sub
Sub KXCashDispenser1_CashUnitInfoChanged(cu)
frameLastEvent.UpdateLastEvent "CashUnitInfoChanged"
LabelCashUnitInfoChangedEvent.innerText = "Cash Unit Info Changed (" & cu & ")"
end sub
Sub KXCashDispenser1_CashUnitThresholdCrossed(cu)
frameLastEvent.UpdateLastEvent "CashUnitThresholdCrossed"
LabelCashUnitInfoChangedEvent.innerText = "Cash Unit Threshold Crossed (" & cu & ")"
End Sub
Sub DisplayLastDispense()
lblLastDispenseCounts.innerText = ToString(KXCashDispenser1.LastDispenseCounts)
lblLastDispensePresented.innerText = KXCashDispenser1.LastDispenseWasPresented
End Sub
Sub UpdateAllStatusDisplays()
If KXCashDispenser1.StDeviceStatus <> "NODEVICE" then
DisplayStatus
DisplayLastDispense
call btnGetMixInfo_OnClick()
call btnGetCUStatus_OnClick()
else
lblDeviceStatus.innerText = KXCashDispenser1.StDeviceStatus
lblDetailedDeviceStatus.innerText = KXCashDispenser1.StDetailedDeviceStatus
end if
end sub
Sub ClearAllEventDisplays()
DisplayValue lblMixReturn, ""
DisplayValue lblDispenseReturn, ""
DisplayValue lblRejectReturn, ""
DisplayValue lblPresentReturn, ""
DisplayValue lblRetractReturn, ""
DisplayValue lblShutterStateChange, ""
DisplayValue lblExchangeStateChange, ""
DisplayValue lblErrorStatus, ""
DisplayValue lblCountResult, ""
DisplayValue lblCountedItems, ""
DisplayValue lblDispensedItems, ""
frameStatusChanged.ClearEventLabels
frameEventManagement.ClearEventLabels
frameLastEvent.ClearEventLabels
End Sub
Sub KXCashDispenser1_CashUnitError(cu)
frameLastEvent.UpdateLastEvent "CashUnitError"
alert "CashUnitError(" & cu & ")"
End Sub
-->
</script>
<h2 align="center"><a name="Mixing and Dispensing Cash">Mix y dispensador de Cash</a></h2>
<SCRIPT id="ClientEventHandlersVBS" language=vbscript>
<!--
OPTION EXPLICIT
Sub btnMix_OnClick()
call ClearAllEventDisplays()
call KXCashDispenser1.Mix(txtMixAmount.Value, txtMixCurrency.Value, txtMixAlgorithm.Value)
end sub
Sub KXCashDispenser1_MixComplete(NoteCounts)
frameLastEvent.UpdateLastEvent "MixComplete"
call UpdateAllStatusDisplays()
lblMixReturn.innerText = "MixComplete"
txtMixDenomination.innerText = ToString(NoteCounts)
end sub
Sub btnDispense_OnClick()
set ErrorTargetLabel = lblDispenseReturn
set CashPresentTargetLabel = lblCountResult
call ClearAllEventDisplays()
if txtMixDenomination.Value <> "" then
dim Denom
Denom = ToArray(txtMixDenomination.Value)
call KXCashDispenser1.Dispense(txtMixAmount.Value,Denom, txtMixCurrency.Value, txtMixAlgorithm.Value)
else
MsgBox("pon la demonicacion primero!")
end if
end sub
Sub KXCashDispenser1_CashDispensed()
frameLastEvent.UpdateLastEvent "CashDispensed"
lblDispenseReturn.innerText = "CashDispensed"
call UpdateAllStatusDisplays()
gNotesInStacker = True
end sub
Sub btnReject_OnClick()
set ErrorTargetLabel = lblRejectReturn
call ClearAllEventDisplays()
' if gNotesInStacker then
call KXCashDispenser1.Reject()
gNotesInStacker = False
' else
' MsgBox(" primero de dispensa antes de hacer reject de las notas!")
' end if
end sub
Sub KXCashDispenser1_CashRejected()
frameLastEvent.UpdateLastEvent "CashRejected"
call UpdateAllStatusDisplays()
lblRejectReturn.innerText = "CashRejected"
gNotesInStacker = False
end sub
Sub btnPresent_OnClick()
set ErrorTargetLabel = lblPresentReturn
set CashPresentTargetLabel = lblPresentReturn
call ClearAllEventDisplays()
call KXCashDispenser1.Present(txtTimeout.Value)
end sub
' Present event handlers
Sub KXCashDispenser1_CashPresented()
frameLastEvent.UpdateLastEvent "CashPresented"
CashPresentTargetLabel.innerText = "CashPresented"
call UpdateAllStatusDisplays()
gNotesInStacker = False
gNotesAtOutput = True
end sub
Sub KXCashDispenser1_WaitCancelled()
frameLastEvent.UpdateLastEvent "WaitCancelled"
lblPresentReturn.innerText = "WaitCancelled"
call UpdateAllStatusDisplays()
end sub
Sub KXCashDispenser1_CashTaken()
frameLastEvent.UpdateLastEvent "CashTaken"
CashPresentTargetLabel.innerText = "CashTaken"
call UpdateAllStatusDisplays()
gNotesAtOutput = False
end sub
Sub KXCashDispenser1_NotDispensable()
frameLastEvent.UpdateLastEvent "NotDispensable"
lblDispenseReturn.innerText = "NotDispensable"
call UpdateAllStatusDisplays()
end sub
Sub btnCancelWait_OnClick()
set ErrorTargetLabel = lblPresentReturn
call ClearAllEventDisplays()
call KXCashDispenser1.CancelWaitForCashTaken()
end sub
Sub btnRetract_OnClick()
set CashPresentTargetLabel = lblRetractReturn
set ErrorTargetLabel = lblRetractReturn
call ClearAllEventDisplays()
call KXCashDispenser1.Retract()
end sub
Sub btnRetractToPosition_OnClick()
set CashPresentTargetLabel = lblRetractReturn
set ErrorTargetLabel = lblRetractReturn
call ClearAllEventDisplays()
call KXCashDispenser1.RetractToPosition(txtRetractLocation.Value)
end sub
Sub KXCashDispenser1_CashRetracted()
frameLastEvent.UpdateLastEvent "CashRetracted"
lblRetractReturn.innerText = "CashRetracted"
call UpdateAllStatusDisplays()
gNotesAtOutput = False
end sub
Sub btnOpenShutter_OnClick()
set ErrorTargetLabel = lblShutterStateChange
call ClearAllEventDisplays()
if (KXCashDispenser1.CpHasShutter) then
call KXCashDispenser1.OpenShutter()
else
call MsgBox("Este SPI no tiene capacidad par abrir el shutter mira el error xfs!")
end if
end sub
Sub KXCashDispenser1_ShutterOpen()
frameLastEvent.UpdateLastEvent "ShutterOpen"
lblShutterStateChange.innerText = "ShutterOpen"
call UpdateAllStatusDisplays()
end sub
Sub btnCloseShutter_OnClick()
set ErrorTargetLabel = lblShutterStateChange
call ClearAllEventDisplays()
if (KXCashDispenser1.CpHasShutter) then
call KXCashDispenser1.CloseShutter()
else
call MsgBox("This Service Provider hasn't got the capabilities to close the shutter!")
end if
end sub
Sub KXCashDispenser1_ShutterClosed()
frameLastEvent.UpdateLastEvent "ShutterClosed"
lblShutterStateChange.innerText = "ShutterClosed"
call UpdateAllStatusDisplays()
end sub
Sub btnMixAndDispense_OnClick()
set ErrorTargetLabel = lblDispenseReturn
call ClearAllEventDisplays()
call KXCashDispenser1.MixAndDispense(txtMixAmount.Value, txtMixCurrency.Value, txtMixAlgorithm.Value)
end sub
Sub btnDispenseAndPresent_OnClick()
set ErrorTargetLabel = lblPresentReturn
set CashPresentTargetLabel = lblPresentReturn
call ClearAllEventDisplays()
if txtMixDenomination.Value <> "" and txtTimeout.Value <> ""then
dim Denom
Denom = ToArray(txtMixDenomination.Value)
call KXCashDispenser1.DispenseAndPresent(txtMixAmount.Value,Denom, txtMixCurrency.Value, txtMixAlgorithm.Value, txtTimeout.Value)
else
MsgBox(" insrta la demonimación y el tiempo primero!")
end if
end sub
Sub ButtonLastDispenseExtendedStatus_OnClick()
Dim Devstatus
Devstatus = KXCashDispenser1.StDeviceStatus
if Devstatus <> "NODEVICE" then
LabelLastDispenseExtendedStatus.innerText = KXCashDispenser1.LastDispenseExtendedStatus(TextLastDispenseExtendedStatus.value)
end if
end sub
-->
</SCRIPT>
<p><small>inserta el monto a dispensar y presiona
"Calculate Mix" to calculate the note mix (if the Service
Provider supports this), or enter the mix as a comma-separated array
of note counts from each cash unit (denomination). Press
"Dispense" then "Present" to finish the
transaction. </small>
</p>
<table align=center width="90%" height="396">
<tr>
<td width="45%" colspan="3">Mix y Dispensar</td>
<td width="30%" colspan="2">Peesentar & Retract</td>
<td width="25%" colspan="2">Control de Shutter </td>
</tr>
<tr>
<td width="15%"><small>Mix Algorithm:</small> <TEXTAREA class=Name id=txtMixAlgorithm>1</TEXTAREA></td>
<td width="15%"><small>Cantidad a dispensar </small><TEXTAREA class=Name id=txtMixAmount>100</TEXTAREA></td>
<td width="15%"><small>Divisa a dispensar</small> <TEXTAREA class=Name id=txtMixCurrency>GBP</TEXTAREA></td>
<td width="30%" colspan=2><small> Timeout (ms)</small> <TEXTAREA class=Name id=txtTimeout>30000</TEXTAREA></td>
<td width="25%" colspan=2 rowspan=2> </td>
</tr>
<tr>
<td width="45%" colspan="3"><small>Las Notes de cada denominación a dispensar</small> <TEXTAREA class=Name id=txtMixDenomination></TEXTAREA></td>
<td width="30%" colspan="2"><small>Retract location</small> <TEXTAREA class=Name id=txtRetractLocation>RETRACT</TEXTAREA></td>
</tr>
<tr>
<td width="15%"><button id=btnMix style="MARGIN-TOP: 25px; HEIGHT: 50px">Calculate <br>MIX</button></td>
<td width="15%"><button id=btnDispense style="MARGIN-TOP: 25px; HEIGHT: 50px">Dispensar!!</button></td>
<td width="15%"><button id=btnReject style="MARGIN-TOP: 25px; HEIGHT: 50px">Reject</button></td>
<td width="15%"><button id=btnPresent style="MARGIN-TOP: 25px; HEIGHT: 50px">PRESENTAR</button></td>
<td width="15%">
<button id=btnCancelWait style="HEIGHT: 33px">Cancel Wait</button><br>
<button id=btnRetract style="HEIGHT: 33px">Retract</button><br>
<button id=btnRetractToPosition style="HEIGHT: 33px">Retract a<br>Posicion</button>
</td>
<td width="12%"><button id=btnOpenShutter style="MARGIN-TOP: 25px; HEIGHT: 50px">Abrir</button></td>
<td width="12%"><button id=btnCloseShutter style="MARGIN-TOP: 25px; HEIGHT: 50px">Cerrar</button></td>
</tr>
<tr>
<td width="45%" colspan="3"><button id=btnMixAndDispense>Mix y Dispensar</button></td>
<td width="30%" colspan="2"><button id=btnDispenseAndPresent>Dispensar y presentar </button></td>
<td width="25%" colspan="2"> </td>
</tr>
<tr>
<td width="15%" class=label id=lblMixReturn>(unset)</td>
<td width="15%" class=label id=lblDispenseReturn>(unset)</td>
<td width="15%" class=label id=lblRejectReturn>(unset)</td>
<td width="15%" class=label id=lblPresentReturn>(unset)</td>
<td width="15%" class=label id=lblRetractReturn>(unset)</td>
<td width="25%" colspan=2 class=label id=lblShutterStateChange>(unset)</td>
</tr>
</table>
<P> </P>
Este código básicamente si el SPI no está ocupado que para ejecutarse no deben permitir de la suite kalignite se ejecute , esto se puede hacer booteando directo al S.O., entonces permite tomar control del SPI para interacciones desde una interfaz HTML a las funciones de KXCashDispenser, y concretamente permitir dispensar si las configuraciones concuerdan con el ATM.
No solamente un ATM son importantes las funciones de dispensado existen muchisimas mas como ( y no limitantes a ):
- Funciones de Audio
- Card reader
- Biométrico
- Lector de códigos de barras
- aceptadores de dinero
- Journal
- PinPad
- Impresora
- sensores ..etc..
Por nombrar algunas funciones entonces en general esto es solo una pequeña demostración de todas las funciones que podemos controlar local o con algún REST API de forma remota del ATM, nos podemos encontrar con más de 3000 funciones , sensores y estados a programar para una operación lógica normal en entornos financieros cabe destacar que en estas series de programación de ATMS, para este caso solo sirven para la interfaz HTML y VBS del software KAL.
Saludos