Exemple #1
0
def create_awards(request):
    auction = request.validated['auction']
    auction.status = 'active.qualification'
    now = get_now()
    auction.awardPeriod = type(auction).awardPeriod({'startDate': now})
    valid_bids = [bid for bid in auction.bids if bid['status'] != 'invalid']
    bids = chef(valid_bids, auction.features or [], [], True)

    for bid, status in zip(bids, ['pending.verification', 'pending.waiting']):
        bid = bid.serialize()
        award = type(auction).awards.model_class({
            '__parent__': request.context,
            'bid_id': bid['id'],
            'status': status,
            'date': now,
            'value': bid['value'],
            'suppliers': bid['tenderers'],
            'complaintPeriod': {
                'startDate': now
            }
        })
        if award.status == 'pending.verification':
            award.signingPeriod = award.paymentPeriod = award.verificationPeriod = {
                'startDate': now
            }
            request.response.headers['Location'] = request.route_url(
                '{}:Auction Awards'.format(auction.procurementMethodType),
                auction_id=auction.id,
                award_id=award['id'])
        auction.awards.append(award)
def create_awards(request):
    """
        Function create NUMBER_OF_BIDS_TO_BE_QUALIFIED awards objects
        First award always in pending.verification status
        others in pending.waiting status
    """
    auction = request.validated['auction']
    auction.status = 'active.qualification'
    now = get_now()
    auction.awardPeriod = type(auction).awardPeriod({'startDate': now})
    awarding_type = request.content_configurator.awarding_type
    valid_bids = [bid for bid in auction.bids if bid['value'] is not None]
    bids = chef(valid_bids, auction.features or [], [], True)
    bids_to_qualify = get_bids_to_qualify(bids)
    for i in xrange(0, bids_to_qualify):
        status = 'pending.waiting'
        if i == 0:
            status = 'pending.verification'
        bid = bids[i].serialize()
        award = make_award(request, auction, bid, status, now, parent=True)
        if bid['status'] == 'invalid':
            set_award_status_unsuccessful(award, now)
        if award.status == 'pending.verification':
            award.signingPeriod = award.paymentPeriod = award.verificationPeriod = {
                'startDate': now
            }
            add_award_route_url(request, auction, award, awarding_type)
        auction.awards.append(award)
def create_awards(request):
    """
        Function create NUMBER_OF_BIDS_TO_BE_QUALIFIED awards objects
        First award always in pending.verification status
        others in pending.waiting status
    """
    auction = request.validated['auction']
    auction.status = 'active.qualification'
    now = get_now()
    auction.awardPeriod = type(auction).awardPeriod({'startDate': now})
    awarding_type = request.content_configurator.awarding_type
    bids = chef(auction.bids, auction.features or [], [], True)
    # minNumberOfQualifiedBids == 1
    bids_to_qualify = get_bids_to_qualify(bids)
    for bid, status in izip_longest(bids[:bids_to_qualify],
                                    ['pending.verification'],
                                    fillvalue='pending.waiting'):
        bid = bid.serialize()
        award = make_award(request, auction, bid, status, now, parent=True)
        if bid['status'] == 'invalid':
            set_award_status_unsuccessful(award, now)
        if award.status == 'pending.verification':
            award.verificationPeriod = award.paymentPeriod = award.signingPeriod = {
                'startDate': now
            }
            add_award_route_url(request, auction, award, awarding_type)
        auction.awards.append(award)
Exemple #4
0
    def _start_awarding(self):
        """
            Function create NUMBER_OF_BIDS_TO_BE_QUALIFIED awards objects
            First award always in pending.verification status
            others in pending.waiting status
            In case that only one bid was applied, award object
            in pending.admission status will be created for that bid
        """

        auction = self.context
        auction.status = 'active.qualification'
        now = get_now()

        auction.awardPeriod = type(auction).awardPeriod({'startDate': now})
        awarding_type = self.awarding_type
        valid_bids = [bid for bid in auction.bids if self.is_bid_valid(bid)]

        award_status = 'pending.admission' if len(
            valid_bids
        ) == 1 and self.pending_admission_for_one_bid else 'pending'

        bids = chef(valid_bids, auction.features or [], [], True)
        bids_to_qualify = self.get_bids_to_qualify(bids)
        for bid, status in izip_longest(bids[:bids_to_qualify], [award_status],
                                        fillvalue='pending.waiting'):
            bid = bid.serialize()
            award = make_award(self.request,
                               auction,
                               bid,
                               status,
                               now,
                               parent=True)

            if bid['status'] == 'invalid':
                set_award_status_unsuccessful(award, now)
            if award.status == 'pending':
                award.verificationPeriod = self.verificationPeriod()
                award.signingPeriod = self.signingPeriod()
                add_award_route_url(self.request, auction, award,
                                    awarding_type)
            if award.status == 'pending.admission':
                award.admissionPeriod = {
                    'startDate':
                    now,
                    'endDate':
                    calculate_business_date(start=now,
                                            context=auction,
                                            **award.ADMISSION_PERIOD_PARAMS)
                }
                add_award_route_url(self.request, auction, award,
                                    awarding_type)
            auction.awards.append(award)
        return True
def prepare_bids_for_awarding(tender, bids, lot_id=None):
    """
    Used by add_next_award method
    :param tender:
    :param bids
    :param lot_id:
    :return: list of bid dict objects sorted in a way they will be selected as winners
    """
    lot_items = [i.id for i in tender.items if i.relatedLot == lot_id]  # all items in case of non-lot tender
    features = [
         i for i in (tender.features or [])
         if i.featureOf == "tenderer"
         or i.featureOf == "lot" and i.relatedItem == lot_id
         or i.featureOf == "item" and i.relatedItem in lot_items
    ]  # all features in case of non-lot tender
    codes = [i.code for i in features]
    active_bids = []
    for bid in bids:
        if bid.status == "active":
            bid_params = [i for i in bid.parameters if i.code in codes]
            if lot_id:
                for lot_value in bid.lotValues:
                    if lot_value.relatedLot == lot_id and getattr(lot_value, "status", "active") == "active":
                        active_bids.append(
                            {
                                "id": bid.id,
                                "value": lot_value.value.serialize(),
                                "tenderers": bid.tenderers,
                                "parameters": bid_params,
                                "date": lot_value.date,
                            }
                        )
                        continue  # only one lotValue in a bid is expected
            else:
                active_bids.append(
                    {
                        "id": bid.id,
                        "value": bid.value.serialize(),
                        "tenderers": bid.tenderers,
                        "parameters": bid_params,
                        "date": bid.date,
                    }
                )
    configurator = tender.__parent__.request.content_configurator
    bids = chef(
        active_bids, features,
        ignore="",  # filters by id, shouldn't be a part of this lib
        reverse=configurator.reverse_awarding_criteria,
        awarding_criteria_key=configurator.awarding_criteria_key,
    )
    return bids
Exemple #6
0
def create_awards(request):
    """
        Function create NUMBER_OF_BIDS_TO_BE_QUALIFIED awards objects
        First award always in pending.verification status
        others in pending.waiting status
        In case that only one bid was applied, award object
        in pending.admission status will be created for that bid
    """
    auction = request.validated['auction']
    auction.status = 'active.qualification'
    now = get_now()
    auction.awardPeriod = type(auction).awardPeriod({'startDate': now})
    awarding_type = request.content_configurator.awarding_type
    valid_bids = [bid for bid in auction.bids if bid['value'] is not None]
    if len(valid_bids) == 1:
        bid = valid_bids[0].serialize()
        award = make_award(request,
                           auction,
                           bid,
                           'pending.admission',
                           now,
                           parent=True)
        if bid['status'] == 'invalid':
            set_award_status_unsuccessful(award, now)
        if award.status == 'pending.admission':
            award.admissionPeriod = {
                'startDate':
                now,
                'endDate':
                calculate_business_date(now, VERIFY_ADMISSION_PROTOCOL_TIME,
                                        auction, True,
                                        AWARDING_PERIODS_END_DATE_HOUR)
            }
            add_award_route_url(request, auction, award, awarding_type)
        auction.awards.append(award)
    else:
        bids = chef(valid_bids, auction.features or [], [], True)
        bids_to_qualify = get_bids_to_qualify(bids)
        for bid, status in izip_longest(bids[:bids_to_qualify], ['pending'],
                                        fillvalue='pending.waiting'):
            bid = bid.serialize()
            award = make_award(request, auction, bid, status, now, parent=True)
            if bid['status'] == 'invalid':
                set_award_status_unsuccessful(award, now)
            if award.status == 'pending':
                award.signingPeriod = award.verificationPeriod = {
                    'startDate': now
                }
                add_award_route_url(request, auction, award, awarding_type)
            auction.awards.append(award)
