Add the late-fee rule with boundary tests

Java · Spring Boot · beginner · greenfield

Adds the late-fee rule finance asked for: 14 days of grace, then a flat 2,500. The calculator is a small pure function, and the tests cover both sides of the grace boundary (day 14 free, day 15 charged), the flat amount months later, invoices not yet due and paid invoices. `./gradlew test` is green.

Billing service on Spring Boot 3.3 (Java 21, Gradle), tests with JUnit 5 and AssertJ 3.25 from `spring-boot-starter-test`. Existing `com.acme.billing.invoice.Invoice` has `isPaid()`, `getDueDate()` (a non-null `LocalDate`) and a test-friendly `Invoice.builder().dueDate(LocalDate).paid(boolean).build()`. The `billingDate` is supplied by the caller (the dunning job passes the business date); the calculator does not read the clock.

Requirements

Files touched

--- src/main/java/com/acme/billing/fees/LateFeeCalculator.java
+package com.acme.billing.fees;
+
+import java.time.LocalDate;
+import java.time.temporal.ChronoUnit;
+
+import org.springframework.stereotype.Component;
+
+import com.acme.billing.invoice.Invoice;
+
+@Component
+public class LateFeeCalculator {
+
+    static final int GRACE_DAYS = 14;
+    static final long LATE_FEE_MINOR = 2_500;
+
+    public long feeFor(Invoice invoice, LocalDate billingDate) {
+        if (invoice.isPaid()) {
+            return 0;
+        }
+        long daysOverdue = ChronoUnit.DAYS.between(invoice.getDueDate(), billingDate);
+        return daysOverdue > GRACE_DAYS ? LATE_FEE_MINOR : 0;
+    }
+}
+
--- src/test/java/com/acme/billing/fees/LateFeeCalculatorTest.java
+package com.acme.billing.fees;
+
+import static org.assertj.core.api.Assertions.assertThat;
+

Review this PR

Java practice