Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
ktarasz committed Jan 25, 2016
2 parents 2a7a7aa + 643cd17 commit d271aea
Show file tree
Hide file tree
Showing 9 changed files with 97 additions and 13 deletions.
Binary file modified docs/source/complaint_w.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion openprocurement/tender/openua/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@

def includeme(config):
config.add_tender_procurementMethodType(Tender)
config.scan("openprocurement.tender.openua")
config.scan("openprocurement.tender.openua.views")
2 changes: 1 addition & 1 deletion openprocurement/tender/openua/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,7 @@ def numberOfBids(self):
def next_check(self):
now = get_now()
checks = []
if self.status == 'active.tendering' and self.tenderPeriod.endDate and not any([i.status == 'accepted' for i in self.complaints]):
if self.status == 'active.tendering' and self.tenderPeriod.endDate and not any([i.status in ['pending', 'accepted'] for i in self.complaints]):
checks.append(self.tenderPeriod.endDate.astimezone(TZ))
elif not self.lots and self.status == 'active.awarded':
standStillEnds = [
Expand Down
7 changes: 6 additions & 1 deletion openprocurement/tender/openua/tests/award.py
Original file line number Diff line number Diff line change
Expand Up @@ -858,7 +858,7 @@ def test_patch_tender_award_complaint(self):
self.assertEqual(response.json['errors'][0]["description"], "Can't update complaint in current (complete) tender status")

def test_review_tender_award_complaint(self):
for status in ['invalid', 'resolved', 'declined']:
for status in ['invalid', 'declined', 'resolved']:
self.app.authorization = ('Basic', ('token', ''))
response = self.app.post_json('/tenders/{}/awards/{}/complaints'.format(self.tender_id, self.award_id), {'data': {
'title': 'complaint title',
Expand Down Expand Up @@ -901,6 +901,11 @@ def test_review_tender_award_complaint(self):
self.assertEqual(response.content_type, 'application/json')
self.assertEqual(response.json['data']["status"], status)

response = self.app.get('/tenders/{}/awards/{}'.format(self.tender_id, self.award_id))
self.assertEqual(response.status, '200 OK')
self.assertEqual(response.content_type, 'application/json')
self.assertEqual(response.json['data']["status"], "cancelled")

def test_get_tender_award_complaint(self):
response = self.app.post_json('/tenders/{}/awards/{}/complaints'.format(
self.tender_id, self.award_id), {'data': {'title': 'complaint title', 'description': 'complaint description', 'author': test_tender_ua_data["procuringEntity"]}})
Expand Down
6 changes: 3 additions & 3 deletions openprocurement/tender/openua/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ def check_bids(request):
tender = request.validated['tender']
if tender.lots:
[setattr(i, 'status', 'unsuccessful') for i in tender.lots if i.numberOfBids < 2]
if set([i.status for i in tender.lots]) == set(['unsuccessful']):
if not set([i.status for i in tender.lots]).difference(set(['unsuccessful', 'cancelled'])):
tender.status = 'unsuccessful'
else:
if tender.numberOfBids < 2:
Expand All @@ -41,15 +41,15 @@ def check_bids(request):
def check_status(request):
tender = request.validated['tender']
now = get_now()
if not tender.lots and tender.status == 'active.tendering' and tender.tenderPeriod.endDate <= now and not any([i.status == 'accepted' for i in tender.complaints]):
if not tender.lots and tender.status == 'active.tendering' and tender.tenderPeriod.endDate <= now and not any([i.status in ['pending', 'accepted'] for i in tender.complaints]):
LOGGER.info('Switched tender {} to {}'.format(tender['id'], 'active.auction'),
extra=context_unpack(request, {'MESSAGE_ID': 'switched_tender_active.auction'}))
tender.status = 'active.auction'
check_bids(request)
if tender.numberOfBids < 2 and tender.auctionPeriod:
tender.auctionPeriod.startDate = None
return
elif tender.lots and tender.status == 'active.tendering' and tender.tenderPeriod.endDate <= now and not any([i.status == 'accepted' for i in tender.complaints]):
elif tender.lots and tender.status == 'active.tendering' and tender.tenderPeriod.endDate <= now and not any([i.status in ['pending', 'accepted'] for i in tender.complaints]):
LOGGER.info('Switched tender {} to {}'.format(tender['id'], 'active.auction'),
extra=context_unpack(request, {'MESSAGE_ID': 'switched_tender_active.auction'}))
tender.status = 'active.auction'
Expand Down
2 changes: 1 addition & 1 deletion openprocurement/tender/openua/views/award.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ def patch(self):
i.complaintPeriod.endDate = now
i.status = 'cancelled'
for j in i.complaints:
if j.status != ['invalid', 'resolved', 'declined']:
if j.status not in ['invalid', 'resolved', 'declined']:
j.status = 'cancelled'
j.cancellationReason = 'cancelled'
j.dateCanceled = now
Expand Down
24 changes: 22 additions & 2 deletions openprocurement/tender/openua/views/award_complaint.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
validate_complaint_data,
validate_patch_complaint_data,
)
from openprocurement.tender.openua.utils import add_next_award

LOGGER = getLogger(__name__)

Expand Down Expand Up @@ -123,14 +124,33 @@ def patch(self):
self.context.dateAccepted = get_now()
elif self.request.authenticated_role == 'reviewers' and self.context.status == 'accepted' 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 == 'reviewers' and self.context.status == 'accepted' and data.get('status', self.context.status) in ['resolved', 'invalid', 'declined']:
elif self.request.authenticated_role == 'reviewers' and self.context.status == 'accepted' and data.get('status', self.context.status) in ['invalid', 'declined']:
apply_patch(self.request, save=False, src=self.context.serialize())
self.context.dateDecision = get_now()
elif self.request.authenticated_role == 'reviewers' and self.context.status == 'accepted' and data.get('status', self.context.status) == 'resolved':
apply_patch(self.request, save=False, src=self.context.serialize())
self.context.dateDecision = get_now()
cancelled_awards = []
for i in tender.awards:
if i.lotID != self.context.relatedLot:
continue
i.complaintPeriod.endDate = self.context.dateDecision
i.status = 'cancelled'
for j in i.complaints:
if j.status not in ['invalid', 'resolved', 'declined']:
j.status = 'cancelled'
j.cancellationReason = 'cancelled'
j.dateCanceled = self.context.dateDecision
cancelled_awards.append(i.id)
for i in tender.contracts:
if i.awardID in cancelled_awards:
i.status = 'cancelled'
add_next_award(self.request)
else:
self.request.errors.add('body', 'data', 'Can\'t update complaint')
self.request.errors.status = 403
return
if self.context.status not in ['draft', 'claim', 'answered', 'pending'] and tender.status == 'active.awarded':
if self.context.status not in ['draft', 'claim', 'answered', 'pending', 'accepted'] and tender.status in ['active.qualification', 'active.awarded']:
check_tender_status(self.request)
if save_tender(self.request):
LOGGER.info('Updated tender award complaint {}'.format(self.context.id),
Expand Down
7 changes: 5 additions & 2 deletions openprocurement/tender/openua/views/complaint.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,14 +127,17 @@ def patch(self):
self.context.dateAccepted = get_now()
elif self.request.authenticated_role == 'reviewers' and self.context.status == 'accepted' 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 == 'reviewers' and self.context.status == 'accepted' and data.get('status', self.context.status) in ['resolved', 'invalid', 'declined']:
elif self.request.authenticated_role == 'reviewers' and self.context.status == 'accepted' and data.get('status', self.context.status) in ['invalid', 'declined']:
apply_patch(self.request, save=False, src=self.context.serialize())
self.context.dateDecision = get_now()
elif self.request.authenticated_role == 'reviewers' and self.context.status == 'accepted' and data.get('status', self.context.status) == 'resolved':
apply_patch(self.request, save=False, src=self.context.serialize())
self.context.dateDecision = get_now()
else:
self.request.errors.add('body', 'data', 'Can\'t update complaint')
self.request.errors.status = 403
return
if self.context.status not in ['draft', 'claim', 'answered', 'pending'] and tender.status == 'active.awarded':
if self.context.status not in ['draft', 'claim', 'answered', 'pending', 'accepted'] and tender.status in ['active.qualification', 'active.awarded']:
check_tender_status(self.request)
if save_tender(self.request):
LOGGER.info('Updated tender complaint {}'.format(self.context.id),
Expand Down
60 changes: 58 additions & 2 deletions openprocurement/tender/openua/views/contract.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@
# -*- coding: utf-8 -*-
from logging import getLogger
from openprocurement.api.models import get_now
from openprocurement.api.utils import opresource
from openprocurement.api.views.contract import TenderAwardContractResource
from openprocurement.api.utils import (
apply_patch,
check_tender_status,
context_unpack,
json_view,
opresource,
save_tender,
)


from openprocurement.api.validation import validate_patch_contract_data

LOGGER = getLogger(__name__)


Expand All @@ -14,4 +23,51 @@
procurementMethodType='aboveThresholdUA',
description="Tender contracts")
class TenderUaAwardContractResource(TenderAwardContractResource):
pass

@json_view(content_type="application/json", permission='edit_tender', validators=(validate_patch_contract_data,))
def patch(self):
"""Update of contract
"""
if self.request.validated['tender_status'] not in ['active.qualification', 'active.awarded', 'complete']:
self.request.errors.add('body', 'data', 'Can\'t update contract in current ({}) tender status'.format(self.request.validated['tender_status']))
self.request.errors.status = 403
return
tender = self.request.validated['tender']
if any([i.status != 'active' for i in tender.lots if i.id in [a.lotID for a in tender.awards if a.id == self.request.context.awardID]]):
self.request.errors.add('body', 'data', 'Can update contract only in active lot status')
self.request.errors.status = 403
return
data = self.request.validated['data']
if self.request.context.status != 'active' and 'status' in data and data['status'] == 'active':
award = [a for a in tender.awards if a.id == self.request.context.awardID][0]
stand_still_end = award.complaintPeriod.endDate
if stand_still_end > get_now():
self.request.errors.add('body', 'data', 'Can\'t sign contract before stand-still period end ({})'.format(stand_still_end.isoformat()))
self.request.errors.status = 403
return
pending_complaints = [
i
for i in tender.complaints
if i.status in ['claim', 'answered', 'pending', 'accepted'] and i.relatedLot in [None, award.lotID]
]
pending_awards_complaints = [
i
for a in tender.awards
for i in a.complaints
if i.status in ['claim', 'answered', 'pending', 'accepted'] and a.lotID == award.lotID
]
if pending_complaints or pending_awards_complaints:
self.request.errors.add('body', 'data', 'Can\'t sign contract before reviewing all complaints')
self.request.errors.status = 403
return
contract_status = self.request.context.status
apply_patch(self.request, save=False, src=self.request.context.serialize())
if contract_status != self.request.context.status and (contract_status != 'pending' or self.request.context.status != 'active'):
self.request.errors.add('body', 'data', 'Can\'t update contract status')
self.request.errors.status = 403
return
check_tender_status(self.request)
if save_tender(self.request):
LOGGER.info('Updated tender contract {}'.format(self.request.context.id),
extra=context_unpack(self.request, {'MESSAGE_ID': 'tender_contract_patch'}))
return {'data': self.request.context.serialize()}

0 comments on commit d271aea

Please sign in to comment.