migrate from addons to new repo bemade-addons and ln in addons

This commit is contained in:
Benoît Vézina 2023-06-26 17:01:44 -04:00
parent 751170b7f3
commit 5752f837a9
44 changed files with 849 additions and 0 deletions

View file

@ -0,0 +1,5 @@
# -*- coding: utf-8 -*-
from . import models

View file

@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
{
"name": "Change default when adding follower",
"version": "15.0.0.0.1",
"category": "Extra Tools",
'summary': 'Change default when adding follower',
"description": """
Change default when adding follower
Send mail false by default
""",
"author": "Bemade",
'website': 'https://www.bemade.org',
"depends": [
'mail',
],
"data": [
],
"auto_install": False,
"installable": True,
'license': 'OPL-1'
}

View file

@ -0,0 +1,2 @@
# -*- coding: utf-8 -*-
from . import mail_wizard_invite

View file

@ -0,0 +1,8 @@
# Copyright Bemade.org
from odoo import models, fields, api
class MailWizardInviteDefault(models.TransientModel):
_inherit = 'mail.wizard.invite'
send_mail = fields.Boolean(default=False, help="If true, an invitation email will be sent to the recipient")

View file

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

View file

@ -0,0 +1,22 @@
{
'name': "Attachment Cleanup",
'version': '1.0.1',
'author': "Bemade",
'website': "http://www.bemade.org",
'category': 'Tools',
'license': 'OPL-1',
'summary': "Find and delete missing attachments",
'description': """
This module adds a wizard in the settings menu to find and delete missing attachments.
The wizard lists all attachments that are not found in the filestore, and allows the user to select and delete them.
Please use this tool with caution, as deleting attachments cannot be undone.
""",
'depends': ['base'],
'data': [
'wizard/attachment_cleanup_wizard_view.xml',
'security/ir.model.access.csv',
],
'installable': True,
'application': False,
}

View file

@ -0,0 +1,37 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * attachment_cleanup
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 15.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-06-08 12:00+0000\n"
"PO-Revision-Date: 2023-06-08 12:00+0000\n"
"Last-Translator: \n"
"Language-Team: \n"
"Language: fr_CA\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: \n"
#. module: attachment_cleanup
#: model:ir.actions.act_window,name:attachment_cleanup.action_open_attachment_cleanup_wizard
msgid "Cleanup Attachments"
msgstr "Nettoyer les pièces jointes"
#. module: attachment_cleanup
#: model:ir.ui.view,arch_db:attachment_cleanup.view_attachment_cleanup_wizard
msgid "Delete"
msgstr "Supprimer"
#. module: attachment_cleanup
#: model:ir.ui.view,arch_db:attachment_cleanup.view_attachment_cleanup_wizard
msgid "Cancel"
msgstr "Annuler"
#. module: attachment_cleanup
#: model:ir.model.fields,field_description:attachment_cleanup.field_attachment_cleanup_wizard_attachment_ids
msgid "Missing Attachments"
msgstr "Pièces jointes manquantes"

View file

@ -0,0 +1,2 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_attachment_cleanup_wizard,access.attachment.cleanup.wizard,model_attachment_cleanup_wizard,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_attachment_cleanup_wizard access.attachment.cleanup.wizard model_attachment_cleanup_wizard base.group_system 1 1 1 1

View file

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

View file

@ -0,0 +1,45 @@
from odoo import api, fields, models
import os
class AttachmentCleanupWizard(models.TransientModel):
_name = 'attachment.cleanup.wizard'
_description = 'Attachment Cleanup Wizard'
attachment_ids = fields.Many2many(
'ir.attachment',
string='Missing Attachments',
readonly=True,
help='Attachments that are not found in the filestore'
)
@api.model
def default_get(self, fields_list):
res = super(AttachmentCleanupWizard, self).default_get(fields_list)
attachments_1 = self.sudo().env['ir.attachment'].search([])
self._cr.execute("SELECT id FROM ir_attachment WHERE company_id = %s", (self.env.company.id,))
attachments = self._cr.fetchall()
filestore_location = self.env['ir.attachment']._filestore()
missing_attachments = []
for attachment_id in attachments:
# if attachment.id == 47984:
# print(attachment.store_fname)
attachment = self.env['ir.attachment'].browse(attachment_id)
if attachment.store_fname:
file_path = os.path.join(filestore_location, attachment.store_fname)
if not os.path.exists(file_path):
missing_attachments.append(attachment.id)
if missing_attachments:
res.update({'attachment_ids': [(6, 0, missing_attachments)]})
return res
def action_cleanup_attachments(self):
self.ensure_one()
self.attachment_ids.unlink()

