Add renewal cost logic to DomainPricingLogic (#1610)

* Add renew cost calculation to DomainPricingLogic

* Fix typos and change assertions
This commit is contained in:
Rachel Guan
2022-05-19 16:05:21 -04:00
committed by GitHub
parent 3a7ac669f5
commit 64fba55f06
6 changed files with 467 additions and 11 deletions
@@ -33,7 +33,7 @@ import org.joda.time.DateTime;
*/
public class DomainPricingCustomLogic extends BaseFlowCustomLogic {
protected DomainPricingCustomLogic(
public DomainPricingCustomLogic(
EppInput eppInput, SessionMetadata sessionMetadata, FlowMetadata flowMetadata) {
super(eppInput, sessionMetadata, flowMetadata);
}
@@ -680,7 +680,7 @@ public class DomainFlowUtils {
break;
case RENEW:
builder.setAvailIfSupported(true);
fees = pricingLogic.getRenewPrice(registry, domainNameString, now, years).getFees();
fees = pricingLogic.getRenewPrice(registry, domainNameString, now, years, null).getFees();
break;
case RESTORE:
// The minimum allowable period per the EPP spec is 1, so, strangely, 1 year still has to be
@@ -14,8 +14,11 @@
package google.registry.flows.domain;
import static com.google.common.base.Preconditions.checkArgument;
import static google.registry.flows.domain.DomainFlowUtils.zeroInCurrency;
import static google.registry.pricing.PricingEngineProxy.getPricesForDomainName;
import static google.registry.util.DomainNameUtils.getTldFromDomainName;
import static google.registry.util.PreconditionsUtils.checkArgumentPresent;
import com.google.common.net.InternetDomainName;
import google.registry.flows.EppException;
@@ -27,15 +30,16 @@ import google.registry.flows.custom.DomainPricingCustomLogic.RenewPriceParameter
import google.registry.flows.custom.DomainPricingCustomLogic.RestorePriceParameters;
import google.registry.flows.custom.DomainPricingCustomLogic.TransferPriceParameters;
import google.registry.flows.custom.DomainPricingCustomLogic.UpdatePriceParameters;
import google.registry.model.billing.BillingEvent.Recurring;
import google.registry.model.domain.fee.BaseFee;
import google.registry.model.domain.fee.BaseFee.FeeType;
import google.registry.model.domain.fee.Fee;
import google.registry.model.domain.token.AllocationToken;
import google.registry.model.pricing.PremiumPricingEngine.DomainPrices;
import google.registry.model.tld.Registry;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Optional;
import javax.annotation.Nullable;
import javax.inject.Inject;
import org.joda.money.CurrencyUnit;
import org.joda.money.Money;
@@ -102,18 +106,63 @@ public final class DomainPricingLogic {
.build());
}
/** Returns a new renew price for the pricer. */
@SuppressWarnings("unused")
FeesAndCredits getRenewPrice(Registry registry, String domainName, DateTime dateTime, int years)
/** Returns a new renewal cost for the pricer. */
FeesAndCredits getRenewPrice(
Registry registry,
String domainName,
DateTime dateTime,
int years,
@Nullable Recurring recurringBillingEvent)
throws EppException {
DomainPrices domainPrices = getPricesForDomainName(domainName, dateTime);
BigDecimal renewCost = domainPrices.getRenewCost().multipliedBy(years).getAmount();
checkArgument(years > 0, "Number of years must be positive");
Money renewCost;
boolean isRenewCostPremiumPrice;
// recurring billing event is null if the domain is still available. Billing events are created
// in the process of domain creation.
if (recurringBillingEvent == null) {
DomainPrices domainPrices = getPricesForDomainName(domainName, dateTime);
renewCost = domainPrices.getRenewCost().multipliedBy(years);
isRenewCostPremiumPrice = domainPrices.isPremium();
} else {
switch (recurringBillingEvent.getRenewalPriceBehavior()) {
case DEFAULT:
DomainPrices domainPrices = getPricesForDomainName(domainName, dateTime);
renewCost = domainPrices.getRenewCost().multipliedBy(years);
isRenewCostPremiumPrice = domainPrices.isPremium();
break;
// if the renewal price behavior is specified, then the renewal price should be the same
// as the creation price, which is stored in the billing event as the renewal price
case SPECIFIED:
checkArgumentPresent(
recurringBillingEvent.getRenewalPrice(),
"Unexpected behavior: renewal price cannot be null when renewal behavior is"
+ " SPECIFIED");
renewCost = recurringBillingEvent.getRenewalPrice().get().multipliedBy(years);
isRenewCostPremiumPrice = false;
break;
// if the renewal price behavior is nonpremium, it means that the domain should be renewed
// at standard price of domains at the time, even if the domain is premium
case NONPREMIUM:
renewCost =
Registry.get(getTldFromDomainName(domainName))
.getStandardRenewCost(dateTime)
.multipliedBy(years);
isRenewCostPremiumPrice = false;
break;
default:
throw new IllegalArgumentException(
String.format(
"Unknown RenewalPriceBehavior enum value: %s",
recurringBillingEvent.getRenewalPriceBehavior()));
}
}
return customLogic.customizeRenewPrice(
RenewPriceParameters.newBuilder()
.setFeesAndCredits(
new FeesAndCredits.Builder()
.setCurrency(registry.getCurrency())
.addFeeOrCredit(Fee.create(renewCost, FeeType.RENEW, domainPrices.isPremium()))
.setCurrency(renewCost.getCurrencyUnit())
.addFeeOrCredit(
Fee.create(renewCost.getAmount(), FeeType.RENEW, isRenewCostPremiumPrice))
.build())
.setRegistry(registry)
.setDomainName(InternetDomainName.from(domainName))
@@ -155,7 +155,8 @@ public final class DomainRenewFlow implements TransactionalFlow {
Optional<FeeRenewCommandExtension> feeRenew =
eppInput.getSingleExtension(FeeRenewCommandExtension.class);
FeesAndCredits feesAndCredits =
pricingLogic.getRenewPrice(Registry.get(existingDomain.getTld()), targetId, now, years);
pricingLogic.getRenewPrice(
Registry.get(existingDomain.getTld()), targetId, now, years, null);
validateFeeChallenge(targetId, now, feeRenew, feesAndCredits);
flowCustomLogic.afterValidation(
AfterValidationParameters.newBuilder()