Compare commits

...
6 Commits
8 changed files with 110 additions and 56 deletions

No files matched your search

+8 -5
View File
@@ -45,11 +45,14 @@
</template> </template>
<p> <p>
<button type="button"
class="icon icon-add" <% if User.current.allowed_to?(:add_line_items, nil, global: true) %>
data-nested-form-add> <button type="button"
<%= l(:button_add) %> class="icon icon-add"
</button> data-nested-form-add>
<%= l(:button_add) %>
</button>
<% end %>
</p> </p>
<% end %> <% end %>
+45 -27
View File
@@ -1,39 +1,57 @@
<% if @issue.line_items.any? %> <% if @issue.line_items.any? || @issue.descendant_line_items_total > 0%>
<hr/> <hr/>
<div> <div>
<p><strong><%= t :label_line_items %></strong></p> <p><strong><%= t :label_line_items %></strong></p>
<table class="list line-items-table"> <% total = 0 %>
<thead>
<tr>
<th style="width:70%;"><%= t :label_description %></th>
<th style="width:10%;"><%= t :label_qty %></th>
<th style="width:10%;"><%= t :label_price %></th>
<th style="width:10%;"><%= t :label_total %></th>
</tr>
</thead>
<tbody> <% if @issue.line_items.any?%>
<% total = 0 %>
<% @issue.line_items.each do |item| %>
<% line_total = item.quantity.to_f * item.unit_price.to_f %>
<% total += line_total %>
<table class="list line-items-table">
<thead>
<tr> <tr>
<td><%= h item.description %></td> <th style="width:70%;"><%= t :label_description %></th>
<td><%= item.quantity %></td> <th style="width:10%;"><%= t :label_qty %></th>
<td><%= number_to_currency(item.unit_price) %></td> <th style="width:10%;"><%= t :label_price %></th>
<td><%= number_to_currency(line_total) %></td> <th style="width:10%;"><%= t :label_total %></th>
</tr>
</thead>
<tbody>
<% @issue.line_items.each do |item| %>
<% line_total = item.quantity.to_f * item.unit_price.to_f %>
<% total += line_total %>
<tr>
<td><%= h item.description %></td>
<td><%= item.quantity %></td>
<td><%= number_to_currency(item.unit_price) %></td>
<td><%= number_to_currency(line_total) %></td>
</tr>
<% end %>
</tbody>
<% end %>
<tfoot>
<% if @issue.line_items.any?%>
<tr>
<td colspan="3" style="text-align:right;"><strong><%= t :label_total %></strong></td>
<td>
<strong><%= number_to_currency(total) %></strong>
</td>
</tr>
<% end %>
<% if @issue.descendant_line_items_total > 0 %>
<tr>
<td colspan="3" style="text-align:right;"><strong><%= t :label_running_total %></strong></td>
<td>
<strong>(<%= number_to_currency(@issue.descendant_line_items_total + total) %>)</strong>
</td>
</tr> </tr>
<% end %> <% end %>
</tbody>
<tfoot>
<tr>
<td colspan="3" style="text-align:right;"><strong><%= t :label_total %></strong></td>
<td><strong><%= number_to_currency(total) %></strong></td>
</tr>
</tfoot> </tfoot>
</table> </table>
</div> </div>
@@ -35,13 +35,15 @@
0.00 0.00
</td> </td>
<% unless readonly %> <% if User.current.allowed_to?(:delete_line_items, nil, global: true) %>
<td class="actions"> <% unless readonly %>
<button type="button" <td class="actions">
class="icon-only icon-del" <button type="button"
title="<%= l(:label_remove) %>" class="icon-only icon-del"
data-nested-form-remove> title="<%= l(:label_remove) %>"
</button> data-nested-form-remove>
</td> </button>
</td>
<% end %>
<% end %> <% end %>
</tr> </tr>
+1
View File
@@ -33,6 +33,7 @@ en:
label_no: "No" label_no: "No"
label_qty: "Quantity" label_qty: "Quantity"
label_remove: "Remove" label_remove: "Remove"
label_running_total: "Running Total"
label_sync_now_accounts: "Sync Accounts" label_sync_now_accounts: "Sync Accounts"
label_sync_now_items: "Sync Items" label_sync_now_items: "Sync Items"
label_type: "Type" label_type: "Type"
+6 -8
View File
@@ -14,7 +14,7 @@ Redmine::Plugin.register :redmine_qbo_lineitems do
name 'Redmine QBO Line Items plugin' name 'Redmine QBO Line Items plugin'
author 'Rick Barrette' author 'Rick Barrette'
description 'A plugin for Redmine to extend the capabilitys of the Redmine QuickBooks Online plugin to attach billable line items to an isuue' description 'A plugin for Redmine to extend the capabilitys of the Redmine QuickBooks Online plugin to attach billable line items to an isuue'
version '2026.4.0' version '2026.9.0'
url 'https://github.com/rickbarrette/redmine_qbo_lineitems' url 'https://github.com/rickbarrette/redmine_qbo_lineitems'
author_url 'https://barrettefabrication.com' author_url 'https://barrettefabrication.com'
requires_redmine version_or_higher: '6.1.0' requires_redmine version_or_higher: '6.1.0'
@@ -29,14 +29,12 @@ Redmine::Plugin.register :redmine_qbo_lineitems do
# Add safe attributes for core models # Add safe attributes for core models
Issue.safe_attributes :line_items_attributes Issue.safe_attributes :line_items_attributes
end
# Administration menu extension # Global Permissions
Redmine::MenuManager.map :admin_menu do |menu| permission :view_line_items, { line_items: [:index, :show] }, global: true
menu.push :redmine_qbo_lineitems, { controller: 'items', action: 'index' }, permission :add_line_items, { line_items: [:new, :create] }, global: true
icon: 'list', permission :edit_line_items, { line_items: [:edit, :update] }, global: true
caption: :label_items, permission :delete_line_items, { line_items: [:destroy] }, global: true
html: { class: 'icon icon-list' }
end end
RedmineQboLineItems.setup RedmineQboLineItems.setup
+8 -8
View File
@@ -24,18 +24,18 @@ module LineItems
]) ])
end end
# Add the line items form to the issue edit page
def view_issues_edit_notes_bottom(context = {}) def view_issues_edit_notes_bottom(context = {})
return if context[:issue].closed? return if context[:issue].closed?
context[:controller].send(:render_to_string, { return unless User.current.allowed_to?(:edit_line_items, nil, global: true)
partial: 'line_items/issue_form', context[:controller].send(:render_to_string, { partial: 'line_items/issue_form', locals: { f: context[:form] } })
locals: {
f: context[:form]
}
}
)
end end
render_on :view_issues_show_description_bottom , partial: 'line_items/issue_line_items' # Add the line items to the issue view page
def view_issues_show_description_bottom (context = {})
return unless User.current.allowed_to?(:view_line_items, nil, global: true)
context[:controller].send(:render_to_string, { partial: 'line_items/issue_line_items', locals: { issue: context[:issue] } })
end
end end
end end
+24
View File
@@ -16,6 +16,30 @@ module LineItems
has_many :line_items, dependent: :destroy has_many :line_items, dependent: :destroy
accepts_nested_attributes_for :line_items, allow_destroy: true, reject_if: proc { |attrs| attrs['description'].blank? } accepts_nested_attributes_for :line_items, allow_destroy: true, reject_if: proc { |attrs| attrs['description'].blank? }
# Returns line items for immediate children
def children_line_items
LineItem.where(issue_id: self.children.pluck(:id))
end
# Calculates the total value of all child line items
def children_line_items_total
children_line_items.sum(:line_total)
end
# Returns line items for the entire tree below this issue
def descendant_line_items
LineItem.where(issue_id: self.descendants.pluck(:id))
end
# Calculates the total value of entire tree below this issue
def descendant_line_items_total
descendant_line_items.sum(:line_total)
end
def line_items_total
line_items.sum(:line_total)
end
def line_items_attributes=(attrs) def line_items_attributes=(attrs)
attrs = attrs.stringify_keys attrs = attrs.stringify_keys
+8
View File
@@ -12,10 +12,18 @@ module RedmineQboLineItems
def self.setup def self.setup
unless Issue.ancestors.include?(LineItems::Patches::IssuePatch) unless Issue.ancestors.include?(LineItems::Patches::IssuePatch)
# Patches
Issue.prepend LineItems::Patches::IssuePatch Issue.prepend LineItems::Patches::IssuePatch
# Hooks
LineItems::Hooks::IssuesSaveHookListener LineItems::Hooks::IssuesSaveHookListener
LineItems::Hooks::QboHookListener LineItems::Hooks::QboHookListener
LineItems::Hooks::ViewHookListener LineItems::Hooks::ViewHookListener
# Administration menu extension
Redmine::MenuManager.map :admin_menu do |menu|
menu.push :redmine_qbo_lineitems, { controller: 'items', action: 'index' }, icon: 'list', caption: :label_items, html: { class: 'icon icon-list' }
end
end end
end end
end end