mirror of
https://github.com/rickbarrette/redmine_qbo.git
synced 2025-11-09 01:14:23 -05:00
Compare commits
67 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| bee48c4f0f | |||
| 0f8fbfb8df | |||
| d71e9a78a1 | |||
| 7ac778586c | |||
| 2558cb69b1 | |||
| 55ac8d12a5 | |||
| a5dc5ce921 | |||
| de65cc0926 | |||
| 80d3eed224 | |||
| 76beccfb9f | |||
| 5579cd9255 | |||
| 236e84f11a | |||
| ed61dc6bbf | |||
| 2b7ac05338 | |||
| 36e63995aa | |||
| 58d16fbc7d | |||
| aa78482c36 | |||
| c35b6a3f6b | |||
| 8d52c46a53 | |||
| 325f124e4e | |||
| 18d71a69f8 | |||
| 7d5fd72297 | |||
| a625f6d9fc | |||
| ede89cc6cf | |||
| c60f06e8ed | |||
| 863a5efa38 | |||
| 670b0aac67 | |||
| d261b156bd | |||
| c49bdb731a | |||
| dc2993bdea | |||
| 09e1c0ad48 | |||
| 370153bed9 | |||
| b115c4bf67 | |||
| 90a7ac1267 | |||
| 887d330ba9 | |||
| fe97a589d9 | |||
| 37d0b2321f | |||
| 47aa454895 | |||
| fecc4956b4 | |||
| 0d5fb8d3e3 | |||
| ca6e51911b | |||
| 8159487631 | |||
| 392b27563a | |||
| 60dced41db | |||
| 8b02a80904 | |||
| ff977cc364 | |||
| 3578908832 | |||
| 4fcde967f1 | |||
| 4e81c16617 | |||
| 8149f5ab9b | |||
| 7800e52299 | |||
| c6f8fd7561 | |||
| e3d26cea23 | |||
| 4fd35d4cb6 | |||
| cf00331497 | |||
| dc8ea82b61 | |||
| aab99e3abe | |||
| f240a5a6a4 | |||
| 05ce348d8a | |||
| 67afbff93d | |||
| bd92ca8f2c | |||
| 7ef3e31465 | |||
| f59aa18be8 | |||
| 2699b37e4f | |||
| 22f8138422 | |||
| 0727257d72 | |||
| f8a9ffbe15 |
@@ -13,7 +13,8 @@ class QboController < ApplicationController
|
|||||||
|
|
||||||
include AuthHelper
|
include AuthHelper
|
||||||
|
|
||||||
before_filter :require_user
|
before_filter :require_user, :except => :qbo_webhook
|
||||||
|
skip_before_filter :verify_authenticity_token, :check_if_login_required
|
||||||
|
|
||||||
#
|
#
|
||||||
# Called when the QBO Top Menu us shown
|
# Called when the QBO Top Menu us shown
|
||||||
@@ -31,9 +32,10 @@ class QboController < ApplicationController
|
|||||||
# Called when the user requests that Redmine to connect to QBO
|
# Called when the user requests that Redmine to connect to QBO
|
||||||
#
|
#
|
||||||
def authenticate
|
def authenticate
|
||||||
callback = request.base_url + qbo_oauth_callback_path
|
callback = qbo_oauth_callback_url
|
||||||
token = Qbo.get_oauth_consumer.get_request_token(:oauth_callback => callback)
|
token = Qbo.get_oauth_consumer.get_request_token(:oauth_callback => callback)
|
||||||
session[:qb_request_token] = token
|
#session[:qb_request_token] = token
|
||||||
|
session[:qb_request_token] = Marshal.dump(token)
|
||||||
redirect_to("https://appcenter.intuit.com/Connect/Begin?oauth_token=#{token.token}") and return
|
redirect_to("https://appcenter.intuit.com/Connect/Begin?oauth_token=#{token.token}") and return
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -41,7 +43,9 @@ class QboController < ApplicationController
|
|||||||
# Called by QBO after authentication has been processed
|
# Called by QBO after authentication has been processed
|
||||||
#
|
#
|
||||||
def oauth_callback
|
def oauth_callback
|
||||||
at = session[:qb_request_token].get_access_token(:oauth_verifier => params[:oauth_verifier])
|
#at = session[:qb_request_token].get_access_token(:oauth_verifier => params[:oauth_verifier])
|
||||||
|
# If Rails >= 4.1 you need to do this =>
|
||||||
|
at = Marshal.load(session[:qb_request_token]).get_access_token(:oauth_verifier => params[:oauth_verifier])
|
||||||
|
|
||||||
#There can only be one...
|
#There can only be one...
|
||||||
Qbo.destroy_all
|
Qbo.destroy_all
|
||||||
@@ -54,13 +58,48 @@ class QboController < ApplicationController
|
|||||||
qbo.reconnect_token_at = 5.months.from_now.utc
|
qbo.reconnect_token_at = 5.months.from_now.utc
|
||||||
qbo.company_id = params['realmId']
|
qbo.company_id = params['realmId']
|
||||||
if qbo.save!
|
if qbo.save!
|
||||||
redirect_to qbo_sync_path, :flash => { :notice => "Successfully connected to Quickbooks" }
|
redirect_to qbo_path, :flash => { :notice => "Successfully connected to Quickbooks" }
|
||||||
else
|
else
|
||||||
redirect_to plugin_settings_path(:redmine_qbo), :flash => { :error => "Error" }
|
redirect_to plugin_settings_path(:redmine_qbo), :flash => { :error => "Error" }
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Quickbooks Webhook Callback
|
||||||
|
def qbo_webhook
|
||||||
|
|
||||||
|
if request.headers['Content-Type'] == 'application/json'
|
||||||
|
data = JSON.parse(request.body.read)
|
||||||
|
else
|
||||||
|
# application/x-www-form-urlencoded
|
||||||
|
data = params.as_json
|
||||||
|
end
|
||||||
|
|
||||||
|
entities = data['eventNotifications'][0]['dataChangeEvent']['entities']
|
||||||
|
|
||||||
|
entities.each do |entity|
|
||||||
|
if entity['name'].eql? "Customer"
|
||||||
|
Customer.sync_by_id(entity['id'].to_i)
|
||||||
|
end
|
||||||
|
|
||||||
|
if entity['name'].eql? "Invoice"
|
||||||
|
QboInvoice.sync_by_id(entity['id'].to_i)
|
||||||
|
end
|
||||||
|
|
||||||
|
if entity['name'].eql? "Estimate"
|
||||||
|
QboEstimate.sync_by_id(entity['id'].to_i)
|
||||||
|
end
|
||||||
|
|
||||||
|
if entity['name'].eql? "Employee"
|
||||||
|
QboEmployee.sync_by_id(entity['id'].to_i)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# The webhook doesn't require a response but let's make sure
|
||||||
|
# we don't send anything
|
||||||
|
render :nothing => true
|
||||||
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
# Synchronizes the QboCustomer table with QBO
|
# Synchronizes the QboCustomer table with QBO
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -36,6 +36,13 @@ class Customer < ActiveRecord::Base
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Convenience Method
|
||||||
|
# Sets the email
|
||||||
|
def email=(s)
|
||||||
|
pull unless @details
|
||||||
|
@details.email_address = s
|
||||||
|
end
|
||||||
|
|
||||||
# Convenience Method
|
# Convenience Method
|
||||||
# returns the customer's primary phone
|
# returns the customer's primary phone
|
||||||
def primary_phone
|
def primary_phone
|
||||||
@@ -108,14 +115,14 @@ class Customer < ActiveRecord::Base
|
|||||||
service = Qbo.get_base(:customer).service
|
service = Qbo.get_base(:customer).service
|
||||||
|
|
||||||
# Sync ALL customers if the database is empty
|
# Sync ALL customers if the database is empty
|
||||||
if count == 0
|
#if count == 0
|
||||||
customers = service.all
|
customers = service.all
|
||||||
else
|
#else
|
||||||
last = Qbo.first.last_sync
|
# last = Qbo.first.last_sync
|
||||||
query = "Select Id, DisplayName From Customer"
|
# query = "Select Id, DisplayName From Customer"
|
||||||
query << " Where Metadata.LastUpdatedTime >= '#{last.iso8601}' " if last
|
# query << " Where Metadata.LastUpdatedTime >= '#{last.iso8601}' " if last
|
||||||
customers = service.query(query)
|
# customers = service.query(query)
|
||||||
end
|
#end
|
||||||
|
|
||||||
customers.each do |customer|
|
customers.each do |customer|
|
||||||
qbo_customer = Customer.find_or_create_by(id: customer.id)
|
qbo_customer = Customer.find_or_create_by(id: customer.id)
|
||||||
@@ -133,6 +140,26 @@ class Customer < ActiveRecord::Base
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# proforms a bruteforce sync operation
|
||||||
|
# This needs to be simplified
|
||||||
|
def self.sync_by_id(id)
|
||||||
|
service = Qbo.get_base(:customer).service
|
||||||
|
|
||||||
|
customer = service.fetch_by_id(id)
|
||||||
|
qbo_customer = Customer.find_or_create_by(id: customer.id)
|
||||||
|
if customer.active?
|
||||||
|
if not qbo_customer.name.eql? customer.display_name
|
||||||
|
qbo_customer.name = customer.display_name
|
||||||
|
qbo_customer.id = customer.id
|
||||||
|
qbo_customer.save_without_push
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if not qbo_customer.new_record?
|
||||||
|
qbo_customer.delete
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# Push the updates
|
# Push the updates
|
||||||
def save_with_push
|
def save_with_push
|
||||||
begin
|
begin
|
||||||
|
|||||||
@@ -12,11 +12,10 @@ class Qbo < ActiveRecord::Base
|
|||||||
unloadable
|
unloadable
|
||||||
validates_presence_of :qb_token, :qb_secret, :company_id, :token_expires_at, :reconnect_token_at
|
validates_presence_of :qb_token, :qb_secret, :company_id, :token_expires_at, :reconnect_token_at
|
||||||
|
|
||||||
QB_KEY = Setting.plugin_redmine_qbo['settingsOAuthConsumerKey']
|
OAUTH_CONSUMER_KEY = Setting.plugin_redmine_qbo['settingsOAuthConsumerKey']
|
||||||
QB_SECRET = Setting.plugin_redmine_qbo['settingsOAuthConsumerSecret']
|
OAUTH_CONSUMER_SECRET = Setting.plugin_redmine_qbo['settingsOAuthConsumerSecret']
|
||||||
|
|
||||||
# Quickbooks Config Info
|
$qb_oauth_consumer = OAuth::Consumer.new(OAUTH_CONSUMER_KEY, OAUTH_CONSUMER_SECRET, {
|
||||||
$qb_oauth_consumer = OAuth::Consumer.new(QB_KEY, QB_SECRET, {
|
|
||||||
:site => "https://oauth.intuit.com",
|
:site => "https://oauth.intuit.com",
|
||||||
:request_token_path => "/oauth/v1/get_request_token",
|
:request_token_path => "/oauth/v1/get_request_token",
|
||||||
:authorize_url => "https://appcenter.intuit.com/Connect/Begin",
|
:authorize_url => "https://appcenter.intuit.com/Connect/Begin",
|
||||||
@@ -31,6 +30,7 @@ class Qbo < ActiveRecord::Base
|
|||||||
end
|
end
|
||||||
|
|
||||||
def self.get_oauth_consumer
|
def self.get_oauth_consumer
|
||||||
|
# Quickbooks Config Info
|
||||||
return $qb_oauth_consumer
|
return $qb_oauth_consumer
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -30,8 +30,14 @@ class QboEmployee < ActiveRecord::Base
|
|||||||
qbo_employee.save!
|
qbo_employee.save!
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
#remove deleted employees
|
def self.sync_by_id(id)
|
||||||
where.not(employees.map(&:id)).destroy_all
|
employee = get_base.service.fetch_by_id(id)
|
||||||
|
|
||||||
|
qbo_employee = find_or_create_by(id: employee.id)
|
||||||
|
qbo_employee.name = employee.display_name
|
||||||
|
qbo_employee.id = employee.id
|
||||||
|
qbo_employee.save!
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -35,6 +35,14 @@ class QboEstimate < ActiveRecord::Base
|
|||||||
where.not(estimates.map(&:id)).destroy_all
|
where.not(estimates.map(&:id)).destroy_all
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.sync_by_id(id)
|
||||||
|
estimate = get_base.service.fetch_by_id(id)
|
||||||
|
qbo_estimate = QboEstimate.find_or_create_by(id: estimate.id)
|
||||||
|
qbo_estimate.doc_number = estimate.doc_number
|
||||||
|
qbo_estimate.id = estimate.id
|
||||||
|
qbo_estimate.save!
|
||||||
|
end
|
||||||
|
|
||||||
def self.update(id)
|
def self.update(id)
|
||||||
# Update the item table
|
# Update the item table
|
||||||
estimate = get_base.service.fetch_by_id(id)
|
estimate = get_base.service.fetch_by_id(id)
|
||||||
|
|||||||
@@ -45,6 +45,14 @@ class QboInvoice < ActiveRecord::Base
|
|||||||
#where.not(invoices.map(&:id)).destroy_all
|
#where.not(invoices.map(&:id)).destroy_all
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.sync_by_id(id)
|
||||||
|
invoice = get_base.service.fetch_by_id(id)
|
||||||
|
qbo_invoice = find_or_create_by(id: invoice.id)
|
||||||
|
qbo_invoice.doc_number = invoice.doc_number
|
||||||
|
qbo_invoice.id = invoice.id
|
||||||
|
qbo_invoice.save!
|
||||||
|
end
|
||||||
|
|
||||||
def self.update(id)
|
def self.update(id)
|
||||||
# Update the item table
|
# Update the item table
|
||||||
invoice = get_base.service.fetch_by_id(id)
|
invoice = get_base.service.fetch_by_id(id)
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ class Vehicle < ActiveRecord::Base
|
|||||||
|
|
||||||
unloadable
|
unloadable
|
||||||
|
|
||||||
|
API_KEY = Setting.plugin_redmine_qbo['settingsEdmundsAPIKey']
|
||||||
|
|
||||||
belongs_to :customer
|
belongs_to :customer
|
||||||
has_many :issues, :foreign_key => 'vehicles_id'
|
has_many :issues, :foreign_key => 'vehicles_id'
|
||||||
|
|
||||||
@@ -91,7 +93,7 @@ class Vehicle < ActiveRecord::Base
|
|||||||
# returns the Edmunds decoder service
|
# returns the Edmunds decoder service
|
||||||
def get_decoder
|
def get_decoder
|
||||||
#TODO API Code via Settings
|
#TODO API Code via Settings
|
||||||
return decoder = Edmunds::Vin.new('2dheutzvhxs28dzukx5tgu47')
|
return decoder = Edmunds::Vin.new(API_KEY)
|
||||||
end
|
end
|
||||||
|
|
||||||
# decodes a vin and updates self
|
# decodes a vin and updates self
|
||||||
|
|||||||
@@ -10,10 +10,27 @@ The above copyright notice and this permission notice shall be included in all c
|
|||||||
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.
|
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.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
|
<!-- somewhere in your document include the Javascript -->
|
||||||
|
<script type="text/javascript" src="https://appcenter.intuit.com/Content/IA/intuit.ipp.anywhere.js"></script>
|
||||||
|
|
||||||
|
<!-- configure the Intuit object: 'grantUrl' is a URL in your application which kicks off the flow, see below -->
|
||||||
|
<script>
|
||||||
|
intuit.ipp.anywhere.setup({menuProxy: '/path/to/blue-dot', grantUrl: '<%= qbo_authenticate_url %>'});
|
||||||
|
</script>
|
||||||
|
|
||||||
<table >
|
<table >
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<th>OAuth Consumer Key</th>
|
<th>Edmunds API Key</th>
|
||||||
|
<td>
|
||||||
|
<input type="text" style="width:350px" id="settingsEdmundsAPIKey"
|
||||||
|
value="<%= settings['settingsEdmundsAPIKey'] %>"
|
||||||
|
name="settings[settingsEdmundsAPIKey]" >
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<th>Intuit QBO OAuth Consumer Key</th>
|
||||||
<td>
|
<td>
|
||||||
<input type="text" style="width:350px" id="settingsOAuthConsumerKey"
|
<input type="text" style="width:350px" id="settingsOAuthConsumerKey"
|
||||||
value="<%= settings['settingsOAuthConsumerKey'] %>"
|
value="<%= settings['settingsOAuthConsumerKey'] %>"
|
||||||
@@ -22,7 +39,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
|
|||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<th>OAuth Consumer Secret</th>
|
<th>Intuit QBO OAuth Consumer Secret</th>
|
||||||
<td>
|
<td>
|
||||||
<input type="text" style="width:350px" id="settingsOAuthConsumerSecret"
|
<input type="text" style="width:350px" id="settingsOAuthConsumerSecret"
|
||||||
value="<%= settings['settingsOAuthConsumerSecret'] %>"
|
value="<%= settings['settingsOAuthConsumerSecret'] %>"
|
||||||
@@ -30,14 +47,6 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<br/>
|
|
||||||
|
|
||||||
<table>
|
|
||||||
<tbody>
|
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<th>Token Expires At</th>
|
<th>Token Expires At</th>
|
||||||
<td><%= if Qbo.exists? then Qbo.first.token_expires_at end %>
|
<td><%= if Qbo.exists? then Qbo.first.token_expires_at end %>
|
||||||
@@ -55,4 +64,5 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
|
|||||||
Note: You need to authenticate after saving your key and secret above
|
Note: You need to authenticate after saving your key and secret above
|
||||||
<br/>
|
<br/>
|
||||||
|
|
||||||
<%= link_to "Authenticate", qbo_authenticate_path, :method => :get %>
|
<!-- this will display a button that the user clicks to start the flow -->
|
||||||
|
<ipp:connectToIntuit></ipp:connectToIntuit>
|
||||||
|
|||||||
@@ -44,6 +44,8 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td/>
|
<td/>
|
||||||
<td>
|
<td>
|
||||||
|
|
||||||
|
<%= button_to "New Issue", new_issue_path(:vehicle_id => vehicle.id, :customer_id => vehicle.customer.id), method: :get%>
|
||||||
<%= button_to "Edit", edit_vehicle_path(vehicle), method: :get%>
|
<%= button_to "Edit", edit_vehicle_path(vehicle), method: :get%>
|
||||||
<%= button_to "Delete", vehicle, method: :delete, data: {confirm: "You sure?"} %>
|
<%= button_to "Delete", vehicle, method: :delete, data: {confirm: "You sure?"} %>
|
||||||
</td>
|
</td>
|
||||||
|
|||||||
@@ -17,5 +17,8 @@ get 'qbo/oauth_callback', :to => 'qbo#oauth_callback'
|
|||||||
get 'qbo/sync', :to => 'qbo#sync'
|
get 'qbo/sync', :to => 'qbo#sync'
|
||||||
get 'qbo/estimate/:id', :to => 'estimate#show', as: :estimate
|
get 'qbo/estimate/:id', :to => 'estimate#show', as: :estimate
|
||||||
get 'qbo/invoice/:id', :to => 'invoice#show', as: :invoice
|
get 'qbo/invoice/:id', :to => 'invoice#show', as: :invoice
|
||||||
|
|
||||||
|
post 'qbo/webhook', :to => 'qbo#qbo_webhook'
|
||||||
|
|
||||||
resources :vehicles
|
resources :vehicles
|
||||||
resources :customers
|
resources :customers
|
||||||
|
|||||||
2
init.rb
2
init.rb
@@ -25,7 +25,7 @@ Redmine::Plugin.register :redmine_qbo do
|
|||||||
name 'Redmine Quickbooks Online plugin'
|
name 'Redmine Quickbooks Online plugin'
|
||||||
author 'Rick Barrette'
|
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'
|
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.0.6'
|
version '0.0.7'
|
||||||
url 'https://github.com/rickbarrette/redmine_qbo'
|
url 'https://github.com/rickbarrette/redmine_qbo'
|
||||||
author_url 'http://rickbarrette.org'
|
author_url 'http://rickbarrette.org'
|
||||||
settings :default => {'empty' => true}, :partial => 'qbo/settings'
|
settings :default => {'empty' => true}, :partial => 'qbo/settings'
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ module IssuePatch
|
|||||||
belongs_to :qbo_item, primary_key: :id
|
belongs_to :qbo_item, primary_key: :id
|
||||||
belongs_to :qbo_estimate, primary_key: :id
|
belongs_to :qbo_estimate, primary_key: :id
|
||||||
belongs_to :qbo_invoice, primary_key: :id
|
belongs_to :qbo_invoice, primary_key: :id
|
||||||
belongs_to :vehicle
|
belongs_to :vehicle, primary_key: :id
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -16,14 +16,15 @@ class IssuesFormHookListener < Redmine::Hook::ViewListener
|
|||||||
f = context[:form]
|
f = context[:form]
|
||||||
|
|
||||||
# Check to see if there is a quickbooks user attached to the issue
|
# Check to see if there is a quickbooks user attached to the issue
|
||||||
@selected_customer = context[:issue].customer ? context[:issue].customer.id : nil
|
selected_customer = context[:issue].customer ? context[:issue].customer.id : nil
|
||||||
selected_item = context[:issue].qbo_item ? context[:issue].qbo_item.id : nil
|
selected_item = context[:issue].qbo_item ? context[:issue].qbo_item.id : nil
|
||||||
selected_invoice = context[:issue].qbo_invoice ? context[:issue].qbo_invoice.id : nil
|
selected_invoice = context[:issue].qbo_invoice ? context[:issue].qbo_invoice.id : nil
|
||||||
selected_estimate = context[:issue].qbo_estimate ? context[:issue].qbo_estimate.id : nil
|
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
|
# Load customer information without callbacks
|
||||||
@customer = Customer.find_by_id(@selected_customer) if @selected_customer
|
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
|
select_customer = f.select :customer_id, Customer.all.pluck(:name, :id).sort, :selected => selected_customer, include_blank: true
|
||||||
|
|
||||||
# Generate the drop down list of quickbooks items
|
# Generate the drop down list of quickbooks items
|
||||||
select_item = f.select :qbo_item_id, QboItem.all.pluck(:name, :id).sort, :selected => selected_item, include_blank: true
|
select_item = f.select :qbo_item_id, QboItem.all.pluck(:name, :id).sort, :selected => selected_item, include_blank: true
|
||||||
@@ -34,10 +35,14 @@ class IssuesFormHookListener < Redmine::Hook::ViewListener
|
|||||||
# Generate the drop down list of quickbooks extimates
|
# 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
|
select_estimate = f.select :qbo_estimate_id, QboEstimate.all.pluck(:doc_number, :id).sort! {|x, y| y <=> x}, :selected => selected_estimate, include_blank: true
|
||||||
|
|
||||||
vehicles = @customer.vehicles.pluck(:name, :id).sort! if context[:issue].customer
|
if context[:issue].customer
|
||||||
vehicles = Vehicle.all.order(:name) if not vehicles
|
vehicles = customer.vehicles.pluck(:name, :id).sort!
|
||||||
vehicle = f.select :vehicles_id, vehicles, include_blank: true, :selected => vehicle
|
else
|
||||||
|
vehicles = Vehicle.all.order(:name).pluck(:name, :id)
|
||||||
|
end
|
||||||
|
|
||||||
return "<p>#{@select_customer}</p> <p>#{select_item}</p> <p>#{select_invoice}</p> <p>#{select_estimate}</p> <p>#{vehicle}</p>"
|
vehicle = f.select :vehicles_id, vehicles, :selected => selected_vehicle, include_blank: true
|
||||||
|
|
||||||
|
return "<p>#{select_customer}</p> <p>#{select_item}</p> <p>#{select_invoice}</p> <p>#{select_estimate}</p> <p>#{vehicle}</p>"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -55,12 +55,15 @@ class IssuesSaveHookListener < Redmine::Hook::ViewListener
|
|||||||
# Called After Issue Saved
|
# Called After Issue Saved
|
||||||
def controller_issues_edit_after_save(context={})
|
def controller_issues_edit_after_save(context={})
|
||||||
issue = context[:issue]
|
issue = context[:issue]
|
||||||
|
|
||||||
|
if issue.assigned_to
|
||||||
employee_id = issue.assigned_to.qbo_employee_id
|
employee_id = issue.assigned_to.qbo_employee_id
|
||||||
|
|
||||||
# Check to see if we have registered with QBO and if the issue is closed.
|
# Check to see if we have registered with QBO and if the issue is closed.
|
||||||
# If so then we need to create a new billable time activity for the customer
|
# If so then we need to create a new billable time activity for the customer
|
||||||
bill_time(issue, employee_id) if Qbo.first && issue.customer && issue.qbo_item && employee_id && issue.status.is_closed?
|
bill_time(issue, employee_id) if Qbo.first && issue.customer && issue.qbo_item && employee_id && issue.status.is_closed?
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# Create billable time entries
|
# Create billable time entries
|
||||||
def bill_time(issue, employee_id)
|
def bill_time(issue, employee_id)
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ class IssuesShowHookListener < Redmine::Hook::ViewListener
|
|||||||
|
|
||||||
<div class=\"vehicle_vin attribute\">
|
<div class=\"vehicle_vin attribute\">
|
||||||
<div class=\"label\"><span>VIN</span>:</div>
|
<div class=\"label\"><span>VIN</span>:</div>
|
||||||
<div class=\"value\">#{vin}</div>
|
<div class=\"value\">#{vin.gsub(/(.{9})/, '\1 ') if vin}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class=\"vehicle_notes attribute\">
|
<div class=\"vehicle_notes attribute\">
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ module IssuesPdfHelperPatch
|
|||||||
vin = v ? v.vin : nil
|
vin = v ? v.vin : nil
|
||||||
notes = v ? v.notes : nil
|
notes = v ? v.notes : nil
|
||||||
left << [l(:field_vehicles), vehicle]
|
left << [l(:field_vehicles), vehicle]
|
||||||
left << [l(:field_vin), vin]
|
left << [l(:field_vin), vin.gsub(/(.{9})/, '\1 ')]
|
||||||
#left << [l(:field_notes), notes]
|
#left << [l(:field_notes), notes]
|
||||||
|
|
||||||
right = []
|
right = []
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ class UsersShowHookListener < Redmine::Hook::ViewListener
|
|||||||
def view_users_form(context={})
|
def view_users_form(context={})
|
||||||
|
|
||||||
# Update the users
|
# Update the users
|
||||||
QboEmployee.update_all
|
#QboEmployee.update_all
|
||||||
|
|
||||||
# Check to see if there is a quickbooks user attached to the issue
|
# Check to see if there is a quickbooks user attached to the issue
|
||||||
@selected = context[:user].qbo_employee.id if context[:user].qbo_employee
|
@selected = context[:user].qbo_employee.id if context[:user].qbo_employee
|
||||||
|
|||||||
Reference in New Issue
Block a user