Sample tracking and experiment preparation
Entities
Shipment
Any participant of an investigation can create a shipment. A shipment is needed when samples are sent to the facility and it is linked to a scheduled investigation. It is specially important to track parcels and sample on-site.
A shipment is mainly composed by:
- Sender and return addresses. These are default addresses that they can be overrided for each aprcel
- A list of parcels: a parcel is the "thing" that will be sent by courier and has a status that allows determine in which stage (or place) the parcel is. A label containing a Qr code can be printed from the application and which identifies phisically a parcel.
Shipments are persisted in a MongoDB database. The full scheme description can be found here: schema
Parcel
A parcel is a "box" which is sent to the facility with the samples and tools needed to perform the experiment. A parcel has one status depending on which stage the parcel is and it is described here
Items
The content of a parcel is filled by items. An item can be:
- Tool
- Sample linked to a sample sheet
- Container
- Other
Tutorial
Creation of a shipment and a parcel
This notebook shows how to create addresses, shipment and a parcel from an existing investigation. It uses the ICAT+ API and needs to have a existing user with permissions to such investigation
import requests
import json
Configuration
As mentioned it needs a running instance of ICAT+, a valid user credentials and an existing investigation.
#icatplus_server = "http://dau-dm-03:8000"
icatplus_server = "http://lalex.esrf.fr:8000"
credential = {
"plugin": "db",
"username": "********",
"password": "********"
}
investigationId = 124564607
Login
This logs into ICAT in order to get the token that is called sessionId
. The sessionId
expires depending of the ICAT configuration and it is returned in the variable lefeTimeMinutes
session = requests.post(icatplus_server + "/session", data = credential)
session = json.loads(session.text)
sessionId = session["sessionId"]
print(session)
{'name': 'admin', 'username': 'admin', 'fullName': 'adminFullName', 'lifeTimeMinutes': 719.9995333333334, 'isAdministrator': True, 'isInstrumentScientist': False, 'isMinter': False, 'sessionId': '8d4728d0-e84d-40fb-b6d2-543e296ba194', 'usersByPrefix': []}
Get Investigation
url = (f'{icatplus_server}/catalogue/{sessionId}/investigation?ids={investigationId}')
print(url)
http://lalex.esrf.fr:8000/catalogue/8d4728d0-e84d-40fb-b6d2-543e296ba194/investigation?ids=124564607
investigation = requests.get(f'{url}')
print(json.dumps(json.loads(investigation.text), indent=2))
[
{
"name": "ID002306",
"startDate": "2023-06-19T13:28:44.492+02:00",
"id": 124564607,
"title": "ID002306",
"visitId": "id00",
"parameters": {
"__datasetCount": "6",
"__sampleCount": "2",
"__fileCount": "0",
"__volume": "0",
"__elapsedTime": "0",
"__acquisitionDatasetCount": "4",
"__processedDatasetCount": "2",
"__acquisitionFileCount": "0",
"__processedFileCount": "0",
"__acquisitionVolume": "0",
"__processedVolume": "0"
},
"instrument": {
"name": "ID00",
"id": 92177647
},
"investigationUsers": [],
"meta": {
"page": {
"totalWithoutFilters": 1,
"total": 1,
"totalPages": 1,
"currentPage": 1
}
},
"type": {
"id": 325,
"createId": "root",
"createTime": "2014-06-18T15:00:43.500+02:00",
"modId": "root",
"modTime": "2014-06-18T15:00:43.500+02:00",
"description": "Test investigation",
"investigations": [],
"name": "TEST"
}
}
]
Shipment and addresses
List Shipment
url_shipment = f'{icatplus_server}/tracking/{sessionId}/investigation/id/{investigationId}/shipment'
print(url_shipment)
http://lalex.esrf.fr:8000/tracking/8d4728d0-e84d-40fb-b6d2-543e296ba194/investigation/id/124564607/shipment
shipment = requests.get(f'{url_shipment}')
print(json.dumps(json.loads(shipment.text), indent=2))
[]
List addresses
url_address = f'{icatplus_server}/tracking/{sessionId}/investigation/id/{investigationId}/address'
print(url_address)
http://lalex.esrf.fr:8000/tracking/8d4728d0-e84d-40fb-b6d2-543e296ba194/investigation/id/124564607/address
addresses = requests.get(f'{url_address}')
print(addresses.text)
[]
Create address
address = {
"name": "Name",
"surname": "Surname",
"companyName": "My Company",
"address": "Rue Victor Hugo",
"city": "Grenoble",
"region": "Isere",
"postalCode": "38000",
"country": "France",
"email": "myemail@email.com",
"phoneNumber": "065222584"
}
address = requests.post(f'{url_address}', data=address)
print(json.dumps(json.loads(address.text), indent=2))
{
"status": "ACTIVE",
"_id": "649168052e95f7e77d8c8cae",
"name": "Name",
"surname": "Surname",
"companyName": "My Company",
"address": "Rue Victor Hugo",
"city": "Grenoble",
"region": "Isere",
"postalCode": "38000",
"country": "France",
"email": "myemail@email.com",
"phoneNumber": "065222584",
"investigationName": "ID002306",
"createdBy": "admin",
"investigationId": 124564607,
"createdAt": "2023-06-20T08:49:09.978Z",
"updatedAt": "2023-06-20T08:49:09.978Z",
"__v": 0
}
Create shipment
shipment = {
"name": "my new Shipment",
"investigationId":investigationId,
"defaultReturnAddress": json.loads(address.text)["_id"],
"defaultShippingAddress": json.loads(address.text)["_id"]
}
shipment = requests.post(f'{url_shipment}', data=shipment)
print(json.dumps(json.loads(shipment.text), indent=2))
{
"status": "OPENED",
"parcels": [],
"_id": "649168062e95f7e77d8c8caf",
"name": "my new Shipment",
"investigationId": 124564607,
"defaultReturnAddress": {
"status": "ACTIVE",
"_id": "649168052e95f7e77d8c8cae",
"name": "Name",
"surname": "Surname",
"companyName": "My Company",
"address": "Rue Victor Hugo",
"city": "Grenoble",
"region": "Isere",
"postalCode": "38000",
"country": "France",
"email": "myemail@email.com",
"phoneNumber": "065222584",
"investigationName": "ID002306",
"createdBy": "admin",
"investigationId": 124564607,
"createdAt": "2023-06-20T08:49:09.978Z",
"updatedAt": "2023-06-20T08:49:09.978Z",
"__v": 0
},
"defaultShippingAddress": {
"status": "ACTIVE",
"_id": "649168052e95f7e77d8c8cae",
"name": "Name",
"surname": "Surname",
"companyName": "My Company",
"address": "Rue Victor Hugo",
"city": "Grenoble",
"region": "Isere",
"postalCode": "38000",
"country": "France",
"email": "myemail@email.com",
"phoneNumber": "065222584",
"investigationName": "ID002306",
"createdBy": "admin",
"investigationId": 124564607,
"createdAt": "2023-06-20T08:49:09.978Z",
"updatedAt": "2023-06-20T08:49:09.978Z",
"__v": 0
},
"investigationName": "ID002306",
"createdAt": "2023-06-20T08:49:10.054Z",
"updatedAt": "2023-06-20T08:49:10.054Z",
"__v": 0
}
shipment = requests.get(f'{url_shipment}')
shipmentId = json.loads(shipment.text)[0]["_id"]
print(json.dumps(json.loads(shipment.text), indent=2))
[
{
"status": "OPENED",
"parcels": [],
"_id": "649168062e95f7e77d8c8caf",
"name": "my new Shipment",
"investigationId": 124564607,
"defaultReturnAddress": {
"status": "ACTIVE",
"_id": "649168052e95f7e77d8c8cae",
"name": "Name",
"surname": "Surname",
"companyName": "My Company",
"address": "Rue Victor Hugo",
"city": "Grenoble",
"region": "Isere",
"postalCode": "38000",
"country": "France",
"email": "myemail@email.com",
"phoneNumber": "065222584",
"investigationName": "ID002306",
"createdBy": "admin",
"investigationId": 124564607,
"createdAt": "2023-06-20T08:49:09.978Z",
"updatedAt": "2023-06-20T08:49:09.978Z",
"__v": 0
},
"defaultShippingAddress": {
"status": "ACTIVE",
"_id": "649168052e95f7e77d8c8cae",
"name": "Name",
"surname": "Surname",
"companyName": "My Company",
"address": "Rue Victor Hugo",
"city": "Grenoble",
"region": "Isere",
"postalCode": "38000",
"country": "France",
"email": "myemail@email.com",
"phoneNumber": "065222584",
"investigationName": "ID002306",
"createdBy": "admin",
"investigationId": 124564607,
"createdAt": "2023-06-20T08:49:09.978Z",
"updatedAt": "2023-06-20T08:49:09.978Z",
"__v": 0
},
"investigationName": "ID002306",
"createdAt": "2023-06-20T08:49:10.054Z",
"updatedAt": "2023-06-20T08:49:10.054Z",
"__v": 0
}
]
Create parcels
url_parcel = f'{icatplus_server}/tracking/{sessionId}/parcel?investigationId={investigationId}&shipmentId={shipmentId}'
print(url_parcel)
http://lalex.esrf.fr:8000/tracking/8d4728d0-e84d-40fb-b6d2-543e296ba194/parcel?investigationId=124564607&shipmentId=649168062e95f7e77d8c8caf
content = [
{
"name": "My Container",
"type": "CONTAINER",
"containerType": {
"containerName": "SPINEPUCK",
"capacity": 10,
},
"content": [
{
"type": "TOOL",
"name": "A tool within a container",
},
],
},
]
parcel = {
"name": "Parcel created by investigation user",
"description": "This parcel has been automatically generated by the unit tests",
"shipmentId" : shipmentId,
"comment": "This is the comment",
"storageConditions": "Fridge",
"content": [
{
"name": "My Container",
"type": "CONTAINER",
"containerType": {
"containerName": "SPINEPUCK",
"capacity": 10,
},
"content": [
{
"type": "TOOL",
"name": "A tool within a container",
},
],
},
]
}
parcelResponse = requests.put(f'{url_parcel}', json=(parcel))
print(parcelResponse)
<Response [200]>
print(requests.get(f'{url_parcel}').text)
[{"type":"DEFAULT","localContactNames":[],"items":[],"_id":"649168062e95f7e77d8c8cb4","name":"Parcel created by investigation user","description":"This parcel has been automatically generated by the unit tests","shipmentId":"649168062e95f7e77d8c8caf","storageConditions":"Fridge","content":[{"content":[{"type":"TOOL","name":"A tool within a container"}],"experimentPlan":[],"processingPlan":[],"_id":"649168062e95f7e77d8c8cb5","name":"My Container","type":"CONTAINER","containerType":{"_id":"649168062e95f7e77d8c8cb6","containerName":"SPINEPUCK","capacity":10,"id":"649168062e95f7e77d8c8cb6"},"createdAt":"2023-06-20T08:49:10.235Z","updatedAt":"2023-06-20T08:49:10.235Z","id":"649168062e95f7e77d8c8cb5"}],"investigationId":124564607,"statuses":[{"status":"CREATED","_id":"649168062e95f7e77d8c8cb7","createdBy":"admin","createdAt":"2023-06-20T08:49:10.235Z","updatedAt":"2023-06-20T08:49:10.235Z","createdByFullName":"adminFullName","id":"649168062e95f7e77d8c8cb7"},{"status":"SCHEDULED","_id":"649168062e95f7e77d8c8cb8","createdBy":"admin","createdAt":"2023-06-20T08:49:10.235Z","updatedAt":"2023-06-20T08:49:10.235Z","createdByFullName":"adminFullName","id":"649168062e95f7e77d8c8cb8"}],"currentStatus":"SCHEDULED","investigationName":"ID002306","createdAt":"2023-06-20T08:49:10.235Z","updatedAt":"2023-06-20T08:49:10.235Z","__v":0,"status":"SCHEDULED","investigation":{"name":"ID002306","startDate":"2023-06-19T13:28:44.492+02:00","id":124564607,"title":"ID002306","visitId":"id00","parameters":{"__datasetCount":"6","__sampleCount":"2","__fileCount":"0","__volume":"0","__elapsedTime":"0","__acquisitionDatasetCount":"4","__processedDatasetCount":"2","__acquisitionFileCount":"0","__processedFileCount":"0","__acquisitionVolume":"0","__processedVolume":"0"},"instrument":{"name":"ID00","id":92177647},"investigationUsers":[],"meta":{"page":{"totalWithoutFilters":1650,"total":1650,"totalPages":1,"currentPage":1}},"type":{"id":325,"createId":"root","createTime":"2014-06-18T15:00:43.500+02:00","modId":"root","modTime":"2014-06-18T15:00:43.500+02:00","description":"Test investigation","investigations":[],"name":"TEST"}},"localContactFullnames":[],"id":"649168062e95f7e77d8c8cb4","meta":{"page":{"total":1,"totalPages":1,"currentPage":1}}}]
print(json.dumps(json.loads(parcelResponse.text)[0]["content"]))
[{"content": [{"type": "TOOL", "name": "A tool within a container"}], "experimentPlan": [], "processingPlan": [], "_id": "649168062e95f7e77d8c8cb5", "name": "My Container", "type": "CONTAINER", "containerType": {"_id": "649168062e95f7e77d8c8cb6", "containerName": "SPINEPUCK", "capacity": 10, "id": "649168062e95f7e77d8c8cb6"}, "createdAt": "2023-06-20T08:49:10.235Z", "updatedAt": "2023-06-20T08:49:10.235Z", "id": "649168062e95f7e77d8c8cb5"}]