[IMP] "website_sale" compatible for multi website

This commit is contained in:
Kaushal Prajapati 2017-12-22 19:47:53 +05:30 committed by Siddharth Bhalgami
parent d00801d466
commit 23e5ea0865
19 changed files with 510 additions and 56 deletions

View File

@ -12,8 +12,10 @@ from flectra.http import request
class WebsiteSaleBackend(WebsiteBackend): class WebsiteSaleBackend(WebsiteBackend):
@http.route() @http.route()
def fetch_dashboard_data(self, date_from, date_to): def fetch_dashboard_data(self, date_from, date_to, website_id=None):
results = super(WebsiteSaleBackend, self).fetch_dashboard_data(date_from, date_to) if not website_id:
website_id = request.website.id
results = super(WebsiteSaleBackend, self).fetch_dashboard_data(date_from, date_to, website_id)
sales_values = dict( sales_values = dict(
graph=[], graph=[],
@ -44,6 +46,7 @@ class WebsiteSaleBackend(WebsiteBackend):
('team_id.team_type', '=', 'website'), ('team_id.team_type', '=', 'website'),
('state', 'in', ['sale', 'done']), ('state', 'in', ['sale', 'done']),
('date', '>=', date_from), ('date', '>=', date_from),
('website_id.id', '=', website_id),
('date', '<=', date_to)], ('date', '<=', date_to)],
fields=['product_id', 'product_uom_qty', 'price_subtotal'], fields=['product_id', 'product_uom_qty', 'price_subtotal'],
groupby='product_id', orderby='product_uom_qty desc', limit=5) groupby='product_id', orderby='product_uom_qty desc', limit=5)
@ -60,7 +63,8 @@ class WebsiteSaleBackend(WebsiteBackend):
sale_order_domain = [ sale_order_domain = [
('team_id', 'in', request.env['crm.team'].search([('team_type', '=', 'website')]).ids), ('team_id', 'in', request.env['crm.team'].search([('team_type', '=', 'website')]).ids),
('date_order', '>=', fields.Datetime.to_string(datetime_from)), ('date_order', '>=', fields.Datetime.to_string(datetime_from)),
('date_order', '<=', fields.Datetime.to_string(datetime_to))] ('date_order', '<=', fields.Datetime.to_string(datetime_to)),
('website_id', '=', website_id)]
so_group_data = request.env['sale.order'].read_group(sale_order_domain, fields=['state'], groupby='state') so_group_data = request.env['sale.order'].read_group(sale_order_domain, fields=['state'], groupby='state')
for res in so_group_data: for res in so_group_data:
if res.get('state') == 'sent': if res.get('state') == 'sent':
@ -74,7 +78,8 @@ class WebsiteSaleBackend(WebsiteBackend):
('team_id.team_type', '=', 'website'), ('team_id.team_type', '=', 'website'),
('state', 'in', ['sale', 'done']), ('state', 'in', ['sale', 'done']),
('date', '>=', date_from), ('date', '>=', date_from),
('date', '<=', date_to)], ('date', '<=', date_to),
('website_id.id', '=', website_id)],
fields=['team_id', 'price_subtotal'], fields=['team_id', 'price_subtotal'],
groupby=['team_id'], groupby=['team_id'],
) )
@ -114,7 +119,8 @@ class WebsiteSaleBackend(WebsiteBackend):
('team_id.team_type', '=', 'website'), ('team_id.team_type', '=', 'website'),
('state', 'in', ['sale', 'done']), ('state', 'in', ['sale', 'done']),
('date', '>=', date_from), ('date', '>=', date_from),
('date', '<=', date_to) ('date', '<=', date_to),
('website_id.id', '=', website_id)
] ]
sales_values['graph'] += [{ sales_values['graph'] += [{
'values': self._compute_sale_graph(date_date_from, date_date_to, sales_domain), 'values': self._compute_sale_graph(date_date_from, date_date_to, sales_domain),

View File

@ -135,7 +135,7 @@ class WebsiteSale(http.Controller):
def get_attribute_value_ids(self, product): def get_attribute_value_ids(self, product):
""" list of selectable attributes of a product """ list of selectable attributes of a product
:return: list of product variant description :return: list of product variant description as requested website
(variant id, [visible attribute ids], variant price, variant sale price) (variant id, [visible attribute ids], variant price, variant sale price)
""" """
# product attributes with at least two choices # product attributes with at least two choices
@ -185,6 +185,8 @@ class WebsiteSale(http.Controller):
ids = [value[1]] ids = [value[1]]
if attrib: if attrib:
domain += [('attribute_line_ids.value_ids', 'in', ids)] domain += [('attribute_line_ids.value_ids', 'in', ids)]
if not request.env.user.has_group('website.group_website_publisher'):
domain += [('website_ids', 'in', request.website.id)]
return domain return domain
@ -222,11 +224,16 @@ class WebsiteSale(http.Controller):
post["search"] = search post["search"] = search
if category: if category:
category = request.env['product.public.category'].browse(int(category)) category = request.env['product.public.category'].browse(int(category))
website = []
for web in category.website_ids:
website.append(web.id)
if request.website.id not in website:
return request.render('website.404')
url = "/shop/category/%s" % slug(category) url = "/shop/category/%s" % slug(category)
if attrib_list: if attrib_list:
post['attrib'] = attrib_list post['attrib'] = attrib_list
categs = request.env['product.public.category'].search([('parent_id', '=', False)]) categs = request.env['product.public.category'].search([('parent_id', '=', False), ('website_ids', 'in', request.website.id)])
Product = request.env['product.template'] Product = request.env['product.template']
parent_category_ids = [] parent_category_ids = []
@ -315,7 +322,7 @@ class WebsiteSale(http.Controller):
@http.route(['/shop/change_pricelist/<model("product.pricelist"):pl_id>'], type='http', auth="public", website=True) @http.route(['/shop/change_pricelist/<model("product.pricelist"):pl_id>'], type='http', auth="public", website=True)
def pricelist_change(self, pl_id, **post): def pricelist_change(self, pl_id, **post):
if (pl_id.selectable or pl_id == request.env.user.partner_id.property_product_pricelist) \ if (pl_id.website_id or pl_id == request.env.user.partner_id.property_product_pricelist) \
and request.website.is_pricelist_available(pl_id.id): and request.website.is_pricelist_available(pl_id.id):
request.session['website_sale_current_pl'] = pl_id.id request.session['website_sale_current_pl'] = pl_id.id
request.website.sale_get_order(force_pricelist=pl_id.id) request.website.sale_get_order(force_pricelist=pl_id.id)

View File

@ -0,0 +1,279 @@
# -*- coding: utf-8 -*-
# Part of Flectra. See LICENSE file for full copyright and licensing details.
from flectra import http
from flectra.http import request
from flectra import tools, _
from flectra.exceptions import AccessError
from flectra.addons.sale.controllers.portal import CustomerPortal
from flectra.addons.account.controllers.portal import PortalAccount
class SaleCustomerPortal(CustomerPortal):
def _prepare_portal_layout_values(self):
values = super(SaleCustomerPortal, self)._prepare_portal_layout_values()
partner = request.env.user.partner_id
SaleOrder = request.env['sale.order']
quotation_count = SaleOrder.search_count([
('message_partner_ids', 'child_of',
[partner.commercial_partner_id.id]),
('state', 'in', ['sent', 'cancel']),
('website_id', '=', request.website.id),
])
order_count = SaleOrder.search_count([
('message_partner_ids', 'child_of',
[partner.commercial_partner_id.id]),
('state', 'in', ['sale', 'done']),
('website_id', '=', request.website.id),
])
values.update({
'quotation_count': quotation_count,
'order_count': order_count,
})
return values
@http.route(['/my/quotes', '/my/quotes/page/<int:page>'], type='http',
auth="user", website=True)
def portal_my_quotes(self, page=1, date_begin=None, date_end=None,
sortby=None, **kw):
values = self._prepare_portal_layout_values()
partner = request.env.user.partner_id
SaleOrder = request.env['sale.order']
domain = [
('message_partner_ids', 'child_of',
[partner.commercial_partner_id.id]),
('state', 'in', ['sent', 'cancel']),
('website_id', '=', request.website.id),
]
searchbar_sortings = {
'date': {'label': _('Order Date'), 'order': 'date_order desc'},
'name': {'label': _('Reference'), 'order': 'name'},
'stage': {'label': _('Stage'), 'order': 'state'},
}
# default sortby order
if not sortby:
sortby = 'date'
sort_order = searchbar_sortings[sortby]['order']
archive_groups = self._get_archive_groups('sale.order', domain)
if date_begin and date_end:
domain += [('create_date', '>', date_begin),
('create_date', '<=', date_end)]
# count for pager
quotation_count = SaleOrder.search_count(domain)
# make pager
pager = request.website.pager(
url="/my/quotes",
url_args={'date_begin': date_begin, 'date_end': date_end,
'sortby': sortby},
total=quotation_count,
page=page,
step=self._items_per_page
)
# search the count to display, according to the pager data
quotations = SaleOrder.search(domain, order=sort_order,
limit=self._items_per_page,
offset=pager['offset'])
request.session['my_quotes_history'] = quotations.ids[:100]
values.update({
'date': date_begin,
'quotations': quotations.sudo(),
'page_name': 'quote',
'pager': pager,
'archive_groups': archive_groups,
'default_url': '/my/quotes',
'searchbar_sortings': searchbar_sortings,
'sortby': sortby,
})
return request.render("sale.portal_my_quotations",
values)
@http.route(['/my/orders', '/my/orders/page/<int:page>'], type='http',
auth="user", website=True)
def portal_my_orders(self, page=1, date_begin=None, date_end=None,
sortby=None, **kw):
values = self._prepare_portal_layout_values()
partner = request.env.user.partner_id
SaleOrder = request.env['sale.order']
domain = [
('message_partner_ids', 'child_of',
[partner.commercial_partner_id.id]),
('state', 'in', ['sale', 'done']),
('website_id', '=', request.website.id),
]
searchbar_sortings = {
'date': {'label': _('Order Date'), 'order': 'date_order desc'},
'name': {'label': _('Reference'), 'order': 'name'},
'stage': {'label': _('Stage'), 'order': 'state'},
}
# default sortby order
if not sortby:
sortby = 'date'
sort_order = searchbar_sortings[sortby]['order']
archive_groups = self._get_archive_groups('sale.order', domain)
if date_begin and date_end:
domain += [('create_date', '>', date_begin),
('create_date', '<=', date_end)]
# count for pager
order_count = SaleOrder.search_count(domain)
# pager
pager = request.website.pager(
url="/my/orders",
url_args={'date_begin': date_begin, 'date_end': date_end,
'sortby': sortby},
total=order_count,
page=page,
step=self._items_per_page
)
# content according to pager and archive selected
orders = SaleOrder.search(domain, order=sort_order,
limit=self._items_per_page,
offset=pager['offset'])
request.session['my_orders_history'] = orders.ids[:100]
values.update({
'date': date_begin,
'orders': orders.sudo(),
'page_name': 'order',
'pager': pager,
'archive_groups': archive_groups,
'default_url': '/my/orders',
'searchbar_sortings': searchbar_sortings,
'sortby': sortby,
})
return request.render("sale.portal_my_orders", values)
@http.route()
def portal_order_page(self, order=None, access_token=None, **kw):
order = request.env['sale.order'].browse([order])
try:
if order.website_id != request.website:
raise AccessError('Invalid Order !!')
except AccessError:
return request.render("website.403")
return super(SaleCustomerPortal, self).portal_order_page(order.id,
access_token, **kw)
@http.route()
def portal_order_report(self, order_id, access_token=None, **kw):
order = request.env['sale.order'].browse([order_id])
try:
if order.website_id != request.website:
raise AccessError('Invalid Order !!')
except AccessError:
return request.render("website.403")
return super(SaleCustomerPortal, self).portal_order_report(order_id,
access_token,
**kw)
class AccountCustomerPortal(PortalAccount):
def _prepare_portal_layout_values(self):
values = super(AccountCustomerPortal, self)._prepare_portal_layout_values()
partner = request.env.user.partner_id
invoice_count = request.env['account.invoice'].search_count([
('type', 'in', ['out_invoice', 'out_refund']),
('message_partner_ids', 'child_of',
[partner.commercial_partner_id.id]),
('state', 'in', ['open', 'paid', 'cancel']),
('website_id', '=', request.website.id),
])
values['invoice_count'] = invoice_count
return values
@http.route()
def portal_my_invoices(self, page=1, date_begin=None, date_end=None,
sortby=None, **kw):
values = self._prepare_portal_layout_values()
partner = request.env.user.partner_id
AccountInvoice = request.env['account.invoice']
domain = [
('type', 'in', ['out_invoice', 'out_refund']),
('message_partner_ids', 'child_of',
[partner.commercial_partner_id.id]),
('state', 'in', ['open', 'paid', 'cancelled']),
('website_id', '=', request.website.id),
]
searchbar_sortings = {
'date': {'label': _('Invoice Date'), 'order': 'date_invoice desc'},
'duedate': {'label': _('Due Date'), 'order': 'date_due desc'},
'name': {'label': _('Reference'), 'order': 'name desc'},
'state': {'label': _('Status'), 'order': 'state'},
}
# default sort by order
if not sortby:
sortby = 'date'
order = searchbar_sortings[sortby]['order']
archive_groups = self._get_archive_groups('account.invoice', domain)
if date_begin and date_end:
domain += [('create_date', '>', date_begin),
('create_date', '<=', date_end)]
# count for pager
invoice_count = AccountInvoice.search_count(domain)
# pager
pager = request.website.pager(
url="/my/invoices",
url_args={'date_begin': date_begin,
'date_end': date_end,
'sortby': sortby},
total=invoice_count,
page=page,
step=self._items_per_page
)
# content according to pager and archive selected
invoices = AccountInvoice.search(domain, order=order,
limit=self._items_per_page,
offset=pager['offset'])
values.update({
'date': date_begin,
'invoices': invoices,
'page_name': 'invoice',
'pager': pager,
'archive_groups': archive_groups,
'default_url': '/my/invoices',
'searchbar_sortings': searchbar_sortings,
'sortby': sortby,
})
return request.render("account.portal_my_invoices", values)
@http.route()
def portal_my_invoice_detail(self, invoice_id, access_token=None, **kw):
invoice = request.env['account.invoice'].browse(invoice_id)
try:
if invoice.website_id != request.website:
raise AccessError('Invalid Invoice !!')
except AccessError:
return request.render("website.403")
return super(PortalAccount, self).portal_my_invoice_detail(invoice_id, access_token,**kw)
@http.route()
def portal_my_invoice_report(self, invoice_id, **kw):
invoice = request.env['account.invoice'].browse(invoice_id)
try:
if invoice.website_id != request.website:
raise AccessError('Invalid Invoice !!')
except AccessError:
return request.render("website.403")
return super(PortalAccount, self).portal_my_invoices_report(invoice_id,
**kw)

View File

@ -38,10 +38,6 @@
<field name="salesteam_id" ref="sales_team.salesteam_website_sales"/> <field name="salesteam_id" ref="sales_team.salesteam_website_sales"/>
</record> </record>
<record model="product.pricelist" id="product.list0">
<field name="selectable" eval="False" />
<field name="website_id" ref="website.default_website" />
</record>
</data> </data>
<data> <data>
<record id="sale.model_sale_order" model="ir.model"> <record id="sale.model_sale_order" model="ir.model">

View File

@ -713,8 +713,7 @@ Weight: 31 grams</field>
<record model="product.pricelist" id="product.list0"> <record model="product.pricelist" id="product.list0">
<field name="name">USD</field> <field name="name">USD</field>
<field name="selectable" eval="True" /> <!--<field name="website_id" eval="[(6, 0, [ref('website.default_website').id])]"/>-->
<field name="website_id" ref="website.default_website" />
<field name="sequence">3</field> <field name="sequence">3</field>
<field name="currency_id" ref="base.USD"/> <field name="currency_id" ref="base.USD"/>
</record> </record>
@ -727,8 +726,7 @@ Weight: 31 grams</field>
<record id="list_christmas" model="product.pricelist"> <record id="list_christmas" model="product.pricelist">
<field name="name">Christmas</field> <field name="name">Christmas</field>
<field name="selectable" eval="False" /> <!--<field name="website_id" eval="[(6, 0, [ref('website.default_website').id])]"/>-->
<field name="website_id" ref="website.default_website" />
<field name="country_group_ids" eval="[(6,0,[ref('base.europe')])]" /> <field name="country_group_ids" eval="[(6,0,[ref('base.europe')])]" />
<field name="sequence">20</field> <field name="sequence">20</field>
</record> </record>
@ -741,8 +739,7 @@ Weight: 31 grams</field>
<record id="list_benelux" model="product.pricelist"> <record id="list_benelux" model="product.pricelist">
<field name="name">Benelux</field> <field name="name">Benelux</field>
<field name="selectable" eval="False" /> <!--<field name="website_id" eval="[(6, 0, [ref('website.default_website').id])]"/>-->
<field name="website_id" ref="website.default_website" />
<field name="country_group_ids" eval="[(6,0,[ref('benelux')])]" /> <field name="country_group_ids" eval="[(6,0,[ref('benelux')])]" />
<field name="sequence">2</field> <field name="sequence">2</field>
</record> </record>
@ -757,8 +754,7 @@ Weight: 31 grams</field>
<record id="list_europe" model="product.pricelist"> <record id="list_europe" model="product.pricelist">
<field name="name">EUR</field> <field name="name">EUR</field>
<field name="selectable" eval="True" /> <!--<field name="website_id" eval="[(6, 0, [ref('website.default_website').id])]"/>-->
<field name="website_id" ref="website.default_website" />
<field name="country_group_ids" eval="[(6,0,[ref('base.europe')])]" /> <field name="country_group_ids" eval="[(6,0,[ref('base.europe')])]" />
<field name="sequence">3</field> <field name="sequence">3</field>
<field name="currency_id" ref="base.EUR"/> <field name="currency_id" ref="base.EUR"/>

View File

@ -1,6 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details. # Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
from . import account_invoice
from . import crm_team from . import crm_team
from . import ir_http from . import ir_http
from . import mail_compose_message from . import mail_compose_message
@ -8,6 +9,7 @@ from . import product
from . import res_country from . import res_country
from . import res_partner from . import res_partner
from . import sale_order from . import sale_order
from . import sale_report
from . import ir_model_fields from . import ir_model_fields
from . import website from . import website
from . import res_config_settings from . import res_config_settings

View File

@ -0,0 +1,24 @@
# -*- coding: utf-8 -*-
# Part of Flectra. See LICENSE file for full copyright and licensing details.
from flectra import api, fields, models, _
class AccountInvoice(models.Model):
_inherit = 'account.invoice'
website_id = fields.Many2one('website', string="Website")
class SaleAdvancePaymentInv(models.TransientModel):
_inherit = "sale.advance.payment.inv"
@api.multi
def _create_invoice(self, order, so_line, amount):
res = super(SaleAdvancePaymentInv, self)._create_invoice(order,
so_line,
amount)
res.website_id = order.website_id
return res

View File

@ -15,15 +15,23 @@ class ProductStyle(models.Model):
html_class = fields.Char(string='HTML Classes') html_class = fields.Char(string='HTML Classes')
class WebsitePriceList(models.Model):
_name = "website.product.pricelist"
pricelist_id = fields.Many2one('product.pricelist',
string='Website Pricelist')
website_id = fields.Many2one('website', string='Website')
selectable = fields.Boolean(string="selectable", default=True)
class ProductPricelist(models.Model): class ProductPricelist(models.Model):
_inherit = "product.pricelist" _inherit = "product.pricelist"
def _default_website(self): def _default_website(self):
return self.env['website'].search([], limit=1) return self.env['website'].search([], limit=1)
website_id = fields.Many2one('website', string="website", default=_default_website) website_id = fields.One2many('website.product.pricelist', 'pricelist_id', string='Website')
code = fields.Char(string='E-commerce Promotional Code', groups="base.group_user") code = fields.Char(string='E-commerce Promotional Code', groups="base.group_user")
selectable = fields.Boolean(help="Allow the end user to choose this price list")
def clear_cache(self): def clear_cache(self):
# website._get_pl() is cached to avoid to recompute at each request the # website._get_pl() is cached to avoid to recompute at each request the
@ -75,16 +83,40 @@ class ProductPublicCategory(models.Model):
help="Small-sized image of the category. It is automatically " help="Small-sized image of the category. It is automatically "
"resized as a 64x64px image, with aspect ratio preserved. " "resized as a 64x64px image, with aspect ratio preserved. "
"Use this field anywhere a small image is required.") "Use this field anywhere a small image is required.")
website_ids = fields.Many2many('website', 'website_prod_public_categ_rel',
'website_id', 'category_id',
string='Websites', copy=False,
help='List of websites in which '
'category is published.')
@api.model @api.model
def create(self, vals): def create(self, vals):
tools.image_resize_images(vals) tools.image_resize_images(vals)
return super(ProductPublicCategory, self).create(vals) res = super(ProductPublicCategory, self).create(vals)
# @todo Check different test-case: child & parent category
if res.parent_id:
res.parent_id.write({
'website_ids': [(4, website_id.id) for website_id in res.website_ids]
})
return res
@api.multi @api.multi
def write(self, vals): def write(self, vals):
tools.image_resize_images(vals) tools.image_resize_images(vals)
return super(ProductPublicCategory, self).write(vals) res = super(ProductPublicCategory, self).write(vals)
# @todo Check different test-case: child & parent category
if self.parent_id and self.website_ids.ids:
self.parent_id.write({
'website_ids': [(4, website_id.id) for website_id in self.website_ids]
})
if self.child_id:
for child_id in self.child_id:
for website_id in child_id.website_ids:
if website_id not in self.website_ids:
child_id.write({
'website_ids': [(3, website_id.id)]
})
return res
@api.constrains('parent_id') @api.constrains('parent_id')
def check_parent_id(self): def check_parent_id(self):
@ -132,6 +164,11 @@ class ProductTemplate(models.Model):
website_price = fields.Float('Website price', compute='_website_price', digits=dp.get_precision('Product Price')) website_price = fields.Float('Website price', compute='_website_price', digits=dp.get_precision('Product Price'))
website_public_price = fields.Float('Website public price', compute='_website_price', digits=dp.get_precision('Product Price')) website_public_price = fields.Float('Website public price', compute='_website_price', digits=dp.get_precision('Product Price'))
website_price_difference = fields.Boolean('Website price difference', compute='_website_price') website_price_difference = fields.Boolean('Website price difference', compute='_website_price')
website_ids = fields.Many2many('website', 'website_prod_pub_rel',
'website_id', 'product_id',
string='Websites', copy=False,
help='List of websites in which '
'Product is published.')
def _website_price(self): def _website_price(self):
# First filter out the ones that have no variant: # First filter out the ones that have no variant:
@ -180,6 +217,11 @@ class ProductTemplate(models.Model):
class Product(models.Model): class Product(models.Model):
_inherit = "product.product" _inherit = "product.product"
def _get_default_website_ids(self):
default_website_id = self.env.ref('website.default_website')
return [default_website_id.id] if default_website_id else None
website_ids = fields.Many2many('website', string="Publish Product On Website", default=_get_default_website_ids)
website_price = fields.Float('Website price', compute='_website_price', digits=dp.get_precision('Product Price')) website_price = fields.Float('Website price', compute='_website_price', digits=dp.get_precision('Product Price'))
website_public_price = fields.Float('Website public price', compute='_website_price', digits=dp.get_precision('Product Price')) website_public_price = fields.Float('Website public price', compute='_website_price', digits=dp.get_precision('Product Price'))
website_price_difference = fields.Boolean('Website price difference', compute='_website_price') website_price_difference = fields.Boolean('Website price difference', compute='_website_price')

View File

@ -21,6 +21,8 @@ class SaleOrder(models.Model):
string='Order Lines displayed on Website', readonly=True, string='Order Lines displayed on Website', readonly=True,
help='Order Lines to be displayed on the website. They should not be used for computation purpose.', help='Order Lines to be displayed on the website. They should not be used for computation purpose.',
) )
website_id = fields.Many2one('website', string='Website',
help='Website reference for quotation/order.')
cart_quantity = fields.Integer(compute='_compute_cart_info', string='Cart Quantity') cart_quantity = fields.Integer(compute='_compute_cart_info', string='Cart Quantity')
only_services = fields.Boolean(compute='_compute_cart_info', string='Only Services') only_services = fields.Boolean(compute='_compute_cart_info', string='Only Services')
can_directly_mark_as_paid = fields.Boolean(compute='_compute_can_directly_mark_as_paid', can_directly_mark_as_paid = fields.Boolean(compute='_compute_can_directly_mark_as_paid',
@ -256,3 +258,9 @@ class SaleOrder(models.Model):
self.payment_tx_id.state = 'done' self.payment_tx_id.state = 'done'
else: else:
raise ValidationError(_("The quote should be sent and the payment acquirer type should be manual or wire transfer")) raise ValidationError(_("The quote should be sent and the payment acquirer type should be manual or wire transfer"))
@api.multi
def _prepare_invoice(self):
res = super(SaleOrder, self)._prepare_invoice()
res['website_id'] = self.website_id.id
return res

View File

@ -0,0 +1,49 @@
# -*- coding: utf-8 -*-
# Part of flectra. See LICENSE file for full copyright and licensing details.
from flectra import api, fields, models
class SaleReport(models.Model):
_inherit = "sale.report"
website_id = fields.Many2one('website', 'Website', readonly=True)
def _select(self):
select_str = """
WITH currency_rate as (%s)
SELECT min(l.id) as id,
l.product_id as product_id,
t.uom_id as product_uom,
sum(l.product_uom_qty / u.factor * u2.factor) as product_uom_qty,
sum(l.qty_delivered / u.factor * u2.factor) as qty_delivered,
sum(l.qty_invoiced / u.factor * u2.factor) as qty_invoiced,
sum(l.qty_to_invoice / u.factor * u2.factor) as qty_to_invoice,
sum(l.price_total / COALESCE(cr.rate, 1.0)) as price_total,
sum(l.price_subtotal / COALESCE(cr.rate, 1.0)) as price_subtotal,
sum(l.amt_to_invoice / COALESCE(cr.rate, 1.0)) as amt_to_invoice,
sum(l.amt_invoiced / COALESCE(cr.rate, 1.0)) as amt_invoiced,
count(*) as nbr,
s.name as name,
s.date_order as date,
s.confirmation_date as confirmation_date,
s.state as state,
s.partner_id as partner_id,
s.user_id as user_id,
s.company_id as company_id,
extract(epoch from avg(date_trunc('day',s.date_order)-date_trunc('day',s.create_date)))/(24*60*60)::decimal(16,2) as delay,
t.categ_id as categ_id,
s.pricelist_id as pricelist_id,
s.analytic_account_id as analytic_account_id,
s.team_id as team_id,
s.website_id as website_id,
p.product_tmpl_id,
partner.country_id as country_id,
partner.commercial_partner_id as commercial_partner_id,
sum(p.weight * l.product_uom_qty / u.factor * u2.factor) as weight,
sum(p.volume * l.product_uom_qty / u.factor * u2.factor) as volume
""" % self.env['res.currency']._select_companies_rates()
return select_str
def _group_by(self):
res = super(SaleReport, self)._group_by()
return res + ',s.website_id'

View File

@ -17,12 +17,14 @@ class Website(models.Model):
currency_id = fields.Many2one('res.currency', related='pricelist_id.currency_id', string='Default Currency') currency_id = fields.Many2one('res.currency', related='pricelist_id.currency_id', string='Default Currency')
salesperson_id = fields.Many2one('res.users', string='Salesperson') salesperson_id = fields.Many2one('res.users', string='Salesperson')
salesteam_id = fields.Many2one('crm.team', string='Sales Channel') salesteam_id = fields.Many2one('crm.team', string='Sales Channel')
pricelist_ids = fields.One2many('product.pricelist', compute="_compute_pricelist_ids", pricelist_ids = fields.One2many('website.product.pricelist', compute="_compute_pricelist_ids",
string='Price list available for this Ecommerce/Website') string='Price list available for this Ecommerce/Website')
@api.one @api.one
def _compute_pricelist_ids(self): def _compute_pricelist_ids(self):
self.pricelist_ids = self.env["product.pricelist"].search([("website_id", "=", self.id)]) for website in self:
website.pricelist_ids = website.env["website.product.pricelist"].search([("website_id", "=", website.id)])
# self.pricelist_ids = self.env["product.pricelist"].search([("website_id", "=", self.id)])
@api.multi @api.multi
def _compute_pricelist_id(self): def _compute_pricelist_id(self):
@ -32,8 +34,8 @@ class Website(models.Model):
website.pricelist_id = website.get_current_pricelist() website.pricelist_id = website.get_current_pricelist()
# This method is cached, must not return records! See also #8795 # This method is cached, must not return records! See also #8795
@tools.ormcache('self.env.uid', 'country_code', 'show_visible', 'website_pl', 'current_pl', 'all_pl', 'partner_pl', 'order_pl') @tools.ormcache('self.env.uid', 'country_code', 'show_visible', 'website_pl', 'current_pl', 'all_pls', 'partner_pl', 'order_pl')
def _get_pl_partner_order(self, country_code, show_visible, website_pl, current_pl, all_pl, partner_pl=False, order_pl=False): def _get_pl_partner_order(self, country_code, show_visible, website_pl, current_pl, all_pls, partner_pl=False, order_pl=False):
""" Return the list of pricelists that can be used on website for the current user. """ Return the list of pricelists that can be used on website for the current user.
:param str country_code: code iso or False, If set, we search only price list available for this country :param str country_code: code iso or False, If set, we search only price list available for this country
:param bool show_visible: if True, we don't display pricelist where selectable is False (Eg: Code promo) :param bool show_visible: if True, we don't display pricelist where selectable is False (Eg: Code promo)
@ -49,7 +51,7 @@ class Website(models.Model):
if country_code: if country_code:
for cgroup in self.env['res.country.group'].search([('country_ids.code', '=', country_code)]): for cgroup in self.env['res.country.group'].search([('country_ids.code', '=', country_code)]):
for group_pricelists in cgroup.pricelist_ids: for group_pricelists in cgroup.pricelist_ids:
if not show_visible or group_pricelists.selectable or group_pricelists.id in (current_pl, order_pl): if not show_visible or group_pricelists.website_id.filtered(lambda web_pl: web_pl.website_id == self.get_current_website() and web_pl.selectable) or group_pricelists.id in (current_pl, order_pl):
pricelists |= group_pricelists pricelists |= group_pricelists
partner = self.env.user.partner_id partner = self.env.user.partner_id
@ -59,9 +61,11 @@ class Website(models.Model):
pricelists |= partner.property_product_pricelist pricelists |= partner.property_product_pricelist
if not pricelists: # no pricelist for this country, or no GeoIP if not pricelists: # no pricelist for this country, or no GeoIP
pricelists |= all_pl.filtered(lambda pl: not show_visible or pl.selectable or pl.id in (current_pl, order_pl)) for all_pl in all_pls:
pricelists |= all_pl.pricelist_id.filtered(lambda pl: not show_visible or (all_pl.pricelist_id == pl and all_pl.selectable) or pl.id in (current_pl, order_pl))
else: else:
pricelists |= all_pl.filtered(lambda pl: not show_visible and pl.sudo().code) for all_pl in all_pls:
pricelists |= all_pl.pricelist_id.filtered(lambda pl: not show_visible and pl.sudo().code)
# This method is cached, must not return records! See also #8795 # This method is cached, must not return records! See also #8795
return pricelists.ids return pricelists.ids
@ -167,6 +171,7 @@ class Website(models.Model):
'partner_invoice_id': addr['invoice'], 'partner_invoice_id': addr['invoice'],
'partner_shipping_id': addr['delivery'], 'partner_shipping_id': addr['delivery'],
'user_id': salesperson_id or self.salesperson_id.id or default_user_id, 'user_id': salesperson_id or self.salesperson_id.id or default_user_id,
'website_id': request.website.id,
} }
company = self.company_id or pricelist.company_id company = self.company_id or pricelist.company_id
if company: if company:

