Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Price Granularity Defaults Fix #3511

Merged
merged 3 commits into from
Nov 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading