zoho expense export

This commit is contained in:
Ralph Soika 2025-05-08 23:10:57 +02:00
parent 4b9da4d98a
commit d47518224f
16 changed files with 906 additions and 105 deletions

View file

@ -18,7 +18,7 @@ Base API URI= https://accounts.zoho.eu/
## 1. Client Einrichten ## 1. Client Einrichten
https://api-console.zoho.eu/client/1000.NLTM2KUEHI696MSLGEIANATVGGX7IN https://api-console.zoho.eu/
## 2. Generating Grant Token ## 2. Generating Grant Token

View file

@ -19,6 +19,60 @@ zoho.scope ZohoBooks.contacts.ALL ZohoBooks.invoices.CREATE ZohoBooks.i
``` ```
## Forum
form@imixs.com
imixs4zoho
https://api-console.zoho.eu/
ZohoBooks.contacts.ALL,ZohoBooks.invoices.ALL,ZohoBooks.bills.ALL
```
zoho.accesstoken 1.....3
zoho.apidomain https://www.zohoapis.eu
zoho.clientid 1000.5SMVXH92JIA5BTIGJF27OY41TAFFAS
zoho.clientsecret 64aabb5e819757e471c9d0dff6a072b1bcf2c7687d
zoho.code 10-
zoho.organization 886888983
zoho.refreshtoken 10...ff440e
zoho.scope ZohoBooks.contacts.ALL ZohoBooks.invoices.CREATE ZohoBooks.invoices.READ ZohoBooks.invoices.UPDATE
```
## Atari
atari.600xl@gmail.com
800xlAtari
```
zoho.apidomain https://www.zohoapis.eu
zoho.clientid 1000.86O4P321HDYDRX0Q0N1G7YOJRJ9D5W
zoho.clientsecret 2a67b6cfc364f5df27cc8eb33e9b0e4e8a0221ebc3
zoho.code 1000.c7dc89c06111b93f1242b587fabed4ac.44c591dffbd978a316e3d90ed3fefc78
zoho.organization 886924765
zoho.scope ZohoBooks.contacts.ALL,ZohoBooks.invoices.ALL,ZohoBooks.bills.ALL
```
## Prod DWC
info@imixs.com
imixs4zoho
https://api-console.zoho.com/
ZohoBooks.contacts.ALL,ZohoBooks.invoices.ALL,ZohoBooks.bills.ALL
```
zoho.apidomain https://www.zohoapis.com
zoho.clientid 1000.MQE1SU8UGY6F2PBPASOXGTLWYQD1FS
zoho.clientsecret 1ca70e1ab803b3fed6b1b5e00858c316e2003d289b
zoho.organization 884218508
zoho.scope ZohoBooks.contacts.ALL,ZohoBooks.invoices.ALL,ZohoBooks.bills.ALL
```
# API Dokumentation # API Dokumentation
- API Docu: https://www.zoho.com/books/api/v3/introduction/ - API Docu: https://www.zoho.com/books/api/v3/introduction/

View file

@ -0,0 +1,167 @@
{
"code": 0,
"message": "The bill has been created.",
"bill": {
"bill_id": "6206847000000103003",
"vendor_id": "6206847000000100015",
"vendor_name": "Feldmuehle GmbH",
"source": "Api",
"contact_category": "",
"tax_treatment": "",
"unused_credits_payable_amount": 0.00,
"status": "paid",
"color_code": "",
"current_sub_status_id": "",
"current_sub_status": "paid",
"sub_statuses": [],
"bill_number": "28195",
"date": "2024-07-26",
"due_date": "2024-07-26",
"discount_setting": "flat",
"tds_calculation_type": "tds_item_level",
"payment_terms": 0,
"payment_terms_label": "Due on Receipt",
"payment_expected_date": "",
"reference_number": "",
"scanned_po_number": "",
"recurring_bill_id": "",
"due_by_days": 286,
"due_in_days": "",
"currency_id": "6206847000000000109",
"currency_code": "EUR",
"currency_symbol": "€",
"currency_name_formatted": "EUR- Euro",
"documents": [],
"subject_content": "",
"price_precision": 2,
"exchange_rate": 1.00,
"custom_fields": [],
"custom_field_hash": {},
"is_viewed_by_client": false,
"client_viewed_time": "",
"is_item_level_tax_calc": false,
"is_inclusive_tax": false,
"tax_rounding": "entity_level",
"is_uber_bill": false,
"is_tally_bill": false,
"track_discount_in_account": true,
"is_bill_reconciliation_violated": false,
"bill_order_type": "",
"line_items": [
{
"purchaseorder_id": "",
"purchaseorder_item_id": "",
"receive_id": "",
"line_item_id": "6206847000000103013",
"item_id": "",
"name": "AB-DEFGHI-1234-567",
"account_id": "6206847000000092271",
"account_name": "TEst",
"description": "",
"bcy_rate": 0.00,
"rate": 0.00,
"sales_rate": "",
"pricebook_id": "",
"header_id": "",
"header_name": "",
"tags": [],
"quantity": 1.00,
"discount": 0.00,
"discounts": [],
"discount_account_id": "",
"discount_account_name": "",
"markup_percent": 0.00,
"tax_id": "",
"tax_name": "",
"tax_type": "tax",
"tax_percentage": 0,
"line_item_taxes": [],
"item_total": 0.00,
"item_order": 1,
"unit": "",
"item_type": "",
"image_name": "",
"image_type": "",
"is_billable": false,
"customer_id": "",
"receipt_line_item_id": "",
"customer_name": "",
"project_id": "",
"project_name": "",
"invoice_id": "",
"invoice_number": "",
"item_custom_fields": [],
"purchase_request_items": [],
"item_matching_type": ""
}
],
"submitted_date": "",
"submitted_by": "",
"submitted_by_name": "",
"submitted_by_email": "",
"submitted_by_photo_url": "",
"submitter_id": "",
"approver_id": "",
"adjustment": 0.00,
"adjustment_description": "",
"discount_amount": 0.00,
"discount": 0.00,
"discount_applied_on_amount": 0.00,
"is_discount_before_tax": true,
"discount_account_id": "",
"discount_account_name": "",
"discount_type": "entity_level",
"sub_total": 0.00,
"sub_total_inclusive_of_tax": 0.00,
"tax_total": 0.00,
"discount_total": 0.00,
"discount_percent": 0.00,
"total": 0.00,
"payment_made": 0.00,
"vendor_credits_applied": 0.00,
"is_line_item_invoiced": false,
"purchaseorders": [],
"taxes": [],
"computation_type": "basic",
"tax_override_preference": "no_override",
"tds_override_preference": "no_override",
"balance": 0.00,
"unprocessed_payment_amount": 0.00,
"billing_address_id": "6206847000000100017",
"billing_address": {
"address": "",
"street2": "",
"city": "",
"state": "",
"zip": "",
"country": "",
"fax": "",
"phone": "",
"attention": ""
},
"payments": [],
"vendor_credits": [],
"created_time": "2025-05-08T21:36:04+0100",
"created_by_id": "6206847000000092001",
"last_modified_id": "6206847000000092001",
"last_modified_time": "2025-05-08T21:36:04+0100",
"reference_id": "",
"notes": "",
"terms": "",
"attachment_name": "",
"template_id": "6206847000000031017",
"template_name": "Standard Template",
"page_width": "8.27in",
"page_height": "11.69in",
"orientation": "portrait",
"template_type": "standard",
"is_approval_required": false,
"allocated_landed_costs": [],
"unallocated_landed_costs": [],
"entity_type": "bill",
"total_retention_amount": 0.00,
"retention_items": [],
"can_send_in_mail": false,
"approvers_list": []
}
}

