306 Commits
0.4.2 ... 0.8.1

Author SHA1 Message Date
d6c114d52b Version 0.8.1 2020-01-05 09:20:23 -05:00
87b8daf283 Fixed expired token check 2020-01-05 09:17:50 -05:00
719abe20a6 Update qbo.rb 2020-01-05 01:22:27 -05:00
4a5b83265d Update qbo.rb 2020-01-05 01:20:23 -05:00
8d103d3fc6 Update qbo.rb 2020-01-05 01:12:48 -05:00
9310f207a3 Update qbo.rb 2020-01-05 01:08:42 -05:00
000b67b329 Added employee 2020-01-05 00:08:00 -05:00
ebee9395ba Update qbo_employee.rb 2020-01-05 00:06:45 -05:00
2cd6731f0c Update qbo_employee.rb 2020-01-05 00:05:25 -05:00
ebdbd25082 Update qbo.rb 2020-01-04 23:45:00 -05:00
18ada91fcd Update qbo.rb 2020-01-04 23:38:46 -05:00
1cf3926585 Update qbo.rb 2020-01-04 23:33:33 -05:00
e776deeece Update qbo.rb 2020-01-04 23:07:53 -05:00
8c2f30949a Update qbo.rb 2020-01-04 23:04:09 -05:00
015a989f72 Update qbo.rb 2020-01-04 22:57:53 -05:00
0d4d5a6136 Update qbo.rb 2020-01-04 22:52:01 -05:00
0364989fe1 Update qbo_controller.rb 2020-01-04 22:46:20 -05:00
fb47eaba0e Update qbo.rb 2020-01-04 22:45:31 -05:00
725d511be5 Update qbo.rb 2020-01-04 22:30:43 -05:00
fd85f296de Update 030_update_qbos_token.rb 2020-01-04 22:16:07 -05:00
9549bb8fe2 Update qbo.rb 2020-01-04 20:24:29 -05:00
6a1c8b0551 Update README.md 2020-01-04 16:09:03 -05:00
086632e804 Version 0.8.0 (OAuth 2.0) 2020-01-04 16:01:16 -05:00
d37ff922fc Update customer.rb 2020-01-04 15:51:04 -05:00
3483efa100 Oauth2 Upgrade 2020-01-04 15:41:15 -05:00
f65eea2820 Oauth2 Upgrade 2020-01-04 15:37:17 -05:00
a4111e0a11 oAuth2 Upgrade 2020-01-04 15:36:36 -05:00
ebe5373d82 Oauth2 Upgrade 2020-01-04 15:34:57 -05:00
5b8c7d42c5 Oauth2 Upgrade 2020-01-04 15:34:04 -05:00
b8fc57d583 Oauth2 Upgrade 2020-01-04 15:31:19 -05:00
7c42197cb1 Oauth2 Upgrade 2020-01-04 15:30:03 -05:00
cc0ffce892 Oauth2 Upgrade 2020-01-04 15:29:18 -05:00
0fd2abbec3 Oauth2 Upgrade 2020-01-04 15:28:43 -05:00
215b219a6d Oauth2 Upgrade 2020-01-04 15:28:04 -05:00
ea71542d81 Oauth2 Upgrade 2020-01-04 15:26:35 -05:00
5dbf486b50 Update qbo_controller.rb 2020-01-04 15:21:14 -05:00
b734125d6b Update qbo_controller.rb 2020-01-04 15:19:31 -05:00
06e6295c6e Update qbo.rb 2020-01-04 14:32:32 -05:00
fd383ad9d4 Update qbo.rb 2020-01-04 14:29:23 -05:00
4eb6c533f1 Update qbo.rb 2020-01-04 14:21:07 -05:00
5af7d73768 Update qbo_controller.rb 2020-01-04 14:18:42 -05:00
1d0ae34261 Update qbo.rb 2020-01-04 14:13:29 -05:00
21656b3e14 Update qbo.rb 2020-01-04 14:09:37 -05:00
131976cd71 Update issue_patch.rb 2020-01-04 14:08:48 -05:00
88c1b9c9a2 Update issue_patch.rb 2020-01-04 14:06:42 -05:00
5ea9aed3cb Update qbo.rb 2020-01-04 14:05:00 -05:00
41e10d9b0e Update qbo.rb 2020-01-04 13:59:09 -05:00
45859bef3e Update qbo.rb 2020-01-04 13:56:38 -05:00
f5c40738dc Update issue_patch.rb 2020-01-04 13:54:29 -05:00
bfa37ee634 Update issue_patch.rb 2020-01-04 13:51:31 -05:00
787b55f3d7 Update qbo.rb 2020-01-04 13:46:13 -05:00
61f882e98c Update qbo.rb 2020-01-04 13:45:00 -05:00
37db0d3d72 Update qbo.rb 2020-01-04 13:31:40 -05:00
4f2dec3069 Update qbo.rb 2020-01-04 13:29:36 -05:00
35a7c3cfeb Create 030_update_qbos_token.rb 2020-01-04 13:28:22 -05:00
cbbaf5a95c Update qbo.rb 2020-01-04 13:22:27 -05:00
647923e5e6 Update 029_update_qbos_types.rb 2020-01-04 13:19:21 -05:00
70ca4e9964 Create 029_update_qbos_types.rb 2020-01-04 13:17:15 -05:00
7fb40ad4a8 Update qbo_controller.rb 2020-01-04 13:09:09 -05:00
36083d23a0 Update qbo_controller.rb 2020-01-04 13:07:36 -05:00
2ec57f2bbf Update qbo_controller.rb 2020-01-04 13:06:23 -05:00
278708e566 Update qbo_controller.rb 2020-01-04 12:47:30 -05:00
23f2b92e8d Update qbo_controller.rb 2020-01-04 12:45:16 -05:00
5d92eeddfb Update qbo_controller.rb 2020-01-04 12:44:05 -05:00
384a8c033c Update qbo_controller.rb 2020-01-04 12:39:23 -05:00
32b12b60f9 Update qbo_controller.rb 2020-01-04 12:33:54 -05:00
93db447239 Update qbo_controller.rb 2020-01-04 12:29:54 -05:00
19a6180e15 Update qbo.rb 2020-01-04 12:26:04 -05:00
3408ee173c Update qbo.rb 2020-01-04 12:25:12 -05:00
b817e842dd Update qbo.rb 2020-01-04 12:23:59 -05:00
51c3b8338e Update qbo.rb 2020-01-04 12:23:05 -05:00
c6a3edfbc1 Update qbo_controller.rb 2020-01-04 12:21:45 -05:00
21d8d90465 Update qbo.rb 2020-01-04 12:21:24 -05:00
04c0fa57c6 Update qbo_controller.rb 2020-01-04 12:17:26 -05:00
f5ad761712 Update qbo_controller.rb 2020-01-04 12:14:54 -05:00
9b80485915 Update qbo.rb 2020-01-04 12:14:05 -05:00
87de865c00 oauth2 2020-01-04 11:51:25 -05:00
1ea27e8511 Only show error flash if errors are not empty 2019-11-12 12:50:44 -05:00
8f0ca00b09 Merge branch 'master' of github.com:rickbarrette/redmine_qbo 2019-11-12 12:45:20 -05:00
859a1d505b always show errors 2019-11-12 12:45:14 -05:00
cd109653a2 Merge branch 'master' of github.com:rickbarrette/redmine_qbo 2019-11-12 12:37:12 -05:00
cab723bbcd Removed styles & removed after find call 2019-11-12 12:36:25 -05:00
3dd712629b added local vin validation 2019-11-12 12:35:54 -05:00
cdf2603e12 Merge branch 'master' of github.com:rickbarrette/redmine_qbo 2019-11-12 12:16:30 -05:00
5df9d324bc Update vehicle.rb 2019-11-12 12:15:59 -05:00
f78c0338b4 Made decode_vin not private 2019-11-12 12:08:04 -05:00
fe6aa7908f Merge branch 'master' of github.com:rickbarrette/redmine_qbo 2019-11-12 11:51:54 -05:00
aa45338e36 Update vehicle.rb 2019-11-11 10:10:23 -05:00
213dca2621 Fixed redicect to :home 2019-07-08 11:30:53 -04:00
fee710d717 Rediect to vehicle if vin is already taken 2019-06-26 11:39:07 -04:00
65eac58f6c Update customer.rb 2019-06-25 12:48:35 -04:00
b4f5112fc3 Create 028_add_customers_mobile_phone_number.rb 2019-06-25 12:46:03 -04:00
fa5dcbf9a9 Fixed redirect to for new vehicles 2019-06-25 12:37:49 -04:00
e0aebb1c23 Update customer.rb 2019-06-25 11:59:08 -04:00
6d176acc2b Update customer.rb 2019-06-25 11:54:26 -04:00
9e9b29fef9 Update 027_add_customers_phone_number.rb 2019-06-25 11:53:40 -04:00
1af846537d Update customer.rb 2019-06-25 11:50:14 -04:00
d6c5daff49 Added phone number 2019-06-25 11:15:57 -04:00
61c76ad80a Create 027_add_customers_phone_number.rb 2019-06-25 10:59:34 -04:00
0d514790fd Moved issue.status.is_closed? check back into issue save hook 2019-03-26 12:15:03 -04:00
748d431d35 Removed controller_issues_edit_before_save hook 2019-03-26 12:11:54 -04:00
87b8d99c41 Working on issue.bill_time 2019-03-26 12:09:38 -04:00
a0da53b6cf Fixed formatting & removed search from heading 2018-10-15 21:10:41 -04:00
02d630c631 Fixed Invoice Link to be HTML safe 2018-10-15 21:07:36 -04:00
15b214c800 Moved html into partial view 2018-10-15 20:57:03 -04:00
1b5e185087 Added nil check 2018-10-15 19:42:41 -04:00
102309600e Merge branch 'master' of github.com:rickbarrette/redmine_qbo 2018-10-15 19:36:09 -04:00
6acc7db91b Changed Customer search to shown on all pages 2018-10-15 19:34:51 -04:00
02898883a8 Update line_item.rb 2018-10-14 23:35:13 -04:00
ce02b70bc3 Update line_items_controler.rb 2018-10-14 23:34:17 -04:00
d4d4a555f8 Forgot to add sidebar files 2018-10-14 23:32:07 -04:00
c2663cd0a0 License update 2018-10-14 23:31:17 -04:00
d48609361f Added customer search to sidebar 2018-10-14 23:27:19 -04:00
70995f6e55 Fixed formating 2018-10-04 20:59:46 -04:00
05a0472939 Changed redirect to :back 2018-10-04 20:57:24 -04:00
cff9f3fde3 Fixed new vehicle add missing customer 2018-09-22 00:29:54 -04:00
e24b704571 Added qbo partial views 2018-09-19 22:57:45 -04:00
4d99f54c79 Added autocomplete to vehicle customer field 2018-09-19 22:33:36 -04:00
e65725c334 Update init.rb 2018-09-19 10:15:13 -04:00
4829daab7c Update new.html.erb 2018-09-19 10:10:54 -04:00
260e9f3e4a Update _list.html.erb 2018-09-19 10:07:52 -04:00
e3ce2445b8 Update index.html.erb 2018-09-19 10:05:45 -04:00
2b333667ed Update init.rb 2018-09-19 09:52:58 -04:00
1077cf214c Update show.html.erb 2018-09-19 09:51:27 -04:00
f27fdf5274 Update index.html.erb 2018-09-19 09:50:58 -04:00
1dbcca4ca0 Create _search.html.erb 2018-09-19 09:49:51 -04:00
558e2359f7 Added partial customers/search & fixed formatting 2018-09-19 09:45:36 -04:00
f99ef648b3 Rename _search.erb to _search.html.erb 2018-09-19 09:24:05 -04:00
5e4e3329c8 Create _search.erb 2018-09-19 09:23:37 -04:00
b0a66aba0a Fixed custom field redering 2018-07-31 15:22:46 -04:00
f2dd500536 Merge branch 'line_items' of github.com:rickbarrette/redmine_qbo into line_items 2018-03-31 08:04:17 -04:00
7412ac4f91 Added boolean billed 2018-03-31 08:03:26 -04:00
2acb3efe5a Create line_items_controler.rb 2018-03-31 08:00:56 -04:00
2cc0d06bc5 Merge branch 'master' into line_items 2018-03-29 22:42:54 -04:00
4070cb7c49 Merge branch 'master' of github.com:rickbarrette/redmine_qbo 2018-03-29 22:42:03 -04:00
fcd196355a Create line_item.rb 2018-03-29 10:17:01 -04:00
ea502d5b7b Create 026_create_line_items.rb 2018-03-29 10:05:37 -04:00
1f33009f89 Update LICENSE 2018-03-28 15:24:44 -04:00
3509ae9725 Removed squish_vin and added last 8 of vin to vehicle name 2018-03-27 09:40:01 -04:00
49858c45c9 do a full search by setting the full parameter to true. 2018-03-27 09:38:44 -04:00
b78cd44cc9 don't bill time if not assigned to anyone EE 2018-03-05 08:58:33 -05:00
39fcd6d4dd Removed Drive & Doors 2018-03-03 13:55:22 -05:00
8838d36793 Fixed vin decoding 2018-03-03 13:54:19 -05:00
63fa94e6f2 Merge branch 'master' into nhtsa_vin 2018-03-03 13:14:05 -05:00
17183f9643 Update vehicle.rb 2018-03-03 13:11:58 -05:00
667d0bfa97 Remove Edmunds API & Added NhtsaVin 2018-03-03 12:38:56 -05:00
88a6be0d27 Remove Edmunds API Key Setting 2018-03-03 12:26:25 -05:00
c3eaddff97 Start work to switch from edmunds_vin to nhtsa_vin 2018-03-03 12:22:44 -05:00
f03adad463 Update issues_form_hook_listener.rb 2017-11-19 22:17:25 -05:00
bd03e3ac32 Did things 2017-11-19 22:14:40 -05:00
299a28a0d2 Create controller_issues_listener.rb 2017-11-19 22:01:20 -05:00
cee8ddced1 Added safe_attributes for ProjecT 2017-11-17 20:54:14 -05:00
738cd21b1f Update issues_form_hook_listener.rb 2017-11-17 10:56:13 -05:00
b8186e4b52 More customer/project relations 2017-11-17 10:51:25 -05:00
d98a8b8cc4 Fixed Project releationships and database migration 2017-11-17 10:14:05 -05:00
dba6c4b131 Update vehicle.rb 2017-11-13 22:19:20 -05:00
118812f16f Update vehicle.rb 2017-11-13 22:17:03 -05:00
0b96a1412c Rename app/views/qbo/list_simple.html.erb to app/views/issues/_list_simple.html.erb 2017-11-13 22:07:12 -05:00
29de191d26 Rename app/views/issues/list_simple.html.erb to app/views/qbo/list_simple.html.erb 2017-11-13 22:06:45 -05:00
f86af9ca71 Create list_simple.html.erb 2017-11-13 22:04:04 -05:00
d25de7b30f Merge remote-tracking branch 'origin/dev' 2017-11-13 21:37:28 -05:00
273bd3d6be Update application.js 2017-11-13 21:01:17 -05:00
ac446723f1 Update application.js 2017-11-13 20:59:45 -05:00
c21bc1333f Update projects_form_hook_listener.rb 2017-11-13 20:38:33 -05:00
4e4255995e Update projects_form_hook_listener.rb 2017-11-13 20:37:59 -05:00
c68b540597 Update projects_form_hook_listener.rb 2017-11-13 20:36:44 -05:00
1358871ccc Update init.rb 2017-11-13 20:31:16 -05:00
908511f299 Update init.rb 2017-11-13 20:30:28 -05:00
6260de21f9 Update query_patch.rb 2017-11-13 20:28:19 -05:00
e2f276097c Update query_patch.rb 2017-11-13 20:27:36 -05:00
205bb67a6a Update query_patch.rb 2017-11-13 20:20:46 -05:00
05edafec4c Update query_patch.rb 2017-11-13 20:13:26 -05:00
4a073d3a71 Update query_patch.rb 2017-11-13 20:12:23 -05:00
f2cbf31e17 Create projects_form_hook_listener.rb 2017-11-13 19:53:37 -05:00
22b22780ea Create project_patch.rb
Add relationships to projects
2017-11-13 19:47:39 -05:00
71cfa28817 Create 025_update_projects.rb
Added customer & vehicle reference to a project.
2017-11-13 19:40:14 -05:00
8b2d88f80b Create qbo_controller.rb 2017-06-14 09:43:52 -04:00
eaf0a57e51 Create qbo_controller.rb 2017-06-13 21:58:42 -04:00
512f5ad7ba Create index.html.erb 2017-06-13 21:55:13 -04:00
8d2351d3f9 Create vehicle.rb 2017-06-13 21:51:36 -04:00
c5a20c9e7f Create vehicle.rb 2017-06-13 21:50:50 -04:00
4a3b663333 Create vehicle.rb 2017-06-13 21:49:10 -04:00
e43635b5d8 Update vehicle.rb 2017-06-13 12:31:07 -04:00
7044377f16 Update vehicle.rb 2017-06-13 12:27:22 -04:00
7ced1bf942 Create vehicle.rb 2017-06-13 12:22:48 -04:00
7ca3315ce5 Update vehicle.rb 2017-06-13 11:44:46 -04:00
2b8c4b4d4d Update vehicle.rb 2017-06-06 08:58:11 -04:00
a359e8815b Update issues_form_hook_listener.rb 2017-06-06 08:53:36 -04:00
01cf82813c Update vehicle.rb 2017-06-06 08:32:21 -04:00
625e400c48 Update vehicle.rb 2017-06-06 08:27:55 -04:00
56793cee7c Update vehicle.rb 2017-06-06 08:25:35 -04:00
3ba5337812 Update vehicle.rb
Updated regex to remove invalid chars
2017-06-06 08:22:50 -04:00
129e3d4821 Update issues_form_hook_listener.rb 2017-06-06 08:12:08 -04:00
4d524a7d61 Update issues_form_hook_listener.rb 2017-06-06 08:10:28 -04:00
429fb920fb Update index.html.erb 2017-04-04 22:29:06 -04:00
77c7f0b6fe Update index.html.erb 2017-04-04 22:28:20 -04:00
1a043bea76 Added Permission Check 2017-04-04 22:26:58 -04:00
e4d770c272 Update index.html.erb 2017-04-04 22:23:33 -04:00
fce3931858 Added new customer button 2017-04-04 22:22:29 -04:00
43cdade6e1 Merge branch 'master' into dev 2017-04-04 09:32:50 -04:00
4374f9436c Removed .service from get_base call 2017-04-04 09:31:02 -04:00
7c63c3c816 Fixed typo 2017-04-04 08:49:08 -04:00
b3f491a60b Fixed logic 2017-04-04 08:48:36 -04:00
4adcbba840 Update vehicle.rb 2017-04-04 08:47:15 -04:00
baccb42455 Merge branch 'dev' of github.com:rickbarrette/redmine_qbo into dev 2017-04-04 08:46:44 -04:00
d0842dd803 Merge branch 'dev' of github.com:rickbarrette/redmine_qbo into dev 2017-04-04 08:45:45 -04:00
02aabe6045 Forgot End 2017-04-04 08:45:34 -04:00
0e47f9eb5f Some Cleanup & Fixed to_s to report vin
to_s to report vin when year,make,model are nil
2017-04-04 08:44:14 -04:00
f1d2d63f20 Removed un-needed initializer 2017-04-04 08:37:49 -04:00
f322f9f7ab Update Copyright 2017-04-04 08:34:03 -04:00
6db8b76902 Update Copyright 2017-04-04 08:33:37 -04:00
61adce1299 0.5.0 2017-04-03 22:59:09 -04:00
daffb3719e Copyright Update & Formating 2017-04-03 22:57:25 -04:00
1b8626d28f Update init.rb 2017-04-03 22:53:34 -04:00
b119344fad Copyright Update 2017-04-03 22:52:37 -04:00
4381d403d4 Copyright Update 2017-04-03 22:52:14 -04:00
26bfaca1d6 Copyright Update 2017-04-03 22:52:00 -04:00
0c68d8094a Copyright Update 2017-04-03 22:51:43 -04:00
6230175ba5 Copyright Update 2017-04-03 22:51:25 -04:00
5dc4dc5637 Copyright Update 2017-04-03 22:51:03 -04:00
ac15307fb8 Copyright Update 2017-04-03 22:50:50 -04:00
ec5ce497d8 Copyright Update 2017-04-03 22:50:38 -04:00
01fe52157d Update issue_patch.rb 2017-04-03 22:50:19 -04:00
75737cf2fd Copyright Update 2017-04-03 22:50:05 -04:00
7824edf5aa Copyright Update 2017-04-03 22:49:52 -04:00
6b70b447a5 Copyright Update 2017-04-03 22:48:07 -04:00
5a6b679099 Copyright Update 2017-04-03 22:47:49 -04:00
72835dcf65 Copyright Update 2017-04-03 22:47:36 -04:00
b9e2349983 Update qbo.rb 2017-04-03 22:47:21 -04:00
ef13ec7e11 Update qbo_employee.rb 2017-04-03 22:47:10 -04:00
00b40da8c4 Copyright Update 2017-04-03 22:46:48 -04:00
2be25adf18 Copyright Update 2017-04-03 22:46:35 -04:00
5ab9a777f6 Copyright Update 2017-04-03 22:46:19 -04:00
7fbb1d6ba3 Copyright Update 2017-04-03 22:46:04 -04:00
786c80609c Copyright Update 2017-04-03 22:45:21 -04:00
efb554824d Update vehicles_controller.rb 2017-04-03 22:44:40 -04:00
c615abc896 Update qbo_controller.rb 2017-04-03 22:44:29 -04:00
8ecc3414da Update payments_controller.rb 2017-04-03 22:44:17 -04:00
505def8d23 Update invoice_controller.rb 2017-04-03 22:44:03 -04:00
da155de514 Copyright Update 2017-04-03 22:43:42 -04:00
7d727e1ad8 Copyright Update 2017-04-03 22:43:25 -04:00
3dcb5155fc Add Blank Option 2017-04-03 22:40:07 -04:00
4424593e63 Add Blank to Select 2017-04-03 22:38:45 -04:00
8eae838ef8 Update filter_estimates_by_customer.js.erb 2017-04-03 22:34:19 -04:00
d5e8b4bbc4 Update qbo_estimate.rb 2017-04-03 22:26:53 -04:00
fc8efa53e9 Merge branch 'dev' of github.com:rickbarrette/redmine_qbo into dev 2017-04-03 22:25:29 -04:00
15ea3aeaa2 Update qbo_estimate.rb 2017-04-03 22:24:04 -04:00
35bf300f2d Show only estimates attached to the customer 2017-04-03 22:07:06 -04:00
72bf10680f Added ajax to update estimates 2017-04-03 21:57:56 -04:00
bd8706deee Create filter_estimates_by_customer.js.erb 2017-04-03 21:55:47 -04:00
e8619529d4 Added routes for filtering estimates & invoices 2017-04-03 21:52:39 -04:00
fd3c8e15e6 Added filter methods for estimates & invoices 2017-04-03 21:49:57 -04:00
166c1d3002 Add files via upload 2017-04-02 17:13:21 -04:00
773d60fb23 Delete plugin_issue_view.png 2017-04-02 17:12:53 -04:00
cc46902095 Update qbo_estimate.rb 2017-04-02 08:45:02 -04:00
acb2628c7a Update qbo_estimate.rb 2017-04-02 08:41:36 -04:00
e4914590f8 Moved Invoice Sync up in the order 2017-04-02 08:31:22 -04:00
e3a8e464ae Update qbo_estimate.rb 2017-04-02 08:21:36 -04:00
8a6bb45b6a Fixed Custom Field Logic 2017-04-02 08:06:07 -04:00
3decf83a7b Update qbo_invoice.rb 2017-04-02 07:54:33 -04:00
1b7b286d1b Update qbo_invoice.rb 2017-04-02 07:31:28 -04:00
a8804f6704 Increment the sync token 2017-04-02 07:28:53 -04:00
5d03e261d1 Added customer association 2017-04-02 07:19:12 -04:00
1ae766b8bd Added customer association 2017-04-02 07:13:28 -04:00
119c36569f Added association for invoices & estimates 2017-04-02 07:08:24 -04:00
3be69d5efd Update 024_update_invoices_and_estimates.rb 2017-04-02 07:00:43 -04:00
b55dd99efd Merge branch 'master' into dev 2017-04-02 06:59:01 -04:00
eff1f97ab2 Create 024_update_invoices_and_estimates.rb 2017-04-02 06:56:17 -04:00
06050bd139 Removed unused method update_vehicles 2017-03-31 16:23:42 -04:00
a48840ddfb Fixed typo 2017-03-31 16:12:21 -04:00
9b9aabee11 Format the VIN 2017-03-31 16:11:19 -04:00
7782627286 Split the VIN 2017-03-31 16:07:09 -04:00
41a113dc59 Do not hide notes 2017-03-31 16:02:48 -04:00
b84e249dfb 0.4.3 2017-03-23 06:05:43 -04:00
6b45f767a4 Merge pull request #8 from rickbarrette/permissions
Permissions
2017-03-23 06:03:06 -04:00
a34b6a07fc fixed typos 2017-03-23 05:56:26 -04:00
2ce811bbbf Update auth_helper.rb 2017-03-23 05:50:31 -04:00
02153de8b0 Added before filters add_customer, view_customer 2017-03-23 05:47:37 -04:00
68be20459b Added global_check_permission 2017-03-23 05:45:45 -04:00
bbd03cc337 Update init.rb 2017-03-23 05:42:54 -04:00
4fc71a93f2 Update init.rb 2017-03-23 05:42:09 -04:00
8e7e1908e4 Update customers_controller.rb 2017-03-23 05:39:55 -04:00
89fba883ef Update customers_controller.rb 2017-03-23 05:38:06 -04:00
15f317fba1 Update customers_controller.rb 2017-03-23 05:36:51 -04:00
894ee9abfd added check_permission 2017-03-23 05:33:58 -04:00
ca17807117 Update payments_controller.rb 2017-03-23 05:29:54 -04:00
a70ba2f164 Update payments_controller.rb 2017-03-23 05:27:38 -04:00
78ac97298c Update payments_controller.rb 2017-03-23 05:25:57 -04:00
72cd349c1b Update payments_controller.rb 2017-03-23 05:23:44 -04:00
6fc1d27dca Update auth_helper.rb 2017-03-23 05:21:56 -04:00
525c6b99d6 Update auth_helper.rb 2017-03-23 05:19:13 -04:00
3eaff0ab30 Update auth_helper.rb 2017-03-23 05:14:47 -04:00
85b40bc9cf Update payments_controller.rb 2017-03-23 05:11:15 -04:00
37a2b95447 Update payments_controller.rb 2017-03-23 05:10:05 -04:00
33feb91713 added permission_checker 2017-03-23 05:08:33 -04:00
f7357f30ce Update payments_controller.rb 2017-03-23 05:03:58 -04:00
c0ae01018b Update payments_controller.rb 2017-03-23 05:01:01 -04:00
4353e910c8 Update payments_controller.rb 2017-03-23 04:57:22 -04:00
bef9774c4e Update payments_controller.rb 2017-03-23 04:52:19 -04:00
863437b1b7 Added before filter to check permissions 2017-03-23 04:50:17 -04:00
7cfa15910a Update init.rb 2017-03-23 04:41:31 -04:00
2154a3d001 Update init.rb 2017-03-22 23:09:05 -04:00
fdab090a3d Update init.rb 2017-03-22 23:06:12 -04:00
3f32b7fef1 Update init.rb 2017-03-22 22:53:21 -04:00
14422bc549 Update init.rb 2017-03-22 22:52:24 -04:00
6bb66597e8 Added some permissions
view_customers, add_customers, view_payments, add_payments
2017-03-22 22:44:09 -04:00
68 changed files with 841 additions and 389 deletions

