Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Uploading a file (pdf, jpeg, xls....) #151

Closed
GildedHonour opened this issue Aug 18, 2014 · 29 comments
Closed

Uploading a file (pdf, jpeg, xls....) #151

GildedHonour opened this issue Aug 18, 2014 · 29 comments

Comments

@GildedHonour
Copy link

I've got a Python script which is supposed to upload files to Quick Books by their API. I've faced into some issues which I couldn't have solved such as "This type can't be consumed" (for application/pdf, xml and others) or when I used "multipart/form-data" it said "Could find no content-disposition header with in a part" or when I'd changed it a bit, it seemed to work well (there were no errors in the response) but the attachments weren't really uploaded.

I'd like to upload a file (pdf, jpeg, xls....) using this gem to make sure it really works well and there is no mistake in the API of Quick Books. I'm familiar with this gem but didn't find a model or service in its source code which looked like the one I was looking for (Attachable, File or something else).

So is there any simple example?

@ruckus
Copy link
Owner

ruckus commented Aug 18, 2014

I didnt even know there was an API endpoint that allowed for file uploads. Which endpoint supports file attachments?

@ruckus
Copy link
Owner

ruckus commented Aug 18, 2014

If your error is reproducible every time and its not clear from the documentation than you should ask your question on StackOverflow and be sure to tag your question with intuit-partner-platform so it goes into the correct section: http://stackoverflow.com/questions/tagged/intuit-partner-platform

@GildedHonour
Copy link
Author

The endpoint is "https://quickbooks.api.intuit.com/v3/company/:company_id/upload"

I'd like to try it in Ruby before asking on so.

@ruckus
Copy link
Owner

ruckus commented Aug 18, 2014

I don't see any discussion of an upload endpoint on the CompanyInfo page. Where did you get that URL?

https://developer.intuit.com/docs/0025_quickbooksapi/0050_data_services/030_entity_services_reference/companyinfo

1 similar comment
@ruckus
Copy link
Owner

ruckus commented Aug 18, 2014

I don't see any discussion of an upload endpoint on the CompanyInfo page. Where did you get that URL?

https://developer.intuit.com/docs/0025_quickbooksapi/0050_data_services/030_entity_services_reference/companyinfo

@ruckus
Copy link
Owner

ruckus commented Aug 18, 2014

I was able to successfully upload an image file, in this branch:

https://github.com/ruckus/quickbooks-ruby/compare/file-upload-prototype

I'm still not able to download a file. Intuit is not accepting the download request, so thats a work in progress.

