Skip to content

Commit 45c5162

Browse files
arg-resolve-auction-price-macro
1 parent ea32800 commit 45c5162

File tree

2 files changed

+218
-2
lines changed

2 files changed

+218
-2
lines changed

src/main/java/org/prebid/server/bidder/thetradedesk/TheTradeDeskBidder.java

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import org.prebid.server.util.BidderUtil;
3030
import org.prebid.server.util.HttpUtil;
3131

32+
import java.math.BigDecimal;
3233
import java.util.ArrayList;
3334
import java.util.Collection;
3435
import java.util.Collections;
@@ -44,6 +45,7 @@ public class TheTradeDeskBidder implements Bidder<BidRequest> {
4445

4546
private static final String SUPPLY_ID_MACRO = "{{SupplyId}}";
4647
private static final Pattern SUPPLY_ID_PATTERN = Pattern.compile("([a-z]+)$");
48+
private static final String PRICE_MACRO = "${AUCTION_PRICE}";
4749

4850
private final String endpointUrl;
4951
private final String supplyId;
@@ -193,10 +195,11 @@ private static List<BidderBid> extractBids(BidResponse bidResponse) {
193195

194196
return bidResponse.getSeatbid().stream()
195197
.filter(Objects::nonNull)
196-
.map(SeatBid::getBid).filter(Objects::nonNull)
198+
.map(SeatBid::getBid)
199+
.filter(Objects::nonNull)
197200
.flatMap(Collection::stream)
198201
.filter(Objects::nonNull)
199-
.map(bid -> BidderBid.of(bid, getBidType(bid), bidResponse.getCur()))
202+
.map(bid -> BidderBid.of(resolvePriceMacros(bid), getBidType(bid), bidResponse.getCur()))
200203
.toList();
201204
}
202205

@@ -208,4 +211,16 @@ private static BidType getBidType(Bid bid) {
208211
case null, default -> throw new PreBidException("unsupported mtype: %s".formatted(bid.getMtype()));
209212
};
210213
}
214+
215+
216+
217+
private static Bid resolvePriceMacros(Bid bid) {
218+
final BigDecimal price = bid.getPrice();
219+
final String priceAsString = price != null ? price.toPlainString() : "0";
220+
221+
return bid.toBuilder()
222+
.nurl(StringUtils.replace(bid.getNurl(), PRICE_MACRO, priceAsString))
223+
.adm(StringUtils.replace(bid.getAdm(), PRICE_MACRO, priceAsString))
224+
.build();
225+
}
211226
}

src/test/java/org/prebid/server/bidder/thetradedesk/TheTradeDeskBidderTest.java

Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.fasterxml.jackson.core.JsonProcessingException;
44
import com.fasterxml.jackson.databind.node.ObjectNode;
5+
import java.math.BigDecimal;
56
import com.iab.openrtb.request.App;
67
import com.iab.openrtb.request.Banner;
78
import com.iab.openrtb.request.BidRequest;
@@ -509,4 +510,204 @@ private static ObjectNode impExt(String publisherId, String supplySourceId) {
509510
return mapper.valueToTree(ExtPrebid.of(null, ExtImpTheTradeDesk.of(publisherId, supplySourceId)));
510511
}
511512

