From: elgekko Date: Wed, 4 Oct 2023 12:46:39 +0000 (+0200) Subject: NAV invoice detail query implemented, import-incoming-invoice workflow updated X-Git-Url: http://git.useribm.hu/?a=commitdiff_plain;h=a783e60bd80a481c5e298863c10f36c1fc788501;p=sly-crm.git NAV invoice detail query implemented, import-incoming-invoice workflow updated --- diff --git a/lis-app/src/test/java/hu/user/lis/workflow/TaxOfficeInvoiceApiIT.java b/lis-app/src/test/java/hu/user/lis/workflow/TaxOfficeInvoiceApiIT.java index a903d74..d78729e 100644 --- a/lis-app/src/test/java/hu/user/lis/workflow/TaxOfficeInvoiceApiIT.java +++ b/lis-app/src/test/java/hu/user/lis/workflow/TaxOfficeInvoiceApiIT.java @@ -5,9 +5,10 @@ package hu.user.lis.workflow; -import hu.gov.nav.schemas.osa._3_0.api.InvoiceDirectionType; -import hu.gov.nav.schemas.osa._3_0.api.QueryInvoiceDigestRequest; -import hu.gov.nav.schemas.osa._3_0.api.QueryInvoiceDigestResponse; +import hu.gov.nav.schemas.ntca._1_0.common.BasicResultType; +import hu.gov.nav.schemas.ntca._1_0.common.FunctionCodeType; +import hu.gov.nav.schemas.osa._3_0.api.*; +import hu.gov.nav.schemas.osa._3_0.data.InvoiceData; import hu.user.lis.service.nav.TaxOfficeInvoiceService; import hu.user.lis.service.nav.TaxOfficeRequestBuilder; import hu.user.lis.service.nav.TaxOfficeXmlConverter; @@ -37,6 +38,7 @@ import java.nio.charset.StandardCharsets; import java.time.Duration; import java.time.ZonedDateTime; import java.util.Collections; +import java.util.List; import java.util.Optional; import java.util.concurrent.TimeUnit; @@ -144,8 +146,40 @@ public class TaxOfficeInvoiceApiIT { @Test public void testWithConnector() throws Exception { - Optional response = taxOfficeInvoiceService.queryInboundInvoices(1); - response.ifPresent(queryInvoiceDigestResponse -> log.info("Response: {}", taxOfficeXmlConverter.toXml(queryInvoiceDigestResponse))); + int availablePages = 1; + int currentPage = 1; + while (currentPage <= availablePages) { + Optional response = taxOfficeInvoiceService.queryInboundInvoices(currentPage); + if (!response.isPresent()) { + break; + } + + Optional functionCode = response + .map(QueryInvoiceDigestResponse::getResult) + .map(BasicResultType::getFuncCode); + + if (functionCode.isPresent() && FunctionCodeType.OK.equals(functionCode.get())) { + if (currentPage == 1) { + availablePages = response + .map(QueryInvoiceDigestResponse::getInvoiceDigestResult) + .map(InvoiceDigestResultType::getAvailablePage).orElse(0); + } + + Optional> invoiceList = response + .map(QueryInvoiceDigestResponse::getInvoiceDigestResult) + .map(InvoiceDigestResultType::getInvoiceDigest); + + if (invoiceList.isPresent()) { + for (InvoiceDigestType invoiceDigest : invoiceList.get()) { + String invoiceNumber = invoiceDigest.getInvoiceNumber(); + String supplierTaxNumber = invoiceDigest.getSupplierTaxNumber(); + Optional invoiceData = taxOfficeInvoiceService.queryInboundInvoiceData(invoiceNumber, supplierTaxNumber); + invoiceData.ifPresent(invoice -> log.info("Found invoice: {}", taxOfficeXmlConverter.toXml(invoice))); + } + } + } + currentPage++; + } } } \ No newline at end of file diff --git a/lis-service/src/main/java/hu/user/lis/service/nav/CustomRestTemplateConfiguration.java b/lis-service/src/main/java/hu/user/lis/service/nav/RestTemplateSSLConfiguration.java similarity index 97% rename from lis-service/src/main/java/hu/user/lis/service/nav/CustomRestTemplateConfiguration.java rename to lis-service/src/main/java/hu/user/lis/service/nav/RestTemplateSSLConfiguration.java index c7cb4c2..57aa73c 100644 --- a/lis-service/src/main/java/hu/user/lis/service/nav/CustomRestTemplateConfiguration.java +++ b/lis-service/src/main/java/hu/user/lis/service/nav/RestTemplateSSLConfiguration.java @@ -21,7 +21,7 @@ import java.security.NoSuchAlgorithmException; import java.security.cert.CertificateException; @Configuration -public class CustomRestTemplateConfiguration { +public class RestTemplateSSLConfiguration { @Value("${service.nav.trust.store}") private Resource trustStore; diff --git a/lis-service/src/main/java/hu/user/lis/service/nav/TaxOfficeInvoiceService.java b/lis-service/src/main/java/hu/user/lis/service/nav/TaxOfficeInvoiceService.java index 8396737..2aab0f7 100644 --- a/lis-service/src/main/java/hu/user/lis/service/nav/TaxOfficeInvoiceService.java +++ b/lis-service/src/main/java/hu/user/lis/service/nav/TaxOfficeInvoiceService.java @@ -1,18 +1,21 @@ package hu.user.lis.service.nav; -import hu.gov.nav.schemas.osa._3_0.api.InvoiceDirectionType; -import hu.gov.nav.schemas.osa._3_0.api.QueryInvoiceDigestRequest; -import hu.gov.nav.schemas.osa._3_0.api.QueryInvoiceDigestResponse; +import hu.gov.nav.schemas.osa._3_0.api.*; +import hu.gov.nav.schemas.osa._3_0.data.InvoiceData; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.web.reactive.function.client.WebClient; import reactor.core.publisher.Mono; +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; import java.util.Optional; +import java.util.zip.GZIPInputStream; @Service public class TaxOfficeInvoiceService { - @Autowired TaxOfficeRequestBuilder taxOfficeRequestBuilder; @@ -22,16 +25,64 @@ public class TaxOfficeInvoiceService { @Autowired TaxOfficeConnector taxOfficeConnector; + private String decompress(byte[] bytes) throws Exception { + final StringBuilder builder = new StringBuilder(); + try (GZIPInputStream gis = new GZIPInputStream(new ByteArrayInputStream(bytes)); + BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(gis, StandardCharsets.UTF_8))) { + String line; + while ((line = bufferedReader.readLine()) != null) { + builder.append(line); + } + } + return builder.toString(); + } + public Optional queryInboundInvoices(int page) throws Exception { - QueryInvoiceDigestRequest queryRequest = taxOfficeRequestBuilder.requestInvoiceDigest(); - queryRequest.setPage(page); - queryRequest.setInvoiceDirection(InvoiceDirectionType.INBOUND); - queryRequest.setInvoiceQueryParams(taxOfficeRequestBuilder.params()); + QueryInvoiceDigestRequest request = taxOfficeRequestBuilder.requestInvoiceDigest(); + request.setPage(page); + request.setInvoiceDirection(InvoiceDirectionType.INBOUND); + request.setInvoiceQueryParams(taxOfficeRequestBuilder.params()); WebClient.RequestBodySpec bodySpec = taxOfficeConnector.getClient().post().uri("/queryInvoiceDigest"); - WebClient.RequestHeadersSpec headersSpec = bodySpec.bodyValue(taxOfficeXmlConverter.toXml(queryRequest)); + WebClient.RequestHeadersSpec headersSpec = bodySpec.bodyValue(taxOfficeXmlConverter.toXml(request)); Mono responseMono = headersSpec.retrieve().bodyToMono(String.class); return taxOfficeXmlConverter.fromXml(responseMono.block(), QueryInvoiceDigestResponse.class); } + public Optional queryInboundInvoiceData(String invoiceNumber, String supplierTaxNumber) throws Exception { + InvoiceNumberQueryType query = new InvoiceNumberQueryType(); + query.setInvoiceDirection(InvoiceDirectionType.INBOUND); + query.setInvoiceNumber(invoiceNumber); + query.setSupplierTaxNumber(supplierTaxNumber); + + QueryInvoiceDataRequest queryRequest = taxOfficeRequestBuilder.requestInvoiceData(); + queryRequest.setInvoiceNumberQuery(query); + + WebClient.RequestBodySpec bodySpec = taxOfficeConnector.getClient().post().uri("/queryInvoiceData"); + WebClient.RequestHeadersSpec headersSpec = bodySpec.bodyValue(taxOfficeXmlConverter.toXml(queryRequest)); + Mono responseMono = headersSpec.retrieve().bodyToMono(String.class); + Optional response = taxOfficeXmlConverter.fromXml(responseMono.block(), QueryInvoiceDataResponse.class); +// invoiceData: A számla adatai BASE64 kódolásban +// compressedContentIndicator: Jelöli, ha az invoiceData tartalmát a BASE64 dekódolást követően még ki kell tömöríteni az olvasáshoz +// Base64 base64 = new Base64(); +// String decodedString = new String(base64.decode(invoiceBytes)); + byte[] invoiceBytes = response + .map(QueryInvoiceDataResponse::getInvoiceDataResult) + .map(InvoiceDataResultType::getInvoiceData) + .orElseThrow(NullPointerException::new); + + boolean isDataCompressed = response + .map(QueryInvoiceDataResponse::getInvoiceDataResult) + .map(InvoiceDataResultType::isCompressedContentIndicator) + .orElse(false); + + String invoiceData; + if (isDataCompressed) { + invoiceData = decompress(invoiceBytes); + } else { + invoiceData = new String(invoiceBytes); + } + return taxOfficeXmlConverter.fromXml(invoiceData, InvoiceData.class); + } + } diff --git a/lis-service/src/main/java/hu/user/lis/service/nav/TaxOfficeRequestBuilder.java b/lis-service/src/main/java/hu/user/lis/service/nav/TaxOfficeRequestBuilder.java index 6da2b39..120870f 100644 --- a/lis-service/src/main/java/hu/user/lis/service/nav/TaxOfficeRequestBuilder.java +++ b/lis-service/src/main/java/hu/user/lis/service/nav/TaxOfficeRequestBuilder.java @@ -132,18 +132,18 @@ public class TaxOfficeRequestBuilder { Az így és sorrendben konkatenált string nagybetűs SHA3-512 hash eredménye lesz a requestSignature értéke. */ - private void calculateSimpleRequestSignature(QueryInvoiceDigestRequest request) { - ZonedDateTime zdt = request.getHeader().getTimestamp().toGregorianCalendar().toZonedDateTime(); + private void calculateSimpleRequestSignature(BasicHeaderType header, UserHeaderType user) { + ZonedDateTime zdt = header.getTimestamp().toGregorianCalendar().toZonedDateTime(); ZonedDateTime zdtUTC = zdt.withZoneSameInstant(ZoneOffset.UTC); - String rsSignature = request.getHeader().getRequestId() + + String rsSignature = header.getRequestId() + DATE_TIME_FORMATTER.format(zdtUTC) + signKey; CryptoType reqCryptoType = new CryptoType(); reqCryptoType.setCryptoType("SHA3-512"); reqCryptoType.setValue(sha3_512Hex(rsSignature).toUpperCase()); - request.getUser().setRequestSignature(reqCryptoType); + user.setRequestSignature(reqCryptoType); } /* Java 9 fölött már támogatott 3rd party nélkül is*/ @@ -158,8 +158,16 @@ public class TaxOfficeRequestBuilder { result.setHeader(header()); result.setUser(user()); result.setSoftware(software()); - calculateSimpleRequestSignature(result); + calculateSimpleRequestSignature(result.getHeader(), result.getUser()); return result; } + public QueryInvoiceDataRequest requestInvoiceData() throws DatatypeConfigurationException { + QueryInvoiceDataRequest result = new QueryInvoiceDataRequest(); + result.setHeader(header()); + result.setUser(user()); + result.setSoftware(software()); + calculateSimpleRequestSignature(result.getHeader(), result.getUser()); + return result; + } } diff --git a/lis-workflow/src/main/java/hu/user/lis/workflow/invoice/DownloadInvoiceData.java b/lis-workflow/src/main/java/hu/user/lis/workflow/invoice/DownloadInvoiceData.java index 3a52917..ee5ed39 100644 --- a/lis-workflow/src/main/java/hu/user/lis/workflow/invoice/DownloadInvoiceData.java +++ b/lis-workflow/src/main/java/hu/user/lis/workflow/invoice/DownloadInvoiceData.java @@ -10,7 +10,6 @@ import org.camunda.bpm.engine.delegate.JavaDelegate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import java.nio.file.Paths; import java.util.Optional; @Log4j2 @@ -18,20 +17,30 @@ import java.util.Optional; public class DownloadInvoiceData implements JavaDelegate { @Autowired - PartnerRepository partnerRepository; + private PartnerRepository partnerRepository; @Autowired - IncomingInvoiceFetcherService incomingInvoiceFetcherService; + private IncomingInvoiceFetcherService incomingInvoiceFetcherService; + +// @Override +// public void execute(DelegateExecution delegateExecution) throws Exception { +// String invoiceId = (String) delegateExecution.getVariable("invoice"); +// log.info("Processing invoice {}", invoiceId); +// IncomingInvoice invoice = incomingInvoiceFetcherService.getInvoiceFromPath(Paths.get(invoiceId)); +// Optional partnerEntity = partnerRepository.findByVatNr(invoice.getPartner().getVatNr()); +// partnerEntity.ifPresent(invoice::setPartner); +// delegateExecution.setVariableLocal("invoiceEntity", invoice); +// log.info("Invoice {} processed", invoiceId); +// } @Override public void execute(DelegateExecution delegateExecution) throws Exception { - String invoiceId = (String) delegateExecution.getVariable("invoice"); - log.info("Processing invoice {}", invoiceId); - IncomingInvoice invoice = incomingInvoiceFetcherService.getInvoiceFromPath(Paths.get(invoiceId)); + String invoiceXml = (String) delegateExecution.getVariable("invoice"); + log.info("Processing invoice {}", invoiceXml); + IncomingInvoice invoice = incomingInvoiceFetcherService.getInvoiceDataOnline(invoiceXml); Optional partnerEntity = partnerRepository.findByVatNr(invoice.getPartner().getVatNr()); partnerEntity.ifPresent(invoice::setPartner); delegateExecution.setVariableLocal("invoiceEntity", invoice); - log.info("Invoice {} processed", invoiceId); + log.info("Invoice {} processed", invoiceXml); } - } diff --git a/lis-workflow/src/main/java/hu/user/lis/workflow/invoice/ListNewInvoices.java b/lis-workflow/src/main/java/hu/user/lis/workflow/invoice/ListNewInvoices.java index 3f98033..84b8ce6 100644 --- a/lis-workflow/src/main/java/hu/user/lis/workflow/invoice/ListNewInvoices.java +++ b/lis-workflow/src/main/java/hu/user/lis/workflow/invoice/ListNewInvoices.java @@ -1,31 +1,37 @@ package hu.user.lis.workflow.invoice; import hu.user.lis.workflow.invoice.service.IncomingInvoiceFetcherService; -import hu.user.lis.workflow.properties.WorkflowProperties; import lombok.extern.log4j.Log4j2; import org.camunda.bpm.engine.delegate.DelegateExecution; import org.camunda.bpm.engine.delegate.JavaDelegate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import java.nio.file.Path; -import java.nio.file.Paths; import java.util.List; @Log4j2 @Component public class ListNewInvoices implements JavaDelegate { - @Autowired - WorkflowProperties workflowProperties; +// @Autowired +// private WorkflowProperties workflowProperties; @Autowired - IncomingInvoiceFetcherService incomingInvoiceFetcherService; + private IncomingInvoiceFetcherService incomingInvoiceFetcherService; + +// @Override +// public void execute(DelegateExecution delegateExecution) throws Exception { +// log.info("Executing"); +// Path inputPath = Paths.get(workflowProperties.getImportInvoice().getInputPath()); +// List invoices = incomingInvoiceFetcherService.getNewInvoicesFromPath(inputPath); +// +// delegateExecution.setVariableLocal("invoices", invoices); +// } @Override public void execute(DelegateExecution delegateExecution) throws Exception { log.info("Executing"); - Path inputPath = Paths.get(workflowProperties.getImportInvoice().getInputPath()); - List invoices = incomingInvoiceFetcherService.getNewInvoicesFromPath(inputPath); + List invoices = incomingInvoiceFetcherService.getNewInvoicesOnline(); delegateExecution.setVariableLocal("invoices", invoices); } + } diff --git a/lis-workflow/src/main/java/hu/user/lis/workflow/invoice/service/IncomingInvoiceFetcherService.java b/lis-workflow/src/main/java/hu/user/lis/workflow/invoice/service/IncomingInvoiceFetcherService.java index 5be2e00..20aa9c4 100644 --- a/lis-workflow/src/main/java/hu/user/lis/workflow/invoice/service/IncomingInvoiceFetcherService.java +++ b/lis-workflow/src/main/java/hu/user/lis/workflow/invoice/service/IncomingInvoiceFetcherService.java @@ -1,11 +1,19 @@ package hu.user.lis.workflow.invoice.service; +import hu.gov.nav.schemas.ntca._1_0.common.BasicResultType; +import hu.gov.nav.schemas.ntca._1_0.common.FunctionCodeType; +import hu.gov.nav.schemas.osa._3_0.api.InvoiceDigestResultType; +import hu.gov.nav.schemas.osa._3_0.api.InvoiceDigestType; +import hu.gov.nav.schemas.osa._3_0.api.QueryInvoiceDigestResponse; +import hu.gov.nav.schemas.osa._3_0.data.InvoiceData; import hu.user.lis.db.Currency; import hu.user.lis.db.IncomingInvoice; import hu.user.lis.db.Partner; import hu.user.lis.db.repository.PartnerRepository; import hu.user.lis.service.data.DataGeneratorService; import hu.user.lis.service.nav.TaxOfficeDataConverter; +import hu.user.lis.service.nav.TaxOfficeInvoiceService; +import hu.user.lis.service.nav.TaxOfficeXmlConverter; import org.apache.commons.lang3.RandomUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -15,9 +23,7 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.text.SimpleDateFormat; -import java.util.Arrays; -import java.util.Date; -import java.util.List; +import java.util.*; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -35,6 +41,12 @@ public class IncomingInvoiceFetcherService { @Autowired private TaxOfficeDataConverter taxOfficeDataConverter; + @Autowired + private TaxOfficeInvoiceService taxOfficeInvoiceService; + + @Autowired + private TaxOfficeXmlConverter taxOfficeXmlConverter; + public List getNewInvoices() { return Arrays.asList("Invoice-test-1", "Invoice-test-2", "Invoice-test-3"); } @@ -89,4 +101,54 @@ public class IncomingInvoiceFetcherService { List partners = partnerRepository.findAll(); return partners.get(RandomUtils.nextInt(0, partners.size())); } + + public IncomingInvoice getInvoiceDataOnline(String invoiceDigestInfo) throws Exception { + String[] tokens = invoiceDigestInfo.split(","); + String invoiceNumber = tokens[0]; + String supplierTaxNumber = tokens[1]; + InvoiceData invoiceData = taxOfficeInvoiceService.queryInboundInvoiceData(invoiceNumber, supplierTaxNumber).orElseThrow(NullPointerException::new); + String invoiceXml = taxOfficeXmlConverter.toXml(invoiceData); + IncomingInvoice result = taxOfficeDataConverter.getIncomingInvoice(invoiceXml); + Partner partner = taxOfficeDataConverter.getPartner(invoiceXml); + result.setPartner(partner); + return result; + } + + public List getNewInvoicesOnline() throws Exception { + List result = new ArrayList<>(); + int availablePages = 1; + int currentPage = 1; + while (currentPage <= availablePages) { + Optional response = taxOfficeInvoiceService.queryInboundInvoices(currentPage); + if (!response.isPresent()) { + break; + } + + Optional functionCode = response + .map(QueryInvoiceDigestResponse::getResult) + .map(BasicResultType::getFuncCode); + + if (functionCode.isPresent() && FunctionCodeType.OK.equals(functionCode.get())) { + if (currentPage == 1) { + availablePages = response + .map(QueryInvoiceDigestResponse::getInvoiceDigestResult) + .map(InvoiceDigestResultType::getAvailablePage).orElse(0); + } + + Optional> invoiceList = response + .map(QueryInvoiceDigestResponse::getInvoiceDigestResult) + .map(InvoiceDigestResultType::getInvoiceDigest); + + if (invoiceList.isPresent()) { + for (InvoiceDigestType invoiceDigest : invoiceList.get()) { + String invoiceNumber = invoiceDigest.getInvoiceNumber(); + String supplierTaxNumber = invoiceDigest.getSupplierTaxNumber(); + result.add(String.format("%s,%s", invoiceNumber, supplierTaxNumber)); + } + } + } + currentPage++; + } + return result; + } }