Compare commits

..

1 Commits

Author SHA1 Message Date
David Beal
c2af621083 wip 2019-03-28 17:45:34 +01:00
257 changed files with 943 additions and 10348 deletions

View File

@@ -1,2 +0,0 @@
from . import account_invoice
from . import account_invoice_report

View File

@@ -1,24 +0,0 @@
# Copyright 2015-2019 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': 'Account Invoice Margin',
'version': '12.0.1.0.0',
'category': 'Invoicing Management',
'license': 'AGPL-3',
'summary': 'Copy standard price on invoice line and compute margins',
'description': """
This module copies the field *standard_price* of the product on the invoice line when the invoice line is created. The allows the computation of the margin of the invoice.
This module has been written by Alexis de Lattre from Akretion
<alexis.delattre@akretion.com>.
""",
'author': 'Akretion',
'website': 'http://www.akretion.com',
'depends': ['account'],
'data': [
'account_invoice_view.xml',
],
'installable': True,
}

View File

@@ -1,152 +0,0 @@
# Copyright 2015-2019 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 api, fields, models
import odoo.addons.decimal_precision as dp
class AccountInvoiceLine(models.Model):
_inherit = 'account.invoice.line'
standard_price_company_currency = fields.Float(
string='Cost Price in Company Currency', readonly=True,
digits=dp.get_precision('Product Price'),
help="Cost price in company currency in the unit of measure "
"of the invoice line (which may be different from the unit "
"of measure of the product).")
standard_price_invoice_currency = fields.Float(
string='Cost Price in Invoice Currency', readonly=True,
compute='_compute_margin', store=True,
digits=dp.get_precision('Product Price'),
help="Cost price in invoice currency in the unit of measure "
"of the invoice line")
margin_invoice_currency = fields.Monetary(
string='Margin in Invoice Currency', readonly=True, store=True,
compute='_compute_margin', currency_field='currency_id')
margin_company_currency = fields.Monetary(
string='Margin in Company Currency', readonly=True, store=True,
compute='_compute_margin', currency_field='company_currency_id')
margin_rate = fields.Float(
string="Margin Rate", readonly=True, store=True,
compute='_compute_margin',
digits=(16, 2), help="Margin rate in percentage of the sale price")
@api.depends(
'standard_price_company_currency', 'invoice_id.currency_id',
'invoice_id.type', 'invoice_id.company_id',
'invoice_id.date_invoice', 'quantity', 'price_subtotal')
def _compute_margin(self):
for il in self:
standard_price_inv_cur = 0.0
margin_inv_cur = 0.0
margin_comp_cur = 0.0
margin_rate = 0.0
inv = il.invoice_id
if inv and inv.type in ('out_invoice', 'out_refund'):
# it works in _get_current_rate
# even if we set date = False in context
# standard_price_inv_cur is in the UoM of the invoice line
date = inv._get_currency_rate_date() or\
fields.Date.context_today(self)
company = inv.company_id
company_currency = company.currency_id
standard_price_inv_cur =\
company_currency._convert(
il.standard_price_company_currency,
inv.currency_id, company, date)
margin_inv_cur =\
il.price_subtotal - il.quantity * standard_price_inv_cur
margin_comp_cur = inv.currency_id._convert(
margin_inv_cur, company_currency, company, date)
if il.price_subtotal:
margin_rate = 100 * margin_inv_cur / il.price_subtotal
# for a refund, margin should be negative
# but margin rate should stay positive
if inv.type == 'out_refund':
margin_inv_cur *= -1
margin_comp_cur *= -1
il.standard_price_invoice_currency = standard_price_inv_cur
il.margin_invoice_currency = margin_inv_cur
il.margin_company_currency = margin_comp_cur
il.margin_rate = margin_rate
# We want to copy standard_price on invoice line for customer
# invoice/refunds. We can't do that via on_change of product_id,
# because it is not always played when invoice is created from code
# => we inherit write/create
# We write standard_price_company_currency even on supplier invoice/refunds
# because we don't have access to the 'type' of the invoice
@api.model
def create(self, vals):
if vals.get('product_id'):
pp = self.env['product.product'].browse(vals['product_id'])
std_price = pp.standard_price
inv_uom_id = vals.get('uom_id')
if inv_uom_id and inv_uom_id != pp.uom_id.id:
inv_uom = self.env['uom.uom'].browse(inv_uom_id)
std_price = pp.uom_id._compute_price(
std_price, inv_uom)
vals['standard_price_company_currency'] = std_price
return super(AccountInvoiceLine, self).create(vals)
def write(self, vals):
if not vals:
vals = {}
if 'product_id' in vals or 'uom_id' in vals:
for il in self:
if 'product_id' in vals:
if vals.get('product_id'):
pp = self.env['product.product'].browse(
vals['product_id'])
else:
pp = False
else:
pp = il.product_id or False
# uom_id is NOT a required field
if 'uom_id' in vals:
if vals.get('uom_id'):
inv_uom = self.env['uom.uom'].browse(
vals['uom_id'])
else:
inv_uom = False
else:
inv_uom = il.uom_id or False
std_price = 0.0
if pp:
std_price = pp.standard_price
if inv_uom and inv_uom != pp.uom_id:
std_price = pp.uom_id._compute_price(
std_price, inv_uom)
il.write({'standard_price_company_currency': std_price})
return super(AccountInvoiceLine, self).write(vals)
class AccountInvoice(models.Model):
_inherit = 'account.invoice'
margin_invoice_currency = fields.Monetary(
string='Margin in Invoice Currency',
compute='_compute_margin', store=True, readonly=True,
currency_field='currency_id')
margin_company_currency = fields.Monetary(
string='Margin in Company Currency',
compute='_compute_margin', store=True, readonly=True,
currency_field='company_currency_id')
@api.depends(
'type',
'invoice_line_ids.margin_invoice_currency',
'invoice_line_ids.margin_company_currency')
def _compute_margin(self):
res = self.env['account.invoice.line'].read_group(
[('invoice_id', 'in', self.ids)],
['invoice_id', 'margin_invoice_currency',
'margin_company_currency'],
['invoice_id'])
for re in res:
if re['invoice_id']:
inv = self.browse(re['invoice_id'][0])
if inv.type in ('out_invoice', 'out_refund'):
inv.margin_invoice_currency = re['margin_invoice_currency']
inv.margin_company_currency = re['margin_company_currency']

View File

@@ -1,60 +0,0 @@
# Copyright 2018-2019 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 api, fields, models
class AccountInvoiceReport(models.Model):
_inherit = 'account.invoice.report'
margin = fields.Float(string='Margin', readonly=True)
# why digits=0 ??? Why is it like that in the native "account" module
user_currency_margin = fields.Float(
string="Margin", compute='_compute_user_currency_margin', digits=0)
_depends = {
'account.invoice': [
'account_id', 'amount_total_company_signed',
'commercial_partner_id', 'company_id',
'currency_id', 'date_due', 'date_invoice', 'fiscal_position_id',
'journal_id', 'number', 'partner_bank_id', 'partner_id',
'payment_term_id', 'residual', 'state', 'type', 'user_id',
],
'account.invoice.line': [
'account_id', 'invoice_id', 'price_subtotal', 'product_id',
'quantity', 'uom_id', 'account_analytic_id',
'margin_company_currency',
],
'product.product': ['product_tmpl_id'],
'product.template': ['categ_id'],
'uom.uom': ['category_id', 'factor', 'name', 'uom_type'],
'res.currency.rate': ['currency_id', 'name'],
'res.partner': ['country_id'],
}
@api.depends('currency_id', 'date', 'margin')
def _compute_user_currency_margin(self):
user_currency = self.env.user.company_id.currency_id
currency_rate = self.env['res.currency.rate'].search([
('rate', '=', 1),
'|',
('company_id', '=', self.env.user.company_id.id),
('company_id', '=', False)], limit=1)
base_currency = currency_rate.currency_id
for record in self:
date = record.date or fields.Date.today()
company = record.company_id
record.user_currency_margin = base_currency._convert(
record.margin, user_currency, company, date)
# TODO check for refunds
def _sub_select(self):
select_str = super(AccountInvoiceReport, self)._sub_select()
select_str += ", SUM(ail.margin_company_currency) AS margin"
return select_str
def _select(self):
select_str = super(AccountInvoiceReport, self)._select()
select_str += ", sub.margin AS margin"
return select_str

View File

@@ -1,51 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
© 2015-2017 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_invoice_line_form" model="ir.ui.view">
<field name="name">margin.account.invoice.line.form</field>
<field name="model">account.invoice.line</field>
<field name="inherit_id" ref="account.view_invoice_line_form"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='analytic_tag_ids']/.." position="inside">
<field name="standard_price_company_currency"
string="Cost Price in Comp. Cur."
groups="base.group_no_one"/>
<field name="standard_price_invoice_currency"
string="Cost Price in Inv. Cur."
groups="base.group_no_one"/>
<field name="margin_invoice_currency"
string="Margin in Inv. Cur."
groups="base.group_no_one"/>
<field name="margin_company_currency"
string="Margin in Comp. Cur."
groups="base.group_no_one"/>
<label for="margin_rate" groups="base.group_no_one"/>
<div name="margin_rate" groups="base.group_no_one">
<field name="margin_rate" class="oe_inline"/> %
</div>
</xpath>
</field>
</record>
<record id="invoice_form" model="ir.ui.view">
<field name="name">margin.account.invoice.form</field>
<field name="model">account.invoice</field>
<field name="inherit_id" ref="account.invoice_form"/>
<field name="arch" type="xml">
<field name="move_id" position="after">
<field name="margin_invoice_currency"
string="Margin in Inv. Cur." groups="base.group_no_one"/>
<field name="margin_company_currency"
string="Margin in Comp. Cur." groups="base.group_no_one"/>
</field>
</field>
</record>
</odoo>

View File

@@ -1,39 +0,0 @@
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg
:target: https://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
Account Invoice Update Wizard
=============================
This module adds a button *Update Invoice* on Customer and Supplier invoices in
Open or Paid state. This button starts a wizard which allows the user to update
non-legal fields of the invoice:
* Source Document
* Reference/Description
* Payment terms (update allowed only to a payment term with same number of terms
of the same amount and on invoices without any payment)
* Bank Account
* Salesman
* Notes
* Description of invoice lines
* Analytic account
* Analytic tags
Bug Tracker
===========
Bugs are tracked on `GitHub Issues
<https://github.com/akretion/odoo-usability/issues>`_. In case of trouble, please
check there if your issue has already been reported. If you spotted it first,
help us smash it by providing detailed and welcomed feedback.
Contributors
------------
* Alexis de Lattre <alexis.delattre@akretion.com>
* Florian da Costa <florian.dacosta@akretion.com>
* Matthieu Dietrich <matthieu.dietrich@camptocamp.com>
* Yannick Vaucher <yannick.vaucher@camptocamp.com>
* Mykhailo Panarin <m.panarin@mobilunity.com>
* Artem Kostyuk <a.kostyuk@mobilunity.com>

View File

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

View File

@@ -1,21 +0,0 @@
# Copyright 2017 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
# Copyright 2018-2019 Camptocamp
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{
'name': 'Account Invoice Update Wizard',
'version': '12.0.1.0.0',
'category': 'Accounting & Finance',
'license': 'AGPL-3',
'summary': 'Wizard to update non-legal fields of an open/paid invoice',
'author': 'Akretion',
'website': 'https://github.com/akretion/odoo-usability',
'depends': [
'account',
],
'data': [
'wizard/account_invoice_update_view.xml',
'views/account_invoice.xml',
],
'installable': True,
}

View File

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

View File

@@ -1,22 +0,0 @@
# Copyright 2019 Camptocamp
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import models, fields, api, _
from odoo.exceptions import UserError
import odoo.addons.decimal_precision as dp
class AccountInvoice(models.Model):
_inherit = 'account.invoice'
def prepare_update_wizard(self):
self.ensure_one()
wizard = self.env['account.invoice.update']
res = wizard._prepare_default_get(self)
action = self.env.ref(
'account_invoice_update_wizard.account_invoice_update_action'
).read()[0]
action['name'] = "Update Wizard"
action['res_id'] = wizard.create(res).id
return action

View File

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

View File

