Skip to content

Commit

Permalink
Merge branch 'a245173837477145_has_unanswered_questions'
Browse files Browse the repository at this point in the history
  • Loading branch information
kroman0 committed Jan 13, 2017
2 parents 7445562 + 5a43822 commit 6e3e38b
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 35 deletions.
72 changes: 72 additions & 0 deletions openprocurement/tender/openua/tests/question.py
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,78 @@ def test_patch_tender_question(self):
self.assertEqual(response.json['data']["answer"], "answer")
self.assertIn('dateAnswered', response.json['data'])

def create_question_for(self, questionOf, relatedItem):
response = self.app.post_json('/tenders/{}/questions'.format(self.tender_id), {'data': {
'title': 'question title',
'description': 'question description',
"questionOf": questionOf,
"relatedItem": relatedItem,
'author': test_organization
}})
self.assertEqual(response.status, '201 Created')
return response.json['data']['id']

def test_tender_has_unanswered_questions(self):
question_id = self.create_question_for("tender", self.tender_id)

self.set_status('active.auction', {'status': 'active.tendering'})
self.app.authorization = ('Basic', ('chronograph', ''))
response = self.app.patch_json('/tenders/{}'.format(self.tender_id), {"data": {"id": self.tender_id}})
self.assertEqual(response.json['data']['status'], 'active.tendering')

self.app.authorization = ('Basic', ('broker', ''))
response = self.app.post_json('/tenders/{}/cancellations?acc_token={}'.format(self.tender_id, self.tender_token), {'data': {
'reason': 'cancellation reason',
'status': 'active',
}})
self.assertEqual(response.status, '201 Created')

response = self.app.get('/tenders/{}'.format(self.tender_id))
self.assertEqual(response.json['data']['status'], 'cancelled')

def test_lot_has_unanswered_questions(self):
question_id = self.create_question_for("lot", self.initial_lots[0]['id'])

self.set_status('active.auction', {'status': 'active.tendering'})
self.app.authorization = ('Basic', ('chronograph', ''))
response = self.app.patch_json('/tenders/{}'.format(self.tender_id), {"data": {"id": self.tender_id}})
self.assertEqual(response.json['data']['status'], 'active.tendering')

self.app.authorization = ('Basic', ('broker', ''))
response = self.app.post_json('/tenders/{}/cancellations?acc_token={}'.format(self.tender_id, self.tender_token), {'data': {
'reason': 'cancellation reason',
'status': 'active',
"cancellationOf": "lot",
"relatedLot": self.initial_lots[0]['id']
}})
self.assertEqual(response.status, '201 Created')

self.app.authorization = ('Basic', ('chronograph', ''))
response = self.app.patch_json('/tenders/{}'.format(self.tender_id), {"data": {"id": self.tender_id}})
self.assertEqual(response.json['data']['status'], 'unsuccessful')

def test_item_has_unanswered_questions(self):
items = self.app.get('/tenders/{}'.format(self.tender_id)).json['data']['items']
question_id = self.create_question_for("item", items[0]['id'])

self.set_status('active.auction', {'status': 'active.tendering'})
self.app.authorization = ('Basic', ('chronograph', ''))
response = self.app.patch_json('/tenders/{}'.format(self.tender_id), {"data": {"id": self.tender_id}})
self.assertEqual(response.json['data']['status'], 'active.tendering')

self.app.authorization = ('Basic', ('broker', ''))
response = self.app.post_json('/tenders/{}/cancellations?acc_token={}'.format(self.tender_id, self.tender_token), {'data': {
'reason': 'cancellation reason',
'status': 'active',
"cancellationOf": "lot",
"relatedLot": self.initial_lots[0]['id']
}})
self.assertEqual(response.status, '201 Created')

self.app.authorization = ('Basic', ('chronograph', ''))
response = self.app.patch_json('/tenders/{}'.format(self.tender_id), {"data": {"id": self.tender_id}})
self.assertEqual(response.json['data']['status'], 'unsuccessful')


