Add EAP fees to domain create flow

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=126411200
This commit is contained in:
ctingue 2016-07-01 08:16:31 -07:00 committed by Ben McIlwain
parent d6bd2d56cd
commit 273fc0014d
7 changed files with 118 additions and 18 deletions

View file

@ -36,7 +36,6 @@ import static google.registry.model.EppResourceUtils.loadByUniqueId;
import static google.registry.model.ofy.ObjectifyService.ofy; import static google.registry.model.ofy.ObjectifyService.ofy;
import static google.registry.model.registry.Registries.findTldForName; import static google.registry.model.registry.Registries.findTldForName;
import static google.registry.model.registry.label.ReservedList.matchesAnchorTenantReservation; import static google.registry.model.registry.label.ReservedList.matchesAnchorTenantReservation;
import static google.registry.pricing.PricingEngineProxy.getDomainCreateCost;
import static google.registry.util.CollectionUtils.nullToEmpty; import static google.registry.util.CollectionUtils.nullToEmpty;
import com.google.common.base.Optional; import com.google.common.base.Optional;
@ -66,8 +65,8 @@ import google.registry.model.registry.Registry;
import google.registry.model.registry.Registry.TldState; import google.registry.model.registry.Registry.TldState;
import google.registry.model.smd.SignedMark; import google.registry.model.smd.SignedMark;
import google.registry.model.tmch.ClaimsListShard; import google.registry.model.tmch.ClaimsListShard;
import google.registry.pricing.TldSpecificLogicEngine;
import org.joda.money.Money; import google.registry.pricing.TldSpecificLogicEngine.EppCommandOperations;
import java.util.Set; import java.util.Set;
@ -89,7 +88,7 @@ public abstract class BaseDomainCreateFlow<R extends DomainBase, B extends Build
protected InternetDomainName domainName; protected InternetDomainName domainName;
protected String idnTableName; protected String idnTableName;
protected FeeCreateExtension feeCreate; protected FeeCreateExtension feeCreate;
protected Money createCost; protected EppCommandOperations commandOperations;
protected boolean hasSignedMarks; protected boolean hasSignedMarks;
protected SignedMark signedMark; protected SignedMark signedMark;
protected boolean isAnchorTenantViaReservation; protected boolean isAnchorTenantViaReservation;
@ -181,7 +180,8 @@ public abstract class BaseDomainCreateFlow<R extends DomainBase, B extends Build
tldState = registry.getTldState(now); tldState = registry.getTldState(now);
checkRegistryStateForTld(tld); checkRegistryStateForTld(tld);
domainLabel = domainName.parts().get(0); domainLabel = domainName.parts().get(0);
createCost = getDomainCreateCost(targetId, now, command.getPeriod().getValue()); commandOperations = TldSpecificLogicEngine.getCreatePrice(
registry, domainName.toString(), now, command.getPeriod().getValue());
// The TLD should always be the parent of the requested domain name. // The TLD should always be the parent of the requested domain name.
isAnchorTenantViaReservation = matchesAnchorTenantReservation( isAnchorTenantViaReservation = matchesAnchorTenantReservation(
domainLabel, tld, command.getAuthInfo().getPw().getValue()); domainLabel, tld, command.getAuthInfo().getPw().getValue());

View file

