def date_signed_on_change_creation(self):
    # test create change with date signed
    one_day_in_past = (get_now() - timedelta(days=1)).isoformat()

    response = self.app.post_json('/contracts/{}/changes?acc_token={}'.format(self.contract['id'], self.contract_token),
                                  {'data': {'rationale': u'причина зміни укр', 'rationale_en': u'change cause en',
                                            'dateSigned': one_day_in_past,
                                            'rationaleTypes': ['priceReduction'], 'contractNumber': u'№ 146'}}, status=403)
    self.assertIn("can't be earlier than contract dateSigned", response.json['errors'][0]["description"])

    one_day_in_future = (get_now() + timedelta(days=1)).isoformat()
    response = self.app.post_json('/contracts/{}/changes?acc_token={}'.format(self.contract['id'], self.contract_token),
                                  {'data': {'rationale': u'причина зміни укр', 'rationale_en': u'change cause en',
                                            'dateSigned': one_day_in_future,
                                            'rationaleTypes': ['priceReduction'], 'contractNumber': u'№ 146'}}, status=422)
    self.assertEqual(response.json['errors'], [
        {"location": "body", "name": "dateSigned", "description": [u"Contract signature date can't be in the future"]}
    ])

    date = get_now().isoformat()
    response = self.app.post_json('/contracts/{}/changes?acc_token={}'.format(self.contract['id'], self.contract_token),
                                  {'data': {'rationale': u'причина зміни укр', 'rationale_en': u'change cause en',
                                            'dateSigned': date,
                                            'rationaleTypes': ['priceReduction'], 'contractNumber': u'№ 146'}})
    self.assertEqual(response.status, '201 Created')
    self.assertEqual(response.content_type, 'application/json')
    change = response.json['data']
    self.assertEqual(change['dateSigned'], date)

    response = self.app.patch_json('/contracts/{}/changes/{}?acc_token={}'.format(self.contract['id'], change['id'], self.contract_token),
                                   {'data': {'status': 'active'}})
    self.assertEqual(response.status, '200 OK')
    def test_migrate_from0to1(self):
        set_db_schema_version(self.db, 0)

        with open(os.path.join(os.path.dirname(__file__), 'data/tender-contract-complete.json'), 'r') as df:
            data = json.loads(df.read())

        t = Tender(data)
        t.store(self.db)
        tender = self.db.get(t.id)

        self.assertEqual(tender['awards'][0]['value'], data['awards'][0]['value'])
        self.assertEqual(tender['awards'][0]['suppliers'], data['awards'][0]['suppliers'])

        contract_data = deepcopy(tender['contracts'][0])
        del contract_data['value']
        del contract_data['suppliers']
        contract_data['tender_id'] = tender['_id']
        contract_data['tender_token'] = 'xxx'
        contract_data['procuringEntity'] = tender['procuringEntity']

        contract = Contract(contract_data)
        contract.dateModified = get_now()
        contract.store(self.db)
        contract_data = self.db.get(contract.id)
        self.assertNotIn("value", contract_data)
        self.assertNotIn("suppliers", contract_data)

        migrate_data(self.app.app.registry, 2)
        migrated_item = self.db.get(contract.id)

        self.assertIn("value", migrated_item)
        self.assertEqual(migrated_item['value'], tender['awards'][0]['value'])
        self.assertIn("suppliers", migrated_item)
        self.assertEqual(migrated_item['suppliers'], tender['awards'][0]['suppliers'])
 def collection_post(self):
     """Post a complaint
     """
     tender = self.context
     complaint = self.request.validated['complaint']
     if complaint.status == 'claim':
         validate_submit_claim_time(self.request)
     elif complaint.status == 'pending':
         validate_submit_complaint_time(self.request)
         complaint.dateSubmitted = get_now()
         complaint.type = 'complaint'
     else:
         complaint.status = 'draft'
     complaint.complaintID = '{}.{}{}'.format(tender.tenderID, self.server_id, self.complaints_len(tender) + 1)
     set_ownership(complaint, self.request)
     tender.complaints.append(complaint)
     if save_tender(self.request):
         self.LOGGER.info('Created tender complaint {}'.format(complaint.id),
                     extra=context_unpack(self.request, {'MESSAGE_ID': 'tender_complaint_create'}, {'complaint_id': complaint.id}))
         self.request.response.status = 201
         self.request.response.headers['Location'] = self.request.route_url('{}:Tender Complaints'.format(tender.procurementMethodType), tender_id=tender.id, complaint_id=complaint.id)
         return {
             'data': complaint.serialize(tender.status),
             'access': {
                 'token': complaint.owner_token
             }
         }
 def collection_post(self):
     """Post a cancellation
     """
     auction = self.request.validated['auction']
     if auction.status in ['complete', 'cancelled', 'unsuccessful']:
         self.request.errors.add('body', 'data', 'Can\'t add cancellation in current ({}) auction status'.format(auction.status))
         self.request.errors.status = 403
         return
     cancellation = self.request.validated['cancellation']
     cancellation.date = get_now()
     if any([i.status != 'active' for i in auction.lots if i.id == cancellation.relatedLot]):
         self.request.errors.add('body', 'data', 'Can add cancellation only in active lot status')
         self.request.errors.status = 403
         return
     if cancellation.relatedLot and cancellation.status == 'active':
         self.cancel_lot(cancellation)
     elif cancellation.status == 'active':
         self.cancel_auction()
     auction.cancellations.append(cancellation)
     if save_auction(self.request):
         self.LOGGER.info('Created auction cancellation {}'.format(cancellation.id),
                     extra=context_unpack(self.request, {'MESSAGE_ID': 'auction_cancellation_create'}, {'cancellation_id': cancellation.id}))
         self.request.response.status = 201
         route = self.request.matched_route.name.replace("collection_", "")
         self.request.response.headers['Location'] = self.request.current_route_url(_route_name=route, cancellation_id=cancellation.id, _query={})
         return {'data': cancellation.serialize("view")}
def from0to1(registry):
    LOGGER.info("Start contracts migration.", extra={'MESSAGE_ID': 'migrate_data'})
    results = registry.db.iterview('contracts/all', 2 ** 10, include_docs=True)
    docs = []
    for i in results:
        doc = i.doc

        if "suppliers" not in doc:
            tender_id = doc['tender_id']
            rel_award = doc['awardID']
            tender_doc = registry.db.get(tender_id)

            rel_award = [aw for aw in tender_doc['awards'] if aw['id'] == doc['awardID']]
            if not rel_award:
                LOGGER.warn("Related award {} for contract {} not found!".format(doc['awardID'], doc['id']), extra={'MESSAGE_ID': 'migrate_data'})
                continue
            rel_award = rel_award[0]

            doc['suppliers'] = rel_award['suppliers']
            if "value" not in doc:
                doc['value'] = rel_award['value']

            doc['dateModified'] = get_now().isoformat()

            docs.append(doc)
        if len(docs) >= 2 ** 7:
            registry.db.update(docs)
            docs = []
    if docs:
        registry.db.update(docs)
    LOGGER.info("Contracts migration is finished.", extra={'MESSAGE_ID': 'migrate_data'})
def check_status(request):
    tender = request.validated['tender']
    now = get_now()

    if tender.status == 'active.tendering' and tender.tenderPeriod.endDate <= now and \
            not has_unanswered_complaints(tender) and not has_unanswered_questions(tender):
        for complaint in tender.complaints:
            check_complaint_status(request, complaint)
        LOGGER.info('Switched tender {} to {}'.format(tender['id'], 'active.pre-qualification'),
                    extra=context_unpack(request, {'MESSAGE_ID': 'switched_tender_active.pre-qualification'}))
        tender.status = 'active.pre-qualification'
        tender.qualificationPeriod = type(tender).qualificationPeriod({'startDate': now})
        check_initial_bids_count(request)
        prepare_qualifications(request)
        return

    elif tender.status == 'active.pre-qualification.stand-still' and tender.qualificationPeriod and tender.qualificationPeriod.endDate <= now and not any([
        i.status in tender.block_complaint_status
        for q in tender.qualifications
        for i in q.complaints
    ]):
        LOGGER.info('Switched tender {} to {}'.format(tender['id'], 'active.stage2.pending'),
                    extra=context_unpack(request, {'MESSAGE_ID': 'switched_tender_active_stage2_pending'}))
        tender.status = 'active.stage2.pending'
        check_initial_bids_count(request)
        return
def no_items_contract_change(self):
    data = deepcopy(self.initial_data)
    del data['items']
    response = self.app.post_json('/contracts', {"data": data})
    self.assertEqual(response.status, '201 Created')
    self.assertEqual(response.content_type, 'application/json')
    contract = response.json['data']
    self.assertEqual(contract['status'], 'active')
    self.assertNotIn('items', contract)
    tender_token = data['tender_token']

    response = self.app.patch_json('/contracts/{}/credentials?acc_token={}'.format(contract['id'], tender_token),
                                   {'data': ''})
    self.assertEqual(response.status, '200 OK')
    token = response.json['access']['token']

    response = self.app.post_json('/contracts/{}/changes?acc_token={}'.format(contract['id'], token),
                                  {'data': {'rationale': u'причина зміни укр',
                                            'rationaleTypes': ['qualityImprovement']}})
    self.assertEqual(response.status, '201 Created')
    change = response.json['data']
    self.assertEqual(change['status'], 'pending')

    response = self.app.patch_json('/contracts/{}/changes/{}?acc_token={}'.format(contract['id'], change['id'], token),
                                   {'data': {'status': 'active', 'dateSigned': get_now().isoformat()}})
    self.assertEqual(response.status, '200 OK')
    self.assertEqual(response.json['data']['status'], 'active')

    response = self.app.patch_json('/contracts/{}?acc_token={}'.format(contract['id'], token),
                                   {"data": {"status": "terminated", "amountPaid": {"amount": 100, "valueAddedTaxIncluded": True, "currency": "UAH"}}})
    self.assertEqual(response.status, '200 OK')
    self.assertEqual(response.json['data']['status'], 'terminated')

    response = self.app.get('/contracts/{}'.format(contract['id']))
    self.assertNotIn('items', response.json['data'])
def date_signed_on_change_creation_for_very_old_contracts_data(self):
    # prepare old contract data
    contract = self.db.get(self.contract['id'])
    contract['dateSigned'] = None
    self.db.save(contract)

    response = self.app.get('/contracts/{}?acc_token={}'.format(self.contract['id'], self.contract_token))
    self.assertEqual(response.status, '200 OK')
    self.assertNotIn('dateSigned', response.json['data'])

    self.app.authorization = ('Basic', ('broker', ''))
    one_day_in_past = (get_now() - timedelta(days=1)).isoformat()
    response = self.app.post_json('/contracts/{}/changes?acc_token={}'.format(self.contract['id'], self.contract_token),
                                  {'data': {'rationale': u'причина зміни укр', 'rationale_en': u'change cause en',
                                            'rationaleTypes': ['priceReduction'], 'contractNumber': u'№ 146',
                                            'dateSigned': one_day_in_past}})
    self.assertEqual(response.json['data']['dateSigned'], one_day_in_past)
    change = response.json['data']
    response = self.app.patch_json('/contracts/{}/changes/{}?acc_token={}'.format(self.contract['id'], change['id'], self.contract_token),
                                   {'data': {'status': 'active'}})
    self.assertEqual(response.json['data']['status'], 'active')

    # prepare old contract change data
    contract = self.db.get(self.contract['id'])
    last_change = contract['changes'][-1]
    last_change['dateSigned'] = None
    self.db.save(contract)

    response = self.app.get('/contracts/{}/changes/{}?acc_token={}'.format(self.contract['id'], last_change['id'], self.contract_token))
    self.assertEqual(response.status, '200 OK')
    self.assertNotIn('dateSigned', response.json['data'])

    response = self.app.post_json('/contracts/{}/changes?acc_token={}'.format(self.contract['id'], self.contract_token),
                                  {'data': {'rationale': u'третя причина зміни укр', 'rationale_en': u'third change cause en',
                                            'rationaleTypes': ['priceReduction'], 'contractNumber': u'№ 148',
                                            'dateSigned': one_day_in_past}}, status=403)
    self.assertEqual("Change dateSigned ({}) can't be earlier than last active change dateSigned ({})".format(one_day_in_past, last_change['date']), response.json['errors'][0]["description"])


    valid_date = get_now().isoformat()
    response = self.app.post_json('/contracts/{}/changes?acc_token={}'.format(self.contract['id'], self.contract_token),
                                  {'data': {'rationale': u'третя причина зміни укр', 'rationale_en': u'third change cause en',
                                            'rationaleTypes': ['priceReduction'], 'contractNumber': u'№ 148',
                                            'dateSigned': valid_date}})
    self.assertEqual(response.json['data']['dateSigned'], valid_date)
 def go_to_enquiryPeriod_end(self):
     now = get_now()
     self.set_status('active.tendering', {
         "enquiryPeriod": {
             "startDate": (now - timedelta(days=28)).isoformat(),
             "endDate": (now - (timedelta(minutes=1) if SANDBOX_MODE else timedelta(days=1))).isoformat()
         },
         "tenderPeriod": {
             "startDate": (now - timedelta(days=28)).isoformat(),
             "endDate": (now + (timedelta(minutes=2) if SANDBOX_MODE else timedelta(days=2))).isoformat()
         }
     })
Ejemplo n.º 10
0
    def patch(self):
        """ Contract change edit """
        change = self.request.validated['change']
        data = self.request.validated['data']
        if 'status' in data and data['status'] != change.status:  # status change

            if data['status'] != 'active':
                self.request.errors.add('body', 'data', 'Can\'t update contract change in current ({}) status'.format(change.status))
                self.request.errors.status = 403
                return
            change['date'] = get_now()

        if apply_patch(self.request, src=change.serialize()):
            self.LOGGER.info('Updated contract change {}'.format(change.id),
                            extra=context_unpack(self.request, {'MESSAGE_ID': 'contract_change_patch'}))
            return {'data': change.serialize('view')}
Ejemplo n.º 11
0
 def collection_post(self):
     """Add a lot
     """
     auction = self.request.validated['auction']
     if auction.status not in ['active.enquiries']:
         self.request.errors.add('body', 'data', 'Can\'t add lot in current ({}) auction status'.format(auction.status))
         self.request.errors.status = 403
         return
     lot = self.request.validated['lot']
     lot.date = get_now()
     auction.lots.append(lot)
     if save_auction(self.request):
         self.LOGGER.info('Created auction lot {}'.format(lot.id),
                     extra=context_unpack(self.request, {'MESSAGE_ID': 'auction_lot_create'}, {'lot_id': lot.id}))
         self.request.response.status = 201
         self.request.response.headers['Location'] = self.request.route_url('Auction Lots', auction_id=auction.id, lot_id=lot.id)
         return {'data': lot.serialize("view")}
Ejemplo n.º 12
0
def add_logging_context(event):
    request = event.request
    params = {
        'API_VERSION': request.registry.settings.get('api_version', VERSION),
        'TAGS': 'python,api',
        'USER': str(request.authenticated_userid or ''),
        'CURRENT_URL': request.url,
        'CURRENT_PATH': request.path_info,
        'REMOTE_ADDR': request.remote_addr or '',
        'USER_AGENT': request.user_agent or '',
        'REQUEST_METHOD': request.method,
        'TIMESTAMP': get_now().isoformat(),
        'REQUEST_ID': request.environ.get('REQUEST_ID', ''),
        'CLIENT_REQUEST_ID': request.headers.get('X-Client-Request-ID', ''),
    }

    request.logging_context = params
 def collection_post(self):
     """Add a lot
     """
     if not self.validate_update_tender('add'):
         return
     lot = self.request.validated['lot']
     lot.date = get_now()
     tender = self.request.validated['tender']
     tender.lots.append(lot)
     if save_tender(self.request):
         self.LOGGER.info('Created tender lot {}'.format(lot.id),
                          extra=context_unpack(self.request, {'MESSAGE_ID': 'tender_lot_create'},
                                               {'lot_id': lot.id}))
         self.request.response.status = 201
         self.request.response.headers['Location'] = self.request.route_url(self.route_name,
                                                                            tender_id=tender.id, lot_id=lot.id)
         return {'data': lot.serialize("view")}
 def shouldStartAfter(self):
     if self.endDate:
         return
     tender = get_tender(self)
     lot = self.__parent__
     if tender.status not in ['active.tendering', 'active.auction'] or lot.status != 'active':
         return
     if tender.status == 'active.auction' and lot.numberOfBids < 2:
         return
     if self.startDate and get_now() > calc_auction_end_time(lot.numberOfBids, self.startDate):
         return calc_auction_end_time(lot.numberOfBids, self.startDate).isoformat()
     else:
         decision_dates = [
             datetime.combine(complaint.dateDecision.date() + timedelta(days=3), time(0, tzinfo=complaint.dateDecision.tzinfo))
             for complaint in tender.complaints
             if complaint.dateDecision
         ]
         decision_dates.append(tender.tenderPeriod.endDate)
         return max(decision_dates).isoformat()
def create_change(self):
    response = self.app.post_json('/contracts/{}/changes?acc_token={}'.format(self.contract['id'], self.contract_token),
                                  {'data': {'rationale': u'причина зміни укр',
                                            'rationale_en': 'change cause en',
                                            'rationaleTypes': ['qualityImprovement']}})
    self.assertEqual(response.status, '201 Created')
    self.assertEqual(response.content_type, 'application/json')
    change = response.json['data']
    self.assertEqual(change['status'], 'pending')
    self.assertIn('date', change)

    response = self.app.get('/contracts/{}/changes'.format(self.contract['id']))
    self.assertEqual(response.status, '200 OK')
    self.assertEqual(len(response.json['data']), 1)

    response = self.app.post_json('/contracts/{}/changes?acc_token={}'.format(self.contract['id'], self.contract_token),
                                  {'data': {'rationale': u'трататата', 'rationaleTypes': ['priceReduction']}}, status=403)
    self.assertEqual(response.status, '403 Forbidden')
    self.assertEqual(response.json['errors'], [
        {"location": "body", "name": "data", "description": "Can't create new contract change while any (pending) change exists"}
    ])

    response = self.app.patch_json('/contracts/{}/changes/{}?acc_token={}'.format(self.contract['id'], change['id'], self.contract_token),
                                   {'data': {'status': 'active', 'dateSigned': get_now().isoformat()}})
    self.assertEqual(response.status, '200 OK')
    self.assertEqual(response.json['data']['status'], 'active')

    response = self.app.post_json('/contracts/{}/changes?acc_token={}'.format(self.contract['id'], self.contract_token),
                                  {'data': {'rationale': u'трататата', 'rationaleTypes': ['non-existing-rationale']}}, status=422)
    self.assertEqual(response.status, '422 Unprocessable Entity')
    self.assertEqual(response.json['errors'], [
        {"location": "body", "name": "rationaleTypes", "description": [["Value must be one of ['volumeCuts', 'itemPriceVariation', 'qualityImprovement', 'thirdParty', 'durationExtension', 'priceReduction', 'taxRate', 'fiscalYearExtension']."]]}
    ])

    response = self.app.post_json('/contracts/{}/changes?acc_token={}'.format(self.contract['id'], self.contract_token),
                                  {'data': {'rationale': u'трататата', 'rationaleTypes': ['priceReduction']}})
    self.assertEqual(response.status, '201 Created')
    change2 = response.json['data']
    self.assertEqual(change2['status'], 'pending')

    response = self.app.get('/contracts/{}/changes'.format(self.contract['id']))
    self.assertEqual(response.status, '200 OK')
    self.assertEqual(len(response.json['data']), 2)
def from1to2(registry):
    class Request(object):
        def __init__(self, registry):
            self.registry = registry
    len(registry.db.view('contracts/all', limit=1))
    results = registry.db.iterview('contracts/all', 2 ** 10, include_docs=True, stale='update_after')
    docs = []
    request = Request(registry)
    root = Root(request)
    for i in results:
        doc = i.doc
        if not all([i.get('url', '').startswith(registry.docservice_url) for i in doc.get('documents', [])]):
            contract = Contract(doc)
            contract.__parent__ = root
            doc = contract.to_primitive()
            doc['dateModified'] = get_now().isoformat()
            docs.append(doc)
        if len(docs) >= 2 ** 7:
            registry.db.update(docs)
            docs = []
    if docs:
        registry.db.update(docs)
def contract_administrator_change(self):
    response = self.app.patch_json('/contracts/{}'.format(self.contract['id']),
                                   {'data': {'mode': u'test',
                                             "suppliers": [{
                                                "contactPoint": {
                                                    "email": "*****@*****.**",
                                                },
                                                "address": {"postalCode": "79014"}
                                             }],
                                             'procuringEntity': {"identifier": {"id": "11111111"},
                                                                 "contactPoint": {"telephone": "102"}}
                                             }})
    self.assertEqual(response.status, '200 OK')
    self.assertEqual(response.content_type, 'application/json')
    self.assertEqual(response.json['data']['mode'], u'test')
    self.assertEqual(response.json['data']["procuringEntity"]["identifier"]["id"], "11111111")
    self.assertEqual(response.json['data']["procuringEntity"]["contactPoint"]["telephone"], "102")
    self.assertEqual(response.json['data']["suppliers"][0]["contactPoint"]["email"], "*****@*****.**")
    self.assertEqual(response.json['data']["suppliers"][0]["contactPoint"]["telephone"], "+380 (322) 91-69-30") # old field value left untouchable
    self.assertEqual(response.json['data']["suppliers"][0]["address"]["postalCode"], "79014")
    self.assertEqual(response.json['data']["suppliers"][0]["address"]["countryName"], u"Україна") # old field value left untouchable
    # administrator has permissions to update only: mode, procuringEntity, suppliers
    response = self.app.patch_json('/contracts/{}'.format(self.contract['id']), {'data': {
        'value': {'amount': 100500},
        'id': '1234' * 8,
        'owner': 'kapitoshka',
        'contractID': "UA-00-00-00",
        'dateSigned': get_now().isoformat(),
    }})
    self.assertEqual(response.body, 'null')

    response = self.app.get('/contracts/{}'.format(self.contract['id']))
    self.assertEqual(response.json['data']['value']['amount'], 238)
    self.assertEqual(response.json['data']['id'], self.initial_data['id'])
    self.assertEqual(response.json['data']['owner'], self.initial_data['owner'])
    self.assertEqual(response.json['data']['contractID'], self.initial_data['contractID'])
    self.assertEqual(response.json['data']['dateSigned'], self.initial_data['dateSigned'])
 def collection_post(self):
     """Add a lot
     """
     auction = self.request.validated["auction"]
     if auction.status not in ["active.enquiries"]:
         self.request.errors.add(
             "body", "data", "Can't add lot in current ({}) auction status".format(auction.status)
         )
         self.request.errors.status = 403
         return
     lot = self.request.validated["lot"]
     lot.date = get_now()
     auction.lots.append(lot)
     if save_auction(self.request):
         self.LOGGER.info(
             "Created auction lot {}".format(lot.id),
             extra=context_unpack(self.request, {"MESSAGE_ID": "auction_lot_create"}, {"lot_id": lot.id}),
         )
         self.request.response.status = 201
         route = self.request.matched_route.name.replace("collection_", "")
         self.request.response.headers["Location"] = self.request.current_route_url(
             _route_name=route, lot_id=lot.id, _query={}
         )
         return {"data": lot.serialize("view")}
def patch_tender_contract(self):
    response = self.app.patch_json('/contracts/{}'.format(self.contract['id']), {"data": {"title": "New Title"}}, status=403)
    self.assertEqual(response.status, '403 Forbidden')

    tender_token = self.initial_data['tender_token']
    response = self.app.patch_json('/contracts/{}?acc_token={}'.format(self.contract['id'], tender_token),
                                   {"data": {"title": "New Title"}}, status=403)
    self.assertEqual(response.status, '403 Forbidden')

    response = self.app.patch_json('/contracts/{}/credentials?acc_token={}'.format(self.contract['id'], tender_token),
                                   {'data': ''})
    self.assertEqual(response.status, '200 OK')
    token = response.json['access']['token']

    response = self.app.patch_json('/contracts/{}?acc_token={}'.format(self.contract['id'], token),
                                   {"data": {"title": "New Title"}})
    self.assertEqual(response.status, '200 OK')
    self.assertEqual(response.json['data']['title'], "New Title")

    # response = self.app.patch_json('/contracts/{}?acc_token={}'.format(contract['id'], token),
                                   # {"data": {"value": {"currency": "USD"}}})
    # response = self.app.patch_json('/contracts/{}?acc_token={}'.format(contract['id'], token),
                                   # {"data": {"value": {"valueAddedTaxIncluded": False}}})

    response = self.app.patch_json('/contracts/{}?acc_token={}'.format(self.contract['id'], token),
                                   {"data": {"amountPaid": {"amount": 900, "currency": "USD", "valueAddedTaxIncluded": False}}})
    self.assertEqual(response.status, '200 OK')
    self.assertEqual(response.json['data']['amountPaid']['amount'], 900)
    self.assertEqual(response.json['data']['amountPaid']['currency'], "UAH")
    self.assertEqual(response.json['data']['amountPaid']['valueAddedTaxIncluded'], True)

    response = self.app.patch_json('/contracts/{}?acc_token={}'.format(self.contract['id'], token),
                                   {"data": {"value": {"amount": 235}}})
    self.assertEqual(response.status, '200 OK')
    self.assertEqual(response.json['data']['value']['amount'], 235)
    self.assertEqual(response.json['data']['value']['currency'], "UAH")
    self.assertEqual(response.json['data']['value']['valueAddedTaxIncluded'], True)
    self.assertEqual(response.json['data']['amountPaid']['amount'], 900)
    self.assertEqual(response.json['data']['amountPaid']['currency'], "UAH")
    self.assertEqual(response.json['data']['amountPaid']['valueAddedTaxIncluded'], True)

    response = self.app.patch_json('/contracts/{}?acc_token={}'.format(self.contract['id'], token),
                                   {"data": {"value": {"currency": "USD", "valueAddedTaxIncluded": False}}})
    self.assertEqual(response.status, '200 OK')
    self.assertEqual(response.json['data']['value']['currency'], "USD")
    self.assertEqual(response.json['data']['value']['valueAddedTaxIncluded'], False)
    self.assertEqual(response.json['data']['value']['amount'], 235)
    self.assertEqual(response.json['data']['amountPaid']['amount'], 900)
    self.assertEqual(response.json['data']['amountPaid']['currency'], "USD")
    self.assertEqual(response.json['data']['amountPaid']['valueAddedTaxIncluded'], False)

    custom_period_start_date = get_now().isoformat()
    custom_period_end_date = (get_now() + timedelta(days=3)).isoformat()
    response = self.app.patch_json('/contracts/{}?acc_token={}'.format(self.contract['id'], token),
                                   {"data": {"period": {'startDate': custom_period_start_date,
                                                        'endDate': custom_period_end_date}}})
    self.assertEqual(response.status, '200 OK')

    response = self.app.patch_json('/contracts/{}?acc_token={}'.format(self.contract['id'], token),
                                   {"data": {"status": "terminated",
                                             "amountPaid": {"amount": 100500},
                                             "terminationDetails": "sink"}})
    self.assertEqual(response.status, '200 OK')
    self.assertEqual(response.json['data']['status'], 'terminated')
    self.assertEqual(response.json['data']['amountPaid']['amount'], 100500)
    self.assertEqual(response.json['data']['terminationDetails'], 'sink')

    response = self.app.patch_json('/contracts/{}?acc_token={}'.format(self.contract['id'], token),
                                   {"data": {"status": "active"}}, status=403)
    self.assertEqual(response.status, '403 Forbidden')

    response = self.app.patch_json('/contracts/{}?acc_token={}'.format(self.contract['id'], token),
                                   {"data": {"title": "fff"}}, status=403)
    self.assertEqual(response.status, '403 Forbidden')

    response = self.app.patch_json('/contracts/some_id', {"data": {"status": "active"}}, status=404)
    self.assertEqual(response.status, '404 Not Found')
    self.assertEqual(response.content_type, 'application/json')
    self.assertEqual(response.json['status'], 'error')
    self.assertEqual(response.json['errors'], [
        {u'description': u'Not Found', u'location':
            u'url', u'name': u'contract_id'}
    ])

    response = self.app.get('/contracts/{}'.format(self.contract['id']))
    self.assertEqual(response.status, '200 OK')
    self.assertEqual(response.content_type, 'application/json')
    self.assertEqual(response.json['data']["status"], "terminated")
    self.assertEqual(response.json['data']["value"]['amount'], 235)
    self.assertEqual(response.json['data']['period']['startDate'], custom_period_start_date)
    self.assertEqual(response.json['data']['period']['endDate'], custom_period_end_date)
    self.assertEqual(response.json['data']['amountPaid']['amount'], 100500)
    self.assertEqual(response.json['data']['terminationDetails'], 'sink')