def sorting_start_bids_by_amount(bids, features=None, reverse=True):
    """
    >>> from json import load
    >>> import os
    >>> data = load(open(os.path.join(os.path.dirname(__file__),
    ...                               'tests/functional/data/tender_simple.json')))
    >>> sorted_data = sorting_start_bids_by_amount(data['data']['bids'])

    """
    def get_amount(item):
        return item['value']['amount']

    # return sorted(bids, key=get_amount, reverse=reverse)
    return chef(bids, features=features)
Exemple #8
0
def migrate_awarding_1_0_to_awarding_2_1(auction, procurementMethodTypes):
    if (auction['procurementMethodType'] not in procurementMethodTypes
            or auction['status'] not in ['active.qualification', 'active.awarded']
            or 'awards' not in auction):
        return

    now = get_now().isoformat()
    awards = auction["awards"]
    award = [a for a in awards if a['status'] in ['active', 'pending']][0]
    award_create_date = award['complaintPeriod']['startDate']
    award.update({
        'verificationPeriod': {
            'startDate': award_create_date,
            'endDate': award_create_date
        },
        'paymentPeriod': {
            'startDate': award_create_date,
        },
        'signingPeriod': {
            'startDate': award_create_date,
        }
    })

    if award['status'] == 'pending':
        award['status'] = 'pending.payment'

    elif award['status'] == 'active':
        award['paymentPeriod']['endDate'] = now

    awarded_bids = set([a['bid_id'] for a in awards])
    sorted_bids = chef(auction['bids'], auction.get('features'), [], True)
    filtered_bids = [bid for bid in sorted_bids if bid['id'] not in awarded_bids]

    for bid in filtered_bids:
        award = {
            'id': uuid4().hex,
            'bid_id': bid['id'],
            'status': 'pending.waiting',
            'date': award_create_date,
            'value': bid['value'],
            'suppliers': bid['tenderers'],
            'complaintPeriod': {
                'startDate': award_create_date
            }
        }
        awards.append(award)
Exemple #9
0
def create_awards(request):
    """
        Function create NUMBER_OF_BIDS_TO_BE_QUALIFIED awards objects
        First award always in pending.verification status
        others in pending.waiting status
    """
    auction = request.validated['auction']
    auction.status = 'active.qualification'
    now = get_now()
    auction.awardPeriod = type(auction).awardPeriod({'startDate': now})
    bids = chef(auction.bids, auction.features or [], [], True)
    # minNumberOfQualifiedBids == 1
    bids_to_qualify = NUMBER_OF_BIDS_TO_BE_QUALIFIED \
        if (len(bids) > NUMBER_OF_BIDS_TO_BE_QUALIFIED) \
        else len(bids)
    for bid, status in izip_longest(bids[:bids_to_qualify],
                                    ['pending.verification'],
                                    fillvalue='pending.waiting'):
        bid = bid.serialize()
        award = type(auction).awards.model_class({
            '__parent__': request.context,
            'bid_id': bid['id'],
            'status': status,
            'date': now,
            'value': bid['value'],
            'suppliers': bid['tenderers'],
            'complaintPeriod': {
                'startDate': now
            }
        })
        if bid['status'] == 'invalid':
            award.status = 'unsuccessful'
            award.complaintPeriod.endDate = now
        if award.status == 'pending.verification':
            award.verificationPeriod = award.paymentPeriod = award.signingPeriod = {
                'startDate': now
            }
            request.response.headers['Location'] = request.route_url(
                '{}:Auction Awards'.format(auction.procurementMethodType),
                auction_id=auction.id,
                award_id=award['id'])
        auction.awards.append(award)
def sorting_start_bids_by_amount(bids, features=None, reverse=True):
    """
    >>> from json import load
    >>> import os
    >>> data = load(open(os.path.join(os.path.dirname(__file__),
    ...                               'tests/data/tender_data.json')))
    >>> sorted_data = sorting_start_bids_by_amount(data['data']['bids'])
    >>> sorted_data[0]['value']['amount'] > sorted_data[1]['value']['amount']
    True

    >>> sorted_data = sorting_start_bids_by_amount(data['data']['bids'],
    ...                                            reverse=False)
    >>> sorted_data[0]['value']['amount'] < sorted_data[1]['value']['amount']
    True

    """
    def get_amount(item):
        return item['value']['amount']

    # return sorted(bids, key=get_amount, reverse=reverse)
    return chef(bids, features=features)
def create_awards(request):
    auction = request.validated['auction']
    auction.status = 'active.qualification'
    now = get_now()
    auction.awardPeriod = type(auction).awardPeriod({'startDate': now})

    bids = chef(auction.bids, auction.features or [], [], True)

    for i, status in enumerate(['pending.verification', 'pending.waiting']):
        bid = bids[i].serialize()
        award = type(auction).awards.model_class({
            'bid_id': bid['id'],
            'status': status,
            'date': now,
            'value': bid['value'],
            'suppliers': bid['tenderers'],
            'complaintPeriod': {
                'startDate': now
            }
        })
        if bid['status'] == 'invalid':
            award.status = 'unsuccessful'
            award.complaintPeriod.endDate = now
        if award.status == 'pending.verification':
            award.verificationPeriod = {'startDate': now}
            award.verificationPeriod.endDate = calculate_business_date(
                now, VERIFY_AUCTION_PROTOCOL_TIME, auction, True)
            award.paymentPeriod = {'startDate': now}
            award.paymentPeriod.endDate = calculate_business_date(
                now, AWARD_PAYMENT_TIME, auction, True)
            award.signingPeriod = {'startDate': now}
            award.complaintPeriod.endDate = award.signingPeriod.endDate = calculate_business_date(
                now, CONTRACT_SIGNING_TIME, auction, True)
            request.response.headers['Location'] = request.route_url(
                '{}:Auction Awards'.format(auction.procurementMethodType),
                auction_id=auction.id,
                award_id=award['id'])
        auction.awards.append(award)
Exemple #12
0
def add_next_awards(request,
                    reverse=False,
                    awarding_criteria_key="amount",
                    regenerate_all_awards=False,
                    lot_id=None):
    """Adding next award.
    :param request:
        The pyramid request object.
    :param reverse:
        Is used for sorting bids to generate award.
        By default (reverse = False) awards are generated from lower to higher by value.amount
        When reverse is set to True awards are generated from higher to lower by value.amount
    """
    tender = request.validated["tender"]
    max_awards = tender["maxAwardsCount"]
    now = get_now()
    if not tender.awardPeriod:
        tender.awardPeriod = type(tender).awardPeriod({})
    if not tender.awardPeriod.startDate:
        tender.awardPeriod.startDate = now
    if tender.lots:
        statuses = set()
        for lot in tender.lots:
            if lot.status != "active":
                continue
            lot_awards = [
                award for award in tender.awards if award.lotID == lot.id
            ]
            lot_awards_statuses = {
                award["status"]
                for award in tender.awards if award.lotID == lot.id
            }
            if lot_awards_statuses and lot_awards_statuses.issubset(
                {"pending", "active"}):
                statuses.union(lot_awards_statuses)
                continue

            all_bids = prepare_bids_for_awarding(tender,
                                                 tender.bids,
                                                 lot_id=lot.id)
            if not all_bids:
                lot.status = "unsuccessful"
                statuses.add("unsuccessful")
                continue

            selected_bids = exclude_unsuccessful_awarded_bids(tender,
                                                              all_bids,
                                                              lot_id=lot.id)

            if not regenerate_all_awards and lot.id == lot_id:
                # this block seems is supposed to cause the function append only one award
                # for a bid of the first (the only?) cancelled award
                cancelled_award_bid_ids = [
                    award.bid_id for award in lot_awards
                    if award.status == "cancelled"
                    and request.context.id == award.id
                ]
                if cancelled_award_bid_ids:
                    selected_bids = [
                        bid for bid in all_bids
                        if bid["id"] == cancelled_award_bid_ids[0]
                    ]

            if max_awards:  # limit awards
                selected_bids = selected_bids[:max_awards]

            active_award_bid_ids = {
                a.bid_id
                for a in lot_awards if a.status in ("active", "pending")
            }
            selected_bids = list(
                filter(lambda b: b["id"] not in active_award_bid_ids,
                       selected_bids))
            if selected_bids:
                for bid in selected_bids:
                    tender.append_award(bid, all_bids, lot_id=lot.id)
                statuses.add("pending")
            else:
                statuses.add("unsuccessful")
        if (statuses.difference({"unsuccessful", "active"})
                and any([i for i in tender.lots])):
            # logic for auction to switch status
            tender.awardPeriod.endDate = None
            tender.status = "active.qualification"
    else:  # pragma: no cover
        if not tender.awards or request.context.status in ("cancelled",
                                                           "unsuccessful"):
            codes = [i.code for i in tender.features or []]
            active_bids = [{
                "id":
                bid.id,
                "value":
                bid.value.serialize(),
                "tenderers":
                bid.tenderers,
                "parameters": [i for i in bid.parameters if i.code in codes],
                "date":
                bid.date,
            } for bid in tender.bids if bid.status == "active"]
            cancelled_awards = None
            if not regenerate_all_awards:
                cancelled_awards = [
                    award.bid_id for award in tender.awards
                    if award.status == "cancelled"
                    and request.context.id == award.id
                ]
            unsuccessful_awards = [
                i.bid_id for i in tender.awards if i.status == "unsuccessful"
            ]
            bids = chef(active_bids, tender.features or [],
                        unsuccessful_awards, reverse, awarding_criteria_key)
            bids = [bid for bid in bids if bid["id"] == cancelled_awards[0]
                    ] if cancelled_awards else bids
            bids = bids[:max_awards] if max_awards else bids
            active_awards = [
                a.bid_id for a in tender.awards
                if a.status in ("active", "pending")
            ]
            bids = [bid for bid in bids if bid["id"] not in active_awards]
            if bids:
                for bid in bids:
                    award = tender.__class__.awards.model_class({
                        "bid_id":
                        bid["id"],
                        "status":
                        "pending",
                        "date":
                        get_now(),
                        "value":
                        bid["value"],
                        "suppliers":
                        bid["tenderers"],
                    })
                    award.__parent__ = tender
                    tender.awards.append(award)
        if tender.awards[
                -1].status == "pending":  # logic for auction to switch status
            tender.awardPeriod.endDate = None
            tender.status = "active.qualification"
