Compare commits

..
3 Commits
3 changed files with 45 additions and 5 deletions
+35 -4
View File
@@ -61,12 +61,43 @@ class CustomersController < ApplicationController
# Used for autocomplete form # Used for autocomplete form
def autocomplete def autocomplete
term = ActiveRecord::Base.sanitize_sql_like(params[:q].to_s) # Support both existing 'q' param and new 'name'/'phone' params
name_query = (params[:name] || params[:q] || params[:term]).to_s.strip
phone_query = params[:phone].to_s.gsub(/\D/, '')
items = Customer.where("name LIKE :t OR phone_number LIKE :t OR mobile_phone_number LIKE :t", t: "%#{term}%") sql_matches = []
.order(:name)
.limit(20)
# 1. Check for phone number matches via SQL
if phone_query.present?
sql_matches += Customer.where("phone_number LIKE :p OR mobile_phone_number LIKE :p", p: "%#{phone_query}%")
end
# 2. Check for exact or partial name matches via SQL
if name_query.present?
safe_name = ActiveRecord::Base.sanitize_sql_like(name_query)
sql_matches += Customer.where("name LIKE :t", t: "%#{safe_name}%")
end
sql_matches = sql_matches.uniq
# 3. Handle spelling errors using built-in string distance
fuzzy_matches = []
if name_query.present?
require 'did_you_mean/jaro_winkler'
# Only scan records we haven't already matched
unmatched = Customer.all - sql_matches
fuzzy_matches = unmatched.select do |c|
# 0.6 is the threshold. 1.0 is an exact match.
DidYouMean::JaroWinkler.distance(c.name.to_s.downcase, name_query.downcase) > 0.6
end
end
# Combine results and limit to top 20
items = (sql_matches + fuzzy_matches).first(20)
# Return JSON formatted for both existing usage and new jQuery UI requirements
render json: items.map { |i| render json: items.map { |i|
{ id: i.id, name: i.name, phone_number: i.phone_number, mobile_phone_number: i.mobile_phone_number } { id: i.id, name: i.name, phone_number: i.phone_number, mobile_phone_number: i.mobile_phone_number }
} }
+1 -1
View File
@@ -14,7 +14,7 @@ Redmine::Plugin.register :redmine_qbo do
name 'Redmine QBO plugin' name 'Redmine QBO plugin'
author 'Rick Barrette' 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' 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.8.2' version '2026.8.3'
url 'https://github.com/rickbarrette/redmine_qbo' url 'https://github.com/rickbarrette/redmine_qbo'
author_url 'https://barrettefabrication.com' author_url 'https://barrettefabrication.com'
settings default: {empty: true}, partial: 'qbo/settings' settings default: {empty: true}, partial: 'qbo/settings'
+9
View File
@@ -29,6 +29,15 @@ module RedmineQbo
RedmineQbo::Hooks::IssuesHookListener RedmineQbo::Hooks::IssuesHookListener
RedmineQbo::Hooks::UsersShowHookListener RedmineQbo::Hooks::UsersShowHookListener
RedmineQbo::Hooks::ViewHookListener RedmineQbo::Hooks::ViewHookListener
# If the SubtaskFieldCopier plugin is installed, register our fields
if defined?(SubtaskFieldCopier)
SubtaskFieldCopier.registered_fields << :customer
SubtaskFieldCopier.registered_fields << :estimate
# Ensure there are no duplicates in case of hot-reloads in development mode
SubtaskFieldCopier.registered_fields.uniq!
end
end end
def self.settings def self.settings