[ADD] website_sale_digital: allows the user to set a product as digital product and use the attachments to sell files. The download link is added on the My Orders page when the payment is confirmed

This commit is contained in:
David Monjoie
2015-01-16 15:47:18 +01:00
committed by Antony Lesuisse
parent 9c70e9242b
commit 8a1b8e880c
11 changed files with 221 additions and 0 deletions
+4
View File
@@ -0,0 +1,4 @@
# -*- encoding: utf-8 -*-
import controllers
import product
import account_invoice
@@ -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',
],
}
@@ -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: <id>, name: <product code> <template_name> <attributes>)
return map(lambda x: x['product_id'][0], purchases)
@@ -0,0 +1,2 @@
# -*- encoding: utf-8 -*-
import main
@@ -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/<int: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()
+21
View File
@@ -0,0 +1,21 @@
<odoo>
<record id="website_sale_digital.product_1" model="product.template">
<field name="name">Alice's Adventures in Wonderland - Lewis Caroll</field>
<field name="standard_price">2</field>
<field name="list_price">4.50</field>
<field name="type">service</field>
<field name="digital_content" eval="True"/>
<field name="website_published" eval="True"/>
<field name="image" type="base64" file="website_sale_digital/static/digital_product_1.jpg"/>
<field name="description">Novel by Lewis Caroll.</field>
<field name="description_sale">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.</field>
</record>
<record id="website_sale_digital.attach1" model="ir.attachment">
<field name="name">alice.pdf</field>
<field name="datas_fname">alice.pdf</field>
<field name="type">binary</field>
<field name="datas" type="base64" file="website_sale_digital/static/alice.pdf"/>
<field name="res_id" ref="website_sale_digital.product_1"/>
<field name="res_model">product.template</field>
</record>
</odoo>
+8
View File
@@ -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.")
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 185 KiB

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template id="orders_followup_downloads" name="Orders Downloads Followup" inherit_id="website_sale.order_invoice">
<xpath expr="//div[@id='product_name']" position="inside">
<t t-set="attachments" t-value="digital_attachments[o.id].get(ol.product_id.id)"/>
<t t-if="attachments">
<span class="dropdown">
<button class="btn btn-xs btn-default dropdown-toggle" type="button" id="dropdownMenu1" data-toggle="dropdown">
Downloads <span class="caret"></span>
</button>
<ul class="dropdown-menu" role="menu" aria-labelledby="dropdownMenu1">
<t t-foreach="attachments" t-as="a">
<li role="presentation"><a role="menuitem" tabindex="-1" t-att-href="'/shop/download?attachment_id=%i' % a['id']"><t t-esc="a['name']"/></a></li>
</t>
</ul>
</span>
</t>
</xpath>
</template>
</odoo>
@@ -0,0 +1,14 @@
<?xml version="1.0" ?>
<odoo>
<record model="ir.ui.view" id="view_product_form_expiry">
<field name="name">product.normal.form</field>
<field name="model">product.template</field>
<field name="inherit_id" ref="product.product_template_form_view" />
<field name="arch" type="xml">
<field name="type" position="after">
<field name="digital_content" />
</field>
</field>
</record>
</odoo>