diff --git a/Gemfile b/Gemfile index 6b47f65..d2363ce 100644 --- a/Gemfile +++ b/Gemfile @@ -3,3 +3,6 @@ source 'https://rubygems.org' gem 'quickbooks-ruby'#, :git => 'https://github.com/ruckus/quickbooks-ruby.git' gem 'oauth-plugin'#, '~> 0.5.1' +gem 'oauth' +gem 'roxml' +gem 'nokogiri' diff --git a/app/controllers/qbo_controller.rb b/app/controllers/qbo_controller.rb index b9c7754..ac2712e 100644 --- a/app/controllers/qbo_controller.rb +++ b/app/controllers/qbo_controller.rb @@ -11,20 +11,24 @@ class QboController < ApplicationController unloadable + # Load OAuth Token QB_KEY = Setting.plugin_redmine_qbo['settingsOAuthConsumerKey'] QB_SECRET = Setting.plugin_redmine_qbo['settingsOAuthConsumerSecret'] $qb_oauth_consumer = OAuth::Consumer.new(QB_KEY, QB_SECRET, { - :site => "https://oauth.intuit.com", - :request_token_path => "/oauth/v1/get_request_token", - :authorize_url => "https://appcenter.intuit.com/Connect/Begin", - :access_token_path => "/oauth/v1/get_access_token" - }) - + :site => "https://oauth.intuit.com", + :request_token_path => "/oauth/v1/get_request_token", + :authorize_url => "https://appcenter.intuit.com/Connect/Begin", + :access_token_path => "/oauth/v1/get_access_token" + }) + def index end + # + # Called when the user requests that Redmine to connect to QBO + # def authenticate callback = "https://rickbarrette.org/redmine/oauth_callback" token = $qb_oauth_consumer.get_request_token(:oauth_callback => callback) @@ -32,6 +36,9 @@ class QboController < ApplicationController redirect_to("https://appcenter.intuit.com/Connect/Begin?oauth_token=#{token.token}") and return end + # + # Called by QBO after authentication has been processed + # def oauth_callback at = session[:qb_request_token].get_access_token(:oauth_verifier => params[:oauth_verifier]) token = at.token @@ -40,7 +47,8 @@ class QboController < ApplicationController #There can only be one... Qbo.destroy_all - + + # Save the authentication information qbo = Qbo.new qbo.token = token qbo.secret = secret @@ -55,6 +63,9 @@ class QboController < ApplicationController end + # + # Synchronizes the QboCustomer table with QBO + # def sync if Qbo.exists? then qbo = Qbo.first diff --git a/lib/qbo_hook_listener.rb b/lib/qbo_hook_listener.rb index b4aa5e2..7e1cb3f 100644 --- a/lib/qbo_hook_listener.rb +++ b/lib/qbo_hook_listener.rb @@ -9,7 +9,7 @@ #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. class QboHookListener < Redmine::Hook::ViewListener - + # Edit Issue Form # Show a dropdown for quickbooks contacts def view_issues_form_details_bottom(context={}) @@ -23,8 +23,6 @@ class QboHookListener < Redmine::Hook::ViewListener # Generate the drop down list of quickbooks contacts select = context[:form].select :qbo_customer_id, QboCustomers.all.pluck(:name, :id), :selected => selected, include_blank: true return "
#{select}
" - - #TODO save selection to Issues.qbp_customer_id end # View Issue @@ -42,14 +40,48 @@ class QboHookListener < Redmine::Hook::ViewListener end # New Issue Saved - def controller_issues_new_after_save(context={}) - issue = context[:issue] - #TODO check if closed then create new quickbooks billable time entery - end + def controller_issues_edit_after_save(context={}) + issue = context[:issue] + qbo = Qbo.first - # Existing Issue updated - def controller_issues_edit_after_save (context={}) - issue = context[:issue] - #TODO check if closed then create new quickbooks billable time entery - end + qb_oauth_consumer = OAuth::Consumer.new(Setting.plugin_redmine_qbo['settingsOAuthConsumerKey'], Setting.plugin_redmine_qbo['settingsOAuthConsumerSecret'], { + :site => "https://oauth.intuit.com", + :request_token_path => "/oauth/v1/get_request_token", + :authorize_url => "https://appcenter.intuit.com/Connect/Begin", + :access_token_path => "/oauth/v1/get_access_token" + }) + + # Check to see if we have registered with QBO + if not qbo.nil? then + # Connect to QBO + oauth_client = OAuth::AccessToken.new(qb_oauth_consumer, qbo.token, qbo.secret) + + # Prepare to create a new Time Activity + time_service = Quickbooks::Service::TimeActivity.new(:company_id => qbo.realmId, :access_token => oauth_client) + time_entry = Quickbooks::Model::TimeActivity.new + + # Convert float spent time to hours and minutes + hours = issue.spent_hours.to_i + minutesDecimal = (( issue.spent_hours - hours) * 60) + minutes = minutesDecimal.to_i + + # If the issue is closed, then create a new billable time activty for the customer + # TODO Add configuration settings for employee_id, hourly_rate, item_id + if issue.status.is_closed? then + time_entry.description = issue.subject + time_entry.employee_id = 59 + time_entry.customer_id = issue.qbo_customer_id + time_entry.billable_status = "Billable" + time_entry.hours = hours + time_entry.minutes = minutes + time_entry.name_of = "Employee" + time_entry.txn_date = Date.today + time_entry.hourly_rate = 50 + time_entry.item_id = 19 + time_entry.start_time = issue.start_date + time_entry.end_time = Time.now + time_service.create(time_entry) + end + end + end end