mirror of
https://github.com/google/nomulus.git
synced 2025-06-29 07:43:37 +02:00
Handle Purchase Order numbers explicitly in billing pipeline
Note that these aren't used for most registrars. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=213631863
This commit is contained in:
parent
3fc7271145
commit
633b30725a
10 changed files with 138 additions and 12 deletions
|
@ -56,7 +56,6 @@ public abstract class BillingEvent implements Serializable {
|
||||||
private static final DateTimeFormatter DATE_TIME_FORMATTER =
|
private static final DateTimeFormatter DATE_TIME_FORMATTER =
|
||||||
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. */
|
/** 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 double SUNRISE_DISCOUNT_PRICE_MODIFIER = 0.85;
|
||||||
|
|
||||||
|
@ -67,6 +66,7 @@ public abstract class BillingEvent implements Serializable {
|
||||||
"eventTime",
|
"eventTime",
|
||||||
"registrarId",
|
"registrarId",
|
||||||
"billingId",
|
"billingId",
|
||||||
|
"poNumber",
|
||||||
"tld",
|
"tld",
|
||||||
"action",
|
"action",
|
||||||
"domain",
|
"domain",
|
||||||
|
@ -78,28 +78,43 @@ public abstract class BillingEvent implements Serializable {
|
||||||
|
|
||||||
/** Returns the unique Objectify ID for the {@code OneTime} associated with this event. */
|
/** Returns the unique Objectify ID for the {@code OneTime} associated with this event. */
|
||||||
abstract long id();
|
abstract long id();
|
||||||
|
|
||||||
/** Returns the UTC DateTime this event becomes billable. */
|
/** Returns the UTC DateTime this event becomes billable. */
|
||||||
abstract ZonedDateTime billingTime();
|
abstract ZonedDateTime billingTime();
|
||||||
|
|
||||||
/** Returns the UTC DateTime this event was generated. */
|
/** Returns the UTC DateTime this event was generated. */
|
||||||
abstract ZonedDateTime eventTime();
|
abstract ZonedDateTime eventTime();
|
||||||
|
|
||||||
/** Returns the billed registrar's name. */
|
/** Returns the billed registrar's name. */
|
||||||
abstract String registrarId();
|
abstract String registrarId();
|
||||||
|
|
||||||
/** Returns the billed registrar's billing account key. */
|
/** Returns the billed registrar's billing account key. */
|
||||||
abstract String billingId();
|
abstract String billingId();
|
||||||
|
|
||||||
|
/** Returns the Purchase Order number. */
|
||||||
|
abstract String poNumber();
|
||||||
|
|
||||||
/** Returns the tld this event was generated for. */
|
/** Returns the tld this event was generated for. */
|
||||||
abstract String tld();
|
abstract String tld();
|
||||||
|
|
||||||
/** Returns the billable action this event was generated for (i.e. RENEW, CREATE, TRANSFER...) */
|
/** Returns the billable action this event was generated for (i.e. RENEW, CREATE, TRANSFER...) */
|
||||||
abstract String action();
|
abstract String action();
|
||||||
|
|
||||||
/** Returns the fully qualified domain name this event was generated for. */
|
/** Returns the fully qualified domain name this event was generated for. */
|
||||||
abstract String domain();
|
abstract String domain();
|
||||||
|
|
||||||
/** Returns the unique RepoID associated with the billed domain. */
|
/** Returns the unique RepoID associated with the billed domain. */
|
||||||
abstract String repositoryId();
|
abstract String repositoryId();
|
||||||
|
|
||||||
/** Returns the number of years this billing event is made out for. */
|
/** Returns the number of years this billing event is made out for. */
|
||||||
abstract int years();
|
abstract int years();
|
||||||
|
|
||||||
/** Returns the 3-letter currency code for the billing event (i.e. USD or JPY.) */
|
/** Returns the 3-letter currency code for the billing event (i.e. USD or JPY.) */
|
||||||
abstract String currency();
|
abstract String currency();
|
||||||
|
|
||||||
/** Returns the cost associated with this billing event. */
|
/** Returns the cost associated with this billing event. */
|
||||||
abstract double amount();
|
abstract double amount();
|
||||||
|
|
||||||
/** Returns a list of space-delimited flags associated with the event. */
|
/** Returns a list of space-delimited flags associated with the event. */
|
||||||
abstract String flags();
|
abstract String flags();
|
||||||
|
|
||||||
|
@ -126,6 +141,7 @@ public abstract class BillingEvent implements Serializable {
|
||||||
.atZone(ZoneId.of("UTC")),
|
.atZone(ZoneId.of("UTC")),
|
||||||
extractField(record, "registrarId"),
|
extractField(record, "registrarId"),
|
||||||
extractField(record, "billingId"),
|
extractField(record, "billingId"),
|
||||||
|
extractField(record, "poNumber"),
|
||||||
extractField(record, "tld"),
|
extractField(record, "tld"),
|
||||||
extractField(record, "action"),
|
extractField(record, "action"),
|
||||||
extractField(record, "domain"),
|
extractField(record, "domain"),
|
||||||
|
@ -171,6 +187,7 @@ public abstract class BillingEvent implements Serializable {
|
||||||
ZonedDateTime eventTime,
|
ZonedDateTime eventTime,
|
||||||
String registrarId,
|
String registrarId,
|
||||||
String billingId,
|
String billingId,
|
||||||
|
String poNumber,
|
||||||
String tld,
|
String tld,
|
||||||
String action,
|
String action,
|
||||||
String domain,
|
String domain,
|
||||||
|
@ -185,6 +202,7 @@ public abstract class BillingEvent implements Serializable {
|
||||||
eventTime,
|
eventTime,
|
||||||
registrarId,
|
registrarId,
|
||||||
billingId,
|
billingId,
|
||||||
|
poNumber,
|
||||||
tld,
|
tld,
|
||||||
action,
|
action,
|
||||||
domain,
|
domain,
|
||||||
|
@ -241,7 +259,7 @@ public abstract class BillingEvent implements Serializable {
|
||||||
String.format("%s | TLD: %s | TERM: %d-year", action(), tld(), years()),
|
String.format("%s | TLD: %s | TERM: %d-year", action(), tld(), years()),
|
||||||
amount(),
|
amount(),
|
||||||
currency(),
|
currency(),
|
||||||
"");
|
poNumber());
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Key for each {@code BillingEvent}, when aggregating for the overall invoice. */
|
/** Key for each {@code BillingEvent}, when aggregating for the overall invoice. */
|
||||||
|
@ -267,18 +285,25 @@ public abstract class BillingEvent implements Serializable {
|
||||||
|
|
||||||
/** Returns the first day this invoice is valid, in yyyy-MM-dd format. */
|
/** Returns the first day this invoice is valid, in yyyy-MM-dd format. */
|
||||||
abstract String startDate();
|
abstract String startDate();
|
||||||
|
|
||||||
/** Returns the last day this invoice is valid, in yyyy-MM-dd format. */
|
/** Returns the last day this invoice is valid, in yyyy-MM-dd format. */
|
||||||
abstract String endDate();
|
abstract String endDate();
|
||||||
|
|
||||||
/** Returns the billing account id, which is the {@code BillingEvent.billingId}. */
|
/** Returns the billing account id, which is the {@code BillingEvent.billingId}. */
|
||||||
abstract String productAccountKey();
|
abstract String productAccountKey();
|
||||||
|
|
||||||
/** Returns the invoice grouping key, which is in the format "registrarId - tld". */
|
/** Returns the invoice grouping key, which is in the format "registrarId - tld". */
|
||||||
abstract String usageGroupingKey();
|
abstract String usageGroupingKey();
|
||||||
|
|
||||||
/** Returns a description of the item, formatted as "action | TLD: tld | TERM: n-year." */
|
/** Returns a description of the item, formatted as "action | TLD: tld | TERM: n-year." */
|
||||||
abstract String description();
|
abstract String description();
|
||||||
|
|
||||||
/** Returns the cost per invoice item. */
|
/** Returns the cost per invoice item. */
|
||||||
abstract Double unitPrice();
|
abstract Double unitPrice();
|
||||||
|
|
||||||
/** Returns the 3-digit currency code the unit price uses. */
|
/** Returns the 3-digit currency code the unit price uses. */
|
||||||
abstract String unitPriceCurrency();
|
abstract String unitPriceCurrency();
|
||||||
|
|
||||||
/** Returns the purchase order number for the item, blank for most registrars. */
|
/** Returns the purchase order number for the item, blank for most registrars. */
|
||||||
abstract String poNumber();
|
abstract String poNumber();
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@ SELECT
|
||||||
eventTime,
|
eventTime,
|
||||||
BillingEvent.clientId AS registrarId,
|
BillingEvent.clientId AS registrarId,
|
||||||
RegistrarData.accountId AS billingId,
|
RegistrarData.accountId AS billingId,
|
||||||
|
RegistrarData.poNumber AS poNumber,
|
||||||
tld,
|
tld,
|
||||||
reason as action,
|
reason as action,
|
||||||
targetId as domain,
|
targetId as domain,
|
||||||
|
@ -63,6 +64,7 @@ JOIN (
|
||||||
SELECT
|
SELECT
|
||||||
__key__.name AS clientId,
|
__key__.name AS clientId,
|
||||||
billingIdentifier,
|
billingIdentifier,
|
||||||
|
IFNULL(poNumber, '') AS poNumber,
|
||||||
r.billingAccountMap.currency[SAFE_OFFSET(index)] AS currency,
|
r.billingAccountMap.currency[SAFE_OFFSET(index)] AS currency,
|
||||||
r.billingAccountMap.accountId[SAFE_OFFSET(index)] AS accountId
|
r.billingAccountMap.accountId[SAFE_OFFSET(index)] AS accountId
|
||||||
FROM
|
FROM
|
||||||
|
|
|
@ -310,6 +310,10 @@ public class Registrar extends ImmutableObject implements Buildable, Jsonifiable
|
||||||
@Nullable
|
@Nullable
|
||||||
Long billingIdentifier;
|
Long billingIdentifier;
|
||||||
|
|
||||||
|
/** Purchase Order number used for invoices in external billing system, if applicable. */
|
||||||
|
@Nullable
|
||||||
|
String poNumber;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Map of currency-to-billing account for the registrar.
|
* Map of currency-to-billing account for the registrar.
|
||||||
*
|
*
|
||||||
|
@ -422,6 +426,10 @@ public class Registrar extends ImmutableObject implements Buildable, Jsonifiable
|
||||||
return billingIdentifier;
|
return billingIdentifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Optional<String> getPoNumber() {
|
||||||
|
return Optional.ofNullable(poNumber);
|
||||||
|
}
|
||||||
|
|
||||||
public ImmutableMap<CurrencyUnit, String> getBillingAccountMap() {
|
public ImmutableMap<CurrencyUnit, String> getBillingAccountMap() {
|
||||||
if (billingAccountMap == null) {
|
if (billingAccountMap == null) {
|
||||||
return ImmutableMap.of();
|
return ImmutableMap.of();
|
||||||
|
@ -644,20 +652,25 @@ public class Registrar extends ImmutableObject implements Buildable, Jsonifiable
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Builder setIanaIdentifier(Long ianaIdentifier) {
|
public Builder setIanaIdentifier(@Nullable Long ianaIdentifier) {
|
||||||
checkArgument(ianaIdentifier == null || ianaIdentifier > 0,
|
checkArgument(ianaIdentifier == null || ianaIdentifier > 0,
|
||||||
"IANA ID must be a positive number");
|
"IANA ID must be a positive number");
|
||||||
getInstance().ianaIdentifier = ianaIdentifier;
|
getInstance().ianaIdentifier = ianaIdentifier;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Builder setBillingIdentifier(Long billingIdentifier) {
|
public Builder setBillingIdentifier(@Nullable Long billingIdentifier) {
|
||||||
checkArgument(billingIdentifier == null || billingIdentifier > 0,
|
checkArgument(billingIdentifier == null || billingIdentifier > 0,
|
||||||
"Billing ID must be a positive number");
|
"Billing ID must be a positive number");
|
||||||
getInstance().billingIdentifier = billingIdentifier;
|
getInstance().billingIdentifier = billingIdentifier;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Builder setPoNumber(Optional<String> poNumber) {
|
||||||
|
getInstance().poNumber = poNumber.orElse(null);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public Builder setBillingAccountMap(@Nullable Map<CurrencyUnit, String> billingAccountMap) {
|
public Builder setBillingAccountMap(@Nullable Map<CurrencyUnit, String> billingAccountMap) {
|
||||||
if (billingAccountMap == null) {
|
if (billingAccountMap == null) {
|
||||||
getInstance().billingAccountMap = null;
|
getInstance().billingAccountMap = null;
|
||||||
|
|
|
@ -173,6 +173,14 @@ abstract class CreateOrUpdateRegistrarCommand extends MutatingCommand {
|
||||||
validateWith = OptionalLongParameter.class)
|
validateWith = OptionalLongParameter.class)
|
||||||
private Optional<Long> billingId;
|
private Optional<Long> billingId;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Parameter(
|
||||||
|
names = "--po_number",
|
||||||
|
description = "Purchase Order number used for billing invoices",
|
||||||
|
converter = OptionalStringParameter.class,
|
||||||
|
validateWith = OptionalStringParameter.class)
|
||||||
|
private Optional<String> poNumber;
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Parameter(
|
@Parameter(
|
||||||
names = "--billing_account_map",
|
names = "--billing_account_map",
|
||||||
|
@ -352,6 +360,7 @@ abstract class CreateOrUpdateRegistrarCommand extends MutatingCommand {
|
||||||
if (billingId != null) {
|
if (billingId != null) {
|
||||||
builder.setBillingIdentifier(billingId.orElse(null));
|
builder.setBillingIdentifier(billingId.orElse(null));
|
||||||
}
|
}
|
||||||
|
Optional.ofNullable(poNumber).ifPresent(builder::setPoNumber);
|
||||||
if (billingAccountMap != null) {
|
if (billingAccountMap != null) {
|
||||||
LinkedHashMap<CurrencyUnit, String> newBillingAccountMap = new LinkedHashMap<>();
|
LinkedHashMap<CurrencyUnit, String> newBillingAccountMap = new LinkedHashMap<>();
|
||||||
if (oldRegistrar != null && oldRegistrar.getBillingAccountMap() != null) {
|
if (oldRegistrar != null && oldRegistrar.getBillingAccountMap() != null) {
|
||||||
|
|
|
@ -47,6 +47,7 @@ public class BillingEventTest {
|
||||||
+ "{\"name\": \"eventTime\", \"type\": \"string\"},"
|
+ "{\"name\": \"eventTime\", \"type\": \"string\"},"
|
||||||
+ "{\"name\": \"registrarId\", \"type\": \"string\"},"
|
+ "{\"name\": \"registrarId\", \"type\": \"string\"},"
|
||||||
+ "{\"name\": \"billingId\", \"type\": \"long\"},"
|
+ "{\"name\": \"billingId\", \"type\": \"long\"},"
|
||||||
|
+ "{\"name\": \"poNumber\", \"type\": \"string\"},"
|
||||||
+ "{\"name\": \"tld\", \"type\": \"string\"},"
|
+ "{\"name\": \"tld\", \"type\": \"string\"},"
|
||||||
+ "{\"name\": \"action\", \"type\": \"string\"},"
|
+ "{\"name\": \"action\", \"type\": \"string\"},"
|
||||||
+ "{\"name\": \"domain\", \"type\": \"string\"},"
|
+ "{\"name\": \"domain\", \"type\": \"string\"},"
|
||||||
|
@ -62,12 +63,17 @@ public class BillingEventTest {
|
||||||
@Before
|
@Before
|
||||||
public void initializeRecord() {
|
public void initializeRecord() {
|
||||||
// Create a record with a given JSON schema.
|
// Create a record with a given JSON schema.
|
||||||
|
schemaAndRecord = new SchemaAndRecord(createRecord(), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private GenericRecord createRecord() {
|
||||||
GenericRecord record = new GenericData.Record(new Schema.Parser().parse(BILLING_EVENT_SCHEMA));
|
GenericRecord record = new GenericData.Record(new Schema.Parser().parse(BILLING_EVENT_SCHEMA));
|
||||||
record.put("id", "1");
|
record.put("id", "1");
|
||||||
record.put("billingTime", 1508835963000000L);
|
record.put("billingTime", 1508835963000000L);
|
||||||
record.put("eventTime", 1484870383000000L);
|
record.put("eventTime", 1484870383000000L);
|
||||||
record.put("registrarId", "myRegistrar");
|
record.put("registrarId", "myRegistrar");
|
||||||
record.put("billingId", "12345-CRRHELLO");
|
record.put("billingId", "12345-CRRHELLO");
|
||||||
|
record.put("poNumber", "");
|
||||||
record.put("tld", "test");
|
record.put("tld", "test");
|
||||||
record.put("action", "RENEW");
|
record.put("action", "RENEW");
|
||||||
record.put("domain", "example.test");
|
record.put("domain", "example.test");
|
||||||
|
@ -76,7 +82,7 @@ public class BillingEventTest {
|
||||||
record.put("currency", "USD");
|
record.put("currency", "USD");
|
||||||
record.put("amount", 20.5);
|
record.put("amount", 20.5);
|
||||||
record.put("flags", "AUTO_RENEW SYNTHETIC");
|
record.put("flags", "AUTO_RENEW SYNTHETIC");
|
||||||
schemaAndRecord = new SchemaAndRecord(record, null);
|
return record;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -89,6 +95,7 @@ public class BillingEventTest {
|
||||||
.isEqualTo(ZonedDateTime.of(2017, 1, 19, 23, 59, 43, 0, ZoneId.of("UTC")));
|
.isEqualTo(ZonedDateTime.of(2017, 1, 19, 23, 59, 43, 0, ZoneId.of("UTC")));
|
||||||
assertThat(event.registrarId()).isEqualTo("myRegistrar");
|
assertThat(event.registrarId()).isEqualTo("myRegistrar");
|
||||||
assertThat(event.billingId()).isEqualTo("12345-CRRHELLO");
|
assertThat(event.billingId()).isEqualTo("12345-CRRHELLO");
|
||||||
|
assertThat(event.poNumber()).isEmpty();
|
||||||
assertThat(event.tld()).isEqualTo("test");
|
assertThat(event.tld()).isEqualTo("test");
|
||||||
assertThat(event.action()).isEqualTo("RENEW");
|
assertThat(event.action()).isEqualTo("RENEW");
|
||||||
assertThat(event.domain()).isEqualTo("example.test");
|
assertThat(event.domain()).isEqualTo("example.test");
|
||||||
|
@ -149,6 +156,16 @@ public class BillingEventTest {
|
||||||
assertThat(invoiceKey.poNumber()).isEmpty();
|
assertThat(invoiceKey.poNumber()).isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_nonNullPoNumber() {
|
||||||
|
GenericRecord record = createRecord();
|
||||||
|
record.put("poNumber", "905610");
|
||||||
|
BillingEvent event = BillingEvent.parseFromRecord(new SchemaAndRecord(record, null));
|
||||||
|
assertThat(event.poNumber()).isEqualTo("905610");
|
||||||
|
InvoiceGroupingKey invoiceKey = event.getInvoiceGroupingKey();
|
||||||
|
assertThat(invoiceKey.poNumber()).isEqualTo("905610");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testConvertInvoiceGroupingKey_toCsv() {
|
public void testConvertInvoiceGroupingKey_toCsv() {
|
||||||
BillingEvent event = BillingEvent.parseFromRecord(schemaAndRecord);
|
BillingEvent event = BillingEvent.parseFromRecord(schemaAndRecord);
|
||||||
|
@ -174,7 +191,7 @@ public class BillingEventTest {
|
||||||
public void testGetDetailReportHeader() {
|
public void testGetDetailReportHeader() {
|
||||||
assertThat(BillingEvent.getHeader())
|
assertThat(BillingEvent.getHeader())
|
||||||
.isEqualTo(
|
.isEqualTo(
|
||||||
"id,billingTime,eventTime,registrarId,billingId,tld,action,"
|
"id,billingTime,eventTime,registrarId,billingId,poNumber,tld,action,"
|
||||||
+ "domain,repositoryId,years,currency,amount,flags");
|
+ "domain,repositoryId,years,currency,amount,flags");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -76,6 +76,7 @@ public class InvoicingPipelineTest {
|
||||||
ZonedDateTime.of(2017, 10, 4, 0, 0, 0, 0, ZoneId.of("UTC")),
|
ZonedDateTime.of(2017, 10, 4, 0, 0, 0, 0, ZoneId.of("UTC")),
|
||||||
"theRegistrar",
|
"theRegistrar",
|
||||||
"234",
|
"234",
|
||||||
|
"",
|
||||||
"test",
|
"test",
|
||||||
"RENEW",
|
"RENEW",
|
||||||
"mydomain.test",
|
"mydomain.test",
|
||||||
|
@ -90,6 +91,7 @@ public class InvoicingPipelineTest {
|
||||||
ZonedDateTime.of(2017, 10, 4, 0, 0, 0, 0, ZoneId.of("UTC")),
|
ZonedDateTime.of(2017, 10, 4, 0, 0, 0, 0, ZoneId.of("UTC")),
|
||||||
"theRegistrar",
|
"theRegistrar",
|
||||||
"234",
|
"234",
|
||||||
|
"",
|
||||||
"test",
|
"test",
|
||||||
"RENEW",
|
"RENEW",
|
||||||
"mydomain2.test",
|
"mydomain2.test",
|
||||||
|
@ -104,6 +106,7 @@ public class InvoicingPipelineTest {
|
||||||
ZonedDateTime.of(2017, 9, 29, 0, 0, 0, 0, ZoneId.of("UTC")),
|
ZonedDateTime.of(2017, 9, 29, 0, 0, 0, 0, ZoneId.of("UTC")),
|
||||||
"theRegistrar",
|
"theRegistrar",
|
||||||
"234",
|
"234",
|
||||||
|
"",
|
||||||
"hello",
|
"hello",
|
||||||
"CREATE",
|
"CREATE",
|
||||||
"mydomain3.hello",
|
"mydomain3.hello",
|
||||||
|
@ -116,8 +119,9 @@ public class InvoicingPipelineTest {
|
||||||
1,
|
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")),
|
||||||
ZonedDateTime.of(2017, 10, 4, 0, 0, 0, 0, ZoneId.of("UTC")),
|
ZonedDateTime.of(2017, 10, 4, 0, 0, 0, 0, ZoneId.of("UTC")),
|
||||||
"googledomains",
|
"bestdomains",
|
||||||
"456",
|
"456",
|
||||||
|
"116688",
|
||||||
"test",
|
"test",
|
||||||
"RENEW",
|
"RENEW",
|
||||||
"mydomain4.test",
|
"mydomain4.test",
|
||||||
|
@ -132,6 +136,7 @@ public class InvoicingPipelineTest {
|
||||||
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",
|
"anotherRegistrar",
|
||||||
"789",
|
"789",
|
||||||
|
"",
|
||||||
"test",
|
"test",
|
||||||
"CREATE",
|
"CREATE",
|
||||||
"mydomain5.test",
|
"mydomain5.test",
|
||||||
|
@ -155,9 +160,9 @@ public class InvoicingPipelineTest {
|
||||||
ImmutableList.of(
|
ImmutableList.of(
|
||||||
"1,2017-10-02 00:00:00 UTC,2017-09-29 00:00:00 UTC,theRegistrar,234,"
|
"1,2017-10-02 00:00:00 UTC,2017-09-29 00:00:00 UTC,theRegistrar,234,"
|
||||||
+ "hello,CREATE,mydomain3.hello,REPO-ID,5,JPY,70.75,"),
|
+ "hello,CREATE,mydomain3.hello,REPO-ID,5,JPY,70.75,"),
|
||||||
"invoice_details_2017-10_googledomains_test.csv",
|
"invoice_details_2017-10_bestdomains_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,bestdomains,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",
|
"invoice_details_2017-10_anotherRegistrar_test.csv",
|
||||||
ImmutableList.of(
|
ImmutableList.of(
|
||||||
|
@ -171,8 +176,8 @@ public class InvoicingPipelineTest {
|
||||||
+ "RENEW | TLD: test | TERM: 3-year,20.50,USD,",
|
+ "RENEW | TLD: test | TERM: 3-year,20.50,USD,",
|
||||||
"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,bestdomains - test,1,"
|
||||||
+ "RENEW | TLD: test | TERM: 1-year,20.50,USD,",
|
+ "RENEW | TLD: test | TERM: 1-year,20.50,USD,116688",
|
||||||
"2017-10-01,2018-09-30,789,0.00,USD,10125,1,PURCHASE,anotherRegistrar - test,1,"
|
"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,");
|
+ "CREATE | TLD: test | TERM: 1-year,0.00,USD,");
|
||||||
}
|
}
|
||||||
|
@ -187,7 +192,7 @@ public class InvoicingPipelineTest {
|
||||||
for (Entry<String, ImmutableList<String>> entry : getExpectedDetailReportMap().entrySet()) {
|
for (Entry<String, ImmutableList<String>> entry : getExpectedDetailReportMap().entrySet()) {
|
||||||
ImmutableList<String> detailReport = resultFileContents(entry.getKey());
|
ImmutableList<String> detailReport = resultFileContents(entry.getKey());
|
||||||
assertThat(detailReport.get(0))
|
assertThat(detailReport.get(0))
|
||||||
.isEqualTo("id,billingTime,eventTime,registrarId,billingId,tld,action,"
|
.isEqualTo("id,billingTime,eventTime,registrarId,billingId,poNumber,tld,action,"
|
||||||
+ "domain,repositoryId,years,currency,amount,flags");
|
+ "domain,repositoryId,years,currency,amount,flags");
|
||||||
assertThat(detailReport.subList(1, detailReport.size()))
|
assertThat(detailReport.subList(1, detailReport.size()))
|
||||||
.containsExactlyElementsIn(entry.getValue());
|
.containsExactlyElementsIn(entry.getValue());
|
||||||
|
|
|
@ -22,6 +22,7 @@ SELECT
|
||||||
eventTime,
|
eventTime,
|
||||||
BillingEvent.clientId AS registrarId,
|
BillingEvent.clientId AS registrarId,
|
||||||
RegistrarData.accountId AS billingId,
|
RegistrarData.accountId AS billingId,
|
||||||
|
RegistrarData.poNumber AS poNumber,
|
||||||
tld,
|
tld,
|
||||||
reason as action,
|
reason as action,
|
||||||
targetId as domain,
|
targetId as domain,
|
||||||
|
@ -63,6 +64,7 @@ JOIN (
|
||||||
SELECT
|
SELECT
|
||||||
__key__.name AS clientId,
|
__key__.name AS clientId,
|
||||||
billingIdentifier,
|
billingIdentifier,
|
||||||
|
IFNULL(poNumber, '') AS poNumber,
|
||||||
r.billingAccountMap.currency[SAFE_OFFSET(index)] AS currency,
|
r.billingAccountMap.currency[SAFE_OFFSET(index)] AS currency,
|
||||||
r.billingAccountMap.accountId[SAFE_OFFSET(index)] AS accountId
|
r.billingAccountMap.accountId[SAFE_OFFSET(index)] AS accountId
|
||||||
FROM
|
FROM
|
||||||
|
|
|
@ -571,6 +571,7 @@ class google.registry.model.registrar.Registrar {
|
||||||
java.lang.String passwordHash;
|
java.lang.String passwordHash;
|
||||||
java.lang.String phoneNumber;
|
java.lang.String phoneNumber;
|
||||||
java.lang.String phonePasscode;
|
java.lang.String phonePasscode;
|
||||||
|
java.lang.String poNumber;
|
||||||
java.lang.String registrarName;
|
java.lang.String registrarName;
|
||||||
java.lang.String salt;
|
java.lang.String salt;
|
||||||
java.lang.String url;
|
java.lang.String url;
|
||||||
|
|
|
@ -91,6 +91,7 @@ public class CreateRegistrarCommandTest extends CommandTestCase<CreateRegistrarC
|
||||||
assertThat(registrar.getLastUpdateTime()).isEqualTo(registrar.getCreationTime());
|
assertThat(registrar.getLastUpdateTime()).isEqualTo(registrar.getCreationTime());
|
||||||
assertThat(registrar.getBlockPremiumNames()).isFalse();
|
assertThat(registrar.getBlockPremiumNames()).isFalse();
|
||||||
assertThat(registrar.getPremiumPriceAckRequired()).isFalse();
|
assertThat(registrar.getPremiumPriceAckRequired()).isFalse();
|
||||||
|
assertThat(registrar.getPoNumber()).isEmpty();
|
||||||
|
|
||||||
verify(connection).send(
|
verify(connection).send(
|
||||||
eq("/_dr/admin/createGroups"),
|
eq("/_dr/admin/createGroups"),
|
||||||
|
@ -416,6 +417,28 @@ public class CreateRegistrarCommandTest extends CommandTestCase<CreateRegistrarC
|
||||||
assertThat(registrar.get().getBillingIdentifier()).isEqualTo(12345);
|
assertThat(registrar.get().getBillingIdentifier()).isEqualTo(12345);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSuccess_poNumber() throws Exception {
|
||||||
|
runCommandForced(
|
||||||
|
"--name=blobio",
|
||||||
|
"--password=some_password",
|
||||||
|
"--registrar_type=REAL",
|
||||||
|
"--iana_id=8",
|
||||||
|
"--po_number=AA55G",
|
||||||
|
"--passcode=01234",
|
||||||
|
"--icann_referral_email=foo@bar.test",
|
||||||
|
"--street=\"123 Fake St\"",
|
||||||
|
"--city Fakington",
|
||||||
|
"--state MA",
|
||||||
|
"--zip 00351",
|
||||||
|
"--cc US",
|
||||||
|
"clientz");
|
||||||
|
|
||||||
|
Optional<Registrar> registrar = Registrar.loadByClientId("clientz");
|
||||||
|
assertThat(registrar).isPresent();
|
||||||
|
assertThat(registrar.get().getPoNumber()).hasValue("AA55G");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSuccess_billingAccountMap() throws Exception {
|
public void testSuccess_billingAccountMap() throws Exception {
|
||||||
runCommandForced(
|
runCommandForced(
|
||||||
|
|
|
@ -16,6 +16,7 @@ package google.registry.tools;
|
||||||
|
|
||||||
import static com.google.common.base.Strings.isNullOrEmpty;
|
import static com.google.common.base.Strings.isNullOrEmpty;
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
import static com.google.common.truth.Truth8.assertThat;
|
||||||
import static google.registry.testing.CertificateSamples.SAMPLE_CERT;
|
import static google.registry.testing.CertificateSamples.SAMPLE_CERT;
|
||||||
import static google.registry.testing.CertificateSamples.SAMPLE_CERT_HASH;
|
import static google.registry.testing.CertificateSamples.SAMPLE_CERT_HASH;
|
||||||
import static google.registry.testing.DatastoreHelper.createTlds;
|
import static google.registry.testing.DatastoreHelper.createTlds;
|
||||||
|
@ -32,6 +33,7 @@ import google.registry.model.registrar.Registrar;
|
||||||
import google.registry.model.registrar.Registrar.State;
|
import google.registry.model.registrar.Registrar.State;
|
||||||
import google.registry.model.registrar.Registrar.Type;
|
import google.registry.model.registrar.Registrar.Type;
|
||||||
import google.registry.util.CidrAddressBlock;
|
import google.registry.util.CidrAddressBlock;
|
||||||
|
import java.util.Optional;
|
||||||
import org.joda.money.CurrencyUnit;
|
import org.joda.money.CurrencyUnit;
|
||||||
import org.joda.time.DateTime;
|
import org.joda.time.DateTime;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
@ -205,6 +207,13 @@ public class UpdateRegistrarCommandTest extends CommandTestCase<UpdateRegistrarC
|
||||||
assertThat(loadRegistrar("NewRegistrar").getBillingIdentifier()).isEqualTo(12345);
|
assertThat(loadRegistrar("NewRegistrar").getBillingIdentifier()).isEqualTo(12345);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSuccess_poNumber() throws Exception {
|
||||||
|
assertThat(loadRegistrar("NewRegistrar").getPoNumber()).isEmpty();
|
||||||
|
runCommand("--po_number=52345", "--force", "NewRegistrar");
|
||||||
|
assertThat(loadRegistrar("NewRegistrar").getPoNumber()).hasValue("52345");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSuccess_billingAccountMap() throws Exception {
|
public void testSuccess_billingAccountMap() throws Exception {
|
||||||
assertThat(loadRegistrar("NewRegistrar").getBillingAccountMap()).isEmpty();
|
assertThat(loadRegistrar("NewRegistrar").getBillingAccountMap()).isEmpty();
|
||||||
|
@ -698,4 +707,24 @@ public class UpdateRegistrarCommandTest extends CommandTestCase<UpdateRegistrarC
|
||||||
IllegalArgumentException.class,
|
IllegalArgumentException.class,
|
||||||
() -> runCommand("--name tHeRe GiStRaR", "--force", "NewRegistrar"));
|
() -> runCommand("--name tHeRe GiStRaR", "--force", "NewRegistrar"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSuccess_poNumberNotSpecified_doesntWipeOutExisting() throws Exception {
|
||||||
|
Registrar registrar =
|
||||||
|
persistResource(
|
||||||
|
loadRegistrar("NewRegistrar").asBuilder().setPoNumber(Optional.of("1664")).build());
|
||||||
|
assertThat(registrar.testPassword("some_password")).isFalse();
|
||||||
|
runCommand("--password=some_password", "--force", "NewRegistrar");
|
||||||
|
Registrar reloadedRegistrar = loadRegistrar("NewRegistrar");
|
||||||
|
assertThat(reloadedRegistrar.testPassword("some_password")).isTrue();
|
||||||
|
assertThat(reloadedRegistrar.getPoNumber()).hasValue("1664");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSuccess_poNumber_canBeBlanked() throws Exception {
|
||||||
|
persistResource(
|
||||||
|
loadRegistrar("NewRegistrar").asBuilder().setPoNumber(Optional.of("1664")).build());
|
||||||
|
runCommand("--po_number=null", "--force", "NewRegistrar");
|
||||||
|
assertThat(loadRegistrar("NewRegistrar").getPoNumber()).isEmpty();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue