Примеры скриптов обработки онлайн-платежей

Материал из BiTel WiKi

Версия от 06:31, 23 июля 2019; DimOn (Обсуждение | вклад)
(разн.) ← Предыдущая | Текущая версия (разн.) | Следующая → (разн.)
Перейти к: навигация, поиск

По новому 54-ФЗ нужно печатать чек на каждый приём денег. Некоторые системы встраивают эту процедуру на своей стороне, в этих модулях биллинга есть возможность пользоваться этим. Они используют, например, атол-онлайн или свои мощности ККМ. Если вы хотите печатать чек на своей стороне и на своём ККМ, то в данный момент это можно сделать через небольшой набор скриптов в версиях до 7.0.

В версиях 7.0+ есть аналогичный штатный механизм: https://docs.bitel.ru/pages/viewpage.action?pageId=126222350

Работает так:

Приходит платёж от сторонней системы, вы скриптом отлавливаете и небольшим кодом через API отправляете на печать чека. ККМ далее делает отправку в ОФД, далее ОФД отправляет email/sms итд. Все скрипты - для дин.кода.

Документация по дин.классам: https://docs.bitel.ru/pages/viewpage.action?pageId=43385236

Привязка дин.кода к событию: https://docs.bitel.ru/pages/viewpage.action?pageId=43385244

Привязка дин.кода к глобальному скрипту: https://docs.bitel.ru/pages/viewpage.action?pageId=43385260

Периодическое выполнение глобальных скриптов: https://docs.bitel.ru/pages/viewpage.action?pageId=43385264


Скрипт на приём платежа:

package ***;
 
import static ru.bitel.bgbilling.common.bean.BGBaseConstants.KEY_CUSTOMER_ADDRESS;
 
import java.sql.Connection;
 
import bitel.billing.server.util.MailMsg;
import ru.bitel.bgbilling.common.BGException;
import ru.bitel.bgbilling.kernel.contract.api.common.bean.Contract;
import ru.bitel.bgbilling.kernel.contract.api.server.bean.ContractDao;
import ru.bitel.bgbilling.kernel.contract.balance.common.bean.Payment;
import ru.bitel.bgbilling.kernel.contract.balance.server.event.PaymentEvent;
import ru.bitel.bgbilling.kernel.contract.config.server.ContractModuleConfigDao;
import ru.bitel.bgbilling.kernel.script.server.dev.EventScriptBase;
import ru.bitel.bgbilling.plugins.cashcheck.server.CashCheckUtils;
import ru.bitel.bgbilling.plugins.cashcheck.server.bean.Check;
import ru.bitel.bgbilling.server.util.Setup;
import ru.bitel.common.sql.ConnectionSet;
 
/**
 * Обрабатываем приход платежа с печатью на регистраторах по событию «Приход платежа».
 * Попытка костыля для обработки онлайн-платежей.
 * @author dimon
 */
