Initial commit: Odoo 18.0-20251222 extra-addons
Some checks failed
pre-commit / pre-commit (push) Has been cancelled
tests / Detect unreleased dependencies (push) Has been cancelled
tests / test with OCB (push) Has been cancelled
tests / test with Odoo (push) Has been cancelled

This commit is contained in:
tocmo0nlord
2026-03-13 20:43:25 +00:00
parent 36e847a7df
commit adbe430761
9472 changed files with 1265727 additions and 0 deletions

86
base_partition/README.rst Executable file
View File

@@ -0,0 +1,86 @@
==============
Base Partition
==============
..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:505fafa7278c9732b9e8b76a4e69e5320eaae57addb3848ced966c35cad279ff
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
:target: https://odoo-community.org/page/development-status
:alt: Beta
.. |badge2| image:: https://img.shields.io/badge/licence-LGPL--3-blue.png
:target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html
:alt: License: LGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fserver--tools-lightgray.png?logo=github
:target: https://github.com/OCA/server-tools/tree/18.0/base_partition
:alt: OCA/server-tools
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/server-tools-18-0/server-tools-18-0-base_partition
:alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png
:target: https://runboat.odoo-community.org/builds?repo=OCA/server-tools&target_branch=18.0
:alt: Try me on Runboat
|badge1| |badge2| |badge3| |badge4| |badge5|
This module adds a partition(self, accessor) method to every model. It
accepts for accessor any parameter that would be accepted by mapped,
i.e. a string "field(.subfield)\*" or a function (lambda x: not x.b). It
returns a dictionary with keys that are equal to
set(record.mapped(accessor)), and with values that are recordsets (these
recordsets forming a partition of the initial recordset, conveniently).
So if we have a recordset (x \| y \| z ) such that x.f == True, y.f ==
z.f == False, then (x \| y \| z ).partition("f") == {True: x, False: (y
\| z)}.
**Table of contents**
.. contents::
:local:
Bug Tracker
===========
Bugs are tracked on `GitHub Issues <https://github.com/OCA/server-tools/issues>`_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us to smash it by providing a detailed and welcomed
`feedback <https://github.com/OCA/server-tools/issues/new?body=module:%20base_partition%0Aversion:%2018.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
Do not contact contributors directly about support or help with technical issues.
Credits
=======
Authors
-------
* Acsone SA/NV
Contributors
------------
- Nans Lefebvre <nans.lefebvre@acsone.eu>
- Hughes Damry <hughes.damry@acsone.eu>
Maintainers
-----------
This module is maintained by the OCA.
.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: https://odoo-community.org
OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.
This module is part of the `OCA/server-tools <https://github.com/OCA/server-tools/tree/18.0/base_partition>`_ project on GitHub.
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

1
base_partition/__init__.py Executable file
View File

@@ -0,0 +1 @@
from . import models

15
base_partition/__manifest__.py Executable file
View File

@@ -0,0 +1,15 @@
# Copyright 2020 Acsone (http://www.acsone.eu)
# Nans Lefebvre <nans.lefebvre@acsone.eu>
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
{
"name": "Base Partition",
"summary": "Base module that provide the partition method on all models",
"version": "18.0.1.0.0",
"category": "Uncategorized",
"website": "https://github.com/OCA/server-tools",
"author": "Acsone SA/NV, Odoo Community Association (OCA)",
"license": "LGPL-3",
"installable": True,
"depends": ["base"],
}

View File

@@ -0,0 +1,27 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * base_partition
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 18.0\n"
"Report-Msgid-Bugs-To: \n"
"Last-Translator: \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: base_partition
#: model:ir.model,name:base_partition.model_base
msgid "Base"
msgstr ""
#. module: base_partition
#. odoo-python
#: code:addons/base_partition/models/models.py:0
msgid ""
"Either set up a '_default_batch_size' on the model or provide a batch_size "
"parameter."
msgstr ""

32
base_partition/i18n/es.po Executable file
View File

