diff --git a/addons/website_sale_digital/__init__.py b/addons/website_sale_digital/__init__.py new file mode 100644 index 00000000000..dedfc9ab606 --- /dev/null +++ b/addons/website_sale_digital/__init__.py @@ -0,0 +1,4 @@ +# -*- encoding: utf-8 -*- +import controllers +import product +import account_invoice diff --git a/addons/website_sale_digital/__openerp__.py b/addons/website_sale_digital/__openerp__.py new file mode 100644 index 00000000000..9883efe53ac --- /dev/null +++ b/addons/website_sale_digital/__openerp__.py @@ -0,0 +1,21 @@ +# -*- encoding: utf-8 -*- +{ + 'name': 'Website Sale Digital - Sell digital products', + 'version': '0.1', + 'description': """ +Sell digital product using attachments to virtual products +""", + 'author': 'Odoo S.A.', + 'depends': [ + 'document', + 'website_sale', + ], + 'installable': True, + 'data': [ + 'views/website_sale_digital.xml', + 'views/website_sale_digital_view.xml', + ], + 'demo': [ + 'demo.xml', + ], +} diff --git a/addons/website_sale_digital/account_invoice.py b/addons/website_sale_digital/account_invoice.py new file mode 100644 index 00000000000..29ab67fb7a4 --- /dev/null +++ b/addons/website_sale_digital/account_invoice.py @@ -0,0 +1,19 @@ +# -*- encoding: utf-8 -*- +from openerp import models, fields, api, _ + +class account_invoice_line(models.Model): + _inherit = ['account.invoice.line'] + + def get_digital_purchases(self,uid): + user = self.env['res.users'].browse(uid) + partner = user.partner_id + + # Get paid invoices + purchases = self.sudo().search_read( + domain=[('invoice_id.state', '=', 'paid'), ('invoice_id.partner_id', '=', partner.id), ('product_id.product_tmpl_id.digital_content', '=', True)], + fields=['product_id'], + ) + + # I only want product_ids, but search_read insists in giving me a list of + # (product_id: , name: ) + return map(lambda x: x['product_id'][0], purchases) \ No newline at end of file diff --git a/addons/website_sale_digital/controllers/__init__.py b/addons/website_sale_digital/controllers/__init__.py new file mode 100644 index 00000000000..1d9fb74e019 --- /dev/null +++ b/addons/website_sale_digital/controllers/__init__.py @@ -0,0 +1,2 @@ +# -*- encoding: utf-8 -*- +import main diff --git a/addons/website_sale_digital/controllers/main.py b/addons/website_sale_digital/controllers/main.py new file mode 100644 index 00000000000..276d1752c4e --- /dev/null +++ b/addons/website_sale_digital/controllers/main.py @@ -0,0 +1,112 @@ +# -*- coding: utf-8 -*- + +import base64 +from openerp.addons.web import http +from openerp.addons.web.http import request +from openerp.addons.website.controllers.main import Website +from openerp.addons.website_sale.controllers.main import website_sale +from cStringIO import StringIO +from werkzeug.utils import redirect + + +class website_sale_digital(website_sale): + + orders_page = '/shop/orders' + + @http.route([ + '/shop/confirmation', + ], type='http', auth="public", website=True) + def payment_confirmation(self, **post): + response = super(website_sale_digital, self).payment_confirmation(**post) + order_lines = response.qcontext['order'].order_line + digital_content = map(lambda x: x.product_id.digital_content, order_lines) + response.qcontext.update(digital=any(digital_content)) + return response + + @http.route([ + '/shop/orders', + '/shop/orders/page/', + ], type='http', auth='user', website=True) + def orders_followup(self, page=1, **post): + response = super(website_sale_digital, self).orders_followup(**post) + + order_products_attachments = {} + for o in response.qcontext['orders']: + invoiced_lines = request.env['account.invoice.line'].sudo().search([('invoice_id', 'in', o.invoice_ids.ids), ('invoice_id.state', '=', 'paid')]) + + purchased_products_attachments = {} + for il in invoiced_lines: + p_obj = il.product_id + # Ignore products that do not have digital content + if not p_obj.product_tmpl_id.digital_content: + continue + + # Search for product attachments + A = request.env['ir.attachment'] + p_id = p_obj.id + template = p_obj.product_tmpl_id + att = A.search_read( + domain=['|', '&', ('res_model', '=', p_obj._name), ('res_id', '=', p_id), '&', ('res_model', '=', template._name), ('res_id', '=', template.id)], + fields=['name', 'write_date'], + order='write_date desc', + ) + + # Ignore products with no attachments + if not att: + continue + + purchased_products_attachments[p_id] = att + + order_products_attachments[o.id] = purchased_products_attachments + + response.qcontext.update({ + 'digital_attachments': order_products_attachments, + }) + return response + + @http.route([ + '/shop/download', + ], type='http', auth='public') + def download_attachment(self, attachment_id): + # Check if this is a valid attachment id + attachment = request.env['ir.attachment'].sudo().search_read( + [('id', '=', int(attachment_id))], + ["name", "datas", "file_type", "res_model", "res_id", "type", "url"] + ) + + if attachment: + attachment = attachment[0] + else: + return redirect(self.orders_page) + + + # Check if the user has bought the associated product + res_model = attachment['res_model'] + res_id = attachment['res_id'] + purchased_products = request.env['account.invoice.line'].get_digital_purchases(request.uid) + + if res_model == 'product.product': + if res_id not in purchased_products: + return redirect(self.orders_page) + + # Also check for attachments in the product templates + elif res_model == 'product.template': + P = request.env['product.product'] + template_ids = map(lambda x: P.browse(x).product_tmpl_id.id, purchased_products) + if res_id not in template_ids: + return redirect(self.orders_page) + + else: + return redirect(self.orders_page) + + # The client has bought the product, otherwise it would have been blocked by now + if attachment["type"] == "url": + if attachment["url"]: + return redirect(attachment["url"]) + else: + return request.not_found() + elif attachment["datas"]: + data = StringIO(base64.standard_b64decode(attachment["datas"])) + return http.send_file(data, filename=attachment['name'], as_attachment=True) + else: + return request.not_found() diff --git a/addons/website_sale_digital/demo.xml b/addons/website_sale_digital/demo.xml new file mode 100644 index 00000000000..8572f210aaa --- /dev/null +++ b/addons/website_sale_digital/demo.xml @@ -0,0 +1,21 @@ + + + Alice's Adventures in Wonderland - Lewis Caroll + 2 + 4.50 + service + + + + Novel by Lewis Caroll. + Alice's Adventures in Wonderland (commonly shortened to Alice in Wonderland) is an 1865 novel written by English author Charles Lutwidge Dodgson under the pseudonym Lewis Carroll. It tells of a girl named Alice falling through a rabbit hole into a fantasy world populated by peculiar, anthropomorphic creatures. The tale plays with logic, giving the story lasting popularity with adults as well as with children. It is considered to be one of the best examples of the literary nonsense genre. Its narrative course and structure, characters and imagery have been enormously influential in both popular culture and literature, especially in the fantasy genre. + + + alice.pdf + alice.pdf + binary + + + product.template + + diff --git a/addons/website_sale_digital/product.py b/addons/website_sale_digital/product.py new file mode 100644 index 00000000000..beeb5edb330 --- /dev/null +++ b/addons/website_sale_digital/product.py @@ -0,0 +1,8 @@ +# -*- encoding: utf-8 -*- +from openerp import models, fields, api, _ + + +class product_template(models.Model): + _inherit = ['product.template'] + + digital_content = fields.Boolean('Digital Content', help="If checked, it will allow clients to download the product attachments when they have bought it.") diff --git a/addons/website_sale_digital/static/alice.pdf b/addons/website_sale_digital/static/alice.pdf new file mode 100644 index 00000000000..10276ceb279 Binary files /dev/null and b/addons/website_sale_digital/static/alice.pdf differ diff --git a/addons/website_sale_digital/static/digital_product_1.jpg b/addons/website_sale_digital/static/digital_product_1.jpg new file mode 100644 index 00000000000..51d7780ee65 Binary files /dev/null and b/addons/website_sale_digital/static/digital_product_1.jpg differ diff --git a/addons/website_sale_digital/views/website_sale_digital.xml b/addons/website_sale_digital/views/website_sale_digital.xml new file mode 100644 index 00000000000..b62c315fdb6 --- /dev/null +++ b/addons/website_sale_digital/views/website_sale_digital.xml @@ -0,0 +1,20 @@ + + + + \ No newline at end of file diff --git a/addons/website_sale_digital/views/website_sale_digital_view.xml b/addons/website_sale_digital/views/website_sale_digital_view.xml new file mode 100644 index 00000000000..d4c4c708d15 --- /dev/null +++ b/addons/website_sale_digital/views/website_sale_digital_view.xml @@ -0,0 +1,14 @@ + + + + product.normal.form + product.template + + + + + + + + +