def add_next_award(request):
    auction = request.validated['auction']
    now = get_now()
    if not auction.awardPeriod:
        auction.awardPeriod = type(auction).awardPeriod({})
    if not auction.awardPeriod.startDate:
        auction.awardPeriod.startDate = now
    if auction.lots:
        statuses = set()
        for lot in auction.lots:
            if lot.status != 'active':
                continue
            lot_awards = [i for i in auction.awards if i.lotID == lot.id]
            if lot_awards and lot_awards[-1].status in ['pending', 'active']:
                statuses.add(lot_awards[-1].status if lot_awards else 'unsuccessful')
                continue
            lot_items = [i.id for i in auction.items if i.relatedLot == lot.id]
            features = [
                i
                for i in (auction.features or [])
                if i.featureOf == 'tenderer' or i.featureOf == 'lot' and i.relatedItem == lot.id or i.featureOf == 'item' and i.relatedItem in lot_items
            ]
            codes = [i.code for i in features]
            bids = [
                {
                    'id': bid.id,
                    'value': [i for i in bid.lotValues if lot.id == i.relatedLot][0].value,
                    'tenderers': bid.tenderers,
                    'parameters': [i for i in bid.parameters if i.code in codes],
                    'date': [i for i in bid.lotValues if lot.id == i.relatedLot][0].date
                }
                for bid in auction.bids
                if lot.id in [i.relatedLot for i in bid.lotValues]
            ]
            if not bids:
                lot.status = 'unsuccessful'
                statuses.add('unsuccessful')
                continue
            unsuccessful_awards = [i.bid_id for i in lot_awards if i.status == 'unsuccessful']
            bids = chef(bids, features, unsuccessful_awards, True)
            if bids:
                bid = bids[0]
                award = type(auction).awards.model_class({
                    'bid_id': bid['id'],
                    'lotID': lot.id,
                    'status': 'pending',
                    'value': bid['value'],
                    'date': get_now(),
                    'suppliers': bid['tenderers'],
                    'complaintPeriod': {
                        'startDate': now.isoformat()
                    }
                })
                auction.awards.append(award)
                request.response.headers['Location'] = request.route_url('{}:Auction Awards'.format(auction.procurementMethodType), auction_id=auction.id, award_id=award['id'])
                statuses.add('pending')
            else:
                statuses.add('unsuccessful')
        if statuses.difference(set(['unsuccessful', 'active'])):
            auction.awardPeriod.endDate = None
            auction.status = 'active.qualification'
        else:
            auction.awardPeriod.endDate = now
            auction.status = 'active.awarded'
    else:
        if not auction.awards or auction.awards[-1].status not in ['pending', 'active']:
            unsuccessful_awards = [i.bid_id for i in auction.awards if i.status == 'unsuccessful']
            bids = chef(auction.bids, auction.features or [], unsuccessful_awards, True)
            if bids:
                bid = bids[0].serialize()
                award = type(auction).awards.model_class({
                    'bid_id': bid['id'],
                    'status': 'pending',
                    'date': get_now(),
                    'value': bid['value'],
                    'suppliers': bid['tenderers'],
                    'complaintPeriod': {
                        'startDate': get_now().isoformat()
                    }
                })
                auction.awards.append(award)
                request.response.headers['Location'] = request.route_url('{}:Auction Awards'.format(auction.procurementMethodType), auction_id=auction.id, award_id=award['id'])
        if auction.awards[-1].status == 'pending':
            auction.awardPeriod.endDate = None
            auction.status = 'active.qualification'
        else:
            auction.awardPeriod.endDate = now
            auction.status = 'active.awarded'
def add_next_award(request):
    tender = request.validated["tender"]
    now = get_now()
    if not tender.awardPeriod:
        tender.awardPeriod = type(tender).awardPeriod({})
    if not tender.awardPeriod.startDate:
        tender.awardPeriod.startDate = now
    if tender.lots:
        statuses = set()
        for lot in tender.lots:
            if lot.status != "active":
                continue
            lot_awards = [i for i in tender.awards if i.lotID == lot.id]
            if lot_awards and lot_awards[-1].status in ["pending", "active"]:
                statuses.add(lot_awards[-1].status if lot_awards else "unsuccessful")
                continue
            lot_items = [i.id for i in tender.items if i.relatedLot == lot.id]
            features = [
                i
                for i in (tender.features or [])
                if i.featureOf == "tenderer"
                or i.featureOf == "lot"
                and i.relatedItem == lot.id
                or i.featureOf == "item"
                and i.relatedItem in lot_items
            ]
            codes = [i.code for i in features]
            bids = [
                {
                    "id": bid.id,
                    "value": [i for i in bid.lotValues if lot.id == i.relatedLot][0].value,
                    "tenderers": bid.tenderers,
                    "parameters": [i for i in bid.parameters if i.code in codes],
                    "date": [i for i in bid.lotValues if lot.id == i.relatedLot][0].date,
                }
                for bid in tender.bids
                if bid.status == "active"
                and lot.id in [i.relatedLot for i in bid.lotValues if getattr(i, "status", "active") == "active"]
            ]
            if not bids:
                lot.status = "unsuccessful"
                statuses.add("unsuccessful")
                continue
            unsuccessful_awards = [i.bid_id for i in lot_awards if i.status == "unsuccessful"]
            bids = chef(bids, features, unsuccessful_awards)
            if bids:
                bid = bids[0]
                award = tender.__class__.awards.model_class(
                    {
                        "bid_id": bid["id"],
                        "lotID": lot.id,
                        "status": "pending",
                        "date": get_now(),
                        "value": bid["value"],
                        "suppliers": bid["tenderers"],
                        "complaintPeriod": {"startDate": now.isoformat()},
                    }
                )
                tender.awards.append(award)
                request.response.headers["Location"] = request.route_url(
                    "Tender Awards", tender_id=tender.id, award_id=award["id"]
                )
                statuses.add("pending")
            else:
                statuses.add("unsuccessful")
        if statuses.difference(set(["unsuccessful", "active"])):
            tender.awardPeriod.endDate = None
            tender.status = "active.qualification"
        else:
            tender.awardPeriod.endDate = now
            tender.status = "active.awarded"
    else:
        if not tender.awards or tender.awards[-1].status not in ["pending", "active"]:
            unsuccessful_awards = [i.bid_id for i in tender.awards if i.status == "unsuccessful"]
            active_bids = [bid for bid in tender.bids if bid.status == "active"]
            bids = chef(active_bids, tender.features or [], unsuccessful_awards)
            if bids:
                bid = bids[0].serialize()
                award = tender.__class__.awards.model_class(
                    {
                        "bid_id": bid["id"],
                        "status": "pending",
                        "date": get_now(),
                        "value": bid["value"],
                        "suppliers": bid["tenderers"],
                        "complaintPeriod": {"startDate": get_now().isoformat()},
                    }
                )
                tender.awards.append(award)
                request.response.headers["Location"] = request.route_url(
                    "Tender Awards", tender_id=tender.id, award_id=award["id"]
                )
        if tender.awards[-1].status == "pending":
            tender.awardPeriod.endDate = None
            tender.status = "active.qualification"
        else:
            tender.awardPeriod.endDate = now
            tender.status = "active.awarded"
