Updated views for items and accounts

This commit is contained in:
2026-03-17 19:18:03 -04:00
parent 2703d6cc3e
commit 6bf5575f9c
9 changed files with 216 additions and 171 deletions

View File

@@ -19,4 +19,9 @@ class AccountsController < ApplicationController
account.update(default: true)
redirect_to accounts_path, notice: "Default account updated."
end
def sync
Account.sync
redirect_to :home, flash: { notice: I18n.t(:label_syncing) }
end
end

View File

@@ -28,6 +28,10 @@ class Account < QboBaseModel
return r
end
def to_s
name
end
private
def clear_other_defaults

View File

@@ -1,39 +1,37 @@
<h1>Accounts</h1>
<h2><%= l(:label_accounts) %></h2>
<%= form_with url: set_default_accounts_path, method: :patch, local: true do %>
<table style="width:100%; border-collapse: collapse; margin-bottom: 1em;">
<thead style="background-color: #f2f2f2;">
<tr>
<th style="padding: 8px; border: 1px solid #ddd;">Default</th>
<th style="padding: 8px; border: 1px solid #ddd;">Name</th>
<th style="padding: 8px; border: 1px solid #ddd;">Description</th>
<th style="padding: 8px; border: 1px solid #ddd;">Classification</th>
<th style="padding: 8px; border: 1px solid #ddd;">Active</th>
</tr>
</thead>
<tbody>
<% @accounts.each_with_index do |account, index| %>
<tr style="background-color: <%= index.even? ? '#ffffff' : '#f9f9f9' %>;">
<td style="text-align: center; border: 1px solid #ddd; padding: 8px;">
<%= radio_button_tag "default_account_id", account.id, account.default %>
</td>
<td style="border: 1px solid #ddd; padding: 8px;"><%= account.name %></td>
<td style="border: 1px solid #ddd; padding: 8px;"><%= account.description %></td>
<td style="border: 1px solid #ddd; padding: 8px;"><%= account.classification %></td>
<td style="text-align: center; border: 1px solid #ddd; padding: 8px;">
<%= account.active ? "Yes" : "No" %>
</td>
<%= form_tag set_default_accounts_path, method: :patch do %>
<div class="autoscroll">
<table class="list accounts">
<thead>
<tr>
<th style="width:50px;"><%= l(:label_default) %></th>
<th><%= l(:field_name) %></th>
<th><%= l(:field_description) %></th>
<th><%= l(:field_classification) %></th>
<th class="center"><%= l(:field_active) %></th>
</tr>
<% end %>
</tbody>
</thead>
<tfoot>
<tr>
<td colspan="5" style="padding: 8px; text-align: right;">
<%= submit_tag "Save Default Account", style: "padding: 6px 12px; font-weight: bold;" %>
</td>
</tr>
</tfoot>
</table>
<tbody>
<% @accounts.each do |account| %>
<tr class="<%= cycle("odd", "even") %>">
<td class="center">
<%= radio_button_tag "default_account_id", account.id, account.default %>
</td>
<td class="name"><strong><%= account.name %></strong></td>
<td class="description"><%= truncate(account.description, length: 80) %></td>
<td class="classification"><%= account.classification %></td>
<td class="active center">
<%= checked_image account.active %>
</td>
</tr>
<% end %>
</tbody>
</table>
</div>
<p class="buttons">
<%= submit_tag l(:button_save), class: 'button-small' %>
</p>
<% end %>

View File

