/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
* Copyright (c) 2013, MPL CodeInside http://codeinside.ru
*/
package ru.codeinside.gws3572c;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.xml.sax.InputSource;
import ru.codeinside.gws.api.*;
import ru.roskazna.xsd.bill.Bill;
import ru.roskazna.xsd.budgetindex.BudgetIndex;
import ru.roskazna.xsd.charge.ChargeType;
import ru.roskazna.xsd.common.AddressType;
import ru.roskazna.xsd.common.ContactInfoType;
import ru.roskazna.xsd.doacknowledgmentrequest.DoAcknowledgmentRequestType;
import ru.roskazna.xsd.doacknowledgmentresponse.DoAcknowledgmentResponseType;
import ru.roskazna.xsd.exportpaymentsresponse.ExportPaymentsResponse;
import ru.roskazna.xsd.exportquittanceresponse.ExportQuittanceResponse;
import ru.roskazna.xsd.organization.Account;
import ru.roskazna.xsd.organization.Bank;
import ru.roskazna.xsd.organization.Organization;
import ru.roskazna.xsd.paymentinfo.PaymentIdentificationDataType;
import ru.roskazna.xsd.paymentinfo.PaymentInfoType;
import ru.roskazna.xsd.paymentinfo.PaymentType;
import ru.roskazna.xsd.pgu_chargesresponse.ExportChargesResponse;
import ru.roskazna.xsd.pgu_datarequest.DataRequest;
import ru.roskazna.xsd.pgu_importrequest.ImportRequest;
import ru.roskazna.xsd.postblock.PostBlock;
import ru.roskazna.xsd.ticket.Ticket;
import ru.rosrazna.xsd.smevunifoservice.ExportData;
import ru.rosrazna.xsd.smevunifoservice.ExportDataResponse;
import ru.rosrazna.xsd.smevunifoservice.ImportData;
import ru.rosrazna.xsd.smevunifoservice.ImportDataResponse;
import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.StringReader;
import java.math.BigInteger;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
public class GMPClient3572 implements Client {
public static final String IMPORT_CHARGE_OPERATION = "importCharge";
public static final String EXPORT_OPERATION = "exportData";
public static final String IMPORT_PAYMENT_OPERATION = "importPayment";
public static final String DO_ACKNOWLEDGMENT_OPERATION = "DoAcknowledgmentRequest";
protected CryptoProvider cryptoProvider;
public static final String SMEV_INITIAL_REG_NUMBER = "smevInitialRegNumber";
private static final String SMEV_INITIAL_REG_DATE = "smevInitialRegDate";
private Logger logger = Logger.getLogger(getClass().getName());
private static Map<String, String> PERSON_DOCUMENT_ID_MAP;
private static Map<String, String> EXPORT_ENTITY_SCHEMA_MAP;
static {
PERSON_DOCUMENT_ID_MAP = new HashMap<String, String>();
PERSON_DOCUMENT_ID_MAP.put("01", "payerPersonDocumentID2");
PERSON_DOCUMENT_ID_MAP.put("02", "payerPersonDocumentID3");
PERSON_DOCUMENT_ID_MAP.put("03", "payerPersonDocumentID4");
PERSON_DOCUMENT_ID_MAP.put("04", "payerPersonDocumentID5");
PERSON_DOCUMENT_ID_MAP.put("05", "payerPersonDocumentID6");
PERSON_DOCUMENT_ID_MAP.put("06", "payerPersonDocumentID7");
PERSON_DOCUMENT_ID_MAP.put("07", "payerPersonDocumentID8");
PERSON_DOCUMENT_ID_MAP.put("08", "payerPersonDocumentID9");
PERSON_DOCUMENT_ID_MAP.put("09", "payerPersonDocumentID10");
PERSON_DOCUMENT_ID_MAP.put("10", "payerPersonDocumentID11");
PERSON_DOCUMENT_ID_MAP.put("11", "payerPersonDocumentID12");
PERSON_DOCUMENT_ID_MAP.put("12", "payerPersonDocumentID13");
PERSON_DOCUMENT_ID_MAP.put("13", "payerPersonDocumentID14");
PERSON_DOCUMENT_ID_MAP.put("21", "payerPersonDocumentID15");
PERSON_DOCUMENT_ID_MAP.put("22", "payerPersonDocumentID16");
PERSON_DOCUMENT_ID_MAP.put("23", "payerPersonDocumentID17");
PERSON_DOCUMENT_ID_MAP.put("24", "payerPersonDocumentID18");
EXPORT_ENTITY_SCHEMA_MAP = new HashMap<String, String>();
EXPORT_ENTITY_SCHEMA_MAP.put("QUITTANCE", "http://roskazna.ru/xsd/ExportQuittanceResponse");
EXPORT_ENTITY_SCHEMA_MAP.put("CHARGE", "http://roskazna.ru/xsd/PGU_ChargesResponse");
EXPORT_ENTITY_SCHEMA_MAP.put("CHARGESTATUS", "http://roskazna.ru/xsd/PGU_ChargesResponse");
EXPORT_ENTITY_SCHEMA_MAP.put("CHARGENOTFULLMATCHED", "http://roskazna.ru/xsd/PGU_ChargesResponse");
EXPORT_ENTITY_SCHEMA_MAP.put("PAYMENT", "http://roskazna.ru/xsd/ExportPaymentsResponse");
EXPORT_ENTITY_SCHEMA_MAP.put("PAYMENTUNMATCHED", "http://roskazna.ru/xsd/ExportPaymentsResponse");
EXPORT_ENTITY_SCHEMA_MAP.put("PAYMENTMODIFIED", "http://roskazna.ru/xsd/ExportPaymentsResponse");
}
public Revision getRevision() {
return ru.codeinside.gws.api.Revision.rev111111;
}
public URL getWsdlUrl() {
return getClass().getClassLoader().getResource("gws3572/SmevUnifoService.wsdl");
}
public ClientRequest createClientRequest(ExchangeContext ctx) {
final String originRequestId = (String) ctx.getVariable("smevOriginRequestId");
final Packet packet = new Packet();
packet.recipient = new InfoSystem("RKZN35001", "Казначейство России");
InfoSystem pnzr8201 = new InfoSystem("8201", "Комплексная система предоставления государственных и муниципальных услуг Пензенской области");
packet.sender = packet.originator = pnzr8201;
packet.typeCode = Packet.Type.EXECUTION;
packet.date = new Date();
packet.exchangeType = "6"; // 1 - Запрос на оказание услуги
packet.originRequestIdRef = originRequestId;
packet.testMsg = (String) ctx.getVariable("smevTest");
final ClientRequest request = new ClientRequest();
BigInteger caseNumber = generateCaseNumber();
packet.caseNumber = caseNumber.toString();
ctx.setVariable(SMEV_INITIAL_REG_NUMBER, caseNumber);
ctx.setVariable(SMEV_INITIAL_REG_DATE, new Date());
request.packet = packet;
request.action = new QName("http://roskazna.ru/SmevUnifoService/", "UnifoTransferMsg");
packet.status = Packet.Status.REQUEST;
try {
String typeOperation = getStringFromContext(ctx, "operationType", "");
if (IMPORT_CHARGE_OPERATION.equals(typeOperation)) {
request.appData = createAppDataForImportChargeOperation(ctx);
} else if (EXPORT_OPERATION.equals(typeOperation)) {
request.appData = createAppDataForExportOperation(ctx);
} else if (IMPORT_PAYMENT_OPERATION.equals(typeOperation)) {
request.appData = createAppDataForImportPaymentOperation(ctx);
} else if (DO_ACKNOWLEDGMENT_OPERATION.equals(typeOperation)) {
request.appData = createAcknowledgmentRequest(ctx);
} else {
throw new IllegalArgumentException("Тип операции не верен");
}
} catch (Exception e) {
logger.log(Level.SEVERE, e.getMessage(), e);
throw new RuntimeException(e.getMessage(), e);
}
return request;
}
private String createAcknowledgmentRequest(ExchangeContext ctx) {
final DoAcknowledgmentRequestType acknowledgmentRequest = new DoAcknowledgmentRequestType();
String postBlockSenderIdentifier = getStringFromContext(ctx, "postBlockSenderIdentifier", "");
final PostBlock postBlock = createPostBlock(ctx, postBlockSenderIdentifier);
acknowledgmentRequest.setPostBlock(postBlock);
acknowledgmentRequest.setSupplierBillID(getStringFromContext(ctx, "SupplierBillID", ""));
long countPayments = (Long)ctx .getVariable("paymentBlock");
if (countPayments > 0l){
acknowledgmentRequest.setPayments(new DoAcknowledgmentRequestType.Payments());
for (long paymentIdx = 0; paymentIdx < countPayments; paymentIdx ++){
String paymentId = getStringFromContext(ctx, "paymentSystemId_" + (paymentIdx + 1), "");
acknowledgmentRequest.getPayments().getPaymentSystemIdentifier().add(paymentId);
}
}
return new XmlTypes(DoAcknowledgmentRequestType.class).toXml(acknowledgmentRequest);
}
private String createAppDataForImportPaymentOperation(ExchangeContext ctx) throws Exception {
ImportData importData = new ImportData();
final ImportRequest importRequest = new ImportRequest();
importData.setImportRequest(importRequest);
String postBlockSenderIdentifier = (String) ctx.getVariable("postBlockSenderIdentifier");
final PostBlock postBlock = createPostBlock(ctx, postBlockSenderIdentifier);
importRequest.setPostBlock(postBlock);
PaymentInfoType paymentInfo = new PaymentInfoType();
importRequest.setFinalPayment(paymentInfo);
paymentInfo.setNarrative(getStringFromContext(ctx, "paymentNarrative", ""));
paymentInfo.setSupplierBillID(getStringFromContext(ctx, "paymentSupplierBillID", ""));
paymentInfo.setAmount(toLong((String) ctx.getVariable("paymentAmount")));
paymentInfo.setPaymentDate(XmlTypes.date(formatDate((Date) ctx.getVariable("paymentDate"), "dd.MM.yyyy")));
paymentInfo.setChangeStatus(getStringFromContext(ctx, "paymentChangeStatus", "1"));
paymentInfo.setPayeeINN(getStringFromContext(ctx, "paymentPayeeINN", ""));
paymentInfo.setPayeeKPP(getStringFromContext(ctx, "paymentPayeeKPP", ""));
paymentInfo.setKBK(getStringFromContext(ctx, "paymentKBK", ""));
paymentInfo.setOKATO(getStringFromContext(ctx, "paymentOKATO", ""));
paymentInfo.setPayerPA(getStringFromContext(ctx, "paymentPA", ""));
Account payeeBankAcc = new Account();
paymentInfo.setPayeeBankAcc(payeeBankAcc);
payeeBankAcc.setAccount(getStringFromContext(ctx, "paymentPayeeAccount", ""));
payeeBankAcc.setKind(getStringFromContext(ctx, "paymentPayeeBankAccKind", "!"));
Bank payeeBank = new Bank();
payeeBankAcc.setBank(payeeBank);
payeeBank.setName(getStringFromContext(ctx, "paymentPayeeBankName", ""));
payeeBank.setCorrespondentBankAccount(getStringFromContext(ctx, "paymentCorrespondentBankAccount", ""));
payeeBank.setBIK(getStringFromContext(ctx, "paymentPayeeBankBIK", ""));
PaymentIdentificationDataType paymentIdentificationData = new PaymentIdentificationDataType();
paymentInfo.setPaymentIdentificationData(paymentIdentificationData);
Bank bank = new Bank();
paymentIdentificationData.setBank(bank);
bank.setBIK(getStringFromContext(ctx, "paymentBIK", ""));
bank.setName(getStringFromContext(ctx, "paymentBankName", ""));
paymentIdentificationData.setSystemIdentifier(buildSystemIdentifierForImportPaymentOperation(ctx));
fillPaymentAdditionalData(paymentInfo, ctx);
final BudgetIndex budgetIndex = new BudgetIndex();
paymentInfo.setBudgetIndex(budgetIndex);
budgetIndex.setStatus(getStringFromContext(ctx, "Status", "0" )); //Статус плательщика
budgetIndex.setPaymentType(getStringFromContext(ctx, "PaymentType", "0" )); // тип платежа
budgetIndex.setPurpose(getStringFromContext(ctx, "Purpose", "0" )); // основание платежа 2 символа максимум
budgetIndex.setTaxPeriod(getStringFromContext(ctx, "TaxPeriod", "0" )); // налоговый период до 10 символов
budgetIndex.setTaxDocNumber(getStringFromContext(ctx, "TaxDocNumber", "0" )); // Показатель номера документа
budgetIndex.setTaxDocDate(getStringFromContext(ctx, "TaxDocDate", "0" )); // Показатель даты документа
paymentInfo.setPayerIdentifier(buildUnifiedPayerID(ctx, ""));
String importDataStr = new XmlTypes(ImportData.class).toXml(importData);
return cryptoProvider.signElement(importDataStr, "FinalPayment", null, true, true, false);
}
private String buildSystemIdentifierForImportPaymentOperation(ExchangeContext ctx) {
String bik = getStringFromContext(ctx, "paymentBIK", "");
Long branchId = (Long)ctx.getVariable( "paymentBankBranch");
Date paymentDate = (Date)ctx.getVariable("paymentDate");
if (ctx.getVariable("paymentId") == null) {
throw new RuntimeException("Уникальный номер платежа внутри отделения в теч. дня должен быть заполнен");
}
Long paymentId = (Long)ctx.getVariable("paymentId");
String branchPart = leftPad(branchId.toString(), 6, '0');
String datePaymentPart = new SimpleDateFormat("yyMMdd").format(paymentDate);
String paymentIdPart = leftPad(paymentId.toString(), 10, '0');
return "1" + bik + branchPart + datePaymentPart + paymentIdPart;
}
String leftPad(String sourceString, int expectedLength, char fillChar) {
String strForPad = "";
if (sourceString.length() < expectedLength) {
for(int idx = 0; idx < expectedLength - sourceString.length(); idx++){
strForPad += fillChar;
}
}
return strForPad + sourceString;
}
private void fillPaymentAdditionalData(PaymentInfoType paymentInfo, ExchangeContext ctx) {
Long valuesCount = (Long)ctx.getVariable("payeeAddDataBlock");
for (long idx = 0; idx < valuesCount; idx++) {
PaymentType.AdditionalData additionalData = new PaymentType.AdditionalData();
additionalData.setName(getStringFromContext(ctx, "payeeAddDataKey_"+ (idx +1), "" ));
additionalData.setValue(getStringFromContext(ctx, "payeeAddDataValue_" + (idx +1), "" ));
paymentInfo.getAdditionalData().add(additionalData);
}
}
String createAppDataForExportOperation(ExchangeContext ctx) {
ExportData exportData = new ExportData();
DataRequest dataRequest = new DataRequest();
Date startDate = (Date) ctx.getVariable("startDate");
if (startDate != null) {
dataRequest.setStartDate(XmlTypes.dateTimeAndZeroMilliseconds(formatDate(startDate, "dd.MM.yyyy HH:mm:ss")));
}
Date endDate = (Date) ctx.getVariable("endDate");
if (endDate != null) {
dataRequest.setEndDate(XmlTypes.dateTimeAndZeroMilliseconds(formatDate(endDate, "dd.MM.yyyy HH:mm:ss")));
}
exportData.setDataRequest(dataRequest);
dataRequest.setKind((String) ctx.getVariable("exportRequestType"));
String postBlockSenderIdentifier = (String) ctx.getVariable("postBlockSenderIdentifier");
final PostBlock postBlock = createPostBlock(ctx, postBlockSenderIdentifier);
dataRequest.setPostBlock(postBlock);
fillSupplierBillIds(ctx, dataRequest);
fillApplicationIds(ctx, dataRequest);
fillUnifiedPayerIds(ctx, dataRequest);
return new XmlTypes(ExportData.class).toXml(exportData);
}
private void fillUnifiedPayerIds(ExchangeContext ctx, DataRequest dataRequest) {
if (ctx.getVariable("payerIdBlock") == null) return;
Long countPayers = (Long) ctx.getVariable("payerIdBlock");
if (countPayers > 0) {
DataRequest.Payers payers = new DataRequest.Payers();
dataRequest.setPayers(payers);
for (int idx = 0; idx < countPayers; idx++) {
payers.getPayerIdentifier().add(buildUnifiedPayerID(ctx, "_" + (idx + 1)));
}
}
}
private void fillApplicationIds(ExchangeContext ctx, DataRequest dataRequest) {
if (ctx.getVariable("ApplicationIdBlock") == null) return;
Long countApplicationIds = (Long) ctx.getVariable("ApplicationIdBlock");
if (countApplicationIds > 0) {
DataRequest.ApplicationIDs applicationIDs = new DataRequest.ApplicationIDs();
dataRequest.setApplicationIDs(applicationIDs);
for (int idx = 0; idx < countApplicationIds; idx++) {
Object supplierBillID = ctx.getVariable("ApplicationId_" + (idx + 1));
if (supplierBillID != null)
applicationIDs.getApplicationID().add((String) supplierBillID);
}
}
}
private void fillSupplierBillIds(ExchangeContext ctx, DataRequest dataRequest) {
if (ctx.getVariable("SupplierBillIDBlock") == null) return;
Long countSupplierBillIds = (Long) ctx.getVariable("SupplierBillIDBlock");
if (countSupplierBillIds > 0) {
DataRequest.SupplierBillIDs supplierBillIDs = new DataRequest.SupplierBillIDs();
dataRequest.setSupplierBillIDs(supplierBillIDs);
for (int idx = 0; idx < countSupplierBillIds; idx++) {
Object supplierBillID = ctx.getVariable("SupplierBillID_" + (idx + 1));
if (supplierBillID != null)
supplierBillIDs.getSupplierBillID().add((String) supplierBillID);
}
}
}
String createAppDataForImportChargeOperation(ExchangeContext ctx) throws Exception {
ImportData importData = new ImportData();
final ImportRequest importRequest = new ImportRequest();
String postBlockSenderIdentifier = (String) ctx.getVariable("postBlockSenderIdentifier");
final PostBlock postBlock = createPostBlock(ctx, postBlockSenderIdentifier);
importRequest.setPostBlock(postBlock);
final ChargeType charge = new ChargeType();
importRequest.setCharge(charge);
String ordinalNumber = (String) ctx.getVariable("ordinalNumber");
if (ordinalNumber == null || "".equals(ordinalNumber)) {
ordinalNumber = formatDate(new Date(), "ddMMyyHHmmss");
}
String supplierBillID = UINGenerator.generateChargeUIN(postBlockSenderIdentifier, ordinalNumber);
ctx.setVariable("supplierBillID", supplierBillID);
charge.setSupplierBillID(supplierBillID); // Уникальный идентификатор счёта в ИСП
charge.setBillDate(XmlTypes.date(formatDate((Date) ctx.getVariable("chargeBillDate"), "dd.MM.yyyy"))); //Дата выставления счёта
final Organization supplierOrgInfo = new Organization();
supplierOrgInfo.setName((String) ctx.getVariable("supplierOrgInfoName"));
supplierOrgInfo.setINN((String) ctx.getVariable("supplierOrgInfoINN"));
supplierOrgInfo.setKPP((String) ctx.getVariable("supplierOrgInfoKPP"));
final Account account = new Account();
account.setAccount((String) ctx.getVariable("accountAccount"));
account.setKind((String) ctx.getVariable("accountKind"));
final Bank bank = new Bank();
bank.setBIK((String) ctx.getVariable("bankBIK"));
bank.setName((String) ctx.getVariable("bankName"));
account.setBank(bank);
supplierOrgInfo.setAccount(account);
charge.setSupplierOrgInfo(supplierOrgInfo);
charge.setBillFor((String) ctx.getVariable("chargeBillFor"));
charge.setTotalAmount(toLong((String) ctx.getVariable("chargeTotalAmount")));
charge.setChangeStatus((String) ctx.getVariable("chargeChangeStatus")); /* Статус счёта 1 - новый 2 - изменение 3 - аннулирование */
charge.setTreasureBranch((String) ctx.getVariable("chargeTreasureBranch")); // Орган ФК, на счёт которого должны поступать средства плательщика
charge.setKBK((String) ctx.getVariable("chargeKBK"));
charge.setOKATO((String) ctx.getVariable("chargeOKATO"));
final BudgetIndex budgetIndex = new BudgetIndex();
budgetIndex.setStatus((String) ctx.getVariable("budgetIndexStatus")); //Статус плательщика
budgetIndex.setPaymentType((String) ctx.getVariable("budgetPaymentType")); // тип платежа
budgetIndex.setPurpose((String) ctx.getVariable("budgetPurpose")); // основание платежа 2 символа максимум
budgetIndex.setTaxPeriod((String) ctx.getVariable("budgetTaxPeriod")); // налоговый период до 10 символов
budgetIndex.setTaxDocNumber((String) ctx.getVariable("budgetTaxDocNumber")); // Показатель номера документа
budgetIndex.setTaxDocDate((String) ctx.getVariable("budgetTaxDocDate")); // Показатель даты документа
charge.setBudgetIndex(budgetIndex);
if ("".equals(getStringFromContext(ctx, "chargeApplicationID", ""))) {
String applicationID = String.valueOf(System.currentTimeMillis());
ctx.setVariable("chargeApplicationID", applicationID);
charge.setApplicationID(applicationID);
} else {
charge.setApplicationID((String) ctx.getVariable("chargeApplicationID"));
}
String unifiedPayerIdentifier = buildUnifiedPayerID(ctx, "");
ctx.setVariable("unifiedPayerIdentifier", unifiedPayerIdentifier);
charge.setUnifiedPayerIdentifier(unifiedPayerIdentifier); // единый идентификатор плательщика
importData.setImportRequest(importRequest);
String importDataStr = new XmlTypes(ImportData.class).toXml(importData);
return cryptoProvider.signElement(importDataStr, "Charge", null, true, true, false);
}
private PostBlock createPostBlock(ExchangeContext ctx, String postBlockSenderIdentifier) {
final PostBlock postBlock = new PostBlock();
String postBlockID = ctx.getVariable("postBlockId") == null ? UUID.randomUUID().toString() : (String) ctx.getVariable("postBlockId");
ctx.setVariable("postBlockId", postBlockID);
postBlock.setID(postBlockID); // идентификатор запроса
postBlock.setSenderIdentifier(postBlockSenderIdentifier);
Date postBlockTimeStamp = ctx.getVariable("postBlockTimeStamp") != null ? (Date) ctx.getVariable("postBlockTimeStamp") : new Date();
postBlock.setTimeStamp(XmlTypes.dateTimeAndZeroMilliseconds(formatDate(postBlockTimeStamp, "dd.MM.yyyy HH:mm:ss"))); //дата составления запроса
return postBlock;
}
String buildUnifiedPayerID(ExchangeContext ctx, String suffix) {
String payerType = getStringFromContext(ctx, "payerType" + suffix, "");
String citizenship = getStringFromContext(ctx, "payerPersonCitizenshipID" + suffix, "");
if ("1".equals(payerType)) { // ФЛ СНИЛС
String snilsNumber = getStringFromContext(ctx, "payerPersonDocumentID1" + suffix, "");
if (!snilsNumber.matches("\\d{11}")) throw new IllegalArgumentException("СНИЛС должен состоять из 11 цифр");
return "1" + snilsNumber;
}
if ("2".equals(payerType)) { // ЮЛ резидент
String legalPersonKPP = getStringFromContext(ctx, "payerLegalKPP" + suffix, "");
String legalPersonINN = getStringFromContext(ctx, "payerLegalINN" + suffix, "");
if (!legalPersonINN.matches("\\d{10}")) throw new IllegalArgumentException("ИНН должен состоять из 10 цифр");
if (!legalPersonKPP.matches("\\d{9}")) throw new IllegalArgumentException("КПП должен состоять из 9 цифр");
return "2" + legalPersonINN + legalPersonKPP;
}
if ("3".equals(payerType)) { // ЮЛ не резидент
String legalPersonKPP = getStringFromContext(ctx, "payerLegalNonResidentKPP" + suffix, "");
String legalPersonINN = getStringFromContext(ctx, "payerLegalNonResidentINN" + suffix, "");
if (!legalPersonINN.matches("\\d{5}")) throw new IllegalArgumentException("КИО должен состоять из 5 цифр");
if (!legalPersonKPP.matches("\\d{9}")) throw new IllegalArgumentException("КПП должен состоять из 9 цифр");
return "3" + legalPersonINN + legalPersonKPP;
}
if (Arrays.asList("01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12", "13", "21", "22", "23", "24").contains(payerType)) {
String personDocumentID = getPersonDocumentId(ctx, suffix, payerType);
if (personDocumentID.length() < 20) {
personDocumentID = padding(20 - personDocumentID.length(), '0').concat(personDocumentID);
if (Arrays.asList("21", "22", "23", "24").contains(payerType)) {
return payerType + personDocumentID + "643";
} else {
if (!citizenship.matches("\\d{3}"))
throw new IllegalArgumentException("Неверно указан код страны, должно быть три цифры");
return payerType + personDocumentID + citizenship;
}
}
}
throw new IllegalArgumentException("Неверный тип плательщика " + payerType);
}
private String getPersonDocumentId(ExchangeContext ctx, String suffix, String payerType) {
String documentVarName = PERSON_DOCUMENT_ID_MAP.get(payerType);
documentVarName = documentVarName + suffix;
return getStringFromContext(ctx, documentVarName, "").replace("-", "").toUpperCase();
}
private String padding(int repeat, char padChar) throws IndexOutOfBoundsException {
if (repeat < 0) {
throw new IndexOutOfBoundsException("Cannot pad a negative amount: " + repeat);
}
final char[] buf = new char[repeat];
for (int i = 0; i < buf.length; i++) {
buf[i] = padChar;
}
return new String(buf);
}
private String getStringFromContext(ExchangeContext ctx, String varName, String defaultString) {
return ctx.getVariable(varName) == null ? defaultString : (String) ctx.getVariable(varName);
}
private String formatDate(Date dateForFormat, String format) {
return new SimpleDateFormat(format).format(dateForFormat);
}
private long toLong(String valueForConvert) {
Double dblValue = Double.parseDouble(valueForConvert.replace(',', '.'));
return new Double(dblValue * 100).longValue();
}
private BigInteger generateCaseNumber() {
BigInteger value = BigInteger.valueOf(new Date().getTime());
value = value.multiply(BigInteger.valueOf(100000));
long randomValue = Math.round(Math.random() * 100000.0);
return value.add(BigInteger.valueOf(randomValue));
}
public void processClientResponse(ClientResponse response, ExchangeContext context) {
try {
context.setVariable("smevPool", true); // сервис синхронный
if (response.verifyResult.error != null) {
context.setVariable("smevError", response.verifyResult.error);
context.setVariable("responseSuccess", false);
context.setVariable("smevPool", false);
context.setVariable("requestProcessResultErrorDescription", response.verifyResult.error);
} else if (new QName("http://roskazna.ru/SmevUnifoService/", "UnifoTransferMsg").equals(response.action)) {
processResponseWithFinalData(response, context);
} else {
context.setVariable("smevError", "Неизвестный ответ " + response.action);
}
} catch (Exception e) {
throw new RuntimeException(e.getMessage(), e);
}
}
private void processResponseWithFinalData(ClientResponse response, ExchangeContext context) throws Exception {
String typeOperation = getStringFromContext(context, "operationType", "");
if (IMPORT_CHARGE_OPERATION.equals(typeOperation)) {
processResponseOnImportChargeRequest(response, context);
} else if (EXPORT_OPERATION.equals(typeOperation)) {
processResponseOnExport(response, context);
} else if (IMPORT_PAYMENT_OPERATION.equals(typeOperation)) {
processResponseOnImportPayment(response, context);
} else if (DO_ACKNOWLEDGMENT_OPERATION.equals(typeOperation)){
processResponseOnAcknowledgmentOperation(response, context);
} else {
throw new IllegalArgumentException("Тип операции не верен");
}
}
private void processResponseOnAcknowledgmentOperation(ClientResponse response, ExchangeContext context) {
context.setVariable("smevPool", false);
DoAcknowledgmentResponseType acknowledgmentResponse = (DoAcknowledgmentResponseType) new XmlTypes(DoAcknowledgmentResponseType.class).toBean(response.appData.getFirstChild());
if (acknowledgmentResponse.getRequestProcessResult() != null) {
context.setVariable("responseSuccess", false);
String errorCode = acknowledgmentResponse.getRequestProcessResult().getErrorCode();
processInternalErrorService(context, errorCode);
context.setVariable("requestProcessResultErrorCode", errorCode);
context.setVariable("requestProcessResultErrorDescription", acknowledgmentResponse.getRequestProcessResult().getErrorDescription());
} else {
context.setVariable("responseSuccess", true);
fillAcknowledgmentQuinttancesToContext(context, acknowledgmentResponse.getQuittances().getQuittance());
}
}
private void fillAcknowledgmentQuinttancesToContext(ExchangeContext context, List<DoAcknowledgmentResponseType.Quittances.Quittance> quittanceList) {
context.setVariable("quittance", (long) quittanceList.size());
//context.setVariable("-quittance", "");
for (int idx = 0; idx < quittanceList.size(); idx++) {
int blockIndex = idx + 1;
DoAcknowledgmentResponseType.Quittances.Quittance quittance = quittanceList.get(idx);
context.setVariable("quittanceSupplierBillID_" + blockIndex, quittance.getSupplierBillID());
context.setVariable("quittancePayerIdentifier_" + blockIndex, quittance.getPayerIdentifier());
context.setVariable("quittanceBalance_" + blockIndex, quittance.getBalance());
context.setVariable("quittanceBillStatus_" + blockIndex, quittance.getBillStatus());
PaymentIdentificationDataType paymentIdentificationData = quittance.getPaymentIdentificationData();
if (paymentIdentificationData != null) {
context.setVariable("quittanceSystemIdentifier_" + blockIndex, paymentIdentificationData.getSystemIdentifier());
context.setVariable("quittanceBankBIK_" + blockIndex, paymentIdentificationData.getBank().getBIK());
context.setVariable("quittanceBankName_" + blockIndex, paymentIdentificationData.getBank().getName());
context.setVariable("quittanceBankCorrAccount_" + blockIndex, paymentIdentificationData.getBank().getCorrespondentBankAccount());
context.setVariable("quittanceBankSWIFT_" + blockIndex, paymentIdentificationData.getBank().getSWIFT());
} else {
PaymentIdentificationDataType incomeRowIdentificationData = quittance.getIncomeRowIdentificationData();
if (incomeRowIdentificationData != null) {
context.setVariable("quittanceUFKName_" + blockIndex, incomeRowIdentificationData.getUFK());
}
}
context.setVariable("quittanceApplicationId_" + blockIndex, quittance.getApplicationID());
context.setVariable("payeeINN_" + blockIndex, quittance.getPayeeINN());
context.setVariable("payeeKPP_" + blockIndex, quittance.getPayeeKPP());
context.setVariable("KBK_" + blockIndex, quittance.getKBK());
context.setVariable("OKATO_" + blockIndex, quittance.getOKATO());
}
}
private void processResponseOnImportPayment(ClientResponse response, ExchangeContext context) {
processResponseOnImportChargeRequest(response, context); // структура данных совпадает. Должно работать
}
private void processResponseOnExport(ClientResponse response, ExchangeContext context) throws Exception {
context.setVariable("smevPool", false);
String exportType = getStringFromContext(context, "exportRequestType", "");
addAdditionalXmlSchema(response, exportType);
ExportDataResponse exportDataResponse = (ExportDataResponse) new XmlTypes(ExportDataResponse.class).toBean(response.appData.getFirstChild());
if (exportDataResponse.getResponseTemplate().getRequestProcessResult() != null) {
context.setVariable("responseSuccess", false);
String errorCode = exportDataResponse.getResponseTemplate().getRequestProcessResult().getErrorCode();
processInternalErrorService(context, errorCode);
context.setVariable("requestProcessResultErrorCode", errorCode);
context.setVariable("requestProcessResultErrorDescription", exportDataResponse.getResponseTemplate().getRequestProcessResult().getErrorDescription());
} else {
context.setVariable("responseSuccess", true);
if ("QUITTANCE".equals(exportType)) {
processExportQuittanceResponse(context, exportDataResponse);
} else if (Arrays.asList("CHARGE", "CHARGESTATUS", "CHARGENOTFULLMATCHED").contains(exportType)) {
processExportChargeResponse(context, exportDataResponse);
} else if (Arrays.asList("PAYMENT", "PAYMENTMODIFIED", "PAYMENTUNMATCHED").contains(exportType)) {
processExportPaymentResponse(context, exportDataResponse);
} else {
throw new IllegalArgumentException("Unknown export type " + exportType);
}
}
}
private void processExportPaymentResponse(ExchangeContext ctx, ExportDataResponse exportDataResponse) throws Exception {
ExportPaymentsResponse exportResponse = (ExportPaymentsResponse) exportDataResponse.getResponseTemplate();
if (exportResponse.getPayments() != null) {
List<ExportPaymentsResponse.Payments.PaymentInfo> paymentInfoList = exportResponse.getPayments().getPaymentInfo();
ctx.setVariable("paymentBlock", (long) paymentInfoList.size());
int blockIndex = 0;
for (ExportPaymentsResponse.Payments.PaymentInfo paymentInfo : paymentInfoList){
blockIndex ++;
PaymentInfoType paymentType = (PaymentInfoType) parseEntity(paymentInfo.getPaymentData(), "http://roskazna.ru/xsd/PaymentInfo", "FinalPayment", PaymentInfoType.class);
ctx.setVariable("paymentNarrative" + "_" + blockIndex, paymentType.getNarrative());
ctx.setVariable("paymentSupplierBillID" + "_" + blockIndex, paymentType.getSupplierBillID());
ctx.setVariable("paymentAmount" + "_" + blockIndex, paymentType.getAmount());
ctx.setVariable("paymentDate" + "_" + blockIndex, paymentType.getPaymentDate().toGregorianCalendar().getTime());
ctx.setVariable("paymentChangeStatus" + "_" + blockIndex, paymentType.getChangeStatus());
ctx.setVariable("paymentPayeeINN" + "_" + blockIndex, paymentType.getPayeeINN());
ctx.setVariable("paymentPayeeKPP" + "_" + blockIndex, paymentType.getPayeeKPP());
ctx.setVariable("paymentKBK" + "_" + blockIndex, paymentType.getKBK());
ctx.setVariable("paymentOKATO" + "_" + blockIndex, paymentType.getOKATO());
ctx.setVariable("paymentPA" + "_" + blockIndex, paymentType.getPayerPA());
if (paymentType.getPayeeBankAcc() != null) {
ctx.setVariable("paymentPayeeAccount" + "_" + blockIndex, paymentType.getPayeeBankAcc().getAccount());
ctx.setVariable("paymentPayeeBankAccKind" + "_" + blockIndex, paymentType.getPayeeBankAcc().getKind());
ctx.setVariable("paymentPayeeBankName" + "_" + blockIndex, paymentType.getPayeeBankAcc().getBank().getName());
ctx.setVariable("paymentCorrespondentBankAccount" + "_" + blockIndex, paymentType.getPayeeBankAcc().getBank().getCorrespondentBankAccount());
ctx.setVariable("paymentPayeeBankBIK" + "_" + blockIndex, paymentType.getPayeeBankAcc().getBank().getBIK());
}
ctx.setVariable("Status" + "_" + blockIndex, paymentType.getBudgetIndex().getStatus());
ctx.setVariable("PaymentType" + "_" + blockIndex, paymentType.getBudgetIndex().getPaymentType());
ctx.setVariable("Purpose" + "_" + blockIndex, paymentType.getBudgetIndex().getPurpose());
ctx.setVariable("TaxPeriod" + "_" + blockIndex, paymentType.getBudgetIndex().getTaxPeriod());
ctx.setVariable("TaxDocNumber" + "_" + blockIndex, paymentType.getBudgetIndex().getTaxDocNumber());
ctx.setVariable("TaxDocDate" + "_" + blockIndex, paymentType.getBudgetIndex().getTaxDocDate());
ctx.setVariable("paymentSystemId" + "_" + blockIndex, paymentType.getPaymentIdentificationData().getSystemIdentifier());
ctx.setVariable("paymentBIK" + "_" + blockIndex, paymentType.getPaymentIdentificationData().getBank().getBIK());
ctx.setVariable("paymentBankName" + "_" + blockIndex, paymentType.getPaymentIdentificationData().getBank().getName());
ctx.setVariable("payerId" + "_" + blockIndex, paymentType.getPayerIdentifier());
}
} else {
ctx.setVariable("paymentBlock", 0l);
}
}
private void processExportChargeResponse(ExchangeContext context, ExportDataResponse exportDataResponse) throws Exception {
ExportChargesResponse exportResponse = (ExportChargesResponse) exportDataResponse.getResponseTemplate();
if (exportResponse.getCharges() != null) {
List<ExportChargesResponse.Charges.ChargeInfo> charges = exportResponse.getCharges().getChargeInfo();
context.setVariable("chargeBlock", (long) charges.size());
for (int idx = 0; idx < charges.size(); idx++) {
int blockIndex = idx + 1;
ExportChargesResponse.Charges.ChargeInfo chargeInfo = charges.get(idx);
context.setVariable("amountToPay_" + blockIndex, chargeInfo.getAmountToPay());
context.setVariable("quittanceWithPaymentStatus_" + blockIndex, chargeInfo.getQuittanceWithPaymentStatus());
context.setVariable("quittanceWithIncomeStatus_" + blockIndex, chargeInfo.getQuittanceWithIncomeStatus());
if (chargeInfo.getIsRevoked() != null) {
context.setVariable("isRevoked_" + blockIndex, chargeInfo.getIsRevoked().isValue());
if (chargeInfo.getIsRevoked().getDate() != null) {
context.setVariable("revokedDate_" + blockIndex, chargeInfo.getIsRevoked().getDate().toGregorianCalendar().getTime());
} else {
context.setVariable("revokedDate_" + blockIndex, null);
}
} else {
context.setVariable("revokedDate_" + blockIndex, null);
context.setVariable("isRevoked_" + blockIndex, false);
}
if (chargeInfo.getChargeData() != null) {
ChargeType charge = (ChargeType) parseEntity(chargeInfo.getChargeData(), "http://roskazna.ru/xsd/Charge", "Charge", ChargeType.class);
addChargeToContext(charge, context, blockIndex);
}
}
} else {
context.setVariable("chargeBlock", 0l);
}
}
private void addChargeToContext(ChargeType charge, ExchangeContext context, int blockIndex) {
context.setVariable("SupplierBillID_" + blockIndex, charge.getSupplierBillID());
context.setVariable("UnifiedPayerId_" + blockIndex, charge.getUnifiedPayerIdentifier());
context.setVariable("BillDate_" + blockIndex, charge.getBillDate().toGregorianCalendar().getTime());
context.setVariable("SupplierOrgInfoName_" + blockIndex, charge.getSupplierOrgInfo().getName());
context.setVariable("SupplierOrgInfoINN_" + blockIndex, charge.getSupplierOrgInfo().getINN());
context.setVariable("SupplierOrgInfoKPP_" + blockIndex, charge.getSupplierOrgInfo().getKPP());
context.setVariable("SupplierOrgAccountKind_" + blockIndex, charge.getSupplierOrgInfo().getAccount().getKind());
context.setVariable("SupplierOrgAccountNumber_" + blockIndex, charge.getSupplierOrgInfo().getAccount().getAccount());
context.setVariable("SupplierOrgAccountBankName_" + blockIndex, charge.getSupplierOrgInfo().getAccount().getBank().getName());
context.setVariable("SupplierOrgAccountBankBIK_" + blockIndex, charge.getSupplierOrgInfo().getAccount().getBank().getBIK());
context.setVariable("ChargeChangeStatus_" + blockIndex, charge.getChangeStatus());
context.setVariable("ChargeKBK_" + blockIndex, charge.getKBK());
context.setVariable("ChargeOKATO_" + blockIndex, charge.getOKATO());
context.setVariable("ChargeTreasureBranch_" + blockIndex, charge.getTreasureBranch());
context.setVariable("budgetStatus_" + blockIndex, charge.getBudgetIndex().getStatus());
context.setVariable("budgetPurpose_" + blockIndex, charge.getBudgetIndex().getPurpose());
context.setVariable("budgetPaymentType_" + blockIndex, charge.getBudgetIndex().getPaymentType());
context.setVariable("budgetTaxPeriod_" + blockIndex, charge.getBudgetIndex().getTaxPeriod());
context.setVariable("budgetTaxDocNumber_" + blockIndex, charge.getBudgetIndex().getTaxDocNumber());
context.setVariable("budgetTaxDocDate_" + blockIndex, charge.getBudgetIndex().getTaxDocDate());
context.setVariable("TotalAmount_" + blockIndex, charge.getTotalAmount());
if (charge.getAdditionalData() != null) {
context.setVariable("additionalData_" + blockIndex, (long)charge.getAdditionalData().size());
int additionalDataIdx = 0;
for (Bill.AdditionalData additionalData : charge.getAdditionalData()) {
additionalDataIdx++;
context.setVariable("additionalDataKey_" + blockIndex + "_" + additionalDataIdx, additionalData.getName());
context.setVariable("additionalDataValue_" + blockIndex + "_" + additionalDataIdx, additionalData.getValue());
}
}else {
context.setVariable("additionalData_" + blockIndex, 0l);
}
if (charge.getSupplierOrgInfo ().getAddresses() != null ) {
int addressIdx = 0;
context.setVariable("SupplierOrgAddress_" + blockIndex, (long)charge.getSupplierOrgInfo ().getAddresses().getAddress().size());
for (AddressType address : charge.getSupplierOrgInfo().getAddresses().getAddress()) {
addressIdx++;
context.setVariable("addressType_" + blockIndex + "_" + addressIdx, address.getKind());
context.setVariable("addressView_" + blockIndex + "_" + addressIdx, address.getView());
}
} else {
context.setVariable("SupplierOrgAddress_" + blockIndex, 0l);
}
if (charge.getSupplierOrgInfo().getContacts() != null) {
int contactIdx = 0;
context.setVariable("SupplierOrgContact_" + blockIndex, (long) charge.getSupplierOrgInfo().getContacts().getContact().size());
for (ContactInfoType contact : charge.getSupplierOrgInfo().getContacts().getContact()) {
contactIdx++;
context.setVariable("contactType_" + blockIndex + "_" + contactIdx, contact.getKind());
context.setVariable("contactValue_" + blockIndex + "_" + contactIdx, contact.getValue());
context.setVariable("contactComment_" + blockIndex + "_" + contactIdx, contact.getComment());
}
} else {
context.setVariable("SupplierOrgContact_" + blockIndex, 0l);
}
}
private Object parseEntity(byte[] chargeData, String namespaceURI, String qualifiedName, Class typeClass) throws Exception {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
DocumentBuilder documentBuilder = dbf.newDocumentBuilder();
InputSource is = new InputSource(new StringReader(new String(chargeData, "UTF-8")));
Document doc = documentBuilder.parse(is);
if ("".equals(doc.getDocumentElement().getNamespaceURI()) || doc.getDocumentElement().getNamespaceURI() == null){
Node renamedElement = doc.renameNode(doc.getDocumentElement(), namespaceURI, qualifiedName);
return new XmlTypes(typeClass).toBean(renamedElement);
} else {
return new XmlTypes(typeClass).toBean(doc.getDocumentElement());
}
}
private void processExportQuittanceResponse(ExchangeContext context, ExportDataResponse exportDataResponse) {
ExportQuittanceResponse exportQuittanceResponse = (ExportQuittanceResponse) exportDataResponse.getResponseTemplate();
List<ExportQuittanceResponse.Quittances.Quittance> quittanceList = exportQuittanceResponse.getQuittances() != null ? exportQuittanceResponse.getQuittances().getQuittance() : Arrays.<ExportQuittanceResponse.Quittances.Quittance>asList();
context.setVariable("quittance", (long) quittanceList.size());
//context.setVariable("-quittance", "");
for (int idx = 0; idx < quittanceList.size(); idx++) {
int blockIndex = idx + 1;
ExportQuittanceResponse.Quittances.Quittance quittance = quittanceList.get(idx);
context.setVariable("quittanceIsRevoked_" + blockIndex, quittance.isIsRevoked());
context.setVariable("quittanceSupplierBillID_" + blockIndex, quittance.getSupplierBillID());
context.setVariable("quittancePayerIdentifier_" + blockIndex, quittance.getPayerIdentifier());
context.setVariable("quittanceBalance_" + blockIndex, quittance.getBalance());
context.setVariable("quittanceBillStatus_" + blockIndex, quittance.getBillStatus());
PaymentIdentificationDataType paymentIdentificationData = quittance.getPaymentIdentificationData();
if (paymentIdentificationData != null) {
context.setVariable("quittanceSystemIdentifier_" + blockIndex, paymentIdentificationData.getSystemIdentifier());
context.setVariable("quittanceBankBIK_" + blockIndex, paymentIdentificationData.getBank().getBIK());
context.setVariable("quittanceBankName_" + blockIndex, paymentIdentificationData.getBank().getName());
context.setVariable("quittanceBankCorrAccount_" + blockIndex, paymentIdentificationData.getBank().getCorrespondentBankAccount());
context.setVariable("quittanceBankSWIFT_" + blockIndex, paymentIdentificationData.getBank().getSWIFT());
} else {
PaymentIdentificationDataType incomeRowIdentificationData = quittance.getIncomeRowIdentificationData();
if (incomeRowIdentificationData != null) {
context.setVariable("quittanceUFKName_" + blockIndex, incomeRowIdentificationData.getUFK());
}
}
context.setVariable("quittanceApplicationId_" + blockIndex, quittance.getApplicationID());
context.setVariable("payeeINN_" + blockIndex, quittance.getPayeeINN());
context.setVariable("payeeKPP_" + blockIndex, quittance.getPayeeKPP());
context.setVariable("KBK_" + blockIndex, quittance.getKBK());
context.setVariable("OKATO_" + blockIndex, quittance.getOKATO());
}
}
private void addAdditionalXmlSchema(ClientResponse response, String requestedEntity) {
if (response.appData.getElementsByTagNameNS(null, "ResponseTemplate").getLength() > 0) {
Node responseTemplateNode = response.appData.getElementsByTagNameNS("", "ResponseTemplate").item(0);
Node typeAttr = responseTemplateNode.getAttributes().getNamedItemNS("http://www.w3.org/2001/XMLSchema-instance", "type");
String attributeValue = typeAttr.getNodeValue();
String schemaURI = EXPORT_ENTITY_SCHEMA_MAP.get(requestedEntity);
response.appData.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:" + attributeValue.split(":")[0], schemaURI);
}
}
private void processResponseOnImportChargeRequest(ClientResponse response, ExchangeContext context) {
ImportDataResponse importDataResponse = (ImportDataResponse) new XmlTypes(ImportDataResponse.class).toBean(response.appData.getFirstChild());
if (importDataResponse == null) throw new IllegalStateException("Can't parse import data response");
Ticket ticket = importDataResponse.getTicket();
context.setVariable("ticketPostBlockID", ticket.getPostBlock().getID());
context.setVariable("ticketPostBlockSenderIdentifier", ticket.getPostBlock().getSenderIdentifier());
context.setVariable("ticketPostBlockTimeStamp", ticket.getPostBlock().getTimeStamp().toGregorianCalendar().getTime());
if (ticket.getRequestProcessResult() != null) {
String errorCode = ticket.getRequestProcessResult().getErrorCode();
context.setVariable("requestProcessResultErrorCode", errorCode);
context.setVariable("requestProcessResultErrorDescription", ticket.getRequestProcessResult().getErrorDescription());
context.setVariable("responseSuccess", false);
context.setVariable("smevPool", false);
processInternalErrorService(context, errorCode);
} else {
context.setVariable("responseSuccess", true);
context.setVariable("smevPool", false);
}
}
private void processInternalErrorService(ExchangeContext context, String errorCode) {
if ("EBPP5000".equals(errorCode)) {
int countRetries = context.getVariableNames().contains("countRetries") ? (Integer) context.getVariable("countRetries") : 0;
countRetries++;
context.setVariable("countRetries", countRetries);
context.setVariable("smevTimeOut", calcTimeOut(countRetries));
context.setVariable("smevPool", countRetries < 5);
}
}
private String calcTimeOut(int countRetries) {
if (countRetries == 1) return "PT30S";
else return "PT600S";
}
public void bindCryptoProvider(CryptoProvider cryptoProvider) {
this.cryptoProvider = cryptoProvider;
}
public void unbindCryptoProvider(CryptoProvider cryptoProvider) {
this.cryptoProvider = null;
}
}