View File

@@ -3,12 +3,11 @@ source 'https://rubygems.org'
gem 'quickbooks-ruby'
gem 'quickbooks-ruby-base'
gem 'oauth-plugin'
gem 'oauth'
gem 'oauth2'
gem 'roxml'
gem 'edmunds_vin'
gem 'nhtsa_vin'
gem 'will_paginate'
gem 'rails-jquery-autocomplete'
gem 'jquery-rails', '~> 3.1.4'
gem 'jquery-ui-rails'
group :assets do

View File

@@ -1,6 +1,6 @@
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
of this software and associated documentation files (the "Software"), to deal

View File

@@ -1,14 +1,18 @@
#Redmine Quickbooks Online
# Redmine Quickbooks Online
A plugin for Redmine to connect to Quickbooks Online
The goal of this project is to allow Redmine to connect with Quickbooks Online to create `Time Activity Entries` for completed work when an Issue is closed.
`Note: Although the core functionality is complete, this project is still under heavy development. I am still working on refining everthing and adding other features. Tags should be stable`
#### Disclaimer
`Note: I am currently using this in a live production enviroment with no issues`
OAuth2 is hacked into place with version 0.8.0 & working but I'm sure I missed a few things
####Features
Note: Although the core functionality is complete, this project is still under heavy development. I am still working on refining everthing and adding other features. Tags should be stable
Also worth metioning I am currently using this in a live production enviroment with no issues
#### Features
* 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
- This is set via a drop down in the user admistration page.
@@ -27,14 +31,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.
- `Customers` are automaticly updated in local database
##Prerequisites
## Prerequisites
* Sign up to become a developer for Intuit https://developer.intuit.com/
* Create your own aplication to obtain your API keys
* Set up webhook service to https://redmine.yourdomain.com/qbo/webhook
- 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
@@ -73,11 +77,11 @@ Note: After the inital synchronization, this plugin will recieve push notificati
* Fix Issue sort by Customer
* MORE Stuff...
##License
## License
The MIT License (MIT)
Copyright (c) 2016 rick barrette
Copyright (c) 2020 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:

