101 Commits
0.0.2 ... 0.0.4

Author SHA1 Message Date
028b309a60 0.0.4
Version Bump
2016-04-01 06:39:04 -04:00
e0b07764c0 Update qbo_customer.rb
Removed delete all
2016-04-01 06:37:30 -04:00
73dc8b3b44 Merge branch 'import' 2016-04-01 06:35:02 -04:00
1bc23ab553 Fixed import errors 2016-03-31 09:22:04 -04:00
5be8d987b6 Update qbo_estimate.rb
Added Transaction
2016-03-31 09:10:41 -04:00
f89cdf8ab2 Update qbo_employee.rb
Added Transaction
2016-03-31 09:09:52 -04:00
d33eba2b20 Update qbo_customer.rb
Added Transaction
2016-03-31 09:08:56 -04:00
39a2e1564f Update qbo_invoice.rb
Added Transaction
2016-03-31 09:07:30 -04:00
3070192485 Update qbo_item.rb
Formatting
2016-03-31 09:05:38 -04:00
ed5959d8e0 Added transaction to items 2016-03-31 09:05:04 -04:00
79d990dd01 Added Sorting to drop downs 2016-03-31 09:02:54 -04:00
b1cf8363a9 Update issues_form_hook_listener.rb
Sort the options!
2016-03-29 09:19:39 -04:00
3d251da80b Update index.html.erb
Sort the options!
2016-03-29 09:18:50 -04:00
cc9af5dc36 Added more garbage collection & removed automatic sync from show hook 2016-03-10 21:00:54 -05:00
2c3503f4ac Added garbage colllection for instance variables 2016-03-10 20:38:15 -05:00
5104509106 Update qbo_estimate.rb
Fixed ID
2016-03-10 12:29:21 -05:00
77be0b9d4c Update qbo_item.rb
Fixed ID
2016-03-10 12:28:18 -05:00
897810b029 Update qbo_customer.rb
Fixed ID
2016-03-10 12:27:43 -05:00
37371d2373 Update qbo_employee.rb
Fixed ID
2016-03-10 12:27:16 -05:00
95fbad525d Update qbo_invoice.rb
Fixed id
2016-03-10 12:26:35 -05:00
9ce8fa4661 Update issues_form_hook_listener.rb
Remove automatic sync of items.
2016-03-10 12:24:42 -05:00
c6ac6141d9 Update qbo_item.rb 2016-03-10 12:23:28 -05:00
f25fac1190 Update qbo_estimate.rb 2016-03-10 12:21:49 -05:00
49f2baed9f Update qbo_employee.rb
Fixed noob mistake
2016-03-10 12:20:34 -05:00
9acc33e373 Update qbo_employee.rb
Fixed removal of customers
2016-03-10 12:19:17 -05:00
4f6d194615 Fixed bug where the selected drop down items were not instance variables 2016-03-02 21:43:07 -05:00
0308a67a86 Simplified all quickbooks inporting
no more loops
2016-03-02 21:11:38 -05:00
7b63e64da0 Update qbo_invoice.rb
Loose the loop!
2016-03-02 14:43:22 -05:00
eb8e2fa018 Update qbo_invoice.rb
Added a block to find_or_create_by to succinctly update doc_number
2016-02-29 11:43:10 -05:00
62ac1bf295 Update qbo_estimate.rb
Fixed Loop
2016-02-29 09:42:51 -05:00
d044024981 Update qbo_item.rb
Removed all call
2016-02-29 09:41:48 -05:00
65be0c5f7a Update qbo_item.rb
Simplified Item Deletion
2016-02-29 09:39:33 -05:00
e9db63ea82 Update qbo_estimate.rb
Simplified Estimate Deletion
2016-02-29 09:37:24 -05:00
c8107c418f Update qbo_employee.rb
Simplified Employee Deletion
2016-02-29 09:36:22 -05:00
2d96f6653b Update qbo_customer.rb
Simplified Customer Deletion
2016-02-29 09:33:43 -05:00
b4833d7a5f Fixed destroy call 2016-02-29 09:27:37 -05:00
12cebb1cd1 Update qbo_invoice.rb 2016-02-29 09:15:11 -05:00
ad4ce232b5 Added removal for deleted entery while syncing
Added Invoices & Estimates to QBO#Index
2016-02-28 12:07:58 -05:00
82a273c0c2 Merge branch 'billable-purchases' 2016-02-25 22:53:46 -05:00
88b66c4b41 Fixed Estiamte & Invoice Link
Added Estimate Drop down
Disabled Automatic Estimate Creation
Added Controllers for Estimates & Invoices
2016-02-25 22:51:38 -05:00
e9038a56c1 Updated locale with Estimate 2016-02-25 20:54:20 -05:00
f2df6b5128 Update qbo_purchase.rb
Updated to use qbo_customer_id
2016-01-27 14:33:27 -05:00
b57d51d80a Create 015_update_qbo_purchases.rb 2016-01-27 14:32:44 -05:00
970a2fa681 Update qbo_purchase.rb
Simplified line item detail logic...

