第二章 门户销售
在门户销售订单中添加图片预览
使用[Mommy_Portal_Sale]模块来完成这个工作。
Odoo原生实现了附件预览的功能,但是没有在门户端实现。我们先来看一下后端如何使用图片预览的功能:
门户订单分组
原生odoo在门户订单列表中只提供了过滤和筛选选项,并未提供分组功能。下面我们来看一下,如何在门户中自定义分组功能。
自定义分组字段
由于所有门户模型都继承自CustomerPortal类,因此分组功能其实已经内置了,只不过我们需要把相关的条件通过代码配置出来。
首先我们要理解门户页面的工作流程,由controller组织数据,然后使用QWeb的render方法将页面渲染出来。因此,我们的改造就要基于Render方法。对于门户销售模块来说,这个方法是_prepare_sale_portal_rendering_values。
def _prepare_sale_portal_rendering_values(
self,
page=1,
date_begin=None,
date_end=None,
sortby=None,
quotation_page=False,
search_in=None,
search=None,
groupby="none",
filterby=None,
**kwargs,
):
...
def get_group_orders():
groupby_mapping = self._get_groupby_mapping()
field = groupby_mapping.get(groupby, None)
orderby = "%s, %s" % (field, sort_order) if field else sort_order
if field:
if groupby == "date":
group_orders = SaleOrder.read_group(
domain,
["amount_total:sum", "ids:array_agg(id)"],
["date_order:day"],
orderby=orderby,
)
grouped_orders = [
SaleOrder.sudo().browse(group["ids"]) for group in group_orders
]
else:
grouped_orders = [
SaleOrder.concat(*g)
for k, g in groupbyelem(orders, itemgetter(field))
]
# group_orders = SaleOrder.sudo().read_group(domain, [field, 'amount_total:sum'], [field])
return grouped_orders
grouped_orders = get_group_orders() or [orders]
...
想要获取分组后的数据,我们在传递给templates就需要将数据根据我们的分组条件分组好。上面的内置方法get_group_orders就是实现此功能。如果分组的条件是None,那么我们将没有分组的orders作为一个数组传递给页面。
values.update(
{
"date": date_begin,
"grouped_orders": grouped_orders,
"quotations": orders.sudo() if quotation_page else SaleOrder,
"orders": orders.sudo() if not quotation_page else SaleOrder,
"page_name": "quote" if quotation_page else "order",
"pager": pager_values,
"default_url": url,
"searchbar_filters": OrderedDict(sorted(searchbar_filters.items())),
"searchbar_groupby": self._sale_get_searchbar_groupby(),
"searchbar_inputs": self._sale_get_searchbar_inputs(),
"searchbar_sortings": searchbar_sortings,
"sortby": sortby,
"groupby": groupby,
"search_in": search_in,
"search": search,
"filterby": filterby,
}
)
return values
我们在返回给页面数据时,groups_orders就是我们分组以后的订单数据,searchbar_groupby代表我们自定义的分组条件。groupby是我们要分组的字段。
分组条件
在门户页面中,分组条件不像后台那样简单写个xml配置就可以,而是需要额外的代码配置。接下来,我们来看一下如何自定义分组条件。
以上面的门户销售为例:
def _sale_get_searchbar_groupby(self):
"""
groupby orders in portal
"""
return {
"none": {"input": "none", "label": _("None")},
"date": {"input": "date_order", "label": _("Date")},
"partner_id": {"input": "partner_id", "label": _("Customer")},
"user_id": {"input": "state", "label": _("Salesperson")},
"team_id": {"input": "team_id", "label": _("Sales Team")},
}
门户的分组过滤功能配置由一个字典组成。外层的KEY代表的是分组的关键字,值代表的是在页面显示的label和输入参数input。
input会在_get_groupby_mapping方法中匹配到对应的分组字段值。
def _get_groupby_mapping(self):
"""
group by mapping
"""
return {
"date": "date_order",
"partner_id": "partner_id",
"user_id": "user_id",
"team_id": "team_id",
}
比如,分组条件中的partner_id,匹配到的字段是partner_id, 也就是使用partner_id进行分组。
分组条件的页面配置
最后,我们需要在页面中对分组的条件进行配置。
<t t-set="grouped_invoices_colspan" t-value="12"/>
<t t-if="grouped_invoices" t-call="portal.portal_table">
<t t-foreach="grouped_invoices" t-as="invoices">
<thead>
<tr t-if="groupby != 'none'" class="table-light">
<t t-set="invoice" t-value="invoices[0].sudo()" t-if="invoices" />
<th t-if="invoice and groupby == 'invoice_date'" t-attf-colspan="">
<em class="font-weight-normal text-muted">Invoice Date:</em>
<span t-field="invoice.invoice_date" />
</th>
<th t-if="invoice and groupby == 'partner_id'" t-attf-colspan="">
<em class="font-weight-normal text-muted">Partner:</em>
<span t-field="invoice.partner_id" />
</th>
<th t-if="invoice and groupby == 'user_id'" t-attf-colspan="">
<em class="font-weight-normal text-muted">Salesperson:</em>
<span t-field="invoice.user_id" />
</th>
</tr>
<tr t-if="groupby=='none'" class="active">
<th>Invoice #</th>
<th>Invoice Date</th>
<th class='d-none d-md-table-cell'>Due Date</th>
<th class="text-center">Status</th>
<th class="text-end">Amount Due</th>
</tr>
</thead>
<tbody>
...
</tbody>
</t>
</t>
</t>
在页面中,我们根据分组后的订单grouped_orders,进行循环遍历。
- 如果分组条件是None,那么就进行额外输出,直接讲分组单据使用原格式输出。
- 如果分组条件不为None,那么将相应的分组条件显示在每个分组订单行的上面。输出格式为: 条件:分组值。