Binary file not shown.

Before

Width:  |  Height:  |  Size: 185 KiB

After

Width:  |  Height:  |  Size: 106 KiB

View File

@@ -1,6 +1,6 @@
#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:
#
@@ -27,17 +27,26 @@ class CustomersController < ApplicationController
include SortHelper
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]
default_search_scope :names
autocomplete :customer, :name, :full => false, :extra_data => [:id]
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
def index
if params[:search]
@@ -144,6 +153,14 @@ class CustomersController < ApplicationController
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 )
found_non_zero = false
array.each do |val|

View File

@@ -1,6 +1,6 @@
#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:
#
@@ -18,7 +18,7 @@ class EstimateController < ApplicationController
# Downloads and forwards the estimate pdf
#
def show
base = QboEstimate.get_base.service
base = QboEstimate.get_base
estimate = base.fetch_by_id(params[:id])
@pdf = base.pdf(estimate)
send_data @pdf, filename: "estimate #{estimate.doc_number}.pdf", :disposition => 'inline', :type => "application/pdf"

View File

@@ -1,6 +1,6 @@
#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:
#

View File

@@ -0,0 +1,94 @@
#The MIT License (MIT)
#
#Copyright (c) 2018 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 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

View File

@@ -1,6 +1,6 @@
#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:
#
@@ -12,16 +12,16 @@ class PaymentsController < ApplicationController
include AuthHelper
before_filter :require_user
before_filter :check_permissions
def new
@payment = Payment.new
@customers = Customer.all.sort_by &:name
@accounts = Qbo.get_base(:account).service.query("SELECT Id, Name FROM Account WHERE AccountType = 'Bank' Order By Name")
@accounts = Qbo.get_base(:account).query("SELECT Id, Name FROM Account WHERE AccountType = 'Bank' Order By Name")
@payment_methods = Qbo.get_base(:payment_method).service.all
@payment_methods = Qbo.get_base(:payment_method).all
end
def create
@@ -32,11 +32,17 @@ class PaymentsController < ApplicationController
else
flash[:error] = @payment.errors.full_messages.to_sentence
redirect_to new_customer_path
end
end
end
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 )
found_non_zero = false
array.each do |val|