View file

@ -0,0 +1,32 @@
<odoo>
<record id="view_attachment_cleanup_wizard" model="ir.ui.view">
<field name="name">attachment.cleanup.wizard.view</field>
<field name="model">attachment.cleanup.wizard</field>
<field name="arch" type="xml">
<form string="Cleanup Attachments">
<field name="attachment_ids" options="{'no_create': True}">
<tree>
<field name="name"/>
<field name="store_fname"/>
<field name="res_model"/>
<field name="res_id"/>
<field name="mimetype"/>
<field name="write_date"/>
<button name="unlink" type="object" string="Delete"/>
</tree>
</field>
<button name="action_cleanup_attachments" type="object" string="Delete All"/>
</form>
</field>
</record>
<record id="action_open_attachment_cleanup_wizard" model="ir.actions.act_window">
<field name="name">Cleanup Attachments</field>
<field name="res_model">attachment.cleanup.wizard</field>
<field name="view_mode">form</field>
<field name="view_id" ref="view_attachment_cleanup_wizard"/>
<field name="target">new</field>
</record>
<menuitem id="menu_attachment_cleanup" name="Cleanup Attachments" parent="base.menu_administration" action="action_open_attachment_cleanup_wizard"/>
</odoo>

View file

@ -0,0 +1,4 @@
# Copyright (C) 2023 Bemade.org
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from . import models

View file

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
{
"name": "Fetchmail Only on production environment",
"version": "15.0.0.0.1",
"category": "Extra Tools",
'summary': 'Fetchmail Only on production environment',
"description": """
Fetchmail Only on production environment
""",
"author": "Bemade",
'website': 'https://www.bemade.org',
"depends": [
'fetchmail',
],
"data": [
],
"auto_install": True,
"installable": True,
'license': 'OPL-1'
}

View file

@ -0,0 +1,4 @@
# Copyright (C) 2023 Bemade.org
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from . import fetchmail_server

View file

@ -0,0 +1,23 @@
# Copyright (C) 2023 Bemade.org
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
import logging
# Import the required classes and decorators from Odoo
from odoo import api, models
from urllib.parse import urlparse
_logger = logging.getLogger(__name__)
class fetchmail_server(models.Model):
_inherit = 'fetchmail.server'
@api.model
def fetch_mail(self):
if urlparse(self.env['ir.config_parameter'].sudo().get_param('web.base.url')).netloc == \
urlparse('https://erp.durpro.com/').netloc:
return super(fetchmail_server, self).fetch_mail()
else:
# Add log message
_logger.info("Trying to fetch email, current URL don't match with production URL, so we don't fetch email")
return True

View file

@ -0,0 +1,5 @@
# -*- coding: utf-8 -*-
# from . import models

View file

@ -0,0 +1,23 @@
# -*- coding: utf-8 -*-
{
"name": "Hide Decimal on unit",
"version": "15.0.0.1.1",
"category": "Extra Tools",
'summary': 'Hide decimal on Qty when there is no decimal',
"description": """
Hide decimal on Qty when there is no decimal
""",
"author": "Bemade",
'website': 'https://www.bemade.org',
"depends": [
'sale',
'purchase'
],
"data": [
'views/sale.xml',
'views/purchase.xml'
],
"auto_install": False,
"installable": True,
'license': 'OPL-1'
}

View file

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template id="report_purchasequotation_document_strip_decimal" inherit_id="purchase.report_purchasequotation_document">
<xpath expr="//tbody//td[hasclass('text-right')]" position="replace">
<td name="td_quantity" class="text-right">
<t t-if="int(order_line.product_uom_qty) == order_line.product_uom_qty">
<span t-esc="'%.0f' % order_line.product_uom_qty"/>
</t>
<t t-else="">
<span t-esc="order_line.product_uom_qty"/>
</t>
<span t-field="order_line.product_uom" groups="uom.group_uom"/>
</td>
</xpath>
</template>
<template id="report_purchaseorder_document_strip_decimal" inherit_id="purchase.report_purchaseorder_document">
<xpath expr="//tbody//td[hasclass('text-right')][1]" position="replace">
<td name="td_quantity" class="text-right">
<t t-if="int(line.product_uom_qty) == line.product_uom_qty">
<span t-esc="'%.0f' % line.product_uom_qty"/>
</t>
<t t-else="">
<span t-esc="line.product_uom_qty"/>
</t>
<span t-field="line.product_uom" groups="uom.group_uom"/>
</td>
</xpath>
</template>
</odoo>