View File

@ -19,3 +19,4 @@ access_account_tax_user,account.tax,account.model_account_tax,base.group_public,
access_product_image_public,product.image public,model_product_image,,1,0,0,0 access_product_image_public,product.image public,model_product_image,,1,0,0,0
access_product_image_publisher,product.image wbesite publisher,model_product_image,website.group_website_publisher,1,1,1,1 access_product_image_publisher,product.image wbesite publisher,model_product_image,website.group_website_publisher,1,1,1,1
access_product_image_sale,product.image sale,model_product_image,sales_team.group_sale_manager,1,1,1,1 access_product_image_sale,product.image sale,model_product_image,sales_team.group_sale_manager,1,1,1,1
access_website_product_pricelist,access_website_product_pricelist,model_website_product_pricelist,,1,0,0,0

1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
19 access_product_image_public product.image public model_product_image 1 0 0 0
20 access_product_image_publisher product.image wbesite publisher model_product_image website.group_website_publisher 1 1 1 1
21 access_product_image_sale product.image sale model_product_image sales_team.group_sale_manager 1 1 1 1
22 access_website_product_pricelist access_website_product_pricelist model_website_product_pricelist 1 0 0 0

View File

@ -22,22 +22,30 @@ class TestWebsitePriceList(TransactionCase):
self.env['product.pricelist'].search([]).write({'website_id': False}) self.env['product.pricelist'].search([]).write({'website_id': False})
website_pls = ('list_benelux', 'list_christmas', 'list_europe') website_pls = ('list_benelux', 'list_christmas', 'list_europe')
for pl in website_pls: for pl in website_pls:
self.env.ref('website_sale.' + pl).website_id = self.website.id self.env['website.product.pricelist'].create({
self.env.ref('product.list0').website_id = self.website.id 'pricelist_id': self.env.ref('website_sale.' + pl).id,
self.env.ref('website_sale.list_benelux').selectable = True 'website_id': self.website.id,
'selectable': False if pl == 'list_christmas' else True
})
self.env['website.product.pricelist'].create({
'pricelist_id': self.env.ref('product.list0').id,
'website_id': self.website.id
})
self.website.pricelist_id = self.ref('product.list0') self.website.pricelist_id = self.ref('product.list0')
ca_group = self.env['res.country.group'].create({ ca_group = self.env['res.country.group'].create({
'name': 'Canada', 'name': 'Canada',
'country_ids': [(6, 0, [self.ref('base.ca')])] 'country_ids': [(6, 0, [self.ref('base.ca')])]
}) })
self.env['product.pricelist'].create({ ppl = self.env['product.pricelist'].create({
'name': 'Canada', 'name': 'Canada',
'selectable': True,
'website_id': self.website.id,
'country_group_ids': [(6, 0, [ca_group.id])], 'country_group_ids': [(6, 0, [ca_group.id])],
'sequence': 10 'sequence': 10
}) })
self.env['website.product.pricelist'].create({
'pricelist_id': ppl.id,
'website_id': self.website.id
})
patcher = patch('flectra.addons.website_sale.models.website.Website.get_pricelist_available', wraps=self._get_pricelist_available) patcher = patch('flectra.addons.website_sale.models.website.Website.get_pricelist_available', wraps=self._get_pricelist_available)
patcher.start() patcher.start()
self.addCleanup(patcher.stop) self.addCleanup(patcher.stop)

