mirror of
https://github.com/bringout/oca-ocb-sale.git
synced 2026-04-27 17:31:59 +02:00
Initial commit: Sale packages
This commit is contained in:
commit
14e3d26998
6469 changed files with 2479670 additions and 0 deletions
154
odoo-bringout-oca-ocb-website_sale/website_sale/README.md
Normal file
154
odoo-bringout-oca-ocb-website_sale/website_sale/README.md
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
Odoo e-Commerce
|
||||
---------------
|
||||
|
||||
### Optimize sales with an awesome online store.
|
||||
|
||||
Odoo is an <a href="https://www.odoo.com/app/ecommerce">Open Source eCommerce</a>
|
||||
unlike anything you have ever seen before. Get an awesome catalog of products
|
||||
and great product description pages.
|
||||
|
||||
It's full-featured, integrated with your management software, fully
|
||||
customizable and super easy.
|
||||
|
||||
Create Awesome Product Pages
|
||||
----------------------------
|
||||
|
||||
Odoo's unique *'edit inline'* and building blocks approach makes product pages
|
||||
creation surprisingly easy. "Want to change the price of a product? or put it
|
||||
in bold? Want to add a banner for a specific product?" just click and change.
|
||||
What you see is what you get. Really.
|
||||
|
||||
Drag & Drop well designed *'Building Blocks'* to create beautifull product
|
||||
pages that your customer will love.
|
||||
|
||||
Increase Your Revenue Per Order
|
||||
-------------------------------
|
||||
|
||||
The built-in cross-selling feature helps you offer extra products related to
|
||||
what the shopper put in his cart. (e.g. accessories)
|
||||
|
||||
Odoo's upselling algorythm allows you to show visitors similar but more
|
||||
expensive products than the one in view, with incentives.
|
||||
|
||||
The inline editing feature allows you to easily change a price, launch a
|
||||
promotion or fine tune the description of a product, in a just a click.
|
||||
|
||||
A Clean Google Analytics Integration
|
||||
------------------------------------
|
||||
|
||||
Get a clear visibility of your sales funnel. Odoo's Google Analytics trackers
|
||||
are configured by default to track all kind of events related to shopping
|
||||
carts, call-to-actions, etc.
|
||||
|
||||
As Odoo marketing tools (mass mailing, campaigns, etc) are also linked with
|
||||
Google Analytics, you get a complete view of your business.
|
||||
|
||||
Target New Markets
|
||||
------------------
|
||||
|
||||
Get your website translated in multiple languages with no effort. Odoo proposes
|
||||
and propagates translations automatically across pages.
|
||||
|
||||
Our translation "on demand" features allows you to benefit from professional
|
||||
translators to translate all your changes automatically. Just change any part
|
||||
of your website (a new blog post, a page modification, product descriptions,
|
||||
...) and the translated versions are updated automatically in around 32 hours.
|
||||
|
||||
Fine Tune Your Catalog
|
||||
----------------------
|
||||
|
||||
Get full control on how you display your products in the catalog page:
|
||||
promotional ribbons, related size of products, discounts, variants, grid/list
|
||||
view, etc.
|
||||
|
||||
Edit any product inline to make your website evolve with your customer need.
|
||||
|
||||
Acquire New Customers
|
||||
---------------------
|
||||
|
||||
SEO tools are ready to use, with no configuration required. Odoo suggests
|
||||
keywords according to Google most searched terms, Google Analytics tracks your
|
||||
shopping cart events, sitemap are created automatically for Google indexation,
|
||||
etc.
|
||||
|
||||
We even do structured content automatically to promote your product and events
|
||||
efficiently in Google.
|
||||
|
||||
Leverage Social Media
|
||||
---------------------
|
||||
|
||||
Create new landing pages easily with the Odoo inline editing feature. Send
|
||||
visitors of your different marketing campaigns to specific landing pages to
|
||||
optimize conversions.
|
||||
|
||||
Manage a Reseller Network
|
||||
-------------------------
|
||||
|
||||
Manage a reseller network to target new market, have local presences or broaden
|
||||
your distribution. Give them access to your reseller portal for an efficient
|
||||
collaboration.
|
||||
|
||||
Promote your resellers online, forward leads to resellers (with built-in
|
||||
geolocalisation feature), define specific pricelists, launch a loyalty program
|
||||
(offer specific discounts to your best customers or resellers), etc.
|
||||
|
||||
Benefit from the power of Odoo, in your online store: a powerfull tax engine,
|
||||
flexible pricing structures, a real inventory management solution, a reseller
|
||||
interface, support for products with different behaviours; physical goods,
|
||||
events, services, variants and options, etc.
|
||||
|
||||
You don't need to interface with your warehouse, sales or accounting software.
|
||||
Everything is integrated with Odoo. No pain, real time.
|
||||
|
||||
A Clean Checkout Process
|
||||
------------------------
|
||||
|
||||
Convert most visitor interests into real orders with a clean checkout process
|
||||
with a minimal number of steps and a great useability on every page.
|
||||
|
||||
Customize your checkout process to fit your business needs: payment modes,
|
||||
delivery methods, cross-selling, special conditions, etc.
|
||||
|
||||
And much more...
|
||||
----------------
|
||||
|
||||
### Online Sales
|
||||
|
||||
- Mobile Interface
|
||||
- Sell products, events or services
|
||||
- Flexible pricelists
|
||||
- Product multi-variants
|
||||
- Multiple stores
|
||||
- Great checkout process
|
||||
|
||||
### Customer Service
|
||||
|
||||
- Customer Portal to track orders
|
||||
- Assisted shopping with website live chats
|
||||
- Returns management
|
||||
- Advanced shipping rules
|
||||
- Coupons or gift certificates
|
||||
|
||||
### Order Management
|
||||
|
||||
- Advanced warehouse management features
|
||||
- Invoicing and accounting integration
|
||||
- Mass mailing and customer segmentations
|
||||
- Lead automation and marketing campaigns
|
||||
- Persistent shopping cart
|
||||
|
||||
Fully Integrated With Other Apps
|
||||
--------------------------------
|
||||
|
||||
### CMS
|
||||
|
||||
Easily create awesome websites with no technical knowledge required.
|
||||
|
||||
### Blogs
|
||||
|
||||
Write news, attract new visitors, build customer loyalty.
|
||||
|
||||
### Online Events
|
||||
|
||||
Schedule, organize, promote or sell events online; conferences, webinars, trainings, etc.
|
||||
|
||||
28
odoo-bringout-oca-ocb-website_sale/website_sale/__init__.py
Normal file
28
odoo-bringout-oca-ocb-website_sale/website_sale/__init__.py
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
from odoo import api, SUPERUSER_ID, _
|
||||
from . import controllers
|
||||
from . import models
|
||||
from . import wizard
|
||||
from . import report
|
||||
|
||||
def _post_init_hook(cr, registry):
|
||||
env = api.Environment(cr, SUPERUSER_ID, {})
|
||||
terms_conditions = env['ir.config_parameter'].get_param('account.use_invoice_terms')
|
||||
if not terms_conditions:
|
||||
env['ir.config_parameter'].set_param('account.use_invoice_terms', True)
|
||||
companies = env['res.company'].search([])
|
||||
for company in companies:
|
||||
company.terms_type = 'html'
|
||||
env['website'].search([]).auth_signup_uninvited = 'b2c'
|
||||
|
||||
def uninstall_hook(cr, registry):
|
||||
''' Need to reenable the `product` pricelist multi-company rule that were
|
||||
disabled to be 'overridden' for multi-website purpose
|
||||
'''
|
||||
env = api.Environment(cr, SUPERUSER_ID, {})
|
||||
pl_rule = env.ref('product.product_pricelist_comp_rule', raise_if_not_found=False)
|
||||
pl_item_rule = env.ref('product.product_pricelist_item_comp_rule', raise_if_not_found=False)
|
||||
multi_company_rules = pl_rule or env['ir.rule']
|
||||
multi_company_rules += pl_item_rule or env['ir.rule']
|
||||
multi_company_rules.write({'active': True})
|
||||
104
odoo-bringout-oca-ocb-website_sale/website_sale/__manifest__.py
Normal file
104
odoo-bringout-oca-ocb-website_sale/website_sale/__manifest__.py
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
{
|
||||
'name': 'eCommerce',
|
||||
'category': 'Website/Website',
|
||||
'sequence': 50,
|
||||
'summary': 'Sell your products online',
|
||||
'website': 'https://www.odoo.com/app/ecommerce',
|
||||
'version': '1.1',
|
||||
'depends': ['website', 'sale', 'website_payment', 'website_mail', 'portal_rating', 'digest'],
|
||||
'data': [
|
||||
'security/ir.model.access.csv',
|
||||
'security/website_sale.xml',
|
||||
'data/data.xml',
|
||||
'data/mail_template_data.xml',
|
||||
'data/product_snippet_template_data.xml',
|
||||
'data/digest_data.xml',
|
||||
'data/ir_cron_data.xml',
|
||||
'views/product_attribute_views.xml',
|
||||
'views/product_tag_views.xml',
|
||||
'views/product_views.xml',
|
||||
'views/account_views.xml',
|
||||
'views/sale_report_views.xml',
|
||||
'views/sale_order_views.xml',
|
||||
'views/crm_team_views.xml',
|
||||
'views/templates.xml',
|
||||
'views/snippets/snippets.xml',
|
||||
'views/snippets/s_add_to_cart.xml',
|
||||
'views/snippets/s_dynamic_snippet_products.xml',
|
||||
'views/res_config_settings_views.xml',
|
||||
'views/digest_views.xml',
|
||||
'views/website_sale_visitor_views.xml',
|
||||
'views/base_unit_view.xml',
|
||||
'views/product_product_add.xml',
|
||||
'views/website_views.xml',
|
||||
'views/website_pages_views.xml',
|
||||
],
|
||||
'demo': [
|
||||
'data/demo.xml',
|
||||
],
|
||||
'installable': True,
|
||||
'application': True,
|
||||
'post_init_hook': '_post_init_hook',
|
||||
'uninstall_hook': 'uninstall_hook',
|
||||
'assets': {
|
||||
'web.assets_frontend': [
|
||||
'website_sale/static/src/js/tours/tour_utils.js',
|
||||
'website_sale/static/src/scss/website_sale.scss',
|
||||
'website_sale/static/src/scss/website_mail.scss',
|
||||
'website_sale/static/src/scss/website_sale_frontend.scss',
|
||||
'website/static/lib/multirange/multirange_custom.scss',
|
||||
'sale/static/src/scss/sale_portal.scss',
|
||||
'sale/static/src/scss/product_configurator.scss',
|
||||
'sale/static/src/js/variant_mixin.js',
|
||||
'website_sale/static/src/js/variant_mixin.js',
|
||||
'website_sale/static/src/js/website_sale.js',
|
||||
'website_sale/static/src/xml/website_sale.xml',
|
||||
'website_sale/static/src/js/website_sale_utils.js',
|
||||
'website_sale/static/src/xml/website_sale_utils.xml',
|
||||
'website_sale/static/src/js/website_sale_payment.js',
|
||||
'website_sale/static/src/js/website_sale_validate.js',
|
||||
'website_sale/static/src/js/website_sale_recently_viewed.js',
|
||||
'website_sale/static/src/js/website_sale_tracking.js',
|
||||
'website/static/lib/multirange/multirange_custom.js',
|
||||
'website_sale/static/src/js/website_sale_category_link.js',
|
||||
'website_sale/static/src/xml/website_sale_image_viewer.xml',
|
||||
'website_sale/static/src/js/components/website_sale_image_viewer.js',
|
||||
'website_sale/static/src/xml/website_sale_reorder_modal.xml',
|
||||
'website_sale/static/src/js/website_sale_reorder.js',
|
||||
],
|
||||
'web._assets_primary_variables': [
|
||||
'website_sale/static/src/scss/primary_variables.scss',
|
||||
],
|
||||
'web.assets_backend': [
|
||||
'website_sale/static/src/js/website_sale_video_field_preview.js',
|
||||
'website_sale/static/src/js/website_sale_backend.js',
|
||||
'website_sale/static/src/scss/website_sale_dashboard.scss',
|
||||
'website_sale/static/src/scss/website_sale_backend.scss',
|
||||
'website_sale/static/src/xml/website_sale_dashboard.xml',
|
||||
'website_sale/static/src/js/tours/website_sale_shop.js',
|
||||
'website_sale/static/src/xml/website_sale.xml',
|
||||
],
|
||||
'website.assets_wysiwyg': [
|
||||
'website_sale/static/src/scss/website_sale.editor.scss',
|
||||
'website_sale/static/src/snippets/s_dynamic_snippet_products/options.js',
|
||||
'website_sale/static/src/snippets/s_add_to_cart/options.js',
|
||||
'website_sale/static/src/js/website_sale.editor.js',
|
||||
],
|
||||
'website.assets_editor': [
|
||||
'website_sale/static/src/js/systray_items/*.js',
|
||||
'website_sale/static/src/js/components/wysiwyg_adapter/wysiwyg_adapter.js',
|
||||
'website_sale/static/src/js/website_sale_form_editor.js',
|
||||
'website_sale/static/src/xml/website_sale_utils.xml',
|
||||
],
|
||||
'web.assets_common': [
|
||||
'website_sale/static/src/js/tours/tour_utils.js',
|
||||
],
|
||||
'web.assets_tests': [
|
||||
'website_sale/static/tests/**/*',
|
||||
],
|
||||
},
|
||||
'license': 'LGPL-3',
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import backend
|
||||
from . import main
|
||||
from . import variant
|
||||
|
|
@ -0,0 +1,183 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
import babel.dates
|
||||
|
||||
from datetime import datetime, timedelta, time
|
||||
|
||||
from odoo import fields, http, _
|
||||
from odoo.addons.website.controllers.backend import WebsiteBackend
|
||||
from odoo.http import request
|
||||
from odoo.tools.misc import get_lang
|
||||
|
||||
|
||||
class WebsiteSaleBackend(WebsiteBackend):
|
||||
|
||||
@http.route()
|
||||
def fetch_dashboard_data(self, website_id, date_from, date_to):
|
||||
Website = request.env['website']
|
||||
current_website = website_id and Website.browse(website_id) or Website.get_current_website()
|
||||
|
||||
results = super(WebsiteSaleBackend, self).fetch_dashboard_data(website_id, date_from, date_to)
|
||||
|
||||
date_date_from = fields.Date.from_string(date_from)
|
||||
date_date_to = fields.Date.from_string(date_to)
|
||||
date_diff_days = (date_date_to - date_date_from).days
|
||||
datetime_from = datetime.combine(date_date_from, time.min)
|
||||
datetime_to = datetime.combine(date_date_to, time.max)
|
||||
|
||||
sales_values = dict(
|
||||
graph=[],
|
||||
best_sellers=[],
|
||||
summary=dict(
|
||||
order_count=0, order_carts_count=0, order_unpaid_count=0,
|
||||
order_to_invoice_count=0, order_carts_abandoned_count=0,
|
||||
payment_to_capture_count=0, total_sold=0,
|
||||
order_per_day_ratio=0, order_sold_ratio=0, order_convertion_pctg=0,
|
||||
)
|
||||
)
|
||||
|
||||
results['dashboards']['sales'] = sales_values
|
||||
|
||||
results['groups']['sale_salesman'] = request.env['res.users'].has_group('sales_team.group_sale_salesman')
|
||||
|
||||
if not results['groups']['sale_salesman']:
|
||||
return results
|
||||
|
||||
results['dashboards']['sales']['utm_graph'] = self.fetch_utm_data(datetime_from, datetime_to)
|
||||
# Product-based computation
|
||||
sale_report_domain = [
|
||||
('website_id', '=', current_website.id),
|
||||
('state', 'in', ['sale', 'done']),
|
||||
('date', '>=', datetime_from),
|
||||
('date', '<=', fields.Datetime.now())
|
||||
]
|
||||
report_product_lines = request.env['sale.report'].read_group(
|
||||
domain=sale_report_domain,
|
||||
fields=['product_tmpl_id', 'product_uom_qty', 'price_subtotal'],
|
||||
groupby='product_tmpl_id', orderby='product_uom_qty desc', limit=5)
|
||||
for product_line in report_product_lines:
|
||||
product_tmpl_id = request.env['product.template'].browse(product_line['product_tmpl_id'][0])
|
||||
sales_values['best_sellers'].append({
|
||||
'id': product_tmpl_id.id,
|
||||
'name': product_tmpl_id.name,
|
||||
'qty': product_line['product_uom_qty'],
|
||||
'sales': product_line['price_subtotal'],
|
||||
})
|
||||
|
||||
# Sale-based results computation
|
||||
sale_order_domain = [
|
||||
('website_id', '=', current_website.id),
|
||||
('date_order', '>=', fields.Datetime.to_string(datetime_from)),
|
||||
('date_order', '<=', fields.Datetime.to_string(datetime_to))]
|
||||
so_group_data = request.env['sale.order'].read_group(sale_order_domain, fields=['state'], groupby='state')
|
||||
for res in so_group_data:
|
||||
if res.get('state') == 'sent':
|
||||
sales_values['summary']['order_unpaid_count'] += res['state_count']
|
||||
elif res.get('state') in ['sale', 'done']:
|
||||
sales_values['summary']['order_count'] += res['state_count']
|
||||
sales_values['summary']['order_carts_count'] += res['state_count']
|
||||
|
||||
report_price_lines = request.env['sale.report'].read_group(
|
||||
domain=[
|
||||
('website_id', '=', current_website.id),
|
||||
('state', 'in', ['sale', 'done']),
|
||||
('date', '>=', datetime_from),
|
||||
('date', '<=', datetime_to)],
|
||||
fields=['team_id', 'price_subtotal'],
|
||||
groupby=['team_id'],
|
||||
)
|
||||
sales_values['summary'].update(
|
||||
order_to_invoice_count=request.env['sale.order'].search_count(sale_order_domain + [
|
||||
('state', 'in', ['sale', 'done']),
|
||||
('order_line', '!=', False),
|
||||
('partner_id', '!=', request.env.ref('base.public_partner').id),
|
||||
('invoice_status', '=', 'to invoice'),
|
||||
]),
|
||||
order_carts_abandoned_count=request.env['sale.order'].search_count(sale_order_domain + [
|
||||
('is_abandoned_cart', '=', True),
|
||||
('cart_recovery_email_sent', '=', False)
|
||||
]),
|
||||
payment_to_capture_count=request.env['payment.transaction'].search_count([
|
||||
('state', '=', 'authorized'),
|
||||
# that part perform a search on sale.order in order to comply with access rights as tx do not have any
|
||||
('sale_order_ids', 'in', request.env['sale.order'].search(sale_order_domain + [('state', '!=', 'cancel')]).ids),
|
||||
]),
|
||||
total_sold=sum(price_line['price_subtotal'] for price_line in report_price_lines)
|
||||
)
|
||||
|
||||
# Ratio computation
|
||||
sales_values['summary']['order_per_day_ratio'] = round(float(sales_values['summary']['order_count']) / date_diff_days, 2)
|
||||
sales_values['summary']['order_sold_ratio'] = round(float(sales_values['summary']['total_sold']) / sales_values['summary']['order_count'], 2) if sales_values['summary']['order_count'] else 0
|
||||
sales_values['summary']['order_convertion_pctg'] = 100.0 * sales_values['summary']['order_count'] / sales_values['summary']['order_carts_count'] if sales_values['summary']['order_carts_count'] else 0
|
||||
|
||||
# Graphes computation
|
||||
if date_diff_days == 7:
|
||||
previous_sale_label = _('Previous Week')
|
||||
elif date_diff_days > 7 and date_diff_days <= 31:
|
||||
previous_sale_label = _('Previous Month')
|
||||
else:
|
||||
previous_sale_label = _('Previous Year')
|
||||
|
||||
sales_values['graph'] += [{
|
||||
'values': self._compute_sale_graph(date_date_from, date_date_to, sale_report_domain),
|
||||
'key': 'Untaxed Total',
|
||||
}, {
|
||||
'values': self._compute_sale_graph(date_date_from - timedelta(days=date_diff_days), date_date_from, sale_report_domain, previous=True),
|
||||
'key': previous_sale_label,
|
||||
}]
|
||||
|
||||
return results
|
||||
|
||||
def fetch_utm_data(self, date_from, date_to):
|
||||
sale_utm_domain = [
|
||||
('website_id', '!=', False),
|
||||
('state', 'in', ['sale', 'done']),
|
||||
('date_order', '>=', date_from),
|
||||
('date_order', '<=', date_to)
|
||||
]
|
||||
|
||||
orders_data_groupby_campaign_id = request.env['sale.order']._read_group(
|
||||
domain=sale_utm_domain + [('campaign_id', '!=', False)],
|
||||
fields=['amount_total', 'id', 'campaign_id'],
|
||||
groupby='campaign_id')
|
||||
|
||||
orders_data_groupby_medium_id = request.env['sale.order']._read_group(
|
||||
domain=sale_utm_domain + [('medium_id', '!=', False)],
|
||||
fields=['amount_total', 'id', 'medium_id'],
|
||||
groupby='medium_id')
|
||||
|
||||
orders_data_groupby_source_id = request.env['sale.order']._read_group(
|
||||
domain=sale_utm_domain + [('source_id', '!=', False)],
|
||||
fields=['amount_total', 'id', 'source_id'],
|
||||
groupby='source_id')
|
||||
|
||||
return {
|
||||
'campaign_id': self.compute_utm_graph_data('campaign_id', orders_data_groupby_campaign_id),
|
||||
'medium_id': self.compute_utm_graph_data('medium_id', orders_data_groupby_medium_id),
|
||||
'source_id': self.compute_utm_graph_data('source_id', orders_data_groupby_source_id),
|
||||
}
|
||||
|
||||
def compute_utm_graph_data(self, utm_type, utm_graph_data):
|
||||
return [{
|
||||
'utm_type': data[utm_type][1],
|
||||
'amount_total': data['amount_total']
|
||||
} for data in utm_graph_data]
|
||||
|
||||
def _compute_sale_graph(self, date_from, date_to, sales_domain, previous=False):
|
||||
days_between = (date_to - date_from).days
|
||||
date_list = [(date_from + timedelta(days=x)) for x in range(0, days_between + 1)]
|
||||
|
||||
daily_sales = request.env['sale.report'].read_group(
|
||||
domain=sales_domain,
|
||||
fields=['date', 'price_subtotal'],
|
||||
groupby='date:day')
|
||||
|
||||
daily_sales_dict = {p['date:day']: p['price_subtotal'] for p in daily_sales}
|
||||
|
||||
sales_graph = [{
|
||||
'0': fields.Date.to_string(d) if not previous else fields.Date.to_string(d + timedelta(days=days_between)),
|
||||
# Respect read_group format in models.py
|
||||
'1': daily_sales_dict.get(babel.dates.format_date(d, format='dd MMM yyyy', locale=get_lang(request.env).code), 0)
|
||||
} for d in date_list]
|
||||
|
||||
return sales_graph
|
||||
1909
odoo-bringout-oca-ocb-website_sale/website_sale/controllers/main.py
Normal file
1909
odoo-bringout-oca-ocb-website_sale/website_sale/controllers/main.py
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,33 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
from odoo import http
|
||||
from odoo.http import request
|
||||
|
||||
from odoo.addons.sale.controllers.variant import VariantController
|
||||
|
||||
|
||||
class WebsiteSaleVariantController(VariantController):
|
||||
@http.route(['/sale/get_combination_info_website'], type='json', auth="public", methods=['POST'], website=True)
|
||||
def get_combination_info_website(self, product_template_id, product_id, combination, add_qty, **kw):
|
||||
"""Special route to use website logic in get_combination_info override.
|
||||
This route is called in JS by appending _website to the base route.
|
||||
"""
|
||||
kw.pop('pricelist_id')
|
||||
combination = self.get_combination_info(product_template_id, product_id, combination, add_qty, request.website.get_current_pricelist(), **kw)
|
||||
|
||||
if request.website.google_analytics_key:
|
||||
combination['product_tracking_info'] = request.env['product.template'].get_google_analytics_data(combination)
|
||||
|
||||
if request.website.product_page_image_width != 'none' and not request.env.context.get('website_sale_no_images', False):
|
||||
carousel_view = request.env['ir.ui.view']._render_template('website_sale.shop_product_images', values={
|
||||
'product': request.env['product.template'].browse(combination['product_template_id']),
|
||||
'product_variant': request.env['product.product'].browse(combination['product_id']),
|
||||
'website': request.env['website'].get_current_website(),
|
||||
})
|
||||
combination['carousel'] = carousel_view
|
||||
return combination
|
||||
|
||||
@http.route(auth="public")
|
||||
def create_product_variant(self, product_template_id, product_template_attribute_value_ids, **kwargs):
|
||||
"""Override because on the website the public user must access it."""
|
||||
return super(WebsiteSaleVariantController, self).create_product_variant(product_template_id, product_template_attribute_value_ids, **kwargs)
|
||||
193
odoo-bringout-oca-ocb-website_sale/website_sale/data/data.xml
Normal file
193
odoo-bringout-oca-ocb-website_sale/website_sale/data/data.xml
Normal file
|
|
@ -0,0 +1,193 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data noupdate="1">
|
||||
|
||||
<record id="menu_shop" model="website.menu">
|
||||
<field name="name">Shop</field>
|
||||
<field name="url">/shop</field>
|
||||
<field name="parent_id" ref="website.main_menu"/>
|
||||
<field name="sequence" type="int">20</field>
|
||||
</record>
|
||||
<record id="action_open_website" model="ir.actions.act_url">
|
||||
<field name="name">Website Shop</field>
|
||||
<field name="target">self</field>
|
||||
<field name="url">/shop</field>
|
||||
</record>
|
||||
<record id="base.open_menu" model="ir.actions.todo">
|
||||
<field name="action_id" ref="action_open_website"/>
|
||||
<field name="state">open</field>
|
||||
</record>
|
||||
|
||||
<record id="product_attribute_brand" model="product.attribute">
|
||||
<field name="name">Brand</field>
|
||||
<field name="sequence">0</field>
|
||||
</record>
|
||||
|
||||
<record id="website_sale.sale_ribbon" model="product.ribbon">
|
||||
<field name="html">Sale</field>
|
||||
<field name="html_class">o_ribbon_left</field>
|
||||
<field name="bg_color">rgb(40, 167, 69)</field>
|
||||
<field name="text_color">white</field>
|
||||
</record>
|
||||
|
||||
<record id="website_sale.sold_out_ribbon" model="product.ribbon">
|
||||
<field name="html">Sold out</field>
|
||||
<field name="html_class">o_ribbon_left</field>
|
||||
<field name="bg_color">rgb(220, 53, 69)</field>
|
||||
<field name="text_color">white</field>
|
||||
</record>
|
||||
|
||||
<record id="website_sale.out_of_stock_ribbon" model="product.ribbon">
|
||||
<field name="html">Out of stock</field>
|
||||
<field name="html_class">o_ribbon_left</field>
|
||||
<field name="bg_color">rgb(255, 193, 7)</field>
|
||||
<field name="text_color">black</field>
|
||||
</record>
|
||||
|
||||
<record id="website_sale.new_ribbon" model="product.ribbon">
|
||||
<field name="html">New!</field>
|
||||
<field name="html_class">o_ribbon_left</field>
|
||||
<field name="bg_color">rgb(0, 123, 255)</field>
|
||||
<field name="text_color">white</field>
|
||||
</record>
|
||||
|
||||
<record id="sales_team.salesteam_website_sales" model="crm.team">
|
||||
<field name="active" eval="True"/>
|
||||
</record>
|
||||
|
||||
<record model="website" id="website.default_website">
|
||||
<field name="salesteam_id" ref="sales_team.salesteam_website_sales"/>
|
||||
</record>
|
||||
|
||||
<record model="product.pricelist" id="product.list0">
|
||||
<field name="selectable" eval="True" />
|
||||
<field name="website_id" eval="False"/>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
<data>
|
||||
<!-- Filters for Dynamic Filter -->
|
||||
<record id="dynamic_snippet_newest_products_filter" model="ir.filters">
|
||||
<field name="name">Newest Products</field>
|
||||
<field name="model_id">product.product</field>
|
||||
<field name="user_id" eval="False" />
|
||||
<field name="domain">[('website_published', '=', True)]</field>
|
||||
<field name="context">{'display_default_code': False, 'add2cart_rerender': False}</field>
|
||||
<field name="sort">["create_date desc"]</field>
|
||||
<field name="action_id" ref="website.action_website"/>
|
||||
</record>
|
||||
<!-- Action Server for Dynamic Filter -->
|
||||
<record id="dynamic_snippet_latest_sold_products_action" model="ir.actions.server">
|
||||
<field name="name">Recently Sold Products</field>
|
||||
<field name="model_id" ref="model_product_product"/>
|
||||
<field name="state">code</field>
|
||||
<field name="code">
|
||||
DynamicFilter = model.env['website.snippet.filter']
|
||||
response = DynamicFilter._get_products('latest_sold', model.env.context)
|
||||
</field>
|
||||
</record>
|
||||
<record id="dynamic_snippet_latest_viewed_products_action" model="ir.actions.server">
|
||||
<field name="name">Recently Viewed Products</field>
|
||||
<field name="model_id" ref="model_product_product"/>
|
||||
<field name="state">code</field>
|
||||
<field name="code">
|
||||
DynamicFilter = model.env['website.snippet.filter']
|
||||
res_products = DynamicFilter._get_products('latest_viewed', model.env.context)
|
||||
for data in res_products:
|
||||
data['_latest_viewed'] = True
|
||||
response = res_products
|
||||
</field>
|
||||
</record>
|
||||
<record id="dynamic_snippet_accessories_action" model="ir.actions.server">
|
||||
<field name="name">Product Accessories</field>
|
||||
<field name="model_id" ref="model_product_product"/>
|
||||
<field name="state">code</field>
|
||||
<field name="code">
|
||||
DynamicFilter = model.env['website.snippet.filter']
|
||||
model.env.context['product_template_id'] = request.params.get('productTemplateId')
|
||||
response = DynamicFilter._get_products('accessories', model.env.context)
|
||||
</field>
|
||||
</record>
|
||||
<record id="dynamic_snippet_recently_sold_with_action" model="ir.actions.server">
|
||||
<field name="name">Products Recently Sold With</field>
|
||||
<field name="model_id" ref="model_product_product"/>
|
||||
<field name="state">code</field>
|
||||
<field name="code">
|
||||
DynamicFilter = model.env['website.snippet.filter']
|
||||
model.env.context['product_template_id'] = request.params.get('productTemplateId')
|
||||
response = DynamicFilter._get_products('recently_sold_with', model.env.context)
|
||||
</field>
|
||||
</record>
|
||||
<record id="dynamic_snippet_alternative_products" model="ir.actions.server">
|
||||
<field name="name">Alternative Products</field>
|
||||
<field name="model_id" ref="model_product_product"/>
|
||||
<field name="state">code</field>
|
||||
<field name="code">
|
||||
DynamicFilter = model.env['website.snippet.filter']
|
||||
model.env.context['product_template_id'] = request.params.get('productTemplateId')
|
||||
response = DynamicFilter._get_products('alternative_products', model.env.context)
|
||||
</field>
|
||||
</record>
|
||||
<!-- Dynamic Filter -->
|
||||
<record id="dynamic_filter_newest_products" model="website.snippet.filter">
|
||||
<field name="filter_id" ref="website_sale.dynamic_snippet_newest_products_filter"/>
|
||||
<field name="field_names">display_name,description_sale,image_512</field>
|
||||
<field name="limit" eval="16"/>
|
||||
<field name="name">Newest Products</field>
|
||||
</record>
|
||||
<record id="dynamic_filter_latest_sold_products" model="website.snippet.filter">
|
||||
<field name="action_server_id" ref="website_sale.dynamic_snippet_latest_sold_products_action"/>
|
||||
<field name="field_names">display_name,description_sale,image_512</field>
|
||||
<field name="limit" eval="16"/>
|
||||
<field name="name">Recently Sold Products</field>
|
||||
</record>
|
||||
<record id="dynamic_filter_latest_viewed_products" model="website.snippet.filter">
|
||||
<field name="action_server_id" ref="website_sale.dynamic_snippet_latest_viewed_products_action"/>
|
||||
<field name="field_names">display_name,description_sale,image_512</field>
|
||||
<field name="limit" eval="16"/>
|
||||
<field name="name">Recently Viewed Products</field>
|
||||
</record>
|
||||
<record id="dynamic_filter_cross_selling_accessories" model="website.snippet.filter">
|
||||
<field name="action_server_id" ref="website_sale.dynamic_snippet_accessories_action"/>
|
||||
<field name="field_names">display_name,description_sale,image_512</field>
|
||||
<field name="limit" eval="16"/>
|
||||
<field name="name">Accessories for Product</field>
|
||||
<field name="product_cross_selling">True</field>
|
||||
</record>
|
||||
<record id="dynamic_filter_cross_selling_recently_sold_with" model="website.snippet.filter">
|
||||
<field name="action_server_id" ref="website_sale.dynamic_snippet_recently_sold_with_action"/>
|
||||
<field name="field_names">display_name,description_sale,image_512</field>
|
||||
<field name="limit" eval="16"/>
|
||||
<field name="name">Products Recently Sold With Product</field>
|
||||
<field name="product_cross_selling">True</field>
|
||||
</record>
|
||||
<record id="dynamic_filter_cross_selling_alternative_products" model="website.snippet.filter">
|
||||
<field name="action_server_id" ref="website_sale.dynamic_snippet_alternative_products"/>
|
||||
<field name="field_names">display_name,description_sale,image_512</field>
|
||||
<field name="limit" eval="16"/>
|
||||
<field name="name">Alternative Products</field>
|
||||
<field name="product_cross_selling">True</field>
|
||||
</record>
|
||||
|
||||
<function model="ir.model.fields" name="formbuilder_whitelist">
|
||||
<value>sale.order</value>
|
||||
<value eval="[
|
||||
'client_order_ref',
|
||||
]"/>
|
||||
</function>
|
||||
|
||||
<record id="base.model_res_partner" model="ir.model">
|
||||
<field name="website_form_key">create_customer</field>
|
||||
<field name="website_form_access">True</field>
|
||||
<field name="website_form_label">Create a Customer</field>
|
||||
</record>
|
||||
<function model="ir.model.fields" name="formbuilder_whitelist">
|
||||
<value>res.partner</value>
|
||||
<value eval="[
|
||||
'name', 'phone', 'email',
|
||||
'city', 'zip', 'street', 'street2', 'state_id', 'country_id',
|
||||
'vat', 'company_name'
|
||||
]"/>
|
||||
</function>
|
||||
</data>
|
||||
</odoo>
|
||||
782
odoo-bringout-oca-ocb-website_sale/website_sale/data/demo.xml
Normal file
782
odoo-bringout-oca-ocb-website_sale/website_sale/data/demo.xml
Normal file
|
|
@ -0,0 +1,782 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo noupdate="1">
|
||||
|
||||
<record model="website" id="website.website2">
|
||||
<field name="salesteam_id" ref="sales_team.salesteam_website_sales"/>
|
||||
</record>
|
||||
|
||||
<record id="product.product_attribute_2" model="product.attribute">
|
||||
<field name="visibility">hidden</field>
|
||||
</record>
|
||||
|
||||
<record id="product.product_product_24" model="product.product">
|
||||
<field name="is_published" eval="True"/>
|
||||
</record>
|
||||
<record id="product.product_product_5" model="product.product">
|
||||
<field name="is_published" eval="True"/>
|
||||
</record>
|
||||
<record id="product.product_product_12" model="product.product">
|
||||
<field name="is_published" eval="True"/>
|
||||
</record>
|
||||
<record id="product.product_product_10" model="product.product">
|
||||
<field name="is_published" eval="True"/>
|
||||
</record>
|
||||
<record id="product.product_product_13" model="product.product">
|
||||
<field name="is_published" eval="True"/>
|
||||
</record>
|
||||
<record id="product.product_product_25" model="product.product">
|
||||
<field name="is_published" eval="True"/>
|
||||
</record>
|
||||
<record id="product.consu_delivery_02" model="product.product">
|
||||
<field name="is_published" eval="True"/>
|
||||
</record>
|
||||
<record id="product.product_delivery_01" model="product.product">
|
||||
<field name="is_published" eval="True"/>
|
||||
</record>
|
||||
<record id="product.product_product_3" model="product.product">
|
||||
<field name="is_published" eval="True"/>
|
||||
</record>
|
||||
<record id="product.product_product_22" model="product.product">
|
||||
<field name="is_published" eval="True"/>
|
||||
</record>
|
||||
<record id="product.consu_delivery_03" model="product.product">
|
||||
<field name="is_published" eval="True"/>
|
||||
</record>
|
||||
<record id="product.product_product_27" model="product.product">
|
||||
<field name="is_published" eval="True"/>
|
||||
</record>
|
||||
<record id="product.product_delivery_02" model="product.product">
|
||||
<field name="is_published" eval="True"/>
|
||||
</record>
|
||||
<record id="product.product_product_16" model="product.product">
|
||||
<field name="is_published" eval="True"/>
|
||||
</record>
|
||||
<record id="product.consu_delivery_01" model="product.product">
|
||||
<field name="is_published" eval="True"/>
|
||||
</record>
|
||||
<record id="product.product_order_01" model="product.product">
|
||||
<field name="is_published" eval="True"/>
|
||||
</record>
|
||||
|
||||
<record id="product.product_product_4" model="product.product">
|
||||
<field name="is_published" eval="True"/>
|
||||
<field name="website_sequence">9950</field>
|
||||
<field name="website_description" type="html">
|
||||
<section class="s_text_image pt32 pb32 o_colored_level o_cc o_cc1" data-snippet="s_text_image" data-name="Text - Image">
|
||||
<div class="container">
|
||||
<div class="row align-items-center">
|
||||
<div class="pt16 pb16 col-lg-6">
|
||||
<h2>Ergonomic</h2>
|
||||
<p>Press a button and watch your desk glide effortlessly from sitting to standing height in seconds.</p>
|
||||
<p>The minimum height is 65 cm, and for standing work the maximum height position is 125 cm.</p>
|
||||
</div>
|
||||
<div class="pt16 pb16 col-lg-6">
|
||||
<img src="/website/static/src/img/snippets_demo/s_text_image.jpg" class="img img-fluid mx-auto" alt=""/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section class="s_text_image pt32 pb32 o_colored_level o_cc o_cc1" data-snippet="s_image_text" data-name="Image - Text">
|
||||
<div class="container">
|
||||
<div class="row align-items-center">
|
||||
<div class="pt16 pb16 col-lg-6">
|
||||
<img src="/website_sale/static/src/img/carpentry.jpg" class="img img-fluid mx-auto" alt=""/>
|
||||
</div>
|
||||
<div class="pt16 pb16 col-lg-6">
|
||||
<h2>Locally handmade</h2>
|
||||
<p>We pay special attention to detail, which is why our desks are of a superior quality.</p>
|
||||
<p>Looking for a custom bamboo stain to match existing furniture? Contact us for a quote.</p>
|
||||
<p><a href="/contactus" class="mb-2 btn btn-primary">Contact Us</a></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="product.product_product_6" model="product.product">
|
||||
<field name="is_published" eval="True"/>
|
||||
</record>
|
||||
|
||||
<record id="product.product_product_7" model="product.product">
|
||||
<field name="is_published" eval="True"/>
|
||||
</record>
|
||||
|
||||
<record id="product.product_product_8" model="product.product">
|
||||
<field name="is_published" eval="True"/>
|
||||
</record>
|
||||
|
||||
<record id="product.product_product_9" model="product.product">
|
||||
<field name="is_published" eval="True"/>
|
||||
</record>
|
||||
|
||||
<record id="product.product_product_11" model="product.product">
|
||||
<field name="is_published" eval="True"/>
|
||||
<field name="accessory_product_ids" eval="[(6, 0, [ref('product.product_product_7')])]"/>
|
||||
</record>
|
||||
|
||||
<record id="item1" model="product.pricelist.item">
|
||||
<field name="base">list_price</field>
|
||||
<field name="applied_on">1_product</field>
|
||||
<field name="pricelist_id" ref="product.list0"/>
|
||||
<field name="product_tmpl_id" ref="product.product_product_4_product_template"/>
|
||||
<field name="price_discount">20</field>
|
||||
<field name="min_quantity">2</field>
|
||||
<field name="compute_price">formula</field>
|
||||
</record>
|
||||
|
||||
<!-- product.public.category -->
|
||||
|
||||
<record id="public_category_desks" model="product.public.category">
|
||||
<field name="name">Desks</field>
|
||||
<field name="sequence">15</field>
|
||||
<field name="image_1920" type="base64" file="website_sale/static/src/img/categories/desks.jpg"/>
|
||||
</record>
|
||||
<record id="public_category_furnitures" model="product.public.category">
|
||||
<field name="name">Furnitures</field>
|
||||
<field name="sequence">17</field>
|
||||
<field name="image_1920" type="base64" file="website_sale/static/src/img/categories/furnitures.jpg"/>
|
||||
</record>
|
||||
<record id="public_category_boxes" model="product.public.category">
|
||||
<field name="name">Boxes</field>
|
||||
<field name="sequence">20</field>
|
||||
<field name="image_1920" type="base64" file="website_sale/static/src/img/categories/boxes.jpg"/>
|
||||
</record>
|
||||
<record id="public_category_drawers" model="product.public.category">
|
||||
<field name="name">Drawers</field>
|
||||
<field name="sequence">21</field>
|
||||
<field name="image_1920" type="base64" file="website_sale/static/src/img/categories/drawers.jpg"/>
|
||||
</record>
|
||||
<record id="public_category_cabinets" model="product.public.category">
|
||||
<field name="name">Cabinets</field>
|
||||
<field name="sequence">22</field>
|
||||
<field name="image_1920" type="base64" file="website_sale/static/src/img/categories/cabinets.jpg"/>
|
||||
</record>
|
||||
<record id="public_category_bins" model="product.public.category">
|
||||
<field name="name">Bins</field>
|
||||
<field name="sequence">23</field>
|
||||
<field name="image_1920" type="base64" file="website_sale/static/src/img/categories/bins.jpg"/>
|
||||
</record>
|
||||
<record id="public_category_lamps" model="product.public.category">
|
||||
<field name="name">Lamps</field>
|
||||
<field name="sequence">24</field>
|
||||
<field name="image_1920" type="base64" file="website_sale/static/src/img/categories/lamps.jpg"/>
|
||||
</record>
|
||||
<record id="services" model="product.public.category">
|
||||
<field name="name">Services</field>
|
||||
<field name="sequence">25</field>
|
||||
<field name="image_1920" type="base64" file="website_sale/static/src/img/warranty.jpg"/>
|
||||
</record>
|
||||
<record id="public_category_multimedia" model="product.public.category">
|
||||
<field name="name">Multimedia</field>
|
||||
<field name="sequence">26</field>
|
||||
<field name="image_1920" type="base64" file="product/static/img/product_product_43-image.jpg"/>
|
||||
</record>
|
||||
|
||||
<!-- subcategories -->
|
||||
<record id="public_category_desks_components" model="product.public.category">
|
||||
<field name="parent_id" eval="ref('public_category_desks')"/>
|
||||
<field name="name">Components</field>
|
||||
<field name="sequence">16</field>
|
||||
<field name="image_1920" type="base64" file="website_sale/static/src/img/categories/desk_components.jpg"/>
|
||||
</record>
|
||||
<record id="public_category_furnitures_chairs" model="product.public.category">
|
||||
<field name="parent_id" eval="ref('public_category_furnitures')"/>
|
||||
<field name="name">Chairs</field>
|
||||
<field name="sequence">18</field>
|
||||
</record>
|
||||
<record id="public_category_furnitures_couches" model="product.public.category">
|
||||
<field name="parent_id" eval="ref('public_category_furnitures')"/>
|
||||
<field name="name">Couches</field>
|
||||
<field name="sequence">19</field>
|
||||
</record>
|
||||
|
||||
<record id="product.product_product_1_product_template" model="product.template">
|
||||
<field name="public_categ_ids" eval="[(6,0,[ref('services')])]"/>
|
||||
</record>
|
||||
<record id="product.product_product_2_product_template" model="product.template">
|
||||
<field name="public_categ_ids" eval="[(6,0,[ref('services')])]"/>
|
||||
</record>
|
||||
<record id="product.product_product_3_product_template" model="product.template">
|
||||
<field name="public_categ_ids" eval="[(6,0,[ref('public_category_desks_components')])]"/>
|
||||
</record>
|
||||
<record id="product.consu_delivery_03_product_template" model="product.template">
|
||||
<field name="public_categ_ids" eval="[(6,0,[ref('public_category_desks')])]"/>
|
||||
</record>
|
||||
<record id="product.product_product_4_product_template" model="product.template">
|
||||
<field name="public_categ_ids" eval="[(6,0,[ref('public_category_desks')])]"/>
|
||||
</record>
|
||||
<record id="product.product_product_5_product_template" model="product.template">
|
||||
<field name="public_categ_ids" eval="[(6,0,[ref('public_category_desks')])]"/>
|
||||
</record>
|
||||
<record id="product.product_product_6_product_template" model="product.template">
|
||||
<field name="public_categ_ids" eval="[(6,0,[ref('public_category_cabinets')])]"/>
|
||||
</record>
|
||||
<record id="product.product_product_7_product_template" model="product.template">
|
||||
<field name="public_categ_ids" eval="[(6,0,[ref('public_category_boxes')])]"/>
|
||||
</record>
|
||||
<record id="product.product_product_8_product_template" model="product.template">
|
||||
<field name="public_categ_ids" eval="[(6,0,[ref('public_category_desks')])]"/>
|
||||
</record>
|
||||
<record id="product.product_product_9_product_template" model="product.template">
|
||||
<field name="public_categ_ids" eval="[(6,0,[ref('public_category_bins')])]"/>
|
||||
</record>
|
||||
<record id="product.product_product_10_product_template" model="product.template">
|
||||
<field name="public_categ_ids" eval="[(6,0,[ref('public_category_cabinets')])]"/>
|
||||
</record>
|
||||
<record id="product.product_product_11_product_template" model="product.template">
|
||||
<field name="website_sequence">9990</field>
|
||||
<field name="public_categ_ids" eval="[(6,0,[ref('public_category_furnitures_chairs')])]"/>
|
||||
</record>
|
||||
<record id="product.product_product_12_product_template" model="product.template">
|
||||
<field name="public_categ_ids" eval="[(6,0,[ref('public_category_furnitures_chairs')])]"/>
|
||||
</record>
|
||||
<record id="product.product_product_13_product_template" model="product.template">
|
||||
<field name="public_categ_ids" eval="[(6,0,[ref('public_category_desks')])]"/>
|
||||
</record>
|
||||
<record id="product.product_product_16_product_template" model="product.template">
|
||||
<field name="public_categ_ids" eval="[(6,0,[ref('public_category_drawers')])]"/>
|
||||
</record>
|
||||
<record id="product.product_product_20_product_template" model="product.template">
|
||||
<field name="public_categ_ids" eval="[(6,0,[ref('public_category_desks_components')])]"/>
|
||||
</record>
|
||||
<record id="product.product_product_22_product_template" model="product.template">
|
||||
<field name="public_categ_ids" eval="[(6,0,[ref('public_category_desks_components')])]"/>
|
||||
</record>
|
||||
<record id="product.product_product_25_product_template" model="product.template">
|
||||
<field name="public_categ_ids" eval="[(6,0,[ref('public_category_desks_components')])]"/>
|
||||
</record>
|
||||
<record id="product.product_product_27_product_template" model="product.template">
|
||||
<field name="public_categ_ids" eval="[(6,0,[ref('public_category_drawers')])]"/>
|
||||
</record>
|
||||
<record id="product.product_order_01_product_template" model="product.template">
|
||||
<field name="public_categ_ids" eval="[(6,0,[ref('public_category_multimedia')])]"/>
|
||||
</record>
|
||||
<record id="product.consu_delivery_01_product_template" model="product.template">
|
||||
<field name="public_categ_ids" eval="[(6,0,[ref('public_category_furnitures_couches')])]"/>
|
||||
</record>
|
||||
<record id="product.consu_delivery_02_product_template" model="product.template">
|
||||
<field name="public_categ_ids" eval="[(6,0,[ref('public_category_desks')])]"/>
|
||||
</record>
|
||||
<record id="product.consu_delivery_03_product_template" model="product.template">
|
||||
<field name="public_categ_ids" eval="[(6,0,[ref('public_category_desks')])]"/>
|
||||
</record>
|
||||
<record id="product.product_delivery_01_product_template" model="product.template">
|
||||
<field name="public_categ_ids" eval="[(6,0,[ref('public_category_furnitures_chairs')])]"/>
|
||||
</record>
|
||||
<record id="product.product_delivery_02_product_template" model="product.template">
|
||||
<field name="public_categ_ids" eval="[(6,0,[ref('public_category_lamps')])]"/>
|
||||
</record>
|
||||
|
||||
<record model="product.pricelist" id="product.list0">
|
||||
<field name="selectable" eval="True" />
|
||||
<field name="sequence">3</field>
|
||||
</record>
|
||||
|
||||
<record id="benelux" model="res.country.group">
|
||||
<field name="name">BeNeLux</field>
|
||||
<field name="country_ids" eval="[(6,0,[
|
||||
ref('base.be'),ref('base.lu'),ref('base.nl')])]"/>
|
||||
</record>
|
||||
|
||||
<record id="list_christmas" model="product.pricelist">
|
||||
<field name="name">Christmas</field>
|
||||
<field name="selectable" eval="False" />
|
||||
<field name="website_id" ref="website.default_website" />
|
||||
<field name="country_group_ids" eval="[(6,0,[ref('base.europe')])]" />
|
||||
<field name="sequence">20</field>
|
||||
</record>
|
||||
<record id="item_christmas" model="product.pricelist.item">
|
||||
<field name="pricelist_id" ref="list_christmas"/>
|
||||
<field name="compute_price">formula</field>
|
||||
<field name="base">list_price</field>
|
||||
<field name="price_discount">20</field>
|
||||
</record>
|
||||
|
||||
<record id="list_benelux" model="product.pricelist">
|
||||
<field name="name">Benelux</field>
|
||||
<field name="selectable" eval="False" />
|
||||
<field name="website_id" ref="website.default_website" />
|
||||
<field name="country_group_ids" eval="[(6,0,[ref('benelux')])]" />
|
||||
<field name="sequence">2</field>
|
||||
</record>
|
||||
<record id="item_benelux" model="product.pricelist.item">
|
||||
<field name="pricelist_id" ref="list_benelux"/>
|
||||
<field name="compute_price">percentage</field>
|
||||
<field name="base">list_price</field>
|
||||
<field name="percent_price">10</field>
|
||||
<field name="currency_id" ref="base.EUR"/>
|
||||
</record>
|
||||
|
||||
|
||||
<record id="list_europe" model="product.pricelist">
|
||||
<field name="name">EUR</field>
|
||||
<field name="selectable" eval="True" />
|
||||
<field name="website_id" ref="website.default_website" />
|
||||
<field name="country_group_ids" eval="[(6,0,[ref('base.europe')])]" />
|
||||
<field name="sequence">3</field>
|
||||
<field name="currency_id" ref="base.EUR"/>
|
||||
</record>
|
||||
<record id="item_europe" model="product.pricelist.item">
|
||||
<field name="pricelist_id" ref="list_europe"/>
|
||||
<field name="compute_price">formula</field>
|
||||
<field name="base">list_price</field>
|
||||
</record>
|
||||
|
||||
<record id="item_us" model="product.pricelist.item">
|
||||
<field name="pricelist_id" ref="product.list0"/>
|
||||
<field name="compute_price">formula</field>
|
||||
<field name="base">list_price</field>
|
||||
</record>
|
||||
|
||||
<!-- Add demo-data for pretty website sales graph (for the sales dashboard) -->
|
||||
<record id="website_sale_order_1" model="sale.order">
|
||||
<field name="create_date" eval="datetime.now() - timedelta(days=8)"/>
|
||||
<field name="partner_id" ref="base.res_partner_3"/>
|
||||
<field name="partner_invoice_id" ref="base.res_partner_address_25"/>
|
||||
<field name="partner_shipping_id" ref="base.res_partner_address_25"/>
|
||||
<field name="user_id" ref="base.user_demo"/>
|
||||
<field name="pricelist_id" ref="product.list0"/>
|
||||
<field name="team_id" ref="sales_team.salesteam_website_sales"/>
|
||||
<field name="date_order" eval="(datetime.now()-relativedelta(days=7)).strftime('%Y-%m-%d %H:%M:%S')"/>
|
||||
<field name="state">sale</field>
|
||||
</record>
|
||||
|
||||
<record id="website_sale_order_line_1" model="sale.order.line">
|
||||
<field name="order_id" ref="website_sale_order_1"/>
|
||||
<field name="name" model="sale.order.line" eval="obj().env.ref('product.product_product_6').get_product_multiline_description_sale()"/>
|
||||
<field name="product_id" ref="product.product_product_6"/>
|
||||
<field name="product_uom_qty">1</field>
|
||||
<field name="product_uom" ref="uom.product_uom_unit"/>
|
||||
<field name="price_unit">599.0</field>
|
||||
</record>
|
||||
|
||||
<record id="website_sale_order_2" model="sale.order">
|
||||
<field name="create_date" eval="datetime.now() - timedelta(days=8)"/>
|
||||
<field name="partner_id" ref="base.res_partner_3"/>
|
||||
<field name="partner_invoice_id" ref="base.res_partner_address_25"/>
|
||||
<field name="partner_shipping_id" ref="base.res_partner_address_25"/>
|
||||
<field name="user_id" ref="base.user_demo"/>
|
||||
<field name="pricelist_id" ref="product.list0"/>
|
||||
<field name="team_id" ref="sales_team.salesteam_website_sales"/>
|
||||
<field name="date_order" eval="(datetime.now()-relativedelta(days=6)).strftime('%Y-%m-%d %H:%M:%S')"/>
|
||||
<field name="state">sale</field>
|
||||
</record>
|
||||
|
||||
<record id="website_sale_order_line_2" model="sale.order.line">
|
||||
<field name="order_id" ref="website_sale_order_2"/>
|
||||
<field name="name" model="sale.order.line" eval="obj().env.ref('product.product_product_4').get_product_multiline_description_sale()"/>
|
||||
<field name="product_id" ref="product.product_product_4"/>
|
||||
<field name="product_uom_qty">1</field>
|
||||
<field name="product_uom" ref="uom.product_uom_unit"/>
|
||||
<field name="price_unit">900</field>
|
||||
</record>
|
||||
|
||||
<record id="website_sale_order_3" model="sale.order">
|
||||
<field name="create_date" eval="datetime.now() - timedelta(days=8)"/>
|
||||
<field name="partner_id" ref="base.res_partner_3"/>
|
||||
<field name="partner_invoice_id" ref="base.res_partner_address_25"/>
|
||||
<field name="partner_shipping_id" ref="base.res_partner_address_25"/>
|
||||
<field name="user_id" ref="base.user_demo"/>
|
||||
<field name="pricelist_id" ref="product.list0"/>
|
||||
<field name="team_id" ref="sales_team.salesteam_website_sales"/>
|
||||
<field name="date_order" eval="(datetime.now()-relativedelta(days=5)).strftime('%Y-%m-%d %H:%M:%S')"/>
|
||||
<field name="tag_ids" eval="[(4, ref('sales_team.categ_oppor2'))]"/>
|
||||
<field name="state">sale</field>
|
||||
</record>
|
||||
|
||||
<record id="website_sale_order_line_3" model="sale.order.line">
|
||||
<field name="order_id" ref="website_sale_order_3"/>
|
||||
<field name="name" model="sale.order.line" eval="obj().env.ref('product.product_product_4').get_product_multiline_description_sale()"/>
|
||||
<field name="product_id" ref="product.product_product_4"/>
|
||||
<field name="product_uom_qty">1</field>
|
||||
<field name="product_uom" ref="uom.product_uom_unit"/>
|
||||
<field name="price_unit">750</field>
|
||||
</record>
|
||||
|
||||
<record id="website_sale_order_4" model="sale.order">
|
||||
<field name="create_date" eval="datetime.now() - timedelta(days=8)"/>
|
||||
<field name="partner_id" ref="base.res_partner_3"/>
|
||||
<field name="partner_invoice_id" ref="base.res_partner_address_25"/>
|
||||
<field name="partner_shipping_id" ref="base.res_partner_address_25"/>
|
||||
<field name="user_id" ref="base.user_demo"/>
|
||||
<field name="pricelist_id" ref="product.list0"/>
|
||||
<field name="team_id" ref="sales_team.salesteam_website_sales"/>
|
||||
<field name="date_order" eval="(datetime.now()-relativedelta(days=4)).strftime('%Y-%m-%d %H:%M:%S')"/>
|
||||
<field name="state">sale</field>
|
||||
</record>
|
||||
|
||||
<record id="website_sale_order_line_4" model="sale.order.line">
|
||||
<field name="order_id" ref="website_sale_order_4"/>
|
||||
<field name="name" model="sale.order.line" eval="obj().env.ref('product.product_product_8').get_product_multiline_description_sale()"/>
|
||||
<field name="product_id" ref="product.product_product_8"/>
|
||||
<field name="product_uom_qty">1</field>
|
||||
<field name="product_uom" ref="uom.product_uom_unit"/>
|
||||
<field name="price_unit">1199.0</field>
|
||||
</record>
|
||||
|
||||
<record id="website_sale_order_5" model="sale.order">
|
||||
<field name="create_date" eval="datetime.now() - timedelta(days=8)"/>
|
||||
<field name="partner_id" ref="base.res_partner_3"/>
|
||||
<field name="partner_invoice_id" ref="base.res_partner_address_25"/>
|
||||
<field name="partner_shipping_id" ref="base.res_partner_address_25"/>
|
||||
<field name="user_id" ref="base.user_demo"/>
|
||||
<field name="pricelist_id" ref="product.list0"/>
|
||||
<field name="team_id" ref="sales_team.salesteam_website_sales"/>
|
||||
<field name="date_order" eval="(datetime.now()-relativedelta(days=3)).strftime('%Y-%m-%d %H:%M:%S')"/>
|
||||
<field name="state">sale</field>
|
||||
</record>
|
||||
|
||||
<record id="website_sale_order_line_5" model="sale.order.line">
|
||||
<field name="order_id" ref="website_sale_order_5"/>
|
||||
<field name="name" model="sale.order.line" eval="obj().env.ref('product.product_product_4').get_product_multiline_description_sale()"/>
|
||||
<field name="product_id" ref="product.product_product_4"/>
|
||||
<field name="product_uom_qty">3</field>
|
||||
<field name="product_uom" ref="uom.product_uom_unit"/>
|
||||
<field name="price_unit">349.0</field>
|
||||
</record>
|
||||
|
||||
<record id="website_sale_order_6" model="sale.order">
|
||||
<field name="create_date" eval="datetime.now() - timedelta(days=8)"/>
|
||||
<field name="partner_id" ref="base.res_partner_3"/>
|
||||
<field name="partner_invoice_id" ref="base.res_partner_address_25"/>
|
||||
<field name="partner_shipping_id" ref="base.res_partner_address_25"/>
|
||||
<field name="user_id" ref="base.user_demo"/>
|
||||
<field name="pricelist_id" ref="product.list0"/>
|
||||
<field name="team_id" ref="sales_team.salesteam_website_sales"/>
|
||||
<field name="date_order" eval="(datetime.now()-relativedelta(days=2)).strftime('%Y-%m-%d %H:%M:%S')"/>
|
||||
<field name="state">sale</field>
|
||||
</record>
|
||||
|
||||
<record id="website_sale_order_line_6" model="sale.order.line">
|
||||
<field name="order_id" ref="website_sale_order_6"/>
|
||||
<field name="name" model="sale.order.line" eval="obj().env.ref('product.product_product_8').get_product_multiline_description_sale()"/>
|
||||
<field name="product_id" ref="product.product_product_8"/>
|
||||
<field name="product_uom_qty">1</field>
|
||||
<field name="product_uom" ref="uom.product_uom_unit"/>
|
||||
<field name="price_unit">1599.00</field>
|
||||
</record>
|
||||
|
||||
<record id="website_sale_order_7" model="sale.order">
|
||||
<field name="create_date" eval="datetime.now() - timedelta(days=8)"/>
|
||||
<field name="partner_id" ref="base.res_partner_3"/>
|
||||
<field name="partner_invoice_id" ref="base.res_partner_address_25"/>
|
||||
<field name="partner_shipping_id" ref="base.res_partner_address_25"/>
|
||||
<field name="user_id" ref="base.user_demo"/>
|
||||
<field name="website_id" ref="website.default_website"/>
|
||||
<field name="pricelist_id" ref="product.list0"/>
|
||||
<field name="team_id" ref="sales_team.salesteam_website_sales"/>
|
||||
<field name="date_order" eval="(datetime.now()-relativedelta(days=1)).strftime('%Y-%m-%d %H:%M:%S')"/>
|
||||
<field name="state">sale</field>
|
||||
</record>
|
||||
|
||||
<record id="website_sale_order_line_7" model="sale.order.line">
|
||||
<field name="order_id" ref="website_sale_order_7"/>
|
||||
<field name="name" model="sale.order.line" eval="obj().env.ref('product.product_product_8').get_product_multiline_description_sale()"/>
|
||||
<field name="product_id" ref="product.product_product_8"/>
|
||||
<field name="product_uom_qty">1</field>
|
||||
<field name="product_uom" ref="uom.product_uom_unit"/>
|
||||
<field name="price_unit">1349.00</field>
|
||||
</record>
|
||||
|
||||
<record id="website_sale_order_8" model="sale.order">
|
||||
<field name="partner_id" ref="base.res_partner_3"/>
|
||||
<field name="partner_invoice_id" ref="base.res_partner_address_25"/>
|
||||
<field name="partner_shipping_id" ref="base.res_partner_address_25"/>
|
||||
<field name="user_id" ref="base.user_demo"/>
|
||||
<field name="website_id" ref="website.default_website"/>
|
||||
<field name="pricelist_id" ref="product.list0"/>
|
||||
<field name="team_id" ref="sales_team.salesteam_website_sales"/>
|
||||
<field name="date_order" eval="datetime.now()"/>
|
||||
<field name="tag_ids" eval="[(4, ref('sales_team.categ_oppor1'))]"/>
|
||||
<field name="state">sale</field>
|
||||
</record>
|
||||
|
||||
<record id="website_sale_order_line_8" model="sale.order.line">
|
||||
<field name="order_id" ref="website_sale_order_8"/>
|
||||
<field name="name" model="sale.order.line" eval="obj().env.ref('product.product_product_8').get_product_multiline_description_sale()"/>
|
||||
<field name="product_id" ref="product.product_product_8"/>
|
||||
<field name="product_uom_qty">1</field>
|
||||
<field name="product_uom" ref="uom.product_uom_unit"/>
|
||||
<field name="price_unit">1799.00</field>
|
||||
</record>
|
||||
|
||||
<record id="website_sale_order_9" model="sale.order">
|
||||
<field name="partner_id" ref="base.res_partner_3"/>
|
||||
<field name="partner_invoice_id" ref="base.res_partner_address_25"/>
|
||||
<field name="partner_shipping_id" ref="base.res_partner_address_25"/>
|
||||
<field name="user_id" ref="base.user_demo"/>
|
||||
<field name="website_id" ref="website.default_website"/>
|
||||
<field name="pricelist_id" ref="product.list0"/>
|
||||
<field name="team_id" ref="sales_team.salesteam_website_sales"/>
|
||||
<field name="date_order" eval="(datetime.now()-relativedelta(hours=2)).strftime('%Y-%m-%d %H:%M:%S')"/>
|
||||
</record>
|
||||
|
||||
<record id="website_sale_order_line_9" model="sale.order.line">
|
||||
<field name="order_id" ref="website_sale_order_9"/>
|
||||
<field name="name" model="sale.order.line" eval="obj().env.ref('product.product_product_25').get_product_multiline_description_sale()"/>
|
||||
<field name="product_id" ref="product.product_product_25"/>
|
||||
<field name="product_uom_qty">1</field>
|
||||
<field name="product_uom" ref="uom.product_uom_unit"/>
|
||||
<field name="price_unit">295.00</field>
|
||||
</record>
|
||||
|
||||
<record id="website_sale_order_line_10" model="sale.order.line">
|
||||
<field name="order_id" ref="website_sale_order_9"/>
|
||||
<field name="name" model="sale.order.line" eval="obj().env.ref('product.product_product_12').get_product_multiline_description_sale()"/>
|
||||
<field name="product_id" ref="product.product_product_12"/>
|
||||
<field name="product_uom_qty">1</field>
|
||||
<field name="product_uom" ref="uom.product_uom_unit"/>
|
||||
<field name="price_unit">120.50</field>
|
||||
</record>
|
||||
|
||||
<!-- Active Carts -->
|
||||
<record id="website_sale_order_10" model="sale.order">
|
||||
<field name="partner_id" ref="base.res_partner_3"/>
|
||||
<field name="partner_invoice_id" ref="base.res_partner_address_25"/>
|
||||
<field name="partner_shipping_id" ref="base.res_partner_address_25"/>
|
||||
<field name="user_id" ref="base.user_demo"/>
|
||||
<field name="website_id" ref="website.default_website"/>
|
||||
<field name="pricelist_id" ref="product.list0"/>
|
||||
<field name="team_id" ref="sales_team.salesteam_website_sales"/>
|
||||
<field name="date_order" eval="datetime.now()"/>
|
||||
<field name="tag_ids" eval="[(4, ref('sales_team.categ_oppor5'))]"/>
|
||||
</record>
|
||||
|
||||
<record id="website_sale_order_line_11" model="sale.order.line">
|
||||
<field name="order_id" ref="website_sale_order_10"/>
|
||||
<field name="name" model="sale.order.line" eval="obj().env.ref('product.product_product_11').get_product_multiline_description_sale()"/>
|
||||
<field name="product_id" ref="product.product_product_11"/>
|
||||
<field name="product_uom_qty">2</field>
|
||||
<field name="product_uom" ref="uom.product_uom_unit"/>
|
||||
<field name="price_unit">33</field>
|
||||
</record>
|
||||
|
||||
<!-- Abandoned Carts -->
|
||||
<record id="website_sale_order_11" model="sale.order">
|
||||
<field name="partner_id" ref="base.res_partner_3"/>
|
||||
<field name="partner_invoice_id" ref="base.res_partner_address_25"/>
|
||||
<field name="partner_shipping_id" ref="base.res_partner_address_25"/>
|
||||
<field name="user_id" ref="base.user_demo"/>
|
||||
<field name="website_id" ref="website.default_website"/>
|
||||
<field name="pricelist_id" ref="product.list0"/>
|
||||
<field name="team_id" ref="sales_team.salesteam_website_sales"/>
|
||||
<field name="date_order" eval="(datetime.now()-timedelta(hours=1)).strftime('%Y-%m-%d %H:%M:%S')"/>
|
||||
</record>
|
||||
|
||||
<record id="website_sale_order_line_12" model="sale.order.line">
|
||||
<field name="order_id" ref="website_sale_order_11"/>
|
||||
<field name="name" model="sale.order.line" eval="obj().env.ref('product.product_product_9').get_product_multiline_description_sale()"/>
|
||||
<field name="product_id" ref="product.product_product_9"/>
|
||||
<field name="product_uom_qty">1</field>
|
||||
<field name="product_uom" ref="uom.product_uom_unit"/>
|
||||
<field name="price_unit">47.0</field>
|
||||
</record>
|
||||
|
||||
<!-- Payments to Capture -->
|
||||
<record id="website_sale_order_13" model="sale.order">
|
||||
<field name="partner_id" ref="base.res_partner_3"/>
|
||||
<field name="partner_invoice_id" ref="base.res_partner_address_25"/>
|
||||
<field name="partner_shipping_id" ref="base.res_partner_address_25"/>
|
||||
<field name="user_id" ref="base.user_demo"/>
|
||||
<field name="website_id" ref="website.default_website"/>
|
||||
<field name="pricelist_id" ref="product.list0"/>
|
||||
<field name="team_id" ref="sales_team.salesteam_website_sales"/>
|
||||
<field name="payment_term_id" ref="account.account_payment_term_immediate"/>
|
||||
<field name="date_order" eval="(datetime.now()-timedelta(hours=1)).strftime('%Y-%m-%d %H:%M:%S')"/>
|
||||
<field name="state">sent</field>
|
||||
</record>
|
||||
|
||||
<record id="website_sale_order_line_14" model="sale.order.line">
|
||||
<field name="order_id" ref="website_sale_order_13"/>
|
||||
<field name="name" model="sale.order.line" eval="obj().env.ref('product.product_product_8').get_product_multiline_description_sale()"/>
|
||||
<field name="product_id" ref="product.product_product_8"/>
|
||||
<field name="product_uom_qty">1</field>
|
||||
<field name="product_uom" ref="uom.product_uom_unit"/>
|
||||
<field name="price_unit">1799.0</field>
|
||||
</record>
|
||||
|
||||
<!-- Order to Invoice -->
|
||||
<record id="website_sale_order_14" model="sale.order">
|
||||
<field name="partner_id" ref="base.res_partner_3"/>
|
||||
<field name="partner_invoice_id" ref="base.res_partner_address_25"/>
|
||||
<field name="partner_shipping_id" ref="base.res_partner_address_25"/>
|
||||
<field name="user_id" ref="base.user_demo"/>
|
||||
<field name="website_id" ref="website.default_website"/>
|
||||
<field name="pricelist_id" ref="product.list0"/>
|
||||
<field name="team_id" ref="sales_team.salesteam_website_sales"/>
|
||||
</record>
|
||||
|
||||
<record id="website_sale_order_line_15" model="sale.order.line">
|
||||
<field name="order_id" ref="website_sale_order_14"/>
|
||||
<field name="name" model="sale.order.line" eval="obj().env.ref('product.product_product_16').get_product_multiline_description_sale()"/>
|
||||
<field name="product_id" ref="product.product_product_16"/>
|
||||
<field name="product_uom_qty">1</field>
|
||||
<field name="product_uom" ref="uom.product_uom_unit"/>
|
||||
<field name="price_unit">25.0</field>
|
||||
</record>
|
||||
|
||||
<record id="website_sale_order_16" model="sale.order">
|
||||
<field name="create_date" eval="datetime.now() - relativedelta(months=1)"/>
|
||||
<field name="partner_id" ref="base.res_partner_3"/>
|
||||
<field name="partner_invoice_id" ref="base.res_partner_address_25"/>
|
||||
<field name="partner_shipping_id" ref="base.res_partner_address_25"/>
|
||||
<field name="user_id" ref="base.user_demo"/>
|
||||
<field name="website_id" ref="website.default_website"/>
|
||||
<field name="pricelist_id" ref="product.list0"/>
|
||||
<field name="team_id" ref="sales_team.salesteam_website_sales"/>
|
||||
<field name="date_order" eval="datetime.now()-relativedelta(months=1)"/>
|
||||
<field name="state">sale</field>
|
||||
</record>
|
||||
|
||||
<record id="website_sale_order_line_16" model="sale.order.line">
|
||||
<field name="order_id" ref="website_sale_order_16"/>
|
||||
<field name="name" model="sale.order.line" eval="obj().env.ref('product.product_product_8').get_product_multiline_description_sale()"/>
|
||||
<field name="product_id" ref="product.product_product_8"/>
|
||||
<field name="product_uom_qty">2</field>
|
||||
<field name="product_uom" ref="uom.product_uom_unit"/>
|
||||
<field name="price_unit">1799.0</field>
|
||||
</record>
|
||||
|
||||
<record id="website_sale_order_17" model="sale.order">
|
||||
<field name="create_date" eval="datetime.now() - relativedelta(months=1, days=2)"/>
|
||||
<field name="partner_id" ref="base.res_partner_3"/>
|
||||
<field name="partner_invoice_id" ref="base.res_partner_address_25"/>
|
||||
<field name="partner_shipping_id" ref="base.res_partner_address_25"/>
|
||||
<field name="user_id" ref="base.user_demo"/>
|
||||
<field name="website_id" ref="website.default_website"/>
|
||||
<field name="pricelist_id" ref="product.list0"/>
|
||||
<field name="team_id" ref="sales_team.salesteam_website_sales"/>
|
||||
<field name="date_order" eval="datetime.now()-relativedelta(months=1, days=2)"/>
|
||||
</record>
|
||||
|
||||
<record id="website_sale_order_line_17" model="sale.order.line">
|
||||
<field name="order_id" ref="website_sale_order_17"/>
|
||||
<field name="name" model="sale.order.line" eval="obj().env.ref('product.product_product_9').get_product_multiline_description_sale()"/>
|
||||
<field name="product_id" ref="product.product_product_9"/>
|
||||
<field name="product_uom_qty">7</field>
|
||||
<field name="product_uom" ref="uom.product_uom_unit"/>
|
||||
<field name="price_unit">47.0</field>
|
||||
<field name="invoice_status">to invoice</field>
|
||||
</record>
|
||||
|
||||
<record id="website_sale_order_18" model="sale.order">
|
||||
<field name="create_date" eval="datetime.now() - relativedelta(months=2)"/>
|
||||
<field name="partner_id" ref="base.res_partner_3"/>
|
||||
<field name="partner_invoice_id" ref="base.res_partner_address_25"/>
|
||||
<field name="partner_shipping_id" ref="base.res_partner_address_25"/>
|
||||
<field name="user_id" ref="base.user_demo"/>
|
||||
<field name="website_id" ref="website.default_website"/>
|
||||
<field name="pricelist_id" ref="product.list0"/>
|
||||
<field name="team_id" ref="sales_team.salesteam_website_sales"/>
|
||||
<field name="date_order" eval="datetime.now()-relativedelta(months=2)"/>
|
||||
</record>
|
||||
|
||||
<record id="website_sale_order_line_18" model="sale.order.line">
|
||||
<field name="order_id" ref="website_sale_order_18"/>
|
||||
<field name="name" model="sale.order.line" eval="obj().env.ref('product.product_product_9').get_product_multiline_description_sale()"/>
|
||||
<field name="product_id" ref="product.product_product_9"/>
|
||||
<field name="product_uom_qty">3</field>
|
||||
<field name="product_uom" ref="uom.product_uom_unit"/>
|
||||
<field name="price_unit">47.0</field>
|
||||
<field name="invoice_status">to invoice</field>
|
||||
</record>
|
||||
|
||||
|
||||
<!-- action_confirm for confirmation date -->
|
||||
<function model="sale.order" name="action_confirm" eval="[[ref('website_sale_order_14')]]"/>
|
||||
|
||||
<record id="product_product_1_product_template" model="product.template">
|
||||
<field name="name">Warranty</field>
|
||||
<field name="list_price">20.0</field>
|
||||
<field name="website_sequence">9980</field>
|
||||
<field name="is_published" eval="True"/>
|
||||
<field name="type">service</field>
|
||||
<field name="uom_id" ref="uom.product_uom_unit"/>
|
||||
<field name="uom_po_id" ref="uom.product_uom_unit"/>
|
||||
<field name="description_sale">Warranty, issued to the purchaser of an article by its manufacturer, promising to repair or replace it if necessary within a specified period of time.</field>
|
||||
<field name="categ_id" ref="product.product_category_3"/>
|
||||
<field name="invoice_policy">delivery</field>
|
||||
<field name="public_categ_ids" eval="[(6, 0, [ref('website_sale.services')])]"/>
|
||||
<field name="image_1920" type="base64" file="website_sale/static/src/img/warranty.jpg"/>
|
||||
</record>
|
||||
|
||||
<record id="product_1_attribute_3_product_template_attribute_line" model="product.template.attribute.line">
|
||||
<field name="product_tmpl_id" ref="website_sale.product_product_1_product_template"/>
|
||||
<field name="attribute_id" ref="product.product_attribute_3"/>
|
||||
<field name="value_ids" eval="[(6,0,[ref('product.product_attribute_value_5'), ref('product.product_attribute_value_6')])]"/>
|
||||
</record>
|
||||
|
||||
<!-- Handle automatically created product.template.attribute.value -->
|
||||
<function model="ir.model.data" name="_update_xmlids">
|
||||
<value model="base" eval="[{
|
||||
'xml_id': 'website_sale.product_1_attribute_3_value_1',
|
||||
'record': obj().env.ref('website_sale.product_1_attribute_3_product_template_attribute_line').product_template_value_ids[0],
|
||||
'noupdate': True,
|
||||
}, {
|
||||
'xml_id': 'website_sale.product_1_attribute_3_value_2',
|
||||
'record': obj().env.ref('website_sale.product_1_attribute_3_product_template_attribute_line').product_template_value_ids[1],
|
||||
'noupdate': True,
|
||||
}]"/>
|
||||
</function>
|
||||
|
||||
<function model="ir.model.data" name="_update_xmlids">
|
||||
<value model="base" eval="[{
|
||||
'xml_id': 'website_sale.product_product_1',
|
||||
'record': obj().env.ref('website_sale.product_product_1_product_template')._get_variant_for_combination(obj().env.ref('website_sale.product_1_attribute_3_value_1')),
|
||||
'noupdate': True,
|
||||
}, {
|
||||
'xml_id': 'website_sale.product_product_1b',
|
||||
'record': obj().env.ref('website_sale.product_product_1_product_template')._get_variant_for_combination(obj().env.ref('website_sale.product_1_attribute_3_value_2')),
|
||||
'noupdate': True,
|
||||
},]"/>
|
||||
</function>
|
||||
|
||||
<record id="product_product_1" model="product.product">
|
||||
<field name="default_code">SERV_125889</field>
|
||||
</record>
|
||||
<record id="product_product_1b" model="product.product">
|
||||
<field name="default_code">SERV_125890</field>
|
||||
</record>
|
||||
|
||||
<record id="website_sale.product_1_attribute_3_value_2" model="product.template.attribute.value">
|
||||
<field name="price_extra">18.00</field>
|
||||
</record>
|
||||
|
||||
<record id="website_sale_activity_1" model="mail.activity">
|
||||
<field name="res_id" ref="website_sale.website_sale_order_3"/>
|
||||
<field name="res_model_id" ref="sale.model_sale_order"/>
|
||||
<field name="activity_type_id" ref="mail.mail_activity_data_call"/>
|
||||
<field name="date_deadline" eval="(DateTime.today() + relativedelta(days=5)).strftime('%Y-%m-%d %H:%M')" />
|
||||
<field name="create_uid" ref="base.user_demo"/>
|
||||
<field name="user_id" ref="base.user_demo"/>
|
||||
</record>
|
||||
<record id="website_sale_activity_2" model="mail.activity">
|
||||
<field name="res_id" ref="website_sale.website_sale_order_8"/>
|
||||
<field name="res_model_id" ref="sale.model_sale_order"/>
|
||||
<field name="activity_type_id" ref="mail.mail_activity_data_todo"/>
|
||||
<field name="date_deadline" eval="(DateTime.today() + relativedelta(days=5)).strftime('%Y-%m-%d %H:%M')" />
|
||||
<field name="summary">Follow-up on satisfaction</field>
|
||||
<field name="create_uid" ref="base.user_demo"/>
|
||||
<field name="user_id" ref="base.user_demo"/>
|
||||
</record>
|
||||
<record id="website_sale_activity_3" model="mail.activity">
|
||||
<field name="res_id" ref="website_sale.website_sale_order_9"/>
|
||||
<field name="res_model_id" ref="sale.model_sale_order"/>
|
||||
<field name="activity_type_id" ref="mail.mail_activity_data_todo"/>
|
||||
<field name="date_deadline" eval="(DateTime.today() + relativedelta(days=5)).strftime('%Y-%m-%d %H:%M')" />
|
||||
<field name="summary">Confirm quote</field>
|
||||
<field name="create_uid" ref="base.user_demo"/>
|
||||
<field name="user_id" ref="base.user_demo"/>
|
||||
</record>
|
||||
<record id="website_sale_activity_5" model="mail.activity">
|
||||
<field name="res_id" ref="website_sale.website_sale_order_11"/>
|
||||
<field name="res_model_id" ref="sale.model_sale_order"/>
|
||||
<field name="activity_type_id" ref="mail.mail_activity_data_email"/>
|
||||
<field name="date_deadline" eval="(DateTime.today() - relativedelta(days=5)).strftime('%Y-%m-%d %H:%M')" />
|
||||
<field name="summary">Send updated pricelist</field>
|
||||
<field name="create_uid" ref="base.user_demo"/>
|
||||
<field name="user_id" ref="base.user_demo"/>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<odoo>
|
||||
<data noupdate="1">
|
||||
<record id="digest.digest_digest_default" model="digest.digest">
|
||||
<field name="kpi_website_sale_total">True</field>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record id="ir_cron_send_availability_email" model="ir.cron">
|
||||
<field name="name">eCommerce: send email to customers about their abandoned cart</field>
|
||||
<field name="interval_number">1</field>
|
||||
<field name="interval_type">hours</field>
|
||||
<field name="numbercall">-1</field>
|
||||
<field name="doall" eval="False"/>
|
||||
<field name="model_id" ref="model_website"/>
|
||||
<field name="code">model._send_abandoned_cart_email()</field>
|
||||
<field name="state">code</field>
|
||||
</record>
|
||||
</odoo>
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data noupdate="1">
|
||||
<record id="mail_template_sale_cart_recovery" model="mail.template">
|
||||
<field name="name">Ecommerce: Cart Recovery</field>
|
||||
<field name="model_id" ref="sale.model_sale_order"/>
|
||||
<field name="subject">You left items in your cart!</field>
|
||||
<field name="email_from">{{ (object.user_id.email_formatted or object.company_id.email_formatted or user.email_formatted or '') }}</field>
|
||||
<field name="partner_to">{{ object.partner_id.id }}</field>
|
||||
<field name="description">If the setting is set, sent to authenticated visitors who abandoned their cart</field>
|
||||
<field name="body_html" type="html">
|
||||
<table border="0" cellpadding="0" cellspacing="0" width="590" style="padding: 0px; background-color: white; color: #454748; border-collapse:separate;">
|
||||
<tbody>
|
||||
<!-- CONTENT -->
|
||||
<tr>
|
||||
<td align="center" style="min-width: 590px;">
|
||||
<table border="0" cellpadding="0" cellspacing="0" width="590" style="min-width: 590px; background-color: white; padding: 0px 0px 0px 0px; border-collapse:separate;">
|
||||
<tr><td valign="top" style="font-size: 13px;">
|
||||
<h1 style="color:#A9A9A9;">THERE'S SOMETHING IN YOUR CART.</h1>
|
||||
Would you like to complete your purchase?<br/><br/>
|
||||
<t t-if="object.order_line">
|
||||
<t t-foreach="object.website_order_line" t-as="line">
|
||||
<hr/>
|
||||
<table width="100%">
|
||||
<tr>
|
||||
<td style="padding: 10px; width:150px;">
|
||||
<img t-attf-src="/web/image/product.product/{{ line.product_id.id }}/image_128" style="width: 100px; height: 100px; object-fit: contain;" alt="Product image"></img>
|
||||
</td>
|
||||
<td>
|
||||
<strong t-out="line.product_id.display_name or ''">[FURN_7800] Desk Combination</strong><br/><t t-out="line.name or ''">[FURN_7800] Desk Combination Desk combination, black-brown: chair + desk + drawer.</t>
|
||||
</td>
|
||||
<td width="100px" align="right">
|
||||
<t t-out="int(line.product_uom_qty) or ''">10000</t> <t t-out="line.product_uom.name or ''">Units</t>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</t>
|
||||
<hr/>
|
||||
</t>
|
||||
<div style="text-align: center; padding: 16px 0px 16px 0px; font-size: 14px;">
|
||||
<a t-attf-href="{{ object.get_base_url() }}/shop/cart?access_token={{ object.access_token }}"
|
||||
target="_blank"
|
||||
style="background-color: #875A7B; padding: 8px 16px 8px 16px; text-decoration: none; color: #fff; border-radius: 5px; font-size:13px;">
|
||||
Resume order
|
||||
</a>
|
||||
</div>
|
||||
<t t-set="company" t-value="object.company_id or object.user_id.company_id or user.company_id"/>
|
||||
<div style="text-align: center;"><strong>Thank you for shopping with <t t-out="company.name or ''">My Company (San Francisco)</t>!</strong></div>
|
||||
</td></tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</field>
|
||||
<field name="lang">{{ object.partner_id.lang }}</field>
|
||||
<field name="auto_delete" eval="False"/>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
|
|
@ -0,0 +1,406 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data>
|
||||
<!-- Templates for Dynamic Snippet -->
|
||||
<template id="dynamic_filter_template_product_product_add_to_cart" name="Classic Card">
|
||||
<t t-foreach="records" t-as="data" data-thumb="/website_sale/static/src/img/snippets_options/product_add_to_cart.svg">
|
||||
<t t-set="record" t-value="data['_record']"/>
|
||||
<div class="o_carousel_product_card card h-100 w-100" t-att-data-add2cart-rerender="data.get('_add2cart_rerender')">
|
||||
<div t-if="is_sample" class="h5 o_ribbon_right bg-primary text-uppercase">Sample</div>
|
||||
<input type="hidden" name="product-id" t-att-data-product-id="record.id"/>
|
||||
<a class="o_carousel_product_img_link o_dynamic_product_hovered overflow-hidden" t-att-href="record.website_url">
|
||||
<img class="card-img-top o_img_product_square o_img_product_cover h-auto" loading="lazy" t-att-src="data['image_512']"
|
||||
t-att-alt="record.display_name"/>
|
||||
</a>
|
||||
<i t-if="data.get('_latest_viewed')" class="fa fa-trash o_carousel_product_remove js_remove"/>
|
||||
<div class="o_carousel_product_card_body card-body d-flex flex-wrap">
|
||||
<a t-att-href="record.website_url" class="text-decoration-none d-block w-100">
|
||||
<div class="h6 card-title mb-0" t-field="record.display_name"/>
|
||||
</a>
|
||||
<div class="mt-2">
|
||||
<t t-if="is_view_active('website_sale.product_comment')" t-call="portal_rating.rating_widget_stars_static">
|
||||
<t t-set="rating_avg" t-value="record.rating_avg"/>
|
||||
<t t-set="rating_count" t-value="record.rating_count"/>
|
||||
</t>
|
||||
</div>
|
||||
<div class="w-100 d-flex flex-wrap flex-md-column flex-lg-row align-items-center align-self-end justify-content-between mt-3">
|
||||
<div class="py-2">
|
||||
<t t-call="website_sale.price_dynamic_filter_template_product_product"/>
|
||||
</div>
|
||||
<div class="o_dynamic_snippet_btn_wrapper" t-if="record._website_show_quick_add()">
|
||||
<button type="button" role="button" class="btn btn-primary js_add_cart ms-auto" title="Add to Cart">
|
||||
<i class="fa fa-fw fa-shopping-cart"/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
<template id="dynamic_filter_template_product_product_view_detail" name="Classic Card - Detailed">
|
||||
<t t-foreach="records" t-as="data" data-number-of-elements="3" data-thumb="/website_sale/static/src/img/snippets_options/product_view_detail.svg">
|
||||
<t t-set="record" t-value="data['_record']" data-arrow-position="bottom"/>
|
||||
<div class="o_carousel_product_card card h-100 w-100" t-att-data-add2cart-rerender="data.get('_add2cart_rerender')">
|
||||
<div t-if="is_sample" class="h5 o_ribbon_right bg-primary text-uppercase">Sample</div>
|
||||
<a class="o_carousel_product_img_link o_dynamic_product_hovered overflow-hidden" t-att-href="record.website_url">
|
||||
<img class="card-img-top o_img_product_square o_img_product_cover h-auto" loading="lazy" t-att-src="data['image_512']" t-att-alt="record.display_name"/>
|
||||
</a>
|
||||
<div class="o_carousel_product_card_body card-body d-flex flex-column justify-content-between">
|
||||
<div class="card-title h5" t-field="record.display_name"/>
|
||||
<div class="card-text flex-grow-1 text-muted h6" t-field="record.description_sale"/>
|
||||
<div class="mt-2">
|
||||
<t t-if="is_view_active('website_sale.product_comment')" t-call="portal_rating.rating_widget_stars_static">
|
||||
<t t-set="rating_avg" t-value="record.rating_avg"/>
|
||||
<t t-set="rating_count" t-value="record.rating_count"/>
|
||||
</t>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between flex-wrap flex-md-column flex-lg-row align-items-center align-self-end w-100 mt-2 pt-3 border-top">
|
||||
<div class="pb-2">
|
||||
<t t-call="website_sale.price_dynamic_filter_template_product_product"/>
|
||||
</div>
|
||||
<a class="btn btn-primary" t-att-href="record.website_url">
|
||||
View product
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
<template id="dynamic_filter_template_product_product_mini_image" name="Image only">
|
||||
<t t-foreach="records" t-as="data" data-number-of-elements="4" data-number-of-elements-sm="1" data-thumb="/website_sale/static/src/img/snippets_options/product_image_only.svg">
|
||||
<t t-set="record" t-value="data['_record']"/>
|
||||
<div class="card h-100 border-0 w-100 rounded-0 bg-transparent" t-att-data-url="record.website_url">
|
||||
<div t-if="is_sample" class="h5 o_ribbon_right bg-primary text-uppercase">Sample</div>
|
||||
<a class="o_carousel_product_img_link o_dynamic_product_hovered overflow-hidden" t-att-href="record.website_url">
|
||||
<img class="card-img-top h-auto o_img_product_square o_img_product_cover rounded" loading="lazy" t-att-src="data['image_512']" t-att-alt="record.display_name"/>
|
||||
</a>
|
||||
</div>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
<template id="dynamic_filter_template_product_product_mini_price" name="Image with price">
|
||||
<t t-foreach="records" t-as="data" data-thumb="/website_sale/static/src/img/snippets_options/product_image_with_price.svg">
|
||||
<t t-set="record" t-value="data['_record']"/>
|
||||
<div class="card h-100 border-0 w-100 rounded-0 bg-transparent o_dynamic_product_hovered" t-att-data-url="record.website_url">
|
||||
<div t-if="is_sample" class="h5 o_ribbon_right bg-primary text-uppercase">Sample</div>
|
||||
<a class="o_carousel_product_img_link o_dynamic_product_hovered overflow-hidden" t-att-href="record.website_url">
|
||||
<img class="card-img-top h-auto o_img_product_square o_img_product_cover rounded" loading="lazy" t-att-src="data['image_512']" t-att-alt="record.display_name"/>
|
||||
</a>
|
||||
<div class="o_carousel_product_card_body mt-2 d-flex justify-content-between">
|
||||
<t t-if="is_view_active('website_sale.product_comment')" t-call="portal_rating.rating_widget_stars_static">
|
||||
<t t-set="rating_style_compressed" t-value="true"/>
|
||||
<t t-set="rating_avg" t-value="record.rating_avg"/>
|
||||
<t t-set="rating_count" t-value="record.rating_count"/>
|
||||
</t>
|
||||
<div class="ms-auto">
|
||||
<t t-call="website_sale.price_dynamic_filter_template_product_product"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
<template id="dynamic_filter_template_product_product_mini_name" name="Image with name">
|
||||
<t t-foreach="records" t-as="data" data-thumb="/website_sale/static/src/img/snippets_options/product_image_with_name.svg">
|
||||
<t t-set="record" t-value="data['_record']"/>
|
||||
<div class="card h-100 border-0 w-100 rounded-0 bg-transparent o_dynamic_product_hovered" t-att-data-url="record.website_url">
|
||||
<div t-if="is_sample" class="h5 o_ribbon_right bg-primary text-uppercase">Sample</div>
|
||||
<a class="o_carousel_product_img_link overflow-hidden" t-att-href="record.website_url">
|
||||
<img class="card-img-top h-auto o_img_product_square o_img_product_cover rounded" loading="lazy" t-att-src="data['image_512']" t-att-alt="record.display_name"/>
|
||||
</a>
|
||||
<div class="h6 text-center mt-2 p-2" t-field="record.display_name"/>
|
||||
<div class="text-center">
|
||||
<t t-if="is_view_active('website_sale.product_comment')" t-call="portal_rating.rating_widget_stars_static">
|
||||
<t t-set="rating_avg" t-value="record.rating_avg"/>
|
||||
<t t-set="rating_count" t-value="record.rating_count"/>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
<template id="dynamic_filter_template_product_product_centered" name="Centered Product">
|
||||
<t t-foreach="records" t-as="data" data-arrow-position="bottom" data-thumb="/website_sale/static/src/img/snippets_options/product_centered.svg">
|
||||
<t t-set="record" t-value="data['_record']"/>
|
||||
<div class="o_carousel_product_card card w-100" t-att-data-add2cart-rerender="data.get('_add2cart_rerender')">
|
||||
<div t-if="is_sample" class="h5 o_ribbon_right bg-primary text-uppercase">Sample</div>
|
||||
<input type="hidden" name="product-id" t-att-data-product-id="record.id"/>
|
||||
<a class="o_carousel_product_img_link position-absolute mx-auto" t-att-href="record.website_url">
|
||||
<img class="card-img-top" loading="lazy" t-att-src="data['image_512']" t-att-alt="record.display_name"/>
|
||||
</a>
|
||||
<div class="o_carousel_product_card_body card-body d-flex flex-column justify-content-between">
|
||||
<div class="card-title h5 text-center" t-field="record.display_name"/>
|
||||
<div class="text-center">
|
||||
<div class="h5">
|
||||
<t t-call="website_sale.price_dynamic_filter_template_product_product"/>
|
||||
</div>
|
||||
<div class="h6 mb-0">
|
||||
<t t-if="is_view_active('website_sale.product_comment')">
|
||||
<t t-call="portal_rating.rating_widget_stars_static">
|
||||
<t t-set="rating_avg" t-value="record.rating_avg"/>
|
||||
<t t-set="rating_count" t-value="record.rating_count"/>
|
||||
</t>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="o_carousel_product_card_footer d-flex align-items-center justify-content-center pb-4">
|
||||
<a class="btn btn-primary d-block" t-att-href="record.website_url">
|
||||
View Product
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
<template id="dynamic_filter_template_product_product_borderless_1" name="Borderless Product n°1">
|
||||
<t t-foreach="records" t-as="data" data-thumb="/website_sale/static/src/img/snippets_options/product_borderless_1.svg">
|
||||
<t t-set="record" t-value="data['_record']"/>
|
||||
<div class="o_carousel_product_card bg-transparent w-100 card border-0">
|
||||
<div t-if="is_sample" class="h5 o_ribbon_right bg-primary text-uppercase">Sample</div>
|
||||
<input type="hidden" name="product-id" t-att-data-product-id="record.id"/>
|
||||
<a class="o_carousel_product_img_link o_dynamic_product_hovered stretched-link" t-att-href="record.website_url">
|
||||
<div class="overflow-hidden rounded">
|
||||
<img class="card-img-top o_img_product_square o_img_product_cover h-auto" loading="lazy" t-att-src="data['image_512']"
|
||||
t-att-alt="record.display_name"/>
|
||||
</div>
|
||||
</a>
|
||||
<div class="o_carousel_product_card_body d-flex flex-wrap flex-column justify-content-between h-100 p-3">
|
||||
<div class="h6 card-title" t-field="record.display_name"/>
|
||||
<div>
|
||||
<t t-if="is_view_active('website_sale.product_comment')" t-call="portal_rating.rating_widget_stars_static">
|
||||
<t t-set="rating_avg" t-value="record.rating_avg"/>
|
||||
<t t-set="rating_count" t-value="record.rating_count"/>
|
||||
</t>
|
||||
<div class="mt-2">
|
||||
<t t-call="website_sale.price_dynamic_filter_template_product_product"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
<template id="dynamic_filter_template_product_product_borderless_2" name="Borderless Product n°2">
|
||||
<t t-foreach="records" t-as="data" data-thumb="/website_sale/static/src/img/snippets_options/product_borderless_2.svg">
|
||||
<t t-set="record" t-value="data['_record']"/>
|
||||
<div class="o_carousel_product_card card w-100 border-0 bg-transparent" t-att-data-add2cart-rerender="data.get('_add2cart_rerender')">
|
||||
<div t-if="is_sample" class="h5 o_ribbon_right bg-primary text-uppercase">Sample</div>
|
||||
<input type="hidden" name="product-id" t-att-data-product-id="record.id"/>
|
||||
<a class="o_carousel_product_img_link o_dynamic_product_hovered" t-att-href="record.website_url">
|
||||
<div class="overflow-hidden rounded">
|
||||
<img class="card-img-top o_img_product_square o_img_product_cover h-auto" loading="lazy" t-att-src="data['image_512']"
|
||||
t-att-alt="record.display_name"/>
|
||||
</div>
|
||||
</a>
|
||||
<div class="o_carousel_product_card_body h-100 p-3 d-flex flex-column justify-content-between">
|
||||
<div class="d-flex justify-content-between align-items-center flex-wrap mb-2">
|
||||
<div class="h5 mb-0 me-4">
|
||||
<t t-call="website_sale.price_dynamic_filter_template_product_product"/>
|
||||
</div>
|
||||
<div class="h6 mb-0">
|
||||
<t t-if="is_view_active('website_sale.product_comment')">
|
||||
<t t-call="portal_rating.rating_widget_stars_static">
|
||||
<t t-set="rating_style_compressed" t-value="true"/>
|
||||
<t t-set="rating_avg" t-value="record.rating_avg"/>
|
||||
<t t-set="rating_count" t-value="record.rating_count"/>
|
||||
</t>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-title h6 flex-grow-1 w-100 mt-2 mb-3" t-field="record.display_name"/>
|
||||
<div class="text-end o_dynamic_snippet_btn_wrapper" t-if="record._website_show_quick_add()">
|
||||
<button type="button" role="button" class="btn btn-primary js_add_cart w-100" title="Add to Cart">
|
||||
Add to Cart
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
<template id="dynamic_filter_template_product_product_banner" name="Large Banner">
|
||||
<t t-foreach="records" t-as="data" data-number-of-elements="1" data-number-of-elements-sm="1" data-thumb="/website_sale/static/src/img/snippets_options/product_banner.svg">
|
||||
<t t-set="record" t-value="data['_record']"/>
|
||||
<div class="o_carousel_product_card card w-100" t-att-data-add2cart-rerender="data.get('_add2cart_rerender')">
|
||||
<div t-if="is_sample" class="h5 o_ribbon_right bg-primary text-uppercase">Sample</div>
|
||||
<input type="hidden" name="product-id" t-att-data-product-id="record.id"/>
|
||||
<div class="row flex-row-reverse">
|
||||
<div class="col-lg-6 d-flex align-items-center justify-content-center justify-content-lg-end o_wrap_product_img position-relative">
|
||||
<img class="img img-fluid position-absolute o_img_product_cover w-100 h-100" loading="lazy" t-att-src="data['image_512']" t-att-alt="record.display_name"/>
|
||||
</div>
|
||||
<div class="col-lg-6 px-5 d-flex align-items-center">
|
||||
<div class="o_carousel_product_card_body card-body p-5">
|
||||
<div class="card-title h1" t-field="record.display_name"/>
|
||||
<div class="d-flex align-items-center my-4">
|
||||
<div class="h4 mb-0 me-3">
|
||||
<t t-call="website_sale.price_dynamic_filter_template_product_product"/>
|
||||
</div>
|
||||
<t t-if="is_view_active('website_sale.product_comment')" t-call="portal_rating.rating_widget_stars_static">
|
||||
<t t-set="rating_avg" t-value="record.rating_avg"/>
|
||||
<t t-set="rating_count" t-value="record.rating_count"/>
|
||||
</t>
|
||||
</div>
|
||||
<div class="card-text text-muted" t-field="record.description_sale"/>
|
||||
<div class="mt-4">
|
||||
<button t-if="record._website_show_quick_add()" type="button" role="button" class="btn btn-primary js_add_cart mt-1" title="Add to Cart">
|
||||
Add to Cart
|
||||
</button>
|
||||
<a class="btn btn-link me-1 mt-1" t-att-href="record.website_url">
|
||||
View Product
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
<template id="dynamic_filter_template_product_product_horizontal_card" name="Horizontal Card">
|
||||
<t t-foreach="records" t-as="data"
|
||||
data-number-of-elements="3"
|
||||
data-number-of-elements-sm="1"
|
||||
data-row-per-slide="2"
|
||||
data-arrow-position="bottom"
|
||||
data-extra-classes="o_carousel_multiple_rows"
|
||||
data-thumb="/website_sale/static/src/img/snippets_options/product_horizontal_card.svg">
|
||||
<t t-set="record" t-value="data['_record']"/>
|
||||
<div class="o_carousel_product_card card w-100 border-0 bg-light p-3" t-att-data-add2cart-rerender="data.get('_add2cart_rerender')">
|
||||
<div t-if="is_sample" class="h5 o_ribbon_right bg-primary text-uppercase">Sample</div>
|
||||
<input type="hidden" name="product-id" t-att-data-product-id="record.id"/>
|
||||
<div class="row h-100 p-0">
|
||||
<div class="col-lg-4 position-static">
|
||||
<a class="stretched-link o_dynamic_product_hovered" t-att-href="record.website_url">
|
||||
<img class="img img-fluid mx-auto o_img_product_square" loading="lazy" t-att-src="data['image_512']" t-att-alt="record.display_name"/>
|
||||
</a>
|
||||
</div>
|
||||
<div class="o_carousel_product_card_body col-lg-8 d-flex flex-column justify-content-between">
|
||||
<div>
|
||||
<div class="card-title h6" t-field="record.display_name"/>
|
||||
</div>
|
||||
<div>
|
||||
<div class="mb-1">
|
||||
<t t-if="is_view_active('website_sale.product_comment')" t-call="portal_rating.rating_widget_stars_static">
|
||||
<t t-set="rating_avg" t-value="record.rating_avg"/>
|
||||
<t t-set="rating_count" t-value="record.rating_count"/>
|
||||
</t>
|
||||
</div>
|
||||
<div class="d-flex align-items-center flex-wrap">
|
||||
<div class="my-2">
|
||||
<t t-call="website_sale.price_dynamic_filter_template_product_product"/>
|
||||
</div>
|
||||
<div t-if="record._website_show_quick_add()" class="o_dynamic_snippet_btn_wrapper ms-auto">
|
||||
<button type="button" role="button" class="btn btn-primary js_add_cart" title="Add to Cart">
|
||||
<i class="fa fa-fw fa-shopping-cart"/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</template>
|
||||
<template id="dynamic_filter_template_product_product_horizontal_card_2" name="Horizontal Card width covered image">
|
||||
<t t-foreach="records" t-as="data"
|
||||
data-row-per-slide="2"
|
||||
data-arrow-position="bottom"
|
||||
data-number-of-elements="2"
|
||||
data-number-of-elements-sm="1"
|
||||
data-extra-classes="o_carousel_multiple_rows"
|
||||
data-thumb="/website_sale/static/src/img/snippets_options/product_horizontal_card_2.svg">
|
||||
<t t-set="record" t-value="data['_record']"/>
|
||||
<div class="o_carousel_product_card card w-100 border-0 o_dynamic_product_hovered o_cc o_cc5">
|
||||
<div t-if="is_sample" class="h5 o_ribbon_right bg-primary text-uppercase">Sample</div>
|
||||
<input type="hidden" name="product-id" t-att-data-product-id="record.id"/>
|
||||
<a class="stretched-link" t-att-href="record.website_url">
|
||||
<img class="img img-fluid position-absolute w-100 h-100 o_img_product_cover" loading="lazy" t-att-src="data['image_512']" t-att-alt="record.display_name"/>
|
||||
</a>
|
||||
<div class="o_carousel_product_card_body d-flex flex-column justify-content-between h-100 bg-black-50 p-3 position-relative">
|
||||
<div class="mb-3">
|
||||
<div class="card-title h5" t-field="record.display_name"/>
|
||||
<t t-if="is_view_active('website_sale.product_comment')" t-call="portal_rating.rating_widget_stars_static">
|
||||
<t t-set="rating_avg" t-value="record.rating_avg"/>
|
||||
<t t-set="rating_count" t-value="record.rating_count"/>
|
||||
</t>
|
||||
</div>
|
||||
<div class="card-text h6 flex-grow-1" t-field="record.description_sale"/>
|
||||
<div class="d-flex justify-content-between align-items-center flex-wrap mt-3">
|
||||
<div class="h5 mb-0 me-2">
|
||||
<t t-call="website_sale.price_dynamic_filter_template_product_product"/>
|
||||
</div>
|
||||
<div t-if="record._website_show_quick_add()" class="o_dynamic_snippet_btn_wrapper">
|
||||
<button type="button" role="button" class="btn btn-primary js_add_cart" title="Add to Cart">
|
||||
Add to Cart
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
<template id="dynamic_filter_template_product_product_card_group" name="Card group">
|
||||
<t t-foreach="records" t-as="data"
|
||||
data-row-per-slide="2"
|
||||
data-number-of-elements="2"
|
||||
data-number-of-elements-sm="1"
|
||||
data-arrow-position="bottom"
|
||||
data-extra-classes="o_card_group rounded"
|
||||
data-thumb="/website_sale/static/src/img/snippets_options/product_card_group.svg">
|
||||
<t t-set="record" t-value="data['_record']"/>
|
||||
<div class="o_carousel_product_card card w-100 rounded-0 border-top-0 border-start-0" t-att-data-url="record.website_url">
|
||||
<div t-if="is_sample" class="h5 o_ribbon_right bg-primary text-uppercase">Sample</div>
|
||||
<input type="hidden" name="product-id" t-att-data-product-id="record.id"/>
|
||||
<div class="o_carousel_product_card_body card-body justify-content-between h-100 p-3">
|
||||
<div class="row h-100">
|
||||
<div class="col-8 d-flex flex-column">
|
||||
<div class="card-title h5" t-field="record.display_name"/>
|
||||
<div class="card-text h6 text-muted" t-field="record.description_sale"/>
|
||||
<div class="d-flex justify-content-between align-items-center flex-wrap w-100 mt-auto">
|
||||
<div class="h5 text-primary mb-0 me-2">
|
||||
<t t-call="website_sale.price_dynamic_filter_template_product_product"/>
|
||||
</div>
|
||||
<t t-if="is_view_active('website_sale.product_comment')" t-call="portal_rating.rating_widget_stars_static">
|
||||
<t t-set="rating_avg" t-value="record.rating_avg"/>
|
||||
<t t-set="rating_count" t-value="record.rating_count"/>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-4 position-static">
|
||||
<div class="overflow-hidden position-static">
|
||||
<a class="stretched-link o_dynamic_product_hovered" t-att-href="record.website_url">
|
||||
<img class="img img-fluid o_img_product_square o_img_product_cover h-auto" loading="lazy" t-att-src="data['image_512']" t-att-alt="record.display_name"/>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</template>
|
||||
<template id="price_dynamic_filter_template_product_product" name="Dynamic Product Filter Price">
|
||||
<t t-set="record_price" t-value="record._get_contextual_price_tax_selection()"/>
|
||||
<t t-if="not website.prevent_zero_price_sale or record_price">
|
||||
<span t-esc="record_price" class="fw-bold"
|
||||
t-options="{'widget': 'monetary', 'display_currency': website.currency_id}"/>
|
||||
<del t-if="data.get('has_discounted_price')" class="text-danger ms-1 h6" style="white-space: nowrap;"
|
||||
t-esc="data['list_price']"
|
||||
t-options="{'widget': 'monetary', 'display_currency': website.currency_id}"/>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<span t-field="website.prevent_zero_price_sale_text"/>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
<!-- Assets -->
|
||||
<record id="website_sale.s_dynamic_snippet_products_000_scss" model="ir.asset">
|
||||
<field name="name">Dynamic snippet products 000 SCSS</field>
|
||||
<field name="bundle">web.assets_frontend</field>
|
||||
<field name="path">website_sale/static/src/snippets/s_dynamic_snippet_products/000.scss</field>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
4357
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/af.po
Normal file
4357
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/af.po
Normal file
File diff suppressed because it is too large
Load diff
4353
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/am.po
Normal file
4353
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/am.po
Normal file
File diff suppressed because it is too large
Load diff
4588
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/ar.po
Normal file
4588
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/ar.po
Normal file
File diff suppressed because it is too large
Load diff
4554
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/az.po
Normal file
4554
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/az.po
Normal file
File diff suppressed because it is too large
Load diff
4357
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/be.po
Normal file
4357
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/be.po
Normal file
File diff suppressed because it is too large
Load diff
4454
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/bg.po
Normal file
4454
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/bg.po
Normal file
File diff suppressed because it is too large
Load diff
4380
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/bs.po
Normal file
4380
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/bs.po
Normal file
File diff suppressed because one or more lines are too long
4604
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/ca.po
Normal file
4604
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/ca.po
Normal file
File diff suppressed because it is too large
Load diff
4581
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/cs.po
Normal file
4581
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/cs.po
Normal file
File diff suppressed because it is too large
Load diff
4601
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/da.po
Normal file
4601
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/da.po
Normal file
File diff suppressed because it is too large
Load diff
4665
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/de.po
Normal file
4665
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/de.po
Normal file
File diff suppressed because it is too large
Load diff
2717
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/el.po
Normal file
2717
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/el.po
Normal file
File diff suppressed because it is too large
Load diff
2295
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/en_GB.po
Normal file
2295
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/en_GB.po
Normal file
File diff suppressed because it is too large
Load diff
4653
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/es.po
Normal file
4653
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/es.po
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,19 @@
|
|||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server saas~12.5\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2019-08-26 08:17+0000\n"
|
||||
"PO-Revision-Date: 2019-08-26 08:17+0000\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: \n"
|
||||
"Language: es_BO\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Plural-Forms: \n"
|
||||
|
||||
#. module: website_sale
|
||||
#: model_terms:ir.ui.view,arch_db:website_sale.address_b2b
|
||||
msgid "TIN / VAT"
|
||||
msgstr "NIT"
|
||||
2267
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/es_CL.po
Normal file
2267
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/es_CL.po
Normal file
File diff suppressed because it is too large
Load diff
2513
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/es_CO.po
Normal file
2513
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/es_CO.po
Normal file
File diff suppressed because it is too large
Load diff
2274
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/es_CR.po
Normal file
2274
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/es_CR.po
Normal file
File diff suppressed because it is too large
Load diff
2317
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/es_DO.po
Normal file
2317
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/es_DO.po
Normal file
File diff suppressed because it is too large
Load diff
2517
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/es_EC.po
Normal file
2517
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/es_EC.po
Normal file
File diff suppressed because it is too large
Load diff
4652
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/es_MX.po
Normal file
4652
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/es_MX.po
Normal file
File diff suppressed because it is too large
Load diff
2283
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/es_PA.po
Normal file
2283
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/es_PA.po
Normal file
File diff suppressed because it is too large
Load diff
2303
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/es_PE.po
Normal file
2303
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/es_PE.po
Normal file
File diff suppressed because it is too large
Load diff
2267
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/es_PY.po
Normal file
2267
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/es_PY.po
Normal file
File diff suppressed because it is too large
Load diff
2276
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/es_VE.po
Normal file
2276
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/es_VE.po
Normal file
File diff suppressed because it is too large
Load diff
4556
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/et.po
Normal file
4556
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/et.po
Normal file
File diff suppressed because it is too large
Load diff
2269
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/eu.po
Normal file
2269
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/eu.po
Normal file
File diff suppressed because it is too large
Load diff
4586
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/fa.po
Normal file
4586
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/fa.po
Normal file
File diff suppressed because it is too large
Load diff
4624
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/fi.po
Normal file
4624
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/fi.po
Normal file
File diff suppressed because it is too large
Load diff
4655
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/fr.po
Normal file
4655
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/fr.po
Normal file
File diff suppressed because it is too large
Load diff
2270
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/gl.po
Normal file
2270
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/gl.po
Normal file
File diff suppressed because it is too large
Load diff
4358
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/gu.po
Normal file
4358
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/gu.po
Normal file
File diff suppressed because it is too large
Load diff
4449
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/he.po
Normal file
4449
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/he.po
Normal file
File diff suppressed because it is too large
Load diff
4391
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/hi.po
Normal file
4391
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/hi.po
Normal file
File diff suppressed because it is too large
Load diff
4496
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/hr.po
Normal file
4496
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/hr.po
Normal file
File diff suppressed because it is too large
Load diff
4469
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/hu.po
Normal file
4469
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/hu.po
Normal file
File diff suppressed because it is too large
Load diff
4353
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/hy.po
Normal file
4353
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/hy.po
Normal file
File diff suppressed because it is too large
Load diff
4628
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/id.po
Normal file
4628
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/id.po
Normal file
File diff suppressed because it is too large
Load diff
4506
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/is.po
Normal file
4506
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/is.po
Normal file
File diff suppressed because it is too large
Load diff
4644
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/it.po
Normal file
4644
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/it.po
Normal file
File diff suppressed because it is too large
Load diff
4522
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/ja.po
Normal file
4522
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/ja.po
Normal file
File diff suppressed because it is too large
Load diff
2261
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/ka.po
Normal file
2261
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/ka.po
Normal file
File diff suppressed because it is too large
Load diff
2273
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/kab.po
Normal file
2273
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/kab.po
Normal file
File diff suppressed because it is too large
Load diff
4405
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/km.po
Normal file
4405
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/km.po
Normal file
File diff suppressed because it is too large
Load diff
4523
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/ko.po
Normal file
4523
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/ko.po
Normal file
File diff suppressed because it is too large
Load diff
3056
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/lb.po
Normal file
3056
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/lb.po
Normal file
File diff suppressed because it is too large
Load diff
4380
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/lo.po
Normal file
4380
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/lo.po
Normal file
File diff suppressed because it is too large
Load diff
4498
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/lt.po
Normal file
4498
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/lt.po
Normal file
File diff suppressed because it is too large
Load diff
4557
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/lv.po
Normal file
4557
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/lv.po
Normal file
File diff suppressed because it is too large
Load diff
2335
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/mk.po
Normal file
2335
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/mk.po
Normal file
File diff suppressed because it is too large
Load diff
4365
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/ml.po
Normal file
4365
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/ml.po
Normal file
File diff suppressed because it is too large
Load diff
4509
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/mn.po
Normal file
4509
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/mn.po
Normal file
File diff suppressed because it is too large
Load diff
4358
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/ms.po
Normal file
4358
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/ms.po
Normal file
File diff suppressed because it is too large
Load diff
4474
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/nb.po
Normal file
4474
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/nb.po
Normal file
File diff suppressed because it is too large
Load diff
4642
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/nl.po
Normal file
4642
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/nl.po
Normal file
File diff suppressed because it is too large
Load diff
4353
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/no.po
Normal file
4353
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/no.po
Normal file
File diff suppressed because it is too large
Load diff
4658
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/pl.po
Normal file
4658
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/pl.po
Normal file
File diff suppressed because it is too large
Load diff
4648
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/pt.po
Normal file
4648
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/pt.po
Normal file
File diff suppressed because it is too large
Load diff
4625
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/pt_BR.po
Normal file
4625
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/pt_BR.po
Normal file
File diff suppressed because it is too large
Load diff
4623
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/ro.po
Normal file
4623
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/ro.po
Normal file
File diff suppressed because it is too large
Load diff
4600
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/ru.po
Normal file
4600
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/ru.po
Normal file
File diff suppressed because it is too large
Load diff
4424
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/sk.po
Normal file
4424
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/sk.po
Normal file
File diff suppressed because it is too large
Load diff
4566
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/sl.po
Normal file
4566
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/sl.po
Normal file
File diff suppressed because it is too large
Load diff
4353
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/sq.po
Normal file
4353
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/sq.po
Normal file
File diff suppressed because it is too large
Load diff
4596
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/sr.po
Normal file
4596
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/sr.po
Normal file
File diff suppressed because it is too large
Load diff
3623
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/sr@latin.po
Normal file
3623
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/sr@latin.po
Normal file
File diff suppressed because it is too large
Load diff
4597
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/sv.po
Normal file
4597
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/sv.po
Normal file
File diff suppressed because it is too large
Load diff
4353
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/sw.po
Normal file
4353
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/sw.po
Normal file
File diff suppressed because it is too large
Load diff
4353
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/ta.po
Normal file
4353
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/ta.po
Normal file
File diff suppressed because it is too large
Load diff
4548
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/th.po
Normal file
4548
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/th.po
Normal file
File diff suppressed because it is too large
Load diff
4621
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/tr.po
Normal file
4621
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/tr.po
Normal file
File diff suppressed because it is too large
Load diff
4617
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/uk.po
Normal file
4617
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/uk.po
Normal file
File diff suppressed because it is too large
Load diff
4597
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/vi.po
Normal file
4597
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/vi.po
Normal file
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
4522
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/zh_CN.po
Normal file
4522
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/zh_CN.po
Normal file
File diff suppressed because it is too large
Load diff
4512
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/zh_TW.po
Normal file
4512
odoo-bringout-oca-ocb-website_sale/website_sale/i18n/zh_TW.po
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,26 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import account_move
|
||||
from . import crm_team
|
||||
from . import digest
|
||||
from . import ir_http
|
||||
from . import payment_provider
|
||||
from . import product_attribute
|
||||
from . import product_image
|
||||
from . import product_pricelist
|
||||
from . import product_product
|
||||
from . import product_public_category
|
||||
from . import product_ribbon
|
||||
from . import product_tag
|
||||
from . import product_template
|
||||
from . import res_company
|
||||
from . import res_config_settings
|
||||
from . import res_country
|
||||
from . import res_partner
|
||||
from . import sale_order
|
||||
from . import sale_order_line
|
||||
from . import website
|
||||
from . import website_base_unit
|
||||
from . import website_snippet_filter
|
||||
from . import website_visitor
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import api, fields, models
|
||||
from odoo.tools.sql import column_exists, create_column
|
||||
|
||||
|
||||
class AccountMove(models.Model):
|
||||
_inherit = 'account.move'
|
||||
|
||||
website_id = fields.Many2one(
|
||||
'website', compute='_compute_website_id', string='Website',
|
||||
help='Website through which this invoice was created for eCommerce orders.',
|
||||
store=True, readonly=True, tracking=True)
|
||||
|
||||
def _auto_init(self):
|
||||
if not column_exists(self.env.cr, "account_move", "website_id"):
|
||||
# Creating the column via `_auto_init` prevents a MemoryError in databases where many
|
||||
# invoices exist when `website_sale` is installed, as it skips the computation of the
|
||||
# `website_id` field.
|
||||
create_column(self.env.cr, "account_move", "website_id", "int4")
|
||||
super()._auto_init()
|
||||
|
||||
def preview_invoice(self):
|
||||
action = super().preview_invoice()
|
||||
if action['url'].startswith('/'):
|
||||
# URL should always be relative, safety check
|
||||
action['url'] = f'/@{action["url"]}'
|
||||
return action
|
||||
|
||||
@api.depends('partner_id') # Dummy depends to trigger compute, will be dropped in master
|
||||
def _compute_website_id(self):
|
||||
for move in self:
|
||||
source_websites = move.line_ids.sale_line_ids.order_id.website_id
|
||||
if len(source_websites) == 1:
|
||||
move.website_id = source_websites
|
||||
else:
|
||||
move.website_id = False
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from datetime import datetime
|
||||
from dateutil.relativedelta import relativedelta
|
||||
|
||||
from odoo import fields,api, models, _
|
||||
from odoo.exceptions import UserError, ValidationError
|
||||
|
||||
|
||||
class CrmTeam(models.Model):
|
||||
_inherit = "crm.team"
|
||||
|
||||
website_ids = fields.One2many('website', 'salesteam_id', string='Websites')
|
||||
abandoned_carts_count = fields.Integer(
|
||||
compute='_compute_abandoned_carts',
|
||||
string='Number of Abandoned Carts', readonly=True)
|
||||
abandoned_carts_amount = fields.Integer(
|
||||
compute='_compute_abandoned_carts',
|
||||
string='Amount of Abandoned Carts', readonly=True)
|
||||
|
||||
def _compute_abandoned_carts(self):
|
||||
# abandoned carts to recover are draft sales orders that have no order lines,
|
||||
# a partner other than the public user, and created over an hour ago
|
||||
# and the recovery mail was not yet sent
|
||||
counts = {}
|
||||
amounts = {}
|
||||
website_teams = self.filtered(lambda team: team.website_ids)
|
||||
if website_teams:
|
||||
abandoned_carts_data = self.env['sale.order']._read_group([
|
||||
('is_abandoned_cart', '=', True),
|
||||
('cart_recovery_email_sent', '=', False),
|
||||
('team_id', 'in', website_teams.ids),
|
||||
], ['amount_total', 'team_id'], ['team_id'])
|
||||
counts = {data['team_id'][0]: data['team_id_count'] for data in abandoned_carts_data}
|
||||
amounts = {data['team_id'][0]: data['amount_total'] for data in abandoned_carts_data}
|
||||
for team in self:
|
||||
team.abandoned_carts_count = counts.get(team.id, 0)
|
||||
team.abandoned_carts_amount = amounts.get(team.id, 0)
|
||||
|
||||
def get_abandoned_carts(self):
|
||||
self.ensure_one()
|
||||
return {
|
||||
'name': _('Abandoned Carts'),
|
||||
'type': 'ir.actions.act_window',
|
||||
'view_mode': 'tree,form',
|
||||
'domain': [('is_abandoned_cart', '=', True)],
|
||||
'search_view_id': [self.env.ref('sale.sale_order_view_search_inherit_sale').id],
|
||||
'context': {
|
||||
'search_default_team_id': self.id,
|
||||
'default_team_id': self.id,
|
||||
'search_default_recovery_email': 1,
|
||||
'create': False
|
||||
},
|
||||
'res_model': 'sale.order',
|
||||
'help': _('''<p class="o_view_nocontent_smiling_face">
|
||||
You can find all abandoned carts here, i.e. the carts generated by your website's visitors from over an hour ago that haven't been confirmed yet.</p>
|
||||
<p>You should send an email to the customers to encourage them!</p>
|
||||
'''),
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import fields, models, _
|
||||
from odoo.exceptions import AccessError
|
||||
|
||||
|
||||
class Digest(models.Model):
|
||||
_inherit = 'digest.digest'
|
||||
|
||||
kpi_website_sale_total = fields.Boolean('eCommerce Sales')
|
||||
kpi_website_sale_total_value = fields.Monetary(compute='_compute_kpi_website_sale_total_value')
|
||||
|
||||
def _compute_kpi_website_sale_total_value(self):
|
||||
if not self.env.user.has_group('sales_team.group_sale_salesman_all_leads'):
|
||||
raise AccessError(_("Do not have access, skip this data for user's digest email"))
|
||||
for record in self:
|
||||
start, end, company = record._get_kpi_compute_parameters()
|
||||
confirmed_website_sales = self.env['sale.order'].search([
|
||||
('date_order', '>=', start),
|
||||
('date_order', '<', end),
|
||||
('state', 'not in', ['draft', 'cancel', 'sent']),
|
||||
('website_id', '!=', False),
|
||||
('company_id', '=', company.id)
|
||||
])
|
||||
record.kpi_website_sale_total_value = sum(
|
||||
sale.currency_id._convert(sale.amount_total, company.currency_id, company, sale.date_order)
|
||||
for sale in confirmed_website_sales
|
||||
)
|
||||
|
||||
def _compute_kpis_actions(self, company, user):
|
||||
res = super(Digest, self)._compute_kpis_actions(company, user)
|
||||
res['kpi_website_sale_total'] = 'website.backend_dashboard&menu_id=%s' % self.env.ref('website.menu_website_configuration').id
|
||||
return res
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
from odoo import models
|
||||
from odoo.http import request
|
||||
|
||||
|
||||
class IrHttp(models.AbstractModel):
|
||||
_inherit = 'ir.http'
|
||||
|
||||
@classmethod
|
||||
def _pre_dispatch(cls, rule, args):
|
||||
super()._pre_dispatch(rule, args)
|
||||
affiliate_id = request.httprequest.args.get('affiliate_id')
|
||||
if affiliate_id:
|
||||
request.session['affiliate_id'] = int(affiliate_id)
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import api, models
|
||||
|
||||
|
||||
class PaymentProvider(models.Model):
|
||||
_inherit = 'payment.provider'
|
||||
|
||||
@api.model
|
||||
def _get_compatible_providers(self, *args, website_id=None, **kwargs):
|
||||
""" Override of payment to only return providers matching website-specific criteria.
|
||||
|
||||
In addition to the base criteria, the website must either not be set or be the same as the
|
||||
one provided in the kwargs.
|
||||
|
||||
:param int website_id: The provided website, as a `website` id
|
||||
:return: The compatible providers
|
||||
:rtype: recordset of `payment.provider`
|
||||
"""
|
||||
providers = super()._get_compatible_providers(*args, website_id=website_id, **kwargs)
|
||||
if website_id:
|
||||
providers = providers.filtered(
|
||||
lambda p: not p.website_id or p.website_id.id == website_id
|
||||
)
|
||||
return providers
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from collections import OrderedDict
|
||||
|
||||
from odoo import models, fields
|
||||
|
||||
|
||||
class ProductAttribute(models.Model):
|
||||
_inherit = 'product.attribute'
|
||||
|
||||
visibility = fields.Selection([('visible', 'Visible'), ('hidden', 'Hidden')], default='visible')
|
||||
|
||||
|
||||
class ProductTemplateAttributeLine(models.Model):
|
||||
_inherit = 'product.template.attribute.line'
|
||||
|
||||
def _prepare_single_value_for_display(self):
|
||||
"""On the product page group together the attribute lines that concern
|
||||
the same attribute and that have only one value each.
|
||||
|
||||
Indeed those are considered informative values, they do not generate
|
||||
choice for the user, so they are displayed below the configurator.
|
||||
|
||||
The returned attributes are ordered as they appear in `self`, so based
|
||||
on the order of the attribute lines.
|
||||
"""
|
||||
single_value_lines = self.filtered(lambda ptal: len(ptal.value_ids) == 1)
|
||||
single_value_attributes = OrderedDict([(pa, self.env['product.template.attribute.line']) for pa in single_value_lines.attribute_id])
|
||||
for ptal in single_value_lines:
|
||||
single_value_attributes[ptal.attribute_id] |= ptal
|
||||
return single_value_attributes
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import base64
|
||||
|
||||
from odoo import api, fields, models, tools, _
|
||||
from odoo.exceptions import ValidationError
|
||||
|
||||
from odoo.addons.web_editor.tools import get_video_embed_code, get_video_thumbnail
|
||||
|
||||
|
||||
class ProductImage(models.Model):
|
||||
_name = 'product.image'
|
||||
_description = "Product Image"
|
||||
_inherit = ['image.mixin']
|
||||
_order = 'sequence, id'
|
||||
|
||||
name = fields.Char("Name", required=True)
|
||||
sequence = fields.Integer(default=10)
|
||||
|
||||
image_1920 = fields.Image()
|
||||
|
||||
product_tmpl_id = fields.Many2one('product.template', "Product Template", index=True, ondelete='cascade')
|
||||
product_variant_id = fields.Many2one('product.product', "Product Variant", index=True, ondelete='cascade')
|
||||
video_url = fields.Char('Video URL',
|
||||
help='URL of a video for showcasing your product.')
|
||||
embed_code = fields.Html(compute="_compute_embed_code", sanitize=False)
|
||||
|
||||
can_image_1024_be_zoomed = fields.Boolean("Can Image 1024 be zoomed", compute='_compute_can_image_1024_be_zoomed', store=True)
|
||||
|
||||
@api.depends('image_1920', 'image_1024')
|
||||
def _compute_can_image_1024_be_zoomed(self):
|
||||
for image in self:
|
||||
image.can_image_1024_be_zoomed = image.image_1920 and tools.is_image_size_above(image.image_1920, image.image_1024)
|
||||
|
||||
@api.onchange('video_url')
|
||||
def _onchange_video_url(self):
|
||||
if not self.image_1920:
|
||||
thumbnail = get_video_thumbnail(self.video_url)
|
||||
self.image_1920 = thumbnail and base64.b64encode(thumbnail) or False
|
||||
|
||||
@api.depends('video_url')
|
||||
def _compute_embed_code(self):
|
||||
for image in self:
|
||||
image.embed_code = get_video_embed_code(image.video_url) or False
|
||||
|
||||
@api.constrains('video_url')
|
||||
def _check_valid_video_url(self):
|
||||
for image in self:
|
||||
if image.video_url and not image.embed_code:
|
||||
raise ValidationError(_("Provided video URL for '%s' is not valid. Please enter a valid video URL.", image.name))
|
||||
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
"""
|
||||
We don't want the default_product_tmpl_id from the context
|
||||
to be applied if we have a product_variant_id set to avoid
|
||||
having the variant images to show also as template images.
|
||||
But we want it if we don't have a product_variant_id set.
|
||||
"""
|
||||
context_without_template = self.with_context({k: v for k, v in self.env.context.items() if k != 'default_product_tmpl_id'})
|
||||
normal_vals = []
|
||||
variant_vals_list = []
|
||||
|
||||
for vals in vals_list:
|
||||
if vals.get('product_variant_id') and 'default_product_tmpl_id' in self.env.context:
|
||||
variant_vals_list.append(vals)
|
||||
else:
|
||||
normal_vals.append(vals)
|
||||
|
||||
return super().create(normal_vals) + super(ProductImage, context_without_template).create(variant_vals_list)
|
||||
|
|
@ -0,0 +1,115 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import api, fields, models, _
|
||||
from odoo.exceptions import ValidationError, UserError
|
||||
from odoo.addons.website.models import ir_http
|
||||
|
||||
|
||||
class ProductPricelist(models.Model):
|
||||
_inherit = "product.pricelist"
|
||||
|
||||
def _default_website(self):
|
||||
""" Find the first company's website, if there is one. """
|
||||
company_id = self.env.company.id
|
||||
|
||||
if self._context.get('default_company_id'):
|
||||
company_id = self._context.get('default_company_id')
|
||||
|
||||
domain = [('company_id', '=', company_id)]
|
||||
return self.env['website'].search(domain, limit=1)
|
||||
|
||||
website_id = fields.Many2one('website', string="Website", ondelete='restrict', default=_default_website, domain="[('company_id', '=?', company_id)]")
|
||||
code = fields.Char(string='E-commerce Promotional Code', groups="base.group_user")
|
||||
selectable = fields.Boolean(help="Allow the end user to choose this price list")
|
||||
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
for vals in vals_list:
|
||||
if vals.get('company_id') and not vals.get('website_id'):
|
||||
# l10n modules install will change the company currency, creating a
|
||||
# pricelist for that currency. Do not use user's company in that
|
||||
# case as module install are done with OdooBot (company 1)
|
||||
# YTI FIXME: The fix is not at the correct place
|
||||
# It be set when we actually create the pricelist
|
||||
self = self.with_context(default_company_id=vals['company_id'])
|
||||
pricelists = super().create(vals_list)
|
||||
pricelists and pricelists.clear_caches()
|
||||
return pricelists
|
||||
|
||||
def write(self, data):
|
||||
res = super(ProductPricelist, self).write(data)
|
||||
if data.keys() & {'code', 'active', 'website_id', 'selectable', 'company_id'}:
|
||||
self._check_website_pricelist()
|
||||
self and self.clear_caches()
|
||||
return res
|
||||
|
||||
def unlink(self):
|
||||
res = super(ProductPricelist, self).unlink()
|
||||
self._check_website_pricelist()
|
||||
self and self.clear_caches()
|
||||
return res
|
||||
|
||||
def _get_partner_pricelist_multi_search_domain_hook(self, company_id):
|
||||
domain = super()._get_partner_pricelist_multi_search_domain_hook(company_id)
|
||||
website = ir_http.get_request_website()
|
||||
if website:
|
||||
domain += self._get_website_pricelists_domain(website)
|
||||
return domain
|
||||
|
||||
def _get_partner_pricelist_multi_filter_hook(self):
|
||||
res = super()._get_partner_pricelist_multi_filter_hook()
|
||||
website = ir_http.get_request_website()
|
||||
if website:
|
||||
res = res.filtered(lambda pl: pl._is_available_on_website(website))
|
||||
return res
|
||||
|
||||
def _check_website_pricelist(self):
|
||||
for website in self.env['website'].search([]):
|
||||
# sudo() to be able to read pricelists/website from another company
|
||||
if not website.sudo().pricelist_ids:
|
||||
raise UserError(_("With this action, '%s' website would not have any pricelist available.") % (website.name))
|
||||
|
||||
def _is_available_on_website(self, website):
|
||||
""" To be able to be used on a website, a pricelist should either:
|
||||
- Have its `website_id` set to current website (specific pricelist).
|
||||
- Have no `website_id` set and should be `selectable` (generic pricelist)
|
||||
or should have a `code` (generic promotion).
|
||||
- Have no `company_id` or a `company_id` matching its website one.
|
||||
|
||||
Note: A pricelist without a website_id, not selectable and without a
|
||||
code is a backend pricelist.
|
||||
|
||||
Change in this method should be reflected in `_get_website_pricelists_domain`.
|
||||
"""
|
||||
self.ensure_one()
|
||||
if self.company_id and self.company_id != website.company_id:
|
||||
return False
|
||||
return self.website_id.id == website.id or (not self.website_id and (self.selectable or self.sudo().code))
|
||||
|
||||
def _is_available_in_country(self, country_code):
|
||||
self.ensure_one()
|
||||
if not country_code or not self.country_group_ids:
|
||||
return True
|
||||
return country_code in self.country_group_ids.country_ids.mapped('code')
|
||||
|
||||
def _get_website_pricelists_domain(self, website):
|
||||
''' Check above `_is_available_on_website` for explanation.
|
||||
Change in this method should be reflected in `_is_available_on_website`.
|
||||
'''
|
||||
return [
|
||||
('active', '=', True),
|
||||
('company_id', 'in', [False, website.company_id.id]),
|
||||
'|', ('website_id', '=', website.id),
|
||||
'&', ('website_id', '=', False),
|
||||
'|', ('selectable', '=', True), ('code', '!=', False),
|
||||
]
|
||||
|
||||
@api.constrains('company_id', 'website_id')
|
||||
def _check_websites_in_company(self):
|
||||
'''Prevent misconfiguration multi-website/multi-companies.
|
||||
If the record has a company, the website should be from that company.
|
||||
'''
|
||||
for record in self.filtered(lambda pl: pl.website_id and pl.company_id):
|
||||
if record.website_id.company_id != record.company_id:
|
||||
raise ValidationError(_("""Only the company's websites are allowed.\nLeave the Company field empty or select a website from that company."""))
|
||||
|
|
@ -0,0 +1,104 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import api, fields, models, _
|
||||
from odoo.exceptions import ValidationError
|
||||
|
||||
|
||||
class Product(models.Model):
|
||||
_inherit = "product.product"
|
||||
_mail_post_access = 'read'
|
||||
|
||||
website_id = fields.Many2one(related='product_tmpl_id.website_id', readonly=False)
|
||||
|
||||
product_variant_image_ids = fields.One2many('product.image', 'product_variant_id', string="Extra Variant Images")
|
||||
|
||||
website_url = fields.Char('Website URL', compute='_compute_product_website_url', help='The full URL to access the document through the website.')
|
||||
|
||||
base_unit_count = fields.Float('Base Unit Count', required=True, default=1, help="Display base unit price on your eCommerce pages. Set to 0 to hide it for this product.")
|
||||
base_unit_id = fields.Many2one('website.base.unit', string='Custom Unit of Measure', help="Define a custom unit to display in the price per unit of measure field.")
|
||||
base_unit_price = fields.Monetary("Price Per Unit", currency_field="currency_id", compute="_compute_base_unit_price")
|
||||
base_unit_name = fields.Char(compute='_compute_base_unit_name', help='Displays the custom unit for the products if defined or the selected unit of measure otherwise.')
|
||||
|
||||
def _get_base_unit_price(self, price):
|
||||
self.ensure_one()
|
||||
return self.base_unit_count and price / self.base_unit_count
|
||||
|
||||
@api.depends('lst_price', 'base_unit_count')
|
||||
def _compute_base_unit_price(self):
|
||||
for product in self:
|
||||
if not product.id:
|
||||
product.base_unit_price = 0
|
||||
else:
|
||||
product.base_unit_price = product._get_base_unit_price(product.lst_price)
|
||||
|
||||
@api.depends('uom_name', 'base_unit_id')
|
||||
def _compute_base_unit_name(self):
|
||||
for product in self:
|
||||
product.base_unit_name = product.base_unit_id.name or product.uom_name
|
||||
|
||||
@api.constrains('base_unit_count')
|
||||
def _check_base_unit_count(self):
|
||||
if any(product.base_unit_count < 0 for product in self):
|
||||
raise ValidationError(_('The value of Base Unit Count must be greater than 0. Use 0 to hide the price per unit on this product.'))
|
||||
|
||||
@api.depends_context('lang')
|
||||
@api.depends('product_tmpl_id.website_url', 'product_template_attribute_value_ids')
|
||||
def _compute_product_website_url(self):
|
||||
for product in self:
|
||||
attributes = ','.join(str(x) for x in product.product_template_attribute_value_ids.ids)
|
||||
product.website_url = "%s#attr=%s" % (product.product_tmpl_id.website_url, attributes)
|
||||
|
||||
def _prepare_variant_values(self, combination):
|
||||
variant_dict = super()._prepare_variant_values(combination)
|
||||
variant_dict['base_unit_count'] = self.base_unit_count
|
||||
return variant_dict
|
||||
|
||||
def website_publish_button(self):
|
||||
self.ensure_one()
|
||||
return self.product_tmpl_id.website_publish_button()
|
||||
|
||||
def open_website_url(self):
|
||||
self.ensure_one()
|
||||
res = self.product_tmpl_id.open_website_url()
|
||||
res['url'] = self.website_url
|
||||
return res
|
||||
|
||||
def _get_images(self):
|
||||
"""Return a list of records implementing `image.mixin` to
|
||||
display on the carousel on the website for this variant.
|
||||
|
||||
This returns a list and not a recordset because the records might be
|
||||
from different models (template, variant and image).
|
||||
|
||||
It contains in this order: the main image of the variant (which will fall back on the main
|
||||
image of the template, if unset), the Variant Extra Images, and the Template Extra Images.
|
||||
"""
|
||||
self.ensure_one()
|
||||
variant_images = list(self.product_variant_image_ids)
|
||||
template_images = list(self.product_tmpl_id.product_template_image_ids)
|
||||
return [self] + variant_images + template_images
|
||||
|
||||
|
||||
def _website_show_quick_add(self):
|
||||
website = self.env['website'].get_current_website()
|
||||
return self.sale_ok and (not website.prevent_zero_price_sale or self._get_contextual_price())
|
||||
|
||||
def _is_add_to_cart_allowed(self):
|
||||
self.ensure_one()
|
||||
return self.user_has_groups('base.group_system') or (self.active and self.sale_ok and self.website_published)
|
||||
|
||||
def _get_contextual_price_tax_selection(self):
|
||||
self.ensure_one()
|
||||
fpos_id = self.env['website'].sudo()._get_current_fiscal_position_id(self.env.user.partner_id)
|
||||
fiscal_position_sudo = self.env['account.fiscal.position'].sudo().browse(fpos_id)
|
||||
product_taxes = self.sudo().taxes_id.filtered(lambda x: x.company_id == self.env.company)
|
||||
return self.env['product.template']._price_with_tax_computed(
|
||||
self._get_contextual_price(),
|
||||
product_taxes,
|
||||
fiscal_position_sudo.map_tax(product_taxes),
|
||||
self.env.company.id,
|
||||
self.env['product.template']._get_contextual_pricelist(),
|
||||
self,
|
||||
self.env.user.partner_id,
|
||||
)
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import api, fields, models, _
|
||||
from odoo.tools.translate import html_translate
|
||||
|
||||
|
||||
class ProductPublicCategory(models.Model):
|
||||
_name = "product.public.category"
|
||||
_inherit = [
|
||||
'website.seo.metadata',
|
||||
'website.multi.mixin',
|
||||
'website.searchable.mixin',
|
||||
'image.mixin',
|
||||
]
|
||||
_description = "Website Product Category"
|
||||
_parent_store = True
|
||||
_order = "sequence, name, id"
|
||||
|
||||
def _default_sequence(self):
|
||||
cat = self.search([], limit=1, order="sequence DESC")
|
||||
if cat:
|
||||
return cat.sequence + 5
|
||||
return 10000
|
||||
|
||||
name = fields.Char(required=True, translate=True)
|
||||
parent_id = fields.Many2one('product.public.category', string='Parent Category', index=True, ondelete="cascade")
|
||||
parent_path = fields.Char(index=True, unaccent=False)
|
||||
child_id = fields.One2many('product.public.category', 'parent_id', string='Children Categories')
|
||||
parents_and_self = fields.Many2many('product.public.category', compute='_compute_parents_and_self')
|
||||
sequence = fields.Integer(help="Gives the sequence order when displaying a list of product categories.", index=True, default=_default_sequence)
|
||||
website_description = fields.Html('Category Description', sanitize_overridable=True, sanitize_attributes=False, translate=html_translate, sanitize_form=False)
|
||||
product_tmpl_ids = fields.Many2many('product.template', relation='product_public_category_product_template_rel')
|
||||
|
||||
@api.constrains('parent_id')
|
||||
def check_parent_id(self):
|
||||
if not self._check_recursion():
|
||||
raise ValueError(_('Error ! You cannot create recursive categories.'))
|
||||
|
||||
def name_get(self):
|
||||
res = []
|
||||
for category in self:
|
||||
res.append((category.id, " / ".join(category.parents_and_self.mapped('name'))))
|
||||
return res
|
||||
|
||||
def _compute_parents_and_self(self):
|
||||
for category in self:
|
||||
if category.parent_path:
|
||||
category.parents_and_self = self.env['product.public.category'].browse([int(p) for p in category.parent_path.split('/')[:-1]])
|
||||
else:
|
||||
category.parents_and_self = category
|
||||
|
||||
@api.model
|
||||
def _search_get_detail(self, website, order, options):
|
||||
with_description = options['displayDescription']
|
||||
search_fields = ['name']
|
||||
fetch_fields = ['id', 'name']
|
||||
mapping = {
|
||||
'name': {'name': 'name', 'type': 'text', 'match': True},
|
||||
'website_url': {'name': 'url', 'type': 'text', 'truncate': False},
|
||||
}
|
||||
if with_description:
|
||||
search_fields.append('website_description')
|
||||
fetch_fields.append('website_description')
|
||||
mapping['description'] = {'name': 'website_description', 'type': 'text', 'match': True, 'html': True}
|
||||
return {
|
||||
'model': 'product.public.category',
|
||||
'base_domain': [website.website_domain()],
|
||||
'search_fields': search_fields,
|
||||
'fetch_fields': fetch_fields,
|
||||
'mapping': mapping,
|
||||
'icon': 'fa-folder-o',
|
||||
'order': 'name desc, id desc' if 'name desc' in order else 'name asc, id desc',
|
||||
}
|
||||
|
||||
def _search_render_results(self, fetch_fields, mapping, icon, limit):
|
||||
results_data = super()._search_render_results(fetch_fields, mapping, icon, limit)
|
||||
for data in results_data:
|
||||
data['url'] = '/shop/category/%s' % data['id']
|
||||
return results_data
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue