Merge PR #2751 into 16.0

Signed-off-by pedrobaeza
pull/2725/merge
OCA-git-bot 2023-11-07 14:12:06 +00:00
commit 7f1de31e95
22 changed files with 1284 additions and 0 deletions

View File

@ -0,0 +1,122 @@
====================
Base Sequence Option
====================
..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:e602f657c96c579338dde96a27ea3d5f49cb35292dd1543bf6bf88cf196d560e
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |badge1| image:: https://img.shields.io/badge/maturity-Alpha-red.png
:target: https://odoo-community.org/page/development-status
:alt: Alpha
.. |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/16.0/base_sequence_option
: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-16-0/server-tools-16-0-base_sequence_option
: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=16.0
:alt: Try me on Runboat
|badge1| |badge2| |badge3| |badge4| |badge5|
This module allow user to add optional sequences to some document model.
On which sequence is used, is based on domain matching with document values
(and original sequence will be bypassed).
For example, it is now possible to,
* Avoid using Odoo automatic sequence on invoice and vendor bill with old style sequence.
* Customer payment and vendor payment to run on different sequence.
* Assign different sales order sequence based on customer region.
This is a base module and does nothing by itself. Following are modules
that will allow managing sequence options for each type of documents, I.e.,
* Purchase Order: purchase_sequence_option
* Invoice / Bill / Refund / Payment: account_sequence_option
* Others: create a new module with few lines of code
.. IMPORTANT::
This is an alpha version, the data model and design can change at any time without warning.
Only for development or testing purpose, do not use in production.
`More details on development status <https://odoo-community.org/page/development-status>`_
**Table of contents**
.. contents::
:local:
Usage
=====
To use this module, you need to:
1. Go to *Settings > Technical > Sequences & Identifier > Manage Sequence Options*.
2. Based on extended module installed, different document types will be listed, i.e., Purchase Order.
3. Activite "Use sequence options" to use, if not, fall back to normal sequence.
4. For each option, provide,
* Name: i.e., Customer Invoice for Cust A., Customer Payment, etc.
* Apply On: a filter domain to test whether a document match this option.
* Sequence: select underlining sequence to perform
**Note:**
* If no options matches the document, fall back to normal sequence.
* If there are multiple sequence options that match same document, error will be raised.
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_sequence_option%0Aversion:%2016.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
~~~~~~~
* Ecosoft
Contributors
~~~~~~~~~~~~
* Kitti U. <kittiu@ecosoft.co.th>
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.
.. |maintainer-kittiu| image:: https://github.com/kittiu.png?size=40px
:target: https://github.com/kittiu
:alt: kittiu
Current `maintainer <https://odoo-community.org/page/maintainer-role>`__:
|maintainer-kittiu|
This module is part of the `OCA/server-tools <https://github.com/OCA/server-tools/tree/16.0/base_sequence_option>`_ project on GitHub.
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

View File

@ -0,0 +1,4 @@
# Copyright 2021 Ecosoft Co., Ltd. (http://ecosoft.co.th)
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
from . import models

View File

@ -0,0 +1,22 @@
# Copyright 2021 Ecosoft Co., Ltd. (http://ecosoft.co.th)
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
{
"name": "Base Sequence Option",
"summary": "Alternative sequence options for specific models",
"version": "16.0.1.0.0",
"author": "Ecosoft, Odoo Community Association (OCA)",
"maintainers": ["kittiu"],
"development_status": "Alpha",
"website": "https://github.com/OCA/server-tools",
"category": "Tools",
"depends": ["base"],
"external_dependencies": {"python": ["odoo_test_helper"]},
"data": [
"security/ir.model.access.csv",
"security/sequence_option_security.xml",
"views/sequence_option_view.xml",
],
"license": "LGPL-3",
"installable": True,
}

View File

