diff --git a/microsetta_private_api/admin/admin_impl.py b/microsetta_private_api/admin/admin_impl.py index a747beca..9cee65eb 100644 --- a/microsetta_private_api/admin/admin_impl.py +++ b/microsetta_private_api/admin/admin_impl.py @@ -60,7 +60,7 @@ def search_kit_id(token_info, kit_id): admin_repo = AdminRepo(t) diag = admin_repo.retrieve_diagnostics_by_kit_id(kit_id) if diag is None: - return jsonify(code=404, message="Kit ID not found"), 404 + return jsonify(code=404, message=f'Kit ID {kit_id} not found'), 404 return jsonify(diag), 200 @@ -267,13 +267,52 @@ def create_kits(body, token_info): number_of_samples = body['number_of_samples'] kit_prefix = body.get('kit_id_prefix', None) project_ids = body['project_ids'] + # NB: The barcodes variable is a list of lists, structured with the notion + # of representing barcodes' constituent lists each representing one sample + # slot in the set of kits being created. + # len(barcodes) == number_of_samples && len(barcodes[x]) == number_of_kits + # This allows the creation of a set of kits with a mixture of + # system-generated and admin-provided barcodes. + barcodes = body['barcodes'] with Transaction() as t: admin_repo = AdminRepo(t) + # Lock the barcode table for the duration of checking the existience + # of barcodes, then (hopefully) creating/inserting new ones + t.lock_table("barcodes.barcode") + + # First, do some basic sanitation + errors = [] + for barcode_list in barcodes: + x = 1 + if len(barcode_list) != 0: + # If barcodes were provided for a given slot, ensure the + # quantity matches the number of kits + if len(barcode_list) != number_of_kits: + errors.append( + f'Incorrect number of barcodes given for Sample {x}' + ) + + # And verify that the barcodes don't already exist + for barcode in barcode_list: + diag = admin_repo.check_exists_barcode(barcode) + if diag is True: + errors.append(f'Barcode {barcode} already exists') + x += 1 + + if len(errors) > 0: + error_str = "; ".join(errors) + return jsonify(code=422, message=error_str), 422 + try: - kits = admin_repo.create_kits(number_of_kits, number_of_samples, - kit_prefix, project_ids) + kits = admin_repo.create_kits( + number_of_kits, + number_of_samples, + kit_prefix, + barcodes, + project_ids + ) except KeyError: return jsonify(code=422, message="Unable to create kits"), 422 else: @@ -282,6 +321,60 @@ def create_kits(body, token_info): return jsonify(kits), 201 +def add_barcodes_to_kits(body, token_info): + validate_admin_access(token_info) + + kit_ids = body['kit_ids'] + barcodes = body['barcodes'] + generate_barcodes = body['generate_barcodes'] + + errors = [] + + with Transaction() as t: + admin_repo = AdminRepo(t) + + # Lock the barcode table for the duration of checking the existience + # of barcodes, then (hopefully) adding them to kits + t.lock_table("barcodes.barcode") + + # First, make sure all of the Kit IDs are valid + for kit_id in kit_ids: + diag = admin_repo.check_exists_kit(kit_id) + if diag is False: + errors.append(f'Kit ID {kit_id} not found') + + if generate_barcodes is False: + # Next, check that the Barcodes are unique if we're not generating + # novel ones + for barcode in barcodes: + diag = admin_repo.check_exists_barcode(barcode) + if diag is True: + errors.append(f'Barcode {barcode} already exists') + + # And verify that the number of barcodes and kit IDs are equal + if len(barcodes) != len(kit_ids): + errors.append("Unequal number of Kit IDs and Barcodes") + else: + if len(barcodes) > 0: + errors.append( + "Barcodes may not be both generated and provided" + ) + + # We found one or more issues with the supplied Kit IDs or Barcodes. + # Return the error message to microsetta-admin. + if len(errors) > 0: + error_str = "; ".join(errors) + return jsonify( + code=422, + message=error_str + ), 422 + + diag = admin_repo.add_barcodes_to_kits(kit_ids, barcodes) + t.commit() + + return jsonify(diag), 201 + + def get_account_events(account_id, token_info): validate_admin_access(token_info) diff --git a/microsetta_private_api/admin/tests/test_admin_repo.py b/microsetta_private_api/admin/tests/test_admin_repo.py index f50bcacc..f1ee3d0a 100644 --- a/microsetta_private_api/admin/tests/test_admin_repo.py +++ b/microsetta_private_api/admin/tests/test_admin_repo.py @@ -352,7 +352,6 @@ def make_tz_datetime(y, m, d): self.assertGreater(len(diag['projects_info']), 0) self.assertEqual(len(diag['scans_info']), 2) # order matters in the returned vals, so test that - print(diag['scans_info'][0], first_scan) self.assertEqual(diag['scans_info'][0], first_scan) self.assertEqual(diag['scans_info'][1], second_scan) self.assertEqual(diag['latest_scan'], second_scan) @@ -454,7 +453,11 @@ def test_get_project_barcodes_by_id(self): output_id = admin_repo.create_project(input) # create some fake kits - created = admin_repo.create_kits(2, 3, 'foo', [output_id, ]) + created = admin_repo.create_kits(2, + 3, + 'foo', + [[], [], []], + [output_id, ]) exp = [] for kit in created['created']: @@ -609,14 +612,14 @@ def test_create_kits_fail_nonexistent_project(self): admin_repo.create_kits(5, 3, '', + [[], [], []], [10000, SurveyTemplateRepo.VIOSCREEN_ID]) def test_create_kits_success_not_microsetta(self): with Transaction() as t: admin_repo = AdminRepo(t) - non_tmi = admin_repo.create_kits(5, 3, '', - [33]) + non_tmi = admin_repo.create_kits(5, 3, '', [[], [], []], [33]) self.assertEqual(['created', ], list(non_tmi.keys())) self.assertEqual(len(non_tmi['created']), 5) for obj in non_tmi['created']: @@ -643,8 +646,7 @@ def test_create_kits_success_not_microsetta(self): def test_create_kits_success_is_microsetta(self): with Transaction() as t: admin_repo = AdminRepo(t) - tmi = admin_repo.create_kits(4, 2, 'foo', - [1]) + tmi = admin_repo.create_kits(4, 2, 'foo', [[], []], [1]) self.assertEqual(['created', ], list(tmi.keys())) self.assertEqual(len(tmi['created']), 4) for obj in tmi['created']: @@ -669,6 +671,63 @@ def test_create_kits_success_is_microsetta(self): observed = cur.fetchall() self.assertEqual(len(observed), 4) + def test_create_kits_success_mix_provided_generated_barcodes(self): + # This test will confirm that AdminRepo.create_kits correctly places + # admin-provided barcodes in relation to intent. We'll do 1 kits with + # 3 samples. 2 samples will be admin-provided barcodes and 1 will be + # generated. + + # Sample Slot 1 + sample_1_barcodes = [ + "thisisabarcode" + ] + # Sample Slot 2 + sample_2_barcodes = [ + "thisisabarcodetoo" + ] + # Sample Slot 3 - generated + sample_3_barcodes = [] + + with Transaction() as t: + admin_repo = AdminRepo(t) + tmi = admin_repo.create_kits( + 1, + 3, + 'foo', + [sample_1_barcodes, sample_2_barcodes, sample_3_barcodes], + [1] + ) + self.assertEqual(['created', ], list(tmi.keys())) + self.assertEqual(len(tmi['created']), 1) + for obj in tmi['created']: + self.assertEqual(len(obj['sample_barcodes']), 3) + self.assertEqual({'kit_id', 'kit_uuid', 'box_id', 'address', + 'outbound_fedex_tracking', + 'inbound_fedex_tracking', + 'sample_barcodes'}, set(obj)) + self.assertTrue(obj['kit_id'].startswith('foo_')) + self.assertEqual(obj['kit_uuid'], obj['box_id']) + self.assertEqual(None, obj['address']) + self.assertEqual(None, obj['outbound_fedex_tracking']) + self.assertEqual(None, obj['inbound_fedex_tracking']) + + # should be present in the ag tables + tmi_kits = [k['kit_id'] for k in tmi['created']] + with t.cursor() as cur: + cur.execute("SELECT supplied_kit_id " + "FROM ag.ag_kit " + "WHERE supplied_kit_id IN %s", + (tuple(tmi_kits),)) + observed = cur.fetchall() + self.assertEqual(len(observed), 1) + + kit = tmi['created'][0] + # Assert that the provided barcodes are present + self.assertEqual(kit['sample_barcodes'][0], sample_1_barcodes[0]) + self.assertEqual(kit['sample_barcodes'][1], sample_2_barcodes[0]) + # And the last barcode starts with X per the generation algorithm + self.assertEqual(kit['sample_barcodes'][2][0], "X") + def test_create_kit_success_is_microsetta(self): input_kit_name = "DM24-A3CF9" input_box_id = "DM89D-VW6Y" @@ -878,7 +937,6 @@ def test_scan_with_multiple_observations(self): scans = [scan['observations'] for scan in diag['scans_info']] scans_observation_ids = [obs['observation_id'] for scan in scans for obs in scan] - self.assertEqual(scans_observation_ids, observation_ids) def test_scan_with_wrong_observation(self): @@ -1488,6 +1546,194 @@ def test_update_perk_fulfillment_state(self): obs = cur.fetchone() self.assertFalse(obs[0]) + def test_add_barcodes_to_kits_generated_success(self): + # These two kit IDs are stable in the dev database and are TMI kits + kit_id_1 = "wiydx" + kit_id_2 = "TjrzA" + kit_ids = [kit_id_1, kit_id_2] + barcodes = [] + + with Transaction() as t: + with t.cursor() as cur: + # Establish counts for barcodes contained in our test kits + cur.execute( + "SELECT COUNT(*) FROM barcodes.barcode " + "WHERE kit_id = %s", + (kit_id_1,) + ) + kit_id_1_barcode_count = cur.fetchone()[0] + cur.execute( + "SELECT COUNT(*) FROM barcodes.barcode " + "WHERE kit_id = %s", + (kit_id_2,) + ) + kit_id_2_barcode_count = cur.fetchone()[0] + + admin_repo = AdminRepo(t) + res = admin_repo.add_barcodes_to_kits(kit_ids, barcodes) + for kit_id, barcode in res: + # Verify that the barcode was created and is associated + # with the kit ID + cur.execute( + "SELECT COUNT(*) FROM barcodes.barcode " + "WHERE kit_id = %s AND barcode = %s", + (kit_id, barcode) + ) + obs = cur.fetchone() + self.assertEqual(obs[0], 1) + + # Verify that the barcode is associated with Project 1 + cur.execute( + "SELECT COUNT(*) FROM barcodes.project_barcode " + "WHERE barcode = %s AND project_id = 1", + (barcode, ) + ) + obs = cur.fetchone() + self.assertEqual(obs[0], 1) + + # Verify that the barcode was added to ag.ag_kit_barcodes + cur.execute( + "SELECT COUNT(*) FROM ag.ag_kit_barcodes " + "WHERE barcode = %s", + (barcode, ) + ) + obs = cur.fetchone() + self.assertEqual(obs[0], 1) + + # Verify that kit_id_1 has exactly one more barcode in the + # barcodes.barcode table + cur.execute( + "SELECT COUNT(*) FROM barcodes.barcode " + "WHERE kit_id = %s", + (kit_id_1,) + ) + obs = cur.fetchone() + self.assertEqual(obs[0], kit_id_1_barcode_count+1) + + # Verify that kit_id_2 has exactly one more barcode in the + # barcodes.barcode table + cur.execute( + "SELECT COUNT(*) FROM barcodes.barcode " + "WHERE kit_id = %s", + (kit_id_2,) + ) + obs = cur.fetchone() + self.assertEqual(obs[0], kit_id_2_barcode_count+1) + + def test_add_barcodes_to_kits_provided_success(self): + # These two kit IDs are stable in the dev database and are TMI kits + kit_id_1 = "wiydx" + kit_id_2 = "TjrzA" + kit_ids = [kit_id_1, kit_id_2] + + # Let's create some fake barcodes that won't exist in the database + barcode_1 = "cf2d5565-9c26-44f4-9aae-3e19d1cc78cf" + barcode_2 = "62596b88-bc63-4939-a8fd-7e53750808bc" + barcodes = [barcode_1, barcode_2] + + with Transaction() as t: + with t.cursor() as cur: + # Establish counts for barcodes contained in our test kits + cur.execute( + "SELECT COUNT(*) FROM barcodes.barcode " + "WHERE kit_id = %s", + (kit_id_1,) + ) + kit_id_1_barcode_count = cur.fetchone()[0] + cur.execute( + "SELECT COUNT(*) FROM barcodes.barcode " + "WHERE kit_id = %s", + (kit_id_2,) + ) + kit_id_2_barcode_count = cur.fetchone()[0] + + admin_repo = AdminRepo(t) + res = admin_repo.add_barcodes_to_kits(kit_ids, barcodes) + for kit_id, barcode in res: + # Verify that the barcode was created and is associated + # with the kit ID + cur.execute( + "SELECT COUNT(*) FROM barcodes.barcode " + "WHERE kit_id = %s AND barcode = %s", + (kit_id, barcode) + ) + obs = cur.fetchone() + self.assertEqual(obs[0], 1) + + # Verify that the barcode is associated with Project 1 + cur.execute( + "SELECT COUNT(*) FROM barcodes.project_barcode " + "WHERE barcode = %s AND project_id = 1", + (barcode, ) + ) + obs = cur.fetchone() + self.assertEqual(obs[0], 1) + + # Verify that the barcode was added to ag.ag_kit_barcodes + cur.execute( + "SELECT COUNT(*) FROM ag.ag_kit_barcodes " + "WHERE barcode = %s", + (barcode, ) + ) + obs = cur.fetchone() + self.assertEqual(obs[0], 1) + + # Verify that kit_id_1 has exactly one more barcode in the + # barcodes.barcode table + cur.execute( + "SELECT COUNT(*) FROM barcodes.barcode " + "WHERE kit_id = %s", + (kit_id_1,) + ) + obs = cur.fetchone() + self.assertEqual(obs[0], kit_id_1_barcode_count+1) + + # Verify that barcode_1 is associated with kit_id_1 + cur.execute( + "SELECT COUNT(*) FROM barcodes.barcode " + "WHERE kit_id = %s AND barcode = %s", + (kit_id_1, barcode_1) + ) + obs = cur.fetchone() + self.assertEqual(obs[0], 1) + + # Verify that kit_id_2 has exactly one more barcode in the + # barcodes.barcode table + cur.execute( + "SELECT COUNT(*) FROM barcodes.barcode " + "WHERE kit_id = %s", + (kit_id_2,) + ) + obs = cur.fetchone() + self.assertEqual(obs[0], kit_id_2_barcode_count+1) + + # Verify that barcode_2 is associated with kit_id_2 + cur.execute( + "SELECT COUNT(*) FROM barcodes.barcode " + "WHERE kit_id = %s AND barcode = %s", + (kit_id_2, barcode_2) + ) + obs = cur.fetchone() + self.assertEqual(obs[0], 1) + + def test_add_barcodes_to_kits_provided_failure(self): + # This test confirms that if the admin provides duplicate barcodes in + # the upload, it will fail to insert + self.assertFalse(False) + # These two kit IDs are stable in the dev database and are TMI kits + kit_id_1 = "wiydx" + kit_id_2 = "TjrzA" + kit_ids = [kit_id_1, kit_id_2] + + # This barcode doesn't exist in the database, but we'll try to use it + # twice + barcode_1 = "cf2d5565-9c26-44f4-9aae-3e19d1cc78cf" + barcodes = [barcode_1, barcode_1] + with Transaction() as t: + admin_repo = AdminRepo(t) + with self.assertRaises(psycopg2.errors.UniqueViolation): + admin_repo.add_barcodes_to_kits(kit_ids, barcodes) + def test_get_barcodes_filter_kit_ids_success(self): with Transaction() as t: setup_sql = """ @@ -1711,3 +1957,39 @@ def test_get_kit_by_barcode_failure(self): admin_repo = AdminRepo(t) kit_info = admin_repo.get_kit_by_barcode(['nonexistent_barcode']) self.assertIsNone(kit_info) + + def test_check_exists_barcode_true(self): + # This is a stable barcode in the dev database + barcode = "000004801" + + with Transaction() as t: + admin_repo = AdminRepo(t) + bc_exists = admin_repo.check_exists_barcode(barcode) + self.assertTrue(bc_exists) + + def test_check_exists_barcode_false(self): + # This is not a barcode in the database + barcode = "absenzelysium" + + with Transaction() as t: + admin_repo = AdminRepo(t) + bc_exists = admin_repo.check_exists_barcode(barcode) + self.assertFalse(bc_exists) + + def test_check_exists_kit_true(self): + # This is a stable kit ID in the dev database + kit_id = "DXHsj" + + with Transaction() as t: + admin_repo = AdminRepo(t) + kit_exists = admin_repo.check_exists_kit(kit_id) + self.assertTrue(kit_exists) + + def test_check_exists_kit_false(self): + # This is not a kit ID in the database + kit_id = "absenzelysium" + + with Transaction() as t: + admin_repo = AdminRepo(t) + kit_exists = admin_repo.check_exists_kit(kit_id) + self.assertFalse(kit_exists) diff --git a/microsetta_private_api/api/microsetta_private_api.yaml b/microsetta_private_api/api/microsetta_private_api.yaml index ef8386d5..6766ff37 100644 --- a/microsetta_private_api/api/microsetta_private_api.yaml +++ b/microsetta_private_api/api/microsetta_private_api.yaml @@ -2789,10 +2789,17 @@ paths: type: array items: type: string + barcodes: + type: array + items: + type: array + items: + type: string required: - number_of_kits - number_of_samples - project_ids + - barcodes responses: '201': description: Kit identifiers and associated samples were successfully created @@ -2805,6 +2812,47 @@ paths: '422': $ref: '#/components/responses/422UnprocessableEntity' + '/admin/add_barcodes_to_kits': + post: + operationId: microsetta_private_api.admin.admin_impl.add_barcodes_to_kits + tags: + - Admin + summary: Add barcodes to an existing kit + description: Add barcodes to an existing kit + requestBody: + content: + application/json: + schema: + type: "object" + properties: + generate_barcodes: + type: boolean + description: Flag for whether barcodes are provided or must be generated + barcodes: + type: array + items: + type: string + description: Barcodes to insert, optional + kit_ids: + type: array + items: + type: string + description: Kit IDs to associate the barcodes with + required: + - generate_barcodes + - kit_ids + responses: + '201': + description: Barcodes were successfully added + content: + application/json: + schema: + type: array + '401': + $ref: '#/components/responses/401Unauthorized' + '422': + $ref: '#/components/responses/422UnprocessableEntity' + '/admin/events/accounts/{account_id}': get: operationId: microsetta_private_api.admin.admin_impl.get_account_events diff --git a/microsetta_private_api/repo/admin_repo.py b/microsetta_private_api/repo/admin_repo.py index 0d8d3a9e..4fccf630 100644 --- a/microsetta_private_api/repo/admin_repo.py +++ b/microsetta_private_api/repo/admin_repo.py @@ -913,7 +913,7 @@ def _generate_random_kit_name(self, name_length, prefix): return prefix + '_' + rand_name def create_kits(self, number_of_kits, number_of_samples, kit_prefix, - project_ids): + barcodes, project_ids): """Create multiple kits, each with the same number of samples Parameters @@ -924,18 +924,46 @@ def create_kits(self, number_of_kits, number_of_samples, kit_prefix, Number of samples that each kit will contain kit_prefix : str or None A prefix to put on to the kit IDs, this is optional. + barcodes : list of lists of str + User provided barcodes to use for the kits. If empty, barcodes + will be generated. project_ids : list of int Project ids the samples are to be associated with """ kit_names = self._generate_novel_kit_names(number_of_kits, kit_prefix) - kit_name_and_barcode_tuples_list, new_barcodes = \ - self._generate_novel_barcodes( - number_of_kits, number_of_samples, kit_names) - return self._create_kits(kit_names, new_barcodes, - kit_name_and_barcode_tuples_list, - number_of_samples, project_ids) + new_barcodes = [] + kit_name_and_barcode_tuples_list = [] + + # Iterate through sample slots and use provided barcodes + for barcode_list in barcodes: + if len(barcode_list) > 0: + # Admin provided barcodes for this sample slot, use them + kit_barcode_tuples = list(zip(kit_names, barcode_list)) + kit_name_and_barcode_tuples_list += kit_barcode_tuples + new_barcodes += barcode_list + + # See if we need to generate barcodes + slots_to_generate = sum(1 for i in barcodes if len(i) == 0) + if slots_to_generate > 0: + # Generate remaining barcodes + kit_barcode_tuples, novel_barcodes = \ + self._generate_novel_barcodes( + number_of_kits, + slots_to_generate, + kit_names + ) + new_barcodes += novel_barcodes + kit_name_and_barcode_tuples_list += kit_barcode_tuples + + return self._create_kits( + kit_names, + new_barcodes, + kit_name_and_barcode_tuples_list, + number_of_samples, + project_ids + ) def _are_any_projects_tmi(self, project_ids): """Return true if any input projects are part of microsetta""" @@ -1015,7 +1043,71 @@ def _generate_novel_barcodes(self, number_of_kits, number_of_samples, kit_name_and_barcode_tuples_list.append( (name, new_barcodes[offset + i])) - return kit_name_and_barcode_tuples_list, new_barcodes + return kit_name_and_barcode_tuples_list, new_barcodes + + def add_barcodes_to_kits(self, kit_ids, barcodes): + """Adds barcodes to supplied kits + + Parameters + ---------- + kit_ids : list of str + The kit IDs for which we're adding barcodes + barcodes : list of str + The list of admin-supplied barcodes; if empty generates novel + barcodes + + Returns + ------- + list of tuples + The pairings of newly added kit IDs/barcodes + """ + + if len(barcodes) == 0: + kits_barcodes_tuples, _ = self._generate_novel_barcodes( + len(kit_ids), + 1, + kit_ids + ) + else: + kits_barcodes_tuples = list(zip(kit_ids, barcodes)) + + with self._transaction.cursor() as cur: + for kit_id, barcode in kits_barcodes_tuples: + kit_d = self.retrieve_diagnostics_by_kit_id(kit_id) + ag_kit_id = kit_d['kit_id'] + + projects = kit_d['sample_diagnostic_info'][0]['projects_info'] + project_ids = [x['project_id'] for x in projects] + is_tmi = self._are_any_projects_tmi(project_ids) + + barcode_projects = [] + for project_id in project_ids: + barcode_projects.append((barcode, project_id)) + + # Add barcodes to barcode table + cur.execute( + "INSERT INTO barcodes.barcode(kit_id, barcode, status) " + "VALUES (%s, %s, 'unassigned')", + (kit_id, barcode) + ) + + # Create project/barcode association(s) + cur.executemany( + "INSERT INTO barcodes.project_barcode " + "(barcode, project_id) " + "VALUES (%s, %s)", + barcode_projects + ) + + # If any projects are TMI-oriented, add to ag_kit_barcodes + if is_tmi: + cur.execute( + "INSERT INTO ag.ag_kit_barcodes (ag_kit_id, barcode) " + "VALUES (%s, %s)", + (ag_kit_id, barcode) + ) + + return kits_barcodes_tuples def _create_kits(self, kit_names, new_barcodes, kit_name_and_barcode_tuples_list, @@ -1047,9 +1139,16 @@ def _create_kits(self, kit_names, new_barcodes, with self._transaction.cursor() as cur: # create barcode project associations barcode_projects = [] - for barcode in new_barcodes: - for prj_id in project_ids: - barcode_projects.append((barcode, prj_id)) + if isinstance(new_barcodes, list) and \ + all(isinstance(item, list) for item in new_barcodes): + for barcodes in new_barcodes: + for barcode in barcodes: + for prj_id in project_ids: + barcode_projects.append((barcode, prj_id)) + else: + for barcode in new_barcodes: + for prj_id in project_ids: + barcode_projects.append((barcode, prj_id)) # create kits in kit table new_kit_uuids = [str(uuid.uuid4()) for x in kit_names] @@ -1146,7 +1245,6 @@ def create_kit(self, kit_name, box_id, address_dict, Project ids that all barcodes in kit are to be associated with """ - kit_names = [kit_name] address = None if address_dict is None else json.dumps(address_dict) kit_details = [{KIT_BOX_ID_KEY: box_id, KIT_ADDRESS_KEY: address, @@ -1154,6 +1252,7 @@ def create_kit(self, kit_name, box_id, address_dict, KIT_INBOUND_KEY: inbound_fedex_code}] kit_name_and_barcode_tuples_list = \ [(kit_name, x) for x in barcodes_list] + kit_names = [kit_name] return self._create_kits(kit_names, barcodes_list, kit_name_and_barcode_tuples_list, @@ -1619,3 +1718,25 @@ def update_perk_fulfillment_state(self, new_state): "SET perk_fulfillment_active = %s", (new_state, ) ) + + def check_exists_barcode(self, barcode): + with self._transaction.cursor() as cur: + cur.execute( + "SELECT COUNT(barcode) " + "FROM barcodes.barcode " + "WHERE barcode = %s", + (barcode, ) + ) + res = cur.fetchone() + return True if res[0] > 0 else False + + def check_exists_kit(self, kit_id): + with self._transaction.cursor() as cur: + cur.execute( + "SELECT COUNT(kit_id) " + "FROM barcodes.kit " + "WHERE kit_id = %s", + (kit_id, ) + ) + res = cur.fetchone() + return True if res[0] > 0 else False diff --git a/microsetta_private_api/repo/tests/test_sample.py b/microsetta_private_api/repo/tests/test_sample.py index e917ed43..01b13f5b 100644 --- a/microsetta_private_api/repo/tests/test_sample.py +++ b/microsetta_private_api/repo/tests/test_sample.py @@ -152,6 +152,7 @@ def test_get_supplied_kit_id_by_sample(self): 1, 1, "UNITTEST", + [[]], [1] )