@@ -0,0 +1,32 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * base_partition
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 16.0\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2023-12-07 18:34+0000\n"
"Last-Translator: Ivorra78 <informatica@totmaterial.es>\n"
"Language-Team: none\n"
"Language: es\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 4.17\n"
#. module: base_partition
#: model:ir.model,name:base_partition.model_base
msgid "Base"
msgstr "Base"
#. module: base_partition
#. odoo-python
#: code:addons/base_partition/models/models.py:0
msgid ""
"Either set up a '_default_batch_size' on the model or provide a batch_size "
"parameter."
msgstr ""
"Configure un '_default_batch_size' en el modelo o proporcione un parámetro "
"de tamaño de lote."

32
base_partition/i18n/fr_BE.pot Executable file
View File

@@ -0,0 +1,32 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * base_partition
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 16.0+e\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-04-24 15:38+0000\n"
"PO-Revision-Date: 2023-04-24 15:38+0000\n"
"Last-Translator: \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: base_partition
#: model:ir.model,name:base_partition.model_base
msgid "Base"
msgstr ""
#. module: base_partition
#. odoo-python
#: code:addons/base_partition/models/models.py:0
#, python-format
msgid ""
"Either set up a '_default_batch_size' on the model or provide a batch_size "
"parameter."
msgstr ""
"Définir '_default_batch_size' sur le modèle ou fournir une valeur de "
"batch_size en paramètre."

32
base_partition/i18n/it.po Executable file
View File

@@ -0,0 +1,32 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * base_partition
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 16.0\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2024-01-02 16:34+0000\n"
"Last-Translator: mymage <stefano.consolaro@mymage.it>\n"
"Language-Team: none\n"
"Language: it\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 4.17\n"
#. module: base_partition
#: model:ir.model,name:base_partition.model_base
msgid "Base"
msgstr "Base"
#. module: base_partition
#. odoo-python
#: code:addons/base_partition/models/models.py:0
msgid ""
"Either set up a '_default_batch_size' on the model or provide a batch_size "
"parameter."
msgstr ""
"Impostare un '_default_batch_size' nel modello o frnire un parametro "
"batch_size."

31
base_partition/i18n/zh_CN.po Executable file
View File

@@ -0,0 +1,31 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * base_partition
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 17.0\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2024-06-16 17:40+0000\n"
"Last-Translator: xtanuiha <feihu.zhang@live.com>\n"
"Language-Team: none\n"
"Language: zh_CN\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: nplurals=1; plural=0;\n"
"X-Generator: Weblate 4.17\n"
#. module: base_partition
#: model:ir.model,name:base_partition.model_base
msgid "Base"
msgstr "基础"
#. module: base_partition
#. odoo-python
#: code:addons/base_partition/models/models.py:0
msgid ""
"Either set up a '_default_batch_size' on the model or provide a batch_size "
"parameter."
msgstr ""
"要么在模型上设置一个'_default_batch_size'要么提供一个batch_size参数。"

View File

@@ -0,0 +1 @@
from . import models

63
base_partition/models/models.py Executable file
View File

@@ -0,0 +1,63 @@
# © 2020 Acsone (http://www.acsone.eu)
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
from odoo import _, models
from odoo.exceptions import UserError
class Base(models.AbstractModel):
_inherit = "base"
def partition(self, accessor):
"""Returns a dictionary forming a partition of self into a dictionary
value/recordset for each value obtained from the accessor.
The accessor itself can be either a string that can be passed to mapped,
or an arbitrary function.
Note that it is always at least as fast to pass a function,
hence the current implementation.
If we have a 'field.subfield' accessor such that subfield is not a relational
then the result is a list (not hashable). Then the str(key) are used.
In the general case a value could both not be hashable nor stringifiable,
in a which case this function would crash.
"""
partition = {}
if isinstance(accessor, str):
if "." not in accessor:
func = lambda r: r[accessor] # noqa: E731
else:
func = lambda r: r.mapped(accessor) # noqa: E731
else:
func = accessor
for record in self:
key = func(record)
if not key.__hash__:
key = str(key)
if key not in partition:
partition[key] = record
else:
partition[key] += record
return partition
def batch(self, batch_size=None):
"""Yield successive batches of size batch_size, or ."""
if not (batch_size or "_default_batch_size" in dir(self)):
raise UserError(
_(
"Either set up a '_default_batch_size' on the model"
" or provide a batch_size parameter."
)
)
batch_size = batch_size or self._default_batch_size
for i in range(0, len(self), batch_size):
yield self[i : i + batch_size]
def read_per_record(self, fields=None, load="_classic_read"):
result = {}
data_list = self.read(fields=fields, load=load)
for d in data_list:
key = d.pop("id")
result[key] = d
return result