untested
2016-01-27 14:14:31 -05:00
3d2176c5bd Update qbo_purchase.rb
WIP Fixing Purchase Sync Methods
2016-01-27 12:42:56 -05:00
baf251e211 Update qbo_purchase.rb
Fixed Typo
2016-01-27 12:33:32 -05:00
def5b72aa3 Update qbo_customer.rb
Added a separate has_many line for purchases
2016-01-27 12:32:18 -05:00
89498c9559 Update qbo_purchase.rb
Added seprate belongs_to line for customer
2016-01-27 12:31:33 -05:00
b28e9b5a5b Update qbo_purchase.rb
Fixed typo for QBO Customer
2016-01-27 12:29:10 -05:00
d529139a9f Update qbo_customer.rb 2016-01-27 09:52:04 -05:00
5155c0bc68 Create 014_update_customers.rb
Added reference to customers for purchases
2016-01-27 09:31:51 -05:00
798bfde516 Update qbo_controller.rb
Added Purchases to sync
2016-01-27 09:21:28 -05:00
d79daa7a28 Fixed migration for purchases 2016-01-26 12:32:49 -05:00
6bcf210f79 Create 013_create_qbo_purchases.rb 2016-01-26 12:24:48 -05:00
7244455bf2 Update README.md
Better Documentation!
2016-01-26 04:42:14 -05:00
e65d78bb25 Create qbo_purchase.rb
Initial & untested commit for billable-purchases.

TODO:
Create database table
Add relationships
Attach to Issues
2016-01-25 12:31:26 -05:00
0b74f2cf52 Added Invoice Support 2016-01-24 18:54:34 -05:00
98b89e7875 Added Patch to Users to add releation ship for Users to Employees 2016-01-24 17:35:07 -05:00
b1996aa309 Update users_show_hook_listener.rb
Cleaned up nil checks
2016-01-22 05:43:06 -05:00
f4712ad849 Update issues_show_hook_listener.rb
Cleaned up nil checks
2016-01-22 05:38:31 -05:00
a8546934ee Cleaned up issue save hook 2016-01-22 05:22:09 -05:00
a7b7db690d Fixed Issue Save Hook 2016-01-22 04:08:21 -05:00
0ed61b191f Update issues_save_hook_listener.rb
Removed un-needed code, and added parenthesis on line 33
2016-01-21 13:37:30 -05:00
0fb4ec1157 Update issues_save_hook_listener.rb
Fixed conventions, Removed explicit non-nil checks, updated comments
2016-01-21 13:27:08 -05:00
d22257e8ab Update issues_form_hook_listener.rb
Fixed conventions, Removed explicit non-nil checks
2016-01-21 13:09:49 -05:00
e1bb565c59 Update qbo_controller.rb
Updating to the following conventions
https://github.com/bbatsov/ruby-style-guide
2016-01-21 12:19:13 -05:00
03e1e7e0b2 Update users_show_hook_listener.rb
Updating to the following conventions
https://github.com/bbatsov/ruby-style-guide
2016-01-21 12:15:20 -05:00
aa3fefd628 Update issues_show_hook_listener.rb
Updating to the following conventions
https://github.com/bbatsov/ruby-style-guide
2016-01-21 12:13:00 -05:00
5e635f9e2b Update issues_form_hook_listener.rb
Updating to the following conventions
https://github.com/bbatsov/ruby-style-guide
2016-01-21 12:09:40 -05:00
2aad7115c4 Update issues_save_hook_listener.rb
Updating to the following conventions
https://github.com/bbatsov/ruby-style-guide
2016-01-21 12:07:36 -05:00
80ee5287a0 Update README.md 2016-01-21 09:52:37 -05:00
26d8d9d3e9 Update README.md 2016-01-21 09:49:29 -05:00
f0c08e155f Update LICENSE
Formating
2016-01-21 06:08:55 -05:00
afb3af18d4 Update README.md 2016-01-20 12:46:24 -05:00
20be533a19 Update issues_save_hook_listener.rb
to ues Qbo.get_base
2016-01-20 12:21:08 -05:00
f07809eacb Update qbo_employee.rb 2016-01-20 12:16:51 -05:00
d1653da540 Update qbo_estimate.rb
to use Qbo.get_base
2016-01-20 12:16:15 -05:00
d9b1b45f89 Update qbo_item.rb
to use Qbo.get_base
2016-01-20 12:15:42 -05:00
2f85d2f56d Updated QBO Customer touse Qbo.get_base 2016-01-20 12:13:44 -05:00
430579d622 Removed nil check 2016-01-20 12:12:37 -05:00
2357b002c6 Update qbo.rb
Added get_base convenience method
2016-01-20 06:39:42 -05:00
191cfd5fff Fixed issue hooks 2016-01-20 06:27:26 -05:00
eb911f195c Removed unneeded code 2016-01-17 10:45:18 -05:00
98cd3d51e9 Estimate PDF is now dowloaded and served
TODO: The routes are somehow messed up and need to be fixed.