But note that the uploading is done by the multipart-post gem as well as the monkey-patch (which you can see in the above diff, its at quickbooks/lib/multipart.rb

@GildedHonour
Copy link
Author

I - vise versa - was able to download a file and not upload, but that was in Python. Would you mind providing me the whole example? I'm going to examine it carefully and find out what http headers it sends.

@ruckus
Copy link
Owner

ruckus commented Aug 18, 2014

All my code is contained in the branch diff at:

https://github.com/ruckus/quickbooks-ruby/compare/file-upload-prototype

I think the heavy-lifting is done by:

  1. multipart-post gem
  2. The monkeypatch which adds this to the OAuth library:
    https://github.com/ruckus/quickbooks-ruby/blob/ce6d0f62ca30ab9f4a1f8900ea1fd8dfeb60dcf2/lib/quickbooks/util/multipart.rb

Then the complete uploading code is:

service = Quickbooks::Service::Upload.new({access_token: token, company_id: "123" })
service.perform(File.new("./tmp/monkey.jpg"), "image/jpeg")

@GildedHonour
Copy link
Author

I couldn't run it. I've created a ruby script (not a rails app) test1.rb and a Gemfile:

#Gemfile
gem "quickbooks-ruby", git: "https://github.com/ruckus/quickbooks-ruby.git", branch: "file-upload-prototype"


#test1.rb
require 'rubygems'
require 'bundler/setup'
require 'quickbooks-ruby'

service = Quickbooks::Service::Upload.new({access_token: "my_access_tokes", company_id: "123" })
a = service.perform(File.new("test1.jpg"), "image/jpeg")
puts a

The error:

/Users/alex/.rvm/gems/ruby-2.1.2/bundler/gems/quickbooks-ruby-ce6d0f62ca30/lib/quickbooks/service/base_service.rb:229:in `do_http': undefined method `post_with_multipart' for "my_access_tokes":String (NoMethodError)
    from /Users/alex/.rvm/gems/ruby-2.1.2/bundler/gems/quickbooks-ruby-ce6d0f62ca30/lib/quickbooks/service/base_service.rb:199:in `do_http_file_upload'
    from /Users/alex/.rvm/gems/ruby-2.1.2/bundler/gems/quickbooks-ruby-ce6d0f62ca30/lib/quickbooks/service/upload.rb:8:in `perform'
    from test2.rb:8:in `<main>'

  1. But it's already added to your gem as a dependency and I don't have to do anything, do I?
  2. Should I do that myself in my local machine? Where is the monkey patch exactly?

@ruckus
Copy link
Owner

ruckus commented Aug 19, 2014

Yes, you need a valid OAuth Access Token from the QB service. The values I sent you are obviously invalid:

service = Quickbooks::Service::Upload.new({access_token: "my_access_tokes", company_id: "123" })

So you won't be able to run the code as-is. Thus, at best you can just inspect what the code does and hopefully that helps!

On Aug 18, 2014, at 5:05 PM, Alex Maslakov notifications@github.com wrote:

I can't run. I've created a ruby script (not a rails app) test1.rb and a Gemfile:

#Gemfile
gem "quickbooks-ruby", git: "https://github.com/ruckus/quickbooks-ruby.git", branch: "file-upload-prototype"

#test1.rb
require 'rubygems'
require 'bundler/setup'

require your gems as usual

require 'quickbooks-ruby'

service = Quickbooks::Service::Upload.new({access_token: "my_access_tokes", company_id: "123" })
a = service.perform(File.new("test1.jpg"), "image/jpeg")
puts a
The error:

/Users/alex/.rvm/gems/ruby-2.1.2/bundler/gems/quickbooks-ruby-ce6d0f62ca30/lib/quickbooks/service/base_service.rb:229:in do_http': undefined methodpost_with_multipart' for "my_access_tokes":String (NoMethodError)
from /Users/alex/.rvm/gems/ruby-2.1.2/bundler/gems/quickbooks-ruby-ce6d0f62ca30/lib/quickbooks/service/base_service.rb:199:in do_http_file_upload' from /Users/alex/.rvm/gems/ruby-2.1.2/bundler/gems/quickbooks-ruby-ce6d0f62ca30/lib/quickbooks/service/upload.rb:8:inperform'
from test2.rb:8:in `

'


Reply to this email directly or view it on GitHub.

@GildedHonour
Copy link
Author

my_access_tokes - isn't the actual token I have, I have the real token, of course, but I didn't post it here, the same for company id.

So what's wrong then?

I have
app_token,
consumer_key
consumer_secret

access_token
access_token_secret
company_id

All are pre-calculated already somehow and were used successfully in the Python code.

@ruckus
Copy link
Owner

ruckus commented Aug 19, 2014

Ok, so if you have both the Access Token and Access Secret (which are BOTH STRINGS), than you need to create an actual OAuth::AccessToken object via:

https://github.com/ruckus/quickbooks-ruby#creating-an-oauth-access-token

and its that object you pass into:

service = Quickbooks::Service::Upload.new({access_token: "my_access_tokes", company_id: "123" })

But your error indicates are you passing in a string and not the real object:

undefined method `post_with_multipart' for "my_access_tokes":String (NoMethodError)

On Aug 18, 2014, at 5:15 PM, Alex Maslakov notifications@github.com wrote:

my_access_tokes - isn't the actual token I have, I have the real token, of course, but I didn't post it here, the same for company id.

So what's wrong then?


Reply to this email directly or view it on GitHub.

@GildedHonour
Copy link
Author

Great, it worked well, thanks.

@GildedHonour
Copy link
Author

Uploading multiple files at the same time is supported by the API https://developer.intuit.com/docs/0025_quickbooksapi/0050_data_services/020_key_concepts/attachments#Multi-Part_Upload_Requests

Is there any way to do that? For now I can upload only one file:

service.perform(File.new("/test1.pdf"), "image/jpeg")

@GildedHonour GildedHonour reopened this Aug 20, 2014
@ruckus
Copy link
Owner

ruckus commented Aug 20, 2014

In my file uploading proof-of-concept I didn't do multiple files, just one at a time. But it should be straight-forward enough to add. If you look at how the code is setup:

https://github.com/ruckus/quickbooks-ruby/blob/file-upload-prototype/lib/quickbooks/service/base_service.rb#L195

You would just generate more "file_content_N" and "file_metadata_N" hash key/value pairs.

So one could just allow passing in an array of uploadIO objects into the do_http_file_upload method which iterates over each and adds in the key/value pairs.

On Aug 19, 2014, at 11:25 PM, Alex Maslakov notifications@github.com wrote:

Uploading multiple files at the same time is supported by the API https://developer.intuit.com/docs/0025_quickbooksapi/0050_data_services/020_key_concepts/attachments#Multi-Part_Upload_Requests

Is there any way to that? For now I can upload only one file:

service.perform(File.new("/test1.pdf"), "image/jpeg")

Reply to this email directly or view it on GitHub.

@GildedHonour
Copy link
Author

I created a pull request.

It failed. Should I run the tests on my machine before creating a pull request?

@GildedHonour
Copy link
Author

Should I run the tests on my machine before creating a pull request?

@ruckus
Copy link
Owner

ruckus commented Sep 4, 2014

Yes, one should always run tests locally before submitting a PR.

Thanks!

On Sep 4, 2014, at 4:43 AM, Alex Maslakov notifications@github.com wrote:

Should I run the tests on my machine before creating a pull request?


Reply to this email directly or view it on GitHub.

@GildedHonour
Copy link
Author

I decided to do a pull request. Actually, the tests fail initially in the branch file-upload-prototype, even if I don't touch anything, 32 ones failure. Will you fix them or should I fix them?

@ruckus
Copy link
Owner

ruckus commented Feb 22, 2015

I've been working on this in a separate branch: attachable. Please review this issue which has more details and a working implementation. Although, right now it doesnt support multiple files.

#218

@GildedHonour
Copy link
Author

Nobody is working on that? I can work?

@ruckus
Copy link
Owner

ruckus commented Feb 23, 2015

@GildedHonour I dont understand your question (?) Are you suggesting that you are interested in taking that branch and trying to get multiple files to work? You're totally welcome too, of course.

A big question is how do we deal with failure scenarios? E.g. in a batch of 5 uploads+metadata, what happens if 1 fails but all the other succeed? How should this be reported back to the user? Is an exception raised after the first failure, or do you keep chugging along and pass that information back to the user at the end?

@GildedHonour
Copy link
Author

Yes.

I think we should keep trying to upload it giving it a finite number of attempts, when they're exceeded - return an error. Otherwise not to notify the user.

@ruckus
Copy link
Owner

ruckus commented Feb 23, 2015

I'm not so sure. If we put the burden on the user to do the iteration over their set of files [to upload] than I think it makes it more explicit and makes our code simpler. Largely, because I imagine that if errors ARE encountered during an upload they are not transient (e.g. network connection) and its because the upload itself is invalid, hence whats the point of trying again for 3-4 times, each time getting the same error?

Ultimately, i think its simpler to only have a one-upload-at-a-time API interface and require the user to do their own iteration, thus doing their own error handling.

@minimul
Copy link
Collaborator

minimul commented Feb 24, 2015

+1 on the one-upload-at-a-time interface.

@GildedHonour
Copy link
Author

If we put the burden on the user to do the iteration over their set of files [to upload] than I think it makes it more explicit and makes our code simpler.

No, I mean, the library should handle it itself. The user doesn't have to do anything, maybe only being notified that "something is wrong, attempt number 2...". It's a pretty standard behaviour in most applications.

@GildedHonour
Copy link
Author

Ultimately, i think its simpler to only have a one-upload-at-a-time API interface and require the user to do their own iteration, thus doing their own error handling.

Do you mean leave it as it is now?

@ruckus
Copy link
Owner

ruckus commented Feb 24, 2015

@GildedHonour yes, I propose keeping it at one-at-a-time for now.

@ruckus ruckus closed this as completed Mar 27, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants