summaryrefslogtreecommitdiff
path: root/addons/sale_product_configurator/views
diff options
context:
space:
mode:
authorstephanchrst <stephanchrst@gmail.com>2022-05-10 21:51:50 +0700
committerstephanchrst <stephanchrst@gmail.com>2022-05-10 21:51:50 +0700
commit3751379f1e9a4c215fb6eb898b4ccc67659b9ace (patch)
treea44932296ef4a9b71d5f010906253d8c53727726 /addons/sale_product_configurator/views
parent0a15094050bfde69a06d6eff798e9a8ddf2b8c21 (diff)
initial commit 2
Diffstat (limited to 'addons/sale_product_configurator/views')
-rw-r--r--addons/sale_product_configurator/views/assets.xml28
-rw-r--r--addons/sale_product_configurator/views/sale_views.xml43
-rw-r--r--addons/sale_product_configurator/views/templates.xml220
3 files changed, 291 insertions, 0 deletions
diff --git a/addons/sale_product_configurator/views/assets.xml b/addons/sale_product_configurator/views/assets.xml
new file mode 100644
index 00000000..5665e7dd
--- /dev/null
+++ b/addons/sale_product_configurator/views/assets.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<odoo>
+ <template id="assets_backend" inherit_id="web.assets_backend" name="sale_product_configurator assets backend">
+ <xpath expr="script[last()]" position="after">
+ <script type="text/javascript" src="/sale/static/src/js/variant_mixin.js"></script>
+ <script type="text/javascript" src="/sale_product_configurator/static/src/js/product_configurator_renderer.js"></script>
+ <script type="text/javascript" src="/sale_product_configurator/static/src/js/product_configurator_controller.js"></script>
+ <script type="text/javascript" src="/sale_product_configurator/static/src/js/product_configurator_view.js"></script>
+ <script type="text/javascript" src="/sale_product_configurator/static/src/js/product_configurator_widget.js"/>
+ <script type="text/javascript" src="/sale_product_configurator/static/src/js/product_configurator_modal.js"></script>
+ </xpath>
+ </template>
+ <template id="assets_tests" name="Sale Product Configurator Assets Tests" inherit_id="web.assets_tests">
+ <xpath expr="." position="inside">
+ <script type="text/javascript" src="/sale_product_configurator/static/tests/tours/product_configurator_ui.js"/>
+ <script type="text/javascript" src="/sale_product_configurator/static/tests/tours/product_configurator_advanced_ui.js"/>
+ <script type="text/javascript" src="/sale_product_configurator/static/tests/tours/product_configurator_edition_ui.js"/>
+ <script type="text/javascript" src="/sale_product_configurator/static/tests/tours/product_configurator_single_custom_attribute_ui.js"/>
+ <script type="text/javascript" src="/sale_product_configurator/static/tests/tours/product_configurator_pricelist_ui.js"/>
+ <script type="text/javascript" src="/sale_product_configurator/static/tests/tours/product_configurator_optional_products_ui.js"/>
+ </xpath>
+ </template>
+ <template id="qunit_suite" inherit_id="web.qunit_suite_tests" name="sale_product_configurator_tests">
+ <xpath expr="." position="inside">
+ <script type="text/javascript" src="/sale_product_configurator/static/tests/product_configurator.test.js"></script>
+ </xpath>
+ </template>
+</odoo>
diff --git a/addons/sale_product_configurator/views/sale_views.xml b/addons/sale_product_configurator/views/sale_views.xml
new file mode 100644
index 00000000..3e55deb1
--- /dev/null
+++ b/addons/sale_product_configurator/views/sale_views.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<odoo>
+ <record id="product_template_view_form" model="ir.ui.view">
+ <field name="name">product.template.form.inherit.sale.product.configurator</field>
+ <field name="model">product.template</field>
+ <field name="inherit_id" ref="product.product_template_form_view"/>
+ <field name="arch" type="xml">
+ <xpath expr="//group[@name='sale']" position="after">
+ <group name="options" groups="product.group_product_variant">
+ <group string="Options">
+ <field name="optional_product_ids" widget="many2many_tags" options="{'color_field': 'color'}" domain="[('id', '!=', active_id), '|', ('company_id', '=', company_id), ('company_id', '=', False)]" />
+ </group>
+ </group>
+ </xpath>
+ </field>
+ </record>
+
+ <record id="sale_order_view_form" model="ir.ui.view">
+ <field name="name">sale.order.form.inherit.sale.product.configurator</field>
+ <field name="model">sale.order</field>
+ <field name="inherit_id" ref="sale.view_order_form"/>
+ <field name="arch" type="xml">
+ <xpath expr="//tree/field[@name='product_template_id']" position="attributes">
+ <attribute name="invisible">0</attribute>
+ </xpath>
+ <xpath expr="//tree/field[@name='product_template_id']" position="after">
+ <field name="product_template_attribute_value_ids" invisible="1" />
+ <field name="product_custom_attribute_value_ids" invisible="1" >
+ <tree>
+ <field name="custom_product_template_attribute_value_id" />
+ <field name="custom_value" />
+ </tree>
+ </field>
+ <field name="product_no_variant_attribute_value_ids" invisible="1" />
+ <field name="is_configurable_product" invisible="1" />
+ </xpath>
+ <xpath expr="//tree/field[@name='product_id']" position="attributes">
+ <attribute name="optional">hide</attribute>
+ <attribute name="string">Product Variant</attribute>
+ </xpath>
+ </field>
+ </record>
+</odoo>
diff --git a/addons/sale_product_configurator/views/templates.xml b/addons/sale_product_configurator/views/templates.xml
new file mode 100644
index 00000000..11ad527c
--- /dev/null
+++ b/addons/sale_product_configurator/views/templates.xml
@@ -0,0 +1,220 @@
+<?xml version="1.0" encoding="utf-8"?>
+<odoo>
+ <template id="optional_products_modal" name="Optional Products">
+ <main class="modal-body">
+ <t t-call="sale_product_configurator.configure_optional_products" />
+ </main>
+ </template>
+
+ <!-- backend -->
+ <template id="configure" name="Configure">
+ <div class="js_product main_product">
+
+ <t t-set="combination" t-value="product_combination if product_combination else product._get_first_possible_combination()"/>
+ <t t-set="combination_info" t-value="product._get_combination_info(combination, add_qty=add_qty or 1, pricelist=pricelist)"/>
+ <t t-set="product_variant" t-value="product.env['product.product'].browse(combination_info['product_id'])"/>
+
+ <input type="hidden" class="product_template_id" t-att-value="product.id"/>
+ <input type="hidden" class="product_id" t-attf-name="product_id" t-att-value="product_variant.id"/>
+ <div class="col-lg-12 text-center mt-5">
+ <t t-if="product._is_add_to_cart_possible()">
+ <div class="col-lg-5 d-inline-block text-left">
+ <t t-if="combination" t-call="sale.variants">
+ <t t-set="parent_combination" t-value="None"/>
+ </t>
+ <h2>
+ <span t-attf-class="text-danger oe_default_price oe_striked_price {{'' if combination_info['has_discounted_price'] else 'd-none'}}"
+ t-esc="combination_info['list_price']"
+ t-options='{
+ "widget": "monetary",
+ "display_currency": (pricelist or product).currency_id
+ }'/>
+ <span class="oe_price product_id mt-3" style="white-space: nowrap;"
+ t-att-data-product-id="product.id"
+ t-esc="combination_info['price']"
+ t-options='{
+ "widget": "monetary",
+ "display_currency": (pricelist or product).currency_id
+ }'/>
+ </h2>
+ <div class="css_quantity input-group" t-if="product.visible_qty_configurator">
+ <div class="input-group-prepend">
+ <button t-attf-href="#" class="btn btn-primary js_add_cart_json d-none d-md-inline-block" aria-label="Remove one" title="Remove one">
+ <i class="fa fa-minus"></i>
+ </button>
+ </div>
+ <input type="text" class="js_quantity form-control quantity" data-min="1" name="add_qty" t-att-value="add_qty or 1"/>
+ <div class="input-group-append">
+ <button t-attf-href="#" class="btn btn-primary float_left js_add_cart_json d-none d-md-inline-block" aria-label="Add one" title="Add one">
+ <i class="fa fa-plus"></i>
+ </button>
+ </div>
+ </div>
+ <p class="css_not_available_msg alert alert-warning">This combination does not exist.</p>
+ </div>
+ <div class="col-lg-1 d-inline-block"></div>
+ <div class="col-lg-5 d-inline-block align-top text-left">
+ <img t-if="product_variant" t-att-src="'/web/image/product.product/%s/image_1024' % product_variant.id" class="d-block product_detail_img" alt="Product Image"/>
+ <img t-else="" t-att-src="'/web/image/product.template/%s/image_1024' % product.id" class="d-block product_detail_img" alt="Product Image"/>
+ </div>
+ </t>
+ <t t-else="">
+ <div class="col-lg-5 d-inline-block text-left">
+ <p class="alert alert-warning">This product has no valid combination.</p>
+ </div>
+ </t>
+ </div>
+ </div>
+ </template>
+
+ <!-- modal: full table, currenclty selected products at top -->
+ <template id="configure_optional_products">
+ <table class="table table-striped table-sm">
+ <thead>
+ <tr>
+ <th class="td-img">Product</th>
+ <th></th>
+ <th class="text-center td-qty">Quantity</th>
+ <th class="text-center td-price">Price</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr class="js_product in_cart main_product">
+
+ <t t-set="combination_info" t-value="product.product_tmpl_id._get_combination_info(combination, product.id, add_qty or 1, pricelist)"/>
+ <t t-set="product_variant" t-value="product.env['product.product'].browse(combination_info['product_id'])"/>
+
+ <input type="hidden" class="product_template_id" t-att-value="product.product_tmpl_id.id"/>
+ <input type="hidden" class="product_id" t-att-value="product_variant.id"/>
+ <td class='td-img'>
+ <img t-if="product_variant" t-att-src="'/web/image/product.product/%s/image_128' % product_variant.id" alt="Product Image"/>
+ <img t-else="" t-att-src="'/web/image/product.template/%s/image_128' % product.id" alt="Product Image"/>
+ </td>
+ <td class='td-product_name'>
+ <strong t-esc="combination_info['display_name']"/>
+ <div class="text-muted small">
+ <div t-field="product.description_sale"/>
+ <div class="js_attributes"/>
+ </div>
+ </td>
+ <td class="text-center td-qty">
+ <div class="css_quantity input-group">
+ <div class="input-group-prepend">
+ <button t-attf-href="#" class="btn btn-primary js_add_cart_json d-none d-md-inline-block" aria-label="Remove one" title="Remove one">
+ <i class="fa fa-minus"></i>
+ </button>
+ </div>
+ <input type="text" class="js_quantity form-control quantity" data-min="1" name="add_qty" t-att-value="add_qty or 1"/>
+ <div class="input-group-append">
+ <button t-attf-href="#" class="btn btn-primary float_left js_add_cart_json d-none d-md-inline-block" aria-label="Add one" title="Add one">
+ <i class="fa fa-plus"></i>
+ </button>
+ </div>
+ </div>
+ </td>
+ <td class="text-center td-price" name="price">
+ <ul class="d-none js_add_cart_variants" t-att-data-attribute_exclusions="{'exclusions: []'}"></ul>
+ <div class="d-none oe_unchanged_value_ids" t-att-data-unchanged_value_ids="variant_values" ></div>
+ <div t-attf-class="text-danger oe_default_price oe_striked_price {{'' if combination_info['has_discounted_price'] else 'd-none'}}"
+ t-esc="combination_info['list_price']"
+ t-options='{
+ "widget": "monetary",
+ "display_currency": (pricelist or product).currency_id
+ }'
+ />
+ <span class="oe_price product_id" style="white-space: nowrap;"
+ t-att-data-product-id="product.id"
+ t-esc="combination_info['price']"
+ t-options='{
+ "widget": "monetary",
+ "display_currency": (pricelist or product).currency_id
+ }'/>
+ <span class="js_raw_price d-none" t-esc="product.price"/>
+ </td>
+ </tr>
+ <tr class="o_total_row">
+ <td colspan="4" class="text-right">
+ <strong>Total:</strong>
+ <span class="js_price_total font-weight-bold" style="white-space: nowrap;"
+ t-att-data-product-id="product.id"
+ t-esc="combination_info['price'] * (add_qty or 1)"
+ t-options='{
+ "widget": "monetary",
+ "display_currency": (pricelist or product).currency_id
+ }'/>
+ </td>
+ </tr>
+ <tr t-if="product.optional_product_ids" class="o_select_options"><td colspan="4"><h4>Available Options:</h4></td></tr>
+ <t t-call="sale_product_configurator.optional_product_items">
+ <t t-set="parent_combination" t-value="combination"/>
+ </t>
+ </tbody>
+ </table>
+ </template>
+
+ <!-- modal: optional products -->
+ <template id="optional_product_items">
+ <t t-foreach="product.optional_product_ids" t-as="product">
+ <t t-set="combination" t-value="product._get_first_possible_combination(parent_combination)"/>
+ <t t-if="product._is_add_to_cart_possible(parent_combination)">
+
+ <t t-set="combination_info" t-value="product._get_combination_info(combination, add_qty=add_qty or 1, pricelist=pricelist)"/>
+ <t t-set="product_variant" t-value="product.env['product.product'].browse(combination_info['product_id'])"/>
+
+ <tr class="js_product">
+ <td class="td-img">
+ <input type="hidden" class="product_template_id" t-att-value="product.id"/>
+ <input type="hidden" class="product_id" t-attf-name="optional-product-#{product.id}" t-att-value="product_variant.id"/>
+ <img t-if="product_variant" t-att-src="'/web/image/product.product/%s/image_128' % product_variant.id" class="variant_image" alt="Product Image"/>
+ <img t-else="" t-att-src="'/web/image/product.template/%s/image_128' % product.id" class="variant_image" alt="Product Image"/>
+ </td>
+ <td class='td-product_name' colspan="2">
+ <div class="float-left">
+ <strong class="product-name product_display_name" t-esc="combination_info['display_name']"/>
+ <div class="text-muted small" t-field="product.description_sale"/>
+ </div>
+ <div class="float-right">
+ <t t-call="sale.variants"/>
+ </div>
+ </td>
+ <td class="text-center td-qty d-none">
+ <div class="css_quantity input-group">
+ <div class="input-group-prepend">
+ <button t-attf-href="#" class="btn btn-primary float_left js_add_cart_json d-none d-md-inline-block" aria-label="Remove one" title="Remove one">
+ <i class="fa fa-minus"></i>
+ </button>
+ </div>
+ <input type="text" class="js_quantity form-control quantity" data-min="1" name="add_qty" t-att-value="add_qty or 1"/>
+ <div class="input-group-append">
+ <button t-attf-href="#" class="btn btn-primary float_left js_add_cart_json d-none d-md-inline-block" aria-label="Add one" title="Add one">
+ <i class="fa fa-plus"></i>
+ </button>
+ </div>
+ </div>
+ </td>
+ <td class="text-center td-price">
+ <div t-attf-class="text-danger oe_default_price oe_optional oe_striked_price {{'' if combination_info['has_discounted_price'] else 'd-none'}}"
+ t-esc="combination_info['list_price']"
+ t-options='{
+ "widget": "monetary",
+ "display_currency": (pricelist or product).currency_id
+ }'/>
+ <div class="oe_price" style="white-space: nowrap;"
+ t-esc="combination_info['price']"
+ t-options='{
+ "widget": "monetary",
+ "display_currency": (pricelist or product).currency_id
+ }'/>
+ <span class="js_raw_price d-none" t-esc="combination_info['price']" />
+ <p class="css_not_available_msg alert alert-warning">Option not available</p>
+
+ <a role="button" href="#" class="js_add btn btn-primary btn-sm"><i class="fa fa-shopping-cart add-optionnal-item"></i> Add to cart</a>
+ <span class="js_remove d-none">
+ <a role="button" href="#" class="js_remove"><i class="fa fa-trash-o remove-optionnal-item"></i></a>
+ </span>
+ </td>
+ </tr>
+ </t>
+ </t>
+ </template>
+</odoo>