Skip to content

Commit

Permalink
Merge pull request #9 from gorserg/init_bridge
Browse files Browse the repository at this point in the history
add bridge
  • Loading branch information
vmaksymiv committed Jul 7, 2016
2 parents 8bdf0ad + 076058a commit a8f7c3b
Show file tree
Hide file tree
Showing 7 changed files with 719 additions and 9 deletions.
1 change: 1 addition & 0 deletions .coveragerc
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
[run]
omit =
*tests*
*databridge.py

[report]
exclude_lines =
Expand Down
606 changes: 606 additions & 0 deletions openprocurement/tender/competitivedialogue/databridge.py

Large diffs are not rendered by default.

34 changes: 34 additions & 0 deletions openprocurement/tender/competitivedialogue/journal_msg_ids.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
DATABRIDGE_RESTART = "cd_bridge_restart"
DATABRIDGE_GET_CREDENTIALS = "cd_bridge_get_tender_credentials"
DATABRIDGE_GOT_CREDENTIALS = "cd_bridge_got_tender_credentials"
DATABRIDGE_FOUND_NOLOT = "cd_bridge_found_nolot"
DATABRIDGE_COPY_TENDER_ITEMS = "cd_bridge_prepare_items"
DATABRIDGE_GET_EXTRA_INFO = "cd_bridge_get_credentials"
DATABRIDGE_MISSING_CREDENTIALS = "cd_bridge_missing_credentials"
DATABRIDGE_GOT_EXTRA_INFO = "cd_bridge_got_credentials"
DATABRIDGE_CREATE_NEW_TENDER = "cd_bridge_create_new_tender"
DATABRIDGE_TENDER_CREATED = "cd_bridge_tender_created"
DATABRIDGE_CD_PATCHED = "cd_bridge_cd_patched"
DATABRIDGE_UNSUCCESSFUL_CREATE = "cd_bridge_unsuccessful_create"
DATABRIDGE_RETRY_CREATE = "cd_bridge_create_retry"
DATABRIDGE_CREATE_ERROR = "cd_bridge_create_error"
DATABRIDGE_TENDER_PROCESS = "cd_bridge_tender_process"
DATABRIDGE_SKIP_NOT_MODIFIED = "cd_bridge_not_modified"
DATABRIDGE_SYNC_SLEEP = "cd_bridge_sleep"
DATABRIDGE_SYNC_RESUME = "cd_bridge_resume"
DATABRIDGE_PATCH_DIALOG = "cd_patch_dialog"
DATABRIDGE_UNSUCCESSFUL_PATCH = "cd_bridge_unsuccessful_patch"
DATABRIDGE_RETRY_PATCH = "cd_bridge_patch_retry"
DATABRIDGE_CD_PATCH_STAGE2_ID = "cd_bridge_patch_dialog_stage2_id"
DATABRIDGE_CD_UNSUCCESSFUL_PATCH_STAGE2_ID = "cd_bridge_unsuccessful_patch_dialog_stage2_id"
DATABRIDGE_CD_RETRY_PATCH_STAGE2_ID = "cd_bridge_retry_patch_dialog_stage2_id"
DATABRIDGE_CD_PATCHED_STAGE2_ID = "cd_bridge_retry_patched_dialog_stage2_id"
DATABRIDGE_PATCH_NEW_TENDER_STATUS = "cd_bridge_patch_new_tender_status"
DATABRIDGE_UNSUCCESSFUL_PATCH_NEW_TENDER_STATUS = "cd_bridge_unsuccessful_patch_new_tender_status"
DATABRIDGE_SUCCESSFUL_PATCH_NEW_TENDER_STATUS = "cd_bridge_successful_patch_new_tender_status"
DATABRIDGE_PATCH_DIALOG_STATUS = "cd_bridge_patch_dialog_status"
DATABRIDGE_UNSUCCESSFUL_PATCH_DIALOG_STATUS = "cd_bridge_unsuccessful_patch_dialog_status"
DATABRIDGE_SUCCESSFUL_PATCH_DIALOG_STATUS = "cd_bridge_successful_patch_dialog_status"
DATABRIDGE_ONLY_PATCH = 'cd_bridge_need_patch'
DATABRIDGE_TENDER_STAGE2_NOT_EXIST = 'cd_bridge_tender_stage2_not_exist'

39 changes: 35 additions & 4 deletions openprocurement/tender/competitivedialogue/models.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
# -*- coding: utf-8 -*-
from datetime import timedelta
from schematics.types import StringType
from schematics.exceptions import ValidationError
from zope.interface import implementer
from pyramid.security import Allow
from schematics.types.compound import ModelType
from openprocurement.api.models import ITender, Identifier, Model
from openprocurement.api.utils import calculate_business_date, get_now
from openprocurement.tender.openua.models import SifterListType, Item as BaseItem
from openprocurement.tender.openeu.models import (Tender as TenderEU, Administrator_bid_role, view_bid_role,
pre_qualifications_role, Bid as BidEU, ConfidentialDocument,
edit_role_eu, auction_patch_role, auction_view_role,
auction_post_role)
auction_post_role, QUESTIONS_STAND_STILL, ENQUIRY_STAND_STILL_TIME,
PeriodStartEndRequired, EnquiryPeriod)
from openprocurement.api.models import (
plain_role, create_role, edit_role, view_role, listing_role,
enquiries_role, validate_cpv_group, validate_items_uniq,
Expand All @@ -25,6 +28,8 @@
STAGE_2_EU_TYPE = "competitiveDialogueEU.stage2"
STAGE_2_UA_TYPE = "competitiveDialogueUA.stage2"

STAGE2_STATUS = 'draft.stage2'

edit_role_ua = edit_role + blacklist('enquiryPeriod', 'status')
edit_stage2_pending = whitelist('status')
edit_stage2_waiting = whitelist('status', 'stage2TenderID')
Expand Down Expand Up @@ -187,7 +192,7 @@ class Tender(CompetitiveDialogEU):

stage_2_roles = {
'plain': plain_role,
'create': (blacklist('owner_token', '_attachments', 'revisions', 'dateModified', 'doc_id', 'tenderID', 'bids', 'documents', 'awards', 'questions', 'complaints', 'auctionUrl', 'status', 'auctionPeriod', 'awardPeriod', 'awardCriteria', 'submissionMethod', 'cancellations') + schematics_embedded_role),
'create': (blacklist('owner_token', 'tenderPeriod', '_attachments', 'revisions', 'dateModified', 'doc_id', 'tenderID', 'bids', 'documents', 'awards', 'questions', 'complaints', 'auctionUrl', 'status', 'auctionPeriod', 'awardPeriod', 'awardCriteria', 'submissionMethod', 'cancellations') + schematics_embedded_role),
'edit': edit_role_eu + close_edit_technical_fields,
'edit_draft': edit_role_eu + close_edit_technical_fields,
'edit_active.tendering': edit_role_eu + close_edit_technical_fields,
Expand All @@ -204,7 +209,8 @@ class Tender(CompetitiveDialogEU):
'auction_view': auction_view_role,
'auction_post': auction_post_role,
'auction_patch': auction_patch_role,
'draft': enquiries_role + hide_dialogue_token,
'draft': enquiries_role + blacklist('dialogue_token', 'shortlistedFirms'),
'draft.stage2': enquiries_role + hide_dialogue_token,
'active.tendering': enquiries_role + hide_dialogue_token,
'active.pre-qualification': pre_qualifications_role + hide_dialogue_token,
'active.pre-qualification.stand-still': pre_qualifications_role + hide_dialogue_token,
Expand All @@ -219,15 +225,28 @@ class Tender(CompetitiveDialogEU):
'Administrator': Administrator_role,
'default': schematics_default_role,
'contracting': whitelist('doc_id', 'owner'),
'competitive_dialogue': edit_stage2_waiting
}


def init_PeriodStartEndRequired():
return PeriodStartEndRequired({"startDate": get_now(),
"endDate": calculate_business_date(get_now(), timedelta(days=30))})

@implementer(ITender)
class Tender(TenderEU):
procurementMethodType = StringType(default=STAGE_2_EU_TYPE)
dialogue_token = StringType(required=True)
dialogueID = StringType()
shortlistedFirms = ListType(ModelType(Firms), required=True)
tenderPeriod = ModelType(PeriodStartEndRequired, required=False,
default=init_PeriodStartEndRequired)
status = StringType(
choices=['draft', 'active.tendering', 'active.pre-qualification', 'active.pre-qualification.stand-still',
'active.auction', 'active.qualification', 'active.awarded', 'complete', 'cancelled',
'unsuccessful', STAGE2_STATUS],
default='active.tendering')


class Options:
roles = stage_2_roles.copy()
Expand All @@ -249,10 +268,22 @@ def __acl__(self):
acl.extend([
(Allow, '{}_{}'.format(self.owner, self.owner_token), 'edit_tender'),
(Allow, '{}_{}'.format(self.owner, self.owner_token), 'upload_tender_documents'),
(Allow, '{}_{}'.format(self.owner, self.owner_token), 'edit_complaint')
(Allow, '{}_{}'.format(self.owner, self.owner_token), 'edit_complaint'),
(Allow, 'g:competitive_dialogue', 'edit_tender')
])
return acl

def initialize(self):
self.tenderPeriod = PeriodStartEndRequired(
dict(startDate=get_now(), endDate=calculate_business_date(get_now(), timedelta(days=30), self)))
endDate = calculate_business_date(self.tenderPeriod.endDate, -QUESTIONS_STAND_STILL, self)
self.enquiryPeriod = EnquiryPeriod(dict(startDate=self.tenderPeriod.startDate,
endDate=endDate,
invalidationDate=self.enquiryPeriod and self.enquiryPeriod.invalidationDate,
clarificationsUntil=calculate_business_date(endDate,
ENQUIRY_STAND_STILL_TIME,
self, True)))


TenderStage2EU = Tender

Expand Down
34 changes: 34 additions & 0 deletions openprocurement/tender/competitivedialogue/validation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
from openprocurement.api.validation import validate_data, validate_json_data
from openprocurement.api.utils import apply_data_patch
from openprocurement.tender.competitivedialogue.models import STAGE2_STATUS


def validate_patch_tender_stage2_data(request):
data = validate_json_data(request)
if request.context.status == 'draft':
default_statuses = ['active.tendering', STAGE2_STATUS]
if data.get('status') not in default_statuses:
request.errors.add('body', 'data', 'Can\'t update tender in current ({0}) status'.format(data['status']))
request.errors.status = 403
return
request.validated['data'] = {'status': data.get('status')}
request.context.status = data.get('status')
return
if data:
if 'items' in data:
items = request.context.items
cpv_group_lists = [i.classification.id[:3] for i in items]
for item in data['items']:
if 'classification' in item and 'id' in item['classification']:
cpv_group_lists.append(item['classification']['id'][:3])
if len(set(cpv_group_lists)) != 1:
request.errors.add('body', 'item', 'Can\'t change classification')
request.errors.status = 403
return None
if 'enquiryPeriod' in data:
if apply_data_patch(request.context.enquiryPeriod.serialize(), data['enquiryPeriod']):
request.errors.add('body', 'item', 'Can\'t change enquiryPeriod')
request.errors.status = 403
return None

return validate_data(request, type(request.tender), True, data)
11 changes: 6 additions & 5 deletions openprocurement/tender/competitivedialogue/views/tender.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from openprocurement.tender.competitivedialogue.utils import patch_eu, set_ownership
from openprocurement.api.utils import opresource, json_view, save_tender, context_unpack, APIResource
from openprocurement.tender.competitivedialogue.models import CD_EU_TYPE, CD_UA_TYPE, STAGE_2_EU_TYPE, STAGE_2_UA_TYPE
from openprocurement.tender.competitivedialogue.validation import validate_patch_tender_stage2_data


@opresource(name='Competitive Dialogue for EU procedure',
Expand Down Expand Up @@ -35,10 +36,10 @@ def patch(self):
path='/tenders/{tender_id}',
procurementMethodType=STAGE_2_UA_TYPE,
description="")
class TenderStage2UAResource(TenderResource):
class TenderStage2UAResource(TenderEUResource):
""" Resource handler for tender stage 2 UA"""

@json_view(content_type="application/json", validators=(validate_patch_tender_ua_data,), permission='edit_tender')
@json_view(content_type="application/json", validators=(validate_patch_tender_stage2_data,), permission='edit_tender')
def patch(self):
return patch_eu(self)

Expand All @@ -47,10 +48,10 @@ def patch(self):
path='/tenders/{tender_id}',
procurementMethodType=STAGE_2_EU_TYPE,
description="")
class TenderStage2UEResource(TenderResource):
class TenderStage2UEResource(TenderEUResource):
""" Resource handler for tender stage 2 EU"""

@json_view(content_type="application/json", validators=(validate_patch_tender_ua_data,), permission='edit_tender')
@json_view(content_type="application/json", validators=(validate_patch_tender_stage2_data,), permission='edit_tender')
def patch(self):
return patch_eu(self)

Expand All @@ -64,7 +65,7 @@ class TenderStage2EUCredentialsResource(APIResource):
@json_view(permission='generate_credentials')
def patch(self):
tender = self.request.validated['tender']
if tender.status != "draft":
if tender.status != "draft.stage2":
self.request.errors.add('body', 'data',
'Can\'t generate credentials in current ({}) contract status'.format(
tender.status))
Expand Down
3 changes: 3 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@
]

entry_points = {
'console_scripts': [
'competitive_dialogue_data_bridge = openprocurement.tender.competitivedialogue.databridge:main'
],
'openprocurement.api.plugins': [
'competitivedialogue = openprocurement.tender.competitivedialogue:includeme'
]
Expand Down

0 comments on commit a8f7c3b

Please sign in to comment.