def validate_tender_auction_data(request):
    data = validate_patch_tender_data(request)
    tender = request.validated['tender']
    if tender.status != 'active.auction':
        request.errors.add(
            'body', 'data', 'Can\'t {} in current ({}) tender status'.format(
                'report auction results' if request.method == 'POST' else
                'update auction urls', tender.status))
        request.errors.status = 403
        raise error_handler(request.errors)
    lot_id = request.matchdict.get('auction_lot_id')
    if tender.lots and any(
        [i.status != 'active' for i in tender.lots if i.id == lot_id]):
        request.errors.add(
            'body', 'data', 'Can {} only in active lot status'.format(
                'report auction results' if request.method ==
                'POST' else 'update auction urls'))
        request.errors.status = 403
        raise error_handler(request.errors)
    if data is not None:
        bids = data.get('bids', [])
        tender_bids_ids = [i.id for i in tender.bids]
        if len(bids) != len(tender.bids):
            request.errors.add(
                'body', 'bids',
                "Number of auction results did not match the number of tender bids"
            )
            request.errors.status = 422
            raise error_handler(request.errors)
        if set([i['id'] for i in bids]) != set(tender_bids_ids):
            request.errors.add(
                'body', 'bids',
                "Auction bids should be identical to the tender bids")
            request.errors.status = 422
            raise error_handler(request.errors)
        data['bids'] = [
            x for (y, x) in sorted(
                zip([tender_bids_ids.index(i['id']) for i in bids], bids))
        ]
        if data.get('lots'):
            tender_lots_ids = [i.id for i in tender.lots]
            if len(data.get('lots', [])) != len(tender.lots):
                request.errors.add(
                    'body', 'lots',
                    "Number of lots did not match the number of tender lots")
                request.errors.status = 422
                raise error_handler(request.errors)
            if set([i['id'] for i in data.get('lots', [])]) != set(
                [i.id for i in tender.lots]):
                request.errors.add(
                    'body', 'lots',
                    "Auction lots should be identical to the tender lots")
                request.errors.status = 422
                raise error_handler(request.errors)
            data['lots'] = [
                x if x['id'] == lot_id else {} for (y, x) in sorted(
                    zip([
                        tender_lots_ids.index(i['id'])
                        for i in data.get('lots', [])
                    ], data.get('lots', [])))
            ]
        if tender.lots:
            for index, bid in enumerate(bids):
                if (getattr(tender.bids[index], 'status', 'active')
                        or 'active') == 'active':
                    if len(bid.get('lotValues', [])) != len(
                            tender.bids[index].lotValues):
                        request.errors.add('body', 'bids', [{
                            u'lotValues': [
                                u'Number of lots of auction results did not match the number of tender lots'
                            ]
                        }])
                        request.errors.status = 422
                        raise error_handler(request.errors)
                    for lot_index, lotValue in enumerate(
                            tender.bids[index].lotValues):
                        if lotValue.relatedLot != bid.get(
                                'lotValues', [])[lot_index].get(
                                    'relatedLot', None):
                            request.errors.add('body', 'bids', [{
                                u'lotValues': [{
                                    u'relatedLot': [
                                        'relatedLot should be one of lots of bid'
                                    ]
                                }]
                            }])
                            request.errors.status = 422
                            raise error_handler(request.errors)
            for bid_index, bid in enumerate(data['bids']):
                if 'lotValues' in bid:
                    bid['lotValues'] = [
                        x if x['relatedLot'] == lot_id and (getattr(
                            tender.bids[bid_index].lotValues[lotValue_index],
                            'status', 'active') or 'active') == 'active' else
                        {} for lotValue_index, x in enumerate(bid['lotValues'])
                    ]

    else:
        data = {}
    if request.method == 'POST':
        now = get_now().isoformat()
        if tender.lots:
            data['lots'] = [{
                'auctionPeriod': {
                    'endDate': now
                }
            } if i.id == lot_id else {} for i in tender.lots]
        else:
            data['auctionPeriod'] = {'endDate': now}
    request.validated['data'] = data
 def time_shift(self, status, extra=None):
     now = get_now()
     tender = self.db.get(self.tender_id)
     data = {}
     if status == 'enquiryPeriod_ends':
         data.update({
             "enquiryPeriod": {
                 "startDate": (now - timedelta(days=28)).isoformat(),
                 "endDate": (now - timedelta(days=1)).isoformat()
             },
             "tenderPeriod": {
                 "startDate": (now - timedelta(days=28)).isoformat(),
                 "endDate": (now + timedelta(days=2)).isoformat()
             },
         })
     if status == 'active.pre-qualification':
         data.update({
             "enquiryPeriod": {
                 "startDate": (now - TENDERING_DURATION).isoformat(),
                 "endDate": (now - QUESTIONS_STAND_STILL).isoformat()
             },
             "tenderPeriod": {
                 "startDate": (now - TENDERING_DURATION).isoformat(),
                 "endDate": (now).isoformat(),
             }
         })
     elif status == 'active.pre-qualification.stand-still':
         data.update({
             "enquiryPeriod": {
                 "startDate": (now - TENDERING_DURATION).isoformat(),
                 "endDate": (now - QUESTIONS_STAND_STILL).isoformat()
             },
             "tenderPeriod": {
                 "startDate": (now - TENDERING_DURATION).isoformat(),
                 "endDate": (now).isoformat(),
             },
             "qualificationPeriod": {
                 "startDate": (now).isoformat(),
             },
         })
         if 'lots' in tender and tender['lots']:
             data['lots'] = []
             for index, lot in enumerate(tender['lots']):
                 lot_data = {'id': lot['id']}
                 if lot['status'] is 'active':
                     lot_data["auctionPeriod"] = {
                         "startDate": (now + COMPLAINT_STAND_STILL).isoformat()
                     }
                 data['lots'].append(lot_data)
         else:
             data.update({
                 "auctionPeriod": {
                     "startDate": (now + COMPLAINT_STAND_STILL).isoformat()
                 }
             })
     elif status == 'active.auction':
         data.update({
             "enquiryPeriod": {
                 "startDate": (now - TENDERING_DURATION - COMPLAINT_STAND_STILL).isoformat(),
                 "endDate": (now - COMPLAINT_STAND_STILL - TENDERING_DURATION + QUESTIONS_STAND_STILL).isoformat()
             },
             "tenderPeriod": {
                 "startDate": (now - TENDERING_DURATION - COMPLAINT_STAND_STILL).isoformat(),
                 "endDate": (now - COMPLAINT_STAND_STILL).isoformat()
             },
             "qualificationPeriod": {
                 "startDate": (now - COMPLAINT_STAND_STILL).isoformat(),
                 "endDate": (now).isoformat()
             }
         })
         if 'lots' in tender and tender['lots']:
             data['lots'] = []
             for index, lot in enumerate(tender['lots']):
                 lot_data = {'id': lot['id']}
                 if lot['status'] == 'active':
                     lot_data["auctionPeriod"] = {
                         "startDate": (now).isoformat()
                     }
                 data['lots'].append(lot_data)
         else:
             data.update({
                 "auctionPeriod": {
                     "startDate": now.isoformat()
                 }
             })
     elif status == 'complete':
         data.update({
             "enquiryPeriod": {
                 "startDate": (now - TENDERING_DURATION - COMPLAINT_STAND_STILL - timedelta(days=3)).isoformat(),
                 "endDate": (now - QUESTIONS_STAND_STILL - COMPLAINT_STAND_STILL - timedelta(days=3)).isoformat()
             },
             "tenderPeriod": {
                 "startDate": (now - TENDERING_DURATION - COMPLAINT_STAND_STILL - timedelta(days=3)).isoformat(),
                 "endDate": (now - COMPLAINT_STAND_STILL - timedelta(days=3)).isoformat()
             },
             "auctionPeriod": {
                 "startDate": (now - timedelta(days=3)).isoformat(),
                 "endDate": (now - timedelta(days=2)).isoformat()
             },
             "awardPeriod": {
                 "startDate": (now - timedelta(days=1)).isoformat(),
                 "endDate": (now).isoformat()
             }
         })
         if self.initial_lots:
             data.update({
                 'lots': [
                     {
                         "auctionPeriod": {
                             "startDate": (now - timedelta(days=3)).isoformat(),
                             "endDate": (now - timedelta(days=2)).isoformat()
                         }
                     }
                     for i in self.initial_lots
                 ]
             })
     if extra:
         data.update(extra)
     tender.update(apply_data_patch(tender, data))
     self.db.save(tender)
Ejemplo n.º 22
0
def create_tender_lot_qualification_complaint(self):
    response = self.app.post_json(
        "/tenders/{}/qualifications/{}/complaints?acc_token={}".format(
            self.tender_id, self.qualification_id, self.initial_bids_tokens.values()[0]
        ),
        {
            "data": test_complaint
        },
    )
    self.assertEqual(response.status, "201 Created")
    self.assertEqual(response.content_type, "application/json")
    complaint = response.json["data"]
    complaint_token = response.json["access"]["token"]
    self.assertIn("id", complaint)
    self.assertIn(complaint["id"], response.headers["Location"])

    if RELEASE_2020_04_19 > get_now():
        self.assertEqual(complaint["author"]["name"], self.author_data["name"])

    else:
        self.assertEqual(response.json["data"]["status"], "draft")
        with change_auth(self.app, ("Basic", ("bot", ""))):
            response = self.app.patch_json(
                 "/tenders/{}/qualifications/{}/complaints/{}".format(
                     self.tender_id, self.qualification_id, complaint["id"]),
                {"data": {"status": "pending"}},
            )
        self.assertEqual(response.status, "200 OK")
        self.assertEqual(response.content_type, "application/json")
        self.assertEqual(response.json["data"]["status"], "pending")

    # set complaint status to invalid to be able to cancel the tender
    with change_auth(self.app, ("Basic", ("reviewer", ""))):
        response = self.app.patch_json(
            "/tenders/{}/qualifications/{}/complaints/{}?acc_token={}".format(
                self.tender_id, self.qualification_id, complaint["id"], complaint_token
            ),
            {"data": {
                "status": "invalid",
                "rejectReason": "buyerViolationsCorrected"
            }},
        )
        self.assertEqual(response.status, "200 OK")

    if RELEASE_2020_04_19 > get_now():
        # Test for old rules
        # In new rules there will be 403 error
        self.cancel_tender()

        response = self.app.post_json(
            "/tenders/{}/qualifications/{}/complaints?acc_token={}".format(
                self.tender_id, self.qualification_id, self.initial_bids_tokens.values()[0]
            ),
            {"data": test_draft_claim},
            status=403,
        )
        self.assertEqual(response.status, "403 Forbidden")
        self.assertEqual(response.content_type, "application/json")
        self.assertEqual(
            response.json["errors"][0]["description"], "Can't add complaint in current (cancelled) tender status"
        )
Ejemplo n.º 23
0
def validate_add_complaint_not_in_qualification_period(request):
    tender = request.validated['tender']
    if tender.qualificationPeriod and \
       (tender.qualificationPeriod.startDate and tender.qualificationPeriod.startDate > get_now() or
            tender.qualificationPeriod.endDate and tender.qualificationPeriod.endDate < get_now()):
        raise_operation_error(request,
                              'Can add complaint only in qualificationPeriod')
Ejemplo n.º 24
0
    def patch(self):
        """Tender Edit (partial)

        For example here is how procuring entity can change number of items to be procured and total Value of a tender:

        .. sourcecode:: http

            PATCH /tenders/4879d3f8ee2443169b5fbbc9f89fa607 HTTP/1.1
            Host: example.com
            Accept: application/json

            {
                "data": {
                    "value": {
                        "amount": 600
                    },
                    "itemsToBeProcured": [
                        {
                            "quantity": 6
                        }
                    ]
                }
            }

        And here is the response to be expected:

        .. sourcecode:: http

            HTTP/1.0 200 OK
            Content-Type: application/json

            {
                "data": {
                    "id": "4879d3f8ee2443169b5fbbc9f89fa607",
                    "tenderID": "UA-64e93250be76435397e8c992ed4214d1",
                    "dateModified": "2014-10-27T08:12:34.956Z",
                    "value": {
                        "amount": 600
                    },
                    "itemsToBeProcured": [
                        {
                            "quantity": 6
                        }
                    ]
                }
            }

        """
        tender = self.context
        config = getAdapter(tender, IContentConfigurator)
        data = self.request.validated['data']
        now = get_now()
        if self.request.authenticated_role == 'tender_owner' and \
                self.request.validated['tender_status'] == 'active.tendering':
            if 'tenderPeriod' in data and 'endDate' in data['tenderPeriod']:
                self.request.validated['tender'].tenderPeriod.import_data(data['tenderPeriod'])
                validate_tender_period_extension(self.request)
                self.request.registry.notify(TenderInitializeEvent(self.request.validated['tender']))
                self.request.validated['data']["enquiryPeriod"] = \
                    self.request.validated['tender'].enquiryPeriod.serialize()

        apply_patch(self.request, save=False, src=self.request.validated['tender_src'])
        if self.request.authenticated_role == 'chronograph':
            check_status(self.request)
        elif self.request.authenticated_role == 'tender_owner' and tender.status == 'active.tendering':
            tender.invalidate_bids_data()
        elif self.request.authenticated_role == 'tender_owner' and \
                self.request.validated['tender_status'] == 'active.pre-qualification' and \
                tender.status == "active.pre-qualification.stand-still":
            active_lots = [lot.id for lot in tender.lots if lot.status == 'active'] if tender.lots else [None]
            if any([i['status'] in self.request.validated['tender'].block_complaint_status
                    for q in self.request.validated['tender']['qualifications']
                    for i in q['complaints'] if q['lotID'] in active_lots]):
                raise_operation_error(
                    self.request,
                    'Can\'t switch to \'active.pre-qualification.stand-still\' before resolve all complaints'
                )
            if all_bids_are_reviewed(self.request):
                normalized_date = calculate_normalized_date(now, tender, True)
                tender.qualificationPeriod.endDate = calculate_business_date(
                    normalized_date, config.qualification_complaint_stand_still, self.request.validated['tender']
                )
                tender.check_auction_time()
            else:
                raise_operation_error(
                    self.request,
                    'Can\'t switch to \'active.pre-qualification.stand-still\' while not all bids are qualified'
                )
        elif self.request.authenticated_role == 'tender_owner' and \
                self.request.validated['tender_status'] == 'active.qualification' and \
                tender.status == "active.qualification.stand-still":
            active_lots = [lot.id for lot in tender.lots if lot.status == 'active'] if tender.lots else [None]
            if any([i['status'] in self.request.validated['tender'].block_complaint_status
                    for a in self.request.validated['tender']['awards']
                    for i in a['complaints'] if a['lotID'] in active_lots]):
                raise_operation_error(
                    self.request,
                    'Can\'t switch to \'active.qualification.stand-still\' before resolve all complaints'
                )
            if all_awards_are_reviewed(self.request):
                normalized_date = calculate_normalized_date(now, tender, True)
                tender.awardPeriod.endDate = calculate_business_date(
                    normalized_date, config.qualification_complaint_stand_still, self.request.validated['tender']
                )
                for award in [a for a in tender.awards if a.status != 'cancelled']:
                    award['complaintPeriod'] = {
                        'startDate': now.isoformat(),
                        'endDate': tender.awardPeriod.endDate.isoformat()
                    }
            else:
                raise_operation_error(
                    self.request,
                    'Can\'t switch to \'active.qualification.stand-still\' while not all awards are qualified'
                )

        save_tender(self.request)
        self.LOGGER.info('Updated tender {}'.format(tender.id),
                         extra=context_unpack(self.request, {'MESSAGE_ID': 'tender_patch'}))
        return {'data': tender.serialize(tender.status)}
 def validate_dateSigned(self, data, value):
     if value and value > get_now():
         raise ValidationError(u"Contract signature date can't be in the future")
 def validate_dateSigned(self, data, value):
     if value and isinstance(data['__parent__'], Model):
         if value > get_now():
             raise ValidationError(
                 u"Contract signature date can't be in the future")
def create_tender_invalid(self):
    request_path = '/tenders'
    response = self.app.post(request_path, 'data', status=415)
    self.assertEqual(response.status, '415 Unsupported Media Type')
    self.assertEqual(response.content_type, 'application/json')
    self.assertEqual(response.json['status'], 'error')
    self.assertEqual(response.json['errors'], [{
        u'description':
        u"Content-Type header should be one of ['application/json']",
        u'location': u'header',
        u'name': u'Content-Type'
    }])

    response = self.app.post(request_path,
                             'data',
                             content_type='application/json',
                             status=422)
    self.assertEqual(response.status, '422 Unprocessable Entity')
    self.assertEqual(response.content_type, 'application/json')
    self.assertEqual(response.json['status'], 'error')
    self.assertEqual(response.json['errors'], [{
        u'description': u'No JSON object could be decoded',
        u'location': u'body',
        u'name': u'data'
    }])

    response = self.app.post_json(request_path, 'data', status=422)
    self.assertEqual(response.status, '422 Unprocessable Entity')
    self.assertEqual(response.content_type, 'application/json')
    self.assertEqual(response.json['status'], 'error')
    self.assertEqual(response.json['errors'], [{
        u'description': u'Data not available',
        u'location': u'body',
        u'name': u'data'
    }])

    response = self.app.post_json(request_path, {'not_data': {}}, status=422)
    self.assertEqual(response.status, '422 Unprocessable Entity')
    self.assertEqual(response.content_type, 'application/json')
    self.assertEqual(response.json['status'], 'error')
    self.assertEqual(response.json['errors'], [{
        u'description': u'Data not available',
        u'location': u'body',
        u'name': u'data'
    }])

    response = self.app.post_json(request_path, {'data': []}, status=422)
    self.assertEqual(response.status, '422 Unprocessable Entity')
    self.assertEqual(response.content_type, 'application/json')
    self.assertEqual(response.json['status'], 'error')
    self.assertEqual(response.json['errors'], [{
        u'description': u'Data not available',
        u'location': u'body',
        u'name': u'data'
    }])

    response = self.app.post_json(
        request_path, {'data': {
            'procurementMethodType': 'invalid_value'
        }},
        status=415)
    self.assertEqual(response.status, '415 Unsupported Media Type')
    self.assertEqual(response.content_type, 'application/json')
    self.assertEqual(response.json['status'], 'error')
    self.assertEqual(response.json['errors'],
                     [{
                         u'description': u'Not implemented',
                         u'location': u'data',
                         u'name': u'procurementMethodType'
                     }])

    response = self.app.post_json(request_path, {
        'data': {
            'procurementMethodType': 'esco.EU',
            'invalid_field': 'invalid_value'
        }
    },
                                  status=422)
    self.assertEqual(response.status, '422 Unprocessable Entity')
    self.assertEqual(response.content_type, 'application/json')
    self.assertEqual(response.json['status'], 'error')
    self.assertEqual(response.json['errors'], [{
        u'description': u'Rogue field',
        u'location': u'body',
        u'name': u'invalid_field'
    }])

    response = self.app.post_json(request_path, {
        'data': {
            'procurementMethodType': 'esco.EU',
            'minValue': 'invalid_value'
        }
    },
                                  status=422)
    self.assertEqual(response.status, '422 Unprocessable Entity')
    self.assertEqual(response.content_type, 'application/json')
    self.assertEqual(response.json['status'], 'error')
    self.assertEqual(response.json['errors'], [{
        u'description': [
            u'Please use a mapping for this field or Value instance instead of unicode.'
        ],
        u'location':
        u'body',
        u'name':
        u'minValue'
    }])

    response = self.app.post_json(request_path, {
        'data': {
            'procurementMethodType': 'esco.EU',
            'procurementMethod': 'invalid_value'
        }
    },
                                  status=422)
    self.assertEqual(response.status, '422 Unprocessable Entity')
    self.assertEqual(response.content_type, 'application/json')
    self.assertEqual(response.json['status'], 'error')
    self.assertIn(
        {
            u'description':
            [u"Value must be one of ['open', 'selective', 'limited']."],
            u'location':
            u'body',
            u'name':
            u'procurementMethod'
        }, response.json['errors'])
    self.assertIn(
        {
            u'description': [u'This field is required.'],
            u'location': u'body',
            u'name': u'tenderPeriod'
        }, response.json['errors'])
    self.assertIn(
        {
            u'description': [u'This field is required.'],
            u'location': u'body',
            u'name': u'minimalStep'
        }, response.json['errors'])
    self.assertIn(
        {
            u'description': [u'This field is required.'],
            u'location': u'body',
            u'name': u'items'
        }, response.json['errors'])
    self.assertIn(
        {
            u'description': [u'This field is required.'],
            u'location': u'body',
            u'name': u'minValue'
        }, response.json['errors'])
    self.assertIn(
        {
            u'description': [u'This field is required.'],
            u'location': u'body',
            u'name': u'items'
        }, response.json['errors'])

    response = self.app.post_json(request_path, {
        'data': {
            'procurementMethodType': 'esco.EU',
            'enquiryPeriod': {
                'endDate': 'invalid_value'
            }
        }
    },
                                  status=422)
    self.assertEqual(response.status, '422 Unprocessable Entity')
    self.assertEqual(response.content_type, 'application/json')
    self.assertEqual(response.json['status'], 'error')
    self.assertEqual(response.json['errors'], [{
        u'description': {
            u'endDate': [u"Could not parse invalid_value. Should be ISO8601."]
        },
        u'location': u'body',
        u'name': u'enquiryPeriod'
    }])

    response = self.app.post_json(request_path, {
        'data': {
            'procurementMethodType': 'esco.EU',
            'enquiryPeriod': {
                'endDate': '9999-12-31T23:59:59.999999'
            }
        }
    },
                                  status=422)
    self.assertEqual(response.status, '422 Unprocessable Entity')
    self.assertEqual(response.content_type, 'application/json')
    self.assertEqual(response.json['status'], 'error')
    self.assertEqual(response.json['errors'], [{
        u'description': {
            u'endDate': [u'date value out of range']
        },
        u'location': u'body',
        u'name': u'enquiryPeriod'
    }])

    data = self.initial_data['tenderPeriod']
    self.initial_data['tenderPeriod'] = {
        'startDate': '2014-10-31T00:00:00',
        'endDate': '2014-10-01T00:00:00'
    }
    response = self.app.post_json(request_path, {'data': self.initial_data},
                                  status=422)
    self.initial_data['tenderPeriod'] = data
    self.assertEqual(response.status, '422 Unprocessable Entity')
    self.assertEqual(response.content_type, 'application/json')
    self.assertEqual(response.json['status'], 'error')
    self.assertEqual(response.json['errors'], [{
        u'description': {
            u'startDate': [u'period should begin before its end']
        },
        u'location': u'body',
        u'name': u'tenderPeriod'
    }])

    self.initial_data['tenderPeriod']['startDate'] = (
        get_now() - timedelta(minutes=30)).isoformat()
    response = self.app.post_json(request_path, {'data': self.initial_data},
                                  status=422)
    del self.initial_data['tenderPeriod']['startDate']
    self.assertEqual(response.status, '422 Unprocessable Entity')
    self.assertEqual(response.content_type, 'application/json')
    self.assertEqual(response.json['status'], 'error')
    self.assertEqual(response.json['errors'], [{
        u'description':
        [u'tenderPeriod.startDate should be in greater than current date'],
        u'location':
        u'body',
        u'name':
        u'tenderPeriod'
    }])

    now = get_now()
    self.initial_data['awardPeriod'] = {
        'startDate': now.isoformat(),
        'endDate': now.isoformat()
    }
    response = self.app.post_json(request_path, {'data': self.initial_data},
                                  status=422)
    del self.initial_data['awardPeriod']
    self.assertEqual(response.status, '422 Unprocessable Entity')
    self.assertEqual(response.content_type, 'application/json')
    self.assertEqual(response.json['status'], 'error')
    self.assertEqual(
        response.json['errors'],
        [{
            u'description': [u'period should begin after tenderPeriod'],
            u'location': u'body',
            u'name': u'awardPeriod'
        }])

    self.initial_data['auctionPeriod'] = {
        'startDate': (now + timedelta(days=35)).isoformat(),
        'endDate': (now + timedelta(days=35)).isoformat()
    }
    self.initial_data['awardPeriod'] = {
        'startDate': (now + timedelta(days=34)).isoformat(),
        'endDate': (now + timedelta(days=34)).isoformat()
    }
    response = self.app.post_json(request_path, {'data': self.initial_data},
                                  status=422)
    del self.initial_data['auctionPeriod']
    del self.initial_data['awardPeriod']
    self.assertEqual(response.status, '422 Unprocessable Entity')
    self.assertEqual(response.content_type, 'application/json')
    self.assertEqual(response.json['status'], 'error')
    self.assertEqual(
        response.json['errors'],
        [{
            u'description': [u'period should begin after auctionPeriod'],
            u'location': u'body',
            u'name': u'awardPeriod'
        }])

    data = self.initial_data['minimalStep']
    self.initial_data['minimalStep'] = {'amount': '1000.0'}
    response = self.app.post_json(request_path, {'data': self.initial_data},
                                  status=422)
    self.initial_data['minimalStep'] = data
    self.assertEqual(response.status, '422 Unprocessable Entity')
    self.assertEqual(response.content_type, 'application/json')
    self.assertEqual(response.json['status'], 'error')
    self.assertEqual(
        response.json['errors'],
        [{
            u'description': [u'value should be less than minValue of tender'],
            u'location': u'body',
            u'name': u'minimalStep'
        }])

    data = self.initial_data['minimalStep']
    self.initial_data['minimalStep'] = {
        'amount': '100.0',
        'valueAddedTaxIncluded': False
    }
    response = self.app.post_json(request_path, {'data': self.initial_data},
                                  status=422)
    self.initial_data['minimalStep'] = data
    self.assertEqual(response.status, '422 Unprocessable Entity')
    self.assertEqual(response.content_type, 'application/json')
    self.assertEqual(response.json['status'], 'error')
    self.assertEqual(response.json['errors'], [{
        u'description': [
            u'valueAddedTaxIncluded should be identical to valueAddedTaxIncluded of minValue of tender'
        ],
        u'location':
        u'body',
        u'name':
        u'minimalStep'
    }])

    data = self.initial_data['minimalStep']
    self.initial_data['minimalStep'] = {'amount': '100.0', 'currency': "USD"}
    response = self.app.post_json(request_path, {'data': self.initial_data},
                                  status=422)
    self.initial_data['minimalStep'] = data
    self.assertEqual(response.status, '422 Unprocessable Entity')
    self.assertEqual(response.content_type, 'application/json')
    self.assertEqual(response.json['status'], 'error')
    self.assertEqual(response.json['errors'], [{
        u'description':
        [u'currency should be identical to currency of minValue of tender'],
        u'location':
        u'body',
        u'name':
        u'minimalStep'
    }])

    data = self.initial_data["items"][0].pop("additionalClassifications")
    if get_now() > CPV_ITEMS_CLASS_FROM:
        cpv_code = self.initial_data["items"][0]['classification']['id']
        self.initial_data["items"][0]['classification']['id'] = '99999999-9'
    response = self.app.post_json(request_path, {'data': self.initial_data},
                                  status=422)
    self.initial_data["items"][0]["additionalClassifications"] = data
    if get_now() > CPV_ITEMS_CLASS_FROM:
        self.initial_data["items"][0]['classification']['id'] = cpv_code
    self.assertEqual(response.status, '422 Unprocessable Entity')
    self.assertEqual(response.content_type, 'application/json')
    self.assertEqual(response.json['status'], 'error')
    self.assertEqual(response.json['errors'], [{
        u'description': [{
            u'additionalClassifications': [u'This field is required.']
        }],
        u'location':
        u'body',
        u'name':
        u'items'
    }])

    data = self.initial_data["items"][0]["additionalClassifications"][0][
        "scheme"]
    self.initial_data["items"][0]["additionalClassifications"][0][
        "scheme"] = 'Не ДКПП'
    if get_now() > CPV_ITEMS_CLASS_FROM:
        cpv_code = self.initial_data["items"][0]['classification']['id']
        self.initial_data["items"][0]['classification']['id'] = '99999999-9'
    response = self.app.post_json(request_path, {'data': self.initial_data},
                                  status=422)
    self.initial_data["items"][0]["additionalClassifications"][0][
        "scheme"] = data
    if get_now() > CPV_ITEMS_CLASS_FROM:
        self.initial_data["items"][0]['classification']['id'] = cpv_code
    self.assertEqual(response.status, '422 Unprocessable Entity')
    self.assertEqual(response.content_type, 'application/json')
    self.assertEqual(response.json['status'], 'error')
    if get_now() > CPV_ITEMS_CLASS_FROM:
        self.assertEqual(response.json['errors'], [{
            u'description': [{
                u'additionalClassifications': [
                    u"One of additional classifications should be one of [ДК003, ДК015, ДК018, specialNorms]."
                ]
            }],
            u'location':
            u'body',
            u'name':
            u'items'
        }])
    else:
        self.assertEqual(response.json['errors'], [{
            u'description': [{
                u'additionalClassifications': [
                    u"One of additional classifications should be one of [ДКПП, NONE, ДК003, ДК015, ДК018]."
                ]
            }],
            u'location':
            u'body',
            u'name':
            u'items'
        }])

    data = self.initial_data["procuringEntity"]["contactPoint"]["telephone"]
    del self.initial_data["procuringEntity"]["contactPoint"]["telephone"]
    response = self.app.post_json(request_path, {'data': self.initial_data},
                                  status=422)
    self.initial_data["procuringEntity"]["contactPoint"]["telephone"] = data
    self.assertEqual(response.status, '422 Unprocessable Entity')
    self.assertEqual(response.content_type, 'application/json')
    self.assertEqual(response.json['status'], 'error')
    self.assertEqual(response.json['errors'], [{
        u'description': {
            u'contactPoint': {
                u'email': [u'telephone or email should be present']
            }
        },
        u'location': u'body',
        u'name': u'procuringEntity'
    }])

    data = self.initial_data["items"][0].copy()
    classification = data['classification'].copy()
    classification["id"] = u'19212310-1'
    data['classification'] = classification
    self.initial_data["items"] = [self.initial_data["items"][0], data]
    response = self.app.post_json(request_path, {'data': self.initial_data},
                                  status=422)
    self.initial_data["items"] = self.initial_data["items"][:1]
    self.assertEqual(response.status, '422 Unprocessable Entity')
    self.assertEqual(response.content_type, 'application/json')
    self.assertEqual(response.json['status'], 'error')
    self.assertEqual(response.json['errors'],
                     [{
                         u'description': [u'CPV group of items be identical'],
                         u'location': u'body',
                         u'name': u'items'
                     }])

    data = deepcopy(self.initial_data)
    del data["items"][0]['deliveryDate']
    response = self.app.post_json(request_path, {'data': data}, status=422)
    self.assertEqual(response.status, '422 Unprocessable Entity')
    self.assertEqual(response.content_type, 'application/json')
    self.assertEqual(response.json['status'], 'error')
    self.assertEqual(
        response.json['errors'],
        [{
            u'description': [{
                u'deliveryDate': [u'This field is required.']
            }],
            u'location': u'body',
            u'name': u'items'
        }])
