# Consignment receipts

Confirm each consignment a facility acknowledges in DHIS2 to the warehouse system of the central store.

This page concludes the [Supply chain](https://zato.io/docs/dev/healthcare/dhis2/supply-chain/index.html) series. When a consignment from the central store arrives at a facility, the storekeeper scans the consignment number on its packing list in the Consignment Receipt Acknowledgement program, which records the receipt as an event. The service below reads the receipts recorded since its previous run and confirms each one to the warehouse system, which then knows the consignment was delivered.

## The configuration {#the-configuration}

`consignments.ini` holds the program and the data element of the consignment number, the cache key under which the service keeps its place, and the time its first run starts reading from. `facilities.ini` is a [config table](https://zato.io/docs/dev/examples/config-tables.html) with the code the warehouse system knows each facility by:

```ini
# config/user-conf/consignments.ini

[receipts]
program = Lq8wZ3nVb6X
element_number = Gd2kP7sYt9R
marker_key = dhis2.supply.receipts.updated-after
start = 2026-10-01T00:00:00
```

```ini
# config/user-conf/facilities.ini

[DHIS2]
DiszpKrYNg8 = FAC-00412
ImspTQPwCqd = FAC-00418
```

## Read the receipts {#read-the-receipts}

The receipts are the program's events updated since the previous run, oldest first:

```python
# -*- coding: utf-8 -*-

# Zato
from zato.server.service import Service

class ConfirmReceipts(Service):
    name = 'dhis2.supply.confirm-receipts'

    def read_receipts(self, updated_after:'str') -> 'list':

        receipts = self.config.consignments.receipts
        fields = 'event,orgUnit,occurredAt,updatedAt,dataValues[dataElement,value]'

        params = {
            'program': receipts.program,
            'updatedAfter': updated_after,
            'order': 'updatedAt:asc',
            'paging': 'false',
            'fields': fields,
        }

        conn = self.rest['DHIS2 Events']
        response = conn.get(params=params)

        out = response.data['events']
        return out
```

## Confirm each one {#confirm-each-one}

A confirmation carries the consignment number, the facility under the warehouse system's code, and the date of receipt. Its payload follows the API of the warehouse system - the one below is an example:

```python
    def confirm(self, receipt:'dict') -> 'None':

        element_number = self.config.consignments.receipts.element_number
        uid = receipt['orgUnit']
        facility = self.config.facilities.translate(source='DHIS2', code=uid)

        # A facility the warehouse system has no code for is logged and left out ..
        if facility is None:
            self.logger.warning('No facility code for %s', uid)
            return

        # .. and every other receipt is confirmed with its consignment number.
        number = ''
        for data_value in receipt['dataValues']:
            if data_value['dataElement'] == element_number:
                number = data_value['value']

        confirmation = {
            'receipt': receipt['event'],
            'consignment': number,
            'facility': facility,
            'received_at': receipt['occurredAt'],
        }

        conn = self.rest['Central Store']
        conn.post(confirmation)
```

The UID of the event goes with each confirmation, so that the warehouse system recognises a receipt it has already confirmed.

## Keep the place {#keep-the-place}

The service keeps the update time of the newest receipt in the cache, as the [zoonotic notifications](https://zato.io/docs/dev/healthcare/dhis2/one-health/notifications.html#keep-the-place) service does:

```python
    def handle(self) -> 'None':

        receipts_config = self.config.consignments.receipts
        marker = self.cache.get(receipts_config.marker_key)

        # Start where the previous run ended ..
        if marker is None:
            updated_after = receipts_config.start
        else:
            updated_after = marker.decode('utf8')

        receipts = self.read_receipts(updated_after)

        # .. confirm each receipt, moving the place past it.
        for receipt in receipts:
            self.confirm(receipt)
            updated_at = receipt['updatedAt']
            self.cache.set(receipts_config.marker_key, updated_at)
```

The place moves after each receipt, so a run that stops halfway, for instance because the warehouse system is unavailable, resumes with the receipt it could not confirm.

## The schedule {#the-schedule}

The service runs from a [scheduler](https://zato.io/docs/dev/examples/scheduler.html) job with an interval of fifteen minutes:

![Consignment receipts job](https://zatosource-production.b-cdn.net/docs/gfx/dhis2/supply-receipts-job-create.webp?v=1791212087)

Dashboard menu: Scheduler > Config

## See also {#see-also}

- [Scheduler](https://zato.io/docs/dev/examples/scheduler.html) - Interval-based jobs
- [Config tables](https://zato.io/docs/dev/examples/config-tables.html) - Translate the codes of one party into another's

## Learn more {#learn-more}

- [Healthcare interface engine](https://zato.io/docs/dev/healthcare/) - Clinical messages, FHIR, conversion and operations
- [HL7 v2 parsing](https://zato.io/docs/dev/healthcare/hl7/v2/parsing/) - Messages as typed objects, with field access and validation
- [MLLP channels](https://zato.io/docs/dev/healthcare/hl7v2/mllp/) - Receiving and sending HL7 v2 over MLLP sockets
- [FHIR integrations](https://zato.io/docs/dev/healthcare/hl7/fhir/) - Read and write FHIR resources, with paths, bundles and extensions
- [HL7 v2 to FHIR](https://zato.io/docs/dev/healthcare/hl7/to-fhir/) - Converting v2 messages into FHIR bundles, codes and references included
- [EDIFACT](https://zato.io/docs/dev/healthcare/edifact/) - Parsing interchanges, dialects and the transports they arrive on
- [Transformation](https://zato.io/docs/dev/healthcare/transformation/) - One message in, another standard out, in ordinary Python
- [Audit log](https://zato.io/docs/dev/healthcare/audit-log.html) - Every message with its acknowledgment, searchable by patient identifier
- [AI in clinical interfaces](https://zato.io/docs/dev/healthcare/ai/) - Services calling LLMs and AI agents calling clinical services as tools
