From 5bef3697aba662c04494639d5b5ee6fc7c23af04 Mon Sep 17 00:00:00 2001 From: Ralph Soika Date: Tue, 18 Jun 2024 16:35:57 +0200 Subject: [PATCH] fix invoice.rate --- .../api/CargosoftMigrationRestService.java | 48 +++- .../TestIMAPOutlookOAuth.java | 2 + .../TestIMAPOutlookOAuthDebug.java | 257 ++++++++++++++++++ 3 files changed, 302 insertions(+), 5 deletions(-) create mode 100644 office-alexander-logistics-app/src/test/java/com/alexanderlogistics/TestIMAPOutlookOAuthDebug.java diff --git a/office-alexander-logistics-app/src/main/java/com/alexanderlogistics/api/CargosoftMigrationRestService.java b/office-alexander-logistics-app/src/main/java/com/alexanderlogistics/api/CargosoftMigrationRestService.java index 264f1f8..7dc2717 100644 --- a/office-alexander-logistics-app/src/main/java/com/alexanderlogistics/api/CargosoftMigrationRestService.java +++ b/office-alexander-logistics-app/src/main/java/com/alexanderlogistics/api/CargosoftMigrationRestService.java @@ -67,6 +67,7 @@ import org.w3c.dom.Node; import org.xml.sax.InputSource; import org.xml.sax.SAXException; +import com.alexanderlogistics.InvoiceUtil; import com.alexanderlogistics.xml.CargosoftXMLInvoiceImportService; /** @@ -88,7 +89,10 @@ public class CargosoftMigrationRestService implements Serializable { String log = ""; int errors = 0; int count = 0; - public static String _QUERY = "($modelversion:rechnungsausgang-de-1.0)\n" + // + // public static String _QUERY = "($modelversion:rechnungsausgang-de-1.0)\n" + + // // + // "AND $created:[20240604 TO 20240619]"; + public static String _QUERY = "($modelversion:rechnungsausgang-dwc-1.0)\n" + // "AND $created:[20240604 TO 20240619]"; @Inject @@ -142,10 +146,7 @@ public class CargosoftMigrationRestService implements Serializable { * @throws ProcessingErrorException * @throws AccessDeniedException */ - @GET - @Path("/fix") - @Produces({ MediaType.TEXT_PLAIN }) - public String fixFehlerhafteCargosoftDaten() + public String fixMissingDueDate() throws QueryException, AccessDeniedException, ProcessingErrorException, PluginException, ModelException { logger.info("query=" + _QUERY); @@ -172,6 +173,43 @@ public class CargosoftMigrationRestService implements Serializable { return log; } + @GET + @Path("/fix") + @Produces({ MediaType.TEXT_PLAIN }) + public String fixMissingRate() + throws QueryException, AccessDeniedException, ProcessingErrorException, PluginException, ModelException { + + logger.info("query=" + _QUERY); + log = "Query\n\n" + _QUERY; + + List result = documentService.find(_QUERY, 9999, 0); + + log = log + "\n\nSelection Count=" + result.size(); + + log = log + "\n\nFixes\n\n"; + + for (ItemCollection workitem : result) { + + if (!workitem.hasItem("invoice.rate")) { + // Fetch frist datev.kurs von _childitems + + List childs = InvoiceUtil.explodeChildList(workitem); + if (childs != null && childs.size() > 0) { + ItemCollection child = childs.get(0); + double rate = child.getItemValueDouble("datev.kurs"); + logger.info("..fix missing rate = " + rate); + workitem.setItemValue("invoice.rate", rate); + // save only + documentService.save(workitem); + } + + } + } + + log = log + "\n\n=== Completed! " + count + " fixes! ===\n\n"; + return log; + } + public String fixFehlerhafteCargosoftDatenMitSnapshot() throws QueryException, AccessDeniedException, ProcessingErrorException, PluginException, ModelException { diff --git a/office-alexander-logistics-app/src/test/java/com/alexanderlogistics/TestIMAPOutlookOAuth.java b/office-alexander-logistics-app/src/test/java/com/alexanderlogistics/TestIMAPOutlookOAuth.java index 542da53..8be20fe 100644 --- a/office-alexander-logistics-app/src/test/java/com/alexanderlogistics/TestIMAPOutlookOAuth.java +++ b/office-alexander-logistics-app/src/test/java/com/alexanderlogistics/TestIMAPOutlookOAuth.java @@ -28,6 +28,7 @@ import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.message.BasicHeader; import org.imixs.archive.importer.mail.IMAPImportHelper; +import org.junit.Ignore; import org.junit.Test; import com.fasterxml.jackson.databind.JavaType; @@ -121,6 +122,7 @@ public class TestIMAPOutlookOAuth { } @Test + @Ignore public void TestMailboxImixsPL() { Store store = null; String token = null; diff --git a/office-alexander-logistics-app/src/test/java/com/alexanderlogistics/TestIMAPOutlookOAuthDebug.java b/office-alexander-logistics-app/src/test/java/com/alexanderlogistics/TestIMAPOutlookOAuthDebug.java new file mode 100644 index 0000000..a1d14d0 --- /dev/null +++ b/office-alexander-logistics-app/src/test/java/com/alexanderlogistics/TestIMAPOutlookOAuthDebug.java @@ -0,0 +1,257 @@ +package com.alexanderlogistics; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.Map; +import java.util.Properties; + +import javax.mail.Address; +import javax.mail.BodyPart; +import javax.mail.Folder; +import javax.mail.Message; +import javax.mail.MessagingException; +import javax.mail.Multipart; +import javax.mail.Part; +import javax.mail.Session; +import javax.mail.Store; +import javax.mail.internet.MimeBodyPart; + +import org.apache.http.client.ClientProtocolException; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.message.BasicHeader; +import org.imixs.archive.importer.mail.IMAPImportHelper; +import org.junit.Ignore; +import org.junit.Test; + +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.sun.mail.imap.IMAPFolder; + +import junit.framework.Assert; + +/** + * This test shows how to access outlook via oauth2 + * + * @author rsoika + */ +public class TestIMAPOutlookOAuthDebug { + + private static final String TENANT_ID = "xxxxxx"; + private static final String CLIENT_ID = "yyyyyyy"; + private static final String CLIENT_SECRET = "zzzzz"; + + @Test + @Ignore + public void TestMailboxImixsPL() { + Store store = null; + String token = null; + try { + // try to connect... + token = getAuthToken(); + Assert.assertNotNull(token); + store = connect(token, "imixspl@alexander-logistics.com"); + + Assert.assertNotNull(store); + + if (!store.isConnected()) { + // not connected! + } else { + // read inbox.... + IMAPFolder inbox = (IMAPFolder) store.getFolder("INBOX"); + inbox.open(Folder.READ_WRITE); + // fetches all messages from the INBOX... + Message[] messages = inbox.getMessages(); + System.out.println("..." + messages.length + " new messages found"); + + System.out.println("...read message subjects..."); + + for (Message message : messages) { + Address[] fromAddress = null; + String subject = null; + // if we can not open the mail (messaging Exception) than we simply skipp this + // mail see Issue #175 + try { + fromAddress = message.getFrom(); + subject = message.getSubject(); + } catch (MessagingException me) { + System.out.println("...Failed to read message from inbox: " + me.getMessage()); + Assert.fail(); + } + + System.out.println("......received mail from: " + fromAddress[0].toString()); + System.out.println("......subject = " + subject); + + Object contentObject = message.getContent(); + if (contentObject instanceof Multipart) { + System.out.println("......multipart objects found"); + + // here we are save to cast the content to Mulipart + Multipart multiPart = (Multipart) message.getContent(); + for (int i = 0; i < multiPart.getCount(); i++) { + + BodyPart bodyPart = multiPart.getBodyPart(i); + if (bodyPart instanceof MimeBodyPart) { + MimeBodyPart mimeBodyPart = (MimeBodyPart) multiPart.getBodyPart(i); + if (Part.ATTACHMENT.equalsIgnoreCase(mimeBodyPart.getDisposition())) { + + String fileName = mimeBodyPart.getFileName(); + if (fileName == null) { + System.out.println("...skip detaching file, because of missing filename"); + continue; // skip this attachment + } + + // add this attachment + InputStream input = mimeBodyPart.getInputStream(); + byte[] content = IMAPImportHelper.readAllBytes(input); + String contentType = mimeBodyPart.getContentType(); + + System.out + .println("...Attachment '" + fileName + "' is ok - size=" + content.length); + } + } + } + } + } + System.out.println("...completed!"); + } + } catch (IOException e) { + e.printStackTrace(); + Assert.fail(); + } catch (MessagingException e) { + e.printStackTrace(); + Assert.fail(); + } + + } + + public String getAuthToken() throws ClientProtocolException, IOException { + CloseableHttpClient client = HttpClients.createDefault(); + + HttpPost loginPost = new HttpPost("https://login.microsoftonline.com/" + TENANT_ID + "/oauth2/v2.0/token"); + String scopes = "https://outlook.office365.com/.default"; + String encodedBody = "client_id=" + CLIENT_ID + "&scope=" + scopes + "&client_secret=" + CLIENT_SECRET + + "&grant_type=client_credentials"; + + loginPost.setEntity(new StringEntity(encodedBody, ContentType.APPLICATION_FORM_URLENCODED)); + + loginPost.addHeader(new BasicHeader("cache-control", "no-cache")); + CloseableHttpResponse loginResponse = client.execute(loginPost); + + InputStream inputStream = loginResponse.getEntity().getContent(); + byte[] response = readAllBytes(inputStream); + ObjectMapper objectMapper = new ObjectMapper(); + JavaType type = objectMapper.constructType( + objectMapper.getTypeFactory().constructParametricType(Map.class, String.class, String.class)); + Map parsed = new ObjectMapper().readValue(response, type); + String result = parsed.get("access_token"); + + System.out.println("....access token = " + result); + return result; + } + + /** + * This method returns a connection to an javax.mail.store + */ + public Store connect(String oauth2AccessToken, String userEmailId) { + + try { + + String host = "outlook.office365.com"; + String port = "993"; + Store store = null; + + String SSL_FACTORY = "javax.net.ssl.SSLSocketFactory"; + Properties props = new Properties(); + + props.put("mail.imaps.ssl.enable", "true"); + props.put("mail.imaps.sasl.enable", "true"); + props.put("mail.imaps.port", port); + props.put("mail.imaps.auth.mechanisms", "XOAUTH2"); + props.put("mail.imaps.sasl.mechanisms", "XOAUTH2"); + + props.put("mail.imaps.auth.login.disable", "true"); + props.put("mail.imaps.auth.plain.disable", "true"); + + props.setProperty("mail.imaps.socketFactory.class", SSL_FACTORY); + props.setProperty("mail.imaps.socketFactory.fallback", "false"); + props.setProperty("mail.imaps.socketFactory.port", port); + props.setProperty("mail.imaps.starttls.enable", "true"); + + // optional set imap user? + // props.put("mail.imap.user", userEmailId); + + props.put("mail.imaps.auth.plain.disable", "true"); + props.put("mail.debug", "true"); + props.put("mail.debug.auth", "true"); + + Session session = Session.getInstance(props); + session.setDebug(true); + + store = session.getStore("imaps"); + + System.out.println("OAUTH2 IMAP trying to connect with system properties to Host:" + host + ", Port: " + + port + ", userEmailId: " + userEmailId + ", AccessToken: " + oauth2AccessToken); + + store.connect(host, userEmailId, oauth2AccessToken); + if (store.isConnected()) { + System.out.println("Connection Established using imap protocol successfully !"); + return store; + + } + System.out.println("Store.Connect failed!"); + } catch (Exception e) { + System.out.println("Store.Connect failed with the errror: " + e.getMessage()); + StringWriter sw = new StringWriter(); + e.printStackTrace(new PrintWriter(sw)); + String exceptionAsString = sw.toString(); + System.out.println(exceptionAsString); + Assert.fail(); + } + + return null; + + } + + /** + * Helper method to read bytes from stream + * + * @param inputStream + * @return + * @throws IOException + */ + private static byte[] readAllBytes(InputStream inputStream) throws IOException { + final int bufLen = 4 * 0x400; // 4KB + byte[] buf = new byte[bufLen]; + int readLen; + IOException exception = null; + + try { + try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { + while ((readLen = inputStream.read(buf, 0, bufLen)) != -1) + outputStream.write(buf, 0, readLen); + + return outputStream.toByteArray(); + } + } catch (IOException e) { + exception = e; + throw e; + } finally { + if (exception == null) + inputStream.close(); + else + try { + inputStream.close(); + } catch (IOException e) { + exception.addSuppressed(e); + } + } + } +} \ No newline at end of file