Ejemplo n.º 28
0
def patch_tender_contract(self):
    response = self.app.get("/tenders/{}/contracts".format(self.tender_id))
    contract = response.json["data"][0]

    self.assertEqual(contract["value"]["amountNet"],
                     self.expected_contract_amount)

    response = self.app.patch_json(
        "/tenders/{}/contracts/{}?acc_token={}".format(self.tender_id,
                                                       contract["id"],
                                                       self.tender_token),
        {"data": {
            "value": {
                "amountNet": contract["value"]["amount"] - 1
            }
        }},
    )
    self.assertEqual(response.status, "200 OK")

    fake_contractID = "myselfID"
    fake_items_data = [{"description": "New Description"}]
    fake_suppliers_data = [{"name": "New Name"}]

    self.app.patch_json(
        "/tenders/{}/contracts/{}?acc_token={}".format(self.tender_id,
                                                       contract["id"],
                                                       self.tender_token),
        {
            "data": {
                "contractID": fake_contractID,
                "items": fake_items_data,
                "suppliers": fake_suppliers_data
            }
        },
    )

    response = self.app.get("/tenders/{}/contracts/{}".format(
        self.tender_id, contract["id"]))
    self.assertNotEqual(fake_contractID, response.json["data"]["contractID"])
    self.assertNotEqual(fake_items_data, response.json["data"]["items"])
    self.assertNotEqual(fake_suppliers_data,
                        response.json["data"]["suppliers"])

    patch_fields = {
        "currency": "USD",
        "amountPerformance": 0,
        "yearlyPaymentsPercentage": 0,
        "annualCostsReduction": 0,
        "contractDuration": {
            "years": 9
        },
    }

    for field, value in patch_fields.items():
        response = self.app.patch_json(
            "/tenders/{}/contracts/{}?acc_token={}".format(
                self.tender_id, contract["id"], self.tender_token),
            {"data": {
                "value": {
                    field: value
                }
            }},
            status=403,
        )
        self.assertEqual(response.status_code, 403, field)
        self.assertEqual(response.json["errors"][0]["description"],
                         "Can't update {} for contract value".format(field))

    response = self.app.patch_json(
        "/tenders/{}/contracts/{}?acc_token={}".format(self.tender_id,
                                                       contract["id"],
                                                       self.tender_token),
        {"data": {
            "value": {
                "amountNet": self.expected_contract_amount + 1
            }
        }},
        status=403,
    )
    self.assertEqual(response.status_code, 403)
    self.assertEqual(
        response.json["errors"][0]["description"],
        "Amount should be greater than amountNet and differ by no more than 20.0%",
    )

    response = self.app.patch_json(
        "/tenders/{}/contracts/{}?acc_token={}".format(self.tender_id,
                                                       contract["id"],
                                                       self.tender_token),
        {"data": {
            "value": {
                "amountNet": 10
            }
        }},
        status=403,
    )
    self.assertEqual(response.status_code, 403)
    self.assertIn(
        "Amount should be greater than amountNet and differ by no more than 20.0%",
        response.json["errors"][0]["description"],
    )

    response = self.app.patch_json(
        "/tenders/{}/contracts/{}?acc_token={}".format(self.tender_id,
                                                       contract["id"],
                                                       self.tender_token),
        {"data": {
            "value": {
                "amountNet": self.expected_contract_amount - 1
            }
        }},
    )
    self.assertEqual(response.status_code, 200)

    response = self.app.patch_json(
        "/tenders/{}/contracts/{}?acc_token={}".format(self.tender_id,
                                                       contract["id"],
                                                       self.tender_token),
        {"data": {
            "status": "active"
        }},
        status=403,
    )
    self.assertEqual(response.status, "403 Forbidden")
    self.assertEqual(response.content_type, "application/json")
    self.assertIn("Can't sign contract before stand-still period end (",
                  response.json["errors"][0]["description"])

    self.set_status("complete", {"status": "active.awarded"})

    token = self.initial_bids_tokens[self.initial_bids[0]["id"]]
    response = self.app.post_json(
        "/tenders/{}/awards/{}/complaints?acc_token={}".format(
            self.tender_id, self.award_id, token),
        {"data": test_draft_complaint},
    )
    self.assertEqual(response.status, "201 Created")
    complaint = response.json["data"]
    owner_token = response.json["access"]["token"]

    if get_now() < RELEASE_2020_04_19:
        response = self.app.patch_json(
            "/tenders/{}/awards/{}/complaints/{}?acc_token={}".format(
                self.tender_id, self.award_id, complaint["id"], owner_token),
            {"data": {
                "status": "pending"
            }},
        )
    else:
        with change_auth(self.app, ("Basic", ("bot", ""))):
            response = self.app.patch_json(
                "/tenders/{}/awards/{}/complaints/{}".format(
                    self.tender_id, self.award_id, complaint["id"]),
                {"data": {
                    "status": "pending"
                }},
            )

    self.assertEqual(response.status, "200 OK")

    tender = self.db.get(self.tender_id)
    for i in tender.get("awards", []):
        i["complaintPeriod"]["endDate"] = i["complaintPeriod"]["startDate"]
    self.db.save(tender)

    response = self.app.patch_json(
        "/tenders/{}/contracts/{}?acc_token={}".format(self.tender_id,
                                                       contract["id"],
                                                       self.tender_token),
        {"data": {
            "dateSigned": i["complaintPeriod"]["endDate"]
        }},
        status=422,
    )
    self.assertEqual(response.status, "422 Unprocessable Entity")
    self.assertEqual(
        response.json["errors"],
        [{
            "description": [
                "Contract signature date should be after award complaint period end date ({})"
                .format(i["complaintPeriod"]["endDate"])
            ],
            "location":
            "body",
            "name":
            "dateSigned",
        }],
    )

    one_hour_in_future = (get_now() + timedelta(hours=1)).isoformat()
    response = self.app.patch_json(
        "/tenders/{}/contracts/{}?acc_token={}".format(self.tender_id,
                                                       contract["id"],
                                                       self.tender_token),
        {"data": {
            "dateSigned": one_hour_in_future
        }},
        status=422,
    )
    self.assertEqual(response.status, "422 Unprocessable Entity")
    self.assertEqual(
        response.json["errors"],
        [{
            "description": ["Contract signature date can't be in the future"],
            "location": "body",
            "name": "dateSigned",
        }],
    )

    custom_signature_date = get_now().isoformat()
    response = self.app.patch_json(
        "/tenders/{}/contracts/{}?acc_token={}".format(self.tender_id,
                                                       contract["id"],
                                                       self.tender_token),
        {"data": {
            "dateSigned": custom_signature_date
        }},
    )
    self.assertEqual(response.status, "200 OK")

    response = self.app.patch_json(
        "/tenders/{}/contracts/{}?acc_token={}".format(self.tender_id,
                                                       contract["id"],
                                                       self.tender_token),
        {"data": {
            "status": "active"
        }},
        status=403,
    )
    self.assertEqual(response.status, "403 Forbidden")
    self.assertEqual(response.content_type, "application/json")
    self.assertEqual(response.json["errors"][0]["description"],
                     "Can't sign contract before reviewing all complaints")

    with change_auth(self.app, ("Basic", ("reviewer", ""))):
        response = self.app.patch_json(
            "/tenders/{}/awards/{}/complaints/{}?acc_token={}".format(
                self.tender_id, self.award_id, complaint["id"], owner_token),
            {
                "data": {
                    "status": "invalid",
                    "rejectReason": "buyerViolationsCorrected"
                }
            },
        )
        self.assertEqual(response.status, "200 OK")

    response = self.app.patch_json(
        "/tenders/{}/contracts/{}?acc_token={}".format(self.tender_id,
                                                       contract["id"],
                                                       self.tender_token),
        {"data": {
            "status": "active"
        }},
    )
    self.assertEqual(response.status, "200 OK")
    self.assertEqual(response.content_type, "application/json")
    self.assertEqual(response.json["data"]["status"], "active")

    response = self.app.patch_json(
        "/tenders/{}/contracts/{}?acc_token={}".format(self.tender_id,
                                                       contract["id"],
                                                       self.tender_token),
        {
            "data": {
                "value": {
                    "annualCostsReduction": [780.5] * 21,
                    "yearlyPaymentsPercentage": 0.9,
                    "contractDuration": {
                        "years": 10
                    },
                },
                "contractID": "myselfID",
                "title": "New Title",
                "items": [{
                    "description": "New Description"
                }],
                "suppliers": [{
                    "name": "New Name"
                }],
            }
        },
        status=403,
    )
    self.assertEqual(response.status, "403 Forbidden")
    self.assertEqual(
        response.json["errors"][0]["description"],
        "Can't update contract in current (complete) tender status")

    response = self.app.patch_json(
        "/tenders/{}/contracts/{}?acc_token={}".format(self.tender_id,
                                                       contract["id"],
                                                       self.tender_token),
        {"data": {
            "status": "active"
        }},
        status=403,
    )
    self.assertEqual(response.status, "403 Forbidden")
    self.assertEqual(response.content_type, "application/json")
    self.assertEqual(
        response.json["errors"][0]["description"],
        "Can't update contract in current (complete) tender status")

    response = self.app.patch_json(
        "/tenders/{}/contracts/{}?acc_token={}".format(self.tender_id,
                                                       contract["id"],
                                                       self.tender_token),
        {"data": {
            "status": "pending"
        }},
        status=403,
    )
    self.assertEqual(response.status, "403 Forbidden")
    self.assertEqual(response.content_type, "application/json")
    self.assertEqual(
        response.json["errors"][0]["description"],
        "Can't update contract in current (complete) tender status")

    response = self.app.patch_json("/tenders/{}/contracts/some_id".format(
        self.tender_id), {"data": {
            "status": "active"
        }},
                                   status=404)
    self.assertEqual(response.status, "404 Not Found")
    self.assertEqual(response.content_type, "application/json")
    self.assertEqual(response.json["status"], "error")
    self.assertEqual(response.json["errors"], [{
        "description": "Not Found",
        "location": "url",
        "name": "contract_id"
    }])

    response = self.app.patch_json("/tenders/some_id/contracts/some_id",
                                   {"data": {
                                       "status": "active"
                                   }},
                                   status=404)
    self.assertEqual(response.status, "404 Not Found")
    self.assertEqual(response.content_type, "application/json")
    self.assertEqual(response.json["status"], "error")
    self.assertEqual(response.json["errors"], [{
        "description": "Not Found",
        "location": "url",
        "name": "tender_id"
    }])

    response = self.app.get("/tenders/{}/contracts/{}".format(
        self.tender_id, contract["id"]))
    self.assertEqual(response.status, "200 OK")
    self.assertEqual(response.content_type, "application/json")
    self.assertEqual(response.json["data"]["status"], "active")
    self.assertEqual(response.json["data"]["value"]["amountPerformance"],
                     self.expected_contract_amountPerformance)
    self.assertEqual(response.json["data"]["value"]["amount"],
                     self.expected_contract_amount)
    self.assertNotEqual(response.json["data"]["value"]["amountNet"],
                        response.json["data"]["value"]["amount"])
    self.assertEqual(response.json["data"]["value"]["amountNet"],
                     self.expected_contract_amount - 1)
Ejemplo n.º 29
0
def patch_eu(self):
    """Tender Edit (partial)

            For example here is how procuring entity can change number of items to be procured and total Value of a tender:

            .. sourcecode:: http

                PATCH /tenders/4879d3f8ee2443169b5fbbc9f89fa607 HTTP/1.1
                Host: example.com
                Accept: application/json

                {
                    "data": {
                        "value": {
                            "amount": 600
                        },
                        "itemsToBeProcured": [
                            {
                                "quantity": 6
                            }
                        ]
                    }
                }

            And here is the response to be expected:

            .. sourcecode:: http

                HTTP/1.0 200 OK
                Content-Type: application/json

                {
                    "data": {
                        "id": "4879d3f8ee2443169b5fbbc9f89fa607",
                        "tenderID": "UA-64e93250be76435397e8c992ed4214d1",
                        "dateModified": "2014-10-27T08:12:34.956Z",
                        "value": {
                            "amount": 600
                        },
                        "itemsToBeProcured": [
                            {
                                "quantity": 6
                            }
                        ]
                    }
                }

            """
    tender = self.context
    data = self.request.validated["data"]
    if (self.request.authenticated_role == "tender_owner"
            and self.request.validated["tender_status"] == "active.tendering"):
        if "tenderPeriod" in data and "endDate" in data["tenderPeriod"]:
            self.request.validated["tender"].tenderPeriod.import_data(
                data["tenderPeriod"])
            validate_tender_period_extension(self.request)
            self.request.registry.notify(
                TenderInitializeEvent(self.request.validated["tender"]))
            self.request.validated["data"][
                "enquiryPeriod"] = self.request.validated[
                    "tender"].enquiryPeriod.serialize()

    apply_patch(self.request,
                save=False,
                src=self.request.validated["tender_src"])
    if self.request.authenticated_role == "chronograph":
        check_status(self.request)
    elif self.request.authenticated_role == "tender_owner" and tender.status == "active.tendering":
        tender.invalidate_bids_data()
    elif (self.request.authenticated_role == "tender_owner" and
          self.request.validated["tender_status"] == "active.pre-qualification"
          and tender.status == "active.pre-qualification.stand-still"):
        if all_bids_are_reviewed(self.request):
            tender.qualificationPeriod.endDate = calculate_tender_business_date(
                get_now(), COMPLAINT_STAND_STILL,
                self.request.validated["tender"])
            tender.check_auction_time()
        else:
            raise_operation_error(
                self.request,
                "Can't switch to 'active.pre-qualification.stand-still' while not all bids are qualified"
            )
    elif (self.request.authenticated_role == "tender_owner" and
          self.request.validated["tender_status"] == "active.pre-qualification"
          and tender.status != "active.pre-qualification.stand-still"):
        raise_operation_error(self.request, "Can't update tender status")

    save_tender(self.request)
    self.LOGGER.info("Updated tender {}".format(tender.id),
                     extra=context_unpack(self.request,
                                          {"MESSAGE_ID": "tender_patch"}))
    return {"data": tender.serialize(tender.status)}
Ejemplo n.º 30
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"],
                        "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"]
            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"],
                        "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"
def contract_change_document(self):
    response = self.app.patch_json('/contracts/{}?acc_token={}'.format(self.contract_id, self.contract_token),
                                   {"data": {"status": "active"}})
    self.assertEqual(response.status, '200 OK')

    response = self.app.post('/contracts/{}/documents?acc_token={}'.format(
        self.contract_id, self.contract_token), upload_files=[('file', str(Header(u'укр.doc', 'utf-8')), 'content')])
    self.assertEqual(response.status, '201 Created')
    self.assertEqual(response.content_type, 'application/json')
    doc_id = response.json["data"]['id']
    self.assertIn(doc_id, response.headers['Location'])
    self.assertEqual(u'укр.doc', response.json["data"]["title"])
    self.assertEqual(response.json["data"]["documentOf"], "contract")
    self.assertNotIn("documentType", response.json["data"])

    response = self.app.patch_json('/contracts/{}/documents/{}?acc_token={}'.format(self.contract_id, doc_id, self.contract_token), {"data": {
        "documentOf": "change",
        "relatedItem": '1234' * 8,
    }}, status=422)
    self.assertEqual(response.status, '422 Unprocessable Entity')
    self.assertEqual(response.json['errors'], [
        {"location": "body", "name": "relatedItem", "description": ["relatedItem should be one of changes"]}])

    response = self.app.post_json('/contracts/{}/changes?acc_token={}'.format(self.contract['id'], self.contract_token),
                                  {'data': {'rationale': u'причина зміни укр',
                                            'rationale_en': 'change cause en',
                                            'rationaleTypes': ['priceReduction']}})
    self.assertEqual(response.status, '201 Created')
    self.assertEqual(response.content_type, 'application/json')
    change = response.json['data']

    response = self.app.patch_json('/contracts/{}/documents/{}?acc_token={}'.format(self.contract_id, doc_id, self.contract_token), {"data": {
        "documentOf": "change",
        "relatedItem": change['id'],
    }})
    self.assertEqual(response.status, '200 OK')
    self.assertEqual(response.content_type, 'application/json')
    self.assertEqual(doc_id, response.json["data"]["id"])
    self.assertEqual(response.json["data"]["documentOf"], 'change')
    self.assertEqual(response.json["data"]["relatedItem"], change['id'])

    response = self.app.put('/contracts/{}/documents/{}?acc_token={}'.format(
        self.contract_id, doc_id, self.contract_token), upload_files=[('file', str(Header(u'укр2.doc', 'utf-8')), 'content2')])
    self.assertEqual(response.status, '200 OK')
    self.assertEqual(response.content_type, 'application/json')
    self.assertEqual(doc_id, response.json["data"]["id"])

    response = self.app.patch_json('/contracts/{}/changes/{}?acc_token={}'.format(self.contract['id'], change['id'], self.contract_token),
                                   {'data': {'status': 'active', 'dateSigned': get_now().isoformat()}})
    self.assertEqual(response.status, '200 OK')

    response = self.app.post('/contracts/{}/documents?acc_token={}'.format(
        self.contract_id, self.contract_token), upload_files=[('file', str(Header(u'укр2.doc', 'utf-8')), 'content2')])
    self.assertEqual(response.status, '201 Created')
    doc_id = response.json["data"]['id']

    response = self.app.patch_json('/contracts/{}/documents/{}?acc_token={}'.format(self.contract_id, doc_id, self.contract_token), {"data": {
        "documentOf": "change",
        "relatedItem": change['id'],
    }}, status=403)
    self.assertEqual(response.status, '403 Forbidden')
    self.assertEqual(response.json['errors'], [
        {"location": "body", "name": "data", "description": "Can't add document to 'active' change"}])
def create_change(self):
    response = self.app.post_json(
        "/contracts/{}/changes?acc_token={}".format(self.contract["id"], self.contract_token),
        {
            "data": {
                "rationale": "причина зміни укр",
                "rationale_en": "change cause en",
                "rationaleTypes": ["qualityImprovement"],
            }
        },
    )
    self.assertEqual(response.status, "201 Created")
    self.assertEqual(response.content_type, "application/json")
    change = response.json["data"]
    self.assertEqual(change["status"], "pending")
    self.assertIn("date", change)

    response = self.app.get("/contracts/{}/changes".format(self.contract["id"]))
    self.assertEqual(response.status, "200 OK")
    self.assertEqual(len(response.json["data"]), 1)

    response = self.app.post_json(
        "/contracts/{}/changes?acc_token={}".format(self.contract["id"], self.contract_token),
        {"data": {"rationale": "трататата", "rationaleTypes": ["priceReduction"]}},
        status=403,
    )
    self.assertEqual(response.status, "403 Forbidden")
    self.assertEqual(
        response.json["errors"],
        [
            {
                "location": "body",
                "name": "data",
                "description": "Can't create new contract change while any (pending) change exists",
            }
        ],
    )

    response = self.app.patch_json(
        "/contracts/{}/changes/{}?acc_token={}".format(self.contract["id"], change["id"], self.contract_token),
        {"data": {"status": "active", "dateSigned": get_now().isoformat()}},
    )
    self.assertEqual(response.status, "200 OK")
    self.assertEqual(response.json["data"]["status"], "active")

    response = self.app.post_json(
        "/contracts/{}/changes?acc_token={}".format(self.contract["id"], self.contract_token),
        {"data": {"rationale": "трататата", "rationaleTypes": ["non-existing-rationale"]}},
        status=422,
    )
    self.assertEqual(response.status, "422 Unprocessable Entity")
    self.assertEqual(
        response.json["errors"],
        [
            {
                "location": "body",
                "name": "rationaleTypes",
                "description": [
                    [
                        "Value must be one of ['volumeCuts', 'itemPriceVariation', 'qualityImprovement', 'thirdParty', 'durationExtension', 'priceReduction', 'taxRate', 'fiscalYearExtension']."
                    ]
                ],
            }
        ],
    )

    response = self.app.post_json(
        "/contracts/{}/changes?acc_token={}".format(self.contract["id"], self.contract_token),
        {"data": {"rationale": "трататата", "rationaleTypes": ["priceReduction"]}},
    )
    self.assertEqual(response.status, "201 Created")
    change2 = response.json["data"]
    self.assertEqual(change2["status"], "pending")

    response = self.app.get("/contracts/{}/changes".format(self.contract["id"]))
    self.assertEqual(response.status, "200 OK")
    self.assertEqual(len(response.json["data"]), 2)
