From fbf5bf2962604d8fba9f543764241eb423639a6d Mon Sep 17 00:00:00 2001 From: Ralph Soika Date: Fri, 29 Aug 2025 09:43:53 +0200 Subject: [PATCH] zoho schnittstelle --- .../zoho/ZohoAPIService.java | 112 ++++++++++-------- .../zoho/ZohoExportAdapter.java | 37 +++++- .../src/test/resources/zoho/response.json | 71 +++++++++++ workflow/dwc/rechnungsausgang-dwc-1.0.7.bpmn | 21 +++- workflow/dwc/rechnungseingang-dwc-1.0.8.bpmn | 24 ++-- 5 files changed, 194 insertions(+), 71 deletions(-) create mode 100644 office-alexander-logistics-app/src/test/resources/zoho/response.json diff --git a/office-alexander-logistics-app/src/main/java/com/alexanderlogistics/zoho/ZohoAPIService.java b/office-alexander-logistics-app/src/main/java/com/alexanderlogistics/zoho/ZohoAPIService.java index 83f74cd..e51d0f8 100644 --- a/office-alexander-logistics-app/src/main/java/com/alexanderlogistics/zoho/ZohoAPIService.java +++ b/office-alexander-logistics-app/src/main/java/com/alexanderlogistics/zoho/ZohoAPIService.java @@ -158,7 +158,7 @@ public class ZohoAPIService { * @return * @throws PluginException */ - public ZohoInvoice findInvoiceIDByInvoiceNumber(String invoiceNumber, String accessToken) + public ZohoInvoice findInvoiceIDByInvoiceNumber(String invoiceNumber, String accessToken, boolean debug) throws PluginException { // Print JSON to console for verification @@ -179,9 +179,11 @@ public class ZohoAPIService { response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); // Print response details to console - logger.fine("├── Zoho Response:"); - logger.fine("│ ├── Status Code: " + response.statusCode()); - logger.fine("│ ├── Response Body: " + response.body()); + if (debug) { + logger.info("├── Zoho Response:"); + logger.info("│ ├── Status Code: " + response.statusCode()); + logger.info("│ ├── Response Body: " + response.body()); + } if (response.statusCode() >= 300) { throw new PluginException(this.getClass().getName(), "Zoho API error", "Failed to find invoice - Status code: " + response.statusCode() + ", Response: " @@ -212,7 +214,7 @@ public class ZohoAPIService { * @param invoice * @throws PluginException */ - public ZohoInvoice exportInvoice(ItemCollection invoice, String contactID, String accessToken) + public ZohoInvoice exportInvoice(ItemCollection invoice, String contactID, String accessToken, boolean debug) throws PluginException { logger.info("├── Zoho Export Invoice " + invoice.getItemValueString("invoice.number") + "..."); @@ -225,9 +227,10 @@ public class ZohoAPIService { String requestBody = jsonb.toJson(zohoInvoice); // Print JSON to console for verification - logger.fine("├── Zoho Invoice JSON Request..."); - logger.fine("│ ├── " + requestBody); - + if (debug) { + logger.info("├── Zoho Invoice JSON Request..."); + logger.info("│ ├── " + requestBody); + } // https://www.zohoapis.com/books/v3/invoices?organization_id=10234695' String uri = zohoOAuthManager.getBaseURI() + "invoices?organization_id=" + zohoOAuthManager.getOrganization(); @@ -241,9 +244,10 @@ public class ZohoAPIService { HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); // Print response details to console - logger.fine("├── Zoho Response:"); - logger.fine("│ ├── Status Code: " + response.statusCode()); - + if (debug) { + logger.info("├── Zoho Response:"); + logger.info("│ ├── Status Code: " + response.statusCode()); + } if (response.statusCode() >= 300) { throw new PluginException(this.getClass().getName(), "Zoho API error", "Failed to create invoice. Status code: " + response.statusCode() + ", Response: " @@ -252,13 +256,14 @@ public class ZohoAPIService { // Erfolgreiche Erstellung String bodyContent = response.body(); - logger.fine("│ ├── Response Body: " + bodyContent); - + if (debug) { + logger.info("│ ├── Response Body: " + bodyContent); + } System.out.print(bodyContent); ZohoInvoiceCreateResponse createResponse = jsonb.fromJson(bodyContent, ZohoInvoiceCreateResponse.class); if (createResponse != null) { - logger.fine("│ ├── OK - customerID=" + createResponse.getInvoice().getCustomerId()); + logger.info("│ ├── OK - customerID=" + createResponse.getInvoice().getCustomerId()); logger.info("│ ├── OK - invoiceID=" + createResponse.getInvoice().getInvoiceId()); zohoInvoice = createResponse.getInvoice(); @@ -286,7 +291,7 @@ public class ZohoAPIService { * @throws PluginException */ public ZohoCreditnote exportCreditnote(ItemCollection invoice, String contactID, - String accessToken) throws PluginException { + String accessToken, boolean debug) throws PluginException { logger.info("├── Zoho Export creditnote " + invoice.getItemValueString("invoice.number") + "..."); String currencyID = lookupCurrency(invoice.getItemValueString("invoice.currency"), accessToken); @@ -298,7 +303,7 @@ public class ZohoAPIService { ItemCollection invoiceRef = documentService.load(invoiceRefID); if (invoiceRef != null) { invoiceZoho = findInvoiceIDByInvoiceNumber(invoiceRef.getItemValueString("invoice.number"), - accessToken); + accessToken, debug); logger.info("├── Zoho fond invoice zoho ref: " + invoiceZoho.getInvoiceId()); } @@ -309,8 +314,10 @@ public class ZohoAPIService { String requestBody = jsonb.toJson(zohoCreditnote); // Print JSON to console for verification - logger.fine("├── Zoho CreditNote JSON Request..."); - logger.fine("│ ├── " + requestBody); + if (debug) { + logger.info("├── Zoho CreditNote JSON Request..."); + logger.info("│ ├── " + requestBody); + } // https://www.zohoapis.com/books/v3/creditnotes?organization_id=10234695' String uri = zohoOAuthManager.getBaseURI() + "creditnotes?organization_id=" @@ -329,8 +336,10 @@ public class ZohoAPIService { HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); // Print response details to console - logger.fine("├── Zoho Response:"); - logger.fine("│ ├── Status Code: " + response.statusCode()); + if (debug) { + logger.info("├── Zoho Response:"); + logger.info("│ ├── Status Code: " + response.statusCode()); + } if (response.statusCode() >= 300) { throw new PluginException(this.getClass().getName(), "Zoho API error", @@ -340,8 +349,9 @@ public class ZohoAPIService { // Erfolgreiche Erstellung String bodyContent = response.body(); - logger.fine("│ ├── Response Body: " + bodyContent); - + if (debug) { + logger.info("│ ├── Response Body: " + bodyContent); + } System.out.print(bodyContent); ZohoCreditnoteCreateResponse createResponse = jsonb.fromJson(bodyContent, ZohoCreditnoteCreateResponse.class); @@ -373,7 +383,7 @@ public class ZohoAPIService { * @throws PluginException */ public ZohoBill exportBill(ItemCollection invoice, String contactID, String accountID, - String accessToken) throws PluginException { + String accessToken, boolean debug) throws PluginException { logger.info("├── Zoho Export Bill " + invoice.getItemValueString("invoice.number") + "..."); String currencyID = lookupCurrency(invoice.getItemValueString("invoice.currency"), accessToken); @@ -385,9 +395,10 @@ public class ZohoAPIService { String requestBody = jsonb.toJson(zohoBill); // Print JSON to console for verification - logger.fine("├── Zoho Bill JSON Request..."); - logger.fine("│ ├── " + requestBody); - + if (debug) { + logger.info("├── Zoho Bill JSON Request..."); + logger.info("│ ├── " + requestBody); + } // https://www.zohoapis.com/books/v3/expenses?organization_id=10234695' String uri = zohoOAuthManager.getBaseURI() + "bills?organization_id=" + zohoOAuthManager.getOrganization(); logger.fine("│ ├── uri= " + uri); @@ -400,9 +411,10 @@ public class ZohoAPIService { HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); // Print response details to console - logger.fine("├── Zoho Response:"); - logger.fine("│ ├── Status Code: " + response.statusCode()); - + if (debug) { + logger.info("├── Zoho Response:"); + logger.info("│ ├── Status Code: " + response.statusCode()); + } if (response.statusCode() >= 300) { throw new PluginException(this.getClass().getName(), "Zoho API error", "Failed to create expense. Status code: " + response.statusCode() + ", Response: " @@ -411,8 +423,9 @@ public class ZohoAPIService { // Erfolgreiche Erstellung String bodyContent = response.body(); - logger.fine("│ ├── Response Body: " + bodyContent); - + if (debug) { + logger.info("│ ├── Response Body: " + bodyContent); + } System.out.print(bodyContent); ZohoBillCreateResponse createResponse = jsonb.fromJson(bodyContent, ZohoBillCreateResponse.class); @@ -443,7 +456,7 @@ public class ZohoAPIService { * @throws PluginException */ public ZohoVendorCredit exportVendorCredit(ItemCollection invoice, String contactID, String accountID, - String accessToken) throws PluginException { + String accessToken, boolean debug) throws PluginException { logger.info("├── Zoho Export VendorCredit " + invoice.getItemValueString("invoice.number") + "..."); String currencyID = lookupCurrency(invoice.getItemValueString("invoice.currency"), accessToken); @@ -456,9 +469,10 @@ public class ZohoAPIService { String requestBody = jsonb.toJson(zohoVendorCredit); // Print JSON to console for verification - logger.fine("├── Zoho VendorCredit JSON Request..."); - logger.fine("│ ├── " + requestBody); - + if (debug) { + logger.info("├── Zoho VendorCredit JSON Request..."); + logger.info("│ ├── " + requestBody); + } // https://www.zohoapis.com/books/v3/expenses?organization_id=10234695' String uri = zohoOAuthManager.getBaseURI() + "vendorcredits?organization_id=" + zohoOAuthManager.getOrganization(); @@ -472,9 +486,10 @@ public class ZohoAPIService { HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); // Print response details to console - logger.fine("├── Zoho Response:"); - logger.fine("│ ├── Status Code: " + response.statusCode()); - + if (debug) { + logger.info("├── Zoho Response:"); + logger.info("│ ├── Status Code: " + response.statusCode()); + } if (response.statusCode() >= 300) { throw new PluginException(this.getClass().getName(), "Zoho API error", "Failed to create expense. Status code: " + response.statusCode() + ", Response: " @@ -483,8 +498,9 @@ public class ZohoAPIService { // Erfolgreiche Erstellung String bodyContent = response.body(); - logger.fine("│ ├── Response Body: " + bodyContent); - + if (debug) { + logger.info("│ ├── Response Body: " + bodyContent); + } System.out.print(bodyContent); ZohoVendorCreditCreateResponse createResponse = jsonb.fromJson(bodyContent, ZohoVendorCreditCreateResponse.class); @@ -712,12 +728,12 @@ public class ZohoAPIService { // List lineItems = new ArrayList<>(); // create only one single item! - ZohoInvoiceItem lineItem = new ZohoInvoiceItem(); - lineItem.setName(invoice.getItemValueString("invoice.text")); - lineItem.setDescription(""); - lineItem.setRate(invoice.getItemValueDouble("invoice.total")); - lineItem.setQuantity(1); - lineItems.add(lineItem); + // ZohoInvoiceItem lineItem = new ZohoInvoiceItem(); + // lineItem.setName(invoice.getItemValueString("invoice.text")); + // lineItem.setDescription(""); + // lineItem.setRate(invoice.getItemValueDouble("invoice.total")); + // lineItem.setQuantity(1); + // lineItems.add(lineItem); return zohoCreditnote; } @@ -906,8 +922,10 @@ public class ZohoAPIService { String boundary = "----WebKitFormBoundary" + System.currentTimeMillis(); // Build multipart request body + // Ersetzt alle Punkte außer dem letzten (vor der Dateierweiterung) + String cleanFileName = file.getName().replaceAll("\\.(?=.*\\.)", "_"); byte[] header = ("--" + boundary + "\r\n" - + "Content-Disposition: form-data; name=\"attachment\"; filename=\"" + file.getName() + "\"\r\n" + + "Content-Disposition: form-data; name=\"attachment\"; filename=\"" + cleanFileName + "\"\r\n" + "Content-Type: " + file.getContentType() + "\r\n\r\n").getBytes(StandardCharsets.UTF_8); byte[] footer = ("\r\n--" + boundary + "--\r\n").getBytes(StandardCharsets.UTF_8); diff --git a/office-alexander-logistics-app/src/main/java/com/alexanderlogistics/zoho/ZohoExportAdapter.java b/office-alexander-logistics-app/src/main/java/com/alexanderlogistics/zoho/ZohoExportAdapter.java index 7b7a8fa..b57952c 100644 --- a/office-alexander-logistics-app/src/main/java/com/alexanderlogistics/zoho/ZohoExportAdapter.java +++ b/office-alexander-logistics-app/src/main/java/com/alexanderlogistics/zoho/ZohoExportAdapter.java @@ -22,6 +22,16 @@ import jakarta.inject.Inject; /** * This adapter exports the invoice data to zoho * + * To activate debug add the following event definition + * + *
+* {@code
+
+   true
+
+* }
+* 
+ * * @version 1.0 * @author rsoika */ @@ -31,6 +41,7 @@ public class ZohoExportAdapter implements SignalAdapter { public static final String ENV_ZOHO_EXPORT_MAX_ATTACHMENT_SIZE = "zoho.export.maxattachmentsize"; private static Logger logger = Logger.getLogger(ZohoExportAdapter.class.getName()); + private boolean debug = false; @Inject ZohoAPIService zohoAPIService; @@ -55,7 +66,19 @@ public class ZohoExportAdapter implements SignalAdapter { @Override public ItemCollection execute(ItemCollection document, ItemCollection event) throws AdapterException { + // read debug flag try { + List zohoDefinitions = workflowService.evalWorkflowResultXML(event, "zoho", + "EXPORT", document, false); + if (zohoDefinitions != null && zohoDefinitions.size() > 0) { + ItemCollection zohoDefinition = zohoDefinitions.get(0); + debug = zohoDefinition.getItemValueBoolean("debug"); + } + } catch (PluginException ee) { + // no op + } + try { + // get access token String accessToken = zohoOAuthManager.getValidAccessToken(); @@ -88,7 +111,8 @@ public class ZohoExportAdapter implements SignalAdapter { * @param accessToken * @throws PluginException */ - private void exportRechnungsausgang(ItemCollection document, String accessToken) throws PluginException { + private void exportRechnungsausgang(ItemCollection document, String accessToken) + throws PluginException { // find currencyID String currencyID = zohoAPIService.lookupCurrency(document.getItemValueString("invoice.currency"), accessToken); @@ -102,7 +126,7 @@ public class ZohoExportAdapter implements SignalAdapter { if (document.getItemValueDouble("invoice.total") < 0) { // create credit note! logger.info("├── CreditNote Export"); - ZohoCreditnote zohoCreditnote = zohoAPIService.exportCreditnote(document, contactID, accessToken); + ZohoCreditnote zohoCreditnote = zohoAPIService.exportCreditnote(document, contactID, accessToken, debug); // Attache Files.... List files = null; @@ -120,7 +144,7 @@ public class ZohoExportAdapter implements SignalAdapter { } } else { logger.info("├── Invoice Export"); - ZohoInvoice zohoInvoice = zohoAPIService.exportInvoice(document, contactID, accessToken); + ZohoInvoice zohoInvoice = zohoAPIService.exportInvoice(document, contactID, accessToken, debug); // Attache Files.... List files = null; @@ -147,7 +171,8 @@ public class ZohoExportAdapter implements SignalAdapter { * @param accessToken * @throws PluginException */ - private void exportRechnungseingang(ItemCollection document, String accessToken) throws PluginException { + private void exportRechnungseingang(ItemCollection document, String accessToken) + throws PluginException { String currencyID = zohoAPIService.lookupCurrency(document.getItemValueString("invoice.currency"), accessToken); @@ -162,7 +187,7 @@ public class ZohoExportAdapter implements SignalAdapter { // Gutschrift logger.info("├── Vendor Credit Export"); ZohoVendorCredit zohoVendorCredit = zohoAPIService.exportVendorCredit(document, contactID, accountID, - accessToken); + accessToken, debug); // Attache Files.... List files = null; @@ -180,7 +205,7 @@ public class ZohoExportAdapter implements SignalAdapter { } } else { logger.info("├── Bill Export"); - ZohoBill zohoBill = zohoAPIService.exportBill(document, contactID, accountID, accessToken); + ZohoBill zohoBill = zohoAPIService.exportBill(document, contactID, accountID, accessToken, debug); // Attache Files.... List files = null; diff --git a/office-alexander-logistics-app/src/test/resources/zoho/response.json b/office-alexander-logistics-app/src/test/resources/zoho/response.json new file mode 100644 index 0000000..8110416 --- /dev/null +++ b/office-alexander-logistics-app/src/test/resources/zoho/response.json @@ -0,0 +1,71 @@ +{ + "creditnote_number": "494", + "currency_id": "6273937000000091141", + "customer_id": "6273937000000192143", + "date": "2025-07-30", + "exchange_rate": 0.0, + "line_items": [ + { + "description": "Air Freight (Door to Airport)", + "name": "IM-DWC-2507-003", + "quantity": 1, + "rate": 3936.0 + }, + { + "description": "DAP Costs", + "name": "IM-DWC-2507-003", + "quantity": 1, + "rate": 3800.0 + }, + { + "description": "Trip cancellation, Truck waiting charges", + "name": "IM-DWC-2507-003", + "quantity": 1, + "rate": 1000.0 + }, + { + "description": "Transport (DIP - Dubai Hills)", + "name": "IM-DWC-2507-003", + "quantity": 1, + "rate": 550.0 + }, + { + "description": "Empty Box disposal", + "name": "IM-DWC-2507-003", + "quantity": 1, + "rate": 250.0 + }, + { + "description": "Warehouse Handling - IN", + "name": "IM-DWC-2507-003", + "quantity": 1, + "rate": 250.0 + }, + { + "description": "Warehouse Handling - OUT", + "name": "IM-DWC-2507-003", + "quantity": 1, + "rate": 250.0 + }, + { + "description": "Storage Fee", + "name": "IM-DWC-2507-003", + "quantity": 1, + "rate": 175.0 + }, + { + "description": "Customs Duty", + "name": "IM-DWC-2507-003", + "quantity": 1, + "rate": 18976.0 + }, + { + "description": "", + "name": "IM-DWC-2507-003", + "quantity": 1, + "rate": -43277.05 + } + ], + "place_of_supply": "DU", + "total": 43277.05 +} \ No newline at end of file diff --git a/workflow/dwc/rechnungsausgang-dwc-1.0.7.bpmn b/workflow/dwc/rechnungsausgang-dwc-1.0.7.bpmn index 142758a..76b470f 100644 --- a/workflow/dwc/rechnungsausgang-dwc-1.0.7.bpmn +++ b/workflow/dwc/rechnungsausgang-dwc-1.0.7.bpmn @@ -1234,6 +1234,11 @@ Wiedervorlage wird um 7 bzw. 5 Tage erhöht + + + false +]]> + @@ -2140,7 +2145,7 @@ result.isValid=true; - + @@ -2162,11 +2167,19 @@ result.isValid=true; - + false + + + sequenceFlow_ZTMZUg @@ -2785,8 +2798,8 @@ result.isValid=true; - - + + diff --git a/workflow/dwc/rechnungseingang-dwc-1.0.8.bpmn b/workflow/dwc/rechnungseingang-dwc-1.0.8.bpmn index 3b71af2..4b4b325 100644 --- a/workflow/dwc/rechnungseingang-dwc-1.0.8.bpmn +++ b/workflow/dwc/rechnungseingang-dwc-1.0.8.bpmn @@ -1551,15 +1551,13 @@ result.isValid=true; false - + +if (workitem.getItemValueString('txtcomment')==='') { + result.isValid=false; + result.errorMessage='Please enter a commment.'; +}]]> @@ -3034,15 +3032,13 @@ result.isValid=true; false - + +if (workitem.getItemValueString('txtcomment')==='') { + result.isValid=false; + result.errorMessage='Please enter a commment.'; +}]]>