155 Commits
0.4.1 ... 0.4.2

Author SHA1 Message Date
32b750b545 Version 0.4.2 2017-03-22 22:38:42 -04:00
5fd3141746 Merge pull request #7 from rickbarrette/dev
Removed un-needed js files
2017-03-22 22:26:04 -04:00
2c38361234 Removed un-needed js files 2017-03-22 22:20:12 -04:00
81b7b1492d Merge pull request #6 from rickbarrette/filter_vehicles_by_customer
Filter vehicles by customer
2017-03-22 22:07:22 -04:00
57ef1ac5a1 Fixed Typo 2017-03-22 22:05:33 -04:00
6597c5a13c Update application.js 2017-03-22 22:03:25 -04:00
8af97072fb Fixed filter_vehicles_by_customer method 2017-03-22 21:55:07 -04:00
48b6df0cef Update application.js 2017-03-22 21:34:04 -04:00
853b7ad804 Rename filter_vehicles_by_customerjs.erb to filter_vehicles_by_customer.js.erb 2017-03-22 21:27:15 -04:00
6a74baff5e Update application.js 2017-03-22 18:56:44 -04:00
8b21b0ff75 Update application.js 2017-03-22 18:54:47 -04:00
d22a6303cd Update application.js 2017-03-22 18:53:47 -04:00
807d6643f4 Update application.js 2017-03-22 18:52:38 -04:00
c725c2774c Update application.js 2017-03-22 18:50:21 -04:00
ae0abae333 Update application.js 2017-03-22 18:48:52 -04:00
fed2282212 Added debug 2017-03-22 18:37:06 -04:00
545960e676 Call autocomplete instead 2017-03-22 18:28:53 -04:00
66781f0625 Update application.js 2017-03-22 13:12:29 -04:00
504b9b93e4 Removed { 2017-03-22 13:11:19 -04:00
b71bba473c Provide empty list 2017-03-22 13:09:15 -04:00
aef3c453c4 Do not list all vehicles without customer 2017-03-22 13:04:50 -04:00
6de3ed94dc Update and rename app/views/filter_vehicles_by_customerjs.erb to app/views/customers/filter_vehicles_by_customerjs.erb
Also changed ID to select#issue_vehicles_id
2017-03-22 12:59:36 -04:00
daada08ea7 Changed select to input 2017-03-22 12:48:43 -04:00
fa37c98500 Removed ID 2017-03-22 12:47:08 -04:00
0ee59704b3 Fixed Javascript includes to += 2017-03-22 12:43:25 -04:00
a22cbb9520 Added Javascript include for application.js 2017-03-22 11:09:19 -04:00
c0d3f64d82 Create application.js 2017-03-22 11:08:14 -04:00
66d2bf4aa4 Create filter_vehicles_by_customerjs.erb 2017-03-22 11:04:48 -04:00
2b90c953ba Added filter_vehicles_by_customer method 2017-03-22 10:29:04 -04:00
0d5e5d679e Added route for filter_vehicles_by_customer 2017-03-22 10:24:16 -04:00
4da891cc07 Merge branch 'master' of git://github.com/sempervictus/redmine_qbo into sempervictus-master 2017-02-22 11:10:46 -05:00
d3475a9b53 Delete vehicles.js 2017-02-14 14:42:13 -05:00
eb583f78ec Delete update_vehicles.js.coffee 2017-02-14 14:41:55 -05:00
47bebf0a1a Delete application.js 2017-02-14 14:41:34 -05:00
f9bd149f21 Commented out un-needed JS 2017-02-14 14:39:58 -05:00
5371b0f193 Update application.js 2017-01-29 22:40:48 -05:00
95497e5514 Update issues_form_hook_listener.rb 2017-01-29 22:40:02 -05:00
1a74abe76c Update issues_form_hook_listener.rb 2017-01-29 22:38:30 -05:00
7f11d3cdc4 Update issues_form_hook_listener.rb 2017-01-29 22:36:32 -05:00
da01d79325 Update customers_controller.rb 2017-01-29 22:29:15 -05:00
82807cfede Update customers_controller.rb 2017-01-29 22:26:53 -05:00
a268d10819 Update customers_controller.rb 2017-01-29 22:25:27 -05:00
ba4bdd9ecb Update routes.rb 2017-01-29 22:19:12 -05:00
0a72e05e03 Update issues_form_hook_listener.rb 2017-01-29 22:05:29 -05:00
8d143ff06d Update customers_controller.rb 2017-01-29 22:00:19 -05:00
3ddb585a58 Update customers_controller.rb 2017-01-29 21:58:49 -05:00
1606ceb743 Update issues_form_hook_listener.rb 2017-01-29 21:49:57 -05:00
97578f8380 Update issues_form_hook_listener.rb 2017-01-29 21:47:09 -05:00
32beae70ef Update issues_form_hook_listener.rb 2017-01-29 21:45:13 -05:00
13fbc9e14f Update issues_form_hook_listener.rb 2017-01-29 21:44:00 -05:00
c57a45c85e Update issues_form_hook_listener.rb 2017-01-29 21:43:25 -05:00
3711a9ca43 Update issues_form_hook_listener.rb 2017-01-29 21:38:18 -05:00
d0c1693f38 Create autocomplete-rails.js 2017-01-29 21:37:27 -05:00
36534ee129 Update issues_form_hook_listener.rb 2017-01-29 21:34:28 -05:00
188c460054 Update issues_form_hook_listener.rb 2017-01-29 21:15:29 -05:00
d9e3cb096b Update application.js 2017-01-29 21:10:41 -05:00
b57b19493f Add files via upload 2017-01-29 21:08:29 -05:00
8c569db541 Update issues_form_hook_listener.rb 2017-01-29 20:56:30 -05:00
997257f42d Update issues_form_hook_listener.rb 2017-01-29 20:54:52 -05:00
f9f1af17bc Update issues_form_hook_listener.rb 2017-01-29 20:53:09 -05:00
f1f44d0048 Update issues_form_hook_listener.rb 2017-01-29 20:46:39 -05:00
7e8511090d Update issues_form_hook_listener.rb 2017-01-29 20:42:18 -05:00
4ca6a3138b Update issues_form_hook_listener.rb 2017-01-29 20:41:38 -05:00
21e1132e0e Update issues_form_hook_listener.rb 2017-01-29 20:36:19 -05:00
dc15424014 Update issues_form_hook_listener.rb 2017-01-29 20:30:34 -05:00
f90cdcd86b Update customers_controller.rb 2017-01-29 20:28:17 -05:00
5e53c18098 Update issues_form_hook_listener.rb 2017-01-29 20:24:06 -05:00
52d13ea7bc Update customers_controller.rb 2017-01-29 20:18:21 -05:00
5e24c5084e Update customers_controller.rb 2017-01-29 20:12:38 -05:00
abdb61cc41 Update Gemfile 2017-01-29 20:07:08 -05:00
03556cc670 Update Gemfile 2017-01-29 20:03:53 -05:00
7f6cd99aba Update Gemfile 2017-01-29 19:58:11 -05:00
ba513fb950 Update issues_form_hook_listener.rb 2017-01-29 19:47:24 -05:00
837ddd722c Update issues_form_hook_listener.rb 2017-01-29 19:46:21 -05:00
f2b0cd3748 Update issues_form_hook_listener.rb 2017-01-29 19:45:31 -05:00
f2a8878af4 Update issues_form_hook_listener.rb 2017-01-29 19:40:51 -05:00
13fccec54b Update routes.rb 2017-01-29 19:36:58 -05:00
eca2b986a9 Update customers_controller.rb 2017-01-29 19:35:45 -05:00
a06599b7f9 Update issues_form_hook_listener.rb 2017-01-29 19:34:31 -05:00
7fda4dc577 Create application.js 2017-01-29 19:32:59 -05:00
9e47152e12 Update Gemfile 2017-01-29 19:31:31 -05:00
83d21da41a Update issues_form_hook_listener.rb 2017-01-29 19:27:23 -05:00
a692f03bfa Update init.rb 2017-01-29 19:17:37 -05:00
994cdf908f Update init.rb 2017-01-29 19:16:55 -05:00
b022d17fc0 Update init.rb 2017-01-29 19:16:05 -05:00
644899c0b5 Update email_worker.rb 2017-01-29 19:15:14 -05:00
be3a3b920d Update email_worker.rb 2017-01-27 12:04:58 -05:00
d546eb026f Update email_worker.rb 2017-01-27 12:01:53 -05:00
fdc59feb13 Create email_worker.rb 2017-01-27 11:47:30 -05:00
186b726a7b Added nil check 2017-01-27 09:38:00 -05:00
RageLtMan
fa362bad55 Merge pull request #3 from sempervictus/bug-dont_call_string_method_on_nil_token
Do not permit OAUTH_CONSUMER_SECRET to be nil
2017-01-19 04:09:34 -05:00
RageLtMan
fcf55bb504 Do not permit OAUTH_CONSUMER_SECRET to be nil
When QBO plugin is not configured, OAUTH_CONSUMER_SECRET can be
nil, and any codepath hitting the model raises a stack trace.

Set a "safe-ish" value here to allow execution in conditions where
QBO plugin is installed, but not yet configured.
2017-01-19 04:02:59 -05:00
RageLtMan
2185667665 Merge pull request #2 from sempervictus/local
Merge initial changes 20170103
2017-01-03 04:34:58 -05:00
RageLtMan
772483817e Prevent billing if issue has no customer assigned 2017-01-03 04:32:04 -05:00
RageLtMan
178ddd32c7 Remove will_paginate version constraint 2017-01-02 05:01:41 -05:00
08e047c90e Added done_ratio to partial billing 2016-10-12 10:31:05 -04:00
b3c3314385 Remove Breaks 2016-09-26 16:41:41 -04:00
9fd5e01bb4 Update qbo_invoice.rb 2016-09-26 16:39:12 -04:00
cd62f65fcd Update qbo_invoice.rb 2016-09-26 16:34:56 -04:00
fb40833abd Update qbo_invoice.rb 2016-09-26 16:33:56 -04:00
6aae155933 Update qbo_invoice.rb 2016-09-21 19:51:22 -04:00
f9e0ae8fef Update qbo_invoice.rb 2016-09-21 19:48:26 -04:00
489e335ca4 Update qbo_invoice.rb 2016-09-21 19:46:55 -04:00
874d0b4db9 Update qbo_invoice.rb 2016-09-21 19:43:40 -04:00
49e8f70b46 Update qbo_invoice.rb 2016-09-21 16:17:07 -04:00
77ea20171e Don't tie invoice to issue if customer is diffrent 2016-09-21 16:15:43 -04:00
11d4034c37 Update query_patch.rb 2016-09-19 23:19:53 -04:00
64369470de Update auth_helper.rb 2016-09-19 23:01:58 -04:00
7b483f3290 Update invoice_controller.rb 2016-09-19 23:01:27 -04:00
32bec79c28 Update invoice_controller.rb 2016-09-19 22:59:44 -04:00
dfd9622ab7 Update invoice_controller.rb 2016-09-19 22:59:02 -04:00
334d3c930b Update auth_helper.rb 2016-09-19 22:57:19 -04:00
8cf2f370bf Update invoice_controller.rb 2016-09-19 22:54:58 -04:00
3965bed6c4 Update invoice_controller.rb 2016-09-19 22:50:18 -04:00
52396eb384 Update invoice_controller.rb 2016-09-19 22:49:06 -04:00
9cfab7bea1 Update invoice_controller.rb 2016-09-19 22:44:52 -04:00
c8ef3bbd4e Update invoice_controller.rb 2016-09-19 22:38:48 -04:00
39e7d3c062 Update invoice_controller.rb 2016-09-19 22:37:53 -04:00
6fa96e11df Update invoice_controller.rb 2016-09-19 22:35:51 -04:00
ecde64193a Update invoice_controller.rb 2016-09-19 22:32:30 -04:00
f701af9a4d Update auth_helper.rb 2016-09-19 22:30:14 -04:00
6d99702a11 Update customers_controller.rb 2016-09-19 22:27:03 -04:00
138f8f2c2f Update auth_helper.rb 2016-09-19 22:21:37 -04:00
61ddf7378d Update auth_helper.rb 2016-09-19 22:18:19 -04:00
f5b72f30be Update customers_controller.rb 2016-09-19 22:17:15 -04:00
1863b33955 Update view.html.erb 2016-09-19 22:05:48 -04:00
a4573fce1c Update issue_patch.rb 2016-09-19 22:01:32 -04:00
0461801ee0 Update issues_form_hook_listener.rb 2016-09-19 21:29:28 -04:00
4c2eaac013 Update routes.rb 2016-09-19 21:26:40 -04:00
7ca56ccd2e Update routes.rb 2016-09-19 20:27:26 -04:00
915a59afa4 Update issues_form_hook_listener.rb 2016-09-19 20:17:00 -04:00
ac61950d48 Update routes.rb 2016-09-19 20:13:57 -04:00
b257fef563 Update customers_controller.rb 2016-09-19 20:10:11 -04:00
504c27c197 Update qbo_invoice.rb 2016-09-19 11:10:26 -04:00
a7a5e2c731 Update qbo_invoice.rb 2016-09-19 11:07:33 -04:00
21d72dcc33 Update qbo_invoice.rb 2016-09-19 11:06:35 -04:00
da7ba40e61 Added Private Note Scanning
Also removed redundant checks
2016-09-19 10:59:20 -04:00
b4d6fc55ea Update customers_controller.rb 2016-09-19 07:57:49 -04:00
515b8feff7 Update attachments_controller_patch.rb 2016-09-19 07:44:03 -04:00
8bc05db033 Update init.rb 2016-09-19 07:30:07 -04:00
34cd6b08dc Create attachments_controller_patch.rb 2016-09-19 07:29:16 -04:00
41195dc095 Update show.html.erb 2016-09-18 22:55:12 -04:00
33a83c8f76 Update _details.html.erb 2016-09-18 22:53:54 -04:00
4f613d3fe1 Update show.html.erb 2016-09-18 22:52:48 -04:00
1c7cdec600 Update show.html.erb 2016-09-18 22:41:24 -04:00
7ae60c0e62 Update show.html.erb 2016-09-18 22:38:26 -04:00
5dd04925e0 Update show.html.erb 2016-09-18 22:37:23 -04:00
92eedbd4d3 Update show.html.erb 2016-09-18 22:32:45 -04:00
5545d72adf Update view.html.erb 2016-09-16 23:11:59 -04:00
226d44cd28 Update customers_controller.rb 2016-09-16 23:10:21 -04:00
b7152d6124 Update view.html.erb 2016-09-16 23:07:05 -04:00
f3e9b58c87 Update customers_controller.rb 2016-09-16 23:06:20 -04:00
5209315236 Update view.html.erb 2016-09-16 23:05:23 -04:00
f38a9e1ff0 Update view.html.erb 2016-09-16 23:04:47 -04:00
80fb296e24 Update customers_controller.rb 2016-09-16 23:03:07 -04:00
23 changed files with 235 additions and 133 deletions

View File

@@ -6,7 +6,10 @@ gem 'oauth-plugin'
gem 'oauth'
gem 'roxml'
gem 'edmunds_vin'
gem 'will_paginate', '~> 3.1.0'
gem 'will_paginate'
gem 'rails-jquery-autocomplete'
gem 'jquery-rails', '~> 3.1.4'
gem 'jquery-ui-rails'
group :assets do
gem 'coffee-rails'

View File

@@ -32,6 +32,12 @@ class CustomersController < ApplicationController
default_search_scope :names
autocomplete :customer, :name, :full => false, :extra_data => [:id]
def filter_vehicles_by_customer
@filtered_vehicles = Vehicle.all.where(customer_id: params[:selected_customer])
end
# display a list of all customers
def index
if params[:search]
@@ -105,9 +111,14 @@ class CustomersController < ApplicationController
# Customer view for an issue
def view
token = CustomerToken.where("token = ? and expires_at > ?", params[:token], Time.now)
if token.first
@issue = Issue.find token.first.issue_id
User.current = User.find_by lastname: 'Anonymous'
@token = CustomerToken.where("token = ? and expires_at > ?", params[:token], Time.now)
@token = @token.first
if @token
session[:token] = @token.token
@issue = Issue.find @token.issue_id
@journals = @issue.journals.
preload(:details).
preload(:user => :email_address).

View File

@@ -12,7 +12,8 @@ class InvoiceController < ApplicationController
include AuthHelper
before_filter :require_user
before_filter :require_user, :unless => proc {|c| session[:token].nil? }
skip_before_filter :verify_authenticity_token, :check_if_login_required, :unless => proc {|c| session[:token].nil? }
#
# Downloads and forwards the invoice pdf

View File

@@ -66,8 +66,12 @@ class QboController < ApplicationController
# Manual Billing
def bill
i = Issue.find_by_id params[:id]
i.bill_time
redirect_to i, :flash => { :notice => "Successfully Billed #{i.customer.name}" }
if i.customer
i.bill_time
redirect_to i, :flash => { :notice => "Successfully Billed #{i.customer.name}" }
else
redirect_to i, :flash => { :error => "Cannot bill without a customer assigned" }
end
end
# Quickbooks Webhook Callback

View File

@@ -11,6 +11,7 @@
module AuthHelper
def require_user
return unless session[:token].nil?
if !User.current.logged?
render :file => "public/401.html.erb", :status => :unauthorized, :layout =>true
end

View File

@@ -15,7 +15,7 @@ class CustomerToken < ActiveRecord::Base
validates_presence_of :expires_at, :issue_id
before_create :generate_token
OAUTH_CONSUMER_SECRET = Setting.plugin_redmine_qbo['settingsOAuthConsumerSecret']
OAUTH_CONSUMER_SECRET = Setting.plugin_redmine_qbo['settingsOAuthConsumerSecret'] || 'CONFIGURE_QBO__' + SecureRandom.uuid
def generate_token
self.token = SecureRandom.base64(15).tr('+/=lIO0', OAUTH_CONSUMER_SECRET)

View File

@@ -46,89 +46,109 @@ class QboInvoice < ActiveRecord::Base
process_invoice invoice
end
private
# Attach the invoice to the issue
def self.attach_to_issue(issue, invoice)
return if issue.nil?
# skip this issue if the issue customer is not the same as the invoice customer
return if issue.customer_id != invoice.customer_ref.value.to_i
# Load the invoice into the database
qbo_invoice = QboInvoice.find_or_create_by(id: invoice.id)
qbo_invoice.doc_number = invoice.doc_number
qbo_invoice.id = invoice.id
qbo_invoice.save!
unless issue.qbo_invoices.include?(qbo_invoice)
issue.qbo_invoices << qbo_invoice
issue.save!
end
compare_custom_fields(issue, invoice)
end
# processes the invoice into the system
def self.process_invoice(invoice)
is_changed = false
# Check the private notes
if not invoice.private_note.nil?
invoice.private_note.scan(/#(\w+)/).flatten.each { |issue|
attach_to_issue(Issue.find_by_id(issue.to_i), invoice)
}
end
# Scan the line items for hashtags and attach to the applicable issues
invoice.line_items.each { |line|
if line.description
line.description.scan(/#(\w+)/).flatten.each { |issue|
i = Issue.find_by_id(issue.to_i)
# Load the invoice into the database
qbo_invoice = QboInvoice.find_or_create_by(id: invoice.id)
qbo_invoice.doc_number = invoice.doc_number
qbo_invoice.id = invoice.id
qbo_invoice.save!
# Attach the invoice to the issue
unless i.qbo_invoices.include?(qbo_invoice)
i.qbo_invoices << qbo_invoice
i.save!
end
# update the invoive custom fields with infomation from the work ticket if available
invoice.custom_fields.each { |cf|
# VIN from the attached vehicle
begin
if cf.name.eql? "VIN"
vin = Vehicle.find(i.vehicles_id).vin
break if vin.nil?
if not cf.string_value.to_s.eql? vin
cf.string_value = vin.to_s
is_changed = true
break
end
end
rescue
#do nothing
end
# Custom Values
begin
value = i.custom_values.find_by(custom_field_id: CustomField.find_by_name(cf.name).id)
# Check to see if the value is blank...
if not value.value.to_s.blank?
# Check to see if the value is diffrent
if not cf.string_value.to_s.eql? value.value.to_s
# Use the lowest Milage
if cf.name.eql? "Mileage In"
if cf.string_value.to_i > value.value.to_i or cf.string_value.blank?
cf.string_value = value.value.to_s
is_changed = true
end
break
end
# Use the max milage
if cf.name.eql? "Mileage Out"
if cf.string_value.to_i < value.value.to_i or cf.string_value.blank?
cf.string_value = value.value.to_s
is_changed = true
end
break
end
# Everything else
cf.string_value = value.value.to_s
is_changed = true
end
end
rescue
# Nothing to do here, there is no match
end
}
attach_to_issue(Issue.find_by_id(issue.to_i), invoice)
}
end
}
end
def self.compare_custom_fields(issue, invoice)
is_changed = false
# update the invoive custom fields with infomation from the work ticket if available
invoice.custom_fields.each { |cf|
# TODO Add some hooks here
# VIN from the attached vehicle
begin
if cf.name.eql? "VIN"
vin = Vehicle.find(issue.vehicles_id).vin
break if vin.nil?
if not cf.string_value.to_s.eql? vin
cf.string_value = vin.to_s
is_changed = true
end
end
rescue
#do nothing
end
# Custom Values
begin
value = issue.custom_values.find_by(custom_field_id: CustomField.find_by_name(cf.name).id)
# Check to see if the value is blank...
if not value.value.to_s.blank?
# Check to see if the value is diffrent
if not cf.string_value.to_s.eql? value.value.to_s
# Use the lowest Milage
if cf.name.eql? "Mileage In"
if cf.string_value.to_i > value.value.to_i or cf.string_value.blank?
cf.string_value = value.value.to_s
is_changed = true
end
end
# Use the max milage
if cf.name.eql? "Mileage Out"
if cf.string_value.to_i < value.value.to_i or cf.string_value.blank?
cf.string_value = value.value.to_s
is_changed = true
end
end
# Everything else
cf.string_value = value.value.to_s
is_changed = true
end
end
rescue
# Nothing to do here, there is no match
end
}
# TODO Add some hooks here
# Push updates
get_base.update(invoice) if is_changed
end
end

View File

@@ -1,10 +1,5 @@
<table>
<tbody>
<tr>
<th>Customer</th>
<td><%= customer.name %></td>
</tr>
<tr>
<th>Email</th>
<td><%= customer.email %></td>

View File

@@ -0,0 +1 @@
$('select#issue_vehicles_id').html('<%= j options_from_collection_for_select(@filtered_vehicles, :id, :to_s) %>');

View File

@@ -1,12 +1,27 @@
<h1>Customer #<%= @customer.id %></h1>
<br/>
<h2>Details:</h2>
<%= render :partial => 'customers/details', locals: {customer: @customer} %>
<br/>
<h2>Vehicles:</h2>
<%= render :partial => 'vehicles/list' %>
<%= button_to "New Vehicle", new_customer_vehicle_path(@customer), method: :get %>
<br/>
<br/>
<h2>Issues:</h2>
<%= render :partial => 'issues/list_simple', locals: {issues: @issues} %>
<div id="content">
<h2>Customer #<%= @customer.id %></h2>
<br/>
<div class="subject">
<div><h3><%= @customer.name %></h3></div>
</div>
<div class="attributes">
<div class="splitcontent">
<div class="splitcontentleft">
<h4>Details:</h4>
<%= render :partial => 'customers/details', locals: {customer: @customer} %>
</div>
<div class="splitcontentleft">
<h4>Vehicles:</h4>
<%= render :partial => 'vehicles/list' %>
<%= button_to "New Vehicle", new_customer_vehicle_path(@customer), method: :get %>
</div>
</div>
<br/>
<h2>Issues:</h2>
<%= render :partial => 'issues/list_simple', locals: {issues: @issues} %>
</div>
</div>

View File

@@ -6,6 +6,7 @@
<div class="subject">
<%= render_issue_subject_with_tree(@issue) %>
This customer link expires in <%= distance_of_time_in_words(Time.now, @token.expires_at) %>
</div>
<p class="author">
<%= authoring @issue.created_on, @issue.author %>.
@@ -41,11 +42,11 @@
rows.right l(:field_estimated_hours), issue_estimated_hours_details(@issue), :class => 'estimated-hours'
end
end
if User.current.allowed_to_view_all_time_entries?(@project)
#if User.current.allowed_to_view_all_time_entries?(@project)
if @issue.total_spent_hours > 0
rows.right l(:label_spent_time), issue_spent_hours_details(@issue), :class => 'spent-time'
end
end
#end
end %>
<%= render_custom_fields_rows(@issue) %>
<%= call_hook(:view_issues_show_details_bottom, :issue => @issue) %>

View File

@@ -0,0 +1,18 @@
#The MIT License (MIT)
#
#Copyright (c) 2017 rick barrette
#
#Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
#
#The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
#
#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# This sidekiq worker class will handle emailing weekly time reports
class EmailWorker
include Sidekiq::Worker
def perform()
# email something
end
end

View File

@@ -0,0 +1,9 @@
$(function() {
$("input#issue_customer_id").on("change", function() {
$.ajax({
url: "/filter_vehicles_by_customer",
type: "GET",
data: { selected_customer: $("input#issue_customer_id").val() }
});
});
});

View File

@@ -0,0 +1 @@
!function(t){t.fn.railsAutocomplete=function(e){var a=function(){this.railsAutoCompleter||(this.railsAutoCompleter=new t.railsAutocomplete(this))};if(void 0!==t.fn.on){if(!e)return;return t(document).on("focus",e,a)}return this.live("focus",a)},t.railsAutocomplete=function(t){var e=t;this.init(e)},t.railsAutocomplete.options={showNoMatches:!0,noMatchesLabel:"no existing match"},t.railsAutocomplete.fn=t.railsAutocomplete.prototype={railsAutocomplete:"0.0.1"},t.railsAutocomplete.fn.extend=t.railsAutocomplete.extend=t.extend,t.railsAutocomplete.fn.extend({init:function(e){function a(t){return t.split(e.delimiter)}function i(t){return a(t).pop().replace(/^\s+/,"")}e.delimiter=t(e).attr("data-delimiter")||null,e.min_length=t(e).attr("data-min-length")||t(e).attr("min-length")||2,e.append_to=t(e).attr("data-append-to")||null,e.autoFocus=t(e).attr("data-auto-focus")||!1,t(e).autocomplete({appendTo:e.append_to,autoFocus:e.autoFocus,delay:t(e).attr("delay")||0,source:function(a,r){var n=this.element[0],o={term:i(a.term)};t(e).attr("data-autocomplete-fields")&&t.each(t.parseJSON(t(e).attr("data-autocomplete-fields")),function(e,a){o[e]=t(a).val()}),t.getJSON(t(e).attr("data-autocomplete"),o,function(){var a={};t.extend(a,t.railsAutocomplete.options),t.each(a,function(i,r){if(a.hasOwnProperty(i)){var n=t(e).attr("data-"+i);a[i]=n?n:r}}),0==arguments[0].length&&t.inArray(a.showNoMatches,[!0,"true"])>=0&&(arguments[0]=[],arguments[0][0]={id:"",label:a.noMatchesLabel}),t(arguments[0]).each(function(a,i){var r={};r[i.id]=i,t(e).data(r)}),r.apply(null,arguments),t(n).trigger("railsAutocomplete.source",arguments)})},change:function(e,a){if(t(this).is("[data-id-element]")&&""!==t(t(this).attr("data-id-element")).val()&&(t(t(this).attr("data-id-element")).val(a.item?a.item.id:"").trigger("change"),t(this).attr("data-update-elements"))){var i=t.parseJSON(t(this).attr("data-update-elements")),r=a.item?t(this).data(a.item.id.toString()):{};if(i&&""===t(i.id).val())return;for(var n in i){var o=t(i[n]);o.is(":checkbox")?null!=r[n]&&o.prop("checked",r[n]):o.val(a.item?r[n]:"").trigger("change")}}},search:function(){var t=i(this.value);return t.length<e.min_length?!1:void 0},focus:function(){return!1},select:function(i,r){if(r.item.value=r.item.value.toString(),-1!=r.item.value.toLowerCase().indexOf("no match")||-1!=r.item.value.toLowerCase().indexOf("too many results"))return t(this).trigger("railsAutocomplete.noMatch",r),!1;var n=a(this.value);if(n.pop(),n.push(r.item.value),null!=e.delimiter)n.push(""),this.value=n.join(e.delimiter);else if(this.value=n.join(""),t(this).attr("data-id-element")&&t(t(this).attr("data-id-element")).val(r.item.id).trigger("change"),t(this).attr("data-update-elements")){var o=r.item,l=-1!=r.item.value.indexOf("Create New")?!0:!1,u=t.parseJSON(t(this).attr("data-update-elements"));for(var s in u)"checkbox"===t(u[s]).attr("type")?o[s]===!0||1===o[s]?t(u[s]).attr("checked","checked"):t(u[s]).removeAttr("checked"):l&&o[s]&&-1==o[s].indexOf("Create New")||!l?t(u[s]).val(o[s]).trigger("change"):t(u[s]).val("").trigger("change")}var c=this.value;return t(this).bind("keyup.clearId",function(){t.trim(t(this).val())!=t.trim(c)&&(t(t(this).attr("data-id-element")).val("").trigger("change"),t(this).unbind("keyup.clearId"))}),t(e).trigger("railsAutocomplete.select",r),!1}}),t(e).trigger("railsAutocomplete.init")}}),t(document).ready(function(){t("input[data-autocomplete]").railsAutocomplete("input[data-autocomplete]")})}(jQuery);

View File

@@ -1,2 +0,0 @@
$("#issue_vehicles_id").empty()
.append("<%= escape_javascript(render(:partial => @vehicles)) %>")

View File

@@ -1,10 +0,0 @@
function customerSelected() {
customer_id = $('issue_customer_id').getValue();
console.log(customer_id);
}
document.observe('dom:loaded', function() {
customerSelected();
$('issue_customer_id').observe('change', customerSelected);
});

View File

@@ -35,11 +35,13 @@ resources :payments
post 'qbo/webhook', :to => 'qbo#qbo_webhook'
#ajax
get "update_vehicles" => 'vehicles#update_vehicles', as: 'update_vehicles'
get 'filter_vehicles_by_customer' => 'customers#filter_vehicles_by_customer'
# Nest Vehicles under customers
resources :customers do
resources :vehicles
get :autocomplete_customer_name, :on => :collection
get :autocomplete_customer_vehicles, :on => :collection
end
#allow for just vehicles too

View File

@@ -23,19 +23,16 @@ Redmine::Plugin.register :redmine_qbo do
require_dependency 'query_patch'
require_dependency 'time_entry_query_patch'
require_dependency 'pdf_patch'
Rails.configuration.to_prepare do
Redmine::Search.available_search_types << 'customers'
end
require_dependency 'attachments_controller_patch'
name 'Redmine Quickbooks Online plugin'
author 'Rick Barrette'
description 'This is a plugin for Redmine to intergrate with Quickbooks Online to allow for seamless intergration CRM and invoicing of completed issues'
version '0.4.1'
version '0.4.2'
url 'https://github.com/rickbarrette/redmine_qbo'
author_url 'http://rickbarrette.org'
settings :default => {'empty' => true}, :partial => 'qbo/settings'
# Add safe attributes
Issue.safe_attributes 'customer_id'
Issue.safe_attributes 'qbo_item_id'

View File

@@ -0,0 +1,38 @@
#The MIT License (MIT)
#
#Copyright (c) 2016 rick barrette
#
#Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
#
#The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
#
#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
require_dependency 'attachments_controller'
module AttachmentsControllerPatch
def self.included(base) # :nodoc:
base.extend(ClassMethods)
base.send(:include, InstanceMethods)
# Same as typing in the class
base.class_eval do
unloadable # Send unloadable so it will not be unloaded in development
skip_before_action :read_authorize
end
end
module ClassMethods
end
module InstanceMethods
end
end
# Add module to AttachmentsController
AttachmentsController.send(:include, AttachmentsControllerPatch)

View File

@@ -72,7 +72,7 @@ module IssuePatch
item = item_service.query("SELECT * FROM Item WHERE Name = '#{key}' ").first
next if item.nil?
time_entry.description = "#{tracker} ##{id}: #{subject} #{"(Partial)" if not closed?}"
time_entry.description = "#{tracker} ##{id}: #{subject} #{"(Partial @ #{done_ratio}%)" if not closed?}"
# TODO entry.user.qbo_employee.id
time_entry.employee_id = assigned_to.qbo_employee_id
time_entry.customer_id = customer_id
@@ -93,7 +93,7 @@ module IssuePatch
# Create a shareable link for a customer
def share_token
CustomerToken.create(:expires_at => Time.now + 24.hours, :issue_id => id)
CustomerToken.create(:expires_at => Time.now + 1.month, :issue_id => id)
end
end

View File

@@ -12,8 +12,8 @@ class IssuesFormHookListener < Redmine::Hook::ViewListener
# Load the javascript
def view_layouts_base_html_head(context = {})
js = javascript_include_tag 'vehicles', :plugin => 'redmine_qbo'
#js += javascript_include_tag 'update_vehicles', :plugin => 'redmine_qbo'
js = javascript_include_tag 'application', :plugin => 'redmine_qbo'
js += javascript_include_tag 'autocomplete-rails', :plugin => 'redmine_qbo'
return js
end
@@ -27,25 +27,22 @@ class IssuesFormHookListener < Redmine::Hook::ViewListener
selected_estimate = context[:issue].qbo_estimate ? context[:issue].qbo_estimate.id : nil
selected_vehicle = context[:issue].vehicles_id ? context[:issue].vehicles_id : nil
# Load customer information without callbacks
customer = Customer.find_by_id(selected_customer) if selected_customer
select_customer = f.select :customer_id,
Customer.all.pluck(:name, :id).sort,
:selected => selected_customer,
include_blank: true,
onchange: "$customerSelected;"
# Load customer information
customer = Customer.find_by_id(selected_customer) if selected_customer
search_customer = f.autocomplete_field :customer, autocomplete_customer_name_customers_path, :selected => selected_customer, :update_elements => {:id => '#issue_customer_id', :value => '#issue_customer'}
customer_id = f.hidden_field :customer_id, :id => "issue_customer_id"
# Generate the drop down list of quickbooks extimates
select_estimate = f.select :qbo_estimate_id, QboEstimate.all.pluck(:doc_number, :id).sort! {|x, y| y <=> x}, :selected => selected_estimate, include_blank: true
if context[:issue].customer
vehicles = customer.vehicles.pluck(:name, :id).sort!
vehicles = customer.vehicles.pluck(:name, :id).sort!
else
vehicles = Vehicle.all.order(:name).pluck(:name, :id)
vehicles = [nil].compact
end
vehicle = f.select :vehicles_id, vehicles, :selected => selected_vehicle, include_blank: true
return "<p>#{select_customer}</p> <p>#{select_estimate}</p> <p>#{vehicle}</p>"
return "<p><label for=\"issue_customer\">Customer</label>#{search_customer} #{customer_id}</p> <p>#{select_estimate}</p> <p>#{vehicle}</p>"
end
end

View File

@@ -51,7 +51,7 @@ module IssuesPdfHelperPatch
vin = v ? v.vin : nil
notes = v ? v.notes : nil
left << [l(:field_vehicles), vehicle]
left << [l(:field_vin), vin.gsub(/(.{9})/, '\1 ')]
left << [l(:field_vin), vin ? vin.gsub(/(.{9})/, '\1 ') : nil]
#left << [l(:field_notes), notes]
right = []

View File

@@ -36,7 +36,7 @@ module QueryPatch
unless @available_columns
@available_columns = available_columns_without_qbo
@available_columns << QueryColumn.new(:customer, :sortable => "#{Customer.table_name}.name", :groupable => true, :caption => :field_customer)
@available_columns << QueryColumn.new(:qbo_billed, :sortable => "#{TimeEntry.table_name}.name", :groupable => true, :caption => :field_qbo_billed)
@available_columns << QueryColumn.new(:qbo_billed, :sortable => "#{TimeEntry.table_name}.qbo_billed", :groupable => true, :caption => :field_qbo_billed)
end
@available_columns
end