Ejemplo n.º 33
0
def patch_tender_contract(self):
    self.app.authorization = ("Basic", ("token", ""))
    response = self.app.get("/tenders/{}/contracts".format(self.tender_id))
    contract = response.json["data"][0]

    self.set_status("active.awarded", start_end="end")

    response = self.app.post_json(
        "/tenders/{}/awards/{}/complaints?acc_token={}".format(
            self.tender_id, self.award_id, self.tender_token),
        {
            "data": {
                "title": "complaint title",
                "description": "complaint description",
                "author": test_author,
                "status": "claim",
            }
        },
        status=404,
    )
    self.assertEqual(response.status, "404 Not Found")
    self.assertEqual(response.content_type, "text/plain")

    tender = self.db.get(self.tender_id)
    self.db.save(tender)

    response = self.app.patch_json(
        "/tenders/{}/contracts/{}?acc_token={}".format(self.tender_id,
                                                       contract["id"],
                                                       self.tender_token),
        {"data": {
            "value": {
                "amountNet": contract["value"]["amount"] - 1
            }
        }},
    )
    self.assertEqual(response.status, "200 OK")

    self.app.patch_json(
        "/tenders/{}/contracts/{}?acc_token={}".format(self.tender_id,
                                                       contract["id"],
                                                       self.tender_token),
        {
            "data": {
                "contractID": "myselfID",
                "items": [{
                    "description": "New Description"
                }],
                "suppliers": [{
                    "name": "New Name"
                }],
            }
        },
    )

    response = self.app.get("/tenders/{}/contracts/{}".format(
        self.tender_id, contract["id"]))
    self.assertEqual(response.json["data"]["contractID"],
                     contract["contractID"])
    self.assertEqual(response.json["data"]["items"], contract["items"])
    self.assertEqual(response.json["data"]["suppliers"], contract["suppliers"])

    response = self.app.patch_json(
        "/tenders/{}/contracts/{}?acc_token={}".format(self.tender_id,
                                                       contract["id"],
                                                       self.tender_token),
        {"data": {
            "value": {
                "currency": "USD"
            }
        }},
        status=403,
    )
    self.assertEqual(response.status, "403 Forbidden")
    self.assertEqual(response.json["errors"][0]["description"],
                     "Can't update currency for contract value")

    one_hour_in_furure = (get_now() + timedelta(hours=1)).isoformat()
    response = self.app.patch_json(
        "/tenders/{}/contracts/{}?acc_token={}".format(self.tender_id,
                                                       contract["id"],
                                                       self.tender_token),
        {"data": {
            "dateSigned": one_hour_in_furure
        }},
        status=422,
    )
    self.assertEqual(response.status, "422 Unprocessable Entity")
    self.assertEqual(
        response.json["errors"],
        [{
            u"description":
            [u"Contract signature date can't be in the future"],
            u"location": u"body",
            u"name": u"dateSigned",
        }],
    )

    custom_signature_date = get_now().isoformat()
    response = self.app.patch_json(
        "/tenders/{}/contracts/{}?acc_token={}".format(self.tender_id,
                                                       contract["id"],
                                                       self.tender_token),
        {"data": {
            "dateSigned": custom_signature_date
        }},
    )
    self.assertEqual(response.status, "200 OK")

    response = self.app.patch_json(
        "/tenders/{}/contracts/{}?acc_token={}".format(self.tender_id,
                                                       contract["id"],
                                                       self.tender_token),
        {"data": {
            "status": "active"
        }},
    )
    self.assertEqual(response.status, "200 OK")
    self.assertEqual(response.content_type, "application/json")
    self.assertEqual(response.json["data"]["status"], "active")

    response = self.app.patch_json(
        "/tenders/{}/contracts/{}?acc_token={}".format(self.tender_id,
                                                       contract["id"],
                                                       self.tender_token),
        {"data": {
            "value": {
                "amount": 232
            }
        }},
        status=403,
    )
    self.assertEqual(response.status, "403 Forbidden")
    self.assertEqual(
        response.json["errors"][0]["description"],
        "Can't update contract in current (complete) tender status")

    response = self.app.patch_json(
        "/tenders/{}/contracts/{}?acc_token={}".format(self.tender_id,
                                                       contract["id"],
                                                       self.tender_token),
        {"data": {
            "contractID": "myselfID"
        }},
        status=403,
    )
    self.assertEqual(response.status, "403 Forbidden")
    self.assertEqual(
        response.json["errors"][0]["description"],
        "Can't update contract in current (complete) tender status")

    response = self.app.patch_json(
        "/tenders/{}/contracts/{}?acc_token={}".format(self.tender_id,
                                                       contract["id"],
                                                       self.tender_token),
        {"data": {
            "items": [{
                "description": "New Description"
            }]
        }},
        status=403,
    )
    self.assertEqual(response.status, "403 Forbidden")
    self.assertEqual(
        response.json["errors"][0]["description"],
        "Can't update contract in current (complete) tender status")

    response = self.app.patch_json(
        "/tenders/{}/contracts/{}?acc_token={}".format(self.tender_id,
                                                       contract["id"],
                                                       self.tender_token),
        {"data": {
            "suppliers": [{
                "name": "New Name"
            }]
        }},
        status=403,
    )
    self.assertEqual(response.status, "403 Forbidden")
    self.assertEqual(
        response.json["errors"][0]["description"],
        "Can't update contract in current (complete) tender status")

    response = self.app.patch_json(
        "/tenders/{}/contracts/{}?acc_token={}".format(self.tender_id,
                                                       contract["id"],
                                                       self.tender_token),
        {"data": {
            "status": "active"
        }},
        status=403,
    )
    self.assertEqual(response.status, "403 Forbidden")
    self.assertEqual(response.content_type, "application/json")
    self.assertEqual(
        response.json["errors"][0]["description"],
        "Can't update contract in current (complete) tender status")

    response = self.app.patch_json(
        "/tenders/{}/contracts/some_id?acc_token={}".format(
            self.tender_id, self.tender_token),
        {"data": {
            "status": "active"
        }},
        status=404,
    )
    self.assertEqual(response.status, "404 Not Found")
    self.assertEqual(response.content_type, "application/json")
    self.assertEqual(response.json["status"], "error")
    self.assertEqual(response.json["errors"], [{
        u"description": u"Not Found",
        u"location": u"url",
        u"name": u"contract_id"
    }])

    response = self.app.patch_json(
        "/tenders/some_id/contracts/some_id?acc_token={}".format(
            self.tender_token),
        {"data": {
            "status": "active"
        }},
        status=404,
    )
    self.assertEqual(response.status, "404 Not Found")
    self.assertEqual(response.content_type, "application/json")
    self.assertEqual(response.json["status"], "error")
    self.assertEqual(response.json["errors"], [{
        u"description": u"Not Found",
        u"location": u"url",
        u"name": u"tender_id"
    }])

    response = self.app.get("/tenders/{}/contracts/{}".format(
        self.tender_id, contract["id"]))
    self.assertEqual(response.status, "200 OK")
    self.assertEqual(response.content_type, "application/json")
    self.assertEqual(response.json["data"]["status"], "active")
    self.assertEqual(response.json["data"]["contractID"],
                     contract["contractID"])
    self.assertEqual(response.json["data"]["items"], contract["items"])
    self.assertEqual(response.json["data"]["suppliers"], contract["suppliers"])
    self.assertEqual(response.json["data"]["dateSigned"],
                     custom_signature_date)
def patch_change(self):
    response = self.app.post_json(
        "/contracts/{}/changes?acc_token={}".format(self.contract["id"], self.contract_token),
        {
            "data": {
                "rationale": "причина зміни укр",
                "rationale_en": "change cause en",
                "rationaleTypes": ["priceReduction"],
                "contractNumber": "№ 146",
            }
        },
    )
    self.assertEqual(response.status, "201 Created")
    self.assertEqual(response.content_type, "application/json")
    change = response.json["data"]
    self.assertEqual(change["status"], "pending")
    self.assertEqual(change["contractNumber"], "№ 146")
    creation_date = change["date"]

    now = get_now().isoformat()
    response = self.app.patch_json(
        "/contracts/{}/changes/{}?acc_token={}".format(self.contract["id"], change["id"], self.contract_token),
        {"data": {"date": now}},
    )
    self.assertEqual(response.status, "200 OK")
    self.assertEqual(response.body, b"null")

    response = self.app.patch_json(
        "/contracts/{}/changes/{}?acc_token={}".format(self.contract["id"], change["id"], self.contract_token),
        {"data": {"rationale_ru": "шота на руськом"}},
    )
    self.assertEqual(response.status, "200 OK")
    self.assertIn("rationale_ru", response.json["data"])
    first_patch_date = response.json["data"]["date"]
    self.assertEqual(first_patch_date, creation_date)

    response = self.app.patch_json(
        "/contracts/{}/changes/{}?acc_token={}".format(self.contract["id"], change["id"], self.contract_token),
        {"data": {"rationale_en": "another cause desctiption"}},
    )
    self.assertEqual(response.status, "200 OK")
    self.assertEqual(response.json["data"]["rationale_en"], "another cause desctiption")
    second_patch_date = response.json["data"]["date"]
    self.assertEqual(first_patch_date, second_patch_date)

    response = self.app.patch_json(
        "/contracts/{}/changes/{}?acc_token={}".format(self.contract["id"], change["id"], self.contract_token),
        {"data": {"rationaleTypes": ["fiscalYearExtension", "priceReduction"]}},
    )
    self.assertEqual(response.status, "200 OK")
    self.assertEqual(response.json["data"]["rationaleTypes"], ["fiscalYearExtension", "priceReduction"])

    response = self.app.patch_json(
        "/contracts/{}/changes/{}?acc_token={}".format(self.contract["id"], change["id"], self.contract_token),
        {"data": {"rationaleTypes": ["fiscalYearExtension", "volumeCuts", "taxRate"]}},
    )
    self.assertEqual(response.status, "200 OK")
    self.assertEqual(response.json["data"]["rationaleTypes"], ["fiscalYearExtension", "volumeCuts", "taxRate"])

    response = self.app.patch_json(
        "/contracts/{}/changes/{}?acc_token={}".format(self.contract["id"], change["id"], self.contract_token),
        {"data": {"rationaleTypes": "fiscalYearExtension"}},
    )
    self.assertEqual(response.status, "200 OK")
    self.assertEqual(response.json["data"]["rationaleTypes"], ["fiscalYearExtension"])

    response = self.app.patch_json(
        "/contracts/{}/changes/{}?acc_token={}".format(self.contract["id"], change["id"], self.contract_token),
        {"data": {"rationaleTypes": "fiscalYearExtension, volumeCuts"}},
        status=422,
    )
    self.assertEqual(response.status, "422 Unprocessable Entity")
    self.assertEqual(
        response.json["errors"],
        [
            {
                "location": "body",
                "name": "rationaleTypes",
                "description": [
                    [
                        "Value must be one of ['volumeCuts', 'itemPriceVariation', 'qualityImprovement', 'thirdParty', 'durationExtension', 'priceReduction', 'taxRate', 'fiscalYearExtension']."
                    ]
                ],
            }
        ],
    )

    response = self.app.patch_json(
        "/contracts/{}/changes/{}?acc_token={}".format(self.contract["id"], change["id"], self.contract_token),
        {"data": {"rationaleTypes": []}},
        status=422,
    )
    self.assertEqual(response.status, "422 Unprocessable Entity")
    self.assertEqual(
        response.json["errors"],
        [{"location": "body", "name": "rationaleTypes", "description": ["Please provide at least 1 item."]}],
    )

    response = self.app.patch_json(
        "/contracts/{}/changes/{}?acc_token={}".format(self.contract["id"], change["id"], self.contract_token),
        {"data": {"id": "1234" * 8}},
    )
    self.assertEqual(response.status, "200 OK")
    self.assertEqual(response.body, b"null")

    self.app.authorization = None
    response = self.app.patch_json(
        "/contracts/{}/changes/{}?acc_token={}".format(self.contract["id"], change["id"], self.contract_token),
        {"data": {"rationale_en": "la-la-la"}},
        status=403,
    )
    self.assertEqual(response.status, "403 Forbidden")

    self.app.authorization = ("Basic", ("broker", ""))
    response = self.app.patch_json(
        "/contracts/{}/changes/{}".format(self.contract["id"], change["id"]),
        {"data": {"rationale_en": "la-la-la"}},
        status=403,
    )
    self.assertEqual(response.status, "403 Forbidden")

    response = self.app.patch_json(
        "/contracts/{}/changes/{}?acc_token={}".format(self.contract["id"], change["id"], self.contract_token),
        {"data": {"status": "active", "dateSigned": get_now().isoformat()}},
    )
    self.assertEqual(response.status, "200 OK")
    self.assertNotEqual(response.json["data"]["date"], creation_date)
    self.assertNotEqual(response.json["data"]["date"], first_patch_date)
    self.assertNotEqual(response.json["data"]["date"], second_patch_date)

    response = self.app.patch_json(
        "/contracts/{}/changes/{}?acc_token={}".format(self.contract["id"], change["id"], self.contract_token),
        {"data": {"status": "pending"}},
        status=403,
    )
    self.assertEqual(response.status, "403 Forbidden")
Ejemplo n.º 35
0
 def validate_scheme(self, data, scheme):
     schematics_document = get_schematics_document(data['__parent__'])
     if (schematics_document.get('revisions')[0].date if schematics_document.get('revisions') else get_now()) > CPV_BLOCK_FROM and scheme != u'ДК021':
         raise ValidationError(BaseType.MESSAGES['choices'].format(unicode([u'ДК021'])))
def change_date_signed(self):
    response = self.app.post_json(
        "/contracts/{}/changes?acc_token={}".format(self.contract["id"], self.contract_token),
        {
            "data": {
                "rationale": "причина зміни укр",
                "rationale_en": "change cause en",
                "rationaleTypes": ["priceReduction"],
                "contractNumber": "№ 146",
            }
        },
    )
    self.assertEqual(response.status, "201 Created")
    self.assertEqual(response.content_type, "application/json")
    change = response.json["data"]
    self.assertEqual(change["status"], "pending")
    self.assertEqual(change["contractNumber"], "№ 146")

    self.app.authorization = ("Basic", ("broker", ""))
    response = self.app.patch_json(
        "/contracts/{}/changes/{}?acc_token={}".format(self.contract["id"], change["id"], self.contract_token),
        {"data": {"status": "active"}},
        status=403,
    )
    self.assertEqual(response.status, "403 Forbidden")
    self.assertEqual(
        response.json["errors"],
        [
            {
                "location": "body",
                "name": "data",
                "description": "Can't update contract change status. 'dateSigned' is required.",
            }
        ],
    )

    response = self.app.patch_json(
        "/contracts/{}/changes/{}?acc_token={}".format(self.contract["id"], change["id"], self.contract_token),
        {"data": {"dateSigned": "12-14-11"}},
        status=422,
    )
    self.assertEqual(
        response.json["errors"],
        [{"location": "body", "name": "dateSigned", "description": ["Could not parse 12-14-11. Should be ISO8601."]}],
    )

    valid_date1_raw = get_now()
    valid_date1 = valid_date1_raw.isoformat()
    response = self.app.patch_json(
        "/contracts/{}/changes/{}?acc_token={}".format(self.contract["id"], change["id"], self.contract_token),
        {"data": {"dateSigned": valid_date1}},
    )
    self.assertEqual(response.status, "200 OK")
    self.assertEqual(response.json["data"]["dateSigned"], valid_date1)

    one_day_in_past = (get_now() - timedelta(days=1)).isoformat()
    response = self.app.patch_json(
        "/contracts/{}/changes/{}?acc_token={}".format(self.contract["id"], change["id"], self.contract_token),
        {"data": {"dateSigned": one_day_in_past}},
        status=403,
    )
    self.assertIn("can't be earlier than contract dateSigned", response.json["errors"][0]["description"])

    response = self.app.patch_json(
        "/contracts/{}/changes/{}?acc_token={}".format(self.contract["id"], change["id"], self.contract_token),
        {"data": {"status": "active"}},
    )
    self.assertEqual(response.status, "200 OK")

    response = self.app.patch_json(
        "/contracts/{}/changes/{}?acc_token={}".format(self.contract["id"], change["id"], self.contract_token),
        {"data": {"dateSigned": get_now().isoformat()}},
        status=403,
    )
    self.assertEqual(
        response.json["errors"],
        [
            {
                "location": "body",
                "name": "data",
                "description": "Can't update contract change in current (active) status",
            }
        ],
    )

    response = self.app.get("/contracts/{}/changes/{}".format(self.contract["id"], change["id"]))
    change1 = response.json["data"]
    self.assertEqual(change1["dateSigned"], valid_date1)

    response = self.app.post_json(
        "/contracts/{}/changes?acc_token={}".format(self.contract["id"], self.contract_token),
        {
            "data": {
                "rationale": "iнша причина зміни укр",
                "rationale_en": "another change cause en",
                "rationaleTypes": ["priceReduction"],
                "contractNumber": "№ 147",
            }
        },
    )
    self.assertEqual(response.status, "201 Created")
    self.assertEqual(response.content_type, "application/json")
    change2 = response.json["data"]
    self.assertEqual(change["status"], "pending")

    one_day_in_future = (get_now() + timedelta(days=1)).isoformat()
    response = self.app.patch_json(
        "/contracts/{}/changes/{}?acc_token={}".format(self.contract["id"], change2["id"], self.contract_token),
        {"data": {"dateSigned": one_day_in_future}},
        status=422,
    )
    self.assertEqual(
        response.json["errors"],
        [
            {
                "location": "body",
                "name": "dateSigned",
                "description": ["Contract signature date can't be in the future"],
            }
        ],
    )

    smaller_than_last_change = (valid_date1_raw - timedelta(seconds=1)).isoformat()
    response = self.app.patch_json(
        "/contracts/{}/changes/{}?acc_token={}".format(self.contract["id"], change2["id"], self.contract_token),
        {"data": {"dateSigned": smaller_than_last_change}},
        status=403,
    )
    self.assertEqual(
        "Change dateSigned ({}) can't be earlier than last active change dateSigned ({})".format(
            smaller_than_last_change, valid_date1
        ),
        response.json["errors"][0]["description"],
    )

    date = get_now().isoformat()
    response = self.app.patch_json(
        "/contracts/{}/changes/{}?acc_token={}".format(self.contract["id"], change2["id"], self.contract_token),
        {"data": {"dateSigned": date}},
    )
    self.assertEqual(response.status, "200 OK")
    self.assertEqual(response.json["data"]["dateSigned"], date)

    # date update request
    valid_date2_raw = get_now()
    valid_date2 = valid_date2_raw.isoformat()
    response = self.app.patch_json(
        "/contracts/{}/changes/{}?acc_token={}".format(self.contract["id"], change2["id"], self.contract_token),
        {"data": {"dateSigned": valid_date2}},
    )
    self.assertEqual(response.status, "200 OK")
    self.assertEqual(response.json["data"]["dateSigned"], valid_date2)

    response = self.app.patch_json(
        "/contracts/{}/changes/{}?acc_token={}".format(self.contract["id"], change2["id"], self.contract_token),
        {"data": {"status": "active"}},
    )
    self.assertEqual(response.status, "200 OK")
    self.assertEqual(response.json["data"]["dateSigned"], valid_date2)

    response = self.app.post_json(
        "/contracts/{}/changes?acc_token={}".format(self.contract["id"], self.contract_token),
        {
            "data": {
                "rationale": "третя причина зміни укр",
                "rationale_en": "third change cause en",
                "rationaleTypes": ["priceReduction"],
                "contractNumber": "№ 148",
            }
        },
    )
    self.assertEqual(response.status, "201 Created")
    change3 = response.json["data"]
    self.assertEqual(change["status"], "pending")

    smaller_than_last_change = (valid_date2_raw - timedelta(seconds=1)).isoformat()
    response = self.app.patch_json(
        "/contracts/{}/changes/{}?acc_token={}".format(self.contract["id"], change3["id"], self.contract_token),
        {"data": {"dateSigned": smaller_than_last_change}},
        status=403,
    )
    self.assertEqual(
        "Change dateSigned ({}) can't be earlier than last active change dateSigned ({})".format(
            smaller_than_last_change, valid_date2
        ),
        response.json["errors"][0]["description"],
    )

    date = get_now().isoformat()
    response = self.app.patch_json(
        "/contracts/{}/changes/{}?acc_token={}".format(self.contract["id"], change3["id"], self.contract_token),
        {"data": {"dateSigned": date}},
    )
    self.assertEqual(response.status, "200 OK")
    self.assertEqual(response.json["data"]["dateSigned"], date)

    response = self.app.patch_json(
        "/contracts/{}/changes/{}?acc_token={}".format(self.contract["id"], change3["id"], self.contract_token),
        {"data": {"status": "active"}},
    )
    self.assertEqual(response.status, "200 OK")

    response = self.app.patch_json(
        "/contracts/{}?acc_token={}".format(self.contract["id"], self.contract_token),
        {"data": {"value": {"amountNet": self.contract["value"]["amount"] - 1}}},
    )

    response = self.app.patch_json(
        "/contracts/{}?acc_token={}".format(self.contract["id"], self.contract_token),
        {"data": {"status": "terminated", "amountPaid": {"amount": 15, "amountNet": 14}}},
    )
    self.assertEqual(response.status, "200 OK")
 def validate_update_tender(self):
     tender = self.request.validated['tender']
     if calculate_business_date(get_now(), TENDERING_EXTRA_PERIOD, tender, True) > tender.tenderPeriod.endDate:
         raise_operation_error(self.request, 'tenderPeriod should be extended by {0.days} working days'.format(TENDERING_EXTRA_PERIOD))
     return True
def date_signed_on_change_creation(self):
    # test create change with date signed
    one_day_in_past = (get_now() - timedelta(days=1)).isoformat()

    response = self.app.post_json(
        "/contracts/{}/changes?acc_token={}".format(self.contract["id"], self.contract_token),
        {
            "data": {
                "rationale": "причина зміни укр",
                "rationale_en": "change cause en",
                "dateSigned": one_day_in_past,
                "rationaleTypes": ["priceReduction"],
                "contractNumber": "№ 146",
            }
        },
        status=403,
    )
    self.assertIn("can't be earlier than contract dateSigned", response.json["errors"][0]["description"])

    one_day_in_future = (get_now() + timedelta(days=1)).isoformat()
    response = self.app.post_json(
        "/contracts/{}/changes?acc_token={}".format(self.contract["id"], self.contract_token),
        {
            "data": {
                "rationale": "причина зміни укр",
                "rationale_en": "change cause en",
                "dateSigned": one_day_in_future,
                "rationaleTypes": ["priceReduction"],
                "contractNumber": "№ 146",
            }
        },
        status=422,
    )
    self.assertEqual(
        response.json["errors"],
        [
            {
                "location": "body",
                "name": "dateSigned",
                "description": ["Contract signature date can't be in the future"],
            }
        ],
    )

    date = get_now().isoformat()
    response = self.app.post_json(
        "/contracts/{}/changes?acc_token={}".format(self.contract["id"], self.contract_token),
        {
            "data": {
                "rationale": "причина зміни укр",
                "rationale_en": "change cause en",
                "dateSigned": date,
                "rationaleTypes": ["priceReduction"],
                "contractNumber": "№ 146",
            }
        },
    )
    self.assertEqual(response.status, "201 Created")
    self.assertEqual(response.content_type, "application/json")
    change = response.json["data"]
    self.assertEqual(change["dateSigned"], date)

    response = self.app.patch_json(
        "/contracts/{}/changes/{}?acc_token={}".format(self.contract["id"], change["id"], self.contract_token),
        {"data": {"status": "active"}},
    )
    self.assertEqual(response.status, "200 OK")