View file

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template id="report_saleorder_document_strip_decimal" inherit_id="sale.report_saleorder_document">
<td name="td_quantity" position="replace">
<td name="td_quantity" class="text-right">
<t t-if="int(line.product_uom_qty) == line.product_uom_qty">
<span t-esc="'%.0f' % line.product_uom_qty"/>
</t>
<t t-else="">
<span t-esc="line.product_uom_qty"/>
</t>
<span t-field="line.product_uom"/>
</td>
</td>
</template>
</odoo>

View file

@ -0,0 +1,5 @@
# -*- coding: utf-8 -*-
from . import models

View file

@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
{
"name": "Chatter on the Reordering Rules",
"version": "15.0.0.0.1",
"category": "Extra Tools",
'license': 'GPL-3',
'summary': 'Add chatter on the reordering rules',
"description": """
Add chatter on the reordering rules
""",
"author": "Bemade",
'website': 'https://www.bemade.org',
"depends": [
'stock',
],
"data": [
'views/stock_warehouse_orderpoint.xml',
],
"auto_install": False,
"installable": True,
}

View file

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

View file

@ -0,0 +1,19 @@
from odoo import models, fields
class StockWarehouseOrderpoint(models.Model):
_name = 'stock.warehouse.orderpoint'
_inherit = ['stock.warehouse.orderpoint', 'mail.thread', 'mail.activity.mixin']
name = fields.Char(tracking=True)
trigger = fields.Selection(tracking=True)
active = fields.Boolean(tracking=True)
snoozed_until = fields.Date(tracking=True)
location_id = fields.Many2one(tracking=True)
product_tmpl_id = fields.Many2one(tracking=True)
product_id = fields.Many2one(tracking=True)
product_min_qty = fields.Float(tracking=True)
product_max_qty = fields.Float(tracking=True)
qty_multiple = fields.Float(tracking=True)
group_id = fields.Many2one(tracking=True)
company_id = fields.Many2one(tracking=True)
route_id = fields.Many2one(tracking=True)

View file

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="view_warehouse_orderpoint_tree_editable_config_chatter" model="ir.ui.view">
<field name="name">stock.warehouse.orderpoint.tree.editable.config.chatter</field>
<field name="model">stock.warehouse.orderpoint</field>
<field name="inherit_id" ref="stock.view_warehouse_orderpoint_tree_editable_config"/>
<field name="arch" type="xml">
<xpath expr="//tree" position="attributes">
<attribute name="editable"/>
</xpath>
</field>
</record>
<record id="view_warehouse_orderpoint_form_chatter" model="ir.ui.view">
<field name="name">stock.warehouse.orderpoint.form.chatter</field>
<field name="model">stock.warehouse.orderpoint</field>
<field name="inherit_id" ref="stock.view_warehouse_orderpoint_form"/>
<field name="arch" type="xml">
<xpath expr="//form/sheet" position="after">
<div class="oe_chatter">
<field name="message_follower_ids" widget="mail_followers" />
<field name="message_ids" widget="mail_thread" />
</div>
</xpath>
</field>
</record>
</odoo>

View file

@ -0,0 +1,22 @@
# -*- coding: utf-8 -*-
{
"name": "Force Partner to be a company on SO and PO",
"version": "15.0.0.0.1",
"category": "Extra Tools",
'summary': 'Force Partner to be a company on SO and PO',
"description": """
Force Partner to be a company on SO and PO
""",
"author": "Bemade",
'website': 'https://www.bemade.org',
"depends": [
'stock','sale',
],
"data": [
'views/sale_order.xml',
'views/purchase_order.xml',
],
"auto_install": False,
"installable": True,
'license': 'OPL-1'
}

View file

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record id="purchase_order_form_view_inherit" model="ir.ui.view">
<field name="name">Purchase Order Form View Inherit</field>
<field name="model">purchase.order</field>
<field name="inherit_id" ref="purchase.purchase_order_form"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='partner_id']" position="attributes">
<attribute name="domain">[('is_company', '=', True)]</attribute>
</xpath>
</field>
</record>
</data>
</odoo>