View File

@ -21,4 +21,15 @@
<field name="search_view_id" ref="product.product_pricelist_view_search" /> <field name="search_view_id" ref="product.product_pricelist_view_search" />
<field name="context">{"default_base":'list_price'}</field> <field name="context">{"default_base":'list_price'}</field>
</record> </record>
<record id="view_invoice_form_inherit" model="ir.ui.view">
<field name="name">account.invoice.form.inherit</field>
<field name="model">account.invoice</field>
<field name="inherit_id" ref="account.invoice_form"/>
<field name="arch" type="xml">
<field name='fiscal_position_id' position="after">
<field name="website_id"/>
</field>
</field>
</record>
</flectra> </flectra>

View File

@ -21,4 +21,24 @@
<field name="view_id" ref="payment.transaction"/> <field name="view_id" ref="payment.transaction"/>
<field name="help">You don't have any payments to capture from the website.</field> <field name="help">You don't have any payments to capture from the website.</field>
</record> </record>
<record id="product_template_only_form_view_inherit" model="ir.ui.view">
<field name="name">product.template.product.form.inherit</field>
<field name="model">product.template</field>
<field name="inherit_id" ref="product.product_template_only_form_view"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='attribute_line_ids']"
position="after">
<field name="product_variant_ids">
<tree editable='bottom' delete="false" create="false">
<field name = 'name' readonly="1"/>
<field name = 'attribute_value_ids'
widget="many2many_tags" readonly="1"/>
<field name = 'lst_price' readonly="1"/>
<field name = 'website_ids' widget="many2many_tags" />
</tree>
</field>
</xpath>
</field>
</record>
</flectra> </flectra>

