Restrict domain transfer pricing to 1 year

This CL restricts domain transfer pricing lookups (on domain check and info) to
only support a 1-year period for inquiring about transfer fees.  That treatment
matches what we do for domain restores, which are also always one year.  This is
a followup to [] which disallowed actual transfer request flows from
specifying multi-year periods.

Since it's no longer necessary, this CL also changes the domain transfer pricing
logic to drop the years parameter, including removing the parameter from the
custom pricing logic TransferPriceParameters object.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=150367839
This commit is contained in:
nickfelt 2017-03-16 14:19:10 -07:00 committed by Ben McIlwain
parent 8b37620af1
commit 70fbdccea2
15 changed files with 133 additions and 18 deletions

View file

@ -576,6 +576,7 @@ information about the domain.
* The requested fees cannot be provided in the requested currency. * The requested fees cannot be provided in the requested currency.
* Fee checks for command phases and subphases are not supported. * Fee checks for command phases and subphases are not supported.
* Restores always renew a domain for one year. * Restores always renew a domain for one year.
* Transfers always renew a domain for one year.
## DomainDeleteFlow ## DomainDeleteFlow
@ -712,6 +713,7 @@ information.
* Domain labels cannot begin with a dash. * Domain labels cannot begin with a dash.
* Restores always renew a domain for one year. * Restores always renew a domain for one year.
* Domain labels cannot end with a dash. * Domain labels cannot end with a dash.
* Transfers always renew a domain for one year.
* Unknown fee command name. * Unknown fee command name.
* By server policy, fee check names must be listed in the availability * By server policy, fee check names must be listed in the availability
check. check.

View file

@ -229,8 +229,6 @@ public class DomainPricingCustomLogic extends BaseFlowCustomLogic {
public abstract DateTime asOfDate(); public abstract DateTime asOfDate();
public abstract int years();
public static Builder newBuilder() { public static Builder newBuilder() {
return new AutoValue_DomainPricingCustomLogic_TransferPriceParameters.Builder(); return new AutoValue_DomainPricingCustomLogic_TransferPriceParameters.Builder();
} }
@ -247,8 +245,6 @@ public class DomainPricingCustomLogic extends BaseFlowCustomLogic {
public abstract Builder setAsOfDate(DateTime asOfDate); public abstract Builder setAsOfDate(DateTime asOfDate);
public abstract Builder setYears(int years);
public abstract TransferPriceParameters build(); public abstract TransferPriceParameters build();
} }
} }

View file

@ -90,6 +90,7 @@ import org.joda.time.DateTime;
* @error {@link DomainFlowUtils.RestoresAreAlwaysForOneYearException} * @error {@link DomainFlowUtils.RestoresAreAlwaysForOneYearException}
* @error {@link DomainFlowUtils.TldDoesNotExistException} * @error {@link DomainFlowUtils.TldDoesNotExistException}
* @error {@link DomainFlowUtils.TrailingDashException} * @error {@link DomainFlowUtils.TrailingDashException}
* @error {@link DomainFlowUtils.TransfersAreAlwaysForOneYearException}
* @error {@link DomainFlowUtils.UnknownFeeCommandException} * @error {@link DomainFlowUtils.UnknownFeeCommandException}
* @error {@link OnlyCheckedNamesCanBeFeeCheckedException} * @error {@link OnlyCheckedNamesCanBeFeeCheckedException}
*/ */

View file