View file

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record id="sale_order_form_view_inherit" model="ir.ui.view">
<field name="name">Sale Order Form View Inherit</field>
<field name="model">sale.order</field>
<field name="inherit_id" ref="sale.view_order_form"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='partner_id']" position="attributes">
<attribute name="domain">[('is_company', '=', True)]</attribute>
</xpath>
</field>
</record>
</data>
</odoo>

View file

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

View file

@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
{
"name": "Add SO Followers to Picking",
"version": "15.0.0.0.1",
"category": "Extra Tools",
'summary': 'Add SO Followers to Picking',
"description": """
Add SO Followers to Picking
""",
"author": "Bemade",
'website': 'https://www.bemade.org',
"depends": [
'sale',
'purchase'
],
"data": [
],
"auto_install": False,
"installable": True,
'license': 'OPL-1'
}

View file

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

View file

@ -0,0 +1,17 @@
from odoo import models, api
class StockPicking(models.Model):
_inherit = 'stock.picking'
@api.model
def create(self, vals):
picking = super(StockPicking, self).create(vals)
if 'origin' in vals:
sale_order = self.env['sale.order'].search([('name', '=', vals['origin'])], limit=1)
if sale_order:
for follower in sale_order.message_follower_ids:
picking.message_subscribe(partner_ids=[follower.partner_id.id])
return picking

View file

@ -0,0 +1,27 @@
# Copyright (C) 2023 Bemade.org
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
# Import the models package so Odoo knows to load our models
from . import models
# Import the Environment for creating an environment for superuser
# Import SUPERUSER_ID for using as the user id for the superuser
from odoo.api import Environment, SUPERUSER_ID
# This is the function that gets called after the module installation
def post_init_hook(cr, registry):
# Create an environment with the database cursor and SUPERUSER_ID
env = Environment(cr, SUPERUSER_ID, {})
menus = env['ir.ui.menu'].search([('parent_id', '=', False)])
# For each user in the system,
for user in env['res.users'].search([]):
# Iterate over each sequence
for menu in menus:
# Create a new record in 'res.users.menu.order' with the user, menu and sequence
env['res.users.menu.order'].create({
'user_id': user.id,
'menu_id': menu.id
})

View file

@ -0,0 +1,42 @@
# -*- coding: utf-8 -*-
{
'name': 'User Custom App Order',
'version': '1.0.1',
'license': 'GPL-3',
'author': 'Bemade',
'website': 'http://www.bemade.org',
'category': 'Extra Tools',
'summary': 'Allows users to customize the order of apps in the app switcher',
'description': """
User Custom App Order
=====================
This module allows each user to customize the order of their apps in the app switcher in Odoo.
Features:
---------
* Users can choose the order of their apps in the app switcher.
* Users can only modify their own app order. Administrators can modify the order for any user.
* The module also automatically handles the creation of app order records for new users and new apps.
Installation:
-------------
No specific steps required for the installation.
Configuration:
--------------
No specific configuration required for this module.
""",
'depends': ['hr',],
'data': [
'security/ir.model.access.csv',
'views/user_menu_sequence.xml',
'views/res_users_view.xml'
],
'assets': {
'web.assets_tests': ['bemade_user_custom_apps_order/static/tests/tours/custom_app_order_tour.js'],
},
'installable': True,
'application': False,
'auto_install': False,
'post_init_hook': 'post_init_hook',
}

View file

@ -0,0 +1,9 @@
# Copyright (C) 2023 Bemade.org
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
# Import the models to extend
from . import res_users
from . import ir_ui_menu
# Import the new model
from . import res_users_menu_order

View file

