Portalum.Zvt is a library designed to simplify communication with payment terminals via the ZVT Protocol used in (Germany, Austria, Switzerland). The library is based on Microsoft .NET.
Communication via Network (TCP) and communication via a serial connection is supported. The most important commands for processing a payment transaction with an electronic POS system are also already integrated.
The aim of this project is to achieve uncomplicated acceptance by payment service providers. The more often this project is referred to, the better it should work. Please help us to achieve this.
The package is available via NuGet
PM> install-package Portalum.Zvt
In the IReceiveHandler
interface the received data is now included in the CompletionReceived
event. Normally, the update should not lead to any difficulties.
event Action CompletionReceived;
change to event Action<byte[]> CompletionReceived;
The following features of the ZVT protocol were implemented.
Commands sent from the cash register to the payment terminal
- Registration
- Log-Off
- Authorization
- Reversal
- Refund
- End-of-Day
- Send Turnover Totals
- Repeat Receipt
- Diagnosis
- Abort
- Software-Update
Information sent from the payment terminal to the cash register
- Status-Information
- Intermediate StatusInformation
- Print Line
- Print Text-Block
- BMP Processing
- TLV Processing
Before sending a payment to the terminal, you should consider how to configure the terminal. For example, it can be set that a manual start of a payment at the terminal is no longer possible. You must also set where the receipts are printed directly via the terminal or via an external printer. For the configuration use the Registration
command.
Here you can find some code examples how to use this library
var deviceCommunication = new TcpNetworkDeviceCommunication("192.168.0.10");
if (!await deviceCommunication.ConnectAsync())
{
return;
}
using var zvtClient = new ZvtClient(deviceCommunication);
zvtClient.StatusInformationReceived += (statusInformation) => Console.WriteLine(statusInformation.ErrorMessage);
await zvtClient.PaymentAsync(10.5M);
var deviceCommunication = new TcpNetworkDeviceCommunication("192.168.0.10");
if (!await deviceCommunication.ConnectAsync())
{
return;
}
using var zvtClient = new ZvtClient(deviceCommunication);
zvtClient.StatusInformationReceived += (statusInformation) => Console.WriteLine(statusInformation.ErrorMessage);
await zvtClient.EndOfDayAsync();
var deviceCommunication = new TcpNetworkDeviceCommunication("192.168.0.10");
if (!await deviceCommunication.ConnectAsync())
{
return;
}
var clientConfig = new ZvtClientConfig
{
Encoding = ZvtEncoding.CodePage437,
Language = Language.German,
Password = 000000
};
var zvtClient = new ZvtClient(deviceCommunication, clientConfig: clientConfig);
This library uses the Microsoft.Extensions.Logging
package so you can easily decide where to write the log files, to a file or directly to the console output for example.
To write the logging output directly to the console output, this nuget packages is needed Microsoft.Extensions.Logging.Console
.
using var loggerFactory = LoggerFactory.Create(builder =>
{
builder.AddConsole().SetMinimumLevel(LogLevel.Debug);
});
var deviceCommunicationLogger = loggerFactory.CreateLogger<TcpNetworkDeviceCommunication>();
var zvtClientLogger = loggerFactory.CreateLogger<ZvtClient>();
var deviceCommunication = new TcpNetworkDeviceCommunication("192.168.0.10", logger: deviceCommunicationLogger);
if (!await deviceCommunication.ConnectAsync())
{
return;
}
var zvtClient = new ZvtClient(deviceCommunication, logger: zvtClientLogger);
var deviceCommunication = new TcpNetworkDeviceCommunication("192.168.0.10", port: 20007);
When using asynchronous completion, the payment process is split into two steps. First the payment is authorized. Then a callback is fired which allows the electronic cash register to dispense it's goods. After the goods have been dispensed successfully, the payment is completed. If something fails during the dispensing process, the payment is automatically reversed by the payment terminal. This ensures that a customer is not charged for goods that have not been dispensed or when something fails.
In order to use asynchronous completion:
- register the
CompletionStartReceived
callback in theZvtClient
. This callback is fired when the payment is authorized. - register the
CompletionDecisionRequested
callback in theZvtClient
. This callback must return the status of the asynchronous completion process.
Please note when using asynchronous completion the StatusInformationReceived
callback is fired multiple times as the payment terminal is
querying the electronic cash register for the completion status.
var deviceCommunication = new TcpNetworkDeviceCommunication("192.168.0.10");
if (!await deviceCommunication.ConnectAsync())
{
return;
}
var completionInfo = new CompletionInfo();
using var zvtClient = new ZvtClient(deviceCommunication);
zvtClient.CompletionStartReceived += (statusInformation) => {
completionInfo.State = CompletionInfoState.Wait;
// here you would start your asynchronous completion process, i.e. start dispensing a water bottle
Console.WriteLine("Start asynchronous completion");
Task.Delay(5000).ContinueWith((_) => {
// After the goods have been dispensed successfully, set the completion status to success
completionInfo.State = CompletionInfoState.Successful;
Console.WriteLine("Asynchronous completion finished");
});
};
// this callback is fired about every 2-4 seconds (depending on the payment terminal) to query the status of the asynchronous completion process
zvtClient.CompletionDecisionRequested += () => completionInfo;
await zvtClient.PaymentAsync(10.5M);
// this task will only return when the asynchronous completion process has finished
The payment terminal can be configured to stop the asynchronous completion after a certain number of queries. By default library sets
the number of tries to 10. This can be changed by setting the GetAsyncCompletionInfoLimit
property on the ZvtClientConfig
object
when constructing the ZvtClient
, see Set a custom configuration.
With the Portalum.Zvt.ControlPanel you can test the different ZVT functions.
To use the tool, the following steps must be performed
- Install at least .NET Desktop Runtime 6.0.16
- Download and extract the ControlPanel (download)
When you only want to transmit an amount to the payment terminal.
Then you can still look at our small tool. Portalum.Zvt.EasyPay
We have already been able to test the terminals of these payment service providers.
Provider | Country | Terminal |
---|---|---|
CardComplete | Austria | ingenico iWL250 |
CardComplete | Austria | Worldline VALINA |
Hobex | Austria | ingenico Desk/3500 |
Wordline/PAYONE (SIX) | Austria | yomani touch family |
Global Payments | Austria | PAX A80 |
- Encoding is fixed to
ISO-8859-1/ISO-8859-2/ISO-8859-15
instead of default character setCP437
. There is no way to configure this Print Line
contains TLV data at the end of the package, afterTLV-activation
. According to official documentation, there should be no TLV data here- The maximum number of retries for asynchronous completion is 3 when no other value is transmitted. According to the ZVT it should be infinite.
- Authorization - Partial issue for Vending machine (Change Amount for asynchronous completion is not supported)
- No
Print Line
support - Sends TLV data even without
TLV-activation
- Authorization - Partial issue for Vending machine (Change Amount for asynchronous completion is not supported)
- Abort from ECR not possible
Common Ports
of the device are 20007, 20008
Common BaudRates
is 9600 or 115200, default Parity
is None, default DataBits
is 8, default StopBits
is 2
The official documentation of the ZVT protocol is available here