summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGjøran Voldengen <gjoranv@gmail.com>2023-10-23 16:15:25 +0200
committerGitHub <noreply@github.com>2023-10-23 16:15:25 +0200
commitce3f04a365d8d655fafd8fe43c5ffa6868db8cdd (patch)
tree0c9a6fe0c431a64e5f48f8fef646f446aa82b56b
parentc9f803a28279856e5481d979550cf17212de3013 (diff)
parent9fa1d2c8e1c6c5424a39e481077c8b2ed0f374c7 (diff)
Merge pull request #29038 from vespa-engine/bill-status-enum
Bill status enum
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/Bill.java31
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/BillStatus.java30
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/BillingController.java2
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/BillingDatabaseClient.java2
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/BillingDatabaseClientMock.java12
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/BillingReporterMock.java10
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/MockBillingController.java6
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/StatusHistory.java35
-rw-r--r--controller-api/src/test/java/com/yahoo/vespa/hosted/controller/api/integration/billing/BillStatusTest.java18
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/BillingReportMaintainer.java4
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/billing/BillingApiHandler.java10
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/billing/BillingApiHandlerV2.java9
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/BillingReportMaintainerTest.java20
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/billing/BillingApiHandlerTest.java10
14 files changed, 139 insertions, 60 deletions
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/Bill.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/Bill.java
index 1acb4964ea6..e7959d2057a 100644
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/Bill.java
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/Bill.java
@@ -8,16 +8,11 @@ import com.yahoo.config.provision.TenantName;
import com.yahoo.config.provision.zone.ZoneId;
import java.math.BigDecimal;
-import java.time.Clock;
import java.time.LocalDate;
-import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.util.List;
-import java.util.Map;
import java.util.Objects;
import java.util.Optional;
-import java.util.SortedMap;
-import java.util.TreeMap;
import java.util.UUID;
import java.util.function.Function;
@@ -69,7 +64,7 @@ public class Bill {
return tenant;
}
- public String status() {
+ public BillStatus status() {
return statusHistory.current();
}
@@ -389,28 +384,4 @@ public class Bill {
}
}
- public static class StatusHistory {
- SortedMap<ZonedDateTime, String> history;
-
- public StatusHistory(SortedMap<ZonedDateTime, String> history) {
- this.history = history;
- }
-
- public static StatusHistory open(Clock clock) {
- var now = clock.instant().atZone(ZoneOffset.UTC);
- return new StatusHistory(
- new TreeMap<>(Map.of(now, "OPEN"))
- );
- }
-
- public String current() {
- return history.get(history.lastKey());
- }
-
- public SortedMap<ZonedDateTime, String> getHistory() {
- return history;
- }
-
- }
-
}
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/BillStatus.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/BillStatus.java
new file mode 100644
index 00000000000..d6c6262069b
--- /dev/null
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/BillStatus.java
@@ -0,0 +1,30 @@
+package com.yahoo.vespa.hosted.controller.api.integration.billing;
+
+/**
+ * @author gjoranv
+ */
+public enum BillStatus {
+ OPEN, // All bills start in this state. The bill can be modified and exported/synced to external systems.
+ FROZEN, // Syncing to external systems is switched off. Reviews should be done in this state.
+ CLOSED, // End state for a valid bill.
+ VOID; // End state, indicating that the bill is not valid.
+
+ private static final String LEGACY_ISSUED = "ISSUED"; // Legacy state, used by historical bills
+ private static final String LEGACY_EXPORTED = "EXPORTED"; // Legacy state, used by historical bills
+
+ private final String value;
+
+ BillStatus() {
+ this.value = name();
+ }
+
+ public String value() {
+ return value;
+ }
+
+ public static BillStatus from(String status) {
+ if (LEGACY_ISSUED.equals(status) || LEGACY_EXPORTED.equals(status)) return OPEN;
+ return Enum.valueOf(BillStatus.class, status.toUpperCase());
+ }
+
+}
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/BillingController.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/BillingController.java
index 45c22c0db28..0aae466feb2 100644
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/BillingController.java
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/BillingController.java
@@ -90,7 +90,7 @@ public interface BillingController {
boolean deleteInstrument(TenantName tenant, String userId, String instrumentId);
/** Change the status of the given bill */
- void updateBillStatus(Bill.Id billId, String agent, String status);
+ void updateBillStatus(Bill.Id billId, String agent, BillStatus status);
/** Add a line item to the given bill */
void addLineItem(TenantName tenant, String description, BigDecimal amount, Optional<Bill.Id> billId, String agent);
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/BillingDatabaseClient.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/BillingDatabaseClient.java
index 3e24314ba5c..c5859cd7d2f 100644
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/BillingDatabaseClient.java
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/BillingDatabaseClient.java
@@ -69,7 +69,7 @@ public interface BillingDatabaseClient {
* @param agent The agent that added the status
* @param status The new status of the bill
*/
- void setStatus(Bill.Id billId, String agent, String status);
+ void setStatus(Bill.Id billId, String agent, BillStatus status);
List<Bill.LineItem> getUnusedLineItems(TenantName tenantName);
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/BillingDatabaseClientMock.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/BillingDatabaseClientMock.java
index ee7679f54ca..a6bcc9bf0ed 100644
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/BillingDatabaseClientMock.java
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/BillingDatabaseClientMock.java
@@ -26,7 +26,7 @@ public class BillingDatabaseClientMock implements BillingDatabaseClient {
private final Map<Bill.Id, List<Bill.LineItem>> lineItems = new HashMap<>();
private final Map<TenantName, List<Bill.LineItem>> uncommittedLineItems = new HashMap<>();
- private final Map<Bill.Id, Bill.StatusHistory> statuses = new HashMap<>();
+ private final Map<Bill.Id, StatusHistory> statuses = new HashMap<>();
private final Map<Bill.Id, ZonedDateTime> startTimes = new HashMap<>();
private final Map<Bill.Id, ZonedDateTime> endTimes = new HashMap<>();
private final Map<Bill.Id, String> exportedInvoiceIds = new HashMap<>();
@@ -54,7 +54,7 @@ public class BillingDatabaseClientMock implements BillingDatabaseClient {
.findFirst();
}
- public String getStatus(Bill.Id invoiceId) {
+ public BillStatus getStatus(Bill.Id invoiceId) {
return statuses.get(invoiceId).current();
}
@@ -62,7 +62,7 @@ public class BillingDatabaseClientMock implements BillingDatabaseClient {
public Bill.Id createBill(TenantName tenant, ZonedDateTime startTime, ZonedDateTime endTime, String agent) {
var invoiceId = Bill.Id.generate();
invoices.put(invoiceId, tenant);
- statuses.computeIfAbsent(invoiceId, l -> Bill.StatusHistory.open(clock));
+ statuses.computeIfAbsent(invoiceId, l -> StatusHistory.open(clock));
startTimes.put(invoiceId, startTime);
endTimes.put(invoiceId, endTime);
return invoiceId;
@@ -72,7 +72,7 @@ public class BillingDatabaseClientMock implements BillingDatabaseClient {
public Optional<Bill> readBill(Bill.Id billId) {
var invoice = Optional.ofNullable(invoices.get(billId));
var lines = lineItems.getOrDefault(billId, List.of());
- var status = statuses.getOrDefault(billId, Bill.StatusHistory.open(clock));
+ var status = statuses.getOrDefault(billId, StatusHistory.open(clock));
var start = startTimes.getOrDefault(billId, startTime);
var end = endTimes.getOrDefault(billId, endTime);
var exportedId = exportedInvoiceId(billId);
@@ -90,8 +90,8 @@ public class BillingDatabaseClientMock implements BillingDatabaseClient {
}
@Override
- public void setStatus(Bill.Id invoiceId, String agent, String status) {
- statuses.computeIfAbsent(invoiceId, k -> Bill.StatusHistory.open(clock))
+ public void setStatus(Bill.Id invoiceId, String agent, BillStatus status) {
+ statuses.computeIfAbsent(invoiceId, k -> StatusHistory.open(clock))
.getHistory()
.put(ZonedDateTime.now(), status);
}
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/BillingReporterMock.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/BillingReporterMock.java
index 4985033d378..689ecc356dc 100644
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/BillingReporterMock.java
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/BillingReporterMock.java
@@ -4,7 +4,10 @@ package com.yahoo.vespa.hosted.controller.api.integration.billing;
import com.yahoo.vespa.hosted.controller.tenant.BillingReference;
import com.yahoo.vespa.hosted.controller.tenant.CloudTenant;
+import java.math.BigDecimal;
import java.time.Clock;
+import java.time.ZonedDateTime;
+import java.util.Optional;
import java.util.UUID;
public class BillingReporterMock implements BillingReporter {
@@ -23,7 +26,8 @@ public class BillingReporterMock implements BillingReporter {
@Override
public InvoiceUpdate maintainInvoice(Bill bill) {
- return new InvoiceUpdate(0,0,1);
+ dbClient.addLineItem(bill.tenant(), maintainedMarkerItem(), Optional.of(bill.id()));
+ return new InvoiceUpdate(1,0,0);
}
@Override
@@ -34,4 +38,8 @@ public class BillingReporterMock implements BillingReporter {
return exportedId;
}
+ private static Bill.LineItem maintainedMarkerItem() {
+ return new Bill.LineItem("maintained", "", BigDecimal.valueOf(0.0), "", "", ZonedDateTime.now());
+ }
+
}
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/MockBillingController.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/MockBillingController.java
index 7a4a787fb11..f8e83b44510 100644
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/MockBillingController.java
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/MockBillingController.java
@@ -74,7 +74,7 @@ public class MockBillingController implements BillingController {
.add(new Bill(
billId,
tenant,
- Bill.StatusHistory.open(clock),
+ StatusHistory.open(clock),
List.of(),
startTime,
endTime
@@ -119,7 +119,7 @@ public class MockBillingController implements BillingController {
}
@Override
- public void updateBillStatus(Bill.Id billId, String agent, String status) {
+ public void updateBillStatus(Bill.Id billId, String agent, BillStatus status) {
var now = clock.instant().atZone(ZoneOffset.UTC);
committedBills.values().stream()
.flatMap(List::stream)
@@ -238,6 +238,6 @@ public class MockBillingController implements BillingController {
private Bill emptyBill() {
var start = clock.instant().atZone(ZoneOffset.UTC);
var end = clock.instant().atZone(ZoneOffset.UTC);
- return new Bill(Bill.Id.of("empty"), TenantName.defaultName(), Bill.StatusHistory.open(clock), List.of(), start, end);
+ return new Bill(Bill.Id.of("empty"), TenantName.defaultName(), StatusHistory.open(clock), List.of(), start, end);
}
}
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/StatusHistory.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/StatusHistory.java
new file mode 100644
index 00000000000..6335ada1396
--- /dev/null
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/billing/StatusHistory.java
@@ -0,0 +1,35 @@
+package com.yahoo.vespa.hosted.controller.api.integration.billing;
+
+import java.time.Clock;
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
+import java.util.Map;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+/**
+ * @author ogronnesby
+ */
+public class StatusHistory {
+ SortedMap<ZonedDateTime, BillStatus> history;
+
+ public StatusHistory(SortedMap<ZonedDateTime, BillStatus> history) {
+ this.history = history;
+ }
+
+ public static StatusHistory open(Clock clock) {
+ var now = clock.instant().atZone(ZoneOffset.UTC);
+ return new StatusHistory(
+ new TreeMap<>(Map.of(now, BillStatus.OPEN))
+ );
+ }
+
+ public BillStatus current() {
+ return history.get(history.lastKey());
+ }
+
+ public SortedMap<ZonedDateTime, BillStatus> getHistory() {
+ return history;
+ }
+
+}
diff --git a/controller-api/src/test/java/com/yahoo/vespa/hosted/controller/api/integration/billing/BillStatusTest.java b/controller-api/src/test/java/com/yahoo/vespa/hosted/controller/api/integration/billing/BillStatusTest.java
new file mode 100644
index 00000000000..9647a11a4ba
--- /dev/null
+++ b/controller-api/src/test/java/com/yahoo/vespa/hosted/controller/api/integration/billing/BillStatusTest.java
@@ -0,0 +1,18 @@
+package com.yahoo.vespa.hosted.controller.api.integration.billing;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+/**
+ * @author gjoranv
+ */
+public class BillStatusTest {
+
+ @Test
+ void legacy_states_are_converted() {
+ assertEquals(BillStatus.OPEN, BillStatus.from("ISSUED"));
+ assertEquals(BillStatus.OPEN, BillStatus.from("EXPORTED"));
+ }
+
+}
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/BillingReportMaintainer.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/BillingReportMaintainer.java
index a12c341c1d1..7868c3fe611 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/BillingReportMaintainer.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/BillingReportMaintainer.java
@@ -5,7 +5,7 @@ import com.yahoo.config.provision.SystemName;
import com.yahoo.config.provision.TenantName;
import com.yahoo.vespa.hosted.controller.Controller;
import com.yahoo.vespa.hosted.controller.LockedTenant;
-import com.yahoo.vespa.hosted.controller.api.integration.billing.Bill;
+import com.yahoo.vespa.hosted.controller.api.integration.billing.BillStatus;
import com.yahoo.vespa.hosted.controller.api.integration.billing.BillingController;
import com.yahoo.vespa.hosted.controller.api.integration.billing.BillingDatabaseClient;
import com.yahoo.vespa.hosted.controller.api.integration.billing.BillingReporter;
@@ -66,7 +66,7 @@ public class BillingReportMaintainer extends ControllerMaintainer {
InvoiceUpdate maintainInvoices() {
var billsNeedingMaintenance = databaseClient.readBills().stream()
.filter(bill -> bill.getExportedId().isPresent())
- .filter(exported -> ! exported.status().equals("ISSUED")) // TODO: This status does not yet exist.
+ .filter(exported -> exported.status() == BillStatus.OPEN)
.toList();
var updates = new InvoiceUpdate.Counter();
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/billing/BillingApiHandler.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/billing/BillingApiHandler.java
index 696f759d16e..6dc29ebe08c 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/billing/BillingApiHandler.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/billing/BillingApiHandler.java
@@ -19,12 +19,14 @@ import com.yahoo.vespa.hosted.controller.ApplicationController;
import com.yahoo.vespa.hosted.controller.Controller;
import com.yahoo.vespa.hosted.controller.TenantController;
import com.yahoo.vespa.hosted.controller.api.integration.billing.Bill;
+import com.yahoo.vespa.hosted.controller.api.integration.billing.BillStatus;
import com.yahoo.vespa.hosted.controller.api.integration.billing.BillingController;
import com.yahoo.vespa.hosted.controller.api.integration.billing.CollectionMethod;
import com.yahoo.vespa.hosted.controller.api.integration.billing.InstrumentOwner;
import com.yahoo.vespa.hosted.controller.api.integration.billing.PaymentInstrument;
import com.yahoo.vespa.hosted.controller.api.integration.billing.PlanId;
import com.yahoo.vespa.hosted.controller.api.integration.billing.PlanRegistry;
+import com.yahoo.vespa.hosted.controller.api.integration.billing.StatusHistory;
import com.yahoo.vespa.hosted.controller.api.role.Role;
import com.yahoo.vespa.hosted.controller.api.role.SecurityContext;
import com.yahoo.vespa.hosted.controller.restapi.ErrorResponses;
@@ -238,7 +240,7 @@ public class BillingApiHandler extends ThreadedHttpRequestHandler {
private HttpResponse setBillStatus(HttpRequest request, String billId, String userId) {
Inspector inspector = inspectorOrThrow(request);
String status = getInspectorFieldOrThrow(inspector, "status");
- billingController.updateBillStatus(Bill.Id.of(billId), userId, status);
+ billingController.updateBillStatus(Bill.Id.of(billId), userId, BillStatus.from(status));
return new MessageResponse("Updated status of invoice " + billId);
}
@@ -380,7 +382,7 @@ public class BillingApiHandler extends ThreadedHttpRequestHandler {
billCursor.setString("to", bill.getEndDate().format(DATE_TIME_FORMATTER));
billCursor.setString("amount", bill.sum().toString());
- billCursor.setString("status", bill.status());
+ billCursor.setString("status", bill.status().value());
var statusCursor = billCursor.setArray("statusHistory");
renderStatusHistory(statusCursor, bill.statusHistory());
@@ -392,14 +394,14 @@ public class BillingApiHandler extends ThreadedHttpRequestHandler {
});
}
- private void renderStatusHistory(Cursor cursor, Bill.StatusHistory statusHistory) {
+ private void renderStatusHistory(Cursor cursor, StatusHistory statusHistory) {
statusHistory.getHistory()
.entrySet()
.stream()
.forEach(entry -> {
var c = cursor.addObject();
c.setString("at", entry.getKey().format(DATE_TIME_FORMATTER));
- c.setString("status", entry.getValue());
+ c.setString("status", entry.getValue().value());
});
}
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/billing/BillingApiHandlerV2.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/billing/BillingApiHandlerV2.java
index 35d09fd541b..edec869f559 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/billing/BillingApiHandlerV2.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/billing/BillingApiHandlerV2.java
@@ -25,6 +25,7 @@ import com.yahoo.vespa.hosted.controller.api.integration.billing.Plan;
import com.yahoo.vespa.hosted.controller.api.integration.billing.PlanId;
import com.yahoo.vespa.hosted.controller.api.integration.billing.PlanRegistry;
import com.yahoo.vespa.hosted.controller.api.integration.billing.Quota;
+import com.yahoo.vespa.hosted.controller.api.integration.billing.StatusHistory;
import com.yahoo.vespa.hosted.controller.api.role.Role;
import com.yahoo.vespa.hosted.controller.api.role.SecurityContext;
import com.yahoo.vespa.hosted.controller.restapi.ErrorResponses;
@@ -461,7 +462,7 @@ public class BillingApiHandlerV2 extends RestApiRequestHandler<BillingApiHandler
slime.setString("from", bill.getStartDate().format(DateTimeFormatter.ISO_LOCAL_DATE));
slime.setString("to", bill.getEndDate().format(DateTimeFormatter.ISO_LOCAL_DATE));
slime.setString("total", bill.sum().toString());
- slime.setString("status", bill.status());
+ slime.setString("status", bill.status().value());
}
private void usageToSlime(Cursor slime, Bill bill) {
@@ -476,16 +477,16 @@ public class BillingApiHandlerV2 extends RestApiRequestHandler<BillingApiHandler
slime.setString("from", bill.getStartDate().format(DateTimeFormatter.ISO_LOCAL_DATE));
slime.setString("to", bill.getEndDate().format(DateTimeFormatter.ISO_LOCAL_DATE));
slime.setString("total", bill.sum().toString());
- slime.setString("status", bill.status());
+ slime.setString("status", bill.status().value());
toSlime(slime.setArray("statusHistory"), bill.statusHistory());
toSlime(slime.setArray("items"), bill.lineItems());
}
- private void toSlime(Cursor slime, Bill.StatusHistory history) {
+ private void toSlime(Cursor slime, StatusHistory history) {
history.getHistory().forEach((key, value) -> {
var c = slime.addObject();
c.setString("at", key.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME));
- c.setString("status", value);
+ c.setString("status", value.value());
});
}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/BillingReportMaintainerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/BillingReportMaintainerTest.java
index a224af83401..5cb46664a75 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/BillingReportMaintainerTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/BillingReportMaintainerTest.java
@@ -4,6 +4,7 @@ package com.yahoo.vespa.hosted.controller.maintenance;
import com.yahoo.config.provision.SystemName;
import com.yahoo.config.provision.TenantName;
import com.yahoo.vespa.hosted.controller.ControllerTester;
+import com.yahoo.vespa.hosted.controller.api.integration.billing.BillStatus;
import com.yahoo.vespa.hosted.controller.api.integration.billing.InvoiceUpdate;
import com.yahoo.vespa.hosted.controller.api.integration.billing.PlanRegistryMock;
import com.yahoo.vespa.hosted.controller.tenant.BillingReference;
@@ -43,25 +44,38 @@ public class BillingReportMaintainerTest {
}
@Test
- void only_bills_with_exported_id_are_maintained() {
+ void only_open_bills_with_exported_id_are_maintained() {
var t1 = tester.createTenant("t1");
var billingController = tester.controller().serviceRegistry().billingController();
var billingDb = tester.controller().serviceRegistry().billingDatabase();
var start = LocalDate.of(2020, 5, 23).atStartOfDay(ZoneOffset.UTC);
var end = start.toLocalDate().plusDays(6).atStartOfDay(ZoneOffset.UTC);
+
var bill1 = billingDb.createBill(t1, start, end, "non-exported");
var bill2 = billingDb.createBill(t1, start, end, "exported");
+ var bill3 = billingDb.createBill(t1, start, end, "exported-and-frozen");
+ billingDb.setStatus(bill3, "foo", BillStatus.FROZEN);
billingController.setPlan(t1, PlanRegistryMock.paidPlan.id(), false, true);
tester.controller().serviceRegistry().billingReporter().exportBill(billingDb.readBill(bill2).get(), "FOO", cloudTenant(t1));
+ tester.controller().serviceRegistry().billingReporter().exportBill(billingDb.readBill(bill3).get(), "FOO", cloudTenant(t1));
var updates = maintainer.maintainInvoices();
- assertEquals(new InvoiceUpdate(0, 0, 1), updates);
+ assertEquals(new InvoiceUpdate(1, 0, 0), updates);
+
+ assertTrue(billingDb.readBill(bill1).get().getExportedId().isEmpty());
var exportedBill = billingDb.readBill(bill2).get();
assertEquals("EXT-ID-123", exportedBill.getExportedId().get());
- assertTrue(billingDb.readBill(bill1).get().getExportedId().isEmpty());
+ var lineItems = exportedBill.lineItems();
+ assertEquals(1, lineItems.size());
+ assertEquals("maintained", lineItems.get(0).id());
+
+ var frozenBill = billingDb.readBill(bill3).get();
+ assertEquals("EXT-ID-123", frozenBill.getExportedId().get());
+ assertEquals(0, frozenBill.lineItems().size());
+
}
private CloudTenant cloudTenant(TenantName tenantName) {
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/billing/BillingApiHandlerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/billing/BillingApiHandlerTest.java
index 7f68fbf6909..f3147d2adde 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/billing/BillingApiHandlerTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/billing/BillingApiHandlerTest.java
@@ -4,9 +4,11 @@ package com.yahoo.vespa.hosted.controller.restapi.billing;
import com.yahoo.config.provision.SystemName;
import com.yahoo.config.provision.TenantName;
import com.yahoo.vespa.hosted.controller.api.integration.billing.Bill;
+import com.yahoo.vespa.hosted.controller.api.integration.billing.BillStatus;
import com.yahoo.vespa.hosted.controller.api.integration.billing.CollectionMethod;
import com.yahoo.vespa.hosted.controller.api.integration.billing.MockBillingController;
import com.yahoo.vespa.hosted.controller.api.integration.billing.PlanId;
+import com.yahoo.vespa.hosted.controller.api.integration.billing.StatusHistory;
import com.yahoo.vespa.hosted.controller.api.role.Role;
import com.yahoo.vespa.hosted.controller.restapi.ContainerTester;
import com.yahoo.vespa.hosted.controller.restapi.ControllerContainerCloudTest;
@@ -26,12 +28,10 @@ import java.util.Optional;
import java.util.Set;
import java.util.TreeMap;
-import static com.yahoo.application.container.handler.Request.Method.DELETE;
import static com.yahoo.application.container.handler.Request.Method.GET;
import static com.yahoo.application.container.handler.Request.Method.PATCH;
import static com.yahoo.application.container.handler.Request.Method.POST;
import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertTrue;
/**
* @author olaa
@@ -152,14 +152,14 @@ public class BillingApiHandlerTest extends ControllerContainerCloudTest {
void adding_new_status() {
billingController.addBill(tenant, createBill(), true);
- var requestBody = "{\"status\":\"DONE\"}";
+ var requestBody = "{\"status\":\"CLOSED\"}";
var request = request("/billing/v1/invoice/id-1/status", POST)
.data(requestBody)
.roles(financeAdmin);
tester.assertResponse(request, "{\"message\":\"Updated status of invoice id-1\"}");
var bill = billingController.getBillsForTenant(tenant).get(0);
- assertEquals("DONE", bill.status());
+ assertEquals(BillStatus.CLOSED, bill.status());
}
@Test
@@ -211,7 +211,7 @@ public class BillingApiHandlerTest extends ControllerContainerCloudTest {
static Bill createBill() {
var start = LocalDate.of(2020, 5, 23).atStartOfDay(ZoneOffset.UTC);
var end = start.toLocalDate().plusDays(6).atStartOfDay(ZoneOffset.UTC);
- var statusHistory = new Bill.StatusHistory(new TreeMap<>(Map.of(start, "OPEN")));
+ var statusHistory = new StatusHistory(new TreeMap<>(Map.of(start, BillStatus.OPEN)));
return new Bill(
Bill.Id.of("id-1"),
TenantName.defaultName(),