example: example.com/redmine/redmine/qbo/estimate/1
in lieu: example.com/redmine/qbo/estimate/1
2016-01-17 10:40:37 -05:00
2365fc2cf8 Corrected get_base to use :customer 2016-01-15 14:26:24 -05:00
6556197dd0 Readded nil checks 2016-01-14 21:49:26 -05:00
e19688a525 Fixed QBO#Index 2016-01-13 21:00:15 -05:00
ec1c263347 Added relationship to issues, renamed qbp_customer, started cleaning up
listeners
2016-01-13 20:37:02 -05:00
6f194e37bd Cleaned up the show_issue hook 2016-01-12 22:39:45 -05:00
135850b74d Estimates are now attached to issues and displayed on the issue 2016-01-12 21:45:56 -05:00
98e94da39b Added qbo_estimate_id to issues safe attribute list 2016-01-12 21:08:04 -05:00
3a4b3c0646 Added qbo_estimate to issues 2016-01-12 21:00:57 -05:00
ddb4f40486 Updated to quickbooks-ruby-base and added QboEstimate 2016-01-12 20:55:56 -05:00
a10b075ab8 Rename columns of QBO table 2016-01-12 20:55:00 -05:00
77448e8dc1 Create table qbo_estimates 2016-01-12 19:40:20 -05:00
cf97b341ab Updated Gemfile to work off my branch 2016-01-12 19:39:30 -05:00
7637a6fa28 Updated Gemfile to use my copy of quickbooks-ruby
Also Added quickbooks-ruby-base
2016-01-12 19:01:33 -05:00
aad4597265 Removed unneeded Code & Fixed Estimate Field Check 2016-01-11 23:37:01 -05:00
f9e271cbcb Added sanity checks for QBO info 2016-01-11 23:24:35 -05:00
2ec9e43951 Added estimate generation capability
TODO: check to see if we can get the PDF link
2016-01-11 23:20:27 -05:00
c2808c7e8f Broke billing of time into a seprate method 2016-01-11 22:18:40 -05:00
35 changed files with 762 additions and 171 deletions

View File

@@ -1,7 +1,7 @@
source 'https://rubygems.org'
gem 'quickbooks-ruby'#, :git => 'https://github.com/ruckus/quickbooks-ruby.git'
gem 'quickbooks-ruby', :git => 'https://github.com/rickbarrette/quickbooks-ruby.git'
gem 'quickbooks-ruby-base'
gem 'oauth-plugin'#, '~> 0.5.1'
gem 'oauth'
gem 'roxml'

20
LICENSE
View File

@@ -1,9 +1,21 @@
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.

View File

@@ -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.
`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
* A QBO customer and service item can be assigned to a redmine issue.
* A QBO employee can be assigned to a redmine user
* When a issue is closed, the following things happen:
- The plugin checks to see if the user assinged to the issue has a QBO employee assinged to them
- The plugin checks to see if the issue has a QBO customer & service item attached
- If the above statements are true, then a new QBO Time Activity is created
- The total time for the Time Activity will be total spent time.
- The rate will be the set be the service item
* Issues can be assigned to a QBO Customer and QBO Service Item via drop down in issues form
- The `QBO Employee` for the issue is assigned via the assigned redmine user
- IF an `Issue` has been assined a `QBO Customer`, `QBO Service Item` & `QBO Employee` when an `Issue` is closed the following will happen:
- A new `QBO Time Activity` agaist the `QBO Customer` will be created using the total spent hours logged agaist an `Issue`.
- The rate will be the set via the `QBO Service Item` price
* `Issues` with the Tracker `Quote` will generate an estimate based on the estimated hours and `QBO Service Item` cost.
- Needs to have a `QBO Customer` & `QBO Service Item` Assiged
* Users will be assigned a `QBO Employee` via a drop down in the user admistration page.
##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
' git clone git@github.com:rickbarrette/redmine_qbo.git '
`git clone git@github.com:rickbarrette/redmine_qbo.git`
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.
![Alt plugin_config](/Screenshots/plugin_config.png)
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)
![Alt plugin_user_edit](/Screenshots/plugin_user_edit.png)
## 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.
![Alt plugin_issue-edit](/Screenshots/plugin_issue_edit.png)
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
![Alt plugin_top_menu](/Screenshots/plugin_top_menu.png)
## 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

View File

@@ -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 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 QboCustomers < ActiveRecord::Base
class EstimateController < ApplicationController
unloadable
has_many :issues
attr_accessible :name
validates_presence_of :id, :name
def self.update_all
qbo = Qbo.first
service = Quickbooks::Service::Customer.new(:company_id => qbo.realmId, :access_token => Qbo.get_auth_token)
# Update the customer table
service.all.each { |customer|
qbo_customer = QboCustomers.find_or_create_by(id: customer.id)
qbo_customer.id = customer.id
qbo_customer.name = customer.display_name
qbo_customer.save!
}
#
# Downloads and forwards the estimate pdf
#
def show
base = QboEstimate.get_base.service
@pdf = base.pdf(base.fetch_by_id(params[:id]))
send_data @pdf, filename: "estimate.pdf", :disposition => 'inline', :type => "application/pdf"
end
end

View 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

View File

@@ -16,12 +16,11 @@ class QboController < ApplicationController
#
def index
@qbo = Qbo.first
@qbo_customer_count = QboCustomers.count
@qbo_customer_count = QboCustomer.count
@qbo_item_count = QboItem.count
@qbo_employee_count = QboEmployee.count
@selected_customer
@selected_item
@selected_employee
@qbo_invoice_count = QboInvoice.count
@qbo_estimate_count = QboEstimate.count
end
#
@@ -65,10 +64,13 @@ class QboController < ApplicationController
# Synchronizes the QboCustomer table with QBO
#
def sync
if Qbo.exists? then
QboCustomers.update_all
if Qbo.exists?
QboCustomer.update_all
QboItem.update_all
QboEmployee.update_all
QboEstimate.update_all
QboInvoice.update_all
QboPurchase.update_all
end
redirect_to qbo_path(:redmine_qbo), :flash => { :notice => "Successfully synced to Quickbooks" }

View File

@@ -0,0 +1,2 @@
module EstimateHelper
end

View File

@@ -0,0 +1,2 @@
module InvoiceHelper
end

View File

@@ -10,11 +10,12 @@
class Qbo < ActiveRecord::Base
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_SECRET = Setting.plugin_redmine_qbo['settingsOAuthConsumerSecret']
# Quickbooks Config Info
$qb_oauth_consumer = OAuth::Consumer.new(QB_KEY, QB_SECRET, {
:site => "https://oauth.intuit.com",
:request_token_path => "/oauth/v1/get_request_token",
@@ -22,12 +23,21 @@ class Qbo < ActiveRecord::Base
:access_token_path => "/oauth/v1/get_access_token"
})
def self.get_auth_token
qbo = first
return OAuth::AccessToken.new($qb_oauth_consumer, qbo.token, qbo.secret)
# Configure quickbooks-ruby-base to access our database
Quickbooks::Base.configure do |c|
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
def self.get_oauth_consumer
return $qb_oauth_consumer
# Get the QBO account
def self.get_account
first
end
end

View 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

View File

@@ -14,16 +14,24 @@ class QboEmployee < ActiveRecord::Base
attr_accessible :name
validates_presence_of :id, :name
def self.update_all
qbo = Qbo.first
service = Quickbooks::Service::Employee.new(:company_id => qbo.realmId, :access_token => Qbo.get_auth_token)
def self.get_base
Qbo.get_base(:employee)
end
# Update the item table
service.all.each { |employee|
qbo_employee = QboEmployee.find_or_create_by(id: employee.id)
qbo_employee.name = employee.display_name
qbo_employee.id = employee.id
qbo_employee.save!
}
def self.update_all
employees = get_base.service.all
transaction do
# Update the item table
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

View 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
View 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

View File

@@ -14,16 +14,24 @@ class QboItem < ActiveRecord::Base
attr_accessible :name
validates_presence_of :id, :name
def self.update_all
qbo = Qbo.first
service = Quickbooks::Service::Item.new(:company_id => qbo.realmId, :access_token => Qbo.get_auth_token)
def self.get_base
Qbo.get_base(:item)
end
# Update the item table
service.find_by(:type, "Service").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!
}
def self.update_all
items = get_base.service.find_by(:type, "Service")
transaction do
# Update the item table
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

View 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

View File

@@ -16,7 +16,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
<div>
<%= f.label "Customer Count:"+@qbo_customer_count.to_s%>
<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>
<br/>
@@ -24,7 +24,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
<div>
<%= f.label "Item Count: "+@qbo_item_count.to_s %>
<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>
<br/>
@@ -32,10 +32,23 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
<div>
<%= f.label "Employee Count: "+@qbo_employee_count.to_s %>
<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>
<% 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/>
<%= link_to "Sync", qbo_sync_path %>

View File

@@ -14,3 +14,5 @@ en:
field_qbo_customer: "Customer"
field_qbo_item: "Item"
field_qbo_employee: "Employee"
field_qbo_invoice: "Invoice"
field_qbo_estimate: "Estimate"

View File

@@ -15,4 +15,5 @@ get 'qbo', :to=> 'qbo#index'
get 'qbo/authenticate', :to => 'qbo#authenticate'
get 'qbo/oauth_callback', :to => 'qbo#oauth_callback'
get 'qbo/sync', :to => 'qbo#sync'
get 'qbo/estimate/:id', :to => 'estimate#show', as: :estimate
get 'qbo/invoice/:id', :to => 'invoice#show', as: :invoice

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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
View File

@@ -10,29 +10,36 @@
Redmine::Plugin.register :redmine_qbo do
require_dependency 'issues_form_hook_listener'
require_dependency 'issues_save_hook_listener'
require_dependency 'issues_show_hook_listener'
require_dependency 'users_show_hook_listener'
# View Hook Listeners
require_dependency 'issues_form_hook_listener'
require_dependency 'issues_save_hook_listener'
require_dependency 'issues_show_hook_listener'
require_dependency 'users_show_hook_listener'
name 'Redmine Quickbooks Online plugin'
author 'Rick Barrette'
description 'This is a plugin for Redmine to intergrate with Quickbooks Online to allow for seamless intergration CRM and invoicing of completed issues'
version '0.0.2'
url 'https://github.com/rickbarrette/redmine_qbo'
author_url 'http://rickbarrette.org'
settings :default => {'empty' => true}, :partial => 'qbo/settings'
# Patches to the Redmine core. Will not work in development mode
require_dependency 'issue_patch'
require_dependency 'user_patch'
# Add safe attributes
Issue.safe_attributes 'qbo_customer_id'
Issue.safe_attributes 'qbo_item_id'
User.safe_attributes 'qbo_employee_id'
TimeEntry.safe_attributes 'qbo_billed'
name 'Redmine Quickbooks Online plugin'
author 'Rick Barrette'
description 'This is a plugin for Redmine to intergrate with Quickbooks Online to allow for seamless intergration CRM and invoicing of completed issues'
version '0.0.4'
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
#Quickbooks.sandbox_mode = true
# Add safe attributes
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
menu :top_menu, :qbo, { :controller => 'qbo', :action => 'index' }, :caption => 'Quickbooks'
# We are playing in the sandbox
#Quickbooks.sandbox_mode = true
# Register QBO top menu item
menu :top_menu, :qbo, { :controller => 'qbo', :action => 'index' }, :caption => 'Quickbooks'
end

42
lib/issue_patch.rb Normal file
View 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)

View File

@@ -13,23 +13,32 @@ class IssuesFormHookListener < Redmine::Hook::ViewListener
# Edit Issue Form
# Show a dropdown for quickbooks contacts
def view_issues_form_details_bottom(context={})
selected = ""
QboCustomers.update_all
QboItem.update_all
# Update the customer and item database
#QboCustomer.update_all
#QboItem.update_all
#QboInvoice.update_all
#QboEstimate.update_all
# 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_id
selected_item = context[:issue].qbo_item_id
end
@selected_customer = context[:issue].qbo_customer ? context[:issue].qbo_customer.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_estimate = context[:issue].qbo_estimate ? context[:issue].qbo_estimate.id : nil
# Generate the drop down list of quickbooks contacts
select_customer = context[:form].select :qbo_customer_id, QboCustomers.all.pluck(:name, :id), :selected => selected_customer, include_blank: true
# Generate the drop down list of quickbooks customers
@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
select_item = context[:form].select :qbo_item_id, QboItem.all.pluck(:name, :id).reverse, :selected => selected_item, include_blank: true
return "<p>#{select_customer}</p> <p>#{select_item}</p>"
# Generate the drop down list of quickbooks items
@select_item = context[:form].select :qbo_item_id, QboItem.all.pluck(:name, :id).sort, :selected => selected_item, include_blank: true
# 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

View File

@@ -10,23 +10,72 @@
class IssuesSaveHookListener < Redmine::Hook::ViewListener
# New Issue Saved
def controller_issues_edit_after_save(context={})
#Before Issue Saved
def controller_issues_edit_before_save(context={})
issue = context[:issue]
qbo = Qbo.first
# 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
time_service = Quickbooks::Service::TimeActivity.new(:company_id => qbo.realmId, :access_token => Qbo.get_auth_token)
item_service = Quickbooks::Service::Item.new(:company_id => qbo.realmId, :access_token => Qbo.get_auth_token)
time_service = Qbo.get_base(:time_activity).service
item_service = Qbo.get_base(:item).service
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
hours = spent_hours.to_i
minutesDecimal = (( spent_hours - hours) * 60)
@@ -38,26 +87,20 @@ class IssuesSaveHookListener < Redmine::Hook::ViewListener
entry.save
end
employee_id = User.find_by_id(issue.assigned_to_id).qbo_employee_id
# 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? and not issue.qbo_customer_id.nil? and not issue.qbo_item_id.nil? and not employee_id.nil? and spent_hours > 0 then
item = item_service.fetch_by_id issue.qbo_item_id
time_entry.description = "#{issue.tracker} ##{issue.id}: #{issue.subject}"
time_entry.employee_id = employee_id
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 = 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
item = item_service.fetch_by_id issue.qbo_item_id
time_entry.description = "#{issue.tracker} ##{issue.id}: #{issue.subject}"
time_entry.employee_id = employee_id
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 = 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

View File

@@ -10,31 +10,59 @@
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
# Display the quickbooks contact in the issue
def view_issues_show_details_bottom(context={})
value = ""
issue = context[:issue]
# Check to see if there is a quickbooks user attached to the issue
if not context[:issue].qbo_customer_id.nil? then
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 = ""
@customer = issue.qbo_customer ? issue.qbo_customer.name : nil
# Check to see if there is a quickbooks item attached to the issue
if not context[:issue].qbo_customer_id.nil? then
if not QboItem.find_by_id(context[:issue].qbo_item_id).nil? then
value = QboItem.find_by_id(context[:issue].qbo_item_id).name
end
@item = issue.qbo_item ? issue.qbo_item.name : nil
@estimate = nil
@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
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 output
return "<div class=\"attributes\">
<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

39
lib/user_patch.rb Normal file
View 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)

View File

@@ -12,16 +12,14 @@ class UsersShowHookListener < Redmine::Hook::ViewListener
# View User
def view_users_form(context={})
selected = ""
# Update the users
QboEmployee.update_all
# 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
end
@selected = context[:user].qbo_employee.id if context[:user].qbo_employee
# 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

View 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

View 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