View File

@ -74,6 +74,7 @@
<field name="accessory_product_ids" widget="many2many_tags"/> <field name="accessory_product_ids" widget="many2many_tags"/>
<field name="website_style_ids" widget="many2many_tags" groups="base.group_no_one"/> <field name="website_style_ids" widget="many2many_tags" groups="base.group_no_one"/>
</group> </group>
<field name="website_ids"/>
</group> </group>
<button name="toggle_active" position="before"> <button name="toggle_active" position="before">
<button class="oe_stat_button" name="website_publish_button" <button class="oe_stat_button" name="website_publish_button"
@ -153,6 +154,7 @@
<field name="name"/> <field name="name"/>
<field name="parent_id"/> <field name="parent_id"/>
<field name="sequence"/> <field name="sequence"/>
<field name="website_ids" widget="many2many_tags"/>
</group> </group>
</div> </div>
</sheet> </sheet>
@ -193,20 +195,13 @@
<field name="model">product.pricelist</field> <field name="model">product.pricelist</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<field name='currency_id' position='after'> <field name='currency_id' position='after'>
<field name="website_id" string='Allow to use on '>
<tree editable='bottom' string="Website Store">
<field name="website_id"/>
<field name="selectable"/> <field name="selectable"/>
<field name="website_id" string='Allow to use on ' placeholder="None website" /> </tree>
</field> </field>
</field> </field>
</record>
<record id="website_sale_pricelist_tree_view" model="ir.ui.view">
<field name="name">product.pricelist.tree.inherit.product</field>
<field name="model">product.pricelist</field>
<field name="inherit_id" ref="product.product_pricelist_view_tree"/>
<field name="arch" type="xml">
<field name="currency_id" position="after">
<field name="selectable" />
</field>
</field> </field>
</record> </record>

