mirror of
https://github.com/rickbarrette/redmine_qbo.git
synced 2025-11-08 17:04:23 -05:00
Compare commits
351 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d4d4a555f8 | |||
| c2663cd0a0 | |||
| d48609361f | |||
| 70995f6e55 | |||
| 05a0472939 | |||
| cff9f3fde3 | |||
| e24b704571 | |||
| 4d99f54c79 | |||
| e65725c334 | |||
| 4829daab7c | |||
| 260e9f3e4a | |||
| e3ce2445b8 | |||
| 2b333667ed | |||
| 1077cf214c | |||
| f27fdf5274 | |||
| 1dbcca4ca0 | |||
| 558e2359f7 | |||
| f99ef648b3 | |||
| 5e4e3329c8 | |||
| b0a66aba0a | |||
| f2dd500536 | |||
| 7412ac4f91 | |||
| 2acb3efe5a | |||
| 2cc0d06bc5 | |||
| 4070cb7c49 | |||
| fcd196355a | |||
| ea502d5b7b | |||
| 1f33009f89 | |||
| 3509ae9725 | |||
| 49858c45c9 | |||
| b78cd44cc9 | |||
| 39fcd6d4dd | |||
| 8838d36793 | |||
| 63fa94e6f2 | |||
| 17183f9643 | |||
| 667d0bfa97 | |||
| 88a6be0d27 | |||
| c3eaddff97 | |||
| f03adad463 | |||
| bd03e3ac32 | |||
| 299a28a0d2 | |||
| cee8ddced1 | |||
| 738cd21b1f | |||
| b8186e4b52 | |||
| d98a8b8cc4 | |||
| dba6c4b131 | |||
| 118812f16f | |||
| 0b96a1412c | |||
| 29de191d26 | |||
| f86af9ca71 | |||
| d25de7b30f | |||
| 273bd3d6be | |||
| ac446723f1 | |||
| c21bc1333f | |||
| 4e4255995e | |||
| c68b540597 | |||
| 1358871ccc | |||
| 908511f299 | |||
| 6260de21f9 | |||
| e2f276097c | |||
| 205bb67a6a | |||
| 05edafec4c | |||
| 4a073d3a71 | |||
| f2cbf31e17 | |||
| 22b22780ea | |||
| 71cfa28817 | |||
| 8b2d88f80b | |||
| eaf0a57e51 | |||
| 512f5ad7ba | |||
| 8d2351d3f9 | |||
| c5a20c9e7f | |||
| 4a3b663333 | |||
| e43635b5d8 | |||
| 7044377f16 | |||
| 7ced1bf942 | |||
| 7ca3315ce5 | |||
| 2b8c4b4d4d | |||
| a359e8815b | |||
| 01cf82813c | |||
| 625e400c48 | |||
| 56793cee7c | |||
| 3ba5337812 | |||
| 129e3d4821 | |||
| 4d524a7d61 | |||
| 429fb920fb | |||
| 77c7f0b6fe | |||
| 1a043bea76 | |||
| e4d770c272 | |||
| fce3931858 | |||
| 43cdade6e1 | |||
| 4374f9436c | |||
| 7c63c3c816 | |||
| b3f491a60b | |||
| 4adcbba840 | |||
| baccb42455 | |||
| d0842dd803 | |||
| 02aabe6045 | |||
| 0e47f9eb5f | |||
| f1d2d63f20 | |||
| f322f9f7ab | |||
| 6db8b76902 | |||
| 61adce1299 | |||
| daffb3719e | |||
| 1b8626d28f | |||
| b119344fad | |||
| 4381d403d4 | |||
| 26bfaca1d6 | |||
| 0c68d8094a | |||
| 6230175ba5 | |||
| 5dc4dc5637 | |||
| ac15307fb8 | |||
| ec5ce497d8 | |||
| 01fe52157d | |||
| 75737cf2fd | |||
| 7824edf5aa | |||
| 6b70b447a5 | |||
| 5a6b679099 | |||
| 72835dcf65 | |||
| b9e2349983 | |||
| ef13ec7e11 | |||
| 00b40da8c4 | |||
| 2be25adf18 | |||
| 5ab9a777f6 | |||
| 7fbb1d6ba3 | |||
| 786c80609c | |||
| efb554824d | |||
| c615abc896 | |||
| 8ecc3414da | |||
| 505def8d23 | |||
| da155de514 | |||
| 7d727e1ad8 | |||
| 3dcb5155fc | |||
| 4424593e63 | |||
| 8eae838ef8 | |||
| d5e8b4bbc4 | |||
| fc8efa53e9 | |||
| 15ea3aeaa2 | |||
| 35bf300f2d | |||
| 72bf10680f | |||
| bd8706deee | |||
| e8619529d4 | |||
| fd3c8e15e6 | |||
| 166c1d3002 | |||
| 773d60fb23 | |||
| cc46902095 | |||
| acb2628c7a | |||
| e4914590f8 | |||
| e3a8e464ae | |||
| 8a6bb45b6a | |||
| 3decf83a7b | |||
| 1b7b286d1b | |||
| a8804f6704 | |||
| 5d03e261d1 | |||
| 1ae766b8bd | |||
| 119c36569f | |||
| 3be69d5efd | |||
| b55dd99efd | |||
| eff1f97ab2 | |||
| 06050bd139 | |||
| a48840ddfb | |||
| 9b9aabee11 | |||
| 7782627286 | |||
| 41a113dc59 | |||
| b84e249dfb | |||
| 6b45f767a4 | |||
| a34b6a07fc | |||
| 2ce811bbbf | |||
| 02153de8b0 | |||
| 68be20459b | |||
| bbd03cc337 | |||
| 4fc71a93f2 | |||
| 8e7e1908e4 | |||
| 89fba883ef | |||
| 15f317fba1 | |||
| 894ee9abfd | |||
| ca17807117 | |||
| a70ba2f164 | |||
| 78ac97298c | |||
| 72cd349c1b | |||
| 6fc1d27dca | |||
| 525c6b99d6 | |||
| 3eaff0ab30 | |||
| 85b40bc9cf | |||
| 37a2b95447 | |||
| 33feb91713 | |||
| f7357f30ce | |||
| c0ae01018b | |||
| 4353e910c8 | |||
| bef9774c4e | |||
| 863437b1b7 | |||
| 7cfa15910a | |||
| 2154a3d001 | |||
| fdab090a3d | |||
| 3f32b7fef1 | |||
| 14422bc549 | |||
| 6bb66597e8 | |||
| 32b750b545 | |||
| 5fd3141746 | |||
| 2c38361234 | |||
| 81b7b1492d | |||
| 57ef1ac5a1 | |||
| 6597c5a13c | |||
| 8af97072fb | |||
| 48b6df0cef | |||
| 853b7ad804 | |||
| 6a74baff5e | |||
| 8b21b0ff75 | |||
| d22a6303cd | |||
| 807d6643f4 | |||
| c725c2774c | |||
| ae0abae333 | |||
| fed2282212 | |||
| 545960e676 | |||
| 66781f0625 | |||
| 504b9b93e4 | |||
| b71bba473c | |||
| aef3c453c4 | |||
| 6de3ed94dc | |||
| daada08ea7 | |||
| fa37c98500 | |||
| 0ee59704b3 | |||
| a22cbb9520 | |||
| c0d3f64d82 | |||
| 66d2bf4aa4 | |||
| 2b90c953ba | |||
| 0d5e5d679e | |||
| 4da891cc07 | |||
| d3475a9b53 | |||
| eb583f78ec | |||
| 47bebf0a1a | |||
| f9bd149f21 | |||
| 5371b0f193 | |||
| 95497e5514 | |||
| 1a74abe76c | |||
| 7f11d3cdc4 | |||
| da01d79325 | |||
| 82807cfede | |||
| a268d10819 | |||
| ba4bdd9ecb | |||
| 0a72e05e03 | |||
| 8d143ff06d | |||
| 3ddb585a58 | |||
| 1606ceb743 | |||
| 97578f8380 | |||
| 32beae70ef | |||
| 13fbc9e14f | |||
| c57a45c85e | |||
| 3711a9ca43 | |||
| d0c1693f38 | |||
| 36534ee129 | |||
| 188c460054 | |||
| d9e3cb096b | |||
| b57b19493f | |||
| 8c569db541 | |||
| 997257f42d | |||
| f9f1af17bc | |||
| f1f44d0048 | |||
| 7e8511090d | |||
| 4ca6a3138b | |||
| 21e1132e0e | |||
| dc15424014 | |||
| f90cdcd86b | |||
| 5e53c18098 | |||
| 52d13ea7bc | |||
| 5e24c5084e | |||
| abdb61cc41 | |||
| 03556cc670 | |||
| 7f6cd99aba | |||
| ba513fb950 | |||
| 837ddd722c | |||
| f2b0cd3748 | |||
| f2a8878af4 | |||
| 13fccec54b | |||
| eca2b986a9 | |||
| a06599b7f9 | |||
| 7fda4dc577 | |||
| 9e47152e12 | |||
| 83d21da41a | |||
| a692f03bfa | |||
| 994cdf908f | |||
| b022d17fc0 | |||
| 644899c0b5 | |||
| be3a3b920d | |||
| d546eb026f | |||
| fdc59feb13 | |||
| 186b726a7b | |||
|
|
fa362bad55 | ||
|
|
fcf55bb504 | ||
|
|
2185667665 | ||
|
|
772483817e | ||
|
|
178ddd32c7 | ||
| 08e047c90e | |||
| b3c3314385 | |||
| 9fd5e01bb4 | |||
| cd62f65fcd | |||
| fb40833abd | |||
| 6aae155933 | |||
| f9e0ae8fef | |||
| 489e335ca4 | |||
| 874d0b4db9 | |||
| 49e8f70b46 | |||
| 77ea20171e | |||
| 11d4034c37 | |||
| 64369470de | |||
| 7b483f3290 | |||
| 32bec79c28 | |||
| dfd9622ab7 | |||
| 334d3c930b | |||
| 8cf2f370bf | |||
| 3965bed6c4 | |||
| 52396eb384 | |||
| 9cfab7bea1 | |||
| c8ef3bbd4e | |||
| 39e7d3c062 | |||
| 6fa96e11df | |||
| ecde64193a | |||
| f701af9a4d | |||
| 6d99702a11 | |||
| 138f8f2c2f | |||
| 61ddf7378d | |||
| f5b72f30be | |||
| 1863b33955 | |||
| a4573fce1c | |||
| 0461801ee0 | |||
| 4c2eaac013 | |||
| 7ca56ccd2e | |||
| 915a59afa4 | |||
| ac61950d48 | |||
| b257fef563 | |||
| 504c27c197 | |||
| a7a5e2c731 | |||
| 21d72dcc33 | |||
| da7ba40e61 | |||
| b4d6fc55ea | |||
| 515b8feff7 | |||
| 8bc05db033 | |||
| 34cd6b08dc | |||
| 41195dc095 | |||
| 33a83c8f76 | |||
| 4f613d3fe1 | |||
| 1c7cdec600 | |||
| 7ae60c0e62 | |||
| 5dd04925e0 | |||
| 92eedbd4d3 | |||
| 5545d72adf | |||
| 226d44cd28 | |||
| b7152d6124 | |||
| f3e9b58c87 | |||
| 5209315236 | |||
| f38a9e1ff0 | |||
| 80fb296e24 |
7
Gemfile
7
Gemfile
@@ -5,8 +5,11 @@ gem 'quickbooks-ruby-base'
|
|||||||
gem 'oauth-plugin'
|
gem 'oauth-plugin'
|
||||||
gem 'oauth'
|
gem 'oauth'
|
||||||
gem 'roxml'
|
gem 'roxml'
|
||||||
gem 'edmunds_vin'
|
gem 'nhtsa_vin'
|
||||||
gem 'will_paginate', '~> 3.1.0'
|
gem 'will_paginate'
|
||||||
|
gem 'rails-jquery-autocomplete'
|
||||||
|
gem 'jquery-rails', '~> 3.1.4'
|
||||||
|
gem 'jquery-ui-rails'
|
||||||
|
|
||||||
group :assets do
|
group :assets do
|
||||||
gem 'coffee-rails'
|
gem 'coffee-rails'
|
||||||
|
|||||||
2
LICENSE
2
LICENSE
@@ -1,6 +1,6 @@
|
|||||||
The MIT License (MIT)
|
The MIT License (MIT)
|
||||||
|
|
||||||
Copyright (c) 2016 Rick Barrette
|
Copyright (c) 2018 Rick Barrette
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|||||||
12
README.md
12
README.md
@@ -1,4 +1,4 @@
|
|||||||
#Redmine Quickbooks Online
|
# Redmine Quickbooks Online
|
||||||
|
|
||||||
A plugin for Redmine to connect to Quickbooks Online
|
A plugin for Redmine to connect to Quickbooks Online
|
||||||
|
|
||||||
@@ -8,7 +8,7 @@ The goal of this project is to allow Redmine to connect with Quickbooks Online t
|
|||||||
|
|
||||||
`Note: I am currently using this in a live production enviroment with no issues`
|
`Note: I am currently using this in a live production enviroment with no issues`
|
||||||
|
|
||||||
####Features
|
#### Features
|
||||||
* Issues can be assigned to a `Customer` via drop down in the edit Issue form
|
* Issues can be assigned to a `Customer` via drop down in the edit Issue form
|
||||||
* The `Employee` for the Issue is assigned via the assigned Redmine User
|
* The `Employee` for the Issue is assigned via the assigned Redmine User
|
||||||
- This is set via a drop down in the user admistration page.
|
- This is set via a drop down in the user admistration page.
|
||||||
@@ -27,14 +27,14 @@ The goal of this project is to allow Redmine to connect with Quickbooks Online t
|
|||||||
+ `Invoice` Custom Fields are matched Issue Custom Fileds and are automaticly updated in Quickbooks. For example, this is usefull for extracting the Mileage In / Out from the Issue and updating the Invoice with the information.
|
+ `Invoice` Custom Fields are matched Issue Custom Fileds and are automaticly updated in Quickbooks. For example, this is usefull for extracting the Mileage In / Out from the Issue and updating the Invoice with the information.
|
||||||
- `Customers` are automaticly updated in local database
|
- `Customers` are automaticly updated in local database
|
||||||
|
|
||||||
##Prerequisites
|
## Prerequisites
|
||||||
|
|
||||||
* Sign up to become a developer for Intuit https://developer.intuit.com/
|
* Sign up to become a developer for Intuit https://developer.intuit.com/
|
||||||
* Create your own aplication to obtain your API keys
|
* Create your own aplication to obtain your API keys
|
||||||
* Set up webhook service to https://redmine.yourdomain.com/qbo/webhook
|
* Set up webhook service to https://redmine.yourdomain.com/qbo/webhook
|
||||||
- See https://developer.intuit.com/docs/0100_accounting/0300_developer_guides/webhooks
|
- See https://developer.intuit.com/docs/0100_accounting/0300_developer_guides/webhooks
|
||||||
|
|
||||||
##The Install
|
## The Install
|
||||||
|
|
||||||
1. To install, clone this repo into your plugin folder
|
1. To install, clone this repo into your plugin folder
|
||||||
|
|
||||||
@@ -73,11 +73,11 @@ Note: After the inital synchronization, this plugin will recieve push notificati
|
|||||||
* Fix Issue sort by Customer
|
* Fix Issue sort by Customer
|
||||||
* MORE Stuff...
|
* MORE Stuff...
|
||||||
|
|
||||||
##License
|
## License
|
||||||
|
|
||||||
The MIT License (MIT)
|
The MIT License (MIT)
|
||||||
|
|
||||||
Copyright (c) 2016 rick barrette
|
Copyright (c) 2017 rick barrette
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
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:
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 185 KiB After Width: | Height: | Size: 106 KiB |
@@ -1,6 +1,6 @@
|
|||||||
#The MIT License (MIT)
|
#The MIT License (MIT)
|
||||||
#
|
#
|
||||||
#Copyright (c) 2016 rick barrette
|
#Copyright (c) 2017 rick barrette
|
||||||
#
|
#
|
||||||
#Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
#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:
|
||||||
#
|
#
|
||||||
@@ -27,11 +27,26 @@ class CustomersController < ApplicationController
|
|||||||
include SortHelper
|
include SortHelper
|
||||||
helper :timelog
|
helper :timelog
|
||||||
|
|
||||||
before_filter :require_user, :except => :view
|
before_filter :add_customer, :only => :new
|
||||||
|
before_filter :view_customer, :except => :new
|
||||||
skip_before_filter :verify_authenticity_token, :check_if_login_required, :only => [:view]
|
skip_before_filter :verify_authenticity_token, :check_if_login_required, :only => [:view]
|
||||||
|
|
||||||
default_search_scope :names
|
default_search_scope :names
|
||||||
|
|
||||||
|
autocomplete :customer, :name, :full => true, :extra_data => [:id]
|
||||||
|
|
||||||
|
def filter_vehicles_by_customer
|
||||||
|
@filtered_vehicles = Vehicle.all.where(customer_id: params[:selected_customer])
|
||||||
|
end
|
||||||
|
|
||||||
|
def filter_invoices_by_customer
|
||||||
|
@filtered_invoices = QboInvoice.all.where(customer_id: params[:selected_customer])
|
||||||
|
end
|
||||||
|
|
||||||
|
def filter_estimates_by_customer
|
||||||
|
@filtered_estimates = QboEstimate.all.where(customer_id: params[:selected_customer])
|
||||||
|
end
|
||||||
|
|
||||||
# display a list of all customers
|
# display a list of all customers
|
||||||
def index
|
def index
|
||||||
if params[:search]
|
if params[:search]
|
||||||
@@ -105,9 +120,14 @@ class CustomersController < ApplicationController
|
|||||||
|
|
||||||
# Customer view for an issue
|
# Customer view for an issue
|
||||||
def view
|
def view
|
||||||
token = CustomerToken.where("token = ? and expires_at > ?", params[:token], Time.now)
|
|
||||||
if token.first
|
User.current = User.find_by lastname: 'Anonymous'
|
||||||
@issue = Issue.find token.first.issue_id
|
|
||||||
|
@token = CustomerToken.where("token = ? and expires_at > ?", params[:token], Time.now)
|
||||||
|
@token = @token.first
|
||||||
|
if @token
|
||||||
|
session[:token] = @token.token
|
||||||
|
@issue = Issue.find @token.issue_id
|
||||||
@journals = @issue.journals.
|
@journals = @issue.journals.
|
||||||
preload(:details).
|
preload(:details).
|
||||||
preload(:user => :email_address).
|
preload(:user => :email_address).
|
||||||
@@ -133,6 +153,14 @@ class CustomersController < ApplicationController
|
|||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def add_customer
|
||||||
|
global_check_permission(:add_customers)
|
||||||
|
end
|
||||||
|
|
||||||
|
def view_customer
|
||||||
|
global_check_permission(:view_customers)
|
||||||
|
end
|
||||||
|
|
||||||
def only_one_non_zero?( array )
|
def only_one_non_zero?( array )
|
||||||
found_non_zero = false
|
found_non_zero = false
|
||||||
array.each do |val|
|
array.each do |val|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#The MIT License (MIT)
|
#The MIT License (MIT)
|
||||||
#
|
#
|
||||||
#Copyright (c) 2016 rick barrette
|
#Copyright (c) 2017 rick barrette
|
||||||
#
|
#
|
||||||
#Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
#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:
|
||||||
#
|
#
|
||||||
@@ -18,7 +18,7 @@ class EstimateController < ApplicationController
|
|||||||
# Downloads and forwards the estimate pdf
|
# Downloads and forwards the estimate pdf
|
||||||
#
|
#
|
||||||
def show
|
def show
|
||||||
base = QboEstimate.get_base.service
|
base = QboEstimate.get_base
|
||||||
estimate = base.fetch_by_id(params[:id])
|
estimate = base.fetch_by_id(params[:id])
|
||||||
@pdf = base.pdf(estimate)
|
@pdf = base.pdf(estimate)
|
||||||
send_data @pdf, filename: "estimate #{estimate.doc_number}.pdf", :disposition => 'inline', :type => "application/pdf"
|
send_data @pdf, filename: "estimate #{estimate.doc_number}.pdf", :disposition => 'inline', :type => "application/pdf"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#The MIT License (MIT)
|
#The MIT License (MIT)
|
||||||
#
|
#
|
||||||
#Copyright (c) 2016 rick barrette
|
#Copyright (c) 2017 rick barrette
|
||||||
#
|
#
|
||||||
#Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
#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:
|
||||||
#
|
#
|
||||||
@@ -12,7 +12,8 @@ class InvoiceController < ApplicationController
|
|||||||
|
|
||||||
include AuthHelper
|
include AuthHelper
|
||||||
|
|
||||||
before_filter :require_user
|
before_filter :require_user, :unless => proc {|c| session[:token].nil? }
|
||||||
|
skip_before_filter :verify_authenticity_token, :check_if_login_required, :unless => proc {|c| session[:token].nil? }
|
||||||
|
|
||||||
#
|
#
|
||||||
# Downloads and forwards the invoice pdf
|
# Downloads and forwards the invoice pdf
|
||||||
|
|||||||
96
app/controllers/line_items_controler.rb
Normal file
96
app/controllers/line_items_controler.rb
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
#The License
|
||||||
|
#
|
||||||
|
#Copyright (c) 2018 Rick Barrette - All Rights Reserved
|
||||||
|
#
|
||||||
|
#Unauthorized copying of this software and associated documentation files (the "Software"), via any medium is strictly prohibited.
|
||||||
|
#
|
||||||
|
#Proprietary and confidential
|
||||||
|
#
|
||||||
|
#The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
#
|
||||||
|
#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
# This controller class will handle map management
|
||||||
|
class LineItemsController < ApplicationController
|
||||||
|
unloadable
|
||||||
|
|
||||||
|
include AuthHelper
|
||||||
|
|
||||||
|
before_filter :require_user
|
||||||
|
|
||||||
|
# display all line items for an issue
|
||||||
|
def index
|
||||||
|
if params[:issue_id]
|
||||||
|
begin
|
||||||
|
@line_items = Issue.find_by_id(params[:issue_id]).line_items
|
||||||
|
rescue ActiveRecord::RecordNotFound
|
||||||
|
render_404
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# return an HTML form for creating a new line item
|
||||||
|
def new
|
||||||
|
@line_item = LineItem.new
|
||||||
|
end
|
||||||
|
|
||||||
|
# create a new line item
|
||||||
|
def create
|
||||||
|
@line_item = LineItem.new(params[:line_item])
|
||||||
|
if @line_item.save
|
||||||
|
flash[:notice] = "New Line Item Created"
|
||||||
|
redirect_to @line_item.issue
|
||||||
|
else
|
||||||
|
flash[:error] = @line_item.errors.full_messages.to_sentence
|
||||||
|
redirect_to new_line_item_path
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# display a specific line item
|
||||||
|
def show
|
||||||
|
begin
|
||||||
|
@line_item = LineItem.find_by_id(params[:id])
|
||||||
|
rescue ActiveRecord::RecordNotFound
|
||||||
|
render_404
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# return an HTML form for editing a line item
|
||||||
|
def edit
|
||||||
|
begin
|
||||||
|
@line_item = LineItem.find_by_id(params[:id])
|
||||||
|
rescue ActiveRecord::RecordNotFound
|
||||||
|
render_404
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# update a specific line item
|
||||||
|
def update
|
||||||
|
begin
|
||||||
|
@line_item = LineItem.find_by_id(params[:id])
|
||||||
|
if @line_item.update_attributes(params[:line_item])
|
||||||
|
flash[:notice] = "Line Item updated"
|
||||||
|
redirect_to @line_item
|
||||||
|
else
|
||||||
|
flash[:error] = @line_item.errors.full_messages.to_sentence if @line_item.errors
|
||||||
|
redirect_to edit_line_item_path
|
||||||
|
end
|
||||||
|
rescue ActiveRecord::RecordNotFound
|
||||||
|
render_404
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# delete a specific line item
|
||||||
|
def destroy
|
||||||
|
begin
|
||||||
|
line_item = LineItem.find_by_id(params[:id])
|
||||||
|
issue = line_item.issue
|
||||||
|
line_item.destroy
|
||||||
|
flash[:notice] = "Line Item deleted successfully"
|
||||||
|
redirect_to issue
|
||||||
|
rescue ActiveRecord::RecordNotFound
|
||||||
|
render_404
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
#The MIT License (MIT)
|
#The MIT License (MIT)
|
||||||
#
|
#
|
||||||
#Copyright (c) 2016 rick barrette
|
#Copyright (c) 2017 rick barrette
|
||||||
#
|
#
|
||||||
#Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
#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:
|
||||||
#
|
#
|
||||||
@@ -12,8 +12,8 @@ class PaymentsController < ApplicationController
|
|||||||
|
|
||||||
include AuthHelper
|
include AuthHelper
|
||||||
|
|
||||||
before_filter :require_user
|
before_filter :check_permissions
|
||||||
|
|
||||||
def new
|
def new
|
||||||
@payment = Payment.new
|
@payment = Payment.new
|
||||||
|
|
||||||
@@ -32,10 +32,16 @@ class PaymentsController < ApplicationController
|
|||||||
else
|
else
|
||||||
flash[:error] = @payment.errors.full_messages.to_sentence
|
flash[:error] = @payment.errors.full_messages.to_sentence
|
||||||
redirect_to new_customer_path
|
redirect_to new_customer_path
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def check_permissions
|
||||||
|
if !allowed_to?(:add_payments)
|
||||||
|
render :file => "public/401.html.erb", :status => :unauthorized, :layout =>true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def only_one_non_zero?( array )
|
def only_one_non_zero?( array )
|
||||||
found_non_zero = false
|
found_non_zero = false
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#The MIT License (MIT)
|
#The MIT License (MIT)
|
||||||
#
|
#
|
||||||
#Copyright (c) 2016 rick barrette
|
#Copyright (c) 2017 rick barrette
|
||||||
#
|
#
|
||||||
#Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
#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:
|
||||||
#
|
#
|
||||||
@@ -66,8 +66,12 @@ class QboController < ApplicationController
|
|||||||
# Manual Billing
|
# Manual Billing
|
||||||
def bill
|
def bill
|
||||||
i = Issue.find_by_id params[:id]
|
i = Issue.find_by_id params[:id]
|
||||||
i.bill_time
|
if i.customer
|
||||||
redirect_to i, :flash => { :notice => "Successfully Billed #{i.customer.name}" }
|
i.bill_time
|
||||||
|
redirect_to i, :flash => { :notice => "Successfully Billed #{i.customer.name}" }
|
||||||
|
else
|
||||||
|
redirect_to i, :flash => { :error => "Cannot bill without a customer assigned" }
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Quickbooks Webhook Callback
|
# Quickbooks Webhook Callback
|
||||||
@@ -129,10 +133,10 @@ class QboController < ApplicationController
|
|||||||
Thread.new do
|
Thread.new do
|
||||||
if Qbo.exists?
|
if Qbo.exists?
|
||||||
Customer.sync
|
Customer.sync
|
||||||
|
QboInvoice.sync
|
||||||
QboItem.sync
|
QboItem.sync
|
||||||
QboEmployee.sync
|
QboEmployee.sync
|
||||||
QboEstimate.sync
|
QboEstimate.sync
|
||||||
QboInvoice.sync
|
|
||||||
|
|
||||||
# Record the last sync time
|
# Record the last sync time
|
||||||
Qbo.update_time_stamp
|
Qbo.update_time_stamp
|
||||||
@@ -140,6 +144,6 @@ class QboController < ApplicationController
|
|||||||
ActiveRecord::Base.connection.close
|
ActiveRecord::Base.connection.close
|
||||||
end
|
end
|
||||||
|
|
||||||
redirect_to qbo_path(:redmine_qbo), :flash => { :notice => "Successfully synced to Quickbooks" }
|
redirect_to :back, :flash => { :notice => "Successfully synced to Quickbooks" }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#The MIT License (MIT)
|
#The MIT License (MIT)
|
||||||
#
|
#
|
||||||
#Copyright (c) 2016 rick barrette
|
#Copyright (c) 2017 rick barrette
|
||||||
#
|
#
|
||||||
#Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
#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:
|
||||||
#
|
#
|
||||||
@@ -37,8 +37,7 @@ class VehiclesController < ApplicationController
|
|||||||
# return an HTML form for creating a new vehicle
|
# return an HTML form for creating a new vehicle
|
||||||
def new
|
def new
|
||||||
@vehicle = Vehicle.new
|
@vehicle = Vehicle.new
|
||||||
@customers = Customer.all.order(:name)
|
@customer = Customer.find_by_id(params[:customer_id]) if params[:customer_id]
|
||||||
@customer = params[:customer_id] if params[:customer_id]
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# create a new vehicle
|
# create a new vehicle
|
||||||
@@ -57,6 +56,7 @@ class VehiclesController < ApplicationController
|
|||||||
def show
|
def show
|
||||||
begin
|
begin
|
||||||
@vehicle = Vehicle.find_by_id(params[:id])
|
@vehicle = Vehicle.find_by_id(params[:id])
|
||||||
|
@vin = @vehicle.vin.scan(/.{1,9}/) if @vehicle.vin
|
||||||
rescue ActiveRecord::RecordNotFound
|
rescue ActiveRecord::RecordNotFound
|
||||||
render_404
|
render_404
|
||||||
end
|
end
|
||||||
@@ -66,8 +66,7 @@ class VehiclesController < ApplicationController
|
|||||||
def edit
|
def edit
|
||||||
begin
|
begin
|
||||||
@vehicle = Vehicle.find_by_id(params[:id])
|
@vehicle = Vehicle.find_by_id(params[:id])
|
||||||
@customer = @vehicle.customer.id
|
@customer = @vehicle.customer
|
||||||
@customers = Customer.all.order(:name)
|
|
||||||
rescue ActiveRecord::RecordNotFound
|
rescue ActiveRecord::RecordNotFound
|
||||||
render_404
|
render_404
|
||||||
end
|
end
|
||||||
@@ -101,15 +100,6 @@ class VehiclesController < ApplicationController
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# returns a dynamic list of vehicles owned by a customer
|
|
||||||
def update_vehicles
|
|
||||||
@vehicles = Customer.find_by(customer_id: params[:customer_id].to_i).vehicles
|
|
||||||
respond_to do |format|
|
|
||||||
format.html { render(:text => "not implemented") }
|
|
||||||
format.js
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def only_one_non_zero?( array )
|
def only_one_non_zero?( array )
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#The MIT License (MIT)
|
#The MIT License (MIT)
|
||||||
#
|
#
|
||||||
#Copyright (c) 2016 rick barrette
|
#Copyright (c) 2017 rick barrette
|
||||||
#
|
#
|
||||||
#Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
#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:
|
||||||
#
|
#
|
||||||
@@ -11,8 +11,43 @@
|
|||||||
module AuthHelper
|
module AuthHelper
|
||||||
|
|
||||||
def require_user
|
def require_user
|
||||||
|
return unless session[:token].nil?
|
||||||
if !User.current.logged?
|
if !User.current.logged?
|
||||||
render :file => "public/401.html.erb", :status => :unauthorized, :layout =>true
|
render :file => "public/401.html.erb", :status => :unauthorized, :layout =>true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def allowed_to?(action)
|
||||||
|
return false if User.current.nil?
|
||||||
|
project = Project.find(params[:project_id])
|
||||||
|
return false if project.nil?
|
||||||
|
return true if User.current.allowed_to?(action, project)
|
||||||
|
false
|
||||||
|
end
|
||||||
|
|
||||||
|
def check_permission(permission)
|
||||||
|
if !allowed_to?(permission)
|
||||||
|
render :file => "public/401.html.erb", :status => :unauthorized, :layout =>true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
def global_check_permission(permission)
|
||||||
|
if !globaly_allowed_to?(permission)
|
||||||
|
render :file => "public/401.html.erb", :status => :unauthorized, :layout =>true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def globaly_allowed_to?( action)
|
||||||
|
return false if User.current.nil?
|
||||||
|
|
||||||
|
projects = Project.all
|
||||||
|
projects.each { |p|
|
||||||
|
if User.current.allowed_to?(action, p)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
}
|
||||||
|
false
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#The MIT License (MIT)
|
#The MIT License (MIT)
|
||||||
#
|
#
|
||||||
#Copyright (c) 2016 rick barrette
|
#Copyright (c) 2017 rick barrette
|
||||||
#
|
#
|
||||||
#Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
#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:
|
||||||
#
|
#
|
||||||
@@ -13,6 +13,8 @@ class Customer < ActiveRecord::Base
|
|||||||
|
|
||||||
has_many :issues
|
has_many :issues
|
||||||
has_many :qbo_purchases
|
has_many :qbo_purchases
|
||||||
|
has_many :qbo_invoices
|
||||||
|
has_many :qbo_estimates
|
||||||
has_many :vehicles
|
has_many :vehicles
|
||||||
|
|
||||||
attr_accessible :name, :notes, :email, :primary_phone, :mobile_phone
|
attr_accessible :name, :notes, :email, :primary_phone, :mobile_phone
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#The MIT License (MIT)
|
#The MIT License (MIT)
|
||||||
#
|
#
|
||||||
#Copyright (c) 2016 rick barrette
|
#Copyright (c) 2017 rick barrette
|
||||||
#
|
#
|
||||||
#Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
#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:
|
||||||
#
|
#
|
||||||
@@ -15,7 +15,7 @@ class CustomerToken < ActiveRecord::Base
|
|||||||
validates_presence_of :expires_at, :issue_id
|
validates_presence_of :expires_at, :issue_id
|
||||||
before_create :generate_token
|
before_create :generate_token
|
||||||
|
|
||||||
OAUTH_CONSUMER_SECRET = Setting.plugin_redmine_qbo['settingsOAuthConsumerSecret']
|
OAUTH_CONSUMER_SECRET = Setting.plugin_redmine_qbo['settingsOAuthConsumerSecret'] || 'CONFIGURE_QBO__' + SecureRandom.uuid
|
||||||
|
|
||||||
def generate_token
|
def generate_token
|
||||||
self.token = SecureRandom.base64(15).tr('+/=lIO0', OAUTH_CONSUMER_SECRET)
|
self.token = SecureRandom.base64(15).tr('+/=lIO0', OAUTH_CONSUMER_SECRET)
|
||||||
|
|||||||
34
app/models/line_item.rb
Normal file
34
app/models/line_item.rb
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
#Copyright (c) 2018 Rick Barrette - All Rights Reserved
|
||||||
|
#
|
||||||
|
#Unauthorized copying of this software and associated documentation files (the "Software"), via any medium is strictly prohibited.
|
||||||
|
#
|
||||||
|
#Proprietary and confidential
|
||||||
|
#
|
||||||
|
#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 LineItem < ActiveRecord::Base
|
||||||
|
|
||||||
|
unloadable
|
||||||
|
|
||||||
|
belongs_to :issue
|
||||||
|
|
||||||
|
attr_accessible :amount, :description, :unit_price, :quantity, :item_id
|
||||||
|
validates_presence_of :amount, :description, :unit_price, :quantity
|
||||||
|
|
||||||
|
def add_to_invoice(invoice)
|
||||||
|
line_item = Quickbooks::Model::InvoiceLineItem.new
|
||||||
|
line_item.amount = amount
|
||||||
|
line_item.description = description
|
||||||
|
line_item.sales_item! do |detail|
|
||||||
|
detail.unit_price = unit_price
|
||||||
|
detail.quantity = quantity
|
||||||
|
detail.item_id = item_id # Item ID here... Where do i get this???
|
||||||
|
end
|
||||||
|
|
||||||
|
invoice.line_items << line_item
|
||||||
|
|
||||||
|
return invoice
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
#The MIT License (MIT)
|
#The MIT License (MIT)
|
||||||
#
|
#
|
||||||
#Copyright (c) 2016 rick barrette
|
#Copyright (c) 2017 rick barrette
|
||||||
#
|
#
|
||||||
#Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
#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:
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#The MIT License (MIT)
|
#The MIT License (MIT)
|
||||||
#
|
#
|
||||||
#Copyright (c) 2016 rick barrette
|
#Copyright (c) 2017 rick barrette
|
||||||
#
|
#
|
||||||
#Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
#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:
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#The MIT License (MIT)
|
#The MIT License (MIT)
|
||||||
#
|
#
|
||||||
#Copyright (c) 2016 rick barrette
|
#Copyright (c) 2017 rick barrette
|
||||||
#
|
#
|
||||||
#Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
#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:
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#The MIT License (MIT)
|
#The MIT License (MIT)
|
||||||
#
|
#
|
||||||
#Copyright (c) 2016 rick barrette
|
#Copyright (c) 2017 rick barrette
|
||||||
#
|
#
|
||||||
#Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
#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:
|
||||||
#
|
#
|
||||||
@@ -10,44 +10,49 @@
|
|||||||
|
|
||||||
class QboEstimate < ActiveRecord::Base
|
class QboEstimate < ActiveRecord::Base
|
||||||
unloadable
|
unloadable
|
||||||
has_many :issues
|
|
||||||
attr_accessible :doc_number
|
|
||||||
validates_presence_of :id, :doc_number
|
|
||||||
|
|
||||||
|
has_and_belongs_to_many :issues
|
||||||
|
belongs_to :customer
|
||||||
|
attr_accessible :doc_number, :id
|
||||||
|
validates_presence_of :doc_number, :id
|
||||||
|
self.primary_key = :id
|
||||||
|
|
||||||
|
# return the QBO Estimate service
|
||||||
def self.get_base
|
def self.get_base
|
||||||
Qbo.get_base(:estimate)
|
Qbo.get_base(:estimate).service
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# sync all estimates
|
||||||
def self.sync
|
def self.sync
|
||||||
estimates = get_base.service.all
|
estimates = get_base.all
|
||||||
|
estimates.each { |estimate|
|
||||||
# Update the item table
|
process_estimate(estimate)
|
||||||
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
|
#remove deleted estimates
|
||||||
where.not(estimates.map(&:id)).destroy_all
|
where.not(estimates.map(&:id)).destroy_all
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# sync only one estimate
|
||||||
def self.sync_by_id(id)
|
def self.sync_by_id(id)
|
||||||
estimate = get_base.service.fetch_by_id(id)
|
process_estimate(get_base.fetch_by_id(id))
|
||||||
qbo_estimate = QboEstimate.find_or_create_by(id: estimate.id)
|
end
|
||||||
|
|
||||||
|
# update an estimate
|
||||||
|
def self.update(id)
|
||||||
|
# Update the item table
|
||||||
|
estimate = get_base.fetch_by_id(id)
|
||||||
|
qbo_estimate = find_or_create_by(id: id)
|
||||||
qbo_estimate.doc_number = estimate.doc_number
|
qbo_estimate.doc_number = estimate.doc_number
|
||||||
qbo_estimate.id = estimate.id
|
|
||||||
qbo_estimate.save!
|
qbo_estimate.save!
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.update(id)
|
# process an estimate into the database
|
||||||
# Update the item table
|
def self.process_estimate(estimate)
|
||||||
estimate = get_base.service.fetch_by_id(id)
|
qbo_estimate = find_or_create_by(id: estimate.id)
|
||||||
qbo_estimate = QboEstimate.find_or_create_by(id: id)
|
qbo_estimate.doc_number = estimate.doc_number
|
||||||
qbo_estimate.doc_number = estimate.doc_number
|
qbo_estimate.customer_id = estimate.customer_ref.value
|
||||||
qbo_estimate.save!
|
qbo_estimate.id = estimate.id
|
||||||
|
qbo_estimate.save!
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#The MIT License (MIT)
|
#The MIT License (MIT)
|
||||||
#
|
#
|
||||||
#Copyright (c) 2016 rick barrette
|
#Copyright (c) 2017 rick barrette
|
||||||
#
|
#
|
||||||
#Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
#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:
|
||||||
#
|
#
|
||||||
@@ -12,6 +12,7 @@ class QboInvoice < ActiveRecord::Base
|
|||||||
unloadable
|
unloadable
|
||||||
|
|
||||||
has_and_belongs_to_many :issues
|
has_and_belongs_to_many :issues
|
||||||
|
belongs_to :customer
|
||||||
attr_accessible :doc_number, :id
|
attr_accessible :doc_number, :id
|
||||||
validates_presence_of :doc_number, :id
|
validates_presence_of :doc_number, :id
|
||||||
self.primary_key = :id
|
self.primary_key = :id
|
||||||
@@ -46,89 +47,109 @@ class QboInvoice < ActiveRecord::Base
|
|||||||
process_invoice invoice
|
process_invoice invoice
|
||||||
end
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
# Attach the invoice to the issue
|
||||||
|
def self.attach_to_issue(issue, invoice)
|
||||||
|
return if issue.nil?
|
||||||
|
|
||||||
|
# skip this issue if the issue customer is not the same as the invoice customer
|
||||||
|
return if issue.customer_id != invoice.customer_ref.value.to_i
|
||||||
|
|
||||||
|
# Load the invoice into the database
|
||||||
|
qbo_invoice = QboInvoice.find_or_create_by(id: invoice.id)
|
||||||
|
qbo_invoice.doc_number = invoice.doc_number
|
||||||
|
qbo_invoice.id = invoice.id
|
||||||
|
qbo_invoice.customer_id = invoice.customer_ref
|
||||||
|
qbo_invoice.save!
|
||||||
|
|
||||||
|
unless issue.qbo_invoices.include?(qbo_invoice)
|
||||||
|
issue.qbo_invoices << qbo_invoice
|
||||||
|
issue.save!
|
||||||
|
end
|
||||||
|
|
||||||
|
compare_custom_fields(issue, invoice)
|
||||||
|
end
|
||||||
|
|
||||||
# processes the invoice into the system
|
# processes the invoice into the system
|
||||||
def self.process_invoice(invoice)
|
def self.process_invoice(invoice)
|
||||||
|
# Check the private notes
|
||||||
is_changed = false
|
if not invoice.private_note.nil?
|
||||||
|
invoice.private_note.scan(/#(\w+)/).flatten.each { |issue|
|
||||||
|
attach_to_issue(Issue.find_by_id(issue.to_i), invoice)
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
# Scan the line items for hashtags and attach to the applicable issues
|
# Scan the line items for hashtags and attach to the applicable issues
|
||||||
invoice.line_items.each { |line|
|
invoice.line_items.each { |line|
|
||||||
if line.description
|
if line.description
|
||||||
line.description.scan(/#(\w+)/).flatten.each { |issue|
|
line.description.scan(/#(\w+)/).flatten.each { |issue|
|
||||||
i = Issue.find_by_id(issue.to_i)
|
attach_to_issue(Issue.find_by_id(issue.to_i), invoice)
|
||||||
|
|
||||||
# Load the invoice into the database
|
|
||||||
qbo_invoice = QboInvoice.find_or_create_by(id: invoice.id)
|
|
||||||
qbo_invoice.doc_number = invoice.doc_number
|
|
||||||
qbo_invoice.id = invoice.id
|
|
||||||
qbo_invoice.save!
|
|
||||||
|
|
||||||
# Attach the invoice to the issue
|
|
||||||
unless i.qbo_invoices.include?(qbo_invoice)
|
|
||||||
i.qbo_invoices << qbo_invoice
|
|
||||||
i.save!
|
|
||||||
end
|
|
||||||
|
|
||||||
# update the invoive custom fields with infomation from the work ticket if available
|
|
||||||
invoice.custom_fields.each { |cf|
|
|
||||||
|
|
||||||
# VIN from the attached vehicle
|
|
||||||
begin
|
|
||||||
if cf.name.eql? "VIN"
|
|
||||||
vin = Vehicle.find(i.vehicles_id).vin
|
|
||||||
break if vin.nil?
|
|
||||||
if not cf.string_value.to_s.eql? vin
|
|
||||||
cf.string_value = vin.to_s
|
|
||||||
is_changed = true
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
rescue
|
|
||||||
#do nothing
|
|
||||||
end
|
|
||||||
|
|
||||||
# Custom Values
|
|
||||||
begin
|
|
||||||
value = i.custom_values.find_by(custom_field_id: CustomField.find_by_name(cf.name).id)
|
|
||||||
|
|
||||||
# Check to see if the value is blank...
|
|
||||||
if not value.value.to_s.blank?
|
|
||||||
# Check to see if the value is diffrent
|
|
||||||
if not cf.string_value.to_s.eql? value.value.to_s
|
|
||||||
|
|
||||||
# Use the lowest Milage
|
|
||||||
if cf.name.eql? "Mileage In"
|
|
||||||
if cf.string_value.to_i > value.value.to_i or cf.string_value.blank?
|
|
||||||
cf.string_value = value.value.to_s
|
|
||||||
is_changed = true
|
|
||||||
end
|
|
||||||
break
|
|
||||||
end
|
|
||||||
|
|
||||||
# Use the max milage
|
|
||||||
if cf.name.eql? "Mileage Out"
|
|
||||||
if cf.string_value.to_i < value.value.to_i or cf.string_value.blank?
|
|
||||||
cf.string_value = value.value.to_s
|
|
||||||
is_changed = true
|
|
||||||
end
|
|
||||||
break
|
|
||||||
end
|
|
||||||
|
|
||||||
# Everything else
|
|
||||||
cf.string_value = value.value.to_s
|
|
||||||
is_changed = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
rescue
|
|
||||||
# Nothing to do here, there is no match
|
|
||||||
end
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
}
|
}
|
||||||
|
|
||||||
# Push updates
|
|
||||||
get_base.update(invoice) if is_changed
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.compare_custom_fields(issue, invoice)
|
||||||
|
is_changed = false
|
||||||
|
|
||||||
|
# update the invoive custom fields with infomation from the work ticket if available
|
||||||
|
invoice.custom_fields.each { |cf|
|
||||||
|
|
||||||
|
# TODO Add some hooks here
|
||||||
|
|
||||||
|
# VIN from the attached vehicle
|
||||||
|
begin
|
||||||
|
if cf.name.eql? "VIN"
|
||||||
|
vin = Vehicle.find(issue.vehicles_id).vin
|
||||||
|
break if vin.nil?
|
||||||
|
if not cf.string_value.to_s.eql? vin
|
||||||
|
cf.string_value = vin.to_s
|
||||||
|
is_changed = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
rescue
|
||||||
|
#do nothing
|
||||||
|
end
|
||||||
|
|
||||||
|
# Custom Values
|
||||||
|
begin
|
||||||
|
value = issue.custom_values.find_by(custom_field_id: CustomField.find_by_name(cf.name).id)
|
||||||
|
|
||||||
|
# Check to see if the value is blank...
|
||||||
|
if not value.value.to_s.blank?
|
||||||
|
# Check to see if the value is diffrent
|
||||||
|
if not cf.string_value.to_s.eql? value.value.to_s
|
||||||
|
|
||||||
|
# Use the lowest Milage
|
||||||
|
if cf.name.eql? "Mileage In"
|
||||||
|
if cf.string_value.to_i > value.value.to_i or cf.string_value.blank?
|
||||||
|
cf.string_value = value.value.to_s
|
||||||
|
is_changed = true
|
||||||
|
end
|
||||||
|
# Use the max milage
|
||||||
|
elsif cf.name.eql? "Mileage Out"
|
||||||
|
if cf.string_value.to_i < value.value.to_i or cf.string_value.blank?
|
||||||
|
cf.string_value = value.value.to_s
|
||||||
|
is_changed = true
|
||||||
|
end
|
||||||
|
else
|
||||||
|
# Everything else
|
||||||
|
cf.string_value = value.value.to_s
|
||||||
|
is_changed = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
rescue
|
||||||
|
# Nothing to do here, there is no match
|
||||||
|
end
|
||||||
|
}
|
||||||
|
|
||||||
|
# TODO Add some hooks here
|
||||||
|
|
||||||
|
# Push updates
|
||||||
|
#invoice.sync_token += 1 if is_changed
|
||||||
|
get_base.update(invoice) if is_changed
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#The MIT License (MIT)
|
#The MIT License (MIT)
|
||||||
#
|
#
|
||||||
#Copyright (c) 2016 rick barrette
|
#Copyright (c) 2017 rick barrette
|
||||||
#
|
#
|
||||||
#Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
#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:
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#The MIT License (MIT)
|
#The MIT License (MIT)
|
||||||
#
|
#
|
||||||
#Copyright (c) 2016 rick barrette
|
#Copyright (c) 2017 rick barrette
|
||||||
#
|
#
|
||||||
#Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
#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:
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#The MIT License (MIT)
|
#The MIT License (MIT)
|
||||||
#
|
#
|
||||||
#Copyright (c) 2016 rick barrette
|
#Copyright (c) 2017 rick barrette
|
||||||
#
|
#
|
||||||
#Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
#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:
|
||||||
#
|
#
|
||||||
@@ -12,8 +12,6 @@ class Vehicle < ActiveRecord::Base
|
|||||||
|
|
||||||
unloadable
|
unloadable
|
||||||
|
|
||||||
API_KEY = Setting.plugin_redmine_qbo['settingsEdmundsAPIKey']
|
|
||||||
|
|
||||||
belongs_to :customer
|
belongs_to :customer
|
||||||
has_many :issues, :foreign_key => 'vehicles_id'
|
has_many :issues, :foreign_key => 'vehicles_id'
|
||||||
|
|
||||||
@@ -21,8 +19,6 @@ class Vehicle < ActiveRecord::Base
|
|||||||
|
|
||||||
validates_presence_of :customer
|
validates_presence_of :customer
|
||||||
validates :vin, uniqueness: true
|
validates :vin, uniqueness: true
|
||||||
#validates :year, numericality: { only_integer: true }
|
|
||||||
|
|
||||||
before_save :decode_vin
|
before_save :decode_vin
|
||||||
after_initialize :get_details
|
after_initialize :get_details
|
||||||
|
|
||||||
@@ -30,7 +26,12 @@ class Vehicle < ActiveRecord::Base
|
|||||||
|
|
||||||
# returns a human readable string
|
# returns a human readable string
|
||||||
def to_s
|
def to_s
|
||||||
return "#{year} #{make} #{model}"
|
if year.nil? or make.nil? or model.nil?
|
||||||
|
return "#{vin}"
|
||||||
|
else
|
||||||
|
split_vin = vin.scan(/.{1,9}/)
|
||||||
|
return "#{year} #{make} #{model} - #{split_vin[1]}"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# returns the raw JSON details from EMUNDS
|
# returns the raw JSON details from EMUNDS
|
||||||
@@ -41,7 +42,7 @@ class Vehicle < ActiveRecord::Base
|
|||||||
# returns the style of the vehicle
|
# returns the style of the vehicle
|
||||||
def style
|
def style
|
||||||
begin
|
begin
|
||||||
return @details['years'][0]['styles'][0]['name'] if @details
|
return @details.trim if @details
|
||||||
rescue
|
rescue
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
@@ -49,12 +50,14 @@ class Vehicle < ActiveRecord::Base
|
|||||||
|
|
||||||
# returns the drive of the vehicle i.e. 2 wheel, 4 wheel, ect.
|
# returns the drive of the vehicle i.e. 2 wheel, 4 wheel, ect.
|
||||||
def drive
|
def drive
|
||||||
return @details['drivenWheels'].to_s.upcase if @details
|
#todo fix this
|
||||||
|
#return @details.drive_type if @details
|
||||||
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
# returns the number of doors of the vehicle
|
# returns the number of doors of the vehicle
|
||||||
def doors
|
def doors
|
||||||
return @details['numOfDoors'] if @details
|
return @details.doors if @details
|
||||||
end
|
end
|
||||||
|
|
||||||
# Force Upper Case for VIN numbers
|
# Force Upper Case for VIN numbers
|
||||||
@@ -71,8 +74,9 @@ class Vehicle < ActiveRecord::Base
|
|||||||
|
|
||||||
# Force Upper Case for VIN numbers
|
# Force Upper Case for VIN numbers
|
||||||
def vin=(val)
|
def vin=(val)
|
||||||
# The to_s is in case you get nil/non-string
|
#strip VIN of all illegal chars (for barcode scanner)
|
||||||
write_attribute(:vin, val.to_s.scan(/^[A-Za-z0-9]+$/).join.upcase)
|
val = val.to_s.upcase.gsub(/[^A-HJ-NPR-Za-hj-npr-z\d]+/,"")
|
||||||
|
write_attribute(:vin, val)
|
||||||
end
|
end
|
||||||
|
|
||||||
# search for a vin
|
# search for a vin
|
||||||
@@ -80,35 +84,29 @@ class Vehicle < ActiveRecord::Base
|
|||||||
where("vin LIKE ?", "%#{search}%")
|
where("vin LIKE ?", "%#{search}%")
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
# init method to pull JSON details from Edmunds
|
# init method to pull JSON details from Edmunds
|
||||||
def get_details
|
def get_details
|
||||||
if self.vin?
|
if self.vin?
|
||||||
begin
|
begin
|
||||||
@details = JSON.parse get_decoder.full(self.vin)
|
query = NhtsaVin.get(self.vin)
|
||||||
raise @details['message'] if @details['status'].to_s.eql? "NOT_FOUND"
|
raise RuntimeError, query.error unless query.valid?
|
||||||
raise @details['message'] if @details['status'].to_s.eql? "BAD_REQUEST"
|
@details = query.response
|
||||||
rescue Exception => e
|
rescue Exception => e
|
||||||
errors.add(:vin, e.message)
|
errors.add(:vin, e.message)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# returns the Edmunds decoder service
|
|
||||||
def get_decoder
|
|
||||||
#TODO API Code via Settings
|
|
||||||
return decoder = Edmunds::Vin.new(API_KEY)
|
|
||||||
end
|
|
||||||
|
|
||||||
# decodes a vin and updates self
|
# decodes a vin and updates self
|
||||||
def decode_vin
|
def decode_vin
|
||||||
get_details
|
get_details
|
||||||
if @details
|
if @details
|
||||||
begin
|
begin
|
||||||
self.year = @details['years'][0]['year']
|
self.year = @details.year unless @details.year.nil?
|
||||||
self.make = @details['make']['name']
|
self.make = @details.make unless @details.make.nil?
|
||||||
self.model = @details['model']['name']
|
self.model = @details.model unless @details.model.nil?
|
||||||
rescue Exception => e
|
rescue Exception => e
|
||||||
errors.add(:vin, e.message)
|
errors.add(:vin, e.message)
|
||||||
end
|
end
|
||||||
@@ -116,15 +114,4 @@ class Vehicle < ActiveRecord::Base
|
|||||||
self.name = to_s
|
self.name = to_s
|
||||||
end
|
end
|
||||||
|
|
||||||
# makes a squishvin
|
|
||||||
# https://api.edmunds.com/api/vehicle/v2/squishvins/#{vin}/?fmt=json&api_key=#{ENV['edmunds_key']}
|
|
||||||
def vin_squish
|
|
||||||
if not self.vin? or self.vin.size < 11
|
|
||||||
# this is to go ahead and query the API, letting them handle the error. :P
|
|
||||||
return '1000000000A'
|
|
||||||
end
|
|
||||||
v = self.vin[0,11]
|
|
||||||
return v.slice(0,8) + v.slice(9,11)
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,10 +1,5 @@
|
|||||||
<table>
|
<table>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
|
||||||
<th>Customer</th>
|
|
||||||
<td><%= customer.name %></td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<th>Email</th>
|
<th>Email</th>
|
||||||
<td><%= customer.email %></td>
|
<td><%= customer.email %></td>
|
||||||
|
|||||||
6
app/views/customers/_search.html.erb
Normal file
6
app/views/customers/_search.html.erb
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<%= form_tag(customers_path, :method => "get", id: "search-form") do %>
|
||||||
|
<%= text_field_tag :search, params[:search], placeholder: "Search Customers" %>
|
||||||
|
<%= submit_tag "Search" %>
|
||||||
|
<% end %>
|
||||||
|
<%= button_to "New Customer", new_customer_path, method: :get%>
|
||||||
|
<%= button_to "Sync", qbo_sync_path, method: :get%>
|
||||||
2
app/views/customers/_sidebar.html.erb
Normal file
2
app/views/customers/_sidebar.html.erb
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
<h3>Customers</h3>
|
||||||
|
<%= render :partial => 'customers/search' %>
|
||||||
1
app/views/customers/filter_estimates_by_customer.js.erb
Normal file
1
app/views/customers/filter_estimates_by_customer.js.erb
Normal file
@@ -0,0 +1 @@
|
|||||||
|
$('select#issue_qbo_estimate_id').html('<%= j content_tag(:option,'',:value=>"")+options_from_collection_for_select(@filtered_estimates, :id, :doc_number) %>');
|
||||||
1
app/views/customers/filter_vehicles_by_customer.js.erb
Normal file
1
app/views/customers/filter_vehicles_by_customer.js.erb
Normal file
@@ -0,0 +1 @@
|
|||||||
|
$('select#issue_vehicles_id').html('<%= j content_tag(:option,'',:value=>"")+options_from_collection_for_select(@filtered_vehicles, :id, :to_s) %>');
|
||||||
@@ -1,10 +1,4 @@
|
|||||||
<h1>Customers</h1>
|
<h2>Customers <span style="float:right"> <%= render :partial => 'customers/search' %> </span> </h2>
|
||||||
<br/>
|
|
||||||
<%= form_tag(customers_path, :method => "get", id: "search-form") do %>
|
|
||||||
<%= text_field_tag :search, params[:search], placeholder: "Search Customers" %>
|
|
||||||
<%= submit_tag "Search" %>
|
|
||||||
<% end %>
|
|
||||||
<br/>
|
|
||||||
<% if @customers.present? %>
|
<% if @customers.present? %>
|
||||||
<br/>
|
<br/>
|
||||||
<% @customers.each do |c| %>
|
<% @customers.each do |c| %>
|
||||||
@@ -15,6 +9,8 @@
|
|||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
|
<p>Matching <%= @customers.count %> Customers </p>
|
||||||
|
|
||||||
<div class="actions">
|
<div class="actions">
|
||||||
<%= will_paginate @customers %>
|
<%= will_paginate @customers %>
|
||||||
</div>
|
</div>
|
||||||
@@ -24,5 +20,5 @@
|
|||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<%= Customer.count %> Customers - <b>Last Sync: </b> <%= Qbo.last_sync if Qbo.exists? %>
|
<%= render :partial => 'qbo/stats' %>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
<h1>New Customer</h1>
|
<h2>New Customer</h2>
|
||||||
<br/>
|
<br/>
|
||||||
<%= render :partial => 'customers/form' %>
|
<%= render :partial => 'customers/form' %>
|
||||||
|
|||||||
@@ -1,12 +1,26 @@
|
|||||||
<h1>Customer #<%= @customer.id %></h1>
|
<div id="content">
|
||||||
<br/>
|
<h2>Customer #<%= @customer.id %> - <%= @customer.name %> <span style="float:right"> <%= render :partial => 'customers/search' %> </span> </h2>
|
||||||
<h2>Details:</h2>
|
<br/>
|
||||||
<%= render :partial => 'customers/details', locals: {customer: @customer} %>
|
|
||||||
<br/>
|
<div class="subject">
|
||||||
<h2>Vehicles:</h2>
|
<div><h3>Details:</h3></div>
|
||||||
<%= render :partial => 'vehicles/list' %>
|
</div>
|
||||||
<%= button_to "New Vehicle", new_customer_vehicle_path(@customer), method: :get %>
|
|
||||||
<br/>
|
<div class="attributes">
|
||||||
<br/>
|
|
||||||
<h2>Issues:</h2>
|
<div class="splitcontent">
|
||||||
<%= render :partial => 'issues/list_simple', locals: {issues: @issues} %>
|
<div class="splitcontentleft">
|
||||||
|
<%= render :partial => 'customers/details', locals: {customer: @customer} %>
|
||||||
|
</div>
|
||||||
|
<div class="splitcontentleft">
|
||||||
|
<h4>Vehicles:</h4>
|
||||||
|
<%= render :partial => 'vehicles/list' %>
|
||||||
|
<%= button_to "New Vehicle", new_customer_vehicle_path(@customer), method: :get %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<br/>
|
||||||
|
<h2>Issues:</h2>
|
||||||
|
<%= render :partial => 'issues/list_simple', locals: {issues: @issues} %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
<div class="subject">
|
<div class="subject">
|
||||||
<%= render_issue_subject_with_tree(@issue) %>
|
<%= render_issue_subject_with_tree(@issue) %>
|
||||||
|
This customer link expires in <%= distance_of_time_in_words(Time.now, @token.expires_at) %>
|
||||||
</div>
|
</div>
|
||||||
<p class="author">
|
<p class="author">
|
||||||
<%= authoring @issue.created_on, @issue.author %>.
|
<%= authoring @issue.created_on, @issue.author %>.
|
||||||
@@ -41,13 +42,13 @@
|
|||||||
rows.right l(:field_estimated_hours), issue_estimated_hours_details(@issue), :class => 'estimated-hours'
|
rows.right l(:field_estimated_hours), issue_estimated_hours_details(@issue), :class => 'estimated-hours'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if User.current.allowed_to_view_all_time_entries?(@project)
|
#if User.current.allowed_to_view_all_time_entries?(@project)
|
||||||
if @issue.total_spent_hours > 0
|
if @issue.total_spent_hours > 0
|
||||||
rows.right l(:label_spent_time), issue_spent_hours_details(@issue), :class => 'spent-time'
|
rows.right l(:label_spent_time), issue_spent_hours_details(@issue), :class => 'spent-time'
|
||||||
end
|
end
|
||||||
end
|
#end
|
||||||
end %>
|
end %>
|
||||||
<%= render_custom_fields_rows(@issue) %>
|
<%= render_full_width_custom_fields_rows(@issue) %>
|
||||||
<%= call_hook(:view_issues_show_details_bottom, :issue => @issue) %>
|
<%= call_hook(:view_issues_show_details_bottom, :issue => @issue) %>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
29
app/views/issues/_list_simple.html.erb
Normal file
29
app/views/issues/_list_simple.html.erb
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
<% if issues && issues.any? %>
|
||||||
|
<%= form_tag({}) do %>
|
||||||
|
<table class="list issues">
|
||||||
|
<thead><tr>
|
||||||
|
<th>#</th>
|
||||||
|
<th><%=l(:field_project)%></th>
|
||||||
|
<th><%=l(:field_tracker)%></th>
|
||||||
|
<th><%=l(:field_subject)%></th>
|
||||||
|
</tr></thead>
|
||||||
|
<tbody>
|
||||||
|
<% for issue in issues %>
|
||||||
|
<tr id="issue-<%= h(issue.id) %>" class="hascontextmenu <%= cycle('odd', 'even') %> <%= issue.css_classes %>">
|
||||||
|
<td class="id">
|
||||||
|
<%= check_box_tag("ids[]", issue.id, false, :style => 'display:none;', :id => nil) %>
|
||||||
|
<%= link_to(issue.id, issue_path(issue)) %>
|
||||||
|
</td>
|
||||||
|
<td class="project"><%= link_to_project(issue.project) %></td>
|
||||||
|
<td class="tracker"><%= issue.tracker %></td>
|
||||||
|
<td class="subject">
|
||||||
|
<%= link_to(issue.subject.truncate(60), issue_path(issue)) %> (<%= issue.status %>)
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<% end %>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<% end %>
|
||||||
|
<% else %>
|
||||||
|
<p class="nodata"><%= l(:label_no_data) %></p>
|
||||||
|
<% end %>
|
||||||
1
app/views/qbo/_last_sync.html.erb
Normal file
1
app/views/qbo/_last_sync.html.erb
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<b>Last Sync: </b> <%= Qbo.last_sync if Qbo.exists? %>
|
||||||
@@ -20,14 +20,6 @@ intuit.ipp.anywhere.setup({menuProxy: '/path/to/blue-dot', grantUrl: '<%= qbo_au
|
|||||||
|
|
||||||
<table >
|
<table >
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
|
||||||
<th>Edmunds API Key</th>
|
|
||||||
<td>
|
|
||||||
<input type="text" style="width:350px" id="settingsEdmundsAPIKey"
|
|
||||||
value="<%= settings['settingsEdmundsAPIKey'] %>"
|
|
||||||
name="settings[settingsEdmundsAPIKey]" >
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<th>Intuit QBO OAuth Consumer Key</th>
|
<th>Intuit QBO OAuth Consumer Key</th>
|
||||||
|
|||||||
1
app/views/qbo/_stats.html.erb
Normal file
1
app/views/qbo/_stats.html.erb
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<%= Customer.count %> Customers - <%= render :partial => 'qbo/last_sync' %>
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<th>VIN</th>
|
<th>VIN</th>
|
||||||
<td><%= vehicle.vin %></td>
|
<td><%= @vin[0] if @vin %><b><%=@vin[1] if @vin%></b></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
@@ -21,16 +21,6 @@
|
|||||||
<td><%= vehicle.style %></td>
|
<td><%= vehicle.style %></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr>
|
|
||||||
<th>Drive</th>
|
|
||||||
<td><%= vehicle.drive %></td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
|
||||||
<th>Doors</th>
|
|
||||||
<td><%= vehicle.doors %></td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<th>Notes</th>
|
<th>Notes</th>
|
||||||
<td><%= vehicle.notes %></td>
|
<td><%= vehicle.notes %></td>
|
||||||
@@ -45,7 +35,6 @@
|
|||||||
<td/>
|
<td/>
|
||||||
<td>
|
<td>
|
||||||
|
|
||||||
<%= button_to "New Issue", new_issue_path(:vehicle_id => vehicle.id, :customer_id => vehicle.customer.id), method: :get%>
|
|
||||||
<%= button_to "Edit", edit_vehicle_path(vehicle), method: :get%>
|
<%= button_to "Edit", edit_vehicle_path(vehicle), method: :get%>
|
||||||
<%= button_to "Delete", vehicle, method: :delete, data: {confirm: "You sure?"} %>
|
<%= button_to "Delete", vehicle, method: :delete, data: {confirm: "You sure?"} %>
|
||||||
</td>
|
</td>
|
||||||
|
|||||||
@@ -4,9 +4,10 @@
|
|||||||
|
|
||||||
<%= form_for @vehicle do |f| %>
|
<%= form_for @vehicle do |f| %>
|
||||||
<div class="clearfix">
|
<div class="clearfix">
|
||||||
Customer:
|
Customer:
|
||||||
<div class="input">
|
<div class="input">
|
||||||
<%= f.collection_select :customer_id, @customers, :id, :name, include_blank: true, :selected => @customer, :required => true%>
|
<%= f.autocomplete_field :customer, autocomplete_customer_name_customers_path, :value => @customer.name, :update_elements => {:id => '#customer_id', :value => '#issue_customer'}, :required => true %>
|
||||||
|
<%= f.hidden_field :customer_id, :id => "customer_id", :value => @customer.id %>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -41,14 +42,7 @@
|
|||||||
<div class="clearfix">
|
<div class="clearfix">
|
||||||
Notes:
|
Notes:
|
||||||
<div class="input">
|
<div class="input">
|
||||||
<p>
|
<%= f.text_area :notes, :cols => 60, :rows => 10, :no_label => true %>
|
||||||
<%= content_tag 'span', :id => "issue_description_and_toolbar", :style => (@vehicle.new_record? ? nil : 'display:none') do %>
|
|
||||||
<%= f.text_area :notes,
|
|
||||||
:cols => 60,
|
|
||||||
:rows => 10,
|
|
||||||
:no_label => true %>
|
|
||||||
<% end %>
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,8 @@
|
|||||||
<%= will_paginate @vehicles %>
|
<%= will_paginate @vehicles %>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<p>Matching <%= @vehicles.count %> Vehicles </p>
|
||||||
|
|
||||||
<% else %>
|
<% else %>
|
||||||
<p>There are no vehicles containing the term(s) <%= params[:search] %>.</p>
|
<p>There are no vehicles containing the term(s) <%= params[:search] %>.</p>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|||||||
4
app/views/vehicles/_search.html.erb
Normal file
4
app/views/vehicles/_search.html.erb
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<%= form_tag(vehicles_path, :method => "get", id: "search-form") do %>
|
||||||
|
<%= text_field_tag :search, params[:search], placeholder: "Search Vehicles by VIN" %>
|
||||||
|
<%= submit_tag "Search" %>
|
||||||
|
<% end %>
|
||||||
@@ -1,9 +1,4 @@
|
|||||||
<h1>Customer Vehicles</h1>
|
<h2>Customer Vehicles <span style="float:right"> <%= render :partial => 'vehicles/search' %> </span> </h2>
|
||||||
<br/>
|
<br/>
|
||||||
|
|
||||||
<%= form_tag(vehicles_path, :method => "get", id: "search-form") do %>
|
|
||||||
<%= text_field_tag :search, params[:search], placeholder: "Search Vehicles by VIN" %>
|
|
||||||
<%= submit_tag "Search" %>
|
|
||||||
<% end %>
|
|
||||||
|
|
||||||
<%= render :partial => 'vehicles/list' %>
|
<%= render :partial => 'vehicles/list' %>
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
<h1>New Customer Vehicle</h1>
|
<h2>New Customer Vehicle</h2>
|
||||||
<br/>
|
<br/>
|
||||||
<%= render :partial => 'vehicles/form' %>
|
<%= render :partial => 'vehicles/form' %>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<h1>Vehicle #<%=@vehicle.id%> </h1>
|
<h2>Vehicle #<%=@vehicle.id%> <span style="float:right"> <%= render :partial => 'customers/search' %> </span> </h2>
|
||||||
<br/>
|
<br/>
|
||||||
|
|
||||||
<div style="text-align: left; width:90%;">
|
<div style="text-align: left; width:90%;">
|
||||||
|
|||||||
18
app/workers/email_worker.rb
Normal file
18
app/workers/email_worker.rb
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
#The MIT License (MIT)
|
||||||
|
#
|
||||||
|
#Copyright (c) 2017 rick barrette
|
||||||
|
#
|
||||||
|
#Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
#
|
||||||
|
#The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
#
|
||||||
|
#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
# This sidekiq worker class will handle emailing weekly time reports
|
||||||
|
class EmailWorker
|
||||||
|
include Sidekiq::Worker
|
||||||
|
|
||||||
|
def perform()
|
||||||
|
# email something
|
||||||
|
end
|
||||||
|
end
|
||||||
23
assets/javascripts/application.js
Normal file
23
assets/javascripts/application.js
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
$(function() {
|
||||||
|
$("input#issue_customer_id").on("change", function() {
|
||||||
|
$.ajax({
|
||||||
|
url: "/filter_vehicles_by_customer",
|
||||||
|
type: "GET",
|
||||||
|
data: { selected_customer: $("input#issue_customer_id").val() }
|
||||||
|
});
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: "/filter_estimates_by_customer",
|
||||||
|
type: "GET",
|
||||||
|
data: { selected_customer: $("input#issue_customer_id").val() }
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$("input#project_customer_id").on("change", function() {
|
||||||
|
$.ajax({
|
||||||
|
url: "/filter_vehicles_by_customer",
|
||||||
|
type: "GET",
|
||||||
|
data: { selected_customer: $("input#project_customer_id").val() }
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
1
assets/javascripts/autocomplete-rails.js
Normal file
1
assets/javascripts/autocomplete-rails.js
Normal file
@@ -0,0 +1 @@
|
|||||||
|
!function(t){t.fn.railsAutocomplete=function(e){var a=function(){this.railsAutoCompleter||(this.railsAutoCompleter=new t.railsAutocomplete(this))};if(void 0!==t.fn.on){if(!e)return;return t(document).on("focus",e,a)}return this.live("focus",a)},t.railsAutocomplete=function(t){var e=t;this.init(e)},t.railsAutocomplete.options={showNoMatches:!0,noMatchesLabel:"no existing match"},t.railsAutocomplete.fn=t.railsAutocomplete.prototype={railsAutocomplete:"0.0.1"},t.railsAutocomplete.fn.extend=t.railsAutocomplete.extend=t.extend,t.railsAutocomplete.fn.extend({init:function(e){function a(t){return t.split(e.delimiter)}function i(t){return a(t).pop().replace(/^\s+/,"")}e.delimiter=t(e).attr("data-delimiter")||null,e.min_length=t(e).attr("data-min-length")||t(e).attr("min-length")||2,e.append_to=t(e).attr("data-append-to")||null,e.autoFocus=t(e).attr("data-auto-focus")||!1,t(e).autocomplete({appendTo:e.append_to,autoFocus:e.autoFocus,delay:t(e).attr("delay")||0,source:function(a,r){var n=this.element[0],o={term:i(a.term)};t(e).attr("data-autocomplete-fields")&&t.each(t.parseJSON(t(e).attr("data-autocomplete-fields")),function(e,a){o[e]=t(a).val()}),t.getJSON(t(e).attr("data-autocomplete"),o,function(){var a={};t.extend(a,t.railsAutocomplete.options),t.each(a,function(i,r){if(a.hasOwnProperty(i)){var n=t(e).attr("data-"+i);a[i]=n?n:r}}),0==arguments[0].length&&t.inArray(a.showNoMatches,[!0,"true"])>=0&&(arguments[0]=[],arguments[0][0]={id:"",label:a.noMatchesLabel}),t(arguments[0]).each(function(a,i){var r={};r[i.id]=i,t(e).data(r)}),r.apply(null,arguments),t(n).trigger("railsAutocomplete.source",arguments)})},change:function(e,a){if(t(this).is("[data-id-element]")&&""!==t(t(this).attr("data-id-element")).val()&&(t(t(this).attr("data-id-element")).val(a.item?a.item.id:"").trigger("change"),t(this).attr("data-update-elements"))){var i=t.parseJSON(t(this).attr("data-update-elements")),r=a.item?t(this).data(a.item.id.toString()):{};if(i&&""===t(i.id).val())return;for(var n in i){var o=t(i[n]);o.is(":checkbox")?null!=r[n]&&o.prop("checked",r[n]):o.val(a.item?r[n]:"").trigger("change")}}},search:function(){var t=i(this.value);return t.length<e.min_length?!1:void 0},focus:function(){return!1},select:function(i,r){if(r.item.value=r.item.value.toString(),-1!=r.item.value.toLowerCase().indexOf("no match")||-1!=r.item.value.toLowerCase().indexOf("too many results"))return t(this).trigger("railsAutocomplete.noMatch",r),!1;var n=a(this.value);if(n.pop(),n.push(r.item.value),null!=e.delimiter)n.push(""),this.value=n.join(e.delimiter);else if(this.value=n.join(""),t(this).attr("data-id-element")&&t(t(this).attr("data-id-element")).val(r.item.id).trigger("change"),t(this).attr("data-update-elements")){var o=r.item,l=-1!=r.item.value.indexOf("Create New")?!0:!1,u=t.parseJSON(t(this).attr("data-update-elements"));for(var s in u)"checkbox"===t(u[s]).attr("type")?o[s]===!0||1===o[s]?t(u[s]).attr("checked","checked"):t(u[s]).removeAttr("checked"):l&&o[s]&&-1==o[s].indexOf("Create New")||!l?t(u[s]).val(o[s]).trigger("change"):t(u[s]).val("").trigger("change")}var c=this.value;return t(this).bind("keyup.clearId",function(){t.trim(t(this).val())!=t.trim(c)&&(t(t(this).attr("data-id-element")).val("").trigger("change"),t(this).unbind("keyup.clearId"))}),t(e).trigger("railsAutocomplete.select",r),!1}}),t(e).trigger("railsAutocomplete.init")}}),t(document).ready(function(){t("input[data-autocomplete]").railsAutocomplete("input[data-autocomplete]")})}(jQuery);
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
$("#issue_vehicles_id").empty()
|
|
||||||
.append("<%= escape_javascript(render(:partial => @vehicles)) %>")
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
|
|
||||||
function customerSelected() {
|
|
||||||
customer_id = $('issue_customer_id').getValue();
|
|
||||||
console.log(customer_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
document.observe('dom:loaded', function() {
|
|
||||||
customerSelected();
|
|
||||||
$('issue_customer_id').observe('change', customerSelected);
|
|
||||||
});
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
Edmunds::Api.configure do |config|
|
|
||||||
config.api_key = '2dheutzvhxs28dzukx5tgu47'
|
|
||||||
end
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
#The MIT License (MIT)
|
#The MIT License (MIT)
|
||||||
#
|
#
|
||||||
#Copyright (c) 2016 rick barrette
|
#Copyright (c) 2017 rick barrette
|
||||||
#
|
#
|
||||||
#Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
#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:
|
||||||
#
|
#
|
||||||
@@ -17,6 +17,7 @@ en:
|
|||||||
field_qbo_invoice: "Invoice"
|
field_qbo_invoice: "Invoice"
|
||||||
field_qbo_estimate: "Estimate"
|
field_qbo_estimate: "Estimate"
|
||||||
field_vehicles: "Vehicle"
|
field_vehicles: "Vehicle"
|
||||||
|
field_vehicle: "Vehicle"
|
||||||
field_vin: "VIN"
|
field_vin: "VIN"
|
||||||
field_notes: "Notes"
|
field_notes: "Notes"
|
||||||
field_qbo_billed: "Billed"
|
field_qbo_billed: "Billed"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#The MIT License (MIT)
|
#The MIT License (MIT)
|
||||||
#
|
#
|
||||||
#Copyright (c) 2016 rick barrette
|
#Copyright (c) 2017 rick barrette
|
||||||
#
|
#
|
||||||
#Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
#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:
|
||||||
#
|
#
|
||||||
@@ -34,12 +34,15 @@ resources :payments
|
|||||||
#webhook
|
#webhook
|
||||||
post 'qbo/webhook', :to => 'qbo#qbo_webhook'
|
post 'qbo/webhook', :to => 'qbo#qbo_webhook'
|
||||||
|
|
||||||
#ajax
|
#java script routes
|
||||||
get "update_vehicles" => 'vehicles#update_vehicles', as: 'update_vehicles'
|
get 'filter_vehicles_by_customer' => 'customers#filter_vehicles_by_customer'
|
||||||
|
get 'filter_estimates_by_customer' => 'customers#filter_estimates_by_customer'
|
||||||
|
get 'filter_invoices_by_customer' => 'customers#filter_invoices_by_customer'
|
||||||
|
|
||||||
# Nest Vehicles under customers
|
# Nest Vehicles under customers
|
||||||
resources :customers do
|
resources :customers do
|
||||||
resources :vehicles
|
resources :vehicles
|
||||||
|
get :autocomplete_customer_name, :on => :collection
|
||||||
end
|
end
|
||||||
|
|
||||||
#allow for just vehicles too
|
#allow for just vehicles too
|
||||||
|
|||||||
16
db/migrate/024_update_invoices_and_estimates.rb
Normal file
16
db/migrate/024_update_invoices_and_estimates.rb
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
#The MIT License (MIT)
|
||||||
|
#
|
||||||
|
#Copyright (c) 2017 rick barrette
|
||||||
|
#
|
||||||
|
#Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
#
|
||||||
|
#The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
#
|
||||||
|
#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
class UpdateInvoicesAndEstimates < ActiveRecord::Migration
|
||||||
|
def change
|
||||||
|
add_reference :qbo_invoices, :customer, index: true
|
||||||
|
add_reference :qbo_estimates, :customer, index: true
|
||||||
|
end
|
||||||
|
end
|
||||||
16
db/migrate/025_update_projects.rb
Normal file
16
db/migrate/025_update_projects.rb
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
#The MIT License (MIT)
|
||||||
|
#
|
||||||
|
#Copyright (c) 2017 rick barrette
|
||||||
|
#
|
||||||
|
#Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
#
|
||||||
|
#The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
#
|
||||||
|
#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
class UpdateProjects < ActiveRecord::Migration
|
||||||
|
def change
|
||||||
|
add_reference :projects, :customer, index: true
|
||||||
|
add_reference :projects, :vehicle, index: true
|
||||||
|
end
|
||||||
|
end
|
||||||
26
db/migrate/026_create_line_items.rb
Normal file
26
db/migrate/026_create_line_items.rb
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
#The License
|
||||||
|
#
|
||||||
|
#Copyright (c) 2018 Rick Barrette - All Rights Reserved
|
||||||
|
#
|
||||||
|
#Unauthorized copying of this software and associated documentation files (the "Software"), via any medium is strictly prohibited.
|
||||||
|
#
|
||||||
|
#Proprietary and confidential
|
||||||
|
#
|
||||||
|
#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 CreateLineItems < ActiveRecord::Migration
|
||||||
|
def change
|
||||||
|
create_table :line_items do |t|
|
||||||
|
t.integer :item_id
|
||||||
|
t.float :amount
|
||||||
|
t.string :description
|
||||||
|
t.float :unit_price
|
||||||
|
t.float :quantity
|
||||||
|
t.boolean :billed
|
||||||
|
end
|
||||||
|
|
||||||
|
add_reference :line_items, :issues, index: true
|
||||||
|
end
|
||||||
|
end
|
||||||
41
init.rb
41
init.rb
@@ -1,6 +1,6 @@
|
|||||||
#The MIT License (MIT)
|
#The MIT License (MIT)
|
||||||
#
|
#
|
||||||
#Copyright (c) 2016 rick barrette
|
#Copyright (c) 2017 rick barrette
|
||||||
#
|
#
|
||||||
#Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
#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:
|
||||||
#
|
#
|
||||||
@@ -16,26 +16,26 @@ Redmine::Plugin.register :redmine_qbo do
|
|||||||
require_dependency 'issues_show_hook_listener'
|
require_dependency 'issues_show_hook_listener'
|
||||||
require_dependency 'users_show_hook_listener'
|
require_dependency 'users_show_hook_listener'
|
||||||
require_dependency 'header_footer_hook_listener'
|
require_dependency 'header_footer_hook_listener'
|
||||||
|
require_dependency 'projects_form_hook_listener'
|
||||||
|
require_dependency 'view_hook_listener'
|
||||||
|
|
||||||
# Patches to the Redmine core. Will not work in development mode
|
# Patches to the Redmine core. Will not work in development mode
|
||||||
require_dependency 'issue_patch'
|
require_dependency 'issue_patch'
|
||||||
|
require_dependency 'project_patch'
|
||||||
require_dependency 'user_patch'
|
require_dependency 'user_patch'
|
||||||
require_dependency 'query_patch'
|
require_dependency 'query_patch'
|
||||||
require_dependency 'time_entry_query_patch'
|
require_dependency 'time_entry_query_patch'
|
||||||
require_dependency 'pdf_patch'
|
require_dependency 'pdf_patch'
|
||||||
|
require_dependency 'attachments_controller_patch'
|
||||||
Rails.configuration.to_prepare do
|
|
||||||
Redmine::Search.available_search_types << 'customers'
|
|
||||||
end
|
|
||||||
|
|
||||||
name 'Redmine Quickbooks Online plugin'
|
name 'Redmine Quickbooks Online plugin'
|
||||||
author 'Rick Barrette'
|
author 'Rick Barrette'
|
||||||
description 'This is a plugin for Redmine to intergrate with Quickbooks Online to allow for seamless intergration CRM and invoicing of completed issues'
|
description 'This is a plugin for Redmine to intergrate with Quickbooks Online to allow for seamless intergration CRM and invoicing of completed issues'
|
||||||
version '0.4.1'
|
version '0.7.0'
|
||||||
url 'https://github.com/rickbarrette/redmine_qbo'
|
url 'https://github.com/rickbarrette/redmine_qbo'
|
||||||
author_url 'http://rickbarrette.org'
|
author_url 'http://rickbarrette.org'
|
||||||
settings :default => {'empty' => true}, :partial => 'qbo/settings'
|
settings :default => {'empty' => true}, :partial => 'qbo/settings'
|
||||||
|
|
||||||
# Add safe attributes
|
# Add safe attributes
|
||||||
Issue.safe_attributes 'customer_id'
|
Issue.safe_attributes 'customer_id'
|
||||||
Issue.safe_attributes 'qbo_item_id'
|
Issue.safe_attributes 'qbo_item_id'
|
||||||
@@ -44,24 +44,23 @@ Redmine::Plugin.register :redmine_qbo do
|
|||||||
Issue.safe_attributes 'vehicles_id'
|
Issue.safe_attributes 'vehicles_id'
|
||||||
User.safe_attributes 'qbo_employee_id'
|
User.safe_attributes 'qbo_employee_id'
|
||||||
TimeEntry.safe_attributes 'qbo_billed'
|
TimeEntry.safe_attributes 'qbo_billed'
|
||||||
|
Project.safe_attributes 'customer_id'
|
||||||
|
Project.safe_attributes 'vehicle_id'
|
||||||
|
|
||||||
# We are playing in the sandbox
|
# We are playing in the sandbox
|
||||||
#Quickbooks.sandbox_mode = true
|
#Quickbooks.sandbox_mode = true
|
||||||
|
|
||||||
# set per_page globally
|
# set per_page globally
|
||||||
WillPaginate.per_page = 10
|
WillPaginate.per_page = 20
|
||||||
|
|
||||||
|
permission :view_customers, :customers => :index, :public => false
|
||||||
|
permission :add_customers, :customers => :new, :public => false
|
||||||
|
permission :view_payments, :payments => :index, :public => false
|
||||||
|
permission :add_payments, :payments => :new, :public => false
|
||||||
|
permission :view_vehicles, :payments => :new, :public => false
|
||||||
|
|
||||||
# Register QBO top menu item
|
# Register QBO top menu item
|
||||||
#menu :top_menu, :qbo, { :controller => :qbo, :action => :index }, :caption => 'Quickbooks', :if => Proc.new { User.current.admin? }
|
menu :top_menu, :customers, { :controller => :customers, :action => :index }, :caption => 'Customers', :if => Proc.new {User.current.logged?}
|
||||||
menu :top_menu, :customers, { :controller => :customers, :action => :index }, :caption => 'Customers', :if => Proc.new { User.current.logged? }
|
|
||||||
menu :top_menu, :vehicles, { :controller => :vehicles, :action => :index }, :caption => 'Vehicles', :if => Proc.new { User.current.logged? }
|
menu :top_menu, :vehicles, { :controller => :vehicles, :action => :index }, :caption => 'Vehicles', :if => Proc.new { User.current.logged? }
|
||||||
|
|
||||||
menu :application_menu, :new_customer, { :controller => :customers, :action => :new }, :caption => 'New Customer', :if => Proc.new { User.current.logged? }
|
|
||||||
menu :application_menu, :new_payment, { :controller => :payments, :action => :new }, :caption => 'New Payment', :if => Proc.new { User.current.logged? }
|
|
||||||
|
|
||||||
permission :customers, { :customers => [:index, :new] }, :public => false
|
|
||||||
menu :project_menu, :customers, { :controller => 'customers', :action => 'new' }, :caption => 'New Customer', :after => :new_issue, :param => :project_id
|
|
||||||
|
|
||||||
permission :payments, { :payments => [:index, :new] }, :public => false
|
|
||||||
menu :project_menu, :payments, { :controller => 'payments', :action => 'new' }, :caption => 'New Payment', :after => :customers, :param => :project_id
|
|
||||||
end
|
end
|
||||||
|
|||||||
38
lib/attachments_controller_patch.rb
Normal file
38
lib/attachments_controller_patch.rb
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
#The MIT License (MIT)
|
||||||
|
#
|
||||||
|
#Copyright (c) 2017 rick barrette
|
||||||
|
#
|
||||||
|
#Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
#
|
||||||
|
#The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
#
|
||||||
|
#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
require_dependency 'attachments_controller'
|
||||||
|
|
||||||
|
module AttachmentsControllerPatch
|
||||||
|
|
||||||
|
def self.included(base) # :nodoc:
|
||||||
|
base.extend(ClassMethods)
|
||||||
|
|
||||||
|
base.send(:include, InstanceMethods)
|
||||||
|
|
||||||
|
# Same as typing in the class
|
||||||
|
base.class_eval do
|
||||||
|
unloadable # Send unloadable so it will not be unloaded in development
|
||||||
|
|
||||||
|
skip_before_action :read_authorize
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
module ClassMethods
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
module InstanceMethods
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Add module to AttachmentsController
|
||||||
|
AttachmentsController.send(:include, AttachmentsControllerPatch)
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
#The MIT License (MIT)
|
#The MIT License (MIT)
|
||||||
#
|
#
|
||||||
#Copyright (c) 2016 rick barrette
|
#Copyright (c) 2017 rick barrette
|
||||||
#
|
#
|
||||||
#Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
#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:
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#The MIT License (MIT)
|
#The MIT License (MIT)
|
||||||
#
|
#
|
||||||
#Copyright (c) 2016 rick barrette
|
#Copyright (c) 2017 rick barrette
|
||||||
#
|
#
|
||||||
#Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
#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:
|
||||||
#
|
#
|
||||||
@@ -41,7 +41,9 @@ module IssuePatch
|
|||||||
|
|
||||||
# Create billable time entries
|
# Create billable time entries
|
||||||
def bill_time
|
def bill_time
|
||||||
|
|
||||||
|
return if assigned_to.nil?
|
||||||
|
|
||||||
# Get unbilled time entries
|
# Get unbilled time entries
|
||||||
spent_time = time_entries.where(qbo_billed: [false, nil])
|
spent_time = time_entries.where(qbo_billed: [false, nil])
|
||||||
spent_hours ||= spent_time.sum(:hours) || 0
|
spent_hours ||= spent_time.sum(:hours) || 0
|
||||||
@@ -72,7 +74,7 @@ module IssuePatch
|
|||||||
item = item_service.query("SELECT * FROM Item WHERE Name = '#{key}' ").first
|
item = item_service.query("SELECT * FROM Item WHERE Name = '#{key}' ").first
|
||||||
next if item.nil?
|
next if item.nil?
|
||||||
|
|
||||||
time_entry.description = "#{tracker} ##{id}: #{subject} #{"(Partial)" if not closed?}"
|
time_entry.description = "#{tracker} ##{id}: #{subject} #{"(Partial @ #{done_ratio}%)" if not closed?}"
|
||||||
# TODO entry.user.qbo_employee.id
|
# TODO entry.user.qbo_employee.id
|
||||||
time_entry.employee_id = assigned_to.qbo_employee_id
|
time_entry.employee_id = assigned_to.qbo_employee_id
|
||||||
time_entry.customer_id = customer_id
|
time_entry.customer_id = customer_id
|
||||||
@@ -93,7 +95,7 @@ module IssuePatch
|
|||||||
|
|
||||||
# Create a shareable link for a customer
|
# Create a shareable link for a customer
|
||||||
def share_token
|
def share_token
|
||||||
CustomerToken.create(:expires_at => Time.now + 24.hours, :issue_id => id)
|
CustomerToken.create(:expires_at => Time.now + 1.month, :issue_id => id)
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#The MIT License (MIT)
|
#The MIT License (MIT)
|
||||||
#
|
#
|
||||||
#Copyright (c) 2016 rick barrette
|
#Copyright (c) 2017 rick barrette
|
||||||
#
|
#
|
||||||
#Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
#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:
|
||||||
#
|
#
|
||||||
@@ -12,8 +12,8 @@ class IssuesFormHookListener < Redmine::Hook::ViewListener
|
|||||||
|
|
||||||
# Load the javascript
|
# Load the javascript
|
||||||
def view_layouts_base_html_head(context = {})
|
def view_layouts_base_html_head(context = {})
|
||||||
js = javascript_include_tag 'vehicles', :plugin => 'redmine_qbo'
|
js = javascript_include_tag 'application', :plugin => 'redmine_qbo'
|
||||||
#js += javascript_include_tag 'update_vehicles', :plugin => 'redmine_qbo'
|
js += javascript_include_tag 'autocomplete-rails', :plugin => 'redmine_qbo'
|
||||||
return js
|
return js
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -21,31 +21,38 @@ class IssuesFormHookListener < Redmine::Hook::ViewListener
|
|||||||
# 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={})
|
||||||
f = context[:form]
|
f = context[:form]
|
||||||
|
|
||||||
|
#check project level customer/vehicle ownership first
|
||||||
|
selected_customer = context[:project].customer ? context[:project].customer.id : nil
|
||||||
|
selected_vehicle = context[:project].vehicle ? context[:project].vehicle.id : nil
|
||||||
|
|
||||||
# Check to see if there is a quickbooks user attached to the issue
|
# Check to see if there is a quickbooks user attached to the issue
|
||||||
selected_customer = context[:issue].customer ? context[:issue].customer.id : nil
|
selected_customer = context[:issue].customer ? context[:issue].customer.id : nil
|
||||||
selected_estimate = context[:issue].qbo_estimate ? context[:issue].qbo_estimate.id : nil
|
selected_estimate = context[:issue].qbo_estimate ? context[:issue].qbo_estimate.id : nil
|
||||||
selected_vehicle = context[:issue].vehicles_id ? context[:issue].vehicles_id : nil
|
selected_vehicle = context[:issue].vehicles_id ? context[:issue].vehicles_id : nil
|
||||||
|
|
||||||
# Load customer information without callbacks
|
# Load customer information
|
||||||
customer = Customer.find_by_id(selected_customer) if selected_customer
|
customer = Customer.find_by_id(selected_customer) if selected_customer
|
||||||
select_customer = f.select :customer_id,
|
search_customer = f.autocomplete_field :customer, autocomplete_customer_name_customers_path, :selected => selected_customer, :update_elements => {:id => '#issue_customer_id', :value => '#issue_customer'}
|
||||||
Customer.all.pluck(:name, :id).sort,
|
customer_id = f.hidden_field :customer_id, :id => "issue_customer_id"
|
||||||
:selected => selected_customer,
|
|
||||||
include_blank: true,
|
|
||||||
onchange: "$customerSelected;"
|
|
||||||
|
|
||||||
# Generate the drop down list of quickbooks extimates
|
|
||||||
select_estimate = f.select :qbo_estimate_id, QboEstimate.all.pluck(:doc_number, :id).sort! {|x, y| y <=> x}, :selected => selected_estimate, include_blank: true
|
|
||||||
|
|
||||||
if context[:issue].customer
|
if context[:issue].customer
|
||||||
vehicles = customer.vehicles.pluck(:name, :id).sort!
|
if customer.vehicles
|
||||||
|
vehicles = customer.vehicles.pluck(:name, :id)
|
||||||
|
else
|
||||||
|
vehicles = [nil].compact
|
||||||
|
end
|
||||||
|
estimates = customer.qbo_estimates.pluck(:doc_number, :id).sort! {|x, y| y <=> x}
|
||||||
else
|
else
|
||||||
vehicles = Vehicle.all.order(:name).pluck(:name, :id)
|
vehicles = [nil].compact
|
||||||
|
estimates = [nil].compact
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Generate the drop down list of quickbooks extimates
|
||||||
|
select_estimate = f.select :qbo_estimate_id, estimates, :selected => selected_estimate, include_blank: true
|
||||||
|
|
||||||
vehicle = f.select :vehicles_id, vehicles, :selected => selected_vehicle, include_blank: true
|
vehicle = f.select :vehicles_id, vehicles, :selected => selected_vehicle, include_blank: true
|
||||||
|
|
||||||
return "<p>#{select_customer}</p> <p>#{select_estimate}</p> <p>#{vehicle}</p>"
|
return "<p><label for=\"issue_customer\">Customer</label>#{search_customer} #{customer_id}</p> <p>#{select_estimate}</p> <p>#{vehicle}</p>"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#The MIT License (MIT)
|
#The MIT License (MIT)
|
||||||
#
|
#
|
||||||
#Copyright (c) 2016 rick barrette
|
#Copyright (c) 2017 rick barrette
|
||||||
#
|
#
|
||||||
#Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
#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:
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#The MIT License (MIT)
|
#The MIT License (MIT)
|
||||||
#
|
#
|
||||||
#Copyright (c) 2016 rick barrette
|
#Copyright (c) 2017 rick barrette
|
||||||
#
|
#
|
||||||
#Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
#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:
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ module IssuesPdfHelperPatch
|
|||||||
vin = v ? v.vin : nil
|
vin = v ? v.vin : nil
|
||||||
notes = v ? v.notes : nil
|
notes = v ? v.notes : nil
|
||||||
left << [l(:field_vehicles), vehicle]
|
left << [l(:field_vehicles), vehicle]
|
||||||
left << [l(:field_vin), vin.gsub(/(.{9})/, '\1 ')]
|
left << [l(:field_vin), vin ? vin.gsub(/(.{9})/, '\1 ') : nil]
|
||||||
#left << [l(:field_notes), notes]
|
#left << [l(:field_notes), notes]
|
||||||
|
|
||||||
right = []
|
right = []
|
||||||
|
|||||||
40
lib/project_patch.rb
Normal file
40
lib/project_patch.rb
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
#The MIT License (MIT)
|
||||||
|
#
|
||||||
|
#Copyright (c) 2017 rick barrette
|
||||||
|
#
|
||||||
|
#Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
#
|
||||||
|
#The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
#
|
||||||
|
#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
require_dependency 'project'
|
||||||
|
|
||||||
|
# Patches Redmine's Projects dynamically.
|
||||||
|
# Adds a relationships
|
||||||
|
module ProjectPatch
|
||||||
|
|
||||||
|
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 :customer, primary_key: :id
|
||||||
|
belongs_to :vehicle, primary_key: :id
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
module ClassMethods
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
module InstanceMethods
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
# Add module to Project
|
||||||
|
Project.send(:include, ProjectPatch)
|
||||||
36
lib/projects_form_hook_listener.rb
Normal file
36
lib/projects_form_hook_listener.rb
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
#The MIT License (MIT)
|
||||||
|
#
|
||||||
|
#Copyright (c) 2017 rick barrette
|
||||||
|
#
|
||||||
|
#Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
#
|
||||||
|
#The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
#
|
||||||
|
#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
class ProjectsFormHookListener < Redmine::Hook::ViewListener
|
||||||
|
|
||||||
|
# Edit Project Form
|
||||||
|
def view_projects_form(context={})
|
||||||
|
f = context[:form]
|
||||||
|
|
||||||
|
# Check to see if there is a quickbooks user attached to the issue
|
||||||
|
selected_customer = context[:project].customer ? context[:project].customer : nil
|
||||||
|
selected_vehicle = context[:project].vehicle_id ? context[:project].vehicle_id : nil
|
||||||
|
|
||||||
|
# Load customer information
|
||||||
|
customer = Customer.find_by_id(selected_customer) if selected_customer
|
||||||
|
search_customer = f.autocomplete_field :customer, autocomplete_customer_name_customers_path, :selected => selected_customer, :update_elements => {:id => '#project_customer_id', :value => '#project_customer'}
|
||||||
|
customer_id = f.hidden_field :customer_id, :id => "project_customer_id"
|
||||||
|
|
||||||
|
if context[:project].customer
|
||||||
|
vehicles = customer.vehicles.pluck(:name, :id).sort!
|
||||||
|
else
|
||||||
|
vehicles = [nil].compact
|
||||||
|
end
|
||||||
|
|
||||||
|
vehicle = f.select :vehicle_id, vehicles, :selected => selected_vehicle, include_blank: true
|
||||||
|
|
||||||
|
return "<p><label for=\"project_customer\">Customer</label>#{search_customer} #{customer_id}</p> <p>#{vehicle}</p>"
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
#The MIT License (MIT)
|
#The MIT License (MIT)
|
||||||
#
|
#
|
||||||
#Copyright (c) 2016 rick barrette
|
#Copyright (c) 2017 rick barrette
|
||||||
#
|
#
|
||||||
#Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
#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:
|
||||||
#
|
#
|
||||||
@@ -36,7 +36,7 @@ module QueryPatch
|
|||||||
unless @available_columns
|
unless @available_columns
|
||||||
@available_columns = available_columns_without_qbo
|
@available_columns = available_columns_without_qbo
|
||||||
@available_columns << QueryColumn.new(:customer, :sortable => "#{Customer.table_name}.name", :groupable => true, :caption => :field_customer)
|
@available_columns << QueryColumn.new(:customer, :sortable => "#{Customer.table_name}.name", :groupable => true, :caption => :field_customer)
|
||||||
@available_columns << QueryColumn.new(:qbo_billed, :sortable => "#{TimeEntry.table_name}.name", :groupable => true, :caption => :field_qbo_billed)
|
@available_columns << QueryColumn.new(:qbo_billed, :sortable => "#{TimeEntry.table_name}.qbo_billed", :groupable => true, :caption => :field_qbo_billed)
|
||||||
end
|
end
|
||||||
@available_columns
|
@available_columns
|
||||||
end
|
end
|
||||||
@@ -52,16 +52,16 @@ module QueryPatch
|
|||||||
# :order => @available_filters.size + 1},
|
# :order => @available_filters.size + 1},
|
||||||
#}
|
#}
|
||||||
|
|
||||||
qbo_filters = {
|
#qbo_filters = {
|
||||||
"customer_id" => {
|
# "customer_id" => {
|
||||||
:id => :customer_id,
|
# :id => :customer_id,
|
||||||
:type => :list_optional,
|
# :type => :list_optional
|
||||||
:order => @available_filters.size + 1,
|
#:order => @available_filters.size + 1,
|
||||||
#:values => Customer.find(:all).collect { |c| [c.name, c.id.to_s]}
|
#:values => Customer.find(:all).collect { |c| [c.name, c.id.to_s]}
|
||||||
}
|
# }
|
||||||
}
|
#}
|
||||||
|
|
||||||
@available_filters.merge!(qbo_filters)
|
#@available_filters.merge!(qbo_filters)
|
||||||
end
|
end
|
||||||
@available_filters
|
@available_filters
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#The MIT License (MIT)
|
#The MIT License (MIT)
|
||||||
#
|
#
|
||||||
#Copyright (c) 2016 rick barrette
|
#Copyright (c) 2017 rick barrette
|
||||||
#
|
#
|
||||||
#Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
#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:
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#The MIT License (MIT)
|
#The MIT License (MIT)
|
||||||
#
|
#
|
||||||
#Copyright (c) 2016 rick barrette
|
#Copyright (c) 2017 rick barrette
|
||||||
#
|
#
|
||||||
#Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
#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:
|
||||||
#
|
#
|
||||||
@@ -36,4 +36,4 @@ module UserPatch
|
|||||||
end
|
end
|
||||||
|
|
||||||
# Add module to Issue
|
# Add module to Issue
|
||||||
User.send(:include, UserPatch)
|
User.send(:include, UserPatch)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#The MIT License (MIT)
|
#The MIT License (MIT)
|
||||||
#
|
#
|
||||||
#Copyright (c) 2016 rick barrette
|
#Copyright (c) 2017 rick barrette
|
||||||
#
|
#
|
||||||
#Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
#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:
|
||||||
#
|
#
|
||||||
|
|||||||
3
lib/view_hook_listener.rb
Normal file
3
lib/view_hook_listener.rb
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
class ViewHookListener < Redmine::Hook::ViewListener
|
||||||
|
render_on :view_issues_sidebar_issues_bottom, :partial => "customers/sidebar"
|
||||||
|
end
|
||||||
Reference in New Issue
Block a user