Ejemplo n.º 39
0
    def test_docs(self):
        request_path = '/tenders?opt_pretty=1'

        # Exploring basic rules

        with open(TARGET_DIR + 'tender-listing.http',
                  'w') as self.app.file_obj:
            self.app.authorization = None
            response = self.app.get(request_path)
            self.assertEqual(response.status, '200 OK')
            self.app.file_obj.write("\n")

        with open(TARGET_DIR + 'tender-post-attempt.http',
                  'w') as self.app.file_obj:
            response = self.app.post(request_path, 'data', status=415)
            self.assertEqual(response.status, '415 Unsupported Media Type')

        with open(TARGET_DIR + 'tender-post-attempt-json.http',
                  'w') as self.app.file_obj:
            self.app.authorization = ('Basic', ('broker', ''))
            response = self.app.post(request_path,
                                     'data',
                                     content_type='application/json',
                                     status=422)
            self.assertEqual(response.status, '422 Unprocessable Entity')

        # Creating tender

        lot = deepcopy(test_lots[0])
        lot['id'] = uuid4().hex
        lot['value'] = test_tender_data['value']
        lot['minimalStep'] = test_tender_data['minimalStep']
        second_item = deepcopy(test_tender_data['items'][0])
        second_item['unit']['code'] = '44617100-8'
        test_tender_data['items'] = [test_tender_data['items'][0], second_item]
        test_tender_data['lots'] = [lot]
        for item in test_tender_data['items']:
            item['relatedLot'] = lot['id']

        test_tender_data.update({
            "tenderPeriod": {
                "endDate": (get_now() + timedelta(days=31)).isoformat()
            }
        })

        self.app.authorization = ('Basic', ('broker', ''))
        with open(TARGET_DIR + 'tender-post-attempt-json-data.http',
                  'w') as self.app.file_obj:
            response = self.app.post_json('/tenders?opt_pretty=1',
                                          {'data': test_tender_data})
            self.assertEqual(response.status, '201 Created')

        tender = response.json['data']
        owner_token = response.json['access']['token']
        self.tender_id = tender['id']

        self.set_status('active.enquiries')

        with open(TARGET_DIR + 'blank-tender-view.http',
                  'w') as self.app.file_obj:
            response = self.app.get('/tenders/{}'.format(tender['id']))
            self.assertEqual(response.status, '200 OK')

        # Let DB index new tender
        self.app.get('/tenders')
        sleep(2)

        with open(TARGET_DIR + 'initial-tender-listing.http',
                  'w') as self.app.file_obj:
            response = self.app.get('/tenders')
            self.assertEqual(response.status, '200 OK')

        self.app.authorization = ('Basic', ('broker', ''))

        # Modifying tender

        tenderPeriod_endDate = get_now() + timedelta(days=30, seconds=10)
        with open(TARGET_DIR + 'patch-items-value-periods.http',
                  'w') as self.app.file_obj:
            response = self.app.patch_json(
                '/tenders/{}?acc_token={}'.format(tender['id'], owner_token), {
                    'data': {
                        "tenderPeriod": {
                            "endDate": tenderPeriod_endDate.isoformat()
                        }
                    }
                })

        with open(TARGET_DIR + 'tender-listing-after-patch.http',
                  'w') as self.app.file_obj:
            self.app.authorization = None
            response = self.app.get(request_path)
            self.assertEqual(response.status, '200 OK')

        self.app.authorization = ('Basic', ('broker', ''))

        # Setting Bid guarantee

        with open(TARGET_DIR + 'set-bid-guarantee.http',
                  'w') as self.app.file_obj:
            response = self.app.patch_json(
                '/tenders/{}/lots/{}?acc_token={}'.format(
                    self.tender_id, lot['id'], owner_token),
                {"data": {
                    "guarantee": {
                        "amount": 8,
                        "currency": "USD"
                    }
                }})
            self.assertEqual(response.status, '200 OK')
            self.assertIn('guarantee', response.json['data'])

        # Uploading documentation

        with open(TARGET_DIR + 'upload-tender-notice.http',
                  'w') as self.app.file_obj:
            response = self.app.post(
                '/tenders/{}/documents?acc_token={}'.format(
                    self.tender_id, owner_token),
                upload_files=[('file', u'Notice.pdf', 'content')])
            self.assertEqual(response.status, '201 Created')

        doc_id = response.json["data"]["id"]
        with open(TARGET_DIR + 'tender-documents.http',
                  'w') as self.app.file_obj:
            response = self.app.get(
                '/tenders/{}/documents/{}?acc_token={}'.format(
                    self.tender_id, doc_id, owner_token))
            self.assertEqual(response.status, '200 OK')

        with open(TARGET_DIR + 'upload-award-criteria.http',
                  'w') as self.app.file_obj:
            response = self.app.post(
                '/tenders/{}/documents?acc_token={}'.format(
                    self.tender_id, owner_token),
                upload_files=[('file', u'AwardCriteria.pdf', 'content')])
            self.assertEqual(response.status, '201 Created')

        doc_id = response.json["data"]["id"]

        with open(TARGET_DIR + 'tender-documents-2.http',
                  'w') as self.app.file_obj:
            response = self.app.get(
                '/tenders/{}/documents?acc_token={}'.format(
                    self.tender_id, owner_token))
            self.assertEqual(response.status, '200 OK')

        with open(TARGET_DIR + 'update-award-criteria.http',
                  'w') as self.app.file_obj:
            response = self.app.put(
                '/tenders/{}/documents/{}?acc_token={}'.format(
                    self.tender_id, doc_id, owner_token),
                upload_files=[('file', 'AwardCriteria-2.pdf', 'content2')])
            self.assertEqual(response.status, '200 OK')

        with open(TARGET_DIR + 'tender-documents-3.http',
                  'w') as self.app.file_obj:
            response = self.app.get('/tenders/{}/documents'.format(
                self.tender_id))
            self.assertEqual(response.status, '200 OK')

        # Enquiries

        with open(TARGET_DIR + 'ask-question.http', 'w') as self.app.file_obj:
            response = self.app.post_json('/tenders/{}/questions'.format(
                self.tender_id), {'data': question},
                                          status=201)
            question_id = response.json['data']['id']
            self.assertEqual(response.status, '201 Created')

        with open(TARGET_DIR + 'answer-question.http',
                  'w') as self.app.file_obj:
            response = self.app.patch_json(
                '/tenders/{}/questions/{}?acc_token={}'.format(
                    self.tender_id, question_id, owner_token),
                {
                    "data": {
                        "answer": "Таблицю додано в файлі \"Kalorijnist.xslx\""
                    }
                },
                status=200)
            self.assertEqual(response.status, '200 OK')

        with open(TARGET_DIR + 'list-question.http', 'w') as self.app.file_obj:
            response = self.app.get('/tenders/{}/questions'.format(
                self.tender_id))
            self.assertEqual(response.status, '200 OK')

        with open(TARGET_DIR + 'get-answer.http', 'w') as self.app.file_obj:
            response = self.app.get('/tenders/{}/questions/{}'.format(
                self.tender_id, question_id))
            self.assertEqual(response.status, '200 OK')

        self.time_shift('enquiryPeriod_ends')

        self.app.authorization = ('Basic', ('broker', ''))

        with open(TARGET_DIR + 'ask-question-after-enquiry-period.http',
                  'w') as self.app.file_obj:
            response = self.app.post_json('/tenders/{}/questions'.format(
                self.tender_id), {'data': question},
                                          status=403)
            self.assertEqual(response.status, '403 Forbidden')

        with open(
                TARGET_DIR +
                'update-tender-after-enqiery-with-update-periods.http',
                'w') as self.app.file_obj:
            tenderPeriod_endDate = get_now() + timedelta(days=8)
            response = self.app.patch_json(
                '/tenders/{}?acc_token={}'.format(tender['id'], owner_token), {
                    'data': {
                        "value": {
                            "amount": 501,
                            "currency": u"UAH"
                        },
                        "tenderPeriod": {
                            "endDate": tenderPeriod_endDate.isoformat()
                        }
                    }
                })
            self.assertEqual(response.status, '200 OK')

        # Registering bid

        bids_access = {}
        with open(TARGET_DIR + 'register-bidder.http',
                  'w') as self.app.file_obj:
            bid['lotValues'][0]['relatedLot'] = lot['id']
            response = self.app.post_json(
                '/tenders/{}/bids'.format(self.tender_id), {'data': bid})
            bid1_id = response.json['data']['id']
            bids_access[bid1_id] = response.json['access']['token']
            self.assertEqual(response.status, '201 Created')

        with open(TARGET_DIR + 'activate-bidder.http',
                  'w') as self.app.file_obj:
            response = self.app.patch_json(
                '/tenders/{}/bids/{}?acc_token={}'.format(
                    self.tender_id, bid1_id, bids_access[bid1_id]),
                {"data": {
                    "status": "pending"
                }})
            self.assertEqual(response.status, '200 OK')

        # Proposal Uploading

        with open(TARGET_DIR + 'upload-bid-proposal.http',
                  'w') as self.app.file_obj:
            response = self.app.post(
                '/tenders/{}/bids/{}/documents?acc_token={}'.format(
                    self.tender_id, bid1_id, bids_access[bid1_id]),
                upload_files=[('file', 'Proposal.pdf', 'content')])
            self.assertEqual(response.status, '201 Created')

        with open(TARGET_DIR + 'upload-bid-private-proposal.http',
                  'w') as self.app.file_obj:
            response = self.app.post(
                '/tenders/{}/bids/{}/documents?acc_token={}'.format(
                    self.tender_id, bid1_id, bids_access[bid1_id]),
                upload_files=[('file', 'Proposal_top_secrets.pdf', 'content')])
            self.assertEqual(response.status, '201 Created')
            priv_doc_id = response.json['data']['id']

        # set confidentiality properties
        with open(TARGET_DIR + 'mark-bid-doc-private.http',
                  'w') as self.app.file_obj:
            response = self.app.patch_json(
                '/tenders/{}/bids/{}/documents/{}?acc_token={}'.format(
                    self.tender_id, bid1_id, priv_doc_id,
                    bids_access[bid1_id]), {
                        'data': {
                            'confidentiality':
                            'buyerOnly',
                            'confidentialityRationale':
                            'Only our company sells badgers with pink hair.',
                        }
                    })
            self.assertEqual(response.status, '200 OK')

        with open(TARGET_DIR + 'bidder-documents.http',
                  'w') as self.app.file_obj:
            response = self.app.get(
                '/tenders/{}/bids/{}/documents?acc_token={}'.format(
                    self.tender_id, bid1_id, bids_access[bid1_id]))

        with open(TARGET_DIR + 'upload-bid-financial-document-proposal.http',
                  'w') as self.app.file_obj:
            response = self.app.post(
                '/tenders/{}/bids/{}/financial_documents?acc_token={}'.format(
                    self.tender_id, bid1_id, bids_access[bid1_id]),
                upload_files=[('file', 'financial_doc.pdf', '1000$')])
            self.assertEqual(response.status, '201 Created')

        response = self.app.post(
            '/tenders/{}/bids/{}/financial_documents?acc_token={}'.format(
                self.tender_id, bid1_id, bids_access[bid1_id]),
            upload_files=[('file', 'financial_doc2.pdf', '1000$')])
        self.assertEqual(response.status, '201 Created')
        # financial_doc_id = response.json['data']['id']

        with open(TARGET_DIR + 'bidder-financial-documents.http',
                  'w') as self.app.file_obj:
            response = self.app.get(
                '/tenders/{}/bids/{}/financial_documents?acc_token={}'.format(
                    self.tender_id, bid1_id, bids_access[bid1_id]))
            self.assertEqual(response.status, '200 OK')

        with open(TARGET_DIR + 'upload-bid-eligibility-document-proposal.http',
                  'w') as self.app.file_obj:
            response = self.app.post(
                '/tenders/{}/bids/{}/eligibility_documents?acc_token={}'.
                format(self.tender_id, bid1_id, bids_access[bid1_id]),
                upload_files=[('file', 'eligibility_doc.pdf', 'content')])
            self.assertEqual(response.status, '201 Created')

        with open(
                TARGET_DIR + 'upload-bid-qualification-document-proposal.http',
                'w') as self.app.file_obj:
            response = self.app.post(
                '/tenders/{}/bids/{}/qualification_documents?acc_token={}'.
                format(self.tender_id, bid1_id, bids_access[bid1_id]),
                upload_files=[('file', 'qualification_document.pdf', 'content')
                              ])
            self.assertEqual(response.status, '201 Created')
            self.qualification_doc_id = response.json['data']['id']
        #  patch bid document by user
        with open(
                TARGET_DIR +
                'upload-bid-qualification-document-proposal-updated.http',
                'w') as self.app.file_obj:
            response = self.app.put(
                '/tenders/{}/bids/{}/qualification_documents/{}?acc_token={}'.
                format(self.tender_id, bid1_id, self.qualification_doc_id,
                       bids_access[bid1_id]),
                upload_files=[('file', 'qualification_document2.pdf',
                               'content')])
            self.assertEqual(response.status, '200 OK')

        with open(TARGET_DIR + 'bidder-view-financial-documents.http',
                  'w') as self.app.file_obj:
            response = self.app.get('/tenders/{}/bids/{}?acc_token={}'.format(
                self.tender_id, bid1_id, bids_access[bid1_id]))
            self.assertEqual(response.status, '200 OK')

        response = self.app.patch_json(
            '/tenders/{}?acc_token={}'.format(tender['id'], owner_token),
            {'data': {
                "value": {
                    'amount': 501.0
                }
            }})
        self.assertEqual(response.status, '200 OK')

        # Bid invalidation

        with open(TARGET_DIR + 'bidder-after-changing-tender.http',
                  'w') as self.app.file_obj:
            response = self.app.get('/tenders/{}/bids/{}?acc_token={}'.format(
                self.tender_id, bid1_id, bids_access[bid1_id]))
            self.assertEqual(response.status, '200 OK')

        # Bid confirmation

        with open(TARGET_DIR + 'bidder-activate-after-changing-tender.http',
                  'w') as self.app.file_obj:
            response = self.app.patch_json(
                '/tenders/{}/bids/{}?acc_token={}'.format(
                    self.tender_id, bid1_id, bids_access[bid1_id]),
                {'data': {
                    "status": "pending"
                }})
            self.assertEqual(response.status, '200 OK')

        with open(TARGET_DIR + 'register-2nd-bidder.http',
                  'w') as self.app.file_obj:
            bid2['lotValues'][0]['relatedLot'] = lot['id']
            response = self.app.post_json(
                '/tenders/{}/bids'.format(self.tender_id), {'data': bid2})
            bid2_id = response.json['data']['id']
            bids_access[bid2_id] = response.json['access']['token']
            self.assertEqual(response.status, '201 Created')

        bid_document2.update({
            'confidentiality':
            'buyerOnly',
            'confidentialityRationale':
            'Only our company sells badgers with pink hair.'
        })
        bid3["documents"] = [bid_document, bid_document2]
        bid3['lotValues'][0]['relatedLot'] = lot['id']
        for document in bid3['documents']:
            document['url'] = self.generate_docservice_url()
        for document in bid3['eligibilityDocuments']:
            document['url'] = self.generate_docservice_url()
        for document in bid3['financialDocuments']:
            document['url'] = self.generate_docservice_url()
        for document in bid3['qualificationDocuments']:
            document['url'] = self.generate_docservice_url()

        with open(TARGET_DIR + 'register-3rd-bidder.http',
                  'w') as self.app.file_obj:
            response = self.app.post_json(
                '/tenders/{}/bids'.format(self.tender_id), {'data': bid3})
            bid3_id = response.json['data']['id']
            bids_access[bid3_id] = response.json['access']['token']
            self.assertEqual(response.status, '201 Created')

        with open(TARGET_DIR + 'register-4rd-bidder.http',
                  'w') as self.app.file_obj:
            response = self.app.post_json(
                '/tenders/{}/bids'.format(self.tender_id), {'data': bid3})
            bid4_id = response.json['data']['id']
            bids_access[bid4_id] = response.json['access']['token']
            self.assertEqual(response.status, '201 Created')

        # Pre-qualification

        self.set_status('active.pre-qualification')
        auth = self.app.authorization
        self.app.authorization = ('Basic', ('chronograph', ''))
        response = self.app.patch_json('/tenders/{}'.format(self.tender_id),
                                       {'data': {
                                           "id": self.tender_id
                                       }})
        self.app.authorization = auth

        with open(TARGET_DIR + 'qualifications-listing.http',
                  'w') as self.app.file_obj:
            response = self.app.get('/tenders/{}/qualifications'.format(
                self.tender_id))
            self.assertEqual(response.status, "200 OK")
            qualifications = response.json['data']
            self.assertEqual(len(qualifications), 4)
            self.assertEqual(qualifications[0]['bidID'], bid1_id)
            self.assertEqual(qualifications[1]['bidID'], bid2_id)
            self.assertEqual(qualifications[2]['bidID'], bid3_id)
            self.assertEqual(qualifications[3]['bidID'], bid4_id)

        with open(TARGET_DIR + 'approve-qualification1.http',
                  'w') as self.app.file_obj:
            response = self.app.patch_json(
                '/tenders/{}/qualifications/{}?acc_token={}'.format(
                    self.tender_id, qualifications[0]['id'], owner_token), {
                        "data": {
                            "status": "active",
                            "qualified": True,
                            "eligible": True
                        }
                    })
            self.assertEqual(response.status, "200 OK")
        with open(TARGET_DIR + 'approve-qualification2.http',
                  'w') as self.app.file_obj:
            response = self.app.patch_json(
                '/tenders/{}/qualifications/{}?acc_token={}'.format(
                    self.tender_id, qualifications[1]['id'], owner_token), {
                        "data": {
                            "status": "active",
                            "qualified": True,
                            "eligible": True
                        }
                    })
            self.assertEqual(response.status, "200 OK")

        with open(TARGET_DIR + 'approve-qualification4.http',
                  'w') as self.app.file_obj:
            response = self.app.patch_json(
                '/tenders/{}/qualifications/{}?acc_token={}'.format(
                    self.tender_id, qualifications[3]['id'], owner_token), {
                        "data": {
                            "status": "active",
                            "qualified": True,
                            "eligible": True
                        }
                    })
            self.assertEqual(response.status, "200 OK")

        with open(TARGET_DIR + 'reject-qualification3.http',
                  'w') as self.app.file_obj:
            response = self.app.patch_json(
                '/tenders/{}/qualifications/{}?acc_token={}'.format(
                    self.tender_id, qualifications[2]['id'], owner_token),
                {"data": {
                    "status": "unsuccessful"
                }})
            self.assertEqual(response.status, "200 OK")

        with open(TARGET_DIR + 'qualificated-bids-view.http',
                  'w') as self.app.file_obj:
            response = self.app.get('/tenders/{}/bids?acc_token={}'.format(
                self.tender_id, owner_token))
            self.assertEqual(response.status, "200 OK")

        with open(TARGET_DIR + 'rejected-bid-view.http',
                  'w') as self.app.file_obj:
            response = self.app.get('/tenders/{}/bids/{}?acc_token={}'.format(
                self.tender_id, bid3_id, owner_token))
            self.assertEqual(response.status, "200 OK")

        # active.pre-qualification.stand-still

        with open(TARGET_DIR + 'pre-qualification-confirmation.http',
                  'w') as self.app.file_obj:
            response = self.app.patch_json(
                '/tenders/{}?acc_token={}'.format(self.tender_id, owner_token),
                {"data": {
                    "status": "active.pre-qualification.stand-still"
                }})
            self.assertEqual(response.status, "200 OK")
            self.assertEqual(response.json['data']['status'],
                             "active.pre-qualification.stand-still")

        # Auction

        self.set_status('active.auction')
        self.app.authorization = ('Basic', ('auction', ''))
        auction_url = u'{}/tenders/{}_{}'.format(self.auctions_url,
                                                 self.tender_id, lot['id'])
        patch_data = {
            'lots': [{
                'auctionUrl': auction_url,
            }],
            'bids': [{
                "id":
                bid1_id,
                "lotValues": [{
                    "participationUrl":
                    u'{}?key_for_bid={}'.format(auction_url, bid1_id)
                }]
            }, {
                "id":
                bid2_id,
                "lotValues": [{
                    "participationUrl":
                    u'{}?key_for_bid={}'.format(auction_url, bid2_id)
                }]
            }, {
                "id": bid3_id,
            }, {
                "id":
                bid4_id,
                "lotValues": [{
                    "participationUrl":
                    u'{}?key_for_bid={}'.format(auction_url, bid4_id)
                }]
            }]
        }
        response = self.app.patch_json(
            '/tenders/{}/auction/{}?acc_token={}'.format(
                self.tender_id, lot['id'], owner_token), {'data': patch_data})
        self.assertEqual(response.status, '200 OK')

        self.app.authorization = ('Basic', ('broker', ''))

        with open(TARGET_DIR + 'auction-url.http', 'w') as self.app.file_obj:
            response = self.app.get('/tenders/{}'.format(self.tender_id))
            self.assertEqual(response.status, '200 OK')

        with open(TARGET_DIR + 'bidder-participation-url.http',
                  'w') as self.app.file_obj:
            response = self.app.get('/tenders/{}/bids/{}?acc_token={}'.format(
                self.tender_id, bid1_id, bids_access[bid1_id]))
            self.assertEqual(response.status, '200 OK')

        with open(TARGET_DIR + 'bidder2-participation-url.http',
                  'w') as self.app.file_obj:
            response = self.app.get('/tenders/{}/bids/{}?acc_token={}'.format(
                self.tender_id, bid2_id, bids_access[bid2_id]))
            self.assertEqual(response.status, '200 OK')

        with open(TARGET_DIR + 'bidder4-participation-url.http',
                  'w') as self.app.file_obj:
            response = self.app.get('/tenders/{}/bids/{}?acc_token={}'.format(
                self.tender_id, bid4_id, bids_access[bid4_id]))
            self.assertEqual(response.status, '200 OK')

        # Confirming qualification
        self.app.authorization = ('Basic', ('auction', ''))
        response = self.app.get('/tenders/{}/auction'.format(self.tender_id))
        auction_bids_data = response.json['data']['bids']
        response = self.app.post_json(
            '/tenders/{}/auction/{}'.format(self.tender_id, lot['id']),
            {'data': {
                'bids': auction_bids_data
            }})

        self.app.authorization = ('Basic', ('broker', ''))

        with open(TARGET_DIR + 'qualifications-list.http',
                  'w') as self.app.file_obj:
            response = self.app.get('/tenders/{}/awards?acc_token={}'.format(
                self.tender_id, owner_token))
        # get pending award
        award_ids = [
            i['id'] for i in response.json['data'] if i['status'] == 'pending'
        ]

        with open(TARGET_DIR + 'confirm-qualification.http',
                  'w') as self.app.file_obj:
            self.app.patch_json(
                '/tenders/{}/awards/{}?acc_token={}'.format(
                    self.tender_id, award_ids[0], owner_token), {
                        "data": {
                            "status": "active",
                            "qualified": True,
                            "eligible": True
                        }
                    })
            self.assertEqual(response.status, '200 OK')

        # Fill Agreement unit prices

        for award_id in award_ids[1:]:
            self.app.patch_json(
                '/tenders/{}/awards/{}?acc_token={}'.format(
                    self.tender_id, award_id, owner_token), {
                        "data": {
                            "status": "active",
                            "qualified": True,
                            "eligible": True
                        }
                    })

        #  patch award to cancelled
        with open(TARGET_DIR + 'patch-award-cancelled.http',
                  'w') as self.app.file_obj:
            self.app.patch_json(
                '/tenders/{}/awards/{}?acc_token={}'.format(
                    self.tender_id, award_ids[0], owner_token),
                {'data': {
                    "status": "cancelled"
                }})
            self.assertEqual(response.status, '200 OK')

        with open(TARGET_DIR + 'qualifications-list2.http',
                  'w') as self.app.file_obj:
            response = self.app.get('/tenders/{}/awards?acc_token={}'.format(
                self.tender_id, owner_token))
        # get pending award
        award_ids = [
            i['id'] for i in response.json['data'] if i['status'] == 'pending'
        ]

        #  patch pending award to unsuccessful
        with open(TARGET_DIR + 'patch-award-unsuccessful.http',
                  'w') as self.app.file_obj:
            self.app.patch_json(
                '/tenders/{}/awards/{}?acc_token={}'.format(
                    self.tender_id, award_ids[0], owner_token),
                {'data': {
                    "status": "unsuccessful"
                }})
            self.assertEqual(response.status, '200 OK')

        #  patch unsuccessful award to cancelled
        with open(TARGET_DIR + 'patch-award-unsuccessful-cancelled.http',
                  'w') as self.app.file_obj:
            self.app.patch_json(
                '/tenders/{}/awards/{}?acc_token={}'.format(
                    self.tender_id, award_ids[0], owner_token),
                {'data': {
                    "status": "cancelled"
                }})
            self.assertEqual(response.status, '200 OK')

        with open(TARGET_DIR + 'qualifications-list3.http',
                  'w') as self.app.file_obj:
            response = self.app.get('/tenders/{}/awards?acc_token={}'.format(
                self.tender_id, owner_token))
        # get pending award
        award_ids = [
            i['id'] for i in response.json['data'] if i['status'] == 'pending'
        ]

        with open(TARGET_DIR + 'confirm-qualification2.http',
                  'w') as self.app.file_obj:
            self.app.patch_json(
                '/tenders/{}/awards/{}?acc_token={}'.format(
                    self.tender_id, award_ids[0], owner_token), {
                        "data": {
                            "status": "active",
                            "qualified": True,
                            "eligible": True
                        }
                    })
            self.assertEqual(response.status, '200 OK')

        for award_id in award_ids[1:]:
            self.app.patch_json(
                '/tenders/{}/awards/{}?acc_token={}'.format(
                    self.tender_id, award_id, owner_token), {
                        "data": {
                            "status": "active",
                            "qualified": True,
                            "eligible": True
                        }
                    })

        self.set_status('active.awarded')

        with open(TARGET_DIR + 'upload-prices-document.http',
                  'w') as self.app.file_obj:
            response = self.app.post(
                '/tenders/{}/bids/{}/financial_documents?acc_token={}'.format(
                    self.tender_id, bid1_id, bids_access[bid1_id]),
                upload_files=[('file', 'prices.xlsx', '<raw_file_data>')])

        with open(TARGET_DIR + 'agreements-list.http',
                  'w') as self.app.file_obj:
            response = self.app.get('/tenders/{}/agreements'.format(
                self.tender_id))
        agreement_id = response.json['data'][0]['id']

        with open(TARGET_DIR + 'agreement-contracts-list.http',
                  'w') as self.app.file_obj:
            response = self.app.get(
                '/tenders/{}/agreements/{}/contracts?acc_token={}'.format(
                    self.tender_id, agreement_id, owner_token))

        contracts = response.json['data']
        i = 1
        for contract in contracts:
            j = 0.5
            unit_prices = []
            for unit_price in contract['unitPrices']:
                unit_prices.append({
                    'relatedItem': unit_price['relatedItem'],
                    'value': {
                        'amount': j
                    }
                })
            with open(
                    TARGET_DIR +
                    'agreement-contract-unitprices{}.http'.format(i),
                    'w') as self.app.file_obj:
                response = self.app.patch_json(
                    '/tenders/{}/agreements/{}/contracts/{}?acc_token={}'.
                    format(self.tender_id, agreement_id, contract['id'],
                           owner_token), {'data': {
                               'unitPrices': unit_prices
                           }})
            i += 1

        # Time travel to agreement.contractPeriod.clarificationsUntil
        tender = self.db.get(self.tender_id)
        tender['contractPeriod']['startDate'] = (
            get_now() - CLARIFICATIONS_UNTIL_PERIOD -
            timedelta(days=1)).isoformat()
        tender['contractPeriod']['clarificationsUntil'] = (
            get_now() - timedelta(days=1)).isoformat()
        self.db.save(tender)

        # Uploading contract documentation

        with open(TARGET_DIR + 'tender-agreement-upload-document.http',
                  'w') as self.app.file_obj:
            response = self.app.post(
                '/tenders/{}/agreements/{}/documents?acc_token={}'.format(
                    self.tender_id, agreement_id, owner_token),
                upload_files=[('file', 'agreement_first_document.doc',
                               'content')])
            self.assertEqual(response.status, '201 Created')

        with open(TARGET_DIR + 'tender-agreement-get-documents.http',
                  'w') as self.app.file_obj:
            response = self.app.get(
                '/tenders/{}/agreements/{}/documents'.format(
                    self.tender_id, agreement_id))
        self.assertEqual(response.status, '200 OK')

        with open(TARGET_DIR + 'tender-agreement-upload-second-document.http',
                  'w') as self.app.file_obj:
            response = self.app.post(
                '/tenders/{}/agreements/{}/documents?acc_token={}'.format(
                    self.tender_id, agreement_id, owner_token),
                upload_files=[('file', 'agreement_second_document.doc',
                               'content')])
            self.assertEqual(response.status, '201 Created')
            self.document_id = response.json['data']['id']

        with open(TARGET_DIR + 'tender-agreement-patch-document.http',
                  'w') as self.app.file_obj:
            response = self.app.patch_json(
                '/tenders/{}/agreements/{}/documents/{}?acc_token={}'.format(
                    self.tender_id, agreement_id, self.document_id,
                    owner_token), {
                        'data': {
                            "language": 'en',
                            'title_en': 'Title of Document',
                            'description_en': 'Description of Document'
                        }
                    })
            self.assertEqual(response.status, '200 OK')

        with open(TARGET_DIR + 'tender-agreement-get-documents-again.http',
                  'w') as self.app.file_obj:
            response = self.app.get(
                '/tenders/{}/agreements/{}/documents'.format(
                    self.tender_id, agreement_id))
        self.assertEqual(response.status, '200 OK')

        with open(TARGET_DIR + 'tender-agreement-get.http',
                  'w') as self.app.file_obj:
            response = self.app.get(
                '/tenders/{}/agreements/{}?acc_token={}'.format(
                    self.tender_id, agreement_id, owner_token))
            self.assertEqual(response.status, '200 OK')

        # Agreement signing

        self.tick()

        with open(TARGET_DIR + 'tender-agreement-sign-date.http',
                  'w') as self.app.file_obj:
            response = self.app.patch_json(
                '/tenders/{}/agreements/{}?acc_token={}'.format(
                    self.tender_id, agreement_id, owner_token),
                {"data": {
                    "dateSigned": get_now().isoformat()
                }})
        self.assertIn('dateSigned', response.json['data'])

        with open(TARGET_DIR + 'tender-agreement-sign.http',
                  'w') as self.app.file_obj:
            response = self.app.patch_json(
                '/tenders/{}/agreements/{}?acc_token={}'.format(
                    self.tender_id, agreement_id, owner_token),
                {
                    "data": {
                        "status": "active",
                        "period": {
                            "startDate":
                            get_now().isoformat(),
                            "endDate":
                            (get_now() + timedelta(days=4 * 365)).isoformat()
                        }
                    }
                })
        self.assertEqual(response.json['data']['status'], 'active')

        with open(TARGET_DIR + 'tender-completed.http',
                  'w') as self.app.file_obj:
            response = self.app.get('/tenders/{}'.format(self.tender_id))
        self.assertEqual(response.json['data']['status'], 'complete')
        # self.contract_id = response.json['data'][0]['id']

        # Rollback agreement signing
        tender = self.db.get(self.tender_id)
        tender['status'] = 'active.tendering'
        tender['agreements'][0]['status'] = 'pending'
        self.db.save(tender)

        # Preparing the cancellation request
        with open(TARGET_DIR + 'prepare-cancellation.http',
                  'w') as self.app.file_obj:
            response = self.app.post_json(
                '/tenders/{}/cancellations?acc_token={}'.format(
                    self.tender_id, owner_token), {
                        'data': {
                            'reason': 'cancellation reason',
                            'reasonType': 'noDemand'
                        }
                    })
            self.assertEqual(response.status, '201 Created')

        cancellation_id = response.json['data']['id']

        with open(TARGET_DIR + 'update-cancellation-reasonType.http',
                  'w') as self.app.file_obj:
            response = self.app.patch_json(
                '/tenders/{}/cancellations/{}?acc_token={}'.format(
                    self.tender_id, cancellation_id, owner_token),
                {"data": {
                    'reasonType': 'unFixable'
                }})
            self.assertEqual(response.status, '200 OK')

        # Filling cancellation with protocol and supplementary documentation

        with open(TARGET_DIR + 'upload-cancellation-doc.http',
                  'w') as self.app.file_obj:
            response = self.app.post(
                '/tenders/{}/cancellations/{}/documents?acc_token={}'.format(
                    self.tender_id, cancellation_id, owner_token),
                upload_files=[('file', u'Notice.pdf', 'content')])
            cancellation_doc_id = response.json['data']['id']
            self.assertEqual(response.status, '201 Created')

        with open(TARGET_DIR + 'patch-cancellation.http',
                  'w') as self.app.file_obj:
            response = self.app.patch_json(
                '/tenders/{}/cancellations/{}/documents/{}?acc_token={}'.
                format(self.tender_id, cancellation_id, cancellation_doc_id,
                       owner_token),
                {'data': {
                    "description": 'Changed description'
                }})
            self.assertEqual(response.status, '200 OK')

        with open(TARGET_DIR + 'update-cancellation-doc.http',
                  'w') as self.app.file_obj:
            response = self.app.put(
                '/tenders/{}/cancellations/{}/documents/{}?acc_token={}'.
                format(self.tender_id, cancellation_id, cancellation_doc_id,
                       owner_token),
                upload_files=[('file', 'Notice-2.pdf', 'content2')])
            self.assertEqual(response.status, '200 OK')

        # Activating the request and cancelling tender
        with open(TARGET_DIR + 'pending-cancellation.http',
                  'w') as self.app.file_obj:
            response = self.app.patch_json(
                '/tenders/{}/cancellations/{}?acc_token={}'.format(
                    self.tender_id, cancellation_id, owner_token),
                {'data': {
                    "status": "pending"
                }})
            self.assertEqual(response.status, '200 OK')

        self.tick(delta=timedelta(days=11))
        self.check_chronograph()

        with open(TARGET_DIR + 'active-cancellation.http',
                  'w') as self.app.file_obj:
            response = self.app.get(
                '/tenders/{}/cancellations/{}?acc_token={}'.format(
                    self.tender_id, cancellation_id, owner_token))
            self.assertEqual(response.status, '200 OK')

        # transfer agreement to unsuccessful
        tender = self.db.get(self.tender_id)
        tender['status'] = 'active.awarded'
        tender['agreements'][0]['status'] = 'pending'
        del tender['cancellations']
        self.db.save(tender)

        with open(TARGET_DIR + 'agreement-unsuccessful.http',
                  'w') as self.app.file_obj:
            response = self.app.patch_json(
                '/tenders/{}/agreements/{}?acc_token={}'.format(
                    self.tender_id, agreement_id, owner_token),
                {"data": {
                    "status": "unsuccessful"
                }})
            self.assertEqual(response.status, '200 OK')

        with open(TARGET_DIR + 'tender-unsuccessful.http',
                  'w') as self.app.file_obj:
            response = self.app.get('/tenders/{}'.format(self.tender_id))
            self.assertEqual(response.status, '200 OK')
