Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bulk_scan barcode #512

Open
wants to merge 22 commits into
base: master-overhaul
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions microsetta_private_api/admin/admin_impl.py
Original file line number Diff line number Diff line change
Expand Up @@ -917,3 +917,34 @@ def get_vioscreen_sample_to_user(token_info):
st_repo = SurveyTemplateRepo(t)
data = st_repo.get_vioscreen_sample_to_user()
return jsonify(data), 200


def map_to_rack(token_info, sample_barcode, body):
validate_admin_access(token_info)

print(str(body))
raginirai553 marked this conversation as resolved.
Show resolved Hide resolved

with Transaction() as t:
admin_repo = AdminRepo(t)
scan_id = admin_repo.map_to_rack(sample_barcode, body)
t.commit()

response = jsonify({"scan_id": scan_id})
response.status_code = 201
return response


def get_sample_from_rack(token_info, rack_id):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The mapping between samples and racks needs to be sensitive to the fact that samples can move from rack to rack. Right now, the code just assumes that there's a stable relationship, which results in issues when you test using different sample barcodes with the same rack ID. Retrieving the samples from a rack should only reflect the samples that were present at the most recent scan, not every sample that has ever been on the rack.

Also, please pluralize the function name to reflect that we expect multiple samples to exist on a rack.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved the issue!

validate_admin_access(token_info)

with Transaction() as t:
admin_repo = AdminRepo(t)
row = admin_repo.get_rack_sample(rack_id)
if row is None:
response = jsonify({"message": "sample does not exist!"})
response.status_code = 404
return response
else:
response = jsonify({"result": row})
response.status_code = 201
return response
17 changes: 17 additions & 0 deletions microsetta_private_api/admin/tests/test_admin_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -1270,6 +1270,23 @@ def mock_func(*args, **kwargs):
headers=MOCK_HEADERS)
self.assertEqual(204, response.status_code)

def test_sample_map_to_rack(self):
barcode = "000001024"
scan_info = {
'rack_id': '005',
'location_row': 'B',
'location_col': '01'
}

response = self.client.post(
'/api/admin/rack/{0}/add'.format(barcode),
content_type="application/json",
data=json.dumps(scan_info),
headers=MOCK_HEADERS
)

self.assertEquals(201, response.status_code)

def test_generate_ffq_codes(self):
input_json = json.dumps({"code_quantity": 2})

Expand Down
30 changes: 30 additions & 0 deletions microsetta_private_api/admin/tests/test_admin_repo.py
Original file line number Diff line number Diff line change
Expand Up @@ -1324,6 +1324,36 @@ def test_set_kit_uuids_for_dak_order(self):
for expected_record in expected_records:
self.assertIn(expected_record, curr_records)

def test_map_to_rack_fail(self):
scan_info = {
'rack_id': '001',
'location_row': 'A',
'location_col': '02'
}

with Transaction() as t:
barcode = '00000000'

admin_repo = AdminRepo(t)
with self.assertRaises(NotFound):
admin_repo.map_to_rack(barcode, scan_info)

def test_map_to_rack_success(self):
scan_info = {
'rack_id': '001',
'location_row': 'A',
'location_col': '02'
}

uuid = ""
with Transaction() as t:
barcode = '000001024'

admin_repo = AdminRepo(t)
uuid = admin_repo.map_to_rack(barcode, scan_info)

self.assertTrue(len(uuid) > 0)

raginirai553 marked this conversation as resolved.
Show resolved Hide resolved
def test_create_ffq_code(self):
with Transaction() as t:
admin_repo = AdminRepo(t)
Expand Down
84 changes: 84 additions & 0 deletions microsetta_private_api/api/microsetta_private_api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2366,6 +2366,60 @@ paths:
schema:
type: object

'/admin/rack/{sample_barcode}/add':
post:
# Note: We might want to be able to differentiate system administrator operations
# from technician operations in the future by user accounts and the routes they post to
operationId: microsetta_private_api.admin.admin_impl.map_to_rack
tags:
- Admin
summary: Add sample to rack for a barcode
description: Add sample to rack for a barcode
parameters:
- $ref: '#/components/parameters/sample_barcode'
requestBody:
content:
application/json:
schema:
type: object
properties:
rack_id:
type: string
location_col:
type: string
location_row:
type: string
responses:
'201':
description: Successfully mapped new barcode scan to rack
content:
application/json:
schema:
type: object

'/admin/rack/sample/{rack_id}':
get:
operationId: microsetta_private_api.admin.admin_impl.get_sample_from_rack
tags:
- Admin
summary: Get sample details from rack by rack id
description: Get sample details from rack by rack id
parameters:
- $ref: '#/components/parameters/rack_id'
responses:
'201':
description: Successfully fetched sample details from rack by rack id
content:
application/json:
schema:
type: object
'404':
description: Sample does not exist
content:
application/json:
schema:
type: object

'/admin/metadata/samples/{sample_barcode}/surveys/{survey_template_id}':
get:
operationId: microsetta_private_api.admin.admin_impl.sample_pulldown_single_survey
Expand Down Expand Up @@ -2949,6 +3003,12 @@ components:
description: Type of consent
schema:
$ref: '#/components/schemas/consent_type'
rack_id:
name: rack_id
in: path
description: Rack id for a particular sample placed in rack
schema:
$ref: '#/components/schemas/rack_id'

