syntax = "proto3"; package komp_ac.exchange_rates; import "common.proto"; // Selects WHICH DATE supplies the rate; this is independent of where the rate // comes from. These are not four user-facing choices: UNSPECIFIED is protobuf's // zero-value sentinel and is rejected when an explicit selection is supplied. // // User-facing mapping: // - "Automatic official rate" uses PREVIOUS_PUBLICATION for an ordinary // transaction, or ON_OR_BEFORE_DATE for a financial statement. // - "Official rate from another date" uses SPECIFIC_PUBLICATION_DATE together // with source OFFICIAL, a specific_rate_date, and an audit reason. // - A saved custom rate still uses one of these rules to determine which dated // custom-rate record applies. enum ExchangeRateDateRule { // Sentinel for an omitted date rule; never a selectable business option. EXCHANGE_RATE_DATE_RULE_UNSPECIFIED = 0; // Latest valid publication strictly before the transaction date. EXCHANGE_RATE_DATE_RULE_PREVIOUS_PUBLICATION = 1; // Latest valid publication on or before the financial-statement date. EXCHANGE_RATE_DATE_RULE_ON_OR_BEFORE_DATE = 2; // An explicitly chosen publication date. Requires specific_rate_date and an // audit reason; an official date must be a real provider publication date. EXCHANGE_RATE_DATE_RULE_SPECIFIC_PUBLICATION_DATE = 3; } // Selects WHERE THE RATE VALUE comes from; date selection is controlled by // ExchangeRateDateRule above. These are not four user-facing choices: // UNSPECIFIED is protobuf's zero-value sentinel and is rejected. // // Current user-facing mapping: // - "Automatic official rate" and "Official rate from another date" are both // OFFICIAL; they differ only in ExchangeRateDateRule. // - "Saved custom rate" is SAVED_CUSTOM: a reusable row already persisted in // the profile's custom_exchange_rates table. // - MANUAL is the current transaction-local, one-off quote path. If the product // supports only persisted manual rates, this value and manual_foreign_units // should be removed and SAVED_CUSTOM should be presented as "Manual rate". enum ExchangeRateSource { // Sentinel for an omitted source; never a selectable business option. EXCHANGE_RATE_SOURCE_UNSPECIFIED = 0; // An immutable observation imported from the configured official provider. EXCHANGE_RATE_SOURCE_OFFICIAL = 1; // A reusable user-maintained quote stored in custom_exchange_rates. EXCHANGE_RATE_SOURCE_SAVED_CUSTOM = 2; // A one-off quote carried only by this request and its audit evidence. EXCHANGE_RATE_SOURCE_MANUAL = 3; } message ExchangeRateSelection { ExchangeRateDateRule date_rule = 1; ExchangeRateSource source = 2; optional string specific_rate_date = 3; optional string manual_foreign_units = 4; string reason = 5; // Omit to use the profile's current default source for the currency. // An explicit different source must be enabled for the same direct pair and // is recorded as an audited per-event override. optional string rate_source_id = 6; } service ExchangeRateService { // Lists the direct-rate providers compiled into and registered by this // server instance. Clients use these stable IDs when configuring profiles. rpc ListRateSources(komp_ac.common.Empty) returns (ListRateSourcesResponse); rpc PreviewDirectConversion(PreviewDirectConversionRequest) returns (PreviewDirectConversionResponse); rpc ListConversionEvidence(ListConversionEvidenceRequest) returns (ListConversionEvidenceResponse); rpc GetProfileExchangeRateSettings(GetProfileExchangeRateSettingsRequest) returns (ProfileExchangeRateSettings); rpc AddProfileCurrencySource(AddProfileCurrencySourceRequest) returns (ProfileForeignCurrency); } message RateSourceProvider { string id = 1; } message ListRateSourcesResponse { repeated RateSourceProvider sources = 1; } message PreviewDirectConversionRequest { string original_amount = 1; string original_currency = 2; string conversion_basis_date = 3; string profile_name = 4; optional ExchangeRateSelection exchange_rate_selection = 5; } message PreviewDirectConversionResponse { string original_amount = 1; string original_currency = 2; string converted_amount = 3; string accounting_currency = 4; string conversion_basis_date = 5; string determination_method = 6; string rounding_method = 7; optional string rate_date = 8; optional string accounting_units = 9; optional string foreign_currency = 10; optional string foreign_units = 11; string source_id = 12; optional int64 official_observation_id = 13; optional string observation_hash = 14; optional string source_payload_hash = 15; optional string rate_fetched_at = 16; optional int64 import_batch_id = 17; optional string source_endpoint = 18; optional int64 custom_rate_table_definition_id = 19; optional int64 custom_rate_record_id = 20; optional int64 custom_rate_row_revision = 21; optional string custom_rate_note = 22; ExchangeRateDateRule applied_date_rule = 23; ExchangeRateSource applied_source = 24; string selection_reason = 25; } message ListConversionEvidenceRequest { string profile_name = 1; string table_name = 2; int64 record_id = 3; string column_name = 4; int32 limit = 5; optional int64 before_evidence_id = 6; } message ConversionEvidence { int64 evidence_id = 1; int64 row_revision = 2; string original_amount = 3; string original_currency = 4; string converted_amount = 5; string accounting_currency = 6; string accounting_units = 7; string foreign_currency = 8; string foreign_units = 9; string conversion_context = 10; string conversion_basis_date = 11; string determination_method = 12; string rounding_method = 13; optional string rate_date = 14; string source_id = 15; optional int64 official_observation_id = 16; optional string observation_hash = 17; optional string source_payload_hash = 18; optional string rate_fetched_at = 19; optional int64 import_batch_id = 20; optional string source_endpoint = 21; string evidence_created_at = 22; optional int64 custom_rate_table_definition_id = 23; optional int64 custom_rate_record_id = 24; optional int64 custom_rate_row_revision = 25; optional string custom_rate_note = 26; string selection_reason = 27; optional string selected_by_user_id = 28; } message ListConversionEvidenceResponse { bool has_exchange = 1; repeated ConversionEvidence evidence = 2; bool has_more = 3; } message GetProfileExchangeRateSettingsRequest { string profile_name = 1; } message ProfileForeignCurrency { string currency = 1; string default_source_id = 2; repeated ProfileCurrencySource sources = 3; } message ProfileCurrencySource { string source_id = 1; bool coverage_complete = 2; optional string verified_from_date = 3; optional string verified_through_date = 4; } message ProfileExchangeRateSettings { string profile_name = 1; string accounting_currency = 2; repeated string enabled_source_ids = 3; repeated ProfileForeignCurrency foreign_currencies = 4; } message AddProfileCurrencySourceRequest { string profile_name = 1; string currency = 2; string source_id = 3; bool make_default = 4; }