def change_date_signed_very_old_contracts_data(self):
    # prepare old contract data
    contract = self.databases.contracts.get(self.contract["id"])
    contract["dateSigned"] = None
    self.databases.contracts.save(contract)

    response = self.app.get("/contracts/{}?acc_token={}".format(self.contract["id"], self.contract_token))
    self.assertEqual(response.status, "200 OK")
    self.assertNotIn("dateSigned", response.json["data"])

    self.app.authorization = ("Basic", ("broker", ""))
    response = self.app.post_json(
        "/contracts/{}/changes?acc_token={}".format(self.contract["id"], self.contract_token),
        {
            "data": {
                "rationale": "причина зміни укр",
                "rationale_en": "change cause en",
                "rationaleTypes": ["priceReduction"],
                "contractNumber": "№ 146",
            }
        },
    )
    self.assertEqual(response.status, "201 Created")
    self.assertEqual(response.content_type, "application/json")
    change = response.json["data"]
    self.assertEqual(change["status"], "pending")

    response = self.app.patch_json(
        "/contracts/{}/changes/{}?acc_token={}".format(self.contract["id"], change["id"], self.contract_token),
        {"data": {"status": "active"}},
        status=403,
    )
    self.assertEqual(response.status, "403 Forbidden")
    self.assertEqual(
        response.json["errors"],
        [
            {
                "location": "body",
                "name": "data",
                "description": "Can't update contract change status. 'dateSigned' is required.",
            }
        ],
    )

    one_day_in_past = (get_now() - timedelta(days=1)).isoformat()
    response = self.app.patch_json(
        "/contracts/{}/changes/{}?acc_token={}".format(self.contract["id"], change["id"], self.contract_token),
        {"data": {"status": "active", "dateSigned": one_day_in_past}},
    )
    self.assertEqual(response.json["data"]["status"], "active")
    self.assertEqual(response.json["data"]["dateSigned"], one_day_in_past)

    response = self.app.post_json(
        "/contracts/{}/changes?acc_token={}".format(self.contract["id"], self.contract_token),
        {
            "data": {
                "rationale": "iнша причина зміни укр",
                "rationale_en": "another change cause en",
                "rationaleTypes": ["priceReduction"],
                "contractNumber": "№ 147",
            }
        },
    )
    self.assertEqual(response.status, "201 Created")
    self.assertEqual(response.content_type, "application/json")
    change2 = response.json["data"]
    self.assertEqual(change["status"], "pending")

    two_days_in_past = (get_now() - timedelta(days=2)).isoformat()
    response = self.app.patch_json(
        "/contracts/{}/changes/{}?acc_token={}".format(self.contract["id"], change2["id"], self.contract_token),
        {"data": {"dateSigned": two_days_in_past}},
        status=403,
    )
    self.assertEqual(
        "Change dateSigned ({}) can't be earlier than last active change dateSigned ({})".format(
            two_days_in_past, one_day_in_past
        ),
        response.json["errors"][0]["description"],
    )

    valid_date = get_now().isoformat()
    response = self.app.patch_json(
        "/contracts/{}/changes/{}?acc_token={}".format(self.contract["id"], change2["id"], self.contract_token),
        {"data": {"status": "active", "dateSigned": valid_date}},
    )
    self.assertEqual(response.json["data"]["status"], "active")
    self.assertEqual(response.json["data"]["dateSigned"], valid_date)

    # prepare old contract change data
    contract = self.databases.contracts.get(self.contract["id"])
    last_change = contract["changes"][-1]
    last_change["dateSigned"] = None
    self.databases.contracts.save(contract)

    response = self.app.get(
        "/contracts/{}/changes/{}?acc_token={}".format(self.contract["id"], last_change["id"], self.contract_token)
    )
    self.assertEqual(response.status, "200 OK")
    self.assertNotIn("dateSigned", response.json["data"])

    response = self.app.post_json(
        "/contracts/{}/changes?acc_token={}".format(self.contract["id"], self.contract_token),
        {
            "data": {
                "rationale": "третя причина зміни укр",
                "rationale_en": "third change cause en",
                "rationaleTypes": ["priceReduction"],
                "contractNumber": "№ 148",
            }
        },
    )
    self.assertEqual(response.status, "201 Created")
    change3 = response.json["data"]
    self.assertEqual(change["status"], "pending")

    response = self.app.patch_json(
        "/contracts/{}/changes/{}?acc_token={}".format(self.contract["id"], change3["id"], self.contract_token),
        {"data": {"dateSigned": two_days_in_past}},
        status=403,
    )
    self.assertEqual(
        "Change dateSigned ({}) can't be earlier than last active change dateSigned ({})".format(
            two_days_in_past, last_change["date"]
        ),
        response.json["errors"][0]["description"],
    )

    valid_date2 = get_now().isoformat()
    response = self.app.patch_json(
        "/contracts/{}/changes/{}?acc_token={}".format(self.contract["id"], change3["id"], self.contract_token),
        {"data": {"status": "active", "dateSigned": valid_date2}},
    )
    self.assertEqual(response.json["data"]["status"], "active")
    self.assertEqual(response.json["data"]["dateSigned"], valid_date2)
def switch_bid_status_unsuccessul_to_active(self):
    bid_id, bid_token = self.initial_bids_tokens.items()[0]

    response = self.app.get("/tenders/{}/qualifications?acc_token={}".format(self.tender_id, self.tender_token))
    self.assertEqual(response.content_type, "application/json")
    qualifications = response.json["data"]
    self.assertEqual(len(qualifications), 3)
    qualification_id = ""
    for qualification in qualifications:
        status = "active"
        if qualification["bidID"] == bid_id:
            status = "unsuccessful"
            qualification_id = qualification["id"]
        response = self.app.patch_json(
            "/tenders/{}/qualifications/{}?acc_token={}".format(self.tender_id, qualification["id"], self.tender_token),
            {"data": {"status": status, "qualified": True, "eligible": True}},
        )
        self.assertEqual(response.status, "200 OK")
        self.assertEqual(response.json["data"]["status"], status)
    response = self.app.patch_json(
        "/tenders/{}?acc_token={}".format(self.tender_id, self.tender_token),
        {"data": {"status": "active.pre-qualification.stand-still"}},
    )
    self.assertEqual(response.status, "200 OK")
    end_date = parse_date(response.json["data"]["qualificationPeriod"]["endDate"])
    date = parse_date(response.json["data"]["date"])
    duration = (end_date - date).total_seconds()
    if SANDBOX_MODE:
        duration = ceil(duration) * 1440
    duration = duration / 86400  # days float
    self.assertEqual(int(duration), 5)

    # create complaint
    response = self.app.post_json(
        "/tenders/{}/qualifications/{}/complaints?acc_token={}".format(self.tender_id, qualification_id, bid_token),
        {
            "data": test_complaint
        },
    )
    self.assertEqual(response.status, "201 Created")
    self.assertEqual(response.content_type, "application/json")
    complaint = response.json["data"]
    complaint_token = response.json["access"]["token"]

    if RELEASE_2020_04_19 < get_now():
        self.assertEqual(response.json["data"]["status"], "draft")
        with change_auth(self.app, ("Basic", ("bot", ""))):
            response = self.app.patch_json(
                 "/tenders/{}/qualifications/{}/complaints/{}".format(
                     self.tender_id, qualification_id, complaint["id"]),
                {"data": {"status": "pending"}},
            )
        self.assertEqual(response.status, "200 OK")
        self.assertEqual(response.content_type, "application/json")
        self.assertEqual(response.json["data"]["status"], "pending")

    self.app.authorization = ("Basic", ("reviewer", ""))
    now = get_now()
    data = {"status": "accepted"}
    if RELEASE_2020_04_19 < now:
        data.update({
            "reviewDate": now.isoformat(),
            "reviewPlace": "some",
        })
    response = self.app.patch_json(
        "/tenders/{}/qualifications/{}/complaints/{}".format(self.tender_id, qualification_id, complaint["id"]),
        {"data": data},
    )
    self.assertEqual(response.status, "200 OK")
    self.assertEqual(response.content_type, "application/json")
    self.assertEqual(response.json["data"]["status"], "accepted")
    if RELEASE_2020_04_19 < now:
        self.assertEqual(response.json["data"]["reviewPlace"], "some")
        self.assertEqual(response.json["data"]["reviewDate"], now.isoformat())

    response = self.app.patch_json(
        "/tenders/{}/qualifications/{}/complaints/{}".format(self.tender_id, qualification_id, complaint["id"]),
        {"data": {"status": "satisfied"}},
    )
    self.assertEqual(response.status, "200 OK")
    self.assertEqual(response.content_type, "application/json")
    self.assertEqual(response.json["data"]["status"], "satisfied")

    # Cancell qualification
    self.app.authorization = ("Basic", ("broker", ""))
    response = self.app.patch_json(
        "/tenders/{}/qualifications/{}?acc_token={}".format(self.tender_id, qualification_id, self.tender_token),
        {"data": {"status": "cancelled"}},
    )
    self.assertEqual(response.status, "200 OK")
    self.assertEqual(response.json["data"]["status"], "cancelled")

    new_qualification_id = response.headers["location"].split("/")[-1]
    response = self.app.patch_json(
        "/tenders/{}/qualifications/{}?acc_token={}".format(self.tender_id, new_qualification_id, self.tender_token),
        {"data": {"status": "active", "qualified": True, "eligible": True}},
    )
    self.assertEqual(response.status, "200 OK")
    self.assertEqual(response.json["data"]["status"], "active")

    response = self.app.get("/tenders/{}/bids".format(self.tender_id))
    for b in response.json["data"]:
        self.assertEqual(b["status"], "active")
    def patch(self):
        """Tender Edit (partial)

        For example here is how procuring entity can change number of items to be procured and total Value of a tender:

        .. sourcecode:: http

            PATCH /tenders/4879d3f8ee2443169b5fbbc9f89fa607 HTTP/1.1
            Host: example.com
            Accept: application/json

            {
                "data": {
                    "value": {
                        "amount": 600
                    },
                    "itemsToBeProcured": [
                        {
                            "quantity": 6
                        }
                    ]
                }
            }

        And here is the response to be expected:

        .. sourcecode:: http

            HTTP/1.0 200 OK
            Content-Type: application/json

            {
                "data": {
                    "id": "4879d3f8ee2443169b5fbbc9f89fa607",
                    "tenderID": "UA-64e93250be76435397e8c992ed4214d1",
                    "dateModified": "2014-10-27T08:12:34.956Z",
                    "value": {
                        "amount": 600
                    },
                    "itemsToBeProcured": [
                        {
                            "quantity": 6
                        }
                    ]
                }
            }

        """
        tender = self.context
        data = self.request.validated['data']
        if self.request.authenticated_role == 'tender_owner' and \
                self.request.validated['tender_status'] in ['active.tendering', STAGE2_STATUS]:
            if 'tenderPeriod' in data and 'endDate' in data['tenderPeriod']:
                self.request.validated['tender'].tenderPeriod.import_data(data['tenderPeriod'])
                validate_tender_period_extension(self.request)
                self.request.registry.notify(TenderInitializeEvent(self.request.validated['tender']))
                self.request.validated['data']["enquiryPeriod"] = self.request.validated['tender'].enquiryPeriod.serialize()

        apply_patch(self.request, save=False, src=self.request.validated['tender_src'])
        if self.request.authenticated_role == 'chronograph':
            check_status_eu(self.request)
        elif self.request.authenticated_role == 'tender_owner' and tender.status == 'active.tendering':
            tender.invalidate_bids_data()
        elif self.request.authenticated_role == 'tender_owner' and \
                self.request.validated['tender_status'] == 'active.pre-qualification' and \
                tender.status == "active.pre-qualification.stand-still":
            if all_bids_are_reviewed(self.request):
                tender.qualificationPeriod.endDate = calculate_business_date(get_now(), COMPLAINT_STAND_STILL,
                                                                             self.request.validated['tender'])
                tender.check_auction_time()
            else:
                raise_operation_error(self.request, 'Can\'t switch to \'active.pre-qualification.stand-still\' while not all bids are qualified')

        save_tender(self.request)
        self.LOGGER.info('Updated tender {}'.format(tender.id),
                         extra=context_unpack(self.request, {'MESSAGE_ID': 'tender_patch'}))
        return {'data': tender.serialize(tender.status)}
def validate_add_complaint_not_in_complaint_period(request):
    if request.context.complaintPeriod and \
       (request.context.complaintPeriod.startDate and request.context.complaintPeriod.startDate > get_now() or
            request.context.complaintPeriod.endDate and request.context.complaintPeriod.endDate < get_now()):
        request.errors.add('body', 'data',
                           'Can add complaint only in complaintPeriod')
        request.errors.status = 403
        raise error_handler(request.errors)
def listing(self):
    response = self.app.get('/contracts')
    self.assertEqual(response.status, '200 OK')
    self.assertEqual(len(response.json['data']), 0)

    contracts = []

    for i in range(3):
        data = deepcopy(self.initial_data)
        data['id'] = uuid4().hex
        offset = get_now().isoformat()
        response = self.app.post_json('/contracts', {'data': data})
        self.assertEqual(response.status, '201 Created')
        self.assertEqual(response.content_type, 'application/json')
        contracts.append(response.json['data'])

    ids = ','.join([i['id'] for i in contracts])

    while True:
        response = self.app.get('/contracts')
        self.assertEqual(response.status, '200 OK')
        self.assertTrue(ids.startswith(','.join([i['id'] for i in response.json['data']])))
        if len(response.json['data']) == 3:
            break

    self.assertEqual(len(response.json['data']), 3)
    self.assertEqual(','.join([i['id'] for i in response.json['data']]), ids)
    self.assertEqual(set(response.json['data'][0]), set([u'id', u'dateModified']))
    self.assertEqual(set([i['id'] for i in response.json['data']]), set([i['id'] for i in contracts]))
    self.assertEqual(set([i['dateModified'] for i in response.json['data']]),
                     set([i['dateModified'] for i in contracts]))
    self.assertEqual([i['dateModified'] for i in response.json['data']], sorted([i['dateModified'] for i in contracts]))

    response = self.app.get('/contracts?offset={}'.format(offset))
    self.assertEqual(response.status, '200 OK')
    self.assertEqual(len(response.json['data']), 1)

    response = self.app.get('/contracts?limit=2')
    self.assertEqual(response.status, '200 OK')
    self.assertNotIn('prev_page', response.json)
    self.assertEqual(len(response.json['data']), 2)

    response = self.app.get(response.json['next_page']['path'].replace(ROUTE_PREFIX, ''))
    self.assertEqual(response.status, '200 OK')
    self.assertIn('descending=1', response.json['prev_page']['uri'])
    self.assertEqual(len(response.json['data']), 1)

    response = self.app.get(response.json['next_page']['path'].replace(ROUTE_PREFIX, ''))
    self.assertEqual(response.status, '200 OK')
    self.assertIn('descending=1', response.json['prev_page']['uri'])
    self.assertEqual(len(response.json['data']), 0)

    response = self.app.get('/contracts', params=[('opt_fields', 'contractID')])
    self.assertEqual(response.status, '200 OK')
    self.assertEqual(len(response.json['data']), 3)
    self.assertEqual(set(response.json['data'][0]), set([u'id', u'dateModified', u'contractID']))
    self.assertIn('opt_fields=contractID', response.json['next_page']['uri'])

    response = self.app.get('/contracts?descending=1')
    self.assertEqual(response.status, '200 OK')
    self.assertEqual(response.content_type, 'application/json')
    self.assertEqual(len(response.json['data']), 3)
    self.assertEqual(set(response.json['data'][0]), set([u'id', u'dateModified']))
    self.assertEqual(set([i['id'] for i in response.json['data']]), set([i['id'] for i in contracts]))
    self.assertEqual([i['dateModified'] for i in response.json['data']],
                     sorted([i['dateModified'] for i in contracts], reverse=True))

    response = self.app.get('/contracts?descending=1&limit=2')
    self.assertEqual(response.status, '200 OK')
    self.assertNotIn('descending=1', response.json['prev_page']['uri'])
    self.assertEqual(len(response.json['data']), 2)

    response = self.app.get(response.json['next_page']['path'].replace(ROUTE_PREFIX, ''))
    self.assertEqual(response.status, '200 OK')
    self.assertNotIn('descending=1', response.json['prev_page']['uri'])
    self.assertEqual(len(response.json['data']), 1)

    response = self.app.get(response.json['next_page']['path'].replace(ROUTE_PREFIX, ''))
    self.assertEqual(response.status, '200 OK')
    self.assertNotIn('descending=1', response.json['prev_page']['uri'])
    self.assertEqual(len(response.json['data']), 0)

    test_contract_data2 = deepcopy(self.initial_data)
    test_contract_data2['mode'] = 'test'
    response = self.app.post_json('/contracts', {'data': test_contract_data2})
    self.assertEqual(response.status, '201 Created')
    self.assertEqual(response.content_type, 'application/json')

    while True:
        response = self.app.get('/contracts?mode=test')
        self.assertEqual(response.status, '200 OK')
        if len(response.json['data']) == 1:
            break
    self.assertEqual(len(response.json['data']), 1)

    response = self.app.get('/contracts?mode=_all_')
    self.assertEqual(response.status, '200 OK')
    self.assertEqual(len(response.json['data']), 4)

    response = self.app.get('/contracts?mode=_all_&opt_fields=status')
    self.assertEqual(response.status, '200 OK')
    self.assertEqual(len(response.json['data']), 4)
def contract_items_change(self):
    tender_token = self.initial_data['tender_token']

    response = self.app.patch_json('/contracts/{}/credentials?acc_token={}'.format(self.contract['id'], tender_token),
                                   {'data': ''})
    self.assertEqual(response.status, '200 OK')
    token = response.json['access']['token']

    response = self.app.get('/contracts/{}'.format(self.contract['id']))
    self.assertEqual(response.status, '200 OK')
    self.assertEqual(response.content_type, 'application/json')
    items = response.json['data']["items"]

    response = self.app.patch_json('/contracts/{}?acc_token={}'.format(self.contract['id'], token),
                                   {"data": {"items": [{
                                       "quantity": 12,
                                       'description': 'тапочки для тараканів'
                                   }]}})
    self.assertEqual(response.status, '200 OK')
    self.assertEqual(response.json['data']['items'][0]['quantity'], 12)
    self.assertEqual(response.json['data']['items'][0]['description'], u'тапочки для тараканів')

    # add one more item
    item = deepcopy(items[0])
    item['quantity'] = 11
    response = self.app.patch_json('/contracts/{}?acc_token={}'.format(self.contract['id'], token),
                                   {"data": {"items": [{}, item]}}, status=422)
    self.assertEqual(response.status, '422 Unprocessable Entity')
    self.assertEqual(response.json['errors'], [
        {"location": "body", "name": "items", "description": ["Item id should be uniq for all items"]}
    ])

    #item['id'] = uuid4().hex
    #response = self.app.patch_json('/contracts/{}?acc_token={}'.format(self.contract['id'], token),
                                   #{"data": {"items": [{}, item]}})
    #self.assertEqual(len(response.json['data']['items']), 2)

    # try to change classification
    response = self.app.patch_json('/contracts/{}?acc_token={}'.format(self.contract['id'], token),
                                   {"data": {"items": [{
                                       'classification': {'id': '19433000-0'},
                                   }]}})
    self.assertEqual(response.status, '200 OK')
    self.assertEqual(response.json, None)

    # add additional classification
    item_classific = deepcopy(self.initial_data['items'][0]['classification'])
    response = self.app.patch_json('/contracts/{}?acc_token={}'.format(self.contract['id'], token),
                                   {"data": {"items": [{
                                       'additionalClassifications': [{}, item_classific],
                                   }]}})
    self.assertEqual(response.status, '200 OK')
    self.assertEqual(response.json, None)

    # update item fields
    startDate = get_now().isoformat()
    endDate = (get_now() + timedelta(days=90)).isoformat()
    response = self.app.patch_json('/contracts/{}?acc_token={}'.format(self.contract['id'], token),
                                   {"data": {"items": [{
                                       'deliveryAddress': {u"postalCode": u"79011", u"streetAddress": u"вул. Літаючого Хом’яка",},
                                       'deliveryDate': {u"startDate": startDate, u"endDate": endDate}
                                   }]}})
    self.assertEqual(response.json['data']['items'][0]['deliveryAddress']['postalCode'], u"79011")
    self.assertEqual(response.json['data']['items'][0]['deliveryAddress']['streetAddress'], u"вул. Літаючого Хом’яка")
    self.assertEqual(response.json['data']['items'][0]['deliveryAddress']['region'], u"м. Київ")
    self.assertEqual(response.json['data']['items'][0]['deliveryAddress']['locality'], u"м. Київ")
    self.assertEqual(response.json['data']['items'][0]['deliveryAddress']['countryName'], u"Україна")
    self.assertEqual(response.json['data']['items'][0]['deliveryDate']['startDate'], startDate)
    self.assertEqual(response.json['data']['items'][0]['deliveryDate']['endDate'], endDate)

    # remove first item
    #response = self.app.patch_json('/contracts/{}?acc_token={}'.format(self.contract['id'], token),
                                   #{"data": {"items": [item_2]}})
    #self.assertEqual(len(response.json['data']['items']), 1)
    #self.assertEqual(response.json['data']['items'][0], item_2)

    # try to remove all items
    response = self.app.patch_json('/contracts/{}?acc_token={}'.format(self.contract['id'], token),
                                   {"data": {"items": []}}, status=422)
    self.assertEqual(response.status, '422 Unprocessable Entity')
