Compare commits

...

19 Commits

Author SHA1 Message Date
clementmbr
279dc7c6c0 [IMP] add domain on origin and destination location for stock.moves in picking view 2021-10-06 14:43:15 +02:00
Alexis de Lattre
f6ddbb48ac [MIG] stock_picking_type_default_partner from v10 to v14 2021-10-01 21:21:31 +02:00
Alexis de Lattre
d3bddf5fda Port stock_picking_type_default_partner to v10 2021-10-01 21:13:11 +02:00
Alexis de Lattre
6f3a468a7c Mass rename from __openerp__.py to __manifest__.py 2021-10-01 21:13:11 +02:00
Alexis de Lattre
0bfa960153 Set all modules as uninstallable 2021-10-01 21:13:11 +02:00
Alexis de Lattre
a520ccff51 Add module stock_picking_type_default_partner 2021-10-01 21:13:11 +02:00
Alexis de Lattre
fa7611eb08 Push missing file 2021-10-01 21:11:30 +02:00
Alexis de Lattre
b2eda2a23b [MIG] sale_confirm_wizard from v10 to v14 2021-10-01 21:10:54 +02:00
Alexis de Lattre
74ff1b5cb5 sale_confirm_wizard: add ability to skip wizard via inherit in some scenarios 2021-10-01 20:52:44 +02:00
Alexis de Lattre
a7b4ed65eb sale_confirm_wizard: don't show main block when sale_warn = block 2021-10-01 20:52:44 +02:00
Alexis de Lattre
7dfb32c2d6 sale_confirm_warning: add sale_warn 2021-10-01 20:52:44 +02:00
Alexis de Lattre
d081bb0fd2 Add module sale_force_invoice_status 2021-10-01 20:52:44 +02:00
Alexis de Lattre
f3fdbec140 Add module sale_confirm_wizard 2021-10-01 20:52:44 +02:00
Alexis de Lattre
ac54c5cc75 Register payment on account.move form view is not highlighted any more 2021-09-30 20:37:00 +02:00
Alexis de Lattre
78c11411c3 Add filter on inventory lines
Always show field prefill_counted_quantity on inventory form
2021-09-26 22:49:24 +02:00
Alexis de Lattre
28ce11b216 stock.inventory improvement 2021-09-26 20:10:58 +02:00
Alexis de Lattre
00e034dacf Show invoice_origin on move form 2021-09-22 14:56:40 +02:00
Alexis de Lattre
8510b9518a Add module hr_contract_usability 2021-09-14 23:45:05 +02:00
Alexis de Lattre
15ef5df155 account_usability: add account_type in res.partner.bank tree view embedded in partner form view 2021-09-09 18:06:56 +00:00
25 changed files with 476 additions and 4 deletions

View File

@@ -18,6 +18,9 @@
<field name="invoice_incoterm_id" position="attributes">
<attribute name="widget">selection</attribute>
</field>
<button name="action_register_payment" position="attributes">
<attribute name="class">btn-default</attribute>
</button>
<button name="action_register_payment" position="before">
<button name="%(account.account_invoices)d" type="action" string="Print" attrs="{'invisible': [('move_type', 'not in', ('out_invoice', 'out_refund'))]}"/>
</button>
@@ -26,6 +29,9 @@
</button>
<!-- move sent field and make it visible -->
<field name="is_move_sent" position="replace"/>
<field name="invoice_origin" position="attributes">
<attribute name="invisible">0</attribute>
</field>
<field name="invoice_origin" position="after">
<field name="is_move_sent" attrs="{'invisible': [('move_type', 'not in', ('out_invoice', 'out_refund'))]}"/>
</field>

View File

@@ -16,6 +16,9 @@
<field name="property_account_position_id" position="attributes">
<attribute name="widget">selection</attribute>
</field>
<xpath expr="//field[@name='bank_ids']/tree/field[@name='acc_number']" position="after">
<field name="acc_type"/>
</xpath>
</field>
</record>

View File

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

View File

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

View File

@@ -0,0 +1,20 @@
# Copyright 2021 Akretion (http://www.akretion.com)
# @author Alexis de Lattre <alexis.delattre@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{
'name': 'HR Contract Usability',
'version': '14.0.1.0.0',
'category': 'Human Resources/Contracts',
'license': 'AGPL-3',
'summary': 'Usability improvements on HR Contract module',
'author': 'Akretion',
'website': 'http://www.akretion.com',
'depends': [
'hr_contract',
],
'data': [
'views/hr_payroll_structure_type.xml',
],
'installable': True,
}