def suite():
suite = unittest.TestSuite()
Expand Down
9 changes: 7 additions & 2 deletions openprocurement/tender/openua/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,13 @@ def check_complaint_status(request, complaint):
def has_unanswered_questions(tender, filter_cancelled_lots=True):
if filter_cancelled_lots and tender.lots:
active_lots = [l.id for l in tender.lots if l.status == 'active']
return any([i.id for i in tender.questions if i.relatedItem in active_lots and not i.answer])
return any([i.id for i in tender.questions if not i.answer])
active_items = [i.id for i in tender.items if not i.relatedLot or i.relatedLot in active_lots]
return any([
not i.answer
for i in tender.questions
if i.questionOf == 'tender' or i.questionOf == 'lot' and i.relatedItem in active_lots or i.questionOf == 'item' and i.relatedItem in active_items
])
return any([not i.answer for i in tender.questions])


def has_unanswered_complaints(tender, filter_cancelled_lots=True):
Expand Down
46 changes: 13 additions & 33 deletions openprocurement/tender/openua/views/question.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,49 +23,29 @@
description="Tender questions")
class TenderUaQuestionResource(TenderQuestionResource):

@json_view(content_type="application/json", validators=(validate_question_data,), permission='create_question')
def collection_post(self):
"""Post a question
"""
def validate_question(self, operation):
tender = self.request.validated['tender']
now = get_now()
if now < tender.enquiryPeriod.startDate or now > tender.enquiryPeriod.endDate:
if operation == 'add' and (now < tender.enquiryPeriod.startDate or now > tender.enquiryPeriod.endDate):
self.request.errors.add('body', 'data', 'Can add question only in enquiryPeriod')
self.request.errors.status = 403
return
question = self.request.validated['question']
if any([i.status != 'active' for i in tender.lots if i.id == question.relatedItem]):
self.request.errors.add('body', 'data', 'Can add question only in active lot status')
self.request.errors.status = 403
return
tender.questions.append(question)
if save_tender(self.request):
self.LOGGER.info('Created tender question {}'.format(question.id),
extra=context_unpack(self.request, {'MESSAGE_ID': 'tender_question_create'}, {'question_id': question.id}))
self.request.response.status = 201
self.request.response.headers['Location'] = self.request.route_url('Tender Questions', tender_id=tender.id, question_id=question.id)
return {'data': question.serialize("view")}

@json_view(content_type="application/json", permission='edit_tender', validators=(validate_patch_question_data,))
def patch(self):
"""Post an Answer
"""
tender = self.request.validated['tender']
if tender.status != 'active.tendering':
if operation == 'update' and tender.status != 'active.tendering':
self.request.errors.add('body', 'data', 'Can\'t update question in current ({}) tender status'.format(tender.status))
self.request.errors.status = 403
return
if any([i.status != 'active' for i in tender.lots if i.id == self.request.context.relatedItem]):
self.request.errors.add('body', 'data', 'Can update question only in active lot status')
question = self.request.validated['question']
items_dict = {i.id: i.relatedLot for i in tender.items}
if any([
i.status != 'active'
for i in tender.lots
if question.questionOf == 'lot' and i.id == question.relatedItem or question.questionOf == 'item' and i.id == items_dict[question.relatedItem]
]):
self.request.errors.add('body', 'data', 'Can {} question only in active lot status'.format(operation))
self.request.errors.status = 403
return
now = get_now()
if now > tender.enquiryPeriod.clarificationsUntil:
if operation == 'update' and now > tender.enquiryPeriod.clarificationsUntil:
self.request.errors.add('body', 'data', 'Can update question only before enquiryPeriod.clarificationsUntil')
self.request.errors.status = 403
return
self.context.dateAnswered = now
if apply_patch(self.request, src=self.request.context.serialize()):
self.LOGGER.info('Updated tender question {}'.format(self.request.context.id),
extra=context_unpack(self.request, {'MESSAGE_ID': 'tender_question_patch'}))
return {'data': self.request.context.serialize(tender.status)}
return True

0 comments on commit 6e3e38b

Please sign in to comment.