diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
new file mode 100644
index 000000000..b2b3131c1
--- /dev/null
+++ b/.github/pull_request_template.md
@@ -0,0 +1,16 @@
+## :wrench: Problem
+
+> _Describe the problem you're trying to solve, the reason why you are creating this pull request. Provide a link to the Notion card if any._
+
+## :cake: Solution
+
+> _Explain the solution that this PR implements to solve the problem above._
+
+
+## :rotating_light: Points to watch/comments
+
+> _If there is anything unusual or some clarifications needed for the reviewer to better understand the PR, discuss it here._
+
+## :desert_island: How to test
+
+> _What someone else than you should do to validate that the solution you implemented is working as expected. Don't hesitate to be too verbose and to explain in details, using bullet points for example, the steps to follow to test the expected behavior._
diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml
index d758a4031..db35ece7c 100644
--- a/.github/workflows/node.js.yml
+++ b/.github/workflows/node.js.yml
@@ -53,9 +53,7 @@ jobs:
uses: actions/cache@v4
with:
path: ~/.local/share/virtualenvs
- key: ${{ runner.os }}-${{ matrix.python-version }}-pipenv-${{ hashFiles('Pipfile.lock') }}
- restore-keys: |
- ${{ runner.os }}-pipenv-
+ key: ${{ runner.os }}-python-${{ steps.setup-python.outputs.python-version }}-pipenv-${{ hashFiles('Pipfile.lock') }}
- name: Install Node dependencies
run: npm ci --prefer-offline --no-audit
diff --git a/CHANGELOG.md b/CHANGELOG.md
index da4586ff8..d7f1f26ac 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,29 @@
# Changelog
+## [2.3.0](https://github.com/MTES-MCT/ecobalyse/compare/v2.2.0...v2.3.0) (2024-09-25)
+
+
+### Features
+
+* add link to changelog in app footer. ([#748](https://github.com/MTES-MCT/ecobalyse/issues/748)) ([efe88f5](https://github.com/MTES-MCT/ecobalyse/commit/efe88f57d4f61e74e84f62c5334a89d36fd767ee))
+* airTransportRatio should depend on durability ([#757](https://github.com/MTES-MCT/ecobalyse/issues/757)) ([a0761d1](https://github.com/MTES-MCT/ecobalyse/commit/a0761d169469fddff7b9158f21de26d96a98ae0f))
+* displayName in the textile explorer, reordered columns ([#737](https://github.com/MTES-MCT/ecobalyse/issues/737)) ([65d0ed5](https://github.com/MTES-MCT/ecobalyse/commit/65d0ed547566c193c5617147a35604e26b0bbe6d))
+
+
+### Bug Fixes
+
+* **api:** handle ingredient plane transport in food POST api. ([#769](https://github.com/MTES-MCT/ecobalyse/issues/769)) ([62587e2](https://github.com/MTES-MCT/ecobalyse/commit/62587e23593e459d66726b2221932092393790e5))
+* check db integrity after building it ([#753](https://github.com/MTES-MCT/ecobalyse/issues/753)) ([5b41ef6](https://github.com/MTES-MCT/ecobalyse/commit/5b41ef6a6e1d4e799ed2abe7f21a321a87f9ae83))
+* check uniqueness of JSON db primary keys at build time. ([#766](https://github.com/MTES-MCT/ecobalyse/issues/766)) ([0927954](https://github.com/MTES-MCT/ecobalyse/commit/0927954dfe472557f0e7c2e5e4aa24d1ce8572c2))
+* decode and validate all optionals. ([#764](https://github.com/MTES-MCT/ecobalyse/issues/764)) ([87a7c6a](https://github.com/MTES-MCT/ecobalyse/commit/87a7c6af3e6edc12c2daa36192ad7f18fdefc444))
+* encode physicalDurability parameter. ([#751](https://github.com/MTES-MCT/ecobalyse/issues/751)) ([f6750b8](https://github.com/MTES-MCT/ecobalyse/commit/f6750b8aea6dc0a4500a23465bfdbc0f0b627743))
+* fix github CI python build setup. ([#762](https://github.com/MTES-MCT/ecobalyse/issues/762)) ([ea2cd9f](https://github.com/MTES-MCT/ecobalyse/commit/ea2cd9ff566129081ccf37caef25377717933c9d))
+* fixed brightway explorer notebook error (wrong key) ([#745](https://github.com/MTES-MCT/ecobalyse/issues/745)) ([bc436c2](https://github.com/MTES-MCT/ecobalyse/commit/bc436c2d1520efb9de269cdadccf6587d1904468))
+* in brightway explorer: improve display of compartment categories, if any ([#754](https://github.com/MTES-MCT/ecobalyse/issues/754)) ([757d5a6](https://github.com/MTES-MCT/ecobalyse/commit/757d5a6b50363995011e23bd5719adedb44d296f))
+* stricter validation of POST json body passed to the textile API. ([#760](https://github.com/MTES-MCT/ecobalyse/issues/760)) ([a85bd8a](https://github.com/MTES-MCT/ecobalyse/commit/a85bd8aa506ce87b9b1310b6a4a933a591ce442e))
+* **textile:** distribution step had no inland road transports added. ([#761](https://github.com/MTES-MCT/ecobalyse/issues/761)) ([d789d7d](https://github.com/MTES-MCT/ecobalyse/commit/d789d7d63a3dede6a4c2b07d43f6f43b9328a519))
+* Update export outside of EU probability. ([#765](https://github.com/MTES-MCT/ecobalyse/issues/765)) ([c3fd9f2](https://github.com/MTES-MCT/ecobalyse/commit/c3fd9f2d5d0cc01232b31f9aa1ef657b33796292))
+
## [2.2.0](https://github.com/MTES-MCT/ecobalyse/compare/v2.1.1...v2.2.0) (2024-09-12)
diff --git a/bin/build-db b/bin/build-db
index bb9f4bee7..d874b3241 100755
--- a/bin/build-db
+++ b/bin/build-db
@@ -22,35 +22,60 @@ try {
process.exit(1);
}
-function getJson(path) {
+function parseAndValidate(path, idKeyName = "id") {
const raw = JSON.parse(fs.readFileSync(path).toString());
+ if (idKeyName && Array.isArray(raw)) {
+ try {
+ validatePrimaryKeys(raw, idKeyName);
+ } catch (err) {
+ console.error(`🚨 ERROR building ${path}:\n ${err}`);
+ process.exit(1);
+ }
+ }
// Adapts a standard JSON string to what is expected to be the format
// used in Elm's template strings (`"""{}"""`).
return JSON.stringify(raw).replaceAll("\\", "\\\\");
}
+/**
+ * Validates that unique identifiers are actually unique in provided datasource.
+ */
+function validatePrimaryKeys(records, idKeyName) {
+ const ids = records.map((record) => record[idKeyName]).sort();
+ const duplicates = ids.filter((item, index) => ids.indexOf(item) !== index);
+ if (duplicates.length > 0) {
+ throw new Error(`Duplicate ${idKeyName}: ${duplicates}`);
+ }
+}
+
const targetDbFile = "src/Static/Json.elm";
const elmTemplate = fs.readFileSync(`${targetDbFile}-template`).toString();
const elmWithFixtures = elmTemplate
// Transverse JSON data
- .replace("%countriesJson%", getJson("public/data/countries.json"))
- .replace("%impactsJson%", getJson("public/data/impacts.json"))
- .replace("%transportsJson%", getJson("public/data/transports.json"))
+ .replace("%countriesJson%", parseAndValidate("public/data/countries.json", "code"))
+ .replace("%impactsJson%", parseAndValidate("public/data/impacts.json"))
+ .replace("%transportsJson%", parseAndValidate("public/data/transports.json"))
// Food JSON data
- .replace("%foodIngredientsJson%", getJson("public/data/food/ingredients.json"))
+ .replace("%foodIngredientsJson%", parseAndValidate("public/data/food/ingredients.json", "id"))
.replace(
"%foodProcessesJson%",
- getJson(NODE_ENV === "test" ? dataFiles.foodDetailed : dataFiles.foodNoDetails),
+ parseAndValidate(NODE_ENV === "test" ? dataFiles.foodDetailed : dataFiles.foodNoDetails, "id"),
)
- .replace("%foodProductExamplesJson%", getJson("public/data/food/examples.json"))
+ .replace("%foodProductExamplesJson%", parseAndValidate("public/data/food/examples.json", "id"))
// Textile JSON data
- .replace("%textileMaterialsJson%", getJson("public/data/textile/materials.json"))
+ .replace("%textileMaterialsJson%", parseAndValidate("public/data/textile/materials.json", "id"))
.replace(
"%textileProcessesJson%",
- getJson(NODE_ENV === "test" ? dataFiles.textileDetailed : dataFiles.textileNoDetails),
+ parseAndValidate(
+ NODE_ENV === "test" ? dataFiles.textileDetailed : dataFiles.textileNoDetails,
+ "uuid",
+ ),
+ )
+ .replace(
+ "%textileProductExamplesJson%",
+ parseAndValidate("public/data/textile/examples.json", "id"),
)
- .replace("%textileProductExamplesJson%", getJson("public/data/textile/examples.json"))
- .replace("%textileProductsJson%", getJson("public/data/textile/products.json"));
+ .replace("%textileProductsJson%", parseAndValidate("public/data/textile/products.json", "id"));
const header =
"---- THIS FILE WAS GENERATED FROM THE FILE `Json.elm-template` BY THE `/bin/build-db` SCRIPT";
diff --git a/data/Makefile b/data/Makefile
index b713cb3de..521ccbf39 100644
--- a/data/Makefile
+++ b/data/Makefile
@@ -47,7 +47,7 @@ compare_food:
@$(call DOCKER,python3 export.py compare)
format:
- npm run format:json
+ npm run fix:all
python:
echo Running Python inside the container...
@@ -94,4 +94,3 @@ clean_image:
docker image rm $(NAME)
clean: clean_data clean_image
-
diff --git a/data/docker/entrypoint.sh b/data/docker/entrypoint.sh
index a21d800db..1544c574f 100755
--- a/data/docker/entrypoint.sh
+++ b/data/docker/entrypoint.sh
@@ -8,6 +8,11 @@ if [ $ECOBALYSE_ID -ne $JOVYAN_ID ]; then
usermod -u $ECOBALYSE_ID jovyan
fi
-chown -R 1000:100 "/home/jovyan/.npm"
+# Ensure .npm directory is owned by jovyan
+mkdir -p /home/jovyan/.npm
+chown -R jovyan:100 "/home/jovyan/.npm"
-gosu jovyan "$@"
+# Clear npm cache
+su jovyan -c "npm cache clean --force"
+
+exec gosu jovyan "$@"
diff --git a/data/notebooks/explore.py b/data/notebooks/explore.py
index 1d190f5b0..e3c7df4e2 100644
--- a/data/notebooks/explore.py
+++ b/data/notebooks/explore.py
@@ -112,12 +112,14 @@ def w_csv_button(contents, columns):
def display_results(database, search, limit):
"""display the list of search results in the w_results widget"""
results = list(bw2data.Database(database).search(search, limit=limit))
+ for a in results:
+ a["categories"] = ", ".join(a.get("categories", []))
w_results.clear_output()
w_details.clear_output()
w_activity.options = [("", "")] + [
(
- str(i)
- + f" {a.get('name', '')} {'(' if a.get('categories') else ''}{', '.join(a.get('categories', []))}{')' if a.get('categories') else ''}",
+ str(i) + f" {a.get('name', '')} "
+ f"{('(in ' + a.get('categories', []) + ')') if a.get('categories') else ''}",
a,
)
for i, a in enumerate(results)
@@ -128,7 +130,7 @@ def display_results(database, search, limit):
display(
Markdown(f"## {('+' if len(results)==LIMIT else '')}{len(results)} results")
)
- columns = ["name", "code", "location"]
+ columns = ["name", "categories", "code", "location"]
html = pandas.io.formats.style.Styler(
pandas.DataFrame(results, columns=columns)
)
@@ -651,7 +653,7 @@ def display_main_data(method, impact_category, activity):
f"
Name: {input_.get('name', 'N/A')}"
f"Code: {input_.get('code', 'N/A')}"
f"Type: {input_.get('type', 'N/A')}"
- f"Categories: {', '.join(input_.get('categories', 'N/A'))}"
+ f"Categories: {', '.join(input_.get('categories', []))}"
f"CAS number: {str(input_.get('CAS number'))}"
f"Unit: {input_.get('unit', 'N/A')}"
f"Id: {input_.get('id', 'N/A')}"
@@ -720,7 +722,8 @@ def display_main_data(method, impact_category, activity):
w_details.clear_output()
display(
Markdown(
- f"# 1 {activity.get('unit', '')} of {activity.get('name', '')} ({', '.join(activity.get('categories', 'N/A'))})"
+ f"# 1 {activity.get('unit', '')} of {activity.get('name', '')} "
+ f"{('(in ' + ', '.join(activity.get('categories', [])) + ')') if activity.get('categories') else ''}"
)
)
display(
diff --git a/package-lock.json b/package-lock.json
index bde2c5768..d0c76d854 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "ecobalyse",
- "version": "2.2.0",
+ "version": "2.3.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "ecobalyse",
- "version": "2.2.0",
+ "version": "2.3.0",
"license": "MIT",
"dependencies": {
"@sentry/browser": "^8.27.0",
diff --git a/package.json b/package.json
index 87cafce18..3b1f0727b 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "ecobalyse",
- "version": "2.2.0",
+ "version": "2.3.0",
"description": "Accélérer l'affichage environnemental de la filière textile française",
"author": "Ecobalyse ",
"license": "MIT",
diff --git a/public/data/countries.json b/public/data/countries.json
index 30a5549b2..8d1318c6e 100644
--- a/public/data/countries.json
+++ b/public/data/countries.json
@@ -5,7 +5,6 @@
"zone": "Asia",
"electricityProcessUuid": "4ee8150b0cbf3603e03345d780ba7a61",
"heatProcessUuid": "heat-row",
- "airTransportRatio": 0.33,
"scopes": ["textile"],
"aquaticPollutionScenario": "Worst"
},
@@ -15,7 +14,6 @@
"zone": "Europe",
"electricityProcessUuid": "region-elec-west-europe",
"heatProcessUuid": "heat-europe",
- "airTransportRatio": 0,
"scopes": ["textile"],
"aquaticPollutionScenario": "Best"
},
@@ -25,7 +23,6 @@
"zone": "Europe",
"electricityProcessUuid": "2764d908c1a6fe88976d6eabf16295da",
"heatProcessUuid": "heat-europe",
- "airTransportRatio": 0,
"scopes": ["textile"],
"aquaticPollutionScenario": "Best"
},
@@ -35,7 +32,6 @@
"zone": "Asia",
"electricityProcessUuid": "elec-medium-region-asia",
"heatProcessUuid": "heat-row",
- "airTransportRatio": 0.33,
"scopes": ["textile"],
"aquaticPollutionScenario": "Worst"
},
@@ -45,7 +41,6 @@
"zone": "Africa",
"electricityProcessUuid": "elec-medium-region-africa",
"heatProcessUuid": "heat-row",
- "airTransportRatio": 0,
"scopes": ["textile"],
"aquaticPollutionScenario": "Worst"
},
@@ -55,7 +50,6 @@
"zone": "Middle_East",
"electricityProcessUuid": "elec-medium-region-middle-east",
"heatProcessUuid": "heat-row",
- "airTransportRatio": 0.33,
"scopes": ["textile"],
"aquaticPollutionScenario": "Average"
},
@@ -65,7 +59,6 @@
"zone": "South_America",
"electricityProcessUuid": "elec-medium-region-latin-america",
"heatProcessUuid": "heat-row",
- "airTransportRatio": 0.33,
"scopes": ["textile"],
"aquaticPollutionScenario": "Average"
},
@@ -75,7 +68,6 @@
"zone": "North_America",
"electricityProcessUuid": "elec-medium-region-north-america",
"heatProcessUuid": "heat-row",
- "airTransportRatio": 0.33,
"scopes": ["textile"],
"aquaticPollutionScenario": "Worst"
},
@@ -85,7 +77,6 @@
"zone": "Oceania",
"electricityProcessUuid": "53c7378e585cf74cea4837819be6e631",
"heatProcessUuid": "heat-row",
- "airTransportRatio": 0.33,
"scopes": ["textile"],
"aquaticPollutionScenario": "Worst"
},
@@ -95,7 +86,6 @@
"zone": "Asia",
"electricityProcessUuid": "4968e9f8cf72cb72700d94b242048db0",
"heatProcessUuid": "heat-row",
- "airTransportRatio": 0.33,
"scopes": ["textile"],
"aquaticPollutionScenario": "Worst"
},
@@ -105,7 +95,6 @@
"zone": "Asia",
"electricityProcessUuid": "0b69950358f3e8f0d3fb049d71481186",
"heatProcessUuid": "heat-row",
- "airTransportRatio": 0.33,
"scopes": ["textile"],
"aquaticPollutionScenario": "Worst"
},
@@ -115,7 +104,6 @@
"zone": "South_America",
"electricityProcessUuid": "825dae104f028cb558dac151f7c45f03",
"heatProcessUuid": "heat-row",
- "airTransportRatio": 0.33,
"scopes": ["food"],
"aquaticPollutionScenario": "Worst"
},
@@ -125,7 +113,6 @@
"zone": "Asia",
"electricityProcessUuid": "8bbc2475141687462993329f9b7c2ddf",
"heatProcessUuid": "heat-row",
- "airTransportRatio": 0.33,
"scopes": ["food", "textile"],
"aquaticPollutionScenario": "Average"
},
@@ -135,7 +122,6 @@
"zone": "Europe",
"electricityProcessUuid": "80ff4bc21a0e197ea3f69d809fd8d4f1",
"heatProcessUuid": "heat-europe",
- "airTransportRatio": 0,
"scopes": ["food"],
"aquaticPollutionScenario": "Best"
},
@@ -145,7 +131,6 @@
"zone": "Europe",
"electricityProcessUuid": "3c131d87f8dd997d14d2ffc3477f83e6",
"heatProcessUuid": "heat-europe",
- "airTransportRatio": 0,
"scopes": ["food", "textile"],
"aquaticPollutionScenario": "Best"
},
@@ -155,7 +140,6 @@
"zone": "Asia",
"electricityProcessUuid": "4ee8150b0cbf3603e03345d780ba7a61",
"heatProcessUuid": "heat-row",
- "airTransportRatio": 0.33,
"scopes": ["textile"],
"aquaticPollutionScenario": "Worst"
},
@@ -165,7 +149,6 @@
"zone": "Europe",
"electricityProcessUuid": "ae9240745e54987338d2228c3be2a5ec",
"heatProcessUuid": "heat-europe",
- "airTransportRatio": 0,
"scopes": ["food"],
"aquaticPollutionScenario": "Best"
},
@@ -175,7 +158,6 @@
"zone": "Africa",
"electricityProcessUuid": "e5f92d33532b4e649da2541b264fa363",
"heatProcessUuid": "heat-row",
- "airTransportRatio": 0.33,
"scopes": ["food"],
"aquaticPollutionScenario": "Average"
},
@@ -185,7 +167,6 @@
"zone": "Asia",
"electricityProcessUuid": "de2cd7848f853b1c9b8a5d7b0f255144",
"heatProcessUuid": "heat-row",
- "airTransportRatio": 0.33,
"scopes": ["textile"],
"aquaticPollutionScenario": "Average"
},
@@ -195,7 +176,6 @@
"zone": "Africa",
"electricityProcessUuid": "d3287580187139b11ce76f80013510d0",
"heatProcessUuid": "heat-row",
- "airTransportRatio": 0,
"scopes": ["food", "textile"],
"aquaticPollutionScenario": "Average"
},
@@ -205,7 +185,6 @@
"zone": "Oceania",
"electricityProcessUuid": "609797e4710a81c9903bc72c141ff191",
"heatProcessUuid": "heat-row",
- "airTransportRatio": 0.33,
"scopes": ["food"],
"aquaticPollutionScenario": "Best"
},
@@ -215,7 +194,6 @@
"zone": "South_America",
"electricityProcessUuid": "debdaaba938a58ac1ab0131e47186092",
"heatProcessUuid": "heat-row",
- "airTransportRatio": 0.33,
"scopes": ["food"],
"aquaticPollutionScenario": "Worst"
},
@@ -225,7 +203,6 @@
"zone": "Asia",
"electricityProcessUuid": "028c9bf863a1ab77a0e636029afc5839",
"heatProcessUuid": "heat-row",
- "airTransportRatio": 0.33,
"scopes": ["textile"],
"aquaticPollutionScenario": "Worst"
},
@@ -235,7 +212,6 @@
"zone": "Africa",
"electricityProcessUuid": "b42506cbed4b459815c78d741b453e8e",
"heatProcessUuid": "heat-row",
- "airTransportRatio": 0,
"scopes": ["textile"],
"aquaticPollutionScenario": "Average"
},
@@ -245,7 +221,6 @@
"zone": "Middle_East",
"electricityProcessUuid": "32644303e316aebb9ffa31e9856c8f6b",
"heatProcessUuid": "heat-row",
- "airTransportRatio": 0.33,
"scopes": ["textile"],
"aquaticPollutionScenario": "Average"
},
@@ -255,7 +230,6 @@
"zone": "North_America",
"electricityProcessUuid": "99b549d4ba7a0f5f4ab6050d6a6689ad",
"heatProcessUuid": "heat-row",
- "airTransportRatio": 0.33,
"scopes": ["food"],
"aquaticPollutionScenario": "Best"
},
@@ -265,7 +239,6 @@
"zone": "Asia",
"electricityProcessUuid": "3f90d52cc1dfe32119bf53db2713c407",
"heatProcessUuid": "heat-row",
- "airTransportRatio": 0.33,
"scopes": ["textile"],
"aquaticPollutionScenario": "Average"
}
diff --git a/public/data/textile/examples.json b/public/data/textile/examples.json
index 0e9ca887f..710b892cf 100644
--- a/public/data/textile/examples.json
+++ b/public/data/textile/examples.json
@@ -447,7 +447,7 @@
}
},
{
- "id": "f48d7a6b-68db-4d1c-9623-6ec0ab89cbdb",
+ "id": "6a2da9ff-9120-4a47-91ad-a8e72be45f4a",
"name": "Tshirt coton (150g) - Remanufacturé",
"category": "Tshirt / Polo",
"query": {
diff --git a/public/data/textile/processes.json b/public/data/textile/processes.json
index 416c085e8..05b556354 100644
--- a/public/data/textile/processes.json
+++ b/public/data/textile/processes.json
@@ -718,7 +718,7 @@
"heat_MJ": 0,
"elec_pppm": 0,
"elec_MJ": 0,
- "waste": 0.270519,
+ "waste": 0.21292,
"alias": null
},
{
@@ -756,7 +756,7 @@
"heat_MJ": 0,
"elec_pppm": 0,
"elec_MJ": 0,
- "waste": 0.270519,
+ "waste": 0.21292,
"alias": null
},
{
@@ -794,7 +794,7 @@
"heat_MJ": 0,
"elec_pppm": 0,
"elec_MJ": 0,
- "waste": 0.270519,
+ "waste": 0.21292,
"alias": null
},
{
@@ -832,7 +832,7 @@
"heat_MJ": 0,
"elec_pppm": 0,
"elec_MJ": 0,
- "waste": 0.0319569,
+ "waste": 0.03097,
"alias": null
},
{
@@ -870,7 +870,7 @@
"heat_MJ": 0,
"elec_pppm": 0,
"elec_MJ": 0,
- "waste": 0.0319569,
+ "waste": 0.03097,
"alias": null
},
{
@@ -908,7 +908,7 @@
"heat_MJ": 0,
"elec_pppm": 0,
"elec_MJ": 0,
- "waste": 0.0319569,
+ "waste": 0.03097,
"alias": null
},
{
@@ -946,7 +946,7 @@
"heat_MJ": 0,
"elec_pppm": 0,
"elec_MJ": 0,
- "waste": 0.0319569,
+ "waste": 0.03097,
"alias": null
},
{
@@ -984,7 +984,7 @@
"heat_MJ": 0,
"elec_pppm": 0,
"elec_MJ": 0,
- "waste": 0.0765978,
+ "waste": 0.07115,
"alias": null
},
{
@@ -1022,7 +1022,7 @@
"heat_MJ": 0,
"elec_pppm": 0,
"elec_MJ": 0,
- "waste": 0.538462,
+ "waste": 0.35,
"alias": null
},
{
@@ -1060,7 +1060,7 @@
"heat_MJ": 0,
"elec_pppm": 0,
"elec_MJ": 0,
- "waste": 0.538462,
+ "waste": 0.35,
"alias": null
},
{
@@ -1098,7 +1098,7 @@
"heat_MJ": 0,
"elec_pppm": 0,
"elec_MJ": 0,
- "waste": 0.201201,
+ "waste": 0.1675,
"alias": null
},
{
@@ -1136,7 +1136,7 @@
"heat_MJ": 0,
"elec_pppm": 0,
"elec_MJ": 0,
- "waste": 0.105105,
+ "waste": 0.09511,
"alias": null
},
{
@@ -1174,7 +1174,7 @@
"heat_MJ": 0,
"elec_pppm": 0,
"elec_MJ": 0,
- "waste": 0.221094,
+ "waste": 0.18106,
"alias": null
},
{
@@ -1212,7 +1212,7 @@
"heat_MJ": 0,
"elec_pppm": 0,
"elec_MJ": 0,
- "waste": 0.0582011,
+ "waste": 0.055,
"alias": null
},
{
@@ -1250,7 +1250,7 @@
"heat_MJ": 0,
"elec_pppm": 0,
"elec_MJ": 0,
- "waste": 0.631206,
+ "waste": 0.38696,
"alias": null
},
{
@@ -1288,7 +1288,7 @@
"heat_MJ": 0,
"elec_pppm": 0,
"elec_MJ": 0,
- "waste": 0.21716,
+ "waste": 0.17842,
"alias": null
},
{
@@ -1326,7 +1326,7 @@
"heat_MJ": 0,
"elec_pppm": 0,
"elec_MJ": 8.64,
- "waste": 0.0576,
+ "waste": 0.05446,
"alias": "knitting-mix"
},
{
@@ -1364,7 +1364,7 @@
"heat_MJ": 0,
"elec_pppm": 0,
"elec_MJ": 6.06443,
- "waste": 0.00502513,
+ "waste": 0.005,
"alias": "knitting-fully-fashioned"
},
{
@@ -1402,7 +1402,7 @@
"heat_MJ": 0,
"elec_pppm": 0,
"elec_MJ": 13.2112,
- "waste": 0.00502513,
+ "waste": 0.005,
"alias": "knitting-seamless"
},
{
@@ -1440,7 +1440,7 @@
"heat_MJ": 0,
"elec_pppm": 0.0003145,
"elec_MJ": 0,
- "waste": 0.0667,
+ "waste": 0.06253,
"alias": "weaving"
},
{
@@ -2694,7 +2694,7 @@
"heat_MJ": 0,
"elec_pppm": 0,
"elec_MJ": 4.194,
- "waste": 0.0417,
+ "waste": 0.04003,
"alias": "knitting-straight"
},
{
@@ -2732,7 +2732,7 @@
"heat_MJ": 0,
"elec_pppm": 0,
"elec_MJ": 4.25101,
- "waste": 0.0351967,
+ "waste": 0.034,
"alias": "knitting-circular"
},
{
diff --git a/src/Data/Common/DecodeUtils.elm b/src/Data/Common/DecodeUtils.elm
new file mode 100644
index 000000000..221d8b782
--- /dev/null
+++ b/src/Data/Common/DecodeUtils.elm
@@ -0,0 +1,12 @@
+module Data.Common.DecodeUtils exposing (strictOptional)
+
+import Json.Decode exposing (Decoder)
+import Json.Decode.Extra as DE
+
+
+{-| A stricter Decode.maybe using Json.Decode.Extra's optionalField here because we want
+a failure when a Maybe decoded field value is invalid.
+-}
+strictOptional : String -> Decoder a -> Decoder (Maybe a -> b) -> Decoder b
+strictOptional field decoder =
+ DE.andMap (DE.optionalField field decoder)
diff --git a/src/Data/Country.elm b/src/Data/Country.elm
index a8b649ba6..4334d6ade 100644
--- a/src/Data/Country.elm
+++ b/src/Data/Country.elm
@@ -10,6 +10,7 @@ module Data.Country exposing
, encodeCode
, findByCode
, getAquaticPollutionRatio
+ , isEuropeOrTurkey
, unknownCountryCode
)
@@ -34,8 +35,7 @@ type AquaticPollutionScenario
type alias Country =
- { airTransportRatio : Split
- , aquaticPollutionScenario : AquaticPollutionScenario
+ { aquaticPollutionScenario : AquaticPollutionScenario
, code : Code
, electricityProcess : Process
, heatProcess : Process
@@ -65,7 +65,6 @@ findByCode code =
decode : List Process -> Decoder Country
decode processes =
Decode.succeed Country
- |> Pipe.required "airTransportRatio" Split.decodeFloat
|> Pipe.required "aquaticPollutionScenario" decodeAquaticPollutionScenario
|> Pipe.required "code" decodeCode
|> Pipe.required "electricityProcessUuid" (Process.decodeFromUuid processes)
@@ -88,8 +87,7 @@ decodeList processes =
encode : Country -> Encode.Value
encode v =
Encode.object
- [ ( "airTransportRatio", Split.encodeFloat v.airTransportRatio )
- , ( "aquaticPollutionScenario", v.aquaticPollutionScenario |> aquaticPollutionScenarioToString |> Encode.string )
+ [ ( "aquaticPollutionScenario", v.aquaticPollutionScenario |> aquaticPollutionScenarioToString |> Encode.string )
, ( "code", encodeCode v.code )
, ( "electricityProcessUuid", v.electricityProcess.uuid |> Process.uuidToString |> Encode.string )
, ( "heatProcessUuid", v.heatProcess.uuid |> Process.uuidToString |> Encode.string )
@@ -152,6 +150,11 @@ getAquaticPollutionRatio scenario =
Split.fromPercent 65 |> Result.withDefault Split.full
+isEuropeOrTurkey : Country -> Bool
+isEuropeOrTurkey country =
+ country.zone == Zone.Europe || country.code == codeFromString "TR"
+
+
unknownCountryCode : Code
unknownCountryCode =
Code "---"
diff --git a/src/Data/Food/Ingredient.elm b/src/Data/Food/Ingredient.elm
index 7e765aaf2..969880db0 100644
--- a/src/Data/Food/Ingredient.elm
+++ b/src/Data/Food/Ingredient.elm
@@ -65,11 +65,18 @@ type TransportCooling
byPlaneAllowed : PlaneTransport -> Ingredient -> Result String PlaneTransport
byPlaneAllowed planeTransport ingredient =
- if byPlaneByDefault ingredient == PlaneNotApplicable && planeTransport /= PlaneNotApplicable then
- Err byPlaneErrorMessage
+ case ( planeTransport, byPlaneByDefault ingredient ) of
+ ( ByPlane, PlaneNotApplicable ) ->
+ Err "Impossible de spécifier un acheminement par avion pour cet ingrédient, son origine par défaut ne le permet pas."
- else
- Ok planeTransport
+ -- Note: PlaneNotApplicable is used for conveying both the absence of air transport AND impossible plane transport;
+ -- here we treat it as the equivalent of a `Nothing` where the ingredient default origin would suggest a
+ -- transport by air (eg. Non-EU Mango)
+ ( PlaneNotApplicable, ByPlane ) ->
+ Ok ByPlane
+
+ _ ->
+ Ok planeTransport
byPlaneByDefault : Ingredient -> PlaneTransport
@@ -81,11 +88,6 @@ byPlaneByDefault ingredient =
PlaneNotApplicable
-byPlaneErrorMessage : String
-byPlaneErrorMessage =
- "Impossible de spécifier un acheminement par avion pour cet ingrédient, son origine par défaut ne le permet pas."
-
-
decodeId : Decode.Decoder Id
decodeId =
Decode.string
@@ -142,7 +144,7 @@ decodeIngredient processes =
|> Pipe.required "id" decodeId
|> Pipe.required "inedible_part" Split.decodeFloat
|> Pipe.required "name" Decode.string
- |> Pipe.required "raw_to_cooked_ratio" (Unit.decodeRatio { percentage = False })
+ |> Pipe.required "raw_to_cooked_ratio" Unit.decodeRatio
|> Pipe.required "transport_cooling" decodeTransportCooling
|> Pipe.required "visible" Decode.bool
diff --git a/src/Data/Food/Process.elm b/src/Data/Food/Process.elm
index a2bee15d6..b2c366ea9 100644
--- a/src/Data/Food/Process.elm
+++ b/src/Data/Food/Process.elm
@@ -17,6 +17,7 @@ module Data.Food.Process exposing
, nameToString
)
+import Data.Common.DecodeUtils as DU
import Data.Impact as Impact exposing (Impacts)
import Json.Decode as Decode exposing (Decoder)
import Json.Decode.Extra as DE
@@ -184,8 +185,8 @@ decodeProcess : Decoder Impact.Impacts -> Decoder Process
decodeProcess impactsDecoder =
Decode.succeed Process
|> Pipe.required "category" decodeCategory
- |> Pipe.optional "comment" (Decode.maybe Decode.string) Nothing
- |> Pipe.optional "displayName" (Decode.maybe Decode.string) Nothing
+ |> DU.strictOptional "comment" Decode.string
+ |> DU.strictOptional "displayName" Decode.string
|> Pipe.required "id" Decode.string
|> Pipe.required "identifier" decodeIdentifier
|> Pipe.required "impacts" impactsDecoder
diff --git a/src/Data/Food/Query.elm b/src/Data/Food/Query.elm
index 360643e40..5931bb8af 100644
--- a/src/Data/Food/Query.elm
+++ b/src/Data/Food/Query.elm
@@ -24,6 +24,7 @@ module Data.Food.Query exposing
)
import Base64
+import Data.Common.DecodeUtils as DU
import Data.Country as Country
import Data.Food.Ingredient as Ingredient
import Data.Food.Preparation as Preparation
@@ -90,7 +91,7 @@ addPackaging packaging query =
buildApiQuery : String -> Query -> String
buildApiQuery clientUrl query =
- """curl -X POST %apiUrl% \\
+ """curl -sS -X POST %apiUrl% \\
-H "accept: application/json" \\
-H "content-type: application/json" \\
-d '%json%'
@@ -102,11 +103,11 @@ buildApiQuery clientUrl query =
decode : Decoder Query
decode =
Decode.succeed Query
- |> Pipe.optional "distribution" (Decode.maybe Retail.decode) Nothing
+ |> DU.strictOptional "distribution" Retail.decode
|> Pipe.required "ingredients" (Decode.list decodeIngredient)
|> Pipe.optional "packaging" (Decode.list decodeProcess) []
|> Pipe.optional "preparation" (Decode.list Preparation.decodeId) []
- |> Pipe.optional "transform" (Decode.maybe decodeProcess) Nothing
+ |> DU.strictOptional "transform" decodeProcess
decodePlaneTransport : Decoder Ingredient.PlaneTransport
@@ -126,15 +127,7 @@ decodePlaneTransport =
Ingredient.PlaneNotApplicable
)
)
- |> Decode.map
- (\maybe ->
- case maybe of
- Just planeTransport ->
- planeTransport
-
- Nothing ->
- Ingredient.PlaneNotApplicable
- )
+ |> Decode.map (Maybe.withDefault Ingredient.PlaneNotApplicable)
decodeMassInGrams : Decoder Mass
@@ -153,7 +146,7 @@ decodeProcess =
decodeIngredient : Decoder IngredientQuery
decodeIngredient =
Decode.succeed IngredientQuery
- |> Pipe.optional "country" (Decode.maybe Country.decodeCode) Nothing
+ |> DU.strictOptional "country" Country.decodeCode
|> Pipe.required "id" Ingredient.decodeId
|> Pipe.required "mass" decodeMassInGrams
|> Pipe.optional "byPlane" decodePlaneTransport Ingredient.PlaneNotApplicable
diff --git a/src/Data/Gitbook.elm b/src/Data/Gitbook.elm
index 496470af3..52ed7febe 100644
--- a/src/Data/Gitbook.elm
+++ b/src/Data/Gitbook.elm
@@ -16,7 +16,6 @@ type Path
| FoodTransformation -- Transformation des ingrédients
| FoodTransport -- Transport entre étapes
| FoodUse -- Consommation
- | TextileAerialTransport -- Part du transport aérien textile
| TextileComplementMicrofibers -- Complément textile microfibres
| TextileDistribution -- Distribution textile
| TextileDurability -- Durabilité textile
@@ -70,9 +69,6 @@ pathToString path =
FoodUse ->
"alimentaire/etapes-du-cycles-de-vie/consommation"
- TextileAerialTransport ->
- "textile/parametres-transverses/transport#part-du-transport-aerien"
-
TextileComplementMicrofibers ->
"textile/complements-hors-acv/microfibres"
diff --git a/src/Data/Impact.elm b/src/Data/Impact.elm
index b78689db3..79573e3e5 100644
--- a/src/Data/Impact.elm
+++ b/src/Data/Impact.elm
@@ -27,7 +27,6 @@ module Data.Impact exposing
, parseTrigram
, per100grams
, perKg
- , setEcotoxWeighting
, stepsColors
, stepsImpactsAsChartEntries
, sumEcosystemicImpacts
@@ -507,81 +506,6 @@ computeAggregatedScore definitions getter (Impacts impacts) =
|> Definition.foldl (\_ -> Quantity.plus) Quantity.zero
-minEcotoxWeighting : Unit.Ratio
-minEcotoxWeighting =
- Unit.ratio 0
-
-
-maxEcotoxWeighting : Unit.Ratio
-maxEcotoxWeighting =
- Unit.ratio 0.25
-
-
-{-| Set the ecotoxicity weighting (EtfC) then redistribute other Ecoscore weightings
-accordingly. The methodology and formulas are described in this card:
-
-FIXME: ensure the card contents are moved to the public documentation eventually
--}
-setEcotoxWeighting : Unit.Ratio -> Definitions -> Definitions
-setEcotoxWeighting (Unit.Ratio weighting) definitions =
- let
- defsToUpdate =
- [ Definition.Acd
- , Definition.Fru
- , Definition.Fwe
- , Definition.Ior
- , Definition.Ldu
- , Definition.Mru
- , Definition.Ozd
- , Definition.Pco
- , Definition.Pma
- , Definition.Swe
- , Definition.Tre
- , Definition.Wtu
- ]
-
- cleanWeighting =
- weighting
- |> clamp (Unit.ratioToFloat minEcotoxWeighting) (Unit.ratioToFloat maxEcotoxWeighting)
- in
- definitions
- -- Start with updating EtfC with the provided ratio
- |> Definition.update Definition.EtfC
- (\({ ecoscoreData } as definition) ->
- { definition
- | ecoscoreData =
- ecoscoreData
- |> Maybe.map (\data -> { data | weighting = Unit.ratio cleanWeighting })
- }
- )
- -- Then redistribute the other weightings accordingly
- |> Definition.map
- (\trg def ->
- if List.member trg defsToUpdate then
- let
- pefWeighting =
- def.pefData
- |> Maybe.map .weighting
- |> Maybe.withDefault (Unit.ratio 0)
- |> Unit.ratioToFloat
- in
- { def
- | ecoscoreData =
- def.ecoscoreData
- |> Maybe.map
- (\ecoscoreData ->
- { ecoscoreData
- -- = (PEF weighting for this trigram) * (78.94% - custom weighting) / 73.05%
- | weighting = Unit.ratio (pefWeighting * (0.7894 - cleanWeighting) / 0.7305)
- }
- )
- }
-
- else
- def
- )
-
-
-- Parser
diff --git a/src/Data/Impact/Definition.elm b/src/Data/Impact/Definition.elm
index 4c1db9417..47ffa37ab 100644
--- a/src/Data/Impact/Definition.elm
+++ b/src/Data/Impact/Definition.elm
@@ -21,6 +21,7 @@ module Data.Impact.Definition exposing
, update
)
+import Data.Split as Split exposing (Split)
import Data.Unit as Unit
import Json.Decode as Decode exposing (Decoder)
import Json.Decode.Extra as DE
@@ -35,7 +36,7 @@ import Json.Encode as Encode
type alias AggregatedScoreData =
{ color : String
, normalization : Unit.Impact
- , weighting : Unit.Ratio
+ , weighting : Split
}
@@ -554,7 +555,7 @@ decodeAggregatedScoreData =
Decode.map3 AggregatedScoreData
(Decode.field "color" Decode.string)
(Decode.field "normalization" Unit.decodeImpact)
- (Decode.field "weighting" (Unit.decodeRatio { percentage = True }))
+ (Decode.field "weighting" Split.decodeFloat)
decodeDefinition : String -> Decoder Definition
diff --git a/src/Data/Split.elm b/src/Data/Split.elm
index e3285a276..efe676689 100644
--- a/src/Data/Split.elm
+++ b/src/Data/Split.elm
@@ -15,6 +15,7 @@ module Data.Split exposing
, quarter
, sixty
, tenth
+ , third
, thirty
, toFloat
, toFloatString
@@ -35,6 +36,7 @@ module Data.Split exposing
import FormatNumber
import FormatNumber.Locales exposing (Decimals(..), frenchLocale)
import Json.Decode as Decode exposing (Decoder)
+import Json.Decode.Extra as DE
import Json.Encode as Encode
import Quantity exposing (Quantity)
@@ -78,6 +80,11 @@ thirty =
Split 30
+third : Split
+third =
+ Split 33
+
+
fourty : Split
fourty =
Split 40
@@ -135,9 +142,8 @@ toFloatString =
toPercentString : Int -> Split -> String
-toPercentString decimals (Split float) =
- float
- |> FormatNumber.format { frenchLocale | decimals = Exact decimals }
+toPercentString decimals =
+ toPercent >> FormatNumber.format { frenchLocale | decimals = Exact decimals }
complement : Split -> Split
@@ -163,16 +169,7 @@ divideBy input split =
decodeFloat : Decoder Split
decodeFloat =
Decode.float
- |> Decode.map fromFloat
- |> Decode.andThen
- (\result ->
- case result of
- Err error ->
- Decode.fail error
-
- Ok split ->
- Decode.succeed split
- )
+ |> Decode.andThen (fromFloat >> DE.fromResult)
encodeFloat : Split -> Encode.Value
diff --git a/src/Data/Textile/Formula.elm b/src/Data/Textile/Formula.elm
index 6ae45d96c..4a5ef6043 100644
--- a/src/Data/Textile/Formula.elm
+++ b/src/Data/Textile/Formula.elm
@@ -9,7 +9,6 @@ module Data.Textile.Formula exposing
, knittingImpacts
, makingDeadStock
, makingImpacts
- , makingWaste
, materialDyeingToxicityImpacts
, materialPrintingToxicityImpacts
, printingImpacts
@@ -50,28 +49,19 @@ type alias StepValues =
{-| Compute source mass needed and waste generated by the operation.
-}
-genericWaste : Unit.Ratio -> Mass -> { mass : Mass, waste : Mass }
-genericWaste processWaste baseMass =
+genericWaste : Split -> Mass -> { mass : Mass, waste : Mass }
+genericWaste processWaste stepOutputMass =
let
- waste =
- baseMass
- |> Quantity.multiplyBy (Unit.ratioToFloat processWaste)
- in
- { mass = baseMass |> Quantity.plus waste, waste = waste }
-
-
-{-| Compute source material mass needed and waste generated by the operation, according to
-material & product waste data.
--}
-makingWaste : Split -> Mass -> { mass : Mass, waste : Mass }
-makingWaste pcrWaste baseMass =
- let
- mass =
- -- (product weight + textile waste for confection) / (1 - PCR product waste rate)
- baseMass
- |> Quantity.divideBy (Split.toFloat (Split.complement pcrWaste))
+ stepInputMass =
+ -- Use input mass waste ratio formula by default
+ -- See https://fabrique-numerique.gitbook.io/ecobalyse/textile/cycle-de-vie-des-produits-textiles/pertes-et-rebus
+ --
+ -- inputMass = outputMass / 1 - Input processWasteRatio
+ stepOutputMass
+ |> Quantity.divideBy (1 - Split.toFloat processWaste)
in
- { mass = mass, waste = Quantity.minus baseMass mass }
+ -- We return the inputMass of this step (considered as the output mass of the previous step)
+ { mass = stepInputMass, waste = Quantity.minus stepOutputMass stepInputMass }
{-| Compute source material mass needed and deadstock generated by the operation, according to
diff --git a/src/Data/Textile/Inputs.elm b/src/Data/Textile/Inputs.elm
index bb667d593..ca03a9055 100644
--- a/src/Data/Textile/Inputs.elm
+++ b/src/Data/Textile/Inputs.elm
@@ -446,7 +446,7 @@ getOutOfEuropeEOLProbability materialInputs =
|> getMaterialCategoryShare Origin.Synthetic
in
Split.fromFloat
- (if Split.toPercent syntheticMaterialsShare >= 10 then
+ (if Split.toPercent syntheticMaterialsShare >= 50 then
0.121
else
diff --git a/src/Data/Textile/Process.elm b/src/Data/Textile/Process.elm
index 5fdb6c592..581f98d95 100644
--- a/src/Data/Textile/Process.elm
+++ b/src/Data/Textile/Process.elm
@@ -15,6 +15,7 @@ module Data.Textile.Process exposing
import Data.Impact as Impact exposing (Impacts)
import Data.Impact.Definition as Definition
+import Data.Split as Split exposing (Split)
import Data.Unit as Unit
import Energy exposing (Energy)
import Json.Decode as Decode exposing (Decoder)
@@ -38,7 +39,7 @@ type alias Process =
, stepUsage : String
, unit : String
, uuid : Uuid
- , waste : Unit.Ratio -- share of raw material wasted when initially processed
+ , waste : Split -- share of raw material wasted when initially processed
}
@@ -106,7 +107,7 @@ decode impactsDecoder =
|> Pipe.required "step_usage" Decode.string
|> Pipe.required "unit" Decode.string
|> Pipe.required "uuid" decodeUuid
- |> Pipe.required "waste" (Unit.decodeRatio { percentage = False })
+ |> Pipe.required "waste" Split.decodeFloat
getDisplayName : Process -> String
@@ -143,18 +144,18 @@ encodeUuid =
encode : Process -> Encode.Value
encode process =
Encode.object
- [ ( "name", Encode.string process.name )
+ [ ( "alias", EncodeExtra.maybe encodeAlias process.alias )
+ , ( "correctif", Encode.string process.correctif )
, ( "displayName", EncodeExtra.maybe Encode.string process.displayName )
+ , ( "elec_MJ", Encode.float (Energy.inMegajoules process.elec) )
+ , ( "elec_pppm", Encode.float process.elec_pppm )
+ , ( "heat_MJ", Encode.float (Energy.inMegajoules process.heat) )
+ , ( "impacts", Impact.encode process.impacts )
, ( "info", Encode.string process.info )
- , ( "unit", Encode.string process.unit )
+ , ( "name", Encode.string process.name )
, ( "source", Encode.string process.source )
- , ( "correctif", Encode.string process.correctif )
, ( "step_usage", Encode.string process.stepUsage )
+ , ( "unit", Encode.string process.unit )
, ( "uuid", encodeUuid process.uuid )
- , ( "impacts", Impact.encode process.impacts )
- , ( "heat_MJ", Encode.float (Energy.inMegajoules process.heat) )
- , ( "elec_pppm", Encode.float process.elec_pppm )
- , ( "elec_MJ", Encode.float (Energy.inMegajoules process.elec) )
- , ( "waste", Unit.encodeRatio process.waste )
- , ( "alias", EncodeExtra.maybe encodeAlias process.alias )
+ , ( "waste", Split.encodeFloat process.waste )
]
diff --git a/src/Data/Textile/Query.elm b/src/Data/Textile/Query.elm
index ba4a9863e..c39060790 100644
--- a/src/Data/Textile/Query.elm
+++ b/src/Data/Textile/Query.elm
@@ -24,6 +24,7 @@ module Data.Textile.Query exposing
)
import Base64
+import Data.Common.DecodeUtils as DU
import Data.Country as Country
import Data.Split as Split exposing (Split)
import Data.Textile.DyeingMedium as DyeingMedium exposing (DyeingMedium)
@@ -98,7 +99,7 @@ addMaterial material query =
buildApiQuery : String -> Query -> String
buildApiQuery clientUrl query =
- """curl -X POST %apiUrl% \\
+ """curl -sS -X POST %apiUrl% \\
-H "accept: application/json" \\
-H "content-type: application/json" \\
-d '%json%'
@@ -110,39 +111,39 @@ buildApiQuery clientUrl query =
decode : Decoder Query
decode =
Decode.succeed Query
- |> Pipe.optional "airTransportRatio" (Decode.maybe Split.decodeFloat) Nothing
- |> Pipe.optional "business" (Decode.maybe Economics.decodeBusiness) Nothing
- |> Pipe.optional "countryDyeing" (Decode.maybe Country.decodeCode) Nothing
- |> Pipe.optional "countryFabric" (Decode.maybe Country.decodeCode) Nothing
- |> Pipe.optional "countryMaking" (Decode.maybe Country.decodeCode) Nothing
- |> Pipe.optional "countrySpinning" (Decode.maybe Country.decodeCode) Nothing
+ |> DU.strictOptional "airTransportRatio" Split.decodeFloat
+ |> DU.strictOptional "business" Economics.decodeBusiness
+ |> DU.strictOptional "countryDyeing" Country.decodeCode
+ |> DU.strictOptional "countryFabric" Country.decodeCode
+ |> DU.strictOptional "countryMaking" Country.decodeCode
+ |> DU.strictOptional "countrySpinning" Country.decodeCode
|> Pipe.optional "disabledSteps" (Decode.list Label.decodeFromCode) []
- |> Pipe.optional "dyeingMedium" (Decode.maybe DyeingMedium.decode) Nothing
- |> Pipe.optional "fabricProcess" (Decode.maybe Fabric.decode) Nothing
- |> Pipe.optional "fading" (Decode.maybe Decode.bool) Nothing
- |> Pipe.optional "makingComplexity" (Decode.maybe MakingComplexity.decode) Nothing
- |> Pipe.optional "makingDeadStock" (Decode.maybe Split.decodeFloat) Nothing
- |> Pipe.optional "makingWaste" (Decode.maybe Split.decodeFloat) Nothing
+ |> DU.strictOptional "dyeingMedium" DyeingMedium.decode
+ |> DU.strictOptional "fabricProcess" Fabric.decode
+ |> DU.strictOptional "fading" Decode.bool
+ |> DU.strictOptional "makingComplexity" MakingComplexity.decode
+ |> DU.strictOptional "makingDeadStock" Split.decodeFloat
+ |> DU.strictOptional "makingWaste" Split.decodeFloat
|> Pipe.required "mass" (Decode.map Mass.kilograms Decode.float)
|> Pipe.required "materials" (Decode.list decodeMaterialQuery)
- |> Pipe.optional "numberOfReferences" (Decode.maybe Decode.int) Nothing
- |> Pipe.optional "physicalDurability" (Decode.maybe Unit.decodePhysicalDurability) Nothing
- |> Pipe.optional "price" (Decode.maybe Economics.decodePrice) Nothing
- |> Pipe.optional "printing" (Decode.maybe Printing.decode) Nothing
+ |> DU.strictOptional "numberOfReferences" Decode.int
+ |> DU.strictOptional "physicalDurability" Unit.decodePhysicalDurability
+ |> DU.strictOptional "price" Economics.decodePrice
+ |> DU.strictOptional "printing" Printing.decode
|> Pipe.required "product" (Decode.map Product.Id Decode.string)
- |> Pipe.optional "surfaceMass" (Decode.maybe Unit.decodeSurfaceMass) Nothing
- |> Pipe.optional "traceability" (Decode.maybe Decode.bool) Nothing
+ |> DU.strictOptional "surfaceMass" Unit.decodeSurfaceMass
+ |> DU.strictOptional "traceability" Decode.bool
|> Pipe.optional "upcycled" Decode.bool False
- |> Pipe.optional "yarnSize" (Decode.maybe Unit.decodeYarnSize) Nothing
+ |> DU.strictOptional "yarnSize" Unit.decodeYarnSize
decodeMaterialQuery : Decoder MaterialQuery
decodeMaterialQuery =
Decode.succeed MaterialQuery
- |> Pipe.optional "country" (Decode.maybe Country.decodeCode) Nothing
+ |> DU.strictOptional "country" Country.decodeCode
|> Pipe.required "id" (Decode.map Material.Id Decode.string)
|> Pipe.required "share" Split.decodeFloat
- |> Pipe.optional "spinning" (Decode.maybe Spinning.decode) Nothing
+ |> DU.strictOptional "spinning" Spinning.decode
encode : Query -> Encode.Value
diff --git a/src/Data/Textile/Simulator.elm b/src/Data/Textile/Simulator.elm
index 9b435d95a..1a881f0bc 100644
--- a/src/Data/Textile/Simulator.elm
+++ b/src/Data/Textile/Simulator.elm
@@ -8,6 +8,7 @@ module Data.Textile.Simulator exposing
)
import Array
+import Data.Country as Country
import Data.Env as Env
import Data.Impact as Impact exposing (Impacts)
import Data.Impact.Definition as Definition
@@ -133,6 +134,8 @@ compute db query =
-- DURABILITY
--
|> next computeDurability
+ -- Compute Making air transport ratio (depends on durability) - Confection
+ |> nextIf Label.Making computeMakingAirTransportRatio
--
-- LIFECYCLE STEP IMPACTS
--
@@ -210,6 +213,35 @@ computeDurability ({ inputs } as simulator) =
}
+computeMakingAirTransportRatio : Simulator -> Simulator
+computeMakingAirTransportRatio ({ durability, inputs } as simulator) =
+ simulator
+ |> updateLifeCycleStep Label.Making
+ (\({ country } as step) ->
+ { step
+ | airTransportRatio =
+ case inputs.airTransportRatio of
+ Just airTransportRatio ->
+ -- User-provided value always takes precedence
+ airTransportRatio
+
+ Nothing ->
+ if Country.isEuropeOrTurkey country then
+ -- If Making country is Europe or Turkey, airTransportRatio is always 0
+ Split.zero
+
+ else if Unit.floatDurabilityFromHolistic durability >= 1 then
+ -- Durable garments outside of Europe and Turkey
+ Split.third
+
+ else
+ -- FIXME: how about falling back to country default?
+ -- country.airTransportRatio
+ Split.full
+ }
+ )
+
+
computeEndOfLifeImpacts : Db -> Simulator -> Simulator
computeEndOfLifeImpacts { textile } simulator =
simulator
@@ -560,7 +592,7 @@ computeMakingStepWaste ({ inputs } as simulator) =
{ mass, waste } =
inputs.mass
- |> Formula.makingWaste
+ |> Formula.genericWaste
(fabricProcess
|> Fabric.getMakingWaste product.making.pcrWaste makingWaste
)
diff --git a/src/Data/Textile/Step.elm b/src/Data/Textile/Step.elm
index cc58a0bb5..bea83f048 100644
--- a/src/Data/Textile/Step.elm
+++ b/src/Data/Textile/Step.elm
@@ -38,6 +38,7 @@ import Data.Transport as Transport exposing (Transport)
import Data.Unit as Unit
import Energy exposing (Energy)
import Json.Encode as Encode
+import Length
import Mass exposing (Mass)
import Quantity
import Static.Db exposing (Db)
@@ -221,15 +222,14 @@ computeTransportImpacts impacts { airTransport, seaTransport } roadProcess mass
computeTransportSummary : Step -> Transport -> Transport
computeTransportSummary step transport =
let
- ( noTransports, defaultInland ) =
- ( Transport.default step.transport.impacts
- , Transport.default step.transport.impacts
- )
+ noTransports =
+ Transport.default step.transport.impacts
in
case step.label of
Label.Distribution ->
- -- Product Distribution leverages no transports
+ -- Add default road transport to materialize transport to/from a warehouse
noTransports
+ |> Transport.add { noTransports | road = Length.kilometers 500 }
Label.EndOfLife ->
-- End of life leverages no transports
@@ -239,10 +239,6 @@ computeTransportSummary step transport =
-- Air transport only applies between the Making and the Distribution steps
transport
|> Formula.transportRatio step.airTransportRatio
- -- Added intermediary inland transport distances to materialize
- -- transport to the "distribution" step
- -- Also ensure we don't add unnecessary air transport
- |> Transport.add { defaultInland | air = Quantity.zero }
Label.Use ->
-- Product Use leverages no transports
@@ -281,7 +277,7 @@ getTransportedMass inputs { label, outputMass } =
updateFromInputs : Textile.Db -> Inputs -> Step -> Step
updateFromInputs { wellKnown } inputs ({ label, country, complementsImpacts } as step) =
let
- { airTransportRatio, dyeingMedium, makingComplexity, makingDeadStock, makingWaste, printing, surfaceMass, yarnSize } =
+ { dyeingMedium, makingComplexity, makingDeadStock, makingWaste, printing, surfaceMass, yarnSize } =
inputs
in
case label of
@@ -348,18 +344,12 @@ updateFromInputs { wellKnown } inputs ({ label, country, complementsImpacts } as
Label.Making ->
{ step
- | airTransportRatio =
- airTransportRatio |> Maybe.withDefault country.airTransportRatio
- , makingComplexity = makingComplexity
+ | makingComplexity = makingComplexity
, makingDeadStock = makingDeadStock
, makingWaste = makingWaste
, processInfo =
{ defaultProcessInfo
- | airTransportRatio =
- country.airTransportRatio
- |> airTransportRatioToString
- |> Just
- , countryElec = Just country.electricityProcess.name
+ | countryElec = Just country.electricityProcess.name
, fading = Just wellKnown.fading.name
}
}
diff --git a/src/Data/Unit.elm b/src/Data/Unit.elm
index c8e33edf9..96de32087 100644
--- a/src/Data/Unit.elm
+++ b/src/Data/Unit.elm
@@ -18,7 +18,6 @@ module Data.Unit exposing
, encodeNonPhysicalDurability
, encodePhysicalDurability
, encodePickPerMeter
- , encodeRatio
, encodeSurfaceMass
, encodeThreadDensity
, encodeYarnSize
@@ -63,6 +62,7 @@ module Data.Unit exposing
)
import Area exposing (Area)
+import Data.Split as Split exposing (Split)
import Energy exposing (Energy)
import Json.Decode as Decode exposing (Decoder)
import Json.Encode as Encode
@@ -89,29 +89,12 @@ ratioToFloat (Ratio float) =
float
-decodeRatio : { percentage : Bool } -> Decoder Ratio
-decodeRatio { percentage } =
+decodeRatio : Decoder Ratio
+decodeRatio =
Decode.float
- |> Decode.andThen
- (\float ->
- if percentage && (float < 0 || float > 1) then
- Decode.fail
- ("Le ratio spécifié ("
- ++ String.fromFloat float
- ++ ") doit être compris entre 0 et 1."
- )
-
- else
- Decode.succeed float
- )
|> Decode.map ratio
-encodeRatio : Ratio -> Encode.Value
-encodeRatio =
- ratioToFloat >> Encode.float
-
-
-- Durability
@@ -187,9 +170,8 @@ decodePhysicalDurability =
)
else
- Decode.succeed float
+ Decode.succeed (physicalDurability float)
)
- |> Decode.map physicalDurability
encodePhysicalDurability : PhysicalDurability -> Encode.Value
@@ -427,10 +409,10 @@ impactToFloat (Quantity value) =
value
-impactAggregateScore : Impact -> Ratio -> Impact -> Impact
+impactAggregateScore : Impact -> Split -> Impact -> Impact
impactAggregateScore normalization weighting =
Quantity.divideBy (impactToFloat normalization)
- >> Quantity.multiplyBy (ratioToFloat weighting)
+ >> Quantity.multiplyBy (Split.toFloat weighting)
-- Raw aggregate scores like PEF are expressed in Pt (points); we want Pts (micropoints)
>> Quantity.multiplyBy 1000000
diff --git a/src/Page/Explore/Countries.elm b/src/Page/Explore/Countries.elm
index dd612693b..59d27e9a1 100644
--- a/src/Page/Explore/Countries.elm
+++ b/src/Page/Explore/Countries.elm
@@ -68,18 +68,6 @@ table distances countries { detailed, scope } =
else
Nothing
- , Just
- { label = "Part du transport aérien"
- , toValue = Table.FloatValue (.airTransportRatio >> Split.toPercent)
- , toCell =
- \country ->
- div [ classList [ ( "text-end", not detailed ) ] ]
- [ Format.splitAsPercentage 0 country.airTransportRatio
- , Link.smallPillExternal
- [ href (Gitbook.publicUrlFromPath Gitbook.TextileAerialTransport) ]
- [ Icon.info ]
- ]
- }
, Just
{ label = "Domaines"
, toValue = Table.StringValue <| .scopes >> List.map Scope.toLabel >> String.join "/"
diff --git a/src/Page/Explore/Impacts.elm b/src/Page/Explore/Impacts.elm
index 8795a2b23..fde85a3ff 100644
--- a/src/Page/Explore/Impacts.elm
+++ b/src/Page/Explore/Impacts.elm
@@ -3,6 +3,7 @@ module Page.Explore.Impacts exposing (table)
import Data.Dataset as Dataset
import Data.Impact.Definition as Definition exposing (Definition)
import Data.Scope exposing (Scope)
+import Data.Split as Split
import Data.Unit as Unit
import Html exposing (..)
import Html.Attributes exposing (..)
@@ -56,9 +57,9 @@ table { detailed, scope } =
, toValue =
Table.FloatValue <|
.pefData
- >> Maybe.map (.weighting >> Unit.ratioToFloat)
+ >> Maybe.map (.weighting >> Split.toFloat)
>> Maybe.withDefault 0
- , toCell = .pefData >> Maybe.map (.weighting >> Format.ratio) >> Maybe.withDefault (text "N/A")
+ , toCell = .pefData >> Maybe.map (.weighting >> Format.splitAsPercentage 2) >> Maybe.withDefault (text "N/A")
}
, { label = "Normalisation (Sc. Imp.)"
, toValue =
@@ -76,9 +77,9 @@ table { detailed, scope } =
, toValue =
Table.FloatValue <|
.ecoscoreData
- >> Maybe.map (.weighting >> Unit.ratioToFloat)
+ >> Maybe.map (.weighting >> Split.toFloat)
>> Maybe.withDefault 0
- , toCell = .ecoscoreData >> Maybe.map (.weighting >> Format.ratio) >> Maybe.withDefault (text "N/A")
+ , toCell = .ecoscoreData >> Maybe.map (.weighting >> Format.splitAsPercentage 2) >> Maybe.withDefault (text "N/A")
}
, { label = "Description"
, toValue = Table.StringValue .description
diff --git a/src/Server.elm b/src/Server.elm
index 8de961528..8eb04f5c4 100644
--- a/src/Server.elm
+++ b/src/Server.elm
@@ -19,7 +19,6 @@ import Data.Textile.Material as Material exposing (Material)
import Data.Textile.Product as TextileProduct exposing (Product)
import Data.Textile.Query as TextileQuery
import Data.Textile.Simulator as Simulator exposing (Simulator)
-import Json.Decode as Decode
import Json.Encode as Encode
import Route as WebRoute
import Server.Query as Query
@@ -277,41 +276,40 @@ handleRequest db request =
|> respondWith 400
-- POST routes
- Just Route.FoodPostRecipe ->
- request.body
- |> handleDecodeBody BuilderQuery.decode
- (\query ->
- executeFoodQuery db (toFoodResults query) query
- )
-
- Just Route.TextilePostSimulator ->
- request.body
- |> handleDecodeBody TextileQuery.decode
- (executeTextileQuery db toAllImpactsSimple)
-
- Just Route.TextilePostSimulatorDetailed ->
- request.body
- |> handleDecodeBody TextileQuery.decode
- (executeTextileQuery db Simulator.encode)
-
- Just (Route.TextilePostSimulatorSingle trigram) ->
- request.body
- |> handleDecodeBody TextileQuery.decode
- (executeTextileQuery db (toSingleImpactSimple trigram))
+ Just (Route.FoodPostRecipe (Ok foodQuery)) ->
+ executeFoodQuery db (toFoodResults foodQuery) foodQuery
- Nothing ->
- encodeStringError "Endpoint doesn't exist"
- |> respondWith 404
+ Just (Route.FoodPostRecipe (Err error)) ->
+ Encode.string error
+ |> respondWith 400
+ Just (Route.TextilePostSimulator (Ok textileQuery)) ->
+ textileQuery
+ |> executeTextileQuery db toAllImpactsSimple
-handleDecodeBody : Decode.Decoder a -> (a -> JsonResponse) -> Encode.Value -> JsonResponse
-handleDecodeBody decoder mapper jsonBody =
- case Decode.decodeValue decoder jsonBody of
- Err error ->
- ( 400, Encode.string (Decode.errorToString error) )
+ Just (Route.TextilePostSimulator (Err error)) ->
+ Encode.string error
+ |> respondWith 400
+
+ Just (Route.TextilePostSimulatorDetailed (Ok textileQuery)) ->
+ textileQuery
+ |> executeTextileQuery db Simulator.encode
- Ok x ->
- mapper x
+ Just (Route.TextilePostSimulatorDetailed (Err error)) ->
+ Encode.string error
+ |> respondWith 400
+
+ Just (Route.TextilePostSimulatorSingle (Ok textileQuery) trigram) ->
+ textileQuery
+ |> executeTextileQuery db (toSingleImpactSimple trigram)
+
+ Just (Route.TextilePostSimulatorSingle (Err error) _) ->
+ Encode.string error
+ |> respondWith 400
+
+ Nothing ->
+ encodeStringError "Endpoint doesn't exist"
+ |> respondWith 404
update : Msg -> Cmd Msg
diff --git a/src/Server/Query.elm b/src/Server/Query.elm
index 393c61677..68e2420ed 100644
--- a/src/Server/Query.elm
+++ b/src/Server/Query.elm
@@ -15,7 +15,6 @@ import Data.Food.Query as BuilderQuery
import Data.Food.Retail as Retail exposing (Distribution)
import Data.Scope as Scope exposing (Scope)
import Data.Split as Split exposing (Split)
-import Data.Textile.Db as Textile
import Data.Textile.DyeingMedium as DyeingMedium exposing (DyeingMedium)
import Data.Textile.Economics as Economics
import Data.Textile.Fabric as Fabric exposing (Fabric)
@@ -33,6 +32,7 @@ import Mass exposing (Mass)
import Quantity
import Regex
import Result.Extra as RE
+import Static.Db exposing (Db)
import Url.Parser.Query as Query exposing (Parser)
@@ -63,8 +63,8 @@ succeed =
always >> Query.custom ""
-parseFoodQuery : List Country -> Food.Db -> Parser (Result Errors BuilderQuery.Query)
-parseFoodQuery countries food =
+parseFoodQuery : Db -> Parser (Result Errors BuilderQuery.Query)
+parseFoodQuery { countries, food } =
succeed (Ok BuilderQuery.Query)
|> apply (distributionParser "distribution")
|> apply (ingredientListParser "ingredients" countries food)
@@ -281,9 +281,8 @@ validatePhysicalDurability string =
)
else
- Ok durability
+ Ok (Unit.PhysicalDurability durability)
)
- |> Result.map Unit.PhysicalDurability
maybeTransformParser : String -> List FoodProcess.Process -> Parser (ParseResult (Maybe BuilderQuery.ProcessQuery))
@@ -384,8 +383,8 @@ parseTransform_ transforms string =
Err <| "Format de procédé de transformation invalide : " ++ string ++ "."
-parseTextileQuery : List Country -> Textile.Db -> Parser (Result Errors TextileQuery.Query)
-parseTextileQuery countries textile =
+parseTextileQuery : Db -> Parser (Result Errors TextileQuery.Query)
+parseTextileQuery { countries, textile } =
succeed (Ok TextileQuery.Query)
|> apply (maybeSplitParser "airTransportRatio")
|> apply (maybeBusiness "business")
@@ -884,7 +883,6 @@ encodeErrors : Errors -> Encode.Value
encodeErrors errors =
Encode.object
[ ( "errors"
- , errors
- |> Encode.dict identity Encode.string
+ , errors |> Encode.dict identity Encode.string
)
]
diff --git a/src/Server/Route.elm b/src/Server/Route.elm
index 34f519a64..6124d5951 100644
--- a/src/Server/Route.elm
+++ b/src/Server/Route.elm
@@ -3,13 +3,13 @@ module Server.Route exposing
, endpoint
)
-import Data.Country exposing (Country)
-import Data.Food.Db as Food
import Data.Food.Query as BuilderQuery
import Data.Impact as Impact
import Data.Impact.Definition as Definition
-import Data.Textile.Db as Textile
+import Data.Textile.Inputs as Inputs
import Data.Textile.Query as TextileQuery
+import Json.Decode as Decode
+import Json.Encode as Encode
import Server.Query as Query
import Server.Request exposing (Request)
import Static.Db exposing (Db)
@@ -38,7 +38,7 @@ type Route
| FoodGetTransformList
-- POST
-- Food recipe builder (POST, JSON body)
- | FoodPostRecipe
+ | FoodPostRecipe (Result String BuilderQuery.Query)
--
-- Textile Routes
-- GET
@@ -56,42 +56,73 @@ type Route
| TextileGetSimulatorSingle Definition.Trigram (Result Query.Errors TextileQuery.Query)
-- POST
-- Textile Simple version of all impacts (POST, JSON body)
- | TextilePostSimulator
+ | TextilePostSimulator (Result String TextileQuery.Query)
-- Textile Detailed version for all impacts (POST, JSON body)
- | TextilePostSimulatorDetailed
- -- Textile Simple version for one specific impact (POST, JSON bosy)
- | TextilePostSimulatorSingle Definition.Trigram
+ | TextilePostSimulatorDetailed (Result String TextileQuery.Query)
+ -- Textile Simple version for one specific impact (POST, JSON body)
+ | TextilePostSimulatorSingle (Result String TextileQuery.Query) Definition.Trigram
-parser : Food.Db -> Textile.Db -> List Country -> Parser (Route -> a) a
-parser foodDb textile countries =
+parser : Db -> Encode.Value -> Parser (Route -> a) a
+parser db body =
Parser.oneOf
[ -- Food
- Parser.map FoodGetCountryList (s "GET" > s "food" > s "countries")
- , Parser.map FoodGetIngredientList (s "GET" > s "food" > s "ingredients")
- , Parser.map FoodGetTransformList (s "GET" > s "food" > s "transforms")
- , Parser.map FoodGetPackagingList (s "GET" > s "food" > s "packagings")
- , Parser.map FoodGetRecipe (s "GET" > s "food" > Query.parseFoodQuery countries foodDb)
- , Parser.map FoodPostRecipe (s "POST" > s "food")
+ -- GET
+ (s "GET" > s "food" > s "countries")
+ |> Parser.map FoodGetCountryList
+ , (s "GET" > s "food" > s "ingredients")
+ |> Parser.map FoodGetIngredientList
+ , (s "GET" > s "food" > s "transforms")
+ |> Parser.map FoodGetTransformList
+ , (s "GET" > s "food" > s "packagings")
+ |> Parser.map FoodGetPackagingList
+ , (s "GET" > s "food" > Query.parseFoodQuery db)
+ |> Parser.map FoodGetRecipe
+ , (s "POST" > s "food")
+ |> Parser.map (FoodPostRecipe (decodeFoodQueryBody body))
-- Textile
- , Parser.map TextileGetCountryList (s "GET" > s "textile" > s "countries")
- , Parser.map TextileGetMaterialList (s "GET" > s "textile" > s "materials")
- , Parser.map TextileGetProductList (s "GET" > s "textile" > s "products")
- , Parser.map TextileGetSimulator (s "GET" > s "textile" > s "simulator" > Query.parseTextileQuery countries textile)
- , Parser.map TextileGetSimulatorDetailed (s "GET" > s "textile" > s "simulator" > s "detailed" > Query.parseTextileQuery countries textile)
- , Parser.map TextileGetSimulatorSingle (s "GET" > s "textile" > s "simulator" > Impact.parseTrigram > Query.parseTextileQuery countries textile)
- , Parser.map TextilePostSimulator (s "POST" > s "textile" > s "simulator")
- , Parser.map TextilePostSimulatorDetailed (s "POST" > s "textile" > s "simulator" > s "detailed")
- , Parser.map TextilePostSimulatorSingle (s "POST" > s "textile" > s "simulator" > Impact.parseTrigram)
+ , (s "GET" > s "textile" > s "countries")
+ |> Parser.map TextileGetCountryList
+ , (s "GET" > s "textile" > s "materials")
+ |> Parser.map TextileGetMaterialList
+ , (s "GET" > s "textile" > s "products")
+ |> Parser.map TextileGetProductList
+ , (s "GET" > s "textile" > s "simulator" > Query.parseTextileQuery db)
+ |> Parser.map TextileGetSimulator
+ , (s "GET" > s "textile" > s "simulator" > s "detailed" > Query.parseTextileQuery db)
+ |> Parser.map TextileGetSimulatorDetailed
+ , (s "GET" > s "textile" > s "simulator" > Impact.parseTrigram > Query.parseTextileQuery db)
+ |> Parser.map TextileGetSimulatorSingle
+ , (s "POST" > s "textile" > s "simulator")
+ |> Parser.map (TextilePostSimulator (decodeTextileQueryBody db body))
+ , (s "POST" > s "textile" > s "simulator" > s "detailed")
+ |> Parser.map (TextilePostSimulatorDetailed (decodeTextileQueryBody db body))
+ , (s "POST" > s "textile" > s "simulator" > Impact.parseTrigram)
+ |> Parser.map (TextilePostSimulatorSingle (decodeTextileQueryBody db body))
]
+decodeFoodQueryBody : Encode.Value -> Result String BuilderQuery.Query
+decodeFoodQueryBody =
+ Decode.decodeValue BuilderQuery.decode
+ >> Result.mapError Decode.errorToString
+
+
+decodeTextileQueryBody : Db -> Encode.Value -> Result String TextileQuery.Query
+decodeTextileQueryBody db =
+ Decode.decodeValue TextileQuery.decode
+ >> Result.mapError Decode.errorToString
+ -- Note: Using inputs mapping to act as query validation
+ >> Result.andThen (Inputs.fromQuery db)
+ >> Result.map Inputs.toQuery
+
+
endpoint : Db -> Request -> Maybe Route
-endpoint { countries, food, textile } { method, url } =
+endpoint db { body, method, url } =
-- Notes:
-- - Url.fromString can't build a Url without a fully qualified URL, so as we only have the
-- request path from Express, we build a fake URL with a fake protocol and hostname.
-- - We update the path appending the HTTP method to it, for simpler, cheaper route parsing.
Url.fromString ("http://x/" ++ method ++ url)
- |> Maybe.andThen (Parser.parse (parser food textile countries))
+ |> Maybe.andThen (Parser.parse (parser db body))
diff --git a/src/Views/Format.elm b/src/Views/Format.elm
index b3f7f8655..5955d71d0 100644
--- a/src/Views/Format.elm
+++ b/src/Views/Format.elm
@@ -16,7 +16,6 @@ module Views.Format exposing
, percent
, picking
, priceInEUR
- , ratio
, splitAsFloat
, splitAsPercentage
, squareMeters
@@ -213,17 +212,6 @@ yarnSize =
Unit.yarnSizeInKilometers >> formatRichFloat 0 "Nm"
-ratio : Unit.Ratio -> Html msg
-ratio =
- ratioToDecimals 2
-
-
-ratioToDecimals : Int -> Unit.Ratio -> Html msg
-ratioToDecimals decimals (Unit.Ratio float) =
- (float * 100)
- |> formatRichFloat decimals "%"
-
-
splitAsFloat : Int -> Split -> Html msg
splitAsFloat int value =
Split.toFloat value
diff --git a/tests/Data/ImpactTest.elm b/tests/Data/ImpactTest.elm
index 390622c20..b788d73f8 100644
--- a/tests/Data/ImpactTest.elm
+++ b/tests/Data/ImpactTest.elm
@@ -2,6 +2,7 @@ module Data.ImpactTest exposing (..)
import Data.Impact as Impact
import Data.Impact.Definition as Definition
+import Data.Split as Split
import Data.Unit as Unit
import Expect
import Mass
@@ -99,7 +100,7 @@ suite =
|> List.map (\trigram -> Definition.get trigram db.definitions)
|> List.filterMap .ecoscoreData
|> List.map .weighting
- |> List.map Unit.ratioToFloat
+ |> List.map Split.toFloat
|> List.sum
|> Expect.within (Expect.Absolute 0.01) 1
|> asTest "should be 1"
@@ -109,34 +110,10 @@ suite =
|> List.map (\trigram -> Definition.get trigram db.definitions)
|> List.filterMap .pefData
|> List.map .weighting
- |> List.map Unit.ratioToFloat
+ |> List.map Split.toFloat
|> List.sum
|> Expect.within (Expect.Absolute 0.01) 1
|> asTest "should be 1"
]
- , describe "setEcotoxWeighting"
- [ db.definitions
- |> Impact.setEcotoxWeighting (Unit.ratio 0)
- |> Definition.get Definition.Acd
- |> .ecoscoreData
- |> Maybe.map (.weighting >> Unit.ratioToFloat)
- |> Maybe.withDefault -99
- |> Expect.within (Expect.Absolute 0.001) 0.067
- |> asTest "should update other weightings"
- , db.definitions
- |> Impact.setEcotoxWeighting (Unit.ratio 0)
- |> Definition.toList
- |> List.filterMap (.ecoscoreData >> Maybe.map (.weighting >> Unit.ratioToFloat))
- |> List.sum
- |> Expect.within (Expect.Absolute 0.001) 1
- |> asTest "should sum all Ecs weightings to 100% when EtfC is set to 0"
- , db.definitions
- |> Impact.setEcotoxWeighting (Unit.ratio 0.25)
- |> Definition.toList
- |> List.filterMap (.ecoscoreData >> Maybe.map (.weighting >> Unit.ratioToFloat))
- |> List.sum
- |> Expect.within (Expect.Absolute 0.001) 1
- |> asTest "should sum all Ecs weightings to 100% when EtfC is set to 25"
- ]
]
)
diff --git a/tests/Data/Textile/FormulaTest.elm b/tests/Data/Textile/FormulaTest.elm
index 3665eb21e..216e02f70 100644
--- a/tests/Data/Textile/FormulaTest.elm
+++ b/tests/Data/Textile/FormulaTest.elm
@@ -28,20 +28,20 @@ km =
noOpProcess : Process
noOpProcess =
- { name = "Default"
+ { alias = Nothing
+ , correctif = ""
, displayName = Just "Default"
+ , elec = Energy.megajoules 0
+ , elec_pppm = 0
+ , heat = Energy.megajoules 0
+ , impacts = Impact.empty
, info = ""
- , unit = ""
- , uuid = Process.Uuid ""
+ , name = "Default"
, source = ""
- , correctif = ""
, stepUsage = ""
- , impacts = Impact.empty
- , heat = Energy.megajoules 0
- , elec_pppm = 0
- , elec = Energy.megajoules 0
- , waste = Unit.ratio 0
- , alias = Nothing
+ , unit = ""
+ , uuid = Process.Uuid ""
+ , waste = Split.zero
}
@@ -57,15 +57,9 @@ suite =
in
[ describe "Formula.genericWaste"
[ kg 1
- |> Formula.genericWaste (Unit.ratio 0.5)
- |> Expect.equal { mass = kg 1.5, waste = kg 0.5 }
- |> asTest "should compute material waste"
- ]
- , describe "Formula.makingWaste"
- [ kg 1
- |> Formula.makingWaste Split.half
+ |> Formula.genericWaste Split.half
|> Expect.equal { mass = kg 2, waste = kg 1 }
- |> asTest "should compute material waste from material and product waste data"
+ |> asTest "should compute generic waste using input waste ratio"
]
, describe "Formula.makingDeadStock"
[ kg 1
diff --git a/tests/Data/Textile/LifeCycleTest.elm b/tests/Data/Textile/LifeCycleTest.elm
index c1b588124..1f9d74521 100644
--- a/tests/Data/Textile/LifeCycleTest.elm
+++ b/tests/Data/Textile/LifeCycleTest.elm
@@ -31,7 +31,7 @@ suite =
|> Result.andThen (lifeCycleToTransports db tShirtCotonFrance)
|> Result.map LifeCycle.computeTotalTransportImpacts
|> Result.map (\{ road, sea } -> ( Length.inKilometers road, Length.inKilometers sea ))
- |> Expect.equal (Ok ( 2000, 21549 ))
+ |> Expect.equal (Ok ( 2500, 21549 ))
|> asTest "should compute default distances"
, let
tShirtCotonEnnoblementIndia =
@@ -46,7 +46,7 @@ suite =
|> Result.andThen (lifeCycleToTransports db tShirtCotonEnnoblementIndia)
|> Result.map LifeCycle.computeTotalTransportImpacts
|> Result.map (\{ road, sea } -> ( Length.inKilometers road, Length.inKilometers sea ))
- |> Expect.equal (Ok ( 1000, 45471 ))
+ |> Expect.equal (Ok ( 1500, 45471 ))
|> asTest "should compute custom distances"
]
]
diff --git a/tests/Data/Textile/SimulatorTest.elm b/tests/Data/Textile/SimulatorTest.elm
index 88c1eab74..dc8d39a7b 100644
--- a/tests/Data/Textile/SimulatorTest.elm
+++ b/tests/Data/Textile/SimulatorTest.elm
@@ -1,7 +1,10 @@
module Data.Textile.SimulatorTest exposing (..)
+import Data.Country as Country
import Data.Impact as Impact
import Data.Impact.Definition as Definition
+import Data.Split as Split
+import Data.Textile.Economics as Economics
import Data.Textile.LifeCycle as LifeCycle
import Data.Textile.Query exposing (Query, tShirtCotonFrance)
import Data.Textile.Simulator as Simulator
@@ -47,7 +50,7 @@ suite =
[ { tShirtCotonFrance
| countrySpinning = Nothing
}
- |> expectImpact db ecs 1469.1531378179673
+ |> expectImpact db ecs 1473.9780976999311
|> asTest "should compute a simulation ecs impact"
, describe "disabled steps"
[ { tShirtCotonFrance | disabledSteps = [ Label.Ennobling ] }
@@ -81,6 +84,69 @@ suite =
)
]
]
+ , let
+ tShirtCotonWithSmallerPhysicalDurability =
+ { tShirtCotonFrance
+ | numberOfReferences = Just 10
+ , price = Just <| Economics.priceFromFloat 100
+ , physicalDurability = Just <| Unit.physicalDurability 1
+ }
+ in
+ describe "compute holistic durability"
+ [ tShirtCotonFrance
+ |> Simulator.compute db
+ |> Result.map .durability
+ |> Expect.equal (Ok { physical = Unit.physicalDurability 1.45, nonPhysical = Unit.nonPhysicalDurability 0.67 })
+ |> asTest "should have default durability"
+ , { physical = Unit.physicalDurability 1.45, nonPhysical = Unit.nonPhysicalDurability 0.67 }
+ |> Unit.floatDurabilityFromHolistic
+ |> Expect.within (Expect.Absolute 0.001) 0.67
+ |> asTest "should take the min of the two durabilities"
+ , tShirtCotonWithSmallerPhysicalDurability
+ |> Simulator.compute db
+ |> Result.map .durability
+ |> Expect.equal (Ok { physical = Unit.physicalDurability 1, nonPhysical = Unit.nonPhysicalDurability 1.19 })
+ |> asTest "should take into account when non physical durability changes"
+ , tShirtCotonWithSmallerPhysicalDurability
+ |> Simulator.compute db
+ |> Result.map (.durability >> Unit.floatDurabilityFromHolistic)
+ |> Expect.equal (Ok 1)
+ |> asTest "should return non physical durability if it is the smallest"
+ ]
+ , let
+ tShirtCotonWithSmallerPhysicalDurabilityCn =
+ { tShirtCotonFrance
+ | numberOfReferences = Just 10
+ , price = Just <| Economics.priceFromFloat 100
+ , physicalDurability = Just <| Unit.physicalDurability 1.1
+ , countryMaking = Just (Country.Code "CN")
+ }
+ in
+ describe "compute airTransporRatio"
+ [ tShirtCotonFrance
+ |> Simulator.compute db
+ |> Result.map (.lifeCycle >> LifeCycle.getStepProp Label.Making .airTransportRatio Split.half)
+ |> Expect.equal (Ok Split.zero)
+ |> asTest "should be zero for products from Europe or Turkey"
+ , { tShirtCotonFrance | countryMaking = Just (Country.Code "CN") }
+ |> Simulator.compute db
+ |> Result.map (.lifeCycle >> LifeCycle.getStepProp Label.Making .airTransportRatio Split.half)
+ |> Expect.equal (Ok Split.full)
+ |> asTest "should be full for products not coming from Europe or Turkey"
+ , tShirtCotonWithSmallerPhysicalDurabilityCn
+ |> Simulator.compute db
+ |> Result.map (.lifeCycle >> LifeCycle.getStepProp Label.Making .airTransportRatio Split.half)
+ |> Expect.equal (Ok Split.third)
+ |> asTest "should be 0.33 for products not coming from Europe or Turkey but with a durability >= 1"
+ , { tShirtCotonFrance
+ | countryMaking = Just (Country.Code "CN")
+ , airTransportRatio = Just Split.two
+ }
+ |> Simulator.compute db
+ |> Result.map (.lifeCycle >> LifeCycle.getStepProp Label.Making .airTransportRatio Split.half)
+ |> Expect.equal (Ok Split.two)
+ |> asTest "should keep the user provided value"
+ ]
, describe "getTotalImpactsWithoutComplements"
[ tShirtCotonFrance
|> Simulator.compute db
diff --git a/tests/Data/UnitTest.elm b/tests/Data/UnitTest.elm
index f52fce313..a364b4fdf 100644
--- a/tests/Data/UnitTest.elm
+++ b/tests/Data/UnitTest.elm
@@ -1,5 +1,6 @@
module Data.UnitTest exposing (..)
+import Data.Split as Split
import Data.Unit as Unit
import Energy
import Expect exposing (Expectation)
@@ -24,15 +25,6 @@ suite =
|> Result.mapError Decode.errorToString
|> Expect.err
|> asTest "should discard erroneous Durability value"
- , "1.1"
- |> Decode.decodeString (Unit.decodeRatio { percentage = True })
- |> Result.mapError Decode.errorToString
- |> Expect.err
- |> asTest "should discard erroneous Ratio value"
- , "1.1"
- |> Decode.decodeString (Unit.decodeRatio { percentage = False })
- |> Expect.ok
- |> asTest "should not discard a non-percentage value"
, "8868687687"
|> Decode.decodeString Unit.decodeSurfaceMass
|> Result.mapError Decode.errorToString
@@ -48,15 +40,15 @@ suite =
]
, describe "Unit.impactAggregateScore"
[ Unit.impact 1
- |> Unit.impactAggregateScore (Unit.impact 1) (Unit.ratio 1)
+ |> Unit.impactAggregateScore (Unit.impact 1) Split.full
|> Expect.equal (Unit.impact 1000000)
|> asTest "should compute impact aggregate score (1, 1)"
, Unit.impact 1
- |> Unit.impactAggregateScore (Unit.impact 2) (Unit.ratio 0.5)
+ |> Unit.impactAggregateScore (Unit.impact 2) Split.half
|> Expect.equal (Unit.impact 250000)
|> asTest "should compute impact aggregate score (1, 0.5)"
, Unit.impact 1
- |> Unit.impactAggregateScore (Unit.impact 0.25) (Unit.ratio 0.75)
+ |> Unit.impactAggregateScore (Unit.impact 0.25) (Split.fromFloat 0.75 |> Result.withDefault Split.zero)
|> Expect.equal (Unit.impact 3000000)
|> asTest "should compute impact aggregate score (0.25, 0.75)"
]
diff --git a/tests/Server/RouteTest.elm b/tests/Server/RouteTest.elm
index 9ea98dab0..5dfc26eac 100644
--- a/tests/Server/RouteTest.elm
+++ b/tests/Server/RouteTest.elm
@@ -12,6 +12,7 @@ import Data.Textile.Material.Spinning as Spinning
import Data.Textile.Process as TextileProcess
import Data.Textile.Query as Query exposing (Query, tShirtCotonFrance)
import Data.Textile.Step.Label as Label
+import Data.Unit as Unit
import Dict exposing (Dict)
import Expect
import Json.Encode as Encode
@@ -75,12 +76,12 @@ foodEndpoints db =
, describe "POST endpoints"
[ "/food"
|> testEndpoint db "POST" (FoodQuery.encode FoodQuery.empty)
- |> Expect.equal (Just Route.FoodPostRecipe)
+ |> Expect.equal (Just (Route.FoodPostRecipe (Ok FoodQuery.empty)))
|> asTest "should map the POST /food endpoint"
, "/food"
|> testEndpoint db "POST" Encode.null
- |> Expect.equal (Just Route.FoodPostRecipe)
- |> asTest "should map the POST /food endpoint whatever the request body is"
+ |> expectFoodSingleErrorContains "ingredients"
+ |> asTest "should fail on invalid query passed"
]
, describe "validation"
[ testEndpoint db "GET" Encode.null "/food?ingredients[]=egg-indoor-code3|0"
@@ -216,12 +217,49 @@ textileEndpoints db =
, describe "POST endpoints"
[ "/textile/simulator"
|> testEndpoint db "POST" (Query.encode tShirtCotonFrance)
- |> Expect.equal (Just Route.TextilePostSimulator)
- |> asTest "should map the POST /textile/simulator endpoint"
+ |> Expect.equal (Just (Route.TextilePostSimulator (Ok tShirtCotonFrance)))
+ |> asTest "should map the POST /textile/simulator endpoint with the body parsed as a valid query"
, "/textile/simulator"
|> testEndpoint db "POST" Encode.null
- |> Expect.equal (Just Route.TextilePostSimulator)
- |> asTest "should map the POST /textile/simulator endpoint whatever the request body is"
+ |> Expect.equal (Just (Route.TextilePostSimulator (Err "Problem with the given value:\n\nnull\n\nExpecting an OBJECT with a field named `product`")))
+ |> asTest "should map the POST /textile/simulator endpoint with an error when json body is invalid"
+ , "/textile/simulator"
+ |> testEndpoint db
+ "POST"
+ (Query.encode
+ { tShirtCotonFrance
+ | physicalDurability =
+ Just <| Unit.physicalDurability 9900000
+ }
+ )
+ |> expectTextileSingleErrorContains "physicalDurability"
+ |> asTest "should reject invalid physicalDurability"
+ , "/textile/simulator"
+ |> testEndpoint db
+ "POST"
+ (Query.encode
+ { tShirtCotonFrance
+ | countrySpinning = Just (Country.Code "invalid")
+ }
+ )
+ |> Expect.equal (Just (Route.TextilePostSimulator (Err "Code pays invalide: invalid.")))
+ |> asTest "should reject invalid spinning country"
+ , "/textile/simulator"
+ |> testEndpoint db
+ "POST"
+ (Query.encode
+ { tShirtCotonFrance
+ | materials =
+ [ { country = Just (Country.Code "invalid")
+ , id = Material.Id "ei-coton"
+ , share = Split.full
+ , spinning = Nothing
+ }
+ ]
+ }
+ )
+ |> Expect.equal (Just (Route.TextilePostSimulator (Err "Code pays invalide: invalid.")))
+ |> asTest "should reject invalid materials country"
]
, describe "materials param checks"
[ let
@@ -394,7 +432,14 @@ testEndpoint dbs method body url =
{ method = method
, url = url
, body = body
- , processes = { foodProcesses = Encode.list FoodProcess.encode dbs.food.processes |> Encode.encode 0, textileProcesses = Encode.list TextileProcess.encode dbs.textile.processes |> Encode.encode 0 }
+ , processes =
+ { foodProcesses =
+ Encode.list FoodProcess.encode dbs.food.processes
+ |> Encode.encode 0
+ , textileProcesses =
+ Encode.list TextileProcess.encode dbs.textile.processes
+ |> Encode.encode 0
+ }
, jsResponseHandler = Encode.null
}
@@ -427,3 +472,23 @@ extractTextileErrors route =
_ ->
Nothing
+
+
+expectFoodSingleErrorContains : String -> Maybe Route.Route -> Expect.Expectation
+expectFoodSingleErrorContains str route =
+ case route of
+ Just (Route.FoodPostRecipe (Err err)) ->
+ Expect.equal (String.contains str err) True
+
+ _ ->
+ Expect.fail "No matching error found"
+
+
+expectTextileSingleErrorContains : String -> Maybe Route.Route -> Expect.Expectation
+expectTextileSingleErrorContains str route =
+ case route of
+ Just (Route.TextilePostSimulator (Err err)) ->
+ Expect.equal (String.contains str err) True
+
+ _ ->
+ Expect.fail "No matching error found"
diff --git a/tests/e2e-food.json b/tests/e2e-food.json
index 216d0181f..82c6fe328 100644
--- a/tests/e2e-food.json
+++ b/tests/e2e-food.json
@@ -28,7 +28,7 @@
"scoring": {
"all": 1384.2968296621593,
"climate": 517.6798374796787,
- "biodiversity": 430.8042070391977,
+ "biodiversity": 430.80420703919776,
"health": 139.12974375280868,
"resources": 296.6830413904739
}
@@ -164,7 +164,7 @@
"scoring": {
"all": 136.84213596200448,
"climate": 22.327421210725763,
- "biodiversity": 64.54418913083381,
+ "biodiversity": 64.54418913083383,
"health": 14.535423007764042,
"resources": 35.43510261268088
}
diff --git a/tests/e2e-textile.json b/tests/e2e-textile.json
index 72612dcb2..ee03eaee0 100644
--- a/tests/e2e-textile.json
+++ b/tests/e2e-textile.json
@@ -10,27 +10,27 @@
"countryMaking=FR"
],
"impacts": {
- "acd": 0.0414446685749946,
- "cch": 6.048874393344061,
- "etf": 133.45735497327883,
- "etf-c": 281.03257869705175,
- "fru": 108.41610613408756,
- "fwe": 0.0015967563755970645,
- "htc": 9.202232406694513e-10,
- "htc-c": 1.5167242473017484e-9,
- "htn": 2.2684998010224684e-8,
- "htn-c": 3.378964481489889e-8,
- "ior": 13.313345405119325,
- "ldu": 105.51839908615344,
- "mru": 0.000052078700426912154,
- "ozd": 0.000030370478290087493,
- "pco": 0.016994499640779308,
- "pma": 3.6240125804991626e-7,
- "swe": 0.02536100942287826,
- "tre": 0.12574953428356123,
- "wtu": 13.97456474348671,
- "ecs": 1469.1531378179673,
- "pef": 939.757440532827
+ "acd": 0.04163544680574335,
+ "cch": 6.076074899448809,
+ "etf": 134.0863054530789,
+ "etf-c": 282.1219011261312,
+ "fru": 108.75723225108744,
+ "fwe": 0.0016020599526329704,
+ "htc": 9.324883616149098e-10,
+ "htc-c": 1.5316938071499886e-9,
+ "htn": 2.2958539136038225e-8,
+ "htn-c": 3.396278638169421e-8,
+ "ior": 13.313836563271293,
+ "ldu": 106.0312189737267,
+ "mru": 0.000052176453397729595,
+ "ozd": 0.00003037113615558597,
+ "pco": 0.017158026522891636,
+ "pma": 3.650629404142302e-7,
+ "swe": 0.025467662607441162,
+ "tre": 0.12648609991631055,
+ "wtu": 14.022971246600134,
+ "ecs": 1473.9780976999311,
+ "pef": 942.9643784896306
}
},
{
@@ -45,27 +45,27 @@
"countryMaking=FR"
],
"impacts": {
- "acd": 0.03999283350554488,
- "cch": 5.591496973560117,
- "etf": 132.02731216356787,
- "etf-c": 279.6313964116634,
- "fru": 105.51519866597374,
- "fwe": 0.0021399640093722767,
- "htc": 9.132619864558306e-10,
- "htc-c": 1.493391231958824e-9,
- "htn": 2.2556947321763515e-8,
- "htn-c": 3.3337697852860114e-8,
- "ior": 13.299228897821145,
- "ldu": 103.94093137151837,
- "mru": 0.00005200935295978153,
- "ozd": 0.000030381656157113567,
- "pco": 0.015366462287409441,
- "pma": 2.9198939677060944e-7,
- "swe": 0.024843458237795588,
- "tre": 0.11892004198055697,
- "wtu": 14.11834524471008,
- "ecs": 1445.545062184085,
- "pef": 916.5851663113473
+ "acd": 0.04017877886165545,
+ "cch": 5.617174959801102,
+ "etf": 132.65150231089498,
+ "etf-c": 280.7160545793037,
+ "fru": 105.84666823008729,
+ "fwe": 0.00214707581824648,
+ "htc": 9.255039347492112e-10,
+ "htc-c": 1.5082831207682146e-9,
+ "htn": 2.2830062191910908e-8,
+ "htn-c": 3.3509334976722056e-8,
+ "ior": 13.299673064884704,
+ "ldu": 104.44850017797987,
+ "mru": 0.000052106875086460975,
+ "ozd": 0.000030382351231542455,
+ "pco": 0.015524569751985531,
+ "pma": 2.944166918372446e-7,
+ "swe": 0.02494838859581367,
+ "tre": 0.1196338735708263,
+ "wtu": 14.167230364956025,
+ "ecs": 1450.2914354053546,
+ "pef": 919.7149683050168
}
},
{
@@ -80,27 +80,27 @@
"countryMaking=FR"
],
"impacts": {
- "acd": 0.05726100108538642,
- "cch": 11.430678438438557,
- "etf": 15.277459947025957,
- "etf-c": 34.84265300567465,
- "fru": 206.01535100674178,
- "fwe": 0.0011795776587754671,
- "htc": 1.154092004935306e-9,
- "htc-c": 9.46355705568073e-10,
- "htn": 1.6726140174842664e-8,
- "htn-c": 8.465101714748085e-9,
- "ior": 13.251490281828953,
- "ldu": 21.306122733566685,
- "mru": 0.00007180961970512356,
- "ozd": 0.000051345605385998686,
- "pco": 0.03355570801711961,
- "pma": 5.336713519599066e-7,
- "swe": 0.011700116042033405,
- "tre": 0.07875433537173472,
- "wtu": 1.164646515699395,
- "ecs": 1617.374306804295,
- "pef": 1143.2791117460363
+ "acd": 0.057581557642514186,
+ "cch": 11.486772334324144,
+ "etf": 15.634225651652217,
+ "etf-c": 35.30084273467208,
+ "fru": 206.83621120280137,
+ "fwe": 0.0011841875998579946,
+ "htc": 1.1733390915883777e-9,
+ "htc-c": 9.657327058055596e-10,
+ "htn": 1.7104907125727847e-8,
+ "htn-c": 8.594192534789848e-9,
+ "ior": 13.251972542033904,
+ "ldu": 21.656481609935792,
+ "mru": 0.00007192741894281859,
+ "ozd": 0.00005134618451117797,
+ "pco": 0.03386786925642574,
+ "pma": 5.381982335152771e-7,
+ "swe": 0.011781122757516282,
+ "tre": 0.07959215390253874,
+ "wtu": 1.1726385765499685,
+ "ecs": 1622.3567024833867,
+ "pef": 1148.1148870018326
}
},
{
@@ -116,27 +116,27 @@
"countryMaking=FR"
],
"impacts": {
- "acd": 0.03136758199562056,
- "cch": 5.73617958103508,
- "etf": 73.59235960432358,
- "etf-c": 150.75526890312173,
- "fru": 115.00637146175967,
- "fwe": 0.0012020066613822507,
- "htc": 9.285876200879071e-10,
- "htc-c": 1.4260328317647246e-9,
- "htn": 1.6450048443954115e-8,
- "htn-c": 1.8946423613892236e-8,
- "ior": 13.307040510287745,
- "ldu": 60.43084658264571,
- "mru": 0.000051638439899460184,
- "ozd": 0.00003306021378271851,
- "pco": 0.014406513880314486,
- "pma": 2.9841384996321926e-7,
- "swe": 0.015247390003884994,
- "tre": 0.0802112463977537,
- "wtu": 6.938926153229093,
- "ecs": 1264.253322580562,
- "pef": 808.6650530625744
+ "acd": 0.03152481557850885,
+ "cch": 5.7623391873436365,
+ "etf": 74.02203123770292,
+ "etf-c": 151.43828158178619,
+ "fru": 115.3694352814857,
+ "fwe": 0.0012059961939220561,
+ "htc": 9.408805844144814e-10,
+ "htc-c": 1.4406978925029883e-9,
+ "htn": 1.670283464363093e-8,
+ "htn-c": 1.906926773536258e-8,
+ "ior": 13.307510680679485,
+ "ldu": 60.793578837279895,
+ "mru": 0.00005173472732919651,
+ "ozd": 0.000033069825250950026,
+ "pco": 0.014561425864626854,
+ "pma": 3.008625307764535e-7,
+ "swe": 0.015320376929918441,
+ "tre": 0.08079622398774226,
+ "wtu": 6.9639123932412055,
+ "ecs": 1267.9101496135304,
+ "pef": 811.4356101328748
}
},
{
@@ -151,27 +151,27 @@
"disabledSteps=ennobling"
],
"impacts": {
- "acd": 0.03285061747828521,
- "cch": 3.467462533557159,
- "etf": 131.19165884805642,
- "etf-c": 251.917120164505,
- "fru": 83.19386944418443,
- "fwe": 0.0012812928247882068,
- "htc": 6.877700085487217e-10,
- "htc-c": 1.2672109600073182e-9,
- "htn": 1.772755177044944e-8,
- "htn-c": 3.327076914892387e-8,
- "ior": 12.844016464249076,
- "ldu": 100.36714158360871,
- "mru": 0.000015799120970367426,
- "ozd": 1.771166191843897e-7,
- "pco": 0.013530668136250815,
- "pma": 2.8119502121058356e-7,
- "swe": 0.02256153447477876,
- "tre": 0.11731038150597263,
- "wtu": 13.893385126239512,
- "ecs": 1211.9684170584155,
- "pef": 711.1273507916327
+ "acd": 0.03304139570903395,
+ "cch": 3.4946630396619085,
+ "etf": 131.8206093278565,
+ "etf-c": 253.00644259358452,
+ "fru": 83.53499556118432,
+ "fwe": 0.0012865964018241127,
+ "htc": 7.000351294941802e-10,
+ "htc-c": 1.2821805198555586e-9,
+ "htn": 1.8001092896262975e-8,
+ "htn-c": 3.344391071571918e-8,
+ "ior": 12.844507622401041,
+ "ldu": 100.87996147118199,
+ "mru": 0.000015896873941184877,
+ "ozd": 1.7777448468287237e-7,
+ "pco": 0.013694195018363142,
+ "pma": 2.838567035748975e-7,
+ "swe": 0.022668187659341657,
+ "tre": 0.11804694713872195,
+ "wtu": 13.941791629352936,
+ "ecs": 1216.7933769403794,
+ "pef": 714.3342887484364
}
},
{
@@ -188,27 +188,27 @@
"airTransportRatio=1"
],
"impacts": {
- "acd": 0.17722447021175042,
- "cch": 29.220539830763823,
- "etf": 398.0046362304084,
- "etf-c": 927.7108872905228,
- "fru": 305.7735885010402,
- "fwe": 0.005856123911524636,
- "htc": 4.293770543739464e-9,
- "htc-c": 6.2789577774944456e-9,
- "htn": 1.2409315049478433e-7,
- "htn-c": 9.004875552369704e-8,
- "ior": 16.32624483164245,
- "ldu": 274.3683670172822,
- "mru": 0.00014282364800809327,
- "ozd": 0.00008057387845328036,
- "pco": 0.09732511847581189,
- "pma": 0.000001964238741109258,
- "swe": 0.07968554841428832,
- "tre": 0.5001375997947459,
- "wtu": 35.02468574572376,
- "ecs": 5024.788688895064,
- "pef": 3043.3311917520828
+ "acd": 0.17776530284519634,
+ "cch": 29.29713112389512,
+ "etf": 400.0061382866833,
+ "etf-c": 931.1534694580287,
+ "fru": 306.7250384898656,
+ "fwe": 0.005872724272504519,
+ "htc": 4.330174862471458e-9,
+ "htc-c": 6.325543794413083e-9,
+ "htn": 1.2485534139249358e-7,
+ "htn-c": 9.056708643635269e-8,
+ "ior": 16.32772384454294,
+ "ldu": 275.870695207961,
+ "mru": 0.00014311958620352283,
+ "ozd": 0.00008057582979176627,
+ "pco": 0.09775567050471355,
+ "pma": 0.0000019718066464557678,
+ "swe": 0.08000116470598892,
+ "tre": 0.5022110547143145,
+ "wtu": 35.180613817523366,
+ "ecs": 4811.167813476992,
+ "pef": 3052.638092437028
}
},
{
@@ -224,27 +224,27 @@
"fading=true"
],
"impacts": {
- "acd": 0.19765495767367622,
- "cch": 27.714300828756784,
- "etf": 391.55199166555997,
- "etf-c": 984.5710735849585,
- "fru": 283.18635414809796,
- "fwe": 0.013010486351602946,
- "htc": 4.166350461842815e-9,
- "htc-c": 6.058019344719065e-9,
- "htn": 1.0808654876338244e-7,
- "htn-c": 9.655709496179501e-8,
- "ior": 16.250956157882147,
- "ldu": 314.33702358990746,
- "mru": 0.00014643102143022628,
- "ozd": 0.00008275031953862176,
- "pco": 0.08218189933890796,
- "pma": 0.0000019579238422117716,
- "swe": 0.0865174249238061,
- "tre": 0.4693534112163854,
- "wtu": 40.98087480750406,
- "ecs": 4965.610570161154,
- "pef": 3154.4908547939185
+ "acd": 0.19650754361129413,
+ "cch": 27.34278194470025,
+ "etf": 390.8126880668444,
+ "etf-c": 985.4292861961296,
+ "fru": 278.1848505021621,
+ "fwe": 0.013024377908051372,
+ "htc": 4.162600787641573e-9,
+ "htc-c": 6.082474936122221e-9,
+ "htn": 1.0400791489444354e-7,
+ "htn-c": 9.70449168665708e-8,
+ "ior": 16.251032132818466,
+ "ldu": 315.86133436995925,
+ "mru": 0.00014671716699291178,
+ "ozd": 0.00008274534837021724,
+ "pco": 0.08009650824743483,
+ "pma": 0.0000019636491591381196,
+ "swe": 0.08611009389584703,
+ "tre": 0.4635144069953214,
+ "wtu": 41.14890419887185,
+ "ecs": 4949.858297610277,
+ "pef": 3134.1630944264157
}
},
{
@@ -260,27 +260,27 @@
"fading=false"
],
"impacts": {
- "acd": 0.16919839778952084,
- "cch": 23.777660767811263,
- "etf": 382.96933902601796,
- "etf-c": 975.3936690299714,
- "fru": 245.73287357468237,
- "fwe": 0.011027564651083278,
- "htc": 3.2119930442141052e-9,
- "htc-c": 4.9521349275326085e-9,
- "htn": 8.562723921230658e-8,
- "htn-c": 9.505431109586212e-8,
- "ior": 16.22469041121089,
- "ldu": 295.0145579973466,
- "mru": 0.00014397650264865014,
- "ozd": 0.00008270664080826244,
- "pco": 0.07011875405995191,
- "pma": 0.0000015299021421205005,
- "swe": 0.07993753303348655,
- "tre": 0.43009685281144183,
- "wtu": 40.61586633690124,
- "ecs": 4662.742937425237,
- "pef": 2818.6043491275173
+ "acd": 0.16805098372713878,
+ "cch": 23.406141883754728,
+ "etf": 382.2300354273023,
+ "etf-c": 976.2518816411425,
+ "fru": 240.7313699287465,
+ "fwe": 0.011041456207531702,
+ "htc": 3.2082433700128635e-9,
+ "htc-c": 4.9765905189357655e-9,
+ "htn": 8.154860534336768e-8,
+ "htn-c": 9.554213300063791e-8,
+ "ior": 16.224766386147213,
+ "ldu": 296.5388687773984,
+ "mru": 0.00014426264821133564,
+ "ozd": 0.00008270166963985792,
+ "pco": 0.06803336296847878,
+ "pma": 0.0000015356274590468485,
+ "swe": 0.07953020200552749,
+ "tre": 0.42425784859037785,
+ "wtu": 40.78389572826903,
+ "ecs": 4646.99066487436,
+ "pef": 2798.276588760015
}
},
{
@@ -296,27 +296,27 @@
"reparability=1.15"
],
"impacts": {
- "acd": 0.0414446685749946,
- "cch": 6.048874393344061,
- "etf": 133.45735497327883,
- "etf-c": 281.03257869705175,
- "fru": 108.41610613408756,
- "fwe": 0.0015967563755970645,
- "htc": 9.202232406694513e-10,
- "htc-c": 1.5167242473017484e-9,
- "htn": 2.2684998010224684e-8,
- "htn-c": 3.378964481489889e-8,
- "ior": 13.313345405119325,
- "ldu": 105.51839908615344,
- "mru": 0.000052078700426912154,
- "ozd": 0.000030370478290087493,
- "pco": 0.016994499640779308,
- "pma": 3.6240125804991626e-7,
- "swe": 0.02536100942287826,
- "tre": 0.12574953428356123,
- "wtu": 13.97456474348671,
- "ecs": 1469.1531378179673,
- "pef": 939.757440532827
+ "acd": 0.04163544680574335,
+ "cch": 6.076074899448809,
+ "etf": 134.0863054530789,
+ "etf-c": 282.1219011261312,
+ "fru": 108.75723225108744,
+ "fwe": 0.0016020599526329704,
+ "htc": 9.324883616149098e-10,
+ "htc-c": 1.5316938071499886e-9,
+ "htn": 2.2958539136038225e-8,
+ "htn-c": 3.396278638169421e-8,
+ "ior": 13.313836563271293,
+ "ldu": 106.0312189737267,
+ "mru": 0.000052176453397729595,
+ "ozd": 0.00003037113615558597,
+ "pco": 0.017158026522891636,
+ "pma": 3.650629404142302e-7,
+ "swe": 0.025467662607441162,
+ "tre": 0.12648609991631055,
+ "wtu": 14.022971246600134,
+ "ecs": 1473.9780976999311,
+ "pef": 942.9643784896306
}
},
{
@@ -331,27 +331,27 @@
"makingWaste=0"
],
"impacts": {
- "acd": 0.03556277405549819,
- "cch": 5.274011521794696,
- "etf": 113.66496753834603,
- "etf-c": 239.18693472401281,
- "fru": 99.89354028951128,
- "fwe": 0.001379642414386105,
- "htc": 7.975127330222743e-10,
- "htc-c": 1.3184705161562507e-9,
- "htn": 1.934041722376756e-8,
- "htn-c": 2.878076729242554e-8,
- "ior": 13.16583070424621,
- "ldu": 91.14088216514263,
- "mru": 0.00004479823453750349,
- "ozd": 0.000025826455410885885,
- "pco": 0.01467685700279186,
- "pma": 3.1336217874581686e-7,
- "swe": 0.02167050815279059,
- "tre": 0.10759516484280496,
- "wtu": 11.891846278042784,
- "ecs": 1299.6317469908283,
- "pef": 837.4947256106926
+ "acd": 0.03573846577551521,
+ "cch": 5.29996737386433,
+ "etf": 114.22944021552313,
+ "etf-c": 240.15186918362068,
+ "fru": 100.2239535034761,
+ "fwe": 0.0013843883280009535,
+ "htc": 8.095023395572573e-10,
+ "htc-c": 1.3329320985332255e-9,
+ "htn": 1.9605468225485186e-8,
+ "htn-c": 2.8937573933380658e-8,
+ "ior": 13.166286970554003,
+ "ldu": 91.60870785555007,
+ "mru": 0.00004489017344329534,
+ "ozd": 0.000025827064835365563,
+ "pco": 0.014834561195870921,
+ "pma": 3.159043475614539e-7,
+ "swe": 0.02176633947907204,
+ "tre": 0.10827607026526874,
+ "wtu": 11.933371318307108,
+ "ecs": 1304.0314709229826,
+ "pef": 840.4876551108515
}
},
{
@@ -366,27 +366,27 @@
"makingWaste=0.25"
],
"impacts": {
- "acd": 0.046673019258991415,
- "cch": 6.737641390276829,
- "etf": 151.05058824877455,
- "etf-c": 318.2287066730863,
- "fru": 115.99172021815534,
- "fwe": 0.0017897465633401396,
- "htc": 1.029299247466942e-9,
- "htc-c": 1.6929497860977452e-9,
- "htn": 2.5657958709297684e-8,
- "htn-c": 3.824198039043076e-8,
- "ior": 13.444469583673206,
- "ldu": 118.29841412705193,
- "mru": 0.00005855022566194208,
- "ozd": 0.00003440960973826669,
- "pco": 0.019054626430101487,
- "pma": 4.059915507646712e-7,
- "swe": 0.028641454996289513,
- "tre": 0.1418867515642335,
- "wtu": 15.825870046103532,
- "ecs": 1619.8388185532008,
- "pef": 1030.657631574724
+ "acd": 0.04687720772150169,
+ "cch": 6.765948255523903,
+ "etf": 151.73685233090626,
+ "etf-c": 319.4285961861407,
+ "fru": 116.34236891563084,
+ "fwe": 0.001795545841194763,
+ "htc": 1.041809270110601e-9,
+ "htc-c": 1.7083708814760004e-9,
+ "htn": 2.593904661208537e-8,
+ "htn-c": 3.842964189130624e-8,
+ "ior": 13.444991756797775,
+ "ldu": 118.85122885655039,
+ "mru": 0.000058653146690560065,
+ "ozd": 0.00003441031066244854,
+ "pco": 0.019223329035798944,
+ "pma": 4.087594673944759e-7,
+ "swe": 0.028757727610435928,
+ "tre": 0.14267279293945884,
+ "wtu": 15.880393405082835,
+ "ecs": 1625.0417659461073,
+ "pef": 1034.0547992707675
}
},
{
@@ -402,27 +402,27 @@
"surfaceMass=300"
],
"impacts": {
- "acd": 0.07267634397534148,
- "cch": 10.566370145958176,
- "etf": 235.05735479215312,
- "etf-c": 495.31278142778234,
- "fru": 175.24855963490427,
- "fwe": 0.002796540073534118,
- "htc": 1.5919968071366613e-9,
- "htc-c": 2.6127190836195204e-9,
- "htn": 3.997288100353046e-8,
- "htn-c": 5.951291773435012e-8,
- "ior": 22.763840053174576,
- "ldu": 185.72468717008135,
- "mru": 0.00009102947573620496,
- "ozd": 0.00005359060692221132,
- "pco": 0.029737143509036355,
- "pma": 6.332899101003791e-7,
- "swe": 0.04461787851377972,
- "tre": 0.22089877023652157,
- "wtu": 24.630629375675866,
- "ecs": 2562.0424840947135,
- "pef": 1622.08056836771
+ "acd": 0.07301301144136867,
+ "cch": 10.614371039084205,
+ "etf": 236.16726740356503,
+ "etf-c": 497.23511512615795,
+ "fru": 175.8505469001982,
+ "fwe": 0.0028058993271268926,
+ "htc": 1.6136411382168829e-9,
+ "htc-c": 2.6391359539399452e-9,
+ "htn": 4.0455600637319064e-8,
+ "htn-c": 5.98184616757536e-8,
+ "ior": 22.76470680285452,
+ "ldu": 186.62966344226942,
+ "mru": 0.00009120198097882398,
+ "ozd": 0.00005359176786132629,
+ "pco": 0.03002572035982282,
+ "pma": 6.379869966256389e-7,
+ "swe": 0.04480609001594954,
+ "tre": 0.22219859194137329,
+ "wtu": 24.71605261646426,
+ "ecs": 2570.5571191805325,
+ "pef": 1627.7398706444221
}
},
{
@@ -438,27 +438,27 @@
"printing=pigment"
],
"impacts": {
- "acd": 0.07394588489266214,
- "cch": 10.83602593808956,
- "etf": 235.61657846444567,
- "etf-c": 507.65662917666367,
- "fru": 184.38310752368184,
- "fwe": 0.002896826121073032,
- "htc": 1.6498750628912446e-9,
- "htc-c": 2.681280684984667e-9,
- "htn": 4.10706733454279e-8,
- "htn-c": 5.987239547781978e-8,
- "ior": 23.04193808555303,
- "ldu": 186.97988567823194,
- "mru": 0.00009158624796893748,
- "ozd": 0.00005360116790855931,
- "pco": 0.030507001264879974,
- "pma": 6.483034674210423e-7,
- "swe": 0.0456672457563599,
- "tre": 0.22289894843837044,
- "wtu": 24.6477403557429,
- "ecs": 2615.2682471286835,
- "pef": 1654.264703386901
+ "acd": 0.07428255235868933,
+ "cch": 10.884026831215587,
+ "etf": 236.72649107585758,
+ "etf-c": 509.5789628750392,
+ "fru": 184.98509478897574,
+ "fwe": 0.0029061853746658066,
+ "htc": 1.671519393971466e-9,
+ "htc-c": 2.707697555305092e-9,
+ "htn": 4.15533929792165e-8,
+ "htn-c": 6.017793941922328e-8,
+ "ior": 23.04280483523297,
+ "ldu": 187.88486195042003,
+ "mru": 0.0000917587532115565,
+ "ozd": 0.000053602328847674277,
+ "pco": 0.030795578115666435,
+ "pma": 6.53000553946302e-7,
+ "swe": 0.04585545725852972,
+ "tre": 0.22419877014322215,
+ "wtu": 24.7331635965313,
+ "ecs": 2623.782882214503,
+ "pef": 1659.9240056636133
}
},
{
@@ -474,27 +474,27 @@
"printing=substantive"
],
"impacts": {
- "acd": 0.07446448136980308,
- "cch": 10.865459053092978,
- "etf": 235.71998929884572,
- "etf-c": 500.6037735496913,
- "fru": 185.257732233438,
- "fwe": 0.002922149679109287,
- "htc": 1.6609112981200832e-9,
- "htc-c": 2.69366950581472e-9,
- "htn": 4.1291958055739324e-8,
- "htn-c": 5.968008004359814e-8,
- "ior": 23.082521039967514,
- "ldu": 187.14773137416543,
- "mru": 0.00009181908475489009,
- "ozd": 0.000053599886340053184,
- "pco": 0.030583985163537,
- "pma": 6.516506209819572e-7,
- "swe": 0.045725416514139174,
- "tre": 0.22317352611139882,
- "wtu": 24.650544818224496,
- "ecs": 2603.8607504048723,
- "pef": 1658.8381379248804
+ "acd": 0.07480114883583026,
+ "cch": 10.913459946219007,
+ "etf": 236.82990191025763,
+ "etf-c": 502.52610724806686,
+ "fru": 185.8597194987319,
+ "fwe": 0.0029315089327020608,
+ "htc": 1.6825556292003047e-9,
+ "htc-c": 2.720086376135145e-9,
+ "htn": 4.177467768952792e-8,
+ "htn-c": 5.998562398500163e-8,
+ "ior": 23.083387789647457,
+ "ldu": 188.0527076463535,
+ "mru": 0.00009199158999750911,
+ "ozd": 0.000053601047279168154,
+ "pco": 0.030872562014323462,
+ "pma": 6.563477075072172e-7,
+ "swe": 0.045913628016308994,
+ "tre": 0.22447334781625053,
+ "wtu": 24.735968059012894,
+ "ecs": 2612.3753854906913,
+ "pef": 1664.4974402015926
}
},
{
@@ -510,27 +510,27 @@
"printing=pigment;0.5"
],
"impacts": {
- "acd": 0.07565313052469849,
- "cch": 11.182825403800452,
- "etf": 236.45541397288443,
- "etf-c": 526.1724007999856,
- "fru": 196.82181516999697,
- "fwe": 0.002983897665138724,
- "htc": 1.73669244652312e-9,
- "htc-c": 2.784123087032387e-9,
- "htn": 4.271736185827405e-8,
- "htn-c": 6.04116120930243e-8,
- "ior": 23.458213102307457,
- "ldu": 188.58627379319242,
- "mru": 0.00009215383538378021,
- "ozd": 0.000053609923385912195,
- "pco": 0.0314264920250721,
- "pma": 6.670176721207272e-7,
- "swe": 0.04594982938891271,
- "tre": 0.2256601688992288,
- "wtu": 24.67340682584345,
- "ecs": 2688.6163069018926,
- "pef": 1694.7748529334613
+ "acd": 0.07598979799072568,
+ "cch": 11.230826296926482,
+ "etf": 237.56532658429637,
+ "etf-c": 528.0947344983612,
+ "fru": 197.42380243529087,
+ "fwe": 0.002993256918731499,
+ "htc": 1.7583367776033414e-9,
+ "htc-c": 2.810539957352812e-9,
+ "htn": 4.3200081492062654e-8,
+ "htn-c": 6.071715603442778e-8,
+ "ior": 23.4590798519874,
+ "ldu": 189.4912500653805,
+ "mru": 0.00009232634062639925,
+ "ozd": 0.000053611084325027164,
+ "pco": 0.03171506887585856,
+ "pma": 6.71714758645987e-7,
+ "swe": 0.046138040891082525,
+ "tre": 0.2269599906040805,
+ "wtu": 24.758830066631848,
+ "ecs": 2697.130941987712,
+ "pef": 1700.4341552101737
}
},
{
@@ -545,27 +545,27 @@
"upcycled=true"
],
"impacts": {
- "acd": 0.0028783103726423317,
- "cch": 1.034447974270687,
- "etf": 2.148056729627463,
- "etf-c": 2.9423659495513848,
- "fru": 74.16903603999697,
- "fwe": 0.0001791955931726597,
- "htc": 1.4699590611006234e-10,
- "htc-c": 2.8471813917534933e-10,
- "htn": 4.71319645111522e-10,
- "htn-c": 5.598702944994033e-10,
- "ior": 13.355660450532385,
- "ldu": 10.346336411626782,
- "mru": 0.000004769965172754928,
- "ozd": 8.310895092724175e-8,
- "pco": 0.00189779033199731,
- "pma": 4.4226576928059735e-8,
- "swe": 0.0009493384564102386,
- "tre": 0.006135195458220896,
- "wtu": 0.1324275226503942,
- "ecs": 318.5020583098391,
- "pef": 308.9809122920371
+ "acd": 0.002968511865179645,
+ "cch": 1.0533507868080005,
+ "etf": 2.3471551919408955,
+ "etf-c": 3.202435248820042,
+ "fru": 74.4387428034298,
+ "fwe": 0.0001807814140681821,
+ "htc": 1.5742426431901755e-10,
+ "htc-c": 2.963011825484837e-10,
+ "htn": 6.882599436189848e-10,
+ "htn-c": 6.241123556934332e-10,
+ "ior": 13.35591899638985,
+ "ldu": 10.55919498476111,
+ "mru": 0.00000482895771006836,
+ "ozd": 8.344387630037608e-8,
+ "pco": 0.0020224992872211905,
+ "pma": 4.609150230119407e-8,
+ "swe": 0.000983845919096806,
+ "tre": 0.006500693022400001,
+ "wtu": 0.13495760676979718,
+ "ecs": 320.49211185973485,
+ "pef": 310.761127204542
}
}
]
diff --git a/tests/server.spec.js b/tests/server.spec.js
index 677ee0303..4246f5a7b 100644
--- a/tests/server.spec.js
+++ b/tests/server.spec.js
@@ -296,11 +296,6 @@ describe("API", () => {
airTransportRatio: 0.5,
durability: 1.2,
reparability: 1.2,
- makingWaste: null,
- makingComplexity: null,
- yarnSize: null,
- surfaceMass: null,
- knittingProcess: null,
disabledSteps: ["use"],
});
expectStatus(response, 200);