Initial commit: Sale packages

This commit is contained in:
Ernad Husremovic 2025-08-29 15:20:49 +02:00
commit 14e3d26998
6469 changed files with 2479670 additions and 0 deletions

View file

@ -0,0 +1,65 @@
<?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='enroll']" position="after">
<field name="product_id"
attrs="{'invisible': [('enroll', '!=', 'payment')], 'required': [('enroll', '=', 'payment')]}"
context="{'default_detailed_type': 'course', 'default_invoice_policy': 'order', 'default_purchase_ok': False, 'default_sale_ok': True, 'default_website_published': True}"/>
</xpath>
<xpath expr="//button[@name='action_redirect_to_members']" position="after">
<button name="action_view_sales"
type="object"
icon="fa-usd"
class="oe_stat_button"
attrs="{'invisible': [('enroll', '!=', 'payment')]}"
groups="sales_team.group_sale_salesman">
<field name="product_sale_revenues" string="Sales" widget="statinfo"/>
</button>
</xpath>
</field>
</record>
<record id="slide_channel_view_tree_report" model="ir.ui.view">
<field name="name">slide.channel.view.tree.report.inherit.sale_slides</field>
<field name="model">slide.channel</field>
<field name="inherit_id" ref="website_slides.slide_channel_view_tree_report"/>
<field name="arch" type="xml">
<field name="members_done_count" position="after">
<field name="currency_id" invisible="1"/>
<field name="product_sale_revenues" string="Total Revenues" sum="Total Revenues" widget="monetary"/>
</field>
</field>
</record>
<record id="slide_channel_view_kanban" model="ir.ui.view">
<field name="name">slide.channel.view.kanban.inherit.sale</field>
<field name="model">slide.channel</field>
<field name="inherit_id" ref="website_slides.slide_channel_view_kanban"/>
<field name="arch" type="xml">
<xpath expr="//div[@name='info_total_time']" position="after">
<div class="d-flex" attrs="{'invisible': [('enroll', '!=', 'payment')]}">
<span class="me-auto"><label for="product_sale_revenues" class="mb0">Sales</label></span>
<field name="product_sale_revenues" widget="monetary" options="{'currency_field': 'currency_id'}"/>
<field name="currency_id" attrs="{'invisible': True}"/>
</div>
</xpath>
</field>
</record>
<record id="slide_channel_view_form_add_inherit_sale_slides" model="ir.ui.view">
<field name="name">slide.channel.view.form.add.inherit.sale.slides</field>
<field name="model">slide.channel</field>
<field name="inherit_id" ref="website_slides.slide_channel_view_form_add"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='allow_comment']" position="after">
<field name="enroll" widget="radio" options="{'horizontal': true}" string="Enroll Policy"/>
<field name="product_id" attrs="{'invisible': [('enroll', '!=', 'payment')], 'required': [('enroll', '=', 'payment')]}"
context="{'default_detailed_type': 'course', 'default_invoice_policy': 'order', 'default_purchase_ok': False, 'default_sale_ok': True, 'default_website_published': True}"/>
</xpath>
</field>
</record>
</data></odoo>

View file

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template id="snippet_options" inherit_id="website.snippet_options" name="Slides Snippet Options">
<xpath expr="." position="inside">
<div data-selector="main:has(.o_wslides_course_header)" data-page-options="true" groups="website.group_website_designer" data-no-check="true" string="Course Page">
<we-checkbox string="Buy Now Button"
data-customize-website-views="website_sale_slides.course_option_buy_course_now"
data-no-preview="true"
data-reload="/"/>
</div>
</xpath>
</template>
</odoo>

View file

@ -0,0 +1,56 @@
<?xml version="1.0" ?>
<odoo><data>
<template id="website_sale_confirmation_slide" inherit_id="website_sale.confirmation">
<xpath expr="//div[@id='oe_structure_website_sale_confirmation_2']" position="after">
<t t-if="any(product.detailed_type == 'course' for product in order.order_line.product_id)" t-call="website_sale_slides.course_purchased_confirmation_message"/>
</xpath>
</template>
<template id="course_purchased_confirmation_message">
<div>
<h4>
<t t-if="order.state == 'sale'">You have gained access to the following course(s):</t>
<t t-else="">Once your order is paid &amp; confirmed, you will gain access to:</t>
</h4>
</div>
<div class="mt-2">
<t t-foreach="order.order_line" t-as="line">
<t t-set="signup_token" t-value="order.partner_id.signup_prepare() and order.partner_id.signup_token"/>
<div t-foreach="line.product_id.channel_ids" t-as="course" class="row mx-0 my-2 border">
<t t-set="slide_url" t-valuef="/web/login?token=#{signup_token}&amp;redirect=/slides/#{slug(course)}"/>
<div class="col-5 d-flex justify-content-center my-auto">
<span t-if="course.image_1920" t-field="course.image_1920" t-options="{'widget': 'image', 'class': 'my-2'}"/>
<img t-else="" class="img img-fluid my-2" src="/website_slides/static/src/img/channel-training-default.jpg"/>
</div>
<div class="col-7">
<a t-att-href="slide_url"><h3 t-out="course.name" class="m-2"/></a>
<div t-out="course.description_short" class="fw-light o_wslides_desc_truncate_2 ms-2"/>
<div class="fw-light ms-2 mt-2">
<t t-out="course.total_time" t-options="{'widget': 'duration', 'unit': 'hour', 'round': 'minute'}"/>
<t t-if="course.total_slides">
<t t-if="course.total_time"> - </t><t t-out="course.total_slides"/> step(s)
</t>
</div>
<a role="button" class="btn btn-primary ms-2 my-2" t-att-href="slide_url">
Start Learning
</a>
</div>
</div>
</t>
</div>
</template>
<template id="cart_summary_inherit_website_sale_slides"
inherit_id="website_sale.cart_summary"
name="Course Cart right column">
<xpath expr="//td[hasclass('td-product_name')]/div/strong" position="after">
<div t-if="line.product_id.channel_ids"
t-foreach="line.product_id.channel_ids.filtered(lambda course: course.enroll == 'payment')"
t-as="course"
t-esc="course.name"/>
</xpath>
</template>
</data></odoo>

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<menuitem name="Revenues"
id="website_slides_menu_report_revenues"
parent="website_slides.website_slides_menu_report"
sequence="3"
action="sale_report_action_slides"/>
</odoo>

