diff --git a/modules/equativBidAdapter.js b/modules/equativBidAdapter.js index 64b61275272..0f6648fc509 100644 --- a/modules/equativBidAdapter.js +++ b/modules/equativBidAdapter.js @@ -18,8 +18,10 @@ const DEFAULT_TTL = 300; const LOG_PREFIX = 'Equativ:'; const PID_STORAGE_NAME = 'eqt_pid'; -let nwid = 0; +let feedbackArray = []; let impIdMap = {}; +let nwid = 0; +let tokens = {}; /** * Assigns values to new properties, removes temporary ones from an object @@ -97,6 +99,36 @@ function makeId() { return str; } +/** + * Updates bid request with data from previous auction + * @param {*} req A bid request object to be updated + * @returns {*} Updated bid request object + */ +function updateFeedbackData(req) { + if (req?.ext?.prebid?.previousauctioninfo) { + req.ext.prebid.previousauctioninfo.forEach(info => { + if (tokens[info?.bidId]) { + feedbackArray.push({ + feedback_token: tokens[info.bidId], + loss: info.bidderCpm == info.highestBidCpm ? 0 : 102, + price: info.highestBidCpm + }); + + delete tokens[info.bidId]; + } + }); + + delete req.ext.prebid; + } + + if (feedbackArray.length) { + deepSetValue(req, 'ext.bid_feedback', feedbackArray[0]); + feedbackArray.shift(); + } + + return req; +} + export const storage = getStorageManager({ bidderCode: BIDDER_CODE }); export const spec = { @@ -122,7 +154,7 @@ export const spec = { requests.push({ data, method: 'POST', - url: 'https://ssb-global.smartadserver.com/api/bid?callerId=169', + url: 'https://ssb-global.smartadserver.com/api/bid?callerId=169' }) }); @@ -145,6 +177,11 @@ export const spec = { .forEach(seat => seat.bid.forEach(bid => { bid.impid = impIdMap[bid.impid]; + + if (deepAccess(bid, 'ext.feedback_token')) { + tokens[bid.impid] = bid.ext.feedback_token; + } + bid.ttl = typeof bid.exp === 'number' && bid.exp > 0 ? bid.exp : DEFAULT_TTL; }) ); @@ -278,7 +315,7 @@ export const converter = ortbConverter({ }); }); - const req = buildRequest(splitImps, bidderRequest, context); + let req = buildRequest(splitImps, bidderRequest, context); let env = ['ortb2.site.publisher', 'ortb2.app.publisher', 'ortb2.dooh.publisher'].find(propPath => deepAccess(bid, propPath)) || 'ortb2.site.publisher'; nwid = deepAccess(bid, env + '.id') || bid.params.networkId; @@ -292,7 +329,7 @@ export const converter = ortbConverter({ if (deepAccess(bid, path)) { props.forEach(prop => { if (!deepAccess(bid, `${path}.${prop}`)) { - logWarn(`${LOG_PREFIX} Property "${path}.${prop}" is missing from request. Request will proceed, but the use of "${prop}" is strongly encouraged.`, bid); + logWarn(`${LOG_PREFIX} Property "${path}.${prop}" is missing from request. Request will proceed, but the use of "${prop}" is strongly encouraged.`, bid); } }); } @@ -303,6 +340,8 @@ export const converter = ortbConverter({ deepSetValue(req, 'user.buyeruid', pid); } + req = updateFeedbackData(req); + return req; } }); diff --git a/test/spec/modules/equativBidAdapter_spec.js b/test/spec/modules/equativBidAdapter_spec.js index d27112edfed..32f5c05077f 100644 --- a/test/spec/modules/equativBidAdapter_spec.js +++ b/test/spec/modules/equativBidAdapter_spec.js @@ -748,7 +748,142 @@ describe('Equativ bid adapter tests', () => { expect(secondImp).to.not.have.property('native'); expect(secondImp).to.have.property('video'); } - }) + }); + + it('should not send ext.prebid', () => { + const request = spec.buildRequests( + DEFAULT_BANNER_BID_REQUESTS, + { + ...DEFAULT_BANNER_BIDDER_REQUEST, + ortb2: { + ext: { + prebid: { + previousauctioninfo: [ + { + bidId: 'abcd1234', + bidderCpm: 5, + highestBidCpm: 6 + } + ] + } + } + } + } + )[0]; + expect(request.data.ext).not.to.have.property('prebid'); + }); + + it('should send feedback data when lost', () => { + const bidId = 'abcd1234'; + const cpm = 3.7; + const impIdMap = getImpIdMap(); + const token = 'y7hd87dw8'; + const RESPONSE_WITH_FEEDBACK = { + body: { + seatbid: [ + { + bid: [ + { + ext: { + feedback_token: token + }, + impid: Object.keys(impIdMap).find(key => impIdMap[key] === bidId) + } + ] + } + ] + } + }; + + let request = spec.buildRequests( + DEFAULT_BANNER_BID_REQUESTS, + DEFAULT_BANNER_BIDDER_REQUEST + )[0]; + + spec.interpretResponse(RESPONSE_WITH_FEEDBACK, request); + + request = spec.buildRequests( + DEFAULT_BANNER_BID_REQUESTS, + { + ...DEFAULT_BANNER_BIDDER_REQUEST, + ortb2: { + ext: { + prebid: { + previousauctioninfo: [ + { + bidId, + bidderCpm: 2.41, + highestBidCpm: cpm + } + ] + } + } + } + } + )[0]; + + expect(request.data.ext).to.have.property('bid_feedback').and.to.deep.equal({ + feedback_token: token, + loss: 102, + price: cpm + }); + }); + + it('should send feedback data when won', () => { + const bidId = 'abcd1234'; + const cpm = 2.34; + const impIdMap = getImpIdMap(); + const token = '87187y83'; + const RESPONSE_WITH_FEEDBACK = { + body: { + seatbid: [ + { + bid: [ + { + ext: { + feedback_token: token + }, + impid: Object.keys(impIdMap).find(key => impIdMap[key] === bidId) + } + ] + } + ] + } + }; + + let request = spec.buildRequests( + DEFAULT_BANNER_BID_REQUESTS, + DEFAULT_BANNER_BIDDER_REQUEST + )[0]; + + spec.interpretResponse(RESPONSE_WITH_FEEDBACK, request); + + request = spec.buildRequests( + DEFAULT_BANNER_BID_REQUESTS, + { + ...DEFAULT_BANNER_BIDDER_REQUEST, + ortb2: { + ext: { + prebid: { + previousauctioninfo: [ + { + bidId, + bidderCpm: 2.34, + highestBidCpm: cpm + } + ] + } + } + } + } + )[0]; + + expect(request.data.ext).to.have.property('bid_feedback').and.to.deep.equal({ + feedback_token: token, + loss: 0, + price: cpm + }); + }); }); describe('getUserSyncs', () => {