def add_next_award(request):
    tender = request.validated['tender']
    now = get_now()
    if not tender.awardPeriod:
        tender.awardPeriod = Period({})
    if not tender.awardPeriod.startDate:
        tender.awardPeriod.startDate = now
    if tender.lots:
        statuses = set()
        for lot in tender.lots:
            if lot.status != 'active':
                continue
            lot_awards = [i for i in tender.awards if i.lotID == lot.id]
            if lot_awards and lot_awards[-1].status in ['pending', 'active']:
                statuses.add(lot_awards[-1].status if lot_awards else 'unsuccessful')
                continue
            lot_items = [i.id for i in tender.items if i.relatedLot == lot.id]
            features = [
                i
                for i in tender.features
                if i.featureOf == 'tenderer' or i.featureOf == 'lot' and i.relatedItem == lot.id or i.featureOf == 'item' and i.relatedItem in lot_items
            ]
            codes = [i.code for i in features]
            bids = [
                {
                    'id': bid.id,
                    'value': [i for i in bid.lotValues if lot.id == i.relatedLot][0].value,
                    'tenderers': bid.tenderers,
                    'parameters': [i for i in bid.parameters if i.code in codes],
                    'date': [i for i in bid.lotValues if lot.id == i.relatedLot][0].date
                }
                for bid in tender.bids
                if lot.id in [i.relatedLot for i in bid.lotValues]
            ]
            if not bids:
                lot.status = 'unsuccessful'
                statuses.add('unsuccessful')
                continue
            unsuccessful_awards = [i.bid_id for i in lot_awards if i.status == 'unsuccessful']
            bids = chef(bids, features, unsuccessful_awards)
            if bids:
                bid = bids[0]
                award = Award({
                    'bid_id': bid['id'],
                    'lotID': lot.id,
                    'status': 'pending',
                    'value': bid['value'],
                    'suppliers': bid['tenderers'],
                    'complaintPeriod': {
                        'startDate': now.isoformat()
                    }
                })
                tender.awards.append(award)
                request.response.headers['Location'] = request.route_url('Tender Awards', tender_id=tender.id, award_id=award['id'])
                statuses.add('pending')
            else:
                statuses.add('unsuccessful')
        if statuses.difference(set(['unsuccessful', 'active'])):
            tender.awardPeriod.endDate = None
            tender.status = 'active.qualification'
        else:
            tender.awardPeriod.endDate = now
            tender.status = 'active.awarded'
    else:
        if not tender.awards or tender.awards[-1].status not in ['pending', 'active']:
            unsuccessful_awards = [i.bid_id for i in tender.awards if i.status == 'unsuccessful']
            bids = chef(tender.bids, tender.features, unsuccessful_awards)
            if bids:
                bid = bids[0].serialize()
                award = Award({
                    'bid_id': bid['id'],
                    'status': 'pending',
                    'value': bid['value'],
                    'suppliers': bid['tenderers'],
                    'complaintPeriod': {
                        'startDate': get_now().isoformat()
                    }
                })
                tender.awards.append(award)
                request.response.headers['Location'] = request.route_url('Tender Awards', tender_id=tender.id, award_id=award['id'])
        if tender.awards[-1].status == 'pending':
            tender.awardPeriod.endDate = None
            tender.status = 'active.qualification'
        else:
            tender.awardPeriod.endDate = now
            tender.status = 'active.awarded'
def from0to1(registry):
    class Request(object):
        def __init__(self, registry):
            self.registry = registry

    results = registry.db.iterview('auctions/all', 2**10, include_docs=True)

    request = Request(registry)
    root = Root(request)

    docs = []
    for i in results:
        auction = i.doc
        if auction['procurementMethodType'] not in ['dgfOtherAssets', 'dgfFinancialAssets'] \
                or auction['status'] not in ['active.qualification', 'active.awarded'] \
                or 'awards' not in auction:
            continue

        now = get_now().isoformat()
        awards = auction["awards"]
        unique_awards = len(set([a['bid_id'] for a in awards]))

        if unique_awards > 2:
            switch_auction_to_unsuccessful(auction)
        else:
            invalidate_bids_under_threshold(auction)
            if all(bid['status'] == 'invalid' for bid in auction['bids']):
                switch_auction_to_unsuccessful(auction)

        if auction['status'] != 'unsuccessful':
            award = [
                a for a in auction["awards"]
                if a['status'] in ['active', 'pending']
            ][0]

            award_create_date = award['complaintPeriod']['startDate']

            periods = {
                'verificationPeriod': {
                    'startDate': award_create_date,
                    'endDate': award_create_date
                },
                'paymentPeriod': {
                    'startDate':
                    award_create_date,
                    'endDate':
                    calculate_business_date(parse_date(award_create_date,
                                                       TZ), AWARD_PAYMENT_TIME,
                                            auction, True).isoformat()
                },
                'signingPeriod': {
                    'startDate':
                    award_create_date,
                    'endDate':
                    calculate_business_date(parse_date(award_create_date, TZ),
                                            CONTRACT_SIGNING_TIME, auction,
                                            True).isoformat()
                }
            }

            award.update(periods)

            if award['status'] == 'pending':
                award['status'] = 'pending.payment'

            elif award['status'] == 'active':
                award['verificationPeriod']['endDate'] = award[
                    'paymentPeriod']['endDate'] = now

            if unique_awards == 1:
                bid = chef(auction['bids'], auction.get('features'), [],
                           True)[1]

                award = {
                    'id': uuid4().hex,
                    'bid_id': bid['id'],
                    'status': 'pending.waiting',
                    'date': awards[0]['date'],
                    'value': bid['value'],
                    'suppliers': bid['tenderers'],
                    'complaintPeriod': {
                        'startDate': awards[0]['date']
                    }
                }
                if bid['status'] == 'invalid':
                    award['status'] == 'unsuccessful'
                    award['complaintPeriod']['endDate'] = now

                awards.append(award)

        model = registry.auction_procurementMethodTypes.get(
            auction['procurementMethodType'])
        if model:
            try:
                auction = model(auction)
                auction.__parent__ = root
                auction = auction.to_primitive()
            except:
                LOGGER.error(
                    "Failed migration of auction {} to schema 1.".format(
                        auction.id),
                    extra={
                        'MESSAGE_ID': 'migrate_data_failed',
                        'AUCTION_ID': auction.id
                    })
            else:
                auction['dateModified'] = get_now().isoformat()
                docs.append(auction)
        if len(docs) >= 2**7:
            registry.db.update(docs)
            docs = []
    if docs:
        registry.db.update(docs)
