mirror of
https://github.com/google/nomulus.git
synced 2025-05-16 09:27:16 +02:00
Add sunrise and anchor tenant discounts to invoicing pipeline
This officially adds a 15% discount to sunrise creates and makes anchor tenant creates free for the first 2 years. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=204805141
This commit is contained in:
parent
ccbdfd0e41
commit
c4a2b5fa8d
4 changed files with 71 additions and 5 deletions
|
@ -10,6 +10,7 @@ java_library(
|
||||||
resources = glob(["sql/*"]),
|
resources = glob(["sql/*"]),
|
||||||
deps = [
|
deps = [
|
||||||
"//java/google/registry/config",
|
"//java/google/registry/config",
|
||||||
|
"//java/google/registry/model",
|
||||||
"//java/google/registry/reporting/billing",
|
"//java/google/registry/reporting/billing",
|
||||||
"//java/google/registry/util",
|
"//java/google/registry/util",
|
||||||
"@com_google_apis_google_api_services_bigquery",
|
"@com_google_apis_google_api_services_bigquery",
|
||||||
|
|
|
@ -19,11 +19,13 @@ import com.google.common.annotations.VisibleForTesting;
|
||||||
import com.google.common.base.Joiner;
|
import com.google.common.base.Joiner;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.flogger.FluentLogger;
|
import com.google.common.flogger.FluentLogger;
|
||||||
|
import google.registry.model.billing.BillingEvent.Flag;
|
||||||
import google.registry.reporting.billing.BillingModule;
|
import google.registry.reporting.billing.BillingModule;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
import java.text.DecimalFormat;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.time.ZoneId;
|
import java.time.ZoneId;
|
||||||
import java.time.ZonedDateTime;
|
import java.time.ZonedDateTime;
|
||||||
|
@ -52,6 +54,9 @@ public abstract class BillingEvent implements Serializable {
|
||||||
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss zzz");
|
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss zzz");
|
||||||
|
|
||||||
|
|
||||||
|
/** The amount we multiply the price for sunrise creates. This is currently a 15% discount. */
|
||||||
|
private static final double SUNRISE_DISCOUNT_PRICE_MODIFIER = 0.85;
|
||||||
|
|
||||||
private static final ImmutableList<String> FIELD_NAMES =
|
private static final ImmutableList<String> FIELD_NAMES =
|
||||||
ImmutableList.of(
|
ImmutableList.of(
|
||||||
"id",
|
"id",
|
||||||
|
@ -105,6 +110,8 @@ public abstract class BillingEvent implements Serializable {
|
||||||
static BillingEvent parseFromRecord(SchemaAndRecord schemaAndRecord) {
|
static BillingEvent parseFromRecord(SchemaAndRecord schemaAndRecord) {
|
||||||
checkFieldsNotNull(schemaAndRecord);
|
checkFieldsNotNull(schemaAndRecord);
|
||||||
GenericRecord record = schemaAndRecord.getRecord();
|
GenericRecord record = schemaAndRecord.getRecord();
|
||||||
|
String flags = extractField(record, "flags");
|
||||||
|
double amount = getDiscountedAmount(Double.parseDouble(extractField(record, "amount")), flags);
|
||||||
return create(
|
return create(
|
||||||
// We need to chain parsers off extractField because GenericRecord only returns
|
// We need to chain parsers off extractField because GenericRecord only returns
|
||||||
// Objects, which contain a string representation of their underlying types.
|
// Objects, which contain a string representation of their underlying types.
|
||||||
|
@ -122,8 +129,30 @@ public abstract class BillingEvent implements Serializable {
|
||||||
extractField(record, "repositoryId"),
|
extractField(record, "repositoryId"),
|
||||||
Integer.parseInt(extractField(record, "years")),
|
Integer.parseInt(extractField(record, "years")),
|
||||||
extractField(record, "currency"),
|
extractField(record, "currency"),
|
||||||
Double.parseDouble(extractField(record, "amount")),
|
amount,
|
||||||
extractField(record, "flags"));
|
flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies a discount to sunrise creates and anchor tenant creates if applicable.
|
||||||
|
*
|
||||||
|
* Currently sunrise creates are discounted 15% and anchor tenant creates are free for 2 years.
|
||||||
|
* All anchor tenant creates are enforced to be 2 years in
|
||||||
|
* {@link google.registry.flows.domain.DomainCreateFlow#verifyAnchorTenantValidPeriod}.
|
||||||
|
*/
|
||||||
|
private static double getDiscountedAmount(double amount, String flags) {
|
||||||
|
// Apply a configurable discount to sunrise creates.
|
||||||
|
if (flags.contains(Flag.SUNRISE.name())) {
|
||||||
|
amount =
|
||||||
|
Double.parseDouble(
|
||||||
|
new DecimalFormat("#.##").format(amount * SUNRISE_DISCOUNT_PRICE_MODIFIER));
|
||||||
|
}
|
||||||
|
// Anchor tenant creates are free for the initial create. This is enforced to be a 2 year period
|
||||||
|
// upon domain create.
|
||||||
|
if (flags.contains(Flag.ANCHOR_TENANT.name())) {
|
||||||
|
amount = 0;
|
||||||
|
}
|
||||||
|
return amount;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -99,6 +99,22 @@ public class BillingEventTest {
|
||||||
assertThat(event.flags()).isEqualTo("AUTO_RENEW SYNTHETIC");
|
assertThat(event.flags()).isEqualTo("AUTO_RENEW SYNTHETIC");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseBillingEventFromRecord_sunriseCreate_reducedPrice_success() {
|
||||||
|
schemaAndRecord.getRecord().put("flags", "SUNRISE");
|
||||||
|
BillingEvent event = BillingEvent.parseFromRecord(schemaAndRecord);
|
||||||
|
assertThat(event.amount()).isEqualTo(17.43);
|
||||||
|
assertThat(event.flags()).isEqualTo("SUNRISE");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseBillingEventFromRecord_anchorTenant_zeroPrice_success() {
|
||||||
|
schemaAndRecord.getRecord().put("flags", "SUNRISE ANCHOR_TENANT");
|
||||||
|
BillingEvent event = BillingEvent.parseFromRecord(schemaAndRecord);
|
||||||
|
assertThat(event.amount()).isZero();
|
||||||
|
assertThat(event.flags()).isEqualTo("SUNRISE ANCHOR_TENANT");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testParseBillingEventFromRecord_nullValue_throwsException() {
|
public void testParseBillingEventFromRecord_nullValue_throwsException() {
|
||||||
schemaAndRecord.getRecord().put("tld", null);
|
schemaAndRecord.getRecord().put("tld", null);
|
||||||
|
|
|
@ -125,7 +125,21 @@ public class InvoicingPipelineTest {
|
||||||
1,
|
1,
|
||||||
"USD",
|
"USD",
|
||||||
20.5,
|
20.5,
|
||||||
""));
|
""),
|
||||||
|
BillingEvent.create(
|
||||||
|
1,
|
||||||
|
ZonedDateTime.of(2017, 10, 4, 0, 0, 0, 0, ZoneId.of("UTC")),
|
||||||
|
ZonedDateTime.of(2017, 10, 4, 0, 0, 0, 0, ZoneId.of("UTC")),
|
||||||
|
"anotherRegistrar",
|
||||||
|
"789",
|
||||||
|
"test",
|
||||||
|
"CREATE",
|
||||||
|
"mydomain5.test",
|
||||||
|
"REPO-ID",
|
||||||
|
1,
|
||||||
|
"USD",
|
||||||
|
0,
|
||||||
|
"SUNRISE ANCHOR_TENANT"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns a map from filename to expected contents for detail reports. */
|
/** Returns a map from filename to expected contents for detail reports. */
|
||||||
|
@ -144,7 +158,11 @@ public class InvoicingPipelineTest {
|
||||||
"invoice_details_2017-10_googledomains_test.csv",
|
"invoice_details_2017-10_googledomains_test.csv",
|
||||||
ImmutableList.of(
|
ImmutableList.of(
|
||||||
"1,2017-10-04 00:00:00 UTC,2017-10-04 00:00:00 UTC,googledomains,456,"
|
"1,2017-10-04 00:00:00 UTC,2017-10-04 00:00:00 UTC,googledomains,456,"
|
||||||
+ "test,RENEW,mydomain4.test,REPO-ID,1,USD,20.50,"));
|
+ "test,RENEW,mydomain4.test,REPO-ID,1,USD,20.50,"),
|
||||||
|
"invoice_details_2017-10_anotherRegistrar_test.csv",
|
||||||
|
ImmutableList.of(
|
||||||
|
"1,2017-10-04 00:00:00 UTC,2017-10-04 00:00:00 UTC,anotherRegistrar,789,"
|
||||||
|
+ "test,CREATE,mydomain5.test,REPO-ID,1,USD,0.00,SUNRISE ANCHOR_TENANT"));
|
||||||
}
|
}
|
||||||
|
|
||||||
private ImmutableList<String> getExpectedInvoiceOutput() {
|
private ImmutableList<String> getExpectedInvoiceOutput() {
|
||||||
|
@ -154,7 +172,9 @@ public class InvoicingPipelineTest {
|
||||||
"2017-10-01,2022-09-30,234,70.75,JPY,10125,1,PURCHASE,theRegistrar - hello,1,"
|
"2017-10-01,2022-09-30,234,70.75,JPY,10125,1,PURCHASE,theRegistrar - hello,1,"
|
||||||
+ "CREATE | TLD: hello | TERM: 5-year,70.75,JPY,",
|
+ "CREATE | TLD: hello | TERM: 5-year,70.75,JPY,",
|
||||||
"2017-10-01,2018-09-30,456,20.50,USD,10125,1,PURCHASE,googledomains - test,1,"
|
"2017-10-01,2018-09-30,456,20.50,USD,10125,1,PURCHASE,googledomains - test,1,"
|
||||||
+ "RENEW | TLD: test | TERM: 1-year,20.50,USD,");
|
+ "RENEW | TLD: test | TERM: 1-year,20.50,USD,",
|
||||||
|
"2017-10-01,2018-09-30,789,0.00,USD,10125,1,PURCHASE,anotherRegistrar - test,1,"
|
||||||
|
+ "CREATE | TLD: test | TERM: 1-year,0.00,USD,");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue