Compare commits
41 Commits
18.0
...
14-fix-mig
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
79f76c40f2 | ||
|
|
fd31627fa6 | ||
|
|
2863de99f4 | ||
|
|
16ed41187f | ||
|
|
7129dd1cce | ||
|
|
d2cf9b73d8 | ||
|
|
d6cf5f82e7 | ||
|
|
e9350bac57 | ||
|
|
2e267d717f | ||
|
|
e8b43b67c1 | ||
|
|
f2b5b0b4dd | ||
|
|
a64c60a540 | ||
|
|
b48db5492d | ||
|
|
9026660416 | ||
|
|
d2a9f953b9 | ||
|
|
acff0a421d | ||
|
|
64f54a9389 | ||
|
|
08db759977 | ||
|
|
e07df6b45a | ||
|
|
fc58a9adf5 | ||
|
|
1d463a744d | ||
|
|
dbad21c13a | ||
|
|
aa16b70bdd | ||
|
|
eff63f2be2 | ||
|
|
937595ca2c | ||
|
|
9397bb9fce | ||
|
|
390ce75827 | ||
|
|
819d145763 | ||
|
|
45bbcc0cb3 | ||
|
|
6ddc1b86d5 | ||
|
|
d0b315f648 | ||
|
|
f1eeaa2e8a | ||
|
|
553f05c58f | ||
|
|
50ae5dc9cb | ||
|
|
9c7775dabb | ||
|
|
70f1f13edd | ||
|
|
989960c7c8 | ||
|
|
9b186028c3 | ||
|
|
c2c4957686 | ||
|
|
d382aea22f | ||
|
|
688a07fc5e |
27
account_bank_reconciliation_summary_xlsx/README.rst
Normal file
27
account_bank_reconciliation_summary_xlsx/README.rst
Normal file
@@ -0,0 +1,27 @@
|
||||
===============================
|
||||
Bank Reconciliation Report XLSX
|
||||
===============================
|
||||
|
||||
In Odoo v13+, a bank reconciliation report is not really needed because all the payments executed that are not debited/credited on the bank account are in separate waiting accounts. But accountants want a bank reconciliation report, so this module adds one, even if it is quite different from a classic bank reconciliation report.
|
||||
|
||||
Configuration
|
||||
=============
|
||||
|
||||
This module doesn't require any configuration.
|
||||
|
||||
Usage
|
||||
=====
|
||||
|
||||
You can launch the Bank Reconciliation Report wizard from:
|
||||
|
||||
* the menu *Accounting > Reports > Bank > Bank Reconciliation*,
|
||||
* the invoicing dashboard: on a bank journal, click on the options, then select *Bank Reconciliation*.
|
||||
* the form view of a bank statement: click on the button *Bank Reconciliation Report*.
|
||||
|
||||
Credits
|
||||
=======
|
||||
|
||||
Contributors
|
||||
------------
|
||||
|
||||
* Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
2
account_bank_reconciliation_summary_xlsx/__init__.py
Normal file
2
account_bank_reconciliation_summary_xlsx/__init__.py
Normal file
@@ -0,0 +1,2 @@
|
||||
from . import report
|
||||
from . import wizard
|
||||
21
account_bank_reconciliation_summary_xlsx/__manifest__.py
Normal file
21
account_bank_reconciliation_summary_xlsx/__manifest__.py
Normal file
@@ -0,0 +1,21 @@
|
||||
# Copyright 2017-2023 Akretion France (http://www.akretion.com/)
|
||||
# @author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
{
|
||||
"name": "Bank Reconciliation Report",
|
||||
"version": "14.0.1.0.0",
|
||||
"license": "AGPL-3",
|
||||
"author": "Akretion",
|
||||
"website": "https://github.com/akretion/odoo-usability",
|
||||
"summary": "Bank reconciliation XLSX report",
|
||||
"depends": ["account", "report_xlsx"],
|
||||
"data": [
|
||||
"report/report.xml",
|
||||
"wizard/bank_reconciliation_report_wizard_view.xml",
|
||||
"views/account_bank_statement.xml",
|
||||
"views/account_journal.xml",
|
||||
"security/ir.model.access.csv",
|
||||
],
|
||||
"installable": True,
|
||||
}
|
||||
213
account_bank_reconciliation_summary_xlsx/i18n/fr.po
Normal file
213
account_bank_reconciliation_summary_xlsx/i18n/fr.po
Normal file
@@ -0,0 +1,213 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * account_bank_reconciliation_summary_xlsx
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server 14.0\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2023-01-13 10:31+0000\n"
|
||||
"PO-Revision-Date: 2023-01-13 10:31+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"
|
||||
|
||||
#. module: account_bank_reconciliation_summary_xlsx
|
||||
#: code:addons/account_bank_reconciliation_summary_xlsx/report/bank_reconciliation_xlsx.py:0
|
||||
#, python-format
|
||||
msgid "Amount"
|
||||
msgstr "Montant"
|
||||
|
||||
#. module: account_bank_reconciliation_summary_xlsx
|
||||
#: code:addons/account_bank_reconciliation_summary_xlsx/report/bank_reconciliation_xlsx.py:0
|
||||
#, python-format
|
||||
msgid "Balance %s:"
|
||||
msgstr "Solde %s :"
|
||||
|
||||
#. module: account_bank_reconciliation_summary_xlsx
|
||||
#: model:ir.model.fields,field_description:account_bank_reconciliation_summary_xlsx.field_bank_reconciliation_report_wizard__journal_ids
|
||||
msgid "Bank Journals"
|
||||
msgstr "Journaux de banque"
|
||||
|
||||
#. module: account_bank_reconciliation_summary_xlsx
|
||||
#: model:ir.actions.act_window,name:account_bank_reconciliation_summary_xlsx.bank_reconciliation_report_wizard_action
|
||||
#: model:ir.ui.menu,name:account_bank_reconciliation_summary_xlsx.bank_reconciliation_report_wizard_menu
|
||||
#: model_terms:ir.ui.view,arch_db:account_bank_reconciliation_summary_xlsx.account_journal_dashboard_kanban_view
|
||||
msgid "Bank Reconciliation"
|
||||
msgstr "Rapprochement bancaire"
|
||||
|
||||
#. module: account_bank_reconciliation_summary_xlsx
|
||||
#: code:addons/account_bank_reconciliation_summary_xlsx/report/bank_reconciliation_xlsx.py:0
|
||||
#: model_terms:ir.ui.view,arch_db:account_bank_reconciliation_summary_xlsx.view_bank_statement_form
|
||||
#, python-format
|
||||
msgid "Bank Reconciliation Report"
|
||||
msgstr "Rapport de rapprochement bancaire"
|
||||
|
||||
#. module: account_bank_reconciliation_summary_xlsx
|
||||
#: model:ir.model,name:account_bank_reconciliation_summary_xlsx.model_bank_reconciliation_report_wizard
|
||||
msgid "Bank Reconciliation Report Wizard"
|
||||
msgstr "Assistant rapport de rapprochement bancaire"
|
||||
|
||||
#. module: account_bank_reconciliation_summary_xlsx
|
||||
#: model:ir.actions.report,name:account_bank_reconciliation_summary_xlsx.bank_reconciliation_xlsx
|
||||
msgid "Bank Reconciliation XLSX"
|
||||
msgstr "Rapprochement bancaire XLSX"
|
||||
|
||||
#. module: account_bank_reconciliation_summary_xlsx
|
||||
#: model:ir.model,name:account_bank_reconciliation_summary_xlsx.model_report_bank_reconciliation_xlsx
|
||||
msgid "Bank Reconciliation XLSX Report"
|
||||
msgstr "Rapport de rapprochement bancaire XLSX"
|
||||
|
||||
#. module: account_bank_reconciliation_summary_xlsx
|
||||
#: model:ir.ui.menu,name:account_bank_reconciliation_summary_xlsx.menu_report_bank_root
|
||||
msgid "Bank Reports"
|
||||
msgstr "Rapports bancaires"
|
||||
|
||||
#. module: account_bank_reconciliation_summary_xlsx
|
||||
#: model_terms:ir.ui.view,arch_db:account_bank_reconciliation_summary_xlsx.bank_reconciliation_report_wizard_form
|
||||
msgid "Cancel"
|
||||
msgstr "Annuler"
|
||||
|
||||
#. module: account_bank_reconciliation_summary_xlsx
|
||||
#: code:addons/account_bank_reconciliation_summary_xlsx/report/bank_reconciliation_xlsx.py:0
|
||||
#: model:ir.model.fields,field_description:account_bank_reconciliation_summary_xlsx.field_bank_reconciliation_report_wizard__company_id
|
||||
#, python-format
|
||||
msgid "Company"
|
||||
msgstr "Société"
|
||||
|
||||
#. module: account_bank_reconciliation_summary_xlsx
|
||||
#: code:addons/account_bank_reconciliation_summary_xlsx/report/bank_reconciliation_xlsx.py:0
|
||||
#, python-format
|
||||
msgid "Counter-part"
|
||||
msgstr "Contre partie"
|
||||
|
||||
#. module: account_bank_reconciliation_summary_xlsx
|
||||
#: model:ir.model.fields,field_description:account_bank_reconciliation_summary_xlsx.field_bank_reconciliation_report_wizard__create_uid
|
||||
msgid "Created by"
|
||||
msgstr "Créé par"
|
||||
|
||||
#. module: account_bank_reconciliation_summary_xlsx
|
||||
#: model:ir.model.fields,field_description:account_bank_reconciliation_summary_xlsx.field_bank_reconciliation_report_wizard__create_date
|
||||
msgid "Created on"
|
||||
msgstr "Créé le"
|
||||
|
||||
#. module: account_bank_reconciliation_summary_xlsx
|
||||
#: code:addons/account_bank_reconciliation_summary_xlsx/report/bank_reconciliation_xlsx.py:0
|
||||
#: code:addons/account_bank_reconciliation_summary_xlsx/report/bank_reconciliation_xlsx.py:0
|
||||
#: model:ir.model.fields,field_description:account_bank_reconciliation_summary_xlsx.field_bank_reconciliation_report_wizard__date
|
||||
#, python-format
|
||||
msgid "Date"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_bank_reconciliation_summary_xlsx
|
||||
#: model:ir.model.fields,field_description:account_bank_reconciliation_summary_xlsx.field_bank_reconciliation_report_wizard__display_name
|
||||
#: model:ir.model.fields,field_description:account_bank_reconciliation_summary_xlsx.field_report_bank_reconciliation_xlsx__display_name
|
||||
msgid "Display Name"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_bank_reconciliation_summary_xlsx
|
||||
#: model:ir.model.fields.selection,name:account_bank_reconciliation_summary_xlsx.selection__bank_reconciliation_report_wizard__move_state__draft_posted
|
||||
msgid "Draft and Posted Entries"
|
||||
msgstr "Écritures brouillon et comptabilisées"
|
||||
|
||||
#. module: account_bank_reconciliation_summary_xlsx
|
||||
#: code:addons/account_bank_reconciliation_summary_xlsx/report/bank_reconciliation_xlsx.py:0
|
||||
#: model:ir.model.fields,field_description:account_bank_reconciliation_summary_xlsx.field_bank_reconciliation_report_wizard__move_state
|
||||
#, python-format
|
||||
msgid "Entries"
|
||||
msgstr "Écritures"
|
||||
|
||||
#. module: account_bank_reconciliation_summary_xlsx
|
||||
#: model_terms:ir.ui.view,arch_db:account_bank_reconciliation_summary_xlsx.bank_reconciliation_report_wizard_form
|
||||
msgid "Export XLSX"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_bank_reconciliation_summary_xlsx
|
||||
#: code:addons/account_bank_reconciliation_summary_xlsx/report/bank_reconciliation_xlsx.py:0
|
||||
#, python-format
|
||||
msgid "Generated on %s"
|
||||
msgstr "Généré le %s"
|
||||
|
||||
#. module: account_bank_reconciliation_summary_xlsx
|
||||
#: model:ir.model.fields,field_description:account_bank_reconciliation_summary_xlsx.field_bank_reconciliation_report_wizard__id
|
||||
#: model:ir.model.fields,field_description:account_bank_reconciliation_summary_xlsx.field_report_bank_reconciliation_xlsx__id
|
||||
msgid "ID"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_bank_reconciliation_summary_xlsx
|
||||
#: code:addons/account_bank_reconciliation_summary_xlsx/report/bank_reconciliation_xlsx.py:0
|
||||
#, python-format
|
||||
msgid "Journal"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_bank_reconciliation_summary_xlsx
|
||||
#: code:addons/account_bank_reconciliation_summary_xlsx/report/bank_reconciliation_xlsx.py:0
|
||||
#, python-format
|
||||
msgid "Label"
|
||||
msgstr "Libellé"
|
||||
|
||||
#. module: account_bank_reconciliation_summary_xlsx
|
||||
#: model:ir.model.fields,field_description:account_bank_reconciliation_summary_xlsx.field_bank_reconciliation_report_wizard____last_update
|
||||
#: model:ir.model.fields,field_description:account_bank_reconciliation_summary_xlsx.field_report_bank_reconciliation_xlsx____last_update
|
||||
msgid "Last Modified on"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_bank_reconciliation_summary_xlsx
|
||||
#: model:ir.model.fields,field_description:account_bank_reconciliation_summary_xlsx.field_bank_reconciliation_report_wizard__write_uid
|
||||
msgid "Last Updated by"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_bank_reconciliation_summary_xlsx
|
||||
#: model:ir.model.fields,field_description:account_bank_reconciliation_summary_xlsx.field_bank_reconciliation_report_wizard__write_date
|
||||
msgid "Last Updated on"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_bank_reconciliation_summary_xlsx
|
||||
#: code:addons/account_bank_reconciliation_summary_xlsx/report/bank_reconciliation_xlsx.py:0
|
||||
#, python-format
|
||||
msgid "Move Number"
|
||||
msgstr "Numéro de pièce"
|
||||
|
||||
#. module: account_bank_reconciliation_summary_xlsx
|
||||
#: code:addons/account_bank_reconciliation_summary_xlsx/report/bank_reconciliation_xlsx.py:0
|
||||
#, python-format
|
||||
msgid "No bank journal selected."
|
||||
msgstr "Aucun journal de banque sélectionné."
|
||||
|
||||
#. module: account_bank_reconciliation_summary_xlsx
|
||||
#: code:addons/account_bank_reconciliation_summary_xlsx/report/bank_reconciliation_xlsx.py:0
|
||||
#, python-format
|
||||
msgid "None"
|
||||
msgstr "Aucun"
|
||||
|
||||
#. module: account_bank_reconciliation_summary_xlsx
|
||||
#: code:addons/account_bank_reconciliation_summary_xlsx/report/bank_reconciliation_xlsx.py:0
|
||||
#, python-format
|
||||
msgid "Partner"
|
||||
msgstr "Partenaire"
|
||||
|
||||
#. module: account_bank_reconciliation_summary_xlsx
|
||||
#: model:ir.model.fields.selection,name:account_bank_reconciliation_summary_xlsx.selection__bank_reconciliation_report_wizard__move_state__posted
|
||||
msgid "Posted Entries"
|
||||
msgstr "Écritures comptabilisées"
|
||||
|
||||
#. module: account_bank_reconciliation_summary_xlsx
|
||||
#: code:addons/account_bank_reconciliation_summary_xlsx/report/bank_reconciliation_xlsx.py:0
|
||||
#, python-format
|
||||
msgid "Ref."
|
||||
msgstr "Réf."
|
||||
|
||||
#. module: account_bank_reconciliation_summary_xlsx
|
||||
#: code:addons/account_bank_reconciliation_summary_xlsx/report/bank_reconciliation_xlsx.py:0
|
||||
#, python-format
|
||||
msgid "Sub-total:"
|
||||
msgstr "Sous-total :"
|
||||
|
||||
#. module: account_bank_reconciliation_summary_xlsx
|
||||
#: code:addons/account_bank_reconciliation_summary_xlsx/report/bank_reconciliation_xlsx.py:0
|
||||
#, python-format
|
||||
msgid "TOTAL:"
|
||||
msgstr "TOTAL :"
|
||||
@@ -0,0 +1 @@
|
||||
from . import bank_reconciliation_xlsx
|
||||
@@ -0,0 +1,296 @@
|
||||
# Copyright 2017-2023 Akretion France (http://www.akretion.com/)
|
||||
# @author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import _, models
|
||||
from odoo.exceptions import UserError
|
||||
from datetime import datetime
|
||||
from odoo.tools.misc import format_datetime
|
||||
import pytz
|
||||
|
||||
|
||||
class BankReconciliationXlsx(models.AbstractModel):
|
||||
_name = "report.bank.reconciliation.xlsx"
|
||||
_description = "Bank Reconciliation XLSX Report"
|
||||
_inherit = "report.report_xlsx.abstract"
|
||||
|
||||
def _domain_add_move_state(self, wizard, domain):
|
||||
if wizard.move_state == 'posted':
|
||||
domain.append(('parent_state', '=', 'posted'))
|
||||
elif wizard.move_state == 'draft_posted':
|
||||
domain.append(('parent_state', 'in', ('draft', 'posted')))
|
||||
|
||||
def _get_account_balance(self, account, wizard):
|
||||
domain = [
|
||||
('account_id', '=', account.id),
|
||||
('date', '<=', wizard.date),
|
||||
('company_id', '=', wizard.company_id.id),
|
||||
]
|
||||
self._domain_add_move_state(wizard, domain)
|
||||
res_rg = self.env['account.move.line'].read_group(domain, ['balance:sum'], [])
|
||||
account_bal = res_rg and res_rg[0].get('balance', 0.0) or 0.0
|
||||
return account_bal
|
||||
|
||||
def _prepare_payment_move_lines(self, journal, account, wizard, unreconciled_only=True):
|
||||
domain = [
|
||||
("company_id", "=", wizard.company_id.id),
|
||||
("account_id", "=", account.id),
|
||||
("journal_id", "=", journal.id),
|
||||
("date", "<=", wizard.date),
|
||||
]
|
||||
if unreconciled_only:
|
||||
limit_datetime_naive = datetime.combine(wizard.date, datetime.max.time())
|
||||
tz = pytz.timezone(self.env.user.tz)
|
||||
limit_datetime_aware = tz.localize(limit_datetime_naive)
|
||||
limit_datetime_utc = limit_datetime_aware.astimezone(pytz.utc)
|
||||
limit_datetime = limit_datetime_utc.replace(tzinfo=None)
|
||||
domain += [
|
||||
'|', ('full_reconcile_id', '=', False),
|
||||
('full_reconcile_id.create_date', '>', limit_datetime)]
|
||||
self._domain_add_move_state(wizard, domain)
|
||||
mlines = self.env["account.move.line"].search(domain)
|
||||
res = []
|
||||
for mline in mlines:
|
||||
move = mline.move_id
|
||||
cpart = []
|
||||
for line in move.line_ids:
|
||||
if (
|
||||
line.account_id != account
|
||||
and line.account_id.code not in cpart
|
||||
):
|
||||
cpart.append(line.account_id.code)
|
||||
counterpart = " ,".join(cpart)
|
||||
res.append(
|
||||
{
|
||||
"date": mline.date,
|
||||
"ref": move.ref or "",
|
||||
"label": mline.name,
|
||||
"partner": mline.partner_id.display_name or "",
|
||||
"amount": mline.balance,
|
||||
"move_name": move.name,
|
||||
"counterpart": counterpart,
|
||||
}
|
||||
)
|
||||
return res
|
||||
|
||||
def _write_move_lines_block(self, jdi, row, account, add2total=True):
|
||||
sheet = jdi['sheet']
|
||||
style = jdi['style']
|
||||
style_suffix = not add2total and '_warn' or ''
|
||||
subtotal = 0.0
|
||||
mlines = self._prepare_payment_move_lines(jdi['journal'], account, jdi['wizard'])
|
||||
if mlines or add2total:
|
||||
sheet.write(row, 0, '%s %s' % (account.name, account.code), style['title' + style_suffix])
|
||||
sheet.write(row, 1, "", style['title' + style_suffix])
|
||||
|
||||
if not mlines:
|
||||
if add2total:
|
||||
sheet.write(row, 2, _("None"), style['none'])
|
||||
else:
|
||||
return
|
||||
else:
|
||||
row += 1
|
||||
col_labels = [
|
||||
_("Date"),
|
||||
_("Partner"),
|
||||
_("Amount"),
|
||||
_("Move Number"),
|
||||
_("Counter-part"),
|
||||
_("Ref."),
|
||||
_("Label"),
|
||||
]
|
||||
col = 0
|
||||
for col_label in col_labels:
|
||||
sheet.write(row, col, col_label, style['col_header'])
|
||||
col += 1
|
||||
row += 1
|
||||
start_line = row + 1
|
||||
for mline in mlines:
|
||||
sheet.write(row, 0, mline["date"], style['regular_date'])
|
||||
sheet.write(row, 1, mline["partner"], style['regular'])
|
||||
sheet.write(row, 2, mline["amount"], style['currency'])
|
||||
sheet.write(row, 3, mline["move_name"], style['regular'])
|
||||
sheet.write(row, 4, mline["counterpart"], style['regular'])
|
||||
sheet.write(row, 5, mline["ref"], style['regular'])
|
||||
sheet.write(row, 6, mline["label"], style['regular'])
|
||||
subtotal += mline["amount"]
|
||||
row += 1
|
||||
end_line = row
|
||||
|
||||
for col in range(1):
|
||||
sheet.write(row, col, "", style['title' + style_suffix])
|
||||
sheet.write(row, 1, _("Sub-total:") + ' ', style['title_right' + style_suffix])
|
||||
|
||||
formula = '=SUM(%s%d:%s%d)' % (
|
||||
jdi['total_col'], start_line, jdi['total_col'], end_line)
|
||||
sheet.write_formula(row, 2, formula, style['currency_bg' + style_suffix], subtotal)
|
||||
if add2total:
|
||||
jdi['total'] += subtotal
|
||||
jdi['total_formula'] += '+%s%d' % (jdi['total_col'], row + 1)
|
||||
return row
|
||||
|
||||
def generate_xlsx_report(self, workbook, data, wizard):
|
||||
if not wizard.journal_ids:
|
||||
raise UserError(_("No bank journal selected."))
|
||||
date_dt = wizard.date
|
||||
company = wizard.company_id
|
||||
style = self._get_style(workbook, company)
|
||||
move_state_label = dict(
|
||||
wizard.fields_get('move_state', 'selection')['move_state']['selection'])
|
||||
generated_on_label = _('Generated on %s') % format_datetime(
|
||||
self.env, datetime.utcnow())
|
||||
for journal in wizard.journal_ids:
|
||||
row = 0
|
||||
sheet = workbook.add_worksheet(journal.code or journal.name)
|
||||
jdi = {
|
||||
'wizard': wizard,
|
||||
'journal': journal,
|
||||
'style': style,
|
||||
'sheet': sheet,
|
||||
'total': 0.0,
|
||||
'total_formula': '=',
|
||||
'total_col': 'C',
|
||||
}
|
||||
sheet.write(
|
||||
row,
|
||||
0,
|
||||
_("Bank Reconciliation Report"),
|
||||
style['doc_title'],
|
||||
)
|
||||
row += 1
|
||||
sheet.write(row, 0, generated_on_label, style['small'])
|
||||
sheet.set_row(0, 26)
|
||||
sheet.set_column(0, 0, 10)
|
||||
sheet.set_column(1, 1, 35)
|
||||
sheet.set_column(2, 2, 15)
|
||||
sheet.set_column(3, 3, 15)
|
||||
sheet.set_column(4, 4, 25)
|
||||
sheet.set_column(5, 5, 30)
|
||||
sheet.set_column(6, 6, 60)
|
||||
row += 3
|
||||
sheet.write(row, 0, _("Company"), style['wizard_field'])
|
||||
sheet.write(row, 1, wizard.company_id.display_name, style['wizard_value'])
|
||||
row += 1
|
||||
sheet.write(row, 0, _("Date"), style['wizard_field'])
|
||||
sheet.write(row, 1, date_dt, style['wizard_value_date'])
|
||||
row += 1
|
||||
sheet.write(row, 0, _("Journal"), style['wizard_field'])
|
||||
sheet.write(row, 1, journal.display_name, style['wizard_value'])
|
||||
row += 1
|
||||
sheet.write(row, 0, _("Entries"), style['wizard_field'])
|
||||
sheet.write(row, 1, move_state_label[wizard.move_state], style['wizard_value'])
|
||||
|
||||
# 1) Show balance of bank account
|
||||
row += 3
|
||||
bank_account = journal.default_account_id
|
||||
for col in range(1):
|
||||
sheet.write(row, col, "", style['title'])
|
||||
sheet.write(row, 1, _("Balance %s:") % bank_account.code + ' ', style['title_right'])
|
||||
account_bal = self._get_account_balance(bank_account, wizard)
|
||||
|
||||
sheet.write(row, 2, account_bal, style['currency_bg'])
|
||||
jdi['total'] += account_bal
|
||||
jdi['total_formula'] += '%s%d' % (jdi['total_col'], row + 1)
|
||||
|
||||
row += 2
|
||||
# 2) Show payment lines IN (debit)
|
||||
debit_account = journal.payment_debit_account_id
|
||||
row = self._write_move_lines_block(jdi, row, debit_account)
|
||||
row += 2
|
||||
# 3) Show payment lines OUT (credit)
|
||||
credit_account = journal.payment_credit_account_id
|
||||
row = self._write_move_lines_block(jdi, row, credit_account)
|
||||
row += 2
|
||||
|
||||
for col in range(1):
|
||||
sheet.write(row, col, "", style['title'])
|
||||
sheet.write(row, 1, _("TOTAL:") + ' ', style['title_right'])
|
||||
sheet.write_formula(
|
||||
row, 2, jdi['total_formula'], style['currency_bg'], jdi['total'])
|
||||
row += 3
|
||||
|
||||
# 4) Show suspense account lines
|
||||
row = self._write_move_lines_block(
|
||||
jdi, row, journal.suspense_account_id, add2total=False)
|
||||
|
||||
def _get_style(self, workbook, company):
|
||||
style = {}
|
||||
font_size = 10
|
||||
light_grey = "#eeeeee"
|
||||
title_blue = "#e6e6fa"
|
||||
subtotal_orange = "#ffcc00"
|
||||
title_warn = "#ff9999"
|
||||
subtotal_warn = "#ffff99"
|
||||
light_purple = "#ffdeff"
|
||||
lang_code = self.env.user.lang
|
||||
lang = False
|
||||
if lang_code:
|
||||
lang = self.env["res.lang"].search([("code", "=", lang_code)])
|
||||
if not lang:
|
||||
lang = self.env["res.lang"].search([], limit=1)
|
||||
xls_date_format = (
|
||||
lang.date_format.replace("%Y", "yyyy")
|
||||
.replace("%m", "mm")
|
||||
.replace("%d", "dd")
|
||||
.replace("%y", "yy")
|
||||
)
|
||||
|
||||
style['doc_title'] = workbook.add_format(
|
||||
{"bold": True, "font_size": font_size + 4})
|
||||
style['small'] = workbook.add_format({"font_size": font_size - 3})
|
||||
style['col_header'] = workbook.add_format(
|
||||
{
|
||||
"bold": True,
|
||||
"bg_color": light_grey,
|
||||
"text_wrap": True,
|
||||
"font_size": font_size,
|
||||
"align": "center",
|
||||
}
|
||||
)
|
||||
title_style = {
|
||||
"bold": True,
|
||||
"bg_color": title_blue,
|
||||
"font_size": font_size,
|
||||
"align": "left",
|
||||
}
|
||||
style['title_right'] = workbook.add_format(dict(title_style, align="right"))
|
||||
style['title'] = workbook.add_format(dict(title_style))
|
||||
style['wizard_field'] = workbook.add_format(dict(title_style, bg_color=light_grey))
|
||||
wizard_value_style = {
|
||||
"bg_color": light_purple,
|
||||
"bold": True,
|
||||
"font_size": font_size,
|
||||
"align": "left",
|
||||
}
|
||||
|
||||
style['wizard_value'] = workbook.add_format(wizard_value_style)
|
||||
style['wizard_value_date'] = workbook.add_format(
|
||||
dict(wizard_value_style, num_format=xls_date_format))
|
||||
style['none'] = workbook.add_format(
|
||||
{"bold": True, "font_size": font_size, "align": "right", "bg_color": subtotal_orange}
|
||||
)
|
||||
# WARN for suspense account
|
||||
style['title_warn'] = workbook.add_format(
|
||||
dict(title_style, align="left", bg_color=title_warn))
|
||||
style['title_right_warn'] = workbook.add_format(
|
||||
dict(title_style, align="right", bg_color=title_warn))
|
||||
style['regular'] = workbook.add_format({"font_size": font_size})
|
||||
if "%" in xls_date_format:
|
||||
# fallback
|
||||
xls_date_format = "yyyy-mm-dd"
|
||||
style['regular_date'] = workbook.add_format(
|
||||
{"num_format": xls_date_format, "font_size": font_size, "align": "left"}
|
||||
)
|
||||
cur_format = "#,##0.00 %s" % (
|
||||
company.currency_id.symbol or company.currency_id.name
|
||||
)
|
||||
# It seems that Excel replaces automatically the decimal
|
||||
# and thousand separator by those of the language under which
|
||||
# Excel runs
|
||||
currency_style = {"num_format": cur_format, "font_size": font_size}
|
||||
style['currency'] = workbook.add_format(currency_style)
|
||||
style['currency_bg'] = workbook.add_format(
|
||||
dict(currency_style, bg_color=subtotal_orange))
|
||||
style['currency_bg_warn'] = workbook.add_format(
|
||||
dict(currency_style, bg_color=subtotal_warn))
|
||||
return style
|
||||
18
account_bank_reconciliation_summary_xlsx/report/report.xml
Normal file
18
account_bank_reconciliation_summary_xlsx/report/report.xml
Normal file
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<!--
|
||||
Copyright 2017-2023 Akretion France (http://www.akretion.com/)
|
||||
@author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
-->
|
||||
<odoo>
|
||||
|
||||
<record id="bank_reconciliation_xlsx" model="ir.actions.report">
|
||||
<field name="name">Bank Reconciliation XLSX</field>
|
||||
<field name="model">bank.reconciliation.report.wizard</field>
|
||||
<field name="report_type">xlsx</field>
|
||||
<field name="report_name">bank.reconciliation.xlsx</field>
|
||||
<field name="report_file">bank.reconciliation.xlsx</field>
|
||||
<!-- print_report_name doesn't work here... -->
|
||||
<field name="print_report_name">'bank_reconciliation-%s' % (object.date)</field>
|
||||
</record>
|
||||
</odoo>
|
||||
@@ -0,0 +1,3 @@
|
||||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_bank_reconciliation_report_wizard_user,Full access on bank.reconciliation.report.wizard,model_bank_reconciliation_report_wizard,account.group_account_user,1,1,1,1
|
||||
access_bank_reconciliation_report_wizard_readonly,Full access on bank.reconciliation.report.wizard,model_bank_reconciliation_report_wizard,account.group_account_readonly,1,1,1,1
|
||||
|
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<!--
|
||||
Copyright 2017-2020 Akretion France (http://www.akretion.com/)
|
||||
@author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
-->
|
||||
<odoo>
|
||||
<record id="view_bank_statement_form" model="ir.ui.view">
|
||||
<field name="name">bank_rec_summary.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_reprocess" position="after">
|
||||
<button
|
||||
name="%(bank_reconciliation_report_wizard_action)d"
|
||||
type="action"
|
||||
string="Bank Reconciliation Report"
|
||||
context="{'default_journal_ids': [journal_id]}"
|
||||
/>
|
||||
</button>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<!--
|
||||
Copyright 2018-2023 Akretion France (http://www.akretion.com/)
|
||||
@author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
-->
|
||||
<odoo>
|
||||
<!-- Accounting Dashboard -->
|
||||
<record id="account_journal_dashboard_kanban_view" model="ir.ui.view">
|
||||
<field
|
||||
name="name"
|
||||
>bank_reconciliation_summarry.account_journal_dashboard</field>
|
||||
<field name="model">account.journal</field>
|
||||
<field name="inherit_id" ref="account.account_journal_dashboard_kanban_view" />
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//a[@name='open_collect_money']/.." position="before">
|
||||
<div name="bank_reconciliation_report">
|
||||
<a
|
||||
role="menuitem"
|
||||
type="action"
|
||||
name="%(bank_reconciliation_report_wizard_action)d"
|
||||
context="{'default_journal_ids': [active_id]}"
|
||||
>Bank Reconciliation</a>
|
||||
</div>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
@@ -0,0 +1 @@
|
||||
from . import bank_reconciliation_report_wizard
|
||||
@@ -0,0 +1,42 @@
|
||||
# Copyright 2017-2023 Akretion France (http://www.akretion.com/)
|
||||
# @author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import api, fields, models
|
||||
|
||||
|
||||
class BankReconciliationReportWizard(models.TransientModel):
|
||||
_name = "bank.reconciliation.report.wizard"
|
||||
_description = "Bank Reconciliation Report Wizard"
|
||||
_check_company_auto = True
|
||||
|
||||
company_id = fields.Many2one(
|
||||
'res.company', string='Company',
|
||||
ondelete='cascade', required=True,
|
||||
default=lambda self: self.env.company)
|
||||
date = fields.Date(required=True, default=fields.Date.context_today)
|
||||
move_state = fields.Selection(
|
||||
[("posted", "Posted Entries"), ("draft_posted", "Draft and Posted Entries")],
|
||||
string="Entries",
|
||||
required=True,
|
||||
default="posted",
|
||||
)
|
||||
journal_ids = fields.Many2many(
|
||||
"account.journal",
|
||||
string="Bank Journals",
|
||||
domain="[('type', '=', 'bank'), ('company_id', '=', company_id)]",
|
||||
required=True,
|
||||
check_company=True,
|
||||
default=lambda self: self._default_journal_ids(),
|
||||
)
|
||||
|
||||
@api.model
|
||||
def _default_journal_ids(self):
|
||||
journals = self.env["account.journal"].search(
|
||||
[
|
||||
("type", "=", "bank"),
|
||||
("bank_account_id", "!=", False),
|
||||
("company_id", "=", self.env.company.id),
|
||||
]
|
||||
)
|
||||
return journals
|
||||
@@ -0,0 +1,49 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<!--
|
||||
Copyright 2017-2023 Akretion France (http://www.akretion.com/)
|
||||
@author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
-->
|
||||
<odoo>
|
||||
<record id="bank_reconciliation_report_wizard_form" model="ir.ui.view">
|
||||
<field name="name">bank.reconciliation.report.wizard.form</field>
|
||||
<field name="model">bank.reconciliation.report.wizard</field>
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<group name="main">
|
||||
<field name="company_id" invisible="1" />
|
||||
<field name="date" />
|
||||
<field name="journal_ids" widget="many2many_tags" options="{'no_open': True, 'no_create': True}"/>
|
||||
<field name="move_state" widget="radio"/>
|
||||
</group>
|
||||
<footer>
|
||||
<button
|
||||
name="%(account_bank_reconciliation_summary_xlsx.bank_reconciliation_xlsx)d"
|
||||
string="Export XLSX"
|
||||
type="action"
|
||||
class="btn-primary"
|
||||
/>
|
||||
<button special="cancel" string="Cancel" />
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
<record id="bank_reconciliation_report_wizard_action" model="ir.actions.act_window">
|
||||
<field name="name">Bank Reconciliation</field>
|
||||
<field name="res_model">bank.reconciliation.report.wizard</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
<menuitem
|
||||
id="menu_report_bank_root"
|
||||
parent="account.menu_finance_reports"
|
||||
name="Bank Reports"
|
||||
sequence="12"
|
||||
/>
|
||||
<menuitem
|
||||
id="bank_reconciliation_report_wizard_menu"
|
||||
action="bank_reconciliation_report_wizard_action"
|
||||
parent="menu_report_bank_root"
|
||||
sequence="10"
|
||||
/>
|
||||
</odoo>
|
||||
@@ -0,0 +1,243 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * account_invoice_update_wizard
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server 14.0\n"
|
||||
"Report-Msgid-Bugs-To: \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"
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_line_update__price_subtotal
|
||||
msgid "Amount"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_line_update__analytic_account_id
|
||||
msgid "Analytic Account"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_line_update__analytic_tag_ids
|
||||
msgid "Analytic Tags"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_update__partner_bank_id
|
||||
msgid "Bank Account"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model_terms:ir.ui.view,arch_db:account_invoice_update_wizard.account_invoice_update_form
|
||||
msgid "Bill Reference"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model_terms:ir.ui.view,arch_db:account_invoice_update_wizard.account_invoice_update_form
|
||||
msgid "Cancel"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_update__company_id
|
||||
msgid "Company"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_line_update__create_uid
|
||||
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_update__create_uid
|
||||
msgid "Created by"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_line_update__create_date
|
||||
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_update__create_date
|
||||
msgid "Created on"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_line_update__currency_id
|
||||
msgid "Currency"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model_terms:ir.ui.view,arch_db:account_invoice_update_wizard.account_invoice_update_form
|
||||
msgid "Customer Reference"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_line_update__name
|
||||
msgid "Description"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move__display_name
|
||||
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_line_update__display_name
|
||||
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_update__display_name
|
||||
msgid "Display Name"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_line_update__display_type
|
||||
msgid "Display Type"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move__id
|
||||
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_line_update__id
|
||||
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_update__id
|
||||
msgid "ID"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_update__invoice_id
|
||||
msgid "Invoice"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_line_update__invoice_line_id
|
||||
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_update__line_ids
|
||||
msgid "Invoice Lines"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model:ir.actions.act_window,name:account_invoice_update_wizard.account_invoice_update_action
|
||||
msgid "Invoice Update Wizard"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model:ir.model,name:account_invoice_update_wizard.model_account_move
|
||||
msgid "Journal Entry"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move____last_update
|
||||
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_line_update____last_update
|
||||
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_update____last_update
|
||||
msgid "Last Modified on"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_line_update__write_uid
|
||||
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_update__write_uid
|
||||
msgid "Last Updated by"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_line_update__write_date
|
||||
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_update__write_date
|
||||
msgid "Last Updated on"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: code:addons/account_invoice_update_wizard/wizard/account_move_update.py:0
|
||||
#, python-format
|
||||
msgid "Non-legal fields of invoice updated via the Invoice Update wizard."
|
||||
msgstr ""
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model:ir.model.fields.selection,name:account_invoice_update_wizard.selection__account_move_line_update__display_type__line_note
|
||||
msgid "Note"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_update__partner_id
|
||||
msgid "Partner"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_update__invoice_payment_term_id
|
||||
msgid "Payment Term"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_line_update__quantity
|
||||
msgid "Quantity"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_update__ref
|
||||
msgid "Reference"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_update__user_id
|
||||
msgid "Salesperson"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model:ir.model.fields.selection,name:account_invoice_update_wizard.selection__account_move_line_update__display_type__line_section
|
||||
msgid "Section"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_line_update__sequence
|
||||
msgid "Sequence"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_update__invoice_origin
|
||||
msgid "Source Document"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model:ir.model.fields,help:account_invoice_update_wizard.field_account_move_line_update__display_type
|
||||
msgid "Technical field for UX purpose."
|
||||
msgstr ""
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: code:addons/account_invoice_update_wizard/wizard/account_move_update.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"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."
|
||||
msgstr ""
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: code:addons/account_invoice_update_wizard/wizard/account_move_update.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"This wizard doesn't support the update of payment terms on an invoice which "
|
||||
"is partially or fully paid."
|
||||
msgstr ""
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_update__move_type
|
||||
msgid "Type"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model_terms:ir.ui.view,arch_db:account_invoice_update_wizard.account_invoice_update_form
|
||||
msgid "Update"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model_terms:ir.ui.view,arch_db:account_invoice_update_wizard.view_move_form_inherit
|
||||
msgid "Update Invoice"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model_terms:ir.ui.view,arch_db:account_invoice_update_wizard.account_invoice_update_form
|
||||
msgid "Update Invoice Wizard"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model:ir.model,name:account_invoice_update_wizard.model_account_move_line_update
|
||||
msgid "Update non-legal fields of invoice lines"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_line_update__parent_id
|
||||
msgid "Wizard"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model:ir.model,name:account_invoice_update_wizard.model_account_move_update
|
||||
msgid "Wizard to update non-legal fields of invoice"
|
||||
msgstr ""
|
||||
250
account_invoice_update_wizard/i18n/fr.po
Normal file
250
account_invoice_update_wizard/i18n/fr.po
Normal file
@@ -0,0 +1,250 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * account_invoice_update_wizard
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server 14.0\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: \n"
|
||||
"Language: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Plural-Forms: \n"
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_line_update__price_subtotal
|
||||
msgid "Amount"
|
||||
msgstr "Montant"
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_line_update__analytic_account_id
|
||||
msgid "Analytic Account"
|
||||
msgstr "Compte Analytique"
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_line_update__analytic_tag_ids
|
||||
msgid "Analytic Tags"
|
||||
msgstr "Tag Analytique"
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_update__partner_bank_id
|
||||
msgid "Bank Account"
|
||||
msgstr "Compte Bancaire"
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model_terms:ir.ui.view,arch_db:account_invoice_update_wizard.account_invoice_update_form
|
||||
#, fuzzy
|
||||
msgid "Bill Reference"
|
||||
msgstr "Reference Client"
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model_terms:ir.ui.view,arch_db:account_invoice_update_wizard.account_invoice_update_form
|
||||
msgid "Cancel"
|
||||
msgstr "Annuler"
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_update__company_id
|
||||
msgid "Company"
|
||||
msgstr "Société"
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_line_update__create_uid
|
||||
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_update__create_uid
|
||||
msgid "Created by"
|
||||
msgstr "Créé par"
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_line_update__create_date
|
||||
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_update__create_date
|
||||
msgid "Created on"
|
||||
msgstr "Créé le"
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_line_update__currency_id
|
||||
msgid "Currency"
|
||||
msgstr "Devise"
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model_terms:ir.ui.view,arch_db:account_invoice_update_wizard.account_invoice_update_form
|
||||
#, fuzzy
|
||||
msgid "Customer Reference"
|
||||
msgstr "Reference Client"
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_line_update__name
|
||||
msgid "Description"
|
||||
msgstr "Description"
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move__display_name
|
||||
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_line_update__display_name
|
||||
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_update__display_name
|
||||
msgid "Display Name"
|
||||
msgstr "Nom"
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_line_update__display_type
|
||||
msgid "Display Type"
|
||||
msgstr "Type Affichage"
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move__id
|
||||
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_line_update__id
|
||||
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_update__id
|
||||
msgid "ID"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_update__invoice_id
|
||||
msgid "Invoice"
|
||||
msgstr "Facture"
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_line_update__invoice_line_id
|
||||
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_update__line_ids
|
||||
msgid "Invoice Lines"
|
||||
msgstr "Ligne de factures"
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model:ir.actions.act_window,name:account_invoice_update_wizard.account_invoice_update_action
|
||||
msgid "Invoice Update Wizard"
|
||||
msgstr "Assistance de mise à jour de la facture"
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model:ir.model,name:account_invoice_update_wizard.model_account_move
|
||||
msgid "Journal Entry"
|
||||
msgstr "Entrée comptable"
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move____last_update
|
||||
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_line_update____last_update
|
||||
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_update____last_update
|
||||
msgid "Last Modified on"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_line_update__write_uid
|
||||
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_update__write_uid
|
||||
msgid "Last Updated by"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_line_update__write_date
|
||||
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_update__write_date
|
||||
msgid "Last Updated on"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: code:addons/account_invoice_update_wizard/wizard/account_move_update.py:0
|
||||
#, python-format
|
||||
msgid "Non-legal fields of invoice updated via the Invoice Update wizard."
|
||||
msgstr "Champs non légaux mis à jour via l'assistant"
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model:ir.model.fields.selection,name:account_invoice_update_wizard.selection__account_move_line_update__display_type__line_note
|
||||
msgid "Note"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_update__partner_id
|
||||
msgid "Partner"
|
||||
msgstr "Client"
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_update__invoice_payment_term_id
|
||||
msgid "Payment Term"
|
||||
msgstr "Condition de paiement"
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_line_update__quantity
|
||||
msgid "Quantity"
|
||||
msgstr "Quantité"
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_update__ref
|
||||
#, fuzzy
|
||||
msgid "Reference"
|
||||
msgstr "Reference Client"
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_update__user_id
|
||||
msgid "Salesperson"
|
||||
msgstr "Vendeur"
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model:ir.model.fields.selection,name:account_invoice_update_wizard.selection__account_move_line_update__display_type__line_section
|
||||
msgid "Section"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_line_update__sequence
|
||||
msgid "Sequence"
|
||||
msgstr "Sequence"
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_update__invoice_origin
|
||||
msgid "Source Document"
|
||||
msgstr "Origine du document"
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model:ir.model.fields,help:account_invoice_update_wizard.field_account_move_line_update__display_type
|
||||
msgid "Technical field for UX purpose."
|
||||
msgstr ""
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: code:addons/account_invoice_update_wizard/wizard/account_move_update.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"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."
|
||||
msgstr ""
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: code:addons/account_invoice_update_wizard/wizard/account_move_update.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"This wizard doesn't support the update of payment terms on an invoice which "
|
||||
"is partially or fully paid."
|
||||
msgstr ""
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_update__move_type
|
||||
msgid "Type"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model_terms:ir.ui.view,arch_db:account_invoice_update_wizard.account_invoice_update_form
|
||||
msgid "Update"
|
||||
msgstr "Mettre à jour"
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model_terms:ir.ui.view,arch_db:account_invoice_update_wizard.view_move_form_inherit
|
||||
msgid "Update Invoice"
|
||||
msgstr "Mettre à jour"
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model_terms:ir.ui.view,arch_db:account_invoice_update_wizard.account_invoice_update_form
|
||||
msgid "Update Invoice Wizard"
|
||||
msgstr "Assistant de mise à jour"
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model:ir.model,name:account_invoice_update_wizard.model_account_move_line_update
|
||||
msgid "Update non-legal fields of invoice lines"
|
||||
msgstr "Mettre à jour les champs non légaux des lignes de facture"
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_line_update__parent_id
|
||||
msgid "Wizard"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_invoice_update_wizard
|
||||
#: model:ir.model,name:account_invoice_update_wizard.model_account_move_update
|
||||
msgid "Wizard to update non-legal fields of invoice"
|
||||
msgstr "Assistant pour mettre à jours les champs non légaux"
|
||||
|
||||
#~ msgid "Account"
|
||||
#~ msgstr "Compte"
|
||||
@@ -48,6 +48,7 @@ class AccountMoveUpdate(models.TransientModel):
|
||||
aa_tags = [(6, 0, aa_tags.ids)] if aa_tags else False
|
||||
res['line_ids'].append([0, 0, {
|
||||
'invoice_line_id': line.id,
|
||||
'sequence': line.sequence,
|
||||
'name': line.name,
|
||||
'quantity': line.quantity,
|
||||
'price_subtotal': line.price_subtotal,
|
||||
@@ -231,7 +232,9 @@ class AccountMoveUpdate(models.TransientModel):
|
||||
class AccountMoveLineUpdate(models.TransientModel):
|
||||
_name = 'account.move.line.update'
|
||||
_description = 'Update non-legal fields of invoice lines'
|
||||
_order = "sequence, name"
|
||||
|
||||
sequence = fields.Integer()
|
||||
parent_id = fields.Many2one(
|
||||
'account.move.update', string='Wizard', ondelete='cascade')
|
||||
invoice_line_id = fields.Many2one(
|
||||
|
||||
@@ -18,12 +18,13 @@
|
||||
<field string="Bill Reference" attrs="{'invisible': [('move_type', 'not in', ('in_invoice', 'in_refund'))]}" name="ref"/>
|
||||
<field string="Customer Reference" attrs="{'invisible': [('move_type', 'not in', ('out_invoice', 'out_refund'))]}" name="ref"/>
|
||||
<field name="invoice_origin"/>
|
||||
<field name="invoice_payment_term_id" widget="selection"/>
|
||||
<!-- update of payment term is broken -->
|
||||
<!-- <field name="invoice_payment_term_id" widget="selection"/>-->
|
||||
<field name="partner_bank_id"/>
|
||||
<field name="user_id" options="{'no_open': True, 'no_create': True, 'no_create_edit': True}"/>
|
||||
</group>
|
||||
<group name="lines">
|
||||
<field name="line_ids" nolabel="1">
|
||||
<field name="line_ids" nolabel="1" widget="section_and_note_one2many">
|
||||
<tree editable="bottom" create="false" delete="false" edit="true">
|
||||
<field name="invoice_line_id" invisible="1"/>
|
||||
<field name="display_type" invisible="1"/>
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<field name="model">account.move.update</field>
|
||||
<field name="inherit_id" ref="account_invoice_update_wizard.account_invoice_update_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="invoice_payment_term_id" position="after">
|
||||
<field name="partner_bank_id" position="before">
|
||||
<field name="payment_mode_filter_type_domain" invisible="1"/>
|
||||
<field name="partner_bank_filter_type_domain" invisible="1"/>
|
||||
<field name="bank_account_required" invisible="1"/>
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
from . import models
|
||||
from . import wizard
|
||||
from .hooks import post_init_hook
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
{
|
||||
'name': 'Account Usability',
|
||||
'version': '14.0.1.0.0',
|
||||
'version': '14.0.1.1.0',
|
||||
'category': 'Accounting & Finance',
|
||||
'license': 'AGPL-3',
|
||||
'summary': 'Small usability enhancements in account module',
|
||||
@@ -29,7 +29,6 @@
|
||||
'views/account_tax.xml',
|
||||
'views/product.xml',
|
||||
'views/res_config_settings.xml',
|
||||
'views/res_partner.xml',
|
||||
'views/res_company.xml',
|
||||
'views/account_report.xml',
|
||||
'views/account_reconcile_model.xml',
|
||||
@@ -41,4 +40,5 @@
|
||||
],
|
||||
'qweb': ['static/src/xml/account_payment.xml'],
|
||||
'installable': True,
|
||||
"post_init_hook": "post_init_hook",
|
||||
}
|
||||
|
||||
9
account_usability/hooks.py
Normal file
9
account_usability/hooks.py
Normal file
@@ -0,0 +1,9 @@
|
||||
# Copyright 2022 Akretion (https://www.akretion.com).
|
||||
# @author Sébastien BEAU <sebastien.beau@akretion.com>
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import SUPERUSER_ID, api
|
||||
|
||||
def post_init_hook(cr, registry):
|
||||
env = api.Environment(cr, SUPERUSER_ID, {})
|
||||
env["account.move.line"].update_matching_number()
|
||||
@@ -524,11 +524,6 @@ msgstr ""
|
||||
msgid "Recipient Bank"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_usability
|
||||
#: model:ir.model.fields,field_description:account_usability.field_account_move_line__reconcile_string
|
||||
msgid "Reconcile"
|
||||
msgstr ""
|
||||
|
||||
#. module: account_usability
|
||||
#: model:ir.model.fields,field_description:account_usability.field_account_bank_statement_line__ref
|
||||
#: model:ir.model.fields,field_description:account_usability.field_account_move__ref
|
||||
|
||||
9
account_usability/migrations/14.0.1.1.0/post-migrate.py
Normal file
9
account_usability/migrations/14.0.1.1.0/post-migrate.py
Normal file
@@ -0,0 +1,9 @@
|
||||
# Copyright 2020 ACSONE SA/NV
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import SUPERUSER_ID, api
|
||||
|
||||
|
||||
def migrate(cr, version):
|
||||
env = api.Environment(cr, SUPERUSER_ID, {})
|
||||
env["account.move.line"].update_matching_number()
|
||||
@@ -2,12 +2,16 @@
|
||||
# @author Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from datetime import timedelta
|
||||
import logging
|
||||
|
||||
from odoo import api, fields, models, _
|
||||
from odoo.exceptions import UserError
|
||||
from odoo.osv import expression
|
||||
from odoo.tools import float_is_zero
|
||||
from odoo.tools.misc import format_date
|
||||
from odoo.osv import expression
|
||||
from datetime import timedelta
|
||||
from odoo.exceptions import UserError
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class AccountMove(models.Model):
|
||||
@@ -108,6 +112,16 @@ class AccountMove(models.Model):
|
||||
# self.invalidate_cache()
|
||||
# return res
|
||||
|
||||
def _reverse_moves(self, default_values_list=None, cancel=False):
|
||||
reverse_moves = super()._reverse_moves(
|
||||
default_values_list=default_values_list, cancel=cancel)
|
||||
# In the simple scenario 1 invoice -> 1 refund, we add a message in the chatter
|
||||
# of the invoice and in the chatter of the refund
|
||||
if len(self) == 1 and len(reverse_moves) == 1:
|
||||
self.message_post(body=_("A reverse journal entry <a href=# data-oe-model=account.move data-oe-id=%d>%s</a> has been generated.") % (reverse_moves.id, reverse_moves.display_name))
|
||||
reverse_moves.message_post(body=_("This journal entry has been generated as the reverse of <a href=# data-oe-model=account.move data-oe-id=%d>%s</a>.") % (self.id, self.display_name))
|
||||
return reverse_moves
|
||||
|
||||
def delete_lines_qty_zero(self):
|
||||
lines = self.env['account.move.line'].search([
|
||||
('display_type', '=', False),
|
||||
@@ -238,8 +252,6 @@ class AccountMoveLine(models.Model):
|
||||
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)
|
||||
# for optional display in tree view
|
||||
product_barcode = fields.Char(related='product_id.barcode', string="Product Barcode")
|
||||
|
||||
@@ -255,17 +267,26 @@ class AccountMoveLine(models.Model):
|
||||
})
|
||||
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
|
||||
def update_matching_number(self):
|
||||
records = self.search([("matching_number", "=", "P")])
|
||||
_logger.info(f"Update partial reconcile number for {len(records)} lines")
|
||||
records.compute_partial_matching_number()
|
||||
|
||||
def compute_partial_matching_number(self):
|
||||
# TODO maybe it will be better to have the same maching_number for
|
||||
# all partial so it will be easier to group by
|
||||
for record in self:
|
||||
if record.matching_number == "P":
|
||||
matching_number = ", ".join([
|
||||
"a%d" % pr.id
|
||||
for pr in record.matched_debit_ids + record.matched_credit_ids
|
||||
])
|
||||
# use sql to avoid triggering python checks
|
||||
self.env.cr.execute(
|
||||
"""
|
||||
UPDATE account_move_line SET matching_number = %s WHERE id = %s
|
||||
""", (matching_number, record.id)
|
||||
)
|
||||
|
||||
def _get_computed_name(self):
|
||||
# This is useful when you want to have the product code in a dedicated
|
||||
|
||||
@@ -13,6 +13,9 @@
|
||||
<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_reopen" position="attributes">
|
||||
<attribute name="confirm">Are you sure ? Don't do 'Reset to New' if you just want to modify the bank journal entry of an existing statement line.</attribute>
|
||||
</button>
|
||||
<button name="button_reopen" position="after">
|
||||
<button
|
||||
name="button_undo_reconciliation"
|
||||
|
||||
@@ -42,8 +42,7 @@
|
||||
<attribute name="optional">show</attribute>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='line_ids']/tree/field[@name='tax_tag_ids']" position="after">
|
||||
<field name="matching_number" optional="hide"/>
|
||||
<field name="reconcile_string" optional="show"/>
|
||||
<field name="matching_number" optional="show"/>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='invoice_line_ids']/tree/field[@name='product_id']" position="after">
|
||||
<field name="product_barcode" optional="hide"/>
|
||||
@@ -106,7 +105,7 @@
|
||||
<separator/>
|
||||
</filter>
|
||||
<field name="partner_id" position="after">
|
||||
<field name="reconcile_string" />
|
||||
<field name="matching_number" />
|
||||
<field name="debit" filter_domain="['|', ('debit', '=', self), ('credit', '=', self)]" string="Debit or Credit"/>
|
||||
</field>
|
||||
<filter name="unreconciled" position="before">
|
||||
@@ -118,6 +117,9 @@
|
||||
<field name="name" position="attributes">
|
||||
<attribute name="string">Label, Reference, Account or Partner</attribute>
|
||||
</field>
|
||||
<field name="name" position="before">
|
||||
<field name="move_id" position="move"/>
|
||||
</field>
|
||||
<field name="partner_id" position="attributes">
|
||||
<attribute name="domain">['|', ('parent_id', '=', False), ('is_company', '=', True)]</attribute>
|
||||
</field>
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright 2017-2020 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">
|
||||
<xpath expr="//field[@name='bank_ids']/tree/field[@name='acc_number']" position="after">
|
||||
<field name="acc_type"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
</odoo>
|
||||
@@ -12,13 +12,14 @@ class AccountMoveReversal(models.TransientModel):
|
||||
|
||||
# Set default reversal date to original move + 1 day
|
||||
# and raise error if original move has already been reversed
|
||||
# WARNING: this wizard is also used to generate refunds
|
||||
@api.model
|
||||
def default_get(self, fields_list):
|
||||
res = super().default_get(fields_list)
|
||||
assert self._context.get('active_model') == 'account.move'
|
||||
amo = self.env['account.move']
|
||||
moves = amo.browse(self._context['active_ids'])
|
||||
if len(moves) == 1:
|
||||
if len(moves) == 1 and moves.move_type not in ('out_invoice', 'in_invoice'):
|
||||
res['date'] = moves.date + relativedelta(days=1)
|
||||
reversed_move = amo.search([('reversed_entry_id', 'in', moves.ids)], limit=1)
|
||||
if reversed_move:
|
||||
|
||||
@@ -19,4 +19,10 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- By default, the menu entry "CRM > Sales > My Activities" is limited to
|
||||
the sales Manager. The Sale user should be able to see it -->
|
||||
<record id="crm.crm_lead_menu_my_activities" model="ir.ui.menu">
|
||||
<field name="groups_id" eval="[(6, 0, [])]"/>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
{
|
||||
'name': 'Developer Menu',
|
||||
'version': '12.0.0.0.0',
|
||||
'category': 'Tools',
|
||||
'license': 'AGPL-3',
|
||||
'summary': "Menu Shortcut for developer usage",
|
||||
'description': """
|
||||
"name": "Developer Menu",
|
||||
"version": "14.0.0.0.0",
|
||||
"category": "Tools",
|
||||
"license": "AGPL-3",
|
||||
"summary": "Menu Shortcut for developer usage",
|
||||
"description": """
|
||||
Developer menu
|
||||
==============
|
||||
|
||||
@@ -21,11 +21,13 @@ near `Technical` menu
|
||||
This module has been written by David Béal
|
||||
from Akretion <david.beal@akretion.com>.
|
||||
""",
|
||||
'author': 'Akretion',
|
||||
'website': 'http://www.akretion.com',
|
||||
'depends': ['mail'],
|
||||
'data': [
|
||||
'menu_view.xml'
|
||||
"author": "Akretion",
|
||||
"website": "https://www.akretion.com",
|
||||
"depends": [
|
||||
"mail",
|
||||
],
|
||||
'installable': False,
|
||||
"data": [
|
||||
"menu_view.xml",
|
||||
],
|
||||
"installable": True,
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
<odoo>
|
||||
|
||||
<menuitem id="conf_tech" parent="base.menu_administration" name="🧰" groups="base.group_erp_manager" sequence="100"/>
|
||||
<menuitem id="conf_tech" parent="base.menu_administration" name="🧰" groups="base.group_erp_manager" sequence="1"/>
|
||||
<menuitem id="model" name="Model" parent="conf_tech" action="base.action_model_model" sequence="10"/>
|
||||
<menuitem id="view" name="View" parent="conf_tech" action="base.action_ui_view" sequence="20" />
|
||||
<menuitem id="rec_rule" name="Record Rule" parent="conf_tech" action="base.action_rule" sequence="30" />
|
||||
|
||||
@@ -10,7 +10,7 @@ def web_m2x_options_create(cr, registry):
|
||||
env = Environment(cr, SUPERUSER_ID, {})
|
||||
config_parameter = env['ir.config_parameter'].search(
|
||||
[('key', '=', 'web_m2x_options.create')])
|
||||
if config_parameter and config_parameter.value != 'False':
|
||||
if config_parameter:
|
||||
config_parameter.write({'value': 'False'})
|
||||
else:
|
||||
env['ir.config_parameter'].create({
|
||||
|
||||
@@ -23,7 +23,7 @@ Small usability improvements on mails:
|
||||
'website': 'http://www.akretion.com',
|
||||
'depends': ['mail'],
|
||||
'data': [
|
||||
#'views/mail_view.xml',
|
||||
'views/mail_activity.xml',
|
||||
#'data/mail_data.xml',
|
||||
#'wizard/email_template_preview_view.xml',
|
||||
#'wizard/mail_compose_message_view.xml',
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
from . import res_partner
|
||||
from . import mail_activity
|
||||
from . import mail_template
|
||||
|
||||
24
mail_usability/models/mail_activity.py
Normal file
24
mail_usability/models/mail_activity.py
Normal file
@@ -0,0 +1,24 @@
|
||||
# Copyright 2023 Akretion France (http://www.akretion.com).
|
||||
# @author Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class MailActivity(models.Model):
|
||||
_inherit = 'mail.activity'
|
||||
|
||||
res_model_name = fields.Char(related='res_model_id.name', string='Document Type')
|
||||
|
||||
def jump_to_record(self):
|
||||
self.ensure_one()
|
||||
action = {}
|
||||
if self.res_id and self.res_model and self.res_name:
|
||||
action.update({
|
||||
'type': 'ir.actions.act_window',
|
||||
'name': self.res_name,
|
||||
'res_model': self.res_model,
|
||||
'view_mode': 'form',
|
||||
'res_id': self.res_id,
|
||||
})
|
||||
return action
|
||||
52
mail_usability/views/mail_activity.xml
Normal file
52
mail_usability/views/mail_activity.xml
Normal file
@@ -0,0 +1,52 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright 2023 Akretion France (http://www.akretion.com/)
|
||||
@author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
-->
|
||||
|
||||
<odoo>
|
||||
|
||||
|
||||
<record id="mail_activity_view_search" model="ir.ui.view">
|
||||
<field name="model">mail.activity</field>
|
||||
<field name="inherit_id" ref="mail.mail_activity_view_search"/>
|
||||
<field name="arch" type="xml">
|
||||
<filter name="activities_upcoming_all" position="after">
|
||||
<separator/>
|
||||
<filter string="My Activities" domain="[('user_id', '=', uid)]" name="my_activities"/>
|
||||
</filter>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="mail_activity_view_tree" model="ir.ui.view">
|
||||
<field name="model">mail.activity</field>
|
||||
<field name="inherit_id" ref="mail.mail_activity_view_tree"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="summary" position="after">
|
||||
<field name="user_id" optional="show" widget="many2one_avatar_user"/>
|
||||
</field>
|
||||
<field name="res_name" position="before">
|
||||
<button name="jump_to_record" type="object" attrs="{'invisible': [('res_name', '=', False)]}" icon="fa-binoculars" string="Go to source" class="text-warning" invisible="not context.get('mail_activity_main_view')"/>
|
||||
</field>
|
||||
<field name="res_name" position="after">
|
||||
<field name="res_model_name" invisible="not context.get('mail_activity_main_view')"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="mail_activity_view_form_popup" model="ir.ui.view">
|
||||
<field name="model">mail.activity</field>
|
||||
<field name="inherit_id" ref="mail.mail_activity_view_form_popup"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="activity_type_id" position="before">
|
||||
<field name="res_name" invisible="not context.get('mail_activity_main_view')"/>
|
||||
<field name="res_model_name" invisible="not context.get('mail_activity_main_view')"/>
|
||||
</field>
|
||||
<button name="action_close_dialog" position="before">
|
||||
<button name="jump_to_record" type="object" attrs="{'invisible': [('res_id', '=', False)]}" class="btn-primary" string="Go to source" invisible="not context.get('mail_activity_main_view')"/>
|
||||
</button>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
@@ -48,7 +48,7 @@ class ProductTemplate(models.Model):
|
||||
_inherit = ['product.template', 'product.categ.tax.mixin']
|
||||
_name = 'product.template'
|
||||
|
||||
@api.constrains('taxes_id', 'supplier_taxes_id')
|
||||
@api.constrains('taxes_id', 'supplier_taxes_id', 'categ_id')
|
||||
def _check_tax_categ(self):
|
||||
# self.name != 'Pay Debt' is a stupid hack to avoid blocking the
|
||||
# installation of the module 'pos_debt_notebook'
|
||||
|
||||
2
product_detailed_type/__init__.py
Normal file
2
product_detailed_type/__init__.py
Normal file
@@ -0,0 +1,2 @@
|
||||
from . import models
|
||||
from .post_install import set_product_detailed_type
|
||||
19
product_detailed_type/__manifest__.py
Normal file
19
product_detailed_type/__manifest__.py
Normal file
@@ -0,0 +1,19 @@
|
||||
# Copyright 2023 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': 'Product Detailed Type',
|
||||
'version': '14.0.1.0.0',
|
||||
'category': 'Product',
|
||||
'license': 'LGPL-3',
|
||||
'summary': 'Backport detailed_type from v16 to v14',
|
||||
'author': 'Akretion',
|
||||
'website': 'https://github.com/akretion/odoo-usability',
|
||||
'depends': ['product'],
|
||||
'data': [
|
||||
'views/product.xml',
|
||||
],
|
||||
'post_init_hook': 'set_product_detailed_type',
|
||||
'installable': True,
|
||||
}
|
||||
1
product_detailed_type/models/__init__.py
Normal file
1
product_detailed_type/models/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from . import product_template
|
||||
25
product_detailed_type/models/product_template.py
Normal file
25
product_detailed_type/models/product_template.py
Normal file
@@ -0,0 +1,25 @@
|
||||
# Copyright 2023 Akretion France (http://www.akretion.com/)
|
||||
# Copyright 2023 Odoo SA (contains code copy-pasted from Odoo v16)
|
||||
# @author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import api, fields, models
|
||||
|
||||
|
||||
class ProductTemplate(models.Model):
|
||||
_inherit = 'product.template'
|
||||
|
||||
detailed_type = fields.Selection([
|
||||
('consu', 'Consumable'),
|
||||
('service', 'Service'),
|
||||
], string='Product Type', default='consu', required=True, tracking=True)
|
||||
type = fields.Selection(compute='_compute_type', store=True, string="Type")
|
||||
|
||||
def _detailed_type_mapping(self):
|
||||
return {}
|
||||
|
||||
@api.depends('detailed_type')
|
||||
def _compute_type(self):
|
||||
type_mapping = self._detailed_type_mapping()
|
||||
for record in self:
|
||||
record.type = type_mapping.get(record.detailed_type, record.detailed_type)
|
||||
7
product_detailed_type/post_install.py
Normal file
7
product_detailed_type/post_install.py
Normal file
@@ -0,0 +1,7 @@
|
||||
# Copyright 2023 Akretion France (http://www.akretion.com/)
|
||||
# @author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
|
||||
def set_product_detailed_type(cr, registry):
|
||||
cr.execute('UPDATE product_template SET detailed_type=type')
|
||||
47
product_detailed_type/views/product.xml
Normal file
47
product_detailed_type/views/product.xml
Normal file
@@ -0,0 +1,47 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright 2023 Akretion France (http://www.akretion.com/)
|
||||
@author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
-->
|
||||
|
||||
<odoo>
|
||||
|
||||
<record id="product_template_tree_view" model="ir.ui.view">
|
||||
<field name="model">product.template</field>
|
||||
<field name="inherit_id" ref="product.product_template_tree_view"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="type" position="after">
|
||||
<field name="detailed_type" optional="hide" readonly="1"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="product_template_form_view" model="ir.ui.view">
|
||||
<field name="model">product.template</field>
|
||||
<field name="inherit_id" ref="product.product_template_form_view"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="type" position="after">
|
||||
<field name="detailed_type"/>
|
||||
</field>
|
||||
<field name="type" position="attributes">
|
||||
<attribute name="invisible">1</attribute>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="product_template_search_view" model="ir.ui.view">
|
||||
<field name="model">product.template</field>
|
||||
<field name="inherit_id" ref="product.product_template_search_view"/>
|
||||
<field name="arch" type="xml">
|
||||
<filter name="type" position="attributes">
|
||||
<attribute name="invisible">1</attribute>
|
||||
</filter>
|
||||
<filter name="type" position="after">
|
||||
<filter name="detailed_type_groupby" string="Product Type" context="{'group_by': 'detailed_type'}"/>
|
||||
</filter>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
</odoo>
|
||||
1
product_detailed_type_stock/__init__.py
Normal file
1
product_detailed_type_stock/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from . import models
|
||||
16
product_detailed_type_stock/__manifest__.py
Normal file
16
product_detailed_type_stock/__manifest__.py
Normal file
@@ -0,0 +1,16 @@
|
||||
# Copyright 2023 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': 'Product Detailed Type Stock',
|
||||
'version': '14.0.1.0.0',
|
||||
'category': 'Product',
|
||||
'license': 'LGPL-3',
|
||||
'summary': 'Glue module between product_detailed_type and stock',
|
||||
'author': 'Akretion',
|
||||
'website': 'https://github.com/akretion/odoo-usability',
|
||||
'depends': ['product_detailed_type', 'stock'],
|
||||
'installable': True,
|
||||
'auto_install': True,
|
||||
}
|
||||
1
product_detailed_type_stock/models/__init__.py
Normal file
1
product_detailed_type_stock/models/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from . import product_template
|
||||
13
product_detailed_type_stock/models/product_template.py
Normal file
13
product_detailed_type_stock/models/product_template.py
Normal file
@@ -0,0 +1,13 @@
|
||||
# Copyright 2023 Akretion France (http://www.akretion.com/)
|
||||
# @author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class ProductTemplate(models.Model):
|
||||
_inherit = 'product.template'
|
||||
|
||||
detailed_type = fields.Selection(selection_add=[
|
||||
('product', 'Storable Product')
|
||||
], ondelete={'product': 'set default'})
|
||||
@@ -41,6 +41,7 @@ This module has been written by Alexis de Lattre from Akretion
|
||||
'barcodes',
|
||||
'base_report_to_printer',
|
||||
],
|
||||
'external_dependencies': {'python': ['python-barcode>=0.14.0']},
|
||||
'data': [
|
||||
'security/ir.model.access.csv',
|
||||
'wizard/product_print_zpl_barcode_view.xml',
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2020 Akretion France (http://www.akretion.com/)
|
||||
# Copyright 2020-2023 Akretion France (http://www.akretion.com/)
|
||||
# @author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import api, fields, models, _
|
||||
from odoo.exceptions import UserError
|
||||
from stdnum.ean import calc_check_digit
|
||||
from stdnum.ean import calc_check_digit, is_valid
|
||||
from barcode import EAN13, EAN8
|
||||
from barcode.writer import ImageWriter, SVGWriter
|
||||
import base64
|
||||
import io
|
||||
|
||||
|
||||
class ProductTemplate(models.Model):
|
||||
@@ -34,8 +37,8 @@ class ProductTemplate(models.Model):
|
||||
"print_zpl_barcode_from_product_template on product '%s' "
|
||||
"because it has %d variants and not just one.")
|
||||
% (self.display_name, self.product_variant_count))
|
||||
action = self.env.ref(
|
||||
'product_print_zpl_barcode.product_print_zpl_barcode_action').sudo().read()[0]
|
||||
action = self.env["ir.actions.actions"]._for_xml_id(
|
||||
'product_print_zpl_barcode.product_print_zpl_barcode_action')
|
||||
action['context'] = {
|
||||
'active_id': self.product_variant_ids[0].id,
|
||||
'active_model': 'product.product',
|
||||
@@ -46,6 +49,50 @@ class ProductTemplate(models.Model):
|
||||
class ProductProduct(models.Model):
|
||||
_inherit = 'product.product'
|
||||
|
||||
# Not useful for ZPL, but it is often useful to have a barcode image field
|
||||
barcode_image_png = fields.Binary(
|
||||
compute='_compute_barcode_image_png',
|
||||
string='PNG Barcode Image')
|
||||
barcode_image_svg = fields.Binary(
|
||||
compute='_compute_barcode_image_svg',
|
||||
string='SVG Barcode Image')
|
||||
|
||||
def _get_barcode_image(self, img_format):
|
||||
self.ensure_one()
|
||||
barcode = self.barcode
|
||||
if not barcode:
|
||||
return False
|
||||
res = False
|
||||
if isinstance(barcode, str) and len(barcode) in (8, 13) and is_valid(barcode):
|
||||
barcode_obj = False
|
||||
if img_format == 'svg':
|
||||
writer = SVGWriter()
|
||||
elif img_format == 'png':
|
||||
writer = ImageWriter()
|
||||
else:
|
||||
return False
|
||||
if len(barcode) == 13:
|
||||
barcode_obj = EAN13(barcode, writer=writer, guardbar=True)
|
||||
elif len(barcode) == 8:
|
||||
barcode_obj = EAN8(barcode, writer=writer, guardbar=True)
|
||||
if barcode_obj:
|
||||
barcode_file = io.BytesIO()
|
||||
barcode_obj.write(barcode_file)
|
||||
barcode_file.seek(0)
|
||||
barcode_img = barcode_file.read()
|
||||
res = base64.b64encode(barcode_img)
|
||||
return res
|
||||
|
||||
@api.depends('barcode')
|
||||
def _compute_barcode_image_svg(self):
|
||||
for product in self:
|
||||
product.barcode_image_svg = product._get_barcode_image('svg')
|
||||
|
||||
@api.depends('barcode')
|
||||
def _compute_barcode_image_png(self):
|
||||
for product in self:
|
||||
product.barcode_image_png = product._get_barcode_image('png')
|
||||
|
||||
def generate_barcode_from_product_product(self):
|
||||
self.ensure_one()
|
||||
if self.barcode:
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
from odoo import api, fields, models, _
|
||||
from odoo.exceptions import UserError
|
||||
from odoo.tools import float_compare, float_is_zero
|
||||
from stdnum.ean import is_valid
|
||||
from stdnum.ean import is_valid, calc_check_digit
|
||||
import base64
|
||||
import re
|
||||
|
||||
@@ -55,8 +55,7 @@ class ProductPrintZplBarcode(models.TransientModel):
|
||||
|
||||
product_id = fields.Many2one(
|
||||
'product.product', string='Product', required=True, readonly=True)
|
||||
uom_id = fields.Many2one(
|
||||
related='product_id.uom_id', readonly=True)
|
||||
uom_id = fields.Many2one(related='product_id.uom_id')
|
||||
# 1 line = un peu moins de 30
|
||||
product_name = fields.Char('Product Label', required=True, size=56)
|
||||
nomenclature_id = fields.Many2one(
|
||||
@@ -64,15 +63,13 @@ class ProductPrintZplBarcode(models.TransientModel):
|
||||
rule_id = fields.Many2one(
|
||||
'barcode.rule', string='Barcode Rule', readonly=True,
|
||||
compute='_compute_rule_id')
|
||||
barcode_type = fields.Selection(
|
||||
related='rule_id.type', readonly=True, string="Barcode Type")
|
||||
barcode_type = fields.Selection(related='rule_id.type', string="Barcode Type")
|
||||
label_size = fields.Selection([
|
||||
('38x25', '38x25 mm'),
|
||||
], required=True, default='38x25', string='Label Size')
|
||||
], required=True, default='38x25')
|
||||
pricelist_id = fields.Many2one(
|
||||
'product.pricelist', string='Pricelist', required=True)
|
||||
currency_id = fields.Many2one(
|
||||
related='pricelist_id.currency_id', readonly=True)
|
||||
currency_id = fields.Many2one(related='pricelist_id.currency_id')
|
||||
# TODO: for the moment, we only support weight, but...
|
||||
quantity = fields.Float(digits='Stock Weight')
|
||||
price_uom = fields.Monetary(
|
||||
@@ -140,14 +137,14 @@ class ProductPrintZplBarcode(models.TransientModel):
|
||||
"of the barcode pattern (%s).")
|
||||
% (pbarcode, len(pbarcode), len(prefix), prefix))
|
||||
barcode = pbarcode[0:len(prefix)]
|
||||
# print "barcode=", barcode
|
||||
# print "pattern=", pattern
|
||||
# print("barcode=", barcode)
|
||||
# print("pattern=", pattern)
|
||||
m = re.search('\{N+D+\}', pattern)
|
||||
# print "m=", m
|
||||
# print("m=", m)
|
||||
assert m
|
||||
pattern_val = m.group(0)
|
||||
pattern_val = pattern_val[1:-1]
|
||||
# print "pattern_val=", pattern_val
|
||||
# print("pattern_val=", pattern_val)
|
||||
max_value = 10**pattern_val.count('N')
|
||||
if float_compare(value, max_value, precision_digits=prec) != -1:
|
||||
raise UserError(_(
|
||||
@@ -166,11 +163,15 @@ class ProductPrintZplBarcode(models.TransientModel):
|
||||
value_d_ext = value_d + '0' * pattern_val.count('D')
|
||||
# 2) cut at the right size
|
||||
barcode += value_d_ext[0:pattern_val.count('D')]
|
||||
# print "barcode=", barcode
|
||||
# print("barcode=", barcode)
|
||||
# Add checksum
|
||||
if self.rule_id.encoding == 'ean13':
|
||||
barcode = bno.sanitize_ean(barcode)
|
||||
# print "barcode FINAL=", barcode
|
||||
# I don't call bno.sanitize_ean() due to this bug:
|
||||
# https://github.com/odoo/odoo/pull/114112
|
||||
barcode = barcode + calc_check_digit(barcode)
|
||||
assert len(barcode) == 13
|
||||
assert is_valid(barcode)
|
||||
# print("barcode FINAL=", barcode)
|
||||
zpl_unicode = self._price_weight_barcode_type_zpl() % {
|
||||
'product_name': self.product_name,
|
||||
'ean_zpl_command': len(self.barcode) == 8 and 'B8' or 'BE',
|
||||
@@ -270,7 +271,8 @@ class ProductPrintZplBarcode(models.TransientModel):
|
||||
'zpl_filename': 'barcode_%s.zpl' % vals['barcode'],
|
||||
})
|
||||
self.write(vals)
|
||||
action = self.env.ref('product_print_zpl_barcode.product_print_zpl_barcode_action').sudo().read()[0]
|
||||
action = self.env["ir.actions.actions"]._for_xml_id(
|
||||
'product_print_zpl_barcode.product_print_zpl_barcode_action')
|
||||
action.update({
|
||||
'res_id': self.id,
|
||||
'context': self._context,
|
||||
@@ -285,7 +287,8 @@ class ProductPrintZplBarcode(models.TransientModel):
|
||||
self.zpl_filename, base64.decodebytes(self.zpl_file), format='raw')
|
||||
action = True
|
||||
if self._context.get('print_and_new'):
|
||||
action = self.env.ref('product_print_zpl_barcode.product_print_zpl_barcode_action').sudo().read()[0]
|
||||
action = self.env["ir.actions.actions"]._for_xml_id(
|
||||
'product_print_zpl_barcode.product_print_zpl_barcode_action')
|
||||
action.update({
|
||||
'views': False,
|
||||
'context': self._context,
|
||||
|
||||
1
product_priority_star/__init__.py
Normal file
1
product_priority_star/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from . import models
|
||||
26
product_priority_star/__manifest__.py
Normal file
26
product_priority_star/__manifest__.py
Normal file
@@ -0,0 +1,26 @@
|
||||
# Copyright 2023 Akretion France (http://www.akretion.com)
|
||||
# @author Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
|
||||
{
|
||||
'name': 'Product Priority Star',
|
||||
'version': '14.0.1.0.0',
|
||||
'category': 'Product',
|
||||
'license': 'AGPL-3',
|
||||
'summary': 'Add a priority star on product',
|
||||
'description': """
|
||||
Product Priority Star
|
||||
=====================
|
||||
|
||||
This module adds a priority star on products (like on pickings and manufacturing order). If the star is yellow, the product will be displayed at the top.
|
||||
|
||||
This module has been written by Alexis de Lattre from Akretion <alexis.delattre@akretion.com>.
|
||||
""",
|
||||
'author': 'Akretion',
|
||||
'website': 'https://github.com/akretion/odoo-usability',
|
||||
'depends': ['product'],
|
||||
'excludes': ['product_priority'],
|
||||
'data': ['views/product_template.xml'],
|
||||
'installable': True,
|
||||
}
|
||||
1
product_priority_star/models/__init__.py
Normal file
1
product_priority_star/models/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from . import product
|
||||
20
product_priority_star/models/product.py
Normal file
20
product_priority_star/models/product.py
Normal file
@@ -0,0 +1,20 @@
|
||||
# Copyright 2023 Akretion France (http://www.akretion.com/)
|
||||
# @author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class ProductTemplate(models.Model):
|
||||
_inherit = 'product.template'
|
||||
_order = "priority desc, name, id"
|
||||
|
||||
priority = fields.Selection([
|
||||
('0', 'Normal'),
|
||||
('1', 'Top List'),
|
||||
], default='0', index=True)
|
||||
|
||||
|
||||
class ProductProduct(models.Model):
|
||||
_inherit = 'product.product'
|
||||
_order = 'priority desc, default_code, name, id'
|
||||
41
product_priority_star/views/product_template.xml
Normal file
41
product_priority_star/views/product_template.xml
Normal file
@@ -0,0 +1,41 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright 2023 Akretion France (http://www.akretion.com/)
|
||||
@author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
-->
|
||||
|
||||
<odoo>
|
||||
|
||||
<record id="product_template_tree_view" model="ir.ui.view">
|
||||
<field name="model">product.template</field>
|
||||
<field name="inherit_id" ref="product.product_template_tree_view"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="sequence" position="after">
|
||||
<field name="priority" widget="priority" optional="show" nolabel="1"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="product_template_form_view" model="ir.ui.view">
|
||||
<field name="model">product.template</field>
|
||||
<field name="inherit_id" ref="product.product_template_form_view"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="name" position="before">
|
||||
<field name="priority" widget="priority" class="mr-3"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="product_template_kanban_view" model="ir.ui.view">
|
||||
<field name="model">product.template</field>
|
||||
<field name="inherit_id" ref="product.product_template_kanban_view"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="lst_price" position="after">
|
||||
<field name="priority" widget="priority"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
</odoo>
|
||||
@@ -9,4 +9,4 @@ from odoo import fields, models
|
||||
class ProductSupplierinfo(models.Model):
|
||||
_inherit = 'product.supplierinfo'
|
||||
|
||||
name = fields.Many2one(domain=[('parent_id', '=', False)])
|
||||
name = fields.Many2one(domain=[('parent_id', '=', False)], ondelete='restrict')
|
||||
|
||||
@@ -30,10 +30,6 @@
|
||||
<field name="date_approve" position="after">
|
||||
<field name="origin"/>
|
||||
</field>
|
||||
<!-- Remove once this PR is merged https://github.com/odoo/odoo/pull/35073 -->
|
||||
<xpath expr="//field[@name='order_line']/form//field[@name='analytic_tag_ids']" position="attributes">
|
||||
<attribute name="groups">analytic.group_analytic_tags</attribute>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='order_line']/tree//field[@name='product_id']" position="after">
|
||||
<field name="product_supplier_code" optional="hide"/>
|
||||
<field name="product_barcode" optional="hide"/>
|
||||
|
||||
@@ -26,18 +26,19 @@
|
||||
<field name="model">purchase.report</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree>
|
||||
<field name="order_id" optional="show"/>
|
||||
<field name="commercial_partner_id"/>
|
||||
<field name="date_order"/>
|
||||
<field name="date_approve"/>
|
||||
<field name="date_order" optional="show"/>
|
||||
<field name="date_approve" optional="show"/>
|
||||
<field name="product_id"/>
|
||||
<field name="qty_ordered" sum="1"/>
|
||||
<field name="qty_received" sum="1"/>
|
||||
<field name="qty_billed" sum="1"/>
|
||||
<field name="product_uom"/>
|
||||
<field name="product_uom" groups="uom.group_uom"/>
|
||||
<field name="price_total" sum="1"/>
|
||||
<field name="account_analytic_id" groups="analytic.group_analytic_accounting"/>
|
||||
<field name="account_analytic_id" groups="analytic.group_analytic_accounting" optional="show"/>
|
||||
<field name="currency_id" invisible="1"/>
|
||||
<field name="user_id"/>
|
||||
<field name="user_id" optional="hide"/>
|
||||
<field name="state"/>
|
||||
</tree>
|
||||
</field>
|
||||
|
||||
1
sale_crm_usability/__init__.py
Normal file
1
sale_crm_usability/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from . import models
|
||||
18
sale_crm_usability/__manifest__.py
Normal file
18
sale_crm_usability/__manifest__.py
Normal file
@@ -0,0 +1,18 @@
|
||||
# Copyright 2023 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': 'Sale CRM Usability',
|
||||
'version': '14.0.1.0.0',
|
||||
'category': 'CRM',
|
||||
'license': 'AGPL-3',
|
||||
'summary': 'Usability improvements on sale_crm module',
|
||||
'author': 'Akretion',
|
||||
'website': 'https://github.com/akretion/odoo-usability',
|
||||
'depends': [
|
||||
'sale_crm',
|
||||
],
|
||||
'data': [],
|
||||
'installable': True,
|
||||
}
|
||||
1
sale_crm_usability/models/__init__.py
Normal file
1
sale_crm_usability/models/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from . import crm_lead
|
||||
14
sale_crm_usability/models/crm_lead.py
Normal file
14
sale_crm_usability/models/crm_lead.py
Normal file
@@ -0,0 +1,14 @@
|
||||
# Copyright 2023 Akretion France (http://www.akretion.com/)
|
||||
# @author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import api, models
|
||||
|
||||
class CrmLead(models.Model):
|
||||
_inherit = 'crm.lead'
|
||||
|
||||
def action_view_sale_quotation(self):
|
||||
action = super().action_view_sale_quotation()
|
||||
if 'search_default_partner_id' in action['context']:
|
||||
action['context'].pop('search_default_partner_id')
|
||||
return action
|
||||
@@ -1,10 +1,10 @@
|
||||
# Copyright 2016-2019 Akretion (http://www.akretion.com)
|
||||
# Copyright 2016-2022 Akretion (http://www.akretion.com)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
# @author Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
|
||||
{
|
||||
'name': 'Sale Quotation Title',
|
||||
'version': '12.0.1.0.0',
|
||||
'version': '14.0.1.0.0',
|
||||
'category': 'Sales',
|
||||
'license': 'AGPL-3',
|
||||
'summary': 'Adds a title field on quotations',
|
||||
@@ -21,5 +21,5 @@ This module has been written by Alexis de Lattre from Akretion
|
||||
'website': 'http://www.akretion.com',
|
||||
'depends': ['sale'],
|
||||
'data': ['sale_view.xml'],
|
||||
'installable': False,
|
||||
'installable': True,
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
# Copyright 2016-2019 Akretion (http://www.akretion.com)
|
||||
# Copyright 2016-2022 Akretion (http://www.akretion.com)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
# @author Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
|
||||
from odoo import models, fields
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class SaleOrder(models.Model):
|
||||
_inherit = 'sale.order'
|
||||
|
||||
quotation_title = fields.Char(string="Quotation Title")
|
||||
quotation_title = fields.Char()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright 2016-2019 Akretion (http://www.akretion.com/)
|
||||
Copyright 2016-2022 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).
|
||||
-->
|
||||
@@ -14,7 +14,7 @@
|
||||
<field name="inherit_id" ref="sale.view_order_tree"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="user_id" position="before">
|
||||
<field name="quotation_title"/>
|
||||
<field name="quotation_title" optional="show"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
@@ -25,7 +25,7 @@
|
||||
<field name="inherit_id" ref="sale.view_quotation_tree"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="user_id" position="before">
|
||||
<field name="quotation_title"/>
|
||||
<field name="quotation_title" optional="show"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
1
sale_show_transaction/__init__.py
Normal file
1
sale_show_transaction/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from . import models
|
||||
25
sale_show_transaction/__manifest__.py
Normal file
25
sale_show_transaction/__manifest__.py
Normal file
@@ -0,0 +1,25 @@
|
||||
# Copyright 2022 Akretion (https://www.akretion.com).
|
||||
# @author Sébastien BEAU <sebastien.beau@akretion.com>
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
|
||||
{
|
||||
"name": "Sale Show Transaction",
|
||||
"summary": "Make transaction hyper visible on sale order",
|
||||
"version": "14.0.1.0.0",
|
||||
"development_status": "Alpha",
|
||||
"category": "Uncategorized",
|
||||
"website": "www.akretion.com",
|
||||
"author": " Akretion",
|
||||
"license": "AGPL-3",
|
||||
"external_dependencies": {
|
||||
"python": [],
|
||||
"bin": [],
|
||||
},
|
||||
"depends": [
|
||||
"sale",
|
||||
],
|
||||
"data": [
|
||||
"views/sale_order_view.xml",
|
||||
],
|
||||
"demo": [
|
||||
],
|
||||
}
|
||||
1
sale_show_transaction/models/__init__.py
Normal file
1
sale_show_transaction/models/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from . import sale_order
|
||||
30
sale_show_transaction/models/sale_order.py
Normal file
30
sale_show_transaction/models/sale_order.py
Normal file
@@ -0,0 +1,30 @@
|
||||
# Copyright 2022 Akretion (https://www.akretion.com).
|
||||
# @author Sébastien BEAU <sebastien.beau@akretion.com>
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import _, api, fields, models
|
||||
|
||||
|
||||
class SaleOrder(models.Model):
|
||||
_inherit = 'sale.order'
|
||||
|
||||
main_acquirer_id = fields.Many2one(
|
||||
'payment.acquirer',
|
||||
'Online payment mode',
|
||||
compute="_compute_main_acquirer",
|
||||
store=True)
|
||||
|
||||
@api.depends("transaction_ids.state")
|
||||
def _compute_main_acquirer(self):
|
||||
for record in self:
|
||||
if len(record.transaction_ids.acquirer_id) > 1:
|
||||
for state in ["done", "authorized", "pending", "draft", "cancel", "error"]:
|
||||
transaction = record.transaction_ids.filtered(lambda s: s.state == state)
|
||||
if len(transaction.acquirer_id) > 1:
|
||||
transaction.sorted("amount")
|
||||
if transaction:
|
||||
record.main_acquirer_id = transaction[0].acquirer_id
|
||||
break
|
||||
else:
|
||||
record.main_acquirer_id = record.transaction_ids.acquirer_id
|
||||
|
||||
46
sale_show_transaction/views/sale_order_view.xml
Normal file
46
sale_show_transaction/views/sale_order_view.xml
Normal file
@@ -0,0 +1,46 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<odoo>
|
||||
|
||||
<record id="sale_order_view_form" model="ir.ui.view">
|
||||
<field name="model">sale.order</field>
|
||||
<field name="inherit_id" ref="sale.view_order_form" />
|
||||
<field name="arch" type="xml">
|
||||
<field name="note" position="after">
|
||||
<separator string="Transaction" colspan="4"/>
|
||||
<field name="transaction_ids" nolabel="1" colspan="4">
|
||||
<tree
|
||||
decoration-danger="state in ('error', 'cancel')"
|
||||
decoration-success="state == 'done'"
|
||||
>
|
||||
<field name="reference"/>
|
||||
<field name="create_date"/>
|
||||
<field name="acquirer_id"/>
|
||||
<field name="amount"/>
|
||||
<field name="state"/>
|
||||
</tree>
|
||||
</field>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_order_tree" model="ir.ui.view">
|
||||
<field name="model">sale.order</field>
|
||||
<field name="inherit_id" ref="sale.view_order_tree" />
|
||||
<field name="arch" type="xml">
|
||||
<field name="state" position="after">
|
||||
<field name="main_acquirer_id"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_quotation_tree" model="ir.ui.view">
|
||||
<field name="model">sale.order</field>
|
||||
<field name="inherit_id" ref="sale.view_quotation_tree" />
|
||||
<field name="arch" type="xml">
|
||||
<field name="currency_id" position="after">
|
||||
<field name="main_acquirer_id"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
1
setup/account_usability/odoo/addons/account_usability
Symbolic link
1
setup/account_usability/odoo/addons/account_usability
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../../account_usability
|
||||
6
setup/account_usability/setup.py
Normal file
6
setup/account_usability/setup.py
Normal file
@@ -0,0 +1,6 @@
|
||||
import setuptools
|
||||
|
||||
setuptools.setup(
|
||||
setup_requires=['setuptools-odoo'],
|
||||
odoo_addon=True,
|
||||
)
|
||||
1
setup/base_usability/odoo/addons/base_usability
Symbolic link
1
setup/base_usability/odoo/addons/base_usability
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../../base_usability
|
||||
6
setup/base_usability/setup.py
Normal file
6
setup/base_usability/setup.py
Normal file
@@ -0,0 +1,6 @@
|
||||
import setuptools
|
||||
|
||||
setuptools.setup(
|
||||
setup_requires=['setuptools-odoo'],
|
||||
odoo_addon=True,
|
||||
)
|
||||
1
stock_move_line_auto_fill_all/__init__.py
Normal file
1
stock_move_line_auto_fill_all/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from . import models
|
||||
27
stock_move_line_auto_fill_all/__manifest__.py
Normal file
27
stock_move_line_auto_fill_all/__manifest__.py
Normal file
@@ -0,0 +1,27 @@
|
||||
# Copyright 2023 Akretion France (http://www.akretion.com/)
|
||||
# @author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
{
|
||||
'name': 'Stock Move Line Auto-fill All',
|
||||
'version': '14.0.1.0.0',
|
||||
'category': 'Warehouse',
|
||||
'license': 'AGPL-3',
|
||||
'summary': 'Add button on picking to auto-fill done qty',
|
||||
'description': """
|
||||
This module is an alternative to the OCA module **stock_move_line_auto_fill** from https://github.com/OCA/stock-logistics-workflow/
|
||||
The OCA module doesn't auto-fill the stock move lines with lots. This module does.
|
||||
|
||||
This module has been written by Alexis de Lattre from Akretion
|
||||
<alexis.delattre@akretion.com>.
|
||||
""",
|
||||
'author': 'Akretion',
|
||||
'maintainers': ['alexis-via'],
|
||||
"development_status": "Mature",
|
||||
'website': 'https://github.com/akretion/odoo-usability',
|
||||
'depends': ['stock'],
|
||||
'data': [
|
||||
'views/stock_picking.xml',
|
||||
],
|
||||
'installable': True,
|
||||
}
|
||||
1
stock_move_line_auto_fill_all/models/__init__.py
Normal file
1
stock_move_line_auto_fill_all/models/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from . import stock_picking
|
||||
34
stock_move_line_auto_fill_all/models/stock_picking.py
Normal file
34
stock_move_line_auto_fill_all/models/stock_picking.py
Normal file
@@ -0,0 +1,34 @@
|
||||
# Copyright 2023 Akretion France (http://www.akretion.com/)
|
||||
# @author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import fields, models, _
|
||||
from odoo.tools import float_compare, float_is_zero
|
||||
from odoo.exceptions import UserError
|
||||
|
||||
|
||||
class StockPicking(models.Model):
|
||||
_inherit = 'stock.picking'
|
||||
|
||||
autofill_done = fields.Boolean(readonly=True)
|
||||
|
||||
def button_stock_move_line_autofill(self):
|
||||
self.ensure_one()
|
||||
prec = self.env['decimal.precision'].precision_get(
|
||||
'Product Unit of Measure')
|
||||
for ml in self.move_line_ids_without_package:
|
||||
if ml.product_id and float_compare(ml.product_uom_qty, 0, precision_digits=prec) > 0 and float_is_zero(ml.qty_done, precision_digits=prec):
|
||||
if (
|
||||
ml.product_id.tracking in ('lot', 'serial') and
|
||||
not ml.lot_id and
|
||||
not ml.lot_name):
|
||||
raise UserError(_(
|
||||
"Autofill is not possible: the lot is not set "
|
||||
"on move line with product '%s' quantity %s %s.")
|
||||
% (
|
||||
ml.product_id.display_name,
|
||||
ml.product_uom_qty,
|
||||
ml.product_uom_id.display_name
|
||||
))
|
||||
ml.write({'qty_done': ml.product_uom_qty})
|
||||
self.write({'autofill_done': True})
|
||||
22
stock_move_line_auto_fill_all/views/stock_picking.xml
Normal file
22
stock_move_line_auto_fill_all/views/stock_picking.xml
Normal file
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright 2023 Akretion France (http://www.akretion.com/)
|
||||
@author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
-->
|
||||
|
||||
<odoo>
|
||||
|
||||
<record id="view_picking_form" model="ir.ui.view">
|
||||
<field name="model">stock.picking</field>
|
||||
<field name="inherit_id" ref="stock.view_picking_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<button name="button_validate" type="object" class="oe_highlight" position="before">
|
||||
<button name="button_stock_move_line_autofill" type="object" string="Auto-Fill" attrs="{'invisible': ['|', ('state', '!=', 'assigned'), ('autofill_done', '=', True)]}" groups="stock.group_stock_user" help="This button will copy the 'Reserved' qty on the 'Done' qty for all the operations of this picking with a null 'Done' qty."/>
|
||||
</button>
|
||||
<field name="origin" position="after">
|
||||
<field name="autofill_done" invisible="1"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
20
stock_quant_package_move_wizard/README.rst
Normal file
20
stock_quant_package_move_wizard/README.rst
Normal file
@@ -0,0 +1,20 @@
|
||||
Module Stock Quant Package Moving Wizard
|
||||
=========================================
|
||||
|
||||
This module provides a **super fast** and **super easy** way of moving a quant to another stock location.
|
||||
|
||||
Usage
|
||||
=====
|
||||
|
||||
1. Select one or several quants
|
||||
2. Click on the *Move* button
|
||||
3. Follow the instructions on the wizard: select a picking type (or a destination stock location) and, if you don't want to move the full quant, edit the quantity to move.
|
||||
4. Validate the wizard
|
||||
|
||||
Contributors
|
||||
============
|
||||
|
||||
* Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
* Oihane Crucelaegui <oihanecrucelaegi@avanzosc.es>
|
||||
* Pedro M. Baeza <pedro.baeza@serviciosbaeza.com>
|
||||
* Ana Juaristi <ajuaristio@gmail.com>
|
||||
2
stock_quant_package_move_wizard/__init__.py
Normal file
2
stock_quant_package_move_wizard/__init__.py
Normal file
@@ -0,0 +1,2 @@
|
||||
from . import models
|
||||
from . import wizards
|
||||
29
stock_quant_package_move_wizard/__manifest__.py
Normal file
29
stock_quant_package_move_wizard/__manifest__.py
Normal file
@@ -0,0 +1,29 @@
|
||||
# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html
|
||||
|
||||
{
|
||||
"name": "Quant & Package moving wizard",
|
||||
"summary": "Select a quant Move quants to another location in a few clicks",
|
||||
"category": "Inventory/Inventory",
|
||||
"version": "14.0.1.0.0",
|
||||
"license": "AGPL-3",
|
||||
"depends": ["stock"],
|
||||
"author": "AvanzOSC, "
|
||||
"Serv. Tecnol. Avanzados - Pedro M. Baeza, "
|
||||
"Akretion",
|
||||
"maintainers": ["alexis-via"],
|
||||
"website": "https://github.com/akretion/odoo-usability",
|
||||
"contributors": [
|
||||
"Oihane Crucelaegui <oihanecrucelaegi@avanzosc.es>",
|
||||
"Pedro M. Baeza <pedro.baeza@serviciosbaeza.com>",
|
||||
"Ana Juaristi <ajuaristio@gmail.com>",
|
||||
"Alexis de Lattre <alexis.delattre@akretion.com>",
|
||||
],
|
||||
"data": [
|
||||
# "wizards/quants_move_wizard_view.xml",
|
||||
"security/ir.model.access.csv",
|
||||
"wizards/stock_quant_move_wizard_view.xml",
|
||||
"views/stock_quant.xml",
|
||||
# "views/stock_quant_package.xml",
|
||||
],
|
||||
"installable": True,
|
||||
}
|
||||
223
stock_quant_package_move_wizard/i18n/fr.po
Normal file
223
stock_quant_package_move_wizard/i18n/fr.po
Normal file
@@ -0,0 +1,223 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * stock_quant_package_move_wizard
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server 16.0\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2023-02-13 21:59+0000\n"
|
||||
"PO-Revision-Date: 2023-02-13 21:59+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"
|
||||
|
||||
#. module: stock_quant_package_move_wizard
|
||||
#: model_terms:ir.ui.view,arch_db:stock_quant_package_move_wizard.stock_quant_move_wizard_form
|
||||
msgid "Cancel"
|
||||
msgstr "Annuler"
|
||||
|
||||
#. module: stock_quant_package_move_wizard
|
||||
#. odoo-python
|
||||
#: code:addons/stock_quant_package_move_wizard/models/stock_quant.py:0
|
||||
#, python-format
|
||||
msgid "Cannot move to '%s' which is a view location."
|
||||
msgstr "Impossible de déplacer vers '%s' qui est un emplacement de type Vue."
|
||||
|
||||
#. module: stock_quant_package_move_wizard
|
||||
#: model:ir.model.fields,field_description:stock_quant_package_move_wizard.field_stock_quant_move_wizard__company_id
|
||||
msgid "Company"
|
||||
msgstr "Société"
|
||||
|
||||
#. module: stock_quant_package_move_wizard
|
||||
#: model:ir.model.fields,field_description:stock_quant_package_move_wizard.field_stock_quant_move_wizard__create_uid
|
||||
#: model:ir.model.fields,field_description:stock_quant_package_move_wizard.field_stock_quant_move_wizard_line__create_uid
|
||||
msgid "Created by"
|
||||
msgstr ""
|
||||
|
||||
#. module: stock_quant_package_move_wizard
|
||||
#: model:ir.model.fields,field_description:stock_quant_package_move_wizard.field_stock_quant_move_wizard__create_date
|
||||
#: model:ir.model.fields,field_description:stock_quant_package_move_wizard.field_stock_quant_move_wizard_line__create_date
|
||||
msgid "Created on"
|
||||
msgstr ""
|
||||
|
||||
#. module: stock_quant_package_move_wizard
|
||||
#: model:ir.model.fields,field_description:stock_quant_package_move_wizard.field_stock_quant_move_wizard_line__src_location_id
|
||||
msgid "Current Location"
|
||||
msgstr "Emplacement actuel"
|
||||
|
||||
#. module: stock_quant_package_move_wizard
|
||||
#: model:ir.model.fields,help:stock_quant_package_move_wizard.field_stock_quant_move_wizard_line__uom_id
|
||||
msgid "Default unit of measure used for all stock operations."
|
||||
msgstr ""
|
||||
|
||||
#. module: stock_quant_package_move_wizard
|
||||
#: model:ir.model.fields,field_description:stock_quant_package_move_wizard.field_stock_quant_move_wizard__location_dest_id
|
||||
msgid "Destination Location"
|
||||
msgstr "Emplacement destination"
|
||||
|
||||
#. module: stock_quant_package_move_wizard
|
||||
#: model:ir.model.fields,field_description:stock_quant_package_move_wizard.field_stock_quant_move_wizard__display_name
|
||||
#: model:ir.model.fields,field_description:stock_quant_package_move_wizard.field_stock_quant_move_wizard_line__display_name
|
||||
msgid "Display Name"
|
||||
msgstr ""
|
||||
|
||||
#. module: stock_quant_package_move_wizard
|
||||
#: model:ir.model.fields,field_description:stock_quant_package_move_wizard.field_stock_quant_move_wizard__id
|
||||
#: model:ir.model.fields,field_description:stock_quant_package_move_wizard.field_stock_quant_move_wizard_line__id
|
||||
msgid "ID"
|
||||
msgstr ""
|
||||
|
||||
#. module: stock_quant_package_move_wizard
|
||||
#: model:ir.model.fields,field_description:stock_quant_package_move_wizard.field_stock_quant_move_wizard____last_update
|
||||
#: model:ir.model.fields,field_description:stock_quant_package_move_wizard.field_stock_quant_move_wizard_line____last_update
|
||||
msgid "Last Modified on"
|
||||
msgstr ""
|
||||
|
||||
#. module: stock_quant_package_move_wizard
|
||||
#: model:ir.model.fields,field_description:stock_quant_package_move_wizard.field_stock_quant_move_wizard__write_uid
|
||||
#: model:ir.model.fields,field_description:stock_quant_package_move_wizard.field_stock_quant_move_wizard_line__write_uid
|
||||
msgid "Last Updated by"
|
||||
msgstr ""
|
||||
|
||||
#. module: stock_quant_package_move_wizard
|
||||
#: model:ir.model.fields,field_description:stock_quant_package_move_wizard.field_stock_quant_move_wizard__write_date
|
||||
#: model:ir.model.fields,field_description:stock_quant_package_move_wizard.field_stock_quant_move_wizard_line__write_date
|
||||
msgid "Last Updated on"
|
||||
msgstr ""
|
||||
|
||||
#. module: stock_quant_package_move_wizard
|
||||
#: model:ir.model.fields,field_description:stock_quant_package_move_wizard.field_stock_quant_move_wizard__line_ids
|
||||
msgid "Lines"
|
||||
msgstr "Lignes"
|
||||
|
||||
#. module: stock_quant_package_move_wizard
|
||||
#: model:ir.model,name:stock_quant_package_move_wizard.model_stock_quant_move_wizard_line
|
||||
msgid "Lines of the wizard to move quants"
|
||||
msgstr "Lignes de l'assistant de déplacement des quants"
|
||||
|
||||
#. module: stock_quant_package_move_wizard
|
||||
#: model:ir.model.fields,field_description:stock_quant_package_move_wizard.field_stock_quant_move_wizard_line__lot_id
|
||||
msgid "Lot/Serial Number"
|
||||
msgstr "Lot/numéro de série"
|
||||
|
||||
#. module: stock_quant_package_move_wizard
|
||||
#: model_terms:ir.ui.view,arch_db:stock_quant_package_move_wizard.stock_quant_move_wizard_form
|
||||
msgid "Move"
|
||||
msgstr "Déplacer"
|
||||
|
||||
#. module: stock_quant_package_move_wizard
|
||||
#: model:ir.actions.act_window,name:stock_quant_package_move_wizard.stock_quant_move_wizard_action
|
||||
msgid "Move to Another Location"
|
||||
msgstr "Déplacer vers un autre emplacement"
|
||||
|
||||
#. module: stock_quant_package_move_wizard
|
||||
#: model:ir.model.fields,field_description:stock_quant_package_move_wizard.field_stock_quant_move_wizard_line__quant_quantity
|
||||
msgid "On Hand Qty"
|
||||
msgstr "Qté en stock"
|
||||
|
||||
#. module: stock_quant_package_move_wizard
|
||||
#: model:ir.model.fields,field_description:stock_quant_package_move_wizard.field_stock_quant_move_wizard__picking_type_id
|
||||
msgid "Picking Type"
|
||||
msgstr "Type d'opération"
|
||||
|
||||
#. module: stock_quant_package_move_wizard
|
||||
#: model:ir.model.fields,field_description:stock_quant_package_move_wizard.field_stock_quant_move_wizard_line__product_id
|
||||
msgid "Product"
|
||||
msgstr "Article"
|
||||
|
||||
#. module: stock_quant_package_move_wizard
|
||||
#: model:ir.model.fields,field_description:stock_quant_package_move_wizard.field_stock_quant_move_wizard_line__quantity
|
||||
msgid "Qty to Move"
|
||||
msgstr "Qté à déplacer"
|
||||
|
||||
#. module: stock_quant_package_move_wizard
|
||||
#: model:ir.model.fields,field_description:stock_quant_package_move_wizard.field_stock_quant_move_wizard_line__quant_id
|
||||
msgid "Quant"
|
||||
msgstr "Quant"
|
||||
|
||||
#. module: stock_quant_package_move_wizard
|
||||
#: model:ir.model.fields,field_description:stock_quant_package_move_wizard.field_stock_quant_move_wizard_line__wizard_id
|
||||
msgid "Quant Move"
|
||||
msgstr "Déplacer Quant"
|
||||
|
||||
#. module: stock_quant_package_move_wizard
|
||||
#: model:ir.model.fields,help:stock_quant_package_move_wizard.field_stock_quant_move_wizard_line__quant_quantity
|
||||
msgid ""
|
||||
"Quantity of products in this quant, in the default unit of measure of the "
|
||||
"product"
|
||||
msgstr ""
|
||||
|
||||
#. module: stock_quant_package_move_wizard
|
||||
#: model:ir.model,name:stock_quant_package_move_wizard.model_stock_quant
|
||||
msgid "Quants"
|
||||
msgstr "Quants"
|
||||
|
||||
#. module: stock_quant_package_move_wizard
|
||||
#: model:ir.model.fields,field_description:stock_quant_package_move_wizard.field_stock_quant_move_wizard__origin
|
||||
msgid "Source Document"
|
||||
msgstr "Document source"
|
||||
|
||||
#. module: stock_quant_package_move_wizard
|
||||
#: model_terms:ir.ui.view,arch_db:stock_quant_package_move_wizard.stock_quant_move_wizard_form
|
||||
msgid "Unit"
|
||||
msgstr "Unité"
|
||||
|
||||
#. module: stock_quant_package_move_wizard
|
||||
#: model:ir.model.fields,field_description:stock_quant_package_move_wizard.field_stock_quant_move_wizard_line__uom_id
|
||||
msgid "Unit of Measure"
|
||||
msgstr "Unité de mesure"
|
||||
|
||||
#. module: stock_quant_package_move_wizard
|
||||
#: model:ir.model,name:stock_quant_package_move_wizard.model_stock_quant_move_wizard
|
||||
msgid "Wizard to Move Quants"
|
||||
msgstr "Assistant de déplacement de quants"
|
||||
|
||||
#. module: stock_quant_package_move_wizard
|
||||
#. odoo-python
|
||||
#: code:addons/stock_quant_package_move_wizard/models/stock_quant.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"You are trying to move %(qty)s %(uom)s of a quant of product "
|
||||
"%(product_name)s that has a quantity of %(quant_quantity)s %(uom)s."
|
||||
msgstr ""
|
||||
"Vous essayez de déplacer %(qty)s %(uom)s d'un quant de l'article "
|
||||
"%(product_name)s dont la quantité est de %(quant_quantity)s %(uom)s."
|
||||
|
||||
#. module: stock_quant_package_move_wizard
|
||||
#. odoo-python
|
||||
#: code:addons/stock_quant_package_move_wizard/models/stock_quant.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"You are trying to move %(qty)s %(uom)s of a quant of product "
|
||||
"%(product_name)s to %(dest_location)s, but it is already on that location!"
|
||||
msgstr ""
|
||||
"Vous essayez de déplacer %(qty)s %(uom)s d'un quant de l'article "
|
||||
"%(product_name)s vers %(dest_location)s, mais il est déjà sur cet emplacement !"
|
||||
|
||||
#. module: stock_quant_package_move_wizard
|
||||
#. odoo-python
|
||||
#: code:addons/stock_quant_package_move_wizard/models/stock_quant.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"You are trying to move %(qty)s %(uom)s of a quant of product "
|
||||
"%(product_name)s, but that quant has a negative quantity (%(quant_quantity)s"
|
||||
" %(uom)s)."
|
||||
msgstr ""
|
||||
"Vous essayez de déplacer %(qty)s %(uom)s d'un quant de l'article "
|
||||
"%(product_name)s, mais ce quant est en quantité négative (%(quant_quantity)s"
|
||||
" %(uom)s)."
|
||||
|
||||
#. module: stock_quant_package_move_wizard
|
||||
#. odoo-python
|
||||
#: code:addons/stock_quant_package_move_wizard/models/stock_quant.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"You are trying to move %(qty)s %(uom)s of a quant of product "
|
||||
"%(product_name)s: the quantity to move must be strictly positive."
|
||||
msgstr ""
|
||||
"Vous essayez de déplacer %(qty)s %(uom)s d'un quant de l'article "
|
||||
"%(product_name)s : la quantité à déplacer doit être strictement positive."
|
||||
@@ -0,0 +1,214 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * stock_quant_package_move_wizard
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server 16.0\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2023-02-13 21:58+0000\n"
|
||||
"PO-Revision-Date: 2023-02-13 21:58+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"
|
||||
|
||||
#. module: stock_quant_package_move_wizard
|
||||
#: model_terms:ir.ui.view,arch_db:stock_quant_package_move_wizard.stock_quant_move_wizard_form
|
||||
msgid "Cancel"
|
||||
msgstr ""
|
||||
|
||||
#. module: stock_quant_package_move_wizard
|
||||
#. odoo-python
|
||||
#: code:addons/stock_quant_package_move_wizard/models/stock_quant.py:0
|
||||
#, python-format
|
||||
msgid "Cannot move to '%s' which is a view location."
|
||||
msgstr ""
|
||||
|
||||
#. module: stock_quant_package_move_wizard
|
||||
#: model:ir.model.fields,field_description:stock_quant_package_move_wizard.field_stock_quant_move_wizard__company_id
|
||||
msgid "Company"
|
||||
msgstr ""
|
||||
|
||||
#. module: stock_quant_package_move_wizard
|
||||
#: model:ir.model.fields,field_description:stock_quant_package_move_wizard.field_stock_quant_move_wizard__create_uid
|
||||
#: model:ir.model.fields,field_description:stock_quant_package_move_wizard.field_stock_quant_move_wizard_line__create_uid
|
||||
msgid "Created by"
|
||||
msgstr ""
|
||||
|
||||
#. module: stock_quant_package_move_wizard
|
||||
#: model:ir.model.fields,field_description:stock_quant_package_move_wizard.field_stock_quant_move_wizard__create_date
|
||||
#: model:ir.model.fields,field_description:stock_quant_package_move_wizard.field_stock_quant_move_wizard_line__create_date
|
||||
msgid "Created on"
|
||||
msgstr ""
|
||||
|
||||
#. module: stock_quant_package_move_wizard
|
||||
#: model:ir.model.fields,field_description:stock_quant_package_move_wizard.field_stock_quant_move_wizard_line__src_location_id
|
||||
msgid "Current Location"
|
||||
msgstr ""
|
||||
|
||||
#. module: stock_quant_package_move_wizard
|
||||
#: model:ir.model.fields,help:stock_quant_package_move_wizard.field_stock_quant_move_wizard_line__uom_id
|
||||
msgid "Default unit of measure used for all stock operations."
|
||||
msgstr ""
|
||||
|
||||
#. module: stock_quant_package_move_wizard
|
||||
#: model:ir.model.fields,field_description:stock_quant_package_move_wizard.field_stock_quant_move_wizard__location_dest_id
|
||||
msgid "Destination Location"
|
||||
msgstr ""
|
||||
|
||||
#. module: stock_quant_package_move_wizard
|
||||
#: model:ir.model.fields,field_description:stock_quant_package_move_wizard.field_stock_quant_move_wizard__display_name
|
||||
#: model:ir.model.fields,field_description:stock_quant_package_move_wizard.field_stock_quant_move_wizard_line__display_name
|
||||
msgid "Display Name"
|
||||
msgstr ""
|
||||
|
||||
#. module: stock_quant_package_move_wizard
|
||||
#: model:ir.model.fields,field_description:stock_quant_package_move_wizard.field_stock_quant_move_wizard__id
|
||||
#: model:ir.model.fields,field_description:stock_quant_package_move_wizard.field_stock_quant_move_wizard_line__id
|
||||
msgid "ID"
|
||||
msgstr ""
|
||||
|
||||
#. module: stock_quant_package_move_wizard
|
||||
#: model:ir.model.fields,field_description:stock_quant_package_move_wizard.field_stock_quant_move_wizard____last_update
|
||||
#: model:ir.model.fields,field_description:stock_quant_package_move_wizard.field_stock_quant_move_wizard_line____last_update
|
||||
msgid "Last Modified on"
|
||||
msgstr ""
|
||||
|
||||
#. module: stock_quant_package_move_wizard
|
||||
#: model:ir.model.fields,field_description:stock_quant_package_move_wizard.field_stock_quant_move_wizard__write_uid
|
||||
#: model:ir.model.fields,field_description:stock_quant_package_move_wizard.field_stock_quant_move_wizard_line__write_uid
|
||||
msgid "Last Updated by"
|
||||
msgstr ""
|
||||
|
||||
#. module: stock_quant_package_move_wizard
|
||||
#: model:ir.model.fields,field_description:stock_quant_package_move_wizard.field_stock_quant_move_wizard__write_date
|
||||
#: model:ir.model.fields,field_description:stock_quant_package_move_wizard.field_stock_quant_move_wizard_line__write_date
|
||||
msgid "Last Updated on"
|
||||
msgstr ""
|
||||
|
||||
#. module: stock_quant_package_move_wizard
|
||||
#: model:ir.model.fields,field_description:stock_quant_package_move_wizard.field_stock_quant_move_wizard__line_ids
|
||||
msgid "Lines"
|
||||
msgstr ""
|
||||
|
||||
#. module: stock_quant_package_move_wizard
|
||||
#: model:ir.model,name:stock_quant_package_move_wizard.model_stock_quant_move_wizard_line
|
||||
msgid "Lines of the wizard to move quants"
|
||||
msgstr ""
|
||||
|
||||
#. module: stock_quant_package_move_wizard
|
||||
#: model:ir.model.fields,field_description:stock_quant_package_move_wizard.field_stock_quant_move_wizard_line__lot_id
|
||||
msgid "Lot/Serial Number"
|
||||
msgstr ""
|
||||
|
||||
#. module: stock_quant_package_move_wizard
|
||||
#: model_terms:ir.ui.view,arch_db:stock_quant_package_move_wizard.stock_quant_move_wizard_form
|
||||
msgid "Move"
|
||||
msgstr ""
|
||||
|
||||
#. module: stock_quant_package_move_wizard
|
||||
#: model:ir.actions.act_window,name:stock_quant_package_move_wizard.stock_quant_move_wizard_action
|
||||
msgid "Move to Another Location"
|
||||
msgstr ""
|
||||
|
||||
#. module: stock_quant_package_move_wizard
|
||||
#: model:ir.model.fields,field_description:stock_quant_package_move_wizard.field_stock_quant_move_wizard_line__quant_quantity
|
||||
msgid "On Hand Qty"
|
||||
msgstr ""
|
||||
|
||||
#. module: stock_quant_package_move_wizard
|
||||
#: model:ir.model.fields,field_description:stock_quant_package_move_wizard.field_stock_quant_move_wizard__picking_type_id
|
||||
msgid "Picking Type"
|
||||
msgstr ""
|
||||
|
||||
#. module: stock_quant_package_move_wizard
|
||||
#: model:ir.model.fields,field_description:stock_quant_package_move_wizard.field_stock_quant_move_wizard_line__product_id
|
||||
msgid "Product"
|
||||
msgstr ""
|
||||
|
||||
#. module: stock_quant_package_move_wizard
|
||||
#: model:ir.model.fields,field_description:stock_quant_package_move_wizard.field_stock_quant_move_wizard_line__quantity
|
||||
msgid "Qty to Move"
|
||||
msgstr ""
|
||||
|
||||
#. module: stock_quant_package_move_wizard
|
||||
#: model:ir.model.fields,field_description:stock_quant_package_move_wizard.field_stock_quant_move_wizard_line__quant_id
|
||||
msgid "Quant"
|
||||
msgstr ""
|
||||
|
||||
#. module: stock_quant_package_move_wizard
|
||||
#: model:ir.model.fields,field_description:stock_quant_package_move_wizard.field_stock_quant_move_wizard_line__wizard_id
|
||||
msgid "Quant Move"
|
||||
msgstr ""
|
||||
|
||||
#. module: stock_quant_package_move_wizard
|
||||
#: model:ir.model.fields,help:stock_quant_package_move_wizard.field_stock_quant_move_wizard_line__quant_quantity
|
||||
msgid ""
|
||||
"Quantity of products in this quant, in the default unit of measure of the "
|
||||
"product"
|
||||
msgstr ""
|
||||
|
||||
#. module: stock_quant_package_move_wizard
|
||||
#: model:ir.model,name:stock_quant_package_move_wizard.model_stock_quant
|
||||
msgid "Quants"
|
||||
msgstr ""
|
||||
|
||||
#. module: stock_quant_package_move_wizard
|
||||
#: model:ir.model.fields,field_description:stock_quant_package_move_wizard.field_stock_quant_move_wizard__origin
|
||||
msgid "Source Document"
|
||||
msgstr ""
|
||||
|
||||
#. module: stock_quant_package_move_wizard
|
||||
#: model_terms:ir.ui.view,arch_db:stock_quant_package_move_wizard.stock_quant_move_wizard_form
|
||||
msgid "Unit"
|
||||
msgstr ""
|
||||
|
||||
#. module: stock_quant_package_move_wizard
|
||||
#: model:ir.model.fields,field_description:stock_quant_package_move_wizard.field_stock_quant_move_wizard_line__uom_id
|
||||
msgid "Unit of Measure"
|
||||
msgstr ""
|
||||
|
||||
#. module: stock_quant_package_move_wizard
|
||||
#: model:ir.model,name:stock_quant_package_move_wizard.model_stock_quant_move_wizard
|
||||
msgid "Wizard to Move Quants"
|
||||
msgstr ""
|
||||
|
||||
#. module: stock_quant_package_move_wizard
|
||||
#. odoo-python
|
||||
#: code:addons/stock_quant_package_move_wizard/models/stock_quant.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"You are trying to move %(qty)s %(uom)s of a quant of product "
|
||||
"%(product_name)s that has a quantity of %(quant_quantity)s %(uom)s."
|
||||
msgstr ""
|
||||
|
||||
#. module: stock_quant_package_move_wizard
|
||||
#. odoo-python
|
||||
#: code:addons/stock_quant_package_move_wizard/models/stock_quant.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"You are trying to move %(qty)s %(uom)s of a quant of product "
|
||||
"%(product_name)s to %(dest_location)s, but it is already on that location!"
|
||||
msgstr ""
|
||||
|
||||
#. module: stock_quant_package_move_wizard
|
||||
#. odoo-python
|
||||
#: code:addons/stock_quant_package_move_wizard/models/stock_quant.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"You are trying to move %(qty)s %(uom)s of a quant of product "
|
||||
"%(product_name)s, but that quant has a negative quantity (%(quant_quantity)s"
|
||||
" %(uom)s)."
|
||||
msgstr ""
|
||||
|
||||
#. module: stock_quant_package_move_wizard
|
||||
#. odoo-python
|
||||
#: code:addons/stock_quant_package_move_wizard/models/stock_quant.py:0
|
||||
#, python-format
|
||||
msgid ""
|
||||
"You are trying to move %(qty)s %(uom)s of a quant of product "
|
||||
"%(product_name)s: the quantity to move must be strictly positive."
|
||||
msgstr ""
|
||||
1
stock_quant_package_move_wizard/models/__init__.py
Normal file
1
stock_quant_package_move_wizard/models/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from . import stock_quant
|
||||
127
stock_quant_package_move_wizard/models/stock_quant.py
Normal file
127
stock_quant_package_move_wizard/models/stock_quant.py
Normal file
@@ -0,0 +1,127 @@
|
||||
# Copyright 2022 Akretion France (http://www.akretion.com/)
|
||||
# @author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html
|
||||
|
||||
from odoo import _, models
|
||||
from odoo.exceptions import UserError
|
||||
from odoo.tools import float_compare
|
||||
from odoo.tools.misc import formatLang
|
||||
|
||||
|
||||
class StockQuant(models.Model):
|
||||
_inherit = "stock.quant"
|
||||
|
||||
def _prepare_move_to_stock_move(self, qty, dest_location, picking_id, origin=False):
|
||||
# qty is in the product's uom_id
|
||||
self.ensure_one()
|
||||
if dest_location.usage == "view":
|
||||
raise UserError(
|
||||
_("Cannot move to '%s' which is a view location.")
|
||||
% dest_location.display_name
|
||||
)
|
||||
prec = self.env["decimal.precision"].precision_get("Product Unit of Measure")
|
||||
raise_dict = {
|
||||
"qty": formatLang(self.env, qty, digits=prec),
|
||||
"uom": self.product_id.uom_id.display_name,
|
||||
"product_name": self.product_id.display_name,
|
||||
"dest_location": dest_location.display_name,
|
||||
"quant_quantity": formatLang(self.env, self.quantity, digits=prec),
|
||||
}
|
||||
if self.location_id == dest_location:
|
||||
raise UserError(
|
||||
_(
|
||||
"You are trying to move %(qty)s %(uom)s of a quant of product "
|
||||
"%(product_name)s to %(dest_location)s, but it is already on "
|
||||
"that location!"
|
||||
)
|
||||
% raise_dict
|
||||
)
|
||||
if float_compare(qty, self.quantity, precision_digits=prec) > 0:
|
||||
raise UserError(
|
||||
_(
|
||||
"You are trying to move %(qty)s %(uom)s of a quant of product "
|
||||
"%(product_name)s that has a quantity of "
|
||||
"%(quant_quantity)s %(uom)s."
|
||||
)
|
||||
% raise_dict
|
||||
)
|
||||
if float_compare(self.quantity, 0, precision_digits=prec) <= 0:
|
||||
raise UserError(
|
||||
_(
|
||||
"You are trying to move %(qty)s %(uom)s of a quant of product "
|
||||
"%(product_name)s, but that quant has a negative quantity "
|
||||
"(%(quant_quantity)s %(uom)s)."
|
||||
)
|
||||
% raise_dict
|
||||
)
|
||||
if float_compare(qty, 0, precision_digits=prec) <= 0:
|
||||
raise UserError(
|
||||
_(
|
||||
"You are trying to move %(qty)s %(uom)s of a quant of product "
|
||||
"%(product_name)s: the quantity to move must be strictly positive."
|
||||
)
|
||||
% raise_dict
|
||||
)
|
||||
product_id = self.product_id.id
|
||||
location_id = self.location_id.id
|
||||
location_dest_id = dest_location.id
|
||||
uom_id = self.product_id.uom_id.id
|
||||
vals = {
|
||||
"picking_id": picking_id,
|
||||
"name": "%s: Move to %s"
|
||||
% (self.product_id.display_name, dest_location.display_name),
|
||||
"product_id": product_id,
|
||||
"location_id": location_id,
|
||||
"location_dest_id": location_dest_id,
|
||||
"product_uom_qty": qty,
|
||||
"product_uom": uom_id,
|
||||
"origin": origin,
|
||||
"move_line_ids": [
|
||||
(
|
||||
0,
|
||||
0,
|
||||
{
|
||||
"product_id": product_id,
|
||||
"product_uom_id": uom_id,
|
||||
"qty_done": qty,
|
||||
"location_id": location_id,
|
||||
"location_dest_id": location_dest_id,
|
||||
"lot_id": self.lot_id.id or False,
|
||||
},
|
||||
)
|
||||
],
|
||||
}
|
||||
return vals
|
||||
|
||||
def _prepare_move_to_stock_picking(self, dest_location, picking_type, origin=False):
|
||||
vals = {
|
||||
"picking_type_id": picking_type.id,
|
||||
"location_dest_id": dest_location.id,
|
||||
"location_id": picking_type.default_location_src_id.id,
|
||||
"origin": origin,
|
||||
}
|
||||
return vals
|
||||
|
||||
def move_full_quant_to(self, dest_location, picking_type=False, origin=False):
|
||||
assert dest_location
|
||||
picking_id = False
|
||||
if picking_type:
|
||||
picking_vals = self._prepare_move_to_stock_picking(
|
||||
dest_location, picking_type, origin=origin
|
||||
)
|
||||
picking_id = self.env["stock.picking"].create(picking_vals).id
|
||||
smo = self.env["stock.move"]
|
||||
stock_move_ids = []
|
||||
for quant in self:
|
||||
vals = quant._prepare_move_to_stock_move(
|
||||
quant.quantity, dest_location, picking_id, origin=origin
|
||||
)
|
||||
new_move = smo.create(vals)
|
||||
# No group has write access on stock.quant -> we need sudo()
|
||||
new_move._action_done()
|
||||
assert new_move.state == "done"
|
||||
stock_move_ids.append(new_move.id)
|
||||
return {
|
||||
"picking_id": picking_id,
|
||||
"stock_move_ids": stock_move_ids,
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_stock_quant_move_wizard,Full access on stock.quant.move.wizard,model_stock_quant_move_wizard,stock.group_stock_user,1,1,1,1
|
||||
access_stock_quant_move_wizard_line,Full access on stock.quant.move.wizard.line,model_stock_quant_move_wizard_line,stock.group_stock_user,1,1,1,1
|
||||
|
28
stock_quant_package_move_wizard/views/stock_quant.xml
Normal file
28
stock_quant_package_move_wizard/views/stock_quant.xml
Normal file
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<!--
|
||||
Copyright 2022 Akretion France (http://www.akretion.com/)
|
||||
@author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
-->
|
||||
<odoo>
|
||||
|
||||
<!-- Maybe it's not a good idea to put a button on tree view of quants
|
||||
from product form view, because all the direct-access buttons on this tree
|
||||
view are for inventory, so it may be hard for users to understand that
|
||||
this button has nothing to do with inventory
|
||||
<record id="view_stock_quant_tree_inventory_editable" model="ir.ui.view">
|
||||
<field name="model">stock.quant</field>
|
||||
<field name="inherit_id" ref="stock.view_stock_quant_tree_inventory_editable" />
|
||||
<field name="arch" type="xml">
|
||||
<button name="stock.action_stock_inventory_adjustement_name" position="before">
|
||||
<button
|
||||
type="action"
|
||||
name="%(stock_quant_move_wizard_action)d"
|
||||
string="Move"
|
||||
/>
|
||||
</button>
|
||||
</field>
|
||||
</record>
|
||||
-->
|
||||
|
||||
</odoo>
|
||||
1
stock_quant_package_move_wizard/wizards/__init__.py
Normal file
1
stock_quant_package_move_wizard/wizards/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from . import stock_quant_move_wizard
|
||||
@@ -0,0 +1,114 @@
|
||||
# Copyright 2022 Akretion France (http://www.akretion.com/)
|
||||
# @author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html
|
||||
|
||||
from odoo import api, fields, models
|
||||
|
||||
|
||||
class StockQuantMoveWizard(models.TransientModel):
|
||||
_name = "stock.quant.move.wizard"
|
||||
_description = "Wizard to Move Quants"
|
||||
_check_company_auto = True
|
||||
|
||||
line_ids = fields.One2many(
|
||||
"stock.quant.move.wizard.line", "wizard_id", string="Lines"
|
||||
)
|
||||
company_id = fields.Many2one("res.company", required=True)
|
||||
location_dest_id = fields.Many2one(
|
||||
"stock.location",
|
||||
string="Destination Location",
|
||||
domain="[('usage', '!=', 'view'), ('company_id', '=', company_id)]",
|
||||
check_company=True,
|
||||
required=True,
|
||||
)
|
||||
picking_type_id = fields.Many2one(
|
||||
"stock.picking.type",
|
||||
domain="[('company_id', '=', company_id)]",
|
||||
check_company=True,
|
||||
)
|
||||
origin = fields.Char(string="Source Document")
|
||||
# Idea : add a bool option 'move even if reserved' (= current behavior)
|
||||
|
||||
@api.onchange("picking_type_id")
|
||||
def picking_type_id_change(self):
|
||||
if self.picking_type_id and self.picking_type_id.default_location_dest_id:
|
||||
self.location_dest_id = self.picking_type_id.default_location_dest_id
|
||||
|
||||
@api.model
|
||||
def default_get(self, fields_list):
|
||||
res = super().default_get(fields_list)
|
||||
assert self._context.get("active_model") == "stock.quant"
|
||||
company_id = self.env.company.id
|
||||
quants_ids = self._context.get("active_ids", [])
|
||||
quants = self.env["stock.quant"].browse(quants_ids)
|
||||
lines = []
|
||||
for quant in quants.filtered(
|
||||
lambda q: not q.package_id and q.company_id.id == company_id
|
||||
):
|
||||
lines.append((0, 0, {"quant_id": quant.id, "quantity": quant.quantity}))
|
||||
picking_type = self.env["stock.picking.type"].search(
|
||||
[("code", "=", "internal"), ("company_id", "=", company_id)], limit=1
|
||||
)
|
||||
res.update(
|
||||
{
|
||||
"line_ids": lines,
|
||||
"company_id": company_id,
|
||||
"picking_type_id": picking_type and picking_type.id or False,
|
||||
}
|
||||
)
|
||||
return res
|
||||
|
||||
def run(self):
|
||||
self.ensure_one()
|
||||
picking_id = False
|
||||
if self.picking_type_id:
|
||||
picking_vals = self.env["stock.quant"]._prepare_move_to_stock_picking(
|
||||
self.location_dest_id, self.picking_type_id, origin=self.origin
|
||||
)
|
||||
picking_id = self.env["stock.picking"].create(picking_vals).id
|
||||
smo = self.env["stock.move"]
|
||||
for line in self.line_ids:
|
||||
quant = line.quant_id
|
||||
assert not quant.package_id
|
||||
vals = quant._prepare_move_to_stock_move(
|
||||
line.quantity, self.location_dest_id, picking_id, origin=self.origin
|
||||
)
|
||||
new_move = smo.create(vals)
|
||||
new_move._action_done()
|
||||
assert new_move.state == "done"
|
||||
action = {}
|
||||
if picking_id and self._context.get("run_show_picking"):
|
||||
action = self.env["ir.actions.actions"]._for_xml_id(
|
||||
"stock.stock_picking_action_picking_type"
|
||||
)
|
||||
action.update(
|
||||
{
|
||||
"res_id": picking_id,
|
||||
"view_mode": "form,tree,pivot",
|
||||
"views": False,
|
||||
"view_id": False,
|
||||
}
|
||||
)
|
||||
return action
|
||||
|
||||
|
||||
class StockQuantMoveWizardLine(models.TransientModel):
|
||||
_name = "stock.quant.move.wizard.line"
|
||||
_description = "Lines of the wizard to move quants"
|
||||
|
||||
wizard_id = fields.Many2one(
|
||||
comodel_name="stock.quant.move.wizard", string="Quant Move", ondelete="cascade"
|
||||
)
|
||||
quant_id = fields.Many2one(
|
||||
comodel_name="stock.quant",
|
||||
string="Quant",
|
||||
required=True,
|
||||
)
|
||||
product_id = fields.Many2one(related="quant_id.product_id")
|
||||
quant_quantity = fields.Float(related="quant_id.quantity", string="On Hand Qty")
|
||||
quantity = fields.Float(string="Qty to Move", digits="Product Unit of Measure")
|
||||
uom_id = fields.Many2one(related="quant_id.product_id.uom_id")
|
||||
lot_id = fields.Many2one(related="quant_id.lot_id")
|
||||
src_location_id = fields.Many2one(
|
||||
related="quant_id.location_id", string="Current Location"
|
||||
)
|
||||
@@ -0,0 +1,54 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<!--
|
||||
Copyright 2022 Akretion France (http://www.akretion.com/)
|
||||
@author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
-->
|
||||
<odoo>
|
||||
|
||||
|
||||
<record id="stock_quant_move_wizard_form" model="ir.ui.view">
|
||||
<field name="model">stock.quant.move.wizard</field>
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<group name="main">
|
||||
<field name="company_id" invisible="1" />
|
||||
<field
|
||||
name="picking_type_id"
|
||||
options="{'no_open': True, 'no_create': True}"
|
||||
/>
|
||||
<field
|
||||
name="location_dest_id"
|
||||
options="{'no_open': True, 'no_create': True}"
|
||||
/>
|
||||
<field name="origin" />
|
||||
<field name="line_ids" nolabel="1" colspan="2">
|
||||
<tree editable="bottom" create="0">
|
||||
<field name="quant_id" invisible="1" />
|
||||
<field name="src_location_id" />
|
||||
<field name="product_id" />
|
||||
<field name="lot_id" groups="stock.group_production_lot" />
|
||||
<field name="quant_quantity" sum="1" />
|
||||
<field name="quantity" sum="1" />
|
||||
<field name="uom_id" groups="uom.group_uom" string="Unit" />
|
||||
</tree>
|
||||
</field>
|
||||
</group>
|
||||
<footer>
|
||||
<button name="run" string="Move" type="object" class="btn-primary" />
|
||||
<button string="Cancel" special="cancel" />
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="stock_quant_move_wizard_action" model="ir.actions.act_window">
|
||||
<field name="name">Move to Another Location</field>
|
||||
<field name="res_model">stock.quant.move.wizard</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="target">new</field>
|
||||
<field name="binding_model_id" ref="stock.model_stock_quant" />
|
||||
<field name="binding_view_types">list</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
Reference in New Issue
Block a user