Skip to content

Commit 6b7fe6a

Browse files
philipwatsonMichele Nasti
authored and
Michele Nasti
committed
StroeerCore Bid Adapter: add price floor support (prebid#9962)
1 parent f631e53 commit 6b7fe6a

File tree

2 files changed

+206
-12
lines changed

2 files changed

+206
-12
lines changed

modules/stroeerCoreBidAdapter.js

Lines changed: 55 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import {buildUrl, deepAccess, getWindowSelf, getWindowTop, isEmpty, isStr, logWarn} from '../src/utils.js';
22
import {registerBidder} from '../src/adapters/bidderFactory.js';
33
import {BANNER, VIDEO} from '../src/mediaTypes.js';
4+
import {find} from '../src/polyfill.js';
45

56
const GVL_ID = 136;
67
const BIDDER_CODE = 'stroeerCore';
@@ -211,12 +212,16 @@ const mapToPayloadBaseBid = (bidRequest) => ({
211212
viz: elementInView(bidRequest.adUnitCode),
212213
});
213214

214-
const mapToPayloadBannerBid = (bidRequest) => ({
215-
ban: {
216-
siz: deepAccess(bidRequest, 'mediaTypes.banner.sizes') || [],
217-
},
218-
...mapToPayloadBaseBid(bidRequest)
219-
});
215+
const mapToPayloadBannerBid = (bidRequest) => {
216+
const sizes = deepAccess(bidRequest, 'mediaTypes.banner.sizes') || [];
217+
return ({
218+
ban: {
219+
siz: sizes,
220+
fp: createFloorPriceObject(BANNER, sizes, bidRequest)
221+
},
222+
...mapToPayloadBaseBid(bidRequest)
223+
});
224+
};
220225

221226
const mapToPayloadVideoBid = (bidRequest) => {
222227
const video = deepAccess(bidRequest, 'mediaTypes.video') || {};
@@ -225,9 +230,53 @@ const mapToPayloadVideoBid = (bidRequest) => {
225230
ctx: video.context,
226231
siz: video.playerSize,
227232
mim: video.mimes,
233+
fp: createFloorPriceObject(VIDEO, [video.playerSize], bidRequest),
228234
},
229235
...mapToPayloadBaseBid(bidRequest)
230236
};
231237
};
232238

239+
const createFloorPriceObject = (mediaType, sizes, bidRequest) => {
240+
if (!bidRequest.getFloor) {
241+
return undefined;
242+
}
243+
244+
const defaultFloor = bidRequest.getFloor({
245+
currency: 'EUR',
246+
mediaType: mediaType,
247+
size: '*'
248+
});
249+
250+
const sizeFloors = sizes.map(size => {
251+
const floor = bidRequest.getFloor({
252+
currency: 'EUR',
253+
mediaType: mediaType,
254+
size: [size[0], size[1]]
255+
});
256+
return {...floor, size};
257+
});
258+
259+
const floorWithCurrency = find([defaultFloor].concat(sizeFloors), floor => floor.currency);
260+
261+
if (!floorWithCurrency) {
262+
return undefined;
263+
}
264+
265+
const currency = floorWithCurrency.currency;
266+
const defaultFloorPrice = defaultFloor.currency === currency ? defaultFloor.floor : undefined;
267+
268+
return {
269+
def: defaultFloorPrice,
270+
cur: currency,
271+
siz: sizeFloors
272+
.filter(sizeFloor => sizeFloor.currency === currency)
273+
.filter(sizeFloor => sizeFloor.floor !== defaultFloorPrice)
274+
.map(sizeFloor => ({
275+
w: sizeFloor.size[0],
276+
h: sizeFloor.size[1],
277+
p: sizeFloor.floor
278+
}))
279+
};
280+
}
281+
233282
registerBidder(spec);

test/spec/modules/stroeerCoreBidAdapter_spec.js