@ -0,0 +1,197 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * base_sequence_option
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 15.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_sequence_option
#: model:ir.model.fields,field_description:base_sequence_option.field_ir_sequence_option_line__filter_domain
msgid "Apply On"
msgstr ""
#. module: base_sequence_option
#: model:ir.model.fields,field_description:base_sequence_option.field_ir_sequence_option__model
#: model:ir.model.fields,field_description:base_sequence_option.field_ir_sequence_option_line__model
msgid "Apply On Model"
msgstr ""
#. module: base_sequence_option
#: model:ir.model.fields,field_description:base_sequence_option.field_ir_sequence_option_line__base_id
msgid "Base"
msgstr ""
#. module: base_sequence_option
#: model:ir.model.fields,field_description:base_sequence_option.field_ir_sequence_option__company_id
#: model:ir.model.fields,field_description:base_sequence_option.field_ir_sequence_option_line__company_id
msgid "Company"
msgstr ""
#. module: base_sequence_option
#: model:ir.model.fields,help:base_sequence_option.field_ir_sequence_option__company_id
#: model:ir.model.fields,help:base_sequence_option.field_ir_sequence_option_line__company_id
msgid "Company related to this sequence option"
msgstr ""
#. module: base_sequence_option
#: model:ir.model.fields,field_description:base_sequence_option.field_ir_sequence_option__create_uid
#: model:ir.model.fields,field_description:base_sequence_option.field_ir_sequence_option_line__create_uid
msgid "Created by"
msgstr ""
#. module: base_sequence_option
#: model:ir.model.fields,field_description:base_sequence_option.field_ir_sequence_option__create_date
#: model:ir.model.fields,field_description:base_sequence_option.field_ir_sequence_option_line__create_date
msgid "Created on"
msgstr ""
#. module: base_sequence_option
#: model:ir.model.fields,field_description:base_sequence_option.field_ir_sequence_option_line__name
msgid "Description"
msgstr ""
#. module: base_sequence_option
#: model:ir.model.fields,field_description:base_sequence_option.field_ir_sequence_option__display_name
#: model:ir.model.fields,field_description:base_sequence_option.field_ir_sequence_option_line__display_name
msgid "Display Name"
msgstr ""
#. module: base_sequence_option
#: model_terms:ir.ui.view,arch_db:base_sequence_option.view_ir_sequence_option_form
msgid "Doctype Sequence"
msgstr ""
#. module: base_sequence_option
#: model:ir.model.fields,help:base_sequence_option.field_ir_sequence_option_line__filter_domain
msgid "Find matching option by document values"
msgstr ""
#. module: base_sequence_option
#: model:ir.model.fields,field_description:base_sequence_option.field_ir_sequence_option__id
#: model:ir.model.fields,field_description:base_sequence_option.field_ir_sequence_option_line__id
msgid "ID"
msgstr ""
#. module: base_sequence_option
#: model:ir.model.fields,help:base_sequence_option.field_ir_sequence_option__use_sequence_option
#: model:ir.model.fields,help:base_sequence_option.field_ir_sequence_option_line__use_sequence_option
msgid ""
"If checked, Odoo will try to find the new matching sequence first, if not "
"found, fall back to use the original Odoo sequence."
msgstr ""
#. module: base_sequence_option
#: model:ir.model.fields,field_description:base_sequence_option.field_ir_sequence_option_line__implementation
msgid "Implementation"
msgstr ""
#. module: base_sequence_option
#: model:ir.model.fields,field_description:base_sequence_option.field_ir_sequence_option____last_update
#: model:ir.model.fields,field_description:base_sequence_option.field_ir_sequence_option_line____last_update
msgid "Last Modified on"
msgstr ""
#. module: base_sequence_option
#: model:ir.model.fields,field_description:base_sequence_option.field_ir_sequence_option__write_uid
#: model:ir.model.fields,field_description:base_sequence_option.field_ir_sequence_option_line__write_uid
msgid "Last Updated by"
msgstr ""
#. module: base_sequence_option
#: model:ir.model.fields,field_description:base_sequence_option.field_ir_sequence_option__write_date
#: model:ir.model.fields,field_description:base_sequence_option.field_ir_sequence_option_line__write_date
msgid "Last Updated on"
msgstr ""
#. module: base_sequence_option
#: model:ir.actions.act_window,name:base_sequence_option.action_ir_sequence_option
#: model:ir.ui.menu,name:base_sequence_option.menu_ir_sequence_option
msgid "Manage Sequence Options"
msgstr ""
#. module: base_sequence_option
#: model_terms:ir.ui.view,arch_db:base_sequence_option.view_ir_sequence_option_form
msgid "Matching Domain"
msgstr ""
#. module: base_sequence_option
#: code:addons/base_sequence_option/models/ir_sequence_option.py:0
#, python-format
msgid "Multiple optional sequences found for this model!"
msgstr ""
#. module: base_sequence_option
#: model:ir.model.fields,field_description:base_sequence_option.field_ir_sequence_option__name
#: model_terms:ir.ui.view,arch_db:base_sequence_option.view_ir_sequence_option_form
msgid "Name"
msgstr ""
#. module: base_sequence_option
#: model:ir.model.fields,field_description:base_sequence_option.field_ir_sequence_option_line__prefix
msgid "Prefix"
msgstr ""
#. module: base_sequence_option
#: model:ir.model.fields,help:base_sequence_option.field_ir_sequence_option_line__prefix
msgid "Prefix value of the record for the sequence"
msgstr ""
#. module: base_sequence_option
#: model:ir.model,name:base_sequence_option.model_ir_sequence
#: model:ir.model.fields,field_description:base_sequence_option.field_ir_sequence_option_line__sequence_id
msgid "Sequence"
msgstr ""
#. module: base_sequence_option
#: model:ir.model,name:base_sequence_option.model_ir_sequence_option
msgid "Sequence Option Base Model"
msgstr ""
#. module: base_sequence_option
#: model:ir.model,name:base_sequence_option.model_ir_sequence_option_line
msgid "Sequence Option Line"
msgstr ""
#. module: base_sequence_option
#: model:ir.model.fields,field_description:base_sequence_option.field_ir_sequence_option__option_ids
msgid "Sequence Options"
msgstr ""
#. module: base_sequence_option
#: model:ir.model.fields,field_description:base_sequence_option.field_ir_sequence_option_line__suffix
msgid "Suffix"
msgstr ""
#. module: base_sequence_option
#: model:ir.model.fields,help:base_sequence_option.field_ir_sequence_option_line__suffix
msgid "Suffix value of the record for the sequence"
msgstr ""
#. module: base_sequence_option
#: model_terms:ir.ui.view,arch_db:base_sequence_option.view_ir_sequence_option_form
msgid "Use Sequence"
msgstr ""
#. module: base_sequence_option
#: model:ir.model.fields,field_description:base_sequence_option.field_ir_sequence_option__use_sequence_option
#: model:ir.model.fields,field_description:base_sequence_option.field_ir_sequence_option_line__use_sequence_option
msgid "Use sequence options"
msgstr ""
#. module: base_sequence_option
#: model:ir.model.fields,help:base_sequence_option.field_ir_sequence_option_line__implementation
msgid ""
"While assigning a sequence number to a record, the 'no gap' sequence "
"implementation ensures that each previous sequence number has been assigned "
"already. While this sequence implementation will not skip any sequence "
"number upon assignment, there can still be gaps in the sequence if records "
"are deleted. The 'no gap' implementation is slower than the standard one."
msgstr ""

View File

@ -0,0 +1,5 @@
# Copyright 2021 Ecosoft Co., Ltd. (http://ecosoft.co.th)
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
from . import ir_sequence_option
from . import ir_sequence

View File

@ -0,0 +1,22 @@
# Copyright 2021 Ecosoft Co., Ltd. (http://ecosoft.co.th)
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
from odoo import api, models
class IrSequence(models.Model):
_inherit = "ir.sequence"
def next_by_id(self, sequence_date=None):
sequence_id = self.env.context.get("sequence_option_id", False)
if sequence_id:
self = self.browse(sequence_id)
return super().next_by_id(sequence_date=sequence_date)
@api.model
def next_by_code(self, sequence_code, sequence_date=None):
sequence_id = self.env.context.get("sequence_option_id", False)
if sequence_id:
self = self.browse(sequence_id)
return super().next_by_id(sequence_date=sequence_date)
return super().next_by_code(sequence_code, sequence_date=sequence_date)

View File

@ -0,0 +1,124 @@
# Copyright 2021 Ecosoft Co., Ltd. (http://ecosoft.co.th)
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
from odoo import _, fields, models
from odoo.exceptions import ValidationError
from odoo.tools import safe_eval
class IrSequenceOption(models.Model):
_name = "ir.sequence.option"
_description = "Sequence Option Base Model"
_check_company_auto = True
name = fields.Char(readonly=True)
use_sequence_option = fields.Boolean(
string="Use sequence options",
help="If checked, Odoo will try to find the new matching sequence first, "
"if not found, fall back to use the original Odoo sequence.",
)
model = fields.Selection(
selection=[],
string="Apply On Model",
required=True,
readonly=False,
index=True,
)
option_ids = fields.One2many(
string="Sequence Options",
comodel_name="ir.sequence.option.line",
inverse_name="base_id",
)
company_id = fields.Many2one(
comodel_name="res.company",
string="Company",
required=True,
readonly=False,
index=True,
default=lambda self: self.env.company,
help="Company related to this sequence option",
)
class IrSequenceOptionLine(models.Model):
_name = "ir.sequence.option.line"
_description = "Sequence Option Line"
_check_company_auto = True
base_id = fields.Many2one(
comodel_name="ir.sequence.option",
index=True,
required=True,
ondelete="cascade",
)
name = fields.Char(
string="Description",
required=True,
)
model = fields.Selection(
related="base_id.model",
store=True,
readonly=True,
)
use_sequence_option = fields.Boolean(
related="base_id.use_sequence_option",
store=True,
)
filter_domain = fields.Char(
string="Apply On",
default="[]",
help="Find matching option by document values",
)
sequence_id = fields.Many2one(
comodel_name="ir.sequence",
string="Sequence",
required=True,
check_company=True,
)
prefix = fields.Char(
related="sequence_id.prefix",
string="Prefix",
readonly=True,
)
suffix = fields.Char(
related="sequence_id.suffix",
string="Suffix",
readonly=True,
)
implementation = fields.Selection(
related="sequence_id.implementation",
string="Implementation",
readonly=True,
)
company_id = fields.Many2one(
comodel_name="res.company",
related="base_id.company_id",
store=True,
)
def get_model_options(self, model):
return self.sudo().search(
[("use_sequence_option", "=", True), ("model", "=", model)]
)
def get_sequence(self, record, options=False):
"""
Find sequence option that match the record values
"""
if not options:
options = self.get_model_options(record._name)
# multi-company
company = (
hasattr(record, "company_id") and record.company_id or self.env.company
)
options = options.filtered(lambda l: l.company_id == company)
sequence = self.env["ir.sequence"]
for option in options:
domain = safe_eval.safe_eval(option.filter_domain)
if record.sudo().filtered_domain(domain):
if sequence: # Do not allow > 1 match
raise ValidationError(
_("Multiple optional sequences found for this model!")
)
sequence = option.sequence_id
return sequence

