2026-04-15 14:29:05 +00:00
|
|
|
|
using DoliMiddlewareApi.Dtos.command;
|
2026-04-16 07:41:46 +00:00
|
|
|
|
using DoliMiddlewareApi.Dtos.Dolibarr;
|
feat: add Contacts & Setup controllers, extend Clients/Invoices/Document controllers
- ContactsController: full CRUD (list, get, get by email, create, update, delete)
- SetupController: dictionary endpoints (payment-types, countries, civilities,
contact-types, payment-terms, company)
- ClientsController: added GET/{id}, POST, PUT/{id}, DELETE/{id}
- InvoicesController: added PUT/{id}/lines/{lineId}, GET /templates
- DocumentController: added GET /list and GET /download endpoints
- ClientService: added GetClientAsync, CreateClientAsync, UpdateClientAsync,
DeleteClientAsync
- InvoiceService: added UpdateInvoiceLineAsync, GetInvoiceTemplatesAsync
- DocumentService: added GetDocumentsAsync, DownloadDocumentAsync (using
new GetAsyncRaw on IDolibarrApiClient)
- ContactService: new service with CRUD operations
- SetupService: new service for Dolibarr dictionary data
- IDolibarrApiClient: added GetAsyncRaw method for raw string responses
- DolibarrApiClient: implemented GetAsyncRaw
- JwtTokenProvider: extended token expiry from 30 min to 8 hours
- AuthApplicationService: extended Dolibarr token cache from 30 min to 8 hours
2026-05-15 16:58:35 +00:00
|
|
|
|
using DoliMiddlewareApi.Exceptions;
|
2026-04-15 14:29:05 +00:00
|
|
|
|
using DoliMiddlewareApi.Services.Clients;
|
2026-04-16 07:41:46 +00:00
|
|
|
|
using System.Text.Json;
|
2026-04-15 14:29:05 +00:00
|
|
|
|
|
feat: add Contacts & Setup controllers, extend Clients/Invoices/Document controllers
- ContactsController: full CRUD (list, get, get by email, create, update, delete)
- SetupController: dictionary endpoints (payment-types, countries, civilities,
contact-types, payment-terms, company)
- ClientsController: added GET/{id}, POST, PUT/{id}, DELETE/{id}
- InvoicesController: added PUT/{id}/lines/{lineId}, GET /templates
- DocumentController: added GET /list and GET /download endpoints
- ClientService: added GetClientAsync, CreateClientAsync, UpdateClientAsync,
DeleteClientAsync
- InvoiceService: added UpdateInvoiceLineAsync, GetInvoiceTemplatesAsync
- DocumentService: added GetDocumentsAsync, DownloadDocumentAsync (using
new GetAsyncRaw on IDolibarrApiClient)
- ContactService: new service with CRUD operations
- SetupService: new service for Dolibarr dictionary data
- IDolibarrApiClient: added GetAsyncRaw method for raw string responses
- DolibarrApiClient: implemented GetAsyncRaw
- JwtTokenProvider: extended token expiry from 30 min to 8 hours
- AuthApplicationService: extended Dolibarr token cache from 30 min to 8 hours
2026-05-15 16:58:35 +00:00
|
|
|
|
namespace DoliMiddlewareApi.Services;
|
|
|
|
|
|
|
2026-04-16 07:41:46 +00:00
|
|
|
|
public class DocumentService(IDolibarrApiClient apiClient)
|
2026-04-15 14:29:05 +00:00
|
|
|
|
{
|
2026-04-16 07:41:46 +00:00
|
|
|
|
public async Task<(byte[] content, string filename)> BuildInvoicePdfAsync(string invoiceRef)
|
2026-04-15 14:29:05 +00:00
|
|
|
|
{
|
2026-04-16 07:41:46 +00:00
|
|
|
|
var request = new BuildDocumentRequest
|
2026-04-15 14:29:05 +00:00
|
|
|
|
{
|
2026-04-16 07:41:46 +00:00
|
|
|
|
modulepart = "invoice",
|
|
|
|
|
|
original_file = $"{invoiceRef}/{invoiceRef}.pdf",
|
|
|
|
|
|
doctemplate = "crabe",
|
|
|
|
|
|
langcode = "es_ES"
|
|
|
|
|
|
};
|
2026-04-15 14:49:41 +00:00
|
|
|
|
|
2026-04-16 07:41:46 +00:00
|
|
|
|
var response = await apiClient.PutAsync("documents/builddoc", request);
|
2026-04-15 14:49:41 +00:00
|
|
|
|
|
2026-04-16 07:41:46 +00:00
|
|
|
|
var result = JsonSerializer.Deserialize<DolibarrPdfResponse>(response);
|
2026-04-15 14:49:41 +00:00
|
|
|
|
|
2026-04-16 07:41:46 +00:00
|
|
|
|
if (result == null || string.IsNullOrEmpty(result.content))
|
|
|
|
|
|
throw new Exception("Dolibarr no devolvió PDF");
|
2026-04-15 14:49:41 +00:00
|
|
|
|
|
2026-04-16 07:41:46 +00:00
|
|
|
|
var bytes = Convert.FromBase64String(result.content);
|
2026-04-15 14:49:41 +00:00
|
|
|
|
|
2026-04-16 07:41:46 +00:00
|
|
|
|
return (bytes, result.filename);
|
2026-04-15 14:29:05 +00:00
|
|
|
|
}
|
2026-04-16 07:41:46 +00:00
|
|
|
|
|
feat: add Contacts & Setup controllers, extend Clients/Invoices/Document controllers
- ContactsController: full CRUD (list, get, get by email, create, update, delete)
- SetupController: dictionary endpoints (payment-types, countries, civilities,
contact-types, payment-terms, company)
- ClientsController: added GET/{id}, POST, PUT/{id}, DELETE/{id}
- InvoicesController: added PUT/{id}/lines/{lineId}, GET /templates
- DocumentController: added GET /list and GET /download endpoints
- ClientService: added GetClientAsync, CreateClientAsync, UpdateClientAsync,
DeleteClientAsync
- InvoiceService: added UpdateInvoiceLineAsync, GetInvoiceTemplatesAsync
- DocumentService: added GetDocumentsAsync, DownloadDocumentAsync (using
new GetAsyncRaw on IDolibarrApiClient)
- ContactService: new service with CRUD operations
- SetupService: new service for Dolibarr dictionary data
- IDolibarrApiClient: added GetAsyncRaw method for raw string responses
- DolibarrApiClient: implemented GetAsyncRaw
- JwtTokenProvider: extended token expiry from 30 min to 8 hours
- AuthApplicationService: extended Dolibarr token cache from 30 min to 8 hours
2026-05-15 16:58:35 +00:00
|
|
|
|
public async Task<List<DocumentItem>> GetDocumentsAsync(string modulePart, string refOrSocid)
|
|
|
|
|
|
{
|
|
|
|
|
|
var endpoint = $"documents?modulepart={modulePart}&ref={Uri.EscapeDataString(refOrSocid)}";
|
|
|
|
|
|
var responseString = await apiClient.GetAsyncRaw(endpoint);
|
|
|
|
|
|
|
|
|
|
|
|
var response = JsonSerializer.Deserialize<List<Dictionary<string, JsonElement>>>(responseString);
|
|
|
|
|
|
|
|
|
|
|
|
if (response == null)
|
|
|
|
|
|
return new List<DocumentItem>();
|
|
|
|
|
|
|
|
|
|
|
|
return response.Select(d =>
|
|
|
|
|
|
{
|
|
|
|
|
|
var name = d.TryGetValue("name", out var nameProp) && nameProp.ValueKind == JsonValueKind.String
|
|
|
|
|
|
? nameProp.GetString() : null;
|
|
|
|
|
|
var path = d.TryGetValue("path", out var pathProp) && pathProp.ValueKind == JsonValueKind.String
|
|
|
|
|
|
? pathProp.GetString() : null;
|
|
|
|
|
|
var size = d.TryGetValue("size", out var sizeProp) && sizeProp.ValueKind == JsonValueKind.Number
|
|
|
|
|
|
? sizeProp.GetInt64() : 0;
|
|
|
|
|
|
|
|
|
|
|
|
return new DocumentItem
|
|
|
|
|
|
{
|
|
|
|
|
|
Name = name,
|
|
|
|
|
|
Path = path,
|
|
|
|
|
|
Size = size
|
|
|
|
|
|
};
|
|
|
|
|
|
}).ToList();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public async Task<(byte[] content, string filename, string contentType)> DownloadDocumentAsync(string modulePart, string fileRef)
|
|
|
|
|
|
{
|
|
|
|
|
|
var endpoint = $"documents/download?modulepart={modulePart}&file={Uri.EscapeDataString(fileRef)}";
|
|
|
|
|
|
var responseString = await apiClient.GetAsyncRaw(endpoint);
|
|
|
|
|
|
|
|
|
|
|
|
var response = JsonSerializer.Deserialize<DolibarrPdfResponse>(responseString);
|
|
|
|
|
|
|
|
|
|
|
|
if (response == null || string.IsNullOrEmpty(response.content))
|
|
|
|
|
|
throw new NotFoundException("Documento no encontrado");
|
|
|
|
|
|
|
|
|
|
|
|
var bytes = Convert.FromBase64String(response.content);
|
|
|
|
|
|
var filename = response.filename ?? "document";
|
|
|
|
|
|
var contentType = filename.EndsWith(".pdf", StringComparison.OrdinalIgnoreCase)
|
|
|
|
|
|
? "application/pdf"
|
|
|
|
|
|
: "application/octet-stream";
|
|
|
|
|
|
|
|
|
|
|
|
return (bytes, filename, contentType);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public class DocumentItem
|
|
|
|
|
|
{
|
|
|
|
|
|
public string? Name { get; set; }
|
|
|
|
|
|
public string? Path { get; set; }
|
|
|
|
|
|
public long Size { get; set; }
|
2026-04-16 07:41:46 +00:00
|
|
|
|
}
|