summaryrefslogtreecommitdiff
path: root/addons
diff options
context:
space:
mode:
authorAurélien Warnon <awa@odoo.com>2019-02-11 12:32:19 +0000
committerThibault Delavallée <tde@odoo.com>2019-02-11 17:46:40 +0000
commit9b7bee73e5b6c09656c3720a5c9709f3948534c0 (patch)
tree8ae9dccb279ec0c01800ec0dc1f9695a717c03f8 /addons
parentfb8126ddd7d0eb6a55435c1eadf99df6cf4fb658 (diff)
[ADD] website_sale_slides: allow to sell slide.channel
Task #1937160 Purpose ======= This commit adds sale capabilities to a slide.channel. A slide.channel can now have the 'payment' visibility, that requires a 'product_id' configured on the channel. When a customer purchases a product linked to a channel, he is added to the members of the channel (see slide.channel.partner_ids) when his order is confirmed. The feature is added in a new module 'website_sale_slides' that comes as a bridge auto-installed between 'website_slides' and 'website_sale'. The final goal is to be able to sell "courses" (see task #1902304).
Diffstat (limited to 'addons')
-rw-r--r--addons/website_sale_slides/__init__.py4
-rw-r--r--addons/website_sale_slides/__manifest__.py17
-rw-r--r--addons/website_sale_slides/data/demo-thumbnails/5WMqwTnZ-qs.pngbin0 -> 196182 bytes
-rw-r--r--addons/website_sale_slides/data/demo-thumbnails/product_course.pngbin0 -> 109408 bytes
-rw-r--r--addons/website_sale_slides/data/demo-thumbnails/ptjeDDoURL8.pngbin0 -> 210254 bytes
-rw-r--r--addons/website_sale_slides/data/website_sale_slides_demo.xml46
-rw-r--r--addons/website_sale_slides/models/__init__.py4
-rw-r--r--addons/website_sale_slides/models/sale_order.py35
-rw-r--r--addons/website_sale_slides/models/slide_channel.py20
-rw-r--r--addons/website_sale_slides/tests/__init__.py4
-rw-r--r--addons/website_sale_slides/tests/test_course_purchase_flow.py46
-rw-r--r--addons/website_sale_slides/views/slide_channel_views.xml16
-rw-r--r--addons/website_slides/models/slide_channel.py14
13 files changed, 203 insertions, 3 deletions
diff --git a/addons/website_sale_slides/__init__.py b/addons/website_sale_slides/__init__.py
new file mode 100644
index 00000000000..dc5e6b693d1
--- /dev/null
+++ b/addons/website_sale_slides/__init__.py
@@ -0,0 +1,4 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from . import models
diff --git a/addons/website_sale_slides/__manifest__.py b/addons/website_sale_slides/__manifest__.py
new file mode 100644
index 00000000000..59d15170b4b
--- /dev/null
+++ b/addons/website_sale_slides/__manifest__.py
@@ -0,0 +1,17 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+{
+ 'name': "Sell Courses",
+ 'summary': 'Sell your courses online',
+ 'description': """Sell your courses using the e-commerce features of the website.""",
+ 'category': 'Hidden',
+ 'version': '0.1',
+
+ 'depends': ['website_slides', 'website_sale'],
+ 'installable': True,
+ 'auto_install': True,
+ 'data': [
+ 'data/website_sale_slides_demo.xml',
+ 'views/slide_channel_views.xml',
+ ]
+}
diff --git a/addons/website_sale_slides/data/demo-thumbnails/5WMqwTnZ-qs.png b/addons/website_sale_slides/data/demo-thumbnails/5WMqwTnZ-qs.png
new file mode 100644
index 00000000000..1bbec207f29
--- /dev/null
+++ b/addons/website_sale_slides/data/demo-thumbnails/5WMqwTnZ-qs.png
Binary files differ
diff --git a/addons/website_sale_slides/data/demo-thumbnails/product_course.png b/addons/website_sale_slides/data/demo-thumbnails/product_course.png
new file mode 100644
index 00000000000..db59564cebc
--- /dev/null
+++ b/addons/website_sale_slides/data/demo-thumbnails/product_course.png
Binary files differ
diff --git a/addons/website_sale_slides/data/demo-thumbnails/ptjeDDoURL8.png b/addons/website_sale_slides/data/demo-thumbnails/ptjeDDoURL8.png
new file mode 100644
index 00000000000..dc3c43dd8a6
--- /dev/null
+++ b/addons/website_sale_slides/data/demo-thumbnails/ptjeDDoURL8.png
Binary files differ
diff --git a/addons/website_sale_slides/data/website_sale_slides_demo.xml b/addons/website_sale_slides/data/website_sale_slides_demo.xml
new file mode 100644
index 00000000000..554e7500133
--- /dev/null
+++ b/addons/website_sale_slides/data/website_sale_slides_demo.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<odoo>
+ <data>
+ <record id="product_course" model="product.product">
+ <field name="name">Furniture creation course</field>
+ <field name="standard_price">100.0</field>
+ <field name="list_price">100.0</field>
+ <field name="type">service</field>
+ <field name="website_published" eval="True"/>
+ <field name="image" type="base64" file="website_sale_slides/data/demo-thumbnails/product_course.png"/>
+ </record>
+
+ <record id="channel_on_payment" model="slide.channel">
+ <field name="name">Furniture creation</field>
+ <field name="promote_strategy">most_viewed</field>
+ <field name="website_published" eval="True"/>
+ <field name="description">All you need to know about furniture creation.</field>
+ <field name="visibility">payment</field>
+ <field name="product_id" ref="product_course"/>
+ </record>
+
+ <record id="slide_find_wood" model="slide.slide">
+ <field name="name">How to find quality wood.</field>
+ <field name="url">https://www.youtube.com/watch?v=5WMqwTnZ-qs</field>
+ <field name="document_id">5WMqwTnZ-qs</field>
+ <field name="slide_type">video</field>
+ <field name="channel_id" ref="channel_on_payment"/>
+ <field name="website_published" eval="True"/>
+ <field name="is_preview" eval="True"/>
+ <field name="image" type="base64" file="website_sale_slides/data/demo-thumbnails/5WMqwTnZ-qs.png"/>
+ <field name="description">Learn of to identify quality wood in order to create solid furnitures.</field>
+ </record>
+
+ <record id="slide_create_furniture" model="slide.slide">
+ <field name="name">How to create your own piece of furniture.</field>
+ <field name="url">https://www.youtube.com/watch?v=ptjeDDoURL8</field>
+ <field name="document_id">ptjeDDoURL8</field>
+ <field name="slide_type">video</field>
+ <field name="channel_id" ref="channel_on_payment"/>
+ <field name="website_published" eval="True"/>
+ <field name="is_preview" eval="True"/>
+ <field name="image" type="base64" file="website_sale_slides/data/demo-thumbnails/ptjeDDoURL8.png"/>
+ <field name="description">From a piece of wood to a fully functional furniture, step by step.</field>
+ </record>
+ </data>
+</odoo>
diff --git a/addons/website_sale_slides/models/__init__.py b/addons/website_sale_slides/models/__init__.py
new file mode 100644
index 00000000000..715f352d147
--- /dev/null
+++ b/addons/website_sale_slides/models/__init__.py
@@ -0,0 +1,4 @@
+# -*- coding: utf-8 -*-
+
+from . import slide_channel
+from . import sale_order
diff --git a/addons/website_sale_slides/models/sale_order.py b/addons/website_sale_slides/models/sale_order.py
new file mode 100644
index 00000000000..880bd0636e6
--- /dev/null
+++ b/addons/website_sale_slides/models/sale_order.py
@@ -0,0 +1,35 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from odoo import models, api
+
+
+class SaleOrder(models.Model):
+ _inherit = "sale.order"
+
+ @api.multi
+ def _action_confirm(self):
+ """ If the product of an order line is a 'course', we add the client of the sale_order
+ as a member of the channel(s) on which this product is configured (see slide.channel.product_id). """
+ result = super(SaleOrder, self)._action_confirm()
+
+ so_lines = self.env['sale.order.line'].search(
+ [('order_id', 'in', self.ids)]
+ )
+ products = so_lines.mapped('product_id')
+ related_channels = self.env['slide.channel'].search(
+ [('product_id', 'in', products.ids)]
+ )
+ channel_products = related_channels.mapped('product_id')
+
+ channels_per_so = {sale_order: self.env['slide.channel'] for sale_order in self}
+ for so_line in so_lines:
+ if so_line.product_id in channel_products:
+ for related_channel in related_channels:
+ if related_channel.product_id == so_line.product_id:
+ channels_per_so[so_line.order_id] = channels_per_so[so_line.order_id] | related_channel
+
+ for sale_order, channels in channels_per_so.items():
+ channels._action_add_member(target_partner=sale_order.partner_id)
+
+ return result
diff --git a/addons/website_sale_slides/models/slide_channel.py b/addons/website_sale_slides/models/slide_channel.py
new file mode 100644
index 00000000000..1947d15b08a
--- /dev/null
+++ b/addons/website_sale_slides/models/slide_channel.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from odoo import models, fields
+
+
+class Channel(models.Model):
+ _inherit = 'slide.channel'
+
+ visibility = fields.Selection(selection_add=[('payment', 'On payment')])
+ product_id = fields.Many2one('product.product', 'Product', index=True)
+
+ _sql_constraints = [
+ ('product_id_check', "CHECK( visibility!='payment' OR product_id IS NOT NULL )", "Product is required for on payment channels.")
+ ]
+
+ def _filter_add_member(self, target_user, **member_values):
+ """ Overridden to add 'payment' channels to the filtered channels """
+ result = super(Channel, self)._filter_add_member(target_user, **member_values)
+ return result | self.filtered(lambda channel: channel.visibility == 'payment')
diff --git a/addons/website_sale_slides/tests/__init__.py b/addons/website_sale_slides/tests/__init__.py
new file mode 100644
index 00000000000..536fe88b96c
--- /dev/null
+++ b/addons/website_sale_slides/tests/__init__.py
@@ -0,0 +1,4 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from . import test_course_purchase_flow
diff --git a/addons/website_sale_slides/tests/test_course_purchase_flow.py b/addons/website_sale_slides/tests/test_course_purchase_flow.py
new file mode 100644
index 00000000000..c97a0269f93
--- /dev/null
+++ b/addons/website_sale_slides/tests/test_course_purchase_flow.py
@@ -0,0 +1,46 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from odoo.addons.website_slides.tests import common
+
+
+class TestCoursePurchaseFlow(common.SlidesCase):
+ def test_course_purchase_flow(self):
+ # Step1: create a course product and assign it to 2 slide.channels
+ course_product = self.env['product.product'].create({
+ 'name': "Course Product",
+ 'standard_price': 100,
+ 'list_price': 150,
+ 'type': 'service',
+ 'invoice_policy': 'order',
+ })
+
+ self.channel.write({
+ 'visibility': 'payment',
+ 'product_id': course_product.id
+ })
+
+ self.channel_2 = self.env['slide.channel'].sudo(self.user_publisher).create({
+ 'name': 'Test Channel',
+ 'visibility': 'payment',
+ 'product_id': course_product.id
+ })
+
+ # Step 2: create a sale_order with the course product
+ sale_order = self.env['sale.order'].create({
+ 'partner_id': self.customer.id,
+ 'order_line': [
+ (0, 0, {
+ 'name': course_product.name,
+ 'product_id': course_product.id,
+ 'product_uom_qty': 1,
+ 'price_unit': course_product.list_price,
+ })
+ ],
+ })
+
+ sale_order.action_confirm()
+
+ # Step 3: check that the customer is now a member of both channel
+ self.assertIn(self.customer, self.channel.partner_ids)
+ self.assertIn(self.customer, self.channel_2.partner_ids)
diff --git a/addons/website_sale_slides/views/slide_channel_views.xml b/addons/website_sale_slides/views/slide_channel_views.xml
new file mode 100644
index 00000000000..cbf499cc6e7
--- /dev/null
+++ b/addons/website_sale_slides/views/slide_channel_views.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<odoo>
+ <data>
+ <record id="slide_channel_view_form" model="ir.ui.view">
+ <field name="name">slide.channel.view.form.inherit.sale</field>
+ <field name="model">slide.channel</field>
+ <field name="inherit_id" ref="website_slides.view_slide_channel_form"/>
+ <field name="arch" type="xml">
+ <xpath expr="//field[@name='visibility']" position="after">
+ <field name="product_id"
+ attrs="{'invisible': [('visibility', '!=', 'payment')], 'required': [('visibility', '=', 'payment')]}" />
+ </xpath>
+ </field>
+ </record>
+ </data>
+</odoo>
diff --git a/addons/website_slides/models/slide_channel.py b/addons/website_slides/models/slide_channel.py
index cad83a33b7e..9c7fcef352c 100644
--- a/addons/website_slides/models/slide_channel.py
+++ b/addons/website_slides/models/slide_channel.py
@@ -250,10 +250,18 @@ class Channel(models.Model):
# ---------------------------------------------------------
def action_add_member(self, **member_values):
- new_cp = self._action_add_member(target_partner=self.env.user.partner_id, **member_values)
- return bool(new_cp)
+ """ Adds the logged in user in the channel members.
+ (see '_action_add_member' for more info)
- def _action_add_member(self, target_partner, **member_values):
+ Returns True if added successfully, False otherwise."""
+ return bool(self._action_add_member(target_partner=self.env.user.partner_id, **member_values))
+
+ def _action_add_member(self, target_partner=False, **member_values):
+ """ Add the target_partner as a member of the channel (to its slide.channel.partner).
+ This will make the content (slides) of the channel available to that partner.
+
+ Returns the added 'slide.channel.partner's (! as sudo !)
+ """
existing = self.env['slide.channel.partner'].sudo().search([
('channel_id', 'in', self.ids),
('partner_id', '=', target_partner.id)