Compare commits

..

2 Commits

Author SHA1 Message Date
David Beal
5ba4eadc15 V11 branch 2018-10-16 11:31:50 +02:00
David Beal
79d8f6edc5 INIT v12 2018-10-12 10:33:26 +02:00
835 changed files with 8 additions and 22188 deletions

56
.gitignore vendored
View File

@@ -1,56 +0,0 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
# C extensions
*.so
# Distribution / packaging
.Python
env/
bin/
build/
develop-eggs/
dist/
eggs/
lib/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.cache
nosetests.xml
coverage.xml
# Translations
*.mo
# Pycharm
.idea
# Mr Developer
.mr.developer.cfg
.project
.pydevproject
# Rope
.ropeproject
# Sphinx documentation
docs/_build/
# Backup files
*~
*.swp

8
README.rst Normal file
View File

@@ -0,0 +1,8 @@
Odoo Usability : 11.0 Branch
============================
Branch unmaintained by Akretion.
Please check these forks:
- https://github.com/camptocamp/odoo-usability

View File

@@ -1,3 +0,0 @@
# -*- coding: utf-8 -*-
from . import partner

View File

@@ -1,25 +0,0 @@
# -*- coding: utf-8 -*-
# Copyright 2015-2018 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': 'Aged Partner Balance from Partner',
'version': '10.0.0.1.0',
'category': 'Accounting',
'license': 'AGPL-3',
'summary': 'Direct access to the aged partner balance report from the partner form',
'description': """
Aged Partner Balance from Partner
=================================
This module adds a button on the partner form view (the icon on the button is a banknote) to easily open the detailed aged partner balance of the partner in PDF format.
This module has been written by Alexis de Lattre from Akretion <alexis.delattre@akretion.com>.
""",
'author': 'Akretion',
'website': 'http://www.akretion.com',
'depends': ['account_financial_report_qweb'],
'data': ['partner_view.xml'],
'installable': True,
}

View File

@@ -1,30 +0,0 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2015-2018 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
class ResPartner(models.Model):
_inherit = 'res.partner'
@api.depends('credit', 'debit')
def _compute_balance(self):
for partner in self:
partner.balance = partner.credit - partner.debit
# The field 'currency_id' defined in the account module
# is a computed field that gets the company currency
balance = fields.Monetary(
compute='_compute_balance', readonly=True,
string="Account Balance")
def open_aged_open_invoices_report(self):
wiz = self.env['aged.partner.balance.wizard'].create({
'show_move_line_details': True,
'partner_ids': [(6, 0, self.ids)],
})
action = wiz.button_export_pdf()
return action

View File

@@ -1,31 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2015-2018 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_partner_form" model="ir.ui.view">
<field name="name">account.balance.button.partner.form</field>
<field name="model">res.partner</field>
<field name="inherit_id" ref="account.partner_view_buttons"/>
<field name="arch" type="xml">
<button name="open_partner_history" type="object" position="after">
<button class="oe_stat_button" type="object"
name="open_aged_open_invoices_report"
attrs="{'invisible': [('parent_id', '!=', False)]}"
icon="fa-money">
<div class="o_form_field o_stat_info">
<span class="o_stat_value"><field name="balance"/></span>
<span class="o_stat_text">Account Balance</span>
</div>
</button>
</button>
</field>
</record>
</odoo>

View File

@@ -1,35 +0,0 @@
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
=======================================
Import French HSBC Card Bank Statements
=======================================
This module allows you to import French HSBC credit cards bank statements (CSV version).
Configuration
=============
Create a bank journal dedicated to HSBC credit cards. Associate it with a new bank account on which you will set the account number to *HSBC_CARD_EUR*.
Usage
=====
In the dashboard of the *Accounting* menu, click on the button *Import Statement* located on the journal corresponding to the bank account of the statement file you are importing.
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.
Credits
=======
Contributors
------------
* Alexis de Lattre <alexis.delattre@akretion.com>

View File

@@ -1,3 +0,0 @@
# -*- coding: utf-8 -*-
from . import wizard

View File

@@ -1,16 +0,0 @@
# -*- coding: utf-8 -*-
# © 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).
{
'name': 'Import French HSBC Card Bank Statements',
'version': '10.0.1.0.0',
'license': 'AGPL-3',
'author': "Akretion",
'website': 'http://www.akretion.com',
'summary': 'Import French HSBC Card Bank Statements in Odoo (CSV version)',
'depends': ['account_bank_statement_import'],
'data': ['views/account_bank_statement_import.xml'],
'installable': True,
}

View File

@@ -1,69 +0,0 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * account_bank_statement_import_fr_cfonb
#
# Translators:
# OCA Transbot <transbot@odoo-community.org>, 2017
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 10.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-01-13 03:36+0000\n"
"PO-Revision-Date: 2017-01-13 03:36+0000\n"
"Last-Translator: OCA Transbot <transbot@odoo-community.org>, 2017\n"
"Language-Team: Norwegian Bokmål (Norway) (https://www.transifex.com/oca/teams/23907/nb_NO/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Language: nb_NO\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#. module: account_bank_statement_import_fr_cfonb
#: code:addons/account_bank_statement_import_fr_cfonb/models/account_bank_statement_import.py:146
#, python-format
msgid "Account %s"
msgstr ""
#. module: account_bank_statement_import_fr_cfonb
#: model:ir.ui.view,arch_db:account_bank_statement_import_fr_cfonb.account_bank_statement_import_view
msgid "CFONB (French format, fixed-length text lines of 120 caracters)"
msgstr ""
#. module: account_bank_statement_import_fr_cfonb
#: model:ir.model,name:account_bank_statement_import_fr_cfonb.model_account_bank_statement_import
msgid "Import Bank Statement"
msgstr "Importer bankutsagn"
#. module: account_bank_statement_import_fr_cfonb
#: code:addons/account_bank_statement_import_fr_cfonb/models/account_bank_statement_import.py:70
#, python-format
msgid ""
"Line %d is %d caracters long. All lines of a CFONB bank statement file must "
"be 120 caracters long."
msgstr ""
"Linje %d er %d tegn langt. Alle linjer i en CFONB-bankutsagnsfil må være 120"
" tegn langt."
#. module: account_bank_statement_import_fr_cfonb
#: code:addons/account_bank_statement_import_fr_cfonb/models/account_bank_statement_import.py:110
#, python-format
msgid ""
"Only single-account files and single-currency files are supported for the "
"moment. It is not the case starting from line %d."
msgstr ""
"Kun enkeltkontofiler og enkeltmyntenhetsfiler støttes for øyeblikket. Dette "
"er ikke tilfellet fra og med linje %d og utover."
#. module: account_bank_statement_import_fr_cfonb
#: code:addons/account_bank_statement_import_fr_cfonb/models/account_bank_statement_import.py:99
#, python-format
msgid ""
"The 2 first letters of the first line are '%s'. A CFONB file should start "
"with '01'"
msgstr ""
#. module: account_bank_statement_import_fr_cfonb
#: code:addons/account_bank_statement_import_fr_cfonb/models/account_bank_statement_import.py:52
#, python-format
msgid "The file is empty."
msgstr "Filen er tom."

View File

@@ -1,22 +0,0 @@
<?xml version="1.0" ?>
<!--
© 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_bank_statement_import_view" model="ir.ui.view">
<field name="name">hsbc.fr.csv.account.bank.statement.import.form</field>
<field name="model">account.bank.statement.import</field>
<field name="inherit_id" ref="account_bank_statement_import.account_bank_statement_import_view"/>
<field name="arch" type="xml">
<xpath expr="//ul[@id='statement_format']" position="inside">
<li>French HSBC Credit Cards (CSV format)</li>
</xpath>
</field>
</record>
</odoo>

View File

@@ -1,3 +0,0 @@
# -*- coding: utf-8 -*-
from . import account_bank_statement_import

View File

@@ -1,105 +0,0 @@
# -*- coding: utf-8 -*-
# © 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).
import logging
import unicodecsv
from tempfile import TemporaryFile
from datetime import datetime
from odoo import models, fields, api, _
from odoo.exceptions import UserError
_logger = logging.getLogger(__name__)
class AccountBankStatementImport(models.TransientModel):
_inherit = 'account.bank.statement.import'
@api.model
def _check_hsbc_card_csv(self, data_file):
return data_file.strip().startswith(
'Titulaire;Division;;Cpt Affaires;Num carte;')
@api.model
def _parse_file(self, data_file):
""" Import a file in French HSBC CSV Credit card format"""
hsbc_csv = self._check_hsbc_card_csv(data_file)
if not hsbc_csv:
return super(AccountBankStatementImport, self)._parse_file(
data_file)
transactions = []
fileobj = TemporaryFile('w+')
fileobj.write(data_file)
fileobj.seek(0)
reader = unicodecsv.DictReader(
fileobj,
fieldnames=[
'company', 'division', 'empty', 'account',
'card_num', 'title', 'lastname', 'firstname',
'op_code', 'seller_type', 'seller', 'date', 'acc_date',
'hour', 'city', 'code', 'label', 'local_amount',
'local_currency', 'acc_amount', 'acc_currency'],
delimiter=';',
quoting=unicodecsv.QUOTE_MINIMAL,
encoding='latin1')
i = 0
start_balance = end_balance = 0.0
currency_code = 'EUR'
account_number = 'HSBC_CARD_EUR'
for line in reader:
i += 1
if i == 1:
continue # skip title line
_logger.debug("Line %d: %s" % (i, line))
if not line:
continue
# cleanup
for key, value in line.iteritems():
line[key] = value and value.strip() or False
if not line['date'] or not line['acc_amount']:
continue
labels = [
'%s %s' % (line['firstname'], line['lastname']),
'%s (%s)' % (line['seller'], line['seller_type']),
line['city']]
if line['local_currency'] != currency_code:
labels.append(
'%s %s' % (line['local_amount'], line['local_currency']))
name = ', '.join(labels)
amount = float(
line['acc_amount'].replace(',', '.').replace(' ', '')) * -1
end_balance += amount
date_dt = datetime.strptime(line['date'], '%d/%m/%Y')
date_str = fields.Date.to_string(date_dt)
if line['acc_currency'] != currency_code:
raise UserError(_(
"On line %d of the HSBC CSV file, the column "
"'Dev Cpt Affaires' contains '%s' instead of 'EUR'")
% (line['acc_currency'], i))
vals_line = {
'date': date_str,
'name': name,
'ref': False,
# unfortunately, I'm obliged to include i in
# the unique_import_id, which will disable the auto-delete
# of already imported lines. But experice has proven that
# Internet payment often have hour=00:00, and it's possible
# to have 2 internet payments for the same supplier the same
# day with the same amount (e.g. purchase a return ticket)
'unique_import_id': '%s-%s-%.2f-%s-%d' % (
date_str, line['hour'], amount, name, i),
'amount': amount,
'partner_id': False,
}
transactions.append(vals_line)
vals_bank_statement = {
'name': _('HSBC Cards'),
'balance_start': start_balance,
'balance_end_real': end_balance,
'transactions': transactions,
}
fileobj.close()
# from pprint import pprint
# pprint(vals_bank_statement)
return currency_code, account_number, [vals_bank_statement]

View File

@@ -1,3 +0,0 @@
# -*- coding: utf-8 -*-
from . import account_bank_statement_import

View File

@@ -1,29 +0,0 @@
# -*- coding: 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).
{
'name': 'Account Bank Statement Import Usability',
'version': '10.0.0.1.0',
'category': 'Accounting & Finance',
'license': 'AGPL-3',
'summary': 'Small usability enhancements in account_bank_statement_import module',
'description': """
Account Bank Statement Import Usability
=======================================
This module adds the following changes:
* Works if the bank statement file only contain the account number and not the full IBAN
* remove start balance and end balance (doesn't work with OFX, which is one of the most used file format !)
This module has been written by Alexis de Lattre from Akretion <alexis.delattre@akretion.com>.
""",
'author': 'Akretion',
'website': 'http://www.akretion.com',
'depends': ['account_bank_statement_import'],
'data': ['account_view.xml'],
'installable': True,
}

View File

@@ -1,35 +0,0 @@
# -*- coding: 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).
from odoo import models, api
class AccountBankStatementImport(models.TransientModel):
_inherit = 'account.bank.statement.import'
def _check_journal_bank_account(self, journal, account_number):
if account_number in journal.bank_account_id.sanitized_acc_number:
return True
return False
class AccountBankStatement(models.Model):
_inherit = 'account.bank.statement'
# When we use the import of bank statement via files,
# the start/end_balance is usually computed from the lines itself
# because we don't have the 'real' information in the file
# But, in the module account_bank_statement_import, in the method
# _create_bank_statement(), the bank statement lines already present in
# Odoo are filtered out, but the start/end balance is not adjusted,
# so the user has to manually modifiy it the close the bank statement
# I think the solution is just to remove the start/end balance system
# on the bank statement when we use the file import
# This code is present in the 'account' module, but I override it here
# and not in account_usability because the users who don't have
# account_bank_statement_import may want to keep start/end balance
@api.multi
def _balance_check(self):
return True

View File

@@ -1,48 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
© 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>
<!--
Let's try again to work with balance_start and balance_end_real
in v10 to see if we can work with it in v10 or not...
If we really can't, I'll re-activate this view inheritance again
<record id="view_bank_statement_form" model="ir.ui.view">
<field name="name">bank_statement_import_usability.account.bank.statement.form</field>
<field name="model">account.bank.statement</field>
<field name="inherit_id" ref="account.view_bank_statement_form"/>
<field name="arch" type="xml">
<field name="balance_start" position="attributes">
<attribute name="invisible">1</attribute>
</field>
<field name="balance_end_real" position="attributes">
<attribute name="invisible">1</attribute>
</field>
</field>
</record>
-->
<record id="view_bank_statement_tree" model="ir.ui.view">
<field name="name">bank_statement_import_usability.account.bank.statement.tree</field>
<field name="model">account.bank.statement</field>
<field name="inherit_id" ref="account.view_bank_statement_tree"/>
<field name="arch" type="xml">
<field name="balance_start" position="attributes">
<attribute name="invisible">1</attribute>
</field>
<field name="balance_end_real" position="attributes">
<attribute name="invisible">1</attribute>
</field>
<tree position="attributes">
<attribute name="colors">blue:state=='draft';black:state=='confirm'</attribute>
</tree>
</field>
</record>
</odoo>

View File

@@ -1,3 +0,0 @@
# -*- coding: utf-8 -*-
from . import account

View File

@@ -1,33 +0,0 @@
# -*- coding: utf-8 -*-
# © 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).
{
'name': 'Account Bank Statement No Reconcile Guess',
'version': '10.0.1.0.0',
'category': 'Accounting & Finance',
'license': 'AGPL-3',
'summary': "Don't pre-select lines to reconcile in bank statements",
'description': """
Account Bank Statement No Reconcile Guess
=========================================
Here is a scenario where the "reconcile guess" feature is a problem for the accountant:
1) The accountant imports a large bank statement with 40 bank statement lines.
2) The "reconcile guess" feature will pre-select reconcile of line X with line 39 of the bank statement. But this guess is a mistake and line X should be reconciled with line 2 of the bank statement.
=> The accountant will not understand why he can't select line X to be reconciled with line 2 of the bank statement. To be able to reconcile line 2 correctif, he has to:
3) click several times on the "next page" button to reach line 39 of the bank statement and unselect line X.
4) Go back to line 2 of the bank statement and now he will be able to select line X.
This module disables the "reconcile guess" feature to avoid this problem.
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': [],
'installable': True,
}

View File

@@ -1,14 +0,0 @@
# -*- coding: utf-8 -*-
# © 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).
from odoo import models
class AccountBankStatementLine(models.Model):
_inherit = 'account.bank.statement.line'
def get_reconciliation_proposition(self, excluded_ids=None):
self.ensure_one()
return self.env['account.move.line']

View File

@@ -1,3 +0,0 @@
# -*- coding: utf-8 -*-
from . import account_credit_control

View File

@@ -1,46 +0,0 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Account Credit Control Usability module for Odoo
# Copyright (C) 2016 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': 'Account Credit Control Usability',
'version': '0.1',
'category': 'Accounting & Finance',
'license': 'AGPL-3',
'summary': 'Small usability enhancements in account_credit_control module',
'description': """
Account Credit Control Usability
================================
The usability enhancements include:
* add phone call in the list of channels
* hide some fields
This module has been written by Alexis de Lattre from Akretion <alexis.delattre@akretion.com>.
""",
'author': 'Akretion',
'website': 'http://www.akretion.com',
'depends': ['account_credit_control', 'partner_aged_open_invoices'],
'data': ['account_credit_control_view.xml'],
'installable': False,
}

View File

@@ -1,82 +0,0 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Account Credit Control Usability module for Odoo
# Copyright (C) 2016 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 openerp import models, fields, api
class CreditControlPolicyLevel(models.Model):
_inherit = "credit.control.policy.level"
_rec_name = 'internal_name'
channel = fields.Selection(selection_add=[('phone', 'Phone Call')])
name = fields.Char(
string='Subject',
help="Will be displayed in the subject of the emails and in "
"the letters")
internal_name = fields.Char(string='Internal Name', required=True)
class CreditControlLine(models.Model):
_inherit = "credit.control.line"
channel = fields.Selection(selection_add=[('phone', 'Phone Call')])
note = fields.Text(string='Notes')
@api.multi
def open_aged_open_invoices_report(self):
self.ensure_one()
return self.partner_id.open_aged_open_invoices_report()
@api.multi
def go_to_partner_form(self):
self.ensure_one()
action = self.env['ir.actions.act_window'].for_xml_id(
'base', 'action_partner_customer_form')
action.update({
'view_mode': 'form,kanban,tree',
'views': False,
'res_id': self.partner_id.id,
'context': {},
})
return action
class CreditControlRun(models.Model):
_inherit = "credit.control.run"
date = fields.Date(default=fields.Date.context_today)
class ResPartner(models.Model):
_inherit = 'res.partner'
@api.one
@api.depends('credit_control_line_ids')
def _credit_control_line_count(self):
try:
self.credit_control_line_count = len(self.credit_control_line_ids)
except:
self.credit_control_line_count = 0
credit_control_line_count = fields.Integer(
compute='_credit_control_line_count',
string="# of Credit Control Lines", readonly=True)

View File

@@ -1,127 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="credit_control_line_tree" model="ir.ui.view">
<field name="name">credit_control_usability.credit_control_line_tree</field>
<field name="model">credit.control.line</field>
<field name="inherit_id" ref="account_credit_control.credit_control_line_tree"/>
<field name="arch" type="xml">
<field name="account_id" position="attributes">
<attribute name="invisible">1</attribute>
</field>
<field name="move_line_id" position="attributes">
<attribute name="invisible">1</attribute>
</field>
<field name="mail_message_id" position="attributes">
<attribute name="invisible">1</attribute>
</field>
<field name="partner_id" position="after">
<button name="go_to_partner_form" type="object"
string="Go to Partner" icon="terp-gtk-jump-to-ltr"/>
<button name="open_aged_open_invoices_report" type="object"
string="Open Aged Open Invoices Report" icon="STOCK_ZOOM_IN"/>
</field>
</field>
</record>
<record id="credit_control_line_form" model="ir.ui.view">
<field name="name">credit_control_usability.credit_control_line_form</field>
<field name="model">credit.control.line</field>
<field name="inherit_id" ref="account_credit_control.credit_control_line_form"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='currency_id']/.." position="after">
<group name="note">
<field name="note"/>
</group>
</xpath>
</field>
</record>
<record id="credit_control_policy_form" model="ir.ui.view">
<field name="name">credit_control_usability.credit.control.policy.form</field>
<field name="model">credit.control.policy</field>
<field name="inherit_id" ref="account_credit_control.credit_control_policy_form"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='level_ids']/tree/field[@name='name']" position="before">
<field name="internal_name"/>
</xpath>
<xpath expr="//field[@name='level_ids']/form//field[@name='name']" position="replace">
<group name="level-main">
<field name="internal_name"/>
<field name="name"/>
</group>
</xpath>
</field>
</record>
<record id="credit_mangement_policy_level_form" model="ir.ui.view">
<field name="name">credit_control_usability.credit.control.policy.level.form</field>
<field name="model">credit.control.policy.level</field>
<field name="inherit_id" ref="account_credit_control.credit_mangement_policy_level_form"/>
<field name="arch" type="xml">
<field name="name" position="before">
<field name="internal_name"/>
</field>
</field>
</record>
<record id="credit_control_policy_level_tree" model="ir.ui.view">
<field name="name">credit_control_usability.credit.control.policy.level.tree</field>
<field name="model">credit.control.policy.level</field>
<field name="inherit_id" ref="account_credit_control.credit_control_policy_level_tree"/>
<field name="arch" type="xml">
<field name="name" position="before">
<field name="internal_name"/>
</field>
</field>
</record>
<record id="credit_control_line_search" model="ir.ui.view">
<field name="name">credit_control_usability.credit_control_line_search</field>
<field name="model">credit.control.line</field>
<field name="inherit_id" ref="account_credit_control.credit_control_line_search"/>
<field name="arch" type="xml">
<filter name="filter_manual" position="after">
<filter name="phone" string="Phone Call" domain="[('channel', '=', 'phone')]"/>
<filter name="letter" string="Letter" domain="[('channel', '=', 'letter')]"/>
<filter name="email" string="Email" domain="[('channel', '=', 'email')]"/>
</filter>
</field>
</record>
<record id="partner_credit_control_line_action" model="ir.actions.act_window">
<field name="name">Credit Control Lines</field>
<field name="res_model">credit.control.line</field>
<field name="view_mode">tree,form</field>
<field name="context">{'search_default_partner_id': active_id}</field>
</record>
<record id="view_partner_form" model="ir.ui.view">
<field name="name">account_credit_control_usability.button.res.partner.form</field>
<field name="model">res.partner</field>
<field name="inherit_id" ref="base.view_partner_form" />
<field name="arch" type="xml">
<xpath expr="//div[@name='buttons']" position="inside">
<button class="oe_inline oe_stat_button" type="action"
name="%(partner_credit_control_line_action)d"
attrs="{'invisible': [('customer', '=', False)]}"
icon="fa-gavel">
<field string="Credit Control"
name="credit_control_line_count" widget="statinfo"/>
</button>
</xpath>
</field>
</record>
<!-- rapport -->
<template id="report_credit_control_summary_document" inherit_id="account_credit_control.report_credit_control_summary_document">
<xpath expr="//span[@t-field='l.amount_due']" position="attributes">
<attribute name="t-field-options">{"widget": "monetary", "display_currency": "l.currency_id or l.company_id.currency_id"}</attribute>
</xpath>
</template>
</data>
</openerp>

View File

@@ -1 +0,0 @@
# -*- coding: utf-8 -*-

View File

@@ -1,24 +0,0 @@
# -*- coding: utf-8 -*-
# © 2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{
'name': 'Account Cutoff Accrual Picking ODS',
'version': '8.0.0.1.0',
'category': 'Tools',
'license': 'AGPL-3',
'summary': 'Adds an Aeroo ODS report on cutoff accrual',
'description': """
Account Cutoff Accrual Picking ODS
==================================
This module will add an Aeroo ODS report on Accrued Revenue and Accrued Expense.
This module has been written by Alexis de Lattre from Akretion <alexis.delattre@akretion.com>.
""",
'author': "Akretion",
'website': 'http://www.akretion.com',
'depends': ['account_cutoff_accrual_picking', 'report_aeroo'],
'data': ['report.xml'],
'installable': False,
}

View File

@@ -1,27 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="account_cutoff_accrual_picking_ods" model="ir.actions.report.xml">
<field name="name">Cutoff Accrual ODS</field>
<field name="model">account.cutoff</field>
<field name="report_name">account.cutoff.accrual.picking.ods</field>
<field name="report_type">aeroo</field>
<field name="in_format">oo-ods</field>
<field name="report_rml">account_cutoff_accrual_picking_ods/cutoff_accrual.ods</field>
<field name="parser_state">default</field>
<field name="tml_source">file</field>
<field name="out_format" ref="report_aeroo.report_mimetypes_ods_ods"/>
</record>
<record id="account_cutoff_accrual_picking_ods_button" model="ir.values">
<field name="name">Cutoff Accrual ODS</field>
<field name="model">account.cutoff</field>
<field name="key2">client_print_multi</field>
<field name="value" eval="'ir.actions.report.xml,%d'%account_cutoff_accrual_picking_ods"/>
</record>
</data>
</openerp>

View File

@@ -1 +0,0 @@
# -*- coding: utf-8 -*-

View File

@@ -1,43 +0,0 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Account Cutoff Prepaid ODS module for Odoo
# Copyright (C) 2016 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': 'Account Cutoff Prepaid ODS',
'version': '8.0.0.1.0',
'category': 'Tools',
'license': 'AGPL-3',
'summary': 'Adds an Aeroo ODS report on cutoff prepaid',
'description': """
Account Cutoff Prepaid ODS
===========================
This module will add an Aeroo ODS report on Prepaid Revenue and Prepaid Expense.
This module has been written by Alexis de Lattre from Akretion <alexis.delattre@akretion.com>.
""",
'author': "Akretion",
'website': 'http://www.akretion.com',
'depends': ['account_cutoff_prepaid', 'report_aeroo'],
'data': ['report.xml'],
'installable': False,
}

View File

@@ -1,27 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="account_cutoff_prepaid_ods" model="ir.actions.report.xml">
<field name="name">Cutoff Prepaid ODS</field>
<field name="model">account.cutoff</field>
<field name="report_name">account.cutoff.prepaid.ods</field>
<field name="report_type">aeroo</field>
<field name="in_format">oo-ods</field>
<field name="report_rml">account_cutoff_prepaid_ods/cutoff_prepaid.ods</field>
<field name="parser_state">default</field>
<field name="tml_source">file</field>
<field name="out_format" ref="report_aeroo.report_mimetypes_ods_ods"/>
</record>
<record id="account_cutoff_prepaid_ods_button" model="ir.values">
<field name="name">Cutoff Prepaid ODS</field>
<field name="model">account.cutoff</field>
<field name="key2">client_print_multi</field>
<field name="value" eval="'ir.actions.report.xml,%d'%account_cutoff_prepaid_ods"/>
</record>
</data>
</openerp>

View File

@@ -1,24 +0,0 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# Account Direct Debit Autogenerate module for Odoo
# Copyright (C) 2015 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 account_invoice

View File

@@ -1,47 +0,0 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# Account Direct Debit Autogenerate module for Odoo
# Copyright (C) 2015 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': 'Account Direct Debit Autogenerate',
'version': '0.1',
'category': 'Accounting & Finance',
'license': 'AGPL-3',
'summary': 'Auto-generate direct debit order on invoice validation',
'description': """
Account Direct Debit Autogenerate
=================================
With this module, when you validate a customer invoice whose payment mode is SEPA Direct Debit :
* if a draft Direct Debit order for SEPA Direct Debit already exists, a new payment line is added to it for the invoice,
* otherwise, a new SEPA Direct Debit order is created for this 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_banking_sepa_direct_debit', 'account_payment_partner'],
'data': [],
'installable': False,
}

View File

@@ -1,107 +0,0 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# Account Direct Debit Autogenerate module for Odoo
# Copyright (C) 2015 Akretion (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 openerp import models, api, _
from openerp.exceptions import Warning
import logging
logger = logging.getLogger(__name__)
class AccountInvoice(models.Model):
_inherit = 'account.invoice'
@api.model
def _prepare_payment_order(self, invoice):
vals = {
'mode': invoice.payment_mode_id.id,
'payment_order_type': 'debit',
}
return vals
@api.model
def _prepare_payment_line(self, move_line, payment_order):
assert move_line.invoice, 'The move line must be linked to an invoice'
if not move_line.invoice.mandate_id:
raise Warning(
_('Missing Mandate on Invoice %s') % move_line.invoice.number)
vals = {
'order_id': payment_order.id,
'move_line_id': move_line.id,
'partner_id': move_line.partner_id.id,
'amount_currency': move_line.debit,
'communication': move_line.invoice.number.replace('/', ''),
'state': 'structured',
'date': move_line.date_maturity,
'currency': move_line.invoice.currency_id.id,
'mandate_id': move_line.invoice.mandate_id.id,
'bank_id': move_line.invoice.mandate_id.partner_bank_id.id,
}
return vals
@api.multi
def invoice_validate(self):
'''Create Direct debit payment order on invoice validation or update
an existing draft Direct Debit pay order'''
res = super(AccountInvoice, self).invoice_validate()
poo = self.env['payment.order']
plo = self.env['payment.line']
for invoice in self:
if (
invoice.type == 'out_invoice'
and invoice.payment_mode_id
and invoice.payment_mode_id.type
and invoice.payment_mode_id.type.code
and invoice.payment_mode_id.type.code.
startswith('pain.008.001.')):
payorders = poo.search([
('state', '=', 'draft'),
('payment_order_type', '=', 'debit'),
('mode', '=', invoice.payment_mode_id.id),
# mode is attached to company
])
if payorders:
payorder = payorders[0]
payorder_type = _('existing')
else:
payorder_vals = self._prepare_payment_order(invoice)
payorder = poo.create(payorder_vals)
payorder_type = _('new')
logger.info(
'New Direct Debit Order created %s'
% payorder.reference)
move_lines = [
line for line in invoice.move_id.line_id
if line.account_id == invoice.account_id]
for move_line in move_lines:
if not invoice.mandate_id:
raise Warning(
_("Missing Mandate on invoice %s")
% invoice.number)
# add payment line
pl_vals = self._prepare_payment_line(move_line, payorder)
pl = plo.create(pl_vals)
invoice.message_post(
_("A new payment line %s has been automatically "
"created on the %s direct debit order %s")
% (pl.name, payorder_type, payorder.reference))
return res

View File

@@ -1,3 +0,0 @@
# -*- coding: utf-8 -*-
from . import account_fiscal_position

View File