View File

@@ -1,6 +1,6 @@
#The MIT License (MIT)
#
#Copyright (c) 2016 rick barrette
#Copyright (c) 2020 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:
#
@@ -34,32 +34,48 @@ class QboController < ApplicationController
# Called when the user requests that Redmine to connect to QBO
#
def authenticate
callback = qbo_oauth_callback_url
token = Qbo.get_oauth_consumer.get_request_token(:oauth_callback => callback)
session[:qb_request_token] = Marshal.dump(token)
redirect_to("https://appcenter.intuit.com/Connect/Begin?oauth_token=#{token.token}") and return
oauth2_client = Qbo.get_client
callback = "https://redmine.rickbarrette.org/qbo/oauth_callback/"
#callback = qbo_oauth_callback_url
grant_url = oauth2_client.auth_code.authorize_url(redirect_uri: callback, response_type: "code", state: SecureRandom.hex(12), scope: "com.intuit.quickbooks.accounting")
redirect_to grant_url
end
#
# Called by QBO after authentication has been processed
#
def oauth_callback
at = Marshal.load(session[:qb_request_token]).get_access_token(:oauth_verifier => params[:oauth_verifier])
if params[:state].present?
oauth2_client = Qbo.get_client
# use the state value to retrieve from your backend any information you need to identify the customer in your system
#redirect_uri = qbo_oauth_callback_url
redirect_uri = "https://redmine.rickbarrette.org/qbo/oauth_callback/"
if resp = oauth2_client.auth_code.get_token(params[:code], redirect_uri: redirect_uri)
# save your tokens here. For example:
# quickbooks_credentials.update_attributes(access_token: resp.token, refresh_token: resp.refresh_token,
# realm_id: params[:realmId])
#There can only be one...
Qbo.destroy_all
Qbo.delete_all
# Save the authentication information
qbo = Qbo.new
qbo.qb_token = at.token
qbo.qb_secret = at.secret
qbo.token_expires_at = 6.months.from_now.utc
qbo.reconnect_token_at = 5.months.from_now.utc
qbo.company_id = params['realmId']
if qbo.save!
redirect_to qbo_sync_path, :flash => { :notice => "Successfully connected to Quickbooks" }
else
redirect_to plugin_settings_path(:redmine_qbo), :flash => { :error => "Error" }
# Save the authentication information
qbo = Qbo.new
qbo.qb_token = resp.token
qbo.qb_secret = resp.refresh_token
qbo.token_expires_at = 6.months.from_now.utc
qbo.reconnect_token_at = 3.months.from_now.utc
qbo.company_id = params[:realmId]
access_token = OAuth2::AccessToken.new(oauth2_client, resp.token, refresh_token: resp.refresh_token)
qbo.token = access_token.to_hash
qbo.expire = 1.hour.from_now.utc
if qbo.save!
redirect_to qbo_sync_path, :flash => { :notice => "Successfully connected to Quickbooks" }
else
redirect_to plugin_settings_path(:redmine_qbo), :flash => { :error => "Error" }
end
end
end
end
@@ -133,10 +149,10 @@ class QboController < ApplicationController
Thread.new do
if Qbo.exists?
Customer.sync
QboInvoice.sync
QboItem.sync
QboEmployee.sync
QboEstimate.sync
QboInvoice.sync
# Record the last sync time
Qbo.update_time_stamp
@@ -144,6 +160,6 @@ class QboController < ApplicationController
ActiveRecord::Base.connection.close
end
redirect_to qbo_path(:redmine_qbo), :flash => { :notice => "Successfully synced to Quickbooks" }
redirect_to :home, :flash => { :notice => "Successfully synced to Quickbooks" }
end
end

View File

