Skip to content

Commit

Permalink
Price Granularity: Defaults Fix (#3511)
Browse files Browse the repository at this point in the history
  • Loading branch information
AntoxaAntoxic authored Nov 4, 2024
1 parent af321ad commit 98e8065
Show file tree
Hide file tree
Showing 13 changed files with 406 additions and 22 deletions.
6 changes: 6 additions & 0 deletions src/main/java/org/prebid/server/auction/PriceGranularity.java
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,12 @@ public static PriceGranularity createFromString(String stringPriceGranularity) {
}
}

public static PriceGranularity createFromStringOrDefault(String stringPriceGranularity) {
return isValidStringPriceGranularityType(stringPriceGranularity)
? STRING_TO_CUSTOM_PRICE_GRANULARITY.get(PriceGranularityType.valueOf(stringPriceGranularity))
: PriceGranularity.DEFAULT;
}

/**
* Returns list of {@link ExtGranularityRange}s.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
import org.prebid.server.proto.openrtb.ext.request.ExtStoredRequest;
import org.prebid.server.proto.openrtb.ext.request.ExtUser;
import org.prebid.server.settings.model.Account;
import org.prebid.server.settings.model.AccountAuctionConfig;
import org.prebid.server.util.HttpUtil;

import java.util.ArrayList;
Expand All @@ -60,6 +61,7 @@
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

public class AmpRequestFactory {
Expand Down Expand Up @@ -407,7 +409,7 @@ private Future<BidRequest> updateBidRequest(AuctionContext auctionContext) {
.map(ortbVersionConversionManager::convertToAuctionSupportedVersion)
.map(bidRequest -> gppService.updateBidRequest(bidRequest, auctionContext))
.map(bidRequest -> validateStoredBidRequest(storedRequestId, bidRequest))
.map(this::fillExplicitParameters)
.map(bidRequest -> fillExplicitParameters(bidRequest, account))
.map(bidRequest -> overrideParameters(bidRequest, httpRequest, auctionContext.getPrebidErrors()))
.map(bidRequest -> paramsResolver.resolve(bidRequest, auctionContext, ENDPOINT, true))
.map(bidRequest -> ortb2RequestFactory.removeEmptyEids(bidRequest, auctionContext.getDebugWarnings()))
Expand Down Expand Up @@ -459,7 +461,7 @@ private static BidRequest validateStoredBidRequest(String tagId, BidRequest bidR
* - Sets {@link BidRequest}.test = 1 if it was passed in {@link RoutingContext}
* - Updates {@link BidRequest}.ext.prebid.amp.data with all query parameters
*/
private BidRequest fillExplicitParameters(BidRequest bidRequest) {
private BidRequest fillExplicitParameters(BidRequest bidRequest, Account account) {
final List<Imp> imps = bidRequest.getImp();
// Force HTTPS as AMP requires it, but pubs can forget to set it.
final Imp imp = imps.getFirst();
Expand Down Expand Up @@ -496,6 +498,7 @@ private BidRequest fillExplicitParameters(BidRequest bidRequest) {
.imp(setSecure ? Collections.singletonList(imps.getFirst().toBuilder().secure(1).build()) : imps)
.ext(extRequest(
bidRequest,
account,
setDefaultTargeting,
setDefaultCache))
.build();
Expand Down Expand Up @@ -692,6 +695,7 @@ private static List<Format> parseMultiSizeParam(String ms) {
* Creates updated bidrequest.ext {@link ObjectNode}.
*/
private ExtRequest extRequest(BidRequest bidRequest,
Account account,
boolean setDefaultTargeting,
boolean setDefaultCache) {

Expand All @@ -704,7 +708,7 @@ private ExtRequest extRequest(BidRequest bidRequest,
: ExtRequestPrebid.builder();

if (setDefaultTargeting) {
prebidBuilder.targeting(createTargetingWithDefaults(prebid));
prebidBuilder.targeting(createTargetingWithDefaults(prebid, account));
}
if (setDefaultCache) {
prebidBuilder.cache(ExtRequestPrebidCache.of(ExtRequestPrebidCacheBids.of(null, null),
Expand All @@ -727,15 +731,14 @@ private ExtRequest extRequest(BidRequest bidRequest,
* Creates updated with default values bidrequest.ext.targeting {@link ExtRequestTargeting} if at least one of it's
* child properties is missed or entire targeting does not exist.
*/
private ExtRequestTargeting createTargetingWithDefaults(ExtRequestPrebid prebid) {
private ExtRequestTargeting createTargetingWithDefaults(ExtRequestPrebid prebid, Account account) {
final ExtRequestTargeting targeting = prebid != null ? prebid.getTargeting() : null;
final boolean isTargetingNull = targeting == null;

final JsonNode priceGranularityNode = isTargetingNull ? null : targeting.getPricegranularity();
final boolean isPriceGranularityNull = priceGranularityNode == null || priceGranularityNode.isNull();
final JsonNode outgoingPriceGranularityNode
= isPriceGranularityNull
? mapper.mapper().valueToTree(ExtPriceGranularity.from(PriceGranularity.DEFAULT))
final JsonNode outgoingPriceGranularityNode = isPriceGranularityNull
? mapper.mapper().valueToTree(ExtPriceGranularity.from(getDefaultPriceGranularity(account)))
: priceGranularityNode;

final ExtMediaTypePriceGranularity mediaTypePriceGranularity = isTargetingNull
Expand All @@ -759,6 +762,14 @@ private ExtRequestTargeting createTargetingWithDefaults(ExtRequestPrebid prebid)
.build();
}

private static PriceGranularity getDefaultPriceGranularity(Account account) {
return Optional.ofNullable(account)
.map(Account::getAuction)
.map(AccountAuctionConfig::getPriceGranularity)
.map(PriceGranularity::createFromStringOrDefault)
.orElse(PriceGranularity.DEFAULT);
}

@Value(staticConstructor = "of")
private static class GppSidExtraction {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@
import org.prebid.server.proto.openrtb.ext.request.ExtRequestTargeting;
import org.prebid.server.proto.openrtb.ext.request.ExtSite;
import org.prebid.server.proto.openrtb.ext.response.BidType;
import org.prebid.server.settings.model.Account;
import org.prebid.server.settings.model.AccountAuctionConfig;
import org.prebid.server.util.HttpUtil;
import org.prebid.server.util.ObjectUtil;
import org.prebid.server.util.StreamUtil;
Expand Down Expand Up @@ -187,7 +189,11 @@ public BidRequest resolve(BidRequest bidRequest,
final ExtRequest ext = bidRequest.getExt();
final List<Imp> imps = bidRequest.getImp();
final ExtRequest populatedExt = populateRequestExt(
ext, bidRequest, ObjectUtils.defaultIfNull(populatedImps, imps), endpoint);
ext,
bidRequest,
ObjectUtils.defaultIfNull(populatedImps, imps),
endpoint,
auctionContext.getAccount());

final Source source = bidRequest.getSource();
final Source populatedSource = populateSource(source, populatedExt, hasStoredBidRequest);
Expand Down Expand Up @@ -713,10 +719,15 @@ private static boolean isUniqueIds(List<Imp> imps) {
return impIdsSet.size() == impIdsList.size();
}

private ExtRequest populateRequestExt(ExtRequest ext, BidRequest bidRequest, List<Imp> imps, String endpoint) {
private ExtRequest populateRequestExt(ExtRequest ext,
BidRequest bidRequest,
List<Imp> imps,
String endpoint,
Account account) {

final ExtRequestPrebid prebid = ObjectUtil.getIfNotNull(ext, ExtRequest::getPrebid);

final ExtRequestTargeting updatedTargeting = targetingOrNull(prebid, imps);
final ExtRequestTargeting updatedTargeting = targetingOrNull(prebid, imps, account);
final ExtRequestPrebidCache updatedCache = cacheOrNull(prebid);
final ExtRequestPrebidChannel updatedChannel = channelOrNull(prebid, bidRequest, endpoint);

Expand Down Expand Up @@ -783,7 +794,7 @@ private static void resolveImpMediaTypes(Imp imp, Set<BidType> impsMediaTypes) {
/**
* Returns populated {@link ExtRequestTargeting} or null if no changes were applied.
*/
private ExtRequestTargeting targetingOrNull(ExtRequestPrebid prebid, List<Imp> imps) {
private ExtRequestTargeting targetingOrNull(ExtRequestPrebid prebid, List<Imp> imps, Account account) {
final ExtRequestTargeting targeting = prebid != null ? prebid.getTargeting() : null;

final boolean isTargetingNotNull = targeting != null;
Expand All @@ -796,8 +807,12 @@ private ExtRequestTargeting targetingOrNull(ExtRequestPrebid prebid, List<Imp> i

if (isPriceGranularityNull || isPriceGranularityTextual || isIncludeWinnersNull || isIncludeBidderKeysNull) {
return targeting.toBuilder()
.pricegranularity(resolvePriceGranularity(targeting, isPriceGranularityNull,
isPriceGranularityTextual, imps))
.pricegranularity(resolvePriceGranularity(
targeting,
isPriceGranularityNull,
isPriceGranularityTextual,
imps,
account))
.includewinners(isIncludeWinnersNull || targeting.getIncludewinners())
.includebidderkeys(isIncludeBidderKeysNull
? !isWinningOnly(prebid.getCache())
Expand All @@ -822,14 +837,22 @@ private boolean isWinningOnly(ExtRequestPrebidCache cache) {
* In case of valid string price granularity replaced it with appropriate custom view.
* In case of invalid string value throws {@link InvalidRequestException}.
*/
private JsonNode resolvePriceGranularity(ExtRequestTargeting targeting, boolean isPriceGranularityNull,
boolean isPriceGranularityTextual, List<Imp> imps) {
private JsonNode resolvePriceGranularity(ExtRequestTargeting targeting,
boolean isPriceGranularityNull,
boolean isPriceGranularityTextual,
List<Imp> imps,
Account account) {

final boolean hasAllMediaTypes = checkExistingMediaTypes(targeting.getMediatypepricegranularity())
.containsAll(getImpMediaTypes(imps));

if (isPriceGranularityNull && !hasAllMediaTypes) {
return mapper.mapper().valueToTree(ExtPriceGranularity.from(PriceGranularity.DEFAULT));
final PriceGranularity defaultPriceGranularity = Optional.ofNullable(account)
.map(Account::getAuction)
.map(AccountAuctionConfig::getPriceGranularity)
.map(PriceGranularity::createFromStringOrDefault)
.orElse(PriceGranularity.DEFAULT);
return mapper.mapper().valueToTree(ExtPriceGranularity.from(defaultPriceGranularity));
}

final JsonNode priceGranularityNode = targeting.getPricegranularity();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import org.prebid.server.functional.model.response.auction.MediaType
@JsonNaming(PropertyNamingStrategies.KebabCaseStrategy)
class AccountAuctionConfig {

String priceGranularity
PriceGranularityType priceGranularity
Integer bannerCacheTtl
Integer videoCacheTtl
Integer truncateTargetAttr
Expand All @@ -28,7 +28,7 @@ class AccountAuctionConfig {
PrivacySandbox privacySandbox

@JsonProperty("price_granularity")
String priceGranularitySnakeCase
PriceGranularityType priceGranularitySnakeCase
@JsonProperty("banner_cache_ttl")
Integer bannerCacheTtlSnakeCase
@JsonProperty("video_cache_ttl")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package org.prebid.server.functional.model.config

import com.fasterxml.jackson.annotation.JsonValue
import org.prebid.server.functional.model.request.auction.Range

enum PriceGranularityType {

LOW(2, [Range.getDefault(5, 0.5)]),
MEDIUM(2, [Range.getDefault(20, 0.1)]),
MED(2, [Range.getDefault(20, 0.1)]),
HIGH(2, [Range.getDefault(20, 0.01)]),
AUTO(2, [Range.getDefault(5, 0.05), Range.getDefault(10, 0.1), Range.getDefault(20, 0.5)]),
DENSE(2, [Range.getDefault(3, 0.01), Range.getDefault(8, 0.05), Range.getDefault(20, 0.5)]),
UNKNOWN(null, [])

final Integer precision
final List<Range> ranges

PriceGranularityType(Integer precision, List<Range> ranges) {
this.precision = precision
this.ranges = ranges
}

@JsonValue
String toLowerCase() {
return name().toLowerCase()
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,21 @@
package org.prebid.server.functional.model.request.auction

import groovy.transform.EqualsAndHashCode
import groovy.transform.ToString
import org.prebid.server.functional.model.config.PriceGranularityType

@ToString(includeNames = true, ignoreNulls = true)
@EqualsAndHashCode
class PriceGranularity {

Integer precision
List<Range> ranges

static PriceGranularity getDefault(PriceGranularityType granularity) {
new PriceGranularity(precision: granularity.precision, ranges: granularity.ranges)
}

static PriceGranularity getDefault() {
getDefault(PriceGranularityType.MED)
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
package org.prebid.server.functional.model.request.auction

import groovy.transform.EqualsAndHashCode
import groovy.transform.ToString

@ToString(includeNames = true, ignoreNulls = true)
@EqualsAndHashCode
class Range {

BigDecimal max
BigDecimal increment

static Range getDefault(Integer max, BigDecimal increment) {
new Range(max: max, increment: increment)
}
}
Loading

0 comments on commit 98e8065

Please sign in to comment.