Lines changed: 151 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -527,14 +527,16 @@ describe('stroeerCore bid adapter', function () {
527527
'bid': 'bid8',
528528
'viz': true,
529529
'ban': {
530-
'siz': [[300, 600], [160, 60]]
531-
}
530+
'siz': [[300, 600], [160, 60]],
531+
'fp': undefined
532+
},
532533
},
533534
{
534535
'sid': 'ABC=',
535536
'bid': 'bid12',
536537
'ban': {
537-
'siz': [[100, 200], [300, 500]]
538+
'siz': [[100, 200], [300, 500]],
539+
'fp': undefined
538540
},
539541
'viz': undefined
540542
}
@@ -548,7 +550,8 @@ describe('stroeerCore bid adapter', function () {
548550
'vid': {
549551
'ctx': 'instream',
550552
'siz': [640, 480],
551-
'mim': ['video/mp4', 'video/quicktime']
553+
'mim': ['video/mp4', 'video/quicktime'],
554+
'fp': undefined
552555
}
553556
}
554557
];
@@ -589,7 +592,8 @@ describe('stroeerCore bid adapter', function () {
589592
'bid': 'bid3',
590593
'viz': true,
591594
'ban': {
592-
'siz': [[100, 200], [300, 500]]
595+
'siz': [[100, 200], [300, 500]],
596+
'fp': undefined
593597
}
594598
}
595599
];
@@ -602,7 +606,8 @@ describe('stroeerCore bid adapter', function () {
602606
'vid': {
603607
'ctx': 'instream',
604608
'siz': [640, 480],
605-
'mim': ['video/mp4', 'video/quicktime']
609+
'mim': ['video/mp4', 'video/quicktime'],
610+
'fp': undefined
606611
}
607612
}
608613
];
@@ -696,6 +701,146 @@ describe('stroeerCore bid adapter', function () {
696701
const serverRequestInfo = spec.buildRequests(bidReq.bids, bidReq);
697702
assert.deepEqual(serverRequestInfo.data.schain, schain);
698703
});
704+
705+
it('should add floor info to banner bid request if floor is available', () => {
706+
const bidReq = buildBidderRequest();
707+
708+
const getFloorStub1 = sinon.stub();
709+
const getFloorStub2 = sinon.stub();
710+
711+
getFloorStub1
712+
.returns({})
713+
.withArgs({currency: 'EUR', mediaType: BANNER, size: '*'})
714+
.returns({currency: 'TRY', floor: 0.7})
715+
.withArgs({currency: 'EUR', mediaType: 'banner', size: [300, 600]})
716+
.returns({currency: 'TRY', floor: 1.3})
717+
.withArgs({currency: 'EUR', mediaType: 'banner', size: [160, 60]})
718+
.returns({currency: 'TRY', floor: 2.5})
719+
720+
getFloorStub2
721+
.returns({})
722+
.withArgs({currency: 'EUR', mediaType: 'banner', size: '*'})
723+
.returns({currency: 'USD', floor: 1.2})
724+
.withArgs({currency: 'EUR', mediaType: 'banner', size: [728, 90]})
725+
.returns({currency: 'USD', floor: 1.85})
726+
727+
bidReq.bids[0].getFloor = getFloorStub1;
728+
bidReq.bids[1].getFloor = getFloorStub2;
729+
730+
const serverRequestInfo = spec.buildRequests(bidReq.bids, bidReq);
731+
732+
const serverRequestBids = serverRequestInfo.data.bids;
733+
const firstBid = serverRequestBids[0];
734+
const secondBid = serverRequestBids[1];
735+
736+
assert.nestedPropertyVal(firstBid, 'ban.fp.def', 0.7);
737+
assert.nestedPropertyVal(firstBid, 'ban.fp.cur', 'TRY');
738+
assert.deepNestedPropertyVal(firstBid, 'ban.fp.siz', [{w: 300, h: 600, p: 1.3}, {w: 160, h: 60, p: 2.5}]);
739+
740+
assert.isTrue(getFloorStub1.calledThrice);
741+
742+
assert.nestedPropertyVal(secondBid, 'ban.fp.def', 1.2);
743+
assert.nestedPropertyVal(secondBid, 'ban.fp.cur', 'USD');
744+
assert.deepNestedPropertyVal(secondBid, 'ban.fp.siz', [{w: 728, h: 90, p: 1.85}]);
745+
746+
assert.isTrue(getFloorStub2.calledTwice);
747+
});
748+
749+
it('should add floor info to video bid request if floor is available', () => {
750+
const bidReq = buildBidderRequest();
751+
752+
const getFloorStub1 = sinon.stub();
753+
const getFloorStub2 = sinon.stub();
754+
755+
getFloorStub1
756+
.returns({})
757+
.withArgs({currency: 'EUR', mediaType: 'video', size: '*'})
758+
.returns({currency: 'NZD', floor: 3.25})
759+
.withArgs({currency: 'EUR', mediaType: 'video', size: [640, 480]})
760+
.returns({currency: 'NZD', floor: 4.10});
761+
762+
getFloorStub2
763+
.returns({})
764+
.withArgs({currency: 'EUR', mediaType: 'video', size: '*'})
765+
.returns({currency: 'GBP', floor: 4.75})
766+
.withArgs({currency: 'EUR', mediaType: 'video', size: [1280, 720]})
767+
.returns({currency: 'GBP', floor: 6.50})
768+
769+
delete bidReq.bids[0].mediaTypes.banner;
770+
bidReq.bids[0].mediaTypes.video = {
771+
playerSize: [640, 480],
772+
context: 'instream'
773+
};
774+
775+
delete bidReq.bids[1].mediaTypes.banner;
776+
bidReq.bids[1].mediaTypes.video = {
777+
playerSize: [1280, 720],
778+
context: 'outstream'
779+
};
780+
781+
bidReq.bids[0].getFloor = getFloorStub1;
782+
bidReq.bids[1].getFloor = getFloorStub2;
783+
784+
const serverRequestInfo = spec.buildRequests(bidReq.bids, bidReq);
785+
786+
const serverRequestBids = serverRequestInfo.data.bids;
787+
const firstBid = serverRequestBids[0];
788+
const secondBid = serverRequestBids[1];
789+
790+
assert.nestedPropertyVal(firstBid, 'vid.fp.def', 3.25);
791+
assert.nestedPropertyVal(firstBid, 'vid.fp.cur', 'NZD');
792+
assert.deepNestedPropertyVal(firstBid, 'vid.fp.siz', [{w: 640, h: 480, p: 4.10}]);
793+
794+
assert.isTrue(getFloorStub1.calledTwice);
795+
796+
assert.nestedPropertyVal(secondBid, 'vid.fp.def', 4.75);
797+
assert.nestedPropertyVal(secondBid, 'vid.fp.cur', 'GBP');
798+
assert.deepNestedPropertyVal(secondBid, 'vid.fp.siz', [{w: 1280, h: 720, p: 6.50}]);
799+
800+
assert.isTrue(getFloorStub2.calledTwice);
801+
});
802+
803+
it('should not add floor info to bid request if floor is unavailable', () => {
804+
const bidReq = buildBidderRequest();
805+
const getFloorSpy = sinon.spy(() => ({}));
806+
807+
delete bidReq.bids[0].getFloor;
808+
bidReq.bids[1].getFloor = getFloorSpy;
809+
810+
const serverRequestInfo = spec.buildRequests(bidReq.bids, bidReq);
811+
812+
const serverRequestBids = serverRequestInfo.data.bids;
813+
const firstBid = serverRequestBids[0];
814+
const secondBid = serverRequestBids[1];
815+
816+
assert.nestedPropertyVal(firstBid, 'ban.fp', undefined);
817+
assert.nestedPropertyVal(secondBid, 'ban.fp', undefined);
818+
819+
assert.isTrue(getFloorSpy.calledWith({currency: 'EUR', mediaType: 'banner', size: '*'}));
820+
assert.isTrue(getFloorSpy.calledWith({currency: 'EUR', mediaType: 'banner', size: [728, 90]}));
821+
assert.isTrue(getFloorSpy.calledTwice);
822+
});
823+
824+
it('should not add floor info for a size when it is the same as the default', () => {
825+
const bidReq = buildBidderRequest();
826+
const getFloorStub = sinon.stub();
827+
828+
getFloorStub
829+
.returns({currency: 'EUR', floor: 1.9})
830+
.withArgs({currency: 'EUR', mediaType: BANNER, size: [160, 60]})
831+
.returns({currency: 'EUR', floor: 2.7});
832+
833+
bidReq.bids[0].getFloor = getFloorStub;
834+
835+
const serverRequestInfo = spec.buildRequests(bidReq.bids, bidReq);
836+
837+
const serverRequestBids = serverRequestInfo.data.bids;
838+
const bid = serverRequestBids[0];
839+
840+
assert.nestedPropertyVal(bid, 'ban.fp.def', 1.9);
841+
assert.nestedPropertyVal(bid, 'ban.fp.cur', 'EUR');
842+
assert.deepNestedPropertyVal(bid, 'ban.fp.siz', [{w: 160, h: 60, p: 2.7}]);
843+
});
699844
});
700845
});
701846
});

0 commit comments

Comments
 (0)