Initial commit: proyecto ContabilidadSaPolar completo
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
package com.sapolar.maintenance;
|
||||
|
||||
import com.sapolar.auth.SecurityUser;
|
||||
import com.sapolar.common.dto.ApiResponse;
|
||||
import com.sapolar.finance.expense.ExpenseCategory;
|
||||
import com.sapolar.finance.expense.ExpenseCategoryRepository;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/maintenance")
|
||||
@RequiredArgsConstructor
|
||||
public class MaintenanceController {
|
||||
|
||||
private final MaintenanceService maintenanceService;
|
||||
private final ExpenseCategoryRepository expenseCategoryRepository;
|
||||
|
||||
@GetMapping
|
||||
public ResponseEntity<ApiResponse<List<ScheduledMaintenance>>> findAll(
|
||||
@RequestParam(required = false) Long propertyId) {
|
||||
if (propertyId != null) {
|
||||
return ResponseEntity.ok(ApiResponse.success(maintenanceService.findByProperty(propertyId)));
|
||||
}
|
||||
return ResponseEntity.ok(ApiResponse.success(maintenanceService.findAll()));
|
||||
}
|
||||
|
||||
@GetMapping("/pending")
|
||||
public ResponseEntity<ApiResponse<List<ScheduledMaintenance>>> getPending() {
|
||||
return ResponseEntity.ok(ApiResponse.success(maintenanceService.findPending()));
|
||||
}
|
||||
|
||||
@GetMapping("/upcoming")
|
||||
public ResponseEntity<ApiResponse<List<ScheduledMaintenance>>> getUpcoming(
|
||||
@RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate from,
|
||||
@RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate to) {
|
||||
return ResponseEntity.ok(ApiResponse.success(maintenanceService.findUpcoming(from, to)));
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<ScheduledMaintenance>> findById(@PathVariable Long id) {
|
||||
return ResponseEntity.ok(ApiResponse.success(maintenanceService.findById(id)));
|
||||
}
|
||||
|
||||
@GetMapping("/expense-categories")
|
||||
public ResponseEntity<ApiResponse<List<ExpenseCategory>>> getExpenseCategories() {
|
||||
return ResponseEntity.ok(ApiResponse.success(expenseCategoryRepository.findAll()));
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public ResponseEntity<ApiResponse<ScheduledMaintenance>> create(@RequestBody ScheduledMaintenance maintenance,
|
||||
@AuthenticationPrincipal SecurityUser user) {
|
||||
return ResponseEntity.ok(ApiResponse.success("Mantenimiento creado",
|
||||
maintenanceService.create(maintenance, user.userId())));
|
||||
}
|
||||
|
||||
@PutMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<ScheduledMaintenance>> update(@PathVariable Long id,
|
||||
@RequestBody ScheduledMaintenance maintenance) {
|
||||
return ResponseEntity.ok(ApiResponse.success("Mantenimiento actualizado",
|
||||
maintenanceService.update(id, maintenance)));
|
||||
}
|
||||
|
||||
@PatchMapping("/{id}/complete")
|
||||
public ResponseEntity<ApiResponse<ScheduledMaintenance>> complete(@PathVariable Long id,
|
||||
@AuthenticationPrincipal SecurityUser user) {
|
||||
return ResponseEntity.ok(ApiResponse.success("Mantenimiento completado",
|
||||
maintenanceService.markCompleted(id, user.userId())));
|
||||
}
|
||||
|
||||
@PatchMapping("/{id}/reopen")
|
||||
public ResponseEntity<ApiResponse<ScheduledMaintenance>> reopen(@PathVariable Long id) {
|
||||
return ResponseEntity.ok(ApiResponse.success("Mantenimiento reabierto",
|
||||
maintenanceService.reopen(id)));
|
||||
}
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
public ResponseEntity<ApiResponse<Void>> delete(@PathVariable Long id) {
|
||||
maintenanceService.delete(id);
|
||||
return ResponseEntity.ok(ApiResponse.success("Mantenimiento eliminado", null));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.sapolar.maintenance;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@Entity
|
||||
@Table(name = "maintenance_periods")
|
||||
public class MaintenancePeriod {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Integer id;
|
||||
|
||||
@Column(nullable = false, unique = true, length = 30)
|
||||
private String name;
|
||||
}
|
||||
@@ -0,0 +1,190 @@
|
||||
package com.sapolar.maintenance;
|
||||
|
||||
import com.sapolar.common.exception.ResourceNotFoundException;
|
||||
import com.sapolar.finance.expense.ExpenseCategory;
|
||||
import com.sapolar.finance.expense.ExpenseReceipt;
|
||||
import com.sapolar.finance.expense.ExpenseReceiptRepository;
|
||||
import com.sapolar.finance.expense.ExpenseStatus;
|
||||
import com.sapolar.property.Property;
|
||||
import com.sapolar.property.PropertyGroup;
|
||||
import com.sapolar.property.PropertyGroupRepository;
|
||||
import com.sapolar.property.PropertyRepository;
|
||||
import com.sapolar.user.User;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class MaintenanceService {
|
||||
|
||||
private final ScheduledMaintenanceRepository maintenanceRepository;
|
||||
private final PropertyRepository propertyRepository;
|
||||
private final PropertyGroupRepository propertyGroupRepository;
|
||||
private final ExpenseReceiptRepository expenseReceiptRepository;
|
||||
|
||||
public List<ScheduledMaintenance> findAll() {
|
||||
return maintenanceRepository.findAll();
|
||||
}
|
||||
|
||||
public List<ScheduledMaintenance> findByProperty(Long propertyId) {
|
||||
return maintenanceRepository.findByPropertyId(propertyId);
|
||||
}
|
||||
|
||||
public List<ScheduledMaintenance> findPending() {
|
||||
return maintenanceRepository.findByCompletedFalse();
|
||||
}
|
||||
|
||||
public List<ScheduledMaintenance> findUpcoming(LocalDate start, LocalDate end) {
|
||||
return maintenanceRepository.findByCompletedFalseAndNextExecutionBetween(start, end);
|
||||
}
|
||||
|
||||
public ScheduledMaintenance findById(Long id) {
|
||||
return maintenanceRepository.findById(id)
|
||||
.orElseThrow(() -> new ResourceNotFoundException("Mantenimiento", id));
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public ScheduledMaintenance create(ScheduledMaintenance maintenance, Long userId) {
|
||||
// Asociar propiedad o conjunto
|
||||
if (maintenance.getProperty() != null && maintenance.getProperty().getId() != null) {
|
||||
Property property = propertyRepository.findById(maintenance.getProperty().getId())
|
||||
.orElseThrow(() -> new ResourceNotFoundException("Propiedad", maintenance.getProperty().getId()));
|
||||
maintenance.setProperty(property);
|
||||
}
|
||||
if (maintenance.getPropertyGroup() != null && maintenance.getPropertyGroup().getId() != null) {
|
||||
PropertyGroup group = propertyGroupRepository.findById(maintenance.getPropertyGroup().getId())
|
||||
.orElseThrow(() -> new ResourceNotFoundException("Conjunto", maintenance.getPropertyGroup().getId()));
|
||||
maintenance.setPropertyGroup(group);
|
||||
}
|
||||
|
||||
User user = new User();
|
||||
user.setId(userId);
|
||||
maintenance.setCreatedBy(user);
|
||||
maintenance.setCompleted(false);
|
||||
|
||||
ScheduledMaintenance saved = maintenanceRepository.save(maintenance);
|
||||
|
||||
// Auto-generar gasto si la opción está activa
|
||||
if (Boolean.TRUE.equals(saved.getGenerateExpense()) && saved.getExpenseCategory() != null) {
|
||||
createExpenseFromMaintenance(saved, userId);
|
||||
}
|
||||
|
||||
return saved;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public ScheduledMaintenance update(Long id, ScheduledMaintenance updated) {
|
||||
ScheduledMaintenance maintenance = findById(id);
|
||||
maintenance.setTitle(updated.getTitle());
|
||||
maintenance.setDescription(updated.getDescription());
|
||||
maintenance.setEstimatedCost(updated.getEstimatedCost());
|
||||
maintenance.setNextExecution(updated.getNextExecution());
|
||||
maintenance.setReminderDaysBefore(updated.getReminderDaysBefore());
|
||||
maintenance.setResponsible(updated.getResponsible());
|
||||
maintenance.setNotes(updated.getNotes());
|
||||
maintenance.setGenerateExpense(updated.getGenerateExpense());
|
||||
if (updated.getPeriod() != null) maintenance.setPeriod(updated.getPeriod());
|
||||
if (updated.getExpenseCategory() != null) maintenance.setExpenseCategory(updated.getExpenseCategory());
|
||||
return maintenanceRepository.save(maintenance);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public ScheduledMaintenance markCompleted(Long id, Long userId) {
|
||||
ScheduledMaintenance maintenance = findById(id);
|
||||
maintenance.setCompleted(true);
|
||||
maintenance.setCompletedAt(LocalDate.now());
|
||||
|
||||
User user = new User();
|
||||
user.setId(userId);
|
||||
maintenance.setCompletedBy(user);
|
||||
|
||||
ScheduledMaintenance saved = maintenanceRepository.save(maintenance);
|
||||
|
||||
// Auto-generar gasto al completar si la opción está activa y es periódico
|
||||
if (Boolean.TRUE.equals(saved.getGenerateExpense()) && saved.getExpenseCategory() != null) {
|
||||
// Para periódicos (no única vez): generar gasto cada vez que se completa
|
||||
if (saved.getPeriod() != null && saved.getPeriod().getId() != 1) {
|
||||
createExpenseFromMaintenance(saved, userId);
|
||||
}
|
||||
}
|
||||
|
||||
return saved;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public ScheduledMaintenance reopen(Long id) {
|
||||
ScheduledMaintenance maintenance = findById(id);
|
||||
maintenance.setCompleted(false);
|
||||
maintenance.setCompletedAt(null);
|
||||
maintenance.setCompletedBy(null);
|
||||
return maintenanceRepository.save(maintenance);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void delete(Long id) {
|
||||
maintenanceRepository.deleteById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Crea un gasto a partir de los datos de una tarea de mantenimiento.
|
||||
*/
|
||||
private ExpenseReceipt createExpenseFromMaintenance(ScheduledMaintenance maintenance, Long userId) {
|
||||
ExpenseReceipt expense = new ExpenseReceipt();
|
||||
|
||||
// Propiedad o conjunto asociado
|
||||
if (maintenance.getProperty() != null && maintenance.getProperty().getId() != null) {
|
||||
Property propertyRef = new Property();
|
||||
propertyRef.setId(maintenance.getProperty().getId());
|
||||
expense.setProperty(propertyRef);
|
||||
}
|
||||
if (maintenance.getPropertyGroup() != null && maintenance.getPropertyGroup().getId() != null) {
|
||||
PropertyGroup groupRef = new PropertyGroup();
|
||||
groupRef.setId(maintenance.getPropertyGroup().getId());
|
||||
expense.setPropertyGroup(groupRef);
|
||||
}
|
||||
|
||||
// Categoría de gasto
|
||||
expense.setCategory(maintenance.getExpenseCategory());
|
||||
|
||||
// Estado PENDIENTE (id=1)
|
||||
ExpenseStatus status = new ExpenseStatus();
|
||||
status.setId(1);
|
||||
expense.setStatus(status);
|
||||
|
||||
// Importes
|
||||
BigDecimal amount = maintenance.getEstimatedCost() != null
|
||||
? maintenance.getEstimatedCost()
|
||||
: BigDecimal.ZERO;
|
||||
expense.setAmount(amount);
|
||||
expense.setTaxAmount(BigDecimal.ZERO);
|
||||
expense.setTotalAmount(amount);
|
||||
|
||||
// Fechas
|
||||
expense.setIssueDate(LocalDate.now());
|
||||
if (maintenance.getNextExecution() != null) {
|
||||
expense.setDueDate(maintenance.getNextExecution());
|
||||
}
|
||||
|
||||
// Descripción
|
||||
String desc = "Mantenimiento: " + maintenance.getTitle();
|
||||
if (maintenance.getProperty() != null && maintenance.getProperty().getName() != null) {
|
||||
desc += " - " + maintenance.getProperty().getName();
|
||||
}
|
||||
expense.setDescription(desc);
|
||||
|
||||
// Responsable como proveedor
|
||||
expense.setSupplierName(maintenance.getResponsible());
|
||||
|
||||
// Creador
|
||||
User user = new User();
|
||||
user.setId(userId);
|
||||
expense.setCreatedBy(user);
|
||||
|
||||
return expenseReceiptRepository.save(expense);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
package com.sapolar.maintenance;
|
||||
|
||||
import com.sapolar.finance.expense.ExpenseCategory;
|
||||
import com.sapolar.property.Property;
|
||||
import com.sapolar.property.PropertyGroup;
|
||||
import com.sapolar.user.User;
|
||||
import jakarta.persistence.*;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@Entity
|
||||
@Table(name = "scheduled_maintenance", indexes = {
|
||||
@Index(name = "idx_maint_property", columnList = "property_id"),
|
||||
@Index(name = "idx_maint_next_exec", columnList = "next_execution"),
|
||||
@Index(name = "idx_maint_completed", columnList = "completed")
|
||||
})
|
||||
public class ScheduledMaintenance {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "property_id")
|
||||
private Property property;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "property_group_id")
|
||||
private PropertyGroup propertyGroup;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "period_id", nullable = false)
|
||||
private MaintenancePeriod period;
|
||||
|
||||
@Column(nullable = false, length = 200)
|
||||
private String title;
|
||||
|
||||
@Column(columnDefinition = "TEXT")
|
||||
private String description;
|
||||
|
||||
@Column(name = "estimated_cost", precision = 12, scale = 2)
|
||||
private BigDecimal estimatedCost;
|
||||
|
||||
@Column(name = "last_execution")
|
||||
private LocalDate lastExecution;
|
||||
|
||||
@Column(name = "next_execution", nullable = false)
|
||||
private LocalDate nextExecution;
|
||||
|
||||
@Column(name = "reminder_days_before", nullable = false)
|
||||
private Integer reminderDaysBefore = 30;
|
||||
|
||||
@Column(length = 200)
|
||||
private String responsible;
|
||||
|
||||
@Column(columnDefinition = "TEXT")
|
||||
private String notes;
|
||||
|
||||
@Column(name = "generate_expense", nullable = false)
|
||||
private Boolean generateExpense = false;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "expense_category_id")
|
||||
private ExpenseCategory expenseCategory;
|
||||
|
||||
@Column(nullable = false)
|
||||
private Boolean completed = false;
|
||||
|
||||
@Column(name = "completed_at")
|
||||
private LocalDate completedAt;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "completed_by")
|
||||
private User completedBy;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "created_by")
|
||||
private User createdBy;
|
||||
|
||||
@Column(name = "created_at", nullable = false, updatable = false)
|
||||
private LocalDateTime createdAt;
|
||||
|
||||
@Column(name = "updated_at", nullable = false)
|
||||
private LocalDateTime updatedAt;
|
||||
|
||||
@PrePersist
|
||||
protected void onCreate() {
|
||||
createdAt = LocalDateTime.now();
|
||||
updatedAt = LocalDateTime.now();
|
||||
}
|
||||
|
||||
@PreUpdate
|
||||
protected void onUpdate() {
|
||||
updatedAt = LocalDateTime.now();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.sapolar.maintenance;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
|
||||
@Repository
|
||||
public interface ScheduledMaintenanceRepository extends JpaRepository<ScheduledMaintenance, Long> {
|
||||
List<ScheduledMaintenance> findByPropertyId(Long propertyId);
|
||||
List<ScheduledMaintenance> findByCompletedFalse();
|
||||
List<ScheduledMaintenance> findByCompletedFalseAndNextExecutionBetween(LocalDate start, LocalDate end);
|
||||
List<ScheduledMaintenance> findByCompletedFalseAndNextExecutionBefore(LocalDate date);
|
||||
}
|
||||
Reference in New Issue
Block a user