PagoController.java
package com.licensis.notaire.api;
import com.licensis.notaire.negocio.Pago;
import com.licensis.notaire.service.PagoService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.transaction.annotation.Transactional;
import java.util.Date;
import java.util.List;
@RestController
@RequestMapping("/api/v1/pagos")
@Tag(name = "Pago", description = "API para gestionar pagos (CU15, CU47)")
public class PagoController {
private static final Logger log = LoggerFactory.getLogger(PagoController.class);
private final PagoService pagoService;
public PagoController(PagoService pagoService) {
this.pagoService = pagoService;
}
@GetMapping
@Operation(summary = "Obtener todos los pagos")
@Transactional(readOnly = true)
public ResponseEntity<List<Pago>> getAll() {
try {
return ResponseEntity.ok(pagoService.findAll());
} catch (Exception e) {
log.error("Error al obtener pagos", e);
return ResponseEntity.internalServerError().build();
}
}
@ApiResponses({
@ApiResponse(responseCode = "200", description = "OK"),
@ApiResponse(responseCode = "404", description = "No encontrado")
})
@GetMapping("/{id}")
@Operation(summary = "CU47 - Consultar pago por ID")
@Transactional(readOnly = true)
public ResponseEntity<Pago> getById(@PathVariable Integer id) {
try {
return pagoService.consultarPago(id)
.map(ResponseEntity::ok)
.orElse(ResponseEntity.notFound().build());
} catch (Exception e) {
log.error("Error al consultar pago ID={}", id, e);
return ResponseEntity.internalServerError().build();
}
}
@GetMapping("/presupuesto/{idPresupuesto}")
@Operation(summary = "Obtener pagos por presupuesto")
@Transactional(readOnly = true)
public ResponseEntity<List<Pago>> getByPresupuesto(@PathVariable Integer idPresupuesto) {
try {
return ResponseEntity.ok(pagoService.findPagosByPresupuesto(idPresupuesto));
} catch (Exception e) {
log.error("Error al obtener pagos por presupuesto ID={}", idPresupuesto, e);
return ResponseEntity.internalServerError().build();
}
}
@GetMapping("/presupuesto/{idPresupuesto}/saldo")
@Operation(summary = "Calcular saldo pendiente de un presupuesto")
@Transactional(readOnly = true)
public ResponseEntity<Float> getSaldoPendiente(@PathVariable Integer idPresupuesto) {
try {
Float saldo = pagoService.calcularSaldoPendiente(idPresupuesto);
return ResponseEntity.ok(saldo);
} catch (IllegalArgumentException e) {
return ResponseEntity.notFound().build();
} catch (Exception e) {
log.error("Error al calcular saldo pendiente", e);
return ResponseEntity.internalServerError().build();
}
}
@GetMapping("/fecha")
@Operation(summary = "Obtener pagos por rango de fechas")
@Transactional(readOnly = true)
public ResponseEntity<List<Pago>> getByFechaRange(
@Parameter(description = "Fecha inicio (YYYY-MM-DD)")
@RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd") Date startDate,
@Parameter(description = "Fecha fin (YYYY-MM-DD)")
@RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd") Date endDate) {
try {
return ResponseEntity.ok(pagoService.findPagosByFechaRange(startDate, endDate));
} catch (Exception e) {
log.error("Error al obtener pagos por fecha", e);
return ResponseEntity.internalServerError().build();
}
}
@ApiResponses({
@ApiResponse(responseCode = "201", description = "Creado"),
@ApiResponse(responseCode = "400", description = "Solicitud inválida"),
@ApiResponse(responseCode = "409", description = "Conflicto")
})
@PostMapping
@Operation(summary = "CU15 - Procesar pago (JSON body)")
public ResponseEntity<Pago> procesarPago(@RequestBody PagoRequest request) {
try {
Pago pago = pagoService.procesarPago(
request.idPresupuesto(),
request.monto(),
request.fecha(),
request.observaciones()
);
return ResponseEntity.status(HttpStatus.CREATED).body(pago);
} catch (IllegalArgumentException e) {
log.warn("Error de validación al procesar pago: {}", e.getMessage());
return ResponseEntity.badRequest().build();
} catch (Exception e) {
log.error("Error al procesar pago", e);
return ResponseEntity.internalServerError().build();
}
}
@PostMapping("/params")
@Operation(summary = "CU15 - Procesar pago (query params)")
public ResponseEntity<Pago> procesarPagoParams(
@Parameter(description = "ID del presupuesto") @RequestParam Integer idPresupuesto,
@Parameter(description = "Monto del pago") @RequestParam Float monto,
@Parameter(description = "Fecha de pago (opcional, YYYY-MM-DD)")
@RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") Date fecha,
@Parameter(description = "Observaciones") @RequestParam(required = false) String observaciones) {
try {
Pago pago = pagoService.procesarPago(idPresupuesto, monto, fecha, observaciones);
return ResponseEntity.status(HttpStatus.CREATED).body(pago);
} catch (IllegalArgumentException e) {
log.warn("Error de validación al procesar pago: {}", e.getMessage());
return ResponseEntity.badRequest().build();
} catch (Exception e) {
log.error("Error al procesar pago", e);
return ResponseEntity.internalServerError().build();
}
}
@ApiResponses({
@ApiResponse(responseCode = "200", description = "OK"),
@ApiResponse(responseCode = "404", description = "No encontrado")
})
@PutMapping("/{id}")
@Operation(summary = "Editar pago")
public ResponseEntity<Pago> update(@PathVariable Integer id, @RequestBody Pago entity) {
try {
Pago updated = pagoService.editarPago(id, entity.getMonto(), entity.getFecha(), entity.getObservaciones());
return ResponseEntity.ok(updated);
} catch (IllegalArgumentException e) {
return ResponseEntity.notFound().build();
} catch (Exception e) {
log.error("Error al actualizar pago ID={}", id, e);
return ResponseEntity.internalServerError().build();
}
}
@ApiResponses({
@ApiResponse(responseCode = "204", description = "Eliminado"),
@ApiResponse(responseCode = "404", description = "No encontrado")
})
@DeleteMapping("/{id}")
@Operation(summary = "Eliminar pago")
public ResponseEntity<Void> delete(@PathVariable Integer id) {
try {
pagoService.deletePago(id);
return ResponseEntity.ok().build();
} catch (IllegalArgumentException e) {
return ResponseEntity.notFound().build();
} catch (Exception e) {
log.error("Error al eliminar pago ID={}", id, e);
return ResponseEntity.internalServerError().build();
}
}
public record PagoRequest(
Integer idPresupuesto,
Float monto,
Date fecha,
String observaciones
) {}
}