mirror of
https://github.com/maybe-finance/maybe.git
synced 2025-08-07 14:35:23 +02:00
Feature: Add "amount type" configuration column for CSV imports (#1947)
* Rough draft * Schema conflict update * Implement signage * Update system tests * Lint fixes
This commit is contained in:
parent
8cf077f28d
commit
c88fe2e3b2
21 changed files with 366 additions and 83 deletions
|
@ -1,10 +1,10 @@
|
|||
<%# locals: (import:) %>
|
||||
|
||||
<%= styled_form_with model: @import, url: import_configuration_path(@import), scope: :import, method: :patch, class: "space-y-2" do |form| %>
|
||||
<%= styled_form_with model: @import, url: import_configuration_path(@import), scope: :import, method: :patch, class: "space-y-4" do |form| %>
|
||||
<%= form.select :entity_type_col_label, import.csv_headers, { include_blank: "Leave empty", label: "Entity Type" } %>
|
||||
<%= form.select :name_col_label, import.csv_headers, { include_blank: "Leave empty", label: "Name (optional)" } %>
|
||||
<%= form.select :amount_col_label, import.csv_headers, { include_blank: "Leave empty", label: "Balance" } %>
|
||||
<%= form.select :currency_col_label, import.csv_headers, { include_blank: "Leave empty", label: "Currency" } %>
|
||||
<%= form.select :name_col_label, import.csv_headers, { include_blank: "Leave empty", label: "Name" }, required: true %>
|
||||
<%= form.select :amount_col_label, import.csv_headers, { include_blank: "Leave empty", label: "Balance" }, required: true %>
|
||||
<%= form.select :currency_col_label, import.csv_headers, { include_blank: "Default", label: "Currency" } %>
|
||||
|
||||
<%= form.submit "Apply configuration", class: "w-full btn btn--primary", disabled: import.complete? %>
|
||||
<% end %>
|
||||
|
|
|
@ -5,18 +5,18 @@
|
|||
<p class="text-sm text-primary italic">We have pre-configured your Mint import for you. Please proceed to the next step.</p>
|
||||
</div>
|
||||
|
||||
<%= styled_form_with model: @import, url: import_configuration_path(@import), scope: :import, method: :patch, class: "space-y-2" do |form| %>
|
||||
<div class="flex items-center gap-2">
|
||||
<%= styled_form_with model: @import, url: import_configuration_path(@import), scope: :import, method: :patch, class: "space-y-4" do |form| %>
|
||||
<div class="flex items-center gap-4">
|
||||
<%= form.select :date_col_label, import.csv_headers, { include_blank: "Leave empty", label: "Date" }, required: true, disabled: import.complete? %>
|
||||
<%= form.select :date_format, Family::DATE_FORMATS, { label: t(".date_format_label")}, label: true, required: true, disabled: import.complete? %>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-2">
|
||||
<div class="flex items-center gap-4">
|
||||
<%= form.select :amount_col_label, import.csv_headers, { include_blank: "Leave empty", label: "Amount" }, required: true, disabled: import.complete? %>
|
||||
<%= form.select :signage_convention, [["Incomes are negative", "inflows_negative"], ["Incomes are positive", "inflows_positive"]], { label: true }, disabled: import.complete? %>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-2">
|
||||
<div class="flex items-center gap-4">
|
||||
<%= form.select :currency_col_label, import.csv_headers, { include_blank: "Leave empty", label: "Currency" }, disabled: import.complete? %>
|
||||
<%= form.select :number_format, Import::NUMBER_FORMATS.keys, { label: "Format", prompt: "Select format" }, required: true %>
|
||||
</div>
|
||||
|
|
|
@ -1,31 +1,31 @@
|
|||
<%# locals: (import:) %>
|
||||
|
||||
<%= styled_form_with model: @import, url: import_configuration_path(@import), scope: :import, method: :patch, class: "space-y-2" do |form| %>
|
||||
<%= styled_form_with model: @import, url: import_configuration_path(@import), scope: :import, method: :patch, class: "space-y-4" do |form| %>
|
||||
<div class="space-y-4">
|
||||
<div class="flex items-center gap-2">
|
||||
<%= form.select :date_col_label, import.csv_headers, { include_blank: "Leave empty", label: "Date" }, required: true %>
|
||||
<div class="flex items-center gap-4">
|
||||
<%= form.select :date_col_label, import.csv_headers, { include_blank: "Select column", label: "Date" }, required: true %>
|
||||
<%= form.select :date_format, Family::DATE_FORMATS, { label: t(".date_format_label")}, label: true, required: true %>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-2">
|
||||
<%= form.select :qty_col_label, import.csv_headers, { include_blank: "Leave empty", label: "Quantity" } %>
|
||||
<%= form.select :signage_convention, [["Buys are positive qty", "inflows_positive"], ["Buys are negative qty", "inflows_negative"]], label: true %>
|
||||
<div class="flex items-center gap-4">
|
||||
<%= form.select :qty_col_label, import.csv_headers, { include_blank: "Select column", label: "Quantity" }, required: true %>
|
||||
<%= form.select :signage_convention, [["Buys are positive qty", "inflows_positive"], ["Buys are negative qty", "inflows_negative"]], label: true, required: true %>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-2">
|
||||
<%= form.select :currency_col_label, import.csv_headers, { include_blank: "Leave empty", label: "Currency" } %>
|
||||
<div class="flex items-center gap-4">
|
||||
<%= form.select :currency_col_label, import.csv_headers, { include_blank: "Default", label: "Currency" } %>
|
||||
<%= form.select :number_format, Import::NUMBER_FORMATS.keys, { label: "Format", prompt: "Select format" }, required: true %>
|
||||
</div>
|
||||
|
||||
<%= form.select :ticker_col_label, import.csv_headers, { include_blank: "Leave empty", label: "Ticker" } %>
|
||||
<%= form.select :exchange_operating_mic_col_label, import.csv_headers, { include_blank: "Leave empty", label: "Exchange Operating MIC" } %>
|
||||
<%= form.select :price_col_label, import.csv_headers, { include_blank: "Leave empty", label: "Price" } %>
|
||||
<%= form.select :ticker_col_label, import.csv_headers, { include_blank: "Select column", label: "Ticker" }, required: true %>
|
||||
<%= form.select :exchange_operating_mic_col_label, import.csv_headers, { include_blank: "Leave empty", label: "Stock exchange code" } %>
|
||||
<%= form.select :price_col_label, import.csv_headers, { include_blank: "Select column", label: "Price" }, required: true %>
|
||||
|
||||
<% unless import.account.present? %>
|
||||
<%= form.select :account_col_label, import.csv_headers, { include_blank: "Leave empty", label: "Account (optional)" } %>
|
||||
<%= form.select :account_col_label, import.csv_headers, { include_blank: "Leave empty", label: "Account" } %>
|
||||
<% end %>
|
||||
|
||||
<%= form.select :name_col_label, import.csv_headers, { include_blank: "Leave empty", label: "Name (optional)" } %>
|
||||
<%= form.select :name_col_label, import.csv_headers, { include_blank: "Leave empty", label: "Name" } %>
|
||||
|
||||
<% unless Security.provider %>
|
||||
<div class="alert alert-warning">
|
||||
|
|
|
@ -1,29 +1,113 @@
|
|||
<%# locals: (import:) %>
|
||||
|
||||
<%= styled_form_with model: @import, url: import_configuration_path(@import), scope: :import, method: :patch, class: "space-y-2" do |form| %>
|
||||
<div class="flex items-center gap-2">
|
||||
<%= form.select :date_col_label, import.csv_headers, { include_blank: "Leave empty", label: "Date" }, required: true %>
|
||||
<%= form.select :date_format, Family::DATE_FORMATS, { label: t(".date_format_label")}, label: true, required: true %>
|
||||
<%= styled_form_with model: @import,
|
||||
url: import_configuration_path(@import),
|
||||
scope: :import,
|
||||
method: :patch,
|
||||
class: "space-y-4",
|
||||
data: {
|
||||
controller: "import",
|
||||
import_csv_value: import.csv_rows.to_json,
|
||||
import_amount_type_column_key_value: @import.entity_type_col_label
|
||||
} do |form| %>
|
||||
|
||||
<%# Date Configuration %>
|
||||
<div class="flex items-center gap-4">
|
||||
<%= form.select :date_col_label,
|
||||
import.csv_headers,
|
||||
{ label: "Date", prompt: "Select column" },
|
||||
required: true %>
|
||||
<%= form.select :date_format,
|
||||
Family::DATE_FORMATS,
|
||||
{ label: t(".date_format_label"), prompt: "Select format" },
|
||||
required: true %>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-2">
|
||||
<%= form.select :amount_col_label, import.csv_headers, { include_blank: "Leave empty", label: "Amount" }, required: true %>
|
||||
<%= form.select :signage_convention, [["Incomes are positive", "inflows_positive"], ["Incomes are negative", "inflows_negative"]], label: true %>
|
||||
<%# Amount Configuration %>
|
||||
<div class="flex items-center gap-4">
|
||||
<%= form.select :amount_col_label,
|
||||
import.csv_headers,
|
||||
{ label: "Amount", container_class: "w-2/5", prompt: "Select column" },
|
||||
required: true %>
|
||||
<%= form.select :currency_col_label,
|
||||
import.csv_headers,
|
||||
{ include_blank: "Default", label: "Currency", container_class: "w-1/5" } %>
|
||||
<%= form.select :number_format,
|
||||
Import::NUMBER_FORMATS.keys,
|
||||
{ label: "Format", prompt: "Select format", container_class: "w-2/5" },
|
||||
required: true %>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-2">
|
||||
<%= form.select :currency_col_label, import.csv_headers, { include_blank: "Leave empty", label: "Currency" } %>
|
||||
<%= form.select :number_format, Import::NUMBER_FORMATS.keys, { label: "Format", prompt: "Select format" }, required: true %>
|
||||
</div>
|
||||
<%# Amount Type Strategy %>
|
||||
<%= form.select :amount_type_strategy,
|
||||
Import::AMOUNT_TYPE_STRATEGIES.map { |strategy| [strategy.humanize, strategy] },
|
||||
{ label: "Amount type strategy", prompt: "Select strategy" },
|
||||
required: true,
|
||||
data: {
|
||||
action: "import#handleAmountTypeStrategyChange",
|
||||
import_target: "amountTypeStrategySelect"
|
||||
} %>
|
||||
|
||||
<% unless import.account.present? %>
|
||||
<%= form.select :account_col_label, import.csv_headers, { include_blank: "Leave empty", label: "Account (optional)" } %>
|
||||
<%# Signed Amount Configuration %>
|
||||
<%= tag.fieldset data: { import_target: "signedAmountFieldset" },
|
||||
class: @import.amount_type_strategy == "signed_amount" ? "block" : "hidden" do %>
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="text-sm shrink-0 text-secondary">↪</span>
|
||||
<%= form.select :signage_convention,
|
||||
[["Incomes are positive", "inflows_positive"], ["Incomes are negative", "inflows_negative"]],
|
||||
{ label: "Amount type", prompt: "Select convention" },
|
||||
required: @import.amount_type_strategy == "signed_amount" %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<%= form.select :name_col_label, import.csv_headers, { include_blank: "Leave empty", label: "Name (optional)" } %>
|
||||
<%= form.select :category_col_label, import.csv_headers, { include_blank: "Leave empty", label: "Category (optional)" } %>
|
||||
<%= form.select :tags_col_label, import.csv_headers, { include_blank: "Leave empty", label: "Tags (optional)" } %>
|
||||
<%= form.select :notes_col_label, import.csv_headers, { include_blank: "Leave empty", label: "Notes (optional)" } %>
|
||||
<%# Custom Column Configuration %>
|
||||
<%= tag.fieldset data: { import_target: "customColumnFieldset" },
|
||||
class: @import.amount_type_strategy == "custom_column" ? "block" : "hidden" do %>
|
||||
<div class="space-y-2">
|
||||
<div class="flex items-center gap-2 text-sm">
|
||||
<span class="shrink-0 text-secondary">↪</span>
|
||||
<span class="text-secondary">Set</span>
|
||||
<%= form.select :entity_type_col_label,
|
||||
import.csv_headers,
|
||||
{ prompt: "Select column", container_class: "w-48 px-3 py-1.5 border border-secondary rounded-md" },
|
||||
required: @import.amount_type_strategy == "custom_column",
|
||||
data: { action: "import#handleAmountTypeChange" } %>
|
||||
<span class="text-secondary">as amount type column</span>
|
||||
</div>
|
||||
|
||||
<%= form.submit "Apply configuration", class: "w-full btn btn--primary", disabled: import.complete? %>
|
||||
<div class="items-center gap-2 text-sm <%= @import.entity_type_col_label.nil? ? "hidden" : "flex" %>" data-import-target="amountTypeValue">
|
||||
<span class="shrink-0 text-secondary">↪</span>
|
||||
<span class="text-secondary">Set</span>
|
||||
<%= form.select :amount_type_inflow_value,
|
||||
@import.selectable_amount_type_values,
|
||||
{ prompt: "Select column", container_class: "w-48 px-3 py-1.5 border border-secondary rounded-md" },
|
||||
required: @import.amount_type_strategy == "custom_column" %>
|
||||
<span class="text-secondary">as "income" (inflow) value</span>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<%# Optional Fields %>
|
||||
<% unless import.account.present? %>
|
||||
<%= form.select :account_col_label,
|
||||
import.csv_headers,
|
||||
{ include_blank: "Leave empty", label: "Account" } %>
|
||||
<% end %>
|
||||
|
||||
<%= form.select :name_col_label,
|
||||
import.csv_headers,
|
||||
{ include_blank: "Leave empty", label: "Name" } %>
|
||||
<%= form.select :category_col_label,
|
||||
import.csv_headers,
|
||||
{ include_blank: "Leave empty", label: "Category" } %>
|
||||
<%= form.select :tags_col_label,
|
||||
import.csv_headers,
|
||||
{ include_blank: "Leave empty", label: "Tags" } %>
|
||||
<%= form.select :notes_col_label,
|
||||
import.csv_headers,
|
||||
{ include_blank: "Leave empty", label: "Notes" } %>
|
||||
|
||||
<%= form.submit "Apply configuration",
|
||||
class: "w-full btn btn--primary",
|
||||
disabled: import.complete? %>
|
||||
<% end %>
|
||||
|
|
|
@ -24,18 +24,15 @@
|
|||
</div>
|
||||
</div>
|
||||
<% else %>
|
||||
<div class="space-y-4">
|
||||
<div class="space-y-6">
|
||||
<div class="text-center space-y-2">
|
||||
<h1 class="text-3xl text-primary font-medium"><%= t(".title") %></h1>
|
||||
<p class="text-secondary text-sm"><%= t(".description") %></p>
|
||||
</div>
|
||||
|
||||
<div class="mx-auto max-w-lg space-y-3">
|
||||
<div class="mx-auto max-w-lg space-y-4">
|
||||
<%= render partial: permitted_import_configuration_path(@import), locals: { import: @import } %>
|
||||
<%= render "imports/table", headers: @import.csv_headers, rows: @import.csv_sample, caption: "Sample data from your uploaded CSV" %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mx-auto max-w-5xl my-12">
|
||||
<%= render "imports/table", headers: @import.csv_headers, rows: @import.csv_sample, caption: "Sample data from your uploaded CSV" %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue