Toggle menu
Toggle preferences menu
Toggle personal menu
Not logged in
Your IP address will be publicly visible if you make any edits.

References/Facility

From OHC Network Wiki
Revision as of 04:15, 5 July 2026 by Admin (talk | contribs) (OHC identity seed)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
referencefacilityCARE 3.0+

A Facility is a physical or virtual care site — hospital, clinic, lab, telemedicine endpoint — and the root of a deployment's administrative hierarchy. You create one before any patient, organization, or device can attach to it.

A Facility spans two layers. The Django model is the storage layer, where columns like features and print_templates are opaque blobs. The API contract — enums, validation, JSON-field shapes, and the read/write schema split — lives in the Pydantic resource specs. When the two disagree (a stored integer vs. a wire label, an object key vs. a resolved URL), the spec wins on the wire.

Source:

Models

Model Purpose
Facility A care site and the root of a deployment's administrative org hierarchy
FacilityMonetoryConfig Per-facility billing config (one-to-one): discount codes, discount monetary components, discount configuration, invoice-number expression. Backs the discount/invoice fields of FacilityRetrieveSpec. See [[References/Facility Config

Facility extends BaseModel, not EMRBaseModel. It gets external_id, created_date/modified_date, and soft-delete via deleted, but none of the EMRBaseModel audit/history/meta machinery: it declares its own created_by FK and has no updated_by, history, or meta columns. FacilityMonetoryConfig does extend EMRBaseModel.

The choice sets and enums it uses are defined alongside the model — see Choices & enums.

Facility fields

The Type column is the Django storage type. Spec / Notes records where the API representation, validation, or bound enum from the Pydantic specs diverges from storage.

Identity & classification

Field Type Spec / Notes
name CharField(1000) Required (blank=False, null=False). Spec enforces case-insensitive uniqueness across all facilities (Lower(Trim(name))); on update the current row is excluded.
description TextField blank=True, null=False; defaults to empty string. Required (str) in FacilityBaseSpec.
facility_type IntegerField Required; choices from FACILITY_TYPES (see below). Wire format is the label string, not the integer: create validates the label against REVERSE_REVERSE_FACILITY_TYPES then maps to the int; read maps the int back to the label via REVERSE_FACILITY_TYPES.
features ArrayField[SmallIntegerField] Nullable; each element a FacilityFeature choice. Spec type list[int].
is_active BooleanField default=True. Server-managed; the specs don't expose it.
verified BooleanField default=False. Server-managed; the specs don't expose it.
is_public BooleanField default=False; controls public visibility. Exposed as bool on FacilityBaseSpec.

Location & contact

Field Type Spec / Notes
address TextField Free-text address. Required (str).
pincode IntegerField default=None, null=True on the model; required int in FacilityBaseSpec.
longitude DecimalField(22, 16) Nullable. Spec type Longitude
latitude DecimalField(22, 16) Nullable. Spec type Latitude
phone_number CharField(14) blank=True; validated with mobile_or_landline_number_validator. Spec type str.
middleware_address CharField(200) Nullable, default=None. Hostname of an external device/middleware integration. Spec type str
Field Type Spec / Notes
geo_organization FK → emr.Organization on_delete=SET_NULL, nullable. Geographic/administrative org placement. On write (FacilityCreateSpec): a required UUID4 (the org's external_id), resolved on deserialization to an Organization with org_type="govt". On read: a nested OrganizationReadSpec dict (empty {} when unset).
geo_organization_cache ArrayField[int] default=list. Denormalized cache of geo_organization's parent_cache chain plus its own id; rebuilt by sync_cache(). Not exposed by specs.
default_internal_organization FK → emr.FacilityOrganization on_delete=SET_NULL, nullable, related_name="default_facilities". The auto-created root Administration org. Not exposed by specs.
internal_organization_cache ArrayField[int] default=list. Denormalized cache of all FacilityOrganization ids (with parent chains) under this facility; rebuilt by sync_cache(). Not exposed by specs.

Both cache fields are platform-maintained denormalizations, rebuilt on every save() so org-scoped filtering avoids deep joins. Never write them directly. See Methods & save behaviour.

Media & presentation

Field Type Spec / Notes
cover_image_url CharField(500) Nullable, default=None. Stores an object key, not a URL. Read specs expose both the raw cover_image_url and a resolved read_cover_image_url (full URL via read_cover_image_url()).

{{Field|model=Facility|section=Media & presentation|name=print_templates|type=JSONField|notes=default=list. Opaque on the model; the real shape is list[PrintTemplate] (see [[#printtemplate-json-shape}}

Integration & audit

Field Type Spec / Notes
created_by FK → users.User on_delete=SET_NULL, nullable. Set to the facility administrator when the root org is provisioned. Read specs expose it as a nested UserSpec dict (cache-backed), None when unset.

Choices & enums

These choice sets live in the model module and are consumed by Facility and related code.

FacilityFeature (IntegerChoices)

Value Name Label
1 CT_SCAN_FACILITY CT Scan Facility
2 MATERNITY_CARE Maternity Care
3 X_RAY_FACILITY X-Ray Facility
4 NEONATAL_CARE Neonatal Care
5 OPERATION_THEATER Operation Theater
6 BLOOD_BANK Blood Bank

HubRelationship (IntegerChoices)

Value Name Label
1 REGULAR_HUB Regular Hub
2 TELE_ICU_HUB Tele ICU Hub

FACILITY_TYPES

A list of (int code, label). Codes are sparse and namespaced (8xx govt hospitals/health centres, 9xx labs/cooperatives, 10xx–16xx COVID-era centres, 3xxx/4xxx NGO/CBO). Commented-out legacy codes (8, 801, 820, 831, 850, 950, 1000) survive in source as historical mapping notes and are not valid. The API binds on the label, not the code.

Code Label Code Label
1 Educational Inst 870 Govt Medical College Hospitals
2 Private Hospital 900 Co-operative hospitals
3 Other 910 Autonomous healthcare facility
4 Hostel 1010 COVID-19 Domiciliary Care Center
5 Hotel 1100 First Line Treatment Centre
6 Lodge 1200 Second Line Treatment Center
7 TeleMedicine 1300 Shifting Centre
9 Govt Labs 1400 Covid Management Center
10 Private Labs 1500 Request Approving Center
800 Primary Health Centres 1510 Request Fulfilment Center
802 Family Health Centres 1600 District War Room
803 Community Health Centres 3000 Clinical Non Governmental Organization
830 Taluk Hospitals 3001 Non Clinical Non Governmental Organization
840 Women and Child Health Centres 4000 Community Based Organization
860 District Hospitals

REVERSE_FACILITY_TYPES (code → label) and REVERSE_REVERSE_FACILITY_TYPES (label → code) are derived from FACILITY_TYPES via reverse_choices. Create validates against the label set and stores the code; read maps the code back to the label.

DOCTOR_TYPES

A list of (int, label) covering 64 medical specialties (1 General Medicine, 2 Pulmonology, 8 Cardiologist, 48 Nurse, 64 Critical Care Physician, etc.). Defined in this module but not referenced by the Facility model or facility specs.

MonetaryComponentType (str enum, from monetary_component.py)

Used by the discount monetary components in FacilityMonetaryCodeSpec / FacilityRetrieveSpec.

Value
base
surcharge
discount
tax
informational

DiscountApplicability (str enum, from monetary_component.py)

Value
total_asc
total_desc

Nested JSON shapes

These Pydantic models define the real structure behind the model's JSON/array fields and the discount config.

PrintTemplate JSON shape

Element type of the print_templates field.

PrintTemplate {
  slug:        str (required)
  page:        PageConfig | null
  print_setup: PrintSetupConfig | null
  branding:    BrandingConfig | null
  watermark:   WatermarkConfig | null
}
PageConfig        { size: "A4"|"A5"|"Letter"|"Legal" | null,
                    orientation: "portrait"|"landscape" | null,
                    margin: PageMargin | null }
PageMargin        { top: float≥0, bottom: float≥0, left: float≥0, right: float≥0 }   # all required
PrintSetupConfig  { auto_print: bool | null }
BrandingConfig    { logo: LogoConfig | null, header_image: HeaderImageConfig | null,
                    footer_image: FooterImageConfig | null }
LogoConfig        { url: str (required), width: float | null, height: float | null,
                    alignment: "left"|"center"|"right" (required) }
HeaderImageConfig { url: str (required), height: float | null }
FooterImageConfig { url: str | null, height: float | null }
WatermarkConfig   { enabled: bool | null, text: str | null,
                    opacity: float | null (0…1), rotation: float | null }

Discount config shapes (FacilityMonetaryCodeSpec / FacilityMonetoryConfig)

discount_codes:                list[Coding]                     # see Coding below
discount_monetary_components:  list[MonetaryComponentDefinition]
discount_configuration:        DiscountConfiguration | null

Coding { system: str|null, version: str|null, code: str (required), display: str|null }   # extra="forbid"

MonetaryComponentDefinition (extends MonetaryComponent) {
  title:                   str (required)
  monetary_component_type: MonetaryComponentType   # base not allowed in a definition
  code:                    Coding | null
  factor:                  Decimal | null (max_digits=20, decimal_places=6)
  amount:                  Decimal | null (max_digits=20, decimal_places=6)
  tax_included_amount:     Decimal | null (base component only)
  global_component:        bool = false
  conditions:              list[EvaluatorConditionSpec] = []
}
EvaluatorConditionSpec { metric: str, operation: str, value: dict|str }   # metric validated against EvaluatorMetricsRegistry
DiscountConfiguration  { max_applicable: int≥0 (required), applicability_order: DiscountApplicability (required) }

PeriodSpec (base.py) is the shared period shape used across EMR resources. Facility doesn't use it directly; it's here for reference: { start: datetime|null, end: datetime|null }, both must be timezone-aware, and start ≤ end.

Resource specs (API schema)

Every spec subclasses EMRResource (base.py), which supplies serialize (DB object → Pydantic), de_serialize (Pydantic → DB object), and the perform_extra_serialization / perform_extra_deserialization hooks. __exclude__ lists fields skipped during (de)serialization; __store_metadata__ (default False) controls whether unknown fields land in the model's meta.

The hierarchy is FacilityBareMinimumSpec → FacilityBaseSpec → {FacilityCreateSpec, FacilityReadSpec → FacilityRetrieveSpec, FacilityMinimalReadSpec}. There is no separate UpdateSpec: FacilityCreateSpec handles both create and update, with its validators reading is_update/object from the serializer context.

Spec class Role Key fields / behaviour
FacilityBareMinimumSpec shared base (@cacheable, base manager) id: UUID4, name. __exclude__=["geo_organization"]. Cacheable, fetchable via model_from_cache.
FacilityBaseSpec shared base Adds description, longitude, latitude, pincode, address, phone_number, middleware_address, facility_type, is_public.
FacilityCreateSpec write · create & update Adds geo_organization: UUID4, features: list[int], print_templates: list[PrintTemplate] = []. Validates the facility_type label and case-insensitive name uniqueness. perform_extra_deserialization resolves geo_organization (must be org_type="govt") and maps the facility_type label → int.
FacilityReadSpec read · list null. perform_extra_serialization sets id=external_id, resolves the cover image URL, maps facility_type int → label, serializes geo_organization via OrganizationReadSpec, and resolves created_by via cached UserSpec.
FacilityRetrieveSpec read · detail Extends FacilityReadSpec + FacilityPermissionsMixin. Adds flags (from get_facility_flags()), facility + instance discount/tax/informational code lists, patient identifier configs, invoice_number_expression, and print_templates: list[dict]. The permissions mixin adds permissions, root_org_permissions, child_org_permissions. Discount/invoice fields come from FacilityMonetoryConfig.get_monetory_config(); instance-level lists come from Django settings.
FacilityMinimalReadSpec read · minimal FacilityBaseSpec + features, cover_image_url, read_cover_image_url, geo_organization: dict. Same serialization as FacilityReadSpec minus created_by.
FacilityMonetaryCodeSpec write · billing config Bound to FacilityMonetoryConfig. Validates ≤ 100 discount codes and ≤ 100 monetary components, forbids duplicate / system-redefining codes, and requires every monetary-component code to be a defined facility or system code.
FacilityInvoiceExpressionSpec write · invoice config invoice_number_expression: str, validated by evaluate_invoice_dummy_expression (raises "Invalid Expression").

Validation & server-side behaviour

  • name — unique case-insensitively (Lower(Trim(name))); on update the current object (from context) is excluded from the check.
  • facility_type — write accepts the label; an unknown label is rejected with the sorted valid-label list. Stored as the integer code; read maps it back to the label.
  • geo_organization — write is a UUID4 resolved to an Organization filtered by org_type="govt", falling to None if no match. Read embeds the full OrganizationReadSpec.
  • featureslist[int]; each int should correspond to a FacilityFeature value.
  • Bound value sets / coded fields — discount/tax/informational components use Coding (extra="forbid"); MonetaryComponentDefinition enforces no base type, the single-base rules inherited from MonetaryComponent, and amount/factor mutual exclusion.
  • cover_image_url — stores an object key; read_cover_image_url is the resolved URL, present only on read specs.
  • PermissionsFacilityRetrieveSpec computes them per requesting user from facility root and sub-org roles (FacilityAccess); can_update_facility is excluded from child_org_permissions.

Facility's relationships resolve through models in adjacent modules:

geo_organization               → FK emr.Organization (SET_NULL)        # write: UUID4 of a govt org
default_internal_organization  → FK emr.FacilityOrganization (SET_NULL) # auto-provisioned root org
created_by                     → FK users.User (SET_NULL)
FacilityMonetoryConfig         → OneToOne facility.Facility (CASCADE)   # billing/discount config

On creation, save() provisions a root FacilityOrganization named Administration (org_type="root", system_generated=True) and a FacilityOrganizationUser linking created_by to it with the FACILITY_ADMIN_ROLE. Feature flags live in FacilityFlag and surface via get_facility_flags().

Methods & save behaviour

Facility overrides save() and adds a few helpers.

Member Behaviour
save() On create only: persists the row, then creates the root Administration FacilityOrganization, sets it as default_internal_organization (an extra write), and creates a FacilityOrganizationUser granting created_by the FACILITY_ADMIN_ROLE. On every save: calls sync_cache().
sync_cache() Rebuilds geo_organization_cache (parent chain of geo_organization + its id) and internal_organization_cache (all FacilityOrganization parent chains + ids, de-duplicated), then persists only those two fields via update_fields.
read_cover_image_url() Resolves cover_image_url to a full URL via settings.FACILITY_CDN, else the S3 external endpoint/bucket; returns None when unset.
get_facility_flags() Delegates to FacilityFlag.get_all_flags(self.id) (cache-backed).
__str__() Returns name.

Creating a facility through the ORM costs three write passes: the initial insert, the default_internal_organization update, and the sync_cache() write of the two cache columns.

Deletes are soft (inherited BaseModel.delete() sets deleted=True); the row and its child organizations are retained.

API integration notes

  • external_id (UUID) is the public identifier, exposed as id by every read spec — the integer pk stays internal.
  • facility_type crosses the wire as the label string (e.g. "Private Hospital"), validated against REVERSE_REVERSE_FACILITY_TYPES; the integer code is storage-only.
  • features are integer FacilityFeature codes; map them to labels client-side.
  • geo_organization is written as the org's UUID (must be a govt org) and read as an embedded OrganizationReadSpec object.
  • print_templates follows the typed PrintTemplate shape on write and comes back as list[dict] on retrieve.
  • geo_organization_cache / internal_organization_cache are platform-maintained — never set them from clients; they rebuild on every save.
  • Creating a facility automatically provisions its root Administration organization and an admin membership for created_by; don't create these manually.
  • cover_image_url stores an object key; render read_cover_image_url instead.
  • Discount/tax/invoice billing config is managed through FacilityMonetaryCodeSpec / FacilityInvoiceExpressionSpec and surfaced on FacilityRetrieveSpec; it's backed by FacilityMonetoryConfig.
  • FacilityRetrieveSpec also returns the requesting user's permissions and feature flags; flags come via get_facility_flags() rather than a row-by-row query.