Product EngineeringFeaturesB2B CollectionBackend

Database schema

labFeatures.b2b_collection flag and trip_management tables for B2B Collection in crelio-app

πŸ‘€ Internal DocsπŸ“… Updated: Apr 7, 2026🏷️ feature

Database schema

B2B Collection touches two areas in crelio-app:

  1. Feature gate β€” labFeatures.b2b_collection (per lab) toggles the product in session / UI.
  2. Logistics data β€” admin.trip_management tables (Trip, stops, routes, samples) behind api-v3/trip-management/b2b-logistics/….

B2B logistics trips are rows in Trip with trip_type = 2 (B2B_TRIP) and the optional visit-link column home_collection_id IS NULL (B2BTrip / B2BTripManager in models/core/trip.py).


labFeatures β€” b2b_collection

Table: labFeatures
Model: admin.account.models.lab_features.LabFeatures
Meta: db_table = "labFeatures"

One row (conceptually) per lab via the lab foreign key. The B2B Collection product is enabled when this column is true for that lab’s features row.

ColumnTypeNotes
idPKAuto
labForIdFK β†’ account.LabsLab this feature row belongs to (labForId on model)
b2b_collectionbooleanTrue = B2B Collection enabled (Registration β†’ B2B Collection, session.b2b_collection)
(other columns)variousMany other lab flags on the same table; see lab_features.py for the full schema

Source: admin/account/models/lab_features.py (field b2b_collection).


Entity overview (trip management)


Trip

Table: Trip
Model: admin.trip_management.models.core.trip.Trip
Proxy (B2B): B2BTrip β€” same table; default Trip.objects manager is phlebotomist-only; use B2BTrip.objects or Trip.all_objects for B2B rows.

ColumnTypeNotes
idPKAuto
created_at, updated_atdatetimeAuto-maintained
phlebotomist_idFK β†’ account.LabUserPickup person (lab_user on model, db_column="phlebotomist_id")
device_idvarchar(100)Device identifier
lab_idFK β†’ account.LabsLab
home_collection_idFK nullable (patient app)NULL for B2B logistics (trip_type = 2); may be set for trip_type = 1 rows on the same table
total_distancefloat, nullableFilled when distance is calculated
start_point, end_pointtextCoordinates / serialized points
statusvarchar(20)NOT_STARTED, STARTED, ENDED, CANCELLED, PAUSED
scheduled_at, started_at, stopped_at, ended_at, cancelled_atdatetime, nullableLifecycle timestamps
reason, commenttext, nullable
is_distance_calculatedbooleanDefault false
namevarchar(50), nullableTrip name
trip_typesmallint1 = phlebotomist, 2 = B2B
cancelled_byint, nullableLabUser id who cancelled
schedule_groupvarchar(50), nullableRecurring / series grouping

Index: (lab_id, started_at, trip_type, status).


trip_location

Table: trip_location
Model: TripLocation

Stops on a trip (sequence, status, distances, notes).

ColumnTypeNotes
idPK
lab_idFK β†’ account.LabsPROTECT
trip_idFK β†’ TripPROTECT
location_idFK β†’ locationPROTECT
sequencesmallintStop order
end_point, start_pointvarchar(40)Coordinates
location_distanceintSegment distance (meters, default 0)
traveled_distanceintDefault 0
statussmallint1–6: NOT_STARTED, IN_PROGRESS, PAUSED, REACHED, COMPLETED, CANCELLED
started_at, ended_atbigint, nullableEpoch ms UTC
note, remark, commenttext

Index: (lab_id, trip_id, location_id, status).


trip_location_sample

Table: trip_location_sample
Model: TripLocationSample

Sample counts captured per stop (optional link to accession sample).

ColumnTypeNotes
idPK
lab_idFK β†’ account.LabsPROTECT
trip_location_idFK β†’ trip_locationPROTECT
sample_idFK β†’ accession.sample, nullableNull = β€œunknown” sample row
countint0 … 10_000 (check constraint)
created_at, updated_atbigintEpoch ms

Unique: (lab_id, trip_location_id, sample_id) (nullable sample_id handled per DB semantics).
Index: (lab_id, trip_location_id).


location

Table: location
Model: Location
UI term: Stop.

ColumnTypeNotes
idPK
organization_idFK β†’ organization.OrganizationPROTECT
created_by_idFK β†’ account.LabUserPROTECT
namevarchar(50)
coordinatesvarchar(40)
addressJSONe.g. { "full_address": "..." }
emailvarchar(50), nullable
country_codevarchar(5), nullable
contactvarchar(15), nullable
created_at, updated_atbigintEpoch ms
notevarchar(255), nullable
is_activebooleanDefault true

Index: (organization_id, name).


route

Table: route
Model: Route

ColumnTypeNotes
idPK
lab_idFK β†’ account.LabsPROTECT
created_by_idFK β†’ account.LabUserPROTECT
namevarchar(50)
distanceintTotal / aggregate distance (meters, default 0)
created_at, updated_atbigintEpoch ms
is_activebooleanDefault true

route_location

Table: route_location
Model: RouteLocation

Ordered stops belonging to a route template.

ColumnTypeNotes
idPK
route_idFK β†’ routePROTECT
location_idFK β†’ locationPROTECT
sequencesmallintOrder in route
distanceintMeters from previous stop to this one

Index: (route_id, location_id).


Source locations

ModelPath
LabFeaturesadmin/account/models/lab_features.py
Trip, B2BTripadmin/trip_management/models/core/trip.py
TripLocationadmin/trip_management/models/core/trip_location.py
TripLocationSampleadmin/trip_management/models/core/trip_location_sample.py
Locationadmin/trip_management/models/core/location.py
Routeadmin/trip_management/models/core/route.py
RouteLocationadmin/trip_management/models/core/route_location.py

On this page