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:
mcilwain 2018-09-19 08:30:03 -07:00 committed by Ben McIlwain
parent 3fc7271145
commit 633b30725a
10 changed files with 138 additions and 12 deletions

View file

@ -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();

View file

@ -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

View file

@ -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;

View file

@ -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) {

View file

@ -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");
} }

View file

@ -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());

View file

@ -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

View file

@ -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;

View file

@ -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(

View file

@ -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();
}
} }