175 lines
5.1 KiB
Java
175 lines
5.1 KiB
Java
package dev.lions.unionflow.server.entity;
|
|
|
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
|
import jakarta.persistence.*;
|
|
import jakarta.validation.constraints.*;
|
|
import java.math.BigDecimal;
|
|
import java.time.LocalDate;
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
import lombok.AllArgsConstructor;
|
|
import lombok.Builder;
|
|
import lombok.Data;
|
|
import lombok.EqualsAndHashCode;
|
|
import lombok.NoArgsConstructor;
|
|
|
|
/**
|
|
* Entité EcritureComptable pour les écritures comptables
|
|
*
|
|
* @author UnionFlow Team
|
|
* @version 3.0
|
|
* @since 2025-01-29
|
|
*/
|
|
@Entity
|
|
@Table(
|
|
name = "ecritures_comptables",
|
|
indexes = {
|
|
@Index(name = "idx_ecriture_numero_piece", columnList = "numero_piece", unique = true),
|
|
@Index(name = "idx_ecriture_date", columnList = "date_ecriture"),
|
|
@Index(name = "idx_ecriture_journal", columnList = "journal_id"),
|
|
@Index(name = "idx_ecriture_organisation", columnList = "organisation_id"),
|
|
@Index(name = "idx_ecriture_paiement", columnList = "paiement_id")
|
|
})
|
|
@Data
|
|
@NoArgsConstructor
|
|
@AllArgsConstructor
|
|
@Builder
|
|
@EqualsAndHashCode(callSuper = true)
|
|
public class EcritureComptable extends BaseEntity {
|
|
|
|
/** Numéro de pièce unique */
|
|
@NotBlank
|
|
@Column(name = "numero_piece", unique = true, nullable = false, length = 50)
|
|
private String numeroPiece;
|
|
|
|
/** Date de l'écriture */
|
|
@NotNull
|
|
@Column(name = "date_ecriture", nullable = false)
|
|
private LocalDate dateEcriture;
|
|
|
|
/** Libellé de l'écriture */
|
|
@NotBlank
|
|
@Column(name = "libelle", nullable = false, length = 500)
|
|
private String libelle;
|
|
|
|
/** Référence externe */
|
|
@Column(name = "reference", length = 100)
|
|
private String reference;
|
|
|
|
/** Lettrage (pour rapprochement) */
|
|
@Column(name = "lettrage", length = 20)
|
|
private String lettrage;
|
|
|
|
/** Pointage (pour rapprochement bancaire) */
|
|
@Builder.Default
|
|
@Column(name = "pointe", nullable = false)
|
|
private Boolean pointe = false;
|
|
|
|
/** Montant total débit (somme des lignes) */
|
|
@Builder.Default
|
|
@DecimalMin(value = "0.0")
|
|
@Digits(integer = 12, fraction = 2)
|
|
@Column(name = "montant_debit", precision = 14, scale = 2)
|
|
private BigDecimal montantDebit = BigDecimal.ZERO;
|
|
|
|
/** Montant total crédit (somme des lignes) */
|
|
@Builder.Default
|
|
@DecimalMin(value = "0.0")
|
|
@Digits(integer = 12, fraction = 2)
|
|
@Column(name = "montant_credit", precision = 14, scale = 2)
|
|
private BigDecimal montantCredit = BigDecimal.ZERO;
|
|
|
|
/** Commentaires */
|
|
@Column(name = "commentaire", length = 1000)
|
|
private String commentaire;
|
|
|
|
// Relations
|
|
@NotNull
|
|
@ManyToOne(fetch = FetchType.LAZY)
|
|
@JoinColumn(name = "journal_id", nullable = false)
|
|
private JournalComptable journal;
|
|
|
|
@ManyToOne(fetch = FetchType.LAZY)
|
|
@JoinColumn(name = "organisation_id")
|
|
private Organisation organisation;
|
|
|
|
@ManyToOne(fetch = FetchType.LAZY)
|
|
@JoinColumn(name = "paiement_id")
|
|
private Paiement paiement;
|
|
|
|
/** Lignes d'écriture */
|
|
@JsonIgnore
|
|
@OneToMany(mappedBy = "ecriture", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
|
|
@Builder.Default
|
|
private List<LigneEcriture> lignes = new ArrayList<>();
|
|
|
|
/** Méthode métier pour vérifier l'équilibre (Débit = Crédit) */
|
|
public boolean isEquilibree() {
|
|
if (montantDebit == null || montantCredit == null) {
|
|
return false;
|
|
}
|
|
return montantDebit.compareTo(montantCredit) == 0;
|
|
}
|
|
|
|
/** Méthode métier pour calculer les totaux à partir des lignes */
|
|
public void calculerTotaux() {
|
|
if (lignes == null || lignes.isEmpty()) {
|
|
montantDebit = BigDecimal.ZERO;
|
|
montantCredit = BigDecimal.ZERO;
|
|
return;
|
|
}
|
|
|
|
montantDebit =
|
|
lignes.stream()
|
|
.map(LigneEcriture::getMontantDebit)
|
|
.filter(amount -> amount != null)
|
|
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
|
|
|
montantCredit =
|
|
lignes.stream()
|
|
.map(LigneEcriture::getMontantCredit)
|
|
.filter(amount -> amount != null)
|
|
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
|
}
|
|
|
|
/** Méthode métier pour générer un numéro de pièce unique */
|
|
public static String genererNumeroPiece(String prefixe, LocalDate date) {
|
|
return String.format(
|
|
"%s-%04d%02d%02d-%012d",
|
|
prefixe, date.getYear(), date.getMonthValue(), date.getDayOfMonth(),
|
|
System.currentTimeMillis() % 1000000000000L);
|
|
}
|
|
|
|
/** Callback JPA avant la persistance */
|
|
@PrePersist
|
|
protected void onCreate() {
|
|
super.onCreate();
|
|
if (numeroPiece == null || numeroPiece.isEmpty()) {
|
|
numeroPiece = genererNumeroPiece("ECR", dateEcriture != null ? dateEcriture : LocalDate.now());
|
|
}
|
|
if (dateEcriture == null) {
|
|
dateEcriture = LocalDate.now();
|
|
}
|
|
if (montantDebit == null) {
|
|
montantDebit = BigDecimal.ZERO;
|
|
}
|
|
if (montantCredit == null) {
|
|
montantCredit = BigDecimal.ZERO;
|
|
}
|
|
if (pointe == null) {
|
|
pointe = false;
|
|
}
|
|
// Calculer les totaux si les lignes sont déjà présentes
|
|
if (lignes != null && !lignes.isEmpty()) {
|
|
calculerTotaux();
|
|
}
|
|
}
|
|
|
|
/** Callback JPA avant la mise à jour */
|
|
@PreUpdate
|
|
protected void onUpdate() {
|
|
calculerTotaux();
|
|
}
|
|
}
|
|
|