@ -0,0 +1,84 @@
# Copyright (C) 2023 Bemade.org
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
# Import the required classes and decorators from Odoo
from odoo import api, models
class IrUiMenu(models.Model):
_inherit = 'ir.ui.menu'
@api.model_create_multi
def create(self, vals_list):
# Override the create method to handle new top-level menus
records = super(IrUiMenu, self).create(vals_list)
menus = self.env['ir.ui.menu'].search([('parent_id', '=', False)])
# For each new menu
for record in records:
# If the menu is a top-level menu
if not record.parent_id and record.id in menus.ids:
# Create a 'res.users.menu.order' record for each user
for user in self.env['res.users'].search([]):
self.env['res.users.menu.order'].create({
'user_id': user.id,
'menu_id': record.id,
'sequence': record.sequence,
})
return records
def unlink(self):
# Override the unlink method to delete associated 'res.users.menu.order' records
self.env['res.users.menu.order'].search([
('menu_id', 'in', self.ids)
]).unlink()
return super(IrUiMenu, self).unlink()
def write(self, vals):
# Call the super method to perform the default write operation
res = super(IrUiMenu, self).write(vals)
menus = self.env['ir.ui.menu'].search([('parent_id', '=', False)])
for self_record in self:
if 'parent_id' in vals:
if vals.get('parent_id') == False and self_record in menus:
# If the menu becomes a top-level menu, create a 'res.users.menu.order' record for each user
users = self.env['res.users'].search([])
for user in users:
existing_order = self.env['res.users.menu.order'].search([
('user_id', '=', user.id),
('menu_id', '=', self_record.id),
], limit=1)
if not existing_order:
self.env['res.users.menu.order'].create({
'user_id': user.id,
'menu_id': self_record.id,
'sequence': self_record.sequence,
})
else:
# Delete the corresponding 'res.users.menu.order' records
self.env['res.users.menu.order'].search([('menu_id', '=', self_record.id)]).unlink()
return res
@api.model
def load_menus(self, debug):
menus = super().load_menus(debug)
# Retrieve the user's menu order records
menu_order_records = self.env['res.users.menu.order'].search([('user_id', '=', self.env.uid)])
# Create a dictionary that maps app ids to sequences
sequence_dict = {record.menu_id.id: record.sequence for record in menu_order_records}
# Retrieve the menu records for the IDs in menus['root']['children']
menu_records = self.browse(menus['root']['children'])
# Sort the menu records based on the sequences in the dictionary
sorted_menu_records = menu_records.sorted(key=lambda menu: sequence_dict.get(menu.id, 9999))
# Replace menus['root']['children'] with the IDs of the sorted menu records
menus['root']['children'] = sorted_menu_records.ids
return menus

View file

@ -0,0 +1,63 @@
# Copyright (C) 2023 Bemade.org
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import models, api, fields
class ResUsers(models.Model):
_inherit = 'res.users'
# Define the One2many field for the app order records
app_order_ids = fields.One2many(
'res.users.menu.order', 'user_id', string='App Order Records')
@property
def SELF_READABLE_FIELDS(self):
return super().SELF_READABLE_FIELDS + ['app_order_ids']
@property
def SELF_WRITEABLE_FIELDS(self):
return super().SELF_WRITEABLE_FIELDS + ['app_order_ids']
@api.model
def create(self, vals):
"""
Overridden to create a new app order record for each top-level menu for the new user when a new user is created.
"""
# Create the user
new_user = super().create(vals)
# Create a new app order record for each top-level menu for the new user
menus = self.env['ir.ui.menu'].search([('parent_id', '=', False)])
for menu in menus:
self.env['res.users.menu.order'].create({
'user_id': new_user.id,
'menu_id': menu.id,
'sequence': 9999, # Or some other default sequence
})
return new_user
def unlink(self):
"""
Overridden to delete the app order records for the user being deleted when a user is deleted.
"""
# Delete the app order records for the user being deleted
self.env['res.users.menu.order'].search([('user_id', 'in', self.ids)]).unlink()
# Delete the user
return super().unlink()
def write(self, vals):
"""
Overridden to allow users to modify their own 'app_order_ids' field.
"""
if 'app_order_ids' in vals and self.env.uid == self.id:
# may be called with sudo can be replaced with WRITINGFIELDRIGHTS but works for now
super(ResUsers, self.sudo()).write(vals)
else:
super().write(vals)
return {
'type': 'ir.actions.client',
'tag': 'reload',
}

View file

@ -0,0 +1,28 @@
# Copyright (C) 2023 Bemade.org
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
# Import the required classes and decorators from Odoo
from odoo import models, fields, api
class ResUsersMenuOrder(models.Model):
"""
This model represents the preferred order in which a user wants to see their apps.
Each record represents the order of one app for one user.
"""
_name = 'res.users.menu.order'
_description = 'User Menu Order'
user_id = fields.Many2one('res.users', string='User', required=True, )
# The user who has set a preferred order for their apps.
menu_id = fields.Many2one('ir.ui.menu', string='Menu', required=True)
# The app that the user has set a preferred order for.
sequence = fields.Integer(string='Sequence')
# The order of the app. A lower sequence means the app will appear earlier.
_sql_constraints = [
('user_menu_uniq', 'unique(user_id, menu_id)', 'A user should only have one order record per menu!'),
]