View File

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

View File

@@ -0,0 +1,10 @@
# Copyright 2021 Akretion (http://www.akretion.com)
# @author Alexis de Lattre <alexis.delattre@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import fields, models
class HrPayrollStructureType(models.Model):
_inherit = 'hr.payroll.structure.type'
active = fields.Boolean(default=True)

View File

@@ -0,0 +1,63 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2021 Akretion France (http://www.akretion.com/)
@author: Alexis de Lattre <alexis.delattre@akretion.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<odoo>
<record id="hr_payroll_structure_type_form" model="ir.ui.view">
<field name="model">hr.payroll.structure.type</field>
<field name="arch" type="xml">
<form>
<widget name="web_ribbon" title="Archived" bg_color="bg-danger" attrs="{'invisible': [('active', '=', True)]}"/>
<group name="main">
<field name="name"/>
<field name="default_resource_calendar_id"/>
<field name="active" invisible="1"/>
<field name="country_id"/>
</group>
</form>
</field>
</record>
<record id="hr_payroll_structure_type_tree" model="ir.ui.view">
<field name="model">hr.payroll.structure.type</field>
<field name="arch" type="xml">
<tree>
<field name="name"/>
<field name="default_resource_calendar_id" optional="show"/>
<field name="country_id"/>
</tree>
</field>
</record>
<record id="hr_payroll_structure_type_search" model="ir.ui.view">
<field name="model">hr.payroll.structure.type</field>
<field name="arch" type="xml">
<search>
<field name="name"/>
<separator/>
<filter string="Archived" name="inactive" domain="[('active', '=', False)]"/>
<group name="groupby">
<filter name="country_groupby" string="Country" context="{'group_by': 'country_id'}"/>
</group>
</search>
</field>
</record>
<record id="hr_payroll_structure_type_action" model="ir.actions.act_window">
<field name="name">Salary Structure Types</field>
<field name="res_model">hr.payroll.structure.type</field>
<field name="view_mode">tree,form</field>
</record>
<menuitem
id="hr_payroll_structure_type_menu"
action="hr_payroll_structure_type_action"
parent="hr_contract.menu_human_resources_configuration_contract"
sequence="10"/>
</odoo>

View File

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

View File

@@ -0,0 +1,38 @@
# Copyright 2017-2021 Akretion France (http://www.akretion.com/)
# @author: Alexis de Lattre <alexis.delattre@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{
'name': 'Sale Confirm Wizard',
'version': '14.0.1.0.0',
'category': 'Sales',
'license': 'AGPL-3',
'summary': 'Open a wizard when you confirm a sale order to update important info',
'description': """
Sale Confirm Wizard
===================
When you confirm a quotation, Odoo will open a small wizard where you will be able to check and update important information:
* customer PO number,
* delivery address,
* invoicing address,
* payment terms.
It will also display the sale warning if the customer's company has one. And it is a blocker warning, the user won't be able to confirm the quotation.
This module has been developped because the experience has shown, when a sales assistant confirms a quotation in Odoo, it overlooks the important information written in the customer PO that may be different from the information of the quotation in Odoo, which causes many errors in delivery and invoicing.
This module has been written by Alexis de Lattre from Akretion
<alexis.delattre@akretion.com>.
""",
'author': 'Akretion',
'website': 'http://www.akretion.com',
'depends': ['sale'],
'data': [
'wizard/sale_confirm_view.xml',
'views/sale_order.xml',
'security/ir.model.access.csv',
],
'installable': True,
}

View File

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

View File

@@ -0,0 +1,17 @@
# Copyright 2020-2021 Akretion France (http://www.akretion.com/)
# @author: Alexis de Lattre <alexis.delattre@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import models
class SaleOrder(models.Model):
_inherit = 'sale.order'
def sale_confirm_wizard_button(self):
"""This method is designed to be inherited.
For example, inherit it if you don't want to start the wizard in
some scenarios"""
action = self.sudo().env.ref(
'sale_confirm_wizard.sale_confirm_action').read()[0]
return action

View File

