From 3a34092e4cf152cf9ba29d2892cf103eb64befb5 Mon Sep 17 00:00:00 2001 From: Filipriec Date: Sun, 23 Aug 2026 09:39:18 +0200 Subject: [PATCH] conversions2 --- common/proto/ecb.proto | 37 +++++++++++++++++++++------- common/src/proto/descriptor.bin | Bin 190995 -> 192348 bytes common/src/proto/komp_ac.ecb.rs | 41 ++++++++++++++++++++++++-------- server | 2 +- 4 files changed, 61 insertions(+), 19 deletions(-) diff --git a/common/proto/ecb.proto b/common/proto/ecb.proto index 6c679df2..a6cb4984 100644 --- a/common/proto/ecb.proto +++ b/common/proto/ecb.proto @@ -15,7 +15,8 @@ enum ExchangeRateDateRule { enum ExchangeRateSource { EXCHANGE_RATE_SOURCE_UNSPECIFIED = 0; - EXCHANGE_RATE_SOURCE_ECB = 1; + // The rate source's own published reference rate (ECB's, today). + EXCHANGE_RATE_SOURCE_OFFICIAL = 1; // A reusable rate from the profile's custom_exchange_rates table. EXCHANGE_RATE_SOURCE_SAVED_CUSTOM = 2; // A one-off rate recorded only in this posting's immutable evidence. @@ -29,8 +30,9 @@ message ExchangeRateSelection { ExchangeRateSource source = 2; // Required for SPECIFIC_PUBLICATION_DATE and MANUAL; YYYY-MM-DD. optional string specific_rate_date = 3; - // Required only for MANUAL. Exact foreign-currency units per EUR. - optional string manual_units_per_eur = 4; + // Required only for MANUAL. Exact foreign-currency units per one unit of + // the rate source's pivot currency (EUR for ECB). + optional string manual_units_per_pivot = 4; // Required for SPECIFIC_PUBLICATION_DATE and MANUAL. string reason = 5; } @@ -153,7 +155,7 @@ message PreviewEcbConversionResponse { string determination_method = 5; string rounding_method = 6; optional string rate_date = 7; - optional string units_per_eur = 8; + optional string units_per_pivot = 8; optional int64 rate_observation_id = 9; optional string observation_hash = 10; optional string source_payload_hash = 11; @@ -162,8 +164,8 @@ message PreviewEcbConversionResponse { optional string source_endpoint = 14; // Present only when determination_method is custom_rate. rate_date and - // units_per_eur then describe the hand-entered row identified here, and the - // ECB observation fields above are empty. + // units_per_pivot then describe the hand-entered row identified here, and + // the ECB observation fields above are empty. optional int64 custom_rate_table_definition_id = 15; optional int64 custom_rate_record_id = 16; optional int64 custom_rate_row_revision = 17; @@ -223,7 +225,7 @@ message EcbConversionEvidence { string determination_method = 8; string rounding_method = 9; optional string rate_date = 10; - optional string units_per_eur = 11; + optional string units_per_pivot = 11; optional int64 rate_observation_id = 12; optional string observation_hash = 13; optional string source_payload_hash = 14; @@ -233,7 +235,7 @@ message EcbConversionEvidence { string evidence_created_at = 18; // Present only when determination_method is custom_rate. The hand-entered row - // that supplied rate_date and units_per_eur. The row itself stays editable, so + // that supplied rate_date and units_per_pivot. The row itself stays editable, so // the figures above are the immutable record of what was actually applied. optional int64 custom_rate_table_definition_id = 19; optional int64 custom_rate_record_id = 20; @@ -253,6 +255,25 @@ message EcbConversionEvidence { // the original-currency-to-EUR leg's evidence_id, which produced this row's // original_amount/original_currency (always EUR). optional int64 derived_from_evidence_id = 26; + + // The pivot currency of the rate source that priced this hop (EUR for + // every hop today). A rate-based hop always has this currency on exactly + // one side of original_currency/converted_currency. + string pivot_currency = 27; + + // Which rate source's policy governs this hop's profile ("ecb" for every + // hop today). Absent only for already_same_currency, where no policy + // needed to be consulted. This is about which policy applies, not about + // who actually supplied this specific rate -- see observation_source_id + // for that. + optional string policy_source_id = 28; + + // Which rate source actually supplied this hop's rate as its own official + // observation. Present only when determination_method is + // official_reference_rate; absent for custom_rate, manual_rate, and + // already_same_currency, since none of those were priced by the policy's + // source itself -- a human entered them. + optional string observation_source_id = 29; } message ListEcbConversionEvidenceResponse { diff --git a/common/src/proto/descriptor.bin b/common/src/proto/descriptor.bin index 4e234c520a9cdbe679725c6fcafe1a3274117bf7..846dbfca48dded5520e4f1e6b355d96ec2565dd8 100644 GIT binary patch delta 7767 zcmZ`;du&`)diObVXYS1PbFQBmkK=2{i5)*fUc`CO#33PeLIO4{iqvAp<8eH!Ju~%; z$@-t%NCmb?L1KGJLKcSvC|Vxc0`j6(Rd$7Fvzt{>Bhd<49$_IN0seuYl2$^h`uon~ z-ffynk(J*$=l46``ObIF_su=tzm|V|seHNh>2u7AWzrMtU1P3_gK|8OGlM-rReZQM{1gv`eOs3THC6**_@?Z#eXvX z-<3;;s(y1z&GK7nE{)X0L$1BjsuGJDPtVWIWpe3-re+#GS}9t0sz$rdsww1Wvgw8K zVt#%uof*$gHYJ5_)o7LM8514DlYhyWeY;hkpD1SL9!Zt5`P?6IS_G$hv{rVn75#t2 z9ICLa@wrqfGd_twL$_G2m#et$&D3q^9;&tC<2M^M)MPb`-#qowV%?*Rz2vnuYz?(p zE#5;7^;HLU?;hScyklPtgA3ZIX~}Ci&SD?WSf(8=D?7V%ThqTY*65WdZg=mtj4J0LdixryD$I=(^;<n;Xb3$IfHX*DhN%^HE$vb@!T<1hitY2~XE-b`}ewpK3IPpx4zm&X-@ zyxVGbXas(1XP5Oj69Pc(yf3lf{YP@Eo6lt&Ivq}a%5qBoXDdY9Iy#!2u3h(!I#c;M z2b-XLkGVqzDQZhXu%z9$Bm_&^?Ji|Wi01C;wRQ+YKnr*9y2N^KHo4aOo0iI+4jxq_ z4e&Z*)f$1NVCCIR&?kLB83`Iah`T z{V8Ze2K^~G7@IMLg)S=E9@U zpm-SeX%r8`v4pF56cEEL%M}j+F`|wR=LUEqK9AyIBqrks^dOiDTU>eFMOkNWf&=%eu-MUR0#+P_BGVA-KDb$fAc!Ga@i_igsA1=(-6}q#pEsSo!SWL8Xf( z=pIzMKp1~eIS2^42jQSMB^!MYdKXtM^*pFTAtVC!!I-oI2;(2bRsUN#9ub@Ne%X1U zJIy0vxginsX|qZrj8DgH>mgwrz#;EU*F^Urb$mjc%s-?KA`p#0$ZQwG;hl%Qp4CI$ z5BusAm=BxsB!)y_KHRj-x?c>(GH1P$s~_l|^^K>1oK?prBm#04$7VKrE@G5aJYwB_xG^ zG{oG9#3M^T?%B=VBR-u%@Q6>R5IkZJsL3e=kE~rMVkkrr=<;={D+VvQz6b@P>x)nz zx~P9BSAqr+cgCp`tInK&{?N!`%+C9#2i2MAn1%_Ze$SZtYC z2YSJMh9#-SB8!1eF?8Er7G1(utLUPvu6M7`>U z)FQK+HH6e6LqR94Fm2;B&$z4ybU2AEUPM9OJ81 zFA@qtErsI@h@2pe!g&UacW4Ny=NK*oX;jQM&M@AkI&q{4Y9*X$K;I}FYQsIl>~=jG zQfJso%4@W_mTjD6yhn8+!w}R`NHKuE6mkq8endzckz@e7x|LG7Z9LDAFJ)&rlmMj? z;;$T1&j(WFka|9FRXL=dXC14QRE2H45IDU8Qh?g13Mjo0c&Y+QFR-}Y>6JjK8cMIQxQ@tbD7`|zg|S{2M%LKItBemQsTxQDYN;AXy&6d22O(fwM`R78US+-g z%BZ+)ycPsm97=#%DGsIA0?);v^crjNgDeiI*C@#TO1jRrjn}<U{QH7MnoF8z);AG8YV({;9c*5t*86m z4JM)M|6LZ78-pP_lQXlGZ($KZKHh`gGuPpzsRDMYEHWJFS43A{p^F4*sS-w zv)k^z<2@Z~Xro3QwSW+KkHzKY147_EhHnI8aHwfV-e+Y`bFb%)dq>`9_y|DJWRgce zVE7e6>jZ)zpj7JN5%4lz%B{0%|TL%|GZOz@*9-P!$0tN6!2#@FgWlKux72`B~sgRK0*y z1W>*;QTH03<0z|XDN6#%3k;o*`dnXNfROrJ7Xg5f`kYR-TmX{fWu4kg`WZ%0D^ZfX z94JwebT8{Hg3*w=tW%rGktMG%-mQ$HED5NkC`n$?k&dyDx}u8!Kqy^dovW2mNRnUZ z``P4_Bmt$83k<0*0;?!XexZv1^g`+jT?CkvC9mot00>fm+9*nrR|6$Vl2>&RfWc6@ zs*3=Va^y9}U72qIAqA|ZC@EeGq$nv~3p_)lH!+vrzk0Y zsfz%UyOb5b)K!2Q8`@qkXQoq+J+~kx}zo!%~4{M`s+z5iX5t9Sz$r~~GjbQRdDBTExxe-b?D40Ky z8`fkSKTt97&&=_5?*6v{0KL~uVEz!?mQ7&(Ko`dQlDW(_j&g70t`FR!_-><4`!Y;^ zl&c!wksdja&gU>sDKjaXT)ea39Y7w41RQ`hX&)xwfX6t# zx2Rq?;4z*^%5uu&&9-rj<7wa}?mRG^O-~DBgNF$D9^xFzW4fHO7i+*11)jO4vNIW{ zt38u;C)&j~aj|&of3F_THaUD-&&@1|A*q?UOllI(KB?J^zn)&_@HAdHoLt_K6IxC# zlbIwJ=bed+gXI?IXRzFU>=JyAf2oQ5dDLGBesPeGSc(KQhrvn_d4p8k!I<2Qn^VB(R#}bD`x3E zDo0@|PD#F)aSqcSs C%U|~Z delta 6435 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 AiU0rr diff --git a/common/src/proto/komp_ac.ecb.rs b/common/src/proto/komp_ac.ecb.rs index 3cf183a2..191e4b09 100644 --- a/common/src/proto/komp_ac.ecb.rs +++ b/common/src/proto/komp_ac.ecb.rs @@ -10,9 +10,10 @@ pub struct ExchangeRateSelection { /// Required for SPECIFIC_PUBLICATION_DATE and MANUAL; YYYY-MM-DD. #[prost(string, optional, tag = "3")] pub specific_rate_date: ::core::option::Option<::prost::alloc::string::String>, - /// Required only for MANUAL. Exact foreign-currency units per EUR. + /// Required only for MANUAL. Exact foreign-currency units per one unit of + /// the rate source's pivot currency (EUR for ECB). #[prost(string, optional, tag = "4")] - pub manual_units_per_eur: ::core::option::Option<::prost::alloc::string::String>, + pub manual_units_per_pivot: ::core::option::Option<::prost::alloc::string::String>, /// Required for SPECIFIC_PUBLICATION_DATE and MANUAL. #[prost(string, tag = "5")] pub reason: ::prost::alloc::string::String, @@ -142,7 +143,7 @@ pub struct PreviewEcbConversionResponse { #[prost(string, optional, tag = "7")] pub rate_date: ::core::option::Option<::prost::alloc::string::String>, #[prost(string, optional, tag = "8")] - pub units_per_eur: ::core::option::Option<::prost::alloc::string::String>, + pub units_per_pivot: ::core::option::Option<::prost::alloc::string::String>, #[prost(int64, optional, tag = "9")] pub rate_observation_id: ::core::option::Option, #[prost(string, optional, tag = "10")] @@ -156,8 +157,8 @@ pub struct PreviewEcbConversionResponse { #[prost(string, optional, tag = "14")] pub source_endpoint: ::core::option::Option<::prost::alloc::string::String>, /// Present only when determination_method is custom_rate. rate_date and - /// units_per_eur then describe the hand-entered row identified here, and the - /// ECB observation fields above are empty. + /// units_per_pivot then describe the hand-entered row identified here, and + /// the ECB observation fields above are empty. #[prost(int64, optional, tag = "15")] pub custom_rate_table_definition_id: ::core::option::Option, #[prost(int64, optional, tag = "16")] @@ -234,7 +235,7 @@ pub struct EcbConversionEvidence { #[prost(string, optional, tag = "10")] pub rate_date: ::core::option::Option<::prost::alloc::string::String>, #[prost(string, optional, tag = "11")] - pub units_per_eur: ::core::option::Option<::prost::alloc::string::String>, + pub units_per_pivot: ::core::option::Option<::prost::alloc::string::String>, #[prost(int64, optional, tag = "12")] pub rate_observation_id: ::core::option::Option, #[prost(string, optional, tag = "13")] @@ -250,7 +251,7 @@ pub struct EcbConversionEvidence { #[prost(string, tag = "18")] pub evidence_created_at: ::prost::alloc::string::String, /// Present only when determination_method is custom_rate. The hand-entered row - /// that supplied rate_date and units_per_eur. The row itself stays editable, so + /// that supplied rate_date and units_per_pivot. The row itself stays editable, so /// the figures above are the immutable record of what was actually applied. #[prost(int64, optional, tag = "19")] pub custom_rate_table_definition_id: ::core::option::Option, @@ -275,6 +276,25 @@ pub struct EcbConversionEvidence { /// original_amount/original_currency (always EUR). #[prost(int64, optional, tag = "26")] pub derived_from_evidence_id: ::core::option::Option, + /// The pivot currency of the rate source that priced this hop (EUR for + /// every hop today). A rate-based hop always has this currency on exactly + /// one side of original_currency/converted_currency. + #[prost(string, tag = "27")] + pub pivot_currency: ::prost::alloc::string::String, + /// Which rate source's policy governs this hop's profile ("ecb" for every + /// hop today). Absent only for already_same_currency, where no policy + /// needed to be consulted. This is about which policy applies, not about + /// who actually supplied this specific rate -- see observation_source_id + /// for that. + #[prost(string, optional, tag = "28")] + pub policy_source_id: ::core::option::Option<::prost::alloc::string::String>, + /// Which rate source actually supplied this hop's rate as its own official + /// observation. Present only when determination_method is + /// official_reference_rate; absent for custom_rate, manual_rate, and + /// already_same_currency, since none of those were priced by the policy's + /// source itself -- a human entered them. + #[prost(string, optional, tag = "29")] + pub observation_source_id: ::core::option::Option<::prost::alloc::string::String>, } #[derive(Clone, PartialEq, ::prost::Message)] pub struct ListEcbConversionEvidenceResponse { @@ -335,7 +355,8 @@ impl ExchangeRateDateRule { #[repr(i32)] pub enum ExchangeRateSource { Unspecified = 0, - Ecb = 1, + /// The rate source's own published reference rate (ECB's, today). + Official = 1, /// A reusable rate from the profile's custom_exchange_rates table. SavedCustom = 2, /// A one-off rate recorded only in this posting's immutable evidence. @@ -349,7 +370,7 @@ impl ExchangeRateSource { pub fn as_str_name(&self) -> &'static str { match self { Self::Unspecified => "EXCHANGE_RATE_SOURCE_UNSPECIFIED", - Self::Ecb => "EXCHANGE_RATE_SOURCE_ECB", + Self::Official => "EXCHANGE_RATE_SOURCE_OFFICIAL", Self::SavedCustom => "EXCHANGE_RATE_SOURCE_SAVED_CUSTOM", Self::Manual => "EXCHANGE_RATE_SOURCE_MANUAL", } @@ -358,7 +379,7 @@ impl ExchangeRateSource { pub fn from_str_name(value: &str) -> ::core::option::Option { match value { "EXCHANGE_RATE_SOURCE_UNSPECIFIED" => Some(Self::Unspecified), - "EXCHANGE_RATE_SOURCE_ECB" => Some(Self::Ecb), + "EXCHANGE_RATE_SOURCE_OFFICIAL" => Some(Self::Official), "EXCHANGE_RATE_SOURCE_SAVED_CUSTOM" => Some(Self::SavedCustom), "EXCHANGE_RATE_SOURCE_MANUAL" => Some(Self::Manual), _ => None, diff --git a/server b/server index 0fc100a4..81f04101 160000 --- a/server +++ b/server @@ -1 +1 @@ -Subproject commit 0fc100a4342846eea066bd239d546f206568cd23 +Subproject commit 81f0410185afd59eb4f8a746dabdbacacd44146b