mirror of
https://github.com/rickbarrette/redmine_qbo.git
synced 2026-04-02 08:21:57 -04:00
Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6434eea906 | |||
| 9b656534ae | |||
| 659a1fbcf0 | |||
| 4dc1f5d0bd | |||
| 02f34582f4 | |||
| 2f9ef6304f | |||
| 886d5f4ace | |||
| 1ade938eb3 | |||
| 3111f391f3 |
@@ -169,6 +169,7 @@ class Customer < ActiveRecord::Base
|
||||
|
||||
# Searchs the database for a customer by name or phone number with out special chars
|
||||
def self.search(search)
|
||||
search = sanitize_sql_like(search)
|
||||
customers = where("name LIKE ? OR phone_number LIKE ? OR mobile_phone_number LIKE ?", "%#{search}%", "%#{search}%", "%#{search}%")
|
||||
return customers.order(:name)
|
||||
end
|
||||
|
||||
2
init.rb
2
init.rb
@@ -14,7 +14,7 @@ Redmine::Plugin.register :redmine_qbo do
|
||||
name 'Redmine QBO plugin'
|
||||
author 'Rick Barrette'
|
||||
description 'A pluging for Redmine to connect with QuickBooks Online to create Time Activity Entries for billable hours logged when an Issue is closed'
|
||||
version '2026.2.8'
|
||||
version '2026.2.12'
|
||||
url 'https://github.com/rickbarrette/redmine_qbo'
|
||||
author_url 'https://barrettefabrication.com'
|
||||
settings default: {empty: true}, partial: 'qbo/settings'
|
||||
|
||||
@@ -25,7 +25,7 @@ module RedmineQbo
|
||||
|
||||
# Same as typing in the class
|
||||
base.class_eval do
|
||||
belongs_to :customer, primary_key: :id
|
||||
belongs_to :customer, class_name: 'Customer', foreign_key: :customer_id, optional: true
|
||||
belongs_to :customer_token, primary_key: :id
|
||||
belongs_to :estimate, primary_key: :id
|
||||
has_and_belongs_to_many :invoices
|
||||
@@ -43,14 +43,18 @@ module RedmineQbo
|
||||
|
||||
# Create billable time entries
|
||||
def bill_time
|
||||
logger.debug "QBO: Billing time for issue ##{id}"
|
||||
return false if assigned_to.nil?
|
||||
logger.debug "QBO: Billing time for issue ##{self.id}"
|
||||
logger.debug "Issue is closed? #{self.closed?}"
|
||||
|
||||
return false if self.assigned_to.nil?
|
||||
return false unless Qbo.first
|
||||
return false unless customer
|
||||
return false unless self.customer
|
||||
|
||||
Thread.new do
|
||||
spent_time = time_entries.where(billed: [false, nil])
|
||||
spent_time = self.time_entries.where(billed: [false, nil])
|
||||
spent_hours ||= spent_time.sum(:hours) || 0
|
||||
|
||||
logger.debug "Issue has spent hours: #{spent_hours}"
|
||||
|
||||
if spent_hours > 0 then
|
||||
|
||||
@@ -73,20 +77,23 @@ module RedmineQbo
|
||||
|
||||
# Now letes upload our totals for each activity as their own billable time entry
|
||||
h.each do |key, val|
|
||||
|
||||
logger.debug "Processing activity '#{key}' with #{val.to_i} hours for issue ##{self.id}"
|
||||
|
||||
# Convert float spent time to hours and minutes
|
||||
hours = val.to_i
|
||||
minutesDecimal = (( val - hours) * 60)
|
||||
minutes = minutesDecimal.to_i
|
||||
|
||||
logger.debug "Converted #{val.to_i} hours to #{hours} hours and #{minutes} minutes"
|
||||
|
||||
# Lets match the activity to an qbo item
|
||||
item = item_service.query("SELECT * FROM Item WHERE Name = '#{key}' ").first
|
||||
next if item.nil?
|
||||
|
||||
# Create the new billable time entry and upload it
|
||||
time_entry.description = "#{tracker} ##{id}: #{subject} #{"(Partial @ #{done_ratio}%)" if not closed?}"
|
||||
time_entry.employee_id = assigned_to.employee_id
|
||||
time_entry.customer_id = customer_id
|
||||
time_entry.description = "#{self.tracker} ##{self.id}: #{self.subject} #{"(Partial @ #{self.done_ratio}%)" unless self.closed?}"
|
||||
time_entry.employee_id = self.assigned_to.employee_id
|
||||
time_entry.customer_id = self.customer_id
|
||||
time_entry.billable_status = "Billable"
|
||||
time_entry.hours = hours
|
||||
time_entry.minutes = minutes
|
||||
|
||||
@@ -13,6 +13,20 @@ require_dependency 'issue_query'
|
||||
module RedmineQbo
|
||||
module Patches
|
||||
module QueryPatch
|
||||
|
||||
def base_scope
|
||||
scope = super
|
||||
|
||||
if filters['customer_name'].present?
|
||||
scope = scope.left_outer_joins(:customer)
|
||||
end
|
||||
|
||||
if has_column?(:customer) || filters['customer_name'].present?
|
||||
scope = scope.includes(:customer)
|
||||
end
|
||||
|
||||
scope
|
||||
end
|
||||
|
||||
# Add qbo options to the aviable columns
|
||||
def available_columns
|
||||
@@ -26,10 +40,27 @@ module RedmineQbo
|
||||
|
||||
# Add customers to filters
|
||||
def initialize_available_filters
|
||||
#add_available_filter "customer", type: :text
|
||||
#add_available_filter "customer_id", type: :list, name: l(:field_customer), :values => lambda {Customer.pluck(:name, :id).map {|name, id| [name, id.to_s]}}
|
||||
add_available_filter( 'customer_name', type: :text, name: l(:field_customer))
|
||||
super
|
||||
end
|
||||
|
||||
def sql_for_customer_name_field(field, operator, value)
|
||||
pattern = "%#{value.first}%"
|
||||
|
||||
sql = case operator
|
||||
when '~'
|
||||
"#{Customer.table_name}.name LIKE ?"
|
||||
when '!~'
|
||||
"#{Customer.table_name}.name NOT LIKE ?"
|
||||
else
|
||||
return nil
|
||||
end
|
||||
|
||||
Issue.joins(:customer).sanitize_sql_for_conditions([sql, pattern])
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
# Add module to Issue
|
||||
|
||||
Reference in New Issue
Block a user