Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
862aa11
feat(converter): refactor "versions" to "health_version_converters" a…
EliNoden May 18, 2026
741dbe8
feat(converter): add ConversionType enum
EliNoden May 18, 2026
f39fb5c
refactor(converter): change cisu_conversion_strategy to cisu_transcod…
EliNoden May 18, 2026
08b3065
refactor(converter): change health_conversion_strategy to health_vers…
EliNoden May 18, 2026
f2adf8a
feat(converter): new cisu_version_conversion_strategy
EliNoden May 18, 2026
ae78b9b
feat(converter): new type param validation
EliNoden May 18, 2026
be28711
test(converter): make conversion strategy based on payload type + tes…
EliNoden May 18, 2026
bdcb943
feat(converter): update MAINTAINED_CISU_VERSION to 'vactive'
EliNoden May 18, 2026
13cbbc6
test(converter): new tests covering MAINTAINED_HEALTH_CISU_VERSION co…
EliNoden May 19, 2026
1703da9
refactor(converter): update constants naming
EliNoden May 20, 2026
0323d56
feat(converter): use proper python enum casting
EliNoden May 20, 2026
2c0464a
refactor(converter): add pydantic payload validation
EliNoden May 20, 2026
4574842
refactor(converter): remove deprecated cisuConversion param
EliNoden May 20, 2026
22e42d2
tests(converter): add tests cover malformed queries
EliNoden May 20, 2026
3ef6cae
feat(converter): base_cisu_version_converter
EliNoden May 21, 2026
541756f
feat(converter): IdenticalCISUVersionConverter
EliNoden May 21, 2026
429b3b8
feat(converter): CreateCaseVersionConverter
EliNoden May 21, 2026
02fda7c
feat(converter): ResourcesInfoCISUVersionConverter
EliNoden May 21, 2026
9c49dfa
feat(converter): implement cisu_version_conversion_strategy
EliNoden May 21, 2026
1f142a3
tests(converter): test conversion v3 <-> vactive
EliNoden May 21, 2026
ed1cce2
tests(converter): test_resource_info_cisu_version_converter
EliNoden May 22, 2026
6fa34ff
tests(converter): test_create_case_version_converter
EliNoden May 22, 2026
c936d03
tests(converter): remove cisu_version_conversion_strategy not yet imp…
EliNoden May 21, 2026
b65189f
tests(converter): update TestCisuVersionConversionStrategy
EliNoden May 25, 2026
f8172e1
feat(converter): helper script
EliNoden May 22, 2026
f0e0cea
feat(converter): update README.md
EliNoden May 22, 2026
60f0365
feat(converter): set cisu expected model version as v3
EliNoden Jul 2, 2026
d6afa24
Merge pull request #429 from ansforge/feat/support-v3-and-vactive
EliNoden Jul 2, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions converter/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,3 +113,43 @@ curl -X POST http://localhost:8080/convert \
-H "Content-Type: application/json" \
-d "$(jq --argjson usecase "$(cat ../src/main/resources/sample/examples/RS-EDA/RS-EDA-SMUR_FemmeEnceinte_DelphineVigneau.01.json)" '.sourceVersion = "v3" | .targetVersion = "v3" | .cisuConversion = true | .edxl.content[0].jsonContent.embeddedJsonContent.message |= (. + $usecase)' tests/fixtures/EDXL/edxl_envelope_health_to_fire.json)"
```

### Helper script — `scripts/call_convert.sh`

Executable helper to call `/convert` quickly without building the payload by hand.

**Prerequisite**: local-dev setup running (see [launch local dev setup](https://github.com/ansforge/SAMU-Hub-Config/blob/main/tools/local-dev/README.md)).

Usage:

```bash
scripts/call_convert.sh <sourceVersion> <targetVersion> <type> <useCase> [options]
```

Positional args:
- `sourceVersion`, `targetVersion`: `v1` | `v2` | `v3` | `vactive`
- `type`: `HealthVersionConversion` | `CISUTranscoding` | `CISUVersionConversion` (see `ConversionType` in `converter/constants.py`)
- `useCase`: local path to a JSON file **or** `http(s)://` URL of the message payload