Ejemplo n.º 46
0
def check_tender_status(request):
    tender = request.validated["tender"]
    now = get_now()
    if tender.lots:
        for lot in tender.lots:
            if lot.status != "active":
                continue
            lot_awards = [i for i in tender.awards if i.lotID == lot.id]
            if not lot_awards:
                continue
            last_award = lot_awards[-1]
            if last_award.status == "unsuccessful":
                LOGGER.info(
                    "Switched lot {} of tender {} to {}".format(lot.id, tender.id, "unsuccessful"),
                    extra=context_unpack(request, {"MESSAGE_ID": "switched_lot_unsuccessful"}, {"LOT_ID": lot.id}),
                )
                lot.status = "unsuccessful"
                continue
            elif last_award.status == "active" and any(
                [i.status == "active" and i.awardID == last_award.id for i in tender.contracts]
            ):
                LOGGER.info(
                    "Switched lot {} of tender {} to {}".format(lot.id, tender.id, "complete"),
                    extra=context_unpack(request, {"MESSAGE_ID": "switched_lot_complete"}, {"LOT_ID": lot.id}),
                )
                lot.status = "complete"
        statuses = set([lot.status for lot in tender.lots])

        if statuses == set(["cancelled"]):
            LOGGER.info(
                "Switched tender {} to {}".format(tender.id, "cancelled"),
                extra=context_unpack(request, {"MESSAGE_ID": "switched_tender_cancelled"}),
            )
            tender.status = "cancelled"
        elif not statuses.difference(set(["unsuccessful", "cancelled"])):
            LOGGER.info(
                "Switched tender {} to {}".format(tender.id, "unsuccessful"),
                extra=context_unpack(request, {"MESSAGE_ID": "switched_tender_unsuccessful"}),
            )
            tender.status = "unsuccessful"
        elif not statuses.difference(set(["complete", "unsuccessful", "cancelled"])):
            LOGGER.info(
                "Switched tender {} to {}".format(tender.id, "complete"),
                extra=context_unpack(request, {"MESSAGE_ID": "switched_tender_complete"}),
            )
            tender.status = "complete"
    else:
        last_award_status = tender.awards[-1].status if tender.awards else ""
        if last_award_status == "unsuccessful":
            LOGGER.info(
                "Switched tender {} to {}".format(tender.id, "unsuccessful"),
                extra=context_unpack(request, {"MESSAGE_ID": "switched_tender_unsuccessful"}),
            )
            tender.status = "unsuccessful"

        if (
                tender.contracts
                and any([contract.status == "active" for contract in tender.contracts])
                and not any([contract.status == "pending" for contract in tender.contracts])
        ):
            tender.status = "complete"
Ejemplo n.º 47
0
def patch_tender_contract(self):
    response = self.app.get("/tenders/{}/contracts".format(self.tender_id))
    contract = response.json["data"][0]

    fake_contractID = "myselfID"
    fake_items_data = [{"description": "New Description"}]
    fake_suppliers_data = [{"name": "New Name"}]

    response = self.app.patch_json(
        "/tenders/{}/contracts/{}?acc_token={}".format(self.tender_id,
                                                       contract["id"],
                                                       self.tender_token),
        {"data": {
            "value": {
                "amountNet": contract["value"]["amount"] - 1
            }
        }},
    )
    self.assertEqual(response.status, "200 OK")

    self.app.patch_json(
        "/tenders/{}/contracts/{}?acc_token={}".format(self.tender_id,
                                                       contract["id"],
                                                       self.tender_token),
        {
            "data": {
                "contractID": fake_contractID,
                "items": fake_items_data,
                "suppliers": fake_suppliers_data
            }
        },
    )

    response = self.app.get("/tenders/{}/contracts/{}".format(
        self.tender_id, contract["id"]))
    self.assertNotEqual(fake_contractID, response.json["data"]["contractID"])
    self.assertNotEqual(fake_items_data, response.json["data"]["items"])
    self.assertNotEqual(fake_suppliers_data,
                        response.json["data"]["suppliers"])

    response = self.app.patch_json(
        "/tenders/{}/contracts/{}?acc_token={}".format(self.tender_id,
                                                       contract["id"],
                                                       self.tender_token),
        {"data": {
            "value": {
                "currency": "USD"
            }
        }},
        status=403,
    )
    self.assertEqual(response.status, "403 Forbidden")
    self.assertEqual(response.json["errors"][0]["description"],
                     "Can't update currency for contract value")

    response = self.app.patch_json(
        "/tenders/{}/contracts/{}?acc_token={}".format(self.tender_id,
                                                       contract["id"],
                                                       self.tender_token),
        {"data": {
            "status": "active"
        }},
        status=403,
    )
    self.assertEqual(response.status, "403 Forbidden")
    self.assertEqual(response.content_type, "application/json")
    self.assertIn("Can't sign contract before stand-still period end (",
                  response.json["errors"][0]["description"])

    self.set_status("complete", {"status": "active.awarded"})

    token = self.initial_bids_tokens[self.initial_bids[0]["id"]]
    response = self.app.post_json(
        "/tenders/{}/awards/{}/complaints?acc_token={}".format(
            self.tender_id, self.award_id, token),
        {"data": test_draft_complaint},
    )
    self.assertEqual(response.status, "201 Created")
    complaint = response.json["data"]
    owner_token = response.json["access"]["token"]

    response = self.app.patch_json(
        "/tenders/{}/awards/{}/complaints/{}?acc_token={}".format(
            self.tender_id, self.award_id, complaint["id"], owner_token),
        {"data": {
            "status": "pending"
        }},
    )
    self.assertEqual(response.status, "200 OK")

    tender = self.db.get(self.tender_id)
    for i in tender.get("awards", []):
        i["complaintPeriod"]["endDate"] = i["complaintPeriod"]["startDate"]
    self.db.save(tender)

    response = self.app.patch_json(
        "/tenders/{}/contracts/{}?acc_token={}".format(self.tender_id,
                                                       contract["id"],
                                                       self.tender_token),
        {"data": {
            "dateSigned": i["complaintPeriod"]["endDate"]
        }},
        status=422,
    )
    self.assertEqual(response.status, "422 Unprocessable Entity")
    self.assertEqual(
        response.json["errors"],
        [{
            u"description": [
                u"Contract signature date should be after award complaint period end date ({})"
                .format(i["complaintPeriod"]["endDate"])
            ],
            u"location":
            u"body",
            u"name":
            u"dateSigned",
        }],
    )

    one_hour_in_furure = (get_now() + timedelta(hours=1)).isoformat()
    response = self.app.patch_json(
        "/tenders/{}/contracts/{}?acc_token={}".format(self.tender_id,
                                                       contract["id"],
                                                       self.tender_token),
        {"data": {
            "dateSigned": one_hour_in_furure
        }},
        status=422,
    )
    self.assertEqual(response.status, "422 Unprocessable Entity")
    self.assertEqual(
        response.json["errors"],
        [{
            u"description":
            [u"Contract signature date can't be in the future"],
            u"location": u"body",
            u"name": u"dateSigned",
        }],
    )

    custom_signature_date = get_now().isoformat()
    response = self.app.patch_json(
        "/tenders/{}/contracts/{}?acc_token={}".format(self.tender_id,
                                                       contract["id"],
                                                       self.tender_token),
        {"data": {
            "dateSigned": custom_signature_date
        }},
    )
    self.assertEqual(response.status, "200 OK")

    response = self.app.patch_json(
        "/tenders/{}/contracts/{}?acc_token={}".format(self.tender_id,
                                                       contract["id"],
                                                       self.tender_token),
        {"data": {
            "status": "active"
        }},
        status=403,
    )
    self.assertEqual(response.status, "403 Forbidden")
    self.assertEqual(response.content_type, "application/json")
    self.assertEqual(response.json["errors"][0]["description"],
                     "Can't sign contract before reviewing all complaints")

    response = self.app.patch_json(
        "/tenders/{}/awards/{}/complaints/{}?acc_token={}".format(
            self.tender_id, self.award_id, complaint["id"], owner_token),
        {"data": {
            "status": "stopping",
            "cancellationReason": "reason"
        }},
    )
    self.assertEqual(response.status, "200 OK")
    self.assertEqual(response.content_type, "application/json")
    self.assertEqual(response.json["data"]["status"], "stopping")

    authorization = self.app.authorization
    self.app.authorization = ("Basic", ("reviewer", ""))
    now = get_now()
    data = {"status": "stopped"}
    if RELEASE_2020_04_19 < now:
        data.update({
            "status": "declined",
            "rejectReason": "tenderCancelled",
            "rejectReasonDescription": "reject reason description"
        })

    response = self.app.patch_json(
        "/tenders/{}/awards/{}/complaints/{}".format(self.tender_id,
                                                     self.award_id,
                                                     complaint["id"]),
        {"data": data},
    )
    self.assertEqual(response.status, "200 OK")
    self.assertEqual(response.json["data"]["status"], data["status"])

    self.app.authorization = authorization
    response = self.app.patch_json(
        "/tenders/{}/contracts/{}?acc_token={}".format(self.tender_id,
                                                       contract["id"],
                                                       self.tender_token),
        {"data": {
            "status": "active"
        }},
    )
    self.assertEqual(response.status, "200 OK")
    self.assertEqual(response.content_type, "application/json")
    self.assertEqual(response.json["data"]["status"], "active")

    response = self.app.patch_json(
        "/tenders/{}/contracts/{}?acc_token={}".format(self.tender_id,
                                                       contract["id"],
                                                       self.tender_token),
        {
            "data": {
                "value": {
                    "amount": 232
                },
                "contractID": "myselfID",
                "title": "New Title",
                "items": [{
                    "description": "New Description"
                }],
                "suppliers": [{
                    "name": "New Name"
                }],
            }
        },
        status=403,
    )
    self.assertEqual(response.status, "403 Forbidden")
    self.assertEqual(
        response.json["errors"][0]["description"],
        "Can't update contract in current (complete) tender status")

    response = self.app.patch_json(
        "/tenders/{}/contracts/{}?acc_token={}".format(self.tender_id,
                                                       contract["id"],
                                                       self.tender_token),
        {"data": {
            "status": "active"
        }},
        status=403,
    )
    self.assertEqual(response.status, "403 Forbidden")
    self.assertEqual(response.content_type, "application/json")
    self.assertEqual(
        response.json["errors"][0]["description"],
        "Can't update contract in current (complete) tender status")

    response = self.app.patch_json(
        "/tenders/{}/contracts/{}?acc_token={}".format(self.tender_id,
                                                       contract["id"],
                                                       self.tender_token),
        {"data": {
            "status": "pending"
        }},
        status=403,
    )
    self.assertEqual(response.status, "403 Forbidden")
    self.assertEqual(response.content_type, "application/json")
    self.assertEqual(
        response.json["errors"][0]["description"],
        "Can't update contract in current (complete) tender status")

    response = self.app.patch_json("/tenders/{}/contracts/some_id".format(
        self.tender_id), {"data": {
            "status": "active"
        }},
                                   status=404)
    self.assertEqual(response.status, "404 Not Found")
    self.assertEqual(response.content_type, "application/json")
    self.assertEqual(response.json["status"], "error")
    self.assertEqual(response.json["errors"], [{
        u"description": u"Not Found",
        u"location": u"url",
        u"name": u"contract_id"
    }])

    response = self.app.patch_json("/tenders/some_id/contracts/some_id",
                                   {"data": {
                                       "status": "active"
                                   }},
                                   status=404)
    self.assertEqual(response.status, "404 Not Found")
    self.assertEqual(response.content_type, "application/json")
    self.assertEqual(response.json["status"], "error")
    self.assertEqual(response.json["errors"], [{
        u"description": u"Not Found",
        u"location": u"url",
        u"name": u"tender_id"
    }])

    response = self.app.get("/tenders/{}/contracts/{}".format(
        self.tender_id, contract["id"]))
    self.assertEqual(response.status, "200 OK")
    self.assertEqual(response.content_type, "application/json")
    self.assertEqual(response.json["data"]["status"], "active")
 def wrapper():
     return PeriodStartEndRequired({"startDate": get_now(),
                                    "endDate": calculate_business_date(get_now(), tendering_duration)})
Ejemplo n.º 49
0
 def time_shift(self, status, extra=None):
     now = get_now()
     tender = self.db.get(self.tender_id)
     data = {}
     if status == 'enquiryPeriod_ends':
         data.update({
             "enquiryPeriod": {
                 "startDate": (now - timedelta(days=28)).isoformat(),
                 "endDate": (now - timedelta(days=1)).isoformat()
             },
             "tenderPeriod": {
                 "startDate": (now - timedelta(days=28)).isoformat(),
                 "endDate": (now + timedelta(days=2)).isoformat()
             },
         })
     if status == 'active.pre-qualification':
         data.update({
             "enquiryPeriod": {
                 "startDate": (now - TENDERING_DURATION).isoformat(),
                 "endDate": (now - QUESTIONS_STAND_STILL).isoformat()
             },
             "tenderPeriod": {
                 "startDate": (now - TENDERING_DURATION).isoformat(),
                 "endDate": (now).isoformat(),
             }
         })
     elif status == 'active.pre-qualification.stand-still':
         data.update({
             "enquiryPeriod": {
                 "startDate": (now - TENDERING_DURATION).isoformat(),
                 "endDate": (now - QUESTIONS_STAND_STILL).isoformat()
             },
             "tenderPeriod": {
                 "startDate": (now - TENDERING_DURATION).isoformat(),
                 "endDate": (now).isoformat(),
             },
             "qualificationPeriod": {
                 "startDate": (now).isoformat(),
             },
         })
         if 'lots' in tender and tender['lots']:
             data['lots'] = []
             for index, lot in enumerate(tender['lots']):
                 lot_data = {'id': lot['id']}
                 if lot['status'] is 'active':
                     lot_data["auctionPeriod"] = {
                         "startDate":
                         (now + COMPLAINT_STAND_STILL).isoformat()
                     }
                 data['lots'].append(lot_data)
         else:
             data.update({
                 "auctionPeriod": {
                     "startDate": (now + COMPLAINT_STAND_STILL).isoformat()
                 }
             })
     elif status == 'active.auction':
         data.update({
             "enquiryPeriod": {
                 "startDate": (now - TENDERING_DURATION -
                               COMPLAINT_STAND_STILL).isoformat(),
                 "endDate":
                 (now - COMPLAINT_STAND_STILL - TENDERING_DURATION +
                  QUESTIONS_STAND_STILL).isoformat()
             },
             "tenderPeriod": {
                 "startDate": (now - TENDERING_DURATION -
                               COMPLAINT_STAND_STILL).isoformat(),
                 "endDate": (now - COMPLAINT_STAND_STILL).isoformat()
             },
             "qualificationPeriod": {
                 "startDate": (now - COMPLAINT_STAND_STILL).isoformat(),
                 "endDate": (now).isoformat()
             }
         })
         if 'lots' in tender and tender['lots']:
             data['lots'] = []
             for index, lot in enumerate(tender['lots']):
                 lot_data = {'id': lot['id']}
                 if lot['status'] == 'active':
                     lot_data["auctionPeriod"] = {
                         "startDate": (now).isoformat()
                     }
                 data['lots'].append(lot_data)
         else:
             data.update({"auctionPeriod": {"startDate": now.isoformat()}})
     elif status == 'complete':
         data.update({
             "enquiryPeriod": {
                 "startDate":
                 (now - TENDERING_DURATION - COMPLAINT_STAND_STILL -
                  timedelta(days=3)).isoformat(),
                 "endDate":
                 (now - QUESTIONS_STAND_STILL - COMPLAINT_STAND_STILL -
                  timedelta(days=3)).isoformat()
             },
             "tenderPeriod": {
                 "startDate":
                 (now - TENDERING_DURATION - COMPLAINT_STAND_STILL -
                  timedelta(days=3)).isoformat(),
                 "endDate": (now - COMPLAINT_STAND_STILL -
                             timedelta(days=3)).isoformat()
             },
             "auctionPeriod": {
                 "startDate": (now - timedelta(days=3)).isoformat(),
                 "endDate": (now - timedelta(days=2)).isoformat()
             },
             "awardPeriod": {
                 "startDate": (now - timedelta(days=1)).isoformat(),
                 "endDate": (now).isoformat()
             }
         })
         if self.initial_lots:
             data.update({
                 'lots': [{
                     "auctionPeriod": {
                         "startDate": (now - timedelta(days=3)).isoformat(),
                         "endDate": (now - timedelta(days=2)).isoformat()
                     }
                 } for i in self.initial_lots]
             })
     if extra:
         data.update(extra)
     tender.update(apply_data_patch(tender, data))
     self.db.save(tender)
Ejemplo n.º 50
0
def listing_changes(self):
    response = self.app.get("/qualifications")
    self.assertEqual(response.status, "200 OK")
    self.assertEqual(len(response.json["data"]), 0)

    qualifications = []

    data = deepcopy(self.initial_submission_data)

    tenderer_ids = ["00037256", "00037257", "00037258"]

    for i in tenderer_ids:
        data["tenderers"][0]["identifier"]["id"] = i
        offset = get_now().isoformat()
        response = self.app.post_json("/submissions", {"data": data})
        self.assertEqual(response.status, "201 Created")
        self.assertEqual(response.content_type, "application/json")
        response = self.app.patch_json(
            "/submissions/{}?acc_token={}".format(
                response.json["data"]["id"], response.json["access"]["token"]),
            {"data": {
                "status": "active"
            }},
        )
        self.assertEqual(response.status, "200 OK")
        self.assertEqual(response.content_type, "application/json")
        qualification_id = response.json["data"]["qualificationID"]

        response = self.app.patch_json(
            "/qualifications/{}?acc_token={}".format(qualification_id,
                                                     self.framework_token),
            {"data": {
                "status": "active"
            }})
        qualifications.append(response.json["data"])

    ids = ",".join([i["id"] for i in qualifications])

    while True:
        response = self.app.get("/qualifications?feed=changes")
        self.assertTrue(
            ids.startswith(",".join([i["id"] for i in response.json["data"]])))
        if len(response.json["data"]) == 3:
            break

    self.assertEqual(",".join([i["id"] for i in response.json["data"]]), ids)
    self.assertEqual(response.status, "200 OK")
    self.assertEqual(len(response.json["data"]), 3)
    self.assertEqual(set(response.json["data"][0]), set(["id",
                                                         "dateModified"]))
    self.assertEqual(set([i["id"] for i in response.json["data"]]),
                     set([i["id"] for i in qualifications]))
    self.assertEqual(set([i["dateModified"] for i in response.json["data"]]),
                     set([i["dateModified"] for i in qualifications]))
    self.assertEqual([i["dateModified"] for i in response.json["data"]],
                     sorted([i["dateModified"] for i in qualifications]))

    response = self.app.get("/qualifications?feed=changes&limit=2")
    self.assertEqual(response.status, "200 OK")
    self.assertNotIn("prev_page", response.json)
    self.assertEqual(len(response.json["data"]), 2)

    response = self.app.get(response.json["next_page"]["path"].replace(
        ROUTE_PREFIX, ""))
    self.assertEqual(response.status, "200 OK")
    self.assertIn("descending=1", response.json["prev_page"]["uri"])
    self.assertEqual(len(response.json["data"]), 1)

    response = self.app.get(response.json["next_page"]["path"].replace(
        ROUTE_PREFIX, ""))
    self.assertEqual(response.status, "200 OK")
    self.assertIn("descending=1", response.json["prev_page"]["uri"])
    self.assertEqual(len(response.json["data"]), 0)

    response = self.app.get("/qualifications?feed=changes",
                            params=[("opt_fields", "status")])
    self.assertEqual(response.status, "200 OK")
    self.assertEqual(len(response.json["data"]), 3)
    self.assertEqual(set(response.json["data"][0]),
                     set(["id", "dateModified", "status"]))
    self.assertIn("opt_fields=status", response.json["next_page"]["uri"])

    response = self.app.get("/qualifications?feed=changes",
                            params=[("opt_fields", "status,owner")])
    self.assertEqual(response.status, "200 OK")
    self.assertEqual(len(response.json["data"]), 3)
    self.assertEqual(set(response.json["data"][0]),
                     set(["id", "dateModified", "status"]))
    self.assertIn("opt_fields=status", response.json["next_page"]["uri"])

    response = self.app.get("/qualifications?feed=changes&descending=1")
    self.assertEqual(response.status, "200 OK")
    self.assertEqual(response.content_type, "application/json")
    self.assertEqual(len(response.json["data"]), 3)
    self.assertEqual(set(response.json["data"][0]), set(["id",
                                                         "dateModified"]))
    self.assertEqual(set([i["id"] for i in response.json["data"]]),
                     set([i["id"] for i in qualifications]))
    self.assertEqual([i["dateModified"] for i in response.json["data"]],
                     sorted([i["dateModified"] for i in qualifications],
                            reverse=True))

    response = self.app.get(
        "/qualifications?feed=changes&descending=1&limit=2")
    self.assertEqual(response.status, "200 OK")
    self.assertNotIn("descending=1", response.json["prev_page"]["uri"])
    self.assertEqual(len(response.json["data"]), 2)

    response = self.app.get(response.json["next_page"]["path"].replace(
        ROUTE_PREFIX, ""))
    self.assertEqual(response.status, "200 OK")
    self.assertNotIn("descending=1", response.json["prev_page"]["uri"])
    self.assertEqual(len(response.json["data"]), 1)

    response = self.app.get(response.json["next_page"]["path"].replace(
        ROUTE_PREFIX, ""))
    self.assertEqual(response.status, "200 OK")
    self.assertNotIn("descending=1", response.json["prev_page"]["uri"])
    self.assertEqual(len(response.json["data"]), 0)
def validate_add_question(request):
    tender = request.validated['tender']
    if tender.status != 'active.enquiries' or tender.enquiryPeriod.startDate and get_now() < tender.enquiryPeriod.startDate or get_now() > tender.enquiryPeriod.endDate:
        raise_operation_error(request, 'Can add question only in enquiryPeriod')
Ejemplo n.º 52
0
def patch_submission_pending(self):
    response = self.app.patch_json(
        "/submissions/{}?acc_token={}".format(self.submission_id,
                                              self.submission_token),
        {"data": {
            "status": "active"
        }},
    )
    self.assertEqual(response.status, "200 OK")
    self.assertEqual(response.content_type, "application/json")
    qualification_id = response.json["data"]["qualificationID"]

    qualification_ignore_patch_data = {
        "date": (get_now() + timedelta(days=2)).isoformat(),
        "dateModified": (get_now() + timedelta(days=1)).isoformat(),
        "submissionID": "0" * 32,
        "qualificationType": "changed",
    }
    response = self.app.patch_json(
        "/qualifications/{}?acc_token={}".format(qualification_id,
                                                 self.framework_token),
        {"data": qualification_ignore_patch_data})
    self.assertEqual(response.status, "200 OK")
    self.assertEqual(response.content_type, "application/json")
    qualification = self.app.get(
        "/qualifications/{}".format(qualification_id)).json["data"]
    for field in qualification_ignore_patch_data:
        self.assertNotEqual(qualification.get(field, ""),
                            qualification_ignore_patch_data[field])

    qualification_patch_data = {"status": "active"}

    response = self.app.patch_json(
        "/qualifications/{}?acc_token={}".format(qualification_id,
                                                 self.framework_token),
        {"data": qualification_patch_data})
    self.assertEqual(response.status, "200 OK")
    self.assertEqual(response.content_type, "application/json")
    qualification = self.app.get("/qualifications/{}".format(
        qualification_id, self.framework_token)).json["data"]
    self.assertEqual(qualification["status"], "active")

    submission = self.app.get("/submissions/{}".format(
        self.submission_id)).json["data"]
    self.assertEqual(submission["status"], "complete")

    submission_data = deepcopy(self.initial_submission_data)
    submission_data["tenderers"][0]["identifier"]["id"] = "00037258"
    response = self.app.post_json("/submissions", {"data": submission_data})
    self.assertEqual(response.status, "201 Created")
    submission_id = response.json["data"]["id"]
    submission_token = response.json["access"]["token"]

    response = self.app.patch_json(
        "/submissions/{}?acc_token={}".format(submission_id, submission_token),
        {"data": {
            "status": "active"
        }},
    )
    self.assertEqual(response.status, "200 OK")
    qualification_id = response.json["data"]["qualificationID"]
    response = self.app.patch_json(
        "/qualifications/{}?acc_token={}".format(qualification_id,
                                                 self.framework_token),
        {"data": {
            "status": "unsuccessful"
        }})
    self.assertEqual(response.status, "200 OK")
    self.assertEqual(response.content_type, "application/json")
    qualification = self.app.get("/qualifications/{}".format(
        qualification_id, self.framework_token)).json["data"]
    self.assertEqual(qualification["status"], "unsuccessful")

    submission = self.app.get(
        "/submissions/{}".format(submission_id)).json["data"]
    self.assertEqual(submission["status"], "complete")
Ejemplo n.º 53
0
# -*- coding: utf-8 -*-

from copy import deepcopy
from datetime import timedelta
from openprocurement.api.utils import get_now
from openprocurement.tender.belowthreshold.tests.base import set_tender_multi_buyers
from openprocurement.tender.pricequotation.constants import PMT
from openprocurement.api.constants import SANDBOX_MODE


now = get_now()