# query parameters
activation_code:
Expand Down Expand Up @@ -3264,6 +3324,18 @@ components:
items:
type: string
example: "https://wherever.com"
rack_id:
type: string
example: "0000"
location_col:
type: string
example: "1"
location_row:
type: string
example: "A"
rack_id:
type: string
example: "aaaaaaaa-bbbb-cccc-dddd-eeeeffffffff"

sample:
type: object
Expand Down Expand Up @@ -3291,6 +3363,18 @@ components:
accession_urls:
$ref: '#/components/schemas/accession_urls'

scanned_sample:
type: object
properties:
rack_id:
$ref: '#/components/schemas/rack_id'
location_col:
$ref: '#/components/schemas/location_col'
location_row:
$ref: '#/components/schemas/location_row'
sample_datetime:
$ref: '#/components/schemas/sample_datetime'

preparation:
type: object
properties:
Expand Down
4 changes: 0 additions & 4 deletions microsetta_private_api/db/patches/0114.sql
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,6 @@ UPDATE ag.survey_question SET american = 'In the past month, have you been expos
UPDATE ag.survey_question SET american = 'In the past month, have you been suspected of having Coronavirus/COVID-19 infection?' WHERE survey_question_id = 212;
UPDATE ag.survey_question SET american = 'In the past 6 weeks, have you had any of the following symptoms? (check all that apply)' WHERE survey_question_id = 214;

-- Adjust the options for question 214
-- First, let's fix the typo in "Loss of appetite" - we'll leave the old option in the database so as to not break existing records
INSERT INTO ag.survey_response (american, spanish, spain_spanish) VALUES ('Lack of appetite', 'Falta de apetito', 'Falta de apetito');
UPDATE ag.survey_question_response SET response = 'Lack of appetite' WHERE response = 'Lack of appetitie';
-- Now let's add new options. First, we'll add the options to the database
INSERT INTO ag.survey_response (american) VALUES
('Shortness of breath or difficulty breathing'),
Expand Down
9 changes: 9 additions & 0 deletions microsetta_private_api/db/patches/0115.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
CREATE TABLE barcodes.rack_samples (
raginirai553 marked this conversation as resolved.
Show resolved Hide resolved
location_id uuid NOT NULL DEFAULT uuid_generate_v4(),
rack_id varchar NOT NULL,
sample_id varchar NOT NULL,
location_row varchar NOT NULL,
location_col varchar NOT NULL,
date_time TIMESTAMP WITH TIME ZONE NOT NULL,
PRIMARY KEY (location_id)
);
63 changes: 63 additions & 0 deletions microsetta_private_api/repo/admin_repo.py
Original file line number Diff line number Diff line change
Expand Up @@ -1136,6 +1136,69 @@ def search_barcode(self, sql_cond, cond_params):
)
return [r[0] for r in cur.fetchall()]

def map_to_rack(self, sample_barcode, scan_info):
with self._transaction.cursor() as cur:

# not actually using the result, just checking there IS one
# to ensure this is a valid barcode
cur.execute(
"SELECT barcode FROM barcodes.barcode WHERE barcode=%s",
(sample_barcode,)
)

if cur.rowcount == 0:
raise NotFound("No such barcode: %s" % sample_barcode)
elif cur.rowcount > 1:
# Note: This "can't" happen.
raise RepoException("ERROR: Multiple barcode entries would be "
"affected by scan; failing out")

# put a new row in the barcodes.barcode_scans table
new_uuid = str(uuid.uuid4())
scan_args = (
new_uuid,
scan_info['rack_id'],
sample_barcode,
scan_info['location_row'],
scan_info['location_col'],
datetime.datetime.now()
)

cur.execute(
"INSERT INTO barcodes.rack_samples "
"(location_id, rack_id, sample_id, "
"location_row, location_col, date_time) "
"VALUES (%s, %s, %s, %s, %s, %s)",
scan_args
)

return new_uuid

def get_rack_sample(self, rack_id):
raginirai553 marked this conversation as resolved.
Show resolved Hide resolved
with self._transaction.dict_cursor() as cur:

# not actually using the result, just checking there IS one
# to ensure this is a valid barcode
raginirai553 marked this conversation as resolved.
Show resolved Hide resolved
cur.execute(
"SELECT sample_id, location_row, location_col "
"FROM barcodes.rack_samples WHERE rack_id=%s",
(rack_id,)
)

sample_rows = cur.fetchall()

if len(sample_rows) == 0:
raise NotFound("No barcode with rack id: %s" % rack_id)

result = []
for row in sample_rows:
data_to_return = {}
data_to_return["location_row"] = row["location_row"]
data_to_return["location_col"] = row["location_col"]
data_to_return["barcode"] = row["sample_id"]
result.append(data_to_return)
return result

def get_survey_metadata(self, sample_barcode, survey_template_id=None):
'''
Return all surveys associated with a given barcode.
Expand Down