@@ -1,6 +1,6 @@
#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:
#
@@ -37,8 +37,7 @@ class VehiclesController < ApplicationController
# return an HTML form for creating a new vehicle
def new
@vehicle = Vehicle.new
@customers = Customer.all.order(:name)
@customer = params[:customer_id] if params[:customer_id]
@customer = Customer.find_by_id(params[:customer_id]) if params[:customer_id]
end
# create a new vehicle
@@ -49,7 +48,7 @@ class VehiclesController < ApplicationController
redirect_to @vehicle
else
flash[:error] = @vehicle.errors.full_messages.to_sentence
redirect_to new_vehicle_path
redirect_to Vehicle.find_by_vin @vehicle.vin
end
end
@@ -57,6 +56,7 @@ class VehiclesController < ApplicationController
def show
begin
@vehicle = Vehicle.find_by_id(params[:id])
@vin = @vehicle.vin.scan(/.{1,9}/) if @vehicle.vin
rescue ActiveRecord::RecordNotFound
render_404
end
@@ -66,8 +66,7 @@ class VehiclesController < ApplicationController
def edit
begin
@vehicle = Vehicle.find_by_id(params[:id])
@customer = @vehicle.customer.id
@customers = Customer.all.order(:name)
@customer = @vehicle.customer
rescue ActiveRecord::RecordNotFound
render_404
end
@@ -82,9 +81,10 @@ class VehiclesController < ApplicationController
flash[:notice] = "Vehicle updated"
redirect_to @vehicle
else
flash[:error] = @vehicle.errors.full_messages.to_sentence if @vehicle.errors
redirect_to edit_vehicle_path
end
#show any errors anyways
flash[:error] = @vehicle.errors.full_messages.to_sentence unless @vehicle.errors.empty?
rescue ActiveRecord::RecordNotFound
render_404
end
@@ -101,15 +101,6 @@ class VehiclesController < ApplicationController
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
def only_one_non_zero?( array )

View File

@@ -1,6 +1,6 @@
#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:
#
@@ -16,4 +16,38 @@ module AuthHelper
render :file => "public/401.html.erb", :status => :unauthorized, :layout =>true
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

View File

@@ -1,6 +1,6 @@
#The MIT License (MIT)
#
#Copyright (c) 2016 rick barrette
#Copyright (c) 2020 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:
#
@@ -13,9 +13,11 @@ class Customer < ActiveRecord::Base
has_many :issues
has_many :qbo_purchases
has_many :qbo_invoices
has_many :qbo_estimates
has_many :vehicles
attr_accessible :name, :notes, :email, :primary_phone, :mobile_phone
attr_accessible :name, :notes, :email, :primary_phone, :mobile_phone, :phone_number
validates_presence_of :id, :name
self.primary_key = :id
@@ -61,6 +63,8 @@ class Customer < ActiveRecord::Base
pn = Quickbooks::Model::TelephoneNumber.new
pn.free_form_number = n
@details.primary_phone = pn
#update our locally stored number too
update_phone_number
end
# Convenience Method
@@ -81,6 +85,26 @@ class Customer < ActiveRecord::Base
pn = Quickbooks::Model::TelephoneNumber.new
pn.free_form_number = n
@details.mobile_phone = pn
#update our locally stored number too
update_mobile_phone_number
end
# update the localy stored phone number as a plain string with no special chars
def update_phone_number
begin
self.phone_number = self.primary_phone.tr('^0-9', '')
rescue
return nil
end
end
# update the localy stored phone number as a plain string with no special chars
def update_mobile_phone_number
begin
self.mobile_phone_number = self.mobile_phone.tr('^0-9', '')
rescue
return nil
end
end
# Convenience Method
@@ -112,7 +136,7 @@ class Customer < ActiveRecord::Base
# proforms a bruteforce sync operation
# This needs to be simplified
def self.sync
service = Qbo.get_base(:customer).service
service = Qbo.get_base(:customer)
# Sync ALL customers if the database is empty
#if count == 0
@@ -140,26 +164,16 @@ class Customer < ActiveRecord::Base
end
end
# Searchs the database for a customer by name
# Searchs the database for a customer by name or phone number with out special chars
def self.search(search)
customers = where("name LIKE ?", "%#{search}%")
#if customers.empty?
# service = Qbo.get_base(:customer).service
# results = service.query("Select Id From Customer Where PrimaryPhone LIKE '%#{search}%' AND Mobile LIKE '%#{search}%'")
# results.each do |customer|
# customers << Customer.find_by_id(customer.id)
# end
#end
customers = where("name LIKE ? OR phone_number LIKE ? OR mobile_phone_number LIKE ?", "%#{search}%", "%#{search}%", "%#{search}%")
return customers.order(:name)
end
# proforms a bruteforce sync operation
# This needs to be simplified
def self.sync_by_id(id)
service = Qbo.get_base(:customer).service
service = Qbo.get_base(:customer)
customer = service.fetch_by_id(id)
qbo_customer = Customer.find_or_create_by(id: customer.id)
@@ -179,7 +193,7 @@ class Customer < ActiveRecord::Base
# Push the updates
def save_with_push
begin
@details = Qbo.get_base(:customer).service.update(@details)
@details = Qbo.get_base(:customer).update(@details)
#raise "QBO Fault" if @details.fault?
self.id = @details.id
rescue Exception => e
@@ -197,7 +211,7 @@ class Customer < ActiveRecord::Base
def pull
begin
raise Exception unless self.id
@details = Qbo.get_base(:customer).find_by_id(self.id)
@details = Qbo.get_base(:customer).fetch_by_id(self.id)
rescue Exception => e
@details = Quickbooks::Model::Customer.new
end

View File

@@ -1,6 +1,6 @@
#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:
#

34
app/models/line_item.rb Normal file
View File

@@ -0,0 +1,34 @@
#The MIT License (MIT)
#
#Copyright (c) 2018 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 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

View File

@@ -1,6 +1,6 @@
#The MIT License (MIT)
#
#Copyright (c) 2016 rick barrette
#Copyright (c) 2020 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:
#
@@ -23,7 +23,7 @@ class Payment
payment.deposit_to_account_id = @account_id.to_i
payment.payment_method_id = @payment_method_id.to_i
payment.total = @total_amount
Qbo.get_base(:payment).service.update(payment)
Qbo.get_base(:payment).update(payment)
end
def save!

View File

@@ -1,6 +1,6 @@
#The MIT License (MIT)
#
#Copyright (c) 2016 rick barrette
#Copyright (c) 2020 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:
#
@@ -11,22 +11,18 @@
class Qbo < ActiveRecord::Base
unloadable
validates_presence_of :qb_token, :qb_secret, :company_id, :token_expires_at, :reconnect_token_at
serialize :token
OAUTH_CONSUMER_KEY = Setting.plugin_redmine_qbo['settingsOAuthConsumerKey']
OAUTH_CONSUMER_SECRET = Setting.plugin_redmine_qbo['settingsOAuthConsumerSecret']
$qb_oauth_consumer = OAuth::Consumer.new(OAUTH_CONSUMER_KEY, OAUTH_CONSUMER_SECRET, {
:site => "https://oauth.intuit.com",
:request_token_path => "/oauth/v1/get_request_token",
:authorize_url => "https://appcenter.intuit.com/Connect/Begin",
:access_token_path => "/oauth/v1/get_access_token"
})
# Configure quickbooks-ruby-base to access our database
Quickbooks::Base.configure do |c|
c.persistent_token = 'qb_token'
c.persistent_secret = 'qb_secret'
c.persistent_company_id = 'company_id'
def self.get_client
oauth_params = {
site: "https://appcenter.intuit.com/connect/oauth2",
authorize_url: "https://appcenter.intuit.com/connect/oauth2",
token_url: "https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer"
}
return OAuth2::Client.new(OAUTH_CONSUMER_KEY, OAUTH_CONSUMER_SECRET, oauth_params)
end
def self.get_oauth_consumer
@@ -34,10 +30,46 @@ class Qbo < ActiveRecord::Base
return $qb_oauth_consumer
end
# Get a quickbooks base object for type
# Get a quickbooks base service object for type
# @params type of base
def self.get_base(type)
Quickbooks::Base.new(first, type)
# lets getnourbold access token from the database
oauth2_client = get_client
qbo = self.first
access_token = OAuth2::AccessToken.from_hash(oauth2_client, qbo.token)
# check to see if we need to refresh the acesstoken
if qbo.expire.to_time.utc.past?
puts "Updating access token"
new_access_token_object = access_token.refresh!
qbo.token = new_access_token_object.to_hash
qbo.expire = 1.hour.from_now.utc
qbo.save!
access_token = new_access_token_object
else
puts "Using current token"
end
# build the reqiested service
case type
when :item
return Quickbooks::Service::Item.new(:company_id => qbo.company_id, :access_token => access_token)
when :time_activity
return Quickbooks::Service::TimeActivity.new(:company_id => qbo.company_id, :access_token => access_token)
when :customer
return Quickbooks::Service::Customer.new(:company_id => qbo.company_id, :access_token => access_token)
when :invoice
return Quickbooks::Service::Invoice.new(:company_id => qbo.company_id, :access_token => access_token)
when :estimate
return Quickbooks::Service::Estimate.new(:company_id => qbo.company_id, :access_token => access_token)
when :account
return Quickbooks::Service::Account.new(:company_id => qbo.company_id, :access_token => access_token)
when :employee
return Quickbooks::Service:: Employee.new(:company_id => qbo.company_id, :access_token => access_token)
else
return access_token
end
end
# Get the QBO account