public class CashCheckPrintPayment
	extends EventScriptBase<PaymentEvent>
{
	/**
	 * [Настройки здесь]
	 * Номер ККМ из конфига плагина, на котором печатать.
	 */
	private int kkmNum = 2;
 
	/**
	 * [Настройки здесь]
	 * Пароль, под которым заходит в ККМ.
	 */
	private int kkmPass = 3;
 
	/**
	 * [Настройки здесь]
	 * e-mail администраторов, куда слать уведомления.
	 */
	private String[] EMAILS = {"***@***.ru"};
 
	/**
	 * [Настройки здесь]
	 * На основании переданных данных (payment, contract) генерируется объект Check.
	 * Там же внутри в объект Check ставятся тип платежей для ККМ (check.setPaymentType) и налоговая группа для ККМ (check.setTax).
	 */
	private void makeCheck(Connection con, Payment payment, Contract contract) throws Exception
	{
		if(payment.getTypeId() == 99)
		{
			check = new Check();
 
			int MID = 16; // это mid модуля платёжного этого, того где в ЛК вводят нужный email, все мыла сохраняются отдельно для каждого модуля, сейчас так сделано			
 
			ContractModuleConfigDao contractModuleConfigDao = new ContractModuleConfigDao( con, MID );
			String customerEmail = contractModuleConfigDao.get( contract.getId(), KEY_CUSTOMER_ADDRESS );
			contractModuleConfigDao.close();
 
			check.setPaymentType(1); // ставим ТИП ПЛАТЕЖА ККМ: 1 - нал, 2,3,4 - безнал или какой-то другой тип оплаты
			check.setTax(0); // ставим ТИП НАЛОГА ККМ: 0 - по номеру секции (в атолах), N  - какой-то другой на выбор
			check.setOnlyElCheck(true); // "только электронный чек"
			check.setCustomerEmail(customerEmail);
			int paymentDep = 1; // отдел, используется ниже в addPayment
			// добавляем параметр договора
			//int PARAM_ID = 3;
			//ContractParameterManager bgParamMan = new ContractParameterManager( con );
			//String paramVal = bgParamMan.getStringParam( event.getContractID(), PARAM_ID );
			// check.addString( "Какой-то параметр договора: " + paramVal );
			check.addPayment( payment.getSum(), "Оплата услуг Интернета и Телевидения по договору" + contract.getTitle(), paymentDep );
		}
		if(payment.getTypeId() == 666) // остальные ветки по аналогии
		{
			//check = new Check();
			//...
		}
	}
 
	// --- всё что ниже менять не нужно ---
 
	private Check check = null;
 
	@Override
	public void onEvent(PaymentEvent event, Setup setup, ConnectionSet set)
		throws Exception
	{
		if(event.isEditMode()) return; // если платёж редактируется, а не создаётся, то сразу уходим
		Connection con = set.getConnection();
		Payment payment = event.getPayment();
		int userId = payment.getUserId();
		check = null;
		print( "CashCheck Autoprint: user id="+userId+", payment should be automatically printed..." );
		ContractDao contractDao = new ContractDao(con, userId);
		Contract contract = contractDao.get(payment.getContractId());
		contractDao.close();
		makeCheck( con, payment, contract ); // в этом методе делается всё про чек - устанавливаются глобальные check и kkmNum
		if( check != null )
		{
			try
			{
				CashCheckUtils.printCheck(check, CashCheckUtils.getPrinter( kkmNum ), kkmPass, con, payment.getId());
				print( "CashCheck Autoprint: check was printed!" );
			}
			catch(BGException e)
			{
				print( "CashCheck Autoprint: check ERROR: " + e.getMessage() );
				sendMails(setup, "CashCheck Autoprint: check ERROR", e.printStackTraceToString());
			}
		}
		else
		{
			error( "CashCheck Autoprint: makeCheck: check == null, payment NOT printed!" ); 
		}
	}
 
	private void sendMails(Setup setup, String subject, String body)
	{
		MailMsg mailmsg = new MailMsg(setup);
		for(String email : EMAILS)
		{
			try
			{
				print("CashCheck Autoprint: Send e-mail to "+email+"...");
				mailmsg.sendMessage(email, subject, body);
			}
			catch (Exception e)
			{
				error("CashCheck Autoprint: Error send e-mail: "+e.toString());
			}
		}
	}
}

Также надо бы автоматически закрывать день. Для этого скрипт по таймеру каждую ночь делает на ККМ z-отчёт.

package ***;
 
import bitel.billing.server.util.MailMsg;
import ru.bitel.bgbilling.common.BGException;
import ru.bitel.bgbilling.kernel.script.server.dev.GlobalScriptBase;
import ru.bitel.bgbilling.plugins.cashcheck.server.CashCheckUtils;
import ru.bitel.bgbilling.server.util.Setup;
import ru.bitel.common.sql.ConnectionSet;
 
/**
 * Закрытие дня (снятие z-отчёта). Скрипт глобальный, для выполнения по таймеру.
 * Подразумевается запуск поздно ночью.
 * Попытка костыля для обработки онлайн-платежей.
 * @author dimon
 */
public class CashCheckCloseDay
	extends GlobalScriptBase
{
	/**
	 * [Настройки здесь]
	 * Номер ККМ из конфига плагина, на котором печатать.
	 */
	private int kkmNum = 2;
 
	/**
	 * [Настройки здесь]
	 * Пароль, под которым заходит в ККМ. Скорее всего нужен админский.
	 */
	private int kkmPass = 30;
 
	/**
	 * [Настройки здесь]
	 * e-mail администраторов, куда слать уведомления.
	 */
	private String[] EMAILS = {"***@***.ru"};
 
	@Override
	public void execute(Setup setup, ConnectionSet set)
		throws Exception
	{
		print( "CashCheck Autoprint: ZReport..." );
		try
		{
			CashCheckUtils.ZReport(CashCheckUtils.getPrinter( kkmNum ), kkmPass);
			print( "CashCheck Autoprint: ZReport was made!" );
			sendMails(setup, "CashCheck Autoprint: ZReport was made!", "subj");
		}
		catch(BGException e)
		{
			print( "CashCheck Autoprint: ZReport ERROR: " + e.getMessage() );
			sendMails(setup, "CashCheck Autoprint: ZReport ERROR", e.printStackTraceToString());
		}
	}
 
	private void sendMails(Setup setup, String subject, String body)
	{
		MailMsg mailmsg = new MailMsg(setup);
		for(String email : EMAILS)
		{
			try
			{
				print("CashCheck Autoprint: Send e-mail to "+email+"...");
				mailmsg.sendMessage(email, subject, body);
			}
			catch (Exception e)
			{
				error("CashCheck Autoprint: Error send e-mail: "+e.toString());
			}
		}
	}
}
Личные инструменты