Интеграция с ПО UPOS через библиотеку PILOT_NT. 1.0 Платформа Win32.

- Титульная страница
- Группы
- Структуры данных

Чтение лояльности с банковской карты или карты лояльности
Расширенный функционал

Терминал может вернуть в ККМ данные, записанные на небанковской магнитной карте или данные из некоторых тегов банковской чиповой или бесконтактной карты карты. Чтение может быть произведено как в процессе выполнения операции "Оплата", так и отдельной функцией. Для чтения данных лояльности в терминале должны быть настроены программы лояльности. Если чтение выполняется в процессе оплаты, в терминале должен быть настроен параметр "Возвращать промежуточный код ответа".

Если была считана банковская карта, то если передать полученный хэш в функцию оплаты, то операция будет выполнена без повторного предложения вставить карту. Исключение представляют бесконтактные карты, т.к. для корректной операции по бесконтактной карте обязательно нужна сумма. Поэтому, если операция совершалась по бесконтактной карте, терминал повторно предложит ее приложить. По этой причине настояльно рекомендуется использовать операцию "оплата" для чтения всех видов карт.

Если карта лояльности или банковская карта с лояльностью считываются в процессе оплаты, то после считывания карты функция оплаты вернет код ответа 4353. В зависимости от настройки терминала это может означать:

1. Считана любая карта;
2. Считана банковская карта Сбербанка;
3. Считаная карта соответсвует одной из настроенных программ лояльноти.

ККМ должна проанализировать причины возврата кода 4353 и, при необходимости продолжить выполнение операции. Если была предъявлена банковская карта, то ККМ должна передать полученный хэш в качестве входного параметра.

Если требуется прочитать карту лояльности или лояльность с банковской карты без выполнения оплаты, нужно использовать функцию ReadCardContext. Перед чтением карты необходимо создать контекст функцией ctxAlloc. Если предполагается чтение GooglePay Smarttap или требуется ограничить срабатывание функции только на магнитные карты, необходимо установить значение параметра PAR_CARD_TYPE функцией ctxSetInt. Можно установить следующие значения:

1. CT_MS_ONLY - терминал ожидает только карты с магнитной полосой. Чиповые и бесконтактные карты игнорируются, сообщение об ошибке предъявления этих карт не отображаются.
2. CT_VAS_AND_PAY - терминал ожидает все карты и дополнительно считывает GooglePay Smarttap
3. CT_VAS_ONLY - терминал ожидает все карты по контактному и магнитному интерфейсу, а по бесконтакту считывает только GooglePay Smarttap. При предъявлении бесконтактной карты без GooglePay Smarttap, терминал отображает сообщение об ошибке и продолжает ждать карту.
4. CT_VAS_AND_MS - терминал ожидает только карты с магнитной полосой, а по бесконтакту считывает только AndroidPay Smarttap

Параметр PAR_CARD_TYPE управляет только интерфейсами. Например, установка значения CT_MS_ONLY означает что будут считываться карты с магнитной полосой как банковские, так и карты лояльноcти. Окончательное отделение одних от других должно выпоняться в ККМ. После установки требуемых значений необходимо вызвать ReadCardContext, передав контекст операции в качестве параметра, дождаться завершения работы и проанализировать возвращенный результат. Ненулевое значение означает ошибку. Если функция завершилась без ошибок, ККМ должна считать из контекста операции требуемые данные. для запроса данных используются функции ctxGetInt, ctxGetString или ctxGetBinary.

1. PAR_LLT_ID - номер настроенной в терминале программы лояльности, которой соответсвует предъявленная карта. Запрашивается функцией ctxGetInt;
2. PAR_PAN - маскированный PAN, если была предъявлена банковская карта или немаскированный PAN карты лояльности, или track2 карты лояльности, если из него не удалось выделить PAN. Запрашивается функцией ctxGetString;
3. PAR_HASH - Хэш от номера карты. Если PAR_PAN содержит track2 карты лояльности, параметр не возвращается. Запрашивается функцией ctxGetString;
4. PAR_CARD_TYPE - Тип считанной банковской карты. Запрашивается функцией ctxGetInt;
5. PAR_OWN_CARD - 1 - Банковская карта выпущена Сбербанком, 0 - карта выпущена сторонним банком или карта лояльности. Запрашивается функцией ctxGetInt;
6. PAR_VAS_LENGTH - длина данных кошелька AndroidPay Smarttap. Запрашивается функцией ctxGetInt;
7. PAR_VAS_STRING - данныt кошелька AndroidPay Smarttap. Запрашивается функцией ctxGetString;
8. PAR_LLT_DATA - номер лояльности считанный с бановской карты или карты лояльности. Запрашивается функцией ctxGetString.

Если один из параметров не найден в контексте, функции ctxGet... вернут ошибку ERR_CTX_GET.

После завершения чтения карты необходимо освободить контекст операции функцией ctxFree.

Например:

