Initial commit: Sale packages

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

View file

@ -0,0 +1,49 @@
# eCommerce
Odoo addon: website_sale
## Installation
```bash
pip install odoo-bringout-oca-ocb-website_sale
```
## Dependencies
This addon depends on:
- website
- sale
- website_payment
- website_mail
- portal_rating
- digest
## Manifest Information
- **Name**: eCommerce
- **Version**: 1.1
- **Category**: Website/Website
- **License**: LGPL-3
- **Installable**: True
## Source
Based on [OCA/OCB](https://github.com/OCA/OCB) branch 16.0, addon `website_sale`.
## License
This package maintains the original LGPL-3 license from the upstream Odoo project.
## Documentation
- Overview: doc/OVERVIEW.md
- Architecture: doc/ARCHITECTURE.md
- Models: doc/MODELS.md
- Controllers: doc/CONTROLLERS.md
- Wizards: doc/WIZARDS.md
- Install: doc/INSTALL.md
- Usage: doc/USAGE.md
- Configuration: doc/CONFIGURATION.md
- Dependencies: doc/DEPENDENCIES.md
- Troubleshooting: doc/TROUBLESHOOTING.md
- FAQ: doc/FAQ.md

View file

@ -0,0 +1,32 @@
# Architecture
```mermaid
flowchart TD
U[Users] -->|HTTP| V[Views and QWeb Templates]
V --> C[Controllers]
V --> W[Wizards Transient Models]
C --> M[Models and ORM]
W --> M
M --> R[Reports]
DX[Data XML] --> M
S[Security ACLs and Groups] -. enforces .-> M
subgraph Website_sale Module - website_sale
direction LR
M:::layer
W:::layer
C:::layer
V:::layer
R:::layer
S:::layer
DX:::layer
end
classDef layer fill:#eef8ff,stroke:#6ea8fe,stroke-width:1px
```
Notes
- Views include tree/form/kanban templates and report templates.
- Controllers provide website/portal routes when present.
- Wizards are UI flows implemented with `models.TransientModel`.
- Data XML loads data/demo records; Security defines groups and access.

View file

@ -0,0 +1,3 @@
# Configuration
Refer to Odoo settings for website_sale. Configure related models, access rights, and options as needed.

View file

@ -0,0 +1,17 @@
# Controllers
HTTP routes provided by this module.
```mermaid
sequenceDiagram
participant U as User/Client
participant C as Module Controllers
participant O as ORM/Views
U->>C: HTTP GET/POST (routes)
C->>O: ORM operations, render templates
O-->>U: HTML/JSON/PDF
```
Notes
- See files in controllers/ for route definitions.

View file

@ -0,0 +1,10 @@
# Dependencies
This addon depends on:
- [website](../../odoo-bringout-oca-ocb-website)
- [sale](../../odoo-bringout-oca-ocb-sale)
- [website_payment](../../odoo-bringout-oca-ocb-website_payment)
- [website_mail](../../odoo-bringout-oca-ocb-website_mail)
- [portal_rating](../../odoo-bringout-oca-ocb-portal_rating)
- [digest](../../odoo-bringout-oca-ocb-digest)

View file

@ -0,0 +1,4 @@
# FAQ
- Q: Which Odoo version? A: 16.0 (OCA/OCB packaged).
- Q: How to enable? A: Start server with --addon website_sale or install in UI.

View file

@ -0,0 +1,7 @@
# Install
```bash
pip install odoo-bringout-oca-ocb-website_sale"
# or
uv pip install odoo-bringout-oca-ocb-website_sale"
```

View file

@ -0,0 +1,37 @@
# Models
Detected core models and extensions in website_sale.
```mermaid
classDiagram
class product_image
class product_public_category
class product_ribbon
class product_tag
class product_template
class website_base_unit
class website_sale_extra_field
class account_move
class crm_team
class digest_digest
class ir_http
class payment_provider
class product_attribute
class product_pricelist
class product_product
class product_template_attribute_line
class res_company
class res_config_settings
class res_country
class res_partner
class sale_order
class sale_order_line
class website
class website_snippet_filter
class website_track
class website_visitor
```
Notes
- Classes show model technical names; fields omitted for brevity.
- Items listed under _inherit are extensions of existing models.

View file

@ -0,0 +1,6 @@
# Overview
Packaged Odoo addon: website_sale. Provides features documented in upstream Odoo 16 under this addon.
- Source: OCA/OCB 16.0, addon website_sale
- License: LGPL-3

View file

@ -0,0 +1,25 @@
# Reports
Report definitions and templates in website_sale.
```mermaid
classDiagram
class SaleReport
Model <|-- SaleReport
```
## Available Reports
No named reports found in XML files.
## Report Files
- **__init__.py** (Python logic)
- **sale_report.py** (Python logic)
## Notes
- Named reports above are accessible through Odoo's reporting menu
- Python files define report logic and data processing
- XML files contain report templates, definitions, and formatting
- Reports are integrated with Odoo's printing and email systems

View file

@ -0,0 +1,42 @@
# Security
Access control and security definitions in website_sale.
## Access Control Lists (ACLs)
Model access permissions defined in:
- **[ir.model.access.csv](../website_sale/security/ir.model.access.csv)**
- 26 model access rules
## Record Rules
Row-level security rules defined in:
## Security Groups & Configuration
Security groups and permissions defined in:
- **[website_sale.xml](../website_sale/security/website_sale.xml)**
- 6 security groups defined
```mermaid
graph TB
subgraph "Security Layers"
A[Users] --> B[Groups]
B --> C[Access Control Lists]
C --> D[Models]
B --> E[Record Rules]
E --> F[Individual Records]
end
```
Security files overview:
- **[ir.model.access.csv](../website_sale/security/ir.model.access.csv)**
- Model access permissions (CRUD rights)
- **[website_sale.xml](../website_sale/security/website_sale.xml)**
- Security groups, categories, and XML-based rules
Notes
- Access Control Lists define which groups can access which models
- Record Rules provide row-level security (filter records by user/group)
- Security groups organize users and define permission sets
- All security is enforced at the ORM level by Odoo

View file

@ -0,0 +1,5 @@
# Troubleshooting
- Ensure Python and Odoo environment matches repo guidance.
- Check database connectivity and logs if startup fails.
- Validate that dependent addons listed in DEPENDENCIES.md are installed.

View file

@ -0,0 +1,7 @@
# Usage
Start Odoo including this addon (from repo root):
```bash
python3 scripts/odoo_web_server.py --db-name mydb --addon website_sale
```

View file

@ -0,0 +1,8 @@
# Wizards
Transient models exposed as UI wizards in website_sale.
```mermaid
classDiagram
class MailComposeMessage
```

View file

@ -0,0 +1,47 @@
[project]
name = "odoo-bringout-oca-ocb-website_sale"
version = "16.0.0"
description = "eCommerce - Sell your products online"
authors = [
{ name = "Ernad Husremovic", email = "hernad@bring.out.ba" }
]
dependencies = [
"odoo-bringout-oca-ocb-website>=16.0.0",
"odoo-bringout-oca-ocb-sale>=16.0.0",
"odoo-bringout-oca-ocb-website_payment>=16.0.0",
"odoo-bringout-oca-ocb-website_mail>=16.0.0",
"odoo-bringout-oca-ocb-portal_rating>=16.0.0",
"odoo-bringout-oca-ocb-digest>=16.0.0",
"requests>=2.25.1"
]
readme = "README.md"
requires-python = ">= 3.11"
classifiers = [
"Development Status :: 5 - Production/Stable",
"Intended Audience :: Developers",
"License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Topic :: Office/Business",
]
[project.urls]
homepage = "https://github.com/bringout/odoo-bringout-oca-ocb-website_sale"
repository = "https://github.com/bringout/odoo-bringout-oca-ocb-website_sale"
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[tool.hatch.metadata]
allow-direct-references = true
[tool.hatch.build.targets.wheel]
packages = ["website_sale"]
[tool.rye]
managed = true
dev-dependencies = [
"pytest>=8.4.1",
]

View 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.

View 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})

View 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',
}

View file

@ -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

View file

@ -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

File diff suppressed because it is too large Load diff

View file

@ -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)

View 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>

View 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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -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"

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

Some files were not shown because too many files have changed in this diff Show more