View File

@@ -1,6 +1,6 @@
#The MIT License (MIT)
#
#Copyright (c) 2016 rick barrette
#Copyright (c) 2020 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:
#
@@ -19,7 +19,7 @@ class QboEmployee < ActiveRecord::Base
end
def self.sync
employees = get_base.service.all
employees = get_base.all
transaction do
# Update the item table
@@ -33,7 +33,7 @@ class QboEmployee < ActiveRecord::Base
end
def self.sync_by_id(id)
employee = get_base.service.fetch_by_id(id)
employee = get_base.fetch_by_id(id)
qbo_employee = find_or_create_by(id: employee.id)
qbo_employee.name = employee.display_name
qbo_employee.id = employee.id

View File

@@ -1,6 +1,6 @@
#The MIT License (MIT)
#
#Copyright (c) 2016 rick barrette
#Copyright (c) 2020 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:
#
@@ -10,44 +10,49 @@
class QboEstimate < ActiveRecord::Base
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
Qbo.get_base(:estimate)
end
# sync all estimates
def self.sync
estimates = get_base.service.all
# Update the item table
transaction do
estimates.each { |estimate|
qbo_estimate = QboEstimate.find_or_create_by(id: estimate.id)
qbo_estimate.doc_number = estimate.doc_number
qbo_estimate.id = estimate.id
qbo_estimate.save!
}
end
estimates = get_base.all
estimates.each { |estimate|
process_estimate(estimate)
}
#remove deleted estimates
where.not(estimates.map(&:id)).destroy_all
end
# sync only one estimate
def self.sync_by_id(id)
estimate = get_base.service.fetch_by_id(id)
qbo_estimate = QboEstimate.find_or_create_by(id: estimate.id)
process_estimate(get_base.fetch_by_id(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.id = estimate.id
qbo_estimate.save!
end
def self.update(id)
# Update the item table
estimate = get_base.service.fetch_by_id(id)
qbo_estimate = QboEstimate.find_or_create_by(id: id)
qbo_estimate.doc_number = estimate.doc_number
qbo_estimate.save!
# process an estimate into the database
def self.process_estimate(estimate)
qbo_estimate = find_or_create_by(id: estimate.id)
qbo_estimate.doc_number = estimate.doc_number
qbo_estimate.customer_id = estimate.customer_ref.value
qbo_estimate.id = estimate.id
qbo_estimate.save!
end
end

View File

@@ -1,6 +1,6 @@
#The MIT License (MIT)
#
#Copyright (c) 2016 rick barrette
#Copyright (c) 2020 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:
#
@@ -12,12 +12,13 @@ class QboInvoice < ActiveRecord::Base
unloadable
has_and_belongs_to_many :issues
belongs_to :customer
attr_accessible :doc_number, :id
validates_presence_of :doc_number, :id
self.primary_key = :id
def self.get_base
Qbo.get_base(:invoice).service
Qbo.get_base(:invoice)
end
# sync ALL the invoices
@@ -59,6 +60,7 @@ class QboInvoice < ActiveRecord::Base
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)
@@ -125,19 +127,17 @@ class QboInvoice < ActiveRecord::Base
cf.string_value = value.value.to_s
is_changed = true
end
end
# Use the max milage
if cf.name.eql? "Mileage Out"
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
# Everything else
cf.string_value = value.value.to_s
is_changed = true
end
end
rescue
@@ -148,6 +148,7 @@ class QboInvoice < ActiveRecord::Base
# TODO Add some hooks here
# Push updates
#invoice.sync_token += 1 if is_changed
get_base.update(invoice) if is_changed
end

View File

@@ -1,6 +1,6 @@
#The MIT License (MIT)
#
#Copyright (c) 2016 rick barrette
#Copyright (c) 2020 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:
#
@@ -27,9 +27,9 @@ class QboItem < ActiveRecord::Base
query << " AND Metadata.LastUpdatedTime >= '#{last.iso8601}' " if last
if count == 0
items = get_base.service.all
items = get_base.all
else
items = get_base.service.query(query)
items = get_base.query(query)
end
unless items.count = 0

View File

@@ -1,6 +1,6 @@
#The MIT License (MIT)
#
#Copyright (c) 2016 rick barrette
#Copyright (c) 2020 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:
#
@@ -20,11 +20,11 @@ class QboPurchase < ActiveRecord::Base
end
def get_purchase(id)
get_base.service.find_by_id(id)
get_base.find_by_id(id)
end
def self.sync
QboPurchase.get_base.service.all.each { |purchase|
QboPurchase.get_base.all.each { |purchase|
purchase.line_items.all? { |line_item|

View File

@@ -1,6 +1,6 @@
#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:
#
@@ -12,8 +12,6 @@ class Vehicle < ActiveRecord::Base
unloadable
API_KEY = Setting.plugin_redmine_qbo['settingsEdmundsAPIKey']
belongs_to :customer
has_many :issues, :foreign_key => 'vehicles_id'
@@ -21,27 +19,32 @@ class Vehicle < ActiveRecord::Base
validates_presence_of :customer
validates :vin, uniqueness: true
#validates :year, numericality: { only_integer: true }
before_save :decode_vin
after_initialize :get_details
#after_find :get_details
self.primary_key = :id
# returns a human readable string
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
# returns the raw JSON details from EMUNDS
def details
get_details if @details.nil?
return @details
end
# returns the style of the vehicle
def style
get_details if @details.nil?
begin
return @details['years'][0]['styles'][0]['name'] if @details
return @details.trim if @details
rescue
return nil
end
@@ -49,21 +52,24 @@ class Vehicle < ActiveRecord::Base
# returns the drive of the vehicle i.e. 2 wheel, 4 wheel, ect.
def drive
return @details['drivenWheels'].to_s.upcase if @details
#todo fix this
#return @details.drive_type if @details
return nil
end
# returns the number of doors of the vehicle
def doors
return @details['numOfDoors'] if @details
get_details if @details.nil?
return @details.doors if @details
end
# Force Upper Case for VIN numbers
# Force Upper Case for make numbers
def make=(val)
# The to_s is in case you get nil/non-string
write_attribute(:make, val.to_s.titleize)
end
# Force Upper Case for VIN numbers
# Force Upper Case for model numbers
def model=(val)
# The to_s is in case you get nil/non-string
write_attribute(:model, val.to_s.titleize)
@@ -71,8 +77,9 @@ class Vehicle < ActiveRecord::Base
# Force Upper Case for VIN numbers
def vin=(val)
# The to_s is in case you get nil/non-string
write_attribute(:vin, val.to_s.scan(/^[A-Za-z0-9]+$/).join.upcase)
#strip VIN of all illegal chars (for barcode scanner)
val = val.to_s.upcase.gsub(/[^A-HJ-NPR-Za-hj-npr-z\d]+/,"")
write_attribute(:vin, val)
end
# search for a vin
@@ -80,35 +87,14 @@ class Vehicle < ActiveRecord::Base
where("vin LIKE ?", "%#{search}%")
end
private
# init method to pull JSON details from Edmunds
def get_details
if self.vin?
begin
@details = JSON.parse get_decoder.full(self.vin)
raise @details['message'] if @details['status'].to_s.eql? "NOT_FOUND"
raise @details['message'] if @details['status'].to_s.eql? "BAD_REQUEST"
rescue Exception => e
errors.add(:vin, e.message)
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
def decode_vin
get_details
if @details
begin
self.year = @details['years'][0]['year']
self.make = @details['make']['name']
self.model = @details['model']['name']
self.year = @details.year unless @details.year.nil?
self.make = @details.make unless @details.make.nil?
self.model = @details.model unless @details.model.nil?
rescue Exception => e
errors.add(:vin, e.message)
end
@@ -116,15 +102,24 @@ class Vehicle < ActiveRecord::Base
self.name = to_s
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'
private
# init method to pull JSON details from Edmunds
def get_details
if self.vin?
#validate the vin before calling a remote server
validation = NhtsaVin.validate(self.vin)
begin
#if the vin validation failed, raise an exception and exit
raise RuntimeError, validation.error unless validation.valid?
# query NHTSA for details on the vin
query = NhtsaVin.get(self.vin)
raise RuntimeError, query.error unless query.valid?
@details = query.response
rescue Exception => e
errors.add(:vin, e.message)
end
end
v = self.vin[0,11]
return v.slice(0,8) + v.slice(9,11)
end
end

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

View File

@@ -0,0 +1,2 @@
<h3>Customers</h3>
<%= render :partial => 'customers/search' %>

View 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) %>');

View File

@@ -1 +1 @@
$('select#issue_vehicles_id').html('<%= j options_from_collection_for_select(@filtered_vehicles, :id, :to_s) %>');
$('select#issue_vehicles_id').html('<%= j content_tag(:option,'',:value=>"")+options_from_collection_for_select(@filtered_vehicles, :id, :to_s) %>');

View File

@@ -1,10 +1,4 @@
<h1>Customers</h1>
<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/>
<h2>Customers <span style="float:right"> <%= render :partial => 'customers/search' %> </span> </h2>
<% if @customers.present? %>
<br/>
<% @customers.each do |c| %>
@@ -15,6 +9,8 @@
</div>
<% end %>
<p>Matching <%= @customers.count %> Customers </p>
<div class="actions">
<%= will_paginate @customers %>
</div>
@@ -24,5 +20,5 @@
<% end %>
<div>
<%= Customer.count %> Customers - <b>Last Sync: </b> <%= Qbo.last_sync if Qbo.exists? %>
<%= render :partial => 'qbo/stats' %>
</div>

View File

@@ -1,3 +1,3 @@
<h1>New Customer</h1>
<h2>New Customer</h2>
<br/>
<%= render :partial => 'customers/form' %>

View File

@@ -1,16 +1,14 @@
<div id="content">
<h2>Customer #<%= @customer.id %></h2>
<h2>Customer #<%= @customer.id %> - <%= @customer.name %> </h2>
<br/>
<div class="subject">
<div><h3><%= @customer.name %></h3></div>
<div><h3>Details:</h3></div>
</div>
<div class="attributes">
<div class="splitcontent">
<div class="splitcontentleft">
<h4>Details:</h4>
<%= render :partial => 'customers/details', locals: {customer: @customer} %>
</div>
<div class="splitcontentleft">
@@ -24,4 +22,3 @@
<h2>Issues:</h2>
<%= render :partial => 'issues/list_simple', locals: {issues: @issues} %>
</div>
</div>

View File

@@ -48,7 +48,7 @@ This customer link expires in <%= distance_of_time_in_words(Time.now, @token.exp
end
#end
end %>
<%= render_custom_fields_rows(@issue) %>
<%= render_full_width_custom_fields_rows(@issue) %>
<%= call_hook(:view_issues_show_details_bottom, :issue => @issue) %>
</div>

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

View File

@@ -0,0 +1,35 @@
<div class="splitcontent">
<div class="splitcontentleft">
<div class="customer_id attribute">
<div class="label"><span>Customer</span>:</div>
<div class="value"><%= customer %></div>
</div>
<div class="qbo_estimate_id attribute">
<div class="label"><span>Estimate</span>:</div>
<div class="value"><%= estimate_link %></div>
</div>
<div class="qbo_invoice_id attribute">
<div class="label"><span>Invoice</span>:</div>
<div class="value"><%= invoice_link %></div>
</div>
</div>
<div class="splitcontentleft">
<div class="vehicle attribute">
<div class="label"><span>Vehicle</span>:</div>
<div class="value"><%= vehicle %></div>
</div>
<div class="vehicle_vin attribute">
<div class="label"><span>VIN</span>:</div>
<div class="value"><%=split_vin[0] if split_vin%><b><%=split_vin[1] if split_vin%></b></div>
</div>
<div class="vehicle_notes attribute">
<div class="label"><span>Notes</span>:</div>
<div class="value"><%=notes%></div>
</div>
</div>
</div>

View File

@@ -0,0 +1 @@
<b>Last Sync: </b> <%= Qbo.last_sync if Qbo.exists? %>

View File

@@ -20,14 +20,6 @@ intuit.ipp.anywhere.setup({menuProxy: '/path/to/blue-dot', grantUrl: '<%= qbo_au
<table >
<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>
<th>Intuit QBO OAuth Consumer Key</th>

View File

@@ -0,0 +1 @@
<%= Customer.count %> Customers - <%= render :partial => 'qbo/last_sync' %>

View File

@@ -13,22 +13,7 @@
<tr>
<th>VIN</th>
<td><%= vehicle.vin %></td>
</tr>
<tr>
<th>Style</th>
<td><%= vehicle.style %></td>
</tr>
<tr>
<th>Drive</th>
<td><%= vehicle.drive %></td>
</tr>
<tr>
<th>Doors</th>
<td><%= vehicle.doors %></td>
<td><%= @vin[0] if @vin %><b><%=@vin[1] if @vin%></b></td>
</tr>
<tr>
@@ -45,7 +30,6 @@
<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 "Delete", vehicle, method: :delete, data: {confirm: "You sure?"} %>
</td>

View File

@@ -4,9 +4,10 @@
<%= form_for @vehicle do |f| %>
<div class="clearfix">
Customer:
<div class="input">
<%= f.collection_select :customer_id, @customers, :id, :name, include_blank: true, :selected => @customer, :required => true%>
Customer:
<div class="input">
<%= 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>
@@ -41,14 +42,7 @@
<div class="clearfix">
Notes:
<div class="input">
<p>
<%= 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>
<%= f.text_area :notes, :cols => 60, :rows => 10, :no_label => true %>
</div>
</div>

View File

@@ -21,6 +21,8 @@
<%= will_paginate @vehicles %>
</div>
<p>Matching <%= @vehicles.count %> Vehicles </p>
<% else %>
<p>There are no vehicles containing the term(s) <%= params[:search] %>.</p>
<% end %>

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

View File

@@ -1,9 +1,4 @@
<h1>Customer Vehicles</h1>
<h2>Customer Vehicles <span style="float:right"> <%= render :partial => 'vehicles/search' %> </span> </h2>
<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' %>

View File

@@ -1,3 +1,3 @@
<h1>New Customer Vehicle</h1>
<h2>New Customer Vehicle</h2>
<br/>
<%= render :partial => 'vehicles/form' %>

View File

@@ -1,4 +1,4 @@
<h1>Vehicle #<%=@vehicle.id%> </h1>
<h2>Vehicle #<%=@vehicle.id%> <span style="float:right"> <%= render :partial => 'customers/search' %> </span> </h2>
<br/>
<div style="text-align: left; width:90%;">

View File

@@ -5,5 +5,19 @@ $(function() {
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() }
});
});
});

View File

@@ -1,3 +0,0 @@
Edmunds::Api.configure do |config|
config.api_key = '2dheutzvhxs28dzukx5tgu47'
end

View File

@@ -1,6 +1,6 @@
#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:
#
@@ -17,6 +17,7 @@ en:
field_qbo_invoice: "Invoice"
field_qbo_estimate: "Estimate"
field_vehicles: "Vehicle"
field_vehicle: "Vehicle"
field_vin: "VIN"
field_notes: "Notes"
field_qbo_billed: "Billed"

View File

@@ -1,6 +1,6 @@
#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:
#
@@ -34,14 +34,15 @@ resources :payments
#webhook
post 'qbo/webhook', :to => 'qbo#qbo_webhook'
#ajax
#java script routes
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
resources :customers do
resources :vehicles
get :autocomplete_customer_name, :on => :collection
get :autocomplete_customer_vehicles, :on => :collection
end
#allow for just vehicles too

View 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

View 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

View 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

View File

@@ -0,0 +1,15 @@
#The MIT License (MIT)
#
#Copyright (c) 2019 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 AddCustomersPhoneNumber < ActiveRecord::Migration
def change
add_column :customers, :phone_number, :string
end
end

View File

@@ -0,0 +1,15 @@
#The MIT License (MIT)
#
#Copyright (c) 2019 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 AddCustomersMobilePhoneNumber < ActiveRecord::Migration
def change
add_column :customers, :mobile_phone_number, :string
end
end

View File

@@ -0,0 +1,17 @@
#The MIT License (MIT)
#
#Copyright (c) 2020 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 UpdateQbosTypes < ActiveRecord::Migration
def change
change_column :qbos, :qb_token, :text
change_column :qbos, :qb_secret, :text
end
end

View File

@@ -0,0 +1,17 @@
#The MIT License (MIT)
#
#Copyright (c) 2020 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 UpdateQbosToken < ActiveRecord::Migration
def change
add_column :qbos, :token, :text
add_column :qbos, :expire, :datetime
end
end

28
init.rb
View File

@@ -1,6 +1,6 @@
#The MIT License (MIT)
#
#Copyright (c) 2016 rick barrette
#Copyright (c) 2020 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:
#
@@ -16,9 +16,12 @@ Redmine::Plugin.register :redmine_qbo do
require_dependency 'issues_show_hook_listener'
require_dependency 'users_show_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
require_dependency 'issue_patch'
require_dependency 'project_patch'
require_dependency 'user_patch'
require_dependency 'query_patch'
require_dependency 'time_entry_query_patch'
@@ -28,7 +31,7 @@ Redmine::Plugin.register :redmine_qbo do
name 'Redmine Quickbooks Online plugin'
author 'Rick Barrette'
description 'This is a plugin for Redmine to intergrate with Quickbooks Online to allow for seamless intergration CRM and invoicing of completed issues'
version '0.4.2'
version '0.8.1'
url 'https://github.com/rickbarrette/redmine_qbo'
author_url 'http://rickbarrette.org'
settings :default => {'empty' => true}, :partial => 'qbo/settings'
@@ -41,24 +44,23 @@ Redmine::Plugin.register :redmine_qbo do
Issue.safe_attributes 'vehicles_id'
User.safe_attributes 'qbo_employee_id'
TimeEntry.safe_attributes 'qbo_billed'
Project.safe_attributes 'customer_id'
Project.safe_attributes 'vehicle_id'
# We are playing in the sandbox
#Quickbooks.sandbox_mode = true
# 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
#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 :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

View File

@@ -1,6 +1,6 @@
#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:
#

View File

@@ -1,6 +1,6 @@
#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:
#

View File

@@ -1,6 +1,6 @@
#The MIT License (MIT)
#
#Copyright (c) 2016 rick barrette
#Copyright (c) 2020 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:
#
@@ -42,6 +42,12 @@ module IssuePatch
# Create billable time entries
def bill_time
# Check to see if we have everything we need to bill the customer
#return unless status.is_closed?
return if assigned_to.nil?
return unless Qbo.first
return unless customer
# Get unbilled time entries
spent_time = time_entries.where(qbo_billed: [false, nil])
spent_hours ||= spent_time.sum(:hours) || 0
@@ -49,19 +55,21 @@ module IssuePatch
if spent_hours > 0 then
# Prepare to create a new Time Activity
time_service = Qbo.get_base(:time_activity).service
item_service = Qbo.get_base(:item).service
time_service = Qbo.get_base(:time_activity)
item_service = Qbo.get_base(:item)
time_entry = Quickbooks::Model::TimeActivity.new
# Lets total up each activity before billing.
# This will simpify the invoicing with a single billable time entry per time activity
h = Hash.new(0)
spent_time.each do |entry|
# Lets tottal up each activity
h[entry.activity.name] += entry.hours
# update time entries billed status
entry.qbo_billed = true
entry.save
end
# Now letes upload our totals for each activity as their own billable time entry
h.each do |key, val|
# Convert float spent time to hours and minutes
@@ -69,9 +77,11 @@ module IssuePatch
minutesDecimal = (( val - hours) * 60)
minutes = minutesDecimal.to_i
# Lets match the activity to an qbo item
item = item_service.query("SELECT * FROM Item WHERE Name = '#{key}' ").first
next if item.nil?
# Create the new billable time entry and upload it
time_entry.description = "#{tracker} ##{id}: #{subject} #{"(Partial @ #{done_ratio}%)" if not closed?}"
# TODO entry.user.qbo_employee.id
time_entry.employee_id = assigned_to.qbo_employee_id

View File

@@ -1,6 +1,6 @@
#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:
#
@@ -22,6 +22,12 @@ class IssuesFormHookListener < Redmine::Hook::ViewListener
def view_issues_form_details_bottom(context={})
f = context[:form]
#check project level customer/vehicle ownership first
if context[:project]
selected_customer = context[:project].customer ? context[:project].customer.id : nil
selected_vehicle = context[:project].vehicle ? context[:project].vehicle.id : nil
end
# Check to see if there is a quickbooks user attached to the issue
selected_customer = context[:issue].customer ? context[:issue].customer.id : nil
selected_estimate = context[:issue].qbo_estimate ? context[:issue].qbo_estimate.id : nil
@@ -32,15 +38,21 @@ class IssuesFormHookListener < Redmine::Hook::ViewListener
search_customer = f.autocomplete_field :customer, autocomplete_customer_name_customers_path, :selected => selected_customer, :update_elements => {:id => '#issue_customer_id', :value => '#issue_customer'}
customer_id = f.hidden_field :customer_id, :id => "issue_customer_id"
# 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
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
vehicles = [nil].compact
estimates = [nil].compact
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
return "<p><label for=\"issue_customer\">Customer</label>#{search_customer} #{customer_id}</p> <p>#{select_estimate}</p> <p>#{vehicle}</p>"

View File

@@ -1,6 +1,6 @@
#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:
#
@@ -10,47 +10,10 @@
class IssuesSaveHookListener < Redmine::Hook::ViewListener
#Before Issue Saved
def controller_issues_edit_before_save(context={})
issue = context[:issue]
# Check to see if we have registered with QBO
if Qbo.first && issue.customer && issue. qbo_item_id
# if this is a quote, lets create a new estimate based off estimated hours
if issue.tracker.name = "Quote" && issue.status.name = "New" && issue.qbo_estimate
# Get QBO Services
item_service = QboItem.get_base.service
estimate_base = QboEstimate.get_base
# Create the estimate
estimate = estimate_base.qr_model(:estimate)
estimate.customer_id = issue.customer_id
estimate.txn_date = Date.today
# Create the line item for labor
item = item_service.fetch_by_id(issue.qbo_item_id)
line_item = Quickbooks::Model::InvoiceLineItem.new
line_item.amount = item.unit_price * issue.estimated_hours
line_item.description = issue.subject
line_item.sales_item! do |detail|
detail.unit_price = item.unit_price
detail.quantity = issue.estimated_hours
detail.item_id = issue.qbo_item_id
end
# Add the line items to the estimate
estimate.line_items << line_item
end
end
end
# Called After Issue Saved
# Called After Issue Saved
def controller_issues_edit_after_save(context={})
issue = context[:issue]
issue.bill_time if Qbo.first && issue.customer && issue.status.is_closed?
issue.bill_time if issue.status.is_closed?
end
end

View File

@@ -1,6 +1,6 @@
#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:
#
@@ -10,11 +10,6 @@
class IssuesShowHookListener < Redmine::Hook::ViewListener
# Additional context fields
# :issue => the issue this is edited
# :f => the form object to create additional fields
#render_on :view_issues_show_details_bottom, :partial => 'hooks/redmine_qbo/_view_issues_show_details_bottom.html.erb'
# View Issue
# Display the quickbooks contact in the issue
def view_issues_show_details_bottom(context={})
@@ -37,6 +32,7 @@ class IssuesShowHookListener < Redmine::Hook::ViewListener
issue.qbo_invoice_ids.each do |i|
invoice = QboInvoice.find i
invoice_link = invoice_link + link_to( invoice.doc_number, "#{Redmine::Utils::relative_url_root}/qbo/invoice/#{i}", :target => "_blank").to_s + " "
invoice_link = invoice_link.html_safe
end
end
@@ -51,43 +47,17 @@ class IssuesShowHookListener < Redmine::Hook::ViewListener
split_vin = vin.scan(/.{1,9}/) if vin
return "
<div class=\"splitcontent\">
<div class=\"splitcontentleft\">
<div class=\"customer_id attribute\">
<div class=\"label\"><span>Customer</span>:</div>
<div class=\"value\">#{customer}</div>
</div>
<div class=\"qbo_estimate_id attribute\">
<div class=\"label\"><span>Estimate</span>:</div>
<div class=\"value\">#{estimate_link}</div>
</div>
<div class=\"qbo_invoice_id attribute\">
<div class=\"label\"><span>Invoice</span>:</div>
<div class=\"value\">#{invoice_link}</div>
</div>
</div>
<div class=\"splitcontentleft\">
<div class=\"vehicle attribute\">
<div class=\"label\"><span>Vehicle</span>:</div>
<div class=\"value\">#{vehicle}</div>
</div>
<div class=\"vehicle_vin attribute\">
<div class=\"label\"><span>VIN</span>:</div>
<div class=\"value\">#{split_vin[0] if split_vin}<b>#{split_vin[1] if split_vin}</b></div>
</div>
<div class=\"vehicle_notes attribute\">
<div class=\"label\"><span>Notes</span>:</div>
<div class=\"value\">#{notes}</div>
</div>
</div>
</div>"
context[:controller].send(:render_to_string, {
:partial => 'qbo/issues_show_details',
locals: {
customer: customer,
estimate_link: estimate_link,
invoice_link: invoice_link,
vehicle: vehicle,
split_vin: split_vin,
notes: notes
}
})
end
def view_issues_show_description_bottom(context={})

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

View 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

View File

@@ -1,6 +1,6 @@
#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:
#
@@ -52,16 +52,16 @@ module QueryPatch
# :order => @available_filters.size + 1},
#}
qbo_filters = {
"customer_id" => {
:id => :customer_id,
:type => :list_optional,
:order => @available_filters.size + 1,
#qbo_filters = {
# "customer_id" => {
# :id => :customer_id,
# :type => :list_optional
#:order => @available_filters.size + 1,
#:values => Customer.find(:all).collect { |c| [c.name, c.id.to_s]}
}
}
# }
#}
@available_filters.merge!(qbo_filters)
#@available_filters.merge!(qbo_filters)
end
@available_filters
end

View File

@@ -1,6 +1,6 @@
#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:
#

View File

@@ -1,6 +1,6 @@
#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:
#

View File

@@ -1,6 +1,6 @@
#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:
#

View File

@@ -0,0 +1,3 @@
class ViewHookListener < Redmine::Hook::ViewListener
render_on :view_layouts_base_sidebar, :partial => "customers/sidebar"
end