EvaluationHrCalculator.java

package com.tdmconsult.ete.evaluation;

import static com.tdmconsult.ete.accounting.BalanceRecords.ZERO_AMOUNT;
import static com.tdmconsult.ete.evaluation.EvaluationHrCalculator.ImpairmentAction.VALUE_DECREASE_WITH_WRITE_DOWN;
import static com.tdmconsult.ete.evaluation.EvaluationHrCalculator.ImpairmentAction.VALUE_INCREASE_NO_WRITE_UP;
import static com.tdmconsult.ete.evaluation.EvaluationHrCalculator.ImpairmentAction.VALUE_INCREASE_WITH_WRITE_UP;
import static com.tdmconsult.ete.evaluation.EvaluationHrCalculator.ImpairmentAction.VALUE_NOOP;

import java.math.BigDecimal;
import lombok.RequiredArgsConstructor;

@RequiredArgsConstructor
public class EvaluationHrCalculator {

    private final EvaluationState state;

    public enum ImpairmentAction {
        VALUE_DECREASE_NO_WRITE_DOWN,
        VALUE_DECREASE_WITH_WRITE_DOWN,
        VALUE_INCREASE_NO_WRITE_UP,
        VALUE_INCREASE_WITH_WRITE_UP,
        VALUE_NOOP
    }

    public record Result(
            BigDecimal amount,
            ImpairmentAction action) {

        public static Result zero(final ImpairmentAction action) {
            return new Result(ZERO_AMOUNT, action);
        }
    }

    public Result calculate() {

        final var fiscalYear = state.getFiscalYear();
        final var evaluationTotalDeltaT0 = state.getEvaluationTotalDelta(fiscalYear);

        final var fiscalYearBefore = state.getFiscalYear() - 1;
        final var evaluationTotalDeltaT1 = state.getEvaluationTotalDelta(fiscalYearBefore);

        // none pending deprecation of last year
        if (evaluationTotalDeltaT1.signum() >= 0) {

            if (evaluationTotalDeltaT0.signum() > 0) {
                return Result.zero(VALUE_INCREASE_NO_WRITE_UP);
            } else if (evaluationTotalDeltaT0.signum() < 0) {
                return new Result(evaluationTotalDeltaT0.abs(), VALUE_DECREASE_WITH_WRITE_DOWN);
            } else {
                return new Result(evaluationTotalDeltaT0.abs(), VALUE_NOOP);
            }
        }

        // pending deprecation - increase that deprecation or reduce it to zero
        final var change = evaluationTotalDeltaT0.subtract(evaluationTotalDeltaT1);
        if (change.signum() < 0) {
            // loss after loss, so increase deprecation
            return new Result(change.abs(), VALUE_DECREASE_WITH_WRITE_DOWN);
        } else  if (change.signum() > 0) {
            // profit after loss, so reducing the deprecation
            final var reduction = change.min(evaluationTotalDeltaT1.abs());
            return new Result(reduction, VALUE_INCREASE_WITH_WRITE_UP);
        }

        return Result.zero(VALUE_INCREASE_NO_WRITE_UP);
    }
}