Compliance - Validators

Location: api/nextango/apps/compliance/services/permit_validators.py, api/nextango/apps/compliance/cannabis/services/permit_validators.py, api/nextango/apps/compliance/cannabis/services/credential_validators.py Last Updated: 2026-07-06

Overview

Validators enforce the shape of Sanity-authored payloads before they are persisted. Two families exist:

  • Permit validators validate the payload attached to a storePermit entry on Store.regulatedCompliance.permits (mirrored to StoreComplianceProfile.permits).
  • Credential validators validate the payload attached to a credential entry in User.credentials.

Each validator is a plain function that accepts a payload dict and either raises ValueError with a message naming the offending field, or returns the normalised payload dict. Services look up validators by type string in the relevant VALIDATORS registry; unknown types are treated as errors at the caller layer.

The generic and cannabis-specific permit validator modules both define a VALIDATORS registry. A dispatcher in the generic module composes the two so callers have a single entrypoint.


Permit Validators (Generic)

Shared _require(payload, field) helper raises ValueError('Missing required field: <field>') if the key is absent or its value is an empty string (after stripping).

TypeValidatorReturned fields
certificate_of_operationvalidate_certificate_of_operationjurisdiction
local_permitvalidate_local_permitjurisdiction
tax_vendor_licensevalidate_tax_vendor_licensejurisdiction, accountNumber
excise_tax_registrationvalidate_excise_tax_registrationjurisdiction, accountNumber
insurancevalidate_insurancecarrier, policyNumber, optional coverageAmount (coerced via float(); raises if non-numeric)

All five are bundled into the module-level VALIDATORS dict.

validate_permit_payload(permit_type, payload)

Single dispatcher. Looks up permit_type in the generic VALIDATORS registry, then falls back to the cannabis registry (imported lazily to avoid circular import). Raises ValueError('Unknown permit type: ...') when neither registry recognises the type.


Permit Validators (Cannabis)

State-agnostic: enforces structural presence of fields (e.g. licenseClass, jurisdiction must be non-empty strings) without encoding any single jurisdiction's class-code taxonomy. Operators enter their regulator's class code verbatim.

TypeValidatorReturned fields
cannabis_retail_licensevalidate_cannabis_retail_licenselicenseClass, jurisdiction
metrc_registrationvalidate_metrc_registrationfacilityId

When a future engagement needs per-jurisdiction validation: add a sibling module under compliance/cannabis/states/<state>/permit_validators.py and compose it into the dispatcher. Do not overload the shared registry with a single jurisdiction's enum.


Credential Validators (Cannabis)

Called by RegulatedCustomerOnboardingService.create_with_credentials() through the VALIDATORS dict in compliance/cannabis/services/credential_validators.py. Unknown credential types are rejected by the service before reaching this module.

validate_government_id_verification(payload)

  • payload must be a dict.
  • Required keys: documentType, dateOfBirth (both truthy).
  • Returned payload keeps documentType, dateOfBirth, and passes through verifiedAt and verifiedByUserId if present.

validate_medical_marijuana_patient_card(payload)

  • payload must be a dict.
  • Required key: patientId (truthy).
  • Returned payload: patientId, programName (defaults to ''), caregiverAllowed (coerced via bool()).

Registry: VALIDATORS = {'government_id_verification': ..., 'medical_marijuana_patient_card': ...}.


Was this page helpful?