initial untested XML commit
This commit is contained in:
4
.gitignore
vendored
4
.gitignore
vendored
@@ -12,6 +12,4 @@
|
|||||||
# Built Visual Studio Code Extensions
|
# Built Visual Studio Code Extensions
|
||||||
*.vsix
|
*.vsix
|
||||||
|
|
||||||
iso*.csv
|
sources/**
|
||||||
domains_operations.txt
|
|
||||||
merge_providers.py
|
|
||||||
|
|||||||
22
README.md
22
README.md
@@ -63,17 +63,17 @@ The specification is expected to support provider capability discovery instead o
|
|||||||
|
|
||||||
## Supported providers
|
## Supported providers
|
||||||
|
|
||||||
| Provider | API key requested | API key received | API tested | Supported |
|
| Provider | XML | API key requested | API key received | API tested | Supported |
|
||||||
| :------------------------------------------------ | :---------------: | :--------------: | :--------: | :-------: |
|
| :------------------------------------------------ | :------: | :---------------: | :--------------: | :--------: | :-------: |
|
||||||
| Atmosfair Webservice 5 | ❌ | | | |
|
| Atmosfair Webservice 5 | ✅ | ❌ | ❌ | ❌ | ❌ |
|
||||||
| Google Travel Impact Model (various versions) | ❌ | | | |
|
| Google Travel Impact Model (various versions) | ✅ | ❌ | ❌ | ❌ | ❌ |
|
||||||
| myclimate Flight Calculator V1 & V2 | ❌ | | | |
|
| myclimate Flight Calculator V1 & V2 | ✅ | ❌ | ❌ | ❌ | ❌ |
|
||||||
| myclimate Bulk Flight Calculator | ❌ | | | |
|
| myclimate Bulk Flight Calculator | ✅ | ❌ | ❌ | ❌ | ❌ |
|
||||||
| GoClimate Flight Footprint | ❌ | | | |
|
| GoClimate Flight Footprint | ✅ | ✅ | ✅ | ✅ | ❌ |
|
||||||
| C-Level Carbon Balance API | ❌ | | | |
|
| C-Level Carbon Balance API | ✅ | ❌ | ❌ | ❌ | ❌ |
|
||||||
| KlimaLink API | ❌ | | | |
|
| KlimaLink API | ✅ | ❌ | ❌ | ❌ | ❌ |
|
||||||
| KlimAPI Calculation & Compensation API (v1 & v2) | ❌ | | | |
|
| KlimAPI Calculation & Compensation API (v1 & v2) | ✅ | ❌ | ❌ | ❌ | ❌ |
|
||||||
| calco2la.to | ✅ | ✅ | ✅ | ✅ |
|
| calco2la.to | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
|||||||
500
merge_providers.py
Normal file
500
merge_providers.py
Normal file
@@ -0,0 +1,500 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import copy
|
||||||
|
import sys
|
||||||
|
import xml.etree.ElementTree as ET
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Iterable
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class ProviderSource:
|
||||||
|
provider_id: str
|
||||||
|
expected_id: str
|
||||||
|
path: Path
|
||||||
|
element: ET.Element
|
||||||
|
|
||||||
|
|
||||||
|
def local_name(tag: str) -> str:
|
||||||
|
"""Return local XML tag name, ignoring namespace if present."""
|
||||||
|
if "}" in tag:
|
||||||
|
return tag.rsplit("}", 1)[1]
|
||||||
|
return tag
|
||||||
|
|
||||||
|
|
||||||
|
def indent_xml(element: ET.Element, level: int = 0) -> None:
|
||||||
|
indentation = "\n" + level * "\t"
|
||||||
|
child_indentation = "\n" + (level + 1) * "\t"
|
||||||
|
|
||||||
|
children = list(element)
|
||||||
|
|
||||||
|
if children:
|
||||||
|
if not element.text or not element.text.strip():
|
||||||
|
element.text = child_indentation
|
||||||
|
|
||||||
|
for child in children:
|
||||||
|
indent_xml(child, level + 1)
|
||||||
|
|
||||||
|
last_child = children[-1]
|
||||||
|
if not last_child.tail or not last_child.tail.strip():
|
||||||
|
last_child.tail = indentation
|
||||||
|
|
||||||
|
if level and (not element.tail or not element.tail.strip()):
|
||||||
|
element.tail = indentation
|
||||||
|
|
||||||
|
|
||||||
|
def parse_csv(value: str | None) -> set[str] | None:
|
||||||
|
if not value:
|
||||||
|
return None
|
||||||
|
|
||||||
|
result = {part.strip() for part in value.split(",") if part.strip()}
|
||||||
|
return result or None
|
||||||
|
|
||||||
|
|
||||||
|
def parse_provider_operations(values: list[str] | None) -> dict[str, set[str]]:
|
||||||
|
"""
|
||||||
|
Parse repeated provider-specific operation filters.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
--provider-operations atmosfair=flight,airports
|
||||||
|
--provider-operations myclimate=flight
|
||||||
|
"""
|
||||||
|
result: dict[str, set[str]] = {}
|
||||||
|
|
||||||
|
if not values:
|
||||||
|
return result
|
||||||
|
|
||||||
|
for value in values:
|
||||||
|
if "=" not in value:
|
||||||
|
raise ValueError(
|
||||||
|
f"Invalid provider operation filter '{value}'. "
|
||||||
|
"Expected format: provider_id=operation1,operation2"
|
||||||
|
)
|
||||||
|
|
||||||
|
provider_id, operations_raw = value.split("=", 1)
|
||||||
|
provider_id = provider_id.strip()
|
||||||
|
|
||||||
|
if not provider_id:
|
||||||
|
raise ValueError(f"Invalid provider operation filter '{value}': missing provider id.")
|
||||||
|
|
||||||
|
operations = parse_csv(operations_raw)
|
||||||
|
if not operations:
|
||||||
|
raise ValueError(f"Invalid provider operation filter '{value}': missing operations.")
|
||||||
|
|
||||||
|
result[provider_id] = operations
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def find_xml_files(input_dir: Path, output_file: Path | None = None) -> list[Path]:
|
||||||
|
files = sorted(input_dir.rglob("*.xml"))
|
||||||
|
|
||||||
|
if output_file:
|
||||||
|
output_file = output_file.resolve()
|
||||||
|
files = [path for path in files if path.resolve() != output_file]
|
||||||
|
|
||||||
|
return files
|
||||||
|
|
||||||
|
|
||||||
|
def expected_provider_id_for_file(input_dir: Path, path: Path) -> str:
|
||||||
|
"""
|
||||||
|
If file is directly in input dir:
|
||||||
|
providers/atmosfair.xml -> atmosfair
|
||||||
|
|
||||||
|
If file is in provider folder:
|
||||||
|
providers/atmosfair/provider.xml -> atmosfair
|
||||||
|
"""
|
||||||
|
relative = path.relative_to(input_dir)
|
||||||
|
|
||||||
|
if len(relative.parts) == 1:
|
||||||
|
return path.stem
|
||||||
|
|
||||||
|
return relative.parts[0]
|
||||||
|
|
||||||
|
|
||||||
|
def find_provider_nodes(root: ET.Element) -> list[ET.Element]:
|
||||||
|
if local_name(root.tag) == "provider":
|
||||||
|
return [root]
|
||||||
|
|
||||||
|
return [element for element in root.iter() if local_name(element.tag) == "provider"]
|
||||||
|
|
||||||
|
|
||||||
|
def provider_id(provider: ET.Element, fallback: str) -> str:
|
||||||
|
value = (
|
||||||
|
provider.attrib.get("id")
|
||||||
|
or provider.attrib.get("name")
|
||||||
|
or provider.attrib.get("provider")
|
||||||
|
or fallback
|
||||||
|
)
|
||||||
|
|
||||||
|
if "id" not in provider.attrib:
|
||||||
|
provider.attrib["id"] = value
|
||||||
|
|
||||||
|
return value
|
||||||
|
|
||||||
|
|
||||||
|
def read_providers(input_dir: Path, output_file: Path | None, strict_ids: bool) -> list[ProviderSource]:
|
||||||
|
providers: list[ProviderSource] = []
|
||||||
|
|
||||||
|
for path in find_xml_files(input_dir, output_file):
|
||||||
|
expected_id = expected_provider_id_for_file(input_dir, path)
|
||||||
|
|
||||||
|
try:
|
||||||
|
tree = ET.parse(path)
|
||||||
|
except ET.ParseError as exc:
|
||||||
|
raise RuntimeError(f"Could not parse XML file '{path}': {exc}") from exc
|
||||||
|
|
||||||
|
root = tree.getroot()
|
||||||
|
provider_nodes = find_provider_nodes(root)
|
||||||
|
|
||||||
|
if not provider_nodes:
|
||||||
|
print(f"Warning: no <provider> node found in {path}", file=sys.stderr)
|
||||||
|
continue
|
||||||
|
|
||||||
|
if len(provider_nodes) > 1:
|
||||||
|
print(
|
||||||
|
f"Warning: multiple <provider> nodes found in {path}; all will be considered.",
|
||||||
|
file=sys.stderr,
|
||||||
|
)
|
||||||
|
|
||||||
|
for provider_node in provider_nodes:
|
||||||
|
current_id = provider_id(provider_node, expected_id)
|
||||||
|
|
||||||
|
if strict_ids and current_id != expected_id:
|
||||||
|
raise RuntimeError(
|
||||||
|
f"Provider id mismatch in '{path}': "
|
||||||
|
f"expected '{expected_id}', found '{current_id}'."
|
||||||
|
)
|
||||||
|
|
||||||
|
if current_id != expected_id:
|
||||||
|
print(
|
||||||
|
f"Warning: provider id mismatch in '{path}': "
|
||||||
|
f"folder/file suggests '{expected_id}', XML says '{current_id}'.",
|
||||||
|
file=sys.stderr,
|
||||||
|
)
|
||||||
|
|
||||||
|
providers.append(
|
||||||
|
ProviderSource(
|
||||||
|
provider_id=current_id,
|
||||||
|
expected_id=expected_id,
|
||||||
|
path=path,
|
||||||
|
element=provider_node,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
return providers
|
||||||
|
|
||||||
|
|
||||||
|
def operation_id(operation: ET.Element) -> str | None:
|
||||||
|
return (
|
||||||
|
operation.attrib.get("id")
|
||||||
|
or operation.attrib.get("name")
|
||||||
|
or operation.attrib.get("operation")
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def find_operations_container(provider: ET.Element) -> ET.Element | None:
|
||||||
|
for child in provider:
|
||||||
|
if local_name(child.tag) == "operations":
|
||||||
|
return child
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def list_provider_operations(provider: ET.Element) -> list[str]:
|
||||||
|
operations_container = find_operations_container(provider)
|
||||||
|
|
||||||
|
if operations_container is None:
|
||||||
|
return []
|
||||||
|
|
||||||
|
operation_ids: list[str] = []
|
||||||
|
|
||||||
|
for child in operations_container:
|
||||||
|
if local_name(child.tag) != "operation":
|
||||||
|
continue
|
||||||
|
|
||||||
|
op_id = operation_id(child)
|
||||||
|
if op_id:
|
||||||
|
operation_ids.append(op_id)
|
||||||
|
|
||||||
|
return operation_ids
|
||||||
|
|
||||||
|
|
||||||
|
def filter_provider_operations(provider: ET.Element, allowed_operations: set[str] | None) -> ET.Element:
|
||||||
|
provider_copy = copy.deepcopy(provider)
|
||||||
|
|
||||||
|
if allowed_operations is None:
|
||||||
|
return provider_copy
|
||||||
|
|
||||||
|
operations_container = find_operations_container(provider_copy)
|
||||||
|
|
||||||
|
if operations_container is None:
|
||||||
|
return provider_copy
|
||||||
|
|
||||||
|
for child in list(operations_container):
|
||||||
|
if local_name(child.tag) != "operation":
|
||||||
|
continue
|
||||||
|
|
||||||
|
op_id = operation_id(child)
|
||||||
|
|
||||||
|
if op_id not in allowed_operations:
|
||||||
|
operations_container.remove(child)
|
||||||
|
|
||||||
|
return provider_copy
|
||||||
|
|
||||||
|
|
||||||
|
def ask_selection(
|
||||||
|
label: str,
|
||||||
|
options: list[str],
|
||||||
|
default_all: bool = True,
|
||||||
|
) -> set[str] | None:
|
||||||
|
if not options:
|
||||||
|
return set()
|
||||||
|
|
||||||
|
print()
|
||||||
|
print(label)
|
||||||
|
for index, option in enumerate(options, start=1):
|
||||||
|
print(f" {index}) {option}")
|
||||||
|
|
||||||
|
if default_all:
|
||||||
|
prompt = "Selection [Enter = all, comma-separated numbers or names]: "
|
||||||
|
else:
|
||||||
|
prompt = "Selection [Enter = none, comma-separated numbers or names]: "
|
||||||
|
|
||||||
|
raw = input(prompt).strip()
|
||||||
|
|
||||||
|
if not raw:
|
||||||
|
return None if default_all else set()
|
||||||
|
|
||||||
|
selected: set[str] = set()
|
||||||
|
|
||||||
|
for part in raw.split(","):
|
||||||
|
part = part.strip()
|
||||||
|
|
||||||
|
if part.isdigit():
|
||||||
|
index = int(part)
|
||||||
|
if index < 1 or index > len(options):
|
||||||
|
raise ValueError(f"Invalid selection number: {index}")
|
||||||
|
selected.add(options[index - 1])
|
||||||
|
else:
|
||||||
|
if part not in options:
|
||||||
|
raise ValueError(f"Invalid selection value: {part}")
|
||||||
|
selected.add(part)
|
||||||
|
|
||||||
|
return selected
|
||||||
|
|
||||||
|
|
||||||
|
def interactive_selection(
|
||||||
|
providers: list[ProviderSource],
|
||||||
|
) -> tuple[set[str] | None, set[str] | None, dict[str, set[str]]]:
|
||||||
|
provider_ids = sorted({provider.provider_id for provider in providers})
|
||||||
|
|
||||||
|
selected_providers = ask_selection(
|
||||||
|
"Available providers:",
|
||||||
|
provider_ids,
|
||||||
|
default_all=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
effective_providers = selected_providers or set(provider_ids)
|
||||||
|
|
||||||
|
all_operations = sorted(
|
||||||
|
{
|
||||||
|
operation
|
||||||
|
for provider in providers
|
||||||
|
if provider.provider_id in effective_providers
|
||||||
|
for operation in list_provider_operations(provider.element)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
global_operations = ask_selection(
|
||||||
|
"Available operations:",
|
||||||
|
all_operations,
|
||||||
|
default_all=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
provider_operations: dict[str, set[str]] = {}
|
||||||
|
|
||||||
|
print()
|
||||||
|
custom = input("Define provider-specific operation filters? [y/N]: ").strip().lower()
|
||||||
|
|
||||||
|
if custom in {"y", "yes"}:
|
||||||
|
for provider_id in sorted(effective_providers):
|
||||||
|
provider = next(p for p in providers if p.provider_id == provider_id)
|
||||||
|
ops = sorted(list_provider_operations(provider.element))
|
||||||
|
|
||||||
|
if not ops:
|
||||||
|
continue
|
||||||
|
|
||||||
|
selected_ops = ask_selection(
|
||||||
|
f"Operations for provider '{provider_id}':",
|
||||||
|
ops,
|
||||||
|
default_all=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
if selected_ops is not None:
|
||||||
|
provider_operations[provider_id] = selected_ops
|
||||||
|
|
||||||
|
return selected_providers, global_operations, provider_operations
|
||||||
|
|
||||||
|
|
||||||
|
def merge_providers(
|
||||||
|
providers: list[ProviderSource],
|
||||||
|
selected_providers: set[str] | None,
|
||||||
|
global_operations: set[str] | None,
|
||||||
|
provider_operations: dict[str, set[str]],
|
||||||
|
) -> ET.Element:
|
||||||
|
root = ET.Element("providers")
|
||||||
|
|
||||||
|
seen_provider_ids: set[str] = set()
|
||||||
|
|
||||||
|
for provider in providers:
|
||||||
|
if selected_providers is not None and provider.provider_id not in selected_providers:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if provider.provider_id in seen_provider_ids:
|
||||||
|
raise RuntimeError(
|
||||||
|
f"Duplicate provider id '{provider.provider_id}' after selection. "
|
||||||
|
"Provider ids must be unique in the merged output."
|
||||||
|
)
|
||||||
|
|
||||||
|
seen_provider_ids.add(provider.provider_id)
|
||||||
|
|
||||||
|
operations_for_provider = provider_operations.get(
|
||||||
|
provider.provider_id,
|
||||||
|
global_operations,
|
||||||
|
)
|
||||||
|
|
||||||
|
provider_element = filter_provider_operations(
|
||||||
|
provider.element,
|
||||||
|
operations_for_provider,
|
||||||
|
)
|
||||||
|
|
||||||
|
root.append(provider_element)
|
||||||
|
|
||||||
|
return root
|
||||||
|
|
||||||
|
|
||||||
|
def write_output(root: ET.Element, output_file: Path) -> None:
|
||||||
|
output_file.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
indent_xml(root)
|
||||||
|
|
||||||
|
ET.register_namespace("", "https://calco2la.to/schema/providers/v1")
|
||||||
|
tree = ET.ElementTree(root)
|
||||||
|
tree.write(
|
||||||
|
output_file,
|
||||||
|
encoding="utf-8",
|
||||||
|
xml_declaration=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def build_arg_parser() -> argparse.ArgumentParser:
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description="Merge single-provider XML descriptions into one provider.xml file."
|
||||||
|
)
|
||||||
|
|
||||||
|
parser.add_argument(
|
||||||
|
"input_dir",
|
||||||
|
type=Path,
|
||||||
|
help="Directory containing provider XML files or provider folders.",
|
||||||
|
)
|
||||||
|
|
||||||
|
parser.add_argument(
|
||||||
|
"-o",
|
||||||
|
"--output",
|
||||||
|
type=Path,
|
||||||
|
default=Path("provider.xml"),
|
||||||
|
help="Output file. Default: provider.xml",
|
||||||
|
)
|
||||||
|
|
||||||
|
parser.add_argument(
|
||||||
|
"--providers",
|
||||||
|
help="Comma-separated provider ids to merge. Default: all providers.",
|
||||||
|
)
|
||||||
|
|
||||||
|
parser.add_argument(
|
||||||
|
"--operations",
|
||||||
|
help="Comma-separated global operation ids to keep. Default: all operations.",
|
||||||
|
)
|
||||||
|
|
||||||
|
parser.add_argument(
|
||||||
|
"--provider-operations",
|
||||||
|
action="append",
|
||||||
|
help=(
|
||||||
|
"Provider-specific operation filter. "
|
||||||
|
"Format: provider_id=operation1,operation2. "
|
||||||
|
"Can be used multiple times."
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
parser.add_argument(
|
||||||
|
"-i",
|
||||||
|
"--interactive",
|
||||||
|
action="store_true",
|
||||||
|
help="Interactively select providers and operations.",
|
||||||
|
)
|
||||||
|
|
||||||
|
parser.add_argument(
|
||||||
|
"--strict-provider-id",
|
||||||
|
action="store_true",
|
||||||
|
help="Fail if folder/file name and XML provider id do not match.",
|
||||||
|
)
|
||||||
|
|
||||||
|
return parser
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
parser = build_arg_parser()
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
input_dir: Path = args.input_dir
|
||||||
|
output_file: Path = args.output
|
||||||
|
|
||||||
|
if not input_dir.exists():
|
||||||
|
print(f"Input directory does not exist: {input_dir}", file=sys.stderr)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
if not input_dir.is_dir():
|
||||||
|
print(f"Input path is not a directory: {input_dir}", file=sys.stderr)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
try:
|
||||||
|
providers = read_providers(
|
||||||
|
input_dir=input_dir,
|
||||||
|
output_file=output_file,
|
||||||
|
strict_ids=args.strict_provider_id,
|
||||||
|
)
|
||||||
|
|
||||||
|
if not providers:
|
||||||
|
print("No providers found.", file=sys.stderr)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
if args.interactive:
|
||||||
|
selected_providers, global_operations, provider_operations = interactive_selection(providers)
|
||||||
|
else:
|
||||||
|
selected_providers = parse_csv(args.providers)
|
||||||
|
global_operations = parse_csv(args.operations)
|
||||||
|
provider_operations = parse_provider_operations(args.provider_operations)
|
||||||
|
|
||||||
|
merged_root = merge_providers(
|
||||||
|
providers=providers,
|
||||||
|
selected_providers=selected_providers,
|
||||||
|
global_operations=global_operations,
|
||||||
|
provider_operations=provider_operations,
|
||||||
|
)
|
||||||
|
|
||||||
|
write_output(merged_root, output_file)
|
||||||
|
|
||||||
|
except Exception as exc:
|
||||||
|
print(f"Error: {exc}", file=sys.stderr)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
print(f"Created merged provider configuration: {output_file}")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(main())
|
||||||
68
providers/atmosfair/atmosfair.xml
Normal file
68
providers/atmosfair/atmosfair.xml
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<providers xmlns="https://calco2la.to/schema/providers/v1">
|
||||||
|
<provider id="atmosfair">
|
||||||
|
<name>Atmosfair Webservice 5</name>
|
||||||
|
<baseUrl>https://api.atmosfair.de</baseUrl>
|
||||||
|
<auth type="bodyCredentials"/>
|
||||||
|
<operations>
|
||||||
|
<operation id="travel.flight.estimate_emissions">
|
||||||
|
<http method="POST" path="/api/emission/flight"/>
|
||||||
|
<requestBody format="json">
|
||||||
|
{
|
||||||
|
"accountId": "${env.ATMOSFAIR_ACCOUNT_ID}",
|
||||||
|
"password": "${env.ATMOSFAIR_PASSWORD}",
|
||||||
|
"calculationMethod": "${request.calculation_method}",
|
||||||
|
"flights": [
|
||||||
|
#for leg in request.legs
|
||||||
|
{
|
||||||
|
"departure": "${leg.origin_iata}",
|
||||||
|
"arrival": "${leg.destination_iata}",
|
||||||
|
"flightNumber": "${leg.flight_number}",
|
||||||
|
"departureDate": "${leg.departure_date}",
|
||||||
|
"passengerCount": ${leg.passenger_count},
|
||||||
|
"flightCount": ${leg.flight_count},
|
||||||
|
"travelClass": "${leg.travel_class}",
|
||||||
|
"charter": ${leg.charter},
|
||||||
|
"aircraftType": "${leg.aircraft_type}"
|
||||||
|
}#sep,
|
||||||
|
#end
|
||||||
|
]
|
||||||
|
}
|
||||||
|
</requestBody>
|
||||||
|
<responseMapping mode="single" rootType="EmissionCalculationResult">
|
||||||
|
<constant target="EmissionCalculationResult.provider" value="atmosfair"/>
|
||||||
|
<constant target="EmissionCalculationResult.domain" value="travel.flight"/>
|
||||||
|
<field source="$.status" target="EmissionCalculationResult.status"/>
|
||||||
|
<field source="$.co2" target="EmissionCalculationResult.total.co2eKg"/>
|
||||||
|
<field source="$.co2WithoutRfi" target="EmissionCalculationResult.total.co2Kg"/>
|
||||||
|
<field source="$.offsetInEUR" target="EmissionCalculationResult.offset.amount"/>
|
||||||
|
<constant target="EmissionCalculationResult.offset.currency" value="EUR"/>
|
||||||
|
<field source="$.distance" target="EmissionCalculationResult.distance.value"/>
|
||||||
|
<constant target="EmissionCalculationResult.distance.unit" value="km"/>
|
||||||
|
<field source="$.fuelInLiter" target="EmissionCalculationResult.fuel.liters"/>
|
||||||
|
<field source="$.errors" target="EmissionCalculationResult.errors"/>
|
||||||
|
<field source="$" target="EmissionCalculationResult.vendorRaw"/>
|
||||||
|
<list source="$.flights[*]" target="EmissionCalculationResult.segments" itemType="SegmentEmissionResult">
|
||||||
|
<field source="$.departure" target="SegmentEmissionResult.origin.iata"/>
|
||||||
|
<field source="$.arrival" target="SegmentEmissionResult.destination.iata"/>
|
||||||
|
<field source="$.flightNumber" target="SegmentEmissionResult.flightNumber"/>
|
||||||
|
<field source="$.departureDate" target="SegmentEmissionResult.flightDate"/>
|
||||||
|
<field source="$.passengerCount" target="SegmentEmissionResult.passengerCount"/>
|
||||||
|
<field source="$.flightCount" target="SegmentEmissionResult.flightCount"/>
|
||||||
|
<field source="$.travelClass" target="SegmentEmissionResult.travelClass"/>
|
||||||
|
<field source="$.charter" target="SegmentEmissionResult.charter"/>
|
||||||
|
<field source="$.aircraftType" target="SegmentEmissionResult.aircraftType"/>
|
||||||
|
<field source="$.co2" target="SegmentEmissionResult.emissions.co2eKg"/>
|
||||||
|
<field source="$.co2WithoutRfi" target="SegmentEmissionResult.emissions.co2Kg"/>
|
||||||
|
<field source="$.distance" target="SegmentEmissionResult.distance.value"/>
|
||||||
|
<constant target="SegmentEmissionResult.distance.unit" value="km"/>
|
||||||
|
<field source="$.fuelInLiter" target="SegmentEmissionResult.fuel.liters"/>
|
||||||
|
<field source="$.cruiseAltitude" target="SegmentEmissionResult.cruiseAltitude"/>
|
||||||
|
<field source="$.distanceInCriticalAltitudes" target="SegmentEmissionResult.distanceInCriticalAltitudes"/>
|
||||||
|
<field source="$" target="SegmentEmissionResult.vendorRaw"/>
|
||||||
|
</list>
|
||||||
|
</responseMapping>
|
||||||
|
</operation>
|
||||||
|
</operations>
|
||||||
|
</provider>
|
||||||
|
</providers>
|
||||||
@@ -3,47 +3,72 @@
|
|||||||
<provider id="calco2lato">
|
<provider id="calco2lato">
|
||||||
<name>calco2la.to</name>
|
<name>calco2la.to</name>
|
||||||
<baseUrl>https://api.calco2la.to</baseUrl>
|
<baseUrl>https://api.calco2la.to</baseUrl>
|
||||||
|
|
||||||
<auth type="apiKey">
|
<auth type="apiKey">
|
||||||
<header>Authorization</header>
|
<header>Authorization</header>
|
||||||
<format>Bearer ${API_KEY}</format>
|
<format>Bearer ${API_KEY}</format>
|
||||||
|
<envKey>CALCO2LATO_API_KEY</envKey>
|
||||||
</auth>
|
</auth>
|
||||||
|
|
||||||
<operations>
|
<operations>
|
||||||
|
|
||||||
<!-- travel.flight.estimate_emissions -->
|
<!-- travel.flight.estimate_emissions -->
|
||||||
<operation id="travel.flight.estimate_emissions">
|
<operation id="travel.flight.estimate_emissions">
|
||||||
<http method="POST" path="/v1/flight/estimate" />
|
<http method="POST" path="/api/flight"/>
|
||||||
|
|
||||||
<!-- Template-based request body in provider's JSON shape -->
|
|
||||||
<requestBody format="json">
|
<requestBody format="json">
|
||||||
{
|
{
|
||||||
"legs": [
|
"api_key": "${env.CALCO2LATO_API_KEY}",
|
||||||
|
"departureDate": "${request.departure_date}",
|
||||||
|
"rfi": ${request.rfi},
|
||||||
|
"pricePerTon": ${request.price_per_ton},
|
||||||
|
"flights": [
|
||||||
#for leg in request.legs
|
#for leg in request.legs
|
||||||
{
|
{
|
||||||
"origin": "${leg.origin_iata}",
|
"departure": "${leg.origin_iata}",
|
||||||
"destination": "${leg.destination_iata}",
|
"arrival": "${leg.destination_iata}",
|
||||||
"departure_time": "${leg.departure_time}"
|
"passengerCount": ${leg.passenger_count},
|
||||||
|
"flightCount": ${leg.flight_count},
|
||||||
|
"travelClass": "${leg.travel_class}",
|
||||||
|
"charter": ${leg.charter},
|
||||||
|
"aircraftType": "${leg.aircraft_type}",
|
||||||
|
"departureDate": "${leg.departure_date}",
|
||||||
|
"calculationMethod": "${request.calculation_method}",
|
||||||
|
"via": ${leg.via},
|
||||||
|
"rfi": ${request.rfi},
|
||||||
|
"pricePerTon": ${request.price_per_ton}
|
||||||
}#sep,
|
}#sep,
|
||||||
#end
|
#end
|
||||||
],
|
]
|
||||||
"cabin_class": "${request.cabin_class}",
|
|
||||||
"passengers": ${request.passengers},
|
|
||||||
"include_non_co2": ${request.include_non_co2}
|
|
||||||
}
|
}
|
||||||
</requestBody>
|
</requestBody>
|
||||||
|
<responseMapping mode="single" rootType="EmissionCalculationResult">
|
||||||
<!-- How to interpret provider's JSON response -->
|
<constant target="EmissionCalculationResult.provider" value="calco2lato"/>
|
||||||
<responseMapping>
|
<constant target="EmissionCalculationResult.domain" value="travel.flight"/>
|
||||||
<map source="$.co2_kg" target="EmissionEstimate.co2_kg" />
|
<field source="$.status" target="EmissionCalculationResult.status"/>
|
||||||
<map source="$.co2e_kg" target="EmissionEstimate.co2e_kg" />
|
<field source="$.co2" target="EmissionCalculationResult.total.co2eKg"/>
|
||||||
<map source="$.non_co2_mult" target="EmissionEstimate.non_co2_multiplier" />
|
<field source="$.co2WithoutRfi" target="EmissionCalculationResult.total.co2Kg"/>
|
||||||
<map source="$.method.name" target="EmissionEstimate.method_name" />
|
<field source="$.rfi" target="EmissionCalculationResult.total.nonCo2Multiplier"/>
|
||||||
<map source="$.method.version" target="EmissionEstimate.method_version" />
|
<field source="$.offsetInEUR" target="EmissionCalculationResult.offset.amount"/>
|
||||||
<map source="$.standard" target="EmissionEstimate.standard" />
|
<constant target="EmissionCalculationResult.offset.currency" value="EUR"/>
|
||||||
<map source="$.documentation_url" target="EmissionEstimate.documentation_url" />
|
<field source="$.distance" target="EmissionCalculationResult.distance.value"/>
|
||||||
<!-- store full JSON -->
|
<constant target="EmissionCalculationResult.distance.unit" value="km"/>
|
||||||
<map source="$" target="EmissionEstimate.vendor_raw" />
|
<field source="$.fuelInLiter" target="EmissionCalculationResult.fuel.liters"/>
|
||||||
|
<field source="$.errors" target="EmissionCalculationResult.errors"/>
|
||||||
|
<field source="$" target="EmissionCalculationResult.vendorRaw"/>
|
||||||
|
<list source="$.flights[*]" target="EmissionCalculationResult.segments" itemType="SegmentEmissionResult">
|
||||||
|
<field source="$.departure.iata" target="SegmentEmissionResult.origin.iata"/>
|
||||||
|
<field source="$.arrival.iata" target="SegmentEmissionResult.destination.iata"/>
|
||||||
|
<field source="$.passengerCount" target="SegmentEmissionResult.passengerCount"/>
|
||||||
|
<field source="$.flightCount" target="SegmentEmissionResult.flightCount"/>
|
||||||
|
<field source="$.travelClass" target="SegmentEmissionResult.travelClass"/>
|
||||||
|
<field source="$.charter" target="SegmentEmissionResult.charter"/>
|
||||||
|
<field source="$.departureDate" target="SegmentEmissionResult.flightDate"/>
|
||||||
|
<field source="$.distance" target="SegmentEmissionResult.distance.value"/>
|
||||||
|
<constant target="SegmentEmissionResult.distance.unit" value="km"/>
|
||||||
|
<field source="$.co2" target="SegmentEmissionResult.emissions.co2eKg"/>
|
||||||
|
<field source="$.co2WithoutRfi" target="SegmentEmissionResult.emissions.co2Kg"/>
|
||||||
|
<field source="$.offsetInEUR" target="SegmentEmissionResult.offset.amount"/>
|
||||||
|
<constant target="SegmentEmissionResult.offset.currency" value="EUR"/>
|
||||||
|
<field source="$" target="SegmentEmissionResult.vendorRaw"/>
|
||||||
|
</list>
|
||||||
</responseMapping>
|
</responseMapping>
|
||||||
</operation>
|
</operation>
|
||||||
|
|
||||||
|
|||||||
36
providers/clevel/clevel.xml
Normal file
36
providers/clevel/clevel.xml
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<provider id="goclimate">
|
||||||
|
<name>GoClimate Flight Footprint</name>
|
||||||
|
<baseUrl>https://api.goclimate.com</baseUrl>
|
||||||
|
<auth type="basic">
|
||||||
|
<usernameIsApiKey>true</usernameIsApiKey>
|
||||||
|
<envKey>GOCLIMATE_API_KEY</envKey>
|
||||||
|
</auth>
|
||||||
|
<operations>
|
||||||
|
<operation id="travel.flight.estimate_emissions">
|
||||||
|
<http method="GET" path="/v1/flight_footprint"/>
|
||||||
|
<requestQuery>
|
||||||
|
#for leg in request.legs
|
||||||
|
<param name="segments[${index}][origin]" value="${leg.origin_iata}"/>
|
||||||
|
<param name="segments[${index}][destination]" value="${leg.destination_iata}"/>
|
||||||
|
#end
|
||||||
|
<param name="cabin_class" value="${request.cabin_class}"/>
|
||||||
|
#for currency in request.currencies
|
||||||
|
<param name="currencies[]" value="${currency}"/>
|
||||||
|
#end
|
||||||
|
</requestQuery>
|
||||||
|
<responseMapping mode="single" rootType="EmissionCalculationResult">
|
||||||
|
<constant target="EmissionCalculationResult.provider" value="goclimate"/>
|
||||||
|
<field source="$.footprint" target="EmissionCalculationResult.total.co2eKg"/>
|
||||||
|
<list source="$.offset_prices[*]" target="EmissionCalculationResult.prices" itemType="MoneyAmount">
|
||||||
|
<field source="$.amount" target="MoneyAmount.amountMinor"/>
|
||||||
|
<field source="$.currency" target="MoneyAmount.currency"/>
|
||||||
|
<field source="$.offset_url" target="MoneyAmount.url"/>
|
||||||
|
<field source="$.locale" target="MoneyAmount.locale"/>
|
||||||
|
</list>
|
||||||
|
<field source="$" target="EmissionCalculationResult.vendorRaw"/>
|
||||||
|
</responseMapping>
|
||||||
|
</operation>
|
||||||
|
</operations>
|
||||||
|
</provider>
|
||||||
|
</providers>
|
||||||
51
providers/goclimate/goclimate.xml
Normal file
51
providers/goclimate/goclimate.xml
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<provider id="clevel">
|
||||||
|
<name>C-Level Carbon Balance API</name>
|
||||||
|
<baseUrl>https://api.c-level.earth</baseUrl>
|
||||||
|
<auth type="apiKey">
|
||||||
|
<header>Authorization</header>
|
||||||
|
<format>Bearer ${API_KEY}</format>
|
||||||
|
<envKey>CLEVEL_API_KEY</envKey>
|
||||||
|
</auth>
|
||||||
|
<operations>
|
||||||
|
<operation id="travel.flight.estimate_emissions">
|
||||||
|
<http method="POST" path="/v1/calculate/flight"/>
|
||||||
|
<requestBody format="json">
|
||||||
|
{
|
||||||
|
"IataCodes":[
|
||||||
|
#for waypoint in request.iata_path
|
||||||
|
"${waypoint}"#sep,
|
||||||
|
#end
|
||||||
|
],
|
||||||
|
"IsReturn":${request.roundtrip},
|
||||||
|
"Passengers":${request.passengers},
|
||||||
|
"Class":"${request.vendor_options.clevel_class}",
|
||||||
|
"Type":"${request.vendor_options.clevel_type}",
|
||||||
|
"AircraftModel":"${request.vendor_options.aircraft_model}",
|
||||||
|
"Reference":"${request.reference}",
|
||||||
|
"CurrencyCode":"${request.currency}"
|
||||||
|
}
|
||||||
|
</requestBody>
|
||||||
|
<responseMapping mode="single" rootType="EmissionCalculationResult">
|
||||||
|
<constant target="EmissionCalculationResult.provider" value="clevel"/>
|
||||||
|
<field source="$.Co2Total_Kg" target="EmissionCalculationResult.total.co2eKg"/>
|
||||||
|
<field source="$.Co2Total_Tonne" target="EmissionCalculationResult.total.co2eTonnes"/>
|
||||||
|
<field source="$.Co2PerPerson_kg" target="EmissionCalculationResult.perPassenger.co2eKg"/>
|
||||||
|
<field source="$.Passengers" target="EmissionCalculationResult.passengerCount"/>
|
||||||
|
<field source="$.FlightClass" target="EmissionCalculationResult.travelClass"/>
|
||||||
|
<field source="$.TotalDistance_Km" target="EmissionCalculationResult.distance.value"/>
|
||||||
|
<constant target="EmissionCalculationResult.distance.unit" value="km"/>
|
||||||
|
<field source="$.TotalDistance_Miles" target="EmissionCalculationResult.distance.miles"/>
|
||||||
|
<field source="$.PerPersonPrice" target="EmissionCalculationResult.perPassengerPrice.amount"/>
|
||||||
|
<field source="$.TotalPrice" target="EmissionCalculationResult.offset.amount"/>
|
||||||
|
<field source="$.CurrencyCode" target="EmissionCalculationResult.offset.currency"/>
|
||||||
|
<field source="$.QuoteId" target="EmissionCalculationResult.quote.id"/>
|
||||||
|
<field source="$.QuoteExpiry" target="EmissionCalculationResult.quote.expiresAt"/>
|
||||||
|
<field source="$.ShortDescription" target="EmissionCalculationResult.description"/>
|
||||||
|
<field source="$.MetaData" target="EmissionCalculationResult.metadata"/>
|
||||||
|
<field source="$" target="EmissionCalculationResult.vendorRaw"/>
|
||||||
|
</responseMapping>
|
||||||
|
</operation>
|
||||||
|
</operations>
|
||||||
|
</provider>
|
||||||
|
</providers>
|
||||||
@@ -3,48 +3,52 @@
|
|||||||
<!-- Google TIM -->
|
<!-- Google TIM -->
|
||||||
<provider id="google_tim">
|
<provider id="google_tim">
|
||||||
<name>Google Travel Impact Model</name>
|
<name>Google Travel Impact Model</name>
|
||||||
<baseUrl>https://travelimpactmodel.googleapis.com/v1</baseUrl>
|
<baseUrl>https://travelimpactmodel.googleapis.com</baseUrl>
|
||||||
|
|
||||||
<auth type="apiKey">
|
<auth type="apiKey">
|
||||||
<header>X-Goog-Api-Key</header>
|
<header>X-Goog-Api-Key</header>
|
||||||
<format>${API_KEY}</format>
|
<format>${API_KEY}</format>
|
||||||
|
<envKey>GOOGLE_TIM_API_KEY</envKey>
|
||||||
</auth>
|
</auth>
|
||||||
|
|
||||||
<operations>
|
<operations>
|
||||||
|
|
||||||
<operation id="travel.flight.estimate_emissions">
|
<operation id="travel.flight.estimate_emissions">
|
||||||
<http method="POST" path="/flights:computeFlightEmissions" />
|
<http method="POST" path="/v1/flights:computeFlightEmissions"/>
|
||||||
|
|
||||||
<requestBody format="json">
|
<requestBody format="json">
|
||||||
{
|
{
|
||||||
"flightSegments": [
|
"flights": [
|
||||||
#for leg in request.legs
|
#for leg in request.legs
|
||||||
{
|
{
|
||||||
"departureAirport": { "code": "${leg.origin_iata}" },
|
"origin":"${leg.origin_iata}",
|
||||||
"arrivalAirport": { "code": "${leg.destination_iata}" }
|
"destination":"${leg.destination_iata}",
|
||||||
|
"operatingCarrierCode":"${leg.operating_carrier}",
|
||||||
|
"flightNumber":${leg.flight_number},
|
||||||
|
"departureDate":{
|
||||||
|
"year":${leg.departure_date.year},
|
||||||
|
"month":${leg.departure_date.month},
|
||||||
|
"day":${leg.departure_date.day}
|
||||||
|
}
|
||||||
}#sep,
|
}#sep,
|
||||||
#end
|
#end
|
||||||
],
|
]
|
||||||
"cabinClass": "${request.cabin_class}",
|
|
||||||
"passengerCount": ${request.passengers}
|
|
||||||
}
|
}
|
||||||
</requestBody>
|
</requestBody>
|
||||||
|
<responseMapping mode="single" rootType="EmissionCalculationResult">
|
||||||
<responseMapping>
|
<constant target="EmissionCalculationResult.provider" value="google_tim"/>
|
||||||
<map source="$.flightEmissions[0].co2Grams"
|
<field source="$.modelVersion.major" target="EmissionCalculationResult.methodology.methodVersion"/>
|
||||||
target="EmissionEstimate.co2_kg"
|
<list source="$.flightEmissions[*]" target="EmissionCalculationResult.segments" itemType="SegmentEmissionResult">
|
||||||
transform="divideBy1000" />
|
<field source="$.flight.origin" target="SegmentEmissionResult.origin.iata"/>
|
||||||
<map source="$.flightEmissions[0].co2eGrams"
|
<field source="$.flight.destination" target="SegmentEmissionResult.destination.iata"/>
|
||||||
target="EmissionEstimate.co2e_kg"
|
<field source="$.flight.operatingCarrierCode" target="SegmentEmissionResult.airline"/>
|
||||||
transform="divideBy1000" />
|
<field source="$.flight.flightNumber" target="SegmentEmissionResult.flightNumber"/>
|
||||||
<map source="$.modelVersion"
|
<field source="$.source" target="SegmentEmissionResult.source"/>
|
||||||
target="EmissionEstimate.method_version" />
|
<field source="$.emissionsGramsPerPax.economy" target="SegmentEmissionResult.classEmissions.economyKg" transform="divideBy1000"/>
|
||||||
<constant target="EmissionEstimate.method_name" value="Travel Impact Model" />
|
<field source="$.emissionsGramsPerPax.premiumEconomy" target="SegmentEmissionResult.classEmissions.premiumEconomyKg" transform="divideBy1000"/>
|
||||||
<constant target="EmissionEstimate.vendor" value="google_tim" />
|
<field source="$.emissionsGramsPerPax.business" target="SegmentEmissionResult.classEmissions.businessKg" transform="divideBy1000"/>
|
||||||
<map source="$" target="EmissionEstimate.vendor_raw" />
|
<field source="$.emissionsGramsPerPax.first" target="SegmentEmissionResult.classEmissions.firstKg" transform="divideBy1000"/>
|
||||||
|
<field source="$" target="SegmentEmissionResult.vendorRaw"/>
|
||||||
|
</list>
|
||||||
|
<field source="$" target="EmissionCalculationResult.vendorRaw"/>
|
||||||
</responseMapping>
|
</responseMapping>
|
||||||
</operation>
|
</operation>
|
||||||
|
|
||||||
</operations>
|
</operations>
|
||||||
</provider>
|
</provider>
|
||||||
</providers>
|
</providers>
|
||||||
|
|||||||
48
providers/klimalink/klimalink.xml
Normal file
48
providers/klimalink/klimalink.xml
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<provider id="klimalink">
|
||||||
|
<name>KlimaLink API</name>
|
||||||
|
<baseUrl>https://api.dev.klimalink.org</baseUrl>
|
||||||
|
<auth type="bearer">
|
||||||
|
<envKey>KLIMALINK_TOKEN</envKey>
|
||||||
|
</auth>
|
||||||
|
<operations>
|
||||||
|
<operation id="travel.flight.estimate_emissions">
|
||||||
|
<http method="POST" path="/api/v1/calculateEmission"/>
|
||||||
|
<requestBody format="json">
|
||||||
|
{
|
||||||
|
"flightActivities": [
|
||||||
|
#for leg in request.legs
|
||||||
|
{
|
||||||
|
"index":${index},
|
||||||
|
"departure":"${leg.origin_iata}",
|
||||||
|
"arrival":"${leg.destination_iata}",
|
||||||
|
"flightNumber":"${leg.flight_number}",
|
||||||
|
"flightDate":"${leg.departure_date}",
|
||||||
|
"aircraftType":"${leg.aircraft_type}",
|
||||||
|
"airline":"${leg.airline}",
|
||||||
|
"passengerCount":${leg.passenger_count},
|
||||||
|
"flightCount":${leg.flight_count},
|
||||||
|
"travelClass":"${leg.travel_class}"
|
||||||
|
}#sep,
|
||||||
|
#end
|
||||||
|
]
|
||||||
|
}
|
||||||
|
</requestBody>
|
||||||
|
<responseMapping mode="single" rootType="EmissionCalculationResult">
|
||||||
|
<constant target="EmissionCalculationResult.provider" value="klimalink"/>
|
||||||
|
<field source="$.status" target="EmissionCalculationResult.status"/>
|
||||||
|
<field source="$.emissionKgCO2eTotal" target="EmissionCalculationResult.total.co2eKg"/>
|
||||||
|
<list source="$.flightActivities[*]" target="EmissionCalculationResult.segments" itemType="SegmentEmissionResult">
|
||||||
|
<field source="$.index" target="SegmentEmissionResult.index"/>
|
||||||
|
<field source="$.type" target="SegmentEmissionResult.type"/>
|
||||||
|
<field source="$.status" target="SegmentEmissionResult.status"/>
|
||||||
|
<field source="$.emissionKgCO2e" target="SegmentEmissionResult.emissions.co2eKg"/>
|
||||||
|
<field source="$.errors" target="SegmentEmissionResult.errors"/>
|
||||||
|
<field source="$" target="SegmentEmissionResult.vendorRaw"/>
|
||||||
|
</list>
|
||||||
|
<field source="$" target="EmissionCalculationResult.vendorRaw"/>
|
||||||
|
</responseMapping>
|
||||||
|
</operation>
|
||||||
|
</operations>
|
||||||
|
</provider>
|
||||||
|
</providers>
|
||||||
147
providers/klimapi/klimapi_v1.xml
Normal file
147
providers/klimapi/klimapi_v1.xml
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<providers xmlns="https://calco2la.to/schema/providers/v1">
|
||||||
|
<provider id="klimapi_v1">
|
||||||
|
<name>KlimAPI v1</name>
|
||||||
|
<baseUrl>https://api.klimapi.com/v1</baseUrl>
|
||||||
|
<auth type="apiKey">
|
||||||
|
<header>X-API-KEY</header>
|
||||||
|
<format>${API_KEY}</format>
|
||||||
|
<envKey>KLIMAPI_V1_API_KEY</envKey>
|
||||||
|
</auth>
|
||||||
|
<operations>
|
||||||
|
<operation id="travel.flight.estimate_emissions">
|
||||||
|
<http method="POST" path="/calculate"/>
|
||||||
|
<requestBody format="json">
|
||||||
|
{
|
||||||
|
"calculation_options": [
|
||||||
|
#for leg in request.legs
|
||||||
|
{
|
||||||
|
"type": "flight",
|
||||||
|
"departure": "${leg.origin_iata}",
|
||||||
|
"destination": "${leg.destination_iata}",
|
||||||
|
"travel_class": "${leg.travel_class}",
|
||||||
|
"passengers": ${leg.passenger_count},
|
||||||
|
"return_trip": ${request.roundtrip}
|
||||||
|
}#sep,
|
||||||
|
#end
|
||||||
|
],
|
||||||
|
"fractional_digits": ${request.fractional_digits}
|
||||||
|
}
|
||||||
|
</requestBody>
|
||||||
|
<responseMapping mode="single" rootType="EmissionCalculationResult">
|
||||||
|
<constant target="EmissionCalculationResult.provider" value="klimapi_v1"/>
|
||||||
|
<constant target="EmissionCalculationResult.domain" value="travel.flight"/>
|
||||||
|
<constant target="EmissionCalculationResult.operation" value="travel.flight.estimate_emissions"/>
|
||||||
|
<field source="$.kg_amount" target="EmissionCalculationResult.total.co2eKg"/>
|
||||||
|
<constant target="EmissionCalculationResult.total.unit" value="kg"/>
|
||||||
|
<constant target="EmissionCalculationResult.total.per" value="request"/>
|
||||||
|
<field source="$.calculation_id" target="EmissionCalculationResult.quote.id"/>
|
||||||
|
<constant target="EmissionCalculationResult.methodology.vendor" value="KlimAPI"/>
|
||||||
|
<constant target="EmissionCalculationResult.methodology.methodName" value="KlimAPI v1 calculation_options"/>
|
||||||
|
<constant target="EmissionCalculationResult.methodology.documentationUrl" value="https://klimapi.com/resources/docs?version=v1"/>
|
||||||
|
<list source="$.results[*]" target="EmissionCalculationResult.segments" itemType="SegmentEmissionResult">
|
||||||
|
<field source="$.result" target="SegmentEmissionResult.emissions.co2eKg"/>
|
||||||
|
<field source="$.type" target="SegmentEmissionResult.type"/>
|
||||||
|
<field source="$.departure" target="SegmentEmissionResult.origin.iata"/>
|
||||||
|
<field source="$.destination" target="SegmentEmissionResult.destination.iata"/>
|
||||||
|
<field source="$.travel_class" target="SegmentEmissionResult.travelClass"/>
|
||||||
|
<field source="$.passengers" target="SegmentEmissionResult.passengerCount"/>
|
||||||
|
<field source="$.return_trip" target="SegmentEmissionResult.vendorRaw.returnTrip"/>
|
||||||
|
<field source="$" target="SegmentEmissionResult.vendorRaw"/>
|
||||||
|
</list>
|
||||||
|
<field source="$" target="EmissionCalculationResult.vendorRaw"/>
|
||||||
|
</responseMapping>
|
||||||
|
</operation>
|
||||||
|
<operation id="travel.flight.estimate_emissions.flight_number">
|
||||||
|
<http method="POST" path="/calculate"/>
|
||||||
|
<requestBody format="json">
|
||||||
|
{
|
||||||
|
"calculation_options": [
|
||||||
|
#for leg in request.legs
|
||||||
|
{
|
||||||
|
"type": "flight",
|
||||||
|
"carrier_code": "${leg.operating_carrier}",
|
||||||
|
"flight_number": ${leg.flight_number},
|
||||||
|
"departure_date": "${leg.departure_date}",
|
||||||
|
"departure": "${leg.origin_iata}",
|
||||||
|
"destination": "${leg.destination_iata}",
|
||||||
|
"travel_class": "${leg.travel_class}",
|
||||||
|
"passengers": ${leg.passenger_count}
|
||||||
|
}#sep,
|
||||||
|
#end
|
||||||
|
],
|
||||||
|
"fractional_digits": ${request.fractional_digits}
|
||||||
|
}
|
||||||
|
</requestBody>
|
||||||
|
<responseMapping mode="single" rootType="EmissionCalculationResult">
|
||||||
|
<constant target="EmissionCalculationResult.provider" value="klimapi_v1"/>
|
||||||
|
<constant target="EmissionCalculationResult.domain" value="travel.flight"/>
|
||||||
|
<constant target="EmissionCalculationResult.operation" value="travel.flight.estimate_emissions.flight_number"/>
|
||||||
|
<field source="$.kg_amount" target="EmissionCalculationResult.total.co2eKg"/>
|
||||||
|
<constant target="EmissionCalculationResult.total.unit" value="kg"/>
|
||||||
|
<constant target="EmissionCalculationResult.total.per" value="request"/>
|
||||||
|
<field source="$.calculation_id" target="EmissionCalculationResult.quote.id"/>
|
||||||
|
<constant target="EmissionCalculationResult.methodology.vendor" value="KlimAPI"/>
|
||||||
|
<constant target="EmissionCalculationResult.methodology.methodName" value="KlimAPI v1 flight-number calculation"/>
|
||||||
|
<constant target="EmissionCalculationResult.methodology.documentationUrl" value="https://klimapi.com/resources/docs?version=v1"/>
|
||||||
|
<list source="$.results[*]" target="EmissionCalculationResult.segments" itemType="SegmentEmissionResult">
|
||||||
|
<field source="$.result" target="SegmentEmissionResult.emissions.co2eKg"/>
|
||||||
|
<field source="$.type" target="SegmentEmissionResult.type"/>
|
||||||
|
<field source="$.carrier_code" target="SegmentEmissionResult.airline"/>
|
||||||
|
<field source="$.flight_number" target="SegmentEmissionResult.flightNumber"/>
|
||||||
|
<field source="$.departure_date" target="SegmentEmissionResult.flightDate"/>
|
||||||
|
<field source="$.departure" target="SegmentEmissionResult.origin.iata"/>
|
||||||
|
<field source="$.destination" target="SegmentEmissionResult.destination.iata"/>
|
||||||
|
<field source="$.travel_class" target="SegmentEmissionResult.travelClass"/>
|
||||||
|
<field source="$.passengers" target="SegmentEmissionResult.passengerCount"/>
|
||||||
|
<field source="$" target="SegmentEmissionResult.vendorRaw"/>
|
||||||
|
</list>
|
||||||
|
<field source="$" target="EmissionCalculationResult.vendorRaw"/>
|
||||||
|
</responseMapping>
|
||||||
|
</operation>
|
||||||
|
<operation id="travel.flight.estimate_emissions.distance">
|
||||||
|
<http method="POST" path="/calculate"/>
|
||||||
|
<requestBody format="json">
|
||||||
|
{
|
||||||
|
"calculation_options": [
|
||||||
|
#for leg in request.legs
|
||||||
|
{
|
||||||
|
"type": "flight",
|
||||||
|
"distance": ${leg.distance_km},
|
||||||
|
"unit": "kilometers",
|
||||||
|
"travel_class": "${leg.travel_class}",
|
||||||
|
"passengers": ${leg.passenger_count},
|
||||||
|
"return_trip": ${request.roundtrip}
|
||||||
|
}#sep,
|
||||||
|
#end
|
||||||
|
],
|
||||||
|
"fractional_digits": ${request.fractional_digits}
|
||||||
|
}
|
||||||
|
</requestBody>
|
||||||
|
<responseMapping mode="single" rootType="EmissionCalculationResult">
|
||||||
|
<constant target="EmissionCalculationResult.provider" value="klimapi_v1"/>
|
||||||
|
<constant target="EmissionCalculationResult.domain" value="travel.flight"/>
|
||||||
|
<constant target="EmissionCalculationResult.operation" value="travel.flight.estimate_emissions.distance"/>
|
||||||
|
<field source="$.kg_amount" target="EmissionCalculationResult.total.co2eKg"/>
|
||||||
|
<constant target="EmissionCalculationResult.total.unit" value="kg"/>
|
||||||
|
<constant target="EmissionCalculationResult.total.per" value="request"/>
|
||||||
|
<field source="$.calculation_id" target="EmissionCalculationResult.quote.id"/>
|
||||||
|
<constant target="EmissionCalculationResult.methodology.vendor" value="KlimAPI"/>
|
||||||
|
<constant target="EmissionCalculationResult.methodology.methodName" value="KlimAPI v1 distance calculation"/>
|
||||||
|
<constant target="EmissionCalculationResult.methodology.documentationUrl" value="https://klimapi.com/resources/docs?version=v1"/>
|
||||||
|
<list source="$.results[*]" target="EmissionCalculationResult.segments" itemType="SegmentEmissionResult">
|
||||||
|
<field source="$.result" target="SegmentEmissionResult.emissions.co2eKg"/>
|
||||||
|
<field source="$.type" target="SegmentEmissionResult.type"/>
|
||||||
|
<field source="$.distance" target="SegmentEmissionResult.distance.value"/>
|
||||||
|
<field source="$.unit" target="SegmentEmissionResult.distance.unit"/>
|
||||||
|
<field source="$.travel_class" target="SegmentEmissionResult.travelClass"/>
|
||||||
|
<field source="$.passengers" target="SegmentEmissionResult.passengerCount"/>
|
||||||
|
<field source="$.return_trip" target="SegmentEmissionResult.vendorRaw.returnTrip"/>
|
||||||
|
<field source="$" target="SegmentEmissionResult.vendorRaw"/>
|
||||||
|
</list>
|
||||||
|
<field source="$" target="EmissionCalculationResult.vendorRaw"/>
|
||||||
|
</responseMapping>
|
||||||
|
</operation>
|
||||||
|
</operations>
|
||||||
|
</provider>
|
||||||
|
</providers>
|
||||||
114
providers/klimapi/klimapi_v2.xml
Normal file
114
providers/klimapi/klimapi_v2.xml
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<providers xmlns="https://calco2la.to/schema/providers/v1">
|
||||||
|
<provider id="klimapi_v2">
|
||||||
|
<name>KlimAPI v2</name>
|
||||||
|
<baseUrl>https://api.klimapi.com/v2</baseUrl>
|
||||||
|
<auth type="apiKey">
|
||||||
|
<header>X-API-KEY</header>
|
||||||
|
<format>${API_KEY}</format>
|
||||||
|
<envKey>KLIMAPI_V2_API_KEY</envKey>
|
||||||
|
</auth>
|
||||||
|
<operations>
|
||||||
|
<operation id="travel.flight.estimate_emissions">
|
||||||
|
<http method="POST" path="/calculate"/>
|
||||||
|
<requestBody format="json">
|
||||||
|
{
|
||||||
|
"calculation_options": [
|
||||||
|
#for leg in request.legs
|
||||||
|
{
|
||||||
|
"type": "travel-air",
|
||||||
|
"activity": "flights",
|
||||||
|
"specification": "${request.vendor_options.klimapi_specification}",
|
||||||
|
"detail": "${request.vendor_options.klimapi_detail}",
|
||||||
|
"departure": "${leg.origin_iata}",
|
||||||
|
"destination": "${leg.destination_iata}",
|
||||||
|
"return_trip": ${request.roundtrip},
|
||||||
|
"passengers": ${leg.passenger_count}
|
||||||
|
}#sep,
|
||||||
|
#end
|
||||||
|
],
|
||||||
|
"fractional_digits": ${request.fractional_digits}
|
||||||
|
}
|
||||||
|
</requestBody>
|
||||||
|
<responseMapping mode="single" rootType="EmissionCalculationResult">
|
||||||
|
<constant target="EmissionCalculationResult.provider" value="klimapi_v2"/>
|
||||||
|
<constant target="EmissionCalculationResult.domain" value="travel.flight"/>
|
||||||
|
<constant target="EmissionCalculationResult.operation" value="travel.flight.estimate_emissions"/>
|
||||||
|
|
||||||
|
<field source="$.kgCO2e" target="EmissionCalculationResult.total.co2eKg"/>
|
||||||
|
<constant target="EmissionCalculationResult.total.unit" value="kg"/>
|
||||||
|
<constant target="EmissionCalculationResult.total.per" value="request"/>
|
||||||
|
<field source="$.calculation_id" target="EmissionCalculationResult.quote.id"/>
|
||||||
|
|
||||||
|
<constant target="EmissionCalculationResult.methodology.vendor" value="KlimAPI"/>
|
||||||
|
<constant target="EmissionCalculationResult.methodology.methodName" value="KlimAPI v2 calculation_options"/>
|
||||||
|
<constant target="EmissionCalculationResult.methodology.documentationUrl" value="https://klimapi.com/resources/docs"/>
|
||||||
|
|
||||||
|
<list source="$.results[*]" target="EmissionCalculationResult.segments" itemType="SegmentEmissionResult">
|
||||||
|
<field source="$.type" target="SegmentEmissionResult.type"/>
|
||||||
|
<field source="$.activity" target="SegmentEmissionResult.vendorRaw.activity"/>
|
||||||
|
<field source="$.specification" target="SegmentEmissionResult.vendorRaw.specification"/>
|
||||||
|
<field source="$.detail" target="SegmentEmissionResult.travelClass"/>
|
||||||
|
<field source="$.value" target="SegmentEmissionResult.distance.value"/>
|
||||||
|
<field source="$.unit" target="SegmentEmissionResult.distance.unit"/>
|
||||||
|
<field source="$.kgCO2e" target="SegmentEmissionResult.emissions.co2eKg"/>
|
||||||
|
<field source="$.emission_factor_id" target="SegmentEmissionResult.vendorRaw.emissionFactorId"/>
|
||||||
|
<field source="$.emission_factor_last_updated" target="SegmentEmissionResult.vendorRaw.emissionFactorLastUpdated"/>
|
||||||
|
<field source="$" target="SegmentEmissionResult.vendorRaw"/>
|
||||||
|
</list>
|
||||||
|
|
||||||
|
<field source="$" target="EmissionCalculationResult.vendorRaw"/>
|
||||||
|
</responseMapping>
|
||||||
|
</operation>
|
||||||
|
<operation id="travel.flight.estimate_emissions.distance">
|
||||||
|
<http method="POST" path="/calculate"/>
|
||||||
|
<requestBody format="json">
|
||||||
|
{
|
||||||
|
"calculation_options": [
|
||||||
|
#for leg in request.legs
|
||||||
|
{
|
||||||
|
"type": "travel-air",
|
||||||
|
"activity": "flights",
|
||||||
|
"specification": "${request.vendor_options.klimapi_specification}",
|
||||||
|
"detail": "${request.vendor_options.klimapi_detail}",
|
||||||
|
"value": ${leg.vendor_options.klimapi_passenger_distance},
|
||||||
|
"unit": "${request.vendor_options.klimapi_unit}"
|
||||||
|
}#sep,
|
||||||
|
#end
|
||||||
|
],
|
||||||
|
"fractional_digits": ${request.fractional_digits}
|
||||||
|
}
|
||||||
|
</requestBody>
|
||||||
|
<responseMapping mode="single" rootType="EmissionCalculationResult">
|
||||||
|
<constant target="EmissionCalculationResult.provider" value="klimapi_v2"/>
|
||||||
|
<constant target="EmissionCalculationResult.domain" value="travel.flight"/>
|
||||||
|
<constant target="EmissionCalculationResult.operation" value="travel.flight.estimate_emissions.distance"/>
|
||||||
|
|
||||||
|
<field source="$.kgCO2e" target="EmissionCalculationResult.total.co2eKg"/>
|
||||||
|
<constant target="EmissionCalculationResult.total.unit" value="kg"/>
|
||||||
|
<constant target="EmissionCalculationResult.total.per" value="request"/>
|
||||||
|
<field source="$.calculation_id" target="EmissionCalculationResult.quote.id"/>
|
||||||
|
|
||||||
|
<constant target="EmissionCalculationResult.methodology.vendor" value="KlimAPI"/>
|
||||||
|
<constant target="EmissionCalculationResult.methodology.methodName" value="KlimAPI v2 passenger-distance calculation"/>
|
||||||
|
<constant target="EmissionCalculationResult.methodology.documentationUrl" value="https://klimapi.com/resources/docs"/>
|
||||||
|
|
||||||
|
<list source="$.results[*]" target="EmissionCalculationResult.segments" itemType="SegmentEmissionResult">
|
||||||
|
<field source="$.type" target="SegmentEmissionResult.type"/>
|
||||||
|
<field source="$.activity" target="SegmentEmissionResult.vendorRaw.activity"/>
|
||||||
|
<field source="$.specification" target="SegmentEmissionResult.vendorRaw.specification"/>
|
||||||
|
<field source="$.detail" target="SegmentEmissionResult.travelClass"/>
|
||||||
|
<field source="$.value" target="SegmentEmissionResult.distance.value"/>
|
||||||
|
<field source="$.unit" target="SegmentEmissionResult.distance.unit"/>
|
||||||
|
<field source="$.kgCO2e" target="SegmentEmissionResult.emissions.co2eKg"/>
|
||||||
|
<field source="$.emission_factor_id" target="SegmentEmissionResult.vendorRaw.emissionFactorId"/>
|
||||||
|
<field source="$.emission_factor_last_updated" target="SegmentEmissionResult.vendorRaw.emissionFactorLastUpdated"/>
|
||||||
|
<field source="$" target="SegmentEmissionResult.vendorRaw"/>
|
||||||
|
</list>
|
||||||
|
<field source="$" target="EmissionCalculationResult.vendorRaw"/>
|
||||||
|
</responseMapping>
|
||||||
|
</operation>
|
||||||
|
</operations>
|
||||||
|
</provider>
|
||||||
|
|
||||||
|
</providers>
|
||||||
45
providers/myclimate/myclimate_bulk.xml
Normal file
45
providers/myclimate/myclimate_bulk.xml
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<providers xmlns="https://calco2la.to/schema/providers/v1">
|
||||||
|
<provider id="myclimate_bulk">
|
||||||
|
<name>myclimate Bulk Flight Calculator</name>
|
||||||
|
<baseUrl>https://api.myclimate.org</baseUrl>
|
||||||
|
<auth type="basic">
|
||||||
|
<usernameEnvKey>MYCLIMATE_USERNAME</usernameEnvKey>
|
||||||
|
<passwordEnvKey>MYCLIMATE_PASSWORD</passwordEnvKey>
|
||||||
|
</auth>
|
||||||
|
<operations>
|
||||||
|
<operation id="travel.flight.estimate_emissions">
|
||||||
|
<http method="POST" path="/v1/bulk_flight_calculators.json"/>
|
||||||
|
<requestBody format="json">
|
||||||
|
{
|
||||||
|
"flights": [
|
||||||
|
#for leg in request.legs
|
||||||
|
{
|
||||||
|
"id":"${leg.id}",
|
||||||
|
"from":"${leg.origin_iata}",
|
||||||
|
"to":"${leg.destination_iata}",
|
||||||
|
"aircraft_type":"${leg.aircraft_type}",
|
||||||
|
"flight_class":"${leg.travel_class}"
|
||||||
|
}#sep,
|
||||||
|
#end
|
||||||
|
]
|
||||||
|
}
|
||||||
|
</requestBody>
|
||||||
|
<responseMapping mode="single" rootType="EmissionCalculationResult">
|
||||||
|
<constant target="EmissionCalculationResult.provider" value="myclimate_bulk"/>
|
||||||
|
<field source="$.sum_co2eq_kg" target="EmissionCalculationResult.total.co2eKg"/>
|
||||||
|
<field source="$.sum_km" target="EmissionCalculationResult.distance.value"/>
|
||||||
|
<list source="$.flights[*]" target="EmissionCalculationResult.segments" itemType="SegmentEmissionResult">
|
||||||
|
<field source="$.id" target="SegmentEmissionResult.id"/>
|
||||||
|
<field source="$.from" target="SegmentEmissionResult.origin.iata"/>
|
||||||
|
<field source="$.to" target="SegmentEmissionResult.destination.iata"/>
|
||||||
|
<field source="$.co2eq_kg" target="SegmentEmissionResult.emissions.co2eKg"/>
|
||||||
|
<field source="$.km" target="SegmentEmissionResult.distance.value"/>
|
||||||
|
<field source="$.status" target="SegmentEmissionResult.status"/>
|
||||||
|
<field source="$" target="SegmentEmissionResult.vendorRaw"/>
|
||||||
|
</list>
|
||||||
|
</responseMapping>
|
||||||
|
</operation>
|
||||||
|
</operations>
|
||||||
|
</provider>
|
||||||
|
</providers>
|
||||||
38
providers/myclimate/myclimate_v1.xml
Normal file
38
providers/myclimate/myclimate_v1.xml
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<providers xmlns="https://calco2la.to/schema/providers/v1">
|
||||||
|
<provider id="myclimate_v1">
|
||||||
|
<name>myclimate Flight Calculator V1</name>
|
||||||
|
<baseUrl>https://api.myclimate.org</baseUrl>
|
||||||
|
<auth type="basic">
|
||||||
|
<usernameEnvKey>MYCLIMATE_USERNAME</usernameEnvKey>
|
||||||
|
<passwordEnvKey>MYCLIMATE_PASSWORD</passwordEnvKey>
|
||||||
|
</auth>
|
||||||
|
<operations>
|
||||||
|
<operation id="travel.flight.estimate_emissions">
|
||||||
|
<http method="POST" path="/v1/flight_calculators.json"/>
|
||||||
|
<requestBody format="json">
|
||||||
|
{
|
||||||
|
"from":"${request.legs[0].origin_iata}",
|
||||||
|
"to":"${request.legs[last].destination_iata}",
|
||||||
|
"via":"${request.vendor_options.via}",
|
||||||
|
"passengers":${request.passengers},
|
||||||
|
"roundtrip":${request.roundtrip},
|
||||||
|
"flight_class":"${request.cabin_class}"
|
||||||
|
}
|
||||||
|
</requestBody>
|
||||||
|
<responseMapping mode="single" rootType="EmissionCalculationResult">
|
||||||
|
<constant target="EmissionCalculationResult.provider" value="myclimate_v1"/>
|
||||||
|
<field source="$.kg" target="EmissionCalculationResult.total.co2eKg"/>
|
||||||
|
<field source="$.km" target="EmissionCalculationResult.distance.value"/>
|
||||||
|
<constant target="EmissionCalculationResult.distance.unit" value="km"/>
|
||||||
|
<field source="$.fuel_kg_per_passenger" target="EmissionCalculationResult.fuel.kg"/>
|
||||||
|
<field source="$.price_in_eur_cents" target="EmissionCalculationResult.offset.amountMinor"/>
|
||||||
|
<constant target="EmissionCalculationResult.offset.currency" value="EUR"/>
|
||||||
|
<field source="$.errors" target="EmissionCalculationResult.errors"/>
|
||||||
|
<field source="$.input_params" target="EmissionCalculationResult.inputEcho"/>
|
||||||
|
<field source="$" target="EmissionCalculationResult.vendorRaw"/>
|
||||||
|
</responseMapping>
|
||||||
|
</operation>
|
||||||
|
</operations>
|
||||||
|
</provider>
|
||||||
|
</providers>
|
||||||
36
providers/myclimate/myclimate_v2.xml
Normal file
36
providers/myclimate/myclimate_v2.xml
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<providers xmlns="https://calco2la.to/schema/providers/v1">
|
||||||
|
<provider id="myclimate_v2">
|
||||||
|
<name>myclimate Flight Calculator V2</name>
|
||||||
|
<baseUrl>https://api.myclimate.org</baseUrl>
|
||||||
|
<auth type="basic">
|
||||||
|
<usernameEnvKey>MYCLIMATE_USERNAME</usernameEnvKey>
|
||||||
|
<passwordEnvKey>MYCLIMATE_PASSWORD</passwordEnvKey>
|
||||||
|
</auth>
|
||||||
|
<operations>
|
||||||
|
<operation id="travel.flight.estimate_emissions">
|
||||||
|
<http method="POST" path="/v2/flight_calculators.json"/>
|
||||||
|
<requestBody format="json">
|
||||||
|
{
|
||||||
|
"from":"${request.legs[0].origin_iata}",
|
||||||
|
"to":"${request.legs[last].destination_iata}",
|
||||||
|
"via":"${request.vendor_options.via}",
|
||||||
|
"aircraft_type_leg_1":"${request.legs[0].aircraft_type}",
|
||||||
|
"aircraft_type_leg_2":"${request.legs[1].aircraft_type}",
|
||||||
|
"passengers":${request.passengers},
|
||||||
|
"roundtrip":${request.roundtrip},
|
||||||
|
"flight_class":"${request.cabin_class}"
|
||||||
|
}
|
||||||
|
</requestBody>
|
||||||
|
<responseMapping mode="single" rootType="EmissionCalculationResult">
|
||||||
|
<constant target="EmissionCalculationResult.provider" value="myclimate_v2"/>
|
||||||
|
<field source="$.kg" target="EmissionCalculationResult.total.co2eKg"/>
|
||||||
|
<field source="$.km" target="EmissionCalculationResult.distance.value"/>
|
||||||
|
<field source="$.fuel_kg_per_passenger" target="EmissionCalculationResult.fuel.kg"/>
|
||||||
|
<field source="$.errors" target="EmissionCalculationResult.errors"/>
|
||||||
|
<field source="$" target="EmissionCalculationResult.vendorRaw"/>
|
||||||
|
</responseMapping>
|
||||||
|
</operation>
|
||||||
|
</operations>
|
||||||
|
</provider>
|
||||||
|
</providers>
|
||||||
Reference in New Issue
Block a user