19.0 vanilla

This commit is contained in:
Ernad Husremovic 2026-03-09 09:32:39 +01:00
parent 38c6088dcc
commit d9452d2060
243 changed files with 30797 additions and 10815 deletions

View file

@ -14,41 +14,16 @@ pip install odoo-bringout-oca-ocb-test_website_slides_full
## Dependencies
This addon depends on:
- website_sale_product_configurator
- website_sale_slides
- website_slides_forum
- website_slides_survey
- payment_demo
## Manifest Information
- **Name**: Test Full eLearning Flow
- **Version**: 1.0
- **Category**: Hidden/Tests
- **License**: LGPL-3
- **Installable**: True
## Source
Based on [OCA/OCB](https://github.com/OCA/OCB) branch 16.0, addon `test_website_slides_full`.
- Repository: https://github.com/OCA/OCB
- Branch: 19.0
- Path: addons/test_website_slides_full
## License
This package maintains the original LGPL-3 license from the upstream Odoo project.
## Documentation
- Overview: doc/OVERVIEW.md
- Architecture: doc/ARCHITECTURE.md
- Models: doc/MODELS.md
- Controllers: doc/CONTROLLERS.md
- Wizards: doc/WIZARDS.md
- Reports: doc/REPORTS.md
- Security: doc/SECURITY.md
- Install: doc/INSTALL.md
- Usage: doc/USAGE.md
- Configuration: doc/CONFIGURATION.md
- Dependencies: doc/DEPENDENCIES.md
- Troubleshooting: doc/TROUBLESHOOTING.md
- FAQ: doc/FAQ.md
This package preserves the original LGPL-3 license.

View file

@ -1,16 +1,16 @@
[project]
name = "odoo-bringout-oca-ocb-test_website_slides_full"
version = "16.0.0"
description = "Test Full eLearning Flow - Odoo addon"
description = "Test Full eLearning Flow -
Odoo addon
"
authors = [
{ name = "Ernad Husremovic", email = "hernad@bring.out.ba" }
]
dependencies = [
"odoo-bringout-oca-ocb-website_sale_product_configurator>=16.0.0",
"odoo-bringout-oca-ocb-website_sale_slides>=16.0.0",
"odoo-bringout-oca-ocb-website_slides_forum>=16.0.0",
"odoo-bringout-oca-ocb-website_slides_survey>=16.0.0",
"odoo-bringout-oca-ocb-payment_demo>=16.0.0",
"odoo-bringout-oca-ocb-website_sale_slides>=19.0.0",
"odoo-bringout-oca-ocb-website_slides_forum>=19.0.0",
"odoo-bringout-oca-ocb-website_slides_survey>=19.0.0",
"requests>=2.25.1"
]
readme = "README.md"
@ -20,7 +20,7 @@ classifiers = [
"Intended Audience :: Developers",
"License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Topic :: Office/Business",
]

View file

@ -10,11 +10,9 @@ It will install the e-learning, survey and e-commerce apps and make a complete
certification flow including purchase, certification, failure and success.
""",
'depends': [
'website_sale_product_configurator',
'website_sale_slides',
'website_slides_forum',
'website_slides_survey',
'payment_demo'
],
'data': [
'data/res_groups_data.xml',
@ -25,8 +23,9 @@ certification flow including purchase, certification, failure and success.
'installable': True,
'assets': {
'web.assets_tests': [
'test_website_slides_full/tests/tours/**/*',
'test_website_slides_full/static/tests/tours/**/*',
],
},
'author': 'Odoo S.A.',
'license': 'LGPL-3',
}

View file

@ -4,8 +4,9 @@
<field name="name">Water can</field>
<field name="standard_price">12.0</field>
<field name="list_price">12.0</field>
<field name="detailed_type">consu</field>
<field name="type">consu</field>
<field name="is_published" eval="True"/>
<field name="categ_id" ref="product.product_category_goods"/>
<field name="image_1920" type="base64" file="website_sale_slides/static/img/water_can.jpg"/>
</record>
@ -13,8 +14,9 @@
<field name="name">Flower pot</field>
<field name="standard_price">4.5</field>
<field name="list_price">4.5</field>
<field name="detailed_type">consu</field>
<field name="type">consu</field>
<field name="is_published" eval="True"/>
<field name="categ_id" ref="product.product_category_goods"/>
<field name="image_1920" type="base64" file="website_sale_slides/static/img/flower_pot.jpg"/>
</record>

View file

@ -0,0 +1,164 @@
import { registry } from "@web/core/registry";
/**
* This tour validates the complete certification flow for a student (= portal user).
*
* The tour consists of two main scenarios:
*
* 1. **Failure Attempts**
* - The student is redirected to the "All Courses" page.
* - Navigates to the certification course.
* - Starts the certification process.
* - Fails the test 3 times, exhausting all attempts.
* - Is removed from the course members.
*
* 2. **Successful Attempt**
* - The student is redirected to the "All Courses" page.
* - Navigates to the certification course.
* - Starts the certification process.
* - Successfully completes the certification.
* - The course is marked as completed.
* - The certification is added to their user profile.
*/
var startCertificationSurvey = [{
content: 'eLearning: go to certification course',
trigger: 'a:contains("DIY Furniture - TEST")',
run: "click",
expectUnloadPage: true,
}, {
content: 'eLearning: user should be enrolled',
trigger: '.o_wslides_js_course_join:contains("You\'re enrolled")',
}, {
content: 'eLearning: start course',
trigger: '.o_wslides_js_slides_list_slide_link',
run: "click",
expectUnloadPage: true,
}];
var failCertificationSteps = [{
content: 'eLearning: start certification',
trigger: 'button:contains("Start Certification")',
run: "click",
}, { // Question: What type of wood is the best for furniture?
content: 'Survey: selecting answer "Fir"',
trigger: 'div.js_question-wrapper:contains("What type of wood is the best for furniture") label:contains("Fir")',
run: "click",
}, { // Question: Select all the furniture shown in the video
content: 'Survey: ticking answer "Table"',
trigger: 'div.js_question-wrapper:contains("Select all the furniture shown in the video") label:contains("Table")',
run: "click",
}, {
content: 'Survey: ticking answer "Bed"',
trigger: 'div.js_question-wrapper:contains("Select all the furniture shown in the video") label:contains("Bed")',
run: "click",
}, {
content: 'Survey: submitting the certification with wrong answers',
trigger: 'button:contains("Submit")',
run: "click",
}, {
content: "Click on Submit",
trigger: 'button.btn-primary:contains("Submit")',
run: "click",
}];
var retrySteps = [{
content: 'Survey: retry certification',
trigger: 'a:contains("Retry")',
run: "click",
expectUnloadPage: true,
}];
var succeedCertificationSteps = [{
content: 'eLearning: start certification',
trigger: 'button:contains("Start Certification")',
run: "click",
}, { // Question: What type of wood is the best for furniture?
content: 'Survey: selecting answer "Oak"',
trigger: 'div.js_question-wrapper:contains("What type of wood is the best for furniture") label:contains("Oak")',
run: "click",
}, { // Question: Select all the furniture shown in the video
content: 'Survey: ticking answer "Chair"',
trigger: 'div.js_question-wrapper:contains("Select all the furniture shown in the video") label:contains("Chair")',
run: "click",
}, {
content: 'Survey: ticking answer "Shelve"',
trigger: 'div.js_question-wrapper:contains("Select all the furniture shown in the video") label:contains("Shelve")',
run: "click",
}, {
content: 'Survey: ticking answer "Desk"',
trigger: 'div.js_question-wrapper:contains("Select all the furniture shown in the video") label:contains("Desk")',
run: "click",
}, {
content: 'Survey: submitting the certification with correct answers',
trigger: 'button:contains("Submit")',
run: "click",
}, {
content: "Click on Submit",
trigger: 'button.btn-primary:contains("Submit")',
run: "click",
}];
var certificationCompletionSteps = [{
content: 'Survey: check certification successful',
trigger: 'div:contains("Congratulations, you have passed the test")',
}, { // Sharing the certification
trigger: 'a:contains("Share your certification")',
run: "click",
}, {
trigger: '.o_wslides_js_share_email input',
run: "edit friend@example.com",
}, {
trigger: '.o_wslides_js_share_email button',
run: "click",
}, {
trigger: '.o_wslides_js_share_email .alert:not(.d-none):contains("Sharing is caring")',
}, {
trigger: 'button.btn-close', // close sharing modal,
run: "click",
}, {
content: 'Survey: back to course home page',
trigger: 'a:contains("Go back to course")',
run: "click",
expectUnloadPage: true,
}, {
content: 'eLearning: course should be completed',
trigger: '.o_wslides_channel_completion_completed',
}];
var profileSteps = [{
content: 'eLearning: back to e-learning home page',
trigger: 'a:contains("Courses")',
run: "click",
expectUnloadPage: true,
}, {
content: 'eLearning: access user profile',
trigger: '.o_wslides_home_aside_loggedin a:contains("View")',
run: "click",
expectUnloadPage: true,
}, {
content: 'eLearning: check that the user profile certifications include the new certification',
trigger: '.o_wprofile_slides_course_card_body:contains("Furniture Creation Certification")',
}];
registry.category("web_tour.tours").add('certification_member_failure', {
url: '/slides',
steps: () => [].concat(
startCertificationSurvey,
failCertificationSteps,
retrySteps,
failCertificationSteps,
retrySteps,
failCertificationSteps
)
});
registry.category("web_tour.tours").add('certification_member_success', {
url: '/slides',
steps: () => [].concat(
startCertificationSurvey,
succeedCertificationSteps,
certificationCompletionSteps,
profileSteps
)
});

View file

@ -4,66 +4,21 @@
from dateutil.relativedelta import relativedelta
from odoo.fields import Datetime
from odoo import tests
from odoo.addons.account.tests.common import AccountTestInvoicingCommon
from odoo.tests.common import users
from odoo.addons.website_slides.tests.test_ui_wslides import TestUICommon
@tests.common.tagged('post_install', '-at_install')
class TestUi(AccountTestInvoicingCommon, TestUICommon):
class TestUi(TestUICommon):
def test_course_certification_employee(self):
user_demo = self.user_demo
self.user_demo.write({
'company_id': self.env.company.id,
'company_ids': [(6, 0, self.env.company.ids)],
})
self.user_demo.sudo().partner_id.company_id = self.env.company
# Avoid Billing/Shipping address page
user_demo.write({
'groups_id': [(5, 0), (4, self.env.ref('base.group_user').id)],
'street': '215 Vine St',
'city': 'Scranton',
'zip': '18503',
'country_id': self.env.ref('base.us').id,
'state_id': self.env.ref('base.state_us_39').id,
'phone': '+1 555-555-5555',
'email': 'admin@yourcompany.example.com',
})
def setUp(cls):
super().setUp()
# Specify Accounting Data
cash_journal = self.env['account.journal'].create({'name': 'Cash - Test', 'type': 'cash', 'code': 'CASH - Test'})
self.env['payment.provider'].sudo().search([('code', '=', 'demo')]).write({
'journal_id': cash_journal.id,
'state': 'test',
'website_id': self.env.ref('website.default_website').id,
'company_id': self.env.company.id,
})
self.env.ref('website.default_website').company_id = self.env.company
a_recv = self.env['account.account'].create({
'code': 'X1012',
'name': 'Debtors - (test)',
'reconcile': True,
'account_type': 'asset_receivable',
})
a_pay = self.env['account.account'].create({
'code': 'X1111',
'name': 'Creditors - (test)',
'account_type': 'liability_payable',
'reconcile': True,
})
# =====================
# CERTIFICATION SURVEY
# =====================
Property = self.env['ir.property']
Property._set_default('property_account_receivable_id', 'res.partner', a_recv, self.env.company)
Property._set_default('property_account_payable_id', 'res.partner', a_pay, self.env.company)
product_course_channel_6 = self.env['product.product'].create({
'name': 'DIY Furniture Course',
'list_price': 100.0,
'type': 'service',
'is_published': True,
})
furniture_survey = self.env['survey.survey'].create({
cls.furniture_survey = cls.env['survey.survey'].create({
'title': 'Furniture Creation Certification',
'access_token': '5632a4d7-48cf-aaaa-8c52-2174d58cf50b',
'access_mode': 'public',
@ -72,7 +27,7 @@ class TestUi(AccountTestInvoicingCommon, TestUICommon):
'users_login_required': True,
'scoring_type': 'scoring_with_answers',
'certification': True,
'certification_mail_template_id': self.env.ref('survey.mail_template_certification').id,
'certification_mail_template_id': cls.env.ref('survey.mail_template_certification').id,
'is_attempts_limited': True,
'attempts_limit': 3,
'description': "<p>Test your furniture knowledge!</p>",
@ -143,11 +98,24 @@ class TestUi(AccountTestInvoicingCommon, TestUICommon):
]
})
slide_channel_demo_6_furn3 = self.env['slide.channel'].create({
# ===============
# COURSE PRODUCT
# ===============
cls.furniture_course_product = cls.env['product.product'].create({
'name': 'DIY Furniture Course',
'list_price': 100.0,
'type': 'service',
'is_published': True,
})
# ===============
# COURSE CHANNEL
# ===============
cls.furniture_course = cls.env['slide.channel'].create({
'name': 'DIY Furniture - TEST',
'user_id': self.env.ref('base.user_admin').id,
'user_id': cls.env.ref('base.user_admin').id,
'enroll': 'payment',
'product_id': product_course_channel_6.id,
'product_id': cls.furniture_course_product.id,
'channel_type': 'training',
'allow_comment': True,
'promote_strategy': 'most_voted',
@ -163,13 +131,54 @@ class TestUi(AccountTestInvoicingCommon, TestUICommon):
'is_published': True,
'is_preview': False,
'description': "It's time to test your knowledge!",
'survey_id': furniture_survey.id,
'survey_id': cls.furniture_survey.id,
})
]
})
self.browser_js(
'/slides',
'odoo.__DEBUG__.services["web_tour.tour"].run("certification_member")',
'odoo.__DEBUG__.services["web_tour.tour"].tours.certification_member.ready',
login=user_demo.login)
@users("portal")
def test_course_certification_employee(self):
# use proper environment to test user dependent computes
self.furniture_course = self.env['slide.channel'].browse(self.furniture_course.id)
user_portal = self.env.user
sale_order_data = {
'partner_id': user_portal.partner_id.id,
'order_line': [
(0, 0, {
'name': self.furniture_course_product.name,
'product_id': self.furniture_course_product.id,
'product_uom_qty': 1,
'price_unit': self.furniture_course_product.list_price,
})
]}
# =================
# FAILURE ATTEMPTS
# =================
self.env['sale.order'].sudo().create(sale_order_data).action_confirm()
# Member should have access to the course
self.assertTrue(self.furniture_course.is_member)
self.start_tour('/slides', 'certification_member_failure', login=user_portal.login)
# Member should no longer have access to the course
self.assertFalse(self.furniture_course.is_member)
# ===================
# SUCCESSFUL ATTEMPT
# ===================
self.env['sale.order'].sudo().create(sale_order_data).action_confirm()
# Member regains access to the course
self.assertTrue(self.furniture_course.is_member)
self.start_tour('/slides', 'certification_member_success', login=user_portal.login)
# ============
# EXTRA TESTS
# ============
member = self.env['slide.channel.partner'].sudo().search([
('channel_id', '=', self.furniture_course.id),
('partner_id', '=', user_portal.partner_id.id),
])
self.assertTrue(member)
self.assertEqual(member.member_status, 'completed', "Member status should be 'completed'")
self.assertEqual(member.completion, 100, "Completion rate should be 100%")

View file

@ -1,176 +0,0 @@
odoo.define('test_website_slides_full.tour.slide.certification.member', function (require) {
"use strict";
var tour = require('web_tour.tour');
const tourUtils = require('website_sale.tour_utils');
/**
* The purpose of this tour is to check the whole certification flow:
*
* -> student (= demo user) checks 'on payment' course content
* -> clicks on "buy course"
* -> is redirected to webshop on the product page
* -> buys the course
* -> fails 3 times, exhausting their attempts
* -> is removed to the members of the course
* -> buys the course again
* -> succeeds the certification
* -> has the course marked as completed
* -> has the certification in their user profile
*
*/
var initTourSteps = [{
content: 'eLearning: go to certification course',
trigger: 'a:contains("DIY Furniture - TEST")'
}, {
content: 'eLearning: does not have access to certification',
trigger: '.o_wslides_course_main',
run: function () {
// check that user doesn't have access to course content
if ($('.o_wslides_slides_list_slide .o_wslides_js_slides_list_slide_link').length === 0) {
$('.o_wslides_course_main').addClass('empty-content-success');
}
}
}, {
content: 'eLearning: previous step check',
trigger: '.o_wslides_course_main.empty-content-success',
run: function () {} // check that previous step succeeded
}];
var buyCertificationSteps = [{
content: 'eLearning: try to buy course',
trigger: 'a:contains("Add to Cart")'
},
tourUtils.goToCart(),
{
content: 'eCommerce: Process Checkout',
trigger: 'a:contains("Process Checkout")'
}, {
content: 'eCommerce: select Test payment provider',
trigger: '.o_payment_option_card:contains("Demo")'
}, {
content: 'eCommerce: add card number',
trigger: 'input[name="customer_input"]',
run: 'text 4242424242424242'
}, {
content: 'eCommerce: pay',
trigger: 'button[name="o_payment_submit_button"]'
}, {
content: 'eCommerce: check that the payment is successful',
trigger: '.oe_website_sale_tx_status:contains("Your payment has been successfully processed.")',
run: function () {}
}, {
content: 'eCommerce: go back to e-learning home page',
trigger: '.nav-link:contains("Courses")'
}, {
content: 'eLearning: go into bought course',
trigger: 'a:contains("DIY Furniture")'
}, {
content: 'eLearning: user should be enrolled',
trigger: '.o_wslides_js_course_join:contains("You\'re enrolled")',
run: function () {}
}, {
content: 'eLearning: start course',
trigger: '.o_wslides_js_slides_list_slide_link'
}];
var failCertificationSteps = [{
content: 'eLearning: start certification',
trigger: 'button:contains("Start Certification")'
}, { // Question: What type of wood is the best for furniture?
content: 'Survey: selecting answer "Fir"',
trigger: 'div.js_question-wrapper:contains("What type of wood is the best for furniture") label:contains("Fir")'
}, { // Question: Select all the furniture shown in the video
content: 'Survey: ticking answer "Table"',
trigger: 'div.js_question-wrapper:contains("Select all the furniture shown in the video") label:contains("Table")'
}, {
content: 'Survey: ticking answer "Bed"',
trigger: 'div.js_question-wrapper:contains("Select all the furniture shown in the video") label:contains("Bed")'
}, {
content: 'Survey: submitting the certification with wrong answers',
trigger: 'button:contains("Submit")'
}];
var retrySteps = [{
content: 'Survey: retry certification',
trigger: 'a:contains("Retry")'
}];
var succeedCertificationSteps = [{
content: 'eLearning: start certification',
trigger: 'button:contains("Start Certification")'
}, { // Question: What type of wood is the best for furniture?
content: 'Survey: selecting answer "Oak"',
trigger: 'div.js_question-wrapper:contains("What type of wood is the best for furniture") label:contains("Oak")',
}, { // Question: Select all the furniture shown in the video
content: 'Survey: ticking answer "Chair"',
trigger: 'div.js_question-wrapper:contains("Select all the furniture shown in the video") label:contains("Chair")'
}, {
content: 'Survey: ticking answer "Shelve"',
trigger: 'div.js_question-wrapper:contains("Select all the furniture shown in the video") label:contains("Shelve")'
}, {
content: 'Survey: ticking answer "Desk"',
trigger: 'div.js_question-wrapper:contains("Select all the furniture shown in the video") label:contains("Desk")'
}, {
content: 'Survey: submitting the certification with correct answers',
trigger: 'button:contains("Submit")'
}];
var certificationCompletionSteps = [{
content: 'Survey: check certification successful',
trigger: 'div:contains("Congratulations, you have passed the test")',
run: function () {}
}, { // Sharing the certification
trigger: 'a:contains("Share your certification")'
}, {
trigger: '.oe_slide_js_share_email input',
run: 'text friend@example.com'
}, {
trigger: '.oe_slide_js_share_email button',
}, {
trigger: '.oe_slide_js_share_email .alert:not(.d-none):contains("Sharing is caring")',
run: function () {} // check email has been sent
}, {
trigger: 'button.btn-close', // close sharing modal
}, {
content: 'Survey: back to course home page',
trigger: 'a:contains("Go back to course")'
}, {
content: 'eLearning: back to e-learning home page',
trigger: '.nav-link:contains("Courses")'
}, {
content: 'eLearning: course should be completed',
trigger: '.o_wslides_course_card:contains("DIY Furniture") .rounded-pill:contains("Completed")',
run: function () {}
}];
var profileSteps = [{
content: 'eLearning: access user profile',
trigger: '.o_wslides_home_aside_loggedin a:contains("View")'
}, {
content: 'eLearning: check that the user profile certifications include the new certification',
trigger: '.o_wprofile_slides_course_card_body:contains("Furniture Creation Certification")',
run: function () {}
}];
tour.register('certification_member', {
url: '/slides',
test: true
}, [].concat(
initTourSteps,
buyCertificationSteps,
failCertificationSteps,
retrySteps,
failCertificationSteps,
retrySteps,
failCertificationSteps,
[{trigger: 'a:contains("Go back to course")'}],
buyCertificationSteps,
succeedCertificationSteps,
certificationCompletionSteps,
profileSteps
)
);
});