Exemple #17
0
def add_next_award(request):
    tender = request.validated["tender"]
    now = get_now()
    if not tender.awardPeriod:
        tender.awardPeriod = type(tender).awardPeriod({})
    if not tender.awardPeriod.startDate:
        tender.awardPeriod.startDate = now
    if tender.lots:
        statuses = set()
        for lot in tender.lots:
            if lot.status != "active":
                continue
            lot_awards = [i for i in tender.awards if i.lotID == lot.id]
            if lot_awards and lot_awards[-1].status in ["pending", "active"]:
                statuses.add(
                    lot_awards[-1].status if lot_awards else "unsuccessful")
                continue
            lot_items = [i.id for i in tender.items if i.relatedLot == lot.id]
            features = [
                i for i in (tender.features or []) if i.featureOf == "tenderer"
                or i.featureOf == "lot" and i.relatedItem == lot.id
                or i.featureOf == "item" and i.relatedItem in lot_items
            ]
            codes = [i.code for i in features]
            bids = [{
                "id":
                bid.id,
                "value": [i for i in bid.lotValues
                          if lot.id == i.relatedLot][0].value,
                "tenderers":
                bid.tenderers,
                "parameters": [i for i in bid.parameters if i.code in codes],
                "date": [i for i in bid.lotValues
                         if lot.id == i.relatedLot][0].date,
            } for bid in tender.bids
                    if lot.id in [i.relatedLot for i in bid.lotValues]]
            if not bids:
                lot.status = "unsuccessful"
                statuses.add("unsuccessful")
                continue
            unsuccessful_awards = [
                i.bid_id for i in lot_awards if i.status == "unsuccessful"
            ]
            bids = chef(bids, features, unsuccessful_awards)
            if bids:
                bid = bids[0]
                award = type(tender).awards.model_class({
                    "bid_id":
                    bid["id"],
                    "lotID":
                    lot.id,
                    "status":
                    "pending",
                    "value":
                    bid["value"],
                    "date":
                    get_now(),
                    "suppliers":
                    bid["tenderers"],
                })
                tender.awards.append(award)
                request.response.headers["Location"] = request.route_url(
                    "{}:Tender Awards".format(tender.procurementMethodType),
                    tender_id=tender.id,
                    award_id=award["id"])
                statuses.add("pending")
            else:
                statuses.add("unsuccessful")
        if statuses.difference(set(["unsuccessful", "active"])):
            tender.awardPeriod.endDate = None
            tender.status = "active.qualification"
        else:
            tender.awardPeriod.endDate = now
            tender.status = "active.awarded"
    else:
        if not tender.awards or tender.awards[-1].status not in [
                "pending", "active"
        ]:
            unsuccessful_awards = [
                i.bid_id for i in tender.awards if i.status == "unsuccessful"
            ]
            bids = chef(tender.bids, tender.features or [],
                        unsuccessful_awards)
            if bids:
                bid = bids[0].serialize()
                award = type(tender).awards.model_class({
                    "bid_id":
                    bid["id"],
                    "status":
                    "pending",
                    "date":
                    get_now(),
                    "value":
                    bid["value"],
                    "suppliers":
                    bid["tenderers"],
                })
                tender.awards.append(award)
                request.response.headers["Location"] = request.route_url(
                    "{}:Tender Awards".format(tender.procurementMethodType),
                    tender_id=tender.id,
                    award_id=award["id"])
        if tender.awards[-1].status == "pending":
            tender.awardPeriod.endDate = None
            tender.status = "active.qualification"
        else:
            tender.awardPeriod.endDate = now
            tender.status = "active.awarded"
Exemple #18
0
def add_next_award(request, reverse=False, awarding_criteria_key="amount"):
    """Adding next award.
    :param request:
        The pyramid request object.
    :param reverse:
        Is used for sorting bids to generate award.
        By default (reverse = False) awards are generated from lower to higher by value.amount
        When reverse is set to True awards are generated from higher to lower by value.amount
    """
    tender = request.validated["tender"]
    now = get_now()
    if not tender.awardPeriod:
        tender.awardPeriod = type(tender).awardPeriod({})
    if not tender.awardPeriod.startDate:
        tender.awardPeriod.startDate = now
    if tender.lots:
        statuses = set()
        for lot in tender.lots:
            if lot.status != "active":
                continue
            lot_awards = [i for i in tender.awards if i.lotID == lot.id]
            if lot_awards and lot_awards[-1].status in ["pending", "active"]:
                statuses.add(lot_awards[-1].status if lot_awards else "unsuccessful")
                continue
            lot_items = [i.id for i in tender.items if i.relatedLot == lot.id]
            features = [
                i
                for i in (tender.features or [])
                if i.featureOf == "tenderer"
                or i.featureOf == "lot"
                and i.relatedItem == lot.id
                or i.featureOf == "item"
                and i.relatedItem in lot_items
            ]
            codes = [i.code for i in features]
            bids = [
                {
                    "id": bid.id,
                    "value": [i for i in bid.lotValues if lot.id == i.relatedLot][0].value.serialize(),
                    "tenderers": bid.tenderers,
                    "parameters": [i for i in bid.parameters if i.code in codes],
                    "date": [i for i in bid.lotValues if lot.id == i.relatedLot][0].date,
                }
                for bid in tender.bids
                if bid.status == "active"
                and lot.id in [i.relatedLot for i in bid.lotValues if getattr(i, "status", "active") == "active"]
            ]
            if not bids:
                lot.status = "unsuccessful"
                statuses.add("unsuccessful")
                continue
            unsuccessful_awards = [i.bid_id for i in lot_awards if i.status == "unsuccessful"]
            bids = chef(bids, features, unsuccessful_awards, reverse, awarding_criteria_key)
            if bids:
                bid = bids[0]
                award = tender.__class__.awards.model_class(
                    {
                        "bid_id": bid["id"],
                        "lotID": lot.id,
                        "status": "pending",
                        "date": get_now(),
                        "value": bid["value"],
                        "suppliers": bid["tenderers"],
                        "complaintPeriod": {"startDate": now.isoformat()},
                    }
                )
                award.__parent__ = tender
                tender.awards.append(award)
                request.response.headers["Location"] = request.route_url(
                    "{}:Tender Awards".format(tender.procurementMethodType), tender_id=tender.id, award_id=award["id"]
                )
                statuses.add("pending")
            else:
                statuses.add("unsuccessful")
        if statuses.difference(set(["unsuccessful", "active"])):
            tender.awardPeriod.endDate = None
            tender.status = "active.qualification"
        else:
            tender.awardPeriod.endDate = now
            tender.status = "active.awarded"
    else:
        if not tender.awards or tender.awards[-1].status not in ["pending", "active"]:
            unsuccessful_awards = [i.bid_id for i in tender.awards if i.status == "unsuccessful"]
            codes = [i.code for i in tender.features or []]
            active_bids = [
                {
                    "id": bid.id,
                    "value": bid.value.serialize(),
                    "tenderers": bid.tenderers,
                    "parameters": [i for i in bid.parameters if i.code in codes],
                    "date": bid.date,
                }
                for bid in tender.bids
                if bid.status == "active"
            ]
            bids = chef(active_bids, tender.features or [], unsuccessful_awards, reverse, awarding_criteria_key)
            if bids:
                bid = bids[0]
                award = tender.__class__.awards.model_class(
                    {
                        "bid_id": bid["id"],
                        "status": "pending",
                        "date": get_now(),
                        "value": bid["value"],
                        "suppliers": bid["tenderers"],
                        "complaintPeriod": {"startDate": get_now().isoformat()},
                    }
                )
                award.__parent__ = tender
                tender.awards.append(award)
                request.response.headers["Location"] = request.route_url(
                    "{}:Tender Awards".format(tender.procurementMethodType), tender_id=tender.id, award_id=award["id"]
                )
        if tender.awards[-1].status == "pending":
            tender.awardPeriod.endDate = None
            tender.status = "active.qualification"
        else:
            tender.awardPeriod.endDate = now
            tender.status = "active.awarded"