@@ -1,76 +1,47 @@
<%= form_with model: @item, local: true do |f| %>
<%= labelled_form_for @item do |f| %>
<%= error_messages_for 'item' %>
<% if @item.errors.any? %>
<div id="errorExplanation" style="border: 1px solid #f00; padding: 10px; background-color: #fee; margin-bottom: 1em;">
<h2 style="color: #900;"><%= pluralize(@item.errors.count, "error") %> prohibited this item from being saved:</h2>
<ul>
<% @item.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="box tabular">
<p>
<%= f.text_field :name, required: true, size: 60 %>
</p>
<table style="width: 100%; border-collapse: collapse;">
<tbody>
<tr>
<td style="padding: 8px; vertical-align: top;"><%= f.label :name %></td>
<td style="padding: 8px;"><%= f.text_field :name, required: true, style: "width: 100%;" %></td>
</tr>
<p>
<%= f.text_field :sku, size: 30 %>
</p>
<tr>
<td style="padding: 8px; vertical-align: top;"><%= f.label :sku %></td>
<td style="padding: 8px;"><%= f.text_field :sku, style: "width: 100%;" %></td>
</tr>
<p>
<%= f.text_area :description, rows: 4, class: 'wiki-edit' %>
</p>
<tr>
<td style="padding: 8px; vertical-align: top;"><%= f.label :description %></td>
<td style="padding: 8px;"><%= f.text_area :description, rows: 3, style: "width: 100%;" %></td>
</tr>
<p>
<%= f.number_field :unit_price, step: 0.01, size: 10 %>
</p>
<tr>
<td style="padding: 8px; vertical-align: top;"><%= f.label :unit_price %></td>
<td style="padding: 8px;"><%= f.number_field :unit_price, step: 0.01, style: "width: 100%;" %></td>
</tr>
<p>
<%= f.check_box :taxable %>
</p>
<tr>
<td style="padding: 8px; vertical-align: middle;"><%= f.label :taxable %></td>
<td style="padding: 8px; vertical-align: middle;">
<%= f.check_box :taxable %>
</td>
</tr>
<p>
<%= f.label :account_id, l(:label_account) %>
<%= f.collection_select :account_id,
Account.where(classification: 'Revenue').order(:name),
:id,
:name,
{ selected: @item.account_id || Account.get_default&.id, include_blank: true } %>
</p>
<tr>
<td style="padding: 8px; vertical-align: top;"><%= f.label :account %></td>
<td style="padding: 8px;">
<%= f.collection_select :account_id,
Account.where(classification: 'Revenue').order(:name),
:id,
:name,
{ selected: @item.account_id || Account.get_default&.id },
{ include_blank: true, style: "width: 100%;" } %>
</td>
</tr>
<p>
<%= f.select :type,
Quickbooks::Model::Item::ITEM_TYPES.map { |t| [t, t] },
{ selected: @item.type || Quickbooks::Model::Item::NON_INVENTORY_TYPE } %>
</p>
<tr>
<td style="padding: 8px; vertical-align: top;"><%= f.label :type %></td>
<td style="padding: 8px;">
<%= f.select :type,
Quickbooks::Model::Item::ITEM_TYPES.map { |t| [t, t] },
{ selected: @item.type || Quickbooks::Model::Item::NON_INVENTORY_TYPE },
{ style: "width: 100%;" } %>
</td>
</tr>
<tr>
<td style="padding: 8px; vertical-align: middle;"><%= f.label :active %></td>
<td style="padding: 8px; vertical-align: middle;"><%= f.check_box :active %></td>
</tr>
</tbody>
</table>
<p style="text-align: right; margin-top: 1em;">
<%= f.submit "Save Item", style: "padding: 6px 12px; font-weight: bold;" %>
</p>
<p>
<%= f.check_box :active %>
</p>
</div>
<%= submit_tag l(:button_save) %>
<%= link_to l(:button_cancel), items_path if controller.action_name == 'edit' %>
<% end %>

View File

@@ -1,37 +1,48 @@
<h2>Items</h2>
<div class="contextual">
<%= link_to "New Item", new_item_path, class: "icon icon-add" %>
<%= link_to l(:label_item_new), new_item_path, class: 'icon icon-add' %>
</div>
<table class="list items">
<thead>
<tr>
<th>Name</th>
<th>SKU</th>
<th>Description</th>
<th>Price</th>
<th>Active</th>
<th></th>
</tr>
</thead>
<h2><%= l(:label_items) %></h2>
<tbody>
<% @items.each do |item| %>
<tr>
<td><%= link_to item.name, item_path(item) %></td>
<td><%= item.sku %></td>
<td><%= item.description %></td>
<td><%= number_to_currency(item.unit_price) %></td>
<td><%= item.active ? "Yes" : "No" %></td>
<td>
<%= link_to "Edit", edit_item_path(item), class: "icon icon-edit" %>
<%= link_to "Delete", item_path(item),
method: :delete,
data: { confirm: "Are you sure?" },
class: "icon icon-del" %>
</td>
</tr>
<% end %>
</tbody>
</table>
<% if @items.any? %>
<div class="autoscroll">
<table class="list items">
<thead>
<tr>
<th><%= l(:field_name) %></th>
<th><%= l(:field_sku) %></th>
<th><%= l(:field_description) %></th>
<th><%= l(:field_unit_price) %></th>
<th class="center"><%= l(:field_taxable) %></th>
<th class="center"><%= l(:field_active) %></th>
<th></th>
</tr>
</thead>
<tbody>
<% @items.each do |item| %>
<tr class="<%= cycle("odd", "even") %>">
<td class="name"><%= link_to item.name, item_path(item) %></td>
<td class="sku"><%= item.sku %></td>
<td class="description"><%= truncate(item.description, length: 60) %></td>
<td class="unit_price"><%= number_to_currency(item.unit_price) %></td>
<td class="taxable center">
<%= item.taxable ? content_tag(:span, '', class: 'icon icon-ok') : "" %>
</td>
<td class="active center">
<%= checked_image item.active %>
</td>
<td class="buttons">
<%= link_to l(:button_edit), edit_item_path(item), class: 'icon icon-edit' %>
<%= link_to l(:button_delete), item_path(item),
method: :delete,
data: { confirm: l(:text_are_you_sure) },
class: 'icon icon-del' %>
</td>
</tr>
<% end %>
</tbody>
</table>
</div>
<% else %>
<p class="nodata"><%= l(:label_no_data) %></p>
<% end %>

View File