@@ -0,0 +1,2 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_sale_confirm_wizard,Full access on sale.confirm wizard,model_sale_confirm,sales_team.group_sale_salesman,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_sale_confirm_wizard Full access on sale.confirm wizard model_sale_confirm sales_team.group_sale_salesman 1 1 1 1

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2017-2021 Akretion France (http://www.akretion.com/)
@author: Alexis de Lattre <alexis.delattre@akretion.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<odoo>
<record id="view_order_form" model="ir.ui.view">
<field name="name">sale.confirm.wizard.sale_order_form</field>
<field name="model">sale.order</field>
<field name="inherit_id" ref="sale.view_order_form"/>
<field name="arch" type="xml">
<button id="action_confirm" position="attributes">
<attribute name="name">sale_confirm_wizard_button</attribute>
</button>
<button name="action_confirm" attrs="{'invisible': [('state', 'not in', ['draft'])]}" position="attributes">
<attribute name="name">sale_confirm_wizard_button</attribute>
</button>
</field>
</record>
</odoo>

View File

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

View File

@@ -0,0 +1,78 @@
# Copyright 2017-2021 Akretion France (http://www.akretion.com/)
# @author: Alexis de Lattre <alexis.delattre@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import models, fields, api, _
from odoo.exceptions import UserError
from odoo.addons.base.models.res_partner import WARNING_MESSAGE
class SaleConfirm(models.TransientModel):
_name = 'sale.confirm'
_description = 'Wizard to confirm a sale order'
sale_id = fields.Many2one(
'sale.order', string='Sale Order', readonly=True)
client_order_ref = fields.Char(string='Customer PO Number')
payment_term_id = fields.Many2one(
'account.payment.term', string='Payment Terms')
partner_invoice_id = fields.Many2one(
'res.partner', 'Invoice Address', required=True)
show_partner_invoice_id = fields.Many2one(
related='partner_invoice_id',
string='Detailed Invoice Address')
partner_shipping_id = fields.Many2one(
'res.partner', 'Delivery Address', required=True)
show_partner_shipping_id = fields.Many2one(
related='partner_shipping_id',
string='Detailed Delivery Address')
sale_warn = fields.Selection(
WARNING_MESSAGE, 'Sale Warning Type', readonly=True)
sale_warn_msg = fields.Text(string='Sale Warning Message', readonly=True)
@api.model
def _prepare_default_get(self, order):
partner = order.partner_id.commercial_partner_id
default = {
'sale_id': order.id,
'client_order_ref': order.client_order_ref,
'payment_term_id': order.payment_term_id.id or False,
'partner_invoice_id': order.partner_invoice_id.id,
'partner_shipping_id': order.partner_shipping_id.id,
'sale_warn_msg': partner.sale_warn_msg,
'sale_warn': partner.sale_warn,
}
return default
@api.model
def default_get(self, fields):
res = super().default_get(fields)
assert self._context.get('active_model') == 'sale.order',\
'active_model should be sale.order'
order = self.env['sale.order'].browse(self._context.get('active_id'))
default = self._prepare_default_get(order)
res.update(default)
return res
def _prepare_update_so(self):
self.ensure_one()
return {
'client_order_ref': self.client_order_ref,
'payment_term_id': self.payment_term_id.id or False,
'partner_invoice_id': self.partner_invoice_id.id,
'partner_shipping_id': self.partner_shipping_id.id,
}
def confirm(self):
self.ensure_one()
partner = self.sale_id.partner_id.commercial_partner_id
if partner.sale_warn == 'block':
raise UserError(_(
"You cannot confirm this quotation because "
"customer '%s' has a blocker sale warning:\n\n%s")
% (partner.display_name, partner.sale_warn_msg))
vals = self._prepare_update_so()
self.sale_id.write(vals)
# confirm sale order
self.sale_id.action_confirm()
return True

View File

@@ -0,0 +1,54 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2017-2021 Akretion France (http://www.akretion.com/)
@author: Alexis de Lattre <alexis.delattre@akretion.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<odoo>
<record id="sale_confirm_form" model="ir.ui.view">
<field name="name">sale.confirm.form</field>
<field name="model">sale.confirm</field>
<field name="arch" type="xml">
<form string="Confirm Order">
<div><p>At this stage, you have received the Purchase Order from the customer and you are about to convert the related quotation to an order.</p></div>
<group name="warn" groups="sale.group_warning_sale" attrs="{'invisible': ['|', ('sale_warn', '=', False), ('sale_warn', '=', 'no-message')]}" string="Warning" col="4">
<field name="sale_warn" nolabel="1"/>
<field name="sale_warn_msg" nolabel="1" colspan="3"/>
</group>
<group name="main" attrs="{'invisible': [('sale_warn', '=', 'block')]}">
<field name="sale_id" invisible="1"/>
<field name="client_order_ref"/>
<field name="partner_invoice_id" context="{'default_type': 'invoice'}"
groups="sale.group_delivery_invoice_address"/>
<!-- partner_invoice_id can't show the full address because
we are in edit mode -->
<field name="show_partner_invoice_id" options="{'always_reload': True}"
context="{'show_address': 1}"
groups="sale.group_delivery_invoice_address"/>
<field name="partner_shipping_id"
context="{'default_type': 'delivery'}"
groups="sale.group_delivery_invoice_address"/>
<field name="show_partner_shipping_id" options="{'always_reload': True}"
context="{'show_address': 1}"
groups="sale.group_delivery_invoice_address"/>
<field name="payment_term_id"/>
</group>
<footer>
<button type="object" name="confirm"
string="Confirm Sale" class="btn-primary" attrs="{'invisible': [('sale_warn', '=', 'block')]}"/>
<button special="cancel" string="Annuler" class="btn-default"/>
</footer>
</form>
</field>
</record>
<record id="sale_confirm_action" model="ir.actions.act_window">
<field name="name">Confirm Order</field>
<field name="res_model">sale.confirm</field>
<field name="view_mode">form</field>
<field name="target">new</field>
</record>
</odoo>

View File

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

View File

@@ -0,0 +1,25 @@
# Copyright 2014-2021 Akretion France (http://www.akretion.com)
# @author Alexis de Lattre <alexis.delattre@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{
'name': 'Stock Picking Type Default Partner',
'version': '14.0.1.0.0',
'category': 'Inventory, Logistics, Warehousing',
'license': 'AGPL-3',
'summary': 'Adds a default partner on types of operation',
'description': """
Stock Picking Type Default Partner
==================================
This module adds a new field on the Types of Operation (stock.picking.type) : *Default Partner*. This is useful for multi-site companies that create inter-site Type of Operations: all the operations that use this Type of Operation should have the same destination partner.
This module has been written by Alexis de Lattre from Akretion <alexis.delattre@akretion.com>.
""",
'author': 'Akretion',
'website': 'http://www.akretion.com',
'depends': ['stock'],
'data': ['views/stock_picking_type.xml'],
'installable': True,
}

View File

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

View File

@@ -0,0 +1,31 @@
# Copyright 2014-2021 Akretion France (http://www.akretion.com)
# @author Alexis de Lattre <alexis.delattre@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import models, fields, api
class StockPickingType(models.Model):
_inherit = 'stock.picking.type'
default_partner_id = fields.Many2one(
'res.partner', string='Default Partner', ondelete='restrict',
help="If set, it will be the default partner on this type of "
"pickings.")
class StockPicking(models.Model):
_inherit = 'stock.picking'
@api.model
def _default_partner_id(self):
if self._context.get('default_picking_type_id'):
picktype = self.env['stock.picking.type'].browse(
self._context.get('default_picking_type_id'))
if picktype.default_partner_id:
return picktype.default_partner_id
return False
partner_id = fields.Many2one(
default=lambda self: self._default_partner_id())

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2015-2021 Akretion (http://www.akretion.com/)
@author Alexis de Lattre <alexis.delattre@akretion.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<odoo>
<record id="view_picking_type_form" model="ir.ui.view">
<field name="name">default.partner.stock.picking.type.form</field>
<field name="model">stock.picking.type</field>
<field name="inherit_id" ref="stock.view_picking_type_form"/>
<field name="arch" type="xml">
<field name="default_location_dest_id" position="after">
<field name="default_partner_id"/>
</field>
</field>
</record>
</odoo>

View File

@@ -2,10 +2,44 @@
# @author: Alexis de Lattre <alexis.delattre@akretion.com>
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from odoo import api, fields, models
from odoo import api, fields, models, _
from odoo.tools import float_compare, float_is_zero
class StockInventory(models.Model):
_inherit = 'stock.inventory'
prefill_counted_quantity = fields.Selection(
readonly=True, states={'draft': [('readonly', False)]})
class StockInventoryLine(models.Model):
_inherit = 'stock.inventory.line'
product_barcode = fields.Char(related='product_id.barcode', string="Product Barcode")
difference_qty = fields.Float(search="_search_difference_qty_usability")
def _search_difference_qty_usability(self, operator, value):
# Inspired by the method _search_difference_qty() from the
# official stock module
# So a part of this code is copyright Odoo SA under LGPL licence
if not self.env.context.get('default_inventory_id'):
raise NotImplementedError(_('Unsupported search on %s outside of an Inventory Adjustment', 'difference_qty'))
lines = self.search([('inventory_id', '=', self.env.context.get('default_inventory_id'))])
line_ids = []
for line in lines:
if operator == '=':
if float_is_zero(line.difference_qty, line.product_id.uom_id.rounding):
line_ids.append(line.id)
elif operator == '!=':
if not float_is_zero(line.difference_qty, line.product_id.uom_id.rounding):
line_ids.append(line.id)
elif operator == '>':
if float_compare(line.difference_qty, 0, line.product_id.uom_id.rounding) > 0:
line_ids.append(line.id)
elif operator == '<':
if float_compare(line.difference_qty, 0, line.product_id.uom_id.rounding) < 0:
line_ids.append(line.id)
else:
raise NotImplementedError()
return [('id', 'in', line_ids)]

View File

@@ -7,6 +7,20 @@
<odoo>
<record id="view_inventory_form" model="ir.ui.view">
<field name="name">usability.stock.inventory.form</field>
<field name="model">stock.inventory</field>
<field name="inherit_id" ref="stock.view_inventory_form"/>
<field name="arch" type="xml">
<button name="action_open_inventory_lines" states="confirm" position="after">
<button name="action_open_inventory_lines" states="done" string="Show Inventory Lines" type="object"/>
</button>
<field name="prefill_counted_quantity" position="attributes">
<attribute name="attrs">{}</attribute>
</field>
</field>
</record>
<record id="stock_inventory_line_tree" model="ir.ui.view">
<field name="name">usability.stock.inventory.line.tree</field>
<field name="model">stock.inventory.line</field>
@@ -30,4 +44,25 @@
</field>
</record>
<record id="stock_inventory_line_search" model="ir.ui.view">
<field name="name">usability.stock.inventory.line.search</field>
<field name="model">stock.inventory.line</field>
<field name="inherit_id" ref="stock.stock_inventory_line_search"/>
<field name="arch" type="xml">
<field name="product_id" position="after">
<field name="categ_id"/>
</field>
<filter name="difference" position="after">
<filter string="Difference = 0"
name="counted_equal" domain="[('difference_qty', '=', 0)]"/>
<filter string="Counted lower than Theoretical"
name="counted_lower" domain="[('difference_qty', '&lt;', 0)]"/>
<filter string="Counted higher than Theoretical"
name="counted_higher" domain="[('difference_qty', '&gt;', 0)]"/>
<separator/>
<filter string="Counted" name="counted" domain="[('product_qty', '>', 0)]"/>
</filter>
</field>
</record>
</odoo>

View File

@@ -34,8 +34,8 @@
<xpath expr="//field[@name='move_ids_without_package']/tree/field[@name='product_id']" position="after">
<field name="product_barcode" optional="hide"/>
<field name="name" optional="hide"/>
<field name="location_id" groups="stock.group_stock_multi_locations" optional="show"/>
<field name="location_dest_id" groups="stock.group_stock_multi_locations" optional="show"/>
<field name="location_id" groups="stock.group_stock_multi_locations" optional="show" domain="[('id', 'child_of', 'parent.location_id')]" options="{'no_create': True}"/>
<field name="location_dest_id" groups="stock.group_stock_multi_locations" optional="show" domain="[('id', 'child_of', 'parent.location_dest_id')]" options="{'no_create': True}"/>
</xpath>
<xpath expr="//field[@name='move_ids_without_package']/tree/button[@name='action_assign_serial']" position="after">
<button type="object" name="button_do_unreserve" string="Unreserve"
@@ -56,7 +56,7 @@
</field>
</field>
</record>
<record id="view_picking_internal_search" model="ir.ui.view">
<field name="name">stock_usability.view_picking_search</field>
<field name="model">stock.picking</field>