@ -540,8 +540,11 @@ public class DomainFlowUtils {
fees = pricingLogic.getRestorePrice(registry, domainNameString, now).getFees(); fees = pricingLogic.getRestorePrice(registry, domainNameString, now).getFees();
break; break;
case TRANSFER: case TRANSFER:
if (years != 1) {
throw new TransfersAreAlwaysForOneYearException();
}
builder.setAvailIfSupported(true); builder.setAvailIfSupported(true);
fees = pricingLogic.getTransferPrice(registry, domainNameString, now, years).getFees(); fees = pricingLogic.getTransferPrice(registry, domainNameString, now).getFees();
break; break;
case UPDATE: case UPDATE:
builder.setAvailIfSupported(true); builder.setAvailIfSupported(true);
@ -1113,6 +1116,13 @@ public class DomainFlowUtils {
} }
} }
/** Transfers always renew a domain for one year. */
static class TransfersAreAlwaysForOneYearException extends ParameterValuePolicyErrorException {
TransfersAreAlwaysForOneYearException() {
super("Transfers always renew a domain for one year");
}
}
/** Requested domain is reserved. */ /** Requested domain is reserved. */
static class DomainReservedException extends StatusProhibitsOperationException { static class DomainReservedException extends StatusProhibitsOperationException {
public DomainReservedException(String domainName) { public DomainReservedException(String domainName) {

View file

@ -66,6 +66,7 @@ import org.joda.time.DateTime;
* @error {@link DomainFlowUtils.CurrencyUnitMismatchException} * @error {@link DomainFlowUtils.CurrencyUnitMismatchException}
* @error {@link DomainFlowUtils.FeeChecksDontSupportPhasesException} * @error {@link DomainFlowUtils.FeeChecksDontSupportPhasesException}
* @error {@link DomainFlowUtils.RestoresAreAlwaysForOneYearException} * @error {@link DomainFlowUtils.RestoresAreAlwaysForOneYearException}
* @error {@link DomainFlowUtils.TransfersAreAlwaysForOneYearException}
*/ */
public final class DomainInfoFlow implements Flow { public final class DomainInfoFlow implements Flow {

View file

@ -110,7 +110,6 @@ public final class DomainPricingLogic {
} }
/** Returns a new restore price for the pricer. */ /** Returns a new restore price for the pricer. */
@SuppressWarnings("unused")
public FeesAndCredits getRestorePrice(Registry registry, String domainName, DateTime date) public FeesAndCredits getRestorePrice(Registry registry, String domainName, DateTime date)
throws EppException { throws EppException {
FeesAndCredits feesAndCredits = FeesAndCredits feesAndCredits =
@ -131,13 +130,9 @@ public final class DomainPricingLogic {
} }
/** Returns a new transfer price for the pricer. */ /** Returns a new transfer price for the pricer. */
public FeesAndCredits getTransferPrice( public FeesAndCredits getTransferPrice(Registry registry, String domainName, DateTime date)
Registry registry,
String domainName,
DateTime transferDate,
int years)
throws EppException { throws EppException {
Money renewCost = getDomainRenewCost(domainName, transferDate, years); Money renewCost = getDomainRenewCost(domainName, date, 1);
return customLogic.customizeTransferPrice( return customLogic.customizeTransferPrice(
TransferPriceParameters.newBuilder() TransferPriceParameters.newBuilder()
.setFeesAndCredits( .setFeesAndCredits(
@ -147,8 +142,7 @@ public final class DomainPricingLogic {
.build()) .build())
.setRegistry(registry) .setRegistry(registry)
.setDomainName(InternetDomainName.from(domainName)) .setDomainName(InternetDomainName.from(domainName))
.setAsOfDate(transferDate) .setAsOfDate(date)
.setYears(years)
.build()); .build());
} }

View file

@ -137,7 +137,7 @@ public final class DomainTransferRequestFlow implements TransactionalFlow {
// An optional extension from the client specifying what they think the transfer should cost. // An optional extension from the client specifying what they think the transfer should cost.
FeeTransferCommandExtension feeTransfer = FeeTransferCommandExtension feeTransfer =
eppInput.getSingleExtension(FeeTransferCommandExtension.class); eppInput.getSingleExtension(FeeTransferCommandExtension.class);
FeesAndCredits feesAndCredits = pricingLogic.getTransferPrice(registry, targetId, now, years); FeesAndCredits feesAndCredits = pricingLogic.getTransferPrice(registry, targetId, now);
validateFeeChallenge(targetId, tld, now, feeTransfer, feesAndCredits); validateFeeChallenge(targetId, tld, now, feeTransfer, feesAndCredits);
HistoryEntry historyEntry = buildHistory(period, existingDomain, now); HistoryEntry historyEntry = buildHistory(period, existingDomain, now);
DateTime automaticTransferTime = now.plus(registry.getAutomaticTransferLength()); DateTime automaticTransferTime = now.plus(registry.getAutomaticTransferLength());

View file

@ -47,6 +47,7 @@ import google.registry.flows.domain.DomainFlowUtils.NotAuthorizedForTldException
import google.registry.flows.domain.DomainFlowUtils.RestoresAreAlwaysForOneYearException; import google.registry.flows.domain.DomainFlowUtils.RestoresAreAlwaysForOneYearException;
import google.registry.flows.domain.DomainFlowUtils.TldDoesNotExistException; import google.registry.flows.domain.DomainFlowUtils.TldDoesNotExistException;
import google.registry.flows.domain.DomainFlowUtils.TrailingDashException; import google.registry.flows.domain.DomainFlowUtils.TrailingDashException;
import google.registry.flows.domain.DomainFlowUtils.TransfersAreAlwaysForOneYearException;
import google.registry.flows.domain.DomainFlowUtils.UnknownFeeCommandException; import google.registry.flows.domain.DomainFlowUtils.UnknownFeeCommandException;
import google.registry.flows.exceptions.TooManyResourceChecksException; import google.registry.flows.exceptions.TooManyResourceChecksException;
import google.registry.model.domain.DomainResource; import google.registry.model.domain.DomainResource;
@ -767,6 +768,27 @@ public class DomainCheckFlowTest
runFlow(); runFlow();
} }
@Test
public void testFeeExtension_multiyearTransfer_v06() throws Exception {
setEppInput("domain_check_fee_multiyear_transfer_v06.xml");
thrown.expect(TransfersAreAlwaysForOneYearException.class);
runFlow();
}
@Test
public void testFeeExtension_multiyearTransfer_v11() throws Exception {
setEppInput("domain_check_fee_multiyear_transfer_v11.xml");
thrown.expect(TransfersAreAlwaysForOneYearException.class);
runFlow();
}
@Test
public void testFeeExtension_multiyearTransfer_v12() throws Exception {
setEppInput("domain_check_fee_multiyear_transfer_v12.xml");
thrown.expect(TransfersAreAlwaysForOneYearException.class);
runFlow();
}
@Test @Test
public void testFeeExtension_unknownCommand_v06() throws Exception { public void testFeeExtension_unknownCommand_v06() throws Exception {
setEppInput("domain_check_fee_unknown_command_v06.xml"); setEppInput("domain_check_fee_unknown_command_v06.xml");

View file

@ -43,6 +43,7 @@ import google.registry.flows.domain.DomainFlowUtils.BadPeriodUnitException;
import google.registry.flows.domain.DomainFlowUtils.CurrencyUnitMismatchException; import google.registry.flows.domain.DomainFlowUtils.CurrencyUnitMismatchException;
import google.registry.flows.domain.DomainFlowUtils.FeeChecksDontSupportPhasesException; import google.registry.flows.domain.DomainFlowUtils.FeeChecksDontSupportPhasesException;
import google.registry.flows.domain.DomainFlowUtils.RestoresAreAlwaysForOneYearException; import google.registry.flows.domain.DomainFlowUtils.RestoresAreAlwaysForOneYearException;
import google.registry.flows.domain.DomainFlowUtils.TransfersAreAlwaysForOneYearException;
import google.registry.model.billing.BillingEvent.Recurring; import google.registry.model.billing.BillingEvent.Recurring;
import google.registry.model.contact.ContactAuthInfo; import google.registry.model.contact.ContactAuthInfo;
import google.registry.model.contact.ContactResource; import google.registry.model.contact.ContactResource;
@ -625,6 +626,15 @@ public class DomainInfoFlowTest extends ResourceFlowTestCase<DomainInfoFlow, Dom
runFlow(); runFlow();
} }
/** Test a transfer for more than one year. */
@Test
public void testFeeExtension_multiyearTransfer() throws Exception {
setEppInput("domain_info_fee_multiyear_transfer.xml");
persistTestEntities(false);
thrown.expect(TransfersAreAlwaysForOneYearException.class);
runFlow();
}
/** Test that we load contacts and hosts as a batch rather than individually. */ /** Test that we load contacts and hosts as a batch rather than individually. */
@Test @Test
public void testBatchLoadingOfReferences() throws Exception { public void testBatchLoadingOfReferences() throws Exception {

View file

@ -0,0 +1,22 @@
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
<command>
<check>
<domain:check xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
<domain:name>example1.tld</domain:name>
</domain:check>
</check>
<extension>
<launch:check xmlns:launch="urn:ietf:params:xml:ns:launch-1.0" type="avail">
<launch:phase name="foo">custom</launch:phase>
</launch:check>
<fee:check xmlns:fee="urn:ietf:params:xml:ns:fee-0.6">
<fee:domain>
<fee:name>example1.tld</fee:name>
<fee:command>transfer</fee:command>
<fee:period unit="y">2</fee:period>
</fee:domain>
</fee:check>
</extension>
<clTRID>ABC-12345</clTRID>
</command>
</epp>

View file

@ -0,0 +1,19 @@
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
<command>
<check>
<domain:check xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
<domain:name>example1.tld</domain:name>
</domain:check>
</check>
<extension>
<launch:check xmlns:launch="urn:ietf:params:xml:ns:launch-1.0" type="avail">
<launch:phase name="foo">custom</launch:phase>
</launch:check>
<fee:check xmlns:fee="urn:ietf:params:xml:ns:fee-0.11">
<fee:command>transfer</fee:command>
<fee:period unit="y">2</fee:period>
</fee:check>
</extension>
<clTRID>ABC-12345</clTRID>
</command>
</epp>

View file

@ -0,0 +1,20 @@
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
<command>
<check>
<domain:check xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
<domain:name>example1.tld</domain:name>
</domain:check>
</check>
<extension>
<launch:check xmlns:launch="urn:ietf:params:xml:ns:launch-1.0" type="avail">
<launch:phase name="foo">custom</launch:phase>
</launch:check>
<fee:check xmlns:fee="urn:ietf:params:xml:ns:fee-0.12">
<fee:command name="transfer">
<fee:period unit="y">2</fee:period>
</fee:command>
</fee:check>
</extension>
<clTRID>ABC-12345</clTRID>
</command>
</epp>

View file

@ -0,0 +1,18 @@
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
<command>
<info>
<domain:info
xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
<domain:name hosts="all">example.tld</domain:name>
</domain:info>
</info>
<extension>
<fee:info xmlns:fee="urn:ietf:params:xml:ns:fee-0.6">
<fee:currency>USD</fee:currency>
<fee:command>transfer</fee:command>
<fee:period unit="y">2</fee:period>
</fee:info>
</extension>
<clTRID>ABC-12345</clTRID>
</command>
</epp>

View file

@ -10,7 +10,7 @@
<fee:info xmlns:fee="urn:ietf:params:xml:ns:fee-0.6"> <fee:info xmlns:fee="urn:ietf:params:xml:ns:fee-0.6">
<fee:currency>USD</fee:currency> <fee:currency>USD</fee:currency>
<fee:command>transfer</fee:command> <fee:command>transfer</fee:command>
<fee:period unit="y">2</fee:period> <fee:period unit="y">1</fee:period>
</fee:info> </fee:info>
</extension> </extension>
<clTRID>ABC-12345</clTRID> <clTRID>ABC-12345</clTRID>

View file

@ -34,8 +34,8 @@
<fee:infData xmlns:fee="urn:ietf:params:xml:ns:fee-0.6"> <fee:infData xmlns:fee="urn:ietf:params:xml:ns:fee-0.6">
<fee:currency>USD</fee:currency> <fee:currency>USD</fee:currency>
<fee:command>transfer</fee:command> <fee:command>transfer</fee:command>
<fee:period unit="y">2</fee:period> <fee:period unit="y">1</fee:period>
<fee:fee description="renew">22.00</fee:fee> <fee:fee description="renew">11.00</fee:fee>
</fee:infData> </fee:infData>
</extension> </extension>
<trID> <trID>