Options:
- `--envelope <path|url>`: EDXL envelope file or URL (default: `tests/fixtures/EDXL/edxl_envelope_health_to_health.json`)
- `--converter_url <url>`: converter base URL, `/convert` is appended (default: `http://localhost:8083`)
- `-h`, `--help`: show usage

Examples:

```bash
# Local fixture, default envelope (health-to-health)
scripts/call_convert.sh v3 v2 HealthVersionConversion tests/fixtures/RS-RI/RS-RI_V3.0_exhaustive_fill.json

# CISU transcoding with a custom envelope
scripts/call_convert.sh v3 vactive CISUTranscoding ./tests/fixtures/RC-EDA/RC-EDA_required_fields.json \
--envelope tests/fixtures/EDXL/edxl_envelope_fire_to_health.json

# Remote payload via URL
scripts/call_convert.sh v3 vactive CISUTranscoding https://raw.githubusercontent.com/org/repo/main/sample.json

# Override endpoint (e.g. staging)
scripts/call_convert.sh v3 vactive CISUTranscoding ./sample.json \
--converter_url https://staging.example.com
```
4 changes: 0 additions & 4 deletions converter/converter/cisu/constants.py

This file was deleted.

5 changes: 5 additions & 0 deletions converter/converter/cisu_transcoders/constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class CISUConstants:
TO_CISU = "to_CISU"
FROM_CISU = "from_CISU"
CISU_EXPECTED_MODEL_VERSION = "v3"
HEALTH_EXPECTED_VERSION_FOR_CISU_CONVERSION = "v3"
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,10 @@

from yaml import dump

from converter.cisu.create_case.create_case_cisu_constants import (
from converter.cisu_transcoders.create_case.create_case_cisu_constants import (
CreateCaseCISUConstants,
)

from converter.cisu.utils import add_to_initial_alert_notes
from converter.cisu_transcoders.utils import add_to_initial_alert_notes
from converter.constants import Constants
from pydantic import BaseModel, Field

Expand All @@ -23,7 +22,7 @@
translate_key_words,
set_value,
)
from converter.cisu.base_cisu_converter import BaseCISUConverter
from converter.cisu_transcoders.base_cisu_converter import BaseCISUConverter
import logging

logger = logging.getLogger(__name__)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from typing import Dict, Any

from converter.cisu.base_cisu_converter import BaseCISUConverter
from converter.cisu_transcoders.base_cisu_converter import BaseCISUConverter


class IdenticalCISUConverter(BaseCISUConverter):
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from converter.cisu.identical_cisu_converter import IdenticalCISUConverter
from converter.cisu_transcoders.identical_cisu_converter import IdenticalCISUConverter


class ReferenceConverter(IdenticalCISUConverter):
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import uuid

from converter.cisu.base_cisu_converter import BaseCISUConverter
from converter.cisu_transcoders.base_cisu_converter import BaseCISUConverter
from typing import Any, Dict, List, TypedDict