View file

@ -21,9 +21,15 @@ import org.imixs.workflow.ItemCollection;
import org.imixs.workflow.exceptions.PluginException; import org.imixs.workflow.exceptions.PluginException;
import com.alexanderlogistics.InvoiceUtil; import com.alexanderlogistics.InvoiceUtil;
import com.alexanderlogistics.zoho.dto.ZohoBill;
import com.alexanderlogistics.zoho.dto.ZohoBillCreateResponse;
import com.alexanderlogistics.zoho.dto.ZohoBillItem;
import com.alexanderlogistics.zoho.dto.ZohoContact; import com.alexanderlogistics.zoho.dto.ZohoContact;
import com.alexanderlogistics.zoho.dto.ZohoContactCreateResponse; import com.alexanderlogistics.zoho.dto.ZohoContactCreateResponse;
import com.alexanderlogistics.zoho.dto.ZohoContactFindResponse; import com.alexanderlogistics.zoho.dto.ZohoContactFindResponse;
import com.alexanderlogistics.zoho.dto.ZohoExpense;
import com.alexanderlogistics.zoho.dto.ZohoExpenseCreateResponse;
import com.alexanderlogistics.zoho.dto.ZohoExpenseItem;
import com.alexanderlogistics.zoho.dto.ZohoInvoice; import com.alexanderlogistics.zoho.dto.ZohoInvoice;
import com.alexanderlogistics.zoho.dto.ZohoInvoiceCreateResponse; import com.alexanderlogistics.zoho.dto.ZohoInvoiceCreateResponse;
import com.alexanderlogistics.zoho.dto.ZohoInvoiceItem; import com.alexanderlogistics.zoho.dto.ZohoInvoiceItem;
@ -53,12 +59,12 @@ public class ZohoAPIService {
private static Logger logger = Logger.getLogger(ZohoAPIService.class.getName()); private static Logger logger = Logger.getLogger(ZohoAPIService.class.getName());
@Inject
ZohoOAuthManager zohoOAuthManager;
private HttpClient httpClient; private HttpClient httpClient;
private Jsonb jsonb; private Jsonb jsonb;
@Inject
ZohoOAuthManager zohoOAuthManager;
@PostConstruct @PostConstruct
void init() { void init() {
this.httpClient = HttpClient.newBuilder().connectTimeout(Duration.ofSeconds(10)).build(); this.httpClient = HttpClient.newBuilder().connectTimeout(Duration.ofSeconds(10)).build();
@ -68,10 +74,11 @@ public class ZohoAPIService {
this.jsonb = JsonbBuilder.create(config); this.jsonb = JsonbBuilder.create(config);
} }
public String findContactIDByCompanyName(String companyName, String accessToken) throws PluginException { public String findContactIDByCompanyName(String companyName, String contactType, String accessToken)
throws PluginException {
// Print JSON to console for verification // Print JSON to console for verification
logger.info("├── Zoho lookup contact '" + companyName + "'..."); logger.info("├── Zoho lookup contact (" + contactType + ") '" + companyName + "'...");
try { try {
// https://www.zohoapis.com/books/v3/contacts?organization_id=10234695&company_name=xxx' // https://www.zohoapis.com/books/v3/contacts?organization_id=10234695&company_name=xxx'
String uri = zohoOAuthManager.getBaseURI() + "contacts?organization_id=" String uri = zohoOAuthManager.getBaseURI() + "contacts?organization_id="
@ -83,7 +90,9 @@ public class ZohoAPIService {
.header("Authorization", "Zoho-oauthtoken " + accessToken) .header("Authorization", "Zoho-oauthtoken " + accessToken)
.header("Content-Type", "application/json").GET().build(); .header("Content-Type", "application/json").GET().build();
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); HttpResponse<String> response;
response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
// Print response details to console // Print response details to console
logger.fine("├── Zoho Response:"); logger.fine("├── Zoho Response:");
@ -100,16 +109,18 @@ public class ZohoAPIService {
if (contactsResponse != null && contactsResponse.getContacts() != null) { if (contactsResponse != null && contactsResponse.getContacts() != null) {
// Durchsuche die Ergebnisse nach exakter Übereinstimmung // Durchsuche die Ergebnisse nach exakter Übereinstimmung
for (ZohoContact contact : contactsResponse.getContacts()) { for (ZohoContact contact : contactsResponse.getContacts()) {
if (companyName.equalsIgnoreCase(contact.getCompanyName())) { if (companyName.equalsIgnoreCase(contact.getCompanyName())
&& contactType.equalsIgnoreCase((contact.getContactType()))) {
logger.info("│ ├── contactID= " + contact.getContactId()); logger.info("│ ├── contactID= " + contact.getContactId());
return contact.getContactId(); return contact.getContactId();
} }
} }
} }
return null; } catch (IOException | InterruptedException e) {
} catch (Exception e) { throw new PluginException(this.getClass().getName(), "Zoho API error",
throw new PluginException(this.getClass().getName(), "Zoho API error", "Failed to find contacts", e); "Failed to find Contacts: " + e.getMessage());
} }
return null;
} }
@ -121,21 +132,12 @@ public class ZohoAPIService {
* @param invoice * @param invoice
* @throws PluginException * @throws PluginException
*/ */
public ZohoInvoice exportInvoice(ItemCollection invoice, List<FileData> files) throws PluginException { public ZohoInvoice exportInvoice(ItemCollection invoice, String contactID, String accessToken)
String accessToken = zohoOAuthManager.getValidAccessToken(); throws PluginException {
logger.info("├── Zoho Export Invoice " + invoice.getItemValueString("invoice.number") + "..."); logger.info("├── Zoho Export Invoice " + invoice.getItemValueString("invoice.number") + "...");
// first lookup contact!
String contactID = "";
contactID = findContactIDByCompanyName(invoice.getItemValueString("dbtr.name"), accessToken);
if (contactID == null) {
logger.info("│ ├── contact not found");
ZohoContact contact = createContact(invoice.getItemValueString("dbtr.name"), accessToken);
contactID = contact.getContactId();
}
// Konvertiere ItemCollection zu ZohoInvoiceDTO // Konvertiere ItemCollection zu ZohoInvoiceDTO
ZohoInvoice zohoInvoice = convertToZohoInvoice(invoice, contactID, accessToken); ZohoInvoice zohoInvoice = convertToZohoInvoice(invoice, contactID);
try { try {
String requestBody = jsonb.toJson(zohoInvoice); String requestBody = jsonb.toJson(zohoInvoice);
@ -173,52 +175,193 @@ public class ZohoAPIService {
System.out.print(bodyContent); System.out.print(bodyContent);
ZohoInvoiceCreateResponse createResponse = jsonb.fromJson(bodyContent, ZohoInvoiceCreateResponse.class); ZohoInvoiceCreateResponse createResponse = jsonb.fromJson(bodyContent, ZohoInvoiceCreateResponse.class);
logger.fine("│ ├── OK - customerID=" + createResponse.getInvoice().getCustomerId());
logger.info("│ ├── OK - invoiceID=" + createResponse.getInvoice().getInvoiceId());
if (createResponse != null) { if (createResponse != null) {
logger.fine("│ ├── OK - customerID=" + createResponse.getInvoice().getCustomerId());
logger.info("│ ├── OK - invoiceID=" + createResponse.getInvoice().getInvoiceId());
zohoInvoice = createResponse.getInvoice(); zohoInvoice = createResponse.getInvoice();
// now add attachments (optional) // now mark the invoice as send
try { markInvoiceAsSend(zohoInvoice.getInvoiceId(), "invoices", accessToken);
if (files != null) {
for (FileData file : files) {
attacheFileData(zohoInvoice.getInvoiceId(), file, "invoices", accessToken);
}
}
// now mark the invoice as send
markInvoiceAsSend(zohoInvoice.getInvoiceId(), "invoices", accessToken);
} catch (PluginException e) {
logger.warning("Failed to export Invoice: " + e.getMessage());
}
logger.info("│ ├── Invoice Export successful."); logger.info("│ ├── Invoice Export successful.");
return zohoInvoice; return zohoInvoice;
} else {
throw new PluginException(this.getClass().getName(), "Zoho API error",
"Failed to export invoice to Zoho: unable to resolve response");
} }
} catch (IOException | InterruptedException e) { } catch (IOException | InterruptedException e) {
throw new PluginException(this.getClass().getName(), "Zoho API error", throw new PluginException(this.getClass().getName(), "Zoho API error",
"Failed to export invoice to Zoho: " + e.getMessage(), e); "Failed to export invoice to Zoho: " + e.getMessage(), e);
} }
return null;
} }
/**
* Exports an Eingangsrechnung document
*
* @see https://www.zoho.com/books/api/v3/expenses/#create-an-expense
*
* @param invoice
* @throws PluginException
*/
public ZohoExpense exportExpense(ItemCollection invoice, String contactID, String accessToken)
throws PluginException {
logger.info("├── Zoho Export Expense " + invoice.getItemValueString("invoice.number") + "...");
// Konvertiere ItemCollection zu ZohoInvoiceDTO
ZohoExpense zohoExpense = convertToZohoExpense(invoice, contactID);
try {
String requestBody = jsonb.toJson(zohoExpense);
// Print JSON to console for verification
logger.fine("├── Zoho Expense JSON Request...");
logger.fine("│ ├── " + requestBody);
// https://www.zohoapis.com/books/v3/expenses?organization_id=10234695'
String uri = zohoOAuthManager.getBaseURI() + "expenses?organization_id="
+ zohoOAuthManager.getOrganization();
logger.fine("│ ├── uri= " + uri);
logger.fine("│ ├── accessToken=" + accessToken);
HttpRequest request = HttpRequest.newBuilder().uri(URI.create(uri))
.header("Authorization", "Zoho-oauthtoken " + accessToken)
.header("Content-Type", "application/json").POST(HttpRequest.BodyPublishers.ofString(requestBody))
.build();
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
// Print response details to console
logger.fine("├── Zoho Response:");
logger.fine("│ ├── 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: "
+ response.body());
}
// Erfolgreiche Erstellung
String bodyContent = response.body();
logger.fine("│ ├── Response Body: " + bodyContent);
System.out.print(bodyContent);
ZohoExpenseCreateResponse createResponse = jsonb.fromJson(bodyContent, ZohoExpenseCreateResponse.class);
if (createResponse != null) {
logger.info("│ ├── OK - customerID=" + createResponse.getExpense().getCustomerId());
logger.info("│ ├── OK - expenseID=" + createResponse.getExpense().getExpenseId());
zohoExpense = createResponse.getExpense();
// now mark the invoice as send
logger.info("│ ├── Invoice Export successful.");
return zohoExpense;
}
} catch (IOException | InterruptedException e) {
throw new PluginException(this.getClass().getName(), "Zoho API error",
"Failed to export invoice to Zoho: " + e.getMessage(), e);
}
return null;
}
/**
* Exports an Eingangsrechnung document
*
* @see https://www.zoho.com/books/api/v3/expenses/#create-an-expense
*
* @param invoice
* @throws PluginException
*/
public ZohoBill exportBill(ItemCollection invoice, String contactID, String accountID, String accessToken)
throws PluginException {
logger.info("├── Zoho Export Bill " + invoice.getItemValueString("invoice.number") + "...");
// Konvertiere ItemCollection zu ZohoInvoiceDTO
ZohoBill zohoBill = convertToZohoBill(invoice, contactID, accountID);
try {
String requestBody = jsonb.toJson(zohoBill);
// Print JSON to console for verification
logger.fine("├── Zoho Bill JSON Request...");
logger.fine("│ ├── " + requestBody);
// https://www.zohoapis.com/books/v3/expenses?organization_id=10234695'
String uri = zohoOAuthManager.getBaseURI() + "bills?organization_id=" + zohoOAuthManager.getOrganization();
logger.fine("│ ├── uri= " + uri);
logger.fine("│ ├── accessToken=" + accessToken);
HttpRequest request = HttpRequest.newBuilder().uri(URI.create(uri))
.header("Authorization", "Zoho-oauthtoken " + accessToken)
.header("Content-Type", "application/json").POST(HttpRequest.BodyPublishers.ofString(requestBody))
.build();
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
// Print response details to console
logger.fine("├── Zoho Response:");
logger.fine("│ ├── 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: "
+ response.body());
}
// Erfolgreiche Erstellung
String bodyContent = response.body();
logger.fine("│ ├── Response Body: " + bodyContent);
System.out.print(bodyContent);
ZohoBillCreateResponse createResponse = jsonb.fromJson(bodyContent, ZohoBillCreateResponse.class);
if (createResponse != null) {
logger.info("│ ├── OK - customerID=" + createResponse.getBill().getVendorId());
logger.info("│ ├── OK - billID=" + createResponse.getBill().getBillId());
zohoBill = createResponse.getBill();
// now mark the invoice as send
logger.info("│ ├── Bill Export successful.");
return zohoBill;
}
} catch (IOException | InterruptedException e) {
throw new PluginException(this.getClass().getName(), "Zoho API error",
"Failed to export bill to Zoho: " + e.getMessage(), e);
}
return null;
}
public String lookupContact(String companyName, String contactType, String accessToken) throws PluginException {
// first lookup contact!
String contactID = "";
contactID = findContactIDByCompanyName(companyName, contactType, accessToken);
if (contactID == null) {
logger.info("│ ├── contact '" + companyName + "' not found");
ZohoContact contact = createContact(companyName, contactType, accessToken);
contactID = contact.getContactId();
}
return contactID;
}
/** /**
* Erstellt einen neuen Contact in Zoho Books * Erstellt einen neuen Contact in Zoho Books
* *
* @param companyName Der Firmenname für den neuen Contact * @param companyName Der Firmenname für den neuen Contact
* @param contactType - customer/vendor
* @return Der erstellte ZohoContact mit contact_id * @return Der erstellte ZohoContact mit contact_id
* @throws PluginException Wenn der API-Aufruf fehlschlägt * @throws PluginException Wenn der API-Aufruf fehlschlägt
*/ */
public ZohoContact createContact(String companyName, String accessToken) throws PluginException { public ZohoContact createContact(String companyName, String contactType, String accessToken)
throws PluginException {
logger.info("├── Zoho create contact '" + companyName + "'..."); logger.info("├── Zoho create contact '" + companyName + "'...");
try { try {
// Contact-DTO vorbereiten // Contact-DTO vorbereiten
ZohoContact newContact = new ZohoContact(); ZohoContact newContact = new ZohoContact();
newContact.setContactName(companyName); // Wir verwenden den Firmennamen auch als Contact Name newContact.setContactName(companyName); // Wir verwenden den Firmennamen auch als Contact Name
newContact.setCompanyName(companyName); newContact.setCompanyName(companyName);
newContact.setContactType(contactType);
// JSON serialisieren // JSON serialisieren
String requestBody = jsonb.toJson(newContact); String requestBody = jsonb.toJson(newContact);
@ -258,8 +401,7 @@ public class ZohoAPIService {
} }
private ZohoInvoice convertToZohoInvoice(ItemCollection invoice, String contactID, String accessToken) private ZohoInvoice convertToZohoInvoice(ItemCollection invoice, String contactID) throws PluginException {
throws PluginException {
ZohoInvoice zohoInvoice = new ZohoInvoice(); ZohoInvoice zohoInvoice = new ZohoInvoice();
// Basisinformationen // Basisinformationen
@ -290,6 +432,65 @@ public class ZohoAPIService {
return zohoInvoice; return zohoInvoice;
} }
private ZohoExpense convertToZohoExpense(ItemCollection invoice, String contactID) throws PluginException {
ZohoExpense zohoExpense = new ZohoExpense();
// Basisinformationen
zohoExpense.setInvoiceNumber(invoice.getItemValueString("invoice.number"));
zohoExpense.setDate(
LocalDate.ofInstant(invoice.getItemValueDate("invoice.date").toInstant(), ZoneId.systemDefault()));
zohoExpense.setAmount(invoice.getItemValueDouble("invoice.total"));
// Kunden-ID (muss angepasst werden je nachdem wie du sie speicherst)
zohoExpense.setCustomerId(contactID);
zohoExpense.setPaid_through_account_id("1700");
List<ItemCollection> positionen = InvoiceUtil.explodeChildList(invoice);
// {amount=[11825.00], total=[11825.00], numpos=[1], name=[AB-DEFGHI-1234-567],
// tax=[0], category=[STORAGE], invoice.period=[]}
List<ZohoExpenseItem> lineItems = positionen.stream().map(item -> {
ItemCollection itemCol = (ItemCollection) item;
ZohoExpenseItem lineItem = new ZohoExpenseItem();
lineItem.setDescription(itemCol.getItemValueString("name"));
return lineItem;
}).collect(Collectors.toList());
zohoExpense.setLineItems(lineItems);
return zohoExpense;
}
private ZohoBill convertToZohoBill(ItemCollection invoice, String contactID, String accountID)
throws PluginException {
ZohoBill zohoBill = new ZohoBill();
// Basisinformationen
zohoBill.setInvoiceNumber(invoice.getItemValueString("invoice.number"));
zohoBill.setDate(
LocalDate.ofInstant(invoice.getItemValueDate("invoice.date").toInstant(), ZoneId.systemDefault()));
zohoBill.setAmount(invoice.getItemValueDouble("invoice.total"));
// Kunden-ID (muss angepasst werden je nachdem wie du sie speicherst)
zohoBill.setVendorId(contactID);
// zohoBill.setPaid_through_account_id("1700");
List<ItemCollection> positionen = InvoiceUtil.explodeChildList(invoice);
// {amount=[11825.00], total=[11825.00], numpos=[1], name=[AB-DEFGHI-1234-567],
// tax=[0], category=[STORAGE], invoice.period=[]}
List<ZohoBillItem> lineItems = positionen.stream().map(item -> {
ItemCollection itemCol = (ItemCollection) item;
ZohoBillItem lineItem = new ZohoBillItem();
lineItem.setName(itemCol.getItemValueString("name"));
lineItem.setAccountId(accountID);
lineItem.setAmount(itemCol.getItemValueDouble("amount"));
return lineItem;
}).collect(Collectors.toList());
zohoBill.setLineItems(lineItems);
return zohoBill;
}
/** /**
* This method adds an attachment to an invoice * This method adds an attachment to an invoice
* *

View file

@ -29,7 +29,7 @@ import java.util.logging.Logger;
import org.imixs.workflow.exceptions.PluginException; import org.imixs.workflow.exceptions.PluginException;
import org.imixs.workflow.office.config.ConfigController; import org.imixs.workflow.office.config.ConfigController;
import jakarta.enterprise.context.ApplicationScoped; import jakarta.enterprise.context.ConversationScoped;
import jakarta.inject.Inject; import jakarta.inject.Inject;
import jakarta.inject.Named; import jakarta.inject.Named;
@ -42,7 +42,8 @@ import jakarta.inject.Named;
* *
*/ */
@Named("zohoController") @Named("zohoController")
@ApplicationScoped // @ApplicationScoped
@ConversationScoped
public class ZohoController extends ConfigController { public class ZohoController extends ConfigController {
public static final String ZOHO_CONFIGURATION = "ZOHO_CONFIGURATION"; public static final String ZOHO_CONFIGURATION = "ZOHO_CONFIGURATION";
@ -64,7 +65,7 @@ public class ZohoController extends ConfigController {
public void updateAccessToken() { public void updateAccessToken() {
// //
try { try {
zohoOAuthManager.updateTokens(this.getWorkitem().getItemValueString("zoho.code")); zohoOAuthManager.updateTokens(this.getWorkitem());
} catch (PluginException e) { } catch (PluginException e) {
String message = "Failed to generate token: " + e.getMessage(); String message = "Failed to generate token: " + e.getMessage();
logger.warning(message); logger.warning(message);

View file

@ -12,6 +12,7 @@ import org.imixs.workflow.engine.WorkflowService;
import org.imixs.workflow.exceptions.AdapterException; import org.imixs.workflow.exceptions.AdapterException;
import org.imixs.workflow.exceptions.PluginException; import org.imixs.workflow.exceptions.PluginException;
import com.alexanderlogistics.zoho.dto.ZohoBill;
import com.alexanderlogistics.zoho.dto.ZohoInvoice; import com.alexanderlogistics.zoho.dto.ZohoInvoice;
import jakarta.inject.Inject; import jakarta.inject.Inject;
@ -37,6 +38,8 @@ public class ZohoExportAdapter implements SignalAdapter {
@Inject @Inject
SnapshotService snapshotService; SnapshotService snapshotService;
@Inject
ZohoOAuthManager zohoOAuthManager;
@Inject @Inject
@ConfigProperty(name = ENV_ZOHO_EXPORT_MAX_ATTACHMENT_SIZE, defaultValue = "10485760") @ConfigProperty(name = ENV_ZOHO_EXPORT_MAX_ATTACHMENT_SIZE, defaultValue = "10485760")
@ -50,21 +53,82 @@ public class ZohoExportAdapter implements SignalAdapter {
@Override @Override
public ItemCollection execute(ItemCollection document, ItemCollection event) public ItemCollection execute(ItemCollection document, ItemCollection event)
throws AdapterException, PluginException { throws AdapterException, PluginException {
logger.info("├── Invoice Export");
// Load attachments
List<FileData> files = null;
ItemCollection snapshot = snapshotService.findSnapshot(document);
if (snapshot != null) {
files = snapshot.getFileData();
}
// read the cargosoft export options // read the cargosoft export options
ItemCollection evalItemCollection = workflowService.evalWorkflowResult(event, "zoho", document, false); ItemCollection evalItemCollection = workflowService.evalWorkflowResult(event, "zoho", document, false);
ZohoInvoice zohoInvoice = zohoAPIService.exportInvoice(document, files); // get access token
String accessToken = zohoOAuthManager.getValidAccessToken();
// Rechnungsausgang
if (document.getModelVersion().startsWith("rechnungsausgang-")) {
logger.info("├── Invoice Export");
exportRechnungsausgang(document, accessToken);
}
// Rechnungseingang
if (document.getModelVersion().startsWith("rechnungseingang-")) {
logger.info("├── Bill Export");
exportRechnungseingang(document, accessToken);
}
return document; return document;
} }
/**
* Help method, - finds/updates - contact, - export invoice, - change state,
* -attache files
*
* @param document
* @param accessToken
* @throws PluginException
*/
private void exportRechnungsausgang(ItemCollection document, String accessToken) throws PluginException {
// find companyID
String contactID = zohoAPIService.lookupContact(document.getItemValueString("dbtr.name"), "customer",
accessToken);
ZohoInvoice zohoInvoice = zohoAPIService.exportInvoice(document, contactID, accessToken);
// Attache Files....
List<FileData> files = null;
ItemCollection snapshot = snapshotService.findSnapshot(document);
if (snapshot != null) {
files = snapshot.getFileData();
if (files != null) {
for (FileData file : files) {
zohoAPIService.attacheFileData(zohoInvoice.getInvoiceId(), file, "invoices", accessToken);
}
}
}
}
/**
* Help method, - finds/updates - contact, - export invoice, - change state,
* -attache files
*
* @param document
* @param accessToken
* @throws PluginException
*/
private void exportRechnungseingang(ItemCollection document, String accessToken) throws PluginException {
// find companyID
String contactID = zohoAPIService.lookupContact(document.getItemValueString("cdtr.name"), "vendor",
accessToken);
String accountID = zohoOAuthManager.getAccountId();
ZohoBill zohoBill = zohoAPIService.exportBill(document, contactID, accountID, accessToken);
// Attache Files....
List<FileData> files = null;
ItemCollection snapshot = snapshotService.findSnapshot(document);
if (snapshot != null) {
files = snapshot.getFileData();
if (files != null) {
for (FileData file : files) {
zohoAPIService.attacheFileData(zohoBill.getBillId(), file, "bills", accessToken);
}
}
}
}
} }

View file

@ -85,6 +85,14 @@ public class ZohoOAuthManager {
return null; return null;
} }
public String getAccountId() throws PluginException {
ItemCollection zohoConfig = configService.loadConfiguration(ZohoController.ZOHO_CONFIGURATION, false);
if (zohoConfig != null) {
return zohoConfig.getItemValueString("zoho.accountid");
}
return null;
}
public String getBaseURI() throws PluginException { public String getBaseURI() throws PluginException {
String uri = ""; String uri = "";
ItemCollection zohoConfig = configService.loadConfiguration(ZohoController.ZOHO_CONFIGURATION, false); ItemCollection zohoConfig = configService.loadConfiguration(ZohoController.ZOHO_CONFIGURATION, false);
@ -109,21 +117,27 @@ public class ZohoOAuthManager {
* @throws PluginException * @throws PluginException
*/ */
@Lock(LockType.WRITE) @Lock(LockType.WRITE)
public void updateTokens(String code) throws PluginException { public void updateTokens(ItemCollection zohoConfig) throws PluginException {
logger.info("├── update Zoho tokens"); logger.info("├── update Zoho tokens");
try { try {
String code = zohoConfig.getItemValueString("zoho.code");
ItemCollection zohoConfig = configService.loadConfiguration(ZohoController.ZOHO_CONFIGURATION, false);
String clientID = zohoConfig.getItemValueString("zoho.clientid"); String clientID = zohoConfig.getItemValueString("zoho.clientid");
String clientSecret = zohoConfig.getItemValueString("zoho.clientsecret"); String clientSecret = zohoConfig.getItemValueString("zoho.clientsecret");
String requestUrl = "https://accounts.zoho.eu/oauth/v2/token" + "?code=" // String requestUrl = zohoConfig.getItemValueString("zoho.oauth.uri") +
// "?code="
// + URLEncoder.encode(code, StandardCharsets.UTF_8) + "&client_id="
// + URLEncoder.encode(clientID, StandardCharsets.UTF_8) + "&client_secret="
// + URLEncoder.encode(clientSecret, StandardCharsets.UTF_8) + "&redirect_uri="
// + URLEncoder.encode(redirectURI, StandardCharsets.UTF_8) +
// "&grant_type=authorization_code";
String requestUrl = zohoConfig.getItemValueString("zoho.oauth.uri") + "?code="
+ URLEncoder.encode(code, StandardCharsets.UTF_8) + "&client_id=" + URLEncoder.encode(code, StandardCharsets.UTF_8) + "&client_id="
+ URLEncoder.encode(clientID, StandardCharsets.UTF_8) + "&client_secret=" + URLEncoder.encode(clientID, StandardCharsets.UTF_8) + "&client_secret="
+ URLEncoder.encode(clientSecret, StandardCharsets.UTF_8) + "&redirect_uri=" + URLEncoder.encode(clientSecret, StandardCharsets.UTF_8) + "&grant_type=authorization_code";
+ URLEncoder.encode(redirectURI, StandardCharsets.UTF_8) + "&grant_type=authorization_code";
logger.fine("│ ├── Request URI=" + requestUrl); logger.info("│ ├── Request URI=" + requestUrl);
HttpRequest request = HttpRequest.newBuilder().uri(URI.create(requestUrl)) HttpRequest request = HttpRequest.newBuilder().uri(URI.create(requestUrl))
.header("Content-Type", "application/x-www-form-urlencoded") .header("Content-Type", "application/x-www-form-urlencoded")
@ -133,10 +147,10 @@ public class ZohoOAuthManager {
HttpResponse<String> response; HttpResponse<String> response;
response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
logger.fine("│ ├── Response statusCode=" + response.statusCode()); logger.info("│ ├── Response statusCode=" + response.statusCode());
if (response.statusCode() == 200) { if (response.statusCode() == 200) {
// 1. Response-Logging für Debugging // 1. Response-Logging für Debugging
logger.fine("│ ├── Response Body=" + response.body()); logger.info("│ ├── Response Body=" + response.body());
if (response.body().contains("error")) { if (response.body().contains("error")) {
throw new PluginException(ZohoOAuthManager.class.getSimpleName(), ZohoOAuthManager.ERROR_CONFIG, throw new PluginException(ZohoOAuthManager.class.getSimpleName(), ZohoOAuthManager.ERROR_CONFIG,
@ -172,7 +186,7 @@ public class ZohoOAuthManager {
String refreshToken = zohoConfig.getItemValueString("zoho.refreshToken"); String refreshToken = zohoConfig.getItemValueString("zoho.refreshToken");
try { try {
String requestUrl = "https://accounts.zoho.eu/oauth/v2/token" + "?refresh_token=" String requestUrl = zohoConfig.getItemValueString("zoho.oauth.uri") + "?refresh_token="
+ URLEncoder.encode(refreshToken, StandardCharsets.UTF_8) + "&client_id=" + URLEncoder.encode(refreshToken, StandardCharsets.UTF_8) + "&client_id="
+ URLEncoder.encode(clientID, StandardCharsets.UTF_8) + "&client_secret=" + URLEncoder.encode(clientID, StandardCharsets.UTF_8) + "&client_secret="
+ URLEncoder.encode(clientSecret, StandardCharsets.UTF_8) + "&grant_type=refresh_token"; + URLEncoder.encode(clientSecret, StandardCharsets.UTF_8) + "&grant_type=refresh_token";
@ -218,33 +232,33 @@ public class ZohoOAuthManager {
String apiDomain = tokenResponse.getApi_domain(); String apiDomain = tokenResponse.getApi_domain();
if (apiDomain != null && !apiDomain.isEmpty()) { if (apiDomain != null && !apiDomain.isEmpty()) {
logger.fine("│ ├── apiDomain=" + apiDomain); logger.info("│ ├── apiDomain=" + apiDomain);
zohoConfig.setItemValue("zoho.apiDomain", apiDomain); zohoConfig.setItemValue("zoho.apiDomain", apiDomain);
} }
String scope = tokenResponse.getScope(); String scope = tokenResponse.getScope();
if (scope != null && !scope.isEmpty()) { if (scope != null && !scope.isEmpty()) {
logger.fine("│ ├── scope=" + scope); logger.info("│ ├── scope=" + scope);
zohoConfig.setItemValue("zoho.scope", scope); zohoConfig.setItemValue("zoho.scope", scope);
} }
String accessToken = tokenResponse.getAccess_token(); String accessToken = tokenResponse.getAccess_token();
if (accessToken != null && !accessToken.isEmpty()) { if (accessToken != null && !accessToken.isEmpty()) {
logger.fine("│ ├── accessToken=" + accessToken); logger.info("│ ├── accessToken=" + accessToken);
zohoConfig.setItemValue("zoho.accessToken", accessToken); zohoConfig.setItemValue("zoho.accessToken", accessToken);
} }
String refreshToken = tokenResponse.getRefresh_token(); String refreshToken = tokenResponse.getRefresh_token();
if (refreshToken != null && !refreshToken.isEmpty()) { if (refreshToken != null && !refreshToken.isEmpty()) {
logger.fine("│ ├── refreshToken=" + refreshToken); logger.info("│ ├── refreshToken=" + refreshToken);
zohoConfig.setItemValue("zoho.refreshToken", refreshToken); zohoConfig.setItemValue("zoho.refreshToken", refreshToken);
} }
logger.fine("│ ├── expires_in=" + tokenResponse.getExpires_in()); logger.info("│ ├── expires_in=" + tokenResponse.getExpires_in());
// Expires-Zeit in Millisekunden berechnen // Expires-Zeit in Millisekunden berechnen
long expiresInSeconds = tokenResponse.getExpires_in() - 60; long expiresInSeconds = tokenResponse.getExpires_in() - 60;
long currentTimeMillis = System.currentTimeMillis(); long currentTimeMillis = System.currentTimeMillis();
long expiresTimeMillis = currentTimeMillis + (expiresInSeconds * 1000); long expiresTimeMillis = currentTimeMillis + (expiresInSeconds * 1000);
// Expires-Zeit in ein Date-Objekt konvertieren // Expires-Zeit in ein Date-Objekt konvertieren
Date expiresDate = new Date(expiresTimeMillis); Date expiresDate = new Date(expiresTimeMillis);
logger.fine("│ ├── expire date=" + expiresDate); logger.info("│ ├── expire date=" + expiresDate);
zohoConfig.setItemValue("zoho.expires", expiresDate); zohoConfig.setItemValue("zoho.expires", expiresDate);
zohoConfig.setItemValue("message", "Access Token OK"); zohoConfig.setItemValue("message", "Access Token OK");
configService.save(zohoConfig); configService.save(zohoConfig);

View file

@ -0,0 +1,90 @@
package com.alexanderlogistics.zoho.dto;
import java.time.LocalDate;
import java.util.List;
import jakarta.json.bind.annotation.JsonbDateFormat;
import jakarta.json.bind.annotation.JsonbProperty;
public class ZohoBill {
@JsonbProperty("bill_id")
private String billId;
@JsonbProperty("vendor_id")
private String vendorId;
@JsonbDateFormat("yyyy-MM-dd")
private LocalDate date;
@JsonbProperty("due_date")
@JsonbDateFormat("yyyy-MM-dd")
private LocalDate dueDate;
@JsonbProperty("bill_number")
private String invoiceNumber;
@JsonbProperty("line_items")
private List<ZohoBillItem> lineItems;
private double amount;
// Getter und Setter
public String getBillId() {
return billId;
}
public void setBillId(String billId) {
this.billId = billId;
}
public String getVendorId() {
return vendorId;
}
public void setVendorId(String vendorId) {
this.vendorId = vendorId;
}
public LocalDate getDate() {
return date;
}
public void setDate(LocalDate date) {
this.date = date;
}
public LocalDate getDueDate() {
return dueDate;
}
public void setDueDate(LocalDate duedate) {
this.dueDate = duedate;
}
public String getInvoiceNumber() {
return invoiceNumber;
}
public void setInvoiceNumber(String invoiceNumber) {
this.invoiceNumber = invoiceNumber;
}
public List<ZohoBillItem> getLineItems() {
return lineItems;
}
public void setLineItems(List<ZohoBillItem> lineItems) {
this.lineItems = lineItems;
}
public double getAmount() {
return amount;
}
public void setAmount(double amount) {
this.amount = amount;
}
}

View file

@ -0,0 +1,39 @@
package com.alexanderlogistics.zoho.dto;
import jakarta.json.bind.annotation.JsonbProperty;
public class ZohoBillCreateResponse {
@JsonbProperty("code")
private int code;
@JsonbProperty("message")
private String message;
@JsonbProperty("bill")
private ZohoBill bill;
// Getter und Setter
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public ZohoBill getBill() {
return bill;
}
public void setBill(ZohoBill bill) {
this.bill = bill;
}
}

View file

@ -0,0 +1,47 @@
package com.alexanderlogistics.zoho.dto;
import jakarta.json.bind.annotation.JsonbProperty;
public class ZohoBillItem {
private String description;
private String name;
private double amount;
@JsonbProperty("account_id")
private String accountId;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
// Getter und Setter
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getAccountId() {
return accountId;
}
public void setAccountId(String accountId) {
this.accountId = accountId;
}
public double getAmount() {
return amount;
}
public void setAmount(double amount) {
this.amount = amount;
}
}

View file

@ -13,6 +13,9 @@ public class ZohoContact {
@JsonbProperty("company_name") @JsonbProperty("company_name")
private String companyName; private String companyName;
@JsonbProperty("contact_type")
private String contactType;
// Weitere Felder nach Bedarf // Weitere Felder nach Bedarf
// Getter und Setter // Getter und Setter
@ -40,4 +43,12 @@ public class ZohoContact {
this.companyName = companyName; this.companyName = companyName;
} }
public String getContactType() {
return contactType;
}
public void setContactType(String contactType) {
this.contactType = contactType;
}
} }

View file

@ -11,32 +11,42 @@ public class ZohoExpense {
@JsonbProperty("expense_id") @JsonbProperty("expense_id")
private String expenseId; private String expenseId;
@JsonbProperty("account_id")
private String accountId;
@JsonbProperty("paid_through_account_id")
private String paid_through_account_id;
@JsonbProperty("customer_id") @JsonbProperty("customer_id")
private String customerId; private String customerId;
@JsonbDateFormat("yyyy-MM-dd") @JsonbDateFormat("yyyy-MM-dd")
private LocalDate date; private LocalDate date;
@JsonbProperty("due_date")
@JsonbDateFormat("yyyy-MM-dd")
private LocalDate dueDate;
@JsonbProperty("reference_number") @JsonbProperty("reference_number")
private String invoiceNumber; private String invoiceNumber;
@JsonbProperty("line_items") @JsonbProperty("line_items")
private List<ZohoInvoiceItem> lineItems; private List<ZohoExpenseItem> lineItems;
private double total; private double amount;
// Getter und Setter // Getter und Setter
public String getInvoiceId() { public String getExpenseId() {
return invoiceId; return expenseId;
} }
public void setInvoiceId(String invoiceId) { public void setExpenseId(String expenseId) {
this.invoiceId = invoiceId; this.expenseId = expenseId;
}
public String getAccountId() {
return accountId;
}
public void setAccountId(String accountId) {
this.accountId = accountId;
} }
public String getCustomerId() { public String getCustomerId() {
@ -55,14 +65,6 @@ public class ZohoExpense {
this.date = date; this.date = date;
} }
public LocalDate getDueDate() {
return dueDate;
}
public void setDueDate(LocalDate duedate) {
this.dueDate = duedate;
}
public String getInvoiceNumber() { public String getInvoiceNumber() {
return invoiceNumber; return invoiceNumber;
} }
@ -71,19 +73,27 @@ public class ZohoExpense {
this.invoiceNumber = invoiceNumber; this.invoiceNumber = invoiceNumber;
} }
public List<ZohoInvoiceItem> getLineItems() { public List<ZohoExpenseItem> getLineItems() {
return lineItems; return lineItems;
} }
public void setLineItems(List<ZohoInvoiceItem> lineItems) { public void setLineItems(List<ZohoExpenseItem> lineItems) {
this.lineItems = lineItems; this.lineItems = lineItems;
} }
public double getTotal() { public double getAmount() {
return total; return amount;
} }
public void setTotal(double total) { public void setAmount(double amount) {
this.total = total; this.amount = amount;
}
public String getPaid_through_account_id() {
return paid_through_account_id;
}
public void setPaid_through_account_id(String paid_through_account_id) {
this.paid_through_account_id = paid_through_account_id;
} }
} }

View file

@ -0,0 +1,39 @@
package com.alexanderlogistics.zoho.dto;
import jakarta.json.bind.annotation.JsonbProperty;
public class ZohoExpenseCreateResponse {
@JsonbProperty("code")
private int code;
@JsonbProperty("message")
private String message;
@JsonbProperty("expense")
private ZohoExpense expense;
// Getter und Setter
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public ZohoExpense getExpense() {
return expense;
}
public void setExpense(ZohoExpense expense) {
this.expense = expense;
}
}

View file

@ -0,0 +1,16 @@
package com.alexanderlogistics.zoho.dto;
public class ZohoExpenseItem {
private String description;
// Getter und Setter
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}

View file

@ -42,12 +42,28 @@
<!-- API Tokens --> <!-- API Tokens -->
<div class="imixs-form-section-2"> <div class="imixs-form-section-2">
<dl>
<dt>API OAuth URL <span class="imixs-required">*</span>
</dt>
<dd>
<h:inputText required="true"
value="#{zohoController.workitem.item['zoho.oauth.uri']}">
</h:inputText>
</dd>
</dl>
<dl> <dl>
<dt>API Base URL <span class="imixs-required">*</span></dt> <dt>API Base URL <span class="imixs-required">*</span></dt>
<dd> <dd>
<h:inputText required="true" <h:inputText required="true"
value="#{zohoController.workitem.item['zoho.uri']}"> value="#{zohoController.workitem.item['zoho.uri']}">
</h:inputText> </h:inputText>
</dd> </dd>
</dl> </dl>
@ -60,6 +76,17 @@
</h:inputText> </h:inputText>
</dd> </dd>
</dl> </dl>
<dl>
<dt>Accountant ID <span class="imixs-required">*</span></dt>
<dd>
<h:inputText required="true"
value="#{zohoController.workitem.item['zoho.accountID']}">
</h:inputText>
</dd>
</dl>
<dl> <dl>
<dt>Client ID <span class="imixs-required">*</span></dt> <dt>Client ID <span class="imixs-required">*</span></dt>
<dd> <dd>
@ -106,7 +133,7 @@
Generieren Sie einen neuen Access Code Generieren Sie einen neuen Access Code
<br /> <br />
Scope: Scope:
<code>ZohoBooks.contacts.ALL,ZohoBooks.invoices.CREATE,ZohoBooks.invoices.READ,ZohoBooks.invoices.UPDATE</code> <code>ZohoBooks.contacts.ALL,ZohoBooks.invoices.ALL,ZohoBooks.bills.ALL</code>
</li> </li>
<li> <li>
Code über den Button "Create" anfordern und in das Feld "Access Code" Code über den Button "Create" anfordern und in das Feld "Access Code"

View file

@ -42,8 +42,23 @@ public class TestUpdateTokens {
private String redirectURI = "https://alexander-logistics-dwc.office-workflow.de/api/zoho/grant"; private String redirectURI = "https://alexander-logistics-dwc.office-workflow.de/api/zoho/grant";
private String clientID = "1000.GR5FTPZYB06HEWSFSSX4DJU3OBD4EJ"; // private String clientID = "1000.GR5FTPZYB06HEWSFSSX4DJU3OBD4EJ";
private String clientSecret = "3f3e74c5212bbc924a7ebf77f887c6296db1106c47"; // private String clientSecret = "3f3e74c5212bbc924a7ebf77f887c6296db1106c47";
// forum
// private String clientID = "1000.ECQXCXYOTQ9LGLRK2V4PYU94OORJKR";
// private String clientSecret = "ce93df3860fc3d804cd015a0bec9b92dcfcf6329b8";
// DWC
// private String clientID = "1000.MQE1SU8UGY6F2PBPASOXGTLWYQD1FS";
// private String clientSecret = "1ca70e1ab803b3fed6b1b5e00858c316e2003d289b";
// Atari
private String clientID = "1000.86O4P321HDYDRX0Q0N1G7YOJRJ9D5W";
private String clientSecret = "2a67b6cfc364f5df27cc8eb33e9b0e4e8a0221ebc3";
// ROLES
// ZohoBooks.contacts.ALL,ZohoBooks.invoices.ALL,ZohoBooks.bills.ALL
private String code = null; private String code = null;
private String accessToken = null; private String accessToken = null;
@ -67,14 +82,20 @@ public class TestUpdateTokens {
logger.info("├── update Zoho tokens"); logger.info("├── update Zoho tokens");
refreshToken = null; refreshToken = null;
accessToken = null; accessToken = null;
code = "1000.48bd85a3965cf724f4691757cfd8d93b.8ae5e3ee7d70f90d307da4d289a9b067"; code = "1000.d2a4e3a9622fc4c5eebe1ae5ee1989b5.d6899d23da56e6d8f73125ebaa498a3e";
try { try {
String requestUrl = "https://accounts.zoho.eu/oauth/v2/token" + "?code=" // String requestUrl = "https://accounts.zoho.eu/oauth/v2/token" + "?code="
// + URLEncoder.encode(code, StandardCharsets.UTF_8) + "&client_id="
// + URLEncoder.encode(clientID, StandardCharsets.UTF_8) + "&client_secret="
// + URLEncoder.encode(clientSecret, StandardCharsets.UTF_8) + "&redirect_uri="
// + URLEncoder.encode(redirectURI, StandardCharsets.UTF_8) +
// "&grant_type=authorization_code";
String requestUrl = "https://accounts.zoho.com/oauth/v2/token" + "?code="
+ URLEncoder.encode(code, StandardCharsets.UTF_8) + "&client_id=" + URLEncoder.encode(code, StandardCharsets.UTF_8) + "&client_id="
+ URLEncoder.encode(clientID, StandardCharsets.UTF_8) + "&client_secret=" + URLEncoder.encode(clientID, StandardCharsets.UTF_8) + "&client_secret="
+ URLEncoder.encode(clientSecret, StandardCharsets.UTF_8) + "&redirect_uri=" + URLEncoder.encode(clientSecret, StandardCharsets.UTF_8) + "&grant_type=authorization_code";
+ URLEncoder.encode(redirectURI, StandardCharsets.UTF_8) + "&grant_type=authorization_code";
logger.info("│ ├── Request URI=" + requestUrl); logger.info("│ ├── Request URI=" + requestUrl);