View File

@ -0,0 +1 @@
* Kitti U. <kittiu@ecosoft.co.th>

View File

@ -0,0 +1,16 @@
This module allow user to add optional sequences to some document model.
On which sequence is used, is based on domain matching with document values
(and original sequence will be bypassed).
For example, it is now possible to,
* Avoid using Odoo automatic sequence on invoice and vendor bill with old style sequence.
* Customer payment and vendor payment to run on different sequence.
* Assign different sales order sequence based on customer region.
This is a base module and does nothing by itself. Following are modules
that will allow managing sequence options for each type of documents, I.e.,
* Purchase Order: purchase_sequence_option
* Invoice / Bill / Refund / Payment: account_sequence_option
* Others: create a new module with few lines of code

View File

@ -0,0 +1,14 @@
To use this module, you need to:
1. Go to *Settings > Technical > Sequences & Identifier > Manage Sequence Options*.
2. Based on extended module installed, different document types will be listed, i.e., Purchase Order.
3. Activite "Use sequence options" to use, if not, fall back to normal sequence.
4. For each option, provide,
* Name: i.e., Customer Invoice for Cust A., Customer Payment, etc.
* Apply On: a filter domain to test whether a document match this option.
* Sequence: select underlining sequence to perform
**Note:**
* If no options matches the document, fall back to normal sequence.
* If there are multiple sequence options that match same document, error will be raised.