CONTEXT_PTR ctx=ctxAlloc();
//set card type
ctxSetInt(ctx, PAR_CARD_TYPE, CT_VAS_AND_MS);
int error = ReadCardContext(ctx);
std::cout << "ReadCardContext result=" << error << std::endl;
if (error==ERR_OK)
{
std::cout << "Retrive context vars..." << std::endl;
int ivalue;
char buf[128];
error = ctxGetInt(ctx, PAR_LLT_ID, &ivalue);
if (error==ERR_OK)
{
std::cout << "Loyalty Id = " << ivalue << std::endl;
error = ctxGetString(ctx, PAR_LLT_DATA, buf, sizeof(buf));
if (error==ERR_OK)
{
std::cout << "Loyalty data = " << buf << std::endl;
}
}
else
{
std::cout << "Loyalty Id is not found in context" << std::endl;
}
error = ctxGetString(ctx, PAR_PAN, buf, sizeof(buf));
if (error==ERR_OK)
{
std::cout << "PAN = " << buf << std::endl;
}
else
{
std::cout << "PAN is not found in context" << std::endl;
}
error = ctxGetString(ctx, PAR_HASH, buf, sizeof(buf));
if (error==ERR_OK)
{
std::cout << "HASH = " << buf << std::endl;
hashFromReadCard=buf;
}
else
{
std::cout << "HASH is not found in context" << std::endl;
}
error = ctxGetInt(ctx, PAR_CARD_TYPE, &ivalue);
if (error==ERR_OK)
{
std::cout << "Card type = " << ivalue << std::endl;
}
else
{
std::cout << "Card type is not found in context" << std::endl;
}
error = ctxGetInt(ctx, PAR_OWN_CARD, &ivalue);
if (error==ERR_OK)
{
std::cout << "Own card = " << ivalue << std::endl;
}
else
{
std::cout << "Own card is not found in context" << std::endl;
}
error = ctxGetInt(ctx, PAR_VAS_LENGTH, &ivalue);
if (error==ERR_OK)
{
std::cout << "vas xml length = " << ivalue << std::endl;
char* vas=new char [ivalue+1];
error = ctxGetString(ctx, PAR_VAS_STRING, vas, ivalue+1);
if (error == ERR_OK)
{
std::cout << "vas xml string " << std::endl << vas << std::endl;
}
else
{
std::cout << "vas xml string is not found in context" << std::endl;
}
delete [] vas;
}
else
{
std::cout << "vas length is not found in context" << std::endl;
}
}
ctxFree(ctx);

Существут два способа прередать хэш функции card_authorize15:

1. В поле ::auth_answer15::Hash. Значение передается в виде ASCII строки. Если хэш получен вызовом функции ReadCardContext, то первый символ 'H' должен быть удален.
2. В аргументе Track2. Значение передается "как есть". Библиотека pilot_nt сама удалит начальный символ 'H'.

Передача хэша в аргументе track2:

auth_answer14 argument;
DWORD amount1 = 99900;
memset(&argument, 0, sizeof(argument));
//allocate context
CONTEXT_PTR ctx=ctxAlloc();
argument.ans.TType = OP_PURCHASE;
argument.ans.Amount = amount1;
//предполагаем, что хэш мы получили предыдущим вызовом ReadCardContext
result = card_authorize15(hashFromReadCard.c_str(), &argument, NULL, 0, ctx);
//Не забываем освободить поле auth_answer::Check
if (argument.ans.Check)
::GlobalFree((HGLOBAL)argument.ans.Check);
ctxFree(ctx);

Передача хэша в поле Hash:

auth_answer14 argument;
DWORD amount1 = 99900;
memset(&argument, 0, sizeof(argument));
//allocate context
CONTEXT_PTR ctx=ctxAlloc();
argument.ans.TType = OP_PURCHASE;
argument.ans.Amount = amount1;
//предполагаем, что хэш мы получили предыдущим вызовом ReadCardContext
//set hash, skiping the first 'H'
strcpy(argument.Hash, hashFromReadCard.c_str()+1);
result = card_authorize15(NULL, &argument, NULL, 0, ctx);
//Не забываем освободить поле auth_answer::Check
if (argument.ans.Check)
::GlobalFree((HGLOBAL)argument.ans.Check);
ctxFree(ctx);

Пример проверки причины получения результата 4353:

if (result == 4353)
{
//check the reason for the response code 4353
//It can be:
//1. The card was issued by Sberbank.
//2. The card corresponds to some kind of loyalty program.
//3. Was read the GooglePay VAS
//check that the vas is present in response
int length=0;
result = ctxGetInt(ctx, PAR_VAS_LENGTH, &length);
if (result==ERR_OK && length)
{
std::cout << "Vas found in response. length = %d" << length << std::endl;
char* vas=new char[length+1];
result = ctxGetString(ctx, PAR_VAS_STRING, vas, length+1);
if (result==ERR_OK)
{
std::cout << "vas xml string " << std::endl << vas << std::endl;
}
delete [] vas;
}
//Check card issuer
hash = std::string(argument.Hash);
if (argument.SberOwnCard)
{
std::cout << "Card was issued by Sberbank. argument.SberOwnCard=" << argument.SberOwnCard<< std::endl;
std::cout << "Using an external library and the hash ";
std::cout << hash.c_str() << " we can query the balance and to write off the Spasibo bonuses"<<std::endl;
}
else
{
std::cout << "This card was issued by third-party bank. argument.SberOwnCard=" << argument.SberOwnCard<< std::endl;
}
//check the loyalty card. In general, it can be a bank card of Sberbank with loyalty data
int lltId=0;
result = ctxGetInt(ctx, PAR_LLT_ID, &lltId);
if (result==ERR_OK && lltId)
{
std::cout << "Loyalty programm number = " << lltId << std::endl;
std::cout << "Loyalty value = " << argument.Track3 << std::endl;
}
else
{
std::cout << "Loyalty not found" << std::endl;
}
//some other code...
}

См. также
  Docs\Для разработчиков ПО ККМ\examples\pilot_nt.dll\cpp\vas