Skip to content

Commit d8991e4

Browse files
committed
Merge branch 'fix/hide-eori' into fix/lims-1980/keycloak-fixes
2 parents f943c47 + d9ea46c commit d8991e4

File tree

18 files changed

+327
-24
lines changed

18 files changed

+327
-24
lines changed

CHANGELOG.rst

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,24 @@ All notable changes to this project will be documented in this file.
77
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
88
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
99

10+
+++++++++
11+
v0.18.0 (21/11/2025)
12+
+++++++++
13+
14+
**Added**
15+
16+
- Add sessions endpoint
17+
- Add endpoint to get shipments in a given proposal
18+
19+
+++++++++
20+
v0.17.0 (05/11/2025)
21+
+++++++++
22+
23+
**Added**
24+
25+
- Push manufacturer serial number to ISPyB
26+
- Include more information when pushing shipment to shipping service
27+
1028
+++++++++
1129
v0.16.1 (17/10/2025)
1230
+++++++++

src/scaup/auth/micro.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,9 @@ def proposal(
132132
proposalReference: str,
133133
token: HTTPAuthorizationCredentials = Depends(auth_scheme),
134134
):
135-
return _check_perms(proposalReference, "proposal", token.credentials)
135+
proposal_reference = parse_proposal(proposal_reference=proposalReference)
136+
_check_perms(proposalReference, "proposal", token.credentials)
137+
return proposal_reference
136138

