diff options
author | Øyvind Grønnesby <oyving@verizonmedia.com> | 2021-11-03 13:19:24 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-11-03 13:19:24 +0100 |
commit | e74f05326c81fc4977dde31759fa7d3d75155641 (patch) | |
tree | f746ee2cebd97e5a6b1ef74e747b568d4e03554e /controller-server | |
parent | e5bc78b971380cb1245e9c6a36c2b3ea0fe6eebf (diff) | |
parent | 41bf6baf7256cfa2619457bb47a935b61d0e7a7b (diff) |
Merge pull request #19842 from vespa-engine/ogronnesby/end-date-inclusive
Make the bill end date inclusive instead of exclusive
Diffstat (limited to 'controller-server')
5 files changed, 38 insertions, 29 deletions
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 b8c8ce4e63a..3afc2c8fc15 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 @@ -111,8 +111,8 @@ public class BillingApiHandler extends LoggingRequestHandler { .map(bill -> { return new Object[] { bill.id().value(), bill.tenant().value(), - bill.getStartTime().format(DateTimeFormatter.ISO_LOCAL_DATE), - bill.getEndTime().format(DateTimeFormatter.ISO_LOCAL_DATE), + bill.getStartDate().format(DateTimeFormatter.ISO_LOCAL_DATE), + bill.getEndDate().format(DateTimeFormatter.ISO_LOCAL_DATE), bill.sumCpuHours(), bill.sumMemoryHours(), bill.sumDiskHours(), bill.sumCpuCost(), bill.sumMemoryCost(), bill.sumDiskCost(), bill.sumAdditionalCost() @@ -246,7 +246,7 @@ public class BillingApiHandler extends LoggingRequestHandler { LocalDate startDate = LocalDate.parse(getInspectorFieldOrThrow(inspector, "startTime")); LocalDate endDate = LocalDate.parse(getInspectorFieldOrThrow(inspector, "endTime")); ZonedDateTime startTime = startDate.atStartOfDay(ZoneId.of("UTC")); - ZonedDateTime endTime = endDate.atStartOfDay(ZoneId.of("UTC")); + ZonedDateTime endTime = endDate.plusDays(1).atStartOfDay(ZoneId.of("UTC")); var billId = billingController.createBillForPeriod(tenantName, startTime, endTime, userId); @@ -332,7 +332,7 @@ public class BillingApiHandler extends LoggingRequestHandler { if (currentUsage == null) return; cursor.setString("amount", currentUsage.sum().toPlainString()); cursor.setString("status", "accrued"); - cursor.setString("from", currentUsage.getStartTime().format(DATE_TIME_FORMATTER)); + cursor.setString("from", currentUsage.getStartDate().format(DATE_TIME_FORMATTER)); var itemsCursor = cursor.setArray("items"); currentUsage.lineItems().forEach(lineItem -> { var itemCursor = itemsCursor.addObject(); @@ -363,8 +363,8 @@ public class BillingApiHandler extends LoggingRequestHandler { private void renderBillToCursor(Cursor billCursor, Bill bill) { billCursor.setString("id", bill.id().value()); - billCursor.setString("from", bill.getStartTime().format(DATE_TIME_FORMATTER)); - billCursor.setString("to", bill.getEndTime().format(DATE_TIME_FORMATTER)); + billCursor.setString("from", bill.getStartDate().format(DATE_TIME_FORMATTER)); + billCursor.setString("to", bill.getEndDate().format(DATE_TIME_FORMATTER)); billCursor.setString("amount", bill.sum().toString()); billCursor.setString("status", bill.status()); 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 101321e4da3..f18d38e971b 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 @@ -35,6 +35,7 @@ import java.time.format.DateTimeFormatter; import java.util.Comparator; import java.util.List; import java.util.Optional; +import java.util.logging.Level; /** * @author ogronnesby @@ -178,7 +179,7 @@ public class BillingApiHandlerV2 extends RestApiRequestHandler<BillingApiHandler private Slime tenantUsage(RestApi.RequestContext requestContext) { var tenantName = TenantName.from(requestContext.pathParameters().getStringOrThrow("tenant")); var tenant = tenants.require(tenantName, CloudTenant.class); - var untilAt = untilParameter(requestContext); + var untilAt = untilParameter(requestContext).orElseGet(clock::instant); var usage = billing.createUncommittedBill(tenant.name(), untilAt.atZone(ZoneOffset.UTC).toLocalDate()); var slime = new Slime(); @@ -189,7 +190,7 @@ public class BillingApiHandlerV2 extends RestApiRequestHandler<BillingApiHandler // --------- ACCOUNTANT API ---------- private Slime accountant(RestApi.RequestContext requestContext) { - var untilAt = untilParameter(requestContext); + var untilAt = untilParameter(requestContext).orElseGet(clock::instant); var usagePerTenant = billing.createUncommittedBills(untilAt.atZone(ZoneOffset.UTC).toLocalDate()); var response = new Slime(); @@ -200,7 +201,7 @@ public class BillingApiHandlerV2 extends RestApiRequestHandler<BillingApiHandler tenantResponse.setString("tenant", tenant.name().value()); tenantResponse.setString("plan", billing.getPlan(tenant.name()).value()); tenantResponse.setString("collection", billing.getCollectionMethod(tenant.name()).name()); - tenantResponse.setString("lastBill", usage.map(Bill::getStartTime).map(DateTimeFormatter.ISO_DATE::format).orElse(null)); + tenantResponse.setString("lastBill", usage.map(Bill::getStartDate).map(DateTimeFormatter.ISO_DATE::format).orElse(null)); tenantResponse.setString("unbilled", usage.map(Bill::sum).map(BigDecimal::toPlainString).orElse("0.00")); }); @@ -210,7 +211,7 @@ public class BillingApiHandlerV2 extends RestApiRequestHandler<BillingApiHandler private Slime previewBill(RestApi.RequestContext requestContext) { var tenantName = TenantName.from(requestContext.pathParameters().getStringOrThrow("tenant")); var tenant = tenants.require(tenantName, CloudTenant.class); - var untilAt = untilParameter(requestContext); + var untilAt = untilParameter(requestContext).orElseGet(this::startOfDayTodayUTC); var usage = billing.createUncommittedBill(tenant.name(), untilAt.atZone(ZoneOffset.UTC).toLocalDate()); @@ -229,7 +230,7 @@ public class BillingApiHandlerV2 extends RestApiRequestHandler<BillingApiHandler var tenant = tenants.require(tenantName, CloudTenant.class); var startAt = LocalDate.parse(getInspectorFieldOrThrow(body, "from")).atStartOfDay(ZoneOffset.UTC); - var endAt = LocalDate.parse(getInspectorFieldOrThrow(body, "to")).atStartOfDay(ZoneOffset.UTC); + var endAt = LocalDate.parse(getInspectorFieldOrThrow(body, "to")).plusDays(1).atStartOfDay(ZoneOffset.UTC); var invoiceId = billing.createBillForPeriod(tenant.name(), startAt, endAt, security.principal().getName()); @@ -246,23 +247,23 @@ public class BillingApiHandlerV2 extends RestApiRequestHandler<BillingApiHandler private void invoiceSummaryToSlime(Cursor slime, Bill bill) { slime.setString("id", bill.id().value()); - slime.setString("from", bill.getStartTime().format(DateTimeFormatter.ISO_LOCAL_DATE)); - slime.setString("to", bill.getStartTime().format(DateTimeFormatter.ISO_LOCAL_DATE)); + 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()); } private void usageToSlime(Cursor slime, Bill bill) { - slime.setString("from", bill.getStartTime().format(DateTimeFormatter.ISO_LOCAL_DATE)); - slime.setString("to", bill.getStartTime().format(DateTimeFormatter.ISO_LOCAL_DATE)); + slime.setString("from", bill.getStartDate().format(DateTimeFormatter.ISO_LOCAL_DATE)); + slime.setString("to", bill.getEndTime().format(DateTimeFormatter.ISO_LOCAL_DATE)); slime.setString("total", bill.sum().toString()); toSlime(slime.setArray("items"), bill.lineItems()); } private void toSlime(Cursor slime, Bill bill) { slime.setString("id", bill.id().value()); - slime.setString("from", bill.getStartTime().format(DateTimeFormatter.ISO_LOCAL_DATE)); - slime.setString("to", bill.getStartTime().format(DateTimeFormatter.ISO_LOCAL_DATE)); + 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()); toSlime(slime.setArray("statusHistory"), bill.statusHistory()); @@ -308,8 +309,8 @@ public class BillingApiHandlerV2 extends RestApiRequestHandler<BillingApiHandler private List<Object[]> toCsv(Bill bill) { return List.<Object[]>of(new Object[]{ bill.id().value(), bill.tenant().value(), - bill.getStartTime().format(DateTimeFormatter.ISO_DATE), - bill.getEndTime().format(DateTimeFormatter.ISO_DATE), + bill.getStartDate().format(DateTimeFormatter.ISO_DATE), + bill.getEndDate().format(DateTimeFormatter.ISO_DATE), bill.sumCpuHours(), bill.sumMemoryHours(), bill.sumDiskHours(), bill.sumCpuCost(), bill.sumMemoryCost(), bill.sumDiskCost(), bill.sumAdditionalCost() @@ -318,11 +319,14 @@ public class BillingApiHandlerV2 extends RestApiRequestHandler<BillingApiHandler // ---------- END INVOICE RENDERING ---------- - private Instant untilParameter(RestApi.RequestContext ctx) { + private Optional<Instant> untilParameter(RestApi.RequestContext ctx) { return ctx.queryParameters().getString("until") .map(LocalDate::parse) - .map(date -> date.plusDays(1).atStartOfDay(ZoneOffset.UTC).toInstant()) - .orElseGet(clock::instant); + .map(date -> date.plusDays(1).atStartOfDay(ZoneOffset.UTC).toInstant()); + } + + private Instant startOfDayTodayUTC() { + return LocalDate.now(clock.withZone(ZoneOffset.UTC)).atStartOfDay(ZoneOffset.UTC).toInstant(); } private static String getInspectorFieldOrThrow(Inspector inspector, String field) { 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 3c4ed8bc8df..74ed1a0bb10 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 @@ -122,8 +122,11 @@ public class BillingApiHandlerTest extends ControllerContainerCloudTest { bills = billingController.getBillsForTenant(tenant); assertEquals(1, bills.size()); Bill bill = bills.get(0); - assertEquals(bill.getStartTime().toString(), "2020-04-20T00:00Z[UTC]"); - assertEquals(bill.getEndTime().toString(), "2020-05-20T00:00Z[UTC]"); + assertEquals("2020-04-20T00:00Z[UTC]", bill.getStartTime().toString()); + assertEquals("2020-05-21T00:00Z[UTC]", bill.getEndTime().toString()); + + assertEquals("2020-04-20", bill.getStartDate().toString()); + assertEquals("2020-05-20", bill.getEndDate().toString()); } @Test @@ -223,7 +226,7 @@ public class BillingApiHandlerTest extends ControllerContainerCloudTest { static Bill createBill() { var start = LocalDate.of(2020, 5, 23).atStartOfDay(ZoneOffset.UTC); - var end = start.plusDays(5); + var end = start.toLocalDate().plusDays(6).atStartOfDay(ZoneOffset.UTC); var statusHistory = new Bill.StatusHistory(new TreeMap<>(Map.of(start, "OPEN"))); return new Bill( Bill.Id.of("id-1"), diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/billing/BillingApiHandlerV2Test.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/billing/BillingApiHandlerV2Test.java index 178cb6f9909..c41616dbba5 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/billing/BillingApiHandlerV2Test.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/billing/BillingApiHandlerV2Test.java @@ -13,6 +13,7 @@ import com.yahoo.vespa.hosted.controller.security.CloudTenantSpec; import org.junit.Before; import org.junit.Test; +import java.time.Duration; import java.time.Instant; import java.util.Set; @@ -105,10 +106,10 @@ public class BillingApiHandlerV2Test extends ControllerContainerCloudTest { @Test public void require_tenant_invoice() { var listRequest = request("/billing/v2/tenant/" + tenant + "/bill").roles(tenantReader); - tester.assertResponse(listRequest, "{\"invoices\":[{\"id\":\"id-1\",\"from\":\"2020-05-23\",\"to\":\"2020-05-23\",\"total\":\"123.00\",\"status\":\"OPEN\"}]}"); + tester.assertResponse(listRequest, "{\"invoices\":[{\"id\":\"id-1\",\"from\":\"2020-05-23\",\"to\":\"2020-05-28\",\"total\":\"123.00\",\"status\":\"OPEN\"}]}"); var singleRequest = request("/billing/v2/tenant/" + tenant + "/bill/id-1").roles(tenantReader); - tester.assertResponse(singleRequest, "{\"id\":\"id-1\",\"from\":\"2020-05-23\",\"to\":\"2020-05-23\",\"total\":\"123.00\",\"status\":\"OPEN\",\"statusHistory\":[{\"at\":\"2020-05-23T00:00:00Z\",\"status\":\"OPEN\"}],\"items\":[{\"id\":\"some-id\",\"description\":\"description\",\"amount\":\"123.00\",\"plan\":\"some-plan\",\"planName\":\"Plan with id: some-plan\",\"cpu\":{},\"memory\":{},\"disk\":{}}]}"); + tester.assertResponse(singleRequest, "{\"id\":\"id-1\",\"from\":\"2020-05-23\",\"to\":\"2020-05-28\",\"total\":\"123.00\",\"status\":\"OPEN\",\"statusHistory\":[{\"at\":\"2020-05-23T00:00:00Z\",\"status\":\"OPEN\"}],\"items\":[{\"id\":\"some-id\",\"description\":\"description\",\"amount\":\"123.00\",\"plan\":\"some-plan\",\"planName\":\"Plan with id: some-plan\",\"cpu\":{},\"memory\":{},\"disk\":{}}]}"); } @Test @@ -126,7 +127,7 @@ public class BillingApiHandlerV2Test extends ControllerContainerCloudTest { @Test public void require_accountant_tenant_preview() { var accountantRequest = request("/billing/v2/accountant/preview/tenant/tenant1").roles(Role.hostedAccountant()); - tester.assertResponse(accountantRequest, "{\"id\":\"empty\",\"from\":\"2021-04-13\",\"to\":\"2021-04-13\",\"total\":\"0.00\",\"status\":\"OPEN\",\"statusHistory\":[{\"at\":\"2021-04-13T00:00:00Z\",\"status\":\"OPEN\"}],\"items\":[]}"); + tester.assertResponse(accountantRequest, "{\"id\":\"empty\",\"from\":\"2021-04-13\",\"to\":\"2021-04-12\",\"total\":\"0.00\",\"status\":\"OPEN\",\"statusHistory\":[{\"at\":\"2021-04-13T00:00:00Z\",\"status\":\"OPEN\"}],\"items\":[]}"); } @Test diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/billing/responses/tenant-billing-view b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/billing/responses/tenant-billing-view index c0deca3d671..e5588c45677 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/billing/responses/tenant-billing-view +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/billing/responses/tenant-billing-view @@ -21,7 +21,8 @@ { "id":"id-1", "from":"2020-05-23", - "to":"2020-05-28","amount":"123.00", + "to":"2020-05-28", + "amount":"123.00", "status":"OPEN", "statusHistory":[ { |