Примеры скриптов обработки онлайн-платежей
Материал из BiTel WiKi
По новому 54-ФЗ нужно печатать чек на каждый приём денег. Некоторые системы встраивают эту процедуру на своей стороне, в этих модулях биллинга есть возможность пользоваться этим. Они используют, например, атол-онлайн или свои мощности ККМ. Если вы хотите печатать чек на своей стороне и на своём ККМ, то в данный момент это можно сделать через небольшой набор скриптов.
Работает так:
Приходит платёж от сторонней системы, вы скриптом отлавливаете и небольшим кодом через 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()); } } } }