Exemple #19
0
def add_next_award(request):
    tender = request.validated['tender']
    now = get_now()
    if not tender.awardPeriod:
        tender.awardPeriod = type(tender).awardPeriod({})
    if not tender.awardPeriod.startDate:
        tender.awardPeriod.startDate = now
    if tender.lots:
        statuses = set()
        for lot in tender.lots:
            if lot.status != 'active':
                continue
            lot_awards = [i for i in tender.awards if i.lotID == lot.id]
            if lot_awards and lot_awards[-1].status in ['pending', 'active']:
                statuses.add(
                    lot_awards[-1].status if lot_awards else 'unsuccessful')
                continue
            lot_items = [i.id for i in tender.items if i.relatedLot == lot.id]
            features = [
                i for i in (tender.features or []) if i.featureOf == 'tenderer'
                or i.featureOf == 'lot' and i.relatedItem == lot.id
                or i.featureOf == 'item' and i.relatedItem in lot_items
            ]
            codes = [i.code for i in features]
            bids = [{
                'id':
                bid.id,
                'value': [i for i in bid.lotValues
                          if lot.id == i.relatedLot][0].value,
                'tenderers':
                bid.tenderers,
                'parameters': [i for i in bid.parameters if i.code in codes],
                'date': [i for i in bid.lotValues
                         if lot.id == i.relatedLot][0].date
            } for bid in tender.bids if bid.status == "active" and lot.id in [
                i.relatedLot for i in bid.lotValues
                if getattr(i, 'status', "active") == "active"
            ]]
            if not bids:
                lot.status = 'unsuccessful'
                statuses.add('unsuccessful')
                continue
            unsuccessful_awards = [
                i.bid_id for i in lot_awards if i.status == 'unsuccessful'
            ]
            bids = chef(bids, features, unsuccessful_awards)
            if bids:
                bid = bids[0]
                award = tender.__class__.awards.model_class({
                    'bid_id':
                    bid['id'],
                    'lotID':
                    lot.id,
                    'status':
                    'pending',
                    'date':
                    get_now(),
                    'value':
                    bid['value'],
                    'suppliers':
                    bid['tenderers'],
                    'complaintPeriod': {
                        'startDate': now.isoformat()
                    }
                })
                tender.awards.append(award)
                request.response.headers['Location'] = request.route_url(
                    'Tender Awards', tender_id=tender.id, award_id=award['id'])
                statuses.add('pending')
            else:
                statuses.add('unsuccessful')
        if statuses.difference(set(['unsuccessful', 'active'])):
            tender.awardPeriod.endDate = None
            tender.status = 'active.qualification'
        else:
            tender.awardPeriod.endDate = now
            tender.status = 'active.awarded'
    else:
        if not tender.awards or tender.awards[-1].status not in [
                'pending', 'active'
        ]:
            unsuccessful_awards = [
                i.bid_id for i in tender.awards if i.status == 'unsuccessful'
            ]
            active_bids = [
                bid for bid in tender.bids if bid.status == "active"
            ]
            bids = chef(active_bids, tender.features or [],
                        unsuccessful_awards)
            if bids:
                bid = bids[0].serialize()
                award = tender.__class__.awards.model_class({
                    'bid_id':
                    bid['id'],
                    'status':
                    'pending',
                    'date':
                    get_now(),
                    'value':
                    bid['value'],
                    'suppliers':
                    bid['tenderers'],
                    'complaintPeriod': {
                        'startDate': get_now().isoformat()
                    }
                })
                tender.awards.append(award)
                request.response.headers['Location'] = request.route_url(
                    'Tender Awards', tender_id=tender.id, award_id=award['id'])
        if tender.awards[-1].status == 'pending':
            tender.awardPeriod.endDate = None
            tender.status = 'active.qualification'
        else:
            tender.awardPeriod.endDate = now
            tender.status = 'active.awarded'
Exemple #20
0
def add_next_award(request):
    auction = request.validated['auction']
    awarding_type = request.content_configurator.awarding_type
    now = get_now()
    if not auction.awardPeriod:
        auction.awardPeriod = type(auction).awardPeriod({})
    if not auction.awardPeriod.startDate:
        auction.awardPeriod.startDate = now
    if auction.lots:
        statuses = set()
        for lot in auction.lots:
            if lot.status != 'active':
                continue
            lot_awards = [i for i in auction.awards if i.lotID == lot.id]
            if lot_awards and lot_awards[-1].status in ['pending', 'active']:
                statuses.add(
                    lot_awards[-1].status if lot_awards else 'unsuccessful')
                continue
            lot_items = [i.id for i in auction.items if i.relatedLot == lot.id]
            features = [
                i for i in (auction.features or [])
                if i.featureOf == 'tenderer'
                or i.featureOf == 'lot' and i.relatedItem == lot.id
                or i.featureOf == 'item' and i.relatedItem in lot_items
            ]
            codes = [i.code for i in features]
            bids = [{
                'id':
                bid.id,
                'value': [i for i in bid.lotValues
                          if lot.id == i.relatedLot][0].value,
                'tenderers':
                bid.tenderers,
                'parameters': [i for i in bid.parameters if i.code in codes],
                'date': [i for i in bid.lotValues
                         if lot.id == i.relatedLot][0].date
            } for bid in auction.bids
                    if lot.id in [i.relatedLot for i in bid.lotValues]]
            if not bids:
                lot.status = 'unsuccessful'
                statuses.add('unsuccessful')
                continue
            unsuccessful_awards = [
                i.bid_id for i in lot_awards if i.status == 'unsuccessful'
            ]
            bids = chef(bids, features, unsuccessful_awards, True)
            if bids:
                bid = bids[0]
                award = make_award(request,
                                   auction,
                                   bid,
                                   'pending',
                                   now,
                                   lot_id=lot.id,
                                   parent=None)
                auction.awards.append(award)
                add_award_route_url(request, auction, award, awarding_type)
                statuses.add('pending')
            else:
                statuses.add('unsuccessful')
        if statuses.difference(set(['unsuccessful', 'active'])):
            auction.awardPeriod.endDate = None
            auction.status = 'active.qualification'
        else:
            auction.awardPeriod.endDate = now
            auction.status = 'active.awarded'
    else:
        if not auction.awards or auction.awards[-1].status not in [
                'pending', 'active'
        ]:
            unsuccessful_awards = [
                i.bid_id for i in auction.awards if i.status == 'unsuccessful'
            ]
            bids = chef(auction.bids, auction.features or [],
                        unsuccessful_awards, True)
            if bids:
                bid = bids[0].serialize()
                award = make_award(request,
                                   auction,
                                   bid,
                                   'pending',
                                   now,
                                   parent=None)
                auction.awards.append(award)
                add_award_route_url(request, auction, award, awarding_type)
        if auction.awards[-1].status == 'pending':
            auction.awardPeriod.endDate = None
            auction.status = 'active.qualification'
        else:
            auction.awardPeriod.endDate = now
            auction.status = 'active.awarded'
def from0to1(registry):
    class Request(object):
        def __init__(self, registry):
            self.registry = registry

    results = registry.db.iterview('auctions/all', 2**10, include_docs=True)

    request = Request(registry)
    root = Root(request)

    docs = []
    for i in results:
        auction = i.doc
        if auction['procurementMethodType'] not in ['dgfOtherAssets', 'dgfFinancialAssets'] \
                or auction['status'] not in ['active.qualification', 'active.awarded'] \
                or 'awards' not in auction:
            continue

        now = get_now().isoformat()
        awards = auction["awards"]
        award = [a for a in awards if a['status'] in ['active', 'pending']][0]
        award_create_date = award['complaintPeriod']['startDate']
        award.update({
            'verificationPeriod': {
                'startDate': award_create_date,
                'endDate': award_create_date
            },
            'paymentPeriod': {
                'startDate': award_create_date,
            },
            'signingPeriod': {
                'startDate': award_create_date,
            }
        })

        if award['status'] == 'pending':
            award['status'] = 'pending.payment'

        elif award['status'] == 'active':
            award['paymentPeriod']['endDate'] = now

        awarded_bids = set([a['bid_id'] for a in awards])
        sorted_bids = chef(auction['bids'], auction.get('features'), [], True)
        filtered_bids = [
            bid for bid in sorted_bids if bid['id'] not in awarded_bids
        ]

        for bid in filtered_bids:
            award = {
                'id': uuid4().hex,
                'bid_id': bid['id'],
                'status': 'pending.waiting',
                'date': award_create_date,
                'value': bid['value'],
                'suppliers': bid['tenderers'],
                'complaintPeriod': {
                    'startDate': award_create_date
                }
            }
            awards.append(award)

        model = registry.auction_procurementMethodTypes.get(
            auction['procurementMethodType'])
        if model:
            try:
                auction = model(auction)
                auction.__parent__ = root
                auction = auction.to_primitive()
            except:  # pragma: no cover
                LOGGER.error(
                    "Failed migration of auction {} to schema 1.".format(
                        auction.id),
                    extra={
                        'MESSAGE_ID': 'migrate_data_failed',
                        'AUCTION_ID': auction.id
                    })
            else:
                auction['dateModified'] = get_now().isoformat()
                docs.append(auction)
        if len(docs) >= 2**7:  # pragma: no cover
            registry.db.update(docs)
            docs = []
    if docs:
        registry.db.update(docs)