137139
@staticmethod
138140
def session(

src/scaup/auth/template.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
class GenericPermissions(Protocol):
88
@staticmethod
99
def proposal(proposalReference: str):
10-
return proposalReference
10+
return parse_proposal(proposal_reference=proposalReference)
1111

1212
@staticmethod
1313
def session(proposalReference: str, visitNumber: int):

src/scaup/crud/proposals.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,13 @@ def get_shipments(token: str, proposal_reference: ProposalReference, limit: int,
3535
query = select(Shipment).filter(
3636
Shipment.proposalCode == proposal_reference.code,
3737
Shipment.proposalNumber == proposal_reference.number,
38-
Shipment.visitNumber == proposal_reference.visit_number,
3938
)
4039

40+
if proposal_reference.visit_number:
41+
query = query.filter(Shipment.visitNumber == proposal_reference.visit_number)
42+
else:
43+
query = query.order_by(Shipment.visitNumber.desc(), Shipment.creationDate.desc())
44+
4145
shipments: Paged[Shipment] = inner_db.paginate(query, limit, page, slow_count=False, scalar=False)
4246
shipments.items = update_shipment_statuses(shipments.items, token)
4347

src/scaup/crud/shipments.py

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ def _get_children(
167167
@assert_no_unassigned
168168
def build_shipment_request(shipmentId: int, token: str):
169169
shipment = _get_shipment_tree(shipmentId)
170+
proposal_reference = f"{shipment.proposalCode}{shipment.proposalNumber:06}"
170171

171172
packages: list[dict] = []
172173
for tlc in shipment.children:
@@ -192,16 +193,28 @@ def build_shipment_request(shipmentId: int, token: str):
192193

193194
# Dewar cases do NOT include the dewar, this merely adds them to the outermost package
194195
if tlc.type == "dewar":
196+
dewar_response = ExternalRequest.request(
197+
token=token,
198+
url=f"/proposals/{proposal_reference}/dewar-registry/{tlc.code}",
199+
)
200+
201+
if dewar_response.status_code != 200:
202+
app_logger.error(f"Error while getting dewar {tlc.code} from upstream: {dewar_response.text}")
203+
raise HTTPException(
204+
status_code=status.HTTP_424_FAILED_DEPENDENCY,
205+
detail="Invalid facility code provided",
206+
)
207+
208+
serial_number = dewar_response.json()["manufacturerSerialNumber"]
209+
195210
line_items.append(
196-
{
197-
"shippable_item_type": "CRYOGENIC_DRY_SHIPPER",
198-
"quantity": 1,
199-
}
211+
{"shippable_item_type": "CRYOGENIC_DRY_SHIPPER", "quantity": 1, "serial_number": serial_number}
200212
)
201213

202214
if tlc.type in TYPE_TO_SHIPPING_SERVICE_TYPE:
203215
packages.append(
204216
{
217+
"container_name": tlc.name,
205218
"line_items": line_items,
206219
"external_id": tlc.externalId,
207220
"shippable_item_type": TYPE_TO_SHIPPING_SERVICE_TYPE[tlc.type],
@@ -237,7 +250,8 @@ def build_shipment_request(shipmentId: int, token: str):
237250

238251
built_request_body = {
239252
# TODO: remove padding once shipping service removes regex check
240-
"proposal": f"{shipment.proposalCode}{shipment.proposalNumber:06}",
253+
"session_number": shipment.visitNumber,
254+
"proposal": proposal_reference,
241255
"external_id": shipment.externalId,
242256
"origin_url": f"{Config.frontend_url}/proposals/{shipment.proposalCode}{shipment.proposalNumber}/sessions/"
243257
+ f"{shipment.visitNumber}/shipments/{shipment.id}",

src/scaup/crud/top_level_containers.py

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,17 @@
2121
DEWAR_PREFIX = "DLS-BI-1"
2222

2323

24+
def _check_if_dls_code(code: str | None):
25+
"""Check if code is DLS barcode, or user provided serial number
26+
27+
Args:
28+
code: User-provided code
29+
30+
Returns:
31+
True if it is a DLS code, False otherwise"""
32+
return code is not None and code[:3] == "DLS"
33+
34+
2435
def _check_fields(
2536
params: TopLevelContainerIn | OptionalTopLevelContainer,
2637
token: str,
@@ -38,7 +49,6 @@ def _check_fields(
3849
if params.code is None:
3950
# Perform no facility code check if code is not present
4051
return
41-
4252
query = query.select_from(TopLevelContainer).filter(TopLevelContainer.id == item_id).join(Shipment)
4353

4454
proposal_reference = inner_db.session.scalar(query)
@@ -72,7 +82,7 @@ def create_top_level_container(shipmentId: int | None, params: TopLevelContainer
7282
).one()
7383
)
7484

75-
if params.code:
85+
if _check_if_dls_code(params.code):
7686
_check_fields(params, token, shipmentId)
7787
elif params.type == "dewar" and autocreate:
7888
# Automatically register dewar if no code is provided
@@ -102,7 +112,10 @@ def create_top_level_container(shipmentId: int | None, params: TopLevelContainer
102112
Config.ispyb_api.jwt,
103113
method="POST",
104114
url=f"/proposals/{proposal.reference}/dewar-registry",
105-
json={"facilityCode": new_code},
115+
json={
116+
"facilityCode": new_code,
117+
"manufacturerSerialNumber": (None if params.code.lower().strip() == "n/a" else params.code),
118+
},
106119
)
107120

108121
if ext_resp.status_code != 201:

src/scaup/main.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
internal,
1313
proposals,
1414
samples,
15+
sessions,
1516
shipments,
1617
top_level_containers,
1718
)
@@ -72,5 +73,6 @@ async def general_exception_handler(request: Request, exc: Exception):
7273
api.include_router(containers.router)
7374
api.include_router(top_level_containers.router)
7475
api.include_router(internal.router)
76+
api.include_router(sessions.router)
7577

7678
app.mount(os.getenv("MOUNT_POINT", "/api"), api)

src/scaup/models/sessions.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
from datetime import datetime
2+
from typing import Optional, Set
3+
4+
from pydantic import AliasChoices, Field
5+
6+
from ..utils.models import OrmBaseModel
7+
8+
9+
class SessionOut(OrmBaseModel):
10+
beamLineSetupId: int | None = None
11+
beamCalendarId: int | None = None
12+
startDate: datetime | None = None
13+
endDate: datetime | None = None
14+
beamLineName: str | None = Field(None, max_length=45)
15+
scheduled: int | None = Field(None, lt=10)
16+
nbShifts: int | None = Field(None, lt=1e9)
17+
comments: str | None = Field(None, max_length=2000)
18+
visit_number: int | None = Field(
19+
None,
20+
lt=1e9,
21+
serialization_alias="visitNumber",
22+
validation_alias=AliasChoices("visitNumber", "visit_number"),
23+
)
24+
usedFlag: int | None = Field(
25+
None,
26+
lt=2,
27+
description="Indicates if session has Datacollections or XFE or EnergyScans attached", # noqa: E501
28+
)
29+
lastUpdate: datetime | None = Field(
30+
None,
31+
description="Last update timestamp: by default the end of the session, the last collect", # noqa: E501
32+
)
33+
parentProposal: str | None = None
34+
proposalId: int = Field(..., lt=1e9, description="Proposal ID")
35+
sessionId: int = Field(..., lt=1e9, description="Session ID")
36+
beamLineOperator: Set[str] | None = None
37+
bltimeStamp: datetime
38+
purgedProcessedData: bool
39+
archived: int = Field(
40+
...,
41+
lt=2,
42+
description="The data for the session is archived and no longer available on disk", # noqa: E501
43+
)
44+
collectionGroups: Optional[int] = None

src/scaup/models/top_level_containers.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ class BaseTopLevelContainer(BaseModel):
2828

2929
class TopLevelContainerIn(BaseTopLevelContainer):
3030
type: str
31-
code: str | None = None
31+
code: str = "n/a"
3232
isInternal: bool = False
3333

3434

src/scaup/routes/proposals.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,16 @@ def get_shipment_data(
103103
return ExternalRequest.request(token=token.credentials, url=f"/proposals/{proposalReference}/data").json()
104104

105105

106+
@router.get("/{proposalReference}/shipments")
107+
def get_proposal_shipments(
108+
proposalReference: ProposalReference = Depends(Permissions.proposal),
109+
token: HTTPAuthorizationCredentials = Depends(auth_scheme),
110+
page: dict[str, int] = Depends(pagination),
111+
):
112+
"""Get shipments in proposal"""
113+
return crud.get_shipments(token=token.credentials, proposal_reference=proposalReference, **page)
114+
115+
106116
@router.post(
107117
"/{proposalReference}/sessions/{visitNumber}/assign-data-collection-groups",
108118
)

0 commit comments

Comments
 (0)