PERIODS = {
    "active.tendering": {
        "start": {
            "tenderPeriod": {
                "startDate": -timedelta(),
                "endDate": timedelta(days=8)
            },
        },
        "end": {
            "tenderPeriod": {
                "startDate": - timedelta(days=8),
                "endDate": timedelta()
            },
        },
    },
    "active.qualification": {
        "start": {
            "tenderPeriod": {
Ejemplo n.º 54
0
Archivo: base.py Proyecto: lttga/op2
 def time_shift(self, status, extra=None):
     now = get_now()
     tender = self.db.get(self.tender_id)
     self.tender_document = tender
     data = {}
     if status == "enquiryPeriod_ends":
         data.update({
             "enquiryPeriod": {
                 "startDate": (now - timedelta(days=28)).isoformat(),
                 "endDate": (now - timedelta(days=1)).isoformat(),
             },
             "tenderPeriod": {
                 "startDate": (now - timedelta(days=28)).isoformat(),
                 "endDate": (now + timedelta(days=2)).isoformat(),
             },
         })
     if status == "active.pre-qualification":
         data.update({
             "enquiryPeriod": {
                 "startDate": (now - TENDERING_DURATION).isoformat(),
                 "endDate": (now - QUESTIONS_STAND_STILL).isoformat(),
             },
             "tenderPeriod": {
                 "startDate": (now - TENDERING_DURATION).isoformat(),
                 "endDate": (now).isoformat()
             },
         })
     elif status == "active.pre-qualification.stand-still":
         data.update({
             "enquiryPeriod": {
                 "startDate": (now - TENDERING_DURATION).isoformat(),
                 "endDate": (now - QUESTIONS_STAND_STILL).isoformat(),
             },
             "tenderPeriod": {
                 "startDate": (now - TENDERING_DURATION).isoformat(),
                 "endDate": (now).isoformat()
             },
             "qualificationPeriod": {
                 "startDate": (now).isoformat()
             },
         })
         if "lots" in tender and tender["lots"]:
             data["lots"] = []
             for index, lot in enumerate(tender["lots"]):
                 lot_data = {"id": lot["id"]}
                 if lot["status"] is "active":
                     lot_data["auctionPeriod"] = {
                         "startDate":
                         (now + COMPLAINT_STAND_STILL).isoformat()
                     }
                 data["lots"].append(lot_data)
         else:
             data.update({
                 "auctionPeriod": {
                     "startDate": (now + COMPLAINT_STAND_STILL).isoformat()
                 }
             })
     elif status == "active.auction":
         data.update({
             "enquiryPeriod": {
                 "startDate": (now - TENDERING_DURATION -
                               COMPLAINT_STAND_STILL).isoformat(),
                 "endDate":
                 (now - COMPLAINT_STAND_STILL - TENDERING_DURATION +
                  QUESTIONS_STAND_STILL).isoformat(),
             },
             "tenderPeriod": {
                 "startDate": (now - TENDERING_DURATION -
                               COMPLAINT_STAND_STILL).isoformat(),
                 "endDate": (now - COMPLAINT_STAND_STILL).isoformat(),
             },
             "qualificationPeriod": {
                 "startDate": (now - COMPLAINT_STAND_STILL).isoformat(),
                 "endDate": (now).isoformat(),
             },
         })
         if "lots" in tender and tender["lots"]:
             data["lots"] = []
             for index, lot in enumerate(tender["lots"]):
                 lot_data = {"id": lot["id"]}
                 if lot["status"] == "active":
                     lot_data["auctionPeriod"] = {
                         "startDate": (now).isoformat()
                     }
                 data["lots"].append(lot_data)
         else:
             data.update({"auctionPeriod": {"startDate": now.isoformat()}})
     elif status == "complete":
         data.update({
             "enquiryPeriod": {
                 "startDate":
                 (now - TENDERING_DURATION - COMPLAINT_STAND_STILL -
                  timedelta(days=3)).isoformat(),
                 "endDate":
                 (now - QUESTIONS_STAND_STILL - COMPLAINT_STAND_STILL -
                  timedelta(days=3)).isoformat(),
             },
             "tenderPeriod": {
                 "startDate":
                 (now - TENDERING_DURATION - COMPLAINT_STAND_STILL -
                  timedelta(days=3)).isoformat(),
                 "endDate": (now - COMPLAINT_STAND_STILL -
                             timedelta(days=3)).isoformat(),
             },
             "auctionPeriod": {
                 "startDate": (now - timedelta(days=3)).isoformat(),
                 "endDate": (now - timedelta(days=2)).isoformat(),
             },
             "awardPeriod": {
                 "startDate": (now - timedelta(days=1)).isoformat(),
                 "endDate": (now).isoformat()
             },
         })
         if self.initial_lots:
             data.update({
                 "lots": [{
                     "auctionPeriod": {
                         "startDate": (now - timedelta(days=3)).isoformat(),
                         "endDate": (now - timedelta(days=2)).isoformat(),
                     }
                 } for i in self.initial_lots]
             })
     if extra:
         data.update(extra)
     self.tender_document_patch = data
     self.save_changes()
Ejemplo n.º 55
0
Archivo: base.py Proyecto: lttga/op2
    def update_status(self, status, extra=None):
        now = get_now()
        data = {"status": status}
        if status == "active.tendering":
            data.update({
                "enquiryPeriod": {
                    "startDate": (now - timedelta(days=1)).isoformat(),
                    "endDate": (now + TENDERING_DURATION -
                                QUESTIONS_STAND_STILL).isoformat(),
                },
                "tenderPeriod": {
                    "startDate": (now - timedelta(days=1)).isoformat(),
                    "endDate": (now + TENDERING_DURATION).isoformat(),
                },
            })
        elif status == "active.pre-qualification":
            data.update({
                "enquiryPeriod": {
                    "startDate":
                    (now - TENDERING_DURATION - timedelta(days=1)).isoformat(),
                    "endDate": (now - QUESTIONS_STAND_STILL).isoformat(),
                },
                "tenderPeriod": {
                    "startDate":
                    (now - TENDERING_DURATION - timedelta(days=1)).isoformat(),
                    "endDate": (now).isoformat(),
                },
                "qualificationPeriod": {
                    "startDate": (now).isoformat()
                },
            })
        elif status == "active.qualification":
            data.update({
                "enquiryPeriod": {
                    "startDate":
                    (now - TENDERING_DURATION - COMPLAINT_STAND_STILL -
                     timedelta(days=2)).isoformat(),
                    "endDate":
                    (now - QUESTIONS_STAND_STILL - COMPLAINT_STAND_STILL -
                     timedelta(days=1)).isoformat(),
                },
                "tenderPeriod": {
                    "startDate":
                    (now - TENDERING_DURATION - COMPLAINT_STAND_STILL -
                     timedelta(days=2)).isoformat(),
                    "endDate": (now - COMPLAINT_STAND_STILL -
                                timedelta(days=1)).isoformat(),
                },
                "auctionPeriod": {
                    "startDate": (now - timedelta(days=1)).isoformat(),
                    "endDate": (now).isoformat()
                },
                "awardPeriod": {
                    "startDate": (now).isoformat()
                },
            })
            if self.initial_lots:
                data.update({
                    "lots": [{
                        "auctionPeriod": {
                            "startDate": (now - timedelta(days=1)).isoformat(),
                            "endDate": (now).isoformat(),
                        }
                    } for i in self.initial_lots]
                })
        elif status == "active.pre-qualification.stand-still":
            data.update({
                "enquiryPeriod": {
                    "startDate":
                    (now - TENDERING_DURATION - timedelta(days=1)).isoformat(),
                    "endDate": (now - QUESTIONS_STAND_STILL).isoformat(),
                },
                "tenderPeriod": {
                    "startDate":
                    (now - TENDERING_DURATION - timedelta(days=1)).isoformat(),
                    "endDate": (now).isoformat(),
                },
                "qualificationPeriod": {
                    "startDate": (now).isoformat()
                },
                "auctionPeriod": {
                    "startDate": (now + COMPLAINT_STAND_STILL).isoformat()
                },
            })
        elif status == "active.stage2.pending":
            data.update({
                "enquiryPeriod": {
                    "startDate":
                    (now - TENDERING_DURATION - COMPLAINT_STAND_STILL -
                     timedelta(days=1)).isoformat(),
                    "endDate":
                    (now - COMPLAINT_STAND_STILL - TENDERING_DURATION +
                     QUESTIONS_STAND_STILL).isoformat(),
                },
                "tenderPeriod": {
                    "startDate":
                    (now - TENDERING_DURATION - COMPLAINT_STAND_STILL -
                     timedelta(days=1)).isoformat(),
                    "endDate": (now - COMPLAINT_STAND_STILL).isoformat(),
                },
                "qualificationPeriod": {
                    "startDate": (now - COMPLAINT_STAND_STILL).isoformat(),
                    "endDate": (now).isoformat(),
                },
            })
            if self.initial_lots:
                data.update({
                    "lots": [{
                        "auctionPeriod": {
                            "startDate": (now).isoformat()
                        }
                    } for i in self.initial_lots]
                })
        elif status == "active.auction":
            data.update({
                "enquiryPeriod": {
                    "startDate":
                    (now - TENDERING_DURATION - COMPLAINT_STAND_STILL -
                     timedelta(days=1)).isoformat(),
                    "endDate":
                    (now - COMPLAINT_STAND_STILL - TENDERING_DURATION +
                     QUESTIONS_STAND_STILL).isoformat(),
                },
                "tenderPeriod": {
                    "startDate":
                    (now - TENDERING_DURATION - COMPLAINT_STAND_STILL -
                     timedelta(days=1)).isoformat(),
                    "endDate": (now - COMPLAINT_STAND_STILL).isoformat(),
                },
                "qualificationPeriod": {
                    "startDate": (now - COMPLAINT_STAND_STILL).isoformat(),
                    "endDate": (now).isoformat(),
                },
                "auctionPeriod": {
                    "startDate": (now).isoformat()
                },
            })
            if self.initial_lots:
                data.update({
                    "lots": [{
                        "auctionPeriod": {
                            "startDate": (now).isoformat()
                        }
                    } for i in self.initial_lots]
                })
        elif status == "active.awarded":
            data.update({
                "enquiryPeriod": {
                    "startDate":
                    (now - TENDERING_DURATION - COMPLAINT_STAND_STILL -
                     timedelta(days=3)).isoformat(),
                    "endDate":
                    (now - QUESTIONS_STAND_STILL - COMPLAINT_STAND_STILL -
                     timedelta(days=2)).isoformat(),
                },
                "tenderPeriod": {
                    "startDate":
                    (now - TENDERING_DURATION - COMPLAINT_STAND_STILL -
                     timedelta(days=3)).isoformat(),
                    "endDate": (now - COMPLAINT_STAND_STILL -
                                timedelta(days=2)).isoformat(),
                },
                "auctionPeriod": {
                    "startDate": (now - timedelta(days=2)).isoformat(),
                    "endDate": (now - timedelta(days=1)).isoformat(),
                },
                "awardPeriod": {
                    "startDate": (now - timedelta(days=1)).isoformat(),
                    "endDate": (now).isoformat()
                },
            })
            if self.initial_lots:
                data.update({
                    "lots": [{
                        "auctionPeriod": {
                            "startDate": (now - timedelta(days=2)).isoformat(),
                            "endDate": (now - timedelta(days=1)).isoformat(),
                        }
                    } for i in self.initial_lots]
                })
        elif status == "complete":
            data.update({
                "enquiryPeriod": {
                    "startDate":
                    (now - TENDERING_DURATION - COMPLAINT_STAND_STILL -
                     timedelta(days=4)).isoformat(),
                    "endDate":
                    (now - QUESTIONS_STAND_STILL - COMPLAINT_STAND_STILL -
                     timedelta(days=3)).isoformat(),
                },
                "tenderPeriod": {
                    "startDate":
                    (now - TENDERING_DURATION - COMPLAINT_STAND_STILL -
                     timedelta(days=4)).isoformat(),
                    "endDate": (now - COMPLAINT_STAND_STILL -
                                timedelta(days=3)).isoformat(),
                },
                "auctionPeriod": {
                    "startDate": (now - timedelta(days=3)).isoformat(),
                    "endDate": (now - timedelta(days=2)).isoformat(),
                },
                "awardPeriod": {
                    "startDate": (now - timedelta(days=1)).isoformat(),
                    "endDate": (now).isoformat()
                },
            })
            if self.initial_lots:
                data.update({
                    "lots": [{
                        "auctionPeriod": {
                            "startDate": (now - timedelta(days=3)).isoformat(),
                            "endDate": (now - timedelta(days=2)).isoformat(),
                        }
                    } for i in self.initial_lots]
                })

        self.tender_document_patch = data
        if extra:
            self.tender_document_patch.update(extra)
        self.save_changes()
Ejemplo n.º 56
0
Archivo: base.py Proyecto: lttga/op2
    def update_status(self, status, extra=None):
        now = get_now()
        data = {"status": status}
        if status == "active.tendering":
            data.update({
                "enquiryPeriod": {
                    "startDate": (now).isoformat(),
                    "endDate": (now + timedelta(days=13)).isoformat(),
                },
                "tenderPeriod": {
                    "startDate": (now).isoformat(),
                    "endDate": (now + timedelta(days=16)).isoformat()
                },
            })
        elif status == "active.auction":
            data.update({
                "enquiryPeriod": {
                    "startDate": (now - timedelta(days=16)).isoformat(),
                    "endDate": (now - timedelta(days=3)).isoformat(),
                },
                "tenderPeriod": {
                    "startDate": (now - timedelta(days=16)).isoformat(),
                    "endDate": (now).isoformat()
                },
                "auctionPeriod": {
                    "startDate": (now).isoformat()
                },
            })
            if self.initial_lots:
                data.update({
                    "lots": [{
                        "auctionPeriod": {
                            "startDate": (now).isoformat()
                        }
                    } for i in self.initial_lots]
                })
        elif status == "active.qualification":
            data.update({
                "enquiryPeriod": {
                    "startDate": (now - timedelta(days=17)).isoformat(),
                    "endDate": (now - timedelta(days=4)).isoformat(),
                },
                "tenderPeriod": {
                    "startDate": (now - timedelta(days=17)).isoformat(),
                    "endDate": (now - timedelta(days=1)).isoformat(),
                },
                "auctionPeriod": {
                    "startDate": (now - timedelta(days=1)).isoformat(),
                    "endDate": (now).isoformat()
                },
                "awardPeriod": {
                    "startDate": (now).isoformat()
                },
            })
            if self.initial_lots:
                data.update({
                    "lots": [{
                        "auctionPeriod": {
                            "startDate": (now - timedelta(days=1)).isoformat(),
                            "endDate": (now).isoformat(),
                        }
                    } for i in self.initial_lots]
                })
        elif status == "active.awarded":
            data.update({
                "enquiryPeriod": {
                    "startDate": (now - timedelta(days=17)).isoformat(),
                    "endDate": (now - timedelta(days=4)).isoformat(),
                },
                "tenderPeriod": {
                    "startDate": (now - timedelta(days=17)).isoformat(),
                    "endDate": (now - timedelta(days=1)).isoformat(),
                },
                "auctionPeriod": {
                    "startDate": (now - timedelta(days=1)).isoformat(),
                    "endDate": (now).isoformat()
                },
                "awardPeriod": {
                    "startDate": (now).isoformat(),
                    "endDate": (now).isoformat()
                },
            })
            if self.initial_lots:
                data.update({
                    "lots": [{
                        "auctionPeriod": {
                            "startDate": (now - timedelta(days=1)).isoformat(),
                            "endDate": (now).isoformat(),
                        }
                    } for i in self.initial_lots]
                })
        elif status == "complete":
            data.update({
                "enquiryPeriod": {
                    "startDate": (now - timedelta(days=25)).isoformat(),
                    "endDate": (now - timedelta(days=11)).isoformat(),
                },
                "tenderPeriod": {
                    "startDate": (now - timedelta(days=25)).isoformat(),
                    "endDate": (now - timedelta(days=8)).isoformat(),
                },
                "auctionPeriod": {
                    "startDate": (now - timedelta(days=8)).isoformat(),
                    "endDate": (now - timedelta(days=7)).isoformat(),
                },
                "awardPeriod": {
                    "startDate": (now - timedelta(days=7)).isoformat(),
                    "endDate": (now - timedelta(days=7)).isoformat(),
                },
            })
            if self.initial_lots:
                data.update({
                    "lots": [{
                        "auctionPeriod": {
                            "startDate": (now - timedelta(days=8)).isoformat(),
                            "endDate": (now - timedelta(days=7)).isoformat(),
                        }
                    } for i in self.initial_lots]
                })

        self.tender_document_patch = data
        if extra:
            self.tender_document_patch.update(extra)
        self.save_changes()
Ejemplo n.º 57
0
 def validate_id(self, data, code):
     schematics_document = get_schematics_document(data['__parent__'])
     if (schematics_document.get('revisions')[0].date if schematics_document.get('revisions') else get_now()) > ATC_INN_CLASSIFICATIONS_FROM:
         if data.get('scheme') == u'ATC' and code not in ATC_CODES:
             raise ValidationError(BaseType.MESSAGES['choices'].format(unicode(ATC_CODES)))
         elif data.get('scheme') == u'INN' and code not in INN_CODES:
             raise ValidationError(BaseType.MESSAGES['choices'].format(unicode(INN_CODES)))
 def patch(self):
     """Post a complaint resolution for award
     """
     tender = self.request.validated['tender']
     data = self.request.validated['data']
     complaintPeriod = self.request.validated['award'].complaintPeriod
     is_complaintPeriod = complaintPeriod.startDate < get_now(
     ) and complaintPeriod.endDate > get_now(
     ) if complaintPeriod.endDate else complaintPeriod.startDate < get_now(
     )
     # complaint_owner
     if self.request.authenticated_role == 'complaint_owner' and self.context.status in [
             'draft', 'claim', 'answered'
     ] and data.get('status', self.context.status) == 'cancelled':
         apply_patch(self.request, save=False, src=self.context.serialize())
         self.context.dateCanceled = get_now()
     elif self.request.authenticated_role == 'complaint_owner' and self.context.status in [
             'pending', 'accepted'
     ] and data.get('status', self.context.status) == 'stopping':
         apply_patch(self.request, save=False, src=self.context.serialize())
         self.context.dateCanceled = get_now()
     elif self.request.authenticated_role == 'complaint_owner' and is_complaintPeriod and self.context.status == 'draft' and data.get(
             'status', self.context.status) == self.context.status:
         apply_patch(self.request, save=False, src=self.context.serialize())
     elif self.request.authenticated_role == 'complaint_owner' and is_complaintPeriod and self.context.status == 'draft' and data.get(
             'status', self.context.status) == 'claim':
         if self.request.validated[
                 'award'].status == 'unsuccessful' and self.request.validated[
                     'award'].bid_id != self.context.bid_id:
             raise_operation_error(
                 self.request,
                 'Can add claim only on unsuccessful award of your bid')
         apply_patch(self.request, save=False, src=self.context.serialize())
         self.context.dateSubmitted = get_now()
     elif self.request.authenticated_role == 'complaint_owner' and is_complaintPeriod and self.context.status == 'draft' and data.get(
             'status', self.context.status) == 'pending':
         if not any([
                 i.status == 'active' for i in tender.awards
                 if i.lotID == self.request.validated['award'].lotID
         ]):
             raise_operation_error(
                 self.request,
                 'Complaint submission is allowed only after award activation.'
             )
         apply_patch(self.request, save=False, src=self.context.serialize())
         self.context.type = 'complaint'
         self.context.dateSubmitted = get_now()
     elif self.request.authenticated_role == 'complaint_owner' and self.context.status == 'answered' and data.get(
             'status', self.context.status) == self.context.status:
         apply_patch(self.request, save=False, src=self.context.serialize())
     # tender_owner
     elif self.request.authenticated_role == 'tender_owner' and self.context.status in [
             'pending', 'accepted'
     ]:
         apply_patch(self.request, save=False, src=self.context.serialize())
     elif self.request.authenticated_role == 'tender_owner' and self.context.status in [
             'claim', 'satisfied'
     ] and data.get('status', self.context.status) == self.context.status:
         apply_patch(self.request, save=False, src=self.context.serialize())
     elif self.request.authenticated_role == 'tender_owner' and self.context.status == 'claim' and data.get(
             'resolution', self.context.resolution) and data.get(
                 'resolutionType',
                 self.context.resolutionType) and data.get(
                     'status', self.context.status) == 'answered':
         if len(data.get('resolution', self.context.resolution)) < 20:
             raise_operation_error(
                 self.request,
                 'Can\'t update complaint: resolution too short')
         apply_patch(self.request, save=False, src=self.context.serialize())
         self.context.dateAnswered = get_now()
     elif self.request.authenticated_role == 'tender_owner' and self.context.status == 'satisfied' and data.get(
             'tendererAction', self.context.tendererAction) and data.get(
                 'status', self.context.status) == 'resolved':
         apply_patch(self.request, save=False, src=self.context.serialize())
     # aboveThresholdReviewers
     elif self.request.authenticated_role == 'aboveThresholdReviewers' and self.context.status in [
             'pending', 'accepted', 'stopping'
     ] and data.get('status', self.context.status) == self.context.status:
         apply_patch(self.request, save=False, src=self.context.serialize())
     elif self.request.authenticated_role == 'aboveThresholdReviewers' and self.context.status in [
             'pending', 'stopping'
     ] and data.get('status',
                    self.context.status) in ['invalid', 'mistaken']:
         apply_patch(self.request, save=False, src=self.context.serialize())
         self.context.dateDecision = get_now()
         self.context.acceptance = False
     elif self.request.authenticated_role == 'aboveThresholdReviewers' and self.context.status == 'pending' and data.get(
             'status', self.context.status) == 'accepted':
         apply_patch(self.request, save=False, src=self.context.serialize())
         self.context.dateAccepted = get_now()
         self.context.acceptance = True
     elif self.request.authenticated_role == 'aboveThresholdReviewers' and self.context.status in [
             'accepted', 'stopping'
     ] and data.get('status',
                    self.context.status) in ['declined', 'satisfied']:
         apply_patch(self.request, save=False, src=self.context.serialize())
         self.context.dateDecision = get_now()
     elif self.request.authenticated_role == 'aboveThresholdReviewers' and self.context.status in [
             'pending', 'accepted', 'stopping'
     ] and data.get('status', self.context.status) == 'stopped':
         apply_patch(self.request, save=False, src=self.context.serialize())
         self.context.dateDecision = get_now()
         self.context.dateCanceled = self.context.dateCanceled or get_now()
     else:
         raise_operation_error(self.request, 'Can\'t update complaint')
     if self.context.tendererAction and not self.context.tendererActionDate:
         self.context.tendererActionDate = get_now()
     if self.context.status not in [
             'draft', 'claim', 'answered', 'pending', 'accepted',
             'satisfied', 'stopping'
     ] and tender.status in ['active.qualification', 'active.awarded']:
         check_tender_status(self.request)
     if save_tender(self.request):
         self.LOGGER.info(
             'Updated tender award complaint {}'.format(self.context.id),
             extra=context_unpack(
                 self.request,
                 {'MESSAGE_ID': 'tender_award_complaint_patch'}))
         return {'data': self.context.serialize("view")}
def date_signed_on_change_creation_for_very_old_contracts_data(self):
    # prepare old contract data
    contract = self.databases.contracts.get(self.contract["id"])
    contract["dateSigned"] = None
    self.databases.contracts.save(contract)

    response = self.app.get("/contracts/{}?acc_token={}".format(self.contract["id"], self.contract_token))
    self.assertEqual(response.status, "200 OK")
    self.assertNotIn("dateSigned", response.json["data"])

    self.app.authorization = ("Basic", ("broker", ""))
    one_day_in_past = (get_now() - timedelta(days=1)).isoformat()
    response = self.app.post_json(
        "/contracts/{}/changes?acc_token={}".format(self.contract["id"], self.contract_token),
        {
            "data": {
                "rationale": "причина зміни укр",
                "rationale_en": "change cause en",
                "rationaleTypes": ["priceReduction"],
                "contractNumber": "№ 146",
                "dateSigned": one_day_in_past,
            }
        },
    )
    self.assertEqual(response.json["data"]["dateSigned"], one_day_in_past)
    change = response.json["data"]
    response = self.app.patch_json(
        "/contracts/{}/changes/{}?acc_token={}".format(self.contract["id"], change["id"], self.contract_token),
        {"data": {"status": "active"}},
    )
    self.assertEqual(response.json["data"]["status"], "active")

    # prepare old contract change data
    contract = self.databases.contracts.get(self.contract["id"])
    last_change = contract["changes"][-1]
    last_change["dateSigned"] = None
    self.databases.contracts.save(contract)

    response = self.app.get(
        "/contracts/{}/changes/{}?acc_token={}".format(self.contract["id"], last_change["id"], self.contract_token)
    )
    self.assertEqual(response.status, "200 OK")
    self.assertNotIn("dateSigned", response.json["data"])

    response = self.app.post_json(
        "/contracts/{}/changes?acc_token={}".format(self.contract["id"], self.contract_token),
        {
            "data": {
                "rationale": "третя причина зміни укр",
                "rationale_en": "third change cause en",
                "rationaleTypes": ["priceReduction"],
                "contractNumber": "№ 148",
                "dateSigned": one_day_in_past,
            }
        },
        status=403,
    )
    self.assertEqual(
        "Change dateSigned ({}) can't be earlier than last active change dateSigned ({})".format(
            one_day_in_past, last_change["date"]
        ),
        response.json["errors"][0]["description"],
    )

    valid_date = get_now().isoformat()
    response = self.app.post_json(
        "/contracts/{}/changes?acc_token={}".format(self.contract["id"], self.contract_token),
        {
            "data": {
                "rationale": "третя причина зміни укр",
                "rationale_en": "third change cause en",
                "rationaleTypes": ["priceReduction"],
                "contractNumber": "№ 148",
                "dateSigned": valid_date,
            }
        },
    )
    self.assertEqual(response.json["data"]["dateSigned"], valid_date)
                    u"region": u"м. Львів",
                    u"locality": u"м. Львів"
                    }
        }
    ],
    u"contractNumber": u"contract #13111",
    u"period": {
                u"startDate": u"2016-03-18T18:47:47.155143+02:00",
                u"endDate": u"2017-03-18T18:47:47.155143+02:00"
            },
    u"value": {
        u"currency": u"UAH",
        u"amount": 238.0,
        u"valueAddedTaxIncluded": True
        },
    u"dateSigned": get_now().isoformat(),
    u"awardID": u"8481d7eb01694c25b18658036c236c5d",
    u"id": uuid4().hex,
    u"contractID": u"UA-2016-03-18-000001-1",
    u"tender_id": uuid4().hex,
    u"tender_token": uuid4().hex,
    u"owner": u"broker"
}


test_contract_data_wo_items = deepcopy(test_contract_data)
del test_contract_data_wo_items['items']


documents = [
    {