3
base_partition/pyproject.toml Executable file
View File

@@ -0,0 +1,3 @@
[build-system]
requires = ["whool"]
build-backend = "whool.buildapi"

View File

@@ -0,0 +1,2 @@
- Nans Lefebvre \<<nans.lefebvre@acsone.eu>\>
- Hughes Damry \<<hughes.damry@acsone.eu>\>

View File

@@ -0,0 +1,10 @@
This module adds a partition(self, accessor) method to every model. It
accepts for accessor any parameter that would be accepted by mapped,
i.e. a string "field(.subfield)\*" or a function (lambda x: not x.b). It
returns a dictionary with keys that are equal to
set(record.mapped(accessor)), and with values that are recordsets (these
recordsets forming a partition of the initial recordset, conveniently).
So if we have a recordset (x \| y \| z ) such that x.f == True, y.f ==
z.f == False, then (x \| y \| z ).partition("f") == {True: x, False: (y
\| z)}.

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

View File

@@ -0,0 +1,432 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils: https://docutils.sourceforge.io/" />
<title>Base Partition</title>
<style type="text/css">
/*
:Author: David Goodger (goodger@python.org)
:Id: $Id: html4css1.css 9511 2024-01-13 09:50:07Z milde $
:Copyright: This stylesheet has been placed in the public domain.
Default cascading style sheet for the HTML output of Docutils.
Despite the name, some widely supported CSS2 features are used.
See https://docutils.sourceforge.io/docs/howto/html-stylesheets.html for how to
customize this style sheet.
*/
/* used to remove borders from tables and images */
.borderless, table.borderless td, table.borderless th {
border: 0 }
table.borderless td, table.borderless th {
/* Override padding for "table.docutils td" with "! important".
The right padding separates the table cells. */
padding: 0 0.5em 0 0 ! important }
.first {
/* Override more specific margin styles with "! important". */
margin-top: 0 ! important }
.last, .with-subtitle {
margin-bottom: 0 ! important }
.hidden {
display: none }
.subscript {
vertical-align: sub;
font-size: smaller }
.superscript {
vertical-align: super;
font-size: smaller }
a.toc-backref {
text-decoration: none ;
color: black }
blockquote.epigraph {
margin: 2em 5em ; }
dl.docutils dd {
margin-bottom: 0.5em }
object[type="image/svg+xml"], object[type="application/x-shockwave-flash"] {
overflow: hidden;
}
/* Uncomment (and remove this text!) to get bold-faced definition list terms
dl.docutils dt {
font-weight: bold }
*/
div.abstract {
margin: 2em 5em }
div.abstract p.topic-title {
font-weight: bold ;
text-align: center }
div.admonition, div.attention, div.caution, div.danger, div.error,
div.hint, div.important, div.note, div.tip, div.warning {
margin: 2em ;
border: medium outset ;
padding: 1em }
div.admonition p.admonition-title, div.hint p.admonition-title,
div.important p.admonition-title, div.note p.admonition-title,
div.tip p.admonition-title {
font-weight: bold ;
font-family: sans-serif }
div.attention p.admonition-title, div.caution p.admonition-title,
div.danger p.admonition-title, div.error p.admonition-title,
div.warning p.admonition-title, .code .error {
color: red ;
font-weight: bold ;
font-family: sans-serif }
/* Uncomment (and remove this text!) to get reduced vertical space in
compound paragraphs.
div.compound .compound-first, div.compound .compound-middle {
margin-bottom: 0.5em }
div.compound .compound-last, div.compound .compound-middle {
margin-top: 0.5em }
*/
div.dedication {
margin: 2em 5em ;
text-align: center ;
font-style: italic }
div.dedication p.topic-title {
font-weight: bold ;
font-style: normal }
div.figure {
margin-left: 2em ;
margin-right: 2em }
div.footer, div.header {
clear: both;
font-size: smaller }
div.line-block {
display: block ;
margin-top: 1em ;
margin-bottom: 1em }
div.line-block div.line-block {
margin-top: 0 ;
margin-bottom: 0 ;
margin-left: 1.5em }
div.sidebar {
margin: 0 0 0.5em 1em ;
border: medium outset ;
padding: 1em ;
background-color: #ffffee ;
width: 40% ;
float: right ;
clear: right }
div.sidebar p.rubric {
font-family: sans-serif ;
font-size: medium }
div.system-messages {
margin: 5em }
div.system-messages h1 {
color: red }
div.system-message {
border: medium outset ;
padding: 1em }
div.system-message p.system-message-title {
color: red ;
font-weight: bold }
div.topic {
margin: 2em }
h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
margin-top: 0.4em }
h1.title {
text-align: center }
h2.subtitle {
text-align: center }
hr.docutils {
width: 75% }
img.align-left, .figure.align-left, object.align-left, table.align-left {
clear: left ;
float: left ;
margin-right: 1em }
img.align-right, .figure.align-right, object.align-right, table.align-right {
clear: right ;
float: right ;
margin-left: 1em }
img.align-center, .figure.align-center, object.align-center {
display: block;
margin-left: auto;
margin-right: auto;
}
table.align-center {
margin-left: auto;
margin-right: auto;
}
.align-left {
text-align: left }
.align-center {
clear: both ;
text-align: center }
.align-right {
text-align: right }
/* reset inner alignment in figures */
div.align-right {
text-align: inherit }
/* div.align-center * { */
/* text-align: left } */
.align-top {
vertical-align: top }
.align-middle {
vertical-align: middle }
.align-bottom {
vertical-align: bottom }
ol.simple, ul.simple {
margin-bottom: 1em }
ol.arabic {
list-style: decimal }
ol.loweralpha {
list-style: lower-alpha }
ol.upperalpha {
list-style: upper-alpha }
ol.lowerroman {
list-style: lower-roman }
ol.upperroman {
list-style: upper-roman }
p.attribution {
text-align: right ;
margin-left: 50% }
p.caption {
font-style: italic }
p.credits {
font-style: italic ;
font-size: smaller }
p.label {
white-space: nowrap }
p.rubric {
font-weight: bold ;
font-size: larger ;
color: maroon ;
text-align: center }
p.sidebar-title {
font-family: sans-serif ;
font-weight: bold ;
font-size: larger }
p.sidebar-subtitle {
font-family: sans-serif ;
font-weight: bold }
p.topic-title {
font-weight: bold }
pre.address {
margin-bottom: 0 ;
margin-top: 0 ;
font: inherit }
pre.literal-block, pre.doctest-block, pre.math, pre.code {
margin-left: 2em ;
margin-right: 2em }
pre.code .ln { color: gray; } /* line numbers */
pre.code, code { background-color: #eeeeee }
pre.code .comment, code .comment { color: #5C6576 }
pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold }
pre.code .literal.string, code .literal.string { color: #0C5404 }
pre.code .name.builtin, code .name.builtin { color: #352B84 }
pre.code .deleted, code .deleted { background-color: #DEB0A1}
pre.code .inserted, code .inserted { background-color: #A3D289}
span.classifier {
font-family: sans-serif ;
font-style: oblique }
span.classifier-delimiter {
font-family: sans-serif ;
font-weight: bold }
span.interpreted {
font-family: sans-serif }
span.option {
white-space: nowrap }
span.pre {
white-space: pre }
span.problematic, pre.problematic {
color: red }
span.section-subtitle {
/* font-size relative to parent (h1..h6 element) */
font-size: 80% }
table.citation {
border-left: solid 1px gray;
margin-left: 1px }
table.docinfo {
margin: 2em 4em }
table.docutils {
margin-top: 0.5em ;
margin-bottom: 0.5em }
table.footnote {
border-left: solid 1px black;
margin-left: 1px }
table.docutils td, table.docutils th,
table.docinfo td, table.docinfo th {
padding-left: 0.5em ;
padding-right: 0.5em ;
vertical-align: top }
table.docutils th.field-name, table.docinfo th.docinfo-name {
font-weight: bold ;
text-align: left ;
white-space: nowrap ;
padding-left: 0 }
/* "booktabs" style (no vertical lines) */
table.docutils.booktabs {
border: 0px;
border-top: 2px solid;
border-bottom: 2px solid;
border-collapse: collapse;
}
table.docutils.booktabs * {
border: 0px;
}
table.docutils.booktabs th {
border-bottom: thin solid;
text-align: left;
}
h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
font-size: 100% }
ul.auto-toc {
list-style-type: none }
</style>
</head>
<body>
<div class="document" id="base-partition">
<h1 class="title">Base Partition</h1>
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:505fafa7278c9732b9e8b76a4e69e5320eaae57addb3848ced966c35cad279ff
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<p><a class="reference external image-reference" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external image-reference" href="http://www.gnu.org/licenses/lgpl-3.0-standalone.html"><img alt="License: LGPL-3" src="https://img.shields.io/badge/licence-LGPL--3-blue.png" /></a> <a class="reference external image-reference" href="https://github.com/OCA/server-tools/tree/18.0/base_partition"><img alt="OCA/server-tools" src="https://img.shields.io/badge/github-OCA%2Fserver--tools-lightgray.png?logo=github" /></a> <a class="reference external image-reference" href="https://translation.odoo-community.org/projects/server-tools-18-0/server-tools-18-0-base_partition"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external image-reference" href="https://runboat.odoo-community.org/builds?repo=OCA/server-tools&amp;target_branch=18.0"><img alt="Try me on Runboat" src="https://img.shields.io/badge/runboat-Try%20me-875A7B.png" /></a></p>
<p>This module adds a partition(self, accessor) method to every model. It
accepts for accessor any parameter that would be accepted by mapped,
i.e. a string “field(.subfield)*” or a function (lambda x: not x.b). It
returns a dictionary with keys that are equal to
set(record.mapped(accessor)), and with values that are recordsets (these
recordsets forming a partition of the initial recordset, conveniently).</p>
<p>So if we have a recordset (x | y | z ) such that x.f == True, y.f ==
z.f == False, then (x | y | z ).partition(“f”) == {True: x, False: (y
| z)}.</p>
<p><strong>Table of contents</strong></p>
<div class="contents local topic" id="contents">
<ul class="simple">
<li><a class="reference internal" href="#bug-tracker" id="toc-entry-1">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="toc-entry-2">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="toc-entry-3">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="toc-entry-4">Contributors</a></li>
<li><a class="reference internal" href="#maintainers" id="toc-entry-5">Maintainers</a></li>
</ul>
</li>
</ul>
</div>
<div class="section" id="bug-tracker">
<h1><a class="toc-backref" href="#toc-entry-1">Bug Tracker</a></h1>
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/server-tools/issues">GitHub Issues</a>.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us to smash it by providing a detailed and welcomed
<a class="reference external" href="https://github.com/OCA/server-tools/issues/new?body=module:%20base_partition%0Aversion:%2018.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
<p>Do not contact contributors directly about support or help with technical issues.</p>
</div>
<div class="section" id="credits">
<h1><a class="toc-backref" href="#toc-entry-2">Credits</a></h1>
<div class="section" id="authors">
<h2><a class="toc-backref" href="#toc-entry-3">Authors</a></h2>
<ul class="simple">
<li>Acsone SA/NV</li>
</ul>
</div>
<div class="section" id="contributors">
<h2><a class="toc-backref" href="#toc-entry-4">Contributors</a></h2>
<ul class="simple">
<li>Nans Lefebvre &lt;<a class="reference external" href="mailto:nans.lefebvre&#64;acsone.eu">nans.lefebvre&#64;acsone.eu</a>&gt;</li>
<li>Hughes Damry &lt;<a class="reference external" href="mailto:hughes.damry&#64;acsone.eu">hughes.damry&#64;acsone.eu</a>&gt;</li>
</ul>
</div>
<div class="section" id="maintainers">
<h2><a class="toc-backref" href="#toc-entry-5">Maintainers</a></h2>
<p>This module is maintained by the OCA.</p>
<a class="reference external image-reference" href="https://odoo-community.org">
<img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" />
</a>
<p>OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.</p>
<p>This module is part of the <a class="reference external" href="https://github.com/OCA/server-tools/tree/18.0/base_partition">OCA/server-tools</a> project on GitHub.</p>
<p>You are welcome to contribute. To learn how please visit <a class="reference external" href="https://odoo-community.org/page/Contribute">https://odoo-community.org/page/Contribute</a>.</p>
</div>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1 @@
from . import test_partition

View File

@@ -0,0 +1,134 @@
# Copyright 2017 ACSONE SA/NV
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl).
import functools
import math
from odoo.exceptions import UserError
from odoo.fields import Command
from odoo.tests.common import TransactionCase
class TestPartition(TransactionCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.Category = cls.env["res.partner.category"]
cls.c1 = cls.Category.create({"name": "c1"})
cls.c2 = cls.Category.create({"name": "c2"})
cls.c3 = cls.Category.create({"name": "c3"})
cls.Partner = cls.env["res.partner"]
cls.parent1 = cls.Partner.create({"name": "parent1"})
cls.parent2 = cls.Partner.create({"name": "parent2"})
cls.child1 = cls.Partner.create({"name": "child1"})
cls.child2 = cls.Partner.create({"name": "child2"})
cls.child3 = cls.Partner.create({"name": "child3"})
cls.x = cls.Partner.create(
{
"name": "x",
"employee": True,
"category_id": [Command.set([cls.c1.id, cls.c2.id])],
"child_ids": [Command.set([cls.child1.id, cls.child2.id])],
"parent_id": cls.parent1.id,
}
)
cls.y = cls.Partner.create(
{
"name": "y",
"employee": False,
"category_id": [Command.set([cls.c2.id, cls.c3.id])],
"child_ids": [Command.set([cls.child2.id, cls.child3.id])],
"parent_id": cls.parent2.id,
}
)
cls.z = cls.Partner.create(
{
"name": "z",
"employee": False,
"category_id": [Command.set([cls.c1.id, cls.c3.id])],
"child_ids": [Command.set([cls.child1.id, cls.child3.id])],
"parent_id": cls.parent2.id,
}
)
cls.xyz = cls.x + cls.y + cls.z
def test_partition_many2many(self):
self.partition_field_test("category_id")
def test_partition_many2one(self):
self.partition_field_test("parent_id")
def test_partition_one2many(self):
self.partition_field_test("child_ids")
def test_partition_boolean(self):
self.partition_field_test("employee", relational=False)
def test_partition_dotdot_relational(self):
self.partition_field_test("parent_id.category_id", relational=True, dotdot=True)
def test_partition_dotdot_nonrelational(self):
self.partition_field_test("parent_id.name", relational=False, dotdot=True)
def partition_field_test(self, field_name, relational=True, dotdot=False):
"""To check that we have a partition we need to check that:
- all field values are keys
- the set of all keys is the same
"""
partition = self.xyz.partition(field_name)
if relational:
values = [s.mapped(field_name) for s in self.xyz]
else:
values = self.xyz.mapped(field_name)
if dotdot and not relational:
values = [str(s.mapped(field_name)) for s in self.xyz]
self.assertEqual(set(partition.keys()), set(values))
records = functools.reduce(sum, partition.values())
self.assertEqual(self.xyz, records) # we get the same recordset
def test_partition_lambda(self):
"""Test an arbitrary predicate."""
partition = (self.c1 | self.c2).partition(lambda c: "2" in c.name)
self.assertEqual(set(partition.keys()), {True, False})
def test_batch(self):
"""The sum of all batches should be the original recordset;
an empty recordset should return no batch;
without a batch parameter, the model's _default_batch_size should be used.
"""
records = self.xyz
batch_size = 2
assert len(records) # only makes sense with nonempty recordset
batches = list(records.batch(batch_size))
self.assertEqual(len(batches), math.ceil(len(records) / batch_size))
for batch in batches[:-1]:
self.assertEqual(len(batch), batch_size)
last_batch_size = len(records) % batch_size or batch_size
self.assertEqual(len(batches[-1]), last_batch_size)
self.assertEqual(functools.reduce(sum, batches), records)
empty_recordset = records.browse()
no_batches = list(empty_recordset.batch(batch_size))
self.assertEqual(no_batches, [])
with self.assertRaises(UserError):
list(records.batch())
records.__class__._default_batch_size = batch_size
batches_from_default = list(records.batch())
self.assertEqual(batches_from_default, batches)
def test_read_per_record(self):
categories = self.c1 | self.c2 | self.c3
field_list = ["name"]
data = categories.read_per_record(field_list)
self.assertEqual(len(data), len(categories))
for record in categories:
self.assertTrue(record.id in data)
record_data = data[record.id]
self.assertEqual(list(record_data.keys()), field_list)