Exemple #22
0
def add_next_awards(request,
                    reverse=False,
                    awarding_criteria_key='amount',
                    regenerate_all_awards=False,
                    lot_id=None):
    """Adding next award.
    :param request:
        The pyramid request object.
    :param reverse:
        Is used for sorting bids to generate award.
        By default (reverse = False) awards are generated from lower to higher by value.amount
        When reverse is set to True awards are generated from higher to lower by value.amount
    """
    tender = request.validated['tender']
    max_awards = tender['maxAwardsCount']
    now = get_now()
    if not tender.awardPeriod:
        tender.awardPeriod = type(tender).awardPeriod({})
    if not tender.awardPeriod.startDate:
        tender.awardPeriod.startDate = now
    if tender.lots:
        statuses = set()
        for lot in tender.lots:
            if lot.status != 'active':
                continue
            lot_awards = [
                award for award in tender.awards if award.lotID == lot.id
            ]
            lot_awards_statuses = [
                award['status'] for award in tender.awards
                if award.lotID == lot.id
            ]
            set_lot_awards_statuses = set(lot_awards_statuses)
            if lot_awards_statuses and set_lot_awards_statuses.issubset(
                {'pending', 'active'}):
                statuses.union(set_lot_awards_statuses)
                continue
            lot_items = [i.id for i in tender.items if i.relatedLot == lot.id]
            features = [
                i for i in (tender.features or []) if i.featureOf == 'tenderer'
                or i.featureOf == 'lot' and i.relatedItem == lot.id
                or i.featureOf == 'item' and i.relatedItem in lot_items
            ]
            codes = [i.code for i in features]
            bids = [{
                'id':
                bid.id,
                'value': [i for i in bid.lotValues
                          if lot.id == i.relatedLot][0].value.serialize(),
                'tenderers':
                bid.tenderers,
                'parameters': [i for i in bid.parameters if i.code in codes],
                'date': [i for i in bid.lotValues
                         if lot.id == i.relatedLot][0].date
            } for bid in tender.bids if bid.status == "active" and lot.id in [
                i.relatedLot for i in bid.lotValues
                if getattr(i, 'status', "active") == "active"
            ]]
            if not bids:
                lot.status = 'unsuccessful'
                statuses.add('unsuccessful')
                continue
            cancelled_awards = None
            if not regenerate_all_awards and lot.id == lot_id:
                cancelled_awards = [award.bid_id for award in lot_awards if \
                                    award.status == 'cancelled' and request.context.id == award.id]
            unsuccessful_awards = [
                i.bid_id for i in lot_awards if i.status == 'unsuccessful'
            ]
            bids = [bid for bid in bids if bid['id'] == cancelled_awards[0]
                    ] if cancelled_awards else bids
            bids = chef(bids, features, unsuccessful_awards, reverse,
                        awarding_criteria_key)

            bids = bids[:max_awards] if max_awards else bids
            active_awards = [
                a.bid_id for a in tender.awards
                if a.status in ('active', 'pending') and a.lotID == lot.id
            ]

            bids = [bid for bid in bids if bid['id'] not in active_awards]
            if bids:
                for bid in bids:
                    award = tender.__class__.awards.model_class({
                        'bid_id':
                        bid['id'],
                        'lotID':
                        lot.id,
                        'status':
                        'pending',
                        'date':
                        get_now(),
                        'value':
                        bid['value'],
                        'suppliers':
                        bid['tenderers']
                    })
                    award.__parent__ = tender
                    tender.awards.append(award)
                statuses.add('pending')
            else:
                statuses.add('unsuccessful')
        if statuses.difference(set(['unsuccessful', 'active'
                                    ])):  # logic for auction to switch status
            tender.awardPeriod.endDate = None
            tender.status = 'active.qualification'
    else:
        if not tender.awards or request.context.status in ('cancelled',
                                                           'unsuccessful'):
            codes = [i.code for i in tender.features or []]
            active_bids = [{
                'id':
                bid.id,
                'value':
                bid.value.serialize(),
                'tenderers':
                bid.tenderers,
                'parameters': [i for i in bid.parameters if i.code in codes],
                'date':
                bid.date
            } for bid in tender.bids if bid.status == "active"]
            cancelled_awards = None
            if not regenerate_all_awards:
                cancelled_awards = [award.bid_id for award in tender.awards if \
                                    award.status == 'cancelled' and request.context.id == award.id]
            unsuccessful_awards = [
                i.bid_id for i in tender.awards if i.status == 'unsuccessful'
            ]
            bids = chef(active_bids, tender.features or [],
                        unsuccessful_awards, reverse, awarding_criteria_key)
            bids = [bid for bid in bids if bid['id'] == cancelled_awards[0]
                    ] if cancelled_awards else bids
            bids = bids[:max_awards] if max_awards else bids
            active_awards = [
                a.bid_id for a in tender.awards
                if a.status in ('active', 'pending')
            ]
            bids = [bid for bid in bids if bid['id'] not in active_awards]
            if bids:
                for bid in bids:
                    award = tender.__class__.awards.model_class({
                        'bid_id':
                        bid['id'],
                        'status':
                        'pending',
                        'date':
                        get_now(),
                        'value':
                        bid['value'],
                        'suppliers':
                        bid['tenderers']
                    })
                    award.__parent__ = tender
                    tender.awards.append(award)
        if tender.awards[
                -1].status == 'pending':  # logic for auction to switch status
            tender.awardPeriod.endDate = None
            tender.status = 'active.qualification'
Exemple #23
0
def migrate_awarding_1_0_to_awarding_2_0(auction):
    if auction['procurementMethodType'] not in ['dgfOtherAssets', 'dgfFinancialAssets'] \
                or auction['status'] not in ['active.qualification', 'active.awarded'] \
                or 'awards' not in auction:
        return
    now = get_now().isoformat()
    awards = auction["awards"]
    unique_awards = len(set([a['bid_id'] for a in awards]))

    if unique_awards > 2:
        switch_auction_to_unsuccessful(auction)
    else:
        invalidate_bids_under_threshold(auction)
        award = [a for a in awards if a['status'] in ['active', 'pending']][0]
        for bid in auction['bids']:
            if bid['id'] == award['bid_id'] and bid['status'] == 'invalid':
                switch_auction_to_unsuccessful(auction)

    if auction['status'] != 'unsuccessful':
        award = [a for a in awards if a['status'] in ['active', 'pending']][0]

        award_create_date = award['complaintPeriod']['startDate']

        award.update({
            'verificationPeriod': {
                'startDate': award_create_date,
                'endDate': award_create_date
            },
            'paymentPeriod': {
                'startDate': award_create_date,
            },
            'signingPeriod': {
                'startDate': award_create_date,
            }
        })

        if award['status'] == 'pending':
            award['status'] = 'pending.payment'

        elif award['status'] == 'active':
            award['verificationPeriod']['endDate'] = award['paymentPeriod'][
                'endDate'] = now

        if unique_awards == 1:
            bid = chef(auction['bids'], auction.get('features'), [], True)[1]

            award = {
                'id': uuid4().hex,
                'bid_id': bid['id'],
                'status': 'pending.waiting',
                'date': awards[0]['date'],
                'value': bid['value'],
                'suppliers': bid['tenderers'],
                'complaintPeriod': {
                    'startDate': awards[0]['date']
                }
            }
            if bid['status'] == 'invalid':
                award['status'] = 'unsuccessful'
                award['complaintPeriod']['endDate'] = now

            awards.append(award)