View File

@ -0,0 +1,5 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_ir_sequence_option_line,access_ir_sequence_option_line,model_ir_sequence_option_line,base.group_user,1,0,0,0
access_ir_sequence_option_line_system,access_ir_sequence_option_line_system,model_ir_sequence_option_line,base.group_system,1,1,1,1
access_ir_sequence_option,access_ir_sequence_option,model_ir_sequence_option,base.group_user,1,0,0,0
access_ir_sequence_option_system,access_ir_sequence_option_system,model_ir_sequence_option,base.group_system,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_ir_sequence_option_line access_ir_sequence_option_line model_ir_sequence_option_line base.group_user 1 0 0 0
3 access_ir_sequence_option_line_system access_ir_sequence_option_line_system model_ir_sequence_option_line base.group_system 1 1 1 1
4 access_ir_sequence_option access_ir_sequence_option model_ir_sequence_option base.group_user 1 0 0 0
5 access_ir_sequence_option_system access_ir_sequence_option_system model_ir_sequence_option base.group_system 1 1 1 1

View File

@ -0,0 +1,18 @@
<odoo noupdate="1">
<record model="ir.rule" id="ir_sequence_option_multi_company_rule">
<field name="name">Sequence Option: multi-company</field>
<field name="model_id" ref="model_ir_sequence_option" />
<field name="global" eval="True" />
<field name="domain_force">
[('company_id', 'in', company_ids)]
</field>
</record>
<record model="ir.rule" id="ir_sequence_option_line_multi_company_rule">
<field name="name">Sequence Option Line: multi-company</field>
<field name="model_id" ref="model_ir_sequence_option_line" />
<field name="global" eval="True" />
<field name="domain_force">
[('company_id', 'in', company_ids)]
</field>
</record>
</odoo>

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

View File

