Skip to content

Instantly share code, notes, and snippets.

@robsonkades
Last active January 15, 2026 01:32
Show Gist options
  • Select an option

  • Save robsonkades/029444862fd7cdeab515069e879a881e to your computer and use it in GitHub Desktop.

Select an option

Save robsonkades/029444862fd7cdeab515069e879a881e to your computer and use it in GitHub Desktop.
record StatusTransition(InvoiceStatus current) {
public void validate(InvoiceStatus next, String invoiceId) {
if (!current.canTransitionTo(next)) {
throw DomainException.with(Message.INVOICE_TRANSITION_NOT_ALLOWED, invoiceId, current, next);
}
}
}
static {
// Definição clara da Máquina de Estados
PENDING.nextPossibleStates = EnumSet.of(PENDING, AUTHORIZED, REJECTED, CANCELED, NUMBER_INVALIDED);
REJECTED.nextPossibleStates = EnumSet.of(PENDING, AUTHORIZED, REJECTED, CANCELED, NUMBER_INVALIDED);
AUTHORIZED.nextPossibleStates = EnumSet.of(AUTHORIZED, CANCELED);
CANCELED.nextPossibleStates = EnumSet.of(CANCELED);
NUMBER_INVALIDED.nextPossibleStates = EnumSet.of(NUMBER_INVALIDED);
}
private final String description;
private Set<InvoiceStatus> nextPossibleStates;
InvoiceStatus(final String description) {
this.description = description;
}
public String getDescription() {
return description;
}
public boolean canTransitionTo(InvoiceStatus next) {
return nextPossibleStates.contains(next);
}
public void markAsPending() {
new StatusTransition(this.status).validate(InvoiceStatus.PENDING, id.getValue());
if (isPending()) {
LOGGER.debug("Invoice {} already authorized", id.getValue());
return;
}
this.clearStatusFields();
this.changeStatus(InvoiceStatus.PENDING);
this.registerEvent(InvoicePending.from(this));
}
public void markAsAuthorized() {
new StatusTransition(this.status).validate(InvoiceStatus.AUTHORIZED, id.getValue());
if (isAuthorized()) {
LOGGER.debug("Invoice {} already authorized", id.getValue());
return;
}
this.changeStatus(InvoiceStatus.AUTHORIZED);
this.registerEvent(InvoiceAuthorized.from(this));
}
public void markAsCanceled() {
new StatusTransition(this.status).validate(InvoiceStatus.CANCELED, id.getValue());
if (isCanceled()) return;
this.changeStatus(InvoiceStatus.CANCELED);
this.registerEvent(InvoiceCanceled.from(this));
}
public void markAsRejected() {
new StatusTransition(this.status).validate(InvoiceStatus.REJECTED, id.getValue());
if (isRejected()) return;
this.changeStatus(InvoiceStatus.REJECTED);
this.registerEvent(InvoiceRejected.from(this));
}
public void markAsNumberInvalided() {
new StatusTransition(this.status).validate(InvoiceStatus.NUMBER_INVALIDED, id.getValue());
if (isRejected()) return;
this.changeStatus(InvoiceStatus.NUMBER_INVALIDED);
}
/**
* Extrai substring de forma segura, retornando null se houver erro
*/
private String safeSubstring(String value, int start, int end) {
try {
if (value == null || start < 0 || end > value.length() || start >= end) {
return null;
}
String substring = value.substring(start, end);
return substring.trim().isEmpty() ? null : substring;
} catch (Exception e) {
return null;
}
}
/**
* Parse seguro de Integer, retornando null se houver erro
*/
private Integer safeParseInt(String value, int start, int end) {
try {
String substring = safeSubstring(value, start, end);
if (substring == null) {
return null;
}
return Integer.parseInt(substring);
} catch (NumberFormatException e) {
return null;
}
}
/**
* Parse seguro de Long, retornando null se houver erro
*/
private Long safeParseLong(String value, int start, int end) {
try {
String substring = safeSubstring(value, start, end);
if (substring == null) {
return null;
}
return Long.parseLong(substring);
} catch (NumberFormatException e) {
return null;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment