currency per column in table definition
This commit is contained in:
@@ -30,7 +30,6 @@ message AnalyticsTable {
|
|||||||
string name = 2;
|
string name = 2;
|
||||||
repeated AnalyticsCatalogColumn columns = 3;
|
repeated AnalyticsCatalogColumn columns = 3;
|
||||||
repeated AnalyticsTableLink links = 4;
|
repeated AnalyticsTableLink links = 4;
|
||||||
string base_currency = 5;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
message AnalyticsCatalogColumn {
|
message AnalyticsCatalogColumn {
|
||||||
@@ -39,6 +38,8 @@ message AnalyticsCatalogColumn {
|
|||||||
string field_type = 2;
|
string field_type = 2;
|
||||||
bool is_system = 3;
|
bool is_system = 3;
|
||||||
string rounding = 4;
|
string rounding = 4;
|
||||||
|
// Canonical ISO-4217 code for MONEY; empty for every other type.
|
||||||
|
string currency = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
message AnalyticsTableLink {
|
message AnalyticsTableLink {
|
||||||
|
|||||||
@@ -83,9 +83,6 @@ message PostTableDefinitionRequest {
|
|||||||
// like "public", "information_schema", or ones starting with "pg_".
|
// like "public", "information_schema", or ones starting with "pg_".
|
||||||
string profile_name = 5;
|
string profile_name = 5;
|
||||||
|
|
||||||
// ISO-4217 base currency used by every MONEY column in this table.
|
|
||||||
string base_currency = 6;
|
|
||||||
|
|
||||||
// Columns whose values identify a row to users in pickers, in the order
|
// Columns whose values identify a row to users in pickers, in the order
|
||||||
// they are shown. Each must name one of the user-defined columns above.
|
// they are shown. Each must name one of the user-defined columns above.
|
||||||
// Empty means the row is identified by its id alone.
|
// Empty means the row is identified by its id alone.
|
||||||
@@ -94,7 +91,7 @@ message PostTableDefinitionRequest {
|
|||||||
// ISO-4217 currency the profile keeps its accounting in. A profile is one
|
// ISO-4217 currency the profile keeps its accounting in. A profile is one
|
||||||
// accounting entity and keeps one set of books, so this is required only when
|
// accounting entity and keeps one set of books, so this is required only when
|
||||||
// the request creates the profile, and is ignored afterwards. It is unrelated
|
// the request creates the profile, and is ignored afterwards. It is unrelated
|
||||||
// to base_currency: tables may hold money in any currency, and amounts convert
|
// to individual MONEY-column currencies: tables may hold money in any currency, and amounts convert
|
||||||
// to this one when they reach the ledger.
|
// to this one when they reach the ledger.
|
||||||
string accounting_currency = 8;
|
string accounting_currency = 8;
|
||||||
}
|
}
|
||||||
@@ -116,7 +113,6 @@ message CreateInvoiceTemplateTableRequest {
|
|||||||
string profile_name = 1;
|
string profile_name = 1;
|
||||||
string table_name = 2;
|
string table_name = 2;
|
||||||
string typst_source = 3;
|
string typst_source = 3;
|
||||||
string base_currency = 4;
|
|
||||||
repeated string row_display_columns = 5;
|
repeated string row_display_columns = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,9 +146,6 @@ message AddTableColumnsRequest {
|
|||||||
// Optional indexes for the new columns only.
|
// Optional indexes for the new columns only.
|
||||||
repeated string indexes = 4;
|
repeated string indexes = 4;
|
||||||
|
|
||||||
// Required when adding the first MONEY column to a table.
|
|
||||||
string base_currency = 5;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum MoneyRounding {
|
enum MoneyRounding {
|
||||||
@@ -176,7 +169,7 @@ message ColumnDefinition {
|
|||||||
// RAW_DATETIME (timezone-free civil datetime)
|
// RAW_DATETIME (timezone-free civil datetime)
|
||||||
// PHONE (international or national phone number; generates extension/type/country/calling-code companions)
|
// PHONE (international or national phone number; generates extension/type/country/calling-code companions)
|
||||||
// TIME (timezone-free time of day)
|
// TIME (timezone-free time of day)
|
||||||
// MONEY (= unconstrained NUMERIC; currency comes from the table)
|
// MONEY (= unconstrained NUMERIC; currency is declared below)
|
||||||
// ACCOUNTING (creates schema-managed name, account, debit, and credit fields;
|
// ACCOUNTING (creates schema-managed name, account, debit, and credit fields;
|
||||||
// account always selects a row from the profile's managed accounts table;
|
// account always selects a row from the profile's managed accounts table;
|
||||||
// name is limited to 10 characters and one stored row contributes
|
// name is limited to 10 characters and one stored row contributes
|
||||||
@@ -197,6 +190,10 @@ message ColumnDefinition {
|
|||||||
// When true, this numeric column is server-owned and projected from the
|
// When true, this numeric column is server-owned and projected from the
|
||||||
// profile quantity ledger.
|
// profile quantity ledger.
|
||||||
bool quantity_ledger = 4;
|
bool quantity_ledger = 4;
|
||||||
|
|
||||||
|
// Canonical uppercase ISO-4217 currency code. Required for MONEY and forbidden
|
||||||
|
// for every other field type.
|
||||||
|
string currency = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Response after table creation (success + DDL preview).
|
// Response after table creation (success + DDL preview).
|
||||||
@@ -299,7 +296,6 @@ message TableDetail {
|
|||||||
int64 id = 2;
|
int64 id = 2;
|
||||||
repeated ColumnDefinition columns = 3;
|
repeated ColumnDefinition columns = 3;
|
||||||
repeated ScriptInfo scripts = 4;
|
repeated ScriptInfo scripts = 4;
|
||||||
string base_currency = 5;
|
|
||||||
repeated string row_display_columns = 6;
|
repeated string row_display_columns = 6;
|
||||||
map<string, ColumnBehavior> column_behaviors = 7;
|
map<string, ColumnBehavior> column_behaviors = 7;
|
||||||
string table_kind = 8;
|
string table_kind = 8;
|
||||||
|
|||||||
@@ -210,8 +210,8 @@ message HydratedColumnValue {
|
|||||||
string value = 4;
|
string value = 4;
|
||||||
// Logical database type used to create a typed client ScriptValue.
|
// Logical database type used to create a typed client ScriptValue.
|
||||||
string field_type = 5;
|
string field_type = 5;
|
||||||
// Related table's base currency for MONEY values; otherwise empty.
|
// Related MONEY column's currency; otherwise empty.
|
||||||
string base_currency = 6;
|
string currency = 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
// One declared related-collection aggregate input for the client Steel context.
|
// One declared related-collection aggregate input for the client Steel context.
|
||||||
@@ -229,8 +229,8 @@ message HydratedAggregateValue {
|
|||||||
string value = 5;
|
string value = 5;
|
||||||
// Logical source-column type; empty for row-only aggregates.
|
// Logical source-column type; empty for row-only aggregates.
|
||||||
string field_type = 6;
|
string field_type = 6;
|
||||||
// Aggregate table's base currency for MONEY values; otherwise empty.
|
// Aggregated MONEY column's currency; otherwise empty.
|
||||||
string base_currency = 7;
|
string currency = 7;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Complete external dependency snapshot for client-side Steel execution.
|
// Complete external dependency snapshot for client-side Steel execution.
|
||||||
|
|||||||
Binary file not shown.
@@ -22,8 +22,6 @@ pub struct AnalyticsTable {
|
|||||||
pub columns: ::prost::alloc::vec::Vec<AnalyticsCatalogColumn>,
|
pub columns: ::prost::alloc::vec::Vec<AnalyticsCatalogColumn>,
|
||||||
#[prost(message, repeated, tag = "4")]
|
#[prost(message, repeated, tag = "4")]
|
||||||
pub links: ::prost::alloc::vec::Vec<AnalyticsTableLink>,
|
pub links: ::prost::alloc::vec::Vec<AnalyticsTableLink>,
|
||||||
#[prost(string, tag = "5")]
|
|
||||||
pub base_currency: ::prost::alloc::string::String,
|
|
||||||
}
|
}
|
||||||
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
|
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
|
||||||
pub struct AnalyticsCatalogColumn {
|
pub struct AnalyticsCatalogColumn {
|
||||||
@@ -36,6 +34,9 @@ pub struct AnalyticsCatalogColumn {
|
|||||||
pub is_system: bool,
|
pub is_system: bool,
|
||||||
#[prost(string, tag = "4")]
|
#[prost(string, tag = "4")]
|
||||||
pub rounding: ::prost::alloc::string::String,
|
pub rounding: ::prost::alloc::string::String,
|
||||||
|
/// Canonical ISO-4217 code for MONEY; empty for every other type.
|
||||||
|
#[prost(string, tag = "5")]
|
||||||
|
pub currency: ::prost::alloc::string::String,
|
||||||
}
|
}
|
||||||
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
|
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
|
||||||
pub struct AnalyticsTableLink {
|
pub struct AnalyticsTableLink {
|
||||||
|
|||||||
@@ -42,9 +42,6 @@ pub struct PostTableDefinitionRequest {
|
|||||||
/// like "public", "information_schema", or ones starting with "pg\_".
|
/// like "public", "information_schema", or ones starting with "pg\_".
|
||||||
#[prost(string, tag = "5")]
|
#[prost(string, tag = "5")]
|
||||||
pub profile_name: ::prost::alloc::string::String,
|
pub profile_name: ::prost::alloc::string::String,
|
||||||
/// ISO-4217 base currency used by every MONEY column in this table.
|
|
||||||
#[prost(string, tag = "6")]
|
|
||||||
pub base_currency: ::prost::alloc::string::String,
|
|
||||||
/// Columns whose values identify a row to users in pickers, in the order
|
/// Columns whose values identify a row to users in pickers, in the order
|
||||||
/// they are shown. Each must name one of the user-defined columns above.
|
/// they are shown. Each must name one of the user-defined columns above.
|
||||||
/// Empty means the row is identified by its id alone.
|
/// Empty means the row is identified by its id alone.
|
||||||
@@ -53,7 +50,7 @@ pub struct PostTableDefinitionRequest {
|
|||||||
/// ISO-4217 currency the profile keeps its accounting in. A profile is one
|
/// ISO-4217 currency the profile keeps its accounting in. A profile is one
|
||||||
/// accounting entity and keeps one set of books, so this is required only when
|
/// accounting entity and keeps one set of books, so this is required only when
|
||||||
/// the request creates the profile, and is ignored afterwards. It is unrelated
|
/// the request creates the profile, and is ignored afterwards. It is unrelated
|
||||||
/// to base_currency: tables may hold money in any currency, and amounts convert
|
/// to individual MONEY-column currencies: tables may hold money in any currency, and amounts convert
|
||||||
/// to this one when they reach the ledger.
|
/// to this one when they reach the ledger.
|
||||||
#[prost(string, tag = "8")]
|
#[prost(string, tag = "8")]
|
||||||
pub accounting_currency: ::prost::alloc::string::String,
|
pub accounting_currency: ::prost::alloc::string::String,
|
||||||
@@ -80,8 +77,6 @@ pub struct CreateInvoiceTemplateTableRequest {
|
|||||||
pub table_name: ::prost::alloc::string::String,
|
pub table_name: ::prost::alloc::string::String,
|
||||||
#[prost(string, tag = "3")]
|
#[prost(string, tag = "3")]
|
||||||
pub typst_source: ::prost::alloc::string::String,
|
pub typst_source: ::prost::alloc::string::String,
|
||||||
#[prost(string, tag = "4")]
|
|
||||||
pub base_currency: ::prost::alloc::string::String,
|
|
||||||
#[prost(string, repeated, tag = "5")]
|
#[prost(string, repeated, tag = "5")]
|
||||||
pub row_display_columns: ::prost::alloc::vec::Vec<::prost::alloc::string::String>,
|
pub row_display_columns: ::prost::alloc::vec::Vec<::prost::alloc::string::String>,
|
||||||
}
|
}
|
||||||
@@ -125,9 +120,6 @@ pub struct AddTableColumnsRequest {
|
|||||||
/// Optional indexes for the new columns only.
|
/// Optional indexes for the new columns only.
|
||||||
#[prost(string, repeated, tag = "4")]
|
#[prost(string, repeated, tag = "4")]
|
||||||
pub indexes: ::prost::alloc::vec::Vec<::prost::alloc::string::String>,
|
pub indexes: ::prost::alloc::vec::Vec<::prost::alloc::string::String>,
|
||||||
/// Required when adding the first MONEY column to a table.
|
|
||||||
#[prost(string, tag = "5")]
|
|
||||||
pub base_currency: ::prost::alloc::string::String,
|
|
||||||
}
|
}
|
||||||
/// Describes one user-defined column for a table.
|
/// Describes one user-defined column for a table.
|
||||||
#[derive(serde::Serialize, serde::Deserialize)]
|
#[derive(serde::Serialize, serde::Deserialize)]
|
||||||
@@ -147,7 +139,7 @@ pub struct ColumnDefinition {
|
|||||||
/// RAW_DATETIME (timezone-free civil datetime)
|
/// RAW_DATETIME (timezone-free civil datetime)
|
||||||
/// PHONE (international or national phone number; generates extension/type/country/calling-code companions)
|
/// PHONE (international or national phone number; generates extension/type/country/calling-code companions)
|
||||||
/// TIME (timezone-free time of day)
|
/// TIME (timezone-free time of day)
|
||||||
/// MONEY (= unconstrained NUMERIC; currency comes from the table)
|
/// MONEY (= unconstrained NUMERIC; currency is declared below)
|
||||||
/// ACCOUNTING (creates schema-managed name, account, debit, and credit fields;
|
/// ACCOUNTING (creates schema-managed name, account, debit, and credit fields;
|
||||||
/// account always selects a row from the profile's managed accounts table;
|
/// account always selects a row from the profile's managed accounts table;
|
||||||
/// name is limited to 10 characters and one stored row contributes
|
/// name is limited to 10 characters and one stored row contributes
|
||||||
@@ -169,6 +161,10 @@ pub struct ColumnDefinition {
|
|||||||
/// profile quantity ledger.
|
/// profile quantity ledger.
|
||||||
#[prost(bool, tag = "4")]
|
#[prost(bool, tag = "4")]
|
||||||
pub quantity_ledger: bool,
|
pub quantity_ledger: bool,
|
||||||
|
/// Canonical uppercase ISO-4217 currency code. Required for MONEY and forbidden
|
||||||
|
/// for every other field type.
|
||||||
|
#[prost(string, tag = "5")]
|
||||||
|
pub currency: ::prost::alloc::string::String,
|
||||||
}
|
}
|
||||||
/// Response after table creation (success + DDL preview).
|
/// Response after table creation (success + DDL preview).
|
||||||
#[derive(serde::Serialize, serde::Deserialize)]
|
#[derive(serde::Serialize, serde::Deserialize)]
|
||||||
@@ -310,8 +306,6 @@ pub struct TableDetail {
|
|||||||
pub columns: ::prost::alloc::vec::Vec<ColumnDefinition>,
|
pub columns: ::prost::alloc::vec::Vec<ColumnDefinition>,
|
||||||
#[prost(message, repeated, tag = "4")]
|
#[prost(message, repeated, tag = "4")]
|
||||||
pub scripts: ::prost::alloc::vec::Vec<ScriptInfo>,
|
pub scripts: ::prost::alloc::vec::Vec<ScriptInfo>,
|
||||||
#[prost(string, tag = "5")]
|
|
||||||
pub base_currency: ::prost::alloc::string::String,
|
|
||||||
#[prost(string, repeated, tag = "6")]
|
#[prost(string, repeated, tag = "6")]
|
||||||
pub row_display_columns: ::prost::alloc::vec::Vec<::prost::alloc::string::String>,
|
pub row_display_columns: ::prost::alloc::vec::Vec<::prost::alloc::string::String>,
|
||||||
#[prost(map = "string, message", tag = "7")]
|
#[prost(map = "string, message", tag = "7")]
|
||||||
|
|||||||
@@ -168,9 +168,9 @@ pub struct HydratedColumnValue {
|
|||||||
/// Logical database type used to create a typed client ScriptValue.
|
/// Logical database type used to create a typed client ScriptValue.
|
||||||
#[prost(string, tag = "5")]
|
#[prost(string, tag = "5")]
|
||||||
pub field_type: ::prost::alloc::string::String,
|
pub field_type: ::prost::alloc::string::String,
|
||||||
/// Related table's base currency for MONEY values; otherwise empty.
|
/// Related MONEY column's currency; otherwise empty.
|
||||||
#[prost(string, tag = "6")]
|
#[prost(string, tag = "6")]
|
||||||
pub base_currency: ::prost::alloc::string::String,
|
pub currency: ::prost::alloc::string::String,
|
||||||
}
|
}
|
||||||
/// One declared related-collection aggregate input for the client Steel context.
|
/// One declared related-collection aggregate input for the client Steel context.
|
||||||
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
|
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
|
||||||
@@ -194,9 +194,9 @@ pub struct HydratedAggregateValue {
|
|||||||
/// Logical source-column type; empty for row-only aggregates.
|
/// Logical source-column type; empty for row-only aggregates.
|
||||||
#[prost(string, tag = "6")]
|
#[prost(string, tag = "6")]
|
||||||
pub field_type: ::prost::alloc::string::String,
|
pub field_type: ::prost::alloc::string::String,
|
||||||
/// Aggregate table's base currency for MONEY values; otherwise empty.
|
/// Aggregated MONEY column's currency; otherwise empty.
|
||||||
#[prost(string, tag = "7")]
|
#[prost(string, tag = "7")]
|
||||||
pub base_currency: ::prost::alloc::string::String,
|
pub currency: ::prost::alloc::string::String,
|
||||||
}
|
}
|
||||||
/// Complete external dependency snapshot for client-side Steel execution.
|
/// Complete external dependency snapshot for client-side Steel execution.
|
||||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
|
|||||||
@@ -146,7 +146,6 @@ grpcurl -plaintext -H "$AUTH_HEADER" \
|
|||||||
"profile_name":"fakturacia_2026",
|
"profile_name":"fakturacia_2026",
|
||||||
"table_name":"faktura",
|
"table_name":"faktura",
|
||||||
"row_display_column":"cislo",
|
"row_display_column":"cislo",
|
||||||
"base_currency":"EUR",
|
|
||||||
"links":[
|
"links":[
|
||||||
{"linked_table_name":"dodavatel","required":true},
|
{"linked_table_name":"dodavatel","required":true},
|
||||||
{"linked_table_name":"odberatel","required":true}
|
{"linked_table_name":"odberatel","required":true}
|
||||||
@@ -158,9 +157,9 @@ grpcurl -plaintext -H "$AUTH_HEADER" \
|
|||||||
{"name":"datum_splatnosti","field_type":"DATE"},
|
{"name":"datum_splatnosti","field_type":"DATE"},
|
||||||
{"name":"variabilny_symbol","field_type":"TEXT"},
|
{"name":"variabilny_symbol","field_type":"TEXT"},
|
||||||
{"name":"sposob_uhrady","field_type":"TEXT"},
|
{"name":"sposob_uhrady","field_type":"TEXT"},
|
||||||
{"name":"zaklad_dane","field_type":"MONEY","rounding":"MONEY_ROUNDING_HALF_UP","recompute_on_dependency_change":true},
|
{"name":"zaklad_dane","field_type":"MONEY","currency":"EUR","rounding":"MONEY_ROUNDING_HALF_UP","recompute_on_dependency_change":true},
|
||||||
{"name":"dph_celkom","field_type":"MONEY","rounding":"MONEY_ROUNDING_HALF_UP","recompute_on_dependency_change":true},
|
{"name":"dph_celkom","field_type":"MONEY","currency":"EUR","rounding":"MONEY_ROUNDING_HALF_UP","recompute_on_dependency_change":true},
|
||||||
{"name":"celkom_spolu","field_type":"MONEY","rounding":"MONEY_ROUNDING_HALF_UP","recompute_on_dependency_change":true},
|
{"name":"celkom_spolu","field_type":"MONEY","currency":"EUR","rounding":"MONEY_ROUNDING_HALF_UP","recompute_on_dependency_change":true},
|
||||||
{"name":"poznamka","field_type":"TEXT"}
|
{"name":"poznamka","field_type":"TEXT"}
|
||||||
]
|
]
|
||||||
}' \
|
}' \
|
||||||
@@ -176,17 +175,16 @@ grpcurl -plaintext -H "$AUTH_HEADER" \
|
|||||||
"profile_name":"fakturacia_2026",
|
"profile_name":"fakturacia_2026",
|
||||||
"table_name":"polozka",
|
"table_name":"polozka",
|
||||||
"row_display_column":"nazov",
|
"row_display_column":"nazov",
|
||||||
"base_currency":"EUR",
|
|
||||||
"links":[{"linked_table_name":"faktura","required":true}],
|
"links":[{"linked_table_name":"faktura","required":true}],
|
||||||
"columns":[
|
"columns":[
|
||||||
{"name":"nazov","field_type":"TEXT"},
|
{"name":"nazov","field_type":"TEXT"},
|
||||||
{"name":"mnozstvo","field_type":"DECIMAL(12,3)"},
|
{"name":"mnozstvo","field_type":"DECIMAL(12,3)"},
|
||||||
{"name":"mj","field_type":"TEXT"},
|
{"name":"mj","field_type":"TEXT"},
|
||||||
{"name":"cena","field_type":"MONEY","rounding":"MONEY_ROUNDING_HALF_UP"},
|
{"name":"cena","field_type":"MONEY","currency":"EUR","rounding":"MONEY_ROUNDING_HALF_UP"},
|
||||||
{"name":"dph","field_type":"DECIMAL(5,2)"},
|
{"name":"dph","field_type":"DECIMAL(5,2)"},
|
||||||
{"name":"bez","field_type":"MONEY","rounding":"MONEY_ROUNDING_HALF_UP","recompute_on_dependency_change":true},
|
{"name":"bez","field_type":"MONEY","currency":"EUR","rounding":"MONEY_ROUNDING_HALF_UP","recompute_on_dependency_change":true},
|
||||||
{"name":"dph_suma","field_type":"MONEY","rounding":"MONEY_ROUNDING_HALF_UP","recompute_on_dependency_change":true},
|
{"name":"dph_suma","field_type":"MONEY","currency":"EUR","rounding":"MONEY_ROUNDING_HALF_UP","recompute_on_dependency_change":true},
|
||||||
{"name":"spolu","field_type":"MONEY","rounding":"MONEY_ROUNDING_HALF_UP","recompute_on_dependency_change":true}
|
{"name":"spolu","field_type":"MONEY","currency":"EUR","rounding":"MONEY_ROUNDING_HALF_UP","recompute_on_dependency_change":true}
|
||||||
]
|
]
|
||||||
}' \
|
}' \
|
||||||
"$GRPC_ADDR" komp_ac.table_definition.TableDefinition/PostTableDefinition
|
"$GRPC_ADDR" komp_ac.table_definition.TableDefinition/PostTableDefinition
|
||||||
|
|||||||
2
server
2
server
Submodule server updated: 453d16c430...c637ba7883
@@ -140,6 +140,7 @@ pub(crate) struct ColumnDefinition {
|
|||||||
pub indexed: bool,
|
pub indexed: bool,
|
||||||
pub quantity_ledger: bool,
|
pub quantity_ledger: bool,
|
||||||
pub money_mode: MoneyMode,
|
pub money_mode: MoneyMode,
|
||||||
|
pub currency: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ColumnDefinition {
|
impl ColumnDefinition {
|
||||||
@@ -147,9 +148,9 @@ impl ColumnDefinition {
|
|||||||
pub(crate) fn option_label(&self) -> String {
|
pub(crate) fn option_label(&self) -> String {
|
||||||
let is_money = self.data_type.eq_ignore_ascii_case("money");
|
let is_money = self.data_type.eq_ignore_ascii_case("money");
|
||||||
match (self.indexed, is_money) {
|
match (self.indexed, is_money) {
|
||||||
(true, true) => format!("indexed, {}", self.money_mode.label()),
|
(true, true) => format!("indexed, {}, {}", self.currency, self.money_mode.label()),
|
||||||
(true, false) => "indexed".to_string(),
|
(true, false) => "indexed".to_string(),
|
||||||
(false, true) => self.money_mode.label().to_string(),
|
(false, true) => format!("{}, {}", self.currency, self.money_mode.label()),
|
||||||
(false, false) => String::new(),
|
(false, false) => String::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -181,7 +182,6 @@ pub(crate) struct TableDraft {
|
|||||||
pub accounting_currency: String,
|
pub accounting_currency: String,
|
||||||
|
|
||||||
pub table_name: String,
|
pub table_name: String,
|
||||||
pub base_currency: String,
|
|
||||||
|
|
||||||
// The column-input panel: one pending column being described.
|
// The column-input panel: one pending column being described.
|
||||||
pub column_name_input: String,
|
pub column_name_input: String,
|
||||||
@@ -191,6 +191,7 @@ pub(crate) struct TableDraft {
|
|||||||
pub column_indexing_input: String,
|
pub column_indexing_input: String,
|
||||||
pub column_quantity_ledger_input: String,
|
pub column_quantity_ledger_input: String,
|
||||||
pub column_rounding_input: String,
|
pub column_rounding_input: String,
|
||||||
|
pub column_currency_input: String,
|
||||||
|
|
||||||
pub columns: Vec<ColumnDefinition>,
|
pub columns: Vec<ColumnDefinition>,
|
||||||
pub links: Vec<LinkDefinition>,
|
pub links: Vec<LinkDefinition>,
|
||||||
@@ -208,10 +209,10 @@ impl TableDraft {
|
|||||||
pub(crate) fn new() -> Self {
|
pub(crate) fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
accounting_currency: "EUR".to_string(),
|
accounting_currency: "EUR".to_string(),
|
||||||
base_currency: "EUR".to_string(),
|
|
||||||
column_indexing_input: "no".to_string(),
|
column_indexing_input: "no".to_string(),
|
||||||
column_quantity_ledger_input: "no".to_string(),
|
column_quantity_ledger_input: "no".to_string(),
|
||||||
column_rounding_input: "none".to_string(),
|
column_rounding_input: "none".to_string(),
|
||||||
|
column_currency_input: "EUR".to_string(),
|
||||||
..Self::default()
|
..Self::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -276,10 +277,6 @@ impl TableDraft {
|
|||||||
self.is_money_column_input()
|
self.is_money_column_input()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn show_base_currency(&self) -> bool {
|
|
||||||
self.is_money_column_input() || self.money_column_count() > 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---- mutations -------------------------------------------------------
|
// ---- mutations -------------------------------------------------------
|
||||||
|
|
||||||
/// Appends the pending column, then clears the input panel.
|
/// Appends the pending column, then clears the input panel.
|
||||||
@@ -320,6 +317,11 @@ impl TableDraft {
|
|||||||
|
|
||||||
let is_money = column_type.eq_ignore_ascii_case("money")
|
let is_money = column_type.eq_ignore_ascii_case("money")
|
||||||
|| column_type.eq_ignore_ascii_case("accounting");
|
|| column_type.eq_ignore_ascii_case("accounting");
|
||||||
|
let currency = if is_money {
|
||||||
|
normalize_currency_input(&self.column_currency_input)?
|
||||||
|
} else {
|
||||||
|
String::new()
|
||||||
|
};
|
||||||
self.columns.push(ColumnDefinition {
|
self.columns.push(ColumnDefinition {
|
||||||
name: column_name.clone(),
|
name: column_name.clone(),
|
||||||
data_type: column_type,
|
data_type: column_type,
|
||||||
@@ -333,6 +335,7 @@ impl TableDraft {
|
|||||||
} else {
|
} else {
|
||||||
MoneyMode::Exact
|
MoneyMode::Exact
|
||||||
},
|
},
|
||||||
|
currency,
|
||||||
});
|
});
|
||||||
|
|
||||||
self.clear_column_inputs();
|
self.clear_column_inputs();
|
||||||
@@ -347,6 +350,7 @@ impl TableDraft {
|
|||||||
self.column_indexing_input = "no".to_string();
|
self.column_indexing_input = "no".to_string();
|
||||||
self.column_quantity_ledger_input = "no".to_string();
|
self.column_quantity_ledger_input = "no".to_string();
|
||||||
self.column_rounding_input = "none".to_string();
|
self.column_rounding_input = "none".to_string();
|
||||||
|
self.column_currency_input = "EUR".to_string();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Removes one column, and drops it from the display columns with it.
|
/// Removes one column, and drops it from the display columns with it.
|
||||||
@@ -440,16 +444,6 @@ impl TableDraft {
|
|||||||
.any(|name| name == &self.table_name)
|
.any(|name| name == &self.table_name)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn money_column_count(&self) -> usize {
|
|
||||||
self.columns
|
|
||||||
.iter()
|
|
||||||
.filter(|column| {
|
|
||||||
column.data_type.eq_ignore_ascii_case("money")
|
|
||||||
|| column.data_type.eq_ignore_ascii_case("accounting")
|
|
||||||
})
|
|
||||||
.count()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn selected_index_names(&self) -> Vec<String> {
|
pub(crate) fn selected_index_names(&self) -> Vec<String> {
|
||||||
self.columns
|
self.columns
|
||||||
.iter()
|
.iter()
|
||||||
@@ -561,9 +555,6 @@ impl TableDraft {
|
|||||||
return Err(format!("Column `{}`: {error}", column.name));
|
return Err(format!("Column `{}`: {error}", column.name));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(error) = validate_base_currency(self) {
|
|
||||||
return Err(error);
|
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -585,6 +576,7 @@ impl TableDraft {
|
|||||||
MoneyMode::Exact => MoneyRounding::None.into(),
|
MoneyMode::Exact => MoneyRounding::None.into(),
|
||||||
},
|
},
|
||||||
quantity_ledger: column.quantity_ledger,
|
quantity_ledger: column.quantity_ledger,
|
||||||
|
currency: column.currency.clone(),
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
indexes: self.selected_index_names(),
|
indexes: self.selected_index_names(),
|
||||||
@@ -597,11 +589,6 @@ impl TableDraft {
|
|||||||
required: link.mode.is_required(),
|
required: link.mode.is_required(),
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
base_currency: if self.money_column_count() == 0 {
|
|
||||||
String::new()
|
|
||||||
} else {
|
|
||||||
self.base_currency.trim().to_ascii_uppercase()
|
|
||||||
},
|
|
||||||
accounting_currency: if self.creating_new_profile {
|
accounting_currency: if self.creating_new_profile {
|
||||||
self.accounting_currency.trim().to_ascii_uppercase()
|
self.accounting_currency.trim().to_ascii_uppercase()
|
||||||
} else {
|
} else {
|
||||||
@@ -612,15 +599,12 @@ impl TableDraft {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn validate_base_currency(draft: &TableDraft) -> Option<String> {
|
fn normalize_currency_input(value: &str) -> Result<String, String> {
|
||||||
if draft.money_column_count() == 0 {
|
let currency = value.trim().to_ascii_uppercase();
|
||||||
return None;
|
if rusty_money::iso::find(¤cy).is_none() {
|
||||||
|
return Err("Currency must be a three-letter ISO-4217 code".to_string());
|
||||||
}
|
}
|
||||||
let currency = draft.base_currency.trim();
|
Ok(currency)
|
||||||
if currency.len() != 3 || !currency.chars().all(|c| c.is_ascii_alphabetic()) {
|
|
||||||
return Some("Base currency must be a three-letter ISO-4217 code".to_string());
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn validate_accounting_currency(draft: &TableDraft) -> Option<String> {
|
pub(crate) fn validate_accounting_currency(draft: &TableDraft) -> Option<String> {
|
||||||
@@ -720,6 +704,11 @@ mod tests {
|
|||||||
indexed: false,
|
indexed: false,
|
||||||
quantity_ledger: false,
|
quantity_ledger: false,
|
||||||
money_mode: MoneyMode::Exact,
|
money_mode: MoneyMode::Exact,
|
||||||
|
currency: if matches!(data_type, "money" | "accounting") {
|
||||||
|
"EUR".to_string()
|
||||||
|
} else {
|
||||||
|
String::new()
|
||||||
|
},
|
||||||
});
|
});
|
||||||
draft
|
draft
|
||||||
}
|
}
|
||||||
@@ -795,14 +784,16 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn money_columns_require_a_valid_base_currency() {
|
fn money_columns_require_a_valid_currency() {
|
||||||
let mut draft = draft_with_column("total", "money");
|
let mut draft = TableDraft::new();
|
||||||
draft.base_currency = "EU".to_string();
|
draft.column_name_input = "total".to_string();
|
||||||
assert!(draft.validate().is_err());
|
draft.column_type_input = "money".to_string();
|
||||||
|
draft.column_currency_input = "EU".to_string();
|
||||||
|
assert!(draft.add_column_from_inputs().is_err());
|
||||||
|
|
||||||
draft.base_currency = "eur".to_string();
|
draft.column_currency_input = "eur".to_string();
|
||||||
assert!(draft.validate().is_ok());
|
draft.add_column_from_inputs().unwrap();
|
||||||
assert_eq!(draft.into_request().unwrap().base_currency, "EUR");
|
assert_eq!(draft.columns[0].currency, "EUR");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -826,8 +817,6 @@ mod tests {
|
|||||||
|
|
||||||
assert_eq!(request.accounting_currency, "");
|
assert_eq!(request.accounting_currency, "");
|
||||||
assert_eq!(request.profile_name, "billing");
|
assert_eq!(request.profile_name, "billing");
|
||||||
// No money column, so no base currency either.
|
|
||||||
assert_eq!(request.base_currency, "");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -886,6 +875,7 @@ mod tests {
|
|||||||
indexed: false,
|
indexed: false,
|
||||||
quantity_ledger: false,
|
quantity_ledger: false,
|
||||||
money_mode: MoneyMode::Exact,
|
money_mode: MoneyMode::Exact,
|
||||||
|
currency: String::new(),
|
||||||
});
|
});
|
||||||
|
|
||||||
draft.toggle_row_display_candidate(2); // issued_on
|
draft.toggle_row_display_candidate(2); // issued_on
|
||||||
|
|||||||
@@ -28,8 +28,6 @@ pub(crate) struct BuilderForm {
|
|||||||
pub accounting_currency: String,
|
pub accounting_currency: String,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub table_name: String,
|
pub table_name: String,
|
||||||
#[serde(default)]
|
|
||||||
pub base_currency: String,
|
|
||||||
|
|
||||||
// The pending column being described in the input panel.
|
// The pending column being described in the input panel.
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
@@ -46,6 +44,8 @@ pub(crate) struct BuilderForm {
|
|||||||
pub column_quantity_ledger_input: String,
|
pub column_quantity_ledger_input: String,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub column_rounding_input: String,
|
pub column_rounding_input: String,
|
||||||
|
#[serde(default)]
|
||||||
|
pub column_currency_input: String,
|
||||||
|
|
||||||
// One entry per already-added column, in order.
|
// One entry per already-added column, in order.
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
@@ -58,6 +58,8 @@ pub(crate) struct BuilderForm {
|
|||||||
pub column_quantity_ledger: Vec<String>,
|
pub column_quantity_ledger: Vec<String>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub column_rounding: Vec<String>,
|
pub column_rounding: Vec<String>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub column_currencies: Vec<String>,
|
||||||
|
|
||||||
// One entry per link target offered by the profile, in order.
|
// One entry per link target offered by the profile, in order.
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
@@ -92,6 +94,7 @@ impl BuilderForm {
|
|||||||
self.column_indexed.len(),
|
self.column_indexed.len(),
|
||||||
self.column_quantity_ledger.len(),
|
self.column_quantity_ledger.len(),
|
||||||
self.column_rounding.len(),
|
self.column_rounding.len(),
|
||||||
|
self.column_currencies.len(),
|
||||||
]
|
]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.min()
|
.min()
|
||||||
@@ -108,6 +111,7 @@ impl BuilderForm {
|
|||||||
} else {
|
} else {
|
||||||
MoneyMode::Exact
|
MoneyMode::Exact
|
||||||
},
|
},
|
||||||
|
currency: self.column_currencies[index].clone(),
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
@@ -138,7 +142,6 @@ impl BuilderForm {
|
|||||||
creating_new_profile,
|
creating_new_profile,
|
||||||
accounting_currency: self.accounting_currency.clone(),
|
accounting_currency: self.accounting_currency.clone(),
|
||||||
table_name: self.table_name.clone(),
|
table_name: self.table_name.clone(),
|
||||||
base_currency: self.base_currency.clone(),
|
|
||||||
column_name_input: self.column_name_input.clone(),
|
column_name_input: self.column_name_input.clone(),
|
||||||
column_type_input: self.column_type_input.clone(),
|
column_type_input: self.column_type_input.clone(),
|
||||||
temporal_type_input: self.temporal_type_input.clone(),
|
temporal_type_input: self.temporal_type_input.clone(),
|
||||||
@@ -146,6 +149,7 @@ impl BuilderForm {
|
|||||||
column_indexing_input: self.column_indexing_input.clone(),
|
column_indexing_input: self.column_indexing_input.clone(),
|
||||||
column_quantity_ledger_input: self.column_quantity_ledger_input.clone(),
|
column_quantity_ledger_input: self.column_quantity_ledger_input.clone(),
|
||||||
column_rounding_input: self.column_rounding_input.clone(),
|
column_rounding_input: self.column_rounding_input.clone(),
|
||||||
|
column_currency_input: self.column_currency_input.clone(),
|
||||||
columns,
|
columns,
|
||||||
links,
|
links,
|
||||||
row_display_columns,
|
row_display_columns,
|
||||||
@@ -231,6 +235,7 @@ mod tests {
|
|||||||
column_indexed: vec!["yes".into(), "no".into()],
|
column_indexed: vec!["yes".into(), "no".into()],
|
||||||
column_quantity_ledger: vec!["no".into(), "no".into()],
|
column_quantity_ledger: vec!["no".into(), "no".into()],
|
||||||
column_rounding: vec!["exact".into(), "half-up".into()],
|
column_rounding: vec!["exact".into(), "half-up".into()],
|
||||||
|
column_currencies: vec![String::new(), "EUR".into()],
|
||||||
link_tables: vec!["customer".into(), "project".into()],
|
link_tables: vec!["customer".into(), "project".into()],
|
||||||
link_modes: vec!["required".into(), "none".into()],
|
link_modes: vec!["required".into(), "none".into()],
|
||||||
row_display_columns: vec!["number".into()],
|
row_display_columns: vec!["number".into()],
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ mod tests {
|
|||||||
indexed: true,
|
indexed: true,
|
||||||
quantity_ledger: false,
|
quantity_ledger: false,
|
||||||
money_mode: MoneyMode::Exact,
|
money_mode: MoneyMode::Exact,
|
||||||
|
currency: String::new(),
|
||||||
});
|
});
|
||||||
draft.set_available_relation_tables(vec!["customer".to_string()]);
|
draft.set_available_relation_tables(vec!["customer".to_string()]);
|
||||||
draft.cycle_link_mode(0);
|
draft.cycle_link_mode(0);
|
||||||
@@ -126,7 +127,7 @@ mod tests {
|
|||||||
state.draft.column_type_input = "gtin".to_string();
|
state.draft.column_type_input = "gtin".to_string();
|
||||||
assert!(render_builder(&state).contains(r#"name="gtin_type_input""#));
|
assert!(render_builder(&state).contains(r#"name="gtin_type_input""#));
|
||||||
|
|
||||||
// Money reveals rounding, and the base currency becomes editable.
|
// Money reveals its currency and rounding inputs.
|
||||||
state.draft.column_type_input = "money".to_string();
|
state.draft.column_type_input = "money".to_string();
|
||||||
let html = render_builder(&state);
|
let html = render_builder(&state);
|
||||||
assert!(html.contains(r#"name="column_rounding_input""#));
|
assert!(html.contains(r#"name="column_rounding_input""#));
|
||||||
|
|||||||
@@ -144,7 +144,6 @@ fn catalog_view(catalog: &GetAnalyticsCatalogResponse) -> CatalogView {
|
|||||||
fn catalog_table_view(table: &AnalyticsTable) -> CatalogTableView {
|
fn catalog_table_view(table: &AnalyticsTable) -> CatalogTableView {
|
||||||
CatalogTableView {
|
CatalogTableView {
|
||||||
name: table.name.clone(),
|
name: table.name.clone(),
|
||||||
base_currency: table.base_currency.clone(),
|
|
||||||
starter_query: format!("SELECT *\nFROM {}\nLIMIT 100;", quote_identifier(&table.name)),
|
starter_query: format!("SELECT *\nFROM {}\nLIMIT 100;", quote_identifier(&table.name)),
|
||||||
columns: table
|
columns: table
|
||||||
.columns
|
.columns
|
||||||
@@ -157,6 +156,9 @@ fn catalog_table_view(table: &AnalyticsTable) -> CatalogTableView {
|
|||||||
if !column.rounding.is_empty() {
|
if !column.rounding.is_empty() {
|
||||||
details.push_str(&format!(", rounding {}", column.rounding));
|
details.push_str(&format!(", rounding {}", column.rounding));
|
||||||
}
|
}
|
||||||
|
if !column.currency.is_empty() {
|
||||||
|
details.push_str(&format!(", currency {}", column.currency));
|
||||||
|
}
|
||||||
CatalogColumnView {
|
CatalogColumnView {
|
||||||
name: column.name.clone(),
|
name: column.name.clone(),
|
||||||
insert_text: quote_identifier(&column.name),
|
insert_text: quote_identifier(&column.name),
|
||||||
@@ -193,9 +195,6 @@ AVAILABLE ANALYTICS SCHEMA\n",
|
|||||||
|
|
||||||
for table in &catalog.tables {
|
for table in &catalog.tables {
|
||||||
text.push_str(&format!("\nTABLE {}\n", quote_identifier(&table.name)));
|
text.push_str(&format!("\nTABLE {}\n", quote_identifier(&table.name)));
|
||||||
if !table.base_currency.is_empty() {
|
|
||||||
text.push_str(&format!(" Base currency: {}\n", table.base_currency));
|
|
||||||
}
|
|
||||||
text.push_str(" Columns:\n");
|
text.push_str(" Columns:\n");
|
||||||
for column in &table.columns {
|
for column in &table.columns {
|
||||||
text.push_str(&format!(
|
text.push_str(&format!(
|
||||||
@@ -209,6 +208,9 @@ AVAILABLE ANALYTICS SCHEMA\n",
|
|||||||
if !column.rounding.is_empty() {
|
if !column.rounding.is_empty() {
|
||||||
text.push_str(&format!(" [rounding: {}]", column.rounding));
|
text.push_str(&format!(" [rounding: {}]", column.rounding));
|
||||||
}
|
}
|
||||||
|
if !column.currency.is_empty() {
|
||||||
|
text.push_str(&format!(" [currency: {}]", column.currency));
|
||||||
|
}
|
||||||
text.push('\n');
|
text.push('\n');
|
||||||
}
|
}
|
||||||
if !table.links.is_empty() {
|
if !table.links.is_empty() {
|
||||||
|
|||||||
@@ -48,7 +48,6 @@ pub(crate) struct CatalogView {
|
|||||||
|
|
||||||
pub(crate) struct CatalogTableView {
|
pub(crate) struct CatalogTableView {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub base_currency: String,
|
|
||||||
pub starter_query: String,
|
pub starter_query: String,
|
||||||
pub columns: Vec<CatalogColumnView>,
|
pub columns: Vec<CatalogColumnView>,
|
||||||
pub links: Vec<CatalogLinkView>,
|
pub links: Vec<CatalogLinkView>,
|
||||||
|
|||||||
@@ -48,15 +48,6 @@
|
|||||||
hx-target="#builder" hx-swap="innerHTML" hx-vals='{"action": "refresh"}'>
|
hx-target="#builder" hx-swap="innerHTML" hx-vals='{"action": "refresh"}'>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
{% if page.draft.show_base_currency() %}
|
|
||||||
<label>Base currency
|
|
||||||
<input name="base_currency" value="{{ page.draft.base_currency }}" list="currency-codes"
|
|
||||||
maxlength="3" placeholder="EUR">
|
|
||||||
<small>Required while the table has a MONEY or ACCOUNTING column.</small>
|
|
||||||
</label>
|
|
||||||
{% else %}
|
|
||||||
<input type="hidden" name="base_currency" value="{{ page.draft.base_currency }}">
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@@ -100,6 +91,10 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if page.draft.show_rounding() %}
|
{% if page.draft.show_rounding() %}
|
||||||
|
<label>Currency
|
||||||
|
<input name="column_currency_input" value="{{ page.draft.column_currency_input }}" list="currency-codes"
|
||||||
|
maxlength="3" placeholder="EUR">
|
||||||
|
</label>
|
||||||
<label>Rounding
|
<label>Rounding
|
||||||
<select name="column_rounding_input">
|
<select name="column_rounding_input">
|
||||||
<option value="none" {% if page.draft.column_rounding_input != "half-up" %}selected{% endif %}>none</option>
|
<option value="none" {% if page.draft.column_rounding_input != "half-up" %}selected{% endif %}>none</option>
|
||||||
@@ -167,6 +162,7 @@
|
|||||||
<input type="hidden" name="column_indexed" value="{% if column.indexed %}yes{% else %}no{% endif %}">
|
<input type="hidden" name="column_indexed" value="{% if column.indexed %}yes{% else %}no{% endif %}">
|
||||||
<input type="hidden" name="column_quantity_ledger" value="{% if column.quantity_ledger %}yes{% else %}no{% endif %}">
|
<input type="hidden" name="column_quantity_ledger" value="{% if column.quantity_ledger %}yes{% else %}no{% endif %}">
|
||||||
<input type="hidden" name="column_rounding" value="{{ column.money_mode.label() }}">
|
<input type="hidden" name="column_rounding" value="{{ column.money_mode.label() }}">
|
||||||
|
<input type="hidden" name="column_currencies" value="{{ column.currency }}">
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
<details class="catalog-table">
|
<details class="catalog-table">
|
||||||
<summary>
|
<summary>
|
||||||
<code>{{ table.name }}</code>
|
<code>{{ table.name }}</code>
|
||||||
{%- if !table.base_currency.is_empty() %}<span class="currency">{{ table.base_currency }}</span>{% endif -%}
|
|
||||||
</summary>
|
</summary>
|
||||||
<button type="button" class="starter-query" data-sql="{{ table.starter_query }}"
|
<button type="button" class="starter-query" data-sql="{{ table.starter_query }}"
|
||||||
x-on:click="sql = $el.dataset.sql; $refs.sql.focus()">Use starter query</button>
|
x-on:click="sql = $el.dataset.sql; $refs.sql.focus()">Use starter query</button>
|
||||||
|
|||||||
Reference in New Issue
Block a user