@@ -1,196 +0,0 @@
# Copyright 2018-2019 Camptocamp
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo.tests.common import SavepointCase
from odoo.exceptions import UserError
class TestAccountInvoiceUpdateWizard(SavepointCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.customer12 = cls.env.ref('base.res_partner_12')
cls.product16 = cls.env.ref('product.product_product_16')
cls.product24 = cls.env.ref('product.product_product_24')
uom_unit = cls.env.ref('uom.product_uom_categ_unit')
cls.invoice1 = cls.env['account.invoice'].create({
'name': 'Test invoice',
'partner_id': cls.customer12.id,
})
cls.inv_line1 = cls.env['account.invoice.line'].create({
'invoice_id': cls.invoice1.id,
'name': "Line1",
'product_id': cls.product16.id,
'product_uom_id': uom_unit.id,
'account_id': cls.invoice1.account_id.id,
'price_unit': 42.0,
})
cls.inv_line2 = cls.env['account.invoice.line'].create({
'invoice_id': cls.invoice1.id,
'name': "Line2",
'product_id': cls.product24.id,
'product_uom_id': uom_unit.id,
'account_id': cls.invoice1.account_id.id,
'price_unit': 1111.1,
})
cls.aa1 = cls.env.ref('analytic.analytic_partners_camp_to_camp')
cls.aa2 = cls.env.ref('analytic.analytic_nebula')
cls.atag1 = cls.env.ref('analytic.tag_contract')
cls.atag2 = cls.env['account.analytic.tag'].create({
'name': '',
})
def create_wizard(self, invoice):
res = self.invoice1.prepare_update_wizard()
self.wiz = self.env['account.invoice.update'].browse(res['res_id'])
def test_add_analytic_account_line1(self):
""" Add analytic account on an invoice line
after the invoice has been approved.
This will:
- update the move line
- create a new analytic line.
"""
self.invoice1.action_invoice_open()
self.create_wizard(self.invoice1)
wiz_line = self.wiz.line_ids.filtered(
lambda rec: rec.invoice_line_id == self.inv_line1)
wiz_line.account_analytic_id = self.aa1
self.wiz.run()
related_ml = self.invoice1.move_id.line_ids.filtered(
lambda rec: rec.product_id == self.product16)
self.assertEqual(related_ml.analytic_account_id, self.aa1)
self.assertEqual(related_ml.analytic_line_ids.account_id, self.aa1)
def test_change_analytic_account_line1(self):
""" Change analytic account on an invoice line
after the invoice has been approved.
This will:
- update the move line
- update the existing analytic line."""
self.inv_line1.account_analytic_id = self.aa2
self.invoice1.action_invoice_open()
self.create_wizard(self.invoice1)
wiz_line = self.wiz.line_ids.filtered(
lambda rec: rec.invoice_line_id == self.inv_line1)
wiz_line.account_analytic_id = self.aa1
self.wiz.run()
related_ml = self.invoice1.move_id.line_ids.filtered(
lambda rec: rec.product_id == self.product16)
self.assertEqual(related_ml.analytic_account_id, self.aa1)
self.assertEqual(related_ml.analytic_line_ids.account_id, self.aa1)
def test_error_grouped_move_lines(self):
""" Change analytic account on an invoice line
after the invoice has been approved where both
lines were grouped in the same move line.
This will raise an error.
"""
self.invoice1.journal_id.group_invoice_lines = True
self.inv_line2.product_id = self.product16
self.inv_line2.unit_price = 42.0
self.invoice1.action_invoice_open()
self.create_wizard(self.invoice1)
line1 = self.wiz.line_ids[0]
line1.account_analytic_id = self.aa1
with self.assertRaises(UserError):
self.wiz.run()
def test_add_analytic_tags_line1(self):
""" Add analytic tags on an invoice line
after the invoice has been approved.
This will update move line.
"""
self.invoice1.action_invoice_open()
self.create_wizard(self.invoice1)
wiz_line = self.wiz.line_ids.filtered(
lambda rec: rec.invoice_line_id == self.inv_line1)
wiz_line.analytic_tag_ids = self.atag2
self.wiz.run()
related_ml = self.invoice1.move_id.line_ids.filtered(
lambda rec: rec.product_id == self.product16)
self.assertEqual(related_ml.analytic_tag_ids, self.atag2)
self.assertFalse(related_ml.analytic_line_ids)
def test_change_analytic_tags_line1(self):
""" Change analytic tags on an invoice line
after the invoice has been approved.
It will update move line and analytic line
"""
self.inv_line1.account_analytic_id = self.aa2
self.inv_line1.analytic_tag_ids = self.atag1
self.invoice1.action_invoice_open()
self.create_wizard(self.invoice1)
wiz_line = self.wiz.line_ids.filtered(
lambda rec: rec.invoice_line_id == self.inv_line1)
wiz_line.analytic_tag_ids = self.atag2
self.wiz.run()
related_ml = self.invoice1.move_id.line_ids.filtered(
lambda rec: rec.product_id == self.product16)
self.assertEqual(related_ml.analytic_tag_ids, self.atag2)
self.assertEqual(related_ml.analytic_line_ids.tag_ids, self.atag2)
def test_add_analytic_info_line1(self):
""" Add analytic account and tags on an invoice line
after the invoice has been approved.
This will:
- update move line
- create an analytic line
"""
self.invoice1.action_invoice_open()
self.create_wizard(self.invoice1)
wiz_line = self.wiz.line_ids.filtered(
lambda rec: rec.invoice_line_id == self.inv_line1)
wiz_line.account_analytic_id = self.aa1
wiz_line.analytic_tag_ids = self.atag2
self.wiz.run()
related_ml = self.invoice1.move_id.line_ids.filtered(
lambda rec: rec.product_id == self.product16)
self.assertEqual(related_ml.analytic_account_id, self.aa1)
self.assertEqual(related_ml.analytic_tag_ids, self.atag2)
self.assertEqual(related_ml.analytic_line_ids.account_id, self.aa1)
self.assertEqual(related_ml.analytic_line_ids.tag_ids, self.atag2)
def test_empty_analytic_account_line1(self):
""" Remove analytic account
after the invoice has been approved.
This will raise an error as it is not implemented.
"""
self.inv_line1.account_analytic_id = self.aa2
self.invoice1.action_invoice_open()
self.create_wizard(self.invoice1)
wiz_line = self.wiz.line_ids.filtered(
lambda rec: rec.invoice_line_id == self.inv_line1)
wiz_line.account_analytic_id = False
self.wiz.run()
related_ml = self.invoice1.move_id.line_ids.filtered(
lambda rec: rec.product_id == self.product16)
self.assertFalse(related_ml.analytic_account_id)
self.assertFalse(related_ml.analytic_line_ids)

View File

@@ -1,29 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2017 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<odoo>
<record id="invoice_supplier_form" model="ir.ui.view">
<field name="model">account.invoice</field>
<field name="inherit_id" ref="account.invoice_supplier_form"/>
<field name="arch" type="xml">
<button name="action_invoice_draft" position="before">
<button name="prepare_update_wizard" type="object" string="Update Invoice" states="open,paid" groups="account.group_account_invoice"/>
</button>
</field>
</record>
<record id="invoice_form" model="ir.ui.view">
<field name="model">account.invoice</field>
<field name="inherit_id" ref="account.invoice_form"/>
<field name="arch" type="xml">
<button name="action_invoice_draft" position="before">
<button name="prepare_update_wizard" type="object" string="Update Invoice" states="open,paid" groups="account.group_account_invoice"/>
</button>
</field>
</record>
</odoo>

View File

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

View File

@@ -1,302 +0,0 @@
# Copyright 2017 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
# Copyright 2018-2019 Camptocamp
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import models, fields, api, _
from odoo.exceptions import UserError
import odoo.addons.decimal_precision as dp
class AccountInvoiceUpdate(models.TransientModel):
_name = 'account.invoice.update'
_description = 'Wizard to update non-legal fields of invoice'
invoice_id = fields.Many2one(
'account.invoice', string='Invoice', required=True,
readonly=True)
type = fields.Selection(related='invoice_id.type', readonly=True)
company_id = fields.Many2one(
related='invoice_id.company_id', readonly=True)
partner_id = fields.Many2one(
related='invoice_id.partner_id', readonly=True)
user_id = fields.Many2one('res.users', string='Salesperson')
payment_term_id = fields.Many2one(
'account.payment.term', string='Payment Term')
reference = fields.Char(string='Invoice Reference')
name = fields.Char(string='Reference/Description')
origin = fields.Char(string='Source Document')
comment = fields.Text('Additional Information')
partner_bank_id = fields.Many2one(
'res.partner.bank', string='Bank Account')
line_ids = fields.One2many(
'account.invoice.line.update', 'parent_id', string='Invoice Lines')
@api.model
def _simple_fields2update(self):
'''List boolean, date, datetime, char, text fields'''
return ['reference', 'name', 'origin', 'comment']
@api.model
def _m2o_fields2update(self):
return ['payment_term_id', 'user_id', 'partner_bank_id']
@api.model
def _prepare_default_get(self, invoice):
res = {'invoice_id': invoice.id, 'line_ids': []}
for sfield in self._simple_fields2update():
res[sfield] = invoice[sfield]
for m2ofield in self._m2o_fields2update():
res[m2ofield] = invoice[m2ofield].id or False
for line in invoice.invoice_line_ids:
aa_tags = line.analytic_tag_ids
aa_tags = [(6, 0, aa_tags.ids)] if aa_tags else False
res['line_ids'].append([0, 0, {
'invoice_line_id': line.id,
'name': line.name,
'quantity': line.quantity,
'price_subtotal': line.price_subtotal,
'account_analytic_id': line.account_analytic_id.id,
'analytic_tag_ids': aa_tags,
'display_type': line.display_type,
}])
return res
@api.onchange('type')
def type_on_change(self):
res = {'domain': {}}
if self.type in ('out_invoice', 'out_refund'):
res['domain']['partner_bank_id'] =\
"[('partner_id.ref_company_ids', 'in', [company_id])]"
else:
res['domain']['partner_bank_id'] =\
"[('partner_id', '=', partner_id)]"
return res
@api.multi
def _prepare_invoice(self):
vals = {}
inv = self.invoice_id
for sfield in self._simple_fields2update():
if self[sfield] != inv[sfield]:
vals[sfield] = self[sfield]
for m2ofield in self._m2o_fields2update():
if self[m2ofield] != inv[m2ofield]:
vals[m2ofield] = self[m2ofield].id or False
if 'payment_term_id' in vals:
pterm_list = self.payment_term_id.compute(
value=1, date_ref=inv.date_invoice)[0]
if pterm_list:
vals['date_due'] = max(line[0] for line in pterm_list)
return vals
@api.model
def _line_simple_fields2update(self):
return ["name",]
@api.model
def _line_m2o_fields2update(self):
return ["account_analytic_id",]
@api.model
def _line_m2m_fields2update(self):
return ["analytic_tag_ids",]
@api.model
def _prepare_invoice_line(self, line):
vals = {}
for field in self._line_simple_fields2update():
if line[field] != line.invoice_line_id[field]:
vals[field] = line[field]
for field in self._line_m2o_fields2update():
if line[field] != line.invoice_line_id[field]:
vals[field] = line[field].id
for field in self._line_m2m_fields2update():
if line[field] != line.invoice_line_id[field]:
vals[field] = [(6, 0, line[field].ids)]
return vals
@api.multi
def _prepare_move(self):
mvals = {}
inv = self.invoice_id
ini_ref = inv.move_id.ref
ref = inv.reference or inv.name
if ini_ref != ref:
mvals['ref'] = ref
return mvals
@api.multi
def _get_matching_inv_line(self, move_line):
""" Find matching invoice line by product """
# TODO make it accept more case as lines won't
# be grouped unless journal.group_invoice_line is True
inv_line = self.invoice_id.invoice_line_ids.filtered(
lambda rec: rec.product_id == move_line.product_id)
if len(inv_line) != 1:
raise UserError(
"Cannot match a single invoice line to move line %s" %
move_line.name)
return inv_line
@api.multi
def _prepare_move_line(self, inv_line):
mlvals = {}
inv_line_upd = self.line_ids.filtered(
lambda rec: rec.invoice_line_id == inv_line)
ini_aa = inv_line.account_analytic_id
new_aa = inv_line_upd.account_analytic_id
if ini_aa != new_aa:
mlvals['analytic_account_id'] = new_aa.id
ini_aa_tags = inv_line.analytic_tag_ids
new_aa_tags = inv_line_upd.analytic_tag_ids
if ini_aa_tags != new_aa_tags:
mlvals['analytic_tag_ids'] = [(6, None, new_aa_tags.ids)]
return mlvals
@api.multi
def _prepare_analytic_line(self, inv_line):
alvals = {}
inv_line_upd = self.line_ids.filtered(
lambda rec: rec.invoice_line_id == inv_line)
ini_aa = inv_line.account_analytic_id
new_aa = inv_line_upd.account_analytic_id
if ini_aa != new_aa:
alvals['account_id'] = new_aa.id
ini_aa_tags = inv_line.analytic_tag_ids
new_aa_tags = inv_line_upd.analytic_tag_ids
if ini_aa_tags != new_aa_tags:
alvals['tag_ids'] = [(6, None, new_aa_tags.ids)]
return alvals
@api.multi
def _update_payment_term_move(self):
self.ensure_one()
inv = self.invoice_id
if (
self.payment_term_id and
self.payment_term_id != inv.payment_term_id and
inv.move_id):
# I don't update pay term when the invoice is partially (or fully)
# paid because if you have a payment term with several lines
# of the same amount, you would also have to take into account
# the reconcile marks to put the new maturity date on the right
# lines
if inv.payment_ids:
raise UserError(_(
"This wizard doesn't support the update of payment "
"terms on an invoice which is partially or fully "
"paid."))
prec = self.env['decimal.precision'].precision_get('Account')
term_res = self.payment_term_id.compute(
inv.amount_total, inv.date_invoice)[0]
new_pterm = {} # key = int(amount * 100), value = [date1, date2]
for entry in term_res:
amount = int(entry[1] * 10 * prec)
if amount in new_pterm:
new_pterm[amount].append(entry[0])
else:
new_pterm[amount] = [entry[0]]
mlines = {} # key = int(amount * 100), value : [line1, line2]
for line in inv.move_id.line_ids:
if line.account_id == inv.account_id:
amount = int(abs(line.credit - line.debit) * 10 * prec)
if amount in mlines:
mlines[amount].append(line)
else:
mlines[amount] = [line]
for iamount, lines in mlines.items():
if len(lines) != len(new_pterm.get(iamount, [])):
raise UserError(_(
"The original payment term '%s' doesn't have the "
"same terms (number of terms and/or amount) as the "
"new payment term '%s'. You can only switch to a "
"payment term that has the same number of terms "
"with the same amount.") % (
inv.payment_term_id.name, self.payment_term_id.name))
for line in lines:
line.date_maturity = new_pterm[iamount].pop()
@api.multi
def run(self):
self.ensure_one()
inv = self.invoice_id
updated = False
# re-write date_maturity on move line
self._update_payment_term_move()
ivals = self._prepare_invoice()
if ivals:
updated = True
inv.write(ivals)
if inv.move_id:
mvals = self._prepare_move()
if mvals:
inv.move_id.write(mvals)
for ml in inv.move_id.line_ids.filtered(
# we are only interested in invoice lines, not tax lines
lambda rec: bool(rec.product_id)
):
if ml.credit == 0.0:
continue
inv_line = self._get_matching_inv_line(ml)
mlvals = self._prepare_move_line(inv_line)
if mlvals:
updated = True
ml.write(mlvals)
aalines = ml.analytic_line_ids
alvals = self._prepare_analytic_line(inv_line)
if aalines and alvals:
updated = True
if ('account_id' in alvals and
alvals['account_id'] is False):
former_aa = inv_line.account_analytic_id
to_remove_aalines = aalines.filtered(
lambda rec: rec.account_id == former_aa)
# remove existing analytic line
to_remove_aalines.unlink()
else:
aalines.write(alvals)
elif 'account_id' in alvals:
# Create analytic lines if analytic account
# is added later
ml.create_analytic_lines()
for line in self.line_ids:
ilvals = self._prepare_invoice_line(line)
if ilvals:
updated = True
line.invoice_line_id.write(ilvals)
if updated:
inv.message_post(body=_(
'Non-legal fields of invoice updated via the Invoice Update '
'wizard.'))
return True
class AccountInvoiceLineUpdate(models.TransientModel):
_name = 'account.invoice.line.update'
_description = 'Update non-legal fields of invoice lines'
parent_id = fields.Many2one(
'account.invoice.update', string='Wizard', ondelete='cascade')
invoice_line_id = fields.Many2one(
'account.invoice.line', string='Invoice Line', readonly=True)
name = fields.Text(string='Description', required=True)
display_type = fields.Selection([
('line_section', "Section"),
('line_note', "Note")], default=False, help="Technical field for UX purpose.")
quantity = fields.Float(
string='Quantity', digits=dp.get_precision('Product Unit of Measure'),
readonly=True)
price_subtotal = fields.Float(
string='Amount', readonly=True, digits=dp.get_precision('Account'))
account_analytic_id = fields.Many2one(
'account.analytic.account', string='Analytic Account')
analytic_tag_ids = fields.Many2many(
'account.analytic.tag', string='Analytic Tags')

View File

@@ -1,54 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
© 2017 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<odoo>
<record id="account_invoice_update_form" model="ir.ui.view">
<field name="model">account.invoice.update</field>
<field name="arch" type="xml">
<form string="Update Invoice Wizard">
<group name="main">
<field name="invoice_id" invisible="1"/>
<field name="type" invisible="1"/>
<field name="company_id" invisible="1"/>
<field name="partner_id" invisible="1"/>
<field name="reference" attrs="{'invisible': [('type', 'not in', ('in_invoice', 'in_refund'))]}"/>
<field name="origin"/>
<field name="name"/>
<field name="payment_term_id" widget="selection"/>
<field name="partner_bank_id"/>
<field name="user_id"/>
<field name="comment"/>
</group>
<group name="lines">
<field name="line_ids" nolabel="1">
<tree editable="bottom" create="false" delete="false" edit="true">
<field name="invoice_line_id" invisible="1"/>
<field name="display_type" invisible="1"/>
<field name="name"/>
<field name="quantity" attrs="{'invisible': [('display_type', '!=', False)]}"/>
<field name="price_subtotal" attrs="{'invisible': [('display_type', '!=', False)]}"/>
<field name="account_analytic_id" attrs="{'invisible': [('display_type', '!=', False)]}" groups="analytic.group_analytic_accounting"/>
<field name="analytic_tag_ids" attrs="{'invisible': [('display_type', '!=', False)]}" groups="analytic.group_analytic_accounting" widget="many2many_tags"/>
</tree>
</field>
</group>
<footer>
<button name="run" type="object" class="oe_highlight" string="Update"/>
<button special="cancel" string="Cancel" class="oe_link"/>
</footer>
</form>
</field>
</record>
<record id="account_invoice_update_action" model="ir.actions.act_window">
<field name="name">Invoice Update Wizard</field>
<field name="res_model">account.invoice.update</field>
<field name="view_mode">form</field>
<field name="target">new</field>
</record>
</odoo>

View File

@@ -1,96 +0,0 @@
=================
Account Usability
=================
.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |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-AGPL--3-blue.png
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-akretion%2Fodoo--usability-lightgray.png?logo=github
:target: https://github.com/akretion/odoo-usability/tree/12.0/account_usability
:alt: akretion/odoo-usability
|badge1| |badge2| |badge3|
This modules adds the following functions:
* Add an *Overdue* filter on invoice search view (this feature was previously
located in te module *account_invoice_overdue_filter*)
* Increase the default limit of 80 lines in account move and account move line view.
* disable reconciliation "guessing"
* fast search on *Reconcile Ref* for account move line.
* add sale dates to invoice report to be compliant with
https://www.service-public.fr/professionnels-entreprises/vosdroits/F31808
* Sale date on qweb invoices
* A wizard to mark several invoices as sent at once (forward from v8)
* Default date for Account Move Reversal is now D+1 instead of today
* Track more fields on invoice (see details in account.py)
* Add boolean fields `has_discount` and `has_attachment` on invoice
* Add button "Delete line qty = 0" on supplier invoice
* Cut name_get() of invoice if too long
* A script for if Odoo screws up invoice attachment filename
* help functions for py3o reports
* Show code on name_get of journal
* add direct search of journal using code
* add copy=False on some fields
* Add unicity constraint on analytic codes per company
* Better default values on account move
* Add link from account move line to invoice
* Add start_date and end_date on bank statements
* Add transfer_account_id to invoicing config page
* Improve domain reconciliation widget
* account.reconcile.model don't copy name to label via onchange
* Add method to get fiscal position without partner_id
* Restore drill-through on sale and invoice reports
* don't attach PDF upon invoice report generation on supplier invoices/refunds
* Add filter on debit and credit amount for Move Lines
* Add supplier invoice number in invoice tree view
Together with this module, I recommend the use of the following modules:
* account_invoice_supplier_ref_unique (OCA project account-invoicing)
* account_move_line_no_default_search (OCA project account-financial-tools)
* invoice_fiscal_position_update (OCA project account-invoicing)
**Table of contents**
.. contents::
:local:
Bug Tracker
===========
Bugs are tracked on `GitHub Issues <https://github.com/akretion/odoo-usability/issues>`_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us smashing it by providing a detailed and welcomed
`feedback <https://github.com/akretion/odoo-usability/issues/new?body=module:%20account_usability%0Aversion:%2012.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
~~~~~~~
* Akretion
Contributors
~~~~~~~~~~~~
* Alexis de Lattre <alexis.delattre@akretion.com>
* David Beal <david.beal@akretion.com>
Maintainers
~~~~~~~~~~~
This module is part of the `akretion/odoo-usability <https://github.com/akretion/odoo-usability/tree/12.0/account_usability>`_ project on GitHub.
You are welcome to contribute.

View File

@@ -4,10 +4,28 @@
{
'name': 'Account Usability',
'version': '12.0.1.0.0',
'version': '10.0.1.0.0',
'category': 'Accounting & Finance',
'license': 'AGPL-3',
'summary': 'Small usability enhancements in account module',
'description': """
Account Usability
=================
The usability enhancements include:
* show the supplier invoice number in the tree view of supplier invoices
* add an *Overdue* filter on invoice search view (this feature was previously located in te module *account_invoice_overdue_filter*)
* Increase the default limit of 80 lines in account move and account move line view.
* Fast search on *Reconcile Ref* for account move line.
* disable reconciliation "guessing"
Together with this module, I recommend the use of the following modules:
* account_invoice_supplier_ref_unique (OCA project account-invoicing)
* account_move_line_no_default_search (OCA project account-financial-tools)
* invoice_fiscal_position_update (OCA project account-invoicing)
This module has been written by Alexis de Lattre from Akretion <alexis.delattre@akretion.com>.
""",
'author': 'Akretion',
'website': 'http://www.akretion.com',
'depends': [
@@ -22,7 +40,6 @@
'account_invoice_report_view.xml',
'partner_view.xml',
'wizard/account_invoice_mark_sent_view.xml',
'report/invoice_report.xml',
],
'installable': True,
}

View File

@@ -6,7 +6,6 @@ from odoo import models, fields, api, _
from odoo.tools import float_compare, float_is_zero
from odoo.tools.misc import formatLang
from odoo.exceptions import UserError, ValidationError
from odoo.osv import expression
from odoo import SUPERUSER_ID
import logging
@@ -38,10 +37,6 @@ class AccountInvoice(models.Model):
has_attachment = fields.Boolean(
compute='_compute_has_attachment',
search='_search_has_attachment', readonly=True)
sale_dates = fields.Char(
compute="_compute_sales_dates", readonly=True,
help="This information appears on invoice qweb report "
"(you may use it for your own report)")
def _compute_has_discount(self):
prec = self.env['decimal.precision'].precision_get('Discount')
@@ -83,7 +78,7 @@ class AccountInvoice(models.Model):
# top of the screen
# That's why we have to cut the name_get() when it's too long
def name_get(self):
old_res = super().name_get()
old_res = super(AccountInvoice, self).name_get()
res = []
for old_re in old_res:
name = old_re[1]
@@ -103,8 +98,9 @@ class AccountInvoice(models.Model):
# 2) the 'name' field of the account.move.line is used in the overdue
# letter, and '/' is not meaningful for our customer !
# TODO mig to v12
# @api.multi
# def action_move_create(self):
# res = super().action_move_create()
# res = super(AccountInvoice, self).action_move_create()
# for inv in self:
# self._cr.execute(
# "UPDATE account_move_line SET name= "
@@ -174,24 +170,6 @@ class AccountInvoice(models.Model):
# ]
return res
def _compute_sales_dates(self):
""" French law requires to set sale order dates into invoice
returned string: "sale1 (date1), sale2 (date2) ..."
"""
for inv in self:
sales = inv.invoice_line_ids.mapped(
'sale_line_ids').mapped('order_id')
lang = inv.partner_id.commercial_partner_id.lang
date_format = self.env["res.lang"]._lang_get(
lang or "").date_format
dates = ["%s%s" % (
x.name,
x.confirmation_date and " (%s)" %
# only when confirmation_date display it
x.confirmation_date.strftime(date_format) or "")
for x in sales]
inv.sale_dates = ", ".join(dates)
class AccountInvoiceLine(models.Model):
_inherit = 'account.invoice.line'
@@ -215,15 +193,7 @@ class AccountInvoiceLine(models.Model):
class AccountJournal(models.Model):
_inherit = 'account.journal'
hide_bank_statement_balance = fields.Boolean(
string='Hide Bank Statement Balance',
help="You may want to enable this option when your bank "
"journal is generated from a bank statement file that "
"doesn't handle start/end balance (QIF for instance) and "
"you don't want to enter the start/end balance manually: it "
"will prevent the display of wrong information in the accounting "
"dashboard and on bank statements.")
@api.multi
@api.depends(
'name', 'currency_id', 'company_id', 'company_id.currency_id', 'code')
def name_get(self):
@@ -269,6 +239,7 @@ class AccountJournal(models.Model):
class AccountAccount(models.Model):
_inherit = 'account.account'
@api.multi
@api.depends('name', 'code')
def name_get(self):
if self._context.get('account_account_show_code_only'):
@@ -277,7 +248,7 @@ class AccountAccount(models.Model):
res.append((record.id, record.code))
return res
else:
return super().name_get()
return super(AccountAccount, self).name_get()
# https://github.com/odoo/odoo/issues/23040
# TODO mig to v12
@@ -360,6 +331,7 @@ class AccountAccount(models.Model):
class AccountAnalyticAccount(models.Model):
_inherit = 'account.analytic.account'
@api.multi
def name_get(self):
if self._context.get('analytic_account_show_code_only'):
res = []
@@ -367,7 +339,7 @@ class AccountAnalyticAccount(models.Model):
res.append((record.id, record.code or record.name))
return res
else:
return super().name_get()
return super(AccountAnalyticAccount, self).name_get()
_sql_constraints = [(
'code_company_unique',
@@ -514,9 +486,8 @@ class AccountBankStatement(models.Model):
end_date = fields.Date(
compute='_compute_dates', string='End Date', readonly=True,
store=True)
hide_bank_statement_balance = fields.Boolean(
related='journal_id.hide_bank_statement_balance', readonly=True)
@api.multi
@api.depends('line_ids.date')
def _compute_dates(self):
for st in self:
@@ -524,14 +495,7 @@ class AccountBankStatement(models.Model):
st.start_date = dates and min(dates) or False
st.end_date = dates and max(dates) or False
def _balance_check(self):
for stmt in self:
if stmt.hide_bank_statement_balance:
continue
else:
super(AccountBankStatement, stmt)._balance_check()
return True
@api.multi
@api.depends('name', 'start_date', 'end_date')
def name_get(self):
res = []
@@ -569,14 +533,15 @@ class AccountBankStatementLine(models.Model):
# search_reconciliation_proposition=False, context=None):
# # Make variable name shorted for PEP8 !
# search_rec_prop = search_reconciliation_proposition
# return super().\
# return super(AccountBankStatementLine, self).\
# get_data_for_reconciliations(
# cr, uid, ids, excluded_ids=excluded_ids,
# search_reconciliation_proposition=search_rec_prop,
# context=context)
def _prepare_reconciliation_move(self, move_ref):
vals = super()._prepare_reconciliation_move(move_ref)
vals = super(AccountBankStatementLine, self).\
_prepare_reconciliation_move(move_ref)
# By default, ref contains the name of the statement + name of the
# statement line. It causes 2 problems:
# 1) The 'ref' field is too big
@@ -594,13 +559,13 @@ class AccountBankStatementLine(models.Model):
def show_account_move(self):
self.ensure_one()
action = self.env['ir.actions.act_window'].for_xml_id(
'account', 'action_move_line_form')
'account', 'action_move_journal_line')
if self.journal_entry_ids:
action.update({
'views': False,
'view_id': False,
'view_mode': 'form,tree',
'res_id': self.journal_entry_ids[0].move_id.id,
'res_id': self.journal_entry_ids[0].id,
})
return action
else:
@@ -661,46 +626,3 @@ class AccountReconcileModel(models.Model):
# Because it's much better to have the bank statement line label as
# label of the counter-part move line, then the label of the button
assert True # Stupid line of code just to have something...
class AccountIncoterms(models.Model):
_inherit = 'account.incoterms'
@api.depends('code', 'name')
def name_get(self):
res = []
for rec in self:
res.append((rec.id, '[%s] %s' % (rec.code, rec.name)))
return res
class AccountReconciliation(models.AbstractModel):
_inherit = 'account.reconciliation.widget'
# Add ability to filter by account code in the work interface of the
# bank statement
@api.model
def _domain_move_lines(self, search_str):
str_domain = super()._domain_move_lines(search_str)
account_code_domain = [('account_id.code', '=ilike', search_str + '%')]
str_domain = expression.OR([str_domain, account_code_domain])
return str_domain
@api.model
def _domain_move_lines_for_reconciliation(
self, st_line, aml_accounts, partner_id,
excluded_ids=None, search_str=False):
domain = super()._domain_move_lines_for_reconciliation(
st_line, aml_accounts, partner_id,
excluded_ids=excluded_ids, search_str=search_str)
# We want to replace a domain item by another one
position = domain.index(('payment_id', '<>', False))
domain[position] = ['journal_id', '=', st_line.journal_id.id]
return domain
class ResConfigSettings(models.TransientModel):
_inherit = 'res.config.settings'
transfer_account_id = fields.Many2one(
related='company_id.transfer_account_id', readonly=False)

View File

@@ -1,13 +1,53 @@
diff --git a/addons/account/static/src/js/reconciliation/reconciliation_renderer.js b/addons/account/static/src/js/reconciliation/reconciliation_renderer.js
index 53f28e0c620..1721d01edf9 100644
--- a/addons/account/static/src/js/reconciliation/reconciliation_renderer.js
+++ b/addons/account/static/src/js/reconciliation/reconciliation_renderer.js
@@ -514,7 +514,7 @@ var LineRenderer = Widget.extend(FieldManagerMixin, {
}
return this.model.makeRecord('account.bank.statement.line', [field], {
partner_id: {
- domain: ["|", ["is_company", "=", true], ["parent_id", "=", false], "|", ["customer", "=", true], ["supplier", "=", true]],
+ domain: ["|", ["is_company", "=", true], ["parent_id", "=", false]],
options: {
no_open: true
}
diff --git a/addons/account/models/account_bank_statement.py b/addons/account/models/account_bank_statement.py
index 8ed1e48..615da43 100644
--- a/addons/account/models/account_bank_statement.py
+++ b/addons/account/models/account_bank_statement.py
@@ -563,7 +563,13 @@ class AccountBankStatementLine(models.Model):
"""
# Blue lines = payment on bank account not assigned to a statement yet
reconciliation_aml_accounts = [self.journal_id.default_credit_account_id.id, self.journal_id.default_debit_account_id.id]
- domain_reconciliation = ['&', '&', ('statement_id', '=', False), ('account_id', 'in', reconciliation_aml_accounts), ('payment_id','<>', False)]
+ # AKRETION HACK 11/7/2017
+ # Remove ('payment_id','<>', False) in order to allow to select move lines
+ # generated from payment orders or check deposit
+ # but I add ('journal_id', '=', self.journal_id.id) to exclude the
+ # opening entry of the first fiscal year
+ #domain_reconciliation = ['&', '&', ('statement_id', '=', False), ('account_id', 'in', reconciliation_aml_accounts), ('payment_id','<>', False)]
+ domain_reconciliation = ['&', '&', ('statement_id', '=', False), ('account_id', 'in', reconciliation_aml_accounts), ('journal_id', '=', self.journal_id.id)]
# Black lines = unreconciled & (not linked to a payment or open balance created by statement
domain_matching = [('reconciled', '=', False)]
diff --git a/addons/account/models/account_move.py b/addons/account/models/account_move.py
index b60ffbe..6c27c57 100644
--- a/addons/account/models/account_move.py
+++ b/addons/account/models/account_move.py
@@ -599,6 +599,7 @@ class AccountMoveLine(models.Model):
domain = expression.AND([domain, [('id', 'not in', excluded_ids)]])
if str:
str_domain = [
+ '|', ('account_id.code', '=ilike', str + '%'),
'|', ('move_id.name', 'ilike', str),
'|', ('move_id.ref', 'ilike', str),
'|', ('date_maturity', 'like', str),
diff --git a/addons/account/static/src/js/account_reconciliation_widgets.js b/addons/account/static/src/js/account_reconciliation_widgets.js
index 453bd41..48c396e 100644
--- a/addons/account/static/src/js/account_reconciliation_widgets.js
+++ b/addons/account/static/src/js/account_reconciliation_widgets.js
@@ -76,7 +76,7 @@ var abstractReconciliation = Widget.extend(ControlPanelMixin, {
this.model_res_users = new Model("res.users");
this.model_tax = new Model("account.tax");
this.model_presets = new Model("account.reconcile.model");
- this.max_move_lines_displayed = 5;
+ this.max_move_lines_displayed = 15;
// Number of reconciliations loaded initially and by clicking 'show more'
this.num_reconciliations_fetched_in_batch = 10;
this.animation_speed = 100; // "Blocking" animations
@@ -1755,7 +1755,7 @@ var bankStatementReconciliationLine = abstractReconciliationLine.extend({
relation: "res.partner",
string: _t("Partner"),
type: "many2one",
- domain: [['parent_id','=',false], '|', ['customer','=',true], ['supplier','=',true]],
+ domain: [['parent_id','=',false]], // AKRETION HACK 26/6/2017 allow all parent partners
help: "",
readonly: false,
required: true,

View File

@@ -0,0 +1,14 @@
diff --git a/addons/account/models/account_bank_statement.py b/addons/account/models/account_bank_statement.py
index 4374528..aea1361 100644
--- a/addons/account/models/account_bank_statement.py
+++ b/addons/account/models/account_bank_statement.py
@@ -1008,7 +1008,7 @@ class AccountBankStatementLine(models.Model):
#record the move name on the statement line to be able to retrieve it in case of unreconciliation
self.write({'move_name': move.name})
payment.write({'payment_reference': move.name})
- elif self.move_name:
- raise UserError(_('Operation not allowed. Since your statement line already received a number, you cannot reconcile it entirely with existing journal entries otherwise it would make a gap in the numbering. You should book an entry and make a regular revert of it in case you want to cancel it.'))
+ #elif self.move_name:
+ # raise UserError(_('Operation not allowed. Since your statement line already received a number, you cannot reconcile it entirely with existing journal entries otherwise it would make a gap in the numbering. You should book an entry and make a regular revert of it in case you want to cancel it.'))
counterpart_moves.assert_balanced()
return counterpart_moves

View File

@@ -16,9 +16,6 @@
<field name="fiscal_position_id" position="attributes">
<attribute name="widget">selection</attribute>
</field>
<field name="incoterm_id" position="attributes">
<attribute name="widget">selection</attribute>
</field>
<field name="invoice_line_ids" position="before">
<button name="delete_lines_qty_zero" states="draft" string="⇒ Delete lines qty=0" type="object" class="oe_link oe_right" groups="account.group_account_invoice"/>
</field>
@@ -36,9 +33,6 @@
<field name="fiscal_position_id" position="attributes">
<attribute name="widget">selection</attribute>
</field>
<field name="incoterm_id" position="attributes">
<attribute name="widget">selection</attribute>
</field>
<!-- move sent field and make it visible -->
<field name="sent" position="replace"/>
<field name="move_id" position="before">
@@ -360,9 +354,8 @@ module -->
<field name="model">account.move.line</field>
<field name="inherit_id" ref="account.view_move_line_tree"/>
<field name="arch" type="xml">
<field name="full_reconcile_id" position="attributes">
<attribute name="invisible">1</attribute>
</field>
<!-- Move reconcile_id to a better position -->
<field name="full_reconcile_id" position="replace"/>
<field name="credit" position="after">
<field name="balance" sum="Total Balance"/>
<field name="reconcile_string"/>
@@ -409,42 +402,6 @@ module -->
</field>
</record>
<record id="view_account_journal_form" model="ir.ui.view">
<field name="name">usability.account.journal.form</field>
<field name="model">account.journal</field>
<field name="inherit_id" ref="account.view_account_journal_form"/>
<field name="arch" type="xml">
<field name="bank_statements_source" position="after">
<field name="hide_bank_statement_balance" groups="account.group_account_user"/>
</field>
</field>
</record>
<record id="account_journal_dashboard_kanban_view" model="ir.ui.view">
<field name="name">usability.account.journal.dashboard</field>
<field name="model">account.journal</field>
<field name="inherit_id" ref="account.account_journal_dashboard_kanban_view"/>
<field name="arch" type="xml">
<field name="kanban_dashboard" position="after">
<field name="hide_bank_statement_balance"/>
</field>
<xpath expr="//div[@name='latest_statement']/.." position="attributes">
<attribute name="t-if">dashboard.last_balance != dashboard.account_balance &amp;&amp; !record.hide_bank_statement_balance.raw_value</attribute>
</xpath>
</field>
</record>
<record id="view_account_journal_tree" model="ir.ui.view">
<field name="name">usability.account.journal.tree</field>
<field name="model">account.journal</field>
<field name="inherit_id" ref="account.view_account_journal_tree"/>
<field name="arch" type="xml">
<field name="name" position="after">
<field name="code"/>
</field>
</field>
</record>
<record id="view_account_journal_search" model="ir.ui.view">
<field name="name">usability.account.journal.search</field>
<field name="model">account.journal</field>
@@ -466,32 +423,16 @@ module -->
<xpath expr="//field[@name='line_ids']/tree/field[@name='bank_account_id']" position="after">
<!-- The cancel button is provided by the account_cancel module, but we don't want to depend on it -->
<button name="show_account_move" type="object"
string="View Account Move" icon="fa-arrow-right"
string="View Account Move" icon="fa fa-arrow-right"
attrs="{'invisible': [('journal_entry_ids', '=', [])]}"/>
</xpath>
<field name="date" position="after">
<field name="start_date"/>
<field name="end_date"/>
<field name="hide_bank_statement_balance" invisible="1"/>
</field>
<field name="date" position="attributes">
<attribute name="invisible">1</attribute>
</field>
<label for="balance_start" position="attributes">
<attribute name="attrs">{'invisible': [('hide_bank_statement_balance', '=', True)]}</attribute>
</label>
<label for="balance_end_real" position="attributes">
<attribute name="attrs">{'invisible': [('hide_bank_statement_balance', '=', True)]}</attribute>
</label>
<xpath expr="//field[@name='balance_start']/.." position="attributes">
<attribute name="attrs">{'invisible': [('hide_bank_statement_balance', '=', True)]}</attribute>
</xpath>
<xpath expr="//field[@name='balance_end_real']/.." position="attributes">
<attribute name="attrs">{'invisible': [('hide_bank_statement_balance', '=', True)]}</attribute>
</xpath>
<group name="sale_total" position="attributes">
<attribute name="attrs">{'invisible': [('hide_bank_statement_balance', '=', True)]}</attribute>
</group>
</field>
</record>
@@ -534,17 +475,6 @@ module -->
</field>
</record>
<!-- ACCOUNT TAX -->
<record id="view_tax_tree" model="ir.ui.view">
<field name="model">account.tax</field>
<field name="inherit_id" ref="account.view_tax_tree"/>
<field name="arch" type="xml">
<field name="company_id" position="before">
<field name="price_include" string="Include"/>
</field>
</field>
</record>
<!-- ACCOUNT TAX GROUP -->
<!-- in the account module, there is nothing for account.tax.group : no form/tree view, no menu... -->
<record id="account_tax_group_form" model="ir.ui.view">
@@ -579,28 +509,6 @@ module -->
<menuitem id="account_tax_group_menu" action="account_tax_group_action" parent="account.account_account_menu" sequence="2"/>
<!-- Account config page -->
<record id="res_config_settings_view_form" model="ir.ui.view">
<field name="name">account_usability account config page</field>
<field name="model">res.config.settings</field>
<field name="inherit_id" ref="account.res_config_settings_view_form"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='account_bank_reconciliation_start']/../.." position="after">
<div class="col-xs-12 col-md-6 o_setting_box">
<div class="o_setting_left_pane"/>
<div class="o_setting_right_pane">
<label for="transfer_account_id"/>
<div class="text-muted">
Transit account when you transfer money from a bank account of your company to another bank account of your company.
</div>
<field name="transfer_account_id"/>
</div>
</div>
</xpath>
</field>
</record>
<!-- Remove menu entry "Accounting > Configuration > Accounting > Bank Accounts"
(account.journal filtered on type = 'bank' with special tree and form view)
because it is useless and confusing -->

View File

@@ -1,33 +1,33 @@
diff --git a/addons/account/models/account_payment.py b/addons/account/models/account_payment.py
index f38f459c533..a475d6a82c7 100644
index b1d8012329d..b8a8e2a673d 100644
--- a/addons/account/models/account_payment.py
+++ b/addons/account/models/account_payment.py
@@ -62,6 +62,7 @@ class account_abstract_payment(models.AbstractModel):
@@ -210,6 +210,7 @@ class account_payment(models.Model):
payment_difference = fields.Monetary(compute='_compute_payment_difference', readonly=True)
payment_difference_handling = fields.Selection([('open', 'Keep open'), ('reconcile', 'Mark invoice as fully paid')], default='open', string="Payment Difference Handling", copy=False)
payment_difference_handling = fields.Selection([('open', 'Keep open'), ('reconcile', 'Mark invoice as fully paid')], default='open', string="Payment Difference", copy=False)
writeoff_account_id = fields.Many2one('account.account', string="Difference Account", domain=[('deprecated', '=', False)], copy=False)
+ writeoff_analytic_account_id = fields.Many2one('account.analytic.account', string="Difference Analytic Account", copy=False)
writeoff_label = fields.Char(
string='Journal Item Label',
help='Change label of the counterpart that will hold the payment difference',
@@ -717,6 +718,7 @@ class account_payment(models.Model):
debit_wo, credit_wo, amount_currency_wo, currency_id = aml_obj.with_context(date=self.payment_date)._compute_amount_fields(self.payment_difference, self.currency_id, self.company_id.currency_id)
writeoff_line['name'] = self.writeoff_label
# FIXME: ondelete='restrict' not working (eg. cancel a bank statement reconciliation with a payment)
move_line_ids = fields.One2many('account.move.line', 'payment_id', readonly=True, copy=False, ondelete='restrict')
@@ -431,6 +432,7 @@ class account_payment(models.Model):
amount_currency_wo = -abs(amount_currency_wo)
writeoff_line['name'] = _('Counterpart')
writeoff_line['account_id'] = self.writeoff_account_id.id
+ writeoff_line['analytic_account_id'] = self.writeoff_analytic_account_id.id or False
writeoff_line['debit'] = debit_wo
writeoff_line['credit'] = credit_wo
writeoff_line['amount_currency'] = amount_currency_wo
diff --git a/addons/account/views/account_payment_view.xml b/addons/account/views/account_payment_view.xml
index 07230902ee8..1359009bf23 100644
index 2460458fbaa..4065d8f9952 100644
--- a/addons/account/views/account_payment_view.xml
+++ b/addons/account/views/account_payment_view.xml
@@ -277,6 +277,8 @@
<div attrs="{'invisible': [('payment_difference_handling','=','open')]}">
<label for="writeoff_account_id" class="oe_edit_only" string="Post Difference In"/>
<field name="writeoff_account_id" string="Post Difference In" attrs="{'required': [('payment_difference_handling', '=', 'reconcile')]}"/>
+ <label for="writeoff_analytic_account_id" class="oe_edit_only" string="Analytic Account" groups="analytic.group_analytic_accounting"/>
+ <field name="writeoff_analytic_account_id" groups="analytic.group_analytic_accounting"/>
<label for="journal_id" string="Journal" attrs="{'invisible': [('amount', '!=', 0)]}"/>
<field name="journal_id" string="Journal" widget="selection" attrs="{'invisible': [('amount', '!=', 0)]}"/>
<label for="writeoff_label" class="oe_edit_only" string="Label"/>
@@ -206,6 +206,8 @@
</div>
<field name="writeoff_account_id" string="Post Difference In"
attrs="{'invisible': [('payment_difference_handling','=','open')], 'required': [('payment_difference_handling', '=', 'reconcile')]}"/>
+ <field name="writeoff_analytic_account_id" string="Post Difference In Analytic Account"
+ attrs="{'invisible': [('payment_difference_handling','=','open')]}"/>
</group>
</group>
</sheet>

View File

@@ -1,2 +0,0 @@
* Alexis de Lattre <alexis.delattre@akretion.com>
* David Beal <david.beal@akretion.com>

View File

@@ -1,39 +0,0 @@
This modules adds the following functions:
* Add an *Overdue* filter on invoice search view (this feature was previously
located in te module *account_invoice_overdue_filter*)
* Increase the default limit of 80 lines in account move and account move line view.
* disable reconciliation "guessing"
* fast search on *Reconcile Ref* for account move line.
* add sale dates to invoice report to be compliant with
https://www.service-public.fr/professionnels-entreprises/vosdroits/F31808
* Sale date on qweb invoices
* A wizard to mark several invoices as sent at once (forward from v8)
* Default date for Account Move Reversal is now D+1 instead of today
* Track more fields on invoice (see details in account.py)
* Add boolean fields `has_discount` and `has_attachment` on invoice
* Add button "Delete line qty = 0" on supplier invoice
* Cut name_get() of invoice if too long
* A script for if Odoo screws up invoice attachment filename
* help functions for py3o reports
* Show code on name_get of journal
* add direct search of journal using code
* add copy=False on some fields
* Add unicity constraint on analytic codes per company
* Better default values on account move
* Add link from account move line to invoice
* Add start_date and end_date on bank statements
* Add transfer_account_id to invoicing config page
* Improve domain reconciliation widget
* account.reconcile.model don't copy name to label via onchange
* Add method to get fiscal position without partner_id
* Restore drill-through on sale and invoice reports
* don't attach PDF upon invoice report generation on supplier invoices/refunds
* Add filter on debit and credit amount for Move Lines
* Add supplier invoice number in invoice tree view
Together with this module, I recommend the use of the following modules:
* account_invoice_supplier_ref_unique (OCA project account-invoicing)
* account_move_line_no_default_search (OCA project account-financial-tools)
* invoice_fiscal_position_update (OCA project account-invoicing)

View File

@@ -1,10 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template id="report_invoice_document" inherit_id="account.report_invoice_document">
<xpath expr="//div[@name='origin']/p" position="replace">
<p class="m-0" t-field="o.sale_dates"/>
</xpath>
</template>
</odoo>

View File

@@ -1,454 +0,0 @@
<?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 0.15.1: http://docutils.sourceforge.net/" />
<title>Account Usability</title>
<style type="text/css">
/*
:Author: David Goodger (goodger@python.org)
:Id: $Id: html4css1.css 7952 2016-07-26 18:15:59Z milde $
:Copyright: This stylesheet has been placed in the public domain.
Default cascading style sheet for the HTML output of Docutils.
See http://docutils.sf.net/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="account-usability">
<h1 class="title">Account Usability</h1>
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<p><a class="reference external" 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" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external" href="https://github.com/akretion/odoo-usability/tree/12.0/account_usability"><img alt="akretion/odoo-usability" src="https://img.shields.io/badge/github-akretion%2Fodoo--usability-lightgray.png?logo=github" /></a></p>
<p>This modules adds the following functions:</p>
<ul class="simple">
<li>Add an <em>Overdue</em> filter on invoice search view (this feature was previously
located in te module <em>account_invoice_overdue_filter</em>)</li>
<li>Increase the default limit of 80 lines in account move and account move line view.</li>
<li>disable reconciliation “guessing”</li>
<li>fast search on <em>Reconcile Ref</em> for account move line.</li>
<li>add sale dates to invoice report to be compliant with
<a class="reference external" href="https://www.service-public.fr/professionnels-entreprises/vosdroits/F31808">https://www.service-public.fr/professionnels-entreprises/vosdroits/F31808</a></li>
<li>Sale date on qweb invoices</li>
<li>A wizard to mark several invoices as sent at once (forward from v8)</li>
<li>Default date for Account Move Reversal is now D+1 instead of today</li>
<li>Track more fields on invoice (see details in account.py)</li>
<li>Add boolean fields <cite>has_discount</cite> and <cite>has_attachment</cite> on invoice</li>
<li>Add button “Delete line qty = 0” on supplier invoice</li>
<li>Cut name_get() of invoice if too long</li>
<li>A script for if Odoo screws up invoice attachment filename</li>
<li>help functions for py3o reports</li>
<li>Show code on name_get of journal</li>
<li>add direct search of journal using code</li>
<li>add copy=False on some fields</li>
<li>Add unicity constraint on analytic codes per company</li>
<li>Better default values on account move</li>
<li>Add link from account move line to invoice</li>
<li>Add start_date and end_date on bank statements</li>
<li>Add transfer_account_id to invoicing config page</li>
<li>Improve domain reconciliation widget</li>
<li>account.reconcile.model dont copy name to label via onchange</li>
<li>Add method to get fiscal position without partner_id</li>
<li>Restore drill-through on sale and invoice reports</li>
<li>dont attach PDF upon invoice report generation on supplier invoices/refunds</li>
<li>Add filter on debit and credit amount for Move Lines</li>
<li>Add supplier invoice number in invoice tree view</li>
</ul>
<p>Together with this module, I recommend the use of the following modules:</p>
<ul class="simple">
<li>account_invoice_supplier_ref_unique (OCA project account-invoicing)</li>
<li>account_move_line_no_default_search (OCA project account-financial-tools)</li>
<li>invoice_fiscal_position_update (OCA project account-invoicing)</li>
</ul>
<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="id1">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="id2">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="id3">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="id4">Contributors</a></li>
<li><a class="reference internal" href="#maintainers" id="id5">Maintainers</a></li>
</ul>
</li>
</ul>
</div>
<div class="section" id="bug-tracker">
<h1><a class="toc-backref" href="#id1">Bug Tracker</a></h1>
<p>Bugs are tracked on <a class="reference external" href="https://github.com/akretion/odoo-usability/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 smashing it by providing a detailed and welcomed
<a class="reference external" href="https://github.com/akretion/odoo-usability/issues/new?body=module:%20account_usability%0Aversion:%2012.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="#id2">Credits</a></h1>
<div class="section" id="authors">
<h2><a class="toc-backref" href="#id3">Authors</a></h2>
<ul class="simple">
<li>Akretion</li>
</ul>
</div>
<div class="section" id="contributors">
<h2><a class="toc-backref" href="#id4">Contributors</a></h2>
<ul class="simple">
<li>Alexis de Lattre &lt;<a class="reference external" href="mailto:alexis.delattre&#64;akretion.com">alexis.delattre&#64;akretion.com</a>&gt;</li>
<li>David Beal &lt;<a class="reference external" href="mailto:david.beal&#64;akretion.com">david.beal&#64;akretion.com</a>&gt;</li>
</ul>
</div>
<div class="section" id="maintainers">
<h2><a class="toc-backref" href="#id5">Maintainers</a></h2>
<p>This module is part of the <a class="reference external" href="https://github.com/akretion/odoo-usability/tree/12.0/account_usability">akretion/odoo-usability</a> project on GitHub.</p>
<p>You are welcome to contribute.</p>
</div>
</div>
</div>
</body>
</html>

View File

@@ -1,61 +0,0 @@
======================
Base Company Extension
======================
.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |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-AGPL--3-blue.png
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-akretion%2Fodoo--usability-lightgray.png?logo=github
:target: https://github.com/akretion/odoo-usability/tree/12.0/base_company_extension
:alt: akretion/odoo-usability
|badge1| |badge2| |badge3|
This module adds the following fields to the ResCompany model:
* Capital Amount
* Legal Type
This is useful to display the legal name of the company in reports
**Table of contents**
.. contents::
:local:
Bug Tracker
===========
Bugs are tracked on `GitHub Issues <https://github.com/akretion/odoo-usability/issues>`_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us smashing it by providing a detailed and welcomed
`feedback <https://github.com/akretion/odoo-usability/issues/new?body=module:%20base_company_extension%0Aversion:%2012.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
~~~~~~~
* Akretion
Contributors
~~~~~~~~~~~~
* Alexis de Lattre <alexis.delattre@akretion.com>
Maintainers
~~~~~~~~~~~
This module is part of the `akretion/odoo-usability <https://github.com/akretion/odoo-usability/tree/12.0/base_company_extension>`_ project on GitHub.
You are welcome to contribute.

View File

@@ -9,6 +9,16 @@
'category': 'Partner',
'license': 'AGPL-3',
'summary': 'Adds capital and title on company',
'description': """
Base Company Extension
======================
This module adds 2 fields on the Company :
* *Capital Amount*
* *Legal Form*
""",
'author': 'Akretion',
'website': 'http://www.akretion.com',
# I depend on base_usability only for _report_company_legal_name()

View File

@@ -1 +0,0 @@
* Alexis de Lattre <alexis.delattre@akretion.com>

View File

@@ -1,5 +0,0 @@
This module adds the following fields to the ResCompany model:
* Capital Amount
* Legal Type
This is useful to display the legal name of the company in reports

View File

@@ -1,417 +0,0 @@
<?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 0.15.1: http://docutils.sourceforge.net/" />
<title>Base Company Extension</title>
<style type="text/css">
/*
:Author: David Goodger (goodger@python.org)
:Id: $Id: html4css1.css 7952 2016-07-26 18:15:59Z milde $
:Copyright: This stylesheet has been placed in the public domain.
Default cascading style sheet for the HTML output of Docutils.
See http://docutils.sf.net/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-company-extension">
<h1 class="title">Base Company Extension</h1>
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<p><a class="reference external" 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" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external" href="https://github.com/akretion/odoo-usability/tree/12.0/base_company_extension"><img alt="akretion/odoo-usability" src="https://img.shields.io/badge/github-akretion%2Fodoo--usability-lightgray.png?logo=github" /></a></p>
<p>This module adds the following fields to the ResCompany model:
* Capital Amount
* Legal Type</p>
<p>This is useful to display the legal name of the company in reports</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="id1">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="id2">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="id3">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="id4">Contributors</a></li>
<li><a class="reference internal" href="#maintainers" id="id5">Maintainers</a></li>
</ul>
</li>
</ul>
</div>
<div class="section" id="bug-tracker">
<h1><a class="toc-backref" href="#id1">Bug Tracker</a></h1>
<p>Bugs are tracked on <a class="reference external" href="https://github.com/akretion/odoo-usability/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 smashing it by providing a detailed and welcomed
<a class="reference external" href="https://github.com/akretion/odoo-usability/issues/new?body=module:%20base_company_extension%0Aversion:%2012.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="#id2">Credits</a></h1>
<div class="section" id="authors">
<h2><a class="toc-backref" href="#id3">Authors</a></h2>
<ul class="simple">
<li>Akretion</li>
</ul>
</div>
<div class="section" id="contributors">
<h2><a class="toc-backref" href="#id4">Contributors</a></h2>
<ul class="simple">
<li>Alexis de Lattre &lt;<a class="reference external" href="mailto:alexis.delattre&#64;akretion.com">alexis.delattre&#64;akretion.com</a>&gt;</li>
</ul>
</div>
<div class="section" id="maintainers">
<h2><a class="toc-backref" href="#id5">Maintainers</a></h2>
<p>This module is part of the <a class="reference external" href="https://github.com/akretion/odoo-usability/tree/12.0/base_company_extension">akretion/odoo-usability</a> project on GitHub.</p>
<p>You are welcome to contribute.</p>
</div>
</div>
</div>
</body>
</html>

View File

@@ -1,61 +0,0 @@
======================
Base Partner Reference
======================
.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |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-AGPL--3-blue.png
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-Akretion%2FOdoo--Usability-lightgray.png?logo=github
:target: https://github.com/Akretion/Odoo-Usability/tree/12.0/base_partner_ref
:alt: Akretion/Odoo-Usability
|badge1| |badge2| |badge3|
Improve usage of partner's Internal Reference, this module adds the following functions:
- Adds Internal Reference in partner tree view
- Adds Internal Reference in name_get()
- Adds unicity constraint on Internal Reference
**Table of contents**
.. contents::
:local:
Bug Tracker
===========
Bugs are tracked on `GitHub Issues <https://github.com/Akretion/Odoo-Usability/issues>`_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us smashing it by providing a detailed and welcomed
`feedback <https://github.com/Akretion/Odoo-Usability/issues/new?body=module:%20base_partner_ref%0Aversion:%2012.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
~~~~~~~
* Akretion
Contributors
~~~~~~~~~~~~
* Alexis de Lattre <alexis.delattre@akretion.com>
* Renato Lima <renato.lima@akretion.com.br>
Maintainers
~~~~~~~~~~~
This module is part of the `Akretion/Odoo-Usability <https://github.com/Akretion/Odoo-Usability/tree/12.0/base_partner_ref>`_ project on GitHub.
You are welcome to contribute.

View File

@@ -1,4 +1 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from . import models
from . import tests
from . import partner

View File

@@ -21,8 +21,6 @@ Base Partner Reference
'author': 'Akretion',
'website': 'http://www.akretion.com',
'depends': ['base'],
'data': [
'views/partner.xml',
],
'data': ['partner_view.xml'],
'installable': True,
}

View File

@@ -1,3 +0,0 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from . import partner

View File

@@ -2,29 +2,19 @@
# @author: Alexis de Lattre <alexis.delattre@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import _, api, fields, models
from odoo import models, fields
class ResPartner(models.Model):
_inherit = 'res.partner'
ref = fields.Char(
copy=False, # To avoid blocking duplicate
)
invalidate_display_name = fields.Boolean()
ref = fields.Char(copy=False) # To avoid blocking duplicate
_sql_constraints = [(
'ref_unique',
'unique(ref)',
_('A partner already exists with this internal reference !')
)]
# add 'ref' in depends
@api.depends('is_company', 'name', 'parent_id.name', 'type',
'company_name', 'ref', 'invalidate_display_name')
def _compute_display_name(self):
super()._compute_display_name()
'A partner already exists with this internal reference!'
)]
def _get_name(self):
partner = self
@@ -36,15 +26,12 @@ class ResPartner(models.Model):
# END modif of native method
if partner.company_name or partner.parent_id:
if not name and partner.type in ['invoice', 'delivery', 'other']:
name = dict(self.fields_get(
['type'])['type']['selection'])[partner.type]
name = dict(self.fields_get(['type'])['type']['selection'])[partner.type]
if not partner.is_company:
# START modif of native name_get() method
company_name = (
partner.commercial_company_name or partner.parent_id.name)
company_name = partner.commercial_company_name or partner.parent_id.name
if partner.parent_id.ref:
company_name = u"[%s] %s" % (
partner.parent_id.ref, company_name)
company_name = u"[%s] %s" % (partner.parent_id.ref, company_name)
name = "%s, %s" % (company_name, name)
# END modif of native name_get() method
if self._context.get('show_address_only'):

View File

@@ -1,2 +0,0 @@
* Alexis de Lattre <alexis.delattre@akretion.com>
* Renato Lima <renato.lima@akretion.com.br>

View File

@@ -1,4 +0,0 @@
Improve usage of partner's Internal Reference, this module adds the following functions:
- Adds Internal Reference in partner tree view
- Adds Internal Reference in name_get()
- Adds unicity constraint on Internal Reference

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.5 KiB

View File

@@ -1,423 +0,0 @@
<?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 0.15.1: http://docutils.sourceforge.net/" />
<title>Base Partner Reference</title>
<style type="text/css">
/*
:Author: David Goodger (goodger@python.org)
:Id: $Id: html4css1.css 7952 2016-07-26 18:15:59Z milde $
:Copyright: This stylesheet has been placed in the public domain.
Default cascading style sheet for the HTML output of Docutils.
See http://docutils.sf.net/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-partner-reference">
<h1 class="title">Base Partner Reference</h1>
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<p><a class="reference external" 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" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external" href="https://github.com/Akretion/Odoo-Usability/tree/12.0/base_partner_ref"><img alt="Akretion/Odoo-Usability" src="https://img.shields.io/badge/github-Akretion%2FOdoo--Usability-lightgray.png?logo=github" /></a></p>
<dl class="docutils">
<dt>Improve usage of partners Internal Reference, this module adds the following functions:</dt>
<dd><ul class="first last simple">
<li>Adds Internal Reference in partner tree view</li>
<li>Adds Internal Reference in name_get()</li>
<li>Adds unicity constraint on Internal Reference</li>
</ul>
</dd>
</dl>
<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="id1">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="id2">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="id3">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="id4">Contributors</a></li>
<li><a class="reference internal" href="#maintainers" id="id5">Maintainers</a></li>
</ul>
</li>
</ul>
</div>
<div class="section" id="bug-tracker">
<h1><a class="toc-backref" href="#id1">Bug Tracker</a></h1>
<p>Bugs are tracked on <a class="reference external" href="https://github.com/Akretion/Odoo-Usability/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 smashing it by providing a detailed and welcomed
<a class="reference external" href="https://github.com/Akretion/Odoo-Usability/issues/new?body=module:%20base_partner_ref%0Aversion:%2012.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="#id2">Credits</a></h1>
<div class="section" id="authors">
<h2><a class="toc-backref" href="#id3">Authors</a></h2>
<ul class="simple">
<li>Akretion</li>
</ul>
</div>
<div class="section" id="contributors">
<h2><a class="toc-backref" href="#id4">Contributors</a></h2>
<ul class="simple">
<li>Alexis de Lattre &lt;<a class="reference external" href="mailto:alexis.delattre&#64;akretion.com">alexis.delattre&#64;akretion.com</a>&gt;</li>
<li>Renato Lima &lt;<a class="reference external" href="mailto:renato.lima&#64;akretion.com.br">renato.lima&#64;akretion.com.br</a>&gt;</li>
</ul>
</div>
<div class="section" id="maintainers">
<h2><a class="toc-backref" href="#id5">Maintainers</a></h2>
<p>This module is part of the <a class="reference external" href="https://github.com/Akretion/Odoo-Usability/tree/12.0/base_partner_ref">Akretion/Odoo-Usability</a> project on GitHub.</p>
<p>You are welcome to contribute.</p>
</div>
</div>
</div>
</body>
</html>

View File

@@ -1,3 +0,0 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from . import test_partner

View File

@@ -1,33 +0,0 @@
# Copyright 2020 Akretion
# @author: Renato Lima <renato.lima@akretion.com.br>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from psycopg2 import IntegrityError
from odoo.tools import mute_logger
from odoo.tests.common import TransactionCase
class TestPartner(TransactionCase):
def setUp(self):
super().setUp()
self.partner_values = {
'name': 'Akretion Test Partner',
'ref': '220',
}
self.partner = self._create_partner(self.partner_values)
def _create_partner(self, values):
return self.env['res.partner'].create(values)
def test_partners_same_ref(self):
"""Check create two partners with same ref"""
with self.assertRaises(IntegrityError), mute_logger('odoo.sql_db'):
self._create_partner(self.partner_values)
def test_partner_get_name(self):
"""Check partner name get"""
self.assertEqual(
self.partner._get_name(), '[220] Akretion Test Partner'
)

View File

@@ -1,82 +0,0 @@
==============
Base Usability
==============
.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |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-AGPL--3-blue.png
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-akretion%2Fodoo--usability-lightgray.png?logo=github
:target: https://github.com/akretion/odoo-usability/tree/12.0/base_usability
:alt: akretion/odoo-usability
|badge1| |badge2| |badge3|
This module adds the following functions:
* Adds *track_visibility='onchange'* on all the important fields of the Partner object
* By default, Odoo doesn't display the title field on all the partner form views. This module fixes it (it replaces the module base_title_on_partner)
* Adds a log message at INFO level when sending an email via SMTP
* Displays the local modules with installable filter
* A group by "State" is added to module search view
* Provides a _display_report_header method on the res.company object and _display_full_address on res.partner which are useful for reporting.
* Add model in cron tree view
* Add prefix field in sequence search view
* Better search and form view for country and state
* Display technical name of modules in kanban view
* Change module filter to `installable`
* Add widget=handle on sequence of res.partner.bank
* Add city and country in partner tree view
* Add widget="email" on email of contacts
* Add script to fix partners related to users in multi-company setup
* Add methods for py3o reports
* Add name_get() on ir.model
* Language wizard defaults to ".po"
* Add tracking on partner fields
* Handle lang in name_title field
* Remove empty lines in address
* Add bank Name field on res.partner.bank
* Partners auto-created for users are Suppliers and not Customers
**Table of contents**
.. contents::
:local:
Bug Tracker
===========
Bugs are tracked on `GitHub Issues <https://github.com/akretion/odoo-usability/issues>`_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us smashing it by providing a detailed and welcomed
`feedback <https://github.com/akretion/odoo-usability/issues/new?body=module:%20base_usability%0Aversion:%2012.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
~~~~~~~
* Akretion
Contributors
~~~~~~~~~~~~
* Alexis de Lattre <alexis.delattre@akretion.com>
* David Beal <david.beal@akretion.com>
Maintainers
~~~~~~~~~~~
This module is part of the `akretion/odoo-usability <https://github.com/akretion/odoo-usability/tree/12.0/base_usability>`_ project on GitHub.
You are welcome to contribute.

View File

@@ -8,6 +8,22 @@
'category': 'Partner',
'license': 'AGPL-3',
'summary': 'Better usability in base module',
'description': """
Base Usability
==============
This module adds *track_visibility='onchange'* on all the important fields of the Partner object.
By default, Odoo doesn't display the title field on all the partner form views. This module fixes it (it replaces the module base_title_on_partner).
It also adds a log message at INFO level when sending an email via SMTP.
It displays the local modules with installable filter.
A group by 'State' is added to module search view.
It provides a _display_report_header method on the res.company object and
_display_full_address on res.partner which are useful for reporting.
""",
'author': 'Akretion',
'website': 'http://www.akretion.com',
'depends': ['base'],

View File

@@ -3,4 +3,3 @@ from . import partner
from . import company
from . import mail
from . import misc
from . import ir_model

View File

@@ -1,16 +0,0 @@
# Copyright 2019 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 api, models
class IrModel(models.Model):
_inherit = 'ir.model'
@api.depends('name', 'model')
def name_get(self):
res = []
for rec in self:
res.append((rec.id, '%s (%s)' % (rec.name, rec.model)))
return res

View File

@@ -1,3 +0,0 @@
* Alexis de Lattre <alexis.delattre@akretion.com>
* Raphaël Valyi <rvalyi@akretion.com>
* David Beal <david.beal@akretion.com>

View File

@@ -1,25 +0,0 @@
This module adds the following functions:
* Adds *track_visibility='onchange'* on all the important fields of the Partner object
* By default, Odoo doesn't display the title field on all the partner form views. This module fixes it (it replaces the module base_title_on_partner)
* Adds a log message at INFO level when sending an email via SMTP
* Displays the local modules with installable filter
* A group by "State" is added to module search view
* Provides a _display_report_header method on the res.company object and _display_full_address on res.partner which are useful for reporting.
* Add model in cron tree view
* Add prefix field in sequence search view
* Better search and form view for country and state
* Display technical name of modules in kanban view
* Change module filter to `installable`
* Add widget=handle on sequence of res.partner.bank
* Add city and country in partner tree view
* Add widget="email" on email of contacts
* Add script to fix partners related to users in multi-company setup
* Add methods for py3o reports
* Add name_get() on ir.model
* Language wizard defaults to ".po"
* Add tracking on partner fields
* Handle lang in name_title field
* Remove empty lines in address
* Add bank Name field on res.partner.bank
* Partners auto-created for users are Suppliers and not Customers

View File

@@ -1,440 +0,0 @@
<?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 0.15.1: http://docutils.sourceforge.net/" />
<title>Base Usability</title>
<style type="text/css">
/*
:Author: David Goodger (goodger@python.org)
:Id: $Id: html4css1.css 7952 2016-07-26 18:15:59Z milde $
:Copyright: This stylesheet has been placed in the public domain.
Default cascading style sheet for the HTML output of Docutils.
See http://docutils.sf.net/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-usability">
<h1 class="title">Base Usability</h1>
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<p><a class="reference external" 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" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external" href="https://github.com/akretion/odoo-usability/tree/12.0/base_usability"><img alt="akretion/odoo-usability" src="https://img.shields.io/badge/github-akretion%2Fodoo--usability-lightgray.png?logo=github" /></a></p>
<p>This module adds the following functions:</p>
<ul class="simple">
<li>Adds <em>track_visibility=onchange</em> on all the important fields of the Partner object</li>
<li>By default, Odoo doesnt display the title field on all the partner form views. This module fixes it (it replaces the module base_title_on_partner)</li>
<li>Adds a log message at INFO level when sending an email via SMTP</li>
<li>Displays the local modules with installable filter</li>
<li>A group by “State” is added to module search view</li>
<li>Provides a _display_report_header method on the res.company object and _display_full_address on res.partner which are useful for reporting.</li>
<li>Add model in cron tree view</li>
<li>Add prefix field in sequence search view</li>
<li>Better search and form view for country and state</li>
<li>Display technical name of modules in kanban view</li>
<li>Change module filter to <cite>installable</cite></li>
<li>Add widget=handle on sequence of res.partner.bank</li>
<li>Add city and country in partner tree view</li>
<li>Add widget=”email” on email of contacts</li>
<li>Add script to fix partners related to users in multi-company setup</li>
<li>Add methods for py3o reports</li>
<li>Add name_get() on ir.model</li>
<li>Language wizard defaults to “.po”</li>
<li>Add tracking on partner fields</li>
<li>Handle lang in name_title field</li>
<li>Remove empty lines in address</li>
<li>Add bank Name field on res.partner.bank</li>
<li>Partners auto-created for users are Suppliers and not Customers</li>
</ul>
<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="id1">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="id2">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="id3">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="id4">Contributors</a></li>
<li><a class="reference internal" href="#maintainers" id="id5">Maintainers</a></li>
</ul>
</li>
</ul>
</div>
<div class="section" id="bug-tracker">
<h1><a class="toc-backref" href="#id1">Bug Tracker</a></h1>
<p>Bugs are tracked on <a class="reference external" href="https://github.com/akretion/odoo-usability/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 smashing it by providing a detailed and welcomed
<a class="reference external" href="https://github.com/akretion/odoo-usability/issues/new?body=module:%20base_usability%0Aversion:%2012.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="#id2">Credits</a></h1>
<div class="section" id="authors">
<h2><a class="toc-backref" href="#id3">Authors</a></h2>
<ul class="simple">
<li>Akretion</li>
</ul>
</div>
<div class="section" id="contributors">
<h2><a class="toc-backref" href="#id4">Contributors</a></h2>
<ul class="simple">
<li>Alexis de Lattre &lt;<a class="reference external" href="mailto:alexis.delattre&#64;akretion.com">alexis.delattre&#64;akretion.com</a>&gt;</li>
<li>David Beal &lt;<a class="reference external" href="mailto:david.beal&#64;akretion.com">david.beal&#64;akretion.com</a>&gt;</li>
</ul>
</div>
<div class="section" id="maintainers">
<h2><a class="toc-backref" href="#id5">Maintainers</a></h2>
<p>This module is part of the <a class="reference external" href="https://github.com/akretion/odoo-usability/tree/12.0/base_usability">akretion/odoo-usability</a> project on GitHub.</p>
<p>You are welcome to contribute.</p>
</div>
</div>
</div>
</body>
</html>

View File

@@ -12,14 +12,4 @@
</field>
</record>
<record id="view_sequence_search" model="ir.ui.view">
<field name="model">ir.sequence</field>
<field name="inherit_id" ref="base.view_sequence_search"/>
<field name="arch" type="xml">
<field name="name" position="after">
<field name="prefix"/>
</field>
</field>
</record>
</odoo>

View File

@@ -1,23 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2015-2019 Akretion France (http://www.akretion.com/)
© 2015-2016 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="module_view_kanban" model="ir.ui.view">
<field name="name">Better display of module technical name</field>
<field name="model">ir.module.module</field>
<field name="inherit_id" ref="base.module_view_kanban"/>
<field name="arch" type="xml">
<xpath expr="//h4[hasclass('o_kanban_record_title')]/code[@groups='base.group_no_one']" position="before">
<br/>
</xpath>
</field>
</record>
<record id="view_module_filter" model="ir.ui.view">
<field name="model">ir.module.module</field>
<field name="inherit_id" ref="base.view_module_filter"/>
@@ -35,5 +24,4 @@
<field name="context">{'search_default_installable': 1}</field>
</record>
</odoo>

View File

@@ -12,6 +12,10 @@
<field name="model">res.partner</field>
<field name="inherit_id" ref="base.view_partner_form"/>
<field name="arch" type="xml">
<!-- Wider 'name' field -->
<xpath expr="//sheet/div[hasclass('oe_title')]" position="attributes">
<attribute name="style">width: 650px;</attribute>
</xpath>
<xpath expr="//field[@name='child_ids']/form//field[@name='email']" position="attributes">
<attribute name="widget">email</attribute>
</xpath>
@@ -57,9 +61,6 @@
<!-- for 'ref', change '=' to 'start with' -->
<attribute name="filter_domain">['|','|',('display_name','ilike',self),('ref','=ilike',self + '%'),('email','ilike',self)]</attribute>
</field>
<filter name="inactive" position="before">
<separator/>
</filter>
</field>
</record>

View File

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

View File

@@ -1,29 +0,0 @@
# Copyright 2018-2019 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': 'Delivery Usability',
'version': '12.0.1.0.0',
'category': 'Stock',
'license': 'AGPL-3',
'summary': 'Several usability enhancements in Delivery',
'description': """
Delivery Usability
===================
The usability enhancements include:
* allow modification of carrier and it's tracking ref. on a done picking
* display field 'invoice_shipping_on_delivery' on sale.order form view
This module has been written by Alexis de Lattre from Akretion <alexis.delattre@akretion.com>.
""",
'author': 'Akretion',
'website': 'http://www.akretion.com',
'depends': ['delivery'],
'data': [
'sale_view.xml',
'stock_view.xml',
],
'installable': True,
}

View File

@@ -1,23 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2018-2019 Akretion
@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_with_carrier" model="ir.ui.view">
<field name="name">delivery_usability.sale.order.form</field>
<field name="model">sale.order</field>
<field name="inherit_id" ref="delivery.view_order_form_with_carrier"/>
<field name="arch" type="xml">
<group name="sale_pay" position="inside">
<field name="invoice_shipping_on_delivery"/>
</group>
</field>
</record>
</odoo>

View File

@@ -1,12 +0,0 @@
# Copyright 2018-2019 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 StockPicking(models.Model):
_inherit = 'stock.picking'
carrier_id = fields.Many2one(track_visibility='onchange')
carrier_tracking_ref = fields.Char(track_visibility='onchange')

View File

@@ -1,26 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2018 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<odoo>
<record id="view_picking_withcarrier_out_form" model="ir.ui.view">
<field name="name">delivery_usability.stock.picking.form</field>
<field name="model">stock.picking</field>
<field name="inherit_id" ref="delivery.view_picking_withcarrier_out_form"/>
<field name="arch" type="xml">
<field name="carrier_id" position="attributes">
<!-- Sometimes we have to modify carrier_id when state is done
so remove readonly when state = done from view and add tracking on_change in
field definition -->
<attribute name="attrs">{}</attribute>
</field>
<field name="carrier_tracking_ref" position="attributes">
<attribute name="attrs">{}</attribute>
</field>
</field>
</record>
</odoo>

View File

@@ -1 +0,0 @@
from .hooks import web_m2x_options_create

View File

@@ -1,25 +0,0 @@
# Copyright 2014-2019 Akretion France (http://www.akretion.com)
# @author Alexis de Lattre <alexis.delattre@akretion.com>
{
'name': 'Eradicate Quick Create',
'version': '12.0.2.0.0',
'category': 'Tools',
'license': 'AGPL-3',
'summary': 'Disable quick create on all objects',
'description': """
Eradicate Quick Create
======================
Disable quick create on all objects of Odoo.
This new version of the module uses the module *web_m2x_options* from the OCA *web* project instead of the module *base_optional_quick_create* from the OCA project *server-ux*.
This module has been written by Alexis de Lattre from Akretion <alexis.delattre@akretion.com>.
""",
'author': 'Akretion',
'website': 'http://www.akretion.com',
'depends': ['web_m2x_options'],
'post_init_hook': 'web_m2x_options_create',
'installable': True,
}

View File

@@ -1,19 +0,0 @@
# Copyright 2019 Akretion France
# @author: Alexis de Lattre <alexis.delattre@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import SUPERUSER_ID
from odoo.api import Environment
def web_m2x_options_create(cr, registry):
env = Environment(cr, SUPERUSER_ID, {})
config_parameter = env['ir.config_parameter'].search(
[('key', '=', 'web_m2x_options.create')])
if config_parameter and config_parameter.value != 'False':
config_parameter.value = 'False'
else:
env['ir.config_parameter'].create({
'key': 'web_m2x_options.create',
'value': 'False',
})

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

View File

@@ -20,7 +20,8 @@ This module has been written by Alexis de Lattre from Akretion <alexis.delattre@
""",
'author': 'Akretion',
'website': 'http://www.akretion.com',
'depends': ['intrastat_product', 'l10n_fr_intrastat_service'],
# 'depends': ['intrastat_product', 'l10n_fr_intrastat_service'],
'depends': ['intrastat_product'],
'data': ['product_view.xml'],
'post_init_hook': 'set_intrastat_type_on_products',
'installable': True,

View File

@@ -60,14 +60,14 @@ class ProductTemplate(models.Model):
return super(ProductTemplate, self).create(vals)
class L10nFrIntrastatServiceDeclaration(models.Model):
_inherit = "l10n.fr.intrastat.service.declaration"
#class L10nFrIntrastatServiceDeclaration(models.Model):
# _inherit = "l10n.fr.intrastat.service.declaration"
def _is_service(self, invoice_line):
if invoice_line.product_id.intrastat_type == 'service':
return True
else:
return False
# def _is_service(self, invoice_line):
# if invoice_line.product_id.intrastat_type == 'service':
# return True
# else:
# return False
class IntrastatProductDeclaration(models.Model):

View File

@@ -1,3 +1 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from . import models
from . import mrp

View File

@@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2016-2019 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).
@@ -24,10 +25,10 @@ This module has been written by Alexis de Lattre from Akretion <alexis.delattre@
'website': 'http://www.akretion.com',
'depends': ['mrp'],
'data': [
'security/mrp_average_cost_security.xml',
'mrp_view.xml',
'mrp_data.xml',
'security/labour_cost_profile_security.xml',
'security/ir.model.access.csv',
'data/mrp_data.xml',
'views/mrp_view.xml',
],
'installable': True,
}

View File

@@ -1,3 +0,0 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from . import mrp

View File

@@ -1,260 +0,0 @@
# Copyright (C) 2016-2019 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 models, fields, api, _
import odoo.addons.decimal_precision as dp
from odoo.exceptions import UserError
from odoo.tools import float_compare, float_is_zero
import logging
logger = logging.getLogger(__name__)
class MrpBomLabourLine(models.Model):
_name = 'mrp.bom.labour.line'
_description = 'Labour lines on BOM'
bom_id = fields.Many2one(
comodel_name='mrp.bom',
string='Labour Lines',
ondelete='cascade')
labour_time = fields.Float(
string='Labour Time',
required=True,
digits=dp.get_precision('Labour Hours'),
help="Average labour time for the production of "
"items of the BOM, in hours.")
labour_cost_profile_id = fields.Many2one(
comodel_name='labour.cost.profile',
string='Labour Cost Profile',
required=True)
note = fields.Text(
string='Note')
_sql_constraints = [(
'labour_time_positive',
'CHECK (labour_time >= 0)',
"The value of the field 'Labour Time' must be positive or 0.")]
class MrpBom(models.Model):
_inherit = 'mrp.bom'
@api.depends(
'labour_line_ids.labour_time',
'labour_line_ids.labour_cost_profile_id.hour_cost')
def _compute_total_labour_cost(self):
for bom in self:
cost = 0.0
for lline in bom.labour_line_ids:
cost += lline.labour_time *\
lline.labour_cost_profile_id.hour_cost
bom.total_labour_cost = cost
@api.depends(
'bom_line_ids.product_id.standard_price',
'total_labour_cost', 'extra_cost')
def _compute_total_cost(self):
for bom in self:
comp_cost = 0.0
for line in bom.bom_line_ids:
comp_price = line.product_id.standard_price
comp_qty_product_uom = line.product_uom_id._compute_quantity(
line.product_qty, line.product_id.uom_id)
comp_cost += comp_price * comp_qty_product_uom
total_cost = comp_cost + bom.extra_cost + bom.total_labour_cost
bom.total_components_cost = comp_cost
bom.total_cost = total_cost
labour_line_ids = fields.One2many(
'mrp.bom.labour.line', 'bom_id', string='Labour Lines')
total_labour_cost = fields.Float(
compute='_compute_total_labour_cost', readonly=True,
digits=dp.get_precision('Product Price'),
string="Total Labour Cost", store=True)
extra_cost = fields.Float(
string='Extra Cost', track_visibility='onchange',
digits=dp.get_precision('Product Price'),
help="Extra cost for the production of the quantity of "
"items of the BOM, in company currency. "
"You can use this field to enter the cost of the consumables "
"that are used to produce the product but are not listed in "
"the BOM")
total_components_cost = fields.Float(
compute='_compute_total_cost', readonly=True,
digits=dp.get_precision('Product Price'),
string='Total Components Cost')
total_cost = fields.Float(
compute='_compute_total_cost', readonly=True,
string='Total Cost',
digits=dp.get_precision('Product Price'),
help="Total Cost = Total Components Cost + "
"Total Labour Cost + Extra Cost")
company_currency_id = fields.Many2one(
related='company_id.currency_id', string='Company Currency')
@api.model
def _phantom_update_product_standard_price(self):
logger.info('Start to auto-update cost price from phantom bom')
boms = self.search([('type', '=', 'phantom')])
boms.with_context(
product_price_history_origin='Automatic update of Phantom BOMs')\
.manual_update_product_standard_price()
logger.info('End of the auto-update cost price from phantom bom')
return True
def manual_update_product_standard_price(self):
if 'product_price_history_origin' not in self._context:
self = self.with_context(
product_price_history_origin='Manual update from BOM')
precision = self.env['decimal.precision'].precision_get(
'Product Price')
for bom in self:
wproduct = bom.product_id
if not wproduct:
wproduct = bom.product_tmpl_id
if float_compare(
wproduct.standard_price, bom.total_cost,
precision_digits=precision):
wproduct.with_context().write(
{'standard_price': bom.total_cost})
logger.info(
'Cost price updated to %s on product %s',
bom.total_cost, wproduct.display_name)
return True
class MrpBomLine(models.Model):
_inherit = 'mrp.bom.line'
standard_price = fields.Float(
related='product_id.standard_price',
readonly=True,
string='Standard Price')
class LabourCostProfile(models.Model):
_name = 'labour.cost.profile'
_inherit = ['mail.thread']
_description = 'Labour Cost Profile'
name = fields.Char(
string='Name',
required=True,
track_visibility='onchange')
hour_cost = fields.Float(
string='Cost per Hour',
required=True,
digits=dp.get_precision('Product Price'),
track_visibility='onchange',
help="Labour cost per hour per person in company currency")
company_id = fields.Many2one(
comodel_name='res.company',
string='Company',
required=True,
default=lambda self: self.env['res.company']._company_default_get())
company_currency_id = fields.Many2one(
related='company_id.currency_id',
readonly=True,
store=True,
string='Company Currency')
@api.depends('name', 'hour_cost', 'company_currency_id.symbol')
def name_get(self):
res = []
for record in self:
res.append((record.id, u'%s (%s %s)' % (
record.name, record.hour_cost,
record.company_currency_id.symbol)))
return res
class MrpProduction(models.Model):
_inherit = 'mrp.production'
unit_cost = fields.Float(
string='Unit Cost', readonly=True,
digits=dp.get_precision('Product Price'),
help="This cost per unit in the unit of measure of the product "
"in company currency takes into account "
"the cost of the raw materials and the labour cost defined on"
"the BOM.")
company_currency_id = fields.Many2one(
related='company_id.currency_id', readonly=True,
string='Company Currency')
def compute_order_unit_cost(self):
self.ensure_one()
mo_total_price = 0.0 # In the UoM of the M0
labor_cost_per_unit = 0.0 # In the UoM of the product
extra_cost_per_unit = 0.0 # In the UoM of the product
# I read the raw materials MO, not on BOM, in order to make
# it work with the "dynamic" BOMs (few raw material are auto-added
# on the fly on MO)
prec = self.env['decimal.precision'].precision_get(
'Product Unit of Measure')
for raw_smove in self.move_raw_ids:
# I don't filter on state, in order to make it work with
# partial productions
# For partial productions, mo.product_qty is not updated
# so we compute with fully qty and we compute with all raw
# materials (consumed or not), so it gives a good price
# per unit at the end
raw_price = raw_smove.product_id.standard_price
raw_material_cost = raw_price * raw_smove.product_qty
logger.info(
'MO %s product %s: raw_material_cost=%s',
self.name, raw_smove.product_id.display_name,
raw_material_cost)
mo_total_price += raw_material_cost
if self.bom_id:
bom = self.bom_id
# if not bom.total_labour_cost:
# raise orm.except_orm(
# _('Error:'),
# _("Total Labor Cost is 0 on bill of material '%s'.")
# % bom.name)
if float_is_zero(bom.product_qty, precision_digits=prec):
raise UserError(_(
"Missing Product Quantity on bill of material '%s'.")
% bom.display_name)
bom_qty_product_uom = bom.product_uom_id._compute_quantity(
bom.product_qty, bom.product_tmpl_id.uom_id)
assert bom_qty_product_uom > 0, 'BoM qty should be positive'
labor_cost_per_unit = bom.total_labour_cost / bom_qty_product_uom
extra_cost_per_unit = bom.extra_cost / bom_qty_product_uom
# mo_standard_price and labor_cost_per_unit are
# in the UoM of the product (not of the MO/BOM)
mo_qty_product_uom = self.product_uom_id._compute_quantity(
self.product_qty, self.product_id.uom_id)
assert mo_qty_product_uom > 0, 'MO qty should be positive'
mo_standard_price = mo_total_price / mo_qty_product_uom
logger.info(
'MO %s: labor_cost_per_unit=%s extra_cost_per_unit=%s',
self.name, labor_cost_per_unit, extra_cost_per_unit)
mo_standard_price += labor_cost_per_unit
mo_standard_price += extra_cost_per_unit
return mo_standard_price
def post_inventory(self):
'''This is the method where _action_done() is called on finished move
So we write on 'price_unit' of the finished move and THEN we call
super() which will call _action_done() which itself calls
product_price_update_before_done()'''
for order in self:
if order.product_id.cost_method == 'average':
unit_cost = order.compute_order_unit_cost()
order.unit_cost = unit_cost
logger.info('MO %s: unit_cost=%s', order.name, unit_cost)
for finished_move in order.move_finished_ids.filtered(
lambda x: x.product_id == order.product_id):
finished_move.price_unit = unit_cost
return super(MrpProduction, self).post_inventory()

288
mrp_average_cost/mrp.py Normal file
View File

@@ -0,0 +1,288 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2016-2019 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 models, fields, api, _
import odoo.addons.decimal_precision as dp
from odoo.tools import float_compare, float_is_zero
import logging
logger = logging.getLogger(__name__)
class MrpBomLabourLine(models.Model):
_name = 'mrp.bom.labour.line'
_description = 'Labour lines on BOM'
bom_id = fields.Many2one(
'mrp.bom', string='Labour Lines', ondelete='cascade')
labour_time = fields.Float(
string='Labour Time', required=True,
digits=dp.get_precision('Labour Hours'),
help="Average labour time for the production of "
"items of the BOM, in hours.")
labour_cost_profile_id = fields.Many2one(
'labour.cost.profile', string='Labour Cost Profile', required=True)
note = fields.Text(string='Note')
_sql_constraints = [(
'labour_time_positive',
'CHECK (labour_time >= 0)',
"The value of the field 'Labour Time' must be positive or 0.")]
class MrpBom(models.Model):
_inherit = 'mrp.bom'
@api.depends('labour_line_ids.labour_time', 'labour_line_ids.labour_cost_profile_id.hour_cost')
def _compute_total_labour_cost(self):
for bom in self:
cost = 0.0
for lline in bom.labour_line_ids:
cost += lline.labour_time * lline.labour_cost_profile_id.hour_cost
bom.total_labour_cost = cost
@api.depends('bom_line_ids.product_id.standard_price', 'total_labour_cost', 'extra_cost')
def _compute_total_cost(self):
puo = self.pool['product.uom']
for bom in self:
component_cost = 0.0
for line in bom.bom_line_ids:
component_price = line.product_id.standard_price
component_qty_product_uom = puo._compute_qty_obj(
cr, uid, line.product_uom, line.product_qty,
line.product_id.uom_id, context=context) # TODO
component_cost += component_price * component_qty_product_uom
total_cost = component_cost + bom.extra_cost + bom.total_labour_cost
bom.total_components_cost = component_cost
bom.total_cost = total_cost
labour_line_ids = fields.One2many(
'mrp.bom.labour.line', 'bom_id', string='Labour Lines')
total_labour_cost = fields.Float(
compute='_compute_total_labour_cost', readonly=True,
digits=dp.get_precision('Product Price'),
string="Total Labour Cost", store=True)
extra_cost = fields.Float(
string='Extra Cost', track_visibility='onchange',
digits=dp.get_precision('Product Price'),
help="Extra cost for the production of the quantity of "
"items of the BOM, in company currency. "
"You can use this field to enter the cost of the consumables "
"that are used to produce the product but are not listed in "
"the BOM")
total_components_cost = fields.Float(
compute='_compute_total_cost', readonly=True,
digits=dp.get_precision('Product Price'),
string='Total Components Cost')
total_cost = fields.Float(
compute='_compute_total_cost', readonly=True,
string='Total Cost',
digits=dp.get_precision('Product Price'),
help="Total Cost = Total Components Cost + "
"Total Labour Cost + Extra Cost")
company_currency_id = fields.Many2one(
related='company_id.currency_id', readonly=True,
string='Company Currency')
# to display in bom lines
class MrpBomLine(models.Model):
_inherit = 'mrp.bom.line'
standard_price = fields.Float(
related='product_id.standard_price', readonly=True,
string='Standard Price')
def manual_update_product_standard_price(self, cr, uid, ids, context=None):
if context is None:
context = {}
ctx = context.copy()
if 'product_price_history_origin' not in ctx:
ctx['product_price_history_origin'] = u'Manual update from BOM'
precision = self.pool['decimal.precision'].precision_get(
cr, uid, 'Product Price')
for bom in self.browse(cr, uid, ids, context=context):
if not bom.product_id:
continue
if float_compare(
bom.product_id.standard_price, bom.total_cost,
precision_digits=precision):
bom.product_id.write(
{'standard_price': bom.total_cost}, context=ctx)
logger.info(
'Cost price updated to %s on product %s',
bom.total_cost, bom.product_id.name_get()[0][1])
return True
def _phantom_update_product_standard_price(self, cr, uid, context=None):
if context is None:
context = {}
ctx = context.copy()
ctx['product_price_history_origin'] = 'Automatic update of Phantom BOMs'
mbo = self.pool['mrp.bom']
bom_ids = mbo.search(
cr, uid, [('type', '=', 'phantom')], context=context)
self.manual_update_product_standard_price(
cr, uid, bom_ids, context=ctx)
return True
class LabourCostProfile(models.Model):
_name = 'labour.cost.profile'
_inherit = ['mail.thread']
_description = 'Labour Cost Profile'
name = fields.Char(
string='Name', required=True, track_visibility='onchange')
hour_cost = fields.Float(
string='Cost per Hour', required=True,
digits=dp.get_precision('Product Price'),
track_visibility='onchange',
help="Labour cost per hour per person in company currency")
company_id = fields.Many2one(
'res.company', string='Company', required=True,
default=lambda self: self.env['res.company']._company_default_get())
company_currency_id = fields.Many2one(
related='company_id.currency_id', readonly=True, store=True,
string='Company Currency')
@api.depends('name', 'hour_cost', 'company_currency_id.symbol')
def name_get(self):
res = []
for record in self:
res.append((record.id, u'%s (%s %s)' % (
record.name, record.hour_cost,
record.company_currency_id.symbol)))
return res
class MrpProduction(models.Model):
_inherit = 'mrp.production'
unit_cost = fields.Float(
string='Unit Cost', readonly=True,
digits=dp.get_precision('Product Price'),
help="This cost per unit in the unit of measure of the product "
"in company currency takes into account "
"the cost of the raw materials and the labour cost defined on"
"the BOM.")
company_currency_id = fields.Many2one(
related='company_id.currency_id', readonly=True,
string='Company Currency')
# TODO port to v12
def compute_order_unit_cost(self, cr, uid, order, context=None):
puo = self.pool['product.uom']
mo_total_price = 0.0 # In the UoM of the M0
labor_cost_per_unit = 0.0 # In the UoM of the product
extra_cost_per_unit = 0.0 # In the UoM of the product
# I read the raw materials MO, not on BOM, in order to make
# it work with the "dynamic" BOMs (few raw material are auto-added
# on the fly on MO)
for raw_smove in order.move_lines + order.move_lines2:
# I don't filter on state, in order to make it work with
# partial productions
# For partial productions, mo.product_qty is not updated
# so we compute with fully qty and we compute with all raw
# materials (consumed or not), so it gives a good price
# per unit at the end
raw_price = raw_smove.product_id.standard_price
raw_qty_product_uom = puo._compute_qty_obj(
cr, uid, raw_smove.product_uom, raw_smove.product_qty,
raw_smove.product_id.uom_id, context=context)
raw_material_cost = raw_price * raw_qty_product_uom
logger.info(
'MO %s product %s: raw_material_cost=%s',
order.name, raw_smove.product_id.name, raw_material_cost)
mo_total_price += raw_material_cost
if order.bom_id:
bom = order.bom_id
#if not bom.total_labour_cost:
# raise orm.except_orm(
# _('Error:'),
# _("Total Labor Cost is 0 on bill of material '%s'.")
# % bom.name)
if not bom.product_qty:
raise orm.except_orm(
_('Error:'),
_("Missing Product Quantity on bill of material '%s'.")
% bom.name)
bom_qty_product_uom = puo._compute_qty_obj(
cr, uid, bom.product_uom, bom.product_qty,
bom.product_id.uom_id, context=context)
assert bom_qty_product_uom > 0, 'BoM qty should be positive'
labor_cost_per_unit = bom.total_labour_cost / bom_qty_product_uom
extra_cost_per_unit = bom.extra_cost / bom_qty_product_uom
# mo_standard_price and labor_cost_per_unit are
# in the UoM of the product (not of the MO/BOM)
mo_qty_product_uom = puo._compute_qty_obj(
cr, uid, order.product_uom, order.product_qty,
order.product_id.uom_id, context=context)
assert mo_qty_product_uom > 0, 'MO qty should be positive'
mo_standard_price = mo_total_price / mo_qty_product_uom
logger.info(
'MO %s: labor_cost_per_unit=%s', order.name, labor_cost_per_unit)
logger.info(
'MO %s: extra_cost_per_unit=%s', order.name, extra_cost_per_unit)
mo_standard_price += labor_cost_per_unit
mo_standard_price += extra_cost_per_unit
order.write({'unit_cost': mo_standard_price}, context=context)
logger.info(
'MO %s: unit_cost=%s', order.name, mo_standard_price)
return mo_standard_price
def update_standard_price(self, cr, uid, order, context=None):
if context is None:
context = {}
puo = self.pool['product.uom']
product = order.product_id
mo_standard_price = self.compute_order_unit_cost(
cr, uid, order, context=context)
mo_qty_product_uom = puo._compute_qty_obj(
cr, uid, order.product_uom, order.product_qty,
order.product_id.uom_id, context=context)
# I can't use the native method _update_average_price of stock.move
# because it only works on move.picking_id.type == 'in'
# As we do the super() at the END of this method,
# the qty produced by this MO in NOT counted inside
# product.qty_available
qty_before_mo = product.qty_available
logger.info(
'MO %s product %s: standard_price before production: %s',
order.name, product.name, product.standard_price)
logger.info(
'MO %s product %s: qty before production: %s',
order.name, product.name, qty_before_mo)
# Here, we handle as if we were in v8 (!)
# so we consider that standard_price is in company currency
# It will not work if you are in multi-company environment
# with companies in different currencies
if not qty_before_mo + mo_qty_product_uom:
new_std_price = mo_standard_price
else:
new_std_price = (
(product.standard_price * qty_before_mo) +
(mo_standard_price * mo_qty_product_uom)) / \
(qty_before_mo + mo_qty_product_uom)
ctx_product = context.copy()
ctx_product['product_price_history_origin'] = _(
'%s (Qty before: %s - Added qty: %s - Unit price of '
'added qty: %s)') % (
order.name, qty_before_mo, mo_qty_product_uom, mo_standard_price)
product.write({'standard_price': new_std_price}, context=ctx_product)
logger.info(
'MO %s product %s: standard_price updated to %s',
order.name, product.name, new_std_price)
return True
def action_produce(
self, cr, uid, production_id, production_qty, production_mode,
context=None):
if production_mode == 'consume_produce':
order = self.browse(cr, uid, production_id, context=context)
if order.product_id.cost_method == 'average':
self.update_standard_price(cr, uid, order, context=context)
return super(MrpProduction, self).action_produce(
cr, uid, production_id, production_qty, production_mode,
context=context)

View File

@@ -16,7 +16,6 @@
<field name="numbercall">-1</field> <!-- don't limit the number of calls -->
<field name="doall" eval="False"/>
<field name="model_id" ref="mrp.model_mrp_bom"/>
<field name="state">code</field>
<field name="code">model._phantom_update_product_standard_price()</field>
</record>

View File

@@ -37,7 +37,7 @@
</group>
</page>
</notebook>
<xpath expr="//field[@name='bom_line_ids']/tree/field[@name='operation_id']" position="after">
<xpath expr="//field[@name='bom_line_ids']/tree/field[@name='product_uom_id']" position="after">
<field name="standard_price"/>
</xpath>
</field>

View File

@@ -1,5 +1,4 @@
# Copyright 2016-2019 Akretion France (http://www.akretion.com/)
# @author: Alexis de Lattre <alexis.delattre@akretion.com>
# © 2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{

View File

@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2016-2019 Akretion France (http://www.akretion.com/)
@author: Alexis de Lattre <alexis.delattre@akretion.com>
© 2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->

View File

@@ -1,22 +0,0 @@
# © 2019 Akretion (http://www.akretion.com)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{
'name': 'MRP Product Tree Default',
'version': '12.0.1.0.0',
'category': 'Product',
'license': 'AGPL-3',
'summary': 'Tree view by default instead of kanban for Products',
'description': """
Replace default kanban view by tree view for product menu in MRP
main menu
""",
'author': 'Akretion',
'website': 'http://www.akretion.com',
'depends': ['mrp'],
'data': [
'views/product_template.xml'
],
'installable': True,
}

View File

@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="mrp.product_template_action" model="ir.actions.act_window">
<field name="view_mode">tree,form,kanban</field>
</record>
</odoo>

View File

@@ -17,7 +17,7 @@ MRP Usability
:target: https://github.com/akretion/odoo-usability/tree/12.0/mrp_usability
:alt: akretion/odoo-usability
|badge1| |badge2| |badge3|
|badge1| |badge2| |badge3|
Small usability improvements on MRP:
@@ -31,8 +31,6 @@ Small usability improvements on MRP:
* complete Manufacturing Order report with unvailable products
* improve smart button from products to BoMs (display BoM form if only one instead of displaying a list of one)
**Table of contents**
.. contents::

View File

@@ -1 +1 @@
from . import models
from . import mrp

View File

@@ -13,8 +13,7 @@
'website': 'http://www.akretion.com',
'depends': ['mrp'],
'data': [
'views/mrp_views.xml',
'views/product_views.xml',
'mrp_view.xml',
'report/mrp_report.xml'
],
'installable': True,

View File

@@ -1,32 +1,25 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * mrp_usability
# * mrp_usability
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 12.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-07-16 13:56+0000\n"
"PO-Revision-Date: 2019-07-16 16:01+0200\n"
"POT-Creation-Date: 2019-03-26 08:56+0000\n"
"PO-Revision-Date: 2019-03-26 08:56+0000\n"
"Last-Translator: <>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
"Language: fr\n"
"X-Generator: Poedit 2.0.6\n"
#. module: mrp_usability
#: model_terms:ir.ui.view,arch_db:mrp_usability.mrp_production_form_view
msgid "Are you sure you want to cancel this manufacturing order?"
msgstr "Etes vous sur de vouloir annuler cet ordre de production"
#. module: mrp_usability
#: model_terms:ir.ui.view,arch_db:mrp_usability.report_mrporder
msgid "Lot"
msgstr ""
#. module: mrp_usability
#: model_terms:ir.ui.view,arch_db:mrp_usability.report_mrporder
msgid "Product"
@@ -44,14 +37,11 @@ msgstr "Quantité"
#. module: mrp_usability
#: model_terms:ir.ui.view,arch_db:mrp_usability.report_mrporder
msgid ""
"These products were unavailable (or partially) while edition of this Manufacturing Order.\n"
" Here is complete quantities for these."
msgstr ""
"Les produits ci-dessous étaient indisponibles (complètement ou partiellement) lors de l'édition de l'OF.<br/>\n"
"Voici les quantités totales de ceux-ci."
msgid "These products were unavailable while edition of this Manufacturing Order"
msgstr "Ces produits étaient indisponibles au moment de l'édition de l'Ordre de Production"
#. module: mrp_usability
#: model_terms:ir.ui.view,arch_db:mrp_usability.view_mrp_bom_filter
msgid "Type"
msgstr ""
msgstr "Type"

View File

@@ -1,2 +0,0 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from . import mrp, product

View File

@@ -1,44 +0,0 @@
# Copyright (C) 2020 - Akretion
# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html
from odoo import models
class ProductTemplate(models.Model):
_inherit = "product.template"
def action_view_bom(self):
"""Replace native action `template_open_bom` to distinguish if we will display
only one BoM form or a list of BoMs."""
self.ensure_one()
act_window_xml_id = "mrp.mrp_bom_form_action"
act_window = self.env.ref(act_window_xml_id).read()[0]
if self.bom_count > 1:
act_window["context"] = {
"default_product_tmpl_id": self.id,
"search_default_product_tmpl_id": self.id,
}
else:
act_window["context"] = {"default_product_tmpl_id": self.id}
act_window["views"] = [(self.env.ref("mrp.mrp_bom_form_view").id, "form")]
act_window["res_id"] = (
self.env["mrp.bom"].search([("product_tmpl_id", "=", self.id)]).id
)
return act_window
class ProductProduct(models.Model):
_inherit = "product.product"
def action_view_bom(self):
res = super().action_view_bom()
bom_target_ids = self.env["mrp.bom"].search(res["domain"])
if len(bom_target_ids) == 1:
res["views"] = [(self.env.ref("mrp.mrp_bom_form_view").id, "form")]
res["res_id"] = bom_target_ids[0].id
return res

View File

@@ -9,5 +9,3 @@ Small usability improvements on MRP:
* show bom type in tree view + add group by
* complete Manufacturing Order report with unvailable products
* improve smart button from products to BoMs (display BoM form if only one instead of displaying a list of one)

View File

@@ -11,12 +11,11 @@
<td t-if="has_serial_number"><span t-field="ml.lot_id"/></td>
</xpath>
<xpath expr="//div[hasclass('oe_structure')][2]" position="after">
<xpath expr="//div[@class='oe_structure'][2]" position="after">
<t t-set="has_product_unavailable"
t-value="any(o.move_raw_ids.filtered(lambda x: x.product_uom_qty &gt; x.reserved_availability))"/>
t-value="any(o.move_raw_ids.filtered(lambda x: not x.reserved_availability))"/>
<h4 if="has_product_unavailable">
These products were unavailable (or partially) while edition of this Manufacturing Order.
Here is complete quantities for these.
These products were unavailable while edition of this Manufacturing Order
</h4>
<table class="table table-sm" t-if="o.move_raw_ids and has_product_unavailable">
<thead>
@@ -27,7 +26,7 @@
</thead>
<tbody>
<t t-set="lines"
t-value="o.move_raw_ids.filtered(lambda x: x.product_uom_qty &gt; x.reserved_availability)"/>
t-value="o.move_raw_ids.filtered(lambda x: not x.reserved_availability)"/>
<t t-foreach="lines" t-as="ml">
<tr>
<td>

View File

@@ -1,25 +0,0 @@
<?xml version="1.0"?>
<odoo>
<record id="product_template_form_view_bom_button" model="ir.ui.view">
<field name="name">product.template.procurement</field>
<field name="model">product.template</field>
<field name="inherit_id" ref="mrp.product_template_form_view_bom_button" />
<field name="arch" type="xml">
<xpath expr="//field[@name='bom_count']/.." position="attributes">
<attribute name="invisible">1</attribute>
</xpath>
<xpath expr="//field[@name='bom_count']/.." position="after">
<button class="oe_stat_button" name="action_view_bom" type="object"
attrs="{'invisible':[('type', 'not in', ['product', 'consu'])]}"
icon="fa-flask">
<field string="Bill of Materials" name="bom_count"
widget="statinfo" />
</button>
</xpath>
</field>
</record>
</odoo>

View File

@@ -1,29 +0,0 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{
"name": "POS Usability",
"version": "12.0.1.0.0",
"category": "Point of sale",
"license": "AGPL-3",
"summary": "Misc usability improvement for point of sale",
"description": """
POS Usability
=============
- Sales Details report : add sub total amount by tax
authors
-------
Akretion:
* David Béal <david.beal@akretion.com>
""",
"author": "Akretion",
"website": "http://www.akretion.com",
"depends": ["point_of_sale"],
"data": ["report/pos.xml"],
"installable": True,
}

View File

@@ -1,23 +0,0 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * pos_usability
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 12.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-10-11 13:11+0000\n"
"PO-Revision-Date: 2019-10-11 15:11+0200\n"
"Last-Translator: <>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: \n"
"Language: fr\n"
"X-Generator: Poedit 2.0.6\n"
#. module: pos_usability
#: model_terms:ir.ui.view,arch_db:pos_usability.report_saledetails
msgid "Amount"
msgstr "Montant"

View File

@@ -1,17 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template id="report_saledetails" inherit_id="point_of_sale.report_saledetails">
<xpath expr="//table[3]/thead/tr/th[3]" position="after">
<th>Amount</th>
</xpath>
<xpath expr="//table[3]/tbody/tr" position="inside">
<td><t t-esc="tax['tax_amount'] + tax['base_amount']"
t-options="{'widget': 'float', 'precision': currency_precision}" /></td>
</xpath>
</template>
</odoo>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.5 KiB

View File

@@ -1,23 +0,0 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# Product No Translation module for Odoo
# Copyright (C) 2014 Akretion (http://www.akretion.com)
# @author Alexis de Lattre <alexis.delattre@akretion.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from . import product

View File

@@ -1,40 +0,0 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# Product No Translation module for Odoo
# Copyright (C) 2014 Akretion (http://www.akretion.com)
# @author Alexis de Lattre <alexis.delattre@akretion.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
{
'name': 'Product no Translation',
'version': '12.0.0.0.1',
'category': 'Sales Management',
'license': 'AGPL-3',
'summary': 'For companies that work with only one language',
'description': """
This module sets the translatable fields of the product object (name,
descriptions) to non-translatable fields.
This change is usefull for companies that work with only one language.
And it reduces the start time of the Point of Sale !
""",
'author': 'Akretion',
'website': 'http://www.akretion.com',
'depends': ['product'],
}

View File

@@ -1,62 +0,0 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# Product No Translation module for Odoo
# Copyright (C) 2014 Akretion (http://www.akretion.com)
# @author Alexis de Lattre <alexis.delattre@akretion.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from odoo import models, fields
class ProductTemplate(models.Model):
_inherit = "product.template"
description_sale = fields.Text(translate=False)
description_purchase = fields.Text(translate=False)
description = fields.Text(translate=False)
name = fields.Char(translate=False)
class ProductCategory(models.Model):
_inherit = "product.category"
name = fields.Char(translate=False)
class ProductAttribute(models.Model):
_inherit = "product.attribute"
name = fields.Char(translate=False)
class ProductAttributeValue(models.Model):
_inherit = "product.attribute.value"
name = fields.Char(translate=False)
class UomCategory(models.Model):
_inherit = 'uom.category'
name = fields.Char(translate=False)
class UomUom(models.Model):
_inherit = 'uom.uom'
name = fields.Char(translate=False)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.0 KiB

View File

@@ -1,3 +1,3 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from . import models
from . import product
from . import pricelist

View File

@@ -28,11 +28,7 @@ This module has been written by Alexis de Lattre from Akretion <alexis.delattre@
'depends': ['product'],
'data': [
'security/product_security.xml',
'views/product_supplierinfo_view.xml',
'views/product_price_history_view.xml',
'views/product_pricelist_view.xml',
'views/product_template_view.xml',
'views/product_view.xml',
],
'product_view.xml',
],
'installable': True,
}

Some files were not shown because too many files have changed in this diff Show More