View File

@ -365,7 +365,7 @@
</div> </div>
</div> </div>
</div> </div>
<div class="col-xs-12 col-md-6 o_setting_box" id="checkout_assignation_setting" groups="base.group_no_one"> <div class="col-xs-12 col-md-6 o_setting_box" id="checkout_assignation_setting">
<div class="o_setting_right_pane"> <div class="o_setting_right_pane">
<label string="Assignation"/> <label string="Assignation"/>
<div class="text-muted"> <div class="text-muted">
@ -374,7 +374,7 @@
<div class="content-group"> <div class="content-group">
<div class="row mt16"> <div class="row mt16">
<label class="o_light_label col-md-3" string="Sales Channel" for="salesteam_id"/> <label class="o_light_label col-md-3" string="Sales Channel" for="salesteam_id"/>
<field name="salesteam_id" context="{'default_team_type': 'website'}"/> <field name="salesteam_id" context="{'default_team_type': 'website'}" required="True"/>
</div> </div>
<div class="row"> <div class="row">
<label class="o_light_label col-md-3" for="salesperson_id"/> <label class="o_light_label col-md-3" for="salesperson_id"/>

View File

@ -11,6 +11,8 @@
<filter string="From Website" name="from_website" domain="[('team_id.team_type', '=', 'website')]"/> <filter string="From Website" name="from_website" domain="[('team_id.team_type', '=', 'website')]"/>
<separator/> <separator/>
<filter string="Recovery Email to Send" name="recovery_email" domain="[('cart_recovery_email_sent', '=', False)]" /> <filter string="Recovery Email to Send" name="recovery_email" domain="[('cart_recovery_email_sent', '=', False)]" />
<separator/>
<filter name="website_id" string="Website" context="{'group_by':'website_id'}"/>
</search> </search>
</field> </field>
</record> </record>
@ -35,6 +37,9 @@
class="btn-primary" class="btn-primary"
attrs="{'invisible': ['|', ('is_abandoned_cart', '=', False), ('cart_recovery_email_sent', '=', True)]}"/> attrs="{'invisible': ['|', ('is_abandoned_cart', '=', False), ('cart_recovery_email_sent', '=', True)]}"/>
</xpath> </xpath>
<xpath expr="//group[@name='sales_person']" position="inside">
<field name="website_id"/>
</xpath>
</field> </field>
</record> </record>

