@@ -2,93 +2,51 @@ use chrono::Utc;
2
2
use pact_data_model:: {
3
3
CarbonFootprint , CharacterizationFactors , CompanyIdSet , CrossSectoralStandard ,
4
4
CrossSectoralStandardSet , DataModelExtension , DeclaredUnit , ExemptedEmissionsPercent ,
5
- IpccCharacterizationFactorsSource , PfId , PfStatus , ProductFootprint , ProductIdSet ,
6
- SpecVersionString , Urn , VersionInteger ,
5
+ IpccCharacterizationFactorsSource , PfId , PfStatus , PositiveDecimal , ProductFootprint ,
6
+ ProductIdSet , SpecVersionString , Urn , VersionInteger ,
7
7
} ;
8
8
use rust_decimal:: Decimal ;
9
- use schemars:: JsonSchema ;
10
- use serde:: { Deserialize , Serialize } ;
9
+ use serde:: Serialize ;
11
10
use uuid:: Uuid ;
12
11
13
12
use crate :: { Hoc , HocCo2eIntensityThroughput , ShipmentFootprint , Toc } ;
14
13
15
- pub enum HocTeuContainerSize {
14
+ /* pub enum HocTeuContainerSize {
16
15
Normal,
17
16
Light,
18
17
Heavy,
19
- }
20
-
21
- #[ derive( Debug , Serialize , Deserialize , JsonSchema , PartialEq , Clone ) ]
22
- pub enum ILeapType {
23
- ShipmentFootprint ( ShipmentFootprint ) ,
24
- Toc ( Toc ) ,
25
- Hoc ( Hoc ) ,
26
- }
27
-
28
- pub fn to_pcf (
29
- ileap_type : ILeapType ,
30
- company_name : & str ,
31
- company_urn : & str ,
32
- hoc_container_size : Option < HocTeuContainerSize > ,
33
- characterization_factors : Option < Vec < CharacterizationFactors > > ,
34
- ) -> ProductFootprint {
35
- let ( characterization_factors, characterization_factors_sources) =
36
- match characterization_factors {
37
- None => (
38
- CharacterizationFactors :: Ar5 ,
39
- vec ! [ IpccCharacterizationFactorsSource :: from( "AR5" . to_string( ) ) ] ,
40
- ) ,
41
- Some ( cf) => {
42
- if cf. is_empty ( ) {
43
- (
44
- CharacterizationFactors :: Ar5 ,
45
- vec ! [ IpccCharacterizationFactorsSource :: from( "AR5" . to_string( ) ) ] ,
46
- )
47
- } else {
48
- let cf: Vec < IpccCharacterizationFactorsSource > = cf
49
- . iter ( )
50
- . map ( |cf| match cf {
51
- CharacterizationFactors :: Ar5 => {
52
- IpccCharacterizationFactorsSource :: from ( "AR5" . to_string ( ) )
53
- }
54
- CharacterizationFactors :: Ar6 => {
55
- IpccCharacterizationFactorsSource :: from ( "AR6" . to_string ( ) )
56
- }
57
- } )
58
- . collect ( ) ;
59
-
60
- let characterization_factors = if cf
61
- . contains ( & IpccCharacterizationFactorsSource :: from ( "AR5" . to_string ( ) ) )
62
- {
63
- CharacterizationFactors :: Ar5
64
- } else {
65
- CharacterizationFactors :: Ar6
66
- } ;
67
-
68
- ( characterization_factors, cf)
69
- }
70
- }
71
- } ;
18
+ }*/
72
19
73
- struct MappedFields {
74
- product_id_type : String ,
75
- id : String ,
76
- product_name_company : String ,
77
- declared_unit : DeclaredUnit ,
78
- unitary_product_amount : Decimal ,
79
- p_cf_excluding_biogenic : Decimal ,
20
+ /* fn get_teu_co2e_intensity_wtw(
21
+ hoc_co2e_intensity_wtw: Decimal,
22
+ hoc_container_size: &Option<HocTeuContainerSize>,
23
+ ) -> Decimal {
24
+ match hoc_container_size {
25
+ Some(HocTeuContainerSize::Normal) => hoc_co2e_intensity_wtw * Decimal::from(10000),
26
+ Some(HocTeuContainerSize::Light) => hoc_co2e_intensity_wtw * Decimal::from(6000),
27
+ Some(HocTeuContainerSize::Heavy) => hoc_co2e_intensity_wtw * Decimal::from(14050),
28
+ None => {
29
+ println!("Warning: HOC TEU container size not specified, using normal container");
30
+ hoc_co2e_intensity_wtw * Decimal::from(10000)
31
+ }
80
32
}
33
+ } */
81
34
82
- let MappedFields {
83
- product_id_type,
84
- id,
85
- product_name_company,
86
- declared_unit,
87
- unitary_product_amount,
88
- p_cf_excluding_biogenic,
89
- } = match ileap_type {
90
- ILeapType :: ShipmentFootprint ( ref shipment) => MappedFields {
91
- product_id_type : "shipment" . to_string ( ) ,
35
+ pub struct MappedFields {
36
+ product_id_type : & ' static str ,
37
+ data_schema_id : & ' static str ,
38
+ id : String ,
39
+ product_name_company : String ,
40
+ declared_unit : DeclaredUnit ,
41
+ unitary_product_amount : Decimal ,
42
+ p_cf_excluding_biogenic : Decimal ,
43
+ }
44
+
45
+ impl From < & ShipmentFootprint > for MappedFields {
46
+ fn from ( shipment : & ShipmentFootprint ) -> Self {
47
+ MappedFields {
48
+ product_id_type : "shipment" ,
49
+ data_schema_id : "shipment-footprint" ,
92
50
id : shipment. shipment_id . clone ( ) ,
93
51
product_name_company : format ! ( "ShipmentFootprint with id {}" , shipment. shipment_id) ,
94
52
declared_unit : DeclaredUnit :: TonKilometer ,
@@ -102,51 +60,83 @@ pub fn to_pcf(
102
60
. 0
103
61
. iter ( )
104
62
. fold ( Decimal :: from ( 0 ) , |acc, tce| acc + tce. co2e_wtw . 0 ) ,
105
- } ,
106
- ILeapType :: Toc ( ref toc) => MappedFields {
107
- product_id_type : "toc" . to_string ( ) ,
108
- id : toc. toc_id . clone ( ) ,
109
- product_name_company : format ! ( "TOC with ID {}" , toc. toc_id) ,
110
- declared_unit : DeclaredUnit :: TonKilometer ,
111
- unitary_product_amount : Decimal :: from ( 1 ) ,
112
- p_cf_excluding_biogenic : toc. co2e_intensity_wtw . 0 ,
113
- } ,
114
- ILeapType :: Hoc ( ref hoc) => MappedFields {
115
- product_id_type : "hoc" . to_string ( ) ,
63
+ }
64
+ }
65
+ }
66
+
67
+ impl From < & Hoc > for MappedFields {
68
+ fn from ( hoc : & Hoc ) -> Self {
69
+ MappedFields {
70
+ product_id_type : "hoc" ,
71
+ data_schema_id : "hoc" ,
116
72
id : hoc. hoc_id . clone ( ) ,
117
73
product_name_company : format ! ( "HOC with ID {}" , hoc. hoc_id) ,
118
74
declared_unit : DeclaredUnit :: Kilogram ,
119
75
unitary_product_amount : Decimal :: from ( 1000 ) ,
120
76
p_cf_excluding_biogenic : match hoc. co2e_intensity_throughput {
121
77
HocCo2eIntensityThroughput :: TEU => {
122
- get_teu_co2e_intensity_wtw ( hoc . co2e_intensity_wtw . 0 , hoc_container_size )
78
+ panic ! ( "HOC with TEU throughput is not supported, yet" )
123
79
}
124
80
HocCo2eIntensityThroughput :: Tonnes => hoc. co2e_intensity_wtw . 0 ,
125
81
} ,
126
- } ,
127
- } ;
82
+ }
83
+ }
84
+ }
128
85
129
- fn get_teu_co2e_intensity_wtw (
130
- hoc_co2e_intensity_wtw : Decimal ,
131
- hoc_container_size : Option < HocTeuContainerSize > ,
132
- ) -> Decimal {
133
- match hoc_container_size {
134
- Some ( HocTeuContainerSize :: Normal ) => hoc_co2e_intensity_wtw * Decimal :: from ( 10000 ) ,
135
- Some ( HocTeuContainerSize :: Light ) => hoc_co2e_intensity_wtw * Decimal :: from ( 6000 ) ,
136
- Some ( HocTeuContainerSize :: Heavy ) => hoc_co2e_intensity_wtw * Decimal :: from ( 14050 ) ,
137
- None => {
138
- println ! ( "Warning: HOC TEU container size not specified, using normal container" ) ;
139
- hoc_co2e_intensity_wtw * Decimal :: from ( 10000 )
140
- }
86
+ impl From < & Toc > for MappedFields {
87
+ fn from ( toc : & Toc ) -> Self {
88
+ MappedFields {
89
+ product_id_type : "toc" ,
90
+ data_schema_id : "toc" ,
91
+ id : toc. toc_id . clone ( ) ,
92
+ product_name_company : format ! ( "TOC with ID {}" , toc. toc_id) ,
93
+ declared_unit : DeclaredUnit :: TonKilometer ,
94
+ unitary_product_amount : Decimal :: from ( 1 ) ,
95
+ p_cf_excluding_biogenic : toc. co2e_intensity_wtw . 0 ,
141
96
}
142
97
}
98
+ }
99
+
100
+ /**
101
+ * converts an iLEAP type into a PACT Data Model's ProductFootprint.
102
+ *
103
+ * To do so, additional propertiers are needed:
104
+ * - company_name: the name of the company that is responsible for the product
105
+ * - company_urn: the URN of the company that is responsible for the product
106
+ * - characterization_factors: the optional IPCC characterization factors that were used in the calculation of the carbon footprint (TOC, HOC, ShipmentFootprint). If not defined `AR5` will be used.
107
+ */
108
+ pub fn to_pcf < T > (
109
+ ileap_type : & T ,
110
+ company_name : & str ,
111
+ company_urn : & str ,
112
+ // hoc_container_size: Option<HocTeuContainerSize>,
113
+ characterization_factors : Option < Vec < CharacterizationFactors > > ,
114
+ ) -> ProductFootprint
115
+ where
116
+ T : Serialize ,
117
+ MappedFields : for < ' a > From < & ' a T > ,
118
+ {
119
+ // massage the optional IPCC characterization factors into a tuple of the actual factors and the IPCC Characterization Factor sources
120
+ let ( characterization_factors, characterization_factors_sources) =
121
+ to_char_factors ( characterization_factors) ;
143
122
144
- let data_schema_id = if product_id_type == "shipment" {
145
- "shipment-footprint"
146
- } else {
147
- product_id_type. as_str ( )
148
- } ;
123
+ // extract the properties necessary to turn the iLEAP type into a ProductFootprint
124
+ // Note: this conversion at this point is "static" and does not require any additional data.
125
+ // However it seems that the current HOC data type (when throughput is declared in `TEU`
126
+ // the current implementation bails out drastically. We are investingating whether
127
+ // this is indicates a lack in the iLEAP Data Model. This function will be updated
128
+ // once we have more information.
129
+ let MappedFields {
130
+ product_id_type,
131
+ data_schema_id,
132
+ id,
133
+ product_name_company,
134
+ declared_unit,
135
+ unitary_product_amount,
136
+ p_cf_excluding_biogenic,
137
+ } = ileap_type. into ( ) ;
149
138
139
+ // fasten your seatbelts, we are about to create a ProductFootprint...
150
140
ProductFootprint {
151
141
id : PfId ( Uuid :: new_v4 ( ) ) ,
152
142
spec_version : SpecVersionString ( "2.2.0" . to_string ( ) ) ,
@@ -171,10 +161,10 @@ pub fn to_pcf(
171
161
declared_unit,
172
162
unitary_product_amount : unitary_product_amount. into ( ) ,
173
163
p_cf_excluding_biogenic : p_cf_excluding_biogenic. into ( ) ,
174
- p_cf_including_biogenic : Some ( p_cf_excluding_biogenic . into ( ) ) , // TODO: to be clarified in the Tech Specs
164
+ p_cf_including_biogenic : None ,
175
165
fossil_ghg_emissions : p_cf_excluding_biogenic. into ( ) ,
176
- fossil_carbon_content : p_cf_excluding_biogenic . into ( ) , // TODO: to be clarified in the Tech Specs
177
- biogenic_carbon_content : p_cf_excluding_biogenic . into ( ) , // TODO: to be clarified in the Tech Specs
166
+ fossil_carbon_content : PositiveDecimal :: from ( Decimal :: from ( 0 ) ) ,
167
+ biogenic_carbon_content : PositiveDecimal :: from ( Decimal :: from ( 0 ) ) ,
178
168
d_luc_ghg_emissions : None ,
179
169
land_management_ghg_emissions : None ,
180
170
other_biogenic_ghg_emissions : None ,
@@ -207,11 +197,57 @@ pub fn to_pcf(
207
197
spec_version: SpecVersionString :: from( "0.2.0" . to_string( ) ) ,
208
198
data_schema: format!( "https://api.ileap.sine.dev/{data_schema_id}.json" ) ,
209
199
documentation: Some ( "https://sine-fdn.github.io/ileap-extension/" . to_string( ) ) ,
210
- data: serde_json:: to_value( & ileap_type)
200
+ data: serde_json:: to_value( ileap_type)
211
201
. unwrap( )
212
202
. as_object( )
213
203
. unwrap( )
214
204
. to_owned( ) ,
215
205
} ] ) ,
216
206
}
217
207
}
208
+
209
+ fn to_char_factors (
210
+ characterization_factors : Option < Vec < CharacterizationFactors > > ,
211
+ ) -> (
212
+ CharacterizationFactors ,
213
+ Vec < IpccCharacterizationFactorsSource > ,
214
+ ) {
215
+ let ( characterization_factors, characterization_factors_sources) =
216
+ match characterization_factors {
217
+ None => (
218
+ CharacterizationFactors :: Ar5 ,
219
+ vec ! [ IpccCharacterizationFactorsSource :: from( "AR5" . to_string( ) ) ] ,
220
+ ) ,
221
+ Some ( cf) => {
222
+ if cf. is_empty ( ) {
223
+ (
224
+ CharacterizationFactors :: Ar5 ,
225
+ vec ! [ IpccCharacterizationFactorsSource :: from( "AR5" . to_string( ) ) ] ,
226
+ )
227
+ } else {
228
+ let cf: Vec < IpccCharacterizationFactorsSource > = cf
229
+ . iter ( )
230
+ . map ( |cf| match cf {
231
+ CharacterizationFactors :: Ar5 => {
232
+ IpccCharacterizationFactorsSource :: from ( "AR5" . to_string ( ) )
233
+ }
234
+ CharacterizationFactors :: Ar6 => {
235
+ IpccCharacterizationFactorsSource :: from ( "AR6" . to_string ( ) )
236
+ }
237
+ } )
238
+ . collect ( ) ;
239
+
240
+ let characterization_factors = if cf
241
+ . contains ( & IpccCharacterizationFactorsSource :: from ( "AR5" . to_string ( ) ) )
242
+ {
243
+ CharacterizationFactors :: Ar5
244
+ } else {
245
+ CharacterizationFactors :: Ar6
246
+ } ;
247
+
248
+ ( characterization_factors, cf)
249
+ }
250
+ }
251
+ } ;
252
+ ( characterization_factors, characterization_factors_sources)
253
+ }
0 commit comments