Skip to content

Commit 060fa97

Browse files
committed
Merge remote-tracking branch 'origin/master' into bid-ranking
# Conflicts: # src/main/java/org/prebid/server/settings/model/AccountAuctionConfig.java
2 parents ae32b81 + 7e2cacf commit 060fa97

File tree

73 files changed

+2717
-119
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

73 files changed

+2717
-119
lines changed

docs/application-settings.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@ There are two ways to configure application settings: database and file. This do
2525
- `auction.bidadjustments.mediatype.*.*.*[].value` - value of the bid adjustment
2626
- `auction.bidadjustments.mediatype.*.*.*[].currency` - currency of the bid adjustment
2727
- `auction.events.enabled` - enables events for account if true
28+
- `auction.bid-rounding` - bid rounding options are:
29+
- **down** - rounding down to the lower price bucket
30+
- **up** - rounding up to the higher price bucket
31+
- **timesplit** - 50% of the time rounding down to the lower PB and 50% of the time rounding up to the higher price bucket
32+
- **true** - if the price >= 50% of the range, rounding up to the higher price bucket, otherwise rounding down
2833
- `auction.price-floors.enabled` - enables price floors for account if true. Defaults to true.
2934
- `auction.price-floors.fetch.enabled`- enables data fetch for price floors for account if true. Defaults to false.
3035
- `auction.price-floors.fetch.url` - url to fetch price floors data from.
@@ -50,6 +55,7 @@ Keep in mind following restrictions:
5055
- `auction.preferredmediatype.<bidder>.<media-type>` - <media-type> that will be left for <bidder> that doesn't support multi-format. Other media types will be removed. Acceptable values: `banner`, `video`, `audio`, `native`.
5156
- `auction.privacysandbox.cookiedeprecation.enabled` - boolean that turns on setting and reading of the Chrome Privacy Sandbox testing label header. Defaults to false.
5257
- `auction.privacysandbox.cookiedeprecation.ttlsec` - if the above setting is true, how long to set the receive-cookie-deprecation cookie's expiration
58+
- `auction.cache.enabled` - enables bids caching for account if true. Defaults to true.
5359
- `privacy.gdpr.enabled` - enables gdpr verifications if true. Has higher priority than configuration in
5460
application.yaml.
5561
- `privacy.gdpr.eea-countries` - overrides the host-level list of 2-letter country codes where TCF processing is applied

extra/modules/fiftyone-devicedetection/src/main/java/org/prebid/server/hooks/modules/fiftyone/devicedetection/v1/core/OrtbDeviceType.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ public enum OrtbDeviceType {
2727
Map.entry("Mobile", OrtbDeviceType.MOBILE_TABLET),
2828
Map.entry("Router", OrtbDeviceType.CONNECTED_DEVICE),
2929
Map.entry("SmallScreen", OrtbDeviceType.CONNECTED_DEVICE),
30-
Map.entry("SmartPhone", OrtbDeviceType.MOBILE_TABLET),
30+
Map.entry("SmartPhone", OrtbDeviceType.PHONE),
3131
Map.entry("SmartSpeaker", OrtbDeviceType.CONNECTED_DEVICE),
3232
Map.entry("SmartWatch", OrtbDeviceType.CONNECTED_DEVICE),
3333
Map.entry("Tablet", OrtbDeviceType.TABLET),

extra/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
<checkstyle.version>10.17.0</checkstyle.version>
3434

3535
<!-- Project production dependency versions -->
36-
<spring.boot.version>3.4.4</spring.boot.version>
36+
<spring.boot.version>3.4.5</spring.boot.version>
3737
<vertx.version>4.5.14</vertx.version>
3838
<validation-api.version>2.0.1.Final</validation-api.version>
3939
<commons.collections.version>4.4</commons.collections.version>

src/main/java/org/prebid/server/auction/BidResponseCreator.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -596,6 +596,7 @@ private Future<CategoryMappingResult> createCategoryMapping(AuctionContext aucti
596596
return categoryMappingService.createCategoryMapping(
597597
bidderResponses,
598598
auctionContext.getBidRequest(),
599+
auctionContext.getAccount(),
599600
auctionContext.getTimeoutContext().getTimeout())
600601

601602
.map(categoryMappingResult -> addCategoryMappingErrors(categoryMappingResult, auctionContext));
@@ -1571,7 +1572,7 @@ private Bid toBid(BidInfo bidInfo,
15711572
final String categoryDuration = bidInfo.getCategory();
15721573
targetingKeywords = keywordsCreator != null
15731574
? keywordsCreator.makeFor(
1574-
bid, seat, isWinningBid, cacheId, bidType.getName(), videoCacheId, categoryDuration)
1575+
bid, seat, isWinningBid, cacheId, bidType.getName(), videoCacheId, categoryDuration, account)
15751576
: null;
15761577
} else {
15771578
targetingKeywords = null;

src/main/java/org/prebid/server/auction/CpmRange.java

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,16 @@
33
import org.apache.commons.lang3.ObjectUtils;
44
import org.apache.commons.lang3.StringUtils;
55
import org.prebid.server.proto.openrtb.ext.request.ExtGranularityRange;
6+
import org.prebid.server.settings.model.Account;
7+
import org.prebid.server.settings.model.AccountAuctionConfig;
8+
import org.prebid.server.settings.model.AccountAuctionBidRoundingMode;
69

710
import java.math.BigDecimal;
811
import java.math.RoundingMode;
912
import java.text.NumberFormat;
1013
import java.util.Locale;
14+
import java.util.Optional;
15+
import java.util.concurrent.ThreadLocalRandom;
1116

1217
/**
1318
* Class for price operating with rules defined in {@link PriceGranularity}
@@ -23,8 +28,8 @@ private CpmRange() {
2328
/**
2429
* Rounding price by specified rules defined in {@link PriceGranularity} object and returns it in string format
2530
*/
26-
public static String fromCpm(BigDecimal cpm, PriceGranularity priceGranularity) {
27-
final BigDecimal value = fromCpmAsNumber(cpm, priceGranularity);
31+
public static String fromCpm(BigDecimal cpm, PriceGranularity priceGranularity, Account account) {
32+
final BigDecimal value = fromCpmAsNumber(cpm, priceGranularity, account);
2833
return value != null ? format(value, priceGranularity.getPrecision()) : StringUtils.EMPTY;
2934
}
3035

@@ -47,7 +52,7 @@ private static NumberFormat numberFormat(int precision) {
4752
* Rounding price by specified rules defined in {@link PriceGranularity} object and returns it in {@link BigDecimal}
4853
* format
4954
*/
50-
public static BigDecimal fromCpmAsNumber(BigDecimal cpm, PriceGranularity priceGranularity) {
55+
public static BigDecimal fromCpmAsNumber(BigDecimal cpm, PriceGranularity priceGranularity, Account account) {
5156
if (cpm.compareTo(BigDecimal.ZERO) <= 0) {
5257
return null;
5358
}
@@ -69,14 +74,32 @@ public static BigDecimal fromCpmAsNumber(BigDecimal cpm, PriceGranularity priceG
6974
min = max;
7075
}
7176

72-
return increment != null ? calculate(cpm, min, increment) : null;
77+
return increment != null ? calculate(cpm, min, increment, resolveRoundingMode(account)) : null;
7378
}
7479

75-
private static BigDecimal calculate(BigDecimal cpm, BigDecimal min, BigDecimal increment) {
80+
private static BigDecimal calculate(BigDecimal cpm,
81+
BigDecimal min,
82+
BigDecimal increment,
83+
RoundingMode roundingMode) {
84+
7685
return cpm
7786
.subtract(min)
78-
.divide(increment, 0, RoundingMode.FLOOR)
87+
.divide(increment, 0, roundingMode)
7988
.multiply(increment)
8089
.add(min);
8190
}
91+
92+
private static RoundingMode resolveRoundingMode(Account account) {
93+
final AccountAuctionBidRoundingMode accountRoundingMode = Optional.ofNullable(account)
94+
.map(Account::getAuction)
95+
.map(AccountAuctionConfig::getBidRounding)
96+
.orElse(AccountAuctionBidRoundingMode.DOWN);
97+
98+
return switch (accountRoundingMode) {
99+
case DOWN -> RoundingMode.FLOOR;
100+
case UP -> RoundingMode.CEILING;
101+
case TRUE -> RoundingMode.HALF_UP;
102+
case TIMESPLIT -> ThreadLocalRandom.current().nextBoolean() ? RoundingMode.FLOOR : RoundingMode.CEILING;
103+
};
104+
}
82105
}

src/main/java/org/prebid/server/auction/ExchangeService.java

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,8 @@
9494
import org.prebid.server.proto.openrtb.ext.request.ExtUser;
9595
import org.prebid.server.proto.openrtb.ext.response.ExtBidPrebidMeta;
9696
import org.prebid.server.settings.model.Account;
97+
import org.prebid.server.settings.model.AccountAuctionConfig;
98+
import org.prebid.server.settings.model.AccountCacheConfig;
9799
import org.prebid.server.util.HttpUtil;
98100
import org.prebid.server.util.ListUtil;
99101
import org.prebid.server.util.PbsUtil;
@@ -241,7 +243,7 @@ private Future<AuctionContext> runAuction(AuctionContext receivedContext) {
241243

242244
final List<SeatBid> storedAuctionResponses = new ArrayList<>();
243245
final BidderAliases aliases = aliases(bidRequest, account);
244-
final BidRequestCacheInfo cacheInfo = bidRequestCacheInfo(bidRequest);
246+
final BidRequestCacheInfo cacheInfo = bidRequestCacheInfo(bidRequest, account);
245247
final Map<String, MultiBidConfig> bidderToMultiBid = bidderToMultiBids(bidRequest, debugWarnings);
246248
receivedContext.getBidRejectionTrackers().putAll(makeBidRejectionTrackers(bidRequest, aliases));
247249

@@ -311,12 +313,18 @@ private static ExtRequestTargeting targeting(BidRequest bidRequest) {
311313
return prebid != null ? prebid.getTargeting() : null;
312314
}
313315

314-
private static BidRequestCacheInfo bidRequestCacheInfo(BidRequest bidRequest) {
316+
private static BidRequestCacheInfo bidRequestCacheInfo(BidRequest bidRequest, Account account) {
317+
final boolean cachingEnabled = Optional.ofNullable(account)
318+
.map(Account::getAuction)
319+
.map(AccountAuctionConfig::getCache)
320+
.map(AccountCacheConfig::getEnabled)
321+
.orElse(true);
322+
315323
final ExtRequestTargeting targeting = targeting(bidRequest);
316324
final ExtRequestPrebid prebid = PbsUtil.extRequestPrebid(bidRequest);
317325
final ExtRequestPrebidCache cache = prebid != null ? prebid.getCache() : null;
318326

319-
if (targeting != null && cache != null) {
327+
if (cachingEnabled && targeting != null && cache != null) {
320328
final boolean shouldCacheBids = cache.getBids() != null;
321329
final boolean shouldCacheVideoBids = cache.getVastxml() != null;
322330
final boolean shouldCacheWinningBidsOnly = !targeting.getIncludebidderkeys()
@@ -345,6 +353,7 @@ private static BidRequestCacheInfo bidRequestCacheInfo(BidRequest bidRequest) {
345353
.build();
346354
}
347355
}
356+
348357
return BidRequestCacheInfo.noCache();
349358
}
350359

src/main/java/org/prebid/server/auction/TargetingKeywordsCreator.java

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import com.iab.openrtb.response.Bid;
44
import org.apache.commons.lang3.StringUtils;
55
import org.prebid.server.proto.openrtb.ext.request.ExtPriceGranularity;
6+
import org.prebid.server.settings.model.Account;
67

78
import java.math.BigDecimal;
89
import java.util.ArrayList;
@@ -152,7 +153,8 @@ Map<String, String> makeFor(Bid bid,
152153
String cacheId,
153154
String format,
154155
String vastCacheId,
155-
String categoryDuration) {
156+
String categoryDuration,
157+
Account account) {
156158

157159
final Map<String, String> keywords = makeFor(
158160
bidder,
@@ -164,7 +166,8 @@ Map<String, String> makeFor(Bid bid,
164166
vastCacheId,
165167
categoryDuration,
166168
format,
167-
bid.getDealid());
169+
bid.getDealid(),
170+
account);
168171

169172
if (resolver == null) {
170173
return truncateKeys(keywords);
@@ -188,7 +191,8 @@ private Map<String, String> makeFor(String bidder,
188191
String vastCacheId,
189192
String categoryDuration,
190193
String format,
191-
String dealId) {
194+
String dealId,
195+
Account account) {
192196

193197
final boolean includeDealBid = alwaysIncludeDeals && StringUtils.isNotEmpty(dealId);
194198
final KeywordMap keywordMap = new KeywordMap(
@@ -198,7 +202,10 @@ private Map<String, String> makeFor(String bidder,
198202
includeBidderKeys || includeDealBid,
199203
Collections.emptySet());
200204

201-
final String roundedCpm = isPriceGranularityValid() ? CpmRange.fromCpm(price, priceGranularity) : DEFAULT_CPM;
205+
final String roundedCpm = isPriceGranularityValid()
206+
? CpmRange.fromCpm(price, priceGranularity, account)
207+
: DEFAULT_CPM;
208+
202209
keywordMap.put(this.keyPrefix + PB_KEY, roundedCpm);
203210

204211
keywordMap.put(this.keyPrefix + BIDDER_KEY, bidder);

src/main/java/org/prebid/server/auction/categorymapping/BasicCategoryMappingService.java

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
import org.prebid.server.proto.openrtb.ext.response.ExtBidPrebid;
4343
import org.prebid.server.proto.openrtb.ext.response.ExtBidPrebidVideo;
4444
import org.prebid.server.settings.ApplicationSettings;
45+
import org.prebid.server.settings.model.Account;
4546
import org.prebid.server.util.ObjectUtil;
4647

4748
import java.math.BigDecimal;
@@ -83,6 +84,7 @@ public BasicCategoryMappingService(ApplicationSettings applicationSettings, Jack
8384
@Override
8485
public Future<CategoryMappingResult> createCategoryMapping(List<BidderResponse> bidderResponses,
8586
BidRequest bidRequest,
87+
Account account,
8688
Timeout timeout) {
8789

8890
final ExtRequestTargeting targeting = targeting(bidRequest);
@@ -110,9 +112,21 @@ public Future<CategoryMappingResult> createCategoryMapping(List<BidderResponse>
110112
final List<RejectedBid> rejectedBids = new ArrayList<>();
111113

112114
return makeBidderToBidCategory(
113-
bidderResponses, withCategory, translateCategories, primaryAdServer, publisher, rejectedBids, timeout)
115+
bidderResponses,
116+
withCategory,
117+
translateCategories,
118+
primaryAdServer,
119+
publisher,
120+
rejectedBids,
121+
timeout)
114122
.map(categoryBidContexts -> resolveBidsCategoriesDurations(
115-
bidderResponses, categoryBidContexts, bidRequest, targeting, withCategory, rejectedBids));
123+
bidderResponses,
124+
categoryBidContexts,
125+
account,
126+
bidRequest,
127+
targeting,
128+
withCategory,
129+
rejectedBids));
116130
}
117131

118132
private static ExtRequestTargeting targeting(BidRequest bidRequest) {
@@ -326,6 +340,7 @@ private static void collectCategoryFetchResults(CompositeFuture compositeFuture,
326340
*/
327341
private CategoryMappingResult resolveBidsCategoriesDurations(List<BidderResponse> bidderResponses,
328342
List<CategoryBidContext> categoryBidContexts,
343+
Account account,
329344
BidRequest bidRequest,
330345
ExtRequestTargeting targeting,
331346
boolean withCategory,
@@ -342,8 +357,15 @@ private CategoryMappingResult resolveBidsCategoriesDurations(List<BidderResponse
342357

343358
final boolean appendBidderNames = BooleanUtils.toBooleanDefaultIfNull(targeting.getAppendbiddernames(), false);
344359
final Map<String, Set<CategoryBidContext>> uniqueCatKeysToCategoryBids = categoryBidContexts.stream()
345-
.map(categoryBidContext -> enrichCategoryBidContext(categoryBidContext, durations, priceGranularity,
346-
withCategory, appendBidderNames, impIdToBiddersDealTear, rejectedBids))
360+
.map(categoryBidContext -> enrichCategoryBidContext(
361+
categoryBidContext,
362+
account,
363+
durations,
364+
priceGranularity,
365+
withCategory,
366+
appendBidderNames,
367+
impIdToBiddersDealTear,
368+
rejectedBids))
347369
.filter(Objects::nonNull)
348370
.collect(Collectors.groupingBy(CategoryBidContext::getCategoryUniqueKey,
349371
Collectors.mapping(Function.identity(), Collectors.toSet())));
@@ -504,6 +526,7 @@ private static boolean isNotRejected(String bidId, String bidder, List<RejectedB
504526
* and creates {@link CategoryBidContext} which is holder for bid category related information.
505527
*/
506528
private CategoryBidContext enrichCategoryBidContext(CategoryBidContext categoryBidContext,
529+
Account account,
507530
List<Integer> durations,
508531
PriceGranularity priceGranularity,
509532
boolean withCategory,
@@ -522,7 +545,7 @@ private CategoryBidContext enrichCategoryBidContext(CategoryBidContext categoryB
522545
return null;
523546
}
524547

525-
final BigDecimal price = CpmRange.fromCpmAsNumber(bid.getPrice(), priceGranularity);
548+
final BigDecimal price = CpmRange.fromCpmAsNumber(bid.getPrice(), priceGranularity, account);
526549
final String rowPrice = CpmRange.format(price, priceGranularity.getPrecision());
527550
final String category = categoryBidContext.getCategory();
528551
final String categoryUniqueKey = createCategoryUniqueKey(withCategory, category, rowPrice, duration);

src/main/java/org/prebid/server/auction/categorymapping/CategoryMappingService.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,14 @@
55
import org.prebid.server.auction.model.BidderResponse;
66
import org.prebid.server.auction.model.CategoryMappingResult;
77
import org.prebid.server.execution.timeout.Timeout;
8+
import org.prebid.server.settings.model.Account;
89

910
import java.util.List;
1011

1112
public interface CategoryMappingService {
1213

1314
Future<CategoryMappingResult> createCategoryMapping(List<BidderResponse> bidderResponses,
1415
BidRequest bidRequest,
16+
Account account,
1517
Timeout timeout);
1618
}

src/main/java/org/prebid/server/auction/categorymapping/NoOpCategoryMappingService.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import org.prebid.server.auction.model.BidderResponse;
66
import org.prebid.server.auction.model.CategoryMappingResult;
77
import org.prebid.server.execution.timeout.Timeout;
8+
import org.prebid.server.settings.model.Account;
89

910
import java.util.List;
1011

@@ -13,6 +14,7 @@ public class NoOpCategoryMappingService implements CategoryMappingService {
1314
@Override
1415
public Future<CategoryMappingResult> createCategoryMapping(List<BidderResponse> bidderResponses,
1516
BidRequest bidRequest,
17+
Account account,
1618
Timeout timeout) {
1719

1820
return Future.succeededFuture(CategoryMappingResult.of(bidderResponses));

0 commit comments

Comments
 (0)