Odoo v12 API get invoice PDF - api

This question got me started with my C# Odoo API implementation. I have working code using CookComputing.XmlRpcV2 to retrieve a list of invoices.
What I would like to implement is the option to retrieve/download a PDF of a selected invoice. Does anybody know what I would need to get this done?
When I search, I find forum posts stating reporting doesn't work since V11, such as this one. Neither do I see it mentioned in the online documentation for V12, although there is mention of it at the bottom of the page for V10.
Update
Someone mentioned to construct an URL:
http://localhost:8069/my/invoices/1?report_type=pdf&download=true&access_token=<ACCESSTOKEN>
Where 1 is the invoice ID. Technically this works, but requires me to be logged in to the portal using the browser. Even if I can log into the portal from my C# service, I do not know where/how to retrieve the correct access token. I can see this is in GUID form. Does anybody know whether this is the same token I could retrieve from the OAuth2 REST API (which is a paid module b.t.w.)?

Correct. You can download the PDF by placing in the access_token.
This is the only way I managed to figure it out for Odoo v.12. after smashing my head against a brick wall repeatedly. My example programming language is with Python 3 though, not C#, but I'm sure you can adapt it.
odoo_url_host = "https://company.odoo.com"
The access_token can be found in the invoice's JSON response.
invoice_id = 1234
models = xmlrpcclient.ServerProxy('{}/xmlrpc/2/object'.format(odoo_url_host))
invoice = models.execute_kw(db, uid, password, "account.invoice", read, [[invoice_id]])
which, provided you get back a found invoice, you can use the response like so:
print(invoice["access_token"])
download_url = "%s/%s/my/invoices/%d?report_type=pdf&download=true&access_token=%s" % (odoo_url_host, invoice_id, invoice["access_token"])
Which if you simply want to automatically download, can be done like so:
import urllib.request
pdf_destination = "./invoices/invoice-%d.pdf" % invoice_id
urllib.request.urlretrieve(download_url, pdf_destination)
You'd need to change the way this is written for Python 2.7.
Also, make sure that you click 'share' on the invoice (within odoo) as sometimes the access_token doesn't get generated for that invoice and returns false otherwise.
Or if you'd like to seamlessly have the access_token generated, execute this before trying to get the access token:
ctx = {'active_model': 'account.invoice', 'active_id': invoice_id}
print(models.execute_kw(db, uid, password, 'portal.share', 'default_get',[{}],{'context': ctx}))
That should get you the share_link for the entire document, but all you need is the access_token to be generated. You can extract the access_token from the share_link value in the JSON response, if you'd like to do it that way. Anyway :) Happy coding.

I would try to use /xmlrpc/2/object with model ir.actions.report and method render_qweb_pdf. Bear in mind that you'll need a ir.actions.report record, because render_qweb_pdf isn't a "model method" (in OOP class method).

I am currently testing a similar functionality but with stock.picking where I need delivery form downloaded from a remote Odoo instance and saved as an attachment in another instance. What I did is adding this function to stock.picking in remote Odoo.
#api.model
def sd_get_delivery_form(self, uid):
picking = self.env['stock.picking'].sudo().search([('sd_uid', 'like', uid)], limit=1)
if picking and picking.sale_id:
pdf = self.env.ref('sale.action_report_saleorder').sudo().render_qweb_pdf([picking.sale_id.id])
b64_pdf = base64.b64encode(pdf[0])
order_pdf = b64_pdf.decode('utf-8')
return {'file': order_pdf}
else:
return False
Then calling it using xmlrpc and save it as an attachment
attachment_name = "delivery_order_({})".format(self.id)
self.env['ir.attachment'].create({
'name': attachment_name,
'type': 'binary',
'datas': dt['file'],
'datas_fname': attachment_name + '.pdf',
'store_fname': attachment_name,
'res_model': self._name,
'res_id': self.id,
'mimetype': 'application/x-pdf'
})
What you can do in C# is getting the base64 and save it as PDF if you like to go in this similar way.

The simplest way is to use OdooRPC library : https://pythonhosted.org/OdooRPC/ref_report.html

Related

REST API modeling

I got two models, a Notebook and a Note one.
I got two routes than can achieve the same (post a note for a specific notebook)
POST /api/note , need to pass notebook ref (id) in the submited datas
POST /api/notebook/[ID]/note , with now now only the note data
Note that I don't need "notes that would not be attached to a notebook".
I read many docs about REST APIs, but I can figured out what's the "best" way.
Does anybody here have some good docs for me?
I assume that a note can only exist in one and only one notebook. Then a note is a subresoure of a notebook. A note is identifed by
/api/notebook/{notebookId}/note/{noteId}
A new note inside a notebook is created by
POST /api/notebook/1234/note
Content-Type: application/json
{
// details of the note without reference to the notebook
}
The server returns
201 Created
Location: /api/notebook/1234/note/B175A7F2-1434-11E5-AFD4-82854B860EDE
with B175A7F2-1434-11E5-AFD4-82854B860EDE being a unique ID assigned to the new note by the server.

