mirror of
https://github.com/rickbarrette/redmine_qbo.git
synced 2025-11-09 01:14:23 -05:00
Compare commits
101 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 028b309a60 | |||
| e0b07764c0 | |||
| 73dc8b3b44 | |||
| 1bc23ab553 | |||
| 5be8d987b6 | |||
| f89cdf8ab2 | |||
| d33eba2b20 | |||
| 39a2e1564f | |||
| 3070192485 | |||
| ed5959d8e0 | |||
| 79d990dd01 | |||
| b1cf8363a9 | |||
| 3d251da80b | |||
| cc9af5dc36 | |||
| 2c3503f4ac | |||
| 5104509106 | |||
| 77be0b9d4c | |||
| 897810b029 | |||
| 37371d2373 | |||
| 95fbad525d | |||
| 9ce8fa4661 | |||
| c6ac6141d9 | |||
| f25fac1190 | |||
| 49f2baed9f | |||
| 9acc33e373 | |||
| 4f6d194615 | |||
| 0308a67a86 | |||
| 7b63e64da0 | |||
| eb8e2fa018 | |||
| 62ac1bf295 | |||
| d044024981 | |||
| 65be0c5f7a | |||
| e9db63ea82 | |||
| c8107c418f | |||
| 2d96f6653b | |||
| b4833d7a5f | |||
| 12cebb1cd1 | |||
| ad4ce232b5 | |||
| 82a273c0c2 | |||
| 88b66c4b41 | |||
| e9038a56c1 | |||
| f2df6b5128 | |||
| b57d51d80a | |||
| 970a2fa681 | |||
| 3d2176c5bd | |||
| baf251e211 | |||
| def5b72aa3 | |||
| 89498c9559 | |||
| b28e9b5a5b | |||
| d529139a9f | |||
| 5155c0bc68 | |||
| 798bfde516 | |||
| d79daa7a28 | |||
| 6bcf210f79 | |||
| 7244455bf2 | |||
| e65d78bb25 | |||
| 0b74f2cf52 | |||
| 98b89e7875 | |||
| b1996aa309 | |||
| f4712ad849 | |||
| a8546934ee | |||
| a7b7db690d | |||
| 0ed61b191f | |||
| 0fb4ec1157 | |||
| d22257e8ab | |||
| e1bb565c59 | |||
| 03e1e7e0b2 | |||
| aa3fefd628 | |||
| 5e635f9e2b | |||
| 2aad7115c4 | |||
| 80ee5287a0 | |||
| 26d8d9d3e9 | |||
| f0c08e155f | |||
| afb3af18d4 | |||
| 20be533a19 | |||
| f07809eacb | |||
| d1653da540 | |||
| d9b1b45f89 | |||
| 2f85d2f56d | |||
| 430579d622 | |||
| 2357b002c6 | |||
| 191cfd5fff | |||
| eb911f195c | |||
| 98cd3d51e9 | |||
| 2365fc2cf8 | |||
| 6556197dd0 | |||
| e19688a525 | |||
| ec1c263347 | |||
| 6f194e37bd | |||
| 135850b74d | |||
| 98e94da39b | |||
| 3a4b3c0646 | |||
| ddb4f40486 | |||
| a10b075ab8 | |||
| 77448e8dc1 | |||
| cf97b341ab | |||
| 7637a6fa28 | |||
| aad4597265 | |||
| f9e271cbcb | |||
| 2ec9e43951 | |||
| c2808c7e8f |
4
Gemfile
4
Gemfile
@@ -1,7 +1,7 @@
|
|||||||
source 'https://rubygems.org'
|
source 'https://rubygems.org'
|
||||||
|
|
||||||
|
gem 'quickbooks-ruby', :git => 'https://github.com/rickbarrette/quickbooks-ruby.git'
|
||||||
gem 'quickbooks-ruby'#, :git => 'https://github.com/ruckus/quickbooks-ruby.git'
|
gem 'quickbooks-ruby-base'
|
||||||
gem 'oauth-plugin'#, '~> 0.5.1'
|
gem 'oauth-plugin'#, '~> 0.5.1'
|
||||||
gem 'oauth'
|
gem 'oauth'
|
||||||
gem 'roxml'
|
gem 'roxml'
|
||||||
|
|||||||
20
LICENSE
20
LICENSE
@@ -1,9 +1,21 @@
|
|||||||
The MIT License (MIT)
|
The MIT License (MIT)
|
||||||
|
|
||||||
Copyright (c) 2016 rick barrette
|
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:
|
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 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.
|
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.
|
||||||
|
|||||||
47
README.md
47
README.md
@@ -4,15 +4,17 @@ A simple plugin for Redmine to connect to Quickbooks Online
|
|||||||
|
|
||||||
The goal of this project is to allow redmine to connect with Quickbooks Online to create time activity entries for completed work when an issue is closed.
|
The goal of this project is to allow redmine to connect with Quickbooks Online to create time activity entries for completed work when an issue is closed.
|
||||||
|
|
||||||
|
`Note: This project is under heavy development. Currently the initial functionality goal has been meet, however I am still working on adding other features. Tags should be stable`
|
||||||
|
|
||||||
####How it works
|
####How it works
|
||||||
* A QBO customer and service item can be assigned to a redmine issue.
|
* Issues can be assigned to a QBO Customer and QBO Service Item via drop down in issues form
|
||||||
* A QBO employee can be assigned to a redmine user
|
- The `QBO Employee` for the issue is assigned via the assigned redmine user
|
||||||
* When a issue is closed, the following things happen:
|
- IF an `Issue` has been assined a `QBO Customer`, `QBO Service Item` & `QBO Employee` when an `Issue` is closed the following will happen:
|
||||||
- The plugin checks to see if the user assinged to the issue has a QBO employee assinged to them
|
- A new `QBO Time Activity` agaist the `QBO Customer` will be created using the total spent hours logged agaist an `Issue`.
|
||||||
- The plugin checks to see if the issue has a QBO customer & service item attached
|
- The rate will be the set via the `QBO Service Item` price
|
||||||
- If the above statements are true, then a new QBO Time Activity is created
|
* `Issues` with the Tracker `Quote` will generate an estimate based on the estimated hours and `QBO Service Item` cost.
|
||||||
- The total time for the Time Activity will be total spent time.
|
- Needs to have a `QBO Customer` & `QBO Service Item` Assiged
|
||||||
- The rate will be the set be the service item
|
* Users will be assigned a `QBO Employee` via a drop down in the user admistration page.
|
||||||
|
|
||||||
##Prerequisites
|
##Prerequisites
|
||||||
|
|
||||||
@@ -23,19 +25,38 @@ The goal of this project is to allow redmine to connect with Quickbooks Online t
|
|||||||
|
|
||||||
1. To install, clone this repo into your plugin folder
|
1. To install, clone this repo into your plugin folder
|
||||||
|
|
||||||
' git clone git@github.com:rickbarrette/redmine_qbo.git '
|
`git clone git@github.com:rickbarrette/redmine_qbo.git`
|
||||||
|
|
||||||
2. Migrate your database
|
2. Migrate your database
|
||||||
|
|
||||||
' rake redmine:plugins:migrate RAILS_ENV=production '
|
`rake redmine:plugins:migrate RAILS_ENV=production`
|
||||||
|
|
||||||
3. Navigate to the plugin configuration page (https://your.redmine.com/settings/plugin/redmine_qbo) and suppy your own OAuth key & secret.
|
3. Navigate to the plugin configuration page and suppy your own OAuth key & secret.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
4. After saving your key & secret, you need to click on the Authenticate link on the plugin configuration page to authenticate with QBO.
|
4. After saving your key & secret, you need to click on the Authenticate link on the plugin configuration page to authenticate with QBO.
|
||||||
|
|
||||||
5. Enjoy
|
5. Assign an Employee to each of your users via the User Administration Page
|
||||||
|
|
||||||
Note: Customers, Employees, and Service Items with automaticly update during normal usage of redmine i.e. a page refresh. You can also manualy force redmine to sync its database with QBO clicking the sync link in the Quickbooks top menu page (https://your.redmine.com/redmine/qbo)
|

|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
To enable automatic `QBO Time Activity` entries for an `Issue` , you need only to assign a `QBO Customer` and `QBO Item` to an `Issue` via drop downs in the creation/update form.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Note: Customers, Employees, and Service Items with automaticly update during normal usage of redmine i.e. a page refresh. You can also manualy force redmine to sync its database with QBO clicking the sync link in the Quickbooks top menu page
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## TODO
|
||||||
|
* Abiltiy to add line items to a ticket in a dynamic table so they can be added to the invoice upon closing of the issue
|
||||||
|
* Add a rake file to create required Trackers or statuses required
|
||||||
|
* Add link Invoice PDF to issue after creation.
|
||||||
|
* Clean up view hook code, possibly use a controller hook and reder partial views
|
||||||
|
* Add Setting for Sandbox Mode
|
||||||
|
|
||||||
##License
|
##License
|
||||||
|
|
||||||
|
|||||||
@@ -7,23 +7,16 @@
|
|||||||
#The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
#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.
|
#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 EstimateController < ApplicationController
|
||||||
class QboCustomers < ActiveRecord::Base
|
|
||||||
unloadable
|
unloadable
|
||||||
has_many :issues
|
|
||||||
attr_accessible :name
|
|
||||||
validates_presence_of :id, :name
|
|
||||||
|
|
||||||
def self.update_all
|
#
|
||||||
qbo = Qbo.first
|
# Downloads and forwards the estimate pdf
|
||||||
service = Quickbooks::Service::Customer.new(:company_id => qbo.realmId, :access_token => Qbo.get_auth_token)
|
#
|
||||||
|
def show
|
||||||
# Update the customer table
|
base = QboEstimate.get_base.service
|
||||||
service.all.each { |customer|
|
@pdf = base.pdf(base.fetch_by_id(params[:id]))
|
||||||
qbo_customer = QboCustomers.find_or_create_by(id: customer.id)
|
send_data @pdf, filename: "estimate.pdf", :disposition => 'inline', :type => "application/pdf"
|
||||||
qbo_customer.id = customer.id
|
|
||||||
qbo_customer.name = customer.display_name
|
|
||||||
qbo_customer.save!
|
|
||||||
}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
21
app/controllers/invoice_controller.rb
Normal file
21
app/controllers/invoice_controller.rb
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
#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.
|
||||||
|
class InvoiceController < ApplicationController
|
||||||
|
unloadable
|
||||||
|
|
||||||
|
#
|
||||||
|
# Downloads and forwards the invoice pdf
|
||||||
|
#
|
||||||
|
def show
|
||||||
|
base = QboInvoice.get_base.service
|
||||||
|
@pdf = base.pdf(base.fetch_by_id(params[:id]))
|
||||||
|
send_data @pdf, filename: "invoice.pdf", :disposition => 'inline', :type => "application/pdf"
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -16,12 +16,11 @@ class QboController < ApplicationController
|
|||||||
#
|
#
|
||||||
def index
|
def index
|
||||||
@qbo = Qbo.first
|
@qbo = Qbo.first
|
||||||
@qbo_customer_count = QboCustomers.count
|
@qbo_customer_count = QboCustomer.count
|
||||||
@qbo_item_count = QboItem.count
|
@qbo_item_count = QboItem.count
|
||||||
@qbo_employee_count = QboEmployee.count
|
@qbo_employee_count = QboEmployee.count
|
||||||
@selected_customer
|
@qbo_invoice_count = QboInvoice.count
|
||||||
@selected_item
|
@qbo_estimate_count = QboEstimate.count
|
||||||
@selected_employee
|
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
@@ -65,10 +64,13 @@ class QboController < ApplicationController
|
|||||||
# Synchronizes the QboCustomer table with QBO
|
# Synchronizes the QboCustomer table with QBO
|
||||||
#
|
#
|
||||||
def sync
|
def sync
|
||||||
if Qbo.exists? then
|
if Qbo.exists?
|
||||||
QboCustomers.update_all
|
QboCustomer.update_all
|
||||||
QboItem.update_all
|
QboItem.update_all
|
||||||
QboEmployee.update_all
|
QboEmployee.update_all
|
||||||
|
QboEstimate.update_all
|
||||||
|
QboInvoice.update_all
|
||||||
|
QboPurchase.update_all
|
||||||
end
|
end
|
||||||
|
|
||||||
redirect_to qbo_path(:redmine_qbo), :flash => { :notice => "Successfully synced to Quickbooks" }
|
redirect_to qbo_path(:redmine_qbo), :flash => { :notice => "Successfully synced to Quickbooks" }
|
||||||
|
|||||||
2
app/helpers/estimate_helper.rb
Normal file
2
app/helpers/estimate_helper.rb
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
module EstimateHelper
|
||||||
|
end
|
||||||
2
app/helpers/invoice_helper.rb
Normal file
2
app/helpers/invoice_helper.rb
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
module InvoiceHelper
|
||||||
|
end
|
||||||
@@ -10,11 +10,12 @@
|
|||||||
|
|
||||||
class Qbo < ActiveRecord::Base
|
class Qbo < ActiveRecord::Base
|
||||||
unloadable
|
unloadable
|
||||||
validates_presence_of :token, :secret, :realmId, :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']
|
QB_KEY = Setting.plugin_redmine_qbo['settingsOAuthConsumerKey']
|
||||||
QB_SECRET = Setting.plugin_redmine_qbo['settingsOAuthConsumerSecret']
|
QB_SECRET = Setting.plugin_redmine_qbo['settingsOAuthConsumerSecret']
|
||||||
|
|
||||||
|
# Quickbooks Config Info
|
||||||
$qb_oauth_consumer = OAuth::Consumer.new(QB_KEY, QB_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",
|
||||||
@@ -22,12 +23,21 @@ class Qbo < ActiveRecord::Base
|
|||||||
:access_token_path => "/oauth/v1/get_access_token"
|
:access_token_path => "/oauth/v1/get_access_token"
|
||||||
})
|
})
|
||||||
|
|
||||||
def self.get_auth_token
|
# Configure quickbooks-ruby-base to access our database
|
||||||
qbo = first
|
Quickbooks::Base.configure do |c|
|
||||||
return OAuth::AccessToken.new($qb_oauth_consumer, qbo.token, qbo.secret)
|
c.persistent_token = 'qb_token'
|
||||||
|
c.persistent_secret = 'qb_secret'
|
||||||
|
c.persistent_company_id = 'company_id'
|
||||||
|
end
|
||||||
|
|
||||||
|
# Get a quickbooks base object for type
|
||||||
|
# @params type of base
|
||||||
|
def self.get_base(type)
|
||||||
|
Quickbooks::Base.new(first, type)
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.get_oauth_consumer
|
# Get the QBO account
|
||||||
return $qb_oauth_consumer
|
def self.get_account
|
||||||
|
first
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
42
app/models/qbo_customer.rb
Normal file
42
app/models/qbo_customer.rb
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
#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.
|
||||||
|
|
||||||
|
class QboCustomer < ActiveRecord::Base
|
||||||
|
unloadable
|
||||||
|
has_many :issues
|
||||||
|
has_many :qbo_purchases
|
||||||
|
attr_accessible :name
|
||||||
|
validates_presence_of :id, :name
|
||||||
|
|
||||||
|
def self.get_base
|
||||||
|
Qbo.get_base(:customer)
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.get_customer (id)
|
||||||
|
get_base.service.find_by_id(id)
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.update_all
|
||||||
|
customers = get_base.service.all
|
||||||
|
|
||||||
|
transaction do
|
||||||
|
# Update the customer table
|
||||||
|
customers.each { |customer|
|
||||||
|
qbo_customer = QboCustomer.find_or_create_by(id: customer.id)
|
||||||
|
qbo_customer.name = customer.display_name
|
||||||
|
qbo_customer.id = customer.id
|
||||||
|
qbo_customer.save!
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
#remove deleted customers
|
||||||
|
where.not(customers.map(&:id)).destroy_all
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -14,16 +14,24 @@ class QboEmployee < ActiveRecord::Base
|
|||||||
attr_accessible :name
|
attr_accessible :name
|
||||||
validates_presence_of :id, :name
|
validates_presence_of :id, :name
|
||||||
|
|
||||||
def self.update_all
|
def self.get_base
|
||||||
qbo = Qbo.first
|
Qbo.get_base(:employee)
|
||||||
service = Quickbooks::Service::Employee.new(:company_id => qbo.realmId, :access_token => Qbo.get_auth_token)
|
end
|
||||||
|
|
||||||
# Update the item table
|
def self.update_all
|
||||||
service.all.each { |employee|
|
employees = get_base.service.all
|
||||||
qbo_employee = QboEmployee.find_or_create_by(id: employee.id)
|
|
||||||
qbo_employee.name = employee.display_name
|
transaction do
|
||||||
qbo_employee.id = employee.id
|
# Update the item table
|
||||||
qbo_employee.save!
|
employees.each { |employee|
|
||||||
}
|
qbo_employee = find_or_create_by(id: employee.id)
|
||||||
|
qbo_employee.name = employee.display_name
|
||||||
|
qbo_employee.id = employee.id
|
||||||
|
qbo_employee.save!
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
#remove deleted employees
|
||||||
|
where.not(employees.map(&:id)).destroy_all
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
45
app/models/qbo_estimate.rb
Normal file
45
app/models/qbo_estimate.rb
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
#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.
|
||||||
|
|
||||||
|
class QboEstimate < ActiveRecord::Base
|
||||||
|
unloadable
|
||||||
|
has_many :issues
|
||||||
|
attr_accessible :doc_number
|
||||||
|
validates_presence_of :id, :doc_number
|
||||||
|
|
||||||
|
def self.get_base
|
||||||
|
Qbo.get_base(:estimate)
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.update_all
|
||||||
|
estimates = get_base.service.all
|
||||||
|
|
||||||
|
# Update the item table
|
||||||
|
transaction do
|
||||||
|
estimates.each { |estimate|
|
||||||
|
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
|
||||||
|
|
||||||
|
#remove deleted estimates
|
||||||
|
where.not(estimates.map(&:id)).destroy_all
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.update(id)
|
||||||
|
# Update the item table
|
||||||
|
estimate = get_base.service.fetch_by_id(id)
|
||||||
|
qbo_estimate = QboEstimate.find_or_create_by(id: id)
|
||||||
|
qbo_estimate.doc_number = estimate.doc_number
|
||||||
|
qbo_estimate.save!
|
||||||
|
end
|
||||||
|
end
|
||||||
46
app/models/qbo_invoice.rb
Normal file
46
app/models/qbo_invoice.rb
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
#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.
|
||||||
|
|
||||||
|
class QboInvoice < ActiveRecord::Base
|
||||||
|
unloadable
|
||||||
|
has_many :issues
|
||||||
|
attr_accessible :doc_number
|
||||||
|
validates_presence_of :id, :doc_number
|
||||||
|
|
||||||
|
def self.get_base
|
||||||
|
Qbo.get_base(:invoice)
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.update_all
|
||||||
|
#Pull the invoices from the quickbooks server
|
||||||
|
invoices = get_base.service.all
|
||||||
|
|
||||||
|
# Update the invoice table
|
||||||
|
transaction do
|
||||||
|
invoices.each { | invoice |
|
||||||
|
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
|
||||||
|
|
||||||
|
#remove deleted invoices
|
||||||
|
where.not(invoices.map(&:id)).destroy_all
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.update(id)
|
||||||
|
# Update the item table
|
||||||
|
invoice = get_base.service.fetch_by_id(id)
|
||||||
|
qbo_invoice = find_or_create_by(id: id)
|
||||||
|
qbo_invoice.doc_number = invoice.doc_number
|
||||||
|
qbo_invoice.save!
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -14,16 +14,24 @@ class QboItem < ActiveRecord::Base
|
|||||||
attr_accessible :name
|
attr_accessible :name
|
||||||
validates_presence_of :id, :name
|
validates_presence_of :id, :name
|
||||||
|
|
||||||
def self.update_all
|
def self.get_base
|
||||||
qbo = Qbo.first
|
Qbo.get_base(:item)
|
||||||
service = Quickbooks::Service::Item.new(:company_id => qbo.realmId, :access_token => Qbo.get_auth_token)
|
end
|
||||||
|
|
||||||
# Update the item table
|
def self.update_all
|
||||||
service.find_by(:type, "Service").each { |item|
|
items = get_base.service.find_by(:type, "Service")
|
||||||
qbo_item = QboItem.find_or_create_by(id: item.id)
|
|
||||||
qbo_item.name = item.name
|
transaction do
|
||||||
qbo_item.id = item.id
|
# Update the item table
|
||||||
qbo_item.save!
|
items.each { |item|
|
||||||
}
|
qbo_item = QboItem.find_or_create_by(id: item.id)
|
||||||
|
qbo_item.name = item.name
|
||||||
|
qbo_item.id = item.id
|
||||||
|
qbo_item.save!
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
#remove deleted items
|
||||||
|
where.not(items.map(&:id)).destroy_all
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
47
app/models/qbo_purchase.rb
Normal file
47
app/models/qbo_purchase.rb
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
#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.
|
||||||
|
|
||||||
|
class QboPurchase < ActiveRecord::Base
|
||||||
|
unloadable
|
||||||
|
belongs_to :issues
|
||||||
|
belongs_to :qbo_customer
|
||||||
|
attr_accessible :description
|
||||||
|
validates_presence_of :id, :line_id, :description, :qbo_customer_id
|
||||||
|
|
||||||
|
def self.get_base
|
||||||
|
Qbo.get_base(:purchase)
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.get_purchase(id)
|
||||||
|
get_base.service.find_by_id(id)
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.update_all
|
||||||
|
QboPurchase.get_base.service.all.each { |purchase|
|
||||||
|
|
||||||
|
purchase.line_items.all? { |line_item|
|
||||||
|
|
||||||
|
detail = line_item.account_based_expense_line_detail ? line_item.account_based_expense_line_detail : line_item.item_based_expense_line_detail
|
||||||
|
|
||||||
|
if detail.billable_status = "Billable"
|
||||||
|
qbo_purchase = find_or_create_by(id: purchase.id)
|
||||||
|
qbo_purchase.line_id = line_item.id
|
||||||
|
qbo_purchase.description = line_item.description
|
||||||
|
qbo_purchase.qbo_customer_id = detail.customer_ref
|
||||||
|
|
||||||
|
#TODO attach to issues
|
||||||
|
#qbo_purchase.issue_id = Issue.find_by_invoice()
|
||||||
|
|
||||||
|
qbo_purchase.save
|
||||||
|
end
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -16,7 +16,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
|
|||||||
<div>
|
<div>
|
||||||
<%= f.label "Customer Count:"+@qbo_customer_count.to_s%>
|
<%= f.label "Customer Count:"+@qbo_customer_count.to_s%>
|
||||||
<br/>
|
<br/>
|
||||||
<%= f.select :qbo_customer_id, QboCustomers.all.pluck(:name, :id), :selected => @selected_customer, include_blank: true %>
|
<%= f.select :qbo_customer_id, QboCustomer.all.pluck(:name, :id).sort, :selected => @selected_customer, include_blank: true %>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<br/>
|
<br/>
|
||||||
@@ -24,7 +24,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
|
|||||||
<div>
|
<div>
|
||||||
<%= f.label "Item Count: "+@qbo_item_count.to_s %>
|
<%= f.label "Item Count: "+@qbo_item_count.to_s %>
|
||||||
<br/>
|
<br/>
|
||||||
<%= f.select :qbo_item_id, QboItem.all.pluck(:name, :id).reverse, :selected => @selected_item, include_blank: true %>
|
<%= f.select :qbo_item_id, QboItem.all.pluck(:name, :id).sort.reverse, :selected => @selected_item, include_blank: true %>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<br/>
|
<br/>
|
||||||
@@ -32,10 +32,23 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
|
|||||||
<div>
|
<div>
|
||||||
<%= f.label "Employee Count: "+@qbo_employee_count.to_s %>
|
<%= f.label "Employee Count: "+@qbo_employee_count.to_s %>
|
||||||
<br/>
|
<br/>
|
||||||
<%= f.select :qbo_employee_id, QboEmployee.all.pluck(:name, :id), :selected => @selected_employee, include_blank: true %>
|
<%= f.select :qbo_employee_id, QboEmployee.all.pluck(:name, :id).sort, :selected => @selected_employee, include_blank: true %>
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
|
||||||
|
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<%= f.label "Invoice Count: "+@qbo_invoice_count.to_s %>
|
||||||
|
<br/>
|
||||||
|
<%=f.select :qbo_invoice_id, QboInvoice.all.pluck(:doc_number, :id).sort! {|x, y| y <=> x}, :selected => @selected_invoice, include_blank: true%>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<%= f.label "Estimate Count: "+@qbo_estimate_count.to_s %>
|
||||||
|
<br/>
|
||||||
|
<%=f.select :qbo_estimate_id, QboEstimate.all.pluck(:doc_number, :id).sort! {|x, y| y <=> x}, :selected => @selected_estimate, include_blank: true%>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
|
||||||
|
<% end %>
|
||||||
<br/>
|
<br/>
|
||||||
<br/>
|
<br/>
|
||||||
<%= link_to "Sync", qbo_sync_path %>
|
<%= link_to "Sync", qbo_sync_path %>
|
||||||
|
|||||||
@@ -14,3 +14,5 @@ en:
|
|||||||
field_qbo_customer: "Customer"
|
field_qbo_customer: "Customer"
|
||||||
field_qbo_item: "Item"
|
field_qbo_item: "Item"
|
||||||
field_qbo_employee: "Employee"
|
field_qbo_employee: "Employee"
|
||||||
|
field_qbo_invoice: "Invoice"
|
||||||
|
field_qbo_estimate: "Estimate"
|
||||||
|
|||||||
@@ -15,4 +15,5 @@ get 'qbo', :to=> 'qbo#index'
|
|||||||
get 'qbo/authenticate', :to => 'qbo#authenticate'
|
get 'qbo/authenticate', :to => 'qbo#authenticate'
|
||||||
get 'qbo/oauth_callback', :to => 'qbo#oauth_callback'
|
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/invoice/:id', :to => 'invoice#show', as: :invoice
|
||||||
18
db/migrate/008_create_qbo_estimates.rb
Normal file
18
db/migrate/008_create_qbo_estimates.rb
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
#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.
|
||||||
|
|
||||||
|
class CreateQboEstimates < ActiveRecord::Migration
|
||||||
|
def change
|
||||||
|
create_table :qbo_estimates, id: false do |t|
|
||||||
|
t.integer :id, :options => 'PRIMARY KEY'
|
||||||
|
t.string :doc_number
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
17
db/migrate/009_update_qbos.rb
Normal file
17
db/migrate/009_update_qbos.rb
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
#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.
|
||||||
|
|
||||||
|
class UpdateQbos < ActiveRecord::Migration
|
||||||
|
def change
|
||||||
|
rename_column :qbos, :token, :qb_token
|
||||||
|
rename_column :qbos, :secret, :qb_secret
|
||||||
|
rename_column :qbos, :realmId, :company_id
|
||||||
|
end
|
||||||
|
end
|
||||||
15
db/migrate/010_update_issues_with_estimates.rb
Normal file
15
db/migrate/010_update_issues_with_estimates.rb
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
#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.
|
||||||
|
|
||||||
|
class UpdateIssuesWithEstimates < ActiveRecord::Migration
|
||||||
|
def change
|
||||||
|
add_reference :issues, :qbo_estimate, index: true
|
||||||
|
end
|
||||||
|
end
|
||||||
18
db/migrate/011_create_qbo_invoices.rb
Normal file
18
db/migrate/011_create_qbo_invoices.rb
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
#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.
|
||||||
|
|
||||||
|
class CreateQboInvoices < ActiveRecord::Migration
|
||||||
|
def change
|
||||||
|
create_table :qbo_invoices, id: false do |t|
|
||||||
|
t.integer :id, :options => 'PRIMARY KEY'
|
||||||
|
t.string :doc_number
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
15
db/migrate/012_update_issues_with_invoices.rb
Normal file
15
db/migrate/012_update_issues_with_invoices.rb
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
#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.
|
||||||
|
|
||||||
|
class UpdateIssuesWithInvoices< ActiveRecord::Migration
|
||||||
|
def change
|
||||||
|
add_reference :issues, :qbo_invoice, index: true
|
||||||
|
end
|
||||||
|
end
|
||||||
21
db/migrate/013_create_qbo_purchases.rb
Normal file
21
db/migrate/013_create_qbo_purchases.rb
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
#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.
|
||||||
|
|
||||||
|
class CreateQboPurchases< ActiveRecord::Migration
|
||||||
|
def change
|
||||||
|
create_table :qbo_purchases, id: false do |t|
|
||||||
|
t.integer :id, :options => 'PRIMARY KEY'
|
||||||
|
t.integer :line_id
|
||||||
|
t.string :description
|
||||||
|
t.integer :customer_id
|
||||||
|
t.integer :issue_id
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
15
db/migrate/014_update_customers.rb
Normal file
15
db/migrate/014_update_customers.rb
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
#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.
|
||||||
|
|
||||||
|
class UpdateCustomers < ActiveRecord::Migration
|
||||||
|
def change
|
||||||
|
add_reference :qbo_customers, :qbo_purchase, index: true
|
||||||
|
end
|
||||||
|
end
|
||||||
15
db/migrate/015_update_qbo_purchases.rb
Normal file
15
db/migrate/015_update_qbo_purchases.rb
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
#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.
|
||||||
|
|
||||||
|
class UpdateQboPurchases < ActiveRecord::Migration
|
||||||
|
def change
|
||||||
|
rename_column :qbo_purchases, :customer_id, :qbo_customer_id
|
||||||
|
end
|
||||||
|
end
|
||||||
47
init.rb
47
init.rb
@@ -10,29 +10,36 @@
|
|||||||
|
|
||||||
Redmine::Plugin.register :redmine_qbo do
|
Redmine::Plugin.register :redmine_qbo do
|
||||||
|
|
||||||
require_dependency 'issues_form_hook_listener'
|
# View Hook Listeners
|
||||||
require_dependency 'issues_save_hook_listener'
|
require_dependency 'issues_form_hook_listener'
|
||||||
require_dependency 'issues_show_hook_listener'
|
require_dependency 'issues_save_hook_listener'
|
||||||
require_dependency 'users_show_hook_listener'
|
require_dependency 'issues_show_hook_listener'
|
||||||
|
require_dependency 'users_show_hook_listener'
|
||||||
|
|
||||||
name 'Redmine Quickbooks Online plugin'
|
# Patches to the Redmine core. Will not work in development mode
|
||||||
author 'Rick Barrette'
|
require_dependency 'issue_patch'
|
||||||
description 'This is a plugin for Redmine to intergrate with Quickbooks Online to allow for seamless intergration CRM and invoicing of completed issues'
|
require_dependency 'user_patch'
|
||||||
version '0.0.2'
|
|
||||||
url 'https://github.com/rickbarrette/redmine_qbo'
|
|
||||||
author_url 'http://rickbarrette.org'
|
|
||||||
settings :default => {'empty' => true}, :partial => 'qbo/settings'
|
|
||||||
|
|
||||||
# Add safe attributes
|
name 'Redmine Quickbooks Online plugin'
|
||||||
Issue.safe_attributes 'qbo_customer_id'
|
author 'Rick Barrette'
|
||||||
Issue.safe_attributes 'qbo_item_id'
|
description 'This is a plugin for Redmine to intergrate with Quickbooks Online to allow for seamless intergration CRM and invoicing of completed issues'
|
||||||
User.safe_attributes 'qbo_employee_id'
|
version '0.0.4'
|
||||||
TimeEntry.safe_attributes 'qbo_billed'
|
url 'https://github.com/rickbarrette/redmine_qbo'
|
||||||
|
author_url 'http://rickbarrette.org'
|
||||||
|
settings :default => {'empty' => true}, :partial => 'qbo/settings'
|
||||||
|
|
||||||
# We are playing in the sandbox
|
# Add safe attributes
|
||||||
#Quickbooks.sandbox_mode = true
|
Issue.safe_attributes 'qbo_customer_id'
|
||||||
|
Issue.safe_attributes 'qbo_item_id'
|
||||||
|
Issue.safe_attributes 'qbo_estimate_id'
|
||||||
|
Issue.safe_attributes 'qbo_invoice_id'
|
||||||
|
User.safe_attributes 'qbo_employee_id'
|
||||||
|
TimeEntry.safe_attributes 'qbo_billed'
|
||||||
|
|
||||||
# Register QBO top menu item
|
# We are playing in the sandbox
|
||||||
menu :top_menu, :qbo, { :controller => 'qbo', :action => 'index' }, :caption => 'Quickbooks'
|
#Quickbooks.sandbox_mode = true
|
||||||
|
|
||||||
|
# Register QBO top menu item
|
||||||
|
menu :top_menu, :qbo, { :controller => 'qbo', :action => 'index' }, :caption => 'Quickbooks'
|
||||||
|
|
||||||
end
|
end
|
||||||
42
lib/issue_patch.rb
Normal file
42
lib/issue_patch.rb
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
#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 'issue'
|
||||||
|
|
||||||
|
# Patches Redmine's Issues dynamically.
|
||||||
|
# Adds a relationships
|
||||||
|
module IssuePatch
|
||||||
|
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
|
||||||
|
belongs_to :qbo_customer, primary_key: :id
|
||||||
|
belongs_to :qbo_item, primary_key: :id
|
||||||
|
belongs_to :qbo_estimate, primary_key: :id
|
||||||
|
belongs_to :qbo_invoice, primary_key: :id
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
module ClassMethods
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
module InstanceMethods
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
# Add module to Issue
|
||||||
|
Issue.send(:include, IssuePatch)
|
||||||
@@ -13,23 +13,32 @@ class IssuesFormHookListener < Redmine::Hook::ViewListener
|
|||||||
# Edit Issue Form
|
# Edit Issue Form
|
||||||
# Show a dropdown for quickbooks contacts
|
# Show a dropdown for quickbooks contacts
|
||||||
def view_issues_form_details_bottom(context={})
|
def view_issues_form_details_bottom(context={})
|
||||||
selected = ""
|
# Update the customer and item database
|
||||||
|
#QboCustomer.update_all
|
||||||
QboCustomers.update_all
|
#QboItem.update_all
|
||||||
QboItem.update_all
|
#QboInvoice.update_all
|
||||||
|
#QboEstimate.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
|
||||||
if not context[:issue].qbo_customer_id.nil? then
|
@selected_customer = context[:issue].qbo_customer ? context[:issue].qbo_customer.id : nil
|
||||||
selected_customer = context[:issue].qbo_customer_id
|
@selected_item = context[:issue].qbo_item ? context[:issue].qbo_item.id : nil
|
||||||
selected_item = context[:issue].qbo_item_id
|
@selected_invoice = context[:issue].qbo_invoice ? context[:issue].qbo_invoice.id : nil
|
||||||
end
|
@selected_estimate = context[:issue].qbo_estimate ? context[:issue].qbo_estimate.id : nil
|
||||||
|
|
||||||
# Generate the drop down list of quickbooks contacts
|
# Generate the drop down list of quickbooks customers
|
||||||
select_customer = context[:form].select :qbo_customer_id, QboCustomers.all.pluck(:name, :id), :selected => selected_customer, include_blank: true
|
@select_customer = context[:form].select :qbo_customer_id, QboCustomer.all.pluck(:name, :id).sort, :selected => selected_customer, include_blank: true
|
||||||
|
|
||||||
# Generate the drop down list of quickbooks contacts
|
# Generate the drop down list of quickbooks items
|
||||||
select_item = context[:form].select :qbo_item_id, QboItem.all.pluck(:name, :id).reverse, :selected => selected_item, include_blank: true
|
@select_item = context[:form].select :qbo_item_id, QboItem.all.pluck(:name, :id).sort, :selected => selected_item, include_blank: true
|
||||||
return "<p>#{select_customer}</p> <p>#{select_item}</p>"
|
|
||||||
|
# Generate the drop down list of quickbooks invoices
|
||||||
|
@select_invoice = context[:form].select :qbo_invoice_id, QboInvoice.all.pluck(:doc_number, :id).sort! {|x, y| y <=> x}, :selected => selected_invoice, include_blank: true
|
||||||
|
|
||||||
|
# Generate the drop down list of quickbooks extimates
|
||||||
|
@select_estimate = context[:form].select :qbo_estimate_id, QboEstimate.all.pluck(:doc_number, :id).sort! {|x, y| y <=> x}, :selected => selected_estimate, include_blank: true
|
||||||
|
|
||||||
|
#@estimates_link = link_to qbo_update_estimates_path
|
||||||
|
|
||||||
|
return "<p>#{@select_customer}</p> <p>#{@select_item}</p> <p>#{@select_invoice}</p> <p>#{@select_estimate} #{@estimates_link}</p>"
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
@@ -10,23 +10,72 @@
|
|||||||
|
|
||||||
class IssuesSaveHookListener < Redmine::Hook::ViewListener
|
class IssuesSaveHookListener < Redmine::Hook::ViewListener
|
||||||
|
|
||||||
# New Issue Saved
|
#Before Issue Saved
|
||||||
def controller_issues_edit_after_save(context={})
|
def controller_issues_edit_before_save(context={})
|
||||||
issue = context[:issue]
|
issue = context[:issue]
|
||||||
qbo = Qbo.first
|
|
||||||
|
|
||||||
# Check to see if we have registered with QBO
|
# Check to see if we have registered with QBO
|
||||||
if not qbo.nil? then
|
if Qbo.first && issue.qbo_customer && issue.qbo_item
|
||||||
|
|
||||||
|
# if this is a quote, lets create a new estimate based off estimated hours
|
||||||
|
if issue.tracker.name = "Quote" && issue.status.name = "New" && issue.qbo_estimate
|
||||||
|
|
||||||
|
# Get QBO Services
|
||||||
|
item_service = QboItem.get_base.service
|
||||||
|
estimate_base = QboEstimate.get_base
|
||||||
|
|
||||||
|
# Create the estimate
|
||||||
|
estimate = estimate_base.qr_model(:estimate)
|
||||||
|
estimate.customer_id = issue.qbo_customer_id
|
||||||
|
estimate.txn_date = Date.today
|
||||||
|
|
||||||
|
# Create the line item for labor
|
||||||
|
item = item_service.fetch_by_id(issue.qbo_item_id)
|
||||||
|
|
||||||
|
line_item = Quickbooks::Model::InvoiceLineItem.new
|
||||||
|
line_item.amount = item.unit_price * issue.estimated_hours
|
||||||
|
line_item.description = issue.subject
|
||||||
|
|
||||||
|
line_item.sales_item! do |detail|
|
||||||
|
detail.unit_price = item.unit_price
|
||||||
|
detail.quantity = issue.estimated_hours
|
||||||
|
detail.item_id = issue.qbo_item_id
|
||||||
|
end
|
||||||
|
|
||||||
|
# Add the line items to the estimate
|
||||||
|
estimate.line_items << line_item
|
||||||
|
|
||||||
|
# Save the etimate to the issue
|
||||||
|
#issue.qbo_estimate_id = estimate_base.service.create(estimate).id
|
||||||
|
#issue.save!
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Called After Issue Saved
|
||||||
|
def controller_issues_edit_after_save(context={})
|
||||||
|
issue = context[:issue]
|
||||||
|
employee_id = issue.assigned_to.qbo_employee_id
|
||||||
|
|
||||||
|
# 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
|
||||||
|
bill_time(issue, employee_id) if Qbo.first && issue.qbo_customer && issue.qbo_item && employee_id && issue.status.is_closed?
|
||||||
|
end
|
||||||
|
|
||||||
|
# Create billable time entries
|
||||||
|
def bill_time(issue, employee_id)
|
||||||
|
|
||||||
|
# Get unbilled time entries
|
||||||
|
spent_time = issue.time_entries.where(qbo_billed: [false, nil])
|
||||||
|
spent_hours ||= spent_time.sum(:hours) || 0
|
||||||
|
|
||||||
|
if spent_hours > 0 then
|
||||||
|
|
||||||
# Prepare to create a new Time Activity
|
# Prepare to create a new Time Activity
|
||||||
time_service = Quickbooks::Service::TimeActivity.new(:company_id => qbo.realmId, :access_token => Qbo.get_auth_token)
|
time_service = Qbo.get_base(:time_activity).service
|
||||||
item_service = Quickbooks::Service::Item.new(:company_id => qbo.realmId, :access_token => Qbo.get_auth_token)
|
item_service = Qbo.get_base(:item).service
|
||||||
time_entry = Quickbooks::Model::TimeActivity.new
|
time_entry = Quickbooks::Model::TimeActivity.new
|
||||||
|
|
||||||
# Get unbilled time entries
|
|
||||||
spent_time = issue.time_entries.where(qbo_billed: [false, nil])
|
|
||||||
spent_hours ||= spent_time.sum(:hours) || 0
|
|
||||||
|
|
||||||
# Convert float spent time to hours and minutes
|
# Convert float spent time to hours and minutes
|
||||||
hours = spent_hours.to_i
|
hours = spent_hours.to_i
|
||||||
minutesDecimal = (( spent_hours - hours) * 60)
|
minutesDecimal = (( spent_hours - hours) * 60)
|
||||||
@@ -38,26 +87,20 @@ class IssuesSaveHookListener < Redmine::Hook::ViewListener
|
|||||||
entry.save
|
entry.save
|
||||||
end
|
end
|
||||||
|
|
||||||
employee_id = User.find_by_id(issue.assigned_to_id).qbo_employee_id
|
item = item_service.fetch_by_id issue.qbo_item_id
|
||||||
|
time_entry.description = "#{issue.tracker} ##{issue.id}: #{issue.subject}"
|
||||||
# If the issue is closed, then create a new billable time activty for the customer
|
time_entry.employee_id = employee_id
|
||||||
# TODO Add configuration settings for employee_id, hourly_rate, item_id
|
time_entry.customer_id = issue.qbo_customer_id
|
||||||
if issue.status.is_closed? and not issue.qbo_customer_id.nil? and not issue.qbo_item_id.nil? and not employee_id.nil? and spent_hours > 0 then
|
time_entry.billable_status = "Billable"
|
||||||
item = item_service.fetch_by_id issue.qbo_item_id
|
time_entry.hours = hours
|
||||||
time_entry.description = "#{issue.tracker} ##{issue.id}: #{issue.subject}"
|
time_entry.minutes = minutes
|
||||||
time_entry.employee_id = employee_id
|
time_entry.name_of = "Employee"
|
||||||
time_entry.customer_id = issue.qbo_customer_id
|
time_entry.txn_date = Date.today
|
||||||
time_entry.billable_status = "Billable"
|
time_entry.hourly_rate = item.unit_price
|
||||||
time_entry.hours = hours
|
time_entry.item_id = issue.qbo_item_id
|
||||||
time_entry.minutes = minutes
|
time_entry.start_time = issue.start_date
|
||||||
time_entry.name_of = "Employee"
|
time_entry.end_time = Time.now
|
||||||
time_entry.txn_date = Date.today
|
time_service.create(time_entry)
|
||||||
time_entry.hourly_rate = item.unit_price
|
|
||||||
time_entry.item_id = issue.qbo_item_id
|
|
||||||
time_entry.start_time = issue.start_date
|
|
||||||
time_entry.end_time = Time.now
|
|
||||||
time_service.create(time_entry)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -10,31 +10,59 @@
|
|||||||
|
|
||||||
class IssuesShowHookListener < Redmine::Hook::ViewListener
|
class IssuesShowHookListener < Redmine::Hook::ViewListener
|
||||||
|
|
||||||
|
# Additional context fields
|
||||||
|
# :issue => the issue this is edited
|
||||||
|
# :f => the form object to create additional fields
|
||||||
|
#render_on :view_issues_show_details_bottom, :partial => 'hooks/redmine_qbo/_view_issues_show_details_bottom.html.erb'
|
||||||
|
|
||||||
# View Issue
|
# View Issue
|
||||||
# Display the quickbooks contact in the issue
|
# Display the quickbooks contact in the issue
|
||||||
def view_issues_show_details_bottom(context={})
|
def view_issues_show_details_bottom(context={})
|
||||||
value = ""
|
issue = context[:issue]
|
||||||
|
|
||||||
# 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
|
||||||
if not context[:issue].qbo_customer_id.nil? then
|
@customer = issue.qbo_customer ? issue.qbo_customer.name : nil
|
||||||
value = QboCustomers.find_by_id(context[:issue].qbo_customer_id).name
|
|
||||||
end
|
|
||||||
|
|
||||||
output = content_tag(:div, content_tag(:div, content_tag(:div, content_tag(:span,"Customer") + ":", class:"label") + content_tag(:div, value, class:"value") , class:"qbo_customer_id attribute"), class:"attributes")
|
|
||||||
|
|
||||||
value = ""
|
|
||||||
|
|
||||||
# Check to see if there is a quickbooks item attached to the issue
|
# Check to see if there is a quickbooks item attached to the issue
|
||||||
if not context[:issue].qbo_customer_id.nil? then
|
@item = issue.qbo_item ? issue.qbo_item.name : nil
|
||||||
if not QboItem.find_by_id(context[:issue].qbo_item_id).nil? then
|
|
||||||
value = QboItem.find_by_id(context[:issue].qbo_item_id).name
|
@estimate = nil
|
||||||
end
|
@estimate_link = nil
|
||||||
|
# Estimate Number
|
||||||
|
if issue.qbo_estimate
|
||||||
|
@estimate = issue.qbo_estimate.doc_number
|
||||||
|
@estimate_link = link_to @estimate, "#{Redmine::Utils::relative_url_root }/qbo/estimate/#{issue.qbo_estimate.id}", :target => "_blank"
|
||||||
end
|
end
|
||||||
|
|
||||||
output << content_tag(:div, content_tag(:div, content_tag(:div, content_tag(:span,"Item") + ":", class:"label") + content_tag(:div, value, class:"value") , class:"qbo_item_id attribute"), class:"attributes")
|
@invoice = nil
|
||||||
|
@invo = nil
|
||||||
|
# Invoice Number
|
||||||
|
if issue.qbo_invoice
|
||||||
|
@invoice = issue.qbo_invoice.doc_number
|
||||||
|
@invoice_link = link_to @invoice, "#{Redmine::Utils::relative_url_root }/qbo/invoice/#{issue.qbo_invoice.id}", :target => "_blank"
|
||||||
|
end
|
||||||
|
|
||||||
# Display the Customers name in the Issue attributes
|
return "<div class=\"attributes\">
|
||||||
return output
|
<div class=\"qbo_customer_id attribute\">
|
||||||
|
<div class=\"label\"><span>Customer</span>:</div>
|
||||||
|
<div class=\"value\">#{@customer}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class=\"qbo_item_id attribute\">
|
||||||
|
<div class=\"label\"><span>Item</span>:</div>
|
||||||
|
<div class=\"value\">#{@item}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class=\"qbo_estimate_id attribute\">
|
||||||
|
<div class=\"label\"><span>Estimate</span>:</div>
|
||||||
|
<div class=\"value\">#{@estimate_link}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class=\"qbo_invoice_id attribute\">
|
||||||
|
<div class=\"label\"><span>Invoice</span>:</div>
|
||||||
|
<div class=\"value\">#{@invoice_link}</div>
|
||||||
|
</div>
|
||||||
|
</div>"
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
39
lib/user_patch.rb
Normal file
39
lib/user_patch.rb
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
#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 'user'
|
||||||
|
|
||||||
|
# Patches Redmine's User dynamically.
|
||||||
|
# Adds a relationships
|
||||||
|
module UserPatch
|
||||||
|
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
|
||||||
|
belongs_to :qbo_employee, primary_key: :id
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
module ClassMethods
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
module InstanceMethods
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
# Add module to Issue
|
||||||
|
User.send(:include, UserPatch)
|
||||||
@@ -12,16 +12,14 @@ class UsersShowHookListener < Redmine::Hook::ViewListener
|
|||||||
|
|
||||||
# View User
|
# View User
|
||||||
def view_users_form(context={})
|
def view_users_form(context={})
|
||||||
selected = ""
|
|
||||||
|
|
||||||
|
# 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
|
||||||
if not context[:user].qbo_employee_id.nil? then
|
@selected = context[:user].qbo_employee.id if context[:user].qbo_employee
|
||||||
selected = context[:user].qbo_employee_id
|
|
||||||
end
|
|
||||||
|
|
||||||
# Generate the drop down list of quickbooks contacts
|
# Generate the drop down list of quickbooks contacts
|
||||||
return "<p>#{context[:form].select :qbo_employee_id, QboEmployee.all.pluck(:name, :id), :selected => selected, include_blank: true}</p>"
|
return "<p>#{context[:form].select :qbo_employee_id, QboEmployee.all.pluck(:name, :id), :selected => @selected, include_blank: true}</p>"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
8
test/functional/estimate_controller_test.rb
Normal file
8
test/functional/estimate_controller_test.rb
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
require File.expand_path('../../test_helper', __FILE__)
|
||||||
|
|
||||||
|
class EstimateControllerTest < ActionController::TestCase
|
||||||
|
# Replace this with your real tests.
|
||||||
|
def test_truth
|
||||||
|
assert true
|
||||||
|
end
|
||||||
|
end
|
||||||
8
test/functional/invoice_controller_test.rb
Normal file
8
test/functional/invoice_controller_test.rb
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
require File.expand_path('../../test_helper', __FILE__)
|
||||||
|
|
||||||
|
class InvoiceControllerTest < ActionController::TestCase
|
||||||
|
# Replace this with your real tests.
|
||||||
|
def test_truth
|
||||||
|
assert true
|
||||||
|
end
|
||||||
|
end
|
||||||
Reference in New Issue
Block a user