View file

@ -0,0 +1,3 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_res_users_menu_order_all,res.users.menu.order.all,model_res_users_menu_order,base.group_user,1,1,1,1
access_res_users_menu_order_admin,res.users.menu.order.admin,model_res_users_menu_order,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_res_users_menu_order_all res.users.menu.order.all model_res_users_menu_order base.group_user 1 1 1 1
3 access_res_users_menu_order_admin res.users.menu.order.admin model_res_users_menu_order base.group_system 1 1 1 1

View file

@ -0,0 +1,19 @@
/** @odoo-module */
import tour from 'web_tour.tour';
tour.register('custom_app_order_tour', {
test: true,
url: '/web',
}, /* Make sure the test task is visible via the Project > Task Templates path */
[
{
trigger: 'div.o_user_menu button.dropdown-toggle',
},
{
trigger: 'span[data-menu="settings"]:contains(My Profile)'
},
{
trigger: 'a.nav-link:contains(App Order)'
}
])

View file

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

View file

@ -0,0 +1,36 @@
from odoo.tests import TransactionCase, HttpCase, tagged
from odoo import Command
class TestCustomAppOrder(TransactionCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
user_group = cls.env.ref('base.group_user')
Users = cls.env['res.users'].with_context({'no_reset_password': True})
Employees = cls.env['hr.employee']
user_partner = cls.env['res.partner'].create({
'name': 'User Partner',
})
cls.user = Users.create({
'name': 'Regular User',
'login': 'reguser',
'partner_id': user_partner.id,
'password': 'reguser',
'email': 'regular_user@test.co',
'groups_id': [(6, 0, [user_group.id])]
})
user_employee = Employees.create({
'name': 'Regular User',
'address_home_id': user_partner.id,
'user_id': cls.user.id,
})
@tagged('-at_install', 'post_install')
class TestCustomAppOrderTours(HttpCase, TestCustomAppOrder):
def test_as_regular_user(self):
self.start_tour('/web', 'custom_app_order_tour', login='reguser')

View file

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- Extend the base view for the user profile -->
<record id="view_users_form_profile" model="ir.ui.view">
<field name="name">res.users.preferences.form.inherit</field>
<field name="model">res.users</field>
<field name="inherit_id" ref="base.view_users_form_simple_modif"/>
<field name="arch" type="xml">
<!-- Add a new page to the notebook on the user profile -->
<xpath expr="//notebook" position="inside">
<page string="App Order">
<!-- Add a list view for the 'app_order_ids' field -->
<field name="app_order_ids" widget="one2many_list" create="false" delete="false">
<!-- Use the 'handle' widget for the sequence field -->
<!-- This gives a draggable handle in the list view -->
<!-- The sequence will be updated based on the new order -->
<!-- Set 'readonly' to False for the sequence field so it can be modified -->
<tree editable="bottom" limit="200">
<field name="sequence" widget="handle"/>
<field name="menu_id" readonly="1"/>
<field name="user_id" invisible="1"/>
</tree>
</field>
</page>
</xpath>
</field>
</record>
</odoo>

View file

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- Record to specify the res.users.menu.order form view -->
<record id="user_menu_sequence_form" model="ir.ui.view">
<field name="name">user.menu.sequence.form</field>
<field name="model">res.users.menu.order</field>
<field name="arch" type="xml">
<form string="User Menu Order">
<!-- Include the fields user_id, menu_id and sequence -->
<group>
<field name="user_id"/>
<field name="menu_id"/>
<field name="sequence"/>
</group>
</form>
</field>
</record>
<!-- Record to specify the res.users.menu.order tree view -->
<record id="user_menu_sequence_tree" model="ir.ui.view">
<field name="name">user.menu.sequence.tree</field>
<field name="model">res.users.menu.order</field>
<field name="arch" type="xml">
<tree string="User Menu Order">
<!-- Include the fields user_id, menu_id and sequence -->
<!-- Add a handle widget to the sequence field for easy reordering -->
<field name="sequence" widget="handle"/>
<field name="user_id"/>
<field name="menu_id"/>
</tree>
</field>
</record>
</odoo>