@@ -1,35 +1,44 @@
<h2 style="margin-bottom: 1em; border-bottom: 2px solid #ccc; padding-bottom: 4px;"><%= @item.name %></h2>
<div class="contextual">
<%= link_to l(:button_edit), edit_item_path(@item), class: 'icon icon-edit' %>
<%= link_to l(:button_back), items_path, class: 'icon icon-list' %>
</div>
<table style="width: 100%; border-collapse: collapse; margin-bottom: 1.5em;">
<tbody>
<tr style="background-color: #f9f9f9;">
<td style="padding: 8px; font-weight: bold; width: 150px;">SKU:</td>
<td style="padding: 8px;"><%= @item.sku.presence || "-" %></td>
</tr>
<tr>
<td style="padding: 8px; font-weight: bold;">Description:</td>
<td style="padding: 8px;"><%= @item.description.presence || "-" %></td>
</tr>
<tr style="background-color: #f9f9f9;">
<td style="padding: 8px; font-weight: bold;">Unit Price:</td>
<td style="padding: 8px;"><%= number_to_currency(@item.unit_price) %></td>
</tr>
<tr>
<td style="padding: 8px; font-weight: bold;">Type:</td>
<td style="padding: 8px;"><%= @item.type.presence || "-" %></td>
</tr>
<tr style="background-color: #f9f9f9;">
<td style="padding: 8px; font-weight: bold;">Account:</td>
<td style="padding: 8px;"><%= @item.account&.name || "-" %></td>
</tr>
<tr>
<td style="padding: 8px; font-weight: bold;">Active:</td>
<td style="padding: 8px;"><%= @item.active ? "Yes" : "No" %></td>
</tr>
</tbody>
</table>
<h2><%= t(:item) %># <%= @item.id %> <%= @item.name %></h2>
<div style="margin-top: 1em;">
<%= link_to "Edit", edit_item_path(@item), class: "btn btn-primary", style: "margin-right: 8px;" %>
<%= link_to "Back", items_path, class: "btn btn-secondary" %>
<div class="issue details"> <div class="attributes">
<div class="splitcontent">
<div class="splitcontentleft">
<p><strong>SKU:</strong> <%= @item.sku.presence || "-" %></p>
<p><strong>Type:</strong> <%= @item.type.presence || "-" %></p>
<p><strong>Unit Price:</strong> <%= number_to_currency(@item.unit_price) %></p>
</div>
<div class="splitcontentleft">
<p><strong>Account:</strong> <%= @item.account&.name || "-" %></p>
<p>
<strong>Taxable:</strong>
<% if @item.taxable %>
<span class="icon icon-ok" style="color: green;">Yes</span>
<% else %>
<span class="icon icon-not-ok" style="color: #999;">No</span>
<% end %>
</p>
<p>
<strong>Active:</strong>
<% if @item.active %>
<span class="icon icon-ok" style="color: green;">Yes</span>
<% else %>
<span class="icon icon-not-ok" style="color: #999;">No</span>
<% end %>
</p>
</div>
</div>
<hr />
<p><strong>Description:</strong></p>
<div class="wiki" style="padding-left: 20px;">
<%= @item.description.presence || "<em>No description provided</em>".html_safe %>
</div>
</div>
</div>

View File

@@ -1,6 +1,39 @@
<div>
<b><%=t(:label_item_count)%></b> <%= Item.count %> @ <%= Item.last_sync %>
<br/>
<%=t(:label_last_sync)%> </b> <%= Qbo.last_sync if Qbo.exists? %>
<div class="box tabular">
<p>
<label><strong><%= t(:label_item_count) %></strong></label>
<%= Item.count %>
<em style="color: #777; font-size: 0.9em; margin-left: 8px;">
(@ <%= Item.last_sync %>)
</em>
</p>
<p>
<label><strong><%= t(:label_account_count) %></strong></label>
<%= Account.count %>
<em style="color: #777; font-size: 0.9em; margin-left: 8px;">
(@ <%= Account.last_sync %>)
</em>
</p>
<p>
<label><strong><%= t(:label_last_sync) %> (QBO)</strong></label>
<%= Qbo.exists? ? Qbo.last_sync : 'Never synced' %>
</p>
<p>
<label><strong><%= t(:label_default_account) %></strong></label>
<%= Account.get_default %>
</p>
</div>
<%= link_to t(:label_sync_now), sync_items_path %>
<fieldset class="box">
<legend>Management & Synchronization</legend>
<div style="margin-bottom: 15px;">
<%= link_to t(:label_sync_now_items), sync_items_path, class: 'button icon icon-reload' %>
<%= link_to t(:label_sync_now_accounts), sync_accounts_path, class: 'button icon icon-reload' %>
</div>
<div>
<%= link_to t(:label_items), items_path, class: 'icon icon-list' %>
<span style="margin: 0 10px; color: #ccc;">|</span>
<%= link_to t(:label_accounts), accounts_path, class: 'icon icon-list' %>
</div>
</fieldset>