diff --git a/sync-service/src/main/java/com/teterialosjuanjos/tfg/sync_service/integration/dolibarr/DolibarrClient.java b/sync-service/src/main/java/com/teterialosjuanjos/tfg/sync_service/integration/dolibarr/DolibarrClient.java index 1d55fc4..a450009 100644 --- a/sync-service/src/main/java/com/teterialosjuanjos/tfg/sync_service/integration/dolibarr/DolibarrClient.java +++ b/sync-service/src/main/java/com/teterialosjuanjos/tfg/sync_service/integration/dolibarr/DolibarrClient.java @@ -9,7 +9,6 @@ import org.springframework.stereotype.Component; import org.springframework.web.client.RestClient; import java.util.List; -import java.util.Map; /** * Typed HTTP client for the Dolibarr REST API. @@ -182,17 +181,38 @@ public class DolibarrClient { // ── Invoices ───────────────────────────────────────────────────────── /** - * Creates an invoice linked to an existing order. + * Creates an invoice linked to an existing Dolibarr order, copying its lines. * - * @param orderId Dolibarr internal order ID - * @param socid customer (thirdparty) internal ID — required by Dolibarr even with fk_commande + *

Dolibarr's {@code POST /invoices} does not copy order lines automatically when + * only {@code fk_commande + socid} are sent — lines must be included in the body.

+ * + * @param order the created order (must have {@code id}, {@code socid}, and {@code lines}) */ - public DolibarrInvoiceDto createInvoiceFromOrder(Integer orderId, Integer socid) { - log.debug("Creating Dolibarr invoice from orderId={}", orderId); - Map body = Map.of("fk_commande", orderId, "socid", socid); + public DolibarrInvoiceDto createInvoiceFromOrder(DolibarrOrderDto order) { + log.debug("Creating Dolibarr invoice from orderId={}", order.id()); + + List invoiceLines = order.lines() == null + ? List.of() + : order.lines().stream() + .map(l -> DolibarrInvoiceDto.InvoiceLine.builder() + .fkProduct(l.fkProduct()) + .productRef(l.productRef()) + .desc(l.desc()) + .subprice(l.subprice()) + .qty(l.qty()) + .tvaTx(l.tvaTx()) + .build()) + .toList(); + + DolibarrInvoiceDto invoiceBody = DolibarrInvoiceDto.builder() + .fkCommande(order.id()) + .socid(order.socid()) + .lines(invoiceLines) + .build(); + Integer newId = restClient.post() .uri("/invoices") - .body(body) + .body(invoiceBody) .retrieve() .body(Integer.class); diff --git a/sync-service/src/main/java/com/teterialosjuanjos/tfg/sync_service/integration/dolibarr/dto/DolibarrInvoiceDto.java b/sync-service/src/main/java/com/teterialosjuanjos/tfg/sync_service/integration/dolibarr/dto/DolibarrInvoiceDto.java index c37b3b1..9a04475 100644 --- a/sync-service/src/main/java/com/teterialosjuanjos/tfg/sync_service/integration/dolibarr/dto/DolibarrInvoiceDto.java +++ b/sync-service/src/main/java/com/teterialosjuanjos/tfg/sync_service/integration/dolibarr/dto/DolibarrInvoiceDto.java @@ -3,18 +3,41 @@ package com.teterialosjuanjos.tfg.sync_service.integration.dolibarr.dto; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Builder; + +import java.util.List; /** - * Minimal representation of a Dolibarr invoice. - * Used for {@code GET /invoices/{id}} responses after creation via {@code POST /invoices}. + * Represents a Dolibarr invoice. + * Used for {@code POST /invoices} request bodies (with lines) and {@code GET /invoices/{id}} responses. */ +@Builder @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_NULL) public record DolibarrInvoiceDto( Integer id, String ref, + Integer socid, /** Linked order internal ID */ @JsonProperty("fk_commande") Integer fkCommande, /** 0 = draft, 1 = validated, 2 = paid, 3 = abandoned */ - Integer statut -) {} + Integer statut, + List lines +) { + + /** + * One line of an invoice. Mirrors {@link DolibarrOrderDto.OrderLine} fields + * so order lines can be copied directly into the invoice on creation. + */ + @Builder + @JsonIgnoreProperties(ignoreUnknown = true) + @JsonInclude(JsonInclude.Include.NON_NULL) + public record InvoiceLine( + @JsonProperty("fk_product") Integer fkProduct, + @JsonProperty("product_ref") String productRef, + String desc, + Double subprice, + Double qty, + @JsonProperty("tva_tx") Double tvaTx + ) {} +} diff --git a/sync-service/src/main/java/com/teterialosjuanjos/tfg/sync_service/sync/OrderSyncService.java b/sync-service/src/main/java/com/teterialosjuanjos/tfg/sync_service/sync/OrderSyncService.java index b5128ff..6496503 100644 --- a/sync-service/src/main/java/com/teterialosjuanjos/tfg/sync_service/sync/OrderSyncService.java +++ b/sync-service/src/main/java/com/teterialosjuanjos/tfg/sync_service/sync/OrderSyncService.java @@ -130,9 +130,8 @@ public class OrderSyncService { DolibarrOrderDto createdOrder = dolibarrClient.createOrder(orderDto); - // 3. Create linked invoice - DolibarrInvoiceDto invoice = dolibarrClient.createInvoiceFromOrder( - createdOrder.id(), customer.id()); + // 3. Create linked invoice with lines copied from the order + DolibarrInvoiceDto invoice = dolibarrClient.createInvoiceFromOrder(createdOrder); // 4. Persist mapping to prevent re-import orderMappingRepository.save(OrderMapping.builder()