diff --git a/openprocurement/auctions/rubble/migration.py b/openprocurement/auctions/rubble/migration.py index 97ab5ac..fa7b293 100644 --- a/openprocurement/auctions/rubble/migration.py +++ b/openprocurement/auctions/rubble/migration.py @@ -6,12 +6,20 @@ ) from openprocurement.auctions.core.traversal import Root from openprocurement.auctions.core.utils import ( - get_plugins, get_procurement_method_types, get_now + get_plugins, get_procurement_method_types, get_now, migrate_all_document_of_tender +) + +from openprocurement.api.migration import ( + BaseMigrationsRunner, + BaseMigrationStep ) LOGGER = logging.getLogger(__name__) SCHEMA_VERSION = 1 SCHEMA_DOC = 'openprocurement_auctions_dgf_schema' +PACKAGE_ALIASES = { + 'openprocurement.auctions.rubble': ['rubbleOther', 'rubbleFinancial'] +} def get_db_schema_version(db): @@ -74,3 +82,32 @@ def __init__(self, registry): docs = [] if docs: registry.db.update(docs) + + +class RubbleMigrationsRunner(BaseMigrationsRunner): + + SCHEMA_VERSION = 1 + SCHEMA_DOC = SCHEMA_DOC + + +class DocumentOfStep(BaseMigrationStep): + + def setUp(self): + self.view = 'auctions/all' + self.procurement_method_types = self.resources.aliases_info.get_package_aliases( + 'openprocurement.auctions.rubble' + ) + + def migrate_document(self, auction): + if auction['procurementMethodType'] in self.procurement_method_types: + changed = migrate_all_document_of_tender(auction) + return auction if changed else None + return None + + +MIGRATION_STEPS = (DocumentOfStep, ) + + +def migrate(resources): + runner = RubbleMigrationsRunner(resources) + runner.migrate(MIGRATION_STEPS) diff --git a/openprocurement/auctions/rubble/models.py b/openprocurement/auctions/rubble/models.py index bfb5e12..187e647 100644 --- a/openprocurement/auctions/rubble/models.py +++ b/openprocurement/auctions/rubble/models.py @@ -23,17 +23,17 @@ auction_embedded_role, calc_auction_end_time, dgfCDB2Complaint, - dgfCDB2Document, + AuctionDocument, dgfCDB2Item, - dgfCancellation, + AuctionCancellation, edit_role, get_auction, validate_items_uniq, validate_lots_uniq, validate_not_available, ) -from openprocurement.auctions.core.plugins.awarding.v2_1.models import Award -from openprocurement.auctions.core.plugins.contracting.v2_1.models import Contract +from openprocurement.auctions.core.plugins.awarding.v2_1.models import Award as BaseAward +from openprocurement.auctions.core.plugins.contracting.v2_1.models import Contract as BaseContract from openprocurement.auctions.core.utils import ( AUCTIONS_COMPLAINT_STAND_STILL_TIME as COMPLAINT_STAND_STILL_TIME, SANDBOX_MODE, @@ -79,7 +79,7 @@ class Options: } status = StringType(choices=['active', 'draft', 'invalid'], default='active') - documents = ListType(ModelType(dgfCDB2Document), default=list()) + documents = ListType(ModelType(AuctionDocument), default=list()) qualified = BooleanType(required=True, choices=[True]) @bids_validation_wrapper @@ -87,8 +87,12 @@ def validate_value(self, data, value): BaseBid._validator_functions['value'](self, data, value) -class Cancellation(dgfCancellation): - documents = ListType(ModelType(dgfCDB2Document), default=list()) +class Award(BaseAward): + documents = ListType(ModelType(AuctionDocument), default=list()) + + +class Contract(BaseContract): + documents = ListType(ModelType(AuctionDocument), default=list()) def rounding_shouldStartAfter(start_after, auction, use_from=datetime(2016, 6, 1, tzinfo=TZ)): @@ -187,11 +191,11 @@ def __local_roles__(self): _internal_type = "rubbleOther" awards = ListType(ModelType(Award), default=list()) bids = ListType(ModelType(Bid), default=list()) # A list of all the companies who entered submissions for the auction. - cancellations = ListType(ModelType(Cancellation), default=list()) + cancellations = ListType(ModelType(AuctionCancellation), default=list()) complaints = ListType(ModelType(dgfCDB2Complaint), default=list()) contracts = ListType(ModelType(Contract), default=list()) dgfID = StringType() - documents = ListType(ModelType(dgfCDB2Document), default=list()) # All documents and attachments related to the auction. + documents = ListType(ModelType(AuctionDocument), default=list()) # All documents and attachments related to the auction. enquiryPeriod = ModelType(Period) # The period during which enquiries may be made and will be answered. rectificationPeriod = ModelType(RectificationPeriod) # The period during which editing of main procedure fields are allowed tenderPeriod = ModelType(Period) # The period when the auction is open for submissions. The end date is the closing date for auction submissions. @@ -302,7 +306,7 @@ def next_check(self): # Rubble Financial models -class dgfFinCDB2Document(dgfCDB2Document): +class RubbleFinancialDocument(AuctionDocument): documentType = StringType(choices=[ 'auctionNotice', 'awardNotice', 'contractNotice', 'notice', 'biddingDocuments', 'technicalSpecifications', @@ -315,10 +319,10 @@ class dgfFinCDB2Document(dgfCDB2Document): 'qualificationDocuments', 'eligibilityDocuments', 'tenderNotice', 'illustration', 'financialLicense', 'virtualDataRoom', 'auctionProtocol', 'x_dgfAssetFamiliarization', - 'x_presentation', 'x_nda', + 'x_presentation', 'x_nda', 'cancellationDetails' ]) -dgfFinCDB2Document.__name__ = 'Document' +RubbleFinancialDocument.__name__ = 'Document' class Bid(Bid): @@ -326,7 +330,7 @@ class Options: roles = { 'create': whitelist('value', 'tenderers', 'parameters', 'lotValues', 'status', 'qualified', 'eligible'), } - documents = ListType(ModelType(dgfFinCDB2Document), default=list()) + documents = ListType(ModelType(RubbleFinancialDocument), default=list()) tenderers = ListType(ModelType(FinancialOrganization), required=True, min_size=1, max_size=1) eligible = BooleanType(required=True, choices=[True]) @@ -335,7 +339,7 @@ class Options: class Auction(RubbleOther): """Data regarding auction process - publicly inviting prospective contractors to submit bids for evaluation and selecting a winner or winners.""" _internal_type = "rubbleFinancial" - documents = ListType(ModelType(dgfFinCDB2Document), default=list()) # All documents and attachments related to the auction. + documents = ListType(ModelType(RubbleFinancialDocument), default=list()) # All documents and attachments related to the auction. bids = ListType(ModelType(Bid), default=list()) procurementMethodType = StringType() eligibilityCriteria = StringType(default=u"До участі допускаються лише ліцензовані фінансові установи.") diff --git a/openprocurement/auctions/rubble/tests/blanks/migration_blanks.py b/openprocurement/auctions/rubble/tests/blanks/migration_blanks.py index 5cac833..7794fdb 100644 --- a/openprocurement/auctions/rubble/tests/blanks/migration_blanks.py +++ b/openprocurement/auctions/rubble/tests/blanks/migration_blanks.py @@ -1217,3 +1217,128 @@ def migrate_unsuccessful_unsuccessful_active(self): self.assertEqual(auction['awards'][1]['status'], 'unsuccessful') self.assertEqual(auction['awards'][2]['status'], 'active') self.assertEqual(auction['contracts'][0]['status'], 'pending') + + +def migrate_document_of_auction_documents(self): + auction = self.db.get(self.auction_id) + self.assertIsNone(auction.get('documents')) + auction['documents'] = [self.test_document_data] + + auction.update(auction) + self.db.save(auction) + + response = self.app.get('/auctions/{}'.format(self.auction_id)) + self.assertEqual(response.status, '200 OK') + self.assertEqual(response.content_type, 'application/json') + self.assertEqual(response.json['data']['documents'][0]['documentOf'], 'tender') + + self.runner.migrate(self.steps) + + response = self.app.get('/auctions/{}'.format(self.auction_id)) + self.assertEqual(response.status, '200 OK') + self.assertEqual(response.content_type, 'application/json') + self.assertEqual(response.json['data']['documents'][0]['documentOf'], 'auction') + + +def migrate_document_of_bids_documents(self): + auction = self.db.get(self.auction_id) + bid, bid_id = self.initial_bids[0], self.initial_bids[0]['id'] + + auction['bids'] = [self.initial_bids[0]] + auction['status'] = 'complete' + auction['bids'][0]['documents'] = [self.test_document_data] + auction.update(auction) + self.db.save(auction) + + response = self.app.get( + '/auctions/{}/bids/{}/documents?acc_token={}'.format(self.auction_id, bid_id, self.initial_bids_tokens[bid_id])) + self.assertEqual(response.status, '200 OK') + self.assertEqual(response.content_type, 'application/json') + self.assertEqual(response.json['data'][0]['documentOf'], 'tender') + + self.runner.migrate(self.steps) + + response = self.app.get( + '/auctions/{}/bids/{}/documents?acc_token={}'.format(self.auction_id, bid_id, self.initial_bids_tokens[bid_id])) + self.assertEqual(response.status, '200 OK') + self.assertEqual(response.content_type, 'application/json') + self.assertEqual(response.json['data'][0]['documentOf'], 'auction') + + +def migrate_document_of_awards_documents(self): + auction = self.db.get(self.auction_id) + _id = uuid4().hex + award = { + 'id': _id, + 'bid_id': self.initial_bids[0]['id'], + "documents": [self.test_document_data] + } + + auction['bids'] = [self.initial_bids[0]] + auction['awards'] = [award] + auction.update(auction) + self.db.save(auction) + + response = self.app.get('/auctions/{}/awards/{}/documents'.format(self.auction_id, _id)) + self.assertEqual(response.json['data'][0]['documentOf'], 'tender') + self.assertEqual(response.status, '200 OK') + self.assertEqual(response.content_type, 'application/json') + + self.runner.migrate(self.steps) + + response = self.app.get('/auctions/{}/awards/{}/documents'.format(self.auction_id, _id)) + self.assertEqual(response.status, '200 OK') + self.assertEqual(response.content_type, 'application/json') + self.assertEqual(response.json['data'][0]['documentOf'], 'auction') + + +def migrate_document_of_contracts_documents(self): + auction = self.db.get(self.auction_id) + _id = uuid4().hex + contract = { + 'id': _id, + "documents": [self.test_document_data] + } + + auction['contracts'] = [contract] + auction.update(auction) + self.db.save(auction) + + response = self.app.get('/auctions/{}/contracts/{}/documents'.format(self.auction_id, _id)) + self.assertEqual(response.json['data'][0]['documentOf'], 'tender') + self.assertEqual(response.status, '200 OK') + self.assertEqual(response.content_type, 'application/json') + + self.runner.migrate(self.steps) + + response = self.app.get('/auctions/{}/contracts/{}/documents'.format(self.auction_id, _id)) + self.assertEqual(response.status, '200 OK') + self.assertEqual(response.content_type, 'application/json') + self.assertEqual(response.json['data'][0]['documentOf'], 'auction') + + +def migrate_document_of_cancellations_documents(self): + + auction = self.db.get(self.auction_id) + id = uuid4().hex + + auction['cancellations'] = [{ + "reason": "cancellation reason", + "id": id, + "documents": [self.test_document_data], + }] + + auction.update(auction) + self.db.save(auction) + + response = self.app.get('/auctions/{}/cancellations/{}/documents'.format(self.auction_id, id)) + self.assertEqual(response.json['data'][0]['documentOf'], 'tender') + self.assertEqual(response.status, '200 OK') + self.assertEqual(response.content_type, 'application/json') + + self.runner.migrate(self.steps) + + response = self.app.get('/auctions/{}/cancellations/{}/documents'.format(self.auction_id, id)) + self.assertEqual(response.status, '200 OK') + self.assertEqual(response.content_type, 'application/json') + self.assertEqual(response.json['data'][0]['documentOf'], 'auction') diff --git a/openprocurement/auctions/rubble/tests/migration.py b/openprocurement/auctions/rubble/tests/migration.py index 54bb770..8545172 100644 --- a/openprocurement/auctions/rubble/tests/migration.py +++ b/openprocurement/auctions/rubble/tests/migration.py @@ -7,7 +7,7 @@ from openprocurement.auctions.core.tests.base import snitch from openprocurement.auctions.rubble.migration import migrate_data, get_db_schema_version, set_db_schema_version, SCHEMA_VERSION -from openprocurement.auctions.rubble.tests.base import BaseWebTest, BaseAuctionWebTest, test_bids +from openprocurement.auctions.rubble.tests.base import BaseWebTest, BaseAuctionWebTest, test_bids, test_auction_data from openprocurement.auctions.rubble.tests.blanks.migration_blanks import ( # MigrateTestFrom1To2Bids migrate_one_pending, @@ -28,9 +28,20 @@ migrate_awards_number, # MigrateTestFrom1To2WithThreeBids migrate_unsuccessful_unsuccessful_pending, - migrate_unsuccessful_unsuccessful_active + migrate_unsuccessful_unsuccessful_active, + # MigrateDocumentOf + migrate_document_of_auction_documents, + migrate_document_of_bids_documents, + migrate_document_of_awards_documents, + migrate_document_of_contracts_documents, + migrate_document_of_cancellations_documents ) +from openprocurement.auctions.rubble.migration import ( + RubbleMigrationsRunner, DocumentOfStep, PACKAGE_ALIASES +) +from openprocurement.api.tests.fixtures.mocks import MigrationResourcesDTO_mock + class MigrateTest(BaseWebTest): @@ -99,12 +110,42 @@ def setUp(self): self.db.save(auction) +class MigrateTestDocumentOf(BaseAuctionWebTest): + initial_data = test_auction_data + initial_bids = test_bids + test_document_data = { + 'title': 'auction_protocol.pdf', + 'hash': 'md5:' + '0' * 32, + 'format': 'application/msword', + "description": "auction protocol", + "documentType": 'auctionProtocol', + 'url': 'http://localhost/test', + 'documentOf': 'tender' + + } + test_migrate_document_of_auction_documents = snitch(migrate_document_of_auction_documents) + test_migrate_document_of_bids_documents = snitch(migrate_document_of_bids_documents) + test_migrate_document_of_awards_documents = snitch(migrate_document_of_awards_documents) + test_migrate_document_of_contracts_documents = snitch(migrate_document_of_contracts_documents) + test_migrate_document_of_cancellations_documents = snitch(migrate_document_of_cancellations_documents) + + def setUp(self): + super(MigrateTestDocumentOf, self).setUp() + self.runner = RubbleMigrationsRunner( + MigrationResourcesDTO_mock( + self.db, PACKAGE_ALIASES + ) + ) + self.steps = (DocumentOfStep, ) + + def suite(): suite = unittest.TestSuite() suite.addTest(unittest.makeSuite(MigrateTest)) suite.addTest(unittest.makeSuite(MigrateTestFrom1To2Bids)) suite.addTest(unittest.makeSuite(MigrateTestFrom1To2WithTwoBids)) suite.addTest(unittest.makeSuite(MigrateTestFrom1To2WithThreeBids)) + suite.addTest(unittest.makeSuiter(MigrateTestDocumentOf)) return suite