Exemple #24
0
def add_next_awards(request,
                    reverse=False,
                    awarding_criteria_key="amount",
                    regenerate_all_awards=False,
                    lot_id=None):
    """Adding next award.
    :param request:
        The pyramid request object.
    :param reverse:
        Is used for sorting bids to generate award.
        By default (reverse = False) awards are generated from lower to higher by value.amount
        When reverse is set to True awards are generated from higher to lower by value.amount
    """
    tender = request.validated["tender"]
    max_awards = tender["maxAwardsCount"]
    now = get_now()
    if not tender.awardPeriod:
        tender.awardPeriod = type(tender).awardPeriod({})
    if not tender.awardPeriod.startDate:
        tender.awardPeriod.startDate = now
    if tender.lots:
        statuses = set()
        for lot in tender.lots:
            if lot.status != "active":
                continue
            lot_awards = [
                award for award in tender.awards if award.lotID == lot.id
            ]
            lot_awards_statuses = [
                award["status"] for award in tender.awards
                if award.lotID == lot.id
            ]
            set_lot_awards_statuses = set(lot_awards_statuses)
            if lot_awards_statuses and set_lot_awards_statuses.issubset(
                {"pending", "active"}):
                statuses.union(set_lot_awards_statuses)
                continue
            lot_items = [i.id for i in tender.items if i.relatedLot == lot.id]
            features = [
                i for i in (tender.features or []) if i.featureOf == "tenderer"
                or i.featureOf == "lot" and i.relatedItem == lot.id
                or i.featureOf == "item" and i.relatedItem in lot_items
            ]
            codes = [i.code for i in features]
            bids = [{
                "id":
                bid.id,
                "value": [i for i in bid.lotValues
                          if lot.id == i.relatedLot][0].value.serialize(),
                "tenderers":
                bid.tenderers,
                "parameters": [i for i in bid.parameters if i.code in codes],
                "date": [i for i in bid.lotValues
                         if lot.id == i.relatedLot][0].date,
            } for bid in tender.bids if bid.status == "active" and lot.id in [
                i.relatedLot for i in bid.lotValues
                if getattr(i, "status", "active") == "active"
            ]]
            if not bids:
                lot.status = "unsuccessful"
                statuses.add("unsuccessful")
                continue
            cancelled_awards = None
            if not regenerate_all_awards and lot.id == lot_id:
                cancelled_awards = [
                    award.bid_id for award in lot_awards
                    if award.status == "cancelled"
                    and request.context.id == award.id
                ]
            unsuccessful_awards = [
                i.bid_id for i in lot_awards if i.status == "unsuccessful"
            ]
            bids = [bid for bid in bids if bid["id"] == cancelled_awards[0]
                    ] if cancelled_awards else bids
            bids = chef(bids, features, unsuccessful_awards, reverse,
                        awarding_criteria_key)

            bids = bids[:max_awards] if max_awards else bids
            active_awards = [
                a.bid_id for a in tender.awards
                if a.status in ("active", "pending") and a.lotID == lot.id
            ]

            bids = [bid for bid in bids if bid["id"] not in active_awards]
            if bids:
                for bid in bids:
                    award = tender.__class__.awards.model_class({
                        "bid_id":
                        bid["id"],
                        "lotID":
                        lot.id,
                        "status":
                        "pending",
                        "date":
                        get_now(),
                        "value":
                        bid["value"],
                        "suppliers":
                        bid["tenderers"],
                    })
                    award.__parent__ = tender
                    tender.awards.append(award)
                statuses.add("pending")
            else:
                statuses.add("unsuccessful")
        if (statuses.difference(set(["unsuccessful", "active"]))
                and any([i for i in tender.lots])):
            # logic for auction to switch status
            tender.awardPeriod.endDate = None
            tender.status = "active.qualification"
    else:  # pragma: no cover
        if not tender.awards or request.context.status in ("cancelled",
                                                           "unsuccessful"):
            codes = [i.code for i in tender.features or []]
            active_bids = [{
                "id":
                bid.id,
                "value":
                bid.value.serialize(),
                "tenderers":
                bid.tenderers,
                "parameters": [i for i in bid.parameters if i.code in codes],
                "date":
                bid.date,
            } for bid in tender.bids if bid.status == "active"]
            cancelled_awards = None
            if not regenerate_all_awards:
                cancelled_awards = [
                    award.bid_id for award in tender.awards
                    if award.status == "cancelled"
                    and request.context.id == award.id
                ]
            unsuccessful_awards = [
                i.bid_id for i in tender.awards if i.status == "unsuccessful"
            ]
            bids = chef(active_bids, tender.features or [],
                        unsuccessful_awards, reverse, awarding_criteria_key)
            bids = [bid for bid in bids if bid["id"] == cancelled_awards[0]
                    ] if cancelled_awards else bids
            bids = bids[:max_awards] if max_awards else bids
            active_awards = [
                a.bid_id for a in tender.awards
                if a.status in ("active", "pending")
            ]
            bids = [bid for bid in bids if bid["id"] not in active_awards]
            if bids:
                for bid in bids:
                    award = tender.__class__.awards.model_class({
                        "bid_id":
                        bid["id"],
                        "status":
                        "pending",
                        "date":
                        get_now(),
                        "value":
                        bid["value"],
                        "suppliers":
                        bid["tenderers"],
                    })
                    award.__parent__ = tender
                    tender.awards.append(award)
        if tender.awards[
                -1].status == "pending":  # logic for auction to switch status
            tender.awardPeriod.endDate = None
            tender.status = "active.qualification"
def add_next_award(request, reverse=False, awarding_criteria_key='amount'):
    """Adding next award.
    :param request:
        The pyramid request object.
    :param reverse:
        Is used for sorting bids to generate award.
        By default (reverse = False) awards are generated from lower to higher by value.amount
        When reverse is set to True awards are generated from higher to lower by value.amount
    """
    tender = request.validated['tender']
    now = get_now()
    if not tender.awardPeriod:
        tender.awardPeriod = type(tender).awardPeriod({})
    if not tender.awardPeriod.startDate:
        tender.awardPeriod.startDate = now
    if tender.lots:
        statuses = set()
        for lot in tender.lots:
            if lot.status != 'active':
                continue
            lot_awards = [i for i in tender.awards if i.lotID == lot.id]
            if lot_awards and lot_awards[-1].status in ['pending', 'active']:
                statuses.add(lot_awards[-1].status if lot_awards else 'unsuccessful')
                continue
            lot_items = [i.id for i in tender.items if i.relatedLot == lot.id]
            features = [
                i
                for i in (tender.features or [])
                if i.featureOf == 'tenderer' or i.featureOf == 'lot' and i.relatedItem == lot.id or i.featureOf == 'item' and i.relatedItem in lot_items
            ]
            codes = [i.code for i in features]
            bids = [
                {
                    'id': bid.id,
                    'value': [i for i in bid.lotValues if lot.id == i.relatedLot][0].value.serialize(),
                    'tenderers': bid.tenderers,
                    'parameters': [i for i in bid.parameters if i.code in codes],
                    'date': [i for i in bid.lotValues if lot.id == i.relatedLot][0].date
                }
                for bid in tender.bids
                if bid.status == "active" and lot.id in [i.relatedLot for i in bid.lotValues if getattr(i, 'status', "active") == "active"]
            ]
            if not bids:
                lot.status = 'unsuccessful'
                statuses.add('unsuccessful')
                continue
            unsuccessful_awards = [i.bid_id for i in lot_awards if i.status == 'unsuccessful']
            bids = chef(bids, features, unsuccessful_awards, reverse, awarding_criteria_key)
            if bids:
                bid = bids[0]
                award = tender.__class__.awards.model_class({
                    'bid_id': bid['id'],
                    'lotID': lot.id,
                    'status': 'pending',
                    'date': get_now(),
                    'value': bid['value'],
                    'suppliers': bid['tenderers'],
                    'complaintPeriod': {
                        'startDate': now.isoformat()
                    }
                })
                award.__parent__ = tender
                tender.awards.append(award)
                request.response.headers['Location'] = request.route_url('{}:Tender Awards'.format(tender.procurementMethodType), tender_id=tender.id, award_id=award['id'])
                statuses.add('pending')
            else:
                statuses.add('unsuccessful')
        if statuses.difference(set(['unsuccessful', 'active'])):
            tender.awardPeriod.endDate = None
            tender.status = 'active.qualification'
        else:
            tender.awardPeriod.endDate = now
            tender.status = 'active.awarded'
    else:
        if not tender.awards or tender.awards[-1].status not in ['pending', 'active']:
            unsuccessful_awards = [i.bid_id for i in tender.awards if i.status == 'unsuccessful']
            codes = [i.code for i in tender.features or []]
            active_bids = [
                {
                    'id': bid.id,
                    'value': bid.value.serialize(),
                    'tenderers': bid.tenderers,
                    'parameters': [i for i in bid.parameters if i.code in codes],
                    'date': bid.date
                }
                for bid in tender.bids
                if bid.status == "active"
            ]
            bids = chef(active_bids, tender.features or [], unsuccessful_awards, reverse, awarding_criteria_key)
            if bids:
                bid = bids[0]
                award = tender.__class__.awards.model_class({
                    'bid_id': bid['id'],
                    'status': 'pending',
                    'date': get_now(),
                    'value': bid['value'],
                    'suppliers': bid['tenderers'],
                    'complaintPeriod': {
                        'startDate': get_now().isoformat()
                    }
                })
                award.__parent__ = tender
                tender.awards.append(award)
                request.response.headers['Location'] = request.route_url('{}:Tender Awards'.format(tender.procurementMethodType), tender_id=tender.id, award_id=award['id'])
        if tender.awards[-1].status == 'pending':
            tender.awardPeriod.endDate = None
            tender.status = 'active.qualification'
        else:
            tender.awardPeriod.endDate = now
            tender.status = 'active.awarded'