def patch(self): """Contract Edit (partial) """ contract = self.request.validated['contract'] if self.request.authenticated_role != 'Administrator' and contract.status != 'active': self.request.errors.add( 'body', 'data', 'Can\'t update contract in current ({}) status'.format( contract.status)) self.request.errors.status = 403 return apply_patch(self.request, save=False, src=self.request.validated['contract_src']) if contract.status == 'terminated' and not contract.amountPaid: self.request.errors.add( 'body', 'data', 'Can\'t terminate contract while \'amountPaid\' is not set') self.request.errors.status = 403 return if save_contract(self.request): self.LOGGER.info( 'Updated contract {}'.format(contract.id), extra=context_unpack(self.request, {'MESSAGE_ID': 'contract_patch'})) return {'data': contract.serialize('view')}
def post(self): contract = self.request.validated['contract'] for i in self.request.validated['json_data'].get('documents', []): doc = type(contract).documents.model_class(i) doc.__parent__ = contract contract.documents.append(doc) # set_ownership(contract, self.request) TODO self.request.validated['contract'] = contract self.request.validated['contract_src'] = {} if save_contract(self.request): self.LOGGER.info('Created contract {} ({})'.format( contract.id, contract.contractID), extra=context_unpack( self.request, {'MESSAGE_ID': 'contract_create'}, { 'contract_id': contract.id, 'contractID': contract.contractID or '' })) self.request.response.status = 201 return { 'data': contract.serialize("view"), 'access': { 'token': contract.owner_token } }
def post(self): contract = self.request.validated["contract"] for i in self.request.validated["json_data"].get("documents", []): doc = type(contract).documents.model_class(i) doc.__parent__ = contract contract.documents.append(doc) self.request.validated["contract"] = contract self.request.validated["contract_src"] = {} if save_contract(self.request): self.LOGGER.info( "Created contract {} ({})".format(contract.id, contract.contractID), extra=context_unpack( self.request, {"MESSAGE_ID": "contract_create"}, { "contract_id": contract.id, "contractID": contract.contractID or "" }, ), ) self.request.response.status = 201 return { "data": contract.serialize("view"), "access": { "token": contract.owner_token } }
def apply_patch(request, data=None, save=True, src=None): data = request.validated['data'] if data is None else data patch = data and apply_data_patch(src or request.context.serialize(), data) if patch: request.context.import_data(patch) if save: return save_contract(request)
def post(self): contract = self.request.validated["contract"] data = self.request.validated["ownership_data"] location = get_transfer_location(self.request, "Contract", contract_id=contract.id) transfer = extract_transfer(self.request, transfer_id=data["id"]) if transfer.get("usedFor") and transfer.get("usedFor") != location: self.request.errors.add("body", "transfer", "Transfer already used") self.request.errors.status = 403 return update_ownership(contract, transfer) self.request.validated["contract"] = contract transfer.usedFor = location self.request.validated["transfer"] = transfer if save_transfer(self.request): self.LOGGER.info( "Updated transfer relation {}".format(transfer.id), extra=context_unpack(self.request, {"MESSAGE_ID": "transfer_relation_update"}), ) if save_contract(self.request): self.LOGGER.info( "Updated ownership of contract {}".format(contract.id), extra=context_unpack(self.request, {"MESSAGE_ID": "contract_ownership_update"}), ) return {"data": contract.serialize("view")}
def put(self): """Contract Document Update""" document = upload_file(self.request) self.request.validated['contract'].documents.append(document) if save_contract(self.request): self.LOGGER.info('Updated contract document {}'.format(self.request.context.id), extra=context_unpack(self.request, {'MESSAGE_ID': 'contract_document_put'})) return {'data': document.serialize("view")}
def patch(self): """ Contract change edit """ change = self.request.validated['change'] data = self.request.validated['data'] if change.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 if 'status' in data and data[ 'status'] != change.status: # status change if not data.get("dateSigned", ''): self.request.errors.add( 'body', 'data', 'Can\'t update contract change status. \'dateSigned\' is required.' ) self.request.errors.status = 403 return change['date'] = get_now() apply_patch(self.request, save=False, src=change.serialize()) if change['dateSigned']: contract = self.request.validated['contract'] changes = contract.get("changes", []) if len(changes) > 1: # has previous changes last_change = contract.changes[:-1][-1] last_date_signed = last_change.dateSigned if not last_date_signed: # BBB old active changes last_date_signed = last_change.date obj_str = "last active change" else: last_date_signed = contract.dateSigned obj_str = "contract" if last_date_signed: # BBB very old contracts if change['dateSigned'] < last_date_signed: self.request.errors.add( 'body', 'data', 'Change dateSigned ({}) can\'t be earlier than {} dateSigned ({})' .format(change['dateSigned'].isoformat(), obj_str, last_date_signed.isoformat())) self.request.errors.status = 403 return if save_contract(self.request): self.LOGGER.info( 'Updated contract change {}'.format(change.id), extra=context_unpack(self.request, {'MESSAGE_ID': 'contract_change_patch'})) return {'data': change.serialize('view')}
def patch(self): contract = self.request.validated["contract"] access = set_ownership(contract, self.request) if save_contract(self.request): self.LOGGER.info( "Generate Contract credentials {}".format(contract.id), extra=context_unpack(self.request, {"MESSAGE_ID": "contract_patch"}), ) return {"data": contract.serialize("view"), "access": access}
def put(self): """Contract Document Update""" document = upload_file(self.request) self.request.validated['contract'].documents.append(document) if save_contract(self.request): self.LOGGER.info( 'Updated contract document {}'.format(self.request.context.id), extra=context_unpack(self.request, {'MESSAGE_ID': 'contract_document_put'})) return {'data': document.serialize("view")}
def put(self): """Contract Document Update""" document = upload_file(self.request) self.request.validated["contract"].documents.append(document) if save_contract(self.request): self.LOGGER.info( "Updated contract document {}".format(self.request.context.id), extra=context_unpack(self.request, {"MESSAGE_ID": "contract_document_put"}), ) return {"data": document.serialize("view")}
def collection_post(self): """ Contract Change create """ contract = self.request.validated['contract'] if contract.status != 'active': self.request.errors.add( 'body', 'data', 'Can\'t add contract change in current ({}) contract status'. format(contract.status)) self.request.errors.status = 403 return if contract.changes and contract.changes[-1].status == 'pending': self.request.errors.add( 'body', 'data', 'Can\'t create new contract change while any (pending) change exists' ) self.request.errors.status = 403 return change = self.request.validated['change'] if change['dateSigned']: changes = contract.get("changes", []) if len(changes) > 0: # has previous changes last_change = contract.changes[-1] last_date_signed = last_change.dateSigned if not last_date_signed: # BBB old active changes last_date_signed = last_change.date obj_str = "last active change" else: last_date_signed = contract.dateSigned obj_str = "contract" if last_date_signed: # BBB very old contracts if change['dateSigned'] < last_date_signed: self.request.errors.add( 'body', 'data', 'Change dateSigned ({}) can\'t be earlier than {} dateSigned ({})' .format(change['dateSigned'].isoformat(), obj_str, last_date_signed.isoformat())) self.request.errors.status = 403 return contract.changes.append(change) if save_contract(self.request): self.LOGGER.info('Created change {} of contract {}'.format( change.id, contract.id), extra=context_unpack( self.request, {'MESSAGE_ID': 'contract_change_create'}, { 'change_id': change.id, 'contract_id': contract.id })) self.request.response.status = 201 return {'data': change.serialize("view")}
def collection_post(self): """Contract Document Upload""" document = upload_file(self.request) self.context.documents.append(document) if save_contract(self.request): self.LOGGER.info('Created contract document {}'.format(document.id), extra=context_unpack(self.request, {'MESSAGE_ID': 'contract_document_create'}, {'document_id': document.id})) self.request.response.status = 201 document_route = self.request.matched_route.name.replace("collection_", "") self.request.response.headers['Location'] = self.request.current_route_url(_route_name=document_route, document_id=document.id, _query={}) return {'data': document.serialize("view")}
def patch(self): """Contract Edit (partial) """ contract = self.request.validated['contract'] apply_patch(self.request, save=False, src=self.request.validated['contract_src']) validate_terminate_contract_without_amountPaid(self.request) if save_contract(self.request): self.LOGGER.info('Updated contract {}'.format(contract.id), extra=context_unpack(self.request, {'MESSAGE_ID': 'contract_patch'})) return {'data': contract.serialize('view')}
def put(self): new_transaction = self.request.json["data"] transaction_id = self.request.matchdict["transaction_id"] new_transaction.update({"id": transaction_id}) contract = self.request.validated["contract"] transactions = contract.implementation.transactions status_mapping = { 0: "successful", -1: "canceled", } _status_value = new_transaction['status'] new_transaction['status'] = status_mapping.get(_status_value, _status_value) existing_transaction = next( (trans for trans in transactions if trans["id"] == transaction_id), None) if existing_transaction: existing_transaction["status"] = new_transaction["status"] if save_contract(self.request): self.LOGGER.info( "Transaction {} for {} contract already exists, status updated" .format(transaction_id, contract.id)) else: trans = type(contract.implementation).transactions.model_class( new_transaction) trans.__parent__ = contract.implementation transactions.append(trans) if save_contract(self.request): self.LOGGER.info( "New transaction {} for {} contract has been created". format(transaction_id, contract.id)) return {"data": contract.serialize("view")}
def patch(self): contract = self.request.validated['contract'] set_ownership(contract, self.request) if save_contract(self.request): self.LOGGER.info('Generate Contract credentials {}'.format(contract.id), extra=context_unpack(self.request, {'MESSAGE_ID': 'contract_patch'})) return { 'data': contract.serialize("view"), 'access': { 'token': contract.owner_token } }
def put(self): """Contract Document Update""" if self.request.validated['contract'].status != 'active': self.request.errors.add('body', 'data', 'Can\'t update document in current ({}) contract status'.format( self.request.validated['contract'].status)) self.request.errors.status = 403 return document = upload_file(self.request) self.request.validated['contract'].documents.append(document) if save_contract(self.request): self.LOGGER.info('Updated contract document {}'.format(self.request.context.id), extra=context_unpack(self.request, {'MESSAGE_ID': 'contract_document_put'})) return {'data': document.serialize("view")}
def put(self): """Contract Document Update""" if self.request.validated['contract'].status != 'active': self.request.errors.add('body', 'data', 'Can\'t update document in current ({}) contract status'.format( self.request.validated['contract'].status)) self.request.errors.status = 403 return document = upload_file(self.request) self.request.validated['contract'].documents.append(document) if save_contract(self.request): self.LOGGER.info('Updated contract document {}'.format(self.request.context.id), extra=context_unpack(self.request, {'MESSAGE_ID': 'contract_document_put'})) return {'data': document.serialize("view")}
def patch(self): """Contract Edit (partial) """ contract = self.request.validated["contract"] apply_patch(self.request, save=False, src=self.request.validated["contract_src"]) validate_terminate_contract_without_amountPaid(self.request) validate_update_contracting_items_unit_value_amount(self.request) if save_contract(self.request): self.LOGGER.info( "Updated contract {}".format(contract.id), extra=context_unpack(self.request, {"MESSAGE_ID": "contract_patch"}), ) return {"data": contract.serialize("view")}
def post(self): """Contract Transaction Document Upload""" document = upload_file_to_transaction(self.request) _transaction = get_transaction_by_id(self.request) _transaction.documents.append(document) if save_contract(self.request): self.LOGGER.info( "Created contract transaction document {}".format(document.id), extra=context_unpack( self.request, {"MESSAGE_ID": "contract_transaction_document_create"}, {"document_id": document.id} ), ) self.request.response.status = 201 return {"data": document.serialize("view")}
def patch(self): contract = self.request.validated['contract'] set_ownership(contract, self.request) if save_contract(self.request): self.LOGGER.info( 'Generate Contract credentials {}'.format(contract.id), extra=context_unpack(self.request, {'MESSAGE_ID': 'contract_patch'})) return { 'data': contract.serialize("view"), 'access': { 'token': contract.owner_token } }
def patch(self): """Contract Edit (partial) """ contract = self.request.validated['contract'] apply_patch(self.request, save=False, src=self.request.validated['contract_src']) validate_terminate_contract_without_amountPaid(self.request) if save_contract(self.request): self.LOGGER.info( 'Updated contract {}'.format(contract.id), extra=context_unpack(self.request, {'MESSAGE_ID': 'contract_patch'})) return {'data': contract.serialize('view')}
def patch(self): contract = self.request.validated['contract'] if contract.status != "draft": self.request.errors.add('body', 'data', 'Can\'t generate credentials in current ({}) contract status'.format(contract.status)) self.request.errors.status = 403 return set_ownership(contract, self.request) if save_contract(self.request): self.LOGGER.info('Generate Contract credentials {}'.format(contract.id), extra=context_unpack(self.request, {'MESSAGE_ID': 'contract_patch'})) return { 'data': contract.serialize("view"), 'access': { 'token': contract.owner_token } }
def collection_post(self): """Contract Document Upload""" if self.request.validated['contract'].status != 'active': self.request.errors.add('body', 'data', 'Can\'t add document in current ({}) contract status'.format( self.request.validated['contract'].status)) self.request.errors.status = 403 return document = upload_file(self.request) self.context.documents.append(document) if save_contract(self.request): self.LOGGER.info('Created contract document {}'.format(document.id), extra=context_unpack(self.request, {'MESSAGE_ID': 'contract_document_create'}, {'document_id': document.id})) self.request.response.status = 201 document_route = self.request.matched_route.name.replace("collection_", "") self.request.response.headers['Location'] = self.request.current_route_url(_route_name=document_route, document_id=document.id, _query={}) return {'data': document.serialize("view")}
def post(self): contract = self.request.validated['contract'] # set_ownership(contract, self.request) TODO self.request.validated['contract'] = contract self.request.validated['contract_src'] = {} if save_contract(self.request): self.LOGGER.info('Created contract {} ({})'.format(contract.id, contract.contractID), extra=context_unpack(self.request, {'MESSAGE_ID': 'contract_create'}, {'contract_id': contract.id, 'contractID': contract.contractID})) self.request.response.status = 201 return { 'data': contract.serialize("view"), 'access': { 'token': contract.owner_token } }
def collection_post(self): """ Contract Change create """ contract = self.request.validated["contract"] change = self.request.validated["change"] if change["dateSigned"]: changes = contract.get("changes", []) if len(changes) > 0: # has previous changes last_change = contract.changes[-1] last_date_signed = last_change.dateSigned if not last_date_signed: # BBB old active changes last_date_signed = last_change.date obj_str = "last active change" else: last_date_signed = contract.dateSigned obj_str = "contract" if last_date_signed: # BBB very old contracts if change["dateSigned"] < last_date_signed: # Can't move validator because of code above raise_operation_error( self.request, "Change dateSigned ({}) can't be earlier than {} dateSigned ({})" .format(change["dateSigned"].isoformat(), obj_str, last_date_signed.isoformat()), ) contract.changes.append(change) if save_contract(self.request): self.LOGGER.info( "Created change {} of contract {}".format( change.id, contract.id), extra=context_unpack( self.request, {"MESSAGE_ID": "contract_change_create"}, { "change_id": change.id, "contract_id": contract.id }, ), ) self.request.response.status = 201 return {"data": change.serialize("view")}
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 validate_update_contract_change_status(self.request) change["date"] = get_now() apply_patch(self.request, save=False, src=change.serialize()) if change["dateSigned"]: contract = self.request.validated["contract"] changes = contract.get("changes", []) if len(changes) > 1: # has previous changes last_change = contract.changes[:-1][-1] last_date_signed = last_change.dateSigned if not last_date_signed: # BBB old active changes last_date_signed = last_change.date obj_str = "last active change" else: last_date_signed = contract.dateSigned obj_str = "contract" if last_date_signed: # BBB very old contracts if change["dateSigned"] < last_date_signed: # Can't move validator because of code above raise_operation_error( self.request, "Change dateSigned ({}) can't be earlier than {} dateSigned ({})" .format(change["dateSigned"].isoformat(), obj_str, last_date_signed.isoformat()), ) if save_contract(self.request): self.LOGGER.info( "Updated contract change {}".format(change.id), extra=context_unpack(self.request, {"MESSAGE_ID": "contract_change_patch"}), ) return {"data": change.serialize("view")}
def patch(self): """Contract Edit (partial) """ contract = self.request.validated['contract'] if self.request.authenticated_role != 'Administrator' and contract.status != 'active': self.request.errors.add('body', 'data', 'Can\'t update contract in current ({}) status'.format(contract.status)) self.request.errors.status = 403 return apply_patch(self.request, save=False, src=self.request.validated['contract_src']) if contract.status == 'terminated' and not contract.amountPaid: self.request.errors.add('body', 'data', 'Can\'t terminate contract while \'amountPaid\' is not set') self.request.errors.status = 403 return if save_contract(self.request): self.LOGGER.info('Updated contract {}'.format(contract.id), extra=context_unpack(self.request, {'MESSAGE_ID': 'contract_patch'})) return {'data': contract.serialize('view')}
def collection_post(self): """Contract Document Upload""" document = upload_file(self.request) self.context.documents.append(document) if save_contract(self.request): self.LOGGER.info( "Created contract document {}".format(document.id), extra=context_unpack( self.request, {"MESSAGE_ID": "contract_document_create"}, {"document_id": document.id}), ) self.request.response.status = 201 document_route = self.request.matched_route.name.replace( "collection_", "") self.request.response.headers[ "Location"] = self.request.current_route_url( _route_name=document_route, document_id=document.id, _query={}) return {"data": document.serialize("view")}
def post(self): contract = self.request.validated['contract'] if contract.status != "active": self.request.errors.add( 'body', 'data', 'Can\'t update credentials in current ({}) contract status'. format(contract.status)) self.request.errors.status = 403 return location = self.request.route_path('Contract', contract_id=contract.id) location = location[len(ROUTE_PREFIX):] # strips /api/<version> if change_ownership(self.request, location) and save_contract( self.request): self.LOGGER.info( 'Updated ownership of contract {}'.format(contract.id), extra=context_unpack( self.request, {'MESSAGE_ID': 'contract_ownership_update'})) return {'data': contract.serialize('view')}
def collection_post(self): """ Contract Change create """ contract = self.request.validated['contract'] if contract.status != 'active': self.request.errors.add('body', 'data', 'Can\'t add contract change in current ({}) contract status'.format(contract.status)) self.request.errors.status = 403 return if contract.changes and contract.changes[-1].status == 'pending': self.request.errors.add('body', 'data', 'Can\'t create new contract change while any (pending) change exists') self.request.errors.status = 403 return change = self.request.validated['change'] contract.changes.append(change) if save_contract(self.request): self.LOGGER.info('Created change {} of contract {}'.format(change.id, contract.id), extra=context_unpack(self.request, {'MESSAGE_ID': 'contract_change_create'}, {'change_id': change.id, 'contract_id': contract.id})) self.request.response.status = 201 return {'data': change.serialize("view")}
def post(self): contract = self.request.validated['contract'] for i in self.request.validated['json_data'].get('documents', []): doc = type(contract).documents.model_class(i) doc.__parent__ = contract contract.documents.append(doc) # set_ownership(contract, self.request) TODO self.request.validated['contract'] = contract self.request.validated['contract_src'] = {} if save_contract(self.request): self.LOGGER.info('Created contract {} ({})'.format(contract.id, contract.contractID), extra=context_unpack(self.request, {'MESSAGE_ID': 'contract_create'}, {'contract_id': contract.id, 'contractID': contract.contractID or ''})) self.request.response.status = 201 return { 'data': contract.serialize("view"), 'access': { 'token': contract.owner_token } }
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 validate_update_contract_change_status(self.request) change['date'] = get_now() apply_patch(self.request, save=False, src=change.serialize()) if change['dateSigned']: contract = self.request.validated['contract'] changes = contract.get("changes", []) if len(changes) > 1: # has previous changes last_change = contract.changes[:-1][-1] last_date_signed = last_change.dateSigned if not last_date_signed: # BBB old active changes last_date_signed = last_change.date obj_str = "last active change" else: last_date_signed = contract.dateSigned obj_str = "contract" if last_date_signed: # BBB very old contracts if change['dateSigned'] < last_date_signed: # Can't move validator because of code above raise_operation_error( self.request, 'Change dateSigned ({}) can\'t be earlier than {} dateSigned ({})' .format(change['dateSigned'].isoformat(), obj_str, last_date_signed.isoformat())) if save_contract(self.request): self.LOGGER.info( 'Updated contract change {}'.format(change.id), extra=context_unpack(self.request, {'MESSAGE_ID': 'contract_change_patch'})) return {'data': change.serialize('view')}
def patch(self): contract = self.request.validated['contract'] if contract.status != "active": self.request.errors.add( 'body', 'data', 'Can\'t generate credentials in current ({}) contract status'. format(contract.status)) self.request.errors.status = 403 return set_ownership(contract, self.request) if save_contract(self.request): self.LOGGER.info( 'Generate Contract credentials {}'.format(contract.id), extra=context_unpack(self.request, {'MESSAGE_ID': 'contract_patch'})) return { 'data': contract.serialize("view"), 'access': { 'token': contract.owner_token } }
def post(self): contract = self.request.validated['contract'] data = self.request.validated['ownership_data'] if contract.status != "active": self.request.errors.add('body', 'data', 'Can\'t update credentials in current ({}) contract status'.format(contract.status)) self.request.errors.status = 403 return if contract.transfer_token == sha512(data.get('transfer', '')).hexdigest() or contract.tender_token == sha512(data.get('tender_token', '')).hexdigest(): transfer = extract_transfer(self.request, transfer_id=data['id']) if data.get('tender_token') and contract.owner != transfer.owner: self.request.errors.add('body', 'transfer', 'Only owner is allowed to generate new credentials.') self.request.errors.status = 403 return location = self.request.route_path('Contract', contract_id=contract.id) location = location[len(ROUTE_PREFIX):] # strips /api/<version> if transfer.get('usedFor') and transfer.get('usedFor') != location: self.request.errors.add('body', 'transfer', 'Transfer already used') self.request.errors.status = 403 return else: self.request.errors.add('body', 'transfer', 'Invalid transfer') self.request.errors.status = 403 return update_ownership(contract, transfer) self.request.validated['contract'] = contract transfer.usedFor = location self.request.validated['transfer'] = transfer if save_transfer(self.request): self.LOGGER.info('Updated transfer relation {}'.format(transfer.id), extra=context_unpack(self.request, {'MESSAGE_ID': 'transfer_relation_update'})) if save_contract(self.request): self.LOGGER.info('Updated ownership of contract {}'.format(contract.id), extra=context_unpack(self.request, {'MESSAGE_ID': 'contract_ownership_update'})) return {'data': contract.serialize('view')}
def post(self): contract = self.request.validated['contract'] # set_ownership(contract, self.request) TODO self.request.validated['contract'] = contract self.request.validated['contract_src'] = {} if save_contract(self.request): self.LOGGER.info('Created contract {} ({})'.format( contract.id, contract.contractID), extra=context_unpack( self.request, {'MESSAGE_ID': 'contract_create'}, { 'contract_id': contract.id, 'contractID': contract.contractID or '' })) self.request.response.status = 201 return { 'data': contract.serialize("view"), 'access': { 'token': contract.owner_token } }
def post(self): contract = self.request.validated['contract'] data = self.request.validated['ownership_data'] if contract.transfer_token == sha512(data['transfer']).hexdigest(): location = self.request.route_path('Contract', contract_id=contract.id) location = location[len(ROUTE_PREFIX):] # strips /api/<version> transfer = extract_transfer(self.request, transfer_id=data['id']) if transfer.get('usedFor') and transfer.get('usedFor') != location: self.request.errors.add('body', 'transfer', 'Transfer already used') self.request.errors.status = 403 return else: self.request.errors.add('body', 'transfer', 'Invalid transfer') self.request.errors.status = 403 return update_ownership(contract, transfer) self.request.validated['contract'] = contract transfer.usedFor = location self.request.validated['transfer'] = transfer if save_transfer(self.request): self.LOGGER.info( 'Updated transfer relation {}'.format(transfer.id), extra=context_unpack( self.request, {'MESSAGE_ID': 'transfer_relation_update'})) if save_contract(self.request): self.LOGGER.info( 'Updated ownership of contract {}'.format(contract.id), extra=context_unpack( self.request, {'MESSAGE_ID': 'contract_ownership_update'})) return {'data': contract.serialize('view')}
def save(self, request, **kwargs): return save_contract(request)
def patch(self): """Esco Contract 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 /contracts/de46983cea7945939bae90862d54693f HTTP/1.1 Host: example.com Accept: application/json { "data": { "period": { u'endDate': '2029-04-27T09:58:56.919991+03:00', u'startDate': u'2018-04-27T09:58:56.919991+03:00' } } } And here is the response to be expected: .. sourcecode:: http HTTP/1.0 200 OK Content-Type: application/json { u'data': { u'NBUdiscountRate': 0.135, u'amountPaid': {u'amount': 100000.0, u'currency': u'UAH', u'valueAddedTaxIncluded': True}, u'awardID': u'29c01dd058c347f38e381f13d4a6a118', u'changes': [{u'date': u'2018-04-27T09:59:02.794216+03:00', u'id': u'78679cfa4c544b5db8069e4e8999a491', u'rationale': u'\u043f\u0440\u0438\u0447\u0438\u043d\u0430 \u0437\u043c\u0456\u043d\u0438 \u0443\u043a\u0440', u'rationaleTypes': [u'itemPriceVariation'], u'rationale_en': u'change cause en', u'status': u'pending'}], u'contractID': u'UA-2017-11-21-001567-c-a1', u'contractNumber': u'17', u'contractType': u'esco', u'dateModified': u'2018-04-27T10:02:21.499264+03:00', u'dateSigned': u'2018-04-27T09:58:56.919991+03:00', u'description': u'', u'id': u'de46983cea7945939bae90862d54693f', u'items': [{u'additionalClassifications': [{u'description': u'\u0421\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0435 \u043d\u043e\u0440\u043c\u044b \u0438 \u0434\u0440\u0443\u0433\u043e\u0435', u'id': u'000', u'scheme': u'specialNorms'}], u'classification': {u'description': u'\u041d\u0435 \u0432\u0456\u0434\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0435 \u0432 \u0456\u043d\u0448\u0438\u0445 \u0440\u043e\u0437\u0434\u0456\u043b\u0430\u0445', u'id': u'99999999-9', u'scheme': u'\u0414\u041a021'}, u'deliveryAddress': {u'countryName': u'\u0423\u043a\u0440\u0430\u0457\u043d\u0430', u'locality': u'\u0421\u0443\u043c\u0438', u'postalCode': u'40007', u'region': u'\u0421\u0443\u043c\u0441\u044c\u043a\u0430 \u043e\u0431\u043b.', u'streetAddress': u'\u041e\u0445\u0442\u0438\u0440\u0441\u044c\u043a\u0430, 21'}, u'description': u'\u0415\u041d\u0435\u0440\u0433\u043e\u0441\u0435\u0440\u0432\u0456\u0441 \u0431\u0443\u0434\u0456\u0432\u043b\u0456 \u041a\u043e\u043c\u0443\u043d\u0430\u043b\u044c\u043d\u043e\u0457 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438 \u0421\u0443\u043c\u0441\u044c\u043a\u0430 \u0437\u0430\u0433\u0430\u043b\u044c\u043d\u043e\u043e\u0441\u0432\u0456\u0442\u043d\u044f \u0448\u043a\u043e\u043b\u0430 \u0406-\u0406\u0406\u0406 \u0441\u0442\u0443\u043f\u0435\u043d\u0456\u0432 \u2116 26 \u043c. \u0421\u0443\u043c\u0438, \u0421\u0443\u043c\u0441\u044c\u043a\u043e\u0457 \u043e\u0431\u043b\u0430\u0441\u0442\u0456', u'description_en': u'Energy service of the public institution building of Sumy secondary school Nr 26', u'id': u'660e66a4ffd0486f8f90041f36105f05'}], u'milestones': [{u'amountPaid': {u'amount': 100000.0, u'currency': u'UAH', u'valueAddedTaxIncluded': True}, u'date': u'2018-04-27T09:58:56.922929+03:00', u'dateModified': u'2018-04-27T09:59:00.931103+03:00', u'description': u'Milestone #1 of year 2018', u'id': u'0458c0495691406bb6a01f98b2aa2429', u'period': {u'endDate': u'2029-04-27T09:58:56.919991+03:00', u'startDate': u'2018-04-27T09:58:56.919991+03:00'}, u'sequenceNumber': 1, u'status': u'pending', u'title': u'Milestone #1 of year 2018', u'value': {u'amount': 0, u'currency': u'UAH', u'valueAddedTaxIncluded': True}}, {u'amountPaid': {u'amount': 0, u'currency': u'UAH', u'valueAddedTaxIncluded': True}, u'date': u'2018-04-27T09:58:56.923050+03:00', u'dateModified': u'2018-04-27T09:58:56.923050+03:00', u'description': u'Milestone #2 of year 2019', u'id': u'cf3fec09adcf405a8629e7912006c20b', u'period': {u'endDate': u'2029-04-27T09:58:56.919991+03:00', u'startDate': u'2019-01-01T00:00:00+02:02'}, u'sequenceNumber': 2, u'status': u'scheduled', u'title': u'Milestone #2 of year 2019', u'value': {u'amount': 164677.28, u'currency': u'UAH', u'valueAddedTaxIncluded': True}}, {u'amountPaid': {u'amount': 0, u'currency': u'UAH', u'valueAddedTaxIncluded': True}, u'date': u'2018-04-27T09:58:56.923203+03:00', u'dateModified': u'2018-04-27T09:58:56.923203+03:00', u'description': u'Milestone #3 of year 2020', u'id': u'17b94728909040ffa2a73c5d2ecd96b8', u'period': {u'endDate': u'2029-04-27T09:58:56.919991+03:00', u'startDate': u'2020-01-01T00:00:00+02:02'}, u'sequenceNumber': 3, u'status': u'scheduled', u'title': u'Milestone #3 of year 2020', u'value': {u'amount': 207592.22, u'currency': u'UAH', u'valueAddedTaxIncluded': True}}, {u'amountPaid': {u'amount': 0, u'currency': u'UAH', u'valueAddedTaxIncluded': True}, u'date': u'2018-04-27T09:58:56.923341+03:00', u'dateModified': u'2018-04-27T09:58:56.923341+03:00', u'description': u'Milestone #4 of year 2021', u'id': u'1d9de5c307284ce19e0035ef25e0a42f', u'period': {u'endDate': u'2029-04-27T09:58:56.919991+03:00', u'startDate': u'2021-01-01T00:00:00+02:02'}, u'sequenceNumber': 4, u'status': u'scheduled', u'title': u'Milestone #4 of year 2021', u'value': {u'amount': 207592.22, u'currency': u'UAH', u'valueAddedTaxIncluded': True}}, {u'amountPaid': {u'amount': 0, u'currency': u'UAH', u'valueAddedTaxIncluded': True}, u'date': u'2018-04-27T09:58:56.923480+03:00', u'dateModified': u'2018-04-27T09:58:56.923480+03:00', u'description': u'Milestone #5 of year 2022', u'id': u'04747c0d72444a8a8dfa602bb5c7e7c1', u'period': {u'endDate': u'2029-04-27T09:58:56.919991+03:00', u'startDate': u'2022-01-01T00:00:00+02:02'}, u'sequenceNumber': 5, u'status': u'scheduled', u'title': u'Milestone #5 of year 2022', u'value': {u'amount': 207592.22, u'currency': u'UAH', u'valueAddedTaxIncluded': True}}, {u'amountPaid': {u'amount': 0, u'currency': u'UAH', u'valueAddedTaxIncluded': True}, u'date': u'2018-04-27T09:58:56.923622+03:00', u'dateModified': u'2018-04-27T09:58:56.923622+03:00', u'description': u'Milestone #6 of year 2023', u'id': u'0f844c8a686e491b81ef701543a43831', u'period': {u'endDate': u'2029-04-27T09:58:56.919991+03:00', u'startDate': u'2023-01-01T00:00:00+02:02'}, u'sequenceNumber': 6, u'status': u'scheduled', u'title': u'Milestone #6 of year 2023', u'value': {u'amount': 207592.22, u'currency': u'UAH', u'valueAddedTaxIncluded': True}}, {u'amountPaid': {u'amount': 0, u'currency': u'UAH', u'valueAddedTaxIncluded': True}, u'date': u'2018-04-27T09:58:56.923757+03:00', u'dateModified': u'2018-04-27T09:58:56.923757+03:00', u'description': u'Milestone #7 of year 2024', u'id': u'833977506d0c49afbd071c81b69d5acd', u'period': {u'endDate': u'2029-04-27T09:58:56.919991+03:00', u'startDate': u'2024-01-01T00:00:00+02:02'}, u'sequenceNumber': 7, u'status': u'scheduled', u'title': u'Milestone #7 of year 2024', u'value': {u'amount': 207592.22, u'currency': u'UAH', u'valueAddedTaxIncluded': True}}, {u'amountPaid': {u'amount': 0, u'currency': u'UAH', u'valueAddedTaxIncluded': True}, u'date': u'2018-04-27T09:58:56.923892+03:00', u'dateModified': u'2018-04-27T09:58:56.923892+03:00', u'description': u'Milestone #8 of year 2025', u'id': u'38a931d02bf24bbca30f60ac1e527a96', u'period': {u'endDate': u'2029-04-27T09:58:56.919991+03:00', u'startDate': u'2025-01-01T00:00:00+02:02'}, u'sequenceNumber': 8, u'status': u'scheduled', u'title': u'Milestone #8 of year 2025', u'value': {u'amount': 35262.24, u'currency': u'UAH', u'valueAddedTaxIncluded': True}}, {u'amountPaid': {u'amount': 0, u'currency': u'UAH', u'valueAddedTaxIncluded': True}, u'date': u'2018-04-27T09:58:56.924039+03:00', u'dateModified': u'2018-04-27T09:58:56.924039+03:00', u'description': u'Milestone #9 of year 2026', u'id': u'143506651440433c8162283e930114ee', u'period': {u'endDate': u'2029-04-27T09:58:56.919991+03:00', u'startDate': u'2026-01-01T00:00:00+02:02'}, u'sequenceNumber': 9, u'status': u'scheduled', u'title': u'Milestone #9 of year 2026', u'value': {u'amount': 0, u'currency': u'UAH', u'valueAddedTaxIncluded': True}}, {u'amountPaid': {u'amount': 0, u'currency': u'UAH', u'valueAddedTaxIncluded': True}, u'date': u'2018-04-27T09:58:56.924145+03:00', u'dateModified': u'2018-04-27T09:58:56.924145+03:00', u'description': u'Milestone #10 of year 2027', u'id': u'04db12f9015a400eb04bbfafc8a2367c', u'period': {u'endDate': u'2029-04-27T09:58:56.919991+03:00', u'startDate': u'2027-01-01T00:00:00+02:02'}, u'sequenceNumber': 10, u'status': u'scheduled', u'title': u'Milestone #10 of year 2027', u'value': {u'amount': 0, u'currency': u'UAH', u'valueAddedTaxIncluded': True}}, {u'amountPaid': {u'amount': 0, u'currency': u'UAH', u'valueAddedTaxIncluded': True}, u'date': u'2018-04-27T09:58:56.924249+03:00', u'dateModified': u'2018-04-27T09:58:56.924249+03:00', u'description': u'Milestone #11 of year 2028', u'id': u'7e31a15694ff494eb04e728937aec0dc', u'period': {u'endDate': u'2029-04-27T09:58:56.919991+03:00', u'startDate': u'2028-01-01T00:00:00+02:02'}, u'sequenceNumber': 11, u'status': u'scheduled', u'title': u'Milestone #11 of year 2028', u'value': {u'amount': 0, u'currency': u'UAH', u'valueAddedTaxIncluded': True}}, {u'amountPaid': {u'amount': 0, u'currency': u'UAH', u'valueAddedTaxIncluded': True}, u'date': u'2018-04-27T09:58:56.924352+03:00', u'dateModified': u'2018-04-27T09:58:56.924352+03:00', u'description': u'Milestone #12 of year 2029', u'id': u'd981d1e2389f4ccabe676cca228d3205', u'period': {u'endDate': u'2029-04-27T09:58:56.919991+03:00', u'startDate': u'2029-01-01T00:00:00+02:02'}, u'sequenceNumber': 12, u'status': u'scheduled', u'title': u'Milestone #12 of year 2029', u'value': {u'amount': 0, u'currency': u'UAH', u'valueAddedTaxIncluded': True}}], u'owner': u'broker', u'period': {u'endDate': u'2029-04-27T09:58:56.919991+03:00', u'startDate': u'2018-04-27T09:58:56.919991+03:00'}, u'procuringEntity': {u'additionalContactPoints': [{u'name': u'\u0414\u0435\u0440\u0436\u0430\u0432\u043d\u0435 \u0443\u043f\u0440\u0430\u0432\u043b\u0456\u043d\u043d\u044f \u0441\u043f\u0440\u0430\u0432\u0430\u043c\u04382', u'telephone': u'0440000001'}], u'address': {u'countryName': u'\u0423\u043a\u0440\u0430\u0457\u043d\u0430', u'locality': u'', u'postalCode': u'', u'region': u'', u'streetAddress': u'01004, \u043c.\u041a\u0438\u0457\u0432, \u0411\u0415\u0421\u0421\u0410\u0420\u0410\u0411\u0421\u042c\u041a\u0410 \u041f\u041b\u041e\u0429\u0410, \u0431\u0443\u0434\u0438\u043d\u043e\u043a 9/1 \u0411, \u043e\u0444\u0456\u0441 2'}, u'contactPoint': {u'availableLanguage': u'en', u'email': u'*****@*****.**', u'name': u'\u0422\u041e\u0412\u0410\u0420\u0418\u0421\u0422\u0412\u041e \u0417 \u041e\u0411\u041c\u0415\u0416\u0415\u041d\u041e\u042e \u0412\u0406\u0414\u041f\u041e\u0412\u0406\u0414\u0410\u041b\u042c\u041d\u0406\u0421\u0422\u042e "\u0404\u0412\u0420\u041e\u041f\u0415\u0419\u0421\u042c\u041a\u0410 \u0415\u041d\u0415\u0420\u0413\u041e\u0421\u0415\u0420\u0412\u0406\u0421\u041d\u0410 \u041a\u041e\u041c\u041f\u0410\u041d\u0406\u042f"', u'telephone': u'+380933907440'}, u'identifier': {u'id': u'40957551', u'legalName': u'\u0422\u041e\u0412\u0410\u0420\u0418\u0421\u0422\u0412\u041e \u0417 \u041e\u0411\u041c\u0415\u0416\u0415\u041d\u041e\u042e \u0412\u0406\u0414\u041f\u041e\u0412\u0406\u0414\u0410\u041b\u042c\u041d\u0406\u0421\u0422\u042e "\u0404\u0412\u0420\u041e\u041f\u0415\u0419\u0421\u042c\u041a\u0410 \u0415\u041d\u0415\u0420\u0413\u041e\u0421\u0415\u0420\u0412\u0406\u0421\u041d\u0410 \u041a\u041e\u041c\u041f\u0410\u041d\u0406\u042f"', u'scheme': u'UA-EDR'}, u'name': u'\u0422\u041e\u0412\u0410\u0420\u0418\u0421\u0422\u0412\u041e \u0417 \u041e\u0411\u041c\u0415\u0416\u0415\u041d\u041e\u042e \u0412\u0406\u0414\u041f\u041e\u0412\u0406\u0414\u0410\u041b\u042c\u041d\u0406\u0421\u0422\u042e "\u0404\u0412\u0420\u041e\u041f\u0415\u0419\u0421\u042c\u041a\u0410 \u0415\u041d\u0415\u0420\u0413\u041e\u0421\u0415\u0420\u0412\u0406\u0421\u041d\u0410 \u041a\u041e\u041c\u041f\u0410\u041d\u0406\u042f"'}, u'status': u'active', u'suppliers': [{u'address': {u'countryName': u'\u0423\u043a\u0440\u0430\u0457\u043d\u0430', u'locality': u'', u'postalCode': u'', u'region': u'', u'streetAddress': u'01004, \u043c.\u041a\u0438\u0457\u0432, \u0411\u0415\u0421\u0421\u0410\u0420\u0410\u0411\u0421\u042c\u041a\u0410 \u041f\u041b\u041e\u0429\u0410, \u0431\u0443\u0434\u0438\u043d\u043e\u043a 9/1 \u0411, \u043e\u0444\u0456\u0441 2'}, u'contactPoint': {u'email': u'*****@*****.**', u'name': u'\u0422\u041e\u0412\u0410\u0420\u0418\u0421\u0422\u0412\u041e \u0417 \u041e\u0411\u041c\u0415\u0416\u0415\u041d\u041e\u042e \u0412\u0406\u0414\u041f\u041e\u0412\u0406\u0414\u0410\u041b\u042c\u041d\u0406\u0421\u0422\u042e "\u0404\u0412\u0420\u041e\u041f\u0415\u0419\u0421\u042c\u041a\u0410 \u0415\u041d\u0415\u0420\u0413\u041e\u0421\u0415\u0420\u0412\u0406\u0421\u041d\u0410 \u041a\u041e\u041c\u041f\u0410\u041d\u0406\u042f"', u'telephone': u'+380933907440'}, u'identifier': {u'id': u'40957551', u'legalName': u'\u0422\u041e\u0412\u0410\u0420\u0418\u0421\u0422\u0412\u041e \u0417 \u041e\u0411\u041c\u0415\u0416\u0415\u041d\u041e\u042e \u0412\u0406\u0414\u041f\u041e\u0412\u0406\u0414\u0410\u041b\u042c\u041d\u0406\u0421\u0422\u042e "\u0404\u0412\u0420\u041e\u041f\u0415\u0419\u0421\u042c\u041a\u0410 \u0415\u041d\u0415\u0420\u0413\u041e\u0421\u0415\u0420\u0412\u0406\u0421\u041d\u0410 \u041a\u041e\u041c\u041f\u0410\u041d\u0406\u042f"', u'scheme': u'UA-EDR'}, u'name': u'\u0422\u041e\u0412\u0410\u0420\u0418\u0421\u0422\u0412\u041e \u0417 \u041e\u0411\u041c\u0415\u0416\u0415\u041d\u041e\u042e \u0412\u0406\u0414\u041f\u041e\u0412\u0406\u0414\u0410\u041b\u042c\u041d\u0406\u0421\u0422\u042e "\u0404\u0412\u0420\u041e\u041f\u0415\u0419\u0421\u042c\u041a\u0410 \u0415\u041d\u0415\u0420\u0413\u041e\u0421\u0415\u0420\u0412\u0406\u0421\u041d\u0410 \u041a\u041e\u041c\u041f\u0410\u041d\u0406\u042f"'}], u'tender_id': u'4f90c49aa1684769b9a41c8196d875fe', u'title': u'New Title', u'value': {u'amount': 1237900.62, u'amountPerformance': 447361.33, u'annualCostsReduction': [0, 178997.04, 225643.72, 225643.72, 225643.72, 225643.72, 225643.72, 225643.72, 141782.47, 141782.47, 141782.47, 141782.47, 141782.47, 141782.47, 141782.47, 141782.47, 141782.47, 141782.47, 141782.47, 141782.47, 141782.47], u'contractDuration': {u'days': 310, u'years': 6}, u'currency': u'UAH', u'valueAddedTaxIncluded': True, u'yearlyPaymentsPercentage': 0.92} } } """ if 'period' in self.request.validated['data'] and \ self.context.period.endDate.isoformat() != self.request.validated['data']['period']['endDate']: update_milestones_dates_and_statuses(self.request) contract = self.request.validated['contract'] apply_patch(self.request, save=False, src=self.request.validated['contract_src']) # validate_terminate_contract_without_amountPaid(self.request) if save_contract(self.request): self.LOGGER.info( 'Updated contract {}'.format(contract.id), extra=context_unpack(self.request, {'MESSAGE_ID': 'contract_patch'})) return {'data': contract.serialize('view')}