Bigcommerce API Add Images

Using the legacy API in bigcommerce, trying to add a product image without success. I have done this before but it seems to not work now.
The API documentation says that there is a function to 'create a product image', however it says that the field 'product_id' is read only and any request will be rejected if it is included. If that is true and not a typo, how are you supposed to create a product image against a product?
Don't add product ID to the parameters, add it to the url. So if you want to add images to product 12345, make a post to
'/products/12345/images'
of the image data
{ 'sort_order': 1, 'image_file': 'http://blah.jpg' }

Which way is it better to call ORM methods in Odoo 7?

Let's say you have in your code an object of model 'account.invoice' and inside a method you want to update the partner. I noticed that you have two ways of calling the 'write' method on model 'res.partner'. You could either do :
invoice.partner_id.write({'name': 'Mister Test'})
OR
partner_obj = self.pool.get('res.partner')
partner_obj.write(cr, uid, invoice.partner_id.id, {'name': 'Mister Test'})
I always used the second way because it is the one that is always described in documentations. However, I discovered that the first way is also working and is shorter. Is it ok to do so ?
When object is browse record than I direct write browse record object.write({'field_name': value})
invoice.partner_id.write({'name': 'Mister Test'})
This line give error because partner_id is a many2one field so it's store integer number. So you can’t use this.
For this you must to browse that partner_id and than you may to write on partner object.
And second point, if you want write something in invoice object than you can use this for example invoice.write({'field_name': value}) this will work.
Hope this make a sense.

Create direct url to LinkedIn company update

I'm implementing a Compony newsfeed on a website and ran into the following problem. The LinkedIn API doesn't provide a direct URL to a company update. Looking at the LinkedIn site there are direct URL's and they're like this for example:
https://www.linkedin.com/company/1441/comments?topic=5849556347070205952&type=U&scope=1441&stype=C&a=5uHW&goback=%2Ebzo_*1_*1_*1_*1_*1_*1_*1_1441
Trying stuff out it seems that the parameters topic, type, scope, stype and a are mandatory for the URL to work.. (goback is the only one that isn't).
Using the LinkedIn API with the Company updates call I'm able to buid the direct url, except for the a parameter. The value is always 4 (for me unexplainable) characters long.
Has anyone ever successfully build a direct URL to a company update or can someone maybe explain the a parameter or how to generate its value?
Updated to new format
You can link directly to any update (company or user) using the following url:
https://www.linkedin.com/feed/update/urn:li:activity:[topic_id]
You can get [topic_id] by getting the last bit of the updateKey in the api response from Linkedin. When updateKey = UPDATE-c7352-6410848097894756353, your topic_id = 6410848097894756353.
In your example that would become https://www.linkedin.com/feed/update/urn:li:activity:5849556347070205952 which links directly to the specific update. The post is too old to work with the new link format
The url used to be
https://www.linkedin.com/nhome/updates/?topic=[topic_id]
Updated thanks to the comment from #sethpollack
For anyone trying to get the topic id from the API response object (as already commented on the OP question), the topic id is the value after the last hyphen of the updateKey property, which can be used with #Daan answer:
"updateKey": "UPDATE-cXXXX-YYYYYYYYYYYYYYYYYY"
Direct URL:
https://www.linkedin.com/nhome/updates?topic=[YYYYYYYYYYYYYYYYYY]
Using the URL format above, get the topic_id by opening the update in its own window/tab, look at the page source code in your browser and search for the string :activity: the long number after the string is the infamous topic_id

How to POST new product in shopify store via api from a private app?

i'm using shopify_app gem and i was able to read to my shop. but then i can't write to it. i have set up the read/write credentials while installing my app so i'm sure the problem's not there. here's what i did to POST a new product in my shop:
product = ShopifyAPI::Product.new
product.title= "Nike Bag"
product.price_range = "27.00"
product.save
but it doesn't save.
Thank you so much. I need this badly.
It looks like this problem has already been solved in the shopify api google group, but just posting it here just in case somebody else finds it useful.
The product above can't be saved because not all required fields are specified. Check the sample in the shopify api docs for a list of required fields. Also check product.errors if save fails, which should give an idea of why it failed.
This should work:
product = ShopifyAPI::Product.new
product.product_type = "Snowboard"
product.title = "Burton Custom Freestlye 151"
product.body_html = "<strong>Good snowboard!</strong>"
product.vendor = "Burton"
product.variants = [ShopifyAPI::Variant.new(:price =>10)]
product.save