zoho credit note
This commit is contained in:
parent
8d236df375
commit
d4f1bd318e
5 changed files with 296 additions and 11 deletions
|
|
@ -30,6 +30,8 @@ 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.ZohoCreditnote;
|
||||||
|
import com.alexanderlogistics.zoho.dto.ZohoCreditnoteCreateResponse;
|
||||||
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;
|
||||||
|
|
@ -197,6 +199,76 @@ public class ZohoAPIService {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exports an Credit Note - outgoing invoice total < 0,00
|
||||||
|
*
|
||||||
|
* @see https://www.zoho.com/books/api/v3/expenses/#create-an-expense
|
||||||
|
*
|
||||||
|
* @param invoice
|
||||||
|
* @throws PluginException
|
||||||
|
*/
|
||||||
|
public ZohoCreditnote exportCreditnote(ItemCollection invoice, String contactID,
|
||||||
|
String accessToken) throws PluginException {
|
||||||
|
logger.info("├── Zoho Export creditnote " + invoice.getItemValueString("invoice.number") + "...");
|
||||||
|
|
||||||
|
// Konvertiere ItemCollection zu ZohoInvoiceDTO
|
||||||
|
ZohoCreditnote zohoCreditnote = convertToZohoCreditnote(invoice, contactID);
|
||||||
|
|
||||||
|
try {
|
||||||
|
String requestBody = jsonb.toJson(zohoCreditnote);
|
||||||
|
|
||||||
|
// Print JSON to console for verification
|
||||||
|
logger.fine("├── Zoho CreditNote JSON Request...");
|
||||||
|
logger.fine("│ ├── " + requestBody);
|
||||||
|
|
||||||
|
// https://www.zohoapis.com/books/v3/creditnotes?organization_id=10234695'
|
||||||
|
String uri = zohoOAuthManager.getBaseURI() + "creditnotes?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 creditnote. Status code: " + response.statusCode() + ", Response: "
|
||||||
|
+ response.body());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Erfolgreiche Erstellung
|
||||||
|
String bodyContent = response.body();
|
||||||
|
logger.fine("│ ├── Response Body: " + bodyContent);
|
||||||
|
|
||||||
|
System.out.print(bodyContent);
|
||||||
|
ZohoCreditnoteCreateResponse createResponse = jsonb.fromJson(bodyContent,
|
||||||
|
ZohoCreditnoteCreateResponse.class);
|
||||||
|
|
||||||
|
if (createResponse != null) {
|
||||||
|
logger.info("│ ├── OK - customerID=" + createResponse.getCreditnote().getCustomerId());
|
||||||
|
logger.info("│ ├── OK - creditNoteID=" + createResponse.getCreditnote().getCreditNoteNumber());
|
||||||
|
zohoCreditnote = createResponse.getCreditnote();
|
||||||
|
|
||||||
|
// now mark the invoice as send
|
||||||
|
logger.info("│ ├── VendorCredit Export successful.");
|
||||||
|
return zohoCreditnote;
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (IOException | InterruptedException e) {
|
||||||
|
throw new PluginException(this.getClass().getName(), "Zoho API error",
|
||||||
|
"Failed to export creditnote to Zoho: " + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Exports an Eingangsrechnung document
|
* Exports an Eingangsrechnung document
|
||||||
*
|
*
|
||||||
|
|
@ -421,6 +493,7 @@ public class ZohoAPIService {
|
||||||
zohoInvoice.setTotal(convertInvoiceTotalToAED(invoice, invoice.getItemValueDouble("invoice.total")));
|
zohoInvoice.setTotal(convertInvoiceTotalToAED(invoice, invoice.getItemValueDouble("invoice.total")));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
* Change: 10.06.2025
|
||||||
* Das Cargosoft unlogische Positionen sendet, ZOHO diese aber erzwingt,
|
* Das Cargosoft unlogische Positionen sendet, ZOHO diese aber erzwingt,
|
||||||
* erzeugen wir nur noch eine einzige Zeile mit dem tatsächlichen Betrag!
|
* erzeugen wir nur noch eine einzige Zeile mit dem tatsächlichen Betrag!
|
||||||
*
|
*
|
||||||
|
|
@ -448,6 +521,54 @@ public class ZohoAPIService {
|
||||||
return zohoInvoice;
|
return zohoInvoice;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ZohoCreditnote convertToZohoCreditnote(ItemCollection invoice, String contactID)
|
||||||
|
throws PluginException {
|
||||||
|
|
||||||
|
ZohoCreditnote zohoCreditnote = new ZohoCreditnote();
|
||||||
|
// Basisinformationen
|
||||||
|
|
||||||
|
zohoCreditnote.setCreditNoteNumber(invoice.getItemValueString("invoice.number"));
|
||||||
|
zohoCreditnote.setDate(
|
||||||
|
LocalDate.ofInstant(invoice.getItemValueDate("invoice.date").toInstant(), ZoneId.systemDefault()));
|
||||||
|
zohoCreditnote.setDueDate(
|
||||||
|
LocalDate.ofInstant(invoice.getItemValueDate("invoice.duedate").toInstant(), ZoneId.systemDefault()));
|
||||||
|
|
||||||
|
zohoCreditnote.setCustomerId(contactID);
|
||||||
|
|
||||||
|
// convert total by rate - negativer betrag!
|
||||||
|
zohoCreditnote
|
||||||
|
.setTotal(convertInvoiceTotalToAED(invoice, Math.abs(invoice.getItemValueDouble("invoice.total"))));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Change: 10.06.2025
|
||||||
|
* Das Cargosoft unlogische Positionen sendet, ZOHO diese aber erzwingt,
|
||||||
|
* erzeugen wir nur noch eine einzige Zeile mit dem tatsächlichen Betrag!
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
// List<ItemCollection> positionen = InvoiceUtil.explodeChildList(invoice);
|
||||||
|
// List<ZohoInvoiceItem> lineItems = positionen.stream().map(item -> {
|
||||||
|
// ItemCollection itemCol = (ItemCollection) item;
|
||||||
|
// ZohoInvoiceItem lineItem = new ZohoInvoiceItem();
|
||||||
|
// lineItem.setName(itemCol.getItemValueString("datev.text"));
|
||||||
|
// lineItem.setDescription(itemCol.getItemValueString("billingtext"));
|
||||||
|
// lineItem.setRate(convertInvoiceTotalToAED(invoice,
|
||||||
|
// itemCol.getItemValueDouble("datev.umsatz")));
|
||||||
|
// lineItem.setQuantity(1);
|
||||||
|
// return lineItem;
|
||||||
|
// }).collect(Collectors.toList());
|
||||||
|
List<ZohoInvoiceItem> lineItems = new ArrayList<>();
|
||||||
|
ZohoInvoiceItem lineItem = new ZohoInvoiceItem();
|
||||||
|
lineItem.setName(invoice.getItemValueString("invoice.text"));
|
||||||
|
lineItem.setDescription("");
|
||||||
|
// negativer Betrag!
|
||||||
|
lineItem.setRate(convertInvoiceTotalToAED(invoice, Math.abs(invoice.getItemValueDouble("invoice.total"))));
|
||||||
|
lineItem.setQuantity(1);
|
||||||
|
lineItems.add(lineItem);
|
||||||
|
|
||||||
|
zohoCreditnote.setLineItems(lineItems);
|
||||||
|
return zohoCreditnote;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Diese Hilfsmethode rechnet den Rechnungsbetrag in Fremdwährung auf AED um
|
* Diese Hilfsmethode rechnet den Rechnungsbetrag in Fremdwährung auf AED um
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ 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.ZohoBill;
|
||||||
|
import com.alexanderlogistics.zoho.dto.ZohoCreditnote;
|
||||||
import com.alexanderlogistics.zoho.dto.ZohoInvoice;
|
import com.alexanderlogistics.zoho.dto.ZohoInvoice;
|
||||||
import com.alexanderlogistics.zoho.dto.ZohoVendorCredit;
|
import com.alexanderlogistics.zoho.dto.ZohoVendorCredit;
|
||||||
|
|
||||||
|
|
@ -90,21 +91,46 @@ public class ZohoExportAdapter implements SignalAdapter {
|
||||||
// String currencyID =
|
// String currencyID =
|
||||||
// zohoAPIService.lookupCurrency(document.getItemValueString("invoice.currency"),
|
// zohoAPIService.lookupCurrency(document.getItemValueString("invoice.currency"),
|
||||||
// accessToken);
|
// accessToken);
|
||||||
ZohoInvoice zohoInvoice = zohoAPIService.exportInvoice(document, contactID, accessToken);
|
|
||||||
|
|
||||||
// Attache Files....
|
// Gutschrift??
|
||||||
List<FileData> files = null;
|
if (document.getItemValueDouble("invoice.total") < 0) {
|
||||||
ItemCollection snapshot = snapshotService.findSnapshot(document);
|
// create credit note!
|
||||||
if (snapshot != null) {
|
logger.info("├── CreditNote Export");
|
||||||
files = snapshot.getFileData();
|
ZohoCreditnote zohoCreditnote = zohoAPIService.exportCreditnote(document, contactID, accessToken);
|
||||||
if (files != null) {
|
|
||||||
for (FileData file : files) {
|
// Attache Files....
|
||||||
if (file.getName().toLowerCase().endsWith(".pdf")) {
|
List<FileData> files = null;
|
||||||
zohoAPIService.attacheFileData(zohoInvoice.getInvoiceId(), file, "invoices", accessToken);
|
ItemCollection snapshot = snapshotService.findSnapshot(document);
|
||||||
|
if (snapshot != null) {
|
||||||
|
files = snapshot.getFileData();
|
||||||
|
if (files != null) {
|
||||||
|
for (FileData file : files) {
|
||||||
|
if (file.getName().toLowerCase().endsWith(".pdf")) {
|
||||||
|
zohoAPIService.attacheFileData(zohoCreditnote.getCreditnoteId(), file, "creditnotes",
|
||||||
|
accessToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logger.info("├── Invoice Export");
|
||||||
|
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) {
|
||||||
|
if (file.getName().toLowerCase().endsWith(".pdf")) {
|
||||||
|
zohoAPIService.attacheFileData(zohoInvoice.getInvoiceId(), file, "invoices", accessToken);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,99 @@
|
||||||
|
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 ZohoCreditnote {
|
||||||
|
@JsonbProperty("creditnote_id")
|
||||||
|
private String creditnoteId;
|
||||||
|
|
||||||
|
@JsonbProperty("customer_id")
|
||||||
|
private String customerId;
|
||||||
|
|
||||||
|
@JsonbProperty("currency_id")
|
||||||
|
private String currencyId;
|
||||||
|
|
||||||
|
@JsonbDateFormat("yyyy-MM-dd")
|
||||||
|
private LocalDate date;
|
||||||
|
|
||||||
|
@JsonbProperty("due_date")
|
||||||
|
@JsonbDateFormat("yyyy-MM-dd")
|
||||||
|
private LocalDate dueDate;
|
||||||
|
|
||||||
|
@JsonbProperty("creditnote_number")
|
||||||
|
private String creditNoteNumber;
|
||||||
|
|
||||||
|
@JsonbProperty("line_items")
|
||||||
|
private List<ZohoInvoiceItem> lineItems;
|
||||||
|
|
||||||
|
private double total;
|
||||||
|
|
||||||
|
// Getter und Setter
|
||||||
|
|
||||||
|
public String getCreditnoteId() {
|
||||||
|
return creditnoteId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCreditnoteId(String creditnoteId) {
|
||||||
|
this.creditnoteId = creditnoteId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCustomerId() {
|
||||||
|
return customerId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCustomerId(String customerId) {
|
||||||
|
this.customerId = customerId;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 getCreditNoteNumber() {
|
||||||
|
return creditNoteNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCreditNoteNumber(String creditNoteNumber) {
|
||||||
|
this.creditNoteNumber = creditNoteNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<ZohoInvoiceItem> getLineItems() {
|
||||||
|
return lineItems;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLineItems(List<ZohoInvoiceItem> lineItems) {
|
||||||
|
this.lineItems = lineItems;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getTotal() {
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTotal(double total) {
|
||||||
|
this.total = total;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCurrencyId() {
|
||||||
|
return currencyId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCurrencyId(String currencyId) {
|
||||||
|
this.currencyId = currencyId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
package com.alexanderlogistics.zoho.dto;
|
||||||
|
|
||||||
|
import jakarta.json.bind.annotation.JsonbProperty;
|
||||||
|
|
||||||
|
public class ZohoCreditnoteCreateResponse {
|
||||||
|
@JsonbProperty("code")
|
||||||
|
private int code;
|
||||||
|
|
||||||
|
@JsonbProperty("message")
|
||||||
|
private String message;
|
||||||
|
|
||||||
|
@JsonbProperty("creditnote")
|
||||||
|
private ZohoCreditnote creditnote;
|
||||||
|
|
||||||
|
// 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 ZohoCreditnote getCreditnote() {
|
||||||
|
return creditnote;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCreditnote(ZohoCreditnote creditnote) {
|
||||||
|
this.creditnote = creditnote;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -137,7 +137,7 @@
|
||||||
Generieren Sie einen neuen Access Code
|
Generieren Sie einen neuen Access Code
|
||||||
<br />
|
<br />
|
||||||
Scope:
|
Scope:
|
||||||
<code>ZohoBooks.contacts.ALL,ZohoBooks.invoices.ALL,ZohoBooks.bills.ALL,ZohoBooks.debitnotes.ALL,ZohoBooks.settings.READ</code>
|
<code>ZohoBooks.contacts.ALL,ZohoBooks.invoices.ALL,ZohoBooks.creditnotes.ALL,ZohoBooks.bills.ALL,ZohoBooks.debitnotes.ALL,ZohoBooks.settings.READ</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"
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue