Compare commits
157 Commits
12-pricel-
...
12.0-MIG-p
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
59cdcbd173 | ||
|
|
7cf224cf23 | ||
|
|
d0d65ebbca | ||
|
|
ca10381be8 | ||
|
|
44b19dfe60 | ||
|
|
c082baa340 | ||
|
|
15ee1b2f59 | ||
|
|
b080dd11ab | ||
|
|
568e6b41ac | ||
|
|
0dee23aeba | ||
|
|
c7d1e13d0d | ||
|
|
e7fae291ee | ||
|
|
bdfe0ce20a | ||
|
|
32eafedf04 | ||
|
|
ba78791ab1 | ||
|
|
946d169665 | ||
|
|
cd51a6784f | ||
|
|
c01942b1a8 | ||
|
|
e11b29deab | ||
|
|
28be3e4e6a | ||
|
|
5c7985a15c | ||
|
|
9b6c34a860 | ||
|
|
f735f8a34d | ||
|
|
74665bb2e8 | ||
|
|
d1deeeac31 | ||
|
|
e96c3d72eb | ||
|
|
a545c8dbb6 | ||
|
|
07824a0570 | ||
|
|
12bd157ad4 | ||
|
|
53f6ab5d0f | ||
|
|
cc88dd994b | ||
|
|
b99659dcc9 | ||
|
|
581bfe78d8 | ||
|
|
9a174c257d | ||
|
|
941c610c96 | ||
|
|
34a4c573b1 | ||
|
|
f64d190ac3 | ||
|
|
c633660e73 | ||
|
|
0dfe8df8e4 | ||
|
|
0e4a562263 | ||
|
|
253a5ebebe | ||
|
|
73c622956f | ||
|
|
38db0da20a | ||
|
|
361f5d3aae | ||
|
|
499d363daf | ||
|
|
035a3dfd1e | ||
|
|
83fec9264f | ||
|
|
9762b5392b | ||
|
|
fc4ea217e0 | ||
|
|
1812c7f5af | ||
|
|
92a4b0d6ac | ||
|
|
33f67279fb | ||
|
|
66c845f3cf | ||
|
|
8a9c75790a | ||
|
|
0de8425cfa | ||
|
|
f8563c1667 | ||
|
|
60cda426a9 | ||
|
|
fe7f2c00c5 | ||
|
|
76b113ed28 | ||
|
|
5140094633 | ||
|
|
e220da006f | ||
|
|
c5ffe375a5 | ||
|
|
dd8487bf0f | ||
|
|
a62d1e01f4 | ||
|
|
e397f3908e | ||
|
|
7b51c993ec | ||
|
|
f480332d3a | ||
|
|
2f875867c5 | ||
|
|
e9049570ee | ||
|
|
52eff801b6 | ||
|
|
d84ef2e8c5 | ||
|
|
9298378e62 | ||
|
|
a7f5e10be4 | ||
|
|
ea5f679a59 | ||
|
|
d63706f764 | ||
|
|
d9b8da5799 | ||
|
|
4896075c7d | ||
|
|
78b0e416fa | ||
|
|
beb0a27ad6 | ||
|
|
5b620a6c5f | ||
|
|
8c1089e138 | ||
|
|
765be077cd | ||
|
|
4f6dc99319 | ||
|
|
59b0a5ac10 | ||
|
|
2d755be1d7 | ||
|
|
61768a34e9 | ||
|
|
140f2d54ee | ||
|
|
e4d4bcd7ca | ||
|
|
e193df7def | ||
|
|
cadbd840d9 | ||
|
|
3052d7c905 | ||
|
|
f59f2ad8ec | ||
|
|
fa22c63176 | ||
|
|
4437afb7d5 | ||
|
|
b762af222d | ||
|
|
f258bf6fdb | ||
|
|
43c60dcb30 | ||
|
|
f4f99647d2 | ||
|
|
a75e14dc8d | ||
|
|
dbd600bcd9 | ||
|
|
4b442bd11b | ||
|
|
d2978475b8 | ||
|
|
c57d2a0564 | ||
|
|
7e0c438ae8 | ||
|
|
7d7a42ba8e | ||
|
|
a21ec776c1 | ||
|
|
62d0af15ac | ||
|
|
24c4dd0225 | ||
|
|
16c2833252 | ||
|
|
f9552e7271 | ||
|
|
19ad0eff78 | ||
|
|
9f28bc6703 | ||
|
|
11ae6e1297 | ||
|
|
b2bf902a78 | ||
|
|
790c55e607 | ||
|
|
694a0d4d29 | ||
|
|
c2ed859534 | ||
|
|
a4765c6cb2 | ||
|
|
9cb99db2b3 | ||
|
|
8b0e59b22f | ||
|
|
dccfead879 | ||
|
|
9cae5e00b6 | ||
|
|
620b459415 | ||
|
|
2062a1f307 | ||
|
|
79172fcc45 | ||
|
|
d937d954ab | ||
|
|
3bb11966dd | ||
|
|
0bd3b0412c | ||
|
|
5a72d2b1b9 | ||
|
|
682f85b2d7 | ||
|
|
087e4d6333 | ||
|
|
d5bf1f1a24 | ||
|
|
317d4fdd42 | ||
|
|
9657f1bcfd | ||
|
|
dc95c30f60 | ||
|
|
2fb715905a | ||
|
|
60a5fa7a33 | ||
|
|
06e0617026 | ||
|
|
fa3e483026 | ||
|
|
1957018a14 | ||
|
|
cfebb6c99c | ||
|
|
cd745c74a9 | ||
|
|
e1f9f2ea92 | ||
|
|
ce08af35bf | ||
|
|
475993422e | ||
|
|
ce4fac8a10 | ||
|
|
a848181bee | ||
|
|
13b9109fc0 | ||
|
|
ec0e3c1868 | ||
|
|
b42474a3c2 | ||
|
|
e5323fb968 | ||
|
|
d806fa48f4 | ||
|
|
c38d533557 | ||
|
|
4c145c12af | ||
|
|
0a2f129ed8 | ||
|
|
4d75ef9fb5 | ||
|
|
bebc328a7b |
2
account_invoice_margin/__init__.py
Normal file
2
account_invoice_margin/__init__.py
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
from . import account_invoice
|
||||||
|
from . import account_invoice_report
|
||||||
24
account_invoice_margin/__manifest__.py
Normal file
24
account_invoice_margin/__manifest__.py
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
# 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,
|
||||||
|
}
|
||||||
152
account_invoice_margin/account_invoice.py
Normal file
152
account_invoice_margin/account_invoice.py
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
# 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']
|
||||||
60
account_invoice_margin/account_invoice_report.py
Normal file
60
account_invoice_margin/account_invoice_report.py
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
# 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
|
||||||
51
account_invoice_margin/account_invoice_view.xml
Normal file
51
account_invoice_margin/account_invoice_view.xml
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
<?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>
|
||||||
39
account_invoice_update_wizard/README.rst
Normal file
39
account_invoice_update_wizard/README.rst
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
.. 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>
|
||||||
2
account_invoice_update_wizard/__init__.py
Normal file
2
account_invoice_update_wizard/__init__.py
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
from . import models
|
||||||
|
from . import wizard
|
||||||
21
account_invoice_update_wizard/__manifest__.py
Normal file
21
account_invoice_update_wizard/__manifest__.py
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
# 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,
|
||||||
|
}
|
||||||
1
account_invoice_update_wizard/models/__init__.py
Normal file
1
account_invoice_update_wizard/models/__init__.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
from . import account_invoice
|
||||||
22
account_invoice_update_wizard/models/account_invoice.py
Normal file
22
account_invoice_update_wizard/models/account_invoice.py
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
# 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
|
||||||
|
|
||||||
1
account_invoice_update_wizard/tests/__init__.py
Normal file
1
account_invoice_update_wizard/tests/__init__.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
from . import test_account_invoice_update_wizard
|
||||||
@@ -0,0 +1,196 @@
|
|||||||
|
# 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)
|
||||||
29
account_invoice_update_wizard/views/account_invoice.xml
Normal file
29
account_invoice_update_wizard/views/account_invoice.xml
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
<?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>
|
||||||
1
account_invoice_update_wizard/wizard/__init__.py
Normal file
1
account_invoice_update_wizard/wizard/__init__.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
from . import account_invoice_update
|
||||||
302
account_invoice_update_wizard/wizard/account_invoice_update.py
Normal file
302
account_invoice_update_wizard/wizard/account_invoice_update.py
Normal file
@@ -0,0 +1,302 @@
|
|||||||
|
# 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')
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
<?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>
|
||||||
96
account_usability/README.rst
Normal file
96
account_usability/README.rst
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
=================
|
||||||
|
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.
|
||||||
@@ -4,28 +4,10 @@
|
|||||||
|
|
||||||
{
|
{
|
||||||
'name': 'Account Usability',
|
'name': 'Account Usability',
|
||||||
'version': '10.0.1.0.0',
|
'version': '12.0.1.0.0',
|
||||||
'category': 'Accounting & Finance',
|
'category': 'Accounting & Finance',
|
||||||
'license': 'AGPL-3',
|
'license': 'AGPL-3',
|
||||||
'summary': 'Small usability enhancements in account module',
|
'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',
|
'author': 'Akretion',
|
||||||
'website': 'http://www.akretion.com',
|
'website': 'http://www.akretion.com',
|
||||||
'depends': [
|
'depends': [
|
||||||
@@ -40,6 +22,7 @@ This module has been written by Alexis de Lattre from Akretion <alexis.delattre@
|
|||||||
'account_invoice_report_view.xml',
|
'account_invoice_report_view.xml',
|
||||||
'partner_view.xml',
|
'partner_view.xml',
|
||||||
'wizard/account_invoice_mark_sent_view.xml',
|
'wizard/account_invoice_mark_sent_view.xml',
|
||||||
|
'report/invoice_report.xml',
|
||||||
],
|
],
|
||||||
'installable': True,
|
'installable': True,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ from odoo import models, fields, api, _
|
|||||||
from odoo.tools import float_compare, float_is_zero
|
from odoo.tools import float_compare, float_is_zero
|
||||||
from odoo.tools.misc import formatLang
|
from odoo.tools.misc import formatLang
|
||||||
from odoo.exceptions import UserError, ValidationError
|
from odoo.exceptions import UserError, ValidationError
|
||||||
|
from odoo.osv import expression
|
||||||
from odoo import SUPERUSER_ID
|
from odoo import SUPERUSER_ID
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
@@ -37,6 +38,10 @@ class AccountInvoice(models.Model):
|
|||||||
has_attachment = fields.Boolean(
|
has_attachment = fields.Boolean(
|
||||||
compute='_compute_has_attachment',
|
compute='_compute_has_attachment',
|
||||||
search='_search_has_attachment', readonly=True)
|
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):
|
def _compute_has_discount(self):
|
||||||
prec = self.env['decimal.precision'].precision_get('Discount')
|
prec = self.env['decimal.precision'].precision_get('Discount')
|
||||||
@@ -78,7 +83,7 @@ class AccountInvoice(models.Model):
|
|||||||
# top of the screen
|
# top of the screen
|
||||||
# That's why we have to cut the name_get() when it's too long
|
# That's why we have to cut the name_get() when it's too long
|
||||||
def name_get(self):
|
def name_get(self):
|
||||||
old_res = super(AccountInvoice, self).name_get()
|
old_res = super().name_get()
|
||||||
res = []
|
res = []
|
||||||
for old_re in old_res:
|
for old_re in old_res:
|
||||||
name = old_re[1]
|
name = old_re[1]
|
||||||
@@ -98,9 +103,8 @@ class AccountInvoice(models.Model):
|
|||||||
# 2) the 'name' field of the account.move.line is used in the overdue
|
# 2) the 'name' field of the account.move.line is used in the overdue
|
||||||
# letter, and '/' is not meaningful for our customer !
|
# letter, and '/' is not meaningful for our customer !
|
||||||
# TODO mig to v12
|
# TODO mig to v12
|
||||||
# @api.multi
|
|
||||||
# def action_move_create(self):
|
# def action_move_create(self):
|
||||||
# res = super(AccountInvoice, self).action_move_create()
|
# res = super().action_move_create()
|
||||||
# for inv in self:
|
# for inv in self:
|
||||||
# self._cr.execute(
|
# self._cr.execute(
|
||||||
# "UPDATE account_move_line SET name= "
|
# "UPDATE account_move_line SET name= "
|
||||||
@@ -170,6 +174,24 @@ class AccountInvoice(models.Model):
|
|||||||
# ]
|
# ]
|
||||||
return res
|
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):
|
class AccountInvoiceLine(models.Model):
|
||||||
_inherit = 'account.invoice.line'
|
_inherit = 'account.invoice.line'
|
||||||
@@ -193,7 +215,15 @@ class AccountInvoiceLine(models.Model):
|
|||||||
class AccountJournal(models.Model):
|
class AccountJournal(models.Model):
|
||||||
_inherit = 'account.journal'
|
_inherit = 'account.journal'
|
||||||
|
|
||||||
@api.multi
|
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.depends(
|
@api.depends(
|
||||||
'name', 'currency_id', 'company_id', 'company_id.currency_id', 'code')
|
'name', 'currency_id', 'company_id', 'company_id.currency_id', 'code')
|
||||||
def name_get(self):
|
def name_get(self):
|
||||||
@@ -239,7 +269,6 @@ class AccountJournal(models.Model):
|
|||||||
class AccountAccount(models.Model):
|
class AccountAccount(models.Model):
|
||||||
_inherit = 'account.account'
|
_inherit = 'account.account'
|
||||||
|
|
||||||
@api.multi
|
|
||||||
@api.depends('name', 'code')
|
@api.depends('name', 'code')
|
||||||
def name_get(self):
|
def name_get(self):
|
||||||
if self._context.get('account_account_show_code_only'):
|
if self._context.get('account_account_show_code_only'):
|
||||||
@@ -248,7 +277,7 @@ class AccountAccount(models.Model):
|
|||||||
res.append((record.id, record.code))
|
res.append((record.id, record.code))
|
||||||
return res
|
return res
|
||||||
else:
|
else:
|
||||||
return super(AccountAccount, self).name_get()
|
return super().name_get()
|
||||||
|
|
||||||
# https://github.com/odoo/odoo/issues/23040
|
# https://github.com/odoo/odoo/issues/23040
|
||||||
# TODO mig to v12
|
# TODO mig to v12
|
||||||
@@ -331,7 +360,6 @@ class AccountAccount(models.Model):
|
|||||||
class AccountAnalyticAccount(models.Model):
|
class AccountAnalyticAccount(models.Model):
|
||||||
_inherit = 'account.analytic.account'
|
_inherit = 'account.analytic.account'
|
||||||
|
|
||||||
@api.multi
|
|
||||||
def name_get(self):
|
def name_get(self):
|
||||||
if self._context.get('analytic_account_show_code_only'):
|
if self._context.get('analytic_account_show_code_only'):
|
||||||
res = []
|
res = []
|
||||||
@@ -339,7 +367,7 @@ class AccountAnalyticAccount(models.Model):
|
|||||||
res.append((record.id, record.code or record.name))
|
res.append((record.id, record.code or record.name))
|
||||||
return res
|
return res
|
||||||
else:
|
else:
|
||||||
return super(AccountAnalyticAccount, self).name_get()
|
return super().name_get()
|
||||||
|
|
||||||
_sql_constraints = [(
|
_sql_constraints = [(
|
||||||
'code_company_unique',
|
'code_company_unique',
|
||||||
@@ -486,8 +514,9 @@ class AccountBankStatement(models.Model):
|
|||||||
end_date = fields.Date(
|
end_date = fields.Date(
|
||||||
compute='_compute_dates', string='End Date', readonly=True,
|
compute='_compute_dates', string='End Date', readonly=True,
|
||||||
store=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')
|
@api.depends('line_ids.date')
|
||||||
def _compute_dates(self):
|
def _compute_dates(self):
|
||||||
for st in self:
|
for st in self:
|
||||||
@@ -495,7 +524,14 @@ class AccountBankStatement(models.Model):
|
|||||||
st.start_date = dates and min(dates) or False
|
st.start_date = dates and min(dates) or False
|
||||||
st.end_date = dates and max(dates) or False
|
st.end_date = dates and max(dates) or False
|
||||||
|
|
||||||
@api.multi
|
def _balance_check(self):
|
||||||
|
for stmt in self:
|
||||||
|
if stmt.hide_bank_statement_balance:
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
super(AccountBankStatement, stmt)._balance_check()
|
||||||
|
return True
|
||||||
|
|
||||||
@api.depends('name', 'start_date', 'end_date')
|
@api.depends('name', 'start_date', 'end_date')
|
||||||
def name_get(self):
|
def name_get(self):
|
||||||
res = []
|
res = []
|
||||||
@@ -533,15 +569,14 @@ class AccountBankStatementLine(models.Model):
|
|||||||
# search_reconciliation_proposition=False, context=None):
|
# search_reconciliation_proposition=False, context=None):
|
||||||
# # Make variable name shorted for PEP8 !
|
# # Make variable name shorted for PEP8 !
|
||||||
# search_rec_prop = search_reconciliation_proposition
|
# search_rec_prop = search_reconciliation_proposition
|
||||||
# return super(AccountBankStatementLine, self).\
|
# return super().\
|
||||||
# get_data_for_reconciliations(
|
# get_data_for_reconciliations(
|
||||||
# cr, uid, ids, excluded_ids=excluded_ids,
|
# cr, uid, ids, excluded_ids=excluded_ids,
|
||||||
# search_reconciliation_proposition=search_rec_prop,
|
# search_reconciliation_proposition=search_rec_prop,
|
||||||
# context=context)
|
# context=context)
|
||||||
|
|
||||||
def _prepare_reconciliation_move(self, move_ref):
|
def _prepare_reconciliation_move(self, move_ref):
|
||||||
vals = super(AccountBankStatementLine, self).\
|
vals = super()._prepare_reconciliation_move(move_ref)
|
||||||
_prepare_reconciliation_move(move_ref)
|
|
||||||
# By default, ref contains the name of the statement + name of the
|
# By default, ref contains the name of the statement + name of the
|
||||||
# statement line. It causes 2 problems:
|
# statement line. It causes 2 problems:
|
||||||
# 1) The 'ref' field is too big
|
# 1) The 'ref' field is too big
|
||||||
@@ -559,13 +594,13 @@ class AccountBankStatementLine(models.Model):
|
|||||||
def show_account_move(self):
|
def show_account_move(self):
|
||||||
self.ensure_one()
|
self.ensure_one()
|
||||||
action = self.env['ir.actions.act_window'].for_xml_id(
|
action = self.env['ir.actions.act_window'].for_xml_id(
|
||||||
'account', 'action_move_journal_line')
|
'account', 'action_move_line_form')
|
||||||
if self.journal_entry_ids:
|
if self.journal_entry_ids:
|
||||||
action.update({
|
action.update({
|
||||||
'views': False,
|
'views': False,
|
||||||
'view_id': False,
|
'view_id': False,
|
||||||
'view_mode': 'form,tree',
|
'view_mode': 'form,tree',
|
||||||
'res_id': self.journal_entry_ids[0].id,
|
'res_id': self.journal_entry_ids[0].move_id.id,
|
||||||
})
|
})
|
||||||
return action
|
return action
|
||||||
else:
|
else:
|
||||||
@@ -626,3 +661,46 @@ class AccountReconcileModel(models.Model):
|
|||||||
# Because it's much better to have the bank statement line label as
|
# 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
|
# label of the counter-part move line, then the label of the button
|
||||||
assert True # Stupid line of code just to have something...
|
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)
|
||||||
|
|||||||
@@ -1,53 +1,13 @@
|
|||||||
diff --git a/addons/account/models/account_bank_statement.py b/addons/account/models/account_bank_statement.py
|
diff --git a/addons/account/static/src/js/reconciliation/reconciliation_renderer.js b/addons/account/static/src/js/reconciliation/reconciliation_renderer.js
|
||||||
index 8ed1e48..615da43 100644
|
index 53f28e0c620..1721d01edf9 100644
|
||||||
--- a/addons/account/models/account_bank_statement.py
|
--- a/addons/account/static/src/js/reconciliation/reconciliation_renderer.js
|
||||||
+++ b/addons/account/models/account_bank_statement.py
|
+++ b/addons/account/static/src/js/reconciliation/reconciliation_renderer.js
|
||||||
@@ -563,7 +563,13 @@ class AccountBankStatementLine(models.Model):
|
@@ -514,7 +514,7 @@ var LineRenderer = Widget.extend(FieldManagerMixin, {
|
||||||
"""
|
}
|
||||||
# Blue lines = payment on bank account not assigned to a statement yet
|
return this.model.makeRecord('account.bank.statement.line', [field], {
|
||||||
reconciliation_aml_accounts = [self.journal_id.default_credit_account_id.id, self.journal_id.default_debit_account_id.id]
|
partner_id: {
|
||||||
- domain_reconciliation = ['&', '&', ('statement_id', '=', False), ('account_id', 'in', reconciliation_aml_accounts), ('payment_id','<>', False)]
|
- domain: ["|", ["is_company", "=", true], ["parent_id", "=", false], "|", ["customer", "=", true], ["supplier", "=", true]],
|
||||||
+ # AKRETION HACK 11/7/2017
|
+ domain: ["|", ["is_company", "=", true], ["parent_id", "=", false]],
|
||||||
+ # Remove ('payment_id','<>', False) in order to allow to select move lines
|
options: {
|
||||||
+ # generated from payment orders or check deposit
|
no_open: true
|
||||||
+ # 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,
|
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
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
|
|
||||||
@@ -16,6 +16,9 @@
|
|||||||
<field name="fiscal_position_id" position="attributes">
|
<field name="fiscal_position_id" position="attributes">
|
||||||
<attribute name="widget">selection</attribute>
|
<attribute name="widget">selection</attribute>
|
||||||
</field>
|
</field>
|
||||||
|
<field name="incoterm_id" position="attributes">
|
||||||
|
<attribute name="widget">selection</attribute>
|
||||||
|
</field>
|
||||||
<field name="invoice_line_ids" position="before">
|
<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"/>
|
<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>
|
</field>
|
||||||
@@ -33,6 +36,9 @@
|
|||||||
<field name="fiscal_position_id" position="attributes">
|
<field name="fiscal_position_id" position="attributes">
|
||||||
<attribute name="widget">selection</attribute>
|
<attribute name="widget">selection</attribute>
|
||||||
</field>
|
</field>
|
||||||
|
<field name="incoterm_id" position="attributes">
|
||||||
|
<attribute name="widget">selection</attribute>
|
||||||
|
</field>
|
||||||
<!-- move sent field and make it visible -->
|
<!-- move sent field and make it visible -->
|
||||||
<field name="sent" position="replace"/>
|
<field name="sent" position="replace"/>
|
||||||
<field name="move_id" position="before">
|
<field name="move_id" position="before">
|
||||||
@@ -354,8 +360,9 @@ module -->
|
|||||||
<field name="model">account.move.line</field>
|
<field name="model">account.move.line</field>
|
||||||
<field name="inherit_id" ref="account.view_move_line_tree"/>
|
<field name="inherit_id" ref="account.view_move_line_tree"/>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<!-- Move reconcile_id to a better position -->
|
<field name="full_reconcile_id" position="attributes">
|
||||||
<field name="full_reconcile_id" position="replace"/>
|
<attribute name="invisible">1</attribute>
|
||||||
|
</field>
|
||||||
<field name="credit" position="after">
|
<field name="credit" position="after">
|
||||||
<field name="balance" sum="Total Balance"/>
|
<field name="balance" sum="Total Balance"/>
|
||||||
<field name="reconcile_string"/>
|
<field name="reconcile_string"/>
|
||||||
@@ -402,6 +409,42 @@ module -->
|
|||||||
</field>
|
</field>
|
||||||
</record>
|
</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 && !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">
|
<record id="view_account_journal_search" model="ir.ui.view">
|
||||||
<field name="name">usability.account.journal.search</field>
|
<field name="name">usability.account.journal.search</field>
|
||||||
<field name="model">account.journal</field>
|
<field name="model">account.journal</field>
|
||||||
@@ -423,16 +466,32 @@ module -->
|
|||||||
<xpath expr="//field[@name='line_ids']/tree/field[@name='bank_account_id']" position="after">
|
<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 -->
|
<!-- 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"
|
<button name="show_account_move" type="object"
|
||||||
string="View Account Move" icon="fa fa-arrow-right"
|
string="View Account Move" icon="fa-arrow-right"
|
||||||
attrs="{'invisible': [('journal_entry_ids', '=', [])]}"/>
|
attrs="{'invisible': [('journal_entry_ids', '=', [])]}"/>
|
||||||
</xpath>
|
</xpath>
|
||||||
<field name="date" position="after">
|
<field name="date" position="after">
|
||||||
<field name="start_date"/>
|
<field name="start_date"/>
|
||||||
<field name="end_date"/>
|
<field name="end_date"/>
|
||||||
|
<field name="hide_bank_statement_balance" invisible="1"/>
|
||||||
</field>
|
</field>
|
||||||
<field name="date" position="attributes">
|
<field name="date" position="attributes">
|
||||||
<attribute name="invisible">1</attribute>
|
<attribute name="invisible">1</attribute>
|
||||||
</field>
|
</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>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
@@ -475,6 +534,17 @@ module -->
|
|||||||
</field>
|
</field>
|
||||||
</record>
|
</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 -->
|
<!-- ACCOUNT TAX GROUP -->
|
||||||
<!-- in the account module, there is nothing for account.tax.group : no form/tree view, no menu... -->
|
<!-- 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">
|
<record id="account_tax_group_form" model="ir.ui.view">
|
||||||
@@ -509,6 +579,28 @@ module -->
|
|||||||
|
|
||||||
<menuitem id="account_tax_group_menu" action="account_tax_group_action" parent="account.account_account_menu" sequence="2"/>
|
<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"
|
<!-- Remove menu entry "Accounting > Configuration > Accounting > Bank Accounts"
|
||||||
(account.journal filtered on type = 'bank' with special tree and form view)
|
(account.journal filtered on type = 'bank' with special tree and form view)
|
||||||
because it is useless and confusing -->
|
because it is useless and confusing -->
|
||||||
|
|||||||
@@ -1,33 +1,33 @@
|
|||||||
diff --git a/addons/account/models/account_payment.py b/addons/account/models/account_payment.py
|
diff --git a/addons/account/models/account_payment.py b/addons/account/models/account_payment.py
|
||||||
index b1d8012329d..b8a8e2a673d 100644
|
index f38f459c533..a475d6a82c7 100644
|
||||||
--- a/addons/account/models/account_payment.py
|
--- a/addons/account/models/account_payment.py
|
||||||
+++ b/addons/account/models/account_payment.py
|
+++ b/addons/account/models/account_payment.py
|
||||||
@@ -210,6 +210,7 @@ class account_payment(models.Model):
|
@@ -62,6 +62,7 @@ class account_abstract_payment(models.AbstractModel):
|
||||||
payment_difference = fields.Monetary(compute='_compute_payment_difference', readonly=True)
|
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", copy=False)
|
payment_difference_handling = fields.Selection([('open', 'Keep open'), ('reconcile', 'Mark invoice as fully paid')], default='open', string="Payment Difference Handling", copy=False)
|
||||||
writeoff_account_id = fields.Many2one('account.account', string="Difference Account", domain=[('deprecated', '=', False)], 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_analytic_account_id = fields.Many2one('account.analytic.account', string="Difference Analytic Account", copy=False)
|
||||||
|
writeoff_label = fields.Char(
|
||||||
# FIXME: ondelete='restrict' not working (eg. cancel a bank statement reconciliation with a payment)
|
string='Journal Item Label',
|
||||||
move_line_ids = fields.One2many('account.move.line', 'payment_id', readonly=True, copy=False, ondelete='restrict')
|
help='Change label of the counterpart that will hold the payment difference',
|
||||||
@@ -431,6 +432,7 @@ class account_payment(models.Model):
|
@@ -717,6 +718,7 @@ class account_payment(models.Model):
|
||||||
amount_currency_wo = -abs(amount_currency_wo)
|
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'] = _('Counterpart')
|
writeoff_line['name'] = self.writeoff_label
|
||||||
writeoff_line['account_id'] = self.writeoff_account_id.id
|
writeoff_line['account_id'] = self.writeoff_account_id.id
|
||||||
+ writeoff_line['analytic_account_id'] = self.writeoff_analytic_account_id.id or False
|
+ writeoff_line['analytic_account_id'] = self.writeoff_analytic_account_id.id or False
|
||||||
writeoff_line['debit'] = debit_wo
|
writeoff_line['debit'] = debit_wo
|
||||||
writeoff_line['credit'] = credit_wo
|
writeoff_line['credit'] = credit_wo
|
||||||
writeoff_line['amount_currency'] = amount_currency_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
|
diff --git a/addons/account/views/account_payment_view.xml b/addons/account/views/account_payment_view.xml
|
||||||
index 2460458fbaa..4065d8f9952 100644
|
index 07230902ee8..1359009bf23 100644
|
||||||
--- a/addons/account/views/account_payment_view.xml
|
--- a/addons/account/views/account_payment_view.xml
|
||||||
+++ b/addons/account/views/account_payment_view.xml
|
+++ b/addons/account/views/account_payment_view.xml
|
||||||
@@ -206,6 +206,8 @@
|
@@ -277,6 +277,8 @@
|
||||||
</div>
|
<div attrs="{'invisible': [('payment_difference_handling','=','open')]}">
|
||||||
<field name="writeoff_account_id" string="Post Difference In"
|
<label for="writeoff_account_id" class="oe_edit_only" string="Post Difference In"/>
|
||||||
attrs="{'invisible': [('payment_difference_handling','=','open')], 'required': [('payment_difference_handling', '=', 'reconcile')]}"/>
|
<field name="writeoff_account_id" string="Post Difference In" attrs="{'required': [('payment_difference_handling', '=', 'reconcile')]}"/>
|
||||||
+ <field name="writeoff_analytic_account_id" string="Post Difference In Analytic Account"
|
+ <label for="writeoff_analytic_account_id" class="oe_edit_only" string="Analytic Account" groups="analytic.group_analytic_accounting"/>
|
||||||
+ attrs="{'invisible': [('payment_difference_handling','=','open')]}"/>
|
+ <field name="writeoff_analytic_account_id" groups="analytic.group_analytic_accounting"/>
|
||||||
</group>
|
<label for="journal_id" string="Journal" attrs="{'invisible': [('amount', '!=', 0)]}"/>
|
||||||
</group>
|
<field name="journal_id" string="Journal" widget="selection" attrs="{'invisible': [('amount', '!=', 0)]}"/>
|
||||||
</sheet>
|
<label for="writeoff_label" class="oe_edit_only" string="Label"/>
|
||||||
|
|||||||
2
account_usability/readme/CONTRIBUTORS.rst
Normal file
2
account_usability/readme/CONTRIBUTORS.rst
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
* Alexis de Lattre <alexis.delattre@akretion.com>
|
||||||
|
* David Beal <david.beal@akretion.com>
|
||||||
39
account_usability/readme/DESCRIPTION.rst
Normal file
39
account_usability/readme/DESCRIPTION.rst
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
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)
|
||||||
10
account_usability/report/invoice_report.xml
Normal file
10
account_usability/report/invoice_report.xml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<?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>
|
||||||
454
account_usability/static/description/index.html
Normal file
454
account_usability/static/description/index.html
Normal file
@@ -0,0 +1,454 @@
|
|||||||
|
<?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 don’t 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>don’t 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 <<a class="reference external" href="mailto:alexis.delattre@akretion.com">alexis.delattre@akretion.com</a>></li>
|
||||||
|
<li>David Beal <<a class="reference external" href="mailto:david.beal@akretion.com">david.beal@akretion.com</a>></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>
|
||||||
61
base_company_extension/README.rst
Normal file
61
base_company_extension/README.rst
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
======================
|
||||||
|
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.
|
||||||
@@ -9,16 +9,6 @@
|
|||||||
'category': 'Partner',
|
'category': 'Partner',
|
||||||
'license': 'AGPL-3',
|
'license': 'AGPL-3',
|
||||||
'summary': 'Adds capital and title on company',
|
'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',
|
'author': 'Akretion',
|
||||||
'website': 'http://www.akretion.com',
|
'website': 'http://www.akretion.com',
|
||||||
# I depend on base_usability only for _report_company_legal_name()
|
# I depend on base_usability only for _report_company_legal_name()
|
||||||
|
|||||||
1
base_company_extension/readme/CONTRIBUTORS.rst
Normal file
1
base_company_extension/readme/CONTRIBUTORS.rst
Normal file
@@ -0,0 +1 @@
|
|||||||
|
* Alexis de Lattre <alexis.delattre@akretion.com>
|
||||||
5
base_company_extension/readme/DESCRIPTION.rst
Normal file
5
base_company_extension/readme/DESCRIPTION.rst
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
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
|
||||||
417
base_company_extension/static/description/index.html
Normal file
417
base_company_extension/static/description/index.html
Normal file
@@ -0,0 +1,417 @@
|
|||||||
|
<?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 <<a class="reference external" href="mailto:alexis.delattre@akretion.com">alexis.delattre@akretion.com</a>></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>
|
||||||
@@ -2,13 +2,14 @@
|
|||||||
# @author: Alexis de Lattre <alexis.delattre@akretion.com>
|
# @author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
|
|
||||||
from odoo import models, fields
|
from odoo import api, fields, models
|
||||||
|
|
||||||
|
|
||||||
class ResPartner(models.Model):
|
class ResPartner(models.Model):
|
||||||
_inherit = 'res.partner'
|
_inherit = 'res.partner'
|
||||||
|
|
||||||
ref = fields.Char(copy=False) # To avoid blocking duplicate
|
ref = fields.Char(copy=False) # To avoid blocking duplicate
|
||||||
|
invalidate_display_name = fields.Boolean()
|
||||||
|
|
||||||
_sql_constraints = [(
|
_sql_constraints = [(
|
||||||
'ref_unique',
|
'ref_unique',
|
||||||
@@ -16,6 +17,11 @@ class ResPartner(models.Model):
|
|||||||
'A partner already exists with this internal reference!'
|
'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(ResPartner, self)._compute_display_name()
|
||||||
|
|
||||||
def _get_name(self):
|
def _get_name(self):
|
||||||
partner = self
|
partner = self
|
||||||
name = partner.name or ''
|
name = partner.name or ''
|
||||||
|
|||||||
82
base_usability/README.rst
Normal file
82
base_usability/README.rst
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
==============
|
||||||
|
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.
|
||||||
@@ -8,22 +8,6 @@
|
|||||||
'category': 'Partner',
|
'category': 'Partner',
|
||||||
'license': 'AGPL-3',
|
'license': 'AGPL-3',
|
||||||
'summary': 'Better usability in base module',
|
'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',
|
'author': 'Akretion',
|
||||||
'website': 'http://www.akretion.com',
|
'website': 'http://www.akretion.com',
|
||||||
'depends': ['base'],
|
'depends': ['base'],
|
||||||
|
|||||||
@@ -3,3 +3,4 @@ from . import partner
|
|||||||
from . import company
|
from . import company
|
||||||
from . import mail
|
from . import mail
|
||||||
from . import misc
|
from . import misc
|
||||||
|
from . import ir_model
|
||||||
|
|||||||
16
base_usability/models/ir_model.py
Normal file
16
base_usability/models/ir_model.py
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
# 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
|
||||||
3
base_usability/readme/CONTRIBUTORS.rst
Normal file
3
base_usability/readme/CONTRIBUTORS.rst
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
* Alexis de Lattre <alexis.delattre@akretion.com>
|
||||||
|
* Raphaël Valyi <rvalyi@akretion.com>
|
||||||
|
* David Beal <david.beal@akretion.com>
|
||||||
25
base_usability/readme/DESCRIPTION.rst
Normal file
25
base_usability/readme/DESCRIPTION.rst
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
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
|
||||||
440
base_usability/static/description/index.html
Normal file
440
base_usability/static/description/index.html
Normal file
@@ -0,0 +1,440 @@
|
|||||||
|
<?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 doesn’t 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 <<a class="reference external" href="mailto:alexis.delattre@akretion.com">alexis.delattre@akretion.com</a>></li>
|
||||||
|
<li>David Beal <<a class="reference external" href="mailto:david.beal@akretion.com">david.beal@akretion.com</a>></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>
|
||||||
@@ -12,4 +12,14 @@
|
|||||||
</field>
|
</field>
|
||||||
</record>
|
</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>
|
</odoo>
|
||||||
|
|||||||
@@ -1,12 +1,23 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!--
|
<!--
|
||||||
© 2015-2016 Akretion (http://www.akretion.com/)
|
Copyright 2015-2019 Akretion France (http://www.akretion.com/)
|
||||||
@author: Alexis de Lattre <alexis.delattre@akretion.com>
|
@author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<odoo>
|
<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">
|
<record id="view_module_filter" model="ir.ui.view">
|
||||||
<field name="model">ir.module.module</field>
|
<field name="model">ir.module.module</field>
|
||||||
<field name="inherit_id" ref="base.view_module_filter"/>
|
<field name="inherit_id" ref="base.view_module_filter"/>
|
||||||
@@ -24,4 +35,5 @@
|
|||||||
<field name="context">{'search_default_installable': 1}</field>
|
<field name="context">{'search_default_installable': 1}</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
|
|
||||||
</odoo>
|
</odoo>
|
||||||
|
|||||||
@@ -12,10 +12,6 @@
|
|||||||
<field name="model">res.partner</field>
|
<field name="model">res.partner</field>
|
||||||
<field name="inherit_id" ref="base.view_partner_form"/>
|
<field name="inherit_id" ref="base.view_partner_form"/>
|
||||||
<field name="arch" type="xml">
|
<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">
|
<xpath expr="//field[@name='child_ids']/form//field[@name='email']" position="attributes">
|
||||||
<attribute name="widget">email</attribute>
|
<attribute name="widget">email</attribute>
|
||||||
</xpath>
|
</xpath>
|
||||||
@@ -61,6 +57,9 @@
|
|||||||
<!-- for 'ref', change '=' to 'start with' -->
|
<!-- for 'ref', change '=' to 'start with' -->
|
||||||
<attribute name="filter_domain">['|','|',('display_name','ilike',self),('ref','=ilike',self + '%'),('email','ilike',self)]</attribute>
|
<attribute name="filter_domain">['|','|',('display_name','ilike',self),('ref','=ilike',self + '%'),('email','ilike',self)]</attribute>
|
||||||
</field>
|
</field>
|
||||||
|
<filter name="inactive" position="before">
|
||||||
|
<separator/>
|
||||||
|
</filter>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
|
|||||||
1
delivery_usability/__init__.py
Normal file
1
delivery_usability/__init__.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
from . import stock
|
||||||
29
delivery_usability/__manifest__.py
Normal file
29
delivery_usability/__manifest__.py
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
# 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,
|
||||||
|
}
|
||||||
23
delivery_usability/sale_view.xml
Normal file
23
delivery_usability/sale_view.xml
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
<?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>
|
||||||
12
delivery_usability/stock.py
Normal file
12
delivery_usability/stock.py
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# 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')
|
||||||
26
delivery_usability/stock_view.xml
Normal file
26
delivery_usability/stock_view.xml
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
<?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>
|
||||||
1
eradicate_quick_create/__init__.py
Normal file
1
eradicate_quick_create/__init__.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
from .hooks import web_m2x_options_create
|
||||||
25
eradicate_quick_create/__manifest__.py
Normal file
25
eradicate_quick_create/__manifest__.py
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
# 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,
|
||||||
|
}
|
||||||
19
eradicate_quick_create/hooks.py
Normal file
19
eradicate_quick_create/hooks.py
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# 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',
|
||||||
|
})
|
||||||
BIN
eradicate_quick_create/static/description/icon.png
Normal file
BIN
eradicate_quick_create/static/description/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.6 KiB |
@@ -20,8 +20,7 @@ This module has been written by Alexis de Lattre from Akretion <alexis.delattre@
|
|||||||
""",
|
""",
|
||||||
'author': 'Akretion',
|
'author': 'Akretion',
|
||||||
'website': 'http://www.akretion.com',
|
'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'],
|
'data': ['product_view.xml'],
|
||||||
'post_init_hook': 'set_intrastat_type_on_products',
|
'post_init_hook': 'set_intrastat_type_on_products',
|
||||||
'installable': True,
|
'installable': True,
|
||||||
|
|||||||
@@ -60,14 +60,14 @@ class ProductTemplate(models.Model):
|
|||||||
return super(ProductTemplate, self).create(vals)
|
return super(ProductTemplate, self).create(vals)
|
||||||
|
|
||||||
|
|
||||||
#class L10nFrIntrastatServiceDeclaration(models.Model):
|
class L10nFrIntrastatServiceDeclaration(models.Model):
|
||||||
# _inherit = "l10n.fr.intrastat.service.declaration"
|
_inherit = "l10n.fr.intrastat.service.declaration"
|
||||||
|
|
||||||
# def _is_service(self, invoice_line):
|
def _is_service(self, invoice_line):
|
||||||
# if invoice_line.product_id.intrastat_type == 'service':
|
if invoice_line.product_id.intrastat_type == 'service':
|
||||||
# return True
|
return True
|
||||||
# else:
|
else:
|
||||||
# return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
class IntrastatProductDeclaration(models.Model):
|
class IntrastatProductDeclaration(models.Model):
|
||||||
|
|||||||
@@ -1 +1,3 @@
|
|||||||
from . import mrp
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
|
|
||||||
|
from . import models
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Copyright (C) 2016-2019 Akretion (http://www.akretion.com)
|
# Copyright (C) 2016-2019 Akretion (http://www.akretion.com)
|
||||||
# @author Alexis de Lattre <alexis.delattre@akretion.com>
|
# @author Alexis de Lattre <alexis.delattre@akretion.com>
|
||||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
@@ -25,10 +24,10 @@ This module has been written by Alexis de Lattre from Akretion <alexis.delattre@
|
|||||||
'website': 'http://www.akretion.com',
|
'website': 'http://www.akretion.com',
|
||||||
'depends': ['mrp'],
|
'depends': ['mrp'],
|
||||||
'data': [
|
'data': [
|
||||||
'mrp_view.xml',
|
'security/mrp_average_cost_security.xml',
|
||||||
'mrp_data.xml',
|
|
||||||
'security/labour_cost_profile_security.xml',
|
|
||||||
'security/ir.model.access.csv',
|
'security/ir.model.access.csv',
|
||||||
|
'data/mrp_data.xml',
|
||||||
|
'views/mrp_view.xml',
|
||||||
],
|
],
|
||||||
'installable': True,
|
'installable': True,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
<field name="numbercall">-1</field> <!-- don't limit the number of calls -->
|
<field name="numbercall">-1</field> <!-- don't limit the number of calls -->
|
||||||
<field name="doall" eval="False"/>
|
<field name="doall" eval="False"/>
|
||||||
<field name="model_id" ref="mrp.model_mrp_bom"/>
|
<field name="model_id" ref="mrp.model_mrp_bom"/>
|
||||||
|
<field name="state">code</field>
|
||||||
<field name="code">model._phantom_update_product_standard_price()</field>
|
<field name="code">model._phantom_update_product_standard_price()</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
3
mrp_average_cost/models/__init__.py
Normal file
3
mrp_average_cost/models/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
|
|
||||||
|
from . import mrp
|
||||||
260
mrp_average_cost/models/mrp.py
Normal file
260
mrp_average_cost/models/mrp.py
Normal file
@@ -0,0 +1,260 @@
|
|||||||
|
# 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()
|
||||||
@@ -1,288 +0,0 @@
|
|||||||
# -*- 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)
|
|
||||||
@@ -37,7 +37,7 @@
|
|||||||
</group>
|
</group>
|
||||||
</page>
|
</page>
|
||||||
</notebook>
|
</notebook>
|
||||||
<xpath expr="//field[@name='bom_line_ids']/tree/field[@name='product_uom_id']" position="after">
|
<xpath expr="//field[@name='bom_line_ids']/tree/field[@name='operation_id']" position="after">
|
||||||
<field name="standard_price"/>
|
<field name="standard_price"/>
|
||||||
</xpath>
|
</xpath>
|
||||||
</field>
|
</field>
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
# © 2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
|
# Copyright 2016-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).
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!--
|
<!--
|
||||||
© 2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
|
Copyright 2016-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).
|
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
-->
|
-->
|
||||||
|
|
||||||
|
|||||||
0
mrp_product_tree_default/__init__.py
Normal file
0
mrp_product_tree_default/__init__.py
Normal file
22
mrp_product_tree_default/__manifest__.py
Normal file
22
mrp_product_tree_default/__manifest__.py
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
# © 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,
|
||||||
|
}
|
||||||
9
mrp_product_tree_default/views/product_template.xml
Normal file
9
mrp_product_tree_default/views/product_template.xml
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<?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>
|
||||||
@@ -17,7 +17,7 @@ MRP Usability
|
|||||||
:target: https://github.com/akretion/odoo-usability/tree/12.0/mrp_usability
|
:target: https://github.com/akretion/odoo-usability/tree/12.0/mrp_usability
|
||||||
:alt: akretion/odoo-usability
|
:alt: akretion/odoo-usability
|
||||||
|
|
||||||
|badge1| |badge2| |badge3|
|
|badge1| |badge2| |badge3|
|
||||||
|
|
||||||
Small usability improvements on MRP:
|
Small usability improvements on MRP:
|
||||||
|
|
||||||
@@ -31,6 +31,8 @@ Small usability improvements on MRP:
|
|||||||
|
|
||||||
* complete Manufacturing Order report with unvailable products
|
* 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**
|
**Table of contents**
|
||||||
|
|
||||||
.. contents::
|
.. contents::
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
from . import mrp
|
from . import models
|
||||||
|
|||||||
@@ -13,7 +13,8 @@
|
|||||||
'website': 'http://www.akretion.com',
|
'website': 'http://www.akretion.com',
|
||||||
'depends': ['mrp'],
|
'depends': ['mrp'],
|
||||||
'data': [
|
'data': [
|
||||||
'mrp_view.xml',
|
'views/mrp_views.xml',
|
||||||
|
'views/product_views.xml',
|
||||||
'report/mrp_report.xml'
|
'report/mrp_report.xml'
|
||||||
],
|
],
|
||||||
'installable': True,
|
'installable': True,
|
||||||
|
|||||||
@@ -1,25 +1,32 @@
|
|||||||
# Translation of Odoo Server.
|
# Translation of Odoo Server.
|
||||||
# This file contains the translation of the following modules:
|
# This file contains the translation of the following modules:
|
||||||
# * mrp_usability
|
# * mrp_usability
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: Odoo Server 12.0\n"
|
"Project-Id-Version: Odoo Server 12.0\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2019-03-26 08:56+0000\n"
|
"POT-Creation-Date: 2019-07-16 13:56+0000\n"
|
||||||
"PO-Revision-Date: 2019-03-26 08:56+0000\n"
|
"PO-Revision-Date: 2019-07-16 16:01+0200\n"
|
||||||
"Last-Translator: <>\n"
|
"Last-Translator: <>\n"
|
||||||
"Language-Team: \n"
|
"Language-Team: \n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: \n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"Plural-Forms: \n"
|
"Plural-Forms: \n"
|
||||||
|
"Language: fr\n"
|
||||||
|
"X-Generator: Poedit 2.0.6\n"
|
||||||
|
|
||||||
#. module: mrp_usability
|
#. module: mrp_usability
|
||||||
#: model_terms:ir.ui.view,arch_db:mrp_usability.mrp_production_form_view
|
#: model_terms:ir.ui.view,arch_db:mrp_usability.mrp_production_form_view
|
||||||
msgid "Are you sure you want to cancel this manufacturing order?"
|
msgid "Are you sure you want to cancel this manufacturing order?"
|
||||||
msgstr "Etes vous sur de vouloir annuler cet ordre de production"
|
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
|
#. module: mrp_usability
|
||||||
#: model_terms:ir.ui.view,arch_db:mrp_usability.report_mrporder
|
#: model_terms:ir.ui.view,arch_db:mrp_usability.report_mrporder
|
||||||
msgid "Product"
|
msgid "Product"
|
||||||
@@ -37,11 +44,14 @@ msgstr "Quantité"
|
|||||||
|
|
||||||
#. module: mrp_usability
|
#. module: mrp_usability
|
||||||
#: model_terms:ir.ui.view,arch_db:mrp_usability.report_mrporder
|
#: model_terms:ir.ui.view,arch_db:mrp_usability.report_mrporder
|
||||||
msgid "These products were unavailable while edition of this Manufacturing Order"
|
msgid ""
|
||||||
msgstr "Ces produits étaient indisponibles au moment de l'édition de l'Ordre de Production"
|
"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."
|
||||||
|
|
||||||
#. module: mrp_usability
|
#. module: mrp_usability
|
||||||
#: model_terms:ir.ui.view,arch_db:mrp_usability.view_mrp_bom_filter
|
#: model_terms:ir.ui.view,arch_db:mrp_usability.view_mrp_bom_filter
|
||||||
msgid "Type"
|
msgid "Type"
|
||||||
msgstr "Type"
|
msgstr ""
|
||||||
|
|
||||||
|
|||||||
2
mrp_usability/models/__init__.py
Normal file
2
mrp_usability/models/__init__.py
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
|
from . import mrp, product
|
||||||
44
mrp_usability/models/product.py
Normal file
44
mrp_usability/models/product.py
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
# 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
|
||||||
@@ -9,3 +9,5 @@ Small usability improvements on MRP:
|
|||||||
* show bom type in tree view + add group by
|
* show bom type in tree view + add group by
|
||||||
|
|
||||||
* complete Manufacturing Order report with unvailable products
|
* 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)
|
||||||
|
|||||||
@@ -11,11 +11,12 @@
|
|||||||
<td t-if="has_serial_number"><span t-field="ml.lot_id"/></td>
|
<td t-if="has_serial_number"><span t-field="ml.lot_id"/></td>
|
||||||
</xpath>
|
</xpath>
|
||||||
|
|
||||||
<xpath expr="//div[@class='oe_structure'][2]" position="after">
|
<xpath expr="//div[hasclass('oe_structure')][2]" position="after">
|
||||||
<t t-set="has_product_unavailable"
|
<t t-set="has_product_unavailable"
|
||||||
t-value="any(o.move_raw_ids.filtered(lambda x: not x.reserved_availability))"/>
|
t-value="any(o.move_raw_ids.filtered(lambda x: x.product_uom_qty > x.reserved_availability))"/>
|
||||||
<h4 if="has_product_unavailable">
|
<h4 if="has_product_unavailable">
|
||||||
These products were unavailable while edition of this Manufacturing Order
|
These products were unavailable (or partially) while edition of this Manufacturing Order.
|
||||||
|
Here is complete quantities for these.
|
||||||
</h4>
|
</h4>
|
||||||
<table class="table table-sm" t-if="o.move_raw_ids and has_product_unavailable">
|
<table class="table table-sm" t-if="o.move_raw_ids and has_product_unavailable">
|
||||||
<thead>
|
<thead>
|
||||||
@@ -26,7 +27,7 @@
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<t t-set="lines"
|
<t t-set="lines"
|
||||||
t-value="o.move_raw_ids.filtered(lambda x: not x.reserved_availability)"/>
|
t-value="o.move_raw_ids.filtered(lambda x: x.product_uom_qty > x.reserved_availability)"/>
|
||||||
<t t-foreach="lines" t-as="ml">
|
<t t-foreach="lines" t-as="ml">
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
|
|||||||
25
mrp_usability/views/product_views.xml
Normal file
25
mrp_usability/views/product_views.xml
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
<?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>
|
||||||
0
pos_usability/__init__.py
Normal file
0
pos_usability/__init__.py
Normal file
29
pos_usability/__manifest__.py
Normal file
29
pos_usability/__manifest__.py
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
# 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,
|
||||||
|
}
|
||||||
23
pos_usability/i18n/fr.po
Normal file
23
pos_usability/i18n/fr.po
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
# 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"
|
||||||
17
pos_usability/report/pos.xml
Normal file
17
pos_usability/report/pos.xml
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<?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>
|
||||||
BIN
pos_usability/static/description/icon.png
Normal file
BIN
pos_usability/static/description/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.5 KiB |
23
product_no_translation/__init__.py
Normal file
23
product_no_translation/__init__.py
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
# -*- 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
|
||||||
40
product_no_translation/__manifest__.py
Normal file
40
product_no_translation/__manifest__.py
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
# -*- 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'],
|
||||||
|
}
|
||||||
62
product_no_translation/product.py
Normal file
62
product_no_translation/product.py
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
# -*- 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)
|
||||||
BIN
product_no_translation/static/description/icon.png
Normal file
BIN
product_no_translation/static/description/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.0 KiB |
@@ -1,3 +1,3 @@
|
|||||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
|
|
||||||
from . import product
|
from . import models
|
||||||
from . import pricelist
|
|
||||||
|
|||||||
@@ -28,7 +28,11 @@ This module has been written by Alexis de Lattre from Akretion <alexis.delattre@
|
|||||||
'depends': ['product'],
|
'depends': ['product'],
|
||||||
'data': [
|
'data': [
|
||||||
'security/product_security.xml',
|
'security/product_security.xml',
|
||||||
'product_view.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',
|
||||||
|
],
|
||||||
'installable': True,
|
'installable': True,
|
||||||
}
|
}
|
||||||
|
|||||||
7
product_usability/models/__init__.py
Normal file
7
product_usability/models/__init__.py
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
|
|
||||||
|
from . import product
|
||||||
|
from . import product_template
|
||||||
|
from . import product_supplierinfo
|
||||||
|
from . import product_price_history
|
||||||
|
from . import pricelist
|
||||||
46
product_usability/models/product.py
Normal file
46
product_usability/models/product.py
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
# © 2015-2016 Akretion (http://www.akretion.com)
|
||||||
|
# @author Alexis de Lattre <alexis.delattre@akretion.com>
|
||||||
|
# @author Raphaël Valyi <rvalyi@akretion.com>
|
||||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
|
|
||||||
|
from odoo import models, fields
|
||||||
|
|
||||||
|
|
||||||
|
class ProductProduct(models.Model):
|
||||||
|
_inherit = 'product.product'
|
||||||
|
|
||||||
|
default_code = fields.Char(
|
||||||
|
track_visibility='onchange',
|
||||||
|
copy=False)
|
||||||
|
|
||||||
|
barcode = fields.Char(
|
||||||
|
track_visibility='onchange',
|
||||||
|
copy=False)
|
||||||
|
|
||||||
|
weight = fields.Float(
|
||||||
|
track_visibility='onchange')
|
||||||
|
|
||||||
|
active = fields.Boolean(
|
||||||
|
track_visibility='onchange')
|
||||||
|
|
||||||
|
price_history_ids = fields.One2many(
|
||||||
|
comodel_name='product.price.history',
|
||||||
|
inverse_name='product_id',
|
||||||
|
string='Product Price History')
|
||||||
|
|
||||||
|
_sql_constraints = [(
|
||||||
|
# Maybe it could be better to have a constrain per company
|
||||||
|
# but the company_id field is on product.template,
|
||||||
|
# not on product.product
|
||||||
|
# If it's a problem, we'll create a company_id field on
|
||||||
|
# product.product
|
||||||
|
'default_code_uniq',
|
||||||
|
'unique(default_code)',
|
||||||
|
'This internal reference already exists!')]
|
||||||
|
|
||||||
|
def show_product_price_history(self):
|
||||||
|
self.ensure_one()
|
||||||
|
action = self.env.ref(
|
||||||
|
'product_usability.product_price_history_action').read()[0]
|
||||||
|
action['domain'] = [('product_id', '=', self.id)]
|
||||||
|
return action
|
||||||
16
product_usability/models/product_price_history.py
Normal file
16
product_usability/models/product_price_history.py
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
# © 2015-2016 Akretion (http://www.akretion.com)
|
||||||
|
# @author Alexis de Lattre <alexis.delattre@akretion.com>
|
||||||
|
# @author Raphaël Valyi <rvalyi@akretion.com>
|
||||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
|
|
||||||
|
from odoo import models, fields
|
||||||
|
|
||||||
|
|
||||||
|
class ProductPriceHistory(models.Model):
|
||||||
|
_inherit = 'product.price.history'
|
||||||
|
|
||||||
|
company_currency_id = fields.Many2one(
|
||||||
|
related='company_id.currency_id',
|
||||||
|
readonly=True,
|
||||||
|
compute_sudo=True,
|
||||||
|
string='Company Currency')
|
||||||
13
product_usability/models/product_supplierinfo.py
Normal file
13
product_usability/models/product_supplierinfo.py
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
# © 2015-2016 Akretion (http://www.akretion.com)
|
||||||
|
# @author Alexis de Lattre <alexis.delattre@akretion.com>
|
||||||
|
# @author Raphaël Valyi <rvalyi@akretion.com>
|
||||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
|
|
||||||
|
from odoo import models, fields
|
||||||
|
|
||||||
|
|
||||||
|
class ProductSupplierinfo(models.Model):
|
||||||
|
_inherit = 'product.supplierinfo'
|
||||||
|
|
||||||
|
name = fields.Many2one(
|
||||||
|
domain=[('supplier', '=', True), ('parent_id', '=', False)])
|
||||||
40
product_usability/models/product_template.py
Normal file
40
product_usability/models/product_template.py
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
# © 2015-2016 Akretion (http://www.akretion.com)
|
||||||
|
# @author Alexis de Lattre <alexis.delattre@akretion.com>
|
||||||
|
# @author Raphaël Valyi <rvalyi@akretion.com>
|
||||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
|
|
||||||
|
from odoo import models, fields
|
||||||
|
|
||||||
|
|
||||||
|
class ProductTemplate(models.Model):
|
||||||
|
_inherit = 'product.template'
|
||||||
|
|
||||||
|
name = fields.Char(
|
||||||
|
track_visibility='onchange')
|
||||||
|
|
||||||
|
type = fields.Selection(
|
||||||
|
track_visibility='onchange')
|
||||||
|
|
||||||
|
categ_id = fields.Many2one(
|
||||||
|
track_visibility='onchange')
|
||||||
|
|
||||||
|
list_price = fields.Float(
|
||||||
|
track_visibility='onchange')
|
||||||
|
|
||||||
|
sale_ok = fields.Boolean(
|
||||||
|
track_visibility='onchange')
|
||||||
|
|
||||||
|
purchase_ok = fields.Boolean(
|
||||||
|
track_visibility='onchange')
|
||||||
|
|
||||||
|
active = fields.Boolean(
|
||||||
|
track_visibility='onchange')
|
||||||
|
|
||||||
|
def show_product_price_history(self):
|
||||||
|
self.ensure_one()
|
||||||
|
products = self.env['product.product'].search(
|
||||||
|
[('product_tmpl_id', '=', self._context['active_id'])])
|
||||||
|
action = self.env.ref(
|
||||||
|
'product_usability.product_price_history_action').read()[0]
|
||||||
|
action['domain'] = [('product_id', 'in', products.ids)]
|
||||||
|
return action
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
|
|
||||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
|
||||||
|
|
||||||
from odoo import models, fields
|
|
||||||
|
|
||||||
|
|
||||||
class ProductTemplate(models.Model):
|
|
||||||
_inherit = 'product.template'
|
|
||||||
|
|
||||||
name = fields.Char(track_visibility='onchange')
|
|
||||||
type = fields.Selection(track_visibility='onchange')
|
|
||||||
categ_id = fields.Many2one(track_visibility='onchange')
|
|
||||||
list_price = fields.Float(track_visibility='onchange')
|
|
||||||
sale_ok = fields.Boolean(track_visibility='onchange')
|
|
||||||
purchase_ok = fields.Boolean(track_visibility='onchange')
|
|
||||||
active = fields.Boolean(track_visibility='onchange')
|
|
||||||
|
|
||||||
def show_product_price_history(self):
|
|
||||||
self.ensure_one()
|
|
||||||
products = self.env['product.product'].search(
|
|
||||||
[('product_tmpl_id', '=', self._context['active_id'])])
|
|
||||||
action = self.env['ir.actions.act_window'].for_xml_id(
|
|
||||||
'product_usability', 'product_price_history_action')
|
|
||||||
action.update({
|
|
||||||
'domain': "[('id', 'in', %s)]" % products.ids,
|
|
||||||
})
|
|
||||||
return action
|
|
||||||
|
|
||||||
|
|
||||||
class ProductProduct(models.Model):
|
|
||||||
_inherit = 'product.product'
|
|
||||||
|
|
||||||
default_code = fields.Char(track_visibility='onchange', copy=False)
|
|
||||||
barcode = fields.Char(track_visibility='onchange', copy=False)
|
|
||||||
weight = fields.Float(track_visibility='onchange')
|
|
||||||
active = fields.Boolean(track_visibility='onchange')
|
|
||||||
price_history_ids = fields.One2many(
|
|
||||||
'product.price.history', 'product_id',
|
|
||||||
string='Product Price History')
|
|
||||||
|
|
||||||
_sql_constraints = [(
|
|
||||||
# Maybe it could be better to have a constrain per company
|
|
||||||
# but the company_id field is on product.template,
|
|
||||||
# not on product.product
|
|
||||||
# If it's a problem, we'll create a company_id field on
|
|
||||||
# product.product
|
|
||||||
'default_code_uniq',
|
|
||||||
'unique(default_code)',
|
|
||||||
'This internal reference already exists!')]
|
|
||||||
|
|
||||||
def show_product_price_history(self):
|
|
||||||
self.ensure_one()
|
|
||||||
action = self.env['ir.actions.act_window'].for_xml_id(
|
|
||||||
'product_usability', 'product_price_history_action')
|
|
||||||
action.update({
|
|
||||||
'domain': "[('product_id', '=', %d)]" % self.ids[0],
|
|
||||||
})
|
|
||||||
return action
|
|
||||||
|
|
||||||
|
|
||||||
class ProductSupplierinfo(models.Model):
|
|
||||||
_inherit = 'product.supplierinfo'
|
|
||||||
|
|
||||||
name = fields.Many2one(
|
|
||||||
domain=[('supplier', '=', True), ('parent_id', '=', False)])
|
|
||||||
|
|
||||||
|
|
||||||
class ProductPriceHistory(models.Model):
|
|
||||||
_inherit = 'product.price.history'
|
|
||||||
|
|
||||||
company_currency_id = fields.Many2one(
|
|
||||||
related='company_id.currency_id', readonly=True, compute_sudo=True,
|
|
||||||
string='Company Currency')
|
|
||||||
@@ -1,223 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!--
|
|
||||||
© 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>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- product.price.history -->
|
|
||||||
<record id="product_price_history_form" model="ir.ui.view">
|
|
||||||
<field name="name">product.price.history.form</field>
|
|
||||||
<field name="model">product.price.history</field>
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<form string="Product Price History">
|
|
||||||
<group name="main">
|
|
||||||
<field name="product_id" invisible="not context.get('product_price_history_main_view')"/>
|
|
||||||
<field name="datetime"/>
|
|
||||||
<field name="cost" widget="monetary" options="{'currency_field': 'company_currency_id'}"/>
|
|
||||||
<field name="create_uid"/>
|
|
||||||
<field name="company_id" groups="base.group_multi_company"/>
|
|
||||||
<field name="company_currency_id" invisible="1"/>
|
|
||||||
</group>
|
|
||||||
</form>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<record id="product_price_history_tree" model="ir.ui.view">
|
|
||||||
<field name="name">product.price.history.tree</field>
|
|
||||||
<field name="model">product.price.history</field>
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<tree string="Product Price History" editable="bottom">
|
|
||||||
<field name="product_id" invisible="not context.get('product_price_history_main_view')"/>
|
|
||||||
<field name="datetime"/>
|
|
||||||
<field name="cost" widget="monetary" options="{'currency_field': 'company_currency_id'}"/>
|
|
||||||
<field name="create_uid"/>
|
|
||||||
<field name="company_id" groups="base.group_multi_company"/>
|
|
||||||
<field name="company_currency_id" invisible="1"/>
|
|
||||||
</tree>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<record id="product_price_history_search" model="ir.ui.view">
|
|
||||||
<field name="name">product.price.history.search</field>
|
|
||||||
<field name="model">product.price.history</field>
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<search string="Search Product Price History">
|
|
||||||
<field name="product_id"/>
|
|
||||||
<group string="Group By" name="groupby">
|
|
||||||
<filter name="product_groupby" string="Product" context="{'group_by': 'product_id'}"/>
|
|
||||||
<filter name="datetime_groupby" string="Date" context="{'group_by': 'datetime:month'}"/>
|
|
||||||
<filter name="create_uid_groupby" string="Created by" context="{'group_by': 'create_uid'}"/>
|
|
||||||
</group>
|
|
||||||
</search>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<record id="product_price_history_action" model="ir.actions.act_window">
|
|
||||||
<field name="name">Product Price History</field>
|
|
||||||
<field name="res_model">product.price.history</field>
|
|
||||||
<field name="view_mode">tree,form</field>
|
|
||||||
<field name="context">{'product_price_history_main_view': True}</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<!--
|
|
||||||
<menuitem id="product_price_history_menu" action="product_price_history_action"
|
|
||||||
parent="product.prod_config_main" sequence="55"/> -->
|
|
||||||
|
|
||||||
<!-- product.template -->
|
|
||||||
<record id="product_template_form_view" model="ir.ui.view">
|
|
||||||
<field name="name">usability.product.template.form</field>
|
|
||||||
<field name="model">product.template</field>
|
|
||||||
<field name="inherit_id" ref="product.product_template_form_view" />
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<field name="standard_price" class="oe_inline" position="after">
|
|
||||||
<button name="show_product_price_history" class="oe_inline oe_link" type="object" string="Show History" context="{'active_id': active_id}"/>
|
|
||||||
</field>
|
|
||||||
<!-- Don't make it too big, othesize computers with small resolutions
|
|
||||||
will see the product name + image under the block of buttons -->
|
|
||||||
<div class="oe_title" position="attributes">
|
|
||||||
<attribute name="style">width: 650px;</attribute>
|
|
||||||
</div>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<!-- It also adds on product.product search view -->
|
|
||||||
<record id="product_template_search_view" model="ir.ui.view">
|
|
||||||
<field name="name">usability.product.template.search</field>
|
|
||||||
<field name="model">product.template</field>
|
|
||||||
<field name="inherit_id" ref="product.product_template_search_view" />
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<field name="categ_id" position="after">
|
|
||||||
<field name="seller_ids" string="Supplier" filter_domain="[('seller_ids.name', 'ilike', self)]"/>
|
|
||||||
</field>
|
|
||||||
<field name="pricelist_id" position="after">
|
|
||||||
<group string="Group By" name="groupby">
|
|
||||||
<filter name="categ_groupby" string="Internal Category" context="{'group_by': 'categ_id'}"/>
|
|
||||||
<filter name="type_groupby" string="Type" context="{'group_by': 'type'}"/>
|
|
||||||
</group>
|
|
||||||
</field>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<record id="product_template_tree_view" model="ir.ui.view">
|
|
||||||
<field name="name">usability.product.template.tree</field>
|
|
||||||
<field name="model">product.template</field>
|
|
||||||
<field name="inherit_id" ref="product.product_template_tree_view"/>
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<field name="list_price" position="after">
|
|
||||||
<field name="currency_id" invisible="1"/>
|
|
||||||
</field>
|
|
||||||
<field name="list_price" position="attributes">
|
|
||||||
<attribute name="widget">monetary</attribute>
|
|
||||||
</field>
|
|
||||||
<field name="standard_price" position="attributes">
|
|
||||||
<attribute name="widget">monetary</attribute>
|
|
||||||
</field>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- product.product -->
|
|
||||||
<record id="product_product_tree_view" model="ir.ui.view">
|
|
||||||
<field name="name">usability.product.product.tree</field>
|
|
||||||
<field name="model">product.product</field>
|
|
||||||
<field name="inherit_id" ref="product.product_product_tree_view"/>
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<field name="lst_price" position="after">
|
|
||||||
<field name="currency_id" invisible="1"/>
|
|
||||||
</field>
|
|
||||||
<field name="lst_price" position="attributes">
|
|
||||||
<attribute name="widget">monetary</attribute>
|
|
||||||
</field>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<!-- product.pricelist -->
|
|
||||||
<record id="product_pricelist_view_tree" model="ir.ui.view">
|
|
||||||
<field name="name">usability.product.pricelist.tree</field>
|
|
||||||
<field name="model">product.pricelist</field>
|
|
||||||
<field name="inherit_id" ref="product.product_pricelist_view_tree"/>
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<field name="currency_id" position="after">
|
|
||||||
<field name="company_id" groups="base.group_multi_company"/>
|
|
||||||
</field>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<!-- product.pricelist.item -->
|
|
||||||
<record id="product_pricelist_item_search" model="ir.ui.view">
|
|
||||||
<field name="name">usability.product.pricelist.item.search</field>
|
|
||||||
<field name="model">product.pricelist.item</field>
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<search string="Search Pricelist Items">
|
|
||||||
<field name="pricelist_id"/>
|
|
||||||
<field name="product_tmpl_id"/>
|
|
||||||
<field name="product_id"/>
|
|
||||||
<field name="categ_id"/>
|
|
||||||
<group string="Group By" name="groupby">
|
|
||||||
<filter name="pricelist_groupby" string="Pricelist" context="{'group_by': 'pricelist_id'}"/>
|
|
||||||
<filter name="applied_on_groupby" string="Apply On" context="{'group_by': 'applied_on'}"/>
|
|
||||||
<filter name="base_on_groupby" string="Based On" context="{'group_by': 'base'}"/>
|
|
||||||
<filter name="compute_price_groupby" string="Compute Price" context="{'group_by': 'compute_price'}"/>
|
|
||||||
<filter name="currency_groupby" string="Currency" context="{'group_by': 'currency_id'}"/>
|
|
||||||
</group>
|
|
||||||
</search>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<record id="product_pricelist_item_form_view" model="ir.ui.view">
|
|
||||||
<field name="name">usability.product.pricelist.item.form</field>
|
|
||||||
<field name="model">product.pricelist.item</field>
|
|
||||||
<field name="inherit_id" ref="product.product_pricelist_item_form_view"/>
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<field name="applied_on" position="before">
|
|
||||||
<field name="pricelist_id" invisible="not context.get('product_pricelist_item_main_view')"/>
|
|
||||||
</field>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<record id="product_pricelist_item_tree_view" model="ir.ui.view">
|
|
||||||
<field name="name">usability.product.pricelist.item.tree</field>
|
|
||||||
<field name="model">product.pricelist.item</field>
|
|
||||||
<field name="inherit_id" ref="product.product_pricelist_item_tree_view"/>
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<field name="name" position="before">
|
|
||||||
<field name="pricelist_id" invisible="not context.get('product_pricelist_item_main_view')"/>
|
|
||||||
</field>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<!-- product.supplierinfo -->
|
|
||||||
<record id="product_supplierinfo_tree_view" model="ir.ui.view">
|
|
||||||
<field name="model">product.supplierinfo</field>
|
|
||||||
<field name="inherit_id" ref="product.product_supplierinfo_tree_view"/>
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<field name="product_tmpl_id" position="after">
|
|
||||||
<field name="product_name"/>
|
|
||||||
<field name="product_code" string="Supplier Code"/>
|
|
||||||
</field>
|
|
||||||
<field name="price" position="after">
|
|
||||||
<field name="currency_id" groups="base.group_multi_currency"/>
|
|
||||||
</field>
|
|
||||||
<field name="min_qty" position="after">
|
|
||||||
<field name="product_uom" groups="uom.group_uom"/>
|
|
||||||
</field>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<record id="product_supplierinfo_search_view" model="ir.ui.view">
|
|
||||||
<field name="model">product.supplierinfo</field>
|
|
||||||
<field name="inherit_id" ref="product.product_supplierinfo_search_view"/>
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<field name="product_tmpl_id" position="after">
|
|
||||||
<field name="product_code" string="Product Supplier Code"/>
|
|
||||||
</field>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
</odoo>
|
|
||||||
BIN
product_usability/static/description/icon.png
Normal file
BIN
product_usability/static/description/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.5 KiB |
419
product_usability/static/description/index.html
Normal file
419
product_usability/static/description/index.html
Normal file
@@ -0,0 +1,419 @@
|
|||||||
|
<?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.14: http://docutils.sourceforge.net/" />
|
||||||
|
<title>MRP 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="mrp-usability">
|
||||||
|
<h1 class="title">MRP 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/mrp_usability"><img alt="akretion/odoo-usability" src="https://img.shields.io/badge/github-akretion%2Fodoo--usability-lightgray.png?logo=github" /></a></p>
|
||||||
|
<p>Small usability improvements on MRP:</p>
|
||||||
|
<ul class="simple">
|
||||||
|
<li>order by id desc</li>
|
||||||
|
<li>show field date_start and date_finished on mrp.production form view</li>
|
||||||
|
<li>show more fields on stock move form</li>
|
||||||
|
<li>show bom type in tree view + add group by</li>
|
||||||
|
<li>complete Manufacturing Order report with unvailable products</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:%20mrp_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>
|
||||||
|
<p>Alexis de Lattre <<a class="reference external" href="mailto:alexis.delattre@akretion.com">alexis.delattre@akretion.com</a>></p>
|
||||||
|
</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/mrp_usability">akretion/odoo-usability</a> project on GitHub.</p>
|
||||||
|
<p>You are welcome to contribute.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
65
product_usability/views/product_price_history_view.xml
Normal file
65
product_usability/views/product_price_history_view.xml
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
© 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>
|
||||||
|
|
||||||
|
<!-- product.price.history -->
|
||||||
|
<record id="product_price_history_form" model="ir.ui.view">
|
||||||
|
<field name="name">product.price.history.form</field>
|
||||||
|
<field name="model">product.price.history</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<form string="Product Price History">
|
||||||
|
<group name="main">
|
||||||
|
<field name="product_id" invisible="not context.get('product_price_history_main_view')"/>
|
||||||
|
<field name="datetime"/>
|
||||||
|
<field name="cost" widget="monetary" options="{'currency_field': 'company_currency_id'}"/>
|
||||||
|
<field name="create_uid"/>
|
||||||
|
<field name="company_id" groups="base.group_multi_company"/>
|
||||||
|
<field name="company_currency_id" invisible="1"/>
|
||||||
|
</group>
|
||||||
|
</form>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="product_price_history_tree" model="ir.ui.view">
|
||||||
|
<field name="name">product.price.history.tree</field>
|
||||||
|
<field name="model">product.price.history</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<tree string="Product Price History" editable="bottom">
|
||||||
|
<field name="product_id" invisible="not context.get('product_price_history_main_view')"/>
|
||||||
|
<field name="datetime"/>
|
||||||
|
<field name="cost" widget="monetary" options="{'currency_field': 'company_currency_id'}"/>
|
||||||
|
<field name="create_uid"/>
|
||||||
|
<field name="company_id" groups="base.group_multi_company"/>
|
||||||
|
<field name="company_currency_id" invisible="1"/>
|
||||||
|
</tree>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="product_price_history_search" model="ir.ui.view">
|
||||||
|
<field name="name">product.price.history.search</field>
|
||||||
|
<field name="model">product.price.history</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<search string="Search Product Price History">
|
||||||
|
<field name="product_id"/>
|
||||||
|
<group string="Group By" name="groupby">
|
||||||
|
<filter name="product_groupby" string="Product" context="{'group_by': 'product_id'}"/>
|
||||||
|
<filter name="datetime_groupby" string="Date" context="{'group_by': 'datetime:month'}"/>
|
||||||
|
<filter name="create_uid_groupby" string="Created by" context="{'group_by': 'create_uid'}"/>
|
||||||
|
</group>
|
||||||
|
</search>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="product_price_history_action" model="ir.actions.act_window">
|
||||||
|
<field name="name">Product Price History</field>
|
||||||
|
<field name="res_model">product.price.history</field>
|
||||||
|
<field name="view_mode">tree,form</field>
|
||||||
|
<field name="context">{'product_price_history_main_view': True}</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
</odoo>
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user