from converter.cisu.resources_info.resources_info_cisu_constants import (
from converter.cisu_transcoders.resources_info.resources_info_cisu_constants import (
ResourcesInfoCISUConstants,
)
from converter.cisu.resources_info.resources_info_cisu_helper import (
from converter.cisu_transcoders.resources_info.resources_info_cisu_helper import (
enrich_rs_ri_with_rs_srs,
get_latest_state,
log_cisu_to_rs_converted_messages_ids,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from converter.conversion_mixin import ConversionMixin
from converter.utils import get_field_value, set_value
from converter.cisu.resources_info.resources_info_cisu_constants import (
from converter.cisu_transcoders.resources_info.resources_info_cisu_constants import (
ResourcesInfoCISUConstants,
)
import logging
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
from converter.cisu.base_cisu_converter import BaseCISUConverter
from converter.cisu_transcoders.base_cisu_converter import BaseCISUConverter
from converter.repositories.message_repository import (
get_rs_messages_by_case_id,
)
from converter.cisu.resources_info.resources_info_cisu_helper import (
from converter.cisu_transcoders.resources_info.resources_info_cisu_helper import (
enrich_rs_ri_with_rs_srs,
)
from converter.cisu.resources_info.resources_info_cisu_converter import (
from converter.cisu_transcoders.resources_info.resources_info_cisu_converter import (
ResourcesInfoCISUConverter,
)
from converter.cisu.resources_info.resources_info_cisu_constants import (
from converter.cisu_transcoders.resources_info.resources_info_cisu_constants import (
ResourcesInfoCISUConstants,
)
from converter.cisu.resources_status.resources_status_constants import (
from converter.cisu_transcoders.resources_status.resources_status_constants import (
ResourcesStatusConstants,
)
from typing import Any, Dict
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
from typing import Any, Dict

from converter.conversion_mixin import ConversionMixin
from converter.cisu_transcoders.constants import CISUConstants


class BaseCISUVersionConverter(ConversionMixin):
def __init__(self):
raise ValueError(
"BaseCISUVersionConverter is an abstract class and cannot be instantiated directly. Use a subclass instead."
)

@classmethod
def convert_v3_to_vactive(cls, edxl_json: Dict[str, Any]) -> Dict[str, Any]:
raise NotImplementedError("convert_v3_to_vactive not implemented yet.")

@classmethod
def convert_vactive_to_v3(cls, edxl_json: Dict[str, Any]) -> Dict[str, Any]:
raise NotImplementedError("convert_vactive_to_v3 not implemented yet.")

@classmethod
def get_message_type(cls) -> str:
raise NotImplementedError(
"Subclasses must implement this method to return the message type in RS specifications."
)

@classmethod
def convert(
cls, source_version: str, target_version: str, edxl_json: Dict[str, Any]
):
if (
source_version == CISUConstants.CISU_EXPECTED_MODEL_VERSION
and target_version
== CISUConstants.HEALTH_EXPECTED_VERSION_FOR_CISU_CONVERSION
):
return cls.convert_vactive_to_v3(edxl_json)
elif (
source_version == CISUConstants.HEALTH_EXPECTED_VERSION_FOR_CISU_CONVERSION
and target_version == CISUConstants.CISU_EXPECTED_MODEL_VERSION
):
return cls.convert_v3_to_vactive(edxl_json)
else:
raise ValueError(
f"CISU version conversion from '{source_version}' to '{target_version}' for message type '{cls.get_message_type()}' is currently not implemented."
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from converter.cisu_version_converters.identical_cisu_version_converter import (
IdenticalCISUVersionConverter,
)


class CreateCaseVersionConverter(IdenticalCISUVersionConverter):
@classmethod
def get_message_type(cls) -> str:
return "createCase"
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from typing import Dict, Any

from converter.cisu_version_converters.base_cisu_version_converter import (
BaseCISUVersionConverter,
)


class IdenticalCISUVersionConverter(BaseCISUVersionConverter):
@classmethod
def convert_v3_to_vactive(cls, edxl_json) -> Dict[str, Any]:
return edxl_json

@classmethod
def convert_vactive_to_v3(cls, edxl_json: Dict[str, Any]) -> Dict[str, Any]:
return edxl_json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from converter.cisu_version_converters.identical_cisu_version_converter import (
IdenticalCISUVersionConverter,
)


class ResourcesInfoCISUVersionConverter(IdenticalCISUVersionConverter):
@classmethod
def get_message_type(cls) -> str:
return "resourcesInfoCisu"
9 changes: 9 additions & 0 deletions converter/converter/constants.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
from enum import Enum


class Constants:
FR_HEALTH_PREFIX = "fr.health"

Expand All @@ -17,3 +20,9 @@ class Constants:
}

MEDICAL_NOTE_RANDOM_ID_LENGTH = 7


class ConversionType(Enum):
CISUVersionConversion = "CISUVersionConversion"
HealthVersionConversion = "HealthVersionConversion"
CISUTranscoding = "CISUTranscoding"
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
import logging

from converter.cisu.create_case.create_case_cisu_converter import (
from converter.cisu_transcoders.create_case.create_case_cisu_converter import (
CreateCaseCISUConverter,
)
from converter.cisu.reference.reference_converter import ReferenceConverter
from converter.cisu.resources_info.resources_info_cisu_converter import (
from converter.cisu_transcoders.reference.reference_converter import ReferenceConverter
from converter.cisu_transcoders.resources_info.resources_info_cisu_converter import (
ResourcesInfoCISUConverter,
)
from converter.cisu.resources_status.resources_status_converter import (
from converter.cisu_transcoders.resources_status.resources_status_converter import (
ResourcesStatusConverter,
)
from converter.constants import Constants
from converter.cisu.constants import CISUConstants
from converter.conversion_strategy.health_conversion_strategy import (
health_conversion_strategy,
from converter.cisu_transcoders.constants import CISUConstants
from converter.conversion_strategy.health_version_conversion_strategy import (
health_version_conversion_strategy,
)
from converter.utils import (
get_recipient,
Expand All @@ -25,7 +25,7 @@
logger = logging.getLogger(__name__)


def cisu_conversion_strategy(edxl_json, source_version, target_version):
def cisu_transcoding_strategy(edxl_json, source_version, target_version):
logger.info(f"CISU Conversion initiated from {source_version} to {target_version}")

direction = compute_message_direction(edxl_json)
Expand All @@ -36,31 +36,35 @@ def cisu_conversion_strategy(edxl_json, source_version, target_version):
logger.info(
"Conversion RS -> CISU",
)
if target_version != CISUConstants.MAINTAINED_CISU_VERSION:
if target_version != CISUConstants.CISU_EXPECTED_MODEL_VERSION:
raise ValueError(
f"Unknown target version {target_version}. Must be: {CISUConstants.MAINTAINED_CISU_VERSION}"
f"Unknown target version {target_version}. Must be: {CISUConstants.CISU_EXPECTED_MODEL_VERSION}"
)

rs_json_message = health_conversion_strategy(
edxl_json, source_version, CISUConstants.MAINTAINED_CISU_VERSION
rs_json_message = health_version_conversion_strategy(
edxl_json,
source_version,
CISUConstants.HEALTH_EXPECTED_VERSION_FOR_CISU_CONVERSION,
)

return selected_strategy.from_rs_to_cisu(rs_json_message)
elif direction == CISUConstants.FROM_CISU:
logger.info(
"Conversion CISU -> RS",
)
if source_version != CISUConstants.MAINTAINED_CISU_VERSION:
if source_version != CISUConstants.CISU_EXPECTED_MODEL_VERSION:
raise ValueError(
f"Unknown source version {source_version}. Must be: {CISUConstants.MAINTAINED_CISU_VERSION}"
f"Unknown source version {source_version}. Must be: {CISUConstants.CISU_EXPECTED_MODEL_VERSION}"
)

rc_json_messages = selected_strategy.from_cisu_to_rs(edxl_json)
if not isinstance(rc_json_messages, list):
rc_json_messages = [rc_json_messages]
return [
health_conversion_strategy(
msg, CISUConstants.MAINTAINED_CISU_VERSION, target_version
health_version_conversion_strategy(
msg,
CISUConstants.HEALTH_EXPECTED_VERSION_FOR_CISU_CONVERSION,
target_version,
)
for msg in rc_json_messages
]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import logging
from converter.cisu_version_converters.create_case.rc_eda_version_converter import (
CreateCaseVersionConverter,
)
from converter.cisu_version_converters.resources_info_cisu.resources_info_cisu_version_converter import (
ResourcesInfoCISUVersionConverter,
)
from converter.utils import (
extract_message_type_from_message_content,
extract_message_content,
)
from converter.cisu_version_converters.identical_cisu_version_converter import (
IdenticalCISUVersionConverter,
)

logger = logging.getLogger(__name__)


def cisu_version_conversion_strategy(edxl_json, source_version, target_version):
logger.info(f"CISU Conversion initiated from {source_version} to {target_version}")

message_content = extract_message_content(edxl_json)
selected_strategy = select_conversion_strategy(message_content)

return selected_strategy.convert(source_version, target_version, edxl_json)


def select_conversion_strategy(message_content):
if "createCase" in message_content:
return CreateCaseVersionConverter
elif "resourcesInfoCisu" in message_content:
return ResourcesInfoCISUVersionConverter
elif "reference" in message_content:
return IdenticalCISUVersionConverter
elif "error" in message_content:
return IdenticalCISUVersionConverter
else:
deducted_message_type = extract_message_type_from_message_content(
message_content
)
raise ValueError(
f"CISU Version conversion for message type '{deducted_message_type}' is not implemented."
)
Loading
Loading