@ -33,7 +33,6 @@ import google.registry.model.domain.DomainApplication;
import google.registry.model.domain.DomainApplication.Builder; import google.registry.model.domain.DomainApplication.Builder;
import google.registry.model.domain.DomainResource; import google.registry.model.domain.DomainResource;
import google.registry.model.domain.Period; import google.registry.model.domain.Period;
import google.registry.model.domain.fee.Fee;
import google.registry.model.domain.fee.FeeCreateExtension; import google.registry.model.domain.fee.FeeCreateExtension;
import google.registry.model.domain.fee.FeeCreateResponseExtension; import google.registry.model.domain.fee.FeeCreateResponseExtension;
import google.registry.model.domain.launch.ApplicationStatus; import google.registry.model.domain.launch.ApplicationStatus;
@ -143,7 +142,8 @@ public class DomainApplicationCreateFlow extends BaseDomainCreateFlow<DomainAppl
@Override @Override
protected void verifyDomainCreateIsAllowed() throws EppException { protected void verifyDomainCreateIsAllowed() throws EppException {
validateFeeChallenge(targetId, getTld(), now, feeCreate, createCost); validateFeeChallenge(
targetId, getTld(), now, feeCreate, commandOperations.getTotalCost());
if (tldState == TldState.LANDRUSH && !isSuperuser) { if (tldState == TldState.LANDRUSH && !isSuperuser) {
// Prohibit creating a landrush application in LANDRUSH (but not in SUNRUSH) if there is // Prohibit creating a landrush application in LANDRUSH (but not in SUNRUSH) if there is
// exactly one sunrise application for the same name. // exactly one sunrise application for the same name.
@ -214,8 +214,8 @@ public class DomainApplicationCreateFlow extends BaseDomainCreateFlow<DomainAppl
.build()); .build());
if (feeCreate != null) { if (feeCreate != null) {
responseExtensionsBuilder.add(new FeeCreateResponseExtension.Builder() responseExtensionsBuilder.add(new FeeCreateResponseExtension.Builder()
.setCurrency(createCost.getCurrencyUnit()) .setCurrency(commandOperations.getCurrency())
.setFee(ImmutableList.of(Fee.create(createCost.getAmount(), "create"))) .setFee(commandOperations.getFees())
.build()); .build());
} }

View file

@ -14,7 +14,6 @@
package google.registry.flows.domain; package google.registry.flows.domain;
import static com.google.common.base.Preconditions.checkNotNull;
import static google.registry.flows.domain.DomainFlowUtils.validateFeeChallenge; import static google.registry.flows.domain.DomainFlowUtils.validateFeeChallenge;
import static google.registry.model.index.DomainApplicationIndex.loadActiveApplicationsByDomainName; import static google.registry.model.index.DomainApplicationIndex.loadActiveApplicationsByDomainName;
import static google.registry.model.ofy.ObjectifyService.ofy; import static google.registry.model.ofy.ObjectifyService.ofy;
@ -112,7 +111,7 @@ public class DomainCreateFlow extends DomainCreateOrAllocateFlow {
@Override @Override
protected final void verifyDomainCreateIsAllowed() throws EppException { protected final void verifyDomainCreateIsAllowed() throws EppException {
String tld = getTld(); String tld = getTld();
validateFeeChallenge(targetId, tld, now, feeCreate, createCost); validateFeeChallenge(targetId, tld, now, feeCreate, commandOperations.getTotalCost());
if (!isSuperuser) { if (!isSuperuser) {
// Prohibit creating a domain if there is an open application for the same name. // Prohibit creating a domain if there is an open application for the same name.
for (DomainApplication application : loadActiveApplicationsByDomainName(targetId, now)) { for (DomainApplication application : loadActiveApplicationsByDomainName(targetId, now)) {
@ -151,13 +150,15 @@ public class DomainCreateFlow extends DomainCreateOrAllocateFlow {
@Override @Override
protected final void setDomainCreateOrAllocateProperties(Builder builder) throws EppException { protected final void setDomainCreateOrAllocateProperties(Builder builder) throws EppException {
Registry registry = Registry.get(getTld()); Registry registry = Registry.get(getTld());
// Bill for the create. // Bill for the create.
BillingEvent.OneTime createEvent = new BillingEvent.OneTime.Builder() BillingEvent.OneTime createEvent = new BillingEvent.OneTime.Builder()
.setReason(Reason.CREATE) .setReason(Reason.CREATE)
.setTargetId(targetId) .setTargetId(targetId)
.setClientId(getClientId()) .setClientId(getClientId())
.setPeriodYears(command.getPeriod().getValue()) .setPeriodYears(command.getPeriod().getValue())
.setCost(checkNotNull(createCost)) // TODO(b/29089413): the EAP fee needs to be a separate billing event.
.setCost(commandOperations.getTotalCost())
.setEventTime(now) .setEventTime(now)
.setBillingTime(now.plus(isAnchorTenant() .setBillingTime(now.plus(isAnchorTenant()
? registry.getAnchorTenantAddGracePeriodLength() ? registry.getAnchorTenantAddGracePeriodLength()

View file

@ -31,7 +31,6 @@ import google.registry.model.billing.BillingEvent.Reason;
import google.registry.model.domain.DomainResource; import google.registry.model.domain.DomainResource;
import google.registry.model.domain.DomainResource.Builder; import google.registry.model.domain.DomainResource.Builder;
import google.registry.model.domain.Period; import google.registry.model.domain.Period;
import google.registry.model.domain.fee.Fee;
import google.registry.model.domain.fee.FeeCreateResponseExtension; import google.registry.model.domain.fee.FeeCreateResponseExtension;
import google.registry.model.eppoutput.CreateData.DomainCreateData; import google.registry.model.eppoutput.CreateData.DomainCreateData;
import google.registry.model.eppoutput.EppOutput; import google.registry.model.eppoutput.EppOutput;
@ -113,8 +112,8 @@ public abstract class DomainCreateOrAllocateFlow
newResource.getRegistrationExpirationTime()), newResource.getRegistrationExpirationTime()),
(feeCreate == null) ? null : ImmutableList.of( (feeCreate == null) ? null : ImmutableList.of(
new FeeCreateResponseExtension.Builder() new FeeCreateResponseExtension.Builder()
.setCurrency(createCost.getCurrencyUnit()) .setCurrency(commandOperations.getCurrency())
.setFee(ImmutableList.of(Fee.create(createCost.getAmount(), "create"))) .setFee(commandOperations.getFees())
.build())); .build()));
} }
} }

View file

@ -161,6 +161,16 @@ public class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow,
private void assertSuccessfulCreate(String domainTld, boolean isAnchorTenant) throws Exception { private void assertSuccessfulCreate(String domainTld, boolean isAnchorTenant) throws Exception {
DomainResource domain = reloadResourceByUniqueId(); DomainResource domain = reloadResourceByUniqueId();
// Calculate the total cost.
Money cost = getPricesForDomainName(getUniqueIdFromCommand(), clock.nowUtc()).isPremium()
? Money.of(USD, 200)
: Money.of(USD, 26);
Money eapFee = Registry.get(domainTld).getEapFeeFor(clock.nowUtc()).getCost();
if (!eapFee.isZero()) {
cost = Money.total(cost, eapFee);
}
DateTime billingTime = isAnchorTenant DateTime billingTime = isAnchorTenant
? clock.nowUtc().plus(Registry.get(domainTld).getAnchorTenantAddGracePeriodLength()) ? clock.nowUtc().plus(Registry.get(domainTld).getAnchorTenantAddGracePeriodLength())
: clock.nowUtc().plus(Registry.get(domainTld).getAddGracePeriodLength()); : clock.nowUtc().plus(Registry.get(domainTld).getAddGracePeriodLength());
@ -178,9 +188,7 @@ public class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow,
.setReason(Reason.CREATE) .setReason(Reason.CREATE)
.setTargetId(getUniqueIdFromCommand()) .setTargetId(getUniqueIdFromCommand())
.setClientId("TheRegistrar") .setClientId("TheRegistrar")
.setCost(getPricesForDomainName(getUniqueIdFromCommand(), clock.nowUtc()).isPremium() .setCost(cost)
? Money.of(USD, 200)
: Money.of(USD, 26))
.setPeriodYears(2) .setPeriodYears(2)
.setEventTime(clock.nowUtc()) .setEventTime(clock.nowUtc())
.setBillingTime(billingTime) .setBillingTime(billingTime)
@ -1280,4 +1288,41 @@ public class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow,
persistContactsAndHosts(); persistContactsAndHosts();
doSuccessfulTest("tld", "domain_create_response.xml"); doSuccessfulTest("tld", "domain_create_response.xml");
} }
@Test
public void testSuccess_eapFeeApplied() throws Exception {
setEppInput("domain_create_eap_fee.xml");
persistContactsAndHosts();
persistResource(Registry.get("tld").asBuilder()
.setEapFeeSchedule(ImmutableSortedMap.of(
START_OF_TIME, Money.of(USD, 0),
clock.nowUtc().minusDays(1), Money.of(USD, 100),
clock.nowUtc().plusDays(1), Money.of(USD, 0)))
.build());
doSuccessfulTest("tld", "domain_create_response_eap_fee.xml");
}
@Test
public void testSuccess_eapFee_beforeEntireSchedule() throws Exception {
persistContactsAndHosts();
persistResource(Registry.get("tld").asBuilder()
.setEapFeeSchedule(ImmutableSortedMap.of(
START_OF_TIME, Money.of(USD, 0),
clock.nowUtc().plusDays(1), Money.of(USD, 10),
clock.nowUtc().plusDays(2), Money.of(USD, 0)))
.build());
doSuccessfulTest("tld", "domain_create_response.xml");
}
@Test
public void testSuccess_eapFee_afterEntireSchedule() throws Exception {
persistContactsAndHosts();
persistResource(Registry.get("tld").asBuilder()
.setEapFeeSchedule(ImmutableSortedMap.of(
START_OF_TIME, Money.of(USD, 0),
clock.nowUtc().minusDays(2), Money.of(USD, 100),
clock.nowUtc().minusDays(1), Money.of(USD, 0)))
.build());
doSuccessfulTest("tld", "domain_create_response.xml");
}
} }

View file

@ -0,0 +1,29 @@
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
<command>
<create>
<domain:create
xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
<domain:name>example.tld</domain:name>
<domain:period unit="y">2</domain:period>
<domain:ns>
<domain:hostObj>ns1.example.net</domain:hostObj>
<domain:hostObj>ns2.example.net</domain:hostObj>
</domain:ns>
<domain:registrant>jd1234</domain:registrant>
<domain:contact type="admin">sh8013</domain:contact>
<domain:contact type="tech">sh8013</domain:contact>
<domain:authInfo>
<domain:pw>2fooBAR</domain:pw>
</domain:authInfo>
</domain:create>
</create>
<extension>
<fee:create xmlns:fee="urn:ietf:params:xml:ns:fee-0.6">
<fee:currency>USD</fee:currency>
<fee:fee>26.00</fee:fee>
<fee:fee description="Early Access Period">100.00</fee:fee>
</fee:create>
</extension>
<clTRID>ABC-12345</clTRID>
</command>
</epp>

View file

@ -0,0 +1,26 @@
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
<response>
<result code="1000">
<msg>Command completed successfully</msg>
</result>
<resData>
<domain:creData
xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
<domain:name>example.tld</domain:name>
<domain:crDate>1999-04-03T22:00:00.0Z</domain:crDate>
<domain:exDate>2001-04-03T22:00:00.0Z</domain:exDate>
</domain:creData>
</resData>
<extension>
<fee:creData xmlns:fee="urn:ietf:params:xml:ns:fee-0.6">
<fee:currency>USD</fee:currency>
<fee:fee description="create">26.00</fee:fee>
<fee:fee description="Early Access Period, fee expires: 1999-04-04T22:00:00.000Z">100.00</fee:fee>
</fee:creData>
</extension>
<trID>
<clTRID>ABC-12345</clTRID>
<svTRID>server-trid</svTRID>
</trID>
</response>
</epp>