@@ -1,26 +0,0 @@
# -*- coding: utf-8 -*-
# © 2016-2017 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{
'name': 'Account Fiscal Position Payable Receivable',
'version': '10.0.1.0.0',
'category': 'Accounting & Finance',
'license': 'AGPL-3',
'summary': 'Configure payable/receivable accounts on fiscal positions',
'description': """
Account Fiscal Position Payable Receivable
==========================================
This module allows to configure a special *Partner Receivable Account* and a special *Partner Payable Account* on fiscal positions. This is used in the onchange of the fiscal position of partners.
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_fiscal_position_view.xml',
],
'installable': True,
}

View File

@@ -1,35 +0,0 @@
# -*- coding: utf-8 -*-
# © 2016-2017 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import models, fields, api
class AccountFiscalPosition(models.Model):
_inherit = 'account.fiscal.position'
receivable_account_id = fields.Many2one(
'account.account', string='Partner Receivable Account',
company_dependent=True, domain=[('internal_type', '=', 'receivable')])
payable_account_id = fields.Many2one(
'account.account', string='Partner Payable Account',
company_dependent=True, domain=[('internal_type', '=', 'payable')])
class ResPartner(models.Model):
_inherit = 'res.partner'
@api.onchange('property_account_position_id')
def fiscal_position_receivable_payable_change(self):
fp = self.property_account_position_id
ipo = self.env['ir.property']
if fp.receivable_account_id:
self.property_account_receivable_id = fp.receivable_account_id
else:
self.property_account_receivable_id = ipo.get(
'property_account_receivable_id', 'res.partner')
if fp.payable_account_id:
self.property_account_payable_id = fp.payable_account_id
else:
self.property_account_payable_id = ipo.get(
'property_account_payable_id', 'res.partner')

View File

@@ -1,23 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
© 2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<odoo>
<record id="view_account_position_form" model="ir.ui.view">
<field name="name">receivable_payable.fiscal_position_form</field>
<field name="model">account.fiscal.position</field>
<field name="inherit_id" ref="account.view_account_position_form" />
<field name="arch" type="xml">
<field name="company_id" position="after">
<field name="receivable_account_id"/>
<field name="payable_account_id"/>
</field>
</field>
</record>
</odoo>

View File

@@ -1,4 +0,0 @@
# -*- coding: utf-8 -*-
from . import account_invoice
from . import account_invoice_report

View File

@@ -1,24 +0,0 @@
# -*- coding: utf-8 -*-
# © 2015-2017 Akretion (http://www.akretion.com)
# @author Alexis de Lattre <alexis.delattre@akretion.com>
{
'name': 'Account Invoice Margin',
'version': '10.0.1.0.0',
'category': 'Accounting & Finance',
'license': 'AGPL-3',
'summary': 'Copy standard price on invoice line and compute margins',
'description': """
This module copies the field *standard_price* of the product on the invoice line when the invoice line is created. The allows the computation of the margin of the invoice.
This module has been written by Alexis de Lattre from Akretion
<alexis.delattre@akretion.com>.
""",
'author': 'Akretion',
'website': 'http://www.akretion.com',
'depends': ['account'],
'data': [
'account_invoice_view.xml',
],
'installable': True,
}

View File

@@ -1,149 +0,0 @@
# -*- coding: 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).
from odoo import models, fields, api
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
standard_price_inv_cur =\
inv.company_id.currency_id.with_context(
date=inv.date_invoice).compute(
il.standard_price_company_currency,
inv.currency_id)
margin_inv_cur =\
il.price_subtotal - il.quantity * standard_price_inv_cur
margin_comp_cur = inv.currency_id.with_context(
date=inv.date_invoice).compute(
margin_inv_cur, inv.company_id.currency_id)
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:
std_price = self.env['product.uom']._compute_price(
pp.uom_id.id, std_price, inv_uom_id)
vals['standard_price_company_currency'] = std_price
return super(AccountInvoiceLine, self).create(vals)
@api.multi
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['product.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',
readonly=True, compute='_compute_margin', store=True,
currency_field='currency_id')
margin_company_currency = fields.Monetary(
string='Margin in Company Currency',
readonly=True, compute='_compute_margin', store=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):
for inv in self:
margin_inv_cur = 0.0
margin_comp_cur = 0.0
if inv.type in ('out_invoice', 'out_refund'):
for il in inv.invoice_line_ids:
margin_inv_cur += il.margin_invoice_currency
margin_comp_cur += il.margin_company_currency
inv.margin_invoice_currency = margin_inv_cur
inv.margin_company_currency = margin_comp_cur

View File

@@ -1,62 +0,0 @@
# -*- coding: utf-8 -*-
# Copyright 2018 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
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', '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'],
'product.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):
context = dict(self._context or {})
user_currency_id = self.env.user.company_id.currency_id
currency_rate_id = self.env['res.currency.rate'].search([
('rate', '=', 1),
'|',
('company_id', '=', self.env.user.company_id.id),
('company_id', '=', False)], limit=1)
base_currency_id = currency_rate_id.currency_id
ctx = context.copy()
for record in self:
ctx['date'] = record.date
record.user_currency_margin = base_currency_id.with_context(
ctx).compute(record.margin, user_currency_id)
# TODO check for refunds
def _sub_select(self):
select_str = super(AccountInvoiceReport, self)._sub_select()
select_str += ", SUM(ail.margin_company_currency) AS margin"
return select_str
def _select(self):
select_str = super(AccountInvoiceReport, self)._select()
select_str += ", sub.margin AS margin"
return select_str

View File

@@ -1,49 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
© 2015-2017 Akretion (http://www.akretion.com/)
@author: Alexis de Lattre <alexis.delattre@akretion.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<odoo>
<record id="view_invoice_line_form" model="ir.ui.view">
<field name="name">margin.account.invoice.line.form</field>
<field name="model">account.invoice.line</field>
<field name="inherit_id" ref="account.view_invoice_line_form"/>
<field name="arch" type="xml">
<field name="company_id" position="after">
<field name="standard_price_company_currency"
groups="base.group_no_one"/>
<field name="standard_price_invoice_currency"
widget="monetary"
options="{'currency_field': 'currency_id'}"
groups="base.group_no_one"/>
<field name="margin_invoice_currency"
groups="base.group_no_one"/>
<field name="margin_company_currency"
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>
</field>
</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" groups="base.group_no_one"/>
<field name="margin_company_currency"
groups="base.group_no_one"/>
</field>
</field>
</record>
</odoo>

View File

@@ -1 +0,0 @@
# -*- coding: utf-8 -*-

View File

@@ -1,26 +0,0 @@
# -*- coding: utf-8 -*-
# Copyright 2018 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': 'partner_address_street3 / account_invoice_transmit_method compat.',
'version': '10.0.0.1.0',
'category': 'Partner',
'license': 'AGPL-3',
'summary': 'Compatibility between partner_address_street3 and account_invoice_transmit_method',
'description': """
Glue module between partner_address_street3 and account_invoice_transmit_method
===============================================================================
Stupid technical module to workaround an Odoo framework limitation about the inherit of the context attribute in a view.
""",
'author': 'Akretion',
'website': 'http://www.akretion.com',
'depends': ['partner_address_street3', 'account_invoice_transmit_method'],
'data': [
'partner_view.xml',
],
'installable': True,
'auto_install': True,
}

View File

@@ -1,23 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2018 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<odoo>
<record id="view_partner_form" model="ir.ui.view">
<field name="name">Compatibility partner_address_street3 / account_invoice_transmit_method</field>
<field name="model">res.partner</field>
<field name="inherit_id" ref="base.view_partner_form"/>
<field name="priority">1000</field>
<field name="arch" type="xml">
<field name="child_ids" position="attributes">
<attribute name="context">{'default_parent_id': active_id, 'default_street': street, 'default_street2': street2, 'default_city': city, 'default_state_id': state_id, 'default_zip': zip, 'default_country_id': country_id, 'default_supplier': supplier, 'default_customer': customer, 'default_lang': lang, 'default_customer_invoice_transmit_method_code': customer_invoice_transmit_method_code, 'default_supplier_invoice_transmit_method_code': supplier_invoice_transmit_method_code, 'default_street3': street3}</attribute>
</field>
</field>
</record>
</odoo>

View File

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

View File

@@ -1,37 +0,0 @@
# -*- coding: utf-8 -*-
# © 2017 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
# Copyright 2018 Camptocamp
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{
'name': 'Account Invoice Update Wizard',
'version': '8.0.1.0.0',
'category': 'Accounting & Finance',
'license': 'AGPL-3',
'summary': 'Wizard to update non-legal fields of an open/paid invoice',
'description': """
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
""",
'author': 'Akretion',
'website': 'http://www.akretion.com',
'depends': ['account'],
'data': [
'wizard/account_invoice_update_view.xml',
'views/account_invoice.xml',
],
'installable': True,
}

View File

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

View File

@@ -1,198 +0,0 @@
# -*- coding: utf-8 -*-
# Copyright 2018 Camptocamp
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo.tests.common import TransactionCase
from odoo.exceptions import UserError
class TestAccountInvoiceUpdateWizard(TransactionCase):
def setUp(self):
super(TestAccountInvoiceUpdateWizard, self).setUp()
self.customer12 = self.env.ref('base.res_partner_12')
self.product16 = self.env.ref('product.product_product_16')
self.product24 = self.env.ref('product.product_product_24')
uom_unit = self.env.ref('product.product_uom_categ_unit')
self.invoice1 = self.env['account.invoice'].create({
'name': 'Test invoice',
'partner_id': self.customer12.id,
})
self.inv_line1 = self.env['account.invoice.line'].create({
'invoice_id': self.invoice1.id,
'name': "Line1",
'product_id': self.product16.id,
'product_uom_id': uom_unit.id,
'account_id': self.invoice1.account_id.id,
'price_unit': 42.0,
})
self.inv_line2 = self.env['account.invoice.line'].create({
'invoice_id': self.invoice1.id,
'name': "Line2",
'product_id': self.product24.id,
'product_uom_id': uom_unit.id,
'account_id': self.invoice1.account_id.id,
'price_unit': 1111.1,
})
self.aa1 = self.env.ref('analytic.analytic_partners_camp_to_camp')
self.aa2 = self.env.ref('analytic.analytic_nebula')
self.atag1 = self.env.ref('analytic.tag_contract')
self.atag2 = self.env['account.analytic.tag'].create({
'name': u'',
})
def create_wizard(self):
UpdateWizard = self.env['account.invoice.update'].with_context(
active_model='account.invoice',
active_id=self.invoice1.id)
self.wiz = UpdateWizard.create({})
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()
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()
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()
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()
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()
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()
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()
wiz_line = self.wiz.line_ids.filtered(
lambda rec: rec.invoice_line_id == self.inv_line1)
wiz_line.account_analytic_id = False
self.wiz.run()
related_ml = self.invoice1.move_id.line_ids.filtered(
lambda rec: rec.product_id == self.product16)
self.assertFalse(related_ml.analytic_account_id)
self.assertFalse(related_ml.analytic_line_ids)

View File

@@ -1,29 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
© 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_cancel" position="before">
<button name="%(account_invoice_update_action)d" type="action" 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_cancel" position="before">
<button name="%(account_invoice_update_action)d" type="action" string="Update Invoice" states="open,paid" groups="account.group_account_invoice"/>
</button>
</field>
</record>
</odoo>

View File

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

View File

@@ -1,308 +0,0 @@
# -*- coding: utf-8 -*-
# © 2017 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
# Copyright 2018 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,
}])
return res
@api.model
def default_get(self, fields_list):
res = super(AccountInvoiceUpdate, self).default_get(fields_list)
assert self._context.get('active_model') == 'account.invoice',\
'active_model should be account.invoice'
inv = self.env['account.invoice'].browse(self._context['active_id'])
res = self._prepare_default_get(inv)
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.iteritems():
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(_(
'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)
quantity = fields.Float(
string='Quantity', digits=dp.get_precision('Product Unit of Measure'),
readonly=True)
price_subtotal = fields.Float(
string='Amount', readonly=True, digits=dp.get_precision('Account'))
account_analytic_id = fields.Many2one(
'account.analytic.account', string='Analytic Account')
analytic_tag_ids = fields.Many2many(
'account.analytic.tag', string='Analytic Tags')

View File

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

View File

@@ -1,3 +0,0 @@
# -*- coding: utf-8 -*-
from . import wizard

View File

@@ -1,25 +0,0 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2016-2018 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': 'Account Move Line Filter Wizard',
'version': '10.0.1.0.0',
'category': 'Accounting',
'license': 'AGPL-3',
'summary': 'Easy and fast access to the details of an account',
'description': """
Account Move Line Filter Wizard
===============================
This module adds a wizard in Accounting > ... >
This module has been written by Alexis de Lattre from Akretion <alexis.delattre@akretion.com>.
""",
'author': 'Akretion',
'website': 'http://www.akretion.com',
'depends': ['account_usability'],
'data': ['wizard/account_move_line_filter_view.xml'],
'installable': True,
}

View File

@@ -1,3 +0,0 @@
# -*- coding: utf-8 -*-
from . import account_move_line_filter

View File

@@ -1,46 +0,0 @@
# -*- coding: utf-8 -*-
# Copyright 2016-2018 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
class AccountMoveLineFilterWizard(models.TransientModel):
_name = 'account.move.line.filter.wizard'
_description = 'Wizard for easy and fast access to account move lines'
partner_id = fields.Many2one(
'res.partner', string='Partner', domain=[('parent_id', '=', False)])
account_id = fields.Many2one(
'account.account', string='Account',
domain=[('deprecated', '=', False)], required=True)
account_reconcile = fields.Boolean(
related='account_id.reconcile', readonly=True)
reconcile = fields.Selection([
('unreconciled', 'Unreconciled or Partially Reconciled'),
('reconciled', 'Fully Reconciled'),
# ('partial_reconciled', 'Partially Reconciled'),
], string='Reconciliation Filter')
@api.onchange('partner_id')
def partner_id_change(self):
if self.partner_id:
if self.partner_id.customer:
self.account_id =\
self.partner_id.property_account_receivable_id.id
else:
self.account_id =\
self.partner_id.property_account_payable_id.id
def go(self):
self.ensure_one()
action = self.env['ir.actions.act_window'].for_xml_id(
'account', 'action_account_moves_all_a')
action['context'] = {'search_default_account_id': [self.account_id.id]}
if self.partner_id:
action['context']['search_default_partner_id'] =\
[self.partner_id.id]
if self.reconcile:
action['context']['search_default_%s' % self.reconcile] = True
return action

View File

@@ -1,44 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2016-2018 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="account_move_line_filter_wizard_form" model="ir.ui.view">
<field name="name">account_move_line_filter_wizard_form</field>
<field name="model">account.move.line.filter.wizard</field>
<field name="arch" type="xml">
<form string="Account Move Lines">
<group name="filters" string="Filters">
<field name="partner_id"/>
<field name="account_id"/>
<field name="account_reconcile" invisible="1"/>
<field name="reconcile"
attrs="{'invisible': [('account_reconcile', '!=', True)]}"/>
</group>
<footer>
<button type="object" name="go" string="Go" class="btn-primary"/>
<button special="cancel" string="Cancel" class="btn-default"/>
</footer>
</form>
</field>
</record>
<record id="account_move_line_filter_wizard_action" model="ir.actions.act_window">
<field name="name">Journal Items of Account</field>
<field name="res_model">account.move.line.filter.wizard</field>
<field name="view_mode">form</field>
<field name="target">new</field>
</record>
<menuitem id="account_move_line_filter_wizard_menu"
action="account_move_line_filter_wizard_action"
parent="account.menu_finance_entries"
sequence="-1"/>
</odoo>

View File

@@ -1,3 +0,0 @@
# -*- coding: utf-8 -*-
from . import account_move_line

View File

@@ -1,44 +0,0 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Account Move Line Start End Dates XLS module for Odoo
# Copyright (C) 2014-2016 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': 'Account Move Line Start End Dates XLS',
'version': '0.1',
'category': 'Accounting & Finance',
'license': 'AGPL-3',
'summary': 'Adds start and end dates in the XLS export of the move lines',
'description': """
Account Move Line Start End Dates XLS
=====================================
This module adds *Start Date* and *End Date* in the XLS export of the account move lines.
This module has been written by Alexis de Lattre from Akretion
<alexis.delattre@akretion.com>.
""",
'author': 'Akretion',
'website': 'http://www.akretion.com/',
'depends': ['account_cutoff_prepaid', 'account_move_line_report_xls'],
'data': [],
'installable': False,
}

View File

@@ -1,66 +0,0 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Account Move Line Start End Dates XLS module for Odoo
# Copyright (C) 2014-2016 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/>.
#
##############################################################################
import xlwt
from openerp import models, api
from openerp.addons.report_xls.utils import _render
from openerp.addons.report_xls.report_xls import report_xls
class AccountMoveLine(models.Model):
_inherit = 'account.move.line'
@api.model
def _report_xls_fields(self):
res = super(AccountMoveLine, self)._report_xls_fields()
return res + ['start_date', 'end_date']
@api.model
def _report_xls_template(self):
res = super(AccountMoveLine, self)._report_xls_template()
bc = '22'
aml_cell_style_date = xlwt.easyxf(
'borders: left thin, right thin, top thin, bottom thin, '
'left_colour %s, right_colour %s, top_colour %s, '
'bottom_colour %s; align: horz left;'
% (bc, bc, bc, bc), num_format_str=report_xls.date_format)
res.update({
'start_date': {
'header': [1, 13, 'text', _render("_('Start Date')")],
'lines': [1, 0, _render(
"line.start_date and line.start_date != 'False' and "
"'date' or 'text'"), _render(
"line.start_date and line.start_date != 'False' and "
"datetime.strptime(line.start_date, '%Y-%m-%d') or None"),
None, aml_cell_style_date],
'totals': [1, 0, 'text', None]},
'end_date': {
'header': [1, 13, 'text', _render("_('End Date')")],
'lines': [1, 0, _render(
"line.end_date and line.end_date != 'False' and "
"'date' or 'text'"), _render(
"line.end_date and line.end_date != 'False' and "
"datetime.strptime(line.end_date, '%Y-%m-%d') or None"),
None, aml_cell_style_date],
'totals': [1, 0, 'text', None]},
})
return res

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -1 +0,0 @@
# -*- coding: utf-8 -*-

View File

@@ -1,25 +0,0 @@
# -*- coding: utf-8 -*-
# © 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).
{
'name': 'Account No Analytic Tags',
'version': '10.0.1.0.0',
'category': 'Accounting & Finance',
'license': 'AGPL-3',
'summary': 'No Analytic Tags in Accounting',
'description': """
Account No Analytic Tags
========================
This module hides analytic tags on invoices and move lines.
This module has been written by Alexis de Lattre from Akretion <alexis.delattre@akretion.com>.
""",
'author': 'Akretion',
'website': 'http://www.akretion.com',
'depends': ['account', 'base_usability'],
'data': ['account_view.xml'],
'installable': True,
}

View File

@@ -1,61 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
© 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>
<!-- INVOICE -->
<record id="invoice_supplier_form" model="ir.ui.view">
<field name="name">account_no_analytic_tags.supplier.invoice.form</field>
<field name="model">account.invoice</field>
<field name="inherit_id" ref="account.invoice_supplier_form"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='invoice_line_ids']/tree/field[@name='analytic_tag_ids']" position="attributes">
<attribute name="invisible">1</attribute>
</xpath>
</field>
</record>
<record id="invoice_form" model="ir.ui.view">
<field name="name">account_no_analytic_tags.invoice.form</field>
<field name="model">account.invoice</field>
<field name="inherit_id" ref="account.invoice_form"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='invoice_line_ids']/tree/field[@name='analytic_tag_ids']" position="attributes">
<attribute name="invisible">1</attribute>
</xpath>
</field>
</record>
<!-- ACCOUNT MOVE LINE -->
<record id="view_move_line_form" model="ir.ui.view">
<field name="name">account_no_analytic_tags.move.line.form</field>
<field name="model">account.move.line</field>
<field name="inherit_id" ref="account.view_move_line_form"/>
<field name="arch" type="xml">
<field name="analytic_tag_ids" position="attributes">
<attribute name="invisible">1</attribute>
</field>
</field>
</record>
<!-- ANALYTIC ACCOUNT -->
<record id="view_account_analytic_account_form" model="ir.ui.view">
<field name="name">account_no_analytic_tags.analytic.account.form</field>
<field name="model">account.analytic.account</field>
<field name="inherit_id" ref="analytic.view_account_analytic_account_form"/>
<field name="arch" type="xml">
<field name="tag_ids" position="attributes">
<attribute name="invisible">1</attribute>
</field>
</field>
</record>
<record id="account.account_analytic_tag_menu" model="ir.ui.menu">
<field name="groups_id" eval="[(6, 0, [ref('base_usability.group_nobody')])]"/>
</record>
</odoo>

View File

@@ -1,6 +0,0 @@
# -*- coding: utf-8 -*-
from . import account
from . import account_invoice_report
from . import partner
from . import wizard

View File

@@ -1,47 +0,0 @@
# -*- coding: 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).
{
'name': 'Account Usability',
'version': '10.0.1.0.0',
'category': 'Accounting & Finance',
'license': 'AGPL-3',
'summary': 'Small usability enhancements in account module',
'description': """
Account Usability
=================
The usability enhancements include:
* show the supplier invoice number in the tree view of supplier invoices
* add an *Overdue* filter on invoice search view (this feature was previously located in te module *account_invoice_overdue_filter*)
* Increase the default limit of 80 lines in account move and account move line view.
* Fast search on *Reconcile Ref* for account move line.
* disable reconciliation "guessing"
Together with this module, I recommend the use of the following modules:
* account_invoice_supplier_ref_unique (OCA project account-invoicing)
* account_move_line_no_default_search (OCA project account-financial-tools)
* invoice_fiscal_position_update (OCA project account-invoicing)
This module has been written by Alexis de Lattre from Akretion <alexis.delattre@akretion.com>.
""",
'author': 'Akretion',
'website': 'http://www.akretion.com',
'depends': [
'account',
'base_view_inheritance_extension',
'base_usability', # needed only to access base_usability.group_nobody
# in v12, I may create a module only for group_nobody
],
'data': [
'account_view.xml',
'account_report.xml',
'account_invoice_report_view.xml',
'partner_view.xml',
'product_view.xml',
'wizard/account_invoice_mark_sent_view.xml',
],
'installable': True,
}

View File

@@ -1,618 +0,0 @@
# -*- coding: 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).
from odoo import models, fields, api, _
from odoo.tools import float_compare, float_is_zero
from odoo.tools.misc import formatLang
from odoo.exceptions import UserError, ValidationError
from odoo import SUPERUSER_ID
import logging
logger = logging.getLogger(__name__)
class AccountInvoice(models.Model):
_inherit = 'account.invoice'
origin = fields.Char(track_visibility='onchange')
reference = fields.Char(track_visibility='onchange')
sent = fields.Boolean(track_visibility='onchange')
date_invoice = fields.Date(track_visibility='onchange')
date_due = fields.Date(track_visibility='onchange')
payment_term_id = fields.Many2one(track_visibility='onchange')
account_id = fields.Many2one(track_visibility='onchange')
journal_id = fields.Many2one(track_visibility='onchange')
partner_bank_id = fields.Many2one(track_visibility='onchange')
fiscal_position_id = fields.Many2one(track_visibility='onchange')
amount_total = fields.Monetary(track_visibility='onchange')
# for those fields, the 'account' module sets track_visibility='always':
partner_id = fields.Many2one(track_visibility='onchange')
currency_id = fields.Many2one(track_visibility='onchange')
type = fields.Selection(track_visibility='onchange')
amount_untaxed = fields.Monetary(track_visibility='onchange')
# I want to see the number of cancelled invoice in chatter
move_id = fields.Many2one(track_visibility='onchange')
# for invoice report
has_discount = fields.Boolean(
compute='_compute_has_discount', readonly=True)
# has_attachment is useful for those who use attachment to archive
# supplier invoices. It allows them to find supplier invoices
# that don't have any attachment
has_attachment = fields.Boolean(
compute='_compute_has_attachment',
search='_search_has_attachment', readonly=True)
def _compute_has_discount(self):
prec = self.env['decimal.precision'].precision_get('Discount')
for inv in self:
has_discount = False
for line in inv.invoice_line_ids:
if not float_is_zero(line.discount, precision_digits=prec):
has_discount = True
break
inv.has_discount = has_discount
def _compute_has_attachment(self):
iao = self.env['ir.attachment']
for inv in self:
if iao.search([
('res_model', '=', 'account.invoice'),
('res_id', '=', inv.id),
('type', '=', 'binary'),
('company_id', '=', inv.company_id.id)], limit=1):
inv.has_attachment = True
else:
inv.has_attachment = False
def _search_has_attachment(self, operator, value):
att_inv_ids = {}
if operator == '=':
search_res = self.env['ir.attachment'].search_read([
('res_model', '=', 'account.invoice'),
('type', '=', 'binary'),
('res_id', '!=', False)], ['res_id'])
for att in search_res:
att_inv_ids[att['res_id']] = True
res = [('id', value and 'in' or 'not in', att_inv_ids.keys())]
return res
# when you have an invoice created from a lot of sale orders, the 'name'
# field is very large, which makes the name_get() of that invoice very big
# which screws-up the form view of that invoice because of the link at the
# top of the screen
# That's why we have to cut the name_get() when it's too long
def name_get(self):
old_res = super(AccountInvoice, self).name_get()
res = []
for old_re in old_res:
name = old_re[1]
if name and len(name) > 100:
# nice cut
name = u'%s ...' % ', '.join(name.split(', ')[:3])
# if not enough, hard cut
if len(name) > 120:
name = u'%s ...' % old_re[1][:120]
res.append((old_re[0], name))
return res
# I really hate to see a "/" in the 'name' field of the account.move.line
# generated from customer invoices linked to the partners' account because:
# 1) the label of an account move line is an important field, we can't
# write a rubbish '/' in it !
# 2) the 'name' field of the account.move.line is used in the overdue
# letter, and '/' is not meaningful for our customer !
@api.multi
def action_move_create(self):
res = super(AccountInvoice, self).action_move_create()
for inv in self:
self._cr.execute(
"UPDATE account_move_line SET name= "
"CASE WHEN name='/' THEN %s "
"ELSE %s||' - '||name END "
"WHERE move_id=%s", (inv.number, inv.number, inv.move_id.id))
self.invalidate_cache()
return res
def delete_lines_qty_zero(self):
lines = self.env['account.invoice.line'].search([
('invoice_id', 'in', self.ids), ('quantity', '=', 0)])
lines.unlink()
return True
def fix_invoice_attachment_filename(self):
# This script is designed to fix attachment of invoices
# badly generated by Odoo v8. I found this problem in Nov 2018 at
# Encres Dubuit when investigating a bug where Odoo would create a
# new attachment when printing an old invoice that already had the
# PDF of the invoice as attachment
logger.info('START fix customer invoice attachment filename')
# Run this script as admin to fix problem in all companies
self = self.sudo()
attachs = self.env['ir.attachment'].search([
('res_model', '=', 'account.invoice'),
('res_id', '!=', False),
('type', '=', 'binary'),
('name', '=like', 'INV%.pdf'),
('datas_fname', '=like', 'INV%.pdf.pdf')])
for attach in attachs:
inv = self.browse(attach.res_id)
if inv.type in ('out_invoice', 'out_refund'):
attach.datas_fname = attach.name
logger.info(
'Fixed field datas_fname of attachment ID %s name %s',
attach.id, attach.name)
logger.info('END fix customer invoice attachment filename')
class AccountInvoiceLine(models.Model):
_inherit = 'account.invoice.line'
# In the 'account' module, we have related stored field for:
# company_id, partner_id, currency_id
invoice_type = fields.Selection(
related='invoice_id.type', store=True, readonly=True)
date_invoice = fields.Date(
related='invoice_id.date_invoice', store=True, readonly=True)
commercial_partner_id = fields.Many2one(
related='invoice_id.partner_id.commercial_partner_id',
store=True, readonly=True, compute_sudo=True)
state = fields.Selection(
related='invoice_id.state', store=True, readonly=True,
string='Invoice State')
invoice_number = fields.Char(
related='invoice_id.move_id.name', store=True, readonly=True,
string='Invoice Number')
class AccountJournal(models.Model):
_inherit = 'account.journal'
@api.multi
@api.depends(
'name', 'currency_id', 'company_id', 'company_id.currency_id', 'code')
def name_get(self):
res = []
if self._context.get('journal_show_code_only'):
for journal in self:
res.append((journal.id, journal.code))
return res
else:
for journal in self:
currency = journal.currency_id or\
journal.company_id.currency_id
name = "[%s] %s (%s)" % (
journal.code, journal.name, currency.name)
res.append((journal.id, name))
return res
# Also search on start of 'code', not only on 'name'
@api.model
def name_search(
self, name='', args=None, operator='ilike', limit=80):
if args is None:
args = []
if name:
jrls = self.search(
[('code', '=ilike', name + '%')] + args, limit=limit)
if jrls:
return jrls.name_get()
return super(AccountJournal, self).name_search(
name=name, args=args, operator=operator, limit=limit)
@api.constrains('default_credit_account_id', 'default_debit_account_id')
def _check_account_type_on_bank_journal(self):
bank_acc_type = self.env.ref('account.data_account_type_liquidity')
for jrl in self:
if jrl.type in ('bank', 'cash'):
if (
jrl.default_debit_account_id and
jrl.default_debit_account_id.user_type_id !=
bank_acc_type):
raise ValidationError(_(
"On journal '%s', the default debit account '%s' "
"should be configured with Type = 'Bank and Cash'.")
% (jrl.display_name,
jrl.default_debit_account_id.display_name))
if (
jrl.default_credit_account_id and
jrl.default_credit_account_id.user_type_id !=
bank_acc_type):
raise ValidationError(_(
"On journal '%s', the default credit account '%s' "
"should be configured with Type = 'Bank and Cash'.")
% (jrl.display_name,
jrl.default_credit_account_id.display_name))
class AccountAccount(models.Model):
_inherit = 'account.account'
@api.multi
def name_get(self):
if self._context.get('account_account_show_code_only'):
res = []
for record in self:
res.append((record.id, record.code))
return res
else:
return super(AccountAccount, self).name_get()
# https://github.com/odoo/odoo/issues/23040
def fix_bank_account_types(self):
aao = self.env['account.account']
companies = self.env['res.company'].search([])
if len(companies) > 1 and self.env.user.id != SUPERUSER_ID:
raise UserError(
"In multi-company setups, you should run this "
"script as admin user")
logger.info("START the script 'fix bank and cash account types'")
bank_type = self.env.ref('account.data_account_type_liquidity')
asset_type = self.env.ref('account.data_account_type_current_assets')
journals = self.env['account.journal'].search(
[('type', 'in', ('bank', 'cash'))], order='company_id')
journal_accounts_bank_type = aao
for journal in journals:
for account in [
journal.default_credit_account_id,
journal.default_debit_account_id]:
if account:
if account.user_type_id != bank_type:
account.user_type_id = bank_type.id
logger.info(
'Company %s: Account %s updated to Bank '
'and Cash type',
account.company_id.display_name, account.code)
if account not in journal_accounts_bank_type:
journal_accounts_bank_type += account
accounts = aao.search([
('user_type_id', '=', bank_type.id)], order='company_id, code')
for account in accounts:
if account not in journal_accounts_bank_type:
account.user_type_id = asset_type.id
logger.info(
'Company %s: Account %s updated to Current Asset type',
account.company_id.display_name, account.code)
logger.info("END of the script 'fix bank and cash account types'")
return True
@api.model
def create_account_groups(self, level=2, name_prefix=u'Comptes '):
'''Should be launched by a script. Make sure the account_group module is installed
(the account_usability module doesn't depend on it currently'''
assert level >= 1
assert isinstance(level, int)
companies = self.env['res.company'].search([])
if len(companies) > 1:
logger.info(
'Multi-company detected: running script create_account_groups '
'as admin')
self = self.sudo()
ago = self.env['account.group']
groups = ago.search([])
if groups:
raise UserError(_("Some account groups already exists"))
accounts = self.search([])
struct = {'childs': {}}
for account in accounts:
assert len(account.code) > level
n = 1
parent = struct
gparent = False
while n <= level:
group_code = account.code[:n]
if group_code not in parent['childs']:
new_group = ago.create({
'name': u'%s%s' % (name_prefix or '', group_code),
'code_prefix': group_code,
'parent_id': gparent and gparent.id or False,
})
parent['childs'][group_code] = {'obj': new_group, 'childs': {}}
parent = parent['childs'][group_code]
gparent = parent['obj']
n += 1
account.group_id = gparent.id
class AccountAnalyticAccount(models.Model):
_inherit = 'account.analytic.account'
@api.multi
def name_get(self):
if self._context.get('analytic_account_show_code_only'):
res = []
for record in self:
res.append((record.id, record.code or record.name))
return res
else:
return super(AccountAnalyticAccount, self).name_get()
_sql_constraints = [(
'code_company_unique',
'unique(code, company_id)',
'An analytic account with the same code already '
'exists in the same company!')]
class AccountMove(models.Model):
_inherit = 'account.move'
default_move_line_name = fields.Char(
string='Default Label', states={'posted': [('readonly', True)]})
# By default, we can still modify "ref" when account move is posted
# which seems a bit lazy for me...
ref = fields.Char(states={'posted': [('readonly', True)]})
date = fields.Date(copy=False)
default_account_id = fields.Many2one(
related='journal_id.default_debit_account_id', readonly=True)
default_credit = fields.Float(
compute='_compute_default_credit_debit', readonly=True)
default_debit = fields.Float(
compute='_compute_default_credit_debit', readonly=True)
@api.depends('line_ids.credit', 'line_ids.debit')
def _compute_default_credit_debit(self):
for move in self:
total_debit = total_credit = default_debit = default_credit = 0.0
for l in move.line_ids:
total_debit += l.debit
total_credit += l.credit
# I could use float_compare, but I don't think it's really needed
# in this context
if total_debit > total_credit:
default_credit = total_debit - total_credit
else:
default_debit = total_credit - total_debit
move.default_credit = default_credit
move.default_debit = default_debit
class AccountMoveLine(models.Model):
_inherit = 'account.move.line'
# Native order:
# _order = "date desc, id desc"
# Problem: when you manually create a journal entry, the
# order of the lines is inverted when you save ! It is quite annoying for
# the user...
_order = "date desc, id asc"
# Update field only to add a string (there is no string in account module)
invoice_id = fields.Many2one(string='Invoice')
date_maturity = fields.Date(copy=False)
account_reconcile = fields.Boolean(
related='account_id.reconcile', readonly=True)
full_reconcile_id = fields.Many2one(string='Full Reconcile')
matched_debit_ids = fields.One2many(string='Partial Reconcile Debit')
matched_credit_ids = fields.One2many(string='Partial Reconcile Credit')
reconcile_string = fields.Char(
compute='_compute_reconcile_string', string='Reconcile', store=True)
@api.onchange('credit')
def _credit_onchange(self):
prec = self.env['decimal.precision'].precision_get('Account')
if (
not float_is_zero(self.credit, precision_digits=prec) and
not float_is_zero(self.debit, precision_digits=prec)):
self.debit = 0
@api.onchange('debit')
def _debit_onchange(self):
prec = self.env['decimal.precision'].precision_get('Account')
if (
not float_is_zero(self.debit, precision_digits=prec) and
not float_is_zero(self.credit, precision_digits=prec)):
self.credit = 0
@api.onchange('currency_id', 'amount_currency')
def _amount_currency_change(self):
prec = self.env['decimal.precision'].precision_get('Account')
if (
self.currency_id and
self.amount_currency and
float_is_zero(self.credit, precision_digits=prec) and
float_is_zero(self.debit, precision_digits=prec)):
date = self.date or None
amount_company_currency = self.currency_id.with_context(
date=date).compute(
self.amount_currency, self.env.user.company_id.currency_id)
precision = self.env['decimal.precision'].precision_get('Account')
if float_compare(
amount_company_currency, 0,
precision_digits=precision) == -1:
self.debit = amount_company_currency * -1
else:
self.credit = amount_company_currency
def show_account_move_form(self):
self.ensure_one()
action = self.env['ir.actions.act_window'].for_xml_id(
'account', 'action_move_line_form')
action.update({
'res_id': self.move_id.id,
'view_id': False,
'views': False,
'view_mode': 'form,tree',
})
return action
@api.depends(
'full_reconcile_id', 'matched_debit_ids', 'matched_credit_ids')
def _compute_reconcile_string(self):
for line in self:
rec_str = False
if line.full_reconcile_id:
rec_str = line.full_reconcile_id.name
else:
rec_str = ', '.join([
'a%d' % pr.id for pr in line.matched_debit_ids + line.matched_credit_ids])
line.reconcile_string = rec_str
class AccountPartialReconcile(models.Model):
_inherit = "account.partial.reconcile"
_rec_name = "id"
def name_get(self):
res = []
for rec in self:
# There is no seq for partial rec, so I simulate one with the ID
# Prefix for full rec: 'A' (upper case)
# Prefix for partial rec: 'a' (lower case)
amount_fmt = formatLang(self.env, rec.amount, currency_obj=rec.company_currency_id)
name = 'a%d (%s)' % (rec.id, amount_fmt)
res.append((rec.id, name))
return res
class AccountBankStatement(models.Model):
_inherit = 'account.bank.statement'
start_date = fields.Date(
compute='_compute_dates', string='Start Date', readonly=True,
store=True)
end_date = fields.Date(
compute='_compute_dates', string='End Date', readonly=True,
store=True)
@api.multi
@api.depends('line_ids.date')
def _compute_dates(self):
for st in self:
dates = [line.date for line in st.line_ids]
st.start_date = dates and min(dates) or False
st.end_date = dates and max(dates) or False
@api.multi
@api.depends('name', 'start_date', 'end_date')
def name_get(self):
res = []
for statement in self:
name = "%s (%s => %s)" % (
statement.name, statement.start_date, statement.end_date)
res.append((statement.id, name))
return res
class AccountBankStatementLine(models.Model):
_inherit = 'account.bank.statement.line'
# Native order is:
# _order = 'statement_id desc, sequence, id desc'
_order = 'statement_id desc, date desc, sequence, id desc'
# Disable guessing for reconciliation
# because my experience with several customers shows that it is a problem
# in the following scenario : move line 'x' has been "guessed" by OpenERP
# to be reconciled with a statement line 'Y' at the end of the bank
# statement, but it is a mistake because it should be reconciled with
# statement line 'B' at the beginning of the bank statement
# When the user is on statement line 'B', he tries to select
# move line 'x', but it can't find it... because it is already "reserved"
# by the guess of OpenERP for statement line 'Y' ! To solve this problem,
# the user must go to statement line 'Y' and unselect move line 'x'
# and then come back on statement line 'B' and select move line 'A'...
# but non super-expert users can't do that because it is impossible to
# figure out that the fact that the user can't find move line 'x'
# is caused by this.
# Set search_reconciliation_proposition to False by default
# TODO: re-write in v10
# def get_data_for_reconciliations(
# self, cr, uid, ids, excluded_ids=None,
# search_reconciliation_proposition=False, context=None):
# # Make variable name shorted for PEP8 !
# search_rec_prop = search_reconciliation_proposition
# return super(AccountBankStatementLine, self).\
# get_data_for_reconciliations(
# cr, uid, ids, excluded_ids=excluded_ids,
# search_reconciliation_proposition=search_rec_prop,
# context=context)
def _prepare_reconciliation_move(self, move_ref):
vals = super(AccountBankStatementLine, self).\
_prepare_reconciliation_move(move_ref)
# By default, ref contains the name of the statement + name of the
# statement line. It causes 2 problems:
# 1) The 'ref' field is too big
# 2) The name of the statement line is already written in the name of
# the move line -> not useful to have the info 2 times
# In the end, I think it's better to just put nothing (we could write
# the name of the statement which has the account number, but it
# doesn't bring any useful info to the accountant)
# The only "good" thing to do would be to have a sequence per
# statement line and write it in this 'ref' field
# But that would required an additionnal field on statement lines
vals['ref'] = False
return vals
@api.multi
def show_account_move(self):
self.ensure_one()
action = self.env['ir.actions.act_window'].for_xml_id(
'account', 'action_move_journal_line')
if self.journal_entry_ids:
action.update({
'views': False,
'view_id': False,
'view_mode': 'form,tree',
'res_id': self.journal_entry_ids[0].id,
})
return action
else:
raise UserError(_(
'No journal entry linked to this bank statement line.'))
class AccountFiscalPosition(models.Model):
_inherit = 'account.fiscal.position'
note = fields.Text(translate=True)
@api.model
def get_fiscal_position_no_partner(
self, company_id=None, vat_subjected=False, country_id=None):
'''This method is inspired by the method get_fiscal_position()
in odoo/addons/account/partner.py : it uses the same algo
but without a real partner.
Returns a recordset of fiscal position, or False'''
domains = [[
('auto_apply', '=', True),
('vat_required', '=', vat_subjected),
('company_id', '=', company_id)]]
if vat_subjected:
domains += [[
('auto_apply', '=', True),
('vat_required', '=', False),
('company_id', '=', company_id)]]
for domain in domains:
if country_id:
fps = self.search(
domain + [('country_id', '=', country_id)], limit=1)
if fps:
return fps[0]
fps = self.search(
domain +
[('country_group_id.country_ids', '=', country_id)],
limit=1)
if fps:
return fps[0]
fps = self.search(
domain +
[('country_id', '=', None), ('country_group_id', '=', None)],
limit=1)
if fps:
return fps[0]
return False
class AccountReconcileModel(models.Model):
_inherit = 'account.reconcile.model'
@api.onchange('name')
def onchange_name(self):
# Do NOT copy by default name on label
# Because it's much better to have the bank statement line label as
# label of the counter-part move line, then the label of the button
assert True # Stupid line of code just to have something...

View File

@@ -1,27 +0,0 @@
# -*- coding: utf-8 -*-
# Copyright 2018 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
class AccountInvoiceReport(models.Model):
_inherit = 'account.invoice.report'
number = fields.Char(string="Number", readonly=True)
def _sub_select(self):
select_str = super(AccountInvoiceReport, self)._sub_select()
select_str += ", ai.number"
return select_str
def _select(self):
select_str = super(AccountInvoiceReport, self)._select()
select_str += ", sub.number"
return select_str
def _group_by(self):
group_by_str = super(AccountInvoiceReport, self)._group_by()
group_by_str += ", ai.number"
return group_by_str

View File

@@ -1,51 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2018 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="account_invoice_report_tree" model="ir.ui.view">
<field name="name">usability.account.invoice.report.tree</field>
<field name="model">account.invoice.report</field>
<field name="arch" type="xml">
<tree string="Invoices Analysis">
<field name="number"/>
<field name="date"/>
<field name="date_due"/>
<field name="type"/>
<field name="commercial_partner_id"/>
<field name="user_id"/>
<field name="product_id"/>
<field name="product_qty" sum="1"/>
<field name="uom_name" groups="product.group_uom"/>
<field name="price_total" sum="1"/>
<field name="state"/>
</tree>
</field>
</record>
<record id="account.action_account_invoice_report_all_supp" model="ir.actions.act_window">
<field name="context">{'search_default_current': 1, 'search_default_supplier': 1, 'search_default_year': 1}</field> <!-- Remove group_by_no_leaf, which breaks tree view -->
</record>
<record id="account.action_account_invoice_report_all" model="ir.actions.act_window">
<field name="context">{'search_default_current': 1, 'search_default_customer': 1, 'search_default_year': 1}</field> <!-- Remove group_by_no_leaf, which breaks tree view -->
</record>
<record id="view_account_invoice_report_pivot" model="ir.ui.view">
<field name="name">usability.account.invoice.report</field>
<field name="model">account.invoice.report</field>
<field name="inherit_id" ref="account.view_account_invoice_report_pivot"/>
<field name="arch" type="xml">
<pivot position="attributes">
<attribute name="disable_linking"></attribute>
</pivot>
</field>
</record>
</odoo>

View File

@@ -1,15 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2018 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="account.account_invoices" model="ir.actions.report.xml">
<!-- Don't attach on supplier invoices/refunds ! -->
<field name="attachment">(object.type in ('out_invoice', 'out_refund')) and (object.state in ('open','paid')) and ('INV'+(object.number or '').replace('/','')+'.pdf')</field>
</record>
</odoo>

View File

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

View File

@@ -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

View File

@@ -1,550 +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>
<!-- INVOICE -->
<record id="invoice_supplier_form" model="ir.ui.view">
<field name="name">account_usability.supplier.invoice.form</field>
<field name="model">account.invoice</field>
<field name="inherit_id" ref="account.invoice_supplier_form"/>
<field name="arch" type="xml">
<field name="fiscal_position_id" position="attributes">
<attribute name="widget">selection</attribute>
</field>
<field name="invoice_line_ids" position="before">
<button name="delete_lines_qty_zero" states="draft" string="⇒ Delete lines qty=0" type="object" class="oe_link oe_right" groups="account.group_account_invoice"/>
</field>
<xpath expr="//field[@name='tax_line_ids']/tree/field[@name='amount']" position="before">
<field name="base" readonly="1"/>
</xpath>
</field>
</record>
<record id="invoice_form" model="ir.ui.view">
<field name="name">account_usability.invoice.form</field>
<field name="model">account.invoice</field>
<field name="inherit_id" ref="account.invoice_form"/>
<field name="arch" type="xml">
<field name="fiscal_position_id" position="attributes">
<attribute name="widget">selection</attribute>
</field>
<!-- move sent field and make it visible -->
<field name="sent" position="replace"/>
<field name="move_id" position="before">
<field name="sent"/>
</field>
<xpath expr="//field[@name='tax_line_ids']/tree/field[@name='amount']" position="before">
<field name="base" readonly="1"/>
</xpath>
<!-- Warning: there are 2 invoice_print buttons in the native view... probably a bug -->
<xpath expr="//button[@name='invoice_print']" position="attributes">
<attribute name="attrs">{'invisible': [('state', 'not in', ('open', 'paid'))]}</attribute>
</xpath>
<xpath expr="//button[@name='invoice_print'][2]" position="attributes">
<attribute name="attrs">{'invisible': True}</attribute>
</xpath>
</field>
</record>
<record id="invoice_tree" model="ir.ui.view">
<field name="name">account_usability.invoice_tree</field>
<field name="model">account.invoice</field>
<field name="inherit_id" ref="account.invoice_tree"/>
<field name="arch" type="xml">
<field name="reference" position="attributes">
<attribute name="invisible">not context.get('type') in ('in_invoice', 'in_refund')</attribute>
</field>
</field>
</record>
<record id="view_account_invoice_filter" model="ir.ui.view">
<field name="name">account_usability.invoice.search</field>
<field name="model">account.invoice</field>
<field name="inherit_id" ref="account.view_account_invoice_filter"/>
<field name="arch" type="xml">
<filter name="late" position="after">
<separator/>
<filter name="to_send" string="To Send" domain="[('sent', '=', False), ('state', 'in', ('open', 'paid'))]"/>
<filter name="sent" string="Sent" domain="[('sent', '=', True)]"/>
<separator/>
<filter name="no_attachment" string="Missing Attachment" domain="[('has_attachment', '=', False)]"/>
</filter>
</field>
</record>
<!-- Having a menu entry on invoice lines is often very usefull for odoo user:
they can search in their lines, etc...
So I enhance the generic views and add actions, but I don't add menu entries here ;
the creation of the corresponding menu entry should be done in the customer-specifc
module -->
<record id="view_invoice_line_tree" model="ir.ui.view">
<field name="name">account_usability.invoice_line_tree</field>
<field name="model">account.invoice.line</field>
<field name="inherit_id" ref="account.view_invoice_line_tree"/>
<field name="arch" type="xml">
<field name="name" position="before">
<field name="partner_id" invisible="not context.get('show_invoice_fields')"/>
<field name="date_invoice" invisible="not context.get('show_invoice_fields')"/>
<field name="invoice_number" invisible="not context.get('show_invoice_fields')"/>
</field>
<field name="currency_id" position="after">
<field name="state" invisible="not context.get('show_invoice_fields')"/>
<field name="invoice_type" invisible="1"/>
</field>
<field name="quantity" position="attributes">
<attribute name="sum">1</attribute>
</field>
<xpath expr="/tree" position="attributes">
<attribute name="decoration-info">state == 'draft'</attribute>
<attribute name="decoration-muted">state == 'cancel'</attribute>
<attribute name="edit">0</attribute>
<attribute name="create">0</attribute>
</xpath>
</field>
</record>
<record id="account_invoice_line_search" model="ir.ui.view">
<field name="name">account_usability.invoice_line_search</field>
<field name="model">account.invoice.line</field>
<field name="arch" type="xml">
<search string="Search Invoice Lines">
<field name="partner_id"/>
<field name="product_id"/>
<field name="account_id"/>
<field name="invoice_number"/>
<field name="name"/>
<filter name="out_invoice" string="Customer Invoices"
domain="[('invoice_type', '=', 'out_invoice')]"/>
<filter name="out_refund" string="Customer Refunds"
domain="[('invoice_type', '=', 'out_refund')]"/>
<filter name="in_invoice" string="Supplier Invoices"
domain="[('invoice_type', '=', 'in_invoice')]"/>
<filter name="in_refund" string="Supplier Refunds"
domain="[('invoice_type', '=', 'in_refund')]"/>
<separator/>
<filter name="draft" string="Draft" domain="[('state', '=', 'draft')]"/>
<filter name="unpaid" string="Not Paid" domain="[('state', '=', 'open')]"/>
<filter name="paid" string="Paid" domain="[('state', '=', 'paid')]"/>
<group string="Group By" name="groupby">
<filter name="partner_groupby" string="Partner"
context="{'group_by': 'partner_id'}"/>
<filter name="date_groupby" string="Invoice Date"
context="{'group_by': 'date_invoice'}"/>
<filter name="product_groupby" string="Product"
context="{'group_by': 'product_id'}"/>
<filter name="account_groupby" string="Account"
context="{'group_by': 'account_id'}"/>
</group>
</search>
</field>
</record>
<record id="out_invoice_line_action" model="ir.actions.act_window">
<field name="name">Customer Invoice Lines</field>
<field name="res_model">account.invoice.line</field>
<field name="view_mode">tree,form</field>
<field name="domain">[('invoice_type', '=', 'out_invoice')]</field>
<field name="context">{'show_invoice_fields': True}</field>
</record>
<record id="out_refund_line_action" model="ir.actions.act_window">
<field name="name">Customer Refund Lines</field>
<field name="res_model">account.invoice.line</field>
<field name="view_mode">tree,form</field>
<field name="domain">[('invoice_type', '=', 'out_refund')]</field>
<field name="context">{'show_invoice_fields': True}</field>
</record>
<record id="out_invoice_refund_line_action" model="ir.actions.act_window">
<field name="name">Customer Invoice Lines</field>
<field name="res_model">account.invoice.line</field>
<field name="view_mode">tree,form</field>
<field name="domain">[('invoice_type', 'in', ('out_invoice', 'out_refund'))]</field>
<field name="context">{'show_invoice_fields': True}</field>
</record>
<record id="in_invoice_line_action" model="ir.actions.act_window">
<field name="name">Supplier Invoice Lines</field>
<field name="res_model">account.invoice.line</field>
<field name="view_mode">tree,form</field>
<field name="domain">[('invoice_type', '=', 'in_invoice')]</field>
<field name="context">{'show_invoice_fields': True}</field>
</record>
<record id="in_refund_line_action" model="ir.actions.act_window">
<field name="name">Supplier Refund Lines</field>
<field name="res_model">account.invoice.line</field>
<field name="view_mode">tree,form</field>
<field name="domain">[('invoice_type', '=', 'in_refund')]</field>
<field name="context">{'show_invoice_fields': True}</field>
</record>
<record id="in_invoice_refund_line_action" model="ir.actions.act_window">
<field name="name">Supplier Invoice Lines</field>
<field name="res_model">account.invoice.line</field>
<field name="view_mode">tree,form</field>
<field name="domain">[('invoice_type', 'in', ('in_invoice', 'in_refund'))]</field>
<field name="context">{'show_invoice_fields': True}</field>
</record>
<record id="view_account_invoice_report_search" model="ir.ui.view">
<field name="name">usability.account.invoice.report.search</field>
<field name="model">account.invoice.report</field>
<field name="inherit_id" ref="account.view_account_invoice_report_search"/>
<field name="arch" type="xml">
<field name="categ_id" position="after">
<field name="product_id"/>
</field>
</field>
</record>
<record id="account_invoice_report_tree" model="ir.ui.view">
<field name="name">usability.account.invoice.report.tree</field>
<field name="model">account.invoice.report</field>
<field name="arch" type="xml">
<tree string="Invoices Analysis">
<field name="date"/>
<field name="commercial_partner_id"/>
<field name="type"/>
<field name="product_id"/>
<field name="product_qty" sum="1"/>
<field name="price_total" sum="1"/>
<field name="state"/>
<field name="currency_id" invisible="1"/>
<field name="company_id" groups="base.group_multi_company"/>
</tree>
</field>
</record>
<record id="account.action_account_invoice_report_all_supp" model="ir.actions.act_window">
<field name="view_mode">pivot,graph,tree</field>
<field name="context">{'search_default_current':1, 'search_default_supplier':1, 'search_default_year': 1}</field>
</record>
<record id="account.action_account_invoice_report_all" model="ir.actions.act_window">
<field name="view_mode">pivot,graph,tree</field>
<field name="context">{'search_default_current':1, 'search_default_customer':1, 'search_default_year': 1}</field>
</record>
<record id="view_account_invoice_report_pivot" model="ir.ui.view">
<field name="name">usability.account.invoice.report.pivot</field>
<field name="model">account.invoice.report</field>
<field name="inherit_id" ref="account.view_account_invoice_report_pivot"/>
<field name="arch" type="xml">
<xpath expr="/pivot" position="attributes">
<attribute name="disable_linking"></attribute>
</xpath>
</field>
</record>
<record id="view_invoice_tax_form" model="ir.ui.view">
<field name="name">usability.account.invoice.tax.form</field>
<field name="model">account.invoice.tax</field>
<field name="inherit_id" ref="account.view_invoice_tax_form"/>
<field name="arch" type="xml">
<field name="name" position="after">
<field name="tax_id"/>
</field>
</field>
</record>
<record id="view_account_payment_form" model="ir.ui.view">
<field name="name">usability.account.payment.form</field>
<field name="model">account.payment</field>
<field name="inherit_id" ref="account.view_account_payment_form"/>
<field name="arch" type="xml">
<field name="communication" position="after">
<field name="payment_reference"/>
</field>
</field>
</record>
<!-- model account.move.line / Journal Items -->
<record id="account.action_account_moves_all_a" model="ir.actions.act_window">
<field name="limit">200</field>
<!-- Win space, because there are already many columns -->
<field name="context">{'journal_show_code_only': True}</field>
</record>
<!-- remove base.group_no_one on Journal Items-->
<record id="account.menu_action_account_moves_all" model="ir.ui.menu">
<field name="groups_id" eval="[(6, 0, [ref('account.group_account_user')])]"/>
</record>
<!-- accountant must be able to access the Adviser section ! -->
<record id="account.menu_finance_entries" model="ir.ui.menu">
<field name="groups_id" eval="[(4, ref('account.group_account_user'))]"/>
</record>
<!-- model account.move / Journal Entries -->
<record id="account.action_move_journal_line" model="ir.actions.act_window">
<field name="limit">200</field>
<field name="context">{}</field> <!-- Don't filter by default on misc journal -->
</record>
<record id="view_move_form" model="ir.ui.view">
<field name="name">account_usability.account_move_form</field>
<field name="model">account.move</field>
<field name="inherit_id" ref="account.view_move_form"/>
<field name="arch" type="xml">
<field name="ref" position="after">
<field name="default_move_line_name"/>
<field name="default_account_id" invisible="1"/>
<field name="default_credit" invisible="0"/>
<field name="default_debit" invisible="0"/>
</field>
<xpath expr="//field[@name='line_ids']" position="attributes">
<attribute name="context" operation="python_dict" key="default_name">default_move_line_name</attribute>
<attribute name="context" operation="python_dict" key="default_account_id">default_account_id</attribute>
<attribute name="context" operation="python_dict" key="default_credit">default_credit</attribute>
<attribute name="context" operation="python_dict" key="default_debit">default_debit</attribute>
</xpath>
<xpath expr="//field[@name='line_ids']/tree/field[@name='credit']" position="after">
<field name="reconcile_string"/>
</xpath>
</field>
</record>
<record id="view_account_move_line_filter" model="ir.ui.view">
<field name="name">account_usability.account_move_line_search</field>
<field name="model">account.move.line</field>
<field name="inherit_id" ref="account.view_account_move_line_filter"/>
<field name="arch" type="xml">
<field name="partner_id" position="after">
<field name="reconcile_string" />
<field name="debit" filter_domain="['|', ('debit', '=', self), ('credit', '=', self)]" string="Debit or Credit"/>
</field>
<filter name="unreconciled" position="before">
<filter name="reconciled" string="Fully Reconciled" domain="[('full_reconcile_id', '!=', False)]"/>
<!-- <filter name="partial_reconciled" string="Partially Reconciled" domain="[('reconcile_partial_id', '!=', False)]"/> -->
</filter>
<filter name="unreconciled" position="attributes">
<attribute name="string">Unreconciled or Partially Reconciled</attribute>
</filter>
<field name="name" position="attributes">
<attribute name="string">Name or Reference</attribute>
</field>
<field name="partner_id" position="attributes">
<attribute name="domain">['|', ('parent_id', '=', False), ('is_company', '=', True)]</attribute>
</field>
</field>
</record>
<record id="view_move_line_form" model="ir.ui.view">
<field name="name">account_usability.account_move_line_form</field>
<field name="model">account.move.line</field>
<field name="inherit_id" ref="account.view_move_line_form"/>
<field name="arch" type="xml">
<field name="quantity" position="after">
<field name="product_id" />
</field>
<field name="move_id" position="after">
<field name="invoice_id"/>
<field name="account_reconcile" invisible="1"/>
</field>
<xpath expr="//field[@name='full_reconcile_id']/.." position="replace">
<field name="full_reconcile_id" nolabel="1"/> <!-- label is already in view -->
<field name="matched_debit_ids" readonly="1" widget="many2many_tags" attrs="{'invisible': ['|', ('full_reconcile_id', '!=', False), ('matched_debit_ids', '=', [])]}"/>
<field name="matched_credit_ids" readonly="1" widget="many2many_tags" attrs="{'invisible': ['|', ('full_reconcile_id', '!=', False), ('matched_credit_ids', '=', [])]}"/>
<field name="reconciled" invisible="1"/>
<button name="open_reconcile_view" class="oe_link" type="object"
string="-> View partially reconciled entries" colspan="2"
attrs="{'invisible': ['|', ('full_reconcile_id', '!=', False), '&amp;', ('matched_debit_ids', '=', []),('matched_credit_ids', '=', [])]}"/>
<span colspan="2" attrs="{'invisible': ['|', '|', ('full_reconcile_id', '!=', False), ('matched_debit_ids', '!=', []), ('matched_credit_ids', '!=', [])]}" class="o_form_field">No Partial Reconcile</span>
</xpath>
<xpath expr="//label[@for='full_reconcile_id']/.." position="attributes">
<attribute name="attrs">{'invisible': [('account_reconcile', '=', False)]}</attribute>
</xpath>
</field>
</record>
<record id="view_move_line_tree" model="ir.ui.view">
<field name="name">account_usability.account_move_line_tree</field>
<field name="model">account.move.line</field>
<field name="inherit_id" ref="account.view_move_line_tree"/>
<field name="arch" type="xml">
<!-- Move reconcile_id to a better position -->
<field name="full_reconcile_id" position="replace"/>
<field name="credit" position="after">
<field name="balance" sum="Total Balance"/>
<field name="reconcile_string"/>
</field>
<field name="date_maturity" position="after">
<button name="show_account_move_form" type="object" icon="fa-arrows-h" string="Show Journal Entry"/>
</field>
</field>
</record>
<record id="view_account_move_filter" model="ir.ui.view">
<field name="name">account_usability.account_move_search</field>
<field name="model">account.move</field>
<field name="inherit_id" ref="account.view_account_move_filter"/>
<field name="arch" type="xml">
<field name="partner_id" position="attributes">
<attribute name="domain">['|', ('parent_id', '=', False), ('is_company', '=', True)]</attribute>
</field>
</field>
</record>
<record id="view_account_search" model="ir.ui.view">
<field name="name">account.account.search</field>
<field name="model">account.account</field>
<field name="inherit_id" ref="account.view_account_search"/>
<field name="arch" type="xml">
<!-- The native "name" filter uses a domain ['|', ('name','ilike',self), ('code','=like',str(self)+'%')]
This is good because it uses '=like' on 'code', but sometimes there are digits in account names,
so you get additionnal unexpected accounts in the result of the search -->
<field name="name" position="after">
<field name="code" filter_domain="[('code', '=like', str(self)+'%')]" string="Code"/>
</field>
</field>
</record>
<record id="view_account_type_tree" model="ir.ui.view">
<field name="name">account_usability.account_type_tree</field>
<field name="model">account.account.type</field>
<field name="inherit_id" ref="account.view_account_type_tree" />
<field name="arch" type="xml">
<field name="type" position="after">
<field name="include_initial_balance" />
</field>
</field>
</record>
<record id="view_account_journal_search" model="ir.ui.view">
<field name="name">usability.account.journal.search</field>
<field name="model">account.journal</field>
<field name="inherit_id" ref="account.view_account_journal_search"/>
<field name="arch" type="xml">
<filter name="dashboard" position="after">
<group name="groupby" string="Group By">
<filter name="type_groupby" string="Type" context="{'group_by': 'type'}"/>
</group>
</filter>
</field>
</record>
<record id="view_bank_statement_form" model="ir.ui.view">
<field name="name">usability.account.bank.statement.form</field>
<field name="model">account.bank.statement</field>
<field name="inherit_id" ref="account.view_bank_statement_form"/>
<field name="arch" type="xml">
<button name="button_cancel" position="attributes">
<attribute name="invisible">1</attribute>
</button>
<xpath expr="//field[@name='line_ids']/tree/field[@name='bank_account_id']" position="after">
<!-- The cancel button is provided by the account_cancel module, but we don't want to depend on it -->
<button name="show_account_move" type="object"
string="View Account Move" icon="fa fa-arrow-right"
attrs="{'invisible': [('journal_entry_ids', '=', [])]}"/>
</xpath>
<field name="date" position="after">
<field name="start_date"/>
<field name="end_date"/>
</field>
<field name="date" position="attributes">
<attribute name="invisible">1</attribute>
</field>
</field>
</record>
<record id="view_bank_statement_tree" model="ir.ui.view">
<field name="name">usability.account.bank.statement.tree</field>
<field name="model">account.bank.statement</field>
<field name="inherit_id" ref="account.view_bank_statement_tree"/>
<field name="arch" type="xml">
<field name="date" position="attributes">
<attribute name="invisible">1</attribute>
</field>
<field name="journal_id" position="after">
<field name="start_date"/>
<field name="end_date"/>
</field>
</field>
</record>
<record id="view_bank_statement_search" model="ir.ui.view">
<field name="name">usability.account.bank.statement.search</field>
<field name="model">account.bank.statement</field>
<field name="inherit_id" ref="account.view_bank_statement_search"/>
<field name="arch" type="xml">
<field name="date" position="attributes">
<attribute name="invisible">1</attribute>
</field>
<field name="date" position="after">
<field name="start_date"/>
<field name="end_date"/>
</field>
<filter context="{'group_by': 'date'}" position="attributes">
<attribute name="invisible">1</attribute>
</filter>
<filter context="{'group_by': 'date'}" position="after">
<filter name="start_date_groupby" string="Start Date"
context="{'group_by': 'start_date'}"/>
<filter name="end_date_groupby" string="End Date"
context="{'group_by': 'end_date'}"/>
</filter>
</field>
</record>
<!-- ACCOUNT TAX GROUP -->
<!-- in the account module, there is nothing for account.tax.group : no form/tree view, no menu... -->
<record id="account_tax_group_form" model="ir.ui.view">
<field name="name">usability.account.tax.group.form</field>
<field name="model">account.tax.group</field>
<field name="arch" type="xml">
<form string="Tax Group">
<group name="main">
<field name="name"/>
<field name="sequence" invisible="1"/>
</group>
</form>
</field>
</record>
<record id="account_tax_group_tree" model="ir.ui.view">
<field name="name">usability.account.tax.group.tree</field>
<field name="model">account.tax.group</field>
<field name="arch" type="xml">
<tree string="Tax Groups">
<field name="sequence" widget="handle"/>
<field name="name"/>
</tree>
</field>
</record>
<record id="account_tax_group_action" model="ir.actions.act_window">
<field name="name">Tax Groups</field>
<field name="res_model">account.tax.group</field>
<field name="view_mode">tree,form</field>
</record>
<menuitem id="account_tax_group_menu" action="account_tax_group_action" parent="account.account_account_menu" sequence="2"/>
<!-- Remove menu entry "Accounting > Configuration > Accounting > Bank Accounts"
(account.journal filtered on type = 'bank' with special tree and form view)
because it is useless and confusing -->
<record id="account.menu_action_account_bank_journal_form" model="ir.ui.menu">
<field name="groups_id" eval="[(6, 0, [ref('base_usability.group_nobody')])]"/>
</record>
<!-- Remove menu entry "Accounting > Reports > PDF Reports" as there are broken -->
<record id="account.menu_finance_legal_statement" model="ir.ui.menu">
<field name="groups_id" eval="[(6, 0, [ref('base_usability.group_nobody')])]"/>
</record>
<!-- Duplicate the menu "Sales > Configuration > Contacts > Bank Accounts"
under "Accounting > Configuration", because most users will try to find it there -->
<menuitem id="bank_account_account_config_menu" name="Bank Accounts" parent="account.menu_finance_configuration" sequence="9"/>
<menuitem id="res_bank_account_config_menu" action="base.action_res_bank_form" parent="bank_account_account_config_menu" sequence="10"/>
<menuitem id="res_partner_bank_account_config_menu" action="base.action_res_partner_bank_account_form" parent="bank_account_account_config_menu" sequence="20"/>
</odoo>

View File

@@ -1,33 +0,0 @@
diff --git a/addons/account/models/account_payment.py b/addons/account/models/account_payment.py
index b1d8012329d..b8a8e2a673d 100644
--- a/addons/account/models/account_payment.py
+++ b/addons/account/models/account_payment.py
@@ -210,6 +210,7 @@ class account_payment(models.Model):
payment_difference = fields.Monetary(compute='_compute_payment_difference', readonly=True)
payment_difference_handling = fields.Selection([('open', 'Keep open'), ('reconcile', 'Mark invoice as fully paid')], default='open', string="Payment Difference", 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)
# FIXME: ondelete='restrict' not working (eg. cancel a bank statement reconciliation with a payment)
move_line_ids = fields.One2many('account.move.line', 'payment_id', readonly=True, copy=False, ondelete='restrict')
@@ -431,6 +432,7 @@ class account_payment(models.Model):
amount_currency_wo = -abs(amount_currency_wo)
writeoff_line['name'] = _('Counterpart')
writeoff_line['account_id'] = self.writeoff_account_id.id
+ writeoff_line['analytic_account_id'] = self.writeoff_analytic_account_id.id or False
writeoff_line['debit'] = debit_wo
writeoff_line['credit'] = credit_wo
writeoff_line['amount_currency'] = amount_currency_wo
diff --git a/addons/account/views/account_payment_view.xml b/addons/account/views/account_payment_view.xml
index 2460458fbaa..4065d8f9952 100644
--- a/addons/account/views/account_payment_view.xml
+++ b/addons/account/views/account_payment_view.xml
@@ -206,6 +206,8 @@
</div>
<field name="writeoff_account_id" string="Post Difference In"
attrs="{'invisible': [('payment_difference_handling','=','open')], 'required': [('payment_difference_handling', '=', 'reconcile')]}"/>
+ <field name="writeoff_analytic_account_id" string="Post Difference In Analytic Account"
+ attrs="{'invisible': [('payment_difference_handling','=','open')]}"/>
</group>
</group>
</sheet>

View File

@@ -1,13 +0,0 @@
# -*- coding: utf-8 -*-
# © 2017 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import models, fields
class ResPartner(models.Model):
_inherit = 'res.partner'
invoice_warn = fields.Selection(track_visibility='onchange')
property_account_position_id = fields.Many2one(
track_visibility='onchange')

View File

@@ -1,26 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
© 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_partner_property_form" model="ir.ui.view">
<field name="name">account_usability.res.partner.form</field>
<field name="model">res.partner</field>
<field name="inherit_id" ref="account.view_partner_property_form"/>
<field name="arch" type="xml">
<field name="property_account_position_id" position="attributes">
<attribute name="widget">selection</attribute>
</field>
<group name="accounting_entries" position="attributes">
<attribute name="groups">account.group_account_user</attribute>
</group>
</field>
</record>
</odoo>

View File

@@ -1,24 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
© 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_category_property_form" model="ir.ui.view">
<field name="name">account_usability.product.category.form</field>
<field name="model">product.category</field>
<field name="inherit_id" ref="account.view_category_property_form"/>
<field name="arch" type="xml">
<!-- On product form view, the group for Invoicing tab is limited to account.group_account_invoice... but on product category form, it is limited to account.group_account_manager -> we fix this and also use account.group_account_invoice -->
<group name="account_property" position="attributes">
<attribute name="groups">account.group_account_invoice</attribute>
</group>
</field>
</record>
</odoo>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.5 KiB

View File

@@ -1,4 +0,0 @@
# -*- encoding: utf-8 -*-
from . import account_invoice_mark_sent
from . import account_move_reversal

View File

@@ -1,23 +0,0 @@
# -*- coding: utf-8 -*-
# © 2017 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import models
import logging
logger = logging.getLogger(__name__)
class AccountInvoiceMarkSent(models.TransientModel):
_name = 'account.invoice.mark.sent'
_description = 'Mark invoices as sent'
def run(self):
assert self.env.context.get('active_model') == 'account.invoice',\
'Source model must be invoices'
assert self.env.context.get('active_ids'), 'No invoices selected'
invoices = self.env['account.invoice'].search([
('id', 'in', self.env.context.get('active_ids')),
('state', 'in', ('open', 'paid'))])
invoices.write({'sent': True})
logger.info('Marking invoices with ID %s as sent', invoices.ids)
return

View File

@@ -1,35 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2017-2018 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_mark_sent_form" model="ir.ui.view">
<field name="name">account.invoice.mark.sent.form</field>
<field name="model">account.invoice.mark.sent</field>
<field name="arch" type="xml">
<form string="Mark invoices as sent">
<p>
This wizard will mark as <i>sent</i> all the selected invoices in open or paid state.
</p>
<footer>
<button type="object" name="run" string="Mark as Sent" class="btn-primary"/>
<button special="cancel" string="Cancel" class="oe_link"/>
</footer>
</form>
</field>
</record>
<act_window id="account_invoice_mark_sent_action"
multi="True"
key2="client_action_multi"
name="Mark as Sent"
res_model="account.invoice.mark.sent"
src_model="account.invoice"
view_mode="form"
target="new"
groups="account.group_account_invoice" />
</odoo>

View File

@@ -1,24 +0,0 @@
# -*- coding: utf-8 -*-
# Copyright 2018 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import api, fields, models
from dateutil.relativedelta import relativedelta
class AccountMoveReversal(models.TransientModel):
_inherit = 'account.move.reversal'
@api.model
def _default_date(self):
date = None
if (
self._context.get('active_model') == 'account.move' and
self._context.get('active_id')):
move = self.env['account.move'].browse(self._context['active_id'])
date_dt = fields.Date.from_string(move.date) +\
relativedelta(days=1)
date = fields.Date.to_string(date_dt)
return date
date = fields.Date(default=_default_date)

View File

@@ -1,3 +0,0 @@
# -*- coding: utf-8 -*-
from . import printing

View File

@@ -1,52 +0,0 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Aeroo Report to Printer module for Odoo
# Copyright (C) 2015 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': 'Aeroo Report to Printer',
'version': '0.1',
'category': 'Aeroo',
'license': 'AGPL-3',
'summary': 'Connect aeroo_report to base_report_to_printer',
'description': """
Aeroo Report to Printer
=======================
There is a module *report_aeroo_direct_print* in https://github.com/aeroo/aeroo_reports that adds support for CUPS printing, but it's not as mature and clean as the OCA module *base_report_to_printer* from https://github.com/OCA/report-print-send.
And I want to use the best of both world : the best reporting engine (Aeroo) with the best CUPS printing module (base_report_to_printer). So I developped this small glue module.
You will find some sample code to use this module in the comments of the main Python file.
WARNING: you need this PR for base_report_to_printer to use this module: https://github.com/OCA/report-print-send/pull/39
This module has been written by Alexis de Lattre from Akretion <alexis.delattre@akretion.com>.
""",
'author': 'Akretion',
'website': 'http://www.akretion.com',
'depends': [
'base_report_to_printer',
'report_aeroo',
'base_other_report_engines',
],
'installable': False,
}

View File

@@ -1,75 +0,0 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Aeroo Report to Printer module for Odoo
# Copyright (C) 2015 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 openerp import models, api, _
from openerp.exceptions import Warning as UserError
import logging
logger = logging.getLogger(__name__)
class PrintingPrinter(models.Model):
_inherit = 'printing.printer'
@api.multi
def aeroo_print_document(self, report_name, object_id, copies=1):
'''
Send an aeroo report to CUPS server for printing
Usage example :
Add this button in an inherit of the view 'stock.view_picking_form':
<button name="print_delivery" type="object" states="done"
string="Print 2 copies"/>
Add this code in the StockPicking class that inherit 'stock.picking'
@api.multi
def print_delivery(self):
if not self.env.user.printing_printer_id:
raise UserError(_(
"Missing 'Default Printer' in your preferences"))
self.env.user.printing_printer_id.aeroo_print_document(
'stock.report_picking', self.id, copies=2)
'''
self.ensure_one()
report = self.env['ir.actions.report.xml']._lookup_report(report_name)
report_xml = self.env['report']._get_report_from_name(report_name)
data = {
'model': report_xml.model,
'id': object_id,
'report_type': 'aeroo',
}
logger.info(
'Request printing aeroo report %s model %s ID %d in %d copies',
report_name, data['model'], data['id'], copies)
aeroo_report_content, aeroo_report_format = report.create(
self.env.cr, self.env.uid, [object_id],
data, context=dict(self.env.context))
if aeroo_report_format in ('pdf', 'raw'):
self.print_document(
report_name, aeroo_report_content, aeroo_report_format, copies)
else:
raise UserError(_(
"Format '%s' is not supported for printing")
% aeroo_report_format)
return True

View File

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

View File

@@ -1,25 +0,0 @@
# coding: utf-8
# © 2016 Akretion
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
{
'name': 'Attribute Usability',
'version': '8.0.0.0.0',
'category': 'Product',
'summary': "Attribute views improved",
'description': """
- Create filter dynamically for each attributes in attribute values search view
- Add a form view to Attribute and Attribute Value views
Contributors: David BEAL
""",
'author': 'Akretion',
'website': 'http://www.akretion.com',
'depends': [
'product',
],
'data': [
'view.xml',
],
'installable': False,
}

View File

@@ -1,48 +0,0 @@
# coding: utf-8
# © 2016 David BEAL @ Akretion
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from openerp import models, api
from lxml import etree
class ProductAtribute(models.Model):
_inherit = 'product.attribute'
_order = 'sequence ASC'
class ProductAttributeValue(models.Model):
_inherit = 'product.attribute.value'
@api.model
def _get_attributes_to_filter(self):
""" Inherit if you want reduce the list """
return [(x.id, x.name)
for x in self.env['product.attribute'].search(
[], order='name DESC')]
@api.model
def _customize_attribute_filters(self, my_filter):
""" Inherit if you to customize search filter display"""
return {
'string': "%s" % my_filter[1],
'help': 'Filtering by Attribute',
'domain': "[('attribute_id','=', %s)]" % my_filter[0]}
@api.model
def fields_view_get(self, view_id=None, view_type='form',
toolbar=False, submenu=False):
""" customize xml output
"""
res = super(ProductAttributeValue, self).fields_view_get(
view_id=view_id, view_type=view_type, toolbar=toolbar,
submenu=submenu)
if view_type == 'search':
filters_to_create = self._get_attributes_to_filter()
doc = etree.XML(res['arch'])
for my_filter in filters_to_create:
elm = etree.Element(
'filter', **self._customize_attribute_filters(my_filter))
doc[0].addprevious(elm)
res['arch'] = etree.tostring(doc, pretty_print=True)
return res

View File

@@ -1,16 +0,0 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 8.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-03-16 16:14+0000\n"
"PO-Revision-Date: 2016-03-16 16:14+0000\n"
"Last-Translator: <>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"

View File

@@ -1,16 +0,0 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 8.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-03-16 16:10+0000\n"
"PO-Revision-Date: 2016-03-16 16:10+0000\n"
"Last-Translator: <>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 936 B

View File

@@ -1,27 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="product.variants_action" model="ir.actions.act_window">
<field name="res_model">product.attribute.value</field>
<field name="view_mode">tree,form</field>
</record>
<record id="product.attribute_action" model="ir.actions.act_window">
<field name="res_model">product.attribute</field>
<field name="view_mode">tree,form</field>
</record>
<!-- After installation of the module, open the adhoc menu -->
<record id="action_client_attribute_usabi_menu" model="ir.actions.client">
<field name="name">Open Attribute Usability Menu</field>
<field name="tag">reload</field>
<field name="params" eval="{'menu_id': ref('product.menu_variants_action')}"/>
</record>
<record id="base.open_menu" model="ir.actions.todo">
<field name="action_id" ref="action_client_attribute_usabi_menu"/>
<field name="state">open</field>
</record>
</data>
</openerp>

View File

@@ -1,3 +0,0 @@
# -*- coding: utf-8 -*-
from . import company

View File

@@ -1,28 +0,0 @@
# -*- coding: utf-8 -*-
# © 2014-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).
{
'name': 'Base Company Extension',
'version': '10.0.1.0.0',
'category': 'Partner',
'license': 'AGPL-3',
'summary': 'Adds capital and title on company',
'description': """
Base Company Extension
======================
This module adds 2 fields on the Company :
* *Capital Amount*
* *Legal Form*
""",
'author': 'Akretion',
'website': 'http://www.akretion.com',
# I depend on base_usability only for _report_company_legal_name()
'depends': ['base_usability'],
'data': ['company_view.xml'],
'installable': True,
}

View File

@@ -1,29 +0,0 @@
# -*- coding: utf-8 -*-
# © 2014-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).
from odoo import models, fields
class ResCompany(models.Model):
_inherit = "res.company"
capital_amount = fields.Monetary(string='Capital Amount')
# in v9, title is only for contacts, not for companies
legal_type = fields.Char(
string="Legal Type", help="Type of Company, e.g. SARL, SAS, ...")
def _report_company_legal_name(self):
self.ensure_one()
if self.legal_type:
name = u'%s %s' % (self.name, self.legal_type)
else:
name = self.name
return name
_sql_constraints = [(
'capital_amount_positive',
'CHECK (capital_amount >= 0)',
"The value of the field 'Capital Amount' must be positive."
)]

View File

@@ -1,22 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
© 2014-2016 Akretion (http://www.akretion.com/)
@author Alexis de Lattre <alexis.delattre@akretion.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<odoo>
<record id="view_company_form" model="ir.ui.view">
<field name="name">company.extension.form</field>
<field name="model">res.company</field>
<field name="inherit_id" ref="base.view_company_form" />
<field name="arch" type="xml">
<field name="company_registry" position="after">
<field name="capital_amount"/>
<field name="legal_type"/>
</field>
</field>
</record>
</odoo>

View File

@@ -1,3 +0,0 @@
# -*- coding: utf-8 -*-
from . import ir_mail_server

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