View File

@ -193,7 +193,7 @@
<t t-if="td_product"> <t t-if="td_product">
<t t-set="product" t-value="td_product['product']" /> <t t-set="product" t-value="td_product['product']" />
<td t-att-colspan="td_product['x'] != 1 and td_product['x']" t-att-rowspan="td_product['y'] != 1 and td_product['y']" t-attf-class="oe_product oe_grid oe-height-#{td_product['y']*2} #{ td_product['class'] }"> <td t-att-colspan="td_product['x'] != 1 and td_product['x']" t-att-rowspan="td_product['y'] != 1 and td_product['y']" t-attf-class="oe_product oe_grid oe-height-#{td_product['y']*2} #{ td_product['class'] }">
<div class="oe_product_cart" t-att-data-publish="product.website_published and 'on' or 'off'"> <div class="oe_product_cart" t-att-data-publish="website in product.website_ids and 'on' or 'off'">
<t t-set="product_image_big" t-value="td_product['x']+td_product['y'] &gt; 2" /> <t t-set="product_image_big" t-value="td_product['x']+td_product['y'] &gt; 2" />
<t t-call="website_sale.products_item" /> <t t-call="website_sale.products_item" />
</div> </div>
@ -258,7 +258,7 @@
<!-- Add to cart button--> <!-- Add to cart button-->
<template id="categories_recursive" name="Category list"> <template id="categories_recursive" name="Category list">
<li t-att-class="'active' if c.id == int(category or 0) else None"> <li t-att-class="'active' if c.id == int(category or 0) else None" t-if="website in c.website_ids">
<a t-att-href="keep('/shop/category/' + slug(c), category=0)" t-field="c.name"></a> <a t-att-href="keep('/shop/category/' + slug(c), category=0)" t-field="c.name"></a>
<ul t-if="c.child_id" class="nav nav-pills nav-stacked nav-hierarchy"> <ul t-if="c.child_id" class="nav nav-pills nav-stacked nav-hierarchy">
<t t-foreach="c.child_id" t-as="c"> <t t-foreach="c.child_id" t-as="c">
@ -365,7 +365,7 @@
<template id="products_list_view" inherit_id="website_sale.products" active="False" customize_show="True" name="List View"> <template id="products_list_view" inherit_id="website_sale.products" active="False" customize_show="True" name="List View">
<xpath expr="//div[@id='products_grid']//table" position="replace"> <xpath expr="//div[@id='products_grid']//table" position="replace">
<t t-foreach="products" t-as="product"> <t t-foreach="products" t-as="product">
<div class="oe_product oe_list oe_product_cart" t-att-data-publish="product.website_published and 'on' or 'off'"> <div class="oe_product oe_list oe_product_cart" t-att-data-publish="website in product.website_ids and 'on' or 'off'">
<t t-call="website_sale.products_item"> <t t-call="website_sale.products_item">
<t t-set="show_publish" t-value="True" /> <t t-set="show_publish" t-value="True" />
</t> </t>