513+
514+
@Test
515+
public void makeBidsShouldReplacePriceMacroInNurlAndAdmWithBidPrice() throws JsonProcessingException {
516+
// given
517+
final BidderCall<BidRequest> httpCall = givenHttpCall(
518+
givenBidResponse(bidBuilder -> bidBuilder
519+
.mtype(1)
520+
.impid("123")
521+
.price(BigDecimal.valueOf(1.23))
522+
.nurl("http://example.com/nurl?price=${AUCTION_PRICE}")
523+
.adm("<div>Price: ${AUCTION_PRICE}</div>")));
524+
525+
// when
526+
final Result<List<BidderBid>> result = target.makeBids(httpCall, null);
527+
528+
// then
529+
assertThat(result.getErrors()).isEmpty();
530+
assertThat(result.getValue()).hasSize(1);
531+
final BidderBid bidderBid = result.getValue().getFirst();
532+
assertThat(bidderBid.getBid().getNurl()).isEqualTo("http://example.com/nurl?price=1.23");
533+
assertThat(bidderBid.getBid().getAdm()).isEqualTo("<div>Price: 1.23</div>");
534+
assertThat(bidderBid.getBid().getPrice()).isEqualTo(BigDecimal.valueOf(1.23));
535+
}
536+
537+
@Test
538+
public void makeBidsShouldReplacePriceMacroWithZeroWhenBidPriceIsNull() throws JsonProcessingException {
539+
// given
540+
final BidderCall<BidRequest> httpCall = givenHttpCall(
541+
givenBidResponse(bidBuilder -> bidBuilder
542+
.mtype(1)
543+
.impid("123")
544+
.price(null)
545+
.nurl("http://example.com/nurl?price=${AUCTION_PRICE}")
546+
.adm("<div>Price: ${AUCTION_PRICE}</div>")));
547+
548+
// when
549+
final Result<List<BidderBid>> result = target.makeBids(httpCall, null);
550+
551+
// then
552+
assertThat(result.getErrors()).isEmpty();
553+
assertThat(result.getValue()).hasSize(1);
554+
final BidderBid bidderBid = result.getValue().getFirst();
555+
assertThat(bidderBid.getBid().getNurl()).isEqualTo("http://example.com/nurl?price=0");
556+
assertThat(bidderBid.getBid().getAdm()).isEqualTo("<div>Price: 0</div>");
557+
}
558+
559+
@Test
560+
public void makeBidsShouldReplacePriceMacroWithZeroWhenBidPriceIsZero() throws JsonProcessingException {
561+
// given
562+
final BidderCall<BidRequest> httpCall = givenHttpCall(
563+
givenBidResponse(bidBuilder -> bidBuilder
564+
.mtype(1)
565+
.impid("123")
566+
.price(BigDecimal.ZERO)
567+
.nurl("http://example.com/nurl?price=${AUCTION_PRICE}")
568+
.adm("<div>Price: ${AUCTION_PRICE}</div>")));
569+
570+
// when
571+
final Result<List<BidderBid>> result = target.makeBids(httpCall, null);
572+
573+
// then
574+
assertThat(result.getErrors()).isEmpty();
575+
assertThat(result.getValue()).hasSize(1);
576+
final BidderBid bidderBid = result.getValue().getFirst();
577+
assertThat(bidderBid.getBid().getNurl()).isEqualTo("http://example.com/nurl?price=0");
578+
assertThat(bidderBid.getBid().getAdm()).isEqualTo("<div>Price: 0</div>");
579+
}
580+
581+
@Test
582+
public void makeBidsShouldReplacePriceMacroInNurlOnlyWhenAdmDoesNotContainMacro() throws JsonProcessingException {
583+
// given
584+
final BidderCall<BidRequest> httpCall = givenHttpCall(
585+
givenBidResponse(bidBuilder -> bidBuilder
586+
.mtype(1)
587+
.impid("123")
588+
.price(BigDecimal.valueOf(5.67))
589+
.nurl("http://example.com/nurl?price=${AUCTION_PRICE}")
590+
.adm("<div>No macro here</div>")));
591+
592+
// when
593+
final Result<List<BidderBid>> result = target.makeBids(httpCall, null);
594+
595+
// then
596+
assertThat(result.getErrors()).isEmpty();
597+
assertThat(result.getValue()).hasSize(1);
598+
final BidderBid bidderBid = result.getValue().getFirst();
599+
assertThat(bidderBid.getBid().getNurl()).isEqualTo("http://example.com/nurl?price=5.67");
600+
assertThat(bidderBid.getBid().getAdm()).isEqualTo("<div>No macro here</div>");
601+
}
602+
603+
@Test
604+
public void makeBidsShouldReplacePriceMacroInAdmOnlyWhenNurlDoesNotContainMacro() throws JsonProcessingException {
605+
// given
606+
final BidderCall<BidRequest> httpCall = givenHttpCall(
607+
givenBidResponse(bidBuilder -> bidBuilder
608+
.mtype(1)
609+
.impid("123")
610+
.price(BigDecimal.valueOf(8.90))
611+
.nurl("http://example.com/nurl")
612+
.adm("<div>Price: ${AUCTION_PRICE}</div>")));
613+
614+
// when
615+
final Result<List<BidderBid>> result = target.makeBids(httpCall, null);
616+
617+
// then
618+
assertThat(result.getErrors()).isEmpty();
619+
assertThat(result.getValue()).hasSize(1);
620+
final BidderBid bidderBid = result.getValue().getFirst();
621+
assertThat(bidderBid.getBid().getNurl()).isEqualTo("http://example.com/nurl");
622+
assertThat(bidderBid.getBid().getAdm()).isEqualTo("<div>Price: 8.90</div>");
623+
}
624+
625+
@Test
626+
public void makeBidsShouldNotReplacePriceMacroWhenNurlAndAdmDoNotContainMacro() throws JsonProcessingException {
627+
// given
628+
final BidderCall<BidRequest> httpCall = givenHttpCall(
629+
givenBidResponse(bidBuilder -> bidBuilder
630+
.mtype(1)
631+
.impid("123")
632+
.price(BigDecimal.valueOf(12.34))
633+
.nurl("http://example.com/nurl")
634+
.adm("<div>No macro</div>")));
635+
636+
// when
637+
final Result<List<BidderBid>> result = target.makeBids(httpCall, null);
638+
639+
// then
640+
assertThat(result.getErrors()).isEmpty();
641+
assertThat(result.getValue()).hasSize(1);
642+
final BidderBid bidderBid = result.getValue().getFirst();
643+
assertThat(bidderBid.getBid().getNurl()).isEqualTo("http://example.com/nurl");
644+
assertThat(bidderBid.getBid().getAdm()).isEqualTo("<div>No macro</div>");
645+
}
646+
647+
@Test
648+
public void makeBidsShouldHandleNullNurlAndAdm() throws JsonProcessingException {
649+
// given
650+
final BidderCall<BidRequest> httpCall = givenHttpCall(
651+
givenBidResponse(bidBuilder -> bidBuilder
652+
.mtype(1)
653+
.impid("123")
654+
.price(BigDecimal.valueOf(15.00))
655+
.nurl(null)
656+
.adm(null)));
657+
658+
// when
659+
final Result<List<BidderBid>> result = target.makeBids(httpCall, null);
660+
661+
// then
662+
assertThat(result.getErrors()).isEmpty();
663+
assertThat(result.getValue()).hasSize(1);
664+
final BidderBid bidderBid = result.getValue().getFirst();
665+
assertThat(bidderBid.getBid().getNurl()).isNull();
666+
assertThat(bidderBid.getBid().getAdm()).isNull();
667+
}
668+
669+
@Test
670+
public void makeBidsShouldReplaceMultiplePriceMacrosInSameField() throws JsonProcessingException {
671+
// given
672+
final BidderCall<BidRequest> httpCall = givenHttpCall(
673+
givenBidResponse(bidBuilder -> bidBuilder
674+
.mtype(1)
675+
.impid("123")
676+
.price(BigDecimal.valueOf(9.99))
677+
.nurl("http://example.com/nurl?price=${AUCTION_PRICE}&backup_price=${AUCTION_PRICE}")
678+
.adm("<div>Price: ${AUCTION_PRICE}, Fallback: ${AUCTION_PRICE}</div>")));
679+
680+
// when
681+
final Result<List<BidderBid>> result = target.makeBids(httpCall, null);
682+
683+
// then
684+
assertThat(result.getErrors()).isEmpty();
685+
assertThat(result.getValue()).hasSize(1);
686+
final BidderBid bidderBid = result.getValue().getFirst();
687+
assertThat(bidderBid.getBid().getNurl()).isEqualTo("http://example.com/nurl?price=9.99&backup_price=9.99");
688+
assertThat(bidderBid.getBid().getAdm()).isEqualTo("<div>Price: 9.99, Fallback: 9.99</div>");
689+
}
690+
691+
@Test
692+
public void makeBidsShouldHandleLargeDecimalPrices() throws JsonProcessingException {
693+
// given
694+
final BidderCall<BidRequest> httpCall = givenHttpCall(
695+
givenBidResponse(bidBuilder -> bidBuilder
696+
.mtype(1)
697+
.impid("123")
698+
.price(new BigDecimal("123456789.123456789"))
699+
.nurl("http://example.com/nurl?price=${AUCTION_PRICE}")
700+
.adm("<div>Price: ${AUCTION_PRICE}</div>")));
701+
702+
// when
703+
final Result<List<BidderBid>> result = target.makeBids(httpCall, null);
704+
705+
// then
706+
assertThat(result.getErrors()).isEmpty();
707+
assertThat(result.getValue()).hasSize(1);
708+
final BidderBid bidderBid = result.getValue().getFirst();
709+
assertThat(bidderBid.getBid().getNurl()).isEqualTo("http://example.com/nurl?price=123456789.123456789");
710+
assertThat(bidderBid.getBid().getAdm()).isEqualTo("<div>Price: 123456789.123456789</div>");
711+
}
712+
512713
}

0 commit comments

Comments
 (0)