@ -0,0 +1,469 @@
<?xml version="1.0" encoding="utf-8"?>
<!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 Sequence Option</title>
<style type="text/css">
/*
:Author: David Goodger (goodger@python.org)
:Id: $Id: html4css1.css 8954 2022-01-20 10:10:25Z milde $
:Copyright: This stylesheet has been placed in the public domain.
Default cascading style sheet for the HTML output of Docutils.
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: grey; } /* 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 {
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-sequence-option">
<h1 class="title">Base Sequence Option</h1>
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:e602f657c96c579338dde96a27ea3d5f49cb35292dd1543bf6bf88cf196d560e
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<p><a class="reference external image-reference" href="https://odoo-community.org/page/development-status"><img alt="Alpha" src="https://img.shields.io/badge/maturity-Alpha-red.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/16.0/base_sequence_option"><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-16-0/server-tools-16-0-base_sequence_option"><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=16.0"><img alt="Try me on Runboat" src="https://img.shields.io/badge/runboat-Try%20me-875A7B.png" /></a></p>
<p>This module allow user to add optional sequences to some document model.
On which sequence is used, is based on domain matching with document values
(and original sequence will be bypassed).</p>
<p>For example, it is now possible to,</p>
<ul class="simple">
<li>Avoid using Odoo automatic sequence on invoice and vendor bill with old style sequence.</li>
<li>Customer payment and vendor payment to run on different sequence.</li>
<li>Assign different sales order sequence based on customer region.</li>
</ul>
<p>This is a base module and does nothing by itself. Following are modules
that will allow managing sequence options for each type of documents, I.e.,</p>
<ul class="simple">
<li>Purchase Order: purchase_sequence_option</li>
<li>Invoice / Bill / Refund / Payment: account_sequence_option</li>
<li>Others: create a new module with few lines of code</li>
</ul>
<div class="admonition important">
<p class="first admonition-title">Important</p>
<p class="last">This is an alpha version, the data model and design can change at any time without warning.
Only for development or testing purpose, do not use in production.
<a class="reference external" href="https://odoo-community.org/page/development-status">More details on development status</a></p>
</div>
<p><strong>Table of contents</strong></p>
<div class="contents local topic" id="contents">
<ul class="simple">
<li><a class="reference internal" href="#usage" id="toc-entry-1">Usage</a></li>
<li><a class="reference internal" href="#bug-tracker" id="toc-entry-2">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="toc-entry-3">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="toc-entry-4">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="toc-entry-5">Contributors</a></li>
<li><a class="reference internal" href="#maintainers" id="toc-entry-6">Maintainers</a></li>
</ul>
</li>
</ul>
</div>
<div class="section" id="usage">
<h1><a class="toc-backref" href="#toc-entry-1">Usage</a></h1>
<p>To use this module, you need to:</p>
<ol class="arabic simple">
<li>Go to <em>Settings &gt; Technical &gt; Sequences &amp; Identifier &gt; Manage Sequence Options</em>.</li>
<li>Based on extended module installed, different document types will be listed, i.e., Purchase Order.</li>
<li>Activite “Use sequence options” to use, if not, fall back to normal sequence.</li>
<li><dl class="first docutils">
<dt>For each option, provide,</dt>
<dd><ul class="first last">
<li>Name: i.e., Customer Invoice for Cust A., Customer Payment, etc.</li>
<li>Apply On: a filter domain to test whether a document match this option.</li>
<li>Sequence: select underlining sequence to perform</li>
</ul>
</dd>
</dl>
</li>
</ol>
<p><strong>Note:</strong></p>
<ul class="simple">
<li>If no options matches the document, fall back to normal sequence.</li>
<li>If there are multiple sequence options that match same document, error will be raised.</li>
</ul>
</div>
<div class="section" id="bug-tracker">
<h1><a class="toc-backref" href="#toc-entry-2">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_sequence_option%0Aversion:%2016.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-3">Credits</a></h1>
<div class="section" id="authors">
<h2><a class="toc-backref" href="#toc-entry-4">Authors</a></h2>
<ul class="simple">
<li>Ecosoft</li>
</ul>
</div>
<div class="section" id="contributors">
<h2><a class="toc-backref" href="#toc-entry-5">Contributors</a></h2>
<ul class="simple">
<li>Kitti U. &lt;<a class="reference external" href="mailto:kittiu&#64;ecosoft.co.th">kittiu&#64;ecosoft.co.th</a>&gt;</li>
</ul>
</div>
<div class="section" id="maintainers">
<h2><a class="toc-backref" href="#toc-entry-6">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>Current <a class="reference external" href="https://odoo-community.org/page/maintainer-role">maintainer</a>:</p>
<p><a class="reference external image-reference" href="https://github.com/kittiu"><img alt="kittiu" src="https://github.com/kittiu.png?size=40px" /></a></p>
<p>This module is part of the <a class="reference external" href="https://github.com/OCA/server-tools/tree/16.0/base_sequence_option">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,5 @@
# Copyright 2021 Ecosoft Co., Ltd. (http://ecosoft.co.th)
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
from . import common
from . import test_ir_sequence_option

View File

@ -0,0 +1,30 @@
# Copyright 2021 Ecosoft Co., Ltd. (http://ecosoft.co.th)
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
from odoo import api, fields, models
class BaseSequenceTester(models.Model):
_name = "base.sequence.tester"
_description = "Base Sequence Tester"
name = fields.Char(default="/")
test_type = fields.Selection(selection=[("a", "A"), ("b", "B")])
@api.model
def create(self, vals):
seq = self.env["ir.sequence.option.line"].get_sequence(self.new(vals))
if seq: # use sequence from sequence.option, instead of base.sequence.tester
self = self.with_context(sequence_option_id=seq.id)
new_seq = self.env["ir.sequence"].next_by_code("base.sequence.tester")
vals["name"] = new_seq
return super().create(vals)
class IrSequenceOption(models.Model):
_inherit = "ir.sequence.option"
model = fields.Selection(
selection_add=[("base.sequence.tester", "base.sequence.tester")],
ondelete={"base.sequence.tester": "cascade"},
)

View File

@ -0,0 +1,93 @@
# Copyright 2021 Ecosoft Co., Ltd. (http://ecosoft.co.th)
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
from odoo_test_helper import FakeModelLoader
from odoo.tests import common
class CommonBaseSequenceOption(common.TransactionCase):
@classmethod
def setUpClass(cls):
super(CommonBaseSequenceOption, cls).setUpClass()
cls.loader = FakeModelLoader(cls.env, cls.__module__)
cls.loader.backup_registry()
from .base_sequence_tester import BaseSequenceTester, IrSequenceOption
cls.loader.update_registry((BaseSequenceTester, IrSequenceOption))
cls.test_model = cls.env[BaseSequenceTester._name]
cls.tester_model = cls.env["ir.model"].search(
[("model", "=", "base.sequence.tester")]
)
# Access record:
cls.env["ir.model.access"].create(
{
"name": "access.tester",
"model_id": cls.tester_model.id,
"perm_read": 1,
"perm_write": 1,
"perm_create": 1,
"perm_unlink": 1,
}
)
# Create sequence for type A and type B
cls.ir_sequence_obj = cls.env["ir.sequence"]
cls.ir_sequence_obj.create(
{
"name": "Default Sequence",
"code": "base.sequence.tester",
"padding": 5,
"prefix": "DEF/",
}
)
seq_a = cls.ir_sequence_obj.create(
{
"name": "Type A",
"padding": 5,
"prefix": "TYPE-A/",
}
)
seq_b = cls.ir_sequence_obj.create(
{
"name": "Type B",
"padding": 5,
"prefix": "TYPE-B/",
}
)
# Create sequence options for model base.sequence.tester:
cls.base_sequence_obj = cls.env["ir.sequence.option"]
cls.base_seq = cls.base_sequence_obj.create(
{
"name": "Test Model",
"model": "base.sequence.tester",
"use_sequence_option": True,
}
)
cls.sequence_obj = cls.env["ir.sequence.option.line"]
cls.sequence_obj.create(
{
"base_id": cls.base_seq.id,
"name": "Option 1",
"filter_domain": [("test_type", "=", "a")],
"sequence_id": seq_a.id,
}
)
cls.sequence_obj.create(
{
"base_id": cls.base_seq.id,
"name": "Option 1",
"filter_domain": [("test_type", "=", "b")],
"sequence_id": seq_b.id,
}
)
@classmethod
def tearDownClass(cls):
cls.loader.restore_registry()
return super(CommonBaseSequenceOption, cls).tearDownClass()

View File

@ -0,0 +1,30 @@
# Copyright 2021 Ecosoft Co., Ltd. (http://ecosoft.co.th)
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
from odoo.tests.common import tagged
from .common import CommonBaseSequenceOption
@tagged("post_install", "-at_install")
class TestBaseSequenceTester(CommonBaseSequenceOption):
def test_sequence_options(self):
"""
Test 3 cases,
1. Default
2. Sequence Type A
3. Sequence Type B
"""
# 1. Default
rec = self.test_model.create({})
self.assertIn("DEF/", rec.name)
# 2. Type A
rec = self.test_model.create({"test_type": "a"})
self.assertIn("TYPE-A/", rec.name)
# 3. Type B
rec = self.test_model.create({"test_type": "b"})
self.assertIn("TYPE-B/", rec.name)
# Not useing the sequence
self.base_seq.use_sequence_option = False
rec = self.test_model.create({"test_type": "b"})
self.assertIn("DEF/", rec.name)

View File

@ -0,0 +1,99 @@
<?xml version="1.0" ?>
<!-- Copyright 2021 Ecosoft Co., Ltd. (http://ecosoft.co.th)
License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html). -->
<odoo>
<record id="view_ir_sequence_option_tree" model="ir.ui.view">
<field name="name">view.ir.sequence.option.tree</field>
<field name="model">ir.sequence.option</field>
<field name="arch" type="xml">
<tree create="1" delete="1">
<field name="name" />
<field name="model" />
<field name="use_sequence_option" />
<field name="company_id" groups="base.group_multi_company" />
</tree>
</field>
</record>
<record id="view_ir_sequence_option_line_tree" model="ir.ui.view">
<field name="name">view.ir.sequence.option.line.tree</field>
<field name="model">ir.sequence.option.line</field>
<field name="arch" type="xml">
<tree>
<field name="name" />
<field name="sequence_id" />
<field name="prefix" />
<field name="suffix" />
<field name="implementation" />
</tree>
</field>
</record>
<record id="view_ir_sequence_option_form" model="ir.ui.view">
<field name="name">view.ir.sequence.option.form</field>
<field name="model">ir.sequence.option</field>
<field name="arch" type="xml">
<form string="Doctype Sequence" create="1" delete="1">
<h1>
<field name="name" class="oe_inline" placeholder="Name" />
</h1>
<group>
<group>
<field name="model" />
<field name="company_id" groups="base.group_multi_company" />
</group>
<group>
<field name="use_sequence_option" widget="boolean_toggle" />
</group>
</group>
<field name="option_ids">
<tree>
<field name="name" />
<field name="model" invisible="1" />
<field name="filter_domain" string="Matching Domain" />
<field name="sequence_id" string="Use Sequence" />
<field name="prefix" />
<field name="suffix" />
<field name="implementation" />
<field name="company_id" invisible="1" />
</tree>
<form>
<group>
<group>
<field name="name" />
<field name="model" invisible="1" />
<field
name="filter_domain"
widget="domain"
options="{'model': 'model', 'in_dialog': True}"
/>
</group>
<group>
<field name="sequence_id" />
<field name="company_id" invisible="1" />
</group>
</group>
</form>
</field>
</form>
</field>
</record>
<record id="action_ir_sequence_option" model="ir.actions.act_window">
<field name="name">Manage Sequence Options</field>
<field name="res_model">ir.sequence.option</field>
<field name="view_mode">tree,form</field>
<field name="view_id" ref="view_ir_sequence_option_tree" />
</record>
<menuitem
name="Manage Sequence Options"
id="menu_ir_sequence_option"
action="action_ir_sequence_option"
parent="base.next_id_5"
sequence="20"
/>
</odoo>

View File

@ -3,6 +3,7 @@ astor
dataclasses
lxml
mako
odoo_test_helper
odoorpc
openpyxl
openupgradelib

View File

@ -0,0 +1 @@
../../../../base_sequence_option

View File

@ -0,0 +1,6 @@
import setuptools
setuptools.setup(
setup_requires=['setuptools-odoo'],
odoo_addon=True,
)