View file

@ -0,0 +1,163 @@
<?xml version="1.0" ?>
<odoo><data>
<!-- LESSON -->
<template id="lesson_content_quiz" inherit_id="website_slides.lesson_content_quiz">
<xpath expr="//div[hasclass('o_wslides_js_lesson_quiz')]" position="attributes">
<attribute name="t-att-data-price">product_info['price'] if product_info else None</attribute>
<attribute name="t-att-data-currency-name">product_info['currency_id'].name if product_info else None</attribute>
<attribute name="t-att-data-currency-symbol">product_info['currency_id'].symbol if product_info else None</attribute>
<attribute name="t-att-data-has-discounted-price">product_info['has_discounted_price'] if product_info else None</attribute>
<attribute name="t-att-data-product-id">slide.channel_id.product_id.id if slide.channel_id.product_id else None</attribute>
<attribute name="t-att-data-list-price">product_info['list_price'] if product_info else None</attribute>
</xpath>
</template>
<template name="Buy Course To Download Resource" id="slide_aside_training_category_buy_course" inherit_id="website_slides.slide_aside_training_category">
<xpath expr="//div[hasclass('o_wslides_js_course_join') and hasclass('o_wslides_no_access')]" position="inside">
<li t-elif="aside_slide.channel_id.enroll == 'payment'" class="text-decoration-none small">
<i class="fa fa-download me-1"/>
<t t-call="website_sale_slides.course_buy_course_link">
<t t-set="for_resources" t-value="1"/>
<t t-set="slide" t-value="aside_slide"/>
</t>
</li>
</xpath>
</template>
<template name="Buy Course To Access Resources or Interact Slide Detail" id="slide_content_detailed_buy_course" inherit_id="website_slides.slide_content_detailed">
<xpath expr="//div[hasclass('o_wslides_js_course_join') and hasclass('o_wslides_no_access')]" position="inside">
<span t-elif="slide.channel_id.enroll == 'payment'" class="text-muted me-auto border-start ps-3">
<t t-call="website_sale_slides.course_buy_course_link">
<t t-set="for_resources" t-value="1"/>
</t>
</span>
</xpath>
<xpath expr="//div[hasclass('o_wslides_js_course_join') and hasclass('o_wslides_no_access_comments')]" position="inside">
<span t-elif="slide.channel_id.enroll == 'payment'">
<t t-call="website_sale_slides.course_buy_course_link"/>
</span>
</xpath>
</template>
<!-- Tweak "preview" badge: display Free Preview if payment-based course -->
<template id="course_slides_list_slide"
name="Slide template for a training channel (Sale)"
inherit_id="website_slides.course_slides_list_slide">
<xpath expr="//a[@t-if='channel.can_upload']/span/span" position="replace">
<span t-if="channel.enroll == 'payment'">Free Preview</span>
<span t-else="">Preview</span>
</xpath>
<xpath expr="//t[@t-elif='slide.is_preview and not channel.is_member']/span/span" position="replace">
<span t-if="channel.enroll == 'payment'">Free Preview</span>
<span t-else="">Preview</span>
</xpath>
</template>
<!-- FULLSCREEN -->
<template id="slide_fullscreen" inherit_id="website_slides.slide_fullscreen">
<xpath expr="//div[hasclass('o_wslides_fs_main')]" position="attributes">
<attribute name="t-att-data-price">product_info['price'] if product_info else None</attribute>
<attribute name="t-att-data-currency-name">product_info['currency_id'].name if product_info else None</attribute>
<attribute name="t-att-data-currency-symbol">product_info['currency_id'].symbol if product_info else None</attribute>
<attribute name="t-att-data-has-discounted-price">product_info['has_discounted_price'] if product_info else None</attribute>
<attribute name="t-att-data-product-id">slide.channel_id.product_id.id if product_info else None</attribute>
<attribute name="t-att-data-list-price">product_info['list_price'] if product_info else None</attribute>
</xpath>
</template>
<template name="Buy Course To Download Resource Fullscreen" id="slide_fullscreen_sidebar_category_buy_course" inherit_id="website_slides.slide_fullscreen_sidebar_category">
<xpath expr="//div[hasclass('o_wslides_js_course_join') and hasclass('o_wslides_no_access')]" position="inside">
<li t-elif="slide.channel_id.enroll == 'payment'" class="o_wslides_fs_slide_link mb-1">
<i class="fa fa-download me-1"/>
<t t-call="website_sale_slides.course_buy_course_link">
<t t-set="for_resources" t-value="1"/>
</t>
</li>
</xpath>
</template>
<!-- COURSE -->
<template name="Course Main" id="course_main" inherit_id="website_slides.course_main">
<xpath expr="//div[@id='home']" position="before">
<div t-if="channel.enroll == 'payment' and not channel.product_id.is_published"
class="alert alert-info" role="alert" groups="website_slides.group_website_slides_officer">
This course cannot be bought because its linked product
<a t-attf-href="/web#id=#{channel.product_id.product_tmpl_id.id}&amp;view_type=form&amp;model=#{channel.product_id.product_tmpl_id._name}&amp;action=website_sale.product_template_action_website"
class="alert-link" t-out="channel.product_id.name"/>
is not published.
</div>
</xpath>
</template>
<template name="Course Sidebar (infos, CTA)" id="course_join" inherit_id="website_slides.course_join">
<!-- Channel main template: override button to join channel -->
<xpath expr="//div[hasclass('o_wslides_js_course_join')]" position="inside">
<t t-if="(not channel.is_member or channel.can_publish) and channel.enroll == 'payment'">
<t t-call="website_sale_slides.course_buy_course_button" />
</t>
</xpath>
</template>
<!-- TOOLS -->
<template name="Buy Course Link" id="course_buy_course_link">
<a class="post_link" t-att-href="'/shop/cart/update?product_id=%s' % slide.channel_id.product_id.id">
Join this Course</a><t t-if="for_resources"> to access resources</t>
</template>
<template name="Buy Course Button" id="course_buy_course_button">
<t t-if="product_info and channel.product_id.website_published and not channel.is_member">
<div t-attf-class="text-center d-flex align-items-center text-center pb-1 #{'justify-content-between' if product_info['has_discounted_price'] else 'justify-content-around'}">
<div class="css_editable_mode_hidden">
<!-- real price -->
<div t-attf-class="oe_price fw-bold text-nowrap my-2 #{'h4' if len(str(product_info['price'])) > 10 else 'h2'}"
t-esc="product_info['price']"
t-options="{'widget': 'monetary', 'display_currency': product_info['currency_id']}"/>
<span itemprop="price" style="display:none;" t-esc="product_info['price']"/>
<span itemprop="priceCurrency" style="display:none;" t-esc="product_info['currency_id'].name"/>
<!-- original discounted price, if any -->
<del t-att-class="'text-600 text-nowrap oe_default_price %s' % ('' if product_info['has_discounted_price'] else 'd-none')"
t-esc="product_info['list_price']"
t-options="{'widget': 'monetary', 'display_currency': product_info['currency_id']}"/>
</div>
<div class="css_non_editable_mode_hidden decimal_precision oe_price fw-bold text-nowrap h2 my-2"
t-att-data-precision="str(product_info['currency_id'].decimal_places)">
<span t-field="channel.product_id.list_price" t-options="{'widget': 'monetary', 'display_currency': product_info['currency_id']}"/>
</div>
</div>
<div class="oe_website_sale">
<div class="add_to_cart_button">
<form action="/shop/cart/update" method="POST">
<input type="hidden" name="csrf_token" t-att-value="request.csrf_token()" />
<input type="hidden" class="product_id" name="product_id" t-att-value="channel.product_id.id"/>
<a id="add_to_cart" role="button" href="#"
class="btn btn-primary d-block js_check_product o_js_add_to_cart a-submit"
data-animation-selector=".o_wslides_course_pict">
<i class="fa fa-shopping-cart"></i> Add to Cart
</a>
<div id="product_option_block"/>
</form>
</div>
</div>
</t>
<t t-elif="not channel.is_member">
<div class="alert my-0 bg-200 text-center">
Course Unavailable
</div>
</t>
</template>
<template name="Display 'Buy Now'" id="course_option_buy_course_now" inherit_id="website_sale_slides.course_buy_course_button" active="False">
<xpath expr="//div[hasclass('add_to_cart_button')]" position="before">
<div class="mb-1">
<a role="button" class="post_link btn btn-primary d-block" t-attf-href="/shop/cart/update?product_id={{channel.product_id.id}}&amp;express=1">
<i class="fa fa-bolt"></i> Buy Now
</a>
</div>
</xpath>
<xpath expr="//div[hasclass('add_to_cart_button')]//a[@id='add_to_cart']" position="attributes">
<attribute name="class">btn btn-outline-primary d-block js_check_product o_js_add_to_cart a-submit</attribute>
</xpath>
</template>
</data></odoo>