api product funcional

PHOTO EMBED

Wed Jan 08 2025 11:04:30 GMT+0000 (Coordinated Universal Time)

Saved by @rcrespocode

@RestResource(urlMapping='/api/products/*')
global with sharing class ProductApi {

    // GET: Recuperar productos por External_ID__c (sin captura de log)
    @HttpGet
    global static List<Product2> getProducts() {
        RestRequest req = RestContext.request;
        String externalId = req.requestURI.substringAfterLast('/');

        if (String.isNotBlank(externalId)) {
            // Recuperar producto por External_ID__c
            List<Product2> products = [SELECT Id, Name, ProductCode, Description, IsActive, External_ID__c 
                                    FROM Product2 WHERE External_ID__c = :externalId];
            return products;
        } else {
            // Recuperar todos los productos si no se proporciona External_ID__c
            List<Product2> products = [SELECT Id, Name, ProductCode, Description, IsActive, External_ID__c 
                                    FROM Product2];
            return products;
        }
    }

    // PATCH: Crear o actualizar un producto y establecer su precio usando solo External_ID__c
    @HttpPatch
    global static Product2 upsertProduct(
        String externalId, 
        String name, 
        String productCode, 
        String description, 
        Boolean isActive, 
        Decimal price
    ) {
        RestRequest req = RestContext.request;
        Product2 product = null;
        try {
            if (String.isBlank(externalId)) {
                throw new CustomException('El campo External_ID__c es obligatorio para realizar un upsert.');
            }

            if (price == null || price < 0) {
                throw new CustomException('El precio debe ser un valor positivo.');
            }

            // Crear o actualizar el producto basado en External_ID__c
            product = new Product2(
                External_ID__c = externalId,
                Name = name,
                ProductCode = productCode,
                Description = description,
                IsActive = isActive
            );

            upsert product External_ID__c;

            // Buscar el Standard Pricebook
            List<Pricebook2> standardPricebookList = [SELECT Id FROM Pricebook2 WHERE IsStandard = true LIMIT 1];
            if (standardPricebookList.isEmpty()) {
                throw new CustomException('No se encontró el Standard Pricebook.');
            }
            Pricebook2 standardPricebook = standardPricebookList[0];

            // Verificar si ya existe un PricebookEntry para este producto
            List<PricebookEntry> existingEntries = [
                SELECT Id, UnitPrice 
                FROM PricebookEntry 
                WHERE Product2Id = :product.Id AND Pricebook2Id = :standardPricebook.Id
            ];

            if (existingEntries.isEmpty()) {
                // Crear un nuevo PricebookEntry si no existe
                PricebookEntry newEntry = new PricebookEntry(
                    Pricebook2Id = standardPricebook.Id,
                    Product2Id = product.Id,
                    UnitPrice = price,
                    IsActive = true
                );
                insert newEntry;
            } else {
                // Actualizar el PricebookEntry existente
                PricebookEntry existingEntry = existingEntries[0];
                existingEntry.UnitPrice = price;
                update existingEntry;
            }

            // Log success
            logIntegrationDetails('PATCH', req, product, null);  // No hay error, pasamos null para la excepción

            return product;
        } catch (Exception e) {
            // Log error
            logIntegrationDetails('PATCH', req, null, e);  // Capturamos el error y lo pasamos al log
            throw e;  // Vuelve a lanzar la excepción para que se maneje como corresponde
        }
    }

    // DELETE: Eliminar un producto por External_ID__c
    @HttpDelete
    global static void deleteProduct() {
        RestRequest req = RestContext.request;
        String productIdOrExternalId = req.requestURI.substringAfterLast('/');

        if (String.isBlank(productIdOrExternalId)) {
            throw new CustomException('Debe proporcionar el ID o el External_ID__c para eliminar.');
        }

        Product2 productToDelete;

        if (productIdOrExternalId.startsWith('a') && productIdOrExternalId.length() == 18) {
            // Buscar por Id estándar
            productToDelete = [SELECT Id, IsDeleted FROM Product2 WHERE Id = :productIdOrExternalId AND IsDeleted = false LIMIT 1];
        } else {
            // Buscar por External_ID__c
            productToDelete = [SELECT Id, IsDeleted FROM Product2 WHERE External_ID__c = :productIdOrExternalId AND IsDeleted = false LIMIT 1];
        }

        // Si el producto no existe o está eliminado, lanzamos una excepción
        if (productToDelete == null || productToDelete.IsDeleted) {
            throw new CustomException('El producto no existe o ha sido eliminado.');
        }

        // Eliminar cualquier PricebookEntry relacionado en el Standard Pricebook
        List<Pricebook2> standardPricebookList = [SELECT Id FROM Pricebook2 WHERE IsStandard = true LIMIT 1];
        if (!standardPricebookList.isEmpty()) {
            Pricebook2 standardPricebook = standardPricebookList[0];
            List<PricebookEntry> entriesToDelete = [
                SELECT Id 
                FROM PricebookEntry 
                WHERE Product2Id = :productToDelete.Id AND Pricebook2Id = :standardPricebook.Id
            ];
            delete entriesToDelete;
        }

        delete productToDelete;

        // Registrar el log de la integración
        try {
            logIntegrationDetails('DELETE', req, productToDelete, null);
        } catch (Exception e) {
            // Si algo sale mal, capturamos la excepción y la mostramos (aunque puede que ya esté registrada)
            System.debug('Error al registrar el log: ' + e.getMessage());
        }
    }

    // Método auxiliar para registrar los detalles de las solicitudes y respuestas en Integration_Log__c
    
    private static void logIntegrationDetails(String operation, RestRequest req, SObject response, Exception e) {
        // Crear el log de la solicitud y la respuesta
        Integration_Log__c log = new Integration_Log__c();
    
        // Si ocurrió un error, capturamos la excepción
        if (e != null) {
            log.Estado__c = 'Error';
            log.Response__c = 'Error: ' + e.getMessage();  // Guardamos el mensaje de la excepción en Response__c
        } else {
            log.Estado__c = 'Success';  // Si todo fue exitoso, lo marcamos como "Success"
            log.Response__c = JSON.serialize(response);  // Serializamos la respuesta
        }
    
        // Asignar el nombre del log con el nombre del objeto y la fecha actual
        String logName = (response != null ? response.getSObjectType().getDescribe().getName() : 'UnknownObject') + ' - ' + DateTime.now().format();
        log.Name = logName;
    
        // Capturamos los parámetros de la solicitud
        log.Request__c = 'Params: ' + req.params;
    
        // Si se está creando/actualizando un producto, asociamos el producto con el log
        if (response instanceof Product2) {
            log.Product__c = ((Product2) response).Id;
        }
    
        insert log; // Insertamos el log en la base de datos
    }
    
    // Clase de excepción personalizada
    global class CustomException extends Exception {}
}
content_copyCOPY