diff --git a/api/serializers/bid.js b/api/serializers/bid.js index d9db354..198bcc8 100644 --- a/api/serializers/bid.js +++ b/api/serializers/bid.js @@ -16,7 +16,6 @@ const lotSerializer = require('./lot'); bidSerializer.formatBid = function (bid) { const formattedBid = _.pick(bid, ['isWinning', 'isSubcontracted', 'xYearApproximated']); - formattedBid.TEDCANID = bid.xTEDCANID; formattedBid.value = _.get(bid, 'price.netAmountEur') || undefined; formattedBid.xAmountApproximated = _.get(bid, 'price.xAmountApproximated'); return formattedBid; diff --git a/api/serializers/network_actor.js b/api/serializers/network_actor.js index f086c61..6a318de 100644 --- a/api/serializers/network_actor.js +++ b/api/serializers/network_actor.js @@ -9,7 +9,7 @@ const bidSerializer = require('./bid'); function formatNetworkActor(networkActor) { const formattedActor = _.pick( networkActor, - ['id', 'label', 'type', 'medianCompetition', 'value', 'country'], + ['id', 'label', 'type', 'medianCompetition', 'value'], ); formattedActor.flags = {}; formattedActor.hidden = !networkActor.active; @@ -17,7 +17,7 @@ function formatNetworkActor(networkActor) { } function formatActorWithDetails(network, networkActor, nodeIDs) { - const node = _.pick(networkActor, ['label', 'id', 'type', 'medianCompetition', 'value']); + const node = _.pick(networkActor, ['label', 'id', 'type', 'medianCompetition', 'value', 'countries']); node.flags = {}; node.hidden = !networkActor.active; const edgeToBidClass = networkActor.type === 'buyer' ? 'Awards' : 'Participates'; diff --git a/api/serializers/tender.js b/api/serializers/tender.js index 3197fae..47ffeaf 100644 --- a/api/serializers/tender.js +++ b/api/serializers/tender.js @@ -18,7 +18,6 @@ tenderSerializer.formatTender = function (tender) { const formattedTender = _.pick(tender, ['id', 'title', 'titleEnglish', 'description', 'sources', 'isCoveredByGpa', 'isFrameworkAgreement', 'procedureType', 'year', 'country', 'isDirective', 'xYearApproximated']); formattedTender.isEUFunded = tender.xIsEuFunded; - formattedTender.TEDCNID = tender.xTEDCNID; formattedTender.isDirective = tender.xIsDirective; formattedTender.finalValue = _.get(tender, 'finalPrice.netAmountEur') || undefined; formattedTender.xAmountApproximated = _.get(tender, 'finalPrice.xAmountApproximated'); diff --git a/api/swagger/swagger.yaml b/api/swagger/swagger.yaml index 9cd9f11..25ee2fc 100644 --- a/api/swagger/swagger.yaml +++ b/api/swagger/swagger.yaml @@ -1346,9 +1346,12 @@ definitions: enum: - bidder - buyer - country: - type: string - description: ISO 3166-1 alpha-2 country code + countries: + type: array + description: Array of bidder/buyer country codes + items: + type: string + description: ISO 3166-1 alpha-2 country code of bidder/buyer medianCompetition: type: number format: double @@ -1556,9 +1559,6 @@ definitions: isWinning: type: boolean description: Did this bid won the lot? - TEDCANID: - type: string - description: ID of the Contract Award Notice on ted.europa.eu isSubcontracted: type: boolean description: Did the winner subcontract another company for this bid? @@ -1629,9 +1629,6 @@ definitions: items: type: string description: URL to tender source - TEDCNID: - type: string - description: ID of the Contract Notice on ted.europa.eu title: type: string description: Title of the tender @@ -1744,9 +1741,12 @@ definitions: enum: - bidder - buyer - country: - type: string - description: Actor country + countries: + type: array + description: Array of bidder/buyer country codes + items: + type: string + description: ISO 3166-1 alpha-2 country code of bidder/buyer Address: type: object properties: diff --git a/api/writers/actor_cluster.js b/api/writers/actor_cluster.js index 6082337..e82d149 100644 --- a/api/writers/actor_cluster.js +++ b/api/writers/actor_cluster.js @@ -19,6 +19,7 @@ async function createCluster(networkID, clusterParams) { label: clusterParams.label, type: clusterParams.type, active: true, + countries: _.uniq(calcuatedAttrs.countries), value: calcuatedAttrs[network.settings.nodeSize], medianCompetition: calcuatedAttrs.medianCompetition, }; @@ -114,7 +115,8 @@ function calculateCluster(edgeToBidClass, network, actorIDs) { const clusterQuery = `SELECT count(*) as numberOfWinningBids, sum(price.netAmountEur) as amountOfMoneyExchanged, - median(out('AppliedTo').bidsCount) as medianCompetition + median(out('AppliedTo').bidsCount) as medianCompetition, + unionall(in('${edgeToBidClass}').address.country) as countries FROM Bid WHERE ${_.join(networkWriters.queryToBidFilters(network.query), ' AND ')} AND in('${edgeToBidClass}').id in :actorIDs diff --git a/api/writers/network.js b/api/writers/network.js index aa4a817..77cf9e2 100644 --- a/api/writers/network.js +++ b/api/writers/network.js @@ -47,6 +47,83 @@ async function createNetwork(networkParams, user) { return transaction.commit(2).return(`$${networkName}`).one(); } +async function updateNetwork(networkParams, existingNetwork) { + const clusterWriters = require('./actor_cluster'); + const newNetworkQuery = _.get(networkParams, 'query', undefined); + let networkQuery = {}; + + if (_.isUndefined(newNetworkQuery) === true) { + networkQuery = existingNetwork.query; + } else { + networkQuery = _.pickBy(newNetworkQuery, (val) => !(_.isUndefined(val))); + } + if (_.isEmpty(networkQuery) === true) { + throw new codes.BadRequestError('Network "query" can\'t be empty.'); + } + + // We have to retrieve the clusters here before we delete the actor nodes + const clusterQuery = `SELECT *, + out('Includes').in('ActingAs').id as originalActorIDs + FROM ActorCluster + WHERE out('PartOf').id=:networkID`; + const existingClusters = await config.db.query( + clusterQuery, + { params: { networkID: existingNetwork.id } } + ); + + const networkName = recordName(existingNetwork.id, 'Network'); + const newNetworkAttrs = Object.assign({}, { + name: _.get(networkParams, 'name', existingNetwork.name), + settings: _.get(networkParams, 'settings', existingNetwork.settings), + synopsis: _.get(networkParams, 'synopsis', existingNetwork.synopsis), + query: networkQuery, + created: existingNetwork.created, + updated: moment().format('YYYY-MM-DD HH:mm:ss'), + }); + + const transaction = config.db.let(networkName, (t) => { + t.update('Network') + .set(newNetworkAttrs) + .where({ '@rid': existingNetwork['@rid'] }) + .return('AFTER'); + }); + + await deleteNetworkActors(transaction, existingNetwork); + + const networkActorsMapping = await Promise.join( + createBuyerNodes(transaction, newNetworkAttrs.settings, networkQuery, networkName), + createBidderNodes(transaction, newNetworkAttrs.settings, networkQuery, networkName), + (buyerActorsMapping, bidderActorsMapping) => + Object.assign(buyerActorsMapping, bidderActorsMapping), + ); + await Promise.all([ + createContractsEdges(transaction, newNetworkAttrs.settings, networkQuery, networkActorsMapping), + createPartnersEdges(transaction, 'Awards', networkQuery, networkActorsMapping), + createPartnersEdges(transaction, 'Participates', networkQuery, networkActorsMapping), + ]); + + return transaction.commit(2).return(`$${networkName}`).one() + .then((updatedNetwork) => + Promise.map(existingClusters, (existingCluster) => { + const clusterActorsQuery = `SELECT * FROM NetworkActor + WHERE out('PartOf').id=:networkID + AND in('ActingAs').id in :actorIDs + ` + return config.db.query( + clusterActorsQuery, + { params: { networkID: updatedNetwork.id, actorIDs: existingCluster.originalActorIDs}}, + ).then((newClusterActors) => { + const newNodeIDs = _.map(newClusterActors, 'id'); + return clusterWriters.updateCluster( + updatedNetwork.id, + existingCluster.id, + { nodes: newNodeIDs } + ); + }) + }) + ); +} + function queryToBidFilters(networkQuery) { const filters = []; const actorFilters = []; @@ -91,6 +168,7 @@ function createBidderNodes(transaction, networkSettings, networkQuery, networkNa bidder[@rid] as bidderRID, count(*) as numberOfWinningBids, sum(price.netAmountEur) as amountOfMoneyExchanged, + bidder.address.country as country, median(out('AppliedTo').bidsCount) as medianCompetition FROM ( SELECT *, in('Participates') as bidder @@ -111,6 +189,7 @@ function createBidderNodes(transaction, networkSettings, networkQuery, networkNa nodeAttrs.id = uuidv4(); nodeAttrs.type = 'bidder'; nodeAttrs.active = true; + nodeAttrs.countries = [node.country]; nodeAttrs.value = node[networkSettings.nodeSize]; const partnerName = createNetworkActor(transaction, nodeAttrs, node.bidderRID, networkName); bidderActorMapping[node.bidderRID] = partnerName; @@ -140,11 +219,12 @@ function createBuyerNodes(transaction, networkSettings, networkQuery, networkNam .then((buyerNodes) => Promise.map(buyerNodes, (node) => { const nodeAttrs = _.pick( node, - ['label', 'medianCompetition', 'country'], + ['label', 'medianCompetition'], ); nodeAttrs.id = uuidv4(); nodeAttrs.type = 'buyer'; nodeAttrs.active = true; + nodeAttrs.countries = [node.country]; nodeAttrs.value = node[networkSettings.nodeSize]; const partnerName = createNetworkActor(transaction, nodeAttrs, node.buyerRID, networkName); buyerActorMapping[node.buyerRID] = partnerName; @@ -259,6 +339,22 @@ function createNetworkEdge(transaction, edgeClass, edgeAttrs, fromName, toName) return edgeName; } +function deleteNetworkActors(transaction, existingNetwork) { + return config.db.select().from('NetworkActor') + .where({ + "out('PartOf').id": existingNetwork.id, + "@class": 'NetworkActor', + }) + .all() + .then((networkActors) => Promise.map(networkActors, (networkActor) => { + const deleteActorName = recordName(networkActor.id, 'delete'); + + transaction.let(deleteActorName, (t) => + t.delete('vertex', 'NetworkActor') + .where({ '@rid': networkActor['@rid'] })); + })); +} + module.exports = { createNetwork, createBidderNodes, @@ -270,4 +366,5 @@ module.exports = { createNetworkEdge, queryToBidFilters, recordName, + updateNetwork, }; diff --git a/api/writers/tender.js b/api/writers/tender.js index 277bf76..29bf6a6 100644 --- a/api/writers/tender.js +++ b/api/writers/tender.js @@ -19,7 +19,7 @@ function recordName(id, className) { // Returns true // Raises OrientDBError if the writing failed -async function writeTender(fullTenderRecord, skipMilitaryFilters = false) { +async function writeTender(fullTenderRecord, skipMilitaryFilters = true) { const awardedLots = _.filter(fullTenderRecord.lots, { status: 'AWARDED' }); // If there are no awarded lots don't even process the tender @@ -60,6 +60,19 @@ async function writeTender(fullTenderRecord, skipMilitaryFilters = false) { } }); + + // The tender already exists. We're deleting the existing CPV, Buyer, Bidder edges + // We also delete the existing Lots and Bids before creating new ones + if (_.isUndefined(existingTender) === false) { + await deleteHasCPV(transaction, tenderName, existingTenderID) + await deleteCreates(transaction, tenderName, existingTenderID) + const existingLotRel = await config.db.select("out('Comprises')").from('Tender') + .where({ '@rid': existingTenderID }).one(); + const existingLotRIDs = existingLotRel.out; + await Promise.map(existingLotRIDs, (existingLotRID) => + deleteLot(transaction, existingLotRID)); + } + const processedCpvs = await Promise.map((fullTenderRecord.cpvs || []), (rawCpv) => upsertCpv(transaction, rawCpv, existingTenderID, tenderName)); // Only process further valid cpvs @@ -71,14 +84,6 @@ async function writeTender(fullTenderRecord, skipMilitaryFilters = false) { (rawBuyer) => upsertBuyer(transaction, rawBuyer, existingTenderID, tenderName, fullTenderRecord), // eslint-disable-line max-len ); - if (_.isUndefined(existingTender) === false) { - const existingLotRel = await config.db.select("out('Comprises')").from('Tender') - .where({ '@rid': existingTenderID }).one(); - const existingLotRIDs = existingLotRel.out; - await Promise.map(existingLotRIDs, (existingLotRID) => - deleteLot(transaction, existingLotRID)); - } - await Promise.map((awardedLots || []), (rawLot) => { const rawBids = (rawLot.bids || []); return createLot(transaction, rawLot, tenderName, fullTenderRecord) @@ -94,6 +99,24 @@ async function writeTender(fullTenderRecord, skipMilitaryFilters = false) { }); } +async function deleteHasCPV(transaction, tenderName, existingTenderID) { + const operationName = `deleteHasCPV${tenderName}`; + + transaction.let(operationName, (t) => + t.delete('edge', 'HasCPV') + .where({ out: existingTenderID})); + return operationName; +} + +async function deleteCreates(transaction, tenderName, existingTenderID){ + const operationName = `deleteCreates${tenderName}`; + + transaction.let(operationName, (t) => + t.delete('edge', 'Creates') + .where({ in: existingTenderID})); + return operationName; +} + async function deleteLot(transaction, lotRID) { const lotName = `delete${recordName(uuidv4(), 'Lot')}`; @@ -190,24 +213,11 @@ async function upsertBuyer(transaction, rawBuyer, existingTenderID, tenderName, }); } - const existingRel = await config.db.select().from('Creates') - .where({ - in: (existingTenderID || null), - out: (existingBuyerID || null), - }).one(); - transaction.let(`${buyerName}creates${tenderName}`, (t) => { - if (_.isUndefined(existingRel)) { - t.create('edge', 'Creates') - .from(`$${buyerName}`) - .to(`$${tenderName}`) - .set(buyerExtractor.extractCreates(rawBuyer)); - } else { - t.update('Creates') - .set(buyerExtractor.extractCreates(rawBuyer)) - .where({ '@rid': existingRel['@rid'] }) - .return('AFTER'); - } - }); + transaction.let(`${buyerName}creates${tenderName}`, (t) => + t.create('edge', 'Creates') + .from(`$${buyerName}`) + .to(`$${tenderName}`) + .set(buyerExtractor.extractCreates(rawBuyer))); return buyerName; } @@ -268,29 +278,13 @@ async function upsertCpv(transaction, rawCpv, existingTenderID, tenderName) { } } - const existingRel = await config.db.select().from('HasCPV') - .where({ - // This is needed because undefined confuses OrientDB - in: (existingCpvID || null), - out: (existingTenderID || null), - }).one(); const edgeName = `${tenderName}has${cpvName}`; if (_.includes(_.map(transaction._state.bcommon, (arr) => arr[0]), edgeName) === false) { - if (_.isUndefined(existingRel)) { - transaction.let(edgeName, (t) => { - t.create('edge', 'HasCPV') - .from(`$${tenderName}`) - .to(`$${cpvName}`) - .set(cpvExtractor.extractHasCpv(rawCpv)); - }); - } else { - transaction.let(edgeName, (t) => { - t.update('HasCPV') - .set(cpvExtractor.extractHasCpv(rawCpv)) - .where({ '@rid': existingRel['@rid'] }) - .return('AFTER'); - }); - } + transaction.let(edgeName, (t) => + t.create('edge', 'HasCPV') + .from(`$${tenderName}`) + .to(`$${cpvName}`) + .set(cpvExtractor.extractHasCpv(rawCpv))); } return cpvName; } diff --git a/extractors/bid.js b/extractors/bid.js index b822a9f..3c12d6c 100644 --- a/extractors/bid.js +++ b/extractors/bid.js @@ -19,13 +19,7 @@ function extractBid(bidAttrs, tenderAttrs, lotAttrs) { robustPrice: priceExtractor.extractPrice(bidAttrs.robustPrice), xCountry: _.get(tenderAttrs, 'ot.country') || tenderAttrs.country, xYear: extractYear(lotAttrs.awardDecisionDate), - xTEDCANID: _ - .chain((tenderAttrs.publications || [])) - .filter({ formType: 'CONTRACT_AWARD' }) - .head() - .get('sourceId') - .value(), - sources: extractSources(tenderAttrs.publications), + sources: [extractSource(tenderAttrs)], }; } @@ -37,10 +31,10 @@ function extractYear(awardDecisionDate) { return year; } -function extractSources(publications) { - const awardNotices = _.filter(publications, { formType: 'CONTRACT_AWARD' }); - const sourceURLs = _.map(awardNotices, 'humanReadableUrl'); - return sourceURLs; +function extractSource(tenderAttrs) { + const fomattedCountry = _.lowerCase(tenderAttrs.country); + const opentenderLink = `https://opentender.eu/${fomattedCountry}/tender/${tenderAttrs.id}`; + return opentenderLink; } module.exports = { diff --git a/extractors/bidder.js b/extractors/bidder.js index 34b3175..b87049c 100644 --- a/extractors/bidder.js +++ b/extractors/bidder.js @@ -7,7 +7,7 @@ const indicatorExtractor = require('./indicator'); function extractBidder(bidderAttrs, tenderAttrs = {}) { return { - id: _.get(bidderAttrs, 'metaData.cleanObjectPersistentId') || bidderAttrs.id, + id: bidderAttrs.id, name: bidderAttrs.name, normalizedName: helpers.removeDiacritics(bidderAttrs.name), address: bidderAttrs.address, diff --git a/extractors/buyer.js b/extractors/buyer.js index 47cfe3f..45a1fce 100644 --- a/extractors/buyer.js +++ b/extractors/buyer.js @@ -6,7 +6,7 @@ const indicatorExtractor = require('./indicator'); function extractBuyer(buyerAttrs, tenderAttrs = {}) { return { - id: _.get(buyerAttrs, 'metaData.cleanObjectPersistentId') || buyerAttrs.id, + id: buyerAttrs.id, name: buyerAttrs.name, normalizedName: helpers.removeDiacritics(buyerAttrs.name), address: buyerAttrs.address, diff --git a/extractors/tender.js b/extractors/tender.js index 2c6c73e..a195b5d 100644 --- a/extractors/tender.js +++ b/extractors/tender.js @@ -23,12 +23,8 @@ function extractTender(tenderAttrs, indicators = [], publications = []) { indicators: _ .filter(indicators, { relatedEntityId: tenderAttrs.id }) .map((indicatorAttrs) => indicatorExtractor.extractIndicator(indicatorAttrs)), - xTEDCNID: _.get( - _.head(_.filter(publications, { formType: 'CONTRACT_NOTICE' })), - 'sourceId', - ), year: extractYear(publications), - sources: extractSources(publications), + sources: [extractSource(tenderAttrs)], }; } @@ -61,10 +57,10 @@ function extractYear(publications) { return year; } -function extractSources(publications) { - const contractNotices = _.filter(publications, { formType: 'CONTRACT_NOTICE' }); - const sourceURLs = _.map(contractNotices, 'humanReadableUrl'); - return sourceURLs; +function extractSource(tenderAttrs) { + const fomattedCountry = _.lowerCase(tenderAttrs.country); + const opentenderLink = `https://opentender.eu/${fomattedCountry}/tender/${tenderAttrs.id}`; + return opentenderLink; } module.exports = { diff --git a/migrations/m20200403_101942_remove_xTEDCNID_from_tender.js b/migrations/m20200403_101942_remove_xTEDCNID_from_tender.js new file mode 100644 index 0000000..1160dfb --- /dev/null +++ b/migrations/m20200403_101942_remove_xTEDCNID_from_tender.js @@ -0,0 +1,19 @@ +"use strict"; +exports.name = "remove xTEDCNID from tender"; + + +exports.up = (db) => ( + db.class.get('Tender') + .then((Tender) => Tender.property.drop('xTEDCNID')) +); + +exports.down = (db) => ( + db.class.get('Tender') + .then((Tender) => + Tender.property.create([ + { + name: 'xTEDCNID', + type: 'String', + }, + ])) +); diff --git a/migrations/m20200403_103410_remove_xTEDCANID_from_Bid.js b/migrations/m20200403_103410_remove_xTEDCANID_from_Bid.js new file mode 100644 index 0000000..356d78c --- /dev/null +++ b/migrations/m20200403_103410_remove_xTEDCANID_from_Bid.js @@ -0,0 +1,18 @@ +"use strict"; +exports.name = "remove xTEDCANID from Bid"; + +exports.up = (db) => ( + db.class.get('Bid') + .then((Bid) => Bid.property.drop('xTEDCANID')) +); + +exports.down = (db) => ( + db.class.get('Bid') + .then((Bid) => + Bid.property.create([ + { + name: 'xTEDCANID', + type: 'String', + }, + ])) +); diff --git a/migrations/m20200510_144033_add_country_to_network_actor.js b/migrations/m20200510_144033_add_country_to_network_actor.js new file mode 100644 index 0000000..94b76fa --- /dev/null +++ b/migrations/m20200510_144033_add_country_to_network_actor.js @@ -0,0 +1,19 @@ +"use strict"; +exports.name = "add country to NetworkActor"; + +exports.up = function (db) { + db.class.get('NetworkActor') + .then((NetworkActor) => + NetworkActor.property.create([ + { + name: 'countries', + type: 'EmbeddedSet', + }, + ])) +}; + +exports.down = (db) => ( + db.class.get('NetworkActor') + .then((NetworkActor) => NetworkActor.property.drop('countries')) +); + diff --git a/scripts/delete_removed_actors.js b/scripts/delete_removed_actors.js new file mode 100644 index 0000000..1805cb0 --- /dev/null +++ b/scripts/delete_removed_actors.js @@ -0,0 +1,63 @@ +/* eslint-disable no-console */ + +'use strict'; + +const _ = require('lodash'); +const { URL } = require('url'); +const Promise = require('bluebird'); + +const config = require('../config/default'); +const helpers = require('./helpers'); + +function recordName(id, className) { + return `${className.toLowerCase()}${id.replace(/-/g, '')}`; +} + +function deleteRemovedActors() { + const removedBuyersQuery = `SELECT * FROM Buyer WHERE out('Awards').size() == 0` + const removedBiddersQuery = `SELECT * FROM Bidder WHERE out('Participates').size() == 0` + return config.db.query(removedBuyersQuery) + .then((removedBuyers) => Promise.map(removedBuyers, (removedBuyer) => + deleteRemovedActor(removedBuyer, 'Buyer'))) + .then((deletedBuyers) => { + console.log(`Deleted ${deletedBuyers.length} buyers`); + }) + .then(() => config.db.query(removedBiddersQuery)) + .then((removedBidders) => Promise.map(removedBidders, (removedBidder) => + deleteRemovedActor(removedBidder, 'Bidder'))) + .then((deletedBidders) => { + console.log(`Deleted ${deletedBidders.length} bidders`); + process.exit(); + }) + .catch((err) => { + console.error(err); + process.exit(-1); + }); +} + +async function deleteRemovedActor(actor, actorClass) { + const actorName = recordName(actor.id, actorClass); + const networkActorRelations = await config.db.select(`out("ActingAs").id`) + .from(actorClass) + .where({ '@rid': actor['@rid'] }) + .all(); + const relatedNetworkActorIDs = _.flatten(_.map(networkActorRelations, (edge) => edge.out)) + console.log(relatedNetworkActorIDs) + + const transaction = config.db.let(actorName, (t) => + t.delete('vertex', actorClass) + .where({ '@rid': actor['@rid'] })); + await Promise.map(relatedNetworkActorIDs, (networkActorID) => { + const networkActorName = recordName(networkActorID, 'NetworkActor'); + transaction.let(networkActorName, (t) => + t.delete('vertex', 'NetworkActor') + .where({ 'id': networkActorID })); + }) + return transaction.commit(2).return(`$${actorName}`).one() + .catch((err) => { + console.log(err); + throw err; + }); +} + +deleteRemovedActors(); diff --git a/test/extractors/bid.js b/test/extractors/bid.js index 10bc449..e6a1a4e 100644 --- a/test/extractors/bid.js +++ b/test/extractors/bid.js @@ -5,29 +5,6 @@ const test = require('ava'); const bidExtractor = require('./../../extractors/bid'); const fixtures = require('./../fixtures'); -test('extractBid extracts contract award notice id from publications', async (t) => { - const publication = await fixtures.build('rawContractAwardNotice'); - const rawBid = await fixtures.build('rawBid'); - const rawTender = await fixtures.build('rawTender', { - publications: [publication], - }); - t.is( - bidExtractor.extractBid(rawBid, rawTender, {}).xTEDCANID, - publication.sourceId, - ); -}); - -test('extractBid returns null if there is no publication', async (t) => { - const rawBid = await fixtures.build('rawBid'); - const rawTender = await fixtures.build('rawTender', { - publications: [], - }); - t.is( - bidExtractor.extractBid(rawBid, rawTender, {}).xTEDCANID, - undefined, - ); -}); - test('extractBid extracts year from lots award decision date', async (t) => { const rawBid = await fixtures.build('rawBid'); const year = 2015; diff --git a/test/extractors/tender.js b/test/extractors/tender.js index 6cc9c4e..212a93a 100644 --- a/test/extractors/tender.js +++ b/test/extractors/tender.js @@ -6,23 +6,6 @@ const test = require('ava'); const tenderExtractor = require('./../../extractors/tender'); const fixtures = require('./../fixtures'); -test('extractTender extracts contract notice id from publications', async (t) => { - const publication = await fixtures.build('rawContractNotice'); - const rawTender = await fixtures.build('rawTender'); - t.is( - tenderExtractor.extractTender(rawTender, [], [publication]).xTEDCNID, - publication.sourceId, - ); -}); - -test('extractTender returns null if there is no publication', async (t) => { - const rawTender = await fixtures.build('rawTender'); - t.is( - tenderExtractor.extractTender(rawTender, [], []).xTEDCNID, - undefined, - ); -}); - test('extractTender extracts sources from contract notice publications', async (t) => { const publication